Commit 7f3d15aa authored by mythria's avatar mythria Committed by Commit bot

[Interpreter] Adds stackcheck in InterpreterPushArgsAndCall/Construct builtins.

In ignition, arguments to function calls and function constructors are
pushed onto the stack before calling the function. It is required to check
that stack does not overflow when pushing the arguments.

BUG=v8:4280
LOG=N

Review-Url: https://codereview.chromium.org/2335513004
Cr-Commit-Position: refs/heads/master@{#39470}
parent e1341ca8
......@@ -1173,15 +1173,33 @@ void Builtins::Generate_InterpreterMarkBaselineOnReturn(MacroAssembler* masm) {
__ Jump(lr);
}
static void Generate_StackOverflowCheck(MacroAssembler* masm, Register num_args,
Register scratch,
Label* stack_overflow) {
// Check the stack for overflow. We are not trying to catch
// interruptions (e.g. debug break and preemption) here, so the "real stack
// limit" is checked.
__ LoadRoot(scratch, Heap::kRealStackLimitRootIndex);
// Make scratch the space we have left. The stack might already be overflowed
// here which will cause scratch to become negative.
__ sub(scratch, sp, scratch);
// Check if the arguments will overflow the stack.
__ cmp(scratch, Operand(num_args, LSL, kPointerSizeLog2));
__ b(le, stack_overflow); // Signed comparison.
}
static void Generate_InterpreterPushArgs(MacroAssembler* masm,
Register num_args, Register index,
Register limit, Register scratch) {
Register limit, Register scratch,
Label* stack_overflow) {
// Add a stack check before pushing arguments.
Generate_StackOverflowCheck(masm, num_args, scratch, stack_overflow);
// Find the address of the last argument.
__ mov(limit, num_args);
__ mov(limit, Operand(limit, LSL, kPointerSizeLog2));
__ sub(limit, index, limit);
// TODO(mythria): Add a stack check before pushing arguments.
Label loop_header, loop_check;
__ b(al, &loop_check);
__ bind(&loop_header);
......@@ -1203,11 +1221,12 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
// they are to be pushed onto the stack.
// -- r1 : the target to call (can be any Object).
// -----------------------------------
Label stack_overflow;
__ add(r3, r0, Operand(1)); // Add one for receiver.
// Push the arguments. r2, r4, r5 will be modified.
Generate_InterpreterPushArgs(masm, r3, r2, r4, r5);
Generate_InterpreterPushArgs(masm, r3, r2, r4, r5, &stack_overflow);
// Call the target.
if (function_type == CallableType::kJSFunction) {
......@@ -1220,6 +1239,13 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
tail_call_mode),
RelocInfo::CODE_TARGET);
}
__ bind(&stack_overflow);
{
__ TailCallRuntime(Runtime::kThrowStackOverflow);
// Unreachable code.
__ bkpt(0);
}
}
// static
......@@ -1232,14 +1258,14 @@ void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
// -- r2 : allocation site feedback if available, undefined otherwise.
// -- r4 : address of the first argument
// -----------------------------------
Label stack_overflow;
// Push a slot for the receiver to be constructed.
__ mov(ip, Operand::Zero());
__ push(ip);
// TODO(mythria): Add a stack check before pushing arguments.
// Push the arguments. r5, r4, r6 will be modified.
Generate_InterpreterPushArgs(masm, r0, r4, r5, r6);
Generate_InterpreterPushArgs(masm, r0, r4, r5, r6, &stack_overflow);
__ AssertUndefinedOrAllocationSite(r2, r5);
if (construct_type == CallableType::kJSFunction) {
......@@ -1257,6 +1283,13 @@ void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
// Call the constructor with r0, r1, and r3 unmodified.
__ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
}
__ bind(&stack_overflow);
{
__ TailCallRuntime(Runtime::kThrowStackOverflow);
// Unreachable code.
__ bkpt(0);
}
}
// static
......@@ -1268,18 +1301,26 @@ void Builtins::Generate_InterpreterPushArgsAndConstructArray(
// -- r2 : allocation site feedback if available, undefined otherwise.
// -- r3 : address of the first argument
// -----------------------------------
Label stack_overflow;
__ add(r4, r0, Operand(1)); // Add one for receiver.
// TODO(mythria): Add a stack check before pushing arguments.
// Push the arguments. r3, r5, r6 will be modified.
Generate_InterpreterPushArgs(masm, r4, r3, r5, r6);
Generate_InterpreterPushArgs(masm, r4, r3, r5, r6, &stack_overflow);
// Array constructor expects constructor in r3. It is same as r1 here.
__ mov(r3, r1);
ArrayConstructorStub stub(masm->isolate());
__ TailCallStub(&stub);
__ bind(&stack_overflow);
{
__ TailCallRuntime(Runtime::kThrowStackOverflow);
// Unreachable code.
__ bkpt(0);
}
}
void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) {
......@@ -2097,26 +2138,6 @@ void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
}
}
static void ArgumentAdaptorStackCheck(MacroAssembler* masm,
Label* stack_overflow) {
// ----------- S t a t e -------------
// -- r0 : actual number of arguments
// -- r1 : function (passed through to callee)
// -- r2 : expected number of arguments
// -- r3 : new target (passed through to callee)
// -----------------------------------
// Check the stack for overflow. We are not trying to catch
// interruptions (e.g. debug break and preemption) here, so the "real stack
// limit" is checked.
__ LoadRoot(r5, Heap::kRealStackLimitRootIndex);
// Make r5 the space we have left. The stack might already be overflowed
// here which will cause r5 to become negative.
__ sub(r5, sp, r5);
// Check if the arguments will overflow the stack.
__ cmp(r5, Operand(r2, LSL, kPointerSizeLog2));
__ b(le, stack_overflow); // Signed comparison.
}
static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) {
__ SmiTag(r0);
__ mov(r4, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
......@@ -2801,7 +2822,7 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
{ // Enough parameters: actual >= expected
__ bind(&enough);
EnterArgumentsAdaptorFrame(masm);
ArgumentAdaptorStackCheck(masm, &stack_overflow);
Generate_StackOverflowCheck(masm, r2, r5, &stack_overflow);
// Calculate copy start address into r0 and copy end address into r4.
// r0: actual number of arguments as a smi
......@@ -2834,7 +2855,7 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
{ // Too few parameters: Actual < expected
__ bind(&too_few);
EnterArgumentsAdaptorFrame(masm);
ArgumentAdaptorStackCheck(masm, &stack_overflow);
Generate_StackOverflowCheck(masm, r2, r5, &stack_overflow);
// Calculate copy start address into r0 and copy end address is fp.
// r0: actual number of arguments as a smi
......
......@@ -1182,10 +1182,30 @@ void Builtins::Generate_InterpreterMarkBaselineOnReturn(MacroAssembler* masm) {
__ Ret();
}
static void Generate_StackOverflowCheck(MacroAssembler* masm, Register num_args,
Register scratch,
Label* stack_overflow) {
// Check the stack for overflow.
// We are not trying to catch interruptions (e.g. debug break and
// preemption) here, so the "real stack limit" is checked.
Label enough_stack_space;
__ LoadRoot(scratch, Heap::kRealStackLimitRootIndex);
// Make scratch the space we have left. The stack might already be overflowed
// here which will cause scratch to become negative.
__ Sub(scratch, jssp, scratch);
// Check if the arguments will overflow the stack.
__ Cmp(scratch, Operand(num_args, LSL, kPointerSizeLog2));
__ B(le, stack_overflow);
}
static void Generate_InterpreterPushArgs(MacroAssembler* masm,
Register num_args, Register index,
Register last_arg, Register stack_addr,
Register scratch) {
Register scratch,
Label* stack_overflow) {
// Add a stack check before pushing arguments.
Generate_StackOverflowCheck(masm, num_args, scratch, stack_overflow);
__ Mov(scratch, num_args);
__ lsl(scratch, scratch, kPointerSizeLog2);
__ sub(last_arg, index, scratch);
......@@ -1194,7 +1214,6 @@ static void Generate_InterpreterPushArgs(MacroAssembler* masm,
__ Mov(stack_addr, jssp);
__ Claim(scratch, 1);
// TODO(mythria): Add a stack check before pushing arguments.
// Push the arguments.
Label loop_header, loop_check;
__ B(&loop_check);
......@@ -1218,12 +1237,13 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
// they are to be pushed onto the stack.
// -- x1 : the target to call (can be any Object).
// -----------------------------------
Label stack_overflow;
// Add one for the receiver.
__ add(x3, x0, Operand(1));
// Push the arguments. x2, x4, x5, x6 will be modified.
Generate_InterpreterPushArgs(masm, x3, x2, x4, x5, x6);
Generate_InterpreterPushArgs(masm, x3, x2, x4, x5, x6, &stack_overflow);
// Call the target.
if (function_type == CallableType::kJSFunction) {
......@@ -1236,6 +1256,12 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
tail_call_mode),
RelocInfo::CODE_TARGET);
}
__ bind(&stack_overflow);
{
__ TailCallRuntime(Runtime::kThrowStackOverflow);
__ Unreachable();
}
}
// static
......@@ -1248,12 +1274,13 @@ void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
// -- x2 : allocation site feedback if available, undefined otherwise
// -- x4 : address of the first argument
// -----------------------------------
Label stack_overflow;
// Push a slot for the receiver.
__ Push(xzr);
// Push the arguments. x5, x4, x6, x7 will be modified.
Generate_InterpreterPushArgs(masm, x0, x4, x5, x6, x7);
Generate_InterpreterPushArgs(masm, x0, x4, x5, x6, x7, &stack_overflow);
__ AssertUndefinedOrAllocationSite(x2, x6);
if (construct_type == CallableType::kJSFunction) {
......@@ -1270,6 +1297,12 @@ void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
// Call the constructor with x0, x1, and x3 unmodified.
__ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
}
__ bind(&stack_overflow);
{
__ TailCallRuntime(Runtime::kThrowStackOverflow);
__ Unreachable();
}
}
// static
......@@ -1281,17 +1314,24 @@ void Builtins::Generate_InterpreterPushArgsAndConstructArray(
// -- x2 : allocation site feedback if available, undefined otherwise.
// -- x3 : address of the first argument
// -----------------------------------
Label stack_overflow;
__ add(x4, x0, Operand(1)); // Add one for the receiver.
// Push the arguments. x3, x5, x6, x7 will be modified.
Generate_InterpreterPushArgs(masm, x4, x3, x5, x6, x7);
Generate_InterpreterPushArgs(masm, x4, x3, x5, x6, x7, &stack_overflow);
// Array constructor expects constructor in x3. It is same as call target.
__ mov(x3, x1);
ArrayConstructorStub stub(masm->isolate());
__ TailCallStub(&stub);
__ bind(&stack_overflow);
{
__ TailCallRuntime(Runtime::kThrowStackOverflow);
__ Unreachable();
}
}
void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) {
......@@ -2152,27 +2192,6 @@ void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
}
}
static void ArgumentAdaptorStackCheck(MacroAssembler* masm,
Label* stack_overflow) {
// ----------- S t a t e -------------
// -- x0 : actual number of arguments
// -- x1 : function (passed through to callee)
// -- x2 : expected number of arguments
// -- x3 : new target (passed through to callee)
// -----------------------------------
// Check the stack for overflow.
// We are not trying to catch interruptions (e.g. debug break and
// preemption) here, so the "real stack limit" is checked.
Label enough_stack_space;
__ LoadRoot(x10, Heap::kRealStackLimitRootIndex);
// Make x10 the space we have left. The stack might already be overflowed
// here which will cause x10 to become negative.
__ Sub(x10, jssp, x10);
// Check if the arguments will overflow the stack.
__ Cmp(x10, Operand(x2, LSL, kPointerSizeLog2));
__ B(le, stack_overflow);
}
static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) {
__ SmiTag(x10, x0);
__ Mov(x11, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
......@@ -2887,7 +2906,7 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
{ // Enough parameters: actual >= expected
EnterArgumentsAdaptorFrame(masm);
ArgumentAdaptorStackCheck(masm, &stack_overflow);
Generate_StackOverflowCheck(masm, x2, x10, &stack_overflow);
Register copy_start = x10;
Register copy_end = x11;
......@@ -2934,7 +2953,7 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
Register scratch1 = x13, scratch2 = x14;
EnterArgumentsAdaptorFrame(masm);
ArgumentAdaptorStackCheck(masm, &stack_overflow);
Generate_StackOverflowCheck(masm, x2, x10, &stack_overflow);
__ Lsl(scratch2, argc_expected, kPointerSizeLog2);
__ Lsl(argc_actual, argc_actual, kPointerSizeLog2);
......
This diff is collapsed.
......@@ -1171,13 +1171,33 @@ void Builtins::Generate_InterpreterMarkBaselineOnReturn(MacroAssembler* masm) {
__ Jump(ra);
}
static void Generate_StackOverflowCheck(MacroAssembler* masm, Register num_args,
Register scratch1, Register scratch2,
Label* stack_overflow) {
// Check the stack for overflow. We are not trying to catch
// interruptions (e.g. debug break and preemption) here, so the "real stack
// limit" is checked.
__ LoadRoot(scratch1, Heap::kRealStackLimitRootIndex);
// Make scratch1 the space we have left. The stack might already be overflowed
// here which will cause scratch1 to become negative.
__ subu(scratch1, sp, scratch1);
// Check if the arguments will overflow the stack.
__ sll(scratch2, num_args, kPointerSizeLog2);
// Signed comparison.
__ Branch(stack_overflow, le, scratch1, Operand(scratch2));
}
static void Generate_InterpreterPushArgs(MacroAssembler* masm,
Register num_args, Register index,
Register scratch, Register last_addr) {
Register scratch, Register scratch2,
Label* stack_overflow) {
Generate_StackOverflowCheck(masm, num_args, scratch, scratch2,
stack_overflow);
// Find the address of the last argument.
__ mov(last_addr, num_args);
__ sll(last_addr, last_addr, kPointerSizeLog2);
__ Subu(last_addr, index, Operand(last_addr));
__ mov(scratch2, num_args);
__ sll(scratch2, scratch2, kPointerSizeLog2);
__ Subu(scratch2, index, Operand(scratch2));
// Push the arguments.
Label loop_header, loop_check;
......@@ -1187,7 +1207,7 @@ static void Generate_InterpreterPushArgs(MacroAssembler* masm,
__ Addu(index, index, Operand(-kPointerSize));
__ push(scratch);
__ bind(&loop_check);
__ Branch(&loop_header, gt, index, Operand(last_addr));
__ Branch(&loop_header, gt, index, Operand(scratch2));
}
// static
......@@ -1201,11 +1221,12 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
// they are to be pushed onto the stack.
// -- a1 : the target to call (can be any Object).
// -----------------------------------
Label stack_overflow;
__ Addu(t0, a0, Operand(1)); // Add one for receiver.
// This function modifies a2, t4 and t1.
Generate_InterpreterPushArgs(masm, t0, a2, t4, t1);
Generate_InterpreterPushArgs(masm, t0, a2, t4, t1, &stack_overflow);
// Call the target.
if (function_type == CallableType::kJSFunction) {
......@@ -1218,6 +1239,13 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
tail_call_mode),
RelocInfo::CODE_TARGET);
}
__ bind(&stack_overflow);
{
__ TailCallRuntime(Runtime::kThrowStackOverflow);
// Unreachable code.
__ break_(0xCC);
}
}
// static
......@@ -1230,12 +1258,13 @@ void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
// -- a2 : allocation site feedback if available, undefined otherwise.
// -- t4 : address of the first argument
// -----------------------------------
Label stack_overflow;
// Push a slot for the receiver.
__ push(zero_reg);
// This function modified t4, t1 and t0.
Generate_InterpreterPushArgs(masm, a0, t4, t1, t0);
Generate_InterpreterPushArgs(masm, a0, t4, t1, t0, &stack_overflow);
__ AssertUndefinedOrAllocationSite(a2, t0);
if (construct_type == CallableType::kJSFunction) {
......@@ -1252,6 +1281,13 @@ void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
// Call the constructor with a0, a1, and a3 unmodified.
__ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
}
__ bind(&stack_overflow);
{
__ TailCallRuntime(Runtime::kThrowStackOverflow);
// Unreachable code.
__ break_(0xCC);
}
}
// static
......@@ -1265,17 +1301,25 @@ void Builtins::Generate_InterpreterPushArgsAndConstructArray(
// arguments should be consecutive above this, in the same order as
// they are to be pushed onto the stack.
// -----------------------------------
Label stack_overflow;
__ Addu(t0, a0, Operand(1)); // Add one for receiver.
// This function modifies a3, t4, and t1.
Generate_InterpreterPushArgs(masm, t0, a3, t1, t4);
Generate_InterpreterPushArgs(masm, t0, a3, t1, t4, &stack_overflow);
// ArrayConstructor stub expects constructor in a3. Set it here.
__ mov(a3, a1);
ArrayConstructorStub stub(masm->isolate());
__ TailCallStub(&stub);
__ bind(&stack_overflow);
{
__ TailCallRuntime(Runtime::kThrowStackOverflow);
// Unreachable code.
__ break_(0xCC);
}
}
void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) {
......@@ -2108,27 +2152,6 @@ void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
}
}
static void ArgumentAdaptorStackCheck(MacroAssembler* masm,
Label* stack_overflow) {
// ----------- S t a t e -------------
// -- a0 : actual number of arguments
// -- a1 : function (passed through to callee)
// -- a2 : expected number of arguments
// -- a3 : new target (passed through to callee)
// -----------------------------------
// Check the stack for overflow. We are not trying to catch
// interruptions (e.g. debug break and preemption) here, so the "real stack
// limit" is checked.
__ LoadRoot(t1, Heap::kRealStackLimitRootIndex);
// Make t1 the space we have left. The stack might already be overflowed
// here which will cause t1 to become negative.
__ subu(t1, sp, t1);
// Check if the arguments will overflow the stack.
__ sll(at, a2, kPointerSizeLog2);
// Signed comparison.
__ Branch(stack_overflow, le, t1, Operand(at));
}
static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) {
__ sll(a0, a0, kSmiTagSize);
__ li(t0, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
......@@ -2871,7 +2894,7 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
// a3: new target (passed through to callee)
__ bind(&enough);
EnterArgumentsAdaptorFrame(masm);
ArgumentAdaptorStackCheck(masm, &stack_overflow);
Generate_StackOverflowCheck(masm, a2, t1, at, &stack_overflow);
// Calculate copy start address into a0 and copy end address into t1.
__ Lsa(a0, fp, a0, kPointerSizeLog2 - kSmiTagSize);
......@@ -2901,7 +2924,7 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
{ // Too few parameters: Actual < expected.
__ bind(&too_few);
EnterArgumentsAdaptorFrame(masm);
ArgumentAdaptorStackCheck(masm, &stack_overflow);
Generate_StackOverflowCheck(masm, a2, t1, at, &stack_overflow);
// Calculate copy start address into a0 and copy end address into t3.
// a0: actual number of arguments as a smi
......
......@@ -1163,13 +1163,33 @@ void Builtins::Generate_InterpreterMarkBaselineOnReturn(MacroAssembler* masm) {
__ Jump(ra);
}
static void Generate_StackOverflowCheck(MacroAssembler* masm, Register num_args,
Register scratch1, Register scratch2,
Label* stack_overflow) {
// Check the stack for overflow. We are not trying to catch
// interruptions (e.g. debug break and preemption) here, so the "real stack
// limit" is checked.
__ LoadRoot(scratch1, Heap::kRealStackLimitRootIndex);
// Make scratch1 the space we have left. The stack might already be overflowed
// here which will cause scratch1 to become negative.
__ dsubu(scratch1, sp, scratch1);
// Check if the arguments will overflow the stack.
__ dsll(scratch2, num_args, kPointerSizeLog2);
// Signed comparison.
__ Branch(stack_overflow, le, scratch1, Operand(scratch2));
}
static void Generate_InterpreterPushArgs(MacroAssembler* masm,
Register num_args, Register index,
Register last_addr, Register scratch) {
Register scratch, Register scratch2,
Label* stack_overflow) {
// Generate_StackOverflowCheck(masm, num_args, scratch, scratch2,
// stack_overflow);
// Find the address of the last argument.
__ mov(last_addr, num_args);
__ dsll(last_addr, last_addr, kPointerSizeLog2);
__ Dsubu(last_addr, index, Operand(last_addr));
__ mov(scratch2, num_args);
__ dsll(scratch2, scratch2, kPointerSizeLog2);
__ Dsubu(scratch2, index, Operand(scratch2));
// Push the arguments.
Label loop_header, loop_check;
......@@ -1179,7 +1199,7 @@ static void Generate_InterpreterPushArgs(MacroAssembler* masm,
__ Daddu(index, index, Operand(-kPointerSize));
__ push(scratch);
__ bind(&loop_check);
__ Branch(&loop_header, gt, index, Operand(last_addr));
__ Branch(&loop_header, gt, index, Operand(scratch2));
}
// static
......@@ -1193,11 +1213,12 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
// they are to be pushed onto the stack.
// -- a1 : the target to call (can be any Object).
// -----------------------------------
Label stack_overflow;
__ Daddu(a3, a0, Operand(1)); // Add one for receiver.
// This function modifies a2, t0 and a4.
Generate_InterpreterPushArgs(masm, a3, a2, a4, t0);
Generate_InterpreterPushArgs(masm, a3, a2, a4, t0, &stack_overflow);
// Call the target.
if (function_type == CallableType::kJSFunction) {
......@@ -1210,6 +1231,13 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
tail_call_mode),
RelocInfo::CODE_TARGET);
}
__ bind(&stack_overflow);
{
__ TailCallRuntime(Runtime::kThrowStackOverflow);
// Unreachable code.
__ break_(0xCC);
}
}
// static
......@@ -1222,12 +1250,13 @@ void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
// -- a2 : allocation site feedback if available, undefined otherwise.
// -- a4 : address of the first argument
// -----------------------------------
Label stack_overflow;
// Push a slot for the receiver.
__ push(zero_reg);
// This function modifies t0, a4 and a5.
Generate_InterpreterPushArgs(masm, a0, a4, a5, t0);
Generate_InterpreterPushArgs(masm, a0, a4, a5, t0, &stack_overflow);
__ AssertUndefinedOrAllocationSite(a2, t0);
if (construct_type == CallableType::kJSFunction) {
......@@ -1244,6 +1273,13 @@ void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
// Call the constructor with a0, a1, and a3 unmodified.
__ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
}
__ bind(&stack_overflow);
{
__ TailCallRuntime(Runtime::kThrowStackOverflow);
// Unreachable code.
__ break_(0xCC);
}
}
// static
......@@ -1257,17 +1293,25 @@ void Builtins::Generate_InterpreterPushArgsAndConstructArray(
// arguments should be consecutive above this, in the same order as
// they are to be pushed onto the stack.
// -----------------------------------
Label stack_overflow;
__ Daddu(a4, a0, Operand(1)); // Add one for receiver.
// This function modifies a3, a5 and a6.
Generate_InterpreterPushArgs(masm, a4, a3, a5, a6);
Generate_InterpreterPushArgs(masm, a4, a3, a5, a6, &stack_overflow);
// ArrayConstructor stub expects constructor in a3. Set it here.
__ mov(a3, a1);
ArrayConstructorStub stub(masm->isolate());
__ TailCallStub(&stub);
__ bind(&stack_overflow);
{
__ TailCallRuntime(Runtime::kThrowStackOverflow);
// Unreachable code.
__ break_(0xCC);
}
}
void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) {
......@@ -2102,27 +2146,6 @@ void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
}
}
static void ArgumentAdaptorStackCheck(MacroAssembler* masm,
Label* stack_overflow) {
// ----------- S t a t e -------------
// -- a0 : actual number of arguments
// -- a1 : function (passed through to callee)
// -- a2 : expected number of arguments
// -- a3 : new target (passed through to callee)
// -----------------------------------
// Check the stack for overflow. We are not trying to catch
// interruptions (e.g. debug break and preemption) here, so the "real stack
// limit" is checked.
__ LoadRoot(a5, Heap::kRealStackLimitRootIndex);
// Make a5 the space we have left. The stack might already be overflowed
// here which will cause a5 to become negative.
__ dsubu(a5, sp, a5);
// Check if the arguments will overflow the stack.
__ dsll(at, a2, kPointerSizeLog2);
// Signed comparison.
__ Branch(stack_overflow, le, a5, Operand(at));
}
static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) {
// __ sll(a0, a0, kSmiTagSize);
__ dsll32(a0, a0, 0);
......@@ -2864,7 +2887,7 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
// a3: new target (passed through to callee)
__ bind(&enough);
EnterArgumentsAdaptorFrame(masm);
ArgumentAdaptorStackCheck(masm, &stack_overflow);
Generate_StackOverflowCheck(masm, a2, a5, at, &stack_overflow);
// Calculate copy start address into a0 and copy end address into a4.
__ SmiScale(a0, a0, kPointerSizeLog2);
......@@ -2895,7 +2918,7 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
{ // Too few parameters: Actual < expected.
__ bind(&too_few);
EnterArgumentsAdaptorFrame(masm);
ArgumentAdaptorStackCheck(masm, &stack_overflow);
Generate_StackOverflowCheck(masm, a2, a5, at, &stack_overflow);
// Calculate copy start address into a0 and copy end address into a7.
// a0: actual number of arguments as a smi
......
......@@ -791,6 +791,26 @@ void Builtins::Generate_InterpreterMarkBaselineOnReturn(MacroAssembler* masm) {
__ ret(0);
}
static void Generate_StackOverflowCheck(MacroAssembler* masm, Register num_args,
Register scratch1, Register scratch2,
Label* stack_overflow) {
// Check the stack for overflow. We are not trying to catch
// interruptions (e.g. debug break and preemption) here, so the "real stack
// limit" is checked.
__ LoadRoot(scratch1, Heap::kRealStackLimitRootIndex);
__ movp(scratch2, rsp);
// Make scratch2 the space we have left. The stack might already be overflowed
// here which will cause scratch2 to become negative.
__ subp(scratch2, scratch1);
// Make scratch1 the space we need for the array when it is unrolled onto the
// stack.
__ movp(scratch1, num_args);
__ shlp(scratch1, Immediate(kPointerSizeLog2));
// Check if the arguments will overflow the stack.
__ cmpp(scratch2, scratch1);
__ j(less_equal, stack_overflow); // Signed comparison.
}
static void Generate_InterpreterPushArgs(MacroAssembler* masm,
Register num_args,
Register start_address,
......@@ -801,7 +821,6 @@ static void Generate_InterpreterPushArgs(MacroAssembler* masm,
__ negp(scratch);
__ addp(scratch, start_address);
// TODO(mythria): Add a stack check before pushing arguments.
// Push the arguments.
Label loop_header, loop_check;
__ j(always, &loop_check);
......@@ -824,14 +843,18 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
// they are to be pushed onto the stack.
// -- rdi : the target to call (can be any Object).
// -----------------------------------
// Pop return address to allow tail-call after pushing arguments.
__ PopReturnAddressTo(kScratchRegister);
Label stack_overflow;
// Number of values to be pushed.
__ Move(rcx, rax);
__ addp(rcx, Immediate(1)); // Add one for receiver.
// Add a stack check before pushing arguments.
Generate_StackOverflowCheck(masm, rcx, rdx, r8, &stack_overflow);
// Pop return address to allow tail-call after pushing arguments.
__ PopReturnAddressTo(kScratchRegister);
// rbx and rdx will be modified.
Generate_InterpreterPushArgs(masm, rcx, rbx, rdx);
......@@ -848,6 +871,14 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
tail_call_mode),
RelocInfo::CODE_TARGET);
}
// Throw stack overflow exception.
__ bind(&stack_overflow);
{
__ TailCallRuntime(Runtime::kThrowStackOverflow);
// This should be unreachable.
__ int3();
}
}
// static
......@@ -863,6 +894,10 @@ void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
// arguments should be consecutive above this, in the same order as
// they are to be pushed onto the stack.
// -----------------------------------
Label stack_overflow;
// Add a stack check before pushing arguments.
Generate_StackOverflowCheck(masm, rax, r8, r9, &stack_overflow);
// Pop return address to allow tail-call after pushing arguments.
__ PopReturnAddressTo(kScratchRegister);
......@@ -892,6 +927,14 @@ void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
// Call the constructor (rax, rdx, rdi passed on).
__ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
}
// Throw stack overflow exception.
__ bind(&stack_overflow);
{
__ TailCallRuntime(Runtime::kThrowStackOverflow);
// This should be unreachable.
__ int3();
}
}
// static
......@@ -905,14 +948,18 @@ void Builtins::Generate_InterpreterPushArgsAndConstructArray(
// arguments should be consecutive above this, in the same order as
// they are to be pushed onto the stack.
// -----------------------------------
// Pop return address to allow tail-call after pushing arguments.
__ PopReturnAddressTo(kScratchRegister);
Label stack_overflow;
// Number of values to be pushed.
__ Move(r8, rax);
__ addp(r8, Immediate(1)); // Add one for receiver.
// Add a stack check before pushing arguments.
Generate_StackOverflowCheck(masm, r8, rdi, r9, &stack_overflow);
// Pop return address to allow tail-call after pushing arguments.
__ PopReturnAddressTo(kScratchRegister);
// rcx and rdi will be modified.
Generate_InterpreterPushArgs(masm, r8, rcx, rdi);
......@@ -924,6 +971,14 @@ void Builtins::Generate_InterpreterPushArgsAndConstructArray(
ArrayConstructorStub stub(masm->isolate());
__ TailCallStub(&stub);
// Throw stack overflow exception.
__ bind(&stack_overflow);
{
__ TailCallRuntime(Runtime::kThrowStackOverflow);
// This should be unreachable.
__ int3();
}
}
void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) {
......@@ -2062,32 +2117,6 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
}
}
static void ArgumentsAdaptorStackCheck(MacroAssembler* masm,
Label* stack_overflow) {
// ----------- S t a t e -------------
// -- rax : actual number of arguments
// -- rbx : expected number of arguments
// -- rdx : new target (passed through to callee)
// -- rdi : function (passed through to callee)
// -----------------------------------
// Check the stack for overflow. We are not trying to catch
// interruptions (e.g. debug break and preemption) here, so the "real stack
// limit" is checked.
Label okay;
__ LoadRoot(r8, Heap::kRealStackLimitRootIndex);
__ movp(rcx, rsp);
// Make rcx the space we have left. The stack might already be overflowed
// here which will cause rcx to become negative.
__ subp(rcx, r8);
// Make r8 the space we need for the array when it is unrolled onto the
// stack.
__ movp(r8, rbx);
__ shlp(r8, Immediate(kPointerSizeLog2));
// Check if the arguments will overflow the stack.
__ cmpp(rcx, r8);
__ j(less_equal, stack_overflow); // Signed comparison.
}
static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) {
__ pushq(rbp);
__ movp(rbp, rsp);
......@@ -2183,7 +2212,8 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
{ // Enough parameters: Actual >= expected.
__ bind(&enough);
EnterArgumentsAdaptorFrame(masm);
ArgumentsAdaptorStackCheck(masm, &stack_overflow);
// The registers rcx and r8 will be modified. The register rbx is only read.
Generate_StackOverflowCheck(masm, rbx, rcx, r8, &stack_overflow);
// Copy receiver and all expected arguments.
const int offset = StandardFrameConstants::kCallerSPOffset;
......@@ -2204,7 +2234,8 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
__ bind(&too_few);
EnterArgumentsAdaptorFrame(masm);
ArgumentsAdaptorStackCheck(masm, &stack_overflow);
// The registers rcx and r8 will be modified. The register rbx is only read.
Generate_StackOverflowCheck(masm, rbx, rcx, r8, &stack_overflow);
// Copy receiver and all actual arguments.
const int offset = StandardFrameConstants::kCallerSPOffset;
......
......@@ -40,7 +40,12 @@ try {
overflow();
} catch (e) {
var first_frame = e.stack.split("\n")[1]
assertTrue(first_frame.indexOf("stack-traces-overflow.js:30:18") > 0);
// The overflow can happen when pushing the arguments (in interpreter) or when
// the new function execution is starting. So the stack trace could either
// point to start of the function (stack-traces-overflow.js30:18) or to the
// location of call (stack-traces-overflow.js32:3).
assertTrue((first_frame.indexOf("stack-traces-overflow.js:30:18") > 0) ||
(first_frame.indexOf("stack-traces-overflow.js:32:3") > 0) );
}
// Test stack trace getter and setter.
......
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