Commit 5a70a5ea authored by Peter Marshall's avatar Peter Marshall Committed by Commit Bot

[memory] Save space in the FeedbackMetadata on 64 bit platforms.

Previously we used a FixedArray for the FeedbackMetadata, packing bits
of information into Smi fields. On 64-bit platforms, we waste at least
half of the available memory by using the Smi representation.

Given that this is just raw data (no pointers), we can just use a new
type that uses the existing packing scheme to store the data in int32
format instead.

This CL changes FeedbackMetadata to a new subclass of HeapObject. This
is to reduce the API surface exposed, in comparison to extending/using
a more general purpose data structure like ByteArray, which is also just
raw data.

FeedbackMetadata only exposes general purpose methods for accessing
slots, but hides the implementation detail of packing bits into int32
fields.

This CL also introduces a sentinal EmptyFeedbackMetadata, because there
are ~750 empty FeedbackMetadata objects when running an empty program in
V8. These are probably for builtins.

Bug: v8:7500
Change-Id: Ic85563153abbd71a22854cee8519260c32b1e9ab
Reviewed-on: https://chromium-review.googlesource.com/945730
Commit-Queue: Peter Marshall <petermarshall@chromium.org>
Reviewed-by: 's avatarUlan Degenbaev <ulan@chromium.org>
Reviewed-by: 's avatarIgor Sheludko <ishell@chromium.org>
Cr-Commit-Position: refs/heads/master@{#51842}
parent 907c7fad
......@@ -254,8 +254,7 @@ void EnsureFeedbackMetadata(CompilationInfo* compilation_info,
// vectors for a different configuration, hence we also recreate a new vector
// when the function is not compiled (i.e. no code was serialized).
// TODO(mvstanton): reintroduce is_empty() predicate to feedback_metadata().
if (compilation_info->shared_info()->feedback_metadata()->length() == 0 ||
if (compilation_info->shared_info()->feedback_metadata()->is_empty() ||
!compilation_info->shared_info()->is_compiled()) {
Handle<FeedbackMetadata> feedback_metadata = FeedbackMetadata::New(
isolate, compilation_info->feedback_vector_spec());
......
......@@ -265,6 +265,7 @@ Type::bitset BitsetType::Lub(i::Map* map) {
case FIXED_ARRAY_TYPE:
case HASH_TABLE_TYPE:
case FIXED_DOUBLE_ARRAY_TYPE:
case FEEDBACK_METADATA_TYPE:
case BYTE_ARRAY_TYPE:
case BYTECODE_ARRAY_TYPE:
case BOILERPLATE_DESCRIPTION_TYPE:
......
......@@ -847,8 +847,9 @@ void LiveEdit::ReplaceFunctionCode(
new_shared_info->feedback_metadata());
shared_info->set_feedback_metadata(*new_feedback_metadata);
} else {
shared_info->set_feedback_metadata(
FeedbackMetadata::cast(isolate->heap()->empty_fixed_array()));
// Use an empty FeedbackMetadata.
Handle<FeedbackMetadata> feedback_metadata = FeedbackMetadata::New(isolate);
shared_info->set_feedback_metadata(*feedback_metadata);
}
int start_position = compile_info_wrapper.GetStartPosition();
......
......@@ -306,6 +306,13 @@ Handle<FixedArrayBase> Factory::NewFixedDoubleArrayWithHoles(
return array;
}
Handle<FeedbackMetadata> Factory::NewFeedbackMetadata(int slot_count) {
DCHECK_LE(0, slot_count);
CALL_HEAP_FUNCTION(isolate(),
isolate()->heap()->AllocateFeedbackMetadata(slot_count),
FeedbackMetadata);
}
Handle<FrameArray> Factory::NewFrameArray(int number_of_frames,
PretenureFlag pretenure) {
DCHECK_LE(0, number_of_frames);
......@@ -2542,51 +2549,53 @@ Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfo(
Handle<Map> map = shared_function_info_map();
Handle<SharedFunctionInfo> share = New<SharedFunctionInfo>(map, OLD_SPACE);
{
DisallowHeapAllocation no_allocation;
// Set pointer fields.
share->set_raw_name(has_shared_name
? *shared_name
: SharedFunctionInfo::kNoSharedNameSentinel);
Handle<Code> code;
if (!maybe_code.ToHandle(&code)) {
code = BUILTIN_CODE(isolate(), Illegal);
}
Object* function_data = (Builtins::IsBuiltinId(maybe_builtin_index) &&
Builtins::IsLazy(maybe_builtin_index))
? Smi::FromInt(maybe_builtin_index)
: Object::cast(*undefined_value());
share->set_function_data(function_data, SKIP_WRITE_BARRIER);
share->set_code(*code);
share->set_scope_info(ScopeInfo::Empty(isolate()));
share->set_outer_scope_info(*the_hole_value());
DCHECK(!Builtins::IsLazy(Builtins::kConstructedNonConstructable));
Handle<Code> construct_stub =
is_constructor ? isolate()->builtins()->JSConstructStubGeneric()
: BUILTIN_CODE(isolate(), ConstructedNonConstructable);
share->SetConstructStub(*construct_stub);
share->set_script(*undefined_value(), SKIP_WRITE_BARRIER);
share->set_debug_info(Smi::kZero, SKIP_WRITE_BARRIER);
share->set_function_identifier(*undefined_value(), SKIP_WRITE_BARRIER);
Handle<FeedbackMetadata> feedback_metadata = FeedbackMetadata::New(isolate());
share->set_feedback_metadata(*feedback_metadata, SKIP_WRITE_BARRIER);
share->set_function_literal_id(FunctionLiteral::kIdTypeInvalid);
// Set pointer fields.
share->set_raw_name(has_shared_name
? *shared_name
: SharedFunctionInfo::kNoSharedNameSentinel);
Handle<Code> code;
if (!maybe_code.ToHandle(&code)) {
code = BUILTIN_CODE(isolate(), Illegal);
}
Object* function_data = (Builtins::IsBuiltinId(maybe_builtin_index) &&
Builtins::IsLazy(maybe_builtin_index))
? Smi::FromInt(maybe_builtin_index)
: Object::cast(*undefined_value());
share->set_function_data(function_data, SKIP_WRITE_BARRIER);
share->set_code(*code);
share->set_scope_info(ScopeInfo::Empty(isolate()));
share->set_outer_scope_info(*the_hole_value());
DCHECK(!Builtins::IsLazy(Builtins::kConstructedNonConstructable));
Handle<Code> construct_stub =
is_constructor ? isolate()->builtins()->JSConstructStubGeneric()
: BUILTIN_CODE(isolate(), ConstructedNonConstructable);
share->SetConstructStub(*construct_stub);
share->set_script(*undefined_value(), SKIP_WRITE_BARRIER);
share->set_debug_info(Smi::kZero, SKIP_WRITE_BARRIER);
share->set_function_identifier(*undefined_value(), SKIP_WRITE_BARRIER);
share->set_feedback_metadata(isolate()->heap()->empty_feedback_metadata(),
SKIP_WRITE_BARRIER);
share->set_function_literal_id(FunctionLiteral::kIdTypeInvalid);
#if V8_SFI_HAS_UNIQUE_ID
share->set_unique_id(isolate()->GetNextUniqueSharedFunctionInfoId());
share->set_unique_id(isolate()->GetNextUniqueSharedFunctionInfoId());
#endif
// Set integer fields (smi or int, depending on the architecture).
share->set_length(0);
share->set_internal_formal_parameter_count(0);
share->set_expected_nof_properties(0);
share->set_start_position_and_type(0);
share->set_end_position(0);
share->set_function_token_position(0);
// All compiler hints default to false or 0.
share->set_compiler_hints(0);
share->set_kind(kind);
share->clear_padding();
// Set integer fields (smi or int, depending on the architecture).
share->set_length(0);
share->set_internal_formal_parameter_count(0);
share->set_expected_nof_properties(0);
share->set_start_position_and_type(0);
share->set_end_position(0);
share->set_function_token_position(0);
// All compiler hints default to false or 0.
share->set_compiler_hints(0);
share->set_kind(kind);
share->clear_padding();
}
// Link into the list.
Handle<Object> new_noscript_list =
FixedArrayOfWeakCells::Add(noscript_shared_function_infos(), share);
......
......@@ -139,6 +139,8 @@ class V8_EXPORT_PRIVATE Factory final {
int size,
PretenureFlag pretenure = NOT_TENURED);
Handle<FeedbackMetadata> NewFeedbackMetadata(int slot_count);
Handle<FrameArray> NewFrameArray(int number_of_frames,
PretenureFlag pretenure = NOT_TENURED);
......
......@@ -19,21 +19,36 @@
namespace v8 {
namespace internal {
INT32_ACCESSORS(FeedbackMetadata, slot_count, kSlotCountOffset)
int32_t FeedbackMetadata::synchronized_slot_count() const {
return static_cast<int32_t>(
base::Acquire_Load(reinterpret_cast<const base::AtomicWord*>(
FIELD_ADDR_CONST(this, kSlotCountOffset))));
}
// static
FeedbackMetadata* FeedbackMetadata::cast(Object* obj) {
DCHECK(obj->IsFeedbackMetadata());
return reinterpret_cast<FeedbackMetadata*>(obj);
}
bool FeedbackMetadata::is_empty() const {
if (length() == 0) return true;
return false;
int32_t FeedbackMetadata::get(int index) const {
DCHECK(index >= 0 && index < length());
int offset = kHeaderSize + index * kInt32Size;
return READ_INT32_FIELD(this, offset);
}
int FeedbackMetadata::slot_count() const {
if (length() == 0) return 0;
DCHECK_GT(length(), kReservedIndexCount);
return Smi::ToInt(get(kSlotsCountIndex));
void FeedbackMetadata::set(int index, int32_t value) {
DCHECK(index >= 0 && index < length());
int offset = kHeaderSize + index * kInt32Size;
WRITE_INT32_FIELD(this, offset, value);
}
bool FeedbackMetadata::is_empty() const { return slot_count() == 0; }
int FeedbackMetadata::length() const {
return FeedbackMetadata::length(slot_count());
}
// static
......
......@@ -53,16 +53,16 @@ std::ostream& operator<<(std::ostream& os, FeedbackSlotKind kind) {
}
FeedbackSlotKind FeedbackMetadata::GetKind(FeedbackSlot slot) const {
int index = VectorICComputer::index(kReservedIndexCount, slot.ToInt());
int data = Smi::ToInt(get(index));
int index = VectorICComputer::index(0, slot.ToInt());
int data = get(index);
return VectorICComputer::decode(data, slot.ToInt());
}
void FeedbackMetadata::SetKind(FeedbackSlot slot, FeedbackSlotKind kind) {
int index = VectorICComputer::index(kReservedIndexCount, slot.ToInt());
int data = Smi::ToInt(get(index));
int index = VectorICComputer::index(0, slot.ToInt());
int data = get(index);
int new_data = VectorICComputer::encode(data, slot.ToInt(), kind);
set(index, Smi::FromInt(new_data));
set(index, new_data);
}
// static
......@@ -71,10 +71,8 @@ Handle<FeedbackMetadata> FeedbackMetadata::New(Isolate* isolate,
Factory* factory = isolate->factory();
const int slot_count = spec == nullptr ? 0 : spec->slots();
const int slot_kinds_length = VectorICComputer::word_count(slot_count);
const int length = slot_kinds_length + kReservedIndexCount;
if (length == kReservedIndexCount) {
return Handle<FeedbackMetadata>::cast(factory->empty_fixed_array());
if (slot_count == 0) {
return factory->empty_feedback_metadata();
}
#ifdef DEBUG
for (int i = 0; i < slot_count;) {
......@@ -89,15 +87,10 @@ Handle<FeedbackMetadata> FeedbackMetadata::New(Isolate* isolate,
}
#endif
Handle<FixedArray> array = factory->NewFixedArray(length, TENURED);
array->set(kSlotsCountIndex, Smi::FromInt(slot_count));
// Fill the bit-vector part with zeros.
for (int i = 0; i < slot_kinds_length; i++) {
array->set(kReservedIndexCount + i, Smi::kZero);
}
Handle<FeedbackMetadata> metadata = Handle<FeedbackMetadata>::cast(array);
Handle<FeedbackMetadata> metadata = factory->NewFeedbackMetadata(slot_count);
// Initialize the slots. The raw data section has already been pre-zeroed in
// NewFeedbackMetadata.
for (int i = 0; i < slot_count; i++) {
DCHECK(spec);
FeedbackSlot slot(i);
......@@ -105,13 +98,6 @@ Handle<FeedbackMetadata> FeedbackMetadata::New(Isolate* isolate,
metadata->SetKind(slot, kind);
}
// It's important that the FeedbackMetadata have a COW map, since it's
// pointed to by both a SharedFunctionInfo and indirectly by closures through
// the FeedbackVector. The serializer uses the COW map type to decide
// this object belongs in the startup snapshot and not the partial
// snapshot(s).
metadata->set_map(isolate->heap()->fixed_cow_array_map());
return metadata;
}
......@@ -190,7 +176,7 @@ const char* FeedbackMetadata::Kind2String(FeedbackSlotKind kind) {
bool FeedbackMetadata::HasTypeProfileSlot() const {
FeedbackSlot slot =
FeedbackVector::ToSlot(FeedbackVectorSpec::kTypeProfileSlotIndex);
return slot.ToInt() < this->length() &&
return slot.ToInt() < slot_count() &&
GetKind(slot) == FeedbackSlotKind::kTypeProfile;
}
......
......@@ -412,19 +412,21 @@ class V8_EXPORT_PRIVATE FeedbackVectorSpec {
ZoneVector<unsigned char> slot_kinds_;
};
// The shape of the FeedbackMetadata is an array with:
// 0: slot_count
// 1: names table
// 2: parameters table
// 3..N: slot kinds packed into a bit vector
//
class FeedbackMetadata : public FixedArray {
// 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 {
public:
// Casting.
static inline FeedbackMetadata* cast(Object* obj);
static const int kSlotsCountIndex = 0;
static const int kReservedIndexCount = 1;
// The number of slots that this metadata contains. Stored as an int32.
DECL_INT32_ACCESSORS(slot_count)
// 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);
......@@ -433,9 +435,6 @@ class FeedbackMetadata : public FixedArray {
inline bool is_empty() const;
// Returns number of slots in the vector.
inline int slot_count() const;
// Returns slot kind for given slot.
FeedbackSlotKind GetKind(FeedbackSlot slot) const;
......@@ -449,21 +448,47 @@ class FeedbackMetadata : public FixedArray {
#endif // OBJECT_PRINT
DECL_PRINTER(FeedbackMetadata)
DECL_VERIFIER(FeedbackMetadata)
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 kHeaderSize = kSlotCountOffset + kInt32Size;
class BodyDescriptor;
// No weak fields.
typedef BodyDescriptor BodyDescriptorWeak;
private:
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);
typedef BitSetComputer<FeedbackSlotKind, kFeedbackSlotKindBits, kSmiValueSize,
uint32_t>
typedef BitSetComputer<FeedbackSlotKind, kFeedbackSlotKindBits,
kInt32Size * kBitsPerByte, uint32_t>
VectorICComputer;
DISALLOW_IMPLICIT_CONSTRUCTORS(FeedbackMetadata);
......
......@@ -4081,6 +4081,24 @@ AllocationResult Heap::AllocateRawFixedDoubleArray(int length,
return object;
}
AllocationResult Heap::AllocateFeedbackMetadata(int slot_count) {
HeapObject* result = nullptr;
int size = FeedbackMetadata::SizeFor(slot_count);
AllocationSpace space = SelectSpace(TENURED);
AllocationResult allocation = AllocateRaw(size, space);
if (!allocation.To(&result)) return allocation;
result->set_map_after_allocation(feedback_metadata_map(), SKIP_WRITE_BARRIER);
FeedbackMetadata::cast(result)->set_slot_count(slot_count);
// Initialize the data section to 0.
int data_size = size - FeedbackMetadata::kHeaderSize;
byte* data_start = result->address() + FeedbackMetadata::kHeaderSize;
memset(data_start, 0, data_size);
return result;
}
AllocationResult Heap::AllocateRawFeedbackVector(int length,
PretenureFlag pretenure) {
DCHECK_LE(0, length);
......
......@@ -107,6 +107,7 @@ using v8::MemoryPressureLevel;
V(Map, debug_evaluate_context_map, DebugEvaluateContextMap) \
V(Map, script_context_table_map, ScriptContextTableMap) \
/* Maps */ \
V(Map, feedback_metadata_map, FeedbackMetadataArrayMap) \
V(Map, array_list_map, ArrayListMap) \
V(Map, bigint_map, BigIntMap) \
V(Map, boilerplate_description_map, BoilerplateDescriptionMap) \
......@@ -211,6 +212,7 @@ using v8::MemoryPressureLevel;
EmptySlowElementDictionary) \
V(FixedArray, empty_ordered_hash_map, EmptyOrderedHashMap) \
V(FixedArray, empty_ordered_hash_set, EmptyOrderedHashSet) \
V(FeedbackMetadata, empty_feedback_metadata, EmptyFeedbackMetadata) \
V(PropertyCell, empty_property_cell, EmptyPropertyCell) \
V(WeakCell, empty_weak_cell, EmptyWeakCell) \
V(Cell, invalid_prototype_validity_cell, InvalidPrototypeValidityCell) \
......@@ -2306,6 +2308,9 @@ class Heap {
MUST_USE_RESULT AllocationResult AllocateUninitializedFixedDoubleArray(
int length, PretenureFlag pretenure = NOT_TENURED);
// Allocates a FeedbackMedata object and zeroes the data section.
MUST_USE_RESULT AllocationResult AllocateFeedbackMetadata(int slot_count);
// Allocate empty fixed array like objects.
MUST_USE_RESULT AllocationResult AllocateEmptyFixedArray();
MUST_USE_RESULT AllocationResult AllocateEmptyScopeInfo();
......
......@@ -682,11 +682,6 @@ void ObjectStatsCollectorImpl::RecordVirtualSharedFunctionInfoDetails(
RecordSimpleVirtualObjectStats(
nullptr, info, ObjectStats::UNCOMPILED_SHARED_FUNCTION_INFO_TYPE);
}
// SharedFunctonInfo::feedback_metadata() is a COW array.
FeedbackMetadata* fm = FeedbackMetadata::cast(info->feedback_metadata());
RecordVirtualObjectStats(info, fm, ObjectStats::FEEDBACK_METADATA_TYPE,
fm->Size(), ObjectStats::kNoOverAllocation,
kIgnoreCow);
}
void ObjectStatsCollectorImpl::RecordVirtualJSFunctionDetails(
......
......@@ -29,7 +29,6 @@
V(EMBEDDED_OBJECT_TYPE) \
V(ENUM_CACHE_TYPE) \
V(ENUM_INDICES_CACHE_TYPE) \
V(FEEDBACK_METADATA_TYPE) \
V(FEEDBACK_VECTOR_ENTRY_TYPE) \
V(FEEDBACK_VECTOR_HEADER_TYPE) \
V(FEEDBACK_VECTOR_SLOT_CALL_TYPE) \
......
......@@ -270,6 +270,7 @@ bool Heap::CreateInitialMaps() {
ALLOCATE_VARSIZE_MAP(FIXED_DOUBLE_ARRAY_TYPE, fixed_double_array)
fixed_double_array_map()->set_elements_kind(HOLEY_DOUBLE_ELEMENTS);
ALLOCATE_VARSIZE_MAP(FEEDBACK_METADATA_TYPE, feedback_metadata)
ALLOCATE_VARSIZE_MAP(BYTE_ARRAY_TYPE, byte_array)
ALLOCATE_VARSIZE_MAP(BYTECODE_ARRAY_TYPE, bytecode_array)
ALLOCATE_VARSIZE_MAP(FREE_SPACE_TYPE, free_space)
......@@ -623,6 +624,11 @@ void Heap::CreateInitialObjects() {
}
set_empty_ordered_hash_set(*empty_ordered_hash_set);
// Allocate the empty FeedbackMetadata.
Handle<FeedbackMetadata> empty_feedback_metadata =
factory->NewFeedbackMetadata(0);
set_empty_feedback_metadata(*empty_feedback_metadata);
// Allocate the empty script.
Handle<Script> script = factory->NewScript(factory->empty_string());
script->set_type(Script::TYPE_NATIVE);
......
......@@ -1740,9 +1740,14 @@ void AccessorAssembler::BranchIfStrictMode(Node* vector, Node* slot,
const int kItemsPerWord = FeedbackMetadata::VectorICComputer::kItemsPerWord;
Node* word_index = Int32Div(slot_int, Int32Constant(kItemsPerWord));
Node* word_offset = Int32Mod(slot_int, Int32Constant(kItemsPerWord));
Node* data = SmiToInt32(LoadFixedArrayElement(
metadata, ChangeInt32ToIntPtr(word_index),
FeedbackMetadata::kReservedIndexCount * kPointerSize, INTPTR_PARAMETERS));
int32_t first_item = FeedbackMetadata::kHeaderSize - kHeapObjectTag;
Node* offset =
ElementOffsetFromIndex(ChangeInt32ToIntPtr(word_index), UINT32_ELEMENTS,
INTPTR_PARAMETERS, first_item);
Node* data = Load(MachineType::Int32(), metadata, offset);
// See VectorICComputer::decode().
const int kBitsPerItem = FeedbackMetadata::kFeedbackSlotKindBits;
Node* shift = Int32Mul(word_offset, Int32Constant(kBitsPerItem));
......
......@@ -268,6 +268,20 @@ class FixedTypedArrayBase::BodyDescriptor final : public BodyDescriptorBase {
}
};
class FeedbackMetadata::BodyDescriptor final : public BodyDescriptorBase {
public:
static bool IsValidSlot(HeapObject* obj, int offset) { return false; }
template <typename ObjectVisitor>
static inline void IterateBody(HeapObject* obj, int object_size,
ObjectVisitor* v) {}
static inline int SizeOf(Map* map, HeapObject* obj) {
return FeedbackMetadata::SizeFor(
FeedbackMetadata::cast(obj)->synchronized_slot_count());
}
};
class FeedbackVector::BodyDescriptor final : public BodyDescriptorBase {
public:
static bool IsValidSlot(HeapObject* obj, int offset) {
......@@ -460,6 +474,8 @@ ReturnType BodyDescriptorApply(InstanceType type, T1 p1, T2 p2, T3 p3) {
return Op::template apply<FixedArray::BodyDescriptor>(p1, p2, p3);
case FIXED_DOUBLE_ARRAY_TYPE:
return ReturnType();
case FEEDBACK_METADATA_TYPE:
return Op::template apply<FeedbackMetadata::BodyDescriptor>(p1, p2, p3);
case PROPERTY_ARRAY_TYPE:
return Op::template apply<PropertyArray::BodyDescriptor>(p1, p2, p3);
case DESCRIPTOR_ARRAY_TYPE:
......
......@@ -129,6 +129,9 @@ void HeapObject::HeapObjectVerify() {
case FIXED_DOUBLE_ARRAY_TYPE:
FixedDoubleArray::cast(this)->FixedDoubleArrayVerify();
break;
case FEEDBACK_METADATA_TYPE:
FeedbackMetadata::cast(this)->FeedbackMetadataVerify();
break;
case BYTE_ARRAY_TYPE:
ByteArray::cast(this)->ByteArrayVerify();
break;
......@@ -553,6 +556,20 @@ void FixedDoubleArray::FixedDoubleArrayVerify() {
}
}
void FeedbackMetadata::FeedbackMetadataVerify() {
if (slot_count() == 0) {
CHECK_EQ(GetHeap()->empty_feedback_metadata(), this);
} else {
FeedbackMetadataIterator iter(this);
while (iter.HasNext()) {
iter.Next();
FeedbackSlotKind kind = iter.kind();
CHECK_NE(FeedbackSlotKind::kInvalid, kind);
CHECK_GT(FeedbackSlotKind::kKindsNumber, kind);
}
}
}
void DescriptorArray::DescriptorArrayVerify() {
FixedArrayVerify();
if (number_of_descriptors_storage() == 0) {
......
......@@ -88,6 +88,7 @@ TYPE_CHECKER(ConstantElementsPair, TUPLE2_TYPE)
TYPE_CHECKER(CoverageInfo, FIXED_ARRAY_TYPE)
TYPE_CHECKER(DescriptorArray, DESCRIPTOR_ARRAY_TYPE)
TYPE_CHECKER(FeedbackCell, FEEDBACK_CELL_TYPE)
TYPE_CHECKER(FeedbackMetadata, FEEDBACK_METADATA_TYPE)
TYPE_CHECKER(FeedbackVector, FEEDBACK_VECTOR_TYPE)
TYPE_CHECKER(Foreign, FOREIGN_TYPE)
TYPE_CHECKER(FreeSpace, FREE_SPACE_TYPE)
......@@ -338,8 +339,6 @@ bool HeapObject::IsRegExpMatchInfo() const { return IsFixedArrayExact(); }
bool Object::IsLayoutDescriptor() const { return IsSmi() || IsByteArray(); }
bool HeapObject::IsFeedbackMetadata() const { return IsFixedArrayExact(); }
bool HeapObject::IsDeoptimizationData() const {
// Must be a fixed array.
if (!IsFixedArrayExact()) return false;
......@@ -2230,6 +2229,11 @@ int HeapObject::SizeFromMap(Map* map) const {
return FixedDoubleArray::SizeFor(
reinterpret_cast<const FixedDoubleArray*>(this)->synchronized_length());
}
if (instance_type == FEEDBACK_METADATA_TYPE) {
return FeedbackMetadata::SizeFor(
reinterpret_cast<const FeedbackMetadata*>(this)
->synchronized_slot_count());
}
if (instance_type >= FIRST_FIXED_TYPED_ARRAY_TYPE &&
instance_type <= LAST_FIXED_TYPED_ARRAY_TYPE) {
return reinterpret_cast<const FixedTypedArrayBase*>(this)->TypedArraySize(
......
......@@ -255,7 +255,9 @@ void HeapObject::HeapObjectPrint(std::ostream& os) { // NOLINT
case SCOPE_INFO_TYPE:
ScopeInfo::cast(this)->ScopeInfoPrint(os);
break;
case FEEDBACK_METADATA_TYPE:
FeedbackMetadata::cast(this)->FeedbackMetadataPrint(os);
break;
default:
os << "UNKNOWN TYPE " << map()->instance_type();
UNREACHABLE();
......@@ -756,13 +758,8 @@ void FeedbackMetadata::Print() {
os << std::flush;
}
void FeedbackMetadata::FeedbackMetadataPrint(std::ostream& os) { // NOLINT
void FeedbackMetadata::FeedbackMetadataPrint(std::ostream& os) {
HeapObject::PrintHeader(os, "FeedbackMetadata");
os << "\n - length: " << length();
if (length() == 0) {
os << " (empty)\n";
return;
}
os << "\n - slot_count: " << slot_count();
FeedbackMetadataIterator iter(this);
......
......@@ -3088,6 +3088,7 @@ VisitorId Map::GetVisitorId(Map* map) {
case FOREIGN_TYPE:
case HEAP_NUMBER_TYPE:
case MUTABLE_HEAP_NUMBER_TYPE:
case FEEDBACK_METADATA_TYPE:
return kVisitDataObject;
case BIGINT_TYPE:
......@@ -12781,6 +12782,7 @@ bool CanSubclassHaveInobjectProperties(InstanceType instance_type) {
case FILLER_TYPE:
case FIXED_ARRAY_TYPE:
case FIXED_DOUBLE_ARRAY_TYPE:
case FEEDBACK_METADATA_TYPE:
case FOREIGN_TYPE:
case FREE_SPACE_TYPE:
case HASH_TABLE_TYPE:
......
......@@ -360,6 +360,7 @@ const int kStubMinorKeyBits = kSmiValueSize - kStubMajorKeyBits - 1;
V(FIXED_BIGUINT64_ARRAY_TYPE) \
\
V(FIXED_DOUBLE_ARRAY_TYPE) \
V(FEEDBACK_METADATA_TYPE) \
V(FILLER_TYPE) \
\
V(ACCESS_CHECK_INFO_TYPE) \
......@@ -710,6 +711,7 @@ enum InstanceType : uint16_t {
FIXED_BIGINT64_ARRAY_TYPE,
FIXED_BIGUINT64_ARRAY_TYPE, // LAST_FIXED_TYPED_ARRAY_TYPE
FIXED_DOUBLE_ARRAY_TYPE,
FEEDBACK_METADATA_TYPE,
FILLER_TYPE, // LAST_DATA_TYPE
// Structs.
......
......@@ -77,7 +77,7 @@ ParseInfo::ParseInfo(Handle<SharedFunctionInfo> shared)
// has the appropriate slots.
set_collect_type_profile(
isolate->is_collecting_type_profile() &&
(shared->feedback_metadata()->length() == 0
(shared->feedback_metadata()->is_empty()
? script->IsUserJavaScript()
: shared->feedback_metadata()->HasTypeProfileSlot()));
if (block_coverage_enabled() && script->IsUserJavaScript()) {
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment