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