diff --git a/src/coreclr/jit/block.cpp b/src/coreclr/jit/block.cpp index 128c4e033d9fa..5df8c1e4358c2 100644 --- a/src/coreclr/jit/block.cpp +++ b/src/coreclr/jit/block.cpp @@ -1431,6 +1431,7 @@ BasicBlock* Compiler::bbNewBasicBlock(BBjumpKinds jumpKind) /* Give the block a number, set the ancestor count and weight */ ++fgBBcount; + ++fgBBNumMax; if (compIsForInlining()) { @@ -1438,7 +1439,7 @@ BasicBlock* Compiler::bbNewBasicBlock(BBjumpKinds jumpKind) } else { - block->bbNum = ++fgBBNumMax; + block->bbNum = fgBBNumMax; } if (compRationalIRForm) diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp index bf49e63ab0cbb..fe5734213afcc 100644 --- a/src/coreclr/jit/compiler.cpp +++ b/src/coreclr/jit/compiler.cpp @@ -6272,6 +6272,9 @@ int Compiler::compCompileHelper(CORINFO_MODULE_HANDLE classPtr, // a potential inline candidate. InlineResult prejitResult(this, methodHnd, "prejit"); + // Profile data allows us to avoid early "too many IL bytes" outs. + prejitResult.NoteBool(InlineObservation::CALLSITE_HAS_PROFILE, fgHaveSufficientProfileData()); + // Do the initial inline screen. impCanInlineIL(methodHnd, methodInfo, forceInline, &prejitResult); diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index b60353d8e8440..9027a5d233529 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -5814,6 +5814,7 @@ class Compiler void WalkSpanningTree(SpanningTreeVisitor* visitor); void fgSetProfileWeight(BasicBlock* block, BasicBlock::weight_t weight); void fgApplyProfileScale(); + bool fgHaveSufficientProfileData(); // fgIsUsingProfileWeights - returns true if we have real profile data for this method // or if we have some fake profile data for the stress mode diff --git a/src/coreclr/jit/fgbasic.cpp b/src/coreclr/jit/fgbasic.cpp index 62a9467da63fe..6c65586fbca1c 100644 --- a/src/coreclr/jit/fgbasic.cpp +++ b/src/coreclr/jit/fgbasic.cpp @@ -818,8 +818,24 @@ class FgStack return false; } const unsigned argNum = value - SLOT_ARGUMENT; - assert(argNum < info->argCnt); - return info->inlArgInfo[argNum].argIsInvariant; + if (argNum < info->argCnt) + { + return info->inlArgInfo[argNum].argIsInvariant; + } + return false; + } + static bool IsExactArgument(FgSlot value, InlineInfo* info) + { + if ((info == nullptr) || !IsArgument(value)) + { + return false; + } + const unsigned argNum = value - SLOT_ARGUMENT; + if (argNum < info->argCnt) + { + return info->inlArgInfo[argNum].argIsExact; + } + return false; } static unsigned SlotTypeToArgNum(FgSlot value) { @@ -876,6 +892,10 @@ void Compiler::fgFindJumpTargets(const BYTE* codeAddr, IL_OFFSET codeSize, Fixed if (makeInlineObservations) { + // Set default values for profile (to avoid NoteFailed in CALLEE_IL_CODE_SIZE's handler) + // these will be overridden later. + compInlineResult->NoteBool(InlineObservation::CALLSITE_HAS_PROFILE, true); + compInlineResult->NoteDouble(InlineObservation::CALLSITE_PROFILE_FREQUENCY, 1.0); // Observe force inline state and code size. compInlineResult->NoteBool(InlineObservation::CALLEE_IS_FORCE_INLINE, isForceInline); compInlineResult->NoteInt(InlineObservation::CALLEE_IL_CODE_SIZE, codeSize); @@ -1031,7 +1051,8 @@ void Compiler::fgFindJumpTargets(const BYTE* codeAddr, IL_OFFSET codeSize, Fixed if (makeInlineObservations) { FgStack::FgSlot slot = pushedStack.Top(); - if (FgStack::IsConstantOrConstArg(slot, impInlineInfo)) + if (FgStack::IsConstantOrConstArg(slot, impInlineInfo) || + FgStack::IsExactArgument(slot, impInlineInfo)) { compInlineResult->Note(InlineObservation::CALLSITE_FOLDABLE_EXPR_UN); handled = true; // and keep argument in the pushedStack @@ -1338,44 +1359,59 @@ void Compiler::fgFindJumpTargets(const BYTE* codeAddr, IL_OFFSET codeSize, Fixed FgStack::FgSlot arg0 = pushedStack.Top(1); FgStack::FgSlot arg1 = pushedStack.Top(0); - if ((FgStack::IsConstant(arg0) && FgStack::IsConstArgument(arg1, impInlineInfo)) || - (FgStack::IsConstant(arg1) && FgStack::IsConstArgument(arg0, impInlineInfo)) || - (FgStack::IsConstArgument(arg0, impInlineInfo) && - FgStack::IsConstArgument(arg1, impInlineInfo))) + // Const op ConstArg -> ConstArg + if (FgStack::IsConstant(arg0) && FgStack::IsConstArgument(arg1, impInlineInfo)) { // keep stack unchanged handled = true; compInlineResult->Note(InlineObservation::CALLSITE_FOLDABLE_EXPR); } - if ((FgStack::IsConstant(arg0) && FgStack::IsConstant(arg1)) || - (FgStack::IsConstant(arg1) && FgStack::IsConstant(arg0))) + // ConstArg op Const -> ConstArg + // ConstArg op ConstArg -> ConstArg + else if (FgStack::IsConstArgument(arg0, impInlineInfo) && + FgStack::IsConstantOrConstArg(arg1, impInlineInfo)) + { + if (FgStack::IsConstant(arg1)) + { + pushedStack.Push(arg0); + } + handled = true; + compInlineResult->Note(InlineObservation::CALLSITE_FOLDABLE_EXPR); + } + // Const op Const -> Const + else if (FgStack::IsConstant(arg0) && FgStack::IsConstant(arg1)) { // both are constants, but we're mostly interested in cases where a const arg leads to // a foldable expression. handled = true; } + // Arg op ConstArg + // Arg op Const else if (FgStack::IsArgument(arg0) && FgStack::IsConstantOrConstArg(arg1, impInlineInfo)) { // "Arg op CNS" --> keep arg0 in the stack for the next ops + pushedStack.Push(arg0); handled = true; compInlineResult->Note(InlineObservation::CALLEE_BINARY_EXRP_WITH_CNS); } + // ConstArg op Arg + // Const op Arg else if (FgStack::IsArgument(arg1) && FgStack::IsConstantOrConstArg(arg0, impInlineInfo)) { // "CNS op ARG" --> keep arg1 in the stack for the next ops - pushedStack.Push(arg1); handled = true; compInlineResult->Note(InlineObservation::CALLEE_BINARY_EXRP_WITH_CNS); } - + // X / ConstArg + // X % ConstArg if (FgStack::IsConstArgument(arg1, impInlineInfo)) { - // Special case: "X / ConstArg" or "X % ConstArg" if ((opcode == CEE_DIV) || (opcode == CEE_DIV_UN) || (opcode == CEE_REM) || (opcode == CEE_REM_UN)) { compInlineResult->Note(InlineObservation::CALLSITE_DIV_BY_CNS); } + pushedStack.Push(arg0); handled = true; } } @@ -1583,6 +1619,10 @@ void Compiler::fgFindJumpTargets(const BYTE* codeAddr, IL_OFFSET codeSize, Fixed if (makeInlineObservations) { compInlineResult->Note(InlineObservation::CALLEE_HAS_SWITCH); + if (FgStack::IsConstantOrConstArg(pushedStack.Top(), impInlineInfo)) + { + compInlineResult->Note(InlineObservation::CALLSITE_FOLDABLE_SWITCH); + } // Fail fast, if we're inlining and can't handle this. if (isInlining && compInlineResult->IsFailure()) diff --git a/src/coreclr/jit/fgprofile.cpp b/src/coreclr/jit/fgprofile.cpp index 1659b2d390529..31d7c208ebaf0 100644 --- a/src/coreclr/jit/fgprofile.cpp +++ b/src/coreclr/jit/fgprofile.cpp @@ -47,6 +47,31 @@ bool Compiler::fgHaveProfileData() return (fgPgoSchema != nullptr); } +//------------------------------------------------------------------------ +// fgHaveSufficientProfileData: check if profile data is available +// and is sufficient enough to be trustful. +// +// Returns: +// true if so +// +// Note: +// See notes for fgHaveProfileData. +// +bool Compiler::fgHaveSufficientProfileData() +{ + if (!fgHaveProfileData()) + { + return false; + } + + if ((fgFirstBB != nullptr) && (fgPgoSource == ICorJitInfo::PgoSource::Static)) + { + const BasicBlock::weight_t sufficientSamples = 1000; + return fgFirstBB->bbWeight > sufficientSamples; + } + return true; +} + //------------------------------------------------------------------------ // fgApplyProfileScale: scale inlinee counts by appropriate scale factor // diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index d49a12ffd13dd..55a8063ac7ce3 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -13258,8 +13258,6 @@ void Compiler::impImportBlockCode(BasicBlock* block) goto COND_JUMP; case CEE_SWITCH: - assert(!compIsForInlining()); - if (tiVerificationNeeded) { Verify(impStackTop().seTypeInfo.IsType(TI_INT), "Bad switch val"); @@ -19071,33 +19069,30 @@ void Compiler::impMakeDiscretionaryInlineObservations(InlineInfo* pInlineInfo, I inlineResult->NoteInt(InlineObservation::CALLSITE_FREQUENCY, static_cast(frequency)); inlineResult->NoteInt(InlineObservation::CALLSITE_WEIGHT, (int)(weight)); + bool hasProfile = false; + double profileFreq = 0.0; + // If the call site has profile data, report the relative frequency of the site. // - if ((pInlineInfo != nullptr) && rootCompiler->fgHaveProfileData() && pInlineInfo->iciBlock->hasProfileWeight()) + if ((pInlineInfo != nullptr) && rootCompiler->fgHaveSufficientProfileData()) { - BasicBlock::weight_t callSiteWeight = pInlineInfo->iciBlock->bbWeight; - BasicBlock::weight_t entryWeight = rootCompiler->fgFirstBB->bbWeight; - BasicBlock::weight_t profileFreq = entryWeight == 0.0f ? 0.0f : callSiteWeight / entryWeight; + const BasicBlock::weight_t callSiteWeight = pInlineInfo->iciBlock->bbWeight; + const BasicBlock::weight_t entryWeight = rootCompiler->fgFirstBB->bbWeight; + profileFreq = entryWeight == 0.0f ? 0.0 : callSiteWeight / entryWeight; + hasProfile = true; assert(callSiteWeight >= 0); assert(entryWeight >= 0); - - BasicBlock::weight_t sufficientSamples = 1000.0f; - - if (!rootCompiler->opts.jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT) || - ((callSiteWeight + entryWeight) > sufficientSamples)) - { - // Let's not report profiles for methods with insufficient samples during prejitting. - inlineResult->NoteBool(InlineObservation::CALLSITE_HAS_PROFILE, true); - inlineResult->NoteDouble(InlineObservation::CALLSITE_PROFILE_FREQUENCY, profileFreq); - } } - else if ((pInlineInfo == nullptr) && rootCompiler->fgHaveProfileData()) + else if (pInlineInfo == nullptr) { // Simulate a hot callsite for PrejitRoot mode. - inlineResult->NoteBool(InlineObservation::CALLSITE_HAS_PROFILE, true); - inlineResult->NoteDouble(InlineObservation::CALLSITE_PROFILE_FREQUENCY, 1.0); + hasProfile = true; + profileFreq = 1.0; } + + inlineResult->NoteBool(InlineObservation::CALLSITE_HAS_PROFILE, hasProfile); + inlineResult->NoteDouble(InlineObservation::CALLSITE_PROFILE_FREQUENCY, profileFreq); } /***************************************************************************** @@ -19243,6 +19238,10 @@ void Compiler::impCheckCanInline(GenTreeCall* call, goto _exit; } + // Profile data allows us to avoid early "too many IL bytes" outs. + pParam->result->NoteBool(InlineObservation::CALLSITE_HAS_PROFILE, + pParam->pThis->fgHaveSufficientProfileData()); + bool forceInline; forceInline = !!(pParam->methAttr & CORINFO_FLG_FORCEINLINE); @@ -19465,6 +19464,10 @@ void Compiler::impInlineRecordArgInfo(InlineInfo* pInlineInfo, } } + bool isExact = false; + bool isNonNull = false; + inlCurArgInfo->argIsExact = (gtGetClassHandle(curArgVal, &isExact, &isNonNull) != NO_CLASS_HANDLE) && isExact; + // If the arg is a local that is address-taken, we can't safely // directly substitute it into the inlinee. // diff --git a/src/coreclr/jit/inline.def b/src/coreclr/jit/inline.def index a16d82888b64a..cbd85ff240dea 100644 --- a/src/coreclr/jit/inline.def +++ b/src/coreclr/jit/inline.def @@ -182,6 +182,7 @@ INLINE_OBSERVATION(FOLDABLE_INTRINSIC, int, "foldable intrinsic", INLINE_OBSERVATION(FOLDABLE_EXPR, int, "foldable binary expression", INFORMATION, CALLSITE) INLINE_OBSERVATION(FOLDABLE_EXPR_UN, int, "foldable unary expression", INFORMATION, CALLSITE) INLINE_OBSERVATION(FOLDABLE_BRANCH, int, "foldable branch", INFORMATION, CALLSITE) +INLINE_OBSERVATION(FOLDABLE_SWITCH, int, "foldable switch", INFORMATION, CALLSITE) INLINE_OBSERVATION(DIV_BY_CNS, int, "dividy by const", INFORMATION, CALLSITE) INLINE_OBSERVATION(CONSTANT_ARG_FEEDS_TEST, bool, "constant argument feeds test", INFORMATION, CALLSITE) INLINE_OBSERVATION(DEPTH, int, "depth", INFORMATION, CALLSITE) diff --git a/src/coreclr/jit/inline.h b/src/coreclr/jit/inline.h index bc08dd8110d2a..6a39b2d9cb5d0 100644 --- a/src/coreclr/jit/inline.h +++ b/src/coreclr/jit/inline.h @@ -610,6 +610,7 @@ struct InlArgInfo unsigned argHasStargOp : 1; // Is there STARG(s) operation on this argument? unsigned argIsByRefToStructLocal : 1; // Is this arg an address of a struct local or a normed struct local or a // field in them? + unsigned argIsExact : 1; // Is this arg of an exact class? }; // InlLclVarInfo describes inline candidate argument and local variable properties. diff --git a/src/coreclr/jit/inlinepolicy.cpp b/src/coreclr/jit/inlinepolicy.cpp index fdf4ae19341c2..e84ff2858a011 100644 --- a/src/coreclr/jit/inlinepolicy.cpp +++ b/src/coreclr/jit/inlinepolicy.cpp @@ -326,7 +326,6 @@ void DefaultPolicy::NoteBool(InlineObservation obs, bool value) m_ArgFeedsRangeCheck++; break; - case InlineObservation::CALLEE_HAS_SWITCH: case InlineObservation::CALLEE_UNSUPPORTED_OPCODE: propagate = true; break; @@ -1294,6 +1293,14 @@ void ExtendedDefaultPolicy::NoteBool(InlineObservation obs, bool value) m_FoldableBranch++; break; + case InlineObservation::CALLSITE_FOLDABLE_SWITCH: + m_FoldableSwitch++; + break; + + case InlineObservation::CALLEE_HAS_SWITCH: + m_Switch++; + break; + case InlineObservation::CALLSITE_DIV_BY_CNS: m_DivByCns++; break; @@ -1327,7 +1334,14 @@ void ExtendedDefaultPolicy::NoteInt(InlineObservation obs, int value) { assert(m_IsForceInlineKnown); assert(value != 0); - m_CodeSize = static_cast(value); + m_CodeSize = static_cast(value); + unsigned maxCodeSize = static_cast(JitConfig.JitExtDefaultPolicyMaxIL()); + + // TODO: Enable for PgoSource::Static as well if it's not the generic profile we bundle. + if (m_HasProfile && (m_RootCompiler->fgPgoSource == ICorJitInfo::PgoSource::Dynamic)) + { + maxCodeSize = static_cast(JitConfig.JitExtDefaultPolicyMaxILProf()); + } if (m_IsForceInline) { @@ -1339,7 +1353,7 @@ void ExtendedDefaultPolicy::NoteInt(InlineObservation obs, int value) // Candidate based on small size SetCandidate(InlineObservation::CALLEE_BELOW_ALWAYS_INLINE_SIZE); } - else if (m_CodeSize <= (unsigned)JitConfig.JitExtDefaultPolicyMaxIL()) + else if (m_CodeSize <= maxCodeSize) { // Candidate, pending profitability evaluation SetCandidate(InlineObservation::CALLEE_IS_DISCRETIONARY_INLINE); @@ -1357,16 +1371,16 @@ void ExtendedDefaultPolicy::NoteInt(InlineObservation obs, int value) { SetNever(InlineObservation::CALLEE_DOES_NOT_RETURN); } - else if (!m_IsForceInline) + else if (!m_IsForceInline && !m_HasProfile) { unsigned bbLimit = (unsigned)JitConfig.JitExtDefaultPolicyMaxBB(); if (m_IsPrejitRoot) { // We're not able to recognize arg-specific foldable branches // in prejit-root mode. - bbLimit += 3; + bbLimit += 5 + m_Switch * 10; } - bbLimit += m_FoldableBranch; + bbLimit += m_FoldableBranch + m_FoldableSwitch * 10; if ((unsigned)value > bbLimit) { SetNever(InlineObservation::CALLEE_TOO_MANY_BASIC_BLOCKS); @@ -1419,13 +1433,13 @@ double ExtendedDefaultPolicy::DetermineMultiplier() if (m_ReturnsStructByValue) { // For structs-passed-by-value we might avoid expensive copy operations if we inline. - multiplier += 1.5; + multiplier += 2.0; JITDUMP("\nInline candidate returns a struct by value. Multiplier increased to %g.", multiplier); } else if (m_ArgIsStructByValue > 0) { // Same here - multiplier += 1.5; + multiplier += 2.0; JITDUMP("\n%d arguments are structs passed by value. Multiplier increased to %g.", m_ArgIsStructByValue, multiplier); } @@ -1451,13 +1465,13 @@ double ExtendedDefaultPolicy::DetermineMultiplier() if (m_ArgFeedsRangeCheck > 0) { - multiplier += 0.5; + multiplier += 1.0; JITDUMP("\nInline candidate has arg that feeds range check. Multiplier increased to %g.", multiplier); } if (m_NonGenericCallsGeneric) { - multiplier += 1.5; + multiplier += 2.0; JITDUMP("\nInline candidate is generic and caller is not. Multiplier increased to %g.", multiplier); } @@ -1507,7 +1521,7 @@ double ExtendedDefaultPolicy::DetermineMultiplier() if (m_Intrinsic > 0) { // In most cases such intrinsics are lowered as single CPU instructions - multiplier += 1.5; + multiplier += 1.0 + m_Intrinsic * 0.3; JITDUMP("\nInline has %d intrinsics. Multiplier increased to %g.", m_Intrinsic, multiplier); } @@ -1636,6 +1650,28 @@ double ExtendedDefaultPolicy::DetermineMultiplier() break; } + if (m_FoldableSwitch > 0) + { + multiplier += 6.0; + JITDUMP("\nInline candidate has %d foldable switches. Multiplier increased to %g.", m_FoldableSwitch, + multiplier); + } + else if (m_Switch > 0) + { + if (m_IsPrejitRoot) + { + // Assume the switches can be foldable in PrejitRoot mode. + multiplier += 6.0; + JITDUMP("\nPrejit root candidate has %d switches. Multiplier increased to %g.", m_Switch, multiplier); + } + else + { + // TODO: Investigate cases where it makes sense to inline non-foldable switches + multiplier = 0.0; + JITDUMP("\nInline candidate has %d switches. Multiplier limited to %g.", m_Switch, multiplier); + } + } + if (m_HasProfile) { // There are cases when Profile Data can be misleading or polluted: @@ -1657,14 +1693,16 @@ double ExtendedDefaultPolicy::DetermineMultiplier() { multiplier *= min(m_ProfileFrequency, 1.0) * profileScale; } - JITDUMP("\nCallsite has profile data: %g.", m_ProfileFrequency); + JITDUMP("\nCallsite has profile data: %g. Multiplier limited to %g.", m_ProfileFrequency, multiplier); } - if (m_RootCompiler->lvaTableCnt > ((unsigned)(JitConfig.JitMaxLocalsToTrack() / 4))) + // Slow down if there are already too many locals + if (m_RootCompiler->lvaTableCnt > 64) { - // Slow down inlining if we already have to many locals in the rootCompiler. - multiplier /= ((double)m_RootCompiler->lvaTableCnt / ((double)JitConfig.JitMaxLocalsToTrack() / 4.0)); - JITDUMP("\nCaller %d locals. Multiplier decreased to %g.", m_RootCompiler->lvaTableCnt, multiplier); + // E.g. MaxLocalsToTrack = 1024 and lvaTableCnt = 512 -> multiplier *= 0.5; + const double lclFullness = min(1.0, (double)m_RootCompiler->lvaTableCnt / JitConfig.JitMaxLocalsToTrack()); + multiplier *= (1.0 - lclFullness); + JITDUMP("\nCaller has %d locals. Multiplier decreased to %g.", m_RootCompiler->lvaTableCnt, multiplier); } if (m_BackwardJump) @@ -1738,6 +1776,8 @@ void ExtendedDefaultPolicy::OnDumpXml(FILE* file, unsigned indent) const XATTR_I4(m_FoldableExpr) XATTR_I4(m_FoldableExprUn) XATTR_I4(m_FoldableBranch) + XATTR_I4(m_FoldableSwitch) + XATTR_I4(m_Switch) XATTR_I4(m_DivByCns) XATTR_B(m_ReturnsStructByValue) XATTR_B(m_IsFromValueClass) @@ -1927,7 +1967,6 @@ void DiscretionaryPolicy::NoteDouble(InlineObservation obs, double value) { assert(obs == InlineObservation::CALLSITE_PROFILE_FREQUENCY); assert(value >= 0.0); - assert(m_ProfileFrequency == 0.0); m_ProfileFrequency = value; } diff --git a/src/coreclr/jit/inlinepolicy.h b/src/coreclr/jit/inlinepolicy.h index 7d0d83bd73646..466e17fe0e112 100644 --- a/src/coreclr/jit/inlinepolicy.h +++ b/src/coreclr/jit/inlinepolicy.h @@ -204,6 +204,8 @@ class ExtendedDefaultPolicy : public DefaultPolicy , m_FoldableExpr(0) , m_FoldableExprUn(0) , m_FoldableBranch(0) + , m_FoldableSwitch(0) + , m_Switch(0) , m_DivByCns(0) , m_ReturnsStructByValue(false) , m_IsFromValueClass(false) @@ -252,6 +254,8 @@ class ExtendedDefaultPolicy : public DefaultPolicy unsigned m_FoldableExpr; unsigned m_FoldableExprUn; unsigned m_FoldableBranch; + unsigned m_FoldableSwitch; + unsigned m_Switch; unsigned m_DivByCns; bool m_ReturnsStructByValue : 1; bool m_IsFromValueClass : 1; diff --git a/src/coreclr/jit/jitconfigvalues.h b/src/coreclr/jit/jitconfigvalues.h index b14597a870298..c1a841bfa787e 100644 --- a/src/coreclr/jit/jitconfigvalues.h +++ b/src/coreclr/jit/jitconfigvalues.h @@ -463,7 +463,8 @@ CONFIG_STRING(JitInlineReplayFile, W("JitInlineReplayFile")) // Extended version of DefaultPolicy that includes a more precise IL scan, // relies on PGO if it exists and generally is more aggressive. CONFIG_INTEGER(JitExtDefaultPolicy, W("JitExtDefaultPolicy"), 1) -CONFIG_INTEGER(JitExtDefaultPolicyMaxIL, W("JitExtDefaultPolicyMaxIL"), 0x64) +CONFIG_INTEGER(JitExtDefaultPolicyMaxIL, W("JitExtDefaultPolicyMaxIL"), 0x80) +CONFIG_INTEGER(JitExtDefaultPolicyMaxILProf, W("JitExtDefaultPolicyMaxILProf"), 0x400) CONFIG_INTEGER(JitExtDefaultPolicyMaxBB, W("JitExtDefaultPolicyMaxBB"), 7) // Inliner uses the following formula for PGO-driven decisions: diff --git a/src/libraries/System.Linq.Expressions/src/System/Linq/Expressions/DebugViewWriter.cs b/src/libraries/System.Linq.Expressions/src/System/Linq/Expressions/DebugViewWriter.cs index af967733a5a7a..2f2ecf4b38435 100644 --- a/src/libraries/System.Linq.Expressions/src/System/Linq/Expressions/DebugViewWriter.cs +++ b/src/libraries/System.Linq.Expressions/src/System/Linq/Expressions/DebugViewWriter.cs @@ -7,6 +7,7 @@ using System.Globalization; using System.IO; using System.Reflection; +using System.Runtime.CompilerServices; namespace System.Linq.Expressions { @@ -168,6 +169,7 @@ private void Out(string s, Flow after) Out(Flow.None, s, after); } + [MethodImpl(MethodImplOptions.NoInlining)] private void Out(Flow before, string s, Flow after) { switch (GetFlow(before))