| //===-- 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 |
| |
| 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"; |
| } |
| } |
| |
| |
| //===----------------------------------------------------------------------===// |
| // 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); |
| } |
| } |