Commit fe33d20f authored by zhengxing.li's avatar zhengxing.li Committed by Commit bot

X87: [builtins] Migrate Number constructor similar to String constructor.

  port 322ffda3 (r33265)

  original commit message:
  Also migrate the Number constructor to a native builtin, using the
  same mechanism already used by the String constructor. Otherwise just
  parsing and compiling the Number constructor to optimized code already
  eats 2ms on desktop for no good reason, and the resulting optimized
  code is not even close to awesome.

  Drive-by-fix: Use correct context for the [[Construct]] case of the
  String constructor as well, and share some code with it.

BUG=

Review URL: https://codereview.chromium.org/1581313002

Cr-Commit-Position: refs/heads/master@{#33280}
parent d19e3a21
......@@ -1374,6 +1374,113 @@ void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
}
// static
void Builtins::Generate_NumberConstructor(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- eax : number of arguments
// -- edi : constructor function
// -- esp[0] : return address
// -- esp[(argc - n) * 4] : arg[n] (zero-based)
// -- esp[(argc + 1) * 4] : receiver
// -----------------------------------
// 1. Load the first argument into eax and get rid of the rest (including the
// receiver).
Label no_arguments;
{
__ test(eax, eax);
__ j(zero, &no_arguments, Label::kNear);
__ mov(ebx, Operand(esp, eax, times_pointer_size, 0));
__ PopReturnAddressTo(ecx);
__ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
__ PushReturnAddressFrom(ecx);
__ mov(eax, ebx);
}
// 2a. Convert the first argument to a number.
ToNumberStub stub(masm->isolate());
__ TailCallStub(&stub);
// 2b. No arguments, return +0 (already in eax).
__ bind(&no_arguments);
__ ret(1 * kPointerSize);
}
// static
void Builtins::Generate_NumberConstructor_ConstructStub(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- eax : number of arguments
// -- edi : constructor function
// -- edx : new target
// -- esp[0] : return address
// -- esp[(argc - n) * 4] : arg[n] (zero-based)
// -- esp[(argc + 1) * 4] : receiver
// -----------------------------------
// 1. Make sure we operate in the context of the called function.
__ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
// 2. Load the first argument into ebx and get rid of the rest (including the
// receiver).
{
Label no_arguments, done;
__ test(eax, eax);
__ j(zero, &no_arguments, Label::kNear);
__ mov(ebx, Operand(esp, eax, times_pointer_size, 0));
__ jmp(&done, Label::kNear);
__ bind(&no_arguments);
__ Move(ebx, Smi::FromInt(0));
__ bind(&done);
__ PopReturnAddressTo(ecx);
__ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
__ PushReturnAddressFrom(ecx);
}
// 3. Make sure ebx is a number.
{
Label done_convert;
__ JumpIfSmi(ebx, &done_convert);
__ CompareRoot(FieldOperand(ebx, HeapObject::kMapOffset),
Heap::kHeapNumberMapRootIndex);
__ j(equal, &done_convert);
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ Push(edi);
__ Push(edx);
__ Move(eax, ebx);
ToNumberStub stub(masm->isolate());
__ CallStub(&stub);
__ Move(ebx, eax);
__ Pop(edx);
__ Pop(edi);
}
__ bind(&done_convert);
}
// 4. Check if new target and constructor differ.
Label new_object;
__ cmp(edx, edi);
__ j(not_equal, &new_object);
// 5. Allocate a JSValue wrapper for the number.
__ AllocateJSValue(eax, edi, ebx, ecx, &new_object);
__ Ret();
// 6. Fallback to the runtime to create new object.
__ bind(&new_object);
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ Push(ebx); // the first argument
__ Push(edi); // constructor function
__ Push(edx); // new target
__ CallRuntime(Runtime::kNewObject);
__ Pop(FieldOperand(eax, JSValue::kValueOffset));
}
__ Ret();
}
// static
void Builtins::Generate_StringConstructor(MacroAssembler* masm) {
// ----------- S t a t e -------------
......@@ -1445,7 +1552,10 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
// -- esp[(argc + 1) * 4] : receiver
// -----------------------------------
// 1. Load the first argument into ebx and get rid of the rest (including the
// 1. Make sure we operate in the context of the called function.
__ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
// 2. Load the first argument into ebx and get rid of the rest (including the
// receiver).
{
Label no_arguments, done;
......@@ -1461,7 +1571,7 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
__ PushReturnAddressFrom(ecx);
}
// 2. Make sure ebx is a string.
// 3. Make sure ebx is a string.
{
Label convert, done_convert;
__ JumpIfSmi(ebx, &convert, Label::kNear);
......@@ -1482,33 +1592,16 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
__ bind(&done_convert);
}
// 3. Check if new target and constructor differ.
// 4. Check if new target and constructor differ.
Label new_object;
__ cmp(edx, edi);
__ j(not_equal, &new_object);
// 4. Allocate a JSValue wrapper for the string.
{
// ----------- S t a t e -------------
// -- ebx : the first argument
// -- edi : constructor function
// -- edx : new target
// -----------------------------------
__ Allocate(JSValue::kSize, eax, ecx, no_reg, &new_object, TAG_OBJECT);
// Initialize the JSValue in eax.
__ LoadGlobalFunctionInitialMap(edi, ecx);
__ mov(FieldOperand(eax, HeapObject::kMapOffset), ecx);
__ mov(FieldOperand(eax, JSObject::kPropertiesOffset),
masm->isolate()->factory()->empty_fixed_array());
__ mov(FieldOperand(eax, JSObject::kElementsOffset),
masm->isolate()->factory()->empty_fixed_array());
__ mov(FieldOperand(eax, JSValue::kValueOffset), ebx);
STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize);
__ Ret();
}
// 5. Allocate a JSValue wrapper for the string.
__ AllocateJSValue(eax, edi, ebx, ecx, &new_object);
__ Ret();
// 5. Fallback to the runtime to create new object.
// 6. Fallback to the runtime to create new object.
__ bind(&new_object);
{
FrameScope scope(masm, StackFrame::INTERNAL);
......
......@@ -1642,6 +1642,27 @@ void MacroAssembler::AllocateOneByteSlicedString(Register result,
}
void MacroAssembler::AllocateJSValue(Register result, Register constructor,
Register value, Register scratch,
Label* gc_required) {
DCHECK(!result.is(constructor));
DCHECK(!result.is(scratch));
DCHECK(!result.is(value));
// Allocate JSValue in new space.
Allocate(JSValue::kSize, result, scratch, no_reg, gc_required, TAG_OBJECT);
// Initialize the JSValue.
LoadGlobalFunctionInitialMap(constructor, scratch);
mov(FieldOperand(result, HeapObject::kMapOffset), scratch);
LoadRoot(scratch, Heap::kEmptyFixedArrayRootIndex);
mov(FieldOperand(result, JSObject::kPropertiesOffset), scratch);
mov(FieldOperand(result, JSObject::kElementsOffset), scratch);
mov(FieldOperand(result, JSValue::kValueOffset), value);
STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize);
}
// Copy memory, byte-by-byte, from source to destination. Not optimized for
// long or aligned copies. The contents of scratch and length are destroyed.
// Source and destination are incremented by length.
......
......@@ -601,6 +601,11 @@ class MacroAssembler: public Assembler {
void AllocateOneByteSlicedString(Register result, Register scratch1,
Register scratch2, Label* gc_required);
// Allocate and initialize a JSValue wrapper with the specified {constructor}
// and {value}.
void AllocateJSValue(Register result, Register constructor, Register value,
Register scratch, Label* gc_required);
// Copy memory, byte-by-byte, from source to destination. Not optimized for
// long or aligned copies.
// The contents of index and scratch are destroyed.
......@@ -750,9 +755,11 @@ class MacroAssembler: public Assembler {
void Move(Register dst, const Immediate& x);
void Move(const Operand& dst, const Immediate& x);
void Move(Register dst, Smi* source) { Move(dst, Immediate(source)); }
// Push a handle value.
void Push(Handle<Object> handle) { push(Immediate(handle)); }
void Push(Smi* smi) { Push(Handle<Smi>(smi, isolate())); }
void Push(Smi* smi) { Push(Immediate(smi)); }
Handle<Object> CodeObject() {
DCHECK(!code_object_.is_null());
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment