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