[builtins] Construct builtin frame in String/Number ctors

BUG=v8:5173
R=bmeurer@chromium.org

Review-Url: https://codereview.chromium.org/2118283003
Cr-Commit-Position: refs/heads/master@{#37598}
This commit is contained in:
jgruber 2016-07-07 23:35:14 -07:00 committed by Commit bot
parent 1f53e42bd6
commit d49d3864d7
22 changed files with 803 additions and 375 deletions

View File

@ -166,15 +166,17 @@ void Builtins::Generate_MathMaxMin(MacroAssembler* masm, MathMaxMinKind kind) {
// Parameter is not a Number, use the ToNumber builtin to convert it.
DCHECK(!FLAG_enable_embedded_constant_pool);
FrameScope scope(masm, StackFrame::MANUAL);
__ Push(lr, fp, cp, r1);
__ add(fp, sp, Operand(2 * kPointerSize));
__ SmiTag(r0);
__ SmiTag(r4);
__ Push(r0, r4, r5);
__ EnterBuiltinFrame(cp, r1, r0);
__ Push(r4, r5);
__ mov(r0, r2);
__ Call(masm->isolate()->builtins()->ToNumber(), RelocInfo::CODE_TARGET);
__ mov(r2, r0);
__ Pop(r0, r4, r5);
__ Pop(r4, r5);
__ LeaveBuiltinFrame(cp, r1, r0);
__ SmiUntag(r4);
__ SmiUntag(r0);
{
// Restore the double accumulator value (d1).
Label done_restore;
@ -183,9 +185,6 @@ void Builtins::Generate_MathMaxMin(MacroAssembler* masm, MathMaxMinKind kind) {
__ vldr(d1, FieldMemOperand(r5, HeapNumber::kValueOffset));
__ bind(&done_restore);
}
__ SmiUntag(r4);
__ SmiUntag(r0);
__ Pop(lr, fp, cp, r1);
}
__ b(&convert);
__ bind(&convert_number);
@ -234,23 +233,36 @@ void Builtins::Generate_NumberConstructor(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- r0 : number of arguments
// -- r1 : constructor function
// -- cp : context
// -- 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).
// 1. Load the first argument into r0.
Label no_arguments;
{
__ mov(r2, r0); // Store argc in r2.
__ sub(r0, r0, Operand(1), SetCC);
__ b(lo, &no_arguments);
__ ldr(r0, MemOperand(sp, r0, LSL, kPointerSizeLog2, PreIndex));
__ Drop(2);
__ ldr(r0, MemOperand(sp, r0, LSL, kPointerSizeLog2));
}
// 2a. Convert the first argument to a number.
__ Jump(masm->isolate()->builtins()->ToNumber(), RelocInfo::CODE_TARGET);
{
FrameScope scope(masm, StackFrame::MANUAL);
__ SmiTag(r2);
__ EnterBuiltinFrame(cp, r1, r2);
__ Call(masm->isolate()->builtins()->ToNumber(), RelocInfo::CODE_TARGET);
__ LeaveBuiltinFrame(cp, r1, r2);
__ SmiUntag(r2);
}
{
// Drop all arguments including the receiver.
__ Drop(r2);
__ Ret(1);
}
// 2b. No arguments, return +0.
__ bind(&no_arguments);
@ -265,6 +277,7 @@ void Builtins::Generate_NumberConstructor_ConstructStub(MacroAssembler* masm) {
// -- r0 : number of arguments
// -- r1 : constructor function
// -- r3 : new target
// -- cp : context
// -- lr : return address
// -- sp[(argc - n - 1) * 4] : arg[n] (zero based)
// -- sp[argc * 4] : receiver
@ -273,18 +286,16 @@ void Builtins::Generate_NumberConstructor_ConstructStub(MacroAssembler* masm) {
// 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).
// 2. Load the first argument into r2.
{
Label no_arguments, done;
__ mov(r6, r0); // Store argc in r6.
__ sub(r0, r0, Operand(1), SetCC);
__ b(lo, &no_arguments);
__ ldr(r2, MemOperand(sp, r0, LSL, kPointerSizeLog2, PreIndex));
__ Drop(2);
__ ldr(r2, MemOperand(sp, r0, LSL, kPointerSizeLog2));
__ b(&done);
__ bind(&no_arguments);
__ Move(r2, Smi::FromInt(0));
__ Drop(1);
__ bind(&done);
}
@ -295,36 +306,49 @@ void Builtins::Generate_NumberConstructor_ConstructStub(MacroAssembler* masm) {
__ CompareObjectType(r2, r4, r4, HEAP_NUMBER_TYPE);
__ b(eq, &done_convert);
{
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
__ Push(r1, r3);
FrameScope scope(masm, StackFrame::MANUAL);
__ SmiTag(r6);
__ EnterBuiltinFrame(cp, r1, r6);
__ Push(r3);
__ Move(r0, r2);
__ Call(masm->isolate()->builtins()->ToNumber(), RelocInfo::CODE_TARGET);
__ Move(r2, r0);
__ Pop(r1, r3);
__ Pop(r3);
__ LeaveBuiltinFrame(cp, r1, r6);
__ SmiUntag(r6);
}
__ bind(&done_convert);
}
// 4. Check if new target and constructor differ.
Label new_object;
Label drop_frame_and_ret, 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();
__ b(&drop_frame_and_ret);
// 6. Fallback to the runtime to create new object.
__ bind(&new_object);
{
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
__ Push(r2); // first argument
FrameScope scope(masm, StackFrame::MANUAL);
FastNewObjectStub stub(masm->isolate());
__ SmiTag(r6);
__ EnterBuiltinFrame(cp, r1, r6);
__ Push(r2); // first argument
__ CallStub(&stub);
__ Pop(r2);
__ LeaveBuiltinFrame(cp, r1, r6);
__ SmiUntag(r6);
}
__ str(r2, FieldMemOperand(r0, JSValue::kValueOffset));
__ Ret();
__ bind(&drop_frame_and_ret);
{
__ Drop(r6);
__ Ret(1);
}
}
@ -333,31 +357,31 @@ void Builtins::Generate_StringConstructor(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- r0 : number of arguments
// -- r1 : constructor function
// -- cp : context
// -- 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).
// 1. Load the first argument into r0.
Label no_arguments;
{
__ mov(r2, r0); // Store argc in r2.
__ sub(r0, r0, Operand(1), SetCC);
__ b(lo, &no_arguments);
__ ldr(r0, MemOperand(sp, r0, LSL, kPointerSizeLog2, PreIndex));
__ Drop(2);
__ ldr(r0, MemOperand(sp, r0, LSL, kPointerSizeLog2));
}
// 2a. At least one argument, return r0 if it's a string, otherwise
// dispatch to appropriate conversion.
Label to_string, symbol_descriptive_string;
Label drop_frame_and_ret, to_string, symbol_descriptive_string;
{
__ JumpIfSmi(r0, &to_string);
STATIC_ASSERT(FIRST_NONSTRING_TYPE == SYMBOL_TYPE);
__ CompareObjectType(r0, r1, r1, FIRST_NONSTRING_TYPE);
__ CompareObjectType(r0, r3, r3, FIRST_NONSTRING_TYPE);
__ b(hi, &to_string);
__ b(eq, &symbol_descriptive_string);
__ Ret();
__ b(&drop_frame_and_ret);
}
// 2b. No arguments, return the empty string (and pop the receiver).
@ -370,16 +394,30 @@ void Builtins::Generate_StringConstructor(MacroAssembler* masm) {
// 3a. Convert r0 to a string.
__ bind(&to_string);
{
FrameScope scope(masm, StackFrame::MANUAL);
ToStringStub stub(masm->isolate());
__ TailCallStub(&stub);
__ SmiTag(r2);
__ EnterBuiltinFrame(cp, r1, r2);
__ CallStub(&stub);
__ LeaveBuiltinFrame(cp, r1, r2);
__ SmiUntag(r2);
}
__ b(&drop_frame_and_ret);
// 3b. Convert symbol in r0 to a string.
__ bind(&symbol_descriptive_string);
{
__ Drop(r2);
__ Drop(1);
__ Push(r0);
__ TailCallRuntime(Runtime::kSymbolDescriptiveString);
}
__ bind(&drop_frame_and_ret);
{
__ Drop(r2);
__ Ret(1);
}
}
@ -389,6 +427,7 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
// -- r0 : number of arguments
// -- r1 : constructor function
// -- r3 : new target
// -- cp : context
// -- lr : return address
// -- sp[(argc - n - 1) * 4] : arg[n] (zero based)
// -- sp[argc * 4] : receiver
@ -397,18 +436,16 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
// 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).
// 2. Load the first argument into r2.
{
Label no_arguments, done;
__ mov(r6, r0); // Store argc in r6.
__ sub(r0, r0, Operand(1), SetCC);
__ b(lo, &no_arguments);
__ ldr(r2, MemOperand(sp, r0, LSL, kPointerSizeLog2, PreIndex));
__ Drop(2);
__ ldr(r2, MemOperand(sp, r0, LSL, kPointerSizeLog2));
__ b(&done);
__ bind(&no_arguments);
__ LoadRoot(r2, Heap::kempty_stringRootIndex);
__ Drop(1);
__ bind(&done);
}
@ -420,37 +457,50 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
__ b(lo, &done_convert);
__ bind(&convert);
{
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
FrameScope scope(masm, StackFrame::MANUAL);
ToStringStub stub(masm->isolate());
__ Push(r1, r3);
__ SmiTag(r6);
__ EnterBuiltinFrame(cp, r1, r6);
__ Push(r3);
__ Move(r0, r2);
__ CallStub(&stub);
__ Move(r2, r0);
__ Pop(r1, r3);
__ Pop(r3);
__ LeaveBuiltinFrame(cp, r1, r6);
__ SmiUntag(r6);
}
__ bind(&done_convert);
}
// 4. Check if new target and constructor differ.
Label new_object;
Label drop_frame_and_ret, new_object;
__ cmp(r1, r3);
__ b(ne, &new_object);
// 5. Allocate a JSValue wrapper for the string.
__ AllocateJSValue(r0, r1, r2, r4, r5, &new_object);
__ Ret();
__ b(&drop_frame_and_ret);
// 6. Fallback to the runtime to create new object.
__ bind(&new_object);
{
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
__ Push(r2); // first argument
FrameScope scope(masm, StackFrame::MANUAL);
FastNewObjectStub stub(masm->isolate());
__ SmiTag(r6);
__ EnterBuiltinFrame(cp, r1, r6);
__ Push(r2); // first argument
__ CallStub(&stub);
__ Pop(r2);
__ LeaveBuiltinFrame(cp, r1, r6);
__ SmiUntag(r6);
}
__ str(r2, FieldMemOperand(r0, JSValue::kValueOffset));
__ Ret();
__ bind(&drop_frame_and_ret);
{
__ Drop(r6);
__ Ret(1);
}
}
@ -1806,10 +1856,9 @@ void Builtins::Generate_DatePrototype_GetField(MacroAssembler* masm,
__ bind(&receiver_not_date);
{
FrameScope scope(masm, StackFrame::MANUAL);
__ Push(r0, lr, fp);
__ Move(fp, sp);
__ Push(cp, r1);
__ Push(Smi::FromInt(0));
__ Push(r0);
__ Move(r0, Smi::FromInt(0));
__ EnterBuiltinFrame(cp, r1, r0);
__ CallRuntime(Runtime::kThrowNotDateError);
}
}

View File

@ -1284,6 +1284,19 @@ int MacroAssembler::LeaveFrame(StackFrame::Type type) {
return frame_ends;
}
void MacroAssembler::EnterBuiltinFrame(Register context, Register target,
Register argc) {
Push(lr, fp, context, target);
add(fp, sp, Operand(2 * kPointerSize));
Push(argc);
}
void MacroAssembler::LeaveBuiltinFrame(Register context, Register target,
Register argc) {
Pop(argc);
Pop(lr, fp, context, target);
}
void MacroAssembler::EnterExitFrame(bool save_doubles, int stack_space,
StackFrame::Type frame_type) {
DCHECK(frame_type == StackFrame::EXIT ||

View File

@ -1438,6 +1438,9 @@ class MacroAssembler: public Assembler {
// Returns the pc offset at which the frame ends.
int LeaveFrame(StackFrame::Type type);
void EnterBuiltinFrame(Register context, Register target, Register argc);
void LeaveBuiltinFrame(Register context, Register target, Register argc);
// Expects object in r0 and returns map with validated enum cache
// in r0. Assumes that any other register can be used as a scratch.
void CheckEnumCache(Label* call_runtime);

View File

@ -163,16 +163,17 @@ void Builtins::Generate_MathMaxMin(MacroAssembler* masm, MathMaxMinKind kind) {
{
// Parameter is not a Number, use the ToNumber builtin to convert it.
FrameScope scope(masm, StackFrame::MANUAL);
__ Push(lr, fp);
__ Move(fp, jssp);
__ Push(cp, x1);
__ SmiTag(x0);
__ SmiTag(x4);
__ Push(x0, x5, x4);
__ EnterBuiltinFrame(cp, x1, x0);
__ Push(x5, x4);
__ Mov(x0, x2);
__ Call(masm->isolate()->builtins()->ToNumber(), RelocInfo::CODE_TARGET);
__ Mov(x2, x0);
__ Pop(x4, x5, x0);
__ Pop(x4, x5);
__ LeaveBuiltinFrame(cp, x1, x0);
__ SmiUntag(x4);
__ SmiUntag(x0);
{
// Restore the double accumulator value (d5).
Label done_restore;
@ -181,9 +182,6 @@ void Builtins::Generate_MathMaxMin(MacroAssembler* masm, MathMaxMinKind kind) {
__ Ldr(d5, FieldMemOperand(x5, HeapNumber::kValueOffset));
__ Bind(&done_restore);
}
__ SmiUntag(x4);
__ SmiUntag(x0);
__ Pop(x1, cp, fp, lr);
}
__ AssertNumber(x2);
__ JumpIfSmi(x2, &convert_smi);
@ -224,24 +222,36 @@ void Builtins::Generate_NumberConstructor(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- x0 : number of arguments
// -- x1 : constructor function
// -- cp : context
// -- 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).
// 1. Load the first argument into x0.
Label no_arguments;
{
__ Cbz(x0, &no_arguments);
__ Mov(x2, x0); // Store argc in x2.
__ Sub(x0, x0, 1);
__ Drop(x0);
__ Ldr(x0, MemOperand(jssp, 2 * kPointerSize, PostIndex));
__ Ldr(x0, MemOperand(jssp, x0, LSL, kPointerSizeLog2));
}
// 2a. Convert first argument to number.
__ Jump(masm->isolate()->builtins()->ToNumber(), RelocInfo::CODE_TARGET);
{
FrameScope scope(masm, StackFrame::MANUAL);
__ SmiTag(x2);
__ EnterBuiltinFrame(cp, x1, x2);
__ Call(masm->isolate()->builtins()->ToNumber(), RelocInfo::CODE_TARGET);
__ LeaveBuiltinFrame(cp, x1, x2);
__ SmiUntag(x2);
}
{
// Drop all arguments.
__ Drop(x2);
}
// 2b. No arguments, return +0 (already in x0).
__ Bind(&no_arguments);
@ -256,6 +266,7 @@ void Builtins::Generate_NumberConstructor_ConstructStub(MacroAssembler* masm) {
// -- x0 : number of arguments
// -- x1 : constructor function
// -- x3 : new target
// -- cp : context
// -- lr : return address
// -- sp[(argc - n - 1) * 8] : arg[n] (zero based)
// -- sp[argc * 8] : receiver
@ -265,17 +276,15 @@ void Builtins::Generate_NumberConstructor_ConstructStub(MacroAssembler* masm) {
// 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).
// 2. Load the first argument into x2.
{
Label no_arguments, done;
__ Move(x6, x0); // Store argc in x6.
__ Cbz(x0, &no_arguments);
__ Sub(x0, x0, 1);
__ Drop(x0);
__ Ldr(x2, MemOperand(jssp, 2 * kPointerSize, PostIndex));
__ Ldr(x2, MemOperand(jssp, x0, LSL, kPointerSizeLog2));
__ B(&done);
__ Bind(&no_arguments);
__ Drop(1);
__ Mov(x2, Smi::FromInt(0));
__ Bind(&done);
}
@ -286,36 +295,50 @@ void Builtins::Generate_NumberConstructor_ConstructStub(MacroAssembler* masm) {
__ JumpIfSmi(x2, &done_convert);
__ JumpIfObjectType(x2, x4, x4, HEAP_NUMBER_TYPE, &done_convert, eq);
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ Push(x1, x3);
FrameScope scope(masm, StackFrame::MANUAL);
__ SmiTag(x6);
__ EnterBuiltinFrame(cp, x1, x6);
__ Push(x3);
__ Move(x0, x2);
__ Call(masm->isolate()->builtins()->ToNumber(), RelocInfo::CODE_TARGET);
__ Move(x2, x0);
__ Pop(x3, x1);
__ Pop(x3);
__ LeaveBuiltinFrame(cp, x1, x6);
__ SmiUntag(x6);
}
__ Bind(&done_convert);
}
// 4. Check if new target and constructor differ.
Label new_object;
Label drop_frame_and_ret, 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();
__ B(&drop_frame_and_ret);
// 6. Fallback to the runtime to create new object.
__ bind(&new_object);
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ Push(x2); // first argument
FrameScope scope(masm, StackFrame::MANUAL);
FastNewObjectStub stub(masm->isolate());
__ SmiTag(x6);
__ EnterBuiltinFrame(cp, x1, x6);
__ Push(x2); // first argument
__ CallStub(&stub);
__ Pop(x2);
__ LeaveBuiltinFrame(cp, x1, x6);
__ SmiUntag(x6);
}
__ Str(x2, FieldMemOperand(x0, JSValue::kValueOffset));
__ Ret();
__ bind(&drop_frame_and_ret);
{
__ Drop(x6);
__ Drop(1);
__ Ret();
}
}
@ -324,32 +347,32 @@ void Builtins::Generate_StringConstructor(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- x0 : number of arguments
// -- x1 : constructor function
// -- cp : context
// -- lr : return address
// -- sp[(argc - n - 1) * 8] : arg[n] (zero based)
// -- sp[argc * 8] : receiver
// -----------------------------------
ASM_LOCATION("Builtins::Generate_StringConstructor");
// 1. Load the first argument into x0 and get rid of the rest (including the
// receiver).
// 1. Load the first argument into x0.
Label no_arguments;
{
__ Cbz(x0, &no_arguments);
__ Mov(x2, x0); // Store argc in x2.
__ Sub(x0, x0, 1);
__ Drop(x0);
__ Ldr(x0, MemOperand(jssp, 2 * kPointerSize, PostIndex));
__ Ldr(x0, MemOperand(jssp, x0, LSL, kPointerSizeLog2));
}
// 2a. At least one argument, return x0 if it's a string, otherwise
// dispatch to appropriate conversion.
Label to_string, symbol_descriptive_string;
Label drop_frame_and_ret, to_string, symbol_descriptive_string;
{
__ JumpIfSmi(x0, &to_string);
STATIC_ASSERT(FIRST_NONSTRING_TYPE == SYMBOL_TYPE);
__ CompareObjectType(x0, x1, x1, FIRST_NONSTRING_TYPE);
__ CompareObjectType(x0, x3, x3, FIRST_NONSTRING_TYPE);
__ B(hi, &to_string);
__ B(eq, &symbol_descriptive_string);
__ Ret();
__ b(&drop_frame_and_ret);
}
// 2b. No arguments, return the empty string (and pop the receiver).
@ -363,16 +386,31 @@ void Builtins::Generate_StringConstructor(MacroAssembler* masm) {
// 3a. Convert x0 to a string.
__ Bind(&to_string);
{
FrameScope scope(masm, StackFrame::MANUAL);
ToStringStub stub(masm->isolate());
__ TailCallStub(&stub);
__ SmiTag(x2);
__ EnterBuiltinFrame(cp, x1, x2);
__ CallStub(&stub);
__ LeaveBuiltinFrame(cp, x1, x2);
__ SmiUntag(x2);
}
__ b(&drop_frame_and_ret);
// 3b. Convert symbol in x0 to a string.
__ Bind(&symbol_descriptive_string);
{
__ Drop(x2);
__ Drop(1);
__ Push(x0);
__ TailCallRuntime(Runtime::kSymbolDescriptiveString);
}
__ bind(&drop_frame_and_ret);
{
__ Drop(x2);
__ Drop(1);
__ Ret();
}
}
@ -382,6 +420,7 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
// -- x0 : number of arguments
// -- x1 : constructor function
// -- x3 : new target
// -- cp : context
// -- lr : return address
// -- sp[(argc - n - 1) * 8] : arg[n] (zero based)
// -- sp[argc * 8] : receiver
@ -391,17 +430,15 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
// 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).
// 2. Load the first argument into x2.
{
Label no_arguments, done;
__ mov(x6, x0); // Store argc in x6.
__ Cbz(x0, &no_arguments);
__ Sub(x0, x0, 1);
__ Drop(x0);
__ Ldr(x2, MemOperand(jssp, 2 * kPointerSize, PostIndex));
__ Ldr(x2, MemOperand(jssp, x0, LSL, kPointerSizeLog2));
__ B(&done);
__ Bind(&no_arguments);
__ Drop(1);
__ LoadRoot(x2, Heap::kempty_stringRootIndex);
__ Bind(&done);
}
@ -413,37 +450,51 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
__ JumpIfObjectType(x2, x4, x4, FIRST_NONSTRING_TYPE, &done_convert, lo);
__ Bind(&convert);
{
FrameScope scope(masm, StackFrame::INTERNAL);
FrameScope scope(masm, StackFrame::MANUAL);
ToStringStub stub(masm->isolate());
__ Push(x1, x3);
__ SmiTag(x6);
__ EnterBuiltinFrame(cp, x1, x6);
__ Push(x3);
__ Move(x0, x2);
__ CallStub(&stub);
__ Move(x2, x0);
__ Pop(x3, x1);
__ Pop(x3);
__ LeaveBuiltinFrame(cp, x1, x6);
__ SmiUntag(x6);
}
__ Bind(&done_convert);
}
// 4. Check if new target and constructor differ.
Label new_object;
Label drop_frame_and_ret, new_object;
__ Cmp(x1, x3);
__ B(ne, &new_object);
// 5. Allocate a JSValue wrapper for the string.
__ AllocateJSValue(x0, x1, x2, x4, x5, &new_object);
__ Ret();
__ B(&drop_frame_and_ret);
// 6. Fallback to the runtime to create new object.
__ bind(&new_object);
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ Push(x2); // first argument
FrameScope scope(masm, StackFrame::MANUAL);
FastNewObjectStub stub(masm->isolate());
__ SmiTag(x6);
__ EnterBuiltinFrame(cp, x1, x6);
__ Push(x2); // first argument
__ CallStub(&stub);
__ Pop(x2);
__ LeaveBuiltinFrame(cp, x1, x6);
__ SmiUntag(x6);
}
__ Str(x2, FieldMemOperand(x0, JSValue::kValueOffset));
__ Ret();
__ bind(&drop_frame_and_ret);
{
__ Drop(x6);
__ Drop(1);
__ Ret();
}
}
static void GenerateTailCallToSharedCode(MacroAssembler* masm) {
@ -1811,10 +1862,9 @@ void Builtins::Generate_DatePrototype_GetField(MacroAssembler* masm,
__ Bind(&receiver_not_date);
{
FrameScope scope(masm, StackFrame::MANUAL);
__ Push(x0, lr, fp);
__ Move(fp, jssp);
__ Push(cp, x1);
__ Push(Smi::FromInt(0));
__ Push(x0);
__ Mov(x0, Smi::FromInt(0));
__ EnterBuiltinFrame(cp, x1, x0);
__ CallRuntime(Runtime::kThrowNotDateError);
}
}

View File

@ -2823,6 +2823,19 @@ void MacroAssembler::ExitFrameRestoreFPRegs() {
}
}
void MacroAssembler::EnterBuiltinFrame(Register context, Register target,
Register argc) {
Push(lr, fp, context, target);
add(fp, jssp, Operand(2 * kPointerSize));
Push(argc);
}
void MacroAssembler::LeaveBuiltinFrame(Register context, Register target,
Register argc) {
Pop(argc);
Pop(target, context, fp, lr);
}
void MacroAssembler::EnterExitFrame(bool save_doubles, const Register& scratch,
int extra_space,
StackFrame::Type frame_type) {

View File

@ -1642,6 +1642,9 @@ class MacroAssembler : public Assembler {
void EnterFrame(StackFrame::Type type, bool load_constant_pool_pointer_reg);
void LeaveFrame(StackFrame::Type type);
void EnterBuiltinFrame(Register context, Register target, Register argc);
void LeaveBuiltinFrame(Register context, Register target, Register argc);
// Returns map with validated enum cache in object register.
void CheckEnumCache(Register object, Register scratch0, Register scratch1,
Register scratch2, Register scratch3, Register scratch4,

View File

@ -1272,11 +1272,8 @@ void Builtins::Generate_DatePrototype_GetField(MacroAssembler* masm,
__ bind(&receiver_not_date);
{
FrameScope scope(masm, StackFrame::MANUAL);
__ Push(ebp);
__ Move(ebp, esp);
__ Push(esi);
__ Push(edi);
__ Push(Immediate(0));
__ Move(ebx, Immediate(0));
__ EnterBuiltinFrame(esi, edi, ebx);
__ CallRuntime(Runtime::kThrowNotDateError);
}
}
@ -1648,13 +1645,9 @@ void Builtins::Generate_MathMaxMin(MacroAssembler* masm, MathMaxMinKind kind) {
{
// Parameter is not a Number, use the ToNumber builtin to convert it.
FrameScope scope(masm, StackFrame::MANUAL);
__ Push(ebp);
__ Move(ebp, esp);
__ Push(esi);
__ Push(edi);
__ SmiTag(eax);
__ SmiTag(ecx);
__ Push(eax);
__ EnterBuiltinFrame(esi, edi, eax);
__ Push(ecx);
__ Push(edx);
__ mov(eax, ebx);
@ -1662,9 +1655,9 @@ void Builtins::Generate_MathMaxMin(MacroAssembler* masm, MathMaxMinKind kind) {
__ mov(ebx, eax);
__ Pop(edx);
__ Pop(ecx);
__ Pop(eax);
__ Pop(edi);
__ Pop(esi);
__ LeaveBuiltinFrame(esi, edi, eax);
__ SmiUntag(ecx);
__ SmiUntag(eax);
{
// Restore the double accumulator value (xmm0).
Label restore_smi, done_restore;
@ -1677,9 +1670,6 @@ void Builtins::Generate_MathMaxMin(MacroAssembler* masm, MathMaxMinKind kind) {
__ SmiTag(edx);
__ bind(&done_restore);
}
__ SmiUntag(ecx);
__ SmiUntag(eax);
__ leave();
}
__ jmp(&convert);
__ bind(&convert_number);
@ -1737,26 +1727,38 @@ void Builtins::Generate_NumberConstructor(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- eax : number of arguments
// -- edi : constructor function
// -- esi : context
// -- 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).
// 1. Load the first argument into ebx.
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.
__ Jump(masm->isolate()->builtins()->ToNumber(), RelocInfo::CODE_TARGET);
{
FrameScope scope(masm, StackFrame::MANUAL);
__ SmiTag(eax);
__ EnterBuiltinFrame(esi, edi, eax);
__ mov(eax, ebx);
__ Call(masm->isolate()->builtins()->ToNumber(), RelocInfo::CODE_TARGET);
__ LeaveBuiltinFrame(esi, edi, ebx); // Argc popped to ebx.
__ SmiUntag(ebx);
}
{
// Drop all arguments including the receiver.
__ PopReturnAddressTo(ecx);
__ lea(esp, Operand(esp, ebx, times_pointer_size, kPointerSize));
__ PushReturnAddressFrom(ecx);
__ Ret();
}
// 2b. No arguments, return +0 (already in eax).
__ bind(&no_arguments);
@ -1770,6 +1772,7 @@ void Builtins::Generate_NumberConstructor_ConstructStub(MacroAssembler* masm) {
// -- eax : number of arguments
// -- edi : constructor function
// -- edx : new target
// -- esi : context
// -- esp[0] : return address
// -- esp[(argc - n) * 4] : arg[n] (zero-based)
// -- esp[(argc + 1) * 4] : receiver
@ -1778,8 +1781,11 @@ void Builtins::Generate_NumberConstructor_ConstructStub(MacroAssembler* masm) {
// 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).
// Store argc in r8.
__ mov(ecx, eax);
__ SmiTag(ecx);
// 2. Load the first argument into ebx.
{
Label no_arguments, done;
__ test(eax, eax);
@ -1789,9 +1795,6 @@ void Builtins::Generate_NumberConstructor_ConstructStub(MacroAssembler* masm) {
__ 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.
@ -1802,37 +1805,51 @@ void Builtins::Generate_NumberConstructor_ConstructStub(MacroAssembler* masm) {
Heap::kHeapNumberMapRootIndex);
__ j(equal, &done_convert);
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ Push(edi);
FrameScope scope(masm, StackFrame::MANUAL);
__ EnterBuiltinFrame(esi, edi, ecx);
__ Push(edx);
__ Move(eax, ebx);
__ Call(masm->isolate()->builtins()->ToNumber(), RelocInfo::CODE_TARGET);
__ Move(ebx, eax);
__ Pop(edx);
__ Pop(edi);
__ LeaveBuiltinFrame(esi, edi, ecx);
}
__ bind(&done_convert);
}
// 4. Check if new target and constructor differ.
Label new_object;
Label drop_frame_and_ret, done_alloc, 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();
__ AllocateJSValue(eax, edi, ebx, esi, &done_alloc);
__ jmp(&drop_frame_and_ret);
__ bind(&done_alloc);
__ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); // Restore esi.
// 6. Fallback to the runtime to create new object.
__ bind(&new_object);
{
FrameScope scope(masm, StackFrame::INTERNAL);
FrameScope scope(masm, StackFrame::MANUAL);
__ EnterBuiltinFrame(esi, edi, ecx);
__ Push(ebx); // the first argument
FastNewObjectStub stub(masm->isolate());
__ CallStub(&stub);
__ Pop(FieldOperand(eax, JSValue::kValueOffset));
__ LeaveBuiltinFrame(esi, edi, ecx);
}
__ bind(&drop_frame_and_ret);
{
// Drop all arguments including the receiver.
__ PopReturnAddressTo(esi);
__ SmiUntag(ecx);
__ lea(esp, Operand(esp, ecx, times_pointer_size, kPointerSize));
__ PushReturnAddressFrom(esi);
__ Ret();
}
__ Ret();
}
@ -1841,34 +1858,31 @@ void Builtins::Generate_StringConstructor(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- eax : number of arguments
// -- edi : constructor function
// -- esi : context
// -- 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).
// 1. Load the first argument into eax.
Label no_arguments;
{
__ mov(ebx, eax); // Store argc in ebx.
__ 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);
__ mov(eax, Operand(esp, eax, times_pointer_size, 0));
}
// 2a. At least one argument, return eax if it's a string, otherwise
// dispatch to appropriate conversion.
Label to_string, symbol_descriptive_string;
Label drop_frame_and_ret, to_string, symbol_descriptive_string;
{
__ JumpIfSmi(eax, &to_string, Label::kNear);
STATIC_ASSERT(FIRST_NONSTRING_TYPE == SYMBOL_TYPE);
__ CmpObjectType(eax, FIRST_NONSTRING_TYPE, edx);
__ j(above, &to_string, Label::kNear);
__ j(equal, &symbol_descriptive_string, Label::kNear);
__ Ret();
__ jmp(&drop_frame_and_ret, Label::kNear);
}
// 2b. No arguments, return the empty string (and pop the receiver).
@ -1881,18 +1895,34 @@ void Builtins::Generate_StringConstructor(MacroAssembler* masm) {
// 3a. Convert eax to a string.
__ bind(&to_string);
{
FrameScope scope(masm, StackFrame::MANUAL);
ToStringStub stub(masm->isolate());
__ TailCallStub(&stub);
__ SmiTag(ebx);
__ EnterBuiltinFrame(esi, edi, ebx);
__ CallStub(&stub);
__ LeaveBuiltinFrame(esi, edi, ebx);
__ SmiUntag(ebx);
}
__ jmp(&drop_frame_and_ret, Label::kNear);
// 3b. Convert symbol in eax to a string.
__ bind(&symbol_descriptive_string);
{
__ PopReturnAddressTo(ecx);
__ lea(esp, Operand(esp, ebx, times_pointer_size, kPointerSize));
__ Push(eax);
__ PushReturnAddressFrom(ecx);
__ TailCallRuntime(Runtime::kSymbolDescriptiveString);
}
__ bind(&drop_frame_and_ret);
{
// Drop all arguments including the receiver.
__ PopReturnAddressTo(ecx);
__ lea(esp, Operand(esp, ebx, times_pointer_size, kPointerSize));
__ PushReturnAddressFrom(ecx);
__ Ret();
}
}
@ -1902,6 +1932,7 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
// -- eax : number of arguments
// -- edi : constructor function
// -- edx : new target
// -- esi : context
// -- esp[0] : return address
// -- esp[(argc - n) * 4] : arg[n] (zero-based)
// -- esp[(argc + 1) * 4] : receiver
@ -1910,62 +1941,82 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
// 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).
__ mov(ebx, eax);
// 2. Load the first argument into eax.
{
Label no_arguments, done;
__ test(eax, eax);
__ test(ebx, ebx);
__ j(zero, &no_arguments, Label::kNear);
__ mov(ebx, Operand(esp, eax, times_pointer_size, 0));
__ mov(eax, Operand(esp, ebx, times_pointer_size, 0));
__ jmp(&done, Label::kNear);
__ bind(&no_arguments);
__ LoadRoot(ebx, Heap::kempty_stringRootIndex);
__ LoadRoot(eax, Heap::kempty_stringRootIndex);
__ bind(&done);
__ PopReturnAddressTo(ecx);
__ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
__ PushReturnAddressFrom(ecx);
}
// 3. Make sure ebx is a string.
// 3. Make sure eax is a string.
{
Label convert, done_convert;
__ JumpIfSmi(ebx, &convert, Label::kNear);
__ CmpObjectType(ebx, FIRST_NONSTRING_TYPE, ecx);
__ JumpIfSmi(eax, &convert, Label::kNear);
__ CmpObjectType(eax, FIRST_NONSTRING_TYPE, ecx);
__ j(below, &done_convert);
__ bind(&convert);
{
FrameScope scope(masm, StackFrame::INTERNAL);
FrameScope scope(masm, StackFrame::MANUAL);
ToStringStub stub(masm->isolate());
__ Push(edi);
__ SmiTag(ebx);
__ EnterBuiltinFrame(esi, edi, ebx);
__ Push(edx);
__ Move(eax, ebx);
__ CallStub(&stub);
__ Move(ebx, eax);
__ Pop(edx);
__ Pop(edi);
__ LeaveBuiltinFrame(esi, edi, ebx);
__ SmiUntag(ebx);
}
__ bind(&done_convert);
}
// 4. Check if new target and constructor differ.
Label new_object;
Label drop_frame_and_ret, done_alloc, new_object;
__ cmp(edx, edi);
__ j(not_equal, &new_object);
// 5. Allocate a JSValue wrapper for the string.
__ AllocateJSValue(eax, edi, ebx, ecx, &new_object);
__ Ret();
// AllocateJSValue can't handle src == dst register. Reuse esi and restore it
// as needed after the call.
__ mov(esi, eax);
__ AllocateJSValue(eax, edi, esi, ecx, &done_alloc);
__ jmp(&drop_frame_and_ret);
__ bind(&done_alloc);
{
// Restore eax to the first argument and esi to the context.
__ mov(eax, esi);
__ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
}
// 6. Fallback to the runtime to create new object.
__ bind(&new_object);
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ Push(ebx); // the first argument
FrameScope scope(masm, StackFrame::MANUAL);
__ SmiTag(ebx);
__ EnterBuiltinFrame(esi, edi, ebx);
__ Push(eax); // the first argument
FastNewObjectStub stub(masm->isolate());
__ CallStub(&stub);
__ Pop(FieldOperand(eax, JSValue::kValueOffset));
__ LeaveBuiltinFrame(esi, edi, ebx);
__ SmiUntag(ebx);
}
__ bind(&drop_frame_and_ret);
{
// Drop all arguments including the receiver.
__ PopReturnAddressTo(ecx);
__ lea(esp, Operand(esp, ebx, times_pointer_size, kPointerSize));
__ PushReturnAddressFrom(ecx);
__ Ret();
}
__ Ret();
}

View File

@ -1130,6 +1130,23 @@ void MacroAssembler::LeaveFrame(StackFrame::Type type) {
leave();
}
void MacroAssembler::EnterBuiltinFrame(Register context, Register target,
Register argc) {
Push(ebp);
Move(ebp, esp);
Push(context);
Push(target);
Push(argc);
}
void MacroAssembler::LeaveBuiltinFrame(Register context, Register target,
Register argc) {
Pop(argc);
Pop(target);
Pop(context);
leave();
}
void MacroAssembler::EnterExitFramePrologue(StackFrame::Type frame_type) {
DCHECK(frame_type == StackFrame::EXIT ||
frame_type == StackFrame::BUILTIN_EXIT);

View File

@ -932,6 +932,9 @@ class MacroAssembler: public Assembler {
void EnterFrame(StackFrame::Type type, bool load_constant_pool_pointer_reg);
void LeaveFrame(StackFrame::Type type);
void EnterBuiltinFrame(Register context, Register target, Register argc);
void LeaveBuiltinFrame(Register context, Register target, Register argc);
// Expects object in eax and returns map with validated enum cache
// in eax. Assumes that any other register can be used as a scratch.
void CheckEnumCache(Label* call_runtime);

View File

@ -168,16 +168,17 @@ void Builtins::Generate_MathMaxMin(MacroAssembler* masm, MathMaxMinKind kind) {
{
// Parameter is not a Number, use the ToNumber builtin to convert it.
FrameScope scope(masm, StackFrame::MANUAL);
__ Push(ra, fp);
__ Move(fp, sp);
__ Push(cp, a1);
__ SmiTag(a0);
__ SmiTag(a3);
__ Push(a0, t2, a3);
__ EnterBuiltinFrame(cp, a1, a0);
__ Push(t2, a3);
__ mov(a0, a2);
__ Call(masm->isolate()->builtins()->ToNumber(), RelocInfo::CODE_TARGET);
__ mov(a2, v0);
__ Pop(a0, t2, a3);
__ Pop(t2, a3);
__ LeaveBuiltinFrame(cp, a1, a0);
__ SmiUntag(a3);
__ SmiUntag(a0);
{
// Restore the double accumulator value (f0).
Label restore_smi, done_restore;
@ -188,10 +189,6 @@ void Builtins::Generate_MathMaxMin(MacroAssembler* masm, MathMaxMinKind kind) {
__ SmiToDoubleFPURegister(t2, f0, t0);
__ bind(&done_restore);
}
__ SmiUntag(a3);
__ SmiUntag(a0);
__ Pop(cp, a1);
__ Pop(ra, fp);
}
__ jmp(&convert);
__ bind(&convert_number);
@ -242,24 +239,37 @@ void Builtins::Generate_NumberConstructor(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- a0 : number of arguments
// -- a1 : constructor function
// -- cp : context
// -- 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).
// 1. Load the first argument into a0.
Label no_arguments;
{
__ Branch(USE_DELAY_SLOT, &no_arguments, eq, a0, Operand(zero_reg));
__ Subu(a0, a0, Operand(1));
__ Lsa(sp, sp, a0, kPointerSizeLog2);
__ lw(a0, MemOperand(sp));
__ Drop(2);
__ Subu(t1, a0, Operand(1)); // In delay slot.
__ mov(t0, a0); // Store argc in t0.
__ Lsa(at, sp, t1, kPointerSizeLog2);
__ lw(a0, MemOperand(at));
}
// 2a. Convert first argument to number.
__ Jump(masm->isolate()->builtins()->ToNumber(), RelocInfo::CODE_TARGET);
{
FrameScope scope(masm, StackFrame::MANUAL);
__ SmiTag(t0);
__ EnterBuiltinFrame(cp, a1, t0);
__ Call(masm->isolate()->builtins()->ToNumber(), RelocInfo::CODE_TARGET);
__ LeaveBuiltinFrame(cp, a1, t0);
__ SmiUntag(t0);
}
{
// Drop all arguments including the receiver.
__ Lsa(sp, sp, t0, kPointerSizeLog2);
__ DropAndRet(1);
}
// 2b. No arguments, return +0.
__ bind(&no_arguments);
@ -274,6 +284,7 @@ void Builtins::Generate_NumberConstructor_ConstructStub(MacroAssembler* masm) {
// -- a0 : number of arguments
// -- a1 : constructor function
// -- a3 : new target
// -- cp : context
// -- ra : return address
// -- sp[(argc - n - 1) * 4] : arg[n] (zero based)
// -- sp[argc * 4] : receiver
@ -282,19 +293,17 @@ void Builtins::Generate_NumberConstructor_ConstructStub(MacroAssembler* masm) {
// 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).
// 2. Load the first argument into a0.
{
Label no_arguments, done;
__ mov(t0, a0); // Store argc in t0.
__ Branch(USE_DELAY_SLOT, &no_arguments, eq, a0, Operand(zero_reg));
__ Subu(a0, a0, Operand(1));
__ Lsa(sp, sp, a0, kPointerSizeLog2);
__ lw(a0, MemOperand(sp));
__ Drop(2);
__ Subu(t1, a0, Operand(1)); // In delay slot.
__ Lsa(at, sp, t1, kPointerSizeLog2);
__ lw(a0, MemOperand(at));
__ jmp(&done);
__ bind(&no_arguments);
__ Move(a0, Smi::FromInt(0));
__ Drop(1);
__ bind(&done);
}
@ -305,34 +314,47 @@ void Builtins::Generate_NumberConstructor_ConstructStub(MacroAssembler* masm) {
__ GetObjectType(a0, a2, a2);
__ Branch(&done_convert, eq, a2, Operand(HEAP_NUMBER_TYPE));
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ Push(a1, a3);
FrameScope scope(masm, StackFrame::MANUAL);
__ SmiTag(t0);
__ EnterBuiltinFrame(cp, a1, t0);
__ Push(a3);
__ Call(masm->isolate()->builtins()->ToNumber(), RelocInfo::CODE_TARGET);
__ Move(a0, v0);
__ Pop(a1, a3);
__ Pop(a3);
__ LeaveBuiltinFrame(cp, a1, t0);
__ SmiUntag(t0);
}
__ bind(&done_convert);
}
// 4. Check if new target and constructor differ.
Label new_object;
Label drop_frame_and_ret, 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();
__ AllocateJSValue(v0, a1, a0, a2, t1, &new_object);
__ jmp(&drop_frame_and_ret);
// 6. Fallback to the runtime to create new object.
__ bind(&new_object);
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ Push(a0); // first argument
FrameScope scope(masm, StackFrame::MANUAL);
FastNewObjectStub stub(masm->isolate());
__ SmiTag(t0);
__ EnterBuiltinFrame(cp, a1, t0);
__ Push(a0); // first argument
__ CallStub(&stub);
__ Pop(a0);
__ LeaveBuiltinFrame(cp, a1, t0);
__ SmiUntag(t0);
}
__ sw(a0, FieldMemOperand(v0, JSValue::kValueOffset));
__ bind(&drop_frame_and_ret);
{
__ Lsa(sp, sp, t0, kPointerSizeLog2);
__ DropAndRet(1);
}
__ Ret(USE_DELAY_SLOT);
__ sw(a0, FieldMemOperand(v0, JSValue::kValueOffset)); // In delay slot
}
@ -341,34 +363,34 @@ void Builtins::Generate_StringConstructor(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- a0 : number of arguments
// -- a1 : constructor function
// -- cp : context
// -- 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).
// 1. Load the first argument into a0.
Label no_arguments;
{
__ Branch(USE_DELAY_SLOT, &no_arguments, eq, a0, Operand(zero_reg));
__ Subu(a0, a0, Operand(1));
__ Lsa(sp, sp, a0, kPointerSizeLog2);
__ lw(a0, MemOperand(sp));
__ Drop(2);
__ Subu(t1, a0, Operand(1));
__ mov(t0, a0); // Store argc in t0.
__ Lsa(at, sp, t1, kPointerSizeLog2);
__ lw(a0, MemOperand(at));
}
// 2a. At least one argument, return a0 if it's a string, otherwise
// dispatch to appropriate conversion.
Label to_string, symbol_descriptive_string;
Label drop_frame_and_ret, to_string, symbol_descriptive_string;
{
__ JumpIfSmi(a0, &to_string);
__ GetObjectType(a0, a1, a1);
__ GetObjectType(a0, t1, t1);
STATIC_ASSERT(FIRST_NONSTRING_TYPE == SYMBOL_TYPE);
__ Subu(a1, a1, Operand(FIRST_NONSTRING_TYPE));
__ Branch(&symbol_descriptive_string, eq, a1, Operand(zero_reg));
__ Branch(&to_string, gt, a1, Operand(zero_reg));
__ Ret(USE_DELAY_SLOT);
__ Subu(t1, t1, Operand(FIRST_NONSTRING_TYPE));
__ Branch(&symbol_descriptive_string, eq, t1, Operand(zero_reg));
__ Branch(&to_string, gt, t1, Operand(zero_reg));
__ mov(v0, a0);
__ jmp(&drop_frame_and_ret);
}
// 2b. No arguments, return the empty string (and pop the receiver).
@ -381,16 +403,30 @@ void Builtins::Generate_StringConstructor(MacroAssembler* masm) {
// 3a. Convert a0 to a string.
__ bind(&to_string);
{
FrameScope scope(masm, StackFrame::MANUAL);
ToStringStub stub(masm->isolate());
__ TailCallStub(&stub);
__ SmiTag(t0);
__ EnterBuiltinFrame(cp, a1, t0);
__ CallStub(&stub);
__ LeaveBuiltinFrame(cp, a1, t0);
__ SmiUntag(t0);
}
__ jmp(&drop_frame_and_ret);
// 3b. Convert symbol in a0 to a string.
__ bind(&symbol_descriptive_string);
{
__ Lsa(sp, sp, t0, kPointerSizeLog2);
__ Drop(1);
__ Push(a0);
__ TailCallRuntime(Runtime::kSymbolDescriptiveString);
}
__ bind(&drop_frame_and_ret);
{
__ Lsa(sp, sp, t0, kPointerSizeLog2);
__ DropAndRet(1);
}
}
@ -400,6 +436,7 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
// -- a0 : number of arguments
// -- a1 : constructor function
// -- a3 : new target
// -- cp : context
// -- ra : return address
// -- sp[(argc - n - 1) * 4] : arg[n] (zero based)
// -- sp[argc * 4] : receiver
@ -408,19 +445,17 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
// 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).
// 2. Load the first argument into a0.
{
Label no_arguments, done;
__ mov(t0, a0); // Store argc in t0.
__ Branch(USE_DELAY_SLOT, &no_arguments, eq, a0, Operand(zero_reg));
__ Subu(a0, a0, Operand(1));
__ Lsa(sp, sp, a0, kPointerSizeLog2);
__ lw(a0, MemOperand(sp));
__ Drop(2);
__ Subu(t1, a0, Operand(1));
__ Lsa(at, sp, t1, kPointerSizeLog2);
__ lw(a0, MemOperand(at));
__ jmp(&done);
__ bind(&no_arguments);
__ LoadRoot(a0, Heap::kempty_stringRootIndex);
__ Drop(1);
__ bind(&done);
}
@ -429,39 +464,52 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
Label convert, done_convert;
__ JumpIfSmi(a0, &convert);
__ GetObjectType(a0, a2, a2);
__ And(t0, a2, Operand(kIsNotStringMask));
__ Branch(&done_convert, eq, t0, Operand(zero_reg));
__ And(t1, a2, Operand(kIsNotStringMask));
__ Branch(&done_convert, eq, t1, Operand(zero_reg));
__ bind(&convert);
{
FrameScope scope(masm, StackFrame::INTERNAL);
FrameScope scope(masm, StackFrame::MANUAL);
ToStringStub stub(masm->isolate());
__ Push(a1, a3);
__ SmiTag(t0);
__ EnterBuiltinFrame(cp, a1, t0);
__ Push(a3);
__ CallStub(&stub);
__ Move(a0, v0);
__ Pop(a1, a3);
__ Pop(a3);
__ LeaveBuiltinFrame(cp, a1, t0);
__ SmiUntag(t0);
}
__ bind(&done_convert);
}
// 4. Check if new target and constructor differ.
Label new_object;
Label drop_frame_and_ret, new_object;
__ Branch(&new_object, ne, a1, Operand(a3));
// 5. Allocate a JSValue wrapper for the string.
__ AllocateJSValue(v0, a1, a0, a2, t0, &new_object);
__ Ret();
__ AllocateJSValue(v0, a1, a0, a2, t1, &new_object);
__ jmp(&drop_frame_and_ret);
// 6. Fallback to the runtime to create new object.
__ bind(&new_object);
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ Push(a0); // first argument
FrameScope scope(masm, StackFrame::MANUAL);
FastNewObjectStub stub(masm->isolate());
__ SmiTag(t0);
__ EnterBuiltinFrame(cp, a1, t0);
__ Push(a0); // first argument
__ CallStub(&stub);
__ Pop(a0);
__ LeaveBuiltinFrame(cp, a1, t0);
__ SmiUntag(t0);
}
__ sw(a0, FieldMemOperand(v0, JSValue::kValueOffset));
__ bind(&drop_frame_and_ret);
{
__ Lsa(sp, sp, t0, kPointerSizeLog2);
__ DropAndRet(1);
}
__ Ret(USE_DELAY_SLOT);
__ sw(a0, FieldMemOperand(v0, JSValue::kValueOffset)); // In delay slot
}
static void GenerateTailCallToSharedCode(MacroAssembler* masm) {
@ -1801,10 +1849,9 @@ void Builtins::Generate_DatePrototype_GetField(MacroAssembler* masm,
__ bind(&receiver_not_date);
{
FrameScope scope(masm, StackFrame::MANUAL);
__ Push(a0, ra, fp);
__ Move(fp, sp);
__ Push(cp, a1);
__ Push(Smi::FromInt(0));
__ Push(a0);
__ Move(a0, Smi::FromInt(0));
__ EnterBuiltinFrame(cp, a1, a0);
__ CallRuntime(Runtime::kThrowNotDateError);
}
}

View File

@ -5911,6 +5911,19 @@ void MacroAssembler::LeaveFrame(StackFrame::Type type) {
lw(fp, MemOperand(fp, 0 * kPointerSize));
}
void MacroAssembler::EnterBuiltinFrame(Register context, Register target,
Register argc) {
Push(ra, fp);
Move(fp, sp);
Push(context, target, argc);
}
void MacroAssembler::LeaveBuiltinFrame(Register context, Register target,
Register argc) {
Pop(context, target, argc);
Pop(ra, fp);
}
void MacroAssembler::EnterExitFrame(bool save_doubles, int stack_space,
StackFrame::Type frame_type) {
DCHECK(frame_type == StackFrame::EXIT ||

View File

@ -1720,6 +1720,9 @@ const Operand& rt = Operand(zero_reg), BranchDelaySlot bd = PROTECT
void EnterFrame(StackFrame::Type type, bool load_constant_pool_pointer_reg);
void LeaveFrame(StackFrame::Type type);
void EnterBuiltinFrame(Register context, Register target, Register argc);
void LeaveBuiltinFrame(Register context, Register target, Register argc);
// Expects object in a0 and returns map with validated enum cache
// in a0. Assumes that any other register can be used as a scratch.
void CheckEnumCache(Label* call_runtime);

View File

@ -167,16 +167,17 @@ void Builtins::Generate_MathMaxMin(MacroAssembler* masm, MathMaxMinKind kind) {
{
// Parameter is not a Number, use the ToNumber builtin to convert it.
FrameScope scope(masm, StackFrame::MANUAL);
__ Push(ra, fp);
__ Move(fp, sp);
__ Push(cp, a1);
__ SmiTag(a0);
__ SmiTag(a3);
__ Push(a0, t1, a3);
__ EnterBuiltinFrame(cp, a1, a0);
__ Push(t1, a3);
__ mov(a0, a2);
__ Call(masm->isolate()->builtins()->ToNumber(), RelocInfo::CODE_TARGET);
__ mov(a2, v0);
__ Pop(a0, t1, a3);
__ Pop(t1, a3);
__ LeaveBuiltinFrame(cp, a1, a0);
__ SmiUntag(a3);
__ SmiUntag(a0);
{
// Restore the double accumulator value (f0).
Label restore_smi, done_restore;
@ -187,10 +188,6 @@ void Builtins::Generate_MathMaxMin(MacroAssembler* masm, MathMaxMinKind kind) {
__ SmiToDoubleFPURegister(t1, f0, a4);
__ bind(&done_restore);
}
__ SmiUntag(a3);
__ SmiUntag(a0);
__ Pop(cp, a1);
__ Pop(ra, fp);
}
__ jmp(&convert);
__ bind(&convert_number);
@ -238,6 +235,7 @@ void Builtins::Generate_NumberConstructor(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- a0 : number of arguments
// -- a1 : constructor function
// -- cp : context
// -- ra : return address
// -- sp[(argc - n - 1) * 8] : arg[n] (zero based)
// -- sp[argc * 8] : receiver
@ -248,14 +246,27 @@ void Builtins::Generate_NumberConstructor(MacroAssembler* masm) {
Label no_arguments;
{
__ Branch(USE_DELAY_SLOT, &no_arguments, eq, a0, Operand(zero_reg));
__ Dsubu(a0, a0, Operand(1));
__ Dlsa(sp, sp, a0, kPointerSizeLog2);
__ ld(a0, MemOperand(sp));
__ Drop(2);
__ Dsubu(t1, a0, Operand(1)); // In delay slot.
__ mov(t0, a0); // Store argc in t0.
__ Dlsa(at, sp, t1, kPointerSizeLog2);
__ ld(a0, MemOperand(at));
}
// 2a. Convert first argument to number.
__ Jump(masm->isolate()->builtins()->ToNumber(), RelocInfo::CODE_TARGET);
{
FrameScope scope(masm, StackFrame::MANUAL);
__ SmiTag(t0);
__ EnterBuiltinFrame(cp, a1, t0);
__ Call(masm->isolate()->builtins()->ToNumber(), RelocInfo::CODE_TARGET);
__ LeaveBuiltinFrame(cp, a1, t0);
__ SmiUntag(t0);
}
{
// Drop all arguments including the receiver.
__ Dlsa(sp, sp, t0, kPointerSizeLog2);
__ DropAndRet(1);
}
// 2b. No arguments, return +0.
__ bind(&no_arguments);
@ -269,6 +280,7 @@ void Builtins::Generate_NumberConstructor_ConstructStub(MacroAssembler* masm) {
// -- a0 : number of arguments
// -- a1 : constructor function
// -- a3 : new target
// -- cp : context
// -- ra : return address
// -- sp[(argc - n - 1) * 8] : arg[n] (zero based)
// -- sp[argc * 8] : receiver
@ -281,15 +293,14 @@ void Builtins::Generate_NumberConstructor_ConstructStub(MacroAssembler* masm) {
// receiver).
{
Label no_arguments, done;
__ mov(t0, a0); // Store argc in t0.
__ Branch(USE_DELAY_SLOT, &no_arguments, eq, a0, Operand(zero_reg));
__ Dsubu(a0, a0, Operand(1));
__ Dlsa(sp, sp, a0, kPointerSizeLog2);
__ ld(a0, MemOperand(sp));
__ Drop(2);
__ Dsubu(a0, a0, Operand(1)); // In delay slot.
__ Dlsa(at, sp, a0, kPointerSizeLog2);
__ ld(a0, MemOperand(at));
__ jmp(&done);
__ bind(&no_arguments);
__ Move(a0, Smi::FromInt(0));
__ Drop(1);
__ bind(&done);
}
@ -298,36 +309,49 @@ void Builtins::Generate_NumberConstructor_ConstructStub(MacroAssembler* masm) {
Label done_convert;
__ JumpIfSmi(a0, &done_convert);
__ GetObjectType(a0, a2, a2);
__ Branch(&done_convert, eq, t0, Operand(HEAP_NUMBER_TYPE));
__ Branch(&done_convert, eq, a2, Operand(HEAP_NUMBER_TYPE));
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ Push(a1, a3);
FrameScope scope(masm, StackFrame::MANUAL);
__ SmiTag(t0);
__ EnterBuiltinFrame(cp, a1, t0);
__ Push(a3);
__ Call(masm->isolate()->builtins()->ToNumber(), RelocInfo::CODE_TARGET);
__ Move(a0, v0);
__ Pop(a1, a3);
__ Pop(a3);
__ LeaveBuiltinFrame(cp, a1, t0);
__ SmiUntag(t0);
}
__ bind(&done_convert);
}
// 4. Check if new target and constructor differ.
Label new_object;
Label drop_frame_and_ret, 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();
__ AllocateJSValue(v0, a1, a0, a2, t1, &new_object);
__ jmp(&drop_frame_and_ret);
// 6. Fallback to the runtime to create new object.
__ bind(&new_object);
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ Push(a0);
FrameScope scope(masm, StackFrame::MANUAL);
FastNewObjectStub stub(masm->isolate());
__ SmiTag(t0);
__ EnterBuiltinFrame(cp, a1, t0);
__ Push(a0);
__ CallStub(&stub);
__ Pop(a0);
__ LeaveBuiltinFrame(cp, a1, t0);
__ SmiUntag(t0);
}
__ sd(a0, FieldMemOperand(v0, JSValue::kValueOffset));
__ bind(&drop_frame_and_ret);
{
__ Dlsa(sp, sp, t0, kPointerSizeLog2);
__ DropAndRet(1);
}
__ Ret(USE_DELAY_SLOT);
__ sd(a0, FieldMemOperand(v0, JSValue::kValueOffset)); // In delay slot.
}
@ -336,6 +360,7 @@ void Builtins::Generate_StringConstructor(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- a0 : number of arguments
// -- a1 : constructor function
// -- cp : context
// -- ra : return address
// -- sp[(argc - n - 1) * 8] : arg[n] (zero based)
// -- sp[argc * 8] : receiver
@ -346,24 +371,24 @@ void Builtins::Generate_StringConstructor(MacroAssembler* masm) {
Label no_arguments;
{
__ Branch(USE_DELAY_SLOT, &no_arguments, eq, a0, Operand(zero_reg));
__ Dsubu(a0, a0, Operand(1));
__ Dlsa(sp, sp, a0, kPointerSizeLog2);
__ ld(a0, MemOperand(sp));
__ Drop(2);
__ Dsubu(t1, a0, Operand(1)); // In delay slot.
__ mov(t0, a0); // Store argc in t0.
__ Dlsa(at, sp, t1, kPointerSizeLog2);
__ ld(a0, MemOperand(at));
}
// 2a. At least one argument, return a0 if it's a string, otherwise
// dispatch to appropriate conversion.
Label to_string, symbol_descriptive_string;
Label drop_frame_and_ret, to_string, symbol_descriptive_string;
{
__ JumpIfSmi(a0, &to_string);
__ GetObjectType(a0, a1, a1);
__ GetObjectType(a0, t1, t1);
STATIC_ASSERT(FIRST_NONSTRING_TYPE == SYMBOL_TYPE);
__ Subu(a1, a1, Operand(FIRST_NONSTRING_TYPE));
__ Branch(&symbol_descriptive_string, eq, a1, Operand(zero_reg));
__ Branch(&to_string, gt, a1, Operand(zero_reg));
__ Ret(USE_DELAY_SLOT);
__ Subu(t1, t1, Operand(FIRST_NONSTRING_TYPE));
__ Branch(&symbol_descriptive_string, eq, t1, Operand(zero_reg));
__ Branch(&to_string, gt, t1, Operand(zero_reg));
__ mov(v0, a0);
__ jmp(&drop_frame_and_ret);
}
// 2b. No arguments, return the empty string (and pop the receiver).
@ -376,16 +401,30 @@ void Builtins::Generate_StringConstructor(MacroAssembler* masm) {
// 3a. Convert a0 to a string.
__ bind(&to_string);
{
FrameScope scope(masm, StackFrame::MANUAL);
ToStringStub stub(masm->isolate());
__ TailCallStub(&stub);
__ SmiTag(t0);
__ EnterBuiltinFrame(cp, a1, t0);
__ CallStub(&stub);
__ LeaveBuiltinFrame(cp, a1, t0);
__ SmiUntag(t0);
}
__ jmp(&drop_frame_and_ret);
// 3b. Convert symbol in a0 to a string.
__ bind(&symbol_descriptive_string);
{
__ Dlsa(sp, sp, t0, kPointerSizeLog2);
__ Drop(1);
__ Push(a0);
__ TailCallRuntime(Runtime::kSymbolDescriptiveString);
}
__ bind(&drop_frame_and_ret);
{
__ Dlsa(sp, sp, t0, kPointerSizeLog2);
__ DropAndRet(1);
}
}
@ -394,6 +433,7 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
// -- a0 : number of arguments
// -- a1 : constructor function
// -- a3 : new target
// -- cp : context
// -- ra : return address
// -- sp[(argc - n - 1) * 8] : arg[n] (zero based)
// -- sp[argc * 8] : receiver
@ -406,15 +446,14 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
// receiver).
{
Label no_arguments, done;
__ mov(t0, a0); // Store argc in t0.
__ Branch(USE_DELAY_SLOT, &no_arguments, eq, a0, Operand(zero_reg));
__ Dsubu(a0, a0, Operand(1));
__ Dlsa(sp, sp, a0, kPointerSizeLog2);
__ ld(a0, MemOperand(sp));
__ Drop(2);
__ Dlsa(at, sp, a0, kPointerSizeLog2);
__ ld(a0, MemOperand(at));
__ jmp(&done);
__ bind(&no_arguments);
__ LoadRoot(a0, Heap::kempty_stringRootIndex);
__ Drop(1);
__ bind(&done);
}
@ -423,39 +462,52 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
Label convert, done_convert;
__ JumpIfSmi(a0, &convert);
__ GetObjectType(a0, a2, a2);
__ And(t0, a2, Operand(kIsNotStringMask));
__ Branch(&done_convert, eq, t0, Operand(zero_reg));
__ And(t1, a2, Operand(kIsNotStringMask));
__ Branch(&done_convert, eq, t1, Operand(zero_reg));
__ bind(&convert);
{
FrameScope scope(masm, StackFrame::INTERNAL);
FrameScope scope(masm, StackFrame::MANUAL);
ToStringStub stub(masm->isolate());
__ Push(a1, a3);
__ SmiTag(t0);
__ EnterBuiltinFrame(cp, a1, t0);
__ Push(a3);
__ CallStub(&stub);
__ Move(a0, v0);
__ Pop(a1, a3);
__ Pop(a3);
__ LeaveBuiltinFrame(cp, a1, t0);
__ SmiUntag(t0);
}
__ bind(&done_convert);
}
// 4. Check if new target and constructor differ.
Label new_object;
Label drop_frame_and_ret, new_object;
__ Branch(&new_object, ne, a1, Operand(a3));
// 5. Allocate a JSValue wrapper for the string.
__ AllocateJSValue(v0, a1, a0, a2, t0, &new_object);
__ Ret();
__ AllocateJSValue(v0, a1, a0, a2, t1, &new_object);
__ jmp(&drop_frame_and_ret);
// 6. Fallback to the runtime to create new object.
__ bind(&new_object);
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ Push(a0);
FrameScope scope(masm, StackFrame::MANUAL);
FastNewObjectStub stub(masm->isolate());
__ SmiTag(t0);
__ EnterBuiltinFrame(cp, a1, t0);
__ Push(a0);
__ CallStub(&stub);
__ Pop(a0);
__ LeaveBuiltinFrame(cp, a1, t0);
__ SmiUntag(t0);
}
__ sd(a0, FieldMemOperand(v0, JSValue::kValueOffset));
__ bind(&drop_frame_and_ret);
{
__ Dlsa(sp, sp, t0, kPointerSizeLog2);
__ DropAndRet(1);
}
__ Ret(USE_DELAY_SLOT);
__ sd(a0, FieldMemOperand(v0, JSValue::kValueOffset)); // In delay slot.
}
static void GenerateTailCallToSharedCode(MacroAssembler* masm) {
@ -1788,10 +1840,9 @@ void Builtins::Generate_DatePrototype_GetField(MacroAssembler* masm,
__ bind(&receiver_not_date);
{
FrameScope scope(masm, StackFrame::MANUAL);
__ Push(a0, ra, fp);
__ Move(fp, sp);
__ Push(cp, a1);
__ Push(Smi::FromInt(0));
__ Push(a0);
__ Move(a0, Smi::FromInt(0));
__ EnterBuiltinFrame(cp, a1, a0);
__ CallRuntime(Runtime::kThrowNotDateError);
}
}

View File

@ -6182,6 +6182,19 @@ void MacroAssembler::LeaveFrame(StackFrame::Type type) {
ld(fp, MemOperand(fp, 0 * kPointerSize));
}
void MacroAssembler::EnterBuiltinFrame(Register context, Register target,
Register argc) {
Push(ra, fp);
Move(fp, sp);
Push(context, target, argc);
}
void MacroAssembler::LeaveBuiltinFrame(Register context, Register target,
Register argc) {
Pop(context, target, argc);
Pop(ra, fp);
}
void MacroAssembler::EnterExitFrame(bool save_doubles, int stack_space,
StackFrame::Type frame_type) {
DCHECK(frame_type == StackFrame::EXIT ||

View File

@ -1853,6 +1853,9 @@ const Operand& rt = Operand(zero_reg), BranchDelaySlot bd = PROTECT
void EnterFrame(StackFrame::Type type, bool load_constant_pool_pointer_reg);
void LeaveFrame(StackFrame::Type type);
void EnterBuiltinFrame(Register context, Register target, Register argc);
void LeaveBuiltinFrame(Register context, Register target, Register argc);
// Expects object in a0 and returns map with validated enum cache
// in a0. Assumes that any other register can be used as a scratch.
void CheckEnumCache(Label* call_runtime);

View File

@ -1323,11 +1323,8 @@ void Builtins::Generate_DatePrototype_GetField(MacroAssembler* masm,
__ bind(&receiver_not_date);
{
FrameScope scope(masm, StackFrame::MANUAL);
__ Push(rbp);
__ Move(rbp, rsp);
__ Push(rsi);
__ Push(rdi);
__ Push(Immediate(0));
__ Move(rbx, Smi::FromInt(0));
__ EnterBuiltinFrame(rsi, rdi, rbx);
__ CallRuntime(Runtime::kThrowNotDateError);
}
}
@ -1673,7 +1670,6 @@ void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
__ TailCallStub(&stub);
}
// static
void Builtins::Generate_MathMaxMin(MacroAssembler* masm, MathMaxMinKind kind) {
// ----------- S t a t e -------------
@ -1716,13 +1712,9 @@ void Builtins::Generate_MathMaxMin(MacroAssembler* masm, MathMaxMinKind kind) {
{
// Parameter is not a Number, use the ToNumber builtin to convert it.
FrameScope scope(masm, StackFrame::MANUAL);
__ Push(rbp);
__ Move(rbp, rsp);
__ Push(rsi);
__ Push(rdi);
__ Integer32ToSmi(rax, rax);
__ Integer32ToSmi(rcx, rcx);
__ Push(rax);
__ EnterBuiltinFrame(rsi, rdi, rax);
__ Push(rcx);
__ Push(rdx);
__ movp(rax, rbx);
@ -1730,9 +1722,9 @@ void Builtins::Generate_MathMaxMin(MacroAssembler* masm, MathMaxMinKind kind) {
__ movp(rbx, rax);
__ Pop(rdx);
__ Pop(rcx);
__ Pop(rax);
__ Pop(rdi);
__ Pop(rsi);
__ LeaveBuiltinFrame(rsi, rdi, rax);
__ SmiToInteger32(rcx, rcx);
__ SmiToInteger32(rax, rax);
{
// Restore the double accumulator value (xmm0).
Label restore_smi, done_restore;
@ -1743,9 +1735,6 @@ void Builtins::Generate_MathMaxMin(MacroAssembler* masm, MathMaxMinKind kind) {
__ SmiToDouble(xmm0, rdx);
__ bind(&done_restore);
}
__ SmiToInteger32(rcx, rcx);
__ SmiToInteger32(rax, rax);
__ leave();
}
__ jmp(&convert);
__ bind(&convert_number);
@ -1799,27 +1788,39 @@ void Builtins::Generate_NumberConstructor(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- rax : number of arguments
// -- rdi : constructor function
// -- rsi : context
// -- 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).
// 1. Load the first argument into rbx.
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.
__ Jump(masm->isolate()->builtins()->ToNumber(), RelocInfo::CODE_TARGET);
{
FrameScope scope(masm, StackFrame::MANUAL);
__ Integer32ToSmi(rax, rax);
__ EnterBuiltinFrame(rsi, rdi, rax);
__ movp(rax, rbx);
__ Call(masm->isolate()->builtins()->ToNumber(), RelocInfo::CODE_TARGET);
__ LeaveBuiltinFrame(rsi, rdi, rbx); // Argc popped to rbx.
__ SmiToInteger32(rbx, rbx);
}
{
// Drop all arguments including the receiver.
__ PopReturnAddressTo(rcx);
__ leap(rsp, Operand(rsp, rbx, times_pointer_size, kPointerSize));
__ PushReturnAddressFrom(rcx);
__ Ret();
}
// 2b. No arguments, return +0 (already in rax).
__ bind(&no_arguments);
@ -1833,6 +1834,7 @@ void Builtins::Generate_NumberConstructor_ConstructStub(MacroAssembler* masm) {
// -- rax : number of arguments
// -- rdi : constructor function
// -- rdx : new target
// -- rsi : context
// -- rsp[0] : return address
// -- rsp[(argc - n) * 8] : arg[n] (zero-based)
// -- rsp[(argc + 1) * 8] : receiver
@ -1841,8 +1843,10 @@ void Builtins::Generate_NumberConstructor_ConstructStub(MacroAssembler* masm) {
// 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).
// Store argc in r8.
__ Integer32ToSmi(r8, rax);
// 2. Load the first argument into rbx.
{
StackArgumentsAccessor args(rsp, rax);
Label no_arguments, done;
@ -1853,9 +1857,6 @@ void Builtins::Generate_NumberConstructor_ConstructStub(MacroAssembler* masm) {
__ 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.
@ -1866,37 +1867,48 @@ void Builtins::Generate_NumberConstructor_ConstructStub(MacroAssembler* masm) {
Heap::kHeapNumberMapRootIndex);
__ j(equal, &done_convert);
{
FrameScope scope(masm, StackFrame::INTERNAL);
FrameScope scope(masm, StackFrame::MANUAL);
__ EnterBuiltinFrame(rsi, rdi, r8);
__ Push(rdx);
__ Push(rdi);
__ Move(rax, rbx);
__ Call(masm->isolate()->builtins()->ToNumber(), RelocInfo::CODE_TARGET);
__ Move(rbx, rax);
__ Pop(rdi);
__ Pop(rdx);
__ LeaveBuiltinFrame(rsi, rdi, r8);
}
__ bind(&done_convert);
}
// 4. Check if new target and constructor differ.
Label new_object;
Label drop_frame_and_ret, 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();
__ jmp(&drop_frame_and_ret, Label::kNear);
// 6. Fallback to the runtime to create new object.
__ bind(&new_object);
{
FrameScope scope(masm, StackFrame::INTERNAL);
FrameScope scope(masm, StackFrame::MANUAL);
__ EnterBuiltinFrame(rsi, rdi, r8);
__ Push(rbx); // the first argument
FastNewObjectStub stub(masm->isolate());
__ CallStub(&stub);
__ Pop(FieldOperand(rax, JSValue::kValueOffset));
__ LeaveBuiltinFrame(rsi, rdi, r8);
}
__ bind(&drop_frame_and_ret);
{
// Drop all arguments including the receiver.
__ PopReturnAddressTo(rcx);
__ SmiToInteger32(r8, r8);
__ leap(rsp, Operand(rsp, r8, times_pointer_size, kPointerSize));
__ PushReturnAddressFrom(rcx);
__ Ret();
}
__ Ret();
}
@ -1905,35 +1917,32 @@ void Builtins::Generate_StringConstructor(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- rax : number of arguments
// -- rdi : constructor function
// -- rsi : context
// -- 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).
// 1. Load the first argument into rax.
Label no_arguments;
{
StackArgumentsAccessor args(rsp, rax);
__ Integer32ToSmi(r8, rax); // Store argc in r8.
__ 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);
__ movp(rax, args.GetArgumentOperand(1));
}
// 2a. At least one argument, return rax if it's a string, otherwise
// dispatch to appropriate conversion.
Label to_string, symbol_descriptive_string;
Label drop_frame_and_ret, to_string, symbol_descriptive_string;
{
__ JumpIfSmi(rax, &to_string, Label::kNear);
STATIC_ASSERT(FIRST_NONSTRING_TYPE == SYMBOL_TYPE);
__ CmpObjectType(rax, FIRST_NONSTRING_TYPE, rdx);
__ j(above, &to_string, Label::kNear);
__ j(equal, &symbol_descriptive_string, Label::kNear);
__ Ret();
__ jmp(&drop_frame_and_ret, Label::kNear);
}
// 2b. No arguments, return the empty string (and pop the receiver).
@ -1946,18 +1955,34 @@ void Builtins::Generate_StringConstructor(MacroAssembler* masm) {
// 3a. Convert rax to a string.
__ bind(&to_string);
{
FrameScope scope(masm, StackFrame::MANUAL);
ToStringStub stub(masm->isolate());
__ TailCallStub(&stub);
__ EnterBuiltinFrame(rsi, rdi, r8);
__ CallStub(&stub);
__ LeaveBuiltinFrame(rsi, rdi, r8);
}
__ jmp(&drop_frame_and_ret, Label::kNear);
// 3b. Convert symbol in rax to a string.
__ bind(&symbol_descriptive_string);
{
__ PopReturnAddressTo(rcx);
__ SmiToInteger32(r8, r8);
__ leap(rsp, Operand(rsp, r8, times_pointer_size, kPointerSize));
__ Push(rax);
__ PushReturnAddressFrom(rcx);
__ TailCallRuntime(Runtime::kSymbolDescriptiveString);
}
__ bind(&drop_frame_and_ret);
{
// Drop all arguments including the receiver.
__ PopReturnAddressTo(rcx);
__ SmiToInteger32(r8, r8);
__ leap(rsp, Operand(rsp, r8, times_pointer_size, kPointerSize));
__ PushReturnAddressFrom(rcx);
__ Ret();
}
}
@ -1967,6 +1992,7 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
// -- rax : number of arguments
// -- rdi : constructor function
// -- rdx : new target
// -- rsi : context
// -- rsp[0] : return address
// -- rsp[(argc - n) * 8] : arg[n] (zero-based)
// -- rsp[(argc + 1) * 8] : receiver
@ -1975,8 +2001,10 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
// 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).
// Store argc in r8.
__ Integer32ToSmi(r8, rax);
// 2. Load the first argument into rbx.
{
StackArgumentsAccessor args(rsp, rax);
Label no_arguments, done;
@ -1987,9 +2015,6 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
__ bind(&no_arguments);
__ LoadRoot(rbx, Heap::kempty_stringRootIndex);
__ bind(&done);
__ PopReturnAddressTo(rcx);
__ leap(rsp, Operand(rsp, rax, times_pointer_size, kPointerSize));
__ PushReturnAddressFrom(rcx);
}
// 3. Make sure rbx is a string.
@ -2000,38 +2025,49 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
__ j(below, &done_convert);
__ bind(&convert);
{
FrameScope scope(masm, StackFrame::INTERNAL);
FrameScope scope(masm, StackFrame::MANUAL);
ToStringStub stub(masm->isolate());
__ EnterBuiltinFrame(rsi, rdi, r8);
__ Push(rdx);
__ Push(rdi);
__ Move(rax, rbx);
__ CallStub(&stub);
__ Move(rbx, rax);
__ Pop(rdi);
__ Pop(rdx);
__ LeaveBuiltinFrame(rsi, rdi, r8);
}
__ bind(&done_convert);
}
// 4. Check if new target and constructor differ.
Label new_object;
Label drop_frame_and_ret, new_object;
__ cmpp(rdx, rdi);
__ j(not_equal, &new_object);
// 5. Allocate a JSValue wrapper for the string.
__ AllocateJSValue(rax, rdi, rbx, rcx, &new_object);
__ Ret();
__ jmp(&drop_frame_and_ret, Label::kNear);
// 6. Fallback to the runtime to create new object.
__ bind(&new_object);
{
FrameScope scope(masm, StackFrame::INTERNAL);
FrameScope scope(masm, StackFrame::MANUAL);
__ EnterBuiltinFrame(rsi, rdi, r8);
__ Push(rbx); // the first argument
FastNewObjectStub stub(masm->isolate());
__ CallStub(&stub);
__ Pop(FieldOperand(rax, JSValue::kValueOffset));
__ LeaveBuiltinFrame(rsi, rdi, r8);
}
__ bind(&drop_frame_and_ret);
{
// Drop all arguments including the receiver.
__ PopReturnAddressTo(rcx);
__ SmiToInteger32(r8, r8);
__ leap(rsp, Operand(rsp, r8, times_pointer_size, kPointerSize));
__ PushReturnAddressFrom(rcx);
__ Ret();
}
__ Ret();
}

View File

@ -4436,6 +4436,23 @@ void MacroAssembler::LeaveFrame(StackFrame::Type type) {
popq(rbp);
}
void MacroAssembler::EnterBuiltinFrame(Register context, Register target,
Register argc) {
Push(rbp);
Move(rbp, rsp);
Push(context);
Push(target);
Push(argc);
}
void MacroAssembler::LeaveBuiltinFrame(Register context, Register target,
Register argc) {
Pop(argc);
Pop(target);
Pop(context);
leave();
}
void MacroAssembler::EnterExitFramePrologue(bool save_rax,
StackFrame::Type frame_type) {
DCHECK(frame_type == StackFrame::EXIT ||

View File

@ -1575,6 +1575,9 @@ class MacroAssembler: public Assembler {
void EnterFrame(StackFrame::Type type, bool load_constant_pool_pointer_reg);
void LeaveFrame(StackFrame::Type type);
void EnterBuiltinFrame(Register context, Register target, Register argc);
void LeaveBuiltinFrame(Register context, Register target, Register argc);
// Expects object in rax and returns map with validated enum cache
// in rax. Assumes that any other register can be used as a scratch.
void CheckEnumCache(Label* call_runtime);

View File

@ -114,6 +114,9 @@
# Assumptions about optimization need investigation in TurboFan.
'regress-sync-optimized-lists': [PASS, NO_VARIANTS],
# Fails in --turbo --always-opt mode.
'regress/regress-105': [PASS, NO_VARIANTS],
##############################################################################
# Too slow in debug mode with --stress-opt mode.
'compiler/regress-stacktrace-methods': [PASS, ['mode == debug', SKIP]],

View File

@ -26,12 +26,12 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
var custom_valueOf = function() {
assertEquals(null, custom_valueOf.caller);
assertEquals(Number, custom_valueOf.caller);
return 2;
}
var custom_toString = function() {
assertEquals(null, custom_toString.caller);
assertEquals(String, custom_toString.caller);
return "I used to be an adventurer like you";
}

View File

@ -16,9 +16,6 @@ function testTraceNativeConversion(nativeFunc) {
}
}
testTraceNativeConversion(Math.max);
testTraceNativeConversion(Math.min);
// C++ builtins.
testTraceNativeConversion(Math.acos);
testTraceNativeConversion(Math.asin);
@ -35,15 +32,6 @@ function testBuiltinInStackTrace(script, expectedString) {
}
}
// Use the full name ('String.getDate') in order to avoid false pass
// results when the method name is mentioned in the error message itself.
// This occurs, e.g., for Date.prototype.getYear, which uses a different code
// path and never hits the Generate_DatePrototype_GetField builtin.
testBuiltinInStackTrace("Date.prototype.getDate.call('')", "at String.getDate");
testBuiltinInStackTrace("Date.prototype.getUTCDate.call('')",
"at String.getUTCDate");
testBuiltinInStackTrace("Date.prototype.getTime.call('')", "at String.getTime");
// C++ builtins.
testBuiltinInStackTrace("Boolean.prototype.toString.call(thrower);",
"at Object.toString");
@ -52,16 +40,12 @@ testBuiltinInStackTrace("Boolean.prototype.toString.call(thrower);",
testBuiltinInStackTrace("new Date(thrower);", "at new Date");
// Ensure we correctly pick up the receiver's string tag.
testBuiltinInStackTrace("Math.max(thrower);", "at Math.max");
testBuiltinInStackTrace("Math.min(thrower);", "at Math.min");
testBuiltinInStackTrace("Math.acos(thrower);", "at Math.acos");
testBuiltinInStackTrace("Math.asin(thrower);", "at Math.asin");
testBuiltinInStackTrace("Math.fround(thrower);", "at Math.fround");
testBuiltinInStackTrace("Math.imul(thrower);", "at Math.imul");
// As above, but function passed as an argument and then called.
testBuiltinInStackTrace("((f, x) => f(x))(Math.max, thrower);", "at max");
testBuiltinInStackTrace("((f, x) => f(x))(Math.min, thrower);", "at min");
testBuiltinInStackTrace("((f, x) => f(x))(Math.acos, thrower);", "at acos");
testBuiltinInStackTrace("((f, x) => f(x))(Math.asin, thrower);", "at asin");
testBuiltinInStackTrace("((f, x) => f(x))(Math.fround, thrower);", "at fround");

View File

@ -0,0 +1,53 @@
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
var thrower = { [Symbol.toPrimitive]: () => FAIL };
// Tests that a native conversion function is included in the
// stack trace.
function testTraceNativeConversion(nativeFunc) {
var nativeFuncName = nativeFunc.name;
try {
nativeFunc(thrower);
assertUnreachable(nativeFuncName);
} catch (e) {
assertTrue(e.stack.indexOf(nativeFuncName) >= 0, nativeFuncName);
}
}
testTraceNativeConversion(Math.max);
testTraceNativeConversion(Math.min);
function testBuiltinInStackTrace(script, expectedString) {
try {
eval(script);
assertUnreachable(expectedString);
} catch (e) {
assertTrue(e.stack.indexOf(expectedString) >= 0, expectedString);
}
}
testBuiltinInStackTrace("Date.prototype.getDate.call('')", "at String.getDate");
testBuiltinInStackTrace("Date.prototype.getUTCDate.call('')",
"at String.getUTCDate");
testBuiltinInStackTrace("Date.prototype.getTime.call('')", "at String.getTime");
// TODO(jgruber): These use a more generic expected string until detection of
// assembly builtin constructors is fixed.
testBuiltinInStackTrace("Number(thrower);", "Number");
testBuiltinInStackTrace("new Number(thrower);", "Number");
testBuiltinInStackTrace("String(thrower);", "String");
testBuiltinInStackTrace("new String(thrower);", "String");
// Ensure we correctly pick up the receiver's string tag.
testBuiltinInStackTrace("Math.acos(thrower);", "at Math.acos");
testBuiltinInStackTrace("Math.asin(thrower);", "at Math.asin");
testBuiltinInStackTrace("Math.fround(thrower);", "at Math.fround");
testBuiltinInStackTrace("Math.imul(thrower);", "at Math.imul");
// As above, but function passed as an argument and then called.
testBuiltinInStackTrace("((f, x) => f(x))(Math.acos, thrower);", "at acos");
testBuiltinInStackTrace("((f, x) => f(x))(Math.asin, thrower);", "at asin");
testBuiltinInStackTrace("((f, x) => f(x))(Math.fround, thrower);", "at fround");
testBuiltinInStackTrace("((f, x) => f(x))(Math.imul, thrower);", "at imul");