]>
Commit | Line | Data |
---|---|---|
9dae56ea A |
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 | ||
ba379fdc A |
25 | #include <wtf/Platform.h> |
26 | ||
27 | #if !USE(JSVALUE32_64) | |
28 | ||
9dae56ea A |
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 | ||
ba379fdc | 49 | #if USE(JSVALUE64) |
9dae56ea A |
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 | |
ba379fdc | 105 | * USE(JSVALUE64) is defined. When this format is used, double precision |
9dae56ea A |
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; | |
ba379fdc | 139 | friend class JSValue; |
9dae56ea | 140 | friend class JSFastMath; |
ba379fdc A |
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) | |
9dae56ea A |
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 | ||
ba379fdc | 184 | #if USE(JSVALUE64) |
9dae56ea A |
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 | ||
ba379fdc | 195 | static ALWAYS_INLINE bool isImmediate(JSValue v) |
9dae56ea A |
196 | { |
197 | return rawValue(v) & TagMask; | |
198 | } | |
199 | ||
ba379fdc | 200 | static ALWAYS_INLINE bool isNumber(JSValue v) |
9dae56ea A |
201 | { |
202 | return rawValue(v) & TagTypeNumber; | |
203 | } | |
204 | ||
ba379fdc | 205 | static ALWAYS_INLINE bool isIntegerNumber(JSValue v) |
9dae56ea | 206 | { |
ba379fdc | 207 | #if USE(JSVALUE64) |
9dae56ea A |
208 | return (rawValue(v) & TagTypeNumber) == TagTypeNumber; |
209 | #else | |
210 | return isNumber(v); | |
211 | #endif | |
212 | } | |
213 | ||
ba379fdc A |
214 | #if USE(JSVALUE64) |
215 | static ALWAYS_INLINE bool isDouble(JSValue v) | |
9dae56ea A |
216 | { |
217 | return isNumber(v) && !isIntegerNumber(v); | |
218 | } | |
219 | #endif | |
220 | ||
ba379fdc | 221 | static ALWAYS_INLINE bool isPositiveIntegerNumber(JSValue v) |
9dae56ea A |
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 | ||
ba379fdc | 227 | static ALWAYS_INLINE bool isBoolean(JSValue v) |
9dae56ea A |
228 | { |
229 | return (rawValue(v) & FullTagTypeMask) == FullTagTypeBool; | |
230 | } | |
231 | ||
ba379fdc | 232 | static ALWAYS_INLINE bool isUndefinedOrNull(JSValue v) |
9dae56ea A |
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 | ||
ba379fdc A |
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); | |
9dae56ea | 250 | |
ba379fdc | 251 | static ALWAYS_INLINE bool isEitherImmediate(JSValue v1, JSValue v2) |
9dae56ea A |
252 | { |
253 | return (rawValue(v1) | rawValue(v2)) & TagMask; | |
254 | } | |
255 | ||
ba379fdc | 256 | static ALWAYS_INLINE bool areBothImmediate(JSValue v1, JSValue v2) |
9dae56ea A |
257 | { |
258 | return isImmediate(v1) & isImmediate(v2); | |
259 | } | |
260 | ||
ba379fdc | 261 | static ALWAYS_INLINE bool areBothImmediateIntegerNumbers(JSValue v1, JSValue v2) |
9dae56ea | 262 | { |
ba379fdc | 263 | #if USE(JSVALUE64) |
9dae56ea A |
264 | return (rawValue(v1) & rawValue(v2) & TagTypeNumber) == TagTypeNumber; |
265 | #else | |
266 | return rawValue(v1) & rawValue(v2) & TagTypeNumber; | |
267 | #endif | |
268 | } | |
269 | ||
ba379fdc A |
270 | static double toDouble(JSValue); |
271 | static bool toBoolean(JSValue); | |
9dae56ea | 272 | |
ba379fdc A |
273 | static bool getUInt32(JSValue, uint32_t&); |
274 | static bool getTruncatedInt32(JSValue, int32_t&); | |
275 | static bool getTruncatedUInt32(JSValue, uint32_t&); | |
9dae56ea | 276 | |
ba379fdc A |
277 | static int32_t getTruncatedInt32(JSValue); |
278 | static uint32_t getTruncatedUInt32(JSValue); | |
9dae56ea | 279 | |
ba379fdc A |
280 | static JSValue trueImmediate(); |
281 | static JSValue falseImmediate(); | |
282 | static JSValue undefinedImmediate(); | |
283 | static JSValue nullImmediate(); | |
284 | static JSValue zeroImmediate(); | |
285 | static JSValue oneImmediate(); | |
9dae56ea A |
286 | |
287 | private: | |
ba379fdc | 288 | #if USE(JSVALUE64) |
9dae56ea A |
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 | ||
ba379fdc | 297 | static ALWAYS_INLINE JSValue makeValue(intptr_t integer) |
9dae56ea | 298 | { |
ba379fdc | 299 | return JSValue::makeImmediate(integer); |
9dae56ea A |
300 | } |
301 | ||
ba379fdc | 302 | // With USE(JSVALUE64) we want the argument to be zero extended, so the |
9dae56ea A |
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. | |
ba379fdc A |
305 | #if USE(JSVALUE64) |
306 | static ALWAYS_INLINE JSValue makeInt(uint32_t value) | |
9dae56ea | 307 | #else |
ba379fdc | 308 | static ALWAYS_INLINE JSValue makeInt(int32_t value) |
9dae56ea A |
309 | #endif |
310 | { | |
311 | return makeValue((static_cast<intptr_t>(value) << IntegerPayloadShift) | TagTypeNumber); | |
312 | } | |
313 | ||
ba379fdc A |
314 | #if USE(JSVALUE64) |
315 | static ALWAYS_INLINE JSValue makeDouble(double value) | |
9dae56ea A |
316 | { |
317 | return makeValue(reinterpretDoubleToIntptr(value) + DoubleEncodeOffset); | |
318 | } | |
319 | #endif | |
320 | ||
ba379fdc | 321 | static ALWAYS_INLINE JSValue makeBool(bool b) |
9dae56ea A |
322 | { |
323 | return makeValue((static_cast<intptr_t>(b) << ExtendedPayloadShift) | FullTagTypeBool); | |
324 | } | |
325 | ||
ba379fdc | 326 | static ALWAYS_INLINE JSValue makeUndefined() |
9dae56ea A |
327 | { |
328 | return makeValue(FullTagTypeUndefined); | |
329 | } | |
330 | ||
ba379fdc | 331 | static ALWAYS_INLINE JSValue makeNull() |
9dae56ea A |
332 | { |
333 | return makeValue(FullTagTypeNull); | |
334 | } | |
335 | ||
336 | template<typename T> | |
ba379fdc | 337 | static JSValue fromNumberOutsideIntegerRange(T); |
9dae56ea | 338 | |
ba379fdc A |
339 | #if USE(JSVALUE64) |
340 | static ALWAYS_INLINE double doubleValue(JSValue v) | |
9dae56ea A |
341 | { |
342 | return reinterpretIntptrToDouble(rawValue(v) - DoubleEncodeOffset); | |
343 | } | |
344 | #endif | |
345 | ||
ba379fdc | 346 | static ALWAYS_INLINE int32_t intValue(JSValue v) |
9dae56ea A |
347 | { |
348 | return static_cast<int32_t>(rawValue(v) >> IntegerPayloadShift); | |
349 | } | |
350 | ||
ba379fdc | 351 | static ALWAYS_INLINE uint32_t uintValue(JSValue v) |
9dae56ea A |
352 | { |
353 | return static_cast<uint32_t>(rawValue(v) >> IntegerPayloadShift); | |
354 | } | |
355 | ||
ba379fdc | 356 | static ALWAYS_INLINE bool boolValue(JSValue v) |
9dae56ea A |
357 | { |
358 | return rawValue(v) & ExtendedPayloadBitBoolValue; | |
359 | } | |
360 | ||
ba379fdc | 361 | static ALWAYS_INLINE intptr_t rawValue(JSValue v) |
9dae56ea A |
362 | { |
363 | return v.immediateValue(); | |
364 | } | |
9dae56ea A |
365 | }; |
366 | ||
ba379fdc A |
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); } | |
9dae56ea | 373 | |
ba379fdc | 374 | #if USE(JSVALUE64) |
9dae56ea A |
375 | inline bool doubleToBoolean(double value) |
376 | { | |
377 | return value < 0.0 || value > 0.0; | |
378 | } | |
379 | ||
ba379fdc | 380 | ALWAYS_INLINE bool JSImmediate::toBoolean(JSValue v) |
9dae56ea A |
381 | { |
382 | ASSERT(isImmediate(v)); | |
383 | return isNumber(v) ? isIntegerNumber(v) ? v != zeroImmediate() | |
384 | : doubleToBoolean(doubleValue(v)) : v == trueImmediate(); | |
385 | } | |
386 | #else | |
ba379fdc | 387 | ALWAYS_INLINE bool JSImmediate::toBoolean(JSValue v) |
9dae56ea A |
388 | { |
389 | ASSERT(isImmediate(v)); | |
390 | return isIntegerNumber(v) ? v != zeroImmediate() : v == trueImmediate(); | |
391 | } | |
392 | #endif | |
393 | ||
ba379fdc | 394 | ALWAYS_INLINE uint32_t JSImmediate::getTruncatedUInt32(JSValue v) |
9dae56ea A |
395 | { |
396 | // FIXME: should probably be asserting isPositiveIntegerNumber here. | |
397 | ASSERT(isIntegerNumber(v)); | |
398 | return intValue(v); | |
399 | } | |
400 | ||
ba379fdc | 401 | #if USE(JSVALUE64) |
9dae56ea | 402 | template<typename T> |
ba379fdc | 403 | inline JSValue JSImmediate::fromNumberOutsideIntegerRange(T value) |
9dae56ea A |
404 | { |
405 | return makeDouble(static_cast<double>(value)); | |
406 | } | |
407 | #else | |
408 | template<typename T> | |
ba379fdc | 409 | inline JSValue JSImmediate::fromNumberOutsideIntegerRange(T) |
9dae56ea | 410 | { |
ba379fdc | 411 | return JSValue(); |
9dae56ea A |
412 | } |
413 | #endif | |
414 | ||
ba379fdc | 415 | ALWAYS_INLINE JSValue JSImmediate::from(char i) |
9dae56ea A |
416 | { |
417 | return makeInt(i); | |
418 | } | |
419 | ||
ba379fdc | 420 | ALWAYS_INLINE JSValue JSImmediate::from(signed char i) |
9dae56ea A |
421 | { |
422 | return makeInt(i); | |
423 | } | |
424 | ||
ba379fdc | 425 | ALWAYS_INLINE JSValue JSImmediate::from(unsigned char i) |
9dae56ea A |
426 | { |
427 | return makeInt(i); | |
428 | } | |
429 | ||
ba379fdc | 430 | ALWAYS_INLINE JSValue JSImmediate::from(short i) |
9dae56ea A |
431 | { |
432 | return makeInt(i); | |
433 | } | |
434 | ||
ba379fdc | 435 | ALWAYS_INLINE JSValue JSImmediate::from(unsigned short i) |
9dae56ea A |
436 | { |
437 | return makeInt(i); | |
438 | } | |
439 | ||
ba379fdc | 440 | ALWAYS_INLINE JSValue JSImmediate::from(int i) |
9dae56ea | 441 | { |
ba379fdc | 442 | #if !USE(JSVALUE64) |
9dae56ea A |
443 | if ((i < minImmediateInt) | (i > maxImmediateInt)) |
444 | return fromNumberOutsideIntegerRange(i); | |
445 | #endif | |
446 | return makeInt(i); | |
447 | } | |
448 | ||
ba379fdc | 449 | ALWAYS_INLINE JSValue JSImmediate::from(unsigned i) |
9dae56ea A |
450 | { |
451 | if (i > maxImmediateUInt) | |
452 | return fromNumberOutsideIntegerRange(i); | |
453 | return makeInt(i); | |
454 | } | |
455 | ||
ba379fdc | 456 | ALWAYS_INLINE JSValue JSImmediate::from(long i) |
9dae56ea A |
457 | { |
458 | if ((i < minImmediateInt) | (i > maxImmediateInt)) | |
459 | return fromNumberOutsideIntegerRange(i); | |
460 | return makeInt(i); | |
461 | } | |
462 | ||
ba379fdc | 463 | ALWAYS_INLINE JSValue JSImmediate::from(unsigned long i) |
9dae56ea A |
464 | { |
465 | if (i > maxImmediateUInt) | |
466 | return fromNumberOutsideIntegerRange(i); | |
467 | return makeInt(i); | |
468 | } | |
469 | ||
ba379fdc | 470 | ALWAYS_INLINE JSValue JSImmediate::from(long long i) |
9dae56ea A |
471 | { |
472 | if ((i < minImmediateInt) | (i > maxImmediateInt)) | |
ba379fdc | 473 | return JSValue(); |
9dae56ea A |
474 | return makeInt(static_cast<intptr_t>(i)); |
475 | } | |
476 | ||
ba379fdc | 477 | ALWAYS_INLINE JSValue JSImmediate::from(unsigned long long i) |
9dae56ea A |
478 | { |
479 | if (i > maxImmediateUInt) | |
480 | return fromNumberOutsideIntegerRange(i); | |
481 | return makeInt(static_cast<intptr_t>(i)); | |
482 | } | |
483 | ||
ba379fdc | 484 | ALWAYS_INLINE JSValue JSImmediate::from(double d) |
9dae56ea A |
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 | ||
ba379fdc | 495 | ALWAYS_INLINE int32_t JSImmediate::getTruncatedInt32(JSValue v) |
9dae56ea A |
496 | { |
497 | ASSERT(isIntegerNumber(v)); | |
498 | return intValue(v); | |
499 | } | |
500 | ||
ba379fdc | 501 | ALWAYS_INLINE double JSImmediate::toDouble(JSValue v) |
9dae56ea A |
502 | { |
503 | ASSERT(isImmediate(v)); | |
504 | ||
505 | if (isIntegerNumber(v)) | |
506 | return intValue(v); | |
507 | ||
ba379fdc | 508 | #if USE(JSVALUE64) |
9dae56ea | 509 | if (isNumber(v)) { |
ba379fdc | 510 | ASSERT(isDouble(v)); |
9dae56ea A |
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 | ||
ba379fdc | 524 | ALWAYS_INLINE bool JSImmediate::getUInt32(JSValue v, uint32_t& i) |
9dae56ea A |
525 | { |
526 | i = uintValue(v); | |
527 | return isPositiveIntegerNumber(v); | |
528 | } | |
529 | ||
ba379fdc | 530 | ALWAYS_INLINE bool JSImmediate::getTruncatedInt32(JSValue v, int32_t& i) |
9dae56ea A |
531 | { |
532 | i = intValue(v); | |
533 | return isIntegerNumber(v); | |
534 | } | |
535 | ||
ba379fdc | 536 | ALWAYS_INLINE bool JSImmediate::getTruncatedUInt32(JSValue v, uint32_t& i) |
9dae56ea A |
537 | { |
538 | return getUInt32(v, i); | |
539 | } | |
540 | ||
ba379fdc | 541 | inline JSValue::JSValue(JSNullTag) |
9dae56ea | 542 | { |
ba379fdc | 543 | *this = JSImmediate::nullImmediate(); |
9dae56ea | 544 | } |
ba379fdc A |
545 | |
546 | inline JSValue::JSValue(JSUndefinedTag) | |
9dae56ea | 547 | { |
ba379fdc | 548 | *this = JSImmediate::undefinedImmediate(); |
9dae56ea A |
549 | } |
550 | ||
ba379fdc | 551 | inline JSValue::JSValue(JSTrueTag) |
9dae56ea | 552 | { |
ba379fdc | 553 | *this = JSImmediate::trueImmediate(); |
9dae56ea A |
554 | } |
555 | ||
ba379fdc | 556 | inline JSValue::JSValue(JSFalseTag) |
9dae56ea | 557 | { |
ba379fdc | 558 | *this = JSImmediate::falseImmediate(); |
9dae56ea A |
559 | } |
560 | ||
ba379fdc | 561 | inline bool JSValue::isUndefinedOrNull() const |
9dae56ea | 562 | { |
ba379fdc | 563 | return JSImmediate::isUndefinedOrNull(asValue()); |
9dae56ea A |
564 | } |
565 | ||
ba379fdc | 566 | inline bool JSValue::isBoolean() const |
9dae56ea | 567 | { |
ba379fdc | 568 | return JSImmediate::isBoolean(asValue()); |
9dae56ea A |
569 | } |
570 | ||
ba379fdc | 571 | inline bool JSValue::isTrue() const |
9dae56ea | 572 | { |
ba379fdc | 573 | return asValue() == JSImmediate::trueImmediate(); |
9dae56ea A |
574 | } |
575 | ||
ba379fdc | 576 | inline bool JSValue::isFalse() const |
9dae56ea | 577 | { |
ba379fdc | 578 | return asValue() == JSImmediate::falseImmediate(); |
9dae56ea A |
579 | } |
580 | ||
ba379fdc | 581 | inline bool JSValue::getBoolean(bool& v) const |
9dae56ea A |
582 | { |
583 | if (JSImmediate::isBoolean(asValue())) { | |
584 | v = JSImmediate::toBoolean(asValue()); | |
585 | return true; | |
586 | } | |
587 | ||
588 | return false; | |
589 | } | |
590 | ||
ba379fdc | 591 | inline bool JSValue::getBoolean() const |
9dae56ea A |
592 | { |
593 | return asValue() == jsBoolean(true); | |
594 | } | |
595 | ||
ba379fdc | 596 | inline bool JSValue::isCell() const |
9dae56ea A |
597 | { |
598 | return !JSImmediate::isImmediate(asValue()); | |
599 | } | |
600 | ||
ba379fdc | 601 | inline bool JSValue::isInt32() const |
9dae56ea A |
602 | { |
603 | return JSImmediate::isIntegerNumber(asValue()); | |
604 | } | |
605 | ||
ba379fdc | 606 | inline int32_t JSValue::asInt32() const |
9dae56ea | 607 | { |
ba379fdc | 608 | ASSERT(isInt32()); |
9dae56ea A |
609 | return JSImmediate::getTruncatedInt32(asValue()); |
610 | } | |
611 | ||
ba379fdc | 612 | inline bool JSValue::isUInt32() const |
9dae56ea A |
613 | { |
614 | return JSImmediate::isPositiveIntegerNumber(asValue()); | |
615 | } | |
616 | ||
ba379fdc | 617 | inline uint32_t JSValue::asUInt32() const |
9dae56ea | 618 | { |
ba379fdc | 619 | ASSERT(isUInt32()); |
9dae56ea A |
620 | return JSImmediate::getTruncatedUInt32(asValue()); |
621 | } | |
622 | ||
9dae56ea A |
623 | class JSFastMath { |
624 | public: | |
ba379fdc | 625 | static ALWAYS_INLINE bool canDoFastBitwiseOperations(JSValue v1, JSValue v2) |
9dae56ea A |
626 | { |
627 | return JSImmediate::areBothImmediateIntegerNumbers(v1, v2); | |
628 | } | |
629 | ||
ba379fdc | 630 | static ALWAYS_INLINE JSValue equal(JSValue v1, JSValue v2) |
9dae56ea A |
631 | { |
632 | ASSERT(canDoFastBitwiseOperations(v1, v2)); | |
633 | return jsBoolean(v1 == v2); | |
634 | } | |
635 | ||
ba379fdc | 636 | static ALWAYS_INLINE JSValue notEqual(JSValue v1, JSValue v2) |
9dae56ea A |
637 | { |
638 | ASSERT(canDoFastBitwiseOperations(v1, v2)); | |
639 | return jsBoolean(v1 != v2); | |
640 | } | |
641 | ||
ba379fdc | 642 | static ALWAYS_INLINE JSValue andImmediateNumbers(JSValue v1, JSValue v2) |
9dae56ea A |
643 | { |
644 | ASSERT(canDoFastBitwiseOperations(v1, v2)); | |
645 | return JSImmediate::makeValue(JSImmediate::rawValue(v1) & JSImmediate::rawValue(v2)); | |
646 | } | |
647 | ||
ba379fdc | 648 | static ALWAYS_INLINE JSValue xorImmediateNumbers(JSValue v1, JSValue v2) |
9dae56ea A |
649 | { |
650 | ASSERT(canDoFastBitwiseOperations(v1, v2)); | |
651 | return JSImmediate::makeValue((JSImmediate::rawValue(v1) ^ JSImmediate::rawValue(v2)) | JSImmediate::TagTypeNumber); | |
652 | } | |
653 | ||
ba379fdc | 654 | static ALWAYS_INLINE JSValue orImmediateNumbers(JSValue v1, JSValue v2) |
9dae56ea A |
655 | { |
656 | ASSERT(canDoFastBitwiseOperations(v1, v2)); | |
657 | return JSImmediate::makeValue(JSImmediate::rawValue(v1) | JSImmediate::rawValue(v2)); | |
658 | } | |
659 | ||
ba379fdc | 660 | static ALWAYS_INLINE bool canDoFastRshift(JSValue v1, JSValue v2) |
9dae56ea A |
661 | { |
662 | return JSImmediate::areBothImmediateIntegerNumbers(v1, v2); | |
663 | } | |
664 | ||
ba379fdc | 665 | static ALWAYS_INLINE bool canDoFastUrshift(JSValue v1, JSValue v2) |
9dae56ea A |
666 | { |
667 | return JSImmediate::areBothImmediateIntegerNumbers(v1, v2) && !(JSImmediate::rawValue(v1) & JSImmediate::signBit); | |
668 | } | |
669 | ||
ba379fdc | 670 | static ALWAYS_INLINE JSValue rightShiftImmediateNumbers(JSValue val, JSValue shift) |
9dae56ea A |
671 | { |
672 | ASSERT(canDoFastRshift(val, shift) || canDoFastUrshift(val, shift)); | |
ba379fdc | 673 | #if USE(JSVALUE64) |
9dae56ea A |
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 | ||
ba379fdc | 680 | static ALWAYS_INLINE bool canDoFastAdditiveOperations(JSValue v) |
9dae56ea A |
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 | ||
ba379fdc | 687 | static ALWAYS_INLINE bool canDoFastAdditiveOperations(JSValue v1, JSValue v2) |
9dae56ea A |
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 | ||
ba379fdc | 694 | static ALWAYS_INLINE JSValue addImmediateNumbers(JSValue v1, JSValue v2) |
9dae56ea A |
695 | { |
696 | ASSERT(canDoFastAdditiveOperations(v1, v2)); | |
697 | return JSImmediate::makeValue(JSImmediate::rawValue(v1) + JSImmediate::rawValue(v2) - JSImmediate::TagTypeNumber); | |
698 | } | |
699 | ||
ba379fdc | 700 | static ALWAYS_INLINE JSValue subImmediateNumbers(JSValue v1, JSValue v2) |
9dae56ea A |
701 | { |
702 | ASSERT(canDoFastAdditiveOperations(v1, v2)); | |
703 | return JSImmediate::makeValue(JSImmediate::rawValue(v1) - JSImmediate::rawValue(v2) + JSImmediate::TagTypeNumber); | |
704 | } | |
705 | ||
ba379fdc | 706 | static ALWAYS_INLINE JSValue incImmediateNumber(JSValue v) |
9dae56ea A |
707 | { |
708 | ASSERT(canDoFastAdditiveOperations(v)); | |
709 | return JSImmediate::makeValue(JSImmediate::rawValue(v) + (1 << JSImmediate::IntegerPayloadShift)); | |
710 | } | |
711 | ||
ba379fdc | 712 | static ALWAYS_INLINE JSValue decImmediateNumber(JSValue v) |
9dae56ea A |
713 | { |
714 | ASSERT(canDoFastAdditiveOperations(v)); | |
715 | return JSImmediate::makeValue(JSImmediate::rawValue(v) - (1 << JSImmediate::IntegerPayloadShift)); | |
716 | } | |
717 | }; | |
718 | ||
719 | } // namespace JSC | |
720 | ||
ba379fdc A |
721 | #endif // !USE(JSVALUE32_64) |
722 | ||
9dae56ea | 723 | #endif // JSImmediate_h |