Backed out changeset 0d55a6e4e98e (bug 1120016) for 980 b2g hazards a=merge
authorWes Kocher <wkocher@mozilla.com>
Wed, 30 Dec 2015 16:34:18 -0800
changeset 314921 22f51211915bf7daff076180847a7140d35aa353
parent 314920 ee14715f713146f3e9298fedd5f955b7dbbe45ff
child 314924 6f4ef2a14886bafda5d255b2ddf36bc5e4ee8817
child 314953 4c891eee4b0d83ff52f0a9a10dc052a0944c17f9
child 315057 23d99eb297e44d559f5583a565cdd670338f34df
push id1079
push userjlund@mozilla.com
push dateFri, 15 Apr 2016 21:02:33 +0000
treeherdermozilla-release@575fbf6786d5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
bugs1120016
milestone46.0a1
backs out0d55a6e4e98e6e420ca9810688f9921434a94eef
first release with
nightly linux32
22f51211915b / 46.0a1 / 20151231030214 / files
nightly linux64
22f51211915b / 46.0a1 / 20151231030214 / files
nightly mac
22f51211915b / 46.0a1 / 20151231030214 / files
nightly win32
22f51211915b / 46.0a1 / 20151231030214 / files
nightly win64
22f51211915b / 46.0a1 / 20151231030214 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backed out changeset 0d55a6e4e98e (bug 1120016) for 980 b2g hazards a=merge
dom/base/nsWrapperCache.cpp
dom/base/nsWrapperCache.h
dom/base/nsWrapperCacheInlines.h
dom/bindings/Codegen.py
dom/bindings/parser/WebIDL.py
dom/events/Event.cpp
dom/webidl/Event.webidl
dom/webidl/MutationObserver.webidl
js/src/devtools/rootAnalysis/annotations.js
js/src/gc/GCRuntime.h
js/src/gc/Marking.cpp
js/src/gc/Nursery.cpp
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jsgc.cpp
xpcom/base/CycleCollectedJSRuntime.cpp
xpcom/base/CycleCollectedJSRuntime.h
xpcom/base/nsCycleCollector.cpp
xpcom/base/nsCycleCollectorTraceJSHelpers.cpp
xpcom/glue/nsCycleCollectionParticipant.h
--- a/dom/base/nsWrapperCache.cpp
+++ b/dom/base/nsWrapperCache.cpp
@@ -4,51 +4,36 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsWrapperCacheInlines.h"
 
 #include "js/Class.h"
 #include "js/Proxy.h"
 #include "mozilla/dom/DOMJSProxyHandler.h"
-#include "mozilla/CycleCollectedJSRuntime.h"
 #include "mozilla/HoldDropJSObjects.h"
 #include "nsCycleCollectionTraversalCallback.h"
 #include "nsCycleCollector.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 #ifdef DEBUG
 /* static */ bool
 nsWrapperCache::HasJSObjectMovedOp(JSObject* aWrapper)
 {
     return js::HasObjectMovedOp(aWrapper);
 }
 #endif
 
-void
+/* static */ void
 nsWrapperCache::HoldJSObjects(void* aScriptObjectHolder,
                               nsScriptObjectTracer* aTracer)
 {
   cyclecollector::HoldJSObjectsImpl(aScriptObjectHolder, aTracer);
-  if (mWrapper && !JS::ObjectIsTenured(mWrapper)) {
-    CycleCollectedJSRuntime::Get()->NurseryWrapperPreserved(mWrapper);
-  }
-}
-
-void
-nsWrapperCache::SetWrapperJSObject(JSObject* aWrapper)
-{
-  mWrapper = aWrapper;
-  UnsetWrapperFlags(kWrapperFlagsMask & ~WRAPPER_IS_NOT_DOM_BINDING);
-
-  if (aWrapper && !JS::ObjectIsTenured(aWrapper)) {
-    CycleCollectedJSRuntime::Get()->NurseryWrapperAdded(this);
-  }
 }
 
 void
 nsWrapperCache::ReleaseWrapper(void* aScriptObjectHolder)
 {
   if (PreservingWrapper()) {
     // PreserveWrapper puts new DOM bindings in the JS holders hash, but they
     // can also be in the DOM expando hash, so we need to try to remove them
--- a/dom/base/nsWrapperCache.h
+++ b/dom/base/nsWrapperCache.h
@@ -253,25 +253,24 @@ public:
   }
 
   void ReleaseWrapper(void* aScriptObjectHolder);
 
 protected:
   void TraceWrapper(JSTracer* aTrc, const char* name)
   {
     if (mWrapper) {
-      JS_CallUnbarrieredObjectTracer(aTrc, &mWrapper, name);
+      JS_CallObjectTracer(aTrc, &mWrapper, name);
     }
   }
 
   void PoisonWrapper()
   {
     if (mWrapper) {
-      // See setToCrashOnTouch() in RootingAPI.h
-      mWrapper = reinterpret_cast<JSObject*>(1);
+      mWrapper.setToCrashOnTouch();
     }
   }
 
 private:
   friend class mozilla::dom::TabChildGlobal;
   friend class mozilla::dom::ProcessGlobal;
   friend class SandboxPrivate;
   friend class nsInProcessTabChildGlobal;
@@ -283,17 +282,23 @@ private:
     SetWrapperFlags(WRAPPER_IS_NOT_DOM_BINDING);
   }
 
   JSObject *GetWrapperJSObject() const
   {
     return mWrapper;
   }
 
