1 // Copyright 2009 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "src/v8.h" 6 7 #include "src/api.h" 8 #include "src/global-handles.h" 9 10 #include "src/vm-state-inl.h" 11 12 namespace v8 { 13 namespace internal { 14 15 ~ObjectGroup()16 ObjectGroup::~ObjectGroup() { 17 if (info != NULL) info->Dispose(); 18 delete[] objects; 19 } 20 21 ~ImplicitRefGroup()22 ImplicitRefGroup::~ImplicitRefGroup() { 23 delete[] children; 24 } 25 26 27 class GlobalHandles::Node { 28 public: 29 // State transition diagram: 30 // FREE -> NORMAL <-> WEAK -> PENDING -> NEAR_DEATH -> { NORMAL, WEAK, FREE } 31 enum State { 32 FREE = 0, 33 NORMAL, // Normal global handle. 34 WEAK, // Flagged as weak but not yet finalized. 35 PENDING, // Has been recognized as only reachable by weak handles. 36 NEAR_DEATH // Callback has informed the handle is near death. 37 }; 38 39 // Maps handle location (slot) to the containing node. FromLocation(Object ** location)40 static Node* FromLocation(Object** location) { 41 DCHECK(OFFSET_OF(Node, object_) == 0); 42 return reinterpret_cast<Node*>(location); 43 } 44 Node()45 Node() { 46 DCHECK(OFFSET_OF(Node, class_id_) == Internals::kNodeClassIdOffset); 47 DCHECK(OFFSET_OF(Node, flags_) == Internals::kNodeFlagsOffset); 48 STATIC_ASSERT(static_cast<int>(NodeState::kMask) == 49 Internals::kNodeStateMask); 50 STATIC_ASSERT(WEAK == Internals::kNodeStateIsWeakValue); 51 STATIC_ASSERT(PENDING == Internals::kNodeStateIsPendingValue); 52 STATIC_ASSERT(NEAR_DEATH == Internals::kNodeStateIsNearDeathValue); 53 STATIC_ASSERT(static_cast<int>(IsIndependent::kShift) == 54 Internals::kNodeIsIndependentShift); 55 STATIC_ASSERT(static_cast<int>(IsPartiallyDependent::kShift) == 56 Internals::kNodeIsPartiallyDependentShift); 57 } 58 59 #ifdef ENABLE_HANDLE_ZAPPING ~Node()60 ~Node() { 61 // TODO(1428): if it's a weak handle we should have invoked its callback. 62 // Zap the values for eager trapping. 63 object_ = reinterpret_cast<Object*>(kGlobalHandleZapValue); 64 class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId; 65 index_ = 0; 66 set_independent(false); 67 set_partially_dependent(false); 68 set_in_new_space_list(false); 69 parameter_or_next_free_.next_free = NULL; 70 weak_callback_ = NULL; 71 } 72 #endif 73 Initialize(int index,Node ** first_free)74 void Initialize(int index, Node** first_free) { 75 index_ = static_cast<uint8_t>(index); 76 DCHECK(static_cast<int>(index_) == index); 77 set_state(FREE); 78 set_in_new_space_list(false); 79 parameter_or_next_free_.next_free = *first_free; 80 *first_free = this; 81 } 82 Acquire(Object * object)83 void Acquire(Object* object) { 84 DCHECK(state() == FREE); 85 object_ = object; 86 class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId; 87 set_independent(false); 88 set_partially_dependent(false); 89 set_state(NORMAL); 90 parameter_or_next_free_.parameter = NULL; 91 weak_callback_ = NULL; 92 IncreaseBlockUses(); 93 } 94 Release()95 void Release() { 96 DCHECK(state() != FREE); 97 set_state(FREE); 98 // Zap the values for eager trapping. 99 object_ = reinterpret_cast<Object*>(kGlobalHandleZapValue); 100 class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId; 101 set_independent(false); 102 set_partially_dependent(false); 103 weak_callback_ = NULL; 104 DecreaseBlockUses(); 105 } 106 107 // Object slot accessors. object() const108 Object* object() const { return object_; } location()109 Object** location() { return &object_; } handle()110 Handle<Object> handle() { return Handle<Object>(location()); } 111 112 // Wrapper class ID accessors. has_wrapper_class_id() const113 bool has_wrapper_class_id() const { 114 return class_id_ != v8::HeapProfiler::kPersistentHandleNoClassId; 115 } 116 wrapper_class_id() const117 uint16_t wrapper_class_id() const { return class_id_; } 118 119 // State and flag accessors. 120 state() const121 State state() const { 122 return NodeState::decode(flags_); 123 } set_state(State state)124 void set_state(State state) { 125 flags_ = NodeState::update(flags_, state); 126 } 127 is_independent()128 bool is_independent() { 129 return IsIndependent::decode(flags_); 130 } set_independent(bool v)131 void set_independent(bool v) { 132 flags_ = IsIndependent::update(flags_, v); 133 } 134 is_partially_dependent()135 bool is_partially_dependent() { 136 return IsPartiallyDependent::decode(flags_); 137 } set_partially_dependent(bool v)138 void set_partially_dependent(bool v) { 139 flags_ = IsPartiallyDependent::update(flags_, v); 140 } 141 is_in_new_space_list()142 bool is_in_new_space_list() { 143 return IsInNewSpaceList::decode(flags_); 144 } set_in_new_space_list(bool v)145 void set_in_new_space_list(bool v) { 146 flags_ = IsInNewSpaceList::update(flags_, v); 147 } 148 IsNearDeath() const149 bool IsNearDeath() const { 150 // Check for PENDING to ensure correct answer when processing callbacks. 151 return state() == PENDING || state() == NEAR_DEATH; 152 } 153 IsWeak() const154 bool IsWeak() const { return state() == WEAK; } 155 IsRetainer() const156 bool IsRetainer() const { return state() != FREE; } 157 IsStrongRetainer() const158 bool IsStrongRetainer() const { return state() == NORMAL; } 159 IsWeakRetainer() const160 bool IsWeakRetainer() const { 161 return state() == WEAK || state() == PENDING || state() == NEAR_DEATH; 162 } 163 MarkPending()164 void MarkPending() { 165 DCHECK(state() == WEAK); 166 set_state(PENDING); 167 } 168 169 // Independent flag accessors. MarkIndependent()170 void MarkIndependent() { 171 DCHECK(state() != FREE); 172 set_independent(true); 173 } 174 MarkPartiallyDependent()175 void MarkPartiallyDependent() { 176 DCHECK(state() != FREE); 177 if (GetGlobalHandles()->isolate()->heap()->InNewSpace(object_)) { 178 set_partially_dependent(true); 179 } 180 } clear_partially_dependent()181 void clear_partially_dependent() { set_partially_dependent(false); } 182 183 // Callback accessor. 184 // TODO(svenpanne) Re-enable or nuke later. 185 // WeakReferenceCallback callback() { return callback_; } 186 187 // Callback parameter accessors. set_parameter(void * parameter)188 void set_parameter(void* parameter) { 189 DCHECK(state() != FREE); 190 parameter_or_next_free_.parameter = parameter; 191 } parameter() const192 void* parameter() const { 193 DCHECK(state() != FREE); 194 return parameter_or_next_free_.parameter; 195 } 196 197 // Accessors for next free node in the free list. next_free()198 Node* next_free() { 199 DCHECK(state() == FREE); 200 return parameter_or_next_free_.next_free; 201 } set_next_free(Node * value)202 void set_next_free(Node* value) { 203 DCHECK(state() == FREE); 204 parameter_or_next_free_.next_free = value; 205 } 206 MakeWeak(void * parameter,WeakCallback weak_callback)207 void MakeWeak(void* parameter, WeakCallback weak_callback) { 208 DCHECK(weak_callback != NULL); 209 DCHECK(state() != FREE); 210 CHECK(object_ != NULL); 211 set_state(WEAK); 212 set_parameter(parameter); 213 weak_callback_ = weak_callback; 214 } 215 ClearWeakness()216 void* ClearWeakness() { 217 DCHECK(state() != FREE); 218 void* p = parameter(); 219 set_state(NORMAL); 220 set_parameter(NULL); 221 return p; 222 } 223 PostGarbageCollectionProcessing(Isolate * isolate)224 bool PostGarbageCollectionProcessing(Isolate* isolate) { 225 if (state() != Node::PENDING) return false; 226 if (weak_callback_ == NULL) { 227 Release(); 228 return false; 229 } 230 void* par = parameter(); 231 set_state(NEAR_DEATH); 232 set_parameter(NULL); 233 234 Object** object = location(); 235 { 236 // Check that we are not passing a finalized external string to 237 // the callback. 238 DCHECK(!object_->IsExternalOneByteString() || 239 ExternalOneByteString::cast(object_)->resource() != NULL); 240 DCHECK(!object_->IsExternalTwoByteString() || 241 ExternalTwoByteString::cast(object_)->resource() != NULL); 242 // Leaving V8. 243 VMState<EXTERNAL> state(isolate); 244 HandleScope handle_scope(isolate); 245 Handle<Object> handle(*object, isolate); 246 v8::WeakCallbackData<v8::Value, void> data( 247 reinterpret_cast<v8::Isolate*>(isolate), 248 v8::Utils::ToLocal(handle), 249 par); 250 weak_callback_(data); 251 } 252 // Absence of explicit cleanup or revival of weak handle 253 // in most of the cases would lead to memory leak. 254 CHECK(state() != NEAR_DEATH); 255 return true; 256 } 257 258 inline GlobalHandles* GetGlobalHandles(); 259 260 private: 261 inline NodeBlock* FindBlock(); 262 inline void IncreaseBlockUses(); 263 inline void DecreaseBlockUses(); 264 265 // Storage for object pointer. 266 // Placed first to avoid offset computation. 267 Object* object_; 268 269 // Next word stores class_id, index, state, and independent. 270 // Note: the most aligned fields should go first. 271 272 // Wrapper class ID. 273 uint16_t class_id_; 274 275 // Index in the containing handle block. 276 uint8_t index_; 277 278 // This stores three flags (independent, partially_dependent and 279 // in_new_space_list) and a State. 280 class NodeState: public BitField<State, 0, 4> {}; 281 class IsIndependent: public BitField<bool, 4, 1> {}; 282 class IsPartiallyDependent: public BitField<bool, 5, 1> {}; 283 class IsInNewSpaceList: public BitField<bool, 6, 1> {}; 284 285 uint8_t flags_; 286 287 // Handle specific callback - might be a weak reference in disguise. 288 WeakCallback weak_callback_; 289 290 // Provided data for callback. In FREE state, this is used for 291 // the free list link. 292 union { 293 void* parameter; 294 Node* next_free; 295 } parameter_or_next_free_; 296 297 DISALLOW_COPY_AND_ASSIGN(Node); 298 }; 299 300 301 class GlobalHandles::NodeBlock { 302 public: 303 static const int kSize = 256; 304 NodeBlock(GlobalHandles * global_handles,NodeBlock * next)305 explicit NodeBlock(GlobalHandles* global_handles, NodeBlock* next) 306 : next_(next), 307 used_nodes_(0), 308 next_used_(NULL), 309 prev_used_(NULL), 310 global_handles_(global_handles) {} 311 PutNodesOnFreeList(Node ** first_free)312 void PutNodesOnFreeList(Node** first_free) { 313 for (int i = kSize - 1; i >= 0; --i) { 314 nodes_[i].Initialize(i, first_free); 315 } 316 } 317 node_at(int index)318 Node* node_at(int index) { 319 DCHECK(0 <= index && index < kSize); 320 return &nodes_[index]; 321 } 322 IncreaseUses()323 void IncreaseUses() { 324 DCHECK(used_nodes_ < kSize); 325 if (used_nodes_++ == 0) { 326 NodeBlock* old_first = global_handles_->first_used_block_; 327 global_handles_->first_used_block_ = this; 328 next_used_ = old_first; 329 prev_used_ = NULL; 330 if (old_first == NULL) return; 331 old_first->prev_used_ = this; 332 } 333 } 334 DecreaseUses()335 void DecreaseUses() { 336 DCHECK(used_nodes_ > 0); 337 if (--used_nodes_ == 0) { 338 if (next_used_ != NULL) next_used_->prev_used_ = prev_used_; 339 if (prev_used_ != NULL) prev_used_->next_used_ = next_used_; 340 if (this == global_handles_->first_used_block_) { 341 global_handles_->first_used_block_ = next_used_; 342 } 343 } 344 } 345 global_handles()346 GlobalHandles* global_handles() { return global_handles_; } 347 348 // Next block in the list of all blocks. next() const349 NodeBlock* next() const { return next_; } 350 351 // Next/previous block in the list of blocks with used nodes. next_used() const352 NodeBlock* next_used() const { return next_used_; } prev_used() const353 NodeBlock* prev_used() const { return prev_used_; } 354 355 private: 356 Node nodes_[kSize]; 357 NodeBlock* const next_; 358 int used_nodes_; 359 NodeBlock* next_used_; 360 NodeBlock* prev_used_; 361 GlobalHandles* global_handles_; 362 }; 363 364 GetGlobalHandles()365 GlobalHandles* GlobalHandles::Node::GetGlobalHandles() { 366 return FindBlock()->global_handles(); 367 } 368 369 FindBlock()370 GlobalHandles::NodeBlock* GlobalHandles::Node::FindBlock() { 371 intptr_t ptr = reinterpret_cast<intptr_t>(this); 372 ptr = ptr - index_ * sizeof(Node); 373 NodeBlock* block = reinterpret_cast<NodeBlock*>(ptr); 374 DCHECK(block->node_at(index_) == this); 375 return block; 376 } 377 378 IncreaseBlockUses()379 void GlobalHandles::Node::IncreaseBlockUses() { 380 NodeBlock* node_block = FindBlock(); 381 node_block->IncreaseUses(); 382 GlobalHandles* global_handles = node_block->global_handles(); 383 global_handles->isolate()->counters()->global_handles()->Increment(); 384 global_handles->number_of_global_handles_++; 385 } 386 387 DecreaseBlockUses()388 void GlobalHandles::Node::DecreaseBlockUses() { 389 NodeBlock* node_block = FindBlock(); 390 GlobalHandles* global_handles = node_block->global_handles(); 391 parameter_or_next_free_.next_free = global_handles->first_free_; 392 global_handles->first_free_ = this; 393 node_block->DecreaseUses(); 394 global_handles->isolate()->counters()->global_handles()->Decrement(); 395 global_handles->number_of_global_handles_--; 396 } 397 398 399 class GlobalHandles::NodeIterator { 400 public: NodeIterator(GlobalHandles * global_handles)401 explicit NodeIterator(GlobalHandles* global_handles) 402 : block_(global_handles->first_used_block_), 403 index_(0) {} 404 done() const405 bool done() const { return block_ == NULL; } 406 node() const407 Node* node() const { 408 DCHECK(!done()); 409 return block_->node_at(index_); 410 } 411 Advance()412 void Advance() { 413 DCHECK(!done()); 414 if (++index_ < NodeBlock::kSize) return; 415 index_ = 0; 416 block_ = block_->next_used(); 417 } 418 419 private: 420 NodeBlock* block_; 421 int index_; 422 423 DISALLOW_COPY_AND_ASSIGN(NodeIterator); 424 }; 425 426 GlobalHandles(Isolate * isolate)427 GlobalHandles::GlobalHandles(Isolate* isolate) 428 : isolate_(isolate), 429 number_of_global_handles_(0), 430 first_block_(NULL), 431 first_used_block_(NULL), 432 first_free_(NULL), 433 post_gc_processing_count_(0), 434 object_group_connections_(kObjectGroupConnectionsCapacity) {} 435 436 ~GlobalHandles()437 GlobalHandles::~GlobalHandles() { 438 NodeBlock* block = first_block_; 439 while (block != NULL) { 440 NodeBlock* tmp = block->next(); 441 delete block; 442 block = tmp; 443 } 444 first_block_ = NULL; 445 } 446 447 Create(Object * value)448 Handle<Object> GlobalHandles::Create(Object* value) { 449 if (first_free_ == NULL) { 450 first_block_ = new NodeBlock(this, first_block_); 451 first_block_->PutNodesOnFreeList(&first_free_); 452 } 453 DCHECK(first_free_ != NULL); 454 // Take the first node in the free list. 455 Node* result = first_free_; 456 first_free_ = result->next_free(); 457 result->Acquire(value); 458 if (isolate_->heap()->InNewSpace(value) && 459 !result->is_in_new_space_list()) { 460 new_space_nodes_.Add(result); 461 result->set_in_new_space_list(true); 462 } 463 return result->handle(); 464 } 465 466 CopyGlobal(Object ** location)467 Handle<Object> GlobalHandles::CopyGlobal(Object** location) { 468 DCHECK(location != NULL); 469 return Node::FromLocation(location)->GetGlobalHandles()->Create(*location); 470 } 471 472 Destroy(Object ** location)473 void GlobalHandles::Destroy(Object** location) { 474 if (location != NULL) Node::FromLocation(location)->Release(); 475 } 476 477 MakeWeak(Object ** location,void * parameter,WeakCallback weak_callback)478 void GlobalHandles::MakeWeak(Object** location, 479 void* parameter, 480 WeakCallback weak_callback) { 481 Node::FromLocation(location)->MakeWeak(parameter, weak_callback); 482 } 483 484 ClearWeakness(Object ** location)485 void* GlobalHandles::ClearWeakness(Object** location) { 486 return Node::FromLocation(location)->ClearWeakness(); 487 } 488 489 MarkIndependent(Object ** location)490 void GlobalHandles::MarkIndependent(Object** location) { 491 Node::FromLocation(location)->MarkIndependent(); 492 } 493 494 MarkPartiallyDependent(Object ** location)495 void GlobalHandles::MarkPartiallyDependent(Object** location) { 496 Node::FromLocation(location)->MarkPartiallyDependent(); 497 } 498 499 IsIndependent(Object ** location)500 bool GlobalHandles::IsIndependent(Object** location) { 501 return Node::FromLocation(location)->is_independent(); 502 } 503 504 IsNearDeath(Object ** location)505 bool GlobalHandles::IsNearDeath(Object** location) { 506 return Node::FromLocation(location)->IsNearDeath(); 507 } 508 509 IsWeak(Object ** location)510 bool GlobalHandles::IsWeak(Object** location) { 511 return Node::FromLocation(location)->IsWeak(); 512 } 513 514 IterateWeakRoots(ObjectVisitor * v)515 void GlobalHandles::IterateWeakRoots(ObjectVisitor* v) { 516 for (NodeIterator it(this); !it.done(); it.Advance()) { 517 if (it.node()->IsWeakRetainer()) v->VisitPointer(it.node()->location()); 518 } 519 } 520 521 IdentifyWeakHandles(WeakSlotCallback f)522 void GlobalHandles::IdentifyWeakHandles(WeakSlotCallback f) { 523 for (NodeIterator it(this); !it.done(); it.Advance()) { 524 if (it.node()->IsWeak() && f(it.node()->location())) { 525 it.node()->MarkPending(); 526 } 527 } 528 } 529 530 IterateNewSpaceStrongAndDependentRoots(ObjectVisitor * v)531 void GlobalHandles::IterateNewSpaceStrongAndDependentRoots(ObjectVisitor* v) { 532 for (int i = 0; i < new_space_nodes_.length(); ++i) { 533 Node* node = new_space_nodes_[i]; 534 if (node->IsStrongRetainer() || 535 (node->IsWeakRetainer() && !node->is_independent() && 536 !node->is_partially_dependent())) { 537 v->VisitPointer(node->location()); 538 } 539 } 540 } 541 542 IdentifyNewSpaceWeakIndependentHandles(WeakSlotCallbackWithHeap f)543 void GlobalHandles::IdentifyNewSpaceWeakIndependentHandles( 544 WeakSlotCallbackWithHeap f) { 545 for (int i = 0; i < new_space_nodes_.length(); ++i) { 546 Node* node = new_space_nodes_[i]; 547 DCHECK(node->is_in_new_space_list()); 548 if ((node->is_independent() || node->is_partially_dependent()) && 549 node->IsWeak() && f(isolate_->heap(), node->location())) { 550 node->MarkPending(); 551 } 552 } 553 } 554 555 IterateNewSpaceWeakIndependentRoots(ObjectVisitor * v)556 void GlobalHandles::IterateNewSpaceWeakIndependentRoots(ObjectVisitor* v) { 557 for (int i = 0; i < new_space_nodes_.length(); ++i) { 558 Node* node = new_space_nodes_[i]; 559 DCHECK(node->is_in_new_space_list()); 560 if ((node->is_independent() || node->is_partially_dependent()) && 561 node->IsWeakRetainer()) { 562 v->VisitPointer(node->location()); 563 } 564 } 565 } 566 567 IterateObjectGroups(ObjectVisitor * v,WeakSlotCallbackWithHeap can_skip)568 bool GlobalHandles::IterateObjectGroups(ObjectVisitor* v, 569 WeakSlotCallbackWithHeap can_skip) { 570 ComputeObjectGroupsAndImplicitReferences(); 571 int last = 0; 572 bool any_group_was_visited = false; 573 for (int i = 0; i < object_groups_.length(); i++) { 574 ObjectGroup* entry = object_groups_.at(i); 575 DCHECK(entry != NULL); 576 577 Object*** objects = entry->objects; 578 bool group_should_be_visited = false; 579 for (size_t j = 0; j < entry->length; j++) { 580 Object* object = *objects[j]; 581 if (object->IsHeapObject()) { 582 if (!can_skip(isolate_->heap(), &object)) { 583 group_should_be_visited = true; 584 break; 585 } 586 } 587 } 588 589 if (!group_should_be_visited) { 590 object_groups_[last++] = entry; 591 continue; 592 } 593 594 // An object in the group requires visiting, so iterate over all 595 // objects in the group. 596 for (size_t j = 0; j < entry->length; ++j) { 597 Object* object = *objects[j]; 598 if (object->IsHeapObject()) { 599 v->VisitPointer(&object); 600 any_group_was_visited = true; 601 } 602 } 603 604 // Once the entire group has been iterated over, set the object 605 // group to NULL so it won't be processed again. 606 delete entry; 607 object_groups_.at(i) = NULL; 608 } 609 object_groups_.Rewind(last); 610 return any_group_was_visited; 611 } 612 613 PostGarbageCollectionProcessing(GarbageCollector collector)614 int GlobalHandles::PostGarbageCollectionProcessing( 615 GarbageCollector collector) { 616 // Process weak global handle callbacks. This must be done after the 617 // GC is completely done, because the callbacks may invoke arbitrary 618 // API functions. 619 DCHECK(isolate_->heap()->gc_state() == Heap::NOT_IN_GC); 620 const int initial_post_gc_processing_count = ++post_gc_processing_count_; 621 int freed_nodes = 0; 622 if (collector == SCAVENGER) { 623 for (int i = 0; i < new_space_nodes_.length(); ++i) { 624 Node* node = new_space_nodes_[i]; 625 DCHECK(node->is_in_new_space_list()); 626 if (!node->IsRetainer()) { 627 // Free nodes do not have weak callbacks. Do not use them to compute 628 // the freed_nodes. 629 continue; 630 } 631 // Skip dependent handles. Their weak callbacks might expect to be 632 // called between two global garbage collection callbacks which 633 // are not called for minor collections. 634 if (!node->is_independent() && !node->is_partially_dependent()) { 635 continue; 636 } 637 node->clear_partially_dependent(); 638 if (node->PostGarbageCollectionProcessing(isolate_)) { 639 if (initial_post_gc_processing_count != post_gc_processing_count_) { 640 // Weak callback triggered another GC and another round of 641 // PostGarbageCollection processing. The current node might 642 // have been deleted in that round, so we need to bail out (or 643 // restart the processing). 644 return freed_nodes; 645 } 646 } 647 if (!node->IsRetainer()) { 648 freed_nodes++; 649 } 650 } 651 } else { 652 for (NodeIterator it(this); !it.done(); it.Advance()) { 653 if (!it.node()->IsRetainer()) { 654 // Free nodes do not have weak callbacks. Do not use them to compute 655 // the freed_nodes. 656 continue; 657 } 658 it.node()->clear_partially_dependent(); 659 if (it.node()->PostGarbageCollectionProcessing(isolate_)) { 660 if (initial_post_gc_processing_count != post_gc_processing_count_) { 661 // See the comment above. 662 return freed_nodes; 663 } 664 } 665 if (!it.node()->IsRetainer()) { 666 freed_nodes++; 667 } 668 } 669 } 670 // Update the list of new space nodes. 671 int last = 0; 672 for (int i = 0; i < new_space_nodes_.length(); ++i) { 673 Node* node = new_space_nodes_[i]; 674 DCHECK(node->is_in_new_space_list()); 675 if (node->IsRetainer()) { 676 if (isolate_->heap()->InNewSpace(node->object())) { 677 new_space_nodes_[last++] = node; 678 isolate_->heap()->IncrementNodesCopiedInNewSpace(); 679 } else { 680 node->set_in_new_space_list(false); 681 isolate_->heap()->IncrementNodesPromoted(); 682 } 683 } else { 684 node->set_in_new_space_list(false); 685 isolate_->heap()->IncrementNodesDiedInNewSpace(); 686 } 687 } 688 new_space_nodes_.Rewind(last); 689 return freed_nodes; 690 } 691 692 IterateStrongRoots(ObjectVisitor * v)693 void GlobalHandles::IterateStrongRoots(ObjectVisitor* v) { 694 for (NodeIterator it(this); !it.done(); it.Advance()) { 695 if (it.node()->IsStrongRetainer()) { 696 v->VisitPointer(it.node()->location()); 697 } 698 } 699 } 700 701 IterateAllRoots(ObjectVisitor * v)702 void GlobalHandles::IterateAllRoots(ObjectVisitor* v) { 703 for (NodeIterator it(this); !it.done(); it.Advance()) { 704 if (it.node()->IsRetainer()) { 705 v->VisitPointer(it.node()->location()); 706 } 707 } 708 } 709 710 IterateAllRootsWithClassIds(ObjectVisitor * v)711 void GlobalHandles::IterateAllRootsWithClassIds(ObjectVisitor* v) { 712 for (NodeIterator it(this); !it.done(); it.Advance()) { 713 if (it.node()->IsRetainer() && it.node()->has_wrapper_class_id()) { 714 v->VisitEmbedderReference(it.node()->location(), 715 it.node()->wrapper_class_id()); 716 } 717 } 718 } 719 720 IterateAllRootsInNewSpaceWithClassIds(ObjectVisitor * v)721 void GlobalHandles::IterateAllRootsInNewSpaceWithClassIds(ObjectVisitor* v) { 722 for (int i = 0; i < new_space_nodes_.length(); ++i) { 723 Node* node = new_space_nodes_[i]; 724 if (node->IsRetainer() && node->has_wrapper_class_id()) { 725 v->VisitEmbedderReference(node->location(), 726 node->wrapper_class_id()); 727 } 728 } 729 } 730 731 NumberOfWeakHandles()732 int GlobalHandles::NumberOfWeakHandles() { 733 int count = 0; 734 for (NodeIterator it(this); !it.done(); it.Advance()) { 735 if (it.node()->IsWeakRetainer()) { 736 count++; 737 } 738 } 739 return count; 740 } 741 742 NumberOfGlobalObjectWeakHandles()743 int GlobalHandles::NumberOfGlobalObjectWeakHandles() { 744 int count = 0; 745 for (NodeIterator it(this); !it.done(); it.Advance()) { 746 if (it.node()->IsWeakRetainer() && 747 it.node()->object()->IsJSGlobalObject()) { 748 count++; 749 } 750 } 751 return count; 752 } 753 754 RecordStats(HeapStats * stats)755 void GlobalHandles::RecordStats(HeapStats* stats) { 756 *stats->global_handle_count = 0; 757 *stats->weak_global_handle_count = 0; 758 *stats->pending_global_handle_count = 0; 759 *stats->near_death_global_handle_count = 0; 760 *stats->free_global_handle_count = 0; 761 for (NodeIterator it(this); !it.done(); it.Advance()) { 762 *stats->global_handle_count += 1; 763 if (it.node()->state() == Node::WEAK) { 764 *stats->weak_global_handle_count += 1; 765 } else if (it.node()->state() == Node::PENDING) { 766 *stats->pending_global_handle_count += 1; 767 } else if (it.node()->state() == Node::NEAR_DEATH) { 768 *stats->near_death_global_handle_count += 1; 769 } else if (it.node()->state() == Node::FREE) { 770 *stats->free_global_handle_count += 1; 771 } 772 } 773 } 774 775 #ifdef DEBUG 776 PrintStats()777 void GlobalHandles::PrintStats() { 778 int total = 0; 779 int weak = 0; 780 int pending = 0; 781 int near_death = 0; 782 int destroyed = 0; 783 784 for (NodeIterator it(this); !it.done(); it.Advance()) { 785 total++; 786 if (it.node()->state() == Node::WEAK) weak++; 787 if (it.node()->state() == Node::PENDING) pending++; 788 if (it.node()->state() == Node::NEAR_DEATH) near_death++; 789 if (it.node()->state() == Node::FREE) destroyed++; 790 } 791 792 PrintF("Global Handle Statistics:\n"); 793 PrintF(" allocated memory = %" V8_PTR_PREFIX "dB\n", sizeof(Node) * total); 794 PrintF(" # weak = %d\n", weak); 795 PrintF(" # pending = %d\n", pending); 796 PrintF(" # near_death = %d\n", near_death); 797 PrintF(" # free = %d\n", destroyed); 798 PrintF(" # total = %d\n", total); 799 } 800 801 Print()802 void GlobalHandles::Print() { 803 PrintF("Global handles:\n"); 804 for (NodeIterator it(this); !it.done(); it.Advance()) { 805 PrintF(" handle %p to %p%s\n", 806 reinterpret_cast<void*>(it.node()->location()), 807 reinterpret_cast<void*>(it.node()->object()), 808 it.node()->IsWeak() ? " (weak)" : ""); 809 } 810 } 811 812 #endif 813 814 815 AddObjectGroup(Object *** handles,size_t length,v8::RetainedObjectInfo * info)816 void GlobalHandles::AddObjectGroup(Object*** handles, 817 size_t length, 818 v8::RetainedObjectInfo* info) { 819 #ifdef DEBUG 820 for (size_t i = 0; i < length; ++i) { 821 DCHECK(!Node::FromLocation(handles[i])->is_independent()); 822 } 823 #endif 824 if (length == 0) { 825 if (info != NULL) info->Dispose(); 826 return; 827 } 828 ObjectGroup* group = new ObjectGroup(length); 829 for (size_t i = 0; i < length; ++i) 830 group->objects[i] = handles[i]; 831 group->info = info; 832 object_groups_.Add(group); 833 } 834 835 SetObjectGroupId(Object ** handle,UniqueId id)836 void GlobalHandles::SetObjectGroupId(Object** handle, 837 UniqueId id) { 838 object_group_connections_.Add(ObjectGroupConnection(id, handle)); 839 } 840 841 SetRetainedObjectInfo(UniqueId id,RetainedObjectInfo * info)842 void GlobalHandles::SetRetainedObjectInfo(UniqueId id, 843 RetainedObjectInfo* info) { 844 retainer_infos_.Add(ObjectGroupRetainerInfo(id, info)); 845 } 846 847 SetReferenceFromGroup(UniqueId id,Object ** child)848 void GlobalHandles::SetReferenceFromGroup(UniqueId id, Object** child) { 849 DCHECK(!Node::FromLocation(child)->is_independent()); 850 implicit_ref_connections_.Add(ObjectGroupConnection(id, child)); 851 } 852 853 SetReference(HeapObject ** parent,Object ** child)854 void GlobalHandles::SetReference(HeapObject** parent, Object** child) { 855 DCHECK(!Node::FromLocation(child)->is_independent()); 856 ImplicitRefGroup* group = new ImplicitRefGroup(parent, 1); 857 group->children[0] = child; 858 implicit_ref_groups_.Add(group); 859 } 860 861 RemoveObjectGroups()862 void GlobalHandles::RemoveObjectGroups() { 863 for (int i = 0; i < object_groups_.length(); i++) 864 delete object_groups_.at(i); 865 object_groups_.Clear(); 866 for (int i = 0; i < retainer_infos_.length(); ++i) 867 retainer_infos_[i].info->Dispose(); 868 retainer_infos_.Clear(); 869 object_group_connections_.Clear(); 870 object_group_connections_.Initialize(kObjectGroupConnectionsCapacity); 871 } 872 873 RemoveImplicitRefGroups()874 void GlobalHandles::RemoveImplicitRefGroups() { 875 for (int i = 0; i < implicit_ref_groups_.length(); i++) { 876 delete implicit_ref_groups_.at(i); 877 } 878 implicit_ref_groups_.Clear(); 879 implicit_ref_connections_.Clear(); 880 } 881 882 TearDown()883 void GlobalHandles::TearDown() { 884 // TODO(1428): invoke weak callbacks. 885 } 886 887 ComputeObjectGroupsAndImplicitReferences()888 void GlobalHandles::ComputeObjectGroupsAndImplicitReferences() { 889 if (object_group_connections_.length() == 0) { 890 for (int i = 0; i < retainer_infos_.length(); ++i) 891 retainer_infos_[i].info->Dispose(); 892 retainer_infos_.Clear(); 893 implicit_ref_connections_.Clear(); 894 return; 895 } 896 897 object_group_connections_.Sort(); 898 retainer_infos_.Sort(); 899 implicit_ref_connections_.Sort(); 900 901 int info_index = 0; // For iterating retainer_infos_. 902 UniqueId current_group_id(0); 903 int current_group_start = 0; 904 905 int current_implicit_refs_start = 0; 906 int current_implicit_refs_end = 0; 907 for (int i = 0; i <= object_group_connections_.length(); ++i) { 908 if (i == 0) 909 current_group_id = object_group_connections_[i].id; 910 if (i == object_group_connections_.length() || 911 current_group_id != object_group_connections_[i].id) { 912 // Group detected: objects in indices [current_group_start, i[. 913 914 // Find out which implicit references are related to this group. (We want 915 // to ignore object groups which only have 1 object, but that object is 916 // needed as a representative object for the implicit refrerence group.) 917 while (current_implicit_refs_start < implicit_ref_connections_.length() && 918 implicit_ref_connections_[current_implicit_refs_start].id < 919 current_group_id) 920 ++current_implicit_refs_start; 921 current_implicit_refs_end = current_implicit_refs_start; 922 while (current_implicit_refs_end < implicit_ref_connections_.length() && 923 implicit_ref_connections_[current_implicit_refs_end].id == 924 current_group_id) 925 ++current_implicit_refs_end; 926 927 if (current_implicit_refs_end > current_implicit_refs_start) { 928 // Find a representative object for the implicit references. 929 HeapObject** representative = NULL; 930 for (int j = current_group_start; j < i; ++j) { 931 Object** object = object_group_connections_[j].object; 932 if ((*object)->IsHeapObject()) { 933 representative = reinterpret_cast<HeapObject**>(object); 934 break; 935 } 936 } 937 if (representative) { 938 ImplicitRefGroup* group = new ImplicitRefGroup( 939 representative, 940 current_implicit_refs_end - current_implicit_refs_start); 941 for (int j = current_implicit_refs_start; 942 j < current_implicit_refs_end; 943 ++j) { 944 group->children[j - current_implicit_refs_start] = 945 implicit_ref_connections_[j].object; 946 } 947 implicit_ref_groups_.Add(group); 948 } 949 current_implicit_refs_start = current_implicit_refs_end; 950 } 951 952 // Find a RetainedObjectInfo for the group. 953 RetainedObjectInfo* info = NULL; 954 while (info_index < retainer_infos_.length() && 955 retainer_infos_[info_index].id < current_group_id) { 956 retainer_infos_[info_index].info->Dispose(); 957 ++info_index; 958 } 959 if (info_index < retainer_infos_.length() && 960 retainer_infos_[info_index].id == current_group_id) { 961 // This object group has an associated ObjectGroupRetainerInfo. 962 info = retainer_infos_[info_index].info; 963 ++info_index; 964 } 965 966 // Ignore groups which only contain one object. 967 if (i > current_group_start + 1) { 968 ObjectGroup* group = new ObjectGroup(i - current_group_start); 969 for (int j = current_group_start; j < i; ++j) { 970 group->objects[j - current_group_start] = 971 object_group_connections_[j].object; 972 } 973 group->info = info; 974 object_groups_.Add(group); 975 } else if (info) { 976 info->Dispose(); 977 } 978 979 if (i < object_group_connections_.length()) { 980 current_group_id = object_group_connections_[i].id; 981 current_group_start = i; 982 } 983 } 984 } 985 object_group_connections_.Clear(); 986 object_group_connections_.Initialize(kObjectGroupConnectionsCapacity); 987 retainer_infos_.Clear(); 988 implicit_ref_connections_.Clear(); 989 } 990 991 EternalHandles()992 EternalHandles::EternalHandles() : size_(0) { 993 for (unsigned i = 0; i < arraysize(singleton_handles_); i++) { 994 singleton_handles_[i] = kInvalidIndex; 995 } 996 } 997 998 ~EternalHandles()999 EternalHandles::~EternalHandles() { 1000 for (int i = 0; i < blocks_.length(); i++) delete[] blocks_[i]; 1001 } 1002 1003 IterateAllRoots(ObjectVisitor * visitor)1004 void EternalHandles::IterateAllRoots(ObjectVisitor* visitor) { 1005 int limit = size_; 1006 for (int i = 0; i < blocks_.length(); i++) { 1007 DCHECK(limit > 0); 1008 Object** block = blocks_[i]; 1009 visitor->VisitPointers(block, block + Min(limit, kSize)); 1010 limit -= kSize; 1011 } 1012 } 1013 1014 IterateNewSpaceRoots(ObjectVisitor * visitor)1015 void EternalHandles::IterateNewSpaceRoots(ObjectVisitor* visitor) { 1016 for (int i = 0; i < new_space_indices_.length(); i++) { 1017 visitor->VisitPointer(GetLocation(new_space_indices_[i])); 1018 } 1019 } 1020 1021 PostGarbageCollectionProcessing(Heap * heap)1022 void EternalHandles::PostGarbageCollectionProcessing(Heap* heap) { 1023 int last = 0; 1024 for (int i = 0; i < new_space_indices_.length(); i++) { 1025 int index = new_space_indices_[i]; 1026 if (heap->InNewSpace(*GetLocation(index))) { 1027 new_space_indices_[last++] = index; 1028 } 1029 } 1030 new_space_indices_.Rewind(last); 1031 } 1032 1033 Create(Isolate * isolate,Object * object,int * index)1034 void EternalHandles::Create(Isolate* isolate, Object* object, int* index) { 1035 DCHECK_EQ(kInvalidIndex, *index); 1036 if (object == NULL) return; 1037 DCHECK_NE(isolate->heap()->the_hole_value(), object); 1038 int block = size_ >> kShift; 1039 int offset = size_ & kMask; 1040 // need to resize 1041 if (offset == 0) { 1042 Object** next_block = new Object*[kSize]; 1043 Object* the_hole = isolate->heap()->the_hole_value(); 1044 MemsetPointer(next_block, the_hole, kSize); 1045 blocks_.Add(next_block); 1046 } 1047 DCHECK_EQ(isolate->heap()->the_hole_value(), blocks_[block][offset]); 1048 blocks_[block][offset] = object; 1049 if (isolate->heap()->InNewSpace(object)) { 1050 new_space_indices_.Add(size_); 1051 } 1052 *index = size_++; 1053 } 1054 1055 1056 } } // namespace v8::internal 1057