Skip to content

Commit 857e438

Browse files
authored
src: fix heap value deduplication in embedder graph
Signed-off-by: ishabi <ilyasshabi94@gmail.com> PR-URL: #64801 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
1 parent 00c80a8 commit 857e438

2 files changed

Lines changed: 44 additions & 19 deletions

File tree

src/heap_utils.cc

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -57,19 +57,13 @@ class JSGraphJSNode : public EmbedderGraph::Node {
5757
CHECK(!val.IsEmpty());
5858
}
5959

60-
struct Equal {
61-
inline bool operator()(JSGraphJSNode* a, JSGraphJSNode* b) const {
62-
Local<Data> data_a = a->V8Value();
63-
Local<Data> data_b = a->V8Value();
64-
if (data_a->IsValue()) {
65-
if (!data_b->IsValue()) {
66-
return false;
67-
}
68-
return data_a.As<Value>()->SameValue(data_b.As<Value>());
69-
}
70-
return data_a == data_b;
60+
bool IsSame(Local<Data> other) {
61+
Local<Data> value = V8Value();
62+
if (value->IsValue() && other->IsValue()) {
63+
return value.As<Value>()->SameValue(other.As<Value>());
7164
}
72-
};
65+
return value == other;
66+
}
7367

7468
private:
7569
Global<Data> persistent_;
@@ -80,12 +74,15 @@ class JSGraph : public EmbedderGraph {
8074
explicit JSGraph(Isolate* isolate) : isolate_(isolate) {}
8175

8276
Node* V8Node(const Local<v8::Data>& value) override {
83-
std::unique_ptr<JSGraphJSNode> n { new JSGraphJSNode(isolate_, value) };
84-
auto it = engine_nodes_.find(n.get());
85-
if (it != engine_nodes_.end())
86-
return *it;
87-
engine_nodes_.insert(n.get());
88-
return AddNode(std::unique_ptr<Node>(n.release()));
77+
for (JSGraphJSNode* node : engine_nodes_) {
78+
if (node->IsSame(value)) {
79+
return node;
80+
}
81+
}
82+
83+
auto node = std::make_unique<JSGraphJSNode>(isolate_, value);
84+
engine_nodes_.push_back(node.get());
85+
return AddNode(std::move(node));
8986
}
9087

9188
Node* V8Node(const Local<v8::Value>& value) override {
@@ -207,14 +204,19 @@ class JSGraph : public EmbedderGraph {
207204
private:
208205
Isolate* isolate_;
209206
std::unordered_set<std::unique_ptr<Node>> nodes_;
210-
std::set<JSGraphJSNode*, JSGraphJSNode::Equal> engine_nodes_;
207+
std::vector<JSGraphJSNode*> engine_nodes_;
211208
std::unordered_map<Node*, std::set<std::pair<const char*, Node*>>> edges_;
212209
};
213210

214211
void BuildEmbedderGraph(const FunctionCallbackInfo<Value>& args) {
215212
Environment* env = Environment::GetCurrent(args);
216213
JSGraph graph(env->isolate());
217214
Environment::BuildEmbedderGraph(env->isolate(), &graph, env);
215+
// This binding is used only by tests. Include supplied values so tests can
216+
// verify that JSGraph returns one graph node for each distinct V8 value.
217+
for (int i = 0; i < args.Length(); i++) {
218+
graph.V8Node(args[i]);
219+
}
218220
Local<Array> ret;
219221
if (graph.CreateObject().ToLocal(&ret))
220222
args.GetReturnValue().Set(ret);
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Flags: --expose-internals
2+
'use strict';
3+
4+
require('../common');
5+
const assert = require('assert');
6+
const { internalBinding } = require('internal/test/binding');
7+
8+
const { buildEmbedderGraph } = internalBinding('heap_utils');
9+
10+
const first = {};
11+
const second = {};
12+
const bigint = BigInt('123456789012345678901234567890');
13+
const sameBigint = BigInt('123456789012345678901234567890');
14+
const graph = buildEmbedderGraph(first, first, second, bigint, sameBigint);
15+
16+
function findNodes(value) {
17+
return graph.filter((node) => Object.hasOwn(node, 'value') &&
18+
Object.is(node.value, value));
19+
}
20+
21+
assert.strictEqual(findNodes(first).length, 1);
22+
assert.strictEqual(findNodes(second).length, 1);
23+
assert.strictEqual(findNodes(bigint).length, 1);

0 commit comments

Comments
 (0)