Inline refactoring: revise candidacy determination
authorAndy Ayers <andya@microsoft.com>
Mon, 7 Mar 2016 20:23:09 +0000 (12:23 -0800)
committerAndy Ayers <andya@microsoft.com>
Mon, 7 Mar 2016 21:29:27 +0000 (13:29 -0800)
Rework the code to determine the key aspects of candidacy up front
rather than figuring it out eventually. In particular this ensures
that the two stages of evaulation for inlines both start at the same
point for candidates.

This will help streamline subsequent work to move the state machine
into the policy, since the state machine is only needed for the
case where the candidate is a discretionary inline, and the policy
now tracks this directly.

For the `LegacyPolicy`, if an inline is both smaller than the always
inline size and marked force inline, attribute its inlining to its
small size.

Remove bulk of the of the "evaluation in progress" candidate
observations since they don't add much value. As a result `noteCandidate`
is not needed as an external API, and can be repurposed internally as
`setCandidate`.

Change how the prejit root case is tracked to make it explicit
from the context rather than a callback to the compiler.

Commit migrated from https://github.com/dotnet/coreclr/commit/96783862204ea1dd91e55ef4c44179535ff68514

src/coreclr/src/jit/compiler.cpp
src/coreclr/src/jit/flowgraph.cpp
src/coreclr/src/jit/importer.cpp
src/coreclr/src/jit/inline.cpp
src/coreclr/src/jit/inline.def
src/coreclr/src/jit/inline.h
src/coreclr/src/jit/inlinepolicy.cpp
src/coreclr/src/jit/inlinepolicy.h

index 8146f3a..53e24b4 100644 (file)
@@ -5059,11 +5059,6 @@ int           Compiler::compCompileHelper (CORINFO_MODULE_HANDLE            clas
 
         if (compIsForInlining())
         {
-            if (forceInline)
-            {
-                compInlineResult->noteCandidate(InlineObservation::CALLEE_IS_FORCE_INLINE);
-            }
-
             compInlineResult->noteInt(InlineObservation::CALLEE_NUMBER_OF_BASIC_BLOCKS, fgBBcount);
 
             if (compInlineResult->isFailure())
index 1bb3e1d..20bc27f 100644 (file)
@@ -4214,11 +4214,19 @@ void        Compiler::fgFindJumpTargets(const BYTE * codeAddr,
     // Keep track of constants and args on the stack.
     fgStack pushedStack;
 
+    // Observe force inline state and code size.
+    bool isForceInline = (info.compFlags & CORINFO_FLG_FORCEINLINE) != 0;
+
+    if (compInlineResult != nullptr)
+    {
+        compInlineResult->noteBool(InlineObservation::CALLEE_IS_FORCE_INLINE, isForceInline);
+        compInlineResult->noteInt(InlineObservation::CALLEE_IL_CODE_SIZE, codeSize);
+    }
+
     // Determine whether to start the state machine to estimate the size of the
     // native code for this method.
     bool useSm = false;
-    if ((codeSize > ALWAYS_INLINE_SIZE) &&
-        !(info.compFlags & CORINFO_FLG_FORCEINLINE))
+    if ((codeSize > ALWAYS_INLINE_SIZE) && !isForceInline)
     {
         // The size of the native code for this method matters for inlining
         // decisions.
@@ -4873,16 +4881,6 @@ TOO_FAR:
             }
         }
     }
-    else 
-    {
-       if (compIsForInlining()) 
-       {
-           // This method's IL was small enough that we didn't use the size model to estimate
-           // inlinability. Note that as the latest candidate reason.
-           compInlineResult->noteCandidate(InlineObservation::CALLEE_BELOW_ALWAYS_INLINE_SIZE);
-       }
-    }
-
 
     if (!compIsForInlining() && // None of the local vars in the inlinee should have address taken or been written to.
                                 // Therefore we should NOT need to enter this "if" statement.
index 9bb76f1..fa89103 100644 (file)
@@ -15706,8 +15706,8 @@ void             Compiler::impCanInlineNative(int           callsiteNativeEstima
                  calleeNativeSizeEstimate / NATIVE_CALL_SIZE_MULTIPLIER,
                  threshold / NATIVE_CALL_SIZE_MULTIPLIER, multiplier));
 
-       // Still a viable candidate....update status
-       inlineResult->noteCandidate(InlineObservation::CALLSITE_NATIVE_SIZE_ESTIMATE_OK);
+       // Candidate has passed the profitability screen, update candidacy.
+       inlineResult->note(InlineObservation::CALLSITE_NATIVE_SIZE_ESTIMATE_OK);
     }
 
 #undef NATIVE_CALL_SIZE_MULTIPLIER
