From 7ecc1845c4f364660e66a42c5745d6d7225b76b6 Mon Sep 17 00:00:00 2001 From: Brian Warner Date: Mon, 26 Oct 2020 13:05:48 -0700 Subject: [PATCH] fix: add stubs for GC tools (no-op on Node v12) The upcoming GC functionality will require `WeakRef` and `FinalizationRegistry`. Node.js v14 provides these as globals, but v12 does not (there might be a command-line flag to enable it, but I think it's marked as experimental). Rather than require all users upgrade to v14, we elect to disable GC when running on v12. This adds a local `weakref.js` module which attempts to pull `WeakRef` and `FinalizationRegistry` from the global, and exports either the real constructors or no-op stubs. refs #1872 refs #1925 --- packages/SwingSet/src/weakref.js | 38 +++++++++++++++++++++ packages/SwingSet/test/test-fake-weakref.js | 23 +++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 packages/SwingSet/src/weakref.js create mode 100644 packages/SwingSet/test/test-fake-weakref.js diff --git a/packages/SwingSet/src/weakref.js b/packages/SwingSet/src/weakref.js new file mode 100644 index 00000000000..205220378fd --- /dev/null +++ b/packages/SwingSet/src/weakref.js @@ -0,0 +1,38 @@ +/* global globalThis */ + +/* + * We retain a measure of compatibility with Node.js v12, which does not + * expose WeakRef or FinalizationRegistry (there is a --flag for it, but it's + * * not clear how stable it is). When running on a platform without these * + * tools, vats cannot do GC, and the tools they get will be no-ops. WeakRef + * instances will hold a strong reference, and the FinalizationRegistry will + * never invoke the callbacks. + * + * Modules should do: + * + * import { WeakRef, FinalizationRegistry } from '.../weakref'; + * + */ + +function FakeWeakRef(obj) { + const wr = Object.create({ + deref: () => obj, + }); + delete wr.constructor; + return wr; +} + +function FakeFinalizationRegistry(_callback) { + const fr = Object.create({ + register: (_obj, _handle) => undefined, + unregister: _handle => undefined, + }); + delete fr.constructor; + return fr; +} + +const WR = globalThis.WeakRef || FakeWeakRef; +const FR = globalThis.FinalizationRegistry || FakeFinalizationRegistry; + +export const WeakRef = WR; +export const FinalizationRegistry = FR; diff --git a/packages/SwingSet/test/test-fake-weakref.js b/packages/SwingSet/test/test-fake-weakref.js new file mode 100644 index 00000000000..75fc5025fe3 --- /dev/null +++ b/packages/SwingSet/test/test-fake-weakref.js @@ -0,0 +1,23 @@ +import '@agoric/install-ses'; +import test from 'ava'; +import { WeakRef, FinalizationRegistry } from '../src/weakref'; + +// We don't test that WeakRefs actually work, we only make sure we can +// interact with them without crashing. This exercises the fake no-op WeakRef +// and FinalizationRegistry that our `src/weakref.js` creates on Node.js v12. +// On v14 we get real constructors. + +test('weakref is callable', async t => { + const obj = {}; + const wr = new WeakRef(obj); + t.is(obj, wr.deref()); + + const callback = () => 0; + const fr = new FinalizationRegistry(callback); + fr.register(obj); + + const obj2 = {}; + const handle = {}; + fr.register(obj2, handle); + fr.unregister(handle); +});