Commit 322ffda3 authored by bmeurer's avatar bmeurer Committed by Commit bot

[builtins] Migrate Number constructor similar to String constructor.

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.

R=jarin@chromium.org

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

Cr-Commit-Position: refs/heads/master@{#33265}
parent 039dce1e
...@@ -136,6 +136,106 @@ void Builtins::Generate_ArrayCode(MacroAssembler* masm) { ...@@ -136,6 +136,106 @@ void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
} }
// static
void Builtins::Generate_NumberConstructor(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- r0 : number of arguments
// -- r1 : constructor function
// -- lr : return address
// -- sp[(argc - n - 1) * 4] : arg[n] (zero based)
// -- sp[argc * 4] : receiver
// -----------------------------------
// 1. Load the first argument into r0 and get rid of the rest (including the
// receiver).
Label no_arguments;
{
__ sub(r0, r0, Operand(1), SetCC);
__ b(lo, &no_arguments);
__ ldr(r0, MemOperand(sp, r0, LSL, kPointerSizeLog2, PreIndex));
__ Drop(2);
}
// 2a. Convert the first argument to a number.
ToNumberStub stub(masm->isolate());
__ TailCallStub(&stub);
// 2b. No arguments, return +0.
__ bind(&no_arguments);
__ Move(r0, Smi::FromInt(0));
__ Ret(1);
}
// static
void Builtins::Generate_NumberConstructor_ConstructStub(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- r0 : number of arguments
// -- r1 : constructor function
// -- r3 : new target
// -- lr : return address
// -- sp[(argc - n - 1) * 4] : arg[n] (zero based)
// -- sp[argc * 4] : receiver
// -----------------------------------
// 1. Make sure we operate in the context of the called function.
__ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
// 2. Load the first argument into r2 and get rid of the rest (including the
// receiver).
{
Label no_arguments, done;
__ sub(r0, r0, Operand(1), SetCC);
__ b(lo, &no_arguments);
__ ldr(r2, MemOperand(sp, r0, LSL, kPointerSizeLog2, PreIndex));
__ Drop(2);
__ b(&done);
__ bind(&no_arguments);
__ Move(r2, Smi::FromInt(0));
__ Drop(1);
__ bind(&done);
}
// 3. Make sure r2 is a number.
{
Label done_convert;
__ JumpIfSmi(r2, &done_convert);
__ CompareObjectType(r2, r4, r4, HEAP_NUMBER_TYPE);
__ b(eq, &done_convert);
{
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
__ Push(r1, r3);
__ Move(r0, r2);
ToNumberStub stub(masm->isolate());
__ CallStub(&stub);
__ Move(r2, r0);
__ Pop(r1, r3);
}
__ bind(&done_convert);
}
// 4. Check if new target and constructor differ.
Label new_object;
__ cmp(r1, r3);
__ b(ne, &new_object);
// 5. Allocate a JSValue wrapper for the number.
__ AllocateJSValue(r0, r1, r2, r4, r5, &new_object);
__ Ret();
// 6. Fallback to the runtime to create new object.
__ bind(&new_object);
{
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
__ Push(r2, r1, r3); // first argument, constructor, new target
__ CallRuntime(Runtime::kNewObject);
__ Pop(r2);
}
__ str(r2, FieldMemOperand(r0, JSValue::kValueOffset));
__ Ret();
}
// static // static
void Builtins::Generate_StringConstructor(MacroAssembler* masm) { void Builtins::Generate_StringConstructor(MacroAssembler* masm) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
...@@ -202,7 +302,10 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) { ...@@ -202,7 +302,10 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
// -- sp[argc * 4] : receiver // -- sp[argc * 4] : receiver
// ----------------------------------- // -----------------------------------
// 1. Load the first argument into r2 and get rid of the rest (including the // 1. Make sure we operate in the context of the called function.
__ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
// 2. Load the first argument into r2 and get rid of the rest (including the
// receiver). // receiver).
{ {
Label no_arguments, done; Label no_arguments, done;
...@@ -217,7 +320,7 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) { ...@@ -217,7 +320,7 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
__ bind(&done); __ bind(&done);
} }
// 2. Make sure r2 is a string. // 3. Make sure r2 is a string.
{ {
Label convert, done_convert; Label convert, done_convert;
__ JumpIfSmi(r2, &convert); __ JumpIfSmi(r2, &convert);
...@@ -236,33 +339,16 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) { ...@@ -236,33 +339,16 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
__ bind(&done_convert); __ bind(&done_convert);
} }
// 3. Check if new target and constructor differ. // 4. Check if new target and constructor differ.
Label new_object; Label new_object;
__ cmp(r1, r3); __ cmp(r1, r3);
__ b(ne, &new_object); __ b(ne, &new_object);
// 4. Allocate a JSValue wrapper for the string. // 5. Allocate a JSValue wrapper for the string.
{ __ AllocateJSValue(r0, r1, r2, r4, r5, &new_object);
// ----------- S t a t e ------------- __ Ret();
// -- r2 : the first argument
// -- r1 : constructor function
// -- r3 : new target
// -- lr : return address
// -----------------------------------
__ Allocate(JSValue::kSize, r0, r4, r5, &new_object, TAG_OBJECT);
// Initialize the JSValue in r0.
__ LoadGlobalFunctionInitialMap(r1, r3, r4);
__ str(r3, FieldMemOperand(r0, HeapObject::kMapOffset));
__ LoadRoot(r3, Heap::kEmptyFixedArrayRootIndex);
__ str(r3, FieldMemOperand(r0, JSObject::kPropertiesOffset));
__ str(r3, FieldMemOperand(r0, JSObject::kElementsOffset));
__ str(r2, FieldMemOperand(r0, JSValue::kValueOffset));
STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize);
__ Ret();
}
// 5. Fallback to the runtime to create new object. // 6. Fallback to the runtime to create new object.
__ bind(&new_object); __ bind(&new_object);
{ {
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL); FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
......
...@@ -2936,6 +2936,28 @@ void MacroAssembler::AllocateHeapNumberWithValue(Register result, ...@@ -2936,6 +2936,28 @@ void MacroAssembler::AllocateHeapNumberWithValue(Register result,
} }
void MacroAssembler::AllocateJSValue(Register result, Register constructor,
Register value, Register scratch1,
Register scratch2, Label* gc_required) {
DCHECK(!result.is(constructor));
DCHECK(!result.is(scratch1));
DCHECK(!result.is(scratch2));
DCHECK(!result.is(value));
// Allocate JSValue in new space.
Allocate(JSValue::kSize, result, scratch1, scratch2, gc_required, TAG_OBJECT);
// Initialize the JSValue.
LoadGlobalFunctionInitialMap(constructor, scratch1, scratch2);
str(scratch1, FieldMemOperand(result, HeapObject::kMapOffset));
LoadRoot(scratch1, Heap::kEmptyFixedArrayRootIndex);
str(scratch1, FieldMemOperand(result, JSObject::kPropertiesOffset));
str(scratch1, FieldMemOperand(result, JSObject::kElementsOffset));
str(value, FieldMemOperand(result, JSValue::kValueOffset));
STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize);
}
void MacroAssembler::CopyBytes(Register src, void MacroAssembler::CopyBytes(Register src,
Register dst, Register dst,
Register length, Register length,
......
...@@ -806,6 +806,12 @@ class MacroAssembler: public Assembler { ...@@ -806,6 +806,12 @@ class MacroAssembler: public Assembler {
Register heap_number_map, Register heap_number_map,
Label* gc_required); Label* gc_required);
// Allocate and initialize a JSValue wrapper with the specified {constructor}
// and {value}.
void AllocateJSValue(Register result, Register constructor, Register value,
Register scratch1, Register scratch2,
Label* gc_required);
// Copies a number of bytes from src to dst. All registers are clobbered. On // Copies a number of bytes from src to dst. All registers are clobbered. On
// exit src and dst will point to the place just after where the last byte was // exit src and dst will point to the place just after where the last byte was
// read or written and length will be zero. // read or written and length will be zero.
......
...@@ -137,6 +137,107 @@ void Builtins::Generate_ArrayCode(MacroAssembler* masm) { ...@@ -137,6 +137,107 @@ void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
} }
// static
void Builtins::Generate_NumberConstructor(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- x0 : number of arguments
// -- x1 : constructor function
// -- lr : return address
// -- sp[(argc - n - 1) * 8] : arg[n] (zero based)
// -- sp[argc * 8] : receiver
// -----------------------------------
ASM_LOCATION("Builtins::Generate_NumberConstructor");
// 1. Load the first argument into x0 and get rid of the rest (including the
// receiver).
Label no_arguments;
{
__ Cbz(x0, &no_arguments);
__ Sub(x0, x0, 1);
__ Drop(x0);
__ Ldr(x0, MemOperand(jssp, 2 * kPointerSize, PostIndex));
}
// 2a. Convert first argument to number.
ToNumberStub stub(masm->isolate());
__ TailCallStub(&stub);
// 2b. No arguments, return +0 (already in x0).
__ Bind(&no_arguments);
__ Drop(1);
__ Ret();
}
// static
void Builtins::Generate_NumberConstructor_ConstructStub(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- x0 : number of arguments
// -- x1 : constructor function
// -- x3 : new target
// -- lr : return address
// -- sp[(argc - n - 1) * 8] : arg[n] (zero based)
// -- sp[argc * 8] : receiver
// -----------------------------------
ASM_LOCATION("Builtins::Generate_NumberConstructor_ConstructStub");
// 1. Make sure we operate in the context of the called function.
__ Ldr(cp, FieldMemOperand(x1, JSFunction::kContextOffset));
// 2. Load the first argument into x2 and get rid of the rest (including the
// receiver).
{
Label no_arguments, done;
__ Cbz(x0, &no_arguments);
__ Sub(x0, x0, 1);
__ Drop(x0);
__ Ldr(x2, MemOperand(jssp, 2 * kPointerSize, PostIndex));
__ B(&done);
__ Bind(&no_arguments);
__ Drop(1);
__ Mov(x2, Smi::FromInt(0));
__ Bind(&done);
}
// 3. Make sure x2 is a number.
{
Label done_convert;
__ JumpIfSmi(x2, &done_convert);
__ JumpIfObjectType(x2, x4, x4, HEAP_NUMBER_TYPE, &done_convert, eq);
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ Push(x1, x3);
__ Move(x0, x2);
ToNumberStub stub(masm->isolate());
__ CallStub(&stub);
__ Move(x2, x0);
__ Pop(x3, x1);
}
__ Bind(&done_convert);
}
// 4. Check if new target and constructor differ.
Label new_object;
__ Cmp(x1, x3);
__ B(ne, &new_object);
// 5. Allocate a JSValue wrapper for the number.
__ AllocateJSValue(x0, x1, x2, x4, x5, &new_object);
__ Ret();
// 6. Fallback to the runtime to create new object.
__ bind(&new_object);
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ Push(x2, x1, x3); // first argument, constructor, new target
__ CallRuntime(Runtime::kNewObject);
__ Pop(x2);
}
__ Str(x2, FieldMemOperand(x0, JSValue::kValueOffset));
__ Ret();
}
// static // static
void Builtins::Generate_StringConstructor(MacroAssembler* masm) { void Builtins::Generate_StringConstructor(MacroAssembler* masm) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
...@@ -206,7 +307,10 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) { ...@@ -206,7 +307,10 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
// ----------------------------------- // -----------------------------------
ASM_LOCATION("Builtins::Generate_StringConstructor_ConstructStub"); ASM_LOCATION("Builtins::Generate_StringConstructor_ConstructStub");
// 1. Load the first argument into x2 and get rid of the rest (including the // 1. Make sure we operate in the context of the called function.
__ Ldr(cp, FieldMemOperand(x1, JSFunction::kContextOffset));
// 2. Load the first argument into x2 and get rid of the rest (including the
// receiver). // receiver).
{ {
Label no_arguments, done; Label no_arguments, done;
...@@ -221,7 +325,7 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) { ...@@ -221,7 +325,7 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
__ Bind(&done); __ Bind(&done);
} }
// 2. Make sure x2 is a string. // 3. Make sure x2 is a string.
{ {
Label convert, done_convert; Label convert, done_convert;
__ JumpIfSmi(x2, &convert); __ JumpIfSmi(x2, &convert);
...@@ -239,33 +343,16 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) { ...@@ -239,33 +343,16 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
__ Bind(&done_convert); __ Bind(&done_convert);
} }
// 3. Check if new target and constructor differ. // 4. Check if new target and constructor differ.
Label new_object; Label new_object;
__ Cmp(x1, x3); __ Cmp(x1, x3);
__ B(ne, &new_object); __ B(ne, &new_object);
// 4. Allocate a JSValue wrapper for the string. // 5. Allocate a JSValue wrapper for the string.
{ __ AllocateJSValue(x0, x1, x2, x4, x5, &new_object);
// ----------- S t a t e ------------- __ Ret();
// -- x2 : the first argument
// -- x1 : constructor function
// -- x3 : new target
// -- lr : return address
// -----------------------------------
__ Allocate(JSValue::kSize, x0, x4, x5, &new_object, TAG_OBJECT);
// Initialize the JSValue in eax.
__ LoadGlobalFunctionInitialMap(x1, x3, x4);
__ Str(x3, FieldMemOperand(x0, HeapObject::kMapOffset));
__ LoadRoot(x3, Heap::kEmptyFixedArrayRootIndex);
__ Str(x3, FieldMemOperand(x0, JSObject::kPropertiesOffset));
__ Str(x3, FieldMemOperand(x0, JSObject::kElementsOffset));
__ Str(x2, FieldMemOperand(x0, JSValue::kValueOffset));
STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize);
__ Ret();
}
// 5. Fallback to the runtime to create new object. // 6. Fallback to the runtime to create new object.
__ bind(&new_object); __ bind(&new_object);
{ {
FrameScope scope(masm, StackFrame::INTERNAL); FrameScope scope(masm, StackFrame::INTERNAL);
......
...@@ -3269,6 +3269,28 @@ void MacroAssembler::JumpIfObjectType(Register object, ...@@ -3269,6 +3269,28 @@ void MacroAssembler::JumpIfObjectType(Register object,
} }
void MacroAssembler::AllocateJSValue(Register result, Register constructor,
Register value, Register scratch1,
Register scratch2, Label* gc_required) {
DCHECK(!result.is(constructor));
DCHECK(!result.is(scratch1));
DCHECK(!result.is(scratch2));
DCHECK(!result.is(value));
// Allocate JSValue in new space.
Allocate(JSValue::kSize, result, scratch1, scratch2, gc_required, TAG_OBJECT);
// Initialize the JSValue.
LoadGlobalFunctionInitialMap(constructor, scratch1, scratch2);
Str(scratch1, FieldMemOperand(result, HeapObject::kMapOffset));
LoadRoot(scratch1, Heap::kEmptyFixedArrayRootIndex);
Str(scratch1, FieldMemOperand(result, JSObject::kPropertiesOffset));
Str(scratch1, FieldMemOperand(result, JSObject::kElementsOffset));
Str(value, FieldMemOperand(result, JSValue::kValueOffset));
STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize);
}
void MacroAssembler::JumpIfNotObjectType(Register object, void MacroAssembler::JumpIfNotObjectType(Register object,
Register map, Register map,
Register type_reg, Register type_reg,
......
...@@ -1340,6 +1340,12 @@ class MacroAssembler : public Assembler { ...@@ -1340,6 +1340,12 @@ class MacroAssembler : public Assembler {
CPURegister heap_number_map = NoReg, CPURegister heap_number_map = NoReg,
MutableMode mode = IMMUTABLE); MutableMode mode = IMMUTABLE);
// Allocate and initialize a JSValue wrapper with the specified {constructor}
// and {value}.
void AllocateJSValue(Register result, Register constructor, Register value,
Register scratch1, Register scratch2,
Label* gc_required);
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Support functions. // Support functions.
......
...@@ -1201,14 +1201,15 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object, ...@@ -1201,14 +1201,15 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
} }
{ // --- N u m b e r --- { // --- N u m b e r ---
Handle<JSFunction> number_fun = Handle<JSFunction> number_fun = InstallFunction(
InstallFunction(global, "Number", JS_VALUE_TYPE, JSValue::kSize, global, "Number", JS_VALUE_TYPE, JSValue::kSize,
isolate->initial_object_prototype(), isolate->initial_object_prototype(), Builtins::kNumberConstructor);
Builtins::kIllegal); number_fun->shared()->DontAdaptArguments();
number_fun->shared()->set_construct_stub(
*isolate->builtins()->NumberConstructor_ConstructStub());
number_fun->shared()->set_length(1);
InstallWithIntrinsicDefaultProto(isolate, number_fun, InstallWithIntrinsicDefaultProto(isolate, number_fun,
Context::NUMBER_FUNCTION_INDEX); Context::NUMBER_FUNCTION_INDEX);
number_fun->shared()->set_construct_stub(
*isolate->builtins()->JSBuiltinsConstructStub());
} }
{ // --- B o o l e a n --- { // --- B o o l e a n ---
......
...@@ -246,6 +246,9 @@ inline bool operator&(BuiltinExtraArguments lhs, BuiltinExtraArguments rhs) { ...@@ -246,6 +246,9 @@ inline bool operator&(BuiltinExtraArguments lhs, BuiltinExtraArguments rhs) {
V(InternalArrayCode, BUILTIN, UNINITIALIZED, kNoExtraICState) \ V(InternalArrayCode, BUILTIN, UNINITIALIZED, kNoExtraICState) \
V(ArrayCode, BUILTIN, UNINITIALIZED, kNoExtraICState) \ V(ArrayCode, BUILTIN, UNINITIALIZED, kNoExtraICState) \
\ \
V(NumberConstructor, BUILTIN, UNINITIALIZED, kNoExtraICState) \
V(NumberConstructor_ConstructStub, BUILTIN, UNINITIALIZED, kNoExtraICState) \
\
V(StringConstructor, BUILTIN, UNINITIALIZED, kNoExtraICState) \ V(StringConstructor, BUILTIN, UNINITIALIZED, kNoExtraICState) \
V(StringConstructor_ConstructStub, BUILTIN, UNINITIALIZED, kNoExtraICState) \ V(StringConstructor_ConstructStub, BUILTIN, UNINITIALIZED, kNoExtraICState) \
\ \
...@@ -479,6 +482,11 @@ class Builtins { ...@@ -479,6 +482,11 @@ class Builtins {
static void Generate_InternalArrayCode(MacroAssembler* masm); static void Generate_InternalArrayCode(MacroAssembler* masm);
static void Generate_ArrayCode(MacroAssembler* masm); static void Generate_ArrayCode(MacroAssembler* masm);
// ES6 section 20.1.1.1 Number ( [ value ] ) for the [[Call]] case.
static void Generate_NumberConstructor(MacroAssembler* masm);
// ES6 section 20.1.1.1 Number ( [ value ] ) for the [[Construct]] case.
static void Generate_NumberConstructor_ConstructStub(MacroAssembler* masm);
static void Generate_StringConstructor(MacroAssembler* masm); static void Generate_StringConstructor(MacroAssembler* masm);
static void Generate_StringConstructor_ConstructStub(MacroAssembler* masm); static void Generate_StringConstructor_ConstructStub(MacroAssembler* masm);
static void Generate_OnStackReplacement(MacroAssembler* masm); static void Generate_OnStackReplacement(MacroAssembler* masm);
......
...@@ -1374,6 +1374,113 @@ void Builtins::Generate_ArrayCode(MacroAssembler* masm) { ...@@ -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 // static
void Builtins::Generate_StringConstructor(MacroAssembler* masm) { void Builtins::Generate_StringConstructor(MacroAssembler* masm) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
...@@ -1445,7 +1552,10 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) { ...@@ -1445,7 +1552,10 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
// -- esp[(argc + 1) * 4] : receiver // -- 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). // receiver).
{ {
Label no_arguments, done; Label no_arguments, done;
...@@ -1461,7 +1571,7 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) { ...@@ -1461,7 +1571,7 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
__ PushReturnAddressFrom(ecx); __ PushReturnAddressFrom(ecx);
} }
// 2. Make sure ebx is a string. // 3. Make sure ebx is a string.
{ {
Label convert, done_convert; Label convert, done_convert;
__ JumpIfSmi(ebx, &convert, Label::kNear); __ JumpIfSmi(ebx, &convert, Label::kNear);
...@@ -1482,33 +1592,16 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) { ...@@ -1482,33 +1592,16 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
__ bind(&done_convert); __ bind(&done_convert);
} }
// 3. Check if new target and constructor differ. // 4. Check if new target and constructor differ.
Label new_object; Label new_object;
__ cmp(edx, edi); __ cmp(edx, edi);
__ j(not_equal, &new_object); __ j(not_equal, &new_object);
// 4. Allocate a JSValue wrapper for the string. // 5. Allocate a JSValue wrapper for the string.
{ __ AllocateJSValue(eax, edi, ebx, ecx, &new_object);
// ----------- S t a t e ------------- __ Ret();
// -- 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. Fallback to the runtime to create new object. // 6. Fallback to the runtime to create new object.
__ bind(&new_object); __ bind(&new_object);
{ {
FrameScope scope(masm, StackFrame::INTERNAL); FrameScope scope(masm, StackFrame::INTERNAL);
......
...@@ -1676,6 +1676,27 @@ void MacroAssembler::AllocateOneByteSlicedString(Register result, ...@@ -1676,6 +1676,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 // Copy memory, byte-by-byte, from source to destination. Not optimized for
// long or aligned copies. The contents of scratch and length are destroyed. // long or aligned copies. The contents of scratch and length are destroyed.
// Source and destination are incremented by length. // Source and destination are incremented by length.
......
...@@ -612,6 +612,11 @@ class MacroAssembler: public Assembler { ...@@ -612,6 +612,11 @@ class MacroAssembler: public Assembler {
void AllocateOneByteSlicedString(Register result, Register scratch1, void AllocateOneByteSlicedString(Register result, Register scratch1,
Register scratch2, Label* gc_required); 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 // Copy memory, byte-by-byte, from source to destination. Not optimized for
// long or aligned copies. // long or aligned copies.
// The contents of index and scratch are destroyed. // The contents of index and scratch are destroyed.
...@@ -773,9 +778,11 @@ class MacroAssembler: public Assembler { ...@@ -773,9 +778,11 @@ class MacroAssembler: public Assembler {
void Move(XMMRegister dst, uint64_t src); void Move(XMMRegister dst, uint64_t src);
void Move(XMMRegister dst, double src) { Move(dst, bit_cast<uint64_t>(src)); } void Move(XMMRegister dst, double src) { Move(dst, bit_cast<uint64_t>(src)); }
void Move(Register dst, Smi* source) { Move(dst, Immediate(source)); }
// Push a handle value. // Push a handle value.
void Push(Handle<Object> handle) { push(Immediate(handle)); } 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() { Handle<Object> CodeObject() {
DCHECK(!code_object_.is_null()); DCHECK(!code_object_.is_null());
......
...@@ -952,18 +952,6 @@ utils.InstallFunctions(GlobalBoolean.prototype, DONT_ENUM, [ ...@@ -952,18 +952,6 @@ utils.InstallFunctions(GlobalBoolean.prototype, DONT_ENUM, [
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Number // Number
function NumberConstructor(x) {
// TODO(bmeurer): Move this to toplevel.
"use strict";
var value = %_ArgumentsLength() == 0 ? 0 : TO_NUMBER(x);
if (IS_UNDEFINED(new.target)) return value;
var result = %NewObject(GlobalNumber, new.target);
%_SetValueOf(result, value);
return result;
}
// ES6 Number.prototype.toString([ radix ]) // ES6 Number.prototype.toString([ radix ])
function NumberToStringJS(radix) { function NumberToStringJS(radix) {
// NOTE: Both Number objects and values can enter here as // NOTE: Both Number objects and values can enter here as
...@@ -1114,7 +1102,6 @@ function NumberIsSafeInteger(number) { ...@@ -1114,7 +1102,6 @@ function NumberIsSafeInteger(number) {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
%SetCode(GlobalNumber, NumberConstructor);
%FunctionSetPrototype(GlobalNumber, new GlobalNumber(0)); %FunctionSetPrototype(GlobalNumber, new GlobalNumber(0));
%OptimizeObjectForAddingMultipleProperties(GlobalNumber.prototype, 8); %OptimizeObjectForAddingMultipleProperties(GlobalNumber.prototype, 8);
......
...@@ -141,6 +141,108 @@ void Builtins::Generate_ArrayCode(MacroAssembler* masm) { ...@@ -141,6 +141,108 @@ void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
} }
// static
void Builtins::Generate_NumberConstructor(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- a0 : number of arguments
// -- a1 : constructor function
// -- ra : return address
// -- sp[(argc - n - 1) * 4] : arg[n] (zero based)
// -- sp[argc * 4] : receiver
// -----------------------------------
// 1. Load the first argument into a0 and get rid of the rest (including the
// receiver).
Label no_arguments;
{
__ Branch(USE_DELAY_SLOT, &no_arguments, eq, a0, Operand(zero_reg));
__ Subu(a0, a0, Operand(1));
__ sll(a0, a0, kPointerSizeLog2);
__ Addu(sp, a0, sp);
__ lw(a0, MemOperand(sp));
__ Drop(2);
}
// 2a. Convert first argument to number.
ToNumberStub stub(masm->isolate());
__ TailCallStub(&stub);
// 2b. No arguments, return +0.
__ bind(&no_arguments);
__ Move(v0, Smi::FromInt(0));
__ DropAndRet(1);
}
// static
void Builtins::Generate_NumberConstructor_ConstructStub(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- a0 : number of arguments
// -- a1 : constructor function
// -- a3 : new target
// -- ra : return address
// -- sp[(argc - n - 1) * 4] : arg[n] (zero based)
// -- sp[argc * 4] : receiver
// -----------------------------------
// 1. Make sure we operate in the context of the called function.
__ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
// 2. Load the first argument into a0 and get rid of the rest (including the
// receiver).
{
Label no_arguments, done;
__ Branch(USE_DELAY_SLOT, &no_arguments, eq, a0, Operand(zero_reg));
__ Subu(a0, a0, Operand(1));
__ sll(a0, a0, kPointerSizeLog2);
__ Addu(sp, a0, sp);
__ lw(a0, MemOperand(sp));
__ Drop(2);
__ jmp(&done);
__ bind(&no_arguments);
__ Move(a0, Smi::FromInt(0));
__ Drop(1);
__ bind(&done);
}
// 3. Make sure a0 is a number.
{
Label done_convert;
__ JumpIfSmi(a0, &done_convert);
__ GetObjectType(a0, a2, a2);
__ Branch(&done_convert, eq, a2, Operand(HEAP_NUMBER_TYPE));
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ Push(a1, a3);
ToNumberStub stub(masm->isolate());
__ CallStub(&stub);
__ Move(a0, v0);
__ Pop(a1, a3);
}
__ bind(&done_convert);
}
// 4. Check if new target and constructor differ.
Label new_object;
__ Branch(&new_object, ne, a1, Operand(a3));
// 5. Allocate a JSValue wrapper for the number.
__ AllocateJSValue(v0, a1, a0, a2, t0, &new_object);
__ Ret();
// 6. Fallback to the runtime to create new object.
__ bind(&new_object);
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ Push(a0, a1, a3); // first argument, constructor, new target
__ CallRuntime(Runtime::kNewObject);
__ Pop(a0);
}
__ Ret(USE_DELAY_SLOT);
__ sw(a0, FieldMemOperand(v0, JSValue::kValueOffset)); // In delay slot
}
// static // static
void Builtins::Generate_StringConstructor(MacroAssembler* masm) { void Builtins::Generate_StringConstructor(MacroAssembler* masm) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
...@@ -211,7 +313,10 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) { ...@@ -211,7 +313,10 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
// -- sp[argc * 4] : receiver // -- sp[argc * 4] : receiver
// ----------------------------------- // -----------------------------------
// 1. Load the first argument into a0 and get rid of the rest (including the // 1. Make sure we operate in the context of the called function.
__ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
// 2. Load the first argument into a0 and get rid of the rest (including the
// receiver). // receiver).
{ {
Label no_arguments, done; Label no_arguments, done;
...@@ -228,7 +333,7 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) { ...@@ -228,7 +333,7 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
__ bind(&done); __ bind(&done);
} }
// 2. Make sure a0 is a string. // 3. Make sure a0 is a string.
{ {
Label convert, done_convert; Label convert, done_convert;
__ JumpIfSmi(a0, &convert); __ JumpIfSmi(a0, &convert);
...@@ -247,32 +352,15 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) { ...@@ -247,32 +352,15 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
__ bind(&done_convert); __ bind(&done_convert);
} }
// 3. Check if new target and constructor differ. // 4. Check if new target and constructor differ.
Label new_object; Label new_object;
__ Branch(&new_object, ne, a1, Operand(a3)); __ Branch(&new_object, ne, a1, Operand(a3));
// 4. Allocate a JSValue wrapper for the string. // 5. Allocate a JSValue wrapper for the string.
{ __ AllocateJSValue(v0, a1, a0, a2, t0, &new_object);
// ----------- S t a t e ------------- __ Ret();
// -- a0 : the first argument
// -- a1 : constructor function
// -- a3 : new target
// -- ra : return address
// -----------------------------------
__ Allocate(JSValue::kSize, v0, a2, t0, &new_object, TAG_OBJECT);
// Initialize the JSValue in eax.
__ LoadGlobalFunctionInitialMap(a1, a2, a3);
__ sw(a2, FieldMemOperand(v0, HeapObject::kMapOffset));
__ LoadRoot(a3, Heap::kEmptyFixedArrayRootIndex);
__ sw(a3, FieldMemOperand(v0, JSObject::kPropertiesOffset));
__ sw(a3, FieldMemOperand(v0, JSObject::kElementsOffset));
__ Ret(USE_DELAY_SLOT);
__ sw(a0, FieldMemOperand(v0, JSValue::kValueOffset));
STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize);
}
// 5. Fallback to the runtime to create new object. // 6. Fallback to the runtime to create new object.
__ bind(&new_object); __ bind(&new_object);
{ {
FrameScope scope(masm, StackFrame::INTERNAL); FrameScope scope(masm, StackFrame::INTERNAL);
...@@ -281,7 +369,7 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) { ...@@ -281,7 +369,7 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
__ Pop(a0); __ Pop(a0);
} }
__ Ret(USE_DELAY_SLOT); __ Ret(USE_DELAY_SLOT);
__ sw(a0, FieldMemOperand(v0, JSValue::kValueOffset)); __ sw(a0, FieldMemOperand(v0, JSValue::kValueOffset)); // In delay slot
} }
......
...@@ -3600,6 +3600,28 @@ void MacroAssembler::AllocateHeapNumberWithValue(Register result, ...@@ -3600,6 +3600,28 @@ void MacroAssembler::AllocateHeapNumberWithValue(Register result,
} }
void MacroAssembler::AllocateJSValue(Register result, Register constructor,
Register value, Register scratch1,
Register scratch2, Label* gc_required) {
DCHECK(!result.is(constructor));
DCHECK(!result.is(scratch1));
DCHECK(!result.is(scratch2));
DCHECK(!result.is(value));
// Allocate JSValue in new space.
Allocate(JSValue::kSize, result, scratch1, scratch2, gc_required, TAG_OBJECT);
// Initialize the JSValue.
LoadGlobalFunctionInitialMap(constructor, scratch1, scratch2);
sw(scratch1, FieldMemOperand(result, HeapObject::kMapOffset));
LoadRoot(scratch1, Heap::kEmptyFixedArrayRootIndex);
sw(scratch1, FieldMemOperand(result, JSObject::kPropertiesOffset));
sw(scratch1, FieldMemOperand(result, JSObject::kElementsOffset));
sw(value, FieldMemOperand(result, JSValue::kValueOffset));
STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize);
}
void MacroAssembler::CopyBytes(Register src, void MacroAssembler::CopyBytes(Register src,
Register dst, Register dst,
Register length, Register length,
......
...@@ -566,6 +566,12 @@ class MacroAssembler: public Assembler { ...@@ -566,6 +566,12 @@ class MacroAssembler: public Assembler {
Register scratch2, Register scratch2,
Label* gc_required); Label* gc_required);
// Allocate and initialize a JSValue wrapper with the specified {constructor}
// and {value}.
void AllocateJSValue(Register result, Register constructor, Register value,
Register scratch1, Register scratch2,
Label* gc_required);
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Instruction macros. // Instruction macros.
......
...@@ -140,6 +140,107 @@ void Builtins::Generate_ArrayCode(MacroAssembler* masm) { ...@@ -140,6 +140,107 @@ void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
} }
// static
void Builtins::Generate_NumberConstructor(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- a0 : number of arguments
// -- a1 : constructor function
// -- ra : return address
// -- sp[(argc - n - 1) * 8] : arg[n] (zero based)
// -- sp[argc * 8] : receiver
// -----------------------------------
// 1. Load the first argument into a0 and get rid of the rest (including the
// receiver).
Label no_arguments;
{
__ Branch(USE_DELAY_SLOT, &no_arguments, eq, a0, Operand(zero_reg));
__ Dsubu(a0, a0, Operand(1));
__ dsll(a0, a0, kPointerSizeLog2);
__ Daddu(sp, a0, sp);
__ ld(a0, MemOperand(sp));
__ Drop(2);
}
// 2a. Convert first argument to number.
ToNumberStub stub(masm->isolate());
__ TailCallStub(&stub);
// 2b. No arguments, return +0.
__ bind(&no_arguments);
__ Move(v0, Smi::FromInt(0));
__ DropAndRet(1);
}
void Builtins::Generate_NumberConstructor_ConstructStub(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- a0 : number of arguments
// -- a1 : constructor function
// -- a3 : new target
// -- ra : return address
// -- sp[(argc - n - 1) * 8] : arg[n] (zero based)
// -- sp[argc * 8] : receiver
// -----------------------------------
// 1. Make sure we operate in the context of the called function.
__ ld(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
// 2. Load the first argument into a0 and get rid of the rest (including the
// receiver).
{
Label no_arguments, done;
__ Branch(USE_DELAY_SLOT, &no_arguments, eq, a0, Operand(zero_reg));
__ Dsubu(a0, a0, Operand(1));
__ dsll(a0, a0, kPointerSizeLog2);
__ Daddu(sp, a0, sp);
__ ld(a0, MemOperand(sp));
__ Drop(2);
__ jmp(&done);
__ bind(&no_arguments);
__ Move(a0, Smi::FromInt(0));
__ Drop(1);
__ bind(&done);
}
// 3. Make sure a0 is a number.
{
Label done_convert;
__ JumpIfSmi(a0, &done_convert);
__ GetObjectType(a0, a2, a2);
__ Branch(&done_convert, eq, t0, Operand(HEAP_NUMBER_TYPE));
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ Push(a1, a3);
ToNumberStub stub(masm->isolate());
__ CallStub(&stub);
__ Move(a0, v0);
__ Pop(a1, a3);
}
__ bind(&done_convert);
}
// 4. Check if new target and constructor differ.
Label new_object;
__ Branch(&new_object, ne, a1, Operand(a3));
// 5. Allocate a JSValue wrapper for the number.
__ AllocateJSValue(v0, a1, a0, a2, t0, &new_object);
__ Ret();
// 6. Fallback to the runtime to create new object.
__ bind(&new_object);
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ Push(a0, a1, a3); // first argument, constructor, new target
__ CallRuntime(Runtime::kNewObject);
__ Pop(a0);
}
__ Ret(USE_DELAY_SLOT);
__ sd(a0, FieldMemOperand(v0, JSValue::kValueOffset)); // In delay slot.
}
// static // static
void Builtins::Generate_StringConstructor(MacroAssembler* masm) { void Builtins::Generate_StringConstructor(MacroAssembler* masm) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
...@@ -209,7 +310,10 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) { ...@@ -209,7 +310,10 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
// -- sp[argc * 8] : receiver // -- sp[argc * 8] : receiver
// ----------------------------------- // -----------------------------------
// 1. Load the first argument into a0 and get rid of the rest (including the // 1. Make sure we operate in the context of the called function.
__ ld(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
// 2. Load the first argument into a0 and get rid of the rest (including the
// receiver). // receiver).
{ {
Label no_arguments, done; Label no_arguments, done;
...@@ -226,7 +330,7 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) { ...@@ -226,7 +330,7 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
__ bind(&done); __ bind(&done);
} }
// 2. Make sure a0 is a string. // 3. Make sure a0 is a string.
{ {
Label convert, done_convert; Label convert, done_convert;
__ JumpIfSmi(a0, &convert); __ JumpIfSmi(a0, &convert);
...@@ -245,32 +349,15 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) { ...@@ -245,32 +349,15 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
__ bind(&done_convert); __ bind(&done_convert);
} }
// 3. Check if new target and constructor differ. // 4. Check if new target and constructor differ.
Label new_object; Label new_object;
__ Branch(&new_object, ne, a1, Operand(a3)); __ Branch(&new_object, ne, a1, Operand(a3));
// 4. Allocate a JSValue wrapper for the string. // 5. Allocate a JSValue wrapper for the string.
{ __ AllocateJSValue(v0, a1, a0, a2, t0, &new_object);
// ----------- S t a t e ------------- __ Ret();
// -- a0 : the first argument
// -- a1 : constructor function
// -- a3 : new target
// -- ra : return address
// -----------------------------------
__ Allocate(JSValue::kSize, v0, a2, t0, &new_object, TAG_OBJECT);
// Initialize the JSValue in eax.
__ LoadGlobalFunctionInitialMap(a1, a2, a3);
__ sd(a2, FieldMemOperand(v0, HeapObject::kMapOffset));
__ LoadRoot(a3, Heap::kEmptyFixedArrayRootIndex);
__ sd(a3, FieldMemOperand(v0, JSObject::kPropertiesOffset));
__ sd(a3, FieldMemOperand(v0, JSObject::kElementsOffset));
__ sd(a0, FieldMemOperand(v0, JSValue::kValueOffset));
STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize);
__ Ret();
}
// 5. Fallback to the runtime to create new object. // 6. Fallback to the runtime to create new object.
__ bind(&new_object); __ bind(&new_object);
{ {
FrameScope scope(masm, StackFrame::INTERNAL); FrameScope scope(masm, StackFrame::INTERNAL);
...@@ -278,8 +365,8 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) { ...@@ -278,8 +365,8 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
__ CallRuntime(Runtime::kNewObject); __ CallRuntime(Runtime::kNewObject);
__ Pop(a0); __ Pop(a0);
} }
__ sd(a0, FieldMemOperand(v0, JSValue::kValueOffset)); __ Ret(USE_DELAY_SLOT);
__ Ret(); __ sd(a0, FieldMemOperand(v0, JSValue::kValueOffset)); // In delay slot.
} }
......
...@@ -4028,6 +4028,28 @@ void MacroAssembler::AllocateHeapNumberWithValue(Register result, ...@@ -4028,6 +4028,28 @@ void MacroAssembler::AllocateHeapNumberWithValue(Register result,
} }
void MacroAssembler::AllocateJSValue(Register result, Register constructor,
Register value, Register scratch1,
Register scratch2, Label* gc_required) {
DCHECK(!result.is(constructor));
DCHECK(!result.is(scratch1));
DCHECK(!result.is(scratch2));
DCHECK(!result.is(value));
// Allocate JSValue in new space.
Allocate(JSValue::kSize, result, scratch1, scratch2, gc_required, TAG_OBJECT);
// Initialize the JSValue.
LoadGlobalFunctionInitialMap(constructor, scratch1, scratch2);
sd(scratch1, FieldMemOperand(result, HeapObject::kMapOffset));
LoadRoot(scratch1, Heap::kEmptyFixedArrayRootIndex);
sd(scratch1, FieldMemOperand(result, JSObject::kPropertiesOffset));
sd(scratch1, FieldMemOperand(result, JSObject::kElementsOffset));
sd(value, FieldMemOperand(result, JSValue::kValueOffset));
STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize);
}
void MacroAssembler::CopyBytes(Register src, void MacroAssembler::CopyBytes(Register src,
Register dst, Register dst,
Register length, Register length,
......
...@@ -595,6 +595,12 @@ class MacroAssembler: public Assembler { ...@@ -595,6 +595,12 @@ class MacroAssembler: public Assembler {
Register scratch2, Register scratch2,
Label* gc_required); Label* gc_required);
// Allocate and initialize a JSValue wrapper with the specified {constructor}
// and {value}.
void AllocateJSValue(Register result, Register constructor, Register value,
Register scratch1, Register scratch2,
Label* gc_required);
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Instruction macros. // Instruction macros.
......
...@@ -1442,6 +1442,115 @@ void Builtins::Generate_ArrayCode(MacroAssembler* masm) { ...@@ -1442,6 +1442,115 @@ void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
} }
// static
void Builtins::Generate_NumberConstructor(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- rax : number of arguments
// -- rdi : constructor function
// -- rsp[0] : return address
// -- rsp[(argc - n) * 8] : arg[n] (zero-based)
// -- rsp[(argc + 1) * 8] : receiver
// -----------------------------------
// 1. Load the first argument into rax and get rid of the rest (including the
// receiver).
Label no_arguments;
{
StackArgumentsAccessor args(rsp, rax);
__ testp(rax, rax);
__ j(zero, &no_arguments, Label::kNear);
__ movp(rbx, args.GetArgumentOperand(1));
__ PopReturnAddressTo(rcx);
__ leap(rsp, Operand(rsp, rax, times_pointer_size, kPointerSize));
__ PushReturnAddressFrom(rcx);
__ movp(rax, rbx);
}
// 2a. Convert the first argument to a number.
ToNumberStub stub(masm->isolate());
__ TailCallStub(&stub);
// 2b. No arguments, return +0 (already in rax).
__ bind(&no_arguments);
__ ret(1 * kPointerSize);
}
// static
void Builtins::Generate_NumberConstructor_ConstructStub(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- rax : number of arguments
// -- rdi : constructor function
// -- rdx : new target
// -- rsp[0] : return address
// -- rsp[(argc - n) * 8] : arg[n] (zero-based)
// -- rsp[(argc + 1) * 8] : receiver
// -----------------------------------
// 1. Make sure we operate in the context of the called function.
__ movp(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
// 2. Load the first argument into rbx and get rid of the rest (including the
// receiver).
{
StackArgumentsAccessor args(rsp, rax);
Label no_arguments, done;
__ testp(rax, rax);
__ j(zero, &no_arguments, Label::kNear);
__ movp(rbx, args.GetArgumentOperand(1));
__ jmp(&done, Label::kNear);
__ bind(&no_arguments);
__ Move(rbx, Smi::FromInt(0));
__ bind(&done);
__ PopReturnAddressTo(rcx);
__ leap(rsp, Operand(rsp, rax, times_pointer_size, kPointerSize));
__ PushReturnAddressFrom(rcx);
}
// 3. Make sure rbx is a number.
{
Label done_convert;
__ JumpIfSmi(rbx, &done_convert);
__ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset),
Heap::kHeapNumberMapRootIndex);
__ j(equal, &done_convert);
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ Push(rdx);
__ Push(rdi);
__ Move(rax, rbx);
ToNumberStub stub(masm->isolate());
__ CallStub(&stub);
__ Move(rbx, rax);
__ Pop(rdi);
__ Pop(rdx);
}
__ bind(&done_convert);
}
// 4. Check if new target and constructor differ.
Label new_object;
__ cmpp(rdx, rdi);
__ j(not_equal, &new_object);
// 5. Allocate a JSValue wrapper for the number.
__ AllocateJSValue(rax, rdi, rbx, rcx, &new_object);
__ Ret();
// 6. Fallback to the runtime to create new object.
__ bind(&new_object);
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ Push(rbx); // the first argument
__ Push(rdi); // constructor function
__ Push(rdx); // new target
__ CallRuntime(Runtime::kNewObject);
__ Pop(FieldOperand(rax, JSValue::kValueOffset));
}
__ Ret();
}
// static // static
void Builtins::Generate_StringConstructor(MacroAssembler* masm) { void Builtins::Generate_StringConstructor(MacroAssembler* masm) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
...@@ -1514,7 +1623,10 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) { ...@@ -1514,7 +1623,10 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
// -- rsp[(argc + 1) * 8] : receiver // -- rsp[(argc + 1) * 8] : receiver
// ----------------------------------- // -----------------------------------
// 1. Load the first argument into rbx and get rid of the rest (including the // 1. Make sure we operate in the context of the called function.
__ movp(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
// 2. Load the first argument into rbx and get rid of the rest (including the
// receiver). // receiver).
{ {
StackArgumentsAccessor args(rsp, rax); StackArgumentsAccessor args(rsp, rax);
...@@ -1531,7 +1643,7 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) { ...@@ -1531,7 +1643,7 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
__ PushReturnAddressFrom(rcx); __ PushReturnAddressFrom(rcx);
} }
// 2. Make sure rbx is a string. // 3. Make sure rbx is a string.
{ {
Label convert, done_convert; Label convert, done_convert;
__ JumpIfSmi(rbx, &convert, Label::kNear); __ JumpIfSmi(rbx, &convert, Label::kNear);
...@@ -1552,32 +1664,16 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) { ...@@ -1552,32 +1664,16 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
__ bind(&done_convert); __ bind(&done_convert);
} }
// 3. Check if new target and constructor differ. // 4. Check if new target and constructor differ.
Label new_object; Label new_object;
__ cmpp(rdx, rdi); __ cmpp(rdx, rdi);
__ j(not_equal, &new_object); __ j(not_equal, &new_object);
// 4. Allocate a JSValue wrapper for the string. // 5. Allocate a JSValue wrapper for the string.
{ __ AllocateJSValue(rax, rdi, rbx, rcx, &new_object);
// ----------- S t a t e ------------- __ Ret();
// -- rbx : the first argument
// -- rdi : constructor function
// -- rdx : new target
// -----------------------------------
__ Allocate(JSValue::kSize, rax, rcx, no_reg, &new_object, TAG_OBJECT);
// Initialize the JSValue in rax.
__ LoadGlobalFunctionInitialMap(rdi, rcx);
__ movp(FieldOperand(rax, HeapObject::kMapOffset), rcx);
__ LoadRoot(rcx, Heap::kEmptyFixedArrayRootIndex);
__ movp(FieldOperand(rax, JSObject::kPropertiesOffset), rcx);
__ movp(FieldOperand(rax, JSObject::kElementsOffset), rcx);
__ movp(FieldOperand(rax, JSValue::kValueOffset), rbx);
STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize);
__ Ret();
}
// 5. Fallback to the runtime to create new object. // 6. Fallback to the runtime to create new object.
__ bind(&new_object); __ bind(&new_object);
{ {
FrameScope scope(masm, StackFrame::INTERNAL); FrameScope scope(masm, StackFrame::INTERNAL);
......
...@@ -4940,6 +4940,27 @@ void MacroAssembler::AllocateOneByteSlicedString(Register result, ...@@ -4940,6 +4940,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);
movp(FieldOperand(result, HeapObject::kMapOffset), scratch);
LoadRoot(scratch, Heap::kEmptyFixedArrayRootIndex);
movp(FieldOperand(result, JSObject::kPropertiesOffset), scratch);
movp(FieldOperand(result, JSObject::kElementsOffset), scratch);
movp(FieldOperand(result, JSValue::kValueOffset), value);
STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize);
}
// Copy memory, byte-by-byte, from source to destination. Not optimized for // Copy memory, byte-by-byte, from source to destination. Not optimized for
// long or aligned copies. The contents of scratch and length are destroyed. // long or aligned copies. The contents of scratch and length are destroyed.
// Destination is incremented by length, source, length and scratch are // Destination is incremented by length, source, length and scratch are
......
...@@ -1319,6 +1319,11 @@ class MacroAssembler: public Assembler { ...@@ -1319,6 +1319,11 @@ class MacroAssembler: public Assembler {
void AllocateOneByteSlicedString(Register result, Register scratch1, void AllocateOneByteSlicedString(Register result, Register scratch1,
Register scratch2, Label* gc_required); 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);
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Support functions. // Support functions.
......
...@@ -69,11 +69,9 @@ function testNotOmittedBuiltin(throwing, included) { ...@@ -69,11 +69,9 @@ function testNotOmittedBuiltin(throwing, included) {
testTraceNativeConversion(String); // Does ToString on argument. testTraceNativeConversion(String); // Does ToString on argument.
testTraceNativeConversion(Number); // Does ToNumber on argument.
testTraceNativeConversion(RegExp); // Does ToString on argument. testTraceNativeConversion(RegExp); // Does ToString on argument.
testTraceNativeConstructor(String); // Does ToString on argument. testTraceNativeConstructor(String); // Does ToString on argument.
testTraceNativeConstructor(Number); // Does ToNumber on argument.
testTraceNativeConstructor(RegExp); // Does ToString on argument. testTraceNativeConstructor(RegExp); // Does ToString on argument.
// QuickSort has builtins object as receiver, and is non-native // QuickSort has builtins object as receiver, and is non-native
......
...@@ -291,11 +291,9 @@ testUnintendedCallerCensorship(); ...@@ -291,11 +291,9 @@ testUnintendedCallerCensorship();
testErrorsDuringFormatting(); testErrorsDuringFormatting();
testTraceNativeConversion(String); // Does ToString on argument. testTraceNativeConversion(String); // Does ToString on argument.
testTraceNativeConversion(Number); // Does ToNumber on argument.
testTraceNativeConversion(RegExp); // Does ToString on argument. testTraceNativeConversion(RegExp); // Does ToString on argument.
testTraceNativeConstructor(String); // Does ToString on argument. testTraceNativeConstructor(String); // Does ToString on argument.
testTraceNativeConstructor(Number); // Does ToNumber on argument.
testTraceNativeConstructor(RegExp); // Does ToString on argument. testTraceNativeConstructor(RegExp); // Does ToString on argument.
// Omitted because QuickSort has builtins object as receiver, and is non-native // Omitted because QuickSort has builtins object as receiver, and is non-native
......
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