89dc3fc74ce1d6f0e20cf85f82e4bcdff540d8da
[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 <stdarg.h>
28 #include <stdint.h>
29 #include <stdlib.h>
30
31 namespace KJS {
32
33 class ExecState;
34 class JSObject;
35 class JSValue;
36 class UString;
37
38 /*
39  * A JSValue*  is either a pointer to a cell (a heap-allocated object) or an immediate (a type-tagged 
40  * IEEE floating point bit pattern masquerading as a pointer). The low two bits in a JSValue* are available 
41  * for type tagging because allocator alignment guarantees they will be 00 in cell pointers.
42  *
43  * For example, on a 32 bit system:
44  *
45  * JSCell*:       XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX                 00
46  *               [ high 30 bits: pointer address ]  [ low 2 bits -- always 0 ]
47  *
48  * JSImmediate:   XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX                 TT
49  *             [ high 30 bits: IEEE encoded float ] [ low 2 bits -- type tag ]
50  *
51  * The bit "payload" (the hight 30 bits) of a non-numeric immediate is its numeric equivalent. For example, 
52  * the payload of null is 0.0. This makes JSValue::toNumber() a simple bitmask for all immediates.
53  *
54  * Notice that the JSType value of NullType is 4, which requires 3 bits to encode. Since we only have 2 bits 
55  * available for type tagging, we tag the null immediate with UndefinedType, and JSImmediate::type() has 
56  * to sort them out. Null and Undefined don't otherwise get confused because the numeric value of Undefined is 
57  * NaN, not 0.0.
58  */
59
60 class JSImmediate {
61 public:
62     static bool isImmediate(const JSValue* v)
63     {
64         return getTag(v) != 0;
65     }
66     
67     static bool isNumber(const JSValue* v)
68     {
69         return (getTag(v) == NumberType);
70     }
71     
72     static bool isBoolean(const JSValue* v)
73     {
74         return (getTag(v) == BooleanType);
75     }
76     
77     // Since we have room for only 3 unique tags, null and undefined have to share.
78     static bool isUndefinedOrNull(const JSValue* v)
79     {
80         return (getTag(v) == UndefinedType);
81     }
82
83     static JSValue* fromDouble(double d);
84     static double toDouble(const JSValue*);
85     static bool toBoolean(const JSValue*);
86     static JSObject* toObject(const JSValue*, ExecState*);
87     static UString toString(const JSValue*);
88     static JSType type(const JSValue*);
89
90     static bool getUInt32(const JSValue*, uint32_t&);
91     static bool getTruncatedInt32(const JSValue*, int32_t&);
92     static bool getTruncatedUInt32(const JSValue*, uint32_t&);
93
94     // It would nice just to use fromDouble() to create these values, but that would prevent them from
95     // turning into compile-time constants.
96     static JSValue* trueImmediate();
97     static JSValue* falseImmediate();
98     static JSValue* NaNImmediate();
99     static JSValue* undefinedImmediate();
100     static JSValue* nullImmediate();
101     
102 private:
103     static const uintptr_t TagMask = 3; // type tags are 2 bits long
104     
105     static JSValue* tag(uintptr_t bits, uintptr_t tag)
106     {
107         return reinterpret_cast<JSValue*>(bits | tag);
108     }
109     
110     static uintptr_t unTag(const JSValue* v)
111     {
112         return reinterpret_cast<uintptr_t>(v) & ~TagMask;
113     }
114     
115     static uintptr_t getTag(const JSValue* v)
116     {
117         return reinterpret_cast<uintptr_t>(v) & TagMask;
118     }
119     
120     // NOTE: With f-strict-aliasing enabled, unions are the only safe way to do type masquerading.
121
122     union FloatUnion {
123         uint32_t asBits;
124         float    asFloat;
125     };
126
127     union DoubleUnion {
128         uint64_t asBits;
129         double   asDouble;
130     };
131
132     // we support 32-bit platforms with sizes like this
133     static const bool is32bit = 
134         sizeof(float) == sizeof(uint32_t) && sizeof(double) == sizeof(uint64_t) && sizeof(uintptr_t) == sizeof(uint32_t);
135
136     // we support 64-bit platforms with sizes like this
137     static const bool is64bit =
138         sizeof(float) == sizeof(uint32_t) && sizeof(double) == sizeof(uint64_t) && sizeof(uintptr_t) == sizeof(uint64_t);
139
140     template<bool for32bit, bool for64bit> struct FPBitValues {};
141 };
142
143 template<> struct JSImmediate::FPBitValues<true, false> {
144     static const uint32_t nanAsBits = 0x7fc00000;
145     static const uint32_t oneAsBits = 0x3f800000;
146     static const uint32_t zeroAsBits = 0x0;
147
148     static JSValue* fromDouble(double d)
149     {
150         FloatUnion floatUnion;
151         floatUnion.asFloat = static_cast<float>(d);
152
153         // check for data loss from tagging
154         if ((floatUnion.asBits & TagMask) != 0)
155             return 0;
156
157         // check for data loss from conversion to float
158         // The d == d check is to allow NaN - it does not
159         // compare equal to itself, but we do want to allow it
160         if (floatUnion.asFloat != d && d == d)
161             return 0;
162
163         return tag(floatUnion.asBits, NumberType);
164     }
165
166     static float toFloat(const JSValue* v)
167     {
168         ASSERT(isImmediate(v));
169
170         FloatUnion floatUnion;
171         floatUnion.asBits = static_cast<uint32_t>(unTag(v));
172         return floatUnion.asFloat;
173     }
174
175     static double toDouble(const JSValue* v)
176     {
177         return toFloat(v);
178     }
179
180     static bool getTruncatedInt32(const JSValue* v, int32_t& i)
181     {
182         float f = toFloat(v);
183         if (!(f >= -2147483648.0F && f < 2147483648.0F))
184             return false;
185         i = static_cast<int32_t>(f);
186         return isNumber(v);
187     }
188
189     static bool getTruncatedUInt32(const JSValue* v, uint32_t& i)
190     {
191         float f = toFloat(v);
192         if (!(f >= 0.0F && f < 4294967296.0F))
193             return false;
194         i = static_cast<uint32_t>(f);
195         return isNumber(v);
196     }
197 };
198
199 template<> struct JSImmediate::FPBitValues<false, true> {
200     static const uint64_t nanAsBits = 0x7ff80000ULL << 32;
201     static const uint64_t oneAsBits = 0x3ff00000ULL << 32;
202     static const uint64_t zeroAsBits = 0x0;
203
204     static JSValue* fromDouble(double d)
205     {
206         DoubleUnion doubleUnion;
207         doubleUnion.asDouble = d;
208
209         // check for data loss from tagging
210         if ((doubleUnion.asBits & TagMask) != 0)
211             return 0;
212
213         return tag(static_cast<uintptr_t>(doubleUnion.asBits), NumberType);
214     }
215
216     static double toDouble(const JSValue* v)
217     {
218         ASSERT(isImmediate(v));
219
220         DoubleUnion doubleUnion;
221         doubleUnion.asBits = unTag(v);
222         return doubleUnion.asDouble;
223     }
224
225     static bool getTruncatedInt32(const JSValue* v, int32_t& i)
226     {
227         double d = toDouble(v);
228         if (!(d >= -2147483648.0 && d < 2147483648.0))
229             return false;
230         i = static_cast<int32_t>(d);
231         return isNumber(v);
232     }
233
234     static bool getTruncatedUInt32(const JSValue* v, uint32_t& i)
235     {
236         double d = toDouble(v);
237         if (!(d >= 0.0 && d < 4294967296.0))
238             return false;
239         i = static_cast<uint32_t>(d);
240         return isNumber(v);
241     }
242 };
243
244 inline JSValue* JSImmediate::trueImmediate() { return tag(FPBitValues<is32bit, is64bit>::oneAsBits, BooleanType); }
245 inline JSValue* JSImmediate::falseImmediate() { return tag(FPBitValues<is32bit, is64bit>::zeroAsBits, BooleanType); }
246 inline JSValue* JSImmediate::NaNImmediate() { return tag(FPBitValues<is32bit, is64bit>::nanAsBits, NumberType); }
247 inline JSValue* JSImmediate::undefinedImmediate() { return tag(FPBitValues<is32bit, is64bit>::nanAsBits, UndefinedType); }
248 inline JSValue* JSImmediate::nullImmediate() { return tag(FPBitValues<is32bit, is64bit>::zeroAsBits, UndefinedType); }
249
250 inline bool JSImmediate::toBoolean(const JSValue* v)
251 {
252     ASSERT(isImmediate(v));
253
254     uintptr_t bits = unTag(v);
255     if ((bits << 1) == 0) // -0.0 has the sign bit set
256         return false;
257
258     return bits != FPBitValues<is32bit, is64bit>::nanAsBits;
259 }
260
261 inline JSValue* JSImmediate::fromDouble(double d)
262 {
263     return FPBitValues<is32bit, is64bit>::fromDouble(d);
264 }
265
266 inline double JSImmediate::toDouble(const JSValue* v)
267 {
268     return FPBitValues<is32bit, is64bit>::toDouble(v);
269 }
270
271 inline bool JSImmediate::getUInt32(const JSValue* v, uint32_t& i)
272 {
273     double d = toDouble(v);
274     i = static_cast<uint32_t>(d);
275     return isNumber(v) & (i == d);
276 }
277
278 inline bool JSImmediate::getTruncatedInt32(const JSValue* v, int32_t& i)
279 {
280     return FPBitValues<is32bit, is64bit>::getTruncatedInt32(v, i);
281 }
282
283 inline bool JSImmediate::getTruncatedUInt32(const JSValue* v, uint32_t& i)
284 {
285     return FPBitValues<is32bit, is64bit>::getTruncatedUInt32(v, i);
286 }
287
288 } // namespace KJS
289
290 #endif