InlinedScope* InlinedScope::find_scope(int c, int& nofIndirections, OutlinedScope*& out) { // return the InlinedScope that contains context c // IN : context no. c for this scope (in interpreter terms) // OUT: number of indirections required at run time (-1 = in same stack frame, // 0 = in context of this frame, 1 = in parent context of this frame's context, etc.) // if the inlined scope is found (nofIndirections = -1) it is returned as the result // if the inlined scope is not found (nofIndirections >= 0), the highest possible scope // is returned and out is set to the outlined scope containing the context assert(c >= 0, "context must be >= 0"); int distance = _method->lexicalDistance(c); nofIndirections = -1; Scope* s = this; out = NULL; // first, go up as far as possible for (int d = distance; d > 0 && s->parent()->isInlinedScope(); d--, s = s->parent()) ; if (d == 0) { // found scope in our nmethod return (InlinedScope*)s; } // InlinedScope not found; go up the rest of the scopes and count how many // stack frames are traversed InlinedScope* top = (InlinedScope*)s; if (top->allocatesCompiledContext()) nofIndirections++; Scope* prev = s; for (s = s->parent(); d > 0; d--, prev = s, s = s->parent()) { if (s->allocatesCompiledContext()) nofIndirections++; } assert(prev->isOutlinedScope(), "must be outlined scope"); out = (OutlinedScope*)prev; assert(nofIndirections >= 0, "must have at least one context access"); return top; }
void InlinedScope::addSend(GrowableArray<PReg*>* expStk, bool isSend) { // add send or prim. call / uncommon branch to this scope and mark locals as debug-visible if (!expStk) return; // not an exposing send for (InlinedScope* s = this; s && s->isInlinedScope(); s = s->sender()) { if (isSend) s->_nofSends++; s->_nofInterruptPoints++; s->markLocalsDebugVisible(expStk); // mark locals as debug-visible } }
bool InlinedScope::isSenderOf(InlinedScope* callee) const { assert(callee, "should have a scope"); if (depth > callee->depth) return false; int d = callee->depth - 1; for (InlinedScope* s = callee->sender(); s && d >= depth; s = s->sender(), d--) { if (this == s) return true; } return false; }
void CompiledLoop::discoverLoopNesting() { // discover enclosing loop (if any) and set up loop header links for (InlinedScope* s = _scope; s != NULL; s = s->sender()) { GrowableArray<CompiledLoop*>* loops = s->loops(); for (int i = loops->length() - 1; i >= 0; i--) { CompiledLoop* l = loops->at(i); if (l->isInLoop(_loopHeader)) { // this is out enclosing loop _loopHeader->set_enclosingLoop(l->loopHeader()); l->loopHeader()->addNestedLoop(_loopHeader); return; } } } }
void PerformanceDebugger::finish_reporting() { // output messages about non-inlined sends if (DebugPerformance && notInlinedBecauseNmethodTooBig) { Reporter r(this); str->print(" did not inline the following sends because the nmethod was getting too big:"); int len = notInlinedBecauseNmethodTooBig->length(); for (int i = 0; i < min(9, len); i++) { if (i % 3 == 0) str->print("\n "); InlinedScope* s = notInlinedBecauseNmethodTooBig->at(i); str->print("%s ", s->key()->print_string()); } if (i < len) str->print("\n (%d more sends omitted)\n", len); str->put('\n'); } }
int InlinedScope::allocateFloatTemporaries(int firstFloatIndex) { assert(firstFloatIndex >= 0, "illegal firstFloatIndex"); _firstFloatIndex = firstFloatIndex; // start index for first float of this scope int nofFloatTemps = hasFloatTemporaries() ? nofFloatTemporaries() : 0; // convert floatLocs into stackLocs for (int k = 0; k < nofFloatTemps; k++) { PReg* preg = floatTemporary(k)->preg(); Location loc = preg->loc; assert(loc.scopeNo() == scopeID() && loc.floatNo() == k, "inconsistency"); preg->loc = Mapping::floatTemporary(scopeID(), k); assert(preg->loc.isStackLocation(), "must be a stack location"); } int startFloatIndex = firstFloatIndex + nofFloatTemps; // start index for first float in subscopes int totalNofFloatsInSubscopes = 0; // allocate float temporaries of subscopes int len = _subScopes->length(); for (int i = 0; i < len; i++) { InlinedScope* scope = _subScopes->at(i); totalNofFloatsInSubscopes = max(totalNofFloatsInSubscopes, scope->allocateFloatTemporaries(startFloatIndex)); } return nofFloatTemps + totalNofFloatsInSubscopes; }
void Compiler::computeBlockInfo() { FlagSetting(EliminateUnneededNodes, true); // unused context nodes must be eliminated GrowableArray<InlinedScope*>* allContexts = new GrowableArray<InlinedScope*>(25); topScope->collectContextInfo(allContexts); // for now, just allocate all contexts as in interpreter // fix this later: collect all uplevel-accessed PRegs at same loop depth, form physical // contexts for these // also, if uplevel-read and single def --> could copy into context and keep // stack/register copy // remove all unused contexts // need to iterate because removing a nested context may enable removal of a parent context // (could avoid iteration with topo sort, but there are few contexts anyway) bool changed = EliminateContexts; while (changed) { changed = false; for (int i = allContexts->length() - 1; i >= 0; i--) { InlinedScope* s = allContexts->at(i); if (s == NULL) continue; PReg* contextPR = s->context(); assert(contextPR->isSinglyAssigned(), "should have exactly one def"); GrowableArray<Expr*>* temps = s->contextTemporaries(); bool noUplevelAccesses = true; // check if all context temps can be stack-allocated for (int j = temps->length() - 1; j >= 0; j--) { PReg* r = temps->at(j)->preg(); if (r->uplevelR() || r->uplevelW() // this temp is still uplevel-accessed, so can't eliminate context || (r->isBlockPReg() && !r->isUnused()) // this block still forces a context ) { noUplevelAccesses = false; break; } } // TO DO: check if context is needed for NLRs // (noUplevelAccesses alone does not allow elimination) if (/*noUplevelAccesses || */contextPR->isSinglyUsed()) { // can eliminate context -- no uplevel-accessed vars // (single use is context initializer) if (CompilerDebug) cout(PrintEliminateContexts)->print("%*s*eliminating context %s\n", s->depth, "", contextPR->safeName()); contextPR->scope()->gen()->removeContextCreation(); allContexts->at_put(i, NULL); // make code generator break if it tries to access this context changed = true; } } } // now collect all remaining contexts int i = allContexts->length(); contextList = new GrowableArray<InlinedScope*>(i, i, NULL); while (i-- > 0) { // should merge several contexts into one physical context if possible // fix this later InlinedScope* s = allContexts->at(i); if (s == NULL) continue; PReg* contextPR = s->context(); if (CompilerDebug) { cout(PrintEliminateContexts)->print("%*s*could not eliminate context %s in scope %s\n", s->depth, "", contextPR->safeName(), s->key()->print_string()); } reporter->report_context(s); contextList->at_put(i, s); ContextCreateNode* c = s->contextInitializer()->creator(); c->set_contextNo(i); GrowableArray<Expr*>* temps = s->contextTemporaries(); // allocate the temps in this context (but only if they're used) int ntemps = temps->length(); int size = 0; for (int j = 0; j < ntemps; j++) { PReg* p = temps->at(j)->preg(); // should be: // if (p->isUsed() && (p->uplevelR() || p->uplevelW())) { // but doesn't work yet (probably must fix set_self_via_context etc.) // -Urs 6/96 if (p->isUsed()) { // allocate p to context temp assert(p->scope() == s || p->isBlockPReg(), "oops"); Location loc = Mapping::contextTemporary(i, size, s->scopeID()); if (p->isBlockPReg()) { // Blocks aren't actually assigned (at the PReg level) so that the inlining info // isn't lost. Thus we need to create a fake destination here if the context exists. SAPReg* dest = new SAPReg(s, loc, true, true, PrologueBCI, EpilogueBCI); Expr* e = new UnknownExpr(dest, NULL); //contextPR->scope()->contextInitializer()->initialize(j, init); temps->at_put(j, e); } else { p->allocateTo(loc); } size++; } } c->set_sizeOfContext(size); if (size < ntemps && c->scope()->number_of_noninlined_blocks() > 0) { // this hasn't been exercised much compiler_warning("while compiling %s: eliminated some context temps", key->print_string()); } } // Compute the number of noninlined blocks for the nmethod and allocate const int nblocks = topScope->number_of_noninlined_blocks(); if (is_method_compile() || nblocks > 0) { // allocate nblocks+1 jumpTable entries const jumpTableID id = Universe::code->jump_table()->allocate(nblocks + 1); if (is_method_compile()) { main_jumpTable_id = id; } else { promoted_jumpTable_id = id; } // first is for nmethod itself int block_index = 1; for (int i = bbIterator->exposedBlks->length() - 1; i >= 0; i--) { BlockPReg* blk = bbIterator->exposedBlks->at(i); if (blk->isUsed()) { assert(block_index <= nblocks, "nblocks too small"); blk->closure()->set_id(id.sub(block_index++)); } } assert(nblocks + 1 == block_index, "just checking"); } }
void InlinedScope::generateDebugInfo() { // Generate debug info for the common parts of methods and blocks if (PrintDebugInfoGeneration) { if (isMethodScope()) { std->print_cr("self: %s", _self->preg()->name()); } else { std->print_cr("no receiver (block method)"); } } ScopeDescRecorder* rec = theCompiler->scopeDescRecorder(); int len, i; if (!isLite()) { // temporaries if (hasTemporaries()) { len = _temporaries->length(); for (i = 0; i < len; i++) { PReg* preg = _temporaries->at(i)->preg(); rec->addTemporary(_scopeInfo, i, preg->createLogicalAddress()); if (PrintDebugInfoGeneration) std->print_cr("temp[%2d]: %s", i, preg->name()); } } // float temporaries if (hasFloatTemporaries()) { len = _floatTemporaries->length(); for (i = 0; i < len; i++) { PReg* preg = _floatTemporaries->at(i)->preg(); rec->addTemporary(_scopeInfo, i, preg->createLogicalAddress()); if (PrintDebugInfoGeneration) std->print_cr("float[%2d]: %s", i, preg->name()); } } // context temporaries if (allocatesInterpretedContext()) { len = _contextTemporaries->length(); for (i = 0; i < len; i++) { PReg* preg = _contextTemporaries->at(i)->preg(); rec->addContextTemporary(_scopeInfo, i, preg->createLogicalAddress()); if (PrintDebugInfoGeneration) std->print_cr("c_temp[%2d]: %s", i, preg->name()); } } // expr stack len = _exprStackElems->length(); for (i = 0; i < len; i++) { Expr* elem = _exprStackElems->at(i); if (elem != NULL) { PReg* r = elem->preg()->cpReg(); if (r->scope()->isSenderOrSame(this)) { // Note: Is it still needed to create this info here, since the // PReg locations may change over time and thus produce more // debug info than actually needed for the new backend. Discuss // this with Lars. rec->addExprStack(_scopeInfo, i, r->createLogicalAddress()); if (PrintDebugInfoGeneration) std->print_cr("expr[%2d]: %s", i, r->name()); } else { // r's scope is too low (i.e. it's not actually live anymore) // this can only happen if the expression is discarded; thus it's safe not to describe this entry // Urs 5/96 // fix this: should check that bci (i) is statement end (or r is NoPReg) } } } } // subscopes len = _subScopes->length(); for (i = 0; i < len; i++) { InlinedScope* s = _subScopes->at(i); if (PrintDebugInfoGeneration) std->print_cr("Subscope %d (id = %d):", i, s->scopeID()); s->generateDebugInfo(); } }