]> git.saurik.com Git - apple/javascriptcore.git/blame - runtime/JSImmediate.h
JavaScriptCore-721.26.tar.gz
[apple/javascriptcore.git] / runtime / JSImmediate.h
CommitLineData
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#if !USE(JSVALUE32_64)
26
9dae56ea
A
27#include <wtf/Assertions.h>
28#include <wtf/AlwaysInline.h>
29#include <wtf/MathExtras.h>
30#include <wtf/StdLibExtras.h>
31#include "JSValue.h"
32#include <limits>
33#include <limits.h>
34#include <stdarg.h>
35#include <stdint.h>
36#include <stdlib.h>
37
38namespace JSC {
39
40 class ExecState;
41 class JSCell;
42 class JSFastMath;
43 class JSGlobalData;
44 class JSObject;
45 class UString;
46
ba379fdc 47#if USE(JSVALUE64)
9dae56ea
A
48 inline intptr_t reinterpretDoubleToIntptr(double value)
49 {
50 return WTF::bitwise_cast<intptr_t>(value);
51 }
52
53 inline double reinterpretIntptrToDouble(intptr_t value)
54 {
55 return WTF::bitwise_cast<double>(value);
56 }
57#endif
58
59 /*
60 * A JSValue* is either a pointer to a cell (a heap-allocated object) or an immediate (a type-tagged
61 * value masquerading as a pointer). The low two bits in a JSValue* are available for type tagging
62 * because allocator alignment guarantees they will be 00 in cell pointers.
63 *
64 * For example, on a 32 bit system:
65 *
66 * JSCell*: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 00
67 * [ high 30 bits: pointer address ] [ low 2 bits -- always 0 ]
68 * JSImmediate: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX TT
69 * [ high 30 bits: 'payload' ] [ low 2 bits -- tag ]
70 *
71 * Where the bottom two bits are non-zero they either indicate that the immediate is a 31 bit signed
72 * integer, or they mark the value as being an immediate of a type other than integer, with a secondary
73 * tag used to indicate the exact type.
74 *
75 * Where the lowest bit is set (TT is equal to 01 or 11) the high 31 bits form a 31 bit signed int value.
76 * Where TT is equal to 10 this indicates this is a type of immediate other than an integer, and the next
77 * two bits will form an extended tag.
78 *
79 * 31 bit signed int: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX X1
80 * [ high 30 bits of the value ] [ high bit part of value ]
81 * Other: YYYYYYYYYYYYYYYYYYYYYYYYYYYY ZZ 10
82 * [ extended 'payload' ] [ extended tag ] [ tag 'other' ]
83 *
84 * Where the first bit of the extended tag is set this flags the value as being a boolean, and the following
85 * bit would flag the value as undefined. If neither bits are set, the value is null.
86 *
87 * Other: YYYYYYYYYYYYYYYYYYYYYYYYYYYY UB 10
88 * [ extended 'payload' ] [ undefined | bool ] [ tag 'other' ]
89 *
90 * For boolean value the lowest bit in the payload holds the value of the bool, all remaining bits are zero.
91 * For undefined or null immediates the payload is zero.
92 *
93 * Boolean: 000000000000000000000000000V 01 10
94 * [ boolean value ] [ bool ] [ tag 'other' ]
95 * Undefined: 0000000000000000000000000000 10 10
96 * [ zero ] [ undefined ] [ tag 'other' ]
97 * Null: 0000000000000000000000000000 00 10
98 * [ zero ] [ zero ] [ tag 'other' ]
99 */
100
101 /*
102 * On 64-bit platforms, we support an alternative encoding form for immediates, if
ba379fdc 103 * USE(JSVALUE64) is defined. When this format is used, double precision
9dae56ea
A
104 * floating point values may also be encoded as JSImmediates.
105 *
106 * The encoding makes use of unused NaN space in the IEEE754 representation. Any value
107 * with the top 13 bits set represents a QNaN (with the sign bit set). QNaN values
108 * can encode a 51-bit payload. Hardware produced and C-library payloads typically
109 * have a payload of zero. We assume that non-zero payloads are available to encode
110 * pointer and integer values. Since any 64-bit bit pattern where the top 15 bits are
111 * all set represents a NaN with a non-zero payload, we can use this space in the NaN
112 * ranges to encode other values (however there are also other ranges of NaN space that
113 * could have been selected). This range of NaN space is represented by 64-bit numbers
114 * begining with the 16-bit hex patterns 0xFFFE and 0xFFFF - we rely on the fact that no
115 * valid double-precision numbers will begin fall in these ranges.
116 *
117 * The scheme we have implemented encodes double precision values by adding 2^48 to the
118 * 64-bit integer representation of the number. After this manipulation, no encoded
119 * double-precision value will begin with the pattern 0x0000 or 0xFFFF.
120 *
121 * The top 16-bits denote the type of the encoded JSImmediate:
122 *
123 * Pointer: 0000:PPPP:PPPP:PPPP
124 * 0001:****:****:****
125 * Double:{ ...
126 * FFFE:****:****:****
127 * Integer: FFFF:0000:IIII:IIII
128 *
129 * 32-bit signed integers are marked with the 16-bit tag 0xFFFF. The tag 0x0000
130 * denotes a pointer, or another form of tagged immediate. Boolean, null and undefined
131 * values are encoded in the same manner as the default format.
132 */
133
134 class JSImmediate {
135 private:
136 friend class JIT;
ba379fdc 137 friend class JSValue;
9dae56ea 138 friend class JSFastMath;
4e4e5a6f
A
139 friend class JSInterfaceJIT;
140 friend class SpecializedThunkJIT;
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;
4e4e5a6f 169#elif USE(JSVALUE32)
9dae56ea
A
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