[PATCH] D74300: [ORC] Add generic initializer/deinitializer support.

Lang Hames via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Mon Feb 17 12:57:54 PST 2020


lhames added a comment.

In D74300#1878463 <https://reviews.llvm.org/D74300#1878463>, @sgraenitz wrote:

> Will initializer symbols be looked up and run again when calling initialize() a second time on a JITDylib? More specifically, is it possible for a client to break this process down and initialize specific (or simply all uninitialized) MaterializationUnits? Otherwise, wouldn't it mean modules cannot be added (and initialized) to a JITDylib after initializiation (without re-init)?
>
>   lli orc-lazy             can we also do this?
>  
>   add all modules          add some modules <--
>   run all initializers     run their initializers <--
>   lookup                   lookup
>   materialize              materialize
>   execute                  execute, 
>   call-through             call-through
>   lookup                   lookup
>   materialize              add more modules <--
>   execute                  run their initializers <--
>   ...                      materialize
>                            execute
>


Whether the initializers would be re-run is up to the platform.

The platform gets two key pieces of information from ORC: setupJITDylib -- called when new dylibs are created, and notifyAdding -- called when modules are added to the JITDylib. Generally, Platform implementations will need to keep a list of initializers to be run and how this list is managed will determine the answer to your question. Here are some example schemes:

(1) //Prohibit any use of initializers//

This can be achieved by returning an error from Platform::notifyAdding override. The platform wouldn't provide an initialization API, because it could never do anything useful.

(2) //Allow support for exactly one round of initialization (this is your example above)//

This can be achieved by maintaining a set of already-initialized JITDylibs in the Platform instance. In the notifyAdding method, if the JITDylib is already in the initialized set then we return an error, e.g.:

  if (MU.getInitializerSymbol() != nullptr && AlreadyInitialized.count(&JD))
    make_error<StringError>("dylib " + JD.getName() + " has already been initialized. No new initializers can be added");

This is a sensible mode for a platform that's trying to emulate the execution environment of a normal statically compiled program. Arguably you could go even further and prohibit //any// new modules from being added after initialization, but this can be tricky: You'd need carve-outs for things like CompileOnDemandLayer's lazily compiled function/partition modules.

(3) //On initialization, run newly added initializers only//

This may be interesting to REPLs that want to allow new code (including initializers) to be added over time. In this case the Platform would maintain a list of not-yet-executed initializers. This would be appended to each time a new module is added via notifyAdding, and cleared when initializers are run. In this case a call to initialize is a no-op if no new initializers have been added since the last call.

(4) //Re-run all initializers every time//

I'm not sure who would want such a mode, but it's interesting to discuss as a prelude to something that is useful.

In this mode there would just be a list of initializers to run. New modules that contain initializers would append to this list, but it would never be cleared. Calling initialize (however it's defined for the platform) would run through the whole list each time, essentially resetting it to a state as if it had just been loaded, except that already compiled code would remain present in memory.

I don't think this is useful as a primary mode, but some variant of this might be useful as an addition to mode (2) if clients want to make dlclosing/re-dlopening a dylib relatively efficient by keeping the linked data and text in memory after dlclose is called. In that case you would modify (2) and replace the already-initialized set with a map from JITDylibs to their initializer list. Repeat dlopen operations would be no-ops, but a dlclose would transfer the already-run initializers back to a pending state so that they could be run again on the next dlopen.

>> Can we think of any use for gating on initializers having run, or should we rip this part back out for now to simplify the patch?
> 
> Not sure if this is related?

I don't think so. The initialized state gives JIT clients a way to do something that you can't do in static code, which is issue a lookup that's guaranteed not to return until the static initializers for the target have run.

I think I'm going to take this back out for now: We can always add it back in later, but there's no sense adding an experimental feature with no use case to an already complicated patch.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D74300/new/

https://reviews.llvm.org/D74300





More information about the llvm-commits mailing list