LCOV - code coverage report
Current view: top level - src - global-handles.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 330 374 88.2 %
Date: 2017-10-20 Functions: 49 56 87.5 %

          Line data    Source code
       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/global-handles.h"
       6             : 
       7             : #include "src/api.h"
       8             : #include "src/cancelable-task.h"
       9             : #include "src/objects-inl.h"
      10             : #include "src/v8.h"
      11             : #include "src/visitors.h"
      12             : #include "src/vm-state-inl.h"
      13             : 
      14             : namespace v8 {
      15             : namespace internal {
      16             : 
      17             : class GlobalHandles::Node {
      18             :  public:
      19             :   // State transition diagram:
      20             :   // FREE -> NORMAL <-> WEAK -> PENDING -> NEAR_DEATH -> { NORMAL, WEAK, FREE }
      21             :   enum State {
      22             :     FREE = 0,
      23             :     NORMAL,      // Normal global handle.
      24             :     WEAK,        // Flagged as weak but not yet finalized.
      25             :     PENDING,     // Has been recognized as only reachable by weak handles.
      26             :     NEAR_DEATH,  // Callback has informed the handle is near death.
      27             :     NUMBER_OF_NODE_STATES
      28             :   };
      29             : 
      30             :   // Maps handle location (slot) to the containing node.
      31             :   static Node* FromLocation(Object** location) {
      32             :     DCHECK_EQ(offsetof(Node, object_), 0);
      33             :     return reinterpret_cast<Node*>(location);
      34             :   }
      35             : 
      36             :   Node() {
      37             :     DCHECK_EQ(offsetof(Node, class_id_), Internals::kNodeClassIdOffset);
      38             :     DCHECK_EQ(offsetof(Node, flags_), Internals::kNodeFlagsOffset);
      39             :     STATIC_ASSERT(static_cast<int>(NodeState::kMask) ==
      40             :                   Internals::kNodeStateMask);
      41             :     STATIC_ASSERT(WEAK == Internals::kNodeStateIsWeakValue);
      42             :     STATIC_ASSERT(PENDING == Internals::kNodeStateIsPendingValue);
      43             :     STATIC_ASSERT(NEAR_DEATH == Internals::kNodeStateIsNearDeathValue);
      44             :     STATIC_ASSERT(static_cast<int>(IsIndependent::kShift) ==
      45             :                   Internals::kNodeIsIndependentShift);
      46             :     STATIC_ASSERT(static_cast<int>(IsActive::kShift) ==
      47             :                   Internals::kNodeIsActiveShift);
      48             :   }
      49             : 
      50             : #ifdef ENABLE_HANDLE_ZAPPING
      51             :   ~Node() {
      52             :     // TODO(1428): if it's a weak handle we should have invoked its callback.
      53             :     // Zap the values for eager trapping.
      54    10978048 :     object_ = reinterpret_cast<Object*>(kGlobalHandleZapValue);
      55    10978048 :     class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
      56    10978048 :     index_ = 0;
      57             :     set_independent(false);
      58             :     set_active(false);
      59             :     set_in_new_space_list(false);
      60    10978048 :     parameter_or_next_free_.next_free = nullptr;
      61    10978048 :     weak_callback_ = nullptr;
      62             :   }
      63             : #endif
      64             : 
      65             :   void Initialize(int index, Node** first_free) {
      66    11398144 :     object_ = reinterpret_cast<Object*>(kGlobalHandleZapValue);
      67    11398144 :     index_ = static_cast<uint8_t>(index);
      68             :     DCHECK(static_cast<int>(index_) == index);
      69             :     set_state(FREE);
      70             :     set_in_new_space_list(false);
      71    11398144 :     parameter_or_next_free_.next_free = *first_free;
      72    11398144 :     *first_free = this;
      73             :   }
      74             : 
      75     3446567 :   void Acquire(Object* object) {
      76             :     DCHECK(state() == FREE);
      77     3446567 :     object_ = object;
      78     3446567 :     class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
      79             :     set_independent(false);
      80             :     set_active(false);
      81             :     set_state(NORMAL);
      82     3446567 :     parameter_or_next_free_.parameter = nullptr;
      83     3446567 :     weak_callback_ = nullptr;
      84     3446567 :     IncreaseBlockUses();
      85     3446566 :   }
      86             : 
      87             :   void Zap() {
      88             :     DCHECK(IsInUse());
      89             :     // Zap the values for eager trapping.
      90             :     object_ = reinterpret_cast<Object*>(kGlobalHandleZapValue);
      91             :   }
      92             : 
      93     2976461 :   void Release() {
      94             :     DCHECK(IsInUse());
      95             :     set_state(FREE);
      96             :     // Zap the values for eager trapping.
      97     2976461 :     object_ = reinterpret_cast<Object*>(kGlobalHandleZapValue);
      98     2976461 :     class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
      99             :     set_independent(false);
     100             :     set_active(false);
     101     2976461 :     weak_callback_ = nullptr;
     102     2976461 :     DecreaseBlockUses();
     103     2976461 :   }
     104             : 
     105             :   // Object slot accessors.
     106             :   Object* object() const { return object_; }
     107             :   Object** location() { return &object_; }
     108     3446566 :   Handle<Object> handle() { return Handle<Object>(location()); }
     109             : 
     110             :   // Wrapper class ID accessors.
     111             :   bool has_wrapper_class_id() const {
     112             :     return class_id_ != v8::HeapProfiler::kPersistentHandleNoClassId;
     113             :   }
     114             : 
     115             :   uint16_t wrapper_class_id() const { return class_id_; }
     116             : 
     117             :   // State and flag accessors.
     118             : 
     119             :   State state() const {
     120             :     return NodeState::decode(flags_);
     121             :   }
     122             :   void set_state(State state) {
     123    38063298 :     flags_ = NodeState::update(flags_, state);
     124             :   }
     125             : 
     126             :   bool is_independent() {
     127             :     return IsIndependent::decode(flags_);
     128             :   }
     129             :   void set_independent(bool v) {
     130    34802152 :     flags_ = IsIndependent::update(flags_, v);
     131             :   }
     132             : 
     133             :   bool is_active() {
     134             :     return IsActive::decode(flags_);
     135             :   }
     136             :   void set_active(bool v) {
     137    38644454 :     flags_ = IsActive::update(flags_, v);
     138             :   }
     139             : 
     140             :   bool is_in_new_space_list() {
     141             :     return IsInNewSpaceList::decode(flags_);
     142             :   }
     143             :   void set_in_new_space_list(bool v) {
     144    46728496 :     flags_ = IsInNewSpaceList::update(flags_, v);
     145             :   }
     146             : 
     147             :   WeaknessType weakness_type() const {
     148             :     return NodeWeaknessType::decode(flags_);
     149             :   }
     150             :   void set_weakness_type(WeaknessType weakness_type) {
     151     1155893 :     flags_ = NodeWeaknessType::update(flags_, weakness_type);
     152             :   }
     153             : 
     154          40 :   bool IsNearDeath() const {
     155             :     // Check for PENDING to ensure correct answer when processing callbacks.
     156          40 :     return state() == PENDING || state() == NEAR_DEATH;
     157             :   }
     158             : 
     159    11615801 :   bool IsWeak() const { return state() == WEAK; }
     160             : 
     161             :   bool IsInUse() const { return state() != FREE; }
     162             : 
     163             :   bool IsPendingPhantomCallback() const {
     164      589492 :     return state() == PENDING &&
     165      113479 :            (weakness_type() == PHANTOM_WEAK ||
     166             :             weakness_type() == PHANTOM_WEAK_2_EMBEDDER_FIELDS);
     167             :   }
     168             : 
     169             :   bool IsPendingPhantomResetHandle() const {
     170      589514 :     return state() == PENDING && weakness_type() == PHANTOM_WEAK_RESET_HANDLE;
     171             :   }
     172             : 
     173    25182163 :   bool IsRetainer() const {
     174    25182163 :     return state() != FREE &&
     175      120100 :            !(state() == NEAR_DEATH && weakness_type() != FINALIZER_WEAK);
     176             :   }
     177             : 
     178    17637129 :   bool IsStrongRetainer() const { return state() == NORMAL; }
     179             : 
     180    11051776 :   bool IsWeakRetainer() const {
     181    11640908 :     return state() == WEAK || state() == PENDING ||
     182           0 :            (state() == NEAR_DEATH && weakness_type() == FINALIZER_WEAK);
     183             :   }
     184             : 
     185             :   void MarkPending() {
     186             :     DCHECK(state() == WEAK);
     187             :     set_state(PENDING);
     188             :   }
     189             : 
     190             :   // Independent flag accessors.
     191             :   void MarkIndependent() {
     192             :     DCHECK(IsInUse());
     193             :     set_independent(true);
     194             :   }
     195             : 
     196             :   // Callback parameter accessors.
     197             :   void set_parameter(void* parameter) {
     198             :     DCHECK(IsInUse());
     199      740552 :     parameter_or_next_free_.parameter = parameter;
     200             :   }
     201             :   void* parameter() const {
     202             :     DCHECK(IsInUse());
     203             :     return parameter_or_next_free_.parameter;
     204             :   }
     205             : 
     206             :   // Accessors for next free node in the free list.
     207             :   Node* next_free() {
     208             :     DCHECK(state() == FREE);
     209             :     return parameter_or_next_free_.next_free;
     210             :   }
     211             :   void set_next_free(Node* value) {
     212             :     DCHECK(state() == FREE);
     213             :     parameter_or_next_free_.next_free = value;
     214             :   }
     215             : 
     216      740516 :   void MakeWeak(void* parameter,
     217             :                 WeakCallbackInfo<void>::Callback phantom_callback,
     218             :                 v8::WeakCallbackType type) {
     219             :     DCHECK_NOT_NULL(phantom_callback);
     220             :     DCHECK(IsInUse());
     221      740516 :     CHECK_NE(object_, reinterpret_cast<Object*>(kGlobalHandleZapValue));
     222             :     set_state(WEAK);
     223      740516 :     switch (type) {
     224             :       case v8::WeakCallbackType::kParameter:
     225             :         set_weakness_type(PHANTOM_WEAK);
     226             :         break;
     227             :       case v8::WeakCallbackType::kInternalFields:
     228             :         set_weakness_type(PHANTOM_WEAK_2_EMBEDDER_FIELDS);
     229             :         break;
     230             :       case v8::WeakCallbackType::kFinalizer:
     231             :         set_weakness_type(FINALIZER_WEAK);
     232             :         break;
     233             :     }
     234             :     set_parameter(parameter);
     235      740516 :     weak_callback_ = phantom_callback;
     236      740516 :   }
     237             : 
     238          11 :   void MakeWeak(Object*** location_addr) {
     239             :     DCHECK(IsInUse());
     240          11 :     CHECK_NE(object_, reinterpret_cast<Object*>(kGlobalHandleZapValue));
     241             :     set_state(WEAK);
     242             :     set_weakness_type(PHANTOM_WEAK_RESET_HANDLE);
     243             :     set_parameter(location_addr);
     244          11 :     weak_callback_ = nullptr;
     245          11 :   }
     246             : 
     247          25 :   void* ClearWeakness() {
     248             :     DCHECK(IsInUse());
     249             :     void* p = parameter();
     250             :     set_state(NORMAL);
     251             :     set_parameter(nullptr);
     252             :     return p;
     253             :   }
     254             : 
     255      122694 :   void CollectPhantomCallbackData(
     256             :       Isolate* isolate,
     257      247820 :       std::vector<PendingPhantomCallback>* pending_phantom_callbacks) {
     258             :     DCHECK(weakness_type() == PHANTOM_WEAK ||
     259             :            weakness_type() == PHANTOM_WEAK_2_EMBEDDER_FIELDS);
     260             :     DCHECK(state() == PENDING);
     261             :     DCHECK_NOT_NULL(weak_callback_);
     262             : 
     263             :     void* embedder_fields[v8::kEmbedderFieldsInWeakCallback] = {nullptr,
     264      122694 :                                                                 nullptr};
     265      123910 :     if (weakness_type() != PHANTOM_WEAK && object()->IsJSObject()) {
     266             :       auto jsobject = JSObject::cast(object());
     267        1216 :       int field_count = jsobject->GetEmbedderFieldCount();
     268        2455 :       for (int i = 0; i < v8::kEmbedderFieldsInWeakCallback; ++i) {
     269        2432 :         if (field_count == i) break;
     270             :         auto field = jsobject->GetEmbedderField(i);
     271        1239 :         if (field->IsSmi()) embedder_fields[i] = field;
     272             :       }
     273             :     }
     274             : 
     275             :     // Zap with something dangerous.
     276      122694 :     *location() = reinterpret_cast<Object*>(0x6057ca11);
     277             : 
     278             :     typedef v8::WeakCallbackInfo<void> Data;
     279      122694 :     auto callback = reinterpret_cast<Data::Callback>(weak_callback_);
     280             :     pending_phantom_callbacks->push_back(
     281      122694 :         PendingPhantomCallback(this, callback, parameter(), embedder_fields));
     282             :     DCHECK(IsInUse());
     283             :     set_state(NEAR_DEATH);
     284      122694 :   }
     285             : 
     286          11 :   void ResetPhantomHandle() {
     287             :     DCHECK(weakness_type() == PHANTOM_WEAK_RESET_HANDLE);
     288             :     DCHECK(state() == PENDING);
     289             :     DCHECK_NULL(weak_callback_);
     290             :     Object*** handle = reinterpret_cast<Object***>(parameter());
     291          11 :     *handle = nullptr;
     292          11 :     Release();
     293             :   }
     294             : 
     295     1431723 :   bool PostGarbageCollectionProcessing(Isolate* isolate) {
     296             :     // Handles only weak handles (not phantom) that are dying.
     297     1207197 :     if (state() != Node::PENDING) return false;
     298      112263 :     if (weak_callback_ == nullptr) {
     299           0 :       Release();
     300           0 :       return false;
     301             :     }
     302             :     set_state(NEAR_DEATH);
     303             : 
     304             :     // Check that we are not passing a finalized external string to
     305             :     // the callback.
     306             :     DCHECK(!object_->IsExternalOneByteString() ||
     307             :            ExternalOneByteString::cast(object_)->resource() != nullptr);
     308             :     DCHECK(!object_->IsExternalTwoByteString() ||
     309             :            ExternalTwoByteString::cast(object_)->resource() != nullptr);
     310      112263 :     if (weakness_type() != FINALIZER_WEAK) {
     311             :       return false;
     312             :     }
     313             : 
     314             :     // Leaving V8.
     315      112263 :     VMState<EXTERNAL> vmstate(isolate);
     316             :     HandleScope handle_scope(isolate);
     317             :     void* embedder_fields[v8::kEmbedderFieldsInWeakCallback] = {nullptr,
     318      112263 :                                                                 nullptr};
     319             :     v8::WeakCallbackInfo<void> data(reinterpret_cast<v8::Isolate*>(isolate),
     320             :                                     parameter(), embedder_fields, nullptr);
     321      112263 :     weak_callback_(data);
     322             : 
     323             :     // Absence of explicit cleanup or revival of weak handle
     324             :     // in most of the cases would lead to memory leak.
     325      112263 :     CHECK(state() != NEAR_DEATH);
     326      112263 :     return true;
     327             :   }
     328             : 
     329             :   inline GlobalHandles* GetGlobalHandles();
     330             : 
     331             :  private:
     332             :   inline NodeBlock* FindBlock();
     333             :   inline void IncreaseBlockUses();
     334             :   inline void DecreaseBlockUses();
     335             : 
     336             :   // Storage for object pointer.
     337             :   // Placed first to avoid offset computation.
     338             :   Object* object_;
     339             : 
     340             :   // Next word stores class_id, index, state, and independent.
     341             :   // Note: the most aligned fields should go first.
     342             : 
     343             :   // Wrapper class ID.
     344             :   uint16_t class_id_;
     345             : 
     346             :   // Index in the containing handle block.
     347             :   uint8_t index_;
     348             : 
     349             :   // This stores three flags (independent, partially_dependent and
     350             :   // in_new_space_list) and a State.
     351             :   class NodeState : public BitField<State, 0, 3> {};
     352             :   class IsIndependent : public BitField<bool, 3, 1> {};
     353             :   // The following two fields are mutually exclusive
     354             :   class IsActive : public BitField<bool, 4, 1> {};
     355             :   class IsInNewSpaceList : public BitField<bool, 5, 1> {};
     356             :   class NodeWeaknessType : public BitField<WeaknessType, 6, 2> {};
     357             : 
     358             :   uint8_t flags_;
     359             : 
     360             :   // Handle specific callback - might be a weak reference in disguise.
     361             :   WeakCallbackInfo<void>::Callback weak_callback_;
     362             : 
     363             :   // Provided data for callback.  In FREE state, this is used for
     364             :   // the free list link.
     365             :   union {
     366             :     void* parameter;
     367             :     Node* next_free;
     368             :   } parameter_or_next_free_;
     369             : 
     370             :   DISALLOW_COPY_AND_ASSIGN(Node);
     371             : };
     372             : 
     373             : 
     374       85766 : class GlobalHandles::NodeBlock {
     375             :  public:
     376             :   static const int kSize = 256;
     377             : 
     378             :   explicit NodeBlock(GlobalHandles* global_handles, NodeBlock* next)
     379             :       : next_(next),
     380             :         used_nodes_(0),
     381             :         next_used_(nullptr),
     382             :         prev_used_(nullptr),
     383       44524 :         global_handles_(global_handles) {}
     384             : 
     385             :   void PutNodesOnFreeList(Node** first_free) {
     386    11398144 :     for (int i = kSize - 1; i >= 0; --i) {
     387    11398144 :       nodes_[i].Initialize(i, first_free);
     388             :     }
     389             :   }
     390             : 
     391             :   Node* node_at(int index) {
     392             :     DCHECK(0 <= index && index < kSize);
     393             :     return &nodes_[index];
     394             :   }
     395             : 
     396             :   void IncreaseUses() {
     397             :     DCHECK_LT(used_nodes_, kSize);
     398     3446567 :     if (used_nodes_++ == 0) {
     399       65672 :       NodeBlock* old_first = global_handles_->first_used_block_;
     400       65672 :       global_handles_->first_used_block_ = this;
     401       65672 :       next_used_ = old_first;
     402       65672 :       prev_used_ = nullptr;
     403       65672 :       if (old_first == nullptr) return;
     404        4595 :       old_first->prev_used_ = this;
     405             :     }
     406             :   }
     407             : 
     408     2976461 :   void DecreaseUses() {
     409             :     DCHECK_GT(used_nodes_, 0);
     410     2976461 :     if (--used_nodes_ == 0) {
     411       55714 :       if (next_used_ != nullptr) next_used_->prev_used_ = prev_used_;
     412       55714 :       if (prev_used_ != nullptr) prev_used_->next_used_ = next_used_;
     413       55714 :       if (this == global_handles_->first_used_block_) {
     414       53622 :         global_handles_->first_used_block_ = next_used_;
     415             :       }
     416             :     }
     417     2976461 :   }
     418             : 
     419             :   GlobalHandles* global_handles() { return global_handles_; }
     420             : 
     421             :   // Next block in the list of all blocks.
     422             :   NodeBlock* next() const { return next_; }
     423             : 
     424             :   // Next/previous block in the list of blocks with used nodes.
     425             :   NodeBlock* next_used() const { return next_used_; }
     426             :   NodeBlock* prev_used() const { return prev_used_; }
     427             : 
     428             :  private:
     429             :   Node nodes_[kSize];
     430             :   NodeBlock* const next_;
     431             :   int used_nodes_;
     432             :   NodeBlock* next_used_;
     433             :   NodeBlock* prev_used_;
     434             :   GlobalHandles* global_handles_;
     435             : };
     436             : 
     437             : 
     438             : GlobalHandles* GlobalHandles::Node::GetGlobalHandles() {
     439          10 :   return FindBlock()->global_handles();
     440             : }
     441             : 
     442             : 
     443             : GlobalHandles::NodeBlock* GlobalHandles::Node::FindBlock() {
     444             :   intptr_t ptr = reinterpret_cast<intptr_t>(this);
     445     6423038 :   ptr = ptr - index_ * sizeof(Node);
     446     6423038 :   NodeBlock* block = reinterpret_cast<NodeBlock*>(ptr);
     447             :   DCHECK(block->node_at(index_) == this);
     448             :   return block;
     449             : }
     450             : 
     451             : 
     452     3446567 : void GlobalHandles::Node::IncreaseBlockUses() {
     453     3446567 :   NodeBlock* node_block = FindBlock();
     454             :   node_block->IncreaseUses();
     455     3446567 :   GlobalHandles* global_handles = node_block->global_handles();
     456     3446567 :   global_handles->isolate()->counters()->global_handles()->Increment();
     457     3446566 :   global_handles->number_of_global_handles_++;
     458     3446566 : }
     459             : 
     460             : 
     461     2976461 : void GlobalHandles::Node::DecreaseBlockUses() {
     462     2976461 :   NodeBlock* node_block = FindBlock();
     463     2976461 :   GlobalHandles* global_handles = node_block->global_handles();
     464     2976461 :   parameter_or_next_free_.next_free = global_handles->first_free_;
     465     2976461 :   global_handles->first_free_ = this;
     466     2976461 :   node_block->DecreaseUses();
     467     2976461 :   global_handles->isolate()->counters()->global_handles()->Decrement();
     468     2976461 :   global_handles->number_of_global_handles_--;
     469     2976461 : }
     470             : 
     471             : 
     472             : class GlobalHandles::NodeIterator {
     473             :  public:
     474             :   explicit NodeIterator(GlobalHandles* global_handles)
     475             :       : block_(global_handles->first_used_block_),
     476      373671 :         index_(0) {}
     477             : 
     478             :   bool done() const { return block_ == nullptr; }
     479             : 
     480             :   Node* node() const {
     481             :     DCHECK(!done());
     482             :     return block_->node_at(index_);
     483             :   }
     484             : 
     485             :   void Advance() {
     486             :     DCHECK(!done());
     487    61828864 :     if (++index_ < NodeBlock::kSize) return;
     488             :     index_ = 0;
     489      241519 :     block_ = block_->next_used();
     490             :   }
     491             : 
     492             :  private:
     493             :   NodeBlock* block_;
     494             :   int index_;
     495             : 
     496             :   DISALLOW_COPY_AND_ASSIGN(NodeIterator);
     497             : };
     498             : 
     499         216 : class GlobalHandles::PendingPhantomCallbacksSecondPassTask
     500             :     : public v8::internal::CancelableTask {
     501             :  public:
     502             :   // Takes ownership of the contents of pending_phantom_callbacks, leaving it in
     503             :   // the same state it would be after a call to Clear().
     504          72 :   PendingPhantomCallbacksSecondPassTask(
     505             :       std::vector<PendingPhantomCallback>* pending_phantom_callbacks,
     506             :       Isolate* isolate)
     507          72 :       : CancelableTask(isolate), isolate_(isolate) {
     508             :     pending_phantom_callbacks_.swap(*pending_phantom_callbacks);
     509          72 :   }
     510             : 
     511         288 :   void RunInternal() override {
     512         144 :     TRACE_EVENT0("v8", "V8.GCPhantomHandleProcessingCallback");
     513             :     isolate()->heap()->CallGCPrologueCallbacks(
     514          72 :         GCType::kGCTypeProcessWeakCallbacks, kNoGCCallbackFlags);
     515          72 :     InvokeSecondPassPhantomCallbacks(&pending_phantom_callbacks_, isolate());
     516             :     isolate()->heap()->CallGCEpilogueCallbacks(
     517          72 :         GCType::kGCTypeProcessWeakCallbacks, kNoGCCallbackFlags);
     518          72 :   }
     519             : 
     520             :   Isolate* isolate() { return isolate_; }
     521             : 
     522             :  private:
     523             :   Isolate* isolate_;
     524             :   std::vector<PendingPhantomCallback> pending_phantom_callbacks_;
     525             : 
     526             :   DISALLOW_COPY_AND_ASSIGN(PendingPhantomCallbacksSecondPassTask);
     527             : };
     528             : 
     529       54999 : GlobalHandles::GlobalHandles(Isolate* isolate)
     530             :     : isolate_(isolate),
     531             :       number_of_global_handles_(0),
     532             :       first_block_(nullptr),
     533             :       first_used_block_(nullptr),
     534             :       first_free_(nullptr),
     535             :       post_gc_processing_count_(0),
     536      164997 :       number_of_phantom_handle_resets_(0) {}
     537             : 
     538       53365 : GlobalHandles::~GlobalHandles() {
     539       96248 :   NodeBlock* block = first_block_;
     540      149613 :   while (block != nullptr) {
     541             :     NodeBlock* tmp = block->next();
     542       42883 :     delete block;
     543             :     block = tmp;
     544             :   }
     545       53365 :   first_block_ = nullptr;
     546       53365 : }
     547             : 
     548             : 
     549     3446567 : Handle<Object> GlobalHandles::Create(Object* value) {
     550     3446567 :   if (first_free_ == nullptr) {
     551       89048 :     first_block_ = new NodeBlock(this, first_block_);
     552             :     first_block_->PutNodesOnFreeList(&first_free_);
     553             :   }
     554             :   DCHECK_NOT_NULL(first_free_);
     555             :   // Take the first node in the free list.
     556     3446567 :   Node* result = first_free_;
     557     4143169 :   first_free_ = result->next_free();
     558     3446567 :   result->Acquire(value);
     559     4143168 :   if (isolate_->heap()->InNewSpace(value) &&
     560      696602 :       !result->is_in_new_space_list()) {
     561      590381 :     new_space_nodes_.push_back(result);
     562      590381 :     result->set_in_new_space_list(true);
     563             :   }
     564     6893132 :   return result->handle();
     565             : }
     566             : 
     567             : 
     568          10 : Handle<Object> GlobalHandles::CopyGlobal(Object** location) {
     569             :   DCHECK_NOT_NULL(location);
     570          20 :   return Node::FromLocation(location)->GetGlobalHandles()->Create(*location);
     571             : }
     572             : 
     573             : 
     574     2976450 : void GlobalHandles::Destroy(Object** location) {
     575     2976450 :   if (location != nullptr) Node::FromLocation(location)->Release();
     576     2976450 : }
     577             : 
     578             : 
     579             : typedef v8::WeakCallbackInfo<void>::Callback GenericCallback;
     580             : 
     581             : 
     582      740516 : void GlobalHandles::MakeWeak(Object** location, void* parameter,
     583             :                              GenericCallback phantom_callback,
     584             :                              v8::WeakCallbackType type) {
     585      740516 :   Node::FromLocation(location)->MakeWeak(parameter, phantom_callback, type);
     586      740516 : }
     587             : 
     588          11 : void GlobalHandles::MakeWeak(Object*** location_addr) {
     589          11 :   Node::FromLocation(*location_addr)->MakeWeak(location_addr);
     590          11 : }
     591             : 
     592          25 : void* GlobalHandles::ClearWeakness(Object** location) {
     593          25 :   return Node::FromLocation(location)->ClearWeakness();
     594             : }
     595             : 
     596             : 
     597           0 : void GlobalHandles::MarkIndependent(Object** location) {
     598             :   Node::FromLocation(location)->MarkIndependent();
     599           0 : }
     600             : 
     601           0 : bool GlobalHandles::IsIndependent(Object** location) {
     602           0 :   return Node::FromLocation(location)->is_independent();
     603             : }
     604             : 
     605             : 
     606          40 : bool GlobalHandles::IsNearDeath(Object** location) {
     607          40 :   return Node::FromLocation(location)->IsNearDeath();
     608             : }
     609             : 
     610             : 
     611          24 : bool GlobalHandles::IsWeak(Object** location) {
     612          24 :   return Node::FromLocation(location)->IsWeak();
     613             : }
     614             : 
     615             : DISABLE_CFI_PERF
     616      176900 : void GlobalHandles::IterateWeakRoots(RootVisitor* v) {
     617    11108576 :   for (NodeIterator it(this); !it.done(); it.Advance()) {
     618    11051776 :     Node* node = it.node();
     619    11051776 :     if (node->IsWeakRetainer()) {
     620             :       // Pending weak phantom handles die immediately. Everything else survives.
     621      337543 :       if (node->IsPendingPhantomResetHandle()) {
     622             :         node->ResetPhantomHandle();
     623          11 :         ++number_of_phantom_handle_resets_;
     624      337532 :       } else if (node->IsPendingPhantomCallback()) {
     625             :         node->CollectPhantomCallbackData(isolate(),
     626      240200 :                                          &pending_phantom_callbacks_);
     627             :       } else {
     628      217432 :         v->VisitRootPointer(Root::kGlobalHandles, node->location());
     629             :       }
     630             :     }
     631             :   }
     632       56800 : }
     633             : 
     634             : 
     635       56800 : void GlobalHandles::IdentifyWeakHandles(WeakSlotCallback f) {
     636    11108576 :   for (NodeIterator it(this); !it.done(); it.Advance()) {
     637    22103552 :     if (it.node()->IsWeak() && f(it.node()->location())) {
     638             :       it.node()->MarkPending();
     639             :     }
     640             :   }
     641       56800 : }
     642             : 
     643       29652 : void GlobalHandles::IterateNewSpaceStrongAndDependentRoots(RootVisitor* v) {
     644      623281 :   for (Node* node : new_space_nodes_) {
     645     1542540 :     if (node->IsStrongRetainer() ||
     646      795870 :         (node->IsWeakRetainer() && !node->is_independent() &&
     647             :          node->is_active())) {
     648      538822 :       v->VisitRootPointer(Root::kGlobalHandles, node->location());
     649             :     }
     650             :   }
     651       29652 : }
     652             : 
     653           0 : void GlobalHandles::IterateNewSpaceStrongAndDependentRootsAndIdentifyUnmodified(
     654             :     RootVisitor* v, size_t start, size_t end) {
     655           0 :   for (size_t i = start; i < end; ++i) {
     656           0 :     Node* node = new_space_nodes_[i];
     657           0 :     if (node->IsWeak() && !JSObject::IsUnmodifiedApiObject(node->location())) {
     658             :       node->set_active(true);
     659             :     }
     660           0 :     if (node->IsStrongRetainer() ||
     661           0 :         (node->IsWeakRetainer() && !node->is_independent() &&
     662             :          node->is_active())) {
     663           0 :       v->VisitRootPointer(Root::kGlobalHandles, node->location());
     664             :     }
     665             :   }
     666           0 : }
     667             : 
     668       29652 : void GlobalHandles::IdentifyWeakUnmodifiedObjects(
     669             :     WeakSlotCallback is_unmodified) {
     670      623281 :   for (Node* node : new_space_nodes_) {
     671      563977 :     if (node->IsWeak() && !is_unmodified(node->location())) {
     672             :       node->set_active(true);
     673             :     }
     674             :   }
     675       29652 : }
     676             : 
     677             : 
     678       29652 : void GlobalHandles::MarkNewSpaceWeakUnmodifiedObjectsPending(
     679             :     WeakSlotCallbackWithHeap is_unscavenged) {
     680      623281 :   for (Node* node : new_space_nodes_) {
     681             :     DCHECK(node->is_in_new_space_list());
     682     1302505 :     if ((node->is_independent() || !node->is_active()) && node->IsWeak() &&
     683       17003 :         is_unscavenged(isolate_->heap(), node->location())) {
     684             :       node->MarkPending();
     685             :     }
     686             :   }
     687       29652 : }
     688             : 
     689       32246 : void GlobalHandles::IterateNewSpaceWeakUnmodifiedRoots(RootVisitor* v) {
     690      623281 :   for (Node* node : new_space_nodes_) {
     691             :     DCHECK(node->is_in_new_space_list());
     692     1285502 :     if ((node->is_independent() || !node->is_active()) &&
     693             :         node->IsWeakRetainer()) {
     694             :       // Pending weak phantom handles die immediately. Everything else survives.
     695       17003 :       if (node->IsPendingPhantomResetHandle()) {
     696             :         node->ResetPhantomHandle();
     697           0 :         ++number_of_phantom_handle_resets_;
     698       17003 :       } else if (node->IsPendingPhantomCallback()) {
     699             :         node->CollectPhantomCallbackData(isolate(),
     700        5188 :                                          &pending_phantom_callbacks_);
     701             :       } else {
     702       14409 :         v->VisitRootPointer(Root::kGlobalHandles, node->location());
     703             :       }
     704             :     }
     705             :   }
     706       29652 : }
     707             : 
     708          87 : void GlobalHandles::InvokeSecondPassPhantomCallbacks(
     709             :     std::vector<PendingPhantomCallback>* callbacks, Isolate* isolate) {
     710         451 :   while (!callbacks->empty()) {
     711         277 :     auto callback = callbacks->back();
     712             :     callbacks->pop_back();
     713             :     DCHECK_NULL(callback.node());
     714             :     // Fire second pass callback
     715         277 :     callback.Invoke(isolate);
     716             :   }
     717          87 : }
     718             : 
     719             : 
     720       29652 : int GlobalHandles::PostScavengeProcessing(
     721             :     const int initial_post_gc_processing_count) {
     722             :   int freed_nodes = 0;
     723      623281 :   for (Node* node : new_space_nodes_) {
     724             :     DCHECK(node->is_in_new_space_list());
     725      563977 :     if (!node->IsRetainer()) {
     726             :       // Free nodes do not have weak callbacks. Do not use them to compute
     727             :       // the freed_nodes.
     728             :       continue;
     729             :     }
     730             :     // Skip dependent or unmodified handles. Their weak callbacks might expect
     731             :     // to be
     732             :     // called between two global garbage collection callbacks which
     733             :     // are not called for minor collections.
     734     1092053 :       if (!node->is_independent() && (node->is_active())) {
     735             :         node->set_active(false);
     736             :         continue;
     737             :       }
     738             :       node->set_active(false);
     739             : 
     740      163800 :     if (node->PostGarbageCollectionProcessing(isolate_)) {
     741           0 :       if (initial_post_gc_processing_count != post_gc_processing_count_) {
     742             :         // Weak callback triggered another GC and another round of
     743             :         // PostGarbageCollection processing.  The current node might
     744             :         // have been deleted in that round, so we need to bail out (or
     745             :         // restart the processing).
     746             :         return freed_nodes;
     747             :       }
     748             :     }
     749      163800 :     if (!node->IsRetainer()) {
     750           0 :       freed_nodes++;
     751             :     }
     752             :   }
     753             :   return freed_nodes;
     754             : }
     755             : 
     756             : 
     757       56800 : int GlobalHandles::PostMarkSweepProcessing(
     758             :     const int initial_post_gc_processing_count) {
     759             :   int freed_nodes = 0;
     760    11058656 :   for (NodeIterator it(this); !it.done(); it.Advance()) {
     761    22003712 :     if (!it.node()->IsRetainer()) {
     762             :       // Free nodes do not have weak callbacks. Do not use them to compute
     763             :       // the freed_nodes.
     764             :       continue;
     765             :     }
     766             :     it.node()->set_active(false);
     767     1043397 :     if (it.node()->PostGarbageCollectionProcessing(isolate_)) {
     768      112263 :       if (initial_post_gc_processing_count != post_gc_processing_count_) {
     769             :         // See the comment above.
     770             :         return freed_nodes;
     771             :       }
     772             :     }
     773     1043397 :     if (!it.node()->IsRetainer()) {
     774      112258 :       freed_nodes++;
     775             :     }
     776             :   }
     777       56800 :   return freed_nodes;
     778             : }
     779             : 
     780             : 
     781       86452 : void GlobalHandles::UpdateListOfNewSpaceNodes() {
     782             :   size_t last = 0;
     783     1565361 :   for (Node* node : new_space_nodes_) {
     784             :     DCHECK(node->is_in_new_space_list());
     785      758824 :     if (node->IsRetainer()) {
     786      633633 :       if (isolate_->heap()->InNewSpace(node->object())) {
     787      722298 :         new_space_nodes_[last++] = node;
     788      361149 :         isolate_->heap()->IncrementNodesCopiedInNewSpace();
     789             :       } else {
     790             :         node->set_in_new_space_list(false);
     791      272484 :         isolate_->heap()->IncrementNodesPromoted();
     792             :       }
     793             :     } else {
     794             :       node->set_in_new_space_list(false);
     795      125191 :       isolate_->heap()->IncrementNodesDiedInNewSpace();
     796             :     }
     797             :   }
     798             :   DCHECK_LE(last, new_space_nodes_.size());
     799       86452 :   new_space_nodes_.resize(last);
     800             :   new_space_nodes_.shrink_to_fit();
     801       86452 : }
     802             : 
     803             : 
     804       86452 : int GlobalHandles::DispatchPendingPhantomCallbacks(
     805      122883 :     bool synchronous_second_pass) {
     806             :   int freed_nodes = 0;
     807             :   std::vector<PendingPhantomCallback> second_pass_callbacks;
     808             :   {
     809             :     // The initial pass callbacks must simply clear the nodes.
     810      295598 :     for (auto callback : pending_phantom_callbacks_) {
     811             :       // Skip callbacks that have already been processed once.
     812      122694 :       if (callback.node() == nullptr) continue;
     813      122694 :       callback.Invoke(isolate());
     814      122694 :       if (callback.callback()) second_pass_callbacks.push_back(callback);
     815      122694 :       freed_nodes++;
     816             :     }
     817             :   }
     818             :   pending_phantom_callbacks_.clear();
     819       86452 :   if (!second_pass_callbacks.empty()) {
     820          87 :     if (FLAG_optimize_for_size || FLAG_predictable || synchronous_second_pass) {
     821             :       isolate()->heap()->CallGCPrologueCallbacks(
     822          15 :           GCType::kGCTypeProcessWeakCallbacks, kNoGCCallbackFlags);
     823          15 :       InvokeSecondPassPhantomCallbacks(&second_pass_callbacks, isolate());
     824             :       isolate()->heap()->CallGCEpilogueCallbacks(
     825          15 :           GCType::kGCTypeProcessWeakCallbacks, kNoGCCallbackFlags);
     826             :     } else {
     827             :       auto task = new PendingPhantomCallbacksSecondPassTask(
     828          72 :           &second_pass_callbacks, isolate());
     829          72 :       V8::GetCurrentPlatform()->CallOnForegroundThread(
     830         144 :           reinterpret_cast<v8::Isolate*>(isolate()), task);
     831             :     }
     832             :   }
     833       86451 :   return freed_nodes;
     834             : }
     835             : 
     836             : 
     837      122971 : void GlobalHandles::PendingPhantomCallback::Invoke(Isolate* isolate) {
     838             :   Data::Callback* callback_addr = nullptr;
     839      122971 :   if (node_ != nullptr) {
     840             :     // Initialize for first pass callback.
     841             :     DCHECK(node_->state() == Node::NEAR_DEATH);
     842      122694 :     callback_addr = &callback_;
     843             :   }
     844             :   Data data(reinterpret_cast<v8::Isolate*>(isolate), parameter_,
     845      122971 :             embedder_fields_, callback_addr);
     846      122971 :   Data::Callback callback = callback_;
     847      122971 :   callback_ = nullptr;
     848      122971 :   callback(data);
     849      122971 :   if (node_ != nullptr) {
     850             :     // Transition to second pass state.
     851             :     DCHECK(node_->state() == Node::FREE);
     852      122694 :     node_ = nullptr;
     853             :   }
     854      122971 : }
     855             : 
     856             : 
     857       86452 : int GlobalHandles::PostGarbageCollectionProcessing(
     858             :     GarbageCollector collector, const v8::GCCallbackFlags gc_callback_flags) {
     859             :   // Process weak global handle callbacks. This must be done after the
     860             :   // GC is completely done, because the callbacks may invoke arbitrary
     861             :   // API functions.
     862             :   DCHECK(isolate_->heap()->gc_state() == Heap::NOT_IN_GC);
     863       86452 :   const int initial_post_gc_processing_count = ++post_gc_processing_count_;
     864             :   int freed_nodes = 0;
     865             :   bool synchronous_second_pass =
     866       86452 :       (gc_callback_flags &
     867             :        (kGCCallbackFlagForced | kGCCallbackFlagCollectAllAvailableGarbage |
     868       86452 :         kGCCallbackFlagSynchronousPhantomCallbackProcessing)) != 0;
     869       86452 :   freed_nodes += DispatchPendingPhantomCallbacks(synchronous_second_pass);
     870       86451 :   if (initial_post_gc_processing_count != post_gc_processing_count_) {
     871             :     // If the callbacks caused a nested GC, then return.  See comment in
     872             :     // PostScavengeProcessing.
     873             :     return freed_nodes;
     874             :   }
     875       86451 :   if (Heap::IsYoungGenerationCollector(collector)) {
     876       29652 :     freed_nodes += PostScavengeProcessing(initial_post_gc_processing_count);
     877             :   } else {
     878       56799 :     freed_nodes += PostMarkSweepProcessing(initial_post_gc_processing_count);
     879             :   }
     880       86452 :   if (initial_post_gc_processing_count != post_gc_processing_count_) {
     881             :     // If the callbacks caused a nested GC, then return.  See comment in
     882             :     // PostScavengeProcessing.
     883             :     return freed_nodes;
     884             :   }
     885       86452 :   if (initial_post_gc_processing_count == post_gc_processing_count_) {
     886       86452 :     UpdateListOfNewSpaceNodes();
     887             :   }
     888       86452 :   return freed_nodes;
     889             : }
     890             : 
     891      144144 : void GlobalHandles::IterateStrongRoots(RootVisitor* v) {
     892    17217296 :   for (NodeIterator it(this); !it.done(); it.Advance()) {
     893    34146304 :     if (it.node()->IsStrongRetainer()) {
     894     1487881 :       v->VisitRootPointer(Root::kGlobalHandles, it.node()->location());
     895             :     }
     896             :   }
     897      144144 : }
     898             : 
     899             : 
     900             : DISABLE_CFI_PERF
     901       58785 : void GlobalHandles::IterateAllRoots(RootVisitor* v) {
     902    11626145 :   for (NodeIterator it(this); !it.done(); it.Advance()) {
     903    23134720 :     if (it.node()->IsRetainer()) {
     904     1085244 :       v->VisitRootPointer(Root::kGlobalHandles, it.node()->location());
     905             :     }
     906             :   }
     907       58785 : }
     908             : 
     909             : DISABLE_CFI_PERF
     910           0 : void GlobalHandles::IterateAllNewSpaceRoots(RootVisitor* v) {
     911           0 :   for (Node* node : new_space_nodes_) {
     912           0 :     if (node->IsRetainer()) {
     913           0 :       v->VisitRootPointer(Root::kGlobalHandles, node->location());
     914             :     }
     915             :   }
     916           0 : }
     917             : 
     918             : DISABLE_CFI_PERF
     919           0 : void GlobalHandles::IterateNewSpaceRoots(RootVisitor* v, size_t start,
     920             :                                          size_t end) {
     921           0 :   for (size_t i = start; i < end; ++i) {
     922           0 :     Node* node = new_space_nodes_[i];
     923           0 :     if (node->IsRetainer()) {
     924           0 :       v->VisitRootPointer(Root::kGlobalHandles, node->location());
     925             :     }
     926             :   }
     927           0 : }
     928             : 
     929             : DISABLE_CFI_PERF
     930           0 : void GlobalHandles::ApplyPersistentHandleVisitor(
     931          25 :     v8::PersistentHandleVisitor* visitor, GlobalHandles::Node* node) {
     932          25 :   v8::Value* value = ToApi<v8::Value>(Handle<Object>(node->location()));
     933             :   visitor->VisitPersistentHandle(
     934             :       reinterpret_cast<v8::Persistent<v8::Value>*>(&value),
     935          50 :       node->wrapper_class_id());
     936           0 : }
     937             : 
     938             : DISABLE_CFI_PERF
     939         324 : void GlobalHandles::IterateAllRootsWithClassIds(
     940             :     v8::PersistentHandleVisitor* visitor) {
     941       83268 :   for (NodeIterator it(this); !it.done(); it.Advance()) {
     942      165888 :     if (it.node()->IsRetainer() && it.node()->has_wrapper_class_id()) {
     943             :       ApplyPersistentHandleVisitor(visitor, it.node());
     944             :     }
     945             :   }
     946         324 : }
     947             : 
     948             : 
     949             : DISABLE_CFI_PERF
     950           5 : void GlobalHandles::IterateAllRootsInNewSpaceWithClassIds(
     951             :     v8::PersistentHandleVisitor* visitor) {
     952          20 :   for (Node* node : new_space_nodes_) {
     953          10 :     if (node->IsRetainer() && node->has_wrapper_class_id()) {
     954             :       ApplyPersistentHandleVisitor(visitor, node);
     955             :     }
     956             :   }
     957           5 : }
     958             : 
     959             : 
     960             : DISABLE_CFI_PERF
     961           0 : void GlobalHandles::IterateWeakRootsInNewSpaceWithClassIds(
     962             :     v8::PersistentHandleVisitor* visitor) {
     963           0 :   for (Node* node : new_space_nodes_) {
     964           0 :     if (node->has_wrapper_class_id() && node->IsWeak()) {
     965             :       ApplyPersistentHandleVisitor(visitor, node);
     966             :     }
     967             :   }
     968           0 : }
     969             : 
     970          18 : void GlobalHandles::RecordStats(HeapStats* stats) {
     971          18 :   *stats->global_handle_count = 0;
     972          18 :   *stats->weak_global_handle_count = 0;
     973          18 :   *stats->pending_global_handle_count = 0;
     974          18 :   *stats->near_death_global_handle_count = 0;
     975          18 :   *stats->free_global_handle_count = 0;
     976          18 :   for (NodeIterator it(this); !it.done(); it.Advance()) {
     977           0 :     *stats->global_handle_count += 1;
     978           0 :     if (it.node()->state() == Node::WEAK) {
     979           0 :       *stats->weak_global_handle_count += 1;
     980           0 :     } else if (it.node()->state() == Node::PENDING) {
     981           0 :       *stats->pending_global_handle_count += 1;
     982           0 :     } else if (it.node()->state() == Node::NEAR_DEATH) {
     983           0 :       *stats->near_death_global_handle_count += 1;
     984           0 :     } else if (it.node()->state() == Node::FREE) {
     985           0 :       *stats->free_global_handle_count += 1;
     986             :     }
     987             :   }
     988          18 : }
     989             : 
     990             : #ifdef DEBUG
     991             : 
     992             : void GlobalHandles::PrintStats() {
     993             :   int total = 0;
     994             :   int weak = 0;
     995             :   int pending = 0;
     996             :   int near_death = 0;
     997             :   int destroyed = 0;
     998             : 
     999             :   for (NodeIterator it(this); !it.done(); it.Advance()) {
    1000             :     total++;
    1001             :     if (it.node()->state() == Node::WEAK) weak++;
    1002             :     if (it.node()->state() == Node::PENDING) pending++;
    1003             :     if (it.node()->state() == Node::NEAR_DEATH) near_death++;
    1004             :     if (it.node()->state() == Node::FREE) destroyed++;
    1005             :   }
    1006             : 
    1007             :   PrintF("Global Handle Statistics:\n");
    1008             :   PrintF("  allocated memory = %" PRIuS "B\n", total * sizeof(Node));
    1009             :   PrintF("  # weak       = %d\n", weak);
    1010             :   PrintF("  # pending    = %d\n", pending);
    1011             :   PrintF("  # near_death = %d\n", near_death);
    1012             :   PrintF("  # free       = %d\n", destroyed);
    1013             :   PrintF("  # total      = %d\n", total);
    1014             : }
    1015             : 
    1016             : 
    1017             : void GlobalHandles::Print() {
    1018             :   PrintF("Global handles:\n");
    1019             :   for (NodeIterator it(this); !it.done(); it.Advance()) {
    1020             :     PrintF("  handle %p to %p%s\n",
    1021             :            reinterpret_cast<void*>(it.node()->location()),
    1022             :            reinterpret_cast<void*>(it.node()->object()),
    1023             :            it.node()->IsWeak() ? " (weak)" : "");
    1024             :   }
    1025             : }
    1026             : 
    1027             : #endif
    1028             : 
    1029       53365 : void GlobalHandles::TearDown() {}
    1030             : 
    1031       54999 : EternalHandles::EternalHandles() : size_(0) {
    1032      109998 :   for (unsigned i = 0; i < arraysize(singleton_handles_); i++) {
    1033       54999 :     singleton_handles_[i] = kInvalidIndex;
    1034             :   }
    1035       54999 : }
    1036             : 
    1037             : 
    1038       53365 : EternalHandles::~EternalHandles() {
    1039      106893 :   for (Object** block : blocks_) delete[] block;
    1040       53365 : }
    1041             : 
    1042      202771 : void EternalHandles::IterateAllRoots(RootVisitor* visitor) {
    1043      202771 :   int limit = size_;
    1044      406066 :   for (Object** block : blocks_) {
    1045             :     DCHECK_GT(limit, 0);
    1046             :     visitor->VisitRootPointers(Root::kEternalHandles, block,
    1047        1048 :                                block + Min(limit, kSize));
    1048         524 :     limit -= kSize;
    1049             :   }
    1050      202771 : }
    1051             : 
    1052       29652 : void EternalHandles::IterateNewSpaceRoots(RootVisitor* visitor) {
    1053       74244 :   for (int index : new_space_indices_) {
    1054       29880 :     visitor->VisitRootPointer(Root::kEternalHandles, GetLocation(index));
    1055             :   }
    1056       29652 : }
    1057             : 
    1058             : 
    1059       86452 : void EternalHandles::PostGarbageCollectionProcessing(Heap* heap) {
    1060             :   size_t last = 0;
    1061      213795 :   for (int index : new_space_indices_) {
    1062       81782 :     if (heap->InNewSpace(*GetLocation(index))) {
    1063       40842 :       new_space_indices_[last++] = index;
    1064             :     }
    1065             :   }
    1066             :   DCHECK_LE(last, new_space_indices_.size());
    1067       86452 :   new_space_indices_.resize(last);
    1068       86452 : }
    1069             : 
    1070             : 
    1071       20558 : void EternalHandles::Create(Isolate* isolate, Object* object, int* index) {
    1072             :   DCHECK_EQ(kInvalidIndex, *index);
    1073       41116 :   if (object == nullptr) return;
    1074             :   DCHECK_NE(isolate->heap()->the_hole_value(), object);
    1075       20558 :   int block = size_ >> kShift;
    1076       20558 :   int offset = size_ & kMask;
    1077             :   // need to resize
    1078       20558 :   if (offset == 0) {
    1079         163 :     Object** next_block = new Object*[kSize];
    1080         163 :     Object* the_hole = isolate->heap()->the_hole_value();
    1081             :     MemsetPointer(next_block, the_hole, kSize);
    1082       20721 :     blocks_.push_back(next_block);
    1083             :   }
    1084             :   DCHECK_EQ(isolate->heap()->the_hole_value(), blocks_[block][offset]);
    1085       41116 :   blocks_[block][offset] = object;
    1086       20558 :   if (isolate->heap()->InNewSpace(object)) {
    1087       20475 :     new_space_indices_.push_back(size_);
    1088             :   }
    1089       20558 :   *index = size_++;
    1090             : }
    1091             : 
    1092             : 
    1093             : }  // namespace internal
    1094             : }  // namespace v8

Generated by: LCOV version 1.10