SSelfScope* SCodeScope::notify(stringOop selector, const char* msg) { if (PrintInlining) { lprintf("%*s*cannot inline %s, cost = %ld (%s)\n", (void*)depth, "", selector_string(selector), (void*)msgCost, msg); } return NULL; // cheap trick to make calls more convenient }
void ShowCompileInMonitor::do_show_compile(oop sel, char* compiler, bool optimize) { method_being_compiled = selector_string(sel); current_compiler_name = compiler; current_compiler_ticks = &compiler_ticks[optimize]; assert(optimize == 0 || optimize == 1, "should use true or false"); recompiling = recompilee != NULL; }
bool SCodeScope::calleeTooBig(SendInfo* info, RScope* rs, InlineLimitType limitType) { // try to see if the potential inlinee is too big fint size = calleeSize(rs); // NB: continue even if size == 0 to bring current estimated size into play assert(limitType <= BlockFnLimit, "bad limit"); limitType = InlineLimitType(limitType + NormalFnInstrLimit-NormalFnLimit); fint cutoff = theSIC->inlineLimit[limitType]; fint estimated = theSIC->estimatedSize(); fint limit = theSIC->inlineLimit[NmInstrLimit]; // reject if inlinee too large, but correct for well-known cheap messages bool bad = size > cutoff && !(info->rcvr->hasMap() && isCheapMessage(info->sel, info->rcvr->myMapOop())); if (bad && estimated + size < limit / 2) { // allow inlining if recompilee itself is small (i.e., a forwarder) if (recompilee && recompilee->instsLen() - oopSize * PrologueSize < cutoff) { bad = false; } } // also reject if est. total size too large (except for ifTrue et al) // but don't trust the isCheap thing if we're way over the limit bad = bad || estimated + size >= limit; if (bad && estimated + size < 2 * limit && (size == 0 || size < cutoff / 8) && info->rcvr->hasMap() && isReallyCheapMessage(info->sel, info->rcvr->myMapOop())) { bad = false; } if (bad && PrintInlining) { lprintf("%*s*not inlining %s: callee too big (%d/%d/%d/%d)\n", (void*)depth, "", selector_string(info->sel), (void*)size, (void*)cutoff, (void*)estimated, (void*)limit); } if (SICDebug && bad && estimated > limit) warning4("SIC: (while compiling %s/%s) estimated nmethod size > limit (%ld > %ld)", selector_string(theSIC->L->selector()), selector_string(info->sel), estimated, limit); return bad; }
SExpr* SCodeScope::doInline(SSelfScope* s, SExpr* rcvr, Node* start, MergeNode* end) { s->receiver = rcvr->asReceiver(); if (PrintInlining) { lprintf("%*s*inlining %s, cost %ld/size %ld (%#lx)%s\n", (void*)depth, "", (s->isCodeScope() ? sprintName((methodMap*)s->method()->map(), s->selector()) : selector_string(s->selector())), // was: selector_string(s->selector()), (void*)msgCost, (void*)calleeSize(s->rscope), s, s->rscope->isNullScope() ? "" : "*"); } Node* next = start->next(); if (next) start->removeNext(next); theNodeGen->current = start; s->genCode(); if (next && end) theNodeGen->branch(end); return s->result; }
bool SCodeScope::calleeIsSmall(SendInfo* info, RScope* rs, InlineLimitType limitType) { // try to see if the potential inlinee is small fint size = calleeSize(rs); if (!size) return false; // no size info assert(limitType <= BlockFnLimit, "bad limit"); limitType = InlineLimitType(limitType + NormalFnInstrLimit-NormalFnLimit); fint cutoff = theSIC->inlineLimit[limitType]; fint estimated = theSIC->estimatedSize(); fint limit = theSIC->inlineLimit[NmInstrLimit]; bool ok = size <= cutoff && estimated + size < limit; if (ok && PrintInlining) { lprintf("%*s*inlining %s anyway: callee is small (%d/%d/%d/%d)\n", (void*)depth, "", selector_string(info->sel), (void*)size, (void*)cutoff, (void*)estimated, (void*)limit); } return ok; }
char* InliningDatabase::compute_file_name(LookupKey* outer, LookupKey* inner, bool create_directories) { char* name = NEW_RESOURCE_ARRAY(char, 1024); // Outer key char* outer_klass_name = mangle_name(klass_string(outer->klass())); char* outer_selector_name = mangle_name(selector_string(outer->selector())); if (create_directories) { if (!check_directory(directory())) return NULL; } strcpy(name, directory()); strcat(name, "\\"); strcat(name, outer_klass_name); if (create_directories) { if (!check_directory(name)) return NULL; } strcat(name, "\\"); strcat(name, outer_selector_name); if (inner) { // Inner key char* inner_klass_name = mangle_name(klass_string(inner->klass())); char* inner_method_name = mangle_name(method_string(inner->method())); if (create_directories) { if (!check_directory(name)) return NULL; } strcat(name, "\\"); strcat(name, inner_klass_name); if (create_directories) { if (!check_directory(name)) return NULL; } strcat(name, "\\"); strcat(name, inner_method_name); } strcat(name, ".txt"); return name; }
SExpr* SCodeScope::inlineMerge(SendInfo* info, MergeNode*& merge) { // inline the send by type-casing; return uninlined cases in others list // If merge has no predecessors, return NULL for merge ref. SExpr* res = NULL; assert(info->rcvr->isMergeSExpr(), "must be a merge"); MergeSExpr* r = (MergeSExpr*)info->rcvr; stringOop sel = info->sel; merge = NULL; if (r->isSplittable() && shouldSplit(info)) { return splitMerge(info, merge); } fint ncases = r->exprs->length(); if (ncases > SICTypeCaseLimit) { info->needRealSend = true; if (PrintInlining) { lprintf("%*s*not type-casing %s (%ld > SICTypeCaseLimit)\n", (void*)depth, "", selector_string(sel), (void*)ncases); } return res; } assert( merge == NULL, "I assume merge is out param only"); merge = new MergeNode("inlineMerge merge"); if (SICDebug) { char* s = NEW_RESOURCE_ARRAY(char, 200); sprintf(s, "begin type-case of %s (ends at node N%ld)", sel->copy_null_terminated(), long(merge->id())); theNodeGen->comment(s); } if (PrintInlining) { lprintf("%*s*type-casing %s\n", (void*)depth, "", selector_string(sel)); } // build list of cases to inline // (add only immediate maps at first, collect others in ...2 lists SSelfScopeBList* slist = new SSelfScopeBList(ncases); SSelfScopeBList* slist2 = new SSelfScopeBList(ncases); SExprBList* elist = new SExprBList(ncases); SExprBList* elist2 = new SExprBList(ncases); SExprBList* others = new SExprBList(ncases); OopBList* mlist = new OopBList(ncases); OopBList* mlist2 = new OopBList(ncases); bool needMapLoad = false; fint i; for (i = 0; i < ncases; i++) { SExpr* nth = r->exprs->nth(i); assert(!nth->isConstantSExpr() || nth->next == NULL || nth->constant() == nth->next->constant(), "shouldn't happen: merged consts - convert to map"); SSelfScope* s; if (!nth->hasMap() || (s = tryLookup(info, nth)) == NULL) { // cannot inline others->append(nth); info->needRealSend = true; continue; } // can inline this case // Notice that for immediates, instead of putting the constants in the mlist, // we put the maps. No point in optimizing just for 17. -- dmu 6/05 Map* map = nth->map(); if (map == Memory->smi_map || map == Memory->float_map) { slist ->append(s); // immediate maps go first // Bug fix: instead of nth->shallowCopy, must generalize to any // with same map, not just the same constant, because other ints (for example) // will pass the type test, too. -- dmu 6/05 elist ->append(new MapSExpr(map->enclosing_mapOop(), r->preg(), NULL)); mlist ->append(map->enclosing_mapOop()); continue; } // can inline but not immediate map slist2->append(s); // append later elist2->append(nth->shallowCopy(r->preg(), NULL)); // use preg of merge if (nth->isConstantSExpr()) { mlist2->append(nth->constant()); } else { needMapLoad = true; // will need to load map of testee mlist2->append(map->enclosing_mapOop()); } } mlist->appendList(mlist2); elist->appendList(elist2); slist->appendList(slist2); // now do the type test and inline the individual cases if (slist->length() > 0) { memoizeBlocks(sel); Node* typeCase = theNodeGen->append(new TypeTestNode(r->preg(), mlist, needMapLoad, info->needRealSend)); Node* fallThrough = typeCase->append(new NopNode); for (i = 0; i < slist->length(); i++) { theNodeGen->current = typeCase->append(i + 1, new NopNode); SExpr* e = doInline(slist->nth(i), elist->nth(i), theNodeGen->current, merge); if (!e->isNoResultSExpr()) { theNodeGen->append(new NopNode); e = e->shallowCopy(info->resReg, theNodeGen->current); res = res ? res->mergeWith(e, merge) : e; } theNodeGen->branch(merge); } theNodeGen->current = fallThrough; } if (res && res->isMergeSExpr()) res->setNode(merge, info->resReg); assert( info->needRealSend && others->length() || !info->needRealSend && !others->length(), "inconsistent"); // NB: *must* use uncommon branch if marked unlikely because // future type tests won't test for unknown if (others->isEmpty()) { // typecase cannot fail theNodeGen->deadEnd(); } else if ( others->length() == 1 && others->first()->isUnknownSExpr() && ((UnknownSExpr*)others->first())->isUnlikely()) { // generate an uncommon branch for the unknown case, not a send theNodeGen->uncommonBranch(currentExprStack(0), info->restartPrim); info->needRealSend = false; if (PrintInlining) lprintf("%*s*making %s uncommon (2)\n", (void*)depth,"",selector_string(sel)); } return res; }
SExpr* SCodeScope::inlineSend(SendInfo* info) { stringOop sel = info->sel; SExpr* res = NULL; info->resReg = new SAPReg(this); MergeNode* merge = NULL; fint argc = sel->arg_count(); if (!Inline && !InlineSTMessages) { // don't do any inlining info->needRealSend = true; } else { info->rcvr = picPredict(info); UnknownSExpr* u = info->rcvr->findUnknown(); if (u && !u->isUnlikely()) { info->rcvr = typePredict(info); } if (info->rcvr->really_hasMap(this)) { // single map - try to inline this send SSelfScope* s = tryLookup(info, info->rcvr); if (s) { SExpr* r = doInline(s, info->rcvr, theNodeGen->current, NULL); if (r->isNoResultSExpr()) { res = r; } else { theNodeGen->append(new NopNode()); // to get right scope for r res = r->shallowCopy(r->preg(), theNodeGen->current); } } else { if (PrintInlining) { lprintf("%*s*marking %s send ReceiverStatic\n", (void*)depth,"", selector_string(sel)); } // receiver type is constant (but e.g. method was too big to inline) info->l |= ReceiverStaticBit; info->needRealSend = true; } } else if (info->rcvr->isMergeSExpr()) { res = inlineMerge(info, merge); } else { // unknown receiver // NB: *must* use uncommon branch if marked unlikely because // future type tests won't test for unknown if (info->rcvr->findUnknown()->isUnlikely()) { // generate an uncommon branch for the unknown case, not a send theNodeGen->current = theNodeGen->uncommonBranch(currentExprStack(0), info->restartPrim); info->needRealSend = false; if (PrintInlining) { lprintf("%*s*making %s uncommon\n", (void*)depth,"",selector_string(sel)); } } else { info->needRealSend = true; } } } if (info->needRealSend) { SExpr* r = genRealSend(info); res = res ? res->mergeWith(r, merge) : r; } if (merge && res && !res->isNoResultSExpr()) theNodeGen->branch(merge); // now pop expr stack for (fint i = 0; i < argc; i++) exprStack->pop(); if (!info->isSelfImplicit) exprStack->pop(); if (!res) res = new NoResultSExpr; return res; }