Title: [280460] trunk
Revision
280460
Author
shvaikal...@gmail.com
Date
2021-07-29 18:36:31 -0700 (Thu, 29 Jul 2021)

Log Message

[JSC] Legacy RegExp fields should be accessors
https://bugs.webkit.org/show_bug.cgi?id=220233

Reviewed by Tadeu Zagallo.

JSTests:

* ChakraCore/test/Lib/forin_lib_v3.baseline-jsc:
* microbenchmarks/assign-custom-setter-polymorphic.js:
* microbenchmarks/assign-custom-setter.js:
* microbenchmarks/custom-setter-getter-as-put-get-by-id.js:
* microbenchmarks/custom-value-2.js:
* microbenchmarks/custom-value.js:
* microbenchmarks/get-custom-getter.js:
* stress/custom-value-delete-property-1.js:
* stress/custom-value-delete-property-2.js:
* stress/custom-value-delete-property-3.js:
* stress/object-assign-fast-path.js:
* stress/reflect-set.js:
* stress/regexp-constructor-dollar-getters-are-unique.js: Added.
* stress/regexp-setter-realm.js: Added.
* stress/static-put-in-prototype-chain.js: Added.
* test262/config.yaml:
* test262/expectations.yaml:

Source/_javascript_Core:

This patch implements a part of Legacy RegExp features proposal [1], replacing
custom values with custom accessors that require |this| value to be RegExp
constructor of the same realm.

Apart from fixing property descriptors, this change brings legacy RegExpConstructor
fields in compliance with invariants of internal methods [2] (described in #151348),
aligning JSC with V8 and SpiderMonkey.

It doesn't, however, implement [[LegacyFeaturesEnabled]] and RegExp.prototype.compile
changes.

[1]: https://github.com/tc39/proposal-regexp-legacy-features
[2]: https://tc39.es/ecma262/#sec-invariants-of-the-essential-internal-methods

* bytecode/AccessCase.cpp:
(JSC::AccessCase::generateImpl):
* runtime/RegExpConstructor.cpp:
(JSC::JSC_DEFINE_CUSTOM_GETTER):
(JSC::JSC_DEFINE_CUSTOM_SETTER):
(JSC::regExpConstructorDollarImpl): Deleted.
* tools/JSDollarVM.cpp:

LayoutTests:

* js/dom/getOwnPropertyDescriptor-expected.txt:
* js/dom/regexp-caching-expected.txt:
* js/dom/regexp-caching.html:
* js/resources/getOwnPropertyDescriptor.js:
* js/script-tests/static-put-in-prototype-chain.js:
* js/static-put-in-prototype-chain-expected.txt:
* js/static-put-in-prototype-chain.html:

Modified Paths

Added Paths

Removed Paths

Diff

Modified: trunk/JSTests/ChakraCore/test/Lib/forin_lib_v3.baseline-jsc (280459 => 280460)


--- trunk/JSTests/ChakraCore/test/Lib/forin_lib_v3.baseline-jsc	2021-07-30 00:28:45 UTC (rev 280459)
+++ trunk/JSTests/ChakraCore/test/Lib/forin_lib_v3.baseline-jsc	2021-07-30 01:36:31 UTC (rev 280460)
@@ -78,38 +78,8 @@
   blah2 = Date
 
 for..in RegExp
-  input = 
-  multiline = false
-  lastMatch = 
-  lastParen = 
-  leftContext = 
-  rightContext = 
-  $1 = 
-  $2 = 
-  $3 = 
-  $4 = 
-  $5 = 
-  $6 = 
-  $7 = 
-  $8 = 
-  $9 = 
   blah2 = Function
 for..in RegExp (with blah)
-  input = 
-  multiline = false
-  lastMatch = 
-  lastParen = 
-  leftContext = 
-  rightContext = 
-  $1 = 
-  $2 = 
-  $3 = 
-  $4 = 
-  $5 = 
-  $6 = 
-  $7 = 
-  $8 = 
-  $9 = 
   blah = b
   blah2 = Function
 for..in new RegExp

Modified: trunk/JSTests/ChangeLog (280459 => 280460)


--- trunk/JSTests/ChangeLog	2021-07-30 00:28:45 UTC (rev 280459)
+++ trunk/JSTests/ChangeLog	2021-07-30 01:36:31 UTC (rev 280460)
@@ -1,3 +1,28 @@
+2021-07-29  Yusuke Suzuki  <ysuz...@apple.com> and Alexey Shvayka  <shvaikal...@gmail.com>
+
+        [JSC] Legacy RegExp fields should be accessors
+        https://bugs.webkit.org/show_bug.cgi?id=220233
+
+        Reviewed by Tadeu Zagallo.
+
+        * ChakraCore/test/Lib/forin_lib_v3.baseline-jsc:
+        * microbenchmarks/assign-custom-setter-polymorphic.js:
+        * microbenchmarks/assign-custom-setter.js:
+        * microbenchmarks/custom-setter-getter-as-put-get-by-id.js:
+        * microbenchmarks/custom-value-2.js:
+        * microbenchmarks/custom-value.js:
+        * microbenchmarks/get-custom-getter.js:
+        * stress/custom-value-delete-property-1.js:
+        * stress/custom-value-delete-property-2.js:
+        * stress/custom-value-delete-property-3.js:
+        * stress/object-assign-fast-path.js:
+        * stress/reflect-set.js:
+        * stress/regexp-constructor-dollar-getters-are-unique.js: Added.
+        * stress/regexp-setter-realm.js: Added.
+        * stress/static-put-in-prototype-chain.js: Added.
+        * test262/config.yaml:
+        * test262/expectations.yaml:
+
 2021-07-28  Yusuke Suzuki  <ysuz...@apple.com>
 
         [JSC] Yarr should perform BoyerMoore search

Modified: trunk/JSTests/microbenchmarks/assign-custom-setter-polymorphic.js (280459 => 280460)


--- trunk/JSTests/microbenchmarks/assign-custom-setter-polymorphic.js	2021-07-30 00:28:45 UTC (rev 280459)
+++ trunk/JSTests/microbenchmarks/assign-custom-setter-polymorphic.js	2021-07-30 01:36:31 UTC (rev 280460)
@@ -1,20 +1,20 @@
 //@ skip if $model == "Apple Watch Series 3" # added by mark-jsc-stress-test.py
 
-o = RegExp;
+o = $vm.createCustomTestGetterSetter();
 j = 0;
 l = 2;
 z = 0;
 function test(o, z) {
     var k = arguments[(((j << 1 | l) >> 1) ^ 1) & (z *= 1)];
-    k.input = 0;
+    k.customValue2 = 0;
     for (var i = 0; i < 25000; i++) {
-        k.input = "foo";
+        k.customValue2 = "foo";
     }
 
-    return k.input;
+    return k.customValue2;
 }
-var result = test({__proto__: {bar:"wibble", input:"foo"}});
-var result = test({input:"foo"});
+var result = test({__proto__: {bar:"wibble", customValue2:"foo"}});
+var result = test({customValue2:"foo"});
 var result = test(o)
 for (var k = 0; k < 6; k++) {
     var start = new Date;

Modified: trunk/JSTests/microbenchmarks/assign-custom-setter.js (280459 => 280460)


--- trunk/JSTests/microbenchmarks/assign-custom-setter.js	2021-07-30 00:28:45 UTC (rev 280459)
+++ trunk/JSTests/microbenchmarks/assign-custom-setter.js	2021-07-30 01:36:31 UTC (rev 280460)
@@ -1,14 +1,13 @@
 //@ skip if $model == "Apple Watch Series 3" # added by mark-jsc-stress-test.py
-// RegExp.input is a handy setter
 
-var o = RegExp;
+var o = $vm.createCustomTestGetterSetter();
 function test(o) {
     var k = 0;
-    o.input = "bar";
+    o.customValue2 = "bar";
     for (var i = 0; i < 30000; i++)
-        o.input = "foo";
+        o.customValue2 = "foo";
 
-    return o.input;
+    return o.customValue2;
 }
 
 var result = test(o);

Modified: trunk/JSTests/microbenchmarks/custom-setter-getter-as-put-get-by-id.js (280459 => 280460)


--- trunk/JSTests/microbenchmarks/custom-setter-getter-as-put-get-by-id.js	2021-07-30 00:28:45 UTC (rev 280459)
+++ trunk/JSTests/microbenchmarks/custom-setter-getter-as-put-get-by-id.js	2021-07-30 01:36:31 UTC (rev 280460)
@@ -5,21 +5,20 @@
 }
 noInline(assert);
 
-// RegExp.input is a handy custom getter/setter.
-var o1 = RegExp;
+var o1 = $vm.createCustomTestGetterSetter();
 function test(o) {
-    o.input = "bar";
-    return o.input;
+    o.customValue2 = "bar";
+    return o.customValue2;
 }
 noInline(test);
 
 var o2 = {
-    input: "hello"
+    customValue2: "hello"
 }
 
 var o3 = {
     x: 20,
-    input: "hello"
+    customValue2: "hello"
 }
 
 // First compile as GetById node.

Modified: trunk/JSTests/microbenchmarks/custom-value-2.js (280459 => 280460)


--- trunk/JSTests/microbenchmarks/custom-value-2.js	2021-07-30 00:28:45 UTC (rev 280459)
+++ trunk/JSTests/microbenchmarks/custom-value-2.js	2021-07-30 01:36:31 UTC (rev 280460)
@@ -4,24 +4,25 @@
         throw new Error;
 }
 
