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 "ExceptionHelpers.h"
30 #include "Identifier.h"
31 #include "InternalFunction.h"
32 #include "JSCJSValue.h"
33 #include "JSCellInlines.h"
34 #include "JSFunction.h"
35 #include <wtf/text/StringImpl.h>
39 ALWAYS_INLINE
int32_t JSValue::toInt32(ExecState
* exec
) const
43 return JSC::toInt32(toNumber(exec
));
46 inline uint32_t JSValue::toUInt32(ExecState
* exec
) const
48 // See comment on JSC::toUInt32, above.
52 inline bool JSValue::isUInt32() const
54 return isInt32() && asInt32() >= 0;
57 inline uint32_t JSValue::asUInt32() const
63 inline double JSValue::asNumber() const
66 return isInt32() ? asInt32() : asDouble();
69 inline JSValue
jsNaN()
74 inline JSValue::JSValue(char i
)
76 *this = JSValue(static_cast<int32_t>(i
));
79 inline JSValue::JSValue(unsigned char i
)
81 *this = JSValue(static_cast<int32_t>(i
));
84 inline JSValue::JSValue(short i
)
86 *this = JSValue(static_cast<int32_t>(i
));
89 inline JSValue::JSValue(unsigned short i
)
91 *this = JSValue(static_cast<int32_t>(i
));
94 inline JSValue::JSValue(unsigned i
)
96 if (static_cast<int32_t>(i
) < 0) {
97 *this = JSValue(EncodeAsDouble
, static_cast<double>(i
));
100 *this = JSValue(static_cast<int32_t>(i
));
103 inline JSValue::JSValue(long i
)
105 if (static_cast<int32_t>(i
) != i
) {
106 *this = JSValue(EncodeAsDouble
, static_cast<double>(i
));
109 *this = JSValue(static_cast<int32_t>(i
));
112 inline JSValue::JSValue(unsigned long i
)
114 if (static_cast<uint32_t>(i
) != i
) {
115 *this = JSValue(EncodeAsDouble
, static_cast<double>(i
));
118 *this = JSValue(static_cast<uint32_t>(i
));
121 inline JSValue::JSValue(long long i
)
123 if (static_cast<int32_t>(i
) != i
) {
124 *this = JSValue(EncodeAsDouble
, static_cast<double>(i
));
127 *this = JSValue(static_cast<int32_t>(i
));
130 inline JSValue::JSValue(unsigned long long i
)
132 if (static_cast<uint32_t>(i
) != i
) {
133 *this = JSValue(EncodeAsDouble
, static_cast<double>(i
));
136 *this = JSValue(static_cast<uint32_t>(i
));
139 inline JSValue::JSValue(double d
)
141 const int32_t asInt32
= static_cast<int32_t>(d
);
142 if (asInt32
!= d
|| (!asInt32
&& std::signbit(d
))) { // true for -0.0
143 *this = JSValue(EncodeAsDouble
, d
);
146 *this = JSValue(static_cast<int32_t>(d
));
149 inline EncodedJSValue
JSValue::encode(JSValue value
)
151 return value
.u
.asInt64
;
154 inline JSValue
JSValue::decode(EncodedJSValue encodedJSValue
)
157 v
.u
.asInt64
= encodedJSValue
;
161 #if USE(JSVALUE32_64)
162 inline JSValue::JSValue()
164 u
.asBits
.tag
= EmptyValueTag
;
165 u
.asBits
.payload
= 0;
168 inline JSValue::JSValue(JSNullTag
)
170 u
.asBits
.tag
= NullTag
;
171 u
.asBits
.payload
= 0;
174 inline JSValue::JSValue(JSUndefinedTag
)
176 u
.asBits
.tag
= UndefinedTag
;
177 u
.asBits
.payload
= 0;
180 inline JSValue::JSValue(JSTrueTag
)
182 u
.asBits
.tag
= BooleanTag
;
183 u
.asBits
.payload
= 1;
186 inline JSValue::JSValue(JSFalseTag
)
188 u
.asBits
.tag
= BooleanTag
;
189 u
.asBits
.payload
= 0;
192 inline JSValue::JSValue(HashTableDeletedValueTag
)
194 u
.asBits
.tag
= DeletedValueTag
;
195 u
.asBits
.payload
= 0;
198 inline JSValue::JSValue(JSCell
* ptr
)
201 u
.asBits
.tag
= CellTag
;
203 u
.asBits
.tag
= EmptyValueTag
;
204 u
.asBits
.payload
= reinterpret_cast<int32_t>(ptr
);
207 inline JSValue::JSValue(const JSCell
* ptr
)
210 u
.asBits
.tag
= CellTag
;
212 u
.asBits
.tag
= EmptyValueTag
;
213 u
.asBits
.payload
= reinterpret_cast<int32_t>(const_cast<JSCell
*>(ptr
));
216 inline JSValue::operator bool() const
218 ASSERT(tag() != DeletedValueTag
);
219 return tag() != EmptyValueTag
;
222 inline bool JSValue::operator==(const JSValue
& other
) const
224 return u
.asInt64
== other
.u
.asInt64
;
227 inline bool JSValue::operator!=(const JSValue
& other
) const
229 return u
.asInt64
!= other
.u
.asInt64
;
232 inline bool JSValue::isEmpty() const
234 return tag() == EmptyValueTag
;
237 inline bool JSValue::isUndefined() const
239 return tag() == UndefinedTag
;
242 inline bool JSValue::isNull() const
244 return tag() == NullTag
;
247 inline bool JSValue::isUndefinedOrNull() const
249 return isUndefined() || isNull();
252 inline bool JSValue::isCell() const
254 return tag() == CellTag
;
257 inline bool JSValue::isInt32() const
259 return tag() == Int32Tag
;
262 inline bool JSValue::isDouble() const
264 return tag() < LowestTag
;
267 inline bool JSValue::isTrue() const
269 return tag() == BooleanTag
&& payload();
272 inline bool JSValue::isFalse() const
274 return tag() == BooleanTag
&& !payload();
277 inline uint32_t JSValue::tag() const
282 inline int32_t JSValue::payload() const
284 return u
.asBits
.payload
;
287 inline int32_t JSValue::asInt32() const
290 return u
.asBits
.payload
;
293 inline double JSValue::asDouble() const
299 ALWAYS_INLINE JSCell
* JSValue::asCell() const
302 return reinterpret_cast<JSCell
*>(u
.asBits
.payload
);
305 ALWAYS_INLINE
JSValue::JSValue(EncodeAsDoubleTag
, double d
)
307 ASSERT(!isImpureNaN(d
));
311 inline JSValue::JSValue(int i
)
313 u
.asBits
.tag
= Int32Tag
;
314 u
.asBits
.payload
= i
;
318 inline JSValue::JSValue(int32_t tag
, int32_t payload
)
321 u
.asBits
.payload
= payload
;
325 inline bool JSValue::isNumber() const
327 return isInt32() || isDouble();
330 inline bool JSValue::isBoolean() const
332 return tag() == BooleanTag
;
335 inline bool JSValue::asBoolean() const
341 #else // !USE(JSVALUE32_64) i.e. USE(JSVALUE64)
343 // 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.
344 inline JSValue::JSValue()
346 u
.asInt64
= ValueEmpty
;
349 // 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.
350 inline JSValue::JSValue(HashTableDeletedValueTag
)
352 u
.asInt64
= ValueDeleted
;
355 inline JSValue::JSValue(JSCell
* ptr
)
357 u
.asInt64
= reinterpret_cast<uintptr_t>(ptr
);
360 inline JSValue::JSValue(const JSCell
* ptr
)
362 u
.asInt64
= reinterpret_cast<uintptr_t>(const_cast<JSCell
*>(ptr
));
365 inline JSValue::operator bool() const
370 inline bool JSValue::operator==(const JSValue
& other
) const
372 return u
.asInt64
== other
.u
.asInt64
;
375 inline bool JSValue::operator!=(const JSValue
& other
) const
377 return u
.asInt64
!= other
.u
.asInt64
;
380 inline bool JSValue::isEmpty() const
382 return u
.asInt64
== ValueEmpty
;
385 inline bool JSValue::isUndefined() const
387 return asValue() == JSValue(JSUndefined
);
390 inline bool JSValue::isNull() const
392 return asValue() == JSValue(JSNull
);
395 inline bool JSValue::isTrue() const
397 return asValue() == JSValue(JSTrue
);
400 inline bool JSValue::isFalse() const
402 return asValue() == JSValue(JSFalse
);
405 inline bool JSValue::asBoolean() const
408 return asValue() == JSValue(JSTrue
);
411 inline int32_t JSValue::asInt32() const
414 return static_cast<int32_t>(u
.asInt64
);
417 inline bool JSValue::isDouble() const
419 return isNumber() && !isInt32();
422 inline JSValue::JSValue(JSNullTag
)
424 u
.asInt64
= ValueNull
;
427 inline JSValue::JSValue(JSUndefinedTag
)
429 u
.asInt64
= ValueUndefined
;
432 inline JSValue::JSValue(JSTrueTag
)
434 u
.asInt64
= ValueTrue
;
437 inline JSValue::JSValue(JSFalseTag
)
439 u
.asInt64
= ValueFalse
;
442 inline bool JSValue::isUndefinedOrNull() const
444 // Undefined and null share the same value, bar the 'undefined' bit in the extended tag.
445 return (u
.asInt64
& ~TagBitUndefined
) == ValueNull
;
448 inline bool JSValue::isBoolean() const
450 return (u
.asInt64
& ~1) == ValueFalse
;
453 inline bool JSValue::isCell() const
455 return !(u
.asInt64
& TagMask
);
458 inline bool JSValue::isInt32() const
460 return (u
.asInt64
& TagTypeNumber
) == TagTypeNumber
;
463 inline int64_t reinterpretDoubleToInt64(double value
)
465 return bitwise_cast
<int64_t>(value
);
467 inline double reinterpretInt64ToDouble(int64_t value
)
469 return bitwise_cast
<double>(value
);
472 ALWAYS_INLINE
JSValue::JSValue(EncodeAsDoubleTag
, double d
)
474 ASSERT(!isImpureNaN(d
));
475 u
.asInt64
= reinterpretDoubleToInt64(d
) + DoubleEncodeOffset
;
478 inline JSValue::JSValue(int i
)
480 u
.asInt64
= TagTypeNumber
| static_cast<uint32_t>(i
);
483 inline double JSValue::asDouble() const
486 return reinterpretInt64ToDouble(u
.asInt64
- DoubleEncodeOffset
);
489 inline bool JSValue::isNumber() const
491 return u
.asInt64
& TagTypeNumber
;
494 ALWAYS_INLINE JSCell
* JSValue::asCell() const
500 #endif // USE(JSVALUE64)
502 inline int64_t tryConvertToInt52(double number
)
504 if (number
!= number
)
505 return JSValue::notInt52
;
506 #if OS(WINDOWS) && CPU(X86)
507 // The VS Compiler for 32-bit builds generates a floating point error when attempting to cast
508 // from an infinity to a 64-bit integer. We leave this routine with the floating point error
509 // left in a register, causing undefined behavior in later floating point operations.
511 // To avoid this issue, we check for infinity here, and return false in that case.
512 if (std::isinf(number
))
513 return JSValue::notInt52
;
515 int64_t asInt64
= static_cast<int64_t>(number
);
516 if (asInt64
!= number
)
517 return JSValue::notInt52
;
518 if (!asInt64
&& std::signbit(number
))
519 return JSValue::notInt52
;
520 if (asInt64
>= (static_cast<int64_t>(1) << (JSValue::numberOfInt52Bits
- 1)))
521 return JSValue::notInt52
;
522 if (asInt64
< -(static_cast<int64_t>(1) << (JSValue::numberOfInt52Bits
- 1)))
523 return JSValue::notInt52
;
527 inline bool isInt52(double number
)
529 return tryConvertToInt52(number
) != JSValue::notInt52
;
532 inline bool JSValue::isMachineInt() const
538 return isInt52(asDouble());
541 inline int64_t JSValue::asMachineInt() const
543 ASSERT(isMachineInt());
546 return static_cast<int64_t>(asDouble());
549 inline bool JSValue::isString() const
551 return isCell() && asCell()->isString();
554 inline bool JSValue::isSymbol() const
556 return isCell() && asCell()->isSymbol();
559 inline bool JSValue::isPrimitive() const
561 return !isCell() || asCell()->isString() || asCell()->isSymbol();
564 inline bool JSValue::isGetterSetter() const
566 return isCell() && asCell()->isGetterSetter();
569 inline bool JSValue::isCustomGetterSetter() const
571 return isCell() && asCell()->isCustomGetterSetter();
574 inline bool JSValue::isObject() const
576 return isCell() && asCell()->isObject();
579 inline bool JSValue::getString(ExecState
* exec
, String
& s
) const
581 return isCell() && asCell()->getString(exec
, s
);
584 inline String
JSValue::getString(ExecState
* exec
) const
586 return isCell() ? asCell()->getString(exec
) : String();
589 template <typename Base
> String HandleConverter
<Base
, Unknown
>::getString(ExecState
* exec
) const
591 return jsValue().getString(exec
);
594 inline JSObject
* JSValue::getObject() const
596 return isCell() ? asCell()->getObject() : 0;
599 ALWAYS_INLINE
bool JSValue::getUInt32(uint32_t& v
) const
602 int32_t i
= asInt32();
603 v
= static_cast<uint32_t>(i
);
607 double d
= asDouble();
608 v
= static_cast<uint32_t>(d
);
614 ALWAYS_INLINE Identifier
JSValue::toPropertyKey(ExecState
* exec
) const
617 return asString(*this)->toIdentifier(exec
);
619 JSValue primitive
= toPrimitive(exec
, PreferString
);
620 if (primitive
.isSymbol())
621 return Identifier::fromUid(asSymbol(primitive
)->privateName());
622 return primitive
.toString(exec
)->toIdentifier(exec
);
625 inline JSValue
JSValue::toPrimitive(ExecState
* exec
, PreferredPrimitiveType preferredType
) const
627 return isCell() ? asCell()->toPrimitive(exec
, preferredType
) : asValue();
630 inline bool JSValue::getPrimitiveNumber(ExecState
* exec
, double& number
, JSValue
& value
)
643 return asCell()->getPrimitiveNumber(exec
, number
, value
);
649 if (isFalse() || isNull()) {
654 ASSERT(isUndefined());
660 ALWAYS_INLINE
double JSValue::toNumber(ExecState
* exec
) const
666 return toNumberSlowCase(exec
);
669 inline JSObject
* JSValue::toObject(ExecState
* exec
) const
671 return isCell() ? asCell()->toObject(exec
, exec
->lexicalGlobalObject()) : toObjectSlowCase(exec
, exec
->lexicalGlobalObject());
674 inline JSObject
* JSValue::toObject(ExecState
* exec
, JSGlobalObject
* globalObject
) const
676 return isCell() ? asCell()->toObject(exec
, globalObject
) : toObjectSlowCase(exec
, globalObject
);
679 inline bool JSValue::isFunction() const
681 return isCell() && (asCell()->inherits(JSFunction::info()) || asCell()->inherits(InternalFunction::info()));
684 // this method is here to be after the inline declaration of JSCell::inherits
685 inline bool JSValue::inherits(const ClassInfo
* classInfo
) const
687 return isCell() && asCell()->inherits(classInfo
);
690 inline JSValue
JSValue::toThis(ExecState
* exec
, ECMAMode ecmaMode
) const
692 return isCell() ? asCell()->methodTable(exec
->vm())->toThis(asCell(), exec
, ecmaMode
) : toThisSlowCase(exec
, ecmaMode
);
695 ALWAYS_INLINE JSValue
JSValue::get(ExecState
* exec
, PropertyName propertyName
) const
697 PropertySlot
slot(asValue());
698 return get(exec
, propertyName
, slot
);
701 ALWAYS_INLINE JSValue
JSValue::get(ExecState
* exec
, PropertyName propertyName
, PropertySlot
& slot
) const
703 return getPropertySlot(exec
, propertyName
, slot
) ?
704 slot
.getValue(exec
, propertyName
) : jsUndefined();
707 ALWAYS_INLINE
bool JSValue::getPropertySlot(ExecState
* exec
, PropertyName propertyName
, PropertySlot
& slot
) const
709 // If this is a primitive, we'll need to synthesize the prototype -
710 // and if it's a string there are special properties to check first.
712 if (UNLIKELY(!isObject())) {
713 if (isString() && asString(*this)->getStringPropertySlot(exec
, propertyName
, slot
))
715 object
= synthesizePrototype(exec
);
717 object
= asObject(asCell());
719 return object
->getPropertySlot(exec
, propertyName
, slot
);
722 ALWAYS_INLINE JSValue
JSValue::get(ExecState
* exec
, unsigned propertyName
) const
724 PropertySlot
slot(asValue());
725 return get(exec
, propertyName
, slot
);
728 ALWAYS_INLINE JSValue
JSValue::get(ExecState
* exec
, unsigned propertyName
, PropertySlot
& slot
) const
730 // If this is a primitive, we'll need to synthesize the prototype -
731 // and if it's a string there are special properties to check first.
733 if (UNLIKELY(!isObject())) {
734 if (isString() && asString(*this)->getStringPropertySlot(exec
, propertyName
, slot
))
735 return slot
.getValue(exec
, propertyName
);
736 object
= synthesizePrototype(exec
);
738 object
= asObject(asCell());
740 if (object
->getPropertySlot(exec
, propertyName
, slot
))
741 return slot
.getValue(exec
, propertyName
);
742 return jsUndefined();
745 inline void JSValue::put(ExecState
* exec
, PropertyName propertyName
, JSValue value
, PutPropertySlot
& slot
)
747 if (UNLIKELY(!isCell())) {
748 putToPrimitive(exec
, propertyName
, value
, slot
);
751 asCell()->methodTable(exec
->vm())->put(asCell(), exec
, propertyName
, value
, slot
);
754 inline void JSValue::putByIndex(ExecState
* exec
, unsigned propertyName
, JSValue value
, bool shouldThrow
)
756 if (UNLIKELY(!isCell())) {
757 putToPrimitiveByIndex(exec
, propertyName
, value
, shouldThrow
);
760 asCell()->methodTable(exec
->vm())->putByIndex(asCell(), exec
, propertyName
, value
, shouldThrow
);
763 inline JSValue
JSValue::structureOrUndefined() const
766 return JSValue(asCell()->structure());
767 return jsUndefined();
771 inline bool JSValue::equal(ExecState
* exec
, JSValue v1
, JSValue v2
)
773 if (v1
.isInt32() && v2
.isInt32())
776 return equalSlowCase(exec
, v1
, v2
);
779 ALWAYS_INLINE
bool JSValue::equalSlowCaseInline(ExecState
* exec
, JSValue v1
, JSValue v2
)
783 if (v1
.isNumber() && v2
.isNumber())
784 return v1
.asNumber() == v2
.asNumber();
786 bool s1
= v1
.isString();
787 bool s2
= v2
.isString();
789 return WTF::equal(*asString(v1
)->value(exec
).impl(), *asString(v2
)->value(exec
).impl());
791 if (v1
.isUndefinedOrNull()) {
792 if (v2
.isUndefinedOrNull())
796 return v2
.asCell()->structure(vm
)->masqueradesAsUndefined(exec
->lexicalGlobalObject());
799 if (v2
.isUndefinedOrNull()) {
802 return v1
.asCell()->structure(vm
)->masqueradesAsUndefined(exec
->lexicalGlobalObject());
808 JSValue p1
= v1
.toPrimitive(exec
);
809 if (exec
->hadException())
812 if (v1
.isInt32() && v2
.isInt32())
818 JSValue p2
= v2
.toPrimitive(exec
);
819 if (exec
->hadException())
822 if (v1
.isInt32() && v2
.isInt32())
827 bool sym1
= v1
.isSymbol();
828 bool sym2
= v2
.isSymbol();
831 return asSymbol(v1
)->privateName() == asSymbol(v2
)->privateName();
836 double d1
= v1
.toNumber(exec
);
837 double d2
= v2
.toNumber(exec
);
841 if (v1
.isBoolean()) {
843 return static_cast<double>(v1
.asBoolean()) == v2
.asNumber();
844 } else if (v2
.isBoolean()) {
846 return v1
.asNumber() == static_cast<double>(v2
.asBoolean());
854 ALWAYS_INLINE
bool JSValue::strictEqualSlowCaseInline(ExecState
* exec
, JSValue v1
, JSValue v2
)
856 ASSERT(v1
.isCell() && v2
.isCell());
858 if (v1
.asCell()->isString() && v2
.asCell()->isString())
859 return WTF::equal(*asString(v1
)->value(exec
).impl(), *asString(v2
)->value(exec
).impl());
860 if (v1
.asCell()->isSymbol() && v2
.asCell()->isSymbol())
861 return asSymbol(v1
)->privateName() == asSymbol(v2
)->privateName();
866 inline bool JSValue::strictEqual(ExecState
* exec
, JSValue v1
, JSValue v2
)
868 if (v1
.isInt32() && v2
.isInt32())
871 if (v1
.isNumber() && v2
.isNumber())
872 return v1
.asNumber() == v2
.asNumber();
874 if (!v1
.isCell() || !v2
.isCell())
877 return strictEqualSlowCaseInline(exec
, v1
, v2
);
880 inline int32_t JSValue::asInt32ForArithmetic() const
887 inline TriState
JSValue::pureStrictEqual(JSValue v1
, JSValue v2
)
889 if (v1
.isInt32() && v2
.isInt32())
890 return triState(v1
== v2
);
892 if (v1
.isNumber() && v2
.isNumber())
893 return triState(v1
.asNumber() == v2
.asNumber());
895 if (!v1
.isCell() || !v2
.isCell())
896 return triState(v1
== v2
);
898 if (v1
.asCell()->isString() && v2
.asCell()->isString()) {
899 const StringImpl
* v1String
= asString(v1
)->tryGetValueImpl();
900 const StringImpl
* v2String
= asString(v2
)->tryGetValueImpl();
901 if (!v1String
|| !v2String
)
902 return MixedTriState
;
903 return triState(WTF::equal(*v1String
, *v2String
));
906 return triState(v1
== v2
);
909 inline TriState
JSValue::pureToBoolean() const
912 return asInt32() ? TrueTriState
: FalseTriState
;
914 return isNotZeroAndOrdered(asDouble()) ? TrueTriState
: FalseTriState
; // false for NaN
916 return asCell()->pureToBoolean();
917 return isTrue() ? TrueTriState
: FalseTriState
;
920 ALWAYS_INLINE
bool JSValue::requireObjectCoercible(ExecState
* exec
) const
922 if (!isUndefinedOrNull())
924 exec
->vm().throwException(exec
, createNotAnObjectError(exec
, *this));
930 #endif // JSValueInlines_h