From c12711ebfeaf482be1cbccc748f6ae428e097420 Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Mon, 7 Aug 2023 16:28:56 +0200 Subject: [PATCH] lib: implement WeakReference on top of JS WeakRef The C++ implementation can now be done entirely in JS using WeakRef. Re-implement it in JS instead to simplify the code. PR-URL: https://github.com/nodejs/node/pull/49053 Reviewed-By: Anna Henningsen Reviewed-By: Yagiz Nizipli Reviewed-By: Rafael Gonzaga Reviewed-By: Benjamin Gruenbaum --- lib/diagnostics_channel.js | 2 +- lib/domain.js | 3 +- lib/internal/util.js | 34 +++++++++++++++++++ test/fixtures/snapshot/weak-reference-gc.js | 3 +- test/fixtures/snapshot/weak-reference.js | 3 +- .../test-internal-util-weakreference.js | 3 +- 6 files changed, 39 insertions(+), 9 deletions(-) diff --git a/lib/diagnostics_channel.js b/lib/diagnostics_channel.js index dae0e930a395e9..10d35054f56535 100644 --- a/lib/diagnostics_channel.js +++ b/lib/diagnostics_channel.js @@ -28,7 +28,7 @@ const { const { triggerUncaughtException } = internalBinding('errors'); -const { WeakReference } = internalBinding('util'); +const { WeakReference } = require('internal/util'); // Can't delete when weakref count reaches 0 as it could increment again. // Only GC can be used as a valid time to clean up the channels map. diff --git a/lib/domain.js b/lib/domain.js index 51565795d72010..7da672a3691560 100644 --- a/lib/domain.js +++ b/lib/domain.js @@ -52,9 +52,8 @@ const { const { createHook } = require('async_hooks'); const { useDomainTrampoline } = require('internal/async_hooks'); -// TODO(addaleax): Use a non-internal solution for this. const kWeak = Symbol('kWeak'); -const { WeakReference } = internalBinding('util'); +const { WeakReference } = require('internal/util'); // Overwrite process.domain with a getter/setter that will allow for more // effective optimizations diff --git a/lib/internal/util.js b/lib/internal/util.js index 1e1a647e693876..3586084ba7b8bd 100644 --- a/lib/internal/util.js +++ b/lib/internal/util.js @@ -33,6 +33,7 @@ const { SafeMap, SafeSet, SafeWeakMap, + SafeWeakRef, StringPrototypeReplace, StringPrototypeToLowerCase, StringPrototypeToUpperCase, @@ -797,6 +798,38 @@ function guessHandleType(fd) { return handleTypes[type]; } +class WeakReference { + #weak = null; + #strong = null; + #refCount = 0; + constructor(object) { + this.#weak = new SafeWeakRef(object); + } + + incRef() { + this.#refCount++; + if (this.#refCount === 1) { + const derefed = this.#weak.deref(); + if (derefed !== undefined) { + this.#strong = derefed; + } + } + return this.#refCount; + } + + decRef() { + this.#refCount--; + if (this.#refCount === 0) { + this.#strong = null; + } + return this.#refCount; + } + + get() { + return this.#weak.deref(); + } +} + module.exports = { getLazy, assertCrypto, @@ -855,4 +888,5 @@ module.exports = { kEnumerableProperty, setOwnProperty, pendingDeprecate, + WeakReference, }; diff --git a/test/fixtures/snapshot/weak-reference-gc.js b/test/fixtures/snapshot/weak-reference-gc.js index 8dada530e77c2a..b6af6c46e3829a 100644 --- a/test/fixtures/snapshot/weak-reference-gc.js +++ b/test/fixtures/snapshot/weak-reference-gc.js @@ -1,7 +1,6 @@ 'use strict'; -const { internalBinding } = require('internal/test/binding'); -const { WeakReference } = internalBinding('util'); +const { WeakReference } = require('internal/util'); const { setDeserializeMainFunction } = require('v8').startupSnapshot diff --git a/test/fixtures/snapshot/weak-reference.js b/test/fixtures/snapshot/weak-reference.js index 214d52fee185fe..1aefc6a1c07195 100644 --- a/test/fixtures/snapshot/weak-reference.js +++ b/test/fixtures/snapshot/weak-reference.js @@ -1,7 +1,6 @@ 'use strict'; -const { internalBinding } = require('internal/test/binding'); -const { WeakReference } = internalBinding('util'); +const { WeakReference } = require('internal/util'); const { setDeserializeMainFunction } = require('v8').startupSnapshot diff --git a/test/parallel/test-internal-util-weakreference.js b/test/parallel/test-internal-util-weakreference.js index 75a00176bb095b..ef3c0943b1f83e 100644 --- a/test/parallel/test-internal-util-weakreference.js +++ b/test/parallel/test-internal-util-weakreference.js @@ -2,8 +2,7 @@ 'use strict'; const common = require('../common'); const assert = require('assert'); -const { internalBinding } = require('internal/test/binding'); -const { WeakReference } = internalBinding('util'); +const { WeakReference } = require('internal/util'); let obj = { hello: 'world' }; const ref = new WeakReference(obj);