Commit 1f295980 authored by mstarzinger's avatar mstarzinger Committed by Commit bot

Fix pushing of register in CallConstructStub outside frame.

This fixes a recent regression where the register holding the original
receiver was pushed onto the stack before the internal frame within the
CallStubInRecordCallTarget helper was created. That in turn confused
the stack walker when allocations in these stubs failed.

R=mvstanton@chromium.org
BUG=chromium:512711
LOG=N

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

Cr-Commit-Position: refs/heads/master@{#29787}
parent 4da289c5
......@@ -1916,38 +1916,57 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
}
static void CallStubInRecordCallTarget(MacroAssembler* masm, CodeStub* stub) {
static void CallStubInRecordCallTarget(MacroAssembler* masm, CodeStub* stub,
bool is_super) {
// eax : number of arguments to the construct function
// ebx : Feedback vector
// ebx : feedback vector
// edx : slot in feedback vector (Smi)
// edi : the function to call
FrameScope scope(masm, StackFrame::INTERNAL);
// esp[0]: original receiver (for IsSuperConstructorCall)
if (is_super) {
__ pop(ecx);
}
// Number-of-arguments register must be smi-tagged to call out.
__ SmiTag(eax);
__ push(eax);
__ push(edi);
__ push(edx);
__ push(ebx);
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ CallStub(stub);
// Number-of-arguments register must be smi-tagged to call out.
__ SmiTag(eax);
__ push(eax);
__ push(edi);
__ push(edx);
__ push(ebx);
if (is_super) {
__ push(ecx);
}
__ pop(ebx);
__ pop(edx);
__ pop(edi);
__ pop(eax);
__ SmiUntag(eax);
__ CallStub(stub);
if (is_super) {
__ pop(ecx);
}
__ pop(ebx);
__ pop(edx);
__ pop(edi);
__ pop(eax);
__ SmiUntag(eax);
}
if (is_super) {
__ push(ecx);
}
}
static void GenerateRecordCallTarget(MacroAssembler* masm) {
static void GenerateRecordCallTarget(MacroAssembler* masm, bool is_super) {
// Cache the called function in a feedback vector slot. Cache states
// are uninitialized, monomorphic (indicated by a JSFunction), and
// megamorphic.
// eax : number of arguments to the construct function
// ebx : Feedback vector
// ebx : feedback vector
// edx : slot in feedback vector (Smi)
// edi : the function to call
// esp[0]: original receiver (for IsSuperConstructorCall)
Isolate* isolate = masm->isolate();
Label initialize, done, miss, megamorphic, not_array_function;
......@@ -2016,14 +2035,14 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) {
// Create an AllocationSite if we don't already have it, store it in the
// slot.
CreateAllocationSiteStub create_stub(isolate);
CallStubInRecordCallTarget(masm, &create_stub);
CallStubInRecordCallTarget(masm, &create_stub, is_super);
__ jmp(&done);
__ bind(&not_array_function);
}
CreateWeakCellStub create_stub(isolate);
CallStubInRecordCallTarget(masm, &create_stub);
CallStubInRecordCallTarget(masm, &create_stub, is_super);
__ bind(&done);
}
......@@ -2163,7 +2182,7 @@ void CallConstructStub::Generate(MacroAssembler* masm) {
__ j(not_equal, &slow);
if (RecordCallTarget()) {
GenerateRecordCallTarget(masm);
GenerateRecordCallTarget(masm, IsSuperConstructorCall());
if (FLAG_pretenuring_call_new) {
// Put the AllocationSite from the feedback vector into ebx.
......@@ -2205,7 +2224,7 @@ void CallConstructStub::Generate(MacroAssembler* masm) {
// edi: called object
// eax: number of arguments
// ecx: object map
// esp[0]: original receiver
// esp[0]: original receiver (for IsSuperConstructorCall)
Label do_call;
__ bind(&slow);
__ CmpInstanceType(ecx, JS_FUNCTION_PROXY_TYPE);
......
......@@ -2515,16 +2515,19 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
}
static void CallStubInRecordCallTarget(MacroAssembler* masm, CodeStub* stub) {
static void CallStubInRecordCallTarget(MacroAssembler* masm, CodeStub* stub,
bool is_super) {
// a0 : number of arguments to the construct function
// a2 : Feedback vector
// a2 : feedback vector
// a3 : slot in feedback vector (Smi)
// a1 : the function to call
// t0 : original constructor (for IsSuperConstructorCall)
FrameScope scope(masm, StackFrame::INTERNAL);
const RegList kSavedRegs = 1 << 4 | // a0
1 << 5 | // a1
1 << 6 | // a2
1 << 7; // a3
const RegList kSavedRegs = 1 << 4 | // a0
1 << 5 | // a1
1 << 6 | // a2
1 << 7 | // a3
BoolToInt(is_super) << 8; // t0
// Number-of-arguments register must be smi-tagged to call out.
__ SmiTag(a0);
......@@ -2537,14 +2540,15 @@ static void CallStubInRecordCallTarget(MacroAssembler* masm, CodeStub* stub) {
}
static void GenerateRecordCallTarget(MacroAssembler* masm) {
static void GenerateRecordCallTarget(MacroAssembler* masm, bool is_super) {
// Cache the called function in a feedback vector slot. Cache states
// are uninitialized, monomorphic (indicated by a JSFunction), and
// megamorphic.
// a0 : number of arguments to the construct function
// a1 : the function to call
// a2 : Feedback vector
// a2 : feedback vector
// a3 : slot in feedback vector (Smi)
// t0 : original constructor (for IsSuperConstructorCall)
Label initialize, done, miss, megamorphic, not_array_function;
DCHECK_EQ(*TypeFeedbackVector::MegamorphicSentinel(masm->isolate()),
......@@ -2552,23 +2556,23 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) {
DCHECK_EQ(*TypeFeedbackVector::UninitializedSentinel(masm->isolate()),
masm->isolate()->heap()->uninitialized_symbol());
// Load the cache state into t0.
__ sll(t0, a3, kPointerSizeLog2 - kSmiTagSize);
__ Addu(t0, a2, Operand(t0));
__ lw(t0, FieldMemOperand(t0, FixedArray::kHeaderSize));
// Load the cache state into t2.
__ sll(t2, a3, kPointerSizeLog2 - kSmiTagSize);
__ Addu(t2, a2, Operand(t2));
__ lw(t2, FieldMemOperand(t2, FixedArray::kHeaderSize));
// A monomorphic cache hit or an already megamorphic state: invoke the
// function without changing the state.
// We don't know if t0 is a WeakCell or a Symbol, but it's harmless to read at
// We don't know if t2 is a WeakCell or a Symbol, but it's harmless to read at
// this position in a symbol (see static asserts in type-feedback-vector.h).
Label check_allocation_site;
Register feedback_map = t1;
Register weak_value = t4;
__ lw(weak_value, FieldMemOperand(t0, WeakCell::kValueOffset));
__ lw(weak_value, FieldMemOperand(t2, WeakCell::kValueOffset));
__ Branch(&done, eq, a1, Operand(weak_value));
__ LoadRoot(at, Heap::kmegamorphic_symbolRootIndex);
__ Branch(&done, eq, t0, Operand(at));
__ lw(feedback_map, FieldMemOperand(t0, HeapObject::kMapOffset));
__ Branch(&done, eq, t2, Operand(at));
__ lw(feedback_map, FieldMemOperand(t2, HeapObject::kMapOffset));
__ LoadRoot(at, Heap::kWeakCellMapRootIndex);
__ Branch(FLAG_pretenuring_call_new ? &miss : &check_allocation_site, ne,
feedback_map, Operand(at));
......@@ -2587,8 +2591,8 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) {
__ Branch(&miss, ne, feedback_map, Operand(at));
// Make sure the function is the Array() function
__ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, t0);
__ Branch(&megamorphic, ne, a1, Operand(t0));
__ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, t2);
__ Branch(&megamorphic, ne, a1, Operand(t2));
__ jmp(&done);
}
......@@ -2597,35 +2601,35 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) {
// A monomorphic miss (i.e, here the cache is not uninitialized) goes
// megamorphic.
__ LoadRoot(at, Heap::kuninitialized_symbolRootIndex);
__ Branch(&initialize, eq, t0, Operand(at));
__ Branch(&initialize, eq, t2, Operand(at));
// MegamorphicSentinel is an immortal immovable object (undefined) so no
// write-barrier is needed.
__ bind(&megamorphic);
__ sll(t0, a3, kPointerSizeLog2 - kSmiTagSize);
__ Addu(t0, a2, Operand(t0));
__ sll(t2, a3, kPointerSizeLog2 - kSmiTagSize);
__ Addu(t2, a2, Operand(t2));
__ LoadRoot(at, Heap::kmegamorphic_symbolRootIndex);
__ sw(at, FieldMemOperand(t0, FixedArray::kHeaderSize));
__ sw(at, FieldMemOperand(t2, FixedArray::kHeaderSize));
__ jmp(&done);
// An uninitialized cache is patched with the function.
__ bind(&initialize);
if (!FLAG_pretenuring_call_new) {
// Make sure the function is the Array() function.
__ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, t0);
__ Branch(&not_array_function, ne, a1, Operand(t0));
__ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, t2);
__ Branch(&not_array_function, ne, a1, Operand(t2));
// The target function is the Array constructor,
// Create an AllocationSite if we don't already have it, store it in the
// slot.
CreateAllocationSiteStub create_stub(masm->isolate());
CallStubInRecordCallTarget(masm, &create_stub);
CallStubInRecordCallTarget(masm, &create_stub, is_super);
__ Branch(&done);
__ bind(&not_array_function);
}
CreateWeakCellStub create_stub(masm->isolate());
CallStubInRecordCallTarget(masm, &create_stub);
CallStubInRecordCallTarget(masm, &create_stub, is_super);
__ bind(&done);
}
......@@ -2758,13 +2762,7 @@ void CallConstructStub::Generate(MacroAssembler* masm) {
__ Branch(&slow, ne, t1, Operand(JS_FUNCTION_TYPE));
if (RecordCallTarget()) {
if (IsSuperConstructorCall()) {
__ push(t0);
}
GenerateRecordCallTarget(masm);
if (IsSuperConstructorCall()) {
__ pop(t0);
}
GenerateRecordCallTarget(masm, IsSuperConstructorCall());
__ sll(at, a3, kPointerSizeLog2 - kSmiTagSize);
__ Addu(t1, a2, at);
......
......@@ -2549,16 +2549,20 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
}
static void CallStubInRecordCallTarget(MacroAssembler* masm, CodeStub* stub) {
static void CallStubInRecordCallTarget(MacroAssembler* masm, CodeStub* stub,
bool is_super) {
// a0 : number of arguments to the construct function
// a2 : Feedback vector
// a2 : feedback vector
// a3 : slot in feedback vector (Smi)
// a1 : the function to call
// a4 : original constructor (for IsSuperConstructorCall)
FrameScope scope(masm, StackFrame::INTERNAL);
const RegList kSavedRegs = 1 << 4 | // a0
1 << 5 | // a1
1 << 6 | // a2
1 << 7; // a3
const RegList kSavedRegs = 1 << 4 | // a0
1 << 5 | // a1
1 << 6 | // a2
1 << 7 | // a3
BoolToInt(is_super) << 8; // a4
// Number-of-arguments register must be smi-tagged to call out.
__ SmiTag(a0);
......@@ -2571,14 +2575,15 @@ static void CallStubInRecordCallTarget(MacroAssembler* masm, CodeStub* stub) {
}
static void GenerateRecordCallTarget(MacroAssembler* masm) {
static void GenerateRecordCallTarget(MacroAssembler* masm, bool is_super) {
// Cache the called function in a feedback vector slot. Cache states
// are uninitialized, monomorphic (indicated by a JSFunction), and
// megamorphic.
// a0 : number of arguments to the construct function
// a1 : the function to call
// a2 : Feedback vector
// a2 : feedback vector
// a3 : slot in feedback vector (Smi)
// a4 : original constructor (for IsSuperConstructorCall)
Label initialize, done, miss, megamorphic, not_array_function;
DCHECK_EQ(*TypeFeedbackVector::MegamorphicSentinel(masm->isolate()),
......@@ -2586,23 +2591,23 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) {
DCHECK_EQ(*TypeFeedbackVector::UninitializedSentinel(masm->isolate()),
masm->isolate()->heap()->uninitialized_symbol());
// Load the cache state into a4.
__ dsrl(a4, a3, 32 - kPointerSizeLog2);
__ Daddu(a4, a2, Operand(a4));
__ ld(a4, FieldMemOperand(a4, FixedArray::kHeaderSize));
// Load the cache state into a5.
__ dsrl(a5, a3, 32 - kPointerSizeLog2);
__ Daddu(a5, a2, Operand(a5));
__ ld(a5, FieldMemOperand(a5, FixedArray::kHeaderSize));
// A monomorphic cache hit or an already megamorphic state: invoke the
// function without changing the state.
// We don't know if a4 is a WeakCell or a Symbol, but it's harmless to read at
// We don't know if a5 is a WeakCell or a Symbol, but it's harmless to read at
// this position in a symbol (see static asserts in type-feedback-vector.h).
Label check_allocation_site;
Register feedback_map = a5;
Register feedback_map = a6;
Register weak_value = t0;
__ ld(weak_value, FieldMemOperand(a4, WeakCell::kValueOffset));
__ ld(weak_value, FieldMemOperand(a5, WeakCell::kValueOffset));
__ Branch(&done, eq, a1, Operand(weak_value));
__ LoadRoot(at, Heap::kmegamorphic_symbolRootIndex);
__ Branch(&done, eq, a4, Operand(at));
__ ld(feedback_map, FieldMemOperand(a4, HeapObject::kMapOffset));
__ Branch(&done, eq, a5, Operand(at));
__ ld(feedback_map, FieldMemOperand(a5, HeapObject::kMapOffset));
__ LoadRoot(at, Heap::kWeakCellMapRootIndex);
__ Branch(FLAG_pretenuring_call_new ? &miss : &check_allocation_site, ne,
feedback_map, Operand(at));
......@@ -2621,8 +2626,8 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) {
__ Branch(&miss, ne, feedback_map, Operand(at));
// Make sure the function is the Array() function
__ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, a4);
__ Branch(&megamorphic, ne, a1, Operand(a4));
__ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, a5);
__ Branch(&megamorphic, ne, a1, Operand(a5));
__ jmp(&done);
}
......@@ -2631,35 +2636,35 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) {
// A monomorphic miss (i.e, here the cache is not uninitialized) goes
// megamorphic.
__ LoadRoot(at, Heap::kuninitialized_symbolRootIndex);
__ Branch(&initialize, eq, a4, Operand(at));
__ Branch(&initialize, eq, a5, Operand(at));
// MegamorphicSentinel is an immortal immovable object (undefined) so no
// write-barrier is needed.
__ bind(&megamorphic);
__ dsrl(a4, a3, 32 - kPointerSizeLog2);
__ Daddu(a4, a2, Operand(a4));
__ dsrl(a5, a3, 32 - kPointerSizeLog2);
__ Daddu(a5, a2, Operand(a5));
__ LoadRoot(at, Heap::kmegamorphic_symbolRootIndex);
__ sd(at, FieldMemOperand(a4, FixedArray::kHeaderSize));
__ sd(at, FieldMemOperand(a5, FixedArray::kHeaderSize));
__ jmp(&done);
// An uninitialized cache is patched with the function.
__ bind(&initialize);
if (!FLAG_pretenuring_call_new) {
// Make sure the function is the Array() function.
__ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, a4);
__ Branch(&not_array_function, ne, a1, Operand(a4));
__ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, a5);
__ Branch(&not_array_function, ne, a1, Operand(a5));
// The target function is the Array constructor,
// Create an AllocationSite if we don't already have it, store it in the
// slot.
CreateAllocationSiteStub create_stub(masm->isolate());
CallStubInRecordCallTarget(masm, &create_stub);
CallStubInRecordCallTarget(masm, &create_stub, is_super);
__ Branch(&done);
__ bind(&not_array_function);
}
CreateWeakCellStub create_stub(masm->isolate());
CallStubInRecordCallTarget(masm, &create_stub);
CallStubInRecordCallTarget(masm, &create_stub, is_super);
__ bind(&done);
}
......@@ -2794,13 +2799,7 @@ void CallConstructStub::Generate(MacroAssembler* masm) {
__ Branch(&slow, ne, a5, Operand(JS_FUNCTION_TYPE));
if (RecordCallTarget()) {
if (IsSuperConstructorCall()) {
__ push(a4);
}
GenerateRecordCallTarget(masm);
if (IsSuperConstructorCall()) {
__ pop(a4);
}
GenerateRecordCallTarget(masm, IsSuperConstructorCall());
__ dsrl(at, a3, 32 - kPointerSizeLog2);
__ Daddu(a5, a2, at);
......
......@@ -1786,11 +1786,13 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
}
static void CallStubInRecordCallTarget(MacroAssembler* masm, CodeStub* stub) {
// eax : number of arguments to the construct function
// ebx : Feedback vector
// edx : slot in feedback vector (Smi)
// edi : the function to call
static void CallStubInRecordCallTarget(MacroAssembler* masm, CodeStub* stub,
bool is_super) {
// rax : number of arguments to the construct function
// rbx : feedback vector
// rcx : original constructor (for IsSuperConstructorCall)
// rdx : slot in feedback vector (Smi)
// rdi : the function to call
FrameScope scope(masm, StackFrame::INTERNAL);
// Number-of-arguments register must be smi-tagged to call out.
......@@ -1800,9 +1802,15 @@ static void CallStubInRecordCallTarget(MacroAssembler* masm, CodeStub* stub) {
__ Integer32ToSmi(rdx, rdx);
__ Push(rdx);
__ Push(rbx);
if (is_super) {
__ Push(rcx);
}
__ CallStub(stub);
if (is_super) {
__ Pop(rcx);
}
__ Pop(rbx);
__ Pop(rdx);
__ Pop(rdi);
......@@ -1811,39 +1819,40 @@ static void CallStubInRecordCallTarget(MacroAssembler* masm, CodeStub* stub) {
}
static void GenerateRecordCallTarget(MacroAssembler* masm) {
static void GenerateRecordCallTarget(MacroAssembler* masm, bool is_super) {
// Cache the called function in a feedback vector slot. Cache states
// are uninitialized, monomorphic (indicated by a JSFunction), and
// megamorphic.
// rax : number of arguments to the construct function
// rbx : Feedback vector
// rbx : feedback vector
// rcx : original constructor (for IsSuperConstructorCall)
// rdx : slot in feedback vector (Smi)
// rdi : the function to call
Isolate* isolate = masm->isolate();
Label initialize, done, miss, megamorphic, not_array_function,
done_no_smi_convert;
// Load the cache state into rcx.
// Load the cache state into r11.
__ SmiToInteger32(rdx, rdx);
__ movp(rcx, FieldOperand(rbx, rdx, times_pointer_size,
FixedArray::kHeaderSize));
__ movp(r11,
FieldOperand(rbx, rdx, times_pointer_size, FixedArray::kHeaderSize));
// A monomorphic cache hit or an already megamorphic state: invoke the
// function without changing the state.
// We don't know if rcx is a WeakCell or a Symbol, but it's harmless to read
// We don't know if r11 is a WeakCell or a Symbol, but it's harmless to read
// at this position in a symbol (see static asserts in
// type-feedback-vector.h).
Label check_allocation_site;
__ cmpp(rdi, FieldOperand(rcx, WeakCell::kValueOffset));
__ cmpp(rdi, FieldOperand(r11, WeakCell::kValueOffset));
__ j(equal, &done, Label::kFar);
__ CompareRoot(rcx, Heap::kmegamorphic_symbolRootIndex);
__ CompareRoot(r11, Heap::kmegamorphic_symbolRootIndex);
__ j(equal, &done, Label::kFar);
__ CompareRoot(FieldOperand(rcx, HeapObject::kMapOffset),
__ CompareRoot(FieldOperand(r11, HeapObject::kMapOffset),
Heap::kWeakCellMapRootIndex);
__ j(not_equal, FLAG_pretenuring_call_new ? &miss : &check_allocation_site);
// If the weak cell is cleared, we have a new chance to become monomorphic.
__ CheckSmi(FieldOperand(rcx, WeakCell::kValueOffset));
__ CheckSmi(FieldOperand(r11, WeakCell::kValueOffset));
__ j(equal, &initialize);
__ jmp(&megamorphic);
......@@ -1853,12 +1862,12 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) {
// If we didn't have a matching function, and we didn't find the megamorph
// sentinel, then we have in the slot either some other function or an
// AllocationSite.
__ CompareRoot(FieldOperand(rcx, 0), Heap::kAllocationSiteMapRootIndex);
__ CompareRoot(FieldOperand(r11, 0), Heap::kAllocationSiteMapRootIndex);
__ j(not_equal, &miss);
// Make sure the function is the Array() function
__ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, rcx);
__ cmpp(rdi, rcx);
__ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, r11);
__ cmpp(rdi, r11);
__ j(not_equal, &megamorphic);
__ jmp(&done);
}
......@@ -1867,7 +1876,7 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) {
// A monomorphic miss (i.e, here the cache is not uninitialized) goes
// megamorphic.
__ CompareRoot(rcx, Heap::kuninitialized_symbolRootIndex);
__ CompareRoot(r11, Heap::kuninitialized_symbolRootIndex);
__ j(equal, &initialize);
// MegamorphicSentinel is an immortal immovable object (undefined) so no
// write-barrier is needed.
......@@ -1882,19 +1891,19 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) {
if (!FLAG_pretenuring_call_new) {
// Make sure the function is the Array() function
__ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, rcx);
__ cmpp(rdi, rcx);
__ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, r11);
__ cmpp(rdi, r11);
__ j(not_equal, &not_array_function);
CreateAllocationSiteStub create_stub(isolate);
CallStubInRecordCallTarget(masm, &create_stub);
CallStubInRecordCallTarget(masm, &create_stub, is_super);
__ jmp(&done_no_smi_convert);
__ bind(&not_array_function);
}
CreateWeakCellStub create_stub(isolate);
CallStubInRecordCallTarget(masm, &create_stub);
CallStubInRecordCallTarget(masm, &create_stub, is_super);
__ jmp(&done_no_smi_convert);
__ bind(&done);
......@@ -2044,13 +2053,7 @@ void CallConstructStub::Generate(MacroAssembler* masm) {
__ j(not_equal, &slow);
if (RecordCallTarget()) {
if (IsSuperConstructorCall()) {
__ Push(rcx);
}
GenerateRecordCallTarget(masm);
if (IsSuperConstructorCall()) {
__ Pop(rcx);
}
GenerateRecordCallTarget(masm, IsSuperConstructorCall());
__ SmiToInteger32(rdx, rdx);
if (FLAG_pretenuring_call_new) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment