// 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_FEEDBACK_VECTOR_INL_H_ #define V8_OBJECTS_FEEDBACK_VECTOR_INL_H_ #include "src/objects/feedback-vector.h" #include "src/common/globals.h" #include "src/heap/factory-inl.h" #include "src/heap/heap-write-barrier-inl.h" #include "src/objects/code-inl.h" #include "src/objects/maybe-object-inl.h" #include "src/objects/shared-function-info.h" #include "src/objects/smi.h" // Has to be the last include (doesn't have include guards): #include "src/objects/object-macros.h" namespace v8 { namespace internal { OBJECT_CONSTRUCTORS_IMPL(FeedbackVector, HeapObject) OBJECT_CONSTRUCTORS_IMPL(FeedbackMetadata, HeapObject) OBJECT_CONSTRUCTORS_IMPL(ClosureFeedbackCellArray, FixedArray) NEVER_READ_ONLY_SPACE_IMPL(FeedbackVector) NEVER_READ_ONLY_SPACE_IMPL(ClosureFeedbackCellArray) CAST_ACCESSOR(FeedbackVector) CAST_ACCESSOR(FeedbackMetadata) CAST_ACCESSOR(ClosureFeedbackCellArray) INT32_ACCESSORS(FeedbackMetadata, slot_count, kSlotCountOffset) INT32_ACCESSORS(FeedbackMetadata, closure_feedback_cell_count, kFeedbackCellCountOffset) int32_t FeedbackMetadata::synchronized_slot_count() const { return base::Acquire_Load(reinterpret_cast( FIELD_ADDR(*this, kSlotCountOffset))); } int32_t FeedbackMetadata::get(int index) const { DCHECK(index >= 0 && index < length()); int offset = kHeaderSize + index * kInt32Size; return ReadField(offset); } void FeedbackMetadata::set(int index, int32_t value) { DCHECK(index >= 0 && index < length()); int offset = kHeaderSize + index * kInt32Size; WriteField(offset, value); } bool FeedbackMetadata::is_empty() const { return slot_count() == 0; } int FeedbackMetadata::length() const { return FeedbackMetadata::length(slot_count()); } int FeedbackMetadata::GetSlotSize(FeedbackSlotKind kind) { switch (kind) { case FeedbackSlotKind::kForIn: case FeedbackSlotKind::kInstanceOf: case FeedbackSlotKind::kCompareOp: case FeedbackSlotKind::kBinaryOp: case FeedbackSlotKind::kLiteral: case FeedbackSlotKind::kTypeProfile: return 1; case FeedbackSlotKind::kCall: case FeedbackSlotKind::kCloneObject: case FeedbackSlotKind::kLoadProperty: case FeedbackSlotKind::kLoadGlobalInsideTypeof: case FeedbackSlotKind::kLoadGlobalNotInsideTypeof: case FeedbackSlotKind::kLoadKeyed: case FeedbackSlotKind::kHasKeyed: case FeedbackSlotKind::kStoreNamedSloppy: case FeedbackSlotKind::kStoreNamedStrict: case FeedbackSlotKind::kStoreOwnNamed: case FeedbackSlotKind::kStoreGlobalSloppy: case FeedbackSlotKind::kStoreGlobalStrict: case FeedbackSlotKind::kStoreKeyedSloppy: case FeedbackSlotKind::kStoreKeyedStrict: case FeedbackSlotKind::kStoreInArrayLiteral: case FeedbackSlotKind::kStoreDataPropertyInLiteral: return 2; case FeedbackSlotKind::kInvalid: case FeedbackSlotKind::kKindsNumber: UNREACHABLE(); } return 1; } Handle ClosureFeedbackCellArray::GetFeedbackCell(int index) { return handle(FeedbackCell::cast(get(index)), GetIsolate()); } ACCESSORS(FeedbackVector, shared_function_info, SharedFunctionInfo, kSharedFunctionInfoOffset) WEAK_ACCESSORS(FeedbackVector, optimized_code_weak_or_smi, kOptimizedCodeWeakOrSmiOffset) ACCESSORS(FeedbackVector, closure_feedback_cell_array, ClosureFeedbackCellArray, kClosureFeedbackCellArrayOffset) INT32_ACCESSORS(FeedbackVector, length, kLengthOffset) INT32_ACCESSORS(FeedbackVector, invocation_count, kInvocationCountOffset) INT32_ACCESSORS(FeedbackVector, profiler_ticks, kProfilerTicksOffset) void FeedbackVector::clear_padding() { if (FIELD_SIZE(kPaddingOffset) == 0) return; DCHECK_EQ(4, FIELD_SIZE(kPaddingOffset)); memset(reinterpret_cast(address() + kPaddingOffset), 0, FIELD_SIZE(kPaddingOffset)); } bool FeedbackVector::is_empty() const { return length() == 0; } FeedbackMetadata FeedbackVector::metadata() const { return shared_function_info().feedback_metadata(); } void FeedbackVector::clear_invocation_count() { set_invocation_count(0); } Code FeedbackVector::optimized_code() const { MaybeObject slot = optimized_code_weak_or_smi(); DCHECK(slot->IsSmi() || slot->IsWeakOrCleared()); HeapObject heap_object; return slot->GetHeapObject(&heap_object) ? Code::cast(heap_object) : Code(); } OptimizationMarker FeedbackVector::optimization_marker() const { MaybeObject slot = optimized_code_weak_or_smi(); Smi value; if (!slot->ToSmi(&value)) return OptimizationMarker::kNone; return static_cast(value.value()); } bool FeedbackVector::has_optimized_code() const { return !optimized_code().is_null(); } bool FeedbackVector::has_optimization_marker() const { return optimization_marker() != OptimizationMarker::kLogFirstExecution && optimization_marker() != OptimizationMarker::kNone; } // Conversion from an integer index to either a slot or an ic slot. // static FeedbackSlot FeedbackVector::ToSlot(int index) { DCHECK_GE(index, 0); return FeedbackSlot(index); } MaybeObject FeedbackVector::Get(FeedbackSlot slot) const { return get(GetIndex(slot)); } MaybeObject FeedbackVector::get(int index) const { DCHECK_GE(index, 0); DCHECK_LT(index, this->length()); int offset = kFeedbackSlotsOffset + index * kTaggedSize; return RELAXED_READ_WEAK_FIELD(*this, offset); } Handle FeedbackVector::GetClosureFeedbackCell(int index) const { DCHECK_GE(index, 0); ClosureFeedbackCellArray cell_array = ClosureFeedbackCellArray::cast(closure_feedback_cell_array()); return cell_array.GetFeedbackCell(index); } void FeedbackVector::Set(FeedbackSlot slot, MaybeObject value, WriteBarrierMode mode) { set(GetIndex(slot), value, mode); } void FeedbackVector::set(int index, MaybeObject value, WriteBarrierMode mode) { DCHECK_GE(index, 0); DCHECK_LT(index, this->length()); int offset = kFeedbackSlotsOffset + index * kTaggedSize; RELAXED_WRITE_WEAK_FIELD(*this, offset, value); CONDITIONAL_WEAK_WRITE_BARRIER(*this, offset, value, mode); } void FeedbackVector::Set(FeedbackSlot slot, Object value, WriteBarrierMode mode) { set(GetIndex(slot), MaybeObject::FromObject(value), mode); } void FeedbackVector::set(int index, Object value, WriteBarrierMode mode) { set(index, MaybeObject::FromObject(value), mode); } inline MaybeObjectSlot FeedbackVector::slots_start() { return RawMaybeWeakField(kFeedbackSlotsOffset); } // Helper function to transform the feedback to BinaryOperationHint. BinaryOperationHint BinaryOperationHintFromFeedback(int type_feedback) { switch (type_feedback) { case BinaryOperationFeedback::kNone: return BinaryOperationHint::kNone; case BinaryOperationFeedback::kSignedSmall: return BinaryOperationHint::kSignedSmall; case BinaryOperationFeedback::kSignedSmallInputs: return BinaryOperationHint::kSignedSmallInputs; case BinaryOperationFeedback::kNumber: return BinaryOperationHint::kNumber; case BinaryOperationFeedback::kNumberOrOddball: return BinaryOperationHint::kNumberOrOddball; case BinaryOperationFeedback::kString: return BinaryOperationHint::kString; case BinaryOperationFeedback::kBigInt: return BinaryOperationHint::kBigInt; default: return BinaryOperationHint::kAny; } UNREACHABLE(); } // Helper function to transform the feedback to CompareOperationHint. CompareOperationHint CompareOperationHintFromFeedback(int type_feedback) { switch (type_feedback) { case CompareOperationFeedback::kNone: return CompareOperationHint::kNone; case CompareOperationFeedback::kSignedSmall: return CompareOperationHint::kSignedSmall; case CompareOperationFeedback::kNumber: return CompareOperationHint::kNumber; case CompareOperationFeedback::kNumberOrOddball: return CompareOperationHint::kNumberOrOddball; case CompareOperationFeedback::kInternalizedString: return CompareOperationHint::kInternalizedString; case CompareOperationFeedback::kString: return CompareOperationHint::kString; case CompareOperationFeedback::kSymbol: return CompareOperationHint::kSymbol; case CompareOperationFeedback::kBigInt: return CompareOperationHint::kBigInt; case CompareOperationFeedback::kReceiver: return CompareOperationHint::kReceiver; case CompareOperationFeedback::kReceiverOrNullOrUndefined: return CompareOperationHint::kReceiverOrNullOrUndefined; default: return CompareOperationHint::kAny; } UNREACHABLE(); } // Helper function to transform the feedback to ForInHint. ForInHint ForInHintFromFeedback(int type_feedback) { switch (type_feedback) { case ForInFeedback::kNone: return ForInHint::kNone; case ForInFeedback::kEnumCacheKeys: return ForInHint::kEnumCacheKeys; case ForInFeedback::kEnumCacheKeysAndIndices: return ForInHint::kEnumCacheKeysAndIndices; default: return ForInHint::kAny; } UNREACHABLE(); } Handle FeedbackVector::UninitializedSentinel(Isolate* isolate) { return isolate->factory()->uninitialized_symbol(); } Handle FeedbackVector::GenericSentinel(Isolate* isolate) { return isolate->factory()->generic_symbol(); } Handle FeedbackVector::MegamorphicSentinel(Isolate* isolate) { return isolate->factory()->megamorphic_symbol(); } Handle FeedbackVector::PremonomorphicSentinel(Isolate* isolate) { return isolate->factory()->premonomorphic_symbol(); } Symbol FeedbackVector::RawUninitializedSentinel(Isolate* isolate) { return ReadOnlyRoots(isolate).uninitialized_symbol(); } bool FeedbackMetadataIterator::HasNext() const { return next_slot_.ToInt() < metadata().slot_count(); } FeedbackSlot FeedbackMetadataIterator::Next() { DCHECK(HasNext()); cur_slot_ = next_slot_; slot_kind_ = metadata().GetKind(cur_slot_); next_slot_ = FeedbackSlot(next_slot_.ToInt() + entry_size()); return cur_slot_; } int FeedbackMetadataIterator::entry_size() const { return FeedbackMetadata::GetSlotSize(kind()); } MaybeObject FeedbackNexus::GetFeedback() const { MaybeObject feedback = vector().Get(slot()); FeedbackVector::AssertNoLegacyTypes(feedback); return feedback; } MaybeObject FeedbackNexus::GetFeedbackExtra() const { #ifdef DEBUG FeedbackSlotKind kind = vector().GetKind(slot()); DCHECK_LT(1, FeedbackMetadata::GetSlotSize(kind)); #endif int extra_index = vector().GetIndex(slot()) + 1; return vector().get(extra_index); } void FeedbackNexus::SetFeedback(Object feedback, WriteBarrierMode mode) { SetFeedback(MaybeObject::FromObject(feedback)); } void FeedbackNexus::SetFeedback(MaybeObject feedback, WriteBarrierMode mode) { FeedbackVector::AssertNoLegacyTypes(feedback); vector().Set(slot(), feedback, mode); } void FeedbackNexus::SetFeedbackExtra(Object feedback_extra, WriteBarrierMode mode) { #ifdef DEBUG FeedbackSlotKind kind = vector().GetKind(slot()); DCHECK_LT(1, FeedbackMetadata::GetSlotSize(kind)); FeedbackVector::AssertNoLegacyTypes(MaybeObject::FromObject(feedback_extra)); #endif int index = vector().GetIndex(slot()) + 1; vector().set(index, MaybeObject::FromObject(feedback_extra), mode); } void FeedbackNexus::SetFeedbackExtra(MaybeObject feedback_extra, WriteBarrierMode mode) { #ifdef DEBUG FeedbackVector::AssertNoLegacyTypes(feedback_extra); #endif int index = vector().GetIndex(slot()) + 1; vector().set(index, feedback_extra, mode); } Isolate* FeedbackNexus::GetIsolate() const { return vector().GetIsolate(); } } // namespace internal } // namespace v8 #include "src/objects/object-macros-undef.h" #endif // V8_OBJECTS_FEEDBACK_VECTOR_INL_H_