Line data Source code
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 :
19 : namespace v8 {
20 : namespace internal {
21 :
22 : class HeapStats;
23 : class RootVisitor;
24 :
25 : enum 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.
42 : class 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 3928389 : 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 15 : size_t old = number_of_phantom_handle_resets_;
177 15 : 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 :
241 : class 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 15282605 : for (int i = 0; i < v8::kEmbedderFieldsInWeakCallback; ++i) {
252 6113042 : 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 :
266 : class 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 15 : 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 152470 : 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_
|