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
This commit is contained in:
parent
ac280c223b
commit
a531c281fd
@ -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
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user