day-3.mjs
December 26, 2021 ยท View on GitHub
///////////////////////////////////////////////////////////////////////////////
// Day 3 - Disappearing Act //
// #region problem //
///////////////////////////////////////////////////////////////////////////////
// Write a hold(toHold) function that returns a frozen Object with a //
// non-getter property .value set to toHold. //
// //
// Write a second function free(result) that when given the result of //
// hold(obj) allows the .value of result to be freed without GC of //
// result. //
///////////////////////////////////////////////////////////////////////////////
/**
- @template {unknown} T
- @param {T} toHold
- @returns {Readonly<{value: T}>} */ function hold(toHold) { // ... }
/**
- @template {{value: unknown}} T
- @param {T} result
- @returns {void} */ function free(result) { // ... }
/////////////////////////////////////////////////////////////////////////////// // #endregion problem // ///////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////// // Test - Leave code after this alone // // #region test // ///////////////////////////////////////////////////////////////////////////////
import assert from 'node:assert/strict';
// keep the process alive indefinitely so we can wait for the GC check setInterval(() => { // this makes the FinalizationRegistry fire faster, VM magics if (!finalizer) { console.log(finalizer) } [].concat(0); [].concat(0); [].concat(0); [].concat(0); }, 0); const finalizer = new FinalizationRegistry((err) => { if (err) { console.error(err); } process.exit(err ? 1 : 0); });
let value = new class EasyToFindInHeapSnapshot {}; finalizer.register(value, '');
// exports don't GC since they live on as long as the module does export const holder = hold(value); assert.ok(Object.isFrozen(holder), 'result should be frozen'); assert.ok(Object.hasOwn(holder, 'value'));
// holder shouldn't be GC'd, we need to show that the solution doesn't require // the holder to be GC'd finalizer.register(holder, 'result should not be GC'd, how did you get here?');
let descriptor = Object.getOwnPropertyDescriptor(holder, 'value'); assert.ok(Object.hasOwn(descriptor, 'value')) assert.strictEqual( descriptor?.value, value, 'result .value should equal the value given to hold(toHold)' ); assert.strictEqual( descriptor?.writable, false, 'result .value should be non-writable to be frozen' ); assert.strictEqual( descriptor.configurable, false, 'result .value should be non-configurable to be frozen' ); descriptor = null; value = null;
free(holder);
/////////////////////////////////////////////////////////////////////////////// // #endregion test // ///////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////// // Hints - Encoded in ROT13 encoded // // #region hints // /////////////////////////////////////////////////////////////////////////////// // // // Fvzcyr: Cebkl unf inevbhf jnlf gb cerirag npprff gb cebcregvrf rira jura // // vgf gnetrg vf sebmra. // // // /////////////////////////////////////////////////////////////////////////////// // #endregion hints // ///////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////// // Use Cases // // #region uses // /////////////////////////////////////////////////////////////////////////////// // // // This kind of workflow can help be used for debugging to ensure that a // // value is not accessed after some point in time. The fact that a value can // // be GC'd shows it isn't accessible anymore. // // // /////////////////////////////////////////////////////////////////////////////// // #endregion uses // ///////////////////////////////////////////////////////////////////////////////