Skip to content

Commit 34f7a52

Browse files
committed
src: make CppgcMixin a MemoryRetainer
1 parent fa965bd commit 34f7a52

13 files changed

Lines changed: 225 additions & 72 deletions

node.gyp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,7 @@
206206
'src/connect_wrap.h',
207207
'src/connection_wrap.h',
208208
'src/cppgc_helpers.h',
209+
'src/cppgc_helpers.cc',
209210
'src/dataqueue/queue.h',
210211
'src/debug_utils.h',
211212
'src/debug_utils-inl.h',

src/base_object.cc

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,5 +181,4 @@ void BaseObjectList::MemoryInfo(node::MemoryTracker* tracker) const {
181181
if (bo->IsDoneInitializing()) tracker->Track(bo);
182182
}
183183
}
184-
185184
} // namespace node

src/cppgc_helpers-inl.h

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#include "cppgc_helpers.h"
2+
#include "env-inl.h"
3+
4+
namespace node {
5+
6+
template <typename T>
7+
void CppgcMixin::Wrap(T* ptr, Realm* realm, v8::Local<v8::Object> obj) {
8+
CHECK_GE(obj->InternalFieldCount(), T::kInternalFieldCount);
9+
ptr->realm_ = realm;
10+
v8::Isolate* isolate = realm->isolate();
11+
ptr->traced_reference_ = v8::TracedReference<v8::Object>(isolate, obj);
12+
// Note that ptr must be of concrete type T in Wrap.
13+
v8::Object::Wrap<v8::CppHeapPointerTag::kDefaultTag>(isolate, obj, ptr);
14+
// Keep the layout consistent with BaseObjects.
15+
obj->SetAlignedPointerInInternalField(
16+
kEmbedderType, realm->isolate_data()->embedder_id_for_cppgc());
17+
obj->SetAlignedPointerInInternalField(kSlot, ptr);
18+
realm->TrackCppgcWrapper(ptr);
19+
}
20+
21+
template <typename T>
22+
void CppgcMixin::Wrap(T* ptr, Environment* env, v8::Local<v8::Object> obj) {
23+
Wrap(ptr, env->principal_realm(), obj);
24+
}
25+
26+
template <typename T>
27+
T* CppgcMixin::Unwrap(v8::Local<v8::Object> obj) {
28+
// We are not using v8::Object::Unwrap currently because that requires
29+
// access to isolate which the ASSIGN_OR_RETURN_UNWRAP macro that we'll shim
30+
// with ASSIGN_OR_RETURN_UNWRAP_GC doesn't take, and we also want a
31+
// signature consistent with BaseObject::Unwrap() to avoid churn. Since
32+
// cppgc-managed objects share the same layout as BaseObjects, just unwrap
33+
// from the pointer in the internal field, which should be valid as long as
34+
// the object is still alive.
35+
if (obj->InternalFieldCount() != T::kInternalFieldCount) {
36+
return nullptr;
37+
}
38+
T* ptr = static_cast<T*>(obj->GetAlignedPointerFromInternalField(T::kSlot));
39+
return ptr;
40+
}
41+
42+
v8::Local<v8::Object> CppgcMixin::object() const {
43+
return traced_reference_.Get(realm_->isolate());
44+
}
45+
46+
Environment* CppgcMixin::env() const {
47+
return realm_->env();
48+
}
49+
50+
} // namespace node

src/cppgc_helpers.cc

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#include "cppgc_helpers.h"
2+
#include "env-inl.h"
3+
4+
namespace node {
5+
6+
void CppgcWrapperList::Cleanup() {
7+
for (auto handle : *this) {
8+
handle->Clean();
9+
}
10+
}
11+
12+
void CppgcWrapperList::MemoryInfo(MemoryTracker* tracker) const {
13+
for (auto handle : *this) {
14+
tracker->Track(handle);
15+
}
16+
}
17+
18+
} // namespace node

src/cppgc_helpers.h

Lines changed: 37 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,18 @@
66
#include <type_traits> // std::remove_reference
77
#include "cppgc/garbage-collected.h"
88
#include "cppgc/name-provider.h"
9-
#include "env.h"
109
#include "memory_tracker.h"
10+
#include "util.h"
1111
#include "v8-cppgc.h"
1212
#include "v8-sandbox.h"
1313
#include "v8.h"
1414

