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