123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813 |
- /*
- * Copyright (C) 2011, 2012 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- #ifndef JSValueInlines_h
- #define JSValueInlines_h
- #include "InternalFunction.h"
- #include "JSCJSValue.h"
- #include "JSCellInlines.h"
- #include "JSFunction.h"
- namespace JSC {
- ALWAYS_INLINE int32_t JSValue::toInt32(ExecState* exec) const
- {
- if (isInt32())
- return asInt32();
- return JSC::toInt32(toNumber(exec));
- }
- inline uint32_t JSValue::toUInt32(ExecState* exec) const
- {
- // See comment on JSC::toUInt32, above.
- return toInt32(exec);
- }
- inline bool JSValue::isUInt32() const
- {
- return isInt32() && asInt32() >= 0;
- }
- inline uint32_t JSValue::asUInt32() const
- {
- ASSERT(isUInt32());
- return asInt32();
- }
- inline double JSValue::asNumber() const
- {
- ASSERT(isNumber());
- return isInt32() ? asInt32() : asDouble();
- }
- inline JSValue jsNaN()
- {
- return JSValue(QNaN);
- }
- inline JSValue::JSValue(char i)
- {
- *this = JSValue(static_cast<int32_t>(i));
- }
- inline JSValue::JSValue(unsigned char i)
- {
- *this = JSValue(static_cast<int32_t>(i));
- }
- inline JSValue::JSValue(short i)
- {
- *this = JSValue(static_cast<int32_t>(i));
- }
- inline JSValue::JSValue(unsigned short i)
- {
- *this = JSValue(static_cast<int32_t>(i));
- }
- inline JSValue::JSValue(unsigned i)
- {
- if (static_cast<int32_t>(i) < 0) {
- *this = JSValue(EncodeAsDouble, static_cast<double>(i));
- return;
- }
- *this = JSValue(static_cast<int32_t>(i));
- }
- inline JSValue::JSValue(long i)
- {
- if (static_cast<int32_t>(i) != i) {
- *this = JSValue(EncodeAsDouble, static_cast<double>(i));
- return;
- }
- *this = JSValue(static_cast<int32_t>(i));
- }
- inline JSValue::JSValue(unsigned long i)
- {
- if (static_cast<uint32_t>(i) != i) {
- *this = JSValue(EncodeAsDouble, static_cast<double>(i));
- return;
- }
- *this = JSValue(static_cast<uint32_t>(i));
- }
- inline JSValue::JSValue(long long i)
- {
- if (static_cast<int32_t>(i) != i) {
- *this = JSValue(EncodeAsDouble, static_cast<double>(i));
- return;
- }
- *this = JSValue(static_cast<int32_t>(i));
- }
- inline JSValue::JSValue(unsigned long long i)
- {
- if (static_cast<uint32_t>(i) != i) {
- *this = JSValue(EncodeAsDouble, static_cast<double>(i));
- return;
- }
- *this = JSValue(static_cast<uint32_t>(i));
- }
- inline JSValue::JSValue(double d)
- {
- const int32_t asInt32 = static_cast<int32_t>(d);
- if (asInt32 != d || (!asInt32 && std::signbit(d))) { // true for -0.0
- *this = JSValue(EncodeAsDouble, d);
- return;
- }
- *this = JSValue(static_cast<int32_t>(d));
- }
- inline EncodedJSValue JSValue::encode(JSValue value)
- {
- return value.u.asInt64;
- }
- inline JSValue JSValue::decode(EncodedJSValue encodedJSValue)
- {
- JSValue v;
- v.u.asInt64 = encodedJSValue;
- return v;
- }
- #if USE(JSVALUE32_64)
- inline JSValue::JSValue()
- {
- u.asBits.tag = EmptyValueTag;
- u.asBits.payload = 0;
- }
- inline JSValue::JSValue(JSNullTag)
- {
- u.asBits.tag = NullTag;
- u.asBits.payload = 0;
- }
-
- inline JSValue::JSValue(JSUndefinedTag)
- {
- u.asBits.tag = UndefinedTag;
- u.asBits.payload = 0;
- }
-
- inline JSValue::JSValue(JSTrueTag)
- {
- u.asBits.tag = BooleanTag;
- u.asBits.payload = 1;
- }
-
- inline JSValue::JSValue(JSFalseTag)
- {
- u.asBits.tag = BooleanTag;
- u.asBits.payload = 0;
- }
- inline JSValue::JSValue(HashTableDeletedValueTag)
- {
- u.asBits.tag = DeletedValueTag;
- u.asBits.payload = 0;
- }
- inline JSValue::JSValue(JSCell* ptr)
- {
- if (ptr)
- u.asBits.tag = CellTag;
- else
- u.asBits.tag = EmptyValueTag;
- u.asBits.payload = reinterpret_cast<int32_t>(ptr);
- }
- inline JSValue::JSValue(const JSCell* ptr)
- {
- if (ptr)
- u.asBits.tag = CellTag;
- else
- u.asBits.tag = EmptyValueTag;
- u.asBits.payload = reinterpret_cast<int32_t>(const_cast<JSCell*>(ptr));
- }
- inline JSValue::operator bool() const
- {
- ASSERT(tag() != DeletedValueTag);
- return tag() != EmptyValueTag;
- }
- inline bool JSValue::operator==(const JSValue& other) const
- {
- return u.asInt64 == other.u.asInt64;
- }
- inline bool JSValue::operator!=(const JSValue& other) const
- {
- return u.asInt64 != other.u.asInt64;
- }
- inline bool JSValue::isEmpty() const
- {
- return tag() == EmptyValueTag;
- }
- inline bool JSValue::isUndefined() const
- {
- return tag() == UndefinedTag;
- }
- inline bool JSValue::isNull() const
- {
- return tag() == NullTag;
- }
- inline bool JSValue::isUndefinedOrNull() const
- {
- return isUndefined() || isNull();
- }
- inline bool JSValue::isCell() const
- {
- return tag() == CellTag;
- }
- inline bool JSValue::isInt32() const
- {
- return tag() == Int32Tag;
- }
- inline bool JSValue::isDouble() const
- {
- return tag() < LowestTag;
- }
- inline bool JSValue::isTrue() const
- {
- return tag() == BooleanTag && payload();
- }
- inline bool JSValue::isFalse() const
- {
- return tag() == BooleanTag && !payload();
- }
- inline uint32_t JSValue::tag() const
- {
- return u.asBits.tag;
- }
-
- inline int32_t JSValue::payload() const
- {
- return u.asBits.payload;
- }
-
- inline int32_t JSValue::asInt32() const
- {
- ASSERT(isInt32());
- return u.asBits.payload;
- }
-
- inline double JSValue::asDouble() const
- {
- ASSERT(isDouble());
- return u.asDouble;
- }
-
- ALWAYS_INLINE JSCell* JSValue::asCell() const
- {
- ASSERT(isCell());
- return reinterpret_cast<JSCell*>(u.asBits.payload);
- }
- ALWAYS_INLINE JSValue::JSValue(EncodeAsDoubleTag, double d)
- {
- u.asDouble = d;
- }
- inline JSValue::JSValue(int i)
- {
- u.asBits.tag = Int32Tag;
- u.asBits.payload = i;
- }
- #if ENABLE(LLINT_C_LOOP)
- inline JSValue::JSValue(int32_t tag, int32_t payload)
- {
- u.asBits.tag = tag;
- u.asBits.payload = payload;
- }
- #endif
- inline bool JSValue::isNumber() const
- {
- return isInt32() || isDouble();
- }
- inline bool JSValue::isBoolean() const
- {
- return isTrue() || isFalse();
- }
- inline bool JSValue::asBoolean() const
- {
- ASSERT(isBoolean());
- return payload();
- }
- #else // !USE(JSVALUE32_64) i.e. USE(JSVALUE64)
- // 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.
- inline JSValue::JSValue()
- {
- u.asInt64 = ValueEmpty;
- }
- // 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.
- inline JSValue::JSValue(HashTableDeletedValueTag)
- {
- u.asInt64 = ValueDeleted;
- }
- inline JSValue::JSValue(JSCell* ptr)
- {
- u.asInt64 = reinterpret_cast<uintptr_t>(ptr);
- }
- inline JSValue::JSValue(const JSCell* ptr)
- {
- u.asInt64 = reinterpret_cast<uintptr_t>(const_cast<JSCell*>(ptr));
- }
- inline JSValue::operator bool() const
- {
- return u.asInt64;
- }
- inline bool JSValue::operator==(const JSValue& other) const
- {
- return u.asInt64 == other.u.asInt64;
- }
- inline bool JSValue::operator!=(const JSValue& other) const
- {
- return u.asInt64 != other.u.asInt64;
- }
- inline bool JSValue::isEmpty() const
- {
- return u.asInt64 == ValueEmpty;
- }
- inline bool JSValue::isUndefined() const
- {
- return asValue() == JSValue(JSUndefined);
- }
- inline bool JSValue::isNull() const
- {
- return asValue() == JSValue(JSNull);
- }
- inline bool JSValue::isTrue() const
- {
- return asValue() == JSValue(JSTrue);
- }
- inline bool JSValue::isFalse() const
- {
- return asValue() == JSValue(JSFalse);
- }
- inline bool JSValue::asBoolean() const
- {
- ASSERT(isBoolean());
- return asValue() == JSValue(JSTrue);
- }
- inline int32_t JSValue::asInt32() const
- {
- ASSERT(isInt32());
- return static_cast<int32_t>(u.asInt64);
- }
- inline bool JSValue::isDouble() const
- {
- return isNumber() && !isInt32();
- }
- inline JSValue::JSValue(JSNullTag)
- {
- u.asInt64 = ValueNull;
- }
-
- inline JSValue::JSValue(JSUndefinedTag)
- {
- u.asInt64 = ValueUndefined;
- }
- inline JSValue::JSValue(JSTrueTag)
- {
- u.asInt64 = ValueTrue;
- }
- inline JSValue::JSValue(JSFalseTag)
- {
- u.asInt64 = ValueFalse;
- }
- inline bool JSValue::isUndefinedOrNull() const
- {
- // Undefined and null share the same value, bar the 'undefined' bit in the extended tag.
- return (u.asInt64 & ~TagBitUndefined) == ValueNull;
- }
- inline bool JSValue::isBoolean() const
- {
- return (u.asInt64 & ~1) == ValueFalse;
- }
- inline bool JSValue::isCell() const
- {
- return !(u.asInt64 & TagMask);
- }
- inline bool JSValue::isInt32() const
- {
- return (u.asInt64 & TagTypeNumber) == TagTypeNumber;
- }
- inline int64_t reinterpretDoubleToInt64(double value)
- {
- return bitwise_cast<int64_t>(value);
- }
- inline double reinterpretInt64ToDouble(int64_t value)
- {
- return bitwise_cast<double>(value);
- }
- ALWAYS_INLINE JSValue::JSValue(EncodeAsDoubleTag, double d)
- {
- u.asInt64 = reinterpretDoubleToInt64(d) + DoubleEncodeOffset;
- }
- inline JSValue::JSValue(int i)
- {
- u.asInt64 = TagTypeNumber | static_cast<uint32_t>(i);
- }
- inline double JSValue::asDouble() const
- {
- ASSERT(isDouble());
- return reinterpretInt64ToDouble(u.asInt64 - DoubleEncodeOffset);
- }
- inline bool JSValue::isNumber() const
- {
- return u.asInt64 & TagTypeNumber;
- }
- ALWAYS_INLINE JSCell* JSValue::asCell() const
- {
- ASSERT(isCell());
- return u.ptr;
- }
- #endif // USE(JSVALUE64)
- inline bool JSValue::isString() const
- {
- return isCell() && asCell()->isString();
- }
- inline bool JSValue::isPrimitive() const
- {
- return !isCell() || asCell()->isString();
- }
- inline bool JSValue::isGetterSetter() const
- {
- return isCell() && asCell()->isGetterSetter();
- }
- inline bool JSValue::isObject() const
- {
- return isCell() && asCell()->isObject();
- }
- inline bool JSValue::getString(ExecState* exec, String& s) const
- {
- return isCell() && asCell()->getString(exec, s);
- }
- inline String JSValue::getString(ExecState* exec) const
- {
- return isCell() ? asCell()->getString(exec) : String();
- }
- template <typename Base> String HandleConverter<Base, Unknown>::getString(ExecState* exec) const
- {
- return jsValue().getString(exec);
- }
- inline JSObject* JSValue::getObject() const
- {
- return isCell() ? asCell()->getObject() : 0;
- }
- ALWAYS_INLINE bool JSValue::getUInt32(uint32_t& v) const
- {
- if (isInt32()) {
- int32_t i = asInt32();
- v = static_cast<uint32_t>(i);
- return i >= 0;
- }
- if (isDouble()) {
- double d = asDouble();
- v = static_cast<uint32_t>(d);
- return v == d;
- }
- return false;
- }
- inline JSValue JSValue::toPrimitive(ExecState* exec, PreferredPrimitiveType preferredType) const
- {
- return isCell() ? asCell()->toPrimitive(exec, preferredType) : asValue();
- }
- inline bool JSValue::getPrimitiveNumber(ExecState* exec, double& number, JSValue& value)
- {
- if (isInt32()) {
- number = asInt32();
- value = *this;
- return true;
- }
- if (isDouble()) {
- number = asDouble();
- value = *this;
- return true;
- }
- if (isCell())
- return asCell()->getPrimitiveNumber(exec, number, value);
- if (isTrue()) {
- number = 1.0;
- value = *this;
- return true;
- }
- if (isFalse() || isNull()) {
- number = 0.0;
- value = *this;
- return true;
- }
- ASSERT(isUndefined());
- number = QNaN;
- value = *this;
- return true;
- }
- ALWAYS_INLINE double JSValue::toNumber(ExecState* exec) const
- {
- if (isInt32())
- return asInt32();
- if (isDouble())
- return asDouble();
- return toNumberSlowCase(exec);
- }
- inline JSObject* JSValue::toObject(ExecState* exec) const
- {
- return isCell() ? asCell()->toObject(exec, exec->lexicalGlobalObject()) : toObjectSlowCase(exec, exec->lexicalGlobalObject());
- }
- inline JSObject* JSValue::toObject(ExecState* exec, JSGlobalObject* globalObject) const
- {
- return isCell() ? asCell()->toObject(exec, globalObject) : toObjectSlowCase(exec, globalObject);
- }
- inline bool JSValue::isFunction() const
- {
- DEFINE_STATIC_CLASSINFO(JSFunction);
- DEFINE_STATIC_CLASSINFO(InternalFunction);
- return isCell() && (asCell()->inherits(sJSFunctionClassInfo) || asCell()->inherits(sInternalFunctionClassInfo));
- }
- // this method is here to be after the inline declaration of JSCell::inherits
- inline bool JSValue::inherits(const ClassInfo* classInfo) const
- {
- return isCell() && asCell()->inherits(classInfo);
- }
- inline JSObject* JSValue::toThisObject(ExecState* exec) const
- {
- return isCell() ? asCell()->methodTable()->toThisObject(asCell(), exec) : toThisObjectSlowCase(exec);
- }
- inline JSValue JSValue::get(ExecState* exec, PropertyName propertyName) const
- {
- PropertySlot slot(asValue());
- return get(exec, propertyName, slot);
- }
- inline JSValue JSValue::get(ExecState* exec, PropertyName propertyName, PropertySlot& slot) const
- {
- if (UNLIKELY(!isCell())) {
- JSObject* prototype = synthesizePrototype(exec);
- if (!prototype->getPropertySlot(exec, propertyName, slot))
- return jsUndefined();
- return slot.getValue(exec, propertyName);
- }
- JSCell* cell = asCell();
- while (true) {
- if (cell->fastGetOwnPropertySlot(exec, propertyName, slot))
- return slot.getValue(exec, propertyName);
- JSValue prototype = asObject(cell)->prototype();
- if (!prototype.isObject())
- return jsUndefined();
- cell = asObject(prototype);
- }
- }
- inline JSValue JSValue::get(ExecState* exec, unsigned propertyName) const
- {
- PropertySlot slot(asValue());
- return get(exec, propertyName, slot);
- }
- inline JSValue JSValue::get(ExecState* exec, unsigned propertyName, PropertySlot& slot) const
- {
- if (UNLIKELY(!isCell())) {
- JSObject* prototype = synthesizePrototype(exec);
- if (!prototype->getPropertySlot(exec, propertyName, slot))
- return jsUndefined();
- return slot.getValue(exec, propertyName);
- }
- JSCell* cell = const_cast<JSCell*>(asCell());
- while (true) {
- if (cell->methodTable()->getOwnPropertySlotByIndex(cell, exec, propertyName, slot))
- return slot.getValue(exec, propertyName);
- JSValue prototype = asObject(cell)->prototype();
- if (!prototype.isObject())
- return jsUndefined();
- cell = prototype.asCell();
- }
- }
- inline void JSValue::put(ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
- {
- if (UNLIKELY(!isCell())) {
- putToPrimitive(exec, propertyName, value, slot);
- return;
- }
- asCell()->methodTable()->put(asCell(), exec, propertyName, value, slot);
- }
- inline void JSValue::putByIndex(ExecState* exec, unsigned propertyName, JSValue value, bool shouldThrow)
- {
- if (UNLIKELY(!isCell())) {
- putToPrimitiveByIndex(exec, propertyName, value, shouldThrow);
- return;
- }
- asCell()->methodTable()->putByIndex(asCell(), exec, propertyName, value, shouldThrow);
- }
- inline JSValue JSValue::structureOrUndefined() const
- {
- if (isCell())
- return JSValue(asCell()->structure());
- return jsUndefined();
- }
- // ECMA 11.9.3
- inline bool JSValue::equal(ExecState* exec, JSValue v1, JSValue v2)
- {
- if (v1.isInt32() && v2.isInt32())
- return v1 == v2;
- return equalSlowCase(exec, v1, v2);
- }
- ALWAYS_INLINE bool JSValue::equalSlowCaseInline(ExecState* exec, JSValue v1, JSValue v2)
- {
- do {
- if (v1.isNumber() && v2.isNumber())
- return v1.asNumber() == v2.asNumber();
- bool s1 = v1.isString();
- bool s2 = v2.isString();
- if (s1 && s2)
- return asString(v1)->value(exec) == asString(v2)->value(exec);
- if (v1.isUndefinedOrNull()) {
- if (v2.isUndefinedOrNull())
- return true;
- if (!v2.isCell())
- return false;
- return v2.asCell()->structure()->masqueradesAsUndefined(exec->lexicalGlobalObject());
- }
- if (v2.isUndefinedOrNull()) {
- if (!v1.isCell())
- return false;
- return v1.asCell()->structure()->masqueradesAsUndefined(exec->lexicalGlobalObject());
- }
- if (v1.isObject()) {
- if (v2.isObject())
- return v1 == v2;
- JSValue p1 = v1.toPrimitive(exec);
- if (exec->hadException())
- return false;
- v1 = p1;
- if (v1.isInt32() && v2.isInt32())
- return v1 == v2;
- continue;
- }
- if (v2.isObject()) {
- JSValue p2 = v2.toPrimitive(exec);
- if (exec->hadException())
- return false;
- v2 = p2;
- if (v1.isInt32() && v2.isInt32())
- return v1 == v2;
- continue;
- }
- if (s1 || s2) {
- double d1 = v1.toNumber(exec);
- double d2 = v2.toNumber(exec);
- return d1 == d2;
- }
- if (v1.isBoolean()) {
- if (v2.isNumber())
- return static_cast<double>(v1.asBoolean()) == v2.asNumber();
- } else if (v2.isBoolean()) {
- if (v1.isNumber())
- return v1.asNumber() == static_cast<double>(v2.asBoolean());
- }
- return v1 == v2;
- } while (true);
- }
- // ECMA 11.9.3
- ALWAYS_INLINE bool JSValue::strictEqualSlowCaseInline(ExecState* exec, JSValue v1, JSValue v2)
- {
- ASSERT(v1.isCell() && v2.isCell());
- if (v1.asCell()->isString() && v2.asCell()->isString())
- return asString(v1)->value(exec) == asString(v2)->value(exec);
- return v1 == v2;
- }
- inline bool JSValue::strictEqual(ExecState* exec, JSValue v1, JSValue v2)
- {
- if (v1.isInt32() && v2.isInt32())
- return v1 == v2;
- if (v1.isNumber() && v2.isNumber())
- return v1.asNumber() == v2.asNumber();
- if (!v1.isCell() || !v2.isCell())
- return v1 == v2;
- return strictEqualSlowCaseInline(exec, v1, v2);
- }
- inline TriState JSValue::pureToBoolean() const
- {
- if (isInt32())
- return asInt32() ? TrueTriState : FalseTriState;
- if (isDouble())
- return isNotZeroAndOrdered(asDouble()) ? TrueTriState : FalseTriState; // false for NaN
- if (isCell())
- return asCell()->pureToBoolean();
- return isTrue() ? TrueTriState : FalseTriState;
- }
- } // namespace JSC
- #endif // JSValueInlines_h
|