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

Reply via email to