#ifndef V8_OBJECTS_FEEDBACK_VECTOR_H_
#define V8_OBJECTS_FEEDBACK_VECTOR_H_
#include <optional>
#include <vector>
#include "src/base/bit-field.h"
#include "src/base/logging.h"
#include "src/base/macros.h"
#include "src/base/small-vector.h"
#include "src/common/globals.h"
#include "src/objects/elements-kind.h"
#include "src/objects/feedback-cell.h"
#include "src/objects/map.h"
#include "src/objects/maybe-object.h"
#include "src/objects/name.h"
#include "src/objects/type-hints.h"
#include "src/zone/zone-containers.h"
#include "src/objects/object-macros.h"
namespace v8::internal {
class IsCompiledScope;
class FeedbackVectorSpec;
enum class UpdateFeedbackMode {
kOptionalFeedback,
kGuaranteedFeedback,
kNoFeedback,
};
enum class ClearBehavior {
kDefault,
kClearAll,
};
enum class FeedbackSlotKind : uint8_t {
kInvalid,
kStoreGlobalSloppy,
kSetNamedSloppy,
kSetKeyedSloppy,
kLastSloppyKind = kSetKeyedSloppy,
kCall,
kLoadProperty,
kLoadGlobalNotInsideTypeof,
kLoadGlobalInsideTypeof,
kLoadKeyed,
kHasKeyed,
kStoreGlobalStrict,
kSetNamedStrict,
kDefineNamedOwn,
kDefineKeyedOwn,
kSetKeyedStrict,
kStoreInArrayLiteral,
kBinaryOp,
kCompareOp,
kDefineKeyedOwnPropertyInLiteral,
kLiteral,
kForIn,
kInstanceOf,
kTypeOf,
kCloneObject,
kStringAddAndInternalize,
kJumpLoop,
kLast = kJumpLoop
};
static constexpr int kFeedbackSlotKindCount =
static_cast<int>(FeedbackSlotKind::kLast) + 1;
using MapAndHandler = std::pair<DirectHandle<Map>, MaybeObjectDirectHandle>;
class MapsAndHandlers {
public:
explicit MapsAndHandlers(Isolate* isolate)
: maps_(isolate), handlers_(isolate) {}
bool empty() const { return maps_.empty(); }
size_t size() const { return maps_.size(); }
void reserve(size_t capacity) {
maps_.reserve(capacity);
handlers_.reserve(capacity);
}
MapAndHandler operator[](size_t i) const {
DCHECK_LT(i, size());
MaybeObjectDirectHandle handler;
switch (handlers_reference_types_[i]) {
case HeapObjectReferenceType::STRONG:
handler = MaybeObjectDirectHandle(handlers_[i]);
break;
case HeapObjectReferenceType::WEAK:
handler = MaybeObjectDirectHandle::Weak(handlers_[i]);
break;
}
return MapAndHandler(maps_[i], handler);
}
void set_map(size_t i, DirectHandle<Map> map) {
DCHECK_LT(i, size());
maps_[i] = map;
}
void set_handler(size_t i, MaybeObjectDirectHandle handler) {
DCHECK_LT(i, size());
handlers_[i] =
handler.is_null() ? DirectHandle<Object>() : handler.object();
handlers_reference_types_[i] = handler.reference_type();
}
class Iterator final
: public base::iterator<std::input_iterator_tag, MapAndHandler> {
public:
constexpr Iterator() = default;
constexpr bool operator==(const Iterator& other) {
return index_ == other.index_;
}
constexpr bool operator!=(const Iterator& other) {
return index_ != other.index_;
}
constexpr Iterator& operator++() {
++index_;
return *this;
}
constexpr Iterator operator++(int) {
Iterator temp = *this;
++*this;
return temp;
}
value_type operator*() const {
DCHECK_NOT_NULL(container_);
return (*container_)[index_];
}
private:
friend class MapsAndHandlers;
constexpr Iterator(const MapsAndHandlers* container, size_t i)
: container_(container), index_(i) {}
const MapsAndHandlers* container_ = nullptr;
size_t index_ = 0;
};
void emplace_back(DirectHandle<Map> map, MaybeObjectDirectHandle handler) {
maps_.push_back(map);
handlers_.push_back(handler.is_null() ? DirectHandle<Object>()
: handler.object());
handlers_reference_types_.push_back(handler.reference_type());
}
Iterator begin() const { return Iterator(this, 0); }
Iterator end() const { return Iterator(this, size()); }
base::Vector<DirectHandle<Map>> maps() { return base::VectorOf(maps_); }
private:
DirectHandleSmallVector<Map, DEFAULT_MAX_POLYMORPHIC_MAP_COUNT> maps_;
DirectHandleSmallVector<Object, DEFAULT_MAX_POLYMORPHIC_MAP_COUNT> handlers_;
base::SmallVector<HeapObjectReferenceType, DEFAULT_MAX_POLYMORPHIC_MAP_COUNT>
handlers_reference_types_;
};
inline bool IsCallICKind(FeedbackSlotKind kind) {
return kind == FeedbackSlotKind::kCall;
}
inline bool IsLoadICKind(FeedbackSlotKind kind) {
return kind == FeedbackSlotKind::kLoadProperty;
}
inline bool IsLoadGlobalICKind(FeedbackSlotKind kind) {
return kind == FeedbackSlotKind::kLoadGlobalNotInsideTypeof ||
kind == FeedbackSlotKind::kLoadGlobalInsideTypeof;
}
inline bool IsKeyedLoadICKind(FeedbackSlotKind kind) {
return kind == FeedbackSlotKind::kLoadKeyed;
}
inline bool IsKeyedHasICKind(FeedbackSlotKind kind) {
return kind == FeedbackSlotKind::kHasKeyed;
}
inline bool IsStoreGlobalICKind(FeedbackSlotKind kind) {
return kind == FeedbackSlotKind::kStoreGlobalSloppy ||
kind == FeedbackSlotKind::kStoreGlobalStrict;
}
inline bool IsSetNamedICKind(FeedbackSlotKind kind) {
return kind == FeedbackSlotKind::kSetNamedSloppy ||
kind == FeedbackSlotKind::kSetNamedStrict;
}
inline bool IsDefineNamedOwnICKind(FeedbackSlotKind kind) {
return kind == FeedbackSlotKind::kDefineNamedOwn;
}
inline bool IsDefineKeyedOwnICKind(FeedbackSlotKind kind) {
return kind == FeedbackSlotKind::kDefineKeyedOwn;
}
inline bool IsDefineKeyedOwnPropertyInLiteralKind(FeedbackSlotKind kind) {
return kind == FeedbackSlotKind::kDefineKeyedOwnPropertyInLiteral;
}
inline bool IsKeyedStoreICKind(FeedbackSlotKind kind) {
return kind == FeedbackSlotKind::kSetKeyedSloppy ||
kind == FeedbackSlotKind::kSetKeyedStrict;
}
inline bool IsStoreInArrayLiteralICKind(FeedbackSlotKind kind) {
return kind == FeedbackSlotKind::kStoreInArrayLiteral;
}
inline bool IsGlobalICKind(FeedbackSlotKind kind) {
return IsLoadGlobalICKind(kind) || IsStoreGlobalICKind(kind);
}
inline bool IsCloneObjectKind(FeedbackSlotKind kind) {
return kind == FeedbackSlotKind::kCloneObject;
}
inline TypeofMode GetTypeofModeFromSlotKind(FeedbackSlotKind kind) {
DCHECK(IsLoadGlobalICKind(kind));
return (kind == FeedbackSlotKind::kLoadGlobalInsideTypeof)
? TypeofMode::kInside
: TypeofMode::kNotInside;
}
inline LanguageMode GetLanguageModeFromSlotKind(FeedbackSlotKind kind) {
DCHECK(IsSetNamedICKind(kind) || IsDefineNamedOwnICKind(kind) ||
IsStoreGlobalICKind(kind) || IsKeyedStoreICKind(kind) ||
IsDefineKeyedOwnICKind(kind));
static_assert(FeedbackSlotKind::kStoreGlobalSloppy <=
FeedbackSlotKind::kLastSloppyKind);
static_assert(FeedbackSlotKind::kSetKeyedSloppy <=
FeedbackSlotKind::kLastSloppyKind);
static_assert(FeedbackSlotKind::kSetNamedSloppy <=
FeedbackSlotKind::kLastSloppyKind);
return (kind <= FeedbackSlotKind::kLastSloppyKind) ? LanguageMode::kSloppy
: LanguageMode::kStrict;
}
V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
FeedbackSlotKind kind);
using MaybeObjectHandles = std::vector<MaybeObjectHandle>;
class FeedbackMetadata;
#include "torque-generated/src/objects/feedback-vector-tq.inc"
class ClosureFeedbackCellArrayShape final : public AllStatic {
public:
using ElementT = FeedbackCell;
using CompressionScheme = V8HeapCompressionScheme;
static constexpr RootIndex kMapRootIndex =
RootIndex::kClosureFeedbackCellArrayMap;
static constexpr bool kLengthEqualsCapacity = true;
};
class ClosureFeedbackCellArray
: public TaggedArrayBase<ClosureFeedbackCellArray,
ClosureFeedbackCellArrayShape> {
using Super =
TaggedArrayBase<ClosureFeedbackCellArray, ClosureFeedbackCellArrayShape>;
public:
using Shape = ClosureFeedbackCellArrayShape;
V8_EXPORT_PRIVATE static DirectHandle<ClosureFeedbackCellArray> New(
Isolate* isolate, DirectHandle<SharedFunctionInfo> shared,
AllocationType allocation = AllocationType::kYoung);
DECL_VERIFIER(ClosureFeedbackCellArray)
DECL_PRINTER(ClosureFeedbackCellArray)
class BodyDescriptor;
};
class NexusConfig;
class FeedbackVector
: public TorqueGeneratedFeedbackVector<FeedbackVector, HeapObject> {
public:
DEFINE_TORQUE_GENERATED_OSR_STATE()
DEFINE_TORQUE_GENERATED_FEEDBACK_VECTOR_FLAGS()
inline bool is_empty() const;
DECL_GETTER(has_metadata, bool)
DECL_GETTER(metadata, Tagged<FeedbackMetadata>)
DECL_ACQUIRE_GETTER(metadata, Tagged<FeedbackMetadata>)
using TorqueGeneratedFeedbackVector::invocation_count;
using TorqueGeneratedFeedbackVector::set_invocation_count;
DECL_RELAXED_INT32_ACCESSORS(invocation_count)
inline void clear_invocation_count(RelaxedStoreTag tag);
using TorqueGeneratedFeedbackVector::invocation_count_before_stable;
using TorqueGeneratedFeedbackVector::set_invocation_count_before_stable;
DECL_RELAXED_UINT8_ACCESSORS(invocation_count_before_stable)
static constexpr uint8_t kInvocationCountBeforeStableDeoptSentinel = 0xff;
static constexpr int kMaxOsrUrgency = 6;
static_assert(OsrUrgencyBits::is_valid(kMaxOsrUrgency));
inline int osr_urgency() const;
inline void set_osr_urgency(int urgency);
inline void reset_osr_urgency();
inline void RequestOsrAtNextOpportunity();
inline bool maybe_has_maglev_osr_code() const;
inline bool maybe_has_turbofan_osr_code() const;
inline bool maybe_has_optimized_osr_code() const;
inline void set_maybe_has_optimized_osr_code(bool value, CodeKind code_kind);
inline void reset_osr_state();
inline std::optional<Tagged<Code>> GetOptimizedOsrCode(
Isolate* isolate, Handle<BytecodeArray> bytecode_array,
FeedbackSlot slot);
void SetOptimizedOsrCode(Isolate* isolate, FeedbackSlot slot,
Tagged<Code> code);
inline void RecomputeOptimizedOsrCodeFlags(
Isolate* isolate, Handle<BytecodeArray> bytecode_array);
inline bool tiering_in_progress() const;
void set_tiering_in_progress(bool);
bool osr_tiering_in_progress();
void set_osr_tiering_in_progress(bool osr_in_progress);
inline bool interrupt_budget_reset_by_ic_change() const;
inline void set_interrupt_budget_reset_by_ic_change(bool value);
inline bool was_once_deoptimized() const;
inline void set_was_once_deoptimized();
void reset_flags();
static int GetIndex(FeedbackSlot slot) { return slot.ToInt(); }
static inline FeedbackSlot ToSlot(intptr_t index);
inline Tagged<MaybeObject> SynchronizedGet(FeedbackSlot slot) const;
inline void SynchronizedSet(FeedbackSlot slot, Tagged<MaybeObject> value,
WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
inline Tagged<MaybeObject> Get(FeedbackSlot slot) const;
inline Tagged<MaybeObject> Get(PtrComprCageBase cage_base,
FeedbackSlot slot) const;
inline DirectHandle<FeedbackCell> GetClosureFeedbackCell(Isolate* isolate,
int index) const;
inline Tagged<FeedbackCell> closure_feedback_cell(int index) const;
inline MaybeObjectSlot slots_start();
V8_EXPORT_PRIVATE FeedbackSlotKind GetKind(FeedbackSlot slot) const;
V8_EXPORT_PRIVATE FeedbackSlotKind GetKind(FeedbackSlot slot,
AcquireLoadTag tag) const;
V8_EXPORT_PRIVATE static Handle<FeedbackVector> New(
Isolate* isolate, DirectHandle<SharedFunctionInfo> shared,
DirectHandle<ClosureFeedbackCellArray> closure_feedback_cell_array,
DirectHandle<FeedbackCell> parent_feedback_cell,
IsCompiledScope* is_compiled_scope);
V8_EXPORT_PRIVATE static Handle<FeedbackVector> NewForTesting(
Isolate* isolate, const FeedbackVectorSpec* spec);
V8_EXPORT_PRIVATE static Handle<FeedbackVector>
NewWithOneBinarySlotForTesting(Zone* zone, Isolate* isolate);
V8_EXPORT_PRIVATE static Handle<FeedbackVector>
NewWithOneCompareSlotForTesting(Zone* zone, Isolate* isolate);
#define DEFINE_SLOT_KIND_PREDICATE(Name) \
bool Name(FeedbackSlot slot) const { return Name##Kind(GetKind(slot)); }
DEFINE_SLOT_KIND_PREDICATE(IsCallIC)
DEFINE_SLOT_KIND_PREDICATE(IsGlobalIC)
DEFINE_SLOT_KIND_PREDICATE(IsLoadIC)
DEFINE_SLOT_KIND_PREDICATE(IsLoadGlobalIC)
DEFINE_SLOT_KIND_PREDICATE(IsKeyedLoadIC)
DEFINE_SLOT_KIND_PREDICATE(IsSetNamedIC)
DEFINE_SLOT_KIND_PREDICATE(IsDefineNamedOwnIC)
DEFINE_SLOT_KIND_PREDICATE(IsStoreGlobalIC)
DEFINE_SLOT_KIND_PREDICATE(IsKeyedStoreIC)
#undef DEFINE_SLOT_KIND_PREDICATE
inline TypeofMode GetTypeofMode(FeedbackSlot slot) const {
return GetTypeofModeFromSlotKind(GetKind(slot));
}
inline LanguageMode GetLanguageMode(FeedbackSlot slot) const {
return GetLanguageModeFromSlotKind(GetKind(slot));
}
DECL_PRINTER(FeedbackVector)
void FeedbackSlotPrint(std::ostream& os, FeedbackSlot slot);
#ifdef V8_TRACE_FEEDBACK_UPDATES
static void TraceFeedbackChange(Isolate* isolate,
Tagged<FeedbackVector> vector,
FeedbackSlot slot, const char* reason);
#endif
bool ClearSlots(Isolate* isolate) {
return ClearSlots(isolate, ClearBehavior::kDefault);
}
bool ClearAllSlotsForTesting(Isolate* isolate) {
return ClearSlots(isolate, ClearBehavior::kClearAll);
}
static inline DirectHandle<Symbol> UninitializedSentinel(Isolate* isolate);
static inline Handle<Symbol> MegamorphicSentinel(Isolate* isolate);
static inline DirectHandle<Symbol> MegaDOMSentinel(Isolate* isolate);
static inline Tagged<Symbol> RawUninitializedSentinel(Isolate* isolate);
static_assert(kHeaderSize % kObjectAlignment == 0,
"Header must be padded for alignment");
class BodyDescriptor;
static constexpr int OffsetOfElementAt(int index) {
return kRawFeedbackSlotsOffset + index * kTaggedSize;
}
TQ_OBJECT_CONSTRUCTORS(FeedbackVector)
private:
bool ClearSlots(Isolate* isolate, ClearBehavior behavior);
static void AddToVectorsForProfilingTools(
Isolate* isolate, DirectHandle<FeedbackVector> vector);
inline void Set(FeedbackSlot slot, Tagged<MaybeObject> value,
WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
#ifdef DEBUG
inline static bool IsOfLegacyType(Tagged<MaybeObject> value);
#endif
friend NexusConfig;
using TorqueGeneratedFeedbackVector::raw_feedback_slots;
};
class V8_EXPORT_PRIVATE FeedbackVectorSpec {
public:
explicit FeedbackVectorSpec(Zone* zone)
: slot_kinds_(zone), create_closure_parameter_counts_(zone) {
slot_kinds_.reserve(16);
}
int slot_count() const { return static_cast<int>(slot_kinds_.size()); }
int create_closure_slot_count() const {
return static_cast<int>(create_closure_parameter_counts_.size());
}
int AddCreateClosureParameterCount(uint16_t parameter_count) {
create_closure_parameter_counts_.push_back(parameter_count);
return create_closure_slot_count() - 1;
}
uint16_t GetCreateClosureParameterCount(int index) const {
return create_closure_parameter_counts_.at(index);
}
FeedbackSlotKind GetKind(FeedbackSlot slot) const {
return slot_kinds_.at(slot.ToInt());
}
FeedbackSlot AddCallICSlot() { return AddSlot(FeedbackSlotKind::kCall); }
FeedbackSlot AddLoadICSlot() {
return AddSlot(FeedbackSlotKind::kLoadProperty);
}
FeedbackSlot AddLoadGlobalICSlot(TypeofMode typeof_mode) {
return AddSlot(typeof_mode == TypeofMode::kInside
? FeedbackSlotKind::kLoadGlobalInsideTypeof
: FeedbackSlotKind::kLoadGlobalNotInsideTypeof);
}
FeedbackSlot AddKeyedLoadICSlot() {
return AddSlot(FeedbackSlotKind::kLoadKeyed);
}
FeedbackSlot AddKeyedHasICSlot() {
return AddSlot(FeedbackSlotKind::kHasKeyed);
}
FeedbackSlotKind GetStoreICSlot(LanguageMode language_mode) {
static_assert(LanguageModeSize == 2);
return is_strict(language_mode) ? FeedbackSlotKind::kSetNamedStrict
: FeedbackSlotKind::kSetNamedSloppy;
}
FeedbackSlot AddStoreICSlot(LanguageMode language_mode) {
return AddSlot(GetStoreICSlot(language_mode));
}
FeedbackSlot AddDefineNamedOwnICSlot() {
return AddSlot(FeedbackSlotKind::kDefineNamedOwn);
}
FeedbackSlot AddDefineKeyedOwnICSlot() {
return AddSlot(FeedbackSlotKind::kDefineKeyedOwn);
}
FeedbackSlot AddStoreGlobalICSlot(LanguageMode language_mode) {
static_assert(LanguageModeSize == 2);
return AddSlot(is_strict(language_mode)
? FeedbackSlotKind::kStoreGlobalStrict
: FeedbackSlotKind::kStoreGlobalSloppy);
}
FeedbackSlotKind GetKeyedStoreICSlotKind(LanguageMode language_mode) {
static_assert(LanguageModeSize == 2);
return is_strict(language_mode) ? FeedbackSlotKind::kSetKeyedStrict
: FeedbackSlotKind::kSetKeyedSloppy;
}
FeedbackSlot AddKeyedStoreICSlot(LanguageMode language_mode) {
return AddSlot(GetKeyedStoreICSlotKind(language_mode));
}
FeedbackSlot AddStoreInArrayLiteralICSlot() {
return AddSlot(FeedbackSlotKind::kStoreInArrayLiteral);
}
FeedbackSlot AddBinaryOpICSlot() {
return AddSlot(FeedbackSlotKind::kBinaryOp);
}
FeedbackSlot AddCompareICSlot() {
return AddSlot(FeedbackSlotKind::kCompareOp);
}
FeedbackSlot AddForInSlot() { return AddSlot(FeedbackSlotKind::kForIn); }
FeedbackSlot AddInstanceOfSlot() {
return AddSlot(FeedbackSlotKind::kInstanceOf);
}
FeedbackSlot AddTypeOfSlot() { return AddSlot(FeedbackSlotKind::kTypeOf); }
FeedbackSlot AddLiteralSlot() { return AddSlot(FeedbackSlotKind::kLiteral); }
FeedbackSlot AddDefineKeyedOwnPropertyInLiteralICSlot() {
return AddSlot(FeedbackSlotKind::kDefineKeyedOwnPropertyInLiteral);
}
FeedbackSlot AddCloneObjectSlot() {
return AddSlot(FeedbackSlotKind::kCloneObject);
}
FeedbackSlot AddJumpLoopSlot() {
return AddSlot(FeedbackSlotKind::kJumpLoop);
}
FeedbackSlot AddStringAddAndInternalizeICSlot() {
return AddSlot(FeedbackSlotKind::kStringAddAndInternalize);
}
#ifdef OBJECT_PRINT
void Print();
#endif
DECL_PRINTER(FeedbackVectorSpec)
private:
FeedbackSlot AddSlot(FeedbackSlotKind kind);
void append(FeedbackSlotKind kind) { slot_kinds_.push_back(kind); }
static_assert(sizeof(FeedbackSlotKind) == sizeof(uint8_t));
ZoneVector<FeedbackSlotKind> slot_kinds_;
ZoneVector<uint16_t> create_closure_parameter_counts_;
friend class SharedFeedbackSlot;
};
class SharedFeedbackSlot {
public:
SharedFeedbackSlot(FeedbackVectorSpec* spec, FeedbackSlotKind kind)
: kind_(kind), spec_(spec) {}
FeedbackSlot Get() {
if (slot_.IsInvalid()) slot_ = spec_->AddSlot(kind_);
return slot_;
}
private:
FeedbackSlotKind kind_;
FeedbackSlot slot_;
FeedbackVectorSpec* spec_;
};
class FeedbackMetadata : public HeapObject {
public:
DECL_INT32_ACCESSORS(slot_count)
DECL_INT32_ACCESSORS(create_closure_slot_count)
inline int32_t slot_count(AcquireLoadTag) const;
inline int32_t create_closure_slot_count(AcquireLoadTag) const;
static inline int GetSlotSize(FeedbackSlotKind kind);
bool SpecDiffersFrom(const FeedbackVectorSpec* other_spec) const;
inline bool is_empty() const;
V8_EXPORT_PRIVATE FeedbackSlotKind GetKind(FeedbackSlot slot) const;
V8_EXPORT_PRIVATE uint16_t GetCreateClosureParameterCount(int index) const;
template <typename IsolateT>
V8_EXPORT_PRIVATE static Handle<FeedbackMetadata> New(
IsolateT* isolate, const FeedbackVectorSpec* spec);
DECL_PRINTER(FeedbackMetadata)
DECL_VERIFIER(FeedbackMetadata)
static const char* Kind2String(FeedbackSlotKind kind);
inline int AllocatedSize();
static int SizeFor(int slot_count, int create_closure_slot_count) {
return OBJECT_POINTER_ALIGN(kHeaderSize +
word_count(slot_count) * kInt32Size +
create_closure_slot_count * kUInt16Size);
}
#define FIELDS(V) \
V(kSlotCountOffset, kInt32Size) \
V(kCreateClosureSlotCountOffset, kInt32Size) \
V(kHeaderSize, 0)
DEFINE_FIELD_OFFSET_CONSTANTS(HeapObject::kHeaderSize, FIELDS)
#undef FIELDS
class BodyDescriptor;
private:
friend class AccessorAssembler;
inline int32_t get(int index) const;
inline void set(int index, int32_t value);
static int word_count(int slot_count) {
return VectorICComputer::word_count(slot_count);
}
inline int word_count() const;
static const int kFeedbackSlotKindBits = 5;
static_assert(kFeedbackSlotKindCount <= (1 << kFeedbackSlotKindBits));
void SetKind(FeedbackSlot slot, FeedbackSlotKind kind);
void SetCreateClosureParameterCount(int index, uint16_t parameter_count);
using VectorICComputer =
base::BitSetComputer<FeedbackSlotKind, kFeedbackSlotKindBits,
kInt32Size * kBitsPerByte, uint32_t>;
OBJECT_CONSTRUCTORS(FeedbackMetadata, HeapObject);
};
static_assert((Name::kEmptyHashField & kHeapObjectTag) == kHeapObjectTag);
static_assert(Name::kEmptyHashField == 0x3);
static_assert(Name::kHashNotComputedMask == kHeapObjectTag);
class FeedbackMetadataIterator {
public:
explicit FeedbackMetadataIterator(Handle<FeedbackMetadata> metadata)
: metadata_handle_(metadata),
next_slot_(FeedbackSlot(0)),
slot_kind_(FeedbackSlotKind::kInvalid) {}
FeedbackMetadataIterator(Tagged<FeedbackMetadata> metadata,
const DisallowGarbageCollection& no_gc)
: metadata_(metadata),
next_slot_(FeedbackSlot(0)),
slot_kind_(FeedbackSlotKind::kInvalid) {}
inline bool HasNext() const;
inline FeedbackSlot Next();
FeedbackSlotKind kind() const {
DCHECK_NE(FeedbackSlotKind::kInvalid, slot_kind_);
return slot_kind_;
}
inline int entry_size() const;
private:
Tagged<FeedbackMetadata> metadata() const {
return !metadata_handle_.is_null() ? *metadata_handle_ : metadata_;
}
Handle<FeedbackMetadata> metadata_handle_;
Tagged<FeedbackMetadata> metadata_;
FeedbackSlot cur_slot_;
FeedbackSlot next_slot_;
FeedbackSlotKind slot_kind_;
};
class V8_EXPORT_PRIVATE NexusConfig {
public:
static NexusConfig FromMainThread(Isolate* isolate) {
DCHECK_NOT_NULL(isolate);
return NexusConfig(isolate);
}
static NexusConfig FromBackgroundThread(Isolate* isolate,
LocalHeap* local_heap) {
DCHECK_NOT_NULL(isolate);
return NexusConfig(isolate, local_heap);
}
enum Mode { MainThread, BackgroundThread };
Mode mode() const {
return local_heap_ == nullptr ? MainThread : BackgroundThread;
}
Isolate* isolate() const { return isolate_; }
MaybeObjectHandle NewHandle(Tagged<MaybeObject> object) const;
template <typename T>
Handle<T> NewHandle(Tagged<T> object) const;
bool can_write() const { return mode() == MainThread; }
inline Tagged<MaybeObject> GetFeedback(Tagged<FeedbackVector> vector,
FeedbackSlot slot) const;
inline void SetFeedback(Tagged<FeedbackVector> vector, FeedbackSlot slot,
Tagged<MaybeObject> object,
WriteBarrierMode mode = UPDATE_WRITE_BARRIER) const;
std::pair<Tagged<MaybeObject>, Tagged<MaybeObject>> GetFeedbackPair(
Tagged<FeedbackVector> vector, FeedbackSlot slot) const;
void SetFeedbackPair(Tagged<FeedbackVector> vector, FeedbackSlot start_slot,
Tagged<MaybeObject> feedback, WriteBarrierMode mode,
Tagged<MaybeObject> feedback_extra,
WriteBarrierMode mode_extra) const;
private:
explicit NexusConfig(Isolate* isolate)
: isolate_(isolate), local_heap_(nullptr) {}
NexusConfig(Isolate* isolate, LocalHeap* local_heap)
: isolate_(isolate), local_heap_(local_heap) {}
Isolate* const isolate_;
LocalHeap* const local_heap_;
};
class V8_EXPORT_PRIVATE FeedbackNexus final {
public:
FeedbackNexus(Isolate* isolate, Handle<FeedbackVector> vector,
FeedbackSlot slot);
FeedbackNexus(Isolate*, Tagged<FeedbackVector> vector, FeedbackSlot slot);
FeedbackNexus(Handle<FeedbackVector> vector, FeedbackSlot slot,
const NexusConfig& config);
const NexusConfig* config() const { return &config_; }
DirectHandle<FeedbackVector> vector_handle() const {
DCHECK(vector_.is_null());
return vector_handle_;
}
Tagged<FeedbackVector> vector() const {
return vector_handle_.is_null() ? vector_ : *vector_handle_;
}
FeedbackSlot slot() const { return slot_; }
FeedbackSlotKind kind() const { return kind_; }
inline LanguageMode GetLanguageMode() const {
return vector()->GetLanguageMode(slot());
}
static inline Builtin GetLoadICHandlerForFieldIndex(int field_index,
bool is_inobject,
bool is_double);
InlineCacheState ic_state() const;
static Builtin ic_handler(Tagged<MaybeObject> feedback_extra,
FeedbackSlotKind kind);
Builtin ic_handler() const;
bool IsUninitialized() const {
return ic_state() == InlineCacheState::UNINITIALIZED;
}
bool IsMegamorphic() const {
return ic_state() == InlineCacheState::MEGAMORPHIC;
}
bool IsGeneric() const { return ic_state() == InlineCacheState::GENERIC; }
void Print(std::ostream& os);
Tagged<Map> GetFirstMap() const;
int ExtractMaps(MapHandles* maps) const;
using TryUpdateHandler = std::function<MaybeHandle<Map>(Handle<Map>)>;
int ExtractMapsAndHandlers(
MapsAndHandlers* maps_and_handlers,
TryUpdateHandler map_handler = TryUpdateHandler()) const;
MaybeObjectDirectHandle FindHandlerForMap(DirectHandle<Map> map) const;
template <typename F>
void IterateMapsWithUnclearedHandler(F) const;
bool IsCleared() const {
InlineCacheState state = ic_state();
return !v8_flags.use_ic || state == InlineCacheState::UNINITIALIZED;
}
bool Clear(ClearBehavior behavior);
void ConfigureUninitialized();
bool ConfigureMegamorphic();
bool ConfigureMegamorphic(IcCheckType property_type);
inline Tagged<MaybeObject> GetFeedback() const;
inline Tagged<MaybeObject> GetFeedbackExtra() const;
inline std::pair<Tagged<MaybeObject>, Tagged<MaybeObject>> GetFeedbackPair()
const;
void ConfigureMonomorphic(DirectHandle<Name> name,
DirectHandle<Map> receiver_map,
const MaybeObjectDirectHandle& handler);
void ConfigurePolymorphic(DirectHandle<Name> name,
MapsAndHandlers const& maps_and_handlers);
void ConfigureMegaDOM(const MaybeObjectDirectHandle& handler);
MaybeObjectHandle ExtractMegaDOMHandler();
BinaryOperationHint GetBinaryOperationFeedback() const;
CompareOperationHint GetCompareOperationFeedback() const;
TypeOfFeedback::Result GetTypeOfFeedback() const;
ForInHint GetForInFeedback() const;
KeyedAccessLoadMode GetKeyedAccessLoadMode() const;
KeyedAccessStoreMode GetKeyedAccessStoreMode() const;
IcCheckType GetKeyType() const;
Tagged<Name> GetName() const;
bool IsOneMapManyNames() const;
int GetCallCount();
void SetSpeculationMode(SpeculationMode mode);
void NextSpeculationMode(SpeculationMode mode);
SpeculationMode GetSpeculationMode();
CallFeedbackContent GetCallFeedbackContent();
float ComputeCallFrequency();
using SpeculationModeField = base::BitField<SpeculationMode, 0, 2>;
using CallFeedbackContentField = base::BitField<CallFeedbackContent, 2, 1>;
using CallCountField = base::BitField<uint32_t, 3, 29>;
MaybeDirectHandle<JSObject> GetConstructorFeedback() const;
void ConfigurePropertyCellMode(DirectHandle<PropertyCell> cell);
bool ConfigureLexicalVarMode(int script_context_index, int context_slot_index,
bool immutable);
void ConfigureHandlerMode(const MaybeObjectDirectHandle& handler);
static constexpr int kCloneObjectPolymorphicEntrySize = 2;
void ConfigureCloneObject(DirectHandle<Map> source_map,
const MaybeObjectHandle& handler);
#define LEXICAL_MODE_BIT_FIELDS(V, _) \
V(ContextIndexBits, unsigned, 12, _) \
V(SlotIndexBits, unsigned, 18, _) \
V(ImmutabilityBit, bool, 1, _)
DEFINE_BIT_FIELDS(LEXICAL_MODE_BIT_FIELDS)
#undef LEXICAL_MODE_BIT_FIELDS
static_assert(LEXICAL_MODE_BIT_FIELDS_Ranges::kBitsCount <= kSmiValueSize);
private:
template <typename FeedbackType>
inline void SetFeedback(Tagged<FeedbackType> feedback,
WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
template <typename FeedbackType, typename FeedbackExtraType>
inline void SetFeedback(Tagged<FeedbackType> feedback, WriteBarrierMode mode,
Tagged<FeedbackExtraType> feedback_extra,
WriteBarrierMode mode_extra = UPDATE_WRITE_BARRIER);
inline Tagged<MaybeObject> UninitializedSentinel() const;
inline Tagged<MaybeObject> MegamorphicSentinel() const;
inline Tagged<MaybeObject> MegaDOMSentinel() const;
DirectHandle<WeakFixedArray> CreateArrayOfSize(int length);
inline Tagged<MaybeObject> FromHandle(MaybeObjectDirectHandle slot) const;
inline MaybeObjectHandle ToHandle(Tagged<MaybeObject> value) const;
Handle<FeedbackVector> vector_handle_;
Tagged<FeedbackVector> vector_;
FeedbackSlot slot_;
FeedbackSlotKind kind_;
mutable std::optional<std::pair<MaybeObjectHandle, MaybeObjectHandle>>
feedback_cache_;
NexusConfig config_;
Isolate* isolate_;
};
class V8_EXPORT_PRIVATE FeedbackIterator final {
public:
explicit FeedbackIterator(const FeedbackNexus* nexus);
void Advance();
bool done() { return done_; }
Tagged<Map> map() { return map_; }
Tagged<MaybeObject> handler() { return handler_; }
static int SizeFor(int number_of_entries) {
CHECK_GT(number_of_entries, 0);
return number_of_entries * kEntrySize;
}
static int MapIndexForEntry(int entry) {
CHECK_GE(entry, 0);
return entry * kEntrySize;
}
static int HandlerIndexForEntry(int entry) {
CHECK_GE(entry, 0);
return (entry * kEntrySize) + kHandlerOffset;
}
static constexpr int kEntrySize = 2;
static constexpr int kHandlerOffset = 1;
private:
void AdvancePolymorphic();
enum State { kMonomorphic, kPolymorphic, kOther };
DirectHandle<WeakFixedArray> polymorphic_feedback_;
Tagged<Map> map_;
Tagged<MaybeObject> handler_;
bool done_;
int index_;
State state_;
};
inline BinaryOperationHint BinaryOperationHintFromFeedback(int type_feedback);
inline CompareOperationHint CompareOperationHintFromFeedback(int type_feedback);
inline ForInHint ForInHintFromFeedback(ForInFeedback type_feedback);
}
#include "src/objects/object-macros-undef.h"
#endif