blob: 4ce1bd077b1c68ad74172417bb1af72a5becdf7d [file] [log] [blame]
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001// Copyright 2011 the V8 project authors. All rights reserved.
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000028#ifndef V8_OBJECTS_VISITING_H_
29#define V8_OBJECTS_VISITING_H_
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000030
lrn@chromium.org1c092762011-05-09 09:42:16 +000031#include "allocation.h"
32
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000033#if V8_TARGET_ARCH_IA32
34#include "ia32/assembler-ia32.h"
35#include "ia32/assembler-ia32-inl.h"
36#elif V8_TARGET_ARCH_X64
37#include "x64/assembler-x64.h"
38#include "x64/assembler-x64-inl.h"
39#elif V8_TARGET_ARCH_ARM
40#include "arm/assembler-arm.h"
41#include "arm/assembler-arm-inl.h"
42#elif V8_TARGET_ARCH_MIPS
43#include "mips/assembler-mips.h"
44#include "mips/assembler-mips-inl.h"
45#else
46#error Unsupported target architecture.
47#endif
48
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000049// This file provides base classes and auxiliary methods for defining
50// static object visitors used during GC.
51// Visiting HeapObject body with a normal ObjectVisitor requires performing
52// two switches on object's instance type to determine object size and layout
53// and one or more virtual method calls on visitor itself.
54// Static visitor is different: it provides a dispatch table which contains
55// pointers to specialized visit functions. Each map has the visitor_id
56// field which contains an index of specialized visitor to use.
57
58namespace v8 {
59namespace internal {
60
61
62// Base class for all static visitors.
63class StaticVisitorBase : public AllStatic {
64 public:
65 enum VisitorId {
66 kVisitSeqAsciiString = 0,
67 kVisitSeqTwoByteString,
68 kVisitShortcutCandidate,
69 kVisitByteArray,
70 kVisitFixedArray,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000071 kVisitFixedDoubleArray,
whesse@chromium.org4a5224e2010-10-20 12:37:07 +000072 kVisitGlobalContext,
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000073
74 // For data objects, JS objects and structs along with generic visitor which
75 // can visit object of any size we provide visitors specialized by
76 // object size in words.
77 // Ids of specialized visitors are declared in a linear order (without
78 // holes) starting from the id of visitor specialized for 2 words objects
79 // (base visitor id) and ending with the id of generic visitor.
80 // Method GetVisitorIdForSize depends on this ordering to calculate visitor
81 // id of specialized visitor from given instance size, base visitor id and
82 // generic visitor's id.
83
84 kVisitDataObject,
85 kVisitDataObject2 = kVisitDataObject,
86 kVisitDataObject3,
87 kVisitDataObject4,
88 kVisitDataObject5,
89 kVisitDataObject6,
90 kVisitDataObject7,
91 kVisitDataObject8,
92 kVisitDataObject9,
93 kVisitDataObjectGeneric,
94
95 kVisitJSObject,
96 kVisitJSObject2 = kVisitJSObject,
97 kVisitJSObject3,
98 kVisitJSObject4,
99 kVisitJSObject5,
100 kVisitJSObject6,
101 kVisitJSObject7,
102 kVisitJSObject8,
103 kVisitJSObject9,
104 kVisitJSObjectGeneric,
105
106 kVisitStruct,
107 kVisitStruct2 = kVisitStruct,
108 kVisitStruct3,
109 kVisitStruct4,
110 kVisitStruct5,
111 kVisitStruct6,
112 kVisitStruct7,
113 kVisitStruct8,
114 kVisitStruct9,
115 kVisitStructGeneric,
116
117 kVisitConsString,
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000118 kVisitSlicedString,
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000119 kVisitOddball,
120 kVisitCode,
121 kVisitMap,
122 kVisitPropertyCell,
123 kVisitSharedFunctionInfo,
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000124 kVisitJSFunction,
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000125 kVisitJSWeakMap,
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000126 kVisitJSRegExp,
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000127
128 kVisitorIdCount,
129 kMinObjectSizeInWords = 2
130 };
131
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000132 // Visitor ID should fit in one byte.
133 STATIC_ASSERT(kVisitorIdCount <= 256);
134
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000135 // Determine which specialized visitor should be used for given instance type
136 // and instance type.
137 static VisitorId GetVisitorId(int instance_type, int instance_size);
138
139 static VisitorId GetVisitorId(Map* map) {
140 return GetVisitorId(map->instance_type(), map->instance_size());
141 }
142
143 // For visitors that allow specialization by size calculate VisitorId based
144 // on size, base visitor id and generic visitor id.
145 static VisitorId GetVisitorIdForSize(VisitorId base,
146 VisitorId generic,
147 int object_size) {
148 ASSERT((base == kVisitDataObject) ||
149 (base == kVisitStruct) ||
150 (base == kVisitJSObject));
151 ASSERT(IsAligned(object_size, kPointerSize));
152 ASSERT(kMinObjectSizeInWords * kPointerSize <= object_size);
153 ASSERT(object_size < Page::kMaxHeapObjectSize);
154
155 const VisitorId specialization = static_cast<VisitorId>(
156 base + (object_size >> kPointerSizeLog2) - kMinObjectSizeInWords);
157
158 return Min(specialization, generic);
159 }
160};
161
162
163template<typename Callback>
164class VisitorDispatchTable {
165 public:
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000166 void CopyFrom(VisitorDispatchTable* other) {
167 // We are not using memcpy to guarantee that during update
168 // every element of callbacks_ array will remain correct
169 // pointer (memcpy might be implemented as a byte copying loop).
170 for (int i = 0; i < StaticVisitorBase::kVisitorIdCount; i++) {
171 NoBarrier_Store(&callbacks_[i], other->callbacks_[i]);
172 }
173 }
174
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000175 inline Callback GetVisitor(Map* map) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000176 return reinterpret_cast<Callback>(callbacks_[map->visitor_id()]);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000177 }
178
179 void Register(StaticVisitorBase::VisitorId id, Callback callback) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000180 ASSERT(id < StaticVisitorBase::kVisitorIdCount); // id is unsigned.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000181 callbacks_[id] = reinterpret_cast<AtomicWord>(callback);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000182 }
183
184 template<typename Visitor,
185 StaticVisitorBase::VisitorId base,
186 StaticVisitorBase::VisitorId generic,
187 int object_size_in_words>
188 void RegisterSpecialization() {
189 static const int size = object_size_in_words * kPointerSize;
190 Register(StaticVisitorBase::GetVisitorIdForSize(base, generic, size),
191 &Visitor::template VisitSpecialized<size>);
192 }
193
194
195 template<typename Visitor,
196 StaticVisitorBase::VisitorId base,
197 StaticVisitorBase::VisitorId generic>
198 void RegisterSpecializations() {
199 STATIC_ASSERT(
200 (generic - base + StaticVisitorBase::kMinObjectSizeInWords) == 10);
201 RegisterSpecialization<Visitor, base, generic, 2>();
202 RegisterSpecialization<Visitor, base, generic, 3>();
203 RegisterSpecialization<Visitor, base, generic, 4>();
204 RegisterSpecialization<Visitor, base, generic, 5>();
205 RegisterSpecialization<Visitor, base, generic, 6>();
206 RegisterSpecialization<Visitor, base, generic, 7>();
207 RegisterSpecialization<Visitor, base, generic, 8>();
208 RegisterSpecialization<Visitor, base, generic, 9>();
209 Register(generic, &Visitor::Visit);
210 }
211
212 private:
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000213 AtomicWord callbacks_[StaticVisitorBase::kVisitorIdCount];
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000214};
215
216
217template<typename StaticVisitor>
218class BodyVisitorBase : public AllStatic {
219 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000220 INLINE(static void IteratePointers(Heap* heap,
221 HeapObject* object,
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000222 int start_offset,
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000223 int end_offset)) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000224 Object** start_slot = reinterpret_cast<Object**>(object->address() +
225 start_offset);
226 Object** end_slot = reinterpret_cast<Object**>(object->address() +
227 end_offset);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000228 StaticVisitor::VisitPointers(heap, start_slot, end_slot);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000229 }
230};
231
232
233template<typename StaticVisitor, typename BodyDescriptor, typename ReturnType>
234class FlexibleBodyVisitor : public BodyVisitorBase<StaticVisitor> {
235 public:
236 static inline ReturnType Visit(Map* map, HeapObject* object) {
237 int object_size = BodyDescriptor::SizeOf(map, object);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000238 BodyVisitorBase<StaticVisitor>::IteratePointers(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000239 map->heap(),
240 object,
241 BodyDescriptor::kStartOffset,
242 object_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000243 return static_cast<ReturnType>(object_size);
244 }
245
246 template<int object_size>
247 static inline ReturnType VisitSpecialized(Map* map, HeapObject* object) {
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000248 ASSERT(BodyDescriptor::SizeOf(map, object) == object_size);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000249 BodyVisitorBase<StaticVisitor>::IteratePointers(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000250 map->heap(),
251 object,
252 BodyDescriptor::kStartOffset,
253 object_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000254 return static_cast<ReturnType>(object_size);
255 }
256};
257
258
259template<typename StaticVisitor, typename BodyDescriptor, typename ReturnType>
260class FixedBodyVisitor : public BodyVisitorBase<StaticVisitor> {
261 public:
262 static inline ReturnType Visit(Map* map, HeapObject* object) {
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000263 BodyVisitorBase<StaticVisitor>::IteratePointers(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000264 map->heap(),
265 object,
266 BodyDescriptor::kStartOffset,
267 BodyDescriptor::kEndOffset);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000268 return static_cast<ReturnType>(BodyDescriptor::kSize);
269 }
270};
271
272
273// Base class for visitors used for a linear new space iteration.
274// IterateBody returns size of visited object.
275// Certain types of objects (i.e. Code objects) are not handled
276// by dispatch table of this visitor because they cannot appear
277// in the new space.
278//
279// This class is intended to be used in the following way:
280//
281// class SomeVisitor : public StaticNewSpaceVisitor<SomeVisitor> {
282// ...
283// }
284//
285// This is an example of Curiously recurring template pattern
286// (see http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern).
287// We use CRTP to guarantee aggressive compile time optimizations (i.e.
288// inlining and specialization of StaticVisitor::VisitPointers methods).
289template<typename StaticVisitor>
290class StaticNewSpaceVisitor : public StaticVisitorBase {
291 public:
292 static void Initialize() {
293 table_.Register(kVisitShortcutCandidate,
294 &FixedBodyVisitor<StaticVisitor,
295 ConsString::BodyDescriptor,
296 int>::Visit);
297
298 table_.Register(kVisitConsString,
299 &FixedBodyVisitor<StaticVisitor,
300 ConsString::BodyDescriptor,
301 int>::Visit);
302
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000303 table_.Register(kVisitSlicedString,
304 &FixedBodyVisitor<StaticVisitor,
305 SlicedString::BodyDescriptor,
306 int>::Visit);
307
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000308 table_.Register(kVisitFixedArray,
309 &FlexibleBodyVisitor<StaticVisitor,
310 FixedArray::BodyDescriptor,
311 int>::Visit);
312
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000313 table_.Register(kVisitFixedDoubleArray, &VisitFixedDoubleArray);
314
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000315 table_.Register(kVisitGlobalContext,
316 &FixedBodyVisitor<StaticVisitor,
317 Context::ScavengeBodyDescriptor,
318 int>::Visit);
319
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000320 table_.Register(kVisitByteArray, &VisitByteArray);
321
322 table_.Register(kVisitSharedFunctionInfo,
323 &FixedBodyVisitor<StaticVisitor,
324 SharedFunctionInfo::BodyDescriptor,
325 int>::Visit);
326
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000327 table_.Register(kVisitJSWeakMap, &VisitJSObject);
328
329 table_.Register(kVisitJSRegExp, &VisitJSObject);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000330
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000331 table_.Register(kVisitSeqAsciiString, &VisitSeqAsciiString);
332
333 table_.Register(kVisitSeqTwoByteString, &VisitSeqTwoByteString);
334
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000335 table_.Register(kVisitJSFunction,
336 &JSObjectVisitor::
337 template VisitSpecialized<JSFunction::kSize>);
338
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000339 table_.RegisterSpecializations<DataObjectVisitor,
340 kVisitDataObject,
341 kVisitDataObjectGeneric>();
342 table_.RegisterSpecializations<JSObjectVisitor,
343 kVisitJSObject,
344 kVisitJSObjectGeneric>();
345 table_.RegisterSpecializations<StructVisitor,
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000346 kVisitStruct,
347 kVisitStructGeneric>();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000348 }
349
350 static inline int IterateBody(Map* map, HeapObject* obj) {
351 return table_.GetVisitor(map)(map, obj);
352 }
353
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000354 static inline void VisitPointers(Heap* heap, Object** start, Object** end) {
355 for (Object** p = start; p < end; p++) StaticVisitor::VisitPointer(heap, p);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000356 }
357
358 private:
359 static inline int VisitByteArray(Map* map, HeapObject* object) {
360 return reinterpret_cast<ByteArray*>(object)->ByteArraySize();
361 }
362
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000363 static inline int VisitFixedDoubleArray(Map* map, HeapObject* object) {
364 int length = reinterpret_cast<FixedDoubleArray*>(object)->length();
365 return FixedDoubleArray::SizeFor(length);
366 }
367
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000368 static inline int VisitJSObject(Map* map, HeapObject* object) {
369 return JSObjectVisitor::Visit(map, object);
370 }
371
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000372 static inline int VisitSeqAsciiString(Map* map, HeapObject* object) {
373 return SeqAsciiString::cast(object)->
374 SeqAsciiStringSize(map->instance_type());
375 }
376
377 static inline int VisitSeqTwoByteString(Map* map, HeapObject* object) {
378 return SeqTwoByteString::cast(object)->
379 SeqTwoByteStringSize(map->instance_type());
380 }
381
382 class DataObjectVisitor {
383 public:
384 template<int object_size>
385 static inline int VisitSpecialized(Map* map, HeapObject* object) {
386 return object_size;
387 }
388
389 static inline int Visit(Map* map, HeapObject* object) {
390 return map->instance_size();
391 }
392 };
393
394 typedef FlexibleBodyVisitor<StaticVisitor,
395 StructBodyDescriptor,
396 int> StructVisitor;
397
398 typedef FlexibleBodyVisitor<StaticVisitor,
399 JSObject::BodyDescriptor,
400 int> JSObjectVisitor;
401
402 typedef int (*Callback)(Map* map, HeapObject* object);
403
404 static VisitorDispatchTable<Callback> table_;
405};
406
407
408template<typename StaticVisitor>
409VisitorDispatchTable<typename StaticNewSpaceVisitor<StaticVisitor>::Callback>
410 StaticNewSpaceVisitor<StaticVisitor>::table_;
411
412
413void Code::CodeIterateBody(ObjectVisitor* v) {
414 int mode_mask = RelocInfo::kCodeTargetMask |
415 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000416 RelocInfo::ModeMask(RelocInfo::GLOBAL_PROPERTY_CELL) |
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000417 RelocInfo::ModeMask(RelocInfo::EXTERNAL_REFERENCE) |
418 RelocInfo::ModeMask(RelocInfo::JS_RETURN) |
419 RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT) |
420 RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY);
421
422 // Use the relocation info pointer before it is visited by
423 // the heap compaction in the next statement.
424 RelocIterator it(this, mode_mask);
425
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000426 IteratePointer(v, kRelocationInfoOffset);
427 IteratePointer(v, kDeoptimizationDataOffset);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000428
429 for (; !it.done(); it.next()) {
430 it.rinfo()->Visit(v);
431 }
432}
433
434
435template<typename StaticVisitor>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000436void Code::CodeIterateBody(Heap* heap) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000437 int mode_mask = RelocInfo::kCodeTargetMask |
438 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000439 RelocInfo::ModeMask(RelocInfo::GLOBAL_PROPERTY_CELL) |
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000440 RelocInfo::ModeMask(RelocInfo::EXTERNAL_REFERENCE) |
441 RelocInfo::ModeMask(RelocInfo::JS_RETURN) |
442 RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT) |
443 RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY);
444
445 // Use the relocation info pointer before it is visited by
446 // the heap compaction in the next statement.
447 RelocIterator it(this, mode_mask);
448
449 StaticVisitor::VisitPointer(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000450 heap,
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000451 reinterpret_cast<Object**>(this->address() + kRelocationInfoOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000452 StaticVisitor::VisitPointer(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000453 heap,
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000454 reinterpret_cast<Object**>(this->address() + kDeoptimizationDataOffset));
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000455
456 for (; !it.done(); it.next()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000457 it.rinfo()->template Visit<StaticVisitor>(heap);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000458 }
459}
460
461
462} } // namespace v8::internal
463
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +0000464#endif // V8_OBJECTS_VISITING_H_