Title: [292895] trunk
Revision
292895
Author
ca...@igalia.com
Date
2022-04-14 16:39:06 -0700 (Thu, 14 Apr 2022)

Log Message

[JSC] ShadowRealm global object has a mutable prototype
https://bugs.webkit.org/show_bug.cgi?id=239332

Reviewed by Yusuke Suzuki.

JSTests:

* stress/shadow-realm-globalThis-mutable-prototype.js: Added.

Source/_javascript_Core:

This patch circumvents the `ASSERT(toThis() == this)` in JSObject::setPrototypeWithCycleCheck()
when `this` is a GlobalObject. Ordinarily, GlobalObjects have the IsImmutablePrototypeExoticObject
bit set and miss this pathway, however this is not the case for ShadowRealm Global Objects.

In addition, the JSC internal version is also modified to have a mutable prototype in the same way
as in WebCore.

* runtime/JSGlobalObject.h:
(JSC::JSGlobalObject::deriveShadowRealmGlobalObject):
(JSC::JSGlobalObject::createStructureForShadowRealm):
* runtime/JSObject.cpp:
(JSC::JSObject::setPrototypeWithCycleCheck):

Source/WebCore:

Hack: The IDL code generator now special cases ShadowRealmGlobalObject to remove the
ImmutablePrototypeExoticObject bit from the inherited JSGlobalObject structure flags.

As a result, this enables the assignment of a ShadowRealm's globalThis.__proto__, or
overwriting the prototype with [Object / Reflect].setPrototypeOf().

Test: js/ShadowRealm-globalThis.html

* bindings/scripts/CodeGeneratorJS.pm:
(GenerateHeader):
* bindings/scripts/test/JS/JSShadowRealmGlobalScope.h:

LayoutTests:

Add a new layout test to verify changes to verify that ShadowRealmGlobalObject has a properly
mutable prototype.

* js/ShadowRealm-globalThis-expected.txt: Added.
* js/ShadowRealm-globalThis.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (292894 => 292895)


--- trunk/JSTests/ChangeLog	2022-04-14 23:36:49 UTC (rev 292894)
+++ trunk/JSTests/ChangeLog	2022-04-14 23:39:06 UTC (rev 292895)
@@ -1,3 +1,12 @@
+2022-04-14  Caitlin Potter  <ca...@igalia.com>
+
+        [JSC] ShadowRealm global object has a mutable prototype
+        https://bugs.webkit.org/show_bug.cgi?id=239332
+
+        Reviewed by Yusuke Suzuki.
+
+        * stress/shadow-realm-globalThis-mutable-prototype.js: Added.
+
 2022-04-14  Alexey Shvayka  <ashva...@apple.com>
 
         InternalFunction::createSubclassStructure() should use base object's global object

Added: trunk/JSTests/stress/shadow-realm-globalThis-mutable-prototype.js (0 => 292895)


--- trunk/JSTests/stress/shadow-realm-globalThis-mutable-prototype.js	                        (rev 0)
+++ trunk/JSTests/stress/shadow-realm-globalThis-mutable-prototype.js	2022-04-14 23:39:06 UTC (rev 292895)
@@ -0,0 +1,39 @@
+//@ requireOptions("--useShadowRealm=1")
+
+let sr = new ShadowRealm;
+
+let install = sr.evaluate(`
+(function(name, fn) {
+  globalThis[name] = fn;
+})
+`);
+
+let log = function(...args) {
+  let string = args.join(" ");
+  print(string);
+  return string;
+};
+install("log", log);
+
+// Test that the GlobalObject prototype is not immutable, 
+let MAX_ITER = 10000;
+sr.evaluate(`
+  var i = 1;
+  function test() {
+    globalThis.__proto__ = { x: i++ };
+  }
+  for (let i = 0; i < ${MAX_ITER}; ++i) {
+    try {
+      test();
+      if (globalThis.x !== i + 1)
+        throw new Error(\`Prototype not written successfully (Expected globalThis.x === \${i + 1}, but found \${globalThis.x})\`);
+    } catch (e) {
+      log(\`\${e}\`);
+      throw e;
+    }
+  }
+`);
+
+if (sr.evaluate(`globalThis.x`) !== MAX_ITER)
+  throw new Error("Prototype invalid in separate eval");
+

