|
| 1 | +# ORC Runtime Design |
| 2 | + |
| 3 | +The ORC runtime provides APIs for *executor* processes in an ORC JIT session |
| 4 | +(as opposed to the LLVM ORC libraries which provide APIs for *controller* |
| 5 | +processes). This includes support for both JIT'd code itself, and for users |
| 6 | +of JIT'd code. |
| 7 | + |
| 8 | +## Background |
| 9 | + |
| 10 | +LLVM's On Request Compilation (ORC) APIs support cross-process loading of JIT'd |
| 11 | +code. We call the process that defines and links the JIT'd code the *controller* |
| 12 | +and the process that executes JIT'd code the *executor*. Controller processes |
| 13 | +will link LLVM's ORC library, and construct a JIT'd program using an |
| 14 | +llvm::orc::ExecutionSession instance (typically through an convenience wrapper |
| 15 | +like llvm::orc::LLJIT). Executor processes construct an `orc_rt::Session` |
| 16 | +object to manage resources for, and access to, JIT'd code within the executor |
| 17 | +process. |
| 18 | + |
| 19 | +## APIs |
| 20 | + |
| 21 | +### Session |
| 22 | + |
| 23 | +The Session object is the root object for a JIT'd program. It owns the |
| 24 | +ResourceManager instances that manage resources supporting JIT'd code (e.g. |
| 25 | +JIT'd memory, unwind info registrations, dynamic library handles, etc.). |
| 26 | + |
| 27 | +The Session object must be constructed prior to adding any JIT'd code, and must |
| 28 | +outlive execution of any JIT'd code. |
| 29 | + |
| 30 | +An executor may have more than one Session object, in which case each Session |
| 31 | +object must outlive execution of any JIT'd code added to that specific session. |
| 32 | + |
| 33 | +### ControllerAccess |
| 34 | + |
| 35 | +ControllerAccess objects support bidirectional RPC between JIT'd code in the |
| 36 | +executor and the ExecutionSession in the controller. |
| 37 | + |
| 38 | +Calls in both directions are to "wrapper functions" with a fixed signature (a |
| 39 | +function that takes a blob of bytes and returns a blob of bytes as its result). |
| 40 | +ControllerAccess objects can not generally assume anything about the format of |
| 41 | +the bytes being sent (their interpretation is up to the called function). The |
| 42 | +RPC is not fully symmetric: Calls from the controller to the executor specify |
| 43 | +wrapper function *addresses* (i.e. the controller can invoke any code in the |
| 44 | +executor). Calls from the executor to the controller specify *tags*, which are |
| 45 | +addresses in the executor processes that are associated with handlers in the |
| 46 | +controller. This ensures that the executing process can only call deliberately |
| 47 | +exposed entry points in the controller. |
| 48 | + |
| 49 | +ControllerAccess objects may be detached before the session ends, at which point |
| 50 | +JIT'd code may continue executing, but will receive no further calls from the |
| 51 | +controller and can make no further calls to the controller. |
| 52 | + |
| 53 | +### ResourceManager |
| 54 | + |
| 55 | +`ResourceManager` is an interface for classes that manage resources that support |
| 56 | +a JIT'd program, for example memory or loaded dylib handles. It provides two |
| 57 | +operations: `detach` and `shutdown`. The `shutdown` operation will be called at |
| 58 | +`Session` destruction time. The `detach` operation may be called if the |
| 59 | +controller detaches: since this means that no further requests for resource |
| 60 | +allocation or release will occur prior to the end of the Session |
| 61 | +ResourceManagers may implement this operation to abandon any fine-grained |
| 62 | +tracking or pre-reserved resources (e.g. address space). |
| 63 | + |
| 64 | +### TaskDispatcher |
| 65 | + |
| 66 | +Runs Tasks within the ORC runtime. In particular, calls originating from the |
| 67 | +controller (via ControllerAccess) will be dispatched as Tasks. |
| 68 | + |
| 69 | +TaskDispatchers are responsible for ensuring that all dispatched Tasks have |
| 70 | +completed or been destroyed during Session shutdown. |
| 71 | + |
| 72 | +### WrapperFunction |
| 73 | + |
| 74 | +A wrapper function is any function with the following C signature: |
| 75 | + |
| 76 | +```c |
| 77 | +void (orc_rt_SessionRef Session, uint64_t CallId, |
| 78 | + orc_rt_WrapperFunctionReturn Return, |
| 79 | + orc_rt_WrapperFunctionBuffer ArgBytes); |
| 80 | +``` |
| 81 | + |
| 82 | +where `orc_rt_WrapperFunctionReturn` and `orc_rt_WrapperFunctionBuffer` are |
| 83 | +defined as: |
| 84 | + |
| 85 | +```c |
| 86 | +typedef struct { |
| 87 | + orc_rt_WrapperFunctionBufferDataUnion Data; |
| 88 | + size_t Size; |
| 89 | +} orc_rt_WrapperFunctionBuffer; |
| 90 | + |
| 91 | +/** |
| 92 | + * Asynchronous return function for an orc-rt wrapper function. |
| 93 | + */ |
| 94 | +typedef void (*orc_rt_WrapperFunctionReturn)( |
| 95 | + orc_rt_SessionRef Session, uint64_t CallId, |
| 96 | + orc_rt_WrapperFunctionBuffer ResultBytes); |
| 97 | +``` |
| 98 | +
|
| 99 | +The orc_rt::WrapperFunction class provides APIs for implementing and calling |
| 100 | +wrapper functions. |
| 101 | +
|
| 102 | +### SPSWrapperFunction |
| 103 | +
|
| 104 | +An SPS wrapper function is a wrapper function that uses the |
| 105 | +SimplePackedSerialization scheme (see documentation in |
| 106 | +orc-rt/include/orc-rt/SimplePackedSerialization.h). |
| 107 | +
|
| 108 | +## TODO: |
| 109 | +
|
| 110 | +Document... |
| 111 | +
|
| 112 | +* C API |
| 113 | +* Error handling |
| 114 | +* RTTI |
| 115 | +* ExecutorAddr / ExecutorAddrRange |
| 116 | +* SimpleNativeMemoryMap |
| 117 | +* Memory Access (unimplemented) |
| 118 | +* Platform classes (unimplemented) |
| 119 | +* Other utilities |
0 commit comments