#include "src/profiler/heap-snapshot-generator.h"
#include <optional>
#include <utility>
#include "src/api/api-inl.h"
#include "src/base/vector.h"
#include "src/codegen/assembler-inl.h"
#include "src/common/assert-scope.h"
#include "src/common/globals.h"
#include "src/debug/debug.h"
#include "src/handles/global-handles.h"
#include "src/heap/combined-heap.h"
#include "src/heap/heap.h"
#include "src/heap/safepoint.h"
#include "src/numbers/conversions.h"
#include "src/objects/allocation-site-inl.h"
#include "src/objects/api-callbacks.h"
#include "src/objects/cell-inl.h"
#include "src/objects/feedback-cell-inl.h"
#include "src/objects/hash-table-inl.h"
#include "src/objects/js-array-buffer-inl.h"
#include "src/objects/js-array-inl.h"
#include "src/objects/js-collection-inl.h"
#include "src/objects/js-generator-inl.h"
#include "src/objects/js-objects.h"
#include "src/objects/js-promise-inl.h"
#include "src/objects/js-regexp-inl.h"
#include "src/objects/js-weak-refs-inl.h"
#include "src/objects/literal-objects-inl.h"
#include "src/objects/objects-inl.h"
#include "src/objects/prototype.h"
#include "src/objects/slots-inl.h"
#include "src/objects/struct-inl.h"
#include "src/objects/transitions-inl.h"
#include "src/objects/visitors.h"
#include "src/profiler/allocation-tracker.h"
#include "src/profiler/heap-profiler.h"
#include "src/profiler/heap-snapshot-generator-inl.h"
#include "src/profiler/output-stream-writer.h"
#if V8_ENABLE_WEBASSEMBLY
#include "src/wasm/names-provider.h"
#include "src/wasm/string-builder.h"
#include "src/wasm/wasm-objects.h"
#endif
namespace v8::internal {
#ifdef V8_ENABLE_HEAP_SNAPSHOT_VERIFY
class HeapEntryVerifier { … };
#endif
HeapGraphEdge::HeapGraphEdge(Type type, const char* name, HeapEntry* from,
HeapEntry* to)
: … { … }
HeapGraphEdge::HeapGraphEdge(Type type, int index, HeapEntry* from,
HeapEntry* to)
: … { … }
HeapEntry::HeapEntry(HeapSnapshot* snapshot, int index, Type type,
const char* name, SnapshotObjectId id, size_t self_size,
unsigned trace_node_id)
: … { … }
void HeapEntry::VerifyReference(HeapGraphEdge::Type type, HeapEntry* entry,
HeapSnapshotGenerator* generator,
ReferenceVerification verification) { … }
void HeapEntry::SetNamedReference(HeapGraphEdge::Type type, const char* name,
HeapEntry* entry,
HeapSnapshotGenerator* generator,
ReferenceVerification verification) { … }
void HeapEntry::SetIndexedReference(HeapGraphEdge::Type type, int index,
HeapEntry* entry,
HeapSnapshotGenerator* generator,
ReferenceVerification verification) { … }
void HeapEntry::SetNamedAutoIndexReference(HeapGraphEdge::Type type,
const char* description,
HeapEntry* child,
StringsStorage* names,
HeapSnapshotGenerator* generator,
ReferenceVerification verification) { … }
void HeapEntry::Print(const char* prefix, const char* edge_name, int max_depth,
int indent) const { … }
const char* HeapEntry::TypeAsString() const { … }
HeapSnapshot::HeapSnapshot(HeapProfiler* profiler,
v8::HeapProfiler::HeapSnapshotMode snapshot_mode,
v8::HeapProfiler::NumericsMode numerics_mode)
: … { … }
void HeapSnapshot::Delete() { … }
void HeapSnapshot::RememberLastJSObjectId() { … }
void HeapSnapshot::AddSyntheticRootEntries() { … }
void HeapSnapshot::AddRootEntry() { … }
void HeapSnapshot::AddGcRootsEntry() { … }
void HeapSnapshot::AddGcSubrootEntry(Root root, SnapshotObjectId id) { … }
void HeapSnapshot::AddLocation(HeapEntry* entry, int scriptId, int line,
int col) { … }
HeapEntry* HeapSnapshot::AddEntry(HeapEntry::Type type, const char* name,
SnapshotObjectId id, size_t size,
unsigned trace_node_id) { … }
void HeapSnapshot::AddScriptLineEnds(int script_id,
String::LineEndsVector&& line_ends) { … }
String::LineEndsVector& HeapSnapshot::GetScriptLineEnds(int script_id) { … }
void HeapSnapshot::FillChildren() { … }
HeapEntry* HeapSnapshot::GetEntryById(SnapshotObjectId id) { … }
void HeapSnapshot::Print(int max_depth) { … }
const SnapshotObjectId HeapObjectsMap::kInternalRootObjectId = …;
const SnapshotObjectId HeapObjectsMap::kGcRootsObjectId = …;
const SnapshotObjectId HeapObjectsMap::kGcRootsFirstSubrootId = …;
const SnapshotObjectId HeapObjectsMap::kFirstAvailableObjectId = …;
const SnapshotObjectId HeapObjectsMap::kFirstAvailableNativeId = …;
HeapObjectsMap::HeapObjectsMap(Heap* heap)
: … { … }
bool HeapObjectsMap::MoveObject(Address from, Address to, int object_size) { … }
void HeapObjectsMap::UpdateObjectSize(Address addr, int size) { … }
SnapshotObjectId HeapObjectsMap::FindEntry(Address addr) { … }
SnapshotObjectId HeapObjectsMap::FindOrAddEntry(
Address addr, unsigned int size, MarkEntryAccessed accessed,
IsNativeObject is_native_object) { … }
SnapshotObjectId HeapObjectsMap::FindMergedNativeEntry(NativeObject addr) { … }
void HeapObjectsMap::AddMergedNativeEntry(NativeObject addr,
Address canonical_addr) { … }
void HeapObjectsMap::StopHeapObjectsTracking() { … }
void HeapObjectsMap::UpdateHeapObjectsMap() { … }
SnapshotObjectId HeapObjectsMap::PushHeapObjectsStats(OutputStream* stream,
int64_t* timestamp_us) { … }
void HeapObjectsMap::RemoveDeadEntries() { … }
V8HeapExplorer::V8HeapExplorer(HeapSnapshot* snapshot,
SnapshottingProgressReportingInterface* progress,
v8::HeapProfiler::ObjectNameResolver* resolver)
: … { … }
HeapEntry* V8HeapExplorer::AllocateEntry(HeapThing ptr) { … }
HeapEntry* V8HeapExplorer::AllocateEntry(Tagged<Smi> smi) { … }
Tagged<JSFunction> V8HeapExplorer::GetLocationFunction(
Tagged<HeapObject> object) { … }
void V8HeapExplorer::ExtractLocation(HeapEntry* entry,
Tagged<HeapObject> object) { … }
void V8HeapExplorer::ExtractLocationForJSFunction(HeapEntry* entry,
Tagged<JSFunction> func) { … }
namespace {
template <const char kTagNameCStr[]>
struct ManagedName { … };
constexpr const char kTagNameForTesting[] = …;
static_assert(std::string_view{
ManagedName<kTagNameForTesting>::str_arr.data()} ==
std::string_view{"system / Managed<Foo>"});
}
HeapEntry* V8HeapExplorer::AddEntry(Tagged<HeapObject> object) { … }
HeapEntry* V8HeapExplorer::AddEntry(Tagged<HeapObject> object,
HeapEntry::Type type, const char* name) { … }
HeapEntry* V8HeapExplorer::AddEntry(Address address, HeapEntry::Type type,
const char* name, size_t size) { … }
const char* V8HeapExplorer::GetSystemEntryName(Tagged<HeapObject> object) { … }
HeapEntry::Type V8HeapExplorer::GetSystemEntryType(Tagged<HeapObject> object) { … }
void V8HeapExplorer::PopulateLineEnds() { … }
uint32_t V8HeapExplorer::EstimateObjectsCount() { … }
#ifdef V8_TARGET_BIG_ENDIAN
namespace {
int AdjustEmbedderFieldIndex(Tagged<HeapObject> heap_obj, int field_index) {
Tagged<Map> map = heap_obj->map();
if (JSObject::MayHaveEmbedderFields(map)) {
int emb_start_index = (JSObject::GetEmbedderFieldsStartOffset(map) +
EmbedderDataSlot::kTaggedPayloadOffset) /
kTaggedSize;
int emb_field_count = JSObject::GetEmbedderFieldCount(map);
int emb_end_index = emb_start_index + emb_field_count;
if (base::IsInRange(field_index, emb_start_index, emb_end_index)) {
return -EmbedderDataSlot::kTaggedPayloadOffset / kTaggedSize;
}
}
return 0;
}
}
#endif
class IndexedReferencesExtractor : public ObjectVisitorWithCageBases { … };
void V8HeapExplorer::ExtractReferences(HeapEntry* entry,
Tagged<HeapObject> obj) { … }
void V8HeapExplorer::ExtractJSGlobalProxyReferences(
HeapEntry* entry, Tagged<JSGlobalProxy> proxy) { … }
void V8HeapExplorer::ExtractJSObjectReferences(HeapEntry* entry,
Tagged<JSObject> js_obj) { … }
void V8HeapExplorer::ExtractStringReferences(HeapEntry* entry,
Tagged<String> string) { … }
void V8HeapExplorer::ExtractSymbolReferences(HeapEntry* entry,
Tagged<Symbol> symbol) { … }
void V8HeapExplorer::ExtractJSCollectionReferences(
HeapEntry* entry, Tagged<JSCollection> collection) { … }
void V8HeapExplorer::ExtractJSWeakCollectionReferences(
HeapEntry* entry, Tagged<JSWeakCollection> obj) { … }
void V8HeapExplorer::ExtractEphemeronHashTableReferences(
HeapEntry* entry, Tagged<EphemeronHashTable> table) { … }
static const struct { … } native_context_names[] = …;
void V8HeapExplorer::ExtractContextReferences(HeapEntry* entry,
Tagged<Context> context) { … }
void V8HeapExplorer::ExtractMapReferences(HeapEntry* entry, Tagged<Map> map) { … }
void V8HeapExplorer::ExtractSharedFunctionInfoReferences(
HeapEntry* entry, Tagged<SharedFunctionInfo> shared) { … }
void V8HeapExplorer::ExtractScriptReferences(HeapEntry* entry,
Tagged<Script> script) { … }
void V8HeapExplorer::ExtractAccessorInfoReferences(
HeapEntry* entry, Tagged<AccessorInfo> accessor_info) { … }
void V8HeapExplorer::ExtractAccessorPairReferences(
HeapEntry* entry, Tagged<AccessorPair> accessors) { … }
void V8HeapExplorer::ExtractJSWeakRefReferences(HeapEntry* entry,
Tagged<JSWeakRef> js_weak_ref) { … }
void V8HeapExplorer::ExtractWeakCellReferences(HeapEntry* entry,
Tagged<WeakCell> weak_cell) { … }
void V8HeapExplorer::TagBuiltinCodeObject(Tagged<Code> code, const char* name) { … }
void V8HeapExplorer::ExtractCodeReferences(HeapEntry* entry,
Tagged<Code> code) { … }
void V8HeapExplorer::ExtractInstructionStreamReferences(
HeapEntry* entry, Tagged<InstructionStream> istream) { … }
void V8HeapExplorer::ExtractCellReferences(HeapEntry* entry,
Tagged<Cell> cell) { … }
void V8HeapExplorer::ExtractFeedbackCellReferences(
HeapEntry* entry, Tagged<FeedbackCell> feedback_cell) { … }
void V8HeapExplorer::ExtractPropertyCellReferences(HeapEntry* entry,
Tagged<PropertyCell> cell) { … }
void V8HeapExplorer::ExtractPrototypeInfoReferences(
HeapEntry* entry, Tagged<PrototypeInfo> info) { … }
void V8HeapExplorer::ExtractAllocationSiteReferences(
HeapEntry* entry, Tagged<AllocationSite> site) { … }
void V8HeapExplorer::ExtractArrayBoilerplateDescriptionReferences(
HeapEntry* entry, Tagged<ArrayBoilerplateDescription> value) { … }
void V8HeapExplorer::ExtractRegExpBoilerplateDescriptionReferences(
HeapEntry* entry, Tagged<RegExpBoilerplateDescription> value) { … }
class JSArrayBufferDataEntryAllocator : public HeapEntriesAllocator { … };
void V8HeapExplorer::ExtractJSArrayBufferReferences(
HeapEntry* entry, Tagged<JSArrayBuffer> buffer) { … }
void V8HeapExplorer::ExtractJSPromiseReferences(HeapEntry* entry,
Tagged<JSPromise> promise) { … }
void V8HeapExplorer::ExtractJSGeneratorObjectReferences(
HeapEntry* entry, Tagged<JSGeneratorObject> generator) { … }
void V8HeapExplorer::ExtractFixedArrayReferences(HeapEntry* entry,
Tagged<FixedArray> array) { … }
void V8HeapExplorer::ExtractNumberReference(HeapEntry* entry,
Tagged<Object> number) { … }
void V8HeapExplorer::ExtractBytecodeArrayReferences(
HeapEntry* entry, Tagged<BytecodeArray> bytecode) { … }
void V8HeapExplorer::ExtractScopeInfoReferences(HeapEntry* entry,
Tagged<ScopeInfo> info) { … }
void V8HeapExplorer::ExtractFeedbackVectorReferences(
HeapEntry* entry, Tagged<FeedbackVector> feedback_vector) { … }
void V8HeapExplorer::ExtractDescriptorArrayReferences(
HeapEntry* entry, Tagged<DescriptorArray> array) { … }
void V8HeapExplorer::ExtractEnumCacheReferences(HeapEntry* entry,
Tagged<EnumCache> cache) { … }
void V8HeapExplorer::ExtractTransitionArrayReferences(
HeapEntry* entry, Tagged<TransitionArray> transitions) { … }
template <typename T>
void V8HeapExplorer::ExtractWeakArrayReferences(int header_size,
HeapEntry* entry,
Tagged<T> array) { … }
void V8HeapExplorer::ExtractPropertyReferences(Tagged<JSObject> js_obj,
HeapEntry* entry) { … }
void V8HeapExplorer::ExtractAccessorPairProperty(HeapEntry* entry,
Tagged<Name> key,
Tagged<Object> callback_obj,
int field_offset) { … }
void V8HeapExplorer::ExtractElementReferences(Tagged<JSObject> js_obj,
HeapEntry* entry) { … }
void V8HeapExplorer::ExtractInternalReferences(Tagged<JSObject> js_obj,
HeapEntry* entry) { … }
#if V8_ENABLE_WEBASSEMBLY
void V8HeapExplorer::ExtractWasmStructReferences(Tagged<WasmStruct> obj,
HeapEntry* entry) { … }
void V8HeapExplorer::ExtractWasmArrayReferences(Tagged<WasmArray> obj,
HeapEntry* entry) { … }
void V8HeapExplorer::ExtractWasmTrustedInstanceDataReferences(
Tagged<WasmTrustedInstanceData> trusted_data, HeapEntry* entry) { … }
#define ASSERT_FIRST_FIELD …
#define ASSERT_CONSECUTIVE_FIELDS …
#define ASSERT_LAST_FIELD …
void V8HeapExplorer::ExtractWasmInstanceObjectReferences(
Tagged<WasmInstanceObject> instance_object, HeapEntry* entry) { … }
void V8HeapExplorer::ExtractWasmModuleObjectReferences(
Tagged<WasmModuleObject> module_object, HeapEntry* entry) { … }
#undef ASSERT_FIRST_FIELD
#undef ASSERT_CONSECUTIVE_FIELDS
#undef ASSERT_LAST_FIELD
#endif
Tagged<JSFunction> V8HeapExplorer::GetConstructor(Isolate* isolate,
Tagged<JSReceiver> receiver) { … }
Tagged<String> V8HeapExplorer::GetConstructorName(Isolate* isolate,
Tagged<JSObject> object) { … }
HeapEntry* V8HeapExplorer::GetEntry(Tagged<Object> obj) { … }
class RootsReferencesExtractor : public RootVisitor { … };
bool V8HeapExplorer::IterateAndExtractReferences(
HeapSnapshotGenerator* generator) { … }
bool V8HeapExplorer::IsEssentialObject(Tagged<Object> object) { … }
bool V8HeapExplorer::IsEssentialHiddenReference(Tagged<Object> parent,
int field_offset) { … }
void V8HeapExplorer::SetContextReference(HeapEntry* parent_entry,
Tagged<String> reference_name,
Tagged<Object> child_obj,
int field_offset) { … }
void V8HeapExplorer::MarkVisitedField(int offset) { … }
void V8HeapExplorer::SetNativeBindReference(HeapEntry* parent_entry,
const char* reference_name,
Tagged<Object> child_obj) { … }
void V8HeapExplorer::SetElementReference(HeapEntry* parent_entry, int index,
Tagged<Object> child_obj) { … }
void V8HeapExplorer::SetInternalReference(HeapEntry* parent_entry,
const char* reference_name,
Tagged<Object> child_obj,
int field_offset) { … }
void V8HeapExplorer::SetInternalReference(HeapEntry* parent_entry, int index,
Tagged<Object> child_obj,
int field_offset) { … }
void V8HeapExplorer::SetHiddenReference(Tagged<HeapObject> parent_obj,
HeapEntry* parent_entry, int index,
Tagged<Object> child_obj,
int field_offset) { … }
void V8HeapExplorer::SetWeakReference(
HeapEntry* parent_entry, const char* reference_name,
Tagged<Object> child_obj, int field_offset,
HeapEntry::ReferenceVerification verification) { … }
void V8HeapExplorer::SetWeakReference(HeapEntry* parent_entry, int index,
Tagged<Object> child_obj,
std::optional<int> field_offset) { … }
void V8HeapExplorer::SetDataOrAccessorPropertyReference(
PropertyKind kind, HeapEntry* parent_entry, Tagged<Name> reference_name,
Tagged<Object> child_obj, const char* name_format_string,
int field_offset) { … }
void V8HeapExplorer::SetPropertyReference(HeapEntry* parent_entry,
Tagged<Name> reference_name,
Tagged<Object> child_obj,
const char* name_format_string,
int field_offset) { … }
void V8HeapExplorer::SetRootGcRootsReference() { … }
void V8HeapExplorer::SetUserGlobalReference(Tagged<Object> child_obj) { … }
void V8HeapExplorer::SetGcRootsReference(Root root) { … }
void V8HeapExplorer::SetGcSubrootReference(Root root, const char* description,
bool is_weak,
Tagged<Object> child_obj) { … }
const char* V8HeapExplorer::GetStrongGcSubrootName(Tagged<HeapObject> object) { … }
void V8HeapExplorer::TagObject(Tagged<Object> obj, const char* tag,
std::optional<HeapEntry::Type> type,
bool overwrite_existing_name) { … }
void V8HeapExplorer::RecursivelyTagConstantPool(Tagged<Object> obj,
const char* tag,
HeapEntry::Type type,
int recursion_limit) { … }
class GlobalObjectsEnumerator : public RootVisitor { … };
V8HeapExplorer::TemporaryGlobalObjectTags
V8HeapExplorer::CollectTemporaryGlobalObjectsTags() { … }
void V8HeapExplorer::MakeGlobalObjectTagMap(
TemporaryGlobalObjectTags&& global_object_tags) { … }
class EmbedderGraphImpl : public EmbedderGraph { … };
class EmbedderGraphEntriesAllocator : public HeapEntriesAllocator { … };
namespace {
const char* EmbedderGraphNodeName(StringsStorage* names,
EmbedderGraphImpl::Node* node) { … }
HeapEntry::Type EmbedderGraphNodeType(EmbedderGraphImpl::Node* node) { … }
const char* MergeNames(StringsStorage* names, const char* embedder_name,
const char* wrapper_name) { … }
}
HeapEntry* EmbedderGraphEntriesAllocator::AllocateEntry(HeapThing ptr) { … }
HeapEntry* EmbedderGraphEntriesAllocator::AllocateEntry(Tagged<Smi> smi) { … }
NativeObjectsExplorer::NativeObjectsExplorer(
HeapSnapshot* snapshot, SnapshottingProgressReportingInterface* progress)
: … { … }
void NativeObjectsExplorer::MergeNodeIntoEntry(
HeapEntry* entry, EmbedderGraph::Node* original_node,
EmbedderGraph::Node* wrapper_node) { … }
HeapEntry* NativeObjectsExplorer::EntryForEmbedderGraphNode(
EmbedderGraphImpl::Node* node) { … }
bool NativeObjectsExplorer::IterateAndExtractReferences(
HeapSnapshotGenerator* generator) { … }
HeapSnapshotGenerator::HeapSnapshotGenerator(
HeapSnapshot* snapshot, v8::ActivityControl* control,
v8::HeapProfiler::ObjectNameResolver* resolver, Heap* heap,
cppgc::EmbedderStackState stack_state)
: … { … }
namespace {
class V8_NODISCARD NullContextForSnapshotScope { … };
}
bool HeapSnapshotGenerator::GenerateSnapshot() { … }
bool HeapSnapshotGenerator::GenerateSnapshotAfterGC() { … }
void HeapSnapshotGenerator::ProgressStep() { … }
bool HeapSnapshotGenerator::ProgressReport(bool force) { … }
void HeapSnapshotGenerator::InitProgressCounter() { … }
bool HeapSnapshotGenerator::FillReferences() { … }
const int HeapSnapshotJSONSerializer::kNodeFieldsCount = …;
void HeapSnapshotJSONSerializer::Serialize(v8::OutputStream* stream) { … }
void HeapSnapshotJSONSerializer::SerializeImpl() { … }
int HeapSnapshotJSONSerializer::GetStringId(const char* s) { … }
namespace {
template <size_t size>
struct ToUnsigned;
template <>
struct ToUnsigned<1> { … };
template <>
struct ToUnsigned<4> { … };
template <>
struct ToUnsigned<8> { … };
}
template <typename T>
static int utoa_impl(T value, base::Vector<char> buffer, int buffer_pos) { … }
template <typename T>
static int utoa(T value, base::Vector<char> buffer, int buffer_pos) { … }
void HeapSnapshotJSONSerializer::SerializeEdge(HeapGraphEdge* edge,
bool first_edge) { … }
void HeapSnapshotJSONSerializer::SerializeEdges() { … }
void HeapSnapshotJSONSerializer::SerializeNode(const HeapEntry* entry) { … }
void HeapSnapshotJSONSerializer::SerializeNodes() { … }
void HeapSnapshotJSONSerializer::SerializeSnapshot() { … }
static void WriteUChar(OutputStreamWriter* w, unibrow::uchar u) { … }
void HeapSnapshotJSONSerializer::SerializeTraceTree() { … }
void HeapSnapshotJSONSerializer::SerializeTraceNode(AllocationTraceNode* node) { … }
static int SerializePosition(int position, base::Vector<char> buffer,
int buffer_pos) { … }
void HeapSnapshotJSONSerializer::SerializeTraceNodeInfos() { … }
void HeapSnapshotJSONSerializer::SerializeSamples() { … }
void HeapSnapshotJSONSerializer::SerializeString(const unsigned char* s) { … }
void HeapSnapshotJSONSerializer::SerializeStrings() { … }
void HeapSnapshotJSONSerializer::SerializeLocation(
const EntrySourceLocation& location) { … }
void HeapSnapshotJSONSerializer::SerializeLocations() { … }
}