Interrupts must not mask stack overflow.
authoryangguo@chromium.org <yangguo@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 17 Jun 2014 13:54:49 +0000 (13:54 +0000)
committeryangguo@chromium.org <yangguo@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 17 Jun 2014 13:54:49 +0000 (13:54 +0000)
R=jarin@chromium.org
BUG=385002
LOG=N

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

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@21874 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

14 files changed:
src/arm/full-codegen-arm.cc
src/arm/regexp-macro-assembler-arm.cc
src/arm64/full-codegen-arm64.cc
src/arm64/regexp-macro-assembler-arm64.cc
src/execution.cc
src/execution.h
src/ia32/full-codegen-ia32.cc
src/ia32/regexp-macro-assembler-ia32.cc
src/isolate.cc
src/isolate.h
src/runtime.cc
src/x64/full-codegen-x64.cc
src/x64/regexp-macro-assembler-x64.cc
test/mjsunit/regress/regress-crbug-385002.js [new file with mode: 0644]

index 241991c..8b079ed 100644 (file)
@@ -88,31 +88,6 @@ class JumpPatchSite BASE_EMBEDDED {
 };
 
 
-static void EmitStackCheck(MacroAssembler* masm_,
-                           Register stack_limit_scratch,
-                           int pointers = 0,
-                           Register scratch = sp) {
-    Isolate* isolate = masm_->isolate();
-  Label ok;
-  ASSERT(scratch.is(sp) == (pointers == 0));
-  Heap::RootListIndex index;
-  if (pointers != 0) {
-    __ sub(scratch, sp, Operand(pointers * kPointerSize));
-    index = Heap::kRealStackLimitRootIndex;
-  } else {
-    index = Heap::kStackLimitRootIndex;
-  }
-  __ LoadRoot(stack_limit_scratch, index);
-  __ cmp(scratch, Operand(stack_limit_scratch));
-  __ b(hs, &ok);
-  Handle<Code> stack_check = isolate->builtins()->StackCheck();
-  PredictableCodeSizeScope predictable(masm_,
-      masm_->CallSize(stack_check, RelocInfo::CODE_TARGET));
-  __ Call(stack_check, RelocInfo::CODE_TARGET);
-  __ bind(&ok);
-}
-
-
 // Generate code for a JS function.  On entry to the function the receiver
 // and arguments have been pushed on the stack left to right.  The actual
 // argument count matches the formal parameter count expected by the
