source: webkit/trunk/JavaScriptCore/kjs/JSImmediate.h@ 27215

Last change on this file since 27215 was 27149, checked in by darin, 18 years ago

Reviewed by Maciej.

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