| // Copyright 2012 the V8 project authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef V8_OBJECTS_VISITING_INL_H_ |
| #define V8_OBJECTS_VISITING_INL_H_ |
| |
| #include "src/heap/array-buffer-tracker.h" |
| #include "src/heap/objects-visiting.h" |
| #include "src/ic/ic-state.h" |
| #include "src/macro-assembler.h" |
| #include "src/objects-body-descriptors-inl.h" |
| |
| namespace v8 { |
| namespace internal { |
| |
| |
| template <typename Callback> |
| Callback VisitorDispatchTable<Callback>::GetVisitor(Map* map) { |
| return reinterpret_cast<Callback>(callbacks_[map->visitor_id()]); |
| } |
| |
| |
| template <typename StaticVisitor> |
| void StaticNewSpaceVisitor<StaticVisitor>::Initialize() { |
| table_.Register( |
| kVisitShortcutCandidate, |
| &FixedBodyVisitor<StaticVisitor, ConsString::BodyDescriptor, int>::Visit); |
| |
| table_.Register( |
| kVisitConsString, |
| &FixedBodyVisitor<StaticVisitor, ConsString::BodyDescriptor, int>::Visit); |
| |
| table_.Register(kVisitSlicedString, |
| &FixedBodyVisitor<StaticVisitor, SlicedString::BodyDescriptor, |
| int>::Visit); |
| |
| table_.Register( |
| kVisitSymbol, |
| &FixedBodyVisitor<StaticVisitor, Symbol::BodyDescriptor, int>::Visit); |
| |
| table_.Register(kVisitFixedArray, |
| &FlexibleBodyVisitor<StaticVisitor, |
| FixedArray::BodyDescriptor, int>::Visit); |
| |
| table_.Register(kVisitFixedDoubleArray, &VisitFixedDoubleArray); |
| table_.Register( |
| kVisitFixedTypedArray, |
| &FlexibleBodyVisitor<StaticVisitor, FixedTypedArrayBase::BodyDescriptor, |
| int>::Visit); |
| |
| table_.Register( |
| kVisitFixedFloat64Array, |
| &FlexibleBodyVisitor<StaticVisitor, FixedTypedArrayBase::BodyDescriptor, |
| int>::Visit); |
| |
| table_.Register( |
| kVisitNativeContext, |
| &FixedBodyVisitor<StaticVisitor, Context::ScavengeBodyDescriptor, |
| int>::Visit); |
| |
| table_.Register(kVisitByteArray, &VisitByteArray); |
| table_.Register(kVisitBytecodeArray, &VisitBytecodeArray); |
| |
| table_.Register( |
| kVisitSharedFunctionInfo, |
| &FixedBodyVisitor<StaticVisitor, SharedFunctionInfo::BodyDescriptor, |
| int>::Visit); |
| |
| table_.Register(kVisitSeqOneByteString, &VisitSeqOneByteString); |
| |
| table_.Register(kVisitSeqTwoByteString, &VisitSeqTwoByteString); |
| |
| // Don't visit code entry. We are using this visitor only during scavenges. |
| table_.Register( |
| kVisitJSFunction, |
| &FlexibleBodyVisitor<StaticVisitor, JSFunction::BodyDescriptorWeakCode, |
| int>::Visit); |
| |
| table_.Register(kVisitJSArrayBuffer, &VisitJSArrayBuffer); |
| |
| table_.Register(kVisitFreeSpace, &VisitFreeSpace); |
| |
| table_.Register(kVisitJSWeakCollection, &JSObjectVisitor::Visit); |
| |
| table_.Register(kVisitJSRegExp, &JSObjectVisitor::Visit); |
| |
| table_.template RegisterSpecializations<DataObjectVisitor, kVisitDataObject, |
| kVisitDataObjectGeneric>(); |
| |
| table_.template RegisterSpecializations<JSObjectVisitor, kVisitJSObject, |
| kVisitJSObjectGeneric>(); |
| table_.template RegisterSpecializations<StructVisitor, kVisitStruct, |
| kVisitStructGeneric>(); |
| } |
| |
| |
| template <typename StaticVisitor> |
| int StaticNewSpaceVisitor<StaticVisitor>::VisitJSArrayBuffer( |
| Map* map, HeapObject* object) { |
| typedef FlexibleBodyVisitor<StaticVisitor, JSArrayBuffer::BodyDescriptor, int> |
| JSArrayBufferBodyVisitor; |
| |
| if (!JSArrayBuffer::cast(object)->is_external()) { |
| Heap* heap = map->GetHeap(); |
| heap->array_buffer_tracker()->MarkLive(JSArrayBuffer::cast(object)); |
| } |
| return JSArrayBufferBodyVisitor::Visit(map, object); |
| } |
| |
| |
| template <typename StaticVisitor> |
| int StaticNewSpaceVisitor<StaticVisitor>::VisitBytecodeArray( |
| Map* map, HeapObject* object) { |
| VisitPointers( |
| map->GetHeap(), object, |
| HeapObject::RawField(object, BytecodeArray::kConstantPoolOffset), |
| HeapObject::RawField(object, BytecodeArray::kFrameSizeOffset)); |
| return reinterpret_cast<BytecodeArray*>(object)->BytecodeArraySize(); |
| } |
| |
| |
| template <typename StaticVisitor> |
| void StaticMarkingVisitor<StaticVisitor>::Initialize() { |
| table_.Register(kVisitShortcutCandidate, |
| &FixedBodyVisitor<StaticVisitor, ConsString::BodyDescriptor, |
| void>::Visit); |
| |
| table_.Register(kVisitConsString, |
| &FixedBodyVisitor<StaticVisitor, ConsString::BodyDescriptor, |
| void>::Visit); |
| |
| table_.Register(kVisitSlicedString, |
| &FixedBodyVisitor<StaticVisitor, SlicedString::BodyDescriptor, |
| void>::Visit); |
| |
| table_.Register( |
| kVisitSymbol, |
| &FixedBodyVisitor<StaticVisitor, Symbol::BodyDescriptor, void>::Visit); |
| |
| table_.Register(kVisitFixedArray, &FixedArrayVisitor::Visit); |
| |
| table_.Register(kVisitFixedDoubleArray, &DataObjectVisitor::Visit); |
| |
| table_.Register( |
| kVisitFixedTypedArray, |
| &FlexibleBodyVisitor<StaticVisitor, FixedTypedArrayBase::BodyDescriptor, |
| void>::Visit); |
| |
| table_.Register( |
| kVisitFixedFloat64Array, |
| &FlexibleBodyVisitor<StaticVisitor, FixedTypedArrayBase::BodyDescriptor, |
| void>::Visit); |
| |
| table_.Register(kVisitNativeContext, &VisitNativeContext); |
| |
| table_.Register(kVisitAllocationSite, &VisitAllocationSite); |
| |
| table_.Register(kVisitByteArray, &DataObjectVisitor::Visit); |
| |
| table_.Register(kVisitBytecodeArray, &VisitBytecodeArray); |
| |
| table_.Register(kVisitFreeSpace, &DataObjectVisitor::Visit); |
| |
| table_.Register(kVisitSeqOneByteString, &DataObjectVisitor::Visit); |
| |
| table_.Register(kVisitSeqTwoByteString, &DataObjectVisitor::Visit); |
| |
| table_.Register(kVisitJSWeakCollection, &VisitWeakCollection); |
| |
| table_.Register( |
| kVisitOddball, |
| &FixedBodyVisitor<StaticVisitor, Oddball::BodyDescriptor, void>::Visit); |
| |
| table_.Register(kVisitMap, &VisitMap); |
| |
| table_.Register(kVisitCode, &VisitCode); |
| |
| table_.Register(kVisitSharedFunctionInfo, &VisitSharedFunctionInfo); |
| |
| table_.Register(kVisitJSFunction, &VisitJSFunction); |
| |
| table_.Register(kVisitJSArrayBuffer, &VisitJSArrayBuffer); |
| |
| // Registration for kVisitJSRegExp is done by StaticVisitor. |
| |
| table_.Register( |
| kVisitCell, |
| &FixedBodyVisitor<StaticVisitor, Cell::BodyDescriptor, void>::Visit); |
| |
| table_.Register(kVisitPropertyCell, &VisitPropertyCell); |
| |
| table_.Register(kVisitWeakCell, &VisitWeakCell); |
| |
| table_.Register(kVisitTransitionArray, &VisitTransitionArray); |
| |
| table_.template RegisterSpecializations<DataObjectVisitor, kVisitDataObject, |
| kVisitDataObjectGeneric>(); |
| |
| table_.template RegisterSpecializations<JSObjectVisitor, kVisitJSObject, |
| kVisitJSObjectGeneric>(); |
| |
| table_.template RegisterSpecializations<StructObjectVisitor, kVisitStruct, |
| kVisitStructGeneric>(); |
| } |
| |
| |
| template <typename StaticVisitor> |
| void StaticMarkingVisitor<StaticVisitor>::VisitCodeEntry( |
| Heap* heap, HeapObject* object, Address entry_address) { |
| Code* code = Code::cast(Code::GetObjectFromEntryAddress(entry_address)); |
| heap->mark_compact_collector()->RecordCodeEntrySlot(object, entry_address, |
| code); |
| StaticVisitor::MarkObject(heap, code); |
| } |
| |
| |
| template <typename StaticVisitor> |
| void StaticMarkingVisitor<StaticVisitor>::VisitEmbeddedPointer( |
| Heap* heap, RelocInfo* rinfo) { |
| DCHECK(rinfo->rmode() == RelocInfo::EMBEDDED_OBJECT); |
| HeapObject* object = HeapObject::cast(rinfo->target_object()); |
| Code* host = rinfo->host(); |
| heap->mark_compact_collector()->RecordRelocSlot(host, rinfo, object); |
| // TODO(ulan): It could be better to record slots only for strongly embedded |
| // objects here and record slots for weakly embedded object during clearing |
| // of non-live references in mark-compact. |
| if (!host->IsWeakObject(object)) { |
| StaticVisitor::MarkObject(heap, object); |
| } |
| } |
| |
| |
| template <typename StaticVisitor> |
| void StaticMarkingVisitor<StaticVisitor>::VisitCell(Heap* heap, |
| RelocInfo* rinfo) { |
| DCHECK(rinfo->rmode() == RelocInfo::CELL); |
| Cell* cell = rinfo->target_cell(); |
| Code* host = rinfo->host(); |
| heap->mark_compact_collector()->RecordRelocSlot(host, rinfo, cell); |
| if (!host->IsWeakObject(cell)) { |
| StaticVisitor::MarkObject(heap, cell); |
| } |
| } |
| |
| |
| template <typename StaticVisitor> |
| void StaticMarkingVisitor<StaticVisitor>::VisitDebugTarget(Heap* heap, |
| RelocInfo* rinfo) { |
| DCHECK(RelocInfo::IsDebugBreakSlot(rinfo->rmode()) && |
| rinfo->IsPatchedDebugBreakSlotSequence()); |
| Code* target = Code::GetCodeFromTargetAddress(rinfo->debug_call_address()); |
| Code* host = rinfo->host(); |
| heap->mark_compact_collector()->RecordRelocSlot(host, rinfo, target); |
| StaticVisitor::MarkObject(heap, target); |
| } |
| |
| |
| template <typename StaticVisitor> |
| void StaticMarkingVisitor<StaticVisitor>::VisitCodeTarget(Heap* heap, |
| RelocInfo* rinfo) { |
| DCHECK(RelocInfo::IsCodeTarget(rinfo->rmode())); |
| Code* target = Code::GetCodeFromTargetAddress(rinfo->target_address()); |
| // Monomorphic ICs are preserved when possible, but need to be flushed |
| // when they might be keeping a Context alive, or when the heap is about |
| // to be serialized. |
| if (FLAG_cleanup_code_caches_at_gc && target->is_inline_cache_stub() && |
| !target->is_call_stub() && (heap->isolate()->serializer_enabled() || |
| target->ic_age() != heap->global_ic_age())) { |
| ICUtility::Clear(heap->isolate(), rinfo->pc(), |
| rinfo->host()->constant_pool()); |
| target = Code::GetCodeFromTargetAddress(rinfo->target_address()); |
| } |
| Code* host = rinfo->host(); |
| heap->mark_compact_collector()->RecordRelocSlot(host, rinfo, target); |
| StaticVisitor::MarkObject(heap, target); |
| } |
| |
| |
| template <typename StaticVisitor> |
| void StaticMarkingVisitor<StaticVisitor>::VisitCodeAgeSequence( |
| Heap* heap, RelocInfo* rinfo) { |
| DCHECK(RelocInfo::IsCodeAgeSequence(rinfo->rmode())); |
| Code* target = rinfo->code_age_stub(); |
| DCHECK(target != NULL); |
| Code* host = rinfo->host(); |
| heap->mark_compact_collector()->RecordRelocSlot(host, rinfo, target); |
| StaticVisitor::MarkObject(heap, target); |
| } |
| |
| |
| template <typename StaticVisitor> |
| void StaticMarkingVisitor<StaticVisitor>::VisitNativeContext( |
| Map* map, HeapObject* object) { |
| FixedBodyVisitor<StaticVisitor, Context::MarkCompactBodyDescriptor, |
| void>::Visit(map, object); |
| } |
| |
| |
| template <typename StaticVisitor> |
| void StaticMarkingVisitor<StaticVisitor>::VisitMap(Map* map, |
| HeapObject* object) { |
| Heap* heap = map->GetHeap(); |
| Map* map_object = Map::cast(object); |
| |
| // Clears the cache of ICs related to this map. |
| if (FLAG_cleanup_code_caches_at_gc) { |
| map_object->ClearCodeCache(heap); |
| } |
| |
| // When map collection is enabled we have to mark through map's transitions |
| // and back pointers in a special way to make these links weak. |
| if (map_object->CanTransition()) { |
| MarkMapContents(heap, map_object); |
| } else { |
| StaticVisitor::VisitPointers( |
| heap, object, |
| HeapObject::RawField(object, Map::kPointerFieldsBeginOffset), |
| HeapObject::RawField(object, Map::kPointerFieldsEndOffset)); |
| } |
| } |
| |
| |
| template <typename StaticVisitor> |
| void StaticMarkingVisitor<StaticVisitor>::VisitPropertyCell( |
| Map* map, HeapObject* object) { |
| Heap* heap = map->GetHeap(); |
| |
| StaticVisitor::VisitPointers( |
| heap, object, |
| HeapObject::RawField(object, PropertyCell::kPointerFieldsBeginOffset), |
| HeapObject::RawField(object, PropertyCell::kPointerFieldsEndOffset)); |
| } |
| |
| |
| template <typename StaticVisitor> |
| void StaticMarkingVisitor<StaticVisitor>::VisitWeakCell(Map* map, |
| HeapObject* object) { |
| Heap* heap = map->GetHeap(); |
| WeakCell* weak_cell = reinterpret_cast<WeakCell*>(object); |
| // Enqueue weak cell in linked list of encountered weak collections. |
| // We can ignore weak cells with cleared values because they will always |
| // contain smi zero. |
| if (weak_cell->next_cleared() && !weak_cell->cleared()) { |
| HeapObject* value = HeapObject::cast(weak_cell->value()); |
| if (MarkCompactCollector::IsMarked(value)) { |
| // Weak cells with live values are directly processed here to reduce |
| // the processing time of weak cells during the main GC pause. |
| Object** slot = HeapObject::RawField(weak_cell, WeakCell::kValueOffset); |
| map->GetHeap()->mark_compact_collector()->RecordSlot(weak_cell, slot, |
| *slot); |
| } else { |
| // If we do not know about liveness of values of weak cells, we have to |
| // process them when we know the liveness of the whole transitive |
| // closure. |
| weak_cell->set_next(heap->encountered_weak_cells(), |
| UPDATE_WEAK_WRITE_BARRIER); |
| heap->set_encountered_weak_cells(weak_cell); |
| } |
| } |
| } |
| |
| |
| template <typename StaticVisitor> |
| void StaticMarkingVisitor<StaticVisitor>::VisitTransitionArray( |
| Map* map, HeapObject* object) { |
| TransitionArray* array = TransitionArray::cast(object); |
| Heap* heap = array->GetHeap(); |
| // Visit strong references. |
| if (array->HasPrototypeTransitions()) { |
| StaticVisitor::VisitPointer(heap, array, |
| array->GetPrototypeTransitionsSlot()); |
| } |
| int num_transitions = TransitionArray::NumberOfTransitions(array); |
| for (int i = 0; i < num_transitions; ++i) { |
| StaticVisitor::VisitPointer(heap, array, array->GetKeySlot(i)); |
| } |
| // Enqueue the array in linked list of encountered transition arrays if it is |
| // not already in the list. |
| if (array->next_link()->IsUndefined()) { |
| Heap* heap = map->GetHeap(); |
| array->set_next_link(heap->encountered_transition_arrays(), |
| UPDATE_WEAK_WRITE_BARRIER); |
| heap->set_encountered_transition_arrays(array); |
| } |
| } |
| |
| |
| template <typename StaticVisitor> |
| void StaticMarkingVisitor<StaticVisitor>::VisitAllocationSite( |
| Map* map, HeapObject* object) { |
| Heap* heap = map->GetHeap(); |
| |
| StaticVisitor::VisitPointers( |
| heap, object, |
| HeapObject::RawField(object, AllocationSite::kPointerFieldsBeginOffset), |
| HeapObject::RawField(object, AllocationSite::kPointerFieldsEndOffset)); |
| } |
| |
| |
| template <typename StaticVisitor> |
| void StaticMarkingVisitor<StaticVisitor>::VisitWeakCollection( |
| Map* map, HeapObject* object) { |
| typedef FlexibleBodyVisitor<StaticVisitor, |
| JSWeakCollection::BodyDescriptorWeak, |
| void> JSWeakCollectionBodyVisitor; |
| Heap* heap = map->GetHeap(); |
| JSWeakCollection* weak_collection = |
| reinterpret_cast<JSWeakCollection*>(object); |
| |
| // Enqueue weak collection in linked list of encountered weak collections. |
| if (weak_collection->next() == heap->undefined_value()) { |
| weak_collection->set_next(heap->encountered_weak_collections()); |
| heap->set_encountered_weak_collections(weak_collection); |
| } |
| |
| // Skip visiting the backing hash table containing the mappings and the |
| // pointer to the other enqueued weak collections, both are post-processed. |
| JSWeakCollectionBodyVisitor::Visit(map, object); |
| |
| // Partially initialized weak collection is enqueued, but table is ignored. |
| if (!weak_collection->table()->IsHashTable()) return; |
| |
| // Mark the backing hash table without pushing it on the marking stack. |
| Object** slot = HeapObject::RawField(object, JSWeakCollection::kTableOffset); |
| HeapObject* obj = HeapObject::cast(*slot); |
| heap->mark_compact_collector()->RecordSlot(object, slot, obj); |
| StaticVisitor::MarkObjectWithoutPush(heap, obj); |
| } |
| |
| |
| template <typename StaticVisitor> |
| void StaticMarkingVisitor<StaticVisitor>::VisitCode(Map* map, |
| HeapObject* object) { |
| typedef FlexibleBodyVisitor<StaticVisitor, Code::BodyDescriptor, void> |
| CodeBodyVisitor; |
| Heap* heap = map->GetHeap(); |
| Code* code = Code::cast(object); |
| if (FLAG_age_code && !heap->isolate()->serializer_enabled()) { |
| code->MakeOlder(heap->mark_compact_collector()->marking_parity()); |
| } |
| CodeBodyVisitor::Visit(map, object); |
| } |
| |
| |
| template <typename StaticVisitor> |
| void StaticMarkingVisitor<StaticVisitor>::VisitSharedFunctionInfo( |
| Map* map, HeapObject* object) { |
| Heap* heap = map->GetHeap(); |
| SharedFunctionInfo* shared = SharedFunctionInfo::cast(object); |
| if (shared->ic_age() != heap->global_ic_age()) { |
| shared->ResetForNewContext(heap->global_ic_age()); |
| } |
| if (FLAG_cleanup_code_caches_at_gc) { |
| shared->ClearTypeFeedbackInfoAtGCTime(); |
| } |
| if (FLAG_flush_optimized_code_cache) { |
| if (!shared->OptimizedCodeMapIsCleared()) { |
| // Always flush the optimized code map if requested by flag. |
| shared->ClearOptimizedCodeMap(); |
| } |
| } |
| MarkCompactCollector* collector = heap->mark_compact_collector(); |
| if (collector->is_code_flushing_enabled()) { |
| if (IsFlushable(heap, shared)) { |
| // This function's code looks flushable. But we have to postpone |
| // the decision until we see all functions that point to the same |
| // SharedFunctionInfo because some of them might be optimized. |
| // That would also make the non-optimized version of the code |
| // non-flushable, because it is required for bailing out from |
| // optimized code. |
| collector->code_flusher()->AddCandidate(shared); |
| // Treat the reference to the code object weakly. |
| VisitSharedFunctionInfoWeakCode(heap, object); |
| return; |
| } |
| } |
| VisitSharedFunctionInfoStrongCode(heap, object); |
| } |
| |
| |
| template <typename StaticVisitor> |
| void StaticMarkingVisitor<StaticVisitor>::VisitJSFunction(Map* map, |
| HeapObject* object) { |
| Heap* heap = map->GetHeap(); |
| JSFunction* function = JSFunction::cast(object); |
| MarkCompactCollector* collector = heap->mark_compact_collector(); |
| if (collector->is_code_flushing_enabled()) { |
| if (IsFlushable(heap, function)) { |
| // This function's code looks flushable. But we have to postpone |
| // the decision until we see all functions that point to the same |
| // SharedFunctionInfo because some of them might be optimized. |
| // That would also make the non-optimized version of the code |
| // non-flushable, because it is required for bailing out from |
| // optimized code. |
| collector->code_flusher()->AddCandidate(function); |
| // Treat the reference to the code object weakly. |
| VisitJSFunctionWeakCode(map, object); |
| return; |
| } else { |
| // Visit all unoptimized code objects to prevent flushing them. |
| StaticVisitor::MarkObject(heap, function->shared()->code()); |
| } |
| } |
| VisitJSFunctionStrongCode(map, object); |
| } |
| |
| |
| template <typename StaticVisitor> |
| void StaticMarkingVisitor<StaticVisitor>::VisitJSRegExp(Map* map, |
| HeapObject* object) { |
| JSObjectVisitor::Visit(map, object); |
| } |
| |
| |
| template <typename StaticVisitor> |
| void StaticMarkingVisitor<StaticVisitor>::VisitJSArrayBuffer( |
| Map* map, HeapObject* object) { |
| Heap* heap = map->GetHeap(); |
| |
| typedef FlexibleBodyVisitor<StaticVisitor, JSArrayBuffer::BodyDescriptor, |
| void> JSArrayBufferBodyVisitor; |
| |
| JSArrayBufferBodyVisitor::Visit(map, object); |
| |
| if (!JSArrayBuffer::cast(object)->is_external() && |
| !heap->InNewSpace(object)) { |
| heap->array_buffer_tracker()->MarkLive(JSArrayBuffer::cast(object)); |
| } |
| } |
| |
| |
| template <typename StaticVisitor> |
| void StaticMarkingVisitor<StaticVisitor>::VisitBytecodeArray( |
| Map* map, HeapObject* object) { |
| StaticVisitor::VisitPointers( |
| map->GetHeap(), object, |
| HeapObject::RawField(object, BytecodeArray::kConstantPoolOffset), |
| HeapObject::RawField(object, BytecodeArray::kFrameSizeOffset)); |
| } |
| |
| |
| template <typename StaticVisitor> |
| void StaticMarkingVisitor<StaticVisitor>::MarkMapContents(Heap* heap, |
| Map* map) { |
| // Since descriptor arrays are potentially shared, ensure that only the |
| // descriptors that belong to this map are marked. The first time a non-empty |
| // descriptor array is marked, its header is also visited. The slot holding |
| // the descriptor array will be implicitly recorded when the pointer fields of |
| // this map are visited. Prototype maps don't keep track of transitions, so |
| // just mark the entire descriptor array. |
| if (!map->is_prototype_map()) { |
| DescriptorArray* descriptors = map->instance_descriptors(); |
| if (StaticVisitor::MarkObjectWithoutPush(heap, descriptors) && |
| descriptors->length() > 0) { |
| StaticVisitor::VisitPointers(heap, descriptors, |
| descriptors->GetFirstElementAddress(), |
| descriptors->GetDescriptorEndSlot(0)); |
| } |
| int start = 0; |
| int end = map->NumberOfOwnDescriptors(); |
| if (start < end) { |
| StaticVisitor::VisitPointers(heap, descriptors, |
| descriptors->GetDescriptorStartSlot(start), |
| descriptors->GetDescriptorEndSlot(end)); |
| } |
| } |
| |
| // Mark the pointer fields of the Map. Since the transitions array has |
| // been marked already, it is fine that one of these fields contains a |
| // pointer to it. |
| StaticVisitor::VisitPointers( |
| heap, map, HeapObject::RawField(map, Map::kPointerFieldsBeginOffset), |
| HeapObject::RawField(map, Map::kPointerFieldsEndOffset)); |
| } |
| |
| |
| inline static bool HasSourceCode(Heap* heap, SharedFunctionInfo* info) { |
| Object* undefined = heap->undefined_value(); |
| return (info->script() != undefined) && |
| (reinterpret_cast<Script*>(info->script())->source() != undefined); |
| } |
| |
| |
| template <typename StaticVisitor> |
| bool StaticMarkingVisitor<StaticVisitor>::IsFlushable(Heap* heap, |
| JSFunction* function) { |
| SharedFunctionInfo* shared_info = function->shared(); |
| |
| // Code is either on stack, in compilation cache or referenced |
| // by optimized version of function. |
| MarkBit code_mark = Marking::MarkBitFrom(function->code()); |
| if (Marking::IsBlackOrGrey(code_mark)) { |
| return false; |
| } |
| |
| // We do not (yet) flush code for optimized functions. |
| if (function->code() != shared_info->code()) { |
| return false; |
| } |
| |
| // Check age of optimized code. |
| if (FLAG_age_code && !function->code()->IsOld()) { |
| return false; |
| } |
| |
| return IsFlushable(heap, shared_info); |
| } |
| |
| |
| template <typename StaticVisitor> |
| bool StaticMarkingVisitor<StaticVisitor>::IsFlushable( |
| Heap* heap, SharedFunctionInfo* shared_info) { |
| // Code is either on stack, in compilation cache or referenced |
| // by optimized version of function. |
| MarkBit code_mark = Marking::MarkBitFrom(shared_info->code()); |
| if (Marking::IsBlackOrGrey(code_mark)) { |
| return false; |
| } |
| |
| // The function must be compiled and have the source code available, |
| // to be able to recompile it in case we need the function again. |
| if (!(shared_info->is_compiled() && HasSourceCode(heap, shared_info))) { |
| return false; |
| } |
| |
| // We never flush code for API functions. |
| Object* function_data = shared_info->function_data(); |
| if (function_data->IsFunctionTemplateInfo()) { |
| return false; |
| } |
| |
| // Only flush code for functions. |
| if (shared_info->code()->kind() != Code::FUNCTION) { |
| return false; |
| } |
| |
| // Function must be lazy compilable. |
| if (!shared_info->allows_lazy_compilation()) { |
| return false; |
| } |
| |
| // We do not (yet?) flush code for generator functions, because we don't know |
| // if there are still live activations (generator objects) on the heap. |
| if (shared_info->is_generator()) { |
| return false; |
| } |
| |
| // If this is a full script wrapped in a function we do not flush the code. |
| if (shared_info->is_toplevel()) { |
| return false; |
| } |
| |
| // The function must not be a builtin. |
| if (shared_info->IsBuiltin()) { |
| return false; |
| } |
| |
| // Maintain debug break slots in the code. |
| if (shared_info->HasDebugCode()) { |
| return false; |
| } |
| |
| // If this is a function initialized with %SetCode then the one-to-one |
| // relation between SharedFunctionInfo and Code is broken. |
| if (shared_info->dont_flush()) { |
| return false; |
| } |
| |
| // Check age of code. If code aging is disabled we never flush. |
| if (!FLAG_age_code || !shared_info->code()->IsOld()) { |
| return false; |
| } |
| |
| return true; |
| } |
| |
| |
| template <typename StaticVisitor> |
| void StaticMarkingVisitor<StaticVisitor>::VisitSharedFunctionInfoStrongCode( |
| Heap* heap, HeapObject* object) { |
| Object** start_slot = HeapObject::RawField( |
| object, SharedFunctionInfo::BodyDescriptor::kStartOffset); |
| Object** end_slot = HeapObject::RawField( |
| object, SharedFunctionInfo::BodyDescriptor::kEndOffset); |
| StaticVisitor::VisitPointers(heap, object, start_slot, end_slot); |
| } |
| |
| |
| template <typename StaticVisitor> |
| void StaticMarkingVisitor<StaticVisitor>::VisitSharedFunctionInfoWeakCode( |
| Heap* heap, HeapObject* object) { |
| Object** name_slot = |
| HeapObject::RawField(object, SharedFunctionInfo::kNameOffset); |
| StaticVisitor::VisitPointer(heap, object, name_slot); |
| |
| // Skip visiting kCodeOffset as it is treated weakly here. |
| STATIC_ASSERT(SharedFunctionInfo::kNameOffset + kPointerSize == |
| SharedFunctionInfo::kCodeOffset); |
| STATIC_ASSERT(SharedFunctionInfo::kCodeOffset + kPointerSize == |
| SharedFunctionInfo::kOptimizedCodeMapOffset); |
| |
| Object** start_slot = |
| HeapObject::RawField(object, SharedFunctionInfo::kOptimizedCodeMapOffset); |
| Object** end_slot = HeapObject::RawField( |
| object, SharedFunctionInfo::BodyDescriptor::kEndOffset); |
| StaticVisitor::VisitPointers(heap, object, start_slot, end_slot); |
| } |
| |
| |
| template <typename StaticVisitor> |
| void StaticMarkingVisitor<StaticVisitor>::VisitJSFunctionStrongCode( |
| Map* map, HeapObject* object) { |
| typedef FlexibleBodyVisitor<StaticVisitor, |
| JSFunction::BodyDescriptorStrongCode, |
| void> JSFunctionStrongCodeBodyVisitor; |
| JSFunctionStrongCodeBodyVisitor::Visit(map, object); |
| } |
| |
| |
| template <typename StaticVisitor> |
| void StaticMarkingVisitor<StaticVisitor>::VisitJSFunctionWeakCode( |
| Map* map, HeapObject* object) { |
| typedef FlexibleBodyVisitor<StaticVisitor, JSFunction::BodyDescriptorWeakCode, |
| void> JSFunctionWeakCodeBodyVisitor; |
| JSFunctionWeakCodeBodyVisitor::Visit(map, object); |
| } |
| |
| |
| } // namespace internal |
| } // namespace v8 |
| |
| #endif // V8_OBJECTS_VISITING_INL_H_ |