• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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)
reinterpretDoubleToIntptr(double value)50     inline intptr_t reinterpretDoubleToIntptr(double value)
51     {
52         return WTF::bitwise_cast<intptr_t>(value);
53     }
54 
reinterpretIntptrToDouble(intptr_t value)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 
isImmediate(JSValue v)195         static ALWAYS_INLINE bool isImmediate(JSValue v)
196         {
197             return rawValue(v) & TagMask;
198         }
199 
isNumber(JSValue v)200         static ALWAYS_INLINE bool isNumber(JSValue v)
201         {
202             return rawValue(v) & TagTypeNumber;
203         }
204 
isIntegerNumber(JSValue v)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)
isDouble(JSValue v)215         static ALWAYS_INLINE bool isDouble(JSValue v)
216         {
217             return isNumber(v) && !isIntegerNumber(v);
218         }
219 #endif
220 
isPositiveIntegerNumber(JSValue v)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 
isBoolean(JSValue v)227         static ALWAYS_INLINE bool isBoolean(JSValue v)
228         {
229             return (rawValue(v) & FullTagTypeMask) == FullTagTypeBool;
230         }
231 
isUndefinedOrNull(JSValue v)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 
isEitherImmediate(JSValue v1,JSValue v2)251         static ALWAYS_INLINE bool isEitherImmediate(JSValue v1, JSValue v2)
252         {
253             return (rawValue(v1) | rawValue(v2)) & TagMask;
254         }
255 
areBothImmediate(JSValue v1,JSValue v2)256         static ALWAYS_INLINE bool areBothImmediate(JSValue v1, JSValue v2)
257         {
258             return isImmediate(v1) & isImmediate(v2);
259         }
260 
areBothImmediateIntegerNumbers(JSValue v1,JSValue v2)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 
makeValue(intptr_t integer)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)
makeInt(uint32_t value)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)
makeDouble(double value)315         static ALWAYS_INLINE JSValue makeDouble(double value)
316         {
317             return makeValue(reinterpretDoubleToIntptr(value) + DoubleEncodeOffset);
318         }
319 #endif
320 
makeBool(bool b)321         static ALWAYS_INLINE JSValue makeBool(bool b)
322         {
323             return makeValue((static_cast<intptr_t>(b) << ExtendedPayloadShift) | FullTagTypeBool);
324         }
325 
makeUndefined()326         static ALWAYS_INLINE JSValue makeUndefined()
327         {
328             return makeValue(FullTagTypeUndefined);
329         }
330 
makeNull()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)
doubleValue(JSValue v)340         static ALWAYS_INLINE double doubleValue(JSValue v)
341         {
342             return reinterpretIntptrToDouble(rawValue(v) - DoubleEncodeOffset);
343         }
344 #endif
345 
intValue(JSValue v)346         static ALWAYS_INLINE int32_t intValue(JSValue v)
347         {
348             return static_cast<int32_t>(rawValue(v) >> IntegerPayloadShift);
349         }
350 
uintValue(JSValue v)351         static ALWAYS_INLINE uint32_t uintValue(JSValue v)
352         {
353             return static_cast<uint32_t>(rawValue(v) >> IntegerPayloadShift);
354         }
355 
boolValue(JSValue v)356         static ALWAYS_INLINE bool boolValue(JSValue v)
357         {
358             return rawValue(v) & ExtendedPayloadBitBoolValue;
359         }
360 
rawValue(JSValue v)361         static ALWAYS_INLINE intptr_t rawValue(JSValue v)
362         {
363             return v.immediateValue();
364         }
365     };
366 
trueImmediate()367     ALWAYS_INLINE JSValue JSImmediate::trueImmediate() { return makeBool(true); }
falseImmediate()368     ALWAYS_INLINE JSValue JSImmediate::falseImmediate() { return makeBool(false); }
undefinedImmediate()369     ALWAYS_INLINE JSValue JSImmediate::undefinedImmediate() { return makeUndefined(); }
nullImmediate()370     ALWAYS_INLINE JSValue JSImmediate::nullImmediate() { return makeNull(); }
zeroImmediate()371     ALWAYS_INLINE JSValue JSImmediate::zeroImmediate() { return makeInt(0); }
oneImmediate()372     ALWAYS_INLINE JSValue JSImmediate::oneImmediate() { return makeInt(1); }
373 
374 #if USE(JSVALUE64)
doubleToBoolean(double value)375     inline bool doubleToBoolean(double value)
376     {
377         return value < 0.0 || value > 0.0;
378     }
379 
toBoolean(JSValue v)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
toBoolean(JSValue v)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 
getTruncatedUInt32(JSValue v)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>
fromNumberOutsideIntegerRange(T value)403     inline JSValue JSImmediate::fromNumberOutsideIntegerRange(T value)
404     {
405         return makeDouble(static_cast<double>(value));
406     }
407 #else
408     template<typename T>
fromNumberOutsideIntegerRange(T)409     inline JSValue JSImmediate::fromNumberOutsideIntegerRange(T)
410     {
411         return JSValue();
412     }
413 #endif
414 
from(char i)415     ALWAYS_INLINE JSValue JSImmediate::from(char i)
416     {
417         return makeInt(i);
418     }
419 
from(signed char i)420     ALWAYS_INLINE JSValue JSImmediate::from(signed char i)
421     {
422         return makeInt(i);
423     }
424 
from(unsigned char i)425     ALWAYS_INLINE JSValue JSImmediate::from(unsigned char i)
426     {
427         return makeInt(i);
428     }
429 
from(short i)430     ALWAYS_INLINE JSValue JSImmediate::from(short i)
431     {
432         return makeInt(i);
433     }
434 
from(unsigned short i)435     ALWAYS_INLINE JSValue JSImmediate::from(unsigned short i)
436     {
437         return makeInt(i);
438     }
439 
from(int i)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 
from(unsigned i)449     ALWAYS_INLINE JSValue JSImmediate::from(unsigned i)
450     {
451         if (i > maxImmediateUInt)
452             return fromNumberOutsideIntegerRange(i);
453         return makeInt(i);
454     }
455 
from(long i)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 
from(unsigned long i)463     ALWAYS_INLINE JSValue JSImmediate::from(unsigned long i)
464     {
465         if (i > maxImmediateUInt)
466             return fromNumberOutsideIntegerRange(i);
467         return makeInt(i);
468     }
469 
from(long long i)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 
from(unsigned long long i)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 
from(double d)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 
getTruncatedInt32(JSValue v)495     ALWAYS_INLINE int32_t JSImmediate::getTruncatedInt32(JSValue v)
496     {
497         ASSERT(isIntegerNumber(v));
498         return intValue(v);
499     }
500 
toDouble(JSValue v)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 
getUInt32(JSValue v,uint32_t & i)524     ALWAYS_INLINE bool JSImmediate::getUInt32(JSValue v, uint32_t& i)
525     {
526         i = uintValue(v);
527         return isPositiveIntegerNumber(v);
528     }
529 
getTruncatedInt32(JSValue v,int32_t & i)530     ALWAYS_INLINE bool JSImmediate::getTruncatedInt32(JSValue v, int32_t& i)
531     {
532         i = intValue(v);
533         return isIntegerNumber(v);
534     }
535 
getTruncatedUInt32(JSValue v,uint32_t & i)536     ALWAYS_INLINE bool JSImmediate::getTruncatedUInt32(JSValue v, uint32_t& i)
537     {
538         return getUInt32(v, i);
539     }
540 
JSValue(JSNullTag)541     inline JSValue::JSValue(JSNullTag)
542     {
543         *this = JSImmediate::nullImmediate();
544     }
545 
JSValue(JSUndefinedTag)546     inline JSValue::JSValue(JSUndefinedTag)
547     {
548         *this = JSImmediate::undefinedImmediate();
549     }
550 
JSValue(JSTrueTag)551     inline JSValue::JSValue(JSTrueTag)
552     {
553         *this = JSImmediate::trueImmediate();
554     }
555 
JSValue(JSFalseTag)556     inline JSValue::JSValue(JSFalseTag)
557     {
558         *this = JSImmediate::falseImmediate();
559     }
560 
isUndefinedOrNull()561     inline bool JSValue::isUndefinedOrNull() const
562     {
563         return JSImmediate::isUndefinedOrNull(asValue());
564     }
565 
isBoolean()566     inline bool JSValue::isBoolean() const
567     {
568         return JSImmediate::isBoolean(asValue());
569     }
570 
isTrue()571     inline bool JSValue::isTrue() const
572     {
573         return asValue() == JSImmediate::trueImmediate();
574     }
575 
isFalse()576     inline bool JSValue::isFalse() const
577     {
578         return asValue() == JSImmediate::falseImmediate();
579     }
580 
getBoolean(bool & v)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 
getBoolean()591     inline bool JSValue::getBoolean() const
592     {
593         return asValue() == jsBoolean(true);
594     }
595 
isCell()596     inline bool JSValue::isCell() const
597     {
598         return !JSImmediate::isImmediate(asValue());
599     }
600 
isInt32()601     inline bool JSValue::isInt32() const
602     {
603         return JSImmediate::isIntegerNumber(asValue());
604     }
605 
asInt32()606     inline int32_t JSValue::asInt32() const
607     {
608         ASSERT(isInt32());
609         return JSImmediate::getTruncatedInt32(asValue());
610     }
611 
isUInt32()612     inline bool JSValue::isUInt32() const
613     {
614         return JSImmediate::isPositiveIntegerNumber(asValue());
615     }
616 
asUInt32()617     inline uint32_t JSValue::asUInt32() const
618     {
619         ASSERT(isUInt32());
620         return JSImmediate::getTruncatedUInt32(asValue());
621     }
622 
623     class JSFastMath {
624     public:
canDoFastBitwiseOperations(JSValue v1,JSValue v2)625         static ALWAYS_INLINE bool canDoFastBitwiseOperations(JSValue v1, JSValue v2)
626         {
627             return JSImmediate::areBothImmediateIntegerNumbers(v1, v2);
628         }
629 
equal(JSValue v1,JSValue v2)630         static ALWAYS_INLINE JSValue equal(JSValue v1, JSValue v2)
631         {
632             ASSERT(canDoFastBitwiseOperations(v1, v2));
633             return jsBoolean(v1 == v2);
634         }
635 
notEqual(JSValue v1,JSValue v2)636         static ALWAYS_INLINE JSValue notEqual(JSValue v1, JSValue v2)
637         {
638             ASSERT(canDoFastBitwiseOperations(v1, v2));
639             return jsBoolean(v1 != v2);
640         }
641 
andImmediateNumbers(JSValue v1,JSValue v2)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 
xorImmediateNumbers(JSValue v1,JSValue v2)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 
orImmediateNumbers(JSValue v1,JSValue v2)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 
canDoFastRshift(JSValue v1,JSValue v2)660         static ALWAYS_INLINE bool canDoFastRshift(JSValue v1, JSValue v2)
661         {
662             return JSImmediate::areBothImmediateIntegerNumbers(v1, v2);
663         }
664 
canDoFastUrshift(JSValue v1,JSValue v2)665         static ALWAYS_INLINE bool canDoFastUrshift(JSValue v1, JSValue v2)
666         {
667             return JSImmediate::areBothImmediateIntegerNumbers(v1, v2) && !(JSImmediate::rawValue(v1) & JSImmediate::signBit);
668         }
669 
rightShiftImmediateNumbers(JSValue val,JSValue shift)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 
canDoFastAdditiveOperations(JSValue v)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 
canDoFastAdditiveOperations(JSValue v1,JSValue v2)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 
addImmediateNumbers(JSValue v1,JSValue v2)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 
subImmediateNumbers(JSValue v1,JSValue v2)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 
incImmediateNumber(JSValue v)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 
decImmediateNumber(JSValue v)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
724