JavaScriptCore:
[WebKit-https.git] / JavaScriptCore / runtime / JSImmediate.h
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 "JSValue.h"
29 #include <limits>
30 #include <limits.h>
31 #include <stdarg.h>
32 #include <stdint.h>
33 #include <stdlib.h>
34
35 namespace JSC {
36
37     class ExecState;
38     class JSCell;
39     class JSObject;
40     class JSValue;
41     class UString;
42
43     /*
44      * A JSValue* is either a pointer to a cell (a heap-allocated object) or an immediate (a type-tagged 
45      * value masquerading as a pointer). The low two bits in a JSValue* are available for type tagging
46      * because allocator alignment guarantees they will be 00 in cell pointers.
47      *
48      * For example, on a 32 bit system:
49      *
50      * JSCell*:             XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX                     00
51      *                      [ high 30 bits: pointer address ]  [ low 2 bits -- always 0 ]
52      * JSImmediate:         XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX                     TT
53      *                      [ high 30 bits: 'payload' ]             [ low 2 bits -- tag ]
54      *
55      * Where the bottom two bits are non-zero they either indicate that the immediate is a 31 bit signed
56      * integer, or they mark the value as being an immediate of a type other than integer, with a secondary
57      * tag used to indicate the exact type.
58      *
59      * Where the lowest bit is set (TT is equal to 01 or 11) the high 31 bits form a 31 bit signed int value.
60      * Where TT is equal to 10 this indicates this is a type of immediate other than an integer, and the next
61      * two bits will form an extended tag.
62      *
63      * 31 bit signed int:   XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX                     X1
64      *                      [ high 30 bits of the value ]      [ high bit part of value ]
65      * Other:               YYYYYYYYYYYYYYYYYYYYYYYYYYYY      ZZ               10
66      *                      [ extended 'payload' ]  [  extended tag  ]  [  tag 'other'  ]
67      *
68      * Where the first bit of the extended tag is set this flags the value as being a boolean, and the following
69      * bit would flag the value as undefined.  If neither bits are set, the value is null.
70      *
71      * Other:               YYYYYYYYYYYYYYYYYYYYYYYYYYYY      UB               10
72      *                      [ extended 'payload' ]  [ undefined | bool ]  [ tag 'other' ]
73      *
74      * For boolean value the lowest bit in the payload holds the value of the bool, all remaining bits are zero.
75      * For undefined or null immediates the payload is zero.
76      *
77      * Boolean:             000000000000000000000000000V      01               10
78      *                      [ boolean value ]              [ bool ]       [ tag 'other' ]
79      * Undefined:           0000000000000000000000000000      10               10
80      *                      [ zero ]                    [ undefined ]     [ tag 'other' ]
81      * Null:                0000000000000000000000000000      00               10
82      *                      [ zero ]                       [ zero ]       [ tag 'other' ]
83      */
84
85     class JSImmediate {
86     private:
87         friend class JIT;
88     
89         static const int32_t TagMask           = 0x3; // primary tag is 2 bits long
90         static const int32_t TagBitTypeInteger = 0x1; // bottom bit set indicates integer, this dominates the following bit
91         static const int32_t TagBitTypeOther   = 0x2; // second bit set indicates immediate other than an integer
92
93         static const int32_t ExtendedTagMask         = 0xC; // extended tag holds a further two bits
94         static const int32_t ExtendedTagBitBool      = 0x4;
95         static const int32_t ExtendedTagBitUndefined = 0x8;
96
97         static const int32_t FullTagTypeMask      = TagMask | ExtendedTagMask;
98         static const int32_t FullTagTypeBool      = TagBitTypeOther | ExtendedTagBitBool;
99         static const int32_t FullTagTypeUndefined = TagBitTypeOther | ExtendedTagBitUndefined;
100         static const int32_t FullTagTypeNull      = TagBitTypeOther;
101
102         static const int32_t IntegerPayloadShift  = 1;
103         static const int32_t ExtendedPayloadShift = 4;
104
105         static const int32_t ExtendedPayloadBitBoolValue = 1 << ExtendedPayloadShift;
106
107 #if USE(ALTERNATE_JSIMMEDIATE)
108         static const intptr_t signBit = 0x100000000ll;
109 #else
110         static const int32_t signBit = 0x80000000;
111 #endif
112  
113     public:
114         static ALWAYS_INLINE bool isImmediate(JSValuePtr v)
115         {
116             return rawValue(v) & TagMask;
117         }
118         
119         static ALWAYS_INLINE bool isNumber(JSValuePtr v)
120         {
121             return rawValue(v) & TagBitTypeInteger;
122         }
123
124         static ALWAYS_INLINE bool isPositiveNumber(JSValuePtr v)
125         {
126             // A single mask to check for the sign bit and the number tag all at once.
127             return (rawValue(v) & (signBit | TagBitTypeInteger)) == TagBitTypeInteger;
128         }
129         
130         static ALWAYS_INLINE bool isBoolean(JSValuePtr v)
131         {
132             return (rawValue(v) & FullTagTypeMask) == FullTagTypeBool;
133         }
134         
135         static ALWAYS_INLINE bool isUndefinedOrNull(JSValuePtr v)
136         {
137             // Undefined and null share the same value, bar the 'undefined' bit in the extended tag.
138             return (rawValue(v) & ~ExtendedTagBitUndefined) == FullTagTypeNull;
139         }
140
141         static bool isNegative(JSValuePtr v)
142         {
143             ASSERT(isNumber(v));
144             return rawValue(v) & signBit;
145         }
146
147         static JSValuePtr from(char);
148         static JSValuePtr from(signed char);
149         static JSValuePtr from(unsigned char);
150         static JSValuePtr from(short);
151         static JSValuePtr from(unsigned short);
152         static JSValuePtr from(int);
153         static JSValuePtr from(unsigned);
154         static JSValuePtr from(long);
155         static JSValuePtr from(unsigned long);
156         static JSValuePtr from(long long);
157         static JSValuePtr from(unsigned long long);
158         static JSValuePtr from(double);
159
160         static ALWAYS_INLINE bool isEitherImmediate(JSValuePtr v1, JSValuePtr v2)
161         {
162             return (rawValue(v1) | rawValue(v2)) & TagMask;
163         }
164
165         static ALWAYS_INLINE bool isAnyImmediate(JSValuePtr v1, JSValuePtr v2, JSValuePtr v3)
166         {
167             return (rawValue(v1) | rawValue(v2) | rawValue(v3)) & TagMask;
168         }
169
170         static ALWAYS_INLINE bool areBothImmediate(JSValuePtr v1, JSValuePtr v2)
171         {
172             return isImmediate(v1) & isImmediate(v2);
173         }
174
175         static ALWAYS_INLINE bool areBothImmediateNumbers(JSValuePtr v1, JSValuePtr v2)
176         {
177             return rawValue(v1) & rawValue(v2) & TagBitTypeInteger;
178         }
179
180         static ALWAYS_INLINE JSValuePtr andImmediateNumbers(JSValuePtr v1, JSValuePtr v2)
181         {
182             ASSERT(areBothImmediateNumbers(v1, v2));
183             return makeValue(rawValue(v1) & rawValue(v2));
184         }
185
186         static ALWAYS_INLINE JSValuePtr xorImmediateNumbers(JSValuePtr v1, JSValuePtr v2)
187         {
188             ASSERT(areBothImmediateNumbers(v1, v2));
189             return makeValue((rawValue(v1) ^ rawValue(v2)) | TagBitTypeInteger);
190         }
191
192         static ALWAYS_INLINE JSValuePtr orImmediateNumbers(JSValuePtr v1, JSValuePtr v2)
193         {
194             ASSERT(areBothImmediateNumbers(v1, v2));
195             return makeValue(rawValue(v1) | rawValue(v2));
196         }
197
198         static ALWAYS_INLINE JSValuePtr rightShiftImmediateNumbers(JSValuePtr val, JSValuePtr shift)
199         {
200             ASSERT(areBothImmediateNumbers(val, shift));
201             return makeValue((rawValue(val) >> ((rawValue(shift) >> IntegerPayloadShift) & 0x1f)) | TagBitTypeInteger);
202         }
203
204         static ALWAYS_INLINE bool canDoFastAdditiveOperations(JSValuePtr v)
205         {
206             // Number is non-negative and an operation involving two of these can't overflow.
207             // Checking for allowed negative numbers takes more time than it's worth on SunSpider.
208             return (rawValue(v) & (TagBitTypeInteger + (signBit | (signBit >> 1)))) == TagBitTypeInteger;
209         }
210
211         static ALWAYS_INLINE JSValuePtr addImmediateNumbers(JSValuePtr v1, JSValuePtr v2)
212         {
213             ASSERT(canDoFastAdditiveOperations(v1));
214             ASSERT(canDoFastAdditiveOperations(v2));
215             return makeValue(rawValue(v1) + rawValue(v2) - TagBitTypeInteger);
216         }
217
218         static ALWAYS_INLINE JSValuePtr subImmediateNumbers(JSValuePtr v1, JSValuePtr v2)
219         {
220             ASSERT(canDoFastAdditiveOperations(v1));
221             ASSERT(canDoFastAdditiveOperations(v2));
222             return makeValue(rawValue(v1) - rawValue(v2) + TagBitTypeInteger);
223         }
224
225         static ALWAYS_INLINE JSValuePtr incImmediateNumber(JSValuePtr v)
226         {
227             ASSERT(canDoFastAdditiveOperations(v));
228             return makeValue(rawValue(v) + (1 << IntegerPayloadShift));
229         }
230
231         static ALWAYS_INLINE JSValuePtr decImmediateNumber(JSValuePtr v)
232         {
233             ASSERT(canDoFastAdditiveOperations(v));
234             return makeValue(rawValue(v) - (1 << IntegerPayloadShift));
235         }
236
237         static double toDouble(JSValuePtr);
238         static bool toBoolean(JSValuePtr);
239         static JSObject* toObject(JSValuePtr, ExecState*);
240         static JSObject* toThisObject(JSValuePtr, ExecState*);
241         static UString toString(JSValuePtr);
242
243         static bool getUInt32(JSValuePtr, uint32_t&);
244         static bool getTruncatedInt32(JSValuePtr, int32_t&);
245         static bool getTruncatedUInt32(JSValuePtr, uint32_t&);
246
247         static int32_t getTruncatedInt32(JSValuePtr);
248         static uint32_t getTruncatedUInt32(JSValuePtr);
249
250         static JSValuePtr trueImmediate();
251         static JSValuePtr falseImmediate();
252         static JSValuePtr undefinedImmediate();
253         static JSValuePtr nullImmediate();
254         static JSValuePtr zeroImmediate();
255         static JSValuePtr oneImmediate();
256
257         static JSValuePtr impossibleValue();
258         
259         static JSObject* prototype(JSValuePtr, ExecState*);
260
261     private:
262 #if USE(ALTERNATE_JSIMMEDIATE)
263         static const int minImmediateInt = ((-INT_MAX) - 1);
264         static const int maxImmediateInt = INT_MAX;
265 #else
266         static const int minImmediateInt = ((-INT_MAX) - 1) >> IntegerPayloadShift;
267         static const int maxImmediateInt = INT_MAX >> IntegerPayloadShift;
268 #endif
269         static const unsigned maxImmediateUInt = maxImmediateInt;
270
271         static ALWAYS_INLINE JSValuePtr makeValue(intptr_t integer)
272         {
273             return JSValuePtr::makeImmediate(integer);
274         }
275
276         static ALWAYS_INLINE JSValuePtr makeInt(int32_t value)
277         {
278             return makeValue((static_cast<intptr_t>(value) << IntegerPayloadShift) | TagBitTypeInteger);
279         }
280         
281         static ALWAYS_INLINE JSValuePtr makeBool(bool b)
282         {
283             return makeValue((static_cast<intptr_t>(b) << ExtendedPayloadShift) | FullTagTypeBool);
284         }
285         
286         static ALWAYS_INLINE JSValuePtr makeUndefined()
287         {
288             return makeValue(FullTagTypeUndefined);
289         }
290         
291         static ALWAYS_INLINE JSValuePtr makeNull()
292         {
293             return makeValue(FullTagTypeNull);
294         }
295         
296         static ALWAYS_INLINE int32_t intValue(JSValuePtr v)
297         {
298             return static_cast<int32_t>(rawValue(v) >> IntegerPayloadShift);
299         }
300         
301         static ALWAYS_INLINE uint32_t uintValue(JSValuePtr v)
302         {
303             return static_cast<uint32_t>(rawValue(v) >> IntegerPayloadShift);
304         }
305         
306         static ALWAYS_INLINE bool boolValue(JSValuePtr v)
307         {
308             return rawValue(v) & ExtendedPayloadBitBoolValue;
309         }
310         
311         static ALWAYS_INLINE intptr_t rawValue(JSValuePtr v)
312         {
313             return v.immediateValue();
314         }
315
316         static double nonInlineNaN();
317     };
318
319     ALWAYS_INLINE JSValuePtr JSImmediate::trueImmediate() { return makeBool(true); }
320     ALWAYS_INLINE JSValuePtr JSImmediate::falseImmediate() { return makeBool(false); }
321     ALWAYS_INLINE JSValuePtr JSImmediate::undefinedImmediate() { return makeUndefined(); }
322     ALWAYS_INLINE JSValuePtr JSImmediate::nullImmediate() { return makeNull(); }
323     ALWAYS_INLINE JSValuePtr JSImmediate::zeroImmediate() { return makeInt(0); }
324     ALWAYS_INLINE JSValuePtr JSImmediate::oneImmediate() { return makeInt(1); }
325
326     // This value is impossible because 0x4 is not a valid pointer but a tag of 0 would indicate non-immediate
327     ALWAYS_INLINE JSValuePtr JSImmediate::impossibleValue() { return makeValue(0x4); }
328
329     ALWAYS_INLINE bool JSImmediate::toBoolean(JSValuePtr v)
330     {
331         ASSERT(isImmediate(v));
332         intptr_t bits = rawValue(v);
333         return (bits & TagBitTypeInteger)
334             ? bits != TagBitTypeInteger // !0 ints
335             : bits == (FullTagTypeBool | ExtendedPayloadBitBoolValue); // bool true
336     }
337
338     ALWAYS_INLINE uint32_t JSImmediate::getTruncatedUInt32(JSValuePtr v)
339     {
340         ASSERT(isNumber(v));
341         return intValue(v);
342     }
343
344     ALWAYS_INLINE JSValuePtr JSImmediate::from(char i)
345     {
346         return makeInt(i);
347     }
348
349     ALWAYS_INLINE JSValuePtr JSImmediate::from(signed char i)
350     {
351         return makeInt(i);
352     }
353
354     ALWAYS_INLINE JSValuePtr JSImmediate::from(unsigned char i)
355     {
356         return makeInt(i);
357     }
358
359     ALWAYS_INLINE JSValuePtr JSImmediate::from(short i)
360     {
361         return makeInt(i);
362     }
363
364     ALWAYS_INLINE JSValuePtr JSImmediate::from(unsigned short i)
365     {
366         return makeInt(i);
367     }
368
369     ALWAYS_INLINE JSValuePtr JSImmediate::from(int i)
370     {
371         if ((i < minImmediateInt) | (i > maxImmediateInt))
372             return noValue();
373         return makeInt(i);
374     }
375
376     ALWAYS_INLINE JSValuePtr JSImmediate::from(unsigned i)
377     {
378         if (i > maxImmediateUInt)
379             return noValue();
380         return makeInt(i);
381     }
382
383     ALWAYS_INLINE JSValuePtr JSImmediate::from(long i)
384     {
385         if ((i < minImmediateInt) | (i > maxImmediateInt))
386             return noValue();
387         return makeInt(i);
388     }
389
390     ALWAYS_INLINE JSValuePtr JSImmediate::from(unsigned long i)
391     {
392         if (i > maxImmediateUInt)
393             return noValue();
394         return makeInt(i);
395     }
396
397     ALWAYS_INLINE JSValuePtr JSImmediate::from(long long i)
398     {
399         if ((i < minImmediateInt) | (i > maxImmediateInt))
400             return noValue();
401         return makeInt(static_cast<intptr_t>(i));
402     }
403
404     ALWAYS_INLINE JSValuePtr JSImmediate::from(unsigned long long i)
405     {
406         if (i > maxImmediateUInt)
407             return noValue();
408         return makeInt(static_cast<intptr_t>(i));
409     }
410
411     ALWAYS_INLINE JSValuePtr JSImmediate::from(double d)
412     {
413         const int intVal = static_cast<int>(d);
414
415         if ((intVal < minImmediateInt) | (intVal > maxImmediateInt))
416             return noValue();
417
418         // Check for data loss from conversion to int.
419         if (intVal != d || (!intVal && signbit(d)))
420             return noValue();
421
422         return makeInt(intVal);
423     }
424
425     ALWAYS_INLINE int32_t JSImmediate::getTruncatedInt32(JSValuePtr v)
426     {
427         ASSERT(isNumber(v));
428         return intValue(v);
429     }
430
431     ALWAYS_INLINE double JSImmediate::toDouble(JSValuePtr v)
432     {
433         ASSERT(isImmediate(v));
434         int i;
435         if (isNumber(v))
436             i = intValue(v);
437         else if (rawValue(v) == FullTagTypeUndefined)
438             return nonInlineNaN();
439         else
440             i = rawValue(v) >> ExtendedPayloadShift;
441         return i;
442     }
443
444     ALWAYS_INLINE bool JSImmediate::getUInt32(JSValuePtr v, uint32_t& i)
445     {
446         i = uintValue(v);
447         return isPositiveNumber(v);
448     }
449
450     ALWAYS_INLINE bool JSImmediate::getTruncatedInt32(JSValuePtr v, int32_t& i)
451     {
452         i = intValue(v);
453         return isNumber(v);
454     }
455
456     ALWAYS_INLINE bool JSImmediate::getTruncatedUInt32(JSValuePtr v, uint32_t& i)
457     {
458         return getUInt32(v, i);
459     }
460
461     inline JSValuePtr jsNull()
462     {
463         return JSImmediate::nullImmediate();
464     }
465
466     inline JSValuePtr jsBoolean(bool b)
467     {
468         return b ? JSImmediate::trueImmediate() : JSImmediate::falseImmediate();
469     }
470
471     inline JSValuePtr jsUndefined()
472     {
473         return JSImmediate::undefinedImmediate();
474     }
475
476     // These are identical logic to the JSValue functions above, and faster than jsNumber(number)->toInt32().
477     int32_t toInt32(double);
478     uint32_t toUInt32(double);
479     int32_t toInt32SlowCase(double, bool& ok);
480     uint32_t toUInt32SlowCase(double, bool& ok);
481
482     inline bool JSValue::isUndefined() const
483     {
484         return asValue() == jsUndefined();
485     }
486
487     inline bool JSValue::isNull() const
488     {
489         return asValue() == jsNull();
490     }
491
492     inline bool JSValue::isUndefinedOrNull() const
493     {
494         return JSImmediate::isUndefinedOrNull(asValue());
495     }
496
497     inline bool JSValue::isBoolean() const
498     {
499         return JSImmediate::isBoolean(asValue());
500     }
501
502     inline bool JSValue::getBoolean(bool& v) const
503     {
504         if (JSImmediate::isBoolean(asValue())) {
505             v = JSImmediate::toBoolean(asValue());
506             return true;
507         }
508         
509         return false;
510     }
511
512     inline bool JSValue::getBoolean() const
513     {
514         return asValue() == jsBoolean(true);
515     }
516
517     ALWAYS_INLINE int32_t JSValue::toInt32(ExecState* exec) const
518     {
519         int32_t i;
520         if (getTruncatedInt32(i))
521             return i;
522         bool ok;
523         return toInt32SlowCase(exec, ok);
524     }
525
526     inline uint32_t JSValue::toUInt32(ExecState* exec) const
527     {
528         uint32_t i;
529         if (getTruncatedUInt32(i))
530             return i;
531         bool ok;
532         return toUInt32SlowCase(exec, ok);
533     }
534
535     inline int32_t toInt32(double val)
536     {
537         if (!(val >= -2147483648.0 && val < 2147483648.0)) {
538             bool ignored;
539             return toInt32SlowCase(val, ignored);
540         }
541         return static_cast<int32_t>(val);
542     }
543
544     inline uint32_t toUInt32(double val)
545     {
546         if (!(val >= 0.0 && val < 4294967296.0)) {
547             bool ignored;
548             return toUInt32SlowCase(val, ignored);
549         }
550         return static_cast<uint32_t>(val);
551     }
552
553     inline int32_t JSValue::toInt32(ExecState* exec, bool& ok) const
554     {
555         int32_t i;
556         if (getTruncatedInt32(i)) {
557             ok = true;
558             return i;
559         }
560         return toInt32SlowCase(exec, ok);
561     }
562
563     inline uint32_t JSValue::toUInt32(ExecState* exec, bool& ok) const
564     {
565         uint32_t i;
566         if (getTruncatedUInt32(i)) {
567             ok = true;
568             return i;
569         }
570         return toUInt32SlowCase(exec, ok);
571     }
572
573 } // namespace JSC
574
575 #endif // JSImmediate_h