Make CreateArgv part of lli rather than part of ExecutionEngine.
authorBrian Gaeke <gaeke@uiuc.edu>
Fri, 5 Sep 2003 18:42:01 +0000 (18:42 +0000)
committerBrian Gaeke <gaeke@uiuc.edu>
Fri, 5 Sep 2003 18:42:01 +0000 (18:42 +0000)
Switch Interpreter and JIT's "run" methods to take a Function and a vector of
 GenericValues.
Move (almost all of) the stuff that constructs a canonical call to main()
 into lli (new methods "callAsMain", "makeStringVector").
Nuke getCurrentExecutablePath(), enableTracing(), getCurrentFunction(),
 isStopped(), and many dead decls from interpreter.
Add linux strdup() support to interpreter.
Make interpreter's atexit handler runner and JIT's runAtExitHandlers() look
 more alike, in preparation for refactoring.
atexit() is spelled "atexit", not "at_exit".

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@8366 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/ExecutionEngine/ExecutionEngine.h
lib/ExecutionEngine/ExecutionEngine.cpp
lib/ExecutionEngine/Interpreter/ExternalFunctions.cpp
lib/ExecutionEngine/Interpreter/Interpreter.cpp
lib/ExecutionEngine/Interpreter/Interpreter.h
lib/ExecutionEngine/JIT/Intercept.cpp
lib/ExecutionEngine/JIT/JIT.cpp
lib/ExecutionEngine/JIT/JIT.h
lib/ExecutionEngine/JIT/VM.h
tools/lli/lli.cpp

index 89a264333a4d9aafa15eb6d73bdf7260f1ffcef7..fdb219df66fcb650c7d5c7a577f0448ec407b882 100644 (file)
@@ -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<std::string> &Args,
-                  const char ** envp) = 0;
+  virtual GenericValue run(Function *F,
+                           const std::vector<GenericValue> &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<std::string> &InputArgv);
   void InitializeMemory(const Constant *Init, void *Addr);
 };
 
index a00c969908202fdc4a4ba7b2ea262ceb936222af..b4baf9f8ffffbb91bfce5a7f006e354984ea6fde 100644 (file)
@@ -316,45 +316,6 @@ void ExecutionEngine::InitializeMemory(const Constant *Init, void *Addr) {
   }
 }
 
-void *ExecutionEngine::CreateArgv(const std::vector<std::string> &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.
index d24557abe05ccabe73cbaf77e354415fcb6abde9..1a28e46d8d08b43938e8fad437c81d1fbb9b87fc 100644 (file)
@@ -29,22 +29,6 @@ static std::map<std::string, ExFunc> 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<GenericValue> &Args) {
   return Ret;
 }
 
+// char *strdup(const char *src);
+GenericValue lle_X_strdup(FunctionType *M, const vector<GenericValue> &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<GenericValue> &Args) {
   assert(Args.size() == 1);
index 6b82dada33929e2f8c34fdd528f53c423890ac02..518290a9f79b4ef1ba61ee32af8bd0b7ace27eac 100644 (file)
@@ -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<std::string> &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<GenericValue>());
+    AtExitHandlers.pop_back();
     run();
   }
-
-  do {
-    // If the program has exited, run atexit handlers...
-    if (ECStack.empty() && !AtExitHandlers.empty()) {
-      callFunction(AtExitHandlers.back(), std::vector<GenericValue>());
-      AtExitHandlers.pop_back();
-      run();
-    }
-  } while (!ECStack.empty());
-
-  return ExitCode;
 }
 
-
-// callMainFunction - Construct call to typical C main() function and
-// call it using callFunction().
-//
-bool Interpreter::callMainFunction(const std::string &Name,
-                                   const std::vector<std::string> &InputArgv) {
-  Function *M = getModule().getNamedFunction(Name);
-  if (M == 0) {
-    std::cerr << "Could not find function '" << Name << "' in module!\n";
-    return 1;
-  }
-  const FunctionType *MT = M->getFunctionType();
-
-  std::vector<GenericValue> 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);
-    }
+/// run - Start execution with the specified function and arguments.
+///
+GenericValue Interpreter::run(Function *F,
+                             const std::vector<GenericValue> &ArgValues) {
+  assert (F && "Function *F was null at entry to run()");
+
+  // 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<GenericValue> ActualArgs;
+  const unsigned ArgCount = F->getFunctionType()->getParamTypes().size();
+  for (unsigned i = 0; i < ArgCount; ++i) {
+    ActualArgs.push_back (ArgValues[i]);
   }
-
-  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;
 }
