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