Revision: 4832
Author: lukezarko
Date: Wed Jun 9 13:52:42 2010
Log: [Isolates] Stack guards - static.
- Begin removing static state from stack guards.
- Split default isolate initialization into two phases:
* Allocate all previously static objects
* Call initialize methods on those static objects
This is necessary to preserve the old behavior of the API; without the
change some tests fail (where the failures cannot be solved by a call
to V8::Initialize).
Review URL: http://codereview.chromium.org/2715004
http://code.google.com/p/v8/source/detail?r=4832
Modified:
/branches/experimental/isolates/src/api.cc
/branches/experimental/isolates/src/arm/regexp-macro-assembler-arm.cc
/branches/experimental/isolates/src/assembler.cc
/branches/experimental/isolates/src/debug.cc
/branches/experimental/isolates/src/debug.h
/branches/experimental/isolates/src/execution.cc
/branches/experimental/isolates/src/execution.h
/branches/experimental/isolates/src/heap.cc
/branches/experimental/isolates/src/heap.h
/branches/experimental/isolates/src/ia32/regexp-macro-assembler-ia32.cc
/branches/experimental/isolates/src/isolate.cc
/branches/experimental/isolates/src/isolate.h
/branches/experimental/isolates/src/runtime.cc
/branches/experimental/isolates/src/top.cc
/branches/experimental/isolates/src/top.h
/branches/experimental/isolates/src/v8.cc
/branches/experimental/isolates/src/v8threads.cc
/branches/experimental/isolates/src/x64/regexp-macro-assembler-x64.cc
/branches/experimental/isolates/test/cctest/test-api.cc
/branches/experimental/isolates/test/cctest/test-debug.cc
/branches/experimental/isolates/test/cctest/test-regexp.cc
=======================================
--- /branches/experimental/isolates/src/api.cc Tue Jun 8 13:45:42 2010
+++ /branches/experimental/isolates/src/api.cc Wed Jun 9 13:52:42 2010
@@ -381,15 +381,18 @@
bool SetResourceConstraints(ResourceConstraints* constraints) {
+ i::Isolate* isolate = i::Isolate::Current();
+
int young_space_size = constraints->max_young_space_size();
int old_gen_size = constraints->max_old_space_size();
if (young_space_size != 0 || old_gen_size != 0) {
- bool result = i::Heap::ConfigureHeap(young_space_size / 2,
old_gen_size);
+ bool result = isolate->heap()->ConfigureHeap(young_space_size / 2,
+ old_gen_size);
if (!result) return false;
}
if (constraints->stack_limit() != NULL) {
uintptr_t limit =
reinterpret_cast<uintptr_t>(constraints->stack_limit());
- i::StackGuard::SetStackLimit(limit);
+ isolate->stack_guard()->SetStackLimit(limit);
}
return true;
}
@@ -3854,11 +3857,12 @@
void V8::TerminateExecution(int thread_id) {
if (!i::V8::IsRunning()) return;
API_ENTRY_CHECK("V8::GetCurrentThreadId()");
+ i::Isolate* isolate = i::Isolate::Current();
// If the thread_id identifies the current thread just terminate
// execution right away. Otherwise, ask the thread manager to
// terminate the thread with the given id if any.
if (thread_id == i::Top::thread_id()) {
- i::StackGuard::TerminateExecution();
+ isolate->stack_guard()->TerminateExecution();
} else {
i::ThreadManager::TerminateExecution(thread_id);
}
@@ -3867,7 +3871,7 @@
void V8::TerminateExecution() {
if (!i::V8::IsRunning()) return;
- i::StackGuard::TerminateExecution();
+ i::Isolate::Current()->stack_guard()->TerminateExecution();
}
@@ -4095,7 +4099,7 @@
void Debug::DebugBreak() {
if (!i::V8::IsRunning()) return;
- i::StackGuard::DebugBreak();
+ i::Isolate::Current()->stack_guard()->DebugBreak();
}
=======================================
--- /branches/experimental/isolates/src/arm/regexp-macro-assembler-arm.cc
Mon May 17 08:41:35 2010
+++ /branches/experimental/isolates/src/arm/regexp-macro-assembler-arm.cc
Wed Jun 9 13:52:42 2010
@@ -995,7 +995,7 @@
int RegExpMacroAssemblerARM::CheckStackGuardState(Address* return_address,
Code* re_code,
Address re_frame) {
- if (StackGuard::IsStackOverflow()) {
+ if (Isolate::Current()->stack_guard()->IsStackOverflow()) {
Top::StackOverflow();
return EXCEPTION;
}
=======================================
--- /branches/experimental/isolates/src/assembler.cc Tue May 18 06:39:16
2010
+++ /branches/experimental/isolates/src/assembler.cc Wed Jun 9 13:52:42
2010
@@ -608,12 +608,14 @@
ExternalReference ExternalReference::address_of_stack_limit() {
- return ExternalReference(StackGuard::address_of_jslimit());
+ return ExternalReference(
+ Isolate::Current()->stack_guard()->address_of_jslimit());
}
ExternalReference ExternalReference::address_of_real_stack_limit() {
- return ExternalReference(StackGuard::address_of_real_jslimit());
+ return ExternalReference(
+ Isolate::Current()->stack_guard()->address_of_real_jslimit());
}
=======================================
--- /branches/experimental/isolates/src/debug.cc Wed Jun 2 00:51:31 2010
+++ /branches/experimental/isolates/src/debug.cc Wed Jun 9 13:52:42 2010
@@ -2211,7 +2211,7 @@
// added. It should be enough to clear the flag only once while we are
in the
// debugger.
ASSERT(Debug::InDebugger());
- StackGuard::Continue(DEBUGCOMMAND);
+ Isolate::Current()->stack_guard()->Continue(DEBUGCOMMAND);
// Notify the debugger that a debug event has occurred unless auto
continue is
// active in which case no event is send.
@@ -2453,7 +2453,7 @@
// Set the debug command break flag to have the command processed.
if (!Debug::InDebugger()) {
- StackGuard::DebugCommand();
+ Isolate::Current()->stack_guard()->DebugCommand();
}
MessageDispatchHelperThread* dispatch_thread;
=======================================
--- /branches/experimental/isolates/src/debug.h Thu May 20 10:15:46 2010
+++ /branches/experimental/isolates/src/debug.h Wed Jun 9 13:52:42 2010
@@ -780,6 +780,10 @@
}
~EnterDebugger() {
+ // TODO(isolates): Check to see if this is the same isolate as in the
+ // constructor.
+ Isolate* isolate = Isolate::Current();
+
// Restore to the previous break state.
Debug::SetBreak(break_frame_id_, break_id_);
@@ -792,9 +796,9 @@
if (!Top::has_pending_exception()) {
// Try to avoid any pending debug break breaking in the clear
mirror
// cache JavaScript code.
- if (StackGuard::IsDebugBreak()) {
+ if (isolate->stack_guard()->IsDebugBreak()) {
Debug::set_interrupts_pending(DEBUGBREAK);
- StackGuard::Continue(DEBUGBREAK);
+ isolate->stack_guard()->Continue(DEBUGBREAK);
}
Debug::ClearMirrorCache();
}
@@ -805,17 +809,17 @@
// This re-scheduling of preemption is to avoid starvation in some
// debugging scenarios.
Debug::clear_interrupt_pending(PREEMPT);
- StackGuard::Preempt();
+ isolate->stack_guard()->Preempt();
}
if (Debug::is_interrupt_pending(DEBUGBREAK)) {
Debug::clear_interrupt_pending(DEBUGBREAK);
- StackGuard::DebugBreak();
+ isolate->stack_guard()->DebugBreak();
}
// If there are commands in the queue when leaving the debugger
request
// that these commands are processed.
if (Debugger::HasCommands()) {
- StackGuard::DebugCommand();
+ isolate->stack_guard()->DebugCommand();
}
// If leaving the debugger with the debugger no longer active unload
it.
=======================================
--- /branches/experimental/isolates/src/execution.cc Tue Jun 1 03:51:42
2010
+++ /branches/experimental/isolates/src/execution.cc Wed Jun 9 13:52:42
2010
@@ -38,6 +38,31 @@
namespace v8 {
namespace internal {
+
+
+StackGuard::StackGuard()
+ : isolate_(NULL),
+ stack_limit_key_(Thread::CreateThreadLocalKey()) {
+ thread_local_.Clear();
+}
+
+
+void StackGuard::set_interrupt_limits(const ExecutionAccess& lock) {
+ ASSERT(isolate_ != NULL);
+ // Ignore attempts to interrupt when interrupts are postponed.
+ if (should_postpone_interrupts(lock)) return;
+ thread_local_.jslimit_ = kInterruptLimit;
+ thread_local_.climit_ = kInterruptLimit;
+ isolate_->heap()->SetStackLimits();
+}
+
+
+void StackGuard::reset_limits(const ExecutionAccess& lock) {
+ ASSERT(isolate_ != NULL);
+ thread_local_.jslimit_ = thread_local_.real_jslimit_;
+ thread_local_.climit_ = thread_local_.real_climit_;
+ isolate_->heap()->SetStackLimits();
+}
static Handle<Object> Invoke(bool construct,
@@ -203,10 +228,6 @@
return Factory::undefined_value();
}
-
-
-// Static state for stack guards.
-StackGuard::ThreadLocal StackGuard::thread_local_;
bool StackGuard::IsStackOverflow() {
@@ -321,17 +342,21 @@
reset_limits(access);
}
}
-
-
-int StackGuard::ArchiveSpacePerThread() {
- return sizeof(ThreadLocal);
-}
char* StackGuard::ArchiveStackGuard(char* to) {
ExecutionAccess access;
memcpy(to, reinterpret_cast<char*>(&thread_local_), sizeof(ThreadLocal));
ThreadLocal blank;
+ blank.Clear();
+
+ // Set the stack limits using the old thread_local_.
+ // TODO(isolates): This was the old semantics of constructing a
ThreadLocal
+ // (as the ctor called SetStackLimits, which looked at
the
+ // current thread_local_ from StackGuard)-- but is this
+ // really what was intended?
+ isolate_->heap()->SetStackLimits();
+
thread_local_ = blank;
return to + sizeof(ThreadLocal);
}
@@ -340,7 +365,7 @@
char* StackGuard::RestoreStackGuard(char* from) {
ExecutionAccess access;
memcpy(reinterpret_cast<char*>(&thread_local_), from,
sizeof(ThreadLocal));
- Heap::SetStackLimits();
+ isolate_->heap()->SetStackLimits();
return from + sizeof(ThreadLocal);
}
@@ -354,6 +379,10 @@
stack_limit_key,
reinterpret_cast<void*>(thread_local_.real_climit_));
}
+
+
+StackGuard::ThreadLocal::ThreadLocal() {
+}
void StackGuard::ThreadLocal::Clear() {
@@ -364,11 +393,11 @@
nesting_ = 0;
postpone_interrupts_nesting_ = 0;
interrupt_flags_ = 0;
- Heap::SetStackLimits();
}
-void StackGuard::ThreadLocal::Initialize() {
+bool StackGuard::ThreadLocal::Initialize() {
+ bool should_set_stack_limits = false;
if (real_climit_ == kIllegalLimit) {
// Takes the address of the limit variable in order to find out where
// the top of stack is right now.
@@ -378,21 +407,23 @@
jslimit_ = SimulatorStack::JsLimitFromCLimit(limit);
real_climit_ = limit;
climit_ = limit;
- Heap::SetStackLimits();
+ should_set_stack_limits = true;
}
nesting_ = 0;
postpone_interrupts_nesting_ = 0;
interrupt_flags_ = 0;
+ return should_set_stack_limits;
}
void StackGuard::ClearThread(const ExecutionAccess& lock) {
thread_local_.Clear();
+ isolate_->heap()->SetStackLimits();
}
void StackGuard::InitThread(const ExecutionAccess& lock) {
- thread_local_.Initialize();
+ if (thread_local_.Initialize()) { isolate_->heap()->SetStackLimits(); }
void* stored_limit = Thread::GetThreadLocal(stack_limit_key);
// You should hold the ExecutionAccess lock when you call this.
if (stored_limit != NULL) {
@@ -572,8 +603,10 @@
static Object* RuntimePreempt() {
+ Isolate* isolate = Isolate::Current();
+
// Clear the preempt request flag.
- StackGuard::Continue(PREEMPT);
+ isolate->stack_guard()->Continue(PREEMPT);
ContextSwitcher::PreemptionReceived();
@@ -593,20 +626,22 @@
Thread::YieldCPU();
#endif
- return HEAP->undefined_value();
+ return isolate->heap()->undefined_value();
}
#ifdef ENABLE_DEBUGGER_SUPPORT
Object* Execution::DebugBreakHelper() {
+ Isolate* isolate = Isolate::Current();
+
// Just continue if breaks are disabled.
if (Debug::disable_break()) {
- return HEAP->undefined_value();
+ return isolate->heap()->undefined_value();
}
// Ignore debug break during bootstrapping.
if (Bootstrapper::IsActive()) {
- return HEAP->undefined_value();
+ return isolate->heap()->undefined_value();
}
{
@@ -616,32 +651,33 @@
if (fun && fun->IsJSFunction()) {
// Don't stop in builtin functions.
if (JSFunction::cast(fun)->IsBuiltin()) {
- return HEAP->undefined_value();
+ return isolate->heap()->undefined_value();
}
GlobalObject* global = JSFunction::cast(fun)->context()->global();
// Don't stop in debugger functions.
if (Debug::IsDebugGlobal(global)) {
- return HEAP->undefined_value();
+ return isolate->heap()->undefined_value();
}
}
}
// Collect the break state before clearing the flags.
bool debug_command_only =
- StackGuard::IsDebugCommand() && !StackGuard::IsDebugBreak();
+ isolate->stack_guard()->IsDebugCommand() &&
+ !isolate->stack_guard()->IsDebugBreak();
// Clear the debug break request flag.
- StackGuard::Continue(DEBUGBREAK);
+ isolate->stack_guard()->Continue(DEBUGBREAK);
ProcessDebugMesssages(debug_command_only);
// Return to continue execution.
- return HEAP->undefined_value();
+ return isolate->heap()->undefined_value();
}
void Execution::ProcessDebugMesssages(bool debug_command_only) {
// Clear the debug command request flag.
- StackGuard::Continue(DEBUGCOMMAND);
+ Isolate::Current()->stack_guard()->Continue(DEBUGCOMMAND);
HandleScope scope;
// Enter the debugger. Just continue if we fail to enter the debugger.
@@ -659,22 +695,24 @@
#endif
Object* Execution::HandleStackGuardInterrupt() {
+ Isolate* isolate = Isolate::Current();
#ifdef ENABLE_DEBUGGER_SUPPORT
- if (StackGuard::IsDebugBreak() || StackGuard::IsDebugCommand()) {
+ if (isolate->stack_guard()->IsDebugBreak() ||
+ isolate->stack_guard()->IsDebugCommand()) {
DebugBreakHelper();
}
#endif
- if (StackGuard::IsPreempted()) RuntimePreempt();
- if (StackGuard::IsTerminateExecution()) {
- StackGuard::Continue(TERMINATE);
+ if (isolate->stack_guard()->IsPreempted()) RuntimePreempt();
+ if (isolate->stack_guard()->IsTerminateExecution()) {
+ isolate->stack_guard()->Continue(TERMINATE);
return Top::TerminateExecution();
}
- if (StackGuard::IsInterrupted()) {
+ if (isolate->stack_guard()->IsInterrupted()) {
// interrupt
- StackGuard::Continue(INTERRUPT);
+ isolate->stack_guard()->Continue(INTERRUPT);
return Top::StackOverflow();
}
- return HEAP->undefined_value();
+ return isolate->heap()->undefined_value();
}
// --- G C E x t e n s i o n ---
=======================================
--- /branches/experimental/isolates/src/execution.h Wed Apr 14 00:36:49 2010
+++ /branches/experimental/isolates/src/execution.h Wed Jun 9 13:52:42 2010
@@ -140,66 +140,72 @@
class ExecutionAccess;
+class Isolate;
// StackGuard contains the handling of the limits that are used to limit
the
// number of nested invocations of JavaScript and the stack size used in
each
// invocation.
-class StackGuard : public AllStatic {
+class StackGuard {
public:
// Pass the address beyond which the stack should not grow. The stack
// is assumed to grow downwards.
- static void SetStackLimit(uintptr_t limit);
+ void SetStackLimit(uintptr_t limit);
// Threading support.
- static char* ArchiveStackGuard(char* to);
- static char* RestoreStackGuard(char* from);
- static int ArchiveSpacePerThread();
- static void FreeThreadResources();
+ char* ArchiveStackGuard(char* to);
+ char* RestoreStackGuard(char* from);
+ static int ArchiveSpacePerThread() { return sizeof(ThreadLocal); }
+ void FreeThreadResources();
// Sets up the default stack guard for this thread if it has not
// already been set up.
- static void InitThread(const ExecutionAccess& lock);
+ void InitThread(const ExecutionAccess& lock);
// Clears the stack guard for this thread so it does not look as if
// it has been set up.
- static void ClearThread(const ExecutionAccess& lock);
-
- static bool IsStackOverflow();
- static bool IsPreempted();
- static void Preempt();
- static bool IsInterrupted();
- static void Interrupt();
- static bool IsTerminateExecution();
- static void TerminateExecution();
+ void ClearThread(const ExecutionAccess& lock);
+
+ bool IsStackOverflow();
+ bool IsPreempted();
+ void Preempt();
+ bool IsInterrupted();
+ void Interrupt();
+ bool IsTerminateExecution();
+ void TerminateExecution();
#ifdef ENABLE_DEBUGGER_SUPPORT
- static bool IsDebugBreak();
- static void DebugBreak();
- static bool IsDebugCommand();
- static void DebugCommand();
+ bool IsDebugBreak();
+ void DebugBreak();
+ bool IsDebugCommand();
+ void DebugCommand();
#endif
- static void Continue(InterruptFlag after_what);
+ void Continue(InterruptFlag after_what);
// 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() {
+ uintptr_t climit() {
return thread_local_.climit_;
}
- static uintptr_t jslimit() {
+ uintptr_t jslimit() {
return thread_local_.jslimit_;
}
- static uintptr_t real_jslimit() {
+ uintptr_t real_jslimit() {
return thread_local_.real_jslimit_;
}
- static Address address_of_jslimit() {
+ Address address_of_jslimit() {
return reinterpret_cast<Address>(&thread_local_.jslimit_);
}
- static Address address_of_real_jslimit() {
+ Address address_of_real_jslimit() {
return reinterpret_cast<Address>(&thread_local_.real_jslimit_);
}
private:
+ StackGuard();
+
+ Isolate* isolate_; // TODO(isolates): Technically this could be
calculated
+ // directly from a pointer to
StackGuard.
+
// You should hold the ExecutionAccess lock when calling this method.
- static bool has_pending_interrupts(const ExecutionAccess& lock) {
+ bool has_pending_interrupts(const ExecutionAccess& lock) {
// Sanity check: We shouldn't be asking about pending interrupts
// unless we're not postponing them anymore.
ASSERT(!should_postpone_interrupts(lock));
@@ -207,30 +213,20 @@
}
// You should hold the ExecutionAccess lock when calling this method.
- static bool should_postpone_interrupts(const ExecutionAccess& lock) {
+ bool should_postpone_interrupts(const ExecutionAccess& lock) {
return thread_local_.postpone_interrupts_nesting_ > 0;
}
// You should hold the ExecutionAccess lock when calling this method.
- static void set_interrupt_limits(const ExecutionAccess& lock) {
- // Ignore attempts to interrupt when interrupts are postponed.
- if (should_postpone_interrupts(lock)) return;
- thread_local_.jslimit_ = kInterruptLimit;
- thread_local_.climit_ = kInterruptLimit;
- Heap::SetStackLimits();
- }
+ inline void set_interrupt_limits(const ExecutionAccess& lock);
// 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_.real_jslimit_;
- thread_local_.climit_ = thread_local_.real_climit_;
- Heap::SetStackLimits();
- }
+ inline void reset_limits(const ExecutionAccess& lock);
// Enable or disable interrupts.
- static void EnableInterrupts();
- static void DisableInterrupts();
+ void EnableInterrupts();
+ void DisableInterrupts();
static const uintptr_t kLimitSize = kPointerSize * 128 * KB;
@@ -244,12 +240,14 @@
class ThreadLocal {
public:
- ThreadLocal() { Clear(); }
+ ThreadLocal();
// You should hold the ExecutionAccess lock when you call Initialize or
// Clear.
- void Initialize();
void Clear();
+ // Returns true if the heap's stack limits should be set, false if not.
+ bool Initialize();
+
// 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
@@ -269,43 +267,14 @@
int interrupt_flags_;
};
- static ThreadLocal thread_local_;
-
+ ThreadLocal thread_local_;
+ Thread::LocalStorageKey stack_limit_key_;
+
+ friend class Isolate;
friend class StackLimitCheck;
friend class PostponeInterruptsScope;
-};
-
-
-// Support for checking for stack-overflows in C++ code.
-class StackLimitCheck BASE_EMBEDDED {
- public:
- bool HasOverflowed() const {
- // Stack has overflowed in C++ code only if stack pointer exceeds the
C++
- // stack guard and the limits are not set to interrupt values.
- // TODO(214): Stack overflows are ignored if a interrupt is pending.
This
- // code should probably always use the initial C++ limit.
- return (reinterpret_cast<uintptr_t>(this) < StackGuard::climit()) &&
- StackGuard::IsStackOverflow();
- }
-};
-
-
-// Support for temporarily postponing interrupts. When the outermost
-// postpone scope is left the interrupts will be re-enabled and any
-// interrupts that occurred while in the scope will be taken into
-// account.
-class PostponeInterruptsScope BASE_EMBEDDED {
- public:
- PostponeInterruptsScope() {
- StackGuard::thread_local_.postpone_interrupts_nesting_++;
- StackGuard::DisableInterrupts();
- }
-
- ~PostponeInterruptsScope() {
- if (--StackGuard::thread_local_.postpone_interrupts_nesting_ == 0) {
- StackGuard::EnableInterrupts();
- }
- }
+
+ DISALLOW_COPY_AND_ASSIGN(StackGuard);
};
=======================================
--- /branches/experimental/isolates/src/heap.cc Tue Jun 8 13:45:42 2010
+++ /branches/experimental/isolates/src/heap.cc Wed Jun 9 13:52:42 2010
@@ -144,7 +144,7 @@
int GCTracer::max_alive_after_gc_ = 0;
int GCTracer::min_in_mutator_ = kMaxInt;
-Heap::Heap() {
+Heap::Heap() : isolate_(NULL) {
// TODO(zarko): members that previously relied on static initialization
// should be initialized here.
}
@@ -3944,6 +3944,8 @@
void Heap::SetStackLimits() {
+ ASSERT(isolate_ != NULL);
+ ASSERT(isolate_ == Isolate::Current());
// 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.
@@ -3951,10 +3953,10 @@
// These are actually addresses, but the tag makes the GC ignore it.
roots_[kStackLimitRootIndex] =
reinterpret_cast<Object*>(
- (StackGuard::jslimit() & ~kSmiTagMask) | kSmiTag);
+ (isolate_->stack_guard()->jslimit() & ~kSmiTagMask) | kSmiTag);
roots_[kRealStackLimitRootIndex] =
reinterpret_cast<Object*>(
- (StackGuard::real_jslimit() & ~kSmiTagMask) | kSmiTag);
+ (isolate_->stack_guard()->real_jslimit() & ~kSmiTagMask) |
kSmiTag);
}
=======================================
--- /branches/experimental/isolates/src/heap.h Thu Jun 3 09:00:45 2010
+++ /branches/experimental/isolates/src/heap.h Wed Jun 9 13:52:42 2010
@@ -202,6 +202,7 @@
// Forward declaration of the GCTracer class.
class GCTracer;
class HeapStats;
+class Isolate;
typedef String* (*ExternalStringTableUpdaterCallback)(Object** pointer);
@@ -232,7 +233,7 @@
// 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();
+ void SetStackLimits();
// Returns whether Setup has been called.
static bool HasBeenSetup();
@@ -1020,6 +1021,10 @@
private:
Heap();
+ // TODO(isolates): Technically this can be calculated directly from
+ // any pointer to Heap.
+ Isolate* isolate_;
+
static int reserved_semispace_size_;
static int max_semispace_size_;
static int initial_semispace_size_;
=======================================
--- /branches/experimental/isolates/src/ia32/regexp-macro-assembler-ia32.cc
Mon May 17 08:41:35 2010
+++ /branches/experimental/isolates/src/ia32/regexp-macro-assembler-ia32.cc
Wed Jun 9 13:52:42 2010
@@ -1034,7 +1034,8 @@
int RegExpMacroAssemblerIA32::CheckStackGuardState(Address* return_address,
Code* re_code,
Address re_frame) {
- if (StackGuard::IsStackOverflow()) {
+ Isolate* isolate = Isolate::Current();
+ if (isolate->stack_guard()->IsStackOverflow()) {
Top::StackOverflow();
return EXCEPTION;
}
=======================================
--- /branches/experimental/isolates/src/isolate.cc Tue Jun 8 13:45:42 2010
+++ /branches/experimental/isolates/src/isolate.cc Wed Jun 9 13:52:42 2010
@@ -46,15 +46,35 @@
int Isolate::number_of_isolates_ = 0;
+class IsolateInitializer {
+ public:
+ IsolateInitializer() {
+ Isolate::InitOnce();
+ }
+};
+
+
+static IsolateInitializer isolate_initializer;
+
+
void Isolate::InitOnce() {
+ ASSERT(global_isolate == NULL);
+ global_isolate = new Isolate();
+ ASSERT(global_isolate->PreInit());
}
Isolate* Isolate::Create(Deserializer* des) {
// While we're still building out support for isolates, only support
// one single global isolate.
- ASSERT(global_isolate == NULL);
- global_isolate = new Isolate();
+
+ if (global_isolate != NULL) {
+ // Allow for two-phase initialization.
+ ASSERT(global_isolate->state_ != INITIALIZED);
+ } else {
+ global_isolate = new Isolate();
+ }
+
if (global_isolate->Init(des)) {
++number_of_isolates_;
return global_isolate;
@@ -67,11 +87,16 @@
Isolate::Isolate()
- : initialized_(false),
+ : state_(UNINITIALIZED),
bootstrapper_(NULL),
+ break_access_(OS::CreateMutex()),
stub_cache_(NULL),
handle_scope_implementer_(NULL) {
+ heap_.isolate_ = this;
+ stack_guard_.isolate_ = this;
+
handle_scope_data_.Initialize();
+
#define ISOLATE_INIT_EXECUTE(type, name,
initial_value) \
name##_ = (initial_value);
ISOLATE_INIT_LIST(ISOLATE_INIT_EXECUTE)
@@ -90,7 +115,26 @@
delete bootstrapper_;
bootstrapper_ = NULL;
- if (initialized_) --number_of_isolates_;
+ if (state_ == INITIALIZED) --number_of_isolates_;
+}
+
+
+bool Isolate::PreInit() {
+ if (state_ != UNINITIALIZED) return true;
+ ASSERT(global_isolate == this);
+
+ // Safe after setting Heap::isolate_, initializing StackGuard and
+ // ensuring that Isolate::Current() == this.
+ heap()->SetStackLimits();
+
+#ifdef DEBUG
+ DisallowAllocationFailure disallow_allocation_failure;
+#endif
+ bootstrapper_ = new Bootstrapper();
+ handle_scope_implementer_ = new HandleScopeImplementer();
+ stub_cache_ = new StubCache();
+ state_ = PREINITIALIZED;
+ return true;
}
@@ -104,10 +148,7 @@
DisallowAllocationFailure disallow_allocation_failure;
#endif
- // Allocate per-isolate globals early.
- bootstrapper_ = new Bootstrapper();
- handle_scope_implementer_ = new HandleScopeImplementer();
- stub_cache_ = new StubCache();
+ if (state_ == UNINITIALIZED && !PreInit()) return false;
// Enable logging before setting up the heap
Logger::Setup();
@@ -127,7 +168,7 @@
// will ensure this too, but we don't have to use lockers if we are
only
// using one thread.
ExecutionAccess lock;
- StackGuard::InitThread(lock);
+ stack_guard_.InitThread(lock);
}
// Setup the object heap
@@ -159,7 +200,7 @@
// Deserializing may put strange things in the root array's copy of the
// stack guard.
- Heap::SetStackLimits();
+ heap_.SetStackLimits();
// Setup the CPU support. Must be done after heap setup and after
// any deserialization because we have to have the initial heap
@@ -176,8 +217,7 @@
LOG(LogCompiledFunctions());
}
- initialized_ = true;
-
+ state_ = INITIALIZED;
return true;
}
=======================================
--- /branches/experimental/isolates/src/isolate.h Tue Jun 8 13:45:42 2010
+++ /branches/experimental/isolates/src/isolate.h Wed Jun 9 13:52:42 2010
@@ -30,6 +30,7 @@
#include "apiutils.h"
#include "heap.h"
+#include "execution.h"
#include "zone.h"
namespace v8 {
@@ -64,9 +65,6 @@
// on failure.
static Isolate* Create(Deserializer* des);
- // Initialize process-wide state.
- static void InitOnce();
-
#define GLOBAL_ACCESSOR(type, name,
initialvalue) \
type name() const { return name##_;
} \
void set_##name(type value) { name##_ = value; }
@@ -77,9 +75,14 @@
type* name() { return &(name##_[0]); }
ISOLATE_INIT_ARRAY_LIST(GLOBAL_ARRAY_ACCESSOR)
#undef GLOBAL_ARRAY_ACCESSOR
+
+ // Debug.
+ // Mutex for serializing access to break control structures.
+ Mutex* break_access() { return break_access_; }
// Accessors.
Bootstrapper* bootstrapper() { return bootstrapper_; }
+ StackGuard* stack_guard() { return &stack_guard_; }
Heap* heap() { return &heap_; }
StubCache* stub_cache() { return stub_cache_; }
v8::ImplementationUtilities::HandleScopeData* handle_scope_data() {
@@ -103,12 +106,25 @@
// TODO(isolates): Access to this global counter should be serialized.
static int number_of_isolates_;
+ // Initialize process-wide state.
+ static void InitOnce();
+
+ bool PreInit();
+
bool Init(Deserializer* des);
- bool initialized_;
+ enum State {
+ UNINITIALIZED, // Some components may not have been allocated.
+ PREINITIALIZED, // Components have been allocated but not
initialized.
+ INITIALIZED // All components are fully initialized.
+ };
+
+ State state_;
Bootstrapper* bootstrapper_;
+ Mutex* break_access_;
Heap heap_;
+ StackGuard stack_guard_;
StubCache* stub_cache_;
v8::ImplementationUtilities::HandleScopeData handle_scope_data_;
HandleScopeImplementer* handle_scope_implementer_;
@@ -124,9 +140,48 @@
ISOLATE_INIT_ARRAY_LIST(GLOBAL_ARRAY_BACKING_STORE)
#undef GLOBAL_ARRAY_BACKING_STORE
+ friend class IsolateInitializer;
+
DISALLOW_COPY_AND_ASSIGN(Isolate);
};
+
+// Support for checking for stack-overflows in C++ code.
+class StackLimitCheck BASE_EMBEDDED {
+ public:
+ bool HasOverflowed() const {
+ StackGuard* stack_guard = Isolate::Current()->stack_guard();
+ // Stack has overflowed in C++ code only if stack pointer exceeds the
C++
+ // stack guard and the limits are not set to interrupt values.
+ // TODO(214): Stack overflows are ignored if a interrupt is pending.
This
+ // code should probably always use the initial C++ limit.
+ return (reinterpret_cast<uintptr_t>(this) < stack_guard->climit()) &&
+ stack_guard->IsStackOverflow();
+ }
+};
+
+
+// Support for temporarily postponing interrupts. When the outermost
+// postpone scope is left the interrupts will be re-enabled and any
+// interrupts that occurred while in the scope will be taken into
+// account.
+class PostponeInterruptsScope BASE_EMBEDDED {
+ public:
+ PostponeInterruptsScope() {
+ StackGuard* stack_guard = Isolate::Current()->stack_guard();
+ stack_guard->thread_local_.postpone_interrupts_nesting_++;
+ stack_guard->DisableInterrupts();
+ }
+
+ ~PostponeInterruptsScope() {
+ StackGuard* stack_guard = Isolate::Current()->stack_guard();
+ if (--stack_guard->thread_local_.postpone_interrupts_nesting_ == 0) {
+ stack_guard->EnableInterrupts();
+ }
+ }
+};
+
+
// Temporary macros for accessing fields off the global isolate. Define
these
// when reformatting code would become burdensome.
#define HEAP (v8::internal::Isolate::Current()->heap())
=======================================
--- /branches/experimental/isolates/src/runtime.cc Tue Jun 8 13:45:42 2010
+++ /branches/experimental/isolates/src/runtime.cc Wed Jun 9 13:52:42 2010
@@ -6999,9 +6999,9 @@
static Object* Runtime_StackGuard(Arguments args) {
ASSERT(args.length() == 1);
-
+ Isolate* isolate = Isolate::Current();
// First check if this is a real stack overflow.
- if (StackGuard::IsStackOverflow()) {
+ if (isolate->stack_guard()->IsStackOverflow()) {
return Runtime_StackOverflow(args);
}
@@ -7949,8 +7949,9 @@
static Object* Runtime_Break(Arguments args) {
ASSERT(args.length() == 0);
- StackGuard::DebugBreak();
- return HEAP->undefined_value();
+ Isolate* isolate = Isolate::Current();
+ isolate->stack_guard()->DebugBreak();
+ return isolate->heap()->undefined_value();
}
=======================================
--- /branches/experimental/isolates/src/top.cc Tue Jun 1 03:51:42 2010
+++ /branches/experimental/isolates/src/top.cc Wed Jun 9 13:52:42 2010
@@ -40,7 +40,6 @@
namespace internal {
ThreadLocalTop Top::thread_local_;
-Mutex* Top::break_access_ = OS::CreateMutex();
NoAllocationStringAllocator* preallocated_message_space = NULL;
@@ -1056,12 +1055,12 @@
ExecutionAccess::ExecutionAccess() {
- Top::break_access_->Lock();
+ Isolate::Current()->break_access()->Lock();
}
ExecutionAccess::~ExecutionAccess() {
- Top::break_access_->Unlock();
+ Isolate::Current()->break_access()->Unlock();
}
=======================================
--- /branches/experimental/isolates/src/top.h Tue Jun 1 03:51:42 2010
+++ /branches/experimental/isolates/src/top.h Wed Jun 9 13:52:42 2010
@@ -377,10 +377,6 @@
static void MarkCompactEpilogue(bool is_compacting,
ThreadLocalTop* archived_thread_data);
- // Debug.
- // Mutex for serializing access to break control structures.
- static Mutex* break_access_;
-
friend class SaveContext;
friend class AssertNoContextChange;
friend class ExecutionAccess;
=======================================
--- /branches/experimental/isolates/src/v8.cc Wed Jun 2 00:42:37 2010
+++ /branches/experimental/isolates/src/v8.cc Wed Jun 9 13:52:42 2010
@@ -53,7 +53,6 @@
has_fatal_error_ = false;
has_been_disposed_ = false;
- Isolate::InitOnce();
return (Isolate::Create(des) != NULL);
}
=======================================
--- /branches/experimental/isolates/src/v8threads.cc Tue Jun 8 13:45:42
2010
+++ /branches/experimental/isolates/src/v8threads.cc Wed Jun 9 13:52:42
2010
@@ -50,6 +50,7 @@
// Constructor for the Locker object. Once the Locker is constructed the
// current thread will be guaranteed to have the big V8 lock.
Locker::Locker() : has_lock_(false), top_level_(true) {
+ internal::Isolate* isolate = internal::Isolate::Current();
// Record that the Locker has been used at least once.
active_ = true;
// Get the big lock if necessary.
@@ -68,8 +69,8 @@
top_level_ = false;
} else {
internal::ExecutionAccess access;
- internal::StackGuard::ClearThread(access);
- internal::StackGuard::InitThread(access);
+ isolate->stack_guard()->ClearThread(access);
+ isolate->stack_guard()->InitThread(access);
}
}
ASSERT(internal::ThreadManager::IsLockedByCurrentThread());
@@ -125,6 +126,7 @@
bool ThreadManager::RestoreThread() {
+ Isolate* isolate = Isolate::Current();
// First check whether the current thread has been 'lazily archived', ie
// not archived at all. If that is the case we put the state storage we
// had prepared back in the free list, since we didn't need it after all.
@@ -152,10 +154,9 @@
reinterpret_cast<ThreadState*>(Thread::GetThreadLocal(thread_state_key));
if (state == NULL) {
// This is a new thread.
- StackGuard::InitThread(access);
+ isolate->stack_guard()->InitThread(access);
return false;
}
- Isolate* isolate = Isolate::Current();
char* from = state->data();
from = isolate->handle_scope_implementer()->RestoreThread(from);
from = Top::RestoreThread(from);
@@ -163,12 +164,12 @@
#ifdef ENABLE_DEBUGGER_SUPPORT
from = Debug::RestoreDebug(from);
#endif
- from = StackGuard::RestoreStackGuard(from);
+ from = isolate->stack_guard()->RestoreStackGuard(from);
from = RegExpStack::RestoreStack(from);
from = isolate->bootstrapper()->RestoreState(from);
Thread::SetThreadLocal(thread_state_key, NULL);
if (state->terminate_on_restore()) {
- StackGuard::TerminateExecution();
+ isolate->stack_guard()->TerminateExecution();
state->set_terminate_on_restore(false);
}
state->set_id(kInvalidId);
@@ -283,9 +284,9 @@
void ThreadManager::EagerlyArchiveThread() {
+ Isolate* isolate = Isolate::Current();
ThreadState* state = lazily_archived_thread_state_;
state->LinkInto(ThreadState::IN_USE_LIST);
- Isolate* isolate = Isolate::Current();
char* to = state->data();
// Ensure that data containing GC roots are archived first, and handle
them
// in ThreadManager::Iterate(ObjectVisitor*).
@@ -295,7 +296,7 @@
#ifdef ENABLE_DEBUGGER_SUPPORT
to = Debug::ArchiveDebug(to);
#endif
- to = StackGuard::ArchiveStackGuard(to);
+ to = isolate->stack_guard()->ArchiveStackGuard(to);
to = RegExpStack::ArchiveStack(to);
to = isolate->bootstrapper()->ArchiveState(to);
lazily_archived_thread_.Initialize(ThreadHandle::INVALID);
@@ -310,7 +311,7 @@
#ifdef ENABLE_DEBUGGER_SUPPORT
Debug::FreeThreadResources();
#endif
- StackGuard::FreeThreadResources();
+ isolate->stack_guard()->FreeThreadResources();
RegExpStack::FreeThreadResources();
isolate->bootstrapper()->FreeThreadResources();
}
@@ -447,7 +448,7 @@
void ContextSwitcher::Run() {
while (keep_going_) {
OS::Sleep(sleep_ms_);
- StackGuard::Preempt();
+ Isolate::Current()->stack_guard()->Preempt();
}
}
=======================================
--- /branches/experimental/isolates/src/x64/regexp-macro-assembler-x64.cc
Mon May 17 08:41:35 2010
+++ /branches/experimental/isolates/src/x64/regexp-macro-assembler-x64.cc
Wed Jun 9 13:52:42 2010
@@ -1134,7 +1134,7 @@
int RegExpMacroAssemblerX64::CheckStackGuardState(Address* return_address,
Code* re_code,
Address re_frame) {
- if (StackGuard::IsStackOverflow()) {
+ if (Isolate::Current()->stack_guard()->IsStackOverflow()) {
Top::StackOverflow();
return EXCEPTION;
}
=======================================
--- /branches/experimental/isolates/test/cctest/test-api.cc Tue Jun 1
03:51:42 2010
+++ /branches/experimental/isolates/test/cctest/test-api.cc Wed Jun 9
13:52:42 2010
@@ -9953,7 +9953,8 @@
static uint32_t* stack_limit;
static v8::Handle<Value> GetStackLimitCallback(const v8::Arguments& args) {
- stack_limit = reinterpret_cast<uint32_t*>(i::StackGuard::climit());
+ stack_limit = reinterpret_cast<uint32_t*>(
+ i::Isolate::Current()->stack_guard()->climit());
return v8::Undefined();
}
=======================================
--- /branches/experimental/isolates/test/cctest/test-debug.cc Wed Jun 2
00:51:31 2010
+++ /branches/experimental/isolates/test/cctest/test-debug.cc Wed Jun 9
13:52:42 2010
@@ -5904,6 +5904,7 @@
static void BreakMessageHandler(const v8::Debug::Message& message) {
+ i::Isolate* isolate = i::Isolate::Current();
if (message.IsEvent() && message.GetEvent() == v8::Break) {
// Count the number of breaks.
break_point_hit_count++;
@@ -5915,18 +5916,18 @@
} else if (message.IsEvent() && message.GetEvent() == v8::AfterCompile) {
v8::HandleScope scope;
- bool is_debug_break = i::StackGuard::IsDebugBreak();
+ bool is_debug_break = isolate->stack_guard()->IsDebugBreak();
// Force DebugBreak flag while serializer is working.
- i::StackGuard::DebugBreak();
+ isolate->stack_guard()->DebugBreak();
// Force serialization to trigger some internal JS execution.
v8::Handle<v8::String> json = message.GetJSON();
// Restore previous state.
if (is_debug_break) {
- i::StackGuard::DebugBreak();
+ isolate->stack_guard()->DebugBreak();
} else {
- i::StackGuard::Continue(i::DEBUGBREAK);
+ isolate->stack_guard()->Continue(i::DEBUGBREAK);
}
}
}
=======================================
--- /branches/experimental/isolates/test/cctest/test-regexp.cc Wed Jun 2
09:14:32 2010
+++ /branches/experimental/isolates/test/cctest/test-regexp.cc Wed Jun 9
13:52:42 2010
@@ -663,7 +663,7 @@
class ContextInitializer {
public:
ContextInitializer()
- : env_(), scope_(), zone_(DELETE_ON_EXIT), stack_guard_() {
+ : env_(), scope_(), zone_(DELETE_ON_EXIT) {
env_ = v8::Context::New();
env_->Enter();
}
@@ -675,7 +675,6 @@
v8::Persistent<v8::Context> env_;
v8::HandleScope scope_;
v8::internal::ZoneScope zone_;
- v8::internal::StackGuard stack_guard_;
};
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev