From 4724f988aede98a5f9f2c1f60f8956acb71c388a Mon Sep 17 00:00:00 2001 From: Jakob Kummerow Date: Thu, 19 Jan 2023 16:01:06 +0100 Subject: [PATCH] [profiler] Support WasmGC objects in heap snapshots Since the heap snapshot generator is based on generic objects-visiting infrastructure, it already reported all objects, but it showed WasmGC objects as generic "system" objects. This patch adds proper categorization, including support for named types and fields. Bug: v8:7748 Change-Id: I1b0997059c9cf0290fe5d6c5402412ba09ecf143 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4181031 Auto-Submit: Jakob Kummerow Commit-Queue: Camillo Bruni Reviewed-by: Camillo Bruni Cr-Commit-Position: refs/heads/main@{#85435} --- include/v8-profiler.h | 1 + src/profiler/heap-snapshot-generator.cc | 67 ++++++++++++++++++++++++- src/profiler/heap-snapshot-generator.h | 10 +++- 3 files changed, 76 insertions(+), 2 deletions(-) diff --git a/include/v8-profiler.h b/include/v8-profiler.h index 6b73fc60bf..d394151221 100644 --- a/include/v8-profiler.h +++ b/include/v8-profiler.h @@ -596,6 +596,7 @@ class V8_EXPORT HeapGraphNode { kBigInt = 13, // BigInt. kObjectShape = 14, // Internal data used for tracking the shapes (or // "hidden classes") of JS objects. + kWasmObject = 15, // A WasmGC struct or array. }; /** Returns node type (see HeapGraphNode::Type). */ diff --git a/src/profiler/heap-snapshot-generator.cc b/src/profiler/heap-snapshot-generator.cc index f0b3058388..2c4588c43b 100644 --- a/src/profiler/heap-snapshot-generator.cc +++ b/src/profiler/heap-snapshot-generator.cc @@ -41,6 +41,12 @@ #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 // V8_ENABLE_WEBASSEMBLY + namespace v8 { namespace internal { @@ -385,6 +391,8 @@ const char* HeapEntry::TypeAsString() const { return "/bigint/"; case kObjectShape: return "/object shape/"; + case kWasmObject: + return "/wasm object/"; default: return "???"; } } @@ -873,6 +881,23 @@ HeapEntry* V8HeapExplorer::AddEntry(HeapObject object) { } else if (InstanceTypeChecker::IsHeapNumber(instance_type)) { return AddEntry(object, HeapEntry::kHeapNumber, "heap number"); } +#if V8_ENABLE_WEBASSEMBLY + if (InstanceTypeChecker::IsWasmObject(instance_type)) { + WasmTypeInfo info = object.map().wasm_type_info(); + wasm::NamesProvider* names = + info.instance().module_object().native_module()->GetNamesProvider(); + wasm::StringBuilder sb; + if (InstanceTypeChecker::IsWasmStruct(instance_type)) { + sb << "wasm struct / "; + } else { + sb << "wasm array / "; + } + names->PrintTypeName(sb, info.type_index()); + sb << '\0'; + const char* name = names_->GetCopy(sb.start()); + return AddEntry(object, HeapEntry::kWasmObject, name); + } +#endif // V8_ENABLE_WEBASSEMBLY return AddEntry(object, GetSystemEntryType(object), GetSystemEntryName(object)); } @@ -1192,6 +1217,12 @@ void V8HeapExplorer::ExtractReferences(HeapEntry* entry, HeapObject obj) { ExtractBytecodeArrayReferences(entry, BytecodeArray::cast(obj)); } else if (obj.IsScopeInfo()) { ExtractScopeInfoReferences(entry, ScopeInfo::cast(obj)); +#if V8_ENABLE_WEBASSEMBLY + } else if (obj.IsWasmStruct()) { + ExtractWasmStructReferences(WasmStruct::cast(obj), entry); + } else if (obj.IsWasmArray()) { + ExtractWasmArrayReferences(WasmArray::cast(obj), entry); +#endif // V8_ENABLE_WEBASSEMBLY } } @@ -1936,6 +1967,39 @@ void V8HeapExplorer::ExtractInternalReferences(JSObject js_obj, } } +#if V8_ENABLE_WEBASSEMBLY + +void V8HeapExplorer::ExtractWasmStructReferences(WasmStruct obj, + HeapEntry* entry) { + wasm::StructType* type = obj.type(); + WasmTypeInfo info = obj.map().wasm_type_info(); + wasm::NamesProvider* names = + info.instance().module_object().native_module()->GetNamesProvider(); + for (uint32_t i = 0; i < type->field_count(); i++) { + if (!type->field(i).is_reference()) continue; + wasm::StringBuilder sb; + names->PrintFieldName(sb, info.type_index(), i); + sb << '\0'; + const char* field_name = names_->GetCopy(sb.start()); + int field_offset = type->field_offset(i); + Object value = obj.RawField(field_offset).load(entry->isolate()); + HeapEntry* value_entry = GetEntry(value); + entry->SetNamedReference(HeapGraphEdge::kProperty, field_name, value_entry, + generator_); + MarkVisitedField(WasmStruct::kHeaderSize + field_offset); + } +} +void V8HeapExplorer::ExtractWasmArrayReferences(WasmArray obj, + HeapEntry* entry) { + if (!obj.type()->element_type().is_reference()) return; + for (uint32_t i = 0; i < obj.length(); i++) { + SetElementReference(entry, i, obj.ElementSlot(i).load(entry->isolate())); + MarkVisitedField(obj.element_offset(i)); + } +} + +#endif // V8_ENABLE_WEBASSEMBLY + JSFunction V8HeapExplorer::GetConstructor(Isolate* isolate, JSReceiver receiver) { DisallowGarbageCollection no_gc; @@ -3001,7 +3065,8 @@ void HeapSnapshotJSONSerializer::SerializeSnapshot() { JSON_S("sliced string") "," JSON_S("symbol") "," JSON_S("bigint") "," - JSON_S("object shape")) "," + JSON_S("object shape") "," + JSON_S("wasm object")) "," JSON_S("string") "," JSON_S("number") "," JSON_S("number") "," diff --git a/src/profiler/heap-snapshot-generator.h b/src/profiler/heap-snapshot-generator.h index 111839e562..d8f6628f1d 100644 --- a/src/profiler/heap-snapshot-generator.h +++ b/src/profiler/heap-snapshot-generator.h @@ -120,6 +120,8 @@ class HeapEntry { kSymbol = v8::HeapGraphNode::kSymbol, kBigInt = v8::HeapGraphNode::kBigInt, kObjectShape = v8::HeapGraphNode::kObjectShape, + kWasmObject = v8::HeapGraphNode::kWasmObject, + kNumTypes, }; HeapEntry(HeapSnapshot* snapshot, int index, Type type, const char* name, @@ -189,7 +191,8 @@ class HeapEntry { V8_INLINE std::vector::iterator children_end() const; const char* TypeAsString() const; - unsigned type_: 4; + static_assert(kNumTypes <= 1 << 4); + unsigned type_ : 4; unsigned index_ : 28; // Supports up to ~250M objects. union { // The count is used during the snapshot build phase, @@ -466,6 +469,11 @@ class V8_EXPORT_PRIVATE V8HeapExplorer : public HeapEntriesAllocator { void ExtractElementReferences(JSObject js_obj, HeapEntry* entry); void ExtractInternalReferences(JSObject js_obj, HeapEntry* entry); +#if V8_ENABLE_WEBASSEMBLY + void ExtractWasmStructReferences(WasmStruct obj, HeapEntry* entry); + void ExtractWasmArrayReferences(WasmArray obj, HeapEntry* entry); +#endif // V8_ENABLE_WEBASSEMBLY + bool IsEssentialObject(Object object); bool IsEssentialHiddenReference(Object parent, int field_offset);