| Index: src/global-handles.cc
|
| ===================================================================
|
| --- src/global-handles.cc (revision 2585)
|
| +++ src/global-handles.cc (working copy)
|
| @@ -33,186 +33,6 @@
|
| namespace v8 {
|
| namespace internal {
|
|
|
| -class GlobalHandles::Node : public Malloced {
|
| - public:
|
| -
|
| - void Initialize(Object* object) {
|
| - // Set the initial value of the handle.
|
| - object_ = object;
|
| - state_ = NORMAL;
|
| - parameter_or_next_free_.parameter = NULL;
|
| - callback_ = NULL;
|
| - }
|
| -
|
| - explicit Node(Object* object) {
|
| - Initialize(object);
|
| - // Initialize link structure.
|
| - next_ = NULL;
|
| - }
|
| -
|
| - ~Node() {
|
| - if (state_ != DESTROYED) Destroy();
|
| -#ifdef DEBUG
|
| - // Zap the values for eager trapping.
|
| - object_ = NULL;
|
| - next_ = NULL;
|
| - parameter_or_next_free_.next_free = NULL;
|
| -#endif
|
| - }
|
| -
|
| - void Destroy() {
|
| - if (state_ == WEAK || IsNearDeath()) {
|
| - GlobalHandles::number_of_weak_handles_--;
|
| - if (object_->IsJSGlobalObject()) {
|
| - GlobalHandles::number_of_global_object_weak_handles_--;
|
| - }
|
| - }
|
| - state_ = DESTROYED;
|
| - }
|
| -
|
| - // Accessors for next_.
|
| - Node* next() { return next_; }
|
| - void set_next(Node* value) { next_ = value; }
|
| - Node** next_addr() { return &next_; }
|
| -
|
| - // Accessors for next free node in the free list.
|
| - Node* next_free() {
|
| - ASSERT(state_ == DESTROYED);
|
| - return parameter_or_next_free_.next_free;
|
| - }
|
| - void set_next_free(Node* value) {
|
| - ASSERT(state_ == DESTROYED);
|
| - parameter_or_next_free_.next_free = value;
|
| - }
|
| -
|
| - // Returns a link from the handle.
|
| - static Node* FromLocation(Object** location) {
|
| - ASSERT(OFFSET_OF(Node, object_) == 0);
|
| - return reinterpret_cast<Node*>(location);
|
| - }
|
| -
|
| - // Returns the handle.
|
| - Handle<Object> handle() { return Handle<Object>(&object_); }
|
| -
|
| - // Make this handle weak.
|
| - void MakeWeak(void* parameter, WeakReferenceCallback callback) {
|
| - LOG(HandleEvent("GlobalHandle::MakeWeak", handle().location()));
|
| - ASSERT(state_ != DESTROYED);
|
| - if (state_ != WEAK && !IsNearDeath()) {
|
| - GlobalHandles::number_of_weak_handles_++;
|
| - if (object_->IsJSGlobalObject()) {
|
| - GlobalHandles::number_of_global_object_weak_handles_++;
|
| - }
|
| - }
|
| - state_ = WEAK;
|
| - set_parameter(parameter);
|
| - callback_ = callback;
|
| - }
|
| -
|
| - void ClearWeakness() {
|
| - LOG(HandleEvent("GlobalHandle::ClearWeakness", handle().location()));
|
| - ASSERT(state_ != DESTROYED);
|
| - if (state_ == WEAK || IsNearDeath()) {
|
| - GlobalHandles::number_of_weak_handles_--;
|
| - if (object_->IsJSGlobalObject()) {
|
| - GlobalHandles::number_of_global_object_weak_handles_--;
|
| - }
|
| - }
|
| - state_ = NORMAL;
|
| - set_parameter(NULL);
|
| - }
|
| -
|
| - bool IsNearDeath() {
|
| - // Check for PENDING to ensure correct answer when processing callbacks.
|
| - return state_ == PENDING || state_ == NEAR_DEATH;
|
| - }
|
| -
|
| - bool IsWeak() {
|
| - return state_ == WEAK;
|
| - }
|
| -
|
| - // Returns the id for this weak handle.
|
| - void set_parameter(void* parameter) {
|
| - ASSERT(state_ != DESTROYED);
|
| - parameter_or_next_free_.parameter = parameter;
|
| - }
|
| - void* parameter() {
|
| - ASSERT(state_ != DESTROYED);
|
| - return parameter_or_next_free_.parameter;
|
| - }
|
| -
|
| - // Returns the callback for this weak handle.
|
| - WeakReferenceCallback callback() { return callback_; }
|
| -
|
| - void PostGarbageCollectionProcessing() {
|
| - if (state_ != Node::PENDING) return;
|
| - LOG(HandleEvent("GlobalHandle::Processing", handle().location()));
|
| - void* par = parameter();
|
| - state_ = NEAR_DEATH;
|
| - set_parameter(NULL);
|
| - // The callback function is resolved as late as possible to preserve old
|
| - // behavior.
|
| - WeakReferenceCallback func = callback();
|
| - if (func != NULL) {
|
| - v8::Persistent<v8::Object> object = ToApi<v8::Object>(handle());
|
| - {
|
| - // Leaving V8.
|
| - VMState state(EXTERNAL);
|
| - func(object, par);
|
| - }
|
| - }
|
| - }
|
| -
|
| - // Place the handle address first to avoid offset computation.
|
| - Object* object_; // Storage for object pointer.
|
| -
|
| - // Transition diagram:
|
| - // NORMAL <-> WEAK -> PENDING -> NEAR_DEATH -> { NORMAL, WEAK, DESTROYED }
|
| - enum State {
|
| - NORMAL, // Normal global handle.
|
| - WEAK, // Flagged as weak but not yet finalized.
|
| - PENDING, // Has been recognized as only reachable by weak handles.
|
| - NEAR_DEATH, // Callback has informed the handle is near death.
|
| - DESTROYED
|
| - };
|
| - State state_;
|
| -
|
| - private:
|
| - // Handle specific callback.
|
| - WeakReferenceCallback callback_;
|
| - // Provided data for callback. In DESTROYED state, this is used for
|
| - // the free list link.
|
| - union {
|
| - void* parameter;
|
| - Node* next_free;
|
| - } parameter_or_next_free_;
|
| -
|
| - // Linkage for the list.
|
| - Node* next_;
|
| -
|
| - public:
|
| - TRACK_MEMORY("GlobalHandles::Node")
|
| -};
|
| -
|
| -
|
| -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 {
|
| - // Take the first node in the free list.
|
| - result = first_free();
|
| - set_first_free(result->next_free());
|
| - result->Initialize(value);
|
| - }
|
| - return result->handle();
|
| -}
|
| -
|
| -
|
| void GlobalHandles::Destroy(Object** location) {
|
| Counters::global_handles.Decrement();
|
| if (location == NULL) return;
|
| @@ -275,7 +95,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);
|
| Node** p = &head_;
|
| while (*p != NULL) {
|
| @@ -284,12 +104,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());
|
| + }
|
| }
|
|
|
|
|
| @@ -303,16 +130,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();
|
| }
|
|
|
|
|
| @@ -321,7 +143,10 @@
|
|
|
| GlobalHandles::Node* GlobalHandles::head_ = NULL;
|
| GlobalHandles::Node* GlobalHandles::first_free_ = NULL;
|
| +GlobalHandles::Node* GlobalHandles::first_deallocated_ = NULL;
|
|
|
| +GlobalHandles::Pool GlobalHandles::pool_;
|
| +
|
| #ifdef DEBUG
|
|
|
| void GlobalHandles::PrintStats() {
|
| @@ -381,4 +206,90 @@
|
| }
|
|
|
|
|
| +void GlobalHandles::Node::Destroy() {
|
| + if (state_ == WEAK || IsNearDeath()) {
|
| + GlobalHandles::number_of_weak_handles_--;
|
| + if (object_->IsJSGlobalObject()) {
|
| + GlobalHandles::number_of_global_object_weak_handles_--;
|
| + }
|
| + }
|
| + state_ = DESTROYED;
|
| +}
|
| +
|
| +
|
| +void GlobalHandles::Node::MakeWeak(void* parameter,
|
| + WeakReferenceCallback callback) {
|
| + LOG(HandleEvent("GlobalHandle::MakeWeak", handle().location()));
|
| + ASSERT(state_ != DESTROYED);
|
| + if (state_ != WEAK && !IsNearDeath()) {
|
| + GlobalHandles::number_of_weak_handles_++;
|
| + if (object_->IsJSGlobalObject()) {
|
| + GlobalHandles::number_of_global_object_weak_handles_++;
|
| + }
|
| + }
|
| + state_ = WEAK;
|
| + set_parameter(parameter);
|
| + callback_ = callback;
|
| +}
|
| +
|
| +
|
| +void GlobalHandles::Node::ClearWeakness() {
|
| + LOG(HandleEvent("GlobalHandle::ClearWeakness", handle().location()));
|
| + ASSERT(state_ != DESTROYED);
|
| + if (state_ == WEAK || IsNearDeath()) {
|
| + GlobalHandles::number_of_weak_handles_--;
|
| + if (object_->IsJSGlobalObject()) {
|
| + GlobalHandles::number_of_global_object_weak_handles_--;
|
| + }
|
| + }
|
| + state_ = NORMAL;
|
| + set_parameter(NULL);
|
| +}
|
| +
|
| +
|
| +void GlobalHandles::Node::PostGarbageCollectionProcessing() {
|
| + if (state_ != Node::PENDING) return;
|
| + LOG(HandleEvent("GlobalHandle::Processing", handle().location()));
|
| + void* par = parameter();
|
| + state_ = NEAR_DEATH;
|
| + set_parameter(NULL);
|
| + // The callback function is resolved as late as possible to preserve old
|
| + // behavior.
|
| + WeakReferenceCallback func = callback();
|
| + if (func != NULL) {
|
| + v8::Persistent<v8::Object> object = ToApi<v8::Object>(handle());
|
| + {
|
| + // Leaving V8.
|
| + VMState state(EXTERNAL);
|
| + func(object, par);
|
| + }
|
| + }
|
| +}
|
| +
|
| +
|
| +GlobalHandles::Node* GlobalHandles::Pool::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;
|
| +}
|
| +
|
| +
|
| +void GlobalHandles::Pool::Release() {
|
| + Chunk* current = current_;
|
| + ASSERT(current != NULL); // At least a single block must be allocated
|
| + do {
|
| + Chunk* previous = current->previous;
|
| + delete current;
|
| + current = previous;
|
| + } while (current != NULL);
|
| + current_ = NULL;
|
| + next_ = limit_ = NULL;
|
| +}
|
| +
|
| +
|
| } } // namespace v8::internal
|
|
|