scope.cpp

Go to the documentation of this file.
00001 /* Copyright 1994 - 1996, LongView Technologies L.L.C. $Revision: 1.118 $ */
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/_scope.cpp.incl"
00028 # include <string.h>
00029 
00030 smi Scope::_currentScopeID;
00031 
00032 // SendInfo implementation
00033 
00034 SendInfo::SendInfo(InlinedScope* sen, LookupKey* lkup, Expr* r) {
00035   senderScope = sen;
00036   rcvr = r; 
00037   sel = lkup->selector(); 
00038   key = lkup;
00039   init();
00040 }
00041 
00042 
00043 void SendInfo::computeNSends(RScope* rscope, int bci) {
00044   GrowableArray<RScope*>* lst = rscope->subScopes(bci);
00045   nsends = 0;
00046   for (int i = lst->length() - 1; i >= 0; i--) {
00047     nsends += lst->at(i)->nsends;
00048   }
00049 }
00050 
00051 void SendInfo::init() {
00052   resReg = NULL; needRealSend = counting = false; 
00053   nsends = -1; receiverStatic = predicted = uninlinable = false;
00054   inPrimFailure = senderScope && senderScope->gen()->in_prim_failure_block();
00055 }
00056 
00057 // Scopes
00058 // NB: constructors are protected to avoid stupid "call-of-virtual-in-constructor" bugs
00059 
00060 InlinedScope::InlinedScope() {}
00061 
00062 void InlinedScope::initialize(methodOop method, klassOop methodHolder, InlinedScope* sender, RScope* rs, SendInfo* info) {
00063   _scopeID              = currentScopeID();
00064   theCompiler->scopes->append(this);
00065   assert(theCompiler->scopes->at(_scopeID) == this, "bad list");
00066   _sender               = sender;
00067   _scopeInfo            = NULL;
00068   if (sender) {
00069     _senderBCI          = sender->bci();
00070     sender->addSubScope(this);
00071     depth               = _sender->depth + 1;
00072     loopDepth           = _sender->loopDepth;
00073   } else {
00074     _senderBCI          = IllegalBCI;
00075     depth = loopDepth   = 0;
00076   }
00077   result = nlrResult    = NULL; // these are set during compilation
00078   if (info && info->resReg) {
00079     resultPR            = info->resReg;
00080   } else {
00081     // potential bug: live range of resultPR is bogus
00082     assert(isTop(), "should have resReg for inlined scope");
00083     resultPR            = new SAPReg(this, resultLoc, false, false, PrologueBCI, EpilogueBCI);
00084   }
00085   rscope                = rs;
00086   rs->extend();
00087       
00088   predicted             = info ? info->predicted : false;
00089 
00090   assert(info->key->klass(), "must have klass");
00091   _key                  = info->key;    
00092   _method               = method;
00093   _methodHolder         = methodHolder; // NB: can be NULL if method is in Object
00094   _nofSends             = 0;
00095   _nofInterruptPoints   = 0;
00096   _primFailure          = sender ? sender->_primFailure : false;
00097   _endsDead             = false;
00098   _self                 = NULL;         // initialized by createTemps or by sender scope
00099   _gen.initialize(this);
00100 
00101   _temporaries          = NULL;         // allocated by createTemporaries
00102   _floatTemporaries     = NULL;         // allocated by createFloatTemporaries
00103   _contextTemporaries   = NULL;         // allocated by createContextTemporaries
00104   _context              = NULL;         // set for blocks and used/set by createContextTemporaries
00105   _exprStackElems       = new GrowableArray<Expr*>(nofBytes());
00106   _subScopes            = new GrowableArray<InlinedScope*>(5);
00107   _loops                = new GrowableArray<CompiledLoop*>(5);
00108   _typeTests            = new GrowableArray<NonTrivialNode*>(10);
00109 
00110   _pregsBegSorted       = new GrowableArray<PReg*>(5);
00111   _pregsEndSorted       = new GrowableArray<PReg*>(5);
00112   _firstFloatIndex      = -1;           // set during float allocation
00113   _hasBeenGenerated     = false;
00114 
00115   theCompiler->nofBytesCompiled(nofBytes());
00116   if (!rs->isNullScope() && rs->method() != method) {
00117     // wrong rscope (could happen after programming change)
00118     rs = new RNullScope;
00119   }
00120 }
00121 
00122 bool InlinedScope::isLite() const {
00123   // A scope is light (doesn't need its locals/expression stack described) if it has no interrupt
00124   // points, i.e., if the program can never stop while the PC is in this scope.
00125   // The top scope of an nmethod can't be light (at least the receiver is needed).
00126   return GenerateLiteScopeDescs && (sender() != NULL) && (_nofInterruptPoints == 0);
00127 }
00128 
00129 void MethodScope::initialize(methodOop method, klassOop methodHolder, InlinedScope* sen, RScope* rs, SendInfo* info) {
00130   InlinedScope::initialize(method, methodHolder, sen, rs, info);
00131 }
00132 
00133 
00134 MethodScope::MethodScope() {}
00135 BlockScope::BlockScope() {}
00136 
00137 
00138 void BlockScope::initialize(methodOop method, klassOop methodHolder, Scope* p, InlinedScope* s, RScope* rs, SendInfo* info) {
00139   InlinedScope::initialize(method, methodHolder, s, rs, info);
00140   _parent = p; 
00141   _self_is_initialized = false;
00142   if (s == NULL) {
00143     // top scope: create a context (currently always initialized for blocks)
00144     // (context is set up by the prologue node)
00145     _context = new SAPReg(this, PrologueBCI, EpilogueBCI);
00146   } else {
00147     // set up for context passed in by caller
00148     // (_context may be changed later if this scope allocates its own context)
00149     switch (method->block_info()) {
00150       case methodOopDesc::expects_nil:          // no context needed
00151         _context = NULL; break;
00152       case methodOopDesc::expects_self:
00153         _context = self()->preg(); fatal("self not known yet -- fix this"); break;
00154       case methodOopDesc::expects_parameter:    // fix this -- should find which
00155         Unimplemented();
00156         break;
00157       case methodOopDesc::expects_context:
00158         if (p->isInlinedScope()) {
00159           _context = ((InlinedScope*)p)->context(); 
00160         } else {
00161           fatal("shouldn't inline");    // shouldn't inline block unless parent was inlined, too
00162         }
00163         break;
00164       default:
00165         fatal("unexpected incoming info");
00166     }
00167   }
00168 }
00169 
00170 
00171 MethodScope* MethodScope::new_MethodScope(methodOop method, klassOop methodHolder, InlinedScope* sen, RScope* rs, SendInfo* info) {
00172   MethodScope* new_scope = new MethodScope;
00173   new_scope->initialize(method, methodHolder, sen, rs, info);
00174   new_scope->initializeArguments();
00175   return new_scope;
00176 }          
00177 
00178 
00179 BlockScope* BlockScope::new_BlockScope(methodOop method, klassOop methodHolder, Scope* p, InlinedScope* s, RScope* rs, SendInfo* info) {
00180   BlockScope* new_scope = new BlockScope;
00181   new_scope->initialize(method, methodHolder, p, s, rs, info);
00182   new_scope->initializeArguments();
00183   return new_scope;
00184 }          
00185 
00186 
00187 void InlinedScope::addSubScope(InlinedScope* s) {
00188   // assert(_subScopes->isEmpty() || _subScopes->last()->senderBCI() <= s->senderBCI(),
00189   //     "scopes not ordered by bci");
00190   // NB: subScopes are not in bci order when generating while loops -- condition is generated
00191   // first but has higher bcis than body.  Ugh.   -Urs 10/95
00192   _subScopes->append(s);
00193 }
00194 
00195 void InlinedScope::subScopesDo(Closure<InlinedScope*>* f) {
00196   f->do_it(this);
00197   _subScopes->apply(f);
00198 }
00199 
00200 MergeNode* InlinedScope::nlrTestPoint() {
00201   /* Generate code handling NLRs coming from below.
00202      There are several factors influencing what happens:
00203 
00204      1. NLR-Target:  A scope is a potential NLR target if the scope is a method scope and
00205         there is at least one block with a NLR in the scope.
00206         NLR targets must test the target of the current NLR and do a normal method return 
00207         if the NLR comes from one of their blocks.
00208         
00209      2. Context: does this scope have a context object?  If so, it must be zapped before
00210         going further (whether the scope was the NLR-target or not).
00211 
00212      3. Top scope:  If the scope is the top scope of an nmethod, it must continue with a
00213         MethodReturn or NLReturn rather than an InlinedMethodReturn/InlinedNLReturn.
00214 
00215      Unfortunately, at this point in the compilation we can't answer questions 1 and 2 yet,
00216      because we don't know yet which blocks (and context objects) have been optimized away.
00217      (We could know, if we kept track of things during the node generation.  However, even
00218      then we'd be wrong sometimes because some optimizations can eliminate blocks later.)
00219      On the other hand, we have to generate *something* here to correctly model the control
00220      flow.  Thus we insert a NLRTestNode now and defer the exact decision about what it
00221      does to the machine code generation phase.
00222   */
00223   if (!_nlrTestPoint) {
00224     int end_bci = nofBytes();
00225     // Note: src has incorrect def because it is implicitly assigned to via a call
00226     // (in sender scopes (when inlining), there will be an assignment when fixing up the connections).
00227     //SAPReg* src = new SAPReg(this, NLRResultLoc, false, true, end_bci, end_bci);
00228     //SAPReg* dst = new SAPReg(this, NLRResultLoc, false, false, end_bci, end_bci);
00229     _nlrTestPoint = NodeFactory::new_MergeNode(end_bci);
00230     _nlrTestPoint->append(NodeFactory::new_NLRTestNode(end_bci));
00231   }
00232   return _nlrTestPoint;
00233 }
00234 
00235 
00236 void InlinedScope::addResult(Expr* e) {
00237   // e is a possible return value; add it to our return expression to keep track of all possible return types
00238   assert(e->preg() == resultPR || resultPR == NULL || e->isNoResultExpr(), "bad result PReg");
00239   if (result == NULL) {
00240     result = e;
00241   } else {
00242     result = result->mergeWith(e, result->node());
00243   }
00244 }
00245 
00246 
00247 void InlinedScope::initializeArguments() {
00248   const int nofArgs = _method->number_of_arguments();
00249   _arguments = new GrowableArray<Expr*>(nofArgs, nofArgs, NULL);
00250   if (isTop()) {
00251     // create expr for self but do not allocate a location yet
00252     // (self is setup by the prologue node)
00253     _self =
00254       new KlassExpr(klassOop(selfKlass()),
00255                     new SAPReg(this, unAllocated, false, false, PrologueBCI, EpilogueBCI),
00256                     NULL);
00257     // preallocate incoming arguments, i.e., create their expressions
00258     // using SAPRegs that are already allocated
00259     for (int i = 0; i < nofArgs; i++) {
00260       SAPReg* arg = new SAPReg(this, Mapping::incomingArg(i, nofArgs), false, false, PrologueBCI, EpilogueBCI);
00261       _arguments->at_put(i, new UnknownExpr(arg));
00262     }
00263   } else {
00264     _self = NULL;       // will be initialized by sender
00265     // get args from sender's expression stack; top of expr stack = last arg, etc.
00266     const int top = sender()->exprStack()->length();
00267     for (int i = 0; i < nofArgs; i++) {
00268       _arguments->at_put(i, sender()->exprStack()->at(top - nofArgs + i));
00269     }
00270   }
00271 }
00272 
00273 
00274 void BlockScope::initializeSelf() {
00275   // for non-inlined top-level scope, make sure self is initialized
00276   // NB: bytecode compiler generates set_self_via_context, but only if self is needed in this
00277   // particular block and block expects a context (e.g., can have nested blocks with
00278   // set_self_via_context but not have one here).
00279   // Thus, load self in top-level block and ignore all nested set_self_via_context bytecodes.
00280   if (_parent->isInlinedScope() && method()->hasNestedBlocks()) {
00281     _gen.set_self_via_context();
00282   }
00283 }
00284 
00285 
00286 void InlinedScope::createTemporaries(int nofTemps) {
00287   // add nofTemps temporaries (may be called multiple times)
00288   int firstNew;
00289   if (!hasTemporaries()) {
00290     // first time we're called
00291     _temporaries = new GrowableArray<Expr*>(nofTemps, nofTemps, NULL);
00292     // The canonical model has the context in the first temporary.
00293     // To preserve this model the first temporary is aliased to _context.
00294     // Lars, 3/8/96
00295     if (_context) {
00296       _temporaries->at_put(0, new ContextExpr(_context));
00297       firstNew = 1;
00298     } else {
00299       firstNew = 0;
00300     }
00301  } else {
00302     // grow existing temp array
00303     const GrowableArray<Expr*>* oldTemps = _temporaries;
00304     const int n = nofTemps + oldTemps->length();
00305     _temporaries = new GrowableArray<Expr*>(n, n, NULL);
00306     firstNew = oldTemps->length();
00307     nofTemps += oldTemps->length();
00308     for (int i = 0; i < firstNew; i++) _temporaries->at_put(i, oldTemps->at(i));
00309   }
00310   // initialize new temps
00311  ConstPReg* nil = new_ConstPReg(this, nilObj);
00312   for (int i = firstNew; i < nofTemps; i++) {
00313     PReg* r = new PReg(this);
00314     _temporaries->at_put(i, new UnknownExpr(r, NULL));
00315     if (isTop()) {
00316       // temps are initialized by PrologueNode
00317     } else {
00318       gen()->append(NodeFactory::new_AssignNode(nil, r));
00319     }
00320   }
00321 }
00322 
00323 
00324 void InlinedScope::createFloatTemporaries(int nofFloats) {
00325   assert(!hasFloatTemporaries(), "cannot be called twice");
00326   _floatTemporaries = new GrowableArray<Expr*>(nofFloats, nofFloats, NULL);
00327   // initialize float temps
00328   for (int i = 0; i < nofFloats; i++) {
00329     PReg* preg = new PReg(this, Location::floatLocation(scopeID(), i), false, false);
00330     _floatTemporaries->at_put(i, new UnknownExpr(preg, NULL));
00331     if (isTop()) {
00332       // floats are initialized by PrologueNode
00333     } else {
00334       warning("float initialization of floats in inlined scopes not implemented yet");
00335     } 
00336   }
00337 }
00338 
00339 
00340 void InlinedScope::createContextTemporaries(int nofTemps) {
00341   // create _contextTemporaries and initialize all elements immediately;
00342   // after creation, some of the elements may be overwritten
00343   // (e.g., copying self or a method argument to the context)
00344   assert(_contextTemporaries == NULL, "more than one context created");
00345   assert(allocatesInterpretedContext(), "inconsistent context info");
00346   _contextTemporaries = new GrowableArray<Expr*>(nofTemps, nofTemps, NULL);
00347   for (int i = 0; i < nofTemps; i++) {
00348     PReg* r = new PReg(this);
00349     _contextTemporaries->at_put(i, new UnknownExpr(r, NULL));
00350   }
00351   // create context if not there yet
00352   if (_context == NULL) {
00353     // assert(isMethodScope(), "BlockScope should have correct context already");
00354     // replaced old assertion with the one below. Since assert disappears in the
00355     // fast version, put in a warning so that we can look at this if it happens
00356     // again (couldn't re-create the situation yet) - gri 5/10/96
00357     assert(isMethodScope() || isBlockScope() && method()->block_info() == methodOopDesc::expects_nil, "check this");
00358     //if (isBlockScope()) warning("possibly a bug in InlinedScope::createContextTemporaries - tell Robert");
00359     _context = new SAPReg(this, PrologueBCI, EpilogueBCI);
00360   }
00361   // The canonical model has the context in the first temporary.
00362   // To preserve this model the first temporary is aliased to _context.
00363   // Lars, 10/9/95
00364   _temporaries->at_put(0, new ContextExpr(_context));
00365 }
00366 
00367 void InlinedScope::contextTemporariesAtPut(int no, Expr* e) { 
00368   assert(!e->preg()->isSAPReg() || e->preg()->isBlockPReg() || ((SAPReg*)e->preg())->isInContext(), "not in context");
00369   _contextTemporaries->at_put(no, e); 
00370 }
00371 
00372 
00373 bool InlinedScope::allocatesCompiledContext() const {
00374   if (!allocatesInterpretedContext()) return false;
00375   ContextCreateNode* c = _contextInitializer->creator();
00376   if (bbIterator->usesBuilt && c->deleted) {
00377     // logically has a context, but it has been optimized away
00378     return false;
00379   } else {
00380     return true;
00381   }
00382 }
00383 
00384 
00385 void InlinedScope::prologue() {
00386   theCompiler->enterScope(this);
00387   initializeSelf();
00388 }
00389 
00390 
00391 static int compare_scopeBCIs(InlinedScope** a, InlinedScope** b) {
00392   // put unused scopes at the end so they can be deleted 
00393   if ((*a)->hasBeenGenerated() == (*b)->hasBeenGenerated()) {
00394     return (*a)->senderBCI() - (*b)->senderBCI();
00395   } else {
00396     return (*a)->hasBeenGenerated() ? -1 : 1;
00397   }
00398 }
00399 
00400 
00401 void InlinedScope::epilogue() {
00402   // generate epilogue code (i.e., everything after last byte code has been processed)
00403   assert(exprStack()->isEmpty(), "expr. stack should be empty now");
00404 
00405   // first make sure subScopes are sorted by bci
00406   _subScopes->sort(compare_scopeBCIs);
00407 
00408   // now remove all subscopes that were created but not used (not inlined)
00409   while (! _subScopes->isEmpty() && !_subScopes->last()->hasBeenGenerated()) _subScopes->pop();
00410 #ifdef ASSERT
00411   for (int i = 0; i < _subScopes->length(); i++) {
00412     if (!_subScopes->at(i)->hasBeenGenerated()) fatal("unused scopes should be at end");
00413   }
00414 #endif
00415 
00416   if (_nofSends > 0 && containsNLR()) {
00417     // this scope *could* be the target of a non-inlined NLR; add an UnknownExpr to
00418     // the scope's result expression to account for this possibility
00419     // note: to be sure, we'd have to know that at least one nested block wasn't inlined,
00420     // but this analysis isn't performed until later
00421     addResult(new UnknownExpr(resultPR, NULL));
00422     // also make sure we have an NLR test point to catch the NLR
00423     (void)nlrTestPoint();
00424     assert(has_nlrTestPoint(), "should have a NLR test point now");
00425   }
00426 
00427   // generate NLR code if needed
00428   if (has_nlrTestPoint()) {
00429     // NB: assertion below is too strict -- may have an nlr node that will be connected
00430     // only during fixupNLRPoints()
00431     // assert(nlrTestPoint()->nPredecessors() > 0, "nlr node is unused??");
00432   } else if (isTop() && theCompiler->nlrTestPoints->nonEmpty()) {
00433     // the top scope doesn't have an NLR point, but needs one anyway so that inlined
00434     // scopes have somewhere to jump to
00435     (void)nlrTestPoint();
00436   }
00437   if (!result) result = new NoResultExpr;
00438   theCompiler->exitScope(this);
00439 }
00440 
00441 
00442 bool InlinedScope::isSenderOf(InlinedScope* callee) const {
00443   assert(callee, "should have a scope");
00444   if (depth > callee->depth) return false;
00445   int d = callee->depth - 1;
00446   for (InlinedScope* s = callee->sender(); s && d >= depth; s = s->sender(), d--) {
00447     if (this == s) return true;
00448   }
00449   return false;
00450 }
00451 
00452 
00453 void InlinedScope::addSend(GrowableArray<PReg*>* expStk, bool isSend) {
00454   // add send or prim. call / uncommon branch to this scope and mark locals as debug-visible
00455   if (!expStk) return;                  // not an exposing send
00456   for (InlinedScope* s = this; s && s->isInlinedScope(); s = s->sender()) {
00457     if (isSend) s->_nofSends++;
00458     s->_nofInterruptPoints++;
00459     s->markLocalsDebugVisible(expStk);  // mark locals as debug-visible
00460   }
00461 }
00462 
00463 
00464 void InlinedScope::markLocalsDebugVisible(GrowableArray<PReg*>* exprStack) {
00465   // this scope has at least one send - mark params & locals as debug-visible
00466   int i;
00467   if (_nofSends <= 1) {
00468     // first time we're called
00469     self()->preg()->debug = true;
00470     for (i = nofArguments() - 1; i >= 0; i--) {
00471       argument(i)->preg()->debug = true;
00472     }
00473     for (i = nofTemporaries() - 1; i >= 0; i--) {
00474       temporary(i)->preg()->debug = true;
00475     }
00476     // if there's a context, mark all context variables as debug-visible too.
00477     GrowableArray<Expr*>*  ct = contextTemporaries();
00478     if (ct != NULL) {
00479       for (i = 0; i < ct->length(); i++) {
00480         ct->at(i)->preg()->debug = true;
00481       }
00482     }
00483   }
00484   // also mark expression stack as debug-visible (excluding arguments to
00485   // current send) (the args are already excluded from the CallNode's
00486   // expression stack, so just use that one instead of this->exprStack)
00487   for (i = 0; i < exprStack->length(); i++) {
00488     exprStack->at(i)->debug = true;
00489   }
00490 }
00491 
00492 
00493 void InlinedScope::setExprForBCI(int bci, Expr* expr) {
00494   assert(_exprStackElems->at_grow(bci) == NULL, "only one expr per BCI allowed");
00495   _exprStackElems->at_put_grow(bci, expr);
00496 }
00497 
00498 
00499 void InlinedScope::set2ndExprForBCI(int bci, Expr* expr) {
00500   _exprStackElems->at_put_grow(bci, expr);
00501 }
00502 
00503 
00504 void InlinedScope::set_self(Expr* e) { 
00505   assert(!_self, "self already set"); 
00506   assert(e->scope()->isSenderOrSame(this), "must be in sender scope");
00507   _self = e; 
00508 }
00509 
00510 
00511 int InlinedScope::homeContext() const {
00512   // count the number of logical (i.e. interpreter) contexts from here up to the home method
00513   // contexts are numbered starting with zero and there is at least one context
00514   int context = -1;
00515   methodOop method = _method;
00516   while (method != NULL) {
00517     if (method->allocatesInterpretedContext()) { context++; }
00518     method = method->parent();
00519   }
00520   assert(context >= 0, "there must be at least one context");
00521   return context;
00522 }
00523 
00524 
00525 InlinedScope* InlinedScope::find_scope(int c, int& nofIndirections, OutlinedScope*& out) {
00526   // return the InlinedScope that contains context c
00527   // IN : context no. c for this scope (in interpreter terms)
00528   // OUT: number of indirections required at run time (-1 = in same stack frame, 
00529   //      0 = in context of this frame, 1 = in parent context of this frame's context, etc.)
00530   // if the inlined scope is found (nofIndirections = -1) it is returned as the result
00531   // if the inlined scope is not found (nofIndirections >= 0), the highest possible scope
00532   // is returned and out is set to the outlined scope containing the context
00533   assert(c >= 0, "context must be >= 0");
00534   int distance = _method->lexicalDistance(c);
00535   nofIndirections = -1;
00536   Scope*        s = this;
00537   out = NULL;
00538   // first, go up as far as possible
00539   for (int d = distance; d > 0 && s->parent()->isInlinedScope(); d--, s = s->parent()) ; 
00540   if (d == 0) {
00541     // found scope in our nmethod
00542     return (InlinedScope*)s;
00543   }
00544 
00545   // InlinedScope not found; go up the rest of the scopes and count how many 
00546   // stack frames are traversed
00547   InlinedScope* top = (InlinedScope*)s;
00548   if (top->allocatesCompiledContext()) nofIndirections++;
00549   Scope* prev = s;
00550   for (s = s->parent(); d > 0; d--, prev = s, s = s->parent()) {
00551     if (s->allocatesCompiledContext()) nofIndirections++;
00552   }
00553   assert(prev->isOutlinedScope(), "must be outlined scope");
00554   out = (OutlinedScope*)prev;
00555   assert(nofIndirections >= 0, "must have at least one context access");
00556   return top;
00557 }
00558 
00559 
00560 void InlinedScope::collectContextInfo(GrowableArray<InlinedScope*>* contextList) {
00561   // collect all scopes with contexts
00562   if (allocatesInterpretedContext()) contextList->append(this);
00563   for (int i = _subScopes->length() - 1; i >= 0; i--) {
00564     _subScopes->at(i)->collectContextInfo(contextList);
00565   }
00566 }
00567 
00568 
00569 int InlinedScope::number_of_noninlined_blocks() {
00570   // return the number of non-inlined blocks in this scope or its callees
00571   int nblocks = 0;
00572   for (int i = bbIterator->exposedBlks->length() - 1; i >= 0; i--) {
00573     BlockPReg* blk = bbIterator->exposedBlks->at(i);
00574     if (blk->isUsed() && isSenderOrSame(blk->scope())) nblocks++;
00575   }
00576   return nblocks;
00577 }
00578 
00579 
00580 void InlinedScope::generateDebugInfoForNonInlinedBlocks() {
00581   for (int i = bbIterator->exposedBlks->length() - 1; i >= 0; i--) {
00582     BlockPReg* blk = bbIterator->exposedBlks->at(i);
00583     if (blk->isUsed()) blk->closure()->generateDebugInfo();
00584   }
00585 }
00586 
00587 
00588 void InlinedScope::copy_noninlined_block_info(nmethod* nm) {
00589   for (int i = bbIterator->exposedBlks->length() - 1; i >= 0; i--) {
00590     BlockPReg* blk = bbIterator->exposedBlks->at(i);
00591     if (blk->isUsed()) {
00592       int offset = theCompiler->scopeDescRecorder()->
00593                      offset_for_noninlined_scope_node(blk->closure()->noninlined_block_scope());
00594       nm->noninlined_block_at_put(blk->closure()->id().minor(), offset);
00595     }
00596   }
00597 }
00598 
00599 
00600 // loop optimizations
00601 
00602 void InlinedScope::addTypeTest(NonTrivialNode* t) {
00603   assert(t->doesTypeTests(), "shouldn't add");
00604   _typeTests->append(t);
00605 }
00606 
00607 CompiledLoop* InlinedScope::addLoop() {
00608   CompiledLoop* l = new CompiledLoop;
00609   _loops->append(l);
00610   return l;
00611 }
00612 
00613 void InlinedScope::optimizeLoops() {
00614   for (int i = _loops->length() - 1; i >= 0; i--) {
00615     CompiledLoop* loop = _loops->at(i);
00616     char* msg = loop->recognize();
00617     if (msg) {
00618       cout(PrintLoopOpts)->print("*loop %d in scope %s not an integer loop: %s\n", i, key()->print_string(), msg);
00619     } else {
00620       cout(PrintLoopOpts)->print("*optimizing integer loop %d in scope %s\n", i, key()->print_string());
00621       loop->optimizeIntegerLoop();
00622     }
00623     if (OptimizeLoops) loop->optimize();
00624   }
00625   for (i = _subScopes->length() - 1; i >= 0; i--) {
00626     _subScopes->at(i)->optimizeLoops();
00627   }
00628 }
00629 
00630 
00631 
00632 // register allocation
00633 
00634 void InlinedScope::addToPRegsBegSorted(PReg* r) {
00635   assert(PrologueBCI <= r->begBCI() && r->begBCI() <= EpilogueBCI, "illegal bci");
00636   assert(_pregsBegSorted->isEmpty() || _pregsBegSorted->last()->begBCI() <= r->begBCI(), "sort order wrong");
00637   _pregsBegSorted->append(r);
00638 }
00639 
00640 
00641 void InlinedScope::addToPRegsEndSorted(PReg* r) {
00642   assert(PrologueBCI <= r->endBCI() && r->endBCI() <= EpilogueBCI, "illegal bci");
00643   assert(_pregsEndSorted->isEmpty() || _pregsEndSorted->last()->endBCI() <= r->endBCI(), "sort order wrong");
00644   _pregsEndSorted->append(r);
00645 }
00646 
00647 
00648 void InlinedScope::allocatePRegs(IntFreeList* f) {
00649   int bci  = PrologueBCI;
00650   int bi   = 0;
00651   int si   = 0;
00652   int ei   = 0;
00653   int blen = _pregsBegSorted->length();
00654   int slen = _subScopes->length();
00655   int elen = _pregsEndSorted->length();
00656   int n    = f->allocated();
00657   assert(blen == elen, "should be the same");
00658   while (bci <= EpilogueBCI) {
00659     // allocate registers that begin at bci
00660     while (bi < blen && _pregsBegSorted->at(bi)->begBCI() == bci) {
00661       _pregsBegSorted->at(bi)->allocateTo(Mapping::localTemporary(f->allocate()));
00662       bi++;
00663       assert(bi == blen || 
00664              _pregsBegSorted->at(bi)->begBCI() >= _pregsBegSorted->at(bi-1)->begBCI(),
00665              "_pregsBegSorted not sorted");
00666     }
00667     // allocate registers for subscopes that begin at bci
00668     while (si < slen && _subScopes->at(si)->senderBCI() == bci) {
00669       _subScopes->at(si)->allocatePRegs(f);
00670       si++;
00671       assert(si == slen || 
00672              _subScopes->at(si)->senderBCI() >= _subScopes->at(si-1)->senderBCI(),
00673              "_subScopes not sorted");
00674     }
00675     // release registers that end at bci
00676     while (ei < elen && _pregsEndSorted->at(ei)->endBCI() == bci) {
00677       f->release(Mapping::localTemporaryIndex(_pregsEndSorted->at(ei)->loc));
00678       ei++;
00679       assert(ei == elen || 
00680              _pregsEndSorted->at(ei)->endBCI() >= _pregsEndSorted->at(ei-1)->endBCI(),
00681              "_pregsEndSorted not sorted");
00682     }
00683     // advance bci
00684     bci = min(bi < blen ? _pregsBegSorted->at(bi)->begBCI() : EpilogueBCI + 1,
00685               si < slen ? _subScopes->at(si)->senderBCI()   : EpilogueBCI + 1,
00686               ei < elen ? _pregsEndSorted->at(ei)->endBCI() : EpilogueBCI + 1);
00687   }
00688   assert(f->allocated() == n, "inconsistent allocation/release");
00689 }
00690 
00691 
00692 int InlinedScope::allocateFloatTemporaries(int firstFloatIndex) {
00693   assert(firstFloatIndex >= 0, "illegal firstFloatIndex");
00694   _firstFloatIndex = firstFloatIndex;                           // start index for first float of this scope
00695   int nofFloatTemps = hasFloatTemporaries() ? nofFloatTemporaries() : 0;
00696   // convert floatLocs into stackLocs
00697   for (int k = 0; k < nofFloatTemps; k++) {
00698     PReg* preg = floatTemporary(k)->preg();
00699     Location loc = preg->loc;
00700     assert(loc.scopeNo() == scopeID() && loc.floatNo() == k, "inconsistency");
00701     preg->loc = Mapping::floatTemporary(scopeID(), k);
00702     assert(preg->loc.isStackLocation(), "must be a stack location");
00703   }
00704   int startFloatIndex = firstFloatIndex + nofFloatTemps;        // start index for first float in subscopes
00705   int totalNofFloatsInSubscopes = 0;
00706   // allocate float temporaries of subscopes
00707   int len = _subScopes->length();
00708   for (int i = 0; i < len; i++) {
00709     InlinedScope* scope = _subScopes->at(i);
00710     totalNofFloatsInSubscopes = max(totalNofFloatsInSubscopes, scope->allocateFloatTemporaries(startFloatIndex));
00711   }
00712   return nofFloatTemps + totalNofFloatsInSubscopes;
00713 }
00714 
00715 
00716 bool MethodScope::isRecursiveCall(methodOop method, klassOop rcvrKlass, int depth) {
00717   // test is method/rcvrKlass would be a recursive invocation of this scope
00718   if (method == _method && rcvrKlass == selfKlass()) {
00719     if (depth <= 1) {
00720       return true;      // terminate recursion here
00721     } else {
00722       // it's recursive, but the unrolling depth hasn't been reached yet
00723       depth--;
00724     }
00725   }
00726   // check sender
00727   if (isTop()) {
00728     return false;
00729   } else {
00730     return sender()->isRecursiveCall(method, rcvrKlass, depth);
00731   }
00732 }
00733 
00734 
00735 bool BlockScope::isRecursiveCall(methodOop method, klassOop rcvrKlass, int depth) {
00736   if (method == _method) {
00737     if (depth <= 1) {
00738       return true;      // terminate recursion here
00739     } else {
00740       // it's recursive, but the unrolling depth hasn't been reached yet
00741       // NB: don't just fall through to parent check below because of
00742       // x := [ x value ]. x value
00743       return sender()->isRecursiveCall(method, rcvrKlass, --depth);
00744     }
00745   }
00746   // don't check sender, only check parent and it's senders
00747   // otherwise, in code like [ x foo. y do: [ z foo ]] the z foo send
00748   // would be considered a recursive invocation of x foo if x class = z class
00749   if (parent()->isOutlinedScope()) {
00750     return false;
00751   } else {
00752     return parent()->isRecursiveCall(method, rcvrKlass, depth);
00753   }
00754 }
00755 
00756 
00757 void InlinedScope::genCode() {
00758   _hasBeenGenerated = true;
00759   prologue();
00760   // always generate (shared) entry points for ordinary & non-local return
00761   _returnPoint        = NodeFactory::new_MergeNode(EpilogueBCI);
00762   _NLReturnPoint      = NodeFactory::new_MergeNode(EpilogueBCI);
00763   _nlrTestPoint       = NULL;
00764   _contextInitializer = NULL;
00765   int nofTemps = method()->number_of_stack_temporaries();
00766   if (isTop()) {
00767     _returnPoint->append(NodeFactory::new_ReturnNode(resultPR, EpilogueBCI));
00768     _NLReturnPoint->append(NodeFactory::new_NLRSetupNode(resultPR, EpilogueBCI));
00769     Node* first = NodeFactory::new_PrologueNode(key(), nofArguments(), nofTemps);
00770     theCompiler->firstNode = first;
00771     gen()->setCurrent(first);
00772   }
00773   // allocate space for temporaries - initialization done in the prologue code
00774   assert(!hasTemporaries(), "should have no temporaries yet\n");
00775   createTemporaries(nofTemps);
00776   // allocate space for float temporaries
00777   int nofFloats = method()->total_number_of_floats();
00778   if (UseFPUStack) {
00779     const int FPUStackSize = 8;
00780     if (method()->float_expression_stack_size() <= FPUStackSize) {
00781       // float expression stack fits in FPU stack, use it instead
00782       // and allocate only space for the real float temporaries
00783       nofFloats = method()->number_of_float_temporaries();
00784     } else {
00785       warning("possible performance bug: cannot use FPU stack for float expressions");
00786     }
00787   }
00788   createFloatTemporaries(nofFloats);
00789   // build the intermediate representation
00790   assert(gen()->current() != NULL, "current() should have been set before");
00791   MethodIterator iter(method(), gen());
00792   if (gen()->aborting()) {
00793     // ends with dead code -- clean up expression stack
00794     while (!exprStack()->isEmpty()) exprStack()->pop();
00795   }
00796   epilogue();
00797 }
00798 
00799 
00800 // debugging info
00801 
00802 void InlinedScope::generateDebugInfo() {
00803   // Generate debug info for the common parts of methods and blocks
00804 
00805   if (PrintDebugInfoGeneration) {
00806     if (isMethodScope()) {
00807       std->print_cr("self: %s", _self->preg()->name());
00808     } else {
00809       std->print_cr("no receiver (block method)");
00810     }
00811   }
00812 
00813   ScopeDescRecorder* rec = theCompiler->scopeDescRecorder();
00814   int len, i;
00815 
00816   if (!isLite()) {
00817     // temporaries
00818     if (hasTemporaries()) {
00819       len = _temporaries->length();
00820       for (i = 0; i < len; i++) {
00821         PReg* preg = _temporaries->at(i)->preg();
00822         rec->addTemporary(_scopeInfo, i, preg->createLogicalAddress());
00823         if (PrintDebugInfoGeneration) std->print_cr("temp[%2d]: %s", i, preg->name());
00824       }
00825     }
00826     // float temporaries
00827     if (hasFloatTemporaries()) {
00828       len = _floatTemporaries->length();
00829       for (i = 0; i < len; i++) {
00830         PReg* preg = _floatTemporaries->at(i)->preg();
00831         rec->addTemporary(_scopeInfo, i, preg->createLogicalAddress());
00832         if (PrintDebugInfoGeneration) std->print_cr("float[%2d]: %s", i, preg->name());
00833       }
00834     }
00835     // context temporaries
00836     if (allocatesInterpretedContext()) {
00837       len = _contextTemporaries->length();
00838       for (i = 0; i < len; i++) {
00839         PReg* preg = _contextTemporaries->at(i)->preg();
00840         rec->addContextTemporary(_scopeInfo, i, preg->createLogicalAddress());
00841         if (PrintDebugInfoGeneration) std->print_cr("c_temp[%2d]: %s", i, preg->name());
00842       }
00843     }
00844     // expr stack
00845     len = _exprStackElems->length();
00846     for (i = 0; i < len; i++) {
00847       Expr* elem = _exprStackElems->at(i);
00848       if (elem != NULL) {
00849         PReg* r = elem->preg()->cpReg();
00850         if (r->scope()->isSenderOrSame(this)) {
00851           // Note: Is it still needed to create this info here, since the
00852           //       PReg locations may change over time and thus produce more
00853           //       debug info than actually needed for the new backend. Discuss
00854           //       this with Lars.
00855           rec->addExprStack(_scopeInfo, i, r->createLogicalAddress());
00856           if (PrintDebugInfoGeneration) std->print_cr("expr[%2d]: %s", i, r->name());
00857         } else {
00858           // r's scope is too low (i.e. it's not actually live anymore)
00859           // this can only happen if the expression is discarded; thus it's safe not to describe this entry
00860           // Urs 5/96
00861           // fix this: should check that bci (i) is statement end (or r is NoPReg)
00862         }
00863       }
00864     }
00865   }
00866 
00867   // subscopes
00868   len = _subScopes->length();
00869   for (i = 0; i < len; i++) {
00870     InlinedScope* s = _subScopes->at(i);
00871     if (PrintDebugInfoGeneration) std->print_cr("Subscope %d (id = %d):", i, s->scopeID());
00872     s->generateDebugInfo();
00873   }
00874 }
00875 
00876 
00877 void MethodScope::generateDebugInfo() {
00878   ScopeDescRecorder* rec = theCompiler->scopeDescRecorder();
00879   const bool visible = true;
00880   _scopeInfo =
00881     rec->addMethodScope(
00882       _key,
00883       _method,
00884       _self->preg()->createLogicalAddress(),
00885       allocatesCompiledContext(),
00886       isLite(), 
00887       _scopeID,
00888       _sender ? _sender->scopeInfo() : NULL,
00889       _senderBCI,
00890       visible
00891     );
00892   InlinedScope::generateDebugInfo();
00893 }
00894 
00895 
00896 void BlockScope::generateDebugInfo() {
00897   ScopeDescRecorder* rec = theCompiler->scopeDescRecorder();
00898   if (_parent->isOutlinedScope()) {
00899     _scopeInfo =
00900       rec->addTopLevelBlockScope(
00901         _method,
00902         _self->preg()->createLogicalAddress(),
00903         _self->klass(),
00904         allocatesCompiledContext()
00905       );
00906   } else {
00907     assert(_parent->isInlinedScope(), "oops");
00908     const bool visible = true;
00909     _scopeInfo =
00910       rec->addBlockScope(
00911         _method,
00912         ((InlinedScope*)_parent)->scopeInfo(),
00913         allocatesCompiledContext(),
00914         isLite(),
00915         _scopeID,
00916         _sender->scopeInfo(),
00917         _senderBCI,
00918         visible
00919       );
00920   }
00921   InlinedScope::generateDebugInfo();
00922 }
00923 
00924 
00925 // Outlined scopes
00926 
00927 OutlinedScope* new_OutlinedScope(nmethod* nm, ScopeDesc* sc) {
00928   if (sc->isMethodScope()) {
00929     return new OutlinedMethodScope(nm, sc);
00930   } else {
00931     return new OutlinedBlockScope(nm, sc);
00932   }
00933 }
00934 
00935 
00936 OutlinedScope::OutlinedScope(nmethod* nm, ScopeDesc* scope) {
00937   _nm = nm;
00938   _scope = scope;
00939 }
00940 
00941 
00942 OutlinedBlockScope::OutlinedBlockScope(nmethod* nm, ScopeDesc* sc) : OutlinedScope(nm, sc) {
00943   ScopeDesc* parent = sc->parent(true);
00944   if (parent) {
00945     _parent = new_OutlinedScope(nm, parent);
00946   } else {
00947     _parent = NULL;
00948   }
00949 }
00950 
00951 
00952 Expr* OutlinedScope::receiverExpr(PReg* p) const { return _scope->selfExpr(p); }
00953 methodOop OutlinedScope::method() const { return _scope->method(); }
00954 klassOop OutlinedMethodScope::methodHolder() const { 
00955   return selfKlass()->klass_part()->lookup_method_holder_for(method()); 
00956 }
00957 
00958 
00959 // printing code
00960 
00961 void SendInfo::print() {
00962   lprintf("SendInfo %#lx \"", this);
00963   sel->print_symbol_on();
00964   lprintf("\" (rcvr = %#lx, nsends = %ld)\n", rcvr, nsends);
00965 }
00966 
00967 
00968 void InlinedScope::printTree() {
00969   print();
00970   for (int i = 0; i < _subScopes->length(); i++) {
00971     _subScopes->at(i)->printTree();
00972   }
00973 }
00974 
00975 void InlinedScope::print() {
00976   lprintf(" method: %#lx\n\tid: %ld", method(), scopeID());
00977   lprintf("\nself:   ");
00978   self()->print();
00979   for (int i = 0; i < nofArguments(); i++) {
00980     lprintf("arg %2d: ", i);
00981     argument(i)->print();
00982   }
00983   lprintf("\n");
00984 }
00985 
00986 
00987 void MethodScope::print_short() {
00988   lprintf("(MethodScope*)%#lx (", this); selector()->print_symbol_on(); lprintf(")");
00989 }
00990 
00991 
00992 void MethodScope::print() {
00993   print_short();
00994   InlinedScope::print();
00995   if (sender()) { lprintf("  sender: "); sender()->print_short(); }
00996   lprintf(" @ %ld\n", senderBCI());
00997   method()->pretty_print();
00998 }
00999 
01000 
01001 void BlockScope::print() {
01002   print_short();
01003   InlinedScope::print();
01004   if (parent()) { printf("\tparent: ");  parent()->print_short(); }
01005   if (sender()) { lprintf("  sender: "); sender()->print_short(); }
01006   lprintf(" @ %ld\n", senderBCI());
01007   method()->pretty_print();
01008 }
01009 
01010 
01011 void BlockScope::print_short() {
01012   lprintf("(BlockScope*)%#lx (", this); selector()->print_symbol_on(); 
01013   lprintf(" %#lx)", method());
01014 }
01015 
01016 
01017 void OutlinedScope::print_short(char* name) {
01018   lprintf("(%s*)%#lx (", name, this); 
01019   _scope->selector()->print_symbol_on();
01020   lprintf(")");
01021 }
01022 
01023 
01024 void OutlinedScope::print(char* name) {
01025   print_short(name);
01026   lprintf("  _nm = %#lx, _scope = %#lx", _nm, _scope);
01027 }
01028 
01029 
01030 void OutlinedMethodScope::print_short() { OutlinedScope::print_short("OutlinedMethodScope"); }
01031 void OutlinedMethodScope::print() { OutlinedScope::print("OutlinedMethodScope"); }
01032 
01033 void OutlinedBlockScope::print() {
01034   OutlinedScope::print("OutlinedMethodScope");
01035   if (parent()) { lprintf("\n    parent: "); parent()->print_short(); }
01036   lprintf("\n");
01037 }
01038 
01039 void OutlinedBlockScope::print_short() { OutlinedScope::print_short("OutlinedMethodScope"); }
01040 
01041 # endif

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