compiledIC.cpp

Go to the documentation of this file.
00001 /* Copyright 1994 - 1996 LongView Technologies L.L.C. $Revision: 1.46 $ */
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 
00026 # ifdef DELTA_COMPILER
00027 # include "incls/_compiledIC.cpp.incl"
00028 
00029 
00030 extern "C" void UncommonTrap() {
00031   ResourceMark rm;
00032   DeltaProcess::active()->trace_stack();
00033   error("Uncommon trap has been executed");
00034   evaluator::read_eval_loop();
00035 }
00036 
00037 
00038 char* CompiledIC::normalLookupRoutine() {
00039   return StubRoutines::ic_normal_lookup_entry();
00040 }
00041 
00042 
00043 char* CompiledIC::superLookupRoutine() {
00044   return StubRoutines::ic_super_lookup_entry();
00045 }
00046 
00047 
00048 extern "C" char* icNormalLookup(oop recv, CompiledIC* ic) {
00049   // As soon as the lookup routine handles 'message not understood' correctly,
00050   // allocation may take place. Then we have to fix the lookup stub as well.
00051   // (receiver cannot be saved/restored within the C frame).
00052   VerifyNoScavenge vna;
00053   return ic->normalLookup(recv);
00054 }
00055 
00056 
00057 bool CompiledIC::is_empty() const { 
00058   char* d = destination(); 
00059   return d == normalLookupRoutine() || d == superLookupRoutine(); 
00060 }
00061 
00062 
00063 int CompiledIC::ntargets() const {
00064   if (is_empty()) return 0;
00065   PIC* p = pic();
00066   return p != NULL ? p->number_of_targets() : 1;
00067 }
00068 
00069 
00070 void CompiledIC::set_call_destination(char* entry_point) {
00071   // if the IC has a PIC we deallocate the PIC before setting the entry_point
00072   PIC* p = pic();
00073   assert(p == NULL || p->entry() != entry_point, "replacing with same address -- shouldn't dealloc");
00074   if (p != NULL) delete p;
00075   NativeCall::set_destination(entry_point);
00076 }
00077 
00078 
00079 extern "C" bool have_nlr_through_C;
00080 
00081 oop nmethod_substitute() {
00082   return Universe::nilObj();
00083 }
00084 
00085 
00086 char* CompiledIC::normalLookup(oop recv) {
00087   ResourceMark rm;
00088   char* entry_point;
00089 
00090   // The assertion below is turned into an if so we can see
00091   // possible problems in the fast version as well - gri 6/21/96
00092   //
00093   // Last problem reported by Steffen (gri 7/24/96): This has been
00094   // called via a nmethod called from within a megamorphic self send
00095   // in the interpreter. I've added Interpreter::_last_native_called
00096   // for better debugging.
00097   //
00098   // assert(!Interpreter::contains(begin_addr()), "should be handled in the interpreter");
00099   if (Interpreter::contains(begin_addr())) {
00100     std->print_cr("nmethod called from interpreter reports ic miss:");
00101     std->print_cr("interpreter call at: 0x%x", begin_addr());
00102     std->print_cr("nmethod entry point: 0x%x", Interpreter::_last_native_called);
00103     InterpretedIC* ic = as_InterpretedIC(next_instruction_address());
00104     fatal("please notify VM people");
00105   }
00106 
00107   if (TraceLookup) {
00108     std->print("CompiledIC lookup (");
00109     recv->klass()->print_value();
00110     std->print(", ");
00111     selector()->print_value();
00112     std->print(")");
00113     std->cr();
00114   }
00115   klassOop klass = recv->klass();
00116   symbolOop sel = selector();
00117   LookupResult result = lookupCache::ic_normal_lookup(klass, sel);
00118 
00119   if (result.is_empty()) {
00120     // does not understand
00121     //
00122     // The following code is just a copy from the corresponding section
00123     // for interpreted code - especially the arguments for the message
00124     // object are not set up yet (0 arguments assumed). This code is
00125     // only here to prevent the system from crashing completely - in
00126     // general one should be able to recover using abort in the evaluator.
00127     //
00128     // FIX THIS (gri 6/10/96)
00129     BlockScavenge bs; // make sure that no scavenge happens
00130     klassOop msgKlass = klassOop(Universe::find_global("Message"));
00131     oop obj = msgKlass->klass_part()->allocateObject();
00132     assert(obj->is_mem(), "just checkin'...");
00133     memOop msg = memOop(obj);
00134     objArrayOop args = oopFactory::new_objArray(0);
00135     // for now: assume instance variables are there...
00136     // later: should check this or use a VM interface:
00137     // msg->set_receiver(recv);
00138     // msg->set_selector(ic->selector());
00139     // msg->set_arguments(args);
00140     msg->raw_at_put(2, recv);
00141     msg->raw_at_put(3, selector());
00142     msg->raw_at_put(4, args);
00143     symbolOop sel = oopFactory::new_symbol("doesNotUnderstand:");
00144     if (interpreter_normal_lookup(recv->klass(), sel).is_empty()) {
00145       // doesNotUnderstand: not found ==> process error
00146       { ResourceMark rm;
00147         std->print("LOOKUP ERROR\n");
00148         sel->print_value(); std->print(" not found\n");
00149       }
00150       if (DeltaProcess::active()->is_scheduler()) {
00151         DeltaProcess::active()->trace_stack();
00152         fatal("lookup error in scheduler");
00153       } else {
00154         DeltaProcess::active()->suspend(::lookup_error);
00155       }
00156       ShouldNotReachHere();
00157     }
00158     // return marked result of doesNotUnderstand: message
00159     oop result = Delta::call(recv, sel, msg);
00160 
00161     if (!have_nlr_through_C) {
00162       Unimplemented();
00163     }
00164     // return a substitute nmethod so that stub routine doesn't crash
00165     return (char*)nmethod_substitute;
00166   
00167     /* Old code - keep around till completely fixed
00168 
00169     LookupKey key(klass, sel);
00170 
00171     std->print("Compiled lookup failed for: ");
00172     key.print_on(std);
00173     std->cr();
00174 
00175     DeltaProcess::active()->trace_stack();
00176     warning("Lookup error: DoesNotUnderstand semantics not implemented for compiled code");
00177     evaluator::read_eval_loop();
00178     Unimplemented();
00179     */
00180   }
00181 
00182   if (isOptimized() && result.is_method()) {
00183     // If this call site is optimized only nmethods should be called.
00184     assert(!isMegamorphic(), "megamorphic ICs shouldn't be optimized");
00185     LookupKey key(klass, sel);
00186     VM_OptimizeMethod op(&key, result.method());
00187     VMProcess::execute(&op);
00188     result = lookupCache::ic_normal_lookup(klass, sel);
00189     assert(result.is_entry(), "result must contain a jump table entry");
00190   }
00191 
00192   bool empty = is_empty();
00193   if (empty) setDirty();
00194   if (!empty || result.is_method()) {
00195     PIC* pic = PIC::allocate(this, klass, result);
00196     if (pic == NULL) {
00197       // PIC too large & MICs (megamorphic PICs) turned off
00198       // => start with empty IC again
00199       assert(!UseMICs, "should return a MIC");
00200       clear();
00201       if (result.is_entry()) {
00202         entry_point =  isReceiverStatic()
00203                     ?  result.entry()->method()->verifiedEntryPoint()
00204                     :  result.entry()->destination();
00205       } else { 
00206         pic = PIC::allocate(this, klass, result);
00207         assert(pic != NULL, "pic must be present");
00208         entry_point = pic->entry();
00209       }
00210     } else {
00211       entry_point = pic->entry();
00212       if (pic->is_megamorphic()) {
00213         setMegamorphic(); // even when UseInlineCaching is turned off? (gri 5/24/96) - check this
00214       }
00215     }
00216   } else {
00217     assert(empty && result.is_entry(), "just checking");
00218 
00219     // result is a jump table entry for an nmethod
00220     if (TraceLookup2) lprintf("nmethod found, f = 0x%x\n", result.get_nmethod());
00221     // fetch the destination of the jump table entry to avoid the indirection
00222 
00223     // is the receiver is static we will use the verified entry point
00224     entry_point =  isReceiverStatic()
00225                 ?  result.entry()->method()->verifiedEntryPoint()
00226                 :  result.entry()->destination();
00227   }
00228   assert(isDirty(), "must be dirty now");       // important invariant for type feedback: non-empty IC must be dirty
00229   if (UseInlineCaching) set_call_destination(entry_point);
00230   if (TraceLookup2) print();
00231   LOG_EVENT3("CompiledICLookup (%#x, %#x) --> %#x", klass, sel, entry_point);
00232   return entry_point;
00233 }
00234 
00235 
00236 extern "C" char* icSuperLookup(oop recv, CompiledIC* ic) {
00237   // As soon as the lookup routine handles 'message not understood' correctly,
00238   // allocation may take place. Then we have to fix the lookup stub as well.
00239   // (receiver cannot be saved/restored within the C frame).
00240   VerifyNoScavenge vna;
00241   return ic->superLookup(recv);
00242 }
00243 
00244 
00245 extern "C" char* zombie_nmethod(char* return_addr) {
00246   // Called from zombie nmethods. Determines if called from interpreted
00247   // or compiled code, does cleanup of the corresponding inline caches
00248   // and restarts the send.
00249   //
00250   // Note: If the nmethod is called from within the interpreter, the
00251   //       send restart entry point is computed via a 2nd ic_info word
00252   //       that follows the ordinary ic_info associated with the call.
00253   //       (the same method as for NLRs used, the target is the send
00254   //       restart entry point).
00255   VerifyNoScavenge vna;
00256   if (Interpreter::contains(return_addr)) {
00257     // nmethod called from interpreted code
00258     frame          f  = DeltaProcess::active()->last_frame();
00259     InterpretedIC* ic = f.current_interpretedIC();
00260     LOG_EVENT1("zombie nmethod called => interpreted IC 0x%x cleared", ic);
00261     ic->cleanup();
00262     // reset instruction pointer => next instruction beeing executed is the same send
00263     f.set_hp(ic->send_code_addr());
00264     // restart send entry point for interpreted sends
00265     return Interpreter::redo_send_entry();
00266   } else {
00267     // nmethod called from compiled code
00268     CompiledIC* ic = CompiledIC_from_return_addr(return_addr);
00269     LOG_EVENT1("zombie nmethod called => compiled IC 0x%x cleaned up", ic);
00270     ic->cleanup();
00271     // restart send entry point is call address
00272     return ic->begin_addr();
00273   }
00274 }
00275 
00276 
00277 klassOop CompiledIC::targetKlass() const {
00278   nmethod* nm = target();
00279   if (nm) {
00280     return nm->key.klass();
00281   } else {
00282     Unimplemented(); return NULL;
00283   }
00284 }
00285 
00286 
00287 klassOop CompiledIC::sending_method_holder() {
00288   char* addr = begin_addr();
00289   nmethod* nm = findNMethod(addr);
00290   PcDesc* pcdesc = nm->containingPcDesc(addr);
00291   ScopeDesc* scope = pcdesc->containingDesc(nm);
00292   return scope->selfKlass()->klass_part()->lookup_method_holder_for(scope->method());
00293 }
00294 
00295 
00296 char* CompiledIC::superLookup(oop recv) {
00297   ResourceMark rm;
00298   char* entry_point;
00299   assert(!Interpreter::contains(begin_addr()), "should be handled in the interpreter");
00300 
00301   klassOop recv_klass = recv->klass();
00302   klassOop mhld_klass = sending_method_holder();
00303   symbolOop       sel = selector();
00304 
00305   if (TraceLookup) {
00306     std->print("CompiledIC super lookup (");
00307     recv_klass->print_value();
00308     std->print(", ");
00309     mhld_klass->print_value();
00310     std->print(", ");
00311     selector()->print_value();
00312     std->print(")");
00313     std->cr();
00314   }
00315 
00316   // The inline cache for super sends looks like the inline cache
00317   // for normal sends.
00318 
00319   LookupResult result = lookupCache::ic_super_lookup(recv_klass, mhld_klass->klass_part()->superKlass(), sel);
00320   assert(!result.is_empty(), "lookup cache error");
00321   if (result.is_method()) {
00322     // a methodOop
00323     if (TraceLookup2) lprintf("methodOop found, m = 0x%x\n", result.method());
00324     // result = (char*)&interpreter_call;
00325     // if (UseInlineCaching) set_call_destination(result);
00326     warning("CompiledIC::superLookup didn't find a nmethod - check this");
00327     Unimplemented();
00328   } else {
00329     // result is a jump table entry for an nmethod
00330     if (TraceLookup2) lprintf("nmethod %#x found\n", result.get_nmethod());
00331     // fetch the destination of the jump table entry to avoid the indirection
00332     entry_point = result.entry()->destination();
00333   }
00334   if (UseInlineCaching) set_call_destination(entry_point);
00335   if (TraceLookup2) print();
00336   LOG_EVENT3("SuperLookup (%#x, %#x) --> %#x", recv_klass, sel, entry_point);
00337   return entry_point;
00338 }
00339 
00340 
00341 bool CompiledIC::is_monomorphic() const  {
00342   if (target() != NULL) return true;
00343   PIC* p = pic();
00344   return p != NULL && p->is_monomorphic();
00345 }
00346 
00347 
00348 bool CompiledIC::is_polymorphic() const {
00349   PIC* p = pic();
00350   return p != NULL && p->is_polymorphic();
00351 }
00352 
00353 
00354 bool CompiledIC::is_megamorphic() const {
00355   PIC* p = pic();
00356   return p != NULL && p->is_megamorphic();
00357 }
00358 
00359 
00360 void CompiledIC::replace(nmethod* nm) {
00361   assert(selector() == nm->key.selector(), "mismatched selector");
00362   LOG_EVENT3("compiled IC at 0x%x: new nmethod 0x%x for klass 0x%x replaces old entry", this, nm, nm->key.klass());
00363 
00364   // MONO
00365   if (is_monomorphic()) {
00366     if (pic()) { 
00367       assert(pic()->klasses()->at(0) == nm->key.klass(), "mismatched klass");
00368     } else {
00369       // verify the key in the old nmethod matches the new
00370       assert(findNMethod(destination())->key.equal(&nm->key), "keys must match");
00371     }
00372     // set_call_destination deallocates the pic if necessary.
00373     set_call_destination(nm->entryPoint());
00374     return;
00375   }
00376   // POLY or MEGA
00377   PIC* p = pic();
00378   if (p != NULL) {
00379     PIC* new_pic = p->replace(nm);
00380     if (new_pic != p) {
00381       set_call_destination(new_pic->entry());
00382     }
00383     return;
00384   }
00385   // EMPTY
00386   ShouldNotReachHere();
00387 }
00388 
00389 
00390 void CompiledIC::clear() {
00391   // Fix this when compiler is more flexible
00392   assert(!isSuperSend() || UseNewBackend, "We cannot yet have super sends in nmethods");
00393   
00394   // Clear destination
00395   set_call_destination(isSuperSend() ? superLookupRoutine() : normalLookupRoutine());
00396 
00397   // Q: Are there any flags to be reset and if so, which ones?
00398   // A: No, they are "invariant" properties of the IC.  Even the dirty bit should not be
00399   //    reset, otherwise the compiler may think it was never executed.    -Urs 7/96
00400 }
00401 
00402 
00403 void CompiledIC::cleanup() {
00404   // Convert all entries using the following rules:
00405   //
00406   //  nmethod   -> nmethod   (nothing changed) 
00407   //            or nmethod'  (new nmethod has been compiled)
00408   //            or methodOop (old nmethod is invalid)
00409   //
00410   //  methodOop -> methodOop (nothing changed)
00411   //            or nmethod   (new nmethod has been compiled)
00412 
00413   // EMPTY
00414   if (is_empty()) return;
00415 
00416   // MONOMORPHIC
00417   if (is_monomorphic()) {
00418     if (pic()) {
00419       // Must be interpreter send
00420       PIC_Iterator it(pic());
00421       assert(it.is_interpreted(), "must be interpreted send in monomorphic case");
00422       // Since it is impossible to retrieve the sending method for a methodOop
00423       // we leave the IC unchanged if we're in a super send.
00424       if (isSuperSend()) return;
00425       LookupKey key(it.get_klass(), selector());
00426       LookupResult result = lookupCache::lookup(&key);
00427       // Nothing to do if lookup result is the same
00428       if (result.matches(it.interpreted_method())) return;
00429       // Otherwise update IC depending on lookup result
00430       if (result.is_empty()) {
00431         clear();
00432       } else if (result.is_method()) {
00433         it.set_methodOop(result.method());
00434       } else {
00435         assert(result.is_entry(), "lookup result should be a jump table entry");
00436         set_call_destination(result.get_nmethod()->entryPoint());
00437       }
00438     } else {
00439       // compiled target
00440       nmethod* old_nm = findNMethod(destination());
00441       LookupResult result = lookupCache::lookup(&old_nm->key);
00442       // Nothing to do if lookup result is the same
00443       if (result.matches(old_nm)) return;
00444       // Otherwise update IC depending on lookup result
00445       if (result.is_empty()) {
00446         clear();
00447       } else if (result.is_method()) {
00448         // don't set to interpreted method -- may be "compiled only" send
00449         clear();
00450       } else {
00451         assert(result.is_entry(), "lookup result should be a jump table entry");
00452         set_call_destination(result.get_nmethod()->entryPoint());
00453       }
00454       /* Old code for compiled target - remove if new version works (gri 7/17/96)
00455 
00456       nmethod* nm = findNMethod(destination());
00457       LookupResult result = lookupCache::lookup(&nm->key);
00458       assert(nm->isZombie() || result.is_entry(), "lookup cache is wrong");
00459       // Nothing to do if lookup result is the same
00460       if (result.matches(nm)) return;
00461       assert(nm->isZombie(), "nmethod should be zombie");
00462       nmethod* newNM = result.get_nmethod();
00463       if (newNM != NULL) {
00464         set_call_destination(newNM->entryPoint());
00465       } else {
00466         clear();    // don't set to interpreted method -- may be "compiled only" send
00467       }
00468       */
00469     }
00470     return;
00471   } 
00472 
00473   // POLYMORPHIC
00474   PIC* p = pic();
00475   if (p) {
00476     nmethod* nm;
00477     PIC* result = p->cleanup(&nm);
00478     if (result != p) {
00479       if (p != NULL) {
00480         // still polymorphic
00481         set_call_destination(result->entry());
00482       } else {
00483         if (nm) {
00484           // monomorphic
00485           set_call_destination(nm->entryPoint());
00486         } else {
00487           // anamorphic
00488           clear();
00489         }
00490       }
00491     }
00492     return;
00493   }
00494 
00495   // IMPOSSIBLE STATE
00496   ShouldNotReachHere();
00497 }
00498 
00499 
00500 void CompiledIC::print() {
00501   ResourceMark rm;    // so we can print from debugger
00502   lprintf("\t((CompiledIC*)%#x) ", this);
00503   if (is_empty()) {
00504     lprintf("(empty) ");
00505   } else {
00506     lprintf("(filled: %d targets) ", ntargets());
00507   }
00508   if (isReceiverStatic()) lprintf("static ");
00509   if (isDirty()) lprintf("dirty ");
00510   if (isOptimized()) lprintf("optimized ");
00511   if (isUninlinable()) lprintf("uninlinable ");
00512   if (isSuperSend()) lprintf("super ");
00513   if (isMegamorphic()) lprintf("megamorphic ");
00514   lprintf("\n");
00515 
00516   lprintf("\t- selector    : ");
00517   selector()->print_symbol_on();
00518   lprintf("\n");
00519 
00520   CompiledIC_Iterator it(this);
00521   while (!it.at_end()) {
00522     lprintf("\t- klass       : ");
00523     it.klass()->print_value();
00524     if (it.is_compiled()) {
00525       lprintf(";\tnmethod %#x\n", it.compiled_method());
00526     } else {
00527       lprintf(";\tmethod %#x\n", it.interpreted_method());
00528     }
00529     it.advance();
00530   }
00531   
00532   lprintf("\t- call address: ");
00533   char* dest = destination();
00534   if (dest == normalLookupRoutine()) {
00535     lprintf("normalLookupRoutine\n");
00536   } else if (dest == superLookupRoutine()) {
00537     lprintf("superLookupRoutine\n");
00538   } else {
00539     // non-empty icache
00540     lprintf("0x%x\n", destination());
00541   }
00542 
00543   lprintf("\t- NLR testcode: 0x%x\n", NLR_testcode());
00544 }
00545 
00546 
00547 InterpretedIC* CompiledIC::inlineCache() const {
00548   // return interpreter inline cache in corresponding source method
00549   char* addr = begin_addr();
00550   nmethod* nm = findNMethod(addr);
00551   PcDesc* pcdesc = nm->containingPcDesc(addr);
00552   ScopeDesc* scope = pcdesc->containingDesc(nm);
00553   CodeIterator iter = CodeIterator(scope->method(), pcdesc->byteCode);
00554   return iter.ic();
00555 }
00556 
00557 
00558 symbolOop CompiledIC::selector() const {
00559   return inlineCache()->selector();
00560 }
00561 
00562 
00563 nmethod* CompiledIC::target() const {
00564   char* dest = destination();
00565   if (Universe::code->contains(dest)) {
00566     // linked to an nmethod
00567     nmethod* m = nmethod_from_insts(dest);
00568     assert(m == findNMethod(dest), "wrong nmethod start");
00569     return m;
00570   } else {
00571     return NULL;
00572   }
00573 }
00574 
00575 
00576 klassOop CompiledIC::get_klass(int i) const {
00577   PIC* p = pic();
00578   if (p) {
00579     PIC_Iterator it(p);
00580     for (int j = 0; j < i; j++) it.advance();
00581     return it.get_klass();
00582   } else {
00583     assert(i == 0, "have max. 1 target method");
00584     return target()->key.klass();
00585   }
00586 }
00587 
00588 
00589 PIC* CompiledIC::pic() const {
00590   char* dest = destination();
00591   return PIC::find(dest);
00592 }
00593 
00594 
00595 LookupKey* CompiledIC::key(int i, bool is_normal_send) const {
00596   if (is_normal_send) {
00597     return LookupKey::allocate(get_klass(i), selector());
00598   } else {
00599     CompiledIC_Iterator it((CompiledIC*)this);
00600     it.goto_elem(i);
00601     return LookupKey::allocate(it.klass(), it.interpreted_method());
00602   }
00603 }
00604 
00605 
00606 bool CompiledIC::wasNeverExecuted() const {
00607   return is_empty() && !isDirty();
00608 }
00609 
00610   CompiledIC* CompiledIC_from_return_addr(char* return_addr) {
00611     return (CompiledIC*)nativeCall_from_return_address(return_addr);
00612   }
00613 
00614   CompiledIC* CompiledIC_from_relocInfo(char* displacement_address) {
00615     return (CompiledIC*)nativeCall_from_relocInfo(displacement_address);
00616   }
00617 
00618 primitive_desc* PrimitiveIC::primitive() {
00619   return primitives::lookup((fntype) destination());
00620 }
00621 
00622 
00623 char* PrimitiveIC::end_addr() {
00624   primitive_desc* pd = primitive();
00625   int offset = pd->can_perform_NLR() ? IC_Info::instruction_size : 0;
00626   return next_instruction_address() + offset;
00627 }
00628 
00629 
00630 void PrimitiveIC::print() {
00631   lprintf("\tPrimitive inline cache\n");
00632   primitive_desc* pd = primitive();
00633   lprintf("\t- name        : %s\n", pd->name());
00634   if (pd->can_perform_NLR()) {
00635     lprintf("\t- NLR testcode: 0x%x\n", NLR_testcode());
00636   }
00637 }
00638 
00639   PrimitiveIC* PrimitiveIC_from_return_addr(char* return_addr) {
00640     return (PrimitiveIC*)nativeCall_from_return_address(return_addr);
00641   }
00642 
00643   PrimitiveIC* PrimitiveIC_from_relocInfo(char* displacement_address) {
00644     return (PrimitiveIC*)nativeCall_from_relocInfo(displacement_address);
00645   }
00646 
00647 #else
00648 
00649 // Dummy for avoiding link error for system without the DELTA_COMPILER
00650 extern "C" void icLookup(int a, int b) {}
00651 extern "C" void icNormalLookup(int a, int b) {}
00652 extern "C" void icSuperLookup(int a, int b) {}
00653 
00654 #endif

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