<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[286251] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/286251">286251</a></dd>
<dt>Author</dt> <dd>ysuzuki@apple.com</dd>
<dt>Date</dt> <dd>2021-11-29 12:04:08 -0800 (Mon, 29 Nov 2021)</dd>
</dl>

<h3>Log Message</h3>
<pre>[JSC] Public Class Field initialization is slow
https://bugs.webkit.org/show_bug.cgi?id=232479

Reviewed by Alexey Shvayka.

JSTests:

* microbenchmarks/class-fields-classic-constructor-assignments.js: Added.
(Classic_Constructor_Assignments):
(bench):
* microbenchmarks/class-fields-private-fields.js: Added.
(ES2022_Private_Fields):
(bench):
* microbenchmarks/class-fields-public-fields.js: Added.
(ES2022_Public_Fields):
(bench):
* stress/class-fields-getter-override.js: Added.
(shouldThrow):
(defineCGetter.):
(B):
(define0Getter.):
(define0Getter):
(D):
* stress/custom-get-set-proto-chain-put.js:
(let.object.of.getObjects):
* stress/freeze-and-seal-should-prevent-extensions.js:
* stress/object-assign-fast-path.js:
* stress/ordinary-set-exceptions.js:
(shouldThrow):
* stress/put-non-reified-static-function-or-custom.js:
* wasm/js-api/test_basic_api.js:
(const.c.in.constructorProperties.switch):

Source/JavaScriptCore:

Class public field implementation did not have optimization for initializing class fields: using
runtime call to initialize fields instead of IC. This patch leverages put_by_id / put_by_val with
direct flag so that we can enable IC.

Currently, we are not changing original putDirect semantics since it is out of this patch's scope.
We will look into it and probably changing it in a separate patch, but not in this patch.

                                                     ToT                     Patched

class-fields-classic-constructor-assignments
                                               17.1491+-2.6327           15.0906+-0.6795          might be 1.1364x faster
class-fields-public-fields                    409.4328+-8.3140     ^     20.2752+-2.0835        ^ definitely 20.1938x faster
class-fields-private-fields                    27.2621+-1.3858           25.1810+-3.9873          might be 1.0826x faster

* bytecompiler/NodesCodegen.cpp:
(JSC::DefineFieldNode::emitBytecode):
* runtime/CommonSlowPaths.h:
(JSC::CommonSlowPaths::putDirectWithReify):
* runtime/JSObject.cpp:
(JSC::JSObject::putDirectCustomAccessor):
(JSC::JSObject::putDirectNonIndexAccessor):
* runtime/JSObject.h:
(JSC::JSObject::putDirect):
(JSC::JSObject::putDirectRespectingExtensibility):
* runtime/JSObjectInlines.h:
(JSC::JSObject::putInlineFast):
(JSC::JSObject::putDirectInternal):
(JSC::JSObject::putOwnDataProperty):
(JSC::JSObject::putOwnDataPropertyMayBeIndex):

Source/WTF:

