1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2  * vim: set ts=8 sts=4 et sw=4 tw=99:
3  * This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #include "jit/IonOptimizationLevels.h"
8 
9 #include "jsscript.h"
10 
11 #include "jit/Ion.h"
12 
13 using namespace js;
14 using namespace js::jit;
15 
16 namespace js {
17 namespace jit {
18 
19 OptimizationInfos IonOptimizations;
20 
21 void
initNormalOptimizationInfo()22 OptimizationInfo::initNormalOptimizationInfo()
23 {
24     level_ = Optimization_Normal;
25 
26     eaa_ = true;
27     edgeCaseAnalysis_ = true;
28     eliminateRedundantChecks_ = true;
29     inlineInterpreted_ = true;
30     inlineNative_ = true;
31     eagerSimdUnbox_ = true;
32     gvn_ = true;
33     licm_ = true;
34     rangeAnalysis_ = true;
35     loopUnrolling_ = true;
36     reordering_ = true;
37     autoTruncate_ = true;
38     sincos_ = true;
39     sink_ = true;
40     registerAllocator_ = RegisterAllocator_Backtracking;
41 
42     inlineMaxBytecodePerCallSiteMainThread_ = 500;
43     inlineMaxBytecodePerCallSiteOffThread_ = 1000;
44     inlineMaxCalleeInlinedBytecodeLength_ = 3350;
45     inlineMaxTotalBytecodeLength_ = 80000;
46     inliningMaxCallerBytecodeLength_ = 1500;
47     maxInlineDepth_ = 3;
48     scalarReplacement_ = true;
49     smallFunctionMaxInlineDepth_ = 10;
50     compilerWarmUpThreshold_ = CompilerWarmupThreshold;
51     inliningWarmUpThresholdFactor_ = 0.125;
52     inliningRecompileThresholdFactor_ = 4;
53 }
54 
55 void
initAsmjsOptimizationInfo()56 OptimizationInfo::initAsmjsOptimizationInfo()
57 {
58     // The AsmJS optimization level
59     // Disables some passes that don't work well with asmjs.
60 
61     // Take normal option values for not specified values.
62     initNormalOptimizationInfo();
63 
64     ama_ = true;
65     level_ = Optimization_AsmJS;
66     eagerSimdUnbox_ = false;           // AsmJS has no boxing / unboxing.
67     edgeCaseAnalysis_ = false;
68     eliminateRedundantChecks_ = false;
69     autoTruncate_ = false;
70     sincos_ = false;
71     sink_ = false;
72     registerAllocator_ = RegisterAllocator_Backtracking;
73     scalarReplacement_ = false;        // AsmJS has no objects.
74 }
75 
76 uint32_t
compilerWarmUpThreshold(JSScript * script,jsbytecode * pc) const77 OptimizationInfo::compilerWarmUpThreshold(JSScript* script, jsbytecode* pc) const
78 {
79     MOZ_ASSERT(pc == nullptr || pc == script->code() || JSOp(*pc) == JSOP_LOOPENTRY);
80 
81     if (pc == script->code())
82         pc = nullptr;
83 
84     uint32_t warmUpThreshold = compilerWarmUpThreshold_;
85     if (JitOptions.forcedDefaultIonWarmUpThreshold.isSome())
86         warmUpThreshold = JitOptions.forcedDefaultIonWarmUpThreshold.ref();
87 
88     // If the script is too large to compile on the main thread, we can still
89     // compile it off thread. In these cases, increase the warm-up counter
90     // threshold to improve the compilation's type information and hopefully
91     // avoid later recompilation.
92 
93     if (script->length() > MAX_MAIN_THREAD_SCRIPT_SIZE)
94         warmUpThreshold *= (script->length() / (double) MAX_MAIN_THREAD_SCRIPT_SIZE);
95 
96     uint32_t numLocalsAndArgs = NumLocalsAndArgs(script);
97     if (numLocalsAndArgs > MAX_MAIN_THREAD_LOCALS_AND_ARGS)
98         warmUpThreshold *= (numLocalsAndArgs / (double) MAX_MAIN_THREAD_LOCALS_AND_ARGS);
99 
100     if (!pc || JitOptions.eagerCompilation)
101         return warmUpThreshold;
102 
103     // It's more efficient to enter outer loops, rather than inner loops, via OSR.
104     // To accomplish this, we use a slightly higher threshold for inner loops.
105     // Note that the loop depth is always > 0 so we will prefer non-OSR over OSR.
106     uint32_t loopDepth = LoopEntryDepthHint(pc);
107     MOZ_ASSERT(loopDepth > 0);
108     return warmUpThreshold + loopDepth * 100;
109 }
110 
OptimizationInfos()111 OptimizationInfos::OptimizationInfos()
112 {
113     infos_[Optimization_Normal - 1].initNormalOptimizationInfo();
114     infos_[Optimization_AsmJS - 1].initAsmjsOptimizationInfo();
115 
116 #ifdef DEBUG
117     OptimizationLevel level = firstLevel();
118     while (!isLastLevel(level)) {
119         OptimizationLevel next = nextLevel(level);
120         MOZ_ASSERT(level < next);
121         level = next;
122     }
123 #endif
124 }
125 
126 OptimizationLevel
nextLevel(OptimizationLevel level) const127 OptimizationInfos::nextLevel(OptimizationLevel level) const
128 {
129     MOZ_ASSERT(!isLastLevel(level));
130     switch (level) {
131       case Optimization_DontCompile:
132         return Optimization_Normal;
133       default:
134         MOZ_CRASH("Unknown optimization level.");
135     }
136 }
137 
138 OptimizationLevel
firstLevel() const139 OptimizationInfos::firstLevel() const
140 {
141     return nextLevel(Optimization_DontCompile);
142 }
143 
144 bool
isLastLevel(OptimizationLevel level) const145 OptimizationInfos::isLastLevel(OptimizationLevel level) const
146 {
147     return level == Optimization_Normal;
148 }
149 
150 OptimizationLevel
levelForScript(JSScript * script,jsbytecode * pc) const151 OptimizationInfos::levelForScript(JSScript* script, jsbytecode* pc) const
152 {
153     OptimizationLevel prev = Optimization_DontCompile;
154 
155     while (!isLastLevel(prev)) {
156         OptimizationLevel level = nextLevel(prev);
157         const OptimizationInfo* info = get(level);
158         if (script->getWarmUpCount() < info->compilerWarmUpThreshold(script, pc))
159             return prev;
160 
161         prev = level;
162     }
163 
164     return prev;
165 }
166 
167 } // namespace jit
168 } // namespace js
169