6
6
#include <type_traits> // std::remove_reference
7
7
#include "cppgc/garbage-collected.h"
8
8
#include "cppgc/name-provider.h"
9
-
#include "env.h"
9
+
#include "cppgc/persistent.h"
10
10
#include "memory_tracker.h"
11
+
#include "util.h"
11
12
#include "v8-cppgc.h"
12
13
#include "v8-sandbox.h"
13
14
#include "v8.h"
14
15
15
16
namespace node {
16
17
18
+
class Environment;
19
+
class Realm;
20
+
class CppgcWrapperListNode;
21
+
17
22
/**
18
23
* This is a helper mixin with a BaseObject-like interface to help
19
24
* implementing wrapper objects managed by V8's cppgc (Oilpan) library.
@@ -25,20 +30,29 @@ namespace node {
25
30
* with V8's GC scheduling.
26
31
*
27
32
* A cppgc-managed native wrapper should look something like this, note
28
-
* that per cppgc rules, CPPGC_MIXIN(Klass) must be at the left-most
33
+
* that per cppgc rules, CPPGC_MIXIN(MyWrap) must be at the left-most
29
34
* position in the hierarchy (which ensures cppgc::GarbageCollected
30
35
* is at the left-most position).
31
36
*
32
-
* class Klass final : CPPGC_MIXIN(Klass) {
37
+
* class MyWrap final : CPPGC_MIXIN(MyWrap) {
33
38
* public:
34
-
* SET_CPPGC_NAME(Klass) // Sets the heap snapshot name to "Node / Klass"
39
+
* SET_CPPGC_NAME(MyWrap) // Sets the heap snapshot name to "Node / MyWrap"
35
40
* void Trace(cppgc::Visitor* visitor) const final {
36
41
* CppgcMixin::Trace(visitor);
37
42
* visitor->Trace(...); // Trace any additional owned traceable data
38
43
* }
39
44
* }
45
+
*
46
+
* If the wrapper needs to perform cleanups when it's destroyed and that
47
+
* cleanup relies on a living Node.js `Realm`, it should implement a
48
+
* pattern like this:
49
+
*
50
+
* ~MyWrap() { this->Destroy(); }
51
+
* void Clean(Realm* env) override {
52
+
* // Do cleanup that relies on a living Environemnt.
53
+
* }
40
54
*/
41
-
class CppgcMixin : public cppgc::GarbageCollectedMixin {
55
+
class CppgcMixin : public cppgc::GarbageCollectedMixin, public MemoryRetainer {
42
56
public:
43
57
// To help various callbacks access wrapper objects with different memory
44
58
// management, cppgc-managed objects share the same layout as BaseObjects.
@@ -48,48 +62,58 @@ class CppgcMixin : public cppgc::GarbageCollectedMixin {
48
62
// invoked from the child class constructor, per cppgc::GarbageCollectedMixin
49
63
// rules.
50
64
template <typename T>
51
-
static void Wrap(T* ptr, Environment* env, v8::Local<v8::Object> obj) {
52
-
CHECK_GE(obj->InternalFieldCount(), T::kInternalFieldCount);
53
-
ptr->env_ = env;
54
-
v8::Isolate* isolate = env->isolate();
55
-
ptr->traced_reference_ = v8::TracedReference<v8::Object>(isolate, obj);
56
-
v8::Object::Wrap<v8::CppHeapPointerTag::kDefaultTag>(isolate, obj, ptr);
57
-
// Keep the layout consistent with BaseObjects.
58
-
obj->SetAlignedPointerInInternalField(
59
-
kEmbedderType, env->isolate_data()->embedder_id_for_cppgc());
60
-
obj->SetAlignedPointerInInternalField(kSlot, ptr);
61
-
}
65
+
static inline void Wrap(T* ptr, Realm* realm, v8::Local<v8::Object> obj);
66
+
template <typename T>
67
+
static inline void Wrap(T* ptr, Environment* env, v8::Local<v8::Object> obj);
62
68
63
-
v8::Local<v8::Object> object() const {
64
-
return traced_reference_.Get(env_->isolate());
69
+
inline v8::Local<v8::Object> object() const;
70
+
inline Environment* env() const;
71
+
inline Realm* realm() const { return realm_; }
72
+
inline v8::Local<v8::Object> object(v8::Isolate* isolate) const {
73
+
return traced_reference_.Get(isolate);
65
74
}
66
75
67
-
Environment* env() const { return env_; }
68
-
69
76
template <typename T>
70
-
static T* Unwrap(v8::Local<v8::Object> obj) {
71
-
// We are not using v8::Object::Unwrap currently because that requires
72
-
// access to isolate which the ASSIGN_OR_RETURN_UNWRAP macro that we'll shim
73
-
// with ASSIGN_OR_RETURN_UNWRAP_GC doesn't take, and we also want a
74
-
// signature consistent with BaseObject::Unwrap() to avoid churn. Since
75
-
// cppgc-managed objects share the same layout as BaseObjects, just unwrap
76
-
// from the pointer in the internal field, which should be valid as long as
77
-
// the object is still alive.
78
-
if (obj->InternalFieldCount() != T::kInternalFieldCount) {
79
-
return nullptr;
80
-
}
81
-
T* ptr = static_cast<T*>(obj->GetAlignedPointerFromInternalField(T::kSlot));
82
-
return ptr;
83
-
}
77
+
static inline T* Unwrap(v8::Local<v8::Object> obj);
84
78
85
79
// Subclasses are expected to invoke CppgcMixin::Trace() in their own Trace()
86
80
// methods.
87
81
void Trace(cppgc::Visitor* visitor) const override {
88
82
visitor->Trace(traced_reference_);
89
83
}
90
84
85
+
// TODO(joyeecheung): use ObjectSizeTrait;
86
+
inline size_t SelfSize() const override { return sizeof(*this); }
87
+
inline bool IsCppgcWrapper() const override { return true; }
88
+
89
+
// This is run for all the remaining Cppgc wrappers tracked in the Realm
90
+
// during Realm shutdown. The destruction of the wrappers would happen later,
91
+
// when the final garbage collection is triggered when CppHeap is torn down as
92
+
// part of the Isolate teardown. If subclasses of CppgcMixin wish to perform
93
+
// cleanups that depend on the Realm during destruction, they should implment
94
+
// it in a Clean() override, and then call this->Finalize() from their
95
+
// destructor. Outside of Finalize(), subclasses should avoid calling
96
+
// into JavaScript or perform any operation that can trigger garbage
97
+
// collection during the destruction.
98
+
void Finalize() {
99
+
if (realm_ == nullptr) return;
100
+
this->Clean(realm_);
101
+
realm_ = nullptr;
102
+
}
103
+
104
+
// The default implementation of Clean() is a no-op. If subclasses wish
105
+
// to perform cleanup that require a living Realm, they should
106
+
// should put the cleanups in a Clean() override, and call this->Finalize()
107
+
// in the destructor, instead of doing those cleanups directly in the
108
+
// destructor.
109
+
virtual void Clean(Realm* realm) {}
110
+
111
+
inline ~CppgcMixin();
112
+
113
+
friend class CppgcWrapperListNode;
114
+
91
115
private:
92
-
Environment* env_;
116
+
Realm* realm_ = nullptr;
93
117
v8::TracedReference<v8::Object> traced_reference_;
94
118
};
95
119
@@ -105,7 +129,8 @@ class CppgcMixin : public cppgc::GarbageCollectedMixin {
105
129
#define SET_CPPGC_NAME(Klass) \
106
130
inline const char* GetHumanReadableName() const final { \
107
131
return "Node / " #Klass; \
108
-
}
132
+
} \
133
+
inline const char* MemoryInfoName() const override { return #Klass; }
109
134
110
135
/**
111
136
* Similar to ASSIGN_OR_RETURN_UNWRAP() but works on cppgc-managed types
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4