]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - runtime/JSCJSValueInlines.h
JavaScriptCore-7600.1.4.9.tar.gz
[apple/javascriptcore.git] / runtime / JSCJSValueInlines.h
index e22fe244fdeef42b56ed1b7421e7e39914ed848f..d0245c13ea709461afbfe86a0d69e6eebc1a2fa7 100644 (file)
@@ -30,6 +30,7 @@
 #include "JSCJSValue.h"
 #include "JSCellInlines.h"
 #include "JSFunction.h"
+#include <wtf/text/StringImpl.h>
 
 namespace JSC {
 
@@ -65,7 +66,7 @@ inline double JSValue::asNumber() const
 
 inline JSValue jsNaN()
 {
-    return JSValue(QNaN);
+    return JSValue(PNaN);
 }
 
 inline JSValue::JSValue(char i)
@@ -210,10 +211,10 @@ inline JSValue::JSValue(const JSCell* ptr)
     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
@@ -301,6 +302,7 @@ ALWAYS_INLINE JSCell* JSValue::asCell() const
 
 ALWAYS_INLINE JSValue::JSValue(EncodeAsDoubleTag, double d)
 {
+    ASSERT(!isImpureNaN(d));
     u.asDouble = d;
 }
 
@@ -310,7 +312,7 @@ inline JSValue::JSValue(int i)
     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;
@@ -358,9 +360,9 @@ inline JSValue::JSValue(const JSCell* ptr)
     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
@@ -467,6 +469,7 @@ inline double reinterpretInt64ToDouble(int64_t value)
 
 ALWAYS_INLINE JSValue::JSValue(EncodeAsDoubleTag, double d)
 {
+    ASSERT(!isImpureNaN(d));
     u.asInt64 = reinterpretDoubleToInt64(d) + DoubleEncodeOffset;
 }
 
@@ -494,6 +497,53 @@ ALWAYS_INLINE JSCell* JSValue::asCell() const
 
 #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();
@@ -509,6 +559,11 @@ inline bool JSValue::isGetterSetter() const
     return isCell() && asCell()->isGetterSetter();
 }
 
+inline bool JSValue::isCustomGetterSetter() const
+{
+    return isCell() && asCell()->isCustomGetterSetter();
+}
+
 inline bool JSValue::isObject() const
 {
     return isCell() && asCell()->isObject();
@@ -579,7 +634,7 @@ inline bool JSValue::getPrimitiveNumber(ExecState* exec, double& number, JSValue
         return true;
     }
     ASSERT(isUndefined());
-    number = QNaN;
+    number = PNaN;
     value = *this;
     return true;
 }
@@ -605,7 +660,7 @@ inline JSObject* JSValue::toObject(ExecState* exec, JSGlobalObject* globalObject
 
 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
@@ -614,59 +669,55 @@ inline bool JSValue::inherits(const ClassInfo* classInfo) const
     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)
@@ -675,7 +726,7 @@ inline void JSValue::put(ExecState* exec, PropertyName propertyName, JSValue val
         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)
@@ -684,7 +735,7 @@ inline void JSValue::putByIndex(ExecState* exec, unsigned propertyName, JSValue
         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
@@ -705,6 +756,7 @@ inline bool JSValue::equal(ExecState* exec, JSValue v1, JSValue v2)
 
 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();
@@ -712,20 +764,20 @@ ALWAYS_INLINE bool JSValue::equalSlowCaseInline(ExecState* exec, JSValue v1, JSV
         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()) {
@@ -774,7 +826,7 @@ ALWAYS_INLINE bool JSValue::strictEqualSlowCaseInline(ExecState* exec, JSValue v
     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;
 }
@@ -793,6 +845,35 @@ inline bool JSValue::strictEqual(ExecState* exec, JSValue v1, JSValue 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())