-
Notifications
You must be signed in to change notification settings - Fork 1.2k
/
Copy pathInliningDecider.h
156 lines (140 loc) · 7.47 KB
/
InliningDecider.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
#pragma once
class InliningDecider
{
private:
InliningThreshold threshold;
Js::FunctionBody *const topFunc;
bool isLoopBody; // We don't support inlining on jit loop bodies as of now.
bool isInDebugMode;
// These variables capture the temporary state
uint32 bytecodeInlinedCount;
uint32 numberOfInlineesWithLoop;
public:
const ExecutionMode jitMode; // Disable certain parts for certain JIT modes
public:
InliningDecider(Js::FunctionBody *const topFunc, bool isLoopBody, bool isInDebugMode, const ExecutionMode jitMode);
~InliningDecider();
public:
bool InlineIntoTopFunc() const;
bool InlineIntoInliner(Js::FunctionBody *const inliner) const;
Js::FunctionInfo *Inline(Js::FunctionBody *const inliner, Js::FunctionInfo* functionInfo, bool isConstructorCall, bool isPolymorphicCall, bool isCallback, uint16 constantArgInfo, Js::ProfileId callSiteId, uint recursiveInlineDepth, bool allowRecursiveInline);
Js::FunctionInfo *InlineCallSite(Js::FunctionBody *const inliner, const Js::ProfileId profiledCallSiteId, uint recursiveInlineDepth = 0);
Js::FunctionInfo *GetCallSiteFuncInfo(Js::FunctionBody *const inliner, const Js::ProfileId profiledCallSiteId, bool* isConstructorCall, bool* isPolymorphicCall);
Js::FunctionInfo * InlineCallback(Js::FunctionBody *const inliner, const Js::ProfileId profiledCallSiteId, uint recursiveInlineDepth);
Js::FunctionInfo * GetCallSiteCallbackInfo(Js::FunctionBody *const inliner, const Js::ProfileId profiledCallSiteId);
Js::FunctionInfo * InlineCallApplyTarget(Js::FunctionBody *const inliner, const Js::ProfileId profiledCallSiteId, uint recursiveInlineDepth);
Js::FunctionInfo * GetCallApplyTargetInfo(Js::FunctionBody *const inliner, const Js::ProfileId profiledCallSiteId);
uint16 GetConstantArgInfo(Js::FunctionBody *const inliner, const Js::ProfileId profiledCallSiteId);
bool HasCallSiteInfo(Js::FunctionBody *const inliner, const Js::ProfileId profiledCallSiteId);
uint InlinePolymorphicCallSite(Js::FunctionBody *const inliner, const Js::ProfileId profiledCallSiteId, Js::FunctionBody** functionBodyArray, uint functionBodyArrayLength, bool* canInlineArray, uint recursiveInlineDepth = 0);
bool GetIsLoopBody() const { return isLoopBody;};
bool ContinueInliningUserDefinedFunctions(uint32 bytecodeInlinedCount) const;
bool CanRecursivelyInline(Js::FunctionBody * inlinee, Js::FunctionBody * inliner, bool allowRecursiveInlining, uint recursiveInlineDepth);
bool DeciderInlineIntoInliner(Js::FunctionBody * inlinee, Js::FunctionBody * inliner, bool isConstructorCall, bool isPolymorphicCall, uint16 constantArgInfo, uint recursiveInlineDepth, bool allowRecursiveInlining);
void SetAggressiveHeuristics() { this->threshold.SetAggressiveHeuristics(); }
void ResetInlineHeuristics() { this->threshold.Reset(); }
void SetLimitOnInlineesWithLoop(uint countOfInlineesWithLoops)
{
// 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.
if ((uint)this->threshold.maxNumberOfInlineesWithLoop <= countOfInlineesWithLoops)
{
this->threshold.maxNumberOfInlineesWithLoop = 0;
}
return;
}
void ResetState()
{
bytecodeInlinedCount = 0;
numberOfInlineesWithLoop = 0;
}
uint32 GetNumberOfInlineesWithLoop() { return numberOfInlineesWithLoop; }
void IncrementNumberOfInlineesWithLoop() { numberOfInlineesWithLoop++; }
static bool GetBuiltInInfo(
const FunctionJITTimeInfo *const funcInfo,
Js::OpCode *const inlineCandidateOpCode,
ValueType *const returnType);
static bool GetBuiltInInfo(
Js::FunctionInfo *const funcInfo,
Js::OpCode *const inlineCandidateOpCode,
ValueType *const returnType);
#if defined(ENABLE_DEBUG_CONFIG_OPTIONS)
static void TraceInlining(Js::FunctionBody *const inliner, const char16* inlineeName, const char16* inlineeFunctionIdandNumberString, uint inlineeByteCodeCount,
Js::FunctionBody* topFunc, uint inlinedByteCodeCount, Js::FunctionBody *const inlinee, uint callSiteId, bool isLoopBody, bool isCallback, uint builtIn = -1);
#endif
private:
static bool GetBuiltInInfoCommon(
uint localFuncId,
Js::OpCode *const inlineCandidateOpCode,
ValueType *const returnType);
static bool IsInlineeLeaf(Js::FunctionBody * const inlinee)
{
return inlinee->HasDynamicProfileInfo()
&& (!PHASE_OFF(Js::InlineBuiltInCallerPhase, inlinee) ? !inlinee->HasNonBuiltInCallee() : inlinee->GetProfiledCallSiteCount() == 0)
&& !inlinee->GetAnyDynamicProfileInfo()->HasLdFldCallSiteInfo();
}
PREVENT_COPY(InliningDecider)
};
#if ENABLE_DEBUG_CONFIG_OPTIONS
#define INLINE_VERBOSE_TRACE(...) \
if (Js::Configuration::Global.flags.Verbose && Js::Configuration::Global.flags.Trace.IsEnabled(Js::InlinePhase, this->topFunc->GetSourceContextId(), this->topFunc->GetLocalFunctionId())) \
{ \
Output::Print(__VA_ARGS__); \
}
#define INLINE_TRACE(...) \
if (Js::Configuration::Global.flags.Trace.IsEnabled(Js::InlinePhase, topFunc->GetSourceContextId(), topFunc->GetLocalFunctionId())) \
{ \
Output::Print(__VA_ARGS__); \
}
#define INLINE_TESTTRACE(...) \
if (Js::Configuration::Global.flags.TestTrace.IsEnabled(Js::InlinePhase, topFunc->GetSourceContextId(), topFunc->GetLocalFunctionId())) \
{ \
Output::Print(__VA_ARGS__); \
Output::Flush(); \
}
#define INLINE_TRACE_AND_TESTTRACE(...) \
INLINE_TRACE(__VA_ARGS__)\
INLINE_TESTTRACE(__VA_ARGS__)
#define INLINE_TESTTRACE_VERBOSE(...) \
if (Js::Configuration::Global.flags.Verbose && Js::Configuration::Global.flags.TestTrace.IsEnabled(Js::InlinePhase, topFunc->GetSourceContextId(), topFunc->GetLocalFunctionId())) \
{ \
Output::Print(__VA_ARGS__); \
Output::Flush(); \
}
#define POLYMORPHIC_INLINE_TESTTRACE(...) \
if (Js::Configuration::Global.flags.TestTrace.IsEnabled(Js::PolymorphicInlinePhase)) \
{ \
Output::Print(__VA_ARGS__); \
Output::Flush(); \
}
#define POLYMORPHIC_INLINE_FIXEDMETHODS_TESTTRACE(...) \
if (Js::Configuration::Global.flags.TestTrace.IsEnabled(Js::PolymorphicInlineFixedMethodsPhase)) \
{ \
Output::Print(__VA_ARGS__); \
Output::Flush(); \
}
#define INLINE_FLUSH() \
if (Js::Configuration::Global.flags.Trace.IsEnabled(Js::InlinePhase,this->topFunc->GetSourceContextId() ,this->topFunc->GetLocalFunctionId()) || Js::Configuration::Global.flags.TestTrace.IsEnabled(Js::InlinePhase)) \
{ \
Output::Flush(); \
}
#define INLINE_CALLBACKS_TRACE(...) \
if (PHASE_TESTTRACE(Js::InlineCallbacksPhase, this->topFunc) || PHASE_TRACE(Js::InlineCallbacksPhase, this->topFunc)) \
{ \
Output::Print(__VA_ARGS__); \
Output::Flush(); \
}
#else
#define INLINE_VERBOSE_TRACE(...)
#define POLYMORPHIC_INLINE_TESTTRACE(...)
#define POLYMORPHIC_INLINE_FIXEDMETHODS_TESTTRACE(...)
#define INLINE_TRACE(...)
#define INLINE_FLUSH()
#define INLINE_TESTTRACE(...)
#define INLINE_TESTTRACE_VERBOSE(...)
#define INLINE_TRACE_AND_TESTTRACE(...)
#define INLINE_CALLBACKS_TRACE(...)
#endif