diff options
Diffstat (limited to 'deps/v8/src/global-handles.cc')
-rw-r--r-- | deps/v8/src/global-handles.cc | 101 |
1 files changed, 84 insertions, 17 deletions
diff --git a/deps/v8/src/global-handles.cc b/deps/v8/src/global-handles.cc index f4b69fcdd3..c6cc288e6a 100644 --- a/deps/v8/src/global-handles.cc +++ b/deps/v8/src/global-handles.cc @@ -44,6 +44,10 @@ class GlobalHandles::Node : public Malloced { callback_ = NULL; } + Node() { + state_ = DESTROYED; + } + explicit Node(Object* object) { Initialize(object); // Initialize link structure. @@ -200,20 +204,80 @@ class GlobalHandles::Node : public Malloced { }; +class GlobalHandles::Pool BASE_EMBEDDED { + public: + Pool() { + current_ = new Chunk(); + current_->previous = NULL; + next_ = current_->nodes; + limit_ = current_->nodes + kNodesPerChunk; + } + + Node* Allocate() { + if (next_ < limit_) { + return next_++; + } + return SlowAllocate(); + } + + void Release() { + Chunk* current = current_; + ASSERT(current != NULL); // At least a single block must by allocated + do { + Chunk* previous = current->previous; + delete current; + current = previous; + } while (current != NULL); + current_ = NULL; + next_ = limit_ = NULL; + } + + private: + static const int kNodesPerChunk = (1 << 12) - 1; + struct Chunk : public Malloced { + Chunk* previous; + Node nodes[kNodesPerChunk]; + }; + + Node* SlowAllocate() { + Chunk* chunk = new Chunk(); + chunk->previous = current_; + current_ = chunk; + + Node* new_nodes = current_->nodes; + next_ = new_nodes + 1; + limit_ = new_nodes + kNodesPerChunk; + return new_nodes; + } + + Chunk* current_; + Node* next_; + Node* limit_; +}; + + +static GlobalHandles::Pool pool_; + + Handle<Object> GlobalHandles::Create(Object* value) { Counters::global_handles.Increment(); Node* result; - if (first_free() == NULL) { - // Allocate a new node. - result = new Node(value); - result->set_next(head()); - set_head(result); - } else { + if (first_free()) { // Take the first node in the free list. result = first_free(); set_first_free(result->next_free()); - result->Initialize(value); + } else if (first_deallocated()) { + // Next try deallocated list + result = first_deallocated(); + set_first_deallocated(result->next_free()); + set_head(result); + } else { + // Allocate a new node. + result = pool_.Allocate(); + result->set_next(head()); + set_head(result); } + result->Initialize(value); return result->handle(); } @@ -292,7 +356,7 @@ void GlobalHandles::PostGarbageCollectionProcessing() { // Process weak global handle callbacks. This must be done after the // GC is completely done, because the callbacks may invoke arbitrary // API functions. - // At the same time deallocate all DESTROYED nodes + // At the same time deallocate all DESTROYED nodes. ASSERT(Heap::gc_state() == Heap::NOT_IN_GC); const int initial_post_gc_processing_count = ++post_gc_processing_count; Node** p = &head_; @@ -310,12 +374,19 @@ void GlobalHandles::PostGarbageCollectionProcessing() { // Delete the link. Node* node = *p; *p = node->next(); // Update the link. - delete node; + if (first_deallocated()) { + first_deallocated()->set_next(node); + } + node->set_next_free(first_deallocated()); + set_first_deallocated(node); } else { p = (*p)->next_addr(); } } set_first_free(NULL); + if (first_deallocated()) { + first_deallocated()->set_next(head()); + } } @@ -329,16 +400,11 @@ void GlobalHandles::IterateRoots(ObjectVisitor* v) { } void GlobalHandles::TearDown() { - // Delete all the nodes in the linked list. - Node* current = head_; - while (current != NULL) { - Node* n = current; - current = current->next(); - delete n; - } - // Reset the head and free_list. + // Reset all the lists. set_head(NULL); set_first_free(NULL); + set_first_deallocated(NULL); + pool_.Release(); } @@ -347,6 +413,7 @@ int GlobalHandles::number_of_global_object_weak_handles_ = 0; GlobalHandles::Node* GlobalHandles::head_ = NULL; GlobalHandles::Node* GlobalHandles::first_free_ = NULL; +GlobalHandles::Node* GlobalHandles::first_deallocated_ = NULL; #ifdef DEBUG |