1/*
2 * Copyright (C) 2008-2018 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 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of Apple Inc. ("Apple") nor the names of
14 * its contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#pragma once
30
31#include "JSCJSValue.h"
32#include <wtf/Assertions.h>
33#include <wtf/VectorTraits.h>
34
35namespace JSC {
36
37 class CodeBlock;
38 class ExecState;
39 class JSLexicalEnvironment;
40 class JSObject;
41 class JSScope;
42
43 typedef ExecState CallFrame;
44
45 class Register {
46 WTF_MAKE_FAST_ALLOCATED;
47 public:
48 Register();
49
50 Register(const JSValue&);
51 Register& operator=(const JSValue&);
52 JSValue jsValue() const;
53 JSValue asanUnsafeJSValue() const;
54 EncodedJSValue encodedJSValue() const;
55
56 Register& operator=(CallFrame*);
57 Register& operator=(CodeBlock*);
58 Register& operator=(JSScope*);
59 Register& operator=(JSObject*);
60
61 int32_t i() const;
62 CallFrame* callFrame() const;
63 CodeBlock* codeBlock() const;
64 CodeBlock* asanUnsafeCodeBlock() const;
65 JSObject* object() const;
66 JSScope* scope() const;
67 int32_t unboxedInt32() const;
68 int32_t asanUnsafeUnboxedInt32() const;
69 int64_t unboxedInt52() const;
70 int64_t asanUnsafeUnboxedInt52() const;
71 int64_t unboxedStrictInt52() const;
72 int64_t asanUnsafeUnboxedStrictInt52() const;
73 bool unboxedBoolean() const;
74 double unboxedDouble() const;
75 double asanUnsafeUnboxedDouble() const;
76 JSCell* unboxedCell() const;
77 JSCell* asanUnsafeUnboxedCell() const;
78 int32_t payload() const;
79 int32_t tag() const;
80 int32_t unsafePayload() const;
81 int32_t unsafeTag() const;
82 int32_t& payload();
83 int32_t& tag();
84
85 void* pointer() const;
86 void* asanUnsafePointer() const;
87
88 static Register withInt(int32_t i)
89 {
90 Register r = jsNumber(i);
91 return r;
92 }
93
94 private:
95 union {
96 EncodedJSValue value;
97 CallFrame* callFrame;
98 CodeBlock* codeBlock;
99 EncodedValueDescriptor encodedValue;
100 double number;
101 int64_t integer;
102 } u;
103 };
104
105 ALWAYS_INLINE Register::Register()
106 {
107#ifndef NDEBUG
108 *this = JSValue();
109#endif
110 }
111
112 ALWAYS_INLINE Register::Register(const JSValue& v)
113 {
114 u.value = JSValue::encode(v);
115 }
116
117 ALWAYS_INLINE Register& Register::operator=(const JSValue& v)
118 {
119 u.value = JSValue::encode(v);
120 return *this;
121 }
122
123 // FIXME (rdar://problem/19379214): ASan only needs to be suppressed for Register::jsValue() when called from prepareOSREntry(), but there is currently no way to express this short of adding a separate copy of the function.
124 SUPPRESS_ASAN ALWAYS_INLINE JSValue Register::asanUnsafeJSValue() const
125 {
126 return JSValue::decode(u.value);
127 }
128
129 ALWAYS_INLINE JSValue Register::jsValue() const
130 {
131 return JSValue::decode(u.value);
132 }
133
134 ALWAYS_INLINE EncodedJSValue Register::encodedJSValue() const
135 {
136 return u.value;
137 }
138
139 // Interpreter functions
140
141 ALWAYS_INLINE Register& Register::operator=(CallFrame* callFrame)
142 {
143 u.callFrame = callFrame;
144 return *this;
145 }
146
147 ALWAYS_INLINE Register& Register::operator=(CodeBlock* codeBlock)
148 {
149 u.codeBlock = codeBlock;
150 return *this;
151 }
152
153 ALWAYS_INLINE int32_t Register::i() const
154 {
155 return jsValue().asInt32();
156 }
157
158 ALWAYS_INLINE CallFrame* Register::callFrame() const
159 {
160 return u.callFrame;
161 }
162
163 ALWAYS_INLINE CodeBlock* Register::codeBlock() const
164 {
165 return u.codeBlock;
166 }
167
168 SUPPRESS_ASAN ALWAYS_INLINE CodeBlock* Register::asanUnsafeCodeBlock() const
169 {
170 return u.codeBlock;
171 }
172
173 ALWAYS_INLINE int32_t Register::unboxedInt32() const
174 {
175 return payload();
176 }
177
178 SUPPRESS_ASAN ALWAYS_INLINE int32_t Register::asanUnsafeUnboxedInt32() const
179 {
180 return unsafePayload();
181 }
182
183 ALWAYS_INLINE int64_t Register::unboxedInt52() const
184 {
185 return u.integer >> JSValue::int52ShiftAmount;
186 }
187
188 SUPPRESS_ASAN ALWAYS_INLINE int64_t Register::asanUnsafeUnboxedInt52() const
189 {
190 return u.integer >> JSValue::int52ShiftAmount;
191 }
192
193 ALWAYS_INLINE int64_t Register::unboxedStrictInt52() const
194 {
195 return u.integer;
196 }
197
198 SUPPRESS_ASAN ALWAYS_INLINE int64_t Register::asanUnsafeUnboxedStrictInt52() const
199 {
200 return u.integer;
201 }
202
203 ALWAYS_INLINE bool Register::unboxedBoolean() const
204 {
205 return !!payload();
206 }
207
208 ALWAYS_INLINE double Register::unboxedDouble() const
209 {
210 return u.number;
211 }
212
213 SUPPRESS_ASAN ALWAYS_INLINE double Register::asanUnsafeUnboxedDouble() const
214 {
215 return u.number;
216 }
217
218 ALWAYS_INLINE JSCell* Register::unboxedCell() const
219 {
220#if USE(JSVALUE64)
221 return u.encodedValue.ptr;
222#else
223 return bitwise_cast<JSCell*>(payload());
224#endif
225 }
226
227 SUPPRESS_ASAN ALWAYS_INLINE JSCell* Register::asanUnsafeUnboxedCell() const
228 {
229#if USE(JSVALUE64)
230 return u.encodedValue.ptr;
231#else
232 return bitwise_cast<JSCell*>(payload());
233#endif
234 }
235
236 ALWAYS_INLINE void* Register::pointer() const
237 {
238#if USE(JSVALUE64)
239 return u.encodedValue.ptr;
240#else
241 return bitwise_cast<void*>(payload());
242#endif
243 }
244
245 SUPPRESS_ASAN ALWAYS_INLINE void* Register::asanUnsafePointer() const
246 {
247#if USE(JSVALUE64)
248 return u.encodedValue.ptr;
249#else
250 return bitwise_cast<void*>(unsafePayload());
251#endif
252 }
253
254 ALWAYS_INLINE int32_t Register::payload() const
255 {
256 return u.encodedValue.asBits.payload;
257 }
258
259 ALWAYS_INLINE int32_t Register::tag() const
260 {
261 return u.encodedValue.asBits.tag;
262 }
263
264 SUPPRESS_ASAN ALWAYS_INLINE int32_t Register::unsafePayload() const
265 {
266 return u.encodedValue.asBits.payload;
267 }
268
269 SUPPRESS_ASAN ALWAYS_INLINE int32_t Register::unsafeTag() const
270 {
271 return u.encodedValue.asBits.tag;
272 }
273
274 ALWAYS_INLINE int32_t& Register::payload()
275 {
276 return u.encodedValue.asBits.payload;
277 }
278
279 ALWAYS_INLINE int32_t& Register::tag()
280 {
281 return u.encodedValue.asBits.tag;
282 }
283
284} // namespace JSC
285
286namespace WTF {
287
288 template<> struct VectorTraits<JSC::Register> : VectorTraitsBase<true, JSC::Register> { };
289
290} // namespace WTF
291