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