Bug 1313347 - Ensure we don't trigger another GC while collecting r=sfink
authorJon Coppeard <jcoppeard@mozilla.com>
Fri, 04 Nov 2016 17:32:36 +0000
changeset 347738 a5d8d7e811c1cfdb813560df4265d224284c4fb0
parent 347737 0f246bb6108c125377deb37e91d473c998ced132
child 347739 24ed6f84d8239ea380f6c8c75f3c1ee7668dc432
push id10298
push userraliiev@mozilla.com
push dateMon, 14 Nov 2016 12:33:03 +0000
treeherdermozilla-aurora@7e29173b1641 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssfink
bugs1313347
milestone52.0a1
Bug 1313347 - Ensure we don't trigger another GC while collecting r=sfink
js/src/gc/Marking.cpp
js/src/jit-test/tests/gc/bug-1313347.js
js/src/jsgc.cpp
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -2248,17 +2248,18 @@ TenuringTracer::traverse(T* thingp)
 
 template <typename T>
 void
 js::gc::StoreBuffer::MonoTypeBuffer<T>::trace(StoreBuffer* owner, TenuringTracer& mover)
 {
     mozilla::ReentrancyGuard g(*owner);
     MOZ_ASSERT(owner->isEnabled());
     MOZ_ASSERT(stores_.initialized());
-    sinkStore(owner);
+    if (last_)
+        last_.trace(mover);
     for (typename StoreSet::Range r = stores_.all(); !r.empty(); r.popFront())
         r.front().trace(mover);
 }
 
 namespace js {
 namespace gc {
 template void
 StoreBuffer::MonoTypeBuffer<StoreBuffer::ValueEdge>::trace(StoreBuffer*, TenuringTracer&);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/gc/bug-1313347.js
@@ -0,0 +1,5 @@
+let tenured = {};
+gc();
+for (let i = 0; i < 100000; i++) {
+    tenured[i/2] = {};
+}
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -2954,31 +2954,35 @@ void
 js::MarkCompartmentActive(InterpreterFrame* fp)
 {
     fp->script()->compartment()->zone()->active = true;
 }
 
 void
 GCRuntime::requestMajorGC(JS::gcreason::Reason reason)
 {
+    MOZ_ASSERT(!CurrentThreadIsPerformingGC());
+
     if (majorGCRequested())
         return;
 
     majorGCTriggerReason = reason;
 
     // There's no need to use RequestInterruptUrgent here. It's slower because
     // it has to interrupt (looping) Ion code, but loops in Ion code that
     // affect GC will have an explicit interrupt check.
     rt->requestInterrupt(JSRuntime::RequestInterruptCanWait);
 }
 
 void
 GCRuntime::requestMinorGC(JS::gcreason::Reason reason)
 {
     MOZ_ASSERT(CurrentThreadCanAccessRuntime(rt));
+    MOZ_ASSERT(!CurrentThreadIsPerformingGC());
+
     if (minorGCRequested())
         return;
 
     minorGCTriggerReason = reason;
 
     // See comment in requestMajorGC.
     rt->requestInterrupt(JSRuntime::RequestInterruptCanWait);
 }