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

Commitb11616b

Browse files
joyeecheungdanielleadams
authored andcommitted
src: support WeakReference in snapshot
Move util::WeakReference to a separate header and implement{de}serialization for it to be snapshotable.PR-URL:#44193Refs:#44014Refs:#37476Reviewed-By: Matteo Collina <matteo.collina@gmail.com>Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
1 parent1ca5755 commitb11616b

File tree

9 files changed

+246
-38
lines changed

9 files changed

+246
-38
lines changed

‎node.gyp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -643,6 +643,7 @@
643643
'src/node_stat_watcher.h',
644644
'src/node_union_bytes.h',
645645
'src/node_url.h',
646+
'src/node_util.h',
646647
'src/node_version.h',
647648
'src/node_v8.h',
648649
'src/node_v8_platform-inl.h',

‎src/node_snapshotable.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include"node_metadata.h"
1717
#include"node_process.h"
1818
#include"node_snapshot_builder.h"
19+
#include"node_util.h"
1920
#include"node_v8.h"
2021
#include"node_v8_platform-inl.h"
2122

‎src/node_snapshotable.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ class ExternalReferenceRegistry;
1818
V(fs_binding_data, fs::BindingData) \
1919
V(v8_binding_data, v8_utils::BindingData) \
2020
V(blob_binding_data, BlobBindingData) \
21-
V(process_binding_data, process::BindingData)
21+
V(process_binding_data, process::BindingData) \
22+
V(util_weak_reference, util::WeakReference)
2223

