<!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>[282943] branches/safari-612-branch</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/282943">282943</a></dd>
<dt>Author</dt> <dd>repstein@apple.com</dd>
<dt>Date</dt> <dd>2021-09-22 22:14:29 -0700 (Wed, 22 Sep 2021)</dd>
</dl>

<h3>Log Message</h3>
<pre>Cherry-pick <a href="http://trac.webkit.org/projects/webkit/changeset/282707">r282707</a>. rdar://problem/83429953

    [JSC] Add fast property enumeration mode for JSON.stringify
    https://bugs.webkit.org/show_bug.cgi?id=230393

    Reviewed by Mark Lam.

    JSTests:

    * stress/json-stringify-object-modify.js: Added.
    (shouldBe):
    (throw.new.Error.let.object.hello.get inner):
    (throw.new.Error):
    (shouldBe.let.object.hello.get inner):

    Source/JavaScriptCore:

    We collected profiles and found several subtests are using JSON.stringify enough. And generated strings are many serialized leaf objects.

    This patch adds fast object property enumeration. When we know that source object meets some conditions, we can say that,
    as long as structure is not changed, we can continue using property names and offset collected from the structure.
    This way removes non observable [[Get]] operations to accelerate JSON.stringify performance for major object iteration cases.

    We also extend MarkedArgumentBuffer: introducing MarkedArgumentBufferWithSize which can take default inline capacity as a template
    parameter. This is used in JSON.stringify to increase the buffer because now we also need to record structures in MarkedArgumentBuffer.

    This offers 0.4% improvement in Speedometer2 (EmberJS-TodoMVC, Vanilla-XXX, EmberJS-Debug-TodoMVC, they have enough amount of JSON.stringify
    time).

    ----------------------------------------------------------------------------------------------------------------------------------
    |               subtest                |     ms      |     ms      |  b / a   | pValue (significance using False Discovery Rate) |
    ----------------------------------------------------------------------------------------------------------------------------------
    | Elm-TodoMVC                          |117.710000   |117.751667   |1.000354  | 0.883246                                         |
    | VueJS-TodoMVC                        |24.500000    |24.311667    |0.992313  | 0.365130                                         |
    | EmberJS-TodoMVC                      |126.646667   |125.738333   |0.992828  | 0.002587 (significant)                           |
    | BackboneJS-TodoMVC                   |47.873333    |47.911667    |1.000801  | 0.762509                                         |
    | Preact-TodoMVC                       |17.020000    |17.070000    |1.002938  | 0.786799                                         |
    | AngularJS-TodoMVC                    |129.856667   |129.353333   |0.996124  | 0.177632                                         |
    | Vanilla-ES2015-TodoMVC               |61.698333    |61.120000    |0.990626  | 0.000003 (significant)                           |
    | Inferno-TodoMVC                      |62.840000    |62.496667    |0.994536  | 0.312340                                         |
    | Flight-TodoMVC                       |77.095000    |76.936667    |0.997946  | 0.702724                                         |
    | Angular2-TypeScript-TodoMVC          |39.740000    |39.191667    |0.986202  | 0.053485                                         |
    | VanillaJS-TodoMVC                    |49.008333    |48.346667    |0.986499  | 0.000638 (significant)                           |
    | jQuery-TodoMVC                       |216.785000   |217.188333   |1.001861  | 0.270747                                         |
    | EmberJS-Debug-TodoMVC                |344.230000   |342.993333   |0.996407  | 0.012262 (significant)                           |
    | React-TodoMVC                        |85.461667    |85.411667    |0.999415  | 0.758049                                         |
    | React-Redux-TodoMVC                  |140.681667   |140.640000   |0.999704  | 0.871277                                         |
    | Vanilla-ES2015-Babel-Webpack-TodoMVC |59.928333    |59.351667    |0.990377  | 0.000000 (significant)                           |
    ----------------------------------------------------------------------------------------------------------------------------------
    a mean = 264.40650
    b mean = 265.51533
    pValue = 0.0005567357
    (Bigger means are better.)
    1.004 times better
    Results ARE significant

    * heap/Heap.cpp:
    (JSC::Heap::addCoreConstraints):
    * heap/Heap.h:
    * heap/HeapInlines.h:
    * runtime/ArgList.cpp:
    (JSC::MarkedArgumentBufferBase::addMarkSet):
    (JSC::MarkedArgumentBufferBase::markLists):
    (JSC::MarkedArgumentBufferBase::slowEnsureCapacity):
    (JSC::MarkedArgumentBufferBase::expandCapacity):
    (JSC::MarkedArgumentBufferBase::slowAppend):
    (JSC::MarkedArgumentBuffer::addMarkSet): Deleted.
    (JSC::MarkedArgumentBuffer::markLists): Deleted.
    (JSC::MarkedArgumentBuffer::slowEnsureCapacity): Deleted.
    (JSC::MarkedArgumentBuffer::expandCapacity): Deleted.
    (JSC::MarkedArgumentBuffer::slowAppend): Deleted.
    * runtime/ArgList.h:
    (JSC::MarkedArgumentBufferWithSize::MarkedArgumentBufferWithSize):
    (JSC::MarkedArgumentBuffer::MarkedArgumentBuffer): Deleted.
    (JSC::MarkedArgumentBuffer::~MarkedArgumentBuffer): Deleted.
    (JSC::MarkedArgumentBuffer::size const): Deleted.
    (JSC::MarkedArgumentBuffer::isEmpty const): Deleted.
    (JSC::MarkedArgumentBuffer::at const): Deleted.
    (JSC::MarkedArgumentBuffer::clear): Deleted.
    (JSC::MarkedArgumentBuffer::appendWithAction): Deleted.
    (JSC::MarkedArgumentBuffer::append): Deleted.
    (JSC::MarkedArgumentBuffer::appendWithCrashOnOverflow): Deleted.
    (JSC::MarkedArgumentBuffer::removeLast): Deleted.
    (JSC::MarkedArgumentBuffer::last): Deleted.
    (JSC::MarkedArgumentBuffer::takeLast): Deleted.
    (JSC::MarkedArgumentBuffer::ensureCapacity): Deleted.
    (JSC::MarkedArgumentBuffer::hasOverflowed): Deleted.
    (JSC::MarkedArgumentBuffer::overflowCheckNotNeeded): Deleted.
    (JSC::MarkedArgumentBuffer::fill): Deleted.
    (JSC::MarkedArgumentBuffer::slotFor const): Deleted.
    (JSC::MarkedArgumentBuffer::mallocBase): Deleted.
    (JSC::MarkedArgumentBuffer::setNeedsOverflowCheck): Deleted.
    (JSC::MarkedArgumentBuffer::clearNeedsOverflowCheck): Deleted.
    * runtime/JSONObject.cpp:
    (JSC::Stringifier::Holder::hasFastObjectProperties const):
    (JSC::Stringifier::appendStringifiedValue):
    (JSC::Stringifier::Holder::Holder):
    (JSC::Stringifier::Holder::appendNextProperty):
    * runtime/ObjectConstructorInlines.h:
    (JSC::canPerformFastPropertyEnumerationForJSONStringify):

    Source/WebCore:

    * Modules/webaudio/AudioWorkletProcessor.cpp:
    (WebCore::AudioWorkletProcessor::buildJSArguments):
    * Modules/webaudio/AudioWorkletProcessor.h:

    Source/WebKitLegacy/mac:

    * Plugins/Hosted/NetscapePluginInstanceProxy.h:
    * Plugins/Hosted/NetscapePluginInstanceProxy.mm:
    (WebKit::NetscapePluginInstanceProxy::demarshalValues):

    git-svn-id: https://svn.webkit.org/repository/webkit/trunk@282707 268f45cc-cd09-0410-ab3c-d52691b4dbfc</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#branchessafari612branchJSTestsChangeLog">branches/safari-612-branch/JSTests/ChangeLog</a></li>
