From a50aca97a2748eaabb415c30ada20988cb4a48b2 Mon Sep 17 00:00:00 2001 From: "ulan@chromium.org" Date: Tue, 15 Apr 2014 08:26:26 +0000 Subject: [PATCH] Reland r20692 "Check stack limit in ArgumentAdaptorTrampoline." BUG=353058 LOG=N TEST=mjsunit/regress/regress-353058 R=mstarzinger@chromium.org Review URL: https://codereview.chromium.org/236633006 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@20751 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/arm/builtins-arm.cc | 32 +++++++++++++++++++++++++++++++- src/arm64/builtins-arm64.cc | 35 ++++++++++++++++++++++++++++++++++- src/builtins.h | 2 +- src/ia32/builtins-ia32.cc | 40 +++++++++++++++++++++++++++++++++++++++- src/mips/builtins-mips.cc | 2 +- src/runtime.js | 2 +- src/x64/builtins-x64.cc | 38 +++++++++++++++++++++++++++++++++++++- test/mjsunit/mjsunit.status | 8 -------- 8 files changed, 144 insertions(+), 15 deletions(-) diff --git a/src/arm/builtins-arm.cc b/src/arm/builtins-arm.cc index f138146..81d7fcb 100644 --- a/src/arm/builtins-arm.cc +++ b/src/arm/builtins-arm.cc @@ -1284,7 +1284,7 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) { // Out of stack space. __ ldr(r1, MemOperand(fp, kFunctionOffset)); __ Push(r1, r0); - __ InvokeBuiltin(Builtins::APPLY_OVERFLOW, CALL_FUNCTION); + __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION); // End of stack check. // Push current limit and index. @@ -1407,6 +1407,26 @@ void Builtins::Generate_FunctionApply(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 + // ----------------------------------- + // 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))); @@ -1446,6 +1466,8 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { // -- r2 : expected number of arguments // ----------------------------------- + Label stack_overflow; + ArgumentAdaptorStackCheck(masm, &stack_overflow); Label invoke, dont_adapt_arguments; Label enough, too_few; @@ -1545,6 +1567,14 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { // ------------------------------------------- __ bind(&dont_adapt_arguments); __ Jump(r3); + + __ bind(&stack_overflow); + { + FrameScope frame(masm, StackFrame::MANUAL); + EnterArgumentsAdaptorFrame(masm); + __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION); + __ bkpt(0); + } } diff --git a/src/arm64/builtins-arm64.cc b/src/arm64/builtins-arm64.cc index 01ac4cc..3fbe67b 100644 --- a/src/arm64/builtins-arm64.cc +++ b/src/arm64/builtins-arm64.cc @@ -1280,7 +1280,7 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) { // There is not enough stack space, so use a builtin to throw an appropriate // error. __ Push(function, argc); - __ InvokeBuiltin(Builtins::APPLY_OVERFLOW, CALL_FUNCTION); + __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION); // We should never return from the APPLY_OVERFLOW builtin. if (__ emit_debug_code()) { __ Unreachable(); @@ -1400,6 +1400,28 @@ void Builtins::Generate_FunctionApply(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 + // ----------------------------------- + // 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); + __ Mov(x11, jssp); + // 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)); @@ -1433,6 +1455,9 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { // -- x2 : expected number of arguments // ----------------------------------- + Label stack_overflow; + ArgumentAdaptorStackCheck(masm, &stack_overflow); + Register argc_actual = x0; // Excluding the receiver. Register argc_expected = x2; // Excluding the receiver. Register function = x1; @@ -1552,6 +1577,14 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { // Call the entry point without adapting the arguments. __ Bind(&dont_adapt_arguments); __ Jump(code_entry); + + __ Bind(&stack_overflow); + { + FrameScope frame(masm, StackFrame::MANUAL); + EnterArgumentsAdaptorFrame(masm); + __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION); + __ Brk(0); + } } diff --git a/src/builtins.h b/src/builtins.h index 88cfd53..16d7835 100644 --- a/src/builtins.h +++ b/src/builtins.h @@ -260,7 +260,7 @@ enum BuiltinExtraArguments { V(STRING_ADD_LEFT, 1) \ V(STRING_ADD_RIGHT, 1) \ V(APPLY_PREPARE, 1) \ - V(APPLY_OVERFLOW, 1) + V(STACK_OVERFLOW, 1) class BuiltinFunctionTable; class ObjectVisitor; diff --git a/src/ia32/builtins-ia32.cc b/src/ia32/builtins-ia32.cc index 785c5fd..12ab3b4 100644 --- a/src/ia32/builtins-ia32.cc +++ b/src/ia32/builtins-ia32.cc @@ -949,7 +949,7 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) { // Out of stack space. __ push(Operand(ebp, 4 * kPointerSize)); // push this __ push(eax); - __ InvokeBuiltin(Builtins::APPLY_OVERFLOW, CALL_FUNCTION); + __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION); __ bind(&okay); // End of stack check. @@ -1252,6 +1252,33 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) { } +static void ArgumentsAdaptorStackCheck(MacroAssembler* masm, + Label* stack_overflow) { + // ----------- S t a t e ------------- + // -- eax : actual number of arguments + // -- ebx : expected number of arguments + // -- edi : 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. + ExternalReference real_stack_limit = + ExternalReference::address_of_real_stack_limit(masm->isolate()); + __ mov(edx, Operand::StaticVariable(real_stack_limit)); + // Make ecx the space we have left. The stack might already be overflowed + // here which will cause ecx to become negative. + __ mov(ecx, esp); + __ sub(ecx, edx); + // Make edx the space we need for the array when it is unrolled onto the + // stack. + __ mov(edx, ebx); + __ shl(edx, kPointerSizeLog2); + // Check if the arguments will overflow the stack. + __ cmp(ecx, edx); + __ j(less_equal, stack_overflow); // Signed comparison. +} + + static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) { __ push(ebp); __ mov(ebp, esp); @@ -1296,6 +1323,9 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { Label invoke, dont_adapt_arguments; __ IncrementCounter(masm->isolate()->counters()->arguments_adaptors(), 1); + Label stack_overflow; + ArgumentsAdaptorStackCheck(masm, &stack_overflow); + Label enough, too_few; __ mov(edx, FieldOperand(edi, JSFunction::kCodeEntryOffset)); __ cmp(eax, ebx); @@ -1370,6 +1400,14 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { // ------------------------------------------- __ bind(&dont_adapt_arguments); __ jmp(edx); + + __ bind(&stack_overflow); + { + FrameScope frame(masm, StackFrame::MANUAL); + EnterArgumentsAdaptorFrame(masm); + __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION); + __ int3(); + } } diff --git a/src/mips/builtins-mips.cc b/src/mips/builtins-mips.cc index 03d6cc8..f941440 100644 --- a/src/mips/builtins-mips.cc +++ b/src/mips/builtins-mips.cc @@ -1305,7 +1305,7 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) { // Out of stack space. __ lw(a1, MemOperand(fp, kFunctionOffset)); __ Push(a1, v0); - __ InvokeBuiltin(Builtins::APPLY_OVERFLOW, CALL_FUNCTION); + __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION); // End of stack check. // Push current limit and index. diff --git a/src/runtime.js b/src/runtime.js index a49bc84..7b83345 100644 --- a/src/runtime.js +++ b/src/runtime.js @@ -464,7 +464,7 @@ function APPLY_PREPARE(args) { } -function APPLY_OVERFLOW(length) { +function STACK_OVERFLOW(length) { throw %MakeRangeError('stack_overflow', []); } diff --git a/src/x64/builtins-x64.cc b/src/x64/builtins-x64.cc index d14a935..5803ad7 100644 --- a/src/x64/builtins-x64.cc +++ b/src/x64/builtins-x64.cc @@ -1017,7 +1017,7 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) { // Out of stack space. __ Push(Operand(rbp, kFunctionOffset)); __ Push(rax); - __ InvokeBuiltin(Builtins::APPLY_OVERFLOW, CALL_FUNCTION); + __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION); __ bind(&okay); // End of stack check. @@ -1322,6 +1322,31 @@ void Builtins::Generate_StringConstructCode(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 + // -- 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(rdx, 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, rdx); + // Make rdx the space we need for the array when it is unrolled onto the + // stack. + __ PositiveSmiTimesPowerOfTwoToInteger64(rdx, rax, kPointerSizeLog2); + // Check if the arguments will overflow the stack. + __ cmpp(rcx, rdx); + __ j(less_equal, stack_overflow); // Signed comparison. +} + + static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) { __ pushq(rbp); __ movp(rbp, rsp); @@ -1367,6 +1392,9 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { Counters* counters = masm->isolate()->counters(); __ IncrementCounter(counters->arguments_adaptors(), 1); + Label stack_overflow; + ArgumentsAdaptorStackCheck(masm, &stack_overflow); + Label enough, too_few; __ movp(rdx, FieldOperand(rdi, JSFunction::kCodeEntryOffset)); __ cmpp(rax, rbx); @@ -1439,6 +1467,14 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { // ------------------------------------------- __ bind(&dont_adapt_arguments); __ jmp(rdx); + + __ bind(&stack_overflow); + { + FrameScope frame(masm, StackFrame::MANUAL); + EnterArgumentsAdaptorFrame(masm); + __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION); + __ int3(); + } } diff --git a/test/mjsunit/mjsunit.status b/test/mjsunit/mjsunit.status index f604e1c..9b9bf32 100644 --- a/test/mjsunit/mjsunit.status +++ b/test/mjsunit/mjsunit.status @@ -168,9 +168,6 @@ 'regress/regress-91013': [SKIP], 'regress/regress-99167': [SKIP], - # TODO(ulan): enable this after relanding r20692. - 'regress/regress-353058': [SKIP], - # Long running tests. 'regress/regress-2185': [PASS, ['mode == debug', PASS, TIMEOUT]], 'regress/regress-2185-2': [PASS, TIMEOUT], @@ -237,8 +234,6 @@ 'big-array-literal': [SKIP], 'big-object-literal': [SKIP], 'regress/regress-crbug-178790': [SKIP], - # TODO(ulan): enable this after relanding r20692. - 'regress/regress-353058': [SKIP], }], # 'asan == True' ############################################################################## @@ -269,9 +264,6 @@ 'regress/regress-create-exception': [SKIP], 'regress/regress-3247124': [SKIP], - # TODO(ulan): enable this after relanding r20692. - 'regress/regress-353058': [SKIP], - # Requires bigger stack size in the Genesis and if stack size is increased, # the test requires too much time to run. However, the problem test covers # should be platform-independent. -- 2.7.4