blob: 7ece7bc54b9af7e9edcc4c1d46d9092da3d860d2 [file] [log] [blame]
Chris Lattner92101ac2001-08-23 17:05:04 +00001//===-- UserInput.cpp - Interpreter Input Loop support --------------------===//
2//
3// This file implements the interpreter Input I/O loop.
4//
5//===----------------------------------------------------------------------===//
6
7#include "Interpreter.h"
Chris Lattner2e42d3a2001-10-15 05:51:48 +00008#include "llvm/Bytecode/Reader.h"
Chris Lattner92101ac2001-08-23 17:05:04 +00009#include "llvm/Assembly/Writer.h"
Chris Lattnerf8f2afb2001-10-18 21:55:32 +000010#include "llvm/DerivedTypes.h"
Chris Lattnere43db882001-10-27 04:15:57 +000011#include "llvm/Transforms/Linker.h"
Chris Lattner92101ac2001-08-23 17:05:04 +000012#include <algorithm>
13
14enum CommandID {
Chris Lattner86660982001-08-27 05:16:50 +000015 Quit, Help, // Basics
16 Print, Info, List, StackTrace, Up, Down, // Inspection
17 Next, Step, Run, Finish, Call, // Control flow changes
18 Break, Watch, // Debugging
Chris Lattner43e3f7c2001-10-27 08:43:52 +000019 Load, Flush,
20 TraceOpt, ProfileOpt // Toggle features
Chris Lattner92101ac2001-08-23 17:05:04 +000021};
22
23// CommandTable - Build a lookup table for the commands available to the user...
24static struct CommandTableElement {
25 const char *Name;
26 enum CommandID CID;
27
28 inline bool operator<(const CommandTableElement &E) const {
29 return string(Name) < string(E.Name);
30 }
31 inline bool operator==(const string &S) const {
32 return string(Name) == S;
33 }
34} CommandTable[] = {
35 { "quit" , Quit }, { "q", Quit }, { "", Quit }, // Empty str = eof
36 { "help" , Help }, { "h", Help },
37
38 { "print" , Print }, { "p", Print },
39 { "list" , List },
Chris Lattner86660982001-08-27 05:16:50 +000040 { "info" , Info },
Chris Lattner92101ac2001-08-23 17:05:04 +000041 { "backtrace", StackTrace }, { "bt", StackTrace }, { "where", StackTrace },
42 { "up" , Up },
43 { "down" , Down },
44
45 { "next" , Next }, { "n", Next },
46 { "step" , Step }, { "s", Step },
47 { "run" , Run },
48 { "finish" , Finish },
49 { "call" , Call },
50
51 { "break" , Break }, { "b", Break },
52 { "watch" , Watch },
53
54 { "load" , Load },
55 { "flush" , Flush },
Chris Lattner43e3f7c2001-10-27 08:43:52 +000056
57 { "trace" , TraceOpt },
58 { "profile" , ProfileOpt },
Chris Lattner92101ac2001-08-23 17:05:04 +000059};
60static CommandTableElement *CommandTableEnd =
61 CommandTable+sizeof(CommandTable)/sizeof(CommandTable[0]);
62
63
64//===----------------------------------------------------------------------===//
65// handleUserInput - Enter the input loop for the interpreter. This function
66// returns when the user quits the interpreter.
67//
68void Interpreter::handleUserInput() {
69 bool UserQuit = false;
70
71 // Sort the table...
72 sort(CommandTable, CommandTableEnd);
73
74 // Print the instruction that we are stopped at...
75 printCurrentInstruction();
76
77 do {
78 string Command;
79 cout << "lli> " << flush;
80 cin >> Command;
81
82 CommandTableElement *E = find(CommandTable, CommandTableEnd, Command);
83
84 if (E == CommandTableEnd) {
85 cout << "Error: '" << Command << "' not recognized!\n";
86 continue;
87 }
88
89 switch (E->CID) {
90 case Quit: UserQuit = true; break;
Chris Lattner2e42d3a2001-10-15 05:51:48 +000091 case Load:
92 cin >> Command;
93 loadModule(Command);
94 break;
95 case Flush: flushModule(); break;
Chris Lattner92101ac2001-08-23 17:05:04 +000096 case Print:
97 cin >> Command;
Chris Lattner2e42d3a2001-10-15 05:51:48 +000098 print(Command);
Chris Lattner92101ac2001-08-23 17:05:04 +000099 break;
Chris Lattner86660982001-08-27 05:16:50 +0000100 case Info:
101 cin >> Command;
102 infoValue(Command);
103 break;
104
Chris Lattner92101ac2001-08-23 17:05:04 +0000105 case List: list(); break;
106 case StackTrace: printStackTrace(); break;
107 case Up:
Chris Lattner461f02f2001-11-07 05:31:27 +0000108 if (CurFrame > 0) { --CurFrame; printStackFrame(); }
Chris Lattner92101ac2001-08-23 17:05:04 +0000109 else cout << "Error: Already at root of stack!\n";
110 break;
111 case Down:
Chris Lattner461f02f2001-11-07 05:31:27 +0000112 if ((unsigned)CurFrame < ECStack.size()-1) {
113 ++CurFrame;
114 printStackFrame();
115 } else
116 cout << "Error: Already at bottom of stack!\n";
Chris Lattner92101ac2001-08-23 17:05:04 +0000117 break;
118 case Next: nextInstruction(); break;
119 case Step: stepInstruction(); break;
120 case Run: run(); break;
121 case Finish: finish(); break;
122 case Call:
123 cin >> Command;
124 callMethod(Command); // Enter the specified method
125 finish(); // Run until it's complete
126 break;
127
Chris Lattner43e3f7c2001-10-27 08:43:52 +0000128 case TraceOpt:
129 Trace = !Trace;
130 cout << "Tracing " << (Trace ? "enabled\n" : "disabled\n");
131 break;
132
133 case ProfileOpt:
134 Profile = !Profile;
135 cout << "Profiling " << (Trace ? "enabled\n" : "disabled\n");
136 break;
137
Chris Lattner92101ac2001-08-23 17:05:04 +0000138 default:
139 cout << "Command '" << Command << "' unimplemented!\n";
140 break;
141 }
142
143 } while (!UserQuit);
144}
145
Chris Lattner2e42d3a2001-10-15 05:51:48 +0000146//===----------------------------------------------------------------------===//
147// loadModule - Load a new module to execute...
148//
149void Interpreter::loadModule(const string &Filename) {
Chris Lattnere43db882001-10-27 04:15:57 +0000150 string ErrorMsg;
Chris Lattner2e42d3a2001-10-15 05:51:48 +0000151 if (CurMod && !flushModule()) return; // Kill current execution
152
Chris Lattnere43db882001-10-27 04:15:57 +0000153 CurMod = ParseBytecodeFile(Filename, &ErrorMsg);
Chris Lattner2e42d3a2001-10-15 05:51:48 +0000154 if (CurMod == 0) {
Chris Lattnere43db882001-10-27 04:15:57 +0000155 cout << "Error parsing '" << Filename << "': No module loaded: "
156 << ErrorMsg << "\n";
Chris Lattner2e42d3a2001-10-15 05:51:48 +0000157 return;
158 }
Chris Lattner5af0c482001-11-07 04:23:00 +0000159 CW.setModule(CurMod); // Update Writer
Chris Lattner2e42d3a2001-10-15 05:51:48 +0000160
Chris Lattnera5637fc2001-10-30 16:40:37 +0000161 string RuntimeLib = getCurrentExecutablePath();
162 if (!RuntimeLib.empty()) RuntimeLib += "/";
163 RuntimeLib += "RuntimeLib.bc";
164
Chris Lattnere43db882001-10-27 04:15:57 +0000165 if (Module *SupportLib = ParseBytecodeFile(RuntimeLib, &ErrorMsg)) {
166 if (LinkModules(CurMod, SupportLib, &ErrorMsg))
167 cerr << "Error Linking runtime library into current module: "
168 << ErrorMsg << endl;
169 } else {
170 cerr << "Error loading runtime library '"+RuntimeLib+"': "
171 << ErrorMsg << "\n";
172 }
Chris Lattner2e42d3a2001-10-15 05:51:48 +0000173}
174
175
176//===----------------------------------------------------------------------===//
177// flushModule - Return true if the current program has been unloaded.
178//
179bool Interpreter::flushModule() {
180 if (CurMod == 0) {
181 cout << "Error flushing: No module loaded!\n";
182 return false;
183 }
184
185 if (!ECStack.empty()) {
186 // TODO: if use is not sure, return false
187 cout << "Killing current execution!\n";
188 ECStack.clear();
189 CurFrame = -1;
190 }
191
Chris Lattner5af0c482001-11-07 04:23:00 +0000192 CW.setModule(0);
Chris Lattner2e42d3a2001-10-15 05:51:48 +0000193 delete CurMod;
194 CurMod = 0;
195 ExitCode = 0;
196 return true;
197}
Chris Lattner92101ac2001-08-23 17:05:04 +0000198
199//===----------------------------------------------------------------------===//
200// setBreakpoint - Enable a breakpoint at the specified location
201//
202void Interpreter::setBreakpoint(const string &Name) {
203 Value *PickedVal = ChooseOneOption(Name, LookupMatchingNames(Name));
204 // TODO: Set a breakpoint on PickedVal
205}
206
207//===----------------------------------------------------------------------===//
208// callMethod - Enter the specified method...
209//
210bool Interpreter::callMethod(const string &Name) {
211 vector<Value*> Options = LookupMatchingNames(Name);
212
213 for (unsigned i = 0; i < Options.size(); ++i) { // Remove nonmethod matches...
Chris Lattner1d87bcf2001-10-01 20:11:19 +0000214 if (!isa<Method>(Options[i])) {
Chris Lattner92101ac2001-08-23 17:05:04 +0000215 Options.erase(Options.begin()+i);
216 --i;
217 }
218 }
219
220 Value *PickedMeth = ChooseOneOption(Name, Options);
221 if (PickedMeth == 0)
222 return true;
223
Chris Lattner9636a912001-10-01 16:18:37 +0000224 Method *M = cast<Method>(PickedMeth);
Chris Lattner365a76e2001-09-10 04:49:44 +0000225
226 vector<GenericValue> Args;
227 // TODO, get args from user...
228
229 callMethod(M, Args); // Start executing it...
Chris Lattner92101ac2001-08-23 17:05:04 +0000230
231 // Reset the current frame location to the top of stack
232 CurFrame = ECStack.size()-1;
233
234 return false;
235}
Chris Lattnerf8f2afb2001-10-18 21:55:32 +0000236
Chris Lattner204eec32001-10-27 05:54:31 +0000237static void *CreateArgv(const vector<string> &InputArgv) {
238 // Pointers are 64 bits...
239 uint64_t *Result = new uint64_t[InputArgv.size()+1];
240
241 for (unsigned i = 0; i < InputArgv.size(); ++i) {
242 unsigned Size = InputArgv[i].size()+1;
243 char *Dest = new char[Size];
244 copy(InputArgv[i].begin(), InputArgv[i].end(), Dest);
245 Dest[Size-1] = 0;
246 Result[i] = (uint64_t)Dest;
247 }
248
249 Result[InputArgv.size()] = 0;
250 return Result;
251}
252
Chris Lattnerf8f2afb2001-10-18 21:55:32 +0000253
254// callMainMethod - This is a nasty gross hack that will dissapear when
255// callMethod can parse command line options and stuff for us.
256//
257bool Interpreter::callMainMethod(const string &Name,
Chris Lattner204eec32001-10-27 05:54:31 +0000258 const vector<string> &InputArgv) {
Chris Lattnerf8f2afb2001-10-18 21:55:32 +0000259 vector<Value*> Options = LookupMatchingNames(Name);
260
261 for (unsigned i = 0; i < Options.size(); ++i) { // Remove nonmethod matches...
262 if (!isa<Method>(Options[i])) {
263 Options.erase(Options.begin()+i);
264 --i;
265 }
266 }
267
268 Value *PickedMeth = ChooseOneOption(Name, Options);
269 if (PickedMeth == 0)
270 return true;
271
272 Method *M = cast<Method>(PickedMeth);
273 const MethodType *MT = M->getMethodType();
274
275 vector<GenericValue> Args;
276 switch (MT->getParamTypes().size()) {
277 default:
278 cout << "Unknown number of arguments to synthesize for '" << Name << "'!\n";
279 return true;
280 case 2: {
281 PointerType *SPP = PointerType::get(PointerType::get(Type::SByteTy));
282 if (MT->getParamTypes()[1] != SPP) {
Chris Lattner461f02f2001-11-07 05:31:27 +0000283 CW << "Second argument of '" << Name << "' should have type: '"
284 << SPP << "'!\n";
Chris Lattnerf8f2afb2001-10-18 21:55:32 +0000285 return true;
286 }
Chris Lattner204eec32001-10-27 05:54:31 +0000287
Chris Lattnerc2593162001-10-27 08:28:11 +0000288 GenericValue GV; GV.PointerVal = (uint64_t)CreateArgv(InputArgv);
Chris Lattnerf8f2afb2001-10-18 21:55:32 +0000289 Args.push_back(GV);
290 }
291 // fallthrough
292 case 1:
293 if (!MT->getParamTypes()[0]->isIntegral()) {
294 cout << "First argument of '" << Name << "' should be integral!\n";
295 return true;
296 } else {
Chris Lattner204eec32001-10-27 05:54:31 +0000297 GenericValue GV; GV.UIntVal = InputArgv.size();
Chris Lattnerf8f2afb2001-10-18 21:55:32 +0000298 Args.insert(Args.begin(), GV);
299 }
300 // fallthrough
301 case 0:
302 break;
303 }
304
305 callMethod(M, Args); // Start executing it...
306
307 // Reset the current frame location to the top of stack
308 CurFrame = ECStack.size()-1;
309
310 return false;
311}
Chris Lattner461f02f2001-11-07 05:31:27 +0000312
313
314
315void Interpreter::list() {
316 if (ECStack.empty())
317 cout << "Error: No program executing!\n";
318 else
319 CW << ECStack[CurFrame].CurMethod; // Just print the method out...
320}
321
322void Interpreter::printStackTrace() {
323 if (ECStack.empty()) cout << "No program executing!\n";
324
325 for (unsigned i = 0; i < ECStack.size(); ++i) {
326 printStackFrame((int)i);
327 }
328}