00:48
<Richard Gibson>

ljharb: I have a not-yet-committed version of what you're looking for; the ultimate fallback really is memory allocations. Simplified version:

const enqueueTask = callback => {
  const id = setTimeout(callback);
  return () => clearTimeout(id);
};
const gcWatches = new FinalizationRegistry(([callback, data]) => void callback(data));
const whenCollected = (target, data = undefined) =>
  new Promise(resolve => gcWatches.register(target, [resolve, data]));
const watchGC = (target, data = undefined) => {
  const collected = whenCollected(target, data);
  let retained = true;
  collected.then(() => { retained = false; });
  // Return a new promise that waits for GC plus a turn (in case the GC promise
  // of the new sentinel object fulfills before that of the target) and then
  // fulfills with the then-current retention status of the target.
  const isRetained = () => whenCollected({}).then().then(() => retained);
  return { collected, isRetained };
};
const forceCollectionP = (async () => {
  let garbageScale = 2 ** 16;
  const tryTriggerGC = () => void new Uint8Array(garbageScale);
  const forceGC = async (patience = 1000) => {
    const sentinelCollectedP = whenCollected({});

    // Wait a turn to clear the stack, then add pressure in a sequence of prompt jobs.
    await null;
    let reject;
    const pressureP = new Promise((...resolvers) => { reject = resolvers[1]; });
    void pressureP.catch(() => {});
    let jobCount = 0;
    let abortNextJob = () => {};
    const abort = () => {
      abortNextJob();
      reject();
      patience = 0;
    };
    (function startNextJob() {
      if (!(jobCount < patience)) return reject(Error(`failed to GC after ${jobCount} attempts`));
      tryTriggerGC();
      jobCount++;
      abortNextJob = enqueueTask(startNextJob);
    })();
    await Promise.race([sentinelCollectedP, pressureP]);
    abort();

    // Try to tune garbageScale for forcing GC in one job.
    if (jobCount > 1 && garbageScale > 0 && garbageScale < 2 ** 28) garbageScale *= 2;

    return { jobCount };
  };

  // Run sanity checks before releasing the function.
  await forceGC();
  const weakmap = new WeakMap();
  let { fastKeyWatch, slowKeyWatch, slowKey } = (() => {
    const fastKey = {};
    const slowKey = {};
    weakmap.set(fastKey, 'fast-gc sanity check');
    weakmap.set(slowKey, 'slow-gc sanity check');
    const fastKeyWatch = watchGC(fastKey);
    const slowKeyWatch = watchGC(slowKey);
    return { fastKeyWatch, slowKeyWatch, slowKey };
  })();
  const fastKeyRetainedP = fastKeyWatch.isRetained();
  const slowKeyRetainedP = slowKeyWatch.isRetained();
  await forceGC();
  if (await fastKeyRetainedP) throw Error('fast-gc key was not collected!');
  if (!(await slowKeyRetainedP)) throw Error('slow-gc key was collected early!');
  const slowKeyStillRetainedP = slowKeyWatch.isRetained();
  slowKey = null;
  await forceGC();
  if (await slowKeyStillRetainedP) throw Error('slow-gc key was not collected!');

  return forceGC;
})();

const forceGC = await forceCollectionP;
03:05
<Domenic>
Bikeshedding help requested for an error type that includes properties with how much X is available, versus how much X you requested: https://github.com/whatwg/webidl/issues/1463
20:29
<Matthew Dean>
Hi all!
20:30
<Matthew Dean>
How would one submit a proposal to TC39?
20:30
<Michael Ficarra>
https://github.com/tc39/ecma262/blob/main/CONTRIBUTING.md
20:32
<Matthew Dean>
🤔 I've been going through that, and I see that proposals are separate repos... but... you can't make a PR to submit a whole repo, can you?
20:32
<Matthew Dean>
It's related to: https://github.com/matthew-dean/proposal-hash-comments
20:32
<Michael Ficarra>
yes, proposals are self-contained repos
20:32
<Michael Ficarra>
they don't become PRs until much later in the process
20:33
<Matthew Dean>
How would I move this under tc39 though?
20:34
<Michael Ficarra>
from the CONTRIBUTING.md document,

If you have a new proposal you want to get into the language, you first need a TC39 "champion": a member of the committee who will make the case for the proposal at in-person TC39 meetings and help it move through the process. If you are a TC39 member, you can be a champion; otherwise, find a TC39 member to work with for this (e.g., through the TC39 discussion group or the Matrix chat room). Proposals may have multiple champions (a "champion group").
20:34
<Matthew Dean>
ah ok
20:34
<Matthew Dean>
So I have to find my champion a la Game of Thrones-style?
20:35
<Michael Ficarra>
so you'll need to convince at least one delegate that it's worthwhile, and once it has been presented, it will be moved within the TC39 org
20:35
<Matthew Dean>
got it
20:35
<Michael Ficarra>
not familiar with the GoT process, but you can find champions both on here or on Discourse
20:36
<Michael Ficarra>
Discourse is probably better since it's less synchronous and less ephemeral
20:36
<Matthew Dean>
The Game of Thrones was a dumb joke reference to an episode
20:38
<Matthew Dean>
But anyway, thanks for the help!
20:43
<Michael Ficarra>
no problem