Changeset 27602 in webkit for trunk/JavaScriptCore/kjs/JSImmediate.h
- Timestamp:
- Nov 8, 2007, 10:27:21 AM (18 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JavaScriptCore/kjs/JSImmediate.h
r27416 r27602 26 26 #include <wtf/Assertions.h> 27 27 #include <wtf/AlwaysInline.h> 28 #include <limits> 29 #include <math.h> 28 30 #include <stdarg.h> 29 31 #include <stdint.h> … … 39 41 /* 40 42 * A JSValue* is either a pointer to a cell (a heap-allocated object) or an immediate (a type-tagged 41 * IEEE floating point bit patternmasquerading as a pointer). The low two bits in a JSValue* are available43 * signed int masquerading as a pointer). The low two bits in a JSValue* are available 42 44 * for type tagging because allocator alignment guarantees they will be 00 in cell pointers. 43 45 * … … 48 50 * 49 51 * JSImmediate: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX TT 50 * [ high 30 bits: IEEE encoded float ][ low 2 bits -- type tag ]51 * 52 * The bit "payload" (the high t 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.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. 54 56 * 55 57 * Notice that the JSType value of NullType is 4, which requires 3 bits to encode. Since we only have 2 bits 56 58 * 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 * to sort them out. 59 60 */ 60 61 … … 97 98 static JSValue* trueImmediate(); 98 99 static JSValue* falseImmediate(); 99 static JSValue* NaNImmediate();100 100 static JSValue* undefinedImmediate(); 101 101 static JSValue* nullImmediate(); … … 119 119 } 120 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 121 // we support 32-bit platforms with sizes like this 134 122 static const bool is32bit = … … 149 137 static ALWAYS_INLINE JSValue* fromDouble(double d) 150 138 { 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. This 159 // unfortunately also rejects NaN, however, it costs more to 160 // do a check that will include NaN than is saved by letting 161 // NaN be an immediate. 162 if (floatUnion.asFloat == d) 163 return tag(floatUnion.asBits, NumberType); 164 165 return 0; 166 } 167 168 static ALWAYS_INLINE float toFloat(const JSValue* v) 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) 169 155 { 170 156 ASSERT(isImmediate(v)); 171 172 FloatUnion floatUnion; 173 floatUnion.asBits = static_cast<uint32_t>(unTag(v)); 174 return floatUnion.asFloat; 175 } 176 177 static ALWAYS_INLINE double toDouble(const JSValue* v) 178 { 179 return toFloat(v); 180 } 181 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 182 163 static ALWAYS_INLINE bool getTruncatedInt32(const JSValue* v, int32_t& i) 183 164 { 184 float f = toFloat(v);185 if ( !(f >= -2147483648.0F && f < 2147483648.0F))165 i = static_cast<int32_t>(unTag(v)) >> 2; 166 if (JSImmediate::getTag(v) == UndefinedType && i) 186 167 return false; 187 i = static_cast<int32_t>(f);188 168 return isNumber(v); 189 169 } 190 170 191 171 static ALWAYS_INLINE bool getTruncatedUInt32(const JSValue* v, uint32_t& i) 192 172 { 193 float f = toFloat(v); 194 if (!(f >= 0.0F && f < 4294967296.0F)) 195 return false; 196 i = static_cast<uint32_t>(f); 197 return isNumber(v); 173 int32_t& si = reinterpret_cast<int&>(i); 174 return getTruncatedInt32(v, si) & (si >= 0); 198 175 } 199 176 }; … … 206 183 static ALWAYS_INLINE JSValue* fromDouble(double d) 207 184 { 208 DoubleUnion doubleUnion; 209 doubleUnion.asDouble = d; 210 211 // check for data loss from tagging 212 if ((doubleUnion.asBits & TagMask) != 0) 213 return 0; 214 215 return tag(static_cast<uintptr_t>(doubleUnion.asBits), NumberType); 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); 216 199 } 217 200 … … 219 202 { 220 203 ASSERT(isImmediate(v)); 221 222 DoubleUnion doubleUnion;223 doubleUnion.asBits = unTag(v);224 return doubleUnion.asDouble;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; 225 208 } 226 209 227 210 static ALWAYS_INLINE bool getTruncatedInt32(const JSValue* v, int32_t& i) 228 211 { 229 double d = toDouble(v);230 if ( !(d >= -2147483648.0 && d < 2147483648.0))212 i = static_cast<int32_t>(unTag(v) >> 2); 213 if (JSImmediate::getTag(v) == UndefinedType && i) 231 214 return false; 232 i = static_cast<int32_t>(d);233 215 return isNumber(v); 234 216 } 235 217 236 218 static ALWAYS_INLINE bool getTruncatedUInt32(const JSValue* v, uint32_t& i) 237 { 238 double d = toDouble(v); 239 if (!(d >= 0.0 && d < 4294967296.0)) 240 return false; 241 i = static_cast<uint32_t>(d); 242 return isNumber(v); 219 { 220 int& si = reinterpret_cast<int&>(i); 221 return getTruncatedInt32(v, si) & (si >= 0); 243 222 } 244 223 }; 245 224 246 ALWAYS_INLINE JSValue* JSImmediate::trueImmediate() { return tag(FPBitValues<is32bit, is64bit>::oneAsBits, BooleanType); } 247 ALWAYS_INLINE JSValue* JSImmediate::falseImmediate() { return tag(FPBitValues<is32bit, is64bit>::zeroAsBits, BooleanType); } 248 ALWAYS_INLINE JSValue* JSImmediate::NaNImmediate() { return tag(FPBitValues<is32bit, is64bit>::nanAsBits, NumberType); } 249 ALWAYS_INLINE JSValue* JSImmediate::undefinedImmediate() { return tag(FPBitValues<is32bit, is64bit>::nanAsBits, UndefinedType); } 250 ALWAYS_INLINE JSValue* JSImmediate::nullImmediate() { return tag(FPBitValues<is32bit, is64bit>::zeroAsBits, UndefinedType); } 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); } 251 229 252 230 ALWAYS_INLINE bool JSImmediate::toBoolean(const JSValue* v) 253 231 { 254 232 ASSERT(isImmediate(v)); 255 256 233 uintptr_t bits = unTag(v); 257 if ((bits << 1) == 0) // -0.0 has the sign bit set 258 return false; 259 260 return bits != FPBitValues<is32bit, is64bit>::nanAsBits; 234 return bits != 0 & (JSImmediate::getTag(v) != UndefinedType); 261 235 } 262 236 … … 273 247 ALWAYS_INLINE bool JSImmediate::getUInt32(const JSValue* v, uint32_t& i) 274 248 { 275 double d = toDouble(v); 276 i = static_cast<uint32_t>(d); 277 return isNumber(v) & (i == d); 249 return FPBitValues<is32bit, is64bit>::getTruncatedUInt32(v, i); 278 250 } 279 251
Note:
See TracChangeset
for help on using the changeset viewer.