]> git.saurik.com Git - apple/javascriptcore.git/blob - dfg/DFGCommon.h
df8c8ef0d319389bf348e2eafcafe7b5597c720f
[apple/javascriptcore.git] / dfg / DFGCommon.h
1 /*
2 * Copyright (C) 2011-2015 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 #ifndef DFGCommon_h
27 #define DFGCommon_h
28
29 #include "DFGCompilationMode.h"
30
31 #if ENABLE(DFG_JIT)
32
33 #include "Options.h"
34 #include "VirtualRegister.h"
35
36 namespace JSC { namespace DFG {
37
38 struct Node;
39
40 typedef uint32_t BlockIndex;
41 static const BlockIndex NoBlock = UINT_MAX;
42
43 struct NodePointerTraits {
44 static Node* defaultValue() { return 0; }
45 static bool isEmptyForDump(Node* value) { return !value; }
46 };
47
48 // Use RefChildren if the child ref counts haven't already been adjusted using
49 // other means and either of the following is true:
50 // - The node you're creating is MustGenerate.
51 // - The place where you're inserting a reference to the node you're creating
52 // will not also do RefChildren.
53 enum RefChildrenMode {
54 RefChildren,
55 DontRefChildren
56 };
57
58 // Use RefNode if you know that the node will be used from another node, and you
59 // will not already be ref'ing the node to account for that use.
60 enum RefNodeMode {
61 RefNode,
62 DontRefNode
63 };
64
65 enum SwitchKind {
66 SwitchImm,
67 SwitchChar,
68 SwitchString,
69 SwitchCell
70 };
71
72 inline bool verboseCompilationEnabled(CompilationMode mode = DFGMode)
73 {
74 return Options::verboseCompilation() || Options::dumpGraphAtEachPhase() || (isFTL(mode) && Options::verboseFTLCompilation());
75 }
76
77 inline bool logCompilationChanges(CompilationMode mode = DFGMode)
78 {
79 return verboseCompilationEnabled(mode) || Options::logCompilationChanges();
80 }
81
82 inline bool shouldDumpGraphAtEachPhase()
83 {
84 return Options::dumpGraphAtEachPhase();
85 }
86
87 inline bool validationEnabled()
88 {
89 #if !ASSERT_DISABLED
90 return true;
91 #else
92 return Options::validateGraph() || Options::validateGraphAtEachPhase();
93 #endif
94 }
95
96 inline bool enableInt52()
97 {
98 #if USE(JSVALUE64)
99 return true;
100 #else
101 return false;
102 #endif
103 }
104
105 enum NoResultTag { NoResult };
106
107 // The prediction propagator effectively does four passes, with the last pass
108 // being done by the separate FixuPhase.
109 enum PredictionPass {
110 // We're converging in a straght-forward forward flow fixpoint. This is the
111 // most conventional part of the propagator - it makes only monotonic decisions
112 // based on value profiles and rare case profiles. It ignores baseline JIT rare
113 // case profiles. The goal here is to develop a good guess of which variables
114 // are likely to be purely numerical, which generally doesn't require knowing
115 // the rare case profiles.
116 PrimaryPass,
117
118 // At this point we know what is numerical and what isn't. Non-numerical inputs
119 // to arithmetic operations will not have useful information in the Baseline JIT
120 // rare case profiles because Baseline may take slow path on non-numerical
121 // inputs even if the DFG could handle the input on the fast path. Boolean
122 // inputs are the most obvious example. This pass of prediction propagation will
123 // use Baseline rare case profiles for purely numerical operations and it will
124 // ignore them for everything else. The point of this pass is to develop a good
125 // guess of which variables are likely to be doubles.
126 //
127 // This pass is intentionally weird and goes against what is considered good
128 // form when writing a static analysis: a new data flow of booleans will cause
129 // us to ignore rare case profiles except that by then, we will have already
130 // propagated double types based on our prior assumption that we shouldn't
131 // ignore rare cases. This probably won't happen because the PrimaryPass is
132 // almost certainly going to establish what is and isn't numerical. But it's
133 // conceivable that during this pass we will discover a new boolean data flow.
134 // This ends up being sound because the prediction propagator could literally
135 // make any guesses it wants and still be sound (worst case, we OSR exit more
136 // often or use too general of types are run a bit slower). This will converge
137 // because we force monotonicity on the types of nodes and variables. So, the
138 // worst thing that can happen is that we violate basic laws of theoretical
139 // decency.
140 RareCasePass,
141
142 // At this point we know what is numerical and what isn't, and we also know what
143 // is a double and what isn't. So, we start forcing variables to be double.
144 // Doing so may have a cascading effect so this is a fixpoint. It's monotonic
145 // in the sense that once a variable is forced double, it cannot be forced in
146 // the other direction.
147 DoubleVotingPass,
148
149 // This pass occurs once we have converged. At this point we are just installing
150 // type checks based on the conclusions we have already reached. It's important
151 // for this pass to reach the same conclusions that DoubleVotingPass reached.
152 FixupPass
153 };
154
155 enum StructureRegistrationState { HaveNotStartedRegistering, AllStructuresAreRegistered };
156
157 enum StructureRegistrationResult { StructureRegisteredNormally, StructureRegisteredAndWatched };
158
159 enum OptimizationFixpointState { BeforeFixpoint, FixpointNotConverged, FixpointConverged };
160
161 // Describes the form you can expect the entire graph to be in.
162 enum GraphForm {
163 // LoadStore form means that basic blocks may freely use GetLocal, SetLocal,
164 // GetLocalUnlinked, and Flush for accessing local variables and indicating
165 // where their live ranges ought to be. Data flow between local accesses is
166 // implicit. Liveness is only explicit at block heads (variablesAtHead).
167 // This is only used by the DFG simplifier and is only preserved by same.
168 //
169 // For example, LoadStore form gives no easy way to determine which SetLocal's
170 // flow into a GetLocal. As well, LoadStore form implies no restrictions on
171 // redundancy: you can freely emit multiple GetLocals, or multiple SetLocals
172 // (or any combination thereof) to the same local in the same block. LoadStore
173 // form does not require basic blocks to declare how they affect or use locals,
174 // other than implicitly by using the local ops and by preserving
175 // variablesAtHead. Finally, LoadStore allows flexibility in how liveness of
176 // locals is extended; for example you can replace a GetLocal with a Phantom
177 // and so long as the Phantom retains the GetLocal's children (i.e. the Phi
178 // most likely) then it implies that the local is still live but that it need
179 // not be stored to the stack necessarily. This implies that Phantom can
180 // reference nodes that have no result, as long as those nodes are valid
181 // GetLocal children (i.e. Phi, SetLocal, SetArgument).
182 //
183 // LoadStore form also implies that Phis need not have children. By default,
184 // they end up having no children if you enter LoadStore using the canonical
185 // way (call Graph::dethread).
186 //
187 // LoadStore form is suitable for CFG transformations, as well as strength
188 // reduction, folding, and CSE.
189 LoadStore,
190
191 // ThreadedCPS form means that basic blocks list up-front which locals they
192 // expect to be live at the head, and which locals they make available at the
193 // tail. ThreadedCPS form also implies that:
194 //
195 // - GetLocals and SetLocals are not redundant within a basic block.
196 //
197 // - All GetLocals and Flushes are linked directly to the last access point
198 // of the variable, which must not be another GetLocal.
199 //
200 // - Phantom(Phi) is not legal, but PhantomLocal is.
201 //
202 // ThreadedCPS form is suitable for data flow analysis (CFA, prediction
203 // propagation), register allocation, and code generation.
204 ThreadedCPS,
205
206 // SSA form. See DFGSSAConversionPhase.h for a description.
207 SSA
208 };
209
210 // Describes the state of the UnionFind structure of VariableAccessData's.
211 enum UnificationState {
212 // BasicBlock-local accesses to variables are appropriately unified with each other.
213 LocallyUnified,
214
215 // Unification has been performed globally.
216 GloballyUnified
217 };
218
219 // Describes how reference counts in the graph behave.
220 enum RefCountState {
221 // Everything has refCount() == 1.
222 EverythingIsLive,
223
224 // Set after DCE has run.
225 ExactRefCount
226 };
227
228 enum OperandSpeculationMode { AutomaticOperandSpeculation, ManualOperandSpeculation };
229
230 enum ProofStatus { NeedsCheck, IsProved };
231
232 inline bool isProved(ProofStatus proofStatus)
233 {
234 ASSERT(proofStatus == IsProved || proofStatus == NeedsCheck);
235 return proofStatus == IsProved;
236 }
237
238 inline ProofStatus proofStatusForIsProved(bool isProved)
239 {
240 return isProved ? IsProved : NeedsCheck;
241 }
242
243 enum KillStatus { DoesNotKill, DoesKill };
244
245 inline bool doesKill(KillStatus killStatus)
246 {
247 ASSERT(killStatus == DoesNotKill || killStatus == DoesKill);
248 return killStatus == DoesKill;
249 }
250
251 inline KillStatus killStatusForDoesKill(bool doesKill)
252 {
253 return doesKill ? DoesKill : DoesNotKill;
254 }
255
256 enum class PlanStage {
257 Initial,
258 AfterFixup
259 };
260
261 template<typename T, typename U>
262 bool checkAndSet(T& left, U right)
263 {
264 if (left == right)
265 return false;
266 left = right;
267 return true;
268 }
269
270 // If possible, this will acquire a lock to make sure that if multiple threads
271 // start crashing at the same time, you get coherent dump output. Use this only
272 // when you're forcing a crash with diagnostics.
273 void startCrashing();
274
275 JS_EXPORT_PRIVATE bool isCrashing();
276
277 struct NodeAndIndex {
278 NodeAndIndex()
279 : node(nullptr)
280 , index(UINT_MAX)
281 {
282 }
283
284 NodeAndIndex(Node* node, unsigned index)
285 : node(node)
286 , index(index)
287 {
288 ASSERT(!node == (index == UINT_MAX));
289 }
290
291 bool operator!() const
292 {
293 return !node;
294 }
295
296 Node* node;
297 unsigned index;
298 };
299
300 // A less-than operator for strings that is useful for generating string switches. Sorts by <
301 // relation on characters. Ensures that if a is a prefix of b, then a < b.
302 bool stringLessThan(StringImpl& a, StringImpl& b);
303
304 } } // namespace JSC::DFG
305
306 namespace WTF {
307
308 void printInternal(PrintStream&, JSC::DFG::OptimizationFixpointState);
309 void printInternal(PrintStream&, JSC::DFG::GraphForm);
310 void printInternal(PrintStream&, JSC::DFG::UnificationState);
311 void printInternal(PrintStream&, JSC::DFG::RefCountState);
312 void printInternal(PrintStream&, JSC::DFG::ProofStatus);
313
314 } // namespace WTF
315
316 #endif // ENABLE(DFG_JIT)
317
318 namespace JSC { namespace DFG {
319
320 // Put things here that must be defined even if ENABLE(DFG_JIT) is false.
321
322 enum CapabilityLevel {
323 CannotCompile,
324 CanCompile,
325 CanCompileAndInline,
326 CapabilityLevelNotSet
327 };
328
329 inline bool canCompile(CapabilityLevel level)
330 {
331 switch (level) {
332 case CanCompile:
333 case CanCompileAndInline:
334 return true;
335 default:
336 return false;
337 }
338 }
339
340 inline bool canInline(CapabilityLevel level)
341 {
342 switch (level) {
343 case CanCompileAndInline:
344 return true;
345 default:
346 return false;
347 }
348 }
349
350 inline CapabilityLevel leastUpperBound(CapabilityLevel a, CapabilityLevel b)
351 {
352 switch (a) {
353 case CannotCompile:
354 return CannotCompile;
355 case CanCompile:
356 switch (b) {
357 case CanCompile:
358 case CanCompileAndInline:
359 return CanCompile;
360 default:
361 return CannotCompile;
362 }
363 case CanCompileAndInline:
364 return b;
365 case CapabilityLevelNotSet:
366 ASSERT_NOT_REACHED();
367 return CannotCompile;
368 }
369 ASSERT_NOT_REACHED();
370 return CannotCompile;
371 }
372
373 // Unconditionally disable DFG disassembly support if the DFG is not compiled in.
374 inline bool shouldShowDisassembly(CompilationMode mode = DFGMode)
375 {
376 #if ENABLE(DFG_JIT)
377 return Options::showDisassembly() || Options::showDFGDisassembly() || (isFTL(mode) && Options::showFTLDisassembly());
378 #else
379 UNUSED_PARAM(mode);
380 return false;
381 #endif
382 }
383
384 } } // namespace JSC::DFG
385
386 namespace WTF {
387
388 void printInternal(PrintStream&, JSC::DFG::CapabilityLevel);
389
390 } // namespace WTF
391
392 #endif // DFGCommon_h
393