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"
33 #include <wtf/text/StringImpl.h>
37 ALWAYS_INLINE
int32_t JSValue::toInt32(ExecState
* exec
) const
41 return JSC::toInt32(toNumber(exec
));
44 inline uint32_t JSValue::toUInt32(ExecState
* exec
) const
46 // See comment on JSC::toUInt32, above.
50 inline bool JSValue::isUInt32() const
52 return isInt32() && asInt32() >= 0;
55 inline uint32_t JSValue::asUInt32() const
61 inline double JSValue::asNumber() const
64 return isInt32() ? asInt32() : asDouble();
67 inline JSValue
jsNaN()
72 inline JSValue::JSValue(char i
)
74 *this = JSValue(static_cast<int32_t>(i
));
77 inline JSValue::JSValue(unsigned char i
)
79 *this = JSValue(static_cast<int32_t>(i
));
82 inline JSValue::JSValue(short i
)
84 *this = JSValue(static_cast<int32_t>(i
));
87 inline JSValue::JSValue(unsigned short i
)
89 *this = JSValue(static_cast<int32_t>(i
));
92 inline JSValue::JSValue(unsigned i
)
94 if (static_cast<int32_t>(i
) < 0) {
95 *this = JSValue(EncodeAsDouble
, static_cast<double>(i
));
98 *this = JSValue(static_cast<int32_t>(i
));
101 inline JSValue::JSValue(long i
)
103 if (static_cast<int32_t>(i
) != i
) {
104 *this = JSValue(EncodeAsDouble
, static_cast<double>(i
));
107 *this = JSValue(static_cast<int32_t>(i
));
110 inline JSValue::JSValue(unsigned long i
)
112 if (static_cast<uint32_t>(i
) != i
) {
113 *this = JSValue(EncodeAsDouble
, static_cast<double>(i
));
116 *this = JSValue(static_cast<uint32_t>(i
));
119 inline JSValue::JSValue(long long i
)
121 if (static_cast<int32_t>(i
) != i
) {
122 *this = JSValue(EncodeAsDouble
, static_cast<double>(i
));
125 *this = JSValue(static_cast<int32_t>(i
));
128 inline JSValue::JSValue(unsigned long long i
)
130 if (static_cast<uint32_t>(i
) != i
) {
131 *this = JSValue(EncodeAsDouble
, static_cast<double>(i
));
134 *this = JSValue(static_cast<uint32_t>(i
));
137 inline JSValue::JSValue(double d
)
139 const int32_t asInt32
= static_cast<int32_t>(d
);
140 if (asInt32
!= d
|| (!asInt32
&& std::signbit(d
))) { // true for -0.0
141 *this = JSValue(EncodeAsDouble
, d
);
144 *this = JSValue(static_cast<int32_t>(d
));
147 inline EncodedJSValue
JSValue::encode(JSValue value
)
149 return value
.u
.asInt64
;
152 inline JSValue
JSValue::decode(EncodedJSValue encodedJSValue
)
155 v
.u
.asInt64
= encodedJSValue
;
159 #if USE(JSVALUE32_64)
160 inline JSValue::JSValue()
162 u
.asBits
.tag
= EmptyValueTag
;
163 u
.asBits
.payload
= 0;
166 inline JSValue::JSValue(JSNullTag
)
168 u
.asBits
.tag
= NullTag
;
169 u
.asBits
.payload
= 0;
172 inline JSValue::JSValue(JSUndefinedTag
)
174 u
.asBits
.tag
= UndefinedTag
;
175 u
.asBits
.payload
= 0;
178 inline JSValue::JSValue(JSTrueTag
)
180 u
.asBits
.tag
= BooleanTag
;
181 u
.asBits
.payload
= 1;
184 inline JSValue::JSValue(JSFalseTag
)
186 u
.asBits
.tag
= BooleanTag
;
187 u
.asBits
.payload
= 0;
190 inline JSValue::JSValue(HashTableDeletedValueTag
)
192 u
.asBits
.tag
= DeletedValueTag
;
193 u
.asBits
.payload
= 0;
196 inline JSValue::JSValue(JSCell
* ptr
)
199 u
.asBits
.tag
= CellTag
;
201 u
.asBits
.tag
= EmptyValueTag
;
202 u
.asBits
.payload
= reinterpret_cast<int32_t>(ptr
);
205 inline JSValue::JSValue(const JSCell
* ptr
)
208 u
.asBits
.tag
= CellTag
;
210 u
.asBits
.tag
= EmptyValueTag
;
211 u
.asBits
.payload
= reinterpret_cast<int32_t>(const_cast<JSCell
*>(ptr
));
214 inline JSValue::operator UnspecifiedBoolType
*() const
216 ASSERT(tag() != DeletedValueTag
);
217 return tag() != EmptyValueTag
? reinterpret_cast<UnspecifiedBoolType
*>(1) : 0;
220 inline bool JSValue::operator==(const JSValue
& other
) const
222 return u
.asInt64
== other
.u
.asInt64
;
225 inline bool JSValue::operator!=(const JSValue
& other
) const
227 return u
.asInt64
!= other
.u
.asInt64
;
230 inline bool JSValue::isEmpty() const
232 return tag() == EmptyValueTag
;
235 inline bool JSValue::isUndefined() const
237 return tag() == UndefinedTag
;
240 inline bool JSValue::isNull() const
242 return tag() == NullTag
;
245 inline bool JSValue::isUndefinedOrNull() const
247 return isUndefined() || isNull();
250 inline bool JSValue::isCell() const
252 return tag() == CellTag
;
255 inline bool JSValue::isInt32() const
257 return tag() == Int32Tag
;
260 inline bool JSValue::isDouble() const
262 return tag() < LowestTag
;
265 inline bool JSValue::isTrue() const
267 return tag() == BooleanTag
&& payload();
270 inline bool JSValue::isFalse() const
272 return tag() == BooleanTag
&& !payload();
275 inline uint32_t JSValue::tag() const
280 inline int32_t JSValue::payload() const
282 return u
.asBits
.payload
;
285 inline int32_t JSValue::asInt32() const
288 return u
.asBits
.payload
;
291 inline double JSValue::asDouble() const
297 ALWAYS_INLINE JSCell
* JSValue::asCell() const
300 return reinterpret_cast<JSCell
*>(u
.asBits
.payload
);
303 ALWAYS_INLINE
JSValue::JSValue(EncodeAsDoubleTag
, double d
)
305 ASSERT(!isImpureNaN(d
));
309 inline JSValue::JSValue(int i
)
311 u
.asBits
.tag
= Int32Tag
;
312 u
.asBits
.payload
= i
;
316 inline JSValue::JSValue(int32_t tag
, int32_t payload
)
319 u
.asBits
.payload
= payload
;
323 inline bool JSValue::isNumber() const
325 return isInt32() || isDouble();
328 inline bool JSValue::isBoolean() const
330 return isTrue() || isFalse();
333 inline bool JSValue::asBoolean() const
339 #else // !USE(JSVALUE32_64) i.e. USE(JSVALUE64)
341 // 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.
342 inline JSValue::JSValue()
344 u
.asInt64
= ValueEmpty
;
347 // 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.
348 inline JSValue::JSValue(HashTableDeletedValueTag
)
350 u
.asInt64
= ValueDeleted
;
353 inline JSValue::JSValue(JSCell
* ptr
)
355 u
.asInt64
= reinterpret_cast<uintptr_t>(ptr
);
358 inline JSValue::JSValue(const JSCell
* ptr
)
360 u
.asInt64
= reinterpret_cast<uintptr_t>(const_cast<JSCell
*>(ptr
));
363 inline JSValue::operator UnspecifiedBoolType
*() const
365 return u
.asInt64
? reinterpret_cast<UnspecifiedBoolType
*>(1) : 0;
368 inline bool JSValue::operator==(const JSValue
& other
) const
370 return u
.asInt64
== other
.u
.asInt64
;
373 inline bool JSValue::operator!=(const JSValue
& other
) const
375 return u
.asInt64
!= other
.u
.asInt64
;
378 inline bool JSValue::isEmpty() const
380 return u
.asInt64
== ValueEmpty
;
383 inline bool JSValue::isUndefined() const
385 return asValue() == JSValue(JSUndefined
);
388 inline bool JSValue::isNull() const
390 return asValue() == JSValue(JSNull
);
393 inline bool JSValue::isTrue() const
395 return asValue() == JSValue(JSTrue
);
398 inline bool JSValue::isFalse() const
400 return asValue() == JSValue(JSFalse
);
403 inline bool JSValue::asBoolean() const
406 return asValue() == JSValue(JSTrue
);
409 inline int32_t JSValue::asInt32() const
412 return static_cast<int32_t>(u
.asInt64
);
415 inline bool JSValue::isDouble() const
417 return isNumber() && !isInt32();
420 inline JSValue::JSValue(JSNullTag
)
422 u
.asInt64
= ValueNull
;
425 inline JSValue::JSValue(JSUndefinedTag
)
427 u
.asInt64
= ValueUndefined
;
430 inline JSValue::JSValue(JSTrueTag
)
432 u
.asInt64
= ValueTrue
;
435 inline JSValue::JSValue(JSFalseTag
)
437 u
.asInt64
= ValueFalse
;
440 inline bool JSValue::isUndefinedOrNull() const
442 // Undefined and null share the same value, bar the 'undefined' bit in the extended tag.
443 return (u
.asInt64
& ~TagBitUndefined
) == ValueNull
;
446 inline bool JSValue::isBoolean() const
448 return (u
.asInt64
& ~1) == ValueFalse
;
451 inline bool JSValue::isCell() const
453 return !(u
.asInt64
& TagMask
);
456 inline bool JSValue::isInt32() const
458 return (u
.asInt64
& TagTypeNumber
) == TagTypeNumber
;
461 inline int64_t reinterpretDoubleToInt64(double value
)
463 return bitwise_cast
<int64_t>(value
);
465 inline double reinterpretInt64ToDouble(int64_t value
)
467 return bitwise_cast
<double>(value
);
470 ALWAYS_INLINE
JSValue::JSValue(EncodeAsDoubleTag
, double d
)
472 ASSERT(!isImpureNaN(d
));
473 u
.asInt64
= reinterpretDoubleToInt64(d
) + DoubleEncodeOffset
;
476 inline JSValue::JSValue(int i
)
478 u
.asInt64
= TagTypeNumber
| static_cast<uint32_t>(i
);
481 inline double JSValue::asDouble() const
484 return reinterpretInt64ToDouble(u
.asInt64
- DoubleEncodeOffset
);
487 inline bool JSValue::isNumber() const
489 return u
.asInt64
& TagTypeNumber
;
492 ALWAYS_INLINE JSCell
* JSValue::asCell() const
498 #endif // USE(JSVALUE64)
500 inline int64_t tryConvertToInt52(double number
)
502 if (number
!= number
)
503 return JSValue::notInt52
;
504 #if OS(WINDOWS) && CPU(X86)
505 // The VS Compiler for 32-bit builds generates a floating point error when attempting to cast
506 // from an infinity to a 64-bit integer. We leave this routine with the floating point error
507 // left in a register, causing undefined behavior in later floating point operations.
509 // To avoid this issue, we check for infinity here, and return false in that case.
510 if (std::isinf(number
))
511 return JSValue::notInt52
;
513 int64_t asInt64
= static_cast<int64_t>(number
);
514 if (asInt64
!= number
)
515 return JSValue::notInt52
;
516 if (!asInt64
&& std::signbit(number
))
517 return JSValue::notInt52
;
518 if (asInt64
>= (static_cast<int64_t>(1) << (JSValue::numberOfInt52Bits
- 1)))
519 return JSValue::notInt52
;
520 if (asInt64
< -(static_cast<int64_t>(1) << (JSValue::numberOfInt52Bits
- 1)))
521 return JSValue::notInt52
;
525 inline bool isInt52(double number
)
527 return tryConvertToInt52(number
) != JSValue::notInt52
;
530 inline bool JSValue::isMachineInt() const
536 return isInt52(asDouble());
539 inline int64_t JSValue::asMachineInt() const
541 ASSERT(isMachineInt());
544 return static_cast<int64_t>(asDouble());
547 inline bool JSValue::isString() const
549 return isCell() && asCell()->isString();
552 inline bool JSValue::isPrimitive() const
554 return !isCell() || asCell()->isString();
557 inline bool JSValue::isGetterSetter() const
559 return isCell() && asCell()->isGetterSetter();
562 inline bool JSValue::isCustomGetterSetter() const
564 return isCell() && asCell()->isCustomGetterSetter();
567 inline bool JSValue::isObject() const
569 return isCell() && asCell()->isObject();
572 inline bool JSValue::getString(ExecState
* exec
, String
& s
) const
574 return isCell() && asCell()->getString(exec
, s
);
577 inline String
JSValue::getString(ExecState
* exec
) const
579 return isCell() ? asCell()->getString(exec
) : String();
582 template <typename Base
> String HandleConverter
<Base
, Unknown
>::getString(ExecState
* exec
) const
584 return jsValue().getString(exec
);
587 inline JSObject
* JSValue::getObject() const
589 return isCell() ? asCell()->getObject() : 0;
592 ALWAYS_INLINE
bool JSValue::getUInt32(uint32_t& v
) const
595 int32_t i
= asInt32();
596 v
= static_cast<uint32_t>(i
);
600 double d
= asDouble();
601 v
= static_cast<uint32_t>(d
);
607 inline JSValue
JSValue::toPrimitive(ExecState
* exec
, PreferredPrimitiveType preferredType
) const
609 return isCell() ? asCell()->toPrimitive(exec
, preferredType
) : asValue();
612 inline bool JSValue::getPrimitiveNumber(ExecState
* exec
, double& number
, JSValue
& value
)
625 return asCell()->getPrimitiveNumber(exec
, number
, value
);
631 if (isFalse() || isNull()) {
636 ASSERT(isUndefined());
642 ALWAYS_INLINE
double JSValue::toNumber(ExecState
* exec
) const
648 return toNumberSlowCase(exec
);
651 inline JSObject
* JSValue::toObject(ExecState
* exec
) const
653 return isCell() ? asCell()->toObject(exec
, exec
->lexicalGlobalObject()) : toObjectSlowCase(exec
, exec
->lexicalGlobalObject());
656 inline JSObject
* JSValue::toObject(ExecState
* exec
, JSGlobalObject
* globalObject
) const
658 return isCell() ? asCell()->toObject(exec
, globalObject
) : toObjectSlowCase(exec
, globalObject
);
661 inline bool JSValue::isFunction() const
663 return isCell() && (asCell()->inherits(JSFunction::info()) || asCell()->inherits(InternalFunction::info()));
666 // this method is here to be after the inline declaration of JSCell::inherits
667 inline bool JSValue::inherits(const ClassInfo
* classInfo
) const
669 return isCell() && asCell()->inherits(classInfo
);
672 inline JSValue
JSValue::toThis(ExecState
* exec
, ECMAMode ecmaMode
) const
674 return isCell() ? asCell()->methodTable(exec
->vm())->toThis(asCell(), exec
, ecmaMode
) : toThisSlowCase(exec
, ecmaMode
);
677 ALWAYS_INLINE JSValue
JSValue::get(ExecState
* exec
, PropertyName propertyName
) const
679 PropertySlot
slot(asValue());
680 return get(exec
, propertyName
, slot
);
683 ALWAYS_INLINE JSValue
JSValue::get(ExecState
* exec
, PropertyName propertyName
, PropertySlot
& slot
) const
685 // If this is a primitive, we'll need to synthesize the prototype -
686 // and if it's a string there are special properties to check first.
688 if (UNLIKELY(!isObject())) {
689 if (isCell() && asString(*this)->getStringPropertySlot(exec
, propertyName
, slot
))
690 return slot
.getValue(exec
, propertyName
);
691 object
= synthesizePrototype(exec
);
693 object
= asObject(asCell());
695 if (object
->getPropertySlot(exec
, propertyName
, slot
))
696 return slot
.getValue(exec
, propertyName
);
697 return jsUndefined();
700 ALWAYS_INLINE JSValue
JSValue::get(ExecState
* exec
, unsigned propertyName
) const
702 PropertySlot
slot(asValue());
703 return get(exec
, propertyName
, slot
);
706 ALWAYS_INLINE JSValue
JSValue::get(ExecState
* exec
, unsigned 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 (isCell() && asString(*this)->getStringPropertySlot(exec
, propertyName
, slot
))
713 return slot
.getValue(exec
, propertyName
);
714 object
= synthesizePrototype(exec
);
716 object
= asObject(asCell());
718 if (object
->getPropertySlot(exec
, propertyName
, slot
))
719 return slot
.getValue(exec
, propertyName
);
720 return jsUndefined();
723 inline void JSValue::put(ExecState
* exec
, PropertyName propertyName
, JSValue value
, PutPropertySlot
& slot
)
725 if (UNLIKELY(!isCell())) {
726 putToPrimitive(exec
, propertyName
, value
, slot
);
729 asCell()->methodTable(exec
->vm())->put(asCell(), exec
, propertyName
, value
, slot
);
732 inline void JSValue::putByIndex(ExecState
* exec
, unsigned propertyName
, JSValue value
, bool shouldThrow
)
734 if (UNLIKELY(!isCell())) {
735 putToPrimitiveByIndex(exec
, propertyName
, value
, shouldThrow
);
738 asCell()->methodTable(exec
->vm())->putByIndex(asCell(), exec
, propertyName
, value
, shouldThrow
);
741 inline JSValue
JSValue::structureOrUndefined() const
744 return JSValue(asCell()->structure());
745 return jsUndefined();
749 inline bool JSValue::equal(ExecState
* exec
, JSValue v1
, JSValue v2
)
751 if (v1
.isInt32() && v2
.isInt32())
754 return equalSlowCase(exec
, v1
, v2
);
757 ALWAYS_INLINE
bool JSValue::equalSlowCaseInline(ExecState
* exec
, JSValue v1
, JSValue v2
)
761 if (v1
.isNumber() && v2
.isNumber())
762 return v1
.asNumber() == v2
.asNumber();
764 bool s1
= v1
.isString();
765 bool s2
= v2
.isString();
767 return WTF::equal(*asString(v1
)->value(exec
).impl(), *asString(v2
)->value(exec
).impl());
769 if (v1
.isUndefinedOrNull()) {
770 if (v2
.isUndefinedOrNull())
774 return v2
.asCell()->structure(vm
)->masqueradesAsUndefined(exec
->lexicalGlobalObject());
777 if (v2
.isUndefinedOrNull()) {
780 return v1
.asCell()->structure(vm
)->masqueradesAsUndefined(exec
->lexicalGlobalObject());
786 JSValue p1
= v1
.toPrimitive(exec
);
787 if (exec
->hadException())
790 if (v1
.isInt32() && v2
.isInt32())
796 JSValue p2
= v2
.toPrimitive(exec
);
797 if (exec
->hadException())
800 if (v1
.isInt32() && v2
.isInt32())
806 double d1
= v1
.toNumber(exec
);
807 double d2
= v2
.toNumber(exec
);
811 if (v1
.isBoolean()) {
813 return static_cast<double>(v1
.asBoolean()) == v2
.asNumber();
814 } else if (v2
.isBoolean()) {
816 return v1
.asNumber() == static_cast<double>(v2
.asBoolean());
824 ALWAYS_INLINE
bool JSValue::strictEqualSlowCaseInline(ExecState
* exec
, JSValue v1
, JSValue v2
)
826 ASSERT(v1
.isCell() && v2
.isCell());
828 if (v1
.asCell()->isString() && v2
.asCell()->isString())
829 return WTF::equal(*asString(v1
)->value(exec
).impl(), *asString(v2
)->value(exec
).impl());
834 inline bool JSValue::strictEqual(ExecState
* exec
, JSValue v1
, JSValue v2
)
836 if (v1
.isInt32() && v2
.isInt32())
839 if (v1
.isNumber() && v2
.isNumber())
840 return v1
.asNumber() == v2
.asNumber();
842 if (!v1
.isCell() || !v2
.isCell())
845 return strictEqualSlowCaseInline(exec
, v1
, v2
);
848 inline int32_t JSValue::asInt32ForArithmetic() const
855 inline TriState
JSValue::pureStrictEqual(JSValue v1
, JSValue v2
)
857 if (v1
.isInt32() && v2
.isInt32())
858 return triState(v1
== v2
);
860 if (v1
.isNumber() && v2
.isNumber())
861 return triState(v1
.asNumber() == v2
.asNumber());
863 if (!v1
.isCell() || !v2
.isCell())
864 return triState(v1
== v2
);
866 if (v1
.asCell()->isString() && v2
.asCell()->isString()) {
867 const StringImpl
* v1String
= asString(v1
)->tryGetValueImpl();
868 const StringImpl
* v2String
= asString(v2
)->tryGetValueImpl();
869 if (!v1String
|| !v2String
)
870 return MixedTriState
;
871 return triState(WTF::equal(*v1String
, *v2String
));
874 return triState(v1
== v2
);
877 inline TriState
JSValue::pureToBoolean() const
880 return asInt32() ? TrueTriState
: FalseTriState
;
882 return isNotZeroAndOrdered(asDouble()) ? TrueTriState
: FalseTriState
; // false for NaN
884 return asCell()->pureToBoolean();
885 return isTrue() ? TrueTriState
: FalseTriState
;
890 #endif // JSValueInlines_h