1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2  * vim: set ts=8 sts=2 et sw=2 tw=80:
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 "jit/Ion.h"
10 #include "vm/JSScript.h"
11 
12 #include "vm/JSScript-inl.h"
13 
14 using namespace js;
15 using namespace js::jit;
16 
17 namespace js {
18 namespace jit {
19 
20 const OptimizationLevelInfo IonOptimizations;
21 
initNormalOptimizationInfo()22 void OptimizationInfo::initNormalOptimizationInfo() {
23   level_ = OptimizationLevel::Normal;
24 
25   autoTruncate_ = true;
26   eaa_ = true;
27   edgeCaseAnalysis_ = true;
28   eliminateRedundantChecks_ = true;
29   inlineInterpreted_ = true;
30   inlineNative_ = true;
31   licm_ = true;
32   gvn_ = true;
33   rangeAnalysis_ = true;
34   reordering_ = true;
35   scalarReplacement_ = true;
36   sink_ = true;
37 
38   registerAllocator_ = RegisterAllocator_Backtracking;
39 }
40 
initWasmOptimizationInfo()41 void OptimizationInfo::initWasmOptimizationInfo() {
42   // The Wasm optimization level
43   // Disables some passes that don't work well with wasm.
44 
45   // Take normal option values for not specified values.
46   initNormalOptimizationInfo();
47 
48   level_ = OptimizationLevel::Wasm;
49 
50   ama_ = true;
51   autoTruncate_ = false;
52   edgeCaseAnalysis_ = false;
53   eliminateRedundantChecks_ = false;
54   scalarReplacement_ = false;  // wasm has no objects.
55   sink_ = false;
56 }
57 
compilerWarmUpThreshold(JSScript * script,jsbytecode * pc) const58 uint32_t OptimizationInfo::compilerWarmUpThreshold(JSScript* script,
59                                                    jsbytecode* pc) const {
60   MOZ_ASSERT(pc == nullptr || pc == script->code() ||
61              JSOp(*pc) == JSOp::LoopHead);
62 
63   // The script must not start with a LoopHead op or the code below would be
64   // wrong. See bug 1602681.
65   MOZ_ASSERT_IF(pc && JSOp(*pc) == JSOp::LoopHead, pc > script->code());
66 
67   if (pc == script->code()) {
68     pc = nullptr;
69   }
70 
71   uint32_t warmUpThreshold = baseCompilerWarmUpThreshold();
72 
73   // If the script is too large to compile on the main thread, we can still
74   // compile it off thread. In these cases, increase the warm-up counter
75   // threshold to improve the compilation's type information and hopefully
76   // avoid later recompilation.
77 
78   if (script->length() > JitOptions.ionMaxScriptSizeMainThread) {
79     warmUpThreshold *=
80         (script->length() / double(JitOptions.ionMaxScriptSizeMainThread));
81   }
82 
83   uint32_t numLocalsAndArgs = NumLocalsAndArgs(script);
84   if (numLocalsAndArgs > JitOptions.ionMaxLocalsAndArgsMainThread) {
85     warmUpThreshold *=
86         (numLocalsAndArgs / double(JitOptions.ionMaxLocalsAndArgsMainThread));
87   }
88 
89   if (!pc || JitOptions.eagerIonCompilation()) {
90     return warmUpThreshold;
91   }
92 
93   // It's more efficient to enter outer loops, rather than inner loops, via OSR.
94   // To accomplish this, we use a slightly higher threshold for inner loops.
95   // Note that the loop depth is always > 0 so we will prefer non-OSR over OSR.
96   uint32_t loopDepth = LoopHeadDepthHint(pc);
97   MOZ_ASSERT(loopDepth > 0);
98   return warmUpThreshold + loopDepth * (baseCompilerWarmUpThreshold() / 10);
99 }
100 
recompileWarmUpThreshold(JSScript * script,jsbytecode * pc) const101 uint32_t OptimizationInfo::recompileWarmUpThreshold(JSScript* script,
102                                                     jsbytecode* pc) const {
103   MOZ_ASSERT(pc == script->code() || JSOp(*pc) == JSOp::LoopHead);
104 
105   uint32_t threshold = compilerWarmUpThreshold(script, pc);
106   if (JSOp(*pc) != JSOp::LoopHead || JitOptions.eagerIonCompilation()) {
107     return threshold;
108   }
109 
110   // If we're stuck in a long-running loop at a low optimization level, we have
111   // to invalidate to be able to tier up. This is worse than recompiling at
112   // function entry (because in that case we can use the lazy link mechanism and
113   // avoid invalidation completely). Use a very high recompilation threshold for
114   // loop edges so that this only affects very long-running loops.
115 
116   uint32_t loopDepth = LoopHeadDepthHint(pc);
117   MOZ_ASSERT(loopDepth > 0);
118   return threshold + loopDepth * (baseCompilerWarmUpThreshold() / 10);
119 }
120 
OptimizationLevelInfo()121 OptimizationLevelInfo::OptimizationLevelInfo() {
122   infos_[OptimizationLevel::Normal].initNormalOptimizationInfo();
123   infos_[OptimizationLevel::Wasm].initWasmOptimizationInfo();
124 }
125 
levelForScript(JSScript * script,jsbytecode * pc) const126 OptimizationLevel OptimizationLevelInfo::levelForScript(JSScript* script,
127                                                         jsbytecode* pc) const {
128   const OptimizationInfo* info = get(OptimizationLevel::Normal);
129   if (script->getWarmUpCount() < info->compilerWarmUpThreshold(script, pc)) {
130     return OptimizationLevel::DontCompile;
131   }
132 
133   return OptimizationLevel::Normal;
134 }
135 
136 }  // namespace jit
137 }  // namespace js
138