@@ -180,7 +155,13 @@ void FullCodeGenerator::Generate() {
     ASSERT(!info->function()->is_generator() || locals_count == 0);
     if (locals_count > 0) {
       if (locals_count >= 128) {
-        EmitStackCheck(masm_, r2, locals_count, r9);
+        Label ok;
+        __ sub(r9, sp, Operand(locals_count * kPointerSize));
+        __ LoadRoot(r2, Heap::kRealStackLimitRootIndex);
+        __ cmp(r9, Operand(r2));
+        __ b(hs, &ok);
+        __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION);
+        __ bind(&ok);
       }
       __ LoadRoot(r9, Heap::kUndefinedValueRootIndex);
       int kMaxPushes = FLAG_optimize_for_size ? 4 : 32;
@@ -321,7 +302,15 @@ void FullCodeGenerator::Generate() {
 
     { Comment cmnt(masm_, "[ Stack check");
       PrepareForBailoutForId(BailoutId::Declarations(), NO_REGISTERS);
-      EmitStackCheck(masm_, ip);
+      Label ok;
+      __ LoadRoot(ip, Heap::kStackLimitRootIndex);
+      __ cmp(sp, Operand(ip));
+      __ b(hs, &ok);
+      Handle<Code> stack_check = isolate()->builtins()->StackCheck();
+      PredictableCodeSizeScope predictable(masm_,
+          masm_->CallSize(stack_check, RelocInfo::CODE_TARGET));
+      __ Call(stack_check, RelocInfo::CODE_TARGET);
+      __ bind(&ok);
     }
 
     { Comment cmnt(masm_, "[ Body");
index 7fa3ce7..e494305 100644 (file)
@@ -1044,7 +1044,8 @@ int RegExpMacroAssemblerARM::CheckStackGuardState(Address* return_address,
                                                   Code* re_code,
                                                   Address re_frame) {
   Isolate* isolate = frame_entry<Isolate*>(re_frame, kIsolate);
-  if (isolate->stack_guard()->IsStackOverflow()) {
+  StackLimitCheck check(isolate);
+  if (check.JsHasOverflowed()) {
     isolate->StackOverflow();
     return EXCEPTION;
   }
index b74a058..4a44e35 100644 (file)
@@ -87,29 +87,6 @@ class JumpPatchSite BASE_EMBEDDED {
 };
 
 
-static void EmitStackCheck(MacroAssembler* masm_,
-                           int pointers = 0,
-                           Register scratch = jssp) {
-  Isolate* isolate = masm_->isolate();
-  Label ok;
-  ASSERT(jssp.Is(__ StackPointer()));
-  ASSERT(scratch.Is(jssp) == (pointers == 0));
-  Heap::RootListIndex index;
-  if (pointers != 0) {
-    __ Sub(scratch, jssp, pointers * kPointerSize);
-    index = Heap::kRealStackLimitRootIndex;
-  } else {
-    index = Heap::kStackLimitRootIndex;
-  }
-  __ CompareRoot(scratch, index);
-  __ B(hs, &ok);
-  PredictableCodeSizeScope predictable(masm_,
-                                       Assembler::kCallSizeWithRelocation);
-  __ Call(isolate->builtins()->StackCheck(), RelocInfo::CODE_TARGET);
-  __ Bind(&ok);
-}
-
-
 // Generate code for a JS function. On entry to the function the receiver
 // and arguments have been pushed on the stack left to right. The actual
 // argument count matches the formal parameter count expected by the
@@ -181,7 +158,13 @@ void FullCodeGenerator::Generate() {
 
     if (locals_count > 0) {
       if (locals_count >= 128) {
-        EmitStackCheck(masm_, locals_count, x10);
+        Label ok;
+        ASSERT(jssp.Is(__ StackPointer()));
+        __ Sub(x10, jssp, locals_count * kPointerSize);
+        __ CompareRoot(x10, Heap::kRealStackLimitRootIndex);
+        __ B(hs, &ok);
+        __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION);
+        __ Bind(&ok);
       }
       __ LoadRoot(x10, Heap::kUndefinedValueRootIndex);
       if (FLAG_optimize_for_size) {
@@ -319,7 +302,14 @@ void FullCodeGenerator::Generate() {
 
   { Comment cmnt(masm_, "[ Stack check");
     PrepareForBailoutForId(BailoutId::Declarations(), NO_REGISTERS);
-    EmitStackCheck(masm_);
+    Label ok;
+    ASSERT(jssp.Is(__ StackPointer()));
+    __ CompareRoot(jssp, Heap::kStackLimitRootIndex);
+    __ B(hs, &ok);
+    PredictableCodeSizeScope predictable(masm_,
+                                         Assembler::kCallSizeWithRelocation);
+    __ Call(isolate()->builtins()->StackCheck(), RelocInfo::CODE_TARGET);
+    __ Bind(&ok);
   }
 
   { Comment cmnt(masm_, "[ Body");
index f236352..a772ef2 100644 (file)
@@ -1289,7 +1289,8 @@ int RegExpMacroAssemblerARM64::CheckStackGuardState(Address* return_address,
                                                   const byte** input_start,
                                                   const byte** input_end) {
   Isolate* isolate = frame_entry<Isolate*>(re_frame, kIsolate);
-  if (isolate->stack_guard()->IsStackOverflow()) {
+  StackLimitCheck check(isolate);
+  if (check.JsHasOverflowed()) {
     isolate->StackOverflow();
     return EXCEPTION;
   }
index fa35689..2766e76 100644 (file)
@@ -307,13 +307,6 @@ MaybeHandle<Object> Execution::TryGetConstructorDelegate(
 }
 
 
-bool StackGuard::IsStackOverflow() {
-  ExecutionAccess access(isolate_);
-  return (thread_local_.jslimit_ != kInterruptLimit &&
-          thread_local_.climit_ != kInterruptLimit);
-}
-
-
 void StackGuard::EnableInterrupts() {
   ExecutionAccess access(isolate_);
   if (has_pending_interrupts(access)) {
index 16bc625..74d0feb 100644 (file)
@@ -145,8 +145,6 @@ class StackGuard V8_FINAL {
   // it has been set up.
   void ClearThread(const ExecutionAccess& lock);
 
-  bool IsStackOverflow();
-
 #define INTERRUPT_LIST(V)                                       \
   V(DEBUGBREAK, DebugBreak)                                     \
   V(DEBUGCOMMAND, DebugCommand)                                 \
@@ -266,6 +264,11 @@ enum InterruptFlag {
     int interrupt_flags_;
   };
 
+  class StackPointer {
+   public:
+    inline uintptr_t address() { return reinterpret_cast<uintptr_t>(this); }
+  };
+
   // TODO(isolates): Technically this could be calculated directly from a
   //                 pointer to StackGuard.
   Isolate* isolate_;
index c9e280d..0ea77f0 100644 (file)
@@ -78,27 +78,6 @@ class JumpPatchSite BASE_EMBEDDED {
 };
 
 
-static void EmitStackCheck(MacroAssembler* masm_,
-                           int pointers = 0,
-                           Register scratch = esp) {
-    Label ok;
-    Isolate* isolate = masm_->isolate();
-    ASSERT(scratch.is(esp) == (pointers == 0));
-    ExternalReference stack_limit;
-    if (pointers != 0) {
-      __ mov(scratch, esp);
-      __ sub(scratch, Immediate(pointers * kPointerSize));
-      stack_limit = ExternalReference::address_of_real_stack_limit(isolate);
-    } else {
-      stack_limit = ExternalReference::address_of_stack_limit(isolate);
-    }
-    __ cmp(scratch, Operand::StaticVariable(stack_limit));
-    __ j(above_equal, &ok, Label::kNear);
-    __ call(isolate->builtins()->StackCheck(), RelocInfo::CODE_TARGET);
-    __ bind(&ok);
-}
-
-
 // Generate code for a JS function.  On entry to the function the receiver
 // and arguments have been pushed on the stack left to right, with the
 // return address on top of them.  The actual argument count matches the
@@ -168,7 +147,15 @@ void FullCodeGenerator::Generate() {
       __ push(Immediate(isolate()->factory()->undefined_value()));
     } else if (locals_count > 1) {
       if (locals_count >= 128) {
-        EmitStackCheck(masm_, locals_count, ecx);
+        Label ok;
+        __ mov(ecx, esp);
+        __ sub(ecx, Immediate(locals_count * kPointerSize));
+        ExternalReference stack_limit =
+            ExternalReference::address_of_real_stack_limit(isolate());
+        __ cmp(ecx, Operand::StaticVariable(stack_limit));
+        __ j(above_equal, &ok, Label::kNear);
+        __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION);
+        __ bind(&ok);
       }
       __ mov(eax, Immediate(isolate()->factory()->undefined_value()));
       const int kMaxPushes = 32;
@@ -309,7 +296,13 @@ void FullCodeGenerator::Generate() {
 
     { Comment cmnt(masm_, "[ Stack check");
       PrepareForBailoutForId(BailoutId::Declarations(), NO_REGISTERS);
-      EmitStackCheck(masm_);
+      Label ok;
+      ExternalReference stack_limit
+          = ExternalReference::address_of_stack_limit(isolate());
+      __ cmp(esp, Operand::StaticVariable(stack_limit));
+      __ j(above_equal, &ok, Label::kNear);
+      __ call(isolate()->builtins()->StackCheck(), RelocInfo::CODE_TARGET);
+      __ bind(&ok);
     }
 
     { Comment cmnt(masm_, "[ Body");
index 155526f..1945bd6 100644 (file)
@@ -1076,7 +1076,8 @@ int RegExpMacroAssemblerIA32::CheckStackGuardState(Address* return_address,
                                                    Code* re_code,
                                                    Address re_frame) {
   Isolate* isolate = frame_entry<Isolate*>(re_frame, kIsolate);
-  if (isolate->stack_guard()->IsStackOverflow()) {
+  StackLimitCheck check(isolate);
+  if (check.JsHasOverflowed()) {
     isolate->StackOverflow();
     return EXCEPTION;
   }
index 5fd30eb..9ec3c9b 100644 (file)
@@ -2344,4 +2344,16 @@ void Isolate::RunMicrotasks() {
 }
 
 
+bool StackLimitCheck::JsHasOverflowed() const {
+  StackGuard* stack_guard = isolate_->stack_guard();
+#ifdef USE_SIMULATOR
+  // The simulator uses a separate JS stack.
+  Address jssp_address = Simulator::current(isolate_)->get_sp();
+  uintptr_t jssp = reinterpret_cast<uintptr_t>(jssp_address);
+  if (jssp < stack_guard->real_jslimit()) return true;
+#endif  // USE_SIMULATOR
+  return reinterpret_cast<uintptr_t>(this) < stack_guard->real_climit();
+}
+
+
 } }  // namespace v8::internal
index 439f2ce..7de7303 100644 (file)
@@ -1390,15 +1390,20 @@ class ExecutionAccess BASE_EMBEDDED {
 };
 
 
-// Support for checking for stack-overflows in C++ code.
+// Support for checking for stack-overflows.
 class StackLimitCheck BASE_EMBEDDED {
  public:
   explicit StackLimitCheck(Isolate* isolate) : isolate_(isolate) { }
 
-  bool HasOverflowed() const {
+  // Use this to check for stack-overflows in C++ code.
+  inline bool HasOverflowed() const {
     StackGuard* stack_guard = isolate_->stack_guard();
-    return (reinterpret_cast<uintptr_t>(this) < stack_guard->real_climit());
+    return reinterpret_cast<uintptr_t>(this) < stack_guard->real_climit();
   }
+
+  // Use this to check for stack-overflow when entering runtime from JS code.
+  bool JsHasOverflowed() const;
+
  private:
   Isolate* isolate_;
 };
index 9273862..bc2e445 100644 (file)
@@ -9524,7 +9524,8 @@ RUNTIME_FUNCTION(RuntimeHidden_StackGuard) {
   ASSERT(args.length() == 0);
 
   // First check if this is a real stack overflow.
-  if (isolate->stack_guard()->IsStackOverflow()) {
+  StackLimitCheck check(isolate);
+  if (check.JsHasOverflowed()) {
     return isolate->StackOverflow();
   }
 
@@ -9538,7 +9539,8 @@ RUNTIME_FUNCTION(RuntimeHidden_TryInstallOptimizedCode) {
   CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
 
   // First check if this is a real stack overflow.
-  if (isolate->stack_guard()->IsStackOverflow()) {
+  StackLimitCheck check(isolate);
+  if (check.JsHasOverflowed()) {
     SealHandleScope shs(isolate);
     return isolate->StackOverflow();
   }
index 1816abe..fa1eee6 100644 (file)
@@ -78,27 +78,6 @@ class JumpPatchSite BASE_EMBEDDED {
 };
 
 
-static void EmitStackCheck(MacroAssembler* masm_,
-                             int pointers = 0,
-                             Register scratch = rsp) {
-    Isolate* isolate = masm_->isolate();
-    Label ok;
-    ASSERT(scratch.is(rsp) == (pointers == 0));
-    Heap::RootListIndex index;
-    if (pointers != 0) {
-      __ movp(scratch, rsp);
-      __ subp(scratch, Immediate(pointers * kPointerSize));
-      index = Heap::kRealStackLimitRootIndex;
-    } else {
-      index = Heap::kStackLimitRootIndex;
-    }
-    __ CompareRoot(scratch, index);
-    __ j(above_equal, &ok, Label::kNear);
-    __ call(isolate->builtins()->StackCheck(), RelocInfo::CODE_TARGET);
-    __ bind(&ok);
-}
-
-
 // Generate code for a JS function.  On entry to the function the receiver
 // and arguments have been pushed on the stack left to right, with the
 // return address on top of them.  The actual argument count matches the
@@ -168,7 +147,13 @@ void FullCodeGenerator::Generate() {
       __ PushRoot(Heap::kUndefinedValueRootIndex);
     } else if (locals_count > 1) {
       if (locals_count >= 128) {
-        EmitStackCheck(masm_, locals_count, rcx);
+        Label ok;
+        __ movp(rcx, rsp);
+        __ subp(rcx, Immediate(locals_count * kPointerSize));
+        __ CompareRoot(rcx, Heap::kRealStackLimitRootIndex);
+        __ j(above_equal, &ok, Label::kNear);
+        __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION);
+        __ bind(&ok);
       }
       __ LoadRoot(rdx, Heap::kUndefinedValueRootIndex);
       const int kMaxPushes = 32;
@@ -309,7 +294,11 @@ void FullCodeGenerator::Generate() {
 
     { Comment cmnt(masm_, "[ Stack check");
       PrepareForBailoutForId(BailoutId::Declarations(), NO_REGISTERS);
-      EmitStackCheck(masm_);
+       Label ok;
+       __ CompareRoot(rsp, Heap::kStackLimitRootIndex);
+       __ j(above_equal, &ok, Label::kNear);
+       __ call(isolate()->builtins()->StackCheck(), RelocInfo::CODE_TARGET);
+       __ bind(&ok);
     }
 
     { Comment cmnt(masm_, "[ Body");
index b24d842..a8c1cb4 100644 (file)
@@ -1183,7 +1183,8 @@ int RegExpMacroAssemblerX64::CheckStackGuardState(Address* return_address,
                                                   Code* re_code,
                                                   Address re_frame) {
   Isolate* isolate = frame_entry<Isolate*>(re_frame, kIsolate);
-  if (isolate->stack_guard()->IsStackOverflow()) {
+  StackLimitCheck check(isolate);
+  if (check.JsHasOverflowed()) {
     isolate->StackOverflow();
     return EXCEPTION;
   }
diff --git a/test/mjsunit/regress/regress-crbug-385002.js b/test/mjsunit/regress/regress-crbug-385002.js
new file mode 100644 (file)
index 0000000..34713e2
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2014 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.
+
+// Flags: --stack-size=200 --allow-natives-syntax
+
+%Break(); // Schedule an interrupt that does not go away.
+
+function f() { f(); }
+assertThrows(f, RangeError);
+
+var locals = "";
+for (var i = 0; i < 1024; i++) locals += "var v" + i + ";";
+eval("function g() {" + locals + "f();}");
+assertThrows("g()", RangeError);