-  void SetWrapperJSObject(JSObject* aWrapper);
+  void SetWrapperJSObject(JSObject* aWrapper)
+  {
+    mWrapper = aWrapper;
+    UnsetWrapperFlags(kWrapperFlagsMask & ~WRAPPER_IS_NOT_DOM_BINDING);
+  }
+
+  void TraceWrapperJSObject(JSTracer* aTrc, const char* aName);
 
   FlagsType GetWrapperFlags() const
   {
     return mFlags & kWrapperFlagsMask;
   }
 
   bool HasWrapperFlag(FlagsType aFlag) const
   {
@@ -308,18 +313,18 @@ private:
   }
 
   void UnsetWrapperFlags(FlagsType aFlagsToUnset)
   {
     MOZ_ASSERT((aFlagsToUnset & ~kWrapperFlagsMask) == 0, "Bad wrapper flag bits");
     mFlags &= ~aFlagsToUnset;
   }
 
-  void HoldJSObjects(void* aScriptObjectHolder,
-                     nsScriptObjectTracer* aTracer);
+  static void HoldJSObjects(void* aScriptObjectHolder,
+                            nsScriptObjectTracer* aTracer);
 
 #ifdef DEBUG
 public:
   void CheckCCWrapperTraversal(void* aScriptObjectHolder,
                                nsScriptObjectTracer* aTracer);
 private:
 #endif // DEBUG
 
@@ -339,18 +344,18 @@ private:
   /**
    * If this bit is set then the wrapper for the native object is not a DOM
    * binding.
    */
   enum { WRAPPER_IS_NOT_DOM_BINDING = 1 << 1 };
 
   enum { kWrapperFlagsMask = (WRAPPER_BIT_PRESERVED | WRAPPER_IS_NOT_DOM_BINDING) };
 