<li><a href="#branchessafari612branchSourceJavaScriptCoreChangeLog">branches/safari-612-branch/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#branchessafari612branchSourceJavaScriptCoreheapHeapcpp">branches/safari-612-branch/Source/JavaScriptCore/heap/Heap.cpp</a></li>
<li><a href="#branchessafari612branchSourceJavaScriptCoreheapHeaph">branches/safari-612-branch/Source/JavaScriptCore/heap/Heap.h</a></li>
<li><a href="#branchessafari612branchSourceJavaScriptCoreheapHeapInlinesh">branches/safari-612-branch/Source/JavaScriptCore/heap/HeapInlines.h</a></li>
<li><a href="#branchessafari612branchSourceJavaScriptCoreruntimeArgListcpp">branches/safari-612-branch/Source/JavaScriptCore/runtime/ArgList.cpp</a></li>
<li><a href="#branchessafari612branchSourceJavaScriptCoreruntimeArgListh">branches/safari-612-branch/Source/JavaScriptCore/runtime/ArgList.h</a></li>
<li><a href="#branchessafari612branchSourceJavaScriptCoreruntimeJSONObjectcpp">branches/safari-612-branch/Source/JavaScriptCore/runtime/JSONObject.cpp</a></li>
<li><a href="#branchessafari612branchSourceJavaScriptCoreruntimeObjectConstructorInlinesh">branches/safari-612-branch/Source/JavaScriptCore/runtime/ObjectConstructorInlines.h</a></li>
<li><a href="#branchessafari612branchSourceWebCoreChangeLog">branches/safari-612-branch/Source/WebCore/ChangeLog</a></li>
<li><a href="#branchessafari612branchSourceWebCoreModuleswebaudioAudioWorkletProcessorcpp">branches/safari-612-branch/Source/WebCore/Modules/webaudio/AudioWorkletProcessor.cpp</a></li>
<li><a href="#branchessafari612branchSourceWebCoreModuleswebaudioAudioWorkletProcessorh">branches/safari-612-branch/Source/WebCore/Modules/webaudio/AudioWorkletProcessor.h</a></li>
<li><a href="#branchessafari612branchSourceWebKitLegacymacChangeLog">branches/safari-612-branch/Source/WebKitLegacy/mac/ChangeLog</a></li>
<li><a href="#branchessafari612branchSourceWebKitLegacymacPluginsHostedNetscapePluginInstanceProxyh">branches/safari-612-branch/Source/WebKitLegacy/mac/Plugins/Hosted/NetscapePluginInstanceProxy.h</a></li>
<li><a href="#branchessafari612branchSourceWebKitLegacymacPluginsHostedNetscapePluginInstanceProxymm">branches/safari-612-branch/Source/WebKitLegacy/mac/Plugins/Hosted/NetscapePluginInstanceProxy.mm</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#branchessafari612branchJSTestsstressjsonstringifyobjectmodifyjs">branches/safari-612-branch/JSTests/stress/json-stringify-object-modify.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="branchessafari612branchJSTestsChangeLog"></a>
<div class="modfile"><h4>Modified: branches/safari-612-branch/JSTests/ChangeLog (282942 => 282943)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-612-branch/JSTests/ChangeLog     2021-09-23 05:14:23 UTC (rev 282942)
+++ branches/safari-612-branch/JSTests/ChangeLog        2021-09-23 05:14:29 UTC (rev 282943)
</span><span class="lines">@@ -1,3 +1,133 @@
</span><ins>+2021-09-22  Alan Coon  <alancoon@apple.com>
+
+        Cherry-pick r282707. rdar://problem/83429953
+
+    [JSC] Add fast property enumeration mode for JSON.stringify
+    https://bugs.webkit.org/show_bug.cgi?id=230393
+    
+    Reviewed by Mark Lam.
+    
+    JSTests:
+    
+    * stress/json-stringify-object-modify.js: Added.
+    (shouldBe):
+    (throw.new.Error.let.object.hello.get inner):
+    (throw.new.Error):
+    (shouldBe.let.object.hello.get inner):
+    
+    Source/JavaScriptCore:
+    
+    We collected profiles and found several subtests are using JSON.stringify enough. And generated strings are many serialized leaf objects.
+    
+    This patch adds fast object property enumeration. When we know that source object meets some conditions, we can say that,
+    as long as structure is not changed, we can continue using property names and offset collected from the structure.
+    This way removes non observable [[Get]] operations to accelerate JSON.stringify performance for major object iteration cases.
+    
+    We also extend MarkedArgumentBuffer: introducing MarkedArgumentBufferWithSize which can take default inline capacity as a template
+    parameter. This is used in JSON.stringify to increase the buffer because now we also need to record structures in MarkedArgumentBuffer.
+    
+    This offers 0.4% improvement in Speedometer2 (EmberJS-TodoMVC, Vanilla-XXX, EmberJS-Debug-TodoMVC, they have enough amount of JSON.stringify
+    time).
+    
+    ----------------------------------------------------------------------------------------------------------------------------------
+    |               subtest                |     ms      |     ms      |  b / a   | pValue (significance using False Discovery Rate) |
+    ----------------------------------------------------------------------------------------------------------------------------------
+    | Elm-TodoMVC                          |117.710000   |117.751667   |1.000354  | 0.883246                                         |
+    | VueJS-TodoMVC                        |24.500000    |24.311667    |0.992313  | 0.365130                                         |
+    | EmberJS-TodoMVC                      |126.646667   |125.738333   |0.992828  | 0.002587 (significant)                           |
+    | BackboneJS-TodoMVC                   |47.873333    |47.911667    |1.000801  | 0.762509                                         |
+    | Preact-TodoMVC                       |17.020000    |17.070000    |1.002938  | 0.786799                                         |
+    | AngularJS-TodoMVC                    |129.856667   |129.353333   |0.996124  | 0.177632                                         |
+    | Vanilla-ES2015-TodoMVC               |61.698333    |61.120000    |0.990626  | 0.000003 (significant)                           |
+    | Inferno-TodoMVC                      |62.840000    |62.496667    |0.994536  | 0.312340                                         |
+    | Flight-TodoMVC                       |77.095000    |76.936667    |0.997946  | 0.702724                                         |
+    | Angular2-TypeScript-TodoMVC          |39.740000    |39.191667    |0.986202  | 0.053485                                         |
+    | VanillaJS-TodoMVC                    |49.008333    |48.346667    |0.986499  | 0.000638 (significant)                           |
+    | jQuery-TodoMVC                       |216.785000   |217.188333   |1.001861  | 0.270747                                         |
+    | EmberJS-Debug-TodoMVC                |344.230000   |342.993333   |0.996407  | 0.012262 (significant)                           |
+    | React-TodoMVC                        |85.461667    |85.411667    |0.999415  | 0.758049                                         |
+    | React-Redux-TodoMVC                  |140.681667   |140.640000   |0.999704  | 0.871277                                         |
+    | Vanilla-ES2015-Babel-Webpack-TodoMVC |59.928333    |59.351667    |0.990377  | 0.000000 (significant)                           |
+    ----------------------------------------------------------------------------------------------------------------------------------
+    a mean = 264.40650
+    b mean = 265.51533
+    pValue = 0.0005567357
+    (Bigger means are better.)
+    1.004 times better
+    Results ARE significant
+    
+    * heap/Heap.cpp:
+    (JSC::Heap::addCoreConstraints):
+    * heap/Heap.h:
+    * heap/HeapInlines.h:
+    * runtime/ArgList.cpp:
+    (JSC::MarkedArgumentBufferBase::addMarkSet):
+    (JSC::MarkedArgumentBufferBase::markLists):
+    (JSC::MarkedArgumentBufferBase::slowEnsureCapacity):
+    (JSC::MarkedArgumentBufferBase::expandCapacity):
+    (JSC::MarkedArgumentBufferBase::slowAppend):
+    (JSC::MarkedArgumentBuffer::addMarkSet): Deleted.
+    (JSC::MarkedArgumentBuffer::markLists): Deleted.
+    (JSC::MarkedArgumentBuffer::slowEnsureCapacity): Deleted.
+    (JSC::MarkedArgumentBuffer::expandCapacity): Deleted.
+    (JSC::MarkedArgumentBuffer::slowAppend): Deleted.
+    * runtime/ArgList.h:
+    (JSC::MarkedArgumentBufferWithSize::MarkedArgumentBufferWithSize):
+    (JSC::MarkedArgumentBuffer::MarkedArgumentBuffer): Deleted.
+    (JSC::MarkedArgumentBuffer::~MarkedArgumentBuffer): Deleted.
+    (JSC::MarkedArgumentBuffer::size const): Deleted.
+    (JSC::MarkedArgumentBuffer::isEmpty const): Deleted.
+    (JSC::MarkedArgumentBuffer::at const): Deleted.
+    (JSC::MarkedArgumentBuffer::clear): Deleted.
+    (JSC::MarkedArgumentBuffer::appendWithAction): Deleted.
+    (JSC::MarkedArgumentBuffer::append): Deleted.
+    (JSC::MarkedArgumentBuffer::appendWithCrashOnOverflow): Deleted.
+    (JSC::MarkedArgumentBuffer::removeLast): Deleted.
+    (JSC::MarkedArgumentBuffer::last): Deleted.
+    (JSC::MarkedArgumentBuffer::takeLast): Deleted.
+    (JSC::MarkedArgumentBuffer::ensureCapacity): Deleted.
+    (JSC::MarkedArgumentBuffer::hasOverflowed): Deleted.
+    (JSC::MarkedArgumentBuffer::overflowCheckNotNeeded): Deleted.
+    (JSC::MarkedArgumentBuffer::fill): Deleted.
+    (JSC::MarkedArgumentBuffer::slotFor const): Deleted.
+    (JSC::MarkedArgumentBuffer::mallocBase): Deleted.
+    (JSC::MarkedArgumentBuffer::setNeedsOverflowCheck): Deleted.
+    (JSC::MarkedArgumentBuffer::clearNeedsOverflowCheck): Deleted.
+    * runtime/JSONObject.cpp:
+    (JSC::Stringifier::Holder::hasFastObjectProperties const):
+    (JSC::Stringifier::appendStringifiedValue):
+    (JSC::Stringifier::Holder::Holder):
+    (JSC::Stringifier::Holder::appendNextProperty):
+    * runtime/ObjectConstructorInlines.h:
+    (JSC::canPerformFastPropertyEnumerationForJSONStringify):
+    
+    Source/WebCore:
+    
+    * Modules/webaudio/AudioWorkletProcessor.cpp:
+    (WebCore::AudioWorkletProcessor::buildJSArguments):
+    * Modules/webaudio/AudioWorkletProcessor.h:
+    
+    Source/WebKitLegacy/mac:
+    
+    * Plugins/Hosted/NetscapePluginInstanceProxy.h:
+    * Plugins/Hosted/NetscapePluginInstanceProxy.mm:
+    (WebKit::NetscapePluginInstanceProxy::demarshalValues):
+    
+    git-svn-id: https://svn.webkit.org/repository/webkit/trunk@282707 268f45cc-cd09-0410-ab3c-d52691b4dbfc
+
+    2021-09-17  Yusuke Suzuki  <ysuzuki@apple.com>
+
+            [JSC] Add fast property enumeration mode for JSON.stringify
+            https://bugs.webkit.org/show_bug.cgi?id=230393
+
+            Reviewed by Mark Lam.
+
+            * stress/json-stringify-object-modify.js: Added.
+            (shouldBe):
+            (throw.new.Error.let.object.hello.get inner):
+            (throw.new.Error):
+            (shouldBe.let.object.hello.get inner):
+
</ins><span class="cx"> 2021-09-16  Russell Epstein  <repstein@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Cherry-pick r282239. rdar://problem/83183776
</span></span></pre></div>
<a id="branchessafari612branchJSTestsstressjsonstringifyobjectmodifyjs"></a>
<div class="addfile"><h4>Added: branches/safari-612-branch/JSTests/stress/json-stringify-object-modify.js (0 => 282943)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-612-branch/JSTests/stress/json-stringify-object-modify.js                                (rev 0)
+++ branches/safari-612-branch/JSTests/stress/json-stringify-object-modify.js   2021-09-23 05:14:29 UTC (rev 282943)
</span><span class="lines">@@ -0,0 +1,35 @@
</span><ins>+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+{
+    let object = {
+        hello: {
+            get inner() {
+                $vm.toUncacheableDictionary(object);
+                object.world = 0;
+                return 33;
+            }
+        },
+        world: 42,
+        test: null,
+    };
+
+    shouldBe(JSON.stringify(object), `{"hello":{"inner":33},"world":0,"test":null}`);
+}
+{
+    let object = {
+        hello: {
+            get inner() {
+                delete object.world;
+                object.testing = 33;
+                return 33;
+            }
+        },
+        world: 42,
+        test: null,
+    };
+
+    shouldBe(JSON.stringify(object), `{"hello":{"inner":33},"test":null}`);
+}
</ins></span></pre></div>
<a id="branchessafari612branchSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: branches/safari-612-branch/Source/JavaScriptCore/ChangeLog (282942 => 282943)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-612-branch/Source/JavaScriptCore/ChangeLog       2021-09-23 05:14:23 UTC (rev 282942)
+++ branches/safari-612-branch/Source/JavaScriptCore/ChangeLog  2021-09-23 05:14:29 UTC (rev 282943)
</span><span class="lines">@@ -1,5 +1,213 @@
</span><span class="cx"> 2021-09-22  Alan Coon  <alancoon@apple.com>
</span><span class="cx"> 
</span><ins>+        Cherry-pick r282707. rdar://problem/83429953
+
+    [JSC] Add fast property enumeration mode for JSON.stringify
+    https://bugs.webkit.org/show_bug.cgi?id=230393
+    
+    Reviewed by Mark Lam.
+    
+    JSTests:
+    
+    * stress/json-stringify-object-modify.js: Added.
+    (shouldBe):
+    (throw.new.Error.let.object.hello.get inner):
+    (throw.new.Error):
+    (shouldBe.let.object.hello.get inner):
+    
+    Source/JavaScriptCore:
+    
+    We collected profiles and found several subtests are using JSON.stringify enough. And generated strings are many serialized leaf objects.
+    
+    This patch adds fast object property enumeration. When we know that source object meets some conditions, we can say that,
+    as long as structure is not changed, we can continue using property names and offset collected from the structure.
+    This way removes non observable [[Get]] operations to accelerate JSON.stringify performance for major object iteration cases.
+    
+    We also extend MarkedArgumentBuffer: introducing MarkedArgumentBufferWithSize which can take default inline capacity as a template
+    parameter. This is used in JSON.stringify to increase the buffer because now we also need to record structures in MarkedArgumentBuffer.
+    
+    This offers 0.4% improvement in Speedometer2 (EmberJS-TodoMVC, Vanilla-XXX, EmberJS-Debug-TodoMVC, they have enough amount of JSON.stringify
+    time).
+    
+    ----------------------------------------------------------------------------------------------------------------------------------
+    |               subtest                |     ms      |     ms      |  b / a   | pValue (significance using False Discovery Rate) |
+    ----------------------------------------------------------------------------------------------------------------------------------
+    | Elm-TodoMVC                          |117.710000   |117.751667   |1.000354  | 0.883246                                         |
+    | VueJS-TodoMVC                        |24.500000    |24.311667    |0.992313  | 0.365130                                         |
+    | EmberJS-TodoMVC                      |126.646667   |125.738333   |0.992828  | 0.002587 (significant)                           |
+    | BackboneJS-TodoMVC                   |47.873333    |47.911667    |1.000801  | 0.762509                                         |
+    | Preact-TodoMVC                       |17.020000    |17.070000    |1.002938  | 0.786799                                         |
+    | AngularJS-TodoMVC                    |129.856667   |129.353333   |0.996124  | 0.177632                                         |
+    | Vanilla-ES2015-TodoMVC               |61.698333    |61.120000    |0.990626  | 0.000003 (significant)                           |
+    | Inferno-TodoMVC                      |62.840000    |62.496667    |0.994536  | 0.312340                                         |
+    | Flight-TodoMVC                       |77.095000    |76.936667    |0.997946  | 0.702724                                         |
+    | Angular2-TypeScript-TodoMVC          |39.740000    |39.191667    |0.986202  | 0.053485                                         |
+    | VanillaJS-TodoMVC                    |49.008333    |48.346667    |0.986499  | 0.000638 (significant)                           |
+    | jQuery-TodoMVC                       |216.785000   |217.188333   |1.001861  | 0.270747                                         |
+    | EmberJS-Debug-TodoMVC                |344.230000   |342.993333   |0.996407  | 0.012262 (significant)                           |
+    | React-TodoMVC                        |85.461667    |85.411667    |0.999415  | 0.758049                                         |
+    | React-Redux-TodoMVC                  |140.681667   |140.640000   |0.999704  | 0.871277                                         |
+    | Vanilla-ES2015-Babel-Webpack-TodoMVC |59.928333    |59.351667    |0.990377  | 0.000000 (significant)                           |
+    ----------------------------------------------------------------------------------------------------------------------------------
+    a mean = 264.40650
+    b mean = 265.51533
+    pValue = 0.0005567357
+    (Bigger means are better.)
+    1.004 times better
+    Results ARE significant
+    
+    * heap/Heap.cpp:
+    (JSC::Heap::addCoreConstraints):
+    * heap/Heap.h:
+    * heap/HeapInlines.h:
+    * runtime/ArgList.cpp:
+    (JSC::MarkedArgumentBufferBase::addMarkSet):
+    (JSC::MarkedArgumentBufferBase::markLists):
+    (JSC::MarkedArgumentBufferBase::slowEnsureCapacity):
+    (JSC::MarkedArgumentBufferBase::expandCapacity):
+    (JSC::MarkedArgumentBufferBase::slowAppend):
+    (JSC::MarkedArgumentBuffer::addMarkSet): Deleted.
+    (JSC::MarkedArgumentBuffer::markLists): Deleted.
+    (JSC::MarkedArgumentBuffer::slowEnsureCapacity): Deleted.
+    (JSC::MarkedArgumentBuffer::expandCapacity): Deleted.
+    (JSC::MarkedArgumentBuffer::slowAppend): Deleted.
+    * runtime/ArgList.h:
+    (JSC::MarkedArgumentBufferWithSize::MarkedArgumentBufferWithSize):
+    (JSC::MarkedArgumentBuffer::MarkedArgumentBuffer): Deleted.
+    (JSC::MarkedArgumentBuffer::~MarkedArgumentBuffer): Deleted.
+    (JSC::MarkedArgumentBuffer::size const): Deleted.
+    (JSC::MarkedArgumentBuffer::isEmpty const): Deleted.
+    (JSC::MarkedArgumentBuffer::at const): Deleted.
+    (JSC::MarkedArgumentBuffer::clear): Deleted.
+    (JSC::MarkedArgumentBuffer::appendWithAction): Deleted.
+    (JSC::MarkedArgumentBuffer::append): Deleted.
+    (JSC::MarkedArgumentBuffer::appendWithCrashOnOverflow): Deleted.
+    (JSC::MarkedArgumentBuffer::removeLast): Deleted.
+    (JSC::MarkedArgumentBuffer::last): Deleted.
+    (JSC::MarkedArgumentBuffer::takeLast): Deleted.
+    (JSC::MarkedArgumentBuffer::ensureCapacity): Deleted.
+    (JSC::MarkedArgumentBuffer::hasOverflowed): Deleted.
+    (JSC::MarkedArgumentBuffer::overflowCheckNotNeeded): Deleted.
+    (JSC::MarkedArgumentBuffer::fill): Deleted.
+    (JSC::MarkedArgumentBuffer::slotFor const): Deleted.
+    (JSC::MarkedArgumentBuffer::mallocBase): Deleted.
+    (JSC::MarkedArgumentBuffer::setNeedsOverflowCheck): Deleted.
+    (JSC::MarkedArgumentBuffer::clearNeedsOverflowCheck): Deleted.
+    * runtime/JSONObject.cpp:
+    (JSC::Stringifier::Holder::hasFastObjectProperties const):
+    (JSC::Stringifier::appendStringifiedValue):
+    (JSC::Stringifier::Holder::Holder):
+    (JSC::Stringifier::Holder::appendNextProperty):
+    * runtime/ObjectConstructorInlines.h:
+    (JSC::canPerformFastPropertyEnumerationForJSONStringify):
+    
+    Source/WebCore:
+    
+    * Modules/webaudio/AudioWorkletProcessor.cpp:
+    (WebCore::AudioWorkletProcessor::buildJSArguments):
+    * Modules/webaudio/AudioWorkletProcessor.h:
+    
+    Source/WebKitLegacy/mac:
+    
+    * Plugins/Hosted/NetscapePluginInstanceProxy.h:
+    * Plugins/Hosted/NetscapePluginInstanceProxy.mm:
+    (WebKit::NetscapePluginInstanceProxy::demarshalValues):
+    
+    git-svn-id: https://svn.webkit.org/repository/webkit/trunk@282707 268f45cc-cd09-0410-ab3c-d52691b4dbfc
+
+    2021-09-17  Yusuke Suzuki  <ysuzuki@apple.com>
+
+            [JSC] Add fast property enumeration mode for JSON.stringify
+            https://bugs.webkit.org/show_bug.cgi?id=230393
+
+            Reviewed by Mark Lam.
+
+            We collected profiles and found several subtests are using JSON.stringify enough. And generated strings are many serialized leaf objects.
+
+            This patch adds fast object property enumeration. When we know that source object meets some conditions, we can say that,
+            as long as structure is not changed, we can continue using property names and offset collected from the structure.
+            This way removes non observable [[Get]] operations to accelerate JSON.stringify performance for major object iteration cases.
+
+            We also extend MarkedArgumentBuffer: introducing MarkedArgumentBufferWithSize which can take default inline capacity as a template
+            parameter. This is used in JSON.stringify to increase the buffer because now we also need to record structures in MarkedArgumentBuffer.
+
+            This offers 0.4% improvement in Speedometer2 (EmberJS-TodoMVC, Vanilla-XXX, EmberJS-Debug-TodoMVC, they have enough amount of JSON.stringify
+            time).
+
+            ----------------------------------------------------------------------------------------------------------------------------------
+            |               subtest                |     ms      |     ms      |  b / a   | pValue (significance using False Discovery Rate) |
+            ----------------------------------------------------------------------------------------------------------------------------------
+            | Elm-TodoMVC                          |117.710000   |117.751667   |1.000354  | 0.883246                                         |
+            | VueJS-TodoMVC                        |24.500000    |24.311667    |0.992313  | 0.365130                                         |
+            | EmberJS-TodoMVC                      |126.646667   |125.738333   |0.992828  | 0.002587 (significant)                           |
+            | BackboneJS-TodoMVC                   |47.873333    |47.911667    |1.000801  | 0.762509                                         |
+            | Preact-TodoMVC                       |17.020000    |17.070000    |1.002938  | 0.786799                                         |
+            | AngularJS-TodoMVC                    |129.856667   |129.353333   |0.996124  | 0.177632                                         |
+            | Vanilla-ES2015-TodoMVC               |61.698333    |61.120000    |0.990626  | 0.000003 (significant)                           |
+            | Inferno-TodoMVC                      |62.840000    |62.496667    |0.994536  | 0.312340                                         |
+            | Flight-TodoMVC                       |77.095000    |76.936667    |0.997946  | 0.702724                                         |
+            | Angular2-TypeScript-TodoMVC          |39.740000    |39.191667    |0.986202  | 0.053485                                         |
+            | VanillaJS-TodoMVC                    |49.008333    |48.346667    |0.986499  | 0.000638 (significant)                           |
+            | jQuery-TodoMVC                       |216.785000   |217.188333   |1.001861  | 0.270747                                         |
+            | EmberJS-Debug-TodoMVC                |344.230000   |342.993333   |0.996407  | 0.012262 (significant)                           |
+            | React-TodoMVC                        |85.461667    |85.411667    |0.999415  | 0.758049                                         |
+            | React-Redux-TodoMVC                  |140.681667   |140.640000   |0.999704  | 0.871277                                         |
+            | Vanilla-ES2015-Babel-Webpack-TodoMVC |59.928333    |59.351667    |0.990377  | 0.000000 (significant)                           |
+            ----------------------------------------------------------------------------------------------------------------------------------
+            a mean = 264.40650
+            b mean = 265.51533
+            pValue = 0.0005567357
+            (Bigger means are better.)
+            1.004 times better
+            Results ARE significant
+
+            * heap/Heap.cpp:
+            (JSC::Heap::addCoreConstraints):
+            * heap/Heap.h:
+            * heap/HeapInlines.h:
+            * runtime/ArgList.cpp:
+            (JSC::MarkedArgumentBufferBase::addMarkSet):
+            (JSC::MarkedArgumentBufferBase::markLists):
+            (JSC::MarkedArgumentBufferBase::slowEnsureCapacity):
+            (JSC::MarkedArgumentBufferBase::expandCapacity):
+            (JSC::MarkedArgumentBufferBase::slowAppend):
+            (JSC::MarkedArgumentBuffer::addMarkSet): Deleted.
+            (JSC::MarkedArgumentBuffer::markLists): Deleted.
+            (JSC::MarkedArgumentBuffer::slowEnsureCapacity): Deleted.
+            (JSC::MarkedArgumentBuffer::expandCapacity): Deleted.
+            (JSC::MarkedArgumentBuffer::slowAppend): Deleted.
+            * runtime/ArgList.h:
+            (JSC::MarkedArgumentBufferWithSize::MarkedArgumentBufferWithSize):
+            (JSC::MarkedArgumentBuffer::MarkedArgumentBuffer): Deleted.
+            (JSC::MarkedArgumentBuffer::~MarkedArgumentBuffer): Deleted.
+            (JSC::MarkedArgumentBuffer::size const): Deleted.
+            (JSC::MarkedArgumentBuffer::isEmpty const): Deleted.
+            (JSC::MarkedArgumentBuffer::at const): Deleted.
+            (JSC::MarkedArgumentBuffer::clear): Deleted.
+            (JSC::MarkedArgumentBuffer::appendWithAction): Deleted.
+            (JSC::MarkedArgumentBuffer::append): Deleted.
+            (JSC::MarkedArgumentBuffer::appendWithCrashOnOverflow): Deleted.
+            (JSC::MarkedArgumentBuffer::removeLast): Deleted.
+            (JSC::MarkedArgumentBuffer::last): Deleted.
+            (JSC::MarkedArgumentBuffer::takeLast): Deleted.
+            (JSC::MarkedArgumentBuffer::ensureCapacity): Deleted.
+            (JSC::MarkedArgumentBuffer::hasOverflowed): Deleted.
+            (JSC::MarkedArgumentBuffer::overflowCheckNotNeeded): Deleted.
+            (JSC::MarkedArgumentBuffer::fill): Deleted.
+            (JSC::MarkedArgumentBuffer::slotFor const): Deleted.
+            (JSC::MarkedArgumentBuffer::mallocBase): Deleted.
+            (JSC::MarkedArgumentBuffer::setNeedsOverflowCheck): Deleted.
+            (JSC::MarkedArgumentBuffer::clearNeedsOverflowCheck): Deleted.
+            * runtime/JSONObject.cpp:
+            (JSC::Stringifier::Holder::hasFastObjectProperties const):
+            (JSC::Stringifier::appendStringifiedValue):
+            (JSC::Stringifier::Holder::Holder):
+            (JSC::Stringifier::Holder::appendNextProperty):
+            * runtime/ObjectConstructorInlines.h:
+            (JSC::canPerformFastPropertyEnumerationForJSONStringify):
+
+2021-09-22  Alan Coon  <alancoon@apple.com>
+
</ins><span class="cx">         Cherry-pick r282663. rdar://problem/83429716
</span><span class="cx"> 
</span><span class="cx">     PutByVal and PutPrivateName ICs should emit a write barrier if a butterfly might be allocated
</span></span></pre></div>
<a id="branchessafari612branchSourceJavaScriptCoreheapHeapcpp"></a>
<div class="modfile"><h4>Modified: branches/safari-612-branch/Source/JavaScriptCore/heap/Heap.cpp (282942 => 282943)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-612-branch/Source/JavaScriptCore/heap/Heap.cpp   2021-09-23 05:14:23 UTC (rev 282942)
+++ branches/safari-612-branch/Source/JavaScriptCore/heap/Heap.cpp      2021-09-23 05:14:29 UTC (rev 282943)
</span><span class="lines">@@ -2767,7 +2767,7 @@
</span><span class="cx">             
</span><span class="cx">             if (m_markListSet && m_markListSet->size()) {
</span><span class="cx">                 SetRootMarkReasonScope rootScope(visitor, RootMarkReason::ConservativeScan);
</span><del>-                MarkedArgumentBuffer::markLists(visitor, *m_markListSet);
</del><ins>+                MarkedArgumentBufferBase::markLists(visitor, *m_markListSet);
</ins><span class="cx">             }
</span><span class="cx"> 
</span><span class="cx">             {
</span></span></pre></div>
<a id="branchessafari612branchSourceJavaScriptCoreheapHeaph"></a>
<div class="modfile"><h4>Modified: branches/safari-612-branch/Source/JavaScriptCore/heap/Heap.h (282942 => 282943)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-612-branch/Source/JavaScriptCore/heap/Heap.h     2021-09-23 05:14:23 UTC (rev 282942)
+++ branches/safari-612-branch/Source/JavaScriptCore/heap/Heap.h        2021-09-23 05:14:29 UTC (rev 282943)
</span><span class="lines">@@ -77,7 +77,7 @@
</span><span class="cx"> class MarkStackMergingConstraint;
</span><span class="cx"> class MarkedJSValueRefArray;
</span><span class="cx"> class BlockDirectory;
</span><del>-class MarkedArgumentBuffer;
</del><ins>+class MarkedArgumentBufferBase;
</ins><span class="cx"> class MarkingConstraint;
</span><span class="cx"> class MarkingConstraintSet;
</span><span class="cx"> class MutatorScheduler;
</span><span class="lines">@@ -245,7 +245,7 @@
</span><span class="cx">     JS_EXPORT_PRIVATE std::unique_ptr<TypeCountSet> protectedObjectTypeCounts();
</span><span class="cx">     JS_EXPORT_PRIVATE std::unique_ptr<TypeCountSet> objectTypeCounts();
</span><span class="cx"> 
</span><del>-    HashSet<MarkedArgumentBuffer*>& markListSet();
</del><ins>+    HashSet<MarkedArgumentBufferBase*>& markListSet();
</ins><span class="cx">     void addMarkedJSValueRefArray(MarkedJSValueRefArray*);
</span><span class="cx">     
</span><span class="cx">     template<typename Functor> void forEachProtectedCell(const Functor&);
</span><span class="lines">@@ -624,7 +624,7 @@
</span><span class="cx">     HashSet<const JSCell*> m_copyingRememberedSet;
</span><span class="cx"> 
</span><span class="cx">     ProtectCountSet m_protectedValues;
</span><del>-    std::unique_ptr<HashSet<MarkedArgumentBuffer*>> m_markListSet;
</del><ins>+    std::unique_ptr<HashSet<MarkedArgumentBufferBase*>> m_markListSet;
</ins><span class="cx">     SentinelLinkedList<MarkedJSValueRefArray, BasicRawSentinelNode<MarkedJSValueRefArray>> m_markedJSValueRefArrays;
</span><span class="cx"> 
</span><span class="cx">     std::unique_ptr<MachineThreads> m_machineThreads;
</span></span></pre></div>
<a id="branchessafari612branchSourceJavaScriptCoreheapHeapInlinesh"></a>
<div class="modfile"><h4>Modified: branches/safari-612-branch/Source/JavaScriptCore/heap/HeapInlines.h (282942 => 282943)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-612-branch/Source/JavaScriptCore/heap/HeapInlines.h      2021-09-23 05:14:23 UTC (rev 282942)
+++ branches/safari-612-branch/Source/JavaScriptCore/heap/HeapInlines.h 2021-09-23 05:14:29 UTC (rev 282943)
</span><span class="lines">@@ -215,10 +215,10 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-inline HashSet<MarkedArgumentBuffer*>& Heap::markListSet()
</del><ins>+inline HashSet<MarkedArgumentBufferBase*>& Heap::markListSet()
</ins><span class="cx"> {
</span><span class="cx">     if (!m_markListSet)
</span><del>-        m_markListSet = makeUnique<HashSet<MarkedArgumentBuffer*>>();
</del><ins>+        m_markListSet = makeUnique<HashSet<MarkedArgumentBufferBase*>>();
</ins><span class="cx">     return *m_markListSet;
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="branchessafari612branchSourceJavaScriptCoreruntimeArgListcpp"></a>
<div class="modfile"><h4>Modified: branches/safari-612-branch/Source/JavaScriptCore/runtime/ArgList.cpp (282942 => 282943)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-612-branch/Source/JavaScriptCore/runtime/ArgList.cpp     2021-09-23 05:14:23 UTC (rev 282942)
+++ branches/safari-612-branch/Source/JavaScriptCore/runtime/ArgList.cpp        2021-09-23 05:14:29 UTC (rev 282943)
</span><span class="lines">@@ -27,7 +27,7 @@
</span><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="cx"> 
</span><del>-void MarkedArgumentBuffer::addMarkSet(JSValue v)
</del><ins>+void MarkedArgumentBufferBase::addMarkSet(JSValue v)
</ins><span class="cx"> {
</span><span class="cx">     if (m_markSet)
</span><span class="cx">         return;
</span><span class="lines">@@ -52,20 +52,20 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> template<typename Visitor>
</span><del>-void MarkedArgumentBuffer::markLists(Visitor& visitor, ListSet& markSet)
</del><ins>+void MarkedArgumentBufferBase::markLists(Visitor& visitor, ListSet& markSet)
</ins><span class="cx"> {
</span><span class="cx">     ListSet::iterator end = markSet.end();
</span><span class="cx">     for (ListSet::iterator it = markSet.begin(); it != end; ++it) {
</span><del>-        MarkedArgumentBuffer* list = *it;
</del><ins>+        MarkedArgumentBufferBase* list = *it;
</ins><span class="cx">         for (int i = 0; i < list->m_size; ++i)
</span><span class="cx">             visitor.appendUnbarriered(JSValue::decode(list->slotFor(i)));
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-template void MarkedArgumentBuffer::markLists(AbstractSlotVisitor&, ListSet&);
-template void MarkedArgumentBuffer::markLists(SlotVisitor&, ListSet&);
</del><ins>+template void MarkedArgumentBufferBase::markLists(AbstractSlotVisitor&, ListSet&);
+template void MarkedArgumentBufferBase::markLists(SlotVisitor&, ListSet&);
</ins><span class="cx"> 
</span><del>-void MarkedArgumentBuffer::slowEnsureCapacity(size_t requestedCapacity)
</del><ins>+void MarkedArgumentBufferBase::slowEnsureCapacity(size_t requestedCapacity)
</ins><span class="cx"> {
</span><span class="cx">     setNeedsOverflowCheck();
</span><span class="cx">     auto checkedNewCapacity = CheckedInt32(requestedCapacity);
</span><span class="lines">@@ -74,7 +74,7 @@
</span><span class="cx">     expandCapacity(checkedNewCapacity);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void MarkedArgumentBuffer::expandCapacity()
</del><ins>+void MarkedArgumentBufferBase::expandCapacity()
</ins><span class="cx"> {
</span><span class="cx">     setNeedsOverflowCheck();
</span><span class="cx">     auto checkedNewCapacity = CheckedInt32(m_capacity) * 2;
</span><span class="lines">@@ -83,7 +83,7 @@
</span><span class="cx">     expandCapacity(checkedNewCapacity);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void MarkedArgumentBuffer::expandCapacity(int newCapacity)
</del><ins>+void MarkedArgumentBufferBase::expandCapacity(int newCapacity)
</ins><span class="cx"> {
</span><span class="cx">     setNeedsOverflowCheck();
</span><span class="cx">     ASSERT(m_capacity < newCapacity);
</span><span class="lines">@@ -105,7 +105,7 @@
</span><span class="cx">     m_capacity = newCapacity;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void MarkedArgumentBuffer::slowAppend(JSValue v)
</del><ins>+void MarkedArgumentBufferBase::slowAppend(JSValue v)
</ins><span class="cx"> {
</span><span class="cx">     ASSERT(m_size <= m_capacity);
</span><span class="cx">     if (m_size == m_capacity)
</span></span></pre></div>
<a id="branchessafari612branchSourceJavaScriptCoreruntimeArgListh"></a>
<div class="modfile"><h4>Modified: branches/safari-612-branch/Source/JavaScriptCore/runtime/ArgList.h (282942 => 282943)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-612-branch/Source/JavaScriptCore/runtime/ArgList.h       2021-09-23 05:14:23 UTC (rev 282942)
+++ branches/safari-612-branch/Source/JavaScriptCore/runtime/ArgList.h  2021-09-23 05:14:29 UTC (rev 282943)
</span><span class="lines">@@ -28,9 +28,9 @@
</span><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="cx"> 
</span><del>-class MarkedArgumentBuffer : public RecordOverflow {
-    WTF_MAKE_NONCOPYABLE(MarkedArgumentBuffer);
-    WTF_MAKE_NONMOVABLE(MarkedArgumentBuffer);
</del><ins>+class alignas(alignof(EncodedJSValue)) MarkedArgumentBufferBase : public RecordOverflow {
+    WTF_MAKE_NONCOPYABLE(MarkedArgumentBufferBase);
+    WTF_MAKE_NONMOVABLE(MarkedArgumentBufferBase);
</ins><span class="cx">     WTF_FORBID_HEAP_ALLOCATION;
</span><span class="cx">     friend class VM;
</span><span class="cx">     friend class ArgList;
</span><span class="lines">@@ -37,21 +37,10 @@
</span><span class="cx"> 
</span><span class="cx"> public:
</span><span class="cx">     using Base = RecordOverflow;
</span><del>-    static constexpr size_t inlineCapacity = 8;
-    typedef HashSet<MarkedArgumentBuffer*> ListSet;
</del><ins>+    typedef HashSet<MarkedArgumentBufferBase*> ListSet;
</ins><span class="cx"> 
</span><del>-    // Constructor for a read-write list, to which you may append values.
-    // FIXME: Remove all clients of this API, then remove this API.
-    MarkedArgumentBuffer()
-        : m_size(0)
-        , m_capacity(inlineCapacity)
-        , m_buffer(m_inlineBuffer)
-        , m_markSet(nullptr)
</del><ins>+    ~MarkedArgumentBufferBase()
</ins><span class="cx">     {
</span><del>-    }
-
-    ~MarkedArgumentBuffer()
-    {
</del><span class="cx">         ASSERT(!m_needsOverflowCheck);
</span><span class="cx">         if (m_markSet)
</span><span class="cx">             m_markSet->remove(this);
</span><span class="lines">@@ -145,6 +134,22 @@
</span><span class="cx">         func(reinterpret_cast<JSValue*>(&slotFor(0)));
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+protected:
+    // Constructor for a read-write list, to which you may append values.
+    // FIXME: Remove all clients of this API, then remove this API.
+    MarkedArgumentBufferBase(size_t capacity)
+        : m_size(0)
+        , m_capacity(capacity)
+        , m_buffer(inlineBuffer())
+        , m_markSet(nullptr)
+    {
+    }
+
+    EncodedJSValue* inlineBuffer()
+    {
+        return bitwise_cast<EncodedJSValue*>(bitwise_cast<uint8_t*>(this) + sizeof(MarkedArgumentBufferBase));
+    }
+
</ins><span class="cx"> private:
</span><span class="cx">     void expandCapacity();
</span><span class="cx">     void expandCapacity(int newCapacity);
</span><span class="lines">@@ -161,7 +166,7 @@
</span><span class="cx">         
</span><span class="cx">     EncodedJSValue* mallocBase()
</span><span class="cx">     {
</span><del>-        if (m_buffer == m_inlineBuffer)
</del><ins>+        if (m_buffer == inlineBuffer())
</ins><span class="cx">             return nullptr;
</span><span class="cx">         return &slotFor(0);
</span><span class="cx">     }
</span><span class="lines">@@ -177,11 +182,27 @@
</span><span class="cx"> #endif // ASSERT_ENABLED
</span><span class="cx">     int m_size;
</span><span class="cx">     int m_capacity;
</span><del>-    EncodedJSValue m_inlineBuffer[inlineCapacity];
</del><span class="cx">     EncodedJSValue* m_buffer;
</span><span class="cx">     ListSet* m_markSet;
</span><span class="cx"> };
</span><span class="cx"> 
</span><ins>+template<size_t passedInlineCapacity = 8>
+class MarkedArgumentBufferWithSize : public MarkedArgumentBufferBase {
+public:
+    static constexpr size_t inlineCapacity = passedInlineCapacity;
+
+    MarkedArgumentBufferWithSize()
+        : MarkedArgumentBufferBase(inlineCapacity)
+    {
+        ASSERT(inlineBuffer() == m_inlineBuffer);
+    }
+
+private:
+    EncodedJSValue m_inlineBuffer[inlineCapacity] { };
+};
+
+using MarkedArgumentBuffer = MarkedArgumentBufferWithSize<>;
+
</ins><span class="cx"> class ArgList {
</span><span class="cx">     WTF_MAKE_FAST_ALLOCATED;
</span><span class="cx">     friend class Interpreter;
</span></span></pre></div>
<a id="branchessafari612branchSourceJavaScriptCoreruntimeJSONObjectcpp"></a>
<div class="modfile"><h4>Modified: branches/safari-612-branch/Source/JavaScriptCore/runtime/JSONObject.cpp (282942 => 282943)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-612-branch/Source/JavaScriptCore/runtime/JSONObject.cpp  2021-09-23 05:14:23 UTC (rev 282942)
+++ branches/safari-612-branch/Source/JavaScriptCore/runtime/JSONObject.cpp     2021-09-23 05:14:29 UTC (rev 282943)
</span><span class="lines">@@ -33,7 +33,7 @@
</span><span class="cx"> #include "JSArrayInlines.h"
</span><span class="cx"> #include "JSCInlines.h"
</span><span class="cx"> #include "LiteralParser.h"
</span><del>-#include "ObjectConstructor.h"
</del><ins>+#include "ObjectConstructorInlines.h"
</ins><span class="cx"> #include "PropertyNameArray.h"
</span><span class="cx"> #include "VMInlines.h"
</span><span class="cx"> #include <wtf/text/StringBuilder.h>
</span><span class="lines">@@ -88,21 +88,25 @@
</span><span class="cx">     class Holder {
</span><span class="cx">     public:
</span><span class="cx">         enum RootHolderTag { RootHolder };
</span><del>-        Holder(JSGlobalObject*, JSObject*);
</del><ins>+        Holder(JSGlobalObject*, JSObject*, Structure*);
</ins><span class="cx">         Holder(RootHolderTag, JSObject*);
</span><span class="cx"> 
</span><span class="cx">         JSObject* object() const { return m_object; }
</span><span class="cx">         bool isArray() const { return m_isArray; }
</span><ins>+        bool hasFastObjectProperties() const { return m_hasFastObjectProperties; }
</ins><span class="cx"> 
</span><span class="cx">         bool appendNextProperty(Stringifier&, StringBuilder&);
</span><span class="cx"> 
</span><span class="cx">     private:
</span><del>-        JSObject* m_object;
-        const bool m_isJSArray;
-        const bool m_isArray;
</del><ins>+        JSObject* m_object { nullptr };
+        Structure* m_structure { nullptr };
+        const bool m_isJSArray { false };
+        const bool m_isArray { false };
+        bool m_hasFastObjectProperties { false };
</ins><span class="cx">         unsigned m_index { 0 };
</span><span class="cx">         unsigned m_size { 0 };
</span><span class="cx">         RefPtr<PropertyNameArrayData> m_propertyNames;
</span><ins>+        Vector<std::tuple<Identifier, unsigned>, 8> m_propertiesAndOffsets;
</ins><span class="cx">     };
</span><span class="cx"> 
</span><span class="cx">     friend class Holder;
</span><span class="lines">@@ -125,7 +129,7 @@
</span><span class="cx">     CallData m_replacerCallData;
</span><span class="cx">     String m_gap;
</span><span class="cx"> 
</span><del>-    MarkedArgumentBuffer m_objectStack;
</del><ins>+    MarkedArgumentBufferWithSize<16> m_objectStack;
</ins><span class="cx">     Vector<Holder, 16, UnsafeVectorOverflow> m_holderStack;
</span><span class="cx">     String m_repeatedGap;
</span><span class="cx">     String m_indent;
</span><span class="lines">@@ -408,8 +412,10 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     bool holderStackWasEmpty = m_holderStack.isEmpty();
</span><del>-    m_holderStack.append(Holder(m_globalObject, object));
</del><ins>+    Structure* structure = object->structure(vm);
+    m_holderStack.append(Holder(m_globalObject, object, structure));
</ins><span class="cx">     m_objectStack.appendWithCrashOnOverflow(object);
</span><ins>+    m_objectStack.appendWithCrashOnOverflow(structure);
</ins><span class="cx">     RETURN_IF_EXCEPTION(scope, StringifyFailed);
</span><span class="cx">     if (!holderStackWasEmpty)
</span><span class="cx">         return StringifySucceeded;
</span><span class="lines">@@ -422,6 +428,7 @@
</span><span class="cx">             return StringifyFailed;
</span><span class="cx">         m_holderStack.removeLast();
</span><span class="cx">         m_objectStack.removeLast();
</span><ins>+        m_objectStack.removeLast();
</ins><span class="cx">     } while (!m_holderStack.isEmpty());
</span><span class="cx">     return StringifySucceeded;
</span><span class="cx"> }
</span><span class="lines">@@ -455,8 +462,9 @@
</span><span class="cx">     builder.append(m_indent);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-inline Stringifier::Holder::Holder(JSGlobalObject* globalObject, JSObject* object)
</del><ins>+inline Stringifier::Holder::Holder(JSGlobalObject* globalObject, JSObject* object, Structure* structure)
</ins><span class="cx">     : m_object(object)
</span><ins>+    , m_structure(structure)
</ins><span class="cx">     , m_isJSArray(isJSArray(object))
</span><span class="cx">     , m_isArray(JSC::isArray(globalObject, object))
</span><span class="cx"> {
</span><span class="lines">@@ -464,8 +472,6 @@
</span><span class="cx"> 
</span><span class="cx"> inline Stringifier::Holder::Holder(RootHolderTag, JSObject* object)
</span><span class="cx">     : m_object(object)
</span><del>-    , m_isJSArray(false)
-    , m_isArray(false)
</del><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -490,15 +496,29 @@
</span><span class="cx">             RETURN_IF_EXCEPTION(scope, false);
</span><span class="cx">             builder.append('[');
</span><span class="cx">         } else {
</span><del>-            if (stringifier.m_usingArrayReplacer)
</del><ins>+            if (stringifier.m_usingArrayReplacer) {
</ins><span class="cx">                 m_propertyNames = stringifier.m_arrayReplacerPropertyNames.data();
</span><del>-            else {
</del><ins>+                m_size = m_propertyNames->propertyNameVector().size();
+            } else if (m_structure && m_object->structureID() == m_structure->id() && canPerformFastPropertyEnumerationForJSONStringify(m_structure)) {
+                m_structure->forEachProperty(vm, [&](const PropertyMapEntry& entry) -> bool {
+                    if (entry.attributes & PropertyAttribute::DontEnum)
+                        return true;
+
+                    PropertyName propertyName(entry.key);
+                    if (propertyName.isSymbol())
+                        return true;
+                    m_propertiesAndOffsets.constructAndAppend(Identifier::fromUid(vm, entry.key), entry.offset);
+                    return true;
+                });
+                m_hasFastObjectProperties = true;
+                m_size = m_propertiesAndOffsets.size();
+            } else {
</ins><span class="cx">                 PropertyNameArray objectPropertyNames(vm, PropertyNameMode::Strings, PrivateSymbolMode::Exclude);
</span><span class="cx">                 m_object->methodTable(vm)->getOwnPropertyNames(m_object, globalObject, objectPropertyNames, DontEnumPropertiesMode::Exclude);
</span><span class="cx">                 RETURN_IF_EXCEPTION(scope, false);
</span><span class="cx">                 m_propertyNames = objectPropertyNames.releaseData();
</span><ins>+                m_size = m_propertyNames->propertyNameVector().size();
</ins><span class="cx">             }
</span><del>-            m_size = m_propertyNames->propertyNameVector().size();
</del><span class="cx">             builder.append('{');
</span><span class="cx">         }
</span><span class="cx">         stringifier.indent();
</span><span class="lines">@@ -538,10 +558,22 @@
</span><span class="cx">         stringifyResult = stringifier.appendStringifiedValue(builder, value, *this, index);
</span><span class="cx">         ASSERT(stringifyResult != StringifyFailedDueToUndefinedOrSymbolValue);
</span><span class="cx">     } else {
</span><del>-        // Get the value.
-        Identifier& propertyName = m_propertyNames->propertyNameVector()[index];
-        JSValue value = m_object->get(globalObject, propertyName);
-        RETURN_IF_EXCEPTION(scope, false);
</del><ins>+        Identifier propertyName;
+        JSValue value;
+        if (m_hasFastObjectProperties) {
+            propertyName = std::get<0>(m_propertiesAndOffsets[index]);
+            if (m_object->structureID() == m_structure->id()) {
+                unsigned offset = std::get<1>(m_propertiesAndOffsets[index]);
+                value = m_object->getDirect(offset);
+            } else {
+                value = m_object->get(globalObject, propertyName);
+                RETURN_IF_EXCEPTION(scope, false);
+            }
+        } else {
+            propertyName = m_propertyNames->propertyNameVector()[index];
+            value = m_object->get(globalObject, propertyName);
+            RETURN_IF_EXCEPTION(scope, false);
+        }
</ins><span class="cx"> 
</span><span class="cx">         rollBackPoint = builder.length();
</span><span class="cx"> 
</span></span></pre></div>
<a id="branchessafari612branchSourceJavaScriptCoreruntimeObjectConstructorInlinesh"></a>
<div class="modfile"><h4>Modified: branches/safari-612-branch/Source/JavaScriptCore/runtime/ObjectConstructorInlines.h (282942 => 282943)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-612-branch/Source/JavaScriptCore/runtime/ObjectConstructorInlines.h      2021-09-23 05:14:23 UTC (rev 282942)
+++ branches/safari-612-branch/Source/JavaScriptCore/runtime/ObjectConstructorInlines.h 2021-09-23 05:14:29 UTC (rev 282943)
</span><span class="lines">@@ -53,6 +53,11 @@
</span><span class="cx">     return true;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+ALWAYS_INLINE bool canPerformFastPropertyEnumerationForJSONStringify(Structure* structure)
+{
+    return canPerformFastPropertyEnumerationForObjectAssign(structure);
+}
+
</ins><span class="cx"> ALWAYS_INLINE void objectAssignFast(VM& vm, JSObject* target, JSObject* source, Vector<RefPtr<UniquedStringImpl>, 8>& properties, MarkedArgumentBuffer& values)
</span><span class="cx"> {
</span><span class="cx">     // |source| Structure does not have any getters. And target can perform fast put.
</span></span></pre></div>
<a id="branchessafari612branchSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: branches/safari-612-branch/Source/WebCore/ChangeLog (282942 => 282943)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-612-branch/Source/WebCore/ChangeLog      2021-09-23 05:14:23 UTC (rev 282942)
+++ branches/safari-612-branch/Source/WebCore/ChangeLog 2021-09-23 05:14:29 UTC (rev 282943)
</span><span class="lines">@@ -1,5 +1,133 @@
</span><span class="cx"> 2021-09-22  Alan Coon  <alancoon@apple.com>
</span><span class="cx"> 
</span><ins>+        Cherry-pick r282707. rdar://problem/83429953
+
+    [JSC] Add fast property enumeration mode for JSON.stringify
+    https://bugs.webkit.org/show_bug.cgi?id=230393
+    
+    Reviewed by Mark Lam.
+    
+    JSTests:
+    
+    * stress/json-stringify-object-modify.js: Added.
+    (shouldBe):
+    (throw.new.Error.let.object.hello.get inner):
+    (throw.new.Error):
+    (shouldBe.let.object.hello.get inner):
+    
+    Source/JavaScriptCore:
+    
+    We collected profiles and found several subtests are using JSON.stringify enough. And generated strings are many serialized leaf objects.
+    
+    This patch adds fast object property enumeration. When we know that source object meets some conditions, we can say that,
+    as long as structure is not changed, we can continue using property names and offset collected from the structure.
+    This way removes non observable [[Get]] operations to accelerate JSON.stringify performance for major object iteration cases.
+    
+    We also extend MarkedArgumentBuffer: introducing MarkedArgumentBufferWithSize which can take default inline capacity as a template
+    parameter. This is used in JSON.stringify to increase the buffer because now we also need to record structures in MarkedArgumentBuffer.
+    
+    This offers 0.4% improvement in Speedometer2 (EmberJS-TodoMVC, Vanilla-XXX, EmberJS-Debug-TodoMVC, they have enough amount of JSON.stringify
+    time).
+    
+    ----------------------------------------------------------------------------------------------------------------------------------
+    |               subtest                |     ms      |     ms      |  b / a   | pValue (significance using False Discovery Rate) |
+    ----------------------------------------------------------------------------------------------------------------------------------
+    | Elm-TodoMVC                          |117.710000   |117.751667   |1.000354  | 0.883246                                         |
+    | VueJS-TodoMVC                        |24.500000    |24.311667    |0.992313  | 0.365130                                         |
+    | EmberJS-TodoMVC                      |126.646667   |125.738333   |0.992828  | 0.002587 (significant)                           |
+    | BackboneJS-TodoMVC                   |47.873333    |47.911667    |1.000801  | 0.762509                                         |
+    | Preact-TodoMVC                       |17.020000    |17.070000    |1.002938  | 0.786799                                         |
+    | AngularJS-TodoMVC                    |129.856667   |129.353333   |0.996124  | 0.177632                                         |
+    | Vanilla-ES2015-TodoMVC               |61.698333    |61.120000    |0.990626  | 0.000003 (significant)                           |
+    | Inferno-TodoMVC                      |62.840000    |62.496667    |0.994536  | 0.312340                                         |
+    | Flight-TodoMVC                       |77.095000    |76.936667    |0.997946  | 0.702724                                         |
+    | Angular2-TypeScript-TodoMVC          |39.740000    |39.191667    |0.986202  | 0.053485                                         |
+    | VanillaJS-TodoMVC                    |49.008333    |48.346667    |0.986499  | 0.000638 (significant)                           |
+    | jQuery-TodoMVC                       |216.785000   |217.188333   |1.001861  | 0.270747                                         |
+    | EmberJS-Debug-TodoMVC                |344.230000   |342.993333   |0.996407  | 0.012262 (significant)                           |
+    | React-TodoMVC                        |85.461667    |85.411667    |0.999415  | 0.758049                                         |
+    | React-Redux-TodoMVC                  |140.681667   |140.640000   |0.999704  | 0.871277                                         |
+    | Vanilla-ES2015-Babel-Webpack-TodoMVC |59.928333    |59.351667    |0.990377  | 0.000000 (significant)                           |
+    ----------------------------------------------------------------------------------------------------------------------------------
+    a mean = 264.40650
+    b mean = 265.51533
+    pValue = 0.0005567357
+    (Bigger means are better.)
+    1.004 times better
+    Results ARE significant
+    
+    * heap/Heap.cpp:
+    (JSC::Heap::addCoreConstraints):
+    * heap/Heap.h:
+    * heap/HeapInlines.h:
+    * runtime/ArgList.cpp:
+    (JSC::MarkedArgumentBufferBase::addMarkSet):
+    (JSC::MarkedArgumentBufferBase::markLists):
+    (JSC::MarkedArgumentBufferBase::slowEnsureCapacity):
+    (JSC::MarkedArgumentBufferBase::expandCapacity):
+    (JSC::MarkedArgumentBufferBase::slowAppend):
+    (JSC::MarkedArgumentBuffer::addMarkSet): Deleted.
+    (JSC::MarkedArgumentBuffer::markLists): Deleted.
+    (JSC::MarkedArgumentBuffer::slowEnsureCapacity): Deleted.
+    (JSC::MarkedArgumentBuffer::expandCapacity): Deleted.
+    (JSC::MarkedArgumentBuffer::slowAppend): Deleted.
+    * runtime/ArgList.h:
+    (JSC::MarkedArgumentBufferWithSize::MarkedArgumentBufferWithSize):
+    (JSC::MarkedArgumentBuffer::MarkedArgumentBuffer): Deleted.
+    (JSC::MarkedArgumentBuffer::~MarkedArgumentBuffer): Deleted.
+    (JSC::MarkedArgumentBuffer::size const): Deleted.
+    (JSC::MarkedArgumentBuffer::isEmpty const): Deleted.
+    (JSC::MarkedArgumentBuffer::at const): Deleted.
+    (JSC::MarkedArgumentBuffer::clear): Deleted.
+    (JSC::MarkedArgumentBuffer::appendWithAction): Deleted.
+    (JSC::MarkedArgumentBuffer::append): Deleted.
+    (JSC::MarkedArgumentBuffer::appendWithCrashOnOverflow): Deleted.
+    (JSC::MarkedArgumentBuffer::removeLast): Deleted.
+    (JSC::MarkedArgumentBuffer::last): Deleted.
+    (JSC::MarkedArgumentBuffer::takeLast): Deleted.
+    (JSC::MarkedArgumentBuffer::ensureCapacity): Deleted.
+    (JSC::MarkedArgumentBuffer::hasOverflowed): Deleted.
+    (JSC::MarkedArgumentBuffer::overflowCheckNotNeeded): Deleted.
+    (JSC::MarkedArgumentBuffer::fill): Deleted.
+    (JSC::MarkedArgumentBuffer::slotFor const): Deleted.
+    (JSC::MarkedArgumentBuffer::mallocBase): Deleted.
+    (JSC::MarkedArgumentBuffer::setNeedsOverflowCheck): Deleted.
+    (JSC::MarkedArgumentBuffer::clearNeedsOverflowCheck): Deleted.
+    * runtime/JSONObject.cpp:
+    (JSC::Stringifier::Holder::hasFastObjectProperties const):
+    (JSC::Stringifier::appendStringifiedValue):
+    (JSC::Stringifier::Holder::Holder):
+    (JSC::Stringifier::Holder::appendNextProperty):
+    * runtime/ObjectConstructorInlines.h:
+    (JSC::canPerformFastPropertyEnumerationForJSONStringify):
+    
+    Source/WebCore:
+    
+    * Modules/webaudio/AudioWorkletProcessor.cpp:
+    (WebCore::AudioWorkletProcessor::buildJSArguments):
+    * Modules/webaudio/AudioWorkletProcessor.h:
+    
+    Source/WebKitLegacy/mac:
+    
+    * Plugins/Hosted/NetscapePluginInstanceProxy.h:
+    * Plugins/Hosted/NetscapePluginInstanceProxy.mm:
+    (WebKit::NetscapePluginInstanceProxy::demarshalValues):
+    
+    git-svn-id: https://svn.webkit.org/repository/webkit/trunk@282707 268f45cc-cd09-0410-ab3c-d52691b4dbfc
+
+    2021-09-17  Yusuke Suzuki  <ysuzuki@apple.com>
+
+            [JSC] Add fast property enumeration mode for JSON.stringify
+            https://bugs.webkit.org/show_bug.cgi?id=230393
+
+            Reviewed by Mark Lam.
+
+            * Modules/webaudio/AudioWorkletProcessor.cpp:
+            (WebCore::AudioWorkletProcessor::buildJSArguments):
+            * Modules/webaudio/AudioWorkletProcessor.h:
+
+2021-09-22  Alan Coon  <alancoon@apple.com>
+
</ins><span class="cx">         Cherry-pick r282615. rdar://problem/83429940
</span><span class="cx"> 
</span><span class="cx">     Throttle a couple of editing-related timers in cases where the user has not interacted with subframes
</span></span></pre></div>
<a id="branchessafari612branchSourceWebCoreModuleswebaudioAudioWorkletProcessorcpp"></a>
<div class="modfile"><h4>Modified: branches/safari-612-branch/Source/WebCore/Modules/webaudio/AudioWorkletProcessor.cpp (282942 => 282943)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-612-branch/Source/WebCore/Modules/webaudio/AudioWorkletProcessor.cpp     2021-09-23 05:14:23 UTC (rev 282942)
+++ branches/safari-612-branch/Source/WebCore/Modules/webaudio/AudioWorkletProcessor.cpp        2021-09-23 05:14:29 UTC (rev 282943)
</span><span class="lines">@@ -213,7 +213,7 @@
</span><span class="cx">     ASSERT(!isMainThread());
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void AudioWorkletProcessor::buildJSArguments(VM& vm, JSGlobalObject& globalObject, MarkedArgumentBuffer& args, const Vector<RefPtr<AudioBus>>& inputs, Vector<Ref<AudioBus>>& outputs, const HashMap<String, std::unique_ptr<AudioFloatArray>>& paramValuesMap)
</del><ins>+void AudioWorkletProcessor::buildJSArguments(VM& vm, JSGlobalObject& globalObject, MarkedArgumentBufferBase& args, const Vector<RefPtr<AudioBus>>& inputs, Vector<Ref<AudioBus>>& outputs, const HashMap<String, std::unique_ptr<AudioFloatArray>>& paramValuesMap)
</ins><span class="cx"> {
</span><span class="cx">     // For performance reasons, we cache the arrays passed to JS and reconstruct them only when the topology changes.
</span><span class="cx">     if (!copyDataFromBusesToJSArray(vm, globalObject, inputs, toJSArray(m_jsInputs)))
</span></span></pre></div>
<a id="branchessafari612branchSourceWebCoreModuleswebaudioAudioWorkletProcessorh"></a>
<div class="modfile"><h4>Modified: branches/safari-612-branch/Source/WebCore/Modules/webaudio/AudioWorkletProcessor.h (282942 => 282943)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-612-branch/Source/WebCore/Modules/webaudio/AudioWorkletProcessor.h       2021-09-23 05:14:23 UTC (rev 282942)
+++ branches/safari-612-branch/Source/WebCore/Modules/webaudio/AudioWorkletProcessor.h  2021-09-23 05:14:29 UTC (rev 282943)
</span><span class="lines">@@ -38,7 +38,7 @@
</span><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="cx"> class JSArray;
</span><del>-class MarkedArgumentBuffer;
</del><ins>+class MarkedArgumentBufferBase;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="lines">@@ -67,7 +67,7 @@
</span><span class="cx"> 
</span><span class="cx"> private:
</span><span class="cx">     explicit AudioWorkletProcessor(const AudioWorkletProcessorConstructionData&);
</span><del>-    void buildJSArguments(JSC::VM&, JSC::JSGlobalObject&, JSC::MarkedArgumentBuffer&, const Vector<RefPtr<AudioBus>>& inputs, Vector<Ref<AudioBus>>& outputs, const HashMap<String, std::unique_ptr<AudioFloatArray>>& paramValuesMap);
</del><ins>+    void buildJSArguments(JSC::VM&, JSC::JSGlobalObject&, JSC::MarkedArgumentBufferBase&, const Vector<RefPtr<AudioBus>>& inputs, Vector<Ref<AudioBus>>& outputs, const HashMap<String, std::unique_ptr<AudioFloatArray>>& paramValuesMap);
</ins><span class="cx"> 
</span><span class="cx">     String m_name;
</span><span class="cx">     Ref<MessagePort> m_port;
</span></span></pre></div>
<a id="branchessafari612branchSourceWebKitLegacymacChangeLog"></a>
<div class="modfile"><h4>Modified: branches/safari-612-branch/Source/WebKitLegacy/mac/ChangeLog (282942 => 282943)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-612-branch/Source/WebKitLegacy/mac/ChangeLog     2021-09-23 05:14:23 UTC (rev 282942)
+++ branches/safari-612-branch/Source/WebKitLegacy/mac/ChangeLog        2021-09-23 05:14:29 UTC (rev 282943)
</span><span class="lines">@@ -1,5 +1,133 @@
</span><span class="cx"> 2021-09-22  Alan Coon  <alancoon@apple.com>
</span><span class="cx"> 
</span><ins>+        Cherry-pick r282707. rdar://problem/83429953
+
+    [JSC] Add fast property enumeration mode for JSON.stringify
+    https://bugs.webkit.org/show_bug.cgi?id=230393
+    
+    Reviewed by Mark Lam.
+    
+    JSTests:
+    
+    * stress/json-stringify-object-modify.js: Added.
+    (shouldBe):
+    (throw.new.Error.let.object.hello.get inner):
+    (throw.new.Error):
+    (shouldBe.let.object.hello.get inner):
+    
+    Source/JavaScriptCore:
+    
+    We collected profiles and found several subtests are using JSON.stringify enough. And generated strings are many serialized leaf objects.
+    
+    This patch adds fast object property enumeration. When we know that source object meets some conditions, we can say that,
+    as long as structure is not changed, we can continue using property names and offset collected from the structure.
+    This way removes non observable [[Get]] operations to accelerate JSON.stringify performance for major object iteration cases.
+    
+    We also extend MarkedArgumentBuffer: introducing MarkedArgumentBufferWithSize which can take default inline capacity as a template
+    parameter. This is used in JSON.stringify to increase the buffer because now we also need to record structures in MarkedArgumentBuffer.
+    
+    This offers 0.4% improvement in Speedometer2 (EmberJS-TodoMVC, Vanilla-XXX, EmberJS-Debug-TodoMVC, they have enough amount of JSON.stringify
+    time).
+    
+    ----------------------------------------------------------------------------------------------------------------------------------
+    |               subtest                |     ms      |     ms      |  b / a   | pValue (significance using False Discovery Rate) |
+    ----------------------------------------------------------------------------------------------------------------------------------
+    | Elm-TodoMVC                          |117.710000   |117.751667   |1.000354  | 0.883246                                         |
+    | VueJS-TodoMVC                        |24.500000    |24.311667    |0.992313  | 0.365130                                         |
+    | EmberJS-TodoMVC                      |126.646667   |125.738333   |0.992828  | 0.002587 (significant)                           |
+    | BackboneJS-TodoMVC                   |47.873333    |47.911667    |1.000801  | 0.762509                                         |
+    | Preact-TodoMVC                       |17.020000    |17.070000    |1.002938  | 0.786799                                         |
+    | AngularJS-TodoMVC                    |129.856667   |129.353333   |0.996124  | 0.177632                                         |
+    | Vanilla-ES2015-TodoMVC               |61.698333    |61.120000    |0.990626  | 0.000003 (significant)                           |
+    | Inferno-TodoMVC                      |62.840000    |62.496667    |0.994536  | 0.312340                                         |
+    | Flight-TodoMVC                       |77.095000    |76.936667    |0.997946  | 0.702724                                         |
+    | Angular2-TypeScript-TodoMVC          |39.740000    |39.191667    |0.986202  | 0.053485                                         |
+    | VanillaJS-TodoMVC                    |49.008333    |48.346667    |0.986499  | 0.000638 (significant)                           |
+    | jQuery-TodoMVC                       |216.785000   |217.188333   |1.001861  | 0.270747                                         |
+    | EmberJS-Debug-TodoMVC                |344.230000   |342.993333   |0.996407  | 0.012262 (significant)                           |
+    | React-TodoMVC                        |85.461667    |85.411667    |0.999415  | 0.758049                                         |
+    | React-Redux-TodoMVC                  |140.681667   |140.640000   |0.999704  | 0.871277                                         |
+    | Vanilla-ES2015-Babel-Webpack-TodoMVC |59.928333    |59.351667    |0.990377  | 0.000000 (significant)                           |
+    ----------------------------------------------------------------------------------------------------------------------------------
+    a mean = 264.40650
+    b mean = 265.51533
+    pValue = 0.0005567357
+    (Bigger means are better.)
+    1.004 times better
+    Results ARE significant
+    
+    * heap/Heap.cpp:
+    (JSC::Heap::addCoreConstraints):
+    * heap/Heap.h:
+    * heap/HeapInlines.h:
+    * runtime/ArgList.cpp:
+    (JSC::MarkedArgumentBufferBase::addMarkSet):
+    (JSC::MarkedArgumentBufferBase::markLists):
+    (JSC::MarkedArgumentBufferBase::slowEnsureCapacity):
+    (JSC::MarkedArgumentBufferBase::expandCapacity):
+    (JSC::MarkedArgumentBufferBase::slowAppend):
+    (JSC::MarkedArgumentBuffer::addMarkSet): Deleted.
+    (JSC::MarkedArgumentBuffer::markLists): Deleted.
+    (JSC::MarkedArgumentBuffer::slowEnsureCapacity): Deleted.
+    (JSC::MarkedArgumentBuffer::expandCapacity): Deleted.
+    (JSC::MarkedArgumentBuffer::slowAppend): Deleted.
+    * runtime/ArgList.h:
+    (JSC::MarkedArgumentBufferWithSize::MarkedArgumentBufferWithSize):
+    (JSC::MarkedArgumentBuffer::MarkedArgumentBuffer): Deleted.
+    (JSC::MarkedArgumentBuffer::~MarkedArgumentBuffer): Deleted.
+    (JSC::MarkedArgumentBuffer::size const): Deleted.
+    (JSC::MarkedArgumentBuffer::isEmpty const): Deleted.
+    (JSC::MarkedArgumentBuffer::at const): Deleted.
+    (JSC::MarkedArgumentBuffer::clear): Deleted.
+    (JSC::MarkedArgumentBuffer::appendWithAction): Deleted.
+    (JSC::MarkedArgumentBuffer::append): Deleted.
+    (JSC::MarkedArgumentBuffer::appendWithCrashOnOverflow): Deleted.
+    (JSC::MarkedArgumentBuffer::removeLast): Deleted.
+    (JSC::MarkedArgumentBuffer::last): Deleted.
+    (JSC::MarkedArgumentBuffer::takeLast): Deleted.
+    (JSC::MarkedArgumentBuffer::ensureCapacity): Deleted.
+    (JSC::MarkedArgumentBuffer::hasOverflowed): Deleted.
+    (JSC::MarkedArgumentBuffer::overflowCheckNotNeeded): Deleted.
+    (JSC::MarkedArgumentBuffer::fill): Deleted.
+    (JSC::MarkedArgumentBuffer::slotFor const): Deleted.
+    (JSC::MarkedArgumentBuffer::mallocBase): Deleted.
+    (JSC::MarkedArgumentBuffer::setNeedsOverflowCheck): Deleted.
+    (JSC::MarkedArgumentBuffer::clearNeedsOverflowCheck): Deleted.
+    * runtime/JSONObject.cpp:
+    (JSC::Stringifier::Holder::hasFastObjectProperties const):
+    (JSC::Stringifier::appendStringifiedValue):
+    (JSC::Stringifier::Holder::Holder):
+    (JSC::Stringifier::Holder::appendNextProperty):
+    * runtime/ObjectConstructorInlines.h:
+    (JSC::canPerformFastPropertyEnumerationForJSONStringify):
+    
+    Source/WebCore:
+    
+    * Modules/webaudio/AudioWorkletProcessor.cpp:
+    (WebCore::AudioWorkletProcessor::buildJSArguments):
+    * Modules/webaudio/AudioWorkletProcessor.h:
+    
+    Source/WebKitLegacy/mac:
+    
+    * Plugins/Hosted/NetscapePluginInstanceProxy.h:
+    * Plugins/Hosted/NetscapePluginInstanceProxy.mm:
+    (WebKit::NetscapePluginInstanceProxy::demarshalValues):
+    
+    git-svn-id: https://svn.webkit.org/repository/webkit/trunk@282707 268f45cc-cd09-0410-ab3c-d52691b4dbfc
+
+    2021-09-17  Yusuke Suzuki  <ysuzuki@apple.com>
+
+            [JSC] Add fast property enumeration mode for JSON.stringify
+            https://bugs.webkit.org/show_bug.cgi?id=230393
+
+            Reviewed by Mark Lam.
+
+            * Plugins/Hosted/NetscapePluginInstanceProxy.h:
+            * Plugins/Hosted/NetscapePluginInstanceProxy.mm:
+            (WebKit::NetscapePluginInstanceProxy::demarshalValues):
+
+2021-09-22  Alan Coon  <alancoon@apple.com>
+
</ins><span class="cx">         Cherry-pick r282393. rdar://problem/83429703
</span><span class="cx"> 
</span><span class="cx">     [Hardening] Validate IDBValue's blob paths in WebIDBServer::putOrAdd()
</span></span></pre></div>
<a id="branchessafari612branchSourceWebKitLegacymacPluginsHostedNetscapePluginInstanceProxyh"></a>
<div class="modfile"><h4>Modified: branches/safari-612-branch/Source/WebKitLegacy/mac/Plugins/Hosted/NetscapePluginInstanceProxy.h (282942 => 282943)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-612-branch/Source/WebKitLegacy/mac/Plugins/Hosted/NetscapePluginInstanceProxy.h  2021-09-23 05:14:23 UTC (rev 282942)
+++ branches/safari-612-branch/Source/WebKitLegacy/mac/Plugins/Hosted/NetscapePluginInstanceProxy.h     2021-09-23 05:14:29 UTC (rev 282943)
</span><span class="lines">@@ -310,7 +310,7 @@
</span><span class="cx">     void addValueToArray(NSMutableArray *, JSC::JSGlobalObject* exec, JSC::JSValue value);
</span><span class="cx">     
</span><span class="cx">     bool demarshalValueFromArray(JSC::JSGlobalObject*, NSArray *array, NSUInteger& index, JSC::JSValue& result);
</span><del>-    void demarshalValues(JSC::JSGlobalObject*, data_t valuesData, mach_msg_type_number_t valuesLength, JSC::MarkedArgumentBuffer& result);
</del><ins>+    void demarshalValues(JSC::JSGlobalObject*, data_t valuesData, mach_msg_type_number_t valuesLength, JSC::MarkedArgumentBufferBase& result);
</ins><span class="cx"> 
</span><span class="cx">     class LocalObjectMap {
</span><span class="cx">         WTF_MAKE_NONCOPYABLE(LocalObjectMap);
</span></span></pre></div>
<a id="branchessafari612branchSourceWebKitLegacymacPluginsHostedNetscapePluginInstanceProxymm"></a>
<div class="modfile"><h4>Modified: branches/safari-612-branch/Source/WebKitLegacy/mac/Plugins/Hosted/NetscapePluginInstanceProxy.mm (282942 => 282943)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-612-branch/Source/WebKitLegacy/mac/Plugins/Hosted/NetscapePluginInstanceProxy.mm 2021-09-23 05:14:23 UTC (rev 282942)
+++ branches/safari-612-branch/Source/WebKitLegacy/mac/Plugins/Hosted/NetscapePluginInstanceProxy.mm    2021-09-23 05:14:29 UTC (rev 282943)
</span><span class="lines">@@ -1433,7 +1433,7 @@
</span><span class="cx">     return value;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void NetscapePluginInstanceProxy::demarshalValues(JSGlobalObject* lexicalGlobalObject, data_t valuesData, mach_msg_type_number_t valuesLength, MarkedArgumentBuffer& result)
</del><ins>+void NetscapePluginInstanceProxy::demarshalValues(JSGlobalObject* lexicalGlobalObject, data_t valuesData, mach_msg_type_number_t valuesLength, MarkedArgumentBufferBase& result)
</ins><span class="cx"> {
</span><span class="cx">     RetainPtr<NSData> data = adoptNS([[NSData alloc] initWithBytesNoCopy:valuesData length:valuesLength freeWhenDone:NO]);
</span><span class="cx"> 
</span></span></pre>
</div>
</div>

</body>
</html>