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

Last change on this file since 20310 was 17723, checked in by ap, 19 years ago

Reviewed by Maciej.

http://bugs.webkit.org/show_bug.cgi?id=11508
Undisable some warnings for JSImmediate.h

Fix suggested by Don Gibson.

  • kjs/JSImmediate.h: Re-enable all MSVC warnings, move the remaining runtime checks to compile-time.
  • Property svn:eol-style set to native
File size: 7.4 KB
Line 
1/*
2 * This file is part of the KDE libraries
3 * Copyright (C) 2003-2006 Apple Computer, Inc
4 * Copyright (C) 2006 Alexey Proskuryakov ([email protected])
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB. If not, write to
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 *
21 */
22
23#ifndef KJS_JS_IMMEDIATE_H
24#define KJS_JS_IMMEDIATE_H
25
26#include "JSType.h"
27#include <wtf/Assertions.h>
28#include <stdint.h>
29#include <stdlib.h>
30
31namespace KJS {
32
33class ExecState;
34class JSObject;
35class JSValue;
36class 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
60class JSImmediate {
61public:
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* v);
85 static bool toBoolean(const JSValue* v);
86 static JSObject* toObject(const JSValue*, ExecState*);
87 static UString toString(const JSValue*);
88 static JSType type(const JSValue*);
89
90 // It would nice just to use fromDouble() to create these values, but that would prevent them from
91 // turning into compile-time constants.
92 static JSValue* trueImmediate();
93 static JSValue* falseImmediate();
94 static JSValue* NaNImmediate();
95 static JSValue* undefinedImmediate();
96 static JSValue* nullImmediate();
97
98private:
99 static const uintptr_t TagMask = 3; // type tags are 2 bits long
100
101 static JSValue* tag(uintptr_t bits, uintptr_t tag)
102 {
103 return reinterpret_cast<JSValue*>(bits | tag);
104 }
105
106 static uintptr_t unTag(const JSValue* v)
107 {
108 return reinterpret_cast<uintptr_t>(v) & ~TagMask;
109 }
110
111 static uintptr_t getTag(const JSValue* v)
112 {
113 return reinterpret_cast<uintptr_t>(v) & TagMask;
114 }
115
116 // NOTE: With f-strict-aliasing enabled, unions are the only safe way to do type masquerading.
117
118 union FloatUnion {
119 uint32_t asBits;
120 float asFloat;
121 };
122
123 union DoubleUnion {
124 uint64_t asBits;
125 double asDouble;
126 };
127
128 // we support 32-bit platforms with sizes like this
129 static const bool is32bit =
130 sizeof(float) == sizeof(uint32_t) && sizeof(double) == sizeof(uint64_t) && sizeof(uintptr_t) == sizeof(uint32_t);
131
132 // we support 64-bit platforms with sizes like this
133 static const bool is64bit =
134 sizeof(float) == sizeof(uint32_t) && sizeof(double) == sizeof(uint64_t) && sizeof(uintptr_t) == sizeof(uint64_t);
135
136 template<bool for32bit, bool for64bit> struct FPBitValues {};
137};
138
139template<> struct JSImmediate::FPBitValues<true, false> {
140 static const uint32_t nanAsBits = 0x7fc00000;
141 static const uint32_t oneAsBits = 0x3f800000;
142 static const uint32_t zeroAsBits = 0x0;
143
144 static JSValue* fromDouble(double d)
145 {
146 FloatUnion floatUnion;
147 floatUnion.asFloat = static_cast<float>(d);
148
149 // check for data loss from tagging
150 if ((floatUnion.asBits & TagMask) != 0)
151 return 0;
152
153 // check for data loss from conversion to float
154 DoubleUnion doubleUnion1, doubleUnion2;
155 doubleUnion1.asDouble = floatUnion.asFloat;
156 doubleUnion2.asDouble = d;
157 if (doubleUnion1.asBits != doubleUnion2.asBits)
158 return 0;
159
160 return tag(floatUnion.asBits, NumberType);
161 }
162
163 static double toDouble(const JSValue* v)
164 {
165 ASSERT(isImmediate(v));
166
167 FloatUnion floatUnion;
168 floatUnion.asBits = static_cast<uint32_t>(unTag(v));
169 return floatUnion.asFloat;
170 }
171};
172
173template<> struct JSImmediate::FPBitValues<false, true> {
174 static const uint64_t nanAsBits = 0x7ff80000ULL << 32;
175 static const uint64_t oneAsBits = 0x3ff00000ULL << 32;
176 static const uint64_t zeroAsBits = 0x0;
177
178 static JSValue* fromDouble(double d)
179 {
180 DoubleUnion doubleUnion;
181 doubleUnion.asDouble = d;
182
183 // check for data loss from tagging
184 if ((doubleUnion.asBits & TagMask) != 0)
185 return 0;
186
187 return tag(static_cast<uintptr_t>(doubleUnion.asBits), NumberType);
188 }
189
190 static double toDouble(const JSValue* v)
191 {
192 ASSERT(isImmediate(v));
193
194 DoubleUnion doubleUnion;
195 doubleUnion.asBits = unTag(v);
196 return doubleUnion.asDouble;
197 }
198};
199
200inline JSValue* JSImmediate::trueImmediate() { return tag(FPBitValues<is32bit, is64bit>::oneAsBits, BooleanType); }
201inline JSValue* JSImmediate::falseImmediate() { return tag(FPBitValues<is32bit, is64bit>::zeroAsBits, BooleanType); }
202inline JSValue* JSImmediate::NaNImmediate() { return tag(FPBitValues<is32bit, is64bit>::nanAsBits, NumberType); }
203inline JSValue* JSImmediate::undefinedImmediate() { return tag(FPBitValues<is32bit, is64bit>::nanAsBits, UndefinedType); }
204inline JSValue* JSImmediate::nullImmediate() { return tag(FPBitValues<is32bit, is64bit>::zeroAsBits, UndefinedType); }
205
206inline bool JSImmediate::toBoolean(const JSValue* v)
207{
208 ASSERT(isImmediate(v));
209
210 uintptr_t bits = unTag(v);
211 if ((bits << 1) == 0) // -0.0 has the sign bit set
212 return false;
213
214 return bits != FPBitValues<is32bit, is64bit>::nanAsBits;
215}
216
217inline JSValue* JSImmediate::fromDouble(double d)
218{
219 return FPBitValues<is32bit, is64bit>::fromDouble(d);
220}
221
222inline double JSImmediate::toDouble(const JSValue* v)
223{
224 return FPBitValues<is32bit, is64bit>::toDouble(v);
225}
226
227} // namespace KJS
228
229#endif
Note: See TracBrowser for help on using the repository browser.