src: add WeakReference utility
Add a simple `WeakReference` utility that we can use until the language provides something on its own. PR-URL: https://github.com/nodejs/node/pull/25993 Fixes: https://github.com/nodejs/node/issues/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>
This commit is contained in:
parent
0a4c69a5c5
commit
8679932607
@ -1,6 +1,7 @@
|
||||
#include "node_errors.h"
|
||||
#include "node_watchdog.h"
|
||||
#include "util.h"
|
||||
#include "base_object-inl.h"
|
||||
|
||||
namespace node {
|
||||
namespace util {
|
||||
@ -11,6 +12,7 @@ using v8::Boolean;
|
||||
using v8::Context;
|
||||
using v8::Function;
|
||||
using v8::FunctionCallbackInfo;
|
||||
using v8::FunctionTemplate;
|
||||
using v8::IndexFilter;
|
||||
using v8::Integer;
|
||||
using v8::Isolate;
|
||||
@ -181,6 +183,37 @@ void EnqueueMicrotask(const FunctionCallbackInfo<Value>& args) {
|
||||
isolate->EnqueueMicrotask(args[0].As<Function>());
|
||||
}
|
||||
|
||||
class WeakReference : public BaseObject {
|
||||
public:
|
||||
WeakReference(Environment* env, Local<Object> object, Local<Object> target)
|
||||
: BaseObject(env, object) {
|
||||
MakeWeak();
|
||||
target_.Reset(env->isolate(), target);
|
||||
target_.SetWeak();
|
||||
}
|
||||
|
||||
static void New(const FunctionCallbackInfo<Value>& args) {
|
||||
Environment* env = Environment::GetCurrent(args);
|
||||
CHECK(args.IsConstructCall());
|
||||
CHECK(args[0]->IsObject());
|
||||
new WeakReference(env, args.This(), args[0].As<Object>());
|
||||
}
|
||||
|
||||
static void Get(const FunctionCallbackInfo<Value>& args) {
|
||||
WeakReference* weak_ref = Unwrap<WeakReference>(args.Holder());
|
||||
Isolate* isolate = args.GetIsolate();
|
||||
if (!weak_ref->target_.IsEmpty())
|
||||
args.GetReturnValue().Set(weak_ref->target_.Get(isolate));
|
||||
}
|
||||
|
||||
SET_MEMORY_INFO_NAME(WeakReference)
|
||||
SET_SELF_SIZE(WeakReference)
|
||||
SET_NO_MEMORY_INFO()
|
||||
|
||||
private:
|
||||
Persistent<Object> target_;
|
||||
};
|
||||
|
||||
void Initialize(Local<Object> target,
|
||||
Local<Value> unused,
|
||||
Local<Context> context,
|
||||
@ -241,6 +274,16 @@ void Initialize(Local<Object> target,
|
||||
should_abort_on_uncaught_toggle,
|
||||
env->should_abort_on_uncaught_toggle().GetJSArray())
|
||||
.FromJust());
|
||||
|
||||
Local<String> weak_ref_string =
|
||||
FIXED_ONE_BYTE_STRING(env->isolate(), "WeakReference");
|
||||
Local<FunctionTemplate> weak_ref =
|
||||
env->NewFunctionTemplate(WeakReference::New);
|
||||
weak_ref->InstanceTemplate()->SetInternalFieldCount(1);
|
||||
weak_ref->SetClassName(weak_ref_string);
|
||||
env->SetProtoMethod(weak_ref, "get", WeakReference::Get);
|
||||
target->Set(context, weak_ref_string,
|
||||
weak_ref->GetFunction(context).ToLocalChecked()).FromJust();
|
||||
}
|
||||
|
||||
} // namespace util
|
||||
|
17
test/parallel/test-internal-util-weakreference.js
Normal file
17
test/parallel/test-internal-util-weakreference.js
Normal file
@ -0,0 +1,17 @@
|
||||
// Flags: --expose-internals --expose-gc
|
||||
'use strict';
|
||||
require('../common');
|
||||
const assert = require('assert');
|
||||
const { internalBinding } = require('internal/test/binding');
|
||||
const { WeakReference } = internalBinding('util');
|
||||
|
||||
let obj = { hello: 'world' };
|
||||
const ref = new WeakReference(obj);
|
||||
assert.strictEqual(ref.get(), obj);
|
||||
|
||||
setImmediate(() => {
|
||||
obj = null;
|
||||
global.gc();
|
||||
|
||||
assert.strictEqual(ref.get(), undefined);
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user