* wtf/text/ASCIILiteral.h:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkJSTestsChangeLog">trunk/JSTests/ChangeLog</a></li>
<li><a href="#trunkJSTestsstresscustomgetsetprotochainputjs">trunk/JSTests/stress/custom-get-set-proto-chain-put.js</a></li>
<li><a href="#trunkJSTestsstressfreezeandsealshouldpreventextensionsjs">trunk/JSTests/stress/freeze-and-seal-should-prevent-extensions.js</a></li>
<li><a href="#trunkJSTestsstressobjectassignfastpathjs">trunk/JSTests/stress/object-assign-fast-path.js</a></li>
<li><a href="#trunkJSTestsstressordinarysetexceptionsjs">trunk/JSTests/stress/ordinary-set-exceptions.js</a></li>
<li><a href="#trunkJSTestsstressputnonreifiedstaticfunctionorcustomjs">trunk/JSTests/stress/put-non-reified-static-function-or-custom.js</a></li>
<li><a href="#trunkJSTestswasmjsapitest_basic_apijs">trunk/JSTests/wasm/js-api/test_basic_api.js</a></li>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecompilerNodesCodegencpp">trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeCommonSlowPathsh">trunk/Source/JavaScriptCore/runtime/CommonSlowPaths.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSObjectcpp">trunk/Source/JavaScriptCore/runtime/JSObject.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSObjecth">trunk/Source/JavaScriptCore/runtime/JSObject.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSObjectInlinesh">trunk/Source/JavaScriptCore/runtime/JSObjectInlines.h</a></li>
<li><a href="#trunkSourceWTFChangeLog">trunk/Source/WTF/ChangeLog</a></li>
<li><a href="#trunkSourceWTFwtftextASCIILiteralh">trunk/Source/WTF/wtf/text/ASCIILiteral.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkJSTestsmicrobenchmarksclassfieldsclassicconstructorassignmentsjs">trunk/JSTests/microbenchmarks/class-fields-classic-constructor-assignments.js</a></li>
<li><a href="#trunkJSTestsmicrobenchmarksclassfieldsprivatefieldsjs">trunk/JSTests/microbenchmarks/class-fields-private-fields.js</a></li>
<li><a href="#trunkJSTestsmicrobenchmarksclassfieldspublicfieldsjs">trunk/JSTests/microbenchmarks/class-fields-public-fields.js</a></li>
<li><a href="#trunkJSTestsstressclassfieldsgetteroverridejs">trunk/JSTests/stress/class-fields-getter-override.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkJSTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/ChangeLog (286250 => 286251)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/ChangeLog  2021-11-29 19:57:11 UTC (rev 286250)
+++ trunk/JSTests/ChangeLog     2021-11-29 20:04:08 UTC (rev 286251)
</span><span class="lines">@@ -1,5 +1,38 @@
</span><span class="cx"> 2021-11-29  Yusuke Suzuki  <ysuzuki@apple.com>
</span><span class="cx"> 
</span><ins>+        [JSC] Public Class Field initialization is slow
+        https://bugs.webkit.org/show_bug.cgi?id=232479
+
+        Reviewed by Alexey Shvayka.
+
+        * microbenchmarks/class-fields-classic-constructor-assignments.js: Added.
+        (Classic_Constructor_Assignments):
+        (bench):
+        * microbenchmarks/class-fields-private-fields.js: Added.
+        (ES2022_Private_Fields):
+        (bench):
+        * microbenchmarks/class-fields-public-fields.js: Added.
+        (ES2022_Public_Fields):
+        (bench):
+        * stress/class-fields-getter-override.js: Added.
+        (shouldThrow):
+        (defineCGetter.):
+        (B):
+        (define0Getter.):
+        (define0Getter):
+        (D):
+        * stress/custom-get-set-proto-chain-put.js:
+        (let.object.of.getObjects):
+        * stress/freeze-and-seal-should-prevent-extensions.js:
+        * stress/object-assign-fast-path.js:
+        * stress/ordinary-set-exceptions.js:
+        (shouldThrow):
+        * stress/put-non-reified-static-function-or-custom.js:
+        * wasm/js-api/test_basic_api.js:
+        (const.c.in.constructorProperties.switch):
+
+2021-11-29  Yusuke Suzuki  <ysuzuki@apple.com>
+
</ins><span class="cx">         [JSC] private name operation should use RETURN_IF_EXCEPTION
</span><span class="cx">         https://bugs.webkit.org/show_bug.cgi?id=233577
</span><span class="cx">         rdar://85813869
</span></span></pre></div>
<a id="trunkJSTestsmicrobenchmarksclassfieldsclassicconstructorassignmentsjs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/microbenchmarks/class-fields-classic-constructor-assignments.js (0 => 286251)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/microbenchmarks/class-fields-classic-constructor-assignments.js                            (rev 0)
+++ trunk/JSTests/microbenchmarks/class-fields-classic-constructor-assignments.js       2021-11-29 20:04:08 UTC (rev 286251)
</span><span class="lines">@@ -0,0 +1,28 @@
</span><ins>+class Classic_Constructor_Assignments {
+    constructor() {
+        this.verification=1;
+
+        this._00=1; this._01=1; this._02=1; this._03=1; this._04=1; this._05=1; this._06=1; this._07=1; this._08=1; this._09=1;
+        this._10=1; this._11=1; this._12=1; this._13=1; this._14=1; this._15=1; this._16=1; this._17=1; this._18=1; this._19=1;
+        this._20=1; this._21=1; this._22=1; this._23=1; this._24=1; this._25=1; this._26=1; this._27=1; this._28=1; this._29=1;
+        this._30=1; this._31=1; this._32=1; this._33=1; this._34=1; this._35=1; this._36=1; this._37=1; this._38=1; this._39=1;
+        this._40=1; this._41=1; this._42=1; this._43=1; this._44=1; this._45=1; this._46=1; this._47=1; this._48=1; this._49=1;
+        this._50=1; this._51=1; this._52=1; this._53=1; this._54=1; this._55=1; this._56=1; this._57=1; this._58=1; this._59=1;
+        this._60=1; this._61=1; this._62=1; this._63=1; this._64=1; this._65=1; this._66=1; this._67=1; this._68=1; this._69=1;
+        this._70=1; this._71=1; this._72=1; this._73=1; this._74=1; this._75=1; this._76=1; this._77=1; this._78=1; this._79=1;
+        this._80=1; this._81=1; this._82=1; this._83=1; this._84=1; this._85=1; this._86=1; this._87=1; this._88=1; this._89=1;
+        this._90=1; this._91=1; this._92=1; this._93=1; this._94=1; this._95=1; this._96=1; this._97=1; this._98=1; this._99=1;
+    }
+}
+
+const ITERATIONS = 100_000;
+
+function bench(testClass) {
+    var acc = 0;
+    for (var i=0; i<ITERATIONS; i++) {
+        const instance = new testClass()
+        acc += instance.verification;
+    }
+}
+
+bench(Classic_Constructor_Assignments);
</ins></span></pre></div>
<a id="trunkJSTestsmicrobenchmarksclassfieldsprivatefieldsjs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/microbenchmarks/class-fields-private-fields.js (0 => 286251)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/microbenchmarks/class-fields-private-fields.js                             (rev 0)
+++ trunk/JSTests/microbenchmarks/class-fields-private-fields.js        2021-11-29 20:04:08 UTC (rev 286251)
</span><span class="lines">@@ -0,0 +1,29 @@
</span><ins>+class ES2022_Private_Fields {
+    verification=1;
+
+    #_00=1; #_01=1; #_02=1; #_03=1; #_04=1; #_05=1; #_06=1; #_07=1; #_08=1; #_09=1;
+    #_10=1; #_11=1; #_12=1; #_13=1; #_14=1; #_15=1; #_16=1; #_17=1; #_18=1; #_19=1;
+    #_20=1; #_21=1; #_22=1; #_23=1; #_24=1; #_25=1; #_26=1; #_27=1; #_28=1; #_29=1;
+    #_30=1; #_31=1; #_32=1; #_33=1; #_34=1; #_35=1; #_36=1; #_37=1; #_38=1; #_39=1;
+    #_40=1; #_41=1; #_42=1; #_43=1; #_44=1; #_45=1; #_46=1; #_47=1; #_48=1; #_49=1;
+    #_50=1; #_51=1; #_52=1; #_53=1; #_54=1; #_55=1; #_56=1; #_57=1; #_58=1; #_59=1;
+    #_60=1; #_61=1; #_62=1; #_63=1; #_64=1; #_65=1; #_66=1; #_67=1; #_68=1; #_69=1;
+    #_70=1; #_71=1; #_72=1; #_73=1; #_74=1; #_75=1; #_76=1; #_77=1; #_78=1; #_79=1;
+    #_80=1; #_81=1; #_82=1; #_83=1; #_84=1; #_85=1; #_86=1; #_87=1; #_88=1; #_89=1;
+    #_90=1; #_91=1; #_92=1; #_93=1; #_94=1; #_95=1; #_96=1; #_97=1; #_98=1; #_99=1;
+}
+
+
+// Benchmarking
+
+const ITERATIONS = 100_000;
+
+function bench(testClass) {
+    var acc = 0;
+    for (var i=0; i<ITERATIONS; i++) {
+        const instance = new testClass()
+        acc += instance.verification;
+    }
+}
+
+bench(ES2022_Private_Fields);
</ins></span></pre></div>
<a id="trunkJSTestsmicrobenchmarksclassfieldspublicfieldsjs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/microbenchmarks/class-fields-public-fields.js (0 => 286251)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/microbenchmarks/class-fields-public-fields.js                              (rev 0)
+++ trunk/JSTests/microbenchmarks/class-fields-public-fields.js 2021-11-29 20:04:08 UTC (rev 286251)
</span><span class="lines">@@ -0,0 +1,26 @@
</span><ins>+class ES2022_Public_Fields {
+    verification=1;
+
+    _00=1; _01=1; _02=1; _03=1; _04=1; _05=1; _06=1; _07=1; _08=1; _09=1;
+    _10=1; _11=1; _12=1; _13=1; _14=1; _15=1; _16=1; _17=1; _18=1; _19=1;
+    _20=1; _21=1; _22=1; _23=1; _24=1; _25=1; _26=1; _27=1; _28=1; _29=1;
+    _30=1; _31=1; _32=1; _33=1; _34=1; _35=1; _36=1; _37=1; _38=1; _39=1;
+    _40=1; _41=1; _42=1; _43=1; _44=1; _45=1; _46=1; _47=1; _48=1; _49=1;
+    _50=1; _51=1; _52=1; _53=1; _54=1; _55=1; _56=1; _57=1; _58=1; _59=1;
+    _60=1; _61=1; _62=1; _63=1; _64=1; _65=1; _66=1; _67=1; _68=1; _69=1;
+    _70=1; _71=1; _72=1; _73=1; _74=1; _75=1; _76=1; _77=1; _78=1; _79=1;
+    _80=1; _81=1; _82=1; _83=1; _84=1; _85=1; _86=1; _87=1; _88=1; _89=1;
+    _90=1; _91=1; _92=1; _93=1; _94=1; _95=1; _96=1; _97=1; _98=1; _99=1;
+}
+
+const ITERATIONS = 100_000;
+
+function bench(testClass) {
+    var acc = 0;
+    for (var i=0; i<ITERATIONS; i++) {
+        const instance = new testClass()
+        acc += instance.verification;
+    }
+}
+
+bench(ES2022_Public_Fields);
</ins></span></pre></div>
<a id="trunkJSTestsstressclassfieldsgetteroverridejs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/stress/class-fields-getter-override.js (0 => 286251)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/stress/class-fields-getter-override.js                             (rev 0)
+++ trunk/JSTests/stress/class-fields-getter-override.js        2021-11-29 20:04:08 UTC (rev 286251)
</span><span class="lines">@@ -0,0 +1,50 @@
</span><ins>+function shouldThrow(func, errorMessage) {
+    var errorThrown = false;
+    var error = null;
+    try {
+        func();
+    } catch (e) {
+        errorThrown = true;
+        error = e;
+    }
+    if (!errorThrown)
+        throw new Error('not thrown');
+    if (String(error) !== errorMessage)
+        throw new Error(`bad error: ${String(error)}`);
+}
+
+function defineCGetter(obj) {
+    Reflect.defineProperty(obj, "c", {
+        get: function() { return 'defineCGetter'; }
+    });
+}
+
+class A {
+    b = defineCGetter(this);
+    c = 42;
+};
+shouldThrow(() => new A(), `TypeError: Attempting to change configurable attribute of unconfigurable property.`);
+
+let key = 'c';
+class B {
+    b = defineCGetter(this);
+    [key] = 42;
+};
+shouldThrow(() => new B(), `TypeError: Attempting to change configurable attribute of unconfigurable property.`);
+
+function define0Getter(obj) {
+    Reflect.defineProperty(obj, "0", {
+        get: function() { return 'defineCGetter'; }
+    });
+}
+class C {
+    b = define0Getter(this);
+    [0] = 42;
+};
+shouldThrow(() => new C(), `TypeError: Attempting to change configurable attribute of unconfigurable property.`);
+
+class D {
+    b = Object.freeze(this);
+    [0] = 42;
+};
+shouldThrow(() => new D(), `TypeError: Attempting to define property on object that is not extensible.`);
</ins></span></pre></div>
<a id="trunkJSTestsstresscustomgetsetprotochainputjs"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/stress/custom-get-set-proto-chain-put.js (286250 => 286251)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/stress/custom-get-set-proto-chain-put.js   2021-11-29 19:57:11 UTC (rev 286250)
+++ trunk/JSTests/stress/custom-get-set-proto-chain-put.js      2021-11-29 20:04:08 UTC (rev 286251)
</span><span class="lines">@@ -121,7 +121,7 @@
</span><span class="cx">     for (let object of getObjects()) {
</span><span class="cx">         Object.preventExtensions(object);
</span><span class="cx">         for (let i = 0; i < 100; ++i) {
</span><del>-            shouldThrow(() => { object.customValueNoSetter = {}; }, "TypeError: Attempted to assign to readonly property.");
</del><ins>+            shouldThrow(() => { object.customValueNoSetter = {}; }, "TypeError: Attempting to define property on object that is not extensible.");
</ins><span class="cx">             assert(!Reflect.set(object, "customValueNoSetter", {}));
</span><span class="cx">         }
</span><span class="cx">     }
</span></span></pre></div>
<a id="trunkJSTestsstressfreezeandsealshouldpreventextensionsjs"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/stress/freeze-and-seal-should-prevent-extensions.js (286250 => 286251)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/stress/freeze-and-seal-should-prevent-extensions.js        2021-11-29 19:57:11 UTC (rev 286250)
+++ trunk/JSTests/stress/freeze-and-seal-should-prevent-extensions.js   2021-11-29 20:04:08 UTC (rev 286251)
</span><span class="lines">@@ -31,7 +31,7 @@
</span><span class="cx">     Object.freeze(object);
</span><span class="cx">     shouldBe(object.Matcha, 'Matcha');
</span><span class="cx">     shouldBe(Reflect.isExtensible(object), false);
</span><del>-    shouldThrow(() => object.Mocha = 'Mocha', `TypeError: Attempted to assign to readonly property.`);
</del><ins>+    shouldThrow(() => object.Mocha = 'Mocha', `TypeError: Attempting to define property on object that is not extensible.`);
</ins><span class="cx"> }());
</span><span class="cx"> 
</span><span class="cx"> (function () {
</span><span class="lines">@@ -47,5 +47,5 @@
</span><span class="cx">     Object.seal(object);
</span><span class="cx">     shouldBe(object.Matcha, 'Matcha');
</span><span class="cx">     shouldBe(Reflect.isExtensible(object), false);
</span><del>-    shouldThrow(() => object.Mocha = 'Mocha', `TypeError: Attempted to assign to readonly property.`);
</del><ins>+    shouldThrow(() => object.Mocha = 'Mocha', `TypeError: Attempting to define property on object that is not extensible.`);
</ins><span class="cx"> }());
</span></span></pre></div>
<a id="trunkJSTestsstressobjectassignfastpathjs"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/stress/object-assign-fast-path.js (286250 => 286251)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/stress/object-assign-fast-path.js  2021-11-29 19:57:11 UTC (rev 286250)
+++ trunk/JSTests/stress/object-assign-fast-path.js     2021-11-29 20:04:08 UTC (rev 286251)
</span><span class="lines">@@ -180,6 +180,6 @@
</span><span class="cx">     let object = Object.preventExtensions({ foo: 1 });
</span><span class="cx">     shouldThrow(() => {
</span><span class="cx">         Object.assign(object, { bar: 2 });
</span><del>-    }, `TypeError: Attempted to assign to readonly property.`);
</del><ins>+    }, `TypeError: Attempting to define property on object that is not extensible.`);
</ins><span class="cx">     shouldBe(object.bar, undefined);
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkJSTestsstressordinarysetexceptionsjs"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/stress/ordinary-set-exceptions.js (286250 => 286251)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/stress/ordinary-set-exceptions.js  2021-11-29 19:57:11 UTC (rev 286250)
+++ trunk/JSTests/stress/ordinary-set-exceptions.js     2021-11-29 20:04:08 UTC (rev 286251)
</span><span class="lines">@@ -63,7 +63,7 @@
</span><span class="cx">         value: 42,
</span><span class="cx">     }), true);
</span><span class="cx">     receiver.cocoa = 'NG';
</span><del>-}, `TypeError: Attempted to assign to readonly property.`);
</del><ins>+}, `TypeError: Attempting to change value of a readonly property.`);
</ins><span class="cx"> 
</span><span class="cx"> // 9.1.9.1 4-d-ii
</span><span class="cx"> shouldThrow(function () {
</span><span class="lines">@@ -85,7 +85,7 @@
</span><span class="cx">         value: 42,
</span><span class="cx">     }), true);
</span><span class="cx">     receiver.cocoa = 'NG';
</span><del>-}, `TypeError: Attempted to assign to readonly property.`);
</del><ins>+}, `TypeError: Attempting to change value of a readonly property.`);
</ins><span class="cx"> 
</span><span class="cx"> // 9.1.9.1 7
</span><span class="cx"> shouldThrow(function () {
</span></span></pre></div>
<a id="trunkJSTestsstressputnonreifiedstaticfunctionorcustomjs"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/stress/put-non-reified-static-function-or-custom.js (286250 => 286251)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/stress/put-non-reified-static-function-or-custom.js        2021-11-29 19:57:11 UTC (rev 286250)
+++ trunk/JSTests/stress/put-non-reified-static-function-or-custom.js   2021-11-29 20:04:08 UTC (rev 286251)
</span><span class="lines">@@ -125,7 +125,7 @@
</span><span class="cx">     const heir = Object.create(object);
</span><span class="cx">     Object.preventExtensions(heir);
</span><span class="cx"> 
</span><del>-    shouldThrow(() => { heir[key] = testValue; }, "TypeError: Attempted to assign to readonly property.", key);
</del><ins>+    shouldThrow(() => { heir[key] = testValue; }, "TypeError: Attempting to define property on object that is not extensible.", key);
</ins><span class="cx">     assert(heir[key] !== testValue, key);
</span><span class="cx">     assert(object[key] !== testValue, key);
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkJSTestswasmjsapitest_basic_apijs"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/wasm/js-api/test_basic_api.js (286250 => 286251)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/wasm/js-api/test_basic_api.js      2021-11-29 19:57:11 UTC (rev 286250)
+++ trunk/JSTests/wasm/js-api/test_basic_api.js 2021-11-29 20:04:08 UTC (rev 286251)
</span><span class="lines">@@ -86,7 +86,7 @@
</span><span class="cx">         assert.eq(Symbol.iterator in instance.exports, false);
</span><span class="cx">         assert.eq(Symbol.toStringTag in instance.exports, false);
</span><span class="cx">         assert.eq(Object.getOwnPropertySymbols(instance.exports).length, 0);
</span><del>-        assert.throws(() => instance.exports[Symbol.toStringTag] = 42, TypeError, `Attempted to assign to readonly property.`);
</del><ins>+        assert.throws(() => instance.exports[Symbol.toStringTag] = 42, TypeError, `Attempting to define property on object that is not extensible.`);
</ins><span class="cx">         break;
</span><span class="cx">     case "Memory":
</span><span class="cx">         new WebAssembly.Memory({initial: 20});
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (286250 => 286251)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog    2021-11-29 19:57:11 UTC (rev 286250)
+++ trunk/Source/JavaScriptCore/ChangeLog       2021-11-29 20:04:08 UTC (rev 286251)
</span><span class="lines">@@ -1,5 +1,42 @@
</span><span class="cx"> 2021-11-29  Yusuke Suzuki  <ysuzuki@apple.com>
</span><span class="cx"> 
</span><ins>+        [JSC] Public Class Field initialization is slow
+        https://bugs.webkit.org/show_bug.cgi?id=232479
+
+        Reviewed by Alexey Shvayka.
+
+        Class public field implementation did not have optimization for initializing class fields: using
+        runtime call to initialize fields instead of IC. This patch leverages put_by_id / put_by_val with
+        direct flag so that we can enable IC.
+
+        Currently, we are not changing original putDirect semantics since it is out of this patch's scope.
+        We will look into it and probably changing it in a separate patch, but not in this patch.
+
+                                                             ToT                     Patched
+
+        class-fields-classic-constructor-assignments
+                                                       17.1491+-2.6327           15.0906+-0.6795          might be 1.1364x faster
+        class-fields-public-fields                    409.4328+-8.3140     ^     20.2752+-2.0835        ^ definitely 20.1938x faster
+        class-fields-private-fields                    27.2621+-1.3858           25.1810+-3.9873          might be 1.0826x faster
+
+        * bytecompiler/NodesCodegen.cpp:
+        (JSC::DefineFieldNode::emitBytecode):
+        * runtime/CommonSlowPaths.h:
+        (JSC::CommonSlowPaths::putDirectWithReify):
+        * runtime/JSObject.cpp:
+        (JSC::JSObject::putDirectCustomAccessor):
+        (JSC::JSObject::putDirectNonIndexAccessor):
+        * runtime/JSObject.h:
+        (JSC::JSObject::putDirect):
+        (JSC::JSObject::putDirectRespectingExtensibility):
+        * runtime/JSObjectInlines.h:
+        (JSC::JSObject::putInlineFast):
+        (JSC::JSObject::putDirectInternal):
+        (JSC::JSObject::putOwnDataProperty):
+        (JSC::JSObject::putOwnDataPropertyMayBeIndex):
+
+2021-11-29  Yusuke Suzuki  <ysuzuki@apple.com>
+
</ins><span class="cx">         [JSC] private name operation should use RETURN_IF_EXCEPTION
</span><span class="cx">         https://bugs.webkit.org/show_bug.cgi?id=233577
</span><span class="cx">         rdar://85813869
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecompilerNodesCodegencpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp (286250 => 286251)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp        2021-11-29 19:57:11 UTC (rev 286250)
+++ trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp   2021-11-29 20:04:08 UTC (rev 286251)
</span><span class="lines">@@ -5039,10 +5039,12 @@
</span><span class="cx"> 
</span><span class="cx">     switch (m_type) {
</span><span class="cx">     case DefineFieldNode::Type::Name: {
</span><del>-        // FIXME: Improve performance of public class fields
-        // https://bugs.webkit.org/show_bug.cgi?id=198330
-        RefPtr<RegisterID> propertyName = generator.emitLoad(nullptr, *m_ident);
-        generator.emitCallDefineProperty(generator.thisRegister(), propertyName.get(), value.get(), nullptr, nullptr, BytecodeGenerator::PropertyConfigurable | BytecodeGenerator::PropertyWritable | BytecodeGenerator::PropertyEnumerable, m_position);
</del><ins>+        StrictModeScope strictModeScope(generator);
+        if (auto index = parseIndex(*m_ident)) {
+            RefPtr<RegisterID> propertyName = generator.emitLoad(nullptr, jsNumber(index.value()));
+            generator.emitDirectPutByVal(generator.thisRegister(), propertyName.get(), value.get());
+        } else
+            generator.emitDirectPutById(generator.thisRegister(), *m_ident, value.get());
</ins><span class="cx">         break;
</span><span class="cx">     }
</span><span class="cx">     case DefineFieldNode::Type::PrivateName: {
</span><span class="lines">@@ -5057,9 +5059,6 @@
</span><span class="cx">         break;
</span><span class="cx">     }
</span><span class="cx">     case DefineFieldNode::Type::ComputedName: {
</span><del>-        // FIXME: Improve performance of public class fields
-        // https://bugs.webkit.org/show_bug.cgi?id=198330
-
</del><span class="cx">         // For ComputedNames, the expression has already been evaluated earlier during evaluation of a ClassExprNode.
</span><span class="cx">         // Here, `m_ident` refers to private symbol ID in a class lexical scope, containing the value already converted to an Expression.
</span><span class="cx">         Variable var = generator.variable(*m_ident);
</span><span class="lines">@@ -5072,7 +5071,10 @@
</span><span class="cx">         if (shouldSetFunctionName)
</span><span class="cx">             generator.emitSetFunctionName(value.get(), privateName.get());
</span><span class="cx">         generator.emitProfileType(privateName.get(), var, m_position, m_position + m_ident->length());
</span><del>-        generator.emitCallDefineProperty(generator.thisRegister(), privateName.get(), value.get(), nullptr, nullptr, BytecodeGenerator::PropertyConfigurable | BytecodeGenerator::PropertyWritable | BytecodeGenerator::PropertyEnumerable, m_position);
</del><ins>+        {
+            StrictModeScope strictModeScope(generator);
+            generator.emitDirectPutByVal(generator.thisRegister(), privateName.get(), value.get());
+        }
</ins><span class="cx">         break;
</span><span class="cx">     }
</span><span class="cx">     }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeCommonSlowPathsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/CommonSlowPaths.h (286250 => 286251)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/CommonSlowPaths.h    2021-11-29 19:57:11 UTC (rev 286250)
+++ trunk/Source/JavaScriptCore/runtime/CommonSlowPaths.h       2021-11-29 20:04:08 UTC (rev 286251)
</span><span class="lines">@@ -35,6 +35,7 @@
</span><span class="cx"> #include "ScopedArguments.h"
</span><span class="cx"> #include "SlowPathFunction.h"
</span><span class="cx"> #include "StackAlignment.h"
</span><ins>+#include "TypeError.h"
</ins><span class="cx"> #include "VMInlines.h"
</span><span class="cx"> #include <wtf/StdLibExtras.h>
</span><span class="cx"> 
</span><span class="lines">@@ -186,18 +187,28 @@
</span><span class="cx">     return value.asCell()->structure(vm);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-
</del><span class="cx"> static ALWAYS_INLINE void putDirectWithReify(VM& vm, JSGlobalObject* globalObject, JSObject* baseObject, PropertyName propertyName, JSValue value, PutPropertySlot& slot, Structure** result = nullptr)
</span><span class="cx"> {
</span><span class="cx">     auto scope = DECLARE_THROW_SCOPE(vm);
</span><del>-    if (baseObject->inherits<JSFunction>(vm)) {
</del><ins>+    bool isJSFunction = baseObject->inherits<JSFunction>(vm);
+    if (isJSFunction) {
</ins><span class="cx">         jsCast<JSFunction*>(baseObject)->reifyLazyPropertyIfNeeded(vm, globalObject, propertyName);
</span><span class="cx">         RETURN_IF_EXCEPTION(scope, void());
</span><span class="cx">     }
</span><span class="cx">     if (result)
</span><span class="cx">         *result = originalStructureBeforePut(vm, baseObject);
</span><del>-    scope.release();
-    baseObject->putDirect(vm, propertyName, value, slot);
</del><ins>+
+    Structure* structure = baseObject->structure(vm);
+    if (LIKELY(propertyName != vm.propertyNames->underscoreProto && !structure->hasReadOnlyOrGetterSetterPropertiesExcludingProto() && (isJSFunction || structure->classInfo()->methodTable.defineOwnProperty == &JSObject::defineOwnProperty))) {
+        auto error = baseObject->putDirectRespectingExtensibility(vm, propertyName, value, 0, slot);
+        if (!error.isNull())
+            typeError(globalObject, scope, slot.isStrictMode(), error);
+    } else {
+        slot.disableCaching();
+        scope.release();
+        PropertyDescriptor descriptor(value, 0);
+        baseObject->methodTable(vm)->defineOwnProperty(baseObject, globalObject, propertyName, descriptor, slot.isStrictMode());
+    }
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> static ALWAYS_INLINE void putDirectAccessorWithReify(VM& vm, JSGlobalObject* globalObject, JSObject* baseObject, PropertyName propertyName, GetterSetter* accessor, unsigned attribute)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSObjectcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSObject.cpp (286250 => 286251)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSObject.cpp 2021-11-29 19:57:11 UTC (rev 286250)
+++ trunk/Source/JavaScriptCore/runtime/JSObject.cpp    2021-11-29 20:04:08 UTC (rev 286251)
</span><span class="lines">@@ -2006,7 +2006,7 @@
</span><span class="cx">         attributes |= PropertyAttribute::CustomValue;
</span><span class="cx"> 
</span><span class="cx">     PutPropertySlot slot(this);
</span><del>-    bool result = putDirectInternal<PutModeDefineOwnProperty>(vm, propertyName, value, attributes, slot);
</del><ins>+    bool result = putDirectInternal<PutModeDefineOwnPropertyIgnoringExtensibility>(vm, propertyName, value, attributes, slot).isNull();
</ins><span class="cx"> 
</span><span class="cx">     ASSERT(slot.type() == PutPropertySlot::NewProperty);
</span><span class="cx"> 
</span><span class="lines">@@ -2037,7 +2037,7 @@
</span><span class="cx"> {
</span><span class="cx">     ASSERT(attributes & PropertyAttribute::Accessor);
</span><span class="cx">     PutPropertySlot slot(this);
</span><del>-    bool result = putDirectInternal<PutModeDefineOwnProperty>(vm, propertyName, accessor, attributes, slot);
</del><ins>+    bool result = putDirectInternal<PutModeDefineOwnPropertyIgnoringExtensibility>(vm, propertyName, accessor, attributes, slot).isNull();
</ins><span class="cx"> 
</span><span class="cx">     Structure* structure = this->structure(vm);
</span><span class="cx">     if (attributes & PropertyAttribute::ReadOnly)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSObjecth"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSObject.h (286250 => 286251)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSObject.h   2021-11-29 19:57:11 UTC (rev 286250)
+++ trunk/Source/JavaScriptCore/runtime/JSObject.h      2021-11-29 20:04:08 UTC (rev 286251)
</span><span class="lines">@@ -100,9 +100,10 @@
</span><span class="cx">     friend class MarkedBlock;
</span><span class="cx">     JS_EXPORT_PRIVATE friend bool setUpStaticFunctionSlot(VM&, const HashTableValue*, JSObject*, PropertyName, PropertySlot&);
</span><span class="cx"> 
</span><del>-    enum PutMode {
</del><ins>+    enum PutMode : uint8_t {
</ins><span class="cx">         PutModePut,
</span><span class="cx">         PutModeDefineOwnProperty,
</span><ins>+        PutModeDefineOwnPropertyIgnoringExtensibility,
</ins><span class="cx">     };
</span><span class="cx"> 
</span><span class="cx"> public:
</span><span class="lines">@@ -685,6 +686,7 @@
</span><span class="cx">     bool putDirect(VM&, PropertyName, JSValue, unsigned attributes = 0);
</span><span class="cx">     bool putDirect(VM&, PropertyName, JSValue, unsigned attributes, PutPropertySlot&);
</span><span class="cx">     bool putDirect(VM&, PropertyName, JSValue, PutPropertySlot&);
</span><ins>+    ASCIILiteral putDirectRespectingExtensibility(VM&, PropertyName, JSValue, unsigned attributes, PutPropertySlot&);
</ins><span class="cx">     void putDirectWithoutTransition(VM&, PropertyName, JSValue, unsigned attributes = 0);
</span><span class="cx">     bool putDirectNonIndexAccessor(VM&, PropertyName, GetterSetter*, unsigned attributes);
</span><span class="cx">     void putDirectNonIndexAccessorWithoutTransition(VM&, PropertyName, GetterSetter*, unsigned attributes);
</span><span class="lines">@@ -1156,7 +1158,7 @@
</span><span class="cx">     ArrayStorage* enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(VM&, ArrayStorage*);
</span><span class="cx">         
</span><span class="cx">     template<PutMode>
</span><del>-    bool putDirectInternal(VM&, PropertyName, JSValue, unsigned attr, PutPropertySlot&);
</del><ins>+    ASCIILiteral putDirectInternal(VM&, PropertyName, JSValue, unsigned attr, PutPropertySlot&);
</ins><span class="cx"> 
</span><span class="cx">     JS_EXPORT_PRIVATE NEVER_INLINE bool putInlineSlow(JSGlobalObject*, PropertyName, JSValue, PutPropertySlot&);
</span><span class="cx">     JS_EXPORT_PRIVATE NEVER_INLINE bool putInlineFastReplacingStaticPropertyIfNeeded(JSGlobalObject*, PropertyName, JSValue, PutPropertySlot&);
</span><span class="lines">@@ -1582,7 +1584,7 @@
</span><span class="cx">     ASSERT(!value.isGetterSetter() && !(attributes & PropertyAttribute::Accessor));
</span><span class="cx">     ASSERT(!value.isCustomGetterSetter() && !(attributes & PropertyAttribute::CustomAccessorOrValue));
</span><span class="cx">     PutPropertySlot slot(this);
</span><del>-    return putDirectInternal<PutModeDefineOwnProperty>(vm, propertyName, value, attributes, slot);
</del><ins>+    return putDirectInternal<PutModeDefineOwnPropertyIgnoringExtensibility>(vm, propertyName, value, attributes, slot).isNull();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> inline bool JSObject::putDirect(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes, PutPropertySlot& slot)
</span><span class="lines">@@ -1589,7 +1591,7 @@
</span><span class="cx"> {
</span><span class="cx">     ASSERT(!value.isGetterSetter());
</span><span class="cx">     ASSERT(!value.isCustomGetterSetter());
</span><del>-    return putDirectInternal<PutModeDefineOwnProperty>(vm, propertyName, value, attributes, slot);
</del><ins>+    return putDirectInternal<PutModeDefineOwnPropertyIgnoringExtensibility>(vm, propertyName, value, attributes, slot).isNull();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> inline bool JSObject::putDirect(VM& vm, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
</span><span class="lines">@@ -1596,9 +1598,16 @@
</span><span class="cx"> {
</span><span class="cx">     ASSERT(!value.isGetterSetter());
</span><span class="cx">     ASSERT(!value.isCustomGetterSetter());
</span><del>-    return putDirectInternal<PutModeDefineOwnProperty>(vm, propertyName, value, 0, slot);
</del><ins>+    return putDirectInternal<PutModeDefineOwnPropertyIgnoringExtensibility>(vm, propertyName, value, 0, slot).isNull();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+inline ASCIILiteral JSObject::putDirectRespectingExtensibility(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes, PutPropertySlot& slot)
+{
+    ASSERT(!value.isGetterSetter());
+    ASSERT(!value.isCustomGetterSetter());
+    return putDirectInternal<PutModeDefineOwnProperty>(vm, propertyName, value, attributes, slot);
+}
+
</ins><span class="cx"> constexpr inline intptr_t offsetInButterfly(PropertyOffset offset)
</span><span class="cx"> {
</span><span class="cx">     return offsetInOutOfLineStorage(offset) + Butterfly::indexOfPropertyStorage();
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSObjectInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSObjectInlines.h (286250 => 286251)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSObjectInlines.h    2021-11-29 19:57:11 UTC (rev 286250)
+++ trunk/Source/JavaScriptCore/runtime/JSObjectInlines.h       2021-11-29 20:04:08 UTC (rev 286251)
</span><span class="lines">@@ -282,9 +282,9 @@
</span><span class="cx">     VM& vm = getVM(globalObject);
</span><span class="cx">     auto scope = DECLARE_THROW_SCOPE(vm);
</span><span class="cx"> 
</span><del>-    // FIXME: For a failure due to non-extensible structure, the error message is misleading
-    if (!putDirectInternal<PutModePut>(vm, propertyName, value, 0, slot))
-        return typeError(globalObject, scope, slot.isStrictMode(), ReadonlyPropertyWriteError);
</del><ins>+    auto error = putDirectInternal<PutModePut>(vm, propertyName, value, 0, slot);
+    if (!error.isNull())
+        return typeError(globalObject, scope, slot.isStrictMode(), error);
</ins><span class="cx">     return true;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -319,7 +319,7 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> template<JSObject::PutMode mode>
</span><del>-ALWAYS_INLINE bool JSObject::putDirectInternal(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes, PutPropertySlot& slot)
</del><ins>+ALWAYS_INLINE ASCIILiteral JSObject::putDirectInternal(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes, PutPropertySlot& slot)
</ins><span class="cx"> {
</span><span class="cx">     ASSERT(value);
</span><span class="cx">     ASSERT(value.isGetterSetter() == !!(attributes & PropertyAttribute::Accessor));
</span><span class="lines">@@ -335,8 +335,8 @@
</span><span class="cx">         unsigned currentAttributes;
</span><span class="cx">         PropertyOffset offset = structure->get(vm, propertyName, currentAttributes);
</span><span class="cx">         if (offset != invalidOffset) {
</span><del>-            if ((mode == PutModePut) && currentAttributes & PropertyAttribute::ReadOnlyOrAccessorOrCustomAccessor)
-                return false;
</del><ins>+            if ((mode == PutModePut || mode == PutModeDefineOwnProperty) && currentAttributes & PropertyAttribute::ReadOnlyOrAccessorOrCustomAccessor)
+                return ReadonlyPropertyChangeError;
</ins><span class="cx"> 
</span><span class="cx">             putDirect(vm, offset, value);
</span><span class="cx">             structure->didReplaceProperty(offset);
</span><span class="lines">@@ -343,7 +343,7 @@
</span><span class="cx"> 
</span><span class="cx">             // FIXME: Check attributes against PropertyAttribute::CustomAccessorOrValue. Changing GetterSetter should work w/o transition.
</span><span class="cx">             // https://bugs.webkit.org/show_bug.cgi?id=214342
</span><del>-            if (mode == PutModeDefineOwnProperty && (attributes != currentAttributes || (attributes & PropertyAttribute::AccessorOrCustomAccessorOrValue)))
</del><ins>+            if ((mode == PutModeDefineOwnProperty || mode == PutModeDefineOwnPropertyIgnoringExtensibility) && (attributes != currentAttributes || (attributes & PropertyAttribute::AccessorOrCustomAccessorOrValue)))
</ins><span class="cx">                 setStructure(vm, Structure::attributeChangeTransition(vm, structure, propertyName, attributes));
</span><span class="cx">             else {
</span><span class="cx">                 ASSERT(!(currentAttributes & PropertyAttribute::AccessorOrCustomAccessorOrValue));
</span><span class="lines">@@ -350,11 +350,11 @@
</span><span class="cx">                 slot.setExistingProperty(this, offset);
</span><span class="cx">             }
</span><span class="cx"> 
</span><del>-            return true;
</del><ins>+            return ASCIILiteral::null();
</ins><span class="cx">         }
</span><span class="cx"> 
</span><del>-        if ((mode == PutModePut) && !isStructureExtensible(vm))
-            return false;
</del><ins>+        if ((mode == PutModePut || mode == PutModeDefineOwnProperty) && !isStructureExtensible(vm))
+            return NonExtensibleObjectPropertyDefineError;
</ins><span class="cx"> 
</span><span class="cx">         offset = prepareToPutDirectWithoutTransition(vm, propertyName, attributes, structureID, structure);
</span><span class="cx">         validateOffset(offset);
</span><span class="lines">@@ -362,7 +362,7 @@
</span><span class="cx">         slot.setNewProperty(this, offset);
</span><span class="cx">         if (attributes & PropertyAttribute::ReadOnly)
</span><span class="cx">             this->structure(vm)->setContainsReadOnlyProperties();
</span><del>-        return true;
</del><ins>+        return ASCIILiteral::null();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     PropertyOffset offset;
</span><span class="lines">@@ -386,14 +386,14 @@
</span><span class="cx">         putDirect(vm, offset, value);
</span><span class="cx">         setStructure(vm, newStructure);
</span><span class="cx">         slot.setNewProperty(this, offset);
</span><del>-        return true;
</del><ins>+        return ASCIILiteral::null();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     unsigned currentAttributes;
</span><span class="cx">     offset = structure->get(vm, propertyName, currentAttributes);
</span><span class="cx">     if (offset != invalidOffset) {
</span><del>-        if ((mode == PutModePut) && currentAttributes & PropertyAttribute::ReadOnlyOrAccessorOrCustomAccessor)
-            return false;
</del><ins>+        if ((mode == PutModePut || mode == PutModeDefineOwnProperty) && currentAttributes & PropertyAttribute::ReadOnlyOrAccessorOrCustomAccessor)
+            return ReadonlyPropertyChangeError;
</ins><span class="cx"> 
</span><span class="cx">         structure->didReplaceProperty(offset);
</span><span class="cx">         putDirect(vm, offset, value);
</span><span class="lines">@@ -400,7 +400,7 @@
</span><span class="cx"> 
</span><span class="cx">         // FIXME: Check attributes against PropertyAttribute::CustomAccessorOrValue. Changing GetterSetter should work w/o transition.
</span><span class="cx">         // https://bugs.webkit.org/show_bug.cgi?id=214342
</span><del>-        if (mode == PutModeDefineOwnProperty && (attributes != currentAttributes || (attributes & PropertyAttribute::AccessorOrCustomAccessorOrValue))) {
</del><ins>+        if ((mode == PutModeDefineOwnProperty || mode == PutModeDefineOwnPropertyIgnoringExtensibility) && (attributes != currentAttributes || (attributes & PropertyAttribute::AccessorOrCustomAccessorOrValue))) {
</ins><span class="cx">             // We want the structure transition watchpoint to fire after this object has switched structure.
</span><span class="cx">             // This allows adaptive watchpoints to observe if the new structure is the one we want.
</span><span class="cx">             DeferredStructureTransitionWatchpointFire deferredWatchpointFire(vm, structure);
</span><span class="lines">@@ -410,11 +410,11 @@
</span><span class="cx">             slot.setExistingProperty(this, offset);
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        return true;
</del><ins>+        return ASCIILiteral::null();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    if ((mode == PutModePut) && !isStructureExtensible(vm))
-        return false;
</del><ins>+    if ((mode == PutModePut || mode == PutModeDefineOwnProperty) && !isStructureExtensible(vm))
+        return NonExtensibleObjectPropertyDefineError;
</ins><span class="cx">     
</span><span class="cx">     // We want the structure transition watchpoint to fire after this object has switched structure.
</span><span class="cx">     // This allows adaptive watchpoints to observe if the new structure is the one we want.
</span><span class="lines">@@ -439,7 +439,7 @@
</span><span class="cx">     slot.setNewProperty(this, offset);
</span><span class="cx">     if (attributes & PropertyAttribute::ReadOnly)
</span><span class="cx">         newStructure->setContainsReadOnlyProperties();
</span><del>-    return true;
</del><ins>+    return ASCIILiteral::null();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> inline bool JSObject::mayBePrototype() const
</span><span class="lines">@@ -573,7 +573,7 @@
</span><span class="cx"> inline bool JSObject::putOwnDataProperty(VM& vm, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
</span><span class="cx"> {
</span><span class="cx">     validatePutOwnDataProperty(vm, propertyName, value);
</span><del>-    return putDirectInternal<PutModePut>(vm, propertyName, value, 0, slot);
</del><ins>+    return putDirectInternal<PutModePut>(vm, propertyName, value, 0, slot).isNull();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> inline bool JSObject::putOwnDataPropertyMayBeIndex(JSGlobalObject* globalObject, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
</span><span class="lines">@@ -583,7 +583,7 @@
</span><span class="cx">     if (std::optional<uint32_t> index = parseIndex(propertyName))
</span><span class="cx">         return putDirectIndex(globalObject, index.value(), value, 0, PutDirectIndexLikePutDirect);
</span><span class="cx"> 
</span><del>-    return putDirectInternal<PutModePut>(vm, propertyName, value, 0, slot);
</del><ins>+    return putDirectInternal<PutModePut>(vm, propertyName, value, 0, slot).isNull();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> ALWAYS_INLINE CallData getCallData(VM& vm, JSCell* cell)
</span></span></pre></div>
<a id="trunkSourceWTFChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/ChangeLog (286250 => 286251)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/ChangeLog       2021-11-29 19:57:11 UTC (rev 286250)
+++ trunk/Source/WTF/ChangeLog  2021-11-29 20:04:08 UTC (rev 286251)
</span><span class="lines">@@ -1,5 +1,14 @@
</span><span class="cx"> 2021-11-29  Yusuke Suzuki  <ysuzuki@apple.com>
</span><span class="cx"> 
</span><ins>+        [JSC] Public Class Field initialization is slow
+        https://bugs.webkit.org/show_bug.cgi?id=232479
+
+        Reviewed by Alexey Shvayka.
+
+        * wtf/text/ASCIILiteral.h:
+
+2021-11-29  Yusuke Suzuki  <ysuzuki@apple.com>
+
</ins><span class="cx">         [JSC] Move m_incomingPolymorphicCalls out of CodeBlock::JITData
</span><span class="cx">         https://bugs.webkit.org/show_bug.cgi?id=233415
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWTFwtftextASCIILiteralh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/text/ASCIILiteral.h (286250 => 286251)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/text/ASCIILiteral.h 2021-11-29 19:57:11 UTC (rev 286250)
+++ trunk/Source/WTF/wtf/text/ASCIILiteral.h    2021-11-29 20:04:08 UTC (rev 286251)
</span><span class="lines">@@ -49,6 +49,8 @@
</span><span class="cx">         return ASCIILiteral { nullptr };
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    constexpr bool isNull() const { return !m_characters; }
+
</ins><span class="cx">     constexpr const char* characters() const { return m_characters; }
</span><span class="cx">     const LChar* characters8() const { return bitwise_cast<const LChar*>(m_characters); }
</span><span class="cx">     size_t length() const { return strlen(m_characters); }
</span></span></pre>
</div>
</div>

</body>
</html>