inliner.cpp

Go to the documentation of this file.
00001 /* Copyright 1994 - 1996, LongView Technologies L.L.C. $Revision: 1.81 $ */
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 
00028 # include "incls/_inliner.cpp.incl"
00029 
00030 // ----------- inlining policy ---------------
00031 
00032 #ifdef later
00033   static const int DefaultCompilerMaxSplitCost        =   50;
00034   static const int DefaultCompilerMaxBlockInstrSize   =  400;
00035   static const int DefaultCompilerMaxFnInstrSize      =  250;
00036   static const int DefaultCompilerMaxBlockFnInstrSize =  600;
00037   static const int DefaultCompilerMaxNmethodInstrSize = 5000;
00038 #endif
00039 
00040 static CompilerInliningPolicy inliningPolicy;
00041 
00042 bool InliningPolicy::shouldNotInline() const {
00043   if (method->method_inlining_info() == methodOopDesc::never_inline) return true;
00044   const symbolOop sel = method->selector();
00045   return (sel == vmSymbols::error() ||
00046           sel == vmSymbols::error_() ||
00047           sel == vmSymbols::subclassResponsibility()); 
00048 }
00049 
00050 bool InliningPolicy::isCriticalSmiSelector(const symbolOop sel) {
00051   // true if performance-critical smi method in standard library
00052   // could also handle these by putting a bit in the methodOops 
00053   return  sel == vmSymbols::plus() ||
00054           sel == vmSymbols::minus() ||
00055           sel == vmSymbols::multiply() ||
00056           sel == vmSymbols::divide() ||
00057           sel == vmSymbols::mod() ||
00058           sel == vmSymbols::equal() ||
00059           sel == vmSymbols::not_equal() ||
00060           sel == vmSymbols::less_than() ||
00061           sel == vmSymbols::less_than() ||
00062           sel == vmSymbols::less_than_or_equal() ||
00063           sel == vmSymbols::greater_than() ||
00064           sel == vmSymbols::greater_than_or_equal() ||
00065           sel == vmSymbols::double_equal() ||
00066           sel == vmSymbols::bitAnd_() || 
00067           sel == vmSymbols::bitOr_() || 
00068           sel == vmSymbols::bitXor_() || 
00069           sel == vmSymbols::bitShift_() || 
00070           sel == vmSymbols::bitInvert();
00071 } 
00072 
00073 bool InliningPolicy::isCriticalArraySelector(const symbolOop sel) {
00074   return  sel == vmSymbols::at() ||
00075           sel == vmSymbols::at_put() ||
00076           sel == vmSymbols::size();
00077 }
00078 
00079 bool InliningPolicy::isCriticalBoolSelector(const symbolOop sel) {
00080   return  sel == vmSymbols::and_() ||
00081           sel == vmSymbols::or_() ||
00082           sel == vmSymbols::and() ||
00083           sel == vmSymbols::or() ||
00084           sel == vmSymbols::and1() ||
00085           sel == vmSymbols::or1() ||
00086           sel == vmSymbols::and() ||
00087           sel == vmSymbols::not() ||
00088           sel == vmSymbols::xor_() ||
00089           sel == vmSymbols::eqv_();
00090 }
00091 
00092 bool InliningPolicy::isPredictedSmiSelector(const symbolOop sel) {
00093   return sel != vmSymbols::equal()     &&
00094          sel != vmSymbols::not_equal() &&
00095          isCriticalSmiSelector(sel);
00096 }
00097 
00098 bool InliningPolicy::isPredictedArraySelector(const symbolOop sel) {
00099   return isCriticalArraySelector(sel);
00100 }
00101 bool InliningPolicy::isPredictedBoolSelector(const symbolOop sel) {
00102   return isCriticalBoolSelector(sel);
00103 }
00104 
00105 bool InliningPolicy::isInterpreterPredictedSmiSelector(const symbolOop sel) {
00106   // true if performance-critical smi method in standard library
00107   // could also handle these by putting a bit in the methodOops 
00108   return  sel == vmSymbols::plus() ||
00109           sel == vmSymbols::minus() ||
00110           sel == vmSymbols::multiply() ||
00111           sel == vmSymbols::divide() ||
00112           sel == vmSymbols::mod() ||
00113           sel == vmSymbols::equal() ||
00114           sel == vmSymbols::not_equal() ||
00115           sel == vmSymbols::less_than() ||
00116           sel == vmSymbols::less_than() ||
00117           sel == vmSymbols::less_than_or_equal() ||
00118           sel == vmSymbols::greater_than() ||
00119           sel == vmSymbols::greater_than_or_equal();
00120 } 
00121 
00122 bool InliningPolicy::isInterpreterPredictedArraySelector(const symbolOop sel) {
00123   return false;
00124 }
00125 
00126 bool InliningPolicy::isInterpreterPredictedBoolSelector(const symbolOop sel) {
00127   return false;
00128 }
00129 
00130 
00131 
00132 bool InliningPolicy::isBuiltinMethod() const {
00133   // true if performance-critical method in standard library
00134   // could also handle these by putting a bit in the methodOops 
00135   if (method->method_inlining_info() == methodOopDesc::always_inline) return true;
00136   const symbolOop sel = method->selector();
00137   const klassOop klass = receiverKlass();
00138   const bool isNum = klass == Universe::smiKlassObj() || klass == Universe::doubleKlassObj();
00139   if  (isNum && isCriticalSmiSelector(sel)) return true;
00140 
00141   const bool isArr = klass == Universe::objArrayKlassObj()  || 
00142                      klass == Universe::byteArrayKlassObj() ||
00143                      klass == Universe::symbolKlassObj()    ||
00144                      false;     // probably should add doubleByteArray et al
00145   if (isArr && isCriticalArraySelector(sel)) return true;
00146 
00147   const bool isBool = klass == Universe::trueObj()->klass() || klass == Universe::falseObj()->klass();
00148   if (isBool && isCriticalBoolSelector(sel)) return true;
00149   return false;
00150 }
00151 
00152 char* CompilerInliningPolicy::shouldInline(InlinedScope* s, InlinedScope* callee) {
00153   if (callee == NULL) {
00154     return "cannot handle super sends";
00155   }
00156 
00157   if (callee->rscope->isDatabaseScope()) {
00158     // This scope is provided by the inlining database and should
00159     // always be inlined.
00160     return NULL;
00161   }
00162 
00163   if (s->rscope->isDatabaseScope()) {
00164     // The caller scope is provided by the inlining database but the callee scope is not.
00165     // ignore the callee when inlining.
00166     return "do not inline (Inlining Database)";
00167   }
00168 
00169   // should check for existing compiled version here -- fix this
00170   sender = s;
00171   this->method = callee->method();
00172   this->rcvr   = callee->self();
00173   if (NodeFactory::cumulCost > MaxNmInstrSize) {
00174     theCompiler->reporter->report_toobig(callee);
00175     return "method getting too big";
00176   }
00177   if (shouldNotInline()) return "should not inline (special)";
00178   // performance bug: should check how many recursive calls the method has -- unrolling factorial
00179   // to depth N gives N copies, but unrolling fibonacci gives 2**N
00180   // also, should look at call chain to estimate how big inlined recursion will get
00181   if (sender->isRecursiveCall(method, callee->selfKlass(), MaxRecursionUnroll)) return "recursive";
00182   return basic_shouldInline(method);
00183 }
00184 
00185 char* InliningPolicy::basic_shouldInline(methodOop method) {
00186   // should the interpreted method be inlined?
00187   if (method->method_inlining_info() == methodOopDesc::always_inline) return NULL;
00188   calleeCost = method->estimated_inline_cost(receiverKlass());
00189 
00190   if (method->is_blockMethod()) {
00191     // even large blocks should be inlined if they make up most of their home's code
00192     int parentCost = method->parent()->estimated_inline_cost(receiverKlass());
00193     assert(parentCost > calleeCost, "must be higher");
00194     if (float(parentCost - calleeCost) / parentCost * 100.0 < MinBlockCostFraction) return NULL;
00195   } 
00196 
00197   // compute the cost limit based on the provided arguments
00198   int cost_limit = method->is_blockMethod() ? MaxBlockInlineCost : MaxFnInlineCost;
00199   for (int i = method->number_of_arguments() - 1; i >= 0; i--) {
00200     klassOop k = nthArgKlass(i);
00201     if (k && k->klass_part()->oop_is_block()) cost_limit += BlockArgAdditionalAllowedInlineCost;
00202   }
00203   if (calleeCost < cost_limit) return NULL;
00204   if (isBuiltinMethod()) return NULL;
00205   return "too big";
00206 }
00207 
00208 klassOop CompilerInliningPolicy::nthArgKlass(int i) const {
00209   int first = sender->exprStack()->length() - method->number_of_arguments();
00210   Expr* e = sender->exprStack()->at(first + i);
00211   return e->hasKlass() ? e->klass() : NULL;
00212 }
00213 
00214 klassOop CompilerInliningPolicy::receiverKlass() const          { return rcvr->klass(); }
00215 
00216 klassOop RecompilerInliningPolicy::nthArgKlass(int i) const     { return _vf ? _vf->argument_at(i)->klass() : NULL; }
00217 klassOop RecompilerInliningPolicy::receiverKlass() const { 
00218   return _vf ? theRecompilation->receiverOf(_vf)->klass() : NULL; 
00219 }
00220 
00221 char* RecompilerInliningPolicy::shouldInline(RFrame* rf) {
00222   // determine if rf's method or nmethod should be inlined into its caller
00223   // use compiled-code size if available, even for interpreted methods
00224   // (gives better info on how big method will become since it includes inlined methods)
00225   // return NULL if ok, reason for not inlining otherwise (for performance debugging)
00226 
00227   // for now, always inline super sends
00228   extern bool SuperSendsAreAlwaysInlined;
00229   assert(SuperSendsAreAlwaysInlined, "fix this");
00230   if (rf->is_super()) return NULL;
00231 
00232   _vf = rf->top_vframe();
00233   this->method = rf->top_method();
00234   nmethod* nm = NULL;
00235   if (rf->is_interpreted()) {
00236     // check to see if we have a compiled version of the method
00237     LookupKey* key = rf->key();
00238     if (key) {
00239       nm = Universe::code->lookup(key);
00240     } else {
00241       // interpreted block; should check for compiled block
00242       // fix this later
00243     }
00244   } else {
00245     assert(rf->is_compiled(), "oops");
00246     nm = ((CompiledRFrame*)rf)->nm();
00247   }
00248   if (nm) {
00249     return shouldInline(nm);
00250   } else {
00251     return basic_shouldInline(method);
00252   }
00253 }
00254 
00255 char* RecompilerInliningPolicy::shouldInline(nmethod* nm) {
00256   if (!CodeSizeImpactsInlining) return NULL;
00257   if (method->method_inlining_info() == methodOopDesc::always_inline) return NULL;
00258   // compute the allowable cost based on the method type and the provided arguments
00259   int cost_limit = method->is_blockMethod() ? MaxBlockInstrSize : MaxFnInstrSize;
00260   int i = method->number_of_arguments();
00261   while (i-- > 0) {
00262     klassOop k = nthArgKlass(i);
00263     if (k && k->klass_part()->oop_is_block()) cost_limit += BlockArgAdditionalInstrSize;
00264   }
00265   if (nm->size() < cost_limit) return NULL;     // ok
00266   if (isBuiltinMethod()) return NULL;           // ok, special case (?)
00267   return "too big (compiled)";
00268 }
00269 
00270 // --------------- Inliner ------------------
00271 
00272 void Inliner::initialize() {
00273   _info = NULL;
00274   res = NULL;
00275   callee = NULL;
00276   gen = NULL;
00277   merge = NULL;
00278   resultPR = NULL;
00279   depth = 0;
00280   _msg = NULL;
00281   lastLookupFailed = false;
00282 }
00283 
00284 void Inliner::initialize(SendInfo* info, SendKind kind) {
00285   initialize();
00286   _info = info;
00287   this->kind = kind;
00288   sender = _info->senderScope;
00289   gen = sender->gen();
00290   _info->resReg = resultPR = new SAPReg(sender);
00291   depth = sender->depth;
00292 }
00293 
00294 Expr* Inliner::inlineNormalSend(SendInfo* info) {
00295   initialize(info, NormalSend);
00296   return inlineSend();
00297 }
00298 
00299 Expr* Inliner::inlineSuperSend(SendInfo* info) {
00300   initialize(info, SuperSend);
00301   return inlineSend();
00302 }
00303 
00304 Expr* Inliner::inlineSelfSend(SendInfo* info) {
00305   initialize(info, SelfSend);
00306   return inlineSend();
00307 }
00308 
00309 Expr* Inliner::inlineSend() {
00310   if (!Inline) {
00311     // don't do any inlining
00312     _info->needRealSend = true;
00313   } else if (gen->is_in_dead_code()) {
00314     // don't waste time inlining dead code 
00315     res = new NoResultExpr;
00316     gen->abort();   // the rest of this method is dead code, too
00317     if (CompilerDebug) cout(PrintInlining)->print("%*s*skipping %s (dead code)\n", depth, "", _info->sel->as_string());
00318   } else {
00319     tryInlineSend();
00320   }
00321 
00322   // generate a real send if necessary
00323   if (_info->needRealSend) {
00324     Expr* r = genRealSend();
00325     res = res ? res->mergeWith(r, merge) : r;
00326     assert(res, "must have result");
00327   }
00328   // merge end of inlined version with end of noninlined version
00329   if (merge && res && !res->isNoResultExpr()) gen->branch(merge);
00330 
00331   // update caller's current node
00332   if (gen != sender->gen()) sender->gen()->setCurrent(gen->current());
00333 
00334   // ...and return result (sender is responsible for popping expr stack)
00335   if (!res) res = new NoResultExpr;
00336   return res;
00337 }
00338 
00339 Expr* Inliner::genRealSend() {
00340   const int nofArgs = _info->sel->number_of_arguments();
00341   bool uninlinable = theCompiler->registerUninlinable(this); 
00342   if (CompilerDebug) {
00343     cout(PrintInlining)->print("%*s*sending %s %s%s\n", depth, "", _info->sel->as_string(),
00344       uninlinable ? "(unlinlinable) " : "",
00345       _info->counting ? "(counting) " : "");
00346   }
00347   switch(kind) {
00348     case NormalSend:    gen->gen_normal_send(_info, nofArgs, resultPR); break; 
00349     case SelfSend:      gen->gen_self_send  (_info, nofArgs, resultPR); break; 
00350     case SuperSend:     gen->gen_super_send (_info, nofArgs, resultPR); break; 
00351     default:            fatal1("illegal SendKind %d", kind);
00352   }
00353   return new UnknownExpr(resultPR, gen->current());
00354 }
00355 
00356 void Inliner::tryInlineSend() {
00357   const symbolOop sel = _info->sel;
00358 
00359   UnknownExpr* u = _info->rcvr->findUnknown();
00360   bool usingInliningDB = sender->rscope->isDatabaseScope();
00361   // first, use type feedback
00362   if (TypeFeedback && u) {
00363     assert(kind != SuperSend, "shouldn't PIC-predict super sends");
00364     // note: when compiling using the inlining database, picPredict won't actually look at any PICs,
00365     // just at the inlining DB
00366     _info->rcvr = picPredict();
00367   }
00368 
00369   // now try static type prediction (but only if type isn't good enough yet)
00370   if (TypePredict && !usingInliningDB && u && !u->isUnlikely() && !_info->uninlinable) {
00371     _info->rcvr = typePredict();
00372   }
00373       
00374   if (_info->rcvr->really_hasKlass(sender)) {
00375     // single klass - try to inline this send
00376     callee = tryLookup(_info->rcvr);
00377     if (callee) {
00378       Expr* r = doInline(sender->current());
00379       res = makeResult(r);
00380     } else {
00381       // must distinguish between lookup failures and rejected successes
00382       if (lastLookupFailed) {
00383         // receiver type is constant (but e.g. method was too big to inline)
00384         _info->receiverStatic = true;
00385       }
00386       _info->needRealSend = true;
00387     }
00388   } else if (_info->rcvr->isMergeExpr()) {
00389     res = inlineMerge(_info);           // inline some cases
00390     if (res) {
00391       // inlined some cases; inlineMerge decided whether needRealSend should be set or not
00392       if (!theCompiler->is_uncommon_compile()) {
00393         _info->uninlinable = true;        // remaining sends are here by choice
00394         _info->counting = false;
00395       }
00396     } else {
00397       // didn't inline anything -- just generate a non-inlined send
00398       _info->needRealSend = true;
00399     }
00400   } else {
00401     // unknown receiver
00402     // NB: *must* use uncommon branch if marked unlikely because
00403     // future type tests won't test for unknown
00404     if (CompilerDebug) cout(PrintInlining)->print("%*s*cannot inline %s (unknown receiver)\n", depth, "", sel->as_string());
00405     if (_info->rcvr->findUnknown()->isUnlikely()) {
00406       // generate an uncommon branch for the unknown case, not a send
00407       gen->append_exit(NodeFactory::new_UncommonNode(sender->gen()->copyCurrentExprStack(), sender->bci()));
00408       _info->needRealSend = false;
00409       if (CompilerDebug) cout(PrintInlining)->print("%*s*making %s uncommon\n", depth, "", sel->as_string());
00410       res = new NoResultExpr();
00411       // rest of method's code is unreachable
00412       assert(gen->current() == NULL, "expected no current node");
00413       gen->abort();
00414     } else {
00415       _info->needRealSend = true;
00416     }
00417   }
00418 }
00419 
00420 
00421 Expr* Inliner::inlineMerge(SendInfo* info) {
00422   // try to inline the send by type-casing
00423   merge = NodeFactory::new_MergeNode(sender->bci());            // where all cases merge again
00424   Expr* res = NULL;                                                     // final (merged) result
00425   assert(info->rcvr->isMergeExpr(), "must be a merge");
00426   MergeExpr* r = (MergeExpr*)info->rcvr;                                // receiver type        
00427   symbolOop sel = info->sel;
00428 
00429   int nexprs = r->exprs->length();
00430   int ncases = nexprs - (r->containsUnknown() ? 1 : 0);
00431   if (ncases > MaxTypeCaseSize) {
00432     info->needRealSend = true;
00433     info->uninlinable = true;
00434     info->counting = false;
00435     if (CompilerDebug) cout(PrintInlining)->print("%*s*not type-casing %s (%ld > MaxTypeCaseSize)\n",
00436                                                        depth, "", sel->as_string(), ncases);
00437     return res;
00438   }  
00439 
00440   // build list of cases to inline
00441   // (add only immediate klasses (currently only smis) at first, collect others in ...2 lists
00442   GrowableArray<InlinedScope*>* scopes  = new GrowableArray<InlinedScope*>(nexprs);
00443   GrowableArray<InlinedScope*>* scopes2 = new GrowableArray<InlinedScope*>(nexprs);
00444   GrowableArray<Expr*>*         exprs   = new GrowableArray<Expr*>(nexprs);
00445   GrowableArray<Expr*>*         exprs2  = new GrowableArray<Expr*>(nexprs);
00446   GrowableArray<Expr*>*         others  = new GrowableArray<Expr*>(nexprs);
00447   GrowableArray<klassOop>*      klasses = new GrowableArray<klassOop>(nexprs);
00448   GrowableArray<klassOop>*      klasses2= new GrowableArray<klassOop>(nexprs);
00449   const bool containsUnknown = r->containsUnknown();
00450 
00451   for (int i = 0; i < nexprs; i++) {    
00452     Expr* nth = r->exprs->at(i)->shallowCopy(r->preg(), NULL);
00453     assert(!nth->isConstantExpr() || nth->next == NULL ||
00454            nth->constant() == nth->next->constant(),
00455            "shouldn't happen: merged consts - convert to klass");
00456     // NB: be sure to generalize constants to klasses before inlining, so that values 
00457     // from an unknown source are dispatched to the optimized code
00458     // also, right now the TypeTestNode only tests for klasses, not constants
00459     if (containsUnknown && nth->isConstantExpr()) {
00460       nth = nth->convertToKlass(nth->preg(), nth->node());
00461     }
00462 
00463     InlinedScope* s;
00464     if (nth->hasKlass() &&
00465         (s = tryLookup(nth)) != NULL) {
00466       // can inline this case
00467       klassOop klass = nth->klass();
00468       if (klass == smiKlassObj) {
00469         scopes  ->append(s);        // smis go first
00470         exprs   ->append(nth);
00471         klasses ->append(klass);
00472       } else {
00473         scopes2 ->append(s);        // append later
00474         exprs2  ->append(nth);
00475         klasses2->append(klass);
00476       }
00477     } else {
00478       if (lastLookupFailed) {
00479         // ignore this case -- most probably it will never happen
00480         // (typical case: the class is returned by something like
00481         // self error: 'should not happen'. ^ self)
00482         if (others->isEmpty()) {
00483           others->append(new UnknownExpr(nth->preg(), NULL, theCompiler->useUncommonTraps));
00484         } 
00485       } else {
00486         others->append(nth);
00487       }
00488       info->needRealSend = true;
00489     }
00490   }
00491 
00492   // combine all lists into one (with immediate case first)
00493   klasses->appendAll(klasses2);
00494   exprs  ->appendAll(exprs2);
00495   scopes ->appendAll(scopes2);
00496 
00497   // decide whether to use uncommon branch for unknown case (if any)
00498   // NB: *must* use uncommon branch if marked unlikely because
00499   // future type tests won't test for unknown
00500   bool useUncommonBranchForUnknown = false;
00501   if (others->length() == 1 && others->first()->isUnknownExpr() &&
00502       ((UnknownExpr*)others->first())->isUnlikely()) {
00503     // generate an uncommon branch for the unknown case, not a send
00504     useUncommonBranchForUnknown = true;
00505     if (CompilerDebug) cout(PrintInlining)->print("%*s*making %s uncommon (2)\n", depth,"",sel->as_string());
00506   }
00507 
00508   // now do the type test and inline the individual cases
00509   Node* typeCase    = NULL;
00510   Node* fallThrough = NULL;
00511   if (scopes->length() > 0) {
00512     //memoizeBlocks(sel);
00513       
00514     if (CompilerDebug) {
00515       char* s = NEW_RESOURCE_ARRAY(char, 200);
00516       sprintf(s, "begin type-case of %s (ends at node N%ld)",
00517               sel->copy_null_terminated(), merge->id());
00518       gen->comment(s);
00519     }
00520     if (CompilerDebug) cout(PrintInlining)->print("%*s*type-casing %s (%d cases)\n", depth, "", sel->as_string(), scopes->length());
00521 
00522     typeCase = NodeFactory::new_TypeTestNode(r->preg(), klasses, info->needRealSend || containsUnknown);
00523     gen->append(typeCase);
00524     fallThrough = typeCase->append(NodeFactory::new_NopNode()); // non-predicted case
00525     for (i = 0; i < scopes->length(); i++) {
00526       // inline one case
00527       Inliner* inliner = new Inliner(sender);
00528       inliner->initialize(new SendInfo(*info), kind);
00529       inliner->callee = scopes->at(i);                  // scope to inline
00530       inliner->gen = callee->gen();                     // node builder to use
00531       inliner->gen->setCurrent(typeCase->append(i + 1, NodeFactory::new_NopNode()));
00532       Expr* rcvr = exprs->at(i);
00533       inliner->info()->rcvr = rcvr;
00534       assert(r->scope()->isSenderOf(inliner->callee), "r must be from caller scope");
00535       Expr* e = inliner->doInline(inliner->gen->current());
00536       if (e->isNoResultExpr()) {
00537         if (!res) res = e;      // must return non-NULL result (otherwise sender thinks no inlining happened)
00538       } else {
00539         assert(e->preg()->scope()->isSenderOf(inliner->callee), 
00540                "result register must be from caller scope");
00541         gen->append(NodeFactory::new_NopNode());
00542         e = e->shallowCopy(info->resReg, gen->current());
00543         res = res ? res->mergeWith(e, merge) : e;
00544       }
00545       gen->branch(merge);
00546     }
00547     assert(gen == sender->gen(), "oops");
00548     gen->setCurrent(fallThrough);
00549   } else {
00550     // no case was deemed inlinable
00551     if (!info->counting && !theCompiler->is_uncommon_compile()) info->uninlinable = true;
00552     useUncommonBranchForUnknown = false;
00553   }
00554 
00555   if (res && res->isMergeExpr()) res->setNode(merge, info->resReg);
00556 
00557   assert( info->needRealSend &&  others->length() ||
00558           !info->needRealSend && !others->length(), "inconsistent");
00559 
00560   if (useUncommonBranchForUnknown) {
00561     // generate an uncommon branch for the unknown case, not a send
00562     gen->append_exit(NodeFactory::new_UncommonNode(gen->copyCurrentExprStack(), sender->bci()));
00563     info->needRealSend = false;
00564   } else if (others->isEmpty()) {
00565     // typecase cannot fail
00566     gen->append_exit(NodeFactory::new_FixedCodeNode(FixedCodeNode::dead_end));
00567   }
00568   
00569   return res;
00570 }
00571 
00572   
00573 Expr* Inliner::makeResult(Expr* r) {
00574   Expr* res;
00575   // massage the result expression so it fulfills all constraints
00576   if (r->isNoResultExpr()) {
00577     res = r;
00578   } else {
00579     // result's scope must be in sender, not in callee (for correct reg. alloc.)
00580     if (r->scope() == sender) {
00581       res = r;
00582     } else {
00583       assert(r->scope() == callee, "what scope?");
00584       //fatal("Urs thinks this shouldn't happen");
00585       ShouldNotReachHere(); // added instead of the fatal (gri 11/27/01)
00586       // bind it to new NopNode to fix scope
00587       Node* n = NodeFactory::new_NopNode();
00588       assert(n->scope() == sender, "wrong scope");
00589       gen->append(n);
00590       res = r->shallowCopy(r->preg(), n);
00591     }
00592   }
00593   return res;
00594 }
00595   
00596 Expr* Inliner::doInline(Node* start) {
00597   // callee scope should be inlined; do it
00598 // HACK -- fix
00599 #define calleeSize(n) 0
00600 
00601   if (CompilerDebug) {
00602     cout(PrintInlining)->print("%*s*inlining %s, cost %ld/size %ld (%#lx)%s\n", depth, "",
00603       callee->selector()->as_string(), inliningPolicy.calleeCost, calleeSize(callee->rscope),
00604       PrintHexAddresses ? callee : 0, callee->rscope->isNullScope() ? "" : "*");
00605     if (PrintInlining) callee->method()->pretty_print();
00606   }
00607 
00608   // Save dependency information in the scopeDesc recorder.
00609   theCompiler->rec->add_dependant(callee->key());
00610 
00611   Node* next = start->next();
00612   assert(!next, "can't insert code (?)");
00613 
00614   // set callee's starting point for code generation
00615   gen = callee->gen();
00616   gen->setCurrent(start);
00617   callee->genCode();
00618 
00619   // make sure caller appends new code after inlined return of callee
00620   gen = sender->gen();
00621   gen->setCurrent(callee->returnPoint());
00622   assert(gen->current()->next() == NULL, "shouldn't have successor");
00623   return callee->result;
00624 }
00625 
00626 Expr* Inliner::picPredict() {
00627   // check PICs for information
00628   const int bci = sender->bci();
00629   RScope* rscope = sender->rscope;
00630 
00631   if (!rscope->hasSubScopes(bci)) {
00632     // note: not fully implemented yet -- if no subScopes, should check to see
00633     // if send should be made unlikely (e.g. sends in prim. failure branches)
00634     // fix this
00635     return _info->rcvr;
00636   }
00637 
00638   // l is the list of receivers predicted by the PIC
00639   GrowableArray<RScope*>* l = sender->rscope->subScopes(sender->bci());
00640 
00641   // check special cases: never executed or uninlinable/megamorphic
00642   if (l->length() == 1) {
00643     if (l->first()->isUntakenScope()) { 
00644       // send was never executed
00645       return picPredictUnlikely(_info, (RUntakenScope*)l->first());
00646     } else if (l->first()->isUninlinableScope()) {
00647       if (CompilerDebug) 
00648         cout(PrintInlining)->print("%*s*PIC-predicting %s as uninlinable/megamorphic\n", depth, "", _info->sel->as_string());
00649       _info->uninlinable = true;        // prevent static type prediction
00650       return _info->rcvr;
00651     }
00652   } 
00653   
00654   // check special case: perfect information (from dataflow information)
00655   if (!_info->rcvr->containsUnknown()) {
00656     return _info->rcvr; // already know type exactly, don't use PIC
00657   }
00658 
00659   // extract klasses from PIC
00660   GrowableArray<Expr*> klasses(5);
00661   MergeExpr* allKlasses = new MergeExpr(_info->rcvr->preg(), NULL);
00662   for (int i = 0; i < l->length(); i++) {
00663     RScope* r = l->at(i);
00664     Expr* expr = r->receiverExpr(_info->rcvr->preg());
00665     if (expr->isUnknownExpr()) {
00666       // untaken real send (from PIC) (usually the "otherwise" branch of predicted sends)
00667       // since prediction was always correct, make sure unknown case is unlikely
00668       assert(((UnknownExpr*)expr)->isUnlikely(), "performance bug: should make unknown unlikely");
00669       continue;
00670     }
00671     klasses.append(expr);
00672     allKlasses = (MergeExpr*)allKlasses->mergeWith(expr, NULL);
00673   }
00674 
00675   // check if PIC info is better than static type info; discard all static info
00676   // that's not in the PIC
00677   int npic = klasses.length();
00678   int nstatic = _info->rcvr->nklasses();
00679   if (npic != 0 && _info->rcvr->isMergeExpr()) {
00680     Expr* newRcvr = _info->rcvr;
00681     for (int i = ((MergeExpr*)_info->rcvr)->exprs->length() - 1; i >= 0; i--) {
00682       Expr* e = ((MergeExpr*)_info->rcvr)->exprs->at(i);
00683       if (e->isUnknownExpr()) continue;
00684       if (!allKlasses->findKlass(e->klass())) {
00685         if (PrintInlining) {
00686           std->print("%*s*discarding static type info for send %s (not found in PIC): ", 
00687                      depth, "", _info->sel->as_string());
00688           e->print();
00689         }
00690         newRcvr = newRcvr->copyWithout(e);
00691       }
00692     }
00693     _info->rcvr = newRcvr;
00694   }
00695 
00696   if (CompilerDebug) 
00697     cout(PrintInlining)->print("%*s*PIC-type-predicting %s (%ld klasses): ", depth, "", 
00698                                 _info->sel->as_string(), npic);
00699 
00700   // iterate through PIC _info and add it to the receiver type (_info->rcvr)
00701   for (i = 0; i < klasses.length(); i++) {
00702     Expr* expr = klasses.at(i);
00703     // use the PIC information for this case
00704     if (CompilerDebug) {
00705 #ifndef PRODUCT // otherwise we get a syntax error (C++ compiler bug?) - gri 11/28/01
00706       expr->klass()->klass_part()->print_name_on(cout(PrintInlining));
00707       cout(PrintInlining)->print(" ");
00708 #endif
00709     }
00710     Expr* alreadyThere = _info->rcvr->findKlass(expr->klass());
00711     // add klass only if not already present (for splitting -- adding klass
00712     // expr with node == NULL destroys splitting opportunity)
00713     if (alreadyThere) {
00714       // generalize constant to klass
00715       if (alreadyThere->isConstantExpr()) {
00716         _info->rcvr = _info->rcvr->mergeWith(expr, NULL);
00717       }
00718     } else {
00719       _info->predicted = true;
00720       _info->rcvr = _info->rcvr->mergeWith(expr, NULL);
00721       if (expr->hasConstant() && klasses.length() == 1) {
00722         // check to see if single predicted receiver is true or false;
00723         // if so, add other boolean to prediction.  Reduces the number
00724         // of uncommon branches; not doing so appears to be overly
00725         // aggressive (as observed experimentally)
00726         oop c = expr->constant();
00727         PReg* p = _info->rcvr->preg();
00728         if (c == trueObj && !_info->rcvr->findKlass(falseObj->klass())) {
00729           Expr* f = new ConstantExpr(falseObj, p, NULL);
00730           _info->rcvr = _info->rcvr->mergeWith(f, NULL);
00731         } else if (c == falseObj && !_info->rcvr->findKlass(trueObj->klass())) {
00732           Expr* t = new ConstantExpr(trueObj, p, NULL);
00733           _info->rcvr = _info->rcvr->mergeWith(t, NULL);
00734         }
00735       }
00736     } 
00737   } // for
00738   if (CompilerDebug) cout(PrintInlining)->print("\n");
00739 
00740   // mark unknown branch as unlikely
00741   UnknownExpr* u = _info->rcvr->findUnknown();
00742   const bool canBeUnlikely = theCompiler->useUncommonTraps;
00743   if (u && canBeUnlikely && !rscope->isNotUncommonAt(bci)) {
00744     _info->rcvr = _info->rcvr->makeUnknownUnlikely(sender);
00745   }
00746      
00747   assert(_info->rcvr->preg(), "should have a preg");
00748   return _info->rcvr;
00749 }
00750 
00751 Expr* Inliner::picPredictUnlikely(SendInfo* info, RUntakenScope* uscope) {
00752   if (!theCompiler->useUncommonTraps) return info->rcvr;
00753   
00754   bool makeUncommon = uscope->isUnlikely();
00755   if (!makeUncommon && info->inPrimFailure) {
00756     // this send was never executed in the recompilee
00757     // only make the send unlikely if it had a chance to execute
00758     // (If the send isn't a prim failure, don't trust the info --
00759     // it's unlikely that the method just stops executing in the middle.
00760     // What probably happened is that recompilation occurred before the
00761     // rest of the method got a chance to execute (e.g. recursion), or it
00762     // always quit via NLR.  In any case, the compiler can't handle this
00763     // yet - need to treat it specially similar to endsDead.)
00764     makeUncommon = false;
00765   }
00766   if (false && CompilerDebug) {
00767     cout(PrintInlining)->print("%*s*%sPIC-type-predicting %s as never executed\n",
00768             depth, "", makeUncommon ? "" : "NOT ",
00769             info->sel->copy_null_terminated());
00770   }
00771   if (makeUncommon) {
00772     return new UnknownExpr(info->rcvr->preg(), NULL, true);
00773   } else {
00774     return info->rcvr;
00775   }
00776 }
00777 
00778 Expr* Inliner::typePredict() {
00779   // NB: all non-predicted cases exit this function early
00780   Expr* r = _info->rcvr;
00781   if (!(r->isUnknownExpr() ||
00782         r->isMergeExpr() && 
00783         ((MergeExpr*)r)->exprs->length() == 1 && 
00784         ((MergeExpr*)r)->exprs->at(0)->isUnknownExpr())) {
00785     // r already has a type (e.g. something predicted via PICs)
00786     // trust that information more than the static type prediction
00787     // NB: UnknownExprs are sometimes merged into a MergeExpr, that's why the above
00788     // test looks a bit more complicated
00789     return _info->rcvr;
00790   }
00791 
00792   // perform static type prediction
00793   if (InliningPolicy::isPredictedSmiSelector(_info->sel)) {
00794     r = r->mergeWith(new KlassExpr(smiKlassObj, r->preg(), NULL), NULL);
00795   } else if (InliningPolicy::isPredictedArraySelector(_info->sel)) {
00796     // don't know what to predict -- objArray? byteArray?
00797     if (TypePredictArrays) {
00798       r = r->mergeWith(new KlassExpr(Universe::objArrayKlassObj(), r->preg(), NULL), NULL);
00799     } else {
00800       return r;
00801     }
00802   } else if (InliningPolicy::isPredictedBoolSelector(_info->sel)) {
00803     r = r->mergeWith(new ConstantExpr(trueObj,  r->preg(), NULL), NULL);
00804     r = r->mergeWith(new ConstantExpr(falseObj, r->preg(), NULL), NULL);
00805   } else {
00806     return r;
00807   }
00808 
00809   // receiver was type-predicted
00810   if (theCompiler->useUncommonTraps) {
00811     // make unknon case unlikely
00812     r = r->makeUnknownUnlikely(sender);
00813   }
00814   return r;
00815 }
00816 
00817 extern bool SuperSendsAreAlwaysInlined = true;  // remove when removing super hack
00818 
00819 InlinedScope* Inliner::tryLookup(Expr* rcvr) {
00820   // try to lookup the send to receiver rcvr and determine if it should be inlined; 
00821   // return new InlinedScope if ok, NULL if lookup error or non-inlinable
00822   // NB: _info->rcvr is the overall receiver (e.g. a merge expr), rcvr is the particular branch
00823   // we're looking at right now
00824   assert(rcvr->hasKlass(), "should know klass");
00825 
00826   const klassOop  klass = (kind == SuperSend) ? sender->methodHolder() : rcvr->klass();
00827   if (klass == NULL) {
00828     _info->uninlinable = true;
00829     assert(kind == SuperSend, "shouldn't happen for normal sends");
00830     return notify("super send in Object");
00831   }
00832 
00833   const symbolOop selector = _info->sel;
00834   const methodOop method = (kind == SuperSend) ? 
00835         lookupCache::compile_time_super_lookup (klass, selector) : 
00836         lookupCache::compile_time_normal_lookup(klass, selector);
00837   lastLookupFailed = method == NULL;
00838 
00839   if (lastLookupFailed) {
00840     // nothing found statically (i.e., lookup error)
00841     _info->uninlinable = true;          // fix this -- probably wrong for merge exprs.
00842     return notify("lookup failed");
00843   } 
00844   
00845   // Construct a lookup key
00846   LookupKey* key = kind == SuperSend
00847                  ? LookupKey::allocate(rcvr->klass(), method)
00848                  : LookupKey::allocate(rcvr->klass(), selector);
00849 
00850   if (CompilerDebug) cout(PrintInlining)->print("%*s found %s --> %#x\n", sender->depth, "", key->print_string(), PrintHexAddresses ? method : 0);
00851 
00852   // NB: use rcvr->klass() (not klass) for the scope -- klass may be the method holder (for super sends)
00853   // was bug -- Urs 3/16/96
00854   InlinedScope* callee = makeScope(rcvr, rcvr->klass(), key, method);
00855   assert(kind != SuperSend || callee != NULL, "Super send must be inlined");
00856 
00857   _msg = inliningPolicy.shouldInline(sender, callee);
00858   if (kind == SuperSend) {
00859     // for now, always inline super sends because run-time system can't handle them yet
00860     // fix this later -- Urs 12/95
00861     SuperSendsAreAlwaysInlined = true;
00862     assert(!_info->predicted, "shouldn't PIC-predict super sends");
00863     _msg = NULL;
00864   } else {
00865     if (_msg == NULL && sender->gen()->in_prim_failure_block()) {
00866       _msg = checkSendInPrimFailure();
00867     }
00868   }
00869   if (_msg) return notify(_msg);                // shouldn't inline this call
00870 
00871   return callee;
00872 }
00873 
00874 char* Inliner::checkSendInPrimFailure() {
00875   // The current send could be inlined, but it is in a primitive failure block.  Decide
00876   // if it really should be inlined (return NULL if so, msg if not).
00877   RScope* rs = sender->rscope;
00878   if (rs->isNullScope() || rs->isInterpretedScope()) {
00879     // not compiled -- don't inline, failure probably never happens
00880     // but make sure we'll detect if it does happen often
00881     if (UseRecompilation) _info->counting = true;
00882     return "send in primitive failure (null/interpreted sender)";
00883   }
00884   RScope* callee = rs->subScope(sender->bci(), _info->key);
00885   if (callee->isUntakenScope()) {
00886     // never executed; shouldn't even generate code for failure!
00887     // (note: if failure block has several sends, this can happen, but in the standard
00888     // system it's probably a performance bug)
00889     if (WizardMode) warning("probably should have made primitive failure uncommon");
00890     return "untaken send in primitive failure";
00891   }
00892   if (callee->isInlinedScope()) {
00893     // was inlined in previous versions, so I guess it's ok to inline it again
00894     return NULL;
00895   }
00896   if (callee->isNullScope()) {
00897     // no info; conservative thing is not to inline
00898     return "untaken send in primitive failure (NullScope)";
00899   }
00900   // ok, inline this send
00901   return NULL;
00902 }
00903 
00904 RScope* Inliner::makeBlockRScope(const Expr* rcvr, LookupKey* key, const methodOop method) {
00905   // create an InlinedScope for this block method
00906   if (!TypeFeedback) return new RNullScope;
00907   if (!rcvr->preg()->isBlockPReg()) {
00908     return new RNullScope;        // block parent is in a different nmethod -- won't inline
00909   }
00910 
00911   // first check if block was inlined in previous nmethod (or comes from inlining database)
00912   const int senderBCI = sender->bci();
00913   GrowableArray<RScope*>* subScopes = sender->rscope->subScopes(senderBCI);
00914   if (subScopes->length() == 1 && subScopes->first()->method() == method) {
00915     RScope* rs = subScopes->first();
00916     assert(rs->method() == method, "mismatched block methods");
00917     return rs;
00918   }
00919 
00920   // must compute rscope differently -- primitiveValue has no inline cache, so must
00921   // get callee nmethod or method manually
00922   InlinedScope* parent = rcvr->preg()->scope();
00923   RScope* rparent = parent->rscope;
00924   const int level = rparent->isNullScope() ? 1 : ((RNonDummyScope*)rparent)->level();
00925   if (rparent->isCompiled()) {
00926     // get type feedback info from compiled block nmethod
00927     nmethod* parentNM = rparent->get_nmethod();
00928     // search for corresponding noninlined block nmethod
00929     int blockIndex = 0;
00930     for (blockIndex = parentNM->number_of_noninlined_blocks(); blockIndex >= 1; blockIndex--) {
00931       if (parentNM->noninlined_block_method_at(blockIndex) == method &&
00932           checkSenderPath(parent, parentNM->noninlined_block_scope_at(blockIndex)->parent())) {
00933         break;    // found it
00934       }
00935     }
00936     if (blockIndex >= 1) {
00937       // try to use non-inlined block nmethod (if it was compiled)
00938       jumpTableEntry* jte = parentNM->noninlined_block_jumpEntry_at(blockIndex);
00939       if (jte->is_nmethod_stub()) {
00940         // use non-inlined block nmethod
00941         nmethod* blockNM = jte->method();
00942         assert(blockNM->method() == method, "method mismatch");
00943         return new RInlinedScope(NULL, senderBCI, blockNM, blockNM->scopes()->root(), level);
00944       } else {
00945         // block nmethod hasn't been compiled yet -- use interpreted method
00946         return new RInterpretedScope(NULL, senderBCI, key, method, level, true);
00947       }
00948     } else {
00949       // block was inlined in previous nmethod, but not found in rscope
00950       assert(sender->rscope->isNullScope() || sender->rscope->isLite(), "should have found subscope");
00951       return new RInterpretedScope(NULL, senderBCI, key, method, level, true);
00952     }
00953   } else {
00954     // get info from interpreted block method
00955     return new RInterpretedScope(NULL, senderBCI, key, method, level, true);
00956   }
00957 }
00958 
00959 
00960 bool Inliner::checkSenderPath(Scope* here, ScopeDesc* there) const {
00961   // return true if sender paths of here and there match
00962   // NB: I believe the code below isn't totally correct, in the sense that it
00963   // will return ok == true if the sender paths match up to the point where
00964   // one path crosses an nmethod boundary -- but there could be a difference
00965   // further up.
00966   // However, this imprecision isn't dangerous -- we'll just use type information
00967   // that may not be accurate.  But since the sender paths agreed up to that
00968   // point, it is likely the types are at least similar.
00969   // Fix this later.  -Urs 8/96
00970   while (here && !there->isTop()) {
00971     InlinedScope* sen = here->sender();
00972     if (sen == NULL) break;
00973     if (sen->bci() != there->senderBCI()) return false;
00974     here  = here->sender();
00975     there = there->sender();
00976   }
00977   return true;
00978 }
00979 
00980 
00981 InlinedScope* Inliner::makeScope(const Expr* rcvr, const klassOop klass, const LookupKey* key, const methodOop method) {
00982   // create an InlinedScope for this method/receiver
00983   SendInfo* calleeInfo = new SendInfo(*_info);
00984   calleeInfo->key = (LookupKey*) key;
00985   const klassOop methodHolder = klass->klass_part()->lookup_method_holder_for(method);
00986   
00987   if (method->is_blockMethod()) {
00988     RScope* rs = makeBlockRScope(rcvr, calleeInfo->key, method);
00989 # ifdef ASSERT
00990     bool isNullRScope = rs->isNullScope();      // for conditional breakpoints (no type feedback info)
00991 # endif
00992     if (rcvr->preg()->isBlockPReg()) {
00993       InlinedScope* parent = rcvr->preg()->scope();
00994       calleeInfo->rcvr = parent->self();
00995       callee = BlockScope::new_BlockScope(method, methodHolder, parent, sender, rs, calleeInfo);
00996       callee->set_self(parent->self());
00997     } else {
00998       // block parent is in a different nmethod -- don't inline
00999       return notify("block parent in different nmethod");
01000     }
01001   } else {
01002     // normal method
01003     RScope* rs = sender->rscope->subScope(sender->bci(), calleeInfo->key);
01004 # ifdef ASSERT
01005     bool isNullRScope = rs->isNullScope();      // for conditional breakpoints (no type feedback info)
01006 # endif
01007     callee = MethodScope::new_MethodScope(method, methodHolder, sender, rs, calleeInfo);
01008     callee->set_self(rcvr->asReceiver());
01009   }
01010 
01011   return callee;
01012 }
01013 
01014 InlinedScope* Inliner::notify(const char* msg) {
01015   if (CompilerDebug) {
01016     cout(PrintInlining)->print("%*s*cannot inline %s, cost = %ld (%s)\n", depth, "", _info->sel->as_string(), 
01017                                     inliningPolicy.calleeCost, msg);
01018   }
01019   _msg = (char*)msg;
01020   return NULL;  // cheap trick to make notify more convenient (can say "return notify(...)")
01021 }
01022 
01023 void Inliner::print() {
01024   std->print("((Inliner*)%#x)\n", PrintHexAddresses ? this : 0);
01025 }
01026 
01027 Expr* Inliner::inlineBlockInvocation(SendInfo* info) {
01028   initialize(info, NormalSend);
01029   Expr* blockExpr = info->rcvr;
01030   assert(blockExpr->preg()->isBlockPReg(), "must be a BlockPR");
01031   const BlockPReg* block = (BlockPReg*)blockExpr->preg();
01032   const methodOop method = block->closure()->method();
01033   const InlinedScope* parent = block->closure()->parent_scope();
01034   // should decide here whether to actually inline -- fix this
01035   if (CompilerDebug) cout(PrintInlining)->print("%*s*inlining block invocation\n", sender->depth, "");
01036 
01037   // Construct a fake lookupKey
01038   LookupKey* key = LookupKey::allocate(parent->selfKlass(), method);
01039   
01040   makeScope(blockExpr, parent->selfKlass(), key, method);
01041   if (callee) {
01042     Expr* r = doInline(sender->current());
01043     return makeResult(r);
01044   } else {
01045     return NULL;        // couldn't inline the block
01046   }
01047 }
01048 
01049 # endif

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