2  * Copyright (C) 2011, 2012 Apple Inc. All rights reserved. 
   4  * Redistribution and use in source and binary forms, with or without 
   5  * modification, are permitted provided that the following conditions 
   7  * 1. Redistributions of source code must retain the above copyright 
   8  *    notice, this list of conditions and the following disclaimer. 
   9  * 2. Redistributions in binary form must reproduce the above copyright 
  10  *    notice, this list of conditions and the following disclaimer in the 
  11  *    documentation and/or other materials provided with the distribution. 
  13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 
  14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
  15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
  16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR 
  17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
  18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
  19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
  20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 
  21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
  22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
  23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  
  26 #ifndef JSValueInlines_h 
  27 #define JSValueInlines_h 
  29 #include "InternalFunction.h" 
  30 #include "JSCJSValue.h" 
  31 #include "JSCellInlines.h" 
  32 #include "JSFunction.h" 
  36 ALWAYS_INLINE 
int32_t JSValue::toInt32(ExecState
* exec
) const 
  40     return JSC::toInt32(toNumber(exec
)); 
  43 inline uint32_t JSValue::toUInt32(ExecState
* exec
) const 
  45     // See comment on JSC::toUInt32, above. 
  49 inline bool JSValue::isUInt32() const 
  51     return isInt32() && asInt32() >= 0; 
  54 inline uint32_t JSValue::asUInt32() const 
  60 inline double JSValue::asNumber() const 
  63     return isInt32() ? asInt32() : asDouble(); 
  66 inline JSValue 
