#ifndef V8_HEAP_OBJECT_STATS_H_
#define V8_HEAP_OBJECT_STATS_H_
#include <vector>
#include "src/objects/code.h"
#include "src/objects/objects.h"
#define VIRTUAL_INSTANCE_TYPE_LIST(V) \
CODE_KIND_LIST(V) \
V(ARRAY_BOILERPLATE_DESCRIPTION_ELEMENTS_TYPE) \
V(ARRAY_DICTIONARY_ELEMENTS_TYPE) \
V(ARRAY_ELEMENTS_TYPE) \
V(BOILERPLATE_ELEMENTS_TYPE) \
V(BOILERPLATE_PROPERTY_ARRAY_TYPE) \
V(BOILERPLATE_PROPERTY_DICTIONARY_TYPE) \
V(BYTECODE_ARRAY_CONSTANT_POOL_TYPE) \
V(BYTECODE_ARRAY_HANDLER_TABLE_TYPE) \
V(COW_ARRAY_TYPE) \
V(DEOPTIMIZATION_DATA_TYPE) \
V(DEPENDENT_CODE_TYPE) \
V(DEPRECATED_DESCRIPTOR_ARRAY_TYPE) \
V(EMBEDDED_OBJECT_TYPE) \
V(ENUM_KEYS_CACHE_TYPE) \
V(ENUM_INDICES_CACHE_TYPE) \
V(FEEDBACK_VECTOR_ENTRY_TYPE) \
V(FEEDBACK_VECTOR_HEADER_TYPE) \
V(FEEDBACK_VECTOR_SLOT_CALL_TYPE) \
V(FEEDBACK_VECTOR_SLOT_CALL_UNUSED_TYPE) \
V(FEEDBACK_VECTOR_SLOT_ENUM_TYPE) \
V(FEEDBACK_VECTOR_SLOT_LOAD_TYPE) \
V(FEEDBACK_VECTOR_SLOT_LOAD_UNUSED_TYPE) \
V(FEEDBACK_VECTOR_SLOT_OTHER_TYPE) \
V(FEEDBACK_VECTOR_SLOT_STORE_TYPE) \
V(FEEDBACK_VECTOR_SLOT_STORE_UNUSED_TYPE) \
V(FUNCTION_TEMPLATE_INFO_ENTRIES_TYPE) \
V(GLOBAL_ELEMENTS_TYPE) \
V(GLOBAL_PROPERTIES_TYPE) \
V(JS_ARRAY_BOILERPLATE_TYPE) \
V(JS_COLLECTION_TABLE_TYPE) \
V(JS_OBJECT_BOILERPLATE_TYPE) \
V(JS_UNCOMPILED_FUNCTION_TYPE) \
V(MAP_ABANDONED_PROTOTYPE_TYPE) \
V(MAP_DEPRECATED_TYPE) \
V(MAP_DICTIONARY_TYPE) \
V(MAP_PROTOTYPE_DICTIONARY_TYPE) \
V(MAP_PROTOTYPE_TYPE) \
V(MAP_STABLE_TYPE) \
V(NUMBER_STRING_CACHE_TYPE) \
V(OBJECT_DICTIONARY_ELEMENTS_TYPE) \
V(OBJECT_ELEMENTS_TYPE) \
V(OBJECT_PROPERTY_ARRAY_TYPE) \
V(OBJECT_PROPERTY_DICTIONARY_TYPE) \
V(OBJECT_TO_CODE_TYPE) \
V(OPTIMIZED_CODE_LITERALS_TYPE) \
V(OTHER_CONTEXT_TYPE) \
V(PROTOTYPE_DESCRIPTOR_ARRAY_TYPE) \
V(PROTOTYPE_PROPERTY_ARRAY_TYPE) \
V(PROTOTYPE_PROPERTY_DICTIONARY_TYPE) \
V(PROTOTYPE_USERS_TYPE) \
V(REGEXP_MULTIPLE_CACHE_TYPE) \
V(RELOC_INFO_TYPE) \
V(RETAINED_MAPS_TYPE) \
V(SCRIPT_LIST_TYPE) \
V(SCRIPT_INFOS_TYPE) \
V(SCRIPT_SOURCE_EXTERNAL_ONE_BYTE_TYPE) \
V(SCRIPT_SOURCE_EXTERNAL_TWO_BYTE_TYPE) \
V(SCRIPT_SOURCE_NON_EXTERNAL_ONE_BYTE_TYPE) \
V(SCRIPT_SOURCE_NON_EXTERNAL_TWO_BYTE_TYPE) \
V(SERIALIZED_OBJECTS_TYPE) \
V(STRING_SPLIT_CACHE_TYPE) \
V(STRING_EXTERNAL_RESOURCE_ONE_BYTE_TYPE) \
V(STRING_EXTERNAL_RESOURCE_TWO_BYTE_TYPE) \
V(SOURCE_POSITION_TABLE_TYPE) \
V(UNCOMPILED_SHARED_FUNCTION_INFO_TYPE) \
V(WASTED_DESCRIPTOR_ARRAY_DETAILS_TYPE) \
V(WASTED_DESCRIPTOR_ARRAY_VALUES_TYPE) \
V(WEAK_NEW_SPACE_OBJECT_TO_CODE_TYPE)
namespace v8 {
namespace internal {
class Heap;
class Isolate;
class ObjectStats {
public:
static const size_t kNoOverAllocation = 0;
struct ObjectData {
uint32_t address;
size_t size;
int type;
};
explicit ObjectStats(Heap* heap) : heap_(heap) { ClearObjectStats(true); }
enum class VirtualInstanceType {
#define DEFINE_VIRTUAL_INSTANCE_TYPE(type) type,
VIRTUAL_INSTANCE_TYPE_LIST(DEFINE_VIRTUAL_INSTANCE_TYPE)
#undef DEFINE_FIXED_ARRAY_SUB_INSTANCE_TYPE
LAST_VIRTUAL_TYPE = WEAK_NEW_SPACE_OBJECT_TO_CODE_TYPE,
};
static constexpr int FIRST_VIRTUAL_TYPE = LAST_TYPE + 1;
static constexpr int OBJECT_STATS_COUNT =
FIRST_VIRTUAL_TYPE +
static_cast<int>(VirtualInstanceType::LAST_VIRTUAL_TYPE) + 1;
void ClearObjectStats(bool clear_last_time_stats = false);
void PrintJSON(const char* key);
void Dump(std::stringstream& stream);
void CheckpointObjectStats();
void RecordObject(Tagged<HeapObject> obj, int type, size_t size);
void RecordObjectStats(Tagged<HeapObject> obj, InstanceType type, size_t size,
size_t over_allocated = kNoOverAllocation);
void RecordVirtualObjectStats(Tagged<HeapObject> obj,
VirtualInstanceType type, size_t size,
size_t over_allocated);
size_t object_count_last_gc(size_t index) {
return object_counts_last_time_[index];
}
size_t object_size_last_gc(size_t index) {
return object_sizes_last_time_[index];
}
Isolate* isolate();
Heap* heap() { return heap_; }
private:
static const int kFirstBucketShift = 5;
static const int kLastBucketShift = 20;
static const int kFirstBucket = 1 << kFirstBucketShift;
static const int kLastBucket = 1 << kLastBucketShift;
static const int kNumberOfBuckets = kLastBucketShift - kFirstBucketShift + 1;
static const int kLastValueBucketIndex = kLastBucketShift - kFirstBucketShift;
void PrintKeyAndId(const char* key, GCEpoch gc_count);
V8_NOINLINE void PrintInstanceTypeJSON(const char* key, GCEpoch gc_count,
const char* name, int index);
V8_NOINLINE void DumpInstanceTypeData(std::stringstream& stream,
const char* name, int index);
int HistogramIndexFromSize(size_t size);
Heap* heap_;
size_t object_counts_[OBJECT_STATS_COUNT];
size_t object_counts_last_time_[OBJECT_STATS_COUNT];
size_t object_sizes_[OBJECT_STATS_COUNT];
size_t object_sizes_last_time_[OBJECT_STATS_COUNT];
size_t over_allocated_[OBJECT_STATS_COUNT];
size_t size_histogram_[OBJECT_STATS_COUNT][kNumberOfBuckets];
size_t over_allocated_histogram_[OBJECT_STATS_COUNT][kNumberOfBuckets];
size_t tagged_fields_count_;
size_t embedder_fields_count_;
size_t inobject_smi_fields_count_;
size_t boxed_double_fields_count_;
size_t string_data_count_;
size_t raw_fields_count_;
#ifdef V8_COMPRESS_POINTERS
std::vector<ObjectData> objects_main_;
std::vector<ObjectData> objects_trusted_;
std::vector<ObjectData> objects_code_;
#endif
friend class ObjectStatsCollectorImpl;
};
class ObjectStatsCollector {
public:
ObjectStatsCollector(Heap* heap, ObjectStats* live, ObjectStats* dead)
: heap_(heap), live_(live), dead_(dead) {
DCHECK_NOT_NULL(heap_);
DCHECK_NOT_NULL(live_);
DCHECK_NOT_NULL(dead_);
}
void Collect();
private:
Heap* const heap_;
ObjectStats* const live_;
ObjectStats* const dead_;
};
}
}
#endif