Chromium Code Reviews| 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 LAST_STATE = NEAR_DEATH | |
|
Michael Starzinger
2013/08/01 12:29:02
Let just rename this to STATE_COUNT or NUMBER_OF_S
| |
| 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 21 matching lines...) Expand all Loading... | |
| 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::NodeBlock { |
| 319 public: | 314 public: |
| 320 static const int kSize = 256; | 315 static const int kSize = 256; |
| 321 | 316 |
| 322 explicit NodeBlock(GlobalHandles* global_handles, NodeBlock* next) | 317 explicit NodeBlock(GlobalHandles* global_handles) |
| 323 : next_(next), | 318 : used_nodes_(0), |
| 324 used_nodes_(0), | 319 first_free_(NULL), |
| 325 next_used_(NULL), | 320 next_block_(NULL), |
| 326 prev_used_(NULL), | 321 prev_block_(NULL), |
| 327 global_handles_(global_handles) {} | 322 global_handles_(global_handles) { |
| 328 | 323 // Initialize nodes |
| 329 void PutNodesOnFreeList(Node** first_free) { | 324 Node* first_free = first_free_; |
| 330 for (int i = kSize - 1; i >= 0; --i) { | 325 for (int i = kSize - 1; i >= 0; --i) { |
| 331 nodes_[i].Initialize(i, first_free); | 326 nodes_[i].Initialize(i, first_free); |
| 332 } | 327 first_free = &nodes_[i]; |
| 333 } | 328 } |
| 329 first_free_ = first_free; | |
| 330 // Link into global_handles | |
| 331 ASSERT(global_handles->first_non_full_block_ == NULL); | |
| 332 global_handles->first_non_full_block_ = this; | |
| 333 global_handles->number_of_blocks_++; | |
| 334 if (global_handles->first_block_ == NULL) { | |
| 335 ASSERT(global_handles->last_block_ == NULL); | |
| 336 global_handles->first_block_ = this; | |
| 337 global_handles->last_block_ = this; | |
| 338 return; | |
| 339 } | |
| 340 ASSERT(global_handles->last_block_ != NULL); | |
| 341 prev_block_ = global_handles->last_block_; | |
| 342 prev_block_->next_block_ = this; | |
| 343 global_handles->last_block_ = this; | |
| 344 } | |
| 345 | |
| 346 Node* Acquire(Object* o) { | |
| 347 ASSERT(used_nodes_ < kSize); | |
| 348 ASSERT(first_free_ != NULL); | |
| 349 ASSERT(global_handles_->first_non_full_block_ == this); | |
| 350 // Remove from free list | |
| 351 Node* node = first_free_; | |
| 352 first_free_ = node->next_free(); | |
| 353 // Increment counters | |
| 354 global_handles_->isolate()->counters()->global_handles()->Increment(); | |
| 355 global_handles_->number_of_global_handles_++; | |
| 356 // Initialize node with value | |
| 357 node->Acquire(o); | |
| 358 // Move block out of first_non_full_block_ if it becomes full | |
| 359 bool now_full = ++used_nodes_ == kSize; | |
| 360 if (now_full) { | |
| 361 global_handles_->first_non_full_block_ = next_block_; | |
| 362 } | |
| 363 return node; | |
| 364 } | |
| 365 | |
| 366 void Release(Node* node) { | |
| 367 ASSERT(used_nodes_ > 0); | |
| 368 // Add to free list | |
| 369 node->set_next_free(first_free_); | |
| 370 first_free_ = node; | |
| 371 // Decrement counters | |
| 372 global_handles_->isolate()->counters()->global_handles()->Decrement(); | |
| 373 global_handles_->number_of_global_handles_--; | |
| 374 // Move this block to first_non_full_block_ if necessary | |
| 375 bool was_full = used_nodes_-- == kSize; | |
| 376 if (!was_full) return; | |
| 377 ASSERT(first_free_->next_free() == NULL); | |
| 378 ASSERT(global_handles_->first_non_full_block_ != this); | |
| 379 // Simple case: last block becomes non full. Just mark. | |
| 380 if (next_block_ == NULL) { | |
| 381 ASSERT(global_handles_->last_block_ == this); | |
| 382 ASSERT(global_handles_->first_non_full_block_ == NULL); | |
| 383 global_handles_->first_non_full_block_ = this; | |
| 384 return; | |
| 385 } | |
| 386 ASSERT(global_handles_->last_block_ != this); | |
| 387 // Unlink prev_block_ and next_block_ | |
| 388 if (prev_block_ == NULL) { | |
| 389 // First block becomes non full | |
| 390 ASSERT(global_handles_->first_block_ == this); | |
| 391 global_handles_->first_block_ = next_block_; | |
| 392 next_block_->prev_block_ = NULL; | |
| 393 } else { | |
| 394 ASSERT(global_handles_->first_block_ != this); | |
| 395 prev_block_->next_block_ = next_block_; | |
| 396 next_block_->prev_block_ = prev_block_; | |
| 397 } | |
| 398 // Relink into first_non_full_block_ position | |
| 399 if (global_handles_->first_non_full_block_ == NULL) { | |
| 400 // Link into last position. | |
| 401 next_block_ = NULL; | |
| 402 prev_block_ = global_handles_->last_block_; | |
| 403 ASSERT(prev_block_->next_block_ == NULL); | |
| 404 prev_block_->next_block_ = this; | |
| 405 global_handles_->last_block_ = this; | |
| 406 } else { | |
| 407 next_block_ = global_handles_->first_non_full_block_; | |
| 408 prev_block_ = next_block_->prev_block_; | |
| 409 next_block_->prev_block_ = this; | |
| 410 if (prev_block_ == NULL) { | |
| 411 // link into first position | |
| 412 ASSERT(global_handles_->first_block_ == next_block_); | |
| 413 global_handles_->first_block_ = this; | |
| 414 } else { | |
| 415 ASSERT(global_handles_->first_block_ != next_block_); | |
| 416 prev_block_->next_block_ = this; | |
| 417 } | |
| 418 } | |
| 419 // Update first_non_full_block_ | |
| 420 global_handles_->first_non_full_block_ = this; | |
| 421 } | |
| 422 | |
| 423 static void SortBlocks(GlobalHandles* global_handles); | |
| 424 static void PruneBlocks(GlobalHandles* global_handles); | |
| 425 // Needed for quicksort | |
| 426 static int CompareBlocks(const void* a, const void* b); | |
| 334 | 427 |
| 335 Node* node_at(int index) { | 428 Node* node_at(int index) { |
| 336 ASSERT(0 <= index && index < kSize); | 429 ASSERT(0 <= index && index < kSize); |
| 337 return &nodes_[index]; | 430 return &nodes_[index]; |
| 338 } | 431 } |
| 339 | 432 |
| 340 void IncreaseUses() { | 433 #ifdef DEBUG |
| 341 ASSERT(used_nodes_ < kSize); | 434 int LengthOfFreeList() { |
| 342 if (used_nodes_++ == 0) { | 435 int count = 0; |
| 343 NodeBlock* old_first = global_handles_->first_used_block_; | 436 Node* node = first_free_; |
| 344 global_handles_->first_used_block_ = this; | 437 while (node != NULL) { |
| 345 next_used_ = old_first; | 438 count++; |
| 346 prev_used_ = NULL; | 439 node = node->next_free(); |
| 347 if (old_first == NULL) return; | 440 } |
| 348 old_first->prev_used_ = this; | 441 return count; |
| 349 } | 442 } |
| 350 } | 443 #endif |
| 351 | 444 |
| 352 void DecreaseUses() { | 445 bool IsUnused() { return used_nodes_ == 0; } |
| 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 | 446 |
| 363 GlobalHandles* global_handles() { return global_handles_; } | 447 GlobalHandles* global_handles() { return global_handles_; } |
| 364 | 448 int used_nodes() const { return used_nodes_; } |
| 365 // Next block in the list of all blocks. | 449 NodeBlock* next_block() const { return next_block_; } |
| 366 NodeBlock* next() const { return next_; } | 450 NodeBlock* prev_block() const { return prev_block_; } |
| 367 | |
| 368 // Next/previous block in the list of blocks with used nodes. | |
| 369 NodeBlock* next_used() const { return next_used_; } | |
| 370 NodeBlock* prev_used() const { return prev_used_; } | |
| 371 | 451 |
| 372 private: | 452 private: |
| 373 Node nodes_[kSize]; | 453 Node nodes_[kSize]; |
| 374 NodeBlock* const next_; | |
| 375 int used_nodes_; | 454 int used_nodes_; |
| 376 NodeBlock* next_used_; | 455 Node* first_free_; |
| 377 NodeBlock* prev_used_; | 456 NodeBlock* next_block_; |
| 457 NodeBlock* prev_block_; | |
| 378 GlobalHandles* global_handles_; | 458 GlobalHandles* global_handles_; |
| 379 }; | 459 }; |
| 380 | 460 |
| 381 | 461 |
| 462 #ifdef DEBUG | |
| 463 void GlobalHandles::VerifyBlockInvariants() { | |
| 464 int number_of_blocks = 0; | |
| 465 int number_of_handles = 0; | |
| 466 NodeBlock* first_non_full_block = NULL; | |
| 467 NodeBlock* block = first_block_; | |
| 468 NodeBlock* prev_block = NULL; | |
| 469 while (block != NULL) { | |
| 470 number_of_blocks++; | |
| 471 int used_nodes = block->used_nodes(); | |
| 472 number_of_handles += used_nodes; | |
| 473 int unused_nodes = block->LengthOfFreeList(); | |
| 474 ASSERT_EQ(used_nodes + unused_nodes, NodeBlock::kSize); | |
| 475 if (first_non_full_block != NULL) { | |
| 476 ASSERT_LT(used_nodes, NodeBlock::kSize); | |
| 477 } else if (used_nodes < NodeBlock::kSize) { | |
| 478 first_non_full_block = block; | |
| 479 } else { | |
| 480 ASSERT_EQ(used_nodes, NodeBlock::kSize); | |
| 481 } | |
| 482 prev_block = block; | |
| 483 block = block->next_block(); | |
| 484 } | |
| 485 ASSERT_EQ(prev_block, last_block_); | |
| 486 ASSERT_EQ(number_of_handles, number_of_global_handles_); | |
| 487 ASSERT_EQ(number_of_blocks, number_of_blocks_); | |
| 488 ASSERT_EQ(first_non_full_block, first_non_full_block_); | |
| 489 } | |
| 490 #endif | |
| 491 | |
| 492 | |
| 493 int GlobalHandles::NodeBlock::CompareBlocks(const void* a, const void* b) { | |
| 494 const NodeBlock* block_a = | |
| 495 *reinterpret_cast<const NodeBlock**>(reinterpret_cast<uintptr_t>(a)); | |
| 496 const NodeBlock* block_b = | |
| 497 *reinterpret_cast<const NodeBlock**>(reinterpret_cast<uintptr_t>(b)); | |
| 498 if (block_a->used_nodes_ > block_b->used_nodes_) return -1; | |
| 499 if (block_a->used_nodes_ == block_b->used_nodes_) return 0; | |
| 500 return 1; | |
| 501 } | |
| 502 | |
| 503 | |
| 504 void GlobalHandles::NodeBlock::SortBlocks(GlobalHandles* global_handles) { | |
| 505 int number_of_blocks = global_handles->number_of_blocks_; | |
| 506 // Always sort at least 2 blocks | |
| 507 if (number_of_blocks <= 1) return; | |
| 508 // Build array of blocks | |
| 509 ScopedVector<NodeBlock*> blocks(number_of_blocks); | |
| 510 { | |
| 511 NodeBlock* block = global_handles->first_block_; | |
| 512 for (int i = 0; block != NULL; i++) { | |
| 513 blocks[i] = block; | |
| 514 block = block->next_block(); | |
| 515 } | |
| 516 } | |
| 517 // Sort blocks | |
| 518 qsort(blocks.start(), number_of_blocks, sizeof(blocks[0]), CompareBlocks); | |
| 519 // Relink blocks | |
| 520 NodeBlock* first_non_full_block = NULL; | |
| 521 { | |
| 522 NodeBlock* first_block = blocks[0]; | |
| 523 global_handles->first_block_ = first_block; | |
| 524 first_block->prev_block_ = NULL; | |
| 525 first_block->next_block_ = blocks[1]; | |
| 526 if (first_block->used_nodes_ < kSize) first_non_full_block = first_block; | |
| 527 } | |
| 528 for (int i = 1; i < number_of_blocks-1; i++) { | |
| 529 NodeBlock* block = blocks[i]; | |
| 530 block->prev_block_ = blocks[i-1]; | |
| 531 block->next_block_ = blocks[i+1]; | |
| 532 if (first_non_full_block == NULL && block->used_nodes_ < kSize) { | |
| 533 first_non_full_block = block; | |
| 534 } | |
| 535 } | |
| 536 { | |
| 537 NodeBlock* last_block = blocks[number_of_blocks-1]; | |
| 538 global_handles->last_block_ = last_block; | |
| 539 last_block->prev_block_ = blocks[number_of_blocks-2]; | |
| 540 last_block->next_block_ = NULL; | |
| 541 if (first_non_full_block == NULL && last_block->used_nodes_ < kSize) { | |
| 542 first_non_full_block = last_block; | |
| 543 } | |
| 544 } | |
| 545 global_handles->first_non_full_block_ = first_non_full_block; | |
| 546 } | |
| 547 | |
| 548 | |
| 549 void GlobalHandles::NodeBlock::PruneBlocks(GlobalHandles* global_handles) { | |
| 550 static const double kUnusedPercentage = 0.30; | |
| 551 static const double kUsedPercentage = 1.30; | |
| 552 ASSERT(global_handles->last_block_ != NULL); | |
| 553 // Have at least one block available for deletion. | |
| 554 int total_slots = global_handles->number_of_blocks_*NodeBlock::kSize; | |
|
Michael Starzinger
2013/08/01 12:29:02
nit: Whitespace around operators. Here and several
| |
| 555 const int total_used = global_handles->number_of_global_handles_; | |
| 556 const int target_unused = static_cast<int>(Max( | |
| 557 total_used*kUsedPercentage, | |
| 558 total_slots*kUnusedPercentage)); | |
| 559 NodeBlock* block = global_handles->last_block_; | |
| 560 int blocks_deleted = 0; | |
| 561 while (block->IsUnused()) { | |
| 562 // Not worth deleting | |
| 563 if (total_slots - total_used < target_unused) break; | |
| 564 // Don't delete only remaining block | |
| 565 if (block->prev_block() == NULL) break; | |
| 566 // Delete | |
| 567 NodeBlock* tmp = block; | |
| 568 block = block->prev_block(); | |
| 569 total_slots -= NodeBlock::kSize; | |
| 570 delete tmp; | |
| 571 blocks_deleted++; | |
| 572 } | |
| 573 if (blocks_deleted == 0) return; | |
| 574 block->next_block_ = NULL; | |
| 575 global_handles->last_block_ = block; | |
| 576 global_handles->number_of_blocks_ -= blocks_deleted; | |
| 577 } | |
| 578 | |
| 579 | |
| 580 void GlobalHandles::SortBlocks(bool shouldPrune) { | |
| 581 #ifdef DEBUG | |
| 582 VerifyBlockInvariants(); | |
| 583 #endif | |
| 584 // Nothing to sort or prune | |
| 585 if (first_non_full_block_ == NULL || first_block_ == last_block_) return; | |
| 586 NodeBlock::SortBlocks(this); | |
| 587 #ifdef DEBUG | |
| 588 VerifyBlockInvariants(); | |
| 589 #endif | |
| 590 if (!shouldPrune) return; | |
| 591 NodeBlock::PruneBlocks(this); | |
| 592 #ifdef DEBUG | |
| 593 VerifyBlockInvariants(); | |
| 594 #endif | |
| 595 } | |
| 596 | |
| 597 | |
| 382 GlobalHandles* GlobalHandles::Node::GetGlobalHandles() { | 598 GlobalHandles* GlobalHandles::Node::GetGlobalHandles() { |
| 383 return FindBlock()->global_handles(); | 599 return FindBlock()->global_handles(); |
| 384 } | 600 } |
| 385 | 601 |
| 386 | 602 |
| 387 GlobalHandles::NodeBlock* GlobalHandles::Node::FindBlock() { | 603 GlobalHandles::NodeBlock* GlobalHandles::Node::FindBlock() { |
| 388 intptr_t ptr = reinterpret_cast<intptr_t>(this); | 604 intptr_t ptr = reinterpret_cast<intptr_t>(this); |
| 389 ptr = ptr - index_ * sizeof(Node); | 605 ptr = ptr - index_ * sizeof(Node); |
| 390 NodeBlock* block = reinterpret_cast<NodeBlock*>(ptr); | 606 NodeBlock* block = reinterpret_cast<NodeBlock*>(ptr); |
| 391 ASSERT(block->node_at(index_) == this); | 607 ASSERT(block->node_at(index_) == this); |
| 392 return block; | 608 return block; |
| 393 } | 609 } |
| 394 | 610 |
| 395 | 611 |
| 396 void GlobalHandles::Node::IncreaseBlockUses() { | 612 void GlobalHandles::Node::ReleaseFromBlock() { |
| 397 NodeBlock* node_block = FindBlock(); | 613 FindBlock()->Release(this); |
| 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 } | 614 } |
| 414 | 615 |
| 415 | 616 |
| 416 class GlobalHandles::NodeIterator { | 617 class GlobalHandles::NodeIterator { |
| 417 public: | 618 public: |
| 418 explicit NodeIterator(GlobalHandles* global_handles) | 619 explicit NodeIterator(GlobalHandles* global_handles) |
| 419 : block_(global_handles->first_used_block_), | 620 : block_(global_handles->first_block_), |
| 420 index_(0) {} | 621 index_(0) { |
| 622 SkipUnused(); | |
| 623 } | |
| 421 | 624 |
| 422 bool done() const { return block_ == NULL; } | 625 bool done() const { return block_ == NULL; } |
| 423 | 626 |
| 424 Node* node() const { | 627 Node* node() const { |
| 425 ASSERT(!done()); | 628 ASSERT(!done()); |
| 426 return block_->node_at(index_); | 629 return block_->node_at(index_); |
| 427 } | 630 } |
| 428 | 631 |
| 429 void Advance() { | 632 void Advance() { |
| 430 ASSERT(!done()); | 633 ASSERT(!done()); |
| 431 if (++index_ < NodeBlock::kSize) return; | 634 if (++index_ < NodeBlock::kSize) return; |
| 432 index_ = 0; | 635 index_ = 0; |
| 433 block_ = block_->next_used(); | 636 block_ = block_->next_block(); |
| 637 SkipUnused(); | |
| 434 } | 638 } |
| 435 | 639 |
| 640 static const int kCountArraySize = Node::LAST_STATE + 1; | |
|
Michael Starzinger
2013/08/01 12:29:02
This constant is obsolete, see comment at the top
| |
| 641 typedef int CountArray[kCountArraySize]; | |
| 642 static int CollectStats(GlobalHandles* global_handles, CountArray counts); | |
| 643 | |
| 436 private: | 644 private: |
| 645 inline void SkipUnused() { | |
| 646 while (block_ != NULL && block_->IsUnused()) block_ = block_->next_block(); | |
| 647 } | |
| 648 | |
| 437 NodeBlock* block_; | 649 NodeBlock* block_; |
| 438 int index_; | 650 int index_; |
| 439 | 651 |
| 440 DISALLOW_COPY_AND_ASSIGN(NodeIterator); | 652 DISALLOW_COPY_AND_ASSIGN(NodeIterator); |
| 441 }; | 653 }; |
| 442 | 654 |
| 443 | 655 |
| 656 int GlobalHandles::NodeIterator::CollectStats(GlobalHandles* global_handles, | |
| 657 CountArray counts) { | |
| 658 for (int i = 0; i < kCountArraySize; i++) { | |
| 659 counts[i] = 0; | |
| 660 } | |
| 661 int total = 0; | |
| 662 for (NodeIterator it(global_handles); !it.done(); it.Advance()) { | |
| 663 total++; | |
| 664 Node::State state = it.node()->state(); | |
| 665 ASSERT(state >= 0 && state < kCountArraySize); | |
| 666 counts[state]++; | |
| 667 } | |
| 668 // NodeIterator skips empty blocks | |
| 669 int skipped = global_handles->number_of_blocks_ * NodeBlock::kSize - total; | |
| 670 total += skipped; | |
| 671 counts[Node::FREE] += total; | |
| 672 return total; | |
| 673 } | |
| 674 | |
| 675 | |
| 444 GlobalHandles::GlobalHandles(Isolate* isolate) | 676 GlobalHandles::GlobalHandles(Isolate* isolate) |
| 445 : isolate_(isolate), | 677 : isolate_(isolate), |
| 678 number_of_blocks_(0), | |
| 446 number_of_global_handles_(0), | 679 number_of_global_handles_(0), |
| 447 first_block_(NULL), | 680 first_block_(NULL), |
| 448 first_used_block_(NULL), | 681 last_block_(NULL), |
| 449 first_free_(NULL), | 682 first_non_full_block_(NULL), |
| 450 post_gc_processing_count_(0), | 683 post_gc_processing_count_(0), |
| 451 object_group_connections_(kObjectGroupConnectionsCapacity) {} | 684 object_group_connections_(kObjectGroupConnectionsCapacity) {} |
| 452 | 685 |
| 453 | 686 |
| 454 GlobalHandles::~GlobalHandles() { | 687 GlobalHandles::~GlobalHandles() { |
| 455 NodeBlock* block = first_block_; | 688 NodeBlock* block = first_block_; |
| 456 while (block != NULL) { | 689 while (block != NULL) { |
| 457 NodeBlock* tmp = block->next(); | 690 NodeBlock* tmp = block->next_block(); |
| 458 delete block; | 691 delete block; |
| 459 block = tmp; | 692 block = tmp; |
| 460 } | 693 } |
| 461 first_block_ = NULL; | 694 first_block_ = NULL; |
| 462 } | 695 } |
| 463 | 696 |
| 464 | 697 |
| 465 Handle<Object> GlobalHandles::Create(Object* value) { | 698 Handle<Object> GlobalHandles::Create(Object* value) { |
| 466 if (first_free_ == NULL) { | 699 if (first_non_full_block_ == NULL) new NodeBlock(this); |
| 467 first_block_ = new NodeBlock(this, first_block_); | 700 ASSERT(first_non_full_block_ != NULL); |
| 468 first_block_->PutNodesOnFreeList(&first_free_); | |
| 469 } | |
| 470 ASSERT(first_free_ != NULL); | |
| 471 // Take the first node in the free list. | 701 // Take the first node in the free list. |
| 472 Node* result = first_free_; | 702 Node* result = first_non_full_block_->Acquire(value); |
| 473 first_free_ = result->next_free(); | |
| 474 result->Acquire(value); | |
| 475 if (isolate_->heap()->InNewSpace(value) && | 703 if (isolate_->heap()->InNewSpace(value) && |
| 476 !result->is_in_new_space_list()) { | 704 !result->is_in_new_space_list()) { |
| 477 new_space_nodes_.Add(result); | 705 new_space_nodes_.Add(result); |
| 478 result->set_in_new_space_list(true); | 706 result->set_in_new_space_list(true); |
| 479 } | 707 } |
| 480 return result->handle(); | 708 return result->handle(); |
| 481 } | 709 } |
| 482 | 710 |
| 483 | 711 |
| 484 void GlobalHandles::Destroy(Object** location) { | 712 void GlobalHandles::Destroy(Object** location) { |
| (...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 691 } else { | 919 } else { |
| 692 node->set_in_new_space_list(false); | 920 node->set_in_new_space_list(false); |
| 693 tracer->increment_nodes_promoted(); | 921 tracer->increment_nodes_promoted(); |
| 694 } | 922 } |
| 695 } else { | 923 } else { |
| 696 node->set_in_new_space_list(false); | 924 node->set_in_new_space_list(false); |
| 697 tracer->increment_nodes_died_in_new_space(); | 925 tracer->increment_nodes_died_in_new_space(); |
| 698 } | 926 } |
| 699 } | 927 } |
| 700 new_space_nodes_.Rewind(last); | 928 new_space_nodes_.Rewind(last); |
| 929 bool shouldPruneBlocks = collector != SCAVENGER; | |
| 930 SortBlocks(shouldPruneBlocks); | |
| 701 return next_gc_likely_to_collect_more; | 931 return next_gc_likely_to_collect_more; |
| 702 } | 932 } |
| 703 | 933 |
| 704 | 934 |
| 705 void GlobalHandles::IterateStrongRoots(ObjectVisitor* v) { | 935 void GlobalHandles::IterateStrongRoots(ObjectVisitor* v) { |
| 706 for (NodeIterator it(this); !it.done(); it.Advance()) { | 936 for (NodeIterator it(this); !it.done(); it.Advance()) { |
| 707 if (it.node()->IsStrongRetainer()) { | 937 if (it.node()->IsStrongRetainer()) { |
| 708 v->VisitPointer(it.node()->location()); | 938 v->VisitPointer(it.node()->location()); |
| 709 } | 939 } |
| 710 } | 940 } |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 758 if (it.node()->IsWeakRetainer() && | 988 if (it.node()->IsWeakRetainer() && |
| 759 it.node()->object()->IsJSGlobalObject()) { | 989 it.node()->object()->IsJSGlobalObject()) { |
| 760 count++; | 990 count++; |
| 761 } | 991 } |
| 762 } | 992 } |
| 763 return count; | 993 return count; |
| 764 } | 994 } |
| 765 | 995 |
| 766 | 996 |
| 767 void GlobalHandles::RecordStats(HeapStats* stats) { | 997 void GlobalHandles::RecordStats(HeapStats* stats) { |
| 768 *stats->global_handle_count = 0; | 998 NodeIterator::CountArray counts; |
| 769 *stats->weak_global_handle_count = 0; | 999 int total = NodeIterator::CollectStats(this, counts); |
| 770 *stats->pending_global_handle_count = 0; | 1000 *stats->global_handle_count = total; |
| 771 *stats->near_death_global_handle_count = 0; | 1001 *stats->weak_global_handle_count = counts[Node::WEAK]; |
| 772 *stats->free_global_handle_count = 0; | 1002 *stats->pending_global_handle_count = counts[Node::PENDING]; |
| 773 for (NodeIterator it(this); !it.done(); it.Advance()) { | 1003 *stats->near_death_global_handle_count = counts[Node::NEAR_DEATH]; |
| 774 *stats->global_handle_count += 1; | 1004 *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 } | 1005 } |
| 786 | 1006 |
| 1007 | |
| 787 #ifdef DEBUG | 1008 #ifdef DEBUG |
| 788 | 1009 |
| 789 void GlobalHandles::PrintStats() { | 1010 void GlobalHandles::PrintStats() { |
| 790 int total = 0; | 1011 NodeIterator::CountArray counts; |
| 791 int weak = 0; | 1012 int total = NodeIterator::CollectStats(this, counts); |
| 792 int pending = 0; | 1013 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"); | 1014 PrintF("Global Handle Statistics:\n"); |
| 805 PrintF(" allocated memory = %" V8_PTR_PREFIX "dB\n", sizeof(Node) * total); | 1015 PrintF(" allocated blocks = %d\n", number_of_blocks_); |
| 806 PrintF(" # weak = %d\n", weak); | 1016 PrintF(" allocated memory = %" V8_PTR_PREFIX "dB\n", total_consumed); |
| 807 PrintF(" # pending = %d\n", pending); | 1017 PrintF(" # normal = %d\n", counts[Node::NORMAL]); |
| 808 PrintF(" # near_death = %d\n", near_death); | 1018 PrintF(" # weak = %d\n", counts[Node::WEAK]); |
| 809 PrintF(" # free = %d\n", destroyed); | 1019 PrintF(" # pending = %d\n", counts[Node::PENDING]); |
| 1020 PrintF(" # near_death = %d\n", counts[Node::NEAR_DEATH]); | |
| 1021 PrintF(" # free = %d\n", counts[Node::FREE]); | |
| 810 PrintF(" # total = %d\n", total); | 1022 PrintF(" # total = %d\n", total); |
| 811 } | 1023 } |
| 812 | 1024 |
| 813 | 1025 |
| 814 void GlobalHandles::Print() { | 1026 void GlobalHandles::Print() { |
| 815 PrintF("Global handles:\n"); | 1027 PrintF("Global handles:\n"); |
| 816 for (NodeIterator it(this); !it.done(); it.Advance()) { | 1028 for (NodeIterator it(this); !it.done(); it.Advance()) { |
| 817 PrintF(" handle %p to %p%s\n", | 1029 PrintF(" handle %p to %p%s\n", |
| 818 reinterpret_cast<void*>(it.node()->location()), | 1030 reinterpret_cast<void*>(it.node()->location()), |
| 819 reinterpret_cast<void*>(it.node()->object()), | 1031 reinterpret_cast<void*>(it.node()->object()), |
| (...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1012 } | 1224 } |
| 1013 } | 1225 } |
| 1014 object_group_connections_.Clear(); | 1226 object_group_connections_.Clear(); |
| 1015 object_group_connections_.Initialize(kObjectGroupConnectionsCapacity); | 1227 object_group_connections_.Initialize(kObjectGroupConnectionsCapacity); |
| 1016 retainer_infos_.Clear(); | 1228 retainer_infos_.Clear(); |
| 1017 implicit_ref_connections_.Clear(); | 1229 implicit_ref_connections_.Clear(); |
| 1018 } | 1230 } |
| 1019 | 1231 |
| 1020 | 1232 |
| 1021 } } // namespace v8::internal | 1233 } } // namespace v8::internal |
| OLD | NEW |