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