evaluator.cpp

Go to the documentation of this file.
00001 /* Copyright 1994, 1995 LongView Technologies L.L.C. $Revision: 1.45 $ */
00002 /* Copyright (c) 2006, Sun Microsystems, Inc.
00003 All rights reserved.
00004 
00005 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the 
00006 following conditions are met:
00007 
00008     * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
00009     * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following 
00010           disclaimer in the documentation and/or other materials provided with the distribution.
00011     * Neither the name of Sun Microsystems nor the names of its contributors may be used to endorse or promote products derived 
00012           from this software without specific prior written permission.
00013 
00014 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT 
00015 NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 
00016 THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
00017 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
00018 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
00019 OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
00020 
00021 
00022 */
00023 
00024 # include "incls/_precompiled.incl"
00025 # include "incls/_evaluator.cpp.incl"
00026 
00027 // The single_step_handler is called from single_step_stub
00028 // when a single step has taken place
00029 // return the distance between the current and the next_bci
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   // change the current to next bci;
00039   frame v(NULL, fr, NULL);
00040 
00041   methodOop method = methodOopDesc::methodOop_from_hcode(v.hp());
00042 
00043   // The interpreter is in the middle of executing a byte code 
00044   // and the hp pointer points to the current bci and NOT the next bci.
00045   int bci = method->next_bci_from(v.hp());
00046 
00047   // in case of single step we ignore the case with
00048   // an empty inline cache since the send is reexecuted.
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   { // Always show code at single step
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   // testers
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 }

Generated on Mon Oct 9 13:37:09 2006 for Strongtalk VM by  doxygen 1.4.7