1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-25 12:12:47 +01:00

[ORC] Add a runAsMain utility function to ExecutionUtils.

The runAsMain function takes a pointer to a function with a standard C main
signature, int(*)(int, char*[]), and invokes it using the given arguments and
program name. The arguments are copied into writable temporary storage as
required by the C and C++ specifications, so runAsMain safe to use when calling
main functions that modify their arguments in-place.

This patch also uses the new runAsMain function to replace hand-rolled versions
in lli, llvm-jitlink, and the SpeculativeJIT example.
This commit is contained in:
Lang Hames 2019-12-02 01:45:49 -08:00
parent a7131050a1
commit 2134d2b597
5 changed files with 47 additions and 41 deletions

View File

@ -176,20 +176,11 @@ int main(int argc, char *argv[]) {
ThreadSafeModule(std::move(M), std::move(Ctx))));
}
// Build an argv array for the JIT'd main.
std::vector<const char *> ArgV;
ArgV.push_back(argv[0]);
for (const auto &InputArg : InputArgv)
ArgV.push_back(InputArg.data());
ArgV.push_back(nullptr);
// Look up the JIT'd main, cast it to a function pointer, then call it.
auto MainSym = ExitOnErr(SJ->lookup("main"));
int (*Main)(int, const char *[]) =
(int (*)(int, const char *[]))MainSym.getAddress();
auto Main =
jitTargetAddressToFunction<int (*)(int, char *[])>(MainSym.getAddress());
Main(ArgV.size() - 1, ArgV.data());
return runAsMain(Main, InputArgv, StringRef(InputFiles.front()));
return 0;
}

View File

@ -40,6 +40,17 @@ namespace orc {
class ObjectLayer;
/// Run a main function, returning the result.
///
/// If the optional ProgramName argument is given then it will be inserted
/// before the strings in Args as the first argument to the called function.
///
/// It is legal to have an empty argument list and no program name, however
/// many main functions will expect a name argument at least, and will fail
/// if none is provided.
int runAsMain(int (*Main)(int, char *[]), ArrayRef<std::string> Args,
Optional<StringRef> ProgramName = None);
/// This iterator provides a convenient way to iterate over the elements
/// of an llvm.global_ctors/llvm.global_dtors instance.
///

View File

@ -19,6 +19,32 @@
namespace llvm {
namespace orc {
int runAsMain(int (*Main)(int, char *[]), ArrayRef<std::string> Args,
Optional<StringRef> ProgramName) {
std::vector<std::unique_ptr<char[]>> ArgVStorage;
std::vector<char *> ArgV;
ArgVStorage.reserve(Args.size() + (ProgramName ? 1 : 0));
ArgV.reserve(Args.size() + 1 + (ProgramName ? 1 : 0));
if (ProgramName) {
ArgVStorage.push_back(std::make_unique<char[]>(ProgramName->size() + 1));
llvm::copy(*ProgramName, &ArgVStorage.back()[0]);
ArgVStorage.back()[ProgramName->size()] = '\0';
ArgV.push_back(ArgVStorage.back().get());
}
for (auto &Arg : Args) {
ArgVStorage.push_back(std::make_unique<char[]>(Arg.size() + 1));
llvm::copy(Arg, &ArgVStorage.back()[0]);
ArgVStorage.back()[Arg.size()] = '\0';
ArgV.push_back(ArgVStorage.back().get());
}
ArgV.push_back(nullptr);
return Main(Args.size(), ArgV.data());
}
CtorDtorIterator::CtorDtorIterator(const GlobalVariable *GV, bool End)
: InitList(
GV ? dyn_cast_or_null<ConstantArray>(GV->getInitializer()) : nullptr),

View File

@ -871,16 +871,11 @@ int runOrcLazyJIT(const char *ProgName) {
// Run main.
auto MainSym = ExitOnErr(J->lookup("main"));
typedef int (*MainFnPtr)(int, const char *[]);
std::vector<const char *> ArgV;
for (auto &Arg : Args)
ArgV.push_back(Arg.c_str());
ArgV.push_back(nullptr);
int ArgC = ArgV.size() - 1;
auto Main =
reinterpret_cast<MainFnPtr>(static_cast<uintptr_t>(MainSym.getAddress()));
auto Result = Main(ArgC, (const char **)ArgV.data());
typedef int (*MainFnPtr)(int, char *[]);
auto Result = orc::runAsMain(
jitTargetAddressToFunction<MainFnPtr>(MainSym.getAddress()), Args,
StringRef("lli"));
// Wait for -entry-point threads.
for (auto &AltEntryThread : AltEntryThreads)

View File

@ -769,25 +769,6 @@ static Expected<JITEvaluatedSymbol> getMainEntryPoint(Session &S) {
return S.ES.lookup(S.JDSearchOrder, EntryPointName);
}
Expected<int> runEntryPoint(Session &S, JITEvaluatedSymbol EntryPoint) {
assert(EntryPoint.getAddress() && "Entry point address should not be null");
constexpr const char *JITProgramName = "<llvm-jitlink jit'd code>";
auto PNStorage = std::make_unique<char[]>(strlen(JITProgramName) + 1);
strcpy(PNStorage.get(), JITProgramName);
std::vector<const char *> EntryPointArgs;
EntryPointArgs.push_back(PNStorage.get());
for (auto &InputArg : InputArgv)
EntryPointArgs.push_back(InputArg.data());
EntryPointArgs.push_back(nullptr);
using MainTy = int (*)(int, const char *[]);
MainTy EntryPointPtr = reinterpret_cast<MainTy>(EntryPoint.getAddress());
return EntryPointPtr(EntryPointArgs.size() - 1, EntryPointArgs.data());
}
struct JITLinkTimers {
TimerGroup JITLinkTG{"llvm-jitlink timers", "timers for llvm-jitlink phases"};
Timer LoadObjectsTimer{"load", "time to load/add object files", JITLinkTG};
@ -841,8 +822,10 @@ int main(int argc, char *argv[]) {
int Result = 0;
{
using MainTy = int (*)(int, char *[]);
auto EntryFn = jitTargetAddressToFunction<MainTy>(EntryPoint.getAddress());
TimeRegion TR(Timers ? &Timers->RunTimer : nullptr);
Result = ExitOnErr(runEntryPoint(S, EntryPoint));
Result = runAsMain(EntryFn, InputArgv, StringRef(InputFiles.front()));
}
return Result;