OLD | NEW |
1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 2009 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
49 | 49 |
50 class GlobalHandles::Node { | 50 class GlobalHandles::Node { |
51 public: | 51 public: |
52 // State transition diagram: | 52 // State transition diagram: |
53 // FREE -> NORMAL <-> WEAK -> PENDING -> NEAR_DEATH -> { NORMAL, WEAK, FREE } | 53 // FREE -> NORMAL <-> WEAK -> PENDING -> NEAR_DEATH -> { NORMAL, WEAK, FREE } |
54 enum State { | 54 enum State { |
55 FREE = 0, | 55 FREE = 0, |
56 NORMAL, // Normal global handle. | 56 NORMAL, // Normal global handle. |
57 WEAK, // Flagged as weak but not yet finalized. | 57 WEAK, // Flagged as weak but not yet finalized. |
58 PENDING, // Has been recognized as only reachable by weak handles. | 58 PENDING, // Has been recognized as only reachable by weak handles. |
59 NEAR_DEATH, // Callback has informed the handle is near death. | 59 NEAR_DEATH // Callback has informed the handle is near death. |
60 | |
61 NUMBER_OF_STATES | |
62 }; | 60 }; |
63 | 61 |
64 // Maps handle location (slot) to the containing node. | 62 // Maps handle location (slot) to the containing node. |
65 static Node* FromLocation(Object** location) { | 63 static Node* FromLocation(Object** location) { |
66 ASSERT(OFFSET_OF(Node, object_) == 0); | 64 ASSERT(OFFSET_OF(Node, object_) == 0); |
67 return reinterpret_cast<Node*>(location); | 65 return reinterpret_cast<Node*>(location); |
68 } | 66 } |
69 | 67 |
70 Node() { | 68 Node() { |
71 ASSERT(OFFSET_OF(Node, class_id_) == Internals::kNodeClassIdOffset); | 69 ASSERT(OFFSET_OF(Node, class_id_) == Internals::kNodeClassIdOffset); |
(...skipping 17 matching lines...) Expand all Loading... |
89 class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId; | 87 class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId; |
90 index_ = 0; | 88 index_ = 0; |
91 set_independent(false); | 89 set_independent(false); |
92 set_partially_dependent(false); | 90 set_partially_dependent(false); |
93 set_in_new_space_list(false); | 91 set_in_new_space_list(false); |
94 parameter_or_next_free_.next_free = NULL; | 92 parameter_or_next_free_.next_free = NULL; |
95 weak_reference_callback_ = NULL; | 93 weak_reference_callback_ = NULL; |
96 } | 94 } |
97 #endif | 95 #endif |
98 | 96 |
99 void Initialize(int index, Node* first_free) { | 97 void Initialize(int index, Node** first_free) { |
100 index_ = static_cast<uint8_t>(index); | 98 index_ = static_cast<uint8_t>(index); |
101 ASSERT(static_cast<int>(index_) == index); | 99 ASSERT(static_cast<int>(index_) == index); |
102 set_state(FREE); | 100 set_state(FREE); |
103 set_in_new_space_list(false); | 101 set_in_new_space_list(false); |
104 parameter_or_next_free_.next_free = first_free; | 102 parameter_or_next_free_.next_free = *first_free; |
| 103 *first_free = this; |
105 } | 104 } |
106 | 105 |
107 void Acquire(Object* object) { | 106 void Acquire(Object* object) { |
108 ASSERT(state() == FREE); | 107 ASSERT(state() == FREE); |
109 object_ = object; | 108 object_ = object; |
110 class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId; | 109 class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId; |
111 set_independent(false); | 110 set_independent(false); |
112 set_partially_dependent(false); | 111 set_partially_dependent(false); |
113 set_state(NORMAL); | 112 set_state(NORMAL); |
114 parameter_or_next_free_.parameter = NULL; | 113 parameter_or_next_free_.parameter = NULL; |
115 weak_reference_callback_ = NULL; | 114 weak_reference_callback_ = NULL; |
| 115 IncreaseBlockUses(); |
116 } | 116 } |
117 | 117 |
118 void Release() { | 118 void Release() { |
119 ASSERT(state() != FREE); | 119 ASSERT(state() != FREE); |
120 set_state(FREE); | 120 set_state(FREE); |
121 #ifdef ENABLE_EXTRA_CHECKS | 121 #ifdef ENABLE_EXTRA_CHECKS |
122 // Zap the values for eager trapping. | 122 // Zap the values for eager trapping. |
123 object_ = reinterpret_cast<Object*>(kGlobalHandleZapValue); | 123 object_ = reinterpret_cast<Object*>(kGlobalHandleZapValue); |
124 class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId; | 124 class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId; |
125 set_independent(false); | 125 set_independent(false); |
126 set_partially_dependent(false); | 126 set_partially_dependent(false); |
127 weak_reference_callback_ = NULL; | 127 weak_reference_callback_ = NULL; |
128 #endif | 128 #endif |
129 ReleaseFromBlock(); | 129 DecreaseBlockUses(); |
130 } | 130 } |
131 | 131 |
132 // Object slot accessors. | 132 // Object slot accessors. |
133 Object* object() const { return object_; } | 133 Object* object() const { return object_; } |
134 Object** location() { return &object_; } | 134 Object** location() { return &object_; } |
135 Handle<Object> handle() { return Handle<Object>(location()); } | 135 Handle<Object> handle() { return Handle<Object>(location()); } |
136 | 136 |
137 // Wrapper class ID accessors. | 137 // Wrapper class ID accessors. |
138 bool has_wrapper_class_id() const { | 138 bool has_wrapper_class_id() const { |
139 return class_id_ != v8::HeapProfiler::kPersistentHandleNoClassId; | 139 return class_id_ != v8::HeapProfiler::kPersistentHandleNoClassId; |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
198 } | 198 } |
199 | 199 |
200 void MarkPartiallyDependent() { | 200 void MarkPartiallyDependent() { |
201 ASSERT(state() != FREE); | 201 ASSERT(state() != FREE); |
202 if (GetGlobalHandles()->isolate()->heap()->InNewSpace(object_)) { | 202 if (GetGlobalHandles()->isolate()->heap()->InNewSpace(object_)) { |
203 set_partially_dependent(true); | 203 set_partially_dependent(true); |
204 } | 204 } |
205 } | 205 } |
206 void clear_partially_dependent() { set_partially_dependent(false); } | 206 void clear_partially_dependent() { set_partially_dependent(false); } |
207 | 207 |
| 208 // Callback accessor. |
| 209 // TODO(svenpanne) Re-enable or nuke later. |
| 210 // WeakReferenceCallback callback() { return callback_; } |
| 211 |
208 // Callback parameter accessors. | 212 // Callback parameter accessors. |
209 void set_parameter(void* parameter) { | 213 void set_parameter(void* parameter) { |
210 ASSERT(state() != FREE); | 214 ASSERT(state() != FREE); |
211 parameter_or_next_free_.parameter = parameter; | 215 parameter_or_next_free_.parameter = parameter; |
212 } | 216 } |
213 void* parameter() const { | 217 void* parameter() const { |
214 ASSERT(state() != FREE); | 218 ASSERT(state() != FREE); |
215 return parameter_or_next_free_.parameter; | 219 return parameter_or_next_free_.parameter; |
216 } | 220 } |
217 | 221 |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
266 } | 270 } |
267 // Absence of explicit cleanup or revival of weak handle | 271 // Absence of explicit cleanup or revival of weak handle |
268 // in most of the cases would lead to memory leak. | 272 // in most of the cases would lead to memory leak. |
269 ASSERT(state() != NEAR_DEATH); | 273 ASSERT(state() != NEAR_DEATH); |
270 return true; | 274 return true; |
271 } | 275 } |
272 | 276 |
273 private: | 277 private: |
274 inline NodeBlock* FindBlock(); | 278 inline NodeBlock* FindBlock(); |
275 inline GlobalHandles* GetGlobalHandles(); | 279 inline GlobalHandles* GetGlobalHandles(); |
276 inline void ReleaseFromBlock(); | 280 inline void IncreaseBlockUses(); |
| 281 inline void DecreaseBlockUses(); |
277 | 282 |
278 // Storage for object pointer. | 283 // Storage for object pointer. |
279 // Placed first to avoid offset computation. | 284 // Placed first to avoid offset computation. |
280 Object* object_; | 285 Object* object_; |
281 | 286 |
282 // Next word stores class_id, index, state, and independent. | 287 // Next word stores class_id, index, state, and independent. |
283 // Note: the most aligned fields should go first. | 288 // Note: the most aligned fields should go first. |
284 | 289 |
285 // Wrapper class ID. | 290 // Wrapper class ID. |
286 uint16_t class_id_; | 291 uint16_t class_id_; |
(...skipping 17 matching lines...) Expand all Loading... |
304 // the free list link. | 309 // the free list link. |
305 union { | 310 union { |
306 void* parameter; | 311 void* parameter; |
307 Node* next_free; | 312 Node* next_free; |
308 } parameter_or_next_free_; | 313 } parameter_or_next_free_; |
309 | 314 |
310 DISALLOW_COPY_AND_ASSIGN(Node); | 315 DISALLOW_COPY_AND_ASSIGN(Node); |
311 }; | 316 }; |
312 | 317 |
313 | 318 |
314 class GlobalHandles::BlockListIterator { | 319 class GlobalHandles::NodeBlock { |
315 public: | |
316 explicit inline BlockListIterator(BlockList* anchor) | |
317 : anchor_(anchor), current_(anchor->next()) { | |
318 ASSERT(anchor->IsAnchor()); | |
319 } | |
320 inline BlockList* block() const { | |
321 ASSERT(!done()); | |
322 return current_; | |
323 } | |
324 inline bool done() const { | |
325 ASSERT_EQ(anchor_ == current_, current_->IsAnchor()); | |
326 return anchor_ == current_; | |
327 } | |
328 inline void Advance() { | |
329 ASSERT(!done()); | |
330 current_ = current_->next(); | |
331 } | |
332 | |
333 private: | |
334 BlockList* const anchor_; | |
335 BlockList* current_; | |
336 DISALLOW_COPY_AND_ASSIGN(BlockListIterator); | |
337 }; | |
338 | |
339 | |
340 GlobalHandles::BlockList::BlockList() | |
341 : prev_block_(this), | |
342 next_block_(this), | |
343 first_free_(NULL), | |
344 used_nodes_(0) {} | |
345 | |
346 | |
347 void GlobalHandles::BlockList::InsertAsNext(BlockList* const block) { | |
348 ASSERT(block != this); | |
349 ASSERT(!block->IsAnchor()); | |
350 ASSERT(block->IsDetached()); | |
351 block->prev_block_ = this; | |
352 block->next_block_ = next_block_; | |
353 next_block_->prev_block_ = block; | |
354 next_block_ = block; | |
355 ASSERT(!IsDetached()); | |
356 ASSERT(!block->IsDetached()); | |
357 } | |
358 | |
359 | |
360 void GlobalHandles::BlockList::Detach() { | |
361 ASSERT(!IsAnchor()); | |
362 ASSERT(!IsDetached()); | |
363 prev_block_->next_block_ = next_block_; | |
364 next_block_->prev_block_ = prev_block_; | |
365 prev_block_ = this; | |
366 next_block_ = this; | |
367 ASSERT(IsDetached()); | |
368 } | |
369 | |
370 | |
371 bool GlobalHandles::BlockList::HasAtLeastLength(int length) { | |
372 ASSERT(IsAnchor()); | |
373 ASSERT(length > 0); | |
374 for (BlockListIterator it(this); !it.done(); it.Advance()) { | |
375 if (--length <= 0) return true; | |
376 } | |
377 return false; | |
378 } | |
379 | |
380 | |
381 #ifdef DEBUG | |
382 int GlobalHandles::BlockList::LengthOfFreeList() { | |
383 int count = 0; | |
384 Node* node = first_free_; | |
385 while (node != NULL) { | |
386 count++; | |
387 node = node->next_free(); | |
388 } | |
389 return count; | |
390 } | |
391 #endif | |
392 | |
393 | |
394 int GlobalHandles::BlockList::CompareBlocks(const void* a, const void* b) { | |
395 const BlockList* block_a = | |
396 *reinterpret_cast<const BlockList**>(reinterpret_cast<uintptr_t>(a)); | |
397 const BlockList* block_b = | |
398 *reinterpret_cast<const BlockList**>(reinterpret_cast<uintptr_t>(b)); | |
399 if (block_a->used_nodes() > block_b->used_nodes()) return -1; | |
400 if (block_a->used_nodes() == block_b->used_nodes()) return 0; | |
401 return 1; | |
402 } | |
403 | |
404 | |
405 class GlobalHandles::NodeBlock : public BlockList { | |
406 public: | 320 public: |
407 static const int kSize = 256; | 321 static const int kSize = 256; |
408 | 322 |
409 explicit NodeBlock(GlobalHandles* global_handles) | 323 explicit NodeBlock(GlobalHandles* global_handles, NodeBlock* next) |
410 : global_handles_(global_handles) { | 324 : next_(next), |
411 // Initialize nodes | 325 used_nodes_(0), |
412 Node* first_free = first_free_; | 326 next_used_(NULL), |
| 327 prev_used_(NULL), |
| 328 global_handles_(global_handles) {} |
| 329 |
| 330 void PutNodesOnFreeList(Node** first_free) { |
413 for (int i = kSize - 1; i >= 0; --i) { | 331 for (int i = kSize - 1; i >= 0; --i) { |
414 nodes_[i].Initialize(i, first_free); | 332 nodes_[i].Initialize(i, first_free); |
415 first_free = &nodes_[i]; | |
416 } | |
417 first_free_ = first_free; | |
418 ASSERT(!IsAnchor()); | |
419 // Link into global_handles | |
420 ASSERT(global_handles->non_full_blocks_.IsDetached()); | |
421 global_handles->non_full_blocks_.InsertAsHead(this); | |
422 global_handles->number_of_blocks_++; | |
423 } | |
424 | |
425 Node* Acquire(Object* o) { | |
426 ASSERT(used_nodes_ < kSize); | |
427 ASSERT(first_free_ != NULL); | |
428 ASSERT(global_handles_->non_full_blocks_.next() == this); | |
429 // Remove from free list | |
430 Node* node = first_free_; | |
431 first_free_ = node->next_free(); | |
432 // Increment counters | |
433 global_handles_->isolate()->counters()->global_handles()->Increment(); | |
434 global_handles_->number_of_global_handles_++; | |
435 // Initialize node with value | |
436 node->Acquire(o); | |
437 bool now_full = ++used_nodes_ == kSize; | |
438 ASSERT_EQ(now_full, first_free_ == NULL); | |
439 if (now_full) { | |
440 // Move block to tail of non_full_blocks_ | |
441 Detach(); | |
442 global_handles_->full_blocks_.InsertAsTail(this); | |
443 } | |
444 return node; | |
445 } | |
446 | |
447 void Release(Node* node) { | |
448 ASSERT(used_nodes_ > 0); | |
449 // Add to free list | |
450 node->set_next_free(first_free_); | |
451 first_free_ = node; | |
452 // Decrement counters | |
453 global_handles_->isolate()->counters()->global_handles()->Decrement(); | |
454 global_handles_->number_of_global_handles_--; | |
455 bool was_full = used_nodes_-- == kSize; | |
456 ASSERT_EQ(was_full, first_free_->next_free() == NULL); | |
457 if (was_full) { | |
458 // Move this block to head of non_full_blocks_ | |
459 Detach(); | |
460 global_handles_->non_full_blocks_.InsertAsHead(this); | |
461 } | 333 } |
462 } | 334 } |
463 | 335 |
464 Node* node_at(int index) { | 336 Node* node_at(int index) { |
465 ASSERT(0 <= index && index < kSize); | 337 ASSERT(0 <= index && index < kSize); |
466 return &nodes_[index]; | 338 return &nodes_[index]; |
467 } | 339 } |
468 | 340 |
| 341 void IncreaseUses() { |
| 342 ASSERT(used_nodes_ < kSize); |
| 343 if (used_nodes_++ == 0) { |
| 344 NodeBlock* old_first = global_handles_->first_used_block_; |
| 345 global_handles_->first_used_block_ = this; |
| 346 next_used_ = old_first; |
| 347 prev_used_ = NULL; |
| 348 if (old_first == NULL) return; |
| 349 old_first->prev_used_ = this; |
| 350 } |
| 351 } |
| 352 |
| 353 void DecreaseUses() { |
| 354 ASSERT(used_nodes_ > 0); |
| 355 if (--used_nodes_ == 0) { |
| 356 if (next_used_ != NULL) next_used_->prev_used_ = prev_used_; |
| 357 if (prev_used_ != NULL) prev_used_->next_used_ = next_used_; |
| 358 if (this == global_handles_->first_used_block_) { |
| 359 global_handles_->first_used_block_ = next_used_; |
| 360 } |
| 361 } |
| 362 } |
| 363 |
469 GlobalHandles* global_handles() { return global_handles_; } | 364 GlobalHandles* global_handles() { return global_handles_; } |
470 | 365 |
471 static NodeBlock* Cast(BlockList* block_list) { | 366 // Next block in the list of all blocks. |
472 ASSERT(!block_list->IsAnchor()); | 367 NodeBlock* next() const { return next_; } |
473 return static_cast<NodeBlock*>(block_list); | |
474 } | |
475 | 368 |
476 static NodeBlock* From(Node* node, uint8_t index) { | 369 // Next/previous block in the list of blocks with used nodes. |
477 uintptr_t ptr = reinterpret_cast<uintptr_t>(node - index); | 370 NodeBlock* next_used() const { return next_used_; } |
478 ptr -= OFFSET_OF(NodeBlock, nodes_); | 371 NodeBlock* prev_used() const { return prev_used_; } |
479 NodeBlock* block = reinterpret_cast<NodeBlock*>(ptr); | |
480 ASSERT(block->node_at(index) == node); | |
481 return block; | |
482 } | |
483 | 372 |
484 private: | 373 private: |
485 Node nodes_[kSize]; | 374 Node nodes_[kSize]; |
| 375 NodeBlock* const next_; |
| 376 int used_nodes_; |
| 377 NodeBlock* next_used_; |
| 378 NodeBlock* prev_used_; |
486 GlobalHandles* global_handles_; | 379 GlobalHandles* global_handles_; |
487 }; | 380 }; |
488 | 381 |
489 | 382 |
490 void GlobalHandles::BlockList::SortBlocks(GlobalHandles* global_handles, | |
491 bool prune) { | |
492 // Always sort at least 2 blocks | |
493 if (!global_handles->non_full_blocks_.HasAtLeastLength(2)) return; | |
494 // build a vector that could contain the upper bound of the block count | |
495 int number_of_blocks = global_handles->block_count(); | |
496 // Build array of blocks and update number_of_blocks to actual count | |
497 ScopedVector<BlockList*> blocks(number_of_blocks); | |
498 { | |
499 int i = 0; | |
500 BlockList* anchor = &global_handles->non_full_blocks_; | |
501 for (BlockListIterator it(anchor); !it.done(); it.Advance()) { | |
502 blocks[i++] = it.block(); | |
503 } | |
504 number_of_blocks = i; | |
505 } | |
506 // Nothing to do. | |
507 if (number_of_blocks <= 1) return; | |
508 // Sort blocks | |
509 qsort(blocks.start(), number_of_blocks, sizeof(blocks[0]), CompareBlocks); | |
510 // Prune empties | |
511 if (prune) { | |
512 static const double kUnusedPercentage = 0.30; | |
513 static const double kUsedPercentage = 1.30; | |
514 int total_slots = global_handles->number_of_blocks_ * NodeBlock::kSize; | |
515 const int total_used = global_handles->number_of_global_handles_; | |
516 const int target_unused = static_cast<int>(Max( | |
517 total_used * kUsedPercentage, | |
518 total_slots * kUnusedPercentage)); | |
519 // Reverse through empty blocks. Note: always leave one block free. | |
520 int blocks_deleted = 0; | |
521 for (int i = number_of_blocks - 1; i > 0 && blocks[i]->IsUnused(); i--) { | |
522 // Not worth deleting | |
523 if (total_slots - total_used < target_unused) break; | |
524 blocks[i]->Detach(); | |
525 delete blocks[i]; | |
526 blocks_deleted++; | |
527 total_slots -= NodeBlock::kSize; | |
528 } | |
529 global_handles->number_of_blocks_ -= blocks_deleted; | |
530 number_of_blocks -= blocks_deleted; | |
531 } | |
532 // Relink all blocks | |
533 for (int i = 0; i < number_of_blocks; i++) { | |
534 blocks[i]->Detach(); | |
535 global_handles->non_full_blocks_.InsertAsTail(blocks[i]); | |
536 } | |
537 #ifdef DEBUG | |
538 // Check sorting | |
539 BlockList* anchor = &global_handles->non_full_blocks_; | |
540 int last_size = NodeBlock::kSize; | |
541 for (BlockListIterator it(anchor); !it.done(); it.Advance()) { | |
542 ASSERT(it.block()->used_nodes() <= last_size); | |
543 last_size = it.block()->used_nodes(); | |
544 } | |
545 #endif | |
546 } | |
547 | |
548 | |
549 #ifdef DEBUG | |
550 void GlobalHandles::VerifyBlockInvariants() { | |
551 int number_of_blocks = 0; | |
552 int number_of_handles = 0; | |
553 for (int i = 0; i < kAllAnchorsSize; i++) { | |
554 for (BlockListIterator it(all_anchors_[i]); !it.done(); it.Advance()) { | |
555 BlockList* block = it.block(); | |
556 number_of_blocks++; | |
557 int used_nodes = block->used_nodes(); | |
558 number_of_handles += used_nodes; | |
559 int unused_nodes = block->LengthOfFreeList(); | |
560 ASSERT_EQ(used_nodes + unused_nodes, NodeBlock::kSize); | |
561 if (all_anchors_[i] == &full_blocks_) { | |
562 ASSERT_EQ(NodeBlock::kSize, used_nodes); | |
563 } else { | |
564 ASSERT_NE(NodeBlock::kSize, used_nodes); | |
565 } | |
566 } | |
567 } | |
568 ASSERT_EQ(number_of_handles, number_of_global_handles_); | |
569 ASSERT_EQ(number_of_blocks, number_of_blocks_); | |
570 } | |
571 #endif | |
572 | |
573 | |
574 void GlobalHandles::SortBlocks(bool shouldPrune) { | |
575 #ifdef DEBUG | |
576 VerifyBlockInvariants(); | |
577 #endif | |
578 BlockList::SortBlocks(this, shouldPrune); | |
579 #ifdef DEBUG | |
580 VerifyBlockInvariants(); | |
581 #endif | |
582 } | |
583 | |
584 | |
585 GlobalHandles* GlobalHandles::Node::GetGlobalHandles() { | 383 GlobalHandles* GlobalHandles::Node::GetGlobalHandles() { |
586 return FindBlock()->global_handles(); | 384 return FindBlock()->global_handles(); |
587 } | 385 } |
588 | 386 |
589 | 387 |
590 GlobalHandles::NodeBlock* GlobalHandles::Node::FindBlock() { | 388 GlobalHandles::NodeBlock* GlobalHandles::Node::FindBlock() { |
591 return NodeBlock::From(this, index_); | 389 intptr_t ptr = reinterpret_cast<intptr_t>(this); |
| 390 ptr = ptr - index_ * sizeof(Node); |
| 391 NodeBlock* block = reinterpret_cast<NodeBlock*>(ptr); |
| 392 ASSERT(block->node_at(index_) == this); |
| 393 return block; |
592 } | 394 } |
593 | 395 |
594 | 396 |
595 void GlobalHandles::Node::ReleaseFromBlock() { | 397 void GlobalHandles::Node::IncreaseBlockUses() { |
596 FindBlock()->Release(this); | 398 NodeBlock* node_block = FindBlock(); |
| 399 node_block->IncreaseUses(); |
| 400 GlobalHandles* global_handles = node_block->global_handles(); |
| 401 global_handles->isolate()->counters()->global_handles()->Increment(); |
| 402 global_handles->number_of_global_handles_++; |
| 403 } |
| 404 |
| 405 |
| 406 void GlobalHandles::Node::DecreaseBlockUses() { |
| 407 NodeBlock* node_block = FindBlock(); |
| 408 GlobalHandles* global_handles = node_block->global_handles(); |
| 409 parameter_or_next_free_.next_free = global_handles->first_free_; |
| 410 global_handles->first_free_ = this; |
| 411 node_block->DecreaseUses(); |
| 412 global_handles->isolate()->counters()->global_handles()->Decrement(); |
| 413 global_handles->number_of_global_handles_--; |
597 } | 414 } |
598 | 415 |
599 | 416 |
600 class GlobalHandles::NodeIterator { | 417 class GlobalHandles::NodeIterator { |
601 public: | 418 public: |
602 explicit NodeIterator(GlobalHandles* global_handles) | 419 explicit NodeIterator(GlobalHandles* global_handles) |
603 : all_anchors_(global_handles->all_anchors_), | 420 : block_(global_handles->first_used_block_), |
604 block_(all_anchors_[0]), | 421 index_(0) {} |
605 anchor_index_(0), | |
606 node_index_(0) { | |
607 AdvanceBlock(); | |
608 } | |
609 | 422 |
610 bool done() const { | 423 bool done() const { return block_ == NULL; } |
611 return anchor_index_ == kAllAnchorsSize; | |
612 } | |
613 | 424 |
614 Node* node() const { | 425 Node* node() const { |
615 ASSERT(!done()); | 426 ASSERT(!done()); |
616 return NodeBlock::Cast(block_)->node_at(node_index_); | 427 return block_->node_at(index_); |
617 } | 428 } |
618 | 429 |
619 void Advance() { | 430 void Advance() { |
620 ASSERT(!done()); | 431 ASSERT(!done()); |
621 if (++node_index_ < NodeBlock::kSize) return; | 432 if (++index_ < NodeBlock::kSize) return; |
622 node_index_ = 0; | 433 index_ = 0; |
623 AdvanceBlock(); | 434 block_ = block_->next_used(); |
624 } | 435 } |
625 | 436 |
626 typedef int CountArray[Node::NUMBER_OF_STATES]; | |
627 static int CollectStats(GlobalHandles* global_handles, CountArray counts); | |
628 | |
629 private: | 437 private: |
630 void AdvanceBlock() { | 438 NodeBlock* block_; |
631 ASSERT(!done()); | 439 int index_; |
632 while (true) { | |
633 block_ = block_->next(); | |
634 // block is valid | |
635 if (block_ != all_anchors_[anchor_index_]) { | |
636 ASSERT(!done()); | |
637 ASSERT(!block_->IsAnchor()); | |
638 // skip empty blocks | |
639 if (block_->IsUnused()) continue; | |
640 return; | |
641 } | |
642 // jump lists | |
643 anchor_index_++; | |
644 if (anchor_index_ == kAllAnchorsSize) break; | |
645 block_ = all_anchors_[anchor_index_]; | |
646 } | |
647 ASSERT(done()); | |
648 } | |
649 | |
650 BlockList* const * const all_anchors_; | |
651 BlockList* block_; | |
652 int anchor_index_; | |
653 int node_index_; | |
654 | 440 |
655 DISALLOW_COPY_AND_ASSIGN(NodeIterator); | 441 DISALLOW_COPY_AND_ASSIGN(NodeIterator); |
656 }; | 442 }; |
657 | 443 |
658 | 444 |
659 int GlobalHandles::NodeIterator::CollectStats(GlobalHandles* global_handles, | |
660 CountArray counts) { | |
661 static const int kSize = Node::NUMBER_OF_STATES; | |
662 for (int i = 0; i < kSize; i++) { | |
663 counts[i] = 0; | |
664 } | |
665 int total = 0; | |
666 for (NodeIterator it(global_handles); !it.done(); it.Advance()) { | |
667 total++; | |
668 Node::State state = it.node()->state(); | |
669 ASSERT(state >= 0 && state < kSize); | |
670 counts[state]++; | |
671 } | |
672 // NodeIterator skips empty blocks | |
673 int skipped = global_handles->number_of_blocks_ * NodeBlock::kSize - total; | |
674 total += skipped; | |
675 counts[Node::FREE] += total; | |
676 return total; | |
677 } | |
678 | |
679 | |
680 GlobalHandles::GlobalHandles(Isolate* isolate) | 445 GlobalHandles::GlobalHandles(Isolate* isolate) |
681 : isolate_(isolate), | 446 : isolate_(isolate), |
682 number_of_blocks_(0), | |
683 number_of_global_handles_(0), | 447 number_of_global_handles_(0), |
| 448 first_block_(NULL), |
| 449 first_used_block_(NULL), |
| 450 first_free_(NULL), |
684 post_gc_processing_count_(0), | 451 post_gc_processing_count_(0), |
685 object_group_connections_(kObjectGroupConnectionsCapacity) { | 452 object_group_connections_(kObjectGroupConnectionsCapacity) {} |
686 all_anchors_[0] = &full_blocks_; | |
687 all_anchors_[1] = &non_full_blocks_; | |
688 } | |
689 | 453 |
690 | 454 |
691 GlobalHandles::~GlobalHandles() { | 455 GlobalHandles::~GlobalHandles() { |
692 for (int i = 0; i < kAllAnchorsSize; i++) { | 456 NodeBlock* block = first_block_; |
693 BlockList* block = all_anchors_[i]->next(); | 457 while (block != NULL) { |
694 while (block != all_anchors_[i]) { | 458 NodeBlock* tmp = block->next(); |
695 BlockList* tmp = block->next(); | 459 delete block; |
696 block->Detach(); | 460 block = tmp; |
697 delete NodeBlock::Cast(block); | |
698 block = tmp; | |
699 } | |
700 } | 461 } |
| 462 first_block_ = NULL; |
701 } | 463 } |
702 | 464 |
703 | 465 |
704 Handle<Object> GlobalHandles::Create(Object* value) { | 466 Handle<Object> GlobalHandles::Create(Object* value) { |
705 if (non_full_blocks_.IsDetached()) { | 467 if (first_free_ == NULL) { |
706 new NodeBlock(this); | 468 first_block_ = new NodeBlock(this, first_block_); |
707 ASSERT(!non_full_blocks_.IsDetached()); | 469 first_block_->PutNodesOnFreeList(&first_free_); |
708 } | 470 } |
709 ASSERT(non_full_blocks_.IsAnchor()); | 471 ASSERT(first_free_ != NULL); |
710 ASSERT(!non_full_blocks_.next()->IsAnchor()); | 472 // Take the first node in the free list. |
711 Node* result = NodeBlock::Cast(non_full_blocks_.next())->Acquire(value); | 473 Node* result = first_free_; |
| 474 first_free_ = result->next_free(); |
| 475 result->Acquire(value); |
712 if (isolate_->heap()->InNewSpace(value) && | 476 if (isolate_->heap()->InNewSpace(value) && |
713 !result->is_in_new_space_list()) { | 477 !result->is_in_new_space_list()) { |
714 new_space_nodes_.Add(result); | 478 new_space_nodes_.Add(result); |
715 result->set_in_new_space_list(true); | 479 result->set_in_new_space_list(true); |
716 } | 480 } |
717 return result->handle(); | 481 return result->handle(); |
718 } | 482 } |
719 | 483 |
720 | 484 |
721 void GlobalHandles::Destroy(Object** location) { | 485 void GlobalHandles::Destroy(Object** location) { |
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
891 // have been deleted in that round, so we need to bail out (or | 655 // have been deleted in that round, so we need to bail out (or |
892 // restart the processing). | 656 // restart the processing). |
893 return next_gc_likely_to_collect_more; | 657 return next_gc_likely_to_collect_more; |
894 } | 658 } |
895 } | 659 } |
896 if (!node->IsRetainer()) { | 660 if (!node->IsRetainer()) { |
897 next_gc_likely_to_collect_more = true; | 661 next_gc_likely_to_collect_more = true; |
898 } | 662 } |
899 } | 663 } |
900 } else { | 664 } else { |
901 // Must cache all blocks, as NodeIterator can't survive mutation. | 665 for (NodeIterator it(this); !it.done(); it.Advance()) { |
902 List<NodeBlock*> blocks(number_of_blocks_); | 666 if (!it.node()->IsRetainer()) { |
903 for (int i = 0; i < kAllAnchorsSize; i++) { | 667 // Free nodes do not have weak callbacks. Do not use them to compute |
904 for (BlockListIterator it(all_anchors_[i]); !it.done(); it.Advance()) { | 668 // the next_gc_likely_to_collect_more. |
905 blocks.Add(NodeBlock::Cast(it.block())); | 669 continue; |
906 } | 670 } |
907 } | 671 it.node()->clear_partially_dependent(); |
908 for (int block_index = 0; block_index < blocks.length(); block_index++) { | 672 if (it.node()->PostGarbageCollectionProcessing(isolate_)) { |
909 NodeBlock* block = blocks[block_index]; | 673 if (initial_post_gc_processing_count != post_gc_processing_count_) { |
910 for (int node_index = 0; node_index < NodeBlock::kSize; node_index++) { | 674 // See the comment above. |
911 Node* node = block->node_at(node_index); | 675 return next_gc_likely_to_collect_more; |
912 if (!node->IsRetainer()) { | |
913 // Free nodes do not have weak callbacks. Do not use them to compute | |
914 // the next_gc_likely_to_collect_more. | |
915 continue; | |
916 } | 676 } |
917 node->clear_partially_dependent(); | 677 } |
918 if (node->PostGarbageCollectionProcessing(isolate_)) { | 678 if (!it.node()->IsRetainer()) { |
919 if (initial_post_gc_processing_count != post_gc_processing_count_) { | 679 next_gc_likely_to_collect_more = true; |
920 // See the comment above. | |
921 return next_gc_likely_to_collect_more; | |
922 } | |
923 } | |
924 if (!node->IsRetainer()) { | |
925 next_gc_likely_to_collect_more = true; | |
926 } | |
927 } | 680 } |
928 } | 681 } |
929 } | 682 } |
930 // Update the list of new space nodes. | 683 // Update the list of new space nodes. |
931 int last = 0; | 684 int last = 0; |
932 for (int i = 0; i < new_space_nodes_.length(); ++i) { | 685 for (int i = 0; i < new_space_nodes_.length(); ++i) { |
933 Node* node = new_space_nodes_[i]; | 686 Node* node = new_space_nodes_[i]; |
934 ASSERT(node->is_in_new_space_list()); | 687 ASSERT(node->is_in_new_space_list()); |
935 if (node->IsRetainer()) { | 688 if (node->IsRetainer()) { |
936 if (isolate_->heap()->InNewSpace(node->object())) { | 689 if (isolate_->heap()->InNewSpace(node->object())) { |
937 new_space_nodes_[last++] = node; | 690 new_space_nodes_[last++] = node; |
938 tracer->increment_nodes_copied_in_new_space(); | 691 tracer->increment_nodes_copied_in_new_space(); |
939 } else { | 692 } else { |
940 node->set_in_new_space_list(false); | 693 node->set_in_new_space_list(false); |
941 tracer->increment_nodes_promoted(); | 694 tracer->increment_nodes_promoted(); |
942 } | 695 } |
943 } else { | 696 } else { |
944 node->set_in_new_space_list(false); | 697 node->set_in_new_space_list(false); |
945 tracer->increment_nodes_died_in_new_space(); | 698 tracer->increment_nodes_died_in_new_space(); |
946 } | 699 } |
947 } | 700 } |
948 new_space_nodes_.Rewind(last); | 701 new_space_nodes_.Rewind(last); |
949 bool shouldPruneBlocks = collector != SCAVENGER; | |
950 SortBlocks(shouldPruneBlocks); | |
951 return next_gc_likely_to_collect_more; | 702 return next_gc_likely_to_collect_more; |
952 } | 703 } |
953 | 704 |
954 | 705 |
955 void GlobalHandles::IterateStrongRoots(ObjectVisitor* v) { | 706 void GlobalHandles::IterateStrongRoots(ObjectVisitor* v) { |
956 for (NodeIterator it(this); !it.done(); it.Advance()) { | 707 for (NodeIterator it(this); !it.done(); it.Advance()) { |
957 if (it.node()->IsStrongRetainer()) { | 708 if (it.node()->IsStrongRetainer()) { |
958 v->VisitPointer(it.node()->location()); | 709 v->VisitPointer(it.node()->location()); |
959 } | 710 } |
960 } | 711 } |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1008 if (it.node()->IsWeakRetainer() && | 759 if (it.node()->IsWeakRetainer() && |
1009 it.node()->object()->IsJSGlobalObject()) { | 760 it.node()->object()->IsJSGlobalObject()) { |
1010 count++; | 761 count++; |
1011 } | 762 } |
1012 } | 763 } |
1013 return count; | 764 return count; |
1014 } | 765 } |
1015 | 766 |
1016 | 767 |
1017 void GlobalHandles::RecordStats(HeapStats* stats) { | 768 void GlobalHandles::RecordStats(HeapStats* stats) { |
1018 NodeIterator::CountArray counts; | 769 *stats->global_handle_count = 0; |
1019 int total = NodeIterator::CollectStats(this, counts); | 770 *stats->weak_global_handle_count = 0; |
1020 *stats->global_handle_count = total; | 771 *stats->pending_global_handle_count = 0; |
1021 *stats->weak_global_handle_count = counts[Node::WEAK]; | 772 *stats->near_death_global_handle_count = 0; |
1022 *stats->pending_global_handle_count = counts[Node::PENDING]; | 773 *stats->free_global_handle_count = 0; |
1023 *stats->near_death_global_handle_count = counts[Node::NEAR_DEATH]; | 774 for (NodeIterator it(this); !it.done(); it.Advance()) { |
1024 *stats->free_global_handle_count = counts[Node::FREE]; | 775 *stats->global_handle_count += 1; |
| 776 if (it.node()->state() == Node::WEAK) { |
| 777 *stats->weak_global_handle_count += 1; |
| 778 } else if (it.node()->state() == Node::PENDING) { |
| 779 *stats->pending_global_handle_count += 1; |
| 780 } else if (it.node()->state() == Node::NEAR_DEATH) { |
| 781 *stats->near_death_global_handle_count += 1; |
| 782 } else if (it.node()->state() == Node::FREE) { |
| 783 *stats->free_global_handle_count += 1; |
| 784 } |
| 785 } |
1025 } | 786 } |
1026 | 787 |
1027 | |
1028 #ifdef DEBUG | 788 #ifdef DEBUG |
1029 | 789 |
1030 void GlobalHandles::PrintStats() { | 790 void GlobalHandles::PrintStats() { |
1031 NodeIterator::CountArray counts; | 791 int total = 0; |
1032 int total = NodeIterator::CollectStats(this, counts); | 792 int weak = 0; |
1033 size_t total_consumed = sizeof(NodeBlock) * number_of_blocks_; | 793 int pending = 0; |
| 794 int near_death = 0; |
| 795 int destroyed = 0; |
| 796 |
| 797 for (NodeIterator it(this); !it.done(); it.Advance()) { |
| 798 total++; |
| 799 if (it.node()->state() == Node::WEAK) weak++; |
| 800 if (it.node()->state() == Node::PENDING) pending++; |
| 801 if (it.node()->state() == Node::NEAR_DEATH) near_death++; |
| 802 if (it.node()->state() == Node::FREE) destroyed++; |
| 803 } |
| 804 |
1034 PrintF("Global Handle Statistics:\n"); | 805 PrintF("Global Handle Statistics:\n"); |
1035 PrintF(" allocated blocks = %d\n", number_of_blocks_); | 806 PrintF(" allocated memory = %" V8_PTR_PREFIX "dB\n", sizeof(Node) * total); |
1036 PrintF(" allocated memory = %" V8_PTR_PREFIX "dB\n", total_consumed); | 807 PrintF(" # weak = %d\n", weak); |
1037 PrintF(" # normal = %d\n", counts[Node::NORMAL]); | 808 PrintF(" # pending = %d\n", pending); |
1038 PrintF(" # weak = %d\n", counts[Node::WEAK]); | 809 PrintF(" # near_death = %d\n", near_death); |
1039 PrintF(" # pending = %d\n", counts[Node::PENDING]); | 810 PrintF(" # free = %d\n", destroyed); |
1040 PrintF(" # near_death = %d\n", counts[Node::NEAR_DEATH]); | |
1041 PrintF(" # free = %d\n", counts[Node::FREE]); | |
1042 PrintF(" # total = %d\n", total); | 811 PrintF(" # total = %d\n", total); |
1043 } | 812 } |
1044 | 813 |
1045 | 814 |
1046 void GlobalHandles::Print() { | 815 void GlobalHandles::Print() { |
1047 PrintF("Global handles:\n"); | 816 PrintF("Global handles:\n"); |
1048 for (NodeIterator it(this); !it.done(); it.Advance()) { | 817 for (NodeIterator it(this); !it.done(); it.Advance()) { |
1049 PrintF(" handle %p to %p%s\n", | 818 PrintF(" handle %p to %p%s\n", |
1050 reinterpret_cast<void*>(it.node()->location()), | 819 reinterpret_cast<void*>(it.node()->location()), |
1051 reinterpret_cast<void*>(it.node()->object()), | 820 reinterpret_cast<void*>(it.node()->object()), |
(...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1308 ASSERT_EQ(isolate->heap()->the_hole_value(), blocks_[block][offset]); | 1077 ASSERT_EQ(isolate->heap()->the_hole_value(), blocks_[block][offset]); |
1309 blocks_[block][offset] = object; | 1078 blocks_[block][offset] = object; |
1310 if (isolate->heap()->InNewSpace(object)) { | 1079 if (isolate->heap()->InNewSpace(object)) { |
1311 new_space_indices_.Add(size_); | 1080 new_space_indices_.Add(size_); |
1312 } | 1081 } |
1313 return size_++; | 1082 return size_++; |
1314 } | 1083 } |
1315 | 1084 |
1316 | 1085 |
1317 } } // namespace v8::internal | 1086 } } // namespace v8::internal |
OLD | NEW |