Add a second kind of HandleScope that ties the lifetime of Handles created in its...
authorsanjoy@chromium.org <sanjoy@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 27 Jun 2012 11:47:47 +0000 (11:47 +0000)
committersanjoy@chromium.org <sanjoy@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 27 Jun 2012 11:47:47 +0000 (11:47 +0000)
BUG=
TEST=

Review URL: https://chromiumcodereview.appspot.com/10640012

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@11939 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/api.cc
src/api.h
src/compiler.cc
src/compiler.h
src/handles.cc
src/handles.h
src/hydrogen.cc

index 0d88047..dda482c 100644 (file)
@@ -6374,12 +6374,28 @@ char* HandleScopeImplementer::RestoreThread(char* storage) {
 
 
 void HandleScopeImplementer::IterateThis(ObjectVisitor* v) {
+#ifdef DEBUG
+  bool found_block_before_deferred = false;
+#endif
   // Iterate over all handles in the blocks except for the last.
   for (int i = blocks()->length() - 2; i >= 0; --i) {
     Object** block = blocks()->at(i);
-    v->VisitPointers(block, &block[kHandleBlockSize]);
+    if (last_handle_before_deferred_block_ != NULL &&
+        (last_handle_before_deferred_block_ < &block[kHandleBlockSize]) &&
+        (last_handle_before_deferred_block_ >= block)) {
+      v->VisitPointers(block, last_handle_before_deferred_block_);
+      ASSERT(!found_block_before_deferred);
+#ifdef DEBUG
+      found_block_before_deferred = true;
+#endif
+    } else {
+      v->VisitPointers(block, &block[kHandleBlockSize]);
+    }
   }
 
+  ASSERT(last_handle_before_deferred_block_ == NULL ||
+         found_block_before_deferred);
+
   // Iterate over live handles in the last block (if any).
   if (!blocks()->is_empty()) {
     v->VisitPointers(blocks()->last(), handle_scope_data_.next);
@@ -6389,6 +6405,12 @@ void HandleScopeImplementer::IterateThis(ObjectVisitor* v) {
     Object** start = reinterpret_cast<Object**>(&saved_contexts_.first());
     v->VisitPointers(start, start + saved_contexts_.length());
   }
+
+  for (DeferredHandles* deferred = deferred_handles_head_;
+       deferred != NULL;
+       deferred = deferred->next_) {
+    deferred->Iterate(v);
+  }
 }
 
 
@@ -6407,4 +6429,75 @@ char* HandleScopeImplementer::Iterate(ObjectVisitor* v, char* storage) {
   return storage + ArchiveSpacePerThread();
 }
 
+
+DeferredHandles* HandleScopeImplementer::Detach(Object** prev_limit) {
+  DeferredHandles* deferred = new DeferredHandles(
+      deferred_handles_head_, isolate()->handle_scope_data()->next, this);
+
+  while (!blocks_.is_empty()) {
+    Object** block_start = blocks_.last();
+    Object** block_limit = &block_start[kHandleBlockSize];
+    // We should not need to check for NoHandleAllocation here. Assert
+    // this.
+    ASSERT(prev_limit == block_limit ||
+           !(block_start <= prev_limit && prev_limit <= block_limit));
+    if (prev_limit == block_limit) break;
+    deferred->blocks_.Add(blocks_.last());
+    blocks_.RemoveLast();
+  }
+
+  ASSERT(!blocks_.is_empty() && prev_limit != NULL);
+  deferred_handles_head_ = deferred;
+  ASSERT(last_handle_before_deferred_block_ != NULL);
+  last_handle_before_deferred_block_ = NULL;
+  return deferred;
+}
+
+
+void HandleScopeImplementer::DestroyDeferredHandles(DeferredHandles* deferred) {
+  if (deferred_handles_head_ == deferred) {
+    deferred_handles_head_ = deferred_handles_head_->next_;
+  }
+  if (deferred->next_ != NULL) {
+    deferred->next_->previous_ = deferred->previous_;
+  }
+  if (deferred->previous_ != NULL) {
+    deferred->previous_->next_ = deferred->next_;
+  }
+  for (int i = 0; i < deferred->blocks_.length(); i++) {
+#ifdef DEBUG
+    HandleScope::ZapRange(deferred->blocks_[i],
+                          &deferred->blocks_[i][kHandleBlockSize]);
+#endif
+    if (spare_ != NULL) DeleteArray(spare_);
+    spare_ = deferred->blocks_[i];
+  }
+}
+
+
+void HandleScopeImplementer::BeginDeferredScope() {
+  ASSERT(last_handle_before_deferred_block_ == NULL);
+  last_handle_before_deferred_block_ = isolate()->handle_scope_data()->next;
+}
+
+
+DeferredHandles::~DeferredHandles() {
+  impl_->DestroyDeferredHandles(this);
+}
+
+
+void DeferredHandles::Iterate(ObjectVisitor* v) {
+  ASSERT(!blocks_.is_empty());
+
+  for (int i = 0; i < (blocks_.length() - 1); i++) {
+    v->VisitPointers(blocks_[i], &blocks_[i][kHandleBlockSize]);
+  }
+
+  ASSERT((last_block_limit_ >= blocks_.last()) &&
+         (last_block_limit_ < &(blocks_.last())[kHandleBlockSize]));
+
+  v->VisitPointers(blocks_.last(), last_block_limit_);
+}
+
+
 } }  // namespace v8::internal
