Title: [197512] trunk/Source/_javascript_Core
Revision
197512
Author
[email protected]
Date
2016-03-03 11:18:35 -0800 (Thu, 03 Mar 2016)

Log Message

[[SetPrototypeOf]] isn't properly implemented everywhere
https://bugs.webkit.org/show_bug.cgi?id=154943

Reviewed by Benjamin Poulain.

We were copy-pasting implememntation bits that belong in OrdinarySetPrototypeOf 
in a few different places that call O.[[SetPrototypeOf]](v)
rather than having those bits in OrdinarySetPrototypeOf itself.
We need to put those copy-pasted bits into OrdinarySetPrototypeOf
and not the call sites of O.[[SetPrototypeOf]](v) because
O.[[SetPrototypeOf]](v) won't always call into OrdinarySetPrototypeOf.
This is needed for correctness because this behavior is now observable
with the ES6 Proxy object.

* runtime/ClassInfo.h:
* runtime/JSCell.cpp:
(JSC::JSCell::isExtensible):
(JSC::JSCell::setPrototype):
* runtime/JSCell.h:
* runtime/JSGlobalObjectFunctions.cpp:
(JSC::globalFuncProtoSetter):
* runtime/JSObject.cpp:
(JSC::JSObject::setPrototypeDirect):
(JSC::JSObject::setPrototypeWithCycleCheck):
(JSC::JSObject::setPrototype):
(JSC::JSObject::allowsAccessFrom):
* runtime/JSObject.h:
(JSC::JSObject::mayInterceptIndexedAccesses):
* runtime/ObjectConstructor.cpp:
(JSC::objectConstructorSetPrototypeOf):
* runtime/ReflectObject.cpp:
(JSC::reflectObjectSetPrototypeOf):

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (197511 => 197512)


--- trunk/Source/_javascript_Core/ChangeLog	2016-03-03 18:34:11 UTC (rev 197511)
+++ trunk/Source/_javascript_Core/ChangeLog	2016-03-03 19:18:35 UTC (rev 197512)
@@ -1,3 +1,38 @@
+2016-03-03  Saam barati  <[email protected]>
+
+        [[SetPrototypeOf]] isn't properly implemented everywhere
+        https://bugs.webkit.org/show_bug.cgi?id=154943
+
+        Reviewed by Benjamin Poulain.
+
+        We were copy-pasting implememntation bits that belong in OrdinarySetPrototypeOf 
+        in a few different places that call O.[[SetPrototypeOf]](v)
+        rather than having those bits in OrdinarySetPrototypeOf itself.
+        We need to put those copy-pasted bits into OrdinarySetPrototypeOf
+        and not the call sites of O.[[SetPrototypeOf]](v) because
+        O.[[SetPrototypeOf]](v) won't always call into OrdinarySetPrototypeOf.
+        This is needed for correctness because this behavior is now observable
+        with the ES6 Proxy object.
+
+        * runtime/ClassInfo.h:
+        * runtime/JSCell.cpp:
+        (JSC::JSCell::isExtensible):
+        (JSC::JSCell::setPrototype):
+        * runtime/JSCell.h:
+        * runtime/JSGlobalObjectFunctions.cpp:
+        (JSC::globalFuncProtoSetter):
+        * runtime/JSObject.cpp:
+        (JSC::JSObject::setPrototypeDirect):
+        (JSC::JSObject::setPrototypeWithCycleCheck):
+        (JSC::JSObject::setPrototype):
+        (JSC::JSObject::allowsAccessFrom):
+        * runtime/JSObject.h:
+        (JSC::JSObject::mayInterceptIndexedAccesses):
+        * runtime/ObjectConstructor.cpp:
+        (JSC::objectConstructorSetPrototypeOf):
+        * runtime/ReflectObject.cpp:
+        (JSC::reflectObjectSetPrototypeOf):
+
 2016-03-03  Alex Christensen  <[email protected]>
 
         Fix Windows build after r197489.

Modified: trunk/Source/_javascript_Core/runtime/ClassInfo.h (197511 => 197512)


--- trunk/Source/_javascript_Core/runtime/ClassInfo.h	2016-03-03 18:34:11 UTC (rev 197511)
+++ trunk/Source/_javascript_Core/runtime/ClassInfo.h	2016-03-03 19:18:35 UTC (rev 197512)
@@ -109,7 +109,7 @@
     typedef bool (*IsExtensibleFunctionPtr)(JSObject*, ExecState*);
     IsExtensibleFunctionPtr isExtensible;
 
-    typedef bool (*SetPrototypeFunctionPtr)(JSObject*, ExecState*, JSValue);
+    typedef bool (*SetPrototypeFunctionPtr)(JSObject*, ExecState*, JSValue, bool shouldThrowIfCantSet);
     SetPrototypeFunctionPtr setPrototype;
 
     typedef void (*DumpToStreamFunctionPtr)(const JSCell*, PrintStream&);

Modified: trunk/Source/_javascript_Core/runtime/JSCell.cpp (197511 => 197512)


--- trunk/Source/_javascript_Core/runtime/JSCell.cpp	2016-03-03 18:34:11 UTC (rev 197511)
+++ trunk/Source/_javascript_Core/runtime/JSCell.cpp	2016-03-03 19:18:35 UTC (rev 197512)
@@ -280,7 +280,7 @@
     RELEASE_ASSERT_NOT_REACHED();
 }
 
-bool JSCell::setPrototype(JSObject*, ExecState*, JSValue)
+bool JSCell::setPrototype(JSObject*, ExecState*, JSValue, bool)
 {
     RELEASE_ASSERT_NOT_REACHED();
 }

Modified: trunk/Source/_javascript_Core/runtime/JSCell.h (197511 => 197512)


--- trunk/Source/_javascript_Core/runtime/JSCell.h	2016-03-03 18:34:11 UTC (rev 197511)
+++ trunk/Source/_javascript_Core/runtime/JSCell.h	2016-03-03 19:18:35 UTC (rev 197512)
@@ -208,7 +208,7 @@
     static NO_RETURN_DUE_TO_CRASH void getGenericPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
     static NO_RETURN_DUE_TO_CRASH bool preventExtensions(JSObject*, ExecState*);
     static NO_RETURN_DUE_TO_CRASH bool isExtensible(JSObject*, ExecState*);
-    static NO_RETURN_DUE_TO_CRASH bool setPrototype(JSObject*, ExecState*, JSValue);
+    static NO_RETURN_DUE_TO_CRASH bool setPrototype(JSObject*, ExecState*, JSValue, bool);
 
     static String className(const JSObject*);
     JS_EXPORT_PRIVATE static bool customHasInstance(JSObject*, ExecState*, JSValue);

Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObjectFunctions.cpp (197511 => 197512)


--- trunk/Source/_javascript_Core/runtime/JSGlobalObjectFunctions.cpp	2016-03-03 18:34:11 UTC (rev 197511)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObjectFunctions.cpp	2016-03-03 19:18:35 UTC (rev 197512)
@@ -882,22 +882,9 @@
     if (!value.isObject() && !value.isNull())
         return JSValue::encode(jsUndefined());
 
-    if (thisObject->prototype() == value)
-        return JSValue::encode(jsUndefined());
-
-    bool isExtensible = thisObject->isExtensible(exec);
-    if (exec->hadException())
-        return JSValue::encode(jsUndefined());
-    if (!isExtensible)
-        return throwVMError(exec, createTypeError(exec, StrictModeReadonlyPropertyWriteError));
-
     VM& vm = exec->vm();
-    if (!thisObject->setPrototype(vm, exec, value)) {
-        if (!vm.exception())
-            vm.throwException(exec, createError(exec, ASCIILiteral("cyclic __proto__ value")));
-        return JSValue::encode(jsUndefined());
-    }
-    ASSERT(!exec->hadException());
+    bool shouldThrowIfCantSet = true;
+    thisObject->setPrototype(vm, exec, value, shouldThrowIfCantSet);
     return JSValue::encode(jsUndefined());
 }
     

Modified: trunk/Source/_javascript_Core/runtime/JSObject.cpp (197511 => 197512)


--- trunk/Source/_javascript_Core/runtime/JSObject.cpp	2016-03-03 18:34:11 UTC (rev 197511)
+++ trunk/Source/_javascript_Core/runtime/JSObject.cpp	2016-03-03 19:18:35 UTC (rev 197512)
@@ -1197,28 +1197,44 @@
     switchToSlowPutArrayStorage(vm);
 }
 
-bool JSObject::setPrototypeWithCycleCheck(VM& vm, ExecState* exec, JSValue prototype)
+bool JSObject::setPrototypeWithCycleCheck(VM& vm, ExecState* exec, JSValue prototype, bool shouldThrowIfCantSet)
 {
-    UNUSED_PARAM(exec);
     ASSERT(methodTable(vm)->toThis(this, exec, NotStrictMode) == this);
+
+    if (this->prototype() == prototype)
+        return true;
+
+    bool isExtensible = this->isExtensible(exec);
+    if (vm.exception())
+        return false;
+
+    if (!isExtensible) {
+        if (shouldThrowIfCantSet)
+            throwVMError(exec, createTypeError(exec, StrictModeReadonlyPropertyWriteError));
+        return false;
+    }
+
     JSValue nextPrototype = prototype;
     while (nextPrototype && nextPrototype.isObject()) {
-        if (nextPrototype == this)
+        if (nextPrototype == this) {
+            if (shouldThrowIfCantSet)
+                vm.throwException(exec, createError(exec, ASCIILiteral("cyclic __proto__ value")));
             return false;
+        }
         nextPrototype = asObject(nextPrototype)->prototype();
     }
     setPrototypeDirect(vm, prototype);
     return true;
 }
 
-bool JSObject::setPrototype(JSObject* object, ExecState* exec, JSValue prototype)
+bool JSObject::setPrototype(JSObject* object, ExecState* exec, JSValue prototype, bool shouldThrowIfCantSet)
 {
-    return object->setPrototypeWithCycleCheck(exec->vm(), exec, prototype);
+    return object->setPrototypeWithCycleCheck(exec->vm(), exec, prototype, shouldThrowIfCantSet);
 }
 
-bool JSObject::setPrototype(VM& vm, ExecState* exec, JSValue prototype)
+bool JSObject::setPrototype(VM& vm, ExecState* exec, JSValue prototype, bool shouldThrowIfCantSet)
 {
-    return methodTable(vm)->setPrototype(this, exec, prototype);
+    return methodTable(vm)->setPrototype(this, exec, prototype, shouldThrowIfCantSet);
 }
 
 bool JSObject::allowsAccessFrom(ExecState* exec)

Modified: trunk/Source/_javascript_Core/runtime/JSObject.h (197511 => 197512)


--- trunk/Source/_javascript_Core/runtime/JSObject.h	2016-03-03 18:34:11 UTC (rev 197511)
+++ trunk/Source/_javascript_Core/runtime/JSObject.h	2016-03-03 19:18:35 UTC (rev 197512)
@@ -114,13 +114,13 @@
 private:
     // This is OrdinarySetPrototypeOf in the specification. Section 9.1.2.1
     // https://tc39.github.io/ecma262/#sec-ordinarysetprototypeof
-    JS_EXPORT_PRIVATE bool setPrototypeWithCycleCheck(VM&, ExecState*, JSValue prototype);
+    JS_EXPORT_PRIVATE bool setPrototypeWithCycleCheck(VM&, ExecState*, JSValue prototype, bool shouldThrowIfCantSet);
 public:
     // This is the fully virtual [[SetPrototypeOf]] internal function defined
     // in the ECMAScript 6 specification. Use this when doing a [[SetPrototypeOf]] 
     // operation as dictated in the specification.
-    bool setPrototype(VM&, ExecState*, JSValue prototype);
-    JS_EXPORT_PRIVATE static bool setPrototype(JSObject*, ExecState*, JSValue prototype);
+    bool setPrototype(VM&, ExecState*, JSValue prototype, bool shouldThrowIfCantSet = false);
+    JS_EXPORT_PRIVATE static bool setPrototype(JSObject*, ExecState*, JSValue prototype, bool shouldThrowIfCantSet);
         
     bool mayInterceptIndexedAccesses()
     {

Modified: trunk/Source/_javascript_Core/runtime/ObjectConstructor.cpp (197511 => 197512)


--- trunk/Source/_javascript_Core/runtime/ObjectConstructor.cpp	2016-03-03 18:34:11 UTC (rev 197511)
+++ trunk/Source/_javascript_Core/runtime/ObjectConstructor.cpp	2016-03-03 19:18:35 UTC (rev 197512)
@@ -209,24 +209,10 @@
     if (!checkProtoSetterAccessAllowed(exec, object))
         return JSValue::encode(objectValue);
 
-    if (object->prototype() == protoValue)
-        return JSValue::encode(objectValue);
-
-    bool isExtensible = object->isExtensible(exec);
-    if (exec->hadException())
-        return JSValue::encode(JSValue());
-    if (!isExtensible)
-        return throwVMError(exec, createTypeError(exec, StrictModeReadonlyPropertyWriteError));
-
     VM& vm = exec->vm();
-    bool didSetPrototype = object->setPrototype(vm, exec, protoValue);
-    if (vm.exception())
-        return JSValue::encode(JSValue());
-    if (!didSetPrototype) {
-        vm.throwException(exec, createError(exec, ASCIILiteral("cyclic __proto__ value")));
-        return JSValue::encode(jsUndefined());
-    }
-
+    bool shouldThrowIfCantSet = true;
+    bool didSetPrototype = object->setPrototype(vm, exec, protoValue, shouldThrowIfCantSet);
+    ASSERT_UNUSED(didSetPrototype, vm.exception() || didSetPrototype);
     return JSValue::encode(objectValue);
 }
 

Modified: trunk/Source/_javascript_Core/runtime/ReflectObject.cpp (197511 => 197512)


--- trunk/Source/_javascript_Core/runtime/ReflectObject.cpp	2016-03-03 18:34:11 UTC (rev 197511)
+++ trunk/Source/_javascript_Core/runtime/ReflectObject.cpp	2016-03-03 19:18:35 UTC (rev 197512)
@@ -212,17 +212,9 @@
     if (!checkProtoSetterAccessAllowed(exec, object))
         return JSValue::encode(jsBoolean(false));
 
-    if (object->prototype() == proto)
-        return JSValue::encode(jsBoolean(true));
-
-    bool isExtensible = object->isExtensible(exec);
-    if (exec->hadException())
-        return JSValue::encode(JSValue());
-    if (!isExtensible)
-        return JSValue::encode(jsBoolean(false));
-
     VM& vm = exec->vm();
-    bool didSetPrototype = object->setPrototype(vm, exec, proto);
+    bool shouldThrowIfCantSet = false;
+    bool didSetPrototype = object->setPrototype(vm, exec, proto, shouldThrowIfCantSet);
     if (vm.exception())
         return JSValue::encode(JSValue());
     return JSValue::encode(jsBoolean(didSetPrototype));
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to