Hi Alexis,
The points you've figured out are correct so far, to answer some of your questions:
>
But I don’t actually understand what interpreterDynamic means! The
Haddock comment just says that it determines whether or not the
“interpreter uses the Dynamic way”, but I don’t see why that matters. My
understanding was that GHCi always requires dynamic linking,
since it is, after all, loading code dynamically.
DynamicWay essentially means whether or not the runtime linker uses the platform linker under the hood. When dynamic way your object files will be linked into a shared library by the RTS linker and that shared library loaded.
This means that the linker itself doesn't have to do a bunch of work such as relocation processing etc. For most Unix platforms this is the default.
The downside of this approach is that on every change, i.e. if you load a new object file into scope, you have to relink the shared library, unload the old one, and link the new one in. This brings with it its own set of problems, such as what happens to references you already hold to symbols on the old shared library etc.
>
Under what
circumstances would interpreterDynamic ever be False?
For instance, on Windows. Linking on Windows using the system linker is generally slower, so creating multiple shared libraries on the fly is time consuming. There are also some practical issues, for instance base is so big that it doesn't fit into a single DLL.
or how Windows handles data and code accesses to symbols Shared libraries, etc. This means that on Windows we load object files and internally do all relocation processing, run initializers etc. Everything you would need to do to be able to run the code inside the object file.
There are several other platforms as well, such as Android, where there's no system linker to call etc.
>
In the case that interpreterDynamic is True, GHC appears to convert the
desired dyn_o object into a shared library by calling the system
linker, then loads that, which can be very slow but otherwise works.
However, when interpreterDynamic is False, it loads the object directly.
Both paths eventually call into “the RTS linker”, implemented in
rts/Linker.c, to actually load the resulting object.
Yes, the end goal is to be able to resolve a function name to an address. So whichever strategy is chosen, we must in the end register the functions with the RTS. Though loading a shared lib is much less error prone than loading the object files directly. It also uses less memory and can benefit from linker level optimizations that we don't implement in the RTS linker. Also loading a shared library has additional benefits such as that the system loader deals with running initializers, registering exception tables, etc.
Hope this clarified it somewhat, but if you have any more questions feel free to ask.
Regards,
Tamar