class Concurrent::AbstractLocals

@!visibility private @!macro internal_implementation_note

An abstract implementation of local storage, with sub-classes for per-thread and per-fiber locals.

Each execution context (EC, thread or fiber) has a lazily initialized array of local variable values. Each time a new local variable is created, we allocate an “index” for it.

For example, if the allocated index is 1, that means slot #1 in EVERY EC’s locals array will be used for the value of that variable.

The good thing about using a per-EC structure to hold values, rather than a global, is that no synchronization is needed when reading and writing those values (since the structure is only ever accessed by a single thread).

Of course, when a local variable is GC’d, 1) we need to recover its index for use by other new local variables (otherwise the locals arrays could get bigger and bigger with time), and 2) we need to null out all the references held in the now-unused slots (both to avoid blocking GC of those objects, and also to prevent “stale” values from being passed on to a new local when the index is reused).

Because we need to null out freed slots, we need to keep references to ALL the locals arrays, so we can null out the appropriate slots in all of them. This is why we need to use a finalizer to clean up the locals array when the EC goes out of scope.