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