00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 # include "incls/_precompiled.incl"
00025 # include "incls/_evaluator.cpp.incl"
00026
00027
00028
00029
00030 extern "C" void single_step_handler() {
00031 ResourceMark rm;
00032 evaluator::single_step(DeltaProcess::active()->last_Delta_fp());
00033 }
00034
00035 int* saved_frame;
00036
00037 bool patch_last_delta_frame(int* fr, int* dist) {
00038
00039 frame v(NULL, fr, NULL);
00040
00041 methodOop method = methodOopDesc::methodOop_from_hcode(v.hp());
00042
00043
00044
00045 int bci = method->next_bci_from(v.hp());
00046
00047
00048
00049 InterpretedIC* ic = method->ic_at(bci);
00050 if (ic && ic->is_empty()) return false;
00051
00052 *dist = method->next_bci(bci) - bci;
00053 v.set_hp(v.hp() + *dist);
00054 return true;
00055 }
00056
00057 void restore_hp(int* fr, int dist) {
00058 frame v(NULL, fr, NULL);
00059 v.set_hp(v.hp() - dist);
00060 }
00061
00062 static bool is_aborting = false;
00063
00064 void evaluator::single_step(int* fr) {
00065 int dist;
00066 if (!patch_last_delta_frame(fr, &dist)) return;
00067
00068 deltaVFrame* df = DeltaProcess::active()->last_delta_vframe();
00069 assert(df, "delta frame must be present");
00070
00071 {
00072 FlagSetting(ActivationShowCode, true);
00073 df->print_activation(1);
00074 }
00075 saved_frame = fr;
00076 read_eval_loop();
00077
00078 restore_hp(fr, dist);
00079
00080 if (is_aborting) {
00081 is_aborting = false;
00082 ErrorHandler::abort_current_process();
00083 }
00084 }
00085
00086 bool evaluator::get_line(char* line) {
00087 int end = 0;
00088 int c;
00089 while (((c = getchar()) != EOF) && (c != '\n'))
00090 line[end++] = c;
00091 while ((end > 0) && ((line[end-1] == ' ') || (line[end-1] == '\t')))
00092 end--;
00093 line[end] = '\0';
00094 return c != EOF;
00095 }
00096
00097
00098 class TokenStream : public StackObj {
00099 private:
00100 GrowableArray<char*>* tokens;
00101 int pos;
00102 void tokenize(char* str);
00103 bool match(char* str) { return strcmp(current(), str) == 0; }
00104 public:
00105 TokenStream(char* line) {
00106 tokens = new GrowableArray<char*>(10);
00107 tokenize(line);
00108 pos = 0;
00109 }
00110 char* current() { return tokens->at(pos); }
00111 void advance() { pos++; }
00112 bool eos() { return pos >= tokens->length(); }
00113
00114
00115 bool is_hat() { return match("^"); }
00116 bool is_step() { return match("s") || match("step"); }
00117 bool is_next() { return match("n") || match("next"); }
00118 bool is_end() { return match("e") || match("end"); }
00119 bool is_cont() { return match("c") || match("cont"); }
00120 bool is_stack() { return match("stack"); }
00121 bool is_abort() { return match("abort"); }
00122 bool is_genesis() { return match("genesis"); }
00123 bool is_top() { return match("top"); }
00124 bool is_show() { return match("show"); }
00125 bool is_break() { return match("break"); }
00126 bool is_events() { return match("events"); }
00127 bool is_status() { return match("status"); }
00128 bool is_help() { return match("?") || match("help"); }
00129 bool is_quit() { return match("q") || match("quit"); }
00130 bool is_plus() { return match("+"); }
00131 bool is_minus() { return match("-"); }
00132
00133 bool is_smi(oop* addr);
00134 bool is_table_entry(oop* addr);
00135 bool is_object_search(oop* addr);
00136 bool is_name(oop* addr);
00137 bool is_symbol(oop* addr);
00138
00139 bool is_unary();
00140 bool is_binary();
00141 bool is_keyword();
00142 };
00143
00144
00145 static char* seps = " \t\n";
00146
00147 void TokenStream::tokenize(char* str) {
00148 char* token = strtok(str, seps);
00149 while( token != NULL ) {
00150 tokens->push(token);
00151 token = strtok(NULL, seps);
00152 }
00153 }
00154
00155
00156 bool TokenStream::is_smi(oop* addr) {
00157 int value;
00158 unsigned int length;
00159 if (sscanf(current(), "%d%n", &value, &length) == 1 && strlen(current()) == length) {
00160 *addr = as_smiOop(value);
00161 return true;
00162 }
00163 return false;
00164 }
00165
00166
00167 bool TokenStream::is_table_entry(oop* addr) {
00168 int value;
00169 unsigned int length;
00170 if (sscanf(current(), "!%d%n", &value, &length) == 1 && strlen(current()) == length) {
00171 if(!objectIDTable::is_index_ok(value)) {
00172 std->print_cr("Could not find index %d in object table.", value);
00173 return true;
00174 }
00175 *addr = objectIDTable::at(value);
00176 return true;
00177 }
00178 return false;
00179 }
00180
00181
00182 bool TokenStream::is_object_search(oop* addr) {
00183 int address;
00184 oop obj;
00185 unsigned int length;
00186 if (sscanf(current(), "0x%x%n", &address, &length) == 1 && strlen(current()) == length) {
00187 if (obj = oop(Universe::object_start((oop*) address))) {
00188 *addr = obj;
00189 return true;
00190 }
00191 }
00192 return false;
00193 }
00194
00195 bool TokenStream::is_name(oop* addr) {
00196 char name[200];
00197 oop obj;
00198 unsigned int length;
00199 if (sscanf(current(), "%[a-zA-Z]%n", name, &length) == 1 && strlen(current()) == length) {
00200 if (obj = Universe::find_global(name)) { *addr = obj ; return true; }
00201 }
00202 return false;
00203 }
00204
00205 bool TokenStream::is_symbol(oop* addr) {
00206 char name[200];
00207 unsigned int length;
00208 if (sscanf(current(), "#%[a-zA-Z0-9_]%n", name, &length) == 1 && strlen(current()) == length) {
00209 *addr = oopFactory::new_symbol(name);
00210 return true;
00211 }
00212 return false;
00213 }
00214
00215 bool TokenStream::is_unary() {
00216 char name[40];
00217 unsigned int length;
00218 return sscanf(current(), "%[a-zA-Z]%n", name, &length) == 1 && strlen(current()) == length;
00219 }
00220
00221 bool TokenStream::is_binary() { return !is_unary() && !is_keyword();}
00222
00223 bool TokenStream::is_keyword() {
00224 char name[40];
00225 unsigned int length;
00226 return sscanf(current(), "%[a-zA-Z]:%n", name, &length) == 1 && strlen(current()) == length;
00227 }
00228
00229 bool evaluator::get_oop(TokenStream* st, oop* addr) {
00230 if (st->is_smi(addr)) { st->advance(); return true; }
00231 if (st->is_table_entry(addr)) { st->advance(); return true; }
00232 if (st->is_object_search(addr)) { st->advance(); return true; }
00233 if (st->is_name(addr)) { st->advance(); return true; }
00234 if (st->is_symbol(addr)) { st->advance(); return true; }
00235 std->print_cr("Error: could not oop'ify [%s]", st->current());
00236 return false;
00237 }
00238
00239
00240 bool validate_lookup(oop receiver, symbolOop selector) {
00241 LookupKey key(receiver->klass(), selector);
00242 if (lookupCache::lookup(&key).is_empty()) {
00243 std->print_cr("Lookup error");
00244 key.print_on(std);
00245 std->cr();
00246 return false;
00247 }
00248 return true;
00249 }
00250
00251 void evaluator::eval_message(TokenStream* st) {
00252 oop receiver;
00253 oop result = nilObj;
00254 symbolOop selector;
00255
00256 if (st->eos()) return;
00257 if (!get_oop(st, &receiver)) return;
00258 if (st->eos()) {
00259 receiver->print();
00260 } else if (st->is_unary()) {
00261 symbolOop selector = oopFactory::new_symbol(st->current());
00262 if (!validate_lookup(receiver, selector)) return;
00263 result = Delta::call(receiver, selector);
00264 } else if (st->is_binary()) {
00265 selector = oopFactory::new_symbol(st->current());
00266 if (!validate_lookup(receiver, selector)) return;
00267 oop argument;
00268 st->advance();
00269 if (!get_oop(st, &argument)) return;
00270 result = Delta::call(receiver, selector, argument);
00271 } else if (st->is_keyword()) {
00272 char name[100];
00273 oop arguments[10];
00274 int nofArgs = 0;
00275 name[0] = '\0';
00276 while (!st->eos()) {
00277 strcat(name, st->current());
00278 st->advance();
00279 oop arg;
00280 if (!get_oop(st, &arg)) return;
00281 arguments[nofArgs++] = arg;
00282 }
00283 selector = oopFactory::new_symbol(name);
00284 if (!validate_lookup(receiver, selector)) return;
00285 static DeltaCallCache cache;
00286 result = Delta::call_generic(&cache, receiver, selector, nofArgs, arguments);
00287 }
00288 result->print_value();
00289 std->cr();
00290 }
00291
00292 void evaluator::top_command(TokenStream* st) {
00293 int number_of_frames_to_show = 10;
00294 st->advance();
00295 if (!st->eos()) {
00296 oop value;
00297 if (st->is_smi(&value)) {
00298 number_of_frames_to_show = smiOop(value)->value();
00299 }
00300 st->advance();
00301 if (!st->eos()) {
00302 std->print_cr("warning: garbage at end");
00303 }
00304 }
00305 DeltaProcess::active()->trace_top(1, number_of_frames_to_show);
00306 };
00307
00308 void evaluator::change_debug_flag(TokenStream* st, bool value) {
00309 st->advance();
00310 if (!st->eos()) {
00311 st->current();
00312 bool r = value;
00313 if (!debugFlags::boolAtPut(st->current(), &r)) {
00314 std->print_cr("boolean flag %s not found", st->current());
00315 }
00316 st->advance();
00317 if (!st->eos()) {
00318 std->print_cr("warning: garbage at end");
00319 }
00320 } else {
00321 std->print_cr("boolean flag expected");
00322 }
00323 }
00324
00325 void evaluator::show_command(TokenStream* st) {
00326 int start_frame = 1;
00327 int number_of_frames_to_show = 1;
00328
00329 st->advance();
00330 if (!st->eos()) {
00331 oop value;
00332 if (st->is_smi(&value)) {
00333 start_frame = smiOop(value)->value();
00334 }
00335 st->advance();
00336 if (!st->eos()) {
00337 if (st->is_smi(&value)) {
00338 number_of_frames_to_show = smiOop(value)->value();
00339 }
00340 st->advance();
00341 if (!st->eos()) {
00342 std->print_cr("warning: garbage at end");
00343 }
00344 }
00345 }
00346 DeltaProcess::active()->trace_top(start_frame, number_of_frames_to_show);
00347 };
00348
00349 bool evaluator::process_line() {
00350 char line[200];
00351 if (!get_line(line)) return false;
00352
00353 TokenStream st(line);
00354 if (st.eos()) return true;
00355
00356 if (st.is_hat()) {
00357 st.advance();
00358 dispatchTable::reset();
00359 eval_message(&st);
00360 return true;
00361 } else {
00362 if (st.is_help()) { print_help(); return true; }
00363 if (st.is_step()) { dispatchTable::intercept_for_step(); return false; }
00364 if (st.is_next()) { dispatchTable::intercept_for_next(saved_frame); return false; }
00365 if (st.is_end()) { dispatchTable::intercept_for_return(saved_frame); return false; }
00366 if (st.is_cont()) { dispatchTable::reset(); return false; }
00367 if (st.is_stack()) { DeltaProcess::active()->trace_stack(); return true; }
00368 if (st.is_quit()) { os::fatalExit(0); return true; }
00369 if (st.is_break()) { fatal("evaluator break"); return true; }
00370 if (st.is_events()) { eventLog->print(); return true; }
00371 if (st.is_top()) { top_command(&st); return true; }
00372 if (st.is_show()) { show_command(&st); return true; }
00373 if (st.is_plus()) { change_debug_flag(&st, true); return true; }
00374 if (st.is_minus()) { change_debug_flag(&st, false); return true; }
00375 if (st.is_status()) { print_status(); return true; }
00376 if (st.is_abort()) {
00377 if (DeltaProcess::active()->is_scheduler()) {
00378 std->print_cr("You cannot abort in the scheduler");
00379 std->print_cr("Try another command");
00380 } else {
00381 dispatchTable::reset();
00382 is_aborting = true;
00383 return false;
00384 }
00385 }
00386 if (st.is_genesis()) {
00387 dispatchTable::reset();
00388 VM_Genesis op;
00389 VMProcess::execute(&op);
00390 return false;
00391 }
00392 oop receiver;
00393 if (get_oop(&st, &receiver)) {
00394 st.advance();
00395 if (!st.eos()) {
00396 std->print_cr("warning: garbage at end");
00397 }
00398 receiver->print();
00399 std->cr();
00400 return true;
00401 }
00402 }
00403 print_mini_help();
00404 return true;
00405 }
00406
00407
00408 void evaluator::read_eval_loop() {
00409 do {
00410 std->print("Eval> ");
00411 } while (process_line());
00412 }
00413
00414
00415 void evaluator::print_mini_help() {
00416 std->print_cr("Use '?' for help ('c' to continue)");
00417 }
00418
00419 class ProcessStatusClosure : public ProcessClosure {
00420 private:
00421 int index;
00422 public:
00423 ProcessStatusClosure() { index = 1; }
00424
00425 void do_process(DeltaProcess* p) {
00426 std->print(" %d:%s ", index++, DeltaProcess::active() == p ? "*" : " ");
00427 p->print();
00428 }
00429 };
00430
00431 void evaluator::print_status() {
00432 std->print_cr("Processes:");
00433 ProcessStatusClosure iter;
00434 Processes::process_iterate(&iter);
00435 }
00436
00437 void evaluator::print_help() {
00438 std->cr();
00439 std->print_cr("<command> ::= 'q' | 'quit' -> quits the system");
00440 std->print_cr(" | 's' | 'step' -> single step byte code");
00441 std->print_cr(" | 'n' | 'next' -> single step statement");
00442 std->print_cr(" | 'e' | 'end' -> single step to end of method");
00443 std->print_cr(" | 'c' | 'cont' -> continue execution");
00444 std->print_cr(" | 'abort' -> aborts the current process");
00445 std->print_cr(" | 'genesis' -> aborts all processes and restarts the scheduler");
00446 std->print_cr(" | 'break' -> provokes fatal() to get into C++ debugger");
00447 std->print_cr(" | 'event' -> prints the event log");
00448 std->print_cr(" | 'stack' -> prints the stack of current process");
00449 std->print_cr(" | 'status' -> prints the status all processes");
00450 std->print_cr(" | 'top' <n> -> prints the top of current process");
00451 std->print_cr(" | 'show' <s> <n> -> prints some activation");
00452 std->print_cr(" | '?' | 'help' -> prints this help\n");
00453 std->print_cr(" | '^' <expr> -> evaluates the expression");
00454 std->print_cr(" | '-' name -> turns off debug flag");
00455 std->print_cr(" | '+' name -> turns on debug flag");
00456 std->print_cr(" | <object> -> prints this object\n");
00457 std->cr();
00458 std->print_cr("<expr> ::= <unary> | <binary> | <keyword>\n");
00459 std->print_cr("<object> ::= <number> -> smi(number)");
00460 std->print_cr(" | !<number> -> objectTable[number]");
00461 std->print_cr(" | 0x<hex_number> -> object_start(number)");
00462 std->print_cr(" | name -> Smalltalk at: #name");
00463 std->print_cr(" | #name -> new_symbol(name)");
00464 std->cr();
00465 }