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 "Identifier.h"
30 #include "InternalFunction.h"
31 #include "JSCJSValue.h"
32 #include "JSCellInlines.h"
33 #include "JSFunction.h"
34 #include <wtf/text/StringImpl.h>
38 ALWAYS_INLINE int32_t JSValue::toInt32(ExecState* exec) const
42 return JSC::toInt32(toNumber(exec));
45 inline uint32_t JSValue::toUInt32(ExecState* exec) const
47 // See comment on JSC::toUInt32, above.
51 inline bool JSValue::isUInt32() const
53 return isInt32() && asInt32() >= 0;
56 inline uint32_t JSValue::asUInt32() const
62 inline double JSValue::asNumber() const
65 return isInt32() ? asInt32() : asDouble();
68 inline JSValue jsNaN()
73 inline JSValue::JSValue(char i)
75 *this = JSValue(static_cast<int32_t>(i));
78 inline JSValue::JSValue(unsigned char i)
80 *this = JSValue(static_cast<int32_t>(i));
83 inline JSValue::JSValue(short i)
85 *this = JSValue(static_cast<int32_t>(i));
88 inline JSValue::JSValue(unsigned short i)
90 *this = JSValue(static_cast<int32_t>(i));
93 inline JSValue::JSValue(unsigned i)
95 if (static_cast<int32_t>(i) < 0) {
96 *this = JSValue(EncodeAsDouble, static_cast<double>(i));
99 *this = JSValue(static_cast<int32_t>(i));
102 inline JSValue::JSValue(long i)
104 if (static_cast<int32_t>(i) != i) {
105 *this = JSValue(EncodeAsDouble, static_cast<double>(i));
108 *this = JSValue(static_cast<int32_t>(i));
111 inline JSValue::JSValue(unsigned long i)
113 if (static_cast<uint32_t>(i) != i) {
114 *this = JSValue(EncodeAsDouble, static_cast<double>(i));
117 *this = JSValue(static_cast<uint32_t>(i));
120 inline JSValue::JSValue(long long i)
122 if (static_cast<int32_t>(i) != i) {
123 *this = JSValue(EncodeAsDouble, static_cast<double>(i));
126 *this = JSValue(static_cast<int32_t>(i));
129 inline JSValue::JSValue(unsigned long long i)
131 if (static_cast<uint32_t>(i) != i) {
132 *this = JSValue(EncodeAsDouble, static_cast<double>(i));
135 *this = JSValue(static_cast<uint32_t>(i));
138 inline JSValue::JSValue(double d)
140 const int32_t asInt32 = static_cast<int32_t>(d);
141 if (asInt32 != d || (!asInt32 && std::signbit(d))) { // true for -0.0
142 *this = JSValue(EncodeAsDouble, d);
145 *this = JSValue(static_cast<int32_t>(d));
148 inline EncodedJSValue JSValue::encode(JSValue value)
150 return value.u.asInt64;
153 inline JSValue JSValue::decode(EncodedJSValue encodedJSValue)
156 v.u.asInt64 = encodedJSValue;
160 #if USE(JSVALUE32_64)
161 inline JSValue::JSValue()
163 u.asBits.tag = EmptyValueTag;
164 u.asBits.payload = 0;
167 inline JSValue::JSValue(JSNullTag)
169 u.asBits.tag = NullTag;
170 u.asBits.payload = 0;
173 inline JSValue::JSValue(JSUndefinedTag)
175 u.asBits.tag = UndefinedTag;
176 u.asBits.payload = 0;
179 inline JSValue::JSValue(JSTrueTag)
181 u.asBits.tag = BooleanTag;
182 u.asBits.payload = 1;
185 inline JSValue::JSValue(JSFalseTag)
187 u.asBits.tag = BooleanTag;
188 u.asBits.payload = 0;
191 inline JSValue::JSValue(HashTableDeletedValueTag)
193 u.asBits.tag = DeletedValueTag;
194 u.asBits.payload = 0;
197 inline JSValue::JSValue(JSCell* ptr)
200 u.asBits.tag = CellTag;
202 u.asBits.tag = EmptyValueTag;
203 u.asBits.payload = reinterpret_cast<int32_t>(ptr);
206 inline JSValue::JSValue(const JSCell* ptr)
209 u.asBits.tag = CellTag;
211 u.asBits.tag = EmptyValueTag;
212 u.asBits.payload = reinterpret_cast<int32_t>(const_cast<JSCell*>(ptr));
215 inline JSValue::operator UnspecifiedBoolType*() const
217 ASSERT(tag() != DeletedValueTag);
218 return tag() != EmptyValueTag ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0;
221 inline bool JSValue::operator==(const JSValue& other) const
223 return u.asInt64 == other.u.asInt64;
226 inline bool JSValue::operator!=(const JSValue& other) const
228 return u.asInt64 != other.u.asInt64;
231 inline bool JSValue::isEmpty() const
233 return tag() == EmptyValueTag;
236 inline bool JSValue::isUndefined() const
238 return tag() == UndefinedTag;
241 inline bool JSValue::isNull() const
243 return tag() == NullTag;
246 inline bool JSValue::isUndefinedOrNull() const
248 return isUndefined() || isNull();
251 inline bool JSValue::isCell() const
253 return tag() == CellTag;
256 inline bool JSValue::isInt32() const
258 return tag() == Int32Tag;
261 inline bool JSValue::isDouble() const
263 return tag() < LowestTag;
266 inline bool JSValue::isTrue() const
268 return tag() == BooleanTag && payload();
271 inline bool JSValue::isFalse() const
273 return tag() == BooleanTag && !payload();
276 inline uint32_t JSValue::tag() const
281 inline int32_t JSValue::payload() const
283 return u.asBits.payload;
286 inline int32_t JSValue::asInt32() const
289 return u.asBits.payload;
292 inline double JSValue::asDouble() const
298 ALWAYS_INLINE JSCell* JSValue::asCell() const
301 return reinterpret_cast<JSCell*>(u.asBits.payload);
304 ALWAYS_INLINE JSValue::JSValue(EncodeAsDoubleTag, double d)
306 ASSERT(!isImpureNaN(d));
310 inline JSValue::JSValue(int i)
312 u.asBits.tag = Int32Tag;
313 u.asBits.payload = i;
317 inline JSValue::JSValue(int32_t tag, int32_t payload)
320 u.asBits.payload = payload;
324 inline bool JSValue::isNumber() const
326 return isInt32() || isDouble();
329 inline bool JSValue::isBoolean() const
331 return tag() == BooleanTag;
334 inline bool JSValue::asBoolean() const
340 #else // !USE(JSVALUE32_64) i.e. USE(JSVALUE64)
342 // 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.
343 inline JSValue::JSValue()
345 u.asInt64 = ValueEmpty;
348 // 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.
349 inline JSValue::JSValue(HashTableDeletedValueTag)
351 u.asInt64 = ValueDeleted;
354 inline JSValue::JSValue(JSCell* ptr)
356 u.asInt64 = reinterpret_cast<uintptr_t>(ptr);
359 inline JSValue::JSValue(const JSCell* ptr)
361 u.asInt64 = reinterpret_cast<uintptr_t>(const_cast<JSCell*>(ptr));
364 inline JSValue::operator UnspecifiedBoolType*() const
366 return u.asInt64 ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0;
369 inline bool JSValue::operator==(const JSValue& other) const
371 return u.asInt64 == other.u.asInt64;
374 inline bool JSValue::operator!=(const JSValue& other) const
376 return u.asInt64 != other.u.asInt64;
379 inline bool JSValue::isEmpty() const
381 return u.asInt64 == ValueEmpty;
384 inline bool JSValue::isUndefined() const
386 return asValue() == JSValue(JSUndefined);
389 inline bool JSValue::isNull() const
391 return asValue() == JSValue(JSNull);
394 inline bool JSValue::isTrue() const
396 return asValue() == JSValue(JSTrue);
399 inline bool JSValue::isFalse() const
401 return asValue() == JSValue(JSFalse);
404 inline bool JSValue::asBoolean() const
407 return asValue() == JSValue(JSTrue);
410 inline int32_t JSValue::asInt32() const
413 return static_cast<int32_t>(u.asInt64);
416 inline bool JSValue::isDouble() const
418 return isNumber() && !isInt32();
421 inline JSValue::JSValue(JSNullTag)
423 u.asInt64 = ValueNull;
426 inline JSValue::JSValue(JSUndefinedTag)
428 u.asInt64 = ValueUndefined;
431 inline JSValue::JSValue(JSTrueTag)
433 u.asInt64 = ValueTrue;
436 inline JSValue::JSValue(JSFalseTag)
438 u.asInt64 = ValueFalse;
441 inline bool JSValue::isUndefinedOrNull() const
443 // Undefined and null share the same value, bar the 'undefined' bit in the extended tag.
444 return (u.asInt64 & ~TagBitUndefined) == ValueNull;
447 inline bool JSValue::isBoolean() const
449 return (u.asInt64 & ~1) == ValueFalse;
452 inline bool JSValue::isCell() const
454 return !(u.asInt64 & TagMask);
457 inline bool JSValue::isInt32() const
459 return (u.asInt64 & TagTypeNumber) == TagTypeNumber;
462 inline int64_t reinterpretDoubleToInt64(double value)
464 return bitwise_cast<int64_t>(value);
466 inline double reinterpretInt64ToDouble(int64_t value)
468 return bitwise_cast<double>(value);
471 ALWAYS_INLINE JSValue::JSValue(EncodeAsDoubleTag, double d)
473 ASSERT(!isImpureNaN(d));
474 u.asInt64 = reinterpretDoubleToInt64(d) + DoubleEncodeOffset;
477 inline JSValue::JSValue(int i)
479 u.asInt64 = TagTypeNumber | static_cast<uint32_t>(i);
482 inline double JSValue::asDouble() const
485 return reinterpretInt64ToDouble(u.asInt64 - DoubleEncodeOffset);
488 inline bool JSValue::isNumber() const
490 return u.asInt64 & TagTypeNumber;
493 ALWAYS_INLINE JSCell* JSValue::asCell() const
499 #endif // USE(JSVALUE64)
501 inline int64_t tryConvertToInt52(double number)
503 if (number != number)
504 return JSValue::notInt52;
505 #if OS(WINDOWS) && CPU(X86)
506 // The VS Compiler for 32-bit builds generates a floating point error when attempting to cast
507 // from an infinity to a 64-bit integer. We leave this routine with the floating point error
508 // left in a register, causing undefined behavior in later floating point operations.
510 // To avoid this issue, we check for infinity here, and return false in that case.
511 if (std::isinf(number))
512 return JSValue::notInt52;
514 int64_t asInt64 = static_cast<int64_t>(number);
515 if (asInt64 != number)
516 return JSValue::notInt52;
517 if (!asInt64 && std::signbit(number))
518 return JSValue::notInt52;
519 if (asInt64 >= (static_cast<int64_t>(1) << (JSValue::numberOfInt52Bits - 1)))
520 return JSValue::notInt52;
521 if (asInt64 < -(static_cast<int64_t>(1) << (JSValue::numberOfInt52Bits - 1)))
522 return JSValue::notInt52;
526 inline bool isInt52(double number)
528 return tryConvertToInt52(number) != JSValue::notInt52;
531 inline bool JSValue::isMachineInt() const
537 return isInt52(asDouble());
540 inline int64_t JSValue::asMachineInt() const
542 ASSERT(isMachineInt());
545 return static_cast<int64_t>(asDouble());
548 inline bool JSValue::isString() const
550 return isCell() && asCell()->isString();
553 inline bool JSValue::isSymbol() const
555 return isCell() && asCell()->isSymbol();
558 inline bool JSValue::isPrimitive() const
560 return !isCell() || asCell()->isString() || asCell()->isSymbol();
563 inline bool JSValue::isGetterSetter() const
565 return isCell() && asCell()->isGetterSetter();
568 inline bool JSValue::isCustomGetterSetter() const
570 return isCell() && asCell()->isCustomGetterSetter();
573 inline bool JSValue::isObject() const
575 return isCell() && asCell()->isObject();
578 inline bool JSValue::getString(ExecState* exec, String& s) const
580 return isCell() && asCell()->getString(exec, s);
583 inline String JSValue::getString(ExecState* exec) const
585 return isCell() ? asCell()->getString(exec) : String();
588 template <typename Base> String HandleConverter<Base, Unknown>::getString(ExecState* exec) const
590 return jsValue().getString(exec);
593 inline JSObject* JSValue::getObject() const
595 return isCell() ? asCell()->getObject() : 0;
598 ALWAYS_INLINE bool JSValue::getUInt32(uint32_t& v) const
601 int32_t i = asInt32();
602 v = static_cast<uint32_t>(i);
606 double d = asDouble();
607 v = static_cast<uint32_t>(d);
613 ALWAYS_INLINE PropertyName JSValue::toPropertyKey(ExecState* exec) const
616 return asString(*this)->toIdentifier(exec);
618 JSValue primitive = toPrimitive(exec, PreferString);
619 if (primitive.isSymbol())
620 return asSymbol(primitive)->privateName();
621 return primitive.toString(exec)->toIdentifier(exec);
624 inline JSValue JSValue::toPrimitive(ExecState* exec, PreferredPrimitiveType preferredType) const
626 return isCell() ? asCell()->toPrimitive(exec, preferredType) : asValue();
629 inline bool JSValue::getPrimitiveNumber(ExecState* exec, double& number, JSValue& value)
642 return asCell()->getPrimitiveNumber(exec, number, value);
648 if (isFalse() || isNull()) {
653 ASSERT(isUndefined());
659 ALWAYS_INLINE double JSValue::toNumber(ExecState* exec) const
665 return toNumberSlowCase(exec);
668 inline JSObject* JSValue::toObject(ExecState* exec) const
670 return isCell() ? asCell()->toObject(exec, exec->lexicalGlobalObject()) : toObjectSlowCase(exec, exec->lexicalGlobalObject());
673 inline JSObject* JSValue::toObject(ExecState* exec, JSGlobalObject* globalObject) const
675 return isCell() ? asCell()->toObject(exec, globalObject) : toObjectSlowCase(exec, globalObject);
678 inline bool JSValue::isFunction() const
680 return isCell() && (asCell()->inherits(JSFunction::info()) || asCell()->inherits(InternalFunction::info()));
683 // this method is here to be after the inline declaration of JSCell::inherits
684 inline bool JSValue::inherits(const ClassInfo* classInfo) const
686 return isCell() && asCell()->inherits(classInfo);
689 inline JSValue JSValue::toThis(ExecState* exec, ECMAMode ecmaMode) const
691 return isCell() ? asCell()->methodTable(exec->vm())->toThis(asCell(), exec, ecmaMode) : toThisSlowCase(exec, ecmaMode);
694 ALWAYS_INLINE JSValue JSValue::get(ExecState* exec, PropertyName propertyName) const
696 PropertySlot slot(asValue());
697 return get(exec, propertyName, slot);
700 ALWAYS_INLINE JSValue JSValue::get(ExecState* exec, PropertyName propertyName, PropertySlot& slot) const
702 return getPropertySlot(exec, propertyName, slot) ?
703 slot.getValue(exec, propertyName) : jsUndefined();
706 ALWAYS_INLINE bool JSValue::getPropertySlot(ExecState* exec, PropertyName propertyName, PropertySlot& slot) const
708 // If this is a primitive, we'll need to synthesize the prototype -
709 // and if it's a string there are special properties to check first.
711 if (UNLIKELY(!isObject())) {
712 if (isString() && asString(*this)->getStringPropertySlot(exec, propertyName, slot))
714 object = synthesizePrototype(exec);
716 object = asObject(asCell());
718 return object->getPropertySlot(exec, propertyName, slot);
721 ALWAYS_INLINE JSValue JSValue::get(ExecState* exec, unsigned propertyName) const
723 PropertySlot slot(asValue());
724 return get(exec, propertyName, slot);
727 ALWAYS_INLINE JSValue JSValue::get(ExecState* exec, unsigned propertyName, PropertySlot& slot) const
729 // If this is a primitive, we'll need to synthesize the prototype -
730 // and if it's a string there are special properties to check first.
732 if (UNLIKELY(!isObject())) {
733 if (isString() && asString(*this)->getStringPropertySlot(exec, propertyName, slot))
734 return slot.getValue(exec, propertyName);
735 object = synthesizePrototype(exec);
737 object = asObject(asCell());
739 if (object->getPropertySlot(exec, propertyName, slot))
740 return slot.getValue(exec, propertyName);
741 return jsUndefined();
744 inline void JSValue::put(ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
746 if (UNLIKELY(!isCell())) {
747 putToPrimitive(exec, propertyName, value, slot);
750 asCell()->methodTable(exec->vm())->put(asCell(), exec, propertyName, value, slot);
753 inline void JSValue::putByIndex(ExecState* exec, unsigned propertyName, JSValue value, bool shouldThrow)
755 if (UNLIKELY(!isCell())) {
756 putToPrimitiveByIndex(exec, propertyName, value, shouldThrow);
759 asCell()->methodTable(exec->vm())->putByIndex(asCell(), exec, propertyName, value, shouldThrow);
762 inline JSValue JSValue::structureOrUndefined() const
765 return JSValue(asCell()->structure());
766 return jsUndefined();
770 inline bool JSValue::equal(ExecState* exec, JSValue v1, JSValue v2)
772 if (v1.isInt32() && v2.isInt32())
775 return equalSlowCase(exec, v1, v2);
778 ALWAYS_INLINE bool JSValue::equalSlowCaseInline(ExecState* exec, JSValue v1, JSValue v2)
782 if (v1.isNumber() && v2.isNumber())
783 return v1.asNumber() == v2.asNumber();
785 bool s1 = v1.isString();
786 bool s2 = v2.isString();
788 return WTF::equal(*asString(v1)->value(exec).impl(), *asString(v2)->value(exec).impl());
790 if (v1.isUndefinedOrNull()) {
791 if (v2.isUndefinedOrNull())
795 return v2.asCell()->structure(vm)->masqueradesAsUndefined(exec->lexicalGlobalObject());
798 if (v2.isUndefinedOrNull()) {
801 return v1.asCell()->structure(vm)->masqueradesAsUndefined(exec->lexicalGlobalObject());
807 JSValue p1 = v1.toPrimitive(exec);
808 if (exec->hadException())
811 if (v1.isInt32() && v2.isInt32())
817 JSValue p2 = v2.toPrimitive(exec);
818 if (exec->hadException())
821 if (v1.isInt32() && v2.isInt32())
826 bool sym1 = v1.isSymbol();
827 bool sym2 = v2.isSymbol();
830 return asSymbol(v1)->privateName() == asSymbol(v2)->privateName();
835 double d1 = v1.toNumber(exec);
836 double d2 = v2.toNumber(exec);
840 if (v1.isBoolean()) {
842 return static_cast<double>(v1.asBoolean()) == v2.asNumber();
843 } else if (v2.isBoolean()) {
845 return v1.asNumber() == static_cast<double>(v2.asBoolean());
853 ALWAYS_INLINE bool JSValue::strictEqualSlowCaseInline(ExecState* exec, JSValue v1, JSValue v2)
855 ASSERT(v1.isCell() && v2.isCell());
857 if (v1.asCell()->isString() && v2.asCell()->isString())
858 return WTF::equal(*asString(v1)->value(exec).impl(), *asString(v2)->value(exec).impl());
859 if (v1.asCell()->isSymbol() && v2.asCell()->isSymbol())
860 return asSymbol(v1)->privateName() == asSymbol(v2)->privateName();
865 inline bool JSValue::strictEqual(ExecState* exec, JSValue v1, JSValue v2)
867 if (v1.isInt32() && v2.isInt32())
870 if (v1.isNumber() && v2.isNumber())
871 return v1.asNumber() == v2.asNumber();
873 if (!v1.isCell() || !v2.isCell())
876 return strictEqualSlowCaseInline(exec, v1, v2);
879 inline int32_t JSValue::asInt32ForArithmetic() const
886 inline TriState JSValue::pureStrictEqual(JSValue v1, JSValue v2)
888 if (v1.isInt32() && v2.isInt32())
889 return triState(v1 == v2);
891 if (v1.isNumber() && v2.isNumber())
892 return triState(v1.asNumber() == v2.asNumber());
894 if (!v1.isCell() || !v2.isCell())
895 return triState(v1 == v2);
897 if (v1.asCell()->isString() && v2.asCell()->isString()) {
898 const StringImpl* v1String = asString(v1)->tryGetValueImpl();
899 const StringImpl* v2String = asString(v2)->tryGetValueImpl();
900 if (!v1String || !v2String)
901 return MixedTriState;
902 return triState(WTF::equal(*v1String, *v2String));
905 return triState(v1 == v2);
908 inline TriState JSValue::pureToBoolean() const
911 return asInt32() ? TrueTriState : FalseTriState;
913 return isNotZeroAndOrdered(asDouble()) ? TrueTriState : FalseTriState; // false for NaN
915 return asCell()->pureToBoolean();
916 return isTrue() ? TrueTriState : FalseTriState;
921 #endif // JSValueInlines_h