Copy a dependency's values when they are read
Why
Forcing a dependency's components copied every value of its interface with the module path substitution, although a dependent reads only a few of them: on a 552-module app, about 5 % of the values of .cmi components are ever read.
For the components of a .cmi signature as it was read, values are now table cells that make the copy on first read. Type ids are allocated in order and end up in .cmt files and in which nodes the backtracking trail logs, so the copies keep their ids: once the process has built the components of the same .cmi contents (same CRC) eagerly, it knows how many type ids each value takes, reserves them when the components are built and makes the copy with exactly those ids when the value is read. A copy that takes a different number is made again with fresh ids, like the deferred signature copies, and counted per domain for the tests. One-shot bsc and the first use of an interface in a build still build eagerly. Types, constructors, labels, extension constructors, module types, submodules and components of anything else (aliases, functor applications, local modules) are built as before.
The tables of an open take the cells too: an open keeps a function giving the binding of each component, and the bindings Env.copy_types replaces through an open in a table checked before the components.
Review
- Can a deferred copy differ from the eager one apart from when it is made? The copied values are the unmarshalled .cmi signature, which the type checker never sees (it only gets copies), and the copy takes no stamps; the type ids are the eager ones, so every later stamp and id, and every operation on the copied nodes, is the same. The new unit tests compare marshalled results of eager and deferred components over every runtime interface, and whole requests (outputs, .cmt and error messages) using functors, aliases, include, module type of, recursive modules, shadowing and first-class modules, also on several domains at once.
- Are the cells shared between requests or domains? No: components belong to the persistent structures of one request; only the count table is shared, behind a mutex, and its arrays are not changed once recorded.