[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 <jkummerow@chromium.org>
Commit-Queue: Camillo Bruni <cbruni@chromium.org>
Reviewed-by: Camillo Bruni <cbruni@chromium.org>
Cr-Commit-Position: refs/heads/main@{#85435}
This commit is contained in:
Jakob Kummerow 2023-01-19 16:01:06 +01:00 committed by V8 LUCI CQ
parent 186068ad3f
commit 4724f988ae
3 changed files with 76 additions and 2 deletions

View File

@ -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). */

View File

@ -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") ","

View File

@ -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<HeapGraphEdge*>::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);