|  | //===-- UserInput.cpp - Interpreter Input Loop support --------------------===// | 
|  | // | 
|  | //  This file implements the interpreter Input I/O loop. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "Interpreter.h" | 
|  | #include "llvm/Bytecode/Reader.h" | 
|  | #include "llvm/Assembly/Writer.h" | 
|  | #include "llvm/DerivedTypes.h" | 
|  | #include "llvm/Transforms/Linker.h" | 
|  | #include <algorithm> | 
|  | using std::string; | 
|  | using std::cout; | 
|  | using std::cin; | 
|  |  | 
|  | enum CommandID { | 
|  | Quit, Help,                                 // Basics | 
|  | Print, Info, List, StackTrace, Up, Down,    // Inspection | 
|  | Next, Step, Run, Finish, Call,              // Control flow changes | 
|  | Break, Watch,                               // Debugging | 
|  | Load, Flush, | 
|  | TraceOpt, ProfileOpt                              // Toggle features | 
|  | }; | 
|  |  | 
|  | // CommandTable - Build a lookup table for the commands available to the user... | 
|  | static struct CommandTableElement { | 
|  | const char *Name; | 
|  | enum CommandID CID; | 
|  |  | 
|  | inline bool operator<(const CommandTableElement &E) const { | 
|  | return string(Name) < string(E.Name); | 
|  | } | 
|  | inline bool operator==(const string &S) const { | 
|  | return string(Name) == S; | 
|  | } | 
|  | } CommandTable[] = { | 
|  | { "quit"     , Quit       }, { "q", Quit }, { "", Quit }, // Empty str = eof | 
|  | { "help"     , Help       }, { "h", Help }, | 
|  |  | 
|  | { "print"    , Print      }, { "p", Print }, | 
|  | { "list"     , List       }, | 
|  | { "info"     , Info       }, | 
|  | { "backtrace", StackTrace }, { "bt", StackTrace }, { "where", StackTrace }, | 
|  | { "up"       , Up         }, | 
|  | { "down"     , Down       }, | 
|  |  | 
|  | { "next"     , Next       }, { "n", Next }, | 
|  | { "step"     , Step       }, { "s", Step }, | 
|  | { "run"      , Run        }, | 
|  | { "finish"   , Finish     }, | 
|  | { "call"     , Call       }, | 
|  |  | 
|  | { "break"    , Break      }, { "b", Break }, | 
|  | { "watch"    , Watch      }, | 
|  |  | 
|  | { "load"     , Load       }, | 
|  | { "flush"    , Flush      }, | 
|  |  | 
|  | { "trace"    , TraceOpt   }, | 
|  | { "profile"  , ProfileOpt }, | 
|  | }; | 
|  | static CommandTableElement *CommandTableEnd = | 
|  | CommandTable+sizeof(CommandTable)/sizeof(CommandTable[0]); | 
|  |  | 
|  |  | 
|  | //===----------------------------------------------------------------------===// | 
|  | // handleUserInput - Enter the input loop for the interpreter.  This function | 
|  | // returns when the user quits the interpreter. | 
|  | // | 
|  | void Interpreter::handleUserInput() { | 
|  | bool UserQuit = false; | 
|  |  | 
|  | // Sort the table... | 
|  | std::sort(CommandTable, CommandTableEnd); | 
|  |  | 
|  | // Print the instruction that we are stopped at... | 
|  | printCurrentInstruction(); | 
|  |  | 
|  | do { | 
|  | string Command; | 
|  | cout << "lli> " << std::flush; | 
|  | cin >> Command; | 
|  |  | 
|  | CommandTableElement *E = find(CommandTable, CommandTableEnd, Command); | 
|  |  | 
|  | if (E == CommandTableEnd) { | 
|  | cout << "Error: '" << Command << "' not recognized!\n"; | 
|  | continue; | 
|  | } | 
|  |  | 
|  | switch (E->CID) { | 
|  | case Quit:       UserQuit = true;   break; | 
|  | case Load: | 
|  | cin >> Command; | 
|  | loadModule(Command); | 
|  | break; | 
|  | case Flush: flushModule(); break; | 
|  | case Print: | 
|  | cin >> Command; | 
|  | print(Command); | 
|  | break; | 
|  | case Info: | 
|  | cin >> Command; | 
|  | infoValue(Command); | 
|  | break; | 
|  |  | 
|  | case List:       list();            break; | 
|  | case StackTrace: printStackTrace(); break; | 
|  | case Up: | 
|  | if (CurFrame > 0) { --CurFrame; printStackFrame(); } | 
|  | else cout << "Error: Already at root of stack!\n"; | 
|  | break; | 
|  | case Down: | 
|  | if ((unsigned)CurFrame < ECStack.size()-1) { | 
|  | ++CurFrame; | 
|  | printStackFrame(); | 
|  | } else | 
|  | cout << "Error: Already at bottom of stack!\n"; | 
|  | break; | 
|  | case Next:       nextInstruction(); break; | 
|  | case Step:       stepInstruction(); break; | 
|  | case Run:        run();             break; | 
|  | case Finish:     finish();          break; | 
|  | case Call: | 
|  | cin >> Command; | 
|  | callMethod(Command);    // Enter the specified method | 
|  | finish();               // Run until it's complete | 
|  | break; | 
|  |  | 
|  | case TraceOpt: | 
|  | Trace = !Trace; | 
|  | cout << "Tracing " << (Trace ? "enabled\n" : "disabled\n"); | 
|  | break; | 
|  |  | 
|  | case ProfileOpt: | 
|  | Profile = !Profile; | 
|  | cout << "Profiling " << (Trace ? "enabled\n" : "disabled\n"); | 
|  | break; | 
|  |  | 
|  | default: | 
|  | cout << "Command '" << Command << "' unimplemented!\n"; | 
|  | break; | 
|  | } | 
|  |  | 
|  | } while (!UserQuit); | 
|  | } | 
|  |  | 
|  | //===----------------------------------------------------------------------===// | 
|  | // loadModule - Load a new module to execute... | 
|  | // | 
|  | void Interpreter::loadModule(const string &Filename) { | 
|  | string ErrorMsg; | 
|  | if (CurMod && !flushModule()) return;  // Kill current execution | 
|  |  | 
|  | CurMod = ParseBytecodeFile(Filename, &ErrorMsg); | 
|  | if (CurMod == 0) { | 
|  | cout << "Error parsing '" << Filename << "': No module loaded: " | 
|  | << ErrorMsg << "\n"; | 
|  | return; | 
|  | } | 
|  | CW.setModule(CurMod);  // Update Writer | 
|  |  | 
|  | #if 0 | 
|  | string RuntimeLib = getCurrentExecutablePath(); | 
|  | if (!RuntimeLib.empty()) RuntimeLib += "/"; | 
|  | RuntimeLib += "RuntimeLib.bc"; | 
|  |  | 
|  | if (Module *SupportLib = ParseBytecodeFile(RuntimeLib, &ErrorMsg)) { | 
|  | if (LinkModules(CurMod, SupportLib, &ErrorMsg)) | 
|  | std::cerr << "Error Linking runtime library into current module: " | 
|  | << ErrorMsg << "\n"; | 
|  | } else { | 
|  | std::cerr << "Error loading runtime library '"+RuntimeLib+"': " | 
|  | << ErrorMsg << "\n"; | 
|  | } | 
|  | #endif | 
|  | } | 
|  |  | 
|  |  | 
|  | //===----------------------------------------------------------------------===// | 
|  | // flushModule - Return true if the current program has been unloaded. | 
|  | // | 
|  | bool Interpreter::flushModule() { | 
|  | if (CurMod == 0) { | 
|  | cout << "Error flushing: No module loaded!\n"; | 
|  | return false; | 
|  | } | 
|  |  | 
|  | if (!ECStack.empty()) { | 
|  | // TODO: if use is not sure, return false | 
|  | cout << "Killing current execution!\n"; | 
|  | ECStack.clear(); | 
|  | CurFrame = -1; | 
|  | } | 
|  |  | 
|  | CW.setModule(0); | 
|  | delete CurMod; | 
|  | CurMod = 0; | 
|  | ExitCode = 0; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | //===----------------------------------------------------------------------===// | 
|  | // setBreakpoint - Enable a breakpoint at the specified location | 
|  | // | 
|  | void Interpreter::setBreakpoint(const string &Name) { | 
|  | Value *PickedVal = ChooseOneOption(Name, LookupMatchingNames(Name)); | 
|  | // TODO: Set a breakpoint on PickedVal | 
|  | } | 
|  |  | 
|  | //===----------------------------------------------------------------------===// | 
|  | // callMethod - Enter the specified method... | 
|  | // | 
|  | bool Interpreter::callMethod(const string &Name) { | 
|  | std::vector<Value*> Options = LookupMatchingNames(Name); | 
|  |  | 
|  | for (unsigned i = 0; i < Options.size(); ++i) { // Remove nonmethod matches... | 
|  | if (!isa<Method>(Options[i])) { | 
|  | Options.erase(Options.begin()+i); | 
|  | --i; | 
|  | } | 
|  | } | 
|  |  | 
|  | Value *PickedMeth = ChooseOneOption(Name, Options); | 
|  | if (PickedMeth == 0) | 
|  | return true; | 
|  |  | 
|  | Method *M = cast<Method>(PickedMeth); | 
|  |  | 
|  | std::vector<GenericValue> Args; | 
|  | // TODO, get args from user... | 
|  |  | 
|  | callMethod(M, Args);  // Start executing it... | 
|  |  | 
|  | // Reset the current frame location to the top of stack | 
|  | CurFrame = ECStack.size()-1; | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | static void *CreateArgv(const std::vector<string> &InputArgv) { | 
|  | // Pointers are 64 bits... | 
|  | uint64_t *Result = new PointerTy[InputArgv.size()+1]; | 
|  |  | 
|  | for (unsigned i = 0; i < InputArgv.size(); ++i) { | 
|  | unsigned Size = InputArgv[i].size()+1; | 
|  | char *Dest = new char[Size]; | 
|  | copy(InputArgv[i].begin(), InputArgv[i].end(), Dest); | 
|  | Dest[Size-1] = 0; | 
|  | Result[i] = (PointerTy)Dest; | 
|  | } | 
|  |  | 
|  | Result[InputArgv.size()] = 0; | 
|  | return Result; | 
|  | } | 
|  |  | 
|  |  | 
|  | // callMainMethod - This is a nasty gross hack that will dissapear when | 
|  | // callMethod can parse command line options and stuff for us. | 
|  | // | 
|  | bool Interpreter::callMainMethod(const string &Name, | 
|  | const std::vector<string> &InputArgv) { | 
|  | std::vector<Value*> Options = LookupMatchingNames(Name); | 
|  |  | 
|  | for (unsigned i = 0; i < Options.size(); ++i) { // Remove nonmethod matches... | 
|  | if (!isa<Method>(Options[i])) { | 
|  | Options.erase(Options.begin()+i); | 
|  | --i; | 
|  | } | 
|  | } | 
|  |  | 
|  | Value *PickedMeth = ChooseOneOption(Name, Options); | 
|  | if (PickedMeth == 0) | 
|  | return true; | 
|  |  | 
|  | Method *M = cast<Method>(PickedMeth); | 
|  | const MethodType *MT = M->getMethodType(); | 
|  |  | 
|  | std::vector<GenericValue> Args; | 
|  | switch (MT->getParamTypes().size()) { | 
|  | default: | 
|  | cout << "Unknown number of arguments to synthesize for '" << Name << "'!\n"; | 
|  | return true; | 
|  | case 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; | 
|  | } | 
|  |  | 
|  | GenericValue GV; GV.PointerVal = (uint64_t)CreateArgv(InputArgv); | 
|  | Args.push_back(GV); | 
|  | } | 
|  | // fallthrough | 
|  | case 1: | 
|  | if (!MT->getParamTypes()[0]->isIntegral()) { | 
|  | cout << "First argument of '" << Name << "' should be integral!\n"; | 
|  | return true; | 
|  | } else { | 
|  | GenericValue GV; GV.UIntVal = InputArgv.size(); | 
|  | Args.insert(Args.begin(), GV); | 
|  | } | 
|  | // fallthrough | 
|  | case 0: | 
|  | break; | 
|  | } | 
|  |  | 
|  | callMethod(M, Args);  // Start executing it... | 
|  |  | 
|  | // Reset the current frame location to the top of stack | 
|  | CurFrame = ECStack.size()-1; | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  | void Interpreter::list() { | 
|  | if (ECStack.empty()) | 
|  | cout << "Error: No program executing!\n"; | 
|  | else | 
|  | CW << ECStack[CurFrame].CurMethod;   // Just print the method out... | 
|  | } | 
|  |  | 
|  | void Interpreter::printStackTrace() { | 
|  | if (ECStack.empty()) cout << "No program executing!\n"; | 
|  |  | 
|  | for (unsigned i = 0; i < ECStack.size(); ++i) { | 
|  | printStackFrame((int)i); | 
|  | } | 
|  | } |