@@ -296,18 +296,49 @@ TBD: absolute symbols, aliases, off-the-shelf layers.
296
296
Laziness
297
297
========
298
298
299
- Laziness in ORC is provided by a utility called "lazy-reexports". The aim of
300
- this utility is to re-use the synchronization provided by the symbol lookup
301
- mechanism to make it safe to lazily compile functions, even if calls to the
302
- stub occur simultaneously on multiple threads of JIT'd code. It does this by
303
- reducing lazy compilation to symbol lookup: The lazy stub performs a lookup of
304
- its underlying definition on first call, updating the function body pointer
305
- once the definition is available. If additional calls arrive on other threads
306
- while compilation is ongoing they will be safely blocked by the normal lookup
307
- synchronization guarantee (no result until the result is safe) and can also
308
- proceed as soon as compilation completes.
309
-
310
- TBD: Usage example.
299
+ Laziness in ORC is provided by a utility called "lazy reexports". A lazy
300
+ reexport is similar to a regular reexport or alias: It provides a new name for
301
+ an existing symbol. Unlike regular reexports however, lookups of lazy reexports
302
+ do not trigger immediate materialization of the reexported symbol. Instead, they
303
+ only trigger materialization of a function stub. This function stub is
304
+ initialized to point at a *lazy call-through *, which provides reentry into the
305
+ JIT. If the stub is called at runtime then the lazy call-through will look up
306
+ the reexported symbol (triggering materialization for it if necessary), update
307
+ the stub (to call directly to the reexported symbol on subsequent calls), and
308
+ then return via the reexported symbol. By re-using the existing symbol lookup
309
+ mechanism, lazy reexports inherit the same concurrency guarantees: calls to lazy
310
+ reexports can be made from multiple threads concurrently, and the reexported
311
+ symbol can be any state of compilation (uncompiled, already in the process of
312
+ being compiled, or already compiled) and the call will succeed. This allows
313
+ laziness to be safely mixed with features like remote compilation, concurrent
314
+ compilation, concurrent JIT'd code, and speculative compilation.
315
+
316
+ There is one other key difference between regular reexports and lazy reexports
317
+ that some clients must be aware of: The address of a lazy reexport will be
318
+ *different * from the address of the reexported symbol (whereas a regular
319
+ reexport is guaranteed to have the same address as the reexported symbol).
320
+ Clients who care about pointer equality will generally want to use the address
321
+ of the reexport as the canonical address of the reexported symbol. This will
322
+ allow the address to be taken without forcing materialization of the reexport.
323
+
324
+ Usage example:
325
+
326
+ If JITDylib ``JD `` contains definitions for symbols ``foo_body `` and
327
+ ``bar_body ``, we can create lazy entry points ``Foo `` and ``Bar `` in JITDylib
328
+ ``JD2 `` by calling:
329
+
330
+ .. code-block :: c++
331
+
332
+ auto ReexportFlags = JITSymbolFlags::Exported | JITSymbolFlags::Callable;
333
+ JD2.define(
334
+ lazyReexports(CallThroughMgr, StubsMgr, JD,
335
+ SymbolAliasMap({
336
+ { Mangle("foo"), { Mangle("foo_body"), ReexportedFlags } },
337
+ { Mangle("bar"), { Mangle("bar_body"), ReexportedFlags } }
338
+ }));
339
+
340
+ A full example of how to use lazyReexports with the LLJIT class can be found at
341
+ ``llvm_project/llvm/examples/LLJITExamples/LLJITWithLazyReexports ``.
311
342
312
343
Supporting Custom Compilers
313
344
===========================
0 commit comments