blob: c4e8f131afa8e1d1c590c2f8643f662449ac1e7f [file] [log] [blame]
Steve Blocka7e24c12009-10-30 11:49:00 +00001// Copyright 2009 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
30#include "api.h"
31#include "global-handles.h"
32
Ben Murdochb0fe1622011-05-05 13:52:32 +010033#include "vm-state-inl.h"
34
Steve Blocka7e24c12009-10-30 11:49:00 +000035namespace v8 {
36namespace internal {
37
Steve Block44f0eee2011-05-26 01:26:41 +010038
39ObjectGroup::~ObjectGroup() {
40 if (info_ != NULL) info_->Dispose();
41}
42
43
Steve Blocka7e24c12009-10-30 11:49:00 +000044class GlobalHandles::Node : public Malloced {
45 public:
46
47 void Initialize(Object* object) {
48 // Set the initial value of the handle.
49 object_ = object;
Steve Block44f0eee2011-05-26 01:26:41 +010050 class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
Steve Blocka7e24c12009-10-30 11:49:00 +000051 state_ = NORMAL;
52 parameter_or_next_free_.parameter = NULL;
53 callback_ = NULL;
54 }
55
Steve Blockd0582a62009-12-15 09:54:21 +000056 Node() {
57 state_ = DESTROYED;
58 }
59
Steve Blocka7e24c12009-10-30 11:49:00 +000060 explicit Node(Object* object) {
61 Initialize(object);
62 // Initialize link structure.
63 next_ = NULL;
64 }
65
66 ~Node() {
Steve Block44f0eee2011-05-26 01:26:41 +010067 if (state_ != DESTROYED) Destroy(Isolate::Current()->global_handles());
Steve Blocka7e24c12009-10-30 11:49:00 +000068#ifdef DEBUG
69 // Zap the values for eager trapping.
70 object_ = NULL;
71 next_ = NULL;
72 parameter_or_next_free_.next_free = NULL;
73#endif
74 }
75
Steve Block44f0eee2011-05-26 01:26:41 +010076 void Destroy(GlobalHandles* global_handles) {
Steve Blocka7e24c12009-10-30 11:49:00 +000077 if (state_ == WEAK || IsNearDeath()) {
Steve Block44f0eee2011-05-26 01:26:41 +010078 global_handles->number_of_weak_handles_--;
Steve Blocka7e24c12009-10-30 11:49:00 +000079 if (object_->IsJSGlobalObject()) {
Steve Block44f0eee2011-05-26 01:26:41 +010080 global_handles->number_of_global_object_weak_handles_--;
Steve Blocka7e24c12009-10-30 11:49:00 +000081 }
82 }
83 state_ = DESTROYED;
84 }
85
86 // Accessors for next_.
87 Node* next() { return next_; }
88 void set_next(Node* value) { next_ = value; }
89 Node** next_addr() { return &next_; }
90
91 // Accessors for next free node in the free list.
92 Node* next_free() {
93 ASSERT(state_ == DESTROYED);
94 return parameter_or_next_free_.next_free;
95 }
96 void set_next_free(Node* value) {
97 ASSERT(state_ == DESTROYED);
98 parameter_or_next_free_.next_free = value;
99 }
100
101 // Returns a link from the handle.
102 static Node* FromLocation(Object** location) {
103 ASSERT(OFFSET_OF(Node, object_) == 0);
104 return reinterpret_cast<Node*>(location);
105 }
106
107 // Returns the handle.
108 Handle<Object> handle() { return Handle<Object>(&object_); }
109
110 // Make this handle weak.
Steve Block44f0eee2011-05-26 01:26:41 +0100111 void MakeWeak(GlobalHandles* global_handles, void* parameter,
112 WeakReferenceCallback callback) {
113 LOG(global_handles->isolate(),
114 HandleEvent("GlobalHandle::MakeWeak", handle().location()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000115 ASSERT(state_ != DESTROYED);
116 if (state_ != WEAK && !IsNearDeath()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100117 global_handles->number_of_weak_handles_++;
Steve Blocka7e24c12009-10-30 11:49:00 +0000118 if (object_->IsJSGlobalObject()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100119 global_handles->number_of_global_object_weak_handles_++;
Steve Blocka7e24c12009-10-30 11:49:00 +0000120 }
121 }
122 state_ = WEAK;
123 set_parameter(parameter);
124 callback_ = callback;
125 }
126
Steve Block44f0eee2011-05-26 01:26:41 +0100127 void ClearWeakness(GlobalHandles* global_handles) {
128 LOG(global_handles->isolate(),
129 HandleEvent("GlobalHandle::ClearWeakness", handle().location()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000130 ASSERT(state_ != DESTROYED);
131 if (state_ == WEAK || IsNearDeath()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100132 global_handles->number_of_weak_handles_--;
Steve Blocka7e24c12009-10-30 11:49:00 +0000133 if (object_->IsJSGlobalObject()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100134 global_handles->number_of_global_object_weak_handles_--;
Steve Blocka7e24c12009-10-30 11:49:00 +0000135 }
136 }
137 state_ = NORMAL;
138 set_parameter(NULL);
139 }
140
141 bool IsNearDeath() {
142 // Check for PENDING to ensure correct answer when processing callbacks.
143 return state_ == PENDING || state_ == NEAR_DEATH;
144 }
145
146 bool IsWeak() {
147 return state_ == WEAK;
148 }
149
Steve Block44f0eee2011-05-26 01:26:41 +0100150 bool CanBeRetainer() {
151 return state_ != DESTROYED && state_ != NEAR_DEATH;
152 }
153
154 void SetWrapperClassId(uint16_t class_id) {
155 class_id_ = class_id;
156 }
157
Steve Blocka7e24c12009-10-30 11:49:00 +0000158 // Returns the id for this weak handle.
159 void set_parameter(void* parameter) {
160 ASSERT(state_ != DESTROYED);
161 parameter_or_next_free_.parameter = parameter;
162 }
163 void* parameter() {
164 ASSERT(state_ != DESTROYED);
165 return parameter_or_next_free_.parameter;
166 }
167
168 // Returns the callback for this weak handle.
169 WeakReferenceCallback callback() { return callback_; }
170
Steve Block44f0eee2011-05-26 01:26:41 +0100171 bool PostGarbageCollectionProcessing(Isolate* isolate,
172 GlobalHandles* global_handles) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000173 if (state_ != Node::PENDING) return false;
Steve Block44f0eee2011-05-26 01:26:41 +0100174 LOG(isolate, HandleEvent("GlobalHandle::Processing", handle().location()));
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100175 WeakReferenceCallback func = callback();
176 if (func == NULL) {
Steve Block44f0eee2011-05-26 01:26:41 +0100177 Destroy(global_handles);
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100178 return false;
179 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000180 void* par = parameter();
181 state_ = NEAR_DEATH;
182 set_parameter(NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +0000183
184 v8::Persistent<v8::Object> object = ToApi<v8::Object>(handle());
185 {
186 // Forbid reuse of destroyed nodes as they might be already deallocated.
187 // It's fine though to reuse nodes that were destroyed in weak callback
188 // as those cannot be deallocated until we are back from the callback.
Steve Block44f0eee2011-05-26 01:26:41 +0100189 global_handles->set_first_free(NULL);
190 if (global_handles->first_deallocated()) {
191 global_handles->first_deallocated()->set_next(global_handles->head());
Steve Blockd0582a62009-12-15 09:54:21 +0000192 }
Leon Clarkee46be812010-01-19 14:06:41 +0000193 // Check that we are not passing a finalized external string to
194 // the callback.
195 ASSERT(!object_->IsExternalAsciiString() ||
196 ExternalAsciiString::cast(object_)->resource() != NULL);
197 ASSERT(!object_->IsExternalTwoByteString() ||
198 ExternalTwoByteString::cast(object_)->resource() != NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +0000199 // Leaving V8.
Steve Block44f0eee2011-05-26 01:26:41 +0100200 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +0000201 func(object, par);
202 }
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100203 // Absense of explicit cleanup or revival of weak handle
204 // in most of the cases would lead to memory leak.
205 ASSERT(state_ != NEAR_DEATH);
Steve Blocka7e24c12009-10-30 11:49:00 +0000206 return true;
207 }
208
209 // Place the handle address first to avoid offset computation.
210 Object* object_; // Storage for object pointer.
211
Steve Block44f0eee2011-05-26 01:26:41 +0100212 uint16_t class_id_;
213
Steve Blocka7e24c12009-10-30 11:49:00 +0000214 // Transition diagram:
215 // NORMAL <-> WEAK -> PENDING -> NEAR_DEATH -> { NORMAL, WEAK, DESTROYED }
216 enum State {
217 NORMAL, // Normal global handle.
218 WEAK, // Flagged as weak but not yet finalized.
219 PENDING, // Has been recognized as only reachable by weak handles.
220 NEAR_DEATH, // Callback has informed the handle is near death.
221 DESTROYED
222 };
Steve Block44f0eee2011-05-26 01:26:41 +0100223 State state_ : 4; // Need one more bit for MSVC as it treats enums as signed.
Steve Blocka7e24c12009-10-30 11:49:00 +0000224
225 private:
226 // Handle specific callback.
227 WeakReferenceCallback callback_;
228 // Provided data for callback. In DESTROYED state, this is used for
229 // the free list link.
230 union {
231 void* parameter;
232 Node* next_free;
233 } parameter_or_next_free_;
234
235 // Linkage for the list.
236 Node* next_;
237
238 public:
239 TRACK_MEMORY("GlobalHandles::Node")
240};
241
242
Steve Block44f0eee2011-05-26 01:26:41 +0100243class GlobalHandles::Pool {
Steve Blockd0582a62009-12-15 09:54:21 +0000244 public:
245 Pool() {
246 current_ = new Chunk();
247 current_->previous = NULL;
248 next_ = current_->nodes;
249 limit_ = current_->nodes + kNodesPerChunk;
250 }
251
Ben Murdochbb769b22010-08-11 14:56:33 +0100252 ~Pool() {
253 if (current_ != NULL) {
254 Release();
255 }
256 }
257
Steve Blockd0582a62009-12-15 09:54:21 +0000258 Node* Allocate() {
259 if (next_ < limit_) {
260 return next_++;
261 }
262 return SlowAllocate();
263 }
264
265 void Release() {
266 Chunk* current = current_;
267 ASSERT(current != NULL); // At least a single block must by allocated
268 do {
269 Chunk* previous = current->previous;
270 delete current;
271 current = previous;
272 } while (current != NULL);
273 current_ = NULL;
274 next_ = limit_ = NULL;
275 }
276
277 private:
278 static const int kNodesPerChunk = (1 << 12) - 1;
279 struct Chunk : public Malloced {
280 Chunk* previous;
281 Node nodes[kNodesPerChunk];
282 };
283
284 Node* SlowAllocate() {
285 Chunk* chunk = new Chunk();
286 chunk->previous = current_;
287 current_ = chunk;
288
289 Node* new_nodes = current_->nodes;
290 next_ = new_nodes + 1;
291 limit_ = new_nodes + kNodesPerChunk;
292 return new_nodes;
293 }
294
295 Chunk* current_;
296 Node* next_;
297 Node* limit_;
298};
299
300
Steve Block44f0eee2011-05-26 01:26:41 +0100301GlobalHandles::GlobalHandles(Isolate* isolate)
302 : isolate_(isolate),
303 number_of_weak_handles_(0),
304 number_of_global_object_weak_handles_(0),
305 head_(NULL),
306 first_free_(NULL),
307 first_deallocated_(NULL),
308 pool_(new Pool()),
309 post_gc_processing_count_(0),
310 object_groups_(4) {
311}
312
313
314GlobalHandles::~GlobalHandles() {
315 delete pool_;
316 pool_ = 0;
317}
Steve Blockd0582a62009-12-15 09:54:21 +0000318
319
Steve Blocka7e24c12009-10-30 11:49:00 +0000320Handle<Object> GlobalHandles::Create(Object* value) {
Steve Block44f0eee2011-05-26 01:26:41 +0100321 isolate_->counters()->global_handles()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +0000322 Node* result;
Steve Blockd0582a62009-12-15 09:54:21 +0000323 if (first_free()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000324 // Take the first node in the free list.
325 result = first_free();
326 set_first_free(result->next_free());
Steve Blockd0582a62009-12-15 09:54:21 +0000327 } else if (first_deallocated()) {
328 // Next try deallocated list
329 result = first_deallocated();
330 set_first_deallocated(result->next_free());
331 ASSERT(result->next() == head());
332 set_head(result);
333 } else {
334 // Allocate a new node.
Steve Block44f0eee2011-05-26 01:26:41 +0100335 result = pool_->Allocate();
Steve Blockd0582a62009-12-15 09:54:21 +0000336 result->set_next(head());
337 set_head(result);
Steve Blocka7e24c12009-10-30 11:49:00 +0000338 }
Steve Blockd0582a62009-12-15 09:54:21 +0000339 result->Initialize(value);
Steve Blocka7e24c12009-10-30 11:49:00 +0000340 return result->handle();
341}
342
343
344void GlobalHandles::Destroy(Object** location) {
Steve Block44f0eee2011-05-26 01:26:41 +0100345 isolate_->counters()->global_handles()->Decrement();
Steve Blocka7e24c12009-10-30 11:49:00 +0000346 if (location == NULL) return;
347 Node* node = Node::FromLocation(location);
Steve Block44f0eee2011-05-26 01:26:41 +0100348 node->Destroy(this);
Steve Blocka7e24c12009-10-30 11:49:00 +0000349 // Link the destroyed.
350 node->set_next_free(first_free());
351 set_first_free(node);
352}
353
354
355void GlobalHandles::MakeWeak(Object** location, void* parameter,
356 WeakReferenceCallback callback) {
357 ASSERT(callback != NULL);
Steve Block44f0eee2011-05-26 01:26:41 +0100358 Node::FromLocation(location)->MakeWeak(this, parameter, callback);
Steve Blocka7e24c12009-10-30 11:49:00 +0000359}
360
361
362void GlobalHandles::ClearWeakness(Object** location) {
Steve Block44f0eee2011-05-26 01:26:41 +0100363 Node::FromLocation(location)->ClearWeakness(this);
Steve Blocka7e24c12009-10-30 11:49:00 +0000364}
365
366
367bool GlobalHandles::IsNearDeath(Object** location) {
368 return Node::FromLocation(location)->IsNearDeath();
369}
370
371
372bool GlobalHandles::IsWeak(Object** location) {
373 return Node::FromLocation(location)->IsWeak();
374}
375
376
Steve Block44f0eee2011-05-26 01:26:41 +0100377void GlobalHandles::SetWrapperClassId(Object** location, uint16_t class_id) {
378 Node::FromLocation(location)->SetWrapperClassId(class_id);
379}
380
381
Steve Blocka7e24c12009-10-30 11:49:00 +0000382void GlobalHandles::IterateWeakRoots(ObjectVisitor* v) {
383 // Traversal of GC roots in the global handle list that are marked as
384 // WEAK or PENDING.
385 for (Node* current = head_; current != NULL; current = current->next()) {
386 if (current->state_ == Node::WEAK
387 || current->state_ == Node::PENDING
388 || current->state_ == Node::NEAR_DEATH) {
389 v->VisitPointer(&current->object_);
390 }
391 }
392}
393
394
Steve Block3ce2e202009-11-05 08:53:23 +0000395void GlobalHandles::IterateWeakRoots(WeakReferenceGuest f,
396 WeakReferenceCallback callback) {
397 for (Node* current = head_; current != NULL; current = current->next()) {
398 if (current->IsWeak() && current->callback() == callback) {
399 f(current->object_, current->parameter());
400 }
401 }
402}
403
404
Steve Blocka7e24c12009-10-30 11:49:00 +0000405void GlobalHandles::IdentifyWeakHandles(WeakSlotCallback f) {
406 for (Node* current = head_; current != NULL; current = current->next()) {
407 if (current->state_ == Node::WEAK) {
408 if (f(&current->object_)) {
409 current->state_ = Node::PENDING;
Steve Block44f0eee2011-05-26 01:26:41 +0100410 LOG(isolate_,
411 HandleEvent("GlobalHandle::Pending", current->handle().location()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000412 }
413 }
414 }
415}
416
417
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800418bool GlobalHandles::PostGarbageCollectionProcessing() {
Steve Blocka7e24c12009-10-30 11:49:00 +0000419 // Process weak global handle callbacks. This must be done after the
420 // GC is completely done, because the callbacks may invoke arbitrary
421 // API functions.
Steve Blockd0582a62009-12-15 09:54:21 +0000422 // At the same time deallocate all DESTROYED nodes.
Steve Block44f0eee2011-05-26 01:26:41 +0100423 ASSERT(isolate_->heap()->gc_state() == Heap::NOT_IN_GC);
424 const int initial_post_gc_processing_count = ++post_gc_processing_count_;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800425 bool next_gc_likely_to_collect_more = false;
Steve Blocka7e24c12009-10-30 11:49:00 +0000426 Node** p = &head_;
427 while (*p != NULL) {
Steve Block44f0eee2011-05-26 01:26:41 +0100428 if ((*p)->PostGarbageCollectionProcessing(isolate_, this)) {
429 if (initial_post_gc_processing_count != post_gc_processing_count_) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000430 // Weak callback triggered another GC and another round of
431 // PostGarbageCollection processing. The current node might
432 // have been deleted in that round, so we need to bail out (or
433 // restart the processing).
434 break;
435 }
436 }
437 if ((*p)->state_ == Node::DESTROYED) {
438 // Delete the link.
439 Node* node = *p;
440 *p = node->next(); // Update the link.
Steve Blockd0582a62009-12-15 09:54:21 +0000441 if (first_deallocated()) {
442 first_deallocated()->set_next(node);
443 }
444 node->set_next_free(first_deallocated());
445 set_first_deallocated(node);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800446 next_gc_likely_to_collect_more = true;
Steve Blocka7e24c12009-10-30 11:49:00 +0000447 } else {
448 p = (*p)->next_addr();
449 }
450 }
451 set_first_free(NULL);
Steve Blockd0582a62009-12-15 09:54:21 +0000452 if (first_deallocated()) {
453 first_deallocated()->set_next(head());
454 }
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800455
456 return next_gc_likely_to_collect_more;
Steve Blocka7e24c12009-10-30 11:49:00 +0000457}
458
459
Steve Blockd0582a62009-12-15 09:54:21 +0000460void GlobalHandles::IterateStrongRoots(ObjectVisitor* v) {
461 // Traversal of global handles marked as NORMAL.
Steve Blocka7e24c12009-10-30 11:49:00 +0000462 for (Node* current = head_; current != NULL; current = current->next()) {
463 if (current->state_ == Node::NORMAL) {
464 v->VisitPointer(&current->object_);
465 }
466 }
467}
468
Steve Blockd0582a62009-12-15 09:54:21 +0000469
470void GlobalHandles::IterateAllRoots(ObjectVisitor* v) {
471 for (Node* current = head_; current != NULL; current = current->next()) {
472 if (current->state_ != Node::DESTROYED) {
473 v->VisitPointer(&current->object_);
474 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000475 }
Steve Blockd0582a62009-12-15 09:54:21 +0000476}
477
478
Steve Block44f0eee2011-05-26 01:26:41 +0100479void GlobalHandles::IterateAllRootsWithClassIds(ObjectVisitor* v) {
480 for (Node* current = head_; current != NULL; current = current->next()) {
481 if (current->class_id_ != v8::HeapProfiler::kPersistentHandleNoClassId &&
482 current->CanBeRetainer()) {
483 v->VisitEmbedderReference(&current->object_, current->class_id_);
484 }
485 }
486}
487
488
Steve Blockd0582a62009-12-15 09:54:21 +0000489void GlobalHandles::TearDown() {
490 // Reset all the lists.
Steve Blocka7e24c12009-10-30 11:49:00 +0000491 set_head(NULL);
492 set_first_free(NULL);
Steve Blockd0582a62009-12-15 09:54:21 +0000493 set_first_deallocated(NULL);
Steve Block44f0eee2011-05-26 01:26:41 +0100494 pool_->Release();
Steve Blocka7e24c12009-10-30 11:49:00 +0000495}
496
497
Steve Blockd0582a62009-12-15 09:54:21 +0000498void GlobalHandles::RecordStats(HeapStats* stats) {
499 *stats->global_handle_count = 0;
500 *stats->weak_global_handle_count = 0;
501 *stats->pending_global_handle_count = 0;
502 *stats->near_death_global_handle_count = 0;
503 *stats->destroyed_global_handle_count = 0;
504 for (Node* current = head_; current != NULL; current = current->next()) {
505 *stats->global_handle_count += 1;
506 if (current->state_ == Node::WEAK) {
507 *stats->weak_global_handle_count += 1;
508 } else if (current->state_ == Node::PENDING) {
509 *stats->pending_global_handle_count += 1;
510 } else if (current->state_ == Node::NEAR_DEATH) {
511 *stats->near_death_global_handle_count += 1;
512 } else if (current->state_ == Node::DESTROYED) {
513 *stats->destroyed_global_handle_count += 1;
514 }
515 }
516}
Steve Blocka7e24c12009-10-30 11:49:00 +0000517
518#ifdef DEBUG
519
520void GlobalHandles::PrintStats() {
521 int total = 0;
522 int weak = 0;
523 int pending = 0;
524 int near_death = 0;
525 int destroyed = 0;
526
527 for (Node* current = head_; current != NULL; current = current->next()) {
528 total++;
529 if (current->state_ == Node::WEAK) weak++;
530 if (current->state_ == Node::PENDING) pending++;
531 if (current->state_ == Node::NEAR_DEATH) near_death++;
532 if (current->state_ == Node::DESTROYED) destroyed++;
533 }
534
535 PrintF("Global Handle Statistics:\n");
Ben Murdochf87a2032010-10-22 12:50:53 +0100536 PrintF(" allocated memory = %" V8_PTR_PREFIX "dB\n", sizeof(Node) * total);
Steve Blocka7e24c12009-10-30 11:49:00 +0000537 PrintF(" # weak = %d\n", weak);
538 PrintF(" # pending = %d\n", pending);
539 PrintF(" # near_death = %d\n", near_death);
540 PrintF(" # destroyed = %d\n", destroyed);
541 PrintF(" # total = %d\n", total);
542}
543
544void GlobalHandles::Print() {
545 PrintF("Global handles:\n");
546 for (Node* current = head_; current != NULL; current = current->next()) {
Ben Murdochf87a2032010-10-22 12:50:53 +0100547 PrintF(" handle %p to %p (weak=%d)\n",
548 reinterpret_cast<void*>(current->handle().location()),
549 reinterpret_cast<void*>(*current->handle()),
550 current->state_ == Node::WEAK);
Steve Blocka7e24c12009-10-30 11:49:00 +0000551 }
552}
553
554#endif
555
Steve Block44f0eee2011-05-26 01:26:41 +0100556
557
558void GlobalHandles::AddObjectGroup(Object*** handles,
559 size_t length,
560 v8::RetainedObjectInfo* info) {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100561 if (length == 0) {
562 if (info != NULL) info->Dispose();
563 return;
Steve Block44f0eee2011-05-26 01:26:41 +0100564 }
Ben Murdoch8b112d22011-06-08 16:22:53 +0100565 object_groups_.Add(ObjectGroup::New(handles, length, info));
Steve Blocka7e24c12009-10-30 11:49:00 +0000566}
567
Steve Block44f0eee2011-05-26 01:26:41 +0100568
Ben Murdoch8b112d22011-06-08 16:22:53 +0100569void GlobalHandles::AddImplicitReferences(HeapObject** parent,
Steve Block44f0eee2011-05-26 01:26:41 +0100570 Object*** children,
571 size_t length) {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100572 if (length == 0) return;
573 implicit_ref_groups_.Add(ImplicitRefGroup::New(parent, children, length));
Steve Blocka7e24c12009-10-30 11:49:00 +0000574}
575
576
577void GlobalHandles::RemoveObjectGroups() {
Steve Block44f0eee2011-05-26 01:26:41 +0100578 for (int i = 0; i < object_groups_.length(); i++) {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100579 object_groups_.at(i)->Dispose();
Steve Blocka7e24c12009-10-30 11:49:00 +0000580 }
Steve Block44f0eee2011-05-26 01:26:41 +0100581 object_groups_.Clear();
Steve Blocka7e24c12009-10-30 11:49:00 +0000582}
583
Steve Block44f0eee2011-05-26 01:26:41 +0100584
585void GlobalHandles::RemoveImplicitRefGroups() {
586 for (int i = 0; i < implicit_ref_groups_.length(); i++) {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100587 implicit_ref_groups_.at(i)->Dispose();
Steve Block44f0eee2011-05-26 01:26:41 +0100588 }
589 implicit_ref_groups_.Clear();
590}
591
592
Steve Blocka7e24c12009-10-30 11:49:00 +0000593} } // namespace v8::internal