global-handles.cc revision d0582a6c46733687d045e4188a1bcd0123c758a1
1a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Copyright 2009 the V8 project authors. All rights reserved.
2a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Redistribution and use in source and binary forms, with or without
3a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// modification, are permitted provided that the following conditions are
4a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// met:
5a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//
6a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//     * Redistributions of source code must retain the above copyright
7a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//       notice, this list of conditions and the following disclaimer.
8a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//     * Redistributions in binary form must reproduce the above
9a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//       copyright notice, this list of conditions and the following
10a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//       disclaimer in the documentation and/or other materials provided
11a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//       with the distribution.
12a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//     * Neither the name of Google Inc. nor the names of its
13a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//       contributors may be used to endorse or promote products derived
14a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//       from this software without specific prior written permission.
15a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//
16a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
28a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "v8.h"
29a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
30a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "api.h"
31a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "global-handles.h"
32a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
33a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocknamespace v8 {
34a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocknamespace internal {
35a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
36a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass GlobalHandles::Node : public Malloced {
37a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public:
38a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
39a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  void Initialize(Object* object) {
40a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Set the initial value of the handle.
41a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    object_ = object;
42a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    state_  = NORMAL;
43a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    parameter_or_next_free_.parameter = NULL;
44a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    callback_ = NULL;
45a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
46a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
47d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  Node() {
48d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    state_ = DESTROYED;
49d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  }
50d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
51a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  explicit Node(Object* object) {
52a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Initialize(object);
53a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Initialize link structure.
54a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    next_ = NULL;
55a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
56a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
57a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ~Node() {
58a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (state_ != DESTROYED) Destroy();
59a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef DEBUG
60a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Zap the values for eager trapping.
61a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    object_ = NULL;
62a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    next_ = NULL;
63a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    parameter_or_next_free_.next_free = NULL;
64a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif
65a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
66a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
67a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  void Destroy() {
68a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (state_ == WEAK || IsNearDeath()) {
69a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      GlobalHandles::number_of_weak_handles_--;
70a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (object_->IsJSGlobalObject()) {
71a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        GlobalHandles::number_of_global_object_weak_handles_--;
72a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
73a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
74a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    state_ = DESTROYED;
75a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
76a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
77a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Accessors for next_.
78a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Node* next() { return next_; }
79a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  void set_next(Node* value) { next_ = value; }
80a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Node** next_addr() { return &next_; }
81a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
82a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Accessors for next free node in the free list.
83a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Node* next_free() {
84a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(state_ == DESTROYED);
85a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return parameter_or_next_free_.next_free;
86a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
87a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  void set_next_free(Node* value) {
88a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(state_ == DESTROYED);
89a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    parameter_or_next_free_.next_free = value;
90a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
91a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
92a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Returns a link from the handle.
93a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  static Node* FromLocation(Object** location) {
94a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(OFFSET_OF(Node, object_) == 0);
95a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return reinterpret_cast<Node*>(location);
96a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
97a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
98a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Returns the handle.
99a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Handle<Object> handle() { return Handle<Object>(&object_); }
100a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
101a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Make this handle weak.
102a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  void MakeWeak(void* parameter, WeakReferenceCallback callback) {
103a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    LOG(HandleEvent("GlobalHandle::MakeWeak", handle().location()));
104a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(state_ != DESTROYED);
105a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (state_ != WEAK && !IsNearDeath()) {
106a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      GlobalHandles::number_of_weak_handles_++;
107a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (object_->IsJSGlobalObject()) {
108a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        GlobalHandles::number_of_global_object_weak_handles_++;
109a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
110a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
111a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    state_ = WEAK;
112a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    set_parameter(parameter);
113a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    callback_ = callback;
114a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
115a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
116a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  void ClearWeakness() {
117a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    LOG(HandleEvent("GlobalHandle::ClearWeakness", handle().location()));
118a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(state_ != DESTROYED);
119a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (state_ == WEAK || IsNearDeath()) {
120a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      GlobalHandles::number_of_weak_handles_--;
121a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (object_->IsJSGlobalObject()) {
122a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        GlobalHandles::number_of_global_object_weak_handles_--;
123a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
124a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
125a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    state_ = NORMAL;
126a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    set_parameter(NULL);
127a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
128a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
129a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  bool IsNearDeath() {
130a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Check for PENDING to ensure correct answer when processing callbacks.
131a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return state_ == PENDING || state_ == NEAR_DEATH;
132a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
133a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
134a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  bool IsWeak() {
135a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return state_ == WEAK;
136a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
137a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
138a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Returns the id for this weak handle.
139a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  void set_parameter(void* parameter) {
140a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(state_ != DESTROYED);
141a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    parameter_or_next_free_.parameter = parameter;
142a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
143a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  void* parameter() {
144a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(state_ != DESTROYED);
145a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return parameter_or_next_free_.parameter;
146a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
147a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
148a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Returns the callback for this weak handle.
149a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  WeakReferenceCallback callback() { return callback_; }
150a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
151a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  bool PostGarbageCollectionProcessing() {
152a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (state_ != Node::PENDING) return false;
153a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    LOG(HandleEvent("GlobalHandle::Processing", handle().location()));
154a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    void* par = parameter();
155a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    state_ = NEAR_DEATH;
156a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    set_parameter(NULL);
157a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // The callback function is resolved as late as possible to preserve old
158a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // behavior.
159a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    WeakReferenceCallback func = callback();
160a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (func == NULL) return false;
161a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
162a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    v8::Persistent<v8::Object> object = ToApi<v8::Object>(handle());
163a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    {
164a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Forbid reuse of destroyed nodes as they might be already deallocated.
165a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // It's fine though to reuse nodes that were destroyed in weak callback
166a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // as those cannot be deallocated until we are back from the callback.
167a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      set_first_free(NULL);
168d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      if (first_deallocated()) {
169d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block        first_deallocated()->set_next(head());
170d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      }
171a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Leaving V8.
172a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      VMState state(EXTERNAL);
173a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      func(object, par);
174a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
175a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return true;
176a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
177a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
178a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Place the handle address first to avoid offset computation.
179a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Object* object_;  // Storage for object pointer.
180a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
181a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Transition diagram:
182a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // NORMAL <-> WEAK -> PENDING -> NEAR_DEATH -> { NORMAL, WEAK, DESTROYED }
183a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  enum State {
184a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    NORMAL,      // Normal global handle.
185a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    WEAK,        // Flagged as weak but not yet finalized.
186a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    PENDING,     // Has been recognized as only reachable by weak handles.
187a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    NEAR_DEATH,  // Callback has informed the handle is near death.
188a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    DESTROYED
189a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  };
190a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  State state_;
191a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
192a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block private:
193a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Handle specific callback.
194a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  WeakReferenceCallback callback_;
195a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Provided data for callback.  In DESTROYED state, this is used for
196a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // the free list link.
197a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  union {
198a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    void* parameter;
199a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Node* next_free;
200a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } parameter_or_next_free_;
201a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
202a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Linkage for the list.
203a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Node* next_;
204a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
205a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public:
206a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  TRACK_MEMORY("GlobalHandles::Node")
207a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block};
208a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
209a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
210d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockclass GlobalHandles::Pool BASE_EMBEDDED {
211d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  public:
212d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    Pool() {
213d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      current_ = new Chunk();
214d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      current_->previous = NULL;
215d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      next_ = current_->nodes;
216d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      limit_ = current_->nodes + kNodesPerChunk;
217d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    }
218d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
219d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    Node* Allocate() {
220d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      if (next_ < limit_) {
221d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block        return next_++;
222d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      }
223d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      return SlowAllocate();
224d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    }
225d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
226d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    void Release() {
227d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      Chunk* current = current_;
228d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      ASSERT(current != NULL);  // At least a single block must by allocated
229d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      do {
230d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block        Chunk* previous = current->previous;
231d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block        delete current;
232d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block        current = previous;
233d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      } while (current != NULL);
234d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      current_ = NULL;
235d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      next_ = limit_ = NULL;
236d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    }
237d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
238d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  private:
239d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    static const int kNodesPerChunk = (1 << 12) - 1;
240d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    struct Chunk : public Malloced {
241d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      Chunk* previous;
242d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      Node nodes[kNodesPerChunk];
243d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    };
244d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
245d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    Node* SlowAllocate() {
246d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      Chunk* chunk = new Chunk();
247d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      chunk->previous = current_;
248d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      current_ = chunk;
249d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
250d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      Node* new_nodes = current_->nodes;
251d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      next_ = new_nodes + 1;
252d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      limit_ = new_nodes + kNodesPerChunk;
253d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      return new_nodes;
254d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    }
255d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
256d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    Chunk* current_;
257d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    Node* next_;
258d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    Node* limit_;
259d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block};
260d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
261d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
262d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockstatic GlobalHandles::Pool pool_;
263d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
264d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
265a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockHandle<Object> GlobalHandles::Create(Object* value) {
266a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Counters::global_handles.Increment();
267a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Node* result;
268d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  if (first_free()) {
269a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Take the first node in the free list.
270a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    result = first_free();
271a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    set_first_free(result->next_free());
272d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  } else if (first_deallocated()) {
273d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    // Next try deallocated list
274d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    result = first_deallocated();
275d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    set_first_deallocated(result->next_free());
276d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    ASSERT(result->next() == head());
277d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    set_head(result);
278d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  } else {
279d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    // Allocate a new node.
280d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    result = pool_.Allocate();
281d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    result->set_next(head());
282d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    set_head(result);
283a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
284d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  result->Initialize(value);
285a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return result->handle();
286a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
287a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
288a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
289a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid GlobalHandles::Destroy(Object** location) {
290a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Counters::global_handles.Decrement();
291a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (location == NULL) return;
292a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Node* node = Node::FromLocation(location);
293a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  node->Destroy();
294a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Link the destroyed.
295a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  node->set_next_free(first_free());
296a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  set_first_free(node);
297a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
298a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
299a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
300a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid GlobalHandles::MakeWeak(Object** location, void* parameter,
301a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                             WeakReferenceCallback callback) {
302a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(callback != NULL);
303a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Node::FromLocation(location)->MakeWeak(parameter, callback);
304a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
305a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
306a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
307a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid GlobalHandles::ClearWeakness(Object** location) {
308a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Node::FromLocation(location)->ClearWeakness();
309a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
310a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
311a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
312a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockbool GlobalHandles::IsNearDeath(Object** location) {
313a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return Node::FromLocation(location)->IsNearDeath();
314a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
315a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
316a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
317a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockbool GlobalHandles::IsWeak(Object** location) {
318a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return Node::FromLocation(location)->IsWeak();
319a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
320a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
321a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
322a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid GlobalHandles::IterateWeakRoots(ObjectVisitor* v) {
323a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Traversal of GC roots in the global handle list that are marked as
324a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // WEAK or PENDING.
325a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  for (Node* current = head_; current != NULL; current = current->next()) {
326a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (current->state_ == Node::WEAK
327a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      || current->state_ == Node::PENDING
328a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      || current->state_ == Node::NEAR_DEATH) {
329a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      v->VisitPointer(&current->object_);
330a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
331a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
332a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
333a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
334a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3353ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Blockvoid GlobalHandles::IterateWeakRoots(WeakReferenceGuest f,
3363ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block                                     WeakReferenceCallback callback) {
3373ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  for (Node* current = head_; current != NULL; current = current->next()) {
3383ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    if (current->IsWeak() && current->callback() == callback) {
3393ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      f(current->object_, current->parameter());
3403ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    }
3413ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  }
3423ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block}
3433ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
3443ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
345a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid GlobalHandles::IdentifyWeakHandles(WeakSlotCallback f) {
346a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  for (Node* current = head_; current != NULL; current = current->next()) {
347a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (current->state_ == Node::WEAK) {
348a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (f(&current->object_)) {
349a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        current->state_ = Node::PENDING;
350a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        LOG(HandleEvent("GlobalHandle::Pending", current->handle().location()));
351a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
352a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
353a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
354a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
355a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
356a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
357a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockint post_gc_processing_count = 0;
358a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
359a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid GlobalHandles::PostGarbageCollectionProcessing() {
360a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Process weak global handle callbacks. This must be done after the
361a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // GC is completely done, because the callbacks may invoke arbitrary
362a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // API functions.
363d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // At the same time deallocate all DESTROYED nodes.
364a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(Heap::gc_state() == Heap::NOT_IN_GC);
365a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  const int initial_post_gc_processing_count = ++post_gc_processing_count;
366a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Node** p = &head_;
367a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  while (*p != NULL) {
368a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if ((*p)->PostGarbageCollectionProcessing()) {
369a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (initial_post_gc_processing_count != post_gc_processing_count) {
370a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // Weak callback triggered another GC and another round of
371a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // PostGarbageCollection processing.  The current node might
372a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // have been deleted in that round, so we need to bail out (or
373a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // restart the processing).
374a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        break;
375a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
376a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
377a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if ((*p)->state_ == Node::DESTROYED) {
378a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Delete the link.
379a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Node* node = *p;
380a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      *p = node->next();  // Update the link.
381d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      if (first_deallocated()) {
382d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block        first_deallocated()->set_next(node);
383d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      }
384d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      node->set_next_free(first_deallocated());
385d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      set_first_deallocated(node);
386a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else {
387a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      p = (*p)->next_addr();
388a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
389a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
390a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  set_first_free(NULL);
391d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  if (first_deallocated()) {
392d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    first_deallocated()->set_next(head());
393d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  }
394a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
395a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
396a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
397d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid GlobalHandles::IterateStrongRoots(ObjectVisitor* v) {
398d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // Traversal of global handles marked as NORMAL.
399a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  for (Node* current = head_; current != NULL; current = current->next()) {
400a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (current->state_ == Node::NORMAL) {
401a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      v->VisitPointer(&current->object_);
402a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
403a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
404a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
405a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
406d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
407d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid GlobalHandles::IterateAllRoots(ObjectVisitor* v) {
408d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  for (Node* current = head_; current != NULL; current = current->next()) {
409d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    if (current->state_ != Node::DESTROYED) {
410d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      v->VisitPointer(&current->object_);
411d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    }
412a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
413d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
414d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
415d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
416d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid GlobalHandles::TearDown() {
417d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // Reset all the lists.
418a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  set_head(NULL);
419a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  set_first_free(NULL);
420d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  set_first_deallocated(NULL);
421d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  pool_.Release();
422a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
423a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
424a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
425a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockint GlobalHandles::number_of_weak_handles_ = 0;
426a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockint GlobalHandles::number_of_global_object_weak_handles_ = 0;
427a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
428a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockGlobalHandles::Node* GlobalHandles::head_ = NULL;
429a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockGlobalHandles::Node* GlobalHandles::first_free_ = NULL;
430d0582a6c46733687d045e4188a1bcd0123c758a1Steve BlockGlobalHandles::Node* GlobalHandles::first_deallocated_ = NULL;
431d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
432d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid GlobalHandles::RecordStats(HeapStats* stats) {
433d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  *stats->global_handle_count = 0;
434d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  *stats->weak_global_handle_count = 0;
435d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  *stats->pending_global_handle_count = 0;
436d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  *stats->near_death_global_handle_count = 0;
437d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  *stats->destroyed_global_handle_count = 0;
438d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  for (Node* current = head_; current != NULL; current = current->next()) {
439d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    *stats->global_handle_count += 1;
440d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    if (current->state_ == Node::WEAK) {
441d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      *stats->weak_global_handle_count += 1;
442d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    } else if (current->state_ == Node::PENDING) {
443d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      *stats->pending_global_handle_count += 1;
444d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    } else if (current->state_ == Node::NEAR_DEATH) {
445d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      *stats->near_death_global_handle_count += 1;
446d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    } else if (current->state_ == Node::DESTROYED) {
447d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      *stats->destroyed_global_handle_count += 1;
448d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    }
449d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  }
450d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
451a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
452a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef DEBUG
453a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
454a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid GlobalHandles::PrintStats() {
455a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int total = 0;
456a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int weak = 0;
457a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int pending = 0;
458a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int near_death = 0;
459a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int destroyed = 0;
460a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
461a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  for (Node* current = head_; current != NULL; current = current->next()) {
462a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    total++;
463a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (current->state_ == Node::WEAK) weak++;
464a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (current->state_ == Node::PENDING) pending++;
465a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (current->state_ == Node::NEAR_DEATH) near_death++;
466a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (current->state_ == Node::DESTROYED) destroyed++;
467a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
468a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
469a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  PrintF("Global Handle Statistics:\n");
470a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  PrintF("  allocated memory = %dB\n", sizeof(Node) * total);
471a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  PrintF("  # weak       = %d\n", weak);
472a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  PrintF("  # pending    = %d\n", pending);
473a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  PrintF("  # near_death = %d\n", near_death);
474a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  PrintF("  # destroyed  = %d\n", destroyed);
475a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  PrintF("  # total      = %d\n", total);
476a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
477a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
478a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid GlobalHandles::Print() {
479a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  PrintF("Global handles:\n");
480a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  for (Node* current = head_; current != NULL; current = current->next()) {
481a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    PrintF("  handle %p to %p (weak=%d)\n", current->handle().location(),
482a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block           *current->handle(), current->state_ == Node::WEAK);
483a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
484a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
485a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
486a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif
487a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
488a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockList<ObjectGroup*>* GlobalHandles::ObjectGroups() {
489a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Lazily initialize the list to avoid startup time static constructors.
490a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  static List<ObjectGroup*> groups(4);
491a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return &groups;
492a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
493a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
494a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid GlobalHandles::AddGroup(Object*** handles, size_t length) {
495a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ObjectGroup* new_entry = new ObjectGroup(length);
496a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  for (size_t i = 0; i < length; ++i)
497a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    new_entry->objects_.Add(handles[i]);
498a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ObjectGroups()->Add(new_entry);
499a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
500a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
501a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
502a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid GlobalHandles::RemoveObjectGroups() {
503a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  List<ObjectGroup*>* object_groups = ObjectGroups();
504a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  for (int i = 0; i< object_groups->length(); i++) {
505a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    delete object_groups->at(i);
506a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
507a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  object_groups->Clear();
508a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
509a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
510a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
511a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} }  // namespace v8::internal
512