| // 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/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/feedback-cell-inl.h" | 
 | #include "src/objects/feedback-vector.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 { | 
 |  | 
 | #include "torque-generated/src/objects/feedback-vector-tq-inl.inc" | 
 |  | 
 | TQ_OBJECT_CONSTRUCTORS_IMPL(FeedbackVector) | 
 | OBJECT_CONSTRUCTORS_IMPL(FeedbackMetadata, HeapObject) | 
 | OBJECT_CONSTRUCTORS_IMPL(ClosureFeedbackCellArray, FixedArray) | 
 |  | 
 | NEVER_READ_ONLY_SPACE_IMPL(FeedbackVector) | 
 | NEVER_READ_ONLY_SPACE_IMPL(ClosureFeedbackCellArray) | 
 |  | 
 | CAST_ACCESSOR(FeedbackMetadata) | 
 | CAST_ACCESSOR(ClosureFeedbackCellArray) | 
 |  | 
 | INT32_ACCESSORS(FeedbackMetadata, slot_count, kSlotCountOffset) | 
 |  | 
 | INT32_ACCESSORS(FeedbackMetadata, create_closure_slot_count, | 
 |                 kCreateClosureSlotCountOffset) | 
 |  | 
 | int32_t FeedbackMetadata::synchronized_slot_count() const { | 
 |   return base::Acquire_Load( | 
 |       reinterpret_cast<const base::Atomic32*>(field_address(kSlotCountOffset))); | 
 | } | 
 |  | 
 | int32_t FeedbackMetadata::get(int index) const { | 
 |   DCHECK(index >= 0 && index < length()); | 
 |   int offset = kHeaderSize + index * kInt32Size; | 
 |   return ReadField<int32_t>(offset); | 
 | } | 
 |  | 
 | void FeedbackMetadata::set(int index, int32_t value) { | 
 |   DCHECK(index >= 0 && index < length()); | 
 |   int offset = kHeaderSize + index * kInt32Size; | 
 |   WriteField<int32_t>(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<FeedbackCell> ClosureFeedbackCellArray::GetFeedbackCell(int index) { | 
 |   return handle(FeedbackCell::cast(get(index)), GetIsolate()); | 
 | } | 
 |  | 
 | 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 = maybe_optimized_code(); | 
 |   DCHECK(slot->IsWeakOrCleared()); | 
 |   HeapObject heap_object; | 
 |   Code code = | 
 |       slot->GetHeapObject(&heap_object) ? Code::cast(heap_object) : Code(); | 
 |   // It is possible that the maybe_optimized_code slot is cleared but the | 
 |   // optimization tier hasn't been updated yet. We update the tier when we | 
 |   // execute the function next time / when we create new closure. | 
 |   DCHECK_IMPLIES(!code.is_null(), OptimizationTierBits::decode(flags()) == | 
 |                                       GetTierForCodeKind(code.kind())); | 
 |   return code; | 
 | } | 
 |  | 
 | OptimizationMarker FeedbackVector::optimization_marker() const { | 
 |   return OptimizationMarkerBits::decode(flags()); | 
 | } | 
 |  | 
 | OptimizationTier FeedbackVector::optimization_tier() const { | 
 |   OptimizationTier tier = OptimizationTierBits::decode(flags()); | 
 |   // It is possible that the optimization tier bits aren't updated when the code | 
 |   // was cleared due to a GC. | 
 |   DCHECK_IMPLIES(tier == OptimizationTier::kNone, | 
 |                  maybe_optimized_code()->IsCleared()); | 
 |   return tier; | 
 | } | 
 |  | 
 | 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(intptr_t index) { | 
 |   DCHECK_LE(static_cast<uintptr_t>(index), | 
 |             static_cast<uintptr_t>(std::numeric_limits<int>::max())); | 
 |   return FeedbackSlot(static_cast<int>(index)); | 
 | } | 
 |  | 
 | #ifdef DEBUG | 
 | // Instead of FixedArray, the Feedback and the Extra should contain | 
 | // WeakFixedArrays. The only allowed FixedArray subtype is HashTable. | 
 | bool FeedbackVector::IsOfLegacyType(MaybeObject value) { | 
 |   HeapObject heap_object; | 
 |   if (value->GetHeapObject(&heap_object)) { | 
 |     return heap_object.IsFixedArray() && !heap_object.IsHashTable(); | 
 |   } | 
 |   return false; | 
 | } | 
 | #endif  // DEBUG | 
 |  | 
 | MaybeObject FeedbackVector::Get(FeedbackSlot slot) const { | 
 |   MaybeObject value = raw_feedback_slots(GetIndex(slot)); | 
 |   DCHECK(!IsOfLegacyType(value)); | 
 |   return value; | 
 | } | 
 |  | 
 | MaybeObject FeedbackVector::Get(IsolateRoot isolate, FeedbackSlot slot) const { | 
 |   MaybeObject value = raw_feedback_slots(isolate, GetIndex(slot)); | 
 |   DCHECK(!IsOfLegacyType(value)); | 
 |   return value; | 
 | } | 
 |  | 
 | Handle<FeedbackCell> FeedbackVector::GetClosureFeedbackCell(int index) const { | 
 |   DCHECK_GE(index, 0); | 
 |   ClosureFeedbackCellArray cell_array = | 
 |       ClosureFeedbackCellArray::cast(closure_feedback_cell_array()); | 
 |   return cell_array.GetFeedbackCell(index); | 
 | } | 
 |  | 
 | MaybeObject FeedbackVector::SynchronizedGet(FeedbackSlot slot) const { | 
 |   const int i = slot.ToInt(); | 
 |   DCHECK_LT(static_cast<unsigned>(i), static_cast<unsigned>(this->length())); | 
 |   const int offset = kRawFeedbackSlotsOffset + i * kTaggedSize; | 
 |   MaybeObject value = TaggedField<MaybeObject>::Acquire_Load(*this, offset); | 
 |   DCHECK(!IsOfLegacyType(value)); | 
 |   return value; | 
 | } | 
 |  | 
 | void FeedbackVector::SynchronizedSet(FeedbackSlot slot, MaybeObject value, | 
 |                                      WriteBarrierMode mode) { | 
 |   DCHECK(!IsOfLegacyType(value)); | 
 |   const int i = slot.ToInt(); | 
 |   DCHECK_LT(static_cast<unsigned>(i), static_cast<unsigned>(this->length())); | 
 |   const int offset = kRawFeedbackSlotsOffset + i * kTaggedSize; | 
 |   TaggedField<MaybeObject>::Release_Store(*this, offset, value); | 
 |   CONDITIONAL_WEAK_WRITE_BARRIER(*this, offset, value, mode); | 
 | } | 
 |  | 
 | void FeedbackVector::SynchronizedSet(FeedbackSlot slot, Object value, | 
 |                                      WriteBarrierMode mode) { | 
 |   SynchronizedSet(slot, MaybeObject::FromObject(value), mode); | 
 | } | 
 |  | 
 | void FeedbackVector::Set(FeedbackSlot slot, MaybeObject value, | 
 |                          WriteBarrierMode mode) { | 
 |   DCHECK(!IsOfLegacyType(value)); | 
 |   set_raw_feedback_slots(GetIndex(slot), value, mode); | 
 | } | 
 |  | 
 | void FeedbackVector::Set(FeedbackSlot slot, Object value, | 
 |                          WriteBarrierMode mode) { | 
 |   MaybeObject maybe_value = MaybeObject::FromObject(value); | 
 |   DCHECK(!IsOfLegacyType(maybe_value)); | 
 |   set_raw_feedback_slots(GetIndex(slot), maybe_value, mode); | 
 | } | 
 |  | 
 | inline MaybeObjectSlot FeedbackVector::slots_start() { | 
 |   return RawMaybeWeakField(OffsetOfElementAt(0)); | 
 | } | 
 |  | 
 | // 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. | 
 | template <CompareOperationFeedback::Type Feedback> | 
 | bool Is(int type_feedback) { | 
 |   return !(type_feedback & ~Feedback); | 
 | } | 
 |  | 
 | CompareOperationHint CompareOperationHintFromFeedback(int type_feedback) { | 
 |   if (Is<CompareOperationFeedback::kNone>(type_feedback)) { | 
 |     return CompareOperationHint::kNone; | 
 |   } | 
 |  | 
 |   if (Is<CompareOperationFeedback::kSignedSmall>(type_feedback)) { | 
 |     return CompareOperationHint::kSignedSmall; | 
 |   } else if (Is<CompareOperationFeedback::kNumber>(type_feedback)) { | 
 |     return CompareOperationHint::kNumber; | 
 |   } else if (Is<CompareOperationFeedback::kNumberOrBoolean>(type_feedback)) { | 
 |     return CompareOperationHint::kNumberOrBoolean; | 
 |   } | 
 |  | 
 |   if (Is<CompareOperationFeedback::kInternalizedString>(type_feedback)) { | 
 |     return CompareOperationHint::kInternalizedString; | 
 |   } else if (Is<CompareOperationFeedback::kString>(type_feedback)) { | 
 |     return CompareOperationHint::kString; | 
 |   } | 
 |  | 
 |   if (Is<CompareOperationFeedback::kReceiver>(type_feedback)) { | 
 |     return CompareOperationHint::kReceiver; | 
 |   } else if (Is<CompareOperationFeedback::kReceiverOrNullOrUndefined>( | 
 |                  type_feedback)) { | 
 |     return CompareOperationHint::kReceiverOrNullOrUndefined; | 
 |   } | 
 |  | 
 |   if (Is<CompareOperationFeedback::kBigInt>(type_feedback)) { | 
 |     return CompareOperationHint::kBigInt; | 
 |   } | 
 |  | 
 |   if (Is<CompareOperationFeedback::kSymbol>(type_feedback)) { | 
 |     return CompareOperationHint::kSymbol; | 
 |   } | 
 |  | 
 |   DCHECK(Is<CompareOperationFeedback::kAny>(type_feedback)); | 
 |   return CompareOperationHint::kAny; | 
 | } | 
 |  | 
 | // Helper function to transform the feedback to ForInHint. | 
 | ForInHint ForInHintFromFeedback(ForInFeedback 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<Symbol> FeedbackVector::UninitializedSentinel(Isolate* isolate) { | 
 |   return isolate->factory()->uninitialized_symbol(); | 
 | } | 
 |  | 
 | Handle<Symbol> FeedbackVector::MegamorphicSentinel(Isolate* isolate) { | 
 |   return isolate->factory()->megamorphic_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 NexusConfig::GetFeedback(FeedbackVector vector, | 
 |                                      FeedbackSlot slot) const { | 
 |   return vector.SynchronizedGet(slot); | 
 | } | 
 |  | 
 | void NexusConfig::SetFeedback(FeedbackVector vector, FeedbackSlot slot, | 
 |                               MaybeObject feedback, | 
 |                               WriteBarrierMode mode) const { | 
 |   DCHECK(can_write()); | 
 |   vector.SynchronizedSet(slot, feedback, mode); | 
 | } | 
 |  | 
 | MaybeObject FeedbackNexus::UninitializedSentinel() const { | 
 |   return MaybeObject::FromObject( | 
 |       *FeedbackVector::UninitializedSentinel(GetIsolate())); | 
 | } | 
 |  | 
 | MaybeObject FeedbackNexus::MegamorphicSentinel() const { | 
 |   return MaybeObject::FromObject( | 
 |       *FeedbackVector::MegamorphicSentinel(GetIsolate())); | 
 | } | 
 |  | 
 | MaybeObject FeedbackNexus::FromHandle(MaybeObjectHandle slot) const { | 
 |   return slot.is_null() ? HeapObjectReference::ClearedValue(config()->isolate()) | 
 |                         : *slot; | 
 | } | 
 |  | 
 | MaybeObjectHandle FeedbackNexus::ToHandle(MaybeObject value) const { | 
 |   return value.IsCleared() ? MaybeObjectHandle() | 
 |                            : MaybeObjectHandle(config()->NewHandle(value)); | 
 | } | 
 |  | 
 | MaybeObject FeedbackNexus::GetFeedback() const { | 
 |   auto pair = GetFeedbackPair(); | 
 |   return pair.first; | 
 | } | 
 |  | 
 | MaybeObject FeedbackNexus::GetFeedbackExtra() const { | 
 |   auto pair = GetFeedbackPair(); | 
 |   return pair.second; | 
 | } | 
 |  | 
 | std::pair<MaybeObject, MaybeObject> FeedbackNexus::GetFeedbackPair() const { | 
 |   if (config()->mode() == NexusConfig::BackgroundThread && | 
 |       feedback_cache_.has_value()) { | 
 |     return std::make_pair(FromHandle(feedback_cache_->first), | 
 |                           FromHandle(feedback_cache_->second)); | 
 |   } | 
 |   auto pair = FeedbackMetadata::GetSlotSize(kind()) == 2 | 
 |                   ? config()->GetFeedbackPair(vector(), slot()) | 
 |                   : std::make_pair(config()->GetFeedback(vector(), slot()), | 
 |                                    MaybeObject()); | 
 |   if (config()->mode() == NexusConfig::BackgroundThread && | 
 |       !feedback_cache_.has_value()) { | 
 |     feedback_cache_ = | 
 |         std::make_pair(ToHandle(pair.first), ToHandle(pair.second)); | 
 |   } | 
 |   return pair; | 
 | } | 
 |  | 
 | template <typename T> | 
 | struct IsValidFeedbackType | 
 |     : public std::integral_constant<bool, | 
 |                                     std::is_base_of<MaybeObject, T>::value || | 
 |                                         std::is_base_of<Object, T>::value> {}; | 
 |  | 
 | template <typename FeedbackType> | 
 | void FeedbackNexus::SetFeedback(FeedbackType feedback, WriteBarrierMode mode) { | 
 |   static_assert(IsValidFeedbackType<FeedbackType>(), | 
 |                 "feedbacks need to be Smi, Object or MaybeObject"); | 
 |   MaybeObject fmo = MaybeObject::Create(feedback); | 
 |   config()->SetFeedback(vector(), slot(), fmo, mode); | 
 | } | 
 |  | 
 | template <typename FeedbackType, typename FeedbackExtraType> | 
 | void FeedbackNexus::SetFeedback(FeedbackType feedback, WriteBarrierMode mode, | 
 |                                 FeedbackExtraType feedback_extra, | 
 |                                 WriteBarrierMode mode_extra) { | 
 |   static_assert(IsValidFeedbackType<FeedbackType>(), | 
 |                 "feedbacks need to be Smi, Object or MaybeObject"); | 
 |   static_assert(IsValidFeedbackType<FeedbackExtraType>(), | 
 |                 "feedbacks need to be Smi, Object or MaybeObject"); | 
 |   MaybeObject fmo = MaybeObject::Create(feedback); | 
 |   MaybeObject fmo_extra = MaybeObject::Create(feedback_extra); | 
 |   config()->SetFeedbackPair(vector(), slot(), fmo, mode, fmo_extra, mode_extra); | 
 | } | 
 |  | 
 | 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_ |