[source]

compiler/main/StaticPtrTable.hs

Note [Grand plan for static forms]

[note link]

Static forms go through the compilation phases as follows. Here is a running example:

f x = let k = map toUpper
in …(static k)…
  • The renamer looks for out-of-scope names in the body of the static form, as always. If all names are in scope, the free variables of the body are stored in AST at the location of the static form.
  • The typechecker verifies that all free variables occurring in the static form are floatable to top level (see Note [Meaning of IdBindingInfo] in TcRnTypes). In our example, ‘k’ is floatable. Even though it is bound in a nested let, we are fine.
  • The desugarer replaces the static form with an application of the function ‘makeStatic’ (defined in module GHC.StaticPtr.Internal of base). So we get
f x = let k = map toUpper
      in ...fromStaticPtr (makeStatic location k)...
  • The simplifier runs the FloatOut pass which moves the calls to ‘makeStatic’ to the top level. Thus the FloatOut pass is always executed, even when optimizations are disabled. So we get
k = map toUpper
static_ptr = makeStatic location k
f x = ...fromStaticPtr static_ptr...
The FloatOut pass is careful to produce an /exported/ Id for a floated ‘makeStatic’ call, so the binding is not removed or inlined by the simplifier. E.g. the code for f above might look like
static_ptr = makeStatic location k
f x = ...(case static_ptr of ...)...
which might be simplified to
f x = ...(case makeStatic location k of ...)...
BUT the top-level binding for static_ptr must remain, so that it can be
collected to populate the Static Pointer Table.
Making the binding exported also has a necessary effect during the CoreTidy pass.
  • The CoreTidy pass replaces all bindings of the form
b = /\ ... -> makeStatic location value
with
b = /\ ... -> StaticPtr key (StaticPtrInfo "pkg key" "module" location) value
where a distinct key is generated for each binding.
  • If we are compiling to object code we insert a C stub (generated by sptModuleInitCode) into the final object which runs when the module is loaded, inserting the static forms defined by the module into the RTS’s static pointer table.
  • If we are compiling for the byte-code interpreter, we instead explicitly add the SPT entries (recorded in CgGuts’ cg_spt_entries field) to the interpreter process’ SPT table using the addSptEntry interpreter message. This happens in upsweep after we have compiled the module (see GhcMake.upsweep’).