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