]> git.saurik.com Git - apple/javascriptcore.git/blob - ftl/FTLOSRExit.h
JavaScriptCore-7601.1.46.3.tar.gz
[apple/javascriptcore.git] / ftl / FTLOSRExit.h
1 /*
2 * Copyright (C) 2013-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 FTLOSRExit_h
27 #define FTLOSRExit_h
28
29 #if ENABLE(FTL_JIT)
30
31 #include "CodeOrigin.h"
32 #include "DFGExitProfile.h"
33 #include "DFGOSRExitBase.h"
34 #include "FTLAbbreviations.h"
35 #include "FTLExitArgumentList.h"
36 #include "FTLExitTimeObjectMaterialization.h"
37 #include "FTLExitValue.h"
38 #include "FTLFormattedValue.h"
39 #include "MethodOfGettingAValueProfile.h"
40 #include "Operands.h"
41 #include "ValueProfile.h"
42 #include "VirtualRegister.h"
43
44 namespace JSC {
45
46 class TrackedReferences;
47
48 namespace FTL {
49
50 // Tracks one OSR exit site within the FTL JIT. OSR exit in FTL works by deconstructing
51 // the crazy that is OSR down to simple SSA CFG primitives that any compiler backend
52 // (including of course LLVM) can grok and do meaningful things to. An exit is just a
53 // conditional branch in the emitted code where one destination is the continuation and
54 // the other is a basic block that performs a no-return tail-call to an exit thunk.
55 // This thunk takes as its arguments the live non-constant not-already-accounted-for
56 // bytecode state. To appreciate how this works consider the following JavaScript
57 // program, and its lowering down to LLVM IR including the relevant exits:
58 //
59 // function foo(o) {
60 // var a = o.a; // predicted int
61 // var b = o.b;
62 // var c = o.c; // NB this is dead
63 // a = a | 5; // our example OSR exit: need to check if a is an int
64 // return a + b;
65 // }
66 //
67 // Just consider the "a | 5". In the DFG IR, this looks like:
68 //
69 // BitOr(Check:Int32:@a, Int32:5)
70 //
71 // Where @a is the node for the value of the 'a' variable. Conceptually, this node can
72 // be further broken down to the following (note that this particular lowering never
73 // actually happens - we skip this step and go straight to LLVM IR - but it's still
74 // useful to see this):
75 //
76 // exitIf(@a is not int32);
77 // continuation;
78 //
79 // Where 'exitIf()' is a function that will exit if the argument is true, and
80 // 'continuation' is the stuff that we will do after the exitIf() check. (Note that
81 // FTL refers to 'exitIf()' as 'speculate()', which is in line with DFG terminology.)
82 // This then gets broken down to the following LLVM IR, assuming that %0 is the LLVM
83 // value corresponding to variable 'a', and %1 is the LLVM value for variable 'b':
84 //
85 // %2 = ... // the predictate corresponding to '@a is not int32'
86 // br i1 %2, label %3, label %4
87 // ; <label>:3
88 // call void exitThunk1(%0, %1) // pass 'a' and 'b', since they're both live-in-bytecode
89 // unreachable
90 // ; <label>:4
91 // ... // code for the continuation
92 //
93 // Where 'exitThunk1' is the IR to get the exit thunk for *this* OSR exit. Each OSR
94 // exit will appear to LLVM to have a distinct exit thunk.
95 //
96 // Note that this didn't have to pass '5', 'o', or 'c' to the exit thunk. 5 is a
97 // constant and the DFG already knows that, and can already tell the OSR exit machinery
98 // what that contant is and which bytecode variables (if any) it needs to be dropped
99 // into. This is conveyed to the exit statically, via the OSRExit data structure below.
100 // See the code for ExitValue for details. 'o' is an argument, and arguments are always
101 // "flushed" - if you never assign them then their values are still in the argument
102 // stack slots, and if you do assign them then we eagerly store them into those slots.
103 // 'c' is dead in bytecode, and the DFG knows this; we statically tell the exit thunk
104 // that it's dead and don't have to pass anything. The exit thunk will "initialize" its
105 // value to Undefined.
106 //
107 // This approach to OSR exit has a number of virtues:
108 //
109 // - It is an entirely unsurprising representation for a compiler that already groks
110 // CFG-like IRs for C-like languages. All existing analyses and transformations just
111 // work.
112 //
113 // - It lends itself naturally to modern approaches to code motion. For example, you
114 // could sink operations from above the exit to below it, if you just duplicate the
115 // operation into the OSR exit block. This is both legal and desirable. It works
116 // because the backend sees the OSR exit block as being no different than any other,
117 // and LLVM already supports sinking if it sees that a value is only partially used.
118 // Hence there exists a value that dominates the exit but is only used by the exit
119 // thunk and not by the continuation, sinking ought to kick in for that value.
120 // Hoisting operations from below it to above it is also possible, for similar
121 // reasons.
122 //
123 // - The no-return tail-call to the OSR exit thunk can be subjected to specialized
124 // code-size reduction optimizations, though this is optional. For example, instead
125 // of actually emitting a call along with all that goes with it (like placing the
126 // arguments into argument position), the backend could choose to simply inform us
127 // where it had placed the arguments and expect the callee (i.e. the exit thunk) to
128 // figure it out from there. It could also tell us what we need to do to pop stack,
129 // although again, it doesn't have to; it could just emit that code normally. We do
130 // all of these things through the patchpoint/stackmap LLVM intrinsics.
131 //
132 // - It could be extended to allow the backend to do its own exit hoisting, by using
133 // intrinsics (or meta-data, or something) to inform the backend that it's safe to
134 // make the predicate passed to 'exitIf()' more truthy.
135
136 struct OSRExit : public DFG::OSRExitBase {
137 OSRExit(
138 ExitKind, ValueFormat profileValueFormat, MethodOfGettingAValueProfile,
139 CodeOrigin, CodeOrigin originForProfile,
140 unsigned numberOfArguments, unsigned numberOfLocals);
141
142 MacroAssemblerCodeRef m_code;
143
144 // The first argument to the exit call may be a value we wish to profile.
145 // If that's the case, the format will be not Invalid and we'll have a
146 // method of getting a value profile. Note that all of the ExitArgument's
147 // are already aware of this possible off-by-one, so there is no need to
148 // correct them.
149 ValueFormat m_profileValueFormat;
150 MethodOfGettingAValueProfile m_valueProfile;
151
152 // Offset within the exit stubs of the stub for this exit.
153 unsigned m_patchableCodeOffset;
154
155 Operands<ExitValue> m_values;
156 Bag<ExitTimeObjectMaterialization> m_materializations;
157
158 uint32_t m_stackmapID;
159
160 CodeLocationJump codeLocationForRepatch(CodeBlock* ftlCodeBlock) const;
161
162 void considerAddingAsFrequentExitSite(CodeBlock* profiledCodeBlock)
163 {
164 OSRExitBase::considerAddingAsFrequentExitSite(profiledCodeBlock, ExitFromFTL);
165 }
166
167 void validateReferences(const TrackedReferences&);
168 };
169
170 } } // namespace JSC::FTL
171
172 #endif // ENABLE(FTL_JIT)
173
174 #endif // FTLOSRExit_h
175