Revision: 5003
Author: [email protected]
Date: Thu Jul  1 14:55:46 2010
Log: [Isolates] RegExpStack and memory allocation limits

regexp-stack:
-> Split RegExpStackState from RegExpStack. RegExpStacks can be allocated
at will, while there is only one RegExpStackState per isolate.

platform-linux/platform-macos:
-> Protect lowest_ever_allocated and highest_ever_allocated with
a mutex (limit_mutex) that is initialized in OS::Setup.


Review URL: http://codereview.chromium.org/2807031
http://code.google.com/p/v8/source/detail?r=5003

Modified:
 /branches/experimental/isolates/src/assembler.cc
 /branches/experimental/isolates/src/isolate.cc
 /branches/experimental/isolates/src/isolate.h
 /branches/experimental/isolates/src/platform-linux.cc
 /branches/experimental/isolates/src/platform-macos.cc
 /branches/experimental/isolates/src/platform-win32.cc
 /branches/experimental/isolates/src/regexp-macro-assembler.cc
 /branches/experimental/isolates/src/regexp-stack.cc
 /branches/experimental/isolates/src/regexp-stack.h
 /branches/experimental/isolates/src/v8threads.cc
 /branches/experimental/isolates/test/cctest/test-alloc.cc
 /branches/experimental/isolates/test/cctest/test-assembler-x64.cc
 /branches/experimental/isolates/test/cctest/test-platform-linux.cc
 /branches/experimental/isolates/test/cctest/test-serialize.cc
 /branches/experimental/isolates/test/cctest/test-spaces.cc
 /branches/experimental/isolates/test/cctest/test-utils.cc

=======================================
--- /branches/experimental/isolates/src/assembler.cc Tue Jun 29 18:06:08 2010 +++ /branches/experimental/isolates/src/assembler.cc Thu Jul 1 14:55:46 2010
@@ -629,7 +629,8 @@


 ExternalReference ExternalReference::address_of_regexp_stack_limit() {
-  return ExternalReference(RegExpStack::limit_address());
+  return ExternalReference(
+      Isolate::Current()->regexp_stack()->limit_address());
 }


@@ -715,11 +716,13 @@
 }

ExternalReference ExternalReference::address_of_regexp_stack_memory_address() {
-  return ExternalReference(RegExpStack::memory_address());
+  return ExternalReference(
+      Isolate::Current()->regexp_stack()->memory_address());
 }

ExternalReference ExternalReference::address_of_regexp_stack_memory_size() {
-  return ExternalReference(RegExpStack::memory_size_address());
+  return ExternalReference(
+      Isolate::Current()->regexp_stack()->memory_size_address());
 }

 #endif  // V8_INTERPRETED_REGEXP
=======================================
--- /branches/experimental/isolates/src/isolate.cc      Thu Jul  1 11:02:03 2010
+++ /branches/experimental/isolates/src/isolate.cc      Thu Jul  1 14:55:46 2010
@@ -37,6 +37,7 @@
 #include "heap-profiler.h"
 #include "isolate.h"
 #include "log.h"
+#include "regexp-stack.h"
 #include "serialize.h"
 #include "scanner.h"
 #include "scopeinfo.h"
@@ -253,7 +254,9 @@
       context_switcher_(NULL),
       thread_manager_(NULL),
       ast_sentinels_(NULL),
+      inline_runtime_functions_table_(NULL),
       string_tracker_(NULL),
