__ push(r0);
__ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_JS);
- Label no_preemption, retry_preemption;
- __ bind(&retry_preemption);
- ExternalReference stack_guard_limit_address =
- ExternalReference::address_of_stack_guard_limit();
- __ mov(r2, Operand(stack_guard_limit_address));
- __ ldr(r2, MemOperand(r2));
- __ cmp(sp, r2);
- __ b(hi, &no_preemption);
-
- // We have encountered a preemption or stack overflow already before we push
- // the array contents. Save r0 which is the Smi-tagged length of the array.
- __ push(r0);
-
- // Runtime routines expect at least one argument, so give it a Smi.
- __ mov(r0, Operand(Smi::FromInt(0)));
- __ push(r0);
- __ CallRuntime(Runtime::kStackGuard, 1);
-
- // Since we returned, it wasn't a stack overflow. Restore r0 and try again.
- __ pop(r0);
- __ b(&retry_preemption);
-
- __ bind(&no_preemption);
-
- // Eagerly check for stack-overflow before starting to push the arguments.
- // r0: number of arguments.
- // r2: stack limit.
+ // Check the stack for overflow. We are not trying need to catch
+ // interruptions (e.g. debug break and preemption) here, so the "real stack
+ // limit" is checked.
Label okay;
+ __ LoadRoot(r2, Heap::kRealStackLimitRootIndex);
+ // Make r2 the space we have left. The stack might already be overflowed
+ // here which will cause r2 to become negative.
__ sub(r2, sp, r2);
-
+ // Check if the arguments will overflow the stack.
__ cmp(r2, Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize));
- __ b(hi, &okay);
+ __ b(gt, &okay); // Signed comparison.
// Out of stack space.
__ ldr(r1, MemOperand(fp, kFunctionOffset));
__ push(r1);
__ push(r0);
__ InvokeBuiltin(Builtins::APPLY_OVERFLOW, CALL_JS);
+ // End of stack check.
// Push current limit and index.
__ bind(&okay);
Label stack_limit_hit;
Label stack_ok;
- ExternalReference stack_guard_limit =
- ExternalReference::address_of_stack_guard_limit();
- __ mov(r0, Operand(stack_guard_limit));
+ ExternalReference stack_limit =
+ ExternalReference::address_of_stack_limit();
+ __ mov(r0, Operand(stack_limit));
__ ldr(r0, MemOperand(r0));
__ sub(r0, sp, r0, SetCC);
// Handle it if the stack pointer is already below the stack limit.
void RegExpMacroAssemblerARM::CheckPreemption() {
// Check for preemption.
- ExternalReference stack_guard_limit =
- ExternalReference::address_of_stack_guard_limit();
- __ mov(r0, Operand(stack_guard_limit));
+ ExternalReference stack_limit =
+ ExternalReference::address_of_stack_limit();
+ __ mov(r0, Operand(stack_limit));
__ ldr(r0, MemOperand(r0));
__ cmp(sp, r0);
SafeCall(&check_preempt_label_, ls);
}
-ExternalReference ExternalReference::address_of_stack_guard_limit() {
+ExternalReference ExternalReference::address_of_stack_limit() {
return ExternalReference(StackGuard::address_of_jslimit());
}
+ExternalReference ExternalReference::address_of_real_stack_limit() {
+ return ExternalReference(StackGuard::address_of_real_jslimit());
+}
+
+
ExternalReference ExternalReference::address_of_regexp_stack_limit() {
return ExternalReference(RegExpStack::limit_address());
}
static ExternalReference roots_address();
// Static variable StackGuard::address_of_jslimit()
- static ExternalReference address_of_stack_guard_limit();
+ static ExternalReference address_of_stack_limit();
+
+ // Static variable StackGuard::address_of_real_jslimit()
+ static ExternalReference address_of_real_stack_limit();
// Static variable RegExpStack::limit_address()
static ExternalReference address_of_regexp_stack_limit();
// If the current limits are special (eg due to a pending interrupt) then
// leave them alone.
uintptr_t jslimit = SimulatorStack::JsLimitFromCLimit(limit);
- if (thread_local_.jslimit_ == thread_local_.initial_jslimit_) {
+ if (thread_local_.jslimit_ == thread_local_.real_jslimit_) {
thread_local_.jslimit_ = jslimit;
- Heap::SetStackLimit(jslimit);
}
- if (thread_local_.climit_ == thread_local_.initial_climit_) {
+ if (thread_local_.climit_ == thread_local_.real_climit_) {
thread_local_.climit_ = limit;
}
- thread_local_.initial_climit_ = limit;
- thread_local_.initial_jslimit_ = jslimit;
+ thread_local_.real_climit_ = limit;
+ thread_local_.real_jslimit_ = jslimit;
}
char* StackGuard::RestoreStackGuard(char* from) {
ExecutionAccess access;
memcpy(reinterpret_cast<char*>(&thread_local_), from, sizeof(ThreadLocal));
- Heap::SetStackLimit(thread_local_.jslimit_);
+ Heap::SetStackLimits();
return from + sizeof(ThreadLocal);
}
void StackGuard::FreeThreadResources() {
Thread::SetThreadLocal(
stack_limit_key,
- reinterpret_cast<void*>(thread_local_.initial_climit_));
+ reinterpret_cast<void*>(thread_local_.real_climit_));
}
void StackGuard::ThreadLocal::Clear() {
- initial_jslimit_ = kIllegalLimit;
+ real_jslimit_ = kIllegalLimit;
jslimit_ = kIllegalLimit;
- initial_climit_ = kIllegalLimit;
+ real_climit_ = kIllegalLimit;
climit_ = kIllegalLimit;
nesting_ = 0;
postpone_interrupts_nesting_ = 0;
interrupt_flags_ = 0;
- Heap::SetStackLimit(kIllegalLimit);
+ Heap::SetStackLimits();
}
void StackGuard::ThreadLocal::Initialize() {
- if (initial_climit_ == kIllegalLimit) {
+ if (real_climit_ == kIllegalLimit) {
// Takes the address of the limit variable in order to find out where
// the top of stack is right now.
uintptr_t limit = reinterpret_cast<uintptr_t>(&limit) - kLimitSize;
ASSERT(reinterpret_cast<uintptr_t>(&limit) > kLimitSize);
- initial_jslimit_ = SimulatorStack::JsLimitFromCLimit(limit);
+ real_jslimit_ = SimulatorStack::JsLimitFromCLimit(limit);
jslimit_ = SimulatorStack::JsLimitFromCLimit(limit);
- initial_climit_ = limit;
+ real_climit_ = limit;
climit_ = limit;
- Heap::SetStackLimit(SimulatorStack::JsLimitFromCLimit(limit));
+ Heap::SetStackLimits();
}
nesting_ = 0;
postpone_interrupts_nesting_ = 0;
// is assumed to grow downwards.
static void SetStackLimit(uintptr_t limit);
- static Address address_of_jslimit() {
- return reinterpret_cast<Address>(&thread_local_.jslimit_);
- }
-
// Threading support.
static char* ArchiveStackGuard(char* to);
static char* RestoreStackGuard(char* from);
#endif
static void Continue(InterruptFlag after_what);
- // This provides an asynchronous read of the stack limit for the current
+ // This provides an asynchronous read of the stack limits for the current
// thread. There are no locks protecting this, but it is assumed that you
// have the global V8 lock if you are using multiple V8 threads.
static uintptr_t climit() {
return thread_local_.climit_;
}
-
static uintptr_t jslimit() {
return thread_local_.jslimit_;
}
+ static uintptr_t real_jslimit() {
+ return thread_local_.real_jslimit_;
+ }
+ static Address address_of_jslimit() {
+ return reinterpret_cast<Address>(&thread_local_.jslimit_);
+ }
+ static Address address_of_real_jslimit() {
+ return reinterpret_cast<Address>(&thread_local_.real_jslimit_);
+ }
private:
// You should hold the ExecutionAccess lock when calling this method.
// You should hold the ExecutionAccess lock when calling this method.
static void set_limits(uintptr_t value, const ExecutionAccess& lock) {
- Heap::SetStackLimit(value);
thread_local_.jslimit_ = value;
thread_local_.climit_ = value;
+ Heap::SetStackLimits();
}
- // Reset limits to initial values. For example after handling interrupt.
+ // Reset limits to actual values. For example after handling interrupt.
// You should hold the ExecutionAccess lock when calling this method.
static void reset_limits(const ExecutionAccess& lock) {
- thread_local_.jslimit_ = thread_local_.initial_jslimit_;
- Heap::SetStackLimit(thread_local_.jslimit_);
- thread_local_.climit_ = thread_local_.initial_climit_;
+ thread_local_.jslimit_ = thread_local_.real_jslimit_;
+ thread_local_.climit_ = thread_local_.real_climit_;
+ Heap::SetStackLimits();
}
// Enable or disable interrupts.
// Clear.
void Initialize();
void Clear();
- uintptr_t initial_jslimit_;
+
+ // The stack limit is split into a JavaScript and a C++ stack limit. These
+ // two are the same except when running on a simulator where the C++ and
+ // JavaScript stacks are separate. Each of the two stack limits have two
+ // values. The one eith the real_ prefix is the actual stack limit
+ // set for the VM. The one without the real_ prefix has the same value as
+ // the actual stack limit except when there is an interruption (e.g. debug
+ // break or preemption) in which case it is lowered to make stack checks
+ // fail. Both the generated code and the runtime system check against the
+ // one without the real_ prefix.
+ uintptr_t real_jslimit_; // Actual JavaScript stack limit set for the VM.
uintptr_t jslimit_;
- uintptr_t initial_climit_;
+ uintptr_t real_climit_; // Actual C++ stack limit set for the VM.
uintptr_t climit_;
+
int nesting_;
int postpone_interrupts_nesting_;
int interrupt_flags_;
}
-void Heap::SetStackLimit(intptr_t limit) {
+void Heap::SetStackLimits() {
// On 64 bit machines, pointers are generally out of range of Smis. We write
// something that looks like an out of range Smi to the GC.
- // Set up the special root array entry containing the stack guard.
- // This is actually an address, but the tag makes the GC ignore it.
+ // Set up the special root array entries containing the stack limits.
+ // These are actually addresses, but the tag makes the GC ignore it.
roots_[kStackLimitRootIndex] =
- reinterpret_cast<Object*>((limit & ~kSmiTagMask) | kSmiTag);
+ reinterpret_cast<Object*>(
+ (StackGuard::jslimit() & ~kSmiTagMask) | kSmiTag);
+ roots_[kRealStackLimitRootIndex] =
+ reinterpret_cast<Object*>(
+ (StackGuard::real_jslimit() & ~kSmiTagMask) | kSmiTag);
}
V(FixedArray, single_character_string_cache, SingleCharacterStringCache) \
V(FixedArray, natives_source_cache, NativesSourceCache) \
V(Object, last_script_id, LastScriptId) \
+ V(Smi, real_stack_limit, RealStackLimit) \
#if V8_TARGET_ARCH_ARM && V8_NATIVE_REGEXP
#define STRONG_ROOT_LIST(V) \
// Destroys all memory allocated by the heap.
static void TearDown();
- // Sets the stack limit in the roots_ array. Some architectures generate code
- // that looks here, because it is faster than loading from the static jslimit_
- // variable.
- static void SetStackLimit(intptr_t limit);
+ // Set the stack limit in the roots_ array. Some architectures generate
+ // code that looks here, because it is faster than loading from the static
+ // jslimit_/real_jslimit_ variable in the StackGuard.
+ static void SetStackLimits();
// Returns whether Setup has been called.
static bool HasBeenSetup();
__ push(Operand(ebp, 2 * kPointerSize)); // push arguments
__ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION);
- // Check the stack for overflow or a break request.
- // We need to catch preemptions right here, otherwise an unlucky preemption
- // could show up as a failed apply.
- ExternalReference stack_guard_limit =
- ExternalReference::address_of_stack_guard_limit();
- Label retry_preemption;
- Label no_preemption;
- __ bind(&retry_preemption);
- __ mov(edi, Operand::StaticVariable(stack_guard_limit));
- __ cmp(esp, Operand(edi));
- __ j(above, &no_preemption, taken);
-
- // Preemption!
- // Because builtins always remove the receiver from the stack, we
- // have to fake one to avoid underflowing the stack.
- __ push(eax);
- __ push(Immediate(Smi::FromInt(0)));
-
- // Do call to runtime routine.
- __ CallRuntime(Runtime::kStackGuard, 1);
- __ pop(eax);
- __ jmp(&retry_preemption);
-
- __ bind(&no_preemption);
-
+ // Check the stack for overflow. We are not trying need to catch
+ // interruptions (e.g. debug break and preemption) here, so the "real stack
+ // limit" is checked.
Label okay;
- // Make ecx the space we have left.
+ ExternalReference real_stack_limit =
+ ExternalReference::address_of_real_stack_limit();
+ __ mov(edi, 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, Operand(esp));
__ sub(ecx, Operand(edi));
// Make edx the space we need for the array when it is unrolled onto the
// stack.
__ mov(edx, Operand(eax));
__ shl(edx, kPointerSizeLog2 - kSmiTagSize);
+ // Check if the arguments will overflow the stack.
__ cmp(ecx, Operand(edx));
- __ j(greater, &okay, taken);
+ __ j(greater, &okay, taken); // Signed comparison.
- // Too bad: Out of stack space.
+ // Out of stack space.
__ push(Operand(ebp, 4 * kPointerSize)); // push this
__ push(eax);
__ InvokeBuiltin(Builtins::APPLY_OVERFLOW, CALL_FUNCTION);
void CodeGenerator::CheckStack() {
DeferredStackCheck* deferred = new DeferredStackCheck;
- ExternalReference stack_guard_limit =
- ExternalReference::address_of_stack_guard_limit();
- __ cmp(esp, Operand::StaticVariable(stack_guard_limit));
+ ExternalReference stack_limit =
+ ExternalReference::address_of_stack_limit();
+ __ cmp(esp, Operand::StaticVariable(stack_limit));
deferred->Branch(below);
deferred->BindExit();
}
{ Comment cmnt(masm_, "[ Stack check");
Label ok;
- ExternalReference stack_guard_limit =
- ExternalReference::address_of_stack_guard_limit();
- __ cmp(esp, Operand::StaticVariable(stack_guard_limit));
+ ExternalReference stack_limit =
+ ExternalReference::address_of_stack_limit();
+ __ cmp(esp, Operand::StaticVariable(stack_limit));
__ j(above_equal, &ok, taken);
StackCheckStub stub;
__ CallStub(&stub);
Label stack_limit_hit;
Label stack_ok;
- ExternalReference stack_guard_limit =
- ExternalReference::address_of_stack_guard_limit();
+ ExternalReference stack_limit =
+ ExternalReference::address_of_stack_limit();
__ mov(ecx, esp);
- __ sub(ecx, Operand::StaticVariable(stack_guard_limit));
+ __ sub(ecx, Operand::StaticVariable(stack_limit));
// Handle it if the stack pointer is already below the stack limit.
__ j(below_equal, &stack_limit_hit, not_taken);
// Check if there is room for the variable number of registers above
void RegExpMacroAssemblerIA32::CheckPreemption() {
// Check for preemption.
Label no_preempt;
- ExternalReference stack_guard_limit =
- ExternalReference::address_of_stack_guard_limit();
- __ cmp(esp, Operand::StaticVariable(stack_guard_limit));
+ ExternalReference stack_limit =
+ ExternalReference::address_of_stack_limit();
+ __ cmp(esp, Operand::StaticVariable(stack_limit));
__ j(above, &no_preempt, taken);
SafeCall(&check_preempt_label_);
UNCLASSIFIED,
3,
"Heap::roots_address()");
- Add(ExternalReference::address_of_stack_guard_limit().address(),
+ Add(ExternalReference::address_of_stack_limit().address(),
UNCLASSIFIED,
4,
"StackGuard::address_of_jslimit()");
- Add(ExternalReference::address_of_regexp_stack_limit().address(),
+ Add(ExternalReference::address_of_real_stack_limit().address(),
UNCLASSIFIED,
5,
+ "StackGuard::address_of_real_jslimit()");
+ Add(ExternalReference::address_of_regexp_stack_limit().address(),
+ UNCLASSIFIED,
+ 6,
"RegExpStack::limit_address()");
Add(ExternalReference::new_space_start().address(),
UNCLASSIFIED,
- 6,
+ 7,
"Heap::NewSpaceStart()");
Add(ExternalReference::heap_always_allocate_scope_depth().address(),
UNCLASSIFIED,
- 7,
+ 8,
"Heap::always_allocate_scope_depth()");
Add(ExternalReference::new_space_allocation_limit_address().address(),
UNCLASSIFIED,
- 8,
+ 9,
"Heap::NewSpaceAllocationLimitAddress()");
Add(ExternalReference::new_space_allocation_top_address().address(),
UNCLASSIFIED,
- 9,
+ 10,
"Heap::NewSpaceAllocationTopAddress()");
#ifdef ENABLE_DEBUGGER_SUPPORT
Add(ExternalReference::debug_break().address(),
UNCLASSIFIED,
- 10,
+ 11,
"Debug::Break()");
Add(ExternalReference::debug_step_in_fp_address().address(),
UNCLASSIFIED,
- 11,
+ 12,
"Debug::step_in_fp_addr()");
#endif
Add(ExternalReference::double_fp_operation(Token::ADD).address(),
UNCLASSIFIED,
- 12,
+ 13,
"add_two_doubles");
Add(ExternalReference::double_fp_operation(Token::SUB).address(),
UNCLASSIFIED,
- 13,
+ 14,
"sub_two_doubles");
Add(ExternalReference::double_fp_operation(Token::MUL).address(),
UNCLASSIFIED,
- 14,
+ 15,
"mul_two_doubles");
Add(ExternalReference::double_fp_operation(Token::DIV).address(),
UNCLASSIFIED,
- 15,
+ 16,
"div_two_doubles");
Add(ExternalReference::double_fp_operation(Token::MOD).address(),
UNCLASSIFIED,
- 16,
+ 17,
"mod_two_doubles");
Add(ExternalReference::compare_doubles().address(),
UNCLASSIFIED,
- 17,
+ 18,
"compare_doubles");
#ifdef V8_NATIVE_REGEXP
Add(ExternalReference::re_case_insensitive_compare_uc16().address(),
UNCLASSIFIED,
- 18,
+ 19,
"NativeRegExpMacroAssembler::CaseInsensitiveCompareUC16()");
Add(ExternalReference::re_check_stack_guard_state().address(),
UNCLASSIFIED,
- 19,
+ 20,
"RegExpMacroAssembler*::CheckStackGuardState()");
Add(ExternalReference::re_grow_stack().address(),
UNCLASSIFIED,
- 20,
+ 21,
"NativeRegExpMacroAssembler::GrowStack()");
#endif
}
// Deserializing may put strange things in the root array's copy of the
// stack guard.
- Heap::SetStackLimit(StackGuard::jslimit());
+ Heap::SetStackLimits();
// Setup the CPU support. Must be done after heap setup and after
// any deserialization because we have to have the initial heap
__ push(Operand(rbp, kArgumentsOffset));
__ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION);
- // Check the stack for overflow or a break request.
- // We need to catch preemptions right here, otherwise an unlucky preemption
- // could show up as a failed apply.
- Label retry_preemption;
- Label no_preemption;
- __ bind(&retry_preemption);
- ExternalReference stack_guard_limit =
- ExternalReference::address_of_stack_guard_limit();
- __ movq(kScratchRegister, stack_guard_limit);
- __ movq(rcx, rsp);
- __ subq(rcx, Operand(kScratchRegister, 0));
- // rcx contains the difference between the stack limit and the stack top.
- // We use it below to check that there is enough room for the arguments.
- __ j(above, &no_preemption);
-
- // Preemption!
- // Because runtime functions always remove the receiver from the stack, we
- // have to fake one to avoid underflowing the stack.
- __ push(rax);
- __ Push(Smi::FromInt(0));
-
- // Do call to runtime routine.
- __ CallRuntime(Runtime::kStackGuard, 1);
- __ pop(rax);
- __ jmp(&retry_preemption);
-
- __ bind(&no_preemption);
-
+ // Check the stack for overflow. We are not trying need to catch
+ // interruptions (e.g. debug break and preemption) here, so the "real stack
+ // limit" is checked.
Label okay;
+ __ LoadRoot(kScratchRegister, Heap::kRealStackLimitRootIndex);
+ __ movq(rcx, rsp);
+ // Make rcx the space we have left. The stack might already be overflowed
+ // here which will cause rcx to become negative.
+ __ subq(rcx, kScratchRegister);
// 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.
__ cmpq(rcx, rdx);
- __ j(greater, &okay);
+ __ j(greater, &okay); // Signed comparison.
- // Too bad: Out of stack space.
+ // Out of stack space.
__ push(Operand(rbp, kFunctionOffset));
__ push(rax);
__ InvokeBuiltin(Builtins::APPLY_OVERFLOW, CALL_FUNCTION);
Label stack_limit_hit;
Label stack_ok;
- ExternalReference stack_guard_limit =
- ExternalReference::address_of_stack_guard_limit();
+ ExternalReference stack_limit =
+ ExternalReference::address_of_stack_limit();
__ movq(rcx, rsp);
- __ movq(kScratchRegister, stack_guard_limit);
+ __ movq(kScratchRegister, stack_limit);
__ subq(rcx, Operand(kScratchRegister, 0));
// Handle it if the stack pointer is already below the stack limit.
__ j(below_equal, &stack_limit_hit);
void RegExpMacroAssemblerX64::CheckPreemption() {
// Check for preemption.
Label no_preempt;
- ExternalReference stack_guard_limit =
- ExternalReference::address_of_stack_guard_limit();
- __ load_rax(stack_guard_limit);
+ ExternalReference stack_limit =
+ ExternalReference::address_of_stack_limit();
+ __ load_rax(stack_limit);
__ cmpq(rsp, rax);
__ j(above, &no_preempt);
}
+// Debug event handler which re-issues a debug break until a limit has been
+// reached.
+int max_break_point_hit_count = 0;
+static void DebugEventBreakMax(v8::DebugEvent event,
+ v8::Handle<v8::Object> exec_state,
+ v8::Handle<v8::Object> event_data,
+ v8::Handle<v8::Value> data) {
+ // When hitting a debug event listener there must be a break set.
+ CHECK_NE(v8::internal::Debug::break_id(), 0);
+
+ if (event == v8::Break && break_point_hit_count < max_break_point_hit_count) {
+ // Count the number of breaks.
+ break_point_hit_count++;
+
+ // Set the break flag again to come back here as soon as possible.
+ v8::Debug::DebugBreak();
+ }
+}
+
+
// --- M e s s a g e C a l l b a c k
v8::Handle<v8::Value> result = run_test->Call(env->Global(), 1, &obj);
CHECK(result->IsTrue());
}
+
+
+// Test that the debug break flag works with function.apply.
+TEST(DebugBreakFunctionApply) {
+ v8::HandleScope scope;
+ DebugLocalContext env;
+
+ // Create a function for testing breaking in apply.
+ v8::Local<v8::Function> foo = CompileFunction(
+ &env,
+ "function baz(x) { }"
+ "function bar(x) { baz(); }"
+ "function foo(){ bar.apply(this, [1]); }",
+ "foo");
+
+ // Register a debug event listener which steps and counts.
+ v8::Debug::SetDebugEventListener(DebugEventBreakMax);
+
+ // Set the debug break flag before calling the code using function.apply.
+ v8::Debug::DebugBreak();
+
+ // Limit the number of debug breaks. This is a regression test for issue 493
+ // where this test would enter an infinite loop.
+ break_point_hit_count = 0;
+ max_break_point_hit_count = 10000; // 10000 => infinite loop.
+ foo->Call(env->Global(), 0, NULL);
+
+ // When keeping the debug break several break will happen.
+ CHECK_EQ(3, break_point_hit_count);
+
+ v8::Debug::SetDebugEventListener(NULL);
+ CheckDebuggerUnloaded();
+}
ExternalReference::the_hole_value_location();
CHECK_EQ(make_code(UNCLASSIFIED, 2),
encoder.Encode(the_hole_value_location.address()));
- ExternalReference stack_guard_limit_address =
- ExternalReference::address_of_stack_guard_limit();
+ ExternalReference stack_limit_address =
+ ExternalReference::address_of_stack_limit();
CHECK_EQ(make_code(UNCLASSIFIED, 4),
- encoder.Encode(stack_guard_limit_address.address()));
- CHECK_EQ(make_code(UNCLASSIFIED, 10),
+ encoder.Encode(stack_limit_address.address()));
+ ExternalReference real_stack_limit_address =
+ ExternalReference::address_of_real_stack_limit();
+ CHECK_EQ(make_code(UNCLASSIFIED, 5),
+ encoder.Encode(real_stack_limit_address.address()));
+ CHECK_EQ(make_code(UNCLASSIFIED, 11),
encoder.Encode(ExternalReference::debug_break().address()));
- CHECK_EQ(make_code(UNCLASSIFIED, 6),
+ CHECK_EQ(make_code(UNCLASSIFIED, 7),
encoder.Encode(ExternalReference::new_space_start().address()));
CHECK_EQ(make_code(UNCLASSIFIED, 3),
encoder.Encode(ExternalReference::roots_address().address()));
decoder.Decode(make_code(UNCLASSIFIED, 1)));
CHECK_EQ(ExternalReference::the_hole_value_location().address(),
decoder.Decode(make_code(UNCLASSIFIED, 2)));
- CHECK_EQ(ExternalReference::address_of_stack_guard_limit().address(),
+ CHECK_EQ(ExternalReference::address_of_stack_limit().address(),
decoder.Decode(make_code(UNCLASSIFIED, 4)));
+ CHECK_EQ(ExternalReference::address_of_real_stack_limit().address(),
+ decoder.Decode(make_code(UNCLASSIFIED, 5)));
CHECK_EQ(ExternalReference::debug_break().address(),
- decoder.Decode(make_code(UNCLASSIFIED, 10)));
+ decoder.Decode(make_code(UNCLASSIFIED, 11)));
CHECK_EQ(ExternalReference::new_space_start().address(),
- decoder.Decode(make_code(UNCLASSIFIED, 6)));
+ decoder.Decode(make_code(UNCLASSIFIED, 7)));
}