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()) { |
| 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 for (int i = 0; i < kAllAnchorsSize; i++) { |
| 553 for (BlockListIterator it(all_anchors_[i]); !it.done(); it.Advance()) { |
| 554 BlockList* block = it.block(); |
| 555 number_of_blocks++; |
| 556 int used_nodes = block->used_nodes(); |
| 557 number_of_handles += used_nodes; |
| 558 int unused_nodes = block->LengthOfFreeList(); |
| 559 ASSERT_EQ(used_nodes + unused_nodes, NodeBlock::kSize); |
| 560 if (all_anchors_[i] == &full_blocks_) { |
| 561 ASSERT_EQ(NodeBlock::kSize, used_nodes); |
| 562 } else { |
| 563 ASSERT_NE(NodeBlock::kSize, used_nodes); |
| 564 } |
| 565 } |
| 566 } |
| 567 ASSERT_EQ(number_of_handles, number_of_global_handles_); |
| 568 ASSERT_EQ(number_of_blocks, number_of_blocks_); |
| 569 } |
| 570 #endif |
| 571 |
| 572 |
| 573 void GlobalHandles::SortBlocks(bool shouldPrune) { |
| 574 #ifdef DEBUG |
| 575 VerifyBlockInvariants(); |
| 576 #endif |
| 577 BlockList::SortBlocks(this, shouldPrune); |
| 578 #ifdef DEBUG |
| 579 VerifyBlockInvariants(); |
| 580 #endif |
| 581 } |
| 582 |
| 583 |
382 GlobalHandles* GlobalHandles::Node::GetGlobalHandles() { | 584 GlobalHandles* GlobalHandles::Node::GetGlobalHandles() { |
383 return FindBlock()->global_handles(); | 585 return FindBlock()->global_handles(); |
384 } | 586 } |
385 | 587 |
386 | 588 |
387 GlobalHandles::NodeBlock* GlobalHandles::Node::FindBlock() { | 589 GlobalHandles::NodeBlock* GlobalHandles::Node::FindBlock() { |
388 intptr_t ptr = reinterpret_cast<intptr_t>(this); | 590 return NodeBlock::From(this, index_); |
389 ptr = ptr - index_ * sizeof(Node); | 591 } |
390 NodeBlock* block = reinterpret_cast<NodeBlock*>(ptr); | 592 |
391 ASSERT(block->node_at(index_) == this); | 593 |
392 return block; | 594 void GlobalHandles::Node::ReleaseFromBlock() { |
393 } | 595 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 } | 596 } |
414 | 597 |
415 | 598 |
416 class GlobalHandles::NodeIterator { | 599 class GlobalHandles::NodeIterator { |
417 public: | 600 public: |
418 explicit NodeIterator(GlobalHandles* global_handles) | 601 explicit NodeIterator(GlobalHandles* global_handles) |
419 : block_(global_handles->first_used_block_), | 602 : all_anchors_(global_handles->all_anchors_), |
420 index_(0) {} | 603 block_(all_anchors_[0]), |
421 | 604 anchor_index_(0), |
422 bool done() const { return block_ == NULL; } | 605 node_index_(0) { |
| 606 AdvanceBlock(); |
| 607 } |
| 608 |
| 609 bool done() const { |
| 610 return anchor_index_ == kAllAnchorsSize; |
| 611 } |
423 | 612 |
424 Node* node() const { | 613 Node* node() const { |
425 ASSERT(!done()); | 614 ASSERT(!done()); |
426 return block_->node_at(index_); | 615 return NodeBlock::Cast(block_)->node_at(node_index_); |
427 } | 616 } |
428 | 617 |
429 void Advance() { | 618 void Advance() { |
430 ASSERT(!done()); | 619 ASSERT(!done()); |
431 if (++index_ < NodeBlock::kSize) return; | 620 if (++node_index_ < NodeBlock::kSize) return; |
432 index_ = 0; | 621 node_index_ = 0; |
433 block_ = block_->next_used(); | 622 AdvanceBlock(); |
434 } | 623 } |
| 624 |
| 625 typedef int CountArray[Node::NUMBER_OF_STATES]; |
| 626 static int CollectStats(GlobalHandles* global_handles, CountArray counts); |
435 | 627 |
436 private: | 628 private: |
437 NodeBlock* block_; | 629 void AdvanceBlock() { |
438 int index_; | 630 ASSERT(!done()); |
| 631 while (true) { |
| 632 block_ = block_->next(); |
| 633 // block is valid |
| 634 if (block_ != all_anchors_[anchor_index_]) { |
| 635 ASSERT(!done()); |
| 636 ASSERT(!block_->IsAnchor()); |
| 637 // skip empty blocks |
| 638 if (block_->IsUnused()) continue; |
| 639 return; |
| 640 } |
| 641 // jump lists |
| 642 anchor_index_++; |
| 643 if (anchor_index_ == kAllAnchorsSize) break; |
| 644 block_ = all_anchors_[anchor_index_]; |
| 645 } |
| 646 ASSERT(done()); |
| 647 } |
| 648 |
| 649 BlockList* const * const all_anchors_; |
| 650 BlockList* block_; |
| 651 int anchor_index_; |
| 652 int node_index_; |
439 | 653 |
440 DISALLOW_COPY_AND_ASSIGN(NodeIterator); | 654 DISALLOW_COPY_AND_ASSIGN(NodeIterator); |
441 }; | 655 }; |
442 | 656 |
443 | 657 |
| 658 int GlobalHandles::NodeIterator::CollectStats(GlobalHandles* global_handles, |
| 659 CountArray counts) { |
| 660 static const int kSize = Node::NUMBER_OF_STATES; |
| 661 for (int i = 0; i < kSize; i++) { |
| 662 counts[i] = 0; |
| 663 } |
| 664 int total = 0; |
| 665 for (NodeIterator it(global_handles); !it.done(); it.Advance()) { |
| 666 total++; |
| 667 Node::State state = it.node()->state(); |
| 668 ASSERT(state >= 0 && state < kSize); |
| 669 counts[state]++; |
| 670 } |
| 671 // NodeIterator skips empty blocks |
| 672 int skipped = global_handles->number_of_blocks_ * NodeBlock::kSize - total; |
| 673 total += skipped; |
| 674 counts[Node::FREE] += total; |
| 675 return total; |
| 676 } |
| 677 |
| 678 |
444 GlobalHandles::GlobalHandles(Isolate* isolate) | 679 GlobalHandles::GlobalHandles(Isolate* isolate) |
445 : isolate_(isolate), | 680 : isolate_(isolate), |
| 681 number_of_blocks_(0), |
446 number_of_global_handles_(0), | 682 number_of_global_handles_(0), |
447 first_block_(NULL), | |
448 first_used_block_(NULL), | |
449 first_free_(NULL), | |
450 post_gc_processing_count_(0), | 683 post_gc_processing_count_(0), |
451 object_group_connections_(kObjectGroupConnectionsCapacity) {} | 684 object_group_connections_(kObjectGroupConnectionsCapacity) { |
| 685 all_anchors_[0] = &full_blocks_; |
| 686 all_anchors_[1] = &non_full_blocks_; |
| 687 } |
452 | 688 |
453 | 689 |
454 GlobalHandles::~GlobalHandles() { | 690 GlobalHandles::~GlobalHandles() { |
455 NodeBlock* block = first_block_; | 691 for (int i = 0; i < kAllAnchorsSize; i++) { |
456 while (block != NULL) { | 692 BlockList* block = all_anchors_[i]->next(); |
457 NodeBlock* tmp = block->next(); | 693 while (block != all_anchors_[i]) { |
458 delete block; | 694 BlockList* tmp = block->next(); |
459 block = tmp; | 695 block->Detach(); |
460 } | 696 delete NodeBlock::Cast(block); |
461 first_block_ = NULL; | 697 block = tmp; |
| 698 } |
| 699 } |
462 } | 700 } |
463 | 701 |
464 | 702 |
465 Handle<Object> GlobalHandles::Create(Object* value) { | 703 Handle<Object> GlobalHandles::Create(Object* value) { |
466 if (first_free_ == NULL) { | 704 if (non_full_blocks_.IsDetached()) { |
467 first_block_ = new NodeBlock(this, first_block_); | 705 new NodeBlock(this); |
468 first_block_->PutNodesOnFreeList(&first_free_); | 706 ASSERT(!non_full_blocks_.IsDetached()); |
469 } | 707 } |
470 ASSERT(first_free_ != NULL); | 708 ASSERT(non_full_blocks_.IsAnchor()); |
471 // Take the first node in the free list. | 709 ASSERT(!non_full_blocks_.next()->IsAnchor()); |
472 Node* result = first_free_; | 710 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) && | 711 if (isolate_->heap()->InNewSpace(value) && |
476 !result->is_in_new_space_list()) { | 712 !result->is_in_new_space_list()) { |
477 new_space_nodes_.Add(result); | 713 new_space_nodes_.Add(result); |
478 result->set_in_new_space_list(true); | 714 result->set_in_new_space_list(true); |
479 } | 715 } |
480 return result->handle(); | 716 return result->handle(); |
481 } | 717 } |
482 | 718 |
483 | 719 |
484 void GlobalHandles::Destroy(Object** location) { | 720 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 | 890 // have been deleted in that round, so we need to bail out (or |
655 // restart the processing). | 891 // restart the processing). |
656 return next_gc_likely_to_collect_more; | 892 return next_gc_likely_to_collect_more; |
657 } | 893 } |
658 } | 894 } |
659 if (!node->IsRetainer()) { | 895 if (!node->IsRetainer()) { |
660 next_gc_likely_to_collect_more = true; | 896 next_gc_likely_to_collect_more = true; |
661 } | 897 } |
662 } | 898 } |
663 } else { | 899 } else { |
664 for (NodeIterator it(this); !it.done(); it.Advance()) { | 900 // Must cache all blocks, as NodeIterator can't survive mutation. |
665 if (!it.node()->IsRetainer()) { | 901 List<NodeBlock*> blocks(number_of_blocks_); |
666 // Free nodes do not have weak callbacks. Do not use them to compute | 902 for (int i = 0; i < kAllAnchorsSize; i++) { |
667 // the next_gc_likely_to_collect_more. | 903 for (BlockListIterator it(all_anchors_[i]); !it.done(); it.Advance()) { |
668 continue; | 904 blocks.Add(NodeBlock::Cast(it.block())); |
669 } | 905 } |
670 it.node()->clear_partially_dependent(); | 906 } |
671 if (it.node()->PostGarbageCollectionProcessing(isolate_)) { | 907 for (int block_index = 0; block_index < blocks.length(); block_index++) { |
672 if (initial_post_gc_processing_count != post_gc_processing_count_) { | 908 NodeBlock* block = blocks[block_index]; |
673 // See the comment above. | 909 for (int node_index = 0; node_index < NodeBlock::kSize; node_index++) { |
674 return next_gc_likely_to_collect_more; | 910 Node* node = block->node_at(node_index); |
| 911 if (!node->IsRetainer()) { |
| 912 // Free nodes do not have weak callbacks. Do not use them to compute |
| 913 // the next_gc_likely_to_collect_more. |
| 914 continue; |
675 } | 915 } |
676 } | 916 node->clear_partially_dependent(); |
677 if (!it.node()->IsRetainer()) { | 917 if (node->PostGarbageCollectionProcessing(isolate_)) { |
678 next_gc_likely_to_collect_more = true; | 918 if (initial_post_gc_processing_count != post_gc_processing_count_) { |
| 919 // See the comment above. |
| 920 return next_gc_likely_to_collect_more; |
| 921 } |
| 922 } |
| 923 if (!node->IsRetainer()) { |
| 924 next_gc_likely_to_collect_more = true; |
| 925 } |
679 } | 926 } |
680 } | 927 } |
681 } | 928 } |
682 // Update the list of new space nodes. | 929 // Update the list of new space nodes. |
683 int last = 0; | 930 int last = 0; |
684 for (int i = 0; i < new_space_nodes_.length(); ++i) { | 931 for (int i = 0; i < new_space_nodes_.length(); ++i) { |
685 Node* node = new_space_nodes_[i]; | 932 Node* node = new_space_nodes_[i]; |
686 ASSERT(node->is_in_new_space_list()); | 933 ASSERT(node->is_in_new_space_list()); |
687 if (node->IsRetainer()) { | 934 if (node->IsRetainer()) { |
688 if (isolate_->heap()->InNewSpace(node->object())) { | 935 if (isolate_->heap()->InNewSpace(node->object())) { |
689 new_space_nodes_[last++] = node; | 936 new_space_nodes_[last++] = node; |
690 tracer->increment_nodes_copied_in_new_space(); | 937 tracer->increment_nodes_copied_in_new_space(); |
691 } else { | 938 } else { |
692 node->set_in_new_space_list(false); | 939 node->set_in_new_space_list(false); |
693 tracer->increment_nodes_promoted(); | 940 tracer->increment_nodes_promoted(); |
694 } | 941 } |
695 } else { | 942 } else { |
696 node->set_in_new_space_list(false); | 943 node->set_in_new_space_list(false); |
697 tracer->increment_nodes_died_in_new_space(); | 944 tracer->increment_nodes_died_in_new_space(); |
698 } | 945 } |
699 } | 946 } |
700 new_space_nodes_.Rewind(last); | 947 new_space_nodes_.Rewind(last); |
| 948 bool shouldPruneBlocks = collector != SCAVENGER; |
| 949 SortBlocks(shouldPruneBlocks); |
701 return next_gc_likely_to_collect_more; | 950 return next_gc_likely_to_collect_more; |
702 } | 951 } |
703 | 952 |
704 | 953 |
705 void GlobalHandles::IterateStrongRoots(ObjectVisitor* v) { | 954 void GlobalHandles::IterateStrongRoots(ObjectVisitor* v) { |
706 for (NodeIterator it(this); !it.done(); it.Advance()) { | 955 for (NodeIterator it(this); !it.done(); it.Advance()) { |
707 if (it.node()->IsStrongRetainer()) { | 956 if (it.node()->IsStrongRetainer()) { |
708 v->VisitPointer(it.node()->location()); | 957 v->VisitPointer(it.node()->location()); |
709 } | 958 } |
710 } | 959 } |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
758 if (it.node()->IsWeakRetainer() && | 1007 if (it.node()->IsWeakRetainer() && |
759 it.node()->object()->IsJSGlobalObject()) { | 1008 it.node()->object()->IsJSGlobalObject()) { |
760 count++; | 1009 count++; |
761 } | 1010 } |
762 } | 1011 } |
763 return count; | 1012 return count; |
764 } | 1013 } |
765 | 1014 |
766 | 1015 |
767 void GlobalHandles::RecordStats(HeapStats* stats) { | 1016 void GlobalHandles::RecordStats(HeapStats* stats) { |
768 *stats->global_handle_count = 0; | 1017 NodeIterator::CountArray counts; |
769 *stats->weak_global_handle_count = 0; | 1018 int total = NodeIterator::CollectStats(this, counts); |
770 *stats->pending_global_handle_count = 0; | 1019 *stats->global_handle_count = total; |
771 *stats->near_death_global_handle_count = 0; | 1020 *stats->weak_global_handle_count = counts[Node::WEAK]; |
772 *stats->free_global_handle_count = 0; | 1021 *stats->pending_global_handle_count = counts[Node::PENDING]; |
773 for (NodeIterator it(this); !it.done(); it.Advance()) { | 1022 *stats->near_death_global_handle_count = counts[Node::NEAR_DEATH]; |
774 *stats->global_handle_count += 1; | 1023 *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 } | 1024 } |
786 | 1025 |
| 1026 |
787 #ifdef DEBUG | 1027 #ifdef DEBUG |
788 | 1028 |
789 void GlobalHandles::PrintStats() { | 1029 void GlobalHandles::PrintStats() { |
790 int total = 0; | 1030 NodeIterator::CountArray counts; |
791 int weak = 0; | 1031 int total = NodeIterator::CollectStats(this, counts); |
792 int pending = 0; | 1032 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"); | 1033 PrintF("Global Handle Statistics:\n"); |
805 PrintF(" allocated memory = %" V8_PTR_PREFIX "dB\n", sizeof(Node) * total); | 1034 PrintF(" allocated blocks = %d\n", number_of_blocks_); |
806 PrintF(" # weak = %d\n", weak); | 1035 PrintF(" allocated memory = %" V8_PTR_PREFIX "dB\n", total_consumed); |
807 PrintF(" # pending = %d\n", pending); | 1036 PrintF(" # normal = %d\n", counts[Node::NORMAL]); |
808 PrintF(" # near_death = %d\n", near_death); | 1037 PrintF(" # weak = %d\n", counts[Node::WEAK]); |
809 PrintF(" # free = %d\n", destroyed); | 1038 PrintF(" # pending = %d\n", counts[Node::PENDING]); |
| 1039 PrintF(" # near_death = %d\n", counts[Node::NEAR_DEATH]); |
| 1040 PrintF(" # free = %d\n", counts[Node::FREE]); |
810 PrintF(" # total = %d\n", total); | 1041 PrintF(" # total = %d\n", total); |
811 } | 1042 } |
812 | 1043 |
813 | 1044 |
814 void GlobalHandles::Print() { | 1045 void GlobalHandles::Print() { |
815 PrintF("Global handles:\n"); | 1046 PrintF("Global handles:\n"); |
816 for (NodeIterator it(this); !it.done(); it.Advance()) { | 1047 for (NodeIterator it(this); !it.done(); it.Advance()) { |
817 PrintF(" handle %p to %p%s\n", | 1048 PrintF(" handle %p to %p%s\n", |
818 reinterpret_cast<void*>(it.node()->location()), | 1049 reinterpret_cast<void*>(it.node()->location()), |
819 reinterpret_cast<void*>(it.node()->object()), | 1050 reinterpret_cast<void*>(it.node()->object()), |
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1012 } | 1243 } |
1013 } | 1244 } |
1014 object_group_connections_.Clear(); | 1245 object_group_connections_.Clear(); |
1015 object_group_connections_.Initialize(kObjectGroupConnectionsCapacity); | 1246 object_group_connections_.Initialize(kObjectGroupConnectionsCapacity); |
1016 retainer_infos_.Clear(); | 1247 retainer_infos_.Clear(); |
1017 implicit_ref_connections_.Clear(); | 1248 implicit_ref_connections_.Clear(); |
1018 } | 1249 } |
1019 | 1250 |
1020 | 1251 |
1021 } } // namespace v8::internal | 1252 } } // namespace v8::internal |
OLD | NEW |