blob: ed76cb97ce6a995a062163b00a66ba61001affa5 [file] [log] [blame]
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001// Copyright 2006-2009 the V8 project authors. All rights reserved.
2// 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
31// This file provides base classes and auxiliary methods for defining
32// static object visitors used during GC.
33// Visiting HeapObject body with a normal ObjectVisitor requires performing
34// two switches on object's instance type to determine object size and layout
35// and one or more virtual method calls on visitor itself.
36// Static visitor is different: it provides a dispatch table which contains
37// pointers to specialized visit functions. Each map has the visitor_id
38// field which contains an index of specialized visitor to use.
39
40namespace v8 {
41namespace internal {
42
43
44// Base class for all static visitors.
45class StaticVisitorBase : public AllStatic {
46 public:
47 enum VisitorId {
48 kVisitSeqAsciiString = 0,
49 kVisitSeqTwoByteString,
50 kVisitShortcutCandidate,
51 kVisitByteArray,
52 kVisitFixedArray,
whesse@chromium.org4a5224e2010-10-20 12:37:07 +000053 kVisitGlobalContext,
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000054
55 // For data objects, JS objects and structs along with generic visitor which
56 // can visit object of any size we provide visitors specialized by
57 // object size in words.
58 // Ids of specialized visitors are declared in a linear order (without
59 // holes) starting from the id of visitor specialized for 2 words objects
60 // (base visitor id) and ending with the id of generic visitor.
61 // Method GetVisitorIdForSize depends on this ordering to calculate visitor
62 // id of specialized visitor from given instance size, base visitor id and
63 // generic visitor's id.
64
65 kVisitDataObject,
66 kVisitDataObject2 = kVisitDataObject,
67 kVisitDataObject3,
68 kVisitDataObject4,
69 kVisitDataObject5,
70 kVisitDataObject6,
71 kVisitDataObject7,
72 kVisitDataObject8,
73 kVisitDataObject9,
74 kVisitDataObjectGeneric,
75
76 kVisitJSObject,
77 kVisitJSObject2 = kVisitJSObject,
78 kVisitJSObject3,
79 kVisitJSObject4,
80 kVisitJSObject5,
81 kVisitJSObject6,
82 kVisitJSObject7,
83 kVisitJSObject8,
84 kVisitJSObject9,
85 kVisitJSObjectGeneric,
86
87 kVisitStruct,
88 kVisitStruct2 = kVisitStruct,
89 kVisitStruct3,
90 kVisitStruct4,
91 kVisitStruct5,
92 kVisitStruct6,
93 kVisitStruct7,
94 kVisitStruct8,
95 kVisitStruct9,
96 kVisitStructGeneric,
97
98 kVisitConsString,
99 kVisitOddball,
100 kVisitCode,
101 kVisitMap,
102 kVisitPropertyCell,
103 kVisitSharedFunctionInfo,
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000104 kVisitJSFunction,
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000105
106 kVisitorIdCount,
107 kMinObjectSizeInWords = 2
108 };
109
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000110 // Visitor ID should fit in one byte.
111 STATIC_ASSERT(kVisitorIdCount <= 256);
112
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000113 // Determine which specialized visitor should be used for given instance type
114 // and instance type.
115 static VisitorId GetVisitorId(int instance_type, int instance_size);
116
117 static VisitorId GetVisitorId(Map* map) {
118 return GetVisitorId(map->instance_type(), map->instance_size());
119 }
120
121 // For visitors that allow specialization by size calculate VisitorId based
122 // on size, base visitor id and generic visitor id.
123 static VisitorId GetVisitorIdForSize(VisitorId base,
124 VisitorId generic,
125 int object_size) {
126 ASSERT((base == kVisitDataObject) ||
127 (base == kVisitStruct) ||
128 (base == kVisitJSObject));
129 ASSERT(IsAligned(object_size, kPointerSize));
130 ASSERT(kMinObjectSizeInWords * kPointerSize <= object_size);
131 ASSERT(object_size < Page::kMaxHeapObjectSize);
132
133 const VisitorId specialization = static_cast<VisitorId>(
134 base + (object_size >> kPointerSizeLog2) - kMinObjectSizeInWords);
135
136 return Min(specialization, generic);
137 }
138};
139
140
141template<typename Callback>
142class VisitorDispatchTable {
143 public:
144 inline Callback GetVisitor(Map* map) {
145 return callbacks_[map->visitor_id()];
146 }
147
148 void Register(StaticVisitorBase::VisitorId id, Callback callback) {
149 ASSERT((0 <= id) && (id < StaticVisitorBase::kVisitorIdCount));
150 callbacks_[id] = callback;
151 }
152
153 template<typename Visitor,
154 StaticVisitorBase::VisitorId base,
155 StaticVisitorBase::VisitorId generic,
156 int object_size_in_words>
157 void RegisterSpecialization() {
158 static const int size = object_size_in_words * kPointerSize;
159 Register(StaticVisitorBase::GetVisitorIdForSize(base, generic, size),
160 &Visitor::template VisitSpecialized<size>);
161 }
162
163
164 template<typename Visitor,
165 StaticVisitorBase::VisitorId base,
166 StaticVisitorBase::VisitorId generic>
167 void RegisterSpecializations() {
168 STATIC_ASSERT(
169 (generic - base + StaticVisitorBase::kMinObjectSizeInWords) == 10);
170 RegisterSpecialization<Visitor, base, generic, 2>();
171 RegisterSpecialization<Visitor, base, generic, 3>();
172 RegisterSpecialization<Visitor, base, generic, 4>();
173 RegisterSpecialization<Visitor, base, generic, 5>();
174 RegisterSpecialization<Visitor, base, generic, 6>();
175 RegisterSpecialization<Visitor, base, generic, 7>();
176 RegisterSpecialization<Visitor, base, generic, 8>();
177 RegisterSpecialization<Visitor, base, generic, 9>();
178 Register(generic, &Visitor::Visit);
179 }
180
181 private:
182 Callback callbacks_[StaticVisitorBase::kVisitorIdCount];
183};
184
185
186template<typename StaticVisitor>
187class BodyVisitorBase : public AllStatic {
188 public:
189 static inline void IteratePointers(HeapObject* object,
190 int start_offset,
191 int end_offset) {
192 Object** start_slot = reinterpret_cast<Object**>(object->address() +
193 start_offset);
194 Object** end_slot = reinterpret_cast<Object**>(object->address() +
195 end_offset);
196 StaticVisitor::VisitPointers(start_slot, end_slot);
197 }
198};
199
200
201template<typename StaticVisitor, typename BodyDescriptor, typename ReturnType>
202class FlexibleBodyVisitor : public BodyVisitorBase<StaticVisitor> {
203 public:
204 static inline ReturnType Visit(Map* map, HeapObject* object) {
205 int object_size = BodyDescriptor::SizeOf(map, object);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000206 BodyVisitorBase<StaticVisitor>::IteratePointers(
207 object, BodyDescriptor::kStartOffset, object_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000208 return static_cast<ReturnType>(object_size);
209 }
210
211 template<int object_size>
212 static inline ReturnType VisitSpecialized(Map* map, HeapObject* object) {
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000213 ASSERT(BodyDescriptor::SizeOf(map, object) == object_size);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000214 BodyVisitorBase<StaticVisitor>::IteratePointers(
215 object, BodyDescriptor::kStartOffset, object_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000216 return static_cast<ReturnType>(object_size);
217 }
218};
219
220
221template<typename StaticVisitor, typename BodyDescriptor, typename ReturnType>
222class FixedBodyVisitor : public BodyVisitorBase<StaticVisitor> {
223 public:
224 static inline ReturnType Visit(Map* map, HeapObject* object) {
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000225 BodyVisitorBase<StaticVisitor>::IteratePointers(
226 object, BodyDescriptor::kStartOffset, BodyDescriptor::kEndOffset);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000227 return static_cast<ReturnType>(BodyDescriptor::kSize);
228 }
229};
230
231
232// Base class for visitors used for a linear new space iteration.
233// IterateBody returns size of visited object.
234// Certain types of objects (i.e. Code objects) are not handled
235// by dispatch table of this visitor because they cannot appear
236// in the new space.
237//
238// This class is intended to be used in the following way:
239//
240// class SomeVisitor : public StaticNewSpaceVisitor<SomeVisitor> {
241// ...
242// }
243//
244// This is an example of Curiously recurring template pattern
245// (see http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern).
246// We use CRTP to guarantee aggressive compile time optimizations (i.e.
247// inlining and specialization of StaticVisitor::VisitPointers methods).
248template<typename StaticVisitor>
249class StaticNewSpaceVisitor : public StaticVisitorBase {
250 public:
251 static void Initialize() {
252 table_.Register(kVisitShortcutCandidate,
253 &FixedBodyVisitor<StaticVisitor,
254 ConsString::BodyDescriptor,
255 int>::Visit);
256
257 table_.Register(kVisitConsString,
258 &FixedBodyVisitor<StaticVisitor,
259 ConsString::BodyDescriptor,
260 int>::Visit);
261
262 table_.Register(kVisitFixedArray,
263 &FlexibleBodyVisitor<StaticVisitor,
264 FixedArray::BodyDescriptor,
265 int>::Visit);
266
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000267 table_.Register(kVisitGlobalContext,
268 &FixedBodyVisitor<StaticVisitor,
269 Context::ScavengeBodyDescriptor,
270 int>::Visit);
271
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000272 table_.Register(kVisitByteArray, &VisitByteArray);
273
274 table_.Register(kVisitSharedFunctionInfo,
275 &FixedBodyVisitor<StaticVisitor,
276 SharedFunctionInfo::BodyDescriptor,
277 int>::Visit);
278
279 table_.Register(kVisitSeqAsciiString, &VisitSeqAsciiString);
280
281 table_.Register(kVisitSeqTwoByteString, &VisitSeqTwoByteString);
282
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000283 table_.Register(kVisitJSFunction,
284 &JSObjectVisitor::
285 template VisitSpecialized<JSFunction::kSize>);
286
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000287 table_.RegisterSpecializations<DataObjectVisitor,
288 kVisitDataObject,
289 kVisitDataObjectGeneric>();
290 table_.RegisterSpecializations<JSObjectVisitor,
291 kVisitJSObject,
292 kVisitJSObjectGeneric>();
293 table_.RegisterSpecializations<StructVisitor,
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000294 kVisitStruct,
295 kVisitStructGeneric>();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000296 }
297
298 static inline int IterateBody(Map* map, HeapObject* obj) {
299 return table_.GetVisitor(map)(map, obj);
300 }
301
302 static inline void VisitPointers(Object** start, Object** end) {
303 for (Object** p = start; p < end; p++) StaticVisitor::VisitPointer(p);
304 }
305
306 private:
307 static inline int VisitByteArray(Map* map, HeapObject* object) {
308 return reinterpret_cast<ByteArray*>(object)->ByteArraySize();
309 }
310
311 static inline int VisitSeqAsciiString(Map* map, HeapObject* object) {
312 return SeqAsciiString::cast(object)->
313 SeqAsciiStringSize(map->instance_type());
314 }
315
316 static inline int VisitSeqTwoByteString(Map* map, HeapObject* object) {
317 return SeqTwoByteString::cast(object)->
318 SeqTwoByteStringSize(map->instance_type());
319 }
320
321 class DataObjectVisitor {
322 public:
323 template<int object_size>
324 static inline int VisitSpecialized(Map* map, HeapObject* object) {
325 return object_size;
326 }
327
328 static inline int Visit(Map* map, HeapObject* object) {
329 return map->instance_size();
330 }
331 };
332
333 typedef FlexibleBodyVisitor<StaticVisitor,
334 StructBodyDescriptor,
335 int> StructVisitor;
336
337 typedef FlexibleBodyVisitor<StaticVisitor,
338 JSObject::BodyDescriptor,
339 int> JSObjectVisitor;
340
341 typedef int (*Callback)(Map* map, HeapObject* object);
342
343 static VisitorDispatchTable<Callback> table_;
344};
345
346
347template<typename StaticVisitor>
348VisitorDispatchTable<typename StaticNewSpaceVisitor<StaticVisitor>::Callback>
349 StaticNewSpaceVisitor<StaticVisitor>::table_;
350
351
352void Code::CodeIterateBody(ObjectVisitor* v) {
353 int mode_mask = RelocInfo::kCodeTargetMask |
354 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
355 RelocInfo::ModeMask(RelocInfo::EXTERNAL_REFERENCE) |
356 RelocInfo::ModeMask(RelocInfo::JS_RETURN) |
357 RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT) |
358 RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY);
359
360 // Use the relocation info pointer before it is visited by
361 // the heap compaction in the next statement.
362 RelocIterator it(this, mode_mask);
363
364 IteratePointers(v,
365 kRelocationInfoOffset,
366 kRelocationInfoOffset + kPointerSize);
367
368 for (; !it.done(); it.next()) {
369 it.rinfo()->Visit(v);
370 }
371}
372
373
374template<typename StaticVisitor>
375void Code::CodeIterateBody() {
376 int mode_mask = RelocInfo::kCodeTargetMask |
377 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
378 RelocInfo::ModeMask(RelocInfo::EXTERNAL_REFERENCE) |
379 RelocInfo::ModeMask(RelocInfo::JS_RETURN) |
380 RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT) |
381 RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY);
382
383 // Use the relocation info pointer before it is visited by
384 // the heap compaction in the next statement.
385 RelocIterator it(this, mode_mask);
386
387 StaticVisitor::VisitPointer(
388 reinterpret_cast<Object**>(this->address() + kRelocationInfoOffset));
389
390 for (; !it.done(); it.next()) {
391 it.rinfo()->template Visit<StaticVisitor>();
392 }
393}
394
395
396} } // namespace v8::internal
397
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +0000398#endif // V8_OBJECTS_VISITING_H_