1// Copyright 2011 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#ifndef V8_HANDLES_GLOBAL_HANDLES_H_
6#define V8_HANDLES_GLOBAL_HANDLES_H_
7
8#include <memory>
9#include <type_traits>
10#include <utility>
11#include <vector>
12
13#include "include/v8-callbacks.h"
14#include "include/v8-persistent-handle.h"
15#include "include/v8-profiler.h"
16#include "include/v8-traced-handle.h"
17#include "src/handles/handles.h"
18#include "src/heap/heap.h"
19#include "src/objects/heap-object.h"
20#include "src/objects/objects.h"
21#include "src/utils/utils.h"
22
23namespace v8 {
24namespace internal {
25
26class HeapStats;
27class RootVisitor;
28
29enum WeaknessType {
30  // Embedder gets a handle to the dying object.
31  FINALIZER_WEAK,
32  // In the following cases, the embedder gets the parameter they passed in
33  // earlier, and 0 or 2 first embedder fields. Note that the internal
34  // fields must contain aligned non-V8 pointers.  Getting pointers to V8
35  // objects through this interface would be GC unsafe so in that case the
36  // embedder gets a null pointer instead.
37  PHANTOM_WEAK,
38  PHANTOM_WEAK_2_EMBEDDER_FIELDS,
39  // The handle is automatically reset by the garbage collector when
40  // the object is no longer reachable.
41  PHANTOM_WEAK_RESET_HANDLE
42};
43
44// Global handles hold handles that are independent of stack-state and can have
45// callbacks and finalizers attached to them.
46class V8_EXPORT_PRIVATE GlobalHandles final {
47 public:
48  static void EnableMarkingBarrier(Isolate*);
49  static void DisableMarkingBarrier(Isolate*);
50
51  GlobalHandles(const GlobalHandles&) = delete;
52  GlobalHandles& operator=(const GlobalHandles&) = delete;
53
54  template <class NodeType>
55  class NodeBlock;
56
57  //
58  // API for regular handles.
59  //
60
61  static void MoveGlobal(Address** from, Address** to);
62
63  static Handle<Object> CopyGlobal(Address* location);
64
65  static void Destroy(Address* location);
66
67  // Make the global handle weak and set the callback parameter for the
68  // handle.  When the garbage collector recognizes that only weak global
69  // handles point to an object the callback function is invoked (for each
70  // handle) with the handle and corresponding parameter as arguments.  By
71  // default the handle still contains a pointer to the object that is being
72  // collected.  For this reason the object is not collected until the next
73  // GC.  For a phantom weak handle the handle is cleared (set to a Smi)
74  // before the callback is invoked, but the handle can still be identified
75  // in the callback by using the location() of the handle.
76  static void MakeWeak(Address* location, void* parameter,
77                       WeakCallbackInfo<void>::Callback weak_callback,
78                       v8::WeakCallbackType type);
79  static void MakeWeak(Address** location_addr);
80
81  static void AnnotateStrongRetainer(Address* location, const char* label);
82
83  // Clear the weakness of a global handle.
84  static void* ClearWeakness(Address* location);
85
86  // Tells whether global handle is weak.
87  static bool IsWeak(Address* location);
88
89  //
90  // API for traced handles.
91  //
92
93  static void MoveTracedReference(Address** from, Address** to);
94  static void CopyTracedReference(const Address* const* from, Address** to);
95  static void DestroyTracedReference(Address* location);
96  static void MarkTraced(Address* location);
97
98  explicit GlobalHandles(Isolate* isolate);
99  ~GlobalHandles();
100
101  // Creates a new global handle that is alive until Destroy is called.
102  Handle<Object> Create(Object value);
103  Handle<Object> Create(Address value);
104
105  template <typename T>
106  inline Handle<T> Create(T value);
107
108  Handle<Object> CreateTraced(Object value, Address* slot,
109                              GlobalHandleStoreMode store_mode,
110                              bool is_on_stack);
111  Handle<Object> CreateTraced(Object value, Address* slot,
112                              GlobalHandleStoreMode store_mode);
113  Handle<Object> CreateTraced(Address value, Address* slot,
114                              GlobalHandleStoreMode store_mode);
115
116  void RecordStats(HeapStats* stats);
117
118  size_t InvokeFirstPassWeakCallbacks();
119  void InvokeSecondPassPhantomCallbacks();
120
121  // Process pending weak handles.
122  // Returns the number of freed nodes.
123  size_t PostGarbageCollectionProcessing(
124      GarbageCollector collector, const v8::GCCallbackFlags gc_callback_flags);
125
126  void IterateStrongRoots(RootVisitor* v);
127  void IterateStrongStackRoots(RootVisitor* v);
128  void IterateWeakRoots(RootVisitor* v);
129  void IterateAllRoots(RootVisitor* v);
130  void IterateAllYoungRoots(RootVisitor* v);
131
132  // Iterates over all handles that have embedder-assigned class ID.
133  void IterateAllRootsWithClassIds(v8::PersistentHandleVisitor* v);
134
135  // Iterates over all handles in the new space that have embedder-assigned
136  // class ID.
137  void IterateAllYoungRootsWithClassIds(v8::PersistentHandleVisitor* v);
138
139  // Iterate over all handles in the new space that are weak, unmodified
140  // and have class IDs
141  void IterateYoungWeakRootsWithClassIds(v8::PersistentHandleVisitor* v);
142
143  // Iterates over all traces handles represented by TracedGlobal.
144  void IterateTracedNodes(
145      v8::EmbedderHeapTracer::TracedGlobalHandleVisitor* visitor);
146
147  // Marks handles with finalizers on the predicate |should_reset_handle| as
148  // pending.
149  void IterateWeakRootsIdentifyFinalizers(
150      WeakSlotCallbackWithHeap should_reset_handle);
151  // Uses the provided visitor |v| to mark handles with finalizers that are
152  // pending.
153  void IterateWeakRootsForFinalizers(RootVisitor* v);
154  // Marks handles that are phantom or have callbacks based on the predicate
155  // |should_reset_handle| as pending.
156  void IterateWeakRootsForPhantomHandles(
157      WeakSlotCallbackWithHeap should_reset_handle);
158
159  //  Note: The following *Young* methods are used for the Scavenger to
160  //  identify and process handles in the young generation. The set of young
161  //  handles is complete but the methods may encounter handles that are
162  //  already in old space.
163
164  // Iterates over strong and dependent handles. See the note above.
165  void IterateYoungStrongAndDependentRoots(RootVisitor* v);
166
167  // Marks weak unmodified handles satisfying |is_dead| as pending.
168  void MarkYoungWeakDeadObjectsPending(WeakSlotCallbackWithHeap is_dead);
169
170  // Iterates over weak independent or unmodified handles.
171  // See the note above.
172  void IterateYoungWeakDeadObjectsForFinalizers(RootVisitor* v);
173  void IterateYoungWeakObjectsForPhantomHandles(
174      RootVisitor* v, WeakSlotCallbackWithHeap should_reset_handle);
175
176  // Identify unmodified objects that are in weak state and marks them
177  // unmodified
178  void IdentifyWeakUnmodifiedObjects(WeakSlotCallback is_unmodified);
179
180  Isolate* isolate() const { return isolate_; }
181
182  size_t TotalSize() const;
183  size_t UsedSize() const;
184
185  // Number of global handles.
186  size_t handles_count() const;
187
188  size_t GetAndResetGlobalHandleResetCount() {
189    size_t old = number_of_phantom_handle_resets_;
190    number_of_phantom_handle_resets_ = 0;
191    return old;
192  }
193
194  void SetStackStart(void* stack_start);
195  void NotifyEmptyEmbedderStack();
196  void CleanupOnStackReferencesBelowCurrentStackPosition();
197  size_t NumberOfOnStackHandlesForTesting();
198
199#ifdef DEBUG
200  void PrintStats();
201  void Print();
202#endif  // DEBUG
203
204 private:
205  // Internal node structures.
206  class Node;
207  template <class BlockType>
208  class NodeIterator;
209  template <class NodeType>
210  class NodeSpace;
211  class PendingPhantomCallback;
212  class TracedNode;
213  class OnStackTracedNodeSpace;
214
215  static GlobalHandles* From(const TracedNode*);
216
217  bool InRecursiveGC(unsigned gc_processing_counter);
218
219  void InvokeSecondPassPhantomCallbacksFromTask();
220  void InvokeOrScheduleSecondPassPhantomCallbacks(bool synchronous_second_pass);
221  size_t PostScavengeProcessing(unsigned post_processing_count);
222  size_t PostMarkSweepProcessing(unsigned post_processing_count);
223
224  template <typename T>
225  size_t InvokeFirstPassWeakCallbacks(
226      std::vector<std::pair<T*, PendingPhantomCallback>>* pending);
227
228  template <typename T>
229  void UpdateAndCompactListOfYoungNode(std::vector<T*>* node_list);
230  void UpdateListOfYoungNodes();
231
232  void ApplyPersistentHandleVisitor(v8::PersistentHandleVisitor* visitor,
233                                    Node* node);
234
235  Isolate* const isolate_;
236  bool is_marking_ = false;
237
238  std::unique_ptr<NodeSpace<Node>> regular_nodes_;
239  // Contains all nodes holding young objects. Note: when the list
240  // is accessed, some of the objects may have been promoted already.
241  std::vector<Node*> young_nodes_;
242
243  std::unique_ptr<NodeSpace<TracedNode>> traced_nodes_;
244  std::vector<TracedNode*> traced_young_nodes_;
245  std::unique_ptr<OnStackTracedNodeSpace> on_stack_nodes_;
246
247  size_t number_of_phantom_handle_resets_ = 0;
248
249  std::vector<std::pair<Node*, PendingPhantomCallback>>
250      regular_pending_phantom_callbacks_;
251  std::vector<std::pair<TracedNode*, PendingPhantomCallback>>
252      traced_pending_phantom_callbacks_;
253  std::vector<PendingPhantomCallback> second_pass_callbacks_;
254  bool second_pass_callbacks_task_posted_ = false;
255  bool running_second_pass_callbacks_ = false;
256
257  // Counter for recursive garbage collections during callback processing.
258  unsigned post_gc_processing_count_ = 0;
259};
260
261class GlobalHandles::PendingPhantomCallback final {
262 public:
263  using Data = v8::WeakCallbackInfo<void>;
264
265  enum InvocationType { kFirstPass, kSecondPass };
266
267  PendingPhantomCallback(
268      Data::Callback callback, void* parameter,
269      void* embedder_fields[v8::kEmbedderFieldsInWeakCallback])
270      : callback_(callback), parameter_(parameter) {
271    for (int i = 0; i < v8::kEmbedderFieldsInWeakCallback; ++i) {
272      embedder_fields_[i] = embedder_fields[i];
273    }
274  }
275
276  void Invoke(Isolate* isolate, InvocationType type);
277
278  Data::Callback callback() const { return callback_; }
279
280 private:
281  Data::Callback callback_;
282  void* parameter_;
283  void* embedder_fields_[v8::kEmbedderFieldsInWeakCallback];
284};
285
286class EternalHandles final {
287 public:
288  EternalHandles() = default;
289  ~EternalHandles();
290  EternalHandles(const EternalHandles&) = delete;
291  EternalHandles& operator=(const EternalHandles&) = delete;
292
293  // Create an EternalHandle, overwriting the index.
294  V8_EXPORT_PRIVATE void Create(Isolate* isolate, Object object, int* index);
295
296  // Grab the handle for an existing EternalHandle.
297  inline Handle<Object> Get(int index) {
298    return Handle<Object>(GetLocation(index));
299  }
300
301  // Iterates over all handles.
302  void IterateAllRoots(RootVisitor* visitor);
303  // Iterates over all handles which might be in the young generation.
304  void IterateYoungRoots(RootVisitor* visitor);
305  // Rebuilds new space list.
306  void PostGarbageCollectionProcessing();
307
308  size_t handles_count() const { return size_; }
309
310 private:
311  static const int kInvalidIndex = -1;
312  static const int kShift = 8;
313  static const int kSize = 1 << kShift;
314  static const int kMask = 0xff;
315
316  // Gets the slot for an index. This returns an Address* rather than an
317  // ObjectSlot in order to avoid #including slots.h in this header file.
318  inline Address* GetLocation(int index) {
319    DCHECK(index >= 0 && index < size_);
320    return &blocks_[index >> kShift][index & kMask];
321  }
322
323  int size_ = 0;
324  std::vector<Address*> blocks_;
325  std::vector<int> young_node_indices_;
326};
327
328// A vector of global Handles which automatically manages the backing of those
329// Handles as a vector of strong-rooted addresses. Handles returned by the
330// vector are valid as long as they are present in the vector.
331template <typename T>
332class GlobalHandleVector {
333 public:
334  class Iterator {
335   public:
336    explicit Iterator(
337        std::vector<Address, StrongRootBlockAllocator>::iterator it)
338        : it_(it) {}
339    Iterator& operator++() {
340      ++it_;
341      return *this;
342    }
343    Handle<T> operator*() { return Handle<T>(&*it_); }
344    bool operator!=(Iterator& that) { return it_ != that.it_; }
345
346   private:
347    std::vector<Address, StrongRootBlockAllocator>::iterator it_;
348  };
349
350  explicit GlobalHandleVector(Heap* heap)
351      : locations_(StrongRootBlockAllocator(heap)) {}
352
353  Handle<T> operator[](size_t i) { return Handle<T>(&locations_[i]); }
354
355  size_t size() const { return locations_.size(); }
356  bool empty() const { return locations_.empty(); }
357
358  void Push(T val) { locations_.push_back(val.ptr()); }
359  // Handles into the GlobalHandleVector become invalid when they are removed,
360  // so "pop" returns a raw object rather than a handle.
361  inline T Pop();
362
363  Iterator begin() { return Iterator(locations_.begin()); }
364  Iterator end() { return Iterator(locations_.end()); }
365
366 private:
367  std::vector<Address, StrongRootBlockAllocator> locations_;
368};
369
370}  // namespace internal
371}  // namespace v8
372
373#endif  // V8_HANDLES_GLOBAL_HANDLES_H_
374