[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}
This commit is contained in:
parent
039dce1e35
commit
322ffda30d
@ -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
|
||||
void Builtins::Generate_StringConstructor(MacroAssembler* masm) {
|
||||
// ----------- S t a t e -------------
|
||||
@ -202,7 +302,10 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
|
||||
// -- 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).
|
||||
{
|
||||
Label no_arguments, done;
|
||||
@ -217,7 +320,7 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
|
||||
__ bind(&done);
|
||||
}
|
||||
|
||||
// 2. Make sure r2 is a string.
|
||||
// 3. Make sure r2 is a string.
|
||||
{
|
||||
Label convert, done_convert;
|
||||
__ JumpIfSmi(r2, &convert);
|
||||
@ -236,33 +339,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(r1, r3);
|
||||
__ b(ne, &new_object);
|
||||
|
||||
// 4. Allocate a JSValue wrapper for the string.
|
||||
{
|
||||
// ----------- S t a t e -------------
|
||||
// -- r2 : the first argument
|
||||
// -- r1 : constructor function
|
||||
// -- r3 : new target
|
||||
// -- lr : return address
|
||||
// -----------------------------------
|
||||
__ Allocate(JSValue::kSize, r0, r4, r5, &new_object, TAG_OBJECT);
|
||||
// 5. Allocate a JSValue wrapper for the string.
|
||||
__ AllocateJSValue(r0, r1, r2, r4, r5, &new_object);
|
||||
__ Ret();
|
||||
|
||||
// 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);
|
||||
{
|
||||
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
|
||||
|
@ -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,
|
||||
Register dst,
|
||||
Register length,
|
||||
|
@ -806,6 +806,12 @@ class MacroAssembler: public Assembler {
|
||||
Register heap_number_map,
|
||||
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
|
||||
// exit src and dst will point to the place just after where the last byte was
|
||||
// read or written and length will be zero.
|
||||
|
@ -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
|
||||
void Builtins::Generate_StringConstructor(MacroAssembler* masm) {
|
||||
// ----------- S t a t e -------------
|
||||
@ -206,7 +307,10 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
|
||||
// -----------------------------------
|
||||
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).
|
||||
{
|
||||
Label no_arguments, done;
|
||||
@ -221,7 +325,7 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
|
||||
__ Bind(&done);
|
||||
}
|
||||
|
||||
// 2. Make sure x2 is a string.
|
||||
// 3. Make sure x2 is a string.
|
||||
{
|
||||
Label convert, done_convert;
|
||||
__ JumpIfSmi(x2, &convert);
|
||||
@ -239,33 +343,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(x1, x3);
|
||||
__ B(ne, &new_object);
|
||||
|
||||
// 4. Allocate a JSValue wrapper for the string.
|
||||
{
|
||||
// ----------- S t a t e -------------
|
||||
// -- x2 : the first argument
|
||||
// -- x1 : constructor function
|
||||
// -- x3 : new target
|
||||
// -- lr : return address
|
||||
// -----------------------------------
|
||||
__ Allocate(JSValue::kSize, x0, x4, x5, &new_object, TAG_OBJECT);
|
||||
// 5. Allocate a JSValue wrapper for the string.
|
||||
__ AllocateJSValue(x0, x1, x2, x4, x5, &new_object);
|
||||
__ Ret();
|
||||
|
||||
// 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);
|
||||
{
|
||||
FrameScope scope(masm, StackFrame::INTERNAL);
|
||||
|
@ -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,
|
||||
Register map,
|
||||
Register type_reg,
|
||||
|
@ -1340,6 +1340,12 @@ class MacroAssembler : public Assembler {
|
||||
CPURegister heap_number_map = NoReg,
|
||||
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.
|
||||
|
||||
|
@ -1201,14 +1201,15 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
|
||||
}
|
||||
|
||||
{ // --- N u m b e r ---
|
||||
Handle<JSFunction> number_fun =
|
||||
InstallFunction(global, "Number", JS_VALUE_TYPE, JSValue::kSize,
|
||||
isolate->initial_object_prototype(),
|
||||
Builtins::kIllegal);
|
||||
Handle<JSFunction> number_fun = InstallFunction(
|
||||
global, "Number", JS_VALUE_TYPE, JSValue::kSize,
|
||||
isolate->initial_object_prototype(), Builtins::kNumberConstructor);
|
||||
number_fun->shared()->DontAdaptArguments();
|
||||
number_fun->shared()->set_construct_stub(
|
||||
*isolate->builtins()->NumberConstructor_ConstructStub());
|
||||
number_fun->shared()->set_length(1);
|
||||
InstallWithIntrinsicDefaultProto(isolate, number_fun,
|
||||
Context::NUMBER_FUNCTION_INDEX);
|
||||
number_fun->shared()->set_construct_stub(
|
||||
*isolate->builtins()->JSBuiltinsConstructStub());
|
||||
}
|
||||
|
||||
{ // --- B o o l e a n ---
|
||||
|
@ -246,6 +246,9 @@ inline bool operator&(BuiltinExtraArguments lhs, BuiltinExtraArguments rhs) {
|
||||
V(InternalArrayCode, 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_ConstructStub, BUILTIN, UNINITIALIZED, kNoExtraICState) \
|
||||
\
|
||||
@ -479,6 +482,11 @@ class Builtins {
|
||||
static void Generate_InternalArrayCode(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_ConstructStub(MacroAssembler* masm);
|
||||
static void Generate_OnStackReplacement(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
|
||||
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);
|
||||
// 5. Allocate a JSValue wrapper for the string.
|
||||
__ AllocateJSValue(eax, edi, ebx, ecx, &new_object);
|
||||
__ Ret();
|
||||
|
||||
// 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);
|
||||
{
|
||||
FrameScope scope(masm, StackFrame::INTERNAL);
|
||||
|
@ -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
|
||||
// long or aligned copies. The contents of scratch and length are destroyed.
|
||||
// Source and destination are incremented by length.
|
||||
|
@ -612,6 +612,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.
|
||||
@ -773,9 +778,11 @@ class MacroAssembler: public Assembler {
|
||||
void Move(XMMRegister dst, 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.
|
||||
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());
|
||||
|
@ -952,18 +952,6 @@ utils.InstallFunctions(GlobalBoolean.prototype, DONT_ENUM, [
|
||||
// ----------------------------------------------------------------------------
|
||||
// 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 ])
|
||||
function NumberToStringJS(radix) {
|
||||
// NOTE: Both Number objects and values can enter here as
|
||||
@ -1114,7 +1102,6 @@ function NumberIsSafeInteger(number) {
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
%SetCode(GlobalNumber, NumberConstructor);
|
||||
%FunctionSetPrototype(GlobalNumber, new GlobalNumber(0));
|
||||
|
||||
%OptimizeObjectForAddingMultipleProperties(GlobalNumber.prototype, 8);
|
||||
|
@ -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
|
||||
void Builtins::Generate_StringConstructor(MacroAssembler* masm) {
|
||||
// ----------- S t a t e -------------
|
||||
@ -211,7 +313,10 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
|
||||
// -- 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).
|
||||
{
|
||||
Label no_arguments, done;
|
||||
@ -228,7 +333,7 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
|
||||
__ bind(&done);
|
||||
}
|
||||
|
||||
// 2. Make sure a0 is a string.
|
||||
// 3. Make sure a0 is a string.
|
||||
{
|
||||
Label convert, done_convert;
|
||||
__ JumpIfSmi(a0, &convert);
|
||||
@ -247,32 +352,15 @@ 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;
|
||||
__ Branch(&new_object, ne, a1, Operand(a3));
|
||||
|
||||
// 4. Allocate a JSValue wrapper for the string.
|
||||
{
|
||||
// ----------- S t a t e -------------
|
||||
// -- a0 : the first argument
|
||||
// -- a1 : constructor function
|
||||
// -- a3 : new target
|
||||
// -- ra : return address
|
||||
// -----------------------------------
|
||||
__ Allocate(JSValue::kSize, v0, a2, t0, &new_object, TAG_OBJECT);
|
||||
// 5. Allocate a JSValue wrapper for the string.
|
||||
__ AllocateJSValue(v0, a1, a0, a2, t0, &new_object);
|
||||
__ Ret();
|
||||
|
||||
// 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);
|
||||
{
|
||||
FrameScope scope(masm, StackFrame::INTERNAL);
|
||||
@ -281,7 +369,7 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
|
||||
__ Pop(a0);
|
||||
}
|
||||
__ 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,
|
||||
}
|
||||
|
||||
|
||||
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,
|
||||
Register dst,
|
||||
Register length,
|
||||
|
@ -566,6 +566,12 @@ class MacroAssembler: public Assembler {
|
||||
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 scratch1, Register scratch2,
|
||||
Label* gc_required);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Instruction macros.
|
||||
|
||||
|
@ -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
|
||||
void Builtins::Generate_StringConstructor(MacroAssembler* masm) {
|
||||
// ----------- S t a t e -------------
|
||||
@ -209,7 +310,10 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
|
||||
// -- 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).
|
||||
{
|
||||
Label no_arguments, done;
|
||||
@ -226,7 +330,7 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
|
||||
__ bind(&done);
|
||||
}
|
||||
|
||||
// 2. Make sure a0 is a string.
|
||||
// 3. Make sure a0 is a string.
|
||||
{
|
||||
Label convert, done_convert;
|
||||
__ JumpIfSmi(a0, &convert);
|
||||
@ -245,32 +349,15 @@ 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;
|
||||
__ Branch(&new_object, ne, a1, Operand(a3));
|
||||
|
||||
// 4. Allocate a JSValue wrapper for the string.
|
||||
{
|
||||
// ----------- S t a t e -------------
|
||||
// -- a0 : the first argument
|
||||
// -- a1 : constructor function
|
||||
// -- a3 : new target
|
||||
// -- ra : return address
|
||||
// -----------------------------------
|
||||
__ Allocate(JSValue::kSize, v0, a2, t0, &new_object, TAG_OBJECT);
|
||||
// 5. Allocate a JSValue wrapper for the string.
|
||||
__ AllocateJSValue(v0, a1, a0, a2, t0, &new_object);
|
||||
__ Ret();
|
||||
|
||||
// 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);
|
||||
{
|
||||
FrameScope scope(masm, StackFrame::INTERNAL);
|
||||
@ -278,8 +365,8 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
|
||||
__ CallRuntime(Runtime::kNewObject);
|
||||
__ Pop(a0);
|
||||
}
|
||||
__ sd(a0, FieldMemOperand(v0, JSValue::kValueOffset));
|
||||
__ Ret();
|
||||
__ Ret(USE_DELAY_SLOT);
|
||||
__ sd(a0, FieldMemOperand(v0, JSValue::kValueOffset)); // In delay slot.
|
||||
}
|
||||
|
||||
|
||||
|
@ -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,
|
||||
Register dst,
|
||||
Register length,
|
||||
|
@ -595,6 +595,12 @@ class MacroAssembler: public Assembler {
|
||||
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 scratch1, Register scratch2,
|
||||
Label* gc_required);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Instruction macros.
|
||||
|
||||
|
@ -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
|
||||
void Builtins::Generate_StringConstructor(MacroAssembler* masm) {
|
||||
// ----------- S t a t e -------------
|
||||
@ -1514,7 +1623,10 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
|
||||
// -- 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).
|
||||
{
|
||||
StackArgumentsAccessor args(rsp, rax);
|
||||
@ -1531,7 +1643,7 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
|
||||
__ PushReturnAddressFrom(rcx);
|
||||
}
|
||||
|
||||
// 2. Make sure rbx is a string.
|
||||
// 3. Make sure rbx is a string.
|
||||
{
|
||||
Label convert, done_convert;
|
||||
__ JumpIfSmi(rbx, &convert, Label::kNear);
|
||||
@ -1552,32 +1664,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;
|
||||
__ cmpp(rdx, rdi);
|
||||
__ j(not_equal, &new_object);
|
||||
|
||||
// 4. Allocate a JSValue wrapper for the string.
|
||||
{
|
||||
// ----------- S t a t e -------------
|
||||
// -- rbx : the first argument
|
||||
// -- rdi : constructor function
|
||||
// -- rdx : new target
|
||||
// -----------------------------------
|
||||
__ Allocate(JSValue::kSize, rax, rcx, no_reg, &new_object, TAG_OBJECT);
|
||||
// 5. Allocate a JSValue wrapper for the string.
|
||||
__ AllocateJSValue(rax, rdi, rbx, rcx, &new_object);
|
||||
__ Ret();
|
||||
|
||||
// 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);
|
||||
{
|
||||
FrameScope scope(masm, StackFrame::INTERNAL);
|
||||
|
@ -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
|
||||
// long or aligned copies. The contents of scratch and length are destroyed.
|
||||
// Destination is incremented by length, source, length and scratch are
|
||||
|
@ -1319,6 +1319,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);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Support functions.
|
||||
|
||||
|
@ -69,11 +69,9 @@ function testNotOmittedBuiltin(throwing, included) {
|
||||
|
||||
|
||||
testTraceNativeConversion(String); // Does ToString on argument.
|
||||
testTraceNativeConversion(Number); // Does ToNumber on argument.
|
||||
testTraceNativeConversion(RegExp); // Does ToString on argument.
|
||||
|
||||
testTraceNativeConstructor(String); // Does ToString on argument.
|
||||
testTraceNativeConstructor(Number); // Does ToNumber on argument.
|
||||
testTraceNativeConstructor(RegExp); // Does ToString on argument.
|
||||
|
||||
// QuickSort has builtins object as receiver, and is non-native
|
||||
|
@ -291,11 +291,9 @@ testUnintendedCallerCensorship();
|
||||
testErrorsDuringFormatting();
|
||||
|
||||
testTraceNativeConversion(String); // Does ToString on argument.
|
||||
testTraceNativeConversion(Number); // Does ToNumber on argument.
|
||||
testTraceNativeConversion(RegExp); // Does ToString on argument.
|
||||
|
||||
testTraceNativeConstructor(String); // Does ToString on argument.
|
||||
testTraceNativeConstructor(Number); // Does ToNumber on argument.
|
||||
testTraceNativeConstructor(RegExp); // Does ToString on argument.
|
||||
|
||||
// Omitted because QuickSort has builtins object as receiver, and is non-native
|
||||
|
Loading…
Reference in New Issue
Block a user