| 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 |