08613129f7c79077a4365dc1ccc900ad14989ca9
[WebKit-https.git] / JavaScriptCore / kjs / JSImmediate.h
1 /*
2  *  Copyright (C) 2003, 2004, 2005, 2006, 2007 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 "JSType.h"
26 #include <wtf/Assertions.h>
27 #include <wtf/AlwaysInline.h>
28 #include <wtf/MathExtras.h>
29 #include <limits>
30 #include <stdarg.h>
31 #include <stdint.h>
32 #include <stdlib.h>
33
34 namespace KJS {
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  * signed int masquerading as a pointer). The low two bits in a JSValue* are available 
44  * for type tagging 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  *
51  * JSImmediate:   XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX                 TT
52  *               [ high 30 bits: signed int ]       [ low 2 bits -- type tag ]
53  *
54  * The bit "payload" (the high 30 bits) is a 30 bit signed int for immediate numbers, a flag to distinguish true/false
55  * and undefined/null.
56  *
57  * Notice that the JSType value of NullType is 4, which requires 3 bits to encode. Since we only have 2 bits 
58  * available for type tagging, we tag the null immediate with UndefinedType, and JSImmediate::type() has 
59  * to sort them out.
60  */
61
62 class JSImmediate {
63 public:
64     static ALWAYS_INLINE bool isImmediate(const JSValue* v)
65     {
66         return getTag(v) != 0;
67     }
68     
69     static ALWAYS_INLINE bool isNumber(const JSValue* v)
70     {
71         return (getTag(v) == NumberType);
72     }
73     
74     static ALWAYS_INLINE bool isBoolean(const JSValue* v)
75     {
76         return (getTag(v) == BooleanType);
77     }
78     
79     // Since we have room for only 3 unique tags, null and undefined have to share.
80     static ALWAYS_INLINE bool isUndefinedOrNull(const JSValue* v)
81     {
82         return (getTag(v) == UndefinedType);
83     }
84
85     static JSValue* fromDouble(double d);
86     static double toDouble(const JSValue*);
87     static bool toBoolean(const JSValue*);
88     static JSObject* toObject(const JSValue*, ExecState*);
89     static UString toString(const JSValue*);
90     static JSType type(const JSValue*);
91
92     static bool getUInt32(const JSValue*, uint32_t&);
93     static bool getTruncatedInt32(const JSValue*, int32_t&);
94     static bool getTruncatedUInt32(const JSValue*, uint32_t&);
95
96     // It would nice just to use fromDouble() to create these values, but that would prevent them from
97     // turning into compile-time constants.
98     static JSValue* trueImmediate();
99     static JSValue* falseImmediate();
100     static JSValue* undefinedImmediate();
101     static JSValue* nullImmediate();
102     
103 private:
104     static const uintptr_t TagMask = 3; // type tags are 2 bits long
105     
106     static ALWAYS_INLINE JSValue* tag(uintptr_t bits, uintptr_t tag)
107     {
108         return reinterpret_cast<JSValue*>(bits | tag);
109     }
110     
111     static ALWAYS_INLINE uintptr_t unTag(const JSValue* v)
112     {
113         return reinterpret_cast<uintptr_t>(v) & ~TagMask;
114     }
115     
116     static ALWAYS_INLINE uintptr_t getTag(const JSValue* v)
117     {
118         return reinterpret_cast<uintptr_t>(v) & TagMask;
119     }
120     
121     // we support 32-bit platforms with sizes like this
122     static const bool is32bit = 
123         sizeof(float) == sizeof(uint32_t) && sizeof(double) == sizeof(uint64_t) && sizeof(uintptr_t) == sizeof(uint32_t);
124
125     // we support 64-bit platforms with sizes like this
126     static const bool is64bit =
127         sizeof(float) == sizeof(uint32_t) && sizeof(double) == sizeof(uint64_t) && sizeof(uintptr_t) == sizeof(uint64_t);
128
129     template<bool for32bit, bool for64bit> struct FPBitValues {};
130 };
131
132 template<> struct JSImmediate::FPBitValues<true, false> {
133     static const uint32_t nanAsBits = 0x7fc00000;
134     static const uint32_t oneAsBits = 0x3f800000;
135     static const uint32_t zeroAsBits = 0x0;
136
137     static ALWAYS_INLINE JSValue* fromDouble(double d)
138     {
139         const int32_t intVal = static_cast<int>(d);
140         
141         // On 32 bit systems immediate values are restricted to a 30 bit signed value
142         if ((intVal <= -(1 << 29)) | (intVal >= ((1 << 29) - 1)))
143             return 0;
144         
145         // Check for data loss from conversion to int. This
146         // will reject NaN, +/-Inf, and -0.
147         // Happily none of these are as common as raw int values
148         if ((intVal != d) || (signbit(d) && !intVal))
149             return 0;
150         
151         return tag(intVal << 2, NumberType);
152     }
153
154     static ALWAYS_INLINE double toDouble(const JSValue* v)
155     {
156         ASSERT(isImmediate(v));
157         const int32_t i = static_cast<int32_t>(unTag(v)) >> 2;
158         if (JSImmediate::getTag(v) == UndefinedType && i)
159             return std::numeric_limits<double>::quiet_NaN();
160         return i;
161     }
162     
163     static ALWAYS_INLINE bool getTruncatedInt32(const JSValue* v, int32_t& i)
164     {
165         i = static_cast<int32_t>(unTag(v)) >> 2;
166         if (JSImmediate::getTag(v) == UndefinedType && i)
167             return false;
168         return isNumber(v);
169     }
170     
171     static ALWAYS_INLINE bool getTruncatedUInt32(const JSValue* v, uint32_t& i)
172     {
173         int32_t& si = reinterpret_cast<int&>(i);
174         return getTruncatedInt32(v, si) & (si >= 0);
175     }
176 };
177
178 template<> struct JSImmediate::FPBitValues<false, true> {
179     static const uint64_t nanAsBits = 0x7ff80000ULL << 32;
180     static const uint64_t oneAsBits = 0x3ff00000ULL << 32;
181     static const uint64_t zeroAsBits = 0x0;
182
183     static ALWAYS_INLINE JSValue* fromDouble(double d)
184     {
185         const int64_t intVal = static_cast<int>(d);
186         
187         // Technically we could fit a 60 bit signed int here, however that would
188         // required more branches when extracting int values.
189         if ((intVal <= -(1L << 29)) | (intVal >= ((1 << 29) - 1)))
190             return 0;
191         
192         // Check for data loss from conversion to int. This
193         // will reject NaN, +/-Inf, and -0.
194         // Happily none of these are as common as raw int values
195         if ((intVal != d) || (signbit(d) && !intVal))
196             return 0;
197
198         return tag(static_cast<uintptr_t>(intVal << 2), NumberType);
199     }
200
201     static ALWAYS_INLINE double toDouble(const JSValue* v)
202     {
203         ASSERT(isImmediate(v));
204         const int32_t i = static_cast<int32_t>(unTag(v) >> 2);
205         if (JSImmediate::getTag(v) == UndefinedType && i)
206             return std::numeric_limits<double>::quiet_NaN();
207         return i;
208     }
209
210     static ALWAYS_INLINE bool getTruncatedInt32(const JSValue* v, int32_t& i)
211     {
212         i = static_cast<int32_t>(unTag(v) >> 2);
213         if (JSImmediate::getTag(v) == UndefinedType && i)
214             return false;
215         return isNumber(v);
216     }
217
218     static ALWAYS_INLINE bool getTruncatedUInt32(const JSValue* v, uint32_t& i)
219     {      
220         int& si = reinterpret_cast<int&>(i);
221         return getTruncatedInt32(v, si) & (si >= 0);
222     }
223 };
224
225 ALWAYS_INLINE JSValue* JSImmediate::trueImmediate() { return tag(1 << 2, BooleanType); }
226 ALWAYS_INLINE JSValue* JSImmediate::falseImmediate() { return tag(0, BooleanType); }
227 ALWAYS_INLINE JSValue* JSImmediate::undefinedImmediate() { return tag(1 << 2, UndefinedType); }
228 ALWAYS_INLINE JSValue* JSImmediate::nullImmediate() { return tag(0, UndefinedType); }
229
230 ALWAYS_INLINE bool JSImmediate::toBoolean(const JSValue* v)
231 {
232     ASSERT(isImmediate(v));
233     uintptr_t bits = unTag(v);
234     return bits != 0 & (JSImmediate::getTag(v) != UndefinedType);
235 }
236
237 ALWAYS_INLINE JSValue* JSImmediate::fromDouble(double d)
238 {
239     return FPBitValues<is32bit, is64bit>::fromDouble(d);
240 }
241
242 ALWAYS_INLINE double JSImmediate::toDouble(const JSValue* v)
243 {
244     return FPBitValues<is32bit, is64bit>::toDouble(v);
245 }
246
247 ALWAYS_INLINE bool JSImmediate::getUInt32(const JSValue* v, uint32_t& i)
248 {
249     return FPBitValues<is32bit, is64bit>::getTruncatedUInt32(v, i);
250 }
251
252 ALWAYS_INLINE bool JSImmediate::getTruncatedInt32(const JSValue* v, int32_t& i)
253 {
254     return FPBitValues<is32bit, is64bit>::getTruncatedInt32(v, i);
255 }
256
257 ALWAYS_INLINE bool JSImmediate::getTruncatedUInt32(const JSValue* v, uint32_t& i)
258 {
259     return FPBitValues<is32bit, is64bit>::getTruncatedUInt32(v, i);
260 }
261
262 } // namespace KJS
263
264 #endif