@@ -15751,11 +15751,6 @@ void Compiler::impCanInlineIL(CORINFO_METHOD_HANDLE    fncHandle,
         return;
     }
 
-    if (forceInline)
-    {
-        inlineResult->noteCandidate(InlineObservation::CALLEE_IS_FORCE_INLINE);
-    }
-
     // Reject if it has too many locals.
     // This is currently an implementation limit due to fixed-size arrays in the
     // inline info, rather than a performance heuristic.
@@ -15780,9 +15775,13 @@ void Compiler::impCanInlineIL(CORINFO_METHOD_HANDLE    fncHandle,
         return;
     }
 
-    // Reject large functions
+    // Note force inline state
 
-    inlineResult->noteInt(InlineObservation::CALLEE_NUMBER_OF_IL_BYTES, codeSize);
+    inlineResult->noteBool(InlineObservation::CALLEE_IS_FORCE_INLINE, forceInline);
+
+    // Note IL code size
+
+    inlineResult->noteInt(InlineObservation::CALLEE_IL_CODE_SIZE, codeSize);
 
     if (inlineResult->isFailure())
     {
@@ -15797,9 +15796,6 @@ void Compiler::impCanInlineIL(CORINFO_METHOD_HANDLE    fncHandle,
     {
         return;
     }
-
-    // Still a viable candidate...
-    inlineResult->noteCandidate(InlineObservation::CALLEE_CAN_INLINE_IL);
 }
 
 /*****************************************************************************
@@ -15984,8 +15980,6 @@ void  Compiler::impCheckCanInline(GenTreePtr                call,
         pInfo->initClassResult = initClassResult;
 
         *(pParam->ppInlineCandidateInfo) = pInfo;
-
-        pParam->result->noteCandidate(InlineObservation::CALLEE_CHECK_CAN_INLINE_IL);
   
 _exit:
         ;
@@ -16091,14 +16085,6 @@ void Compiler::impInlineRecordArgInfo(InlineInfo *  pInlineInfo,
         printf("\n");
     }
 #endif
-
-    //
-    // The current arg does not prevent inlining.
-    //
-    // This doesn't mean that other information or other args
-    // will not prevent inlining of this method.
-    //
-    inlineResult->noteCandidate(InlineObservation::CALLSITE_ARGS_OK);
 }
 
 /*****************************************************************************
@@ -16443,7 +16429,6 @@ void  Compiler::impInlineInitVars(InlineInfo * pInlineInfo)
     pInlineInfo->hasSIMDTypeArgLocalOrReturn = foundSIMDType;
 #endif // FEATURE_SIMD
 
-    inlineResult->noteCandidate(InlineObservation::CALLSITE_LOCALS_OK);
 }
 
 
index b0519f2..0b582ca 100644 (file)
@@ -544,7 +544,8 @@ InlineResult::InlineResult(Compiler*    compiler,
     , inlReported(false)
 {
     // Set the policy
-    inlPolicy = InlinePolicy::getPolicy(compiler);
+    const bool isPrejitRoot = false;
+    inlPolicy = InlinePolicy::getPolicy(compiler, isPrejitRoot);
 
     // Get method handle for caller
     inlCaller = inlCompiler->info.compMethodHnd;
@@ -558,7 +559,7 @@ InlineResult::InlineResult(Compiler*    compiler,
 
 //------------------------------------------------------------------------
 // InlineResult: Construct an InlineResult to evaluate a particular
-// method as a possible inline candidate.
+// method as a possible inline candidate, while prejtting.
 //
 // Arguments:
 //    compiler - the compiler instance doing the prejitting
@@ -584,7 +585,8 @@ InlineResult::InlineResult(Compiler*              compiler,
     , inlReported(false)
 {
     // Set the policy
-    inlPolicy = InlinePolicy::getPolicy(compiler);
+    const bool isPrejitRoot = true;
+    inlPolicy = InlinePolicy::getPolicy(compiler, isPrejitRoot);
 }
 
 //------------------------------------------------------------------------
index 2678ee3..19a5147 100644 (file)
@@ -74,20 +74,19 @@ INLINE_OBSERVATION(TOO_MUCH_IL,               bool,   "too many il bytes",
 INLINE_OBSERVATION(ARG_FEEDS_CONSTANT_TEST,   bool,   "argument feeds constant test",  INFORMATION, CALLEE)
 INLINE_OBSERVATION(ARG_FEEDS_RANGE_CHECK,     bool,   "argument feeds range check",    INFORMATION, CALLEE)
 INLINE_OBSERVATION(BELOW_ALWAYS_INLINE_SIZE,  bool,   "below ALWAYS_INLINE size",      INFORMATION, CALLEE)
-INLINE_OBSERVATION(CAN_INLINE_IL,             bool,   "IL passes basic checks",        INFORMATION, CALLEE)
-INLINE_OBSERVATION(CHECK_CAN_INLINE_IL,       bool,   "IL passes detailed checks",     INFORMATION, CALLEE)
 INLINE_OBSERVATION(CLASS_PROMOTABLE,          bool,   "promotable value class",        INFORMATION, CALLEE)
 INLINE_OBSERVATION(HAS_SIMD,                  bool,   "has SIMD arg, local, or ret",   INFORMATION, CALLEE)
 INLINE_OBSERVATION(HAS_SWITCH,                bool,   "has switch",                    INFORMATION, CALLEE)
+INLINE_OBSERVATION(IL_CODE_SIZE,              int,    "number of bytes of IL",         INFORMATION, CALLEE)
+INLINE_OBSERVATION(IS_DISCRETIONARY_INLINE,   bool,   "can inline, check heuristics",  INFORMATION, CALLEE)
 INLINE_OBSERVATION(IS_FORCE_INLINE,           bool,   "aggressive inline attribute",   INFORMATION, CALLEE)
 INLINE_OBSERVATION(IS_INSTANCE_CTOR,          bool,   "instance constructor",          INFORMATION, CALLEE)
+INLINE_OBSERVATION(IS_MOSTLY_LOAD_STORE,      bool,   "method is mostly load/store",   INFORMATION, CALLEE)
 INLINE_OBSERVATION(LOOKS_LIKE_WRAPPER,        bool,   "thin wrapper around a call",    INFORMATION, CALLEE)
 INLINE_OBSERVATION(MAXSTACK,                  int,    "maxstack",                      INFORMATION, CALLEE)
-INLINE_OBSERVATION(IS_MOSTLY_LOAD_STORE,      bool,   "method is mostly load/store",   INFORMATION, CALLEE)
 INLINE_OBSERVATION(NATIVE_SIZE_ESTIMATE,      double, "native size estimate",          INFORMATION, CALLEE)
 INLINE_OBSERVATION(NUMBER_OF_ARGUMENTS,       int,    "number of arguments",           INFORMATION, CALLEE)
 INLINE_OBSERVATION(NUMBER_OF_BASIC_BLOCKS,    int,    "number of basic blocks",        INFORMATION, CALLEE)
-INLINE_OBSERVATION(NUMBER_OF_IL_BYTES,        int,    "number of bytes of IL",         INFORMATION, CALLEE)
 INLINE_OBSERVATION(NUMBER_OF_LOCALS,          int,    "number of locals",              INFORMATION, CALLEE)
 
 // ------ Caller Corectness ------- 
@@ -141,11 +140,9 @@ INLINE_OBSERVATION(TOO_MANY_LOCALS,           bool,   "too many locals",
 
 // ------ Call Site Information ------- 
 
-INLINE_OBSERVATION(ARGS_OK,                   bool,   "arguments suitable",            INFORMATION, CALLSITE)
 INLINE_OBSERVATION(BENEFIT_MULTIPLIER,        double, "benefit multiplier",            INFORMATION, CALLSITE)
 INLINE_OBSERVATION(CONSTANT_ARG_FEEDS_TEST,   bool,   "constant argument feeds test",  INFORMATION, CALLSITE)
 INLINE_OBSERVATION(DEPTH,                     int,    "depth",                         INFORMATION, CALLSITE)
-INLINE_OBSERVATION(LOCALS_OK,                 bool,   "locals suitable",               INFORMATION, CALLSITE)
 INLINE_OBSERVATION(NATIVE_SIZE_ESTIMATE,      double, "native size estimate",          INFORMATION, CALLSITE)
 INLINE_OBSERVATION(NATIVE_SIZE_ESTIMATE_OK,   bool,   "native size estimate ok",       INFORMATION, CALLSITE)
 
index 75367fa..625e1ea 100644 (file)
@@ -208,7 +208,7 @@ class InlinePolicy
 public:
 
     // Factory method for getting policies
-    static InlinePolicy* getPolicy(Compiler* compiler);
+    static InlinePolicy* getPolicy(Compiler* compiler, bool isPrejitRoot);
 
     // Obligatory virtual dtor
     virtual ~InlinePolicy() {}
@@ -220,9 +220,8 @@ public:
     InlineObservation getObservation() const { return inlObservation; }
 
     // Policy observations
-    virtual void noteCandidate(InlineObservation obs) = 0;
     virtual void noteSuccess() = 0;
-    virtual void note(InlineObservation obs) = 0;
+    virtual void noteBool(InlineObservation obs, bool value) = 0;
     virtual void noteFatal(InlineObservation obs) = 0;
     virtual void noteInt(InlineObservation obs, int value) = 0;
     virtual void noteDouble(InlineObservation obs, double value) = 0;
@@ -240,9 +239,10 @@ public:
 
 protected:
 
-    InlinePolicy()
+    InlinePolicy(bool isPrejitRoot)
         : inlDecision(InlineDecision::UNDECIDED)
         , inlObservation(InlineObservation::CALLEE_UNUSED_INITIAL)
+        , inlIsPrejitRoot(isPrejitRoot)
     {
         // empty
     }
@@ -255,8 +255,9 @@ private:
 
 protected:
 
-    InlineDecision inlDecision;
+    InlineDecision    inlDecision;
     InlineObservation inlObservation;
+    bool              inlIsPrejitRoot;
 };
 
 // InlineResult summarizes what is known about the viability of a
@@ -309,24 +310,6 @@ public:
         return inlDecisionIsDecided(inlPolicy->getDecision());
     }
 
-    // noteCandidate indicates the prospective inline has passed at least
-    // some of the correctness checks and is still a viable inline
-    // candidate, but no decision has been made yet.
-    //
-    // This may be called multiple times as various tests are performed
-    // and the candidate gets closer and closer to actually getting
-    // inlined.
-    void noteCandidate(InlineObservation obs)
-    {
-        assert(!isDecided());
-
-        // Check the impact, it should be INFORMATION
-        InlineImpact impact = inlGetImpact(obs);
-        assert(impact == InlineImpact::INFORMATION);
-
-        inlPolicy->noteCandidate(obs);
-    }
-
     // noteSuccess means the all the various checks have passed and
     // the inline can happen.
     void noteSuccess()
@@ -335,13 +318,24 @@ public:
         inlPolicy->noteSuccess();
     }
 
-    // Make an observation, and update internal state appropriately.
+    // Make a true observation, and update internal state
+    // appropriately.
     //
     // Caller is expected to call isFailure after this to see whether
     // more observation is desired.
     void note(InlineObservation obs)
     {
-        inlPolicy->note(obs);
+        inlPolicy->noteBool(obs, true);
+    }
+
+    // Make a boolean observation, and update internal state
+    // appropriately.
+    //
+    // Caller is expected to call isFailure after this to see whether
+    // more observation is desired.
+    void noteBool(InlineObservation obs, bool value)
+    {
+        inlPolicy->noteBool(obs, value);
     }
 
     // Make an observation that must lead to immediate failure.
index 31580af..bec5da2 100644 (file)
@@ -13,7 +13,8 @@
 // getPolicy: Factory method for getting an InlinePolicy
 //
 // Arguments:
-//    compiler - the compiler instance that will evaluate inlines
+//    compiler     - the compiler instance that will evaluate inlines
+//    isPrejitRoot - true if this policy is evaluating a prejit root
 //
 // Return Value:
 //    InlinePolicy to use in evaluating the inlines
 //    Determines which of the various policies should apply,
 //    and creates (or reuses) a policy instance to use.
 
-InlinePolicy* InlinePolicy::getPolicy(Compiler* compiler)
+InlinePolicy* InlinePolicy::getPolicy(Compiler* compiler, bool isPrejitRoot)
 {
     // For now, always create a Legacy policy.
-    InlinePolicy* policy = new (compiler, CMK_Inlining) LegacyPolicy(compiler);
+    InlinePolicy* policy = new (compiler, CMK_Inlining) LegacyPolicy(compiler, isPrejitRoot);
 
     return policy;
 }
 
 //------------------------------------------------------------------------
-// noteCandidate: handle passing a set of inlining checks successfully
-//
-// Arguments:
-//    obs      - the current obsevation
-
-void LegacyPolicy::noteCandidate(InlineObservation obs)
-{
-    assert(!inlDecisionIsDecided(inlDecision));
-
-    // Check the impact, it should be INFORMATION
-    InlineImpact impact = inlGetImpact(obs);
-    assert(impact == InlineImpact::INFORMATION);
-
-    switch (inlDecision)
-    {
-    case InlineDecision::UNDECIDED:
-    case InlineDecision::CANDIDATE:
-        // Candidate observations overwrite one another
-        inlDecision = InlineDecision::CANDIDATE;
-        inlObservation = obs;
-        break;
-    default:
-        // SUCCESS or NEVER or FAILURE or ??
-        assert(!"Unexpected inlDecision");
-        unreached();
-    }
-
-    // Now fall through to the general handling.
-    note(obs);
-}
-
-//------------------------------------------------------------------------
 // noteSuccess: handle finishing all the inlining checks successfully
 
 void LegacyPolicy::noteSuccess()
@@ -76,8 +45,9 @@ void LegacyPolicy::noteSuccess()
 //
 // Arguments:
 //    obs      - the current obsevation
+//    value    - the value of the observation
 
-void LegacyPolicy::note(InlineObservation obs)
+void LegacyPolicy::noteBool(InlineObservation obs, bool value)
 {
     // Check the impact
     InlineImpact impact = inlGetImpact(obs);
@@ -95,35 +65,43 @@ void LegacyPolicy::note(InlineObservation obs)
         switch (obs)
         {
         case InlineObservation::CALLEE_IS_FORCE_INLINE:
-            inlIsForceInline = true;
+            // We may make the force-inline observation more than
+            // once.  All observations should agree.
+            assert(!inlIsForceInlineKnown || (inlIsForceInline == value));
+            inlIsForceInline = value;
+            inlIsForceInlineKnown = true;
             break;
         case InlineObservation::CALLEE_IS_INSTANCE_CTOR:
-            inlIsInstanceCtor = true;
+            inlIsInstanceCtor = value;
             break;
         case InlineObservation::CALLEE_CLASS_PROMOTABLE:
-            inlIsFromPromotableValueClass = true;
+            inlIsFromPromotableValueClass = value;
             break;
         case InlineObservation::CALLEE_HAS_SIMD:
-            inlHasSimd = true;
+            inlHasSimd = value;
             break;
         case InlineObservation::CALLEE_LOOKS_LIKE_WRAPPER:
-            inlLooksLikeWrapperMethod = true;
+            inlLooksLikeWrapperMethod = value;
             break;
         case InlineObservation::CALLEE_ARG_FEEDS_CONSTANT_TEST:
-            inlArgFeedsConstantTest = true;
+            inlArgFeedsConstantTest = value;
             break;
         case InlineObservation::CALLEE_ARG_FEEDS_RANGE_CHECK:
-            inlArgFeedsRangeCheck = true;
+            inlArgFeedsRangeCheck = value;
             break;
         case InlineObservation::CALLEE_IS_MOSTLY_LOAD_STORE:
-            inlMethodIsMostlyLoadStore = true;
+            inlMethodIsMostlyLoadStore = value;
             break;
         case InlineObservation::CALLEE_HAS_SWITCH:
             // Pass this one on, it should cause inlining to fail.
             propagate = true;
             break;
         case InlineObservation::CALLSITE_CONSTANT_ARG_FEEDS_TEST:
-            inlConstantFeedsConstantTest = true;
+            inlConstantFeedsConstantTest = value;
+            break;
+        case InlineObservation::CALLSITE_NATIVE_SIZE_ESTIMATE_OK:
+            // Passed the profitability screen. Update candidacy.
+            setCandidate(obs);
             break;
         default:
             // Ignore the remainder for now
@@ -165,6 +143,8 @@ void LegacyPolicy::noteInt(InlineObservation obs, int value)
     {
     case InlineObservation::CALLEE_MAXSTACK:
         {
+            assert(inlIsForceInlineKnown);
+
             unsigned calleeMaxStack = static_cast<unsigned>(value);
 
             if (!inlIsForceInline && (calleeMaxStack > SMALL_STACK_SIZE))
@@ -177,6 +157,7 @@ void LegacyPolicy::noteInt(InlineObservation obs, int value)
 
     case InlineObservation::CALLEE_NUMBER_OF_BASIC_BLOCKS:
         {
+            assert(inlIsForceInlineKnown);
             assert(value != 0);
 
             unsigned basicBlockCount = static_cast<unsigned>(value);
@@ -189,14 +170,32 @@ void LegacyPolicy::noteInt(InlineObservation obs, int value)
             break;
         }
 
-    case InlineObservation::CALLEE_NUMBER_OF_IL_BYTES:
+    case InlineObservation::CALLEE_IL_CODE_SIZE:
         {
+            assert(inlIsForceInlineKnown);
             assert(value != 0);
-
             unsigned ilByteSize = static_cast<unsigned>(value);
 
-            if (!inlIsForceInline && (ilByteSize > inlCompiler->getImpInlineSize()))
+            // Now that we know size and forceinline state,
+            // update candidacy.
+            if (ilByteSize <= ALWAYS_INLINE_SIZE)
             {
+                // Candidate based on small size
+                setCandidate(InlineObservation::CALLEE_BELOW_ALWAYS_INLINE_SIZE);
+            }
+            else if (inlIsForceInline)
+            {
+                // Candidate based on force inline
+                setCandidate(InlineObservation::CALLEE_IS_FORCE_INLINE);
+            }
+            else if (ilByteSize <= inlCompiler->getImpInlineSize())
+            {
+                // Candidate, pending profitability evaluation
+                setCandidate(InlineObservation::CALLEE_IS_DISCRETIONARY_INLINE);
+            }
+            else
+            {
+                // Callee too big, not a candidate
                 setNever(InlineObservation::CALLEE_TOO_MUCH_IL);
             }
 
@@ -205,7 +204,6 @@ void LegacyPolicy::noteInt(InlineObservation obs, int value)
 
     default:
         // Ignore all other information
-        note(obs);
         break;
     }
 }
@@ -219,8 +217,9 @@ void LegacyPolicy::noteInt(InlineObservation obs, int value)
 
 void LegacyPolicy::noteDouble(InlineObservation obs, double value)
 {
+    // Ignore for now...
     (void) value;
-    note(obs);
+    (void) obs;
 }
 
 //------------------------------------------------------------------------
@@ -259,8 +258,8 @@ void LegacyPolicy::setFailure(InlineObservation obs)
     switch (inlDecision)
     {
     case InlineDecision::FAILURE:
-        // Repeated failure only ok if in prejit scan
-        assert(isPrejitScan());
+        // Repeated failure only ok if evaluating a prejit root
+        assert(inlIsPrejitRoot);
         break;
     case InlineDecision::UNDECIDED:
     case InlineDecision::CANDIDATE:
@@ -288,8 +287,8 @@ void LegacyPolicy::setNever(InlineObservation obs)
     switch (inlDecision)
     {
     case InlineDecision::NEVER:
-        // Repeated never only ok if in prejit scan
-        assert(isPrejitScan());
+        // Repeated never only ok if evaluating a prejit root
+        assert(inlIsPrejitRoot);
         break;
     case InlineDecision::UNDECIDED:
     case InlineDecision::CANDIDATE:
@@ -304,6 +303,33 @@ void LegacyPolicy::setNever(InlineObservation obs)
 }
 
 //------------------------------------------------------------------------
+// setCandidate: helper updating candidacy
+//
+// Arguments:
+//    obs      - the current obsevation
+//
+// Note:
+//    Candidate observations are handled here. If the inline has already
+//    failed, they're ignored. If there's already a candidate reason,
+//    this new reason trumps it.
+
+void LegacyPolicy::setCandidate(InlineObservation obs)
+{
+    // Ignore if this inline is going to fail.
+    if (inlDecisionIsFailure(inlDecision))
+    {
+        return;
+    }
+
+    // We should not have declared success yet.
+    assert(!inlDecisionIsSuccess(inlDecision));
+
+    // Update, overriding any previous candidacy.
+    inlDecision = InlineDecision::CANDIDATE;
+    inlObservation = obs;
+}
+
+//------------------------------------------------------------------------
 // determineMultiplier: determine benefit multiplier for this inline
 //
 // Notes: uses the accumulated set of observations to compute a
index 42047d1..4f831a1 100644 (file)
@@ -36,10 +36,11 @@ class LegacyPolicy : public InlinePolicy
 public:
 
     // Construct a LegacyPolicy
-    LegacyPolicy(Compiler* compiler)
-        : InlinePolicy()
+    LegacyPolicy(Compiler* compiler, bool isPrejitRoot)
+        : InlinePolicy(isPrejitRoot)
         , inlCompiler(compiler)
         , inlIsForceInline(false)
+        , inlIsForceInlineKnown(false)
         , inlIsInstanceCtor(false)
         , inlIsFromPromotableValueClass(false)
         , inlHasSimd(false)
@@ -53,10 +54,9 @@ public:
     }
 
     // Policy observations
-    void noteCandidate(InlineObservation obs) override;
     void noteSuccess() override;
-    void note(InlineObservation obs) override;
     void noteFatal(InlineObservation obs) override;
+    void noteBool(InlineObservation obs, bool value) override;
     void noteInt(InlineObservation obs, int value) override;
     void noteDouble(InlineObservation obs, double value) override;
 
@@ -74,22 +74,17 @@ private:
 
     // Helper methods
     void noteInternal(InlineObservation obs);
+    void setCandidate(InlineObservation obs);
     void setFailure(InlineObservation obs);
     void setNever(InlineObservation obs);
 
-    // True if this policy is being used to scan a method during
-    // prejitting.
-    bool isPrejitScan() const 
-    { 
-        return !inlCompiler->compIsForInlining(); 
-    }
-
     // Constants
     const unsigned MAX_BASIC_BLOCKS = 5;
 
     // Data members
     Compiler* inlCompiler;
     bool      inlIsForceInline :1;
+    bool      inlIsForceInlineKnown :1;
     bool      inlIsInstanceCtor :1;
     bool      inlIsFromPromotableValueClass :1;
     bool      inlHasSimd :1;