jsNaN() 
  71 inline JSValue::JSValue(char i
) 
  73     *this = JSValue(static_cast<int32_t>(i
)); 
  76 inline JSValue::JSValue(unsigned char i
) 
  78     *this = JSValue(static_cast<int32_t>(i
)); 
  81 inline JSValue::JSValue(short i
) 
  83     *this = JSValue(static_cast<int32_t>(i
)); 
  86 inline JSValue::JSValue(unsigned short i
) 
  88     *this = JSValue(static_cast<int32_t>(i
)); 
  91 inline JSValue::JSValue(unsigned i
) 
  93     if (static_cast<int32_t>(i
) < 0) { 
  94         *this = JSValue(EncodeAsDouble
, static_cast<double>(i
)); 
  97     *this = JSValue(static_cast<int32_t>(i
)); 
 100 inline JSValue::JSValue(long i
) 
 102     if (static_cast<int32_t>(i
) != i
) { 
 103         *this = JSValue(EncodeAsDouble
, static_cast<double>(i
)); 
 106     *this = JSValue(static_cast<int32_t>(i
)); 
 109 inline JSValue::JSValue(unsigned long i
) 
 111     if (static_cast<uint32_t>(i
) != i
) { 
 112         *this = JSValue(EncodeAsDouble
, static_cast<double>(i
)); 
 115     *this = JSValue(static_cast<uint32_t>(i
)); 
 118 inline JSValue::JSValue(long long i
) 
 120     if (static_cast<int32_t>(i
) != i
) { 
 121         *this = JSValue(EncodeAsDouble
, static_cast<double>(i
)); 
 124     *this = JSValue(static_cast<int32_t>(i
)); 
 127 inline JSValue::JSValue(unsigned long long i
) 
 129     if (static_cast<uint32_t>(i
) != i
) { 
 130         *this = JSValue(EncodeAsDouble
, static_cast<double>(i
)); 
 133     *this = JSValue(static_cast<uint32_t>(i
)); 
 136 inline JSValue::JSValue(double d
) 
 138     const int32_t asInt32 
= static_cast<int32_t>(d
); 
 139     if (asInt32 
!= d 
|| (!asInt32 
&& std::signbit(d
))) { // true for -0.0 
 140         *this = JSValue(EncodeAsDouble
, d
); 
 143     *this = JSValue(static_cast<int32_t>(d
)); 
 146 inline EncodedJSValue 
JSValue::encode(JSValue value
) 
 148     return value
.u
.asInt64
; 
 151 inline JSValue 
JSValue::decode(EncodedJSValue encodedJSValue
) 
 154     v
.u
.asInt64 
= encodedJSValue
; 
 158 #if USE(JSVALUE32_64) 
 159 inline JSValue::JSValue() 
 161     u
.asBits
.tag 
= EmptyValueTag
; 
 162     u
.asBits
.payload 
= 0; 
 165 inline JSValue::JSValue(JSNullTag
) 
 167     u
.asBits
.tag 
= NullTag
; 
 168     u
.asBits
.payload 
= 0; 
 171 inline JSValue::JSValue(JSUndefinedTag
) 
 173     u
.asBits
.tag 
= UndefinedTag
; 
 174     u
.asBits
.payload 
= 0; 
 177 inline JSValue::JSValue(JSTrueTag
) 
 179     u
.asBits
.tag 
= BooleanTag
; 
 180     u
.asBits
.payload 
= 1; 
 183 inline JSValue::JSValue(JSFalseTag
) 
 185     u
.asBits
.tag 
= BooleanTag
; 
 186     u
.asBits
.payload 
= 0; 
 189 inline JSValue::JSValue(HashTableDeletedValueTag
) 
 191     u
.asBits
.tag 
= DeletedValueTag
; 
 192     u
.asBits
.payload 
= 0; 
 195 inline JSValue::JSValue(JSCell
* ptr
) 
 198         u
.asBits
.tag 
= CellTag
; 
 200         u
.asBits
.tag 
= EmptyValueTag
; 
 201     u
.asBits
.payload 
= reinterpret_cast<int32_t>(ptr
); 
 204 inline JSValue::JSValue(const JSCell
* ptr
) 
 207         u
.asBits
.tag 
= CellTag
; 
 209         u
.asBits
.tag 
= EmptyValueTag
; 
 210     u
.asBits
.payload 
= reinterpret_cast<int32_t>(const_cast<JSCell
*>(ptr
)); 
 213 inline JSValue::operator bool() const 
 215     ASSERT(tag() != DeletedValueTag
); 
 216     return tag() != EmptyValueTag
; 
 219 inline bool JSValue::operator==(const JSValue
& other
) const 
 221     return u
.asInt64 
== other
.u
.asInt64
; 
 224 inline bool JSValue::operator!=(const JSValue
& other
) const 
 226     return u
.asInt64 
!= other
.u
.asInt64
; 
 229 inline bool JSValue::isEmpty() const 
 231     return tag() == EmptyValueTag
; 
 234 inline bool JSValue::isUndefined() const 
 236     return tag() == UndefinedTag
; 
 239 inline bool JSValue::isNull() const 
 241     return tag() == NullTag
; 
 244 inline bool JSValue::isUndefinedOrNull() const 
 246     return isUndefined() || isNull(); 
 249 inline bool JSValue::isCell() const 
 251     return tag() == CellTag
; 
 254 inline bool JSValue::isInt32() const 
 256     return tag() == Int32Tag
; 
 259 inline bool JSValue::isDouble() const 
 261     return tag() < LowestTag
; 
 264 inline bool JSValue::isTrue() const 
 266     return tag() == BooleanTag 
&& payload(); 
 269 inline bool JSValue::isFalse() const 
 271     return tag() == BooleanTag 
&& !payload(); 
 274 inline uint32_t JSValue::tag() const 
 279 inline int32_t JSValue::payload() const 
 281     return u
.asBits
.payload
; 
 284 inline int32_t JSValue::asInt32() const 
 287     return u
.asBits
.payload
; 
 290 inline double JSValue::asDouble() const 
 296 ALWAYS_INLINE JSCell
* JSValue::asCell() const 
 299     return reinterpret_cast<JSCell
*>(u
.asBits
.payload
); 
 302 ALWAYS_INLINE 
JSValue::JSValue(EncodeAsDoubleTag
, double d
) 
 307 inline JSValue::JSValue(int i
) 
 309     u
.asBits
.tag 
= Int32Tag
; 
 310     u
.asBits
.payload 
= i
; 
 313 #if ENABLE(LLINT_C_LOOP) 
 314 inline JSValue::JSValue(int32_t tag
, int32_t payload
) 
 317     u
.asBits
.payload 
= payload
; 
 321 inline bool JSValue::isNumber() const 
 323     return isInt32() || isDouble(); 
 326 inline bool JSValue::isBoolean() const 
 328     return isTrue() || isFalse(); 
 331 inline bool JSValue::asBoolean() const 
 337 #else // !USE(JSVALUE32_64) i.e. USE(JSVALUE64) 
 339 // 0x0 can never occur naturally because it has a tag of 00, indicating a pointer value, but a payload of 0x0, which is in the (invalid) zero page. 
 340 inline JSValue::JSValue() 
 342     u
.asInt64 
= ValueEmpty
; 
 345 // 0x4 can never occur naturally because it has a tag of 00, indicating a pointer value, but a payload of 0x4, which is in the (invalid) zero page. 
 346 inline JSValue::JSValue(HashTableDeletedValueTag
) 
 348     u
.asInt64 
= ValueDeleted
; 
 351 inline JSValue::JSValue(JSCell
* ptr
) 
 353     u
.asInt64 
= reinterpret_cast<uintptr_t>(ptr
); 
 356 inline JSValue::JSValue(const JSCell
* ptr
) 
 358     u
.asInt64 
= reinterpret_cast<uintptr_t>(const_cast<JSCell
*>(ptr
)); 
 361 inline JSValue::operator bool() const 
 366 inline bool JSValue::operator==(const JSValue
& other
) const 
 368     return u
.asInt64 
== other
.u
.asInt64
; 
 371 inline bool JSValue::operator!=(const JSValue
& other
) const 
 373     return u
.asInt64 
!= other
.u
.asInt64
; 
 376 inline bool JSValue::isEmpty() const 
 378     return u
.asInt64 
== ValueEmpty
; 
 381 inline bool JSValue::isUndefined() const 
 383     return asValue() == JSValue(JSUndefined
); 
 386 inline bool JSValue::isNull() const 
 388     return asValue() == JSValue(JSNull
); 
 391 inline bool JSValue::isTrue() const 
 393     return asValue() == JSValue(JSTrue
); 
 396 inline bool JSValue::isFalse() const 
 398     return asValue() == JSValue(JSFalse
); 
 401 inline bool JSValue::asBoolean() const 
 404     return asValue() == JSValue(JSTrue
); 
 407 inline int32_t JSValue::asInt32() const 
 410     return static_cast<int32_t>(u
.asInt64
); 
 413 inline bool JSValue::isDouble() const 
 415     return isNumber() && !isInt32(); 
 418 inline JSValue::JSValue(JSNullTag
) 
 420     u
.asInt64 
= ValueNull
; 
 423 inline JSValue::JSValue(JSUndefinedTag
) 
 425     u
.asInt64 
= ValueUndefined
; 
 428 inline JSValue::JSValue(JSTrueTag
) 
 430     u
.asInt64 
= ValueTrue
; 
 433 inline JSValue::JSValue(JSFalseTag
) 
 435     u
.asInt64 
= ValueFalse
; 
 438 inline bool JSValue::isUndefinedOrNull() const 
 440     // Undefined and null share the same value, bar the 'undefined' bit in the extended tag. 
 441     return (u
.asInt64 
& ~TagBitUndefined
) == ValueNull
; 
 444 inline bool JSValue::isBoolean() const 
 446     return (u
.asInt64 
& ~1) == ValueFalse
; 
 449 inline bool JSValue::isCell() const 
 451     return !(u
.asInt64 
& TagMask
); 
 454 inline bool JSValue::isInt32() const 
 456     return (u
.asInt64 
& TagTypeNumber
) == TagTypeNumber
; 
 459 inline int64_t reinterpretDoubleToInt64(double value
) 
 461     return bitwise_cast
<int64_t>(value
); 
 463 inline double reinterpretInt64ToDouble(int64_t value
) 
 465     return bitwise_cast
<double>(value
); 
 468 ALWAYS_INLINE 
JSValue::JSValue(EncodeAsDoubleTag
, double d
) 
 470     u
.asInt64 
= reinterpretDoubleToInt64(d
) + DoubleEncodeOffset
; 
 473 inline JSValue::JSValue(int i
) 
 475     u
.asInt64 
= TagTypeNumber 
| static_cast<uint32_t>(i
); 
 478 inline double JSValue::asDouble() const 
 481     return reinterpretInt64ToDouble(u
.asInt64 
- DoubleEncodeOffset
); 
 484 inline bool JSValue::isNumber() const 
 486     return u
.asInt64 
& TagTypeNumber
; 
 489 ALWAYS_INLINE JSCell
* JSValue::asCell() const 
 495 #endif // USE(JSVALUE64) 
 497 inline bool JSValue::isString() const 
 499     return isCell() && asCell()->isString(); 
 502 inline bool JSValue::isPrimitive() const 
 504     return !isCell() || asCell()->isString(); 
 507 inline bool JSValue::isGetterSetter() const 
 509     return isCell() && asCell()->isGetterSetter(); 
 512 inline bool JSValue::isObject() const 
 514     return isCell() && asCell()->isObject(); 
 517 inline bool JSValue::getString(ExecState
* exec
, String
& s
) const 
 519     return isCell() && asCell()->getString(exec
, s
); 
 522 inline String 
JSValue::getString(ExecState
* exec
) const 
 524     return isCell() ? asCell()->getString(exec
) : String(); 
 527 template <typename Base
> String HandleConverter
<Base
, Unknown
>::getString(ExecState
* exec
) const 
 529     return jsValue().getString(exec
); 
 532 inline JSObject
* JSValue::getObject() const 
 534     return isCell() ? asCell()->getObject() : 0; 
 537 ALWAYS_INLINE 
bool JSValue::getUInt32(uint32_t& v
) const 
 540         int32_t i 
= asInt32(); 
 541         v 
= static_cast<uint32_t>(i
); 
 545         double d 
= asDouble(); 
 546         v 
= static_cast<uint32_t>(d
); 
 552 inline JSValue 
JSValue::toPrimitive(ExecState
* exec
, PreferredPrimitiveType preferredType
) const 
 554     return isCell() ? asCell()->toPrimitive(exec
, preferredType
) : asValue(); 
 557 inline bool JSValue::getPrimitiveNumber(ExecState
* exec
, double& number
, JSValue
& value
) 
 570         return asCell()->getPrimitiveNumber(exec
, number
, value
); 
 576     if (isFalse() || isNull()) { 
 581     ASSERT(isUndefined()); 
 587 ALWAYS_INLINE 
double JSValue::toNumber(ExecState
* exec
) const 
 593     return toNumberSlowCase(exec
); 
 596 inline JSObject
* JSValue::toObject(ExecState
* exec
) const 
 598     return isCell() ? asCell()->toObject(exec
, exec
->lexicalGlobalObject()) : toObjectSlowCase(exec
, exec
->lexicalGlobalObject()); 
 601 inline JSObject
* JSValue::toObject(ExecState
* exec
, JSGlobalObject
* globalObject
) const 
 603     return isCell() ? asCell()->toObject(exec
, globalObject
) : toObjectSlowCase(exec
, globalObject
); 
 606 inline bool JSValue::isFunction() const 
 608     return isCell() && (asCell()->inherits(&JSFunction::s_info
) || asCell()->inherits(&InternalFunction::s_info
)); 
 611 // this method is here to be after the inline declaration of JSCell::inherits 
 612 inline bool JSValue::inherits(const ClassInfo
* classInfo
) const 
 614     return isCell() && asCell()->inherits(classInfo
); 
 617 inline JSObject
* JSValue::toThisObject(ExecState
* exec
) const 
 619     return isCell() ? asCell()->methodTable()->toThisObject(asCell(), exec
) : toThisObjectSlowCase(exec
); 
 622 inline JSValue 
JSValue::get(ExecState
* exec
, PropertyName propertyName
) const 
 624     PropertySlot 
slot(asValue()); 
 625     return get(exec
, propertyName
, slot
); 
 628 inline JSValue 
JSValue::get(ExecState
* exec
, PropertyName propertyName
, PropertySlot
& slot
) const 
 630     if (UNLIKELY(!isCell())) { 
 631         JSObject
* prototype 
= synthesizePrototype(exec
); 
 632         if (!prototype
->getPropertySlot(exec
, propertyName
, slot
)) 
 633             return jsUndefined(); 
 634         return slot
.getValue(exec
, propertyName
); 
 636     JSCell
* cell 
= asCell(); 
 638         if (cell
->fastGetOwnPropertySlot(exec
, propertyName
, slot
)) 
 639             return slot
.getValue(exec
, propertyName
); 
 640         JSValue prototype 
= asObject(cell
)->prototype(); 
 641         if (!prototype
.isObject()) 
 642             return jsUndefined(); 
 643         cell 
= asObject(prototype
); 
 647 inline JSValue 
JSValue::get(ExecState
* exec
, unsigned propertyName
) const 
 649     PropertySlot 
slot(asValue()); 
 650     return get(exec
, propertyName
, slot
); 
 653 inline JSValue 
JSValue::get(ExecState
* exec
, unsigned propertyName
, PropertySlot
& slot
) const 
 655     if (UNLIKELY(!isCell())) { 
 656         JSObject
* prototype 
= synthesizePrototype(exec
); 
 657         if (!prototype
->getPropertySlot(exec
, propertyName
, slot
)) 
 658             return jsUndefined(); 
 659         return slot
.getValue(exec
, propertyName
); 
 661     JSCell
* cell 
= const_cast<JSCell
*>(asCell()); 
 663         if (cell
->methodTable()->getOwnPropertySlotByIndex(cell
, exec
, propertyName
, slot
)) 
 664             return slot
.getValue(exec
, propertyName
); 
 665         JSValue prototype 
= asObject(cell
)->prototype(); 
 666         if (!prototype
.isObject()) 
 667             return jsUndefined(); 
 668         cell 
= prototype
.asCell(); 
 672 inline void JSValue::put(ExecState
* exec
, PropertyName propertyName
, JSValue value
, PutPropertySlot
& slot
) 
 674     if (UNLIKELY(!isCell())) { 
 675         putToPrimitive(exec
, propertyName
, value
, slot
); 
 678     asCell()->methodTable()->put(asCell(), exec
, propertyName
, value
, slot
); 
 681 inline void JSValue::putByIndex(ExecState
* exec
, unsigned propertyName
, JSValue value
, bool shouldThrow
) 
 683     if (UNLIKELY(!isCell())) { 
 684         putToPrimitiveByIndex(exec
, propertyName
, value
, shouldThrow
); 
 687     asCell()->methodTable()->putByIndex(asCell(), exec
, propertyName
, value
, shouldThrow
); 
 690 inline JSValue 
JSValue::structureOrUndefined() const 
 693         return JSValue(asCell()->structure()); 
 694     return jsUndefined(); 
 698 inline bool JSValue::equal(ExecState
* exec
, JSValue v1
, JSValue v2
) 
 700     if (v1
.isInt32() && v2
.isInt32()) 
 703     return equalSlowCase(exec
, v1
, v2
); 
 706 ALWAYS_INLINE 
bool JSValue::equalSlowCaseInline(ExecState
* exec
, JSValue v1
, JSValue v2
) 
 709         if (v1
.isNumber() && v2
.isNumber()) 
 710             return v1
.asNumber() == v2
.asNumber(); 
 712         bool s1 
= v1
.isString(); 
 713         bool s2 
= v2
.isString(); 
 715             return asString(v1
)->value(exec
) == asString(v2
)->value(exec
); 
 717         if (v1
.isUndefinedOrNull()) { 
 718             if (v2
.isUndefinedOrNull()) 
 722             return v2
.asCell()->structure()->masqueradesAsUndefined(exec
->lexicalGlobalObject()); 
 725         if (v2
.isUndefinedOrNull()) { 
 728             return v1
.asCell()->structure()->masqueradesAsUndefined(exec
->lexicalGlobalObject()); 
 734             JSValue p1 
= v1
.toPrimitive(exec
); 
 735             if (exec
->hadException()) 
 738             if (v1
.isInt32() && v2
.isInt32()) 
 744             JSValue p2 
= v2
.toPrimitive(exec
); 
 745             if (exec
->hadException()) 
 748             if (v1
.isInt32() && v2
.isInt32()) 
 754             double d1 
= v1
.toNumber(exec
); 
 755             double d2 
= v2
.toNumber(exec
); 
 759         if (v1
.isBoolean()) { 
 761                 return static_cast<double>(v1
.asBoolean()) == v2
.asNumber(); 
 762         } else if (v2
.isBoolean()) { 
 764                 return v1
.asNumber() == static_cast<double>(v2
.asBoolean()); 
 772 ALWAYS_INLINE 
bool JSValue::strictEqualSlowCaseInline(ExecState
* exec
, JSValue v1
, JSValue v2
) 
 774     ASSERT(v1
.isCell() && v2
.isCell()); 
 776     if (v1
.asCell()->isString() && v2
.asCell()->isString()) 
 777         return asString(v1
)->value(exec
) == asString(v2
)->value(exec
); 
 782 inline bool JSValue::strictEqual(ExecState
* exec
, JSValue v1
, JSValue v2
) 
 784     if (v1
.isInt32() && v2
.isInt32()) 
 787     if (v1
.isNumber() && v2
.isNumber()) 
 788         return v1
.asNumber() == v2
.asNumber(); 
 790     if (!v1
.isCell() || !v2
.isCell()) 
 793     return strictEqualSlowCaseInline(exec
, v1
, v2
); 
 796 inline TriState 
JSValue::pureToBoolean() const 
 799         return asInt32() ? TrueTriState 
: FalseTriState
; 
 801         return isNotZeroAndOrdered(asDouble()) ? TrueTriState 
: FalseTriState
; // false for NaN 
 803         return asCell()->pureToBoolean(); 
 804     return isTrue() ? TrueTriState 
: FalseTriState
; 
 809 #endif // JSValueInlines_h