Ephemerons explained
lists.squeakfoundation.org
lists.squeakfoundation.org
There it's the WeakMap type: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
WeakMap prevents observing when the weakly referenced key objects are garbage collected. It does this by being deliberately non-enumerable (see the MDN link). So it may be considered missing part of the definition of ephemerons. It has the weak-key part without the finalizer part.
But modern browsers support WeakRef and FinalizationRegistry, which eventually reveal when objects have been garbage collected. https://v8.dev/features/weak-references, https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe... and https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
So this part of the WeakMap design is just an annoying obstacle which can be worked around.
(Note, as FinalizationRegistry is designed to accompany WeakRef, it's intriguing that MDN lists Opera as supporting FinalizationRegistry but not WeakRef.)
A WeakMap M is a table of entries, each of which maps a key K to a value V. If you have the M and K in hand, you can use them to look up V. (And if you don't have either one, then you can't!)
From a GC perspective, each entry is an edge that says that V is alive if both M and K are alive[1]. (And if either of them dies, then the entry no longer serves to keep anything alive. Note the parallelism with the above parenthetical.)
They're mostly useful for associating a value V with some other object K without modifying K. They're sort of an annotation mechanism. If you tried to do that with a regular Map, then you would have to manually remove any Ks that you wanted to go away.
In implementation terms, ...y'know, why don't I write it up as a blog post: https://blog.mozilla.org/sfink/2022/06/09/ephemeron-tables-a...
[1] Note that WeakMaps are not "weak" in the sense of weak references; the name WeakMap is a bit of a misnomer. Normal weak things can be skipped during marking. After liveness is determined, you'll check to see if they're still alive. You can't skip ephemeron edges like this! They're strong edges and it's invalid to throw away a V if its M and K are live. But EphemeronTable is a bit long...
Multiple cycles are not fundamental to ephemeron collection, though. If you keep all of your unmarked keys (specifically, keys of ephemeron tables that have been marked) in a lookup table, then in theory every time you mark anything you could look it up in that table to see if you need to traverse an ephemeron edge. In practice, you probably don't want to do those lookups until you've traversed the "easy" part of the heap that doesn't require traversing ephemerons to get to.
Source: that's how I implemented it in SpiderMonkey: https://searchfox.org/mozilla-central/rev/552bfc6334b797d92f...