LCOV - code coverage report
Current view: top level - src - global-handles.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 434 466 93.1 %
Date: 2019-02-19 Functions: 77 81 95.1 %

          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      107702 : 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       53851 :   NodeBlock(GlobalHandles* global_handles,
      37             :             GlobalHandles::NodeSpace<NodeType>* space,
      38             :             NodeBlock* next) V8_NOEXCEPT : next_(next),
      39             :                                            global_handles_(global_handles),
      40    13839707 :                                            space_(space) {}
      41             : 
      42             :   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    18628355 :       reinterpret_cast<uintptr_t>(node) - sizeof(NodeType) * node->index();
      73    18628355 :   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     6449707 :   return used_nodes_++ == 0;
      82             : }
      83             : 
      84             : template <class NodeType>
      85             : void GlobalHandles::NodeBlock<NodeType>::ListAdd(BlockType** top) {
      86       84845 :   BlockType* old_top = *top;
      87       84845 :   *top = this;
      88       84845 :   next_used_ = old_top;
      89       84845 :   prev_used_ = nullptr;
      90       84845 :   if (old_top != nullptr) {
      91       12661 :     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     6089319 :   return --used_nodes_ == 0;
      99             : }
     100             : 
     101             : template <class NodeType>
     102             : void GlobalHandles::NodeBlock<NodeType>::ListRemove(BlockType** top) {
     103       72540 :   if (next_used_ != nullptr) next_used_->prev_used_ = prev_used_;
     104       72540 :   if (prev_used_ != nullptr) prev_used_->next_used_ = next_used_;
     105       72540 :   if (this == *top) {
     106       69590 :     *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   154219520 :     if (++index_ < kBlockSize) return *this;
     135             :     index_ = 0;
     136      602420 :     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      122098 :       : 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      122068 : GlobalHandles::NodeSpace<NodeType>::~NodeSpace() {
     180      175919 :   auto* block = first_block_;
     181      297987 :   while (block != nullptr) {
     182             :     auto* tmp = block->next();
     183       53851 :     delete block;
     184             :     block = tmp;
     185             :   }
     186      122068 : }
     187             : 
     188             : template <class NodeType>
     189             : NodeType* GlobalHandles::NodeSpace<NodeType>::Acquire(Object object) {
     190    12899342 :   if (first_free_ == nullptr) {
     191     6503558 :     first_block_ = new BlockType(global_handles_, this, first_block_);
     192       53851 :     PutNodesOnFreeList(first_block_);
     193             :   }
     194             :   DCHECK_NOT_NULL(first_free_);
     195     6449706 :   NodeType* node = first_free_;
     196     6449706 :   first_free_ = first_free_->next_free();
     197     6449707 :   node->Acquire(object);
     198             :   BlockType* block = BlockType::From(node);
     199     6449707 :   if (block->IncreaseUsage()) {
     200             :     block->ListAdd(&first_used_block_);
     201             :   }
     202    12899414 :   global_handles_->isolate()->counters()->global_handles()->Increment();
     203     6449707 :   global_handles_->handles_count_++;
     204             :   DCHECK(node->IsInUse());
     205             :   return node;
     206             : }
     207             : 
     208             : template <class NodeType>
     209       53851 : void GlobalHandles::NodeSpace<NodeType>::PutNodesOnFreeList(BlockType* block) {
     210    13785856 :   for (int32_t i = kBlockSize - 1; i >= 0; --i) {
     211    13785856 :     NodeType* node = block->at(i);
     212             :     const uint8_t index = static_cast<uint8_t>(i);
     213             :     DCHECK_EQ(i, index);
     214    13785856 :     node->set_index(index);
     215    13785856 :     node->Free(first_free_);
     216    13785856 :     first_free_ = node;
     217             :   }
     218       53851 : }
     219             : 
     220             : template <class NodeType>
     221     6089319 : void GlobalHandles::NodeSpace<NodeType>::Release(NodeType* node) {
     222     6089319 :   BlockType* block = BlockType::From(node);
     223             :   block->space()->Free(node);
     224     6089319 : }
     225             : 
     226             : template <class NodeType>
     227             : void GlobalHandles::NodeSpace<NodeType>::Free(NodeType* node) {
     228     6089319 :   node->Release(first_free_);
     229     6089319 :   first_free_ = node;
     230             :   BlockType* block = BlockType::From(node);
     231     6089319 :   if (block->DecreaseUsage()) {
     232             :     block->ListRemove(&first_used_block_);
     233             :   }
     234     6089319 :   global_handles_->isolate()->counters()->global_handles()->Decrement();
     235     6089319 :   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    13785686 :     data_.next_free = nullptr;
     255    13785686 :     index_ = 0;
     256             :   }
     257             : #endif
     258             : 
     259             :   void Free(Child* free_list) {
     260             :     ClearFields();
     261             :     AsChild()->MarkAsFree();
     262    19875175 :     data_.next_free = free_list;
     263             :   }
     264             : 
     265     6449707 :   void Acquire(Object object) {
     266             :     DCHECK(!AsChild()->IsInUse());
     267             :     CheckFieldsAreCleared();
     268     6449707 :     object_ = object.ptr();
     269             :     AsChild()->MarkAsUsed();
     270     6449707 :     data_.parameter = nullptr;
     271             :     DCHECK(AsChild()->IsInUse());
     272     6449707 :   }
     273             : 
     274     6089319 :   void Release(Child* free_list) {
     275             :     DCHECK(AsChild()->IsInUse());
     276             :     Free(free_list);
     277             :     DCHECK(!AsChild()->IsInUse());
     278     6089319 :   }
     279             : 
     280             :   Object object() const { return Object(object_); }
     281    21758812 :   FullObjectSlot location() { return FullObjectSlot(&object_); }
     282     6449737 :   Handle<Object> handle() { return Handle<Object>(&object_); }
     283             : 
     284    18628353 :   uint8_t index() const { return index_; }
     285    13785856 :   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          70 :   Child* next_free() {
     294             :     DCHECK(!AsChild()->IsInUse());
     295          70 :     return data_.next_free;
     296             :   }
     297             : 
     298             :   void set_parameter(void* parameter) {
     299             :     DCHECK(AsChild()->IsInUse());
     300     3435414 :     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    33660861 :     object_ = kGlobalHandleZapValue;
     314    33660861 :     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          76 :   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             : 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(NEAR_DEATH == Internals::kNodeStateIsNearDeathValue);
     383             :     STATIC_ASSERT(static_cast<int>(IsIndependent::kShift) ==
     384             :                   Internals::kNodeIsIndependentShift);
     385             :     STATIC_ASSERT(static_cast<int>(IsActive::kShift) ==
     386             :                   Internals::kNodeIsActiveShift);
     387             :     set_in_young_list(false);
     388             :   }
     389             : 
     390             :   void Zap() {
     391             :     DCHECK(IsInUse());
     392             :     // Zap the values for eager trapping.
     393             :     object_ = kGlobalHandleZapValue;
     394             :   }
     395             : 
     396       26931 :   const char* label() const {
     397             :     return state() == NORMAL ? reinterpret_cast<char*>(data_.parameter)
     398     8264629 :                              : nullptr;
     399             :   }
     400             : 
     401             :   // State and flag accessors.
     402             : 
     403             :   State state() const {
     404             :     return NodeState::decode(flags_);
     405             :   }
     406             :   void set_state(State state) {
     407    48582993 :     flags_ = NodeState::update(flags_, state);
     408             :   }
     409             : 
     410             :   bool is_independent() { return IsIndependent::decode(flags_); }
     411    67249902 :   void set_independent(bool v) { flags_ = IsIndependent::update(flags_, v); }
     412             : 
     413             :   bool is_active() {
     414             :     return IsActive::decode(flags_);
     415             :   }
     416             :   void set_active(bool v) {
     417    38241419 :     flags_ = IsActive::update(flags_, v);
     418             :   }
     419             : 
     420             :   bool is_in_young_list() const { return IsInYoungList::decode(flags_); }
     421    37237928 :   void set_in_young_list(bool v) { flags_ = IsInYoungList::update(flags_, v); }
     422             : 
     423             :   WeaknessType weakness_type() const {
     424             :     return NodeWeaknessType::decode(flags_);
     425             :   }
     426             :   void set_weakness_type(WeaknessType weakness_type) {
     427     3435239 :     flags_ = NodeWeaknessType::update(flags_, weakness_type);
     428             :   }
     429             : 
     430          40 :   bool IsNearDeath() const {
     431             :     // Check for PENDING to ensure correct answer when processing callbacks.
     432          40 :     return state() == PENDING || state() == NEAR_DEATH;
     433             :   }
     434             : 
     435    24434384 :   bool IsWeak() const { return state() == WEAK; }
     436             : 
     437     4446523 :   bool IsInUse() const { return state() != FREE; }
     438             : 
     439        7744 :   bool IsPhantomCallback() const {
     440     2993049 :     return weakness_type() == PHANTOM_WEAK ||
     441             :            weakness_type() == PHANTOM_WEAK_2_EMBEDDER_FIELDS;
     442             :   }
     443             : 
     444     2985336 :   bool IsPhantomResetHandle() const {
     445             :     return weakness_type() == PHANTOM_WEAK_RESET_HANDLE;
     446             :   }
     447             : 
     448     2977620 :   bool IsFinalizerHandle() const { return weakness_type() == FINALIZER_WEAK; }
     449             : 
     450             :   bool IsPendingPhantomCallback() const {
     451             :     return state() == PENDING && IsPhantomCallback();
     452             :   }
     453             : 
     454             :   bool IsPendingPhantomResetHandle() const {
     455             :     return state() == PENDING && IsPhantomResetHandle();
     456             :   }
     457             : 
     458          20 :   bool IsPendingFinalizer() const {
     459          40 :     return state() == PENDING && weakness_type() == FINALIZER_WEAK;
     460             :   }
     461             : 
     462             :   bool IsPending() const { return state() == PENDING; }
     463             : 
     464    50655057 :   bool IsRetainer() const {
     465    50655057 :     return state() != FREE &&
     466     2977561 :            !(state() == NEAR_DEATH && weakness_type() != FINALIZER_WEAK);
     467             :   }
     468             : 
     469    36438110 :   bool IsStrongRetainer() const { return state() == NORMAL; }
     470             : 
     471    48002048 :   bool IsWeakRetainer() const {
     472    48600946 :     return state() == WEAK || state() == PENDING ||
     473           0 :            (state() == NEAR_DEATH && weakness_type() == FINALIZER_WEAK);
     474             :   }
     475             : 
     476             :   void MarkPending() {
     477             :     DCHECK(state() == WEAK);
     478             :     set_state(PENDING);
     479             :   }
     480             : 
     481             :   bool has_callback() const { return weak_callback_ != nullptr; }
     482             : 
     483             :   // Accessors for next free node in the free list.
     484     6449637 :   Node* next_free() {
     485             :     DCHECK_EQ(FREE, state());
     486     6449637 :     return data_.next_free;
     487             :   }
     488             : 
     489     3435203 :   void MakeWeak(void* parameter,
     490             :                 WeakCallbackInfo<void>::Callback phantom_callback,
     491             :                 v8::WeakCallbackType type) {
     492             :     DCHECK_NOT_NULL(phantom_callback);
     493             :     DCHECK(IsInUse());
     494     3435203 :     CHECK_NE(object_, kGlobalHandleZapValue);
     495             :     set_state(WEAK);
     496     3435203 :     switch (type) {
     497             :       case v8::WeakCallbackType::kParameter:
     498             :         set_weakness_type(PHANTOM_WEAK);
     499             :         break;
     500             :       case v8::WeakCallbackType::kInternalFields:
     501             :         set_weakness_type(PHANTOM_WEAK_2_EMBEDDER_FIELDS);
     502             :         break;
     503             :       case v8::WeakCallbackType::kFinalizer:
     504             :         set_weakness_type(FINALIZER_WEAK);
     505             :         break;
     506             :     }
     507             :     set_parameter(parameter);
     508     3435203 :     weak_callback_ = phantom_callback;
     509     3435203 :   }
     510             : 
     511          36 :   void MakeWeak(Address** location_addr) {
     512             :     DCHECK(IsInUse());
     513          36 :     CHECK_NE(object_, kGlobalHandleZapValue);
     514             :     set_state(WEAK);
     515             :     set_weakness_type(PHANTOM_WEAK_RESET_HANDLE);
     516             :     set_parameter(location_addr);
     517          36 :     weak_callback_ = nullptr;
     518          36 :   }
     519             : 
     520             :   void* ClearWeakness() {
     521             :     DCHECK(IsInUse());
     522          35 :     void* p = parameter();
     523             :     set_state(NORMAL);
     524             :     set_parameter(nullptr);
     525             :     return p;
     526             :   }
     527             : 
     528             :   void AnnotateStrongRetainer(const char* label) {
     529             :     DCHECK_EQ(state(), NORMAL);
     530     2828921 :     data_.parameter = const_cast<char*>(label);
     531             :   }
     532             : 
     533     2985305 :   void CollectPhantomCallbackData(
     534             :       std::vector<std::pair<Node*, PendingPhantomCallback>>*
     535     2985305 :           pending_phantom_callbacks) {
     536             :     DCHECK(weakness_type() == PHANTOM_WEAK ||
     537             :            weakness_type() == PHANTOM_WEAK_2_EMBEDDER_FIELDS);
     538             :     DCHECK(state() == PENDING);
     539             :     DCHECK_NOT_NULL(weak_callback_);
     540             : 
     541             :     void* embedder_fields[v8::kEmbedderFieldsInWeakCallback] = {nullptr,
     542     2985305 :                                                                 nullptr};
     543     5970627 :     if (weakness_type() != PHANTOM_WEAK && object()->IsJSObject()) {
     544             :       ExtractInternalFields(JSObject::cast(object()), embedder_fields,
     545          17 :                             v8::kEmbedderFieldsInWeakCallback);
     546             :     }
     547             : 
     548             :     // Zap with something dangerous.
     549             :     location().store(Object(0xCA11));
     550             : 
     551             :     pending_phantom_callbacks->push_back(std::make_pair(
     552             :         this,
     553     5970610 :         PendingPhantomCallback(weak_callback_, parameter(), embedder_fields)));
     554             :     DCHECK(IsInUse());
     555             :     set_state(NEAR_DEATH);
     556     2985305 :   }
     557             : 
     558             :   void ResetPhantomHandle() {
     559             :     DCHECK_EQ(PHANTOM_WEAK_RESET_HANDLE, weakness_type());
     560             :     DCHECK_EQ(PENDING, state());
     561             :     DCHECK_NULL(weak_callback_);
     562          31 :     Address** handle = reinterpret_cast<Address**>(parameter());
     563          31 :     *handle = nullptr;
     564          31 :     NodeSpace<Node>::Release(this);
     565             :   }
     566             : 
     567          40 :   void PostGarbageCollectionProcessing(Isolate* isolate) {
     568             :     // This method invokes a finalizer. Updating the method name would require
     569             :     // adjusting CFI blacklist as weak_callback_ is invoked on the wrong type.
     570          20 :     CHECK(IsPendingFinalizer());
     571          20 :     CHECK(!is_active());
     572             :     set_state(NEAR_DEATH);
     573             :     // Check that we are not passing a finalized external string to
     574             :     // the callback.
     575             :     DCHECK(!object()->IsExternalOneByteString() ||
     576             :            ExternalOneByteString::cast(object())->resource() != nullptr);
     577             :     DCHECK(!object()->IsExternalTwoByteString() ||
     578             :            ExternalTwoByteString::cast(object())->resource() != nullptr);
     579             :     // Leaving V8.
     580          20 :     VMState<EXTERNAL> vmstate(isolate);
     581             :     HandleScope handle_scope(isolate);
     582             :     void* embedder_fields[v8::kEmbedderFieldsInWeakCallback] = {nullptr,
     583          20 :                                                                 nullptr};
     584             :     v8::WeakCallbackInfo<void> data(reinterpret_cast<v8::Isolate*>(isolate),
     585          20 :                                     parameter(), embedder_fields, nullptr);
     586          20 :     weak_callback_(data);
     587             :     // For finalizers the handle must have either been reset or made strong.
     588             :     // Both cases reset the state.
     589          40 :     CHECK_NE(NEAR_DEATH, state());
     590          20 :   }
     591             : 
     592             :   void MarkAsFree() { set_state(FREE); }
     593             :   void MarkAsUsed() { set_state(NORMAL); }
     594             : 
     595             :   GlobalHandles* global_handles() {
     596          10 :     return NodeBlock<Node>::From(this)->global_handles();
     597             :   }
     598             : 
     599             :  private:
     600             :   // Fields that are not used for managing node memory.
     601             :   void ClearImplFields() {
     602             :     set_independent(false);
     603             :     set_active(false);
     604    33624951 :     weak_callback_ = nullptr;
     605             :   }
     606             : 
     607             :   void CheckImplFieldsAreCleared() {
     608             :     DCHECK(!is_independent());
     609             :     DCHECK(!is_active());
     610             :     DCHECK_EQ(nullptr, weak_callback_);
     611             :   }
     612             : 
     613             :   // This stores three flags (independent, partially_dependent and
     614             :   // in_young_list) and a State.
     615             :   class NodeState : public BitField8<State, 0, 3> {};
     616             :   class IsIndependent : public BitField8<bool, NodeState::kNext, 1> {};
     617             :   // The following two fields are mutually exclusive
     618             :   class IsActive : public BitField8<bool, IsIndependent::kNext, 1> {};
     619             :   class IsInYoungList : public BitField8<bool, IsActive::kNext, 1> {};
     620             :   class NodeWeaknessType
     621             :       : public BitField8<WeaknessType, IsInYoungList::kNext, 2> {};
     622             : 
     623             :   // Handle specific callback - might be a weak reference in disguise.
     624             :   WeakCallbackInfo<void>::Callback weak_callback_;
     625             : 
     626             :   friend class NodeBase<Node>;
     627             : 
     628             :   DISALLOW_COPY_AND_ASSIGN(Node);
     629             : };
     630             : 
     631             : class GlobalHandles::TracedNode final
     632             :     : public NodeBase<GlobalHandles::TracedNode> {
     633             :  public:
     634             :   TracedNode() { set_in_young_list(false); }
     635             : 
     636             :   enum State { FREE = 0, NORMAL, NEAR_DEATH };
     637             : 
     638             :   State state() const { return NodeState::decode(flags_); }
     639       18150 :   void set_state(State state) { flags_ = NodeState::update(flags_, state); }
     640             : 
     641             :   void MarkAsFree() { set_state(FREE); }
     642             :   void MarkAsUsed() { set_state(NORMAL); }
     643        9091 :   bool IsInUse() const { return state() != FREE; }
     644        3840 :   bool IsRetainer() const { return state() == NORMAL; }
     645             :   bool IsPhantomResetHandle() const { return callback_ == nullptr; }
     646             : 
     647             :   bool is_in_young_list() const { return IsInYoungList::decode(flags_); }
     648       36011 :   void set_in_young_list(bool v) { flags_ = IsInYoungList::update(flags_, v); }
     649             : 
     650             :   bool is_root() const { return IsRoot::decode(flags_); }
     651       71850 :   void set_root(bool v) { flags_ = IsRoot::update(flags_, v); }
     652             : 
     653             :   void SetFinalizationCallback(void* parameter,
     654             :                                WeakCallbackInfo<void>::Callback callback) {
     655             :     set_parameter(parameter);
     656          10 :     callback_ = callback;
     657             :   }
     658             :   bool HasFinalizationCallback() const { return callback_ != nullptr; }
     659             : 
     660          10 :   void CollectPhantomCallbackData(
     661             :       std::vector<std::pair<TracedNode*, PendingPhantomCallback>>*
     662             :           pending_phantom_callbacks) {
     663             :     DCHECK(IsInUse());
     664             :     DCHECK_NOT_NULL(callback_);
     665             : 
     666             :     void* embedder_fields[v8::kEmbedderFieldsInWeakCallback] = {nullptr,
     667          10 :                                                                 nullptr};
     668             :     ExtractInternalFields(JSObject::cast(object()), embedder_fields,
     669          30 :                           v8::kEmbedderFieldsInWeakCallback);
     670             : 
     671             :     // Zap with something dangerous.
     672             :     location().store(Object(0xCA11));
     673             : 
     674             :     pending_phantom_callbacks->push_back(std::make_pair(
     675          20 :         this, PendingPhantomCallback(callback_, parameter(), embedder_fields)));
     676             :     set_state(NEAR_DEATH);
     677          10 :   }
     678             : 
     679             :   void ResetPhantomHandle() {
     680             :     DCHECK(IsInUse());
     681          20 :     Address** handle = reinterpret_cast<Address**>(data_.parameter);
     682          20 :     *handle = nullptr;
     683          20 :     NodeSpace<TracedNode>::Release(this);
     684             :     DCHECK(!IsInUse());
     685             :   }
     686             : 
     687             :  protected:
     688             :   class NodeState : public BitField8<State, 0, 2> {};
     689             :   class IsInYoungList : public BitField8<bool, NodeState::kNext, 1> {};
     690             :   class IsRoot : public BitField8<bool, IsInYoungList::kNext, 1> {};
     691             : 
     692             :   void ClearImplFields() {
     693             :     set_root(true);
     694       35910 :     callback_ = nullptr;
     695             :   }
     696             : 
     697             :   void CheckImplFieldsAreCleared() const {
     698             :     DCHECK(is_root());
     699             :     DCHECK_NULL(callback_);
     700             :   }
     701             : 
     702             :   WeakCallbackInfo<void>::Callback callback_;
     703             : 
     704             :   friend class NodeBase<GlobalHandles::TracedNode>;
     705             : 
     706             :   DISALLOW_COPY_AND_ASSIGN(TracedNode);
     707             : };
     708             : 
     709       61049 : GlobalHandles::GlobalHandles(Isolate* isolate)
     710             :     : isolate_(isolate),
     711             :       regular_nodes_(new NodeSpace<GlobalHandles::Node>(this)),
     712      244196 :       traced_nodes_(new NodeSpace<GlobalHandles::TracedNode>(this)) {}
     713             : 
     714      122068 : GlobalHandles::~GlobalHandles() { regular_nodes_.reset(nullptr); }
     715             : 
     716     6449636 : Handle<Object> GlobalHandles::Create(Object value) {
     717     6449637 :   GlobalHandles::Node* result = regular_nodes_->Acquire(value);
     718     9859703 :   if (ObjectInYoungGeneration(value) && !result->is_in_young_list()) {
     719     3251467 :     young_nodes_.push_back(result);
     720     3251467 :     result->set_in_young_list(true);
     721             :   }
     722    12899274 :   return result->handle();
     723             : }
     724             : 
     725     3049145 : Handle<Object> GlobalHandles::Create(Address value) {
     726     3049155 :   return Create(Object(value));
     727             : }
     728             : 
     729          70 : Handle<Object> GlobalHandles::CreateTraced(Object value, Address* slot) {
     730          70 :   GlobalHandles::TracedNode* result = traced_nodes_->Acquire(value);
     731         140 :   if (ObjectInYoungGeneration(value) && !result->is_in_young_list()) {
     732          70 :     traced_young_nodes_.push_back(result);
     733          70 :     result->set_in_young_list(true);
     734             :   }
     735          70 :   result->set_parameter(slot);
     736          70 :   return result->handle();
     737             : }
     738             : 
     739          70 : Handle<Object> GlobalHandles::CreateTraced(Address value, Address* slot) {
     740          70 :   return CreateTraced(Object(value), slot);
     741             : }
     742             : 
     743          10 : Handle<Object> GlobalHandles::CopyGlobal(Address* location) {
     744             :   DCHECK_NOT_NULL(location);
     745             :   GlobalHandles* global_handles =
     746             :       Node::FromLocation(location)->global_handles();
     747             : #ifdef VERIFY_HEAP
     748             :   if (i::FLAG_verify_heap) {
     749             :     Object(*location)->ObjectVerify(global_handles->isolate());
     750             :   }
     751             : #endif  // VERIFY_HEAP
     752          20 :   return global_handles->Create(*location);
     753             : }
     754             : 
     755        5706 : void GlobalHandles::MoveGlobal(Address** from, Address** to) {
     756             :   DCHECK_NOT_NULL(*from);
     757             :   DCHECK_NOT_NULL(*to);
     758             :   DCHECK_EQ(*from, *to);
     759        5706 :   Node* node = Node::FromLocation(*from);
     760        5711 :   if (node->IsWeak() && node->IsPhantomResetHandle()) {
     761             :     node->set_parameter(to);
     762             :   }
     763             : 
     764             :   // - Strong handles do not require fixups.
     765             :   // - Weak handles with finalizers and callbacks are too general to fix up. For
     766             :   //   those the callers need to ensure consistency.
     767        5706 : }
     768             : 
     769          55 : void GlobalHandles::MoveTracedGlobal(Address** from, Address** to) {
     770             :   DCHECK_NOT_NULL(*from);
     771             :   DCHECK_NOT_NULL(*to);
     772             :   DCHECK_EQ(*from, *to);
     773          55 :   TracedNode* node = TracedNode::FromLocation(*from);
     774             :   // Only set the backpointer for clearing a phantom handle when there is no
     775             :   // finalization callback attached. As soon as a callback is attached to a node
     776             :   // the embedder is on its own when resetting a handle.
     777          55 :   if (!node->HasFinalizationCallback()) {
     778             :     node->set_parameter(to);
     779             :   }
     780          55 : }
     781             : 
     782     6089218 : void GlobalHandles::Destroy(Address* location) {
     783     6089218 :   if (location != nullptr) {
     784     6089218 :     NodeSpace<Node>::Release(Node::FromLocation(location));
     785             :   }
     786     6089218 : }
     787             : 
     788          50 : void GlobalHandles::DestroyTraced(Address* location) {
     789          50 :   if (location != nullptr) {
     790          50 :     NodeSpace<TracedNode>::Release(TracedNode::FromLocation(location));
     791             :   }
     792          50 : }
     793             : 
     794          10 : void GlobalHandles::SetFinalizationCallbackForTraced(
     795             :     Address* location, void* parameter,
     796             :     WeakCallbackInfo<void>::Callback callback) {
     797             :   TracedNode::FromLocation(location)->SetFinalizationCallback(parameter,
     798             :                                                               callback);
     799          10 : }
     800             : 
     801             : typedef v8::WeakCallbackInfo<void>::Callback GenericCallback;
     802             : 
     803     3435203 : void GlobalHandles::MakeWeak(Address* location, void* parameter,
     804             :                              GenericCallback phantom_callback,
     805             :                              v8::WeakCallbackType type) {
     806     3435203 :   Node::FromLocation(location)->MakeWeak(parameter, phantom_callback, type);
     807     3435203 : }
     808             : 
     809          36 : void GlobalHandles::MakeWeak(Address** location_addr) {
     810          36 :   Node::FromLocation(*location_addr)->MakeWeak(location_addr);
     811          36 : }
     812             : 
     813          35 : void* GlobalHandles::ClearWeakness(Address* location) {
     814          35 :   return Node::FromLocation(location)->ClearWeakness();
     815             : }
     816             : 
     817     2828921 : void GlobalHandles::AnnotateStrongRetainer(Address* location,
     818             :                                            const char* label) {
     819             :   Node::FromLocation(location)->AnnotateStrongRetainer(label);
     820     2828921 : }
     821             : 
     822          40 : bool GlobalHandles::IsNearDeath(Address* location) {
     823          40 :   return Node::FromLocation(location)->IsNearDeath();
     824             : }
     825             : 
     826          20 : bool GlobalHandles::IsWeak(Address* location) {
     827          20 :   return Node::FromLocation(location)->IsWeak();
     828             : }
     829             : 
     830             : DISABLE_CFI_PERF
     831       74510 : void GlobalHandles::IterateWeakRootsForFinalizers(RootVisitor* v) {
     832    24150044 :   for (Node* node : *regular_nodes_) {
     833    24001024 :     if (node->IsWeakRetainer() && node->state() == Node::PENDING) {
     834             :       DCHECK(!node->IsPhantomCallback());
     835             :       DCHECK(!node->IsPhantomResetHandle());
     836             :       // Finalizers need to survive.
     837             :       v->VisitRootPointer(Root::kGlobalHandles, node->label(),
     838          40 :                           node->location());
     839             :     }
     840             :   }
     841       74510 : }
     842             : 
     843             : DISABLE_CFI_PERF
     844       74510 : void GlobalHandles::IterateWeakRootsForPhantomHandles(
     845     5164052 :     WeakSlotCallbackWithHeap should_reset_handle) {
     846    24150044 :   for (Node* node : *regular_nodes_) {
     847    29165046 :     if (node->IsWeakRetainer() &&
     848     5164022 :         should_reset_handle(isolate()->heap(), node->location())) {
     849     2977592 :       if (node->IsPhantomResetHandle()) {
     850             :         node->MarkPending();
     851             :         node->ResetPhantomHandle();
     852          31 :         ++number_of_phantom_handle_resets_;
     853     2977561 :       } else if (node->IsPhantomCallback()) {
     854             :         node->MarkPending();
     855     2977561 :         node->CollectPhantomCallbackData(&regular_pending_phantom_callbacks_);
     856             :       }
     857             :     }
     858             :   }
     859      156720 :   for (TracedNode* node : *traced_nodes_) {
     860        7710 :     if (node->IsInUse() &&
     861          30 :         should_reset_handle(isolate()->heap(), node->location())) {
     862          20 :       if (node->IsPhantomResetHandle()) {
     863             :         node->ResetPhantomHandle();
     864          15 :         ++number_of_phantom_handle_resets_;
     865             :       } else {
     866           5 :         node->CollectPhantomCallbackData(&traced_pending_phantom_callbacks_);
     867             :       }
     868             :     }
     869             :   }
     870       74510 : }
     871             : 
     872       74510 : void GlobalHandles::IterateWeakRootsIdentifyFinalizers(
     873     5164022 :     WeakSlotCallbackWithHeap should_reset_handle) {
     874    24150044 :   for (Node* node : *regular_nodes_) {
     875    29165046 :     if (node->IsWeak() &&
     876     5164022 :         should_reset_handle(isolate()->heap(), node->location())) {
     877     2977620 :       if (node->IsFinalizerHandle()) {
     878             :         node->MarkPending();
     879             :       }
     880             :     }
     881             :   }
     882       74510 : }
     883             : 
     884       23490 : void GlobalHandles::IdentifyWeakUnmodifiedObjects(
     885       23490 :     WeakSlotCallback is_unmodified) {
     886      372706 :   for (Node* node : young_nodes_) {
     887      464026 :     if (node->IsWeak() && !is_unmodified(node->location())) {
     888             :       node->set_active(true);
     889             :     }
     890             :   }
     891             : 
     892             :   LocalEmbedderHeapTracer* const tracer =
     893             :       isolate()->heap()->local_embedder_heap_tracer();
     894       47005 :   for (TracedNode* node : traced_young_nodes_) {
     895          25 :     if (node->IsInUse()) {
     896             :       DCHECK(node->is_root());
     897          25 :       if (is_unmodified(node->location())) {
     898          15 :         v8::Value* value = ToApi<v8::Value>(node->handle());
     899             :         node->set_root(tracer->IsRootForNonTracingGC(
     900             :             *reinterpret_cast<v8::TracedGlobal<v8::Value>*>(&value)));
     901             :       }
     902             :     }
     903             :   }
     904       23490 : }
     905             : 
     906       23490 : void GlobalHandles::IterateYoungStrongAndDependentRoots(RootVisitor* v) {
     907      372706 :   for (Node* node : young_nodes_) {
     908      806148 :     if (node->IsStrongRetainer() ||
     909      241961 :         (node->IsWeakRetainer() && !node->is_independent() &&
     910             :          node->is_active())) {
     911             :       v->VisitRootPointer(Root::kGlobalHandles, node->label(),
     912      549310 :                           node->location());
     913             :     }
     914             :   }
     915       47005 :   for (TracedNode* node : traced_young_nodes_) {
     916          50 :     if (node->IsInUse() && node->is_root()) {
     917          30 :       v->VisitRootPointer(Root::kGlobalHandles, nullptr, node->location());
     918             :     }
     919             :   }
     920       23490 : }
     921             : 
     922       23490 : void GlobalHandles::MarkYoungWeakUnmodifiedObjectsPending(
     923             :     WeakSlotCallbackWithHeap is_dead) {
     924      372706 :   for (Node* node : young_nodes_) {
     925             :     DCHECK(node->is_in_young_list());
     926      873589 :     if ((node->is_independent() || !node->is_active()) && node->IsWeak() &&
     927       34675 :         is_dead(isolate_->heap(), node->location())) {
     928        7744 :       if (!node->IsPhantomCallback() && !node->IsPhantomResetHandle()) {
     929             :         node->MarkPending();
     930             :       }
     931             :     }
     932             :   }
     933       23490 : }
     934             : 
     935       23490 : void GlobalHandles::IterateYoungWeakUnmodifiedRootsForFinalizers(
     936             :     RootVisitor* v) {
     937      372706 :   for (Node* node : young_nodes_) {
     938             :     DCHECK(node->is_in_young_list());
     939      838914 :     if ((node->is_independent() || !node->is_active()) &&
     940      360401 :         node->IsWeakRetainer() && (node->state() == Node::PENDING)) {
     941             :       DCHECK(!node->IsPhantomCallback());
     942             :       DCHECK(!node->IsPhantomResetHandle());
     943             :       // Finalizers need to survive.
     944             :       v->VisitRootPointer(Root::kGlobalHandles, node->label(),
     945           0 :                           node->location());
     946             :     }
     947             :   }
     948       23490 : }
     949             : 
     950       23490 : void GlobalHandles::IterateYoungWeakUnmodifiedRootsForPhantomHandles(
     951             :     RootVisitor* v, WeakSlotCallbackWithHeap should_reset_handle) {
     952      372706 :   for (Node* node : young_nodes_) {
     953             :     DCHECK(node->is_in_young_list());
     954      838914 :     if ((node->is_independent() || !node->is_active()) &&
     955      360401 :         node->IsWeakRetainer() && (node->state() != Node::PENDING)) {
     956       34675 :       if (should_reset_handle(isolate_->heap(), node->location())) {
     957             :         DCHECK(node->IsPhantomResetHandle() || node->IsPhantomCallback());
     958        7744 :         if (node->IsPhantomResetHandle()) {
     959             :           node->MarkPending();
     960             :           node->ResetPhantomHandle();
     961           0 :           ++number_of_phantom_handle_resets_;
     962        7744 :         } else if (node->IsPhantomCallback()) {
     963             :           node->MarkPending();
     964        7744 :           node->CollectPhantomCallbackData(&regular_pending_phantom_callbacks_);
     965             :         } else {
     966           0 :           UNREACHABLE();
     967             :         }
     968             :       } else {
     969             :         // Node survived and needs to be visited.
     970             :         v->VisitRootPointer(Root::kGlobalHandles, node->label(),
     971       53862 :                             node->location());
     972             :       }
     973             :     }
     974             :   }
     975       47030 :   for (TracedNode* node : traced_young_nodes_) {
     976          25 :     if (!node->IsInUse()) continue;
     977             : 
     978             :     DCHECK_IMPLIES(node->is_root(),
     979             :                    !should_reset_handle(isolate_->heap(), node->location()));
     980          25 :     if (should_reset_handle(isolate_->heap(), node->location())) {
     981          10 :       if (node->IsPhantomResetHandle()) {
     982             :         node->ResetPhantomHandle();
     983           5 :         ++number_of_phantom_handle_resets_;
     984             :       } else {
     985           5 :         node->CollectPhantomCallbackData(&traced_pending_phantom_callbacks_);
     986             :       }
     987             :     } else {
     988          15 :       if (!node->is_root()) {
     989             :         node->set_root(true);
     990           0 :         v->VisitRootPointer(Root::kGlobalHandles, nullptr, node->location());
     991             :       }
     992             :     }
     993             :   }
     994       23490 : }
     995             : 
     996        1998 : void GlobalHandles::InvokeSecondPassPhantomCallbacksFromTask() {
     997             :   DCHECK(second_pass_callbacks_task_posted_);
     998         666 :   second_pass_callbacks_task_posted_ = false;
     999        1332 :   TRACE_EVENT0("v8", "V8.GCPhantomHandleProcessingCallback");
    1000             :   isolate()->heap()->CallGCPrologueCallbacks(
    1001         666 :       GCType::kGCTypeProcessWeakCallbacks, kNoGCCallbackFlags);
    1002         666 :   InvokeSecondPassPhantomCallbacks();
    1003             :   isolate()->heap()->CallGCEpilogueCallbacks(
    1004         666 :       GCType::kGCTypeProcessWeakCallbacks, kNoGCCallbackFlags);
    1005         666 : }
    1006             : 
    1007     2734013 : void GlobalHandles::InvokeSecondPassPhantomCallbacks() {
    1008     2840814 :   while (!second_pass_callbacks_.empty()) {
    1009     2627212 :     auto callback = second_pass_callbacks_.back();
    1010             :     second_pass_callbacks_.pop_back();
    1011     2627212 :     callback.Invoke(isolate(), PendingPhantomCallback::kSecondPass);
    1012             :   }
    1013      106801 : }
    1014             : 
    1015       23490 : size_t GlobalHandles::PostScavengeProcessing(unsigned post_processing_count) {
    1016             :   size_t freed_nodes = 0;
    1017      372706 :   for (Node* node : young_nodes_) {
    1018             :     // Filter free nodes.
    1019      325726 :     if (!node->IsRetainer()) continue;
    1020             : 
    1021             :     // Reset active state for all affected nodes.
    1022             :     node->set_active(false);
    1023             : 
    1024      301586 :     if (node->IsPending()) {
    1025             :       DCHECK(node->has_callback());
    1026             :       DCHECK(node->IsPendingFinalizer());
    1027           0 :       node->PostGarbageCollectionProcessing(isolate_);
    1028             :     }
    1029      301586 :     if (InRecursiveGC(post_processing_count)) return freed_nodes;
    1030             : 
    1031      301586 :     if (!node->IsRetainer()) freed_nodes++;
    1032             :   }
    1033             :   return freed_nodes;
    1034             : }
    1035             : 
    1036       74510 : size_t GlobalHandles::PostMarkSweepProcessing(unsigned post_processing_count) {
    1037             :   size_t freed_nodes = 0;
    1038    21697820 :   for (Node* node : *regular_nodes_) {
    1039             :     // Filter free nodes.
    1040    21548800 :     if (!node->IsRetainer()) continue;
    1041             : 
    1042             :     // Reset active state for all affected nodes.
    1043             :     node->set_active(false);
    1044             : 
    1045     4038364 :     if (node->IsPending()) {
    1046             :       DCHECK(node->has_callback());
    1047             :       DCHECK(node->IsPendingFinalizer());
    1048          20 :       node->PostGarbageCollectionProcessing(isolate_);
    1049             :     }
    1050     4038364 :     if (InRecursiveGC(post_processing_count)) return freed_nodes;
    1051             : 
    1052     4038364 :     if (!node->IsRetainer()) freed_nodes++;
    1053             :   }
    1054       74510 :   return freed_nodes;
    1055             : }
    1056             : 
    1057             : template <typename T>
    1058      196000 : void GlobalHandles::UpdateAndCompactListOfYoungNode(
    1059     1557350 :     std::vector<T*>* node_list) {
    1060             :   size_t last = 0;
    1061     4838579 :   for (T* node : *node_list) {
    1062             :     DCHECK(node->is_in_young_list());
    1063     4446579 :     if (node->IsInUse()) {
    1064     1867274 :       if (ObjectInYoungGeneration(node->object())) {
    1065     3114700 :         (*node_list)[last++] = node;
    1066     1557350 :         isolate_->heap()->IncrementNodesCopiedInNewSpace();
    1067             :       } else {
    1068             :         node->set_in_young_list(false);
    1069      309924 :         isolate_->heap()->IncrementNodesPromoted();
    1070             :       }
    1071             :     } else {
    1072             :       node->set_in_young_list(false);
    1073     2579305 :       isolate_->heap()->IncrementNodesDiedInNewSpace();
    1074             :     }
    1075             :   }
    1076             :   DCHECK_LE(last, node_list->size());
    1077      196000 :   node_list->resize(last);
    1078             :   node_list->shrink_to_fit();
    1079      196000 : }
    1080             : 
    1081       98000 : void GlobalHandles::UpdateListOfYoungNodes() {
    1082       98000 :   UpdateAndCompactListOfYoungNode(&young_nodes_);
    1083       98000 :   UpdateAndCompactListOfYoungNode(&traced_young_nodes_);
    1084       98000 : }
    1085             : 
    1086             : template <typename T>
    1087      196000 : size_t GlobalHandles::InvokeFirstPassWeakCallbacks(
    1088     2985315 :     std::vector<std::pair<T*, PendingPhantomCallback>>* pending) {
    1089             :   size_t freed_nodes = 0;
    1090             :   std::vector<std::pair<T*, PendingPhantomCallback>> pending_phantom_callbacks;
    1091             :   pending_phantom_callbacks.swap(*pending);
    1092             :   {
    1093             :     // The initial pass callbacks must simply clear the nodes.
    1094     3377315 :     for (auto& pair : pending_phantom_callbacks) {
    1095     5970630 :       T* node = pair.first;
    1096             :       DCHECK_EQ(T::NEAR_DEATH, node->state());
    1097     5970630 :       pair.second.Invoke(isolate(), PendingPhantomCallback::kFirstPass);
    1098             : 
    1099             :       // Transition to second pass. It is required that the first pass callback
    1100             :       // resets the handle using |v8::PersistentBase::Reset|. Also see comments
    1101             :       // on |v8::WeakCallbackInfo|.
    1102     2985315 :       CHECK_WITH_MSG(T::FREE == node->state(),
    1103             :                      "Handle not reset in first callback. See comments on "
    1104             :                      "|v8::WeakCallbackInfo|.");
    1105             : 
    1106     2985315 :       if (pair.second.callback()) second_pass_callbacks_.push_back(pair.second);
    1107     2985315 :       freed_nodes++;
    1108             :     }
    1109             :   }
    1110      196000 :   return freed_nodes;
    1111             : }
    1112             : 
    1113       98000 : size_t GlobalHandles::InvokeFirstPassWeakCallbacks() {
    1114       98000 :   return InvokeFirstPassWeakCallbacks(&regular_pending_phantom_callbacks_) +
    1115       98000 :          InvokeFirstPassWeakCallbacks(&traced_pending_phantom_callbacks_);
    1116             : }
    1117             : 
    1118       98000 : void GlobalHandles::InvokeOrScheduleSecondPassPhantomCallbacks(
    1119       17602 :     bool synchronous_second_pass) {
    1120       98000 :   if (!second_pass_callbacks_.empty()) {
    1121        9076 :     if (FLAG_optimize_for_size || FLAG_predictable || synchronous_second_pass) {
    1122             :       isolate()->heap()->CallGCPrologueCallbacks(
    1123        8135 :           GCType::kGCTypeProcessWeakCallbacks, kNoGCCallbackFlags);
    1124        8135 :       InvokeSecondPassPhantomCallbacks();
    1125             :       isolate()->heap()->CallGCEpilogueCallbacks(
    1126        8135 :           GCType::kGCTypeProcessWeakCallbacks, kNoGCCallbackFlags);
    1127         941 :     } else if (!second_pass_callbacks_task_posted_) {
    1128         666 :       second_pass_callbacks_task_posted_ = true;
    1129         666 :       auto taskrunner = V8::GetCurrentPlatform()->GetForegroundTaskRunner(
    1130        1332 :           reinterpret_cast<v8::Isolate*>(isolate()));
    1131         666 :       taskrunner->PostTask(MakeCancelableTask(
    1132        4662 :           isolate(), [this] { InvokeSecondPassPhantomCallbacksFromTask(); }));
    1133             :     }
    1134             :   }
    1135       98000 : }
    1136             : 
    1137     5612527 : void GlobalHandles::PendingPhantomCallback::Invoke(Isolate* isolate,
    1138             :                                                    InvocationType type) {
    1139             :   Data::Callback* callback_addr = nullptr;
    1140     5612527 :   if (type == kFirstPass) {
    1141     2985315 :     callback_addr = &callback_;
    1142             :   }
    1143             :   Data data(reinterpret_cast<v8::Isolate*>(isolate), parameter_,
    1144     5612527 :             embedder_fields_, callback_addr);
    1145     5612527 :   Data::Callback callback = callback_;
    1146     5612527 :   callback_ = nullptr;
    1147     5612527 :   callback(data);
    1148     5612527 : }
    1149             : 
    1150           0 : bool GlobalHandles::InRecursiveGC(unsigned gc_processing_counter) {
    1151     4535950 :   return gc_processing_counter != post_gc_processing_count_;
    1152             : }
    1153             : 
    1154       98000 : size_t GlobalHandles::PostGarbageCollectionProcessing(
    1155             :     GarbageCollector collector, const v8::GCCallbackFlags gc_callback_flags) {
    1156             :   // Process weak global handle callbacks. This must be done after the
    1157             :   // GC is completely done, because the callbacks may invoke arbitrary
    1158             :   // API functions.
    1159             :   DCHECK_EQ(Heap::NOT_IN_GC, isolate_->heap()->gc_state());
    1160       98000 :   const unsigned post_processing_count = ++post_gc_processing_count_;
    1161             :   size_t freed_nodes = 0;
    1162             :   bool synchronous_second_pass =
    1163      196000 :       isolate_->heap()->IsTearingDown() ||
    1164       98000 :       (gc_callback_flags &
    1165             :        (kGCCallbackFlagForced | kGCCallbackFlagCollectAllAvailableGarbage |
    1166             :         kGCCallbackFlagSynchronousPhantomCallbackProcessing)) != 0;
    1167       98000 :   InvokeOrScheduleSecondPassPhantomCallbacks(synchronous_second_pass);
    1168       98000 :   if (InRecursiveGC(post_processing_count)) return freed_nodes;
    1169             : 
    1170             :   freed_nodes += Heap::IsYoungGenerationCollector(collector)
    1171             :                      ? PostScavengeProcessing(post_processing_count)
    1172       98000 :                      : PostMarkSweepProcessing(post_processing_count);
    1173       98000 :   if (InRecursiveGC(post_processing_count)) return freed_nodes;
    1174             : 
    1175       98000 :   UpdateListOfYoungNodes();
    1176       98000 :   return freed_nodes;
    1177             : }
    1178             : 
    1179      120298 : void GlobalHandles::IterateStrongRoots(RootVisitor* v) {
    1180    36352980 :   for (Node* node : *regular_nodes_) {
    1181    36112384 :     if (node->IsStrongRetainer()) {
    1182             :       v->VisitRootPointer(Root::kGlobalHandles, node->label(),
    1183     7756298 :                           node->location());
    1184             :     }
    1185             :   }
    1186      120298 : }
    1187             : 
    1188         398 : void GlobalHandles::IterateWeakRoots(RootVisitor* v) {
    1189      102684 :   for (Node* node : *regular_nodes_) {
    1190      101888 :     if (node->IsWeak()) {
    1191             :       v->VisitRootPointer(Root::kGlobalHandles, node->label(),
    1192          60 :                           node->location());
    1193             :     }
    1194             :   }
    1195         796 :   for (TracedNode* node : *traced_nodes_) {
    1196           0 :     if (node->IsInUse()) {
    1197           0 :       v->VisitRootPointer(Root::kGlobalHandles, nullptr, node->location());
    1198             :     }
    1199             :   }
    1200         398 : }
    1201             : 
    1202             : DISABLE_CFI_PERF
    1203       76389 : void GlobalHandles::IterateAllRoots(RootVisitor* v) {
    1204    24590794 :   for (Node* node : *regular_nodes_) {
    1205    24438016 :     if (node->IsRetainer()) {
    1206             :       v->VisitRootPointer(Root::kGlobalHandles, node->label(),
    1207     8169688 :                           node->location());
    1208             :     }
    1209             :   }
    1210      156618 :   for (TracedNode* node : *traced_nodes_) {
    1211        3840 :     if (node->IsRetainer()) {
    1212          20 :       v->VisitRootPointer(Root::kGlobalHandles, nullptr, node->location());
    1213             :     }
    1214             :   }
    1215       76389 : }
    1216             : 
    1217             : DISABLE_CFI_PERF
    1218           0 : void GlobalHandles::IterateAllYoungRoots(RootVisitor* v) {
    1219           0 :   for (Node* node : young_nodes_) {
    1220           0 :     if (node->IsRetainer()) {
    1221             :       v->VisitRootPointer(Root::kGlobalHandles, node->label(),
    1222           0 :                           node->location());
    1223             :     }
    1224             :   }
    1225           0 :   for (TracedNode* node : traced_young_nodes_) {
    1226           0 :     if (node->IsRetainer()) {
    1227           0 :       v->VisitRootPointer(Root::kGlobalHandles, nullptr, node->location());
    1228             :     }
    1229             :   }
    1230           0 : }
    1231             : 
    1232             : DISABLE_CFI_PERF
    1233           0 : void GlobalHandles::ApplyPersistentHandleVisitor(
    1234             :     v8::PersistentHandleVisitor* visitor, GlobalHandles::Node* node) {
    1235          50 :   v8::Value* value = ToApi<v8::Value>(node->handle());
    1236             :   visitor->VisitPersistentHandle(
    1237             :       reinterpret_cast<v8::Persistent<v8::Value>*>(&value),
    1238          50 :       node->wrapper_class_id());
    1239           0 : }
    1240             : 
    1241             : DISABLE_CFI_PERF
    1242          10 : void GlobalHandles::IterateAllRootsWithClassIds(
    1243             :     v8::PersistentHandleVisitor* visitor) {
    1244        2580 :   for (Node* node : *regular_nodes_) {
    1245        2560 :     if (node->IsRetainer() && node->has_wrapper_class_id()) {
    1246             :       ApplyPersistentHandleVisitor(visitor, node);
    1247             :     }
    1248             :   }
    1249          10 : }
    1250             : 
    1251             : DISABLE_CFI_PERF
    1252           5 : void GlobalHandles::IterateTracedNodes(
    1253             :     v8::EmbedderHeapTracer::TracedGlobalHandleVisitor* visitor) {
    1254        1290 :   for (TracedNode* node : *traced_nodes_) {
    1255        1280 :     if (node->IsInUse()) {
    1256           5 :       v8::Value* value = ToApi<v8::Value>(node->handle());
    1257             :       visitor->VisitTracedGlobalHandle(
    1258           5 :           *reinterpret_cast<v8::TracedGlobal<v8::Value>*>(&value));
    1259             :     }
    1260             :   }
    1261           5 : }
    1262             : 
    1263             : DISABLE_CFI_PERF
    1264           5 : void GlobalHandles::IterateAllYoungRootsWithClassIds(
    1265             :     v8::PersistentHandleVisitor* visitor) {
    1266          15 :   for (Node* node : young_nodes_) {
    1267           5 :     if (node->IsRetainer() && node->has_wrapper_class_id()) {
    1268             :       ApplyPersistentHandleVisitor(visitor, node);
    1269             :     }
    1270             :   }
    1271           5 : }
    1272             : 
    1273             : DISABLE_CFI_PERF
    1274           0 : void GlobalHandles::IterateYoungWeakRootsWithClassIds(
    1275             :     v8::PersistentHandleVisitor* visitor) {
    1276           0 :   for (Node* node : young_nodes_) {
    1277           0 :     if (node->has_wrapper_class_id() && node->IsWeak()) {
    1278             :       ApplyPersistentHandleVisitor(visitor, node);
    1279             :     }
    1280             :   }
    1281           0 : }
    1282             : 
    1283          15 : void GlobalHandles::RecordStats(HeapStats* stats) {
    1284          15 :   *stats->global_handle_count = 0;
    1285          15 :   *stats->weak_global_handle_count = 0;
    1286          15 :   *stats->pending_global_handle_count = 0;
    1287          15 :   *stats->near_death_global_handle_count = 0;
    1288          15 :   *stats->free_global_handle_count = 0;
    1289          30 :   for (Node* node : *regular_nodes_) {
    1290           0 :     *stats->global_handle_count += 1;
    1291           0 :     if (node->state() == Node::WEAK) {
    1292           0 :       *stats->weak_global_handle_count += 1;
    1293           0 :     } else if (node->state() == Node::PENDING) {
    1294           0 :       *stats->pending_global_handle_count += 1;
    1295           0 :     } else if (node->state() == Node::NEAR_DEATH) {
    1296           0 :       *stats->near_death_global_handle_count += 1;
    1297           0 :     } else if (node->state() == Node::FREE) {
    1298           0 :       *stats->free_global_handle_count += 1;
    1299             :     }
    1300             :   }
    1301          15 : }
    1302             : 
    1303             : #ifdef DEBUG
    1304             : 
    1305             : void GlobalHandles::PrintStats() {
    1306             :   int total = 0;
    1307             :   int weak = 0;
    1308             :   int pending = 0;
    1309             :   int near_death = 0;
    1310             :   int destroyed = 0;
    1311             : 
    1312             :   for (Node* node : *regular_nodes_) {
    1313             :     total++;
    1314             :     if (node->state() == Node::WEAK) weak++;
    1315             :     if (node->state() == Node::PENDING) pending++;
    1316             :     if (node->state() == Node::NEAR_DEATH) near_death++;
    1317             :     if (node->state() == Node::FREE) destroyed++;
    1318             :   }
    1319             : 
    1320             :   PrintF("Global Handle Statistics:\n");
    1321             :   PrintF("  allocated memory = %" PRIuS "B\n", total * sizeof(Node));
    1322             :   PrintF("  # weak       = %d\n", weak);
    1323             :   PrintF("  # pending    = %d\n", pending);
    1324             :   PrintF("  # near_death = %d\n", near_death);
    1325             :   PrintF("  # free       = %d\n", destroyed);
    1326             :   PrintF("  # total      = %d\n", total);
    1327             : }
    1328             : 
    1329             : 
    1330             : void GlobalHandles::Print() {
    1331             :   PrintF("Global handles:\n");
    1332             :   for (Node* node : *regular_nodes_) {
    1333             :     PrintF("  handle %p to %p%s\n", node->location().ToVoidPtr(),
    1334             :            reinterpret_cast<void*>(node->object()->ptr()),
    1335             :            node->IsWeak() ? " (weak)" : "");
    1336             :   }
    1337             : }
    1338             : 
    1339             : #endif
    1340             : 
    1341       61034 : EternalHandles::~EternalHandles() {
    1342      122153 :   for (Address* block : blocks_) delete[] block;
    1343       61034 : }
    1344             : 
    1345      196289 : void EternalHandles::IterateAllRoots(RootVisitor* visitor) {
    1346      196289 :   int limit = size_;
    1347      392955 :   for (Address* block : blocks_) {
    1348             :     DCHECK_GT(limit, 0);
    1349             :     visitor->VisitRootPointers(Root::kEternalHandles, nullptr,
    1350             :                                FullObjectSlot(block),
    1351        1131 :                                FullObjectSlot(block + Min(limit, kSize)));
    1352         377 :     limit -= kSize;
    1353             :   }
    1354      196289 : }
    1355             : 
    1356       23490 : void EternalHandles::IterateYoungRoots(RootVisitor* visitor) {
    1357       62028 :   for (int index : young_node_indices_) {
    1358             :     visitor->VisitRootPointer(Root::kEternalHandles, nullptr,
    1359       30096 :                               FullObjectSlot(GetLocation(index)));
    1360             :   }
    1361       23490 : }
    1362             : 
    1363       98000 : void EternalHandles::PostGarbageCollectionProcessing() {
    1364             :   size_t last = 0;
    1365      236890 :   for (int index : young_node_indices_) {
    1366       81780 :     if (ObjectInYoungGeneration(Object(*GetLocation(index)))) {
    1367       40840 :       young_node_indices_[last++] = index;
    1368             :     }
    1369             :   }
    1370             :   DCHECK_LE(last, young_node_indices_.size());
    1371       98000 :   young_node_indices_.resize(last);
    1372       98000 : }
    1373             : 
    1374       20480 : void EternalHandles::Create(Isolate* isolate, Object object, int* index) {
    1375             :   DCHECK_EQ(kInvalidIndex, *index);
    1376       40960 :   if (object == Object()) return;
    1377             :   Object the_hole = ReadOnlyRoots(isolate).the_hole_value();
    1378             :   DCHECK_NE(the_hole, object);
    1379       20480 :   int block = size_ >> kShift;
    1380       20480 :   int offset = size_ & kMask;
    1381             :   // Need to resize.
    1382       20480 :   if (offset == 0) {
    1383          85 :     Address* next_block = new Address[kSize];
    1384             :     MemsetPointer(FullObjectSlot(next_block), the_hole, kSize);
    1385       20565 :     blocks_.push_back(next_block);
    1386             :   }
    1387             :   DCHECK_EQ(the_hole->ptr(), blocks_[block][offset]);
    1388       40960 :   blocks_[block][offset] = object->ptr();
    1389       20480 :   if (ObjectInYoungGeneration(object)) {
    1390       20475 :     young_node_indices_.push_back(size_);
    1391             :   }
    1392       20480 :   *index = size_++;
    1393             : }
    1394             : 
    1395             : }  // namespace internal
    1396      178779 : }  // namespace v8

Generated by: LCOV version 1.10