0
|
1 |
/*
|
|
2 |
* Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
|
|
3 |
* Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org)
|
|
4 |
*
|
|
5 |
* This library is free software; you can redistribute it and/or
|
|
6 |
* modify it under the terms of the GNU Library General Public
|
|
7 |
* License as published by the Free Software Foundation; either
|
|
8 |
* version 2 of the License, or (at your option) any later version.
|
|
9 |
*
|
|
10 |
* This library is distributed in the hope that it will be useful,
|
|
11 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
13 |
* Library General Public License for more details.
|
|
14 |
*
|
|
15 |
* You should have received a copy of the GNU Library General Public License
|
|
16 |
* along with this library; see the file COPYING.LIB. If not, write to
|
|
17 |
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
18 |
* Boston, MA 02110-1301, USA.
|
|
19 |
*
|
|
20 |
*/
|
|
21 |
|
|
22 |
#ifndef JSImmediate_h
|
|
23 |
#define JSImmediate_h
|
|
24 |
|
|
25 |
#include <wtf/Platform.h>
|
|
26 |
|
|
27 |
#if !USE(JSVALUE32_64)
|
|
28 |
|
|
29 |
#include <wtf/Assertions.h>
|
|
30 |
#include <wtf/AlwaysInline.h>
|
|
31 |
#include <wtf/MathExtras.h>
|
|
32 |
#include <wtf/StdLibExtras.h>
|
|
33 |
#include "JSValue.h"
|
|
34 |
#include <limits>
|
|
35 |
#include <limits.h>
|
|
36 |
#include <stdarg.h>
|
|
37 |
#include <stdint.h>
|
|
38 |
#include <stdlib.h>
|
|
39 |
|
|
40 |
namespace JSC {
|
|
41 |
|
|
42 |
class ExecState;
|
|
43 |
class JSCell;
|
|
44 |
class JSFastMath;
|
|
45 |
class JSGlobalData;
|
|
46 |
class JSObject;
|
|
47 |
class UString;
|
|
48 |
|
|
49 |
#if USE(JSVALUE64)
|
|
50 |
inline intptr_t reinterpretDoubleToIntptr(double value)
|
|
51 |
{
|
|
52 |
return WTF::bitwise_cast<intptr_t>(value);
|
|
53 |
}
|
|
54 |
|
|
55 |
inline double reinterpretIntptrToDouble(intptr_t value)
|
|
56 |
{
|
|
57 |
return WTF::bitwise_cast<double>(value);
|
|
58 |
}
|
|
59 |
#endif
|
|
60 |
|
|
61 |
/*
|
|
62 |
* A JSValue* is either a pointer to a cell (a heap-allocated object) or an immediate (a type-tagged
|
|
63 |
* value masquerading as a pointer). The low two bits in a JSValue* are available for type tagging
|
|
64 |
* because allocator alignment guarantees they will be 00 in cell pointers.
|
|
65 |
*
|
|
66 |
* For example, on a 32 bit system:
|
|
67 |
*
|
|
68 |
* JSCell*: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 00
|
|
69 |
* [ high 30 bits: pointer address ] [ low 2 bits -- always 0 ]
|
|
70 |
* JSImmediate: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX TT
|
|
71 |
* [ high 30 bits: 'payload' ] [ low 2 bits -- tag ]
|
|
72 |
*
|
|
73 |
* Where the bottom two bits are non-zero they either indicate that the immediate is a 31 bit signed
|
|
74 |
* integer, or they mark the value as being an immediate of a type other than integer, with a secondary
|
|
75 |
* tag used to indicate the exact type.
|
|
76 |
*
|
|
77 |
* Where the lowest bit is set (TT is equal to 01 or 11) the high 31 bits form a 31 bit signed int value.
|
|
78 |
* Where TT is equal to 10 this indicates this is a type of immediate other than an integer, and the next
|
|
79 |
* two bits will form an extended tag.
|
|
80 |
*
|
|
81 |
* 31 bit signed int: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX X1
|
|
82 |
* [ high 30 bits of the value ] [ high bit part of value ]
|
|
83 |
* Other: YYYYYYYYYYYYYYYYYYYYYYYYYYYY ZZ 10
|
|
84 |
* [ extended 'payload' ] [ extended tag ] [ tag 'other' ]
|
|
85 |
*
|
|
86 |
* Where the first bit of the extended tag is set this flags the value as being a boolean, and the following
|
|
87 |
* bit would flag the value as undefined. If neither bits are set, the value is null.
|
|
88 |
*
|
|
89 |
* Other: YYYYYYYYYYYYYYYYYYYYYYYYYYYY UB 10
|
|
90 |
* [ extended 'payload' ] [ undefined | bool ] [ tag 'other' ]
|
|
91 |
*
|
|
92 |
* For boolean value the lowest bit in the payload holds the value of the bool, all remaining bits are zero.
|
|
93 |
* For undefined or null immediates the payload is zero.
|
|
94 |
*
|
|
95 |
* Boolean: 000000000000000000000000000V 01 10
|
|
96 |
* [ boolean value ] [ bool ] [ tag 'other' ]
|
|
97 |
* Undefined: 0000000000000000000000000000 10 10
|
|
98 |
* [ zero ] [ undefined ] [ tag 'other' ]
|
|
99 |
* Null: 0000000000000000000000000000 00 10
|
|
100 |
* [ zero ] [ zero ] [ tag 'other' ]
|
|
101 |
*/
|
|
102 |
|
|
103 |
/*
|
|
104 |
* On 64-bit platforms, we support an alternative encoding form for immediates, if
|
|
105 |
* USE(JSVALUE64) is defined. When this format is used, double precision
|
|
106 |
* floating point values may also be encoded as JSImmediates.
|
|
107 |
*
|
|
108 |
* The encoding makes use of unused NaN space in the IEEE754 representation. Any value
|
|
109 |
* with the top 13 bits set represents a QNaN (with the sign bit set). QNaN values
|
|
110 |
* can encode a 51-bit payload. Hardware produced and C-library payloads typically
|
|
111 |
* have a payload of zero. We assume that non-zero payloads are available to encode
|
|
112 |
* pointer and integer values. Since any 64-bit bit pattern where the top 15 bits are
|
|
113 |
* all set represents a NaN with a non-zero payload, we can use this space in the NaN
|
|
114 |
* ranges to encode other values (however there are also other ranges of NaN space that
|
|
115 |
* could have been selected). This range of NaN space is represented by 64-bit numbers
|
|
116 |
* begining with the 16-bit hex patterns 0xFFFE and 0xFFFF - we rely on the fact that no
|
|
117 |
* valid double-precision numbers will begin fall in these ranges.
|
|
118 |
*
|
|
119 |
* The scheme we have implemented encodes double precision values by adding 2^48 to the
|
|
120 |
* 64-bit integer representation of the number. After this manipulation, no encoded
|
|
121 |
* double-precision value will begin with the pattern 0x0000 or 0xFFFF.
|
|
122 |
*
|
|
123 |
* The top 16-bits denote the type of the encoded JSImmediate:
|
|
124 |
*
|
|
125 |
* Pointer: 0000:PPPP:PPPP:PPPP
|
|
126 |
* 0001:****:****:****
|
|
127 |
* Double:{ ...
|
|
128 |
* FFFE:****:****:****
|
|
129 |
* Integer: FFFF:0000:IIII:IIII
|
|
130 |
*
|
|
131 |
* 32-bit signed integers are marked with the 16-bit tag 0xFFFF. The tag 0x0000
|
|
132 |
* denotes a pointer, or another form of tagged immediate. Boolean, null and undefined
|
|
133 |
* values are encoded in the same manner as the default format.
|
|
134 |
*/
|
|
135 |
|
|
136 |
class JSImmediate {
|
|
137 |
private:
|
|
138 |
friend class JIT;
|
|
139 |
friend class JSValue;
|
|
140 |
friend class JSFastMath;
|
|
141 |
friend JSValue jsNumber(ExecState* exec, double d);
|
|
142 |
friend JSValue jsNumber(ExecState*, char i);
|
|
143 |
friend JSValue jsNumber(ExecState*, unsigned char i);
|
|
144 |
friend JSValue jsNumber(ExecState*, short i);
|
|
145 |
friend JSValue jsNumber(ExecState*, unsigned short i);
|
|
146 |
friend JSValue jsNumber(ExecState* exec, int i);
|
|
147 |
friend JSValue jsNumber(ExecState* exec, unsigned i);
|
|
148 |
friend JSValue jsNumber(ExecState* exec, long i);
|
|
149 |
friend JSValue jsNumber(ExecState* exec, unsigned long i);
|
|
150 |
friend JSValue jsNumber(ExecState* exec, long long i);
|
|
151 |
friend JSValue jsNumber(ExecState* exec, unsigned long long i);
|
|
152 |
friend JSValue jsNumber(JSGlobalData* globalData, double d);
|
|
153 |
friend JSValue jsNumber(JSGlobalData* globalData, short i);
|
|
154 |
friend JSValue jsNumber(JSGlobalData* globalData, unsigned short i);
|
|
155 |
friend JSValue jsNumber(JSGlobalData* globalData, int i);
|
|
156 |
friend JSValue jsNumber(JSGlobalData* globalData, unsigned i);
|
|
157 |
friend JSValue jsNumber(JSGlobalData* globalData, long i);
|
|
158 |
friend JSValue jsNumber(JSGlobalData* globalData, unsigned long i);
|
|
159 |
friend JSValue jsNumber(JSGlobalData* globalData, long long i);
|
|
160 |
friend JSValue jsNumber(JSGlobalData* globalData, unsigned long long i);
|
|
161 |
|
|
162 |
#if USE(JSVALUE64)
|
|
163 |
// If all bits in the mask are set, this indicates an integer number,
|
|
164 |
// if any but not all are set this value is a double precision number.
|
|
165 |
static const intptr_t TagTypeNumber = 0xffff000000000000ll;
|
|
166 |
// This value is 2^48, used to encode doubles such that the encoded value will begin
|
|
167 |
// with a 16-bit pattern within the range 0x0001..0xFFFE.
|
|
168 |
static const intptr_t DoubleEncodeOffset = 0x1000000000000ll;
|
|
169 |
#else
|
|
170 |
static const intptr_t TagTypeNumber = 0x1; // bottom bit set indicates integer, this dominates the following bit
|
|
171 |
#endif
|
|
172 |
static const intptr_t TagBitTypeOther = 0x2; // second bit set indicates immediate other than an integer
|
|
173 |
static const intptr_t TagMask = TagTypeNumber | TagBitTypeOther;
|
|
174 |
|
|
175 |
static const intptr_t ExtendedTagMask = 0xC; // extended tag holds a further two bits
|
|
176 |
static const intptr_t ExtendedTagBitBool = 0x4;
|
|
177 |
static const intptr_t ExtendedTagBitUndefined = 0x8;
|
|
178 |
|
|
179 |
static const intptr_t FullTagTypeMask = TagMask | ExtendedTagMask;
|
|
180 |
static const intptr_t FullTagTypeBool = TagBitTypeOther | ExtendedTagBitBool;
|
|
181 |
static const intptr_t FullTagTypeUndefined = TagBitTypeOther | ExtendedTagBitUndefined;
|
|
182 |
static const intptr_t FullTagTypeNull = TagBitTypeOther;
|
|
183 |
|
|
184 |
#if USE(JSVALUE64)
|
|
185 |
static const int32_t IntegerPayloadShift = 0;
|
|
186 |
#else
|
|
187 |
static const int32_t IntegerPayloadShift = 1;
|
|
188 |
#endif
|
|
189 |
static const int32_t ExtendedPayloadShift = 4;
|
|
190 |
|
|
191 |
static const intptr_t ExtendedPayloadBitBoolValue = 1 << ExtendedPayloadShift;
|
|
192 |
|
|
193 |
static const int32_t signBit = 0x80000000;
|
|
194 |
|
|
195 |
static ALWAYS_INLINE bool isImmediate(JSValue v)
|
|
196 |
{
|
|
197 |
return rawValue(v) & TagMask;
|
|
198 |
}
|
|
199 |
|
|
200 |
static ALWAYS_INLINE bool isNumber(JSValue v)
|
|
201 |
{
|
|
202 |
return rawValue(v) & TagTypeNumber;
|
|
203 |
}
|
|
204 |
|
|
205 |
static ALWAYS_INLINE bool isIntegerNumber(JSValue v)
|
|
206 |
{
|
|
207 |
#if USE(JSVALUE64)
|
|
208 |
return (rawValue(v) & TagTypeNumber) == TagTypeNumber;
|
|
209 |
#else
|
|
210 |
return isNumber(v);
|
|
211 |
#endif
|
|
212 |
}
|
|
213 |
|
|
214 |
#if USE(JSVALUE64)
|
|
215 |
static ALWAYS_INLINE bool isDouble(JSValue v)
|
|
216 |
{
|
|
217 |
return isNumber(v) && !isIntegerNumber(v);
|
|
218 |
}
|
|
219 |
#endif
|
|
220 |
|
|
221 |
static ALWAYS_INLINE bool isPositiveIntegerNumber(JSValue v)
|
|
222 |
{
|
|
223 |
// A single mask to check for the sign bit and the number tag all at once.
|
|
224 |
return (rawValue(v) & (signBit | TagTypeNumber)) == TagTypeNumber;
|
|
225 |
}
|
|
226 |
|
|
227 |
static ALWAYS_INLINE bool isBoolean(JSValue v)
|
|
228 |
{
|
|
229 |
return (rawValue(v) & FullTagTypeMask) == FullTagTypeBool;
|
|
230 |
}
|
|
231 |
|
|
232 |
static ALWAYS_INLINE bool isUndefinedOrNull(JSValue v)
|
|
233 |
{
|
|
234 |
// Undefined and null share the same value, bar the 'undefined' bit in the extended tag.
|
|
235 |
return (rawValue(v) & ~ExtendedTagBitUndefined) == FullTagTypeNull;
|
|
236 |
}
|
|
237 |
|
|
238 |
static JSValue from(char);
|
|
239 |
static JSValue from(signed char);
|
|
240 |
static JSValue from(unsigned char);
|
|
241 |
static JSValue from(short);
|
|
242 |
static JSValue from(unsigned short);
|
|
243 |
static JSValue from(int);
|
|
244 |
static JSValue from(unsigned);
|
|
245 |
static JSValue from(long);
|
|
246 |
static JSValue from(unsigned long);
|
|
247 |
static JSValue from(long long);
|
|
248 |
static JSValue from(unsigned long long);
|
|
249 |
static JSValue from(double);
|
|
250 |
|
|
251 |
static ALWAYS_INLINE bool isEitherImmediate(JSValue v1, JSValue v2)
|
|
252 |
{
|
|
253 |
return (rawValue(v1) | rawValue(v2)) & TagMask;
|
|
254 |
}
|
|
255 |
|
|
256 |
static ALWAYS_INLINE bool areBothImmediate(JSValue v1, JSValue v2)
|
|
257 |
{
|
|
258 |
return isImmediate(v1) & isImmediate(v2);
|
|
259 |
}
|
|
260 |
|
|
261 |
static ALWAYS_INLINE bool areBothImmediateIntegerNumbers(JSValue v1, JSValue v2)
|
|
262 |
{
|
|
263 |
#if USE(JSVALUE64)
|
|
264 |
return (rawValue(v1) & rawValue(v2) & TagTypeNumber) == TagTypeNumber;
|
|
265 |
#else
|
|
266 |
return rawValue(v1) & rawValue(v2) & TagTypeNumber;
|
|
267 |
#endif
|
|
268 |
}
|
|
269 |
|
|
270 |
static double toDouble(JSValue);
|
|
271 |
static bool toBoolean(JSValue);
|
|
272 |
|
|
273 |
static bool getUInt32(JSValue, uint32_t&);
|
|
274 |
static bool getTruncatedInt32(JSValue, int32_t&);
|
|
275 |
static bool getTruncatedUInt32(JSValue, uint32_t&);
|
|
276 |
|
|
277 |
static int32_t getTruncatedInt32(JSValue);
|
|
278 |
static uint32_t getTruncatedUInt32(JSValue);
|
|
279 |
|
|
280 |
static JSValue trueImmediate();
|
|
281 |
static JSValue falseImmediate();
|
|
282 |
static JSValue undefinedImmediate();
|
|
283 |
static JSValue nullImmediate();
|
|
284 |
static JSValue zeroImmediate();
|
|
285 |
static JSValue oneImmediate();
|
|
286 |
|
|
287 |
private:
|
|
288 |
#if USE(JSVALUE64)
|
|
289 |
static const int minImmediateInt = ((-INT_MAX) - 1);
|
|
290 |
static const int maxImmediateInt = INT_MAX;
|
|
291 |
#else
|
|
292 |
static const int minImmediateInt = ((-INT_MAX) - 1) >> IntegerPayloadShift;
|
|
293 |
static const int maxImmediateInt = INT_MAX >> IntegerPayloadShift;
|
|
294 |
#endif
|
|
295 |
static const unsigned maxImmediateUInt = maxImmediateInt;
|
|
296 |
|
|
297 |
static ALWAYS_INLINE JSValue makeValue(intptr_t integer)
|
|
298 |
{
|
|
299 |
return JSValue::makeImmediate(integer);
|
|
300 |
}
|
|
301 |
|
|
302 |
// With USE(JSVALUE64) we want the argument to be zero extended, so the
|
|
303 |
// integer doesn't interfere with the tag bits in the upper word. In the default encoding,
|
|
304 |
// if intptr_t id larger then int32_t we sign extend the value through the upper word.
|
|
305 |
#if USE(JSVALUE64)
|
|
306 |
static ALWAYS_INLINE JSValue makeInt(uint32_t value)
|
|
307 |
#else
|
|
308 |
static ALWAYS_INLINE JSValue makeInt(int32_t value)
|
|
309 |
#endif
|
|
310 |
{
|
|
311 |
return makeValue((static_cast<intptr_t>(value) << IntegerPayloadShift) | TagTypeNumber);
|
|
312 |
}
|
|
313 |
|
|
314 |
#if USE(JSVALUE64)
|
|
315 |
static ALWAYS_INLINE JSValue makeDouble(double value)
|
|
316 |
{
|
|
317 |
return makeValue(reinterpretDoubleToIntptr(value) + DoubleEncodeOffset);
|
|
318 |
}
|
|
319 |
#endif
|
|
320 |
|
|
321 |
static ALWAYS_INLINE JSValue makeBool(bool b)
|
|
322 |
{
|
|
323 |
return makeValue((static_cast<intptr_t>(b) << ExtendedPayloadShift) | FullTagTypeBool);
|
|
324 |
}
|
|
325 |
|
|
326 |
static ALWAYS_INLINE JSValue makeUndefined()
|
|
327 |
{
|
|
328 |
return makeValue(FullTagTypeUndefined);
|
|
329 |
}
|
|
330 |
|
|
331 |
static ALWAYS_INLINE JSValue makeNull()
|
|
332 |
{
|
|
333 |
return makeValue(FullTagTypeNull);
|
|
334 |
}
|
|
335 |
|
|
336 |
template<typename T>
|
|
337 |
static JSValue fromNumberOutsideIntegerRange(T);
|
|
338 |
|
|
339 |
#if USE(JSVALUE64)
|
|
340 |
static ALWAYS_INLINE double doubleValue(JSValue v)
|
|
341 |
{
|
|
342 |
return reinterpretIntptrToDouble(rawValue(v) - DoubleEncodeOffset);
|
|
343 |
}
|
|
344 |
#endif
|
|
345 |
|
|
346 |
static ALWAYS_INLINE int32_t intValue(JSValue v)
|
|
347 |
{
|
|
348 |
return static_cast<int32_t>(rawValue(v) >> IntegerPayloadShift);
|
|
349 |
}
|
|
350 |
|
|
351 |
static ALWAYS_INLINE uint32_t uintValue(JSValue v)
|
|
352 |
{
|
|
353 |
return static_cast<uint32_t>(rawValue(v) >> IntegerPayloadShift);
|
|
354 |
}
|
|
355 |
|
|
356 |
static ALWAYS_INLINE bool boolValue(JSValue v)
|
|
357 |
{
|
|
358 |
return rawValue(v) & ExtendedPayloadBitBoolValue;
|
|
359 |
}
|
|
360 |
|
|
361 |
static ALWAYS_INLINE intptr_t rawValue(JSValue v)
|
|
362 |
{
|
|
363 |
return v.immediateValue();
|
|
364 |
}
|
|
365 |
};
|
|
366 |
|
|
367 |
ALWAYS_INLINE JSValue JSImmediate::trueImmediate() { return makeBool(true); }
|
|
368 |
ALWAYS_INLINE JSValue JSImmediate::falseImmediate() { return makeBool(false); }
|
|
369 |
ALWAYS_INLINE JSValue JSImmediate::undefinedImmediate() { return makeUndefined(); }
|
|
370 |
ALWAYS_INLINE JSValue JSImmediate::nullImmediate() { return makeNull(); }
|
|
371 |
ALWAYS_INLINE JSValue JSImmediate::zeroImmediate() { return makeInt(0); }
|
|
372 |
ALWAYS_INLINE JSValue JSImmediate::oneImmediate() { return makeInt(1); }
|
|
373 |
|
|
374 |
#if USE(JSVALUE64)
|
|
375 |
inline bool doubleToBoolean(double value)
|
|
376 |
{
|
|
377 |
return value < 0.0 || value > 0.0;
|
|
378 |
}
|
|
379 |
|
|
380 |
ALWAYS_INLINE bool JSImmediate::toBoolean(JSValue v)
|
|
381 |
{
|
|
382 |
ASSERT(isImmediate(v));
|
|
383 |
return isNumber(v) ? isIntegerNumber(v) ? v != zeroImmediate()
|
|
384 |
: doubleToBoolean(doubleValue(v)) : v == trueImmediate();
|
|
385 |
}
|
|
386 |
#else
|
|
387 |
ALWAYS_INLINE bool JSImmediate::toBoolean(JSValue v)
|
|
388 |
{
|
|
389 |
ASSERT(isImmediate(v));
|
|
390 |
return isIntegerNumber(v) ? v != zeroImmediate() : v == trueImmediate();
|
|
391 |
}
|
|
392 |
#endif
|
|
393 |
|
|
394 |
ALWAYS_INLINE uint32_t JSImmediate::getTruncatedUInt32(JSValue v)
|
|
395 |
{
|
|
396 |
// FIXME: should probably be asserting isPositiveIntegerNumber here.
|
|
397 |
ASSERT(isIntegerNumber(v));
|
|
398 |
return intValue(v);
|
|
399 |
}
|
|
400 |
|
|
401 |
#if USE(JSVALUE64)
|
|
402 |
template<typename T>
|
|
403 |
inline JSValue JSImmediate::fromNumberOutsideIntegerRange(T value)
|
|
404 |
{
|
|
405 |
return makeDouble(static_cast<double>(value));
|
|
406 |
}
|
|
407 |
#else
|
|
408 |
template<typename T>
|
|
409 |
inline JSValue JSImmediate::fromNumberOutsideIntegerRange(T)
|
|
410 |
{
|
|
411 |
return JSValue();
|
|
412 |
}
|
|
413 |
#endif
|
|
414 |
|
|
415 |
ALWAYS_INLINE JSValue JSImmediate::from(char i)
|
|
416 |
{
|
|
417 |
return makeInt(i);
|
|
418 |
}
|
|
419 |
|
|
420 |
ALWAYS_INLINE JSValue JSImmediate::from(signed char i)
|
|
421 |
{
|
|
422 |
return makeInt(i);
|
|
423 |
}
|
|
424 |
|
|
425 |
ALWAYS_INLINE JSValue JSImmediate::from(unsigned char i)
|
|
426 |
{
|
|
427 |
return makeInt(i);
|
|
428 |
}
|
|
429 |
|
|
430 |
ALWAYS_INLINE JSValue JSImmediate::from(short i)
|
|
431 |
{
|
|
432 |
return makeInt(i);
|
|
433 |
}
|
|
434 |
|
|
435 |
ALWAYS_INLINE JSValue JSImmediate::from(unsigned short i)
|
|
436 |
{
|
|
437 |
return makeInt(i);
|
|
438 |
}
|
|
439 |
|
|
440 |
ALWAYS_INLINE JSValue JSImmediate::from(int i)
|
|
441 |
{
|
|
442 |
#if !USE(JSVALUE64)
|
|
443 |
if ((i < minImmediateInt) | (i > maxImmediateInt))
|
|
444 |
return fromNumberOutsideIntegerRange(i);
|
|
445 |
#endif
|
|
446 |
return makeInt(i);
|
|
447 |
}
|
|
448 |
|
|
449 |
ALWAYS_INLINE JSValue JSImmediate::from(unsigned i)
|
|
450 |
{
|
|
451 |
if (i > maxImmediateUInt)
|
|
452 |
return fromNumberOutsideIntegerRange(i);
|
|
453 |
return makeInt(i);
|
|
454 |
}
|
|
455 |
|
|
456 |
ALWAYS_INLINE JSValue JSImmediate::from(long i)
|
|
457 |
{
|
|
458 |
if ((i < minImmediateInt) | (i > maxImmediateInt))
|
|
459 |
return fromNumberOutsideIntegerRange(i);
|
|
460 |
return makeInt(i);
|
|
461 |
}
|
|
462 |
|
|
463 |
ALWAYS_INLINE JSValue JSImmediate::from(unsigned long i)
|
|
464 |
{
|
|
465 |
if (i > maxImmediateUInt)
|
|
466 |
return fromNumberOutsideIntegerRange(i);
|
|
467 |
return makeInt(i);
|
|
468 |
}
|
|
469 |
|
|
470 |
ALWAYS_INLINE JSValue JSImmediate::from(long long i)
|
|
471 |
{
|
|
472 |
if ((i < minImmediateInt) | (i > maxImmediateInt))
|
|
473 |
return JSValue();
|
|
474 |
return makeInt(static_cast<intptr_t>(i));
|
|
475 |
}
|
|
476 |
|
|
477 |
ALWAYS_INLINE JSValue JSImmediate::from(unsigned long long i)
|
|
478 |
{
|
|
479 |
if (i > maxImmediateUInt)
|
|
480 |
return fromNumberOutsideIntegerRange(i);
|
|
481 |
return makeInt(static_cast<intptr_t>(i));
|
|
482 |
}
|
|
483 |
|
|
484 |
ALWAYS_INLINE JSValue JSImmediate::from(double d)
|
|
485 |
{
|
|
486 |
const int intVal = static_cast<int>(d);
|
|
487 |
|
|
488 |
// Check for data loss from conversion to int.
|
|
489 |
if (intVal != d || (!intVal && signbit(d)))
|
|
490 |
return fromNumberOutsideIntegerRange(d);
|
|
491 |
|
|
492 |
return from(intVal);
|
|
493 |
}
|
|
494 |
|
|
495 |
ALWAYS_INLINE int32_t JSImmediate::getTruncatedInt32(JSValue v)
|
|
496 |
{
|
|
497 |
ASSERT(isIntegerNumber(v));
|
|
498 |
return intValue(v);
|
|
499 |
}
|
|
500 |
|
|
501 |
ALWAYS_INLINE double JSImmediate::toDouble(JSValue v)
|
|
502 |
{
|
|
503 |
ASSERT(isImmediate(v));
|
|
504 |
|
|
505 |
if (isIntegerNumber(v))
|
|
506 |
return intValue(v);
|
|
507 |
|
|
508 |
#if USE(JSVALUE64)
|
|
509 |
if (isNumber(v)) {
|
|
510 |
ASSERT(isDouble(v));
|
|
511 |
return doubleValue(v);
|
|
512 |
}
|
|
513 |
#else
|
|
514 |
ASSERT(!isNumber(v));
|
|
515 |
#endif
|
|
516 |
|
|
517 |
if (rawValue(v) == FullTagTypeUndefined)
|
|
518 |
return nonInlineNaN();
|
|
519 |
|
|
520 |
ASSERT(JSImmediate::isBoolean(v) || (v == JSImmediate::nullImmediate()));
|
|
521 |
return rawValue(v) >> ExtendedPayloadShift;
|
|
522 |
}
|
|
523 |
|
|
524 |
ALWAYS_INLINE bool JSImmediate::getUInt32(JSValue v, uint32_t& i)
|
|
525 |
{
|
|
526 |
i = uintValue(v);
|
|
527 |
return isPositiveIntegerNumber(v);
|
|
528 |
}
|
|
529 |
|
|
530 |
ALWAYS_INLINE bool JSImmediate::getTruncatedInt32(JSValue v, int32_t& i)
|
|
531 |
{
|
|
532 |
i = intValue(v);
|
|
533 |
return isIntegerNumber(v);
|
|
534 |
}
|
|
535 |
|
|
536 |
ALWAYS_INLINE bool JSImmediate::getTruncatedUInt32(JSValue v, uint32_t& i)
|
|
537 |
{
|
|
538 |
return getUInt32(v, i);
|
|
539 |
}
|
|
540 |
|
|
541 |
inline JSValue::JSValue(JSNullTag)
|
|
542 |
{
|
|
543 |
*this = JSImmediate::nullImmediate();
|
|
544 |
}
|
|
545 |
|
|
546 |
inline JSValue::JSValue(JSUndefinedTag)
|
|
547 |
{
|
|
548 |
*this = JSImmediate::undefinedImmediate();
|
|
549 |
}
|
|
550 |
|
|
551 |
inline JSValue::JSValue(JSTrueTag)
|
|
552 |
{
|
|
553 |
*this = JSImmediate::trueImmediate();
|
|
554 |
}
|
|
555 |
|
|
556 |
inline JSValue::JSValue(JSFalseTag)
|
|
557 |
{
|
|
558 |
*this = JSImmediate::falseImmediate();
|
|
559 |
}
|
|
560 |
|
|
561 |
inline bool JSValue::isUndefinedOrNull() const
|
|
562 |
{
|
|
563 |
return JSImmediate::isUndefinedOrNull(asValue());
|
|
564 |
}
|
|
565 |
|
|
566 |
inline bool JSValue::isBoolean() const
|
|
567 |
{
|
|
568 |
return JSImmediate::isBoolean(asValue());
|
|
569 |
}
|
|
570 |
|
|
571 |
inline bool JSValue::isTrue() const
|
|
572 |
{
|
|
573 |
return asValue() == JSImmediate::trueImmediate();
|
|
574 |
}
|
|
575 |
|
|
576 |
inline bool JSValue::isFalse() const
|
|
577 |
{
|
|
578 |
return asValue() == JSImmediate::falseImmediate();
|
|
579 |
}
|
|
580 |
|
|
581 |
inline bool JSValue::getBoolean(bool& v) const
|
|
582 |
{
|
|
583 |
if (JSImmediate::isBoolean(asValue())) {
|
|
584 |
v = JSImmediate::toBoolean(asValue());
|
|
585 |
return true;
|
|
586 |
}
|
|
587 |
|
|
588 |
return false;
|
|
589 |
}
|
|
590 |
|
|
591 |
inline bool JSValue::getBoolean() const
|
|
592 |
{
|
|
593 |
return asValue() == jsBoolean(true);
|
|
594 |
}
|
|
595 |
|
|
596 |
inline bool JSValue::isCell() const
|
|
597 |
{
|
|
598 |
return !JSImmediate::isImmediate(asValue());
|
|
599 |
}
|
|
600 |
|
|
601 |
inline bool JSValue::isInt32() const
|
|
602 |
{
|
|
603 |
return JSImmediate::isIntegerNumber(asValue());
|
|
604 |
}
|
|
605 |
|
|
606 |
inline int32_t JSValue::asInt32() const
|
|
607 |
{
|
|
608 |
ASSERT(isInt32());
|
|
609 |
return JSImmediate::getTruncatedInt32(asValue());
|
|
610 |
}
|
|
611 |
|
|
612 |
inline bool JSValue::isUInt32() const
|
|
613 |
{
|
|
614 |
return JSImmediate::isPositiveIntegerNumber(asValue());
|
|
615 |
}
|
|
616 |
|
|
617 |
inline uint32_t JSValue::asUInt32() const
|
|
618 |
{
|
|
619 |
ASSERT(isUInt32());
|
|
620 |
return JSImmediate::getTruncatedUInt32(asValue());
|
|
621 |
}
|
|
622 |
|
|
623 |
class JSFastMath {
|
|
624 |
public:
|
|
625 |
static ALWAYS_INLINE bool canDoFastBitwiseOperations(JSValue v1, JSValue v2)
|
|
626 |
{
|
|
627 |
return JSImmediate::areBothImmediateIntegerNumbers(v1, v2);
|
|
628 |
}
|
|
629 |
|
|
630 |
static ALWAYS_INLINE JSValue equal(JSValue v1, JSValue v2)
|
|
631 |
{
|
|
632 |
ASSERT(canDoFastBitwiseOperations(v1, v2));
|
|
633 |
return jsBoolean(v1 == v2);
|
|
634 |
}
|
|
635 |
|
|
636 |
static ALWAYS_INLINE JSValue notEqual(JSValue v1, JSValue v2)
|
|
637 |
{
|
|
638 |
ASSERT(canDoFastBitwiseOperations(v1, v2));
|
|
639 |
return jsBoolean(v1 != v2);
|
|
640 |
}
|
|
641 |
|
|
642 |
static ALWAYS_INLINE JSValue andImmediateNumbers(JSValue v1, JSValue v2)
|
|
643 |
{
|
|
644 |
ASSERT(canDoFastBitwiseOperations(v1, v2));
|
|
645 |
return JSImmediate::makeValue(JSImmediate::rawValue(v1) & JSImmediate::rawValue(v2));
|
|
646 |
}
|
|
647 |
|
|
648 |
static ALWAYS_INLINE JSValue xorImmediateNumbers(JSValue v1, JSValue v2)
|
|
649 |
{
|
|
650 |
ASSERT(canDoFastBitwiseOperations(v1, v2));
|
|
651 |
return JSImmediate::makeValue((JSImmediate::rawValue(v1) ^ JSImmediate::rawValue(v2)) | JSImmediate::TagTypeNumber);
|
|
652 |
}
|
|
653 |
|
|
654 |
static ALWAYS_INLINE JSValue orImmediateNumbers(JSValue v1, JSValue v2)
|
|
655 |
{
|
|
656 |
ASSERT(canDoFastBitwiseOperations(v1, v2));
|
|
657 |
return JSImmediate::makeValue(JSImmediate::rawValue(v1) | JSImmediate::rawValue(v2));
|
|
658 |
}
|
|
659 |
|
|
660 |
static ALWAYS_INLINE bool canDoFastRshift(JSValue v1, JSValue v2)
|
|
661 |
{
|
|
662 |
return JSImmediate::areBothImmediateIntegerNumbers(v1, v2);
|
|
663 |
}
|
|
664 |
|
|
665 |
static ALWAYS_INLINE bool canDoFastUrshift(JSValue v1, JSValue v2)
|
|
666 |
{
|
|
667 |
return JSImmediate::areBothImmediateIntegerNumbers(v1, v2) && !(JSImmediate::rawValue(v1) & JSImmediate::signBit);
|
|
668 |
}
|
|
669 |
|
|
670 |
static ALWAYS_INLINE JSValue rightShiftImmediateNumbers(JSValue val, JSValue shift)
|
|
671 |
{
|
|
672 |
ASSERT(canDoFastRshift(val, shift) || canDoFastUrshift(val, shift));
|
|
673 |
#if USE(JSVALUE64)
|
|
674 |
return JSImmediate::makeValue(static_cast<intptr_t>(static_cast<uint32_t>(static_cast<int32_t>(JSImmediate::rawValue(val)) >> ((JSImmediate::rawValue(shift) >> JSImmediate::IntegerPayloadShift) & 0x1f))) | JSImmediate::TagTypeNumber);
|
|
675 |
#else
|
|
676 |
return JSImmediate::makeValue((JSImmediate::rawValue(val) >> ((JSImmediate::rawValue(shift) >> JSImmediate::IntegerPayloadShift) & 0x1f)) | JSImmediate::TagTypeNumber);
|
|
677 |
#endif
|
|
678 |
}
|
|
679 |
|
|
680 |
static ALWAYS_INLINE bool canDoFastAdditiveOperations(JSValue v)
|
|
681 |
{
|
|
682 |
// Number is non-negative and an operation involving two of these can't overflow.
|
|
683 |
// Checking for allowed negative numbers takes more time than it's worth on SunSpider.
|
|
684 |
return (JSImmediate::rawValue(v) & (JSImmediate::TagTypeNumber + (JSImmediate::signBit | (JSImmediate::signBit >> 1)))) == JSImmediate::TagTypeNumber;
|
|
685 |
}
|
|
686 |
|
|
687 |
static ALWAYS_INLINE bool canDoFastAdditiveOperations(JSValue v1, JSValue v2)
|
|
688 |
{
|
|
689 |
// Number is non-negative and an operation involving two of these can't overflow.
|
|
690 |
// Checking for allowed negative numbers takes more time than it's worth on SunSpider.
|
|
691 |
return canDoFastAdditiveOperations(v1) && canDoFastAdditiveOperations(v2);
|
|
692 |
}
|
|
693 |
|
|
694 |
static ALWAYS_INLINE JSValue addImmediateNumbers(JSValue v1, JSValue v2)
|
|
695 |
{
|
|
696 |
ASSERT(canDoFastAdditiveOperations(v1, v2));
|
|
697 |
return JSImmediate::makeValue(JSImmediate::rawValue(v1) + JSImmediate::rawValue(v2) - JSImmediate::TagTypeNumber);
|
|
698 |
}
|
|
699 |
|
|
700 |
static ALWAYS_INLINE JSValue subImmediateNumbers(JSValue v1, JSValue v2)
|
|
701 |
{
|
|
702 |
ASSERT(canDoFastAdditiveOperations(v1, v2));
|
|
703 |
return JSImmediate::makeValue(JSImmediate::rawValue(v1) - JSImmediate::rawValue(v2) + JSImmediate::TagTypeNumber);
|
|
704 |
}
|
|
705 |
|
|
706 |
static ALWAYS_INLINE JSValue incImmediateNumber(JSValue v)
|
|
707 |
{
|
|
708 |
ASSERT(canDoFastAdditiveOperations(v));
|
|
709 |
return JSImmediate::makeValue(JSImmediate::rawValue(v) + (1 << JSImmediate::IntegerPayloadShift));
|
|
710 |
}
|
|
711 |
|
|
712 |
static ALWAYS_INLINE JSValue decImmediateNumber(JSValue v)
|
|
713 |
{
|
|
714 |
ASSERT(canDoFastAdditiveOperations(v));
|
|
715 |
return JSImmediate::makeValue(JSImmediate::rawValue(v) - (1 << JSImmediate::IntegerPayloadShift));
|
|
716 |
}
|
|
717 |
};
|
|
718 |
|
|
719 |
} // namespace JSC
|
|
720 |
|
|
721 |
#endif // !USE(JSVALUE32_64)
|
|
722 |
|
|
723 |
#endif // JSImmediate_h
|