2 * Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
3 * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org)
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.
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.
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.
22 #ifndef KJS_JS_IMMEDIATE_H
23 #define KJS_JS_IMMEDIATE_H
26 #include <wtf/Assertions.h>
27 #include <wtf/AlwaysInline.h>
28 #include <wtf/MathExtras.h>
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.
46 * For example, on a 32 bit system:
48 * JSCell*: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 00
49 * [ high 30 bits: pointer address ] [ low 2 bits -- always 0 ]
51 * JSImmediate: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX TT
52 * [ high 30 bits: signed int ] [ low 2 bits -- type tag ]
54 * The bit "payload" (the high 30 bits) is a 30 bit signed int for immediate numbers, a flag to distinguish true/false
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
64 static ALWAYS_INLINE bool isImmediate(const JSValue* v)
66 return getTag(v) != 0;
69 static ALWAYS_INLINE bool isNumber(const JSValue* v)
71 return (getTag(v) == NumberType);
74 static ALWAYS_INLINE bool isBoolean(const JSValue* v)
76 return (getTag(v) == BooleanType);
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)
82 return (getTag(v) == UndefinedType);
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*);
92 static bool getUInt32(const JSValue*, uint32_t&);
93 static bool getTruncatedInt32(const JSValue*, int32_t&);
94 static bool getTruncatedUInt32(const JSValue*, uint32_t&);
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();
104 static const uintptr_t TagMask = 3; // type tags are 2 bits long
106 static ALWAYS_INLINE JSValue* tag(uintptr_t bits, uintptr_t tag)
108 return reinterpret_cast<JSValue*>(bits | tag);
111 static ALWAYS_INLINE uintptr_t unTag(const JSValue* v)
113 return reinterpret_cast<uintptr_t>(v) & ~TagMask;
116 static ALWAYS_INLINE uintptr_t getTag(const JSValue* v)
118 return reinterpret_cast<uintptr_t>(v) & TagMask;
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);
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);
129 template<bool for32bit, bool for64bit> struct FPBitValues {};
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;
137 static ALWAYS_INLINE JSValue* fromDouble(double d)
139 const int32_t intVal = static_cast<int>(d);
141 // On 32 bit systems immediate values are restricted to a 30 bit signed value
142 if ((intVal <= -(1 << 29)) | (intVal >= ((1 << 29) - 1)))
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))
151 return tag(intVal << 2, NumberType);
154 static ALWAYS_INLINE double toDouble(const JSValue* v)
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();
163 static ALWAYS_INLINE bool getTruncatedInt32(const JSValue* v, int32_t& i)
165 i = static_cast<int32_t>(unTag(v)) >> 2;
166 if (JSImmediate::getTag(v) == UndefinedType && i)
171 static ALWAYS_INLINE bool getTruncatedUInt32(const JSValue* v, uint32_t& i)
173 int32_t& si = reinterpret_cast<int&>(i);
174 return getTruncatedInt32(v, si) & (si >= 0);
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;
183 static ALWAYS_INLINE JSValue* fromDouble(double d)
185 const int64_t intVal = static_cast<int>(d);
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)))
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))
198 return tag(static_cast<uintptr_t>(intVal << 2), NumberType);
201 static ALWAYS_INLINE double toDouble(const JSValue* v)
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();
210 static ALWAYS_INLINE bool getTruncatedInt32(const JSValue* v, int32_t& i)
212 i = static_cast<int32_t>(unTag(v) >> 2);
213 if (JSImmediate::getTag(v) == UndefinedType && i)
218 static ALWAYS_INLINE bool getTruncatedUInt32(const JSValue* v, uint32_t& i)
220 int& si = reinterpret_cast<int&>(i);
221 return getTruncatedInt32(v, si) & (si >= 0);
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); }
230 ALWAYS_INLINE bool JSImmediate::toBoolean(const JSValue* v)
232 ASSERT(isImmediate(v));
233 uintptr_t bits = unTag(v);
234 return (bits != 0) & (JSImmediate::getTag(v) != UndefinedType);
237 ALWAYS_INLINE JSValue* JSImmediate::fromDouble(double d)
239 return FPBitValues<is32bit, is64bit>::fromDouble(d);
242 ALWAYS_INLINE double JSImmediate::toDouble(const JSValue* v)
244 return FPBitValues<is32bit, is64bit>::toDouble(v);
247 ALWAYS_INLINE bool JSImmediate::getUInt32(const JSValue* v, uint32_t& i)
249 return FPBitValues<is32bit, is64bit>::getTruncatedUInt32(v, i);
252 ALWAYS_INLINE bool JSImmediate::getTruncatedInt32(const JSValue* v, int32_t& i)
254 return FPBitValues<is32bit, is64bit>::getTruncatedInt32(v, i);
257 ALWAYS_INLINE bool JSImmediate::getTruncatedUInt32(const JSValue* v, uint32_t& i)
259 return FPBitValues<is32bit, is64bit>::getTruncatedUInt32(v, i);