<!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>[247888] 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/247888">247888</a></dd>
<dt>Author</dt> <dd>ysuzuki@apple.com</dd>
<dt>Date</dt> <dd>2019-07-26 21:55:11 -0700 (Fri, 26 Jul 2019)</dd>
</dl>

<h3>Log Message</h3>
<pre>[JSC] Potential GC fix for JSPropertyNameEnumerator
https://bugs.webkit.org/show_bug.cgi?id=200151

Reviewed by Mark Lam.

JSTests:

* stress/for-in-stress.js: Added.
(keys):

Source/JavaScriptCore:

We have been seeing some JSPropertyNameEnumerator::visitChildren crashes for a long time. The crash frequency itself is not high, but it has existed for a long time.
The crash happens when visiting m_propertyNames. It is also possible that this crash is caused by random corruption somewhere, but JSPropertyNameEnumerator
has some tricky (and potentially dangerous) implementations anyway.

1. JSPropertyNameEnumerator have Vector<WriteBarrier<JSString>> and it is extended in finishCreation with a lock.
   We should use Auxiliary memory for this use case. And we should set this memory in the constructor so that
   we do not extend it in finishCreation, and we do not need a lock.
2. JSPropertyNameEnumerator gets StructureID before allocating JSPropertyNameEnumerator. This is potentially dangerous because the conservative scan
   cannot find the Structure* since we could only have StructureID. Since allocation code happens after StructureID is retrieved, it is possible that
   the allocation causes GC and Structure* is collected.

In this patch, we align JSPropertyNameEnumerator implementation to the modern one to avoid using Vector<WriteBarrier<JSString>>. And we can make JSPropertyNameEnumerator
a non-destructible cell. Since JSCell's destructor is one of the cause of various issues, we should avoid it if we can.

No behavior change. This patch adds a test stressing JSPropertyNameEnumerator.

