1/*
2 * Copyright (C) 2011, 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#pragma once
27
28#include "DFGMinifiedID.h"
29#include "DataFormat.h"
30#if ENABLE(JIT)
31#include "GPRInfo.h"
32#include "FPRInfo.h"
33#include "Reg.h"
34#endif
35#include "JSCJSValue.h"
36#include "MacroAssembler.h"
37#include "VirtualRegister.h"
38
39namespace JSC {
40
41struct DumpContext;
42struct InlineCallFrame;
43
44// Describes how to recover a given bytecode virtual register at a given
45// code point.
46enum ValueRecoveryTechnique : uint8_t {
47 // It's in a register.
48 InGPR,
49 UnboxedInt32InGPR,
50 UnboxedInt52InGPR,
51 UnboxedStrictInt52InGPR,
52 UnboxedBooleanInGPR,
53 UnboxedCellInGPR,
54#if USE(JSVALUE32_64)
55 InPair,
56#endif
57 InFPR,
58 UnboxedDoubleInFPR,
59 // It's in the stack, but at a different location.
60 DisplacedInJSStack,
61 // It's in the stack, at a different location, and it's unboxed.
62 Int32DisplacedInJSStack,
63 Int52DisplacedInJSStack,
64 StrictInt52DisplacedInJSStack,
65 DoubleDisplacedInJSStack,
66 CellDisplacedInJSStack,
67 BooleanDisplacedInJSStack,
68 // It's an Arguments object. This arises because of the simplified arguments simplification done by the DFG.
69 DirectArgumentsThatWereNotCreated,
70 ClonedArgumentsThatWereNotCreated,
71 // It's a constant.
72 Constant,
73 // Don't know how to recover it.
74 DontKnow
75};
76
77class ValueRecovery {
78public:
79 ValueRecovery()
80 : m_technique(DontKnow)
81 {
82 }
83
84 bool isSet() const { return m_technique != DontKnow; }
85 bool operator!() const { return !isSet(); }
86
87#if ENABLE(JIT)
88 static ValueRecovery inRegister(Reg reg, DataFormat dataFormat)
89 {
90 if (reg.isGPR())
91 return inGPR(reg.gpr(), dataFormat);
92
93 ASSERT(reg.isFPR());
94 return inFPR(reg.fpr(), dataFormat);
95 }
96#endif
97
98 explicit operator bool() const { return isSet(); }
99
100 static ValueRecovery inGPR(MacroAssembler::RegisterID gpr, DataFormat dataFormat)
101 {
102 ASSERT(dataFormat != DataFormatNone);
103#if USE(JSVALUE32_64)
104 ASSERT(dataFormat == DataFormatInt32 || dataFormat == DataFormatCell || dataFormat == DataFormatBoolean);
105#endif
106 ValueRecovery result;
107 if (dataFormat == DataFormatInt32)
108 result.m_technique = UnboxedInt32InGPR;
109 else if (dataFormat == DataFormatInt52)
110 result.m_technique = UnboxedInt52InGPR;
111 else if (dataFormat == DataFormatStrictInt52)
112 result.m_technique = UnboxedStrictInt52InGPR;
113 else if (dataFormat == DataFormatBoolean)
114 result.m_technique = UnboxedBooleanInGPR;
115 else if (dataFormat == DataFormatCell)
116 result.m_technique = UnboxedCellInGPR;
117 else
118 result.m_technique = InGPR;
119 UnionType u;
120 u.gpr = gpr;
121 result.m_source = WTFMove(u);
122 return result;
123 }
124
125#if USE(JSVALUE32_64)
126 static ValueRecovery inPair(MacroAssembler::RegisterID tagGPR, MacroAssembler::RegisterID payloadGPR)
127 {
128 ValueRecovery result;
129 result.m_technique = InPair;
130 UnionType u;
131 u.pair.tagGPR = tagGPR;
132 u.pair.payloadGPR = payloadGPR;
133 result.m_source = WTFMove(u);
134 return result;
135 }
136#endif
137
138 static ValueRecovery inFPR(MacroAssembler::FPRegisterID fpr, DataFormat dataFormat)
139 {
140 ASSERT(dataFormat == DataFormatDouble || dataFormat & DataFormatJS);
141 ValueRecovery result;
142 if (dataFormat == DataFormatDouble)
143 result.m_technique = UnboxedDoubleInFPR;
144 else
145 result.m_technique = InFPR;
146 UnionType u;
147 u.fpr = fpr;
148 result.m_source = WTFMove(u);
149 return result;
150 }
151
152 static ValueRecovery displacedInJSStack(VirtualRegister virtualReg, DataFormat dataFormat)
153 {
154 ValueRecovery result;
155 switch (dataFormat) {
156 case DataFormatInt32:
157 result.m_technique = Int32DisplacedInJSStack;
158 break;
159
160 case DataFormatInt52:
161 result.m_technique = Int52DisplacedInJSStack;
162 break;
163
164 case DataFormatStrictInt52:
165 result.m_technique = StrictInt52DisplacedInJSStack;
166 break;
167
168 case DataFormatDouble:
169 result.m_technique = DoubleDisplacedInJSStack;
170 break;
171
172 case DataFormatCell:
173 result.m_technique = CellDisplacedInJSStack;
174 break;
175
176 case DataFormatBoolean:
177 result.m_technique = BooleanDisplacedInJSStack;
178 break;
179
180 default:
181 ASSERT(dataFormat != DataFormatNone && dataFormat != DataFormatStorage);
182 result.m_technique = DisplacedInJSStack;
183 break;
184 }
185 UnionType u;
186 u.virtualReg = virtualReg.offset();
187 result.m_source = WTFMove(u);
188 return result;
189 }
190
191 static ValueRecovery constant(JSValue value)
192 {
193 ValueRecovery result;
194 result.m_technique = Constant;
195 UnionType u;
196 u.constant = JSValue::encode(value);
197 result.m_source = WTFMove(u);
198 return result;
199 }
200
201 static ValueRecovery directArgumentsThatWereNotCreated(DFG::MinifiedID id)
202 {
203 ValueRecovery result;
204 result.m_technique = DirectArgumentsThatWereNotCreated;
205 UnionType u;
206 u.nodeID = id.bits();
207 result.m_source = WTFMove(u);
208 return result;
209 }
210
211 static ValueRecovery clonedArgumentsThatWereNotCreated(DFG::MinifiedID id)
212 {
213 ValueRecovery result;
214 result.m_technique = ClonedArgumentsThatWereNotCreated;
215 UnionType u;
216 u.nodeID = id.bits();
217 result.m_source = WTFMove(u);
218 return result;
219 }
220
221 ValueRecoveryTechnique technique() const { return m_technique; }
222
223 bool isConstant() const { return m_technique == Constant; }
224
225 bool isInGPR() const
226 {
227 switch (m_technique) {
228 case InGPR:
229 case UnboxedInt32InGPR:
230 case UnboxedBooleanInGPR:
231 case UnboxedCellInGPR:
232 case UnboxedInt52InGPR:
233 case UnboxedStrictInt52InGPR:
234 return true;
235 default:
236 return false;
237 }
238 }
239
240 bool isInFPR() const
241 {
242 switch (m_technique) {
243 case InFPR:
244 case UnboxedDoubleInFPR:
245 return true;
246 default:
247 return false;
248 }
249 }
250
251 bool isInRegisters() const
252 {
253 return isInJSValueRegs() || isInGPR() || isInFPR();
254 }
255
256 bool isInJSStack() const
257 {
258 switch (m_technique) {
259 case DisplacedInJSStack:
260 case Int32DisplacedInJSStack:
261 case Int52DisplacedInJSStack:
262 case StrictInt52DisplacedInJSStack:
263 case DoubleDisplacedInJSStack:
264 case CellDisplacedInJSStack:
265 case BooleanDisplacedInJSStack:
266 return true;
267 default:
268 return false;
269 }
270 }
271
272 DataFormat dataFormat() const
273 {
274 switch (m_technique) {
275 case InGPR:
276 case InFPR:
277 case DisplacedInJSStack:
278 case Constant:
279#if USE(JSVALUE32_64)
280 case InPair:
281#endif
282 return DataFormatJS;
283 case UnboxedInt32InGPR:
284 case Int32DisplacedInJSStack:
285 return DataFormatInt32;
286 case UnboxedInt52InGPR:
287 case Int52DisplacedInJSStack:
288 return DataFormatInt52;
289 case UnboxedStrictInt52InGPR:
290 case StrictInt52DisplacedInJSStack:
291 return DataFormatStrictInt52;
292 case UnboxedBooleanInGPR:
293 case BooleanDisplacedInJSStack:
294 return DataFormatBoolean;
295 case UnboxedCellInGPR:
296 case CellDisplacedInJSStack:
297 return DataFormatCell;
298 case UnboxedDoubleInFPR:
299 case DoubleDisplacedInJSStack:
300 return DataFormatDouble;
301 default:
302 return DataFormatNone;
303 }
304 }
305
306 MacroAssembler::RegisterID gpr() const
307 {
308 ASSERT(isInGPR());
309 return m_source.get().gpr;
310 }
311
312#if USE(JSVALUE32_64)
313 MacroAssembler::RegisterID tagGPR() const
314 {
315 ASSERT(m_technique == InPair);
316 return m_source.get().pair.tagGPR;
317 }
318
319 MacroAssembler::RegisterID payloadGPR() const
320 {
321 ASSERT(m_technique == InPair);
322 return m_source.get().pair.payloadGPR;
323 }
324
325 bool isInJSValueRegs() const
326 {
327 return m_technique == InPair;
328 }
329
330#if ENABLE(JIT)
331 JSValueRegs jsValueRegs() const
332 {
333 ASSERT(isInJSValueRegs());
334 return JSValueRegs(tagGPR(), payloadGPR());
335 }
336#endif // ENABLE(JIT)
337#else
338 bool isInJSValueRegs() const
339 {
340 return isInGPR();
341 }
342#endif // USE(JSVALUE32_64)
343
344 MacroAssembler::FPRegisterID fpr() const
345 {
346 ASSERT(isInFPR());
347 return m_source.get().fpr;
348 }
349
350 VirtualRegister virtualRegister() const
351 {
352 ASSERT(isInJSStack());
353 return VirtualRegister(m_source.get().virtualReg);
354 }
355
356 ValueRecovery withLocalsOffset(int offset) const
357 {
358 switch (m_technique) {
359 case DisplacedInJSStack:
360 case Int32DisplacedInJSStack:
361 case DoubleDisplacedInJSStack:
362 case CellDisplacedInJSStack:
363 case BooleanDisplacedInJSStack:
364 case Int52DisplacedInJSStack:
365 case StrictInt52DisplacedInJSStack: {
366 ValueRecovery result;
367 result.m_technique = m_technique;
368 UnionType u;
369 u.virtualReg = m_source.get().virtualReg + offset;
370 result.m_source = WTFMove(u);
371 return result;
372 }
373
374 default:
375 return *this;
376 }
377 }
378
379 JSValue constant() const
380 {
381 ASSERT(isConstant());
382 return JSValue::decode(m_source.get().constant);
383 }
384
385 DFG::MinifiedID nodeID() const
386 {
387 ASSERT(m_technique == DirectArgumentsThatWereNotCreated || m_technique == ClonedArgumentsThatWereNotCreated);
388 return DFG::MinifiedID::fromBits(m_source.get().nodeID);
389 }
390
391 JSValue recover(CallFrame*) const;
392
393#if ENABLE(JIT)
394 template<typename Func>
395 void forEachReg(const Func& func)
396 {
397 switch (m_technique) {
398 case InGPR:
399 case UnboxedInt32InGPR:
400 case UnboxedBooleanInGPR:
401 case UnboxedCellInGPR:
402 case UnboxedInt52InGPR:
403 case UnboxedStrictInt52InGPR:
404 func(gpr());
405 return;
406 case InFPR:
407 case UnboxedDoubleInFPR:
408 func(fpr());
409 return;
410#if USE(JSVALUE32_64)
411 case InPair:
412 func(jsValueRegs().payloadGPR());
413 func(jsValueRegs().tagGPR());
414 return;
415#endif
416 default:
417 return;
418 }
419 }
420
421 void dumpInContext(PrintStream& out, DumpContext* context) const;
422 void dump(PrintStream& out) const;
423#endif
424
425private:
426 ValueRecoveryTechnique m_technique;
427 union UnionType {
428 MacroAssembler::RegisterID gpr;
429 MacroAssembler::FPRegisterID fpr;
430#if USE(JSVALUE32_64)
431 struct {
432 MacroAssembler::RegisterID tagGPR;
433 MacroAssembler::RegisterID payloadGPR;
434 } pair;
435#endif
436 int virtualReg;
437 EncodedJSValue constant;
438 unsigned nodeID;
439 };
440 Packed<UnionType> m_source;
441};
442static_assert(alignof(ValueRecovery) == 1);
443
444} // namespace JSC
445