Skip to content

Commit b9ea23c

Browse files
addaleaxMylesBorins
authored andcommitted
src: add WeakReference utility
Add a simple `WeakReference` utility that we can use until the language provides something on its own. Backport-PR-URL: #27749 PR-URL: #25993 Fixes: #23862 Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: Ruben Bridgewater <[email protected]> Reviewed-By: Сковорода Никита Андреевич <[email protected]> Reviewed-By: Vladimir de Turckheim <[email protected]> Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: Refael Ackermann <[email protected]>
1 parent ec02117 commit b9ea23c

File tree

2 files changed

+61
-0
lines changed

2 files changed

+61
-0
lines changed

src/node_util.cc

+44
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "node_internals.h"
22
#include "node_watchdog.h"
3+
#include "base_object-inl.h"
34

45
namespace node {
56
namespace util {
@@ -9,8 +10,10 @@ using v8::Array;
910
using v8::Boolean;
1011
using v8::Context;
1112
using v8::FunctionCallbackInfo;
13+
using v8::FunctionTemplate;
1214
using v8::IndexFilter;
1315
using v8::Integer;
16+
using v8::Isolate;
1417
using v8::KeyCollectionMode;
1518
using v8::Local;
1619
using v8::NewStringType;
@@ -178,6 +181,37 @@ void SafeGetenv(const FunctionCallbackInfo<Value>& args) {
178181
NewStringType::kNormal).ToLocalChecked());
179182
}
180183

184+
class WeakReference : public BaseObject {
185+
public:
186+
WeakReference(Environment* env, Local<Object> object, Local<Object> target)
187+
: BaseObject(env, object) {
188+
MakeWeak();
189+
target_.Reset(env->isolate(), target);
190+
target_.SetWeak();
191+
}
192+
193+
static void New(const FunctionCallbackInfo<Value>& args) {
194+
Environment* env = Environment::GetCurrent(args);
195+
CHECK(args.IsConstructCall());
196+
CHECK(args[0]->IsObject());
197+
new WeakReference(env, args.This(), args[0].As<Object>());
198+
}
199+
200+
static void Get(const FunctionCallbackInfo<Value>& args) {
201+
WeakReference* weak_ref = Unwrap<WeakReference>(args.Holder());
202+
Isolate* isolate = args.GetIsolate();
203+
if (!weak_ref->target_.IsEmpty())
204+
args.GetReturnValue().Set(weak_ref->target_.Get(isolate));
205+
}
206+
207+
SET_MEMORY_INFO_NAME(WeakReference)
208+
SET_SELF_SIZE(WeakReference)
209+
SET_NO_MEMORY_INFO()
210+
211+
private:
212+
Persistent<Object> target_;
213+
};
214+
181215
void Initialize(Local<Object> target,
182216
Local<Value> unused,
183217
Local<Context> context) {
@@ -235,6 +269,16 @@ void Initialize(Local<Object> target,
235269
target->Set(context,
236270
FIXED_ONE_BYTE_STRING(env->isolate(), "propertyFilter"),
237271
constants).FromJust();
272+
273+
Local<String> weak_ref_string =
274+
FIXED_ONE_BYTE_STRING(env->isolate(), "WeakReference");
275+
Local<FunctionTemplate> weak_ref =
276+
env->NewFunctionTemplate(WeakReference::New);
277+
weak_ref->InstanceTemplate()->SetInternalFieldCount(1);
278+
weak_ref->SetClassName(weak_ref_string);
279+
env->SetProtoMethod(weak_ref, "get", WeakReference::Get);
280+
target->Set(context, weak_ref_string,
281+
weak_ref->GetFunction(context).ToLocalChecked()).FromJust();
238282
}
239283

240284
} // 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)