-  JSObject* mWrapper;
-  FlagsType mFlags;
+  JS::Heap<JSObject*> mWrapper;
+  FlagsType           mFlags;
 };
 
 enum { WRAPPER_CACHE_FLAGS_BITS_USED = 2 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsWrapperCache, NS_WRAPPERCACHE_IID)
 
 #define NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY                                 \
   if ( aIID.Equals(NS_GET_IID(nsWrapperCache)) ) {                            \
--- a/dom/base/nsWrapperCacheInlines.h
+++ b/dom/base/nsWrapperCacheInlines.h
@@ -48,9 +48,15 @@ nsWrapperCache::HasNothingToTrace(nsISup
 }
 
 inline bool
 nsWrapperCache::IsBlackAndDoesNotNeedTracing(nsISupports* aThis)
 {
   return IsBlack() && HasNothingToTrace(aThis);
 }
 
+inline void
+nsWrapperCache::TraceWrapperJSObject(JSTracer* aTrc, const char* aName)
+{
+  JS_CallObjectTracer(aTrc, &mWrapper, aName);
+}
+
 #endif /* nsWrapperCache_h___ */
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -417,18 +417,16 @@ class CGDOMJSClass(CGThing):
         if self.descriptor.isGlobal():
             classFlags += "JSCLASS_DOM_GLOBAL | JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(DOM_GLOBAL_SLOTS)"
             traceHook = "JS_GlobalObjectTraceHook"
             reservedSlots = "JSCLASS_GLOBAL_APPLICATION_SLOTS"
         else:
             classFlags += "JSCLASS_HAS_RESERVED_SLOTS(%d)" % slotCount
             traceHook = 'nullptr'
             reservedSlots = slotCount
-        if self.descriptor.interface.isProbablyShortLivingObject():
-            classFlags += " | JSCLASS_SKIP_NURSERY_FINALIZE"
         if self.descriptor.interface.getExtendedAttribute("NeedResolve"):
             resolveHook = RESOLVE_HOOK_NAME
             mayResolveHook = MAY_RESOLVE_HOOK_NAME
             enumerateHook = ENUMERATE_HOOK_NAME
         elif self.descriptor.isGlobal():
             resolveHook = "mozilla::dom::ResolveGlobal"
             mayResolveHook = "mozilla::dom::MayResolveGlobal"
             enumerateHook = "mozilla::dom::EnumerateGlobal"
--- a/dom/bindings/parser/WebIDL.py
+++ b/dom/bindings/parser/WebIDL.py
@@ -559,19 +559,16 @@ class IDLExternalInterface(IDLObjectWith
         pass
 
     def getJSImplementation(self):
         return None
 
     def isJSImplemented(self):
         return False
 
-    def isProbablyShortLivingObject(self):
-        return False
-
     def getNavigatorProperty(self):
         return None
 
     def _getDependentObjects(self):
         return set()
 
 
 class IDLPartialInterface(IDLObject):
@@ -1406,18 +1403,17 @@ class IDLInterface(IDLObjectWithScope, I
                 self.parentScope.globalNames.add(self.identifier.name)
                 self.parentScope.globalNameMapping[self.identifier.name].add(self.identifier.name)
                 self._isOnGlobalProtoChain = True
             elif (identifier == "NeedResolve" or
                   identifier == "OverrideBuiltins" or
                   identifier == "ChromeOnly" or
                   identifier == "Unforgeable" or
                   identifier == "UnsafeInPrerendering" or
-                  identifier == "LegacyEventInit" or
-                  identifier == "ProbablyShortLivingObject"):
+                  identifier == "LegacyEventInit"):
                 # Known extended attributes that do not take values
                 if not attr.noArguments():
                     raise WebIDLError("[%s] must take no arguments" % identifier,
                                       [attr.location])
             elif identifier == "Exposed":
                 convertExposedAttrToGlobalNameSet(attr,
                                                   self._exposureGlobalNames)
             elif (identifier == "Pref" or
@@ -1521,24 +1517,16 @@ class IDLInterface(IDLObjectWithScope, I
             return classId
         assert isinstance(classId, list)
         assert len(classId) == 1
         return classId[0]
 
     def isJSImplemented(self):
         return bool(self.getJSImplementation())
 
-    def isProbablyShortLivingObject(self):
-        current = self
-        while current:
-            if current.getExtendedAttribute("ProbablyShortLivingObject"):
-                return True
-            current = current.parent
-        return False
-
     def getNavigatorProperty(self):
         naviProp = self.getExtendedAttribute("NavigatorProperty")
         if not naviProp:
             return None
         assert len(naviProp) == 1
         assert isinstance(naviProp, list)
         assert len(naviProp[0]) != 0
         return naviProp[0]
--- a/dom/events/Event.cpp
+++ b/dom/events/Event.cpp
@@ -232,16 +232,19 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 
 JSObject*
 Event::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
+  if (mIsMainThreadEvent && !GetWrapperPreserveColor()) {
+    nsJSContext::LikelyShortLivingObjectCreated();
+  }
   return WrapObjectInternal(aCx, aGivenProto);
 }
 
 JSObject*
 Event::WrapObjectInternal(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return EventBinding::Wrap(aCx, this, aGivenProto);
 }
--- a/dom/webidl/Event.webidl
+++ b/dom/webidl/Event.webidl
@@ -6,17 +6,17 @@
  * The origin of this IDL file is
  * http://www.w3.org/TR/2012/WD-dom-20120105/
  *
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
 [Constructor(DOMString type, optional EventInit eventInitDict),
- Exposed=(Window,Worker,System), ProbablyShortLivingObject]
+ Exposed=(Window,Worker,System)]
 interface Event {
   [Pure]
   readonly attribute DOMString type;
   [Pure]
   readonly attribute EventTarget? target;
   [Pure]
   readonly attribute EventTarget? currentTarget;
 
--- a/dom/webidl/MutationObserver.webidl
+++ b/dom/webidl/MutationObserver.webidl
@@ -2,17 +2,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/.
  *
  * The origin of this IDL file is
  * http://dom.spec.whatwg.org
  */
 
-[ProbablyShortLivingObject]
 interface MutationRecord {
   [Constant]
   readonly attribute DOMString type;
   // .target is not nullable per the spec, but in order to prevent crashes,
   // if there are GC/CC bugs in Gecko, we let the property to be null.
   [Constant]
   readonly attribute Node? target;
   [Constant]
--- a/js/src/devtools/rootAnalysis/annotations.js
+++ b/js/src/devtools/rootAnalysis/annotations.js
@@ -73,18 +73,17 @@ var ignoreCallees = {
     "JSRuntime.destroyPrincipals" : true,
     "icu_50::UObject.__deleting_dtor" : true, // destructors in ICU code can't cause GC
     "mozilla::CycleCollectedJSRuntime.DescribeCustomObjects" : true, // During tracing, cannot GC.
     "mozilla::CycleCollectedJSRuntime.NoteCustomGCThingXPCOMChildren" : true, // During tracing, cannot GC.
     "PLDHashTableOps.hashKey" : true,
     "z_stream_s.zfree" : true,
     "GrGLInterface.fCallback" : true,
     "std::strstreambuf._M_alloc_fun" : true,
-    "std::strstreambuf._M_free_fun" : true,
-    "struct js::gc::Callback<void (*)(JSRuntime*, void*)>.op" : true,
+    "std::strstreambuf._M_free_fun" : true
 };
 
 function fieldCallCannotGC(csu, fullfield)
 {
     if (csu in ignoreClasses)
         return true;
     if (fullfield in ignoreCallees)
         return true;
@@ -183,18 +182,16 @@ var ignoreFunctions = {
     // particular runnable it posts can't even GC, but the analysis isn't
     // currently smart enough to determine that. In either case, this is (a)
     // only in GTests, and (b) only when the Gtest has already failed. We have
     // static and dynamic checks for no GC in the non-test code, and in the test
     // code we fall back to only the dynamic checks.
     "void test::RingbufferDumper::OnTestPartResult(testing::TestPartResult*)" : true,
 
     "float64 JS_GetCurrentEmbedderTime()" : true,
-
-    "uint64 js::TenuringTracer::moveObjectToTenured(JSObject*, JSObject*, int32)" : true,
 };
 
 function isProtobuf(name)
 {
     return name.match(/\bgoogle::protobuf\b/) ||
            name.match(/\bmozilla::devtools::protobuf\b/);
 }
 
--- a/js/src/gc/GCRuntime.h
+++ b/js/src/gc/GCRuntime.h
@@ -751,19 +751,16 @@ class GCRuntime
     int32_t getMallocBytes() const { return mallocBytesUntilGC; }
     void resetMallocBytes();
     bool isTooMuchMalloc() const { return mallocBytesUntilGC <= 0; }
     void updateMallocCounter(JS::Zone* zone, size_t nbytes);
     void onTooMuchMalloc();
 
     void setGCCallback(JSGCCallback callback, void* data);
     void callGCCallback(JSGCStatus status) const;
-    void setObjectsTenuredCallback(JSObjectsTenuredCallback callback,
-                                   void* data);
-    void callObjectsTenuredCallback();
     bool addFinalizeCallback(JSFinalizeCallback callback, void* data);
     void removeFinalizeCallback(JSFinalizeCallback func);
     bool addWeakPointerZoneGroupCallback(JSWeakPointerZoneGroupCallback callback, void* data);
     void removeWeakPointerZoneGroupCallback(JSWeakPointerZoneGroupCallback callback);
     bool addWeakPointerCompartmentCallback(JSWeakPointerCompartmentCallback callback, void* data);
     void removeWeakPointerCompartmentCallback(JSWeakPointerCompartmentCallback callback);
     JS::GCSliceCallback setSliceCallback(JS::GCSliceCallback callback);
 
@@ -1271,17 +1268,16 @@ class GCRuntime
 
     js::Vector<JSObject*, 0, js::SystemAllocPolicy> selectedForMarking;
 #endif
 
     bool validate;
     bool fullCompartmentChecks;
 
     Callback<JSGCCallback> gcCallback;
-    Callback<JSObjectsTenuredCallback> tenuredCallback;
     CallbackVector<JSFinalizeCallback> finalizeCallbacks;
     CallbackVector<JSWeakPointerZoneGroupCallback> updateWeakPointerZoneGroupCallbacks;
     CallbackVector<JSWeakPointerCompartmentCallback> updateWeakPointerCompartmentCallbacks;
 
     /*
      * Malloc counter to measure memory pressure for GC scheduling. It runs
      * from maxMallocBytes down to zero.
      */
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -2210,18 +2210,16 @@ js::TenuringTracer::moveObjectToTenured(
 
     if (src->getClass()->flags & JSCLASS_SKIP_NURSERY_FINALIZE) {
         if (src->is<InlineTypedObject>()) {
             InlineTypedObject::objectMovedDuringMinorGC(this, dst, src);
         } else if (src->is<UnboxedArrayObject>()) {
             tenuredSize += UnboxedArrayObject::objectMovedDuringMinorGC(this, dst, src, dstKind);
         } else if (src->is<ArgumentsObject>()) {
             tenuredSize += ArgumentsObject::objectMovedDuringMinorGC(this, dst, src);
-        } else if (JSObjectMovedOp op = dst->getClass()->ext.objectMovedOp) {
-            op(dst, src);
         } else {
             // Objects with JSCLASS_SKIP_NURSERY_FINALIZE need to be handled above
             // to ensure any additional nursery buffers they hold are moved.
             MOZ_CRASH("Unhandled JSCLASS_SKIP_NURSERY_FINALIZE Class");
         }
     }
 
     return tenuredSize;
--- a/js/src/gc/Nursery.cpp
+++ b/js/src/gc/Nursery.cpp
@@ -491,20 +491,16 @@ js::Nursery::collect(JSRuntime* rt, JS::
     TIME_END(sweepArrayBufferViewList);
 
     // Update any slot or element pointers whose destination has been tenured.
     TIME_START(updateJitActivations);
     js::jit::UpdateJitActivationsForMinorGC(rt, &mover);
     forwardedBuffers.finish();
     TIME_END(updateJitActivations);
 
-    TIME_START(objectsTenuredCallback);
-    rt->gc.callObjectsTenuredCallback();
-    TIME_END(objectsTenuredCallback);
-
     // Sweep.
     TIME_START(freeMallocedBuffers);
     freeMallocedBuffers();
     TIME_END(freeMallocedBuffers);
 
     TIME_START(sweep);
     sweep();
     TIME_END(sweep);
@@ -575,17 +571,16 @@ js::Nursery::collect(JSRuntime* rt, JS::
             {"mkSlts", TIME_TOTAL(traceSlots)},
             {"mcWCll", TIME_TOTAL(traceWholeCells)},
             {"mkGnrc", TIME_TOTAL(traceGenericEntries)},
             {"ckTbls", TIME_TOTAL(checkHashTables)},
             {"mkRntm", TIME_TOTAL(markRuntime)},
             {"mkDbgr", TIME_TOTAL(markDebugger)},
             {"clrNOC", TIME_TOTAL(clearNewObjectCache)},
             {"collct", TIME_TOTAL(collectToFP)},
-            {" tenCB", TIME_TOTAL(objectsTenuredCallback)},
             {"swpABO", TIME_TOTAL(sweepArrayBufferViewList)},
             {"updtIn", TIME_TOTAL(updateJitActivations)},
             {"frSlts", TIME_TOTAL(freeMallocedBuffers)},
             {" clrSB", TIME_TOTAL(clearStoreBuffer)},
             {" sweep", TIME_TOTAL(sweep)},
             {"resize", TIME_TOTAL(resize)},
             {"pretnr", TIME_TOTAL(pretenure)},
             {"logPtT", TIME_TOTAL(logPromotionsToTenured)}
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -1390,24 +1390,16 @@ JS_MaybeGC(JSContext* cx)
 
 JS_PUBLIC_API(void)
 JS_SetGCCallback(JSRuntime* rt, JSGCCallback cb, void* data)
 {
     AssertHeapIsIdle(rt);
     rt->gc.setGCCallback(cb, data);
 }
 
-JS_PUBLIC_API(void)
-JS_SetObjectsTenuredCallback(JSRuntime* rt, JSObjectsTenuredCallback cb,
-                             void* data)
-{
-    AssertHeapIsIdle(rt);
-    rt->gc.setObjectsTenuredCallback(cb, data);
-}
-
 JS_PUBLIC_API(bool)
 JS_AddFinalizeCallback(JSRuntime* rt, JSFinalizeCallback cb, void* data)
 {
     AssertHeapIsIdle(rt);
     return rt->gc.addFinalizeCallback(cb, data);
 }
 
 JS_PUBLIC_API(void)
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -567,19 +567,16 @@ typedef bool
 typedef enum JSGCStatus {
     JSGC_BEGIN,
     JSGC_END
 } JSGCStatus;
 
 typedef void
 (* JSGCCallback)(JSRuntime* rt, JSGCStatus status, void* data);
 
-typedef void
-(* JSObjectsTenuredCallback)(JSRuntime* rt, void* data);
-
 typedef enum JSFinalizeStatus {
     /**
      * Called when preparing to sweep a group of compartments, before anything
      * has been swept.  The collector will not yield to the mutator before
      * calling the callback with JSFINALIZE_GROUP_END status.
      */
     JSFINALIZE_GROUP_START,
 
@@ -1652,20 +1649,16 @@ extern JS_PUBLIC_API(void)
 JS_GC(JSRuntime* rt);
 
 extern JS_PUBLIC_API(void)
 JS_MaybeGC(JSContext* cx);
 
 extern JS_PUBLIC_API(void)
 JS_SetGCCallback(JSRuntime* rt, JSGCCallback cb, void* data);
 
-extern JS_PUBLIC_API(void)
-JS_SetObjectsTenuredCallback(JSRuntime* rt, JSObjectsTenuredCallback cb,
-                             void* data);
-
 extern JS_PUBLIC_API(bool)
 JS_AddFinalizeCallback(JSRuntime* rt, JSFinalizeCallback cb, void* data);
 
 extern JS_PUBLIC_API(void)
 JS_RemoveFinalizeCallback(JSRuntime* rt, JSFinalizeCallback cb);
 
 /*
  * Weak pointers and garbage collection
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -1601,31 +1601,16 @@ GCRuntime::setGCCallback(JSGCCallback ca
 
 void
 GCRuntime::callGCCallback(JSGCStatus status) const
 {
     if (gcCallback.op)
         gcCallback.op(rt, status, gcCallback.data);
 }
 
-void
-GCRuntime::setObjectsTenuredCallback(JSObjectsTenuredCallback callback,
-                                     void* data)
-{
-    tenuredCallback.op = callback;
-    tenuredCallback.data = data;
-}
-
-void
-GCRuntime::callObjectsTenuredCallback()
-{
-    if (tenuredCallback.op)
-        tenuredCallback.op(rt, tenuredCallback.data);
-}
-
 namespace {
 
 class AutoNotifyGCActivity {
   public:
     explicit AutoNotifyGCActivity(GCRuntime& gc) : gc_(gc) {
         if (!gc_.isIncrementalGCInProgress()) {
             gcstats::AutoPhase ap(gc_.stats, gcstats::PHASE_GC_BEGIN);
             gc_.callGCCallback(JSGC_BEGIN);
--- a/xpcom/base/CycleCollectedJSRuntime.cpp
+++ b/xpcom/base/CycleCollectedJSRuntime.cpp
@@ -68,17 +68,16 @@
 #include "jsprf.h"
 #include "js/Debug.h"
 #include "nsContentUtils.h"
 #include "nsCycleCollectionNoteRootCallback.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsCycleCollector.h"
 #include "nsDOMJSUtils.h"
 #include "nsJSUtils.h"
-#include "nsWrapperCache.h"
 
 #ifdef MOZ_CRASHREPORTER
 #include "nsExceptionHandler.h"
 #endif
 
 #include "nsIException.h"
 #include "nsThread.h"
 #include "nsThreadUtils.h"
@@ -393,22 +392,16 @@ NoteJSChildGrayWrapperShim(void* aData, 
  * purple buffer during every CC, which may contain the last reference to a garbage
  * cycle.)
  */
 
 // NB: This is only used to initialize the participant in
 // CycleCollectedJSRuntime. It should never be used directly.
 static const JSZoneParticipant sJSZoneCycleCollectorGlobal;
 
-static
-void JSObjectsTenuredCb(JSRuntime* aRuntime, void* aData)
-{
-  static_cast<CycleCollectedJSRuntime*>(aData)->JSObjectsTenured(aRuntime);
-}
-
 CycleCollectedJSRuntime::CycleCollectedJSRuntime(JSRuntime* aParentRuntime,
                                                  uint32_t aMaxBytes,
                                                  uint32_t aMaxNurseryBytes)
   : mGCThingCycleCollectorGlobal(sGCThingCycleCollectorGlobal)
   , mJSZoneCycleCollectorGlobal(sJSZoneCycleCollectorGlobal)
   , mJSRuntime(nullptr)
   , mPrevGCSliceCallback(nullptr)
   , mJSHolders(256)
@@ -432,17 +425,16 @@ CycleCollectedJSRuntime::CycleCollectedJ
   }
 
   if (!JS_AddExtraGCRootsTracer(mJSRuntime, TraceBlackJS, this)) {
     MOZ_CRASH();
   }
   JS_SetGrayGCRootsTracer(mJSRuntime, TraceGrayJS, this);
   JS_SetGCCallback(mJSRuntime, GCCallback, this);
   mPrevGCSliceCallback = JS::SetGCSliceCallback(mJSRuntime, GCSliceCallback);
-  JS_SetObjectsTenuredCallback(mJSRuntime, JSObjectsTenuredCb, this);
   JS::SetOutOfMemoryCallback(mJSRuntime, OutOfMemoryCallback, this);
   JS::SetLargeAllocationFailureCallback(mJSRuntime,
                                         LargeAllocationFailureCallback, this);
   JS_SetContextCallback(mJSRuntime, ContextCallback, this);
   JS_SetDestroyZoneCallback(mJSRuntime, XPCStringConvert::FreeZoneCache);
   JS_SetSweepZoneCallback(mJSRuntime, XPCStringConvert::ClearZoneCache);
 
   static js::DOMCallbacks DOMcallbacks = {
@@ -788,21 +780,16 @@ struct JsGcTracer : public TraceCallback
   {
     JS_CallIdTracer(static_cast<JSTracer*>(aClosure), aPtr, aName);
   }
   virtual void Trace(JS::Heap<JSObject*>* aPtr, const char* aName,
                      void* aClosure) const override
   {
     JS_CallObjectTracer(static_cast<JSTracer*>(aClosure), aPtr, aName);
   }
-  virtual void Trace(JSObject** aPtr, const char* aName,
-                     void* aClosure) const override
-  {
-    JS_CallUnbarrieredObjectTracer(static_cast<JSTracer*>(aClosure), aPtr, aName);
-  }
   virtual void Trace(JS::TenuredHeap<JSObject*>* aPtr, const char* aName,
                      void* aClosure) const override
   {
     JS_CallTenuredObjectTracer(static_cast<JSTracer*>(aClosure), aPtr, aName);
   }
   virtual void Trace(JS::Heap<JSString*>* aPtr, const char* aName,
                      void* aClosure) const override
   {
@@ -860,22 +847,16 @@ struct ClearJSHolder : TraceCallbacks
     *aPtr = JSID_VOID;
   }
 
   virtual void Trace(JS::Heap<JSObject*>* aPtr, const char*, void*) const override
   {
     *aPtr = nullptr;
   }
 
-  virtual void Trace(JSObject** aPtr, const char* aName,
-                     void* aClosure) const override
-  {
-    *aPtr = nullptr;
-  }
-
   virtual void Trace(JS::TenuredHeap<JSObject*>* aPtr, const char*, void*) const override
   {
     *aPtr = nullptr;
   }
 
   virtual void Trace(JS::Heap<JSString*>* aPtr, const char*, void*) const override
   {
     *aPtr = nullptr;
@@ -1023,56 +1004,16 @@ CycleCollectedJSRuntime::GarbageCollect(
   MOZ_ASSERT(aReason < JS::gcreason::NUM_REASONS);
   JS::gcreason::Reason gcreason = static_cast<JS::gcreason::Reason>(aReason);
 
   JS::PrepareForFullGC(mJSRuntime);
   JS::GCForReason(mJSRuntime, GC_NORMAL, gcreason);
 }
 
 void
-CycleCollectedJSRuntime::JSObjectsTenured(JSRuntime* aRuntime)
-{
-  for (auto iter = mNurseryObjects.Iter(); !iter.Done(); iter.Next()) {
-    nsWrapperCache* cache = iter.Get();
-    JSObject* wrapper = cache->GetWrapperPreserveColor();
-    MOZ_ASSERT(wrapper);
-    if (!JS::ObjectIsTenured(wrapper)) {
-      MOZ_ASSERT(!cache->PreservingWrapper());
-      const JSClass* jsClass = js::GetObjectJSClass(wrapper);
-      jsClass->finalize(nullptr, wrapper);
-    }
-  }
-
-#ifdef DEBUG
-for (auto iter = mPreservedNurseryObjects.Iter(); !iter.Done(); iter.Next()) {
-  MOZ_ASSERT(JS::ObjectIsTenured(iter.Get().get()));
-}
-#endif
-
-  mNurseryObjects.Clear();
-  mPreservedNurseryObjects.Clear();
-}
-
-void
-CycleCollectedJSRuntime::NurseryWrapperAdded(nsWrapperCache* aCache)
-{
-  MOZ_ASSERT(aCache);
-  MOZ_ASSERT(aCache->GetWrapperPreserveColor());
-  MOZ_ASSERT(!JS::ObjectIsTenured(aCache->GetWrapperPreserveColor()));
-  mNurseryObjects.InfallibleAppend(aCache);
-}
-
-void
-CycleCollectedJSRuntime::NurseryWrapperPreserved(JSObject* aWrapper)
-{
-  mPreservedNurseryObjects.InfallibleAppend(
-    JS::PersistentRooted<JSObject*>(mJSRuntime, aWrapper));
-}
-
-void
 CycleCollectedJSRuntime::DeferredFinalize(DeferredFinalizeAppendFunction aAppendFunc,
                                           DeferredFinalizeFunction aFunc,
                                           void* aThing)
 {
   void* thingArray = nullptr;
   bool hadThingArray = mDeferredFinalizerTable.Get(aFunc, &thingArray);
 
   thingArray = aAppendFunc(thingArray, aThing);
--- a/xpcom/base/CycleCollectedJSRuntime.h
+++ b/xpcom/base/CycleCollectedJSRuntime.h
@@ -5,31 +5,28 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_CycleCollectedJSRuntime_h__
 #define mozilla_CycleCollectedJSRuntime_h__
 
 #include <queue>
 
 #include "mozilla/DeferredFinalize.h"
-#include "mozilla/mozalloc.h"
 #include "mozilla/MemoryReporting.h"
-#include "mozilla/SegmentedVector.h"
 #include "jsapi.h"
 
 #include "nsCycleCollectionParticipant.h"
 #include "nsDataHashtable.h"
 #include "nsHashKeys.h"
 #include "nsTArray.h"
 
 class nsCycleCollectionNoteRootCallback;
 class nsIException;
 class nsIRunnable;
 class nsThread;
-class nsWrapperCache;
 
 namespace js {
 struct Class;
 } // namespace js
 
 namespace mozilla {
 
 class JSGCThingParticipant: public nsCycleCollectionParticipant
@@ -278,20 +275,16 @@ public:
   nsCycleCollectionParticipant* ZoneParticipant();
 
   nsresult TraverseRoots(nsCycleCollectionNoteRootCallback& aCb);
   bool UsefulToMergeZones() const;
   void FixWeakMappingGrayBits() const;
   bool AreGCGrayBitsValid() const;
   void GarbageCollect(uint32_t aReason) const;
 
-  void NurseryWrapperAdded(nsWrapperCache* aCache);
-  void NurseryWrapperPreserved(JSObject* aWrapper);
-  void JSObjectsTenured(JSRuntime* aRuntime);
-
   void DeferredFinalize(DeferredFinalizeAppendFunction aAppendFunc,
                         DeferredFinalizeFunction aFunc,
                         void* aThing);
   void DeferredFinalize(nsISupports* aSupports);
 
   void DumpJSHeap(FILE* aFile);
 
   virtual void PrepareForForgetSkippable() = 0;
@@ -363,23 +356,16 @@ private:
 
   nsTArray<nsCOMPtr<nsIRunnable>> mStableStateEvents;
   nsTArray<RunInMetastableStateData> mMetastableStateEvents;
   uint32_t mBaseRecursionDepth;
   bool mDoingStableStates;
 
   OOMState mOutOfMemoryState;
   OOMState mLargeAllocationFailureState;
-
-  static const size_t kSegmentSize = 512;
-  SegmentedVector<nsWrapperCache*, kSegmentSize, InfallibleAllocPolicy>
-    mNurseryObjects;
-  SegmentedVector<JS::PersistentRooted<JSObject*>, kSegmentSize,
-                  InfallibleAllocPolicy>
-    mPreservedNurseryObjects;
 };
 
 void TraceScriptHolder(nsISupports* aHolder, JSTracer* aTracer);
 
 // Returns true if the JS::TraceKind is one the cycle collector cares about.
 inline bool AddToCCKind(JS::TraceKind aKind)
 {
   return aKind == JS::TraceKind::Object || aKind == JS::TraceKind::Script;
--- a/xpcom/base/nsCycleCollector.cpp
+++ b/xpcom/base/nsCycleCollector.cpp
@@ -2672,67 +2672,61 @@ public:
   }
 
   bool HasSnowWhiteObjects() const
   {
     return !mObjects.IsEmpty();
   }
 
   virtual void Trace(JS::Heap<JS::Value>* aValue, const char* aName,
-                     void* aClosure) const override
+                     void* aClosure) const
   {
     if (aValue->isMarkable() && ValueIsGrayCCThing(*aValue)) {
       MOZ_ASSERT(!js::gc::IsInsideNursery(aValue->toGCThing()));
       mCollector->GetJSPurpleBuffer()->mValues.InfallibleAppend(*aValue);
     }
   }
 
   virtual void Trace(JS::Heap<jsid>* aId, const char* aName,
-                     void* aClosure) const override
+                     void* aClosure) const
   {
   }
 
   void AppendJSObjectToPurpleBuffer(JSObject* obj) const
   {
     if (obj && JS::ObjectIsMarkedGray(obj)) {
       MOZ_ASSERT(JS::ObjectIsTenured(obj));
       mCollector->GetJSPurpleBuffer()->mObjects.InfallibleAppend(obj);
     }
   }
 
   virtual void Trace(JS::Heap<JSObject*>* aObject, const char* aName,
-                     void* aClosure) const override
-  {
-    AppendJSObjectToPurpleBuffer(*aObject);
-  }
-
-  virtual void Trace(JSObject** aObject, const char* aName,
-                     void* aClosure) const override
+                     void* aClosure) const
   {
     AppendJSObjectToPurpleBuffer(*aObject);
   }
 
   virtual void Trace(JS::TenuredHeap<JSObject*>* aObject, const char* aName,
-                     void* aClosure) const override
+                     void* aClosure) const
   {
     AppendJSObjectToPurpleBuffer(*aObject);
   }
 
   virtual void Trace(JS::Heap<JSString*>* aString, const char* aName,
-                     void* aClosure) const override
+                     void* aClosure) const
   {
   }
 
   virtual void Trace(JS::Heap<JSScript*>* aScript, const char* aName,
-                     void* aClosure) const override
+                     void* aClosure) const
   {
   }
 
   virtual void Trace(JS::Heap<JSFunction*>* aFunction, const char* aName,
-                     void* aClosure) const override
+                     void* aClosure) const
   {
   }
 
 private:
   RefPtr<nsCycleCollector> mCollector;
   ObjectsVector mObjects;
 };
 
--- a/xpcom/base/nsCycleCollectorTraceJSHelpers.cpp
+++ b/xpcom/base/nsCycleCollectorTraceJSHelpers.cpp
@@ -57,23 +57,16 @@ TraceCallbackFunc::Trace(JS::Heap<jsid>*
 void
 TraceCallbackFunc::Trace(JS::Heap<JSObject*>* aPtr, const char* aName,
                          void* aClosure) const
 {
   mCallback(JS::GCCellPtr(aPtr->get()), aName, aClosure);
 }
 
 void
-TraceCallbackFunc::Trace(JSObject** aPtr, const char* aName,
-                         void* aClosure) const
-{
-  mCallback(JS::GCCellPtr(*aPtr), aName, aClosure);
-}
-
-void
 TraceCallbackFunc::Trace(JS::TenuredHeap<JSObject*>* aPtr, const char* aName,
                          void* aClosure) const
 {
   mCallback(JS::GCCellPtr(aPtr->getPtr()), aName, aClosure);
 }
 
 void
 TraceCallbackFunc::Trace(JS::Heap<JSFunction*>* aPtr, const char* aName,
--- a/xpcom/glue/nsCycleCollectionParticipant.h
+++ b/xpcom/glue/nsCycleCollectionParticipant.h
@@ -59,18 +59,16 @@ template<class T> class Heap;
 struct TraceCallbacks
 {
   virtual void Trace(JS::Heap<JS::Value>* aPtr, const char* aName,
                      void* aClosure) const = 0;
   virtual void Trace(JS::Heap<jsid>* aPtr, const char* aName,
                      void* aClosure) const = 0;
   virtual void Trace(JS::Heap<JSObject*>* aPtr, const char* aName,
                      void* aClosure) const = 0;
-  virtual void Trace(JSObject** aPtr, const char* aName,
-                     void* aClosure) const = 0;
   virtual void Trace(JS::TenuredHeap<JSObject*>* aPtr, const char* aName,
                      void* aClosure) const = 0;
   virtual void Trace(JS::Heap<JSString*>* aPtr, const char* aName,
                      void* aClosure) const = 0;
   virtual void Trace(JS::Heap<JSScript*>* aPtr, const char* aName,
                      void* aClosure) const = 0;
   virtual void Trace(JS::Heap<JSFunction*>* aPtr, const char* aName,
                      void* aClosure) const = 0;
@@ -87,18 +85,16 @@ struct TraceCallbackFunc : public TraceC
   explicit TraceCallbackFunc(Func aCb) : mCallback(aCb) {}
 
   virtual void Trace(JS::Heap<JS::Value>* aPtr, const char* aName,
                      void* aClosure) const override;
   virtual void Trace(JS::Heap<jsid>* aPtr, const char* aName,
                      void* aClosure) const override;
   virtual void Trace(JS::Heap<JSObject*>* aPtr, const char* aName,
                      void* aClosure) const override;
-  virtual void Trace(JSObject** aPtr, const char* aName,
-                     void* aClosure) const override;
   virtual void Trace(JS::TenuredHeap<JSObject*>* aPtr, const char* aName,
                      void* aClosure) const override;
   virtual void Trace(JS::Heap<JSString*>* aPtr, const char* aName,
                      void* aClosure) const override;
   virtual void Trace(JS::Heap<JSScript*>* aPtr, const char* aName,
                      void* aClosure) const override;
   virtual void Trace(JS::Heap<JSFunction*>* aPtr, const char* aName,
                      void* aClosure) const override;