]>
Commit | Line | Data |
---|---|---|
81345200 | 1 | /* |
ed1e77d3 | 2 | * Copyright (C) 2013-2015 Apple Inc. All rights reserved. |
81345200 A |
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" | |
ed1e77d3 | 36 | #include "FTLExitTimeObjectMaterialization.h" |
81345200 A |
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 | ||
ed1e77d3 A |
44 | namespace JSC { |
45 | ||
46 | class TrackedReferences; | |
47 | ||
48 | namespace FTL { | |
81345200 A |
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 | |
ed1e77d3 A |
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: | |
81345200 A |
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 | // | |
ed1e77d3 A |
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): | |
81345200 A |
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, | |
ed1e77d3 A |
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. | |
81345200 A |
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. | |
81345200 A |
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; | |
ed1e77d3 | 156 | Bag<ExitTimeObjectMaterialization> m_materializations; |
81345200 A |
157 | |
158 | uint32_t m_stackmapID; | |
159 | ||
160 | CodeLocationJump codeLocationForRepatch(CodeBlock* ftlCodeBlock) const; | |
161 | ||
ed1e77d3 | 162 | void considerAddingAsFrequentExitSite(CodeBlock* profiledCodeBlock) |
81345200 | 163 | { |
ed1e77d3 | 164 | OSRExitBase::considerAddingAsFrequentExitSite(profiledCodeBlock, ExitFromFTL); |
81345200 | 165 | } |
ed1e77d3 A |
166 | |
167 | void validateReferences(const TrackedReferences&); | |
81345200 A |
168 | }; |
169 | ||
170 | } } // namespace JSC::FTL | |
171 | ||
172 | #endif // ENABLE(FTL_JIT) | |
173 | ||
174 | #endif // FTLOSRExit_h | |
175 |