Modified: trunk/LayoutTests/ChangeLog (292894 => 292895)


--- trunk/LayoutTests/ChangeLog	2022-04-14 23:36:49 UTC (rev 292894)
+++ trunk/LayoutTests/ChangeLog	2022-04-14 23:39:06 UTC (rev 292895)
@@ -1,3 +1,16 @@
+2022-04-14  Caitlin Potter  <ca...@igalia.com>
+
+        [JSC] ShadowRealm global object has a mutable prototype
+        https://bugs.webkit.org/show_bug.cgi?id=239332
+
+        Reviewed by Yusuke Suzuki.
+
+        Add a new layout test to verify changes to verify that ShadowRealmGlobalObject has a properly
+        mutable prototype.
+
+        * js/ShadowRealm-globalThis-expected.txt: Added.
+        * js/ShadowRealm-globalThis.html: Added.
+
 2022-04-14  Nikolaos Mouchtaris  <nmouchta...@apple.com>
 
         calc(): Serialize top level min/max/hypot as calc()

Added: trunk/LayoutTests/js/ShadowRealm-globalThis-expected.txt (0 => 292895)


--- trunk/LayoutTests/js/ShadowRealm-globalThis-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/js/ShadowRealm-globalThis-expected.txt	2022-04-14 23:39:06 UTC (rev 292895)
@@ -0,0 +1,12 @@
+Test to ensure correct behaviour of ShadowRealm global scope
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Object.getPrototypeOf(globalThis) === Object.prototype
+globalThis.__proto__ = { alpha: "omega" };
+Object.setPrototypeOf(globalThis, { chuckle: "buckle" });
+Reflect.setPrototypeOf(globalThis, { zoo: "moo" });
+
+PASS ShadowRealm global scope is an ordinary object
+

Added: trunk/LayoutTests/js/ShadowRealm-globalThis.html (0 => 292895)


--- trunk/LayoutTests/js/ShadowRealm-globalThis.html	                        (rev 0)
+++ trunk/LayoutTests/js/ShadowRealm-globalThis.html	2022-04-14 23:39:06 UTC (rev 292895)
@@ -0,0 +1,58 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"><!-- webkit-test-runner [ jscOptions=--useShadowRealm=true ] -->
+<html>
+<head>
+<script src=""
+</head>
+<body>
+<script src =""
+<script src =""
+<script>
+    description("Test to ensure correct behaviour of ShadowRealm global scope");
+
+    promise_test(async t => {
+        const bootstrap = function() {
+            const shadowRealm = new ShadowRealm;
+            const install = shadowRealm.evaluate(`(function(name, fn) {
+                globalThis[name] = fn;
+                return;
+            })`);
+            install("debug", (...args) => { debug(...args); });
+            return shadowRealm;
+        }
+
+        debug(`Object.getPrototypeOf(globalThis) === Object.prototype`);
+        let shadowRealm = bootstrap();
+        assert_equals(shadowRealm.evaluate("Object.getPrototypeOf(globalThis) === Object.prototype"), true);
+
+        debug(`globalThis.__proto__ = { alpha: "omega" };`);
+        shadowRealm.evaluate(`try {
+            globalThis.__proto__ = { alpha: "omega" };
+            "ok";
+        } catch (e) {
+            debug("Failed to set globalThis.__proto__");
+        }`);
+        assert_equals(shadowRealm.evaluate("globalThis.alpha"), "omega");
+
+        debug(`Object.setPrototypeOf(globalThis, { chuckle: "buckle" });`);
+        shadowRealm = bootstrap();
+        shadowRealm.evaluate(`try {
+            Object.setPrototypeOf(globalThis, { chuckle: "buckle" });
+            "ok";
+        } catch (e) {
+            debug("Failure in Object.setPrototypeOf(globalThis)");
+        }`);
+        assert_equals(shadowRealm.evaluate("globalThis.chuckle"), "buckle");
+
+        debug(`Reflect.setPrototypeOf(globalThis, { zoo: "moo" });`);
+        shadowRealm = bootstrap();
+        shadowRealm.evaluate(`try {
+            Reflect.setPrototypeOf(globalThis, { zoo: "moo" });
+            "ok";
+        } catch (e) {
+            debug("Failure in Reflect.setPrototypeOf(globalThis)");
+        }`);
+        assert_equals(shadowRealm.evaluate("globalThis.zoo"), "moo");
+    }, "ShadowRealm global scope is an ordinary object");
+</script>
+</body>
+</html>

