It does 3 things:
- run the block only when precompilling (it incorporates
if ccall(:jl_generating_output, Cint, ()) == 1
) so that if you’re running with--compiled-modules=no
you don’t waste time - disables the interpreter when running the block (to ensure everything gets compiled)
- intercept runtime dispatch to force precompilation of calls to methods defined in other packages
Item 3 is the really new thing. To explain in detail, any call made by runtime dispatch will break the chain of backedges. If those backedges don’t link back to the currently-precompiling package, the type-inferred code won’t be cached in the precompile file. Thus if the callee is a method in your package, no sweat (it’s already in your package so will be cached), but if the (runtime-dispatched) callee is in Base
or elsewhere it won’t get precompiled by default on 1.8. @precompile_all_calls
fixes this by snooping on inference and recording all new entrances to inference; once the @precompile_all_calls
block exits it just iterates through the list of all newly-inferred MethodInstances and generates a manual precompile(f, (argtypes...))
command (which on 1.8 does force caching even if the method is external).
None of this is a concern for inferrable dispatch, because on Julia 1.8 all inferrable dispatch gets cached regardless of module ownership. This is really just to scoop up those runtime-dispatched dependencies.
This really eliminates the need to ever statically generate those precompile
directives, unless your workload has undesirable side-effects.