#include "JSCJSValue.h"
#include "JSCellInlines.h"
#include "JSFunction.h"
+#include <wtf/text/StringImpl.h>
namespace JSC {
inline JSValue jsNaN()
{
- return JSValue(QNaN);
+ return JSValue(PNaN);
}
inline JSValue::JSValue(char i)
u.asBits.payload = reinterpret_cast<int32_t>(const_cast<JSCell*>(ptr));
}
-inline JSValue::operator bool() const
+inline JSValue::operator UnspecifiedBoolType*() const
{
ASSERT(tag() != DeletedValueTag);
- return tag() != EmptyValueTag;
+ return tag() != EmptyValueTag ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0;
}
inline bool JSValue::operator==(const JSValue& other) const
ALWAYS_INLINE JSValue::JSValue(EncodeAsDoubleTag, double d)
{
+ ASSERT(!isImpureNaN(d));
u.asDouble = d;
}
u.asBits.payload = i;
}
-#if ENABLE(LLINT_C_LOOP)
+#if !ENABLE(JIT)
inline JSValue::JSValue(int32_t tag, int32_t payload)
{
u.asBits.tag = tag;
u.asInt64 = reinterpret_cast<uintptr_t>(const_cast<JSCell*>(ptr));
}
-inline JSValue::operator bool() const
+inline JSValue::operator UnspecifiedBoolType*() const
{
- return u.asInt64;
+ return u.asInt64 ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0;
}
inline bool JSValue::operator==(const JSValue& other) const
ALWAYS_INLINE JSValue::JSValue(EncodeAsDoubleTag, double d)
{
+ ASSERT(!isImpureNaN(d));
u.asInt64 = reinterpretDoubleToInt64(d) + DoubleEncodeOffset;
}
#endif // USE(JSVALUE64)
+inline int64_t tryConvertToInt52(double number)
+{
+ if (number != number)
+ return JSValue::notInt52;
+#if OS(WINDOWS) && CPU(X86)
+ // The VS Compiler for 32-bit builds generates a floating point error when attempting to cast
+ // from an infinity to a 64-bit integer. We leave this routine with the floating point error
+ // left in a register, causing undefined behavior in later floating point operations.
+ //
+ // To avoid this issue, we check for infinity here, and return false in that case.
+ if (std::isinf(number))
+ return JSValue::notInt52;
+#endif
+ int64_t asInt64 = static_cast<int64_t>(number);
+ if (asInt64 != number)
+ return JSValue::notInt52;
+ if (!asInt64 && std::signbit(number))
+ return JSValue::notInt52;
+ if (asInt64 >= (static_cast<int64_t>(1) << (JSValue::numberOfInt52Bits - 1)))
+ return JSValue::notInt52;
+ if (asInt64 < -(static_cast<int64_t>(1) << (JSValue::numberOfInt52Bits - 1)))
+ return JSValue::notInt52;
+ return asInt64;
+}
+
+inline bool isInt52(double number)
+{
+ return tryConvertToInt52(number) != JSValue::notInt52;
+}
+
+inline bool JSValue::isMachineInt() const
+{
+ if (isInt32())
+ return true;
+ if (!isNumber())
+ return false;
+ return isInt52(asDouble());
+}
+
+inline int64_t JSValue::asMachineInt() const
+{
+ ASSERT(isMachineInt());
+ if (isInt32())
+ return asInt32();
+ return static_cast<int64_t>(asDouble());
+}
+
inline bool JSValue::isString() const
{
return isCell() && asCell()->isString();
return isCell() && asCell()->isGetterSetter();
}
+inline bool JSValue::isCustomGetterSetter() const
+{
+ return isCell() && asCell()->isCustomGetterSetter();
+}
+
inline bool JSValue::isObject() const
{
return isCell() && asCell()->isObject();
return true;
}
ASSERT(isUndefined());
- number = QNaN;
+ number = PNaN;
value = *this;
return true;
}
inline bool JSValue::isFunction() const
{
- return isCell() && (asCell()->inherits(&JSFunction::s_info) || asCell()->inherits(&InternalFunction::s_info));
+ return isCell() && (asCell()->inherits(JSFunction::info()) || asCell()->inherits(InternalFunction::info()));
}
// this method is here to be after the inline declaration of JSCell::inherits
return isCell() && asCell()->inherits(classInfo);
}
-inline JSObject* JSValue::toThisObject(ExecState* exec) const
+inline JSValue JSValue::toThis(ExecState* exec, ECMAMode ecmaMode) const
{
- return isCell() ? asCell()->methodTable()->toThisObject(asCell(), exec) : toThisObjectSlowCase(exec);
+ return isCell() ? asCell()->methodTable(exec->vm())->toThis(asCell(), exec, ecmaMode) : toThisSlowCase(exec, ecmaMode);
}
-inline JSValue JSValue::get(ExecState* exec, PropertyName propertyName) const
+ALWAYS_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
+ALWAYS_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))
+ // If this is a primitive, we'll need to synthesize the prototype -
+ // and if it's a string there are special properties to check first.
+ JSObject* object;
+ if (UNLIKELY(!isObject())) {
+ if (isCell() && asString(*this)->getStringPropertySlot(exec, propertyName, slot))
return slot.getValue(exec, propertyName);
- JSValue prototype = asObject(cell)->prototype();
- if (!prototype.isObject())
- return jsUndefined();
- cell = asObject(prototype);
- }
+ object = synthesizePrototype(exec);
+ } else
+ object = asObject(asCell());
+
+ if (object->getPropertySlot(exec, propertyName, slot))
+ return slot.getValue(exec, propertyName);
+ return jsUndefined();
}
-inline JSValue JSValue::get(ExecState* exec, unsigned propertyName) const
+ALWAYS_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
+ALWAYS_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))
+ // If this is a primitive, we'll need to synthesize the prototype -
+ // and if it's a string there are special properties to check first.
+ JSObject* object;
+ if (UNLIKELY(!isObject())) {
+ if (isCell() && asString(*this)->getStringPropertySlot(exec, propertyName, slot))
return slot.getValue(exec, propertyName);
- JSValue prototype = asObject(cell)->prototype();
- if (!prototype.isObject())
- return jsUndefined();
- cell = prototype.asCell();
- }
+ object = synthesizePrototype(exec);
+ } else
+ object = asObject(asCell());
+
+ if (object->getPropertySlot(exec, propertyName, slot))
+ return slot.getValue(exec, propertyName);
+ return jsUndefined();
}
inline void JSValue::put(ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
putToPrimitive(exec, propertyName, value, slot);
return;
}
- asCell()->methodTable()->put(asCell(), exec, propertyName, value, slot);
+ asCell()->methodTable(exec->vm())->put(asCell(), exec, propertyName, value, slot);
}
inline void JSValue::putByIndex(ExecState* exec, unsigned propertyName, JSValue value, bool shouldThrow)
putToPrimitiveByIndex(exec, propertyName, value, shouldThrow);
return;
}
- asCell()->methodTable()->putByIndex(asCell(), exec, propertyName, value, shouldThrow);
+ asCell()->methodTable(exec->vm())->putByIndex(asCell(), exec, propertyName, value, shouldThrow);
}
inline JSValue JSValue::structureOrUndefined() const
ALWAYS_INLINE bool JSValue::equalSlowCaseInline(ExecState* exec, JSValue v1, JSValue v2)
{
+ VM& vm = exec->vm();
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);
+ return WTF::equal(*asString(v1)->value(exec).impl(), *asString(v2)->value(exec).impl());
if (v1.isUndefinedOrNull()) {
if (v2.isUndefinedOrNull())
return true;
if (!v2.isCell())
return false;
- return v2.asCell()->structure()->masqueradesAsUndefined(exec->lexicalGlobalObject());
+ return v2.asCell()->structure(vm)->masqueradesAsUndefined(exec->lexicalGlobalObject());
}
if (v2.isUndefinedOrNull()) {
if (!v1.isCell())
return false;
- return v1.asCell()->structure()->masqueradesAsUndefined(exec->lexicalGlobalObject());
+ return v1.asCell()->structure(vm)->masqueradesAsUndefined(exec->lexicalGlobalObject());
}
if (v1.isObject()) {
ASSERT(v1.isCell() && v2.isCell());
if (v1.asCell()->isString() && v2.asCell()->isString())
- return asString(v1)->value(exec) == asString(v2)->value(exec);
+ return WTF::equal(*asString(v1)->value(exec).impl(), *asString(v2)->value(exec).impl());
return v1 == v2;
}
return strictEqualSlowCaseInline(exec, v1, v2);
}
+inline int32_t JSValue::asInt32ForArithmetic() const
+{
+ if (isBoolean())
+ return asBoolean();
+ return asInt32();
+}
+
+inline TriState JSValue::pureStrictEqual(JSValue v1, JSValue v2)
+{
+ if (v1.isInt32() && v2.isInt32())
+ return triState(v1 == v2);
+
+ if (v1.isNumber() && v2.isNumber())
+ return triState(v1.asNumber() == v2.asNumber());
+
+ if (!v1.isCell() || !v2.isCell())
+ return triState(v1 == v2);
+
+ if (v1.asCell()->isString() && v2.asCell()->isString()) {
+ const StringImpl* v1String = asString(v1)->tryGetValueImpl();
+ const StringImpl* v2String = asString(v2)->tryGetValueImpl();
+ if (!v1String || !v2String)
+ return MixedTriState;
+ return triState(WTF::equal(*v1String, *v2String));
+ }
+
+ return triState(v1 == v2);
+}
+
inline TriState JSValue::pureToBoolean() const
{
if (isInt32())