• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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