void Compiler::initLimits() { if (recompileeRScope) { // We're compiling from the inlining data base _nextLevel = MaxRecompilationLevels - 1; } else if (recompilee) { if (DeltaProcess::active()->isUncommon()) { // when recompiling because of an uncommon trap, reset level _nextLevel = 0; } else { _nextLevel = recompilee->level() + 1; if (_nextLevel >= MaxRecompilationLevels) { warning("recompilation level too high -- should not happen"); _nextLevel = MaxRecompilationLevels; } } } else { // new nmethod _nextLevel = 0; } _noInlinableSends = true; #ifdef LATER inlineLimit[NormalFnLimit] = getLimit(limits[NormalFnLimit], level); inlineLimit[BlockFnLimit] = getLimit(limits[BlockFnLimit], level); inlineLimit[BlockArgFnLimit] = getLimit(limits[BlockArgFnLimit], level); inlineLimit[NormalFnInstrLimit] = getLimit(limits[NormalFnInstrLimit], level); inlineLimit[BlockFnInstrLimit] = getLimit(limits[BlockFnInstrLimit], level); inlineLimit[BlockArgFnInstrLimit] = getLimit(limits[BlockArgFnInstrLimit], level); inlineLimit[SplitCostLimit] = getLimit(limits[SplitCostLimit], level); inlineLimit[NmInstrLimit] = getLimit(limits[NmInstrLimit], level); if (CompilerAdjustLimits) { // adjust NmInstrLimit if top-level method is large int cost = sicCost((methodKlass*)method->klass(), topScope, costP); if (cost > NormalMethodLen) { float l = (float)cost / NormalMethodLen * inlineLimit[NmInstrLimit]; inlineLimit[NmInstrLimit] = min(int(l), CompilerInstructionsSize / 3); } } #endif }
void SICompiler::initLimits() { fint level; if (currentProcess->isUncommon()) { // when recompiling because of an uncommon trap, reset level level = nextLevel = 0; } else { level = AbstractCompiler::level(); nextLevel = MaxRecompilationLevels - 1; if (nstages > 1 && recompilee == NULL) { // always use a counter in first version nextLevel = nstages - 1; } } noInlinableSends = true; inlineLimit[NormalFnLimit] = getLimit(limits[NormalFnLimit], level); inlineLimit[BlockFnLimit] = getLimit(limits[BlockFnLimit], level); inlineLimit[BlockArgFnLimit] = getLimit(limits[BlockArgFnLimit], level); inlineLimit[NormalFnInstrLimit] = getLimit(limits[NormalFnInstrLimit], level); inlineLimit[BlockFnInstrLimit] = getLimit(limits[BlockFnInstrLimit], level); inlineLimit[BlockArgFnInstrLimit] = getLimit(limits[BlockArgFnInstrLimit], level); inlineLimit[SplitCostLimit] = getLimit(limits[SplitCostLimit], level); inlineLimit[NmInstrLimit] = getLimit(limits[NmInstrLimit], level); if (SICAdjustLimits) { // adjust NmInstrLimit if top-level method is large fint cost = sicCost( method(), topScope, costP); if (cost > NormalMethodLen) { float l = (float)cost / NormalMethodLen * inlineLimit[NmInstrLimit]; inlineLimit[NmInstrLimit] = min(int(l), SICInstructionsSize / 3); } } }
bool SCodeScope::shouldInlineSend(SendInfo* info, RScope* rs, SExpr* rcvr, oop m, InlineLimitType limitType) { MethodLookupKey* k = info->key; if (!k->selector->is_string()) return false; if (isRecursiveCall(m, k->receiverMapOop(), MaxRecursionUnroll)) { info->uninlinable = true; return false; } if (!Inline) { assert(InlineSTMessages, "shouldn't be here"); // NB: works only with rewritten whileTrue/False (using _Restart) if (isSmalltalkInlined(k->selector)) return true; if (isSmalltalkInlined(selector())) return true; return false; } if (limitType == NormalFnLimit) { // check args to see if any of them is a block; if so, increase limit fint top = exprStack->length(); fint argc = stringOop(k->selector)->arg_count(); for (fint i = argc; i > 0; i--) { if (exprStack->nth(top - i)->preg()->isBlockPReg()) { limitType = BlockArgFnLimit; goto done; } } // check receiver if (lookupReceiverIsSelf(k->lookupType)) { if (self->preg()->isBlockPReg()) limitType = BlockArgFnLimit; } else if (exprStack->nth(top - argc - 1)->preg()->isBlockPReg()) { limitType = BlockArgFnLimit; } } done: if (calleeTooBig(info, rs, limitType)) { // register this send as uninlinable theSIC->registerUninlinable(info, limitType, 9999); return false; } // NB: this test comes after calleeTooBig to prevent forced inlining of // e.g. a really complicated user-defined '+' for matrices if (isCheapMessage(stringOop(k->selector))) { msgCost = costP->cheapSendCost; return true; } fint cutoff = theSIC->inlineLimit[limitType]; msgCost = sicCost( m, this, costP); if (info->primFailure && info->nsends < MinPrimFailureInvocations) { if (rs->isPICScope() && ((RPICScope*)rs)->sd->isOptimized()) { // the fail block send is optimized, it's probably executed frequently } else if (rs->isSelfScope()) { // was inlined in previous version, so do it again } else { // don't inline error block unless trivial or taken often if (msgCost > MaxTrivialPrimFailureCost) return false; // should also look at block method, not default value:With: Map* map = rcvr->map(); if (map->is_block()) { slotsOop method = ((blockMap*)map)->value(); msgCost = sicCost( method, this, failCostP); // bug: should estimate real length of prim failure; e.g. could // have single send (cost 1) but that method sends more and more // msgs...i.e. need concept of "being in fail branch" so that // no further inlining takes place -- fix this if (msgCost > MaxTrivialPrimFailureCost) return false; } } } if (msgCost > cutoff) { if (calleeIsSmall(info, rs, limitType)) return true; theSIC->registerUninlinable(info, limitType, msgCost); return false; } return true; }