Fix reading Time zone rules using Julian days (#17672)
[platform/upstream/coreclr.git] / src / jit / inline.h
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4
5 // Inlining Support
6 //
7 // This file contains enum and class definitions and related
8 // information that the jit uses to make inlining decisions.
9 //
10 // -- ENUMS --
11 //
12 // InlineCallFrequency - rough assessment of call site frequency
13 // InlineDecision      - overall decision made about an inline
14 // InlineTarget        - target of a particular observation
15 // InlineImpact        - impact of a particular observation
16 // InlineObservation   - facts observed when considering an inline
17 //
18 // -- CLASSES --
19 //
20 // InlineResult        - accumulates observations, consults with policy
21 // InlineCandidateInfo - basic information needed for inlining
22 // InlArgInfo          - information about a candidate's argument
23 // InlLclVarInfo       - information about a candidate's local variable
24 // InlineInfo          - detailed information needed for inlining
25 // InlineContext       - class, remembers what inlines happened
26 // InlinePolicy        - class, determines policy for inlining
27 // InlineStrategy      - class, determines overall inline strategy
28 //
29 // Enums are used throughout to provide various descriptions.
30 //
31 // There are 4 sitations where inline candidacy is evaluated.  In each
32 // case an InlineResult is allocated on the stack to collect
33 // information about the inline candidate.  Each InlineResult refers
34 // to an InlinePolicy.
35 //
36 // 1. Importer Candidate Screen (impMarkInlineCandidate)
37 //
38 // Creates: InlineCandidateInfo
39 //
40 // During importing, the IL being imported is scanned to identify
41 // inline candidates. This happens both when the root method is being
42 // imported as well as when prospective inlines are being imported.
43 // Candidates are marked in the IL and given an InlineCandidateInfo.
44 //
45 // 2. Inlining Optimization Pass -- candidates (fgInline)
46 //
47 // Creates / Uses: InlineContext
48 // Creates: InlineInfo, InlArgInfo, InlLocalVarInfo
49 //
50 // During the inlining optimation pass, each candidate is further
51 // analyzed. Viable candidates will eventually inspire creation of an
52 // InlineInfo and a set of InlArgInfos (for call arguments) and
53 // InlLocalVarInfos (for callee locals).
54 //
55 // The analysis will also examine InlineContexts from relevant prior
56 // inlines. If the inline is successful, a new InlineContext will be
57 // created to remember this inline. In DEBUG builds, failing inlines
58 // also create InlineContexts.
59 //
60 // 3. Inlining Optimization Pass -- non-candidates (fgNoteNotInlineCandidate)
61 //
62 // Creates / Uses: InlineContext
63 //
64 // In DEBUG, the jit also searches for non-candidate calls to try
65 // and get a complete picture of the set of failed inlines.
66 //
67 // 4. Prejit suitability screen (compCompileHelper)
68 //
69 // When prejitting, each method is scanned to see if it is a viable
70 // inline candidate.
71
72 #ifndef _INLINE_H_
73 #define _INLINE_H_
74
75 #include "jit.h"
76 #include "gentree.h"
77
78 // Implementation limits
79
80 #ifndef LEGACY_BACKEND
81 const unsigned int MAX_INL_ARGS = 32; // does not include obj pointer
82 const unsigned int MAX_INL_LCLS = 32;
83 #else  // LEGACY_BACKEND
84 const unsigned int MAX_INL_ARGS = 10; // does not include obj pointer
85 const unsigned int MAX_INL_LCLS = 8;
86 #endif // LEGACY_BACKEND
87
88 // Forward declarations
89
90 class InlineStrategy;
91
92 // InlineCallsiteFrequency gives a rough classification of how
93 // often a call site will be excuted at runtime.
94
95 enum class InlineCallsiteFrequency
96 {
97     UNUSED, // n/a
98     RARE,   // once in a blue moon
99     BORING, // normal call site
100     WARM,   // seen during profiling
101     LOOP,   // in a loop
102     HOT     // very frequent
103 };
104
105 // InlineDecision describes the various states the jit goes through when
106 // evaluating an inline candidate. It is distinct from CorInfoInline
107 // because it must capture internal states that don't get reported back
108 // to the runtime.
109
110 enum class InlineDecision
111 {
112     UNDECIDED,
113     CANDIDATE,
114     SUCCESS,
115     FAILURE,
116     NEVER
117 };
118
119 // Translate a decision into a CorInfoInline for reporting back to the runtime.
120
121 CorInfoInline InlGetCorInfoInlineDecision(InlineDecision d);
122
123 // Get a string describing this InlineDecision
124
125 const char* InlGetDecisionString(InlineDecision d);
126
127 // True if this InlineDecsion describes a failing inline
128
129 bool InlDecisionIsFailure(InlineDecision d);
130
131 // True if this decision describes a successful inline
132
133 bool InlDecisionIsSuccess(InlineDecision d);
134
135 // True if this InlineDecision is a never inline decision
136
137 bool InlDecisionIsNever(InlineDecision d);
138
139 // True if this InlineDecision describes a viable candidate
140
141 bool InlDecisionIsCandidate(InlineDecision d);
142
143 // True if this InlineDecsion describes a decision
144
145 bool InlDecisionIsDecided(InlineDecision d);
146
147 // InlineTarget describes the possible targets of an inline observation.
148
149 enum class InlineTarget
150 {
151     CALLEE,  // observation applies to all calls to this callee
152     CALLER,  // observation applies to all calls made by this caller
153     CALLSITE // observation applies to a specific call site
154 };
155
156 // InlineImpact describe the possible impact of an inline observation.
157
158 enum class InlineImpact
159 {
160     FATAL,       // inlining impossible, unsafe to evaluate further
161     FUNDAMENTAL, // inlining impossible for fundamental reasons, deeper exploration safe
162     LIMITATION,  // inlining impossible because of jit limitations, deeper exploration safe
163     PERFORMANCE, // inlining inadvisable because of performance concerns
164     INFORMATION  // policy-free observation to provide data for later decision making
165 };
166
167 // InlineObservation describes the set of possible inline observations.
168
169 enum class InlineObservation
170 {
171 #define INLINE_OBSERVATION(name, type, description, impact, scope) scope##_##name,
172 #include "inline.def"
173 #undef INLINE_OBSERVATION
174 };
175
176 #ifdef DEBUG
177
178 // Sanity check the observation value
179
180 bool InlIsValidObservation(InlineObservation obs);
181
182 #endif // DEBUG
183
184 // Get a string describing this observation
185
186 const char* InlGetObservationString(InlineObservation obs);
187
188 // Get a string describing the target of this observation
189
190 const char* InlGetTargetString(InlineObservation obs);
191
192 // Get a string describing the impact of this observation
193
194 const char* InlGetImpactString(InlineObservation obs);
195
196 // Get the target of this observation
197
198 InlineTarget InlGetTarget(InlineObservation obs);
199
200 // Get the impact of this observation
201
202 InlineImpact InlGetImpact(InlineObservation obs);
203
204 // InlinePolicy is an abstract base class for a family of inline
205 // policies.
206
207 class InlinePolicy
208 {
209 public:
210     // Factory method for getting policies
211     static InlinePolicy* GetPolicy(Compiler* compiler, bool isPrejitRoot);
212
213     // Obligatory virtual dtor
214     virtual ~InlinePolicy()
215     {
216     }
217
218     // Get the current decision
219     InlineDecision GetDecision() const
220     {
221         return m_Decision;
222     }
223
224     // Get the observation responsible for the result
225     InlineObservation GetObservation() const
226     {
227         return m_Observation;
228     }
229
230     // Policy observations
231     virtual void NoteSuccess() = 0;
232     virtual void NoteBool(InlineObservation obs, bool value) = 0;
233     virtual void NoteFatal(InlineObservation obs) = 0;
234     virtual void NoteInt(InlineObservation obs, int value) = 0;
235
236     // Optional observations. Most policies ignore these.
237     virtual void NoteContext(InlineContext* context)
238     {
239         (void)context;
240     }
241     virtual void NoteOffset(IL_OFFSETX offset)
242     {
243         (void)offset;
244     }
245
246     // Policy determinations
247     virtual void DetermineProfitability(CORINFO_METHOD_INFO* methodInfo) = 0;
248
249     // Policy policies
250     virtual bool PropagateNeverToRuntime() const = 0;
251
252     // Policy estimates
253     virtual int CodeSizeEstimate() = 0;
254
255 #if defined(DEBUG) || defined(INLINE_DATA)
256
257     // Record observation for prior failure
258     virtual void NotePriorFailure(InlineObservation obs) = 0;
259
260     // Name of the policy
261     virtual const char* GetName() const = 0;
262     // Detailed data value dump
263     virtual void DumpData(FILE* file) const
264     {
265     }
266     // Detailed data name dump
267     virtual void DumpSchema(FILE* file) const
268     {
269     }
270     // True if this is the inline targeted by data collection
271     bool IsDataCollectionTarget()
272     {
273         return m_IsDataCollectionTarget;
274     }
275
276 #endif // defined(DEBUG) || defined(INLINE_DATA)
277
278 protected:
279     InlinePolicy(bool isPrejitRoot)
280         : m_Decision(InlineDecision::UNDECIDED)
281         , m_Observation(InlineObservation::CALLEE_UNUSED_INITIAL)
282         , m_IsPrejitRoot(isPrejitRoot)
283 #if defined(DEBUG) || defined(INLINE_DATA)
284         , m_IsDataCollectionTarget(false)
285 #endif // defined(DEBUG) || defined(INLINE_DATA)
286
287     {
288         // empty
289     }
290
291 private:
292     // No copying or assignment supported
293     InlinePolicy(const InlinePolicy&) = delete;
294     InlinePolicy& operator=(const InlinePolicy&) = delete;
295
296 protected:
297     InlineDecision    m_Decision;
298     InlineObservation m_Observation;
299     bool              m_IsPrejitRoot;
300
301 #if defined(DEBUG) || defined(INLINE_DATA)
302
303     bool m_IsDataCollectionTarget;
304
305 #endif // defined(DEBUG) || defined(INLINE_DATA)
306 };
307
308 // InlineResult summarizes what is known about the viability of a
309 // particular inline candiate.
310
311 class InlineResult
312 {
313 public:
314     // Construct a new InlineResult to help evaluate a
315     // particular call for inlining.
316     InlineResult(Compiler* compiler, GenTreeCall* call, GenTreeStmt* stmt, const char* description);
317
318     // Construct a new InlineResult to evaluate a particular
319     // method to see if it is inlineable.
320     InlineResult(Compiler* compiler, CORINFO_METHOD_HANDLE method, const char* description);
321
322     // Has the policy determined this inline should fail?
323     bool IsFailure() const
324     {
325         return InlDecisionIsFailure(m_Policy->GetDecision());
326     }
327
328     // Has the policy determined this inline will succeed?
329     bool IsSuccess() const
330     {
331         return InlDecisionIsSuccess(m_Policy->GetDecision());
332     }
333
334     // Has the policy determined this inline will fail,
335     // and that the callee should never be inlined?
336     bool IsNever() const
337     {
338         return InlDecisionIsNever(m_Policy->GetDecision());
339     }
340
341     // Has the policy determined this inline attempt is still viable?
342     bool IsCandidate() const
343     {
344         return InlDecisionIsCandidate(m_Policy->GetDecision());
345     }
346
347     // Has the policy determined this inline attempt is still viable
348     // and is a discretionary inline?
349     bool IsDiscretionaryCandidate() const
350     {
351         bool result = InlDecisionIsCandidate(m_Policy->GetDecision()) &&
352                       (m_Policy->GetObservation() == InlineObservation::CALLEE_IS_DISCRETIONARY_INLINE);
353
354         return result;
355     }
356
357     // Has the policy made a determination?
358     bool IsDecided() const
359     {
360         return InlDecisionIsDecided(m_Policy->GetDecision());
361     }
362
363     // NoteSuccess means the all the various checks have passed and
364     // the inline can happen.
365     void NoteSuccess()
366     {
367         assert(IsCandidate());
368         m_Policy->NoteSuccess();
369     }
370
371     // Make a true observation, and update internal state
372     // appropriately.
373     //
374     // Caller is expected to call isFailure after this to see whether
375     // more observation is desired.
376     void Note(InlineObservation obs)
377     {
378         m_Policy->NoteBool(obs, true);
379     }
380
381     // Make a boolean observation, and update internal state
382     // appropriately.
383     //
384     // Caller is expected to call isFailure after this to see whether
385     // more observation is desired.
386     void NoteBool(InlineObservation obs, bool value)
387     {
388         m_Policy->NoteBool(obs, value);
389     }
390
391     // Make an observation that must lead to immediate failure.
392     void NoteFatal(InlineObservation obs)
393     {
394         m_Policy->NoteFatal(obs);
395         assert(IsFailure());
396     }
397
398     // Make an observation with an int value
399     void NoteInt(InlineObservation obs, int value)
400     {
401         m_Policy->NoteInt(obs, value);
402     }
403
404 #if defined(DEBUG) || defined(INLINE_DATA)
405
406     // Record observation from an earlier failure.
407     void NotePriorFailure(InlineObservation obs)
408     {
409         m_Policy->NotePriorFailure(obs);
410         assert(IsFailure());
411     }
412
413 #endif // defined(DEBUG) || defined(INLINE_DATA)
414
415     // Determine if this inline is profitable
416     void DetermineProfitability(CORINFO_METHOD_INFO* methodInfo)
417     {
418         m_Policy->DetermineProfitability(methodInfo);
419     }
420
421     // Ensure details of this inlining process are appropriately
422     // reported when the result goes out of scope.
423     ~InlineResult()
424     {
425         Report();
426     }
427
428     // The observation leading to this particular result
429     InlineObservation GetObservation() const
430     {
431         return m_Policy->GetObservation();
432     }
433
434     // The callee handle for this result
435     CORINFO_METHOD_HANDLE GetCallee() const
436     {
437         return m_Callee;
438     }
439
440     // The call being considered
441     GenTreeCall* GetCall() const
442     {
443         return m_Call;
444     }
445
446     // Result that can be reported back to the runtime
447     CorInfoInline Result() const
448     {
449         return InlGetCorInfoInlineDecision(m_Policy->GetDecision());
450     }
451
452     // String describing the decision made
453     const char* ResultString() const
454     {
455         return InlGetDecisionString(m_Policy->GetDecision());
456     }
457
458     // String describing the reason for the decision
459     const char* ReasonString() const
460     {
461         return InlGetObservationString(m_Policy->GetObservation());
462     }
463
464     // Get the policy that evaluated this result.
465     InlinePolicy* GetPolicy() const
466     {
467         return m_Policy;
468     }
469
470     // SetReported indicates that this particular result doesn't need
471     // to be reported back to the runtime, either because the runtime
472     // already knows, or we aren't actually inlining yet.
473     void SetReported()
474     {
475         m_Reported = true;
476     }
477
478     // Get the InlineContext for this inline
479     InlineContext* GetInlineContext() const
480     {
481         return m_InlineContext;
482     }
483
484 private:
485     // No copying or assignment allowed.
486     InlineResult(const InlineResult&) = delete;
487     InlineResult& operator=(const InlineResult&) = delete;
488
489     // Report/log/dump decision as appropriate
490     void Report();
491
492     Compiler*             m_RootCompiler;
493     InlinePolicy*         m_Policy;
494     GenTreeCall*          m_Call;
495     InlineContext*        m_InlineContext;
496     CORINFO_METHOD_HANDLE m_Caller; // immediate caller's handle
497     CORINFO_METHOD_HANDLE m_Callee;
498     const char*           m_Description;
499     bool                  m_Reported;
500 };
501
502 // InlineCandidateInfo provides basic information about a particular
503 // inline candidate.
504
505 struct InlineCandidateInfo
506 {
507     DWORD                  dwRestrictions;
508     CORINFO_METHOD_INFO    methInfo;
509     unsigned               methAttr;
510     CORINFO_CLASS_HANDLE   clsHandle;
511     unsigned               clsAttr;
512     var_types              fncRetType;
513     CORINFO_METHOD_HANDLE  ilCallerHandle; // the logical IL caller of this inlinee.
514     CORINFO_CONTEXT_HANDLE exactContextHnd;
515     bool                   exactContextNeedsRuntimeLookup;
516     CorInfoInitClassResult initClassResult;
517 };
518
519 // InlArgInfo describes inline candidate argument properties.
520
521 struct InlArgInfo
522 {
523     GenTree* argNode;                     // caller node for this argument
524     GenTree* argBashTmpNode;              // tmp node created, if it may be replaced with actual arg
525     unsigned argTmpNum;                   // the argument tmp number
526     unsigned argIsUsed : 1;               // is this arg used at all?
527     unsigned argIsInvariant : 1;          // the argument is a constant or a local variable address
528     unsigned argIsLclVar : 1;             // the argument is a local variable
529     unsigned argIsThis : 1;               // the argument is the 'this' pointer
530     unsigned argHasSideEff : 1;           // the argument has side effects
531     unsigned argHasGlobRef : 1;           // the argument has a global ref
532     unsigned argHasCallerLocalRef : 1;    // the argument value depends on an aliased caller local
533     unsigned argHasTmp : 1;               // the argument will be evaluated to a temp
534     unsigned argHasLdargaOp : 1;          // Is there LDARGA(s) operation on this argument?
535     unsigned argHasStargOp : 1;           // Is there STARG(s) operation on this argument?
536     unsigned argIsByRefToStructLocal : 1; // Is this arg an address of a struct local or a normed struct local or a
537                                           // field in them?
538 };
539
540 // InlLclVarInfo describes inline candidate argument and local variable properties.
541
542 struct InlLclVarInfo
543 {
544     typeInfo  lclVerTypeInfo;
545     var_types lclTypeInfo;
546     unsigned  lclHasLdlocaOp : 1;        // Is there LDLOCA(s) operation on this local?
547     unsigned  lclHasStlocOp : 1;         // Is there a STLOC on this local?
548     unsigned  lclHasMultipleStlocOp : 1; // Is there more than one STLOC on this local
549     unsigned  lclIsPinned : 1;
550 };
551
552 // InlineInfo provides detailed information about a particular inline candidate.
553
554 struct InlineInfo
555 {
556     Compiler* InlinerCompiler; // The Compiler instance for the caller (i.e. the inliner)
557     Compiler* InlineRoot; // The Compiler instance that is the root of the inlining tree of which the owner of "this" is
558                           // a member.
559
560     CORINFO_METHOD_HANDLE fncHandle;
561     InlineCandidateInfo*  inlineCandidateInfo;
562
563     InlineResult* inlineResult;
564
565     GenTree*             retExpr; // The return expression of the inlined candidate.
566     CORINFO_CLASS_HANDLE retExprClassHnd;
567     bool                 retExprClassHndIsExact;
568
569     CORINFO_CONTEXT_HANDLE tokenLookupContextHandle; // The context handle that will be passed to
570                                                      // impTokenLookupContextHandle in Inlinee's Compiler.
571
572     unsigned      argCnt;
573     InlArgInfo    inlArgInfo[MAX_INL_ARGS + 1];
574     int           lclTmpNum[MAX_INL_LCLS];                     // map local# -> temp# (-1 if unused)
575     InlLclVarInfo lclVarInfo[MAX_INL_LCLS + MAX_INL_ARGS + 1]; // type information from local sig
576
577     unsigned numberOfGcRefLocals; // Number of TYP_REF and TYP_BYREF locals
578
579     bool HasGcRefLocals() const
580     {
581         return numberOfGcRefLocals > 0;
582     }
583
584     bool     thisDereferencedFirst;
585     unsigned typeContextArg;
586
587 #ifdef FEATURE_SIMD
588     bool hasSIMDTypeArgLocalOrReturn;
589 #endif // FEATURE_SIMD
590
591     GenTreeCall* iciCall;  // The GT_CALL node to be inlined.
592     GenTreeStmt* iciStmt;  // The statement iciCall is in.
593     BasicBlock*  iciBlock; // The basic block iciStmt is in.
594 };
595
596 // InlineContext tracks the inline history in a method.
597 //
598 // Notes:
599 //
600 // InlineContexts form a tree with the root method as the root and
601 // inlines as children. Nested inlines are represented as granchildren
602 // and so on.
603 //
604 // Leaves in the tree represent successful inlines of leaf methods.
605 // In DEBUG builds we also keep track of failed inline attempts.
606 //
607 // During inlining, all statements in the IR refer back to the
608 // InlineContext that is responsible for those statements existing.
609 // This makes it possible to detect recursion and to keep track of the
610 // depth of each inline attempt.
611
612 class InlineContext
613 {
614     // InlineContexts are created by InlineStrategies
615     friend class InlineStrategy;
616
617 public:
618 #if defined(DEBUG) || defined(INLINE_DATA)
619
620     // Dump the full subtree, including failures
621     void Dump(unsigned indent = 0);
622
623     // Dump only the success subtree, with rich data
624     void DumpData(unsigned indent = 0);
625
626     // Dump full subtree in xml format
627     void DumpXml(FILE* file = stderr, unsigned indent = 0);
628
629     // Get callee handle
630     CORINFO_METHOD_HANDLE GetCallee() const
631     {
632         return m_Callee;
633     }
634
635 #endif // defined(DEBUG) || defined(INLINE_DATA)
636
637     // Get the parent context for this context.
638     InlineContext* GetParent() const
639     {
640         return m_Parent;
641     }
642
643     // Get the code pointer for this context.
644     BYTE* GetCode() const
645     {
646         return m_Code;
647     }
648
649     // True if this context describes a successful inline.
650     bool IsSuccess() const
651     {
652         return m_Success;
653     }
654
655     // Get the observation that supported or disqualified this inline.
656     InlineObservation GetObservation() const
657     {
658         return m_Observation;
659     }
660
661     // Get the IL code size for this inline.
662     unsigned GetILSize() const
663     {
664         return m_ILSize;
665     }
666
667     // Get the native code size estimate for this inline.
668     unsigned GetCodeSizeEstimate() const
669     {
670         return m_CodeSizeEstimate;
671     }
672
673     // Get the offset of the call site
674     IL_OFFSETX GetOffset() const
675     {
676         return m_Offset;
677     }
678
679     // True if this is the root context
680     bool IsRoot() const
681     {
682         return m_Parent == nullptr;
683     }
684
685 private:
686     InlineContext(InlineStrategy* strategy);
687
688 private:
689     InlineStrategy*   m_InlineStrategy;   // overall strategy
690     InlineContext*    m_Parent;           // logical caller (parent)
691     InlineContext*    m_Child;            // first child
692     InlineContext*    m_Sibling;          // next child of the parent
693     BYTE*             m_Code;             // address of IL buffer for the method
694     unsigned          m_ILSize;           // size of IL buffer for the method
695     IL_OFFSETX        m_Offset;           // call site location within parent
696     InlineObservation m_Observation;      // what lead to this inline
697     int               m_CodeSizeEstimate; // in bytes * 10
698     bool              m_Success;          // true if this was a successful inline
699
700 #if defined(DEBUG) || defined(INLINE_DATA)
701
702     InlinePolicy*         m_Policy;  // policy that evaluated this inline
703     CORINFO_METHOD_HANDLE m_Callee;  // handle to the method
704     unsigned              m_TreeID;  // ID of the GenTreeCall
705     unsigned              m_Ordinal; // Ordinal number of this inline
706
707 #endif // defined(DEBUG) || defined(INLINE_DATA)
708 };
709
710 // The InlineStrategy holds the per-method persistent inline state.
711 // It is responsible for providing information that applies to
712 // multiple inlining decisions.
713
714 class InlineStrategy
715 {
716
717 public:
718     // Construct a new inline strategy.
719     InlineStrategy(Compiler* compiler);
720
721     // Create context for a successful inline.
722     InlineContext* NewSuccess(InlineInfo* inlineInfo);
723
724     // Create context for a failing inline.
725     InlineContext* NewFailure(GenTreeStmt* stmt, InlineResult* inlineResult);
726
727     // Compiler associated with this strategy
728     Compiler* GetCompiler() const
729     {
730         return m_Compiler;
731     }
732
733     // Root context
734     InlineContext* GetRootContext();
735
736     // Context for the last sucessful inline
737     // (or root if no inlines)
738     InlineContext* GetLastContext() const
739     {
740         return m_LastContext;
741     }
742
743     // Get IL size for maximum allowable inline
744     unsigned GetMaxInlineILSize() const
745     {
746         return m_MaxInlineSize;
747     }
748
749     // Get depth of maximum allowable inline
750     unsigned GetMaxInlineDepth() const
751     {
752         return m_MaxInlineDepth;
753     }
754
755     // Number of successful inlines into the root
756     unsigned GetInlineCount() const
757     {
758         return m_InlineCount;
759     }
760
761     // Return the current code size estimate for this method
762     int GetCurrentSizeEstimate() const
763     {
764         return m_CurrentSizeEstimate;
765     }
766
767     // Return the initial code size estimate for this method
768     int GetInitialSizeEstimate() const
769     {
770         return m_InitialSizeEstimate;
771     }
772
773     // Inform strategy that there's another call
774     void NoteCall()
775     {
776         m_CallCount++;
777     }
778
779     // Inform strategy that there's a new inline candidate.
780     void NoteCandidate()
781     {
782         m_CandidateCount++;
783     }
784
785     // Inform strategy that a candidate was assessed and determined to
786     // be unprofitable.
787     void NoteUnprofitable()
788     {
789         m_UnprofitableCandidateCount++;
790     }
791
792     // Inform strategy that a candidate has passed screening
793     // and that the jit will attempt to inline.
794     void NoteAttempt(InlineResult* result);
795
796     // Inform strategy that jit is about to import the inlinee IL.
797     void NoteImport()
798     {
799         m_ImportCount++;
800     }
801
802     // Inform strategy about the inline decision for a prejit root
803     void NotePrejitDecision(const InlineResult& r)
804     {
805         m_PrejitRootDecision    = r.GetPolicy()->GetDecision();
806         m_PrejitRootObservation = r.GetPolicy()->GetObservation();
807     }
808
809     // Dump csv header for inline stats to indicated file.
810     static void DumpCsvHeader(FILE* f);
811
812     // Dump csv data for inline stats to indicated file.
813     void DumpCsvData(FILE* f);
814
815     // See if an inline of this size would fit within the current jit
816     // time budget.
817     bool BudgetCheck(unsigned ilSize);
818
819     // Check if this method is not allowing inlines.
820     static bool IsNoInline(ICorJitInfo* info, CORINFO_METHOD_HANDLE method);
821
822 #if defined(DEBUG) || defined(INLINE_DATA)
823
824     // Dump textual description of inlines done so far.
825     void Dump();
826
827     // Dump data-format description of inlines done so far.
828     void DumpData();
829     void DumpDataEnsurePolicyIsSet();
830     void DumpDataHeader(FILE* file);
831     void DumpDataSchema(FILE* file);
832     void DumpDataContents(FILE* file);
833
834     // Dump xml-formatted description of inlines
835     void DumpXml(FILE* file = stderr, unsigned indent = 0);
836     static void FinalizeXml(FILE* file = stderr);
837
838     // Cache for file position of this method in the inline xml
839     long GetMethodXmlFilePosition()
840     {
841         return m_MethodXmlFilePosition;
842     }
843
844     void SetMethodXmlFilePosition(long val)
845     {
846         m_MethodXmlFilePosition = val;
847     }
848
849     // Set up or access random state (for use by RandomPolicy)
850     CLRRandom* GetRandom();
851
852 #endif // defined(DEBUG) || defined(INLINE_DATA)
853
854     // Some inline limit values
855     enum
856     {
857         ALWAYS_INLINE_SIZE              = 16,
858         IMPLEMENTATION_MAX_INLINE_SIZE  = _UI16_MAX,
859         IMPLEMENTATION_MAX_INLINE_DEPTH = 1000
860     };
861
862 private:
863     // Create a context for the root method.
864     InlineContext* NewRoot();
865
866     // Accounting updates for a successful or failed inline.
867     void NoteOutcome(InlineContext* context);
868
869     // Cap on allowable increase in jit time due to inlining.
870     // Multiplicative, so BUDGET = 10 means up to 10x increase
871     // in jit time.
872     enum
873     {
874         BUDGET = 10
875     };
876
877     // Estimate the jit time change because of this inline.
878     int EstimateTime(InlineContext* context);
879
880     // EstimateTime helpers
881     int EstimateRootTime(unsigned ilSize);
882     int EstimateInlineTime(unsigned ilSize);
883
884     // Estimate native code size change because of this inline.
885     int EstimateSize(InlineContext* context);
886
887 #if defined(DEBUG) || defined(INLINE_DATA)
888     static bool          s_HasDumpedDataHeader;
889     static bool          s_HasDumpedXmlHeader;
890     static CritSecObject s_XmlWriterLock;
891 #endif // defined(DEBUG) || defined(INLINE_DATA)
892
893     Compiler*         m_Compiler;
894     InlineContext*    m_RootContext;
895     InlinePolicy*     m_LastSuccessfulPolicy;
896     InlineContext*    m_LastContext;
897     InlineDecision    m_PrejitRootDecision;
898     InlineObservation m_PrejitRootObservation;
899     unsigned          m_CallCount;
900     unsigned          m_CandidateCount;
901     unsigned          m_AlwaysCandidateCount;
902     unsigned          m_ForceCandidateCount;
903     unsigned          m_DiscretionaryCandidateCount;
904     unsigned          m_UnprofitableCandidateCount;
905     unsigned          m_ImportCount;
906     unsigned          m_InlineCount;
907     unsigned          m_MaxInlineSize;
908     unsigned          m_MaxInlineDepth;
909     int               m_InitialTimeBudget;
910     int               m_InitialTimeEstimate;
911     int               m_CurrentTimeBudget;
912     int               m_CurrentTimeEstimate;
913     int               m_InitialSizeEstimate;
914     int               m_CurrentSizeEstimate;
915     bool              m_HasForceViaDiscretionary;
916
917 #if defined(DEBUG) || defined(INLINE_DATA)
918     long       m_MethodXmlFilePosition;
919     CLRRandom* m_Random;
920 #endif // defined(DEBUG) || defined(INLINE_DATA)
921 };
922
923 #endif // _INLINE_H_