index 58e6a6e..cd6c3da 100644 (file)
--- a/src/api.h
+++ b/src/api.h
@@ -392,6 +392,28 @@ class StringTracker {
 };
 
 
+class DeferredHandles {
+ public:
+  ~DeferredHandles();
+
+ private:
+  DeferredHandles(DeferredHandles* next, Object** last_block_limit,
+                  HandleScopeImplementer* impl)
+      : next_(next), previous_(NULL), last_block_limit_(last_block_limit),
+        impl_(impl) {}
+
+  void Iterate(ObjectVisitor* v);
+
+  List<Object**> blocks_;
+  DeferredHandles* next_;
+  DeferredHandles* previous_;
+  Object** last_block_limit_;
+  HandleScopeImplementer* impl_;
+
+  friend class HandleScopeImplementer;
+};
+
+
 // This class is here in order to be able to declare it a friend of
 // HandleScope.  Moving these methods to be members of HandleScope would be
 // neat in some ways, but it would expose internal implementation details in
@@ -409,7 +431,9 @@ class HandleScopeImplementer {
         entered_contexts_(0),
         saved_contexts_(0),
         spare_(NULL),
-        call_depth_(0) { }
+        call_depth_(0),
+        last_handle_before_deferred_block_(NULL),
+        deferred_handles_head_(NULL) { }
 
   ~HandleScopeImplementer() {
     DeleteArray(spare_);
@@ -445,6 +469,7 @@ class HandleScopeImplementer {
   inline bool HasSavedContexts();
 
   inline List<internal::Object**>* blocks() { return &blocks_; }
+  Isolate* isolate() const { return isolate_; }
 
  private:
   void ResetAfterArchive() {
@@ -469,6 +494,10 @@ class HandleScopeImplementer {
     ASSERT(call_depth_ == 0);
   }
 
+  void BeginDeferredScope();
+  DeferredHandles* Detach(Object** prev_limit);
+  void DestroyDeferredHandles(DeferredHandles* handles);
+
   Isolate* isolate_;
   List<internal::Object**> blocks_;
   // Used as a stack to keep track of entered contexts.
@@ -477,6 +506,8 @@ class HandleScopeImplementer {
   List<Context*> saved_contexts_;
   Object** spare_;
   int call_depth_;
+  Object** last_handle_before_deferred_block_;
+  DeferredHandles* deferred_handles_head_;
   // This is only used for threading support.
   v8::ImplementationUtilities::HandleScopeData handle_scope_data_;
 
@@ -484,6 +515,9 @@ class HandleScopeImplementer {
   char* RestoreThreadHelper(char* from);
   char* ArchiveThreadHelper(char* to);
 
+  friend class DeferredHandles;
+  friend class DeferredHandleScope;
+
   DISALLOW_COPY_AND_ASSIGN(HandleScopeImplementer);
 };
 
index d35532f..06a056a 100644 (file)
@@ -61,7 +61,8 @@ CompilationInfo::CompilationInfo(Handle<Script> script, Zone* zone)
       extension_(NULL),
       pre_parse_data_(NULL),
       osr_ast_id_(AstNode::kNoNumber),
-      zone_(zone) {
+      zone_(zone),
+      deferred_handles_(NULL) {
   Initialize(BASE);
 }
 
@@ -79,7 +80,8 @@ CompilationInfo::CompilationInfo(Handle<SharedFunctionInfo> shared_info,
       extension_(NULL),
       pre_parse_data_(NULL),
       osr_ast_id_(AstNode::kNoNumber),
-      zone_(zone) {
+      zone_(zone),
+      deferred_handles_(NULL) {
   Initialize(BASE);
 }
 
@@ -97,11 +99,17 @@ CompilationInfo::CompilationInfo(Handle<JSFunction> closure, Zone* zone)
       extension_(NULL),
       pre_parse_data_(NULL),
       osr_ast_id_(AstNode::kNoNumber),
-      zone_(zone) {
+      zone_(zone),
+      deferred_handles_(NULL) {
   Initialize(BASE);
 }
 
 
+CompilationInfo::~CompilationInfo() {
+  delete deferred_handles_;
+}
+
+
 // Disable optimization for the rest of the compilation pipeline.
 void CompilationInfo::DisableOptimization() {
   bool is_optimizable_closure =
index 26c0ac4..1359048 100644 (file)
@@ -45,6 +45,8 @@ class CompilationInfo BASE_EMBEDDED {
   CompilationInfo(Handle<SharedFunctionInfo> shared_info, Zone* zone);
   CompilationInfo(Handle<JSFunction> closure, Zone* zone);
 
+  ~CompilationInfo();
+
   Isolate* isolate() {
     ASSERT(Isolate::Current() == isolate_);
     return isolate_;
@@ -173,6 +175,11 @@ class CompilationInfo BASE_EMBEDDED {
   // current compilation pipeline.
   void AbortOptimization();
 
+  void set_deferred_handles(DeferredHandles* deferred_handles) {
+    ASSERT(deferred_handles_ == NULL);
+    deferred_handles_ = deferred_handles;
+  }
+
  private:
   Isolate* isolate_;
 
@@ -259,6 +266,8 @@ class CompilationInfo BASE_EMBEDDED {
   // CompilationInfo allocates.
   Zone* zone_;
 
+  DeferredHandles* deferred_handles_;
+
   DISALLOW_COPY_AND_ASSIGN(CompilationInfo);
 };
 
@@ -286,6 +295,23 @@ class CompilationInfoWithZone: public CompilationInfo {
 };
 
 
+// A wrapper around a CompilationInfo that detaches the Handles from
+// the underlying DeferredHandleScope and stores them in info_ on
+// destruction.
+class CompilationHandleScope BASE_EMBEDDED {
+ public:
+  explicit CompilationHandleScope(CompilationInfo* info)
+      : deferred_(info->isolate()), info_(info) {}
+  ~CompilationHandleScope() {
+    info_->set_deferred_handles(deferred_.Detach());
+  }
+
+ private:
+  DeferredHandleScope deferred_;
+  CompilationInfo* info_;
+};
+
+
 // The V8 compiler
 //
 // General strategy: Source code is translated into an anonymous function w/o
index def1604..1962e2f 100644 (file)
@@ -958,4 +958,45 @@ int Utf8Length(Handle<String> str) {
   return len;
 }
 
+
+DeferredHandleScope::DeferredHandleScope(Isolate* isolate)
+    : impl_(isolate->handle_scope_implementer()) {
+  impl_->BeginDeferredScope();
+  Object** new_next = impl_->GetSpareOrNewBlock();
+  Object** new_limit = &new_next[kHandleBlockSize];
+  impl_->blocks()->Add(new_next);
+
+  v8::ImplementationUtilities::HandleScopeData* data =
+      impl_->isolate()->handle_scope_data();
+#ifdef DEBUG
+  prev_level_ = data->level;
+#endif
+  data->level++;
+  prev_limit_ = data->limit;
+  prev_next_ = data->next;
+  data->next = new_next;
+  data->limit = new_limit;
+}
+
+
+DeferredHandleScope::~DeferredHandleScope() {
+  impl_->isolate()->handle_scope_data()->level--;
+  ASSERT(handles_detached_);
+  ASSERT(impl_->isolate()->handle_scope_data()->level == prev_level_);
+}
+
+
+DeferredHandles* DeferredHandleScope::Detach() {
+  DeferredHandles* deferred = impl_->Detach(prev_limit_);
+  v8::ImplementationUtilities::HandleScopeData* data =
+      impl_->isolate()->handle_scope_data();
+  data->next = prev_next_;
+  data->limit = prev_limit_;
+#ifdef DEBUG
+  handles_detached_ = true;
+#endif
+  return deferred;
+}
+
+
 } }  // namespace v8::internal
index 960696b..aca8690 100644 (file)
@@ -95,6 +95,9 @@ class Handle {
 };
 
 
+class HandleScopeImplementer;
+
+
 // A stack-allocated class that governs a number of local handles.
 // After a handle scope has been created, all local handles will be
 // allocated within that handle scope until either the handle scope is
@@ -157,10 +160,37 @@ class HandleScope {
   static void ZapRange(internal::Object** start, internal::Object** end);
 
   friend class v8::HandleScope;
+  friend class v8::internal::HandleScopeImplementer;
   friend class v8::ImplementationUtilities;
 };
 
 
+class DeferredHandles;
+
+
+class DeferredHandleScope {
+ public:
+  explicit DeferredHandleScope(Isolate* isolate);
+  // The DeferredHandles object returned stores the Handles created
+  // since the creation of this DeferredHandleScope.  The Handles are
+  // alive as long as the DeferredHandles object is alive.
+  DeferredHandles* Detach();
+  ~DeferredHandleScope();
+
+ private:
+  Object** prev_limit_;
+  Object** prev_next_;
+  HandleScopeImplementer* impl_;
+
+#ifdef DEBUG
+  bool handles_detached_;
+  int prev_level_;
+#endif
+
+  friend class HandleScopeImplementer;
+};
+
+
 // ----------------------------------------------------------------------------
 // Handle operations.
 // They might invoke garbage collection. The result is an handle to
index e91965e..16e7a0c 100644 (file)
@@ -3053,6 +3053,7 @@ HGraph* HGraphBuilder::CreateGraph() {
 
   {
     HPhase phase("H_Block building");
+    CompilationHandleScope handle_scope(info());
     current_block_ = graph()->entry_block();
 
     Scope* scope = info()->scope();