Chris Lattner 2fbfdcffd3 Change references to the Method class to be references to the Function
class.  The Method class is obsolete (renamed) and all references to it
are being converted over to Function.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@2144 91177308-0d34-0410-b5e6-96231b3b80d8
2002-04-07 20:49:59 +00:00

334 lines
9.2 KiB
C++

//===-- 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 function
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 non-fn matches...
if (!isa<Function>(Options[i])) {
Options.erase(Options.begin()+i);
--i;
}
}
Value *PickedMeth = ChooseOneOption(Name, Options);
if (PickedMeth == 0)
return true;
Function *F = cast<Function>(PickedMeth);
std::vector<GenericValue> Args;
// TODO, get args from user...
callMethod(F, 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 non-fn matches...
if (!isa<Function>(Options[i])) {
Options.erase(Options.begin()+i);
--i;
}
}
Value *PickedMeth = ChooseOneOption(Name, Options);
if (PickedMeth == 0)
return true;
Function *M = cast<Function>(PickedMeth);
const FunctionType *MT = M->getFunctionType();
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 function out...
}
void Interpreter::printStackTrace() {
if (ECStack.empty()) cout << "No program executing!\n";
for (unsigned i = 0; i < ECStack.size(); ++i) {
printStackFrame((int)i);
}
}