index 5434fe0b81e70e64c76fa8f00431dc67ceb2effd..ef0540c1fed5bf53df437ec40bb6c4ca5874eb2e 100644 (file)
@@ -79,41 +79,38 @@ class Interpreter : public ExecutionEngine, public InstVisitor<Interpreter> {
   // function record.
   std::vector<ExecutionContext> 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<Function*> 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<std::string> &Args,
-                  const char ** envp);
-
-  void enableTracing() { Trace = true; }
+  virtual GenericValue run(Function *F,
+                          const std::vector<GenericValue> &ArgValues);
 
-  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<std::string> &InputFilename);
-
-  // Code execution methods...
+  // Methods used to execute code:
+  // Place a call on the stack
   void callFunction(Function *F, const std::vector<GenericValue> &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<GenericValue> &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();
 };
index 10fd97015f2e58c23efc02f04e3db744ebc99ddd..09cbe28740a57779f45af0e9f127e9fc431ea929 100644 (file)
 #include "Config/dlfcn.h"    // dlsym access
 #include <iostream>
 
-// AtExitList - List of functions registered with the at_exit function
-static std::vector<void (*)()> AtExitList;
+// AtExitHandlers - List of functions to call when the program exits,
+// registered with the atexit() library function.
+static std::vector<void (*)()> 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
 }
 
index 9a2dc1aacb7dd91c50e928fedacab509f794ead4..4c4c2221e32d8f404806855761cce2688f4d8c61 100644 (file)
@@ -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<std::string> &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<GenericValue> &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;
 }
index 764afcf66fe4496775da49732a10145058797017..9a7a645a4ee6b6c33d404cbc3743c111fd52a3ed 100644 (file)
@@ -33,9 +33,8 @@ public:
 
   /// run - Start execution with the specified function and arguments.
   ///
-  virtual int run(const std::string &FnName,
-                  const std::vector<std::string> &Args,
-                  const char ** envp);
+  virtual GenericValue run(Function *F,
+                          const std::vector<GenericValue> &ArgValues);
 
   /// getPointerToNamedFunction - This method returns the address of the
   /// specified function by using the dlsym function call.  As such it is only
index 764afcf66fe4496775da49732a10145058797017..9a7a645a4ee6b6c33d404cbc3743c111fd52a3ed 100644 (file)
@@ -33,9 +33,8 @@ public:
 
   /// run - Start execution with the specified function and arguments.
   ///
-  virtual int run(const std::string &FnName,
-                  const std::vector<std::string> &Args,
-                  const char ** envp);
+  virtual GenericValue run(Function *F,
+                          const std::vector<GenericValue> &ArgValues);
 
   /// getPointerToNamedFunction - This method returns the address of the
   /// specified function by using the dlsym function call.  As such it is only
index db3526824a59dfefddabd69b86b5f0877dcb3028..125f075856768d715a0751bc9f121086731290df 100644 (file)
 //===----------------------------------------------------------------------===//
 
 #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<std::string>
@@ -33,10 +37,82 @@ namespace {
                                 cl::init(false));
 }
 
+static std::vector<std::string> makeStringVector (const char **envp) {
+  std::vector<std::string> rv;
+  for (unsigned i = 0; envp[i]; ++i)
+    rv.push_back (envp[i]);
+  return rv;
+}
+
+static void *CreateArgv(ExecutionEngine *EE,
+                       const std::vector<std::string> &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<std::string> &Args,
+                const std::vector<std::string> &EnvVars) {
+  Function *Fn = M->getNamedFunction (FnName);
+  if (!Fn) {
+    std::cerr << "Function '" << FnName << "' not found in module.\n";
+    return -1;
+  }
+  std::vector<GenericValue> 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;