]> git.saurik.com Git - apple/javascriptcore.git/blob - ftl/FTLExitValue.h
JavaScriptCore-7600.1.4.15.12.tar.gz
[apple/javascriptcore.git] / ftl / FTLExitValue.h
1 /*
2 * Copyright (C) 2013, 2014 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 FTLExitValue_h
27 #define FTLExitValue_h
28
29 #if ENABLE(FTL_JIT)
30
31 #include "FTLExitArgument.h"
32 #include "FTLRecoveryOpcode.h"
33 #include "JSCJSValue.h"
34 #include "VirtualRegister.h"
35 #include <wtf/PrintStream.h>
36
37 namespace JSC { namespace FTL {
38
39 // This is like ValueRecovery, but respects the way that the FTL does OSR
40 // exit: the live non-constant non-flushed values are passed as arguments
41 // to a noreturn tail call. ExitValue is hence mostly responsible for
42 // telling us the mapping between operands in bytecode and the arguments to
43 // the call.
44
45 enum ExitValueKind {
46 InvalidExitValue,
47 ExitValueDead,
48 ExitValueArgument,
49 ExitValueConstant,
50 ExitValueInJSStack,
51 ExitValueInJSStackAsInt32,
52 ExitValueInJSStackAsInt52,
53 ExitValueInJSStackAsDouble,
54 ExitValueArgumentsObjectThatWasNotCreated,
55 ExitValueRecovery
56 };
57
58 class ExitValue {
59 public:
60 ExitValue()
61 : m_kind(InvalidExitValue)
62 {
63 }
64
65 bool operator!() const { return m_kind == InvalidExitValue; }
66
67 static ExitValue dead()
68 {
69 ExitValue result;
70 result.m_kind = ExitValueDead;
71 return result;
72 }
73
74 static ExitValue inJSStack(VirtualRegister reg)
75 {
76 ExitValue result;
77 result.m_kind = ExitValueInJSStack;
78 result.u.virtualRegister = reg.offset();
79 return result;
80 }
81
82 static ExitValue inJSStackAsInt32(VirtualRegister reg)
83 {
84 ExitValue result;
85 result.m_kind = ExitValueInJSStackAsInt32;
86 result.u.virtualRegister = reg.offset();
87 return result;
88 }
89
90 static ExitValue inJSStackAsInt52(VirtualRegister reg)
91 {
92 ExitValue result;
93 result.m_kind = ExitValueInJSStackAsInt52;
94 result.u.virtualRegister = reg.offset();
95 return result;
96 }
97
98 static ExitValue inJSStackAsDouble(VirtualRegister reg)
99 {
100 ExitValue result;
101 result.m_kind = ExitValueInJSStackAsDouble;
102 result.u.virtualRegister = reg.offset();
103 return result;
104 }
105
106 static ExitValue constant(JSValue value)
107 {
108 ExitValue result;
109 result.m_kind = ExitValueConstant;
110 result.u.constant = JSValue::encode(value);
111 return result;
112 }
113
114 static ExitValue exitArgument(const ExitArgument& argument)
115 {
116 ExitValue result;
117 result.m_kind = ExitValueArgument;
118 result.u.argument = argument.representation();
119 return result;
120 }
121
122 static ExitValue argumentsObjectThatWasNotCreated()
123 {
124 ExitValue result;
125 result.m_kind = ExitValueArgumentsObjectThatWasNotCreated;
126 return result;
127 }
128
129 static ExitValue recovery(RecoveryOpcode opcode, unsigned leftArgument, unsigned rightArgument, ValueFormat format)
130 {
131 ExitValue result;
132 result.m_kind = ExitValueRecovery;
133 result.u.recovery.opcode = opcode;
134 result.u.recovery.leftArgument = leftArgument;
135 result.u.recovery.rightArgument = rightArgument;
136 result.u.recovery.format = format;
137 return result;
138 }
139
140 ExitValueKind kind() const { return m_kind; }
141
142 bool isDead() const { return kind() == ExitValueDead; }
143 bool isInJSStackSomehow() const
144 {
145 switch (kind()) {
146 case ExitValueInJSStack:
147 case ExitValueInJSStackAsInt32:
148 case ExitValueInJSStackAsInt52:
149 case ExitValueInJSStackAsDouble:
150 return true;
151 default:
152 return false;
153 }
154 }
155 bool isConstant() const { return kind() == ExitValueConstant; }
156 bool isArgument() const { return kind() == ExitValueArgument; }
157 bool isArgumentsObjectThatWasNotCreated() const { return kind() == ExitValueArgumentsObjectThatWasNotCreated; }
158 bool isRecovery() const { return kind() == ExitValueRecovery; }
159
160 ExitArgument exitArgument() const
161 {
162 ASSERT(isArgument());
163 return ExitArgument(u.argument);
164 }
165
166 unsigned leftRecoveryArgument() const
167 {
168 ASSERT(isRecovery());
169 return u.recovery.leftArgument;
170 }
171
172 unsigned rightRecoveryArgument() const
173 {
174 ASSERT(isRecovery());
175 return u.recovery.rightArgument;
176 }
177
178 ValueFormat recoveryFormat() const
179 {
180 ASSERT(isRecovery());
181 return static_cast<ValueFormat>(u.recovery.format);
182 }
183
184 RecoveryOpcode recoveryOpcode() const
185 {
186 ASSERT(isRecovery());
187 return static_cast<RecoveryOpcode>(u.recovery.opcode);
188 }
189
190 JSValue constant() const
191 {
192 ASSERT(isConstant());
193 return JSValue::decode(u.constant);
194 }
195
196 VirtualRegister virtualRegister() const
197 {
198 ASSERT(isInJSStackSomehow());
199 return VirtualRegister(u.virtualRegister);
200 }
201
202 ExitValue withVirtualRegister(VirtualRegister virtualRegister)
203 {
204 ASSERT(isInJSStackSomehow());
205 ExitValue result;
206 result.m_kind = m_kind;
207 result.u.virtualRegister = virtualRegister.offset();
208 return result;
209 }
210
211 // If it's in the JSStack somehow, this will tell you what format it's in, in a manner
212 // that is compatible with exitArgument().format(). If it's a constant or it's dead, it
213 // will claim to be a JSValue. If it's an argument then it will tell you the argument's
214 // format.
215 ValueFormat valueFormat() const
216 {
217 switch (kind()) {
218 case InvalidExitValue:
219 RELEASE_ASSERT_NOT_REACHED();
220 return InvalidValueFormat;
221
222 case ExitValueDead:
223 case ExitValueConstant:
224 case ExitValueInJSStack:
225 case ExitValueArgumentsObjectThatWasNotCreated:
226 return ValueFormatJSValue;
227
228 case ExitValueArgument:
229 return exitArgument().format();
230
231 case ExitValueInJSStackAsInt32:
232 return ValueFormatInt32;
233
234 case ExitValueInJSStackAsInt52:
235 return ValueFormatInt52;
236
237 case ExitValueInJSStackAsDouble:
238 return ValueFormatDouble;
239
240 case ExitValueRecovery:
241 return recoveryFormat();
242 }
243
244 RELEASE_ASSERT_NOT_REACHED();
245 return InvalidValueFormat;
246 }
247
248 void dump(PrintStream&) const;
249 void dumpInContext(PrintStream&, DumpContext*) const;
250
251 private:
252 ExitValueKind m_kind;
253 union {
254 ExitArgumentRepresentation argument;
255 EncodedJSValue constant;
256 int virtualRegister;
257 struct {
258 uint16_t leftArgument;
259 uint16_t rightArgument;
260 uint16_t opcode;
261 uint16_t format;
262 } recovery;
263 } u;
264 };
265
266 } } // namespace JSC::FTL
267
268 #endif // ENABLE(FTL_JIT)
269
270 #endif // FTLExitValue_h