Commit 96618d09 authored by Michael Lippautz's avatar Michael Lippautz Committed by Commit Bot

heap-snapshot: Add detachedness field

Adds a field that can be propagated by embedders. The field holds
the detachedness state of DOM objects but can be used in general
by embedder to indicate which objects are for sure part of interesting
application logic and which objects are not. This field is then
processed properly by the DevTools front end.

Bug: chromium:1110816
Change-Id: I53a172208cd69ce2ba2ed9524d36b6512aae7d30
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2332174Reviewed-by: 's avatarUlan Degenbaev <ulan@chromium.org>
Commit-Queue: Michael Lippautz <mlippautz@chromium.org>
Cr-Commit-Position: refs/heads/master@{#69780}
parent 76d684cc
......@@ -6,6 +6,7 @@
#define V8_V8_PROFILER_H_
#include <limits.h>
#include <memory>
#include <unordered_set>
#include <vector>
......@@ -712,6 +713,19 @@ class V8_EXPORT EmbedderGraph {
public:
class Node {
public:
/**
* Detachedness specifies whether an object is attached or detached from the
* main application state. While unkown in general, there may be objects
* that specifically know their state. V8 passes this information along in
* the snapshot. Users of the snapshot may use it to annotate the object
* graph.
*/
enum class Detachedness : uint8_t {
kUnkown = 0,
kAttached = 1,
kDetached = 2,
};
Node() = default;
virtual ~Node() = default;
virtual const char* Name() = 0;
......@@ -736,6 +750,14 @@ class V8_EXPORT EmbedderGraph {
*/
virtual NativeObject GetNativeObject() { return nullptr; }
/**
* Detachedness state of a given object. While unkown in general, there may
* be objects that specifically know their state. V8 passes this information
* along in the snapshot. Users of the snapshot may use it to annotate the
* object graph.
*/
virtual Detachedness GetDetachedness() { return Detachedness::kUnkown; }
Node(const Node&) = delete;
Node& operator=(const Node&) = delete;
};
......
......@@ -8,6 +8,7 @@
#include "src/api/api-inl.h"
#include "src/codegen/assembler-inl.h"
#include "src/common/globals.h"
#include "src/debug/debug.h"
#include "src/handles/global-handles.h"
#include "src/heap/combined-heap.h"
......@@ -187,10 +188,14 @@ HeapSnapshot::HeapSnapshot(HeapProfiler* profiler, bool global_objects_as_roots)
treat_global_objects_as_roots_(global_objects_as_roots) {
// It is very important to keep objects that form a heap snapshot
// as small as possible. Check assumptions about data structure sizes.
STATIC_ASSERT((kSystemPointerSize == 4 && sizeof(HeapGraphEdge) == 12) ||
(kSystemPointerSize == 8 && sizeof(HeapGraphEdge) == 24));
STATIC_ASSERT((kSystemPointerSize == 4 && sizeof(HeapEntry) == 28) ||
(kSystemPointerSize == 8 && sizeof(HeapEntry) == 40));
STATIC_ASSERT(kSystemPointerSize != 4 || sizeof(HeapGraphEdge) == 12);
STATIC_ASSERT(kSystemPointerSize != 8 || sizeof(HeapGraphEdge) == 24);
STATIC_ASSERT(kSystemPointerSize != 4 || sizeof(HeapEntry) == 32);
#if V8_CC_MSVC
STATIC_ASSERT(kSystemPointerSize != 8 || sizeof(HeapEntry) == 48);
#else // !V8_CC_MSVC
STATIC_ASSERT(kSystemPointerSize != 8 || sizeof(HeapEntry) == 40);
#endif // !V8_CC_MSVC
memset(&gc_subroot_entries_, 0, sizeof(gc_subroot_entries_));
}
......@@ -1937,9 +1942,11 @@ HeapEntry* EmbedderGraphEntriesAllocator::AllocateEntry(HeapThing ptr) {
(lookup_address) ? heap_object_map_->FindOrAddEntry(lookup_address, 0)
: static_cast<SnapshotObjectId>(
reinterpret_cast<uintptr_t>(node) << 1);
return snapshot_->AddEntry(EmbedderGraphNodeType(node),
EmbedderGraphNodeName(names_, node), id,
static_cast<int>(size), 0);
auto* heap_entry = snapshot_->AddEntry(EmbedderGraphNodeType(node),
EmbedderGraphNodeName(names_, node),
id, static_cast<int>(size), 0);
heap_entry->set_detachedness(node->GetDetachedness());
return heap_entry;
}
NativeObjectsExplorer::NativeObjectsExplorer(
......@@ -1956,7 +1963,10 @@ HeapEntry* NativeObjectsExplorer::EntryForEmbedderGraphNode(
EmbedderGraphImpl::Node* node) {
EmbedderGraphImpl::Node* wrapper = node->WrapperNode();
NativeObject native_object = node->GetNativeObject();
v8::EmbedderGraph::Node::Detachedness detachedness =
v8::EmbedderGraph::Node::Detachedness::kUnkown;
if (wrapper) {
detachedness = node->GetDetachedness();
node = wrapper;
}
if (node->IsEmbedderNode()) {
......@@ -1969,6 +1979,7 @@ HeapEntry* NativeObjectsExplorer::EntryForEmbedderGraphNode(
if (object.IsSmi()) return nullptr;
HeapEntry* entry = generator_->FindEntry(
reinterpret_cast<void*>(Object::cast(object).ptr()));
entry->set_detachedness(detachedness);
if (native_object) {
HeapObject heap_object = HeapObject::cast(object);
heap_object_map_->AddMergedNativeEntry(native_object,
......@@ -2125,6 +2136,11 @@ bool HeapSnapshotGenerator::FillReferences() {
}
template<int bytes> struct MaxDecimalDigitsIn;
template <>
struct MaxDecimalDigitsIn<1> {
static const int kSigned = 3;
static const int kUnsigned = 3;
};
template<> struct MaxDecimalDigitsIn<4> {
static const int kSigned = 11;
static const int kUnsigned = 10;
......@@ -2224,8 +2240,8 @@ class OutputStreamWriter {
// type, name|index, to_node.
const int HeapSnapshotJSONSerializer::kEdgeFieldsCount = 3;
// type, name, id, self_size, edge_count, trace_node_id.
const int HeapSnapshotJSONSerializer::kNodeFieldsCount = 6;
// type, name, id, self_size, edge_count, trace_node_id, detachedness.
const int HeapSnapshotJSONSerializer::kNodeFieldsCount = 7;
void HeapSnapshotJSONSerializer::Serialize(v8::OutputStream* stream) {
if (AllocationTracker* allocation_tracker =
......@@ -2298,6 +2314,11 @@ namespace {
template<size_t size> struct ToUnsigned;
template <>
struct ToUnsigned<1> {
using Type = uint8_t;
};
template<> struct ToUnsigned<4> {
using Type = uint32_t;
};
......@@ -2371,11 +2392,12 @@ void HeapSnapshotJSONSerializer::SerializeEdges() {
}
void HeapSnapshotJSONSerializer::SerializeNode(const HeapEntry* entry) {
// The buffer needs space for 4 unsigned ints, 1 size_t, 5 commas, \n and \0
// The buffer needs space for 5 unsigned ints, 1 size_t, 1 uint8_t, 7 commas,
// \n and \0
static const int kBufferSize =
5 * MaxDecimalDigitsIn<sizeof(unsigned)>::kUnsigned // NOLINT
+ MaxDecimalDigitsIn<sizeof(size_t)>::kUnsigned // NOLINT
+ 6 + 1 + 1;
+ MaxDecimalDigitsIn<sizeof(size_t)>::kUnsigned // NOLINT
+ MaxDecimalDigitsIn<sizeof(uint8_t)>::kUnsigned + 7 + 1 + 1;
EmbeddedVector<char, kBufferSize> buffer;
int buffer_pos = 0;
if (to_node_index(entry) != 0) {
......@@ -2392,6 +2414,8 @@ void HeapSnapshotJSONSerializer::SerializeNode(const HeapEntry* entry) {
buffer_pos = utoa(entry->children_count(), buffer, buffer_pos);
buffer[buffer_pos++] = ',';
buffer_pos = utoa(entry->trace_node_id(), buffer, buffer_pos);
buffer[buffer_pos++] = ',';
buffer_pos = utoa(entry->detachedness(), buffer, buffer_pos);
buffer[buffer_pos++] = '\n';
buffer[buffer_pos++] = '\0';
writer_->AddString(buffer.begin());
......@@ -2421,7 +2445,8 @@ void HeapSnapshotJSONSerializer::SerializeSnapshot() {
JSON_S("id") ","
JSON_S("self_size") ","
JSON_S("edge_count") ","
JSON_S("trace_node_id")) ","
JSON_S("trace_node_id") ","
JSON_S("detachedness")) ","
JSON_S("node_types") ":" JSON_A(
JSON_A(
JSON_S("hidden") ","
......
......@@ -133,6 +133,11 @@ class HeapEntry {
V8_INLINE HeapGraphEdge* child(int i);
V8_INLINE Isolate* isolate() const;
void set_detachedness(v8::EmbedderGraph::Node::Detachedness value) {
detachedness_ = static_cast<uint8_t>(value);
}
uint8_t detachedness() const { return detachedness_; }
void SetIndexedReference(
HeapGraphEdge::Type type, int index, HeapEntry* entry);
void SetNamedReference(
......@@ -161,7 +166,12 @@ class HeapEntry {
unsigned children_count_;
unsigned children_end_index_;
};
#ifdef V8_TARGET_ARCH_64_BIT
size_t self_size_ : 48;
#else // !V8_TARGET_ARCH_64_BIT
size_t self_size_;
#endif // !V8_TARGET_ARCH_64_BIT
uint8_t detachedness_ = 0;
HeapSnapshot* snapshot_;
const char* name_;
SnapshotObjectId id_;
......
......@@ -7,7 +7,7 @@ let {session, contextGroup, Protocol} = InspectorTest.start(
const kNodeName = 1;
const kNodeEdgeCount = 4;
const kNodeSize = 6;
const kNodeSize = 7;
const kEdgeName = 1;
const kEdgeTarget = 2;
const kEdgeSize = 3;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment