]> git.saurik.com Git - apple/javascriptcore.git/blame_incremental - runtime/JSImmediate.h
JavaScriptCore-721.26.tar.gz
[apple/javascriptcore.git] / runtime / JSImmediate.h
... / ...
CommitLineData
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#if !USE(JSVALUE32_64)
26
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
47#if USE(JSVALUE64)
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
103 * USE(JSVALUE64) is defined. When this format is used, double precision
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;
137 friend class JSValue;
138 friend class JSFastMath;
139 friend class JSInterfaceJIT;
140 friend class SpecializedThunkJIT;
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#elif USE(JSVALUE32)
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