Line data Source code
1 : // Copyright 2012 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_OBJECTS_VISITING_H_
6 : #define V8_OBJECTS_VISITING_H_
7 :
8 : #include "src/allocation.h"
9 : #include "src/heap/embedder-tracing.h"
10 : #include "src/heap/heap.h"
11 : #include "src/heap/spaces.h"
12 : #include "src/layout-descriptor.h"
13 : #include "src/objects-body-descriptors.h"
14 :
15 : // This file provides base classes and auxiliary methods for defining
16 : // static object visitors used during GC.
17 : // Visiting HeapObject body with a normal ObjectVisitor requires performing
18 : // two switches on object's instance type to determine object size and layout
19 : // and one or more virtual method calls on visitor itself.
20 : // Static visitor is different: it provides a dispatch table which contains
21 : // pointers to specialized visit functions. Each map has the visitor_id
22 : // field which contains an index of specialized visitor to use.
23 :
24 : namespace v8 {
25 : namespace internal {
26 :
27 :
28 : // Base class for all static visitors.
29 : class StaticVisitorBase : public AllStatic {
30 : public:
31 : #define VISITOR_ID_LIST(V) \
32 : V(SeqOneByteString) \
33 : V(SeqTwoByteString) \
34 : V(ShortcutCandidate) \
35 : V(ByteArray) \
36 : V(BytecodeArray) \
37 : V(FreeSpace) \
38 : V(FixedArray) \
39 : V(FixedDoubleArray) \
40 : V(FixedTypedArray) \
41 : V(FixedFloat64Array) \
42 : V(NativeContext) \
43 : V(AllocationSite) \
44 : V(DataObject) \
45 : V(JSObjectFast) \
46 : V(JSObject) \
47 : V(JSApiObject) \
48 : V(Struct) \
49 : V(ConsString) \
50 : V(SlicedString) \
51 : V(ThinString) \
52 : V(Symbol) \
53 : V(Oddball) \
54 : V(Code) \
55 : V(Map) \
56 : V(Cell) \
57 : V(PropertyCell) \
58 : V(WeakCell) \
59 : V(TransitionArray) \
60 : V(SharedFunctionInfo) \
61 : V(JSFunction) \
62 : V(JSWeakCollection) \
63 : V(JSArrayBuffer) \
64 : V(JSRegExp)
65 :
66 : // For data objects, JS objects and structs along with generic visitor which
67 : // can visit object of any size we provide visitors specialized by
68 : // object size in words.
69 : // Ids of specialized visitors are declared in a linear order (without
70 : // holes) starting from the id of visitor specialized for 2 words objects
71 : // (base visitor id) and ending with the id of generic visitor.
72 : // Method GetVisitorIdForSize depends on this ordering to calculate visitor
73 : // id of specialized visitor from given instance size, base visitor id and
74 : // generic visitor's id.
75 : enum VisitorId {
76 : #define VISITOR_ID_ENUM_DECL(id) kVisit##id,
77 : VISITOR_ID_LIST(VISITOR_ID_ENUM_DECL)
78 : #undef VISITOR_ID_ENUM_DECL
79 : kVisitorIdCount
80 : };
81 :
82 : // Visitor ID should fit in one byte.
83 : STATIC_ASSERT(kVisitorIdCount <= 256);
84 :
85 : // Determine which specialized visitor should be used for given instance type
86 : // and instance type.
87 : static VisitorId GetVisitorId(int instance_type, int instance_size,
88 : bool has_unboxed_fields);
89 :
90 : // Determine which specialized visitor should be used for given map.
91 : static VisitorId GetVisitorId(Map* map);
92 : };
93 :
94 :
95 : template <typename Callback>
96 : class VisitorDispatchTable {
97 : public:
98 : void CopyFrom(VisitorDispatchTable* other) {
99 : // We are not using memcpy to guarantee that during update
100 : // every element of callbacks_ array will remain correct
101 : // pointer (memcpy might be implemented as a byte copying loop).
102 2283237 : for (int i = 0; i < StaticVisitorBase::kVisitorIdCount; i++) {
103 2283237 : base::NoBarrier_Store(&callbacks_[i], other->callbacks_[i]);
104 : }
105 : }
106 :
107 : inline Callback GetVisitor(Map* map);
108 :
109 : inline Callback GetVisitorById(StaticVisitorBase::VisitorId id) {
110 28 : return reinterpret_cast<Callback>(callbacks_[id]);
111 : }
112 :
113 : void Register(StaticVisitorBase::VisitorId id, Callback callback) {
114 : DCHECK(id < StaticVisitorBase::kVisitorIdCount); // id is unsigned.
115 522190 : callbacks_[id] = reinterpret_cast<base::AtomicWord>(callback);
116 : }
117 :
118 : private:
119 : base::AtomicWord callbacks_[StaticVisitorBase::kVisitorIdCount];
120 : };
121 :
122 :
123 : template <typename StaticVisitor, typename BodyDescriptor, typename ReturnType>
124 : class FlexibleBodyVisitor : public AllStatic {
125 : public:
126 110301806 : INLINE(static ReturnType Visit(Map* map, HeapObject* object)) {
127 250793858 : int object_size = BodyDescriptor::SizeOf(map, object);
128 250793883 : BodyDescriptor::template IterateBody<StaticVisitor>(object, object_size);
129 110301810 : return static_cast<ReturnType>(object_size);
130 : }
131 : };
132 :
133 :
134 : template <typename StaticVisitor, typename BodyDescriptor, typename ReturnType>
135 : class FixedBodyVisitor : public AllStatic {
136 : public:
137 100524226 : INLINE(static ReturnType Visit(Map* map, HeapObject* object)) {
138 158944840 : BodyDescriptor::template IterateBody<StaticVisitor>(object);
139 100524227 : return static_cast<ReturnType>(BodyDescriptor::kSize);
140 : }
141 : };
142 :
143 :
144 : // Base class for visitors used for a linear new space iteration.
145 : // IterateBody returns size of visited object.
146 : // Certain types of objects (i.e. Code objects) are not handled
147 : // by dispatch table of this visitor because they cannot appear
148 : // in the new space.
149 : //
150 : // This class is intended to be used in the following way:
151 : //
152 : // class SomeVisitor : public StaticNewSpaceVisitor<SomeVisitor> {
153 : // ...
154 : // }
155 : //
156 : // This is an example of Curiously recurring template pattern
157 : // (see http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern).
158 : // We use CRTP to guarantee aggressive compile time optimizations (i.e.
159 : // inlining and specialization of StaticVisitor::VisitPointers methods).
160 : template <typename StaticVisitor>
161 : class StaticNewSpaceVisitor : public StaticVisitorBase {
162 : public:
163 : static void Initialize();
164 :
165 : INLINE(static int IterateBody(Map* map, HeapObject* obj)) {
166 70508953 : return table_.GetVisitor(map)(map, obj);
167 : }
168 :
169 : INLINE(static void VisitPointers(Heap* heap, HeapObject* object,
170 : Object** start, Object** end)) {
171 412075003 : for (Object** p = start; p < end; p++) {
172 412075003 : StaticVisitor::VisitPointer(heap, object, p);
173 : }
174 : }
175 :
176 : // Although we are using the JSFunction body descriptor which does not
177 : // visit the code entry, compiler wants it to be accessible.
178 : // See JSFunction::BodyDescriptorImpl.
179 : inline static void VisitCodeEntry(Heap* heap, HeapObject* object,
180 : Address entry_address) {
181 : UNREACHABLE();
182 : }
183 :
184 : private:
185 0 : inline static int UnreachableVisitor(Map* map, HeapObject* object) {
186 0 : UNREACHABLE();
187 : return 0;
188 : }
189 :
190 24213 : INLINE(static int VisitByteArray(Map* map, HeapObject* object)) {
191 24213 : return reinterpret_cast<ByteArray*>(object)->ByteArraySize();
192 : }
193 :
194 73665 : INLINE(static int VisitFixedDoubleArray(Map* map, HeapObject* object)) {
195 73665 : int length = reinterpret_cast<FixedDoubleArray*>(object)->length();
196 73665 : return FixedDoubleArray::SizeFor(length);
197 : }
198 :
199 8514287 : INLINE(static int VisitSeqOneByteString(Map* map, HeapObject* object)) {
200 : return SeqOneByteString::cast(object)
201 8514287 : ->SeqOneByteStringSize(map->instance_type());
202 : }
203 :
204 6558695 : INLINE(static int VisitSeqTwoByteString(Map* map, HeapObject* object)) {
205 : return SeqTwoByteString::cast(object)
206 6558695 : ->SeqTwoByteStringSize(map->instance_type());
207 : }
208 :
209 4198 : INLINE(static int VisitFreeSpace(Map* map, HeapObject* object)) {
210 4198 : return FreeSpace::cast(object)->size();
211 : }
212 :
213 : class DataObjectVisitor {
214 : public:
215 : template <int object_size>
216 : static inline int VisitSpecialized(Map* map, HeapObject* object) {
217 : return object_size;
218 : }
219 :
220 2604818 : INLINE(static int Visit(Map* map, HeapObject* object)) {
221 2604818 : return map->instance_size();
222 : }
223 : };
224 :
225 : typedef FlexibleBodyVisitor<StaticVisitor, StructBodyDescriptor, int>
226 : StructVisitor;
227 :
228 : typedef FlexibleBodyVisitor<StaticVisitor, JSObject::BodyDescriptor, int>
229 : JSObjectVisitor;
230 :
231 : // Visitor for JSObjects without unboxed double fields.
232 : typedef FlexibleBodyVisitor<StaticVisitor, JSObject::FastBodyDescriptor, int>
233 : JSObjectFastVisitor;
234 :
235 : typedef int (*Callback)(Map* map, HeapObject* object);
236 :
237 : static VisitorDispatchTable<Callback> table_;
238 : };
239 :
240 :
241 : template <typename StaticVisitor>
242 : VisitorDispatchTable<typename StaticNewSpaceVisitor<StaticVisitor>::Callback>
243 : StaticNewSpaceVisitor<StaticVisitor>::table_;
244 :
245 :
246 : // Base class for visitors used to transitively mark the entire heap.
247 : // IterateBody returns nothing.
248 : // Certain types of objects might not be handled by this base class and
249 : // no visitor function is registered by the generic initialization. A
250 : // specialized visitor function needs to be provided by the inheriting
251 : // class itself for those cases.
252 : //
253 : // This class is intended to be used in the following way:
254 : //
255 : // class SomeVisitor : public StaticMarkingVisitor<SomeVisitor> {
256 : // ...
257 : // }
258 : //
259 : // This is an example of Curiously recurring template pattern.
260 : template <typename StaticVisitor>
261 : class StaticMarkingVisitor : public StaticVisitorBase {
262 : public:
263 : static void Initialize();
264 :
265 : INLINE(static void IterateBody(Map* map, HeapObject* obj)) {
266 699251893 : table_.GetVisitor(map)(map, obj);
267 : }
268 :
269 : INLINE(static void VisitWeakCell(Map* map, HeapObject* object));
270 : INLINE(static void VisitTransitionArray(Map* map, HeapObject* object));
271 : INLINE(static void VisitCodeEntry(Heap* heap, HeapObject* object,
272 : Address entry_address));
273 : INLINE(static void VisitEmbeddedPointer(Heap* heap, RelocInfo* rinfo));
274 : INLINE(static void VisitCell(Heap* heap, RelocInfo* rinfo));
275 : INLINE(static void VisitDebugTarget(Heap* heap, RelocInfo* rinfo));
276 : INLINE(static void VisitCodeTarget(Heap* heap, RelocInfo* rinfo));
277 : INLINE(static void VisitCodeAgeSequence(Heap* heap, RelocInfo* rinfo));
278 : INLINE(static void VisitExternalReference(RelocInfo* rinfo)) {}
279 : INLINE(static void VisitInternalReference(RelocInfo* rinfo)) {}
280 : INLINE(static void VisitRuntimeEntry(RelocInfo* rinfo)) {}
281 : // Skip the weak next code link in a code object.
282 : INLINE(static void VisitNextCodeLink(Heap* heap, Object** slot)) {}
283 :
284 : protected:
285 : INLINE(static void VisitMap(Map* map, HeapObject* object));
286 : INLINE(static void VisitCode(Map* map, HeapObject* object));
287 : INLINE(static void VisitBytecodeArray(Map* map, HeapObject* object));
288 : INLINE(static void VisitSharedFunctionInfo(Map* map, HeapObject* object));
289 : INLINE(static void VisitWeakCollection(Map* map, HeapObject* object));
290 : INLINE(static void VisitJSFunction(Map* map, HeapObject* object));
291 : INLINE(static void VisitNativeContext(Map* map, HeapObject* object));
292 :
293 : // Mark pointers in a Map treating some elements of the descriptor array weak.
294 : static void MarkMapContents(Heap* heap, Map* map);
295 :
296 : // Code flushing support.
297 : INLINE(static bool IsFlushable(Heap* heap, JSFunction* function));
298 : INLINE(static bool IsFlushable(Heap* heap, SharedFunctionInfo* shared_info));
299 :
300 : // Helpers used by code flushing support that visit pointer fields and treat
301 : // references to code objects either strongly or weakly.
302 : static void VisitSharedFunctionInfoStrongCode(Map* map, HeapObject* object);
303 : static void VisitSharedFunctionInfoWeakCode(Map* map, HeapObject* object);
304 : static void VisitJSFunctionStrongCode(Map* map, HeapObject* object);
305 : static void VisitJSFunctionWeakCode(Map* map, HeapObject* object);
306 :
307 : class DataObjectVisitor {
308 : public:
309 : template <int size>
310 : static inline void VisitSpecialized(Map* map, HeapObject* object) {}
311 :
312 206274372 : INLINE(static void Visit(Map* map, HeapObject* object)) {}
313 : };
314 :
315 : typedef FlexibleBodyVisitor<StaticVisitor, FixedArray::BodyDescriptor, void>
316 : FixedArrayVisitor;
317 :
318 : typedef FlexibleBodyVisitor<StaticVisitor, JSObject::FastBodyDescriptor, void>
319 : JSObjectFastVisitor;
320 : typedef FlexibleBodyVisitor<StaticVisitor, JSObject::BodyDescriptor, void>
321 : JSObjectVisitor;
322 :
323 : class JSApiObjectVisitor : AllStatic {
324 : public:
325 368449 : INLINE(static void Visit(Map* map, HeapObject* object)) {
326 : TracePossibleWrapper(object);
327 : JSObjectVisitor::Visit(map, object);
328 368449 : }
329 :
330 : private:
331 : INLINE(static void TracePossibleWrapper(HeapObject* object)) {
332 368449 : if (object->GetHeap()->local_embedder_heap_tracer()->InUse()) {
333 : DCHECK(object->IsJSObject());
334 0 : object->GetHeap()->TracePossibleWrapper(JSObject::cast(object));
335 : }
336 : }
337 : };
338 :
339 : typedef FlexibleBodyVisitor<StaticVisitor, StructBodyDescriptor, void>
340 : StructObjectVisitor;
341 :
342 : typedef void (*Callback)(Map* map, HeapObject* object);
343 :
344 : static VisitorDispatchTable<Callback> table_;
345 : };
346 :
347 :
348 : template <typename StaticVisitor>
349 : VisitorDispatchTable<typename StaticMarkingVisitor<StaticVisitor>::Callback>
350 : StaticMarkingVisitor<StaticVisitor>::table_;
351 :
352 :
353 : class WeakObjectRetainer;
354 :
355 :
356 : // A weak list is single linked list where each element has a weak pointer to
357 : // the next element. Given the head of the list, this function removes dead
358 : // elements from the list and if requested records slots for next-element
359 : // pointers. The template parameter T is a WeakListVisitor that defines how to
360 : // access the next-element pointers.
361 : template <class T>
362 : Object* VisitWeakList(Heap* heap, Object* list, WeakObjectRetainer* retainer);
363 : } // namespace internal
364 : } // namespace v8
365 :
366 : #endif // V8_OBJECTS_VISITING_H_
|