2324
enumclassEmbedderObjectType :uint8_t {
2425
#defineV(PropertyName, NativeType) k_##PropertyName,

‎src/node_util.cc

Lines changed: 92 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#include"node_util.h"
12
#include"base_object-inl.h"
23
#include"node_errors.h"
34
#include"node_external_reference.h"
@@ -15,7 +16,7 @@ using v8::Context;
1516
using v8::External;
1617
using v8::FunctionCallbackInfo;
1718
using v8::FunctionTemplate;
18-
using v8::Global;
19+
using v8::HandleScope;
1920
using v8::IndexFilter;
2021
using v8::Integer;
2122
using v8::Isolate;
@@ -207,52 +208,106 @@ void ArrayBufferViewHasBuffer(const FunctionCallbackInfo<Value>& args) {
207208
args.GetReturnValue().Set(args[0].As<ArrayBufferView>()->HasBuffer());
208209
}
209210

210-
classWeakReference :publicBaseObject {
211-
public:
212-
WeakReference(Environment* env, Local<Object> object, Local<Object> target)
213-
: BaseObject(env, object) {
214-
MakeWeak();
211+
WeakReference::WeakReference(Environment* env,
212+
Local<Object> object,
213+
Local<Object> target)
214+
: WeakReference(env, object, target,0) {}
215+
216+
WeakReference::WeakReference(Environment* env,
217+
Local<Object> object,
218+
Local<Object> target,
219+
uint64_t reference_count)
220+
: SnapshotableObject(env, object, type_int),
221+
reference_count_(reference_count) {
222+
MakeWeak();
223+
if (!target.IsEmpty()) {
215224
target_.Reset(env->isolate(), target);
216-
target_.SetWeak();
225+
if (reference_count_ ==0) {
226+
target_.SetWeak();
227+
}
217228
}
229+
}
218230

219-
staticvoidNew(const FunctionCallbackInfo<Value>& args) {
220-
Environment* env =Environment::GetCurrent(args);
221-
CHECK(args.IsConstructCall());
222-
CHECK(args[0]->IsObject());
223-
newWeakReference(env, args.This(), args[0].As<Object>());
231+
boolWeakReference::PrepareForSerialization(Local<Context> context,
232+
v8::SnapshotCreator* creator) {
233+
if (target_.IsEmpty()) {
234+
target_index_ =0;
235+
returntrue;
224236
}
225237

226-
staticvoidGet(const FunctionCallbackInfo<Value>& args) {
227-
WeakReference* weak_ref = Unwrap<WeakReference>(args.Holder());
228-
Isolate* isolate = args.GetIsolate();
229-
if (!weak_ref->target_.IsEmpty())
230-
args.GetReturnValue().Set(weak_ref->target_.Get(isolate));
231-
}
238+
// Users can still hold strong references to target in addition to the
239+
// reference that we manage here, and they could expect that the referenced
240+
// object remains the same as long as that external strong reference
241+
// is alive. Since we have no way to know if there is any other reference
242+
// keeping the target alive, the best we can do to maintain consistency is to
243+
// simply save a reference to the target in the snapshot (effectively making
244+
// it strong) during serialization, and restore it during deserialization.
245+
// If there's no known counted reference from our side, we'll make the
246+
// reference here weak upon deserialization so that it can be GC'ed if users
247+
// do not hold additional references to it.
248+
Local<Object> target = target_.Get(context->GetIsolate());
249+
target_index_ = creator->AddData(context, target);
250+
DCHECK_NE(target_index_,0);
251+
target_.Reset();
252+
returntrue;
253+
}
232254

233-
staticvoidIncRef(const FunctionCallbackInfo<Value>& args) {
234-
WeakReference* weak_ref = Unwrap<WeakReference>(args.Holder());
235-
weak_ref->reference_count_++;
236-
if (weak_ref->target_.IsEmpty())return;
237-
if (weak_ref->reference_count_ ==1) weak_ref->target_.ClearWeak();
238-
}
255+
InternalFieldInfoBase*WeakReference::Serialize(int index) {
256+
DCHECK_EQ(index, BaseObject::kEmbedderType);
257+
InternalFieldInfo* info =
258+
InternalFieldInfoBase::New<InternalFieldInfo>(type());
259+
info->target = target_index_;
260+
info->reference_count = reference_count_;
261+
return info;
262+
}
239263

240-
staticvoidDecRef(const FunctionCallbackInfo<Value>& args) {
241-
WeakReference* weak_ref = Unwrap<WeakReference>(args.Holder());
242-
CHECK_GE(weak_ref->reference_count_,1);
243-
weak_ref->reference_count_--;
244-
if (weak_ref->target_.IsEmpty())return;
245-
if (weak_ref->reference_count_ ==0) weak_ref->target_.SetWeak();
264+
voidWeakReference::Deserialize(Local<Context> context,
265+
Local<Object> holder,
266+
int index,
267+
InternalFieldInfoBase* info) {
268+
DCHECK_EQ(index, BaseObject::kEmbedderType);
269+
HandleScopescope(context->GetIsolate());
270+
271+
InternalFieldInfo* weak_info =reinterpret_cast<InternalFieldInfo*>(info);
272+
Local<Object> target;
273+
if (weak_info->target !=0) {
274+
target = context->GetDataFromSnapshotOnce<Object>(weak_info->target)
275+
.ToLocalChecked();
246276
}
277+
newWeakReference(Environment::GetCurrent(context),
278+
holder,
279+
target,
280+
weak_info->reference_count);
281+
}
282+
283+
voidWeakReference::New(const FunctionCallbackInfo<Value>& args) {
284+
Environment* env =Environment::GetCurrent(args);
285+
CHECK(args.IsConstructCall());
286+
CHECK(args[0]->IsObject());
287+
newWeakReference(env, args.This(), args[0].As<Object>());
288+
}
289+
290+
voidWeakReference::Get(const FunctionCallbackInfo<Value>& args) {
291+
WeakReference* weak_ref = Unwrap<WeakReference>(args.Holder());
292+
Isolate* isolate = args.GetIsolate();
293+
if (!weak_ref->target_.IsEmpty())
294+
args.GetReturnValue().Set(weak_ref->target_.Get(isolate));
295+
}
247296

248-
SET_MEMORY_INFO_NAME(WeakReference)
249-
SET_SELF_SIZE(WeakReference)
250-
SET_NO_MEMORY_INFO()
297+
voidWeakReference::IncRef(const FunctionCallbackInfo<Value>& args) {
298+
WeakReference* weak_ref = Unwrap<WeakReference>(args.Holder());
299+
weak_ref->reference_count_++;
300+
if (weak_ref->target_.IsEmpty())return;
301+
if (weak_ref->reference_count_ ==1) weak_ref->target_.ClearWeak();
302+
}
251303

252-
private:
253-
Global<Object> target_;
254-
uint64_t reference_count_ =0;
255-
};
304+
voidWeakReference::DecRef(const FunctionCallbackInfo<Value>& args) {
305+
WeakReference* weak_ref = Unwrap<WeakReference>(args.Holder());
306+
CHECK_GE(weak_ref->reference_count_,1);
307+
weak_ref->reference_count_--;
308+
if (weak_ref->target_.IsEmpty())return;
309+
if (weak_ref->reference_count_ ==0) weak_ref->target_.SetWeak();
310+
}
256311

257312
staticvoidGuessHandleType(const FunctionCallbackInfo<Value>& args) {
258313
Environment* env =Environment::GetCurrent(args);

‎src/node_util.h

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
2+
#ifndef SRC_NODE_UTIL_H_
3+
#defineSRC_NODE_UTIL_H_
4+
5+
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
6+
#include"base_object.h"
7+
#include"node_snapshotable.h"
8+
#include"v8.h"
9+
10+
namespacenode {
11+
namespaceutil {
12+
13+
classWeakReference :publicSnapshotableObject {
14+
public:
15+
SERIALIZABLE_OBJECT_METHODS();
16+
17+
staticconstexpr FastStringKey type_name{"node::util::WeakReference"};
18+
staticconstexpr EmbedderObjectType type_int =
19+
EmbedderObjectType::k_util_weak_reference;
20+
21+
WeakReference(Environment* env,
22+
v8::Local<v8::Object> object,
23+
v8::Local<v8::Object> target);
24+
staticvoidNew(const v8::FunctionCallbackInfo<v8::Value>& args);
25+
staticvoidGet(const v8::FunctionCallbackInfo<v8::Value>& args);
26+
staticvoidIncRef(const v8::FunctionCallbackInfo<v8::Value>& args);
27+
staticvoidDecRef(const v8::FunctionCallbackInfo<v8::Value>& args);
28+
29+
SET_MEMORY_INFO_NAME(WeakReference)
30+
SET_SELF_SIZE(WeakReference)
31+
SET_NO_MEMORY_INFO()
32+
33+
structInternalFieldInfo :publicnode::InternalFieldInfoBase {
34+
SnapshotIndex target;
35+
uint64_t reference_count;
36+
};
37+
38+
private:
39+
WeakReference(Environment* env,
40+
v8::Local<v8::Object> object,
41+
v8::Local<v8::Object> target,
42+
uint64_t reference_count);
43+
v8::Global<v8::Object> target_;
44+
uint64_t reference_count_ =0;
45+
46+
SnapshotIndex target_index_ =0;// 0 means target_ is not snapshotted
47+
};
48+
49+
}// namespace util
50+
}// namespace node
51+
52+
#endif// defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
53+
54+
#endif// SRC_NODE_UTIL_H_

‎src/util.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include"node_buffer.h"
2828
#include"node_errors.h"
2929
#include"node_internals.h"
30+
#include"node_util.h"
3031
#include"string_bytes.h"
3132
#include"uv.h"
3233

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
'use strict';
2+
3+
const{ internalBinding}=require('internal/test/binding');
4+
const{ WeakReference}=internalBinding('util');
5+
const{
6+
setDeserializeMainFunction
7+
}=require('v8').startupSnapshot
8+
constassert=require('assert');
9+
10+
letobj={hello:'world'};
11+
constref=newWeakReference(obj);
12+
13+
setDeserializeMainFunction(()=>{
14+
obj=null;
15+
globalThis.gc();
16+
17+
setImmediate(()=>{
18+
assert.strictEqual(ref.get(),undefined);
19+
});
20+
});
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
'use strict';
2+
3+
const{ internalBinding}=require('internal/test/binding');
4+
const{ WeakReference}=internalBinding('util');
5+
const{
6+
setDeserializeMainFunction
7+
}=require('v8').startupSnapshot
8+
constassert=require('assert');
9+
10+
letobj={hello:'world'};
11+
constref=newWeakReference(obj);
12+
13+
setDeserializeMainFunction(()=>{
14+
assert.strictEqual(ref.get(),obj);
15+
});
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
'use strict';
2+
3+
// This tests that weak references work across serialization.
4+
5+
require('../common');
6+
constassert=require('assert');
7+
const{ spawnSync}=require('child_process');
8+
consttmpdir=require('../common/tmpdir');
9+
constfixtures=require('../common/fixtures');
10+
constpath=require('path');
11+
constfs=require('fs');
12+
13+
tmpdir.refresh();
14+
constblobPath=path.join(tmpdir.path,'snapshot.blob');
15+
16+
functionrunTest(entry){
17+
console.log('running test with',entry);
18+
{
19+
constchild=spawnSync(process.execPath,[
20+
'--expose-internals',
21+
'--expose-gc',
22+
'--snapshot-blob',
23+
blobPath,
24+
'--build-snapshot',
25+
entry,
26+
],{
27+
cwd:tmpdir.path
28+
});
29+
if(child.status!==0){
30+
console.log(child.stderr.toString());
31+
console.log(child.stdout.toString());
32+
assert.strictEqual(child.status,0);
33+
}
34+
conststats=fs.statSync(path.join(tmpdir.path,'snapshot.blob'));
35+
assert(stats.isFile());
36+
}
37+
38+
{
39+
constchild=spawnSync(process.execPath,[
40+
'--expose-internals',
41+
'--expose-gc',
42+
'--snapshot-blob',
43+
blobPath,
44+
],{
45+
cwd:tmpdir.path,
46+
env:{
47+
...process.env,
48+
}
49+
});
50+
51+
conststdout=child.stdout.toString().trim();
52+
conststderr=child.stderr.toString().trim();
53+
console.log(`[stdout]:\n${stdout}\n`);
54+
console.log(`[stderr]:\n${stderr}\n`);
55+
assert.strictEqual(child.status,0);
56+
}
57+
}
58+
59+
runTest(fixtures.path('snapshot','weak-reference.js'));
60+
runTest(fixtures.path('snapshot','weak-reference-gc.js'));

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp