[JSC] Unify how we throw TypeError from C++
[WebKit-https.git] / Source / JavaScriptCore / runtime / ObjectPrototype.cpp
index fdaba1a..6e0e7cb 100644 (file)
@@ -81,7 +81,10 @@ ObjectPrototype* ObjectPrototype::create(VM& vm, JSGlobalObject* globalObject, S
 EncodedJSValue JSC_HOST_CALL objectProtoFuncValueOf(ExecState* exec)
 {
     JSValue thisValue = exec->thisValue().toThis(exec, StrictMode);
-    return JSValue::encode(thisValue.toObject(exec));
+    JSObject* valueObj = thisValue.toObject(exec);
+    if (!valueObj)
+        return JSValue::encode(JSValue());
+    return JSValue::encode(valueObj);
 }
 
 EncodedJSValue JSC_HOST_CALL objectProtoFuncHasOwnProperty(ExecState* exec)
@@ -90,25 +93,35 @@ EncodedJSValue JSC_HOST_CALL objectProtoFuncHasOwnProperty(ExecState* exec)
     auto propertyName = exec->argument(0).toPropertyKey(exec);
     if (exec->hadException())
         return JSValue::encode(jsUndefined());
-    return JSValue::encode(jsBoolean(thisValue.toObject(exec)->hasOwnProperty(exec, propertyName)));
+    JSObject* thisObject = thisValue.toObject(exec);
+    if (!thisObject)
+        return JSValue::encode(JSValue());
+    return JSValue::encode(jsBoolean(thisObject->hasOwnProperty(exec, propertyName)));
 }
 
 EncodedJSValue JSC_HOST_CALL objectProtoFuncIsPrototypeOf(ExecState* exec)
 {
     JSValue thisValue = exec->thisValue().toThis(exec, StrictMode);
     JSObject* thisObj = thisValue.toObject(exec);
+    if (!thisObj)
+        return JSValue::encode(JSValue());
 
     if (!exec->argument(0).isObject())
         return JSValue::encode(jsBoolean(false));
 
-    JSValue v = asObject(exec->argument(0))->prototype();
+    VM& vm = exec->vm();
+    JSValue v = asObject(exec->argument(0))->getPrototype(vm, exec);
+    if (UNLIKELY(vm.exception()))
+        return JSValue::encode(JSValue());
 
     while (true) {
         if (!v.isObject())
             return JSValue::encode(jsBoolean(false));
         if (v == thisObj)
             return JSValue::encode(jsBoolean(true));
-        v = asObject(v)->prototype();
+        v = asObject(v)->getPrototype(vm, exec);
+        if (UNLIKELY(vm.exception()))
+            return JSValue::encode(JSValue());
     }
 }
 
@@ -120,8 +133,8 @@ EncodedJSValue JSC_HOST_CALL objectProtoFuncDefineGetter(ExecState* exec)
 
     JSValue get = exec->argument(1);
     CallData callData;
-    if (getCallData(get, callData) == CallTypeNone)
-        return throwVMError(exec, createTypeError(exec, ASCIILiteral("invalid getter usage")));
+    if (getCallData(get, callData) == CallType::None)
+        return throwVMTypeError(exec, ASCIILiteral("invalid getter usage"));
 
     auto propertyName = exec->argument(0).toPropertyKey(exec);
     if (exec->hadException())
@@ -132,7 +145,7 @@ EncodedJSValue JSC_HOST_CALL objectProtoFuncDefineGetter(ExecState* exec)
     descriptor.setEnumerable(true);
     descriptor.setConfigurable(true);
 
-    bool shouldThrow = false;
+    bool shouldThrow = true;
     thisObject->methodTable(exec->vm())->defineOwnProperty(thisObject, exec, propertyName, descriptor, shouldThrow);
 
     return JSValue::encode(jsUndefined());
@@ -146,8 +159,8 @@ EncodedJSValue JSC_HOST_CALL objectProtoFuncDefineSetter(ExecState* exec)
 
     JSValue set = exec->argument(1);
     CallData callData;
-    if (getCallData(set, callData) == CallTypeNone)
-        return throwVMError(exec, createTypeError(exec, ASCIILiteral("invalid setter usage")));
+    if (getCallData(set, callData) == CallType::None)
+        return throwVMTypeError(exec, ASCIILiteral("invalid setter usage"));
 
     auto propertyName = exec->argument(0).toPropertyKey(exec);
     if (exec->hadException())
@@ -158,7 +171,7 @@ EncodedJSValue JSC_HOST_CALL objectProtoFuncDefineSetter(ExecState* exec)
     descriptor.setEnumerable(true);
     descriptor.setConfigurable(true);
 
-    bool shouldThrow = false;
+    bool shouldThrow = true;
     thisObject->methodTable(exec->vm())->defineOwnProperty(thisObject, exec, propertyName, descriptor, shouldThrow);
 
     return JSValue::encode(jsUndefined());
@@ -174,7 +187,7 @@ EncodedJSValue JSC_HOST_CALL objectProtoFuncLookupGetter(ExecState* exec)
     if (exec->hadException())
         return JSValue::encode(jsUndefined());
 
-    PropertySlot slot(thisObject);
+    PropertySlot slot(thisObject, PropertySlot::InternalMethodType::GetOwnProperty);
     if (thisObject->getPropertySlot(exec, propertyName, slot)) {
         if (slot.isAccessor()) {
             GetterSetter* getterSetter = slot.getterSetter();
@@ -201,7 +214,7 @@ EncodedJSValue JSC_HOST_CALL objectProtoFuncLookupSetter(ExecState* exec)
     if (exec->hadException())
         return JSValue::encode(jsUndefined());
 
-    PropertySlot slot(thisObject);
+    PropertySlot slot(thisObject, PropertySlot::InternalMethodType::GetOwnProperty);
     if (thisObject->getPropertySlot(exec, propertyName, slot)) {
         if (slot.isAccessor()) {
             GetterSetter* getterSetter = slot.getterSetter();
@@ -246,7 +259,7 @@ EncodedJSValue JSC_HOST_CALL objectProtoFuncToLocaleString(ExecState* exec)
     // 3. If IsCallable(toString) is false, throw a TypeError exception.
     CallData callData;
     CallType callType = getCallData(toString, callData);
-    if (callType == CallTypeNone)
+    if (callType == CallType::None)
         return JSValue::encode(jsUndefined());
 
     // 4. Return the result of calling the [[Call]] internal method of toString passing O as the this value and no arguments.
@@ -260,34 +273,39 @@ EncodedJSValue JSC_HOST_CALL objectProtoFuncToString(ExecState* exec)
     if (thisValue.isUndefinedOrNull())
         return JSValue::encode(thisValue.isUndefined() ? vm.smallStrings.undefinedObjectString() : vm.smallStrings.nullObjectString());
     JSObject* thisObject = thisValue.toObject(exec);
+    if (!thisObject)
+        return JSValue::encode(jsUndefined());
 
-    JSString* result = thisObject->structure(vm)->objectToStringValue();
-    if (!result) {
-        PropertyName toStringTagSymbol = exec->propertyNames().toStringTagSymbol;
-        PropertySlot toStringTagSlot(thisObject);
-        if (thisObject->getPropertySlot(exec, toStringTagSymbol, toStringTagSlot)) {
+    auto result = thisObject->structure(vm)->objectToStringValue();
+    if (result)
+        return JSValue::encode(result);
+
+    PropertyName toStringTagSymbol = exec->propertyNames().toStringTagSymbol;
+    return JSValue::encode(thisObject->getPropertySlot(exec, toStringTagSymbol, [&] (bool found, PropertySlot& toStringTagSlot) -> JSValue {
+        if (found) {
             JSValue stringTag = toStringTagSlot.getValue(exec, toStringTagSymbol);
+            if (UNLIKELY(vm.exception()))
+                return jsUndefined();
             if (stringTag.isString()) {
                 JSRopeString::RopeBuilder ropeBuilder(vm);
                 ropeBuilder.append(vm.smallStrings.objectStringStart());
                 ropeBuilder.append(jsCast<JSString*>(stringTag));
                 ropeBuilder.append(vm.smallStrings.singleCharacterString(']'));
-                result = ropeBuilder.release();
+                JSString* result = ropeBuilder.release();
 
                 thisObject->structure(vm)->setObjectToStringValue(exec, vm, result, toStringTagSlot);
-                return JSValue::encode(result);
+                return result;
             }
         }
 
         String newString = WTF::tryMakeString("[object ", thisObject->methodTable(exec->vm())->className(thisObject), "]");
         if (!newString)
-            return JSValue::encode(throwOutOfMemoryError(exec));
+            return throwOutOfMemoryError(exec);
 
-        result = jsNontrivialString(&vm, newString);
+        auto result = jsNontrivialString(&vm, newString);
         thisObject->structure(vm)->setObjectToStringValue(exec, vm, result, toStringTagSlot);
-    }
-
-    return JSValue::encode(result);
+        return result;
+    }));
 }
 
 } // namespace JSC