X.[[SetPrototypeOf]](Y) should succeed if X.[[Prototype]] is already Y even if X...
authorutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 13 Aug 2015 17:25:01 +0000 (17:25 +0000)
committerutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 13 Aug 2015 17:25:01 +0000 (17:25 +0000)
https://bugs.webkit.org/show_bug.cgi?id=147930

Reviewed by Saam Barati.

When the passed prototype object to be set is the same to the existing
prototype object, [[SetPrototypeOf]] just finishes its operation even
if the extensibility of the target object is `false`.

* runtime/JSGlobalObjectFunctions.cpp:
(JSC::globalFuncProtoSetter):
* runtime/ObjectConstructor.cpp:
(JSC::objectConstructorSetPrototypeOf):
* runtime/ReflectObject.cpp:
(JSC::reflectObjectSetPrototypeOf):
* tests/stress/set-same-prototype.js: Added.
(shouldBe):
(shouldThrow):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188384 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp
Source/JavaScriptCore/runtime/ObjectConstructor.cpp
Source/JavaScriptCore/runtime/ReflectObject.cpp
Source/JavaScriptCore/tests/stress/set-same-prototype.js [new file with mode: 0644]

index 8ec6425..c5dffb5 100644 (file)
@@ -1,3 +1,24 @@
+2015-08-13  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        X.[[SetPrototypeOf]](Y) should succeed if X.[[Prototype]] is already Y even if X is not extensible
+        https://bugs.webkit.org/show_bug.cgi?id=147930
+
+        Reviewed by Saam Barati.
+
+        When the passed prototype object to be set is the same to the existing
+        prototype object, [[SetPrototypeOf]] just finishes its operation even
+        if the extensibility of the target object is `false`.
+
+        * runtime/JSGlobalObjectFunctions.cpp:
+        (JSC::globalFuncProtoSetter):
+        * runtime/ObjectConstructor.cpp:
+        (JSC::objectConstructorSetPrototypeOf):
+        * runtime/ReflectObject.cpp:
+        (JSC::reflectObjectSetPrototypeOf):
+        * tests/stress/set-same-prototype.js: Added.
+        (shouldBe):
+        (shouldThrow):
+
 2015-08-12  Geoffrey Garen  <ggaren@apple.com>
 
         Removed clearEvalCodeCache()
index 3362441..b7ee125 100644 (file)
@@ -874,6 +874,9 @@ EncodedJSValue JSC_HOST_CALL globalFuncProtoSetter(ExecState* exec)
     if (!value.isObject() && !value.isNull())
         return JSValue::encode(jsUndefined());
 
+    if (thisObject->prototype() == value)
+        return JSValue::encode(jsUndefined());
+
     if (!thisObject->isExtensible())
         return throwVMError(exec, createTypeError(exec, StrictModeReadonlyPropertyWriteError));
 
index a2a2088..65acb48 100644 (file)
@@ -208,6 +208,9 @@ EncodedJSValue JSC_HOST_CALL objectConstructorSetPrototypeOf(ExecState* exec)
     if (!checkProtoSetterAccessAllowed(exec, object))
         return JSValue::encode(objectValue);
 
+    if (object->prototype() == protoValue)
+        return JSValue::encode(objectValue);
+
     if (!object->isExtensible())
         return throwVMError(exec, createTypeError(exec, StrictModeReadonlyPropertyWriteError));
 
index ea3321e..b9a127e 100644 (file)
@@ -168,6 +168,9 @@ EncodedJSValue JSC_HOST_CALL reflectObjectSetPrototypeOf(ExecState* exec)
     if (!checkProtoSetterAccessAllowed(exec, object))
         return JSValue::encode(jsBoolean(false));
 
+    if (object->prototype() == proto)
+        return JSValue::encode(jsBoolean(true));
+
     if (!object->isExtensible())
         return JSValue::encode(jsBoolean(false));
 
diff --git a/Source/JavaScriptCore/tests/stress/set-same-prototype.js b/Source/JavaScriptCore/tests/stress/set-same-prototype.js
new file mode 100644 (file)
index 0000000..65f5c71
--- /dev/null
@@ -0,0 +1,38 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function shouldThrow(func, errorMessage) {
+    var errorThrown = false;
+    var error = null;
+    try {
+        func();
+    } catch (e) {
+        errorThrown = true;
+        error = e;
+    }
+    if (!errorThrown)
+        throw new Error('not thrown');
+    if (String(error) !== errorMessage)
+        throw new Error(`bad error: ${String(error)}`);
+}
+
+var proto = {};
+var object = Object.preventExtensions(Object.create(proto));
+
+shouldBe(Object.setPrototypeOf(object, proto), object);
+shouldThrow(() => {
+    Object.setPrototypeOf(object, {});
+}, `TypeError: Attempted to assign to readonly property.`);
+shouldBe(Reflect.getPrototypeOf(object), proto);
+
+shouldBe(Reflect.setPrototypeOf(object, proto), true);
+shouldBe(Reflect.setPrototypeOf(object, {}), false);
+shouldBe(Reflect.getPrototypeOf(object), proto);
+
+object.__proto__ = proto;
+shouldThrow(() => {
+    object.__proto__ = {};
+}, `TypeError: Attempted to assign to readonly property.`);
+shouldBe(object.__proto__, proto);