1 /* 2 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. 3 * Copyright (C) 2006 Alexey Proskuryakov (ap@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/Assertions.h> 26 #include <wtf/AlwaysInline.h> 27 #include <wtf/MathExtras.h> 28 #include <wtf/StdLibExtras.h> 29 #include "JSValue.h" 30 #include <limits> 31 #include <limits.h> 32 #include <stdarg.h> 33 #include <stdint.h> 34 #include <stdlib.h> 35 36 namespace JSC { 37 38 class ExecState; 39 class JSCell; 40 class JSFastMath; 41 class JSGlobalData; 42 class JSObject; 43 class UString; 44 45 JSValuePtr js0(); 46 JSValuePtr jsNull(); 47 JSValuePtr jsBoolean(bool b); 48 JSValuePtr jsUndefined(); 49 JSValuePtr jsImpossibleValue(); 50 JSValuePtr jsNumber(ExecState* exec, double d); 51 JSValuePtr jsNumber(ExecState*, char i); 52 JSValuePtr jsNumber(ExecState*, unsigned char i); 53 JSValuePtr jsNumber(ExecState*, short i); 54 JSValuePtr jsNumber(ExecState*, unsigned short i); 55 JSValuePtr jsNumber(ExecState* exec, int i); 56 JSValuePtr jsNumber(ExecState* exec, unsigned i); 57 JSValuePtr jsNumber(ExecState* exec, long i); 58 JSValuePtr jsNumber(ExecState* exec, unsigned long i); 59 JSValuePtr jsNumber(ExecState* exec, long long i); 60 JSValuePtr jsNumber(ExecState* exec, unsigned long long i); 61 JSValuePtr jsNumber(JSGlobalData* globalData, double d); 62 JSValuePtr jsNumber(JSGlobalData* globalData, short i); 63 JSValuePtr jsNumber(JSGlobalData* globalData, unsigned short i); 64 JSValuePtr jsNumber(JSGlobalData* globalData, int i); 65 JSValuePtr jsNumber(JSGlobalData* globalData, unsigned i); 66 JSValuePtr jsNumber(JSGlobalData* globalData, long i); 67 JSValuePtr jsNumber(JSGlobalData* globalData, unsigned long i); 68 JSValuePtr jsNumber(JSGlobalData* globalData, long long i); 69 JSValuePtr jsNumber(JSGlobalData* globalData, unsigned long long i); 70 71 #if USE(ALTERNATE_JSIMMEDIATE) reinterpretDoubleToIntptr(double value)72 inline intptr_t reinterpretDoubleToIntptr(double value) 73 { 74 return WTF::bitwise_cast<intptr_t>(value); 75 } 76 reinterpretIntptrToDouble(intptr_t value)77 inline double reinterpretIntptrToDouble(intptr_t value) 78 { 79 return WTF::bitwise_cast<double>(value); 80 } 81 #endif 82 83 /* 84 * A JSValue* is either a pointer to a cell (a heap-allocated object) or an immediate (a type-tagged 85 * value masquerading as a pointer). The low two bits in a JSValue* are available for type tagging 86 * because allocator alignment guarantees they will be 00 in cell pointers. 87 * 88 * For example, on a 32 bit system: 89 * 90 * JSCell*: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 00 91 * [ high 30 bits: pointer address ] [ low 2 bits -- always 0 ] 92 * JSImmediate: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX TT 93 * [ high 30 bits: 'payload' ] [ low 2 bits -- tag ] 94 * 95 * Where the bottom two bits are non-zero they either indicate that the immediate is a 31 bit signed 96 * integer, or they mark the value as being an immediate of a type other than integer, with a secondary 97 * tag used to indicate the exact type. 98 * 99 * Where the lowest bit is set (TT is equal to 01 or 11) the high 31 bits form a 31 bit signed int value. 100 * Where TT is equal to 10 this indicates this is a type of immediate other than an integer, and the next 101 * two bits will form an extended tag. 102 * 103 * 31 bit signed int: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX X1 104 * [ high 30 bits of the value ] [ high bit part of value ] 105 * Other: YYYYYYYYYYYYYYYYYYYYYYYYYYYY ZZ 10 106 * [ extended 'payload' ] [ extended tag ] [ tag 'other' ] 107 * 108 * Where the first bit of the extended tag is set this flags the value as being a boolean, and the following 109 * bit would flag the value as undefined. If neither bits are set, the value is null. 110 * 111 * Other: YYYYYYYYYYYYYYYYYYYYYYYYYYYY UB 10 112 * [ extended 'payload' ] [ undefined | bool ] [ tag 'other' ] 113 * 114 * For boolean value the lowest bit in the payload holds the value of the bool, all remaining bits are zero. 115 * For undefined or null immediates the payload is zero. 116 * 117 * Boolean: 000000000000000000000000000V 01 10 118 * [ boolean value ] [ bool ] [ tag 'other' ] 119 * Undefined: 0000000000000000000000000000 10 10 120 * [ zero ] [ undefined ] [ tag 'other' ] 121 * Null: 0000000000000000000000000000 00 10 122 * [ zero ] [ zero ] [ tag 'other' ] 123 */ 124 125 /* 126 * On 64-bit platforms, we support an alternative encoding form for immediates, if 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: 146 * 147 * Pointer: 0000:PPPP:PPPP:PPPP 148 * 0001:****:****:**** 149 * Double:{ ... 150 * FFFE:****:****:**** 151 * Integer: FFFF:0000:IIII:IIII 152 * 153 * 32-bit signed integers are marked with the 16-bit tag 0xFFFF. The tag 0x0000 154 * denotes a pointer, or another form of tagged immediate. Boolean, null and undefined 155 * values are encoded in the same manner as the default format. 156 */ 157 158 class JSImmediate { 159 private: 160 friend class JIT; 161 friend class JSValuePtr; 162 friend class JSFastMath; 163 friend JSValuePtr js0(); 164 friend JSValuePtr jsNull(); 165 friend JSValuePtr jsBoolean(bool b); 166 friend JSValuePtr jsUndefined(); 167 friend JSValuePtr jsImpossibleValue(); 168 friend JSValuePtr jsNumber(ExecState* exec, double d); 169 friend JSValuePtr jsNumber(ExecState*, char i); 170 friend JSValuePtr jsNumber(ExecState*, unsigned char i); 171 friend JSValuePtr jsNumber(ExecState*, short i); 172 friend JSValuePtr jsNumber(ExecState*, unsigned short i); 173 friend JSValuePtr jsNumber(ExecState* exec, int i); 174 friend JSValuePtr jsNumber(ExecState* exec, unsigned i); 175 friend JSValuePtr jsNumber(ExecState* exec, long i); 176 friend JSValuePtr jsNumber(ExecState* exec, unsigned long i); 177 friend JSValuePtr jsNumber(ExecState* exec, long long i); 178 friend JSValuePtr jsNumber(ExecState* exec, unsigned long long i); 179 friend JSValuePtr jsNumber(JSGlobalData* globalData, double d); 180 friend JSValuePtr jsNumber(JSGlobalData* globalData, short i); 181 friend JSValuePtr jsNumber(JSGlobalData* globalData, unsigned short i); 182 friend JSValuePtr jsNumber(JSGlobalData* globalData, int i); 183 friend JSValuePtr jsNumber(JSGlobalData* globalData, unsigned i); 184 friend JSValuePtr jsNumber(JSGlobalData* globalData, long i); 185 friend JSValuePtr jsNumber(JSGlobalData* globalData, unsigned long i); 186 friend JSValuePtr jsNumber(JSGlobalData* globalData, long long i); 187 friend JSValuePtr jsNumber(JSGlobalData* globalData, unsigned long long i); 188 189 #if USE(ALTERNATE_JSIMMEDIATE) 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 198 #endif 199 static const intptr_t TagBitTypeOther = 0x2; // second bit set indicates immediate other than an integer 200 static const intptr_t TagMask = TagTypeNumber | TagBitTypeOther; 201 202 static const intptr_t ExtendedTagMask = 0xC; // extended tag holds a further two bits 203 static const intptr_t ExtendedTagBitBool = 0x4; 204 static const intptr_t ExtendedTagBitUndefined = 0x8; 205 206 static const intptr_t FullTagTypeMask = TagMask | ExtendedTagMask; 207 static const intptr_t FullTagTypeBool = TagBitTypeOther | ExtendedTagBitBool; 208 static const intptr_t FullTagTypeUndefined = TagBitTypeOther | ExtendedTagBitUndefined; 209 static const intptr_t FullTagTypeNull = TagBitTypeOther; 210 211 #if USE(ALTERNATE_JSIMMEDIATE) 212 static const int32_t IntegerPayloadShift = 0; 213 #else 214 static const int32_t IntegerPayloadShift = 1; 215 #endif 216 static const int32_t ExtendedPayloadShift = 4; 217 218 static const intptr_t ExtendedPayloadBitBoolValue = 1 << ExtendedPayloadShift; 219 220 static const int32_t signBit = 0x80000000; 221 isImmediate(JSValuePtr v)222 static ALWAYS_INLINE bool isImmediate(JSValuePtr v) 223 { 224 return rawValue(v) & TagMask; 225 } 226 isNumber(JSValuePtr v)227 static ALWAYS_INLINE bool isNumber(JSValuePtr v) 228 { 229 return rawValue(v) & TagTypeNumber; 230 } 231 isIntegerNumber(JSValuePtr v)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) isDoubleNumber(JSValuePtr v)242 static ALWAYS_INLINE bool isDoubleNumber(JSValuePtr v) 243 { 244 return isNumber(v) && !isIntegerNumber(v); 245 } 246 #endif 247 isPositiveIntegerNumber(JSValuePtr v)248 static ALWAYS_INLINE bool isPositiveIntegerNumber(JSValuePtr v) 249 { 250 // A single mask to check for the sign bit and the number tag all at once. 251 return (rawValue(v) & (signBit | TagTypeNumber)) == TagTypeNumber; 252 } 253 isBoolean(JSValuePtr v)254 static ALWAYS_INLINE bool isBoolean(JSValuePtr v) 255 { 256 return (rawValue(v) & FullTagTypeMask) == FullTagTypeBool; 257 } 258 isUndefinedOrNull(JSValuePtr v)259 static ALWAYS_INLINE bool isUndefinedOrNull(JSValuePtr v) 260 { 261 // Undefined and null share the same value, bar the 'undefined' bit in the extended tag. 262 return (rawValue(v) & ~ExtendedTagBitUndefined) == FullTagTypeNull; 263 } 264 265 static JSValuePtr from(char); 266 static JSValuePtr from(signed char); 267 static JSValuePtr from(unsigned char); 268 static JSValuePtr from(short); 269 static JSValuePtr from(unsigned short); 270 static JSValuePtr from(int); 271 static JSValuePtr from(unsigned); 272 static JSValuePtr from(long); 273 static JSValuePtr from(unsigned long); 274 static JSValuePtr from(long long); 275 static JSValuePtr from(unsigned long long); 276 static JSValuePtr from(double); 277 isEitherImmediate(JSValuePtr v1,JSValuePtr v2)278 static ALWAYS_INLINE bool isEitherImmediate(JSValuePtr v1, JSValuePtr v2) 279 { 280 return (rawValue(v1) | rawValue(v2)) & TagMask; 281 } 282 areBothImmediate(JSValuePtr v1,JSValuePtr v2)283 static ALWAYS_INLINE bool areBothImmediate(JSValuePtr v1, JSValuePtr v2) 284 { 285 return isImmediate(v1) & isImmediate(v2); 286 } 287 areBothImmediateIntegerNumbers(JSValuePtr v1,JSValuePtr v2)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 295 } 296 297 static double toDouble(JSValuePtr); 298 static bool toBoolean(JSValuePtr); 299 static JSObject* toObject(JSValuePtr, ExecState*); 300 static JSObject* toThisObject(JSValuePtr, ExecState*); 301 static UString toString(JSValuePtr); 302 303 static bool getUInt32(JSValuePtr, uint32_t&); 304 static bool getTruncatedInt32(JSValuePtr, int32_t&); 305 static bool getTruncatedUInt32(JSValuePtr, uint32_t&); 306 307 static int32_t getTruncatedInt32(JSValuePtr); 308 static uint32_t getTruncatedUInt32(JSValuePtr); 309 310 static JSValuePtr trueImmediate(); 311 static JSValuePtr falseImmediate(); 312 static JSValuePtr undefinedImmediate(); 313 static JSValuePtr nullImmediate(); 314 static JSValuePtr zeroImmediate(); 315 static JSValuePtr oneImmediate(); 316 317 static JSValuePtr impossibleValue(); 318 319 static JSObject* prototype(JSValuePtr, ExecState*); 320 321 private: 322 #if USE(ALTERNATE_JSIMMEDIATE) 323 static const int minImmediateInt = ((-INT_MAX) - 1); 324 static const int maxImmediateInt = INT_MAX; 325 #else 326 static const int minImmediateInt = ((-INT_MAX) - 1) >> IntegerPayloadShift; 327 static const int maxImmediateInt = INT_MAX >> IntegerPayloadShift; 328 #endif 329 static const unsigned maxImmediateUInt = maxImmediateInt; 330 makeValue(intptr_t integer)331 static ALWAYS_INLINE JSValuePtr makeValue(intptr_t integer) 332 { 333 return JSValuePtr::makeImmediate(integer); 334 } 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. 339 #if USE(ALTERNATE_JSIMMEDIATE) makeInt(uint32_t value)340 static ALWAYS_INLINE JSValuePtr makeInt(uint32_t value) 341 #else 342 static ALWAYS_INLINE JSValuePtr makeInt(int32_t value) 343 #endif 344 { 345 return makeValue((static_cast<intptr_t>(value) << IntegerPayloadShift) | TagTypeNumber); 346 } 347 348 #if USE(ALTERNATE_JSIMMEDIATE) makeDouble(double value)349 static ALWAYS_INLINE JSValuePtr makeDouble(double value) 350 { 351 return makeValue(reinterpretDoubleToIntptr(value) + DoubleEncodeOffset); 352 } 353 #endif 354 makeBool(bool b)355 static ALWAYS_INLINE JSValuePtr makeBool(bool b) 356 { 357 return makeValue((static_cast<intptr_t>(b) << ExtendedPayloadShift) | FullTagTypeBool); 358 } 359 makeUndefined()360 static ALWAYS_INLINE JSValuePtr makeUndefined() 361 { 362 return makeValue(FullTagTypeUndefined); 363 } 364 makeNull()365 static ALWAYS_INLINE JSValuePtr makeNull() 366 { 367 return makeValue(FullTagTypeNull); 368 } 369 370 template<typename T> 371 static JSValuePtr fromNumberOutsideIntegerRange(T); 372 373 #if USE(ALTERNATE_JSIMMEDIATE) doubleValue(JSValuePtr v)374 static ALWAYS_INLINE double doubleValue(JSValuePtr v) 375 { 376 return reinterpretIntptrToDouble(rawValue(v) - DoubleEncodeOffset); 377 } 378 #endif 379 intValue(JSValuePtr v)380 static ALWAYS_INLINE int32_t intValue(JSValuePtr v) 381 { 382 return static_cast<int32_t>(rawValue(v) >> IntegerPayloadShift); 383 } 384 uintValue(JSValuePtr v)385 static ALWAYS_INLINE uint32_t uintValue(JSValuePtr v) 386 { 387 return static_cast<uint32_t>(rawValue(v) >> IntegerPayloadShift); 388 } 389 boolValue(JSValuePtr v)390 static ALWAYS_INLINE bool boolValue(JSValuePtr v) 391 { 392 return rawValue(v) & ExtendedPayloadBitBoolValue; 393 } 394 rawValue(JSValuePtr v)395 static ALWAYS_INLINE intptr_t rawValue(JSValuePtr v) 396 { 397 return v.immediateValue(); 398 } 399 400 static double nonInlineNaN(); 401 }; 402 trueImmediate()403 ALWAYS_INLINE JSValuePtr JSImmediate::trueImmediate() { return makeBool(true); } falseImmediate()404 ALWAYS_INLINE JSValuePtr JSImmediate::falseImmediate() { return makeBool(false); } undefinedImmediate()405 ALWAYS_INLINE JSValuePtr JSImmediate::undefinedImmediate() { return makeUndefined(); } nullImmediate()406 ALWAYS_INLINE JSValuePtr JSImmediate::nullImmediate() { return makeNull(); } zeroImmediate()407 ALWAYS_INLINE JSValuePtr JSImmediate::zeroImmediate() { return makeInt(0); } oneImmediate()408 ALWAYS_INLINE JSValuePtr JSImmediate::oneImmediate() { return makeInt(1); } 409 410 // This value is impossible because 0x4 is not a valid pointer but a tag of 0 would indicate non-immediate impossibleValue()411 ALWAYS_INLINE JSValuePtr JSImmediate::impossibleValue() { return makeValue(0x4); } 412 413 #if USE(ALTERNATE_JSIMMEDIATE) doubleToBoolean(double value)414 inline bool doubleToBoolean(double value) 415 { 416 return value < 0.0 || value > 0.0; 417 } 418 toBoolean(JSValuePtr v)419 ALWAYS_INLINE bool JSImmediate::toBoolean(JSValuePtr v) 420 { 421 ASSERT(isImmediate(v)); 422 return isNumber(v) ? isIntegerNumber(v) ? v != zeroImmediate() 423 : doubleToBoolean(doubleValue(v)) : v == trueImmediate(); 424 } 425 #else toBoolean(JSValuePtr v)426 ALWAYS_INLINE bool JSImmediate::toBoolean(JSValuePtr v) 427 { 428 ASSERT(isImmediate(v)); 429 return isIntegerNumber(v) ? v != zeroImmediate() : v == trueImmediate(); 430 } 431 #endif 432 getTruncatedUInt32(JSValuePtr v)433 ALWAYS_INLINE uint32_t JSImmediate::getTruncatedUInt32(JSValuePtr v) 434 { 435 // FIXME: should probably be asserting isPositiveIntegerNumber here. 436 ASSERT(isIntegerNumber(v)); 437 return intValue(v); 438 } 439 440 #if USE(ALTERNATE_JSIMMEDIATE) 441 template<typename T> fromNumberOutsideIntegerRange(T value)442 inline JSValuePtr JSImmediate::fromNumberOutsideIntegerRange(T value) 443 { 444 return makeDouble(static_cast<double>(value)); 445 } 446 #else 447 template<typename T> fromNumberOutsideIntegerRange(T)448 inline JSValuePtr JSImmediate::fromNumberOutsideIntegerRange(T) 449 { 450 return noValue(); 451 } 452 #endif 453 from(char i)454 ALWAYS_INLINE JSValuePtr JSImmediate::from(char i) 455 { 456 return makeInt(i); 457 } 458 from(signed char i)459 ALWAYS_INLINE JSValuePtr JSImmediate::from(signed char i) 460 { 461 return makeInt(i); 462 } 463 from(unsigned char i)464 ALWAYS_INLINE JSValuePtr JSImmediate::from(unsigned char i) 465 { 466 return makeInt(i); 467 } 468 from(short i)469 ALWAYS_INLINE JSValuePtr JSImmediate::from(short i) 470 { 471 return makeInt(i); 472 } 473 from(unsigned short i)474 ALWAYS_INLINE JSValuePtr JSImmediate::from(unsigned short i) 475 { 476 return makeInt(i); 477 } 478 from(int i)479 ALWAYS_INLINE JSValuePtr JSImmediate::from(int i) 480 { 481 #if !USE(ALTERNATE_JSIMMEDIATE) 482 if ((i < minImmediateInt) | (i > maxImmediateInt)) 483 return fromNumberOutsideIntegerRange(i); 484 #endif 485 return makeInt(i); 486 } 487 from(unsigned i)488 ALWAYS_INLINE JSValuePtr JSImmediate::from(unsigned i) 489 { 490 if (i > maxImmediateUInt) 491 return fromNumberOutsideIntegerRange(i); 492 return makeInt(i); 493 } 494 from(long i)495 ALWAYS_INLINE JSValuePtr JSImmediate::from(long i) 496 { 497 if ((i < minImmediateInt) | (i > maxImmediateInt)) 498 return fromNumberOutsideIntegerRange(i); 499 return makeInt(i); 500 } 501 from(unsigned long i)502 ALWAYS_INLINE JSValuePtr JSImmediate::from(unsigned long i) 503 { 504 if (i > maxImmediateUInt) 505 return fromNumberOutsideIntegerRange(i); 506 return makeInt(i); 507 } 508 from(long long i)509 ALWAYS_INLINE JSValuePtr JSImmediate::from(long long i) 510 { 511 if ((i < minImmediateInt) | (i > maxImmediateInt)) 512 return noValue(); 513 return makeInt(static_cast<intptr_t>(i)); 514 } 515 from(unsigned long long i)516 ALWAYS_INLINE JSValuePtr JSImmediate::from(unsigned long long i) 517 { 518 if (i > maxImmediateUInt) 519 return fromNumberOutsideIntegerRange(i); 520 return makeInt(static_cast<intptr_t>(i)); 521 } 522 from(double d)523 ALWAYS_INLINE JSValuePtr JSImmediate::from(double d) 524 { 525 const int intVal = static_cast<int>(d); 526 527 // Check for data loss from conversion to int. 528 if (intVal != d || (!intVal && signbit(d))) 529 return fromNumberOutsideIntegerRange(d); 530 531 return from(intVal); 532 } 533 getTruncatedInt32(JSValuePtr v)534 ALWAYS_INLINE int32_t JSImmediate::getTruncatedInt32(JSValuePtr v) 535 { 536 ASSERT(isIntegerNumber(v)); 537 return intValue(v); 538 } 539 toDouble(JSValuePtr v)540 ALWAYS_INLINE double JSImmediate::toDouble(JSValuePtr v) 541 { 542 ASSERT(isImmediate(v)); 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) 557 return nonInlineNaN(); 558 559 ASSERT(JSImmediate::isBoolean(v) || (v == JSImmediate::nullImmediate())); 560 return rawValue(v) >> ExtendedPayloadShift; 561 } 562 getUInt32(JSValuePtr v,uint32_t & i)563 ALWAYS_INLINE bool JSImmediate::getUInt32(JSValuePtr v, uint32_t& i) 564 { 565 i = uintValue(v); 566 return isPositiveIntegerNumber(v); 567 } 568 getTruncatedInt32(JSValuePtr v,int32_t & i)569 ALWAYS_INLINE bool JSImmediate::getTruncatedInt32(JSValuePtr v, int32_t& i) 570 { 571 i = intValue(v); 572 return isIntegerNumber(v); 573 } 574 getTruncatedUInt32(JSValuePtr v,uint32_t & i)575 ALWAYS_INLINE bool JSImmediate::getTruncatedUInt32(JSValuePtr v, uint32_t& i) 576 { 577 return getUInt32(v, i); 578 } 579 js0()580 inline JSValuePtr js0() 581 { 582 return JSImmediate::zeroImmediate(); 583 } 584 jsNull()585 inline JSValuePtr jsNull() 586 { 587 return JSImmediate::nullImmediate(); 588 } 589 jsBoolean(bool b)590 inline JSValuePtr jsBoolean(bool b) 591 { 592 return b ? JSImmediate::trueImmediate() : JSImmediate::falseImmediate(); 593 } 594 jsUndefined()595 inline JSValuePtr jsUndefined() 596 { 597 return JSImmediate::undefinedImmediate(); 598 } 599 jsImpossibleValue()600 inline JSValuePtr jsImpossibleValue() 601 { 602 return JSImmediate::impossibleValue(); 603 } 604 605 // These are identical logic to the JSValue functions above, and faster than jsNumber(number).toInt32(). 606 int32_t toInt32(double); 607 uint32_t toUInt32(double); 608 int32_t toInt32SlowCase(double, bool& ok); 609 uint32_t toUInt32SlowCase(double, bool& ok); 610 isUndefined()611 inline bool JSValuePtr::isUndefined() const 612 { 613 return asValue() == jsUndefined(); 614 } 615 isNull()616 inline bool JSValuePtr::isNull() const 617 { 618 return asValue() == jsNull(); 619 } 620 isUndefinedOrNull()621 inline bool JSValuePtr::isUndefinedOrNull() const 622 { 623 return JSImmediate::isUndefinedOrNull(asValue()); 624 } 625 isBoolean()626 inline bool JSValuePtr::isBoolean() const 627 { 628 return JSImmediate::isBoolean(asValue()); 629 } 630 getBoolean(bool & v)631 inline bool JSValuePtr::getBoolean(bool& v) const 632 { 633 if (JSImmediate::isBoolean(asValue())) { 634 v = JSImmediate::toBoolean(asValue()); 635 return true; 636 } 637 638 return false; 639 } 640 getBoolean()641 inline bool JSValuePtr::getBoolean() const 642 { 643 return asValue() == jsBoolean(true); 644 } 645 toInt32(ExecState * exec)646 ALWAYS_INLINE int32_t JSValuePtr::toInt32(ExecState* exec) const 647 { 648 int32_t i; 649 if (getTruncatedInt32(i)) 650 return i; 651 bool ignored; 652 return toInt32SlowCase(toNumber(exec), ignored); 653 } 654 toUInt32(ExecState * exec)655 inline uint32_t JSValuePtr::toUInt32(ExecState* exec) const 656 { 657 uint32_t i; 658 if (getTruncatedUInt32(i)) 659 return i; 660 bool ignored; 661 return toUInt32SlowCase(toNumber(exec), ignored); 662 } 663 toInt32(double val)664 inline int32_t toInt32(double val) 665 { 666 if (!(val >= -2147483648.0 && val < 2147483648.0)) { 667 bool ignored; 668 return toInt32SlowCase(val, ignored); 669 } 670 return static_cast<int32_t>(val); 671 } 672 toUInt32(double val)673 inline uint32_t toUInt32(double val) 674 { 675 if (!(val >= 0.0 && val < 4294967296.0)) { 676 bool ignored; 677 return toUInt32SlowCase(val, ignored); 678 } 679 return static_cast<uint32_t>(val); 680 } 681 toInt32(ExecState * exec,bool & ok)682 inline int32_t JSValuePtr::toInt32(ExecState* exec, bool& ok) const 683 { 684 int32_t i; 685 if (getTruncatedInt32(i)) { 686 ok = true; 687 return i; 688 } 689 return toInt32SlowCase(toNumber(exec), ok); 690 } 691 toUInt32(ExecState * exec,bool & ok)692 inline uint32_t JSValuePtr::toUInt32(ExecState* exec, bool& ok) const 693 { 694 uint32_t i; 695 if (getTruncatedUInt32(i)) { 696 ok = true; 697 return i; 698 } 699 return toUInt32SlowCase(toNumber(exec), ok); 700 } 701 isCell()702 inline bool JSValuePtr::isCell() const 703 { 704 return !JSImmediate::isImmediate(asValue()); 705 } 706 isInt32Fast()707 inline bool JSValuePtr::isInt32Fast() const 708 { 709 return JSImmediate::isIntegerNumber(asValue()); 710 } 711 getInt32Fast()712 inline int32_t JSValuePtr::getInt32Fast() const 713 { 714 ASSERT(isInt32Fast()); 715 return JSImmediate::getTruncatedInt32(asValue()); 716 } 717 isUInt32Fast()718 inline bool JSValuePtr::isUInt32Fast() const 719 { 720 return JSImmediate::isPositiveIntegerNumber(asValue()); 721 } 722 getUInt32Fast()723 inline uint32_t JSValuePtr::getUInt32Fast() const 724 { 725 ASSERT(isUInt32Fast()); 726 return JSImmediate::getTruncatedUInt32(asValue()); 727 } 728 makeInt32Fast(int32_t i)729 inline JSValuePtr JSValuePtr::makeInt32Fast(int32_t i) 730 { 731 return JSImmediate::from(i); 732 } 733 areBothInt32Fast(JSValuePtr v1,JSValuePtr v2)734 inline bool JSValuePtr::areBothInt32Fast(JSValuePtr v1, JSValuePtr v2) 735 { 736 return JSImmediate::areBothImmediateIntegerNumbers(v1, v2); 737 } 738 739 class JSFastMath { 740 public: canDoFastBitwiseOperations(JSValuePtr v1,JSValuePtr v2)741 static ALWAYS_INLINE bool canDoFastBitwiseOperations(JSValuePtr v1, JSValuePtr v2) 742 { 743 return JSImmediate::areBothImmediateIntegerNumbers(v1, v2); 744 } 745 equal(JSValuePtr v1,JSValuePtr v2)746 static ALWAYS_INLINE JSValuePtr equal(JSValuePtr v1, JSValuePtr v2) 747 { 748 ASSERT(canDoFastBitwiseOperations(v1, v2)); 749 return jsBoolean(v1 == v2); 750 } 751 notEqual(JSValuePtr v1,JSValuePtr v2)752 static ALWAYS_INLINE JSValuePtr notEqual(JSValuePtr v1, JSValuePtr v2) 753 { 754 ASSERT(canDoFastBitwiseOperations(v1, v2)); 755 return jsBoolean(v1 != v2); 756 } 757 andImmediateNumbers(JSValuePtr v1,JSValuePtr v2)758 static ALWAYS_INLINE JSValuePtr andImmediateNumbers(JSValuePtr v1, JSValuePtr v2) 759 { 760 ASSERT(canDoFastBitwiseOperations(v1, v2)); 761 return JSImmediate::makeValue(JSImmediate::rawValue(v1) & JSImmediate::rawValue(v2)); 762 } 763 xorImmediateNumbers(JSValuePtr v1,JSValuePtr v2)764 static ALWAYS_INLINE JSValuePtr xorImmediateNumbers(JSValuePtr v1, JSValuePtr v2) 765 { 766 ASSERT(canDoFastBitwiseOperations(v1, v2)); 767 return JSImmediate::makeValue((JSImmediate::rawValue(v1) ^ JSImmediate::rawValue(v2)) | JSImmediate::TagTypeNumber); 768 } 769 orImmediateNumbers(JSValuePtr v1,JSValuePtr v2)770 static ALWAYS_INLINE JSValuePtr orImmediateNumbers(JSValuePtr v1, JSValuePtr v2) 771 { 772 ASSERT(canDoFastBitwiseOperations(v1, v2)); 773 return JSImmediate::makeValue(JSImmediate::rawValue(v1) | JSImmediate::rawValue(v2)); 774 } 775 canDoFastRshift(JSValuePtr v1,JSValuePtr v2)776 static ALWAYS_INLINE bool canDoFastRshift(JSValuePtr v1, JSValuePtr v2) 777 { 778 return JSImmediate::areBothImmediateIntegerNumbers(v1, v2); 779 } 780 canDoFastUrshift(JSValuePtr v1,JSValuePtr v2)781 static ALWAYS_INLINE bool canDoFastUrshift(JSValuePtr v1, JSValuePtr v2) 782 { 783 return JSImmediate::areBothImmediateIntegerNumbers(v1, v2) && !(JSImmediate::rawValue(v1) & JSImmediate::signBit); 784 } 785 rightShiftImmediateNumbers(JSValuePtr val,JSValuePtr shift)786 static ALWAYS_INLINE JSValuePtr rightShiftImmediateNumbers(JSValuePtr val, JSValuePtr shift) 787 { 788 ASSERT(canDoFastRshift(val, shift) || canDoFastUrshift(val, shift)); 789 #if USE(ALTERNATE_JSIMMEDIATE) 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); 793 #endif 794 } 795 canDoFastAdditiveOperations(JSValuePtr v)796 static ALWAYS_INLINE bool canDoFastAdditiveOperations(JSValuePtr v) 797 { 798 // Number is non-negative and an operation involving two of these can't overflow. 799 // Checking for allowed negative numbers takes more time than it's worth on SunSpider. 800 return (JSImmediate::rawValue(v) & (JSImmediate::TagTypeNumber + (JSImmediate::signBit | (JSImmediate::signBit >> 1)))) == JSImmediate::TagTypeNumber; 801 } 802 canDoFastAdditiveOperations(JSValuePtr v1,JSValuePtr v2)803 static ALWAYS_INLINE bool canDoFastAdditiveOperations(JSValuePtr v1, JSValuePtr v2) 804 { 805 // Number is non-negative and an operation involving two of these can't overflow. 806 // Checking for allowed negative numbers takes more time than it's worth on SunSpider. 807 return canDoFastAdditiveOperations(v1) && canDoFastAdditiveOperations(v2); 808 } 809 addImmediateNumbers(JSValuePtr v1,JSValuePtr v2)810 static ALWAYS_INLINE JSValuePtr addImmediateNumbers(JSValuePtr v1, JSValuePtr v2) 811 { 812 ASSERT(canDoFastAdditiveOperations(v1, v2)); 813 return JSImmediate::makeValue(JSImmediate::rawValue(v1) + JSImmediate::rawValue(v2) - JSImmediate::TagTypeNumber); 814 } 815 subImmediateNumbers(JSValuePtr v1,JSValuePtr v2)816 static ALWAYS_INLINE JSValuePtr subImmediateNumbers(JSValuePtr v1, JSValuePtr v2) 817 { 818 ASSERT(canDoFastAdditiveOperations(v1, v2)); 819 return JSImmediate::makeValue(JSImmediate::rawValue(v1) - JSImmediate::rawValue(v2) + JSImmediate::TagTypeNumber); 820 } 821 incImmediateNumber(JSValuePtr v)822 static ALWAYS_INLINE JSValuePtr incImmediateNumber(JSValuePtr v) 823 { 824 ASSERT(canDoFastAdditiveOperations(v)); 825 return JSImmediate::makeValue(JSImmediate::rawValue(v) + (1 << JSImmediate::IntegerPayloadShift)); 826 } 827 decImmediateNumber(JSValuePtr v)828 static ALWAYS_INLINE JSValuePtr decImmediateNumber(JSValuePtr v) 829 { 830 ASSERT(canDoFastAdditiveOperations(v)); 831 return JSImmediate::makeValue(JSImmediate::rawValue(v) - (1 << JSImmediate::IntegerPayloadShift)); 832 } 833 }; 834 835 } // namespace JSC 836 837 #endif // JSImmediate_h 838