LCOV - code coverage report
Current view: top level - src - global-handles.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 355 397 89.4 %
Date: 2019-01-20 Functions: 57 62 91.9 %

          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/objects-inl.h"
      11             : #include "src/objects/slots.h"
      12             : #include "src/task-utils.h"
      13             : #include "src/v8.h"
      14             : #include "src/visitors.h"
      15             : #include "src/vm-state-inl.h"
      16             : 
      17             : namespace v8 {
      18             : namespace internal {
      19             : 
      20             : namespace {
      21             : 
      22             : constexpr size_t kBlockSize = 256;
      23             : 
      24             : }  // namespace
      25             : 
      26             : template <class _NodeType>
      27      111424 : class GlobalHandles::NodeBlock final {
      28             :  public:
      29             :   using BlockType = NodeBlock<_NodeType>;
      30             :   using NodeType = _NodeType;
      31             : 
      32             :   V8_INLINE static NodeBlock* From(NodeType* node);
      33             : 
      34       55713 :   NodeBlock(GlobalHandles* global_handles,
      35             :             GlobalHandles::NodeSpace<NodeType>* space,
      36             :             NodeBlock* next) V8_NOEXCEPT : next_(next),
      37             :                                            global_handles_(global_handles),
      38    14318241 :                                            space_(space) {}
      39             : 
      40             :   NodeType* at(size_t index) { return &nodes_[index]; }
      41             :   const NodeType* at(size_t index) const { return &nodes_[index]; }
      42             :   GlobalHandles::NodeSpace<NodeType>* space() const { return space_; }
      43             :   GlobalHandles* global_handles() const { return global_handles_; }
      44             : 
      45             :   V8_INLINE bool IncreaseUsage();
      46             :   V8_INLINE bool DecreaseUsage();
      47             : 
      48             :   V8_INLINE void ListAdd(NodeBlock** top);
      49             :   V8_INLINE void ListRemove(NodeBlock** top);
      50             : 
      51             :   NodeBlock* next() const { return next_; }
      52             :   NodeBlock* next_used() const { return next_used_; }
      53             : 
      54             :  private:
      55             :   NodeType nodes_[kBlockSize];
      56             :   NodeBlock* const next_;
      57             :   GlobalHandles* const global_handles_;
      58             :   GlobalHandles::NodeSpace<NodeType>* const space_;
      59             :   NodeBlock* next_used_ = nullptr;
      60             :   NodeBlock* prev_used_ = nullptr;
      61             :   uint32_t used_nodes_ = 0;
      62             : 
      63             :   DISALLOW_COPY_AND_ASSIGN(NodeBlock);
      64             : };
      65             : 
      66             : template <class NodeType>
      67             : GlobalHandles::NodeBlock<NodeType>* GlobalHandles::NodeBlock<NodeType>::From(
      68    20720765 :     NodeType* node) {
      69             :   uintptr_t ptr =
      70    34676921 :       reinterpret_cast<uintptr_t>(node) - sizeof(NodeType) * node->index();
      71    20720765 :   BlockType* block = reinterpret_cast<BlockType*>(ptr);
      72             :   DCHECK_EQ(node, block->at(node->index()));
      73             :   return block;
      74             : }
      75             : 
      76             : template <class NodeType>
      77             : bool GlobalHandles::NodeBlock<NodeType>::IncreaseUsage() {
      78             :   DCHECK_LT(used_nodes_, kBlockSize);
      79     7191537 :   return used_nodes_++ == 0;
      80             : }
      81             : 
      82             : template <class NodeType>
      83             : void GlobalHandles::NodeBlock<NodeType>::ListAdd(BlockType** top) {
      84       88260 :   BlockType* old_top = *top;
      85       88260 :   *top = this;
      86       88260 :   next_used_ = old_top;
      87       88260 :   prev_used_ = nullptr;
      88       88260 :   if (old_top != nullptr) {
      89       14900 :     old_top->prev_used_ = this;
      90             :   }
      91             : }
      92             : 
      93             : template <class NodeType>
      94             : bool GlobalHandles::NodeBlock<NodeType>::DecreaseUsage() {
      95             :   DCHECK_GT(used_nodes_, 0);
      96     6764609 :   return --used_nodes_ == 0;
      97             : }
      98             : 
      99             : template <class NodeType>
     100             : void GlobalHandles::NodeBlock<NodeType>::ListRemove(BlockType** top) {
     101       73552 :   if (next_used_ != nullptr) next_used_->prev_used_ = prev_used_;
     102       73552 :   if (prev_used_ != nullptr) prev_used_->next_used_ = next_used_;
     103       73552 :   if (this == *top) {
     104       69860 :     *top = next_used_;
     105             :   }
     106             : }
     107             : 
     108             : template <class BlockType>
     109             : class GlobalHandles::NodeIterator final {
     110             :  public:
     111             :   using NodeType = typename BlockType::NodeType;
     112             : 
     113             :   // Iterator traits.
     114             :   using iterator_category = std::forward_iterator_tag;
     115             :   using difference_type = std::ptrdiff_t;
     116             :   using value_type = NodeType*;
     117             :   using reference = value_type;
     118             :   using pointer = value_type*;
     119             : 
     120             :   explicit NodeIterator(BlockType* block) V8_NOEXCEPT : block_(block) {}
     121             :   NodeIterator(NodeIterator&& other) V8_NOEXCEPT : block_(other.block_),
     122             :                                                    index_(other.index_) {}
     123             : 
     124             :   bool operator==(const NodeIterator& other) const {
     125             :     return block_ == other.block_;
     126             :   }
     127             :   bool operator!=(const NodeIterator& other) const {
     128             :     return block_ != other.block_;
     129             :   }
     130             : 
     131             :   NodeIterator& operator++() {
     132   172731136 :     if (++index_ < kBlockSize) return *this;
     133             :     index_ = 0;
     134      674731 :     block_ = block_->next_used();
     135             :     return *this;
     136             :   }
     137             : 
     138             :   NodeType* operator*() { return block_->at(index_); }
     139             :   NodeType* operator->() { return block_->at(index_); }
     140             : 
     141             :  private:
     142             :   BlockType* block_ = nullptr;
     143             :   size_t index_ = 0;
     144             : 
     145             :   DISALLOW_COPY_AND_ASSIGN(NodeIterator);
     146             : };
     147             : 
     148             : template <class NodeType>
     149             : class GlobalHandles::NodeSpace final {
     150             :  public:
     151             :   using BlockType = NodeBlock<NodeType>;
     152             :   using iterator = NodeIterator<BlockType>;
     153             : 
     154             :   static NodeSpace* From(NodeType* node);
     155             :   static void Release(NodeType* node);
     156             : 
     157             :   explicit NodeSpace(GlobalHandles* global_handles) V8_NOEXCEPT
     158       62883 :       : global_handles_(global_handles) {}
     159             :   ~NodeSpace();
     160             : 
     161             :   V8_INLINE NodeType* Acquire(Object object);
     162             : 
     163             :   iterator begin() { return iterator(first_used_block_); }
     164             :   iterator end() { return iterator(nullptr); }
     165             : 
     166             :  private:
     167             :   void PutNodesOnFreeList(BlockType* block);
     168             :   V8_INLINE void Free(NodeType* node);
     169             : 
     170             :   GlobalHandles* const global_handles_;
     171             :   BlockType* first_block_ = nullptr;
     172             :   BlockType* first_used_block_ = nullptr;
     173             :   NodeType* first_free_ = nullptr;
     174             : };
     175             : 
     176             : template <class NodeType>
     177       62867 : GlobalHandles::NodeSpace<NodeType>::~NodeSpace() {
     178      118579 :   auto* block = first_block_;
     179      181447 :   while (block != nullptr) {
     180             :     auto* tmp = block->next();
     181       55712 :     delete block;
     182             :     block = tmp;
     183             :   }
     184       62868 : }
     185             : 
     186             : template <class NodeType>
     187             : NodeType* GlobalHandles::NodeSpace<NodeType>::Acquire(Object object) {
     188    14383066 :   if (first_free_ == nullptr) {
     189     7247250 :     first_block_ = new BlockType(global_handles_, this, first_block_);
     190       55713 :     PutNodesOnFreeList(first_block_);
     191             :   }
     192             :   DCHECK_NOT_NULL(first_free_);
     193     7191533 :   NodeType* node = first_free_;
     194     7191533 :   first_free_ = first_free_->next_free();
     195     7191537 :   node->Acquire(object);
     196             :   BlockType* block = BlockType::From(node);
     197     7191537 :   if (block->IncreaseUsage()) {
     198             :     block->ListAdd(&first_used_block_);
     199             :   }
     200    14383074 :   global_handles_->isolate()->counters()->global_handles()->Increment();
     201     7191537 :   global_handles_->number_of_global_handles_++;
     202             :   DCHECK(node->IsInUse());
     203             :   return node;
     204             : }
     205             : 
     206             : template <class NodeType>
     207       55713 : void GlobalHandles::NodeSpace<NodeType>::PutNodesOnFreeList(BlockType* block) {
     208    14262528 :   for (int32_t i = kBlockSize - 1; i >= 0; --i) {
     209    14262528 :     NodeType* node = block->at(i);
     210             :     const uint8_t index = static_cast<uint8_t>(i);
     211             :     DCHECK_EQ(i, index);
     212    14262528 :     node->set_index(index);
     213    14262528 :     node->Free(first_free_);
     214    14262528 :     first_free_ = node;
     215             :   }
     216       55713 : }
     217             : 
     218             : template <class NodeType>
     219     6764609 : void GlobalHandles::NodeSpace<NodeType>::Release(NodeType* node) {
     220     6764609 :   BlockType* block = BlockType::From(node);
     221             :   block->space()->Free(node);
     222     6764609 : }
     223             : 
     224             : template <class NodeType>
     225             : void GlobalHandles::NodeSpace<NodeType>::Free(NodeType* node) {
     226     6764609 :   node->Release(first_free_);
     227     6764609 :   first_free_ = node;
     228             :   BlockType* block = BlockType::From(node);
     229     6764609 :   if (block->DecreaseUsage()) {
     230             :     block->ListRemove(&first_used_block_);
     231             :   }
     232     6764609 :   global_handles_->isolate()->counters()->global_handles()->Decrement();
     233     6764609 :   global_handles_->number_of_global_handles_--;
     234             : }
     235             : 
     236             : class GlobalHandles::Node final {
     237             :  public:
     238             :   // State transition diagram:
     239             :   // FREE -> NORMAL <-> WEAK -> PENDING -> NEAR_DEATH -> { NORMAL, WEAK, FREE }
     240             :   enum State {
     241             :     FREE = 0,
     242             :     NORMAL,      // Normal global handle.
     243             :     WEAK,        // Flagged as weak but not yet finalized.
     244             :     PENDING,     // Has been recognized as only reachable by weak handles.
     245             :     NEAR_DEATH,  // Callback has informed the handle is near death.
     246             :     NUMBER_OF_NODE_STATES
     247             :   };
     248             : 
     249             :   // Maps handle location (slot) to the containing node.
     250             :   static Node* FromLocation(Address* location) {
     251             :     DCHECK_EQ(offsetof(Node, object_), 0);
     252             :     return reinterpret_cast<Node*>(location);
     253             :   }
     254             : 
     255             :   Node() {
     256             :     DCHECK_EQ(offsetof(Node, class_id_), Internals::kNodeClassIdOffset);
     257             :     DCHECK_EQ(offsetof(Node, flags_), Internals::kNodeFlagsOffset);
     258             :     STATIC_ASSERT(static_cast<int>(NodeState::kMask) ==
     259             :                   Internals::kNodeStateMask);
     260             :     STATIC_ASSERT(WEAK == Internals::kNodeStateIsWeakValue);
     261             :     STATIC_ASSERT(PENDING == Internals::kNodeStateIsPendingValue);
     262             :     STATIC_ASSERT(NEAR_DEATH == Internals::kNodeStateIsNearDeathValue);
     263             :     STATIC_ASSERT(static_cast<int>(IsIndependent::kShift) ==
     264             :                   Internals::kNodeIsIndependentShift);
     265             :     STATIC_ASSERT(static_cast<int>(IsActive::kShift) ==
     266             :                   Internals::kNodeIsActiveShift);
     267             :     set_in_new_space_list(false);
     268             :   }
     269             : 
     270             : #ifdef ENABLE_HANDLE_ZAPPING
     271             :   ~Node() {
     272             :     ClearFields();
     273    14262168 :     data_.next_free = nullptr;
     274    14262168 :     index_ = 0;
     275             :   }
     276             : #endif
     277             : 
     278             :   void Free(Node* free_list) {
     279             :     ClearFields();
     280             :     set_state(FREE);
     281    21027137 :     data_.next_free = free_list;
     282             :   }
     283             : 
     284     7191537 :   void Acquire(Object object) {
     285             :     DCHECK(!IsInUse());
     286             :     CheckFieldsAreCleared();
     287     7191537 :     object_ = object.ptr();
     288             :     set_state(NORMAL);
     289     7191537 :     data_.parameter = nullptr;
     290             :     DCHECK(IsInUse());
     291     7191537 :   }
     292             : 
     293     6764609 :   void Release(Node* free_list) {
     294             :     DCHECK(IsInUse());
     295             :     Free(free_list);
     296             :     DCHECK(!IsInUse());
     297     6764609 :   }
     298             : 
     299             :   void Zap() {
     300             :     DCHECK(IsInUse());
     301             :     // Zap the values for eager trapping.
     302             :     object_ = kGlobalHandleZapValue;
     303             :   }
     304             : 
     305             :   // Object slot accessors.
     306             :   Object object() const { return Object(object_); }
     307    24703882 :   FullObjectSlot location() { return FullObjectSlot(&object_); }
     308     8489580 :   const char* label() { return state() == NORMAL ? data_.label : nullptr; }
     309     7191562 :   Handle<Object> handle() { return Handle<Object>(&object_); }
     310             : 
     311             :   // Wrapper class ID accessors.
     312             :   bool has_wrapper_class_id() const {
     313             :     return class_id_ != v8::HeapProfiler::kPersistentHandleNoClassId;
     314             :   }
     315             :   uint16_t wrapper_class_id() const { return class_id_; }
     316             : 
     317             :   // State and flag accessors.
     318             : 
     319             :   State state() const {
     320             :     return NodeState::decode(flags_);
     321             :   }
     322             :   void set_state(State state) {
     323    79554580 :     flags_ = NodeState::update(flags_, state);
     324             :   }
     325             : 
     326             :   bool is_independent() { return IsIndependent::decode(flags_); }
     327    70578610 :   void set_independent(bool v) { flags_ = IsIndependent::update(flags_, v); }
     328             : 
     329             :   bool is_active() {
     330             :     return IsActive::decode(flags_);
     331             :   }
     332             :   void set_active(bool v) {
     333    79913297 :     flags_ = IsActive::update(flags_, v);
     334             :   }
     335             : 
     336             :   bool is_in_new_space_list() {
     337             :     return IsInNewSpaceList::decode(flags_);
     338             :   }
     339             :   void set_in_new_space_list(bool v) {
     340    43353324 :     flags_ = IsInNewSpaceList::update(flags_, v);
     341             :   }
     342             : 
     343             :   WeaknessType weakness_type() const {
     344             :     return NodeWeaknessType::decode(flags_);
     345             :   }
     346             :   void set_weakness_type(WeaknessType weakness_type) {
     347     8393686 :     flags_ = NodeWeaknessType::update(flags_, weakness_type);
     348             :   }
     349             : 
     350          40 :   bool IsNearDeath() const {
     351             :     // Check for PENDING to ensure correct answer when processing callbacks.
     352          40 :     return state() == PENDING || state() == NEAR_DEATH;
     353             :   }
     354             : 
     355    27282107 :   bool IsWeak() const { return state() == WEAK; }
     356             : 
     357             :   bool IsInUse() const { return state() != FREE; }
     358             : 
     359     3680870 :   bool IsPhantomCallback() const {
     360     7361696 :     return weakness_type() == PHANTOM_WEAK ||
     361             :            weakness_type() == PHANTOM_WEAK_2_EMBEDDER_FIELDS;
     362             :   }
     363             : 
     364     3680842 :   bool IsPhantomResetHandle() const {
     365             :     return weakness_type() == PHANTOM_WEAK_RESET_HANDLE;
     366             :   }
     367             : 
     368             :   bool IsPendingPhantomCallback() const {
     369             :     return state() == PENDING && IsPhantomCallback();
     370             :   }
     371             : 
     372             :   bool IsPendingPhantomResetHandle() const {
     373             :     return state() == PENDING && IsPhantomResetHandle();
     374             :   }
     375             : 
     376    61355071 :   bool IsRetainer() const {
     377    61355071 :     return state() != FREE &&
     378     3673089 :            !(state() == NEAR_DEATH && weakness_type() != FINALIZER_WEAK);
     379             :   }
     380             : 
     381    41161363 :   bool IsStrongRetainer() const { return state() == NORMAL; }
     382             : 
     383    53713408 :   bool IsWeakRetainer() const {
     384    54305855 :     return state() == WEAK || state() == PENDING ||
     385           0 :            (state() == NEAR_DEATH && weakness_type() == FINALIZER_WEAK);
     386             :   }
     387             : 
     388             :   void MarkPending() {
     389             :     DCHECK(state() == WEAK);
     390             :     set_state(PENDING);
     391             :   }
     392             : 
     393             :   // Callback parameter accessors.
     394             :   void set_parameter(void* parameter) {
     395             :     DCHECK(IsInUse());
     396     4196908 :     data_.parameter = parameter;
     397             :   }
     398             :   void* parameter() const {
     399             :     DCHECK(IsInUse());
     400             :     return data_.parameter;
     401             :   }
     402             : 
     403             :   // Accessors for next free node in the free list.
     404     7191537 :   Node* next_free() {
     405             :     DCHECK_EQ(FREE, state());
     406     7191537 :     return data_.next_free;
     407             :   }
     408             : 
     409     4196847 :   void MakeWeak(void* parameter,
     410             :                 WeakCallbackInfo<void>::Callback phantom_callback,
     411             :                 v8::WeakCallbackType type) {
     412             :     DCHECK_NOT_NULL(phantom_callback);
     413             :     DCHECK(IsInUse());
     414     4196847 :     CHECK_NE(object_, kGlobalHandleZapValue);
     415             :     set_state(WEAK);
     416     4196847 :     switch (type) {
     417             :       case v8::WeakCallbackType::kParameter:
     418             :         set_weakness_type(PHANTOM_WEAK);
     419             :         break;
     420             :       case v8::WeakCallbackType::kInternalFields:
     421             :         set_weakness_type(PHANTOM_WEAK_2_EMBEDDER_FIELDS);
     422             :         break;
     423             :       case v8::WeakCallbackType::kFinalizer:
     424             :         set_weakness_type(FINALIZER_WEAK);
     425             :         break;
     426             :     }
     427             :     set_parameter(parameter);
     428     4196847 :     weak_callback_ = phantom_callback;
     429     4196847 :   }
     430             : 
     431          26 :   void MakeWeak(Address** location_addr) {
     432             :     DCHECK(IsInUse());
     433          26 :     CHECK_NE(object_, kGlobalHandleZapValue);
     434             :     set_state(WEAK);
     435             :     set_weakness_type(PHANTOM_WEAK_RESET_HANDLE);
     436             :     set_parameter(location_addr);
     437          26 :     weak_callback_ = nullptr;
     438          26 :   }
     439             : 
     440          35 :   void* ClearWeakness() {
     441             :     DCHECK(IsInUse());
     442             :     void* p = parameter();
     443             :     set_state(NORMAL);
     444             :     set_parameter(nullptr);
     445             :     return p;
     446             :   }
     447             : 
     448             :   void AnnotateStrongRetainer(const char* label) {
     449             :     DCHECK_EQ(state(), NORMAL);
     450     2814437 :     data_.label = label;
     451             :   }
     452             : 
     453     3680826 :   void CollectPhantomCallbackData(
     454             : 
     455     7361686 :       std::vector<PendingPhantomCallback>* pending_phantom_callbacks) {
     456             :     DCHECK(weakness_type() == PHANTOM_WEAK ||
     457             :            weakness_type() == PHANTOM_WEAK_2_EMBEDDER_FIELDS);
     458             :     DCHECK(state() == PENDING);
     459             :     DCHECK_NOT_NULL(weak_callback_);
     460             : 
     461             :     void* embedder_fields[v8::kEmbedderFieldsInWeakCallback] = {nullptr,
     462     3680826 :                                                                 nullptr};
     463     3680860 :     if (weakness_type() != PHANTOM_WEAK && object()->IsJSObject()) {
     464          17 :       JSObject jsobject = JSObject::cast(object());
     465          17 :       int field_count = jsobject->GetEmbedderFieldCount();
     466          46 :       for (int i = 0; i < v8::kEmbedderFieldsInWeakCallback; ++i) {
     467          34 :         if (field_count == i) break;
     468             :         void* pointer;
     469          29 :         if (EmbedderDataSlot(jsobject, i).ToAlignedPointer(&pointer)) {
     470          29 :           embedder_fields[i] = pointer;
     471             :         }
     472             :       }
     473             :     }
     474             : 
     475             :     // Zap with something dangerous.
     476             :     location().store(Object(0x6057CA11));
     477             : 
     478             :     pending_phantom_callbacks->push_back(PendingPhantomCallback(
     479     7361652 :         this, weak_callback_, parameter(), embedder_fields));
     480             :     DCHECK(IsInUse());
     481             :     set_state(NEAR_DEATH);
     482     3680826 :   }
     483             : 
     484          16 :   void ResetPhantomHandle() {
     485             :     DCHECK(weakness_type() == PHANTOM_WEAK_RESET_HANDLE);
     486             :     DCHECK(state() == PENDING);
     487             :     DCHECK_NULL(weak_callback_);
     488             :     Address** handle = reinterpret_cast<Address**>(parameter());
     489          16 :     *handle = nullptr;
     490          16 :     NodeSpace<Node>::Release(this);
     491             :   }
     492             : 
     493     4525174 :   bool PostGarbageCollectionProcessing(Isolate* isolate) {
     494             :     // Handles only weak handles (not phantom) that are dying.
     495     4525134 :     if (state() != Node::PENDING) return false;
     496          20 :     if (weak_callback_ == nullptr) {
     497           0 :       NodeSpace<Node>::Release(this);
     498           0 :       return false;
     499             :     }
     500             :     set_state(NEAR_DEATH);
     501             : 
     502             :     // Check that we are not passing a finalized external string to
     503             :     // the callback.
     504             :     DCHECK(!object()->IsExternalOneByteString() ||
     505             :            ExternalOneByteString::cast(object())->resource() != nullptr);
     506             :     DCHECK(!object()->IsExternalTwoByteString() ||
     507             :            ExternalTwoByteString::cast(object())->resource() != nullptr);
     508          20 :     if (weakness_type() != FINALIZER_WEAK) {
     509             :       return false;
     510             :     }
     511             : 
     512             :     // Leaving V8.
     513          20 :     VMState<EXTERNAL> vmstate(isolate);
     514             :     HandleScope handle_scope(isolate);
     515             :     void* embedder_fields[v8::kEmbedderFieldsInWeakCallback] = {nullptr,
     516          20 :                                                                 nullptr};
     517             :     v8::WeakCallbackInfo<void> data(reinterpret_cast<v8::Isolate*>(isolate),
     518             :                                     parameter(), embedder_fields, nullptr);
     519          20 :     weak_callback_(data);
     520             : 
     521             :     // Absence of explicit cleanup or revival of weak handle
     522             :     // in most of the cases would lead to memory leak.
     523          20 :     CHECK(state() != NEAR_DEATH);
     524          20 :     return true;
     525             :   }
     526             : 
     527             :   inline GlobalHandles* GetGlobalHandles();
     528             : 
     529    20720764 :   uint8_t index() const { return index_; }
     530    14262528 :   void set_index(uint8_t value) { index_ = value; }
     531             : 
     532             :  private:
     533             :   // Fields that are not used for managing node memory.
     534             :   void ClearFields() {
     535             :     // Zap the values for eager trapping.
     536    35289305 :     object_ = kGlobalHandleZapValue;
     537    35289305 :     class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
     538             :     set_independent(false);
     539             :     set_active(false);
     540    35289305 :     weak_callback_ = nullptr;
     541             :   }
     542             : 
     543             :   void CheckFieldsAreCleared() {
     544             :     DCHECK_EQ(kGlobalHandleZapValue, object_);
     545             :     DCHECK_EQ(v8::HeapProfiler::kPersistentHandleNoClassId, class_id_);
     546             :     DCHECK(!is_independent());
     547             :     DCHECK(!is_active());
     548             :     DCHECK_EQ(nullptr, weak_callback_);
     549             :   }
     550             : 
     551             :   // Storage for object pointer.
     552             :   //
     553             :   // Placed first to avoid offset computation. The stored data is equivalent to
     554             :   // an Object. It is stored as a plain Address for convenience (smallest number
     555             :   // of casts), and because it is a private implementation detail: the public
     556             :   // interface provides type safety.
     557             :   Address object_;
     558             : 
     559             :   // Next word stores class_id, index, state, and independent.
     560             :   // Note: the most aligned fields should go first.
     561             : 
     562             :   // Wrapper class ID.
     563             :   uint16_t class_id_;
     564             : 
     565             :   // Index in the containing handle block.
     566             :   uint8_t index_;
     567             : 
     568             :   // This stores three flags (independent, partially_dependent and
     569             :   // in_new_space_list) and a State.
     570             :   class NodeState : public BitField<State, 0, 3> {};
     571             :   class IsIndependent : public BitField<bool, 3, 1> {};
     572             :   // The following two fields are mutually exclusive
     573             :   class IsActive : public BitField<bool, 4, 1> {};
     574             :   class IsInNewSpaceList : public BitField<bool, 5, 1> {};
     575             :   class NodeWeaknessType : public BitField<WeaknessType, 6, 2> {};
     576             : 
     577             :   uint8_t flags_;
     578             : 
     579             :   // Handle specific callback - might be a weak reference in disguise.
     580             :   WeakCallbackInfo<void>::Callback weak_callback_;
     581             : 
     582             :   // The meaning of this field depends on node state:
     583             :   // state == FREE: it stores the next free node pointer.
     584             :   // state == NORMAL: it stores the strong retainer label.
     585             :   // otherwise: it stores the parameter for the weak callback.
     586             :   union {
     587             :     Node* next_free;
     588             :     const char* label;
     589             :     void* parameter;
     590             :   } data_;
     591             : 
     592             :   DISALLOW_COPY_AND_ASSIGN(Node);
     593             : };
     594             : 
     595             : GlobalHandles* GlobalHandles::Node::GetGlobalHandles() {
     596          10 :   return NodeBlock<Node>::From(this)->global_handles();
     597             : }
     598             : 
     599       62883 : GlobalHandles::GlobalHandles(Isolate* isolate)
     600             :     : isolate_(isolate),
     601             :       regular_nodes_(new NodeSpace<GlobalHandles::Node>(this)),
     602             :       number_of_global_handles_(0),
     603             :       post_gc_processing_count_(0),
     604      188649 :       number_of_phantom_handle_resets_(0) {}
     605             : 
     606      125735 : GlobalHandles::~GlobalHandles() { regular_nodes_.reset(nullptr); }
     607             : 
     608     7191533 : Handle<Object> GlobalHandles::Create(Object value) {
     609     7191537 :   GlobalHandles::Node* result = regular_nodes_->Acquire(value);
     610    11270579 :   if (Heap::InNewSpace(value) && !result->is_in_new_space_list()) {
     611     3918755 :     new_space_nodes_.push_back(result);
     612     3918755 :     result->set_in_new_space_list(true);
     613             :   }
     614    14383074 :   return result->handle();
     615             : }
     616             : 
     617     3032512 : Handle<Object> GlobalHandles::Create(Address value) {
     618     3032522 :   return Create(Object(value));
     619             : }
     620             : 
     621          10 : Handle<Object> GlobalHandles::CopyGlobal(Address* location) {
     622             :   DCHECK_NOT_NULL(location);
     623             :   GlobalHandles* global_handles =
     624             :       Node::FromLocation(location)->GetGlobalHandles();
     625             : #ifdef VERIFY_HEAP
     626             :   if (i::FLAG_verify_heap) {
     627             :     Object(*location)->ObjectVerify(global_handles->isolate());
     628             :   }
     629             : #endif  // VERIFY_HEAP
     630          20 :   return global_handles->Create(*location);
     631             : }
     632             : 
     633     6764593 : void GlobalHandles::Destroy(Address* location) {
     634     6764593 :   if (location != nullptr) {
     635     6764593 :     NodeSpace<Node>::Release(Node::FromLocation(location));
     636             :   }
     637     6764593 : }
     638             : 
     639             : typedef v8::WeakCallbackInfo<void>::Callback GenericCallback;
     640             : 
     641             : 
     642     4196847 : void GlobalHandles::MakeWeak(Address* location, void* parameter,
     643             :                              GenericCallback phantom_callback,
     644             :                              v8::WeakCallbackType type) {
     645     4196847 :   Node::FromLocation(location)->MakeWeak(parameter, phantom_callback, type);
     646     4196848 : }
     647             : 
     648          26 : void GlobalHandles::MakeWeak(Address** location_addr) {
     649          26 :   Node::FromLocation(*location_addr)->MakeWeak(location_addr);
     650          26 : }
     651             : 
     652          35 : void* GlobalHandles::ClearWeakness(Address* location) {
     653          35 :   return Node::FromLocation(location)->ClearWeakness();
     654             : }
     655             : 
     656     2814437 : void GlobalHandles::AnnotateStrongRetainer(Address* location,
     657             :                                            const char* label) {
     658             :   Node::FromLocation(location)->AnnotateStrongRetainer(label);
     659     2814437 : }
     660             : 
     661          40 : bool GlobalHandles::IsNearDeath(Address* location) {
     662          40 :   return Node::FromLocation(location)->IsNearDeath();
     663             : }
     664             : 
     665          20 : bool GlobalHandles::IsWeak(Address* location) {
     666          20 :   return Node::FromLocation(location)->IsWeak();
     667             : }
     668             : 
     669             : DISABLE_CFI_PERF
     670       83492 : void GlobalHandles::IterateWeakRootsForFinalizers(RootVisitor* v) {
     671    27023688 :   for (Node* node : *regular_nodes_) {
     672    26856704 :     if (node->IsWeakRetainer() && node->state() == Node::PENDING) {
     673             :       DCHECK(!node->IsPhantomCallback());
     674             :       DCHECK(!node->IsPhantomResetHandle());
     675             :       // Finalizers need to survive.
     676             :       v->VisitRootPointer(Root::kGlobalHandles, node->label(),
     677          40 :                           node->location());
     678             :     }
     679             :   }
     680       83492 : }
     681             : 
     682             : DISABLE_CFI_PERF
     683       83492 : void GlobalHandles::IterateWeakRootsForPhantomHandles(
     684     6189964 :     WeakSlotCallbackWithHeap should_reset_handle) {
     685    27023688 :   for (Node* node : *regular_nodes_) {
     686    33046668 :     if (node->IsWeakRetainer() &&
     687     6189964 :         should_reset_handle(isolate()->heap(), node->location())) {
     688     3673105 :       if (node->IsPhantomResetHandle()) {
     689             :         node->MarkPending();
     690             :         node->ResetPhantomHandle();
     691          16 :         ++number_of_phantom_handle_resets_;
     692     3673089 :       } else if (node->IsPhantomCallback()) {
     693             :         node->MarkPending();
     694     3673089 :         node->CollectPhantomCallbackData(&pending_phantom_callbacks_);
     695             :       }
     696             :     }
     697             :   }
     698       83492 : }
     699             : 
     700       83492 : void GlobalHandles::IdentifyWeakHandles(
     701     6189964 :     WeakSlotCallbackWithHeap should_reset_handle) {
     702    27023688 :   for (Node* node : *regular_nodes_) {
     703    33046668 :     if (node->IsWeak() &&
     704     6189964 :         should_reset_handle(isolate()->heap(), node->location())) {
     705     3673133 :       if (!node->IsPhantomCallback() && !node->IsPhantomResetHandle()) {
     706             :         node->MarkPending();
     707             :       }
     708             :     }
     709             :   }
     710       83492 : }
     711             : 
     712       23594 : void GlobalHandles::IterateNewSpaceStrongAndDependentRoots(RootVisitor* v) {
     713      370407 :   for (Node* node : new_space_nodes_) {
     714      798807 :     if (node->IsStrongRetainer() ||
     715      241290 :         (node->IsWeakRetainer() && !node->is_independent() &&
     716             :          node->is_active())) {
     717             :       v->VisitRootPointer(Root::kGlobalHandles, node->label(),
     718      548060 :                           node->location());
     719             :     }
     720             :   }
     721       23594 : }
     722             : 
     723           0 : void GlobalHandles::IterateNewSpaceStrongAndDependentRootsAndIdentifyUnmodified(
     724             :     RootVisitor* v, size_t start, size_t end) {
     725           0 :   for (size_t i = start; i < end; ++i) {
     726           0 :     Node* node = new_space_nodes_[i];
     727           0 :     if (node->IsWeak() && !JSObject::IsUnmodifiedApiObject(node->location())) {
     728             :       node->set_active(true);
     729             :     }
     730           0 :     if (node->IsStrongRetainer() ||
     731           0 :         (node->IsWeakRetainer() && !node->is_independent() &&
     732             :          node->is_active())) {
     733             :       v->VisitRootPointer(Root::kGlobalHandles, node->label(),
     734           0 :                           node->location());
     735             :     }
     736             :   }
     737           0 : }
     738             : 
     739       23594 : void GlobalHandles::IdentifyWeakUnmodifiedObjects(
     740             :     WeakSlotCallback is_unmodified) {
     741      370407 :   for (Node* node : new_space_nodes_) {
     742      461293 :     if (node->IsWeak() && !is_unmodified(node->location())) {
     743             :       node->set_active(true);
     744             :     }
     745             :   }
     746       23594 : }
     747             : 
     748       23594 : void GlobalHandles::MarkNewSpaceWeakUnmodifiedObjectsPending(
     749             :     WeakSlotCallbackWithHeap is_dead) {
     750      370407 :   for (Node* node : new_space_nodes_) {
     751             :     DCHECK(node->is_in_new_space_list());
     752      866513 :     if ((node->is_independent() || !node->is_active()) && node->IsWeak() &&
     753       34894 :         is_dead(isolate_->heap(), node->location())) {
     754        7737 :       if (!node->IsPhantomCallback() && !node->IsPhantomResetHandle()) {
     755             :         node->MarkPending();
     756             :       }
     757             :     }
     758             :   }
     759       23594 : }
     760             : 
     761       23594 : void GlobalHandles::IterateNewSpaceWeakUnmodifiedRootsForFinalizers(
     762             :     RootVisitor* v) {
     763      370407 :   for (Node* node : new_space_nodes_) {
     764             :     DCHECK(node->is_in_new_space_list());
     765      831619 :     if ((node->is_independent() || !node->is_active()) &&
     766      358113 :         node->IsWeakRetainer() && (node->state() == Node::PENDING)) {
     767             :       DCHECK(!node->IsPhantomCallback());
     768             :       DCHECK(!node->IsPhantomResetHandle());
     769             :       // Finalizers need to survive.
     770             :       v->VisitRootPointer(Root::kGlobalHandles, node->label(),
     771           0 :                           node->location());
     772             :     }
     773             :   }
     774       23594 : }
     775             : 
     776       23594 : void GlobalHandles::IterateNewSpaceWeakUnmodifiedRootsForPhantomHandles(
     777             :     RootVisitor* v, WeakSlotCallbackWithHeap should_reset_handle) {
     778      370407 :   for (Node* node : new_space_nodes_) {
     779             :     DCHECK(node->is_in_new_space_list());
     780      831619 :     if ((node->is_independent() || !node->is_active()) &&
     781      358113 :         node->IsWeakRetainer() && (node->state() != Node::PENDING)) {
     782       34894 :       if (should_reset_handle(isolate_->heap(), node->location())) {
     783             :         DCHECK(node->IsPhantomResetHandle() || node->IsPhantomCallback());
     784        7737 :         if (node->IsPhantomResetHandle()) {
     785             :           node->MarkPending();
     786             :           node->ResetPhantomHandle();
     787           0 :           ++number_of_phantom_handle_resets_;
     788             : 
     789        7737 :         } else if (node->IsPhantomCallback()) {
     790             :           node->MarkPending();
     791        7737 :           node->CollectPhantomCallbackData(&pending_phantom_callbacks_);
     792             :         } else {
     793           0 :           UNREACHABLE();
     794             :         }
     795             :       } else {
     796             :         // Node survived and needs to be visited.
     797             :         v->VisitRootPointer(Root::kGlobalHandles, node->label(),
     798       54314 :                             node->location());
     799             :       }
     800             :     }
     801             :   }
     802       23594 : }
     803             : 
     804        2565 : void GlobalHandles::InvokeSecondPassPhantomCallbacksFromTask() {
     805             :   DCHECK(second_pass_callbacks_task_posted_);
     806         855 :   second_pass_callbacks_task_posted_ = false;
     807        1710 :   TRACE_EVENT0("v8", "V8.GCPhantomHandleProcessingCallback");
     808             :   isolate()->heap()->CallGCPrologueCallbacks(
     809         855 :       GCType::kGCTypeProcessWeakCallbacks, kNoGCCallbackFlags);
     810         855 :   InvokeSecondPassPhantomCallbacks();
     811             :   isolate()->heap()->CallGCEpilogueCallbacks(
     812         855 :       GCType::kGCTypeProcessWeakCallbacks, kNoGCCallbackFlags);
     813         855 : }
     814             : 
     815     3353299 : void GlobalHandles::InvokeSecondPassPhantomCallbacks() {
     816     3470633 :   while (!second_pass_callbacks_.empty()) {
     817     3235965 :     auto callback = second_pass_callbacks_.back();
     818             :     second_pass_callbacks_.pop_back();
     819             :     DCHECK_NULL(callback.node());
     820             :     // Fire second pass callback
     821     3235965 :     callback.Invoke(isolate());
     822             :   }
     823      117334 : }
     824             : 
     825       23594 : int GlobalHandles::PostScavengeProcessing(
     826             :     const int initial_post_gc_processing_count) {
     827             :   int freed_nodes = 0;
     828      370407 :   for (Node* node : new_space_nodes_) {
     829             :     DCHECK(node->is_in_new_space_list());
     830      323219 :     if (!node->IsRetainer()) {
     831             :       // Free nodes do not have weak callbacks. Do not use them to compute
     832             :       // the freed_nodes.
     833             :       continue;
     834             :     }
     835             :     // Skip dependent or unmodified handles. Their weak callbacks might expect
     836             :     // to be
     837             :     // called between two global garbage collection callbacks which
     838             :     // are not called for minor collections.
     839      575227 :     if (!node->is_independent() && (node->is_active())) {
     840             :       node->set_active(false);
     841             :       continue;
     842             :     }
     843             :     node->set_active(false);
     844             : 
     845      198007 :     if (node->PostGarbageCollectionProcessing(isolate_)) {
     846           0 :       if (initial_post_gc_processing_count != post_gc_processing_count_) {
     847             :         // Weak callback triggered another GC and another round of
     848             :         // PostGarbageCollection processing.  The current node might
     849             :         // have been deleted in that round, so we need to bail out (or
     850             :         // restart the processing).
     851             :         return freed_nodes;
     852             :       }
     853             :     }
     854      198007 :     if (!node->IsRetainer()) {
     855           0 :       freed_nodes++;
     856             :     }
     857             :   }
     858             :   return freed_nodes;
     859             : }
     860             : 
     861             : 
     862       83492 : int GlobalHandles::PostMarkSweepProcessing(
     863             :     const int initial_post_gc_processing_count) {
     864             :   int freed_nodes = 0;
     865    23995208 :   for (Node* node : *regular_nodes_) {
     866    23828224 :     if (!node->IsRetainer()) {
     867             :       // Free nodes do not have weak callbacks. Do not use them to compute
     868             :       // the freed_nodes.
     869             :       continue;
     870             :     }
     871             :     node->set_active(false);
     872     4327127 :     if (node->PostGarbageCollectionProcessing(isolate_)) {
     873          20 :       if (initial_post_gc_processing_count != post_gc_processing_count_) {
     874             :         // See the comment above.
     875             :         return freed_nodes;
     876             :       }
     877             :     }
     878     4327127 :     if (!node->IsRetainer()) {
     879           5 :       freed_nodes++;
     880             :     }
     881             :   }
     882       83492 :   return freed_nodes;
     883             : }
     884             : 
     885             : 
     886      107086 : void GlobalHandles::UpdateListOfNewSpaceNodes() {
     887             :   size_t last = 0;
     888     7615465 :   for (Node* node : new_space_nodes_) {
     889             :     DCHECK(node->is_in_new_space_list());
     890     5285977 :     if (node->IsRetainer()) {
     891     2115316 :       if (Heap::InNewSpace(node->object())) {
     892     3581196 :         new_space_nodes_[last++] = node;
     893     1790598 :         isolate_->heap()->IncrementNodesCopiedInNewSpace();
     894             :       } else {
     895             :         node->set_in_new_space_list(false);
     896      324718 :         isolate_->heap()->IncrementNodesPromoted();
     897             :       }
     898             :     } else {
     899             :       node->set_in_new_space_list(false);
     900     3170661 :       isolate_->heap()->IncrementNodesDiedInNewSpace();
     901             :     }
     902             :   }
     903             :   DCHECK_LE(last, new_space_nodes_.size());
     904      107086 :   new_space_nodes_.resize(last);
     905             :   new_space_nodes_.shrink_to_fit();
     906      107086 : }
     907             : 
     908     3787912 : int GlobalHandles::InvokeFirstPassWeakCallbacks() {
     909             :   int freed_nodes = 0;
     910             :   std::vector<PendingPhantomCallback> pending_phantom_callbacks;
     911             :   pending_phantom_callbacks.swap(pending_phantom_callbacks_);
     912             :   {
     913             :     // The initial pass callbacks must simply clear the nodes.
     914     3894998 :     for (auto callback : pending_phantom_callbacks) {
     915             :       // Skip callbacks that have already been processed once.
     916     3680826 :       if (callback.node() == nullptr) continue;
     917     3680826 :       callback.Invoke(isolate());
     918     3680826 :       if (callback.callback()) second_pass_callbacks_.push_back(callback);
     919     3680826 :       freed_nodes++;
     920             :     }
     921             :   }
     922      107086 :   return freed_nodes;
     923             : }
     924             : 
     925      107086 : void GlobalHandles::InvokeOrScheduleSecondPassPhantomCallbacks(
     926       20496 :     bool synchronous_second_pass) {
     927      107086 :   if (!second_pass_callbacks_.empty()) {
     928       10487 :     if (FLAG_optimize_for_size || FLAG_predictable || synchronous_second_pass) {
     929             :       isolate()->heap()->CallGCPrologueCallbacks(
     930        9393 :           GCType::kGCTypeProcessWeakCallbacks, kNoGCCallbackFlags);
     931        9393 :       InvokeSecondPassPhantomCallbacks();
     932             :       isolate()->heap()->CallGCEpilogueCallbacks(
     933        9393 :           GCType::kGCTypeProcessWeakCallbacks, kNoGCCallbackFlags);
     934        1094 :     } else if (!second_pass_callbacks_task_posted_) {
     935         855 :       second_pass_callbacks_task_posted_ = true;
     936         855 :       auto taskrunner = V8::GetCurrentPlatform()->GetForegroundTaskRunner(
     937        1710 :           reinterpret_cast<v8::Isolate*>(isolate()));
     938         855 :       taskrunner->PostTask(MakeCancelableTask(
     939        5985 :           isolate(), [this] { InvokeSecondPassPhantomCallbacksFromTask(); }));
     940             :     }
     941             :   }
     942      107086 : }
     943             : 
     944     6916791 : void GlobalHandles::PendingPhantomCallback::Invoke(Isolate* isolate) {
     945             :   Data::Callback* callback_addr = nullptr;
     946    10597617 :   if (node_ != nullptr) {
     947             :     // Initialize for first pass callback.
     948             :     DCHECK(node_->state() == Node::NEAR_DEATH);
     949     3680826 :     callback_addr = &callback_;
     950             :   }
     951             :   Data data(reinterpret_cast<v8::Isolate*>(isolate), parameter_,
     952     6916791 :             embedder_fields_, callback_addr);
     953     6916791 :   Data::Callback callback = callback_;
     954     6916791 :   callback_ = nullptr;
     955     6916791 :   callback(data);
     956     6916791 :   if (node_ != nullptr) {
     957             :     // Transition to second pass. It is required that the first pass callback
     958             :     // resets the handle using |v8::PersistentBase::Reset|. Also see comments on
     959             :     // |v8::WeakCallbackInfo|.
     960     3680826 :     CHECK_WITH_MSG(Node::FREE == node_->state(),
     961             :                    "Handle not reset in first callback. See comments on "
     962             :                    "|v8::WeakCallbackInfo|.");
     963     3680826 :     node_ = nullptr;
     964             :   }
     965     6916791 : }
     966             : 
     967      107086 : int GlobalHandles::PostGarbageCollectionProcessing(
     968             :     GarbageCollector collector, const v8::GCCallbackFlags gc_callback_flags) {
     969             :   // Process weak global handle callbacks. This must be done after the
     970             :   // GC is completely done, because the callbacks may invoke arbitrary
     971             :   // API functions.
     972             :   DCHECK(isolate_->heap()->gc_state() == Heap::NOT_IN_GC);
     973      107086 :   const int initial_post_gc_processing_count = ++post_gc_processing_count_;
     974             :   int freed_nodes = 0;
     975             :   bool synchronous_second_pass =
     976      214172 :       isolate_->heap()->IsTearingDown() ||
     977      107086 :       (gc_callback_flags &
     978             :        (kGCCallbackFlagForced | kGCCallbackFlagCollectAllAvailableGarbage |
     979             :         kGCCallbackFlagSynchronousPhantomCallbackProcessing)) != 0;
     980      107086 :   InvokeOrScheduleSecondPassPhantomCallbacks(synchronous_second_pass);
     981      107086 :   if (initial_post_gc_processing_count != post_gc_processing_count_) {
     982             :     // If the callbacks caused a nested GC, then return.  See comment in
     983             :     // PostScavengeProcessing.
     984             :     return freed_nodes;
     985             :   }
     986      107086 :   if (Heap::IsYoungGenerationCollector(collector)) {
     987       23594 :     freed_nodes += PostScavengeProcessing(initial_post_gc_processing_count);
     988             :   } else {
     989       83492 :     freed_nodes += PostMarkSweepProcessing(initial_post_gc_processing_count);
     990             :   }
     991      107086 :   if (initial_post_gc_processing_count != post_gc_processing_count_) {
     992             :     // If the callbacks caused a nested GC, then return.  See comment in
     993             :     // PostScavengeProcessing.
     994             :     return freed_nodes;
     995             :   }
     996      107086 :   if (initial_post_gc_processing_count == post_gc_processing_count_) {
     997      107086 :     UpdateListOfNewSpaceNodes();
     998             :   }
     999      107086 :   return freed_nodes;
    1000             : }
    1001             : 
    1002      135795 : void GlobalHandles::IterateStrongRoots(RootVisitor* v) {
    1003    41109734 :   for (Node* node : *regular_nodes_) {
    1004    40838144 :     if (node->IsStrongRetainer()) {
    1005             :       v->VisitRootPointer(Root::kGlobalHandles, node->label(),
    1006     7575154 :                           node->location());
    1007             :     }
    1008             :   }
    1009      135795 : }
    1010             : 
    1011         399 : void GlobalHandles::IterateWeakRoots(RootVisitor* v) {
    1012      102942 :   for (Node* node : *regular_nodes_) {
    1013      102144 :     if (node->IsWeak()) {
    1014             :       v->VisitRootPointer(Root::kGlobalHandles, node->label(),
    1015          60 :                           node->location());
    1016             :     }
    1017             :   }
    1018         399 : }
    1019             : 
    1020             : DISABLE_CFI_PERF
    1021       85368 : void GlobalHandles::IterateAllRoots(RootVisitor* v) {
    1022    27467504 :   for (Node* node : *regular_nodes_) {
    1023    27296768 :     if (node->IsRetainer()) {
    1024             :       v->VisitRootPointer(Root::kGlobalHandles, node->label(),
    1025     8747218 :                           node->location());
    1026             :     }
    1027             :   }
    1028       85368 : }
    1029             : 
    1030             : DISABLE_CFI_PERF
    1031           0 : void GlobalHandles::IterateAllNewSpaceRoots(RootVisitor* v) {
    1032           0 :   for (Node* node : new_space_nodes_) {
    1033           0 :     if (node->IsRetainer()) {
    1034             :       v->VisitRootPointer(Root::kGlobalHandles, node->label(),
    1035           0 :                           node->location());
    1036             :     }
    1037             :   }
    1038           0 : }
    1039             : 
    1040             : DISABLE_CFI_PERF
    1041           0 : void GlobalHandles::IterateNewSpaceRoots(RootVisitor* v, size_t start,
    1042             :                                          size_t end) {
    1043           0 :   for (size_t i = start; i < end; ++i) {
    1044           0 :     Node* node = new_space_nodes_[i];
    1045           0 :     if (node->IsRetainer()) {
    1046             :       v->VisitRootPointer(Root::kGlobalHandles, node->label(),
    1047           0 :                           node->location());
    1048             :     }
    1049             :   }
    1050           0 : }
    1051             : 
    1052             : DISABLE_CFI_PERF
    1053           0 : void GlobalHandles::ApplyPersistentHandleVisitor(
    1054          25 :     v8::PersistentHandleVisitor* visitor, GlobalHandles::Node* node) {
    1055          25 :   v8::Value* value = ToApi<v8::Value>(node->handle());
    1056             :   visitor->VisitPersistentHandle(
    1057             :       reinterpret_cast<v8::Persistent<v8::Value>*>(&value),
    1058          50 :       node->wrapper_class_id());
    1059           0 : }
    1060             : 
    1061             : DISABLE_CFI_PERF
    1062         374 : void GlobalHandles::IterateAllRootsWithClassIds(
    1063             :     v8::PersistentHandleVisitor* visitor) {
    1064       97076 :   for (Node* node : *regular_nodes_) {
    1065       96328 :     if (node->IsRetainer() && node->has_wrapper_class_id()) {
    1066             :       ApplyPersistentHandleVisitor(visitor, node);
    1067             :     }
    1068             :   }
    1069         374 : }
    1070             : 
    1071             : 
    1072             : DISABLE_CFI_PERF
    1073           5 : void GlobalHandles::IterateAllRootsInNewSpaceWithClassIds(
    1074             :     v8::PersistentHandleVisitor* visitor) {
    1075          20 :   for (Node* node : new_space_nodes_) {
    1076          10 :     if (node->IsRetainer() && node->has_wrapper_class_id()) {
    1077             :       ApplyPersistentHandleVisitor(visitor, node);
    1078             :     }
    1079             :   }
    1080           5 : }
    1081             : 
    1082             : 
    1083             : DISABLE_CFI_PERF
    1084           0 : void GlobalHandles::IterateWeakRootsInNewSpaceWithClassIds(
    1085             :     v8::PersistentHandleVisitor* visitor) {
    1086           0 :   for (Node* node : new_space_nodes_) {
    1087           0 :     if (node->has_wrapper_class_id() && node->IsWeak()) {
    1088             :       ApplyPersistentHandleVisitor(visitor, node);
    1089             :     }
    1090             :   }
    1091           0 : }
    1092             : 
    1093          15 : void GlobalHandles::RecordStats(HeapStats* stats) {
    1094          15 :   *stats->global_handle_count = 0;
    1095          15 :   *stats->weak_global_handle_count = 0;
    1096          15 :   *stats->pending_global_handle_count = 0;
    1097          15 :   *stats->near_death_global_handle_count = 0;
    1098          15 :   *stats->free_global_handle_count = 0;
    1099          30 :   for (Node* node : *regular_nodes_) {
    1100           0 :     *stats->global_handle_count += 1;
    1101           0 :     if (node->state() == Node::WEAK) {
    1102           0 :       *stats->weak_global_handle_count += 1;
    1103           0 :     } else if (node->state() == Node::PENDING) {
    1104           0 :       *stats->pending_global_handle_count += 1;
    1105           0 :     } else if (node->state() == Node::NEAR_DEATH) {
    1106           0 :       *stats->near_death_global_handle_count += 1;
    1107           0 :     } else if (node->state() == Node::FREE) {
    1108           0 :       *stats->free_global_handle_count += 1;
    1109             :     }
    1110             :   }
    1111          15 : }
    1112             : 
    1113             : #ifdef DEBUG
    1114             : 
    1115             : void GlobalHandles::PrintStats() {
    1116             :   int total = 0;
    1117             :   int weak = 0;
    1118             :   int pending = 0;
    1119             :   int near_death = 0;
    1120             :   int destroyed = 0;
    1121             : 
    1122             :   for (Node* node : *regular_nodes_) {
    1123             :     total++;
    1124             :     if (node->state() == Node::WEAK) weak++;
    1125             :     if (node->state() == Node::PENDING) pending++;
    1126             :     if (node->state() == Node::NEAR_DEATH) near_death++;
    1127             :     if (node->state() == Node::FREE) destroyed++;
    1128             :   }
    1129             : 
    1130             :   PrintF("Global Handle Statistics:\n");
    1131             :   PrintF("  allocated memory = %" PRIuS "B\n", total * sizeof(Node));
    1132             :   PrintF("  # weak       = %d\n", weak);
    1133             :   PrintF("  # pending    = %d\n", pending);
    1134             :   PrintF("  # near_death = %d\n", near_death);
    1135             :   PrintF("  # free       = %d\n", destroyed);
    1136             :   PrintF("  # total      = %d\n", total);
    1137             : }
    1138             : 
    1139             : 
    1140             : void GlobalHandles::Print() {
    1141             :   PrintF("Global handles:\n");
    1142             :   for (Node* node : *regular_nodes_) {
    1143             :     PrintF("  handle %p to %p%s\n", node->location().ToVoidPtr(),
    1144             :            reinterpret_cast<void*>(node->object()->ptr()),
    1145             :            node->IsWeak() ? " (weak)" : "");
    1146             :   }
    1147             : }
    1148             : 
    1149             : #endif
    1150             : 
    1151       62867 : void GlobalHandles::TearDown() {}
    1152             : 
    1153      125766 : EternalHandles::EternalHandles() : size_(0) {}
    1154             : 
    1155       62867 : EternalHandles::~EternalHandles() {
    1156      125819 :   for (Address* block : blocks_) delete[] block;
    1157       62867 : }
    1158             : 
    1159      220764 : void EternalHandles::IterateAllRoots(RootVisitor* visitor) {
    1160      220764 :   int limit = size_;
    1161      441937 :   for (Address* block : blocks_) {
    1162             :     DCHECK_GT(limit, 0);
    1163             :     visitor->VisitRootPointers(Root::kEternalHandles, nullptr,
    1164             :                                FullObjectSlot(block),
    1165        1227 :                                FullObjectSlot(block + Min(limit, kSize)));
    1166         409 :     limit -= kSize;
    1167             :   }
    1168      220764 : }
    1169             : 
    1170       23594 : void EternalHandles::IterateNewSpaceRoots(RootVisitor* visitor) {
    1171       62228 :   for (int index : new_space_indices_) {
    1172             :     visitor->VisitRootPointer(Root::kEternalHandles, nullptr,
    1173       30080 :                               FullObjectSlot(GetLocation(index)));
    1174             :   }
    1175       23594 : }
    1176             : 
    1177      107086 : void EternalHandles::PostGarbageCollectionProcessing() {
    1178             :   size_t last = 0;
    1179      255063 :   for (int index : new_space_indices_) {
    1180       81782 :     if (Heap::InNewSpace(Object(*GetLocation(index)))) {
    1181       40842 :       new_space_indices_[last++] = index;
    1182             :     }
    1183             :   }
    1184             :   DCHECK_LE(last, new_space_indices_.size());
    1185      107086 :   new_space_indices_.resize(last);
    1186      107086 : }
    1187             : 
    1188       20480 : void EternalHandles::Create(Isolate* isolate, Object object, int* index) {
    1189             :   DCHECK_EQ(kInvalidIndex, *index);
    1190       40960 :   if (object == Object()) return;
    1191             :   Object the_hole = ReadOnlyRoots(isolate).the_hole_value();
    1192             :   DCHECK_NE(the_hole, object);
    1193       20480 :   int block = size_ >> kShift;
    1194       20480 :   int offset = size_ & kMask;
    1195             :   // Need to resize.
    1196       20480 :   if (offset == 0) {
    1197          85 :     Address* next_block = new Address[kSize];
    1198             :     MemsetPointer(FullObjectSlot(next_block), the_hole, kSize);
    1199       20565 :     blocks_.push_back(next_block);
    1200             :   }
    1201             :   DCHECK_EQ(the_hole->ptr(), blocks_[block][offset]);
    1202       40960 :   blocks_[block][offset] = object->ptr();
    1203       20480 :   if (Heap::InNewSpace(object)) {
    1204       20475 :     new_space_indices_.push_back(size_);
    1205             :   }
    1206       20480 :   *index = size_++;
    1207             : }
    1208             : 
    1209             : }  // namespace internal
    1210      183867 : }  // namespace v8

Generated by: LCOV version 1.10