| 1 | //===------ SelfExecutorProcessControl.cpp -- EPC for in-process JITs -----===// |
| 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 | |
| 9 | #include "llvm/ExecutionEngine/Orc/SelfExecutorProcessControl.h" |
| 10 | |
| 11 | #include "llvm/ExecutionEngine/Orc/Core.h" |
| 12 | #include "llvm/ExecutionEngine/Orc/TargetProcess/DefaultHostBootstrapValues.h" |
| 13 | #include "llvm/ExecutionEngine/Orc/TargetProcess/TargetExecutionUtils.h" |
| 14 | #include "llvm/Support/DynamicLibrary.h" |
| 15 | #include "llvm/Support/Process.h" |
| 16 | #include "llvm/TargetParser/Host.h" |
| 17 | |
| 18 | #define DEBUG_TYPE "orc" |
| 19 | |
| 20 | namespace llvm::orc { |
| 21 | |
| 22 | SelfExecutorProcessControl::SelfExecutorProcessControl( |
| 23 | std::shared_ptr<SymbolStringPool> SSP, std::unique_ptr<TaskDispatcher> D, |
| 24 | Triple TargetTriple, unsigned PageSize, |
| 25 | std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr) |
| 26 | : ExecutorProcessControl(std::move(SSP), std::move(D)), |
| 27 | IPMA(TargetTriple.isArch64Bit()) { |
| 28 | |
| 29 | OwnedMemMgr = std::move(MemMgr); |
| 30 | if (!OwnedMemMgr) |
| 31 | OwnedMemMgr = std::make_unique<jitlink::InProcessMemoryManager>( |
| 32 | args: sys::Process::getPageSizeEstimate()); |
| 33 | |
| 34 | this->TargetTriple = std::move(TargetTriple); |
| 35 | this->PageSize = PageSize; |
| 36 | this->MemMgr = OwnedMemMgr.get(); |
| 37 | this->MemAccess = &IPMA; |
| 38 | this->JDI = {.JITDispatchFunction: ExecutorAddr::fromPtr(Ptr: jitDispatchViaWrapperFunctionManager), |
| 39 | .JITDispatchContext: ExecutorAddr::fromPtr(Ptr: this)}; |
| 40 | |
| 41 | addDefaultBootstrapValuesForHostProcess(BootstrapMap, BootstrapSymbols); |
| 42 | |
| 43 | #ifdef __APPLE__ |
| 44 | // FIXME: Don't add an UnwindInfoManager by default -- it's redundant when |
| 45 | // the ORC runtime is loaded. We'll need a way to document this and |
| 46 | // allow clients to choose. |
| 47 | if (UnwindInfoManager::TryEnable()) |
| 48 | UnwindInfoManager::addBootstrapSymbols(this->BootstrapSymbols); |
| 49 | #endif // __APPLE__ |
| 50 | } |
| 51 | |
| 52 | Expected<std::unique_ptr<SelfExecutorProcessControl>> |
| 53 | SelfExecutorProcessControl::Create( |
| 54 | std::shared_ptr<SymbolStringPool> SSP, std::unique_ptr<TaskDispatcher> D, |
| 55 | std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr) { |
| 56 | |
| 57 | if (!SSP) |
| 58 | SSP = std::make_shared<SymbolStringPool>(); |
| 59 | |
| 60 | if (!D) |
| 61 | D = std::make_unique<InPlaceTaskDispatcher>(); |
| 62 | |
| 63 | auto PageSize = sys::Process::getPageSize(); |
| 64 | if (!PageSize) |
| 65 | return PageSize.takeError(); |
| 66 | |
| 67 | Triple TT(sys::getProcessTriple()); |
| 68 | |
| 69 | return std::make_unique<SelfExecutorProcessControl>( |
| 70 | args: std::move(SSP), args: std::move(D), args: std::move(TT), args&: *PageSize, |
| 71 | args: std::move(MemMgr)); |
| 72 | } |
| 73 | |
| 74 | Expected<int32_t> |
| 75 | SelfExecutorProcessControl::runAsMain(ExecutorAddr MainFnAddr, |
| 76 | ArrayRef<std::string> Args) { |
| 77 | using MainTy = int (*)(int, char *[]); |
| 78 | return orc::runAsMain(Main: MainFnAddr.toPtr<MainTy>(), Args); |
| 79 | } |
| 80 | |
| 81 | Expected<int32_t> |
| 82 | SelfExecutorProcessControl::runAsVoidFunction(ExecutorAddr VoidFnAddr) { |
| 83 | using VoidTy = int (*)(); |
| 84 | return orc::runAsVoidFunction(Func: VoidFnAddr.toPtr<VoidTy>()); |
| 85 | } |
| 86 | |
| 87 | Expected<int32_t> |
| 88 | SelfExecutorProcessControl::runAsIntFunction(ExecutorAddr IntFnAddr, int Arg) { |
| 89 | using IntTy = int (*)(int); |
| 90 | return orc::runAsIntFunction(Func: IntFnAddr.toPtr<IntTy>(), Arg); |
| 91 | } |
| 92 | |
| 93 | void SelfExecutorProcessControl::callWrapperAsync(ExecutorAddr WrapperFnAddr, |
| 94 | IncomingWFRHandler SendResult, |
| 95 | ArrayRef<char> ArgBuffer) { |
| 96 | using WrapperFnTy = |
| 97 | shared::CWrapperFunctionBuffer (*)(const char *Data, size_t Size); |
| 98 | auto *WrapperFn = WrapperFnAddr.toPtr<WrapperFnTy>(); |
| 99 | SendResult(shared::WrapperFunctionBuffer( |
| 100 | WrapperFn(ArgBuffer.data(), ArgBuffer.size()))); |
| 101 | } |
| 102 | |
| 103 | Error SelfExecutorProcessControl::disconnect() { |
| 104 | D->shutdown(); |
| 105 | return Error::success(); |
| 106 | } |
| 107 | |
| 108 | Expected<std::unique_ptr<DylibManager>> |
| 109 | SelfExecutorProcessControl::createDefaultDylibMgr() { |
| 110 | char Prefix = TargetTriple.isOSBinFormatMachO() ? '_' : '\0'; |
| 111 | return std::make_unique<InProcessDylibManager>(args&: Prefix); |
| 112 | } |
| 113 | |
| 114 | shared::CWrapperFunctionBuffer |
| 115 | SelfExecutorProcessControl::jitDispatchViaWrapperFunctionManager( |
| 116 | void *Ctx, const void *FnTag, const char *Data, size_t Size) { |
| 117 | |
| 118 | LLVM_DEBUG({ |
| 119 | dbgs() << "jit-dispatch call with tag " << FnTag << " and " << Size |
| 120 | << " byte payload.\n" ; |
| 121 | }); |
| 122 | |
| 123 | std::promise<shared::WrapperFunctionBuffer> ResultP; |
| 124 | auto ResultF = ResultP.get_future(); |
| 125 | static_cast<SelfExecutorProcessControl *>(Ctx) |
| 126 | ->getExecutionSession() |
| 127 | .runJITDispatchHandler( |
| 128 | SendResult: [ResultP = std::move(ResultP)]( |
| 129 | shared::WrapperFunctionBuffer Result) mutable { |
| 130 | ResultP.set_value(std::move(Result)); |
| 131 | }, |
| 132 | HandlerFnTagAddr: ExecutorAddr::fromPtr(Ptr: FnTag), |
| 133 | ArgBytes: shared::WrapperFunctionBuffer::copyFrom(Source: Data, Size)); |
| 134 | |
| 135 | return ResultF.get().release(); |
| 136 | } |
| 137 | |
| 138 | SelfExecutorProcessControl::InProcessDylibManager::InProcessDylibManager( |
| 139 | char GlobalManglingPrefix) |
| 140 | : GlobalManglingPrefix(GlobalManglingPrefix) {} |
| 141 | |
| 142 | Expected<tpctypes::DylibHandle> |
| 143 | SelfExecutorProcessControl::InProcessDylibManager::loadDylib( |
| 144 | const char *DylibPath) { |
| 145 | std::string ErrMsg; |
| 146 | auto Dylib = sys::DynamicLibrary::getPermanentLibrary(filename: DylibPath, errMsg: &ErrMsg); |
| 147 | if (!Dylib.isValid()) |
| 148 | return make_error<StringError>(Args: std::move(ErrMsg), Args: inconvertibleErrorCode()); |
| 149 | return ExecutorAddr::fromPtr(Ptr: Dylib.getOSSpecificHandle()); |
| 150 | } |
| 151 | |
| 152 | void SelfExecutorProcessControl::InProcessDylibManager::lookupSymbolsAsync( |
| 153 | ArrayRef<LookupRequest> Request, |
| 154 | DylibManager::SymbolLookupCompleteFn Complete) { |
| 155 | std::vector<tpctypes::LookupResult> R; |
| 156 | |
| 157 | for (auto &Elem : Request) { |
| 158 | sys::DynamicLibrary Dylib(Elem.Handle.toPtr<void *>()); |
| 159 | R.push_back(x: tpctypes::LookupResult()); |
| 160 | for (auto &KV : Elem.Symbols) { |
| 161 | auto &Sym = KV.first; |
| 162 | std::string Tmp((*Sym).data() + !!GlobalManglingPrefix, |
| 163 | (*Sym).size() - !!GlobalManglingPrefix); |
| 164 | void *Addr = Dylib.getAddressOfSymbol(symbolName: Tmp.c_str()); |
| 165 | if (!Addr && KV.second == SymbolLookupFlags::RequiredSymbol) |
| 166 | R.back().emplace_back(); |
| 167 | else |
| 168 | // FIXME: determine accurate JITSymbolFlags. |
| 169 | R.back().emplace_back(args: ExecutorSymbolDef(ExecutorAddr::fromPtr(Ptr: Addr), |
| 170 | JITSymbolFlags::Exported)); |
| 171 | } |
| 172 | } |
| 173 | Complete(std::move(R)); |
| 174 | } |
| 175 | |
| 176 | } // namespace llvm::orc |
| 177 | |