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