blob: af03bb4130cdc4152713bc7f1c72a21fd1671802 [file] [log] [blame]
// Copyright 2014 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.
#include <vector>
#include "src/base/logging.h"
#include "src/base/macros.h"
#include "src/common/globals.h"
#include "src/objects/elements-kind.h"
#include "src/objects/map.h"
#include "src/objects/name.h"
#include "src/objects/type-hints.h"
#include "src/zone/zone-containers.h"
// Has to be the last include (doesn't have include guards):
#include "src/objects/object-macros.h"
namespace v8 {
namespace internal {
enum class FeedbackSlotKind {
// This kind means that the slot points to the middle of other slot
// which occupies more than one feedback vector element.
// There must be no such slots in the system.
// Sloppy kinds come first, for easy language mode testing.
kLastSloppyKind = kStoreKeyedSloppy,
// Strict and language mode unaware kinds.
kKindsNumber // Last value indicating number of kinds.
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 IsStoreICKind(FeedbackSlotKind kind) {
return kind == FeedbackSlotKind::kStoreNamedSloppy ||
kind == FeedbackSlotKind::kStoreNamedStrict;
inline bool IsStoreOwnICKind(FeedbackSlotKind kind) {
return kind == FeedbackSlotKind::kStoreOwnNamed;
inline bool IsStoreDataPropertyInLiteralKind(FeedbackSlotKind kind) {
return kind == FeedbackSlotKind::kStoreDataPropertyInLiteral;
inline bool IsKeyedStoreICKind(FeedbackSlotKind kind) {
return kind == FeedbackSlotKind::kStoreKeyedSloppy ||
kind == FeedbackSlotKind::kStoreKeyedStrict;
inline bool IsStoreInArrayLiteralICKind(FeedbackSlotKind kind) {
return kind == FeedbackSlotKind::kStoreInArrayLiteral;
inline bool IsGlobalICKind(FeedbackSlotKind kind) {
return IsLoadGlobalICKind(kind) || IsStoreGlobalICKind(kind);
inline bool IsTypeProfileKind(FeedbackSlotKind kind) {
return kind == FeedbackSlotKind::kTypeProfile;
inline bool IsCloneObjectKind(FeedbackSlotKind kind) {
return kind == FeedbackSlotKind::kCloneObject;
inline TypeofMode GetTypeofModeFromSlotKind(FeedbackSlotKind kind) {
return (kind == FeedbackSlotKind::kLoadGlobalInsideTypeof)
inline LanguageMode GetLanguageModeFromSlotKind(FeedbackSlotKind kind) {
DCHECK(IsStoreICKind(kind) || IsStoreOwnICKind(kind) ||
IsStoreGlobalICKind(kind) || IsKeyedStoreICKind(kind));
STATIC_ASSERT(FeedbackSlotKind::kStoreGlobalSloppy <=
STATIC_ASSERT(FeedbackSlotKind::kStoreKeyedSloppy <=
STATIC_ASSERT(FeedbackSlotKind::kStoreNamedSloppy <=
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;
// ClosureFeedbackCellArray is a FixedArray that contains feedback cells used
// when creating closures from a function. Along with the feedback
// cells, the first slot (slot 0) is used to hold a budget to measure the
// hotness of the function. This is created once the function is compiled and is
// either held by the feedback vector (if allocated) or by the FeedbackCell of
// the closure.
class ClosureFeedbackCellArray : public FixedArray {
V8_EXPORT_PRIVATE static Handle<ClosureFeedbackCellArray> New(
Isolate* isolate, Handle<SharedFunctionInfo> shared);
inline Handle<FeedbackCell> GetFeedbackCell(int index);
OBJECT_CONSTRUCTORS(ClosureFeedbackCellArray, FixedArray);
// A FeedbackVector has a fixed header with:
// - shared function info (which includes feedback metadata)
// - invocation count
// - runtime profiler ticks
// - optimized code cell (weak cell or Smi marker)
// followed by an array of feedback slots, of length determined by the feedback
// metadata.
class FeedbackVector : public HeapObject {
inline bool is_empty() const;
inline FeedbackMetadata metadata() const;
// [shared_function_info]: The shared function info for the function with this
// feedback vector.
DECL_ACCESSORS(shared_function_info, SharedFunctionInfo)
// [optimized_code_weak_or_smi]: weak reference to optimized code or a Smi
// marker defining optimization behaviour.
DECL_ACCESSORS(optimized_code_weak_or_smi, MaybeObject)
// [feedback_cell_array]: The FixedArray to hold the feedback cells for any
// closures created by this function.
DECL_ACCESSORS(closure_feedback_cell_array, ClosureFeedbackCellArray)
// [length]: The length of the feedback vector (not including the header, i.e.
// the number of feedback slots).
// [invocation_count]: The number of times this function has been invoked.
// [profiler_ticks]: The number of times this function has been seen by the
// runtime profiler.
// Initialize the padding if necessary.
inline void clear_padding();
inline void clear_invocation_count();
inline Code optimized_code() const;
inline OptimizationMarker optimization_marker() const;
inline bool has_optimized_code() const;
inline bool has_optimization_marker() const;
void ClearOptimizedCode();
void EvictOptimizedCodeMarkedForDeoptimization(SharedFunctionInfo shared,
const char* reason);
static void SetOptimizedCode(Handle<FeedbackVector> vector,
Handle<Code> code);
void SetOptimizationMarker(OptimizationMarker marker);
// Clears the optimization marker in the feedback vector.
void ClearOptimizationMarker();
// Conversion from a slot to an integer index to the underlying array.
static int GetIndex(FeedbackSlot slot) { return slot.ToInt(); }
// Conversion from an integer index to the underlying array to a slot.
static inline FeedbackSlot ToSlot(int index);
inline MaybeObject Get(FeedbackSlot slot) const;
inline MaybeObject Get(Isolate* isolate, FeedbackSlot slot) const;
inline MaybeObject get(int index) const;
inline MaybeObject get(Isolate* isolate, int index) const;
inline void Set(FeedbackSlot slot, MaybeObject value,
WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
inline void set(int index, MaybeObject value,
WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
inline void Set(FeedbackSlot slot, Object value,
WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
inline void set(int index, Object value,
WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
// Returns the feedback cell at |index| that is used to create the
// closure.
inline Handle<FeedbackCell> GetClosureFeedbackCell(int index) const;
// Gives access to raw memory which stores the array's data.
inline MaybeObjectSlot slots_start();
// Returns slot kind for given slot.
V8_EXPORT_PRIVATE FeedbackSlotKind GetKind(FeedbackSlot slot) const;
FeedbackSlot GetTypeProfileSlot() const;
V8_EXPORT_PRIVATE static Handle<FeedbackVector> New(
Isolate* isolate, Handle<SharedFunctionInfo> shared,
Handle<ClosureFeedbackCellArray> closure_feedback_cell_array);
bool Name(FeedbackSlot slot) const { return Name##Kind(GetKind(slot)); }
// Returns typeof mode encoded into kind of given slot.
inline TypeofMode GetTypeofMode(FeedbackSlot slot) const {
return GetTypeofModeFromSlotKind(GetKind(slot));
// Returns language mode encoded into kind of given slot.
inline LanguageMode GetLanguageMode(FeedbackSlot slot) const {
return GetLanguageModeFromSlotKind(GetKind(slot));
V8_EXPORT_PRIVATE static void AssertNoLegacyTypes(MaybeObject object);
void FeedbackSlotPrint(std::ostream& os, FeedbackSlot slot); // NOLINT
// Clears the vector slots. Return true if feedback has changed.
bool ClearSlots(Isolate* isolate);
// The object that indicates an uninitialized cache.
static inline Handle<Symbol> UninitializedSentinel(Isolate* isolate);
// The object that indicates a generic state.
static inline Handle<Symbol> GenericSentinel(Isolate* isolate);
// The object that indicates a megamorphic state.
static inline Handle<Symbol> MegamorphicSentinel(Isolate* isolate);
// The object that indicates a premonomorphic state.
static inline Handle<Symbol> PremonomorphicSentinel(Isolate* isolate);
// A raw version of the uninitialized sentinel that's safe to read during
// garbage collection (e.g., for patching the cache).
static inline Symbol RawUninitializedSentinel(Isolate* isolate);
// Layout description.
static const int kHeaderSize = kSize;
static_assert(kSize % kObjectAlignment == 0,
"Header must be padded for alignment");
static const int kFeedbackSlotsOffset = kHeaderSize;
class BodyDescriptor;
static constexpr int OffsetOfElementAt(int index) {
return kFeedbackSlotsOffset + index * kTaggedSize;
// Garbage collection support.
static constexpr int SizeFor(int length) { return OffsetOfElementAt(length); }
static void AddToVectorsForProfilingTools(Isolate* isolate,
Handle<FeedbackVector> vector);
OBJECT_CONSTRUCTORS(FeedbackVector, HeapObject);
class V8_EXPORT_PRIVATE FeedbackVectorSpec {
explicit FeedbackVectorSpec(Zone* zone)
: slot_kinds_(zone), num_closure_feedback_cells_(0) {
int slots() const { return static_cast<int>(slot_kinds_.size()); }
int closure_feedback_cells() const { return num_closure_feedback_cells_; }
int AddFeedbackCellForCreateClosure() {
return num_closure_feedback_cells_++;
FeedbackSlotKind GetKind(FeedbackSlot slot) const {
return static_cast<FeedbackSlotKind>(;
bool HasTypeProfileSlot() const;
// If used, the TypeProfileSlot is always added as the first slot and its
// index is constant. If other slots are added before the TypeProfileSlot,
// this number changes.
static const int kTypeProfileSlotIndex = 0;
FeedbackSlot AddCallICSlot() { return AddSlot(FeedbackSlotKind::kCall); }
FeedbackSlot AddLoadICSlot() {
return AddSlot(FeedbackSlotKind::kLoadProperty);
FeedbackSlot AddLoadGlobalICSlot(TypeofMode typeof_mode) {
return AddSlot(typeof_mode == INSIDE_TYPEOF
? 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::kStoreNamedStrict
: FeedbackSlotKind::kStoreNamedSloppy;
FeedbackSlot AddStoreICSlot(LanguageMode language_mode) {
return AddSlot(GetStoreICSlot(language_mode));
FeedbackSlot AddStoreOwnICSlot() {
return AddSlot(FeedbackSlotKind::kStoreOwnNamed);
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::kStoreKeyedStrict
: FeedbackSlotKind::kStoreKeyedSloppy;
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 AddLiteralSlot() { return AddSlot(FeedbackSlotKind::kLiteral); }
FeedbackSlot AddStoreDataPropertyInLiteralICSlot() {
return AddSlot(FeedbackSlotKind::kStoreDataPropertyInLiteral);
FeedbackSlot AddTypeProfileSlot();
FeedbackSlot AddCloneObjectSlot() {
return AddSlot(FeedbackSlotKind::kCloneObject);
// For gdb debugging.
void Print();
#endif // OBJECT_PRINT
FeedbackSlot AddSlot(FeedbackSlotKind kind);
void append(FeedbackSlotKind kind) {
slot_kinds_.push_back(static_cast<unsigned char>(kind));
ZoneVector<unsigned char> slot_kinds_;
unsigned int num_closure_feedback_cells_;
friend class SharedFeedbackSlot;
// Helper class that creates a feedback slot on-demand.
class SharedFeedbackSlot {
// FeedbackSlot default constructor constructs an invalid slot.
SharedFeedbackSlot(FeedbackVectorSpec* spec, FeedbackSlotKind kind)
: kind_(kind), spec_(spec) {}
FeedbackSlot Get() {
if (slot_.IsInvalid()) slot_ = spec_->AddSlot(kind_);
return slot_;
FeedbackSlotKind kind_;
FeedbackSlot slot_;
FeedbackVectorSpec* spec_;
// FeedbackMetadata is an array-like object with a slot count (indicating how
// many slots are stored). We save space by packing several slots into an array
// of int32 data. The length is never stored - it is always calculated from
// slot_count. All instances are created through the static New function, and
// the number of slots is static once an instance is created.
class FeedbackMetadata : public HeapObject {
// The number of slots that this metadata contains. Stored as an int32.
// The number of feedback cells required for create closures. Stored as an
// int32.
// TODO(mythria): Consider using 16 bits for this and slot_count so that we
// can save 4 bytes.
// Get slot_count using an acquire load.
inline int32_t synchronized_slot_count() const;
// Returns number of feedback vector elements used by given slot kind.
static inline int GetSlotSize(FeedbackSlotKind kind);
bool SpecDiffersFrom(const FeedbackVectorSpec* other_spec) const;
inline bool is_empty() const;
// Returns slot kind for given slot.
V8_EXPORT_PRIVATE FeedbackSlotKind GetKind(FeedbackSlot slot) const;
// If {spec} is null, then it is considered empty.
V8_EXPORT_PRIVATE static Handle<FeedbackMetadata> New(
Isolate* isolate, const FeedbackVectorSpec* spec = nullptr);
static const char* Kind2String(FeedbackSlotKind kind);
bool HasTypeProfileSlot() const;
// Garbage collection support.
// This includes any necessary padding at the end of the object for pointer
// size alignment.
static int SizeFor(int slot_count) {
return OBJECT_POINTER_ALIGN(kHeaderSize + length(slot_count) * kInt32Size);
static const int kSlotCountOffset = HeapObject::kHeaderSize;
static const int kFeedbackCellCountOffset = kSlotCountOffset + kInt32Size;
static const int kHeaderSize = kFeedbackCellCountOffset + kInt32Size;
class BodyDescriptor;
friend class AccessorAssembler;
// Raw accessors to the encoded slot data.
inline int32_t get(int index) const;
inline void set(int index, int32_t value);
// The number of int32 data fields needed to store {slot_count} slots.
// Does not include any extra padding for pointer size alignment.
static int length(int slot_count) {
return VectorICComputer::word_count(slot_count);
inline int length() const;
static const int kFeedbackSlotKindBits = 5;
STATIC_ASSERT(static_cast<int>(FeedbackSlotKind::kKindsNumber) <
(1 << kFeedbackSlotKindBits));
void SetKind(FeedbackSlot slot, FeedbackSlotKind kind);
using VectorICComputer =
BitSetComputer<FeedbackSlotKind, kFeedbackSlotKindBits,
kInt32Size * kBitsPerByte, uint32_t>;
OBJECT_CONSTRUCTORS(FeedbackMetadata, HeapObject);
// Verify that an empty hash field looks like a tagged object, but can't
// possibly be confused with a pointer.
// NOLINTNEXTLINE(runtime/references) (false positive)
STATIC_ASSERT((Name::kEmptyHashField & kHeapObjectTag) == kHeapObjectTag);
STATIC_ASSERT(Name::kEmptyHashField == 0x3);
// Verify that a set hash field will not look like a tagged object.
STATIC_ASSERT(Name::kHashNotComputedMask == kHeapObjectTag);
class FeedbackMetadataIterator {
explicit FeedbackMetadataIterator(Handle<FeedbackMetadata> metadata)
: metadata_handle_(metadata),
slot_kind_(FeedbackSlotKind::kInvalid) {}
explicit FeedbackMetadataIterator(FeedbackMetadata metadata)
: metadata_(metadata),
slot_kind_(FeedbackSlotKind::kInvalid) {}
inline bool HasNext() const;
inline FeedbackSlot Next();
// Returns slot kind of the last slot returned by Next().
FeedbackSlotKind kind() const {
DCHECK_NE(FeedbackSlotKind::kInvalid, slot_kind_);
DCHECK_NE(FeedbackSlotKind::kKindsNumber, slot_kind_);
return slot_kind_;
// Returns entry size of the last slot returned by Next().
inline int entry_size() const;
FeedbackMetadata metadata() const {
return !metadata_handle_.is_null() ? *metadata_handle_ : metadata_;
// The reason for having a handle and a raw pointer to the meta data is
// to have a single iterator implementation for both "handlified" and raw
// pointer use cases.
Handle<FeedbackMetadata> metadata_handle_;
FeedbackMetadata metadata_;
FeedbackSlot cur_slot_;
FeedbackSlot next_slot_;
FeedbackSlotKind slot_kind_;
// A FeedbackNexus is the combination of a FeedbackVector and a slot.
class V8_EXPORT_PRIVATE FeedbackNexus final {
FeedbackNexus(Handle<FeedbackVector> vector, FeedbackSlot slot)
: vector_handle_(vector), slot_(slot) {
kind_ =
(vector.is_null()) ? FeedbackSlotKind::kInvalid : vector->GetKind(slot);
FeedbackNexus(FeedbackVector vector, FeedbackSlot slot)
: vector_(vector), slot_(slot) {
kind_ =
(vector.is_null()) ? FeedbackSlotKind::kInvalid : vector.GetKind(slot);
Handle<FeedbackVector> vector_handle() const {
return vector_handle_;
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());
InlineCacheState ic_state() const;
bool IsUninitialized() const { return ic_state() == UNINITIALIZED; }
bool IsMegamorphic() const { return ic_state() == MEGAMORPHIC; }
bool IsGeneric() const { return ic_state() == GENERIC; }
void Print(std::ostream& os); // NOLINT
// For map-based ICs (load, keyed-load, store, keyed-store).
Map GetFirstMap() const;
int ExtractMaps(MapHandles* maps) const;
int ExtractMapsAndHandlers(MapHandles* maps,
MaybeObjectHandles* handlers) const;
MaybeObjectHandle FindHandlerForMap(Handle<Map> map) const;
bool IsCleared() const {
InlineCacheState state = ic_state();
return !FLAG_use_ic || state == UNINITIALIZED || state == PREMONOMORPHIC;
// Clear() returns true if the state of the underlying vector was changed.
bool Clear();
void ConfigureUninitialized();
void ConfigurePremonomorphic(Handle<Map> receiver_map);
// ConfigureMegamorphic() returns true if the state of the underlying vector
// was changed. Extra feedback is cleared if the 0 parameter version is used.
bool ConfigureMegamorphic();
bool ConfigureMegamorphic(IcCheckType property_type);
inline MaybeObject GetFeedback() const;
inline MaybeObject GetFeedbackExtra() const;
inline Isolate* GetIsolate() const;
void ConfigureMonomorphic(Handle<Name> name, Handle<Map> receiver_map,
const MaybeObjectHandle& handler);
void ConfigurePolymorphic(Handle<Name> name, MapHandles const& maps,
MaybeObjectHandles* handlers);
BinaryOperationHint GetBinaryOperationFeedback() const;
CompareOperationHint GetCompareOperationFeedback() const;
ForInHint GetForInFeedback() const;
// For KeyedLoad ICs.
KeyedAccessLoadMode GetKeyedAccessLoadMode() const;
// For KeyedStore ICs.
KeyedAccessStoreMode GetKeyedAccessStoreMode() const;
// For KeyedLoad and KeyedStore ICs.
IcCheckType GetKeyType() const;
Name GetName() const;
// For Call ICs.
int GetCallCount();
void SetSpeculationMode(SpeculationMode mode);
SpeculationMode GetSpeculationMode();
// Compute the call frequency based on the call count and the invocation
// count (taken from the type feedback vector).
float ComputeCallFrequency();
using SpeculationModeField = BitField<SpeculationMode, 0, 1>;
using CallCountField = BitField<uint32_t, 1, 31>;
// For InstanceOf ICs.
MaybeHandle<JSObject> GetConstructorFeedback() const;
// For Global Load and Store ICs.
void ConfigurePropertyCellMode(Handle<PropertyCell> cell);
// Returns false if given combination of indices is not allowed.
bool ConfigureLexicalVarMode(int script_context_index, int context_slot_index,
bool immutable);
void ConfigureHandlerMode(const MaybeObjectHandle& handler);
// For CloneObject ICs
static constexpr int kCloneObjectPolymorphicEntrySize = 2;
void ConfigureCloneObject(Handle<Map> source_map, Handle<Map> result_map);
// Bit positions in a smi that encodes lexical environment variable access.
V(ContextIndexBits, unsigned, 12, _) \
V(SlotIndexBits, unsigned, 18, _) \
V(ImmutabilityBit, bool, 1, _)
// Make sure we don't overflow the smi.
// For TypeProfile feedback vector slots.
// ResetTypeProfile will always reset type profile information.
void ResetTypeProfile();
// Add a type to the list of types for source position <position>.
void Collect(Handle<String> type, int position);
JSObject GetTypeProfile() const;
std::vector<int> GetSourcePositions() const;
std::vector<Handle<String>> GetTypesForSourcePositions(uint32_t pos) const;
inline void SetFeedback(Object feedback,
WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
inline void SetFeedback(MaybeObject feedback,
WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
inline void SetFeedbackExtra(Object feedback_extra,
WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
inline void SetFeedbackExtra(MaybeObject feedback_extra,
WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
Handle<WeakFixedArray> EnsureArrayOfSize(int length);
Handle<WeakFixedArray> EnsureExtraArrayOfSize(int length);
// The reason for having a vector handle and a raw pointer is that we can and
// should use handles during IC miss, but not during GC when we clear ICs. If
// you have a handle to the vector that is better because more operations can
// be done, like allocation.
Handle<FeedbackVector> vector_handle_;
FeedbackVector vector_;
FeedbackSlot slot_;
FeedbackSlotKind kind_;
inline BinaryOperationHint BinaryOperationHintFromFeedback(int type_feedback);
inline CompareOperationHint CompareOperationHintFromFeedback(int type_feedback);
inline ForInHint ForInHintFromFeedback(int type_feedback);
} // namespace internal
} // namespace v8
#include "src/objects/object-macros-undef.h"