예제 #1
0
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;
}
예제 #2
0
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
  }
}
예제 #3
0
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;
}
예제 #4
0
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;
      }
    }
  }
}
예제 #5
0
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');
  }
}
예제 #6
0
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;
}
예제 #7
0
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");
  }
}
예제 #8
0
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();
  }
}