1 /* 2 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. 3 * Copyright (C) 2006 Alexey Proskuryakov (ap (at) webkit.org) 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 JSImmediate_h 23 #define JSImmediate_h 24 25 #include <wtf/Platform.h> 26 27 #if !USE(JSVALUE32_64) 28 29 #include <wtf/Assertions.h> 30 #include <wtf/AlwaysInline.h> 31 #include <wtf/MathExtras.h> 32 #include <wtf/StdLibExtras.h> 33 #include "JSValue.h" 34 #include <limits> 35 #include <limits.h> 36 #include <stdarg.h> 37 #include <stdint.h> 38 #include <stdlib.h> 39 40 namespace JSC { 41 42 class ExecState; 43 class JSCell; 44 class JSFastMath; 45 class JSGlobalData; 46 class JSObject; 47 class UString; 48 49 #if USE(JSVALUE64) 50 inline intptr_t reinterpretDoubleToIntptr(double value) 51 { 52 return WTF::bitwise_cast<intptr_t>(value); 53 } 54 55 inline double reinterpretIntptrToDouble(intptr_t value) 56 { 57 return WTF::bitwise_cast<double>(value); 58 } 59 #endif 60 61 /* 62 * A JSValue* is either a pointer to a cell (a heap-allocated object) or an immediate (a type-tagged 63 * value masquerading as a pointer). The low two bits in a JSValue* are available for type tagging 64 * because allocator alignment guarantees they will be 00 in cell pointers. 65 * 66 * For example, on a 32 bit system: 67 * 68 * JSCell*: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 00 69 * [ high 30 bits: pointer address ] [ low 2 bits -- always 0 ] 70 * JSImmediate: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX TT 71 * [ high 30 bits: 'payload' ] [ low 2 bits -- tag ] 72 * 73 * Where the bottom two bits are non-zero they either indicate that the immediate is a 31 bit signed 74 * integer, or they mark the value as being an immediate of a type other than integer, with a secondary 75 * tag used to indicate the exact type. 76 * 77 * Where the lowest bit is set (TT is equal to 01 or 11) the high 31 bits form a 31 bit signed int value. 78 * Where TT is equal to 10 this indicates this is a type of immediate other than an integer, and the next 79 * two bits will form an extended tag. 80 * 81 * 31 bit signed int: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX X1 82 * [ high 30 bits of the value ] [ high bit part of value ] 83 * Other: YYYYYYYYYYYYYYYYYYYYYYYYYYYY ZZ 10 84 * [ extended 'payload' ] [ extended tag ] [ tag 'other' ] 85 * 86 * Where the first bit of the extended tag is set this flags the value as being a boolean, and the following 87 * bit would flag the value as undefined. If neither bits are set, the value is null. 88 * 89 * Other: YYYYYYYYYYYYYYYYYYYYYYYYYYYY UB 10 90 * [ extended 'payload' ] [ undefined | bool ] [ tag 'other' ] 91 * 92 * For boolean value the lowest bit in the payload holds the value of the bool, all remaining bits are zero. 93 * For undefined or null immediates the payload is zero. 94 * 95 * Boolean: 000000000000000000000000000V 01 10 96 * [ boolean value ] [ bool ] [ tag 'other' ] 97 * Undefined: 0000000000000000000000000000 10 10 98 * [ zero ] [ undefined ] [ tag 'other' ] 99 * Null: 0000000000000000000000000000 00 10 100 * [ zero ] [ zero ] [ tag 'other' ] 101 */ 102 103 /* 104 * On 64-bit platforms, we support an alternative encoding form for immediates, if 105 * USE(JSVALUE64) is defined. When this format is used, double precision 106 * floating point values may also be encoded as JSImmediates. 107 * 108 * The encoding makes use of unused NaN space in the IEEE754 representation. Any value 109 * with the top 13 bits set represents a QNaN (with the sign bit set). QNaN values 110 * can encode a 51-bit payload. Hardware produced and C-library payloads typically 111 * have a payload of zero. We assume that non-zero payloads are available to encode 112 * pointer and integer values. Since any 64-bit bit pattern where the top 15 bits are 113 * all set represents a NaN with a non-zero payload, we can use this space in the NaN 114 * ranges to encode other values (however there are also other ranges of NaN space that 115 * could have been selected). This range of NaN space is represented by 64-bit numbers 116 * begining with the 16-bit hex patterns 0xFFFE and 0xFFFF - we rely on the fact that no 117 * valid double-precision numbers will begin fall in these ranges. 118 * 119 * The scheme we have implemented encodes double precision values by adding 2^48 to the 120 * 64-bit integer representation of the number. After this manipulation, no encoded 121 * double-precision value will begin with the pattern 0x0000 or 0xFFFF. 122 * 123 * The top 16-bits denote the type of the encoded JSImmediate: 124 * 125 * Pointer: 0000:PPPP:PPPP:PPPP 126 * 0001:****:****:**** 127 * Double:{ ... 128 * FFFE:****:****:**** 129 * Integer: FFFF:0000:IIII:IIII 130 * 131 * 32-bit signed integers are marked with the 16-bit tag 0xFFFF. The tag 0x0000 132 * denotes a pointer, or another form of tagged immediate. Boolean, null and undefined 133 * values are encoded in the same manner as the default format. 134 */ 135 136 class JSImmediate { 137 private: 138 friend class JIT; 139 friend class JSValue; 140 friend class JSFastMath; 141 friend JSValue jsNumber(ExecState* exec, double d); 142 friend JSValue jsNumber(ExecState*, char i); 143 friend JSValue jsNumber(ExecState*, unsigned char i); 144 friend JSValue jsNumber(ExecState*, short i); 145 friend JSValue jsNumber(ExecState*, unsigned short i); 146 friend JSValue jsNumber(ExecState* exec, int i); 147 friend JSValue jsNumber(ExecState* exec, unsigned i); 148 friend JSValue jsNumber(ExecState* exec, long i); 149 friend JSValue jsNumber(ExecState* exec, unsigned long i); 150 friend JSValue jsNumber(ExecState* exec, long long i); 151 friend JSValue jsNumber(ExecState* exec, unsigned long long i); 152 friend JSValue jsNumber(JSGlobalData* globalData, double d); 153 friend JSValue jsNumber(JSGlobalData* globalData, short i); 154 friend JSValue jsNumber(JSGlobalData* globalData, unsigned short i); 155 friend JSValue jsNumber(JSGlobalData* globalData, int i); 156 friend JSValue jsNumber(JSGlobalData* globalData, unsigned i); 157 friend JSValue jsNumber(JSGlobalData* globalData, long i); 158 friend JSValue jsNumber(JSGlobalData* globalData, unsigned long i); 159 friend JSValue jsNumber(JSGlobalData* globalData, long long i); 160 friend JSValue jsNumber(JSGlobalData* globalData, unsigned long long i); 161 162 #if USE(JSVALUE64) 163 // If all bits in the mask are set, this indicates an integer number, 164 // if any but not all are set this value is a double precision number. 165 static const intptr_t TagTypeNumber = 0xffff000000000000ll; 166 // This value is 2^48, used to encode doubles such that the encoded value will begin 167 // with a 16-bit pattern within the range 0x0001..0xFFFE. 168 static const intptr_t DoubleEncodeOffset = 0x1000000000000ll; 169 #else 170 static const intptr_t TagTypeNumber = 0x1; // bottom bit set indicates integer, this dominates the following bit 171 #endif 172 static const intptr_t TagBitTypeOther = 0x2; // second bit set indicates immediate other than an integer 173 static const intptr_t TagMask = TagTypeNumber | TagBitTypeOther; 174 175 static const intptr_t ExtendedTagMask = 0xC; // extended tag holds a further two bits 176 static const intptr_t ExtendedTagBitBool = 0x4; 177 static const intptr_t ExtendedTagBitUndefined = 0x8; 178 179 static const intptr_t FullTagTypeMask = TagMask | ExtendedTagMask; 180 static const intptr_t FullTagTypeBool = TagBitTypeOther | ExtendedTagBitBool; 181 static const intptr_t FullTagTypeUndefined = TagBitTypeOther | ExtendedTagBitUndefined; 182 static const intptr_t FullTagTypeNull = TagBitTypeOther; 183 184 #if USE(JSVALUE64) 185 static const int32_t IntegerPayloadShift = 0; 186 #else 187 static const int32_t IntegerPayloadShift = 1; 188 #endif 189 static const int32_t ExtendedPayloadShift = 4; 190 191 static const intptr_t ExtendedPayloadBitBoolValue = 1 << ExtendedPayloadShift; 192 193 static const int32_t signBit = 0x80000000; 194 195 static ALWAYS_INLINE bool isImmediate(JSValue v) 196 { 197 return rawValue(v) & TagMask; 198 } 199 200 static ALWAYS_INLINE bool isNumber(JSValue v) 201 { 202 return rawValue(v) & TagTypeNumber; 203 } 204 205 static ALWAYS_INLINE bool isIntegerNumber(JSValue v) 206 { 207 #if USE(JSVALUE64) 208 return (rawValue(v) & TagTypeNumber) == TagTypeNumber; 209 #else 210 return isNumber(v); 211 #endif 212 } 213 214 #if USE(JSVALUE64) 215 static ALWAYS_INLINE bool isDouble(JSValue v) 216 { 217 return isNumber(v) && !isIntegerNumber(v); 218 } 219 #endif 220 221 static ALWAYS_INLINE bool isPositiveIntegerNumber(JSValue v) 222 { 223 // A single mask to check for the sign bit and the number tag all at once. 224 return (rawValue(v) & (signBit | TagTypeNumber)) == TagTypeNumber; 225 } 226 227 static ALWAYS_INLINE bool isBoolean(JSValue v) 228 { 229 return (rawValue(v) & FullTagTypeMask) == FullTagTypeBool; 230 } 231 232 static ALWAYS_INLINE bool isUndefinedOrNull(JSValue v) 233 { 234 // Undefined and null share the same value, bar the 'undefined' bit in the extended tag. 235 return (rawValue(v) & ~ExtendedTagBitUndefined) == FullTagTypeNull; 236 } 237 238 static JSValue from(char); 239 static JSValue from(signed char); 240 static JSValue from(unsigned char); 241 static JSValue from(short); 242 static JSValue from(unsigned short); 243 static JSValue from(int); 244 static JSValue from(unsigned); 245 static JSValue from(long); 246 static JSValue from(unsigned long); 247 static JSValue from(long long); 248 static JSValue from(unsigned long long); 249 static JSValue from(double); 250 251 static ALWAYS_INLINE bool isEitherImmediate(JSValue v1, JSValue v2) 252 { 253 return (rawValue(v1) | rawValue(v2)) & TagMask; 254 } 255 256 static ALWAYS_INLINE bool areBothImmediate(JSValue v1, JSValue v2) 257 { 258 return isImmediate(v1) & isImmediate(v2); 259 } 260 261 static ALWAYS_INLINE bool areBothImmediateIntegerNumbers(JSValue v1, JSValue v2) 262 { 263 #if USE(JSVALUE64) 264 return (rawValue(v1) & rawValue(v2) & TagTypeNumber) == TagTypeNumber; 265 #else 266 return rawValue(v1) & rawValue(v2) & TagTypeNumber; 267 #endif 268 } 269 270 static double toDouble(JSValue); 271 static bool toBoolean(JSValue); 272 273 static bool getUInt32(JSValue, uint32_t&); 274 static bool getTruncatedInt32(JSValue, int32_t&); 275 static bool getTruncatedUInt32(JSValue, uint32_t&); 276 277 static int32_t getTruncatedInt32(JSValue); 278 static uint32_t getTruncatedUInt32(JSValue); 279 280 static JSValue trueImmediate(); 281 static JSValue falseImmediate(); 282 static JSValue undefinedImmediate(); 283 static JSValue nullImmediate(); 284 static JSValue zeroImmediate(); 285 static JSValue oneImmediate(); 286 287 private: 288 #if USE(JSVALUE64) 289 static const int minImmediateInt = ((-INT_MAX) - 1); 290 static const int maxImmediateInt = INT_MAX; 291 #else 292 static const int minImmediateInt = ((-INT_MAX) - 1) >> IntegerPayloadShift; 293 static const int maxImmediateInt = INT_MAX >> IntegerPayloadShift; 294 #endif 295 static const unsigned maxImmediateUInt = maxImmediateInt; 296 297 static ALWAYS_INLINE JSValue makeValue(intptr_t integer) 298 { 299 return JSValue::makeImmediate(integer); 300 } 301 302 // With USE(JSVALUE64) we want the argument to be zero extended, so the 303 // integer doesn't interfere with the tag bits in the upper word. In the default encoding, 304 // if intptr_t id larger then int32_t we sign extend the value through the upper word. 305 #if USE(JSVALUE64) 306 static ALWAYS_INLINE JSValue makeInt(uint32_t value) 307 #else 308 static ALWAYS_INLINE JSValue makeInt(int32_t value) 309 #endif 310 { 311 return makeValue((static_cast<intptr_t>(value) << IntegerPayloadShift) | TagTypeNumber); 312 } 313 314 #if USE(JSVALUE64) 315 static ALWAYS_INLINE JSValue makeDouble(double value) 316 { 317 return makeValue(reinterpretDoubleToIntptr(value) + DoubleEncodeOffset); 318 } 319 #endif 320 321 static ALWAYS_INLINE JSValue makeBool(bool b) 322 { 323 return makeValue((static_cast<intptr_t>(b) << ExtendedPayloadShift) | FullTagTypeBool); 324 } 325 326 static ALWAYS_INLINE JSValue makeUndefined() 327 { 328 return makeValue(FullTagTypeUndefined); 329 } 330 331 static ALWAYS_INLINE JSValue makeNull() 332 { 333 return makeValue(FullTagTypeNull); 334 } 335 336 template<typename T> 337 static JSValue fromNumberOutsideIntegerRange(T); 338 339 #if USE(JSVALUE64) 340 static ALWAYS_INLINE double doubleValue(JSValue v) 341 { 342 return reinterpretIntptrToDouble(rawValue(v) - DoubleEncodeOffset); 343 } 344 #endif 345 346 static ALWAYS_INLINE int32_t intValue(JSValue v) 347 { 348 return static_cast<int32_t>(rawValue(v) >> IntegerPayloadShift); 349 } 350 351 static ALWAYS_INLINE uint32_t uintValue(JSValue v) 352 { 353 return static_cast<uint32_t>(rawValue(v) >> IntegerPayloadShift); 354 } 355 356 static ALWAYS_INLINE bool boolValue(JSValue v) 357 { 358 return rawValue(v) & ExtendedPayloadBitBoolValue; 359 } 360 361 static ALWAYS_INLINE intptr_t rawValue(JSValue v) 362 { 363 return v.immediateValue(); 364 } 365 }; 366 367 ALWAYS_INLINE JSValue JSImmediate::trueImmediate() { return makeBool(true); } 368 ALWAYS_INLINE JSValue JSImmediate::falseImmediate() { return makeBool(false); } 369 ALWAYS_INLINE JSValue JSImmediate::undefinedImmediate() { return makeUndefined(); } 370 ALWAYS_INLINE JSValue JSImmediate::nullImmediate() { return makeNull(); } 371 ALWAYS_INLINE JSValue JSImmediate::zeroImmediate() { return makeInt(0); } 372 ALWAYS_INLINE JSValue JSImmediate::oneImmediate() { return makeInt(1); } 373 374 #if USE(JSVALUE64) 375 inline bool doubleToBoolean(double value) 376 { 377 return value < 0.0 || value > 0.0; 378 } 379 380 ALWAYS_INLINE bool JSImmediate::toBoolean(JSValue v) 381 { 382 ASSERT(isImmediate(v)); 383 return isNumber(v) ? isIntegerNumber(v) ? v != zeroImmediate() 384 : doubleToBoolean(doubleValue(v)) : v == trueImmediate(); 385 } 386 #else 387 ALWAYS_INLINE bool JSImmediate::toBoolean(JSValue v) 388 { 389 ASSERT(isImmediate(v)); 390 return isIntegerNumber(v) ? v != zeroImmediate() : v == trueImmediate(); 391 } 392 #endif 393 394 ALWAYS_INLINE uint32_t JSImmediate::getTruncatedUInt32(JSValue v) 395 { 396 // FIXME: should probably be asserting isPositiveIntegerNumber here. 397 ASSERT(isIntegerNumber(v)); 398 return intValue(v); 399 } 400 401 #if USE(JSVALUE64) 402 template<typename T> 403 inline JSValue JSImmediate::fromNumberOutsideIntegerRange(T value) 404 { 405 return makeDouble(static_cast<double>(value)); 406 } 407 #else 408 template<typename T> 409 inline JSValue JSImmediate::fromNumberOutsideIntegerRange(T) 410 { 411 return JSValue(); 412 } 413 #endif 414 415 ALWAYS_INLINE JSValue JSImmediate::from(char i) 416 { 417 return makeInt(i); 418 } 419 420 ALWAYS_INLINE JSValue JSImmediate::from(signed char i) 421 { 422 return makeInt(i); 423 } 424 425 ALWAYS_INLINE JSValue JSImmediate::from(unsigned char i) 426 { 427 return makeInt(i); 428 } 429 430 ALWAYS_INLINE JSValue JSImmediate::from(short i) 431 { 432 return makeInt(i); 433 } 434 435 ALWAYS_INLINE JSValue JSImmediate::from(unsigned short i) 436 { 437 return makeInt(i); 438 } 439 440 ALWAYS_INLINE JSValue JSImmediate::from(int i) 441 { 442 #if !USE(JSVALUE64) 443 if ((i < minImmediateInt) | (i > maxImmediateInt)) 444 return fromNumberOutsideIntegerRange(i); 445 #endif 446 return makeInt(i); 447 } 448 449 ALWAYS_INLINE JSValue JSImmediate::from(unsigned i) 450 { 451 if (i > maxImmediateUInt) 452 return fromNumberOutsideIntegerRange(i); 453 return makeInt(i); 454 } 455 456 ALWAYS_INLINE JSValue JSImmediate::from(long i) 457 { 458 if ((i < minImmediateInt) | (i > maxImmediateInt)) 459 return fromNumberOutsideIntegerRange(i); 460 return makeInt(i); 461 } 462 463 ALWAYS_INLINE JSValue JSImmediate::from(unsigned long i) 464 { 465 if (i > maxImmediateUInt) 466 return fromNumberOutsideIntegerRange(i); 467 return makeInt(i); 468 } 469 470 ALWAYS_INLINE JSValue JSImmediate::from(long long i) 471 { 472 if ((i < minImmediateInt) | (i > maxImmediateInt)) 473 return JSValue(); 474 return makeInt(static_cast<intptr_t>(i)); 475 } 476 477 ALWAYS_INLINE JSValue JSImmediate::from(unsigned long long i) 478 { 479 if (i > maxImmediateUInt) 480 return fromNumberOutsideIntegerRange(i); 481 return makeInt(static_cast<intptr_t>(i)); 482 } 483 484 ALWAYS_INLINE JSValue JSImmediate::from(double d) 485 { 486 const int intVal = static_cast<int>(d); 487 488 // Check for data loss from conversion to int. 489 if (intVal != d || (!intVal && signbit(d))) 490 return fromNumberOutsideIntegerRange(d); 491 492 return from(intVal); 493 } 494 495 ALWAYS_INLINE int32_t JSImmediate::getTruncatedInt32(JSValue v) 496 { 497 ASSERT(isIntegerNumber(v)); 498 return intValue(v); 499 } 500 501 ALWAYS_INLINE double JSImmediate::toDouble(JSValue v) 502 { 503 ASSERT(isImmediate(v)); 504 505 if (isIntegerNumber(v)) 506 return intValue(v); 507 508 #if USE(JSVALUE64) 509 if (isNumber(v)) { 510 ASSERT(isDouble(v)); 511 return doubleValue(v); 512 } 513 #else 514 ASSERT(!isNumber(v)); 515 #endif 516 517 if (rawValue(v) == FullTagTypeUndefined) 518 return nonInlineNaN(); 519 520 ASSERT(JSImmediate::isBoolean(v) || (v == JSImmediate::nullImmediate())); 521 return rawValue(v) >> ExtendedPayloadShift; 522 } 523 524 ALWAYS_INLINE bool JSImmediate::getUInt32(JSValue v, uint32_t& i) 525 { 526 i = uintValue(v); 527 return isPositiveIntegerNumber(v); 528 } 529 530 ALWAYS_INLINE bool JSImmediate::getTruncatedInt32(JSValue v, int32_t& i) 531 { 532 i = intValue(v); 533 return isIntegerNumber(v); 534 } 535 536 ALWAYS_INLINE bool JSImmediate::getTruncatedUInt32(JSValue v, uint32_t& i) 537 { 538 return getUInt32(v, i); 539 } 540 541 inline JSValue::JSValue(JSNullTag) 542 { 543 *this = JSImmediate::nullImmediate(); 544 } 545 546 inline JSValue::JSValue(JSUndefinedTag) 547 { 548 *this = JSImmediate::undefinedImmediate(); 549 } 550 551 inline JSValue::JSValue(JSTrueTag) 552 { 553 *this = JSImmediate::trueImmediate(); 554 } 555 556 inline JSValue::JSValue(JSFalseTag) 557 { 558 *this = JSImmediate::falseImmediate(); 559 } 560 561 inline bool JSValue::isUndefinedOrNull() const 562 { 563 return JSImmediate::isUndefinedOrNull(asValue()); 564 } 565 566 inline bool JSValue::isBoolean() const 567 { 568 return JSImmediate::isBoolean(asValue()); 569 } 570 571 inline bool JSValue::isTrue() const 572 { 573 return asValue() == JSImmediate::trueImmediate(); 574 } 575 576 inline bool JSValue::isFalse() const 577 { 578 return asValue() == JSImmediate::falseImmediate(); 579 } 580 581 inline bool JSValue::getBoolean(bool& v) const 582 { 583 if (JSImmediate::isBoolean(asValue())) { 584 v = JSImmediate::toBoolean(asValue()); 585 return true; 586 } 587 588 return false; 589 } 590 591 inline bool JSValue::getBoolean() const 592 { 593 return asValue() == jsBoolean(true); 594 } 595 596 inline bool JSValue::isCell() const 597 { 598 return !JSImmediate::isImmediate(asValue()); 599 } 600 601 inline bool JSValue::isInt32() const 602 { 603 return JSImmediate::isIntegerNumber(asValue()); 604 } 605 606 inline int32_t JSValue::asInt32() const 607 { 608 ASSERT(isInt32()); 609 return JSImmediate::getTruncatedInt32(asValue()); 610 } 611 612 inline bool JSValue::isUInt32() const 613 { 614 return JSImmediate::isPositiveIntegerNumber(asValue()); 615 } 616 617 inline uint32_t JSValue::asUInt32() const 618 { 619 ASSERT(isUInt32()); 620 return JSImmediate::getTruncatedUInt32(asValue()); 621 } 622 623 class JSFastMath { 624 public: 625 static ALWAYS_INLINE bool canDoFastBitwiseOperations(JSValue v1, JSValue v2) 626 { 627 return JSImmediate::areBothImmediateIntegerNumbers(v1, v2); 628 } 629 630 static ALWAYS_INLINE JSValue equal(JSValue v1, JSValue v2) 631 { 632 ASSERT(canDoFastBitwiseOperations(v1, v2)); 633 return jsBoolean(v1 == v2); 634 } 635 636 static ALWAYS_INLINE JSValue notEqual(JSValue v1, JSValue v2) 637 { 638 ASSERT(canDoFastBitwiseOperations(v1, v2)); 639 return jsBoolean(v1 != v2); 640 } 641 642 static ALWAYS_INLINE JSValue andImmediateNumbers(JSValue v1, JSValue v2) 643 { 644 ASSERT(canDoFastBitwiseOperations(v1, v2)); 645 return JSImmediate::makeValue(JSImmediate::rawValue(v1) & JSImmediate::rawValue(v2)); 646 } 647 648 static ALWAYS_INLINE JSValue xorImmediateNumbers(JSValue v1, JSValue v2) 649 { 650 ASSERT(canDoFastBitwiseOperations(v1, v2)); 651 return JSImmediate::makeValue((JSImmediate::rawValue(v1) ^ JSImmediate::rawValue(v2)) | JSImmediate::TagTypeNumber); 652 } 653 654 static ALWAYS_INLINE JSValue orImmediateNumbers(JSValue v1, JSValue v2) 655 { 656 ASSERT(canDoFastBitwiseOperations(v1, v2)); 657 return JSImmediate::makeValue(JSImmediate::rawValue(v1) | JSImmediate::rawValue(v2)); 658 } 659 660 static ALWAYS_INLINE bool canDoFastRshift(JSValue v1, JSValue v2) 661 { 662 return JSImmediate::areBothImmediateIntegerNumbers(v1, v2); 663 } 664 665 static ALWAYS_INLINE bool canDoFastUrshift(JSValue v1, JSValue v2) 666 { 667 return JSImmediate::areBothImmediateIntegerNumbers(v1, v2) && !(JSImmediate::rawValue(v1) & JSImmediate::signBit); 668 } 669 670 static ALWAYS_INLINE JSValue rightShiftImmediateNumbers(JSValue val, JSValue shift) 671 { 672 ASSERT(canDoFastRshift(val, shift) || canDoFastUrshift(val, shift)); 673 #if USE(JSVALUE64) 674 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); 675 #else 676 return JSImmediate::makeValue((JSImmediate::rawValue(val) >> ((JSImmediate::rawValue(shift) >> JSImmediate::IntegerPayloadShift) & 0x1f)) | JSImmediate::TagTypeNumber); 677 #endif 678 } 679 680 static ALWAYS_INLINE bool canDoFastAdditiveOperations(JSValue v) 681 { 682 // Number is non-negative and an operation involving two of these can't overflow. 683 // Checking for allowed negative numbers takes more time than it's worth on SunSpider. 684 return (JSImmediate::rawValue(v) & (JSImmediate::TagTypeNumber + (JSImmediate::signBit | (JSImmediate::signBit >> 1)))) == JSImmediate::TagTypeNumber; 685 } 686 687 static ALWAYS_INLINE bool canDoFastAdditiveOperations(JSValue v1, JSValue v2) 688 { 689 // Number is non-negative and an operation involving two of these can't overflow. 690 // Checking for allowed negative numbers takes more time than it's worth on SunSpider. 691 return canDoFastAdditiveOperations(v1) && canDoFastAdditiveOperations(v2); 692 } 693 694 static ALWAYS_INLINE JSValue addImmediateNumbers(JSValue v1, JSValue v2) 695 { 696 ASSERT(canDoFastAdditiveOperations(v1, v2)); 697 return JSImmediate::makeValue(JSImmediate::rawValue(v1) + JSImmediate::rawValue(v2) - JSImmediate::TagTypeNumber); 698 } 699 700 static ALWAYS_INLINE JSValue subImmediateNumbers(JSValue v1, JSValue v2) 701 { 702 ASSERT(canDoFastAdditiveOperations(v1, v2)); 703 return JSImmediate::makeValue(JSImmediate::rawValue(v1) - JSImmediate::rawValue(v2) + JSImmediate::TagTypeNumber); 704 } 705 706 static ALWAYS_INLINE JSValue incImmediateNumber(JSValue v) 707 { 708 ASSERT(canDoFastAdditiveOperations(v)); 709 return JSImmediate::makeValue(JSImmediate::rawValue(v) + (1 << JSImmediate::IntegerPayloadShift)); 710 } 711 712 static ALWAYS_INLINE JSValue decImmediateNumber(JSValue v) 713 { 714 ASSERT(canDoFastAdditiveOperations(v)); 715 return JSImmediate::makeValue(JSImmediate::rawValue(v) - (1 << JSImmediate::IntegerPayloadShift)); 716 } 717 }; 718 719 } // namespace JSC 720 721 #endif // !USE(JSVALUE32_64) 722 723 #endif // JSImmediate_h 724