LCOV - code coverage report
Current view: top level - src - global-handles.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 331 392 84.4 %
Date: 2017-04-26 Functions: 48 59 81.4 %

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

Generated by: LCOV version 1.10