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