blob: c96a8efc738e4ea49ee92263eaa1f824cf2f5041 [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,
118 kVisitOddball,
119 kVisitCode,
120 kVisitMap,
121 kVisitPropertyCell,
122 kVisitSharedFunctionInfo,
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000123 kVisitJSFunction,
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000124 kVisitJSWeakMap,
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000125 kVisitJSRegExp,
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000126
127 kVisitorIdCount,
128 kMinObjectSizeInWords = 2
129 };
130
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000131 // Visitor ID should fit in one byte.
132 STATIC_ASSERT(kVisitorIdCount <= 256);
133
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000134 // Determine which specialized visitor should be used for given instance type
135 // and instance type.
136 static VisitorId GetVisitorId(int instance_type, int instance_size);
137
138 static VisitorId GetVisitorId(Map* map) {
139 return GetVisitorId(map->instance_type(), map->instance_size());
140 }
141
142 // For visitors that allow specialization by size calculate VisitorId based
143 // on size, base visitor id and generic visitor id.
144 static VisitorId GetVisitorIdForSize(VisitorId base,
145 VisitorId generic,
146 int object_size) {
147 ASSERT((base == kVisitDataObject) ||
148 (base == kVisitStruct) ||
149 (base == kVisitJSObject));
150 ASSERT(IsAligned(object_size, kPointerSize));
151 ASSERT(kMinObjectSizeInWords * kPointerSize <= object_size);
152 ASSERT(object_size < Page::kMaxHeapObjectSize);
153
154 const VisitorId specialization = static_cast<VisitorId>(
155 base + (object_size >> kPointerSizeLog2) - kMinObjectSizeInWords);
156
157 return Min(specialization, generic);
158 }
159};
160
161
162template<typename Callback>
163class VisitorDispatchTable {
164 public:
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000165 void CopyFrom(VisitorDispatchTable* other) {
166 // We are not using memcpy to guarantee that during update
167 // every element of callbacks_ array will remain correct
168 // pointer (memcpy might be implemented as a byte copying loop).
169 for (int i = 0; i < StaticVisitorBase::kVisitorIdCount; i++) {
170 NoBarrier_Store(&callbacks_[i], other->callbacks_[i]);
171 }
172 }
173
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000174 inline Callback GetVisitor(Map* map) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000175 return reinterpret_cast<Callback>(callbacks_[map->visitor_id()]);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000176 }
177
178 void Register(StaticVisitorBase::VisitorId id, Callback callback) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000179 ASSERT(id < StaticVisitorBase::kVisitorIdCount); // id is unsigned.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000180 callbacks_[id] = reinterpret_cast<AtomicWord>(callback);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000181 }
182
183 template<typename Visitor,
184 StaticVisitorBase::VisitorId base,
185 StaticVisitorBase::VisitorId generic,
186 int object_size_in_words>
187 void RegisterSpecialization() {
188 static const int size = object_size_in_words * kPointerSize;
189 Register(StaticVisitorBase::GetVisitorIdForSize(base, generic, size),
190 &Visitor::template VisitSpecialized<size>);
191 }
192
193
194 template<typename Visitor,
195 StaticVisitorBase::VisitorId base,
196 StaticVisitorBase::VisitorId generic>
197 void RegisterSpecializations() {
198 STATIC_ASSERT(
199 (generic - base + StaticVisitorBase::kMinObjectSizeInWords) == 10);
200 RegisterSpecialization<Visitor, base, generic, 2>();
201 RegisterSpecialization<Visitor, base, generic, 3>();
202 RegisterSpecialization<Visitor, base, generic, 4>();
203 RegisterSpecialization<Visitor, base, generic, 5>();
204 RegisterSpecialization<Visitor, base, generic, 6>();
205 RegisterSpecialization<Visitor, base, generic, 7>();
206 RegisterSpecialization<Visitor, base, generic, 8>();
207 RegisterSpecialization<Visitor, base, generic, 9>();
208 Register(generic, &Visitor::Visit);
209 }
210
211 private:
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000212 AtomicWord callbacks_[StaticVisitorBase::kVisitorIdCount];
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000213};
214
215
216template<typename StaticVisitor>
217class BodyVisitorBase : public AllStatic {
218 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000219 INLINE(static void IteratePointers(Heap* heap,
220 HeapObject* object,
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000221 int start_offset,
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000222 int end_offset)) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000223 Object** start_slot = reinterpret_cast<Object**>(object->address() +
224 start_offset);
225 Object** end_slot = reinterpret_cast<Object**>(object->address() +
226 end_offset);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000227 StaticVisitor::VisitPointers(heap, start_slot, end_slot);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000228 }
229};
230
231
232template<typename StaticVisitor, typename BodyDescriptor, typename ReturnType>
233class FlexibleBodyVisitor : public BodyVisitorBase<StaticVisitor> {
234 public:
235 static inline ReturnType Visit(Map* map, HeapObject* object) {
236 int object_size = BodyDescriptor::SizeOf(map, object);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000237 BodyVisitorBase<StaticVisitor>::IteratePointers(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000238 map->heap(),
239 object,
240 BodyDescriptor::kStartOffset,
241 object_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000242 return static_cast<ReturnType>(object_size);
243 }
244
245 template<int object_size>
246 static inline ReturnType VisitSpecialized(Map* map, HeapObject* object) {
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000247 ASSERT(BodyDescriptor::SizeOf(map, object) == object_size);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000248 BodyVisitorBase<StaticVisitor>::IteratePointers(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000249 map->heap(),
250 object,
251 BodyDescriptor::kStartOffset,
252 object_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000253 return static_cast<ReturnType>(object_size);
254 }
255};
256
257
258template<typename StaticVisitor, typename BodyDescriptor, typename ReturnType>
259class FixedBodyVisitor : public BodyVisitorBase<StaticVisitor> {
260 public:
261 static inline ReturnType Visit(Map* map, HeapObject* object) {
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000262 BodyVisitorBase<StaticVisitor>::IteratePointers(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000263 map->heap(),
264 object,
265 BodyDescriptor::kStartOffset,
266 BodyDescriptor::kEndOffset);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000267 return static_cast<ReturnType>(BodyDescriptor::kSize);
268 }
269};
270
271
272// Base class for visitors used for a linear new space iteration.
273// IterateBody returns size of visited object.
274// Certain types of objects (i.e. Code objects) are not handled
275// by dispatch table of this visitor because they cannot appear
276// in the new space.
277//
278// This class is intended to be used in the following way:
279//
280// class SomeVisitor : public StaticNewSpaceVisitor<SomeVisitor> {
281// ...
282// }
283//
284// This is an example of Curiously recurring template pattern
285// (see http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern).
286// We use CRTP to guarantee aggressive compile time optimizations (i.e.
287// inlining and specialization of StaticVisitor::VisitPointers methods).
288template<typename StaticVisitor>
289class StaticNewSpaceVisitor : public StaticVisitorBase {
290 public:
291 static void Initialize() {
292 table_.Register(kVisitShortcutCandidate,
293 &FixedBodyVisitor<StaticVisitor,
294 ConsString::BodyDescriptor,
295 int>::Visit);
296
297 table_.Register(kVisitConsString,
298 &FixedBodyVisitor<StaticVisitor,
299 ConsString::BodyDescriptor,
300 int>::Visit);
301
302 table_.Register(kVisitFixedArray,
303 &FlexibleBodyVisitor<StaticVisitor,
304 FixedArray::BodyDescriptor,
305 int>::Visit);
306
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000307 table_.Register(kVisitFixedDoubleArray, &VisitFixedDoubleArray);
308
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000309 table_.Register(kVisitGlobalContext,
310 &FixedBodyVisitor<StaticVisitor,
311 Context::ScavengeBodyDescriptor,
312 int>::Visit);
313
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000314 table_.Register(kVisitByteArray, &VisitByteArray);
315
316 table_.Register(kVisitSharedFunctionInfo,
317 &FixedBodyVisitor<StaticVisitor,
318 SharedFunctionInfo::BodyDescriptor,
319 int>::Visit);
320
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000321 table_.Register(kVisitJSWeakMap, &VisitJSObject);
322
323 table_.Register(kVisitJSRegExp, &VisitJSObject);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000324
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000325 table_.Register(kVisitSeqAsciiString, &VisitSeqAsciiString);
326
327 table_.Register(kVisitSeqTwoByteString, &VisitSeqTwoByteString);
328
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000329 table_.Register(kVisitJSFunction,
330 &JSObjectVisitor::
331 template VisitSpecialized<JSFunction::kSize>);
332
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000333 table_.RegisterSpecializations<DataObjectVisitor,
334 kVisitDataObject,
335 kVisitDataObjectGeneric>();
336 table_.RegisterSpecializations<JSObjectVisitor,
337 kVisitJSObject,
338 kVisitJSObjectGeneric>();
339 table_.RegisterSpecializations<StructVisitor,
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000340 kVisitStruct,
341 kVisitStructGeneric>();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000342 }
343
344 static inline int IterateBody(Map* map, HeapObject* obj) {
345 return table_.GetVisitor(map)(map, obj);
346 }
347
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000348 static inline void VisitPointers(Heap* heap, Object** start, Object** end) {
349 for (Object** p = start; p < end; p++) StaticVisitor::VisitPointer(heap, p);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000350 }
351
352 private:
353 static inline int VisitByteArray(Map* map, HeapObject* object) {
354 return reinterpret_cast<ByteArray*>(object)->ByteArraySize();
355 }
356
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000357 static inline int VisitFixedDoubleArray(Map* map, HeapObject* object) {
358 int length = reinterpret_cast<FixedDoubleArray*>(object)->length();
359 return FixedDoubleArray::SizeFor(length);
360 }
361
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000362 static inline int VisitJSObject(Map* map, HeapObject* object) {
363 return JSObjectVisitor::Visit(map, object);
364 }
365
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000366 static inline int VisitSeqAsciiString(Map* map, HeapObject* object) {
367 return SeqAsciiString::cast(object)->
368 SeqAsciiStringSize(map->instance_type());
369 }
370
371 static inline int VisitSeqTwoByteString(Map* map, HeapObject* object) {
372 return SeqTwoByteString::cast(object)->
373 SeqTwoByteStringSize(map->instance_type());
374 }
375
376 class DataObjectVisitor {
377 public:
378 template<int object_size>
379 static inline int VisitSpecialized(Map* map, HeapObject* object) {
380 return object_size;
381 }
382
383 static inline int Visit(Map* map, HeapObject* object) {
384 return map->instance_size();
385 }
386 };
387
388 typedef FlexibleBodyVisitor<StaticVisitor,
389 StructBodyDescriptor,
390 int> StructVisitor;
391
392 typedef FlexibleBodyVisitor<StaticVisitor,
393 JSObject::BodyDescriptor,
394 int> JSObjectVisitor;
395
396 typedef int (*Callback)(Map* map, HeapObject* object);
397
398 static VisitorDispatchTable<Callback> table_;
399};
400
401
402template<typename StaticVisitor>
403VisitorDispatchTable<typename StaticNewSpaceVisitor<StaticVisitor>::Callback>
404 StaticNewSpaceVisitor<StaticVisitor>::table_;
405
406
407void Code::CodeIterateBody(ObjectVisitor* v) {
408 int mode_mask = RelocInfo::kCodeTargetMask |
409 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000410 RelocInfo::ModeMask(RelocInfo::GLOBAL_PROPERTY_CELL) |
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000411 RelocInfo::ModeMask(RelocInfo::EXTERNAL_REFERENCE) |
412 RelocInfo::ModeMask(RelocInfo::JS_RETURN) |
413 RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT) |
414 RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY);
415
416 // Use the relocation info pointer before it is visited by
417 // the heap compaction in the next statement.
418 RelocIterator it(this, mode_mask);
419
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000420 IteratePointer(v, kRelocationInfoOffset);
421 IteratePointer(v, kDeoptimizationDataOffset);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000422
423 for (; !it.done(); it.next()) {
424 it.rinfo()->Visit(v);
425 }
426}
427
428
429template<typename StaticVisitor>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000430void Code::CodeIterateBody(Heap* heap) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000431 int mode_mask = RelocInfo::kCodeTargetMask |
432 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000433 RelocInfo::ModeMask(RelocInfo::GLOBAL_PROPERTY_CELL) |
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000434 RelocInfo::ModeMask(RelocInfo::EXTERNAL_REFERENCE) |
435 RelocInfo::ModeMask(RelocInfo::JS_RETURN) |
436 RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT) |
437 RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY);
438
439 // Use the relocation info pointer before it is visited by
440 // the heap compaction in the next statement.
441 RelocIterator it(this, mode_mask);
442
443 StaticVisitor::VisitPointer(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000444 heap,
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000445 reinterpret_cast<Object**>(this->address() + kRelocationInfoOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000446 StaticVisitor::VisitPointer(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000447 heap,
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000448 reinterpret_cast<Object**>(this->address() + kDeoptimizationDataOffset));
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000449
450 for (; !it.done(); it.next()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000451 it.rinfo()->template Visit<StaticVisitor>(heap);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000452 }
453}
454
455
456} } // namespace v8::internal
457
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +0000458#endif // V8_OBJECTS_VISITING_H_