Skip to content

Commit

Permalink
src: add WeakReference utility
Browse files Browse the repository at this point in the history
Add a simple `WeakReference` utility that we can use until the
language provides something on its own.

PR-URL: nodejs#25993
Fixes: nodejs#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]>
  • Loading branch information
addaleax authored and MylesBorins committed May 17, 2019
1 parent ec02117 commit 19fd3a0
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 0 deletions.
44 changes: 44 additions & 0 deletions src/node_util.cc
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "node_internals.h"
#include "node_watchdog.h"
#include "base_object-inl.h"

namespace node {
namespace util {
Expand All @@ -9,8 +10,10 @@ using v8::Array;
using v8::Boolean;
using v8::Context;
using v8::FunctionCallbackInfo;
using v8::FunctionTemplate;
using v8::IndexFilter;
using v8::Integer;
using v8::Isolate;
using v8::KeyCollectionMode;
using v8::Local;
using v8::NewStringType;
Expand Down Expand Up @@ -178,6 +181,37 @@ void SafeGetenv(const FunctionCallbackInfo<Value>& args) {
NewStringType::kNormal).ToLocalChecked());
}

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) {
Expand Down Expand Up @@ -235,6 +269,16 @@ void Initialize(Local<Object> target,
target->Set(context,
FIXED_ONE_BYTE_STRING(env->isolate(), "propertyFilter"),
constants).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
Expand Down
17 changes: 17 additions & 0 deletions test/parallel/test-internal-util-weakreference.js
Original file line number Diff line number Diff line change
@@ -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);
});

0 comments on commit 19fd3a0

Please sign in to comment.