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