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