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