1/*
2 * Copyright (C) 2011, 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 DFGValueSource_h
27#define DFGValueSource_h
28
29#if ENABLE(DFG_JIT)
30
31#include "DFGCommon.h"
32#include "DFGFlushFormat.h"
33#include "DFGMinifiedID.h"
34#include "DataFormat.h"
35#include "SpeculatedType.h"
36#include "ValueRecovery.h"
37
38namespace JSC { namespace DFG {
39
40enum ValueSourceKind {
41    SourceNotSet,
42    ValueInJSStack,
43    Int32InJSStack,
44    Int52InJSStack,
45    CellInJSStack,
46    BooleanInJSStack,
47    DoubleInJSStack,
48    ArgumentsSource,
49    SourceIsDead,
50    HaveNode
51};
52
53static inline ValueSourceKind dataFormatToValueSourceKind(DataFormat dataFormat)
54{
55    switch (dataFormat) {
56    case DataFormatInt32:
57        return Int32InJSStack;
58    case DataFormatInt52:
59        return Int52InJSStack;
60    case DataFormatDouble:
61        return DoubleInJSStack;
62    case DataFormatBoolean:
63        return BooleanInJSStack;
64    case DataFormatCell:
65        return CellInJSStack;
66    case DataFormatDead:
67        return SourceIsDead;
68    case DataFormatArguments:
69        return ArgumentsSource;
70    default:
71        RELEASE_ASSERT(dataFormat & DataFormatJS);
72        return ValueInJSStack;
73    }
74}
75
76static inline DataFormat valueSourceKindToDataFormat(ValueSourceKind kind)
77{
78    switch (kind) {
79    case ValueInJSStack:
80        return DataFormatJS;
81    case Int32InJSStack:
82        return DataFormatInt32;
83    case Int52InJSStack:
84        return DataFormatInt52;
85    case CellInJSStack:
86        return DataFormatCell;
87    case BooleanInJSStack:
88        return DataFormatBoolean;
89    case DoubleInJSStack:
90        return DataFormatDouble;
91    case ArgumentsSource:
92        return DataFormatArguments;
93    case SourceIsDead:
94        return DataFormatDead;
95    default:
96        return DataFormatNone;
97    }
98}
99
100static inline bool isInJSStack(ValueSourceKind kind)
101{
102    DataFormat format = valueSourceKindToDataFormat(kind);
103    return format != DataFormatNone && format < DataFormatOSRMarker;
104}
105
106// Can this value be recovered without having to look at register allocation state or
107// DFG node liveness?
108static inline bool isTriviallyRecoverable(ValueSourceKind kind)
109{
110    return valueSourceKindToDataFormat(kind) != DataFormatNone;
111}
112
113class ValueSource {
114public:
115    ValueSource()
116        : m_kind(SourceNotSet)
117    {
118    }
119
120    explicit ValueSource(ValueSourceKind valueSourceKind)
121        : m_kind(valueSourceKind)
122    {
123        ASSERT(kind() == ArgumentsSource || kind() == SourceIsDead || kind() == ArgumentsSource);
124    }
125
126    explicit ValueSource(MinifiedID id)
127        : m_kind(HaveNode)
128        , m_value(id.bits())
129    {
130        ASSERT(!!id);
131        ASSERT(kind() == HaveNode);
132    }
133
134    ValueSource(ValueSourceKind valueSourceKind, VirtualRegister where)
135        : m_kind(valueSourceKind)
136        , m_value(static_cast<intptr_t>(where.offset()))
137    {
138        ASSERT(kind() != SourceNotSet);
139        ASSERT(kind() != HaveNode);
140    }
141
142    static ValueSource forFlushFormat(VirtualRegister where, FlushFormat format)
143    {
144        switch (format) {
145        case DeadFlush:
146        case ConflictingFlush:
147            return ValueSource(SourceIsDead);
148        case FlushedJSValue:
149            return ValueSource(ValueInJSStack, where);
150        case FlushedDouble:
151            return ValueSource(DoubleInJSStack, where);
152        case FlushedInt32:
153            return ValueSource(Int32InJSStack, where);
154        case FlushedInt52:
155            return ValueSource(Int52InJSStack, where);
156        case FlushedCell:
157            return ValueSource(CellInJSStack, where);
158        case FlushedBoolean:
159            return ValueSource(BooleanInJSStack, where);
160        case FlushedArguments:
161            return ValueSource(ArgumentsSource);
162        }
163        RELEASE_ASSERT_NOT_REACHED();
164        return ValueSource();
165    }
166
167    static ValueSource forDataFormat(VirtualRegister where, DataFormat dataFormat)
168    {
169        return ValueSource(dataFormatToValueSourceKind(dataFormat), where);
170    }
171
172    bool isSet() const
173    {
174        return kind() != SourceNotSet;
175    }
176
177    bool operator!() const { return !isSet(); }
178
179    ValueSourceKind kind() const
180    {
181        return m_kind;
182    }
183
184    bool isInJSStack() const { return JSC::DFG::isInJSStack(kind()); }
185    bool isTriviallyRecoverable() const { return JSC::DFG::isTriviallyRecoverable(kind()); }
186
187    DataFormat dataFormat() const
188    {
189        return valueSourceKindToDataFormat(kind());
190    }
191
192    ValueRecovery valueRecovery() const
193    {
194        ASSERT(isTriviallyRecoverable());
195        switch (kind()) {
196        case SourceIsDead:
197            return ValueRecovery::constant(jsUndefined());
198
199        case ArgumentsSource:
200            return ValueRecovery::argumentsThatWereNotCreated();
201
202        default:
203            return ValueRecovery::displacedInJSStack(virtualRegister(), dataFormat());
204        }
205    }
206
207    MinifiedID id() const
208    {
209        ASSERT(kind() == HaveNode);
210        return MinifiedID::fromBits(m_value);
211    }
212
213    VirtualRegister virtualRegister() const
214    {
215        ASSERT(isInJSStack());
216        return VirtualRegister(m_value);
217    }
218
219    void dump(PrintStream&) const;
220    void dumpInContext(PrintStream&, DumpContext*) const;
221
222private:
223    ValueSourceKind m_kind;
224    uintptr_t m_value;
225};
226
227} } // namespace JSC::DFG
228
229#endif // ENABLE(DFG_JIT)
230
231#endif // DFGValueSource_h
232
233