diff --git a/include/llvm/ExecutionEngine/ExecutionEngine.h b/include/llvm/ExecutionEngine/ExecutionEngine.h index 89a264333a4..fdb219df66f 100644 --- a/include/llvm/ExecutionEngine/ExecutionEngine.h +++ b/include/llvm/ExecutionEngine/ExecutionEngine.h @@ -44,9 +44,8 @@ public: /// run - Start execution with the specified function, arguments, and /// environment. /// - virtual int run(const std::string &FnName, - const std::vector &Args, - const char ** envp) = 0; + virtual GenericValue run(Function *F, + const std::vector &ArgValues) = 0; static ExecutionEngine *create (Module *M, bool ForceInterpreter, bool TraceMode); @@ -83,7 +82,6 @@ public: // FIXME: protected: // API shared among subclasses GenericValue getConstantValue(const Constant *C); void StoreValueToMemory(GenericValue Val, GenericValue *Ptr, const Type *Ty); GenericValue LoadValueFromMemory(GenericValue *Ptr, const Type *Ty); - void *CreateArgv(const std::vector &InputArgv); void InitializeMemory(const Constant *Init, void *Addr); }; diff --git a/lib/ExecutionEngine/ExecutionEngine.cpp b/lib/ExecutionEngine/ExecutionEngine.cpp index a00c9699082..b4baf9f8fff 100644 --- a/lib/ExecutionEngine/ExecutionEngine.cpp +++ b/lib/ExecutionEngine/ExecutionEngine.cpp @@ -316,45 +316,6 @@ void ExecutionEngine::InitializeMemory(const Constant *Init, void *Addr) { } } -void *ExecutionEngine::CreateArgv(const std::vector &InputArgv) { - if (getTargetData().getPointerSize() == 8) { // 64 bit target? - PointerTy *Result = new PointerTy[InputArgv.size()+1]; - DEBUG(std::cerr << "ARGV = " << (void*)Result << "\n"); - - for (unsigned i = 0; i < InputArgv.size(); ++i) { - unsigned Size = InputArgv[i].size()+1; - char *Dest = new char[Size]; - DEBUG(std::cerr << "ARGV[" << i << "] = " << (void*)Dest << "\n"); - - copy(InputArgv[i].begin(), InputArgv[i].end(), Dest); - Dest[Size-1] = 0; - - // Endian safe: Result[i] = (PointerTy)Dest; - StoreValueToMemory(PTOGV(Dest), (GenericValue*)(Result+i), Type::LongTy); - } - Result[InputArgv.size()] = 0; - return Result; - - } else { // 32 bit target? - int *Result = new int[InputArgv.size()+1]; - DEBUG(std::cerr << "ARGV = " << (void*)Result << "\n"); - - for (unsigned i = 0; i < InputArgv.size(); ++i) { - unsigned Size = InputArgv[i].size()+1; - char *Dest = new char[Size]; - DEBUG(std::cerr << "ARGV[" << i << "] = " << (void*)Dest << "\n"); - - copy(InputArgv[i].begin(), InputArgv[i].end(), Dest); - Dest[Size-1] = 0; - - // Endian safe: Result[i] = (PointerTy)Dest; - StoreValueToMemory(PTOGV(Dest), (GenericValue*)(Result+i), Type::IntTy); - } - Result[InputArgv.size()] = 0; // null terminate it - return Result; - } -} - /// EmitGlobals - Emit all of the global variables to memory, storing their /// addresses into GlobalAddress. This must make sure to copy the contents of /// their initializers into the memory. diff --git a/lib/ExecutionEngine/Interpreter/ExternalFunctions.cpp b/lib/ExecutionEngine/Interpreter/ExternalFunctions.cpp index d24557abe05..1a28e46d8d0 100644 --- a/lib/ExecutionEngine/Interpreter/ExternalFunctions.cpp +++ b/lib/ExecutionEngine/Interpreter/ExternalFunctions.cpp @@ -29,22 +29,6 @@ static std::map FuncNames; static Interpreter *TheInterpreter; -// getCurrentExecutablePath() - Return the directory that the lli executable -// lives in. -// -std::string Interpreter::getCurrentExecutablePath() const { - Dl_info Info; - if (dladdr(&TheInterpreter, &Info) == 0) return ""; - - std::string LinkAddr(Info.dli_fname); - unsigned SlashPos = LinkAddr.rfind('/'); - if (SlashPos != std::string::npos) - LinkAddr.resize(SlashPos); // Trim the executable name off... - - return LinkAddr; -} - - static char getTypeID(const Type *Ty) { switch (Ty->getPrimitiveID()) { case Type::VoidTyID: return 'V'; @@ -498,6 +482,12 @@ GenericValue lle_X_strlen(FunctionType *M, const vector &Args) { return Ret; } +// char *strdup(const char *src); +GenericValue lle_X_strdup(FunctionType *M, const vector &Args) { + assert(Args.size() == 1); + return PTOGV(strdup((char*)GVTOP(Args[0]))); +} + // char *__strdup(const char *src); GenericValue lle_X___strdup(FunctionType *M, const vector &Args) { assert(Args.size() == 1); diff --git a/lib/ExecutionEngine/Interpreter/Interpreter.cpp b/lib/ExecutionEngine/Interpreter/Interpreter.cpp index 6b82dada339..518290a9f79 100644 --- a/lib/ExecutionEngine/Interpreter/Interpreter.cpp +++ b/lib/ExecutionEngine/Interpreter/Interpreter.cpp @@ -54,69 +54,46 @@ Interpreter::Interpreter(Module *M, bool isLittleEndian, bool isLongPointer, emitGlobals(); } -/// run - Start execution with the specified function and arguments. -/// -int Interpreter::run(const std::string &MainFunction, - const std::vector &Args, - const char ** envp) { - // Start interpreter into the main function... - // - if (!callMainFunction(MainFunction, Args)) { - // If the call succeeded, run the code now... +void Interpreter::runAtExitHandlers () { + while (!AtExitHandlers.empty()) { + callFunction(AtExitHandlers.back(), std::vector()); + AtExitHandlers.pop_back(); run(); } - - do { - // If the program has exited, run atexit handlers... - if (ECStack.empty() && !AtExitHandlers.empty()) { - callFunction(AtExitHandlers.back(), std::vector()); - AtExitHandlers.pop_back(); - run(); - } - } while (!ECStack.empty()); - - return ExitCode; } +/// run - Start execution with the specified function and arguments. +/// +GenericValue Interpreter::run(Function *F, + const std::vector &ArgValues) { + assert (F && "Function *F was null at entry to run()"); -// callMainFunction - Construct call to typical C main() function and -// call it using callFunction(). -// -bool Interpreter::callMainFunction(const std::string &Name, - const std::vector &InputArgv) { - Function *M = getModule().getNamedFunction(Name); - if (M == 0) { - std::cerr << "Could not find function '" << Name << "' in module!\n"; - return 1; + // Try extra hard not to pass extra args to a function that isn't + // expecting them. C programmers frequently bend the rules and + // declare main() with fewer parameters than it actually gets + // passed, and the interpreter barfs if you pass a function more + // parameters than it is declared to take. This does not attempt to + // take into account gratuitous differences in declared types, + // though. + std::vector ActualArgs; + const unsigned ArgCount = F->getFunctionType()->getParamTypes().size(); + for (unsigned i = 0; i < ArgCount; ++i) { + ActualArgs.push_back (ArgValues[i]); } - const FunctionType *MT = M->getFunctionType(); - - std::vector Args; - if (MT->getParamTypes().size() >= 2) { - PointerType *SPP = PointerType::get(PointerType::get(Type::SByteTy)); - if (MT->getParamTypes()[1] != SPP) { - CW << "Second argument of '" << Name << "' should have type: '" - << SPP << "'!\n"; - return true; - } - Args.push_back(PTOGV(CreateArgv(InputArgv))); - } - - if (MT->getParamTypes().size() >= 1) { - if (!MT->getParamTypes()[0]->isInteger()) { - std::cout << "First argument of '" << Name - << "' should be an integer!\n"; - return true; - } else { - GenericValue GV; GV.UIntVal = InputArgv.size(); - Args.insert(Args.begin(), GV); - } - } - - callFunction(M, Args); // Start executing it... + + // Set up the function call. + callFunction(F, ActualArgs); // Reset the current frame location to the top of stack CurFrame = ECStack.size()-1; - return false; + // Start executing the function. + run(); + + // Run any atexit handlers now! + runAtExitHandlers(); + + GenericValue rv; + rv.IntVal = ExitCode; + return rv; } diff --git a/lib/ExecutionEngine/Interpreter/Interpreter.h b/lib/ExecutionEngine/Interpreter/Interpreter.h index 5434fe0b81e..ef0540c1fed 100644 --- a/lib/ExecutionEngine/Interpreter/Interpreter.h +++ b/lib/ExecutionEngine/Interpreter/Interpreter.h @@ -79,41 +79,38 @@ class Interpreter : public ExecutionEngine, public InstVisitor { // function record. std::vector ECStack; - // AtExitHandlers - List of functions to call when the program exits. + // AtExitHandlers - List of functions to call when the program exits, + // registered with the atexit() library function. std::vector AtExitHandlers; public: Interpreter(Module *M, bool isLittleEndian, bool isLongPointer, bool TraceMode); inline ~Interpreter() { CW.setModule(0); } + /// runAtExitHandlers - Run any functions registered by the + /// program's calls to atexit(3), which we intercept and store in + /// AtExitHandlers. + /// + void runAtExitHandlers (); + /// create - Create an interpreter ExecutionEngine. This can never fail. /// static ExecutionEngine *create(Module *M, bool TraceMode); /// run - Start execution with the specified function and arguments. /// - virtual int run(const std::string &FnName, - const std::vector &Args, - const char ** envp); - + virtual GenericValue run(Function *F, + const std::vector &ArgValues); - void enableTracing() { Trace = true; } - - void handleUserInput(); - - // User Interation Methods... - bool callFunction(const std::string &Name); // return true on failure + // Methods used for debug printouts: static void print(const Type *Ty, GenericValue V); static void printValue(const Type *Ty, GenericValue V); - bool callMainFunction(const std::string &MainName, - const std::vector &InputFilename); - - // Code execution methods... + // Methods used to execute code: + // Place a call on the stack void callFunction(Function *F, const std::vector &ArgVals); - void executeInstruction(); // Execute one instruction... - - void run(); // Do the 'run' command + void executeInstruction(); // Execute one instruction + void run(); // Execute instructions until nothing left to do // Opcode Implementations void visitReturnInst(ReturnInst &I); @@ -142,16 +139,6 @@ public: const std::vector &ArgVals); void exitCalled(GenericValue GV); - // getCurrentFunction - Return the currently executing function - inline Function *getCurrentFunction() const { - return CurFrame < 0 ? 0 : ECStack[CurFrame].CurFunction; - } - - // isStopped - Return true if a program is stopped. Return false if no - // program is running. - // - inline bool isStopped() const { return !ECStack.empty(); } - void addAtExitHandler(Function *F) { AtExitHandlers.push_back(F); } @@ -170,16 +157,6 @@ private: // Helper functions void *getPointerToFunction(Function *F) { return (void*)F; } - // getCurrentExecutablePath() - Return the directory that the lli executable - // lives in. - // - std::string getCurrentExecutablePath() const; - - // printCurrentInstruction - Print out the instruction that the virtual PC is - // at, or fail silently if no program is running. - // - void printCurrentInstruction(); - void initializeExecutionEngine(); void initializeExternalFunctions(); }; diff --git a/lib/ExecutionEngine/JIT/Intercept.cpp b/lib/ExecutionEngine/JIT/Intercept.cpp index 10fd97015f2..09cbe28740a 100644 --- a/lib/ExecutionEngine/JIT/Intercept.cpp +++ b/lib/ExecutionEngine/JIT/Intercept.cpp @@ -12,33 +12,38 @@ #include "Config/dlfcn.h" // dlsym access #include -// AtExitList - List of functions registered with the at_exit function -static std::vector AtExitList; +// AtExitHandlers - List of functions to call when the program exits, +// registered with the atexit() library function. +static std::vector AtExitHandlers; +/// runAtExitHandlers - Run any functions registered by the program's +/// calls to atexit(3), which we intercept and store in +/// AtExitHandlers. +/// void VM::runAtExitHandlers() { - while (!AtExitList.empty()) { - void (*Fn)() = AtExitList.back(); - AtExitList.pop_back(); + while (!AtExitHandlers.empty()) { + void (*Fn)() = AtExitHandlers.back(); + AtExitHandlers.pop_back(); Fn(); } } //===----------------------------------------------------------------------===// -// Function stubs that are invoked instead of raw system calls +// Function stubs that are invoked instead of certain library calls //===----------------------------------------------------------------------===// // NoopFn - Used if we have nothing else to call... static void NoopFn() {} -// jit_exit - Used to intercept the "exit" system call. +// jit_exit - Used to intercept the "exit" library call. static void jit_exit(int Status) { - VM::runAtExitHandlers(); // Run at_exit handlers... + VM::runAtExitHandlers(); // Run atexit handlers... exit(Status); } -// jit_atexit - Used to intercept the "at_exit" system call. +// jit_atexit - Used to intercept the "atexit" library call. static int jit_atexit(void (*Fn)(void)) { - AtExitList.push_back(Fn); // Take note of at_exit handler... + AtExitHandlers.push_back(Fn); // Take note of atexit handler... return 0; // Always successful } diff --git a/lib/ExecutionEngine/JIT/JIT.cpp b/lib/ExecutionEngine/JIT/JIT.cpp index 9a2dc1aacb7..4c4c2221e32 100644 --- a/lib/ExecutionEngine/JIT/JIT.cpp +++ b/lib/ExecutionEngine/JIT/JIT.cpp @@ -6,6 +6,7 @@ //===----------------------------------------------------------------------===// #include "VM.h" +#include "../GenericValue.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetMachineImpls.h" #include "llvm/Module.h" @@ -100,38 +101,24 @@ VM::VM(Module *M, TargetMachine *tm) : ExecutionEngine(M), TM(*tm) { emitGlobals(); } -/// VM::run - This method begins the execution of a program beginning at the -/// specified function name. The function is called with the specified -/// arguments and array of environment variables (a la main()). +/// run - Start execution with the specified function and arguments. /// -/// Inputs: -/// FnName - The name of the function as a C++ string. -/// Args - A vector of C++ strings containing the arguments. -/// envp - An array of C strings containing the environment. -/// -/// Return value: -/// 1 - An error occurred. -/// Otherwise, the return value from the specified function is returned. -/// -int VM::run(const std::string &FnName, const std::vector &Args, - const char **envp) { - Function *F = getModule().getNamedFunction(FnName); - if (F == 0) { - std::cerr << "Could not find function '" << FnName << "' in module!\n"; - return 1; - } +GenericValue VM::run(Function *F, const std::vector &ArgValues) +{ + assert (F && "Function *F was null at entry to run()"); - int (*PF)(int, char**, const char**) = - (int(*)(int, char**, const char**))getPointerToFunction(F); - assert(PF != 0 && "Null pointer to function?"); + int (*PF)(int, char **, const char **) = + (int(*)(int, char **, const char **))getPointerToFunction(F); + assert(PF != 0 && "Pointer to fn's code was null after getPointerToFunction"); - // Build an argv vector... - char **Argv = (char**)CreateArgv(Args); - - // Call the main function... - int Result = PF(Args.size(), Argv, envp); + // Call the function. + int ExitCode = PF(ArgValues[0].IntVal, (char **) GVTOP (ArgValues[1]), + (const char **) GVTOP (ArgValues[2])); // Run any atexit handlers now! runAtExitHandlers(); - return Result; + + GenericValue rv; + rv.IntVal = ExitCode; + return rv; } diff --git a/lib/ExecutionEngine/JIT/JIT.h b/lib/ExecutionEngine/JIT/JIT.h index 764afcf66fe..9a7a645a4ee 100644 --- a/lib/ExecutionEngine/JIT/JIT.h +++ b/lib/ExecutionEngine/JIT/JIT.h @@ -33,9 +33,8 @@ public: /// run - Start execution with the specified function and arguments. /// - virtual int run(const std::string &FnName, - const std::vector &Args, - const char ** envp); + virtual GenericValue run(Function *F, + const std::vector &ArgValues); /// getPointerToNamedFunction - This method returns the address of the /// specified function by using the dlsym function call. As such it is only diff --git a/lib/ExecutionEngine/JIT/VM.h b/lib/ExecutionEngine/JIT/VM.h index 764afcf66fe..9a7a645a4ee 100644 --- a/lib/ExecutionEngine/JIT/VM.h +++ b/lib/ExecutionEngine/JIT/VM.h @@ -33,9 +33,8 @@ public: /// run - Start execution with the specified function and arguments. /// - virtual int run(const std::string &FnName, - const std::vector &Args, - const char ** envp); + virtual GenericValue run(Function *F, + const std::vector &ArgValues); /// getPointerToNamedFunction - This method returns the address of the /// specified function by using the dlsym function call. As such it is only diff --git a/tools/lli/lli.cpp b/tools/lli/lli.cpp index db3526824a5..125f0758567 100644 --- a/tools/lli/lli.cpp +++ b/tools/lli/lli.cpp @@ -10,10 +10,14 @@ //===----------------------------------------------------------------------===// #include "ExecutionEngine.h" +#include "GenericValue.h" #include "Support/CommandLine.h" +#include "Support/Debug.h" #include "llvm/Bytecode/Reader.h" #include "llvm/Module.h" #include "llvm/Target/TargetMachineImpls.h" +#include "llvm/DerivedTypes.h" +#include "llvm/Target/TargetData.h" namespace { cl::opt @@ -33,10 +37,82 @@ namespace { cl::init(false)); } +static std::vector makeStringVector (const char **envp) { + std::vector rv; + for (unsigned i = 0; envp[i]; ++i) + rv.push_back (envp[i]); + return rv; +} + +static void *CreateArgv(ExecutionEngine *EE, + const std::vector &InputArgv) { + if (EE->getTargetData().getPointerSize() == 8) { // 64 bit target? + PointerTy *Result = new PointerTy[InputArgv.size()+1]; + DEBUG(std::cerr << "ARGV = " << (void*)Result << "\n"); + + for (unsigned i = 0; i < InputArgv.size(); ++i) { + unsigned Size = InputArgv[i].size()+1; + char *Dest = new char[Size]; + DEBUG(std::cerr << "ARGV[" << i << "] = " << (void*)Dest << "\n"); + + std::copy(InputArgv[i].begin(), InputArgv[i].end(), Dest); + Dest[Size-1] = 0; + + // Endian safe: Result[i] = (PointerTy)Dest; + EE->StoreValueToMemory(PTOGV(Dest), (GenericValue*)(Result+i), + Type::LongTy); + } + Result[InputArgv.size()] = 0; + return Result; + } else { // 32 bit target? + int *Result = new int[InputArgv.size()+1]; + DEBUG(std::cerr << "ARGV = " << (void*)Result << "\n"); + + for (unsigned i = 0; i < InputArgv.size(); ++i) { + unsigned Size = InputArgv[i].size()+1; + char *Dest = new char[Size]; + DEBUG(std::cerr << "ARGV[" << i << "] = " << (void*)Dest << "\n"); + + std::copy(InputArgv[i].begin(), InputArgv[i].end(), Dest); + Dest[Size-1] = 0; + + // Endian safe: Result[i] = (PointerTy)Dest; + EE->StoreValueToMemory(PTOGV(Dest), (GenericValue*)(Result+i), + Type::IntTy); + } + Result[InputArgv.size()] = 0; // null terminate it + return Result; + } +} + +/// callAsMain - Call the function named FnName from M as if its +/// signature were int main (int argc, char **argv, const char +/// **envp), using the contents of Args to determine argc & argv, and +/// the contents of EnvVars to determine envp. Returns the result +/// from calling FnName, or -1 and prints an error msg. if the named +/// function cannot be found. +/// +int callAsMain (ExecutionEngine *EE, Module *M, const std::string &FnName, + const std::vector &Args, + const std::vector &EnvVars) { + Function *Fn = M->getNamedFunction (FnName); + if (!Fn) { + std::cerr << "Function '" << FnName << "' not found in module.\n"; + return -1; + } + std::vector GVArgs; + GenericValue GVArgc; + GVArgc.IntVal = Args.size (); + GVArgs.push_back (GVArgc); // Arg #0 = argc. + GVArgs.push_back (PTOGV (CreateArgv (EE, Args))); // Arg #1 = argv. + GVArgs.push_back (PTOGV (CreateArgv (EE, EnvVars))); // Arg #2 = envp. + return EE->run (Fn, GVArgs).IntVal; +} + //===----------------------------------------------------------------------===// // main Driver function // -int main(int argc, char** argv, const char ** envp) { +int main(int argc, char **argv, const char **envp) { cl::ParseCommandLineOptions(argc, argv, " llvm interpreter & dynamic compiler\n"); @@ -64,7 +140,8 @@ int main(int argc, char** argv, const char ** envp) { InputArgv.insert(InputArgv.begin(), InputFile); // Run the main function! - int ExitCode = EE->run(MainFunction, InputArgv, envp); + int ExitCode = callAsMain (EE, M, MainFunction, InputArgv, + makeStringVector (envp)); // Now that we are done executing the program, shut down the execution engine delete EE;