Modified: trunk/Source/_javascript_Core/ChangeLog (292894 => 292895)


--- trunk/Source/_javascript_Core/ChangeLog	2022-04-14 23:36:49 UTC (rev 292894)
+++ trunk/Source/_javascript_Core/ChangeLog	2022-04-14 23:39:06 UTC (rev 292895)
@@ -1,3 +1,23 @@
+2022-04-14  Caitlin Potter  <ca...@igalia.com>
+
+        [JSC] ShadowRealm global object has a mutable prototype
+        https://bugs.webkit.org/show_bug.cgi?id=239332
+
+        Reviewed by Yusuke Suzuki.
+
+        This patch circumvents the `ASSERT(toThis() == this)` in JSObject::setPrototypeWithCycleCheck()
+        when `this` is a GlobalObject. Ordinarily, GlobalObjects have the IsImmutablePrototypeExoticObject
+        bit set and miss this pathway, however this is not the case for ShadowRealm Global Objects. 
+
+        In addition, the JSC internal version is also modified to have a mutable prototype in the same way
+        as in WebCore.
+
+        * runtime/JSGlobalObject.h:
+        (JSC::JSGlobalObject::deriveShadowRealmGlobalObject):
+        (JSC::JSGlobalObject::createStructureForShadowRealm):
+        * runtime/JSObject.cpp:
+        (JSC::JSObject::setPrototypeWithCycleCheck):
+
 2022-04-14  Yusuke Suzuki  <ysuz...@apple.com>
 
         [JSC] Reduce use of CallFrame::deprecatedVM

Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObject.h (292894 => 292895)


--- trunk/Source/_javascript_Core/runtime/JSGlobalObject.h	2022-04-14 23:36:49 UTC (rev 292894)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObject.h	2022-04-14 23:39:06 UTC (rev 292895)
@@ -1099,7 +1099,8 @@
     static JSGlobalObject* deriveShadowRealmGlobalObject(JSGlobalObject* globalObject)
     {
         auto& vm = globalObject->vm();
-        return JSGlobalObject::createWithCustomMethodTable(vm, JSGlobalObject::createStructure(vm, jsNull()), globalObject->globalObjectMethodTable());
+        JSGlobalObject* result = JSGlobalObject::createWithCustomMethodTable(vm, JSGlobalObject::createStructureForShadowRealm(vm, jsNull()), globalObject->globalObjectMethodTable());
+        return result;
     }
 
     static bool shouldInterruptScript(const JSGlobalObject*) { return true; }
@@ -1143,6 +1144,12 @@
         result->setTransitionWatchpointIsLikelyToBeFired(true);
         return result;
     }
+    static Structure* createStructureForShadowRealm(VM& vm, JSValue prototype)
+    {
+        Structure* result = Structure::create(vm, nullptr, prototype, TypeInfo(GlobalObjectType, StructureFlags & ~IsImmutablePrototypeExoticObject), info());
+        result->setTransitionWatchpointIsLikelyToBeFired(true);
+        return result;
+    }
 
     void registerWeakMap(OpaqueJSWeakObjectMap* map)
     {

Modified: trunk/Source/_javascript_Core/runtime/JSObject.cpp (292894 => 292895)


--- trunk/Source/_javascript_Core/runtime/JSObject.cpp	2022-04-14 23:36:49 UTC (rev 292894)
+++ trunk/Source/_javascript_Core/runtime/JSObject.cpp	2022-04-14 23:39:06 UTC (rev 292895)
@@ -1915,7 +1915,9 @@
         return typeError(globalObject, scope, shouldThrowIfCantSet, "Cannot set prototype of immutable prototype object"_s);
     }
 
