recompile.cpp

Go to the documentation of this file.
00001 /* Copyright 1994 - 1996 LongView Technologies L.L.C. $Revision: 1.57 $ */
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 
00025 # include "incls/_precompiled.incl"
00026 
00027 #ifdef DELTA_COMPILER
00028 
00029 #include "incls/_recompile.cpp.incl"
00030 
00031 nmethod* recompilee = NULL;             // method being recompiled
00032 Recompilation* theRecompilation;
00033 
00034 char* Recompilation::methodOop_invocation_counter_overflow(oop rcvr, methodOop method) {
00035   // called by the interpreter whenever a method's invocation counter reaches the limit
00036   // returns continuation pc or NULL if continuing in interpreter
00037   // Note: For block methods the receiver is the context associated with the
00038   //       block closure from which the method is coming from.
00039 
00040   // It seems that sometimes the method is screwed up, which causes a crash in consequence.
00041   // The following tests are for debugging only and should be removed at some point - gri 7/11/96.
00042   // If the method is illegal, recompilation is simply aborted.
00043   bool ok = false;
00044   if (Universe::is_heap((oop*)method)) {
00045     memOop obj = as_memOop(Universe::object_start((oop*) method));
00046     if (obj->is_method()) {
00047       ok = true;
00048     }
00049   }
00050   if (!ok) {
00051     // Possibly caused by a method sweeper bug: inline cache has been modified during the send.
00052     // To check: method is a jumpTable entry to an nmethod instead of a methodOop.
00053     char* msg = oop(method)->is_smi() ? "(method might be jump table entry)" : "";
00054     LOG_EVENT3("invocation counter overflow with broken methodOop 0x%x (recv = 0x%x) %s", method, rcvr, msg);
00055     fatal("invocation counter overflow with illegal method - internal error");
00056     // fatal("invocation counter overflow with illegal method - tell Robert");
00057     // continuing here is probably catastrophal because the invocation counter
00058     // increment might have modified the jump table entries anyway.
00059     return NULL;
00060   }
00061 
00062   if (UseRecompilation) {
00063     Recompilation recomp(rcvr, method);
00064     VMProcess::execute(&recomp);
00065     if (recomp.recompiledTrigger()) {
00066       return recomp.result();
00067     } else {
00068       return NULL;
00069     }
00070   } else {
00071     method->set_invocation_count(0);
00072     return NULL;
00073   }
00074 }
00075 
00076 
00077 char* Recompilation::nmethod_invocation_counter_overflow(oop rcvr, char* retpc) {
00078   // called by an nmethod whenever the nmethod's invocation counter reaches its limit
00079   // retpc is the recompilee's return PC (i.e., the pc of the nmethod which triggered
00080   // the invocation counter overflow).
00081   ResourceMark rm;
00082   nmethod* trigger = findNMethod(retpc);
00083   LOG_EVENT3("nmethod_invocation_counter_overflow: rcvr = %#x, pc = %#x (nmethod %#x)", rcvr, retpc, trigger);
00084   char* continuationAddr = trigger->verifiedEntryPoint();   // where to continue
00085 #ifdef ASSERT
00086   deltaVFrame* vf = DeltaProcess::active()->last_delta_vframe();
00087   assert(vf->is_compiled_frame() && ((compiledVFrame*)vf)->code() == trigger,
00088          "stack isn't set up right");
00089   //DeltaProcess::active()->trace_stack();
00090 #endif
00091   if (UseRecompilation) {
00092     Recompilation recomp(rcvr, trigger);
00093     VMProcess::execute(&recomp);
00094     if (recomp.recompiledTrigger()) {
00095       continuationAddr = recomp.result();
00096     }
00097   } else {
00098     //compiler_warning("if UseRecompilation is off, why does nmethod %#x have a counter?", trigger);
00099     trigger->set_invocation_count(1);
00100   }
00101   return continuationAddr;
00102 }
00103 
00104 
00105 nmethod* compile_method(LookupKey* key, methodOop m) {
00106   if (UseInliningDatabase && !m->is_blockMethod()) {
00107     // Find entry in inlining database matching the key.
00108     // If entry found we use the stored RScope a basis for the compile.
00109     RScope* rscope = InliningDatabase::lookup_and_remove(key);
00110     if (rscope) {
00111       VM_OptimizeRScope op(rscope);
00112       VMProcess::execute(&op);
00113       if (TraceInliningDatabase) {
00114         std->print_cr("Inlining database compile ");
00115         key->print_on(std);
00116         std->cr();
00117       }
00118       return op.result();
00119     }
00120   }
00121   VM_OptimizeMethod op(key, m);
00122   VMProcess::execute(&op);
00123   return op.result();
00124 }
00125 
00126 
00127 void Recompilation::init() {
00128   _newNM = NULL; 
00129   _triggerVF = NULL;
00130   _recompiledTrigger = false;
00131   assert(!theRecompilation, "already set");
00132   theRecompilation = this;
00133   if (_method->is_blockMethod() && !isCompiled()) {
00134     // interpreter passes in parent context, not receiver
00135     // should compute receiver via context (although receiver isn't actually used
00136     // for block RFrames right now) -- fix this
00137     if (_rcvr->is_context()) {
00138       contextOop ctx = (contextOop)_rcvr;
00139     } else {
00140       assert(_rcvr == nilObj, "expected nil");
00141     }
00142   }
00143 }
00144 
00145 
00146 void Recompilation::doit() {
00147   ResourceMark rm;
00148   if (PrintRecompilation) {
00149     lprintf("recompilation trigger: %s (%#x)\n", 
00150             _method->selector()->as_string(), 
00151             isCompiled() ? (char*)_nm : (char*)_method);
00152   }
00153 
00154   _triggerVF = calling_process()->last_delta_vframe();
00155   // trigger is the frame that triggered its counter
00156   // caution: that frame may be in a bad state, so don't access data within it
00157   RFrame* first;
00158   if (isCompiled()) {
00159     first = new CompiledRFrame(_triggerVF->fr());
00160   } else {
00161     first = new InterpretedRFrame(_triggerVF->fr(), _method, _rcvr->klass());
00162   }
00163 
00164   RecompilationPolicy policy(first);
00165   if (handleStaleInlineCache(first)) {
00166     // called obsolete method/nmethod -- no need to recompile
00167   } else {
00168     Recompilee* r;
00169     if (_isUncommon) {
00170       assert(isCompiled(), "must be compiled");
00171       r = Recompilee::new_Recompilee(first);
00172     } else {
00173       r = policy.findRecompilee();
00174     }
00175     _recompiledTrigger = r != NULL && r->rframe() == first;
00176     if (r) {
00177       recompile(r);
00178     } 
00179   
00180     if (true || !_recompiledTrigger) {    // fix this
00181       // reset the trigger's counter
00182       if (isCompiled() && !_nm->isUncommonRecompiled()) {
00183         // don't 
00184         _nm->set_invocation_count(1);
00185       } else {
00186         _method->set_invocation_count(1);
00187       }
00188     }
00189   }
00190   policy.cleanupStaleInlineCaches();
00191   recompilee = NULL;
00192 }
00193 
00194 bool Recompilation::handleStaleInlineCache(RFrame* first) {
00195   // check if the trigger was an interpreted method that has already been compiled; return true if so
00196   LookupKey* key = first->key();
00197   nmethod* nm;
00198   if (key && (nm = Universe::code->lookup(key)) != NULL) {
00199     // yes, we already have a compiled method; see if the sending inline cache points to that nmethod
00200     IC_Iterator* it = first->caller()->fr().current_ic_iterator();
00201     if (!it) return false;      // no inline cache (perform)
00202     assert(it->selector() == key->selector(), "selector mismatch");
00203     while (!it->at_end() && it->klass() != key->klass()) it->advance();
00204     if (it->at_end()) {
00205       // NB: this is possible -- inline cache could have been modified after the call, so now the
00206       // called method is no longer in it
00207     } else {
00208       nmethod* target = it->compiled_method();
00209       assert(!target || target == nm || target->key.equal(&nm->key), "inconsistent target");
00210       if (!target || target != nm) {
00211         // yes, the inline cache still calls the interpreted method rather than the compiled one,
00212         // or calls an obsolete nmethod which has been recompiled
00213         // replace it with the compiled one; no need to recompile anything now
00214         if (PrintRecompilation) {
00215           if (it->is_interpreted_ic()) {
00216             lprintf("replacing nm %#x in InterpretedIC %#x\n", nm, it->interpreted_ic());
00217           } else {
00218             lprintf("replacing nm %#x in CompiledIC %#x\n", nm, it->compiled_ic());
00219           }
00220         }
00221 
00222         // Replace the element in the inline cache
00223         if (it->is_interpreted_ic()) {
00224           it->interpreted_ic()->replace(nm);
00225         } else {
00226           it->compiled_ic()->replace(nm);
00227         }
00228 
00229         _newNM = nm;
00230         return true;
00231       }
00232     }
00233   }
00234   return false;
00235 }
00236 
00237 
00238 oop Recompilation::receiverOf(deltaVFrame* vf) const {
00239   return _triggerVF->equal(vf) ? _rcvr : vf->receiver();
00240 }
00241 
00242 
00243 #ifdef HEAVY_CLEANUP
00244 class CleanupInlineCaches: public ObjectClosure {
00245   void do_object(memOop obj) {
00246     if (obj->is_method()) 
00247       methodOop(obj)->cleanup_inline_caches();
00248   }
00249 };
00250 #endif
00251 
00252 
00253 void Recompilation::recompile(Recompilee* r) {
00254   // recompile r
00255   recompilee = r->is_compiled() ? r->code() : NULL;     // previous version (if any)
00256   if (r->rframe()->is_blockMethod()) {
00257     recompile_block(r);
00258   } else {
00259     recompile_method(r);
00260   }
00261 
00262   if (_newNM == NULL) return;                 // possible -- fix this later
00263 
00264   if (recompilee) {
00265     // discard old nmethod (*after* compiling newNM)
00266     recompilee->clear_inline_caches();
00267   }
00268 
00269   // because compilation uses oldNM's PICs)
00270   recompilee = NULL;
00271 
00272   // now install _newNM in calling inline cache
00273   vframe* vf = r->rframe()->top_vframe();
00274   IC_Iterator* it = vf->fr().sender_ic_iterator();
00275   if (it) {
00276     // Replace the element in the inline cache
00277     if (it->is_interpreted_ic()) {
00278       InterpretedIC* ic = it->interpreted_ic();
00279       if (!ic->is_empty()) ic->replace(_newNM);
00280     } else {
00281       CompiledIC* ic = it->compiled_ic();
00282       if (!ic->is_empty()) ic->replace(_newNM);
00283     }
00284   } else if (!_newNM->is_method()) {
00285     // recompiled a block: block call stub has already been updated
00286   } else {
00287     // called from C (incl. performs)
00288   }
00289 
00290   // update lookup caches
00291   lookupCache::flush(&_newNM->key);
00292   DeltaCallCache::clearAll();
00293 }
00294 
00295 
00296 void Recompilation::recompile_method(Recompilee* r) {
00297   // recompile method r
00298   LookupKey* key = r->key();
00299   methodOop m = r->method();
00300 #ifdef ASSERT
00301   LookupResult res = lookupCache::lookup(key);
00302   assert(res.method() == m, "mismatched method");
00303 #endif
00304   _newNM = Universe::code->lookup(key);       // see if we've already compiled it
00305 
00306   if (_newNM == NULL || _newNM == recompilee) {
00307     if (recompilee && !recompilee->isZombie()) recompilee->unlink(); // remove it from the code table
00308     _newNM = compile_method(key, m);
00309     if (recompilee && !recompilee->isZombie()) recompilee->makeZombie(true);
00310 #ifdef HEAVY_CLEANUP
00311     static int count;
00312     if (count++ > 10) {
00313       count = 0;
00314       TraceTime t("*cleaning inline caches...", PrintRecompilation2);
00315       CleanupInlineCaches blk;
00316       Universe::object_iterate(&blk);
00317       Universe::code->cleanup_inline_caches();
00318     }
00319 #endif
00320   } else {
00321     recompilee = NULL;                        // no recompilation necessary
00322   }
00323 }
00324 
00325 
00326 void Recompilation::recompile_block(Recompilee* r) {
00327   assert(r->rframe()->is_blockMethod(), "must be block recompilation");
00328   if (recompilee == NULL) {
00329     // Urs please fix this.
00330     // Sometimes recompilee is NULL when this is called
00331     // Lars, 6-18-96
00332     compiler_warning("recompilee == NULL when recompile_block is called, possibly internal error");
00333     //compiler_warning("recompilee == NULL when recompile_block is called -- Urs please look at this");
00334     _newNM = NULL;
00335     return;
00336   }
00337   assert(recompilee != NULL, "must have block recompilee");
00338 
00339   deltaVFrame* vf = r->rframe()->top_vframe();
00340   oop block;
00341   if (recompilee && recompilee->is_block()) {
00342     deltaVFrame* sender = vf->sender_delta_frame();
00343     if (sender == NULL) return;               // pathological case (not sure it can happen)
00344     GrowableArray<oop>* exprs = sender->expression_stack();
00345     // primitiveValue takes block as first argument
00346     int nargs = recompilee->method()->nofArgs();
00347     block = exprs->at(nargs);
00348   } else {
00349     block = receiverOf(vf);
00350   }
00351   assert(block->is_block(), "must be a block");
00352   _newNM = jumpTable::compile_block(blockClosureOop(block));
00353   if (recompilee != NULL) recompilee->makeZombie(true);   // do this last (after recompilation) 
00354 }
00355 
00356 
00357 Recompilee* Recompilee::new_Recompilee(RFrame* rf) {
00358   if (rf->is_compiled()) {
00359     return new CompiledRecompilee(rf, ((CompiledRFrame*)rf)->nm());
00360   } else {
00361     InterpretedRFrame* irf = (InterpretedRFrame*)rf;
00362     // Urs, please check this!
00363     assert(irf->key() != NULL, "must have a key");
00364     return new InterpretedRecompilee(irf, irf->key(), irf->top_method());
00365   }
00366 }
00367 
00368 LookupKey* CompiledRecompilee::key() const      { return &_nm->key; }
00369 methodOop  CompiledRecompilee::method() const   { return _nm->method(); }
00370 
00371 #else
00372 
00373 extern "C" void invocation_counter_overflow(oop receiver, methodOop method) {
00374   fatal("performance bug: shouldn't count invocations");
00375 }
00376 
00377 #endif

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