1*258f055eSStefan Gränitz //===-- RemoteJITUtils.cpp - Utilities for remote-JITing --------*- C++ -*-===// 2*258f055eSStefan Gränitz // 3*258f055eSStefan Gränitz // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*258f055eSStefan Gränitz // See https://llvm.org/LICENSE.txt for license information. 5*258f055eSStefan Gränitz // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*258f055eSStefan Gränitz // 7*258f055eSStefan Gränitz //===----------------------------------------------------------------------===// 8*258f055eSStefan Gränitz 9*258f055eSStefan Gränitz #include "RemoteJITUtils.h" 10*258f055eSStefan Gränitz 11*258f055eSStefan Gränitz #include "llvm/ExecutionEngine/Orc/DebugObjectManagerPlugin.h" 12*258f055eSStefan Gränitz #include "llvm/ExecutionEngine/Orc/OrcRPCTargetProcessControl.h" 13*258f055eSStefan Gränitz #include "llvm/ExecutionEngine/Orc/Shared/RPCUtils.h" 14*258f055eSStefan Gränitz #include "llvm/ExecutionEngine/Orc/TPCDebugObjectRegistrar.h" 15*258f055eSStefan Gränitz #include "llvm/ExecutionEngine/Orc/TPCDynamicLibrarySearchGenerator.h" 16*258f055eSStefan Gränitz #include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.h" 17*258f055eSStefan Gränitz #include "llvm/Support/FileSystem.h" 18*258f055eSStefan Gränitz #include "llvm/Support/Path.h" 19*258f055eSStefan Gränitz #include "llvm/Support/ToolOutputFile.h" 20*258f055eSStefan Gränitz 21*258f055eSStefan Gränitz #ifdef LLVM_ON_UNIX 22*258f055eSStefan Gränitz #include <netdb.h> 23*258f055eSStefan Gränitz #include <netinet/in.h> 24*258f055eSStefan Gränitz #include <sys/socket.h> 25*258f055eSStefan Gränitz #include <unistd.h> 26*258f055eSStefan Gränitz #endif // LLVM_ON_UNIX 27*258f055eSStefan Gränitz 28*258f055eSStefan Gränitz using namespace llvm; 29*258f055eSStefan Gränitz using namespace llvm::orc; 30*258f055eSStefan Gränitz 31*258f055eSStefan Gränitz namespace llvm { 32*258f055eSStefan Gränitz namespace orc { 33*258f055eSStefan Gränitz 34*258f055eSStefan Gränitz class RemoteTargetProcessControl 35*258f055eSStefan Gränitz : public OrcRPCTargetProcessControlBase< 36*258f055eSStefan Gränitz shared::MultiThreadedRPCEndpoint<JITLinkExecutor::RPCChannel>> { 37*258f055eSStefan Gränitz public: 38*258f055eSStefan Gränitz using RPCChannel = JITLinkExecutor::RPCChannel; 39*258f055eSStefan Gränitz using RPCEndpoint = shared::MultiThreadedRPCEndpoint<RPCChannel>; 40*258f055eSStefan Gränitz 41*258f055eSStefan Gränitz private: 42*258f055eSStefan Gränitz using ThisT = RemoteTargetProcessControl; 43*258f055eSStefan Gränitz using BaseT = OrcRPCTargetProcessControlBase<RPCEndpoint>; 44*258f055eSStefan Gränitz using MemoryAccess = OrcRPCTPCMemoryAccess<ThisT>; 45*258f055eSStefan Gränitz using MemoryManager = OrcRPCTPCJITLinkMemoryManager<ThisT>; 46*258f055eSStefan Gränitz 47*258f055eSStefan Gränitz public: 48*258f055eSStefan Gränitz using BaseT::initializeORCRPCTPCBase; 49*258f055eSStefan Gränitz 50*258f055eSStefan Gränitz RemoteTargetProcessControl(ExecutionSession &ES, 51*258f055eSStefan Gränitz std::unique_ptr<RPCChannel> Channel, 52*258f055eSStefan Gränitz std::unique_ptr<RPCEndpoint> Endpoint); 53*258f055eSStefan Gränitz 54*258f055eSStefan Gränitz void initializeMemoryManagement(); 55*258f055eSStefan Gränitz Error disconnect() override; 56*258f055eSStefan Gränitz 57*258f055eSStefan Gränitz private: 58*258f055eSStefan Gränitz std::unique_ptr<RPCChannel> Channel; 59*258f055eSStefan Gränitz std::unique_ptr<RPCEndpoint> Endpoint; 60*258f055eSStefan Gränitz std::unique_ptr<MemoryAccess> OwnedMemAccess; 61*258f055eSStefan Gränitz std::unique_ptr<MemoryManager> OwnedMemMgr; 62*258f055eSStefan Gränitz std::atomic<bool> Finished{false}; 63*258f055eSStefan Gränitz std::thread ListenerThread; 64*258f055eSStefan Gränitz }; 65*258f055eSStefan Gränitz 66*258f055eSStefan Gränitz RemoteTargetProcessControl::RemoteTargetProcessControl( 67*258f055eSStefan Gränitz ExecutionSession &ES, std::unique_ptr<RPCChannel> Channel, 68*258f055eSStefan Gränitz std::unique_ptr<RPCEndpoint> Endpoint) 69*258f055eSStefan Gränitz : BaseT(ES.getSymbolStringPool(), *Endpoint, 70*258f055eSStefan Gränitz [&ES](Error Err) { ES.reportError(std::move(Err)); }), 71*258f055eSStefan Gränitz Channel(std::move(Channel)), Endpoint(std::move(Endpoint)) { 72*258f055eSStefan Gränitz 73*258f055eSStefan Gränitz ListenerThread = std::thread([&]() { 74*258f055eSStefan Gränitz while (!Finished) { 75*258f055eSStefan Gränitz if (auto Err = this->Endpoint->handleOne()) { 76*258f055eSStefan Gränitz reportError(std::move(Err)); 77*258f055eSStefan Gränitz return; 78*258f055eSStefan Gränitz } 79*258f055eSStefan Gränitz } 80*258f055eSStefan Gränitz }); 81*258f055eSStefan Gränitz } 82*258f055eSStefan Gränitz 83*258f055eSStefan Gränitz void RemoteTargetProcessControl::initializeMemoryManagement() { 84*258f055eSStefan Gränitz OwnedMemAccess = std::make_unique<MemoryAccess>(*this); 85*258f055eSStefan Gränitz OwnedMemMgr = std::make_unique<MemoryManager>(*this); 86*258f055eSStefan Gränitz 87*258f055eSStefan Gränitz // Base class needs non-owning access. 88*258f055eSStefan Gränitz MemAccess = OwnedMemAccess.get(); 89*258f055eSStefan Gränitz MemMgr = OwnedMemMgr.get(); 90*258f055eSStefan Gränitz } 91*258f055eSStefan Gränitz 92*258f055eSStefan Gränitz Error RemoteTargetProcessControl::disconnect() { 93*258f055eSStefan Gränitz std::promise<MSVCPError> P; 94*258f055eSStefan Gränitz auto F = P.get_future(); 95*258f055eSStefan Gränitz auto Err = closeConnection([&](Error Err) -> Error { 96*258f055eSStefan Gränitz P.set_value(std::move(Err)); 97*258f055eSStefan Gränitz Finished = true; 98*258f055eSStefan Gränitz return Error::success(); 99*258f055eSStefan Gränitz }); 100*258f055eSStefan Gränitz ListenerThread.join(); 101*258f055eSStefan Gränitz return joinErrors(std::move(Err), F.get()); 102*258f055eSStefan Gränitz } 103*258f055eSStefan Gränitz 104*258f055eSStefan Gränitz } // namespace orc 105*258f055eSStefan Gränitz } // namespace llvm 106*258f055eSStefan Gränitz 107*258f055eSStefan Gränitz JITLinkExecutor::JITLinkExecutor() = default; 108*258f055eSStefan Gränitz JITLinkExecutor::~JITLinkExecutor() = default; 109*258f055eSStefan Gränitz 110*258f055eSStefan Gränitz Expected<std::unique_ptr<ObjectLayer>> 111*258f055eSStefan Gränitz JITLinkExecutor::operator()(ExecutionSession &ES, const Triple &TT) { 112*258f055eSStefan Gränitz return std::make_unique<ObjectLinkingLayer>(ES, TPC->getMemMgr()); 113*258f055eSStefan Gränitz } 114*258f055eSStefan Gränitz 115*258f055eSStefan Gränitz Error JITLinkExecutor::addDebugSupport(ObjectLayer &ObjLayer) { 116*258f055eSStefan Gränitz auto Registrar = createJITLoaderGDBRegistrar(*TPC); 117*258f055eSStefan Gränitz if (!Registrar) 118*258f055eSStefan Gränitz return Registrar.takeError(); 119*258f055eSStefan Gränitz 120*258f055eSStefan Gränitz cast<ObjectLinkingLayer>(&ObjLayer)->addPlugin( 121*258f055eSStefan Gränitz std::make_unique<DebugObjectManagerPlugin>(ObjLayer.getExecutionSession(), 122*258f055eSStefan Gränitz std::move(*Registrar))); 123*258f055eSStefan Gränitz 124*258f055eSStefan Gränitz return Error::success(); 125*258f055eSStefan Gränitz } 126*258f055eSStefan Gränitz 127*258f055eSStefan Gränitz Expected<std::unique_ptr<DefinitionGenerator>> 128*258f055eSStefan Gränitz JITLinkExecutor::loadDylib(StringRef RemotePath) { 129*258f055eSStefan Gränitz if (auto Handle = TPC->loadDylib(RemotePath.data())) 130*258f055eSStefan Gränitz return std::make_unique<TPCDynamicLibrarySearchGenerator>(*TPC, *Handle); 131*258f055eSStefan Gränitz else 132*258f055eSStefan Gränitz return Handle.takeError(); 133*258f055eSStefan Gränitz } 134*258f055eSStefan Gränitz 135*258f055eSStefan Gränitz Expected<int> JITLinkExecutor::runAsMain(JITEvaluatedSymbol MainSym, 136*258f055eSStefan Gränitz ArrayRef<std::string> Args) { 137*258f055eSStefan Gränitz return TPC->runAsMain(MainSym.getAddress(), Args); 138*258f055eSStefan Gränitz } 139*258f055eSStefan Gränitz 140*258f055eSStefan Gränitz Error JITLinkExecutor::disconnect() { return TPC->disconnect(); } 141*258f055eSStefan Gränitz 142*258f055eSStefan Gränitz static std::string defaultPath(const char *HostArgv0, StringRef ExecutorName) { 143*258f055eSStefan Gränitz // This just needs to be some symbol in the binary; C++ doesn't 144*258f055eSStefan Gränitz // allow taking the address of ::main however. 145*258f055eSStefan Gränitz void *P = (void *)(intptr_t)defaultPath; 146*258f055eSStefan Gränitz SmallString<256> FullName(sys::fs::getMainExecutable(HostArgv0, P)); 147*258f055eSStefan Gränitz sys::path::remove_filename(FullName); 148*258f055eSStefan Gränitz sys::path::append(FullName, ExecutorName); 149*258f055eSStefan Gränitz return FullName.str().str(); 150*258f055eSStefan Gränitz } 151*258f055eSStefan Gränitz 152*258f055eSStefan Gränitz Expected<std::unique_ptr<ChildProcessJITLinkExecutor>> 153*258f055eSStefan Gränitz JITLinkExecutor::FindLocal(const char *HostArgv) { 154*258f055eSStefan Gränitz std::string BestGuess = defaultPath(HostArgv, "llvm-jitlink-executor"); 155*258f055eSStefan Gränitz auto Executor = CreateLocal(BestGuess); 156*258f055eSStefan Gränitz if (!Executor) { 157*258f055eSStefan Gränitz consumeError(Executor.takeError()); 158*258f055eSStefan Gränitz return make_error<StringError>( 159*258f055eSStefan Gränitz formatv("Unable to find usable executor: {0}", BestGuess), 160*258f055eSStefan Gränitz inconvertibleErrorCode()); 161*258f055eSStefan Gränitz } 162*258f055eSStefan Gränitz return Executor; 163*258f055eSStefan Gränitz } 164*258f055eSStefan Gränitz 165*258f055eSStefan Gränitz Expected<std::unique_ptr<ChildProcessJITLinkExecutor>> 166*258f055eSStefan Gränitz JITLinkExecutor::CreateLocal(std::string ExecutablePath) { 167*258f055eSStefan Gränitz if (!sys::fs::can_execute(ExecutablePath)) 168*258f055eSStefan Gränitz return make_error<StringError>( 169*258f055eSStefan Gränitz formatv("Specified executor invalid: {0}", ExecutablePath), 170*258f055eSStefan Gränitz inconvertibleErrorCode()); 171*258f055eSStefan Gränitz return std::unique_ptr<ChildProcessJITLinkExecutor>( 172*258f055eSStefan Gränitz new ChildProcessJITLinkExecutor(std::move(ExecutablePath))); 173*258f055eSStefan Gränitz } 174*258f055eSStefan Gränitz 175*258f055eSStefan Gränitz TCPSocketJITLinkExecutor::TCPSocketJITLinkExecutor( 176*258f055eSStefan Gränitz std::unique_ptr<RemoteTargetProcessControl> TPC) { 177*258f055eSStefan Gränitz this->TPC = std::move(TPC); 178*258f055eSStefan Gränitz } 179*258f055eSStefan Gränitz 180*258f055eSStefan Gränitz #ifndef LLVM_ON_UNIX 181*258f055eSStefan Gränitz 182*258f055eSStefan Gränitz // FIXME: Add support for Windows. 183*258f055eSStefan Gränitz Error ChildProcessJITLinkExecutor::launch(ExecutionSession &ES) { 184*258f055eSStefan Gränitz return make_error<StringError>( 185*258f055eSStefan Gränitz "Remote JITing not yet supported on non-unix platforms", 186*258f055eSStefan Gränitz inconvertibleErrorCode()); 187*258f055eSStefan Gränitz } 188*258f055eSStefan Gränitz 189*258f055eSStefan Gränitz // FIXME: Add support for Windows. 190*258f055eSStefan Gränitz Expected<std::unique_ptr<TCPSocketJITLinkExecutor>> 191*258f055eSStefan Gränitz JITLinkExecutor::ConnectTCPSocket(StringRef NetworkAddress, 192*258f055eSStefan Gränitz ExecutionSession &ES) { 193*258f055eSStefan Gränitz return make_error<StringError>( 194*258f055eSStefan Gränitz "Remote JITing not yet supported on non-unix platforms", 195*258f055eSStefan Gränitz inconvertibleErrorCode()); 196*258f055eSStefan Gränitz } 197*258f055eSStefan Gränitz 198*258f055eSStefan Gränitz #else 199*258f055eSStefan Gränitz 200*258f055eSStefan Gränitz Error ChildProcessJITLinkExecutor::launch(ExecutionSession &ES) { 201*258f055eSStefan Gränitz constexpr int ReadEnd = 0; 202*258f055eSStefan Gränitz constexpr int WriteEnd = 1; 203*258f055eSStefan Gränitz 204*258f055eSStefan Gränitz // Pipe FDs. 205*258f055eSStefan Gränitz int ToExecutor[2]; 206*258f055eSStefan Gränitz int FromExecutor[2]; 207*258f055eSStefan Gränitz 208*258f055eSStefan Gränitz // Create pipes to/from the executor.. 209*258f055eSStefan Gränitz if (pipe(ToExecutor) != 0 || pipe(FromExecutor) != 0) 210*258f055eSStefan Gränitz return make_error<StringError>("Unable to create pipe for executor", 211*258f055eSStefan Gränitz inconvertibleErrorCode()); 212*258f055eSStefan Gränitz 213*258f055eSStefan Gränitz ProcessID = fork(); 214*258f055eSStefan Gränitz if (ProcessID == 0) { 215*258f055eSStefan Gränitz // In the child... 216*258f055eSStefan Gränitz 217*258f055eSStefan Gränitz // Close the parent ends of the pipes 218*258f055eSStefan Gränitz close(ToExecutor[WriteEnd]); 219*258f055eSStefan Gränitz close(FromExecutor[ReadEnd]); 220*258f055eSStefan Gränitz 221*258f055eSStefan Gränitz // Execute the child process. 222*258f055eSStefan Gränitz std::unique_ptr<char[]> ExecPath, FDSpecifier; 223*258f055eSStefan Gränitz { 224*258f055eSStefan Gränitz ExecPath = std::make_unique<char[]>(ExecutablePath.size() + 1); 225*258f055eSStefan Gränitz strcpy(ExecPath.get(), ExecutablePath.data()); 226*258f055eSStefan Gränitz 227*258f055eSStefan Gränitz std::string FDSpecifierStr("filedescs="); 228*258f055eSStefan Gränitz FDSpecifierStr += utostr(ToExecutor[ReadEnd]); 229*258f055eSStefan Gränitz FDSpecifierStr += ','; 230*258f055eSStefan Gränitz FDSpecifierStr += utostr(FromExecutor[WriteEnd]); 231*258f055eSStefan Gränitz FDSpecifier = std::make_unique<char[]>(FDSpecifierStr.size() + 1); 232*258f055eSStefan Gränitz strcpy(FDSpecifier.get(), FDSpecifierStr.c_str()); 233*258f055eSStefan Gränitz } 234*258f055eSStefan Gränitz 235*258f055eSStefan Gränitz char *const Args[] = {ExecPath.get(), FDSpecifier.get(), nullptr}; 236*258f055eSStefan Gränitz int RC = execvp(ExecPath.get(), Args); 237*258f055eSStefan Gränitz if (RC != 0) 238*258f055eSStefan Gränitz return make_error<StringError>( 239*258f055eSStefan Gränitz "Unable to launch out-of-process executor '" + ExecutablePath + "'\n", 240*258f055eSStefan Gränitz inconvertibleErrorCode()); 241*258f055eSStefan Gränitz 242*258f055eSStefan Gränitz llvm_unreachable("Fork won't return in success case"); 243*258f055eSStefan Gränitz } 244*258f055eSStefan Gränitz // else we're the parent... 245*258f055eSStefan Gränitz 246*258f055eSStefan Gränitz // Close the child ends of the pipes 247*258f055eSStefan Gränitz close(ToExecutor[ReadEnd]); 248*258f055eSStefan Gränitz close(FromExecutor[WriteEnd]); 249*258f055eSStefan Gränitz 250*258f055eSStefan Gränitz auto Channel = 251*258f055eSStefan Gränitz std::make_unique<RPCChannel>(FromExecutor[ReadEnd], ToExecutor[WriteEnd]); 252*258f055eSStefan Gränitz auto Endpoint = 253*258f055eSStefan Gränitz std::make_unique<RemoteTargetProcessControl::RPCEndpoint>(*Channel, true); 254*258f055eSStefan Gränitz 255*258f055eSStefan Gränitz TPC = std::make_unique<RemoteTargetProcessControl>(ES, std::move(Channel), 256*258f055eSStefan Gränitz std::move(Endpoint)); 257*258f055eSStefan Gränitz 258*258f055eSStefan Gränitz if (auto Err = TPC->initializeORCRPCTPCBase()) 259*258f055eSStefan Gränitz return joinErrors(std::move(Err), TPC->disconnect()); 260*258f055eSStefan Gränitz 261*258f055eSStefan Gränitz TPC->initializeMemoryManagement(); 262*258f055eSStefan Gränitz 263*258f055eSStefan Gränitz shared::registerStringError<RPCChannel>(); 264*258f055eSStefan Gränitz return Error::success(); 265*258f055eSStefan Gränitz } 266*258f055eSStefan Gränitz 267*258f055eSStefan Gränitz static Expected<int> connectTCPSocketImpl(std::string Host, 268*258f055eSStefan Gränitz std::string PortStr) { 269*258f055eSStefan Gränitz addrinfo *AI; 270*258f055eSStefan Gränitz addrinfo Hints{}; 271*258f055eSStefan Gränitz Hints.ai_family = AF_INET; 272*258f055eSStefan Gränitz Hints.ai_socktype = SOCK_STREAM; 273*258f055eSStefan Gränitz Hints.ai_flags = AI_NUMERICSERV; 274*258f055eSStefan Gränitz 275*258f055eSStefan Gränitz if (int EC = getaddrinfo(Host.c_str(), PortStr.c_str(), &Hints, &AI)) 276*258f055eSStefan Gränitz return make_error<StringError>( 277*258f055eSStefan Gränitz formatv("address resolution failed ({0})", gai_strerror(EC)), 278*258f055eSStefan Gränitz inconvertibleErrorCode()); 279*258f055eSStefan Gränitz 280*258f055eSStefan Gränitz // Cycle through the returned addrinfo structures and connect to the first 281*258f055eSStefan Gränitz // reachable endpoint. 282*258f055eSStefan Gränitz int SockFD; 283*258f055eSStefan Gränitz addrinfo *Server; 284*258f055eSStefan Gränitz for (Server = AI; Server != nullptr; Server = Server->ai_next) { 285*258f055eSStefan Gränitz // If socket fails, maybe it's because the address family is not supported. 286*258f055eSStefan Gränitz // Skip to the next addrinfo structure. 287*258f055eSStefan Gränitz if ((SockFD = socket(AI->ai_family, AI->ai_socktype, AI->ai_protocol)) < 0) 288*258f055eSStefan Gränitz continue; 289*258f055eSStefan Gränitz 290*258f055eSStefan Gränitz // If connect works, we exit the loop with a working socket. 291*258f055eSStefan Gränitz if (connect(SockFD, Server->ai_addr, Server->ai_addrlen) == 0) 292*258f055eSStefan Gränitz break; 293*258f055eSStefan Gränitz 294*258f055eSStefan Gränitz close(SockFD); 295*258f055eSStefan Gränitz } 296*258f055eSStefan Gränitz freeaddrinfo(AI); 297*258f055eSStefan Gränitz 298*258f055eSStefan Gränitz // Did we reach the end of the loop without connecting to a valid endpoint? 299*258f055eSStefan Gränitz if (Server == nullptr) 300*258f055eSStefan Gränitz return make_error<StringError>("invalid hostname", 301*258f055eSStefan Gränitz inconvertibleErrorCode()); 302*258f055eSStefan Gränitz 303*258f055eSStefan Gränitz return SockFD; 304*258f055eSStefan Gränitz } 305*258f055eSStefan Gränitz 306*258f055eSStefan Gränitz Expected<std::unique_ptr<TCPSocketJITLinkExecutor>> 307*258f055eSStefan Gränitz JITLinkExecutor::ConnectTCPSocket(StringRef NetworkAddress, 308*258f055eSStefan Gränitz ExecutionSession &ES) { 309*258f055eSStefan Gränitz auto CreateErr = [NetworkAddress](StringRef Details) { 310*258f055eSStefan Gränitz return make_error<StringError>( 311*258f055eSStefan Gränitz formatv("Failed to connect TCP socket '{0}': {1}", NetworkAddress, 312*258f055eSStefan Gränitz Details), 313*258f055eSStefan Gränitz inconvertibleErrorCode()); 314*258f055eSStefan Gränitz }; 315*258f055eSStefan Gränitz 316*258f055eSStefan Gränitz StringRef Host, PortStr; 317*258f055eSStefan Gränitz std::tie(Host, PortStr) = NetworkAddress.split(':'); 318*258f055eSStefan Gränitz if (Host.empty()) 319*258f055eSStefan Gränitz return CreateErr("host name cannot be empty"); 320*258f055eSStefan Gränitz if (PortStr.empty()) 321*258f055eSStefan Gränitz return CreateErr("port cannot be empty"); 322*258f055eSStefan Gränitz int Port = 0; 323*258f055eSStefan Gränitz if (PortStr.getAsInteger(10, Port)) 324*258f055eSStefan Gränitz return CreateErr("port number is not a valid integer"); 325*258f055eSStefan Gränitz 326*258f055eSStefan Gränitz Expected<int> SockFD = connectTCPSocketImpl(Host.str(), PortStr.str()); 327*258f055eSStefan Gränitz if (!SockFD) 328*258f055eSStefan Gränitz return CreateErr(toString(SockFD.takeError())); 329*258f055eSStefan Gränitz 330*258f055eSStefan Gränitz auto Channel = std::make_unique<RPCChannel>(*SockFD, *SockFD); 331*258f055eSStefan Gränitz auto Endpoint = 332*258f055eSStefan Gränitz std::make_unique<RemoteTargetProcessControl::RPCEndpoint>(*Channel, true); 333*258f055eSStefan Gränitz 334*258f055eSStefan Gränitz auto TPC = std::make_unique<RemoteTargetProcessControl>( 335*258f055eSStefan Gränitz ES, std::move(Channel), std::move(Endpoint)); 336*258f055eSStefan Gränitz 337*258f055eSStefan Gränitz if (auto Err = TPC->initializeORCRPCTPCBase()) 338*258f055eSStefan Gränitz return joinErrors(std::move(Err), TPC->disconnect()); 339*258f055eSStefan Gränitz 340*258f055eSStefan Gränitz TPC->initializeMemoryManagement(); 341*258f055eSStefan Gränitz shared::registerStringError<RPCChannel>(); 342*258f055eSStefan Gränitz 343*258f055eSStefan Gränitz return std::unique_ptr<TCPSocketJITLinkExecutor>( 344*258f055eSStefan Gränitz new TCPSocketJITLinkExecutor(std::move(TPC))); 345*258f055eSStefan Gränitz } 346*258f055eSStefan Gränitz 347*258f055eSStefan Gränitz #endif 348