1/*
2 * Copyright (C) 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#if ENABLE(FTL_JIT)
29
30#include "FTLExitArgument.h"
31#include "FTLRecoveryOpcode.h"
32#include "JSCJSValue.h"
33#include "VirtualRegister.h"
34#include <wtf/PrintStream.h>
35
36namespace JSC {
37
38class TrackedReferences;
39
40namespace FTL {
41
42// This is like ValueRecovery, but respects the way that the FTL does OSR
43// exit: the live non-constant non-flushed values are passed as arguments
44// to a noreturn tail call. ExitValue is hence mostly responsible for
45// telling us the mapping between operands in bytecode and the arguments to
46// the call.
47
48enum ExitValueKind : uint8_t {
49 InvalidExitValue,
50 ExitValueDead,
51 ExitValueArgument,
52 ExitValueConstant,
53 ExitValueInJSStack,
54 ExitValueInJSStackAsInt32,
55 ExitValueInJSStackAsInt52,
56 ExitValueInJSStackAsDouble,
57 ExitValueMaterializeNewObject
58};
59
60class ExitTimeObjectMaterialization;
61
62class ExitValue {
63public:
64 ExitValue()
65 : m_kind(InvalidExitValue)
66 {
67 }
68
69 bool operator!() const { return m_kind == InvalidExitValue; }
70
71 static ExitValue dead()
72 {
73 ExitValue result;
74 result.m_kind = ExitValueDead;
75 return result;
76 }
77
78 static ExitValue inJSStack(VirtualRegister reg)
79 {
80 ExitValue result;
81 result.m_kind = ExitValueInJSStack;
82 UnionType u;
83 u.virtualRegister = reg.offset();
84 result.m_value = WTFMove(u);
85 return result;
86 }
87
88 static ExitValue inJSStackAsInt32(VirtualRegister reg)
89 {
90 ExitValue result;
91 result.m_kind = ExitValueInJSStackAsInt32;
92 UnionType u;
93 u.virtualRegister = reg.offset();
94 result.m_value = WTFMove(u);
95 return result;
96 }
97
98 static ExitValue inJSStackAsInt52(VirtualRegister reg)
99 {
100 ExitValue result;
101 result.m_kind = ExitValueInJSStackAsInt52;
102 UnionType u;
103 u.virtualRegister = reg.offset();
104 result.m_value = WTFMove(u);
105 return result;
106 }
107
108 static ExitValue inJSStackAsDouble(VirtualRegister reg)
109 {
110 ExitValue result;
111 result.m_kind = ExitValueInJSStackAsDouble;
112 UnionType u;
113 u.virtualRegister = reg.offset();
114 result.m_value = WTFMove(u);
115 return result;
116 }
117
118 static ExitValue constant(JSValue value)
119 {
120 ExitValue result;
121 result.m_kind = ExitValueConstant;
122 UnionType u;
123 u.constant = JSValue::encode(value);
124 result.m_value = WTFMove(u);
125 return result;
126 }
127
128 static ExitValue exitArgument(const ExitArgument& argument)
129 {
130 ExitValue result;
131 result.m_kind = ExitValueArgument;
132 UnionType u;
133 u.argument = argument.representation();
134 result.m_value = WTFMove(u);
135 return result;
136 }
137
138 static ExitValue materializeNewObject(ExitTimeObjectMaterialization*);
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 isObjectMaterialization() const { return kind() == ExitValueMaterializeNewObject; }
158 bool hasIndexInStackmapLocations() const { return isArgument(); }
159
160 ExitArgument exitArgument() const
161 {
162 ASSERT(isArgument());
163 return ExitArgument(m_value.get().argument);
164 }
165
166 void adjustStackmapLocationsIndexByOffset(unsigned offset)
167 {
168 ASSERT(hasIndexInStackmapLocations());
169 ASSERT(isArgument());
170 UnionType u = m_value.get();
171 u.argument.argument += offset;
172 m_value = WTFMove(u);
173 }
174
175 JSValue constant() const
176 {
177 ASSERT(isConstant());
178 return JSValue::decode(m_value.get().constant);
179 }
180
181 VirtualRegister virtualRegister() const
182 {
183 ASSERT(isInJSStackSomehow());
184 return VirtualRegister(m_value.get().virtualRegister);
185 }
186
187 ExitTimeObjectMaterialization* objectMaterialization() const
188 {
189 ASSERT(isObjectMaterialization());
190 return m_value.get().newObjectMaterializationData;
191 }
192
193 ExitValue withVirtualRegister(VirtualRegister virtualRegister) const
194 {
195 ASSERT(isInJSStackSomehow());
196 ExitValue result;
197 result.m_kind = m_kind;
198 UnionType u;
199 u.virtualRegister = virtualRegister.offset();
200 result.m_value = WTFMove(u);
201 return result;
202 }
203
204 ExitValue withLocalsOffset(int offset) const;
205
206 // If it's in the JSStack somehow, this will tell you what format it's in, in a manner
207 // that is compatible with exitArgument().format(). If it's a constant or it's dead, it
208 // will claim to be a JSValue. If it's an argument then it will tell you the argument's
209 // format.
210 DataFormat dataFormat() const;
211
212 void dump(PrintStream&) const;
213 void dumpInContext(PrintStream&, DumpContext*) const;
214
215 void validateReferences(const TrackedReferences&) const;
216
217private:
218 ExitValueKind m_kind;
219 union UnionType {
220 ExitArgumentRepresentation argument;
221 EncodedJSValue constant;
222 int virtualRegister;
223 ExitTimeObjectMaterialization* newObjectMaterializationData;
224 };
225 Packed<UnionType> m_value;
226};
227
228} } // namespace JSC::FTL
229
230#endif // ENABLE(FTL_JIT)
231