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 {
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 result.m_source.gpr = gpr;
120 return result;
121 }
122
123#if USE(JSVALUE32_64)
124 static ValueRecovery inPair(MacroAssembler::RegisterID tagGPR, MacroAssembler::RegisterID payloadGPR)
125 {
126 ValueRecovery result;
127 result.m_technique = InPair;
128 result.m_source.pair.tagGPR = tagGPR;
129 result.m_source.pair.payloadGPR = payloadGPR;
130 return result;
131 }
132#endif
133
134 static ValueRecovery inFPR(MacroAssembler::FPRegisterID fpr, DataFormat dataFormat)
135 {
136 ASSERT(dataFormat == DataFormatDouble || dataFormat & DataFormatJS);
137 ValueRecovery result;
138 if (dataFormat == DataFormatDouble)
139 result.m_technique = UnboxedDoubleInFPR;
140 else
141 result.m_technique = InFPR;
142 result.m_source.fpr = fpr;
143 return result;
144 }
145
146 static ValueRecovery displacedInJSStack(VirtualRegister virtualReg, DataFormat dataFormat)
147 {
148 ValueRecovery result;
149 switch (dataFormat) {
150 case DataFormatInt32:
151 result.m_technique = Int32DisplacedInJSStack;
152 break;
153
154 case DataFormatInt52:
155 result.m_technique = Int52DisplacedInJSStack;
156 break;
157
158 case DataFormatStrictInt52:
159 result.m_technique = StrictInt52DisplacedInJSStack;
160 break;
161
162 case DataFormatDouble:
163 result.m_technique = DoubleDisplacedInJSStack;
164 break;
165
166 case DataFormatCell:
167 result.m_technique = CellDisplacedInJSStack;
168 break;
169
170 case DataFormatBoolean:
171 result.m_technique = BooleanDisplacedInJSStack;
172 break;
173
174 default:
175 ASSERT(dataFormat != DataFormatNone && dataFormat != DataFormatStorage);
176 result.m_technique = DisplacedInJSStack;
177 break;
178 }
179 result.m_source.virtualReg = virtualReg.offset();
180 return result;
181 }
182
183 static ValueRecovery constant(JSValue value)
184 {
185 ValueRecovery result;
186 result.m_technique = Constant;
187 result.m_source.constant = JSValue::encode(value);
188 return result;
189 }
190
191 static ValueRecovery directArgumentsThatWereNotCreated(DFG::MinifiedID id)
192 {
193 ValueRecovery result;
194 result.m_technique = DirectArgumentsThatWereNotCreated;
195 result.m_source.nodeID = id.bits();
196 return result;
197 }
198
199 static ValueRecovery clonedArgumentsThatWereNotCreated(DFG::MinifiedID id)
200 {
201 ValueRecovery result;
202 result.m_technique = ClonedArgumentsThatWereNotCreated;
203 result.m_source.nodeID = id.bits();
204 return result;
205 }
206
207 ValueRecoveryTechnique technique() const { return m_technique; }
208
209 bool isConstant() const { return m_technique == Constant; }
210
211 bool isInGPR() const
212 {
213 switch (m_technique) {
214 case InGPR:
215 case UnboxedInt32InGPR:
216 case UnboxedBooleanInGPR:
217 case UnboxedCellInGPR:
218 case UnboxedInt52InGPR:
219 case UnboxedStrictInt52InGPR:
220 return true;
221 default:
222 return false;
223 }
224 }
225
226 bool isInFPR() const
227 {
228 switch (m_technique) {
229 case InFPR:
230 case UnboxedDoubleInFPR:
231 return true;
232 default:
233 return false;
234 }
235 }
236
237 bool isInRegisters() const
238 {
239 return isInJSValueRegs() || isInGPR() || isInFPR();
240 }
241
242 bool isInJSStack() const
243 {
244 switch (m_technique) {
245 case DisplacedInJSStack:
246 case Int32DisplacedInJSStack:
247 case Int52DisplacedInJSStack:
248 case StrictInt52DisplacedInJSStack:
249 case DoubleDisplacedInJSStack:
250 case CellDisplacedInJSStack:
251 case BooleanDisplacedInJSStack:
252 return true;
253 default:
254 return false;
255 }
256 }
257
258 DataFormat dataFormat() const
259 {
260 switch (m_technique) {
261 case InGPR:
262 case InFPR:
263 case DisplacedInJSStack:
264 case Constant:
265#if USE(JSVALUE32_64)
266 case InPair:
267#endif
268 return DataFormatJS;
269 case UnboxedInt32InGPR:
270 case Int32DisplacedInJSStack:
271 return DataFormatInt32;
272 case UnboxedInt52InGPR:
273 case Int52DisplacedInJSStack:
274 return DataFormatInt52;
275 case UnboxedStrictInt52InGPR:
276 case StrictInt52DisplacedInJSStack:
277 return DataFormatStrictInt52;
278 case UnboxedBooleanInGPR:
279 case BooleanDisplacedInJSStack:
280 return DataFormatBoolean;
281 case UnboxedCellInGPR:
282 case CellDisplacedInJSStack:
283 return DataFormatCell;
284 case UnboxedDoubleInFPR:
285 case DoubleDisplacedInJSStack:
286 return DataFormatDouble;
287 default:
288 return DataFormatNone;
289 }
290 }
291
292 MacroAssembler::RegisterID gpr() const
293 {
294 ASSERT(isInGPR());
295 return m_source.gpr;
296 }
297
298#if USE(JSVALUE32_64)
299 MacroAssembler::RegisterID tagGPR() const
300 {
301 ASSERT(m_technique == InPair);
302 return m_source.pair.tagGPR;
303 }
304
305 MacroAssembler::RegisterID payloadGPR() const
306 {
307 ASSERT(m_technique == InPair);
308 return m_source.pair.payloadGPR;
309 }
310
311 bool isInJSValueRegs() const
312 {
313 return m_technique == InPair;
314 }
315
316#if ENABLE(JIT)
317 JSValueRegs jsValueRegs() const
318 {
319 ASSERT(isInJSValueRegs());
320 return JSValueRegs(tagGPR(), payloadGPR());
321 }
322#endif // ENABLE(JIT)
323#else
324 bool isInJSValueRegs() const
325 {
326 return isInGPR();
327 }
328#endif // USE(JSVALUE32_64)
329
330 MacroAssembler::FPRegisterID fpr() const
331 {
332 ASSERT(isInFPR());
333 return m_source.fpr;
334 }
335
336 VirtualRegister virtualRegister() const
337 {
338 ASSERT(isInJSStack());
339 return VirtualRegister(m_source.virtualReg);
340 }
341
342 ValueRecovery withLocalsOffset(int offset) const
343 {
344 switch (m_technique) {
345 case DisplacedInJSStack:
346 case Int32DisplacedInJSStack:
347 case DoubleDisplacedInJSStack:
348 case CellDisplacedInJSStack:
349 case BooleanDisplacedInJSStack:
350 case Int52DisplacedInJSStack:
351 case StrictInt52DisplacedInJSStack: {
352 ValueRecovery result;
353 result.m_technique = m_technique;
354 result.m_source.virtualReg = m_source.virtualReg + offset;
355 return result;
356 }
357
358 default:
359 return *this;
360 }
361 }
362
363 JSValue constant() const
364 {
365 ASSERT(isConstant());
366 return JSValue::decode(m_source.constant);
367 }
368
369 DFG::MinifiedID nodeID() const
370 {
371 ASSERT(m_technique == DirectArgumentsThatWereNotCreated || m_technique == ClonedArgumentsThatWereNotCreated);
372 return DFG::MinifiedID::fromBits(m_source.nodeID);
373 }
374
375 JSValue recover(ExecState*) const;
376
377#if ENABLE(JIT)
378 template<typename Func>
379 void forEachReg(const Func& func)
380 {
381 switch (m_technique) {
382 case InGPR:
383 case UnboxedInt32InGPR:
384 case UnboxedBooleanInGPR:
385 case UnboxedCellInGPR:
386 case UnboxedInt52InGPR:
387 case UnboxedStrictInt52InGPR:
388 func(gpr());
389 return;
390 case InFPR:
391 case UnboxedDoubleInFPR:
392 func(fpr());
393 return;
394#if USE(JSVALUE32_64)
395 case InPair:
396 func(jsValueRegs().payloadGPR());
397 func(jsValueRegs().tagGPR());
398 return;
399#endif
400 default:
401 return;
402 }
403 }
404
405 void dumpInContext(PrintStream& out, DumpContext* context) const;
406 void dump(PrintStream& out) const;
407#endif
408
409private:
410 ValueRecoveryTechnique m_technique;
411 union {
412 MacroAssembler::RegisterID gpr;
413 MacroAssembler::FPRegisterID fpr;
414#if USE(JSVALUE32_64)
415 struct {
416 MacroAssembler::RegisterID tagGPR;
417 MacroAssembler::RegisterID payloadGPR;
418 } pair;
419#endif
420 int virtualReg;
421 EncodedJSValue constant;
422 uintptr_t nodeID;
423 } m_source;
424};
425
426} // namespace JSC
427