[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:
parent
1f53e42bd6
commit
d49d3864d7
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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 ||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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,
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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 ||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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 ||
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
@ -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 ||
|
||||
|
@ -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);
|
||||
|
@ -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]],
|
||||
|
@ -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";
|
||||
}
|
||||
|
||||
|
@ -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");
|
||||
|
53
test/mjsunit/regress/regress-5173.js
Normal file
53
test/mjsunit/regress/regress-5173.js
Normal 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");
|
Loading…
Reference in New Issue
Block a user