Index: src/global-handles.cc |
=================================================================== |
--- src/global-handles.cc (revision 3093) |
+++ src/global-handles.cc (working copy) |
@@ -44,6 +44,10 @@ |
callback_ = NULL; |
} |
+ Node() { |
+ state_ = DESTROYED; |
+ } |
+ |
explicit Node(Object* object) { |
Initialize(object); |
// Initialize link structure. |
@@ -200,20 +204,80 @@ |
}; |
+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 << 13) - 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) { |
+ if (first_free()) { |
+ // Take the first node in the free list. |
+ result = first_free(); |
+ set_first_free(result->next_free()); |
+ } 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 = new Node(value); |
+ result = pool_.Allocate(); |
result->set_next(head()); |
set_head(result); |
- } else { |
- // Take the first node in the free list. |
- result = first_free(); |
- set_first_free(result->next_free()); |
- result->Initialize(value); |
} |
+ result->Initialize(value); |
return result->handle(); |
} |
@@ -292,7 +356,7 @@ |
// 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 @@ |
// 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::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 @@ |
GlobalHandles::Node* GlobalHandles::head_ = NULL; |
GlobalHandles::Node* GlobalHandles::first_free_ = NULL; |
+GlobalHandles::Node* GlobalHandles::first_deallocated_ = NULL; |
#ifdef DEBUG |