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 }