LCOV - code coverage report
Current view: top level - src - global-handles.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 391 432 90.5 %
Date: 2019-04-17 Functions: 61 68 89.7 %

          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-inl.h"
       8             : #include "src/base/compiler-specific.h"
       9             : #include "src/cancelable-task.h"
      10             : #include "src/heap/embedder-tracing.h"
      11             : #include "src/heap/heap-write-barrier-inl.h"
      12             : #include "src/objects-inl.h"
      13             : #include "src/objects/slots.h"
      14             : #include "src/task-utils.h"
      15             : #include "src/v8.h"
      16             : #include "src/visitors.h"
      17             : #include "src/vm-state-inl.h"
      18             : 
      19             : namespace v8 {
      20             : namespace internal {
      21             : 
      22             : namespace {
      23             : 
      24             : constexpr size_t kBlockSize = 256;
      25             : 
      26             : }  // namespace
      27             : 
      28             : template <class _NodeType>
      29      111472 : class GlobalHandles::NodeBlock final {
      30             :  public:
      31             :   using BlockType = NodeBlock<_NodeType>;
      32             :   using NodeType = _NodeType;
      33             : 
      34             :   V8_INLINE static NodeBlock* From(NodeType* node);
      35             : 
      36             :   NodeBlock(GlobalHandles* global_handles,
      37             :             GlobalHandles::NodeSpace<NodeType>* space,
      38             :             NodeBlock* next) V8_NOEXCEPT : next_(next),
      39             :                                            global_handles_(global_handles),
      40    14324152 :                                            space_(space) {}
      41             : 
      42   178999040 :   NodeType* at(size_t index) { return &nodes_[index]; }
      43             :   const NodeType* at(size_t index) const { return &nodes_[index]; }
      44             :   GlobalHandles::NodeSpace<NodeType>* space() const { return space_; }
      45             :   GlobalHandles* global_handles() const { return global_handles_; }
      46             : 
      47             :   V8_INLINE bool IncreaseUsage();
      48             :   V8_INLINE bool DecreaseUsage();
      49             : 
      50             :   V8_INLINE void ListAdd(NodeBlock** top);
      51             :   V8_INLINE void ListRemove(NodeBlock** top);
      52             : 
      53             :   NodeBlock* next() const { return next_; }
      54             :   NodeBlock* next_used() const { return next_used_; }
      55             : 
      56             :  private:
      57             :   NodeType nodes_[kBlockSize];
      58             :   NodeBlock* const next_;
      59             :   GlobalHandles* const global_handles_;
      60             :   GlobalHandles::NodeSpace<NodeType>* const space_;
      61             :   NodeBlock* next_used_ = nullptr;
      62             :   NodeBlock* prev_used_ = nullptr;
      63             :   uint32_t used_nodes_ = 0;
      64             : 
      65             :   DISALLOW_COPY_AND_ASSIGN(NodeBlock);
      66             : };
      67             : 
      68             : template <class NodeType>
      69             : GlobalHandles::NodeBlock<NodeType>* GlobalHandles::NodeBlock<NodeType>::From(
      70             :     NodeType* node) {
      71             :   uintptr_t ptr =
      72    20113453 :       reinterpret_cast<uintptr_t>(node) - sizeof(NodeType) * node->index();
      73    20113453 :   BlockType* block = reinterpret_cast<BlockType*>(ptr);
      74             :   DCHECK_EQ(node, block->at(node->index()));
      75             :   return block;
      76             : }
      77             : 
      78             : template <class NodeType>
      79             : bool GlobalHandles::NodeBlock<NodeType>::IncreaseUsage() {
      80             :   DCHECK_LT(used_nodes_, kBlockSize);
      81     6980875 :   return used_nodes_++ == 0;
      82             : }
      83             : 
      84             : template <class NodeType>
      85             : void GlobalHandles::NodeBlock<NodeType>::ListAdd(BlockType** top) {
      86       86957 :   BlockType* old_top = *top;
      87       86957 :   *top = this;
      88       86957 :   next_used_ = old_top;
      89       86957 :   prev_used_ = nullptr;
      90       86957 :   if (old_top != nullptr) {
      91       13270 :     old_top->prev_used_ = this;
      92             :   }
      93             : }
      94             : 
      95             : template <class NodeType>
      96             : bool GlobalHandles::NodeBlock<NodeType>::DecreaseUsage() {
      97             :   DCHECK_GT(used_nodes_, 0);
      98     6566284 :   return --used_nodes_ == 0;
      99             : }
     100             : 
     101             : template <class NodeType>
     102             : void GlobalHandles::NodeBlock<NodeType>::ListRemove(BlockType** top) {
     103       73093 :   if (next_used_ != nullptr) next_used_->prev_used_ = prev_used_;
     104       73093 :   if (prev_used_ != nullptr) prev_used_->next_used_ = next_used_;
     105       73093 :   if (this == *top) {
     106       68647 :     *top = next_used_;
     107             :   }
     108             : }
     109             : 
     110             : template <class BlockType>
     111             : class GlobalHandles::NodeIterator final {
     112             :  public:
     113             :   using NodeType = typename BlockType::NodeType;
     114             : 
     115             :   // Iterator traits.
     116             :   using iterator_category = std::forward_iterator_tag;
     117             :   using difference_type = std::ptrdiff_t;
     118             :   using value_type = NodeType*;
     119             :   using reference = value_type;
     120             :   using pointer = value_type*;
     121             : 
     122             :   explicit NodeIterator(BlockType* block) V8_NOEXCEPT : block_(block) {}
     123             :   NodeIterator(NodeIterator&& other) V8_NOEXCEPT : block_(other.block_),
     124             :                                                    index_(other.index_) {}
     125             : 
     126             :   bool operator==(const NodeIterator& other) const {
     127             :     return block_ == other.block_;
     128             :   }
     129             :   bool operator!=(const NodeIterator& other) const {
     130             :     return block_ != other.block_;
     131             :   }
     132             : 
     133             :   NodeIterator& operator++() {
     134   164730624 :     if (++index_ < kBlockSize) return *this;
     135             :     index_ = 0;
     136             :     block_ = block_->next_used();
     137             :     return *this;
     138             :   }
     139             : 
     140             :   NodeType* operator*() { return block_->at(index_); }
     141             :   NodeType* operator->() { return block_->at(index_); }
     142             : 
     143             :  private:
     144             :   BlockType* block_ = nullptr;
     145             :   size_t index_ = 0;
     146             : 
     147             :   DISALLOW_COPY_AND_ASSIGN(NodeIterator);
     148             : };
     149             : 
     150             : template <class NodeType>
     151             : class GlobalHandles::NodeSpace final {
     152             :  public:
     153             :   using BlockType = NodeBlock<NodeType>;
     154             :   using iterator = NodeIterator<BlockType>;
     155             : 
     156             :   static NodeSpace* From(NodeType* node);
     157             :   static void Release(NodeType* node);
     158             : 
     159             :   explicit NodeSpace(GlobalHandles* global_handles) V8_NOEXCEPT
     160      124852 :       : global_handles_(global_handles) {}
     161             :   ~NodeSpace();
     162             : 
     163             :   V8_INLINE NodeType* Acquire(Object object);
     164             : 
     165             :   iterator begin() { return iterator(first_used_block_); }
     166             :   iterator end() { return iterator(nullptr); }
     167             : 
     168             :  private:
     169             :   void PutNodesOnFreeList(BlockType* block);
     170             :   V8_INLINE void Free(NodeType* node);
     171             : 
     172             :   GlobalHandles* const global_handles_;
     173             :   BlockType* first_block_ = nullptr;
     174             :   BlockType* first_used_block_ = nullptr;
     175             :   NodeType* first_free_ = nullptr;
     176             : };
     177             : 
     178             : template <class NodeType>
     179      124822 : GlobalHandles::NodeSpace<NodeType>::~NodeSpace() {
     180      124822 :   auto* block = first_block_;
     181      180558 :   while (block != nullptr) {
     182             :     auto* tmp = block->next();
     183      111472 :     delete block;
     184             :     block = tmp;
     185             :   }
     186      124822 : }
     187             : 
     188             : template <class NodeType>
     189             : NodeType* GlobalHandles::NodeSpace<NodeType>::Acquire(Object object) {
     190     6980875 :   if (first_free_ == nullptr) {
     191      111472 :     first_block_ = new BlockType(global_handles_, this, first_block_);
     192             :     PutNodesOnFreeList(first_block_);
     193             :   }
     194             :   DCHECK_NOT_NULL(first_free_);
     195     6980875 :   NodeType* node = first_free_;
     196     6980875 :   first_free_ = first_free_->next_free();
     197             :   node->Acquire(object);
     198             :   BlockType* block = BlockType::From(node);
     199     6980875 :   if (block->IncreaseUsage()) {
     200             :     block->ListAdd(&first_used_block_);
     201             :   }
     202    13961750 :   global_handles_->isolate()->counters()->global_handles()->Increment();
     203     6980875 :   global_handles_->handles_count_++;
     204             :   DCHECK(node->IsInUse());
     205             :   return node;
     206             : }
     207             : 
     208             : template <class NodeType>
     209             : void GlobalHandles::NodeSpace<NodeType>::PutNodesOnFreeList(BlockType* block) {
     210    28592568 :   for (int32_t i = kBlockSize - 1; i >= 0; --i) {
     211    14268416 :     NodeType* node = block->at(i);
     212             :     const uint8_t index = static_cast<uint8_t>(i);
     213             :     DCHECK_EQ(i, index);
     214             :     node->set_index(index);
     215    14268416 :     node->Free(first_free_);
     216    14268416 :     first_free_ = node;
     217             :   }
     218             : }
     219             : 
     220             : template <class NodeType>
     221     6566284 : void GlobalHandles::NodeSpace<NodeType>::Release(NodeType* node) {
     222             :   BlockType* block = BlockType::From(node);
     223             :   block->space()->Free(node);
     224     6566283 : }
     225             : 
     226             : template <class NodeType>
     227             : void GlobalHandles::NodeSpace<NodeType>::Free(NodeType* node) {
     228     6566284 :   node->Release(first_free_);
     229     6566284 :   first_free_ = node;
     230             :   BlockType* block = BlockType::From(node);
     231     6566284 :   if (block->DecreaseUsage()) {
     232             :     block->ListRemove(&first_used_block_);
     233             :   }
     234    13132568 :   global_handles_->isolate()->counters()->global_handles()->Decrement();
     235     6566283 :   global_handles_->handles_count_--;
     236             : }
     237             : 
     238             : template <class Child>
     239             : class NodeBase {
     240             :  public:
     241             :   static Child* FromLocation(Address* location) {
     242             :     return reinterpret_cast<Child*>(location);
     243             :   }
     244             : 
     245             :   NodeBase() {
     246             :     DCHECK_EQ(offsetof(NodeBase, object_), 0);
     247             :     DCHECK_EQ(offsetof(NodeBase, class_id_), Internals::kNodeClassIdOffset);
     248             :     DCHECK_EQ(offsetof(NodeBase, flags_), Internals::kNodeFlagsOffset);
     249             :   }
     250             : 
     251             : #ifdef ENABLE_HANDLE_ZAPPING
     252             :   ~NodeBase() {
     253             :     ClearFields();
     254    14268416 :     data_.next_free = nullptr;
     255    14268416 :     index_ = 0;
     256    14268416 :   }
     257             : #endif
     258             : 
     259             :   void Free(Child* free_list) {
     260             :     ClearFields();
     261             :     AsChild()->MarkAsFree();
     262    20834700 :     data_.next_free = free_list;
     263             :   }
     264             : 
     265             :   void Acquire(Object object) {
     266             :     DCHECK(!AsChild()->IsInUse());
     267             :     CheckFieldsAreCleared();
     268     6980875 :     object_ = object.ptr();
     269             :     AsChild()->MarkAsUsed();
     270     6980875 :     data_.parameter = nullptr;
     271             :     DCHECK(AsChild()->IsInUse());
     272             :   }
     273             : 
     274     6566284 :   void Release(Child* free_list) {
     275             :     DCHECK(AsChild()->IsInUse());
     276             :     Free(free_list);
     277             :     DCHECK(!AsChild()->IsInUse());
     278     6566284 :   }
     279             : 
     280             :   Object object() const { return Object(object_); }
     281    24255871 :   FullObjectSlot location() { return FullObjectSlot(&object_); }
     282     6980900 :   Handle<Object> handle() { return Handle<Object>(&object_); }
     283             : 
     284          10 :   uint8_t index() const { return index_; }
     285    14268416 :   void set_index(uint8_t value) { index_ = value; }
     286             : 
     287             :   uint16_t wrapper_class_id() const { return class_id_; }
     288             :   bool has_wrapper_class_id() const {
     289             :     return class_id_ != v8::HeapProfiler::kPersistentHandleNoClassId;
     290             :   }
     291             : 
     292             :   // Accessors for next free node in the free list.
     293             :   Child* next_free() {
     294             :     DCHECK(!AsChild()->IsInUse());
     295             :     return data_.next_free;
     296             :   }
     297             : 
     298             :   void set_parameter(void* parameter) {
     299             :     DCHECK(AsChild()->IsInUse());
     300     3675707 :     data_.parameter = parameter;
     301             :   }
     302             :   void* parameter() const {
     303             :     DCHECK(AsChild()->IsInUse());
     304             :     return data_.parameter;
     305             :   }
     306             : 
     307             :  protected:
     308             :   Child* AsChild() { return reinterpret_cast<Child*>(this); }
     309             :   const Child* AsChild() const { return reinterpret_cast<const Child*>(this); }
     310             : 
     311             :   void ClearFields() {
     312             :     // Zap the values for eager trapping.
     313    35103116 :     object_ = kGlobalHandleZapValue;
     314    35103116 :     class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
     315             :     AsChild()->ClearImplFields();
     316             :   }
     317             : 
     318             :   void CheckFieldsAreCleared() {
     319             :     DCHECK_EQ(kGlobalHandleZapValue, object_);
     320             :     DCHECK_EQ(v8::HeapProfiler::kPersistentHandleNoClassId, class_id_);
     321             :     AsChild()->CheckImplFieldsAreCleared();
     322             :   }
     323             : 
     324             :   // Storage for object pointer.
     325             :   //
     326             :   // Placed first to avoid offset computation. The stored data is equivalent to
     327             :   // an Object. It is stored as a plain Address for convenience (smallest number
     328             :   // of casts), and because it is a private implementation detail: the public
     329             :   // interface provides type safety.
     330             :   Address object_;
     331             : 
     332             :   // Class id set by the embedder.
     333             :   uint16_t class_id_;
     334             : 
     335             :   // Index in the containing handle block.
     336             :   uint8_t index_;
     337             : 
     338             :   uint8_t flags_;
     339             : 
     340             :   // The meaning of this field depends on node state:
     341             :   // - Node in free list: Stores next free node pointer.
     342             :   // - Otherwise, specific to the node implementation.
     343             :   union {
     344             :     Child* next_free;
     345             :     void* parameter;
     346             :   } data_;
     347             : };
     348             : 
     349             : namespace {
     350             : 
     351          27 : void ExtractInternalFields(JSObject jsobject, void** embedder_fields, int len) {
     352          27 :   int field_count = jsobject->GetEmbedderFieldCount();
     353         125 :   for (int i = 0; i < len; ++i) {
     354          54 :     if (field_count == i) break;
     355             :     void* pointer;
     356          49 :     if (EmbedderDataSlot(jsobject, i).ToAlignedPointer(&pointer)) {
     357          49 :       embedder_fields[i] = pointer;
     358             :     }
     359             :   }
     360          27 : }
     361             : 
     362             : }  // namespace
     363             : 
     364    14250496 : class GlobalHandles::Node final : public NodeBase<GlobalHandles::Node> {
     365             :  public:
     366             :   // State transition diagram:
     367             :   // FREE -> NORMAL <-> WEAK -> PENDING -> NEAR_DEATH -> { NORMAL, WEAK, FREE }
     368             :   enum State {
     369             :     FREE = 0,
     370             :     NORMAL,      // Normal global handle.
     371             :     WEAK,        // Flagged as weak but not yet finalized.
     372             :     PENDING,     // Has been recognized as only reachable by weak handles.
     373             :     NEAR_DEATH,  // Callback has informed the handle is near death.
     374             :     NUMBER_OF_NODE_STATES
     375             :   };
     376             : 
     377             :   Node() {
     378             :     STATIC_ASSERT(static_cast<int>(NodeState::kMask) ==
     379             :                   Internals::kNodeStateMask);
     380             :     STATIC_ASSERT(WEAK == Internals::kNodeStateIsWeakValue);
     381             :     STATIC_ASSERT(PENDING == Internals::kNodeStateIsPendingValue);
     382             :     STATIC_ASSERT(static_cast<int>(IsIndependent::kShift) ==
     383             :                   Internals::kNodeIsIndependentShift);
     384             :     STATIC_ASSERT(static_cast<int>(IsActive::kShift) ==
     385             :                   Internals::kNodeIsActiveShift);
     386             :     set_in_young_list(false);
     387             :   }
     388             : 
     389             :   void Zap() {
     390             :     DCHECK(IsInUse());
     391             :     // Zap the values for eager trapping.
     392             :     object_ = kGlobalHandleZapValue;
     393             :   }
     394             : 
     395             :   const char* label() const {
     396             :     return state() == NORMAL ? reinterpret_cast<char*>(data_.parameter)
     397     9976330 :                              : nullptr;
     398             :   }
     399             : 
     400             :   // State and flag accessors.
     401             : 
     402             :   State state() const {
     403             :     return NodeState::decode(flags_);
     404             :   }
     405             :   void set_state(State state) {
     406    51452129 :     flags_ = NodeState::update(flags_, state);
     407             :   }
     408             : 
     409             :   bool is_independent() { return IsIndependent::decode(flags_); }
     410    70134412 :   void set_independent(bool v) { flags_ = IsIndependent::update(flags_, v); }
     411             : 
     412             :   bool is_active() {
     413             :     return IsActive::decode(flags_);
     414             :   }
     415             :   void set_active(bool v) {
     416    45059902 :     flags_ = IsActive::update(flags_, v);
     417             :   }
     418             : 
     419             :   bool is_in_young_list() const { return IsInYoungList::decode(flags_); }
     420    38366775 :   void set_in_young_list(bool v) { flags_ = IsInYoungList::update(flags_, v); }
     421             : 
     422             :   WeaknessType weakness_type() const {
     423             :     return NodeWeaknessType::decode(flags_);
     424             :   }
     425             :   void set_weakness_type(WeaknessType weakness_type) {
     426     3654438 :     flags_ = NodeWeaknessType::update(flags_, weakness_type);
     427             :   }
     428             : 
     429          20 :   bool IsWeak() const { return state() == WEAK; }
     430             : 
     431             :   bool IsInUse() const { return state() != FREE; }
     432             : 
     433             :   bool IsPhantomCallback() const {
     434     3101187 :     return weakness_type() == PHANTOM_WEAK ||
     435             :            weakness_type() == PHANTOM_WEAK_2_EMBEDDER_FIELDS;
     436             :   }
     437             : 
     438             :   bool IsPhantomResetHandle() const {
     439             :     return weakness_type() == PHANTOM_WEAK_RESET_HANDLE;
     440             :   }
     441             : 
     442             :   bool IsFinalizerHandle() const { return weakness_type() == FINALIZER_WEAK; }
     443             : 
     444             :   bool IsPendingPhantomCallback() const {
     445             :     return state() == PENDING && IsPhantomCallback();
     446             :   }
     447             : 
     448             :   bool IsPendingPhantomResetHandle() const {
     449             :     return state() == PENDING && IsPhantomResetHandle();
     450             :   }
     451             : 
     452             :   bool IsPendingFinalizer() const {
     453       42228 :     return state() == PENDING && weakness_type() == FINALIZER_WEAK;
     454             :   }
     455             : 
     456             :   bool IsPending() const { return state() == PENDING; }
     457             : 
     458             :   bool IsRetainer() const {
     459    54429051 :     return state() != FREE &&
     460     3085757 :            !(state() == NEAR_DEATH && weakness_type() != FINALIZER_WEAK);
     461             :   }
     462             : 
     463             :   bool IsStrongRetainer() const { return state() == NORMAL; }
     464             : 
     465             :   bool IsWeakRetainer() const {
     466    51658038 :     return state() == WEAK || state() == PENDING ||
     467           0 :            (state() == NEAR_DEATH && weakness_type() == FINALIZER_WEAK);
     468             :   }
     469             : 
     470             :   void MarkPending() {
     471             :     DCHECK(state() == WEAK);
     472             :     set_state(PENDING);
     473             :   }
     474             : 
     475             :   bool has_callback() const { return weak_callback_ != nullptr; }
     476             : 
     477             :   // Accessors for next free node in the free list.
     478             :   Node* next_free() {
     479             :     DCHECK_EQ(FREE, state());
     480             :     return data_.next_free;
     481             :   }
     482             : 
     483     3654402 :   void MakeWeak(void* parameter,
     484             :                 WeakCallbackInfo<void>::Callback phantom_callback,
     485             :                 v8::WeakCallbackType type) {
     486             :     DCHECK_NOT_NULL(phantom_callback);
     487             :     DCHECK(IsInUse());
     488     3654402 :     CHECK_NE(object_, kGlobalHandleZapValue);
     489             :     set_state(WEAK);
     490     3654402 :     switch (type) {
     491             :       case v8::WeakCallbackType::kParameter:
     492             :         set_weakness_type(PHANTOM_WEAK);
     493             :         break;
     494             :       case v8::WeakCallbackType::kInternalFields:
     495             :         set_weakness_type(PHANTOM_WEAK_2_EMBEDDER_FIELDS);
     496             :         break;
     497             :       case v8::WeakCallbackType::kFinalizer:
     498             :         set_weakness_type(FINALIZER_WEAK);
     499             :         break;
     500             :     }
     501             :     set_parameter(parameter);
     502     3654402 :     weak_callback_ = phantom_callback;
     503     3654402 :   }
     504             : 
     505          36 :   void MakeWeak(Address** location_addr) {
     506             :     DCHECK(IsInUse());
     507          36 :     CHECK_NE(object_, kGlobalHandleZapValue);
     508             :     set_state(WEAK);
     509             :     set_weakness_type(PHANTOM_WEAK_RESET_HANDLE);
     510             :     set_parameter(location_addr);
     511          36 :     weak_callback_ = nullptr;
     512          36 :   }
     513             : 
     514             :   void* ClearWeakness() {
     515             :     DCHECK(IsInUse());
     516             :     void* p = parameter();
     517             :     set_state(NORMAL);
     518             :     set_parameter(nullptr);
     519             :     return p;
     520             :   }
     521             : 
     522             :   void AnnotateStrongRetainer(const char* label) {
     523             :     DCHECK_EQ(state(), NORMAL);
     524     2827991 :     data_.parameter = const_cast<char*>(label);
     525             :   }
     526             : 
     527     3093472 :   void CollectPhantomCallbackData(
     528             :       std::vector<std::pair<Node*, PendingPhantomCallback>>*
     529             :           pending_phantom_callbacks) {
     530             :     DCHECK(weakness_type() == PHANTOM_WEAK ||
     531             :            weakness_type() == PHANTOM_WEAK_2_EMBEDDER_FIELDS);
     532             :     DCHECK(state() == PENDING);
     533             :     DCHECK_NOT_NULL(weak_callback_);
     534             : 
     535             :     void* embedder_fields[v8::kEmbedderFieldsInWeakCallback] = {nullptr,
     536     3093472 :                                                                 nullptr};
     537     3093489 :     if (weakness_type() != PHANTOM_WEAK && object()->IsJSObject()) {
     538             :       ExtractInternalFields(JSObject::cast(object()), embedder_fields,
     539          17 :                             v8::kEmbedderFieldsInWeakCallback);
     540             :     }
     541             : 
     542             :     // Zap with something dangerous.
     543             :     location().store(Object(0xCA11));
     544             : 
     545     3093472 :     pending_phantom_callbacks->push_back(std::make_pair(
     546             :         this,
     547     6186944 :         PendingPhantomCallback(weak_callback_, parameter(), embedder_fields)));
     548             :     DCHECK(IsInUse());
     549             :     set_state(NEAR_DEATH);
     550     3093472 :   }
     551             : 
     552             :   void ResetPhantomHandle() {
     553             :     DCHECK_EQ(PHANTOM_WEAK_RESET_HANDLE, weakness_type());
     554             :     DCHECK_EQ(PENDING, state());
     555             :     DCHECK_NULL(weak_callback_);
     556             :     Address** handle = reinterpret_cast<Address**>(parameter());
     557          31 :     *handle = nullptr;
     558          31 :     NodeSpace<Node>::Release(this);
     559             :   }
     560             : 
     561       21114 :   void PostGarbageCollectionProcessing(Isolate* isolate) {
     562             :     // This method invokes a finalizer. Updating the method name would require
     563             :     // adjusting CFI blacklist as weak_callback_ is invoked on the wrong type.
     564       21114 :     CHECK(IsPendingFinalizer());
     565       21114 :     CHECK(!is_active());
     566             :     set_state(NEAR_DEATH);
     567             :     // Check that we are not passing a finalized external string to
     568             :     // the callback.
     569             :     DCHECK(!object()->IsExternalOneByteString() ||
     570             :            ExternalOneByteString::cast(object())->resource() != nullptr);
     571             :     DCHECK(!object()->IsExternalTwoByteString() ||
     572             :            ExternalTwoByteString::cast(object())->resource() != nullptr);
     573             :     // Leaving V8.
     574       42228 :     VMState<EXTERNAL> vmstate(isolate);
     575             :     HandleScope handle_scope(isolate);
     576             :     void* embedder_fields[v8::kEmbedderFieldsInWeakCallback] = {nullptr,
     577       21114 :                                                                 nullptr};
     578             :     v8::WeakCallbackInfo<void> data(reinterpret_cast<v8::Isolate*>(isolate),
     579             :                                     parameter(), embedder_fields, nullptr);
     580       21114 :     weak_callback_(data);
     581             :     // For finalizers the handle must have either been reset or made strong.
     582             :     // Both cases reset the state.
     583       21114 :     CHECK_NE(NEAR_DEATH, state());
     584       21114 :   }
     585             : 
     586             :   void MarkAsFree() { set_state(FREE); }
     587             :   void MarkAsUsed() { set_state(NORMAL); }
     588             : 
     589             :   GlobalHandles* global_handles() {
     590             :     return NodeBlock<Node>::From(this)->global_handles();
     591             :   }
     592             : 
     593             :  private:
     594             :   // Fields that are not used for managing node memory.
     595             :   void ClearImplFields() {
     596             :     set_independent(false);
     597             :     set_active(false);
     598    35067206 :     weak_callback_ = nullptr;
     599             :   }
     600             : 
     601             :   void CheckImplFieldsAreCleared() {
     602             :     DCHECK(!is_independent());
     603             :     DCHECK(!is_active());
     604             :     DCHECK_EQ(nullptr, weak_callback_);
     605             :   }
     606             : 
     607             :   // This stores three flags (independent, partially_dependent and
     608             :   // in_young_list) and a State.
     609             :   class NodeState : public BitField8<State, 0, 3> {};
     610             :   class IsIndependent : public BitField8<bool, NodeState::kNext, 1> {};
     611             :   // The following two fields are mutually exclusive
     612             :   class IsActive : public BitField8<bool, IsIndependent::kNext, 1> {};
     613             :   class IsInYoungList : public BitField8<bool, IsActive::kNext, 1> {};
     614             :   class NodeWeaknessType
     615             :       : public BitField8<WeaknessType, IsInYoungList::kNext, 2> {};
     616             : 
     617             :   // Handle specific callback - might be a weak reference in disguise.
     618             :   WeakCallbackInfo<void>::Callback weak_callback_;
     619             : 
     620             :   friend class NodeBase<Node>;
     621             : 
     622             :   DISALLOW_COPY_AND_ASSIGN(Node);
     623             : };
     624             : 
     625       17920 : class GlobalHandles::TracedNode final
     626             :     : public NodeBase<GlobalHandles::TracedNode> {
     627             :  public:
     628             :   TracedNode() { set_in_young_list(false); }
     629             : 
     630             :   enum State { FREE = 0, NORMAL, NEAR_DEATH };
     631             : 
     632             :   State state() const { return NodeState::decode(flags_); }
     633       18150 :   void set_state(State state) { flags_ = NodeState::update(flags_, state); }
     634             : 
     635             :   void MarkAsFree() { set_state(FREE); }
     636             :   void MarkAsUsed() { set_state(NORMAL); }
     637             :   bool IsInUse() const { return state() != FREE; }
     638             :   bool IsRetainer() const { return state() == NORMAL; }
     639             :   bool IsPhantomResetHandle() const { return callback_ == nullptr; }
     640             : 
     641             :   bool is_in_young_list() const { return IsInYoungList::decode(flags_); }
     642       36012 :   void set_in_young_list(bool v) { flags_ = IsInYoungList::update(flags_, v); }
     643             : 
     644             :   bool is_root() const { return IsRoot::decode(flags_); }
     645       71850 :   void set_root(bool v) { flags_ = IsRoot::update(flags_, v); }
     646             : 
     647             :   void SetFinalizationCallback(void* parameter,
     648             :                                WeakCallbackInfo<void>::Callback callback) {
     649             :     set_parameter(parameter);
     650          10 :     callback_ = callback;
     651             :   }
     652             :   bool HasFinalizationCallback() const { return callback_ != nullptr; }
     653             : 
     654          10 :   void CollectPhantomCallbackData(
     655             :       std::vector<std::pair<TracedNode*, PendingPhantomCallback>>*
     656             :           pending_phantom_callbacks) {
     657             :     DCHECK(IsInUse());
     658             :     DCHECK_NOT_NULL(callback_);
     659             : 
     660             :     void* embedder_fields[v8::kEmbedderFieldsInWeakCallback] = {nullptr,
     661          10 :                                                                 nullptr};
     662             :     ExtractInternalFields(JSObject::cast(object()), embedder_fields,
     663          10 :                           v8::kEmbedderFieldsInWeakCallback);
     664             : 
     665             :     // Zap with something dangerous.
     666             :     location().store(Object(0xCA11));
     667             : 
     668          10 :     pending_phantom_callbacks->push_back(std::make_pair(
     669          20 :         this, PendingPhantomCallback(callback_, parameter(), embedder_fields)));
     670             :     set_state(NEAR_DEATH);
     671          10 :   }
     672             : 
     673             :   void ResetPhantomHandle() {
     674             :     DCHECK(IsInUse());
     675          20 :     Address** handle = reinterpret_cast<Address**>(data_.parameter);
     676          20 :     *handle = nullptr;
     677          20 :     NodeSpace<TracedNode>::Release(this);
     678             :     DCHECK(!IsInUse());
     679             :   }
     680             : 
     681             :  protected:
     682             :   class NodeState : public BitField8<State, 0, 2> {};
     683             :   class IsInYoungList : public BitField8<bool, NodeState::kNext, 1> {};
     684             :   class IsRoot : public BitField8<bool, IsInYoungList::kNext, 1> {};
     685             : 
     686             :   void ClearImplFields() {
     687             :     set_root(true);
     688       35910 :     callback_ = nullptr;
     689             :   }
     690             : 
     691             :   void CheckImplFieldsAreCleared() const {
     692             :     DCHECK(is_root());
     693             :     DCHECK_NULL(callback_);
     694             :   }
     695             : 
     696             :   WeakCallbackInfo<void>::Callback callback_;
     697             : 
     698             :   friend class NodeBase<GlobalHandles::TracedNode>;
     699             : 
     700             :   DISALLOW_COPY_AND_ASSIGN(TracedNode);
     701             : };
     702             : 
     703       62426 : GlobalHandles::GlobalHandles(Isolate* isolate)
     704             :     : isolate_(isolate),
     705             :       regular_nodes_(new NodeSpace<GlobalHandles::Node>(this)),
     706      249704 :       traced_nodes_(new NodeSpace<GlobalHandles::TracedNode>(this)) {}
     707             : 
     708      187233 : GlobalHandles::~GlobalHandles() { regular_nodes_.reset(nullptr); }
     709             : 
     710     6980805 : Handle<Object> GlobalHandles::Create(Object value) {
     711     6980805 :   GlobalHandles::Node* result = regular_nodes_->Acquire(value);
     712    10553990 :   if (ObjectInYoungGeneration(value) && !result->is_in_young_list()) {
     713     3412735 :     young_nodes_.push_back(result);
     714     3412735 :     result->set_in_young_list(true);
     715             :   }
     716    13961610 :   return result->handle();
     717             : }
     718             : 
     719     3049925 : Handle<Object> GlobalHandles::Create(Address value) {
     720     3049935 :   return Create(Object(value));
     721             : }
     722             : 
     723          70 : Handle<Object> GlobalHandles::CreateTraced(Object value, Address* slot) {
     724          70 :   GlobalHandles::TracedNode* result = traced_nodes_->Acquire(value);
     725         140 :   if (ObjectInYoungGeneration(value) && !result->is_in_young_list()) {
     726          70 :     traced_young_nodes_.push_back(result);
     727          70 :     result->set_in_young_list(true);
     728             :   }
     729          70 :   result->set_parameter(slot);
     730          70 :   return result->handle();
     731             : }
     732             : 
     733          70 : Handle<Object> GlobalHandles::CreateTraced(Address value, Address* slot) {
     734          70 :   return CreateTraced(Object(value), slot);
     735             : }
     736             : 
     737          10 : Handle<Object> GlobalHandles::CopyGlobal(Address* location) {
     738             :   DCHECK_NOT_NULL(location);
     739             :   GlobalHandles* global_handles =
     740             :       Node::FromLocation(location)->global_handles();
     741             : #ifdef VERIFY_HEAP
     742             :   if (i::FLAG_verify_heap) {
     743             :     Object(*location)->ObjectVerify(global_handles->isolate());
     744             :   }
     745             : #endif  // VERIFY_HEAP
     746          20 :   return global_handles->Create(*location);
     747             : }
     748             : 
     749        5836 : void GlobalHandles::MoveGlobal(Address** from, Address** to) {
     750             :   DCHECK_NOT_NULL(*from);
     751             :   DCHECK_NOT_NULL(*to);
     752             :   DCHECK_EQ(*from, *to);
     753        5836 :   Node* node = Node::FromLocation(*from);
     754        5841 :   if (node->IsWeak() && node->IsPhantomResetHandle()) {
     755             :     node->set_parameter(to);
     756             :   }
     757             : 
     758             :   // - Strong handles do not require fixups.
     759             :   // - Weak handles with finalizers and callbacks are too general to fix up. For
     760             :   //   those the callers need to ensure consistency.
     761        5836 : }
     762             : 
     763          55 : void GlobalHandles::MoveTracedGlobal(Address** from, Address** to) {
     764             :   DCHECK_NOT_NULL(*from);
     765             :   DCHECK_NOT_NULL(*to);
     766             :   DCHECK_EQ(*from, *to);
     767          55 :   TracedNode* node = TracedNode::FromLocation(*from);
     768             :   // Only set the backpointer for clearing a phantom handle when there is no
     769             :   // finalization callback attached. As soon as a callback is attached to a node
     770             :   // the embedder is on its own when resetting a handle.
     771          55 :   if (!node->HasFinalizationCallback()) {
     772             :     node->set_parameter(to);
     773             :   }
     774          55 : }
     775             : 
     776     6566183 : void GlobalHandles::Destroy(Address* location) {
     777     6566183 :   if (location != nullptr) {
     778     6566183 :     NodeSpace<Node>::Release(Node::FromLocation(location));
     779             :   }
     780     6566182 : }
     781             : 
     782          50 : void GlobalHandles::DestroyTraced(Address* location) {
     783          50 :   if (location != nullptr) {
     784          50 :     NodeSpace<TracedNode>::Release(TracedNode::FromLocation(location));
     785             :   }
     786          50 : }
     787             : 
     788          10 : void GlobalHandles::SetFinalizationCallbackForTraced(
     789             :     Address* location, void* parameter,
     790             :     WeakCallbackInfo<void>::Callback callback) {
     791             :   TracedNode::FromLocation(location)->SetFinalizationCallback(parameter,
     792             :                                                               callback);
     793          10 : }
     794             : 
     795             : typedef v8::WeakCallbackInfo<void>::Callback GenericCallback;
     796             : 
     797     3654402 : void GlobalHandles::MakeWeak(Address* location, void* parameter,
     798             :                              GenericCallback phantom_callback,
     799             :                              v8::WeakCallbackType type) {
     800     3654402 :   Node::FromLocation(location)->MakeWeak(parameter, phantom_callback, type);
     801     3654402 : }
     802             : 
     803          36 : void GlobalHandles::MakeWeak(Address** location_addr) {
     804          36 :   Node::FromLocation(*location_addr)->MakeWeak(location_addr);
     805          36 : }
     806             : 
     807       21129 : void* GlobalHandles::ClearWeakness(Address* location) {
     808       21129 :   return Node::FromLocation(location)->ClearWeakness();
     809             : }
     810             : 
     811     2827991 : void GlobalHandles::AnnotateStrongRetainer(Address* location,
     812             :                                            const char* label) {
     813             :   Node::FromLocation(location)->AnnotateStrongRetainer(label);
     814     2827991 : }
     815             : 
     816          20 : bool GlobalHandles::IsWeak(Address* location) {
     817          20 :   return Node::FromLocation(location)->IsWeak();
     818             : }
     819             : 
     820             : DISABLE_CFI_PERF
     821       75337 : void GlobalHandles::IterateWeakRootsForFinalizers(RootVisitor* v) {
     822    25502025 :   for (Node* node : *regular_nodes_) {
     823    25426688 :     if (node->IsWeakRetainer() && node->state() == Node::PENDING) {
     824             :       DCHECK(!node->IsPhantomCallback());
     825             :       DCHECK(!node->IsPhantomResetHandle());
     826             :       // Finalizers need to survive.
     827             :       v->VisitRootPointer(Root::kGlobalHandles, node->label(),
     828       42228 :                           node->location());
     829             :     }
     830             :   }
     831       75337 : }
     832             : 
     833             : DISABLE_CFI_PERF
     834       75337 : void GlobalHandles::IterateWeakRootsForPhantomHandles(
     835             :     WeakSlotCallbackWithHeap should_reset_handle) {
     836    25502025 :   for (Node* node : *regular_nodes_) {
     837    30827926 :     if (node->IsWeakRetainer() &&
     838     5401238 :         should_reset_handle(isolate()->heap(), node->location())) {
     839     3085788 :       if (node->IsPhantomResetHandle()) {
     840             :         node->MarkPending();
     841             :         node->ResetPhantomHandle();
     842          31 :         ++number_of_phantom_handle_resets_;
     843     3085757 :       } else if (node->IsPhantomCallback()) {
     844             :         node->MarkPending();
     845     3085757 :         node->CollectPhantomCallbackData(&regular_pending_phantom_callbacks_);
     846             :       }
     847             :     }
     848             :   }
     849       83017 :   for (TracedNode* node : *traced_nodes_) {
     850        7710 :     if (node->IsInUse() &&
     851          30 :         should_reset_handle(isolate()->heap(), node->location())) {
     852          20 :       if (node->IsPhantomResetHandle()) {
     853             :         node->ResetPhantomHandle();
     854          15 :         ++number_of_phantom_handle_resets_;
     855             :       } else {
     856           5 :         node->CollectPhantomCallbackData(&traced_pending_phantom_callbacks_);
     857             :       }
     858             :     }
     859             :   }
     860       75337 : }
     861             : 
     862       75337 : void GlobalHandles::IterateWeakRootsIdentifyFinalizers(
     863             :     WeakSlotCallbackWithHeap should_reset_handle) {
     864    25502025 :   for (Node* node : *regular_nodes_) {
     865    30827926 :     if (node->IsWeak() &&
     866     5401238 :         should_reset_handle(isolate()->heap(), node->location())) {
     867     3106910 :       if (node->IsFinalizerHandle()) {
     868             :         node->MarkPending();
     869             :       }
     870             :     }
     871             :   }
     872       75337 : }
     873             : 
     874       28965 : void GlobalHandles::IdentifyWeakUnmodifiedObjects(
     875             :     WeakSlotCallback is_unmodified) {
     876      561656 :   for (Node* node : young_nodes_) {
     877      874387 :     if (node->IsWeak() && !is_unmodified(node->location())) {
     878             :       node->set_active(true);
     879             :     }
     880             :   }
     881             : 
     882             :   LocalEmbedderHeapTracer* const tracer =
     883             :       isolate()->heap()->local_embedder_heap_tracer();
     884       28990 :   for (TracedNode* node : traced_young_nodes_) {
     885          25 :     if (node->IsInUse()) {
     886             :       DCHECK(node->is_root());
     887          25 :       if (is_unmodified(node->location())) {
     888          15 :         v8::Value* value = ToApi<v8::Value>(node->handle());
     889             :         node->set_root(tracer->IsRootForNonTracingGC(
     890             :             *reinterpret_cast<v8::TracedGlobal<v8::Value>*>(&value)));
     891             :       }
     892             :     }
     893             :   }
     894       28965 : }
     895             : 
     896       28965 : void GlobalHandles::IterateYoungStrongAndDependentRoots(RootVisitor* v) {
     897      561656 :   for (Node* node : young_nodes_) {
     898     1419920 :     if (node->IsStrongRetainer() ||
     899      649361 :         (node->IsWeakRetainer() && !node->is_independent() &&
     900             :          node->is_active())) {
     901             :       v->VisitRootPointer(Root::kGlobalHandles, node->label(),
     902      971564 :                           node->location());
     903             :     }
     904             :   }
     905       28990 :   for (TracedNode* node : traced_young_nodes_) {
     906          50 :     if (node->IsInUse() && node->is_root()) {
     907          30 :       v->VisitRootPointer(Root::kGlobalHandles, nullptr, node->location());
     908             :     }
     909             :   }
     910       28965 : }
     911             : 
     912       28965 : void GlobalHandles::MarkYoungWeakUnmodifiedObjectsPending(
     913             :     WeakSlotCallbackWithHeap is_dead) {
     914      561656 :   for (Node* node : young_nodes_) {
     915             :     DCHECK(node->is_in_young_list());
     916     1290480 :     if ((node->is_independent() || !node->is_active()) && node->IsWeak() &&
     917       68134 :         is_dead(isolate_->heap(), node->location())) {
     918        7715 :       if (!node->IsPhantomCallback() && !node->IsPhantomResetHandle()) {
     919             :         node->MarkPending();
     920             :       }
     921             :     }
     922             :   }
     923       28965 : }
     924             : 
     925       28965 : void GlobalHandles::IterateYoungWeakUnmodifiedRootsForFinalizers(
     926             :     RootVisitor* v) {
     927      561656 :   for (Node* node : young_nodes_) {
     928             :     DCHECK(node->is_in_young_list());
     929     1256413 :     if ((node->is_independent() || !node->is_active()) &&
     930      566758 :         node->IsWeakRetainer() && (node->state() == Node::PENDING)) {
     931             :       DCHECK(!node->IsPhantomCallback());
     932             :       DCHECK(!node->IsPhantomResetHandle());
     933             :       // Finalizers need to survive.
     934             :       v->VisitRootPointer(Root::kGlobalHandles, node->label(),
     935           0 :                           node->location());
     936             :     }
     937             :   }
     938       28965 : }
     939             : 
     940       28965 : void GlobalHandles::IterateYoungWeakUnmodifiedRootsForPhantomHandles(
     941             :     RootVisitor* v, WeakSlotCallbackWithHeap should_reset_handle) {
     942      561656 :   for (Node* node : young_nodes_) {
     943             :     DCHECK(node->is_in_young_list());
     944     1256413 :     if ((node->is_independent() || !node->is_active()) &&
     945      566758 :         node->IsWeakRetainer() && (node->state() != Node::PENDING)) {
     946       68134 :       if (should_reset_handle(isolate_->heap(), node->location())) {
     947             :         DCHECK(node->IsPhantomResetHandle() || node->IsPhantomCallback());
     948        7715 :         if (node->IsPhantomResetHandle()) {
     949             :           node->MarkPending();
     950             :           node->ResetPhantomHandle();
     951           0 :           ++number_of_phantom_handle_resets_;
     952        7715 :         } else if (node->IsPhantomCallback()) {
     953             :           node->MarkPending();
     954        7715 :           node->CollectPhantomCallbackData(&regular_pending_phantom_callbacks_);
     955             :         } else {
     956           0 :           UNREACHABLE();
     957             :         }
     958             :       } else {
     959             :         // Node survived and needs to be visited.
     960             :         v->VisitRootPointer(Root::kGlobalHandles, node->label(),
     961       52704 :                             node->location());
     962             :       }
     963             :     }
     964             :   }
     965       28990 :   for (TracedNode* node : traced_young_nodes_) {
     966          25 :     if (!node->IsInUse()) continue;
     967             : 
     968             :     DCHECK_IMPLIES(node->is_root(),
     969             :                    !should_reset_handle(isolate_->heap(), node->location()));
     970          50 :     if (should_reset_handle(isolate_->heap(), node->location())) {
     971          10 :       if (node->IsPhantomResetHandle()) {
     972             :         node->ResetPhantomHandle();
     973           5 :         ++number_of_phantom_handle_resets_;
     974             :       } else {
     975           5 :         node->CollectPhantomCallbackData(&traced_pending_phantom_callbacks_);
     976             :       }
     977             :     } else {
     978          15 :       if (!node->is_root()) {
     979             :         node->set_root(true);
     980           0 :         v->VisitRootPointer(Root::kGlobalHandles, nullptr, node->location());
     981             :       }
     982             :     }
     983             :   }
     984       28965 : }
     985             : 
     986         666 : void GlobalHandles::InvokeSecondPassPhantomCallbacksFromTask() {
     987             :   DCHECK(second_pass_callbacks_task_posted_);
     988         666 :   second_pass_callbacks_task_posted_ = false;
     989        1998 :   TRACE_EVENT0("v8", "V8.GCPhantomHandleProcessingCallback");
     990             :   isolate()->heap()->CallGCPrologueCallbacks(
     991         666 :       GCType::kGCTypeProcessWeakCallbacks, kNoGCCallbackFlags);
     992         666 :   InvokeSecondPassPhantomCallbacks();
     993             :   isolate()->heap()->CallGCEpilogueCallbacks(
     994         666 :       GCType::kGCTypeProcessWeakCallbacks, kNoGCCallbackFlags);
     995         666 : }
     996             : 
     997      113175 : void GlobalHandles::InvokeSecondPassPhantomCallbacks() {
     998     5579833 :   while (!second_pass_callbacks_.empty()) {
     999     2733329 :     auto callback = second_pass_callbacks_.back();
    1000             :     second_pass_callbacks_.pop_back();
    1001             :     callback.Invoke(isolate(), PendingPhantomCallback::kSecondPass);
    1002             :   }
    1003      113175 : }
    1004             : 
    1005       28965 : size_t GlobalHandles::PostScavengeProcessing(unsigned post_processing_count) {
    1006             :   size_t freed_nodes = 0;
    1007      561656 :   for (Node* node : young_nodes_) {
    1008             :     // Filter free nodes.
    1009      532691 :     if (!node->IsRetainer()) continue;
    1010             : 
    1011             :     // Reset active state for all affected nodes.
    1012             :     node->set_active(false);
    1013             : 
    1014      512134 :     if (node->IsPending()) {
    1015             :       DCHECK(node->has_callback());
    1016             :       DCHECK(node->IsPendingFinalizer());
    1017           0 :       node->PostGarbageCollectionProcessing(isolate_);
    1018             :     }
    1019      512134 :     if (InRecursiveGC(post_processing_count)) return freed_nodes;
    1020             : 
    1021      512134 :     if (!node->IsRetainer()) freed_nodes++;
    1022             :   }
    1023             :   return freed_nodes;
    1024             : }
    1025             : 
    1026       75337 : size_t GlobalHandles::PostMarkSweepProcessing(unsigned post_processing_count) {
    1027             :   size_t freed_nodes = 0;
    1028    23194697 :   for (Node* node : *regular_nodes_) {
    1029             :     // Filter free nodes.
    1030    23119360 :     if (!node->IsRetainer()) continue;
    1031             : 
    1032             :     // Reset active state for all affected nodes.
    1033             :     node->set_active(false);
    1034             : 
    1035     4398626 :     if (node->IsPending()) {
    1036             :       DCHECK(node->has_callback());
    1037             :       DCHECK(node->IsPendingFinalizer());
    1038       21114 :       node->PostGarbageCollectionProcessing(isolate_);
    1039             :     }
    1040     4398626 :     if (InRecursiveGC(post_processing_count)) return freed_nodes;
    1041             : 
    1042     4398626 :     if (!node->IsRetainer()) freed_nodes++;
    1043             :   }
    1044       75337 :   return freed_nodes;
    1045             : }
    1046             : 
    1047             : template <typename T>
    1048      208604 : void GlobalHandles::UpdateAndCompactListOfYoungNode(
    1049             :     std::vector<T*>* node_list) {
    1050             :   size_t last = 0;
    1051     4917777 :   for (T* node : *node_list) {
    1052             :     DCHECK(node->is_in_young_list());
    1053     4709173 :     if (node->IsInUse()) {
    1054     2065548 :       if (ObjectInYoungGeneration(node->object())) {
    1055     3337656 :         (*node_list)[last++] = node;
    1056     1668828 :         isolate_->heap()->IncrementNodesCopiedInNewSpace();
    1057             :       } else {
    1058             :         node->set_in_young_list(false);
    1059      396720 :         isolate_->heap()->IncrementNodesPromoted();
    1060             :       }
    1061             :     } else {
    1062             :       node->set_in_young_list(false);
    1063     2643625 :       isolate_->heap()->IncrementNodesDiedInNewSpace();
    1064             :     }
    1065             :   }
    1066             :   DCHECK_LE(last, node_list->size());
    1067      208604 :   node_list->resize(last);
    1068             :   node_list->shrink_to_fit();
    1069      208604 : }
    1070             : 
    1071           0 : void GlobalHandles::UpdateListOfYoungNodes() {
    1072      104302 :   UpdateAndCompactListOfYoungNode(&young_nodes_);
    1073      104302 :   UpdateAndCompactListOfYoungNode(&traced_young_nodes_);
    1074           0 : }
    1075             : 
    1076             : template <typename T>
    1077      208604 : size_t GlobalHandles::InvokeFirstPassWeakCallbacks(
    1078             :     std::vector<std::pair<T*, PendingPhantomCallback>>* pending) {
    1079             :   size_t freed_nodes = 0;
    1080             :   std::vector<std::pair<T*, PendingPhantomCallback>> pending_phantom_callbacks;
    1081             :   pending_phantom_callbacks.swap(*pending);
    1082             :   {
    1083             :     // The initial pass callbacks must simply clear the nodes.
    1084     3302086 :     for (auto& pair : pending_phantom_callbacks) {
    1085     3093482 :       T* node = pair.first;
    1086             :       DCHECK_EQ(T::NEAR_DEATH, node->state());
    1087             :       pair.second.Invoke(isolate(), PendingPhantomCallback::kFirstPass);
    1088             : 
    1089             :       // Transition to second pass. It is required that the first pass callback
    1090             :       // resets the handle using |v8::PersistentBase::Reset|. Also see comments
    1091             :       // on |v8::WeakCallbackInfo|.
    1092     3093482 :       CHECK_WITH_MSG(T::FREE == node->state(),
    1093             :                      "Handle not reset in first callback. See comments on "
    1094             :                      "|v8::WeakCallbackInfo|.");
    1095             : 
    1096     3093482 :       if (pair.second.callback()) second_pass_callbacks_.push_back(pair.second);
    1097     3093482 :       freed_nodes++;
    1098             :     }
    1099             :   }
    1100      208604 :   return freed_nodes;
    1101             : }
    1102             : 
    1103      104302 : size_t GlobalHandles::InvokeFirstPassWeakCallbacks() {
    1104      104302 :   return InvokeFirstPassWeakCallbacks(&regular_pending_phantom_callbacks_) +
    1105      104302 :          InvokeFirstPassWeakCallbacks(&traced_pending_phantom_callbacks_);
    1106             : }
    1107             : 
    1108      104302 : void GlobalHandles::InvokeOrScheduleSecondPassPhantomCallbacks(
    1109             :     bool synchronous_second_pass) {
    1110      104302 :   if (!second_pass_callbacks_.empty()) {
    1111        9453 :     if (FLAG_optimize_for_size || FLAG_predictable || synchronous_second_pass) {
    1112             :       isolate()->heap()->CallGCPrologueCallbacks(
    1113        8207 :           GCType::kGCTypeProcessWeakCallbacks, kNoGCCallbackFlags);
    1114        8207 :       InvokeSecondPassPhantomCallbacks();
    1115             :       isolate()->heap()->CallGCEpilogueCallbacks(
    1116        8207 :           GCType::kGCTypeProcessWeakCallbacks, kNoGCCallbackFlags);
    1117        1246 :     } else if (!second_pass_callbacks_task_posted_) {
    1118         666 :       second_pass_callbacks_task_posted_ = true;
    1119         666 :       auto taskrunner = V8::GetCurrentPlatform()->GetForegroundTaskRunner(
    1120         666 :           reinterpret_cast<v8::Isolate*>(isolate()));
    1121        2664 :       taskrunner->PostTask(MakeCancelableTask(
    1122        1998 :           isolate(), [this] { InvokeSecondPassPhantomCallbacksFromTask(); }));
    1123             :     }
    1124             :   }
    1125      104302 : }
    1126             : 
    1127           0 : void GlobalHandles::PendingPhantomCallback::Invoke(Isolate* isolate,
    1128             :                                                    InvocationType type) {
    1129             :   Data::Callback* callback_addr = nullptr;
    1130           0 :   if (type == kFirstPass) {
    1131     3093482 :     callback_addr = &callback_;
    1132             :   }
    1133             :   Data data(reinterpret_cast<v8::Isolate*>(isolate), parameter_,
    1134     5826811 :             embedder_fields_, callback_addr);
    1135     5826811 :   Data::Callback callback = callback_;
    1136     5826811 :   callback_ = nullptr;
    1137     5826811 :   callback(data);
    1138           0 : }
    1139             : 
    1140           0 : bool GlobalHandles::InRecursiveGC(unsigned gc_processing_counter) {
    1141     5119364 :   return gc_processing_counter != post_gc_processing_count_;
    1142             : }
    1143             : 
    1144      104302 : size_t GlobalHandles::PostGarbageCollectionProcessing(
    1145             :     GarbageCollector collector, const v8::GCCallbackFlags gc_callback_flags) {
    1146             :   // Process weak global handle callbacks. This must be done after the
    1147             :   // GC is completely done, because the callbacks may invoke arbitrary
    1148             :   // API functions.
    1149             :   DCHECK_EQ(Heap::NOT_IN_GC, isolate_->heap()->gc_state());
    1150      104302 :   const unsigned post_processing_count = ++post_gc_processing_count_;
    1151             :   size_t freed_nodes = 0;
    1152             :   bool synchronous_second_pass =
    1153      208604 :       isolate_->heap()->IsTearingDown() ||
    1154      104302 :       (gc_callback_flags &
    1155             :        (kGCCallbackFlagForced | kGCCallbackFlagCollectAllAvailableGarbage |
    1156             :         kGCCallbackFlagSynchronousPhantomCallbackProcessing)) != 0;
    1157      104302 :   InvokeOrScheduleSecondPassPhantomCallbacks(synchronous_second_pass);
    1158      104302 :   if (InRecursiveGC(post_processing_count)) return freed_nodes;
    1159             : 
    1160             :   freed_nodes += Heap::IsYoungGenerationCollector(collector)
    1161             :                      ? PostScavengeProcessing(post_processing_count)
    1162      104302 :                      : PostMarkSweepProcessing(post_processing_count);
    1163      104302 :   if (InRecursiveGC(post_processing_count)) return freed_nodes;
    1164             : 
    1165             :   UpdateListOfYoungNodes();
    1166      104302 :   return freed_nodes;
    1167             : }
    1168             : 
    1169      123038 : void GlobalHandles::IterateStrongRoots(RootVisitor* v) {
    1170    39473310 :   for (Node* node : *regular_nodes_) {
    1171    39350272 :     if (node->IsStrongRetainer()) {
    1172             :       v->VisitRootPointer(Root::kGlobalHandles, node->label(),
    1173     9465738 :                           node->location());
    1174             :     }
    1175             :   }
    1176      123038 : }
    1177             : 
    1178         398 : void GlobalHandles::IterateWeakRoots(RootVisitor* v) {
    1179      102286 :   for (Node* node : *regular_nodes_) {
    1180      101888 :     if (node->IsWeak()) {
    1181             :       v->VisitRootPointer(Root::kGlobalHandles, node->label(),
    1182         110 :                           node->location());
    1183             :     }
    1184             :   }
    1185         398 :   for (TracedNode* node : *traced_nodes_) {
    1186           0 :     if (node->IsInUse()) {
    1187           0 :       v->VisitRootPointer(Root::kGlobalHandles, nullptr, node->location());
    1188             :     }
    1189             :   }
    1190         398 : }
    1191             : 
    1192             : DISABLE_CFI_PERF
    1193       77221 : void GlobalHandles::IterateAllRoots(RootVisitor* v) {
    1194    25940901 :   for (Node* node : *regular_nodes_) {
    1195    25863680 :     if (node->IsRetainer()) {
    1196             :       v->VisitRootPointer(Root::kGlobalHandles, node->label(),
    1197     9420316 :                           node->location());
    1198             :     }
    1199             :   }
    1200       81061 :   for (TracedNode* node : *traced_nodes_) {
    1201        3840 :     if (node->IsRetainer()) {
    1202          20 :       v->VisitRootPointer(Root::kGlobalHandles, nullptr, node->location());
    1203             :     }
    1204             :   }
    1205       77221 : }
    1206             : 
    1207             : DISABLE_CFI_PERF
    1208           0 : void GlobalHandles::IterateAllYoungRoots(RootVisitor* v) {
    1209           0 :   for (Node* node : young_nodes_) {
    1210           0 :     if (node->IsRetainer()) {
    1211             :       v->VisitRootPointer(Root::kGlobalHandles, node->label(),
    1212           0 :                           node->location());
    1213             :     }
    1214             :   }
    1215           0 :   for (TracedNode* node : traced_young_nodes_) {
    1216           0 :     if (node->IsRetainer()) {
    1217           0 :       v->VisitRootPointer(Root::kGlobalHandles, nullptr, node->location());
    1218             :     }
    1219             :   }
    1220           0 : }
    1221             : 
    1222             : DISABLE_CFI_PERF
    1223           0 : void GlobalHandles::ApplyPersistentHandleVisitor(
    1224             :     v8::PersistentHandleVisitor* visitor, GlobalHandles::Node* node) {
    1225          20 :   v8::Value* value = ToApi<v8::Value>(node->handle());
    1226          20 :   visitor->VisitPersistentHandle(
    1227             :       reinterpret_cast<v8::Persistent<v8::Value>*>(&value),
    1228          40 :       node->wrapper_class_id());
    1229           0 : }
    1230             : 
    1231             : DISABLE_CFI_PERF
    1232          10 : void GlobalHandles::IterateAllRootsWithClassIds(
    1233             :     v8::PersistentHandleVisitor* visitor) {
    1234        2570 :   for (Node* node : *regular_nodes_) {
    1235        2560 :     if (node->IsRetainer() && node->has_wrapper_class_id()) {
    1236             :       ApplyPersistentHandleVisitor(visitor, node);
    1237             :     }
    1238             :   }
    1239          10 : }
    1240             : 
    1241             : DISABLE_CFI_PERF
    1242           5 : void GlobalHandles::IterateTracedNodes(
    1243             :     v8::EmbedderHeapTracer::TracedGlobalHandleVisitor* visitor) {
    1244        1285 :   for (TracedNode* node : *traced_nodes_) {
    1245        1280 :     if (node->IsInUse()) {
    1246           5 :       v8::Value* value = ToApi<v8::Value>(node->handle());
    1247             :       visitor->VisitTracedGlobalHandle(
    1248           5 :           *reinterpret_cast<v8::TracedGlobal<v8::Value>*>(&value));
    1249             :     }
    1250             :   }
    1251           5 : }
    1252             : 
    1253             : DISABLE_CFI_PERF
    1254           0 : void GlobalHandles::IterateAllYoungRootsWithClassIds(
    1255             :     v8::PersistentHandleVisitor* visitor) {
    1256           0 :   for (Node* node : young_nodes_) {
    1257           0 :     if (node->IsRetainer() && node->has_wrapper_class_id()) {
    1258             :       ApplyPersistentHandleVisitor(visitor, node);
    1259             :     }
    1260             :   }
    1261           0 : }
    1262             : 
    1263             : DISABLE_CFI_PERF
    1264           0 : void GlobalHandles::IterateYoungWeakRootsWithClassIds(
    1265             :     v8::PersistentHandleVisitor* visitor) {
    1266           0 :   for (Node* node : young_nodes_) {
    1267           0 :     if (node->has_wrapper_class_id() && node->IsWeak()) {
    1268             :       ApplyPersistentHandleVisitor(visitor, node);
    1269             :     }
    1270             :   }
    1271           0 : }
    1272             : 
    1273          15 : void GlobalHandles::RecordStats(HeapStats* stats) {
    1274          15 :   *stats->global_handle_count = 0;
    1275          15 :   *stats->weak_global_handle_count = 0;
    1276          15 :   *stats->pending_global_handle_count = 0;
    1277          15 :   *stats->near_death_global_handle_count = 0;
    1278          15 :   *stats->free_global_handle_count = 0;
    1279          15 :   for (Node* node : *regular_nodes_) {
    1280           0 :     *stats->global_handle_count += 1;
    1281           0 :     if (node->state() == Node::WEAK) {
    1282           0 :       *stats->weak_global_handle_count += 1;
    1283           0 :     } else if (node->state() == Node::PENDING) {
    1284           0 :       *stats->pending_global_handle_count += 1;
    1285           0 :     } else if (node->state() == Node::NEAR_DEATH) {
    1286           0 :       *stats->near_death_global_handle_count += 1;
    1287           0 :     } else if (node->state() == Node::FREE) {
    1288           0 :       *stats->free_global_handle_count += 1;
    1289             :     }
    1290             :   }
    1291          15 : }
    1292             : 
    1293             : #ifdef DEBUG
    1294             : 
    1295             : void GlobalHandles::PrintStats() {
    1296             :   int total = 0;
    1297             :   int weak = 0;
    1298             :   int pending = 0;
    1299             :   int near_death = 0;
    1300             :   int destroyed = 0;
    1301             : 
    1302             :   for (Node* node : *regular_nodes_) {
    1303             :     total++;
    1304             :     if (node->state() == Node::WEAK) weak++;
    1305             :     if (node->state() == Node::PENDING) pending++;
    1306             :     if (node->state() == Node::NEAR_DEATH) near_death++;
    1307             :     if (node->state() == Node::FREE) destroyed++;
    1308             :   }
    1309             : 
    1310             :   PrintF("Global Handle Statistics:\n");
    1311             :   PrintF("  allocated memory = %" PRIuS "B\n", total * sizeof(Node));
    1312             :   PrintF("  # weak       = %d\n", weak);
    1313             :   PrintF("  # pending    = %d\n", pending);
    1314             :   PrintF("  # near_death = %d\n", near_death);
    1315             :   PrintF("  # free       = %d\n", destroyed);
    1316             :   PrintF("  # total      = %d\n", total);
    1317             : }
    1318             : 
    1319             : 
    1320             : void GlobalHandles::Print() {
    1321             :   PrintF("Global handles:\n");
    1322             :   for (Node* node : *regular_nodes_) {
    1323             :     PrintF("  handle %p to %p%s\n", node->location().ToVoidPtr(),
    1324             :            reinterpret_cast<void*>(node->object()->ptr()),
    1325             :            node->IsWeak() ? " (weak)" : "");
    1326             :   }
    1327             : }
    1328             : 
    1329             : #endif
    1330             : 
    1331      124822 : EternalHandles::~EternalHandles() {
    1332       62496 :   for (Address* block : blocks_) delete[] block;
    1333       62411 : }
    1334             : 
    1335      199861 : void EternalHandles::IterateAllRoots(RootVisitor* visitor) {
    1336      199861 :   int limit = size_;
    1337      200238 :   for (Address* block : blocks_) {
    1338             :     DCHECK_GT(limit, 0);
    1339         754 :     visitor->VisitRootPointers(Root::kEternalHandles, nullptr,
    1340             :                                FullObjectSlot(block),
    1341         754 :                                FullObjectSlot(block + Min(limit, kSize)));
    1342         377 :     limit -= kSize;
    1343             :   }
    1344      199861 : }
    1345             : 
    1346       28965 : void EternalHandles::IterateYoungRoots(RootVisitor* visitor) {
    1347       43829 :   for (int index : young_node_indices_) {
    1348       14864 :     visitor->VisitRootPointer(Root::kEternalHandles, nullptr,
    1349       29728 :                               FullObjectSlot(GetLocation(index)));
    1350             :   }
    1351       28965 : }
    1352             : 
    1353      104302 : void EternalHandles::PostGarbageCollectionProcessing() {
    1354             :   size_t last = 0;
    1355      145192 :   for (int index : young_node_indices_) {
    1356       81780 :     if (ObjectInYoungGeneration(Object(*GetLocation(index)))) {
    1357       40840 :       young_node_indices_[last++] = index;
    1358             :     }
    1359             :   }
    1360             :   DCHECK_LE(last, young_node_indices_.size());
    1361      104302 :   young_node_indices_.resize(last);
    1362      104302 : }
    1363             : 
    1364       20480 : void EternalHandles::Create(Isolate* isolate, Object object, int* index) {
    1365             :   DCHECK_EQ(kInvalidIndex, *index);
    1366       20480 :   if (object == Object()) return;
    1367             :   Object the_hole = ReadOnlyRoots(isolate).the_hole_value();
    1368             :   DCHECK_NE(the_hole, object);
    1369       20480 :   int block = size_ >> kShift;
    1370       20480 :   int offset = size_ & kMask;
    1371             :   // Need to resize.
    1372       20480 :   if (offset == 0) {
    1373          85 :     Address* next_block = new Address[kSize];
    1374             :     MemsetPointer(FullObjectSlot(next_block), the_hole, kSize);
    1375          85 :     blocks_.push_back(next_block);
    1376             :   }
    1377             :   DCHECK_EQ(the_hole->ptr(), blocks_[block][offset]);
    1378       40960 :   blocks_[block][offset] = object->ptr();
    1379       20480 :   if (ObjectInYoungGeneration(object)) {
    1380       20475 :     young_node_indices_.push_back(size_);
    1381             :   }
    1382       20480 :   *index = size_++;
    1383             : }
    1384             : 
    1385             : }  // namespace internal
    1386      122004 : }  // namespace v8

Generated by: LCOV version 1.10