1/*
2 * Copyright (C) 2011, 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 ValueRecovery_h
27#define ValueRecovery_h
28
29#include "DataFormat.h"
30#if ENABLE(JIT)
31#include "GPRInfo.h"
32#include "FPRInfo.h"
33#endif
34#include "JSCJSValue.h"
35#include "MacroAssembler.h"
36#include "VirtualRegister.h"
37
38namespace JSC {
39
40struct DumpContext;
41
42// Describes how to recover a given bytecode virtual register at a given
43// code point.
44enum ValueRecoveryTechnique {
45    // It's in a register.
46    InGPR,
47    UnboxedInt32InGPR,
48    UnboxedInt52InGPR,
49    UnboxedStrictInt52InGPR,
50    UnboxedBooleanInGPR,
51    UnboxedCellInGPR,
52#if USE(JSVALUE32_64)
53    InPair,
54#endif
55    InFPR,
56    // It's in the stack, but at a different location.
57    DisplacedInJSStack,
58    // It's in the stack, at a different location, and it's unboxed.
59    Int32DisplacedInJSStack,
60    Int52DisplacedInJSStack,
61    StrictInt52DisplacedInJSStack,
62    DoubleDisplacedInJSStack,
63    CellDisplacedInJSStack,
64    BooleanDisplacedInJSStack,
65    // It's an Arguments object.
66    ArgumentsThatWereNotCreated,
67    // It's a constant.
68    Constant,
69    // Don't know how to recover it.
70    DontKnow
71};
72
73class ValueRecovery {
74public:
75    ValueRecovery()
76        : m_technique(DontKnow)
77    {
78    }
79
80    bool isSet() const { return m_technique != DontKnow; }
81    bool operator!() const { return !isSet(); }
82
83    static ValueRecovery inGPR(MacroAssembler::RegisterID gpr, DataFormat dataFormat)
84    {
85        ASSERT(dataFormat != DataFormatNone);
86#if USE(JSVALUE32_64)
87        ASSERT(dataFormat == DataFormatInt32 || dataFormat == DataFormatCell || dataFormat == DataFormatBoolean);
88#endif
89        ValueRecovery result;
90        if (dataFormat == DataFormatInt32)
91            result.m_technique = UnboxedInt32InGPR;
92        else if (dataFormat == DataFormatInt52)
93            result.m_technique = UnboxedInt52InGPR;
94        else if (dataFormat == DataFormatStrictInt52)
95            result.m_technique = UnboxedStrictInt52InGPR;
96        else if (dataFormat == DataFormatBoolean)
97            result.m_technique = UnboxedBooleanInGPR;
98        else if (dataFormat == DataFormatCell)
99            result.m_technique = UnboxedCellInGPR;
100        else
101            result.m_technique = InGPR;
102        result.m_source.gpr = gpr;
103        return result;
104    }
105
106#if USE(JSVALUE32_64)
107    static ValueRecovery inPair(MacroAssembler::RegisterID tagGPR, MacroAssembler::RegisterID payloadGPR)
108    {
109        ValueRecovery result;
110        result.m_technique = InPair;
111        result.m_source.pair.tagGPR = tagGPR;
112        result.m_source.pair.payloadGPR = payloadGPR;
113        return result;
114    }
115#endif
116
117    static ValueRecovery inFPR(MacroAssembler::FPRegisterID fpr)
118    {
119        ValueRecovery result;
120        result.m_technique = InFPR;
121        result.m_source.fpr = fpr;
122        return result;
123    }
124
125    static ValueRecovery displacedInJSStack(VirtualRegister virtualReg, DataFormat dataFormat)
126    {
127        ValueRecovery result;
128        switch (dataFormat) {
129        case DataFormatInt32:
130            result.m_technique = Int32DisplacedInJSStack;
131            break;
132
133        case DataFormatInt52:
134            result.m_technique = Int52DisplacedInJSStack;
135            break;
136
137        case DataFormatStrictInt52:
138            result.m_technique = StrictInt52DisplacedInJSStack;
139            break;
140
141        case DataFormatDouble:
142            result.m_technique = DoubleDisplacedInJSStack;
143            break;
144
145        case DataFormatCell:
146            result.m_technique = CellDisplacedInJSStack;
147            break;
148
149        case DataFormatBoolean:
150            result.m_technique = BooleanDisplacedInJSStack;
151            break;
152
153        default:
154            ASSERT(dataFormat != DataFormatNone && dataFormat != DataFormatStorage);
155            result.m_technique = DisplacedInJSStack;
156            break;
157        }
158        result.m_source.virtualReg = virtualReg.offset();
159        return result;
160    }
161
162    static ValueRecovery constant(JSValue value)
163    {
164        ValueRecovery result;
165        result.m_technique = Constant;
166        result.m_source.constant = JSValue::encode(value);
167        return result;
168    }
169
170    static ValueRecovery argumentsThatWereNotCreated()
171    {
172        ValueRecovery result;
173        result.m_technique = ArgumentsThatWereNotCreated;
174        return result;
175    }
176
177    ValueRecoveryTechnique technique() const { return m_technique; }
178
179    bool isConstant() const { return m_technique == Constant; }
180
181    bool isInRegisters() const
182    {
183        switch (m_technique) {
184        case InGPR:
185        case UnboxedInt32InGPR:
186        case UnboxedBooleanInGPR:
187        case UnboxedCellInGPR:
188        case UnboxedInt52InGPR:
189        case UnboxedStrictInt52InGPR:
190#if USE(JSVALUE32_64)
191        case InPair:
192#endif
193        case InFPR:
194            return true;
195        default:
196            return false;
197        }
198    }
199
200    MacroAssembler::RegisterID gpr() const
201    {
202        ASSERT(m_technique == InGPR || m_technique == UnboxedInt32InGPR || m_technique == UnboxedBooleanInGPR || m_technique == UnboxedInt52InGPR || m_technique == UnboxedStrictInt52InGPR || m_technique == UnboxedCellInGPR);
203        return m_source.gpr;
204    }
205
206#if USE(JSVALUE32_64)
207    MacroAssembler::RegisterID tagGPR() const
208    {
209        ASSERT(m_technique == InPair);
210        return m_source.pair.tagGPR;
211    }
212
213    MacroAssembler::RegisterID payloadGPR() const
214    {
215        ASSERT(m_technique == InPair);
216        return m_source.pair.payloadGPR;
217    }
218#endif
219
220    MacroAssembler::FPRegisterID fpr() const
221    {
222        ASSERT(m_technique == InFPR);
223        return m_source.fpr;
224    }
225
226    VirtualRegister virtualRegister() const
227    {
228        ASSERT(m_technique == DisplacedInJSStack || m_technique == Int32DisplacedInJSStack || m_technique == DoubleDisplacedInJSStack || m_technique == CellDisplacedInJSStack || m_technique == BooleanDisplacedInJSStack || m_technique == Int52DisplacedInJSStack || m_technique == StrictInt52DisplacedInJSStack);
229        return VirtualRegister(m_source.virtualReg);
230    }
231
232    ValueRecovery withLocalsOffset(int offset) const
233    {
234        switch (m_technique) {
235        case DisplacedInJSStack:
236        case Int32DisplacedInJSStack:
237        case DoubleDisplacedInJSStack:
238        case CellDisplacedInJSStack:
239        case BooleanDisplacedInJSStack:
240        case Int52DisplacedInJSStack:
241        case StrictInt52DisplacedInJSStack: {
242            ValueRecovery result;
243            result.m_technique = m_technique;
244            result.m_source.virtualReg = m_source.virtualReg + offset;
245            return result;
246        }
247
248        default:
249            return *this;
250        }
251    }
252
253    JSValue constant() const
254    {
255        ASSERT(m_technique == Constant);
256        return JSValue::decode(m_source.constant);
257    }
258
259    JSValue recover(ExecState*) const;
260
261#if ENABLE(JIT)
262    void dumpInContext(PrintStream& out, DumpContext* context) const;
263    void dump(PrintStream& out) const;
264#endif
265
266private:
267    ValueRecoveryTechnique m_technique;
268    union {
269        MacroAssembler::RegisterID gpr;
270        MacroAssembler::FPRegisterID fpr;
271#if USE(JSVALUE32_64)
272        struct {
273            MacroAssembler::RegisterID tagGPR;
274            MacroAssembler::RegisterID payloadGPR;
275        } pair;
276#endif
277        int virtualReg;
278        EncodedJSValue constant;
279    } m_source;
280};
281
282} // namespace JSC
283
284#endif // ValueRecovery_h
285