Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

deps: cherry-pick 6ee8345 from upstream V8 #22106

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion common.gypi
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@

# Reset this number to 0 on major V8 upgrades.
# Increment by one for each non-official patch applied to deps/v8.
'v8_embedder_string': '-node.15',
'v8_embedder_string': '-node.16',

# Enable disassembler for `--print-code` v8 options
'v8_enable_disassembler': 1,
Expand Down
9 changes: 6 additions & 3 deletions deps/v8/include/v8-profiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -686,11 +686,14 @@ class V8_EXPORT EmbedderGraph {
virtual Node* AddNode(std::unique_ptr<Node> node) = 0;

/**
* Adds an edge that represents a strong reference from the given node
* |from| to the given node |to|. The nodes must be added to the graph
* Adds an edge that represents a strong reference from the given
* node |from| to the given node |to|. The nodes must be added to the graph
* before calling this function.
*
* If name is nullptr, the edge will have auto-increment indexes, otherwise
* it will be named accordingly.
*/
virtual void AddEdge(Node* from, Node* to) = 0;
virtual void AddEdge(Node* from, Node* to, const char* name = nullptr) = 0;

virtual ~EmbedderGraph() = default;
};
Expand Down
14 changes: 11 additions & 3 deletions deps/v8/src/profiler/heap-snapshot-generator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1989,6 +1989,7 @@ class EmbedderGraphImpl : public EmbedderGraph {
struct Edge {
Node* from;
Node* to;
const char* name;
};

class V8NodeImpl : public Node {
Expand Down Expand Up @@ -2025,7 +2026,9 @@ class EmbedderGraphImpl : public EmbedderGraph {
return result;
}

void AddEdge(Node* from, Node* to) final { edges_.push_back({from, to}); }
void AddEdge(Node* from, Node* to, const char* name) final {
edges_.push_back({from, to, name});
}

const std::vector<std::unique_ptr<Node>>& nodes() { return nodes_; }
const std::vector<Edge>& edges() { return edges_; }
Expand Down Expand Up @@ -2318,8 +2321,13 @@ bool NativeObjectsExplorer::IterateAndExtractReferences(
int from_index = from->index();
HeapEntry* to = EntryForEmbedderGraphNode(edge.to);
if (to) {
filler_->SetIndexedAutoIndexReference(HeapGraphEdge::kElement,
from_index, to);
if (edge.name == nullptr) {
filler_->SetIndexedAutoIndexReference(HeapGraphEdge::kElement,
from_index, to);
} else {
filler_->SetNamedReference(HeapGraphEdge::kInternal, from_index,
edge.name, to);
}
}
}
} else {
Expand Down
83 changes: 83 additions & 0 deletions deps/v8/test/cctest/test-heap-profiler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,12 @@ static const char* GetName(const v8::HeapGraphNode* node) {
->name();
}

static const char* GetName(const v8::HeapGraphEdge* edge) {
return const_cast<i::HeapGraphEdge*>(
reinterpret_cast<const i::HeapGraphEdge*>(edge))
->name();
}

static size_t GetSize(const v8::HeapGraphNode* node) {
return const_cast<i::HeapEntry*>(reinterpret_cast<const i::HeapEntry*>(node))
->self_size();
Expand All @@ -128,6 +134,18 @@ static const v8::HeapGraphNode* GetChildByName(const v8::HeapGraphNode* node,
return nullptr;
}

static const v8::HeapGraphEdge* GetEdgeByChildName(
const v8::HeapGraphNode* node, const char* name) {
for (int i = 0, count = node->GetChildrenCount(); i < count; ++i) {
const v8::HeapGraphEdge* edge = node->GetChild(i);
const v8::HeapGraphNode* child = edge->GetToNode();
if (!strcmp(name, GetName(child))) {
return edge;
}
}
return nullptr;
}

static const v8::HeapGraphNode* GetRootChild(const v8::HeapSnapshot* snapshot,
const char* name) {
return GetChildByName(snapshot->GetRoot(), name);
Expand Down Expand Up @@ -2986,6 +3004,71 @@ TEST(EmbedderGraph) {
CheckEmbedderGraphSnapshot(env->GetIsolate(), snapshot);
}

void BuildEmbedderGraphWithNamedEdges(v8::Isolate* v8_isolate,
v8::EmbedderGraph* graph, void* data) {
using Node = v8::EmbedderGraph::Node;
Node* global_node = graph->V8Node(*global_object_pointer);
Node* embedder_node_A = graph->AddNode(
std::unique_ptr<Node>(new EmbedderNode("EmbedderNodeA", 10)));
Node* embedder_node_B = graph->AddNode(
std::unique_ptr<Node>(new EmbedderNode("EmbedderNodeB", 20)));
Node* embedder_node_C = graph->AddNode(
std::unique_ptr<Node>(new EmbedderNode("EmbedderNodeC", 30)));
graph->AddEdge(global_node, embedder_node_A, "global_to_a");
graph->AddEdge(embedder_node_A, embedder_node_B, "a_to_b");
graph->AddEdge(embedder_node_B, embedder_node_C);
}

void CheckEmbedderGraphWithNamedEdges(v8::Isolate* isolate,
const v8::HeapSnapshot* snapshot) {
const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
const v8::HeapGraphEdge* global_to_a =
GetEdgeByChildName(global, "EmbedderNodeA");
CHECK(global_to_a);
CHECK_EQ(v8::HeapGraphEdge::kInternal, global_to_a->GetType());
CHECK(global_to_a->GetName()->IsString());
CHECK_EQ(0, strcmp("global_to_a", GetName(global_to_a)));
const v8::HeapGraphNode* embedder_node_A = global_to_a->GetToNode();
CHECK_EQ(0, strcmp("EmbedderNodeA", GetName(embedder_node_A)));
CHECK_EQ(10, GetSize(embedder_node_A));

const v8::HeapGraphEdge* a_to_b =
GetEdgeByChildName(embedder_node_A, "EmbedderNodeB");
CHECK(a_to_b);
CHECK(a_to_b->GetName()->IsString());
CHECK_EQ(0, strcmp("a_to_b", GetName(a_to_b)));
CHECK_EQ(v8::HeapGraphEdge::kInternal, a_to_b->GetType());
const v8::HeapGraphNode* embedder_node_B = a_to_b->GetToNode();
CHECK_EQ(0, strcmp("EmbedderNodeB", GetName(embedder_node_B)));
CHECK_EQ(20, GetSize(embedder_node_B));

const v8::HeapGraphEdge* b_to_c =
GetEdgeByChildName(embedder_node_B, "EmbedderNodeC");
CHECK(b_to_c);
CHECK(b_to_c->GetName()->IsNumber());
CHECK_EQ(v8::HeapGraphEdge::kElement, b_to_c->GetType());
const v8::HeapGraphNode* embedder_node_C = b_to_c->GetToNode();
CHECK_EQ(0, strcmp("EmbedderNodeC", GetName(embedder_node_C)));
CHECK_EQ(30, GetSize(embedder_node_C));
}

TEST(EmbedderGraphWithNamedEdges) {
i::FLAG_heap_profiler_use_embedder_graph = true;
LocalContext env;
v8::HandleScope scope(env->GetIsolate());
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(env->GetIsolate());
v8::Local<v8::Value> global_object =
v8::Utils::ToLocal(i::Handle<i::JSObject>(
(isolate->context()->native_context()->global_object()), isolate));
global_object_pointer = &global_object;
v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
heap_profiler->AddBuildEmbedderGraphCallback(BuildEmbedderGraphWithNamedEdges,
nullptr);
const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
CHECK(ValidateSnapshot(snapshot));
CheckEmbedderGraphWithNamedEdges(env->GetIsolate(), snapshot);
}

struct GraphBuildingContext {
int counter = 0;
};
Expand Down
28 changes: 21 additions & 7 deletions src/heap_utils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ class JSGraph : public EmbedderGraph {
return n;
}

void AddEdge(Node* from, Node* to) override {
edges_[from].insert(to);
void AddEdge(Node* from, Node* to, const char* name = nullptr) override {
edges_[from].insert(std::make_pair(name, to));
}

MaybeLocal<Array> CreateObject() const {
Expand All @@ -92,6 +92,7 @@ class JSGraph : public EmbedderGraph {
Local<String> size_string = FIXED_ONE_BYTE_STRING(isolate_, "size");
Local<String> value_string = FIXED_ONE_BYTE_STRING(isolate_, "value");
Local<String> wraps_string = FIXED_ONE_BYTE_STRING(isolate_, "wraps");
Local<String> to_string = FIXED_ONE_BYTE_STRING(isolate_, "to");

for (const std::unique_ptr<Node>& n : nodes_)
info_objects[n.get()] = Object::New(isolate_);
Expand Down Expand Up @@ -141,10 +142,23 @@ class JSGraph : public EmbedderGraph {
}

size_t i = 0;
for (Node* target : edge_info.second) {
if (edges.As<Array>()->Set(context,
i++,
info_objects[target]).IsNothing()) {
size_t j = 0;
for (const auto& edge : edge_info.second) {
Local<Object> to_object = info_objects[edge.second];
Local<Object> edge_info = Object::New(isolate_);
Local<Value> edge_name_value;
const char* edge_name = edge.first;
if (edge_name != nullptr &&
!String::NewFromUtf8(
isolate_, edge_name, v8::NewStringType::kNormal)
.ToLocal(&edge_name_value)) {
return MaybeLocal<Array>();
} else {
edge_name_value = Number::New(isolate_, j++);
}
if (edge_info->Set(context, name_string, edge_name_value).IsNothing() ||
edge_info->Set(context, to_string, to_object).IsNothing() ||
edges.As<Array>()->Set(context, i++, edge_info).IsNothing()) {
return MaybeLocal<Array>();
}
}
Expand All @@ -158,7 +172,7 @@ class JSGraph : public EmbedderGraph {
std::unordered_set<std::unique_ptr<Node>> nodes_;
std::unordered_set<JSGraphJSNode*, JSGraphJSNode::Hash, JSGraphJSNode::Equal>
engine_nodes_;
std::unordered_map<Node*, std::unordered_set<Node*>> edges_;
std::unordered_map<Node*, std::set<std::pair<const char*, Node*>>> edges_;
};

void BuildEmbedderGraph(const FunctionCallbackInfo<Value>& args) {
Expand Down
20 changes: 12 additions & 8 deletions test/common/heap.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,19 @@ class State {
else
assert.strictEqual(graph.length, expected.length);
for (const expectedNode of expected) {
if (expectedNode.edges) {
if (expectedNode.children) {
for (const expectedChild of expectedNode.children) {
const check = typeof expectedChild === 'function' ?
expectedChild : (node) => {
return node.name === expectedChild.name ||
(node.value &&
node.value.constructor &&
node.value.constructor.name === expectedChild.name);
};
const check = (edge) => {
// TODO(joyeecheung): check the edge names
const node = edge.to;
if (typeof expectedChild === 'function') {
return expectedChild(node);
}
return node.name === expectedChild.name ||
(node.value &&
node.value.constructor &&
node.value.constructor.name === expectedChild.name);
};

assert(graph.some((node) => node.edges.some(check)),
`expected to find child ${util.inspect(expectedChild)} ` +
Expand Down