Changeset 440 for trunk/JavaScriptCore/kjs/JSImmediate.h
- Timestamp:
- 08/18/08 11:14:49 (5 months ago)
- Files:
-
- trunk/JavaScriptCore/kjs/JSImmediate.h (modified) (23 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/JavaScriptCore/kjs/JSImmediate.h
r418 r440 28 28 #include <wtf/MathExtras.h> 29 29 #include <limits> 30 #include <limits.h> 30 31 #include <stdarg.h> 31 32 #include <stdint.h> … … 41 42 /* 42 43 * 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 available44 * for type taggingbecause allocator alignment guarantees they will be 00 in cell pointers.44 * value masquerading as a pointer). The low two bits in a JSValue* are available for type tagging 45 * because allocator alignment guarantees they will be 00 in cell pointers. 45 46 * 46 47 * For example, on a 32 bit system: 47 48 * 48 * JSCell*: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 00 49 * [ high 30 bits: pointer address ] [ low 2 bits -- always 0 ] 50 * 51 * JSImmediate: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX TT 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. 56 * 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 59 * to sort them out. 49 * JSCell*: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 00 50 * [ high 30 bits: pointer address ] [ low 2 bits -- always 0 ] 51 * JSImmediate: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX TT 52 * [ high 30 bits: 'payload' ] [ low 2 bits -- tag ] 53 * 54 * Where the bottom two bits are non-zero they either indicate that the immediate is a 31 bit signed 55 * integer, or they mark the value as being an immediate of a type other than integer, with a secondary 56 * tag used to indicate the exact type. 57 * 58 * Where the lowest bit is set (TT is equal to 01 or 11) the high 31 bits form a 31 bit signed int value. 59 * Where TT is equal to 10 this indicates this is a type of immediate other than an integer, and the next 60 * two bits will form an extended tag. 61 * 62 * 31 bit signed int: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX X1 63 * [ high 30 bits of the value ] [ high bit part of value ] 64 * Other: YYYYYYYYYYYYYYYYYYYYYYYYYYYY ZZ 10 65 * [ extended 'payload' ] [ extended tag ] [ tag 'other' ] 66 * 67 * Where the first bit of the extended tag is set this flags the value as being a boolean, and the following 68 * bit would flag the value as undefined. If neither bits are set, the value is null. 69 * 70 * Other: YYYYYYYYYYYYYYYYYYYYYYYYYYYY UB 10 71 * [ extended 'payload' ] [ undefined | bool ] [ tag 'other' ] 72 * 73 * For boolean value the lowest bit in the payload holds the value of the bool, all remaining bits are zero. 74 * For undefined or null immediates the payload is zero. 75 * 76 * Boolean: 000000000000000000000000000V 01 10 77 * [ boolean value ] [ bool ] [ tag 'other' ] 78 * Undefined: 0000000000000000000000000000 10 10 79 * [ zero ] [ undefined ] [ tag 'other' ] 80 * Null: 0000000000000000000000000000 00 10 81 * [ zero ] [ zero ] [ tag 'other' ] 60 82 */ 61 83 62 84 class JSImmediate { 85 static const uintptr_t TagMask = 0x3u; // primary tag is 2 bits long 86 static const uintptr_t TagBitTypeInteger = 0x1u; // bottom bit set indicates int, this dominates the following bit 87 static const uintptr_t TagBitTypeOther = 0x2u; // second bit set indicates immediate other than an integer 88 89 static const uintptr_t ExtendedTagMask = 0xCu; // extended tag holds a further two bits 90 static const uintptr_t ExtendedTagBitBool = 0x4u; 91 static const uintptr_t ExtendedTagBitUndefined = 0x8u; 92 93 static const uintptr_t FullTagTypeMask = TagMask | ExtendedTagMask; 94 static const uintptr_t FullTagTypeBool = TagBitTypeOther | ExtendedTagBitBool; 95 static const uintptr_t FullTagTypeUndefined = TagBitTypeOther | ExtendedTagBitUndefined; 96 static const uintptr_t FullTagTypeNull = TagBitTypeOther; 97 98 static const uint32_t IntegerPayloadShift = 1u; 99 static const uint32_t ExtendedPayloadShift = 4u; 100 101 static const uintptr_t ExtendedPayloadBitBoolValue = 1 << ExtendedPayloadShift; 102 63 103 public: 64 104 static ALWAYS_INLINE bool isImmediate(const JSValue* v) 65 105 { 66 return getTag(v) != 0;106 return (reinterpret_cast<uintptr_t>(v) & TagMask); 67 107 } 68 108 69 109 static ALWAYS_INLINE bool isNumber(const JSValue* v) 70 110 { 71 return ( getTag(v) == NumberType);111 return (reinterpret_cast<uintptr_t>(v) & TagBitTypeInteger); 72 112 } 73 113 … … 75 115 { 76 116 // A single mask to check for the sign bit and the number tag all at once. 77 return (reinterpret_cast<uintptr_t>(v) & (0x80000000 | NumberType)) == NumberType;117 return (reinterpret_cast<uintptr_t>(v) & (0x80000000 | TagBitTypeInteger)) == TagBitTypeInteger; 78 118 } 79 119 80 120 static ALWAYS_INLINE bool isBoolean(const JSValue* v) 81 121 { 82 return (getTag(v) == BooleanType); 83 } 84 85 // Since we have room for only 3 unique tags, null and undefined have to share. 122 return ((reinterpret_cast<uintptr_t>(v) & FullTagTypeMask) == FullTagTypeBool); 123 } 124 86 125 static ALWAYS_INLINE bool isUndefinedOrNull(const JSValue* v) 87 126 { 88 return (getTag(v) == UndefinedType); 127 // Undefined and null share the same value, bar the 'undefined' bit in the extended tag. 128 return ((reinterpret_cast<uintptr_t>(v) & ~ExtendedTagBitUndefined) == FullTagTypeNull); 89 129 } 90 130 … … 110 150 static ALWAYS_INLINE bool areBothImmediateNumbers(const JSValue* v1, const JSValue* v2) 111 151 { 112 return (reinterpret_cast<uintptr_t>(v1) & reinterpret_cast<uintptr_t>(v2) & TagMask) == NumberType;152 return (reinterpret_cast<uintptr_t>(v1) & reinterpret_cast<uintptr_t>(v2) & TagBitTypeInteger); 113 153 } 114 154 … … 122 162 { 123 163 ASSERT(areBothImmediateNumbers(v1, v2)); 124 return tag(reinterpret_cast<uintptr_t>(v1) ^ reinterpret_cast<uintptr_t>(v2), NumberType);164 return reinterpret_cast<JSValue*>((reinterpret_cast<uintptr_t>(v1) ^ reinterpret_cast<uintptr_t>(v2)) | TagBitTypeInteger); 125 165 } 126 166 … … 134 174 { 135 175 ASSERT(areBothImmediateNumbers(val, shift)); 136 return reinterpret_cast<JSValue*>((reinterpret_cast<intptr_t>(val) >> ((reinterpret_cast<uintptr_t>(shift) >> 2) & 0x1f)) | NumberType);176 return reinterpret_cast<JSValue*>((reinterpret_cast<intptr_t>(val) >> ((reinterpret_cast<uintptr_t>(shift) >> IntegerPayloadShift) & 0x1f)) | TagBitTypeInteger); 137 177 } 138 178 … … 141 181 // Number is non-negative and an operation involving two of these can't overflow. 142 182 // Checking for allowed negative numbers takes more time than it's worth on SunSpider. 143 return (reinterpret_cast<uintptr_t>(v) & ( NumberType + (3 << 30))) == NumberType;183 return (reinterpret_cast<uintptr_t>(v) & (TagBitTypeInteger + (3u << 30))) == TagBitTypeInteger; 144 184 } 145 185 … … 148 188 ASSERT(canDoFastAdditiveOperations(v1)); 149 189 ASSERT(canDoFastAdditiveOperations(v2)); 150 return reinterpret_cast<JSValue*>(reinterpret_cast<uintptr_t>(v1) + (reinterpret_cast<uintptr_t>(v2) & ~NumberType));190 return reinterpret_cast<JSValue*>(reinterpret_cast<uintptr_t>(v1) + reinterpret_cast<uintptr_t>(v2) - TagBitTypeInteger); 151 191 } 152 192 … … 155 195 ASSERT(canDoFastAdditiveOperations(v1)); 156 196 ASSERT(canDoFastAdditiveOperations(v2)); 157 return reinterpret_cast<JSValue*>(reinterpret_cast<uintptr_t>(v1) - (reinterpret_cast<uintptr_t>(v2) & ~NumberType));197 return reinterpret_cast<JSValue*>(reinterpret_cast<uintptr_t>(v1) - reinterpret_cast<uintptr_t>(v2) + TagBitTypeInteger); 158 198 } 159 199 … … 161 201 { 162 202 ASSERT(canDoFastAdditiveOperations(v)); 163 return reinterpret_cast<JSValue*>(reinterpret_cast<uintptr_t>(v) + TagMask + 1);203 return reinterpret_cast<JSValue*>(reinterpret_cast<uintptr_t>(v) + (1 << IntegerPayloadShift)); 164 204 } 165 205 … … 167 207 { 168 208 ASSERT(canDoFastAdditiveOperations(v)); 169 return reinterpret_cast<JSValue*>(reinterpret_cast<uintptr_t>(v) - ( TagMask + 1));209 return reinterpret_cast<JSValue*>(reinterpret_cast<uintptr_t>(v) - (1 << IntegerPayloadShift)); 170 210 } 171 211 … … 193 233 194 234 private: 195 static const uintptr_t TagMask = 3; // type tags are 2 bits long196 197 235 // Immediate values are restricted to a 30 bit signed value. 198 static const int minImmediateInt = -(1 << 29);199 static const int maxImmediateInt = (1 << 29) - 1;236 static const int minImmediateInt = ((-INT_MAX) - 1) >> IntegerPayloadShift; 237 static const int maxImmediateInt = INT_MAX >> IntegerPayloadShift; 200 238 static const unsigned maxImmediateUInt = maxImmediateInt; 201 239 202 static ALWAYS_INLINE JSValue* tag(uintptr_t bits, uintptr_t tag) 203 { 204 return reinterpret_cast<JSValue*>(bits | tag); 205 } 206 207 static ALWAYS_INLINE uintptr_t unTag(const JSValue* v) 208 { 209 return reinterpret_cast<uintptr_t>(v) & ~TagMask; 210 } 211 212 static ALWAYS_INLINE uintptr_t getTag(const JSValue* v) 213 { 214 return reinterpret_cast<uintptr_t>(v) & TagMask; 240 static ALWAYS_INLINE JSValue* makeInt(int32_t value) 241 { 242 return reinterpret_cast<JSValue*>((value << IntegerPayloadShift) | TagBitTypeInteger); 243 } 244 245 static ALWAYS_INLINE JSValue* makeBool(bool b) 246 { 247 return reinterpret_cast<JSValue*>((static_cast<uintptr_t>(b) << ExtendedPayloadShift) | FullTagTypeBool); 248 } 249 250 static ALWAYS_INLINE JSValue* makeUndefined() 251 { 252 return reinterpret_cast<JSValue*>(FullTagTypeUndefined); 253 } 254 255 static ALWAYS_INLINE JSValue* makeNull() 256 { 257 return reinterpret_cast<JSValue*>(FullTagTypeNull); 258 } 259 260 static ALWAYS_INLINE int32_t intValue(const JSValue* v) 261 { 262 return static_cast<int32_t>(reinterpret_cast<intptr_t>(v) >> IntegerPayloadShift); 263 } 264 265 static ALWAYS_INLINE uint32_t uintValue(const JSValue* v) 266 { 267 return static_cast<uint32_t>(rawValue(v) >> IntegerPayloadShift); 268 } 269 270 static ALWAYS_INLINE bool boolValue(const JSValue* v) 271 { 272 return (rawValue(v) & ExtendedPayloadBitBoolValue) != 0; 273 } 274 275 static ALWAYS_INLINE uintptr_t rawValue(const JSValue* v) 276 { 277 return reinterpret_cast<uintptr_t>(v); 215 278 } 216 279 }; 217 280 218 ALWAYS_INLINE JSValue* JSImmediate::trueImmediate() { return tag(1 << 2, BooleanType); }219 ALWAYS_INLINE JSValue* JSImmediate::falseImmediate() { return tag(0, BooleanType); }220 ALWAYS_INLINE JSValue* JSImmediate::undefinedImmediate() { return tag(1 << 2, UndefinedType); }221 ALWAYS_INLINE JSValue* JSImmediate::nullImmediate() { return tag(0, UndefinedType); }281 ALWAYS_INLINE JSValue* JSImmediate::trueImmediate() { return makeBool(true); } 282 ALWAYS_INLINE JSValue* JSImmediate::falseImmediate() { return makeBool(false); } 283 ALWAYS_INLINE JSValue* JSImmediate::undefinedImmediate() { return makeUndefined(); } 284 ALWAYS_INLINE JSValue* JSImmediate::nullImmediate() { return makeNull(); } 222 285 223 286 // This value is impossible because 0x4 is not a valid pointer but a tag of 0 would indicate non-immediate 224 ALWAYS_INLINE JSValue* JSImmediate::impossibleValue() { return tag(1 << 2, 0); }287 ALWAYS_INLINE JSValue* JSImmediate::impossibleValue() { return reinterpret_cast<JSValue*>(0x4); } 225 288 226 289 ALWAYS_INLINE bool JSImmediate::toBoolean(const JSValue* v) 227 290 { 228 291 ASSERT(isImmediate(v)); 229 uintptr_t bits = unTag(v); 230 return (bits != 0) & (JSImmediate::getTag(v) != UndefinedType); 292 uintptr_t bits = rawValue(v); 293 return 294 (bits & TagBitTypeInteger) ? (bits != TagBitTypeInteger) : // !0 ints 295 (bits == (FullTagTypeBool | ExtendedPayloadBitBoolValue)); // bool true 231 296 } 232 297 233 298 ALWAYS_INLINE uint32_t JSImmediate::toTruncatedUInt32(const JSValue* v) 234 299 { 235 ASSERT(is Immediate(v));236 return static_cast<uint32_t>(reinterpret_cast<intptr_t>(v) >> 2);300 ASSERT(isNumber(v)); 301 return intValue(v); 237 302 } 238 303 239 304 ALWAYS_INLINE JSValue* JSImmediate::from(char i) 240 305 { 241 return tag(i << 2, NumberType);306 return makeInt(i); 242 307 } 243 308 244 309 ALWAYS_INLINE JSValue* JSImmediate::from(signed char i) 245 310 { 246 return tag(i << 2, NumberType);311 return makeInt(i); 247 312 } 248 313 249 314 ALWAYS_INLINE JSValue* JSImmediate::from(unsigned char i) 250 315 { 251 return tag(i << 2, NumberType);316 return makeInt(i); 252 317 } 253 318 254 319 ALWAYS_INLINE JSValue* JSImmediate::from(short i) 255 320 { 256 return tag(i << 2, NumberType);321 return makeInt(i); 257 322 } 258 323 259 324 ALWAYS_INLINE JSValue* JSImmediate::from(unsigned short i) 260 325 { 261 return tag(i << 2, NumberType);326 return makeInt(i); 262 327 } 263 328 … … 266 331 if ((i < minImmediateInt) | (i > maxImmediateInt)) 267 332 return 0; 268 return tag(i << 2, NumberType);333 return makeInt(i); 269 334 } 270 335 … … 273 338 if (i > maxImmediateUInt) 274 339 return 0; 275 return tag(i << 2, NumberType);340 return makeInt(i); 276 341 } 277 342 … … 280 345 if ((i < minImmediateInt) | (i > maxImmediateInt)) 281 346 return 0; 282 return tag(i << 2, NumberType);347 return makeInt(i); 283 348 } 284 349 … … 287 352 if (i > maxImmediateUInt) 288 353 return 0; 289 return tag(i << 2, NumberType);354 return makeInt(i); 290 355 } 291 356 … … 294 359 if ((i < minImmediateInt) | (i > maxImmediateInt)) 295 360 return 0; 296 return tag(static_cast<uintptr_t>(i) << 2, NumberType);361 return makeInt(static_cast<uintptr_t>(i)); 297 362 } 298 363 … … 301 366 if (i > maxImmediateUInt) 302 367 return 0; 303 return tag(static_cast<uintptr_t>(i) << 2, NumberType);368 return makeInt(static_cast<uintptr_t>(i)); 304 369 } 305 370 … … 315 380 return 0; 316 381 317 return tag(intVal << 2, NumberType);382 return makeInt(intVal); 318 383 } 319 384 … … 321 386 { 322 387 ASSERT(isNumber(v)); 323 return static_cast<int32_t>(unTag(v)) >> 2;388 return intValue(v); 324 389 } 325 390 … … 327 392 { 328 393 ASSERT(isImmediate(v)); 329 const int32_t i = static_cast<int32_t>(unTag(v)) >> 2; 330 if (JSImmediate::getTag(v) == UndefinedType && i) 331 return std::numeric_limits<double>::quiet_NaN(); 332 return i; 394 if (isNumber(v)) 395 return intValue(v); 396 if (rawValue(v) == (FullTagTypeBool | ExtendedPayloadBitBoolValue)) 397 return 1.0; 398 if (rawValue(v) != FullTagTypeUndefined) 399 return 0.0; 400 return std::numeric_limits<double>::quiet_NaN(); 333 401 } 334 402 335 403 ALWAYS_INLINE bool JSImmediate::getUInt32(const JSValue* v, uint32_t& i) 336 404 { 337 i = static_cast<uintptr_t>(unTag(v)) >> 2;405 i = uintValue(v); 338 406 return isPositiveNumber(v); 339 407 } … … 341 409 ALWAYS_INLINE bool JSImmediate::getTruncatedInt32(const JSValue* v, int32_t& i) 342 410 { 343 i = static_cast<int32_t>(unTag(v)) >> 2;411 i = intValue(v); 344 412 return isNumber(v); 345 413 } … … 354 422 ASSERT(isImmediate(v)); 355 423 356 uintptr_t tag = getTag(v); 357 if (tag == UndefinedType) 358 return v == undefinedImmediate() ? UndefinedType : NullType; 359 return static_cast<JSType>(tag); 424 if (isNumber(v)) 425 return NumberType; 426 if (isBoolean(v)) 427 return BooleanType; 428 if (v != undefinedImmediate()) 429 return NullType; 430 return UndefinedType; 360 431 } 361 432