+const Value = $vm.createCustomTestGetterSetter();
 function test1() {
-    function getMultiline(o) {
-        return o.multiline;
+    function getCustomValue2(o) {
+        return o.customValue2;
     }
-    noInline(getMultiline);
+    noInline(getCustomValue2);
 
-    RegExp.foo = 42;
+    Value.foo = 42;
 
     const o = {};
-    o.__proto__ = RegExp;
-    RegExp.multiline = false;
+    o.__proto__ = Value;
+    Value.customValue2 = false;
 
     for (let i = 0; i < 5000000; ++i) {
-        assert(getMultiline(o) === false);
+        assert(getCustomValue2(o) === false);
     }
-    delete RegExp.foo;
+    delete Value.foo;
     for (let i = 0; i < 5000000; ++i) {
-        assert(getMultiline(o) === false);
+        assert(getCustomValue2(o) === false);
     }
 }
 test1();

Modified: trunk/JSTests/microbenchmarks/custom-value.js (280459 => 280460)


--- trunk/JSTests/microbenchmarks/custom-value.js	2021-07-30 00:28:45 UTC (rev 280459)
+++ trunk/JSTests/microbenchmarks/custom-value.js	2021-07-30 01:36:31 UTC (rev 280460)
@@ -4,18 +4,19 @@
         throw new Error;
 }
 
+const Value = $vm.createCustomTestGetterSetter();
 function test1() {
-    function getMultiline(o) {
-        return o.multiline;
+    function getCustomValue2(o) {
+        return o.customValue2;
     }
-    noInline(getMultiline);
+    noInline(getCustomValue2);
 
     const o = {};
-    o.__proto__ = RegExp;
-    RegExp.multiline = false;
+    o.__proto__ = Value;
+    Value.customValue2 = false;
 
     for (let i = 0; i < 5000000; ++i) {
-        assert(getMultiline(o) === false);
+        assert(getCustomValue2(o) === false);
     }
 }
 

Modified: trunk/JSTests/microbenchmarks/get-custom-getter.js (280459 => 280460)


--- trunk/JSTests/microbenchmarks/get-custom-getter.js	2021-07-30 00:28:45 UTC (rev 280459)
+++ trunk/JSTests/microbenchmarks/get-custom-getter.js	2021-07-30 01:36:31 UTC (rev 280460)
@@ -1,13 +1,12 @@
 //@ skip if $model == "Apple Watch Series 3" # added by mark-jsc-stress-test.py
-// RegExp.input is a handy getter
 
-var o = RegExp;
-o.input = "foo";
+var o = $vm.createCustomTestGetterSetter();
+o.customValue2 = "foo";
 
 function test(o) {
     var result = null;
     for (var i = 0; i < 30000; i++)
-        result = o.input;
+        result = o.customValue2;
 
     return result;
 }

Modified: trunk/JSTests/stress/custom-value-delete-property-1.js (280459 => 280460)


--- trunk/JSTests/stress/custom-value-delete-property-1.js	2021-07-30 00:28:45 UTC (rev 280459)
+++ trunk/JSTests/stress/custom-value-delete-property-1.js	2021-07-30 01:36:31 UTC (rev 280460)
@@ -3,21 +3,21 @@
         throw new Error;
 }
 