+      regexp_stack_(NULL),
       frame_element_constant_list_(0),
       result_constant_list_(0) {
   memset(isolate_addresses_, 0,
@@ -336,6 +339,9 @@
   delete scanner_character_classes_;
   scanner_character_classes_ = NULL;

+  delete regexp_stack_;
+  regexp_stack_ = NULL;
+
   delete inline_runtime_functions_table_;
   inline_runtime_functions_table_ = NULL;

@@ -448,6 +454,8 @@
   stub_cache_ = new StubCache();
   ast_sentinels_ = new AstSentinels();
   inline_runtime_functions_table_ = new InlineRuntimeFunctionsTable();
+  regexp_stack_ = new RegExpStack();
+  regexp_stack_->isolate_ = this;

 #ifdef ENABLE_DEBUGGER_SUPPORT
   debugger_ = new Debugger();
=======================================
--- /branches/experimental/isolates/src/isolate.h       Thu Jul  1 11:02:03 2010
+++ /branches/experimental/isolates/src/isolate.h       Thu Jul  1 14:55:46 2010
@@ -67,6 +67,7 @@
 class NoAllocationStringAllocator;
 class PreallocatedMemoryThread;
 class ProducerHeapProfile;
+class RegExpStack;
 class SaveContext;
 class StubCache;
 class StringInputBuffer;
@@ -662,6 +663,8 @@
       regexp_macro_assembler_canonicalize() {
     return &regexp_macro_assembler_canonicalize_;
   }
+
+  RegExpStack* regexp_stack() { return regexp_stack_; }

   unibrow::Mapping<unibrow::Ecma262Canonicalize>*
       interp_canonicalize_mapping() {
@@ -800,6 +803,7 @@
   StaticResource<StringInputBuffer> objects_string_input_buffer_;
   unibrow::Mapping<unibrow::Ecma262Canonicalize>
       regexp_macro_assembler_canonicalize_;
+  RegExpStack* regexp_stack_;
unibrow::Mapping<unibrow::Ecma262Canonicalize> interp_canonicalize_mapping_;
   ZoneObjectList frame_element_constant_list_;
   ZoneObjectList result_constant_list_;
=======================================
--- /branches/experimental/isolates/src/platform-linux.cc Thu Jun 24 09:41:05 2010 +++ /branches/experimental/isolates/src/platform-linux.cc Thu Jul 1 14:55:46 2010
@@ -70,6 +70,9 @@
 double ceiling(double x) {
   return ceil(x);
 }
+
+
+static Mutex* limit_mutex = NULL;


 void OS::Setup() {
@@ -80,6 +83,7 @@
   // call this setup code within the same millisecond.
   uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
   srandom(static_cast<unsigned int>(seed));
+  limit_mutex = CreateMutex();
 }


@@ -215,6 +219,9 @@


 static void UpdateAllocatedSpaceLimits(void* address, int size) {
+  ASSERT(limit_mutex != NULL);
+  ScopedLock lock(limit_mutex);
+
   lowest_ever_allocated = Min(lowest_ever_allocated, address);
   highest_ever_allocated =
       Max(highest_ever_allocated,
=======================================
--- /branches/experimental/isolates/src/platform-macos.cc Fri May 21 22:27:19 2010 +++ /branches/experimental/isolates/src/platform-macos.cc Thu Jul 1 14:55:46 2010
@@ -85,6 +85,9 @@
     return ceil(x);
   }
 }
+
+
+static Mutex* limit_mutex = NULL;


 void OS::Setup() {
@@ -95,6 +98,7 @@
   // call this setup code within the same millisecond.
   uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
   srandom(static_cast<unsigned int>(seed));
+  limit_mutex = CreateMutex();
 }


@@ -108,6 +112,9 @@


 static void UpdateAllocatedSpaceLimits(void* address, int size) {
+  ASSERT(limit_mutex != NULL);
+  ScopedLock lock(limit_mutex);
+
   lowest_ever_allocated = Min(lowest_ever_allocated, address);
   highest_ever_allocated =
       Max(highest_ever_allocated,
=======================================
--- /branches/experimental/isolates/src/platform-win32.cc Fri May 21 22:27:19 2010 +++ /branches/experimental/isolates/src/platform-win32.cc Thu Jul 1 14:55:46 2010
@@ -222,6 +222,10 @@
 double ceiling(double x) {
   return ceil(x);
 }
+
+
+static Mutex* limit_mutex = NULL;
+

 #ifdef _WIN64
 typedef double (*ModuloFunction)(double, double);
@@ -590,6 +594,7 @@
   // call this setup code within the same millisecond.
   uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
   srand(static_cast<unsigned int>(seed));
+  limit_mutex = CreateMutex();
 }


@@ -791,6 +796,9 @@


 static void UpdateAllocatedSpaceLimits(void* address, int size) {
+  ASSERT(limit_mutex != NULL);
+  ScopedLock lock(limit_mutex);
+
   lowest_ever_allocated = Min(lowest_ever_allocated, address);
   highest_ever_allocated =
       Max(highest_ever_allocated,
=======================================
--- /branches/experimental/isolates/src/regexp-macro-assembler.cc Tue Jun 29 11:05:31 2010 +++ /branches/experimental/isolates/src/regexp-macro-assembler.cc Thu Jul 1 14:55:46 2010
@@ -156,13 +156,14 @@
     const byte* input_start,
     const byte* input_end,
     int* output) {
+  Isolate* isolate = Isolate::Current();
   typedef int (*matcher)(String*, int, const byte*,
                          const byte*, int*, Address, int);
   matcher matcher_func = FUNCTION_CAST<matcher>(code->entry());

   // Ensure that the minimum stack has been allocated.
-  RegExpStack stack;
-  Address stack_base = RegExpStack::stack_base();
+  RegExpStackScope stack_scope(isolate);
+  Address stack_base = stack_scope.stack()->stack_base();

   int direct_call = 0;
   int result = CALL_GENERATED_REGEXP_CODE(matcher_func,
@@ -176,10 +177,10 @@
   ASSERT(result <= SUCCESS);
   ASSERT(result >= RETRY);

- if (result == EXCEPTION && !Isolate::Current()->has_pending_exception()) {
+  if (result == EXCEPTION && !isolate->has_pending_exception()) {
// We detected a stack overflow (on the backtrack stack) in RegExp code,
     // but haven't created the exception yet.
-    Isolate::Current()->StackOverflow();
+    isolate->StackOverflow();
   }
   return static_cast<Result>(result);
 }
@@ -243,12 +244,13 @@

 Address NativeRegExpMacroAssembler::GrowStack(Address stack_pointer,
                                               Address* stack_base) {
-  size_t size = RegExpStack::stack_capacity();
-  Address old_stack_base = RegExpStack::stack_base();
+  RegExpStack* regexp_stack = Isolate::Current()->regexp_stack();
+  size_t size = regexp_stack->stack_capacity();
+  Address old_stack_base = regexp_stack->stack_base();
   ASSERT(old_stack_base == *stack_base);
   ASSERT(stack_pointer <= old_stack_base);
   ASSERT(static_cast<size_t>(old_stack_base - stack_pointer) <= size);
-  Address new_stack_base = RegExpStack::EnsureCapacity(size * 2);
+  Address new_stack_base = regexp_stack->EnsureCapacity(size * 2);
   if (new_stack_base == NULL) {
     return NULL;
   }
=======================================
--- /branches/experimental/isolates/src/regexp-stack.cc Mon Jun 21 10:40:11 2010 +++ /branches/experimental/isolates/src/regexp-stack.cc Thu Jul 1 14:55:46 2010
@@ -31,15 +31,26 @@
 namespace v8 {
 namespace internal {

-RegExpStack::RegExpStack() {
+RegExpStackScope::RegExpStackScope(Isolate* isolate)
+    : regexp_stack_(isolate->regexp_stack()) {
   // Initialize, if not already initialized.
-  RegExpStack::EnsureCapacity(0);
+  regexp_stack_->EnsureCapacity(0);
 }


-RegExpStack::~RegExpStack() {
+RegExpStackScope::~RegExpStackScope() {
+  ASSERT(Isolate::Current() == regexp_stack_->isolate_);
   // Reset the buffer if it has grown.
-  RegExpStack::Reset();
+  regexp_stack_->Reset();
+}
+
+
+RegExpStack::RegExpStack()
+    : isolate_(NULL) {
+}
+
+
+RegExpStack::~RegExpStack() {
 }


@@ -69,9 +80,9 @@


 void RegExpStack::ThreadLocal::Free() {
-  if (thread_local_.memory_size_ > 0) {
-    DeleteArray(thread_local_.memory_);
-    thread_local_ = ThreadLocal();
+  if (memory_size_ > 0) {
+    DeleteArray(memory_);
+    Clear();
   }
 }

@@ -97,6 +108,4 @@
 }


-RegExpStack::ThreadLocal RegExpStack::thread_local_;
-
 }}  // namespace v8::internal
=======================================
--- /branches/experimental/isolates/src/regexp-stack.h Wed Jan 6 03:09:30 2010 +++ /branches/experimental/isolates/src/regexp-stack.h Thu Jul 1 14:55:46 2010
@@ -31,11 +31,30 @@
 namespace v8 {
 namespace internal {

+class RegExpStack;
+
 // Maintains a per-v8thread stack area that can be used by irregexp
 // implementation for its backtracking stack.
 // Since there is only one stack area, the Irregexp implementation is not
// re-entrant. I.e., no regular expressions may be executed in the same thread
 // during a preempted Irregexp execution.
+class RegExpStackScope {
+ public:
+ // Create and delete an instance to control the life-time of a growing stack.
+
+  // Initializes the stack memory area if necessary.
+  explicit RegExpStackScope(Isolate* isolate);
+  ~RegExpStackScope();  // Releases the stack if it has grown.
+
+  RegExpStack* stack() const { return regexp_stack_; }
+
+ private:
+  RegExpStack* regexp_stack_;
+
+  DISALLOW_COPY_AND_ASSIGN(RegExpStackScope);
+};
+
+
 class RegExpStack {
  public:
   // Number of allocated locations on the stack below the limit.
@@ -43,39 +62,37 @@
   // check.
   static const int kStackLimitSlack = 32;

- // Create and delete an instance to control the life-time of a growing stack.
-  RegExpStack();  // Initializes the stack memory area if necessary.
-  ~RegExpStack();  // Releases the stack if it has grown.
-
   // Gives the top of the memory used as stack.
-  static Address stack_base() {
+  Address stack_base() {
     ASSERT(thread_local_.memory_size_ != 0);
     return thread_local_.memory_ + thread_local_.memory_size_;
   }

   // The total size of the memory allocated for the stack.
-  static size_t stack_capacity() { return thread_local_.memory_size_; }
+  size_t stack_capacity() { return thread_local_.memory_size_; }

   // If the stack pointer gets below the limit, we should react and
   // either grow the stack or report an out-of-stack exception.
   // There is only a limited number of locations below the stack limit,
   // so users of the stack should check the stack limit during any
   // sequence of pushes longer that this.
-  static Address* limit_address() { return &(thread_local_.limit_); }
+  Address* limit_address() { return &(thread_local_.limit_); }

   // Ensures that there is a memory area with at least the specified size.
   // If passing zero, the default/minimum size buffer is allocated.
-  static Address EnsureCapacity(size_t size);
+  Address EnsureCapacity(size_t size);

   // Thread local archiving.
   static int ArchiveSpacePerThread() {
-    return static_cast<int>(sizeof(thread_local_));
-  }
-  static char* ArchiveStack(char* to);
-  static char* RestoreStack(char* from);
-  static void FreeThreadResources() { thread_local_.Free(); }
-
+    return static_cast<int>(sizeof(ThreadLocal));
+  }
+  char* ArchiveStack(char* to);
+  char* RestoreStack(char* from);
+  void FreeThreadResources() { thread_local_.Free(); }
  private:
+  RegExpStack();
+  ~RegExpStack();
+
   // Artificial limit used when no memory has been allocated.
   static const uintptr_t kMemoryTop = static_cast<uintptr_t>(-1);

@@ -87,35 +104,42 @@

   // Structure holding the allocated memory, size and limit.
   struct ThreadLocal {
-    ThreadLocal()
-        : memory_(NULL),
-          memory_size_(0),
-          limit_(reinterpret_cast<Address>(kMemoryTop)) {}
+    ThreadLocal() { Clear(); }
     // If memory_size_ > 0 then memory_ must be non-NULL.
     Address memory_;
     size_t memory_size_;
     Address limit_;
+    void Clear() {
+      memory_ = NULL;
+      memory_size_ = 0;
+      limit_ = reinterpret_cast<Address>(kMemoryTop);
+    }
     void Free();
   };

   // Address of allocated memory.
-  static Address memory_address() {
+  Address memory_address() {
     return reinterpret_cast<Address>(&thread_local_.memory_);
   }

   // Address of size of allocated memory.
-  static Address memory_size_address() {
+  Address memory_size_address() {
     return reinterpret_cast<Address>(&thread_local_.memory_size_);
   }

   // Resets the buffer if it has grown beyond the default/minimum size.
   // After this, the buffer is either the default size, or it is empty, so
   // you have to call EnsureCapacity before using it again.
-  static void Reset();
-
-  static ThreadLocal thread_local_;
+  void Reset();
+
+  ThreadLocal thread_local_;
+  Isolate* isolate_;

   friend class ExternalReference;
+  friend class Isolate;
+  friend class RegExpStackScope;
+
+  DISALLOW_COPY_AND_ASSIGN(RegExpStack);
 };

 }}  // namespace v8::internal
=======================================
--- /branches/experimental/isolates/src/v8threads.cc Tue Jun 29 13:01:19 2010 +++ /branches/experimental/isolates/src/v8threads.cc Thu Jul 1 14:55:46 2010
@@ -163,7 +163,7 @@
   from = isolate_->debug()->RestoreDebug(from);
 #endif
   from = isolate_->stack_guard()->RestoreStackGuard(from);
-  from = RegExpStack::RestoreStack(from);
+  from = isolate_->regexp_stack()->RestoreStack(from);
   from = isolate_->bootstrapper()->RestoreState(from);
   Thread::SetThreadLocal(thread_state_key_, NULL);
   if (state->terminate_on_restore()) {
@@ -307,7 +307,7 @@
   to = isolate_->debug()->ArchiveDebug(to);
 #endif
   to = isolate_->stack_guard()->ArchiveStackGuard(to);
-  to = RegExpStack::ArchiveStack(to);
+  to = isolate_->regexp_stack()->ArchiveStack(to);
   to = isolate_->bootstrapper()->ArchiveState(to);
   lazily_archived_thread_.Initialize(ThreadHandle::INVALID);
   lazily_archived_thread_state_ = NULL;
@@ -321,7 +321,7 @@
   isolate_->debug()->FreeThreadResources();
 #endif
   isolate_->stack_guard()->FreeThreadResources();
-  RegExpStack::FreeThreadResources();
+  isolate_->regexp_stack()->FreeThreadResources();
   isolate_->bootstrapper()->FreeThreadResources();
 }

=======================================
--- /branches/experimental/isolates/test/cctest/test-alloc.cc Fri Jun 25 15:32:52 2010 +++ /branches/experimental/isolates/test/cctest/test-alloc.cc Thu Jul 1 14:55:46 2010
@@ -185,6 +185,7 @@

 TEST(CodeRange) {
   const int code_range_size = 16*MB;
+  OS::Setup();
   Isolate::Current()->code_range()->Setup(code_range_size);
   int current_allocated = 0;
   int total_allocated = 0;
=======================================
--- /branches/experimental/isolates/test/cctest/test-assembler-x64.cc Wed Nov 11 01:50:06 2009 +++ /branches/experimental/isolates/test/cctest/test-assembler-x64.cc Thu Jul 1 14:55:46 2010
@@ -80,6 +80,7 @@


 TEST(AssemblerX64ReturnOperation) {
+  OS::Setup();
   // Allocate an executable page of memory.
   size_t actual_size;
byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
@@ -101,6 +102,7 @@
 }

 TEST(AssemblerX64StackOperations) {
+  OS::Setup();
   // Allocate an executable page of memory.
   size_t actual_size;
byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
@@ -132,6 +134,7 @@
 }

 TEST(AssemblerX64ArithmeticOperations) {
+  OS::Setup();
   // Allocate an executable page of memory.
   size_t actual_size;
byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
@@ -153,6 +156,7 @@
 }

 TEST(AssemblerX64ImulOperation) {
+  OS::Setup();
   // Allocate an executable page of memory.
   size_t actual_size;
byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
@@ -180,6 +184,7 @@
 }

 TEST(AssemblerX64MemoryOperands) {
+  OS::Setup();
   // Allocate an executable page of memory.
   size_t actual_size;
byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
@@ -213,6 +218,7 @@
 }

 TEST(AssemblerX64ControlFlow) {
+  OS::Setup();
   // Allocate an executable page of memory.
   size_t actual_size;
byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
@@ -241,6 +247,7 @@
 }

 TEST(AssemblerX64LoopImmediates) {
+  OS::Setup();
   // Allocate an executable page of memory.
   size_t actual_size;
byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
=======================================
--- /branches/experimental/isolates/test/cctest/test-platform-linux.cc Tue Sep 9 13:08:45 2008 +++ /branches/experimental/isolates/test/cctest/test-platform-linux.cc Thu Jul 1 14:55:46 2010
@@ -67,6 +67,7 @@


 TEST(VirtualMemory) {
+  OS::Setup();
   VirtualMemory* vm = new VirtualMemory(1 * MB);
   CHECK(vm->IsReserved());
   void* block_addr = vm->address();
=======================================
--- /branches/experimental/isolates/test/cctest/test-serialize.cc Thu Jul 1 11:02:03 2010 +++ /branches/experimental/isolates/test/cctest/test-serialize.cc Thu Jul 1 14:55:46 2010
@@ -106,6 +106,7 @@


 TEST(ExternalReferenceEncoder) {
+  OS::Setup();
i::Isolate::Current()->stats_table()->SetCounterFunction(counter_function);
   HEAP->Setup(false);
   ExternalReferenceEncoder encoder;
@@ -147,6 +148,7 @@


 TEST(ExternalReferenceDecoder) {
+  OS::Setup();
i::Isolate::Current()->stats_table()->SetCounterFunction(counter_function);
   HEAP->Setup(false);
   ExternalReferenceDecoder decoder;
=======================================
--- /branches/experimental/isolates/test/cctest/test-spaces.cc Mon Jun 21 15:48:21 2010 +++ /branches/experimental/isolates/test/cctest/test-spaces.cc Thu Jul 1 14:55:46 2010
@@ -90,6 +90,7 @@


 TEST(MemoryAllocator) {
+  OS::Setup();
   Isolate* isolate = Isolate::Current();

   CHECK(isolate->heap()->ConfigureHeapDefault());
@@ -151,6 +152,7 @@


 TEST(NewSpace) {
+  OS::Setup();
   CHECK(HEAP->ConfigureHeapDefault());
CHECK(Isolate::Current()->memory_allocator()->Setup(HEAP->MaxReserved()));

@@ -177,6 +179,7 @@


 TEST(OldSpace) {
+  OS::Setup();
   CHECK(HEAP->ConfigureHeapDefault());
CHECK(Isolate::Current()->memory_allocator()->Setup(HEAP->MaxReserved()));

@@ -206,6 +209,7 @@


 TEST(LargeObjectSpace) {
+  OS::Setup();
   CHECK(HEAP->Setup(false));

   LargeObjectSpace* lo = HEAP->lo_space();
=======================================
--- /branches/experimental/isolates/test/cctest/test-utils.cc Wed Jun 9 16:02:44 2010 +++ /branches/experimental/isolates/test/cctest/test-utils.cc Thu Jul 1 14:55:46 2010
@@ -103,6 +103,7 @@


 TEST(MemCopy) {
+  OS::Setup();
   const int N = kMinComplexMemCopy + 128;
   Vector<byte> buffer1 = Vector<byte>::New(N);
   Vector<byte> buffer2 = Vector<byte>::New(N);

--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to