Skip to content
Open
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
10 changes: 8 additions & 2 deletions src/memory_tracker-inl.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -300,7 +300,7 @@ void MemoryTracker::Track(const CppgcMixin* retainer, const char* edge_name) {
auto it = seen_.find(retainer);
if (it != seen_.end()) {
if (CurrentNode() != nullptr) {
AddEdge(CurrentNode(), it->second, edge_name);
AddEdge(CurrentNode(), it->second->JSWrapperNode(), edge_name);
}
return; // It has already been tracked, no need to call MemoryInfo again
}
Expand DownExpand Up@@ -357,6 +357,11 @@ inline void MemoryTracker::TraitTrackInline(const T& retainer,
-(static_cast<int>(MemoryRetainerTraits<T>::SelfSize(retainer))));
}

MemoryTracker::MemoryTracker(v8::Isolate* isolate, v8::EmbedderGraph* graph)
: isolate_(isolate), graph_(graph) {}

MemoryTracker::~MemoryTracker() = default;

v8::EmbedderGraph::Node* MemoryTracker::CurrentNode() const {
if (node_stack_.empty()) return nullptr;
MemoryRetainerNode* n = node_stack_.top();
Expand All@@ -373,7 +378,8 @@ MemoryRetainerNode* MemoryTracker::AddNode(const CppgcMixin* retainer,
return it->second;
}

MemoryRetainerNode* n = new MemoryRetainerNode(this, retainer);
cppgc_nodes_.push_back(std::make_unique<MemoryRetainerNode>(this, retainer));
MemoryRetainerNode* n = cppgc_nodes_.back().get();
seen_[retainer] = n;
if (CurrentNode() != nullptr) {
AddEdge(CurrentNode(), n->JSWrapperNode(), edge_name);
Expand Down
9 changes: 6 additions & 3 deletions src/memory_tracker.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,10 +8,12 @@
#include <uv.h>

#include <limits>
#include <memory>
#include <queue>
#include <stack>
#include <string>
#include <unordered_map>
#include <vector>

namespace v8 {
class BackingStore;
Expand DownExpand Up@@ -294,9 +296,8 @@ class MemoryTracker {
inline v8::EmbedderGraph* graph() { return graph_; }
inline v8::Isolate* isolate() { return isolate_; }

inline explicit MemoryTracker(v8::Isolate* isolate,
v8::EmbedderGraph* graph)
: isolate_(isolate), graph_(graph) {}
inline explicit MemoryTracker(v8::Isolate* isolate, v8::EmbedderGraph* graph);
inline ~MemoryTracker();

// Can be passed to Track() if it is not desirable
// to create a strong edge between nodes, i.e. when
Expand DownExpand Up@@ -334,6 +335,8 @@ class MemoryTracker {
v8::EmbedderGraph* graph_;
std::stack<MemoryRetainerNode*> node_stack_;
NodeMap seen_;
// Placeholder nodes for cppgc wrappers; the graph only owns their JS nodes.
std::vector<std::unique_ptr<MemoryRetainerNode>> cppgc_nodes_;
};

} // namespace node
Expand Down
13 changes: 13 additions & 0 deletions test/cctest/test_environment.cc
Original file line numberDiff line numberDiff line change
Expand Up@@ -328,6 +328,19 @@ TEST_F(EnvironmentTest, MultipleEnvironmentsPerIsolate) {
EXPECT_TRUE(called_cb_2);
}

TEST_F(EnvironmentTest, HeapSnapshotWithCppgcWrappersDoesNotLeak) {
const v8::HandleScope handle_scope(isolate_);
const Argv argv;
Env env{handle_scope, argv};
node::LoadEnvironment(*env,
"const vm = require('vm');"
"globalThis.script = new vm.Script('1');"
"globalThis.context = vm.createContext();")
.ToLocalChecked();
node::heap::HeapSnapshotPointer snapshot{
isolate_->GetHeapProfiler()->TakeHeapSnapshot()};
}

TEST_F(EnvironmentTest, NoEnvironmentSanity) {
const v8::HandleScope handle_scope(isolate_);
v8::Local<v8::Context> context = v8::Context::New(isolate_);
Expand Down
Loading