};
-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
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;
{ 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");
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;
}
};
-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
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) {
{ 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");
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;
}
}
-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)) {
// it has been set up.
void ClearThread(const ExecutionAccess& lock);
- bool IsStackOverflow();
-
#define INTERRUPT_LIST(V) \
V(DEBUGBREAK, DebugBreak) \
V(DEBUGCOMMAND, DebugCommand) \
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_;
};
-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
__ 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;
{ 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");
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;
}
}
+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
};
-// 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_;
};
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();
}
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();
}
};
-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
__ 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;
{ 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");
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;
}
--- /dev/null
+// 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);