From a531c281fdb7def7bd1396280c9a6c9dfb8789d8 Mon Sep 17 00:00:00 2001 From: "antonm@chromium.org" Date: Mon, 26 Oct 2009 12:54:41 +0000 Subject: [PATCH] Allocate global handles in chunks. Review URL: http://codereview.chromium.org/327008 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3128 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/global-handles.cc | 101 +++++++++++++++++++++++++++++++++++++++++--------- src/global-handles.h | 18 +++++++++ 2 files changed, 102 insertions(+), 17 deletions(-) diff --git a/src/global-handles.cc b/src/global-handles.cc index f4b69fc..c6cc288 100644 --- a/src/global-handles.cc +++ b/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 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 diff --git a/src/global-handles.h b/src/global-handles.h index feb95bf..87eb9b8 100644 --- a/src/global-handles.h +++ b/src/global-handles.h @@ -127,6 +127,7 @@ class GlobalHandles : public AllStatic { static void PrintStats(); static void Print(); #endif + class Pool; private: // Internal node structure, one for each global handle. class Node; @@ -148,6 +149,23 @@ class GlobalHandles : public AllStatic { static Node* first_free_; static Node* first_free() { return first_free_; } static void set_first_free(Node* value) { first_free_ = value; } + + // List of deallocated nodes. + // Deallocated nodes form a prefix of all the nodes and + // |first_deallocated| points to last deallocated node before + // |head|. Those deallocated nodes are additionally linked + // by |next_free|: + // 1st deallocated head + // | | + // V V + // node node ... node node + // .next -> .next -> .next -> + // <- .next_free <- .next_free <- .next_free + static Node* first_deallocated_; + static Node* first_deallocated() { return first_deallocated_; } + static void set_first_deallocated(Node* value) { + first_deallocated_ = value; + } }; -- 2.7.4