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