Changeset 280460 in webkit


Ignore:
Timestamp:
Jul 29, 2021 6:36:31 PM (12 months ago)
Author:
Alexey Shvayka
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/JavaScriptCore:

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:
Location:
trunk
Files:
3 added
3 deleted
24 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChakraCore/test/Lib/forin_lib_v3.baseline-jsc

    r205387 r280460  
    7979
    8080for..in RegExp
    81   input =
    82   multiline = false
    83   lastMatch =
    84   lastParen =
    85   leftContext =
    86   rightContext =
    87   $1 =
    88   $2 =
    89   $3 =
    90   $4 =
    91   $5 =
    92   $6 =
    93   $7 =
    94   $8 =
    95   $9 =
    9681  blah2 = Function
    9782for..in RegExp (with blah)
    98   input =
    99   multiline = false
    100   lastMatch =
    101   lastParen =
    102   leftContext =
    103   rightContext =
    104   $1 =
    105   $2 =
    106   $3 =
    107   $4 =
    108   $5 =
    109   $6 =
    110   $7 =
    111   $8 =
    112   $9 =
    11383  blah = b
    11484  blah2 = Function
  • trunk/JSTests/ChangeLog

    r280452 r280460  
     12021-07-29  Yusuke Suzuki  <ysuzuki@apple.com> and Alexey Shvayka  <shvaikalesh@gmail.com>
     2
     3        [JSC] Legacy RegExp fields should be accessors
     4        https://bugs.webkit.org/show_bug.cgi?id=220233
     5
     6        Reviewed by Tadeu Zagallo.
     7
     8        * ChakraCore/test/Lib/forin_lib_v3.baseline-jsc:
     9        * microbenchmarks/assign-custom-setter-polymorphic.js:
     10        * microbenchmarks/assign-custom-setter.js:
     11        * microbenchmarks/custom-setter-getter-as-put-get-by-id.js:
     12        * microbenchmarks/custom-value-2.js:
     13        * microbenchmarks/custom-value.js:
     14        * microbenchmarks/get-custom-getter.js:
     15        * stress/custom-value-delete-property-1.js:
     16        * stress/custom-value-delete-property-2.js:
     17        * stress/custom-value-delete-property-3.js:
     18        * stress/object-assign-fast-path.js:
     19        * stress/reflect-set.js:
     20        * stress/regexp-constructor-dollar-getters-are-unique.js: Added.
     21        * stress/regexp-setter-realm.js: Added.
     22        * stress/static-put-in-prototype-chain.js: Added.
     23        * test262/config.yaml:
     24        * test262/expectations.yaml:
     25
    1262021-07-28  Yusuke Suzuki  <ysuzuki@apple.com>
    227
  • trunk/JSTests/microbenchmarks/assign-custom-setter-polymorphic.js

    r251463 r280460  
    11//@ skip if $model == "Apple Watch Series 3" # added by mark-jsc-stress-test.py
    22
    3 o = RegExp;
     3o = $vm.createCustomTestGetterSetter();
    44j = 0;
    55l = 2;
     
    77function test(o, z) {
    88    var k = arguments[(((j << 1 | l) >> 1) ^ 1) & (z *= 1)];
    9     k.input = 0;
     9    k.customValue2 = 0;
    1010    for (var i = 0; i < 25000; i++) {
    11         k.input = "foo";
     11        k.customValue2 = "foo";
    1212    }
    1313
    14     return k.input;
     14    return k.customValue2;
    1515}
    16 var result = test({__proto__: {bar:"wibble", input:"foo"}});
    17 var result = test({input:"foo"});
     16var result = test({__proto__: {bar:"wibble", customValue2:"foo"}});
     17var result = test({customValue2:"foo"});
    1818var result = test(o)
    1919for (var k = 0; k < 6; k++) {
  • trunk/JSTests/microbenchmarks/assign-custom-setter.js

    r251463 r280460  
    11//@ skip if $model == "Apple Watch Series 3" # added by mark-jsc-stress-test.py
    2 // RegExp.input is a handy setter
    32
    4 var o = RegExp;
     3var o = $vm.createCustomTestGetterSetter();
    54function test(o) {
    65    var k = 0;
    7     o.input = "bar";
     6    o.customValue2 = "bar";
    87    for (var i = 0; i < 30000; i++)
    9         o.input = "foo";
     8        o.customValue2 = "foo";
    109
    11     return o.input;
     10    return o.customValue2;
    1211}
    1312
  • trunk/JSTests/microbenchmarks/custom-setter-getter-as-put-get-by-id.js

    r251463 r280460  
    66noInline(assert);
    77
    8 // RegExp.input is a handy custom getter/setter.
    9 var o1 = RegExp;
     8var o1 = $vm.createCustomTestGetterSetter();
    109function test(o) {
    11     o.input = "bar";
    12     return o.input;
     10    o.customValue2 = "bar";
     11    return o.customValue2;
    1312}
    1413noInline(test);
    1514
    1615var o2 = {
    17     input: "hello"
     16    customValue2: "hello"
    1817}
    1918
    2019var o3 = {
    2120    x: 20,
    22     input: "hello"
     21    customValue2: "hello"
    2322}
    2423
  • trunk/JSTests/microbenchmarks/custom-value-2.js

    r251463 r280460  
    55}
    66
     7const Value = $vm.createCustomTestGetterSetter();
    78function test1() {
    8     function getMultiline(o) {
    9         return o.multiline;
     9    function getCustomValue2(o) {
     10        return o.customValue2;
    1011    }
    11     noInline(getMultiline);
     12    noInline(getCustomValue2);
    1213
    13     RegExp.foo = 42;
     14    Value.foo = 42;
    1415
    1516    const o = {};
    16     o.__proto__ = RegExp;
    17     RegExp.multiline = false;
     17    o.__proto__ = Value;
     18    Value.customValue2 = false;
    1819
    1920    for (let i = 0; i < 5000000; ++i) {
    20         assert(getMultiline(o) === false);
     21        assert(getCustomValue2(o) === false);
    2122    }
    22     delete RegExp.foo;
     23    delete Value.foo;
    2324    for (let i = 0; i < 5000000; ++i) {
    24         assert(getMultiline(o) === false);
     25        assert(getCustomValue2(o) === false);
    2526    }
    2627}
  • trunk/JSTests/microbenchmarks/custom-value.js

    r251463 r280460  
    55}
    66
     7const Value = $vm.createCustomTestGetterSetter();
    78function test1() {
    8     function getMultiline(o) {
    9         return o.multiline;
     9    function getCustomValue2(o) {
     10        return o.customValue2;
    1011    }
    11     noInline(getMultiline);
     12    noInline(getCustomValue2);
    1213
    1314    const o = {};
    14     o.__proto__ = RegExp;
    15     RegExp.multiline = false;
     15    o.__proto__ = Value;
     16    Value.customValue2 = false;
    1617
    1718    for (let i = 0; i < 5000000; ++i) {
    18         assert(getMultiline(o) === false);
     19        assert(getCustomValue2(o) === false);
    1920    }
    2021}
  • trunk/JSTests/microbenchmarks/get-custom-getter.js

    r251463 r280460  
    11//@ skip if $model == "Apple Watch Series 3" # added by mark-jsc-stress-test.py
    2 // RegExp.input is a handy getter
    32
    4 var o = RegExp;
    5 o.input = "foo";
     3var o = $vm.createCustomTestGetterSetter();
     4o.customValue2 = "foo";
    65
    76function test(o) {
    87    var result = null;
    98    for (var i = 0; i < 30000; i++)
    10         result = o.input;
     9        result = o.customValue2;
    1110
    1211    return result;
  • trunk/JSTests/stress/custom-value-delete-property-1.js

    r250540 r280460  
    44}
    55
     6const Value = $vm.createCustomTestGetterSetter();
    67function test1() {
    7     function getMultiline(o) {
    8         return o.multiline;
     8    function getCustomValue2(o) {
     9        return o.customValue2;
    910    }
    10     noInline(getMultiline);
     11    noInline(getCustomValue2);
    1112
    1213    const o = {};
    13     o.__proto__ = RegExp;
    14     RegExp.multiline = false;
     14    o.__proto__ = Value;
     15    Value.customValue2 = false;
    1516
    1617    for (let i = 0; i < 500; ++i) {
    17         assert(getMultiline(o) === false);
     18        assert(getCustomValue2(o) === false);
    1819    }
    19     delete RegExp.input;
    20     delete RegExp.multiline;
    21     assert(getMultiline(o) === undefined);
     20    delete Value.customValue2;
     21    assert(getCustomValue2(o) === undefined);
    2222}
    2323test1();
  • trunk/JSTests/stress/custom-value-delete-property-2.js

    r250540 r280460  
     1const Value = $vm.createCustomTestGetterSetter();
    12function test2() {
    23    function foo() {
    34        const o = {};
    45        for (let i = 0; i < 8; i++) {
    5             let x = o.multiline;
    6             o.__proto__ = RegExp;
     6            let x = o.customValue2;
     7            o.__proto__ = Value;
    78        }
    8         delete RegExp.input;
     9        delete Value.customValue;
    910    }
    1011
  • trunk/JSTests/stress/custom-value-delete-property-3.js

    r250540 r280460  
    11function test6() {
     2    var custom = $vm.createCustomTestGetterSetter();
    23    function foo() {
    34        const o = {};
    45        for (let i = 0; i < 8; i++) {
    5             o.lastMatch;
    6             o.__proto__ = RegExp;
     6            o.customValue2;
     7            o.__proto__ = custom;
    78        }
    8         delete RegExp.input;
     9        delete custom.customValue2;
    910    }
    1011
  • trunk/JSTests/stress/object-assign-fast-path.js

    r280289 r280460  
    3333{
    3434    let result = Object.assign({}, RegExp);
    35     shouldBe(JSON.stringify(Object.getOwnPropertyNames(result).sort()), `["$1","$2","$3","$4","$5","$6","$7","$8","$9","input","lastMatch","lastParen","leftContext","multiline","rightContext"]`);
     35    shouldBe(JSON.stringify(Object.getOwnPropertyNames(result).sort()), `[]`);
     36}
     37{
     38    let result = Object.assign({}, $vm.createCustomTestGetterSetter());
     39    shouldBe(JSON.stringify(Object.getOwnPropertyNames(result).sort()), `["customAccessor","customAccessorGlobalObject","customAccessorReadOnly","customFunction","customValue","customValue2","customValueGlobalObject","customValueNoSetter"]`);
    3640}
    3741{
  • trunk/JSTests/stress/reflect-set.js

    r280289 r280460  
    11181118}());
    11191119
    1120 (function customValue() {
    1121     // In this case, RegExp.multiline behaves like a setter because it coerce boolean type.
    1122     // Anyway, it's OK, because RegExp.multiline is not specified in the spec.
    1123 
     1120(function regExpMultiline() {
    11241121    function test1() {
    11251122        shouldBe(Reflect.set(RegExp, 'multiline', 'Cappuccino'), true);
     
    11291126
    11301127        var receiver = {};
    1131         shouldBe(Reflect.set(RegExp, 'multiline', 'Cappuccino', receiver), true);
    1132         shouldBe(Reflect.get(receiver, 'multiline'), 'Cappuccino');
     1128        shouldThrow(() => Reflect.set(RegExp, 'multiline', 'Cappuccino', receiver), `TypeError: RegExp.multiline setters require RegExp constructor as |this|`);
     1129        shouldBe(Reflect.get(receiver, 'multiline'), undefined);
    11331130        shouldBe(Reflect.get(RegExp, 'multiline'), false);
    11341131    }
     
    11421139
    11431140        var receiver = {};
    1144         shouldBe(Reflect.set(RegExp, 'multiline', 'Cappuccino', receiver), true);
    1145         shouldBe(Reflect.get(receiver, 'multiline'), 'Cappuccino');
     1141        shouldThrow(() => Reflect.set(RegExp, 'multiline', 'Cappuccino', receiver), `TypeError: RegExp.multiline setters require RegExp constructor as |this|`);
     1142        shouldBe(Reflect.get(receiver, 'multiline'), undefined);
    11461143        shouldBe(Reflect.get(RegExp, 'multiline'), false);
    11471144    }
     
    11521149            writable: false
    11531150        }), true);
    1154         shouldBe(Reflect.get(RegExp, 'multiline'), false);
     1151        shouldBe(Reflect.get(RegExp, 'multiline'), undefined);
    11551152        shouldBe(Reflect.set(RegExp, 'multiline', 'Cappuccino'), false);
    1156         shouldBe(Reflect.get(RegExp, 'multiline'), false);
     1153        shouldBe(Reflect.get(RegExp, 'multiline'), undefined);
    11571154        shouldBe(Reflect.set(RegExp, 'multiline', 0), false);
    1158         shouldBe(Reflect.get(RegExp, 'multiline'), false);
     1155        shouldBe(Reflect.get(RegExp, 'multiline'), undefined);
    11591156
    11601157        var receiver = {};
     
    12001197        regexp.lastIndex = 'NG';
    12011198    }, `TypeError: Attempted to assign to readonly property.`);
     1199}());
     1200
     1201(function customValue() {
     1202    const Value = $vm.createCustomTestGetterSetter();
     1203    function test1() {
     1204        shouldBe(Reflect.set(Value, 'customValue2', 'Cappuccino'), true);
     1205        shouldBe(Reflect.get(Value, 'customValue2'), 'Cappuccino');
     1206        shouldBe(Reflect.set(Value, 'customValue2', 0), true);
     1207        shouldBe(Reflect.get(Value, 'customValue2'), 0);
     1208
     1209        var receiver = {};
     1210        shouldBe(Reflect.set(Value, 'customValue2', 'Cappuccino', receiver), true);
     1211        shouldBe(Reflect.get(receiver, 'customValue2'), 'Cappuccino');
     1212        shouldBe(Reflect.get(Value, 'customValue2'), 0);
     1213    }
     1214
     1215    function test2() {
     1216        'use strict';
     1217        shouldBe(Reflect.set(Value, 'customValue2', 'Cappuccino'), true);
     1218        shouldBe(Reflect.get(Value, 'customValue2'), 'Cappuccino');
     1219        shouldBe(Reflect.set(Value, 'customValue2', 0), true);
     1220        shouldBe(Reflect.get(Value, 'customValue2'), 0);
     1221
     1222        var receiver = {};
     1223        shouldBe(Reflect.set(Value, 'customValue2', 'Cappuccino', receiver), true);
     1224        shouldBe(Reflect.get(receiver, 'customValue2'), 'Cappuccino');
     1225        shouldBe(Reflect.get(Value, 'customValue2'), 0);
     1226    }
     1227
     1228    function test3() {
     1229        'use strict';
     1230        shouldBe(Reflect.defineProperty(Value, 'customValue2', {
     1231            writable: false,
     1232            value: undefined,
     1233        }), true);
     1234        shouldBe(Reflect.get(Value, 'customValue2'), undefined);
     1235        shouldBe(Reflect.set(Value, 'customValue2', 'Cappuccino'), false);
     1236        shouldBe(Reflect.get(Value, 'customValue2'), undefined);
     1237        shouldBe(Reflect.set(Value, 'customValue2', 0), false);
     1238        shouldBe(Reflect.get(Value, 'customValue2'), undefined);
     1239
     1240        var receiver = {};
     1241        shouldBe(Reflect.set(Value, 'customValue2', 'Cappuccino', receiver), false);
     1242        shouldBe(Reflect.get(receiver, 'customValue2'), undefined);
     1243    }
     1244
     1245    test1();
     1246    test2();
     1247    test3();
    12021248}());
    12031249
  • trunk/JSTests/test262/config.yaml

    r280289 r280460  
    2323    # https://bugs.webkit.org/show_bug.cgi?id=174931
    2424    - regexp-lookbehind
    25     - legacy-regexp
    2625    - cleanupSome
    2726    - Intl.Locale-info
  • trunk/JSTests/test262/expectations.yaml

    r280289 r280460  
    66  default: "SyntaxError: Unexpected token '}'. Expected a parameter pattern or a ')' in parameter list."
    77  strict mode: "SyntaxError: Unexpected token '}'. Expected a parameter pattern or a ')' in parameter list."
     8test/annexB/built-ins/RegExp/prototype/compile/this-cross-realm-instance.js:
     9  default: 'Test262Error: `RegExp.prototype.compile.call(otherRealm_regexp)` throws TypeError Expected a TypeError to be thrown but no exception was thrown at all'
     10  strict mode: 'Test262Error: `RegExp.prototype.compile.call(otherRealm_regexp)` throws TypeError Expected a TypeError to be thrown but no exception was thrown at all'
     11test/annexB/built-ins/RegExp/prototype/compile/this-subclass-instance.js:
     12  default: 'Test262Error: `subclass_regexp.compile()` throws TypeError Expected a TypeError to be thrown but no exception was thrown at all'
     13  strict mode: 'Test262Error: `subclass_regexp.compile()` throws TypeError Expected a TypeError to be thrown but no exception was thrown at all'
    814test/annexB/language/eval-code/direct/func-block-decl-eval-func-skip-early-err-block.js:
    915  default: 'Test262Error: An initialized binding is not created prior to evaluation Expected a ReferenceError to be thrown but no exception was thrown at all'
     
    670676  default: 'Test262Error: Conforms to NativeFunction Syntax: "async function f( /* b */ ) /* c */ { /* d */ }" (async f /* a */ ( /* b */ ) /* c */ { /* d */ })'
    671677  strict mode: 'Test262Error: Conforms to NativeFunction Syntax: "async function f( /* b */ ) /* c */ { /* d */ }" (async f /* a */ ( /* b */ ) /* c */ { /* d */ })'
     678test/built-ins/Function/prototype/toString/built-in-function-object.js:
     679  default: 'Test262Error: Conforms to NativeFunction Syntax: "function $*() {\n    [native code]\n}" (%RegExp%.$*)'
     680  strict mode: 'Test262Error: Conforms to NativeFunction Syntax: "function $*() {\n    [native code]\n}" (%RegExp%.$*)'
    672681test/built-ins/Function/prototype/toString/function-declaration-non-simple-parameter-list.js:
    673682  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 */ })'
     
    763772  default: 'Test262Error: Expected [a, name] and [name, a] to have the same contents. '
    764773  strict mode: 'Test262Error: Expected [a, name] and [name, a] to have the same contents. '
    765 test/built-ins/Object/internals/DefineOwnProperty/consistent-value-regexp-dollar1.js:
    766   default: 'Test262Error: Expected SameValue(«», «x») to be true'
    767   strict mode: 'Test262Error: Expected SameValue(«», «x») to be true'
    768774test/built-ins/Object/keys/order-after-define-property.js:
    769775  default: 'Test262Error: Expected [a, length] and [length, a] to have the same contents. '
  • trunk/LayoutTests/ChangeLog

    r280459 r280460  
     12021-07-29  Yusuke Suzuki  <ysuzuki@apple.com> and Alexey Shvayka  <shvaikalesh@gmail.com>
     2
     3        [JSC] Legacy RegExp fields should be accessors
     4        https://bugs.webkit.org/show_bug.cgi?id=220233
     5
     6        Reviewed by Tadeu Zagallo.
     7
     8        * js/dom/getOwnPropertyDescriptor-expected.txt:
     9        * js/dom/regexp-caching-expected.txt:
     10        * js/dom/regexp-caching.html:
     11        * js/resources/getOwnPropertyDescriptor.js:
     12        * js/script-tests/static-put-in-prototype-chain.js:
     13        * js/static-put-in-prototype-chain-expected.txt:
     14        * js/static-put-in-prototype-chain.html:
     15
    1162021-07-29  Devin Rousso  <drousso@apple.com>
    217
  • trunk/LayoutTests/js/dom/getOwnPropertyDescriptor-expected.txt

    r268640 r280460  
    4040PASS Object.getOwnPropertyDescriptor(Number, 'NEGATIVE_INFINITY').enumerable is false
    4141PASS Object.getOwnPropertyDescriptor(Number, 'NEGATIVE_INFINITY').configurable is false
    42 PASS Object.getOwnPropertyDescriptor(RegExp, '$_').value is RegExp.$_
    43 PASS Object.getOwnPropertyDescriptor(RegExp, '$_').hasOwnProperty('get') is false
    44 PASS Object.getOwnPropertyDescriptor(RegExp, '$_').hasOwnProperty('set') is false
     42PASS Object.getOwnPropertyDescriptor(RegExp, '$_').get is RegExp$_Getter
     43PASS Object.getOwnPropertyDescriptor(RegExp, '$_').set is RegExp$_Setter
     44PASS Object.getOwnPropertyDescriptor(RegExp, '$_').hasOwnProperty('value') is false
     45PASS Object.getOwnPropertyDescriptor(RegExp, '$_').hasOwnProperty('writable') is false
    4546PASS Object.getOwnPropertyDescriptor(RegExp, '$_').enumerable is false
    4647PASS Object.getOwnPropertyDescriptor(RegExp, '$_').configurable is true
  • trunk/LayoutTests/js/dom/regexp-caching-expected.txt

    r156066 r280460  
    22
    33Properties of RegExp at startup:
     4$&: {} (read-only)
     5$': {} (read-only)
     6$*: {false} (read-write)
     7$+: {} (read-only)
    48$1: {} (read-only)
    59$2: {} (read-only)
     
    1115$8: {} (read-only)
    1216$9: {} (read-only)
     17$_: {} (read-write)
     18$`: {} (read-only)
    1319input: {} (read-write)
    1420lastMatch: {} (read-only)
    1521lastParen: {} (read-only)
    1622leftContext: {} (read-only)
     23length: {2} (read-only)
    1724multiline: {false} (read-write)
     25name: {RegExp} (read-only)
     26prototype: {/(?:)/} (read-only)
    1827rightContext: {} (read-only)
    1928
    2029Properties of RegExp after /(1)(2)(3)(4)(5)(6)(7)(8)(9)(0)/.exec(<1234567890>):
     30$&: {1234567890}
     31$': {>}
     32$*: {false}
     33$+: {0}
    2134$1: {1}
    2235$2: {2}
     
    2841$8: {8}
    2942$9: {9}
     43$_: {<1234567890>}
     44$`: {<}
    3045input: {<1234567890>}
    3146lastMatch: {1234567890}
    3247lastParen: {0}
    3348leftContext: {<}
     49length: {2}
    3450multiline: {false}
     51name: {RegExp}
     52prototype: {/(?:)/}
    3553rightContext: {>}
    3654
     
    4260
    4361Properties of RegExp after /(1)(2)(3)(4)(5)(6)(7)(8)(9)(0)/.exec(XXX):
     62$&: {1234567890}
     63$': {>}
     64$*: {true}
     65$+: {0}
    4466$1: {1}
    4567$2: {2}
     
    5173$8: {8}
    5274$9: {9}
     75$_: {0}
     76$`: {<}
    5377input: {0}
    5478lastMatch: {1234567890}
    5579lastParen: {0}
    5680leftContext: {<}
     81length: {2}
    5782multiline: {true}
     83name: {RegExp}
     84prototype: {/(?:)/}
    5885rightContext: {>}
    5986
    6087---------- [Cleared RegExp values] ----------
    6188Properties of RegExp after <1234567890>.search(/(1)(2)(3)(4)(5)(6)(7)(8)(9)(0)/):
     89$&: {1234567890}
     90$': {>}
     91$*: {true}
     92$+: {0}
    6293$1: {1}
    6394$2: {2}
     
    69100$8: {8}
    70101$9: {9}
     102$_: {<1234567890>}
     103$`: {<}
    71104input: {<1234567890>}
    72105lastMatch: {1234567890}
    73106lastParen: {0}
    74107leftContext: {<}
     108length: {2}
    75109multiline: {true}
     110name: {RegExp}
     111prototype: {/(?:)/}
    76112rightContext: {>}
    77113
    78114---------- [Cleared RegExp values] ----------
    79115Properties of RegExp after <1234567890>.replace(/(1)(2)(3)(4)(5)(6)(7)(8)(9)(0)/):
     116$&: {1234567890}
     117$': {>}
     118$*: {true}
     119$+: {0}
    80120$1: {1}
    81121$2: {2}
     
    87127$8: {8}
    88128$9: {9}
     129$_: {<1234567890>}
     130$`: {<}
    89131input: {<1234567890>}
    90132lastMatch: {1234567890}
    91133lastParen: {0}
    92134leftContext: {<}
     135length: {2}
    93136multiline: {true}
     137name: {RegExp}
     138prototype: {/(?:)/}
    94139rightContext: {>}
    95140
  • trunk/LayoutTests/js/dom/regexp-caching.html

    r156066 r280460  
    2121function printPropertiesWithReadOnly(object)
    2222{
    23     var array = new Array;
    24     for (var property in object) {
    25         array.push(property);
    26     }
     23    var array = Object.getOwnPropertyNames(object);
    2724    array.sort();
    2825    for (var i = 0; i < array.length; i++) {
     
    3431function printProperties(object)
    3532{
    36     var array = new Array;
    37     for (var property in object) {
    38         array.push(property);
    39     }
     33    var array = Object.getOwnPropertyNames(object);
    4034    array.sort();
    4135    for (var i = 0; i < array.length; i++) {
  • trunk/LayoutTests/js/resources/getOwnPropertyDescriptor.js

    r268640 r280460  
    2626descriptorShouldBe("document.__proto__.__proto__", "'createElement'", {writable: true, enumerable: true, configurable: true, value:"document.createElement"});
    2727descriptorShouldBe("Number", "'NEGATIVE_INFINITY'", {writable: false, enumerable: false, configurable: false, value:"Number.NEGATIVE_INFINITY"});
    28 descriptorShouldBe("RegExp", "'$_'", {writable: true, enumerable: false, configurable: true, value:"RegExp.$_"});
     28var RegExp$_Getter = Object.getOwnPropertyDescriptor(RegExp, '$_').get;
     29var RegExp$_Setter = Object.getOwnPropertyDescriptor(RegExp, '$_').set;
     30descriptorShouldBe("RegExp", "'$_'", {get: "RegExp$_Getter", set: "RegExp$_Setter", enumerable: false, configurable: true,});
    2931descriptorShouldBe("Node", "'DOCUMENT_POSITION_DISCONNECTED'", {writable: false, enumerable: true, configurable: false, value:"Node.DOCUMENT_POSITION_DISCONNECTED"});
    3032descriptorShouldBe("Math", "'sin'", {writable: true, enumerable: false, configurable: true, value:"Math.sin"});
  • trunk/Source/JavaScriptCore/ChangeLog

    r280456 r280460  
     12021-07-29  Yusuke Suzuki  <ysuzuki@apple.com> and Alexey Shvayka  <shvaikalesh@gmail.com>
     2
     3        [JSC] Legacy RegExp fields should be accessors
     4        https://bugs.webkit.org/show_bug.cgi?id=220233
     5
     6        Reviewed by Tadeu Zagallo.
     7
     8        This patch implements a part of Legacy RegExp features proposal [1], replacing
     9        custom values with custom accessors that require |this| value to be RegExp
     10        constructor of the same realm.
     11
     12        Apart from fixing property descriptors, this change brings legacy RegExpConstructor
     13        fields in compliance with invariants of internal methods [2] (described in #151348),
     14        aligning JSC with V8 and SpiderMonkey.
     15
     16        It doesn't, however, implement [[LegacyFeaturesEnabled]] and RegExp.prototype.compile
     17        changes.
     18
     19        [1]: https://github.com/tc39/proposal-regexp-legacy-features
     20        [2]: https://tc39.es/ecma262/#sec-invariants-of-the-essential-internal-methods
     21
     22        * bytecode/AccessCase.cpp:
     23        (JSC::AccessCase::generateImpl):
     24        * runtime/RegExpConstructor.cpp:
     25        (JSC::JSC_DEFINE_CUSTOM_GETTER):
     26        (JSC::JSC_DEFINE_CUSTOM_SETTER):
     27        (JSC::regExpConstructorDollarImpl): Deleted.
     28        * tools/JSDollarVM.cpp:
     29
    1302021-07-29  Myles C. Maxfield  <mmaxfield@apple.com>
    231
  • trunk/Source/JavaScriptCore/bytecode/AccessCase.cpp

    r280256 r280460  
    14781478        GPRReg valueRegsPayloadGPR = valueRegs.payloadGPR();
    14791479
    1480         if (isValidOffset(m_offset)) {
    1481             Structure* currStructure;
    1482             if (!hasAlternateBase())
    1483                 currStructure = structure();
    1484             else
    1485                 currStructure = alternateBase()->structure(vm);
     1480        Structure* currStructure = hasAlternateBase() ? alternateBase()->structure(vm) : structure();
     1481        if (isValidOffset(m_offset))
    14861482            currStructure->startWatchingPropertyForReplacements(vm, offset());
    1487         }
    14881483
    14891484        bool doesPropertyStorageLoads = m_type == Load
     
    17501745            ASSERT(!doesPropertyStorageLoads); // Or we need an extra register. We rely on propertyOwnerGPR being correct here.
    17511746
    1752             JSGlobalObject* globalObject = hasAlternateBase() ? alternateBase()->globalObject(vm) : structure()->globalObject();
     1747            // We do not need to keep globalObject alive since
     1748            // 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.
     1749            // 2. if it is CustomAccessor, structure should hold it.
     1750            JSGlobalObject* globalObject = currStructure->globalObject();
    17531751
    17541752            // Need to make room for the C call so any of our stack spillage isn't overwritten. It's
  • trunk/Source/JavaScriptCore/runtime/RegExpConstructor.cpp

    r274724 r280460  
    3636static JSC_DECLARE_CUSTOM_GETTER(regExpConstructorLeftContext);
    3737static JSC_DECLARE_CUSTOM_GETTER(regExpConstructorRightContext);
    38 static JSC_DECLARE_CUSTOM_GETTER(regExpConstructorDollar1);
    39 static JSC_DECLARE_CUSTOM_GETTER(regExpConstructorDollar2);
    40 static JSC_DECLARE_CUSTOM_GETTER(regExpConstructorDollar3);
    41 static JSC_DECLARE_CUSTOM_GETTER(regExpConstructorDollar4);
    42 static JSC_DECLARE_CUSTOM_GETTER(regExpConstructorDollar5);
    43 static JSC_DECLARE_CUSTOM_GETTER(regExpConstructorDollar6);
    44 static JSC_DECLARE_CUSTOM_GETTER(regExpConstructorDollar7);
    45 static JSC_DECLARE_CUSTOM_GETTER(regExpConstructorDollar8);
    46 static JSC_DECLARE_CUSTOM_GETTER(regExpConstructorDollar9);
     38static JSC_DECLARE_CUSTOM_GETTER(regExpConstructorDollar);
    4739static JSC_DECLARE_CUSTOM_SETTER(setRegExpConstructorInput);
    4840static JSC_DECLARE_CUSTOM_SETTER(setRegExpConstructorMultiline);
     
    5850/* Source for RegExpConstructor.lut.h
    5951@begin regExpConstructorTable
    60     input           regExpConstructorInput          None
    61     $_              regExpConstructorInput          DontEnum
    62     multiline       regExpConstructorMultiline      None
    63     $*              regExpConstructorMultiline      DontEnum
    64     lastMatch       regExpConstructorLastMatch      DontDelete|ReadOnly
    65     $&              regExpConstructorLastMatch      DontDelete|ReadOnly|DontEnum
    66     lastParen       regExpConstructorLastParen      DontDelete|ReadOnly
    67     $+              regExpConstructorLastParen      DontDelete|ReadOnly|DontEnum
    68     leftContext     regExpConstructorLeftContext    DontDelete|ReadOnly
    69     $`              regExpConstructorLeftContext    DontDelete|ReadOnly|DontEnum
    70     rightContext    regExpConstructorRightContext   DontDelete|ReadOnly
    71     $'              regExpConstructorRightContext   DontDelete|ReadOnly|DontEnum
    72     $1              regExpConstructorDollar1        DontDelete|ReadOnly
    73     $2              regExpConstructorDollar2        DontDelete|ReadOnly
    74     $3              regExpConstructorDollar3        DontDelete|ReadOnly
    75     $4              regExpConstructorDollar4        DontDelete|ReadOnly
    76     $5              regExpConstructorDollar5        DontDelete|ReadOnly
    77     $6              regExpConstructorDollar6        DontDelete|ReadOnly
    78     $7              regExpConstructorDollar7        DontDelete|ReadOnly
    79     $8              regExpConstructorDollar8        DontDelete|ReadOnly
    80     $9              regExpConstructorDollar9        DontDelete|ReadOnly
     52    input           regExpConstructorInput          CustomAccessor|DontEnum
     53    $_              regExpConstructorInput          CustomAccessor|DontEnum
     54    multiline       regExpConstructorMultiline      CustomAccessor|DontEnum
     55    $*              regExpConstructorMultiline      CustomAccessor|DontEnum
     56    lastMatch       regExpConstructorLastMatch      CustomAccessor|ReadOnly|DontEnum
     57    $&              regExpConstructorLastMatch      CustomAccessor|ReadOnly|DontEnum
     58    lastParen       regExpConstructorLastParen      CustomAccessor|ReadOnly|DontEnum
     59    $+              regExpConstructorLastParen      CustomAccessor|ReadOnly|DontEnum
     60    leftContext     regExpConstructorLeftContext    CustomAccessor|ReadOnly|DontEnum
     61    $`              regExpConstructorLeftContext    CustomAccessor|ReadOnly|DontEnum
     62    rightContext    regExpConstructorRightContext   CustomAccessor|ReadOnly|DontEnum
     63    $'              regExpConstructorRightContext   CustomAccessor|ReadOnly|DontEnum
     64    $1              regExpConstructorDollar         CustomAccessor|ReadOnly|DontEnum
     65    $2              regExpConstructorDollar         CustomAccessor|ReadOnly|DontEnum
     66    $3              regExpConstructorDollar         CustomAccessor|ReadOnly|DontEnum
     67    $4              regExpConstructorDollar         CustomAccessor|ReadOnly|DontEnum
     68    $5              regExpConstructorDollar         CustomAccessor|ReadOnly|DontEnum
     69    $6              regExpConstructorDollar         CustomAccessor|ReadOnly|DontEnum
     70    $7              regExpConstructorDollar         CustomAccessor|ReadOnly|DontEnum
     71    $8              regExpConstructorDollar         CustomAccessor|ReadOnly|DontEnum
     72    $9              regExpConstructorDollar         CustomAccessor|ReadOnly|DontEnum
    8173@end
    8274*/
     
    10193}
    10294
    103 template<int N>
    104 inline EncodedJSValue regExpConstructorDollarImpl(JSGlobalObject*, EncodedJSValue thisValue, PropertyName)
    105 {
    106     JSGlobalObject* globalObject = jsCast<RegExpConstructor*>(JSValue::decode(thisValue))->globalObject();
     95JSC_DEFINE_CUSTOM_GETTER(regExpConstructorDollar, (JSGlobalObject* globalObject, EncodedJSValue thisValue, PropertyName propertyName))
     96{
     97    VM& vm = globalObject->vm();
     98    auto scope = DECLARE_THROW_SCOPE(vm);
     99    if (JSValue::decode(thisValue) != globalObject->regExpConstructor())
     100        return throwVMTypeError(globalObject, scope, "RegExp.$N getters require RegExp constructor as |this|"_s);
     101    unsigned N = propertyName.uid()->at(1) - '0';
     102    ASSERT(N >= 1 && N <= 9);
    107103    return JSValue::encode(globalObject->regExpGlobalData().getBackref(globalObject, N));
    108104}
    109105
    110 JSC_DEFINE_CUSTOM_GETTER(regExpConstructorDollar1, (JSGlobalObject* globalObject, EncodedJSValue thisValue, PropertyName propertyName))
    111 {
    112     return regExpConstructorDollarImpl<1>(globalObject, thisValue, propertyName);
    113 }
    114 JSC_DEFINE_CUSTOM_GETTER(regExpConstructorDollar2, (JSGlobalObject* globalObject, EncodedJSValue thisValue, PropertyName propertyName))
    115 {
    116     return regExpConstructorDollarImpl<2>(globalObject, thisValue, propertyName);
    117 }
    118 JSC_DEFINE_CUSTOM_GETTER(regExpConstructorDollar3, (JSGlobalObject* globalObject, EncodedJSValue thisValue, PropertyName propertyName))
    119 {
    120     return regExpConstructorDollarImpl<3>(globalObject, thisValue, propertyName);
    121 }
    122 JSC_DEFINE_CUSTOM_GETTER(regExpConstructorDollar4, (JSGlobalObject* globalObject, EncodedJSValue thisValue, PropertyName propertyName))
    123 {
    124     return regExpConstructorDollarImpl<4>(globalObject, thisValue, propertyName);
    125 }
    126 JSC_DEFINE_CUSTOM_GETTER(regExpConstructorDollar5, (JSGlobalObject* globalObject, EncodedJSValue thisValue, PropertyName propertyName))
    127 {
    128     return regExpConstructorDollarImpl<5>(globalObject, thisValue, propertyName);
    129 }
    130 JSC_DEFINE_CUSTOM_GETTER(regExpConstructorDollar6, (JSGlobalObject* globalObject, EncodedJSValue thisValue, PropertyName propertyName))
    131 {
    132     return regExpConstructorDollarImpl<6>(globalObject, thisValue, propertyName);
    133 }
    134 JSC_DEFINE_CUSTOM_GETTER(regExpConstructorDollar7, (JSGlobalObject* globalObject, EncodedJSValue thisValue, PropertyName propertyName))
    135 {
    136     return regExpConstructorDollarImpl<7>(globalObject, thisValue, propertyName);
    137 }
    138 JSC_DEFINE_CUSTOM_GETTER(regExpConstructorDollar8, (JSGlobalObject* globalObject, EncodedJSValue thisValue, PropertyName propertyName))
    139 {
    140     return regExpConstructorDollarImpl<8>(globalObject, thisValue, propertyName);
    141 }
    142 JSC_DEFINE_CUSTOM_GETTER(regExpConstructorDollar9, (JSGlobalObject* globalObject, EncodedJSValue thisValue, PropertyName propertyName))
    143 {
    144     return regExpConstructorDollarImpl<9>(globalObject, thisValue, propertyName);
    145 }
    146 
    147 JSC_DEFINE_CUSTOM_GETTER(regExpConstructorInput, (JSGlobalObject*, EncodedJSValue thisValue, PropertyName))
    148 {
    149     JSGlobalObject* globalObject = jsCast<RegExpConstructor*>(JSValue::decode(thisValue))->globalObject();
     106JSC_DEFINE_CUSTOM_GETTER(regExpConstructorInput, (JSGlobalObject* globalObject, EncodedJSValue thisValue, PropertyName))
     107{
     108    VM& vm = globalObject->vm();
     109    auto scope = DECLARE_THROW_SCOPE(vm);
     110    if (JSValue::decode(thisValue) != globalObject->regExpConstructor())
     111        return throwVMTypeError(globalObject, scope, "RegExp.input getter requires RegExp constructor as |this|"_s);
    150112    return JSValue::encode(globalObject->regExpGlobalData().input());
    151113}
    152114
    153 JSC_DEFINE_CUSTOM_GETTER(regExpConstructorMultiline, (JSGlobalObject*, EncodedJSValue thisValue, PropertyName))
    154 {
    155     JSGlobalObject* globalObject = jsCast<RegExpConstructor*>(JSValue::decode(thisValue))->globalObject();
     115JSC_DEFINE_CUSTOM_GETTER(regExpConstructorMultiline, (JSGlobalObject* globalObject, EncodedJSValue thisValue, PropertyName))
     116{
     117    VM& vm = globalObject->vm();
     118    auto scope = DECLARE_THROW_SCOPE(vm);
     119    if (JSValue::decode(thisValue) != globalObject->regExpConstructor())
     120        return throwVMTypeError(globalObject, scope, "RegExp.multiline getter require RegExp constructor as |this|"_s);
    156121    return JSValue::encode(jsBoolean(globalObject->regExpGlobalData().multiline()));
    157122}
    158123
    159 JSC_DEFINE_CUSTOM_GETTER(regExpConstructorLastMatch, (JSGlobalObject*, EncodedJSValue thisValue, PropertyName))
    160 {
    161     JSGlobalObject* globalObject = jsCast<RegExpConstructor*>(JSValue::decode(thisValue))->globalObject();
    162     return JSValue::encode(globalObject->regExpGlobalData().getBackref(globalObject, 0));
    163 }
    164 
    165 JSC_DEFINE_CUSTOM_GETTER(regExpConstructorLastParen, (JSGlobalObject*, EncodedJSValue thisValue, PropertyName))
    166 {
    167     JSGlobalObject* globalObject = jsCast<RegExpConstructor*>(JSValue::decode(thisValue))->globalObject();
    168     return JSValue::encode(globalObject->regExpGlobalData().getLastParen(globalObject));
    169 }
    170 
    171 JSC_DEFINE_CUSTOM_GETTER(regExpConstructorLeftContext, (JSGlobalObject*, EncodedJSValue thisValue, PropertyName))
    172 {
    173     JSGlobalObject* globalObject = jsCast<RegExpConstructor*>(JSValue::decode(thisValue))->globalObject();
    174     return JSValue::encode(globalObject->regExpGlobalData().getLeftContext(globalObject));
    175 }
    176 
    177 JSC_DEFINE_CUSTOM_GETTER(regExpConstructorRightContext, (JSGlobalObject*, EncodedJSValue thisValue, PropertyName))
    178 {
    179     JSGlobalObject* globalObject = jsCast<RegExpConstructor*>(JSValue::decode(thisValue))->globalObject();
    180     return JSValue::encode(globalObject->regExpGlobalData().getRightContext(globalObject));
     124JSC_DEFINE_CUSTOM_GETTER(regExpConstructorLastMatch, (JSGlobalObject* globalObject, EncodedJSValue thisValue, PropertyName))
     125{
     126    VM& vm = globalObject->vm();
     127    auto scope = DECLARE_THROW_SCOPE(vm);
     128    if (JSValue::decode(thisValue) != globalObject->regExpConstructor())
     129        return throwVMTypeError(globalObject, scope, "RegExp.lastMatch getter require RegExp constructor as |this|"_s);
     130    RELEASE_AND_RETURN(scope, JSValue::encode(globalObject->regExpGlobalData().getBackref(globalObject, 0)));
     131}
     132
     133JSC_DEFINE_CUSTOM_GETTER(regExpConstructorLastParen, (JSGlobalObject* globalObject, EncodedJSValue thisValue, PropertyName))
     134{
     135    VM& vm = globalObject->vm();
     136    auto scope = DECLARE_THROW_SCOPE(vm);
     137    if (JSValue::decode(thisValue) != globalObject->regExpConstructor())
     138        return throwVMTypeError(globalObject, scope, "RegExp.lastParen getter require RegExp constructor as |this|"_s);
     139    RELEASE_AND_RETURN(scope, JSValue::encode(globalObject->regExpGlobalData().getLastParen(globalObject)));
     140}
     141
     142JSC_DEFINE_CUSTOM_GETTER(regExpConstructorLeftContext, (JSGlobalObject* globalObject, EncodedJSValue thisValue, PropertyName))
     143{
     144    VM& vm = globalObject->vm();
     145    auto scope = DECLARE_THROW_SCOPE(vm);
     146    if (JSValue::decode(thisValue) != globalObject->regExpConstructor())
     147        return throwVMTypeError(globalObject, scope, "RegExp.leftContext getter require RegExp constructor as |this|"_s);
     148    RELEASE_AND_RETURN(scope, JSValue::encode(globalObject->regExpGlobalData().getLeftContext(globalObject)));
     149}
     150
     151JSC_DEFINE_CUSTOM_GETTER(regExpConstructorRightContext, (JSGlobalObject* globalObject, EncodedJSValue thisValue, PropertyName))
     152{
     153    VM& vm = globalObject->vm();
     154    auto scope = DECLARE_THROW_SCOPE(vm);
     155    if (JSValue::decode(thisValue) != globalObject->regExpConstructor())
     156        return throwVMTypeError(globalObject, scope, "RegExp.rightContext getter require RegExp constructor as |this|"_s);
     157    RELEASE_AND_RETURN(scope, JSValue::encode(globalObject->regExpGlobalData().getRightContext(globalObject)));
    181158}
    182159
     
    185162    VM& vm = globalObject->vm();
    186163    auto scope = DECLARE_THROW_SCOPE(vm);
    187     if (auto constructor = jsDynamicCast<RegExpConstructor*>(vm, JSValue::decode(thisValue))) {
    188         auto* string = JSValue::decode(value).toString(globalObject);
    189         RETURN_IF_EXCEPTION(scope, { });
    190         scope.release();
    191         JSGlobalObject* globalObject = constructor->globalObject();
    192         globalObject->regExpGlobalData().setInput(globalObject, string);
    193         return true;
    194     }
    195     return false;
     164    if (JSValue::decode(thisValue) != globalObject->regExpConstructor()) {
     165        throwTypeError(globalObject, scope, "RegExp.input setters require RegExp constructor as |this|"_s);
     166        return false;
     167    }
     168    auto* string = JSValue::decode(value).toString(globalObject);
     169    RETURN_IF_EXCEPTION(scope, { });
     170    scope.release();
     171    globalObject->regExpGlobalData().setInput(globalObject, string);
     172    return true;
    196173}
    197174
     
    200177    VM& vm = globalObject->vm();
    201178    auto scope = DECLARE_THROW_SCOPE(vm);
    202     if (auto constructor = jsDynamicCast<RegExpConstructor*>(vm, JSValue::decode(thisValue))) {
    203         bool multiline = JSValue::decode(value).toBoolean(globalObject);
    204         RETURN_IF_EXCEPTION(scope, { });
    205         scope.release();
    206         JSGlobalObject* globalObject = constructor->globalObject();
    207         globalObject->regExpGlobalData().setMultiline(multiline);
    208         return true;
    209     }
    210     return false;
     179    if (JSValue::decode(thisValue) != globalObject->regExpConstructor()) {
     180        throwTypeError(globalObject, scope, "RegExp.multiline setters require RegExp constructor as |this|"_s);
     181        return false;
     182    }
     183    bool multiline = JSValue::decode(value).toBoolean(globalObject);
     184    RETURN_IF_EXCEPTION(scope, { });
     185    scope.release();
     186    globalObject->regExpGlobalData().setMultiline(multiline);
     187    return true;
    211188}
    212189
  • trunk/Source/JavaScriptCore/tools/JSDollarVM.cpp

    r280256 r280460  
    16011601static JSC_DECLARE_CUSTOM_GETTER(customGetAccessor);
    16021602static JSC_DECLARE_CUSTOM_GETTER(customGetValue);
     1603static JSC_DECLARE_CUSTOM_GETTER(customGetValue2);
    16031604static JSC_DECLARE_CUSTOM_GETTER(customGetAccessorGlobalObject);
    16041605static JSC_DECLARE_CUSTOM_GETTER(customGetValueGlobalObject);
     
    16061607static JSC_DECLARE_CUSTOM_SETTER(customSetAccessorGlobalObject);
    16071608static JSC_DECLARE_CUSTOM_SETTER(customSetValue);
     1609static JSC_DECLARE_CUSTOM_SETTER(customSetValue2);
    16081610static JSC_DECLARE_CUSTOM_SETTER(customSetValueGlobalObject);
    16091611static JSC_DECLARE_CUSTOM_SETTER(customFunctionSetter);
     
    16221624}
    16231625
     1626JSC_DEFINE_CUSTOM_GETTER(customGetValue2, (JSGlobalObject* globalObject, EncodedJSValue slotValue, PropertyName))
     1627{
     1628    DollarVMAssertScope assertScope;
     1629    VM& vm = globalObject->vm();
     1630
     1631    RELEASE_ASSERT(JSValue::decode(slotValue).inherits<JSTestCustomGetterSetter>(globalObject->vm()));
     1632
     1633    auto* target = jsCast<JSTestCustomGetterSetter*>(JSValue::decode(slotValue));
     1634    JSValue value = target->getDirect(vm, Identifier::fromString(vm, "value2"));
     1635    return JSValue::encode(value ? value : jsUndefined());
     1636}
     1637
    16241638JSC_DEFINE_CUSTOM_GETTER(customGetAccessorGlobalObject, (JSGlobalObject* globalObject, EncodedJSValue, PropertyName))
    16251639{
     
    16971711    object->put(object, globalObject, Identifier::fromString(vm, "result"), globalObject, slot);
    16981712
     1713    return true;
     1714}
     1715
     1716JSC_DEFINE_CUSTOM_SETTER(customSetValue2, (JSGlobalObject* globalObject, EncodedJSValue slotValue, EncodedJSValue encodedValue, PropertyName))
     1717{
     1718    DollarVMAssertScope assertScope;
     1719    VM& vm = globalObject->vm();
     1720
     1721    RELEASE_ASSERT(JSValue::decode(slotValue).inherits<JSTestCustomGetterSetter>(vm));
     1722    auto* target = jsCast<JSTestCustomGetterSetter*>(JSValue::decode(slotValue));
     1723    PutPropertySlot slot(target);
     1724    target->putDirect(vm, Identifier::fromString(vm, "value2"), JSValue::decode(encodedValue));
    16991725    return true;
    17001726}
     
    17241750    putDirectCustomAccessor(vm, Identifier::fromString(vm, "customValue"),
    17251751        CustomGetterSetter::create(vm, customGetValue, customSetValue), 0);
     1752    putDirectCustomAccessor(vm, Identifier::fromString(vm, "customValue2"),
     1753        CustomGetterSetter::create(vm, customGetValue2, customSetValue2), static_cast<unsigned>(PropertyAttribute::CustomValue));
    17261754    putDirectCustomAccessor(vm, Identifier::fromString(vm, "customAccessor"),
    17271755        CustomGetterSetter::create(vm, customGetAccessor, customSetAccessor), static_cast<unsigned>(PropertyAttribute::CustomAccessor));
Note: See TracChangeset for help on using the changeset viewer.