LLVM 23.0.0git
InProcessEPC.cpp
Go to the documentation of this file.
1//===---------- InProcessEPC.cpp -- In-process EPC for new ORC runtime ----===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
10
18
19#define DEBUG_TYPE "orc"
20
21namespace llvm::orc {
22
23Expected<std::unique_ptr<InProcessEPC>>
25 std::shared_ptr<SymbolStringPool> SSP,
26 std::unique_ptr<TaskDispatcher> D) {
27 assert(C && "C must not be null");
28 assert(BIA && "BIA must not be null");
29
30 // Lifecycle and IPCA-side fields must be populated by the controller side
31 // before OnConnect is invoked.
32 assert(C->Retain && "C->Retain not set by controller");
33 assert(C->Release && "C->Release not set by controller");
34 assert(C->Disconnect && "C->Disconnect not set by controller");
35 assert(C->EnterMessageScope && "C->EnterMessageScope not set by controller");
36 assert(C->LeaveMessageScope && "C->LeaveMessageScope not set by controller");
37 assert(C->IPCA && "C->IPCA not set by controller");
38 assert(C->CallWrapper && "C->CallWrapper not set by controller");
39 assert(C->ReturnJITDispatchResult &&
40 "C->ReturnJITDispatchResult not set by controller");
41
42 if (!SSP)
43 SSP = std::make_shared<SymbolStringPool>();
44
45 if (!D)
46 D = std::make_unique<InPlaceTaskDispatcher>();
47
48 std::unique_ptr<InProcessEPC> IPEPC(
49 new InProcessEPC(C, std::move(SSP), std::move(D)));
50
51 // First set values in C.
52 C->IPEPC = IPEPC.get();
53 C->CallJITDispatch = callJITDispatchEntry;
54 C->ReturnWrapperResult = returnWrapperResultEntry;
55
56 // Then grab bootstrap values.
57 if (auto PageSize = BIA->GetPageSize(BIA))
58 IPEPC->PageSize = PageSize;
59 else
61 "Cannot create InProcessEPC with page-size = 0",
63
64 if (auto TT = BIA->GetTargetTriple(BIA)) {
65 IPEPC->TargetTriple = llvm::Triple(TT);
66 } else
68 "Cannot create InProcessEPC with target-triple = \"\"",
70
71 {
72 const char *Name;
73 const char *ValBytes;
74 uint64_t ValSize;
75 int RC;
76 while ((RC = BIA->GetNextValue(BIA, &Name, &ValBytes, &ValSize)) == 1) {
77 if (!IPEPC->BootstrapMap
78 .try_emplace(Name,
79 std::vector<char>(ValBytes, ValBytes + ValSize))
80 .second)
82 ("Cannot create InProcessEPC: bootstrap-value map contains "
83 "duplicate key \"" +
84 StringRef(Name) + "\""),
86 }
87 if (RC < 0)
89 "Cannot create InProcessEPC: bootstrap-value map corrupted",
91 }
92
93 {
94 const char *SymName;
95 uint64_t SymAddr;
96 int RC;
97 while ((RC = BIA->GetNextSymbol(BIA, &SymName, &SymAddr)) == 1) {
98 if (!IPEPC->BootstrapSymbols.try_emplace(SymName, ExecutorAddr(SymAddr))
99 .second)
101 ("Cannot create InProcessEPC: bootstrap-symbol map contains "
102 "duplicate symbol \"" +
103 StringRef(SymName) + "\""),
105 }
106 if (RC < 0)
108 "Cannot create InProcessEPC: bootstrap-symbol map corrupted",
110 }
111
112 return std::move(IPEPC);
113}
114
116 // Guarantee that a discarded InProcessEPC initiates disconnect, even if it
117 // was never attached to an ExecutionSession (e.g. Create failed partway
118 // through, or the caller dropped the returned object without handing it to
119 // a session). When the InProcessEPC *is* attached, the ExecutionSession is
120 // guaranteed to call disconnect() during shutdown, and this call becomes a
121 // no-op via the idempotency of C->Disconnect.
122 doDisconnect();
123
124 // Shut down the dispatcher.
125 D->shutdown();
126
127 // Release the connection object.
128 C->Release(C);
129}
130
133 using MainTy = int (*)(int, char *[]);
134 return orc::runAsMain(MainFnAddr.toPtr<MainTy>(), Args);
135}
136
138 using VoidTy = int (*)();
139 return orc::runAsVoidFunction(VoidFnAddr.toPtr<VoidTy>());
140}
141
143 int Arg) {
144 using IntTy = int (*)(int);
145 return orc::runAsIntFunction(IntFnAddr.toPtr<IntTy>(), Arg);
146}
147
149 IncomingWFRHandler OnComplete,
150 ArrayRef<char> ArgBuffer) {
151 if (C->EnterMessageScope(C)) {
152 auto CallId = registerPendingCallWrapperResult(std::move(OnComplete));
153 auto ArgBytes = shared::WrapperFunctionBuffer::copyFrom(ArgBuffer.data(),
154 ArgBuffer.size());
155
156 LLVM_DEBUG(dbgs() << "InProcessEPC: callWrapperAsync call id " << CallId
157 << " to " << WrapperFnAddr << "\n");
158
159 C->CallWrapper(C->IPCA, CallId, WrapperFnAddr.toPtr<void *>(),
160 ArgBytes.release());
161 C->LeaveMessageScope(C);
162 } else
164 "connection closed"));
165}
166
169 // FIXME: Should actually use InProcessMemoryManager for this.
171}
172
174 // FIXME: Should actually use in-process for this.
176 if (!DM)
177 return DM.takeError();
178 return std::make_unique<EPCGenericDylibManager>(std::move(*DM));
179}
180
202
204 doDisconnect();
205 return Error::success();
206}
207
208uint64_t InProcessEPC::registerPendingCallWrapperResult(IncomingWFRHandler H) {
209 std::scoped_lock<std::mutex> Lock(M);
210 assert(!PendingCallWrapperResults.count(NextCallId) &&
211 "CallId already in use");
212 PendingCallWrapperResults[NextCallId] = std::move(H);
213 return NextCallId++;
214}
215
216void InProcessEPC::doDisconnect() {
217 // Disconnect from InProcessControllerAccess. This should prevent any further
218 // incoming or outgoing calls.
219 C->Disconnect(C);
220
221 // Drain any pending handlers.
223 {
224 std::scoped_lock<std::mutex> Lock(M);
225 HandlersToDrain = std::move(PendingCallWrapperResults);
226 }
227
228 for (auto &[_, H] : HandlersToDrain)
230}
231
232void InProcessEPC::callJITDispatch(uint64_t CallId, void *HandlerTag,
234 assert(C->ReturnJITDispatchResult && "ReturnJITDispatchResult not set");
235
236 LLVM_DEBUG(dbgs() << "InProcessEPC: JIT-dispatch call id " << CallId << " to "
237 << HandlerTag << "\n");
238
240 [this, CallId](shared::WrapperFunctionBuffer ResultBytes) {
241 LLVM_DEBUG(dbgs() << "InProcessEPC: Returning JIT-dispatch result for "
242 "call id "
243 << CallId << "\n");
244 if (C->EnterMessageScope(C)) {
245 C->ReturnJITDispatchResult(C->IPCA, CallId, ResultBytes.release());
246 C->LeaveMessageScope(C);
247 }
248 },
249 ExecutorAddr::fromPtr(HandlerTag),
250 shared::WrapperFunctionBuffer(ArgBytes));
251}
252
253void InProcessEPC::callJITDispatchEntry(
254 void *IPEPC, uint64_t CallId, void *HandlerTag,
256 static_cast<InProcessEPC *>(IPEPC)->callJITDispatch(CallId, HandlerTag,
257 ArgBytes);
258}
259
260void InProcessEPC::returnWrapperResult(
261 uint64_t CallId, shared::CWrapperFunctionBuffer ResultBytes) {
262
263 LLVM_DEBUG(dbgs() << "InProcessEPC: Wrapper result for call id " << CallId
264 << "\n");
265
267 {
268 std::scoped_lock<std::mutex> Lock(M);
269 auto I = PendingCallWrapperResults.find(CallId);
270 if (I != PendingCallWrapperResults.end()) {
271 H = std::move(I->second);
272 PendingCallWrapperResults.erase(I);
273 }
274 }
275
276 if (!H) {
278 "InProcessEPC received result for invalid call id " + Twine(CallId),
280 return;
281 }
282
283 H(shared::WrapperFunctionBuffer(ResultBytes));
284}
285
286void InProcessEPC::returnWrapperResultEntry(
287 void *IPEPC, uint64_t CallId, shared::CWrapperFunctionBuffer ResultBytes) {
288 static_cast<InProcessEPC *>(IPEPC)->returnWrapperResult(CallId, ResultBytes);
289}
290
291} // namespace llvm::orc
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static RegisterPass< DebugifyModulePass > DM("debugify", "Attach debug info to everything")
#define _
#define I(x, y, z)
Definition MD5.cpp:57
#define H(x, y, z)
Definition MD5.cpp:56
Provides a library for accessing information about this process and other processes on the operating ...
#define LLVM_DEBUG(...)
Definition Debug.h:119
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
size_t size() const
Get the array size.
Definition ArrayRef.h:141
const T * data() const
Definition ArrayRef.h:138
size_type count(const_arg_type_t< KeyT > Val) const
Return 1 if the specified key is in the map, 0 otherwise.
Definition DenseMap.h:221
Lightweight error class with error context and mandatory checking.
Definition Error.h:159
static ErrorSuccess success()
Create a success value.
Definition Error.h:336
Tagged union holding either a T or a Error.
Definition Error.h:485
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
Triple - Helper class for working with autoconf configuration names.
Definition Triple.h:47
static Expected< EPCGenericDylibManager > Create(JITDylib &JD, rt::SimpleExecutorDylibManagerSymbolNames SNs=rt::orc_rt_NativeDylibManagerSPSSymbols)
Create an EPCGenericDylibManager using the given implementation symbol names.
static Expected< std::unique_ptr< EPCGenericJITLinkMemoryManager > > Create(JITDylib &JD, rt::SimpleExecutorMemoryManagerSymbolNames SNs=rt::orc_rt_SimpleNativeMemoryMapSPSSymbols)
Create an EPCGenericJITLinkMemoryManager using the given implementation symbol names.
LLVM_ABI void runJITDispatchHandler(SendResultFunction SendResult, ExecutorAddr HandlerFnTagAddr, shared::WrapperFunctionBuffer ArgBytes)
Run a registered jit-side wrapper function.
Definition Core.cpp:1919
void reportError(Error Err)
Report a error for this execution session.
Definition Core.h:1282
Represents an address in the executor process.
static ExecutorAddr fromPtr(T *Ptr, UnwrapFn &&Unwrap=UnwrapFn())
Create an ExecutorAddr from the given pointer.
std::enable_if_t< std::is_pointer< T >::value, T > toPtr(WrapFn &&Wrap=WrapFn()) const
Cast this ExecutorAddr to a pointer of the given type.
A handler or incoming WrapperFunctionBuffers – either return values from callWrapper* calls,...
std::unique_ptr< TaskDispatcher > D
std::shared_ptr< SymbolStringPool > SSP
Error getBootstrapSymbols(ArrayRef< std::pair< ExecutorAddr &, StringRef > > Pairs) const
For each (ExecutorAddr&, StringRef) pair, looks up the string in the bootstrap symbols map and writes...
ExecutionSession & getExecutionSession()
Return the ExecutionSession associated with this instance.
Expected< std::unique_ptr< jitlink::JITLinkMemoryManager > > createDefaultMemoryManager() override
Create a default JITLinkMemoryManager for the target process.
Expected< int32_t > runAsIntFunction(ExecutorAddr IntFnAddr, int Arg) override
Run function with a int (*)(int) signature.
Expected< int32_t > runAsVoidFunction(ExecutorAddr VoidFnAddr) override
Run function with a int (*)(void) signature.
Expected< std::unique_ptr< DylibManager > > createDefaultDylibMgr() override
Create a default DylibManager for the target process.
void callWrapperAsync(ExecutorAddr WrapperFnAddr, IncomingWFRHandler OnComplete, ArrayRef< char > ArgBuffer) override
Run a wrapper function in the executor.
static Expected< std::unique_ptr< InProcessEPC > > Create(Connection *C, BootstrapInfoAccess *BIA, std::shared_ptr< SymbolStringPool > SSP=nullptr, std::unique_ptr< TaskDispatcher > D=nullptr)
Create a new InProcessEPC.
Error disconnect() override
Disconnect from the target process.
Expected< std::unique_ptr< MemoryAccess > > createDefaultMemoryAccess() override
Create a default MemoryAccess for the target process.
Expected< int32_t > runAsMain(ExecutorAddr MainFnAddr, ArrayRef< std::string > Args) override
Run function with a main-like signature.
static WrapperFunctionBuffer copyFrom(const char *Source, size_t Size)
Copy from the given char range.
static WrapperFunctionBuffer createOutOfBandError(const char *Msg)
Create an out-of-band error by copying the given string.
@ C
The default llvm calling convention, compatible with C.
Definition CallingConv.h:34
LLVM_ABI const char * MemoryReadUInt64sWrapperName
LLVM_ABI const char * MemoryWriteUInt16sWrapperName
LLVM_ABI const char * MemoryReadStringsWrapperName
LLVM_ABI const char * MemoryReadUInt16sWrapperName
LLVM_ABI const char * MemoryReadUInt32sWrapperName
LLVM_ABI const char * MemoryWriteUInt64sWrapperName
LLVM_ABI const char * MemoryWriteUInt8sWrapperName
LLVM_ABI const char * MemoryWritePointersWrapperName
LLVM_ABI const char * MemoryWriteUInt32sWrapperName
LLVM_ABI const char * MemoryWriteBuffersWrapperName
LLVM_ABI const char * MemoryReadBuffersWrapperName
LLVM_ABI const char * MemoryReadUInt8sWrapperName
LLVM_ABI int runAsVoidFunction(int(*Func)(void))
LLVM_ABI int runAsIntFunction(int(*Func)(int), int Arg)
LLVM_ABI int runAsMain(int(*Main)(int, char *[]), ArrayRef< std::string > Args, std::optional< StringRef > ProgramName=std::nullopt)
Run a main function, returning the result.
LLVM_ABI std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
Definition Error.cpp:94
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
Error make_error(ArgTs &&... Args)
Make a Error instance representing failure using the given error info type.
Definition Error.h:340
Function addresses for memory access.
Provides access to bootstrap info.
const char *(* GetTargetTriple)(void *BIA)
int(* GetNextSymbol)(void *BIA, const char **Name, uint64_t *Addr)
int(* GetNextValue)(void *BIA, const char **Name, const char **ValueBytes, uint64_t *ValueSize)
Pseudo-connection C struct.