<!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>[210694] trunk/Source/JavaScriptCore</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/210694">210694</a></dd>
<dt>Author</dt> <dd>sbarati@apple.com</dd>
<dt>Date</dt> <dd>2017-01-12 19:12:09 -0800 (Thu, 12 Jan 2017)</dd>
</dl>
<h3>Log Message</h3>
<pre>Concurrent GC has a bug where we would detect a race but fail to rescan the object
https://bugs.webkit.org/show_bug.cgi?id=166960
<rdar://problem/29983526>
Reviewed by Filip Pizlo and Mark Lam.
We have code like this in JSC:
```
Butterfly* butterfly = allocateMoreOutOfLineStorage(vm, oldOutOfLineCapacity, newOutOfLineCapacity);
nukeStructureAndSetButterfly(vm, structureID, butterfly);
structure->setLastOffset(newLastOffset);
WTF::storeStoreFence();
setStructureIDDirectly(structureID);
```
Note that the collector could detect a race here, which sometimes
incorrectly caused us to not visit the object again.
Mutator Thread: M, Collector Thread: C, assuming sequential consistency via
proper barriers:
M: allocate new butterfly
M: Set nuked structure ID
M: Set butterfly (this does a barrier)
C: Start scanning O
C: load structure ID
C: See it's nuked and bail, (we used to rely on a write barrier to rescan).
We sometimes never rescanned here because we were calling
setStructureIDDirectly which doesn't do a write barrier.
(Note, the places that do this but call setStructure were
OK because setStructure will perform a write barrier.)
(This same issue also existed in places where the collector thread
detected races for Structure::m_offset, but places that changed
Structure::m_offset didn't perform a write barrier on the object
after changing its Structure's m_offset.)
To prevent such code from requiring every call site to perform
a write barrier on the object, I've changed the collector code
to keep a stack of cells to be revisited due to races. This stack
is then consulted when we do marking. Because such races are rare,
we have a single stack on Heap that is guarded by a lock.
* heap/Heap.cpp:
(JSC::Heap::Heap):
(JSC::Heap::~Heap):
(JSC::Heap::markToFixpoint):
(JSC::Heap::endMarking):
(JSC::Heap::buildConstraintSet):
(JSC::Heap::addToRaceMarkStack):
* heap/Heap.h:
(JSC::Heap::collectorSlotVisitor):
(JSC::Heap::mutatorMarkStack): Deleted.
* heap/SlotVisitor.cpp:
(JSC::SlotVisitor::didRace):
* heap/SlotVisitor.h:
(JSC::SlotVisitor::didRace):
(JSC::SlotVisitor::didNotRace): Deleted.
* heap/SlotVisitorInlines.h:
(JSC::SlotVisitor::didNotRace): Deleted.
* runtime/JSObject.cpp:
(JSC::JSObject::visitButterfly):
(JSC::JSObject::visitButterflyImpl):
* runtime/JSObjectInlines.h:
(JSC::JSObject::prepareToPutDirectWithoutTransition):
* runtime/Structure.cpp:
(JSC::Structure::flattenDictionaryStructure):</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapHeapcpp">trunk/Source/JavaScriptCore/heap/Heap.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapHeaph">trunk/Source/JavaScriptCore/heap/Heap.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapSlotVisitorcpp">trunk/Source/JavaScriptCore/heap/SlotVisitor.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapSlotVisitorh">trunk/Source/JavaScriptCore/heap/SlotVisitor.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapSlotVisitorInlinesh">trunk/Source/JavaScriptCore/heap/SlotVisitorInlines.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSObjectcpp">trunk/Source/JavaScriptCore/runtime/JSObject.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSObjectInlinesh">trunk/Source/JavaScriptCore/runtime/JSObjectInlines.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeStructurecpp">trunk/Source/JavaScriptCore/runtime/Structure.cpp</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (210693 => 210694)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2017-01-13 02:46:50 UTC (rev 210693)
+++ trunk/Source/JavaScriptCore/ChangeLog        2017-01-13 03:12:09 UTC (rev 210694)
</span><span class="lines">@@ -1,3 +1,75 @@
</span><ins>+2017-01-12 Saam Barati <sbarati@apple.com>
+
+ Concurrent GC has a bug where we would detect a race but fail to rescan the object
+ https://bugs.webkit.org/show_bug.cgi?id=166960
+ <rdar://problem/29983526>
+
+ Reviewed by Filip Pizlo and Mark Lam.
+
+ We have code like this in JSC:
+
+ ```
+ Butterfly* butterfly = allocateMoreOutOfLineStorage(vm, oldOutOfLineCapacity, newOutOfLineCapacity);
+ nukeStructureAndSetButterfly(vm, structureID, butterfly);
+ structure->setLastOffset(newLastOffset);
+ WTF::storeStoreFence();
+ setStructureIDDirectly(structureID);
+ ```
+
+ Note that the collector could detect a race here, which sometimes
+ incorrectly caused us to not visit the object again.
+
+ Mutator Thread: M, Collector Thread: C, assuming sequential consistency via
+ proper barriers:
+
+ M: allocate new butterfly
+ M: Set nuked structure ID
+ M: Set butterfly (this does a barrier)
+ C: Start scanning O
+ C: load structure ID
+ C: See it's nuked and bail, (we used to rely on a write barrier to rescan).
+
+ We sometimes never rescanned here because we were calling
+ setStructureIDDirectly which doesn't do a write barrier.
+ (Note, the places that do this but call setStructure were
+ OK because setStructure will perform a write barrier.)
+
+ (This same issue also existed in places where the collector thread
+ detected races for Structure::m_offset, but places that changed
+ Structure::m_offset didn't perform a write barrier on the object
+ after changing its Structure's m_offset.)
+
+ To prevent such code from requiring every call site to perform
+ a write barrier on the object, I've changed the collector code
+ to keep a stack of cells to be revisited due to races. This stack
+ is then consulted when we do marking. Because such races are rare,
+ we have a single stack on Heap that is guarded by a lock.
+
+ * heap/Heap.cpp:
+ (JSC::Heap::Heap):
+ (JSC::Heap::~Heap):
+ (JSC::Heap::markToFixpoint):
+ (JSC::Heap::endMarking):
+ (JSC::Heap::buildConstraintSet):
+ (JSC::Heap::addToRaceMarkStack):
+ * heap/Heap.h:
+ (JSC::Heap::collectorSlotVisitor):
+ (JSC::Heap::mutatorMarkStack): Deleted.
+ * heap/SlotVisitor.cpp:
+ (JSC::SlotVisitor::didRace):
+ * heap/SlotVisitor.h:
+ (JSC::SlotVisitor::didRace):
+ (JSC::SlotVisitor::didNotRace): Deleted.
+ * heap/SlotVisitorInlines.h:
+ (JSC::SlotVisitor::didNotRace): Deleted.
+ * runtime/JSObject.cpp:
+ (JSC::JSObject::visitButterfly):
+ (JSC::JSObject::visitButterflyImpl):
+ * runtime/JSObjectInlines.h:
+ (JSC::JSObject::prepareToPutDirectWithoutTransition):
+ * runtime/Structure.cpp:
+ (JSC::Structure::flattenDictionaryStructure):
+
</ins><span class="cx"> 2017-01-12 Chris Dumez <cdumez@apple.com>
</span><span class="cx">
</span><span class="cx"> Add KEYBOARD_KEY_ATTRIBUTE / KEYBOARD_CODE_ATTRIBUTE to FeatureDefines.xcconfig
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapHeapcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/Heap.cpp (210693 => 210694)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/Heap.cpp        2017-01-13 02:46:50 UTC (rev 210693)
+++ trunk/Source/JavaScriptCore/heap/Heap.cpp        2017-01-13 03:12:09 UTC (rev 210694)
</span><span class="lines">@@ -259,6 +259,7 @@
</span><span class="cx"> , m_machineThreads(this)
</span><span class="cx"> , m_collectorSlotVisitor(std::make_unique<SlotVisitor>(*this))
</span><span class="cx"> , m_mutatorMarkStack(std::make_unique<MarkStackArray>())
</span><ins>+ , m_raceMarkStack(std::make_unique<MarkStackArray>())
</ins><span class="cx"> , m_handleSet(vm)
</span><span class="cx"> , m_codeBlocks(std::make_unique<CodeBlockSet>())
</span><span class="cx"> , m_jitStubRoutines(std::make_unique<JITStubRoutineSet>())
</span><span class="lines">@@ -311,6 +312,7 @@
</span><span class="cx"> slotVisitor->clearMarkStacks();
</span><span class="cx"> m_collectorSlotVisitor->clearMarkStacks();
</span><span class="cx"> m_mutatorMarkStack->clear();
</span><ins>+ m_raceMarkStack->clear();
</ins><span class="cx">
</span><span class="cx"> for (WeakBlock* block : m_logicallyEmptyWeakBlocks)
</span><span class="cx"> WeakBlock::destroy(*this, block);
</span><span class="lines">@@ -526,6 +528,8 @@
</span><span class="cx"> m_mutatorMarkStack->clear();
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ RELEASE_ASSERT(m_raceMarkStack->isEmpty());
+
</ins><span class="cx"> beginMarking();
</span><span class="cx">
</span><span class="cx"> m_parallelMarkersShouldExit = false;
</span><span class="lines">@@ -785,11 +789,6 @@
</span><span class="cx">
</span><span class="cx"> void Heap::endMarking()
</span><span class="cx"> {
</span><del>- if (!m_visitRaces.isEmpty()) {
- dataLog("Unresolved visit races: ", listDump(m_visitRaces), "\n");
- RELEASE_ASSERT_NOT_REACHED();
- }
-
</del><span class="cx"> m_collectorSlotVisitor->reset();
</span><span class="cx">
</span><span class="cx"> for (auto& parallelVisitor : m_parallelSlotVisitors)
</span><span class="lines">@@ -797,6 +796,8 @@
</span><span class="cx">
</span><span class="cx"> assertSharedMarkStacksEmpty();
</span><span class="cx"> m_weakReferenceHarvesters.removeAll();
</span><ins>+
+ RELEASE_ASSERT(m_raceMarkStack->isEmpty());
</ins><span class="cx">
</span><span class="cx"> m_objectSpace.endMarking();
</span><span class="cx"> setMutatorShouldBeFenced(Options::forceFencedBarrier());
</span><span class="lines">@@ -2252,10 +2253,10 @@
</span><span class="cx"> MarkingConstraint::GreyedByExecution);
</span><span class="cx">
</span><span class="cx"> m_constraintSet->add(
</span><del>- "Mms", "Mutator Mark Stack",
</del><ins>+ "Mrms", "Mutator+Race Mark Stack",
</ins><span class="cx"> [this] (SlotVisitor& slotVisitor, const VisitingTimeout&) {
</span><span class="cx"> // Indicate to the fixpoint that we introduced work!
</span><del>- size_t size = m_mutatorMarkStack->size();
</del><ins>+ size_t size = m_mutatorMarkStack->size() + m_raceMarkStack->size();
</ins><span class="cx"> slotVisitor.addToVisitCount(size);
</span><span class="cx">
</span><span class="cx"> if (Options::logGC())
</span><span class="lines">@@ -2262,9 +2263,10 @@
</span><span class="cx"> dataLog("(", size, ")");
</span><span class="cx">
</span><span class="cx"> m_mutatorMarkStack->transferTo(slotVisitor.mutatorMarkStack());
</span><ins>+ m_raceMarkStack->transferTo(slotVisitor.mutatorMarkStack());
</ins><span class="cx"> },
</span><span class="cx"> [this] (SlotVisitor&) -> double {
</span><del>- return m_mutatorMarkStack->size();
</del><ins>+ return m_mutatorMarkStack->size() + m_raceMarkStack->size();
</ins><span class="cx"> },
</span><span class="cx"> MarkingConstraint::GreyedByExecution);
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapHeaph"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/Heap.h (210693 => 210694)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/Heap.h        2017-01-13 02:46:50 UTC (rev 210693)
+++ trunk/Source/JavaScriptCore/heap/Heap.h        2017-01-13 03:12:09 UTC (rev 210694)
</span><span class="lines">@@ -139,7 +139,6 @@
</span><span class="cx"> MachineThreads& machineThreads() { return m_machineThreads; }
</span><span class="cx">
</span><span class="cx"> SlotVisitor& collectorSlotVisitor() { return *m_collectorSlotVisitor; }
</span><del>- MarkStackArray& mutatorMarkStack() { return *m_mutatorMarkStack; }
</del><span class="cx">
</span><span class="cx"> JS_EXPORT_PRIVATE GCActivityCallback* fullActivityCallback();
</span><span class="cx"> JS_EXPORT_PRIVATE GCActivityCallback* edenActivityCallback();
</span><span class="lines">@@ -540,7 +539,10 @@
</span><span class="cx">
</span><span class="cx"> std::unique_ptr<SlotVisitor> m_collectorSlotVisitor;
</span><span class="cx"> std::unique_ptr<MarkStackArray> m_mutatorMarkStack;
</span><del>-
</del><ins>+
+ Lock m_raceMarkStackLock;
+ std::unique_ptr<MarkStackArray> m_raceMarkStack;
+
</ins><span class="cx"> std::unique_ptr<MarkingConstraintSet> m_constraintSet;
</span><span class="cx">
</span><span class="cx"> // We pool the slot visitors used by parallel marking threads. It's useful to be able to
</span><span class="lines">@@ -597,7 +599,6 @@
</span><span class="cx">
</span><span class="cx"> HashMap<void*, std::function<void()>> m_weakGCMaps;
</span><span class="cx">
</span><del>- HashSet<VisitRaceKey> m_visitRaces;
</del><span class="cx"> Lock m_visitRaceLock;
</span><span class="cx">
</span><span class="cx"> Lock m_markingMutex;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapSlotVisitorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/SlotVisitor.cpp (210693 => 210694)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/SlotVisitor.cpp        2017-01-13 02:46:50 UTC (rev 210693)
+++ trunk/Source/JavaScriptCore/heap/SlotVisitor.cpp        2017-01-13 03:12:09 UTC (rev 210694)
</span><span class="lines">@@ -284,7 +284,6 @@
</span><span class="cx"> {
</span><span class="cx"> ASSERT(Heap::isMarkedConcurrently(cell));
</span><span class="cx"> ASSERT(!cell->isZapped());
</span><del>- ASSERT(cell->cellState() == CellState::PossiblyGrey);
</del><span class="cx">
</span><span class="cx"> container.noteMarked();
</span><span class="cx">
</span><span class="lines">@@ -702,10 +701,10 @@
</span><span class="cx"> if (Options::verboseVisitRace())
</span><span class="cx"> dataLog(toCString("GC visit race: ", race, "\n"));
</span><span class="cx">
</span><del>- if (!ASSERT_DISABLED) {
- auto locker = holdLock(heap()->m_visitRaceLock);
- heap()->m_visitRaces.add(race);
- }
</del><ins>+ auto locker = holdLock(heap()->m_raceMarkStackLock);
+ JSCell* cell = race.cell();
+ cell->setCellState(CellState::PossiblyGrey);
+ heap()->m_raceMarkStack->append(cell);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> void SlotVisitor::dump(PrintStream& out) const
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapSlotVisitorh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/SlotVisitor.h (210693 => 210694)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/SlotVisitor.h        2017-01-13 02:46:50 UTC (rev 210693)
+++ trunk/Source/JavaScriptCore/heap/SlotVisitor.h        2017-01-13 03:12:09 UTC (rev 210694)
</span><span class="lines">@@ -151,8 +151,6 @@
</span><span class="cx">
</span><span class="cx"> void didRace(const VisitRaceKey&);
</span><span class="cx"> void didRace(JSCell* cell, const char* reason) { didRace(VisitRaceKey(cell, reason)); }
</span><del>- void didNotRace(const VisitRaceKey&);
- void didNotRace(JSCell* cell, const char* reason) { didNotRace(VisitRaceKey(cell, reason)); }
</del><span class="cx">
</span><span class="cx"> void visitAsConstraint(const JSCell*);
</span><span class="cx">
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapSlotVisitorInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/SlotVisitorInlines.h (210693 => 210694)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/SlotVisitorInlines.h        2017-01-13 02:46:50 UTC (rev 210693)
+++ trunk/Source/JavaScriptCore/heap/SlotVisitorInlines.h        2017-01-13 03:12:09 UTC (rev 210694)
</span><span class="lines">@@ -108,18 +108,4 @@
</span><span class="cx"> return *m_heap.m_vm;
</span><span class="cx"> }
</span><span class="cx">
</span><del>-inline void SlotVisitor::didNotRace(const VisitRaceKey& race)
-{
- if (ASSERT_DISABLED)
- return;
-
- if (!m_isVisitingMutatorStack) {
- // This is the first visit so we don't need to remove anything.
- return;
- }
-
- auto locker = holdLock(heap()->m_visitRaceLock);
- heap()->m_visitRaces.remove(race);
-}
-
</del><span class="cx"> } // namespace JSC
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSObjectcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSObject.cpp (210693 => 210694)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSObject.cpp        2017-01-13 02:46:50 UTC (rev 210693)
+++ trunk/Source/JavaScriptCore/runtime/JSObject.cpp        2017-01-13 03:12:09 UTC (rev 210694)
</span><span class="lines">@@ -120,9 +120,7 @@
</span><span class="cx"> {
</span><span class="cx"> static const char* raceReason = "JSObject::visitButterfly";
</span><span class="cx"> Structure* result = visitButterflyImpl(visitor);
</span><del>- if (result)
- visitor.didNotRace(this, raceReason);
- else
</del><ins>+ if (!result)
</ins><span class="cx"> visitor.didRace(this, raceReason);
</span><span class="cx"> return result;
</span><span class="cx"> }
</span><span class="lines">@@ -188,7 +186,7 @@
</span><span class="cx"> //
</span><span class="cx"> // BEFORE: Scan the object with the structure and butterfly *before* the mutator's transition.
</span><span class="cx"> // AFTER: Scan the object with the structure and butterfly *after* the mutator's transition.
</span><del>- // IGNORE: Give up, so long as the write barrier on PutNewStructure executes after ReadStructureEarly.
</del><ins>+ // IGNORE: Ignore the butterfly and call didRace to schedule us to be revisted again in the future.
</ins><span class="cx"> //
</span><span class="cx"> // In other words, the collector will never see any torn structure/butterfly mix. It will
</span><span class="cx"> // always see the structure/butterfly before the transition or after but not in between.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSObjectInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSObjectInlines.h (210693 => 210694)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSObjectInlines.h        2017-01-13 02:46:50 UTC (rev 210693)
+++ trunk/Source/JavaScriptCore/runtime/JSObjectInlines.h        2017-01-13 03:12:09 UTC (rev 210694)
</span><span class="lines">@@ -183,6 +183,7 @@
</span><span class="cx"> Butterfly* butterfly = allocateMoreOutOfLineStorage(vm, oldOutOfLineCapacity, newOutOfLineCapacity);
</span><span class="cx"> nukeStructureAndSetButterfly(vm, structureID, butterfly);
</span><span class="cx"> structure->setLastOffset(newLastOffset);
</span><ins>+ WTF::storeStoreFence();
</ins><span class="cx"> setStructureIDDirectly(structureID);
</span><span class="cx"> } else
</span><span class="cx"> structure->setLastOffset(newLastOffset);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeStructurecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/Structure.cpp (210693 => 210694)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/Structure.cpp        2017-01-13 02:46:50 UTC (rev 210693)
+++ trunk/Source/JavaScriptCore/runtime/Structure.cpp        2017-01-13 03:12:09 UTC (rev 210694)
</span><span class="lines">@@ -793,10 +793,14 @@
</span><span class="cx"> object->shiftButterflyAfterFlattening(locker, vm, this, afterOutOfLineCapacity);
</span><span class="cx"> }
</span><span class="cx">
</span><del>- vm.heap.writeBarrier(object);
</del><span class="cx"> WTF::storeStoreFence();
</span><span class="cx"> object->setStructureIDDirectly(id());
</span><del>-
</del><ins>+
+ // FIXME: This is probably no longer needed since we have a stronger mechanism
+ // for detecting races and rescanning an object.
+ // https://bugs.webkit.org/show_bug.cgi?id=166989
+ vm.heap.writeBarrier(object);
+
</ins><span class="cx"> return this;
</span><span class="cx"> }
</span><span class="cx">
</span></span></pre>
</div>
</div>
</body>
</html>