-    ASSERT(methodTable(vm)->toThis(this, globalObject, ECMAMode::sloppy()) == this);
+    // Default realm global objects should have mutable prototypes despite having
+    // a Proxy globalThis.
+    ASSERT(this->isGlobalObject() || methodTable(vm)->toThis(this, globalObject, ECMAMode::sloppy()) == this);
 
     if (this->getPrototypeDirect(vm) == prototype)
         return true;

Modified: trunk/Source/WebCore/ChangeLog (292894 => 292895)


--- trunk/Source/WebCore/ChangeLog	2022-04-14 23:36:49 UTC (rev 292894)
+++ trunk/Source/WebCore/ChangeLog	2022-04-14 23:39:06 UTC (rev 292895)
@@ -1,3 +1,22 @@
+2022-04-14  Caitlin Potter  <ca...@igalia.com>
+
+        [JSC] ShadowRealm global object has a mutable prototype
+        https://bugs.webkit.org/show_bug.cgi?id=239332
+
+        Reviewed by Yusuke Suzuki.
+
+        Hack: The IDL code generator now special cases ShadowRealmGlobalObject to remove the 
+        ImmutablePrototypeExoticObject bit from the inherited JSGlobalObject structure flags.
+
+        As a result, this enables the assignment of a ShadowRealm's globalThis.__proto__, or
+        overwriting the prototype with [Object / Reflect].setPrototypeOf().
+
+        Test: js/ShadowRealm-globalThis.html
+
+        * bindings/scripts/CodeGeneratorJS.pm:
+        (GenerateHeader):
+        * bindings/scripts/test/JS/JSShadowRealmGlobalScope.h:
+
 2022-04-14  Nikolaos Mouchtaris  <nmouchta...@apple.com>
 
         calc(): Serialize top level min/max/hypot as calc()

Modified: trunk/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm (292894 => 292895)


--- trunk/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm	2022-04-14 23:36:49 UTC (rev 292894)
+++ trunk/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm	2022-04-14 23:39:06 UTC (rev 292895)
@@ -3205,7 +3205,12 @@
     # structure flags
     if (%structureFlags) {
         push(@headerContent, "public:\n");
-        push(@headerContent, "    static constexpr unsigned StructureFlags = Base::StructureFlags");
+        if ($interfaceName eq "ShadowRealmGlobalScope") {
+            # Hack to make ShadowRealmGlobalScope a default realm global object (not an ImmutablePrototypeExoticObject)
+            push(@headerContent, "    static constexpr unsigned StructureFlags = (Base::StructureFlags & ~JSC::IsImmutablePrototypeExoticObject)");
+        } else {
+            push(@headerContent, "    static constexpr unsigned StructureFlags = Base::StructureFlags");
+        }
         foreach my $structureFlag (sort (keys %structureFlags)) {
             push(@headerContent, " | " . $structureFlag);
         }

Modified: trunk/Source/WebCore/bindings/scripts/test/JS/JSShadowRealmGlobalScope.h (292894 => 292895)


--- trunk/Source/WebCore/bindings/scripts/test/JS/JSShadowRealmGlobalScope.h	2022-04-14 23:36:49 UTC (rev 292894)
+++ trunk/Source/WebCore/bindings/scripts/test/JS/JSShadowRealmGlobalScope.h	2022-04-14 23:39:06 UTC (rev 292895)
@@ -57,7 +57,7 @@
     static JSC::GCClient::IsoSubspace* subspaceForImpl(JSC::VM& vm);
     static void analyzeHeap(JSCell*, JSC::HeapAnalyzer&);
 public:
-    static constexpr unsigned StructureFlags = Base::StructureFlags | JSC::HasStaticPropertyTable;
+    static constexpr unsigned StructureFlags = (Base::StructureFlags & ~JSC::IsImmutablePrototypeExoticObject) | JSC::HasStaticPropertyTable;
 protected:
     JSShadowRealmGlobalScope(JSC::VM&, JSC::Structure*, Ref<ShadowRealmGlobalScope>&&);
     void finishCreation(JSC::VM&, JSC::JSProxy*);
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to