Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitd482ddb

Browse files
committed
src: create BaseObject with node::Realm
BaseObject is a wrapper around JS objects. These objects should becreated in a node::Realm and destroyed when their associated realm iscleaning up.
1 parent0a297ff commitd482ddb

14 files changed

+464
-367
lines changed

‎node.gyp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,7 @@
465465
'src/api/hooks.cc',
466466
'src/api/utils.cc',
467467
'src/async_wrap.cc',
468+
'src/base_object.cc',
468469
'src/cares_wrap.cc',
469470
'src/connect_wrap.cc',
470471
'src/connection_wrap.cc',

‎src/api/embed_helpers.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ Maybe<int> SpinEventLoop(Environment* env) {
6868
env->set_snapshot_serialize_callback(Local<Function>());
6969

7070
env->PrintInfoForSnapshotIfDebug();
71-
env->VerifyNoStrongBaseObjects();
71+
env->principal_realm()->VerifyNoStrongBaseObjects();
7272
returnEmitProcessExit(env);
7373
}
7474

‎src/base_object-inl.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@
3232

3333
namespacenode {
3434

35+
BaseObject::BaseObject(Environment* env, v8::Local<v8::Object> object)
36+
: BaseObject(env->principal_realm(), object) {}
37+
3538
// static
3639
v8::Local<v8::FunctionTemplate>BaseObject::GetConstructorTemplate(
3740
Environment* env) {
@@ -63,7 +66,11 @@ v8::Local<v8::Object> BaseObject::object(v8::Isolate* isolate) const {
6366
}
6467

6568
Environment*BaseObject::env()const {
66-
return env_;
69+
return realm_->env();
70+
}
71+
72+
Realm*BaseObject::realm()const {
73+
return realm_;
6774
}
6875

6976
BaseObject*BaseObject::FromJSObject(v8::Local<v8::Value> value) {

‎src/base_object.cc

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
#include"base_object.h"
2+
#include"env-inl.h"
3+
#include"node_realm-inl.h"
4+
5+
namespacenode {
6+
7+
using v8::FunctionCallbackInfo;
8+
using v8::FunctionTemplate;
9+
using v8::HandleScope;
10+
using v8::Local;
11+
using v8::Object;
12+
using v8::Value;
13+
using v8::WeakCallbackInfo;
14+
using v8::WeakCallbackType;
15+
16+
BaseObject::BaseObject(Realm* realm, Local<Object> object)
17+
: persistent_handle_(realm->isolate(), object), realm_(realm) {
18+
CHECK_EQ(false, object.IsEmpty());
19+
CHECK_GE(object->InternalFieldCount(), BaseObject::kInternalFieldCount);
20+
object->SetAlignedPointerInInternalField(BaseObject::kEmbedderType,
21+
&kNodeEmbedderId);
22+
object->SetAlignedPointerInInternalField(BaseObject::kSlot,
23+
static_cast<void*>(this));
24+
realm->AddCleanupHook(DeleteMe,static_cast<void*>(this));
25+
realm->modify_base_object_count(1);
26+
}
27+
28+
BaseObject::~BaseObject() {
29+
realm()->modify_base_object_count(-1);
30+
realm()->RemoveCleanupHook(DeleteMe,static_cast<void*>(this));
31+
32+
if (UNLIKELY(has_pointer_data())) {
33+
PointerData* metadata =pointer_data();
34+
CHECK_EQ(metadata->strong_ptr_count,0);
35+
metadata->self =nullptr;
36+
if (metadata->weak_ptr_count ==0)delete metadata;
37+
}
38+
39+
if (persistent_handle_.IsEmpty()) {
40+
// This most likely happened because the weak callback below cleared it.
41+
return;
42+
}
43+
44+
{
45+
HandleScopehandle_scope(env()->isolate());
46+
object()->SetAlignedPointerInInternalField(BaseObject::kSlot,nullptr);
47+
}
48+
}
49+
50+
voidBaseObject::MakeWeak() {
51+
if (has_pointer_data()) {
52+
pointer_data()->wants_weak_jsobj =true;
53+
if (pointer_data()->strong_ptr_count >0)return;
54+
}
55+
56+
persistent_handle_.SetWeak(
57+
this,
58+
[](const WeakCallbackInfo<BaseObject>& data) {
59+
BaseObject* obj = data.GetParameter();
60+
// Clear the persistent handle so that ~BaseObject() doesn't attempt
61+
// to mess with internal fields, since the JS object may have
62+
// transitioned into an invalid state.
63+
// Refs: https://github.com/nodejs/node/issues/18897
64+
obj->persistent_handle_.Reset();
65+
CHECK_IMPLIES(obj->has_pointer_data(),
66+
obj->pointer_data()->strong_ptr_count ==0);
67+
obj->OnGCCollect();
68+
},
69+
WeakCallbackType::kParameter);
70+
}
71+
72+
// This just has to be different from the Chromium ones:
73+
// https://source.chromium.org/chromium/chromium/src/+/main:gin/public/gin_embedders.h;l=18-23;drc=5a758a97032f0b656c3c36a3497560762495501a
74+
// Otherwise, when Node is loaded in an isolate which uses cppgc, cppgc will
75+
// misinterpret the data stored in the embedder fields and try to garbage
76+
// collect them.
77+
uint16_tkNodeEmbedderId =0x90de;
78+
79+
voidBaseObject::LazilyInitializedJSTemplateConstructor(
80+
const FunctionCallbackInfo<Value>& args) {
81+
DCHECK(args.IsConstructCall());
82+
CHECK_GE(args.This()->InternalFieldCount(), BaseObject::kInternalFieldCount);
83+
args.This()->SetAlignedPointerInInternalField(BaseObject::kEmbedderType,
84+
&kNodeEmbedderId);
85+
args.This()->SetAlignedPointerInInternalField(BaseObject::kSlot,nullptr);
86+
}
87+
88+
Local<FunctionTemplate>BaseObject::MakeLazilyInitializedJSTemplate(
89+
Environment* env) {
90+
Local<FunctionTemplate> t =NewFunctionTemplate(
91+
env->isolate(), LazilyInitializedJSTemplateConstructor);
92+
t->Inherit(BaseObject::GetConstructorTemplate(env));
93+
t->InstanceTemplate()->SetInternalFieldCount(BaseObject::kInternalFieldCount);
94+
return t;
95+
}
96+
97+
BaseObject::PointerData*BaseObject::pointer_data() {
98+
if (!has_pointer_data()) {
99+
PointerData* metadata =newPointerData();
100+
metadata->wants_weak_jsobj = persistent_handle_.IsWeak();
101+
metadata->self =this;
102+
pointer_data_ = metadata;
103+
}
104+
CHECK(has_pointer_data());
105+
return pointer_data_;
106+
}
107+
108+
voidBaseObject::decrease_refcount() {
109+
CHECK(has_pointer_data());
110+
PointerData* metadata =pointer_data();
111+
CHECK_GT(metadata->strong_ptr_count,0);
112+
unsignedint new_refcount = --metadata->strong_ptr_count;
113+
if (new_refcount ==0) {
114+
if (metadata->is_detached) {
115+
OnGCCollect();
116+
}elseif (metadata->wants_weak_jsobj && !persistent_handle_.IsEmpty()) {
117+
MakeWeak();
118+
}
119+
}
120+
}
121+
122+
voidBaseObject::increase_refcount() {
123+
unsignedint prev_refcount =pointer_data()->strong_ptr_count++;
124+
if (prev_refcount ==0 && !persistent_handle_.IsEmpty())
125+
persistent_handle_.ClearWeak();
126+
}
127+
128+
voidBaseObject::DeleteMe(void* data) {
129+
BaseObject* self =static_cast<BaseObject*>(data);
130+
if (self->has_pointer_data() && self->pointer_data()->strong_ptr_count >0) {
131+
return self->Detach();
132+
}
133+
delete self;
134+
}
135+
136+
boolBaseObject::IsDoneInitializing()const {
137+
returntrue;
138+
}
139+
140+
Local<Object>BaseObject::WrappedObject()const {
141+
returnobject();
142+
}
143+
144+
boolBaseObject::IsRootNode()const {
145+
return !persistent_handle_.IsWeak();
146+
}
147+
148+
Local<FunctionTemplate>BaseObject::GetConstructorTemplate(
149+
IsolateData* isolate_data) {
150+
Local<FunctionTemplate> tmpl = isolate_data->base_object_ctor_template();
151+
if (tmpl.IsEmpty()) {
152+
tmpl =NewFunctionTemplate(isolate_data->isolate(),nullptr);
153+
tmpl->SetClassName(
154+
FIXED_ONE_BYTE_STRING(isolate_data->isolate(),"BaseObject"));
155+
isolate_data->set_base_object_ctor_template(tmpl);
156+
}
157+
return tmpl;
158+
}
159+
160+
boolBaseObject::IsNotIndicativeOfMemoryLeakAtExit()const {
161+
returnIsWeakOrDetached();
162+
}
163+
164+
}// namespace node

‎src/base_object.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ namespace node {
3232

3333
classEnvironment;
3434
classIsolateData;
35+
classRealm;
3536
template<typename T,boolkIsWeak>
3637
classBaseObjectPtrImpl;
3738

@@ -47,7 +48,10 @@ class BaseObject : public MemoryRetainer {
4748

4849
// Associates this object with `object`. It uses the 1st internal field for
4950
// that, and in particular aborts if there is no such field.
50-
BaseObject(Environment* env, v8::Local<v8::Object> object);
51+
// This is the designated constructor.
52+
BaseObject(Realm* realm, v8::Local<v8::Object> object);
53+
// Convenient constructor for constructing BaseObject in the principal realm.
54+
inlineBaseObject(Environment* env, v8::Local<v8::Object> object);
5155
~BaseObject()override;
5256

5357
BaseObject() =delete;
@@ -63,6 +67,7 @@ class BaseObject : public MemoryRetainer {
6367
inline v8::Global<v8::Object>&persistent();
6468

6569
inline Environment*env()const;
70+
inline Realm*realm()const;
6671

6772
// Get a BaseObject* pointer, or subclass pointer, for the JS object that
6873
// was also passed to the `BaseObject()` constructor initially.
@@ -91,6 +96,7 @@ class BaseObject : public MemoryRetainer {
9196
// Utility to create a FunctionTemplate with one internal field (used for
9297
// the `BaseObject*` pointer) and a constructor that initializes that field
9398
// to `nullptr`.
99+
// TODO(@legendecas): Disentangle template with env.
94100
static v8::Local<v8::FunctionTemplate>MakeLazilyInitializedJSTemplate(
95101
Environment* env);
96102

@@ -213,7 +219,7 @@ class BaseObject : public MemoryRetainer {
213219
voiddecrease_refcount();
214220
voidincrease_refcount();
215221

216-
Environment* env_;
222+
Realm* realm_;
217223
PointerData* pointer_data_ =nullptr;
218224
};
219225

‎src/env-inl.h

Lines changed: 0 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -793,48 +793,6 @@ void Environment::RemoveCleanupHook(CleanupCallback fn, void* arg) {
793793
cleanup_hooks_.erase(search);
794794
}
795795

796-
size_tCleanupHookCallback::Hash::operator()(
797-
const CleanupHookCallback& cb)const {
798-
return std::hash<void*>()(cb.arg_);
799-
}
800-
801-
boolCleanupHookCallback::Equal::operator()(
802-
const CleanupHookCallback& a,const CleanupHookCallback& b)const {
803-
return a.fn_ == b.fn_ && a.arg_ == b.arg_;
804-
}
805-
806-
BaseObject*CleanupHookCallback::GetBaseObject()const {
807-
if (fn_ == BaseObject::DeleteMe)
808-
returnstatic_cast<BaseObject*>(arg_);
809-
else
810-
returnnullptr;
811-
}
812-
813-
template<typename T>
814-
voidEnvironment::ForEachBaseObject(T&& iterator) {
815-
for (constauto& hook : cleanup_hooks_) {
816-
BaseObject* obj = hook.GetBaseObject();
817-
if (obj !=nullptr)
818-
iterator(obj);
819-
}
820-
}
821-
822-
voidEnvironment::modify_base_object_count(int64_t delta) {
823-
base_object_count_ += delta;
824-
}
825-
826-
int64_tEnvironment::base_object_count()const {
827-
return base_object_count_;
828-
}
829-
830-
inlinevoidEnvironment::set_base_object_created_by_bootstrap(int64_t count) {
831-
base_object_created_by_bootstrap_ = base_object_count_;
832-
}
833-
834-
int64_tEnvironment::base_object_created_after_bootstrap()const {
835-
return base_object_count_ - base_object_created_by_bootstrap_;
836-
}
837-
838796
voidEnvironment::set_main_utf16(std::unique_ptr<v8::String::Value> str) {
839797
CHECK(!main_utf16_);
840798
main_utf16_ =std::move(str);

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp