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
37namespace 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
45enum ExitValueKind {
46    InvalidExitValue,
47    ExitValueDead,
48    ExitValueArgument,
49    ExitValueConstant,
50    ExitValueInJSStack,
51    ExitValueInJSStackAsInt32,
52    ExitValueInJSStackAsInt52,
53    ExitValueInJSStackAsDouble,
54    ExitValueArgumentsObjectThatWasNotCreated,
55    ExitValueRecovery
56};
57
58class ExitValue {
59public:
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
251private:
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
271