58e735338439425cc0c31fb6e8cfc45596fe4672
[WebKit-https.git] / Source / JavaScriptCore / bytecode / ValueRecovery.h
1 /*
2  * Copyright (C) 2011 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 ValueRecovery_h
27 #define ValueRecovery_h
28
29 #include "DataFormat.h"
30 #include "GPRInfo.h"
31 #include "FPRInfo.h"
32 #include "JSCJSValue.h"
33 #include "MacroAssembler.h"
34 #include "VirtualRegister.h"
35 #include <stdio.h>
36 #include <wtf/Platform.h>
37
38 namespace JSC {
39
40 struct DumpContext;
41
42 // Describes how to recover a given bytecode virtual register at a given
43 // code point.
44 enum ValueRecoveryTechnique {
45     // It's already in the stack at the right location.
46     AlreadyInJSStack,
47     // It's already in the stack but unboxed.
48     AlreadyInJSStackAsUnboxedInt32,
49     AlreadyInJSStackAsUnboxedInt52,
50     AlreadyInJSStackAsUnboxedCell,
51     AlreadyInJSStackAsUnboxedBoolean,
52     AlreadyInJSStackAsUnboxedDouble,
53     // It's in a register.
54     InGPR,
55     UnboxedInt32InGPR,
56     UnboxedInt52InGPR,
57     UnboxedStrictInt52InGPR,
58     UnboxedBooleanInGPR,
59 #if USE(JSVALUE32_64)
60     InPair,
61 #endif
62     InFPR,
63     UInt32InGPR,
64     // It's in the stack, but at a different location.
65     DisplacedInJSStack,
66     // It's in the stack, at a different location, and it's unboxed.
67     Int32DisplacedInJSStack,
68     Int52DisplacedInJSStack,
69     StrictInt52DisplacedInJSStack,
70     DoubleDisplacedInJSStack,
71     CellDisplacedInJSStack,
72     BooleanDisplacedInJSStack,
73     // It's an Arguments object.
74     ArgumentsThatWereNotCreated,
75     // It's a constant.
76     Constant,
77     // Don't know how to recover it.
78     DontKnow
79 };
80
81 class ValueRecovery {
82 public:
83     ValueRecovery()
84         : m_technique(DontKnow)
85     {
86     }
87     
88     bool isSet() const { return m_technique != DontKnow; }
89     bool operator!() const { return !isSet(); }
90     
91     static ValueRecovery alreadyInJSStack()
92     {
93         ValueRecovery result;
94         result.m_technique = AlreadyInJSStack;
95         return result;
96     }
97     
98     static ValueRecovery alreadyInJSStackAsUnboxedInt32()
99     {
100         ValueRecovery result;
101         result.m_technique = AlreadyInJSStackAsUnboxedInt32;
102         return result;
103     }
104     
105     static ValueRecovery alreadyInJSStackAsUnboxedInt52()
106     {
107         ValueRecovery result;
108         result.m_technique = AlreadyInJSStackAsUnboxedInt52;
109         return result;
110     }
111     
112     static ValueRecovery alreadyInJSStackAsUnboxedCell()
113     {
114         ValueRecovery result;
115         result.m_technique = AlreadyInJSStackAsUnboxedCell;
116         return result;
117     }
118     
119     static ValueRecovery alreadyInJSStackAsUnboxedBoolean()
120     {
121         ValueRecovery result;
122         result.m_technique = AlreadyInJSStackAsUnboxedBoolean;
123         return result;
124     }
125     
126     static ValueRecovery alreadyInJSStackAsUnboxedDouble()
127     {
128         ValueRecovery result;
129         result.m_technique = AlreadyInJSStackAsUnboxedDouble;
130         return result;
131     }
132     
133     static ValueRecovery inGPR(MacroAssembler::RegisterID gpr, DataFormat dataFormat)
134     {
135         ASSERT(dataFormat != DataFormatNone);
136 #if USE(JSVALUE32_64)
137         ASSERT(dataFormat == DataFormatInt32 || dataFormat == DataFormatCell || dataFormat == DataFormatBoolean);
138 #endif
139         ValueRecovery result;
140         if (dataFormat == DataFormatInt32)
141             result.m_technique = UnboxedInt32InGPR;
142         else if (dataFormat == DataFormatInt52)
143             result.m_technique = UnboxedInt52InGPR;
144         else if (dataFormat == DataFormatStrictInt52)
145             result.m_technique = UnboxedStrictInt52InGPR;
146         else if (dataFormat == DataFormatBoolean)
147             result.m_technique = UnboxedBooleanInGPR;
148         else
149             result.m_technique = InGPR;
150         result.m_source.gpr = gpr;
151         return result;
152     }
153     
154     static ValueRecovery uint32InGPR(MacroAssembler::RegisterID gpr)
155     {
156         ValueRecovery result;
157         result.m_technique = UInt32InGPR;
158         result.m_source.gpr = gpr;
159         return result;
160     }
161     
162 #if USE(JSVALUE32_64)
163     static ValueRecovery inPair(MacroAssembler::RegisterID tagGPR, MacroAssembler::RegisterID payloadGPR)
164     {
165         ValueRecovery result;
166         result.m_technique = InPair;
167         result.m_source.pair.tagGPR = tagGPR;
168         result.m_source.pair.payloadGPR = payloadGPR;
169         return result;
170     }
171 #endif
172
173     static ValueRecovery inFPR(MacroAssembler::FPRegisterID fpr)
174     {
175         ValueRecovery result;
176         result.m_technique = InFPR;
177         result.m_source.fpr = fpr;
178         return result;
179     }
180     
181     static ValueRecovery displacedInJSStack(VirtualRegister virtualReg, DataFormat dataFormat)
182     {
183         ValueRecovery result;
184         switch (dataFormat) {
185         case DataFormatInt32:
186             result.m_technique = Int32DisplacedInJSStack;
187             break;
188             
189         case DataFormatInt52:
190             result.m_technique = Int52DisplacedInJSStack;
191             break;
192             
193         case DataFormatStrictInt52:
194             result.m_technique = StrictInt52DisplacedInJSStack;
195             break;
196             
197         case DataFormatDouble:
198             result.m_technique = DoubleDisplacedInJSStack;
199             break;
200
201         case DataFormatCell:
202             result.m_technique = CellDisplacedInJSStack;
203             break;
204             
205         case DataFormatBoolean:
206             result.m_technique = BooleanDisplacedInJSStack;
207             break;
208             
209         default:
210             ASSERT(dataFormat != DataFormatNone && dataFormat != DataFormatStorage);
211             result.m_technique = DisplacedInJSStack;
212             break;
213         }
214         result.m_source.virtualReg = virtualReg.offset();
215         return result;
216     }
217     
218     static ValueRecovery constant(JSValue value)
219     {
220         ValueRecovery result;
221         result.m_technique = Constant;
222         result.m_source.constant = JSValue::encode(value);
223         return result;
224     }
225     
226     static ValueRecovery argumentsThatWereNotCreated()
227     {
228         ValueRecovery result;
229         result.m_technique = ArgumentsThatWereNotCreated;
230         return result;
231     }
232     
233     ValueRecoveryTechnique technique() const { return m_technique; }
234     
235     bool isConstant() const { return m_technique == Constant; }
236     
237     bool isInRegisters() const
238     {
239         switch (m_technique) {
240         case InGPR:
241         case UnboxedInt32InGPR:
242         case UnboxedBooleanInGPR:
243 #if USE(JSVALUE32_64)
244         case InPair:
245 #endif
246         case InFPR:
247             return true;
248         default:
249             return false;
250         }
251     }
252     
253     bool isAlreadyInJSStack() const
254     {
255         switch (technique()) {
256         case AlreadyInJSStack:
257         case AlreadyInJSStackAsUnboxedInt32:
258         case AlreadyInJSStackAsUnboxedInt52:
259         case AlreadyInJSStackAsUnboxedCell:
260         case AlreadyInJSStackAsUnboxedBoolean:
261         case AlreadyInJSStackAsUnboxedDouble:
262             return true;
263         default:
264             return false;
265         }
266     }
267     
268     MacroAssembler::RegisterID gpr() const
269     {
270         ASSERT(m_technique == InGPR || m_technique == UnboxedInt32InGPR || m_technique == UnboxedBooleanInGPR || m_technique == UInt32InGPR || m_technique == UnboxedInt52InGPR || m_technique == UnboxedStrictInt52InGPR);
271         return m_source.gpr;
272     }
273     
274 #if USE(JSVALUE32_64)
275     MacroAssembler::RegisterID tagGPR() const
276     {
277         ASSERT(m_technique == InPair);
278         return m_source.pair.tagGPR;
279     }
280     
281     MacroAssembler::RegisterID payloadGPR() const
282     {
283         ASSERT(m_technique == InPair);
284         return m_source.pair.payloadGPR;
285     }
286 #endif
287     
288     MacroAssembler::FPRegisterID fpr() const
289     {
290         ASSERT(m_technique == InFPR);
291         return m_source.fpr;
292     }
293     
294     VirtualRegister virtualRegister() const
295     {
296         ASSERT(m_technique == DisplacedInJSStack || m_technique == Int32DisplacedInJSStack || m_technique == DoubleDisplacedInJSStack || m_technique == CellDisplacedInJSStack || m_technique == BooleanDisplacedInJSStack || m_technique == Int52DisplacedInJSStack || m_technique == StrictInt52DisplacedInJSStack);
297         return VirtualRegister(m_source.virtualReg);
298     }
299     
300     JSValue constant() const
301     {
302         ASSERT(m_technique == Constant);
303         return JSValue::decode(m_source.constant);
304     }
305     
306     void dumpInContext(PrintStream& out, DumpContext* context) const
307     {
308         switch (technique()) {
309         case AlreadyInJSStack:
310             out.printf("-");
311             return;
312         case AlreadyInJSStackAsUnboxedInt32:
313             out.printf("(int32)");
314             return;
315         case AlreadyInJSStackAsUnboxedInt52:
316             out.printf("(int52)");
317             return;
318         case AlreadyInJSStackAsUnboxedCell:
319             out.printf("(cell)");
320             return;
321         case AlreadyInJSStackAsUnboxedBoolean:
322             out.printf("(bool)");
323             return;
324         case AlreadyInJSStackAsUnboxedDouble:
325             out.printf("(double)");
326             return;
327         case InGPR:
328             out.print(gpr());
329             return;
330         case UnboxedInt32InGPR:
331             out.print("int32(", gpr(), ")");
332             return;
333         case UnboxedInt52InGPR:
334             out.print("int52(", gpr(), ")");
335             return;
336         case UnboxedStrictInt52InGPR:
337             out.print("strictInt52(", gpr(), ")");
338             return;
339         case UnboxedBooleanInGPR:
340             out.print("bool(", gpr(), ")");
341             return;
342         case UInt32InGPR:
343             out.print("uint32(", gpr(), ")");
344             return;
345         case InFPR:
346             out.print(fpr());
347             return;
348 #if USE(JSVALUE32_64)
349         case InPair:
350             out.print("pair(", tagGPR(), ", ", payloadGPR(), ")");
351             return;
352 #endif
353         case DisplacedInJSStack:
354             out.printf("*%d", virtualRegister().offset());
355             return;
356         case Int32DisplacedInJSStack:
357             out.printf("*int32(%d)", virtualRegister().offset());
358             return;
359         case Int52DisplacedInJSStack:
360             out.printf("*int52(%d)", virtualRegister().offset());
361             return;
362         case StrictInt52DisplacedInJSStack:
363             out.printf("*strictInt52(%d)", virtualRegister().offset());
364             return;
365         case DoubleDisplacedInJSStack:
366             out.printf("*double(%d)", virtualRegister().offset());
367             return;
368         case CellDisplacedInJSStack:
369             out.printf("*cell(%d)", virtualRegister().offset());
370             return;
371         case BooleanDisplacedInJSStack:
372             out.printf("*bool(%d)", virtualRegister().offset());
373             return;
374         case ArgumentsThatWereNotCreated:
375             out.printf("arguments");
376             return;
377         case Constant:
378             out.print("[", inContext(constant(), context), "]");
379             return;
380         case DontKnow:
381             out.printf("!");
382             return;
383         }
384         RELEASE_ASSERT_NOT_REACHED();
385     }
386     
387     void dump(PrintStream& out) const
388     {
389         dumpInContext(out, 0);
390     }
391     
392 private:
393     ValueRecoveryTechnique m_technique;
394     union {
395         MacroAssembler::RegisterID gpr;
396         MacroAssembler::FPRegisterID fpr;
397 #if USE(JSVALUE32_64)
398         struct {
399             MacroAssembler::RegisterID tagGPR;
400             MacroAssembler::RegisterID payloadGPR;
401         } pair;
402 #endif
403         int virtualReg;
404         EncodedJSValue constant;
405     } m_source;
406 };
407
408 } // namespace JSC
409
410 #endif // ValueRecovery_h