prim.cpp

Go to the documentation of this file.
00001 /* Copyright 1994, 1995 LongView Technologies L.L.C. $Revision: 1.47 $ */
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/_prim.cpp.incl"
00026 
00027 // The primitive_table is generated from prims.src.
00028 // The output has the following format:
00029 //   static int size_of_primitive_table
00030 //   static primitive_desc* primitive_table;
00031 #include "prims.inc"
00032 
00033 // the typedefs below are necessary to ensure that args are passed correctly when calling a primitive
00034 // through a function pointer
00035 // NB: there's no general n-argument primitive because some calling conventions can't handle vararg functions
00036 typedef  oop (*prim_fntype0)();
00037 typedef  oop (*prim_fntype1)(oop);
00038 typedef  oop (*prim_fntype2)(oop, oop);
00039 typedef  oop (*prim_fntype3)(oop, oop, oop);
00040 typedef  oop (*prim_fntype4)(oop, oop, oop, oop);
00041 typedef  oop (*prim_fntype5)(oop, oop, oop, oop, oop);
00042 typedef  oop (*prim_fntype6)(oop, oop, oop, oop, oop, oop);
00043 typedef  oop (*prim_fntype7)(oop, oop, oop, oop, oop, oop, oop);
00044 typedef  oop (*prim_fntype8)(oop, oop, oop, oop, oop, oop, oop, oop);
00045 typedef  oop (*prim_fntype9)(oop, oop, oop, oop, oop, oop, oop, oop, oop);
00046 
00047 
00048 oop primitive_desc::eval(oop* a) {
00049   const bool reverseArgs = true;        // change this when changing primitive calling convention
00050   oop res;
00051   if (reverseArgs) {
00052     switch (number_of_parameters()) {
00053       case  0: res = ((prim_fntype0)_fn)(); break;
00054       case  1: res = ((prim_fntype1)_fn)(a[0]); break;
00055       case  2: res = ((prim_fntype2)_fn)(a[1], a[0]); break;
00056       case  3: res = ((prim_fntype3)_fn)(a[2], a[1], a[0]); break;
00057       case  4: res = ((prim_fntype4)_fn)(a[3], a[2], a[1], a[0]); break;
00058       case  5: res = ((prim_fntype5)_fn)(a[4], a[3], a[2], a[1], a[0]); break;
00059       case  6: res = ((prim_fntype6)_fn)(a[5], a[4], a[3], a[2], a[1], a[0]); break;
00060       case  7: res = ((prim_fntype7)_fn)(a[6], a[5], a[4], a[3], a[2], a[1], a[0]); break;
00061       case  8: res = ((prim_fntype8)_fn)(a[7], a[6], a[5], a[4], a[3], a[2], a[1], a[0]); break;
00062       case  9: res = ((prim_fntype9)_fn)(a[8], a[7], a[6], a[5], a[4], a[3], a[2], a[1], a[0]); break;
00063       default: ShouldNotReachHere();
00064     }
00065   } else {
00066     switch (number_of_parameters()) {
00067       case  0: res = ((prim_fntype0)_fn)(); break;
00068       case  1: res = ((prim_fntype1)_fn)(a[0]); break;
00069       case  2: res = ((prim_fntype2)_fn)(a[0], a[1]); break;
00070       case  3: res = ((prim_fntype3)_fn)(a[0], a[1], a[2]); break;
00071       case  4: res = ((prim_fntype4)_fn)(a[0], a[1], a[2], a[3]); break;
00072       case  5: res = ((prim_fntype5)_fn)(a[0], a[1], a[2], a[3], a[4]); break;
00073       case  6: res = ((prim_fntype6)_fn)(a[0], a[1], a[2], a[3], a[4], a[5]); break;
00074       case  7: res = ((prim_fntype7)_fn)(a[0], a[1], a[2], a[3], a[4], a[5], a[6]); break;
00075       case  8: res = ((prim_fntype8)_fn)(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7]); break;
00076       case  9: res = ((prim_fntype9)_fn)(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]); break;
00077       default: ShouldNotReachHere();
00078     }
00079   }
00080   return res;
00081 }
00082 
00083 
00084 void primitives::print_table() {
00085   std->print_cr("Primitive table:");
00086   for (int index = 0; index < size_of_primitive_table; index++) {
00087     primitive_desc* e = primitive_table[index];
00088     std->print("%3d ",index);
00089     e->print();
00090   }
00091   std->print_cr(" - format: <index> <name> <number_of_parameters> <flags> [category]");
00092   std->print_cr("    flags:  R = has receiver,           F = has failure block,");
00093   std->print_cr("            S = can scavenge,           N = can perform NLR,");
00094   std->print_cr("            C = can be constant folded, D = can invoke Delta code");
00095   std->print_cr("            I = internal,               P = needs Delta fp code");
00096   std->print_cr("            W = can walk stack (computed)");
00097 }
00098 
00099 
00100 bool primitive_desc::can_walk_stack() const {
00101   return can_scavenge() || can_invoke_delta() || can_perform_NLR();
00102 }
00103 
00104 
00105 symbolOop primitive_desc::selector() const {
00106   return oopFactory::new_symbol(name());
00107 }
00108 
00109 
00110 void primitive_desc::print() {
00111   std->print("%48s %d %s%s%s%s%s%s%s%s%s",
00112              name(), 
00113              number_of_parameters(),
00114              has_receiver()           ? "R" : "_",
00115              can_fail()               ? "F" : "_",
00116              can_scavenge()           ? "S" : "_",
00117              can_walk_stack()         ? "W" : "_",
00118              can_perform_NLR()        ? "N" : "_",
00119              can_be_constant_folded() ? "C" : "_",
00120              can_invoke_delta()       ? "D" : "_",
00121              is_internal()            ? "I" : "_",
00122              needs_delta_fp_code()    ? "P" : "_");
00123   switch(group()) {
00124     case IntComparisonPrimitive:   std->print(", smi compare");           break;
00125     case IntArithmeticPrimitive:   std->print(", smi arith");             break;
00126     case FloatComparisonPrimitive: std->print(", double compare");        break;
00127     case FloatArithmeticPrimitive: std->print(", double arith");          break;
00128     case ByteArrayPrimitive:       std->print(", byte array op.");        break;
00129     case DoubleByteArrayPrimitive: std->print(", double-byte array op."); break;
00130     case ObjArrayPrimitive:        std->print(", array op.");             break;
00131     case BlockPrimitive:           std->print(", block/context");         break;
00132     case NormalPrimitive:                                                 break;
00133     default: fatal("Unknown primitive group");
00134   }
00135   std->cr();
00136 }
00137 
00138 
00139 char* primitive_desc::parameter_type(int index) const {
00140   assert((0 <= index) && (index < number_of_parameters()), "illegal parameter index");
00141   return _types[1 + index];
00142 }
00143 
00144 
00145 char* primitive_desc::return_type() const { 
00146   return _types[0];
00147 }
00148 
00149 
00150 Expr* primitive_desc::convertToKlass(char* type, PReg* p, Node* n) const {
00151   if (0 == strcmp(type, "SmallInteger")) return new KlassExpr(Universe::smiKlassObj(), p, n);
00152   if (0 == strcmp(type, "Double"))       return new KlassExpr(Universe::doubleKlassObj(), p, n);
00153   if (0 == strcmp(type, "Float"))        return new KlassExpr(Universe::doubleKlassObj(), p, n);
00154   if (0 == strcmp(type, "Symbol"))       return new KlassExpr(Universe::symbolKlassObj(), p, n);
00155   if (0 == strcmp(type, "Boolean")) {
00156     // NB: set expression node to NULL, not n -- MergeExpr cannot be split
00157     Expr* t = new ConstantExpr(Universe::trueObj(), p, NULL);
00158     Expr* f = new ConstantExpr(Universe::falseObj(), p, NULL);
00159     return new MergeExpr(t, f, p, NULL);
00160   }
00161 
00162   // should extend:
00163   // - looking up klassName in global class dictionary would cover many other cases
00164   // - for these, need to agree what prim info means: "exact match" or "any subclass of"
00165   // fix this later  -Urs 11/95
00166   return NULL;
00167 }
00168 
00169 
00170 Expr* primitive_desc::parameter_klass(int index, PReg* p, Node* n) const {
00171   return convertToKlass(parameter_type(index), p, n);
00172 }
00173 
00174 
00175 Expr* primitive_desc::return_klass(PReg* p, Node* n) const {
00176   return convertToKlass(return_type(), p, n);
00177 }
00178 
00179 
00180 void primitive_desc::error(char* msg) {
00181   print();
00182   ::error(msg);
00183 }
00184 
00185 void primitive_desc::verify() {
00186   bool ok = true;
00187   if (can_invoke_delta()) {
00188     if (!can_scavenge()) error("canInvokeDelta implies canScavenge");
00189     if (!can_walk_stack()) error("canInvokeDelta implies can_walk_stack");
00190     if (can_be_constant_folded()) error("canInvokeDelta implies !canbeConstantFolded");
00191     if (!can_perform_NLR()) error("canInvokeDelta implies canPerformNLR");
00192   }
00193   if (can_be_constant_folded()) {
00194     if (can_perform_NLR()) error("canbeConstantFolded implies !canPerformNLR");
00195   }
00196   if (group() == BlockPrimitive) {
00197     if (!can_walk_stack()) error("blocks must have can_walk_stack");
00198   }
00199 }
00200 
00201 int primitive_desc::compare(char* str, int len) {
00202   int src_len = strlen(name());
00203   int sign = strncmp(name(), str, min(src_len, len));
00204   if (sign != 0 || src_len == len) return sign;
00205   return src_len < len ? -1 : 1;
00206 }
00207 
00208 primitive_desc* primitives::lookup(char* s, int len) {
00209   int first = 0;
00210   int last  = size_of_primitive_table;
00211 
00212   primitive_desc* element;
00213   do {
00214     int middle = first + (last - first)/2;
00215     element    = primitive_table[middle];
00216     int sign   = element->compare(s, len);
00217          if (sign == -1) first = middle + 1;
00218     else if (sign ==  1) last  = middle - 1;
00219     else return element;
00220   } while (first < last);
00221 
00222   assert(first == last, "check for one element");
00223   element = primitive_table[first];
00224 
00225   return element->compare(s, len) == 0 ? element : NULL;
00226 }
00227 
00228 
00229 primitive_desc* primitives::lookup(fntype fn) {
00230   for (int index = 0; index < size_of_primitive_table; index++) {
00231     primitive_desc* e = primitive_table[index];
00232     if (e->fn() == fn) return e;
00233   }
00234   return NULL;
00235 }
00236 
00237 
00238 void primitives::lookup_and_patch() {
00239   // get primitive call info
00240   frame f = DeltaProcess::active()->last_frame();
00241   CodeIterator it(f.hp());
00242   oop* selector_addr = it.aligned_oop(1);
00243 
00244   symbolOop sel = symbolOop(*selector_addr);
00245   assert(sel->is_symbol(), "symbol expected");
00246   // do lookup
00247   primitive_desc* pdesc = primitives::lookup(sel);
00248   if (pdesc != NULL && !pdesc->is_internal()) {
00249     // primitive found => patch bytecode & cache
00250     *f.hp() = u_char(Bytecodes::primitive_call_code_for(Bytecodes::Code(*f.hp())));
00251     *selector_addr = oop(pdesc->fn());
00252   } else {
00253     // advance hp so that it points to the next instruction
00254     it.advance();
00255     f.set_hp(it.hp());
00256 
00257     { ResourceMark rm;
00258       // primitive not found => process error
00259       std->print("primitive lookup error\n");
00260       sel->print_value(); std->print(" not found\n");
00261     }
00262     if (DeltaProcess::active()->is_scheduler()) {
00263       ResourceMark rm;
00264       DeltaProcess::active()->trace_stack();
00265       fatal("primitive lookup error in scheduler");
00266     } else {
00267       DeltaProcess::active()->suspend(primitive_lookup_error);
00268     }
00269     ShouldNotReachHere();
00270   }
00271 }
00272 
00273 
00274 void prim_init() { 
00275   primitives::initialize();
00276   primitive_desc* prev = NULL;
00277   for (int index = 0; index < size_of_primitive_table; index++) {
00278     primitive_desc* e = primitive_table[index];
00279     e->verify();
00280     if (prev) {
00281       guarantee(strcmp(prev->name(), e->name()) == -1, "primitive table not sorted");
00282     }
00283   }
00284   primitives::clear_counters();
00285 }
00286 
00287 // For debugging/profiling
00288 void primitives::clear_counters() {
00289   behaviorPrimitives::number_of_calls        = 0;
00290   byteArrayPrimitives::number_of_calls       = 0;
00291   callBackPrimitives::number_of_calls        = 0;
00292   doubleByteArrayPrimitives::number_of_calls = 0;
00293   debugPrimitives::number_of_calls           = 0;
00294   doubleOopPrimitives::number_of_calls       = 0;
00295   methodOopPrimitives::number_of_calls       = 0;
00296   mixinOopPrimitives::number_of_calls        = 0;
00297   objArrayPrimitives::number_of_calls        = 0;
00298   oopPrimitives::number_of_calls             = 0;
00299   processOopPrimitives::number_of_calls      = 0;
00300   proxyOopPrimitives::number_of_calls        = 0;
00301   smiOopPrimitives::number_of_calls          = 0;
00302   systemPrimitives::number_of_calls          = 0;
00303 }
00304 
00305 
00306 static void print_calls(char* name, int inc, int* total) {
00307   if (inc > 0) {
00308     lprintf(" %s:\t%6d\n", name, inc);
00309     *total = *total + inc;
00310   }
00311 }
00312 
00313 
00314 void primitives::print_counters() {
00315   int total = 0;
00316   lprintf("Primitive call counters:\n");
00317   print_calls("Behavoir",        behaviorPrimitives::number_of_calls,        &total);
00318   print_calls("byteArray",       byteArrayPrimitives::number_of_calls,       &total);
00319   print_calls("callBack",        callBackPrimitives::number_of_calls,        &total);
00320   print_calls("doubelByteArray", doubleByteArrayPrimitives::number_of_calls, &total);
00321   print_calls("debug",           debugPrimitives::number_of_calls,           &total);
00322   print_calls("double",          doubleOopPrimitives::number_of_calls,       &total);
00323   print_calls("method",          methodOopPrimitives::number_of_calls,       &total);
00324   print_calls("mixin",           mixinOopPrimitives::number_of_calls,        &total);
00325   print_calls("objArray",        objArrayPrimitives::number_of_calls,        &total);
00326   print_calls("oop",             oopPrimitives::number_of_calls,             &total);
00327   print_calls("process",         processOopPrimitives::number_of_calls,      &total);
00328   print_calls("proxy",           proxyOopPrimitives::number_of_calls,        &total);
00329   print_calls("smi",             smiOopPrimitives::number_of_calls,          &total);
00330   print_calls("system",          systemPrimitives::number_of_calls,          &total);
00331   lprintf("Total:\t%6d\n", total);
00332 
00333 }
00334 
00335 primitive_desc* InterpretedPrim_Cache::pdesc() const {
00336   CodeIterator c(hp());
00337   switch (c.code()) {
00338     case Bytecodes::prim_call:
00339     case Bytecodes::prim_call_failure:
00340     case Bytecodes::prim_call_self:
00341     case Bytecodes::prim_call_self_failure:
00342       return primitives::lookup((fntype) c.word_at(1));
00343 
00344     case Bytecodes::prim_call_lookup:
00345     case Bytecodes::prim_call_failure_lookup:
00346     case Bytecodes::prim_call_self_lookup:
00347     case Bytecodes::prim_call_self_failure_lookup:
00348       return primitives::lookup(symbolOop(c.oop_at(1)));
00349 
00350     default: fatal("Wrong bytecode");
00351   }
00352   return NULL;
00353 }
00354 
00355 bool InterpretedPrim_Cache::has_receiver() const {
00356   CodeIterator c(hp());
00357   switch (c.code()) {
00358     case Bytecodes::prim_call_self:
00359     case Bytecodes::prim_call_self_failure:
00360     case Bytecodes::prim_call_self_lookup:
00361     case Bytecodes::prim_call_self_failure_lookup:
00362       return true;
00363 
00364     case Bytecodes::prim_call:
00365     case Bytecodes::prim_call_failure:
00366     case Bytecodes::prim_call_lookup:
00367     case Bytecodes::prim_call_failure_lookup:
00368        return false;
00369 
00370     default: fatal("Wrong bytecode");
00371   }
00372   return false;
00373 }
00374 
00375 symbolOop InterpretedPrim_Cache::name() const {
00376   CodeIterator c(hp());
00377   switch (c.code()) {
00378     case Bytecodes::prim_call:
00379     case Bytecodes::prim_call_failure:
00380     case Bytecodes::prim_call_self:
00381     case Bytecodes::prim_call_self_failure:
00382       return primitives::lookup((fntype) c.word_at(1))->selector();
00383 
00384     case Bytecodes::prim_call_lookup:
00385     case Bytecodes::prim_call_failure_lookup:
00386     case Bytecodes::prim_call_self_lookup:
00387     case Bytecodes::prim_call_self_failure_lookup:
00388       return symbolOop(c.oop_at(1));
00389 
00390     default: fatal("Wrong bytecode");
00391   }
00392   return NULL;
00393 }
00394 
00395 int InterpretedPrim_Cache::number_of_parameters() const {
00396   int result = name()->number_of_arguments()
00397              + (has_receiver()     ? 1 : 0)
00398              - (has_failure_code() ? 1 : 0);
00399   assert(pdesc() == NULL || pdesc()->number_of_parameters() == result, "checking result");
00400   return result;
00401 }
00402 
00403 bool InterpretedPrim_Cache::has_failure_code() const {
00404   CodeIterator c(hp());
00405   switch (c.code()) {
00406     case Bytecodes::prim_call_failure:
00407     case Bytecodes::prim_call_failure_lookup:
00408     case Bytecodes::prim_call_self_failure:
00409     case Bytecodes::prim_call_self_failure_lookup:
00410       return true;
00411 
00412     case Bytecodes::prim_call:
00413     case Bytecodes::prim_call_lookup:
00414     case Bytecodes::prim_call_self_lookup:
00415     case Bytecodes::prim_call_self:
00416       return false;
00417 
00418     default: fatal("Wrong bytecode");
00419   }
00420   return false;
00421 }
00422 
00423 primitive_desc* primitives::_new0;
00424 primitive_desc* primitives::_new1;
00425 primitive_desc* primitives::_new2;
00426 primitive_desc* primitives::_new3;
00427 primitive_desc* primitives::_new4;
00428 primitive_desc* primitives::_new5;
00429 primitive_desc* primitives::_new6;
00430 primitive_desc* primitives::_new7;
00431 primitive_desc* primitives::_new8;
00432 primitive_desc* primitives::_new9;
00433 primitive_desc* primitives::_equal;
00434 primitive_desc* primitives::_not_equal;
00435 primitive_desc* primitives::_block_allocate;
00436 primitive_desc* primitives::_block_allocate0;
00437 primitive_desc* primitives::_block_allocate1;
00438 primitive_desc* primitives::_block_allocate2;
00439 primitive_desc* primitives::_context_allocate;
00440 primitive_desc* primitives::_context_allocate0;
00441 primitive_desc* primitives::_context_allocate1;
00442 primitive_desc* primitives::_context_allocate2;
00443 
00444 primitive_desc* primitives::verified_lookup(char* selector) {
00445   primitive_desc* result = lookup(selector);
00446   if (result == NULL) {
00447     err->print_cr("Verified primitive lookup failed");
00448     err->print_cr(" selector = %s", selector);
00449     fatal("aborted"); 
00450   }
00451   return result;
00452 }
00453 
00454 void primitives::initialize() {
00455   _new0              = verified_lookup("primitiveNew0");
00456   _new1              = verified_lookup("primitiveNew1");
00457   _new2              = verified_lookup("primitiveNew2");
00458   _new3              = verified_lookup("primitiveNew3");
00459   _new4              = verified_lookup("primitiveNew4");
00460   _new5              = verified_lookup("primitiveNew5");
00461   _new6              = verified_lookup("primitiveNew6");
00462   _new7              = verified_lookup("primitiveNew7");
00463   _new8              = verified_lookup("primitiveNew8");
00464   _new9              = verified_lookup("primitiveNew9");
00465 
00466   _equal             = verified_lookup("primitiveEqual:");
00467   _not_equal         = verified_lookup("primitiveNotEqual:");
00468 
00469   _block_allocate    = verified_lookup("primitiveCompiledBlockAllocate:");
00470   _block_allocate0   = verified_lookup("primitiveCompiledBlockAllocate0");
00471   _block_allocate1   = verified_lookup("primitiveCompiledBlockAllocate1");
00472   _block_allocate2   = verified_lookup("primitiveCompiledBlockAllocate2");
00473   _context_allocate  = verified_lookup("primitiveCompiledContextAllocate:");
00474   _context_allocate0 = verified_lookup("primitiveCompiledContextAllocate0");
00475   _context_allocate1 = verified_lookup("primitiveCompiledContextAllocate1");
00476   _context_allocate2 = verified_lookup("primitiveCompiledContextAllocate2");
00477 }

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