Expand Up
@@ -13,11 +13,9 @@
//
// ===----------------------------------------------------------------------===//
#include " llvm/IR/LLVMContext.h"
#include " OrcLazyJIT.h"
#include " RemoteMemoryManager.h"
#include " RemoteTarget.h"
#include " RemoteTargetExternal.h"
#include " RemoteJITUtils.h"
#include " llvm/IR/LLVMContext.h"
#include " llvm/ADT/Triple.h"
#include " llvm/Bitcode/ReaderWriter.h"
#include " llvm/CodeGen/LinkAllCodegenComponents.h"
Expand All
@@ -28,6 +26,7 @@
#include " llvm/ExecutionEngine/ObjectCache.h"
#include " llvm/ExecutionEngine/OrcMCJITReplacement.h"
#include " llvm/ExecutionEngine/SectionMemoryManager.h"
#include " llvm/ExecutionEngine/Orc/OrcRemoteTargetClient.h"
#include " llvm/IR/IRBuilder.h"
#include " llvm/IR/Module.h"
#include " llvm/IR/Type.h"
Expand Down
Expand Up
@@ -449,7 +448,7 @@ int main(int argc, char **argv, char * const *envp) {
RTDyldMemoryManager *RTDyldMM = nullptr ;
if (!ForceInterpreter) {
if (RemoteMCJIT)
RTDyldMM = new RemoteMemoryManager ();
RTDyldMM = new ForwardingMemoryManager ();
else
RTDyldMM = new SectionMemoryManager ();
Expand Down
Expand Up
@@ -582,6 +581,27 @@ int main(int argc, char **argv, char * const *envp) {
int Result;
// Sanity check use of remote-jit: LLI currently only supports use of the
// remote JIT on Unix platforms.
// FIXME: Remove this pointless fallback mode which causes tests to "pass"
// on platforms where they should XFAIL.
if (RemoteMCJIT) {
#ifndef LLVM_ON_UNIX
errs () << " Warning: host does not support external remote targets.\n "
<< " Defaulting to local execution execution\n " ;
RemoteMCJIT = false ;
#else
if (ChildExecPath.empty ()) {
errs () << " -remote-mcjit requires -mcjit-remote-process.\n " ;
exit (1 );
} else if (!sys::fs::can_execute (ChildExecPath)) {
errs () << " Unable to find usable child executable: '" << ChildExecPath
<< " '\n " ;
return -1 ;
}
#endif
}
if (!RemoteMCJIT) {
// If the program doesn't explicitly call exit, we will need the Exit
// function later on to make an explicit call, so get the function now.
Expand Down
Expand Up
@@ -629,66 +649,123 @@ int main(int argc, char **argv, char * const *envp) {
// Remote target MCJIT doesn't (yet) support static constructors. No reason
// it couldn't. This is a limitation of the LLI implemantation, not the
// MCJIT itself. FIXME.
//
RemoteMemoryManager *MM = static_cast <RemoteMemoryManager*>(RTDyldMM);
// Everything is prepared now, so lay out our program for the target
// address space, assign the section addresses to resolve any relocations,
// and send it to the target.
std::unique_ptr<RemoteTarget> Target;
if (!ChildExecPath.empty ()) { // Remote execution on a child process
#ifndef LLVM_ON_UNIX
// FIXME: Remove this pointless fallback mode which causes tests to "pass"
// on platforms where they should XFAIL.
errs () << " Warning: host does not support external remote targets.\n "
<< " Defaulting to simulated remote execution\n " ;
Target.reset (new RemoteTarget);
#else
if (!sys::fs::can_execute (ChildExecPath)) {
errs () << " Unable to find usable child executable: '" << ChildExecPath
<< " '\n " ;
return -1 ;
}
Target.reset (new RemoteTargetExternal (ChildExecPath));
#endif
} else {
// No child process name provided, use simulated remote execution.
Target.reset (new RemoteTarget);
// Lanch the remote process and get a channel to it.
std::unique_ptr<FDRPCChannel> C = launchRemote ();
if (!C) {
errs () << " Failed to launch remote JIT.\n " ;
exit (1 );
}
// Give the memory manager a pointer to our remote target interface object.
MM->setRemoteTarget (Target.get ());
// Create a remote target client running over the channel.
typedef orc::remote::OrcRemoteTargetClient<orc::remote::RPCChannel> MyRemote;
ErrorOr<MyRemote> R = MyRemote::Create (*C);
if (!R) {
errs () << " Could not create remote: " << R.getError ().message () << " \n " ;
exit (1 );
}
// Create the remote target.
if (!Target->create ()) {
errs () << " ERROR: " << Target->getErrorMsg () << " \n " ;
return EXIT_FAILURE;
// Create a remote memory manager.
std::unique_ptr<MyRemote::RCMemoryManager> RemoteMM;
if (auto EC = R->createRemoteMemoryManager (RemoteMM)) {
errs () << " Could not create remote memory manager: " << EC.message () << " \n " ;
exit (1 );
}
// Since we're executing in a (at least simulated) remote address space,
// we can't use the ExecutionEngine::runFunctionAsMain(). We have to
// grab the function address directly here and tell the remote target
// to execute the function.
//
// Our memory manager will map generated code into the remote address
// space as it is loaded and copy the bits over during the finalizeMemory
// operation.
//
// Forward MCJIT's memory manager calls to the remote memory manager.
static_cast <ForwardingMemoryManager*>(RTDyldMM)->setMemMgr (
std::move (RemoteMM));
// Forward MCJIT's symbol resolution calls to the remote.
static_cast <ForwardingMemoryManager*>(RTDyldMM)->setResolver (
orc::createLambdaResolver (
[&](const std::string &Name) {
orc::TargetAddress Addr = 0 ;
if (auto EC = R->getSymbolAddress (Addr, Name)) {
errs () << " Failure during symbol lookup: " << EC.message () << " \n " ;
exit (1 );
}
return RuntimeDyld::SymbolInfo (Addr, JITSymbolFlags::Exported);
},
[](const std::string &Name) { return nullptr ; }
));
// Grab the target address of the JIT'd main function on the remote and call
// it.
// FIXME: argv and envp handling.
uint64_t Entry = EE->getFunctionAddress (EntryFn->getName ().str ());
orc::TargetAddress Entry = EE->getFunctionAddress (EntryFn->getName ().str ());
EE-> finalizeObject ();
DEBUG (dbgs () << " Executing '" << EntryFn->getName () << " ' at 0x"
<< format (" %llx" , Entry) << " \n " );
if (!Target->executeCode (Entry, Result))
errs () << " ERROR: " << Target->getErrorMsg () << " \n " ;
if (auto EC = R->callIntVoid (Result, Entry))
errs () << " ERROR: " << EC.message () << " \n " ;
// Like static constructors, the remote target MCJIT support doesn't handle
// this yet. It could. FIXME.
// Stop the remote target
Target->stop ();
// Delete the EE - we need to tear it down *before* we terminate the session
// with the remote, otherwise it'll crash when it tries to release resources
// on a remote that has already been disconnected.
delete EE;
EE = nullptr ;
// Signal the remote target that we're done JITing.
R->terminateSession ();
}
return Result;
}
std::unique_ptr<FDRPCChannel> launchRemote () {
#ifndef LLVM_ON_UNIX
llvm_unreachable (" launchRemote not supported on non-Unix platforms" );
#else
int PipeFD[2 ][2 ];
pid_t ChildPID;
// Create two pipes.
if (pipe (PipeFD[0 ]) != 0 || pipe (PipeFD[1 ]) != 0 )
perror (" Error creating pipe: " );
ChildPID = fork ();
if (ChildPID == 0 ) {
// In the child...
// Close the parent ends of the pipes
close (PipeFD[0 ][1 ]);
close (PipeFD[1 ][0 ]);
// Execute the child process.
std::unique_ptr<char []> ChildPath, ChildIn, ChildOut;
{
ChildPath.reset (new char [ChildExecPath.size () + 1 ]);
std::copy (ChildExecPath.begin (), ChildExecPath.end (), &ChildPath[0 ]);
ChildPath[ChildExecPath.size ()] = ' \0 ' ;
std::string ChildInStr = std::to_string (PipeFD[0 ][0 ]);
ChildIn.reset (new char [ChildInStr.size () + 1 ]);
std::copy (ChildInStr.begin (), ChildInStr.end (), &ChildIn[0 ]);
ChildIn[ChildInStr.size ()] = ' \0 ' ;
std::string ChildOutStr = std::to_string (PipeFD[1 ][1 ]);
ChildOut.reset (new char [ChildOutStr.size () + 1 ]);
std::copy (ChildOutStr.begin (), ChildOutStr.end (), &ChildOut[0 ]);
ChildOut[ChildOutStr.size ()] = ' \0 ' ;
}
char * const args[] = { &ChildPath[0 ], &ChildIn[0 ], &ChildOut[0 ], nullptr };
int rc = execv (ChildExecPath.c_str (), args);
if (rc != 0 )
perror (" Error executing child process: " );
llvm_unreachable (" Error executing child process" );
}
// else we're the parent...
// Close the child ends of the pipes
close (PipeFD[0 ][0 ]);
close (PipeFD[1 ][1 ]);
// Return an RPC channel connected to our end of the pipes.
return llvm::make_unique<FDRPCChannel>(PipeFD[1 ][0 ], PipeFD[0 ][1 ]);
#endif
}