* dfg/DFGOperations.cpp:
* runtime/CommonSlowPaths.cpp:
(JSC::SLOW_PATH_DECL):
* runtime/JSPropertyNameEnumerator.cpp:
(JSC::JSPropertyNameEnumerator::create):
(JSC::JSPropertyNameEnumerator::JSPropertyNameEnumerator):
(JSC::JSPropertyNameEnumerator::finishCreation):
(JSC::JSPropertyNameEnumerator::visitChildren):
(JSC::JSPropertyNameEnumerator::destroy): Deleted.
* runtime/JSPropertyNameEnumerator.h:
* runtime/VM.cpp:
(JSC::VM::emptyPropertyNameEnumeratorSlow):
* runtime/VM.h:
(JSC::VM::emptyPropertyNameEnumerator):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkJSTestsChangeLog">trunk/JSTests/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGOperationscpp">trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeCommonSlowPathscpp">trunk/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSPropertyNameEnumeratorcpp">trunk/Source/JavaScriptCore/runtime/JSPropertyNameEnumerator.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSPropertyNameEnumeratorh">trunk/Source/JavaScriptCore/runtime/JSPropertyNameEnumerator.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeVMcpp">trunk/Source/JavaScriptCore/runtime/VM.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeVMh">trunk/Source/JavaScriptCore/runtime/VM.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkJSTestsstressforinstressjs">trunk/JSTests/stress/for-in-stress.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkJSTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/ChangeLog (247887 => 247888)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/ChangeLog  2019-07-27 02:18:41 UTC (rev 247887)
+++ trunk/JSTests/ChangeLog     2019-07-27 04:55:11 UTC (rev 247888)
</span><span class="lines">@@ -1,3 +1,13 @@
</span><ins>+2019-07-26  Yusuke Suzuki  <ysuzuki@apple.com>
+
+        [JSC] Potential GC fix for JSPropertyNameEnumerator
+        https://bugs.webkit.org/show_bug.cgi?id=200151
+
+        Reviewed by Mark Lam.
+
+        * stress/for-in-stress.js: Added.
+        (keys):
+
</ins><span class="cx"> 2019-07-25  Ross Kirsling  <ross.kirsling@sony.com>
</span><span class="cx"> 
</span><span class="cx">         Legacy numeric literals should not permit separators or BigInt
</span></span></pre></div>
<a id="trunkJSTestsstressforinstressjs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/stress/for-in-stress.js (0 => 247888)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/stress/for-in-stress.js                            (rev 0)
+++ trunk/JSTests/stress/for-in-stress.js       2019-07-27 04:55:11 UTC (rev 247888)
</span><span class="lines">@@ -0,0 +1,29 @@
</span><ins>+var counter = 0;
+function keys(a, b, c) {
+    for (var i in a) {
+        for (var j in b) {
+            for (var k in c) {
+            }
+        }
+    }
+    if ((++counter) % 1000 === 0)
+        gc();
+}
+noInline(keys);
+
+var dictionary = {
+    0: 2,
+    "Hey": "Hello",
+    "World": 32.4,
+    "deleted": 20,
+};
+delete dictionary["deleted"];
+for (var i = 0; i < 1e4; ++i) {
+    keys([], [20], ["Hey"]);
+    keys(["OK", 30], { Hello: 0, World: 2 }, []);
+    keys(["OK", 30], { Hello: 0, World: 2 }, [42]);
+    keys(["OK", 30], [], { Hello: 0, World: 2 });
+    keys(["OK", 30], [2.5, 3.7], dictionary);
+    keys(dictionary, { Hello: 0, World: 2 }, dictionary);
+    keys({ Hello: 0, World: 2 }, dictionary, { Hello: 0, World: 2, 3:42 });
+}
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (247887 => 247888)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog    2019-07-27 02:18:41 UTC (rev 247887)
+++ trunk/Source/JavaScriptCore/ChangeLog       2019-07-27 04:55:11 UTC (rev 247888)
</span><span class="lines">@@ -1,3 +1,41 @@
</span><ins>+2019-07-26  Yusuke Suzuki  <ysuzuki@apple.com>
+
+        [JSC] Potential GC fix for JSPropertyNameEnumerator
+        https://bugs.webkit.org/show_bug.cgi?id=200151
+
+        Reviewed by Mark Lam.
+
+        We have been seeing some JSPropertyNameEnumerator::visitChildren crashes for a long time. The crash frequency itself is not high, but it has existed for a long time.
+        The crash happens when visiting m_propertyNames. It is also possible that this crash is caused by random corruption somewhere, but JSPropertyNameEnumerator
+        has some tricky (and potentially dangerous) implementations anyway.
+
+        1. JSPropertyNameEnumerator have Vector<WriteBarrier<JSString>> and it is extended in finishCreation with a lock.
+           We should use Auxiliary memory for this use case. And we should set this memory in the constructor so that
+           we do not extend it in finishCreation, and we do not need a lock.
+        2. JSPropertyNameEnumerator gets StructureID before allocating JSPropertyNameEnumerator. This is potentially dangerous because the conservative scan
+           cannot find the Structure* since we could only have StructureID. Since allocation code happens after StructureID is retrieved, it is possible that
+           the allocation causes GC and Structure* is collected.
+
+        In this patch, we align JSPropertyNameEnumerator implementation to the modern one to avoid using Vector<WriteBarrier<JSString>>. And we can make JSPropertyNameEnumerator
+        a non-destructible cell. Since JSCell's destructor is one of the cause of various issues, we should avoid it if we can.
+
+        No behavior change. This patch adds a test stressing JSPropertyNameEnumerator.
+
+        * dfg/DFGOperations.cpp:
+        * runtime/CommonSlowPaths.cpp:
+        (JSC::SLOW_PATH_DECL):
+        * runtime/JSPropertyNameEnumerator.cpp:
+        (JSC::JSPropertyNameEnumerator::create):
+        (JSC::JSPropertyNameEnumerator::JSPropertyNameEnumerator):
+        (JSC::JSPropertyNameEnumerator::finishCreation):
+        (JSC::JSPropertyNameEnumerator::visitChildren):
+        (JSC::JSPropertyNameEnumerator::destroy): Deleted.
+        * runtime/JSPropertyNameEnumerator.h:
+        * runtime/VM.cpp:
+        (JSC::VM::emptyPropertyNameEnumeratorSlow):
+        * runtime/VM.h:
+        (JSC::VM::emptyPropertyNameEnumerator):
+
</ins><span class="cx"> 2019-07-26  Mark Lam  <mark.lam@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Add crash diagnostics for debugging unexpected zapped cells.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGOperationscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp (247887 => 247888)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp        2019-07-27 02:18:41 UTC (rev 247887)
+++ trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp   2019-07-27 04:55:11 UTC (rev 247888)
</span><span class="lines">@@ -2162,7 +2162,7 @@
</span><span class="cx"> 
</span><span class="cx">     JSValue base = JSValue::decode(encodedBase);
</span><span class="cx">     if (base.isUndefinedOrNull())
</span><del>-        return JSPropertyNameEnumerator::create(vm);
</del><ins>+        return vm.emptyPropertyNameEnumerator();
</ins><span class="cx"> 
</span><span class="cx">     JSObject* baseObject = base.toObject(exec);
</span><span class="cx">     RETURN_IF_EXCEPTION(scope, { });
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeCommonSlowPathscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp (247887 => 247888)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp  2019-07-27 02:18:41 UTC (rev 247887)
+++ trunk/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp     2019-07-27 04:55:11 UTC (rev 247888)
</span><span class="lines">@@ -972,7 +972,7 @@
</span><span class="cx">     auto bytecode = pc->as<OpGetPropertyEnumerator>();
</span><span class="cx">     JSValue baseValue = GET(bytecode.m_base).jsValue();
</span><span class="cx">     if (baseValue.isUndefinedOrNull())
</span><del>-        RETURN(JSPropertyNameEnumerator::create(vm));
</del><ins>+        RETURN(vm.emptyPropertyNameEnumerator());
</ins><span class="cx"> 
</span><span class="cx">     JSObject* base = baseValue.toObject(exec);
</span><span class="cx">     CHECK_EXCEPTION();
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSPropertyNameEnumeratorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSPropertyNameEnumerator.cpp (247887 => 247888)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSPropertyNameEnumerator.cpp 2019-07-27 02:18:41 UTC (rev 247887)
+++ trunk/Source/JavaScriptCore/runtime/JSPropertyNameEnumerator.cpp    2019-07-27 04:55:11 UTC (rev 247888)
</span><span class="lines">@@ -34,65 +34,53 @@
</span><span class="cx"> 
</span><span class="cx"> const ClassInfo JSPropertyNameEnumerator::s_info = { "JSPropertyNameEnumerator", nullptr, nullptr, nullptr, CREATE_METHOD_TABLE(JSPropertyNameEnumerator) };
</span><span class="cx"> 
</span><del>-JSPropertyNameEnumerator* JSPropertyNameEnumerator::create(VM& vm)
</del><ins>+JSPropertyNameEnumerator* JSPropertyNameEnumerator::create(VM& vm, Structure* structure, uint32_t indexedLength, uint32_t numberStructureProperties, PropertyNameArray&& propertyNames)
</ins><span class="cx"> {
</span><del>-    if (!vm.emptyPropertyNameEnumerator.get()) {
-        PropertyNameArray propertyNames(&vm, PropertyNameMode::Strings, PrivateSymbolMode::Exclude);
-        vm.emptyPropertyNameEnumerator = Strong<JSCell>(vm, create(vm, 0, 0, 0, WTFMove(propertyNames)));
</del><ins>+    unsigned propertyNamesSize = propertyNames.size();
+    unsigned propertyNamesBufferSizeInBytes = (Checked<unsigned>(propertyNamesSize) * sizeof(WriteBarrier<JSString>)).unsafeGet();
+    WriteBarrier<JSString>* propertyNamesBuffer = nullptr;
+    if (propertyNamesBufferSizeInBytes) {
+        propertyNamesBuffer = static_cast<WriteBarrier<JSString>*>(vm.jsValueGigacageAuxiliarySpace.allocateNonVirtual(vm, propertyNamesBufferSizeInBytes, nullptr, AllocationFailureMode::Assert));
+        for (unsigned i = 0; i < propertyNamesSize; ++i)
+            propertyNamesBuffer[i].clear();
</ins><span class="cx">     }
</span><del>-    return jsCast<JSPropertyNameEnumerator*>(vm.emptyPropertyNameEnumerator.get());
-}
-
-JSPropertyNameEnumerator* JSPropertyNameEnumerator::create(VM& vm, Structure* structure, uint32_t indexedLength, uint32_t numberStructureProperties, PropertyNameArray&& propertyNames)
-{
-    StructureID structureID = structure ? structure->id() : 0;
-    uint32_t inlineCapacity = structure ? structure->inlineCapacity() : 0;
-    JSPropertyNameEnumerator* enumerator = new (NotNull, 
-        allocateCell<JSPropertyNameEnumerator>(vm.heap)) JSPropertyNameEnumerator(vm, structureID, inlineCapacity);
-    enumerator->finishCreation(vm, indexedLength, numberStructureProperties, propertyNames.releaseData());
</del><ins>+    JSPropertyNameEnumerator* enumerator = new (NotNull, allocateCell<JSPropertyNameEnumerator>(vm.heap)) JSPropertyNameEnumerator(vm, structure, indexedLength, numberStructureProperties, propertyNamesBuffer, propertyNamesSize);
+    enumerator->finishCreation(vm, propertyNames.releaseData());
</ins><span class="cx">     return enumerator;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-JSPropertyNameEnumerator::JSPropertyNameEnumerator(VM& vm, StructureID structureID, uint32_t inlineCapacity)
</del><ins>+JSPropertyNameEnumerator::JSPropertyNameEnumerator(VM& vm, Structure* structure, uint32_t indexedLength, uint32_t numberStructureProperties, WriteBarrier<JSString>* propertyNamesBuffer, unsigned propertyNamesSize)
</ins><span class="cx">     : JSCell(vm, vm.propertyNameEnumeratorStructure.get())
</span><del>-    , m_cachedStructureID(structureID)
-    , m_cachedInlineCapacity(inlineCapacity)
</del><ins>+    , m_propertyNames(vm, this, propertyNamesBuffer)
+    , m_cachedStructureID(structure ? structure->id() : 0)
+    , m_indexedLength(indexedLength)
+    , m_endStructurePropertyIndex(numberStructureProperties)
+    , m_endGenericPropertyIndex(propertyNamesSize)
+    , m_cachedInlineCapacity(structure ? structure->inlineCapacity() : 0)
</ins><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void JSPropertyNameEnumerator::finishCreation(VM& vm, uint32_t indexedLength, uint32_t endStructurePropertyIndex, RefPtr<PropertyNameArrayData>&& identifiers)
</del><ins>+void JSPropertyNameEnumerator::finishCreation(VM& vm, RefPtr<PropertyNameArrayData>&& identifiers)
</ins><span class="cx"> {
</span><span class="cx">     Base::finishCreation(vm);
</span><span class="cx"> 
</span><span class="cx">     PropertyNameArrayData::PropertyNameVector& vector = identifiers->propertyNameVector();
</span><del>-
-    m_indexedLength = indexedLength;
-    m_endStructurePropertyIndex = endStructurePropertyIndex;
-    m_endGenericPropertyIndex = vector.size();
-
-    {
-        auto locker = lockDuringMarking(vm.heap, cellLock());
-        m_propertyNames.resizeToFit(vector.size());
-    }
</del><ins>+    ASSERT(m_endGenericPropertyIndex == vector.size());
</ins><span class="cx">     for (unsigned i = 0; i < vector.size(); ++i) {
</span><span class="cx">         const Identifier& identifier = vector[i];
</span><del>-        m_propertyNames[i].set(vm, this, jsString(&vm, identifier.string()));
</del><ins>+        m_propertyNames.get()[i].set(vm, this, jsString(&vm, identifier.string()));
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void JSPropertyNameEnumerator::destroy(JSCell* cell)
-{
-    static_cast<JSPropertyNameEnumerator*>(cell)->JSPropertyNameEnumerator::~JSPropertyNameEnumerator();
-}
-
</del><span class="cx"> void JSPropertyNameEnumerator::visitChildren(JSCell* cell, SlotVisitor& visitor)
</span><span class="cx"> {
</span><span class="cx">     JSPropertyNameEnumerator* thisObject = jsCast<JSPropertyNameEnumerator*>(cell);
</span><span class="cx">     ASSERT_GC_OBJECT_INHERITS(thisObject, info());
</span><span class="cx">     Base::visitChildren(cell, visitor);
</span><del>-    auto locker = holdLock(thisObject->cellLock());
-    for (auto& propertyName : thisObject->m_propertyNames)
-        visitor.append(propertyName);
</del><ins>+    if (auto* propertyNames = thisObject->m_propertyNames.get()) {
+        visitor.markAuxiliary(propertyNames);
+        visitor.append(propertyNames, propertyNames + thisObject->sizeOfPropertyNames());
+    }
</ins><span class="cx">     visitor.append(thisObject->m_prototypeChain);
</span><span class="cx"> 
</span><span class="cx">     if (thisObject->cachedStructureID()) {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSPropertyNameEnumeratorh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSPropertyNameEnumerator.h (247887 => 247888)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSPropertyNameEnumerator.h   2019-07-27 02:18:41 UTC (rev 247887)
+++ trunk/Source/JavaScriptCore/runtime/JSPropertyNameEnumerator.h      2019-07-27 04:55:11 UTC (rev 247888)
</span><span class="lines">@@ -34,15 +34,11 @@
</span><span class="cx"> 
</span><span class="cx"> class JSPropertyNameEnumerator final : public JSCell {
</span><span class="cx"> public:
</span><del>-    typedef JSCell Base;
</del><ins>+    using Base = JSCell;
</ins><span class="cx">     static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
</span><span class="cx"> 
</span><del>-    static JSPropertyNameEnumerator* create(VM&);
</del><span class="cx">     static JSPropertyNameEnumerator* create(VM&, Structure*, uint32_t, uint32_t, PropertyNameArray&&);
</span><span class="cx"> 
</span><del>-    static const bool needsDestruction = true;
-    static void destroy(JSCell*);
-
</del><span class="cx">     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
</span><span class="cx">     {
</span><span class="cx">         return Structure::create(vm, globalObject, prototype, TypeInfo(CellType, StructureFlags), info());
</span><span class="lines">@@ -50,11 +46,11 @@
</span><span class="cx"> 
</span><span class="cx">     DECLARE_EXPORT_INFO;
</span><span class="cx"> 
</span><del>-    JSString* propertyNameAtIndex(uint32_t index) const
</del><ins>+    JSString* propertyNameAtIndex(uint32_t index)
</ins><span class="cx">     {
</span><del>-        if (index >= m_propertyNames.size())
</del><ins>+        if (index >= sizeOfPropertyNames())
</ins><span class="cx">             return nullptr;
</span><del>-        return m_propertyNames[index].get();
</del><ins>+        return m_propertyNames.get()[index].get();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     StructureChain* cachedPrototypeChain() const { return m_prototypeChain.get(); }
</span><span class="lines">@@ -71,6 +67,7 @@
</span><span class="cx">     uint32_t endStructurePropertyIndex() const { return m_endStructurePropertyIndex; }
</span><span class="cx">     uint32_t endGenericPropertyIndex() const { return m_endGenericPropertyIndex; }
</span><span class="cx">     uint32_t cachedInlineCapacity() const { return m_cachedInlineCapacity; }
</span><ins>+    uint32_t sizeOfPropertyNames() const { return endGenericPropertyIndex(); }
</ins><span class="cx">     static ptrdiff_t cachedStructureIDOffset() { return OBJECT_OFFSETOF(JSPropertyNameEnumerator, m_cachedStructureID); }
</span><span class="cx">     static ptrdiff_t indexedLengthOffset() { return OBJECT_OFFSETOF(JSPropertyNameEnumerator, m_indexedLength); }
</span><span class="cx">     static ptrdiff_t endStructurePropertyIndexOffset() { return OBJECT_OFFSETOF(JSPropertyNameEnumerator, m_endStructurePropertyIndex); }
</span><span class="lines">@@ -78,18 +75,18 @@
</span><span class="cx">     static ptrdiff_t cachedInlineCapacityOffset() { return OBJECT_OFFSETOF(JSPropertyNameEnumerator, m_cachedInlineCapacity); }
</span><span class="cx">     static ptrdiff_t cachedPropertyNamesVectorOffset()
</span><span class="cx">     {
</span><del>-        return OBJECT_OFFSETOF(JSPropertyNameEnumerator, m_propertyNames) + Vector<WriteBarrier<JSString>>::dataMemoryOffset();
</del><ins>+        return OBJECT_OFFSETOF(JSPropertyNameEnumerator, m_propertyNames);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     static void visitChildren(JSCell*, SlotVisitor&);
</span><span class="cx"> 
</span><span class="cx"> private:
</span><del>-    JSPropertyNameEnumerator(VM&, StructureID, uint32_t);
-    void finishCreation(VM&, uint32_t, uint32_t, RefPtr<PropertyNameArrayData>&&);
</del><ins>+    JSPropertyNameEnumerator(VM&, Structure*, uint32_t, uint32_t, WriteBarrier<JSString>*, unsigned);
+    void finishCreation(VM&, RefPtr<PropertyNameArrayData>&&);
</ins><span class="cx"> 
</span><del>-    Vector<WriteBarrier<JSString>> m_propertyNames;
</del><ins>+    AuxiliaryBarrier<WriteBarrier<JSString>*> m_propertyNames;
+    WriteBarrier<StructureChain> m_prototypeChain;
</ins><span class="cx">     StructureID m_cachedStructureID;
</span><del>-    WriteBarrier<StructureChain> m_prototypeChain;
</del><span class="cx">     uint32_t m_indexedLength;
</span><span class="cx">     uint32_t m_endStructurePropertyIndex;
</span><span class="cx">     uint32_t m_endGenericPropertyIndex;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeVMcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/VM.cpp (247887 => 247888)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/VM.cpp       2019-07-27 02:18:41 UTC (rev 247887)
+++ trunk/Source/JavaScriptCore/runtime/VM.cpp  2019-07-27 04:55:11 UTC (rev 247888)
</span><span class="lines">@@ -1308,6 +1308,15 @@
</span><span class="cx">     return sentinel;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+JSPropertyNameEnumerator* VM::emptyPropertyNameEnumeratorSlow()
+{
+    ASSERT(!m_emptyPropertyNameEnumerator);
+    PropertyNameArray propertyNames(this, PropertyNameMode::Strings, PrivateSymbolMode::Exclude);
+    auto* enumerator = JSPropertyNameEnumerator::create(*this, nullptr, 0, 0, WTFMove(propertyNames));
+    m_emptyPropertyNameEnumerator.set(*this, enumerator);
+    return enumerator;
+}
+
</ins><span class="cx"> JSGlobalObject* VM::vmEntryGlobalObject(const CallFrame* callFrame) const
</span><span class="cx"> {
</span><span class="cx">     if (callFrame && callFrame->isGlobalExec()) {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeVMh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/VM.h (247887 => 247888)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/VM.h 2019-07-27 02:18:41 UTC (rev 247887)
+++ trunk/Source/JavaScriptCore/runtime/VM.h    2019-07-27 04:55:11 UTC (rev 247888)
</span><span class="lines">@@ -123,6 +123,7 @@
</span><span class="cx"> class JSDestructibleObjectHeapCellType;
</span><span class="cx"> class JSGlobalObject;
</span><span class="cx"> class JSObject;
</span><ins>+class JSPropertyNameEnumerator;
</ins><span class="cx"> class JSRunLoopTimer;
</span><span class="cx"> class JSStringHeapCellType;
</span><span class="cx"> class JSWebAssemblyCodeBlockHeapCellType;
</span><span class="lines">@@ -545,7 +546,7 @@
</span><span class="cx">     Strong<Structure> m_setIteratorStructure;
</span><span class="cx">     Strong<Structure> m_mapIteratorStructure;
</span><span class="cx"> 
</span><del>-    Strong<JSCell> emptyPropertyNameEnumerator;
</del><ins>+    Strong<JSPropertyNameEnumerator> m_emptyPropertyNameEnumerator;
</ins><span class="cx"> 
</span><span class="cx">     Strong<JSCell> m_sentinelSetBucket;
</span><span class="cx">     Strong<JSCell> m_sentinelMapBucket;
</span><span class="lines">@@ -598,6 +599,13 @@
</span><span class="cx">         return sentinelMapBucketSlow();
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    JSPropertyNameEnumerator* emptyPropertyNameEnumerator()
+    {
+        if (LIKELY(m_emptyPropertyNameEnumerator))
+            return m_emptyPropertyNameEnumerator.get();
+        return emptyPropertyNameEnumeratorSlow();
+    }
+
</ins><span class="cx">     WeakGCMap<SymbolImpl*, Symbol, PtrHash<SymbolImpl*>> symbolImplToSymbolMap;
</span><span class="cx"> 
</span><span class="cx">     enum class DeletePropertyMode {
</span><span class="lines">@@ -953,6 +961,7 @@
</span><span class="cx">     JS_EXPORT_PRIVATE Structure* mapIteratorStructureSlow();
</span><span class="cx">     JSCell* sentinelSetBucketSlow();
</span><span class="cx">     JSCell* sentinelMapBucketSlow();
</span><ins>+    JSPropertyNameEnumerator* emptyPropertyNameEnumeratorSlow();
</ins><span class="cx"> 
</span><span class="cx">     void updateStackLimits();
</span><span class="cx"> 
</span></span></pre>
</div>
</div>

</body>
</html>