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 #ifndef jit_MIRGenerator_h
8 #define jit_MIRGenerator_h
9 
10 // This file declares the data structures used to build a control-flow graph
11 // containing MIR.
12 
13 #include "mozilla/Atomics.h"
14 
15 #include <stdarg.h>
16 
17 #include "jscntxt.h"
18 #include "jscompartment.h"
19 
20 #include "jit/CompileInfo.h"
21 #include "jit/JitAllocPolicy.h"
22 #include "jit/JitCompartment.h"
23 #include "jit/MIR.h"
24 #ifdef JS_ION_PERF
25 # include "jit/PerfSpewer.h"
26 #endif
27 #include "jit/RegisterSets.h"
28 
29 namespace js {
30 namespace jit {
31 
32 class MIRGraph;
33 class OptimizationInfo;
34 
35 class MIRGenerator
36 {
37   public:
38     MIRGenerator(CompileCompartment* compartment, const JitCompileOptions& options,
39                  TempAllocator* alloc, MIRGraph* graph,
40                  const CompileInfo* info, const OptimizationInfo* optimizationInfo,
41                  bool usesSignalHandlersForAsmJSOOB = false);
42 
alloc()43     TempAllocator& alloc() {
44         return *alloc_;
45     }
graph()46     MIRGraph& graph() {
47         return *graph_;
48     }
ensureBallast()49     bool ensureBallast() {
50         return alloc().ensureBallast();
51     }
jitRuntime()52     const JitRuntime* jitRuntime() const {
53         return GetJitContext()->runtime->jitRuntime();
54     }
info()55     const CompileInfo& info() const {
56         return *info_;
57     }
optimizationInfo()58     const OptimizationInfo& optimizationInfo() const {
59         return *optimizationInfo_;
60     }
61 
62     template <typename T>
63     T* allocate(size_t count = 1) {
64         size_t bytes;
65         if (MOZ_UNLIKELY(!CalculateAllocSize<T>(count, &bytes)))
66             return nullptr;
67         return static_cast<T*>(alloc().allocate(bytes));
68     }
69 
70     // Set an error state and prints a message. Returns false so errors can be
71     // propagated up.
72     bool abort(const char* message, ...);
73     bool abortFmt(const char* message, va_list ap);
74 
errored()75     bool errored() const {
76         return error_;
77     }
78 
instrumentedProfiling()79     bool instrumentedProfiling() {
80         if (!instrumentedProfilingIsCached_) {
81             instrumentedProfiling_ = GetJitContext()->runtime->spsProfiler().enabled();
82             instrumentedProfilingIsCached_ = true;
83         }
84         return instrumentedProfiling_;
85     }
86 
isProfilerInstrumentationEnabled()87     bool isProfilerInstrumentationEnabled() {
88         return !compilingAsmJS() && instrumentedProfiling();
89     }
90 
isOptimizationTrackingEnabled()91     bool isOptimizationTrackingEnabled() {
92         return isProfilerInstrumentationEnabled() && !info().isAnalysis();
93     }
94 
safeForMinorGC()95     bool safeForMinorGC() const {
96         return safeForMinorGC_;
97     }
setNotSafeForMinorGC()98     void setNotSafeForMinorGC() {
99         safeForMinorGC_ = false;
100     }
101 
102     // Whether the main thread is trying to cancel this build.
shouldCancel(const char * why)103     bool shouldCancel(const char* why) {
104         maybePause();
105         return cancelBuild_;
106     }
cancel()107     void cancel() {
108         cancelBuild_ = true;
109     }
110 
maybePause()111     void maybePause() {
112         if (pauseBuild_ && *pauseBuild_)
113             PauseCurrentHelperThread();
114     }
setPauseFlag(mozilla::Atomic<bool,mozilla::Relaxed> * pauseBuild)115     void setPauseFlag(mozilla::Atomic<bool, mozilla::Relaxed>* pauseBuild) {
116         pauseBuild_ = pauseBuild;
117     }
118 
disable()119     void disable() {
120         abortReason_ = AbortReason_Disable;
121     }
abortReason()122     AbortReason abortReason() {
123         return abortReason_;
124     }
125 
compilingAsmJS()126     bool compilingAsmJS() const {
127         return info_->compilingAsmJS();
128     }
129 
maxAsmJSStackArgBytes()130     uint32_t maxAsmJSStackArgBytes() const {
131         MOZ_ASSERT(compilingAsmJS());
132         return maxAsmJSStackArgBytes_;
133     }
resetAsmJSMaxStackArgBytes()134     uint32_t resetAsmJSMaxStackArgBytes() {
135         MOZ_ASSERT(compilingAsmJS());
136         uint32_t old = maxAsmJSStackArgBytes_;
137         maxAsmJSStackArgBytes_ = 0;
138         return old;
139     }
setAsmJSMaxStackArgBytes(uint32_t n)140     void setAsmJSMaxStackArgBytes(uint32_t n) {
141         MOZ_ASSERT(compilingAsmJS());
142         maxAsmJSStackArgBytes_ = n;
143     }
setPerformsCall()144     void setPerformsCall() {
145         performsCall_ = true;
146     }
performsCall()147     bool performsCall() const {
148         return performsCall_;
149     }
150     // Traverses the graph to find if there's any SIMD instruction. Costful but
151     // the value is cached, so don't worry about calling it several times.
152     bool usesSimd();
153 
modifiesFrameArguments()154     bool modifiesFrameArguments() const {
155         return modifiesFrameArguments_;
156     }
157 
158     typedef Vector<ObjectGroup*, 0, JitAllocPolicy> ObjectGroupVector;
159 
160     // When abortReason() == AbortReason_PreliminaryObjects, all groups with
161     // preliminary objects which haven't been analyzed yet.
abortedPreliminaryGroups()162     const ObjectGroupVector& abortedPreliminaryGroups() const {
163         return abortedPreliminaryGroups_;
164     }
165 
166   public:
167     CompileCompartment* compartment;
168 
169   protected:
170     const CompileInfo* info_;
171     const OptimizationInfo* optimizationInfo_;
172     TempAllocator* alloc_;
173     JSFunction* fun_;
174     uint32_t nslots_;
175     MIRGraph* graph_;
176     AbortReason abortReason_;
177     bool shouldForceAbort_; // Force AbortReason_Disable
178     ObjectGroupVector abortedPreliminaryGroups_;
179     bool error_;
180     mozilla::Atomic<bool, mozilla::Relaxed>* pauseBuild_;
181     mozilla::Atomic<bool, mozilla::Relaxed> cancelBuild_;
182 
183     uint32_t maxAsmJSStackArgBytes_;
184     bool performsCall_;
185     bool usesSimd_;
186     bool usesSimdCached_;
187 
188     // Keep track of whether frame arguments are modified during execution.
189     // RegAlloc needs to know this as spilling values back to their register
190     // slots is not compatible with that.
191     bool modifiesFrameArguments_;
192 
193     bool instrumentedProfiling_;
194     bool instrumentedProfilingIsCached_;
195     bool safeForMinorGC_;
196 
197     void addAbortedPreliminaryGroup(ObjectGroup* group);
198 
199 #if defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB)
200     bool usesSignalHandlersForAsmJSOOB_;
201 #endif
202 
setForceAbort()203     void setForceAbort() {
204         shouldForceAbort_ = true;
205     }
shouldForceAbort()206     bool shouldForceAbort() {
207         return shouldForceAbort_;
208     }
209 
210 #if defined(JS_ION_PERF)
211     AsmJSPerfSpewer asmJSPerfSpewer_;
212 
213   public:
perfSpewer()214     AsmJSPerfSpewer& perfSpewer() { return asmJSPerfSpewer_; }
215 #endif
216 
217   public:
218     const JitCompileOptions options;
219 
220     bool needsAsmJSBoundsCheckBranch(const MAsmJSHeapAccess* access) const;
221     size_t foldableOffsetRange(const MAsmJSHeapAccess* access) const;
222 
223   private:
224     GraphSpewer gs_;
225 
226   public:
graphSpewer()227     GraphSpewer& graphSpewer() {
228         return gs_;
229     }
230 };
231 
232 } // namespace jit
233 } // namespace js
234 
235 #endif /* jit_MIRGenerator_h */
236