Changeset 39958 in webkit for trunk/JavaScriptCore/runtime/JSImmediate.h
- Timestamp:
- Jan 15, 2009, 7:20:35 PM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JavaScriptCore/runtime/JSImmediate.h
r39879 r39958 26 26 #include <wtf/AlwaysInline.h> 27 27 #include <wtf/MathExtras.h> 28 #include <wtf/StdLibExtras.h> 28 29 #include "JSValue.h" 29 30 #include <limits> … … 68 69 JSValuePtr jsNumber(JSGlobalData* globalData, unsigned long long i); 69 70 71 #if USE(ALTERNATE_JSIMMEDIATE) 72 inline intptr_t reinterpretDoubleToIntptr(double value) 73 { 74 return WTF::bitwise_cast<intptr_t>(value); 75 } 76 77 inline double reinterpretIntptrToDouble(intptr_t value) 78 { 79 return WTF::bitwise_cast<double>(value); 80 } 81 #endif 82 70 83 /* 71 84 * A JSValue* is either a pointer to a cell (a heap-allocated object) or an immediate (a type-tagged … … 112 125 /* 113 126 * On 64-bit platforms, we support an alternative encoding form for immediates, if 114 * USE(ALTERNATE_JSIMMEDIATE) is defined. 115 * 116 * The top 16-bits denote the type: 127 * USE(ALTERNATE_JSIMMEDIATE) is defined. When this format is used, double precision 128 * floating point values may also be encoded as JSImmediates. 129 * 130 * The encoding makes use of unused NaN space in the IEEE754 representation. Any value 131 * with the top 13 bits set represents a QNaN (with the sign bit set). QNaN values 132 * can encode a 51-bit payload. Hardware produced and C-library payloads typically 133 * have a payload of zero. We assume that non-zero payloads are available to encode 134 * pointer and integer values. Since any 64-bit bit pattern where the top 15 bits are 135 * all set represents a NaN with a non-zero payload, we can use this space in the NaN 136 * ranges to encode other values (however there are also other ranges of NaN space that 137 * could have been selected). This range of NaN space is represented by 64-bit numbers 138 * begining with the 16-bit hex patterns 0xFFFE and 0xFFFF - we rely on the fact that no 139 * valid double-precision numbers will begin fall in these ranges. 140 * 141 * The scheme we have implemented encodes double precision values by adding 2^48 to the 142 * 64-bit integer representation of the number. After this manipulation, no encoded 143 * double-precision value will begin with the pattern 0x0000 or 0xFFFF. 144 * 145 * The top 16-bits denote the type of the encoded JSImmediate: 117 146 * 118 147 * Pointer: 0000:PPPP:PPPP:PPPP 148 * 0001:****:****:**** 149 * Double:{ ... 150 * FFFE:****:****:**** 119 151 * Integer: FFFF:0000:IIII:IIII 120 152 * 121 * 32-bit signed integers are marked with the 16-bit tag '0xFFFF'. The tag '0x0000'153 * 32-bit signed integers are marked with the 16-bit tag 0xFFFF. The tag 0x0000 122 154 * denotes a pointer, or another form of tagged immediate. Boolean, null and undefined 123 155 * values are encoded in the same manner as the default format. … … 156 188 157 189 #if USE(ALTERNATE_JSIMMEDIATE) 158 static const intptr_t TagTypeInteger = 0xffff000000000000ll; // bottom bit set indicates integer, this dominates the following bit 159 #else 160 static const intptr_t TagTypeInteger = 0x1; // bottom bit set indicates integer, this dominates the following bit 190 // If all bits in the mask are set, this indicates an integer number, 191 // if any but not all are set this value is a double precision number. 192 static const intptr_t TagTypeNumber = 0xffff000000000000ll; 193 // This value is 2^48, used to encode doubles such that the encoded value will begin 194 // with a 16-bit pattern within the range 0x0001..0xFFFE. 195 static const intptr_t DoubleEncodeOffset = 0x1000000000000ll; 196 #else 197 static const intptr_t TagTypeNumber = 0x1; // bottom bit set indicates integer, this dominates the following bit 161 198 #endif 162 199 static const intptr_t TagBitTypeOther = 0x2; // second bit set indicates immediate other than an integer 163 static const intptr_t TagMask = TagType Integer | TagBitTypeOther;200 static const intptr_t TagMask = TagTypeNumber | TagBitTypeOther; 164 201 165 202 static const intptr_t ExtendedTagMask = 0xC; // extended tag holds a further two bits … … 190 227 static ALWAYS_INLINE bool isNumber(JSValuePtr v) 191 228 { 192 return rawValue(v) & TagTypeInteger; 193 } 194 195 static ALWAYS_INLINE bool isPositiveNumber(JSValuePtr v) 229 return rawValue(v) & TagTypeNumber; 230 } 231 232 static ALWAYS_INLINE bool isIntegerNumber(JSValuePtr v) 233 { 234 #if USE(ALTERNATE_JSIMMEDIATE) 235 return (rawValue(v) & TagTypeNumber) == TagTypeNumber; 236 #else 237 return isNumber(v); 238 #endif 239 } 240 241 #if USE(ALTERNATE_JSIMMEDIATE) 242 static ALWAYS_INLINE bool isDoubleNumber(JSValuePtr v) 243 { 244 return isNumber(v) && !isIntegerNumber(v); 245 } 246 #endif 247 248 static ALWAYS_INLINE bool isPositiveIntegerNumber(JSValuePtr v) 196 249 { 197 250 // A single mask to check for the sign bit and the number tag all at once. 198 return (rawValue(v) & (signBit | TagType Integer)) == TagTypeInteger;251 return (rawValue(v) & (signBit | TagTypeNumber)) == TagTypeNumber; 199 252 } 200 253 … … 208 261 // Undefined and null share the same value, bar the 'undefined' bit in the extended tag. 209 262 return (rawValue(v) & ~ExtendedTagBitUndefined) == FullTagTypeNull; 210 }211 212 static bool isNegative(JSValuePtr v)213 {214 ASSERT(isNumber(v));215 return rawValue(v) & signBit;216 263 } 217 264 … … 239 286 } 240 287 241 static ALWAYS_INLINE bool areBothImmediateNumbers(JSValuePtr v1, JSValuePtr v2) 242 { 243 return rawValue(v1) & rawValue(v2) & TagTypeInteger; 288 static ALWAYS_INLINE bool areBothImmediateIntegerNumbers(JSValuePtr v1, JSValuePtr v2) 289 { 290 #if USE(ALTERNATE_JSIMMEDIATE) 291 return (rawValue(v1) & rawValue(v2) & TagTypeNumber) == TagTypeNumber; 292 #else 293 return rawValue(v1) & rawValue(v2) & TagTypeNumber; 294 #endif 244 295 } 245 296 … … 283 334 } 284 335 336 // With USE(ALTERNATE_JSIMMEDIATE) we want the argument to be zero extended, so the 337 // integer doesn't interfere with the tag bits in the upper word. In the default encoding, 338 // if intptr_t id larger then int32_t we sign extend the value through the upper word. 285 339 #if USE(ALTERNATE_JSIMMEDIATE) 286 340 static ALWAYS_INLINE JSValuePtr makeInt(uint32_t value) … … 289 343 #endif 290 344 { 291 return makeValue((static_cast<intptr_t>(value) << IntegerPayloadShift) | TagTypeInteger); 292 } 345 return makeValue((static_cast<intptr_t>(value) << IntegerPayloadShift) | TagTypeNumber); 346 } 347 348 #if USE(ALTERNATE_JSIMMEDIATE) 349 static ALWAYS_INLINE JSValuePtr makeDouble(double value) 350 { 351 return makeValue(reinterpretDoubleToIntptr(value) + DoubleEncodeOffset); 352 } 353 #endif 293 354 294 355 static ALWAYS_INLINE JSValuePtr makeBool(bool b) … … 306 367 return makeValue(FullTagTypeNull); 307 368 } 308 369 370 template<typename T> 371 static JSValuePtr fromNumberOutsideIntegerRange(T); 372 373 #if USE(ALTERNATE_JSIMMEDIATE) 374 static ALWAYS_INLINE double doubleValue(JSValuePtr v) 375 { 376 return reinterpretIntptrToDouble(rawValue(v) - DoubleEncodeOffset); 377 } 378 #endif 379 309 380 static ALWAYS_INLINE int32_t intValue(JSValuePtr v) 310 381 { … … 340 411 ALWAYS_INLINE JSValuePtr JSImmediate::impossibleValue() { return makeValue(0x4); } 341 412 413 #if USE(ALTERNATE_JSIMMEDIATE) 414 inline bool doubleToBoolean(double value) 415 { 416 return value < 0.0 || value > 0.0; 417 } 418 342 419 ALWAYS_INLINE bool JSImmediate::toBoolean(JSValuePtr v) 343 420 { 344 421 ASSERT(isImmediate(v)); 345 intptr_t bits = rawValue(v); 346 return (bits & TagTypeInteger) 347 ? bits != TagTypeInteger // !0 ints 348 : bits == (FullTagTypeBool | ExtendedPayloadBitBoolValue); // bool true 349 } 422 return isNumber(v) ? isIntegerNumber(v) ? v != zeroImmediate() 423 : doubleToBoolean(doubleValue(v)) : v == trueImmediate(); 424 } 425 #else 426 ALWAYS_INLINE bool JSImmediate::toBoolean(JSValuePtr v) 427 { 428 ASSERT(isImmediate(v)); 429 return isIntegerNumber(v) ? v != zeroImmediate() : v == trueImmediate(); 430 } 431 #endif 350 432 351 433 ALWAYS_INLINE uint32_t JSImmediate::getTruncatedUInt32(JSValuePtr v) 352 434 { 353 ASSERT(isNumber(v)); 435 // FIXME: should probably be asserting isPositiveIntegerNumber here. 436 ASSERT(isIntegerNumber(v)); 354 437 return intValue(v); 355 438 } 356 439 440 #if USE(ALTERNATE_JSIMMEDIATE) 441 template<typename T> 442 inline JSValuePtr JSImmediate::fromNumberOutsideIntegerRange(T value) 443 { 444 return makeDouble(static_cast<double>(value)); 445 } 446 #else 447 template<typename T> 448 inline JSValuePtr JSImmediate::fromNumberOutsideIntegerRange(T) 449 { 450 return noValue(); 451 } 452 #endif 453 357 454 ALWAYS_INLINE JSValuePtr JSImmediate::from(char i) 358 455 { … … 382 479 ALWAYS_INLINE JSValuePtr JSImmediate::from(int i) 383 480 { 481 #if !USE(ALTERNATE_JSIMMEDIATE) 384 482 if ((i < minImmediateInt) | (i > maxImmediateInt)) 385 return noValue(); 483 return fromNumberOutsideIntegerRange(i); 484 #endif 386 485 return makeInt(i); 387 486 } … … 390 489 { 391 490 if (i > maxImmediateUInt) 392 return noValue();491 return fromNumberOutsideIntegerRange(i); 393 492 return makeInt(i); 394 493 } … … 397 496 { 398 497 if ((i < minImmediateInt) | (i > maxImmediateInt)) 399 return noValue();498 return fromNumberOutsideIntegerRange(i); 400 499 return makeInt(i); 401 500 } … … 404 503 { 405 504 if (i > maxImmediateUInt) 406 return noValue();505 return fromNumberOutsideIntegerRange(i); 407 506 return makeInt(i); 408 507 } … … 418 517 { 419 518 if (i > maxImmediateUInt) 420 return noValue();519 return fromNumberOutsideIntegerRange(i); 421 520 return makeInt(static_cast<intptr_t>(i)); 422 521 } … … 425 524 { 426 525 const int intVal = static_cast<int>(d); 427 428 if ((intVal < minImmediateInt) | (intVal > maxImmediateInt))429 return noValue();430 526 431 527 // Check for data loss from conversion to int. 432 528 if (intVal != d || (!intVal && signbit(d))) 433 return noValue();434 435 return makeInt(intVal);529 return fromNumberOutsideIntegerRange(d); 530 531 return from(intVal); 436 532 } 437 533 438 534 ALWAYS_INLINE int32_t JSImmediate::getTruncatedInt32(JSValuePtr v) 439 535 { 440 ASSERT(is Number(v));536 ASSERT(isIntegerNumber(v)); 441 537 return intValue(v); 442 538 } … … 445 541 { 446 542 ASSERT(isImmediate(v)); 447 int i; 448 if (isNumber(v)) 449 i = intValue(v); 450 else if (rawValue(v) == FullTagTypeUndefined) 543 544 if (isIntegerNumber(v)) 545 return intValue(v); 546 547 #if USE(ALTERNATE_JSIMMEDIATE) 548 if (isNumber(v)) { 549 ASSERT(isDoubleNumber(v)); 550 return doubleValue(v); 551 } 552 #else 553 ASSERT(!isNumber(v)); 554 #endif 555 556 if (rawValue(v) == FullTagTypeUndefined) 451 557 return nonInlineNaN(); 452 else 453 i = rawValue(v) >> ExtendedPayloadShift;454 return i;558 559 ASSERT(JSImmediate::isBoolean(v) || (v == JSImmediate::nullImmediate())); 560 return rawValue(v) >> ExtendedPayloadShift; 455 561 } 456 562 … … 458 564 { 459 565 i = uintValue(v); 460 return isPositive Number(v);566 return isPositiveIntegerNumber(v); 461 567 } 462 568 … … 464 570 { 465 571 i = intValue(v); 466 return is Number(v);572 return isIntegerNumber(v); 467 573 } 468 574 … … 601 707 inline bool JSValuePtr::isInt32Fast() const 602 708 { 603 return JSImmediate::is Number(asValue());709 return JSImmediate::isIntegerNumber(asValue()); 604 710 } 605 711 … … 612 718 inline bool JSValuePtr::isUInt32Fast() const 613 719 { 614 return JSImmediate::isPositive Number(asValue());720 return JSImmediate::isPositiveIntegerNumber(asValue()); 615 721 } 616 722 … … 628 734 inline bool JSValuePtr::areBothInt32Fast(JSValuePtr v1, JSValuePtr v2) 629 735 { 630 return JSImmediate::areBothImmediate Numbers(v1, v2);736 return JSImmediate::areBothImmediateIntegerNumbers(v1, v2); 631 737 } 632 738 … … 635 741 static ALWAYS_INLINE bool canDoFastBitwiseOperations(JSValuePtr v1, JSValuePtr v2) 636 742 { 637 return JSImmediate::areBothImmediate Numbers(v1, v2);743 return JSImmediate::areBothImmediateIntegerNumbers(v1, v2); 638 744 } 639 745 … … 659 765 { 660 766 ASSERT(canDoFastBitwiseOperations(v1, v2)); 661 return JSImmediate::makeValue((JSImmediate::rawValue(v1) ^ JSImmediate::rawValue(v2)) | JSImmediate::TagType Integer);767 return JSImmediate::makeValue((JSImmediate::rawValue(v1) ^ JSImmediate::rawValue(v2)) | JSImmediate::TagTypeNumber); 662 768 } 663 769 … … 670 776 static ALWAYS_INLINE bool canDoFastRshift(JSValuePtr v1, JSValuePtr v2) 671 777 { 672 return JSImmediate::areBothImmediate Numbers(v1, v2);778 return JSImmediate::areBothImmediateIntegerNumbers(v1, v2); 673 779 } 674 780 675 781 static ALWAYS_INLINE bool canDoFastUrshift(JSValuePtr v1, JSValuePtr v2) 676 782 { 677 return JSImmediate::areBothImmediate Numbers(v1, v2) && !JSImmediate::isNegative(v1);783 return JSImmediate::areBothImmediateIntegerNumbers(v1, v2) && !(JSImmediate::rawValue(v1) & JSImmediate::signBit); 678 784 } 679 785 … … 682 788 ASSERT(canDoFastRshift(val, shift) || canDoFastUrshift(val, shift)); 683 789 #if USE(ALTERNATE_JSIMMEDIATE) 684 return JSImmediate::makeValue(static_cast<intptr_t>(static_cast<uint32_t>(static_cast<int32_t>(JSImmediate::rawValue(val)) >> ((JSImmediate::rawValue(shift) >> JSImmediate::IntegerPayloadShift) & 0x1f))) | JSImmediate::TagType Integer);685 #else 686 return JSImmediate::makeValue((JSImmediate::rawValue(val) >> ((JSImmediate::rawValue(shift) >> JSImmediate::IntegerPayloadShift) & 0x1f)) | JSImmediate::TagType Integer);790 return JSImmediate::makeValue(static_cast<intptr_t>(static_cast<uint32_t>(static_cast<int32_t>(JSImmediate::rawValue(val)) >> ((JSImmediate::rawValue(shift) >> JSImmediate::IntegerPayloadShift) & 0x1f))) | JSImmediate::TagTypeNumber); 791 #else 792 return JSImmediate::makeValue((JSImmediate::rawValue(val) >> ((JSImmediate::rawValue(shift) >> JSImmediate::IntegerPayloadShift) & 0x1f)) | JSImmediate::TagTypeNumber); 687 793 #endif 688 794 } … … 692 798 // Number is non-negative and an operation involving two of these can't overflow. 693 799 // Checking for allowed negative numbers takes more time than it's worth on SunSpider. 694 return (JSImmediate::rawValue(v) & (JSImmediate::TagType Integer + (JSImmediate::signBit | (JSImmediate::signBit >> 1)))) == JSImmediate::TagTypeInteger;800 return (JSImmediate::rawValue(v) & (JSImmediate::TagTypeNumber + (JSImmediate::signBit | (JSImmediate::signBit >> 1)))) == JSImmediate::TagTypeNumber; 695 801 } 696 802 … … 705 811 { 706 812 ASSERT(canDoFastAdditiveOperations(v1, v2)); 707 return JSImmediate::makeValue(JSImmediate::rawValue(v1) + JSImmediate::rawValue(v2) - JSImmediate::TagType Integer);813 return JSImmediate::makeValue(JSImmediate::rawValue(v1) + JSImmediate::rawValue(v2) - JSImmediate::TagTypeNumber); 708 814 } 709 815 … … 711 817 { 712 818 ASSERT(canDoFastAdditiveOperations(v1, v2)); 713 return JSImmediate::makeValue(JSImmediate::rawValue(v1) - JSImmediate::rawValue(v2) + JSImmediate::TagType Integer);819 return JSImmediate::makeValue(JSImmediate::rawValue(v1) - JSImmediate::rawValue(v2) + JSImmediate::TagTypeNumber); 714 820 } 715 821
Note:
See TracChangeset
for help on using the changeset viewer.