To support module caching, module path indexes must be cloned
for each use of the cached module, so that path resolutions
don't collide. Cloning was previously implemented at the point
of shifting the modidx based on the module instantiation name,
but now its cloned at declaration time. This result in better
sharing of module-path resolutions, which in turn speeds up
compile-time instantiation of modules, which in turn speeds up
interactions & examples in documentation (as much as 10% for the
Guide, for example).
Furthermore, the reverse cache within a modidx may have been
used improperly during cloning, and that's not a problem in
the new implementation.
Doc rendering has been occasionally crashing in Pixman/Cairo. It might
have something to do with a non-atomic callback, so let's try avoiding
that, first. (If that doesn't work, the next step is to avoid using
Cairo in a multi-threaded way, for which this is a first step, too.)
The JIT wants to detect calls to functions bound to module-level
variables that are always instantiated to a procedure of a particular
arity, in which case it can avoid some checks. The problem is that
bytecode and JITted code can be shared via the module cache across
namespaces that use different modules to implement a particular module
path or that enable the JIT differently. In particular, starting with
one that has a procedure binding and then using one (in a different
namespace) that has a non-procedure binding could lead to a crash.
Defend against this possibility by never treating imported variables
as constant in that sense. The JIT detects imported variables through
a new import map in the prefix.
This change may slow code. My guess is that it will have no
performance impact in practice, due to cross-module inlining,
although I can construct a microbenchmark that slows by 20%.