void InlinedScope::genCode() { _hasBeenGenerated = true; prologue(); // always generate (shared) entry points for ordinary & non-local return _returnPoint = NodeFactory::new_MergeNode(EpilogueBCI); _NLReturnPoint = NodeFactory::new_MergeNode(EpilogueBCI); _nlrTestPoint = NULL; _contextInitializer = NULL; int nofTemps = method()->number_of_stack_temporaries(); if (isTop()) { _returnPoint->append(NodeFactory::new_ReturnNode(resultPR, EpilogueBCI)); _NLReturnPoint->append(NodeFactory::new_NLRSetupNode(resultPR, EpilogueBCI)); Node* first = NodeFactory::new_PrologueNode(key(), nofArguments(), nofTemps); theCompiler->firstNode = first; gen()->setCurrent(first); } // allocate space for temporaries - initialization done in the prologue code assert(!hasTemporaries(), "should have no temporaries yet\n"); createTemporaries(nofTemps); // allocate space for float temporaries int nofFloats = method()->total_number_of_floats(); if (UseFPUStack) { const int FPUStackSize = 8; if (method()->float_expression_stack_size() <= FPUStackSize) { // float expression stack fits in FPU stack, use it instead // and allocate only space for the real float temporaries nofFloats = method()->number_of_float_temporaries(); } else { warning("possible performance bug: cannot use FPU stack for float expressions"); } } createFloatTemporaries(nofFloats); // build the intermediate representation assert(gen()->current() != NULL, "current() should have been set before"); MethodIterator iter(method(), gen()); if (gen()->aborting()) { // ends with dead code -- clean up expression stack while (!exprStack()->isEmpty()) exprStack()->pop(); } epilogue(); }
void InlinedScope::epilogue() { // generate epilogue code (i.e., everything after last byte code has been processed) assert(exprStack()->isEmpty(), "expr. stack should be empty now"); // first make sure subScopes are sorted by bci _subScopes->sort(compare_scopeBCIs); // now remove all subscopes that were created but not used (not inlined) while (! _subScopes->isEmpty() && !_subScopes->last()->hasBeenGenerated()) _subScopes->pop(); #ifdef ASSERT for (int i = 0; i < _subScopes->length(); i++) { if (!_subScopes->at(i)->hasBeenGenerated()) fatal("unused scopes should be at end"); } #endif if (_nofSends > 0 && containsNLR()) { // this scope *could* be the target of a non-inlined NLR; add an UnknownExpr to // the scope's result expression to account for this possibility // note: to be sure, we'd have to know that at least one nested block wasn't inlined, // but this analysis isn't performed until later addResult(new UnknownExpr(resultPR, NULL)); // also make sure we have an NLR test point to catch the NLR (void)nlrTestPoint(); assert(has_nlrTestPoint(), "should have a NLR test point now"); } // generate NLR code if needed if (has_nlrTestPoint()) { // NB: assertion below is too strict -- may have an nlr node that will be connected // only during fixupNLRPoints() // assert(nlrTestPoint()->nPredecessors() > 0, "nlr node is unused??"); } else if (isTop() && theCompiler->nlrTestPoints->nonEmpty()) { // the top scope doesn't have an NLR point, but needs one anyway so that inlined // scopes have somewhere to jump to (void)nlrTestPoint(); } if (!result) result = new NoResultExpr; theCompiler->exitScope(this); }
SExpr* SPrimScope::genPrimFailure(PrimNode* call, PReg* errorReg, Node*& test, MergeNode*& merge, PReg* resultReg, bool failure) { // generate primitive failure code // two modes: // if call == NULL, omit the test for failure because it's already // been generated (inlined prim.); in this case, errorReg // must be set // if call != NULL, generate test code (setting test & merge node args) // returns the result of the failure branch // pop prim args (they're not on the expr stack anymore in the fail branch) while (npop-- > 0) exprStack()->pop(); SCodeScope* s = sender(); NodeGen* ng = theNodeGen; if (call) { fint b = bci(); SAPReg* t = new SAPReg(s, b, b); // extract tag field and test for mark tag ng->append(new ArithRCNode(AndArithOp, call->dest(), Tag_Mask, t)); ng->append(new ArithRCNode(SubCCArithOp, t, Tag_Mask, ng->noPR)); test = ng->append(new BranchNode(NEBranchOp)); // failure branch; load error string if (!errorReg) errorReg = new SAPReg(s, b, b); ng->current = test->append(new ArithRCNode(SubArithOp, call->dest(), Mark_Tag-Mem_Tag, errorReg)); } SExpr* failReceiver = hasFailBlock ? failBlock : receiver; SendInfo* info = new SendInfo(failReceiver, NormalLookupType, false, false, (stringOop)failSelector, NULL); info->computeNSends(rscope, bci()); info->primFailure = failure; info->restartPrim = call == NULL; // restart inlined prims (unc. traps) s->exprStack->push(failReceiver); if (errorReg->isConstPReg()) { s->exprStack->push(new ConstantSExpr(((ConstPReg*)errorReg)->constant, errorReg, ng->current)); } else { s->exprStack->push(new MapSExpr(Memory->stringObj->map()->enclosing_mapOop(), errorReg, ng->current)); } ConstPReg* failSelReg = new_ConstPReg(s, selector()); s->exprStack->push(new ConstantSExpr(selector(), failSelReg, NULL)); SExpr* res = s->inlineSend(info); if (res->isNoResultSExpr()) { // never returns ng->current = merge; // set to NULL if no merge } else { if (needZap) { assert(failBlock->preg()->isBlockPReg(), "should be a block"); ng->zapBlock((BlockPReg*)failBlock->preg()); } ng->move(res->preg(), resultReg); res = res->shallowCopy(resultReg, ng->current); // moved creation down from before if res->isNoResult... // to avoid creating unreachable merge -- dmu if (merge == NULL) merge = new MergeNode("genPrimFailure merge"); ng->append(merge); } return res; }