]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - runtime/JSCJSValue.cpp
JavaScriptCore-7601.1.46.3.tar.gz
[apple/javascriptcore.git] / runtime / JSCJSValue.cpp
index 627e9e077e239b744c2577b3a674ac3d1113e855..9e0aab1774de17a03ca6de12c9e98f9d7236360b 100644 (file)
@@ -25,6 +25,7 @@
 
 #include "BooleanConstructor.h"
 #include "BooleanPrototype.h"
+#include "CustomGetterSetter.h"
 #include "Error.h"
 #include "ExceptionHelpers.h"
 #include "GetterSetter.h"
 #include "JSGlobalObject.h"
 #include "JSNotAnObject.h"
 #include "NumberObject.h"
+#include "StructureInlines.h"
 #include <wtf/MathExtras.h>
 #include <wtf/StringExtras.h>
 
 namespace JSC {
 
-static const double D32 = 4294967296.0;
-
 // ECMA 9.4
 double JSValue::toInteger(ExecState* exec) const
 {
@@ -63,7 +63,7 @@ double JSValue::toNumberSlowCase(ExecState* exec) const
         return asCell()->toNumber(exec);
     if (isTrue())
         return 1.0;
-    return isUndefined() ? QNaN : 0; // null and false both convert to 0.
+    return isUndefined() ? PNaN : 0; // null and false both convert to 0.
 }
 
 JSObject* JSValue::toObjectSlowCase(ExecState* exec, JSGlobalObject* globalObject) const
@@ -76,14 +76,18 @@ JSObject* JSValue::toObjectSlowCase(ExecState* exec, JSGlobalObject* globalObjec
         return constructBooleanFromImmediateBoolean(exec, globalObject, asValue());
 
     ASSERT(isUndefinedOrNull());
-    throwError(exec, createNotAnObjectError(exec, *this));
-    return JSNotAnObject::create(exec);
+    VM& vm = exec->vm();
+    vm.throwException(exec, createNotAnObjectError(exec, *this));
+    return JSNotAnObject::create(vm);
 }
 
-JSObject* JSValue::toThisObjectSlowCase(ExecState* exec) const
+JSValue JSValue::toThisSlowCase(ExecState* exec, ECMAMode ecmaMode) const
 {
     ASSERT(!isCell());
 
+    if (ecmaMode == StrictMode)
+        return *this;
+
     if (isInt32() || isDouble())
         return constructNumber(exec, exec->lexicalGlobalObject(), asValue());
     if (isTrue() || isFalse())
@@ -95,8 +99,10 @@ JSObject* JSValue::toThisObjectSlowCase(ExecState* exec) const
 JSObject* JSValue::synthesizePrototype(ExecState* exec) const
 {
     if (isCell()) {
-        ASSERT(isString());
-        return exec->lexicalGlobalObject()->stringPrototype();
+        if (isString())
+            return exec->lexicalGlobalObject()->stringPrototype();
+        ASSERT(isSymbol());
+        return exec->lexicalGlobalObject()->symbolPrototype();
     }
 
     if (isNumber())
@@ -105,8 +111,9 @@ JSObject* JSValue::synthesizePrototype(ExecState* exec) const
         return exec->lexicalGlobalObject()->booleanPrototype();
 
     ASSERT(isUndefinedOrNull());
-    throwError(exec, createNotAnObjectError(exec, *this));
-    return JSNotAnObject::create(exec);
+    VM& vm = exec->vm();
+    vm.throwException(exec, createNotAnObjectError(exec, *this));
+    return JSNotAnObject::create(vm);
 }
 
 // ECMA 8.7.2
@@ -114,9 +121,8 @@ void JSValue::putToPrimitive(ExecState* exec, PropertyName propertyName, JSValue
 {
     VM& vm = exec->vm();
 
-    unsigned index = propertyName.asIndex();
-    if (index != PropertyName::NotAnIndex) {
-        putToPrimitiveByIndex(exec, index, value, slot.isStrictMode());
+    if (Optional<uint32_t> index = parseIndex(propertyName)) {
+        putToPrimitiveByIndex(exec, index.value(), value, slot.isStrictMode());
         return;
     }
 
@@ -136,31 +142,22 @@ void JSValue::putToPrimitive(ExecState* exec, PropertyName propertyName, JSValue
 
     for (; ; obj = asObject(prototype)) {
         unsigned attributes;
-        JSCell* specificValue;
-        PropertyOffset offset = obj->structure()->get(vm, propertyName, attributes, specificValue);
+        PropertyOffset offset = obj->structure()->get(vm, propertyName, attributes);
         if (offset != invalidOffset) {
             if (attributes & ReadOnly) {
                 if (slot.isStrictMode())
-                    throwError(exec, createTypeError(exec, StrictModeReadonlyPropertyWriteError));
+                    exec->vm().throwException(exec, createTypeError(exec, StrictModeReadonlyPropertyWriteError));
                 return;
             }
 
             JSValue gs = obj->getDirect(offset);
             if (gs.isGetterSetter()) {
-                JSObject* setterFunc = asGetterSetter(gs)->setter();        
-                if (!setterFunc) {
-                    if (slot.isStrictMode())
-                        throwError(exec, createTypeError(exec, ASCIILiteral("setting a property that has only a getter")));
-                    return;
-                }
-                
-                CallData callData;
-                CallType callType = setterFunc->methodTable()->getCallData(setterFunc, callData);
-                MarkedArgumentBuffer args;
-                args.append(value);
-
-                // If this is WebCore's global object then we need to substitute the shell.
-                call(exec, setterFunc, callType, callData, *this, args);
+                callSetter(exec, *this, gs, value, slot.isStrictMode() ? StrictMode : NotStrictMode);
+                return;
+            }
+
+            if (gs.isCustomGetterSetter()) {
+                callCustomSetter(exec, gs, obj, slot.thisValue(), value);
                 return;
             }
 
@@ -182,7 +179,7 @@ void JSValue::putToPrimitive(ExecState* exec, PropertyName propertyName, JSValue
 void JSValue::putToPrimitiveByIndex(ExecState* exec, unsigned propertyName, JSValue value, bool shouldThrow)
 {
     if (propertyName > MAX_ARRAY_INDEX) {
-        PutPropertySlot slot(shouldThrow);
+        PutPropertySlot slot(*this, shouldThrow);
         putToPrimitive(exec, Identifier::from(exec, propertyName), value, slot);
         return;
     }
@@ -195,6 +192,18 @@ void JSValue::putToPrimitiveByIndex(ExecState* exec, unsigned propertyName, JSVa
 }
 
 void JSValue::dump(PrintStream& out) const
+{
+    dumpInContext(out, 0);
+}
+
+void JSValue::dumpInContext(PrintStream& out, DumpContext* context) const
+{
+    dumpInContextAssumingStructure(
+        out, context, (!!*this && isCell()) ? asCell()->structure() : nullptr);
+}
+
+void JSValue::dumpInContextAssumingStructure(
+    PrintStream& out, DumpContext* context, Structure* structure) const
 {
     if (!*this)
         out.print("<JSValue()>");
@@ -212,24 +221,71 @@ void JSValue::dump(PrintStream& out) const
         out.printf("Double: %08x:%08x, %lf", u.asTwoInt32s[1], u.asTwoInt32s[0], asDouble());
 #endif
     } else if (isCell()) {
-        if (asCell()->inherits(&JSString::s_info)) {
+        if (structure->classInfo()->isSubClassOf(JSString::info())) {
             JSString* string = jsCast<JSString*>(asCell());
-            out.print("String");
+            out.print("String");
             if (string->isRope())
-                out.print("(rope) ");
-            out.print(string->tryGetValue());
-        } else if (asCell()->inherits(&Structure::s_info)) {
-            Structure* structure = jsCast<Structure*>(asCell());
-            out.print(
-                "Structure: ", RawPointer(structure), ": ", structure->classInfo()->className,
-                ", ", IndexingTypeDump(structure->indexingTypeIncludingHistory()));
-        } else {
+                out.print(" (rope)");
+            const StringImpl* impl = string->tryGetValueImpl();
+            if (impl) {
+                if (impl->isAtomic())
+                    out.print(" (atomic)");
+                if (impl->isAtomic())
+                    out.print(" (identifier)");
+                if (impl->isSymbol())
+                    out.print(" (symbol)");
+            } else
+                out.print(" (unresolved)");
+            out.print(": ", impl);
+        } else if (structure->classInfo()->isSubClassOf(Structure::info()))
+            out.print("Structure: ", inContext(*jsCast<Structure*>(asCell()), context));
+        else {
             out.print("Cell: ", RawPointer(asCell()));
-            if (isObject() && asObject(*this)->butterfly())
-                out.print("->", RawPointer(asObject(*this)->butterfly()));
-            out.print(
-                " (", RawPointer(asCell()->structure()), ": ", asCell()->structure()->classInfo()->className,
-                ", ", IndexingTypeDump(asCell()->structure()->indexingTypeIncludingHistory()), ")");
+            out.print(" (", inContext(*structure, context), ")");
+        }
+#if USE(JSVALUE64)
+        out.print(", ID: ", asCell()->structureID());
+#endif
+    } else if (isTrue())
+        out.print("True");
+    else if (isFalse())
+        out.print("False");
+    else if (isNull())
+        out.print("Null");
+    else if (isUndefined())
+        out.print("Undefined");
+    else
+        out.print("INVALID");
+}
+
+void JSValue::dumpForBacktrace(PrintStream& out) const
+{
+    if (!*this)
+        out.print("<JSValue()>");
+    else if (isInt32())
+        out.printf("%d", asInt32());
+    else if (isDouble())
+        out.printf("%lf", asDouble());
+    else if (isCell()) {
+        if (asCell()->inherits(JSString::info())) {
+            JSString* string = jsCast<JSString*>(asCell());
+            const StringImpl* impl = string->tryGetValueImpl();
+            if (impl)
+                out.print("\"", impl, "\"");
+            else
+                out.print("(unresolved string)");
+        } else if (asCell()->inherits(Structure::info())) {
+            out.print("Structure[ ", asCell()->structure()->classInfo()->className);
+#if USE(JSVALUE64)
+            out.print(" ID: ", asCell()->structureID());
+#endif
+            out.print("]: ", RawPointer(asCell()));
+        } else {
+            out.print("Cell[", asCell()->structure()->classInfo()->className);
+#if USE(JSVALUE64)
+            out.print(" ID: ", asCell()->structureID());
+#endif
+            out.print("]: ", RawPointer(asCell()));
         }
     } else if (isTrue())
         out.print("True");
@@ -297,8 +353,12 @@ JSString* JSValue::toStringSlowCase(ExecState* exec) const
 {
     VM& vm = exec->vm();
     ASSERT(!isString());
-    if (isInt32())
-        return jsString(&vm, vm.numericStrings.add(asInt32()));
+    if (isInt32()) {
+        auto integer = asInt32();
+        if (static_cast<unsigned>(integer) <= 9)
+            return vm.smallStrings.singleCharacterString(integer + '0');
+        return jsNontrivialString(&vm, vm.numericStrings.add(integer));
+    }
     if (isDouble())
         return jsString(&vm, vm.numericStrings.add(asDouble()));
     if (isTrue())
@@ -309,6 +369,10 @@ JSString* JSValue::toStringSlowCase(ExecState* exec) const
         return vm.smallStrings.nullString();
     if (isUndefined())
         return vm.smallStrings.undefinedString();
+    if (isSymbol()) {
+        throwTypeError(exec);
+        return jsEmptyString(exec);
+    }
 
     ASSERT(isCell());
     JSValue value = asCell()->toPrimitive(exec, PreferString);
@@ -320,7 +384,20 @@ JSString* JSValue::toStringSlowCase(ExecState* exec) const
 
 String JSValue::toWTFStringSlowCase(ExecState* exec) const
 {
-    return inlineJSValueNotStringtoString(*this, exec);
+    VM& vm = exec->vm();
+    if (isInt32())
+        return vm.numericStrings.add(asInt32());
+    if (isDouble())
+        return vm.numericStrings.add(asDouble());
+    if (isTrue())
+        return vm.propertyNames->trueKeyword.string();
+    if (isFalse())
+        return vm.propertyNames->falseKeyword.string();
+    if (isNull())
+        return vm.propertyNames->nullKeyword.string();
+    if (isUndefined())
+        return vm.propertyNames->undefinedKeyword.string();
+    return toString(exec)->value(exec);
 }
 
 } // namespace JSC