+const Value = $vm.createCustomTestGetterSetter();
 function test1() {
-    function getMultiline(o) {
-        return o.multiline;
+    function getCustomValue2(o) {
+        return o.customValue2;
     }
-    noInline(getMultiline);
+    noInline(getCustomValue2);
 
     const o = {};
-    o.__proto__ = RegExp;
-    RegExp.multiline = false;
+    o.__proto__ = Value;
+    Value.customValue2 = false;
 
     for (let i = 0; i < 500; ++i) {
-        assert(getMultiline(o) === false);
+        assert(getCustomValue2(o) === false);
     }
-    delete RegExp.input;
-    delete RegExp.multiline;
-    assert(getMultiline(o) === undefined);
+    delete Value.customValue2;
+    assert(getCustomValue2(o) === undefined);
 }
 test1();

Modified: trunk/JSTests/stress/custom-value-delete-property-2.js (280459 => 280460)


--- trunk/JSTests/stress/custom-value-delete-property-2.js	2021-07-30 00:28:45 UTC (rev 280459)
+++ trunk/JSTests/stress/custom-value-delete-property-2.js	2021-07-30 01:36:31 UTC (rev 280460)
@@ -1,11 +1,12 @@
+const Value = $vm.createCustomTestGetterSetter();
 function test2() {
     function foo() {
         const o = {};
         for (let i = 0; i < 8; i++) {
-            let x = o.multiline;
-            o.__proto__ = RegExp;
+            let x = o.customValue2;
+            o.__proto__ = Value;
         }
-        delete RegExp.input;
+        delete Value.customValue;
     }
 
     foo();

Modified: trunk/JSTests/stress/custom-value-delete-property-3.js (280459 => 280460)


--- trunk/JSTests/stress/custom-value-delete-property-3.js	2021-07-30 00:28:45 UTC (rev 280459)
+++ trunk/JSTests/stress/custom-value-delete-property-3.js	2021-07-30 01:36:31 UTC (rev 280460)
@@ -1,11 +1,12 @@
 function test6() {
+    var custom = $vm.createCustomTestGetterSetter();
     function foo() {
         const o = {};
         for (let i = 0; i < 8; i++) {
-            o.lastMatch;
-            o.__proto__ = RegExp;
+            o.customValue2;
+            o.__proto__ = custom;
         }
-        delete RegExp.input;
+        delete custom.customValue2;
     }
 
     foo();

Modified: trunk/JSTests/stress/object-assign-fast-path.js (280459 => 280460)


--- trunk/JSTests/stress/object-assign-fast-path.js	2021-07-30 00:28:45 UTC (rev 280459)
+++ trunk/JSTests/stress/object-assign-fast-path.js	2021-07-30 01:36:31 UTC (rev 280460)
@@ -32,9 +32,13 @@
 
 {
     let result = Object.assign({}, RegExp);
-    shouldBe(JSON.stringify(Object.getOwnPropertyNames(result).sort()), `["$1","$2","$3","$4","$5","$6","$7","$8","$9","input","lastMatch","lastParen","leftContext","multiline","rightContext"]`);
+    shouldBe(JSON.stringify(Object.getOwnPropertyNames(result).sort()), `[]`);
 }
 {
+    let result = Object.assign({}, $vm.createCustomTestGetterSetter());
+    shouldBe(JSON.stringify(Object.getOwnPropertyNames(result).sort()), `["customAccessor","customAccessorGlobalObject","customAccessorReadOnly","customFunction","customValue","customValue2","customValueGlobalObject","customValueNoSetter"]`);
+}
+{
     function Hello() { }
     let result = Object.assign(Hello, {
         ok: 42

Modified: trunk/JSTests/stress/reflect-set.js (280459 => 280460)


--- trunk/JSTests/stress/reflect-set.js	2021-07-30 00:28:45 UTC (rev 280459)
+++ trunk/JSTests/stress/reflect-set.js	2021-07-30 01:36:31 UTC (rev 280460)
@@ -1117,10 +1117,7 @@
     receiverTestIndexed(/hello/, {});
 }());
 
-(function customValue() {
-    // In this case, RegExp.multiline behaves like a setter because it coerce boolean type.
-    // Anyway, it's OK, because RegExp.multiline is not specified in the spec.
-
+(function regExpMultiline() {
     function test1() {
         shouldBe(Reflect.set(RegExp, 'multiline', 'Cappuccino'), true);
         shouldBe(Reflect.get(RegExp, 'multiline'), true);
@@ -1128,8 +1125,8 @@
         shouldBe(Reflect.get(RegExp, 'multiline'), false);
 
         var receiver = {};
-        shouldBe(Reflect.set(RegExp, 'multiline', 'Cappuccino', receiver), true);
-        shouldBe(Reflect.get(receiver, 'multiline'), 'Cappuccino');
+        shouldThrow(() => Reflect.set(RegExp, 'multiline', 'Cappuccino', receiver), `TypeError: RegExp.multiline setters require RegExp constructor as |this|`);
+        shouldBe(Reflect.get(receiver, 'multiline'), undefined);
         shouldBe(Reflect.get(RegExp, 'multiline'), false);
     }
 
@@ -1141,8 +1138,8 @@
         shouldBe(Reflect.get(RegExp, 'multiline'), false);
 
         var receiver = {};
-        shouldBe(Reflect.set(RegExp, 'multiline', 'Cappuccino', receiver), true);
-        shouldBe(Reflect.get(receiver, 'multiline'), 'Cappuccino');
+        shouldThrow(() => Reflect.set(RegExp, 'multiline', 'Cappuccino', receiver), `TypeError: RegExp.multiline setters require RegExp constructor as |this|`);
+        shouldBe(Reflect.get(receiver, 'multiline'), undefined);
         shouldBe(Reflect.get(RegExp, 'multiline'), false);
     }
 
@@ -1151,11 +1148,11 @@
         shouldBe(Reflect.defineProperty(RegExp, 'multiline', {
             writable: false
         }), true);
-        shouldBe(Reflect.get(RegExp, 'multiline'), false);
+        shouldBe(Reflect.get(RegExp, 'multiline'), undefined);
         shouldBe(Reflect.set(RegExp, 'multiline', 'Cappuccino'), false);
-        shouldBe(Reflect.get(RegExp, 'multiline'), false);
+        shouldBe(Reflect.get(RegExp, 'multiline'), undefined);
         shouldBe(Reflect.set(RegExp, 'multiline', 0), false);
-        shouldBe(Reflect.get(RegExp, 'multiline'), false);
+        shouldBe(Reflect.get(RegExp, 'multiline'), undefined);
 
         var receiver = {};
         shouldBe(Reflect.set(RegExp, 'multiline', 'Cappuccino', receiver), false);
@@ -1201,6 +1198,55 @@
     }, `TypeError: Attempted to assign to readonly property.`);
 }());
 
+(function customValue() {
+    const Value = $vm.createCustomTestGetterSetter();
+    function test1() {
+        shouldBe(Reflect.set(Value, 'customValue2', 'Cappuccino'), true);
+        shouldBe(Reflect.get(Value, 'customValue2'), 'Cappuccino');
+        shouldBe(Reflect.set(Value, 'customValue2', 0), true);
+        shouldBe(Reflect.get(Value, 'customValue2'), 0);
+
+        var receiver = {};
+        shouldBe(Reflect.set(Value, 'customValue2', 'Cappuccino', receiver), true);
+        shouldBe(Reflect.get(receiver, 'customValue2'), 'Cappuccino');
+        shouldBe(Reflect.get(Value, 'customValue2'), 0);
+    }
+
+    function test2() {
+        'use strict';
+        shouldBe(Reflect.set(Value, 'customValue2', 'Cappuccino'), true);
+        shouldBe(Reflect.get(Value, 'customValue2'), 'Cappuccino');
+        shouldBe(Reflect.set(Value, 'customValue2', 0), true);
+        shouldBe(Reflect.get(Value, 'customValue2'), 0);
+
+        var receiver = {};
+        shouldBe(Reflect.set(Value, 'customValue2', 'Cappuccino', receiver), true);
+        shouldBe(Reflect.get(receiver, 'customValue2'), 'Cappuccino');
+        shouldBe(Reflect.get(Value, 'customValue2'), 0);
+    }
+
+    function test3() {
+        'use strict';
+        shouldBe(Reflect.defineProperty(Value, 'customValue2', {
+            writable: false,
+            value: undefined,
+        }), true);
+        shouldBe(Reflect.get(Value, 'customValue2'), undefined);
+        shouldBe(Reflect.set(Value, 'customValue2', 'Cappuccino'), false);
+        shouldBe(Reflect.get(Value, 'customValue2'), undefined);
+        shouldBe(Reflect.set(Value, 'customValue2', 0), false);
+        shouldBe(Reflect.get(Value, 'customValue2'), undefined);
+
+        var receiver = {};
+        shouldBe(Reflect.set(Value, 'customValue2', 'Cappuccino', receiver), false);
+        shouldBe(Reflect.get(receiver, 'customValue2'), undefined);
+    }
+
+    test1();
+    test2();
+    test3();
+}());
+
 (function functionCase() {
     var func = function () { };
     shouldBe(Reflect.get(func, 'arguments'), null);

Added: trunk/JSTests/stress/regexp-constructor-dollar-getters-are-unique.js (0 => 280460)


--- trunk/JSTests/stress/regexp-constructor-dollar-getters-are-unique.js	                        (rev 0)
+++ trunk/JSTests/stress/regexp-constructor-dollar-getters-are-unique.js	2021-07-30 01:36:31 UTC (rev 280460)
@@ -0,0 +1,16 @@
+function assert(x) {
+    if (!x)
+        throw new Error("Bad assertion!");
+}
+
+const seenGetters = new WeakSet();
+
+for (const [key, desc] of Object.entries(Object.getOwnPropertyDescriptors(RegExp))) {
+    if (!/^\$\d$/.test(key))
+        continue;
+
+    assert(typeof desc.get === "function");
+    assert(!seenGetters.has(desc.get));
+
+    seenGetters.add(desc.get);
+}

Added: trunk/JSTests/stress/regexp-setter-realm.js (0 => 280460)


--- trunk/JSTests/stress/regexp-setter-realm.js	                        (rev 0)
+++ trunk/JSTests/stress/regexp-setter-realm.js	2021-07-30 01:36:31 UTC (rev 280460)
@@ -0,0 +1,9 @@
+let realm = createGlobalObject();
+{
+    let descriptor = Object.getOwnPropertyDescriptor(realm.RegExp, "multiline");
+    descriptor.set.call(realm.RegExp, 42);
+}
+{
+    let descriptor = Object.getOwnPropertyDescriptor(realm.RegExp, "input");
+    descriptor.set.call(realm.RegExp, 42);
+}

Added: trunk/JSTests/stress/static-put-in-prototype-chain.js (0 => 280460)


--- trunk/JSTests/stress/static-put-in-prototype-chain.js	                        (rev 0)
+++ trunk/JSTests/stress/static-put-in-prototype-chain.js	2021-07-30 01:36:31 UTC (rev 280460)
@@ -0,0 +1,14 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+var target = $vm.createCustomTestGetterSetter();
+var testObject = { __proto__: target }
+var result = {
+    result: undefined
+};
+
+testObject.customValue = result;
+
+shouldBe(result.result, target);

Modified: trunk/JSTests/test262/config.yaml (280459 => 280460)


--- trunk/JSTests/test262/config.yaml	2021-07-30 00:28:45 UTC (rev 280459)
+++ trunk/JSTests/test262/config.yaml	2021-07-30 01:36:31 UTC (rev 280460)
@@ -22,7 +22,6 @@
     - Atomics.waitAsync
     # https://bugs.webkit.org/show_bug.cgi?id=174931
     - regexp-lookbehind
-    - legacy-regexp
     - cleanupSome
     - Intl.Locale-info
     - resizable-arraybuffer

Modified: trunk/JSTests/test262/expectations.yaml (280459 => 280460)


--- trunk/JSTests/test262/expectations.yaml	2021-07-30 00:28:45 UTC (rev 280459)
+++ trunk/JSTests/test262/expectations.yaml	2021-07-30 01:36:31 UTC (rev 280460)
@@ -5,6 +5,12 @@
 test/annexB/built-ins/Function/createdynfn-html-open-comment-params.js:
   default: "SyntaxError: Unexpected token '}'. Expected a parameter pattern or a ')' in parameter list."
   strict mode: "SyntaxError: Unexpected token '}'. Expected a parameter pattern or a ')' in parameter list."
+test/annexB/built-ins/RegExp/prototype/compile/this-cross-realm-instance.js:
+  default: 'Test262Error: `RegExp.prototype.compile.call(otherRealm_regexp)` throws TypeError Expected a TypeError to be thrown but no exception was thrown at all'
+  strict mode: 'Test262Error: `RegExp.prototype.compile.call(otherRealm_regexp)` throws TypeError Expected a TypeError to be thrown but no exception was thrown at all'
+test/annexB/built-ins/RegExp/prototype/compile/this-subclass-instance.js:
+  default: 'Test262Error: `subclass_regexp.compile()` throws TypeError Expected a TypeError to be thrown but no exception was thrown at all'
+  strict mode: 'Test262Error: `subclass_regexp.compile()` throws TypeError Expected a TypeError to be thrown but no exception was thrown at all'
 test/annexB/language/eval-code/direct/func-block-decl-eval-func-skip-early-err-block.js:
   default: 'Test262Error: An initialized binding is not created prior to evaluation Expected a ReferenceError to be thrown but no exception was thrown at all'
 test/annexB/language/eval-code/direct/func-block-decl-eval-func-skip-early-err-for-in.js:
@@ -669,6 +675,9 @@
 test/built-ins/Function/prototype/toString/async-method-object.js:
   default: 'Test262Error: Conforms to NativeFunction Syntax: "async function f( /* b */ ) /* c */ { /* d */ }" (async f /* a */ ( /* b */ ) /* c */ { /* d */ })'
   strict mode: 'Test262Error: Conforms to NativeFunction Syntax: "async function f( /* b */ ) /* c */ { /* d */ }" (async f /* a */ ( /* b */ ) /* c */ { /* d */ })'
+test/built-ins/Function/prototype/toString/built-in-function-object.js:
+  default: 'Test262Error: Conforms to NativeFunction Syntax: "function $*() {\n    [native code]\n}" (%RegExp%.$*)'
+  strict mode: 'Test262Error: Conforms to NativeFunction Syntax: "function $*() {\n    [native code]\n}" (%RegExp%.$*)'
 test/built-ins/Function/prototype/toString/function-declaration-non-simple-parameter-list.js:
   default: 'Test262Error: Conforms to NativeFunction Syntax: "function f( /* c */ a /* d */ = /* e */ 0 /* f */ , /* g */ { /* h */ b /* i */ = /* j */ 0 /* k */ } /* l */ ) /* m */ { /* n */ }" (function /* a */ f /* b */ ( /* c */ a /* d */ = /* e */ 0 /* f */ , /* g */ { /* h */ b /* i */ = /* j */ 0 /* k */ } /* l */ ) /* m */ { /* n */ })'
   strict mode: 'Test262Error: Conforms to NativeFunction Syntax: "function f( /* c */ a /* d */ = /* e */ 0 /* f */ , /* g */ { /* h */ b /* i */ = /* j */ 0 /* k */ } /* l */ ) /* m */ { /* n */ }" (function /* a */ f /* b */ ( /* c */ a /* d */ = /* e */ 0 /* f */ , /* g */ { /* h */ b /* i */ = /* j */ 0 /* k */ } /* l */ ) /* m */ { /* n */ })'
@@ -762,9 +771,6 @@
 test/built-ins/Object/entries/order-after-define-property.js:
   default: 'Test262Error: Expected [a, name] and [name, a] to have the same contents. '
   strict mode: 'Test262Error: Expected [a, name] and [name, a] to have the same contents. '
-test/built-ins/Object/internals/DefineOwnProperty/consistent-value-regexp-dollar1.js:
-  default: 'Test262Error: Expected SameValue(«», «x») to be true'
-  strict mode: 'Test262Error: Expected SameValue(«», «x») to be true'
 test/built-ins/Object/keys/order-after-define-property.js:
   default: 'Test262Error: Expected [a, length] and [length, a] to have the same contents. '
   strict mode: 'Test262Error: Expected [a, length] and [length, a] to have the same contents. '

Modified: trunk/LayoutTests/ChangeLog (280459 => 280460)


--- trunk/LayoutTests/ChangeLog	2021-07-30 00:28:45 UTC (rev 280459)
+++ trunk/LayoutTests/ChangeLog	2021-07-30 01:36:31 UTC (rev 280460)
@@ -1,3 +1,18 @@
+2021-07-29  Yusuke Suzuki  <ysuz...@apple.com> and Alexey Shvayka  <shvaikal...@gmail.com>
+
+        [JSC] Legacy RegExp fields should be accessors
+        https://bugs.webkit.org/show_bug.cgi?id=220233
+
+        Reviewed by Tadeu Zagallo.
+
+        * js/dom/getOwnPropertyDescriptor-expected.txt:
+        * js/dom/regexp-caching-expected.txt:
+        * js/dom/regexp-caching.html:
+        * js/resources/getOwnPropertyDescriptor.js:
+        * js/script-tests/static-put-in-prototype-chain.js:
+        * js/static-put-in-prototype-chain-expected.txt:
+        * js/static-put-in-prototype-chain.html:
+
 2021-07-29  Devin Rousso  <drou...@apple.com>
 
         [Payment Request] `additionalShippingMethods` are not used if a `paymentMethodType` is provided

Modified: trunk/LayoutTests/js/dom/getOwnPropertyDescriptor-expected.txt (280459 => 280460)


--- trunk/LayoutTests/js/dom/getOwnPropertyDescriptor-expected.txt	2021-07-30 00:28:45 UTC (rev 280459)
+++ trunk/LayoutTests/js/dom/getOwnPropertyDescriptor-expected.txt	2021-07-30 01:36:31 UTC (rev 280460)
@@ -39,9 +39,10 @@
 PASS Object.getOwnPropertyDescriptor(Number, 'NEGATIVE_INFINITY').hasOwnProperty('set') is false
 PASS Object.getOwnPropertyDescriptor(Number, 'NEGATIVE_INFINITY').enumerable is false
 PASS Object.getOwnPropertyDescriptor(Number, 'NEGATIVE_INFINITY').configurable is false
-PASS Object.getOwnPropertyDescriptor(RegExp, '$_').value is RegExp.$_
-PASS Object.getOwnPropertyDescriptor(RegExp, '$_').hasOwnProperty('get') is false
-PASS Object.getOwnPropertyDescriptor(RegExp, '$_').hasOwnProperty('set') is false
+PASS Object.getOwnPropertyDescriptor(RegExp, '$_').get is RegExp$_Getter
+PASS Object.getOwnPropertyDescriptor(RegExp, '$_').set is RegExp$_Setter
+PASS Object.getOwnPropertyDescriptor(RegExp, '$_').hasOwnProperty('value') is false
+PASS Object.getOwnPropertyDescriptor(RegExp, '$_').hasOwnProperty('writable') is false
 PASS Object.getOwnPropertyDescriptor(RegExp, '$_').enumerable is false
 PASS Object.getOwnPropertyDescriptor(RegExp, '$_').configurable is true
 PASS Object.getOwnPropertyDescriptor(Node, 'DOCUMENT_POSITION_DISCONNECTED').value is Node.DOCUMENT_POSITION_DISCONNECTED

Modified: trunk/LayoutTests/js/dom/regexp-caching-expected.txt (280459 => 280460)


--- trunk/LayoutTests/js/dom/regexp-caching-expected.txt	2021-07-30 00:28:45 UTC (rev 280459)
+++ trunk/LayoutTests/js/dom/regexp-caching-expected.txt	2021-07-30 01:36:31 UTC (rev 280460)
@@ -1,6 +1,10 @@
 This test checks our implementation of the special RegExp member variables.
 
 Properties of RegExp at startup:
+$&: {} (read-only)
+$': {} (read-only)
+$*: {false} (read-write)
+$+: {} (read-only)
 $1: {} (read-only)
 $2: {} (read-only)
 $3: {} (read-only)
@@ -10,14 +14,23 @@
 $7: {} (read-only)
 $8: {} (read-only)
 $9: {} (read-only)
+$_: {} (read-write)
+$`: {} (read-only)
 input: {} (read-write)
 lastMatch: {} (read-only)
 lastParen: {} (read-only)
 leftContext: {} (read-only)
+length: {2} (read-only)
 multiline: {false} (read-write)
+name: {RegExp} (read-only)
+prototype: {/(?:)/} (read-only)
 rightContext: {} (read-only)
 
 Properties of RegExp after /(1)(2)(3)(4)(5)(6)(7)(8)(9)(0)/.exec(<1234567890>):
+$&: {1234567890}
+$': {>}
+$*: {false}
+$+: {0}
 $1: {1}
 $2: {2}
 $3: {3}
@@ -27,11 +40,16 @@
 $7: {7}
 $8: {8}
 $9: {9}
+$_: {<1234567890>}
+$`: {<}
 input: {<1234567890>}
 lastMatch: {1234567890}
 lastParen: {0}
 leftContext: {<}
+length: {2}
 multiline: {false}
+name: {RegExp}
+prototype: {/(?:)/}
 rightContext: {>}
 
 RegExp.$0 does not exist
@@ -41,6 +59,10 @@
 RegExp.input coerces values to strings
 
 Properties of RegExp after /(1)(2)(3)(4)(5)(6)(7)(8)(9)(0)/.exec(XXX):
+$&: {1234567890}
+$': {>}
+$*: {true}
+$+: {0}
 $1: {1}
 $2: {2}
 $3: {3}
@@ -50,15 +72,24 @@
 $7: {7}
 $8: {8}
 $9: {9}
+$_: {0}
+$`: {<}
 input: {0}
 lastMatch: {1234567890}
 lastParen: {0}
 leftContext: {<}
+length: {2}
 multiline: {true}
+name: {RegExp}
+prototype: {/(?:)/}
 rightContext: {>}
 
 ---------- [Cleared RegExp values] ----------
 Properties of RegExp after <1234567890>.search(/(1)(2)(3)(4)(5)(6)(7)(8)(9)(0)/):
+$&: {1234567890}
+$': {>}
+$*: {true}
+$+: {0}
 $1: {1}
 $2: {2}
 $3: {3}
@@ -68,15 +99,24 @@
 $7: {7}
 $8: {8}
 $9: {9}
+$_: {<1234567890>}
+$`: {<}
 input: {<1234567890>}
 lastMatch: {1234567890}
 lastParen: {0}
 leftContext: {<}
+length: {2}
 multiline: {true}
+name: {RegExp}
+prototype: {/(?:)/}
 rightContext: {>}
 
 ---------- [Cleared RegExp values] ----------
 Properties of RegExp after <1234567890>.replace(/(1)(2)(3)(4)(5)(6)(7)(8)(9)(0)/):
+$&: {1234567890}
+$': {>}
+$*: {true}
+$+: {0}
 $1: {1}
 $2: {2}
 $3: {3}
@@ -86,10 +126,15 @@
 $7: {7}
 $8: {8}
 $9: {9}
+$_: {<1234567890>}
+$`: {<}
 input: {<1234567890>}
 lastMatch: {1234567890}
 lastParen: {0}
 leftContext: {<}
+length: {2}
 multiline: {true}
+name: {RegExp}
+prototype: {/(?:)/}
 rightContext: {>}
 

Modified: trunk/LayoutTests/js/dom/regexp-caching.html (280459 => 280460)


--- trunk/LayoutTests/js/dom/regexp-caching.html	2021-07-30 00:28:45 UTC (rev 280459)
+++ trunk/LayoutTests/js/dom/regexp-caching.html	2021-07-30 01:36:31 UTC (rev 280460)
@@ -20,10 +20,7 @@
 
 function printPropertiesWithReadOnly(object)
 {
-    var array = new Array;
-    for (var property in object) {
-        array.push(property);
-    }
+    var array = Object.getOwnPropertyNames(object);
     array.sort();
     for (var i = 0; i < array.length; i++) {
         var property = array[i];
@@ -33,10 +30,7 @@
 
 function printProperties(object)
 {
-    var array = new Array;
-    for (var property in object) {
-        array.push(property);
-    }
+    var array = Object.getOwnPropertyNames(object);
     array.sort();
     for (var i = 0; i < array.length; i++) {
         var property = array[i];

Modified: trunk/LayoutTests/js/resources/getOwnPropertyDescriptor.js (280459 => 280460)


--- trunk/LayoutTests/js/resources/getOwnPropertyDescriptor.js	2021-07-30 00:28:45 UTC (rev 280459)
+++ trunk/LayoutTests/js/resources/getOwnPropertyDescriptor.js	2021-07-30 01:36:31 UTC (rev 280460)
@@ -25,7 +25,9 @@
 descriptorShouldBe("RegExp.prototype", "'exec'", {writable: true, enumerable: false, configurable: true, value:"RegExp.prototype.exec"});
 descriptorShouldBe("document.__proto__.__proto__", "'createElement'", {writable: true, enumerable: true, configurable: true, value:"document.createElement"});
 descriptorShouldBe("Number", "'NEGATIVE_INFINITY'", {writable: false, enumerable: false, configurable: false, value:"Number.NEGATIVE_INFINITY"});
-descriptorShouldBe("RegExp", "'$_'", {writable: true, enumerable: false, configurable: true, value:"RegExp.$_"});
+var RegExp$_Getter = Object.getOwnPropertyDescriptor(RegExp, '$_').get;
+var RegExp$_Setter = Object.getOwnPropertyDescriptor(RegExp, '$_').set;
+descriptorShouldBe("RegExp", "'$_'", {get: "RegExp$_Getter", set: "RegExp$_Setter", enumerable: false, configurable: true,});
 descriptorShouldBe("Node", "'DOCUMENT_POSITION_DISCONNECTED'", {writable: false, enumerable: true, configurable: false, value:"Node.DOCUMENT_POSITION_DISCONNECTED"});
 descriptorShouldBe("Math", "'sin'", {writable: true, enumerable: false, configurable: true, value:"Math.sin"});
 descriptorShouldBe("[1,2,3]", "0", {writable: true, enumerable: true, configurable: true, value:"1"});

Deleted: trunk/LayoutTests/js/script-tests/static-put-in-prototype-chain.js (280459 => 280460)


--- trunk/LayoutTests/js/script-tests/static-put-in-prototype-chain.js	2021-07-30 00:28:45 UTC (rev 280459)
+++ trunk/LayoutTests/js/script-tests/static-put-in-prototype-chain.js	2021-07-30 01:36:31 UTC (rev 280460)
@@ -1,12 +0,0 @@
-description("This test ensures that we will call a custom setter when the setter is in the prototype chain");
-
-// The RegExp Object is a convenient constructor with a custom setter.
-// This will also test the weird behaviour in which the RegExp constructor
-// setters are expected to act on the base object (e.g. the constructor object)
-// rather than the this value.
-var testObject = {__proto__: RegExp }
-
-testObject.input = "testInput"
-
-shouldBe("testObject.input", "'testInput'")
-shouldBe("RegExp.input", "'testInput'")

Deleted: trunk/LayoutTests/js/static-put-in-prototype-chain-expected.txt (280459 => 280460)


--- trunk/LayoutTests/js/static-put-in-prototype-chain-expected.txt	2021-07-30 00:28:45 UTC (rev 280459)
+++ trunk/LayoutTests/js/static-put-in-prototype-chain-expected.txt	2021-07-30 01:36:31 UTC (rev 280460)
@@ -1,11 +0,0 @@
-This test ensures that we will call a custom setter when the setter is in the prototype chain
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS testObject.input is 'testInput'
-PASS RegExp.input is 'testInput'
-PASS successfullyParsed is true
-
-TEST COMPLETE
-

Deleted: trunk/LayoutTests/js/static-put-in-prototype-chain.html (280459 => 280460)


--- trunk/LayoutTests/js/static-put-in-prototype-chain.html	2021-07-30 00:28:45 UTC (rev 280459)
+++ trunk/LayoutTests/js/static-put-in-prototype-chain.html	2021-07-30 01:36:31 UTC (rev 280460)
@@ -1,10 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
-<html>
-<head>
-<script src=""
-</head>
-<body>
-<script src=""
-<script src=""
-</body>
-</html>

Modified: trunk/Source/_javascript_Core/ChangeLog (280459 => 280460)


--- trunk/Source/_javascript_Core/ChangeLog	2021-07-30 00:28:45 UTC (rev 280459)
+++ trunk/Source/_javascript_Core/ChangeLog	2021-07-30 01:36:31 UTC (rev 280460)
@@ -1,3 +1,32 @@
+2021-07-29  Yusuke Suzuki  <ysuz...@apple.com> and Alexey Shvayka  <shvaikal...@gmail.com>
+
+        [JSC] Legacy RegExp fields should be accessors
+        https://bugs.webkit.org/show_bug.cgi?id=220233
+
+        Reviewed by Tadeu Zagallo.
+
+        This patch implements a part of Legacy RegExp features proposal [1], replacing
+        custom values with custom accessors that require |this| value to be RegExp
+        constructor of the same realm.
+
+        Apart from fixing property descriptors, this change brings legacy RegExpConstructor
+        fields in compliance with invariants of internal methods [2] (described in #151348),
+        aligning JSC with V8 and SpiderMonkey.
+
+        It doesn't, however, implement [[LegacyFeaturesEnabled]] and RegExp.prototype.compile
+        changes.
+
+        [1]: https://github.com/tc39/proposal-regexp-legacy-features
+        [2]: https://tc39.es/ecma262/#sec-invariants-of-the-essential-internal-methods
+
+        * bytecode/AccessCase.cpp:
+        (JSC::AccessCase::generateImpl):
+        * runtime/RegExpConstructor.cpp:
+        (JSC::JSC_DEFINE_CUSTOM_GETTER):
+        (JSC::JSC_DEFINE_CUSTOM_SETTER):
+        (JSC::regExpConstructorDollarImpl): Deleted.
+        * tools/JSDollarVM.cpp:
+
 2021-07-29  Myles C. Maxfield  <mmaxfi...@apple.com>
 
         Add WebGPU to webkit.org/status

Modified: trunk/Source/_javascript_Core/bytecode/AccessCase.cpp (280459 => 280460)


--- trunk/Source/_javascript_Core/bytecode/AccessCase.cpp	2021-07-30 00:28:45 UTC (rev 280459)
+++ trunk/Source/_javascript_Core/bytecode/AccessCase.cpp	2021-07-30 01:36:31 UTC (rev 280460)
@@ -1477,14 +1477,9 @@
     case CustomAccessorSetter: {
         GPRReg valueRegsPayloadGPR = valueRegs.payloadGPR();
 
-        if (isValidOffset(m_offset)) {
-            Structure* currStructure;
-            if (!hasAlternateBase())
-                currStructure = structure();
-            else
-                currStructure = alternateBase()->structure(vm);
+        Structure* currStructure = hasAlternateBase() ? alternateBase()->structure(vm) : structure();
+        if (isValidOffset(m_offset))
             currStructure->startWatchingPropertyForReplacements(vm, offset());
-        }
 
         bool doesPropertyStorageLoads = m_type == Load 
             || m_type == GetGetter
@@ -1749,7 +1744,10 @@
             ASSERT(m_type == CustomValueGetter || m_type == CustomAccessorGetter || m_type == CustomValueSetter || m_type == CustomAccessorSetter);
             ASSERT(!doesPropertyStorageLoads); // Or we need an extra register. We rely on propertyOwnerGPR being correct here.
 
-            JSGlobalObject* globalObject = hasAlternateBase() ? alternateBase()->globalObject(vm) : structure()->globalObject();
+            // We do not need to keep globalObject alive since
+            // 1. if it is CustomValue, the owner CodeBlock (even if JSGlobalObject* is one of CodeBlock that is inlined and held by DFG CodeBlock) must keep it alive.
+            // 2. if it is CustomAccessor, structure should hold it.
+            JSGlobalObject* globalObject = currStructure->globalObject();
 
             // Need to make room for the C call so any of our stack spillage isn't overwritten. It's
             // hard to track if someone did spillage or not, so we just assume that we always need

Modified: trunk/Source/_javascript_Core/runtime/RegExpConstructor.cpp (280459 => 280460)


--- trunk/Source/_javascript_Core/runtime/RegExpConstructor.cpp	2021-07-30 00:28:45 UTC (rev 280459)
+++ trunk/Source/_javascript_Core/runtime/RegExpConstructor.cpp	2021-07-30 01:36:31 UTC (rev 280460)
@@ -35,15 +35,7 @@
 static JSC_DECLARE_CUSTOM_GETTER(regExpConstructorLastParen);
 static JSC_DECLARE_CUSTOM_GETTER(regExpConstructorLeftContext);
 static JSC_DECLARE_CUSTOM_GETTER(regExpConstructorRightContext);
-static JSC_DECLARE_CUSTOM_GETTER(regExpConstructorDollar1);
-static JSC_DECLARE_CUSTOM_GETTER(regExpConstructorDollar2);
-static JSC_DECLARE_CUSTOM_GETTER(regExpConstructorDollar3);
-static JSC_DECLARE_CUSTOM_GETTER(regExpConstructorDollar4);
-static JSC_DECLARE_CUSTOM_GETTER(regExpConstructorDollar5);
-static JSC_DECLARE_CUSTOM_GETTER(regExpConstructorDollar6);
-static JSC_DECLARE_CUSTOM_GETTER(regExpConstructorDollar7);
-static JSC_DECLARE_CUSTOM_GETTER(regExpConstructorDollar8);
-static JSC_DECLARE_CUSTOM_GETTER(regExpConstructorDollar9);
+static JSC_DECLARE_CUSTOM_GETTER(regExpConstructorDollar);
 static JSC_DECLARE_CUSTOM_SETTER(setRegExpConstructorInput);
 static JSC_DECLARE_CUSTOM_SETTER(setRegExpConstructorMultiline);
 
@@ -57,27 +49,27 @@
 
 /* Source for RegExpConstructor.lut.h
 @begin regExpConstructorTable
-    input           regExpConstructorInput          None
-    $_              regExpConstructorInput          DontEnum
-    multiline       regExpConstructorMultiline      None
-    $*              regExpConstructorMultiline      DontEnum
-    lastMatch       regExpConstructorLastMatch      DontDelete|ReadOnly
-    $&              regExpConstructorLastMatch      DontDelete|ReadOnly|DontEnum
-    lastParen       regExpConstructorLastParen      DontDelete|ReadOnly
-    $+              regExpConstructorLastParen      DontDelete|ReadOnly|DontEnum
-    leftContext     regExpConstructorLeftContext    DontDelete|ReadOnly
-    $`              regExpConstructorLeftContext    DontDelete|ReadOnly|DontEnum
-    rightContext    regExpConstructorRightContext   DontDelete|ReadOnly
-    $'              regExpConstructorRightContext   DontDelete|ReadOnly|DontEnum
-    $1              regExpConstructorDollar1        DontDelete|ReadOnly
-    $2              regExpConstructorDollar2        DontDelete|ReadOnly
-    $3              regExpConstructorDollar3        DontDelete|ReadOnly
-    $4              regExpConstructorDollar4        DontDelete|ReadOnly
-    $5              regExpConstructorDollar5        DontDelete|ReadOnly
-    $6              regExpConstructorDollar6        DontDelete|ReadOnly
-    $7              regExpConstructorDollar7        DontDelete|ReadOnly
-    $8              regExpConstructorDollar8        DontDelete|ReadOnly
-    $9              regExpConstructorDollar9        DontDelete|ReadOnly
+    input           regExpConstructorInput          CustomAccessor|DontEnum
+    $_              regExpConstructorInput          CustomAccessor|DontEnum
+    multiline       regExpConstructorMultiline      CustomAccessor|DontEnum
+    $*              regExpConstructorMultiline      CustomAccessor|DontEnum
+    lastMatch       regExpConstructorLastMatch      CustomAccessor|ReadOnly|DontEnum
+    $&              regExpConstructorLastMatch      CustomAccessor|ReadOnly|DontEnum
+    lastParen       regExpConstructorLastParen      CustomAccessor|ReadOnly|DontEnum
+    $+              regExpConstructorLastParen      CustomAccessor|ReadOnly|DontEnum
+    leftContext     regExpConstructorLeftContext    CustomAccessor|ReadOnly|DontEnum
+    $`              regExpConstructorLeftContext    CustomAccessor|ReadOnly|DontEnum
+    rightContext    regExpConstructorRightContext   CustomAccessor|ReadOnly|DontEnum
+    $'              regExpConstructorRightContext   CustomAccessor|ReadOnly|DontEnum
+    $1              regExpConstructorDollar         CustomAccessor|ReadOnly|DontEnum
+    $2              regExpConstructorDollar         CustomAccessor|ReadOnly|DontEnum
+    $3              regExpConstructorDollar         CustomAccessor|ReadOnly|DontEnum
+    $4              regExpConstructorDollar         CustomAccessor|ReadOnly|DontEnum
+    $5              regExpConstructorDollar         CustomAccessor|ReadOnly|DontEnum
+    $6              regExpConstructorDollar         CustomAccessor|ReadOnly|DontEnum
+    $7              regExpConstructorDollar         CustomAccessor|ReadOnly|DontEnum
+    $8              regExpConstructorDollar         CustomAccessor|ReadOnly|DontEnum
+    $9              regExpConstructorDollar         CustomAccessor|ReadOnly|DontEnum
 @end
 */
 
@@ -100,84 +92,69 @@
     putDirectNonIndexAccessorWithoutTransition(vm, vm.propertyNames->speciesSymbol, speciesSymbol, PropertyAttribute::Accessor | PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum);
 }
 
-template<int N>
-inline EncodedJSValue regExpConstructorDollarImpl(JSGlobalObject*, EncodedJSValue thisValue, PropertyName)
+JSC_DEFINE_CUSTOM_GETTER(regExpConstructorDollar, (JSGlobalObject* globalObject, EncodedJSValue thisValue, PropertyName propertyName))
 {
-    JSGlobalObject* globalObject = jsCast<RegExpConstructor*>(JSValue::decode(thisValue))->globalObject();
+    VM& vm = globalObject->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+    if (JSValue::decode(thisValue) != globalObject->regExpConstructor())
+        return throwVMTypeError(globalObject, scope, "RegExp.$N getters require RegExp constructor as |this|"_s);
+    unsigned N = propertyName.uid()->at(1) - '0';
+    ASSERT(N >= 1 && N <= 9);
     return JSValue::encode(globalObject->regExpGlobalData().getBackref(globalObject, N));
 }
 
-JSC_DEFINE_CUSTOM_GETTER(regExpConstructorDollar1, (JSGlobalObject* globalObject, EncodedJSValue thisValue, PropertyName propertyName))
+JSC_DEFINE_CUSTOM_GETTER(regExpConstructorInput, (JSGlobalObject* globalObject, EncodedJSValue thisValue, PropertyName))
 {
-    return regExpConstructorDollarImpl<1>(globalObject, thisValue, propertyName);
-}
-JSC_DEFINE_CUSTOM_GETTER(regExpConstructorDollar2, (JSGlobalObject* globalObject, EncodedJSValue thisValue, PropertyName propertyName))
-{
-    return regExpConstructorDollarImpl<2>(globalObject, thisValue, propertyName);
-}
-JSC_DEFINE_CUSTOM_GETTER(regExpConstructorDollar3, (JSGlobalObject* globalObject, EncodedJSValue thisValue, PropertyName propertyName))
-{
-    return regExpConstructorDollarImpl<3>(globalObject, thisValue, propertyName);
-}
-JSC_DEFINE_CUSTOM_GETTER(regExpConstructorDollar4, (JSGlobalObject* globalObject, EncodedJSValue thisValue, PropertyName propertyName))
-{
-    return regExpConstructorDollarImpl<4>(globalObject, thisValue, propertyName);
-}
-JSC_DEFINE_CUSTOM_GETTER(regExpConstructorDollar5, (JSGlobalObject* globalObject, EncodedJSValue thisValue, PropertyName propertyName))
-{
-    return regExpConstructorDollarImpl<5>(globalObject, thisValue, propertyName);
-}
-JSC_DEFINE_CUSTOM_GETTER(regExpConstructorDollar6, (JSGlobalObject* globalObject, EncodedJSValue thisValue, PropertyName propertyName))
-{
-    return regExpConstructorDollarImpl<6>(globalObject, thisValue, propertyName);
-}
-JSC_DEFINE_CUSTOM_GETTER(regExpConstructorDollar7, (JSGlobalObject* globalObject, EncodedJSValue thisValue, PropertyName propertyName))
-{
-    return regExpConstructorDollarImpl<7>(globalObject, thisValue, propertyName);
-}
-JSC_DEFINE_CUSTOM_GETTER(regExpConstructorDollar8, (JSGlobalObject* globalObject, EncodedJSValue thisValue, PropertyName propertyName))
-{
-    return regExpConstructorDollarImpl<8>(globalObject, thisValue, propertyName);
-}
-JSC_DEFINE_CUSTOM_GETTER(regExpConstructorDollar9, (JSGlobalObject* globalObject, EncodedJSValue thisValue, PropertyName propertyName))
-{
-    return regExpConstructorDollarImpl<9>(globalObject, thisValue, propertyName);
-}
-
-JSC_DEFINE_CUSTOM_GETTER(regExpConstructorInput, (JSGlobalObject*, EncodedJSValue thisValue, PropertyName))
-{
-    JSGlobalObject* globalObject = jsCast<RegExpConstructor*>(JSValue::decode(thisValue))->globalObject();
+    VM& vm = globalObject->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+    if (JSValue::decode(thisValue) != globalObject->regExpConstructor())
+        return throwVMTypeError(globalObject, scope, "RegExp.input getter requires RegExp constructor as |this|"_s);
     return JSValue::encode(globalObject->regExpGlobalData().input());
 }
 
-JSC_DEFINE_CUSTOM_GETTER(regExpConstructorMultiline, (JSGlobalObject*, EncodedJSValue thisValue, PropertyName))
+JSC_DEFINE_CUSTOM_GETTER(regExpConstructorMultiline, (JSGlobalObject* globalObject, EncodedJSValue thisValue, PropertyName))
 {
-    JSGlobalObject* globalObject = jsCast<RegExpConstructor*>(JSValue::decode(thisValue))->globalObject();
+    VM& vm = globalObject->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+    if (JSValue::decode(thisValue) != globalObject->regExpConstructor())
+        return throwVMTypeError(globalObject, scope, "RegExp.multiline getter require RegExp constructor as |this|"_s);
     return JSValue::encode(jsBoolean(globalObject->regExpGlobalData().multiline()));
 }
 
-JSC_DEFINE_CUSTOM_GETTER(regExpConstructorLastMatch, (JSGlobalObject*, EncodedJSValue thisValue, PropertyName))
+JSC_DEFINE_CUSTOM_GETTER(regExpConstructorLastMatch, (JSGlobalObject* globalObject, EncodedJSValue thisValue, PropertyName))
 {
-    JSGlobalObject* globalObject = jsCast<RegExpConstructor*>(JSValue::decode(thisValue))->globalObject();
-    return JSValue::encode(globalObject->regExpGlobalData().getBackref(globalObject, 0));
+    VM& vm = globalObject->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+    if (JSValue::decode(thisValue) != globalObject->regExpConstructor())
+        return throwVMTypeError(globalObject, scope, "RegExp.lastMatch getter require RegExp constructor as |this|"_s);
+    RELEASE_AND_RETURN(scope, JSValue::encode(globalObject->regExpGlobalData().getBackref(globalObject, 0)));
 }
 
-JSC_DEFINE_CUSTOM_GETTER(regExpConstructorLastParen, (JSGlobalObject*, EncodedJSValue thisValue, PropertyName))
+JSC_DEFINE_CUSTOM_GETTER(regExpConstructorLastParen, (JSGlobalObject* globalObject, EncodedJSValue thisValue, PropertyName))
 {
-    JSGlobalObject* globalObject = jsCast<RegExpConstructor*>(JSValue::decode(thisValue))->globalObject();
-    return JSValue::encode(globalObject->regExpGlobalData().getLastParen(globalObject));
+    VM& vm = globalObject->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+    if (JSValue::decode(thisValue) != globalObject->regExpConstructor())
+        return throwVMTypeError(globalObject, scope, "RegExp.lastParen getter require RegExp constructor as |this|"_s);
+    RELEASE_AND_RETURN(scope, JSValue::encode(globalObject->regExpGlobalData().getLastParen(globalObject)));
 }
 
-JSC_DEFINE_CUSTOM_GETTER(regExpConstructorLeftContext, (JSGlobalObject*, EncodedJSValue thisValue, PropertyName))
+JSC_DEFINE_CUSTOM_GETTER(regExpConstructorLeftContext, (JSGlobalObject* globalObject, EncodedJSValue thisValue, PropertyName))
 {
-    JSGlobalObject* globalObject = jsCast<RegExpConstructor*>(JSValue::decode(thisValue))->globalObject();
-    return JSValue::encode(globalObject->regExpGlobalData().getLeftContext(globalObject));
+    VM& vm = globalObject->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+    if (JSValue::decode(thisValue) != globalObject->regExpConstructor())
+        return throwVMTypeError(globalObject, scope, "RegExp.leftContext getter require RegExp constructor as |this|"_s);
+    RELEASE_AND_RETURN(scope, JSValue::encode(globalObject->regExpGlobalData().getLeftContext(globalObject)));
 }
 
-JSC_DEFINE_CUSTOM_GETTER(regExpConstructorRightContext, (JSGlobalObject*, EncodedJSValue thisValue, PropertyName))
+JSC_DEFINE_CUSTOM_GETTER(regExpConstructorRightContext, (JSGlobalObject* globalObject, EncodedJSValue thisValue, PropertyName))
 {
-    JSGlobalObject* globalObject = jsCast<RegExpConstructor*>(JSValue::decode(thisValue))->globalObject();
-    return JSValue::encode(globalObject->regExpGlobalData().getRightContext(globalObject));
+    VM& vm = globalObject->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+    if (JSValue::decode(thisValue) != globalObject->regExpConstructor())
+        return throwVMTypeError(globalObject, scope, "RegExp.rightContext getter require RegExp constructor as |this|"_s);
+    RELEASE_AND_RETURN(scope, JSValue::encode(globalObject->regExpGlobalData().getRightContext(globalObject)));
 }
 
 JSC_DEFINE_CUSTOM_SETTER(setRegExpConstructorInput, (JSGlobalObject* globalObject, EncodedJSValue thisValue, EncodedJSValue value, PropertyName))
@@ -184,15 +161,15 @@
 {
     VM& vm = globalObject->vm();
     auto scope = DECLARE_THROW_SCOPE(vm);
-    if (auto constructor = jsDynamicCast<RegExpConstructor*>(vm, JSValue::decode(thisValue))) {
-        auto* string = JSValue::decode(value).toString(globalObject);
-        RETURN_IF_EXCEPTION(scope, { });
-        scope.release();
-        JSGlobalObject* globalObject = constructor->globalObject();
-        globalObject->regExpGlobalData().setInput(globalObject, string);
-        return true;
+    if (JSValue::decode(thisValue) != globalObject->regExpConstructor()) {
+        throwTypeError(globalObject, scope, "RegExp.input setters require RegExp constructor as |this|"_s);
+        return false;
     }
-    return false;
+    auto* string = JSValue::decode(value).toString(globalObject);
+    RETURN_IF_EXCEPTION(scope, { });
+    scope.release();
+    globalObject->regExpGlobalData().setInput(globalObject, string);
+    return true;
 }
 
 JSC_DEFINE_CUSTOM_SETTER(setRegExpConstructorMultiline, (JSGlobalObject* globalObject, EncodedJSValue thisValue, EncodedJSValue value, PropertyName))
@@ -199,15 +176,15 @@
 {
     VM& vm = globalObject->vm();
     auto scope = DECLARE_THROW_SCOPE(vm);
-    if (auto constructor = jsDynamicCast<RegExpConstructor*>(vm, JSValue::decode(thisValue))) {
-        bool multiline = JSValue::decode(value).toBoolean(globalObject);
-        RETURN_IF_EXCEPTION(scope, { });
-        scope.release();
-        JSGlobalObject* globalObject = constructor->globalObject();
-        globalObject->regExpGlobalData().setMultiline(multiline);
-        return true;
+    if (JSValue::decode(thisValue) != globalObject->regExpConstructor()) {
+        throwTypeError(globalObject, scope, "RegExp.multiline setters require RegExp constructor as |this|"_s);
+        return false;
     }
-    return false;
+    bool multiline = JSValue::decode(value).toBoolean(globalObject);
+    RETURN_IF_EXCEPTION(scope, { });
+    scope.release();
+    globalObject->regExpGlobalData().setMultiline(multiline);
+    return true;
 }
 
 inline Structure* getRegExpStructure(JSGlobalObject* globalObject, JSValue newTarget)

Modified: trunk/Source/_javascript_Core/tools/JSDollarVM.cpp (280459 => 280460)


--- trunk/Source/_javascript_Core/tools/JSDollarVM.cpp	2021-07-30 00:28:45 UTC (rev 280459)
+++ trunk/Source/_javascript_Core/tools/JSDollarVM.cpp	2021-07-30 01:36:31 UTC (rev 280460)
@@ -1600,11 +1600,13 @@
 
 static JSC_DECLARE_CUSTOM_GETTER(customGetAccessor);
 static JSC_DECLARE_CUSTOM_GETTER(customGetValue);
+static JSC_DECLARE_CUSTOM_GETTER(customGetValue2);
 static JSC_DECLARE_CUSTOM_GETTER(customGetAccessorGlobalObject);
 static JSC_DECLARE_CUSTOM_GETTER(customGetValueGlobalObject);
 static JSC_DECLARE_CUSTOM_SETTER(customSetAccessor);
 static JSC_DECLARE_CUSTOM_SETTER(customSetAccessorGlobalObject);
 static JSC_DECLARE_CUSTOM_SETTER(customSetValue);
+static JSC_DECLARE_CUSTOM_SETTER(customSetValue2);
 static JSC_DECLARE_CUSTOM_SETTER(customSetValueGlobalObject);
 static JSC_DECLARE_CUSTOM_SETTER(customFunctionSetter);
 
@@ -1621,6 +1623,18 @@
     return slotValue;
 }
 
+JSC_DEFINE_CUSTOM_GETTER(customGetValue2, (JSGlobalObject* globalObject, EncodedJSValue slotValue, PropertyName))
+{
+    DollarVMAssertScope assertScope;
+    VM& vm = globalObject->vm();
+
+    RELEASE_ASSERT(JSValue::decode(slotValue).inherits<JSTestCustomGetterSetter>(globalObject->vm()));
+
+    auto* target = jsCast<JSTestCustomGetterSetter*>(JSValue::decode(slotValue));
+    JSValue value = target->getDirect(vm, Identifier::fromString(vm, "value2"));
+    return JSValue::encode(value ? value : jsUndefined());
+}
+
 JSC_DEFINE_CUSTOM_GETTER(customGetAccessorGlobalObject, (JSGlobalObject* globalObject, EncodedJSValue, PropertyName))
 {
     return JSValue::encode(globalObject);
@@ -1699,6 +1713,18 @@
     return true;
 }
 
+JSC_DEFINE_CUSTOM_SETTER(customSetValue2, (JSGlobalObject* globalObject, EncodedJSValue slotValue, EncodedJSValue encodedValue, PropertyName))
+{
+    DollarVMAssertScope assertScope;
+    VM& vm = globalObject->vm();
+
+    RELEASE_ASSERT(JSValue::decode(slotValue).inherits<JSTestCustomGetterSetter>(vm));
+    auto* target = jsCast<JSTestCustomGetterSetter*>(JSValue::decode(slotValue));
+    PutPropertySlot slot(target);
+    target->putDirect(vm, Identifier::fromString(vm, "value2"), JSValue::decode(encodedValue));
+    return true;
+}
+
 JSC_DEFINE_CUSTOM_SETTER(customFunctionSetter, (JSGlobalObject* globalObject, EncodedJSValue, EncodedJSValue encodedValue, PropertyName))
 {
     DollarVMAssertScope assertScope;
@@ -1723,6 +1749,8 @@
 
     putDirectCustomAccessor(vm, Identifier::fromString(vm, "customValue"),
         CustomGetterSetter::create(vm, customGetValue, customSetValue), 0);
+    putDirectCustomAccessor(vm, Identifier::fromString(vm, "customValue2"),
+        CustomGetterSetter::create(vm, customGetValue2, customSetValue2), static_cast<unsigned>(PropertyAttribute::CustomValue));
     putDirectCustomAccessor(vm, Identifier::fromString(vm, "customAccessor"),
         CustomGetterSetter::create(vm, customGetAccessor, customSetAccessor), static_cast<unsigned>(PropertyAttribute::CustomAccessor));
     putDirectCustomAccessor(vm, Identifier::fromString(vm, "customValueGlobalObject"),
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to