InliningDecider.h 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #pragma once
  6. class InliningDecider
  7. {
  8. private:
  9. InliningThreshold threshold;
  10. Js::FunctionBody *const topFunc;
  11. bool isLoopBody; // We don't support inlining on jit loop bodies as of now.
  12. bool isInDebugMode;
  13. // These variables capture the temporary state
  14. uint32 bytecodeInlinedCount;
  15. uint32 numberOfInlineesWithLoop;
  16. public:
  17. const ExecutionMode jitMode; // Disable certain parts for certain JIT modes
  18. public:
  19. InliningDecider(Js::FunctionBody *const topFunc, bool isLoopBody, bool isInDebugMode, const ExecutionMode jitMode);
  20. ~InliningDecider();
  21. public:
  22. bool InlineIntoTopFunc() const;
  23. bool InlineIntoInliner(Js::FunctionBody *const inliner) const;
  24. Js::FunctionInfo *Inline(Js::FunctionBody *const inliner, Js::FunctionInfo* functionInfo, bool isConstructorCall, bool isPolymorphicCall, uint16 constantArgInfo, Js::ProfileId callSiteId, uint recursiveInlineDepth, bool allowRecursiveInline);
  25. Js::FunctionInfo *InlineCallSite(Js::FunctionBody *const inliner, const Js::ProfileId profiledCallSiteId, uint recursiveInlineDepth = 0);
  26. Js::FunctionInfo *GetCallSiteFuncInfo(Js::FunctionBody *const inliner, const Js::ProfileId profiledCallSiteId, bool* isConstructorCall, bool* isPolymorphicCall);
  27. uint16 GetConstantArgInfo(Js::FunctionBody *const inliner, const Js::ProfileId profiledCallSiteId);
  28. bool HasCallSiteInfo(Js::FunctionBody *const inliner, const Js::ProfileId profiledCallSiteId);
  29. uint InlinePolymorphicCallSite(Js::FunctionBody *const inliner, const Js::ProfileId profiledCallSiteId, Js::FunctionBody** functionBodyArray, uint functionBodyArrayLength, bool* canInlineArray, uint recursiveInlineDepth = 0);
  30. bool GetIsLoopBody() const { return isLoopBody;};
  31. bool ContinueInliningUserDefinedFunctions(uint32 bytecodeInlinedCount) const;
  32. bool CanRecursivelyInline(Js::FunctionBody * inlinee, Js::FunctionBody * inliner, bool allowRecursiveInlining, uint recursiveInlineDepth);
  33. bool DeciderInlineIntoInliner(Js::FunctionBody * inlinee, Js::FunctionBody * inliner, bool isConstructorCall, bool isPolymorphicCall, uint16 constantArgInfo, uint recursiveInlineDepth, bool allowRecursiveInlining);
  34. void SetAggressiveHeuristics() { this->threshold.SetAggressiveHeuristics(); }
  35. void ResetInlineHeuristics() { this->threshold.Reset(); }
  36. void SetLimitOnInlineesWithLoop(uint countOfInlineesWithLoops)
  37. {
  38. // If we have determined in TryAggressiveInlining phase there are too many inlinees with loop, just set the limit such that we don't inline them.
  39. if ((uint)this->threshold.maxNumberOfInlineesWithLoop <= countOfInlineesWithLoops)
  40. {
  41. this->threshold.maxNumberOfInlineesWithLoop = 0;
  42. }
  43. return;
  44. }
  45. void ResetState()
  46. {
  47. bytecodeInlinedCount = 0;
  48. numberOfInlineesWithLoop = 0;
  49. }
  50. uint32 GetNumberOfInlineesWithLoop() { return numberOfInlineesWithLoop; }
  51. void IncrementNumberOfInlineesWithLoop() { numberOfInlineesWithLoop++; }
  52. static bool GetBuiltInInfo(
  53. const FunctionJITTimeInfo *const funcInfo,
  54. Js::OpCode *const inlineCandidateOpCode,
  55. ValueType *const returnType);
  56. static bool GetBuiltInInfo(
  57. Js::FunctionInfo *const funcInfo,
  58. Js::OpCode *const inlineCandidateOpCode,
  59. ValueType *const returnType);
  60. #if defined(ENABLE_DEBUG_CONFIG_OPTIONS)
  61. static void TraceInlining(Js::FunctionBody *const inliner, const char16* inlineeName, const char16* inlineeFunctionIdandNumberString, uint inlineeByteCodeCount,
  62. Js::FunctionBody* topFunc, uint inlinedByteCodeCount, Js::FunctionBody *const inlinee, uint callSiteId, bool isLoopBody, uint builtIn = -1);
  63. #endif
  64. private:
  65. static bool GetBuiltInInfoCommon(
  66. uint localFuncId,
  67. Js::OpCode *const inlineCandidateOpCode,
  68. ValueType *const returnType);
  69. static bool IsInlineeLeaf(Js::FunctionBody * const inlinee)
  70. {
  71. return inlinee->HasDynamicProfileInfo()
  72. && (!PHASE_OFF(Js::InlineBuiltInCallerPhase, inlinee) ? !inlinee->HasNonBuiltInCallee() : inlinee->GetProfiledCallSiteCount() == 0)
  73. && !inlinee->GetAnyDynamicProfileInfo()->HasLdFldCallSiteInfo();
  74. }
  75. PREVENT_COPY(InliningDecider)
  76. };
  77. #if ENABLE_DEBUG_CONFIG_OPTIONS
  78. #define INLINE_VERBOSE_TRACE(...) \
  79. if (Js::Configuration::Global.flags.Verbose && Js::Configuration::Global.flags.Trace.IsEnabled(Js::InlinePhase, this->topFunc->GetSourceContextId(), this->topFunc->GetLocalFunctionId())) \
  80. { \
  81. Output::Print(__VA_ARGS__); \
  82. }
  83. #define INLINE_TRACE(...) \
  84. if (Js::Configuration::Global.flags.Trace.IsEnabled(Js::InlinePhase, topFunc->GetSourceContextId(), topFunc->GetLocalFunctionId())) \
  85. { \
  86. Output::Print(__VA_ARGS__); \
  87. }
  88. #define INLINE_TESTTRACE(...) \
  89. if (Js::Configuration::Global.flags.TestTrace.IsEnabled(Js::InlinePhase, topFunc->GetSourceContextId(), topFunc->GetLocalFunctionId())) \
  90. { \
  91. Output::Print(__VA_ARGS__); \
  92. Output::Flush(); \
  93. }
  94. #define INLINE_TESTTRACE_VERBOSE(...) \
  95. if (Js::Configuration::Global.flags.Verbose && Js::Configuration::Global.flags.TestTrace.IsEnabled(Js::InlinePhase, topFunc->GetSourceContextId(), topFunc->GetLocalFunctionId())) \
  96. { \
  97. Output::Print(__VA_ARGS__); \
  98. Output::Flush(); \
  99. }
  100. #define POLYMORPHIC_INLINE_TESTTRACE(...) \
  101. if (Js::Configuration::Global.flags.TestTrace.IsEnabled(Js::PolymorphicInlinePhase)) \
  102. { \
  103. Output::Print(__VA_ARGS__); \
  104. Output::Flush(); \
  105. }
  106. #define POLYMORPHIC_INLINE_FIXEDMETHODS_TESTTRACE(...) \
  107. if (Js::Configuration::Global.flags.TestTrace.IsEnabled(Js::PolymorphicInlineFixedMethodsPhase)) \
  108. { \
  109. Output::Print(__VA_ARGS__); \
  110. Output::Flush(); \
  111. }
  112. #define INLINE_FLUSH() \
  113. if (Js::Configuration::Global.flags.Trace.IsEnabled(Js::InlinePhase,this->topFunc->GetSourceContextId() ,this->topFunc->GetLocalFunctionId()) || Js::Configuration::Global.flags.TestTrace.IsEnabled(Js::InlinePhase)) \
  114. { \
  115. Output::Flush(); \
  116. }
  117. #else
  118. #define INLINE_VERBOSE_TRACE(...)
  119. #define POLYMORPHIC_INLINE_TESTTRACE(...)
  120. #define POLYMORPHIC_INLINE_FIXEDMETHODS_TESTTRACE(...)
  121. #define INLINE_TRACE(...)
  122. #define INLINE_FLUSH()
  123. #define INLINE_TESTTRACE(...)
  124. #define INLINE_TESTTRACE_VERBOSE(...)
  125. #endif