The name "Service" better reflects the general purpose of this class: It provides *something* (often resource management) to the Session, is owned by the Session, and receives notifications from the Session when the controller detaches / is detached, and when the Session is shut down. An example of a non-resource-managing Service (to be added in an upcoming patch) is a detach / shutdown notification service: Clients can add this service to register arbitrary callbacks to be run on detach / shutdown. The advantage of this over the current Session detach / shutdown callback system is that clients can control both the order of the callbacks, and their order relative to notification of other services.
121 lines
4.4 KiB
Markdown
121 lines
4.4 KiB
Markdown
# ORC Runtime Design
|
|
|
|
The ORC runtime provides APIs for *executor* processes in an ORC JIT session
|
|
(as opposed to the LLVM ORC libraries which provide APIs for *controller*
|
|
processes). This includes support for both JIT'd code itself, and for users
|
|
of JIT'd code.
|
|
|
|
## Background
|
|
|
|
LLVM's On Request Compilation (ORC) APIs support cross-process loading of JIT'd
|
|
code. We call the process that defines and links the JIT'd code the *controller*
|
|
and the process that executes JIT'd code the *executor*. Controller processes
|
|
will link LLVM's ORC library, and construct a JIT'd program using an
|
|
llvm::orc::ExecutionSession instance (typically through an convenience wrapper
|
|
like llvm::orc::LLJIT). Executor processes construct an `orc_rt::Session`
|
|
object to manage resources for, and access to, JIT'd code within the executor
|
|
process.
|
|
|
|
## APIs
|
|
|
|
### Session
|
|
|
|
The Session object is the root object for a JIT'd program. It owns the
|
|
Service instances that manage services and resources supporting JIT'd code
|
|
(e.g. JIT'd memory, unwind info registrations, dynamic library handles, etc.).
|
|
|
|
The Session object must be constructed prior to adding any JIT'd code, and must
|
|
outlive execution of any JIT'd code.
|
|
|
|
An executor may have more than one Session object, in which case each Session
|
|
object must outlive execution of any JIT'd code added to that specific session.
|
|
|
|
### ControllerAccess
|
|
|
|
ControllerAccess objects support bidirectional RPC between JIT'd code in the
|
|
executor and the ExecutionSession in the controller.
|
|
|
|
Calls in both directions are to "wrapper functions" with a fixed signature (a
|
|
function that takes a blob of bytes and returns a blob of bytes as its result).
|
|
ControllerAccess objects can not generally assume anything about the format of
|
|
the bytes being sent (their interpretation is up to the called function). The
|
|
RPC is not fully symmetric: Calls from the controller to the executor specify
|
|
wrapper function *addresses* (i.e. the controller can invoke any code in the
|
|
executor). Calls from the executor to the controller specify *tags*, which are
|
|
addresses in the executor processes that are associated with handlers in the
|
|
controller. This ensures that the executing process can only call deliberately
|
|
exposed entry points in the controller.
|
|
|
|
ControllerAccess objects may be detached before the session ends, at which point
|
|
JIT'd code may continue executing, but will receive no further calls from the
|
|
controller and can make no further calls to the controller.
|
|
|
|
### Service
|
|
|
|
`Service` is an interface for classes that provide services to the Session.
|
|
E.g. memory managers, or dynamic library loaders.
|
|
|
|
The `Service` interface provides two operations: `detach` and `shutdown`. The
|
|
`shutdown` operation will be called at `Session` destruction time. The `detach`
|
|
operation will be called if the controller detaches. Since this means that no
|
|
further requests for service will be made by the controller, Services may
|
|
implement this operation to abandon any fine-grained book-keeping that is
|
|
needed to provide ongoing services to the controller.
|
|
|
|
### TaskDispatcher
|
|
|
|
Runs Tasks within the ORC runtime. In particular, calls originating from the
|
|
controller (via ControllerAccess) will be dispatched as Tasks.
|
|
|
|
TaskDispatchers are responsible for ensuring that all dispatched Tasks have
|
|
completed or been destroyed during Session shutdown.
|
|
|
|
### WrapperFunction
|
|
|
|
A wrapper function is any function with the following C signature:
|
|
|
|
```c
|
|
void (orc_rt_SessionRef Session, uint64_t CallId,
|
|
orc_rt_WrapperFunctionReturn Return,
|
|
orc_rt_WrapperFunctionBuffer ArgBytes);
|
|
```
|
|
|
|
where `orc_rt_WrapperFunctionReturn` and `orc_rt_WrapperFunctionBuffer` are
|
|
defined as:
|
|
|
|
```c
|
|
typedef struct {
|
|
orc_rt_WrapperFunctionBufferDataUnion Data;
|
|
size_t Size;
|
|
} orc_rt_WrapperFunctionBuffer;
|
|
|
|
/**
|
|
* Asynchronous return function for an orc-rt wrapper function.
|
|
*/
|
|
typedef void (*orc_rt_WrapperFunctionReturn)(
|
|
orc_rt_SessionRef Session, uint64_t CallId,
|
|
orc_rt_WrapperFunctionBuffer ResultBytes);
|
|
```
|
|
|
|
The orc_rt::WrapperFunction class provides APIs for implementing and calling
|
|
wrapper functions.
|
|
|
|
### SPSWrapperFunction
|
|
|
|
An SPS wrapper function is a wrapper function that uses the
|
|
SimplePackedSerialization scheme (see documentation in
|
|
orc-rt/include/orc-rt/SimplePackedSerialization.h).
|
|
|
|
## TODO:
|
|
|
|
Document...
|
|
|
|
* C API
|
|
* Error handling
|
|
* RTTI
|
|
* ExecutorAddr / ExecutorAddrRange
|
|
* SimpleNativeMemoryMap
|
|
* Memory Access (unimplemented)
|
|
* Platform classes (unimplemented)
|
|
* Other utilities
|