blob: e4bbc9582e6d33e755e67a352c1d9679241ad394 [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;
Ben Murdoch257744e2011-11-30 15:57:28 +000051 independent_ = false;
Steve Blocka7e24c12009-10-30 11:49:00 +000052 state_ = NORMAL;
53 parameter_or_next_free_.parameter = NULL;
54 callback_ = NULL;
55 }
56
Steve Blockd0582a62009-12-15 09:54:21 +000057 Node() {
58 state_ = DESTROYED;
59 }
60
Steve Blocka7e24c12009-10-30 11:49:00 +000061 explicit Node(Object* object) {
62 Initialize(object);
63 // Initialize link structure.
64 next_ = NULL;
65 }
66
67 ~Node() {
Steve Block44f0eee2011-05-26 01:26:41 +010068 if (state_ != DESTROYED) Destroy(Isolate::Current()->global_handles());
Steve Blocka7e24c12009-10-30 11:49:00 +000069#ifdef DEBUG
70 // Zap the values for eager trapping.
71 object_ = NULL;
72 next_ = NULL;
73 parameter_or_next_free_.next_free = NULL;
74#endif
75 }
76
Steve Block44f0eee2011-05-26 01:26:41 +010077 void Destroy(GlobalHandles* global_handles) {
Steve Blocka7e24c12009-10-30 11:49:00 +000078 if (state_ == WEAK || IsNearDeath()) {
Steve Block44f0eee2011-05-26 01:26:41 +010079 global_handles->number_of_weak_handles_--;
Steve Blocka7e24c12009-10-30 11:49:00 +000080 if (object_->IsJSGlobalObject()) {
Steve Block44f0eee2011-05-26 01:26:41 +010081 global_handles->number_of_global_object_weak_handles_--;
Steve Blocka7e24c12009-10-30 11:49:00 +000082 }
83 }
84 state_ = DESTROYED;
85 }
86
87 // Accessors for next_.
88 Node* next() { return next_; }
89 void set_next(Node* value) { next_ = value; }
90 Node** next_addr() { return &next_; }
91
92 // Accessors for next free node in the free list.
93 Node* next_free() {
94 ASSERT(state_ == DESTROYED);
95 return parameter_or_next_free_.next_free;
96 }
97 void set_next_free(Node* value) {
98 ASSERT(state_ == DESTROYED);
99 parameter_or_next_free_.next_free = value;
100 }
101
102 // Returns a link from the handle.
103 static Node* FromLocation(Object** location) {
104 ASSERT(OFFSET_OF(Node, object_) == 0);
105 return reinterpret_cast<Node*>(location);
106 }
107
108 // Returns the handle.
109 Handle<Object> handle() { return Handle<Object>(&object_); }
110
111 // Make this handle weak.
Steve Block44f0eee2011-05-26 01:26:41 +0100112 void MakeWeak(GlobalHandles* global_handles, void* parameter,
113 WeakReferenceCallback callback) {
114 LOG(global_handles->isolate(),
115 HandleEvent("GlobalHandle::MakeWeak", handle().location()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000116 ASSERT(state_ != DESTROYED);
117 if (state_ != WEAK && !IsNearDeath()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100118 global_handles->number_of_weak_handles_++;
Steve Blocka7e24c12009-10-30 11:49:00 +0000119 if (object_->IsJSGlobalObject()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100120 global_handles->number_of_global_object_weak_handles_++;
Steve Blocka7e24c12009-10-30 11:49:00 +0000121 }
122 }
123 state_ = WEAK;
124 set_parameter(parameter);
125 callback_ = callback;
126 }
127
Steve Block44f0eee2011-05-26 01:26:41 +0100128 void ClearWeakness(GlobalHandles* global_handles) {
129 LOG(global_handles->isolate(),
130 HandleEvent("GlobalHandle::ClearWeakness", handle().location()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000131 ASSERT(state_ != DESTROYED);
132 if (state_ == WEAK || IsNearDeath()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100133 global_handles->number_of_weak_handles_--;
Steve Blocka7e24c12009-10-30 11:49:00 +0000134 if (object_->IsJSGlobalObject()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100135 global_handles->number_of_global_object_weak_handles_--;
Steve Blocka7e24c12009-10-30 11:49:00 +0000136 }
137 }
138 state_ = NORMAL;
139 set_parameter(NULL);
140 }
141
Ben Murdoch257744e2011-11-30 15:57:28 +0000142 void MarkIndependent(GlobalHandles* global_handles) {
143 LOG(global_handles->isolate(),
144 HandleEvent("GlobalHandle::MarkIndependent", handle().location()));
145 ASSERT(state_ != DESTROYED);
146 independent_ = true;
147 }
148
Steve Blocka7e24c12009-10-30 11:49:00 +0000149 bool IsNearDeath() {
150 // Check for PENDING to ensure correct answer when processing callbacks.
151 return state_ == PENDING || state_ == NEAR_DEATH;
152 }
153
154 bool IsWeak() {
155 return state_ == WEAK;
156 }
157
Steve Block44f0eee2011-05-26 01:26:41 +0100158 bool CanBeRetainer() {
159 return state_ != DESTROYED && state_ != NEAR_DEATH;
160 }
161
162 void SetWrapperClassId(uint16_t class_id) {
163 class_id_ = class_id;
164 }
165
Steve Blocka7e24c12009-10-30 11:49:00 +0000166 // Returns the id for this weak handle.
167 void set_parameter(void* parameter) {
168 ASSERT(state_ != DESTROYED);
169 parameter_or_next_free_.parameter = parameter;
170 }
171 void* parameter() {
172 ASSERT(state_ != DESTROYED);
173 return parameter_or_next_free_.parameter;
174 }
175
176 // Returns the callback for this weak handle.
177 WeakReferenceCallback callback() { return callback_; }
178
Steve Block44f0eee2011-05-26 01:26:41 +0100179 bool PostGarbageCollectionProcessing(Isolate* isolate,
180 GlobalHandles* global_handles) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000181 if (state_ != Node::PENDING) return false;
Steve Block44f0eee2011-05-26 01:26:41 +0100182 LOG(isolate, HandleEvent("GlobalHandle::Processing", handle().location()));
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100183 WeakReferenceCallback func = callback();
184 if (func == NULL) {
Steve Block44f0eee2011-05-26 01:26:41 +0100185 Destroy(global_handles);
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100186 return false;
187 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000188 void* par = parameter();
189 state_ = NEAR_DEATH;
190 set_parameter(NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +0000191
192 v8::Persistent<v8::Object> object = ToApi<v8::Object>(handle());
193 {
194 // Forbid reuse of destroyed nodes as they might be already deallocated.
195 // It's fine though to reuse nodes that were destroyed in weak callback
196 // as those cannot be deallocated until we are back from the callback.
Steve Block44f0eee2011-05-26 01:26:41 +0100197 global_handles->set_first_free(NULL);
198 if (global_handles->first_deallocated()) {
199 global_handles->first_deallocated()->set_next(global_handles->head());
Steve Blockd0582a62009-12-15 09:54:21 +0000200 }
Leon Clarkee46be812010-01-19 14:06:41 +0000201 // Check that we are not passing a finalized external string to
202 // the callback.
203 ASSERT(!object_->IsExternalAsciiString() ||
204 ExternalAsciiString::cast(object_)->resource() != NULL);
205 ASSERT(!object_->IsExternalTwoByteString() ||
206 ExternalTwoByteString::cast(object_)->resource() != NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +0000207 // Leaving V8.
Steve Block44f0eee2011-05-26 01:26:41 +0100208 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +0000209 func(object, par);
210 }
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100211 // Absense of explicit cleanup or revival of weak handle
212 // in most of the cases would lead to memory leak.
213 ASSERT(state_ != NEAR_DEATH);
Steve Blocka7e24c12009-10-30 11:49:00 +0000214 return true;
215 }
216
217 // Place the handle address first to avoid offset computation.
218 Object* object_; // Storage for object pointer.
219
Steve Block44f0eee2011-05-26 01:26:41 +0100220 uint16_t class_id_;
221
Steve Blocka7e24c12009-10-30 11:49:00 +0000222 // Transition diagram:
223 // NORMAL <-> WEAK -> PENDING -> NEAR_DEATH -> { NORMAL, WEAK, DESTROYED }
224 enum State {
225 NORMAL, // Normal global handle.
226 WEAK, // Flagged as weak but not yet finalized.
227 PENDING, // Has been recognized as only reachable by weak handles.
228 NEAR_DEATH, // Callback has informed the handle is near death.
229 DESTROYED
230 };
Steve Block44f0eee2011-05-26 01:26:41 +0100231 State state_ : 4; // Need one more bit for MSVC as it treats enums as signed.
Steve Blocka7e24c12009-10-30 11:49:00 +0000232
Ben Murdoch257744e2011-11-30 15:57:28 +0000233 bool independent_ : 1;
234
Steve Blocka7e24c12009-10-30 11:49:00 +0000235 private:
236 // Handle specific callback.
237 WeakReferenceCallback callback_;
238 // Provided data for callback. In DESTROYED state, this is used for
239 // the free list link.
240 union {
241 void* parameter;
242 Node* next_free;
243 } parameter_or_next_free_;
244
245 // Linkage for the list.
246 Node* next_;
247
248 public:
249 TRACK_MEMORY("GlobalHandles::Node")
250};
251
252
Steve Block44f0eee2011-05-26 01:26:41 +0100253class GlobalHandles::Pool {
Steve Blockd0582a62009-12-15 09:54:21 +0000254 public:
255 Pool() {
256 current_ = new Chunk();
257 current_->previous = NULL;
258 next_ = current_->nodes;
259 limit_ = current_->nodes + kNodesPerChunk;
260 }
261
Ben Murdochbb769b22010-08-11 14:56:33 +0100262 ~Pool() {
263 if (current_ != NULL) {
264 Release();
265 }
266 }
267
Steve Blockd0582a62009-12-15 09:54:21 +0000268 Node* Allocate() {
269 if (next_ < limit_) {
270 return next_++;
271 }
272 return SlowAllocate();
273 }
274
275 void Release() {
276 Chunk* current = current_;
277 ASSERT(current != NULL); // At least a single block must by allocated
278 do {
279 Chunk* previous = current->previous;
280 delete current;
281 current = previous;
282 } while (current != NULL);
283 current_ = NULL;
284 next_ = limit_ = NULL;
285 }
286
287 private:
288 static const int kNodesPerChunk = (1 << 12) - 1;
289 struct Chunk : public Malloced {
290 Chunk* previous;
291 Node nodes[kNodesPerChunk];
292 };
293
294 Node* SlowAllocate() {
295 Chunk* chunk = new Chunk();
296 chunk->previous = current_;
297 current_ = chunk;
298
299 Node* new_nodes = current_->nodes;
300 next_ = new_nodes + 1;
301 limit_ = new_nodes + kNodesPerChunk;
302 return new_nodes;
303 }
304
305 Chunk* current_;
306 Node* next_;
307 Node* limit_;
308};
309
310
Steve Block44f0eee2011-05-26 01:26:41 +0100311GlobalHandles::GlobalHandles(Isolate* isolate)
312 : isolate_(isolate),
313 number_of_weak_handles_(0),
314 number_of_global_object_weak_handles_(0),
315 head_(NULL),
316 first_free_(NULL),
317 first_deallocated_(NULL),
318 pool_(new Pool()),
319 post_gc_processing_count_(0),
320 object_groups_(4) {
321}
322
323
324GlobalHandles::~GlobalHandles() {
325 delete pool_;
326 pool_ = 0;
327}
Steve Blockd0582a62009-12-15 09:54:21 +0000328
329
Steve Blocka7e24c12009-10-30 11:49:00 +0000330Handle<Object> GlobalHandles::Create(Object* value) {
Steve Block44f0eee2011-05-26 01:26:41 +0100331 isolate_->counters()->global_handles()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +0000332 Node* result;
Steve Blockd0582a62009-12-15 09:54:21 +0000333 if (first_free()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000334 // Take the first node in the free list.
335 result = first_free();
336 set_first_free(result->next_free());
Steve Blockd0582a62009-12-15 09:54:21 +0000337 } else if (first_deallocated()) {
338 // Next try deallocated list
339 result = first_deallocated();
340 set_first_deallocated(result->next_free());
341 ASSERT(result->next() == head());
342 set_head(result);
343 } else {
344 // Allocate a new node.
Steve Block44f0eee2011-05-26 01:26:41 +0100345 result = pool_->Allocate();
Steve Blockd0582a62009-12-15 09:54:21 +0000346 result->set_next(head());
347 set_head(result);
Steve Blocka7e24c12009-10-30 11:49:00 +0000348 }
Steve Blockd0582a62009-12-15 09:54:21 +0000349 result->Initialize(value);
Steve Blocka7e24c12009-10-30 11:49:00 +0000350 return result->handle();
351}
352
353
354void GlobalHandles::Destroy(Object** location) {
Steve Block44f0eee2011-05-26 01:26:41 +0100355 isolate_->counters()->global_handles()->Decrement();
Steve Blocka7e24c12009-10-30 11:49:00 +0000356 if (location == NULL) return;
357 Node* node = Node::FromLocation(location);
Steve Block44f0eee2011-05-26 01:26:41 +0100358 node->Destroy(this);
Steve Blocka7e24c12009-10-30 11:49:00 +0000359 // Link the destroyed.
360 node->set_next_free(first_free());
361 set_first_free(node);
362}
363
364
365void GlobalHandles::MakeWeak(Object** location, void* parameter,
366 WeakReferenceCallback callback) {
367 ASSERT(callback != NULL);
Steve Block44f0eee2011-05-26 01:26:41 +0100368 Node::FromLocation(location)->MakeWeak(this, parameter, callback);
Steve Blocka7e24c12009-10-30 11:49:00 +0000369}
370
371
372void GlobalHandles::ClearWeakness(Object** location) {
Steve Block44f0eee2011-05-26 01:26:41 +0100373 Node::FromLocation(location)->ClearWeakness(this);
Steve Blocka7e24c12009-10-30 11:49:00 +0000374}
375
376
Ben Murdoch257744e2011-11-30 15:57:28 +0000377void GlobalHandles::MarkIndependent(Object** location) {
378 Node::FromLocation(location)->MarkIndependent(this);
379}
380
381
Steve Blocka7e24c12009-10-30 11:49:00 +0000382bool GlobalHandles::IsNearDeath(Object** location) {
383 return Node::FromLocation(location)->IsNearDeath();
384}
385
386
387bool GlobalHandles::IsWeak(Object** location) {
388 return Node::FromLocation(location)->IsWeak();
389}
390
391
Steve Block44f0eee2011-05-26 01:26:41 +0100392void GlobalHandles::SetWrapperClassId(Object** location, uint16_t class_id) {
393 Node::FromLocation(location)->SetWrapperClassId(class_id);
394}
395
396
Steve Blocka7e24c12009-10-30 11:49:00 +0000397void GlobalHandles::IterateWeakRoots(ObjectVisitor* v) {
398 // Traversal of GC roots in the global handle list that are marked as
Ben Murdoch257744e2011-11-30 15:57:28 +0000399 // WEAK, PENDING or NEAR_DEATH.
Steve Blocka7e24c12009-10-30 11:49:00 +0000400 for (Node* current = head_; current != NULL; current = current->next()) {
401 if (current->state_ == Node::WEAK
402 || current->state_ == Node::PENDING
403 || current->state_ == Node::NEAR_DEATH) {
404 v->VisitPointer(&current->object_);
405 }
406 }
407}
408
409
Ben Murdoch257744e2011-11-30 15:57:28 +0000410void GlobalHandles::IterateWeakIndependentRoots(ObjectVisitor* v) {
411 // Traversal of GC roots in the global handle list that are independent
412 // and marked as WEAK, PENDING or NEAR_DEATH.
413 for (Node* current = head_; current != NULL; current = current->next()) {
414 if (!current->independent_) continue;
415 if (current->state_ == Node::WEAK
416 || current->state_ == Node::PENDING
417 || current->state_ == Node::NEAR_DEATH) {
418 v->VisitPointer(&current->object_);
419 }
420 }
421}
422
423
Steve Block3ce2e202009-11-05 08:53:23 +0000424void GlobalHandles::IterateWeakRoots(WeakReferenceGuest f,
425 WeakReferenceCallback callback) {
426 for (Node* current = head_; current != NULL; current = current->next()) {
427 if (current->IsWeak() && current->callback() == callback) {
428 f(current->object_, current->parameter());
429 }
430 }
431}
432
433
Steve Blocka7e24c12009-10-30 11:49:00 +0000434void GlobalHandles::IdentifyWeakHandles(WeakSlotCallback f) {
435 for (Node* current = head_; current != NULL; current = current->next()) {
436 if (current->state_ == Node::WEAK) {
437 if (f(&current->object_)) {
438 current->state_ = Node::PENDING;
Steve Block44f0eee2011-05-26 01:26:41 +0100439 LOG(isolate_,
440 HandleEvent("GlobalHandle::Pending", current->handle().location()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000441 }
442 }
443 }
444}
445
446
Ben Murdoch257744e2011-11-30 15:57:28 +0000447void GlobalHandles::IdentifyWeakIndependentHandles(WeakSlotCallbackWithHeap f) {
448 for (Node* current = head_; current != NULL; current = current->next()) {
449 if (current->state_ == Node::WEAK && current->independent_) {
450 if (f(isolate_->heap(), &current->object_)) {
451 current->state_ = Node::PENDING;
452 LOG(isolate_,
453 HandleEvent("GlobalHandle::Pending", current->handle().location()));
454 }
455 }
456 }
457}
458
459
460bool GlobalHandles::PostGarbageCollectionProcessing(
461 GarbageCollector collector) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000462 // Process weak global handle callbacks. This must be done after the
463 // GC is completely done, because the callbacks may invoke arbitrary
464 // API functions.
Steve Blockd0582a62009-12-15 09:54:21 +0000465 // At the same time deallocate all DESTROYED nodes.
Steve Block44f0eee2011-05-26 01:26:41 +0100466 ASSERT(isolate_->heap()->gc_state() == Heap::NOT_IN_GC);
467 const int initial_post_gc_processing_count = ++post_gc_processing_count_;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800468 bool next_gc_likely_to_collect_more = false;
Steve Blocka7e24c12009-10-30 11:49:00 +0000469 Node** p = &head_;
470 while (*p != NULL) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000471 // Skip dependent handles. Their weak callbacks might expect to be
472 // called between two global garbage collection callbacks which
473 // are not called for minor collections.
474 if (collector == SCAVENGER && !(*p)->independent_) {
475 p = (*p)->next_addr();
476 continue;
477 }
478
Steve Block44f0eee2011-05-26 01:26:41 +0100479 if ((*p)->PostGarbageCollectionProcessing(isolate_, this)) {
480 if (initial_post_gc_processing_count != post_gc_processing_count_) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000481 // Weak callback triggered another GC and another round of
482 // PostGarbageCollection processing. The current node might
483 // have been deleted in that round, so we need to bail out (or
484 // restart the processing).
485 break;
486 }
487 }
488 if ((*p)->state_ == Node::DESTROYED) {
489 // Delete the link.
490 Node* node = *p;
491 *p = node->next(); // Update the link.
Steve Blockd0582a62009-12-15 09:54:21 +0000492 if (first_deallocated()) {
493 first_deallocated()->set_next(node);
494 }
495 node->set_next_free(first_deallocated());
496 set_first_deallocated(node);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800497 next_gc_likely_to_collect_more = true;
Steve Blocka7e24c12009-10-30 11:49:00 +0000498 } else {
499 p = (*p)->next_addr();
500 }
501 }
502 set_first_free(NULL);
Steve Blockd0582a62009-12-15 09:54:21 +0000503 if (first_deallocated()) {
504 first_deallocated()->set_next(head());
505 }
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800506
507 return next_gc_likely_to_collect_more;
Steve Blocka7e24c12009-10-30 11:49:00 +0000508}
509
510
Steve Blockd0582a62009-12-15 09:54:21 +0000511void GlobalHandles::IterateStrongRoots(ObjectVisitor* v) {
512 // Traversal of global handles marked as NORMAL.
Steve Blocka7e24c12009-10-30 11:49:00 +0000513 for (Node* current = head_; current != NULL; current = current->next()) {
514 if (current->state_ == Node::NORMAL) {
515 v->VisitPointer(&current->object_);
516 }
517 }
518}
519
Steve Blockd0582a62009-12-15 09:54:21 +0000520
521void GlobalHandles::IterateAllRoots(ObjectVisitor* v) {
522 for (Node* current = head_; current != NULL; current = current->next()) {
523 if (current->state_ != Node::DESTROYED) {
524 v->VisitPointer(&current->object_);
525 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000526 }
Steve Blockd0582a62009-12-15 09:54:21 +0000527}
528
529
Ben Murdoch257744e2011-11-30 15:57:28 +0000530void GlobalHandles::IterateStrongAndDependentRoots(ObjectVisitor* v) {
531 for (Node* current = head_; current != NULL; current = current->next()) {
532 if ((current->independent_ && current->state_ == Node::NORMAL) ||
533 (!current->independent_ && current->state_ != Node::DESTROYED)) {
534 v->VisitPointer(&current->object_);
535 }
536 }
537}
538
539
Steve Block44f0eee2011-05-26 01:26:41 +0100540void GlobalHandles::IterateAllRootsWithClassIds(ObjectVisitor* v) {
541 for (Node* current = head_; current != NULL; current = current->next()) {
542 if (current->class_id_ != v8::HeapProfiler::kPersistentHandleNoClassId &&
543 current->CanBeRetainer()) {
544 v->VisitEmbedderReference(&current->object_, current->class_id_);
545 }
546 }
547}
548
549
Steve Blockd0582a62009-12-15 09:54:21 +0000550void GlobalHandles::TearDown() {
551 // Reset all the lists.
Steve Blocka7e24c12009-10-30 11:49:00 +0000552 set_head(NULL);
553 set_first_free(NULL);
Steve Blockd0582a62009-12-15 09:54:21 +0000554 set_first_deallocated(NULL);
Steve Block44f0eee2011-05-26 01:26:41 +0100555 pool_->Release();
Steve Blocka7e24c12009-10-30 11:49:00 +0000556}
557
558
Steve Blockd0582a62009-12-15 09:54:21 +0000559void GlobalHandles::RecordStats(HeapStats* stats) {
560 *stats->global_handle_count = 0;
561 *stats->weak_global_handle_count = 0;
562 *stats->pending_global_handle_count = 0;
563 *stats->near_death_global_handle_count = 0;
564 *stats->destroyed_global_handle_count = 0;
565 for (Node* current = head_; current != NULL; current = current->next()) {
566 *stats->global_handle_count += 1;
567 if (current->state_ == Node::WEAK) {
568 *stats->weak_global_handle_count += 1;
569 } else if (current->state_ == Node::PENDING) {
570 *stats->pending_global_handle_count += 1;
571 } else if (current->state_ == Node::NEAR_DEATH) {
572 *stats->near_death_global_handle_count += 1;
573 } else if (current->state_ == Node::DESTROYED) {
574 *stats->destroyed_global_handle_count += 1;
575 }
576 }
577}
Steve Blocka7e24c12009-10-30 11:49:00 +0000578
579#ifdef DEBUG
580
581void GlobalHandles::PrintStats() {
582 int total = 0;
583 int weak = 0;
584 int pending = 0;
585 int near_death = 0;
586 int destroyed = 0;
587
588 for (Node* current = head_; current != NULL; current = current->next()) {
589 total++;
590 if (current->state_ == Node::WEAK) weak++;
591 if (current->state_ == Node::PENDING) pending++;
592 if (current->state_ == Node::NEAR_DEATH) near_death++;
593 if (current->state_ == Node::DESTROYED) destroyed++;
594 }
595
596 PrintF("Global Handle Statistics:\n");
Ben Murdochf87a2032010-10-22 12:50:53 +0100597 PrintF(" allocated memory = %" V8_PTR_PREFIX "dB\n", sizeof(Node) * total);
Steve Blocka7e24c12009-10-30 11:49:00 +0000598 PrintF(" # weak = %d\n", weak);
599 PrintF(" # pending = %d\n", pending);
600 PrintF(" # near_death = %d\n", near_death);
601 PrintF(" # destroyed = %d\n", destroyed);
602 PrintF(" # total = %d\n", total);
603}
604
605void GlobalHandles::Print() {
606 PrintF("Global handles:\n");
607 for (Node* current = head_; current != NULL; current = current->next()) {
Ben Murdochf87a2032010-10-22 12:50:53 +0100608 PrintF(" handle %p to %p (weak=%d)\n",
609 reinterpret_cast<void*>(current->handle().location()),
610 reinterpret_cast<void*>(*current->handle()),
611 current->state_ == Node::WEAK);
Steve Blocka7e24c12009-10-30 11:49:00 +0000612 }
613}
614
615#endif
616
Steve Block44f0eee2011-05-26 01:26:41 +0100617
618
619void GlobalHandles::AddObjectGroup(Object*** handles,
620 size_t length,
621 v8::RetainedObjectInfo* info) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000622#ifdef DEBUG
623 for (size_t i = 0; i < length; ++i) {
624 ASSERT(!Node::FromLocation(handles[i])->independent_);
625 }
626#endif
Ben Murdoch8b112d22011-06-08 16:22:53 +0100627 if (length == 0) {
628 if (info != NULL) info->Dispose();
629 return;
Steve Block44f0eee2011-05-26 01:26:41 +0100630 }
Ben Murdoch8b112d22011-06-08 16:22:53 +0100631 object_groups_.Add(ObjectGroup::New(handles, length, info));
Steve Blocka7e24c12009-10-30 11:49:00 +0000632}
633
Steve Block44f0eee2011-05-26 01:26:41 +0100634
Ben Murdoch8b112d22011-06-08 16:22:53 +0100635void GlobalHandles::AddImplicitReferences(HeapObject** parent,
Steve Block44f0eee2011-05-26 01:26:41 +0100636 Object*** children,
637 size_t length) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000638#ifdef DEBUG
639 ASSERT(!Node::FromLocation(BitCast<Object**>(parent))->independent_);
640 for (size_t i = 0; i < length; ++i) {
641 ASSERT(!Node::FromLocation(children[i])->independent_);
642 }
643#endif
Ben Murdoch8b112d22011-06-08 16:22:53 +0100644 if (length == 0) return;
645 implicit_ref_groups_.Add(ImplicitRefGroup::New(parent, children, length));
Steve Blocka7e24c12009-10-30 11:49:00 +0000646}
647
648
649void GlobalHandles::RemoveObjectGroups() {
Steve Block44f0eee2011-05-26 01:26:41 +0100650 for (int i = 0; i < object_groups_.length(); i++) {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100651 object_groups_.at(i)->Dispose();
Steve Blocka7e24c12009-10-30 11:49:00 +0000652 }
Steve Block44f0eee2011-05-26 01:26:41 +0100653 object_groups_.Clear();
Steve Blocka7e24c12009-10-30 11:49:00 +0000654}
655
Steve Block44f0eee2011-05-26 01:26:41 +0100656
657void GlobalHandles::RemoveImplicitRefGroups() {
658 for (int i = 0; i < implicit_ref_groups_.length(); i++) {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100659 implicit_ref_groups_.at(i)->Dispose();
Steve Block44f0eee2011-05-26 01:26:41 +0100660 }
661 implicit_ref_groups_.Clear();
662}
663
664
Steve Blocka7e24c12009-10-30 11:49:00 +0000665} } // namespace v8::internal