1515
namespace node {
1616

17+
class Environment;
18+
class Realm;
19+
class CppgcWrapperList;
20+
1721
/**
1822
* This is a helper mixin with a BaseObject-like interface to help
1923
* implementing wrapper objects managed by V8's cppgc (Oilpan) library.
@@ -47,8 +51,7 @@ namespace node {
4751
* // Do cleanup that relies on a living Environemnt.
4852
* }
4953
*/
50-
class CppgcMixin : public cppgc::GarbageCollectedMixin,
51-
public CppgcWrapperListNode {
54+
class CppgcMixin : public cppgc::GarbageCollectedMixin, public MemoryRetainer {
5255
public:
5356
// To help various callbacks access wrapper objects with different memory
5457
// management, cppgc-managed objects share the same layout as BaseObjects.
@@ -58,71 +61,55 @@ class CppgcMixin : public cppgc::GarbageCollectedMixin,
5861
// invoked from the child class constructor, per cppgc::GarbageCollectedMixin
5962
// rules.
6063
template <typename T>
61-
static void Wrap(T* ptr, Environment* env, v8::Local<v8::Object> obj) {
62-
CHECK_GE(obj->InternalFieldCount(), T::kInternalFieldCount);
63-
ptr->env_ = env;
64-
v8::Isolate* isolate = env->isolate();
65-
ptr->traced_reference_ = v8::TracedReference<v8::Object>(isolate, obj);
66-
v8::Object::Wrap<v8::CppHeapPointerTag::kDefaultTag>(isolate, obj, ptr);
67-
// Keep the layout consistent with BaseObjects.
68-
obj->SetAlignedPointerInInternalField(
69-
kEmbedderType, env->isolate_data()->embedder_id_for_cppgc());
70-
obj->SetAlignedPointerInInternalField(kSlot, ptr);
71-
env->cppgc_wrapper_list()->PushFront(ptr);
72-
}
64+
static inline void Wrap(T* ptr, Realm* realm, v8::Local<v8::Object> obj);
65+
template <typename T>
66+
static inline void Wrap(T* ptr, Environment* env, v8::Local<v8::Object> obj);
7367

74-
v8::Local<v8::Object> object() const {
75-
return traced_reference_.Get(env_->isolate());
68+
inline v8::Local<v8::Object> object() const;
69+
inline Environment* env() const;
70+
inline v8::Local<v8::Object> object(v8::Isolate* isolate) const {
71+
return traced_reference_.Get(isolate);
7672
}
7773

78-
Environment* env() const { return env_; }
79-
8074
template <typename T>
81-
static T* Unwrap(v8::Local<v8::Object> obj) {
82-
// We are not using v8::Object::Unwrap currently because that requires
83-
// access to isolate which the ASSIGN_OR_RETURN_UNWRAP macro that we'll shim
84-
// with ASSIGN_OR_RETURN_UNWRAP_GC doesn't take, and we also want a
85-
// signature consistent with BaseObject::Unwrap() to avoid churn. Since
86-
// cppgc-managed objects share the same layout as BaseObjects, just unwrap
87-
// from the pointer in the internal field, which should be valid as long as
88-
// the object is still alive.
89-
if (obj->InternalFieldCount() != T::kInternalFieldCount) {
90-
return nullptr;
91-
}
92-
T* ptr = static_cast<T*>(obj->GetAlignedPointerFromInternalField(T::kSlot));
93-
return ptr;
94-
}
75+
static inline T* Unwrap(v8::Local<v8::Object> obj);
9576

9677
// Subclasses are expected to invoke CppgcMixin::Trace() in their own Trace()
9778
// methods.
9879
void Trace(cppgc::Visitor* visitor) const override {
9980
visitor->Trace(traced_reference_);
10081
}
10182

102-
// This implements CppgcWrapperListNode::Clean and is run for all the
103-
// remaining Cppgc wrappers tracked in the Environment during Environment
104-
// shutdown. The destruction of the wrappers would happen later, when the
105-
// final garbage collection is triggered when CppHeap is torn down as part of
106-
// the Isolate teardown. If subclasses of CppgcMixin wish to perform cleanups
107-
// that depend on the Environment during destruction, they should implment it
108-
// in a CleanEnvResource() override, and then call this->Clean() from their
83+
// TODO(joyeecheung): use ObjectSizeTrait;
84+
inline size_t SelfSize() const override { return sizeof(*this); }
85+
inline bool IsCppgcWrapper() const override { return true; }
86+
87+
// This is run for all the remaining Cppgc wrappers tracked in the Realm
88+
// during Realm shutdown. The destruction of the wrappers would happen later,
89+
// when the final garbage collection is triggered when CppHeap is torn down as
90+
// part of the Isolate teardown. If subclasses of CppgcMixin wish to perform
91+
// cleanups that depend on the Realm during destruction, they should implment
92+
// it in a CleanEnvResource() override, and then call this->Clean() from their
10993
// destructor. Outside of CleanEnvResource(), subclasses should avoid calling
11094
// into JavaScript or perform any operation that can trigger garbage
11195
// collection during the destruction.
112-
void Clean() override {
113-
if (env_ == nullptr) return;
114-
this->CleanEnvResource(env_);
115-
env_ = nullptr;
96+
void Clean() {
97+
if (realm_ == nullptr) return;
98+
this->CleanEnvResource(realm_);
99+
realm_ = nullptr;
116100
}
117101

118102
// The default implementation of CleanEnvResource() is a no-op. Subclasses
119-
// should override it to perform cleanup that require a living Environment,
103+
// should override it to perform cleanup that require a living Realm,
120104
// instead of doing these cleanups directly in the destructor.
121-
virtual void CleanEnvResource(Environment* env) {}
105+
virtual void CleanEnvResource(Realm* realm) {}
106+
107+
friend class CppgcWrapperList;
122108

123109
private:
124-
Environment* env_ = nullptr;
110+
Realm* realm_ = nullptr;
125111
v8::TracedReference<v8::Object> traced_reference_;
112+
ListNode<CppgcMixin> wrapper_list_node_;
126113
};
127114

128115
// If the class doesn't have additional owned traceable data, use this macro to
@@ -137,6 +124,9 @@ class CppgcMixin : public cppgc::GarbageCollectedMixin,
137124
#define SET_CPPGC_NAME(Klass) \
138125
inline const char* GetHumanReadableName() const final { \
139126
return "Node / " #Klass; \
127+
} \
128+
inline const char* MemoryInfoName() const override { \
129+
return #Klass; \
140130
}
141131

142132
/**

src/env.cc

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1302,8 +1302,6 @@ void Environment::RunCleanup() {
13021302
CleanupHandles();
13031303
}
13041304

1305-
for (CppgcWrapperListNode* handle : cppgc_wrapper_list_) handle->Clean();
1306-
13071305
for (const int fd : unmanaged_fds_) {
13081306
uv_fs_t close_req;
13091307
uv_fs_close(nullptr, &close_req, fd, nullptr);

src/env.h

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -602,12 +602,6 @@ class Cleanable {
602602
friend class Environment;
603603
};
604604

605-
class CppgcWrapperListNode {
606-
public:
607-
virtual void Clean() = 0;
608-
ListNode<CppgcWrapperListNode> wrapper_list_node;
609-
};
610-
611605
/**
612606
* Environment is a per-isolate data structure that represents an execution
613607
* environment. Each environment has a principal realm. An environment can
@@ -903,18 +897,12 @@ class Environment final : public MemoryRetainer {
903897
typedef ListHead<HandleWrap, &HandleWrap::handle_wrap_queue_> HandleWrapQueue;
904898
typedef ListHead<ReqWrapBase, &ReqWrapBase::req_wrap_queue_> ReqWrapQueue;
905899
typedef ListHead<Cleanable, &Cleanable::cleanable_queue_> CleanableQueue;
906-
typedef ListHead<CppgcWrapperListNode,
907-
&CppgcWrapperListNode::wrapper_list_node>
908-
CppgcWrapperList;
909900

910901
inline HandleWrapQueue* handle_wrap_queue() { return &handle_wrap_queue_; }
911902
inline CleanableQueue* cleanable_queue() {
912903
return &cleanable_queue_;
913904
}
914905
inline ReqWrapQueue* req_wrap_queue() { return &req_wrap_queue_; }
915-
inline CppgcWrapperList* cppgc_wrapper_list() {
916-
return &cppgc_wrapper_list_;
917-
}
918906

919907
// https://w3c.github.io/hr-time/#dfn-time-origin
920908
inline uint64_t time_origin() {
@@ -1203,7 +1191,6 @@ class Environment final : public MemoryRetainer {
12031191
CleanableQueue cleanable_queue_;
12041192
HandleWrapQueue handle_wrap_queue_;
12051193
ReqWrapQueue req_wrap_queue_;
1206-
CppgcWrapperList cppgc_wrapper_list_;
12071194

12081195
int handle_cleanup_waiting_ = 0;
12091196
int request_waiting_ = 0;

0 commit comments

Comments
 (0)