48#if V8_ENABLE_WEBASSEMBLY
58#ifdef V8_ENABLE_HEAP_SNAPSHOT_VERIFY
59class HeapEntryVerifier {
61 HeapEntryVerifier(HeapSnapshotGenerator* generator, Tagged<HeapObject> obj)
65 ReferenceSummary::SummarizeReferencesFrom(generator->
heap(), obj)) {
66 generator->set_verifier(
this);
68 ~HeapEntryVerifier() {
69 CheckAllReferencesWereChecked();
76 void CheckStrongReference(Tagged<HeapObject> host,
77 Tagged<HeapObject> target) {
81 checked_objects_.insert(target);
84 if (reference_summary_.strong_references().find(target) !=
85 reference_summary_.strong_references().end()) {
94 for (
size_t level = 0; level < 3; ++level) {
95 const UnorderedHeapObjectSet& indirect =
96 GetIndirectStrongReferences(level);
97 if (indirect.find(target) != indirect.end()) {
102 FATAL(
"Could not find any matching reference");
107 void CheckWeakReference(Tagged<HeapObject> host, Tagged<HeapObject> target) {
111 checked_objects_.insert(target);
112 CHECK_NE(reference_summary_.weak_references().find(target),
113 reference_summary_.weak_references().end());
120 void MarkReferenceCheckedWithoutChecking(Tagged<HeapObject> host,
121 Tagged<HeapObject> target) {
123 checked_objects_.insert(target);
132 void CheckAllReferencesWereChecked() {
137 for (Tagged<HeapObject> obj : reference_summary_.strong_references()) {
138 if (!MemoryChunk::FromHeapObject(obj)->InReadOnlySpace()) {
139 CHECK_NE(checked_objects_.find(obj), checked_objects_.end());
142 for (Tagged<HeapObject> obj : reference_summary_.weak_references()) {
143 if (!MemoryChunk::FromHeapObject(obj)->InReadOnlySpace()) {
144 CHECK_NE(checked_objects_.find(obj), checked_objects_.end());
150 using UnorderedHeapObjectSet =
151 std::unordered_set<Tagged<HeapObject>, Object::Hasher,
152 Object::KeyEqualSafe>;
154 const UnorderedHeapObjectSet& GetIndirectStrongReferences(
size_t level) {
155 CHECK_GE(indirect_strong_references_.size(), level);
157 if (indirect_strong_references_.size() == level) {
159 indirect_strong_references_.resize(level + 1);
160 const UnorderedHeapObjectSet&
previous =
161 level == 0 ? reference_summary_.strong_references()
162 : indirect_strong_references_[level - 1];
163 for (Tagged<HeapObject> obj :
previous) {
164 if (MemoryChunk::FromHeapObject(obj)->InReadOnlySpace()) {
174 if (IsJSReceiver(obj) || IsString(obj) || IsContext(obj)) {
178 ReferenceSummary summary =
179 ReferenceSummary::SummarizeReferencesFrom(
generator_->heap(), obj);
180 indirect_strong_references_[level].insert(
181 summary.strong_references().begin(),
182 summary.strong_references().end());
186 return indirect_strong_references_[level];
194 ReferenceSummary reference_summary_;
199 std::unordered_set<Tagged<HeapObject>, Object::Hasher, Object::KeyEqualSafe>
205 std::vector<UnorderedHeapObjectSet> indirect_strong_references_;
230 unsigned trace_node_id)
231 :
type_(static_cast<unsigned>(type)),
234 self_size_(self_size),
238 trace_node_id_(trace_node_id) {
245#ifdef V8_ENABLE_HEAP_SNAPSHOT_VERIFY
246 if (verification ==
kOffHeapPointer || generator->verifier() ==
nullptr) {
260 reinterpret_cast<Address>(generator->FindHeapThingForHeapEntry(
this));
262 reinterpret_cast<Address>(generator->FindHeapThingForHeapEntry(entry));
281 generator->verifier()->MarkReferenceCheckedWithoutChecking(from_obj,
284 generator->verifier()->CheckWeakReference(from_obj, to_obj);
286 generator->verifier()->CheckStrongReference(from_obj, to_obj);
310 const char* description,
316 const char* name = description
317 ? names->GetFormatted(
"%d / %s", index, description)
318 : names->GetName(index);
324 static_assert(
sizeof(unsigned) ==
sizeof(
id()));
325 base::OS::Print(
"%6zu @%6u %*c %s%s: ",
self_size(),
id(), indent,
' ',
330 base::OS::Print(
"\"");
331 const char* c =
name_;
332 while (*c && (c -
name_) <= 40) {
334 base::OS::Print(
"%c", *c);
336 base::OS::Print(
"\\n");
339 base::OS::Print(
"\"\n");
341 if (--max_depth == 0)
return;
344 const char* edge_prefix =
"";
346 edge_name = index.
begin();
347 switch (edge.
type()) {
350 edge_name = edge.
name();
353 SNPrintF(index,
"%d", edge.
index());
357 edge_name = edge.
name();
360 edge_name = edge.
name();
364 SNPrintF(index,
"%d", edge.
index());
368 edge_name = edge.
name();
372 edge_name = edge.
name();
375 SNPrintF(index,
"!!! unknown edge type: %d ", edge.
type());
377 edge.
to()->
Print(edge_prefix, edge_name, max_depth, indent + 2);
402 return "/synthetic/";
404 return "/concatenated string/";
406 return "/sliced string/";
412 return "/object shape/";
421 : profiler_(profiler),
422 snapshot_mode_(snapshot_mode),
423 numerics_mode_(numerics_mode) {
482 unsigned trace_node_id) {
484 entries_.emplace_back(
this,
static_cast<int>(
entries_.size()), type, name,
id,
485 size, trace_node_id);
502 int children_index = 0;
504 children_index = entry.set_children_index(children_index);
509 edge.from()->add_child(&edge);
543 if (IsExternalOneByteString(
object, cage_base)) {
550 PtrComprCageBase cage_base) {
552 GetExternalStringResource(
object, cage_base);
554 if (external_string_size ==
556 return object->ExternalPayloadSize();
558 DCHECK_LE(external_string_size, std::numeric_limits<int>::max());
559 return base::saturated_cast<int>(external_string_size);
567 int size =
object->Size(cage_base);
578 : next_id_(kFirstAvailableObjectId),
579 next_native_id_(kFirstAvailableNativeId),
591 if (from == to)
return false;
594 if (from_value ==
nullptr) {
600 if (to_value !=
nullptr) {
601 int to_entry_info_index =
602 static_cast<int>(
reinterpret_cast<intptr_t
>(to_value));
608 if (to_entry->
value !=
nullptr) {
614 int to_entry_info_index =
615 static_cast<int>(
reinterpret_cast<intptr_t
>(to_entry->
value));
618 int from_entry_info_index =
619 static_cast<int>(
reinterpret_cast<intptr_t
>(from_value));
624 if (
v8_flags.heap_profiler_trace_objects) {
625 PrintF(
"Move object from %p to %p old size %6d new size %6d\n",
626 reinterpret_cast<void*
>(from),
reinterpret_cast<void*
>(to),
627 entries_.at(from_entry_info_index).size, object_size);
629 entries_.at(from_entry_info_index).size = object_size;
630 to_entry->
value = from_value;
632 return from_value !=
nullptr;
643 int entry_index =
static_cast<int>(
reinterpret_cast<intptr_t
>(entry->
value));
646 return entry_info.
id;
657 if (entry->
value !=
nullptr) {
659 static_cast<int>(
reinterpret_cast<intptr_t
>(entry->
value));
661 entry_info.
accessed = accessed_bool;
662 if (
v8_flags.heap_profiler_trace_objects) {
663 PrintF(
"Update object size : %p with old size %d and new size %d\n",
664 reinterpret_cast<void*
>(addr), entry_info.
size, size);
667 DCHECK_EQ(is_native_object_bool, entry_info.
id % 2 == 0);
668 return entry_info.
id;
691 {addr,
reinterpret_cast<size_t>(entry->
value)});
693 result.first->second =
reinterpret_cast<size_t>(entry->
value);
700 if (
v8_flags.heap_profiler_trace_objects) {
701 PrintF(
"Begin HeapObjectsMap::UpdateHeapObjectsMap. map has %d entries.\n",
709 obj = iterator.
Next()) {
711 if (
v8_flags.heap_profiler_trace_objects) {
712 int object_size = obj->Size(cage_base);
713 PrintF(
"Update object : %p %6d. Next address is %p\n",
714 reinterpret_cast<void*
>(obj.address()), object_size,
715 reinterpret_cast<void*
>(obj.address() + object_size));
719 if (
v8_flags.heap_profiler_trace_objects) {
720 PrintF(
"End HeapObjectsMap::UpdateHeapObjectsMap. map has %d entries.\n",
726 int64_t* timestamp_us) {
730 std::vector<v8::HeapStatsUpdate> stats_buffer;
734 for (
size_t time_interval_index = 0;
738 uint32_t entries_size = 0;
739 EntryInfo* start_entry_info = entry_info;
740 while (entry_info < end_entry_info && entry_info->
id < time_interval_id) {
741 entries_size += entry_info->
size;
744 uint32_t entries_count =
745 static_cast<uint32_t
>(entry_info - start_entry_info);
746 if (time_interval.
count != entries_count ||
747 time_interval.
size != entries_size) {
748 stats_buffer.emplace_back(
static_cast<uint32_t
>(time_interval_index),
749 time_interval.
count = entries_count,
750 time_interval.
size = entries_size);
751 if (
static_cast<int>(stats_buffer.size()) >= prefered_chunk_size) {
753 &stats_buffer.front(),
static_cast<int>(stats_buffer.size()));
755 stats_buffer.clear();
759 DCHECK(entry_info == end_entry_info);
760 if (!stats_buffer.empty()) {
762 &stats_buffer.front(),
static_cast<int>(stats_buffer.size()));
779 std::unordered_map<size_t, NativeObject> reverse_merged_native_entries_map;
782 reverse_merged_native_entries_map.emplace(it.second, it.first);
787 size_t first_free_entry = 1;
790 auto merged_reverse_it = reverse_merged_native_entries_map.find(
i);
792 if (first_free_entry !=
i) {
793 entries_.at(first_free_entry) = entry_info;
795 entries_.at(first_free_entry).accessed =
false;
800 entry->
value =
reinterpret_cast<void*
>(first_free_entry);
801 if (merged_reverse_it != reverse_merged_native_entries_map.end()) {
804 it->second = first_free_entry;
808 if (entry_info.
addr) {
811 if (merged_reverse_it != reverse_merged_native_entries_map.end()) {
826 :
heap_(snapshot->profiler()->heap_object_map()->
heap()),
828 names_(snapshot_->profiler()->names()),
829 heap_object_map_(snapshot_->profiler()->heap_object_map()),
832 global_object_name_resolver_(resolver) {}
853 if (IsJSFunction(
object)) {
855 }
else if (IsJSGeneratorObject(
object)) {
857 return gen->function();
858 }
else if (IsJSObject(
object)) {
863 return maybe_constructor;
880 if (!IsScript(func->shared()->script()))
return;
882 int scriptId = script->id();
883 int start = func->shared()->StartPosition();
885 if (script->has_line_ends()) {
886 script->GetPositionInfo(
start, &info);
888 script->GetPositionInfoWithLineEnds(
896 InstanceType instance_type =
object->map(cage_base)->instance_type();
897 if (InstanceTypeChecker::IsJSObject(instance_type)) {
898 if (InstanceTypeChecker::IsJSFunction(instance_type)) {
904 }
else if (InstanceTypeChecker::IsJSBoundFunction(instance_type)) {
907 if (InstanceTypeChecker::IsJSRegExp(instance_type)) {
916 if (InstanceTypeChecker::IsJSGlobalObject(instance_type)) {
919 name =
names_->GetFormatted(
"%s / %s", name, it->second);
924 }
else if (InstanceTypeChecker::IsString(instance_type)) {
926 if (IsConsString(
string, cage_base)) {
928 }
else if (IsSlicedString(
string, cage_base)) {
934 }
else if (InstanceTypeChecker::IsSymbol(instance_type)) {
940 }
else if (InstanceTypeChecker::IsBigInt(instance_type)) {
943 }
else if (InstanceTypeChecker::IsInstructionStream(instance_type) ||
944 InstanceTypeChecker::IsCode(instance_type)) {
947 }
else if (InstanceTypeChecker::IsSharedFunctionInfo(instance_type)) {
951 }
else if (InstanceTypeChecker::IsScript(instance_type)) {
956 }
else if (InstanceTypeChecker::IsNativeContext(instance_type)) {
959 }
else if (InstanceTypeChecker::IsContext(instance_type)) {
962 }
else if (InstanceTypeChecker::IsHeapNumber(instance_type)) {
964 }
else if (InstanceTypeChecker::IsOddball(instance_type)) {
968#if V8_ENABLE_WEBASSEMBLY
969 if (InstanceTypeChecker::IsWasmObject(instance_type)) {
974 sb <<
" (wasm)" <<
'\0';
980 if (InstanceTypeChecker::IsForeign(instance_type)) {
984 size_t size = SizeForSnapshot(
object, cage_base);
985 const char* name =
nullptr;
990 name =
"system / Managed<Unknown>";
992#if V8_ENABLE_WEBASSEMBLY
994 name =
"system / Managed<WasmStreaming>";
997 name =
"system / Managed<wasm::FuncData>";
1000 name =
"system / Managed<wasm::ManagedData>";
1005 ->EstimateCurrentMemoryConsumption();
1006 name =
"system / Managed<wasm::NativeModule>";
1010 name =
"system / Managed<icu::BreakIterator>";
1013 name =
"system / Managed<icu::UnicodeString>";
1016 name =
"system / Managed<icu::ListFormatter>";
1019 name =
"system / Managed<icu::Locale>";
1022 name =
"system / Managed<icu::SimpleDateFormat>";
1025 name =
"system / Managed<icu::DateIntervalFormat>";
1028 name =
"system / Managed<icu::RelativeDateTimeFormatter>";
1031 name =
"system / Managed<icu::LocalizedNumberFormatter>";
1034 name =
"system / Managed<icu::PluralRules>";
1037 name =
"system / Managed<icu::Collator>";
1040 name =
"system / Managed<DisplayNamesInternal>";
1045 if (name !=
nullptr) {
1057 return AddEntry(
object.address(), type, name,
1058 SizeForSnapshot(
object, cage_base));
1062 const char* name,
size_t size) {
1063 if (
v8_flags.heap_profiler_show_hidden_objects &&
1068 address,
static_cast<unsigned int>(size));
1069 unsigned trace_node_id = 0;
1073 allocation_tracker->address_to_trace()->GetTraceNodeId(address);
1079 if (IsMap(
object)) {
1080 switch (
Cast<Map>(
object)->instance_type()) {
1081#define MAKE_STRING_MAP_CASE(instance_type, size, name, Name) \
1082 case instance_type: \
1083 return "system / Map (" #Name ")";
1085#undef MAKE_STRING_MAP_CASE
1087 return "system / Map";
1095 if (InstanceTypeChecker::IsFixedArray(type) ||
1096 InstanceTypeChecker::IsFixedDoubleArray(type) ||
1097 InstanceTypeChecker::IsByteArray(type)) {
1102#define MAKE_TORQUE_CASE(Name, TYPE) \
1104 return "system / " #Name;
1112#undef MAKE_TORQUE_CASE
1115#define MAKE_STRING_CASE(instance_type, size, name, Name) \
1116 case instance_type: \
1119#undef MAKE_STRING_CASE
1125 if (InstanceTypeChecker::IsAllocationSite(type) ||
1126 InstanceTypeChecker::IsArrayBoilerplateDescription(type) ||
1127 InstanceTypeChecker::IsBytecodeArray(type) ||
1128 InstanceTypeChecker::IsBytecodeWrapper(type) ||
1129 InstanceTypeChecker::IsClosureFeedbackCellArray(type) ||
1130 InstanceTypeChecker::IsCode(type) ||
1131 InstanceTypeChecker::IsCodeWrapper(type) ||
1132 InstanceTypeChecker::IsFeedbackCell(type) ||
1133 InstanceTypeChecker::IsFeedbackMetadata(type) ||
1134 InstanceTypeChecker::IsFeedbackVector(type) ||
1135 InstanceTypeChecker::IsInstructionStream(type) ||
1136 InstanceTypeChecker::IsInterpreterData(type) ||
1137 InstanceTypeChecker::IsLoadHandler(type) ||
1138 InstanceTypeChecker::IsObjectBoilerplateDescription(type) ||
1139 InstanceTypeChecker::IsPreparseData(type) ||
1140 InstanceTypeChecker::IsRegExpBoilerplateDescription(type) ||
1141 InstanceTypeChecker::IsScopeInfo(type) ||
1142 InstanceTypeChecker::IsStoreHandler(type) ||
1143 InstanceTypeChecker::IsTemplateObjectDescription(type) ||
1144 InstanceTypeChecker::IsTurbofanType(type) ||
1145 InstanceTypeChecker::IsUncompiledData(type)) {
1151 if (InstanceTypeChecker::IsFixedArray(type) ||
1152 InstanceTypeChecker::IsFixedDoubleArray(type) ||
1153 InstanceTypeChecker::IsByteArray(type)) {
1159 if ((InstanceTypeChecker::IsMap(type) &&
1161 InstanceTypeChecker::IsDescriptorArray(type) ||
1162 InstanceTypeChecker::IsTransitionArray(type) ||
1163 InstanceTypeChecker::IsPrototypeInfo(type) ||
1164 InstanceTypeChecker::IsEnumCache(type)) {
1172 std::vector<Handle<Script>> scripts;
1178 script = iterator.
Next()) {
1179 if (!script->has_line_ends()) {
1185 for (
auto& script : scripts) {
1193 uint32_t objects_count = 0;
1197 while (!it.Next().is_null() &&
1198 objects_count != std::numeric_limits<uint32_t>::max())
1200 return objects_count;
1203#ifdef V8_TARGET_BIG_ENDIAN
1212 int emb_end_index = emb_start_index + emb_field_count;
1267 if (code->IsWeakObject(
object)) {
1299#ifdef V8_ENABLE_LEAPTIERING
1303 if (IsJSFunction(host)) {
1304 int field_index = JSFunction::kDispatchHandleOffset /
kTaggedSize;
1307 }
else if (IsCode(host) || IsFeedbackCell(host)) {
1316 template <
typename TIsolateOrCageBase,
typename TSlot>
1321 TSlot::kSlotDataSize;
1322#ifdef V8_TARGET_BIG_ENDIAN
1323 field_index += AdjustEmbedderFieldIndex(
parent_obj_, field_index);
1330 auto loaded_value = slot.load(isolate_or_cage_base);
1331 if (loaded_value.GetHeapObjectIfStrong(&heap_object)) {
1333 }
else if (loaded_value.GetHeapObjectIfWeak(&heap_object)) {
1359 if (IsJSGlobalProxy(obj)) {
1361 }
else if (IsJSArrayBuffer(obj)) {
1363 }
else if (IsJSObject(obj)) {
1364 if (IsJSWeakSet(obj)) {
1366 }
else if (IsJSWeakMap(obj)) {
1368 }
else if (IsJSSet(obj)) {
1370 }
else if (IsJSMap(obj)) {
1372 }
else if (IsJSPromise(obj)) {
1374 }
else if (IsJSGeneratorObject(obj)) {
1376 }
else if (IsJSWeakRef(obj)) {
1378#if V8_ENABLE_WEBASSEMBLY
1379 }
else if (IsWasmInstanceObject(obj)) {
1381 }
else if (IsWasmModuleObject(obj)) {
1386 }
else if (IsString(obj)) {
1388 }
else if (IsSymbol(obj)) {
1390 }
else if (IsMap(obj)) {
1392 }
else if (IsSharedFunctionInfo(obj)) {
1394 }
else if (IsScript(obj)) {
1396 }
else if (IsAccessorInfo(obj)) {
1398 }
else if (IsAccessorPair(obj)) {
1400 }
else if (IsCode(obj)) {
1402 }
else if (IsInstructionStream(obj)) {
1404 }
else if (IsCell(obj)) {
1406 }
else if (IsFeedbackCell(obj)) {
1408 }
else if (IsPropertyCell(obj)) {
1410 }
else if (IsPrototypeInfo(obj)) {
1412 }
else if (IsAllocationSite(obj)) {
1414 }
else if (IsArrayBoilerplateDescription(obj)) {
1417 }
else if (IsRegExpBoilerplateDescription(obj)) {
1420 }
else if (IsFeedbackVector(obj)) {
1422 }
else if (IsDescriptorArray(obj)) {
1424 }
else if (IsEnumCache(obj)) {
1426 }
else if (IsTransitionArray(obj)) {
1428 }
else if (IsWeakFixedArray(obj)) {
1431 }
else if (IsWeakArrayList(obj)) {
1434 }
else if (IsContext(obj)) {
1436 }
else if (IsEphemeronHashTable(obj)) {
1438 }
else if (IsFixedArray(obj)) {
1440 }
else if (IsWeakCell(obj)) {
1442 }
else if (IsHeapNumber(obj)) {
1446 }
else if (IsBytecodeArray(obj)) {
1448 }
else if (IsScopeInfo(obj)) {
1450#if V8_ENABLE_WEBASSEMBLY
1451 }
else if (IsWasmStruct(obj)) {
1453 }
else if (IsWasmArray(obj)) {
1455 }
else if (IsWasmTrustedInstanceData(obj)) {
1475 if (IsJSBoundFunction(obj)) {
1477 TagObject(js_fun->bound_arguments(),
"(bound arguments)");
1479 JSBoundFunction::kBoundArgumentsOffset);
1481 JSBoundFunction::kBoundThisOffset);
1483 js_fun->bound_target_function(),
1484 JSBoundFunction::kBoundTargetFunctionOffset);
1486 for (
int i = 0;
i < bindings->length();
i++) {
1487 const char* reference_name =
names_->GetFormatted(
"bound_argument_%d",
i);
1490 }
else if (IsJSFunction(obj)) {
1492 if (js_fun->has_prototype_slot()) {
1495 if (!IsTheHole(proto_or_map, isolate)) {
1496 if (!IsMap(proto_or_map)) {
1499 JSFunction::kPrototypeOrInitialMapOffset);
1502 js_fun->prototype());
1504 JSFunction::kPrototypeOrInitialMapOffset);
1509 TagObject(js_fun->raw_feedback_cell(),
"(function feedback cell)");
1511 JSFunction::kFeedbackCellOffset);
1512 TagObject(shared_info,
"(shared function info)");
1514 JSFunction::kSharedFunctionInfoOffset);
1515 TagObject(js_fun->context(),
"(context)");
1517 JSFunction::kContextOffset);
1518#ifdef V8_ENABLE_LEAPTIERING
1520 JSFunction::kDispatchHandleOffset);
1523 JSFunction::kCodeOffset);
1525 }
else if (IsJSGlobalObject(obj)) {
1528 JSGlobalObject::kGlobalProxyOffset);
1529 }
else if (IsJSArrayBufferView(obj)) {
1532 JSArrayBufferView::kBufferOffset);
1535 TagObject(js_obj->raw_properties_or_hash(),
"(object properties)");
1537 JSObject::kPropertiesOrHashOffset);
1539 TagObject(js_obj->elements(),
"(object elements)");
1541 JSObject::kElementsOffset);
1548 ExternalDataEntryAllocator(
size_t size,
V8HeapExplorer* explorer,
1551 HeapEntry* AllocateEntry(
HeapThing ptr)
override {
1563class ExternalStringRecorder
1566 ExternalStringRecorder(HeapEntry* entry, V8HeapExplorer* explorer,
1567 HeapSnapshotGenerator* generator,
1568 StringsStorage* names)
1573 void RecordSharedMemoryUsage(
const void* location,
size_t size)
final {
1574 ExternalDataEntryAllocator allocator(size, explorer_,
1575 "system / ExternalStringData");
1576 HeapEntry* data_entry =
1579 "backing_store", data_entry, names_,
1594 if (IsConsString(
string)) {
1600 }
else if (IsSlicedString(
string)) {
1604 }
else if (IsThinString(
string)) {
1608 }
else if (IsExternalString(
string)) {
1611 GetExternalStringResource(es,
isolate())) {
1621 offsetof(
Symbol, description_));
1627 JSCollection::kTableOffset);
1633 JSWeakCollection::kTableOffset);
1639 int key_index = EphemeronHashTable::EntryToIndex(
i) +
1640 EphemeronHashTable::kEntryKeyIndex;
1641 int value_index = EphemeronHashTable::EntryToValueIndex(
i);
1645 table->OffsetOfElementAt(key_index));
1647 table->OffsetOfElementAt(value_index));
1651 if (key_entry && value_entry && !IsUndefined(
key)) {
1652 const char* edge_name =
names_->GetFormatted(
1653 "part of key (%s @%u) -> value (%s @%u) pair in WeakMap (table @%u)",
1654 key_entry->
name(), key_entry->
id(), value_entry->
name(),
1655 value_entry->
id(), table_entry->
id());
1669static const struct {
1673#define CONTEXT_FIELD_INDEX_NAME(index, _, name) {Context::index, #name},
1675#undef CONTEXT_FIELD_INDEX_NAME
1681 if (!IsNativeContext(context) && context->is_declaration_context()) {
1685 int idx = scope_info->ContextHeaderLength() + it->index();
1689 if (scope_info->HasContextAllocatedFunctionName()) {
1691 int idx = scope_info->FunctionContextSlotIndex(name);
1704 if (context->has_extension()) {
1710 if (IsNativeContext(context)) {
1711 TagObject(context->normalized_map_cache(),
"(context norm. map cache)");
1712 TagObject(context->embedder_data(),
"(context data)");
1728 map->raw_transitions();
1731 &raw_transitions_or_prototype_info)) {
1732 DCHECK(IsMap(raw_transitions_or_prototype_info));
1734 Map::kTransitionsOrPrototypeInfoOffset);
1736 &raw_transitions_or_prototype_info)) {
1737 if (IsTransitionArray(raw_transitions_or_prototype_info)) {
1740 if (map->CanTransition() && transitions->HasPrototypeTransitions()) {
1741 TagObject(transitions->GetPrototypeTransitions(),
1742 "(prototype transitions)");
1744 TagObject(transitions,
"(transition array)");
1746 Map::kTransitionsOrPrototypeInfoOffset);
1747 }
else if (IsFixedArray(raw_transitions_or_prototype_info)) {
1748 TagObject(raw_transitions_or_prototype_info,
"(transition)");
1750 raw_transitions_or_prototype_info,
1751 Map::kTransitionsOrPrototypeInfoOffset);
1752 }
else if (map->is_prototype_map()) {
1753 TagObject(raw_transitions_or_prototype_info,
"prototype_info");
1755 raw_transitions_or_prototype_info,
1756 Map::kTransitionsOrPrototypeInfoOffset);
1760 TagObject(descriptors,
"(map descriptors)");
1762 Map::kInstanceDescriptorsOffset);
1764 Map::kPrototypeOffset);
1765 if (IsContextMap(map) || IsMapMap(map)) {
1769 Map::kConstructorOrBackPointerOrNativeContextOffset);
1772 map->constructor_or_back_pointer();
1776 Map::kConstructorOrBackPointerOrNativeContextOffset);
1781 Map::kConstructorOrBackPointerOrNativeContextOffset);
1784 Map::kConstructorOrBackPointerOrNativeContextOffset);
1787 TagObject(map->dependent_code(),
"(dependent code)");
1789 Map::kDependentCodeOffset);
1796 TagObject(shared,
"(shared function info)");
1798 std::unique_ptr<char[]> name = shared->DebugNameCStr();
1801 ?
names_->GetFormatted(
"(code for %s)", name.get())
1802 :
names_->GetFormatted(
"(%s code)",
1804 if (code->has_instruction_stream()) {
1806 code->instruction_stream(),
1808 ?
names_->GetFormatted(
"(instruction stream for %s)", name.get())
1809 :
names_->GetFormatted(
"(%s instruction stream)",
1815 if (IsScopeInfo(name_or_scope_info)) {
1816 TagObject(name_or_scope_info,
"(function scope info)");
1819 SharedFunctionInfo::kNameOrScopeInfoOffset);
1821 SharedFunctionInfo::kScriptOffset);
1823 shared->GetTrustedData(isolate()),
1824 SharedFunctionInfo::kTrustedFunctionDataOffset);
1826 shared->GetUntrustedData(),
1827 SharedFunctionInfo::kUntrustedFunctionDataOffset);
1829 entry,
"raw_outer_scope_info_or_feedback_metadata",
1830 shared->raw_outer_scope_info_or_feedback_metadata(),
1831 SharedFunctionInfo::kOuterScopeInfoOrFeedbackMetadataOffset);
1837 Script::kSourceOffset);
1840 Script::kContextDataOffset);
1843 Script::kLineEndsOffset);
1845 TagObject(script->host_defined_options(),
"(host-defined options)",
1847#if V8_ENABLE_WEBASSEMBLY
1848 if (script->type() == Script::Type::kWasm) {
1851 script->wasm_breakpoint_infos(),
1852 Script::kEvalFromSharedOrWrappedArgumentsOffset);
1854 script->wasm_managed_native_module(),
1855 Script::kEvalFromPositionOffset);
1857 script->wasm_weak_instance_list(),
1858 Script::kInfosOffset);
1866 AccessorInfo::kNameOffset);
1868 AccessorInfo::kDataOffset);
1882 JSWeakRef::kTargetOffset);
1888 WeakCell::kTargetOffset);
1890 WeakCell::kUnregisterTokenOffset);
1895 if (code->has_instruction_stream()) {
1897 names_->GetFormatted(
"(%s builtin instruction stream)", name));
1903 if (!code->has_instruction_stream())
return;
1906 Code::kInstructionStreamOffset);
1908 if (code->kind() == CodeKind::BASELINE) {
1909 TagObject(code->bytecode_or_interpreter_data(),
"(interpreter data)");
1911 code->bytecode_or_interpreter_data(),
1912 Code::kDeoptimizationDataOrInterpreterDataOffset);
1913 TagObject(code->bytecode_offset_table(),
"(bytecode offset table)",
1916 code->bytecode_offset_table(),
1917 Code::kPositionTableOffset);
1918 }
else if (code->uses_deoptimization_data()) {
1923 Code::kDeoptimizationDataOrInterpreterDataOffset);
1924 if (deoptimization_data->length() > 0) {
1925 TagObject(deoptimization_data->FrameTranslation(),
"(code deopt data)",
1927 TagObject(deoptimization_data->LiteralArray(),
"(code deopt data)",
1929 TagObject(deoptimization_data->InliningPositions(),
"(code deopt data)",
1932 TagObject(code->source_position_table(),
"(source position table)",
1935 code->source_position_table(),
1936 Code::kPositionTableOffset);
1948 TagObject(istream->relocation_info(),
"(code relocation info)",
1951 InstructionStream::kRelocationInfoOffset);
1961 TagObject(feedback_cell,
"(feedback cell)");
1963 FeedbackCell::kValueOffset);
1969 PropertyCell::kValueOffset);
1970 TagObject(cell->dependent_code(),
"(dependent code)");
1972 PropertyCell::kDependentCodeOffset);
1977 TagObject(info->prototype_chain_enum_cache(),
"(prototype chain enum cache)",
1979 TagObject(info->prototype_users(),
"(prototype users)",
1986 entry,
"transition_info", site->transition_info_or_boilerplate(),
1999 ArrayBoilerplateDescription::kConstantElementsOffset);
2011 if (!buffer->backing_store())
return;
2012 size_t data_size = buffer->byte_length();
2013 ExternalDataEntryAllocator allocator(data_size,
this,
2014 "system / JSArrayBufferData");
2024 promise->reactions_or_result(),
2025 JSPromise::kReactionsOrResultOffset);
2031 JSGeneratorObject::kFunctionOffset);
2033 JSGeneratorObject::kContextOffset);
2035 JSGeneratorObject::kReceiverOffset);
2037 generator->parameters_and_registers(),
2038 JSGeneratorObject::kParametersAndRegistersOffset);
2043 for (
int i = 0, l = array->
length();
i < l; ++
i) {
2058 if (
IsSmi(number)) {
2068 const char* name =
names_->
GetCopy(std::string(
string).c_str());
2088 if (!info->HasInlinedLocalNames()) {
2089 TagObject(info->context_local_names_hashtable(),
"(context local names)",
2096#ifndef V8_ENABLE_LEAPTIERING
2099 if (code.GetHeapObjectIfWeak(&code_heap_object)) {
2101 FeedbackVector::kMaybeOptimizedCodeOffset);
2104 for (
int i = 0;
i < feedback_vector->length(); ++
i) {
2108 (entry_obj->map(isolate())->instance_type() == WEAK_FIXED_ARRAY_TYPE ||
2109 IsFixedArrayExact(entry_obj))) {
2118 DescriptorArray::kEnumCacheOffset);
2121 array->GetDescriptorSlot(array->number_of_all_descriptors()));
2124 int offset =
static_cast<int>(slot.
address() - array.address());
2127 if (
object.GetHeapObjectIfWeak(&heap_object)) {
2129 }
else if (
object.GetHeapObjectIfStrong(&heap_object)) {
2143 if (transitions->HasPrototypeTransitions()) {
2144 TagObject(transitions->GetPrototypeTransitions(),
"(prototype transitions)",
2149template <
typename T>
2153 for (
int i = 0;
i < array->
length(); ++
i) {
2156 if (
object.GetHeapObjectIfWeak(&heap_object)) {
2158 }
else if (
object.GetHeapObjectIfStrong(&heap_object)) {
2167 Isolate* isolate = js_obj->GetIsolate();
2168 if (js_obj->HasFastProperties()) {
2170 js_obj->map()->instance_descriptors(isolate);
2177 if (
r.IsSmi() ||
r.IsDouble())
break;
2188 nullptr, field_offset);
2194 descs->GetStrongValue(
i));
2198 }
else if (IsJSGlobalObject(js_obj)) {
2204 if (!dictionary->IsKey(roots, dictionary->KeyAt(
i)))
continue;
2217 js_obj->property_dictionary_swiss();
2221 if (!dictionary->IsKey(roots, k))
continue;
2232 if (!dictionary->IsKey(roots, k))
continue;
2245 if (!IsAccessorPair(callback_obj))
return;
2249 if (!IsOddball(
getter)) {
2253 if (!IsOddball(
setter)) {
2261 if (js_obj->HasObjectElements()) {
2264 : elements->length();
2266 if (!IsTheHole(elements->get(
i), roots)) {
2270 }
else if (js_obj->HasDictionaryElements()) {
2274 if (!dictionary->IsKey(roots, k))
continue;
2284 int length = js_obj->GetEmbedderFieldCount();
2291#if V8_ENABLE_WEBASSEMBLY
2301 for (uint32_t
i = 0;
i < type->field_count();
i++) {
2303 names->PrintFieldName(sb, info->type_index(),
i);
2306 switch (type->field(
i).kind()) {
2316 std::string value_string = obj->GetFieldValue(
i).to_string();
2317 const char* value_name =
names_->
GetCopy(value_string.c_str());
2326 case wasm::kRefNull: {
2327 int field_offset = type->field_offset(
i);
2328 Tagged<Object> value = obj->RawField(field_offset).load(isolate);
2333 HeapEntry* value_entry =
GetEntry(value);
2349 const wasm::CanonicalValueType element_type =
2350 obj->map()->wasm_type_info()->element_type();
2351 if (!element_type.is_reference())
return;
2353 ReadOnlyRoots roots(isolate);
2354 for (uint32_t
i = 0;
i < obj->
length();
i++) {
2367void V8HeapExplorer::ExtractWasmTrustedInstanceDataReferences(
2387#define ASSERT_FIRST_FIELD(Class, Field) \
2388 static_assert(Class::Super::kHeaderSize == Class::k##Field##Offset)
2389#define ASSERT_CONSECUTIVE_FIELDS(Class, Field, NextField) \
2390 static_assert(Class::k##Field##OffsetEnd + 1 == Class::k##NextField##Offset)
2391#define ASSERT_LAST_FIELD(Class, Field) \
2392 static_assert(Class::k##Field##OffsetEnd + 1 == Class::kHeaderSize)
2394void V8HeapExplorer::ExtractWasmInstanceObjectReferences(
2398 ASSERT_FIRST_FIELD(WasmInstanceObject, TrustedData);
2401 WasmInstanceObject::kTrustedDataOffset);
2402 ASSERT_CONSECUTIVE_FIELDS(WasmInstanceObject, TrustedData, ModuleObject);
2404 WasmInstanceObject::kModuleObjectOffset);
2405 ASSERT_CONSECUTIVE_FIELDS(WasmInstanceObject, ModuleObject, ExportsObject);
2407 WasmInstanceObject::kExportsObjectOffset);
2408 ASSERT_LAST_FIELD(WasmInstanceObject, ExportsObject);
2411void V8HeapExplorer::ExtractWasmModuleObjectReferences(
2415 ASSERT_FIRST_FIELD(WasmModuleObject, ManagedNativeModule);
2417 module_object->managed_native_module(),
2418 WasmModuleObject::kManagedNativeModuleOffset);
2419 ASSERT_CONSECUTIVE_FIELDS(WasmModuleObject, ManagedNativeModule, Script);
2421 WasmModuleObject::kScriptOffset);
2422 ASSERT_LAST_FIELD(WasmModuleObject, Script);
2425#undef ASSERT_FIRST_FIELD
2426#undef ASSERT_CONSECUTIVE_FIELDS
2427#undef ASSERT_LAST_FIELD
2473#ifdef V8_ENABLE_DIRECT_HANDLE
2476 if (root == Root::kBuiltins) {
2507 if (istream_or_smi_zero !=
Smi::zero()) {
2509 code->IterateDeoptimizationLiterals(
this);
2545 bool interrupted =
false;
2553 if (interrupted)
continue;
2561#ifdef V8_ENABLE_HEAP_SNAPSHOT_VERIFY
2562 std::unique_ptr<HeapEntryVerifier> verifier;
2567 if (
v8_flags.heap_snapshot_verify &&
2569 verifier = std::make_unique<HeapEntryVerifier>(generator, obj);
2609 return !IsOddball(
object, isolate) &&
object != roots.the_hole_value() &&
2610 object != roots.empty_byte_array() &&
2611 object != roots.empty_fixed_array() &&
2612 object != roots.empty_weak_fixed_array() &&
2613 object != roots.empty_descriptor_array() &&
2614 object != roots.fixed_array_map() &&
object != roots.cell_map() &&
2615 object != roots.global_property_cell_map() &&
2616 object != roots.shared_function_info_map() &&
2617 object != roots.free_space_map() &&
2618 object != roots.one_pointer_filler_map() &&
2619 object != roots.two_pointer_filler_map();
2624 if (IsAllocationSite(parent) &&
2627 if (IsContext(parent) &&
2630 if (IsJSFinalizationRegistry(parent) &&
2631 field_offset == JSFinalizationRegistry::kNextDirtyOffset)
2641 if (child_entry ==
nullptr)
return;
2657 const char* reference_name,
2660 if (child_entry ==
nullptr)
return;
2668 if (child_entry ==
nullptr)
return;
2674 const char* reference_name,
2719 HeapEntry* parent_entry,
const char* reference_name,
2734 std::optional<int> field_offset) {
2741 names_->GetFormatted(
"%d", index),
2743 if (field_offset.has_value()) {
2757 name_format_string, field_offset);
2764 const char* name_format_string,
2767 if (child_entry ==
nullptr)
return;
2769 IsSymbol(reference_name) ||
Cast<String>(reference_name)->length() > 0
2772 const char* name = name_format_string !=
nullptr && IsString(reference_name)
2802 if (
IsSmi(child_obj)) {
2810 if (child_entry ==
nullptr)
return;
2815 if (name !=
nullptr) {
2830 if (is_weak || !IsNativeContext(child_heap_obj))
return;
2834 if (!IsJSGlobalObject(global))
return;
2858 std::optional<HeapEntry::Type> type,
2859 bool overwrite_existing_name) {
2862 if (overwrite_existing_name || entry->
name()[0] ==
'\0') {
2865 if (type.has_value()) {
2874 int recursion_limit) {
2876 if (IsFixedArrayExact(obj,
isolate())) {
2879 if (recursion_limit <= 0)
return;
2880 for (
int i = 0;
i < arr->length(); ++
i) {
2883 }
else if (IsTrustedFixedArray(obj,
isolate())) {
2886 if (recursion_limit <= 0)
return;
2887 for (
int i = 0;
i < arr->length(); ++
i) {
2890 }
else if (IsNameDictionary(obj,
isolate()) ||
2891 IsNumberDictionary(obj,
isolate())) {
2914 template <
typename TSlot>
2917 for (TSlot p =
start; p <
end; ++p) {
2920 if (!IsNativeContext(o,
isolate_))
continue;
2922 if (!IsJSGlobalProxy(proxy,
isolate_))
continue;
2924 if (!IsJSGlobalObject(global,
isolate_))
continue;
2941 isolate, [
this, isolate, &global_object_tags](
2945 global_object_tags.emplace_back(
2949 global_object_tags.back().first.SetWeak();
2952 isolate->global_handles()->IterateAllRoots(&enumerator);
2953 isolate->traced_handles()->Iterate(&enumerator);
2954 return global_object_tags;
2960 for (
const auto& pair : global_object_tags) {
2961 if (!pair.first.IsEmpty()) {
3004 DCHECK(!
object.is_null());
3010 nodes_.push_back(std::move(node));
3049 const char* prefix = node->NamePrefix();
3050 return prefix ? names->GetFormatted(
"%s %s", prefix, node->Name())
3051 : names->GetCopy(node->Name());
3062const char* MergeNames(StringsStorage* names,
const char* embedder_name,
3063 const char* wrapper_name) {
3064 const char* suffix = strchr(wrapper_name,
'/');
3065 return suffix ? names->GetFormatted(
"%s %s", embedder_name, suffix)
3074 DCHECK(node->IsEmbedderNode());
3075 size_t size = node->SizeInBytes();
3076 Address lookup_address =
reinterpret_cast<Address>(node->GetNativeObject());
3081 if (!lookup_address) {
3084 lookup_address =
reinterpret_cast<Address>(node->GetAddress());
3087 if (!lookup_address) {
3097 lookup_address, 0, accessed, is_native_object);
3099 EmbedderGraphNodeName(
names_, node),
3100 id,
static_cast<int>(size), 0);
3113 Isolate::FromHeap(snapshot->profiler()->heap_object_map()->
heap())),
3114 snapshot_(snapshot),
3115 names_(snapshot_->profiler()->names()),
3116 heap_object_map_(snapshot_->profiler()->heap_object_map()),
3117 embedder_graph_entries_allocator_(
3142 entry->
set_type(EmbedderGraphNodeType(original_node));
3151 if (node->WrapperNode()) {
3152 node = node->WrapperNode();
3155 if (node->IsEmbedderNode()) {
3162 if (
IsSmi(
object))
return nullptr;
3172 if (
v8_flags.heap_profiler_use_embedder_graph &&
3178 for (
const auto& node : graph.nodes()) {
3181 if (!node->IsEmbedderNode())
continue;
3184 if (node->IsRootNode()) {
3189 if (node->WrapperNode()) {
3195 for (
const auto& edge : graph.edges()) {
3199 if (!from)
continue;
3202 if (edge.name ==
nullptr) {
3222 : snapshot_(snapshot),
3224 v8_heap_explorer_(snapshot_, this, resolver),
3225 dom_explorer_(snapshot_, this),
3227 stack_state_(stack_state) {}
3232 explicit NullContextForSnapshotScope(
Isolate* isolate)
3236 ~NullContextForSnapshotScope() {
isolate_->set_context(
prev_); }
3251 auto temporary_global_object_tags =
3264 NullContextForSnapshotScope null_context_scope(isolate);
3267 std::move(temporary_global_object_tags));
3282 base::OS::PrintError(
"[Heap snapshot took %0.3f ms]\n",
3283 timer.Elapsed().InMillisecondsF());
3293 auto temporary_global_object_tags =
3295 NullContextForSnapshotScope null_context_scope(
heap_->
isolate());
3297 std::move(temporary_global_object_tags));
3321 const int kProgressReportGranularity = 10000;
3354 static_cast<uint32_t
>(tracker->function_info_list().
size());
3361 base::OS::PrintError(
"[Serialization of heap snapshot took %0.3f ms]\n",
3362 timer.Elapsed().InMillisecondsF());
3413 if (cache_entry->
value ==
nullptr) {
3416 return static_cast<int>(
reinterpret_cast<intptr_t
>(cache_entry->
value));
3437 for (
size_t i = 0;
i < edges.size(); ++
i) {
3482#define JSON_A(s) "[" s "]"
3483#define JSON_S(s) "\"" s "\""
3485 JSON_S(
"node_fields")
":["
3490 JSON_S(
"edge_count")
",");
3507 JSON_S(
"concatenated string")
","
3508 JSON_S(
"sliced string")
","
3511 JSON_S(
"object shape"))
","
3520 JSON_S(
"name_or_index")
","
3531 JSON_S(
"string_or_number")
","
3534 JSON_S(
"function_id")
","
3536 JSON_S(
"script_name")
","
3542 JSON_S(
"function_info_index")
","
3547 JSON_S(
"timestamp_us")
","
3548 JSON_S(
"last_assigned_id"))
","
3550 JSON_S(
"object_index")
","
3569 static const char hex_chars[] =
"0123456789ABCDEF";
3579 if (!tracker)
return;
3606 if (!tracker)
return;
3628 const std::vector<HeapObjectsMap::TimeInterval>& samples =
3630 if (samples.empty())
return;
3646 for (; *s !=
'\0'; ++
s) {
3669 if (*s > 31 && *s < 128) {
3671 }
else if (*s <= 31) {
3676 size_t length = 1, cursor = 0;
3677 for (; length <= 4 && *(s +
length) !=
'\0'; ++
length) {
3698 int index =
static_cast<int>(
reinterpret_cast<uintptr_t
>(entry->value));
3699 sorted_strings[
index] =
reinterpret_cast<const unsigned char*
>(entry->key);
3702 for (
int i = 1;
i < sorted_strings.
length(); ++
i) {
3722 for (
size_t i = 0;
i < locations.size();
i++) {
#define DISALLOW_GARBAGE_COLLECTION(name)
static const uchar kBadChar
static uchar CalculateValue(const uint8_t *str, size_t length, size_t *cursor)
virtual ControlOption ReportProgressValue(uint32_t done, uint32_t total)=0
virtual Detachedness GetDetachedness()
virtual size_t SizeInBytes()=0
virtual bool IsEmbedderNode()
virtual NativeObject GetNativeObject()
virtual const char * GetName(Local< Object > object)=0
static const SnapshotObjectId kUnknownObjectId
virtual WriteResult WriteHeapStatsChunk(HeapStatsUpdate *data, int count)
virtual void EndOfStream()=0
virtual int GetChunkSize()
static constexpr size_t kDefaultMemoryEstimate
virtual void EstimateSharedMemoryUsage(SharedMemoryUsageRecorder *recorder) const
virtual size_t EstimateMemoryUsage() const
static v8::internal::DirectHandle< To > OpenDirectHandle(v8::Local< From > handle)
static v8::internal::Handle< v8::internal::Object > OpenPersistent(const v8::PersistentBase< T > &persistent)
Entry * Next(Entry *entry) const
uint32_t occupancy() const
Entry * LookupOrInsert(const Key &key, uint32_t hash)
Value Remove(const Key &key, uint32_t hash)
Entry * Lookup(const Key &key, uint32_t hash) const
int64_t InMicroseconds() const
constexpr T * begin() const
const std::vector< AllocationTraceNode * > & children() const
AllocationTraceTree * trace_tree()
const std::vector< FunctionInfo * > & function_info_list() const
Tagged< HeapObject > Next()
static V8_INLINE constexpr int OffsetOfElementAt(int index)
static constexpr int kTaggedPayloadOffset
HeapEntry * AllocateEntry(HeapThing ptr) override
EmbedderGraphEntriesAllocator(HeapSnapshot *snapshot)
HeapObjectsMap * heap_object_map_
Tagged< Object > GetObject()
bool IsEmbedderNode() override
const char * Name() override
size_t SizeInBytes() override
V8NodeImpl(Tagged< Object > object)
size_t native_size() const
void AddNativeSize(size_t size) final
Node * V8Node(const v8::Local< v8::Data > &data) final
std::vector< std::unique_ptr< Node > > nodes_
void AddEdge(Node *from, Node *to, const char *name) final
const std::vector< Edge > & edges()
std::vector< Edge > edges_
const std::vector< std::unique_ptr< Node > > & nodes()
Node * AddNode(std::unique_ptr< Node > node) final
Node * V8Node(const v8::Local< v8::Value > &value) final
static FieldIndex ForDetails(Tagged< Map > map, PropertyDetails details)
GlobalObjectsEnumerator(Isolate *isolate, std::function< void(Handle< JSGlobalObject >)> handler)
std::function< void(Handle< JSGlobalObject >)> handler_
void VisitRootPointers(Root root, const char *description, FullObjectSlot start, FullObjectSlot end) override
void VisitRootPointers(Root root, const char *description, OffHeapObjectSlot start, OffHeapObjectSlot end) override
void VisitRootPointersImpl(Root root, const char *description, TSlot start, TSlot end)
V8_INLINE std::vector< HeapGraphEdge * >::iterator children_end() const
void set_detachedness(v8::EmbedderGraph::Node::Detachedness value)
V8_EXPORT_PRIVATE void Print(const char *prefix, const char *edge_name, int max_depth, int indent) const
void SetIndexedAutoIndexReference(HeapGraphEdge::Type type, HeapEntry *child, HeapSnapshotGenerator *generator, ReferenceVerification verification=kVerify)
HeapEntry(HeapSnapshot *snapshot, int index, Type type, const char *name, SnapshotObjectId id, size_t self_size, unsigned trace_node_id)
const char * TypeAsString() const
uint8_t detachedness() const
SnapshotObjectId id() const
void VerifyReference(HeapGraphEdge::Type type, HeapEntry *entry, HeapSnapshotGenerator *generator, ReferenceVerification verification)
void SetNamedAutoIndexReference(HeapGraphEdge::Type type, const char *description, HeapEntry *child, StringsStorage *strings, HeapSnapshotGenerator *generator, ReferenceVerification verification=kVerify)
void SetIndexedReference(HeapGraphEdge::Type type, int index, HeapEntry *entry, HeapSnapshotGenerator *generator, ReferenceVerification verification=kVerify)
V8_INLINE std::vector< HeapGraphEdge * >::iterator children_begin() const
unsigned trace_node_id() const
void set_name(const char *name)
V8_INLINE HeapGraphEdge * child(int i)
void add_self_size(size_t size)
const char * name() const
void SetNamedReference(HeapGraphEdge::Type type, const char *name, HeapEntry *entry, HeapSnapshotGenerator *generator, ReferenceVerification verification=kVerify)
V8_INLINE int children_count() const
HeapGraphEdge(Type type, const char *name, HeapEntry *from, HeapEntry *to)
const char * name() const
static V8_INLINE bool InTrustedSpace(Tagged< HeapObject > object)
static V8_INLINE bool InReadOnlySpace(Tagged< HeapObject > object)
static V8_INLINE bool InCodeSpace(Tagged< HeapObject > object)
static constexpr int kMapOffset
static const SnapshotObjectId kFirstAvailableObjectId
static const SnapshotObjectId kInternalRootObjectId
static const int kObjectIdStep
static const SnapshotObjectId kGcRootsFirstSubrootId
void UpdateObjectSize(Address addr, int size)
SnapshotObjectId FindOrAddEntry(Address addr, unsigned int size, MarkEntryAccessed accessed=MarkEntryAccessed::kYes, IsNativeObject is_native_object=IsNativeObject::kNo)
bool MoveObject(Address from, Address to, int size)
SnapshotObjectId last_assigned_id() const
const std::vector< TimeInterval > & samples() const
SnapshotObjectId FindMergedNativeEntry(NativeObject addr)
SnapshotObjectId get_next_native_id()
void StopHeapObjectsTracking()
SnapshotObjectId get_next_id()
SnapshotObjectId PushHeapObjectsStats(OutputStream *stream, int64_t *timestamp_us)
static const SnapshotObjectId kFirstAvailableNativeId
SnapshotObjectId next_id_
SnapshotObjectId FindEntry(Address addr)
static const SnapshotObjectId kGcRootsObjectId
std::unordered_map< NativeObject, size_t > merged_native_entries_map_
void AddMergedNativeEntry(NativeObject addr, Address canonical_addr)
HeapObjectsMap(Heap *heap)
std::vector< EntryInfo > entries_
void UpdateHeapObjectsMap()
std::vector< TimeInterval > time_intervals_
base::HashMap entries_map_
HeapObjectsMap * heap_object_map() const
bool HasBuildEmbedderGraphCallback()
void RemoveSnapshot(HeapSnapshot *snapshot)
AllocationTracker * allocation_tracker() const
void BuildEmbedderGraph(Isolate *isolate, v8::EmbedderGraph *graph)
bool GenerateSnapshotAfterGC()
NativeObjectsExplorer dom_explorer_
void InitProgressCounter()
bool ProgressReport(bool force=false) override
HeapEntry * FindOrAddEntry(HeapThing ptr, HeapEntriesAllocator *allocator)
cppgc::EmbedderStackState stack_state_
uint32_t progress_counter_
HeapEntry * FindEntry(HeapThing ptr)
HeapSnapshotGenerator(HeapSnapshot *snapshot, v8::ActivityControl *control, v8::HeapProfiler::ObjectNameResolver *resolver, Heap *heap, cppgc::EmbedderStackState stack_state)
V8HeapExplorer v8_heap_explorer_
void ProgressStep() override
v8::ActivityControl * control_
void SerializeTraceNode(AllocationTraceNode *node)
static const int kNodeFieldsCountWithTraceNodeId
void Serialize(v8::OutputStream *stream)
void SerializeTraceNodeInfos()
void SerializeTraceTree()
static V8_INLINE uint32_t StringHash(const void *string)
void SerializeLocation(const EntrySourceLocation &location)
void SerializeEdge(HeapGraphEdge *edge, bool first_edge)
void SerializeNode(const HeapEntry *entry)
V8_INLINE int to_node_index(const HeapEntry *e)
OutputStreamWriter * writer_
void SerializeLocations()
void SerializeString(const unsigned char *s)
uint32_t trace_function_count_
int GetStringId(const char *s)
static const int kNodeFieldsCountWithoutTraceNodeId
base::CustomMatcherHashMap strings_
HeapSnapshot(HeapProfiler *profiler, v8::HeapProfiler::HeapSnapshotMode snapshot_mode, v8::HeapProfiler::NumericsMode numerics_mode)
void AddSyntheticRootEntries()
void AddScriptLineEnds(int script_id, String::LineEndsVector &&line_ends)
std::deque< HeapEntry > & entries()
String::LineEndsVector & GetScriptLineEnds(int script_id)
SnapshotObjectId max_snapshot_js_object_id_
size_t extra_native_bytes() const
void Print(int max_depth)
std::deque< HeapEntry > entries_
void RememberLastJSObjectId()
HeapEntry * gc_roots() const
void AddLocation(HeapEntry *entry, int scriptId, int line, int col)
HeapEntry * AddEntry(HeapEntry::Type type, const char *name, SnapshotObjectId id, size_t size, unsigned trace_node_id)
HeapProfiler * profiler() const
std::vector< EntrySourceLocation > locations_
std::deque< HeapGraphEdge > & edges()
void set_extra_native_bytes(size_t bytes)
HeapEntry * GetEntryById(SnapshotObjectId id)
std::unordered_map< SnapshotObjectId, HeapEntry * > entries_by_id_cache_
const std::vector< EntrySourceLocation > & locations() const
HeapEntry * gc_subroot_entries_[static_cast< int >(Root::kNumberOfRoots)]
ScriptsLineEndsMap scripts_line_ends_map_
HeapEntry * gc_roots_entry_
void AddGcSubrootEntry(Root root, SnapshotObjectId id)
bool expose_internals() const
HeapEntry * gc_subroot(Root root) const
bool capture_numeric_value() const
std::vector< HeapGraphEdge * > & children()
V8_EXPORT_PRIVATE void PreciseCollectAllGarbage(GCFlags gc_flags, GarbageCollectionReason gc_reason, const GCCallbackFlags gc_callback_flags=kNoGCCallbackFlags)
V8_EXPORT_PRIVATE void CollectAllAvailableGarbage(GarbageCollectionReason gc_reason)
void IterateWeakRoots(RootVisitor *v, base::EnumSet< SkipRoot > options)
void IterateRoots(RootVisitor *v, base::EnumSet< SkipRoot > options, IterateRootsMode roots_mode=IterateRootsMode::kMainIsolate)
void IterateWeakGlobalHandles(RootVisitor *v)
Isolate * isolate() const
static Tagged< InstructionStream > FromTargetAddress(Address address)
static Isolate * FromHeap(const Heap *heap)
bool MayHaveEmbedderFields() const
int GetEmbedderFieldsStartOffset()
int GetEmbedderFieldCount() const
static MaybeDirectHandle< JSFunction > GetConstructor(Isolate *isolate, DirectHandle< JSReceiver > receiver)
static DirectHandle< String > GetConstructorName(Isolate *isolate, DirectHandle< JSReceiver > receiver)
static constexpr bool IsPacked(Address)
V8_INLINE DirectHandle< T > ToHandleChecked() const
V8_INLINE bool is_null() const
static V8_INLINE MemoryChunk * FromHeapObject(Tagged< HeapObject > object)
V8_INLINE bool InReadOnlySpace() const
HeapSnapshotGenerator * generator_
HeapEntry * EntryForEmbedderGraphNode(EmbedderGraph::Node *node)
bool IterateAndExtractReferences(HeapSnapshotGenerator *generator)
NativeObjectsExplorer(HeapSnapshot *snapshot, SnapshottingProgressReportingInterface *progress)
HeapObjectsMap * heap_object_map_
void MergeNodeIntoEntry(HeapEntry *entry, EmbedderGraph::Node *original_node, EmbedderGraph::Node *wrapper_node)
std::unique_ptr< HeapEntriesAllocator > embedder_graph_entries_allocator_
PtrComprCageBase code_cage_base() const
PtrComprCageBase cage_base() const
static double NumberValue(Tagged< Number > obj)
void AddString(const char *s)
void AddCharacter(char c)
PropertyLocation location() const
Representation representation() const
PropertyKind kind() const
Tagged< T > GetCurrent() const
void Iterate(RootVisitor *visitor)
V8_INLINE Address target_address()
V8_INLINE Tagged< HeapObject > target_object(PtrComprCageBase cage_base)
static const char * RootName(Root root)
static const char * name(RootIndex root_index)
static LocalNamesRange< DirectHandle< ScopeInfo > > IterateLocalNames(DirectHandle< ScopeInfo > scope_info)
static V8_EXPORT_PRIVATE String::LineEndsVector GetLineEnds(Isolate *isolate, DirectHandle< Script > script)
static constexpr int ToInt(const Tagged< Object > object)
static constexpr Tagged< Smi > zero()
virtual bool ProgressReport(bool force)=0
virtual void ProgressStep()=0
const char * GetCopy(const char *src)
const char * GetName(Tagged< Name > name)
static constexpr int OffsetOfElementAt(int index)
static PtrType load(Tagged< HeapObject > host, int offset=0)
V8_INLINE constexpr StorageType ptr() const
bool GetHeapObjectIfStrong(Tagged< HeapObject > *result) const
bool GetHeapObjectIfWeak(Tagged< HeapObject > *result) const
V8_INLINE constexpr bool is_null() const
void ExtractJSWeakCollectionReferences(HeapEntry *entry, Tagged< JSWeakCollection > collection)
void ExtractEphemeronHashTableReferences(HeapEntry *entry, Tagged< EphemeronHashTable > table)
const char * GetSystemEntryName(Tagged< HeapObject > object)
std::vector< bool > visited_fields_
void ExtractPropertyReferences(Tagged< JSObject > js_obj, HeapEntry *entry)
void ExtractInstructionStreamReferences(HeapEntry *entry, Tagged< InstructionStream > code)
HeapObjectsMap * heap_object_map_
void SetInternalReference(HeapEntry *parent_entry, const char *reference_name, Tagged< Object > child, int field_offset=-1)
void SetPropertyReference(HeapEntry *parent_entry, Tagged< Name > reference_name, Tagged< Object > child, const char *name_format_string=nullptr, int field_offset=-1)
void RecursivelyTagConstantPool(Tagged< Object > obj, const char *tag, HeapEntry::Type type, int recursion_limit)
void ExtractDescriptorArrayReferences(HeapEntry *entry, Tagged< DescriptorArray > array)
void SetGcSubrootReference(Root root, const char *description, bool is_weak, Tagged< Object > child)
void SetElementReference(HeapEntry *parent_entry, int index, Tagged< Object > child)
HeapEntry::Type GetSystemEntryType(Tagged< HeapObject > object)
void MakeGlobalObjectTagMap(TemporaryGlobalObjectTags &&)
V8HeapExplorer(HeapSnapshot *snapshot, SnapshottingProgressReportingInterface *progress, v8::HeapProfiler::ObjectNameResolver *resolver)
void ExtractAccessorPairProperty(HeapEntry *entry, Tagged< Name > key, Tagged< Object > callback_obj, int field_offset=-1)
uint32_t EstimateObjectsCount()
SnapshottingProgressReportingInterface * progress_
void ExtractJSCollectionReferences(HeapEntry *entry, Tagged< JSCollection > collection)
void MarkVisitedField(int offset)
void ExtractAccessorInfoReferences(HeapEntry *entry, Tagged< AccessorInfo > accessor_info)
void ExtractEnumCacheReferences(HeapEntry *entry, Tagged< EnumCache > cache)
void ExtractJSPromiseReferences(HeapEntry *entry, Tagged< JSPromise > promise)
void ExtractAllocationSiteReferences(HeapEntry *entry, Tagged< AllocationSite > site)
static Tagged< JSFunction > GetConstructor(Isolate *isolate, Tagged< JSReceiver > receiver)
void ExtractBytecodeArrayReferences(HeapEntry *entry, Tagged< BytecodeArray > bytecode)
HeapEntry * AllocateEntry(HeapThing ptr) override
void ExtractPropertyCellReferences(HeapEntry *entry, Tagged< PropertyCell > cell)
std::unordered_set< Tagged< JSGlobalObject >, Object::Hasher > user_roots_
void ExtractSymbolReferences(HeapEntry *entry, Tagged< Symbol > symbol)
void ExtractJSGlobalProxyReferences(HeapEntry *entry, Tagged< JSGlobalProxy > proxy)
void ExtractScriptReferences(HeapEntry *entry, Tagged< Script > script)
static Tagged< String > GetConstructorName(Isolate *isolate, Tagged< JSObject > object)
void ExtractStringReferences(HeapEntry *entry, Tagged< String > obj)
void ExtractFeedbackVectorReferences(HeapEntry *entry, Tagged< FeedbackVector > feedback_vector)
void SetDataOrAccessorPropertyReference(PropertyKind kind, HeapEntry *parent_entry, Tagged< Name > reference_name, Tagged< Object > child, const char *name_format_string=nullptr, int field_offset=-1)
void ExtractJSWeakRefReferences(HeapEntry *entry, Tagged< JSWeakRef > js_weak_ref)
void ExtractContextReferences(HeapEntry *entry, Tagged< Context > context)
v8::HeapProfiler::ObjectNameResolver * global_object_name_resolver_
void ExtractNumberReference(HeapEntry *entry, Tagged< Object > number)
void ExtractJSObjectReferences(HeapEntry *entry, Tagged< JSObject > js_obj)
void SetRootGcRootsReference()
HeapEntry * GetEntry(Tagged< Object > obj)
V8_INLINE Isolate * isolate()
void ExtractJSArrayBufferReferences(HeapEntry *entry, Tagged< JSArrayBuffer > buffer)
void ExtractCodeReferences(HeapEntry *entry, Tagged< Code > code)
void SetHiddenReference(Tagged< HeapObject > parent_obj, HeapEntry *parent_entry, int index, Tagged< Object > child, int field_offset)
bool IsEssentialHiddenReference(Tagged< Object > parent, int field_offset)
TemporaryGlobalObjectTags CollectTemporaryGlobalObjectsTags()
void SetNativeBindReference(HeapEntry *parent_entry, const char *reference_name, Tagged< Object > child)
void ExtractTransitionArrayReferences(HeapEntry *entry, Tagged< TransitionArray > transitions)
void ExtractRegExpBoilerplateDescriptionReferences(HeapEntry *entry, Tagged< RegExpBoilerplateDescription > value)
void SetUserGlobalReference(Tagged< Object > user_global)
void ExtractScopeInfoReferences(HeapEntry *entry, Tagged< ScopeInfo > info)
UnorderedHeapObjectMap< const char * > strong_gc_subroot_names_
std::unordered_map< Tagged< JSGlobalObject >, const char *, Object::Hasher > global_object_tag_map_
const char * GetStrongGcSubrootName(Tagged< HeapObject > object)
void ExtractPrototypeInfoReferences(HeapEntry *entry, Tagged< PrototypeInfo > info)
void ExtractLocation(HeapEntry *entry, Tagged< HeapObject > object)
std::vector< std::pair< v8::Global< v8::Object >, const char * > > TemporaryGlobalObjectTags
void ExtractWeakCellReferences(HeapEntry *entry, Tagged< WeakCell > weak_cell)
void ExtractCellReferences(HeapEntry *entry, Tagged< Cell > cell)
void ExtractLocationForJSFunction(HeapEntry *entry, Tagged< JSFunction > func)
void ExtractFixedArrayReferences(HeapEntry *entry, Tagged< FixedArray > array)
void ExtractMapReferences(HeapEntry *entry, Tagged< Map > map)
HeapEntry * AddEntry(Address address, HeapEntry::Type type, const char *name, size_t size)
bool IsEssentialObject(Tagged< Object > object)
void ExtractInternalReferences(Tagged< JSObject > js_obj, HeapEntry *entry)
void TagBuiltinCodeObject(Tagged< Code > code, const char *name)
void ExtractArrayBoilerplateDescriptionReferences(HeapEntry *entry, Tagged< ArrayBoilerplateDescription > value)
void SetGcRootsReference(Root root)
void SetWeakReference(HeapEntry *parent_entry, const char *reference_name, Tagged< Object > child_obj, int field_offset, HeapEntry::ReferenceVerification verification=HeapEntry::kVerify)
void ExtractFeedbackCellReferences(HeapEntry *entry, Tagged< FeedbackCell > feedback_cell)
void ExtractElementReferences(Tagged< JSObject > js_obj, HeapEntry *entry)
void TagObject(Tagged< Object > obj, const char *tag, std::optional< HeapEntry::Type > type={}, bool overwrite_existing_name=false)
void ExtractWeakArrayReferences(int header_size, HeapEntry *entry, Tagged< T > array)
void SetContextReference(HeapEntry *parent_entry, Tagged< String > reference_name, Tagged< Object > child, int field_offset)
void ExtractAccessorPairReferences(HeapEntry *entry, Tagged< AccessorPair > accessors)
void ExtractJSGeneratorObjectReferences(HeapEntry *entry, Tagged< JSGeneratorObject > generator)
Tagged< JSFunction > GetLocationFunction(Tagged< HeapObject > object)
void ExtractSharedFunctionInfoReferences(HeapEntry *entry, Tagged< SharedFunctionInfo > shared)
HeapSnapshotGenerator * generator_
void ExtractReferences(HeapEntry *entry, Tagged< HeapObject > obj)
bool IterateAndExtractReferences(HeapSnapshotGenerator *generator)
static constexpr std::array< const char *, 6 > kProtectedFieldNames
static constexpr std::array< uint16_t, 6 > kProtectedFieldOffsets
static constexpr std::array< const char *, kTaggedFieldsCount > kTaggedFieldNames
static constexpr std::array< uint16_t, kTaggedFieldsCount > kTaggedFieldOffsets
void PrintTypeName(StringBuilder &out, CanonicalTypeIndex type_index, NamesProvider::IndexAsComment index_as_comment=NamesProvider::kDontPrintIndex)
const char * start() const
V8_EXPORT_PRIVATE const CanonicalStructType * LookupStruct(CanonicalTypeIndex index) const
#define V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL
#define NATIVE_CONTEXT_FIELDS(V)
Handle< SharedFunctionInfo > info
#define CONTEXT_FIELD_INDEX_NAME(index, _, name)
V8HeapExplorer * explorer_
#define MAKE_TORQUE_CASE(Name, TYPE)
#define MAKE_STRING_CASE(instance_type, size, name, Name)
#define MAKE_STRING_MAP_CASE(instance_type, size, name, Name)
std::unique_ptr< icu::DateTimePatternGenerator > generator_
ZoneVector< RpoNumber > & result
ZoneVector< Entry > entries
constexpr Vector< T > ArrayVector(T(&arr)[N])
constexpr bool IsInRange(T value, U lower_limit, U higher_limit)
V8_INLINE constexpr bool IsExternalString(InstanceType instance_type)
TypeCanonicalizer * GetTypeCanonicalizer()
CanonicalTypeNamesProvider * GetCanonicalTypeNamesProvider()
V8_INLINE IndirectHandle< T > handle(Tagged< T > object, Isolate *isolate)
static V8_INLINE bool HasWeakHeapObjectTag(const Tagged< Object > value)
static void WriteUChar(OutputStreamWriter *w, unibrow::uchar u)
constexpr int kTaggedSize
constexpr Address kTaggedNullAddress
bool IsNumber(Tagged< Object > obj)
ReadOnlyRoots GetReadOnlyRoots()
void PrintF(const char *format,...)
const char * CodeKindToString(CodeKind kind)
Tagged(T object) -> Tagged< T >
V8_INLINE constexpr bool IsSmi(TaggedImpl< kRefType, StorageType > obj)
std::string_view IntToStringView(int n, base::Vector< char > buffer)
kInterpreterTrampolineOffset Tagged< HeapObject >
void VisitObject(Isolate *isolate, Tagged< HeapObject > object, ObjectVisitor *visitor)
V8_INLINE DirectHandle< T > direct_handle(Tagged< T > object, Isolate *isolate)
too high values may cause the compiler to set high thresholds for inlining to as much as possible avoid inlined allocation of objects that cannot escape trace load stores from virtual maglev objects use TurboFan fast string builder analyze liveness of environment slots and zap dead values trace TurboFan load elimination emit data about basic block usage in builtins to this enable builtin reordering when run mksnapshot flag for emit warnings when applying builtin profile data verify register allocation in TurboFan randomly schedule instructions to stress dependency tracking enable store store elimination in TurboFan rewrite far to near simulate GC compiler thread race related to allow float parameters to be passed in simulator mode JS Wasm Run additional turbo_optimize_inlined_js_wasm_wrappers enable experimental feedback collection in generic lowering enable Turboshaft s WasmLoadElimination enable Turboshaft s low level load elimination for JS enable Turboshaft s escape analysis for string concatenation use enable Turbolev features that we want to ship in the not too far future trace individual Turboshaft reduction steps trace intermediate Turboshaft reduction steps invocation count threshold for early optimization Enables optimizations which favor memory size over execution speed Enables sampling allocation profiler with X as a sample interval min size of a semi the new space consists of two semi spaces max size of the Collect garbage after Collect garbage after keeps maps alive for< n > old space garbage collections print one detailed trace line in name
kMemory0SizeOffset Address kNewAllocationLimitAddressOffset Address kOldAllocationLimitAddressOffset uint8_t kGlobalsStartOffset kJumpTableStartOffset std::atomic< uint32_t > kTieringBudgetArrayOffset kDataSegmentStartsOffset kElementSegmentsOffset Tagged< WasmInstanceObject >
Handle< To > UncheckedCast(Handle< From > value)
constexpr int kSystemPointerSize
static const struct v8::internal::@145 native_context_names[]
constexpr ExternalPointerTagRange kAnyManagedExternalPointerTagRange(kFirstManagedExternalPointerTag, kLastManagedExternalPointerTag)
@ kIcuSimpleDateFormatTag
@ kIcuLocalizedNumberFormatterTag
@ kDisplayNamesInternalTag
@ kIcuRelativeDateTimeFormatterTag
@ kIcuDateIntervalFormatTag
V8_INLINE constexpr bool IsHeapObject(TaggedImpl< kRefType, StorageType > obj)
V8_EXPORT_PRIVATE FlagValues v8_flags
std::string_view DoubleToStringView(double v, base::Vector< char > buffer)
static constexpr Address kNullAddress
SlotTraits::TMaybeObjectSlot MaybeObjectSlot
kMemory0SizeOffset Address kNewAllocationLimitAddressOffset Address kOldAllocationLimitAddressOffset uint8_t kGlobalsStartOffset kJumpTableStartOffset std::atomic< uint32_t > kTieringBudgetArrayOffset kDataSegmentStartsOffset kElementSegmentsOffset instance_object
constructor_or_back_pointer
@ kFirstStrongOrReadOnlyRoot
@ kLastStrongOrReadOnlyRoot
template const char * string
uint32_t ComputeAddressHash(Address address)
!IsContextMap !IsContextMap native_context
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
static constexpr RelaxedLoadTag kRelaxedLoad
uint32_t SnapshotObjectId
static constexpr AcquireLoadTag kAcquireLoad
#define STRING_TYPE_LIST(V)
Tagged< HeapObject > primary_object_
BytecodeSequenceNode * parent_
#define DCHECK_LE(v1, v2)
#define CHECK_GE(lhs, rhs)
#define CHECK_LE(lhs, rhs)
#define DCHECK_NOT_NULL(val)
#define DCHECK_NE(v1, v2)
#define CHECK_NE(lhs, rhs)
#define DCHECK_GE(v1, v2)
#define CHECK_EQ(lhs, rhs)
#define DCHECK(condition)
#define DCHECK_LT(v1, v2)
#define DCHECK_EQ(v1, v2)
constexpr bool Contains(Tag tag) const
#define OFFSET_OF_DATA_START(Type)