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_INL_H_
6 #define V8_OBJECTS_VISITING_INL_H_
7
8
9 namespace v8 {
10 namespace internal {
11
12 template<typename StaticVisitor>
Initialize()13 void StaticNewSpaceVisitor<StaticVisitor>::Initialize() {
14 table_.Register(kVisitShortcutCandidate,
15 &FixedBodyVisitor<StaticVisitor,
16 ConsString::BodyDescriptor,
17 int>::Visit);
18
19 table_.Register(kVisitConsString,
20 &FixedBodyVisitor<StaticVisitor,
21 ConsString::BodyDescriptor,
22 int>::Visit);
23
24 table_.Register(kVisitSlicedString,
25 &FixedBodyVisitor<StaticVisitor,
26 SlicedString::BodyDescriptor,
27 int>::Visit);
28
29 table_.Register(kVisitSymbol,
30 &FixedBodyVisitor<StaticVisitor,
31 Symbol::BodyDescriptor,
32 int>::Visit);
33
34 table_.Register(kVisitFixedArray,
35 &FlexibleBodyVisitor<StaticVisitor,
36 FixedArray::BodyDescriptor,
37 int>::Visit);
38
39 table_.Register(kVisitFixedDoubleArray, &VisitFixedDoubleArray);
40 table_.Register(kVisitFixedTypedArray, &VisitFixedTypedArray);
41 table_.Register(kVisitFixedFloat64Array, &VisitFixedTypedArray);
42
43 table_.Register(kVisitNativeContext,
44 &FixedBodyVisitor<StaticVisitor,
45 Context::ScavengeBodyDescriptor,
46 int>::Visit);
47
48 table_.Register(kVisitByteArray, &VisitByteArray);
49
50 table_.Register(kVisitSharedFunctionInfo,
51 &FixedBodyVisitor<StaticVisitor,
52 SharedFunctionInfo::BodyDescriptor,
53 int>::Visit);
54
55 table_.Register(kVisitSeqOneByteString, &VisitSeqOneByteString);
56
57 table_.Register(kVisitSeqTwoByteString, &VisitSeqTwoByteString);
58
59 table_.Register(kVisitJSFunction, &VisitJSFunction);
60
61 table_.Register(kVisitJSArrayBuffer, &VisitJSArrayBuffer);
62
63 table_.Register(kVisitJSTypedArray, &VisitJSTypedArray);
64
65 table_.Register(kVisitJSDataView, &VisitJSDataView);
66
67 table_.Register(kVisitFreeSpace, &VisitFreeSpace);
68
69 table_.Register(kVisitJSWeakCollection, &JSObjectVisitor::Visit);
70
71 table_.Register(kVisitJSRegExp, &JSObjectVisitor::Visit);
72
73 table_.template RegisterSpecializations<DataObjectVisitor,
74 kVisitDataObject,
75 kVisitDataObjectGeneric>();
76
77 table_.template RegisterSpecializations<JSObjectVisitor,
78 kVisitJSObject,
79 kVisitJSObjectGeneric>();
80 table_.template RegisterSpecializations<StructVisitor,
81 kVisitStruct,
82 kVisitStructGeneric>();
83 }
84
85
86 template<typename StaticVisitor>
VisitJSArrayBuffer(Map * map,HeapObject * object)87 int StaticNewSpaceVisitor<StaticVisitor>::VisitJSArrayBuffer(
88 Map* map, HeapObject* object) {
89 Heap* heap = map->GetHeap();
90
91 STATIC_ASSERT(
92 JSArrayBuffer::kWeakFirstViewOffset ==
93 JSArrayBuffer::kWeakNextOffset + kPointerSize);
94 VisitPointers(
95 heap,
96 HeapObject::RawField(object, JSArrayBuffer::BodyDescriptor::kStartOffset),
97 HeapObject::RawField(object, JSArrayBuffer::kWeakNextOffset));
98 VisitPointers(
99 heap,
100 HeapObject::RawField(object,
101 JSArrayBuffer::kWeakNextOffset + 2 * kPointerSize),
102 HeapObject::RawField(object, JSArrayBuffer::kSizeWithInternalFields));
103 return JSArrayBuffer::kSizeWithInternalFields;
104 }
105
106
107 template<typename StaticVisitor>
VisitJSTypedArray(Map * map,HeapObject * object)108 int StaticNewSpaceVisitor<StaticVisitor>::VisitJSTypedArray(
109 Map* map, HeapObject* object) {
110 VisitPointers(
111 map->GetHeap(),
112 HeapObject::RawField(object, JSTypedArray::BodyDescriptor::kStartOffset),
113 HeapObject::RawField(object, JSTypedArray::kWeakNextOffset));
114 VisitPointers(
115 map->GetHeap(),
116 HeapObject::RawField(object,
117 JSTypedArray::kWeakNextOffset + kPointerSize),
118 HeapObject::RawField(object, JSTypedArray::kSizeWithInternalFields));
119 return JSTypedArray::kSizeWithInternalFields;
120 }
121
122
123 template<typename StaticVisitor>
VisitJSDataView(Map * map,HeapObject * object)124 int StaticNewSpaceVisitor<StaticVisitor>::VisitJSDataView(
125 Map* map, HeapObject* object) {
126 VisitPointers(
127 map->GetHeap(),
128 HeapObject::RawField(object, JSDataView::BodyDescriptor::kStartOffset),
129 HeapObject::RawField(object, JSDataView::kWeakNextOffset));
130 VisitPointers(
131 map->GetHeap(),
132 HeapObject::RawField(object,
133 JSDataView::kWeakNextOffset + kPointerSize),
134 HeapObject::RawField(object, JSDataView::kSizeWithInternalFields));
135 return JSDataView::kSizeWithInternalFields;
136 }
137
138
139 template<typename StaticVisitor>
Initialize()140 void StaticMarkingVisitor<StaticVisitor>::Initialize() {
141 table_.Register(kVisitShortcutCandidate,
142 &FixedBodyVisitor<StaticVisitor,
143 ConsString::BodyDescriptor,
144 void>::Visit);
145
146 table_.Register(kVisitConsString,
147 &FixedBodyVisitor<StaticVisitor,
148 ConsString::BodyDescriptor,
149 void>::Visit);
150
151 table_.Register(kVisitSlicedString,
152 &FixedBodyVisitor<StaticVisitor,
153 SlicedString::BodyDescriptor,
154 void>::Visit);
155
156 table_.Register(kVisitSymbol,
157 &FixedBodyVisitor<StaticVisitor,
158 Symbol::BodyDescriptor,
159 void>::Visit);
160
161 table_.Register(kVisitFixedArray, &FixedArrayVisitor::Visit);
162
163 table_.Register(kVisitFixedDoubleArray, &DataObjectVisitor::Visit);
164
165 table_.Register(kVisitFixedTypedArray, &DataObjectVisitor::Visit);
166
167 table_.Register(kVisitFixedFloat64Array, &DataObjectVisitor::Visit);
168
169 table_.Register(kVisitConstantPoolArray, &VisitConstantPoolArray);
170
171 table_.Register(kVisitNativeContext, &VisitNativeContext);
172
173 table_.Register(kVisitAllocationSite, &VisitAllocationSite);
174
175 table_.Register(kVisitByteArray, &DataObjectVisitor::Visit);
176
177 table_.Register(kVisitFreeSpace, &DataObjectVisitor::Visit);
178
179 table_.Register(kVisitSeqOneByteString, &DataObjectVisitor::Visit);
180
181 table_.Register(kVisitSeqTwoByteString, &DataObjectVisitor::Visit);
182
183 table_.Register(kVisitJSWeakCollection, &VisitWeakCollection);
184
185 table_.Register(kVisitOddball,
186 &FixedBodyVisitor<StaticVisitor,
187 Oddball::BodyDescriptor,
188 void>::Visit);
189
190 table_.Register(kVisitMap, &VisitMap);
191
192 table_.Register(kVisitCode, &VisitCode);
193
194 table_.Register(kVisitSharedFunctionInfo, &VisitSharedFunctionInfo);
195
196 table_.Register(kVisitJSFunction, &VisitJSFunction);
197
198 table_.Register(kVisitJSArrayBuffer, &VisitJSArrayBuffer);
199
200 table_.Register(kVisitJSTypedArray, &VisitJSTypedArray);
201
202 table_.Register(kVisitJSDataView, &VisitJSDataView);
203
204 // Registration for kVisitJSRegExp is done by StaticVisitor.
205
206 table_.Register(kVisitCell,
207 &FixedBodyVisitor<StaticVisitor,
208 Cell::BodyDescriptor,
209 void>::Visit);
210
211 table_.Register(kVisitPropertyCell, &VisitPropertyCell);
212
213 table_.template RegisterSpecializations<DataObjectVisitor,
214 kVisitDataObject,
215 kVisitDataObjectGeneric>();
216
217 table_.template RegisterSpecializations<JSObjectVisitor,
218 kVisitJSObject,
219 kVisitJSObjectGeneric>();
220
221 table_.template RegisterSpecializations<StructObjectVisitor,
222 kVisitStruct,
223 kVisitStructGeneric>();
224 }
225
226
227 template<typename StaticVisitor>
VisitCodeEntry(Heap * heap,Address entry_address)228 void StaticMarkingVisitor<StaticVisitor>::VisitCodeEntry(
229 Heap* heap, Address entry_address) {
230 Code* code = Code::cast(Code::GetObjectFromEntryAddress(entry_address));
231 heap->mark_compact_collector()->RecordCodeEntrySlot(entry_address, code);
232 StaticVisitor::MarkObject(heap, code);
233 }
234
235
236 template<typename StaticVisitor>
VisitEmbeddedPointer(Heap * heap,RelocInfo * rinfo)237 void StaticMarkingVisitor<StaticVisitor>::VisitEmbeddedPointer(
238 Heap* heap, RelocInfo* rinfo) {
239 ASSERT(rinfo->rmode() == RelocInfo::EMBEDDED_OBJECT);
240 ASSERT(!rinfo->target_object()->IsConsString());
241 HeapObject* object = HeapObject::cast(rinfo->target_object());
242 heap->mark_compact_collector()->RecordRelocSlot(rinfo, object);
243 // TODO(ulan): It could be better to record slots only for strongly embedded
244 // objects here and record slots for weakly embedded object during clearing
245 // of non-live references in mark-compact.
246 if (!rinfo->host()->IsWeakObject(object)) {
247 StaticVisitor::MarkObject(heap, object);
248 }
249 }
250
251
252 template<typename StaticVisitor>
VisitCell(Heap * heap,RelocInfo * rinfo)253 void StaticMarkingVisitor<StaticVisitor>::VisitCell(
254 Heap* heap, RelocInfo* rinfo) {
255 ASSERT(rinfo->rmode() == RelocInfo::CELL);
256 Cell* cell = rinfo->target_cell();
257 // No need to record slots because the cell space is not compacted during GC.
258 if (!rinfo->host()->IsWeakObject(cell)) {
259 StaticVisitor::MarkObject(heap, cell);
260 }
261 }
262
263
264 template<typename StaticVisitor>
VisitDebugTarget(Heap * heap,RelocInfo * rinfo)265 void StaticMarkingVisitor<StaticVisitor>::VisitDebugTarget(
266 Heap* heap, RelocInfo* rinfo) {
267 ASSERT((RelocInfo::IsJSReturn(rinfo->rmode()) &&
268 rinfo->IsPatchedReturnSequence()) ||
269 (RelocInfo::IsDebugBreakSlot(rinfo->rmode()) &&
270 rinfo->IsPatchedDebugBreakSlotSequence()));
271 Code* target = Code::GetCodeFromTargetAddress(rinfo->call_address());
272 heap->mark_compact_collector()->RecordRelocSlot(rinfo, target);
273 StaticVisitor::MarkObject(heap, target);
274 }
275
276
277 template<typename StaticVisitor>
VisitCodeTarget(Heap * heap,RelocInfo * rinfo)278 void StaticMarkingVisitor<StaticVisitor>::VisitCodeTarget(
279 Heap* heap, RelocInfo* rinfo) {
280 ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
281 Code* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
282 // Monomorphic ICs are preserved when possible, but need to be flushed
283 // when they might be keeping a Context alive, or when the heap is about
284 // to be serialized.
285 if (FLAG_cleanup_code_caches_at_gc && target->is_inline_cache_stub()
286 && (target->ic_state() == MEGAMORPHIC || target->ic_state() == GENERIC ||
287 target->ic_state() == POLYMORPHIC || heap->flush_monomorphic_ics() ||
288 heap->isolate()->serializer_enabled() ||
289 target->ic_age() != heap->global_ic_age() ||
290 target->is_invalidated_weak_stub())) {
291 IC::Clear(heap->isolate(), rinfo->pc(), rinfo->host()->constant_pool());
292 target = Code::GetCodeFromTargetAddress(rinfo->target_address());
293 }
294 heap->mark_compact_collector()->RecordRelocSlot(rinfo, target);
295 StaticVisitor::MarkObject(heap, target);
296 }
297
298
299 template<typename StaticVisitor>
VisitCodeAgeSequence(Heap * heap,RelocInfo * rinfo)300 void StaticMarkingVisitor<StaticVisitor>::VisitCodeAgeSequence(
301 Heap* heap, RelocInfo* rinfo) {
302 ASSERT(RelocInfo::IsCodeAgeSequence(rinfo->rmode()));
303 Code* target = rinfo->code_age_stub();
304 ASSERT(target != NULL);
305 heap->mark_compact_collector()->RecordRelocSlot(rinfo, target);
306 StaticVisitor::MarkObject(heap, target);
307 }
308
309
310 template<typename StaticVisitor>
VisitNativeContext(Map * map,HeapObject * object)311 void StaticMarkingVisitor<StaticVisitor>::VisitNativeContext(
312 Map* map, HeapObject* object) {
313 FixedBodyVisitor<StaticVisitor,
314 Context::MarkCompactBodyDescriptor,
315 void>::Visit(map, object);
316
317 MarkCompactCollector* collector = map->GetHeap()->mark_compact_collector();
318 for (int idx = Context::FIRST_WEAK_SLOT;
319 idx < Context::NATIVE_CONTEXT_SLOTS;
320 ++idx) {
321 Object** slot = Context::cast(object)->RawFieldOfElementAt(idx);
322 collector->RecordSlot(slot, slot, *slot);
323 }
324 }
325
326
327 template<typename StaticVisitor>
VisitMap(Map * map,HeapObject * object)328 void StaticMarkingVisitor<StaticVisitor>::VisitMap(
329 Map* map, HeapObject* object) {
330 Heap* heap = map->GetHeap();
331 Map* map_object = Map::cast(object);
332
333 // Clears the cache of ICs related to this map.
334 if (FLAG_cleanup_code_caches_at_gc) {
335 map_object->ClearCodeCache(heap);
336 }
337
338 // When map collection is enabled we have to mark through map's transitions
339 // and back pointers in a special way to make these links weak.
340 if (FLAG_collect_maps && map_object->CanTransition()) {
341 MarkMapContents(heap, map_object);
342 } else {
343 StaticVisitor::VisitPointers(heap,
344 HeapObject::RawField(object, Map::kPointerFieldsBeginOffset),
345 HeapObject::RawField(object, Map::kPointerFieldsEndOffset));
346 }
347 }
348
349
350 template<typename StaticVisitor>
VisitPropertyCell(Map * map,HeapObject * object)351 void StaticMarkingVisitor<StaticVisitor>::VisitPropertyCell(
352 Map* map, HeapObject* object) {
353 Heap* heap = map->GetHeap();
354
355 Object** slot =
356 HeapObject::RawField(object, PropertyCell::kDependentCodeOffset);
357 if (FLAG_collect_maps) {
358 // Mark property cell dependent codes array but do not push it onto marking
359 // stack, this will make references from it weak. We will clean dead
360 // codes when we iterate over property cells in ClearNonLiveReferences.
361 HeapObject* obj = HeapObject::cast(*slot);
362 heap->mark_compact_collector()->RecordSlot(slot, slot, obj);
363 StaticVisitor::MarkObjectWithoutPush(heap, obj);
364 } else {
365 StaticVisitor::VisitPointer(heap, slot);
366 }
367
368 StaticVisitor::VisitPointers(heap,
369 HeapObject::RawField(object, PropertyCell::kPointerFieldsBeginOffset),
370 HeapObject::RawField(object, PropertyCell::kPointerFieldsEndOffset));
371 }
372
373
374 template<typename StaticVisitor>
VisitAllocationSite(Map * map,HeapObject * object)375 void StaticMarkingVisitor<StaticVisitor>::VisitAllocationSite(
376 Map* map, HeapObject* object) {
377 Heap* heap = map->GetHeap();
378
379 Object** slot =
380 HeapObject::RawField(object, AllocationSite::kDependentCodeOffset);
381 if (FLAG_collect_maps) {
382 // Mark allocation site dependent codes array but do not push it onto
383 // marking stack, this will make references from it weak. We will clean
384 // dead codes when we iterate over allocation sites in
385 // ClearNonLiveReferences.
386 HeapObject* obj = HeapObject::cast(*slot);
387 heap->mark_compact_collector()->RecordSlot(slot, slot, obj);
388 StaticVisitor::MarkObjectWithoutPush(heap, obj);
389 } else {
390 StaticVisitor::VisitPointer(heap, slot);
391 }
392
393 StaticVisitor::VisitPointers(heap,
394 HeapObject::RawField(object, AllocationSite::kPointerFieldsBeginOffset),
395 HeapObject::RawField(object, AllocationSite::kPointerFieldsEndOffset));
396 }
397
398
399 template<typename StaticVisitor>
VisitWeakCollection(Map * map,HeapObject * object)400 void StaticMarkingVisitor<StaticVisitor>::VisitWeakCollection(
401 Map* map, HeapObject* object) {
402 Heap* heap = map->GetHeap();
403 JSWeakCollection* weak_collection =
404 reinterpret_cast<JSWeakCollection*>(object);
405
406 // Enqueue weak collection in linked list of encountered weak collections.
407 if (weak_collection->next() == heap->undefined_value()) {
408 weak_collection->set_next(heap->encountered_weak_collections());
409 heap->set_encountered_weak_collections(weak_collection);
410 }
411
412 // Skip visiting the backing hash table containing the mappings and the
413 // pointer to the other enqueued weak collections, both are post-processed.
414 StaticVisitor::VisitPointers(heap,
415 HeapObject::RawField(object, JSWeakCollection::kPropertiesOffset),
416 HeapObject::RawField(object, JSWeakCollection::kTableOffset));
417 STATIC_ASSERT(JSWeakCollection::kTableOffset + kPointerSize ==
418 JSWeakCollection::kNextOffset);
419 STATIC_ASSERT(JSWeakCollection::kNextOffset + kPointerSize ==
420 JSWeakCollection::kSize);
421
422 // Partially initialized weak collection is enqueued, but table is ignored.
423 if (!weak_collection->table()->IsHashTable()) return;
424
425 // Mark the backing hash table without pushing it on the marking stack.
426 Object** slot = HeapObject::RawField(object, JSWeakCollection::kTableOffset);
427 HeapObject* obj = HeapObject::cast(*slot);
428 heap->mark_compact_collector()->RecordSlot(slot, slot, obj);
429 StaticVisitor::MarkObjectWithoutPush(heap, obj);
430 }
431
432
433 template<typename StaticVisitor>
VisitCode(Map * map,HeapObject * object)434 void StaticMarkingVisitor<StaticVisitor>::VisitCode(
435 Map* map, HeapObject* object) {
436 Heap* heap = map->GetHeap();
437 Code* code = Code::cast(object);
438 if (FLAG_age_code && !heap->isolate()->serializer_enabled()) {
439 code->MakeOlder(heap->mark_compact_collector()->marking_parity());
440 }
441 code->CodeIterateBody<StaticVisitor>(heap);
442 }
443
444
445 template<typename StaticVisitor>
VisitSharedFunctionInfo(Map * map,HeapObject * object)446 void StaticMarkingVisitor<StaticVisitor>::VisitSharedFunctionInfo(
447 Map* map, HeapObject* object) {
448 Heap* heap = map->GetHeap();
449 SharedFunctionInfo* shared = SharedFunctionInfo::cast(object);
450 if (shared->ic_age() != heap->global_ic_age()) {
451 shared->ResetForNewContext(heap->global_ic_age());
452 }
453 if (FLAG_cleanup_code_caches_at_gc) {
454 shared->ClearTypeFeedbackInfo();
455 }
456 if (FLAG_cache_optimized_code &&
457 FLAG_flush_optimized_code_cache &&
458 !shared->optimized_code_map()->IsSmi()) {
459 // Always flush the optimized code map if requested by flag.
460 shared->ClearOptimizedCodeMap();
461 }
462 MarkCompactCollector* collector = heap->mark_compact_collector();
463 if (collector->is_code_flushing_enabled()) {
464 if (FLAG_cache_optimized_code && !shared->optimized_code_map()->IsSmi()) {
465 // Add the shared function info holding an optimized code map to
466 // the code flusher for processing of code maps after marking.
467 collector->code_flusher()->AddOptimizedCodeMap(shared);
468 // Treat all references within the code map weakly by marking the
469 // code map itself but not pushing it onto the marking deque.
470 FixedArray* code_map = FixedArray::cast(shared->optimized_code_map());
471 StaticVisitor::MarkObjectWithoutPush(heap, code_map);
472 }
473 if (IsFlushable(heap, shared)) {
474 // This function's code looks flushable. But we have to postpone
475 // the decision until we see all functions that point to the same
476 // SharedFunctionInfo because some of them might be optimized.
477 // That would also make the non-optimized version of the code
478 // non-flushable, because it is required for bailing out from
479 // optimized code.
480 collector->code_flusher()->AddCandidate(shared);
481 // Treat the reference to the code object weakly.
482 VisitSharedFunctionInfoWeakCode(heap, object);
483 return;
484 }
485 } else {
486 if (FLAG_cache_optimized_code && !shared->optimized_code_map()->IsSmi()) {
487 // Flush optimized code map on major GCs without code flushing,
488 // needed because cached code doesn't contain breakpoints.
489 shared->ClearOptimizedCodeMap();
490 }
491 }
492 VisitSharedFunctionInfoStrongCode(heap, object);
493 }
494
495
496 template<typename StaticVisitor>
VisitConstantPoolArray(Map * map,HeapObject * object)497 void StaticMarkingVisitor<StaticVisitor>::VisitConstantPoolArray(
498 Map* map, HeapObject* object) {
499 Heap* heap = map->GetHeap();
500 ConstantPoolArray* array = ConstantPoolArray::cast(object);
501 ConstantPoolArray::Iterator code_iter(array, ConstantPoolArray::CODE_PTR);
502 while (!code_iter.is_finished()) {
503 Address code_entry = reinterpret_cast<Address>(
504 array->RawFieldOfElementAt(code_iter.next_index()));
505 StaticVisitor::VisitCodeEntry(heap, code_entry);
506 }
507
508 ConstantPoolArray::Iterator heap_iter(array, ConstantPoolArray::HEAP_PTR);
509 while (!heap_iter.is_finished()) {
510 Object** slot = array->RawFieldOfElementAt(heap_iter.next_index());
511 HeapObject* object = HeapObject::cast(*slot);
512 heap->mark_compact_collector()->RecordSlot(slot, slot, object);
513 bool is_weak_object =
514 (array->get_weak_object_state() ==
515 ConstantPoolArray::WEAK_OBJECTS_IN_OPTIMIZED_CODE &&
516 Code::IsWeakObjectInOptimizedCode(object)) ||
517 (array->get_weak_object_state() ==
518 ConstantPoolArray::WEAK_OBJECTS_IN_IC &&
519 Code::IsWeakObjectInIC(object));
520 if (!is_weak_object) {
521 StaticVisitor::MarkObject(heap, object);
522 }
523 }
524 }
525
526
527 template<typename StaticVisitor>
VisitJSFunction(Map * map,HeapObject * object)528 void StaticMarkingVisitor<StaticVisitor>::VisitJSFunction(
529 Map* map, HeapObject* object) {
530 Heap* heap = map->GetHeap();
531 JSFunction* function = JSFunction::cast(object);
532 MarkCompactCollector* collector = heap->mark_compact_collector();
533 if (collector->is_code_flushing_enabled()) {
534 if (IsFlushable(heap, function)) {
535 // This function's code looks flushable. But we have to postpone
536 // the decision until we see all functions that point to the same
537 // SharedFunctionInfo because some of them might be optimized.
538 // That would also make the non-optimized version of the code
539 // non-flushable, because it is required for bailing out from
540 // optimized code.
541 collector->code_flusher()->AddCandidate(function);
542 // Visit shared function info immediately to avoid double checking
543 // of its flushability later. This is just an optimization because
544 // the shared function info would eventually be visited.
545 SharedFunctionInfo* shared = function->shared();
546 if (StaticVisitor::MarkObjectWithoutPush(heap, shared)) {
547 StaticVisitor::MarkObject(heap, shared->map());
548 VisitSharedFunctionInfoWeakCode(heap, shared);
549 }
550 // Treat the reference to the code object weakly.
551 VisitJSFunctionWeakCode(heap, object);
552 return;
553 } else {
554 // Visit all unoptimized code objects to prevent flushing them.
555 StaticVisitor::MarkObject(heap, function->shared()->code());
556 if (function->code()->kind() == Code::OPTIMIZED_FUNCTION) {
557 MarkInlinedFunctionsCode(heap, function->code());
558 }
559 }
560 }
561 VisitJSFunctionStrongCode(heap, object);
562 }
563
564
565 template<typename StaticVisitor>
VisitJSRegExp(Map * map,HeapObject * object)566 void StaticMarkingVisitor<StaticVisitor>::VisitJSRegExp(
567 Map* map, HeapObject* object) {
568 int last_property_offset =
569 JSRegExp::kSize + kPointerSize * map->inobject_properties();
570 StaticVisitor::VisitPointers(map->GetHeap(),
571 HeapObject::RawField(object, JSRegExp::kPropertiesOffset),
572 HeapObject::RawField(object, last_property_offset));
573 }
574
575
576 template<typename StaticVisitor>
VisitJSArrayBuffer(Map * map,HeapObject * object)577 void StaticMarkingVisitor<StaticVisitor>::VisitJSArrayBuffer(
578 Map* map, HeapObject* object) {
579 Heap* heap = map->GetHeap();
580
581 STATIC_ASSERT(
582 JSArrayBuffer::kWeakFirstViewOffset ==
583 JSArrayBuffer::kWeakNextOffset + kPointerSize);
584 StaticVisitor::VisitPointers(
585 heap,
586 HeapObject::RawField(object, JSArrayBuffer::BodyDescriptor::kStartOffset),
587 HeapObject::RawField(object, JSArrayBuffer::kWeakNextOffset));
588 StaticVisitor::VisitPointers(
589 heap,
590 HeapObject::RawField(object,
591 JSArrayBuffer::kWeakNextOffset + 2 * kPointerSize),
592 HeapObject::RawField(object, JSArrayBuffer::kSizeWithInternalFields));
593 }
594
595
596 template<typename StaticVisitor>
VisitJSTypedArray(Map * map,HeapObject * object)597 void StaticMarkingVisitor<StaticVisitor>::VisitJSTypedArray(
598 Map* map, HeapObject* object) {
599 StaticVisitor::VisitPointers(
600 map->GetHeap(),
601 HeapObject::RawField(object, JSTypedArray::BodyDescriptor::kStartOffset),
602 HeapObject::RawField(object, JSTypedArray::kWeakNextOffset));
603 StaticVisitor::VisitPointers(
604 map->GetHeap(),
605 HeapObject::RawField(object,
606 JSTypedArray::kWeakNextOffset + kPointerSize),
607 HeapObject::RawField(object, JSTypedArray::kSizeWithInternalFields));
608 }
609
610
611 template<typename StaticVisitor>
VisitJSDataView(Map * map,HeapObject * object)612 void StaticMarkingVisitor<StaticVisitor>::VisitJSDataView(
613 Map* map, HeapObject* object) {
614 StaticVisitor::VisitPointers(
615 map->GetHeap(),
616 HeapObject::RawField(object, JSDataView::BodyDescriptor::kStartOffset),
617 HeapObject::RawField(object, JSDataView::kWeakNextOffset));
618 StaticVisitor::VisitPointers(
619 map->GetHeap(),
620 HeapObject::RawField(object,
621 JSDataView::kWeakNextOffset + kPointerSize),
622 HeapObject::RawField(object, JSDataView::kSizeWithInternalFields));
623 }
624
625
626 template<typename StaticVisitor>
MarkMapContents(Heap * heap,Map * map)627 void StaticMarkingVisitor<StaticVisitor>::MarkMapContents(
628 Heap* heap, Map* map) {
629 // Make sure that the back pointer stored either in the map itself or
630 // inside its transitions array is marked. Skip recording the back
631 // pointer slot since map space is not compacted.
632 StaticVisitor::MarkObject(heap, HeapObject::cast(map->GetBackPointer()));
633
634 // Treat pointers in the transitions array as weak and also mark that
635 // array to prevent visiting it later. Skip recording the transition
636 // array slot, since it will be implicitly recorded when the pointer
637 // fields of this map are visited.
638 if (map->HasTransitionArray()) {
639 TransitionArray* transitions = map->transitions();
640 MarkTransitionArray(heap, transitions);
641 }
642
643 // Since descriptor arrays are potentially shared, ensure that only the
644 // descriptors that belong to this map are marked. The first time a
645 // non-empty descriptor array is marked, its header is also visited. The slot
646 // holding the descriptor array will be implicitly recorded when the pointer
647 // fields of this map are visited.
648 DescriptorArray* descriptors = map->instance_descriptors();
649 if (StaticVisitor::MarkObjectWithoutPush(heap, descriptors) &&
650 descriptors->length() > 0) {
651 StaticVisitor::VisitPointers(heap,
652 descriptors->GetFirstElementAddress(),
653 descriptors->GetDescriptorEndSlot(0));
654 }
655 int start = 0;
656 int end = map->NumberOfOwnDescriptors();
657 if (start < end) {
658 StaticVisitor::VisitPointers(heap,
659 descriptors->GetDescriptorStartSlot(start),
660 descriptors->GetDescriptorEndSlot(end));
661 }
662
663 // Mark prototype dependent codes array but do not push it onto marking
664 // stack, this will make references from it weak. We will clean dead
665 // codes when we iterate over maps in ClearNonLiveTransitions.
666 Object** slot = HeapObject::RawField(map, Map::kDependentCodeOffset);
667 HeapObject* obj = HeapObject::cast(*slot);
668 heap->mark_compact_collector()->RecordSlot(slot, slot, obj);
669 StaticVisitor::MarkObjectWithoutPush(heap, obj);
670
671 // Mark the pointer fields of the Map. Since the transitions array has
672 // been marked already, it is fine that one of these fields contains a
673 // pointer to it.
674 StaticVisitor::VisitPointers(heap,
675 HeapObject::RawField(map, Map::kPointerFieldsBeginOffset),
676 HeapObject::RawField(map, Map::kPointerFieldsEndOffset));
677 }
678
679
680 template<typename StaticVisitor>
MarkTransitionArray(Heap * heap,TransitionArray * transitions)681 void StaticMarkingVisitor<StaticVisitor>::MarkTransitionArray(
682 Heap* heap, TransitionArray* transitions) {
683 if (!StaticVisitor::MarkObjectWithoutPush(heap, transitions)) return;
684
685 // Simple transitions do not have keys nor prototype transitions.
686 if (transitions->IsSimpleTransition()) return;
687
688 if (transitions->HasPrototypeTransitions()) {
689 // Mark prototype transitions array but do not push it onto marking
690 // stack, this will make references from it weak. We will clean dead
691 // prototype transitions in ClearNonLiveTransitions.
692 Object** slot = transitions->GetPrototypeTransitionsSlot();
693 HeapObject* obj = HeapObject::cast(*slot);
694 heap->mark_compact_collector()->RecordSlot(slot, slot, obj);
695 StaticVisitor::MarkObjectWithoutPush(heap, obj);
696 }
697
698 for (int i = 0; i < transitions->number_of_transitions(); ++i) {
699 StaticVisitor::VisitPointer(heap, transitions->GetKeySlot(i));
700 }
701 }
702
703
704 template<typename StaticVisitor>
MarkInlinedFunctionsCode(Heap * heap,Code * code)705 void StaticMarkingVisitor<StaticVisitor>::MarkInlinedFunctionsCode(
706 Heap* heap, Code* code) {
707 // For optimized functions we should retain both non-optimized version
708 // of its code and non-optimized version of all inlined functions.
709 // This is required to support bailing out from inlined code.
710 DeoptimizationInputData* data =
711 DeoptimizationInputData::cast(code->deoptimization_data());
712 FixedArray* literals = data->LiteralArray();
713 for (int i = 0, count = data->InlinedFunctionCount()->value();
714 i < count;
715 i++) {
716 JSFunction* inlined = JSFunction::cast(literals->get(i));
717 StaticVisitor::MarkObject(heap, inlined->shared()->code());
718 }
719 }
720
721
IsValidNonBuiltinContext(Object * context)722 inline static bool IsValidNonBuiltinContext(Object* context) {
723 return context->IsContext() &&
724 !Context::cast(context)->global_object()->IsJSBuiltinsObject();
725 }
726
727
HasSourceCode(Heap * heap,SharedFunctionInfo * info)728 inline static bool HasSourceCode(Heap* heap, SharedFunctionInfo* info) {
729 Object* undefined = heap->undefined_value();
730 return (info->script() != undefined) &&
731 (reinterpret_cast<Script*>(info->script())->source() != undefined);
732 }
733
734
735 template<typename StaticVisitor>
IsFlushable(Heap * heap,JSFunction * function)736 bool StaticMarkingVisitor<StaticVisitor>::IsFlushable(
737 Heap* heap, JSFunction* function) {
738 SharedFunctionInfo* shared_info = function->shared();
739
740 // Code is either on stack, in compilation cache or referenced
741 // by optimized version of function.
742 MarkBit code_mark = Marking::MarkBitFrom(function->code());
743 if (code_mark.Get()) {
744 return false;
745 }
746
747 // The function must have a valid context and not be a builtin.
748 if (!IsValidNonBuiltinContext(function->context())) {
749 return false;
750 }
751
752 // We do not (yet) flush code for optimized functions.
753 if (function->code() != shared_info->code()) {
754 return false;
755 }
756
757 // Check age of optimized code.
758 if (FLAG_age_code && !function->code()->IsOld()) {
759 return false;
760 }
761
762 return IsFlushable(heap, shared_info);
763 }
764
765
766 template<typename StaticVisitor>
IsFlushable(Heap * heap,SharedFunctionInfo * shared_info)767 bool StaticMarkingVisitor<StaticVisitor>::IsFlushable(
768 Heap* heap, SharedFunctionInfo* shared_info) {
769 // Code is either on stack, in compilation cache or referenced
770 // by optimized version of function.
771 MarkBit code_mark = Marking::MarkBitFrom(shared_info->code());
772 if (code_mark.Get()) {
773 return false;
774 }
775
776 // The function must be compiled and have the source code available,
777 // to be able to recompile it in case we need the function again.
778 if (!(shared_info->is_compiled() && HasSourceCode(heap, shared_info))) {
779 return false;
780 }
781
782 // We never flush code for API functions.
783 Object* function_data = shared_info->function_data();
784 if (function_data->IsFunctionTemplateInfo()) {
785 return false;
786 }
787
788 // Only flush code for functions.
789 if (shared_info->code()->kind() != Code::FUNCTION) {
790 return false;
791 }
792
793 // Function must be lazy compilable.
794 if (!shared_info->allows_lazy_compilation()) {
795 return false;
796 }
797
798 // We do not (yet?) flush code for generator functions, because we don't know
799 // if there are still live activations (generator objects) on the heap.
800 if (shared_info->is_generator()) {
801 return false;
802 }
803
804 // If this is a full script wrapped in a function we do not flush the code.
805 if (shared_info->is_toplevel()) {
806 return false;
807 }
808
809 // If this is a function initialized with %SetCode then the one-to-one
810 // relation between SharedFunctionInfo and Code is broken.
811 if (shared_info->dont_flush()) {
812 return false;
813 }
814
815 // Check age of code. If code aging is disabled we never flush.
816 if (!FLAG_age_code || !shared_info->code()->IsOld()) {
817 return false;
818 }
819
820 return true;
821 }
822
823
824 template<typename StaticVisitor>
VisitSharedFunctionInfoStrongCode(Heap * heap,HeapObject * object)825 void StaticMarkingVisitor<StaticVisitor>::VisitSharedFunctionInfoStrongCode(
826 Heap* heap, HeapObject* object) {
827 Object** start_slot =
828 HeapObject::RawField(object,
829 SharedFunctionInfo::BodyDescriptor::kStartOffset);
830 Object** end_slot =
831 HeapObject::RawField(object,
832 SharedFunctionInfo::BodyDescriptor::kEndOffset);
833 StaticVisitor::VisitPointers(heap, start_slot, end_slot);
834 }
835
836
837 template<typename StaticVisitor>
VisitSharedFunctionInfoWeakCode(Heap * heap,HeapObject * object)838 void StaticMarkingVisitor<StaticVisitor>::VisitSharedFunctionInfoWeakCode(
839 Heap* heap, HeapObject* object) {
840 Object** name_slot =
841 HeapObject::RawField(object, SharedFunctionInfo::kNameOffset);
842 StaticVisitor::VisitPointer(heap, name_slot);
843
844 // Skip visiting kCodeOffset as it is treated weakly here.
845 STATIC_ASSERT(SharedFunctionInfo::kNameOffset + kPointerSize ==
846 SharedFunctionInfo::kCodeOffset);
847 STATIC_ASSERT(SharedFunctionInfo::kCodeOffset + kPointerSize ==
848 SharedFunctionInfo::kOptimizedCodeMapOffset);
849
850 Object** start_slot =
851 HeapObject::RawField(object,
852 SharedFunctionInfo::kOptimizedCodeMapOffset);
853 Object** end_slot =
854 HeapObject::RawField(object,
855 SharedFunctionInfo::BodyDescriptor::kEndOffset);
856 StaticVisitor::VisitPointers(heap, start_slot, end_slot);
857 }
858
859
860 template<typename StaticVisitor>
VisitJSFunctionStrongCode(Heap * heap,HeapObject * object)861 void StaticMarkingVisitor<StaticVisitor>::VisitJSFunctionStrongCode(
862 Heap* heap, HeapObject* object) {
863 Object** start_slot =
864 HeapObject::RawField(object, JSFunction::kPropertiesOffset);
865 Object** end_slot =
866 HeapObject::RawField(object, JSFunction::kCodeEntryOffset);
867 StaticVisitor::VisitPointers(heap, start_slot, end_slot);
868
869 VisitCodeEntry(heap, object->address() + JSFunction::kCodeEntryOffset);
870 STATIC_ASSERT(JSFunction::kCodeEntryOffset + kPointerSize ==
871 JSFunction::kPrototypeOrInitialMapOffset);
872
873 start_slot =
874 HeapObject::RawField(object, JSFunction::kPrototypeOrInitialMapOffset);
875 end_slot =
876 HeapObject::RawField(object, JSFunction::kNonWeakFieldsEndOffset);
877 StaticVisitor::VisitPointers(heap, start_slot, end_slot);
878 }
879
880
881 template<typename StaticVisitor>
VisitJSFunctionWeakCode(Heap * heap,HeapObject * object)882 void StaticMarkingVisitor<StaticVisitor>::VisitJSFunctionWeakCode(
883 Heap* heap, HeapObject* object) {
884 Object** start_slot =
885 HeapObject::RawField(object, JSFunction::kPropertiesOffset);
886 Object** end_slot =
887 HeapObject::RawField(object, JSFunction::kCodeEntryOffset);
888 StaticVisitor::VisitPointers(heap, start_slot, end_slot);
889
890 // Skip visiting kCodeEntryOffset as it is treated weakly here.
891 STATIC_ASSERT(JSFunction::kCodeEntryOffset + kPointerSize ==
892 JSFunction::kPrototypeOrInitialMapOffset);
893
894 start_slot =
895 HeapObject::RawField(object, JSFunction::kPrototypeOrInitialMapOffset);
896 end_slot =
897 HeapObject::RawField(object, JSFunction::kNonWeakFieldsEndOffset);
898 StaticVisitor::VisitPointers(heap, start_slot, end_slot);
899 }
900
901
CodeIterateBody(ObjectVisitor * v)902 void Code::CodeIterateBody(ObjectVisitor* v) {
903 int mode_mask = RelocInfo::kCodeTargetMask |
904 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
905 RelocInfo::ModeMask(RelocInfo::CELL) |
906 RelocInfo::ModeMask(RelocInfo::EXTERNAL_REFERENCE) |
907 RelocInfo::ModeMask(RelocInfo::JS_RETURN) |
908 RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT) |
909 RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY);
910
911 // There are two places where we iterate code bodies: here and the
912 // templated CodeIterateBody (below). They should be kept in sync.
913 IteratePointer(v, kRelocationInfoOffset);
914 IteratePointer(v, kHandlerTableOffset);
915 IteratePointer(v, kDeoptimizationDataOffset);
916 IteratePointer(v, kTypeFeedbackInfoOffset);
917 IterateNextCodeLink(v, kNextCodeLinkOffset);
918 IteratePointer(v, kConstantPoolOffset);
919
920 RelocIterator it(this, mode_mask);
921 Isolate* isolate = this->GetIsolate();
922 for (; !it.done(); it.next()) {
923 it.rinfo()->Visit(isolate, v);
924 }
925 }
926
927
928 template<typename StaticVisitor>
CodeIterateBody(Heap * heap)929 void Code::CodeIterateBody(Heap* heap) {
930 int mode_mask = RelocInfo::kCodeTargetMask |
931 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
932 RelocInfo::ModeMask(RelocInfo::CELL) |
933 RelocInfo::ModeMask(RelocInfo::EXTERNAL_REFERENCE) |
934 RelocInfo::ModeMask(RelocInfo::JS_RETURN) |
935 RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT) |
936 RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY);
937
938 // There are two places where we iterate code bodies: here and the non-
939 // templated CodeIterateBody (above). They should be kept in sync.
940 StaticVisitor::VisitPointer(
941 heap,
942 reinterpret_cast<Object**>(this->address() + kRelocationInfoOffset));
943 StaticVisitor::VisitPointer(
944 heap,
945 reinterpret_cast<Object**>(this->address() + kHandlerTableOffset));
946 StaticVisitor::VisitPointer(
947 heap,
948 reinterpret_cast<Object**>(this->address() + kDeoptimizationDataOffset));
949 StaticVisitor::VisitPointer(
950 heap,
951 reinterpret_cast<Object**>(this->address() + kTypeFeedbackInfoOffset));
952 StaticVisitor::VisitNextCodeLink(
953 heap,
954 reinterpret_cast<Object**>(this->address() + kNextCodeLinkOffset));
955 StaticVisitor::VisitPointer(
956 heap,
957 reinterpret_cast<Object**>(this->address() + kConstantPoolOffset));
958
959
960 RelocIterator it(this, mode_mask);
961 for (; !it.done(); it.next()) {
962 it.rinfo()->template Visit<StaticVisitor>(heap);
963 }
964 }
965
966
967 } } // namespace v8::internal
968
969 #endif // V8_OBJECTS_VISITING_INL_H_
970