Skip to content

Commit 731c273

Browse files
committed
src: add WeakReference utility
Add a simple `WeakReference` utility that we can use until the language provides something on its own. PR-URL: #25993 Fixes: #23862 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de> Reviewed-By: Сковорода Никита Андреевич <chalkerx@gmail.com> Reviewed-By: Vladimir de Turckheim <vlad2t@hotmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Refael Ackermann <refack@gmail.com>
1 parent 663b625 commit 731c273

File tree

2 files changed

+60
-0
lines changed

2 files changed

+60
-0
lines changed

src/node_util.cc

+43
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "node_errors.h"
22
#include "node_watchdog.h"
33
#include "util.h"
4+
#include "base_object-inl.h"
45

56
namespace node {
67
namespace util {
@@ -11,6 +12,7 @@ using v8::Boolean;
1112
using v8::Context;
1213
using v8::Function;
1314
using v8::FunctionCallbackInfo;
15+
using v8::FunctionTemplate;
1416
using v8::IndexFilter;
1517
using v8::Integer;
1618
using v8::Isolate;
@@ -181,6 +183,37 @@ void EnqueueMicrotask(const FunctionCallbackInfo<Value>& args) {
181183
isolate->EnqueueMicrotask(args[0].As<Function>());
182184
}
183185

186+
class WeakReference : public BaseObject {
187+
public:
188+
WeakReference(Environment* env, Local<Object> object, Local<Object> target)
189+
: BaseObject(env, object) {
190+
MakeWeak();
191+
target_.Reset(env->isolate(), target);
192+
target_.SetWeak();
193+
}
194+
195+
static void New(const FunctionCallbackInfo<Value>& args) {
196+
Environment* env = Environment::GetCurrent(args);
197+
CHECK(args.IsConstructCall());
198+
CHECK(args[0]->IsObject());
199+
new WeakReference(env, args.This(), args[0].As<Object>());
200+
}
201+
202+
static void Get(const FunctionCallbackInfo<Value>& args) {
203+
WeakReference* weak_ref = Unwrap<WeakReference>(args.Holder());
204+
Isolate* isolate = args.GetIsolate();
205+
if (!weak_ref->target_.IsEmpty())
206+
args.GetReturnValue().Set(weak_ref->target_.Get(isolate));
207+
}
208+
209+
SET_MEMORY_INFO_NAME(WeakReference)
210+
SET_SELF_SIZE(WeakReference)
211+
SET_NO_MEMORY_INFO()
212+
213+
private:
214+
Persistent<Object> target_;
215+
};
216+
184217
void Initialize(Local<Object> target,
185218
Local<Value> unused,
186219
Local<Context> context,
@@ -241,6 +274,16 @@ void Initialize(Local<Object> target,
241274
should_abort_on_uncaught_toggle,
242275
env->should_abort_on_uncaught_toggle().GetJSArray())
243276
.FromJust());
277+
278+
Local<String> weak_ref_string =
279+
FIXED_ONE_BYTE_STRING(env->isolate(), "WeakReference");
280+
Local<FunctionTemplate> weak_ref =
281+
env->NewFunctionTemplate(WeakReference::New);
282+
weak_ref->InstanceTemplate()->SetInternalFieldCount(1);
283+
weak_ref->SetClassName(weak_ref_string);
284+
env->SetProtoMethod(weak_ref, "get", WeakReference::Get);
285+
target->Set(context, weak_ref_string,
286+
weak_ref->GetFunction(context).ToLocalChecked()).FromJust();
244287
}
245288

246289
} // namespace util
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Flags: --expose-internals --expose-gc
2+
'use strict';
3+
require('../common');
4+
const assert = require('assert');
5+
const { internalBinding } = require('internal/test/binding');
6+
const { WeakReference } = internalBinding('util');
7+
8+
let obj = { hello: 'world' };
9+
const ref = new WeakReference(obj);
10+
assert.strictEqual(ref.get(), obj);
11+
12+
setImmediate(() => {
13+
obj = null;
14+
global.gc();
15+
16+
assert.strictEqual(ref.get(), undefined);
17+
});

0 commit comments

Comments
 (0)