Merge m-c to b-i
authorPhil Ringnalda <philringnalda@gmail.com>
Sun, 09 Mar 2014 20:43:45 -0700
changeset 189912 488cc3850f92b90d6d1e1dbb7558c6f4ad1042cf
parent 189911 09ad3e796ebfc3392659ca3e6b68e06327b69136 (current diff)
parent 189880 fc9947c00b51182fbf095fa4f3d90384152e86bb (diff)
child 189913 ddc516774998afcc8088c1489216dfea3685f6ff
child 189919 69331cb9b7d6a03e948774a9e7a7f96665b1bc12
push id3503
push userraliiev@mozilla.com
push dateMon, 28 Apr 2014 18:51:11 +0000
treeherdermozilla-beta@c95ac01e332e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone30.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge m-c to b-i
js/src/jit-test/tests/gc/bug-914614.js
media/webrtc/signaling/src/media-conduit/MediaEngineWrapper.h
--- a/content/media/webrtc/MediaEngineWebRTC.cpp
+++ b/content/media/webrtc/MediaEngineWebRTC.cpp
@@ -103,18 +103,19 @@ MediaEngineWebRTC::EnumerateVideoDevices
       vSource = new MediaEngineWebRTCVideoSource(i);
       mVideoSources.Put(uuid, vSource); // Hashtable takes ownership.
       aVSources->AppendElement(vSource);
     }
   }
 
   return;
 #else
-  webrtc::ViEBase* ptrViEBase;
-  webrtc::ViECapture* ptrViECapture;
+  ScopedCustomReleasePtr<webrtc::ViEBase> ptrViEBase;
+  ScopedCustomReleasePtr<webrtc::ViECapture> ptrViECapture;
+
   // We spawn threads to handle gUM runnables, so we must protect the member vars
   MutexAutoLock lock(mMutex);
 
 #ifdef MOZ_WIDGET_ANDROID
   jobject context = mozilla::AndroidBridge::Bridge()->GetGlobalContextRef();
 
   // get the JVM
   JavaVM *jvm = mozilla::AndroidBridge::Bridge()->GetVM();
@@ -227,28 +228,25 @@ MediaEngineWebRTC::EnumerateVideoDevices
       aVSources->AppendElement(vSource.get());
     } else {
       vSource = new MediaEngineWebRTCVideoSource(mVideoEngine, i);
       mVideoSources.Put(uuid, vSource); // Hashtable takes ownership.
       aVSources->AppendElement(vSource);
     }
   }
 
-  ptrViEBase->Release();
-  ptrViECapture->Release();
-
   return;
 #endif
 }
 
 void
 MediaEngineWebRTC::EnumerateAudioDevices(nsTArray<nsRefPtr<MediaEngineAudioSource> >* aASources)
 {
-  webrtc::VoEBase* ptrVoEBase = nullptr;
-  webrtc::VoEHardware* ptrVoEHw = nullptr;
+  ScopedCustomReleasePtr<webrtc::VoEBase> ptrVoEBase;
+  ScopedCustomReleasePtr<webrtc::VoEHardware> ptrVoEHw;
   // We spawn threads to handle gUM runnables, so we must protect the member vars
   MutexAutoLock lock(mMutex);
 
 #ifdef MOZ_WIDGET_ANDROID
   jobject context = mozilla::AndroidBridge::Bridge()->GetGlobalContextRef();
 
   // get the JVM
   JavaVM *jvm = mozilla::AndroidBridge::Bridge()->GetVM();
@@ -331,19 +329,16 @@ MediaEngineWebRTC::EnumerateAudioDevices
     } else {
       aSource = new MediaEngineWebRTCAudioSource(
         mVoiceEngine, i, deviceName, uniqueId
       );
       mAudioSources.Put(uuid, aSource); // Hashtable takes ownership.
       aASources->AppendElement(aSource);
     }
   }
-
-  ptrVoEHw->Release();
-  ptrVoEBase->Release();
 }
 
 void
 MediaEngineWebRTC::Shutdown()
 {
   // This is likely paranoia
   MutexAutoLock lock(mMutex);
 
--- a/content/media/webrtc/MediaEngineWebRTC.h
+++ b/content/media/webrtc/MediaEngineWebRTC.h
@@ -23,16 +23,18 @@
 #include "VideoUtils.h"
 #include "MediaEngine.h"
 #include "VideoSegment.h"
 #include "AudioSegment.h"
 #include "StreamBuffer.h"
 #include "MediaStreamGraph.h"
 #include "LoadMonitor.h"
 
+#include "MediaEngineWrapper.h"
+
 // WebRTC library includes follow
 
 // Audio Engine
 #include "webrtc/voice_engine/include/voe_base.h"
 #include "webrtc/voice_engine/include/voe_codec.h"
 #include "webrtc/voice_engine/include/voe_hardware.h"
 #include "webrtc/voice_engine/include/voe_network.h"
 #include "webrtc/voice_engine/include/voe_audio_processing.h"
@@ -303,20 +305,20 @@ public:
 private:
   static const unsigned int KMaxDeviceNameLength = 128;
   static const unsigned int KMaxUniqueIdLength = 256;
 
   void Init();
   void Shutdown();
 
   webrtc::VoiceEngine* mVoiceEngine;
-  webrtc::VoEBase* mVoEBase;
-  webrtc::VoEExternalMedia* mVoERender;
-  webrtc::VoENetwork*  mVoENetwork;
-  webrtc::VoEAudioProcessing *mVoEProcessing;
+  ScopedCustomReleasePtr<webrtc::VoEBase> mVoEBase;
+  ScopedCustomReleasePtr<webrtc::VoEExternalMedia> mVoERender;
+  ScopedCustomReleasePtr<webrtc::VoENetwork> mVoENetwork;
+  ScopedCustomReleasePtr<webrtc::VoEAudioProcessing> mVoEProcessing;
 
   // mMonitor protects mSources[] access/changes, and transitions of mState
   // from kStarted to kStopped (which are combined with EndTrack()).
   // mSources[] is accessed from webrtc threads.
   Monitor mMonitor;
   nsTArray<SourceMediaStream *> mSources; // When this goes empty, we shut down HW
 
   int mCapIndex;
--- a/content/media/webrtc/MediaEngineWebRTCAudio.cpp
+++ b/content/media/webrtc/MediaEngineWebRTCAudio.cpp
@@ -104,20 +104,18 @@ MediaEngineWebRTCAudioSource::Config(boo
   return NS_OK;
 }
 
 nsresult
 MediaEngineWebRTCAudioSource::Allocate(const MediaEnginePrefs &aPrefs)
 {
   if (mState == kReleased) {
     if (mInitDone) {
-      webrtc::VoEHardware* ptrVoEHw = webrtc::VoEHardware::GetInterface(mVoiceEngine);
-      int res = ptrVoEHw->SetRecordingDevice(mCapIndex);
-      ptrVoEHw->Release();
-      if (res) {
+      ScopedCustomReleasePtr<webrtc::VoEHardware> ptrVoEHw(webrtc::VoEHardware::GetInterface(mVoiceEngine));
+      if (!ptrVoEHw || ptrVoEHw->SetRecordingDevice(mCapIndex)) {
         return NS_ERROR_FAILURE;
       }
       mState = kAllocated;
       LOG(("Audio device %d allocated", mCapIndex));
     } else {
       LOG(("Audio device is not initalized"));
       return NS_ERROR_FAILURE;
     }
@@ -273,52 +271,48 @@ MediaEngineWebRTCAudioSource::Init()
     return;
   }
   mNullTransport = new NullTransport();
   if (mVoENetwork->RegisterExternalTransport(mChannel, *mNullTransport)) {
     return;
   }
 
   // Check for availability.
-  webrtc::VoEHardware* ptrVoEHw = webrtc::VoEHardware::GetInterface(mVoiceEngine);
-  if (ptrVoEHw->SetRecordingDevice(mCapIndex)) {
-    ptrVoEHw->Release();
+  ScopedCustomReleasePtr<webrtc::VoEHardware> ptrVoEHw(webrtc::VoEHardware::GetInterface(mVoiceEngine));
+  if (!ptrVoEHw || ptrVoEHw->SetRecordingDevice(mCapIndex)) {
     return;
   }
 
 #ifndef MOZ_B2G
   // Because of the permission mechanism of B2G, we need to skip the status
   // check here.
   bool avail = false;
   ptrVoEHw->GetRecordingDeviceStatus(avail);
-  ptrVoEHw->Release();
   if (!avail) {
     return;
   }
 #endif // MOZ_B2G
+
   // Set "codec" to PCM, 32kHz on 1 channel
-  webrtc::VoECodec* ptrVoECodec;
-  webrtc::CodecInst codec;
-  ptrVoECodec = webrtc::VoECodec::GetInterface(mVoiceEngine);
+  ScopedCustomReleasePtr<webrtc::VoECodec> ptrVoECodec(webrtc::VoECodec::GetInterface(mVoiceEngine));
   if (!ptrVoECodec) {
     return;
   }
 
+  webrtc::CodecInst codec;
   strcpy(codec.plname, ENCODING);
   codec.channels = CHANNELS;
   codec.rate = SAMPLE_RATE;
   codec.plfreq = SAMPLE_FREQUENCY;
   codec.pacsize = SAMPLE_LENGTH;
   codec.pltype = 0; // Default payload type
 
-  if (ptrVoECodec->SetSendCodec(mChannel, codec)) {
-    return;
+  if (!ptrVoECodec->SetSendCodec(mChannel, codec)) {
+    mInitDone = true;
   }
-
-  mInitDone = true;
 }
 
 void
 MediaEngineWebRTCAudioSource::Shutdown()
 {
   if (!mInitDone) {
     // duplicate these here in case we failed during Init()
     if (mChannel != -1) {
@@ -347,18 +341,20 @@ MediaEngineWebRTCAudioSource::Shutdown()
   if (mChannel != -1) {
     mVoENetwork->DeRegisterExternalTransport(mChannel);
   }
 
   if (mNullTransport) {
     delete mNullTransport;
   }
 
-  mVoERender->Release();
-  mVoEBase->Release();
+  mVoEProcessing = nullptr;
+  mVoENetwork = nullptr;
+  mVoERender = nullptr;
+  mVoEBase = nullptr;
 
   mState = kReleased;
   mInitDone = false;
 }
 
 typedef int16_t sample;
 
 void
--- a/dom/system/NetworkGeolocationProvider.js
+++ b/dom/system/NetworkGeolocationProvider.js
@@ -5,23 +5,28 @@
 // See https://developers.google.com/maps/documentation/business/geolocation/
 
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 Components.utils.import("resource://gre/modules/Services.jsm");
 
 const Ci = Components.interfaces;
 const Cc = Components.classes;
 
+const POSITION_UNAVAILABLE = Ci.nsIDOMGeoPositionError.POSITION_UNAVAILABLE;
+
 let gLoggingEnabled = false;
-let gTestingEnabled = false;
-let gUseScanning = true;
+
+// if we don't see any wifi responses in 5 seconds, send the request.
+let gTimeToWaitBeforeSending = 5000; //ms
+
+let gWifiScanningEnabled = true;
+let gWifiResults;
 
 function LOG(aMsg) {
-  if (gLoggingEnabled)
-  {
+  if (gLoggingEnabled) {
     aMsg = "*** WIFI GEO: " + aMsg + "\n";
     Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService).logStringMessage(aMsg);
     dump(aMsg);
   }
 }
 
 function WifiGeoCoordsObject(lat, lon, acc, alt, altacc) {
   this.latitude = lat;
@@ -57,185 +62,143 @@ WifiGeoPositionObject.prototype = {
 };
 
 function WifiGeoPositionProvider() {
   try {
     gLoggingEnabled = Services.prefs.getBoolPref("geo.wifi.logging.enabled");
   } catch (e) {}
 
   try {
-    gTestingEnabled = Services.prefs.getBoolPref("geo.wifi.testing");
+    gTimeToWaitBeforeSending = Services.prefs.getIntPref("geo.wifi.timeToWaitBeforeSending");
   } catch (e) {}
 
   try {
-    gUseScanning = Services.prefs.getBoolPref("geo.wifi.scan");
+    gWifiScanningEnabled = Services.prefs.getBoolPref("geo.wifi.scan");
   } catch (e) {}
 
   this.wifiService = null;
-  this.timer = null;
-  this.hasSeenWiFi = false;
+  this.timeoutTimer = null;
   this.started = false;
-  // this is only used when logging is enabled, to debug interactions with the
-  // geolocation service
-  this.highAccuracy = false;
 }
 
 WifiGeoPositionProvider.prototype = {
   classID:          Components.ID("{77DA64D3-7458-4920-9491-86CC9914F904}"),
   QueryInterface:   XPCOMUtils.generateQI([Ci.nsIGeolocationProvider,
                                            Ci.nsIWifiListener,
                                            Ci.nsITimerCallback]),
   startup:  function() {
     if (this.started)
       return;
     this.started = true;
-    this.hasSeenWiFi = false;
 
-    LOG("startup called.  testing mode is" + gTestingEnabled);
-
-    // if we don't see anything in 5 seconds, kick of one IP geo lookup.
-    // if we are testing, just hammer this callback so that we are more or less
-    // always sending data.  It doesn't matter if we have an access point or not.
-    this.timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
-    if (!gTestingEnabled)
-      this.timer.initWithCallback(this, 5000, this.timer.TYPE_ONE_SHOT);
-    else
-      this.timer.initWithCallback(this, 200, this.timer.TYPE_REPEATING_SLACK);
+    if (gWifiScanningEnabled) {
+      this.wifiService = Cc["@mozilla.org/wifi/monitor;1"].getService(Components.interfaces.nsIWifiMonitor);
+      this.wifiService.startWatching(this);
+    }
+    this.timeoutTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
+    this.timeoutTimer.initWithCallback(this,
+                                       gTimeToWaitBeforeSending,
+                                       this.timeoutTimer.TYPE_REPEATING_SLACK);
+    LOG("startup called.");
   },
 
   watch: function(c) {
-    LOG("watch called");
-
-    if (!this.wifiService && gUseScanning) {
-      this.wifiService = Cc["@mozilla.org/wifi/monitor;1"].getService(Components.interfaces.nsIWifiMonitor);
-      this.wifiService.startWatching(this);
-    }
-    if (this.hasSeenWiFi) {
-      this.hasSeenWiFi = false;
-      if (gUseScanning) {
-        this.wifiService.stopWatching(this);
-        this.wifiService.startWatching(this);
-      } else {
-        // For testing situations, ensure that we always trigger an update.
-        this.timer.initWithCallback(this, 5000, this.timer.TYPE_ONE_SHOT);
-      }
-    }
   },
 
-  shutdown: function() { 
+  shutdown: function() {
     LOG("shutdown called");
+    if (this.started == false) {
+      return;
+    }
+
+    if (this.timeoutTimer) {
+      this.timeoutTimer.cancel();
+      this.timeoutTimer = null;
+    }
+
     if(this.wifiService) {
       this.wifiService.stopWatching(this);
       this.wifiService = null;
     }
-    if (this.timer != null) {
-      this.timer.cancel();
-      this.timer = null;
-    }
-
     this.started = false;
   },
 
   setHighAccuracy: function(enable) {
-    this.highAccuracy = enable;
-    LOG("setting highAccuracy to " + (this.highAccuracy?"TRUE":"FALSE"));
   },
 
   onChange: function(accessPoints) {
-    LOG("onChange called, highAccuracy = " + (this.highAccuracy?"TRUE":"FALSE"));
-    this.hasSeenWiFi = true;
-
-    Cc["@mozilla.org/geolocation/service;1"].getService(Ci.nsIGeolocationUpdate)
-        .locationUpdatePending();
-
-    let url = Services.urlFormatter.formatURLPref("geo.wifi.uri");
 
     function isPublic(ap) {
-        let mask = "_nomap"
-        let result = ap.ssid.indexOf(mask, ap.ssid.length - mask.length);
-        if (result != -1) {
-            LOG("Filtering out " + ap.ssid + " " + result);
-        }
-        return result;
+      let mask = "_nomap"
+      let result = ap.ssid.indexOf(mask, ap.ssid.length - mask.length);
+      if (result != -1) {
+        LOG("Filtering out " + ap.ssid + " " + result);
+      }
+      return result;
     };
 
     function sort(a, b) {
       return b.signal - a.signal;
     };
 
     function encode(ap) {
-      return { 'macAddress': ap.mac, 'signalStrength': ap.signal }; 
+      return { 'macAddress': ap.mac, 'signalStrength': ap.signal };
     };
 
     var data;
     if (accessPoints) {
-        data = JSON.stringify({wifiAccessPoints: accessPoints.filter(isPublic).sort(sort).map(encode)})
+      data = JSON.stringify({wifiAccessPoints: accessPoints.filter(isPublic).sort(sort).map(encode)})
     }
+    gWifiResults = data;
+  },
 
-    LOG("************************************* Sending request:\n" + url + "\n");
+  onError: function (code) {
+    LOG("wifi error: " + code);
+  },
 
-    // send our request to a wifi geolocation network provider:
+  notify: function (timeoutTimer) {
+    let url = Services.urlFormatter.formatURLPref("geo.wifi.uri");
+    LOG("Sending request: " + url + "\n");
+
     let xhr = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"]
                         .createInstance(Ci.nsIXMLHttpRequest);
 
-    // This is a background load
-  
+    getGeoService().locationUpdatePending();
+
     try {
-        xhr.open("POST", url, true);
+      xhr.open("POST", url, true);
     } catch (e) {
-       triggerError();
-       return;
+      getGeoService().notifyError(POSITION_UNAVAILABLE);
+      return;
     }
     xhr.setRequestHeader("Content-Type", "application/json; charset=UTF-8");
     xhr.responseType = "json";
     xhr.mozBackgroundRequest = true;
     xhr.channel.loadFlags = Ci.nsIChannel.LOAD_ANONYMOUS;
     xhr.onerror = function() {
-        LOG("onerror: " + xhr);
-        triggerError();
+      getGeoService().notifyError(POSITION_UNAVAILABLE);
+    };
+    xhr.onload = function() {
+      LOG("gls returned status: " + xhr.status + " --> " +  JSON.stringify(xhr.response));
+      if ((xhr.channel instanceof Ci.nsIHttpChannel && xhr.status != 200) ||
+          !xhr.response || !xhr.response.location) {
+        getGeoService().notifyError(POSITION_UNAVAILABLE);
+        return;
+      }
+
+      let newLocation = new WifiGeoPositionObject(xhr.response.location.lat,
+                                                  xhr.response.location.lng,
+                                                  xhr.response.accuracy);
+
+      getGeoService().update(newLocation);
     };
 
-    xhr.onload = function() {  
-        LOG("gls returned status: " + xhr.status + " --> " +  JSON.stringify(xhr.response));
-        if (xhr.channel instanceof Ci.nsIHttpChannel && xhr.status != 200) {
-            triggerError();
-            return;
-        }
-
-        if (!xhr.response || !xhr.response.location) {
-            triggerError();
-            return;
-        }
-
-        let newLocation = new WifiGeoPositionObject(xhr.response.location.lat,
-                                                    xhr.response.location.lng,
-                                                    xhr.response.accuracy);
-        
-        Cc["@mozilla.org/geolocation/service;1"].getService(Ci.nsIGeolocationUpdate)
-            .update(newLocation);
-    };
-
-    LOG("************************************* ------>>>> sending " + data);
+    let data = gWifiResults;
+    LOG("sending " + data);
     xhr.send(data);
   },
-
-  onError: function (code) {
-    LOG("wifi error: " + code);
-  },
-
-  notify: function (timer) {
-    if (gTestingEnabled || !gUseScanning) {
-      // if we are testing, timer is repeating
-      this.onChange(null);
-    }
-    else {
-      if (!this.hasSeenWiFi)
-        this.onChange(null);
-      this.timer = null;
-    }
-  },
 };
 
-function triggerError() {
-    Cc["@mozilla.org/geolocation/service;1"].getService(Ci.nsIGeolocationUpdate)
-        .notifyError(Ci.nsIDOMGeoPositionError.POSITION_UNAVAILABLE);
+function getGeoService() {
+  return Cc["@mozilla.org/geolocation/service;1"].getService(Ci.nsIGeolocationUpdate);
 }
+
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([WifiGeoPositionProvider]);
--- a/gfx/2d/GenericRefCounted.h
+++ b/gfx/2d/GenericRefCounted.h
@@ -32,16 +32,21 @@ class GenericRefCountedBase
 
     virtual void Release() = 0;
 
     // ref() and deref() method names are for compatibility with wtf::RefPtr.
     // No virtual keywords here: if a subclass wants to override the refcounting
     // mechanism, it is welcome to do so by overriding AddRef() and Release().
     void ref() { AddRef(); }
     void deref() { Release(); }
+
+#ifdef MOZ_REFCOUNTED_LEAK_CHECKING
+    virtual const char* typeName() const = 0;
+    virtual size_t typeSize() const = 0;
+#endif
 };
 
 namespace detail {
 
 template<RefCountAtomicity Atomicity>
 class GenericRefCounted : public GenericRefCountedBase
 {
   protected:
@@ -50,21 +55,28 @@ class GenericRefCounted : public Generic
     virtual ~GenericRefCounted() {
       MOZ_ASSERT(refCnt == detail::DEAD);
     }
 
   public:
     virtual void AddRef() {
       MOZ_ASSERT(int32_t(refCnt) >= 0);
       ++refCnt;
+#ifdef MOZ_REFCOUNTED_LEAK_CHECKING
+      detail::RefCountLogger::logAddRef(this, refCnt, typeName(), typeSize());
+#endif
     }
 
     virtual void Release() {
       MOZ_ASSERT(int32_t(refCnt) > 0);
-      if (0 == --refCnt) {
+      --refCnt;
+#ifdef MOZ_REFCOUNTED_LEAK_CHECKING
+      detail::RefCountLogger::logRelease(this, refCnt, typeName());
+#endif
+      if (0 == refCnt) {
 #ifdef DEBUG
         refCnt = detail::DEAD;
 #endif
         delete this;
       }
     }
 
     MozRefCountType refCount() const { return refCnt; }
--- a/gfx/gl/GLContextCGL.h
+++ b/gfx/gl/GLContextCGL.h
@@ -22,16 +22,17 @@ namespace gl {
 
 class GLContextCGL : public GLContext
 {
     friend class GLContextProviderCGL;
 
     NSOpenGLContext *mContext;
 
 public:
+    MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GLContextCGL)
     GLContextCGL(const SurfaceCaps& caps,
                  GLContext *shareContext,
                  NSOpenGLContext *context,
                  bool isOffscreen = false);
 
     ~GLContextCGL();
 
     virtual GLContextType GetContextType() const MOZ_OVERRIDE { return GLContextType::CGL; }
--- a/gfx/gl/GLContextEGL.h
+++ b/gfx/gl/GLContextEGL.h
@@ -24,16 +24,17 @@ class GLContextEGL : public GLContext
     static already_AddRefed<GLContextEGL>
     CreateGLContext(const SurfaceCaps& caps,
                     GLContextEGL *shareContext,
                     bool isOffscreen,
                     EGLConfig config,
                     EGLSurface surface);
 
 public:
+    MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GLContextEGL)
     GLContextEGL(const SurfaceCaps& caps,
                  GLContext* shareContext,
                  bool isOffscreen,
                  EGLConfig config,
                  EGLSurface surface,
                  EGLContext context);
 
     ~GLContextEGL();
--- a/gfx/gl/GLContextGLX.h
+++ b/gfx/gl/GLContextGLX.h
@@ -11,16 +11,17 @@
 #include "GLXLibrary.h"
 
 namespace mozilla {
 namespace gl {
 
 class GLContextGLX : public GLContext
 {
 public:
+    MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GLContextGLX)
     static already_AddRefed<GLContextGLX>
     CreateGLContext(const SurfaceCaps& caps,
                     GLContextGLX* shareContext,
                     bool isOffscreen,
                     Display* display,
                     GLXDrawable drawable,
                     GLXFBConfig cfg,
                     bool deleteDrawable,
--- a/gfx/gl/GLContextWGL.h
+++ b/gfx/gl/GLContextWGL.h
@@ -11,16 +11,17 @@
 #include "WGLLibrary.h"
 
 namespace mozilla {
 namespace gl {
 
 class GLContextWGL : public GLContext
 {
 public:
+    MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GLContextWGL)
     // From Window: (possibly for offscreen!)
     GLContextWGL(const SurfaceCaps& caps,
                  GLContext* sharedContext,
                  bool isOffscreen,
                  HDC aDC,
                  HGLRC aContext,
                  HWND aWindow = nullptr);
 
--- a/gfx/gl/SkiaGLGlue.h
+++ b/gfx/gl/SkiaGLGlue.h
@@ -12,16 +12,17 @@
 #include "skia/GrContext.h"
 
 namespace mozilla {
 namespace gl {
 
 class SkiaGLGlue : public GenericAtomicRefCounted
 {
 public:
+  MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SkiaGLGlue)
   SkiaGLGlue(GLContext* context);
   GLContext* GetGLContext() const { return mGLContext.get(); }
   GrContext* GetGrContext() const { return mGrContext.get(); }
 
 protected:
   virtual ~SkiaGLGlue() {
     /*
      * These members have inter-dependencies, but do not keep each other alive, so
--- a/gfx/gl/SurfaceStream.h
+++ b/gfx/gl/SurfaceStream.h
@@ -23,16 +23,17 @@ class GLContext;
 namespace gfx {
 class SharedSurface;
 class SurfaceFactory;
 
 // Owned by: ScreenBuffer
 class SurfaceStream : public GenericAtomicRefCounted
 {
 public:
+    MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SurfaceStream)
     typedef enum {
         MainThread,
         OffMainThread
     } OMTC;
 
     static SurfaceStreamType ChooseGLStreamType(OMTC omtc,
                                                 bool preserveBuffer);
 
@@ -140,16 +141,17 @@ public:
 // Not thread-safe. Don't use cross-threads.
 class SurfaceStream_SingleBuffer
     : public SurfaceStream
 {
 protected:
     SharedSurface* mConsumer; // Only present after resize-swap.
 
 public:
+    MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SurfaceStream_SingleBuffer)
     SurfaceStream_SingleBuffer(SurfaceStream* prevStream);
     virtual ~SurfaceStream_SingleBuffer();
 
     /* Since we're non-OMTC, we know the order of execution here:
      * SwapProd gets called in UpdateSurface, followed by
      * SwapCons being called in Render.
      */
     virtual SharedSurface* SwapProducer(SurfaceFactory* factory,
@@ -164,16 +166,17 @@ public:
 class SurfaceStream_TripleBuffer_Copy
     : public SurfaceStream
 {
 protected:
     SharedSurface* mStaging;
     SharedSurface* mConsumer;
 
 public:
+    MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SurfaceStream_TripleBuffer_Copy)
     SurfaceStream_TripleBuffer_Copy(SurfaceStream* prevStream);
     virtual ~SurfaceStream_TripleBuffer_Copy();
 
     virtual SharedSurface* SwapProducer(SurfaceFactory* factory,
                                         const gfx::IntSize& size);
 
     virtual SharedSurface* SwapConsumer_NoWait();
 
@@ -187,16 +190,17 @@ class SurfaceStream_TripleBuffer
 protected:
     SharedSurface* mStaging;
     SharedSurface* mConsumer;
 
     // To support subclasses initializing the mType.
     SurfaceStream_TripleBuffer(SurfaceStreamType type, SurfaceStream* prevStream);
 
 public:
+    MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SurfaceStream_TripleBuffer)
     SurfaceStream_TripleBuffer(SurfaceStream* prevStream);
     virtual ~SurfaceStream_TripleBuffer();
     virtual bool CopySurfaceToProducer(SharedSurface* src, SurfaceFactory* factory);
 
 private:
     // Common constructor code.
     void Init(SurfaceStream* prevStream);
 
--- a/ipc/chromium/src/base/message_loop.cc
+++ b/ipc/chromium/src/base/message_loop.cc
@@ -385,44 +385,22 @@ void MessageLoop::ReloadWorkQueue() {
     if (incoming_queue_.empty())
       return;
     std::swap(incoming_queue_, work_queue_);
     DCHECK(incoming_queue_.empty());
   }
 }
 
 bool MessageLoop::DeletePendingTasks() {
-  bool did_work = !work_queue_.empty();
-  while (!work_queue_.empty()) {
-    PendingTask pending_task = work_queue_.front();
-    work_queue_.pop();
-    if (!pending_task.delayed_run_time.is_null()) {
-      // We want to delete delayed tasks in the same order in which they would
-      // normally be deleted in case of any funny dependencies between delayed
-      // tasks.
-      AddToDelayedWorkQueue(pending_task);
-    } else {
-      // TODO(darin): Delete all tasks once it is safe to do so.
-      // Until it is totally safe, just do it when running purify.
-#ifdef PURIFY
-      delete pending_task.task;
-#endif  // PURIFY
-    }
-  }
-  did_work |= !deferred_non_nestable_work_queue_.empty();
+  MOZ_ASSERT(work_queue_.empty());
+  bool did_work = !deferred_non_nestable_work_queue_.empty();
   while (!deferred_non_nestable_work_queue_.empty()) {
-    // TODO(darin): Delete all tasks once it is safe to do so.
-    // Until it is totaly safe, just delete them to keep purify happy.
-#ifdef PURIFY
     Task* task = deferred_non_nestable_work_queue_.front().task;
-#endif
     deferred_non_nestable_work_queue_.pop();
-#ifdef PURIFY
     delete task;
-#endif
   }
   did_work |= !delayed_work_queue_.empty();
   while (!delayed_work_queue_.empty()) {
     Task* task = delayed_work_queue_.top().task;
     delayed_work_queue_.pop();
     delete task;
   }
   return did_work;
--- a/js/src/gc/GCInternals.h
+++ b/js/src/gc/GCInternals.h
@@ -147,15 +147,12 @@ class AutoStopVerifyingBarriers
 };
 #else
 struct AutoStopVerifyingBarriers
 {
     AutoStopVerifyingBarriers(JSRuntime *, bool) {}
 };
 #endif /* JS_GC_ZEAL */
 
-void
-CrashAtUnhandlableOOM(const char *reason);
-
 } /* namespace gc */
 } /* namespace js */
 
 #endif /* gc_GCInternals_h */
--- a/js/src/gc/StoreBuffer.h
+++ b/js/src/gc/StoreBuffer.h
@@ -19,20 +19,21 @@
 #include "jsalloc.h"
 
 #include "ds/LifoAlloc.h"
 #include "gc/Nursery.h"
 #include "js/MemoryMetrics.h"
 #include "js/Tracer.h"
 
 namespace js {
-namespace gc {
 
-extern void
-CrashAtUnhandlableOOM(const char *);
+void
+CrashAtUnhandlableOOM(const char *reason);
+
+namespace gc {
 
 /*
  * BufferableRef represents an abstract reference for use in the generational
  * GC's remembered set. Entries in the store buffer that cannot be represented
  * with the simple pointer-to-a-pointer scheme must derive from this class and
  * use the generic store buffer interface.
  */
 class BufferableRef
--- a/js/src/gc/Verifier.cpp
+++ b/js/src/gc/Verifier.cpp
@@ -877,17 +877,8 @@ js::gc::FinishVerifier(JSRuntime *rt)
     if (VerifyPostTracer *trc = (VerifyPostTracer *)rt->gcVerifyPostData) {
         js_delete(trc);
         rt->gcVerifyPostData = nullptr;
     }
 #endif
 }
 
 #endif /* JS_GC_ZEAL */
-
-void
-js::gc::CrashAtUnhandlableOOM(const char *reason)
-{
-    char msgbuf[1024];
-    JS_snprintf(msgbuf, sizeof(msgbuf), "[unhandlable oom] %s", reason);
-    MOZ_ReportAssertionFailure(msgbuf, __FILE__, __LINE__);
-    MOZ_CRASH();
-}
deleted file mode 100644
--- a/js/src/jit-test/tests/gc/bug-914614.js
+++ /dev/null
@@ -1,6 +0,0 @@
-// |jit-test| allow-oom
-if (typeof oomAfterAllocations == 'function') {
-    gczeal(4);
-    oomAfterAllocations(1);
-    var s = new Set;
-}
--- a/js/src/jit/IonAnalysis.cpp
+++ b/js/src/jit/IonAnalysis.cpp
@@ -2060,17 +2060,18 @@ AnalyzePoppedThis(JSContext *cx, types::
 
         Vector<MResumePoint *> callerResumePoints(cx);
         MBasicBlock *block = ins->block();
         for (MResumePoint *rp = block->callerResumePoint();
              rp;
              block = rp->block(), rp = block->callerResumePoint())
         {
             JSScript *script = rp->block()->info().script();
-            types::AddClearDefiniteFunctionUsesInScript(cx, type, script, block->info().script());
+            if (!types::AddClearDefiniteFunctionUsesInScript(cx, type, script, block->info().script()))
+                return true;
             if (!callerResumePoints.append(rp))
                 return false;
         }
 
         for (int i = callerResumePoints.length() - 1; i >= 0; i--) {
             MResumePoint *rp = callerResumePoints[i];
             JSScript *script = rp->block()->info().script();
             types::TypeNewScript::Initializer entry(types::TypeNewScript::Initializer::SETPROP_FRAME,
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -612,18 +612,17 @@ IonBuilder::build()
                 (int)script()->getUseCount(), OptimizationLevelString(optimizationInfo().level()));
     } else {
         IonSpew(IonSpew_Scripts, "Analyzing script %s:%d (%p) (usecount=%d, level=%s)",
                 script()->filename(), script()->lineno(), (void *)script(),
                 (int)script()->getUseCount(), OptimizationLevelString(optimizationInfo().level()));
     }
 #endif
 
-    if (!initParameters())
-        return false;
+    initParameters();
 
     // Initialize local variables.
     for (uint32_t i = 0; i < info().nlocals(); i++) {
         MConstant *undef = MConstant::New(alloc(), UndefinedValue());
         current->add(undef);
         current->initSlot(info().localSlot(i), undef);
     }
 
@@ -905,50 +904,45 @@ IonBuilder::rewriteParameters()
         return;
 
     for (uint32_t i = info().startArgSlot(); i < info().endArgSlot(); i++) {
         MDefinition *param = current->getSlot(i);
         rewriteParameter(i, param, param->toParameter()->index());
     }
 }
 
-bool
+void
 IonBuilder::initParameters()
 {
     if (!info().funMaybeLazy())
-        return true;
+        return;
 
     // If we are doing OSR on a frame which initially executed in the
     // interpreter and didn't accumulate type information, try to use that OSR
     // frame to determine possible initial types for 'this' and parameters.
 
-    if (thisTypes->empty() && baselineFrame_) {
-        if (!thisTypes->addType(baselineFrame_->thisType, alloc_->lifoAlloc()))
-            return false;
-    }
+    if (thisTypes->empty() && baselineFrame_)
+        thisTypes->addType(baselineFrame_->thisType, alloc_->lifoAlloc());
 
     MParameter *param = MParameter::New(alloc(), MParameter::THIS_SLOT, thisTypes);
     current->add(param);
     current->initSlot(info().thisSlot(), param);
 
     for (uint32_t i = 0; i < info().nargs(); i++) {
         types::TemporaryTypeSet *types = &argTypes[i];
         if (types->empty() && baselineFrame_ &&
             !script_->baselineScript()->modifiesArguments())
         {
-            if (!types->addType(baselineFrame_->argTypes[i], alloc_->lifoAlloc()))
-                return false;
+            types->addType(baselineFrame_->argTypes[i], alloc_->lifoAlloc());
         }
 
         param = MParameter::New(alloc(), i, types);
         current->add(param);
         current->initSlot(info().argSlotUnchecked(i), param);
     }
-
-    return true;
 }
 
 bool
 IonBuilder::initScopeChain(MDefinition *callee)
 {
     MInstruction *scope = nullptr;
 
     // If the script doesn't use the scopechain, then it's already initialized
@@ -4966,24 +4960,22 @@ IonBuilder::jsop_funapplyarguments(uint3
 bool
 IonBuilder::jsop_call(uint32_t argc, bool constructing)
 {
     // If this call has never executed, try to seed the observed type set
     // based on how the call result is used.
     types::TemporaryTypeSet *observed = bytecodeTypes(pc);
     if (observed->empty()) {
         if (BytecodeFlowsToBitop(pc)) {
-            if (!observed->addType(types::Type::Int32Type(), alloc_->lifoAlloc()))
-                return false;
+            observed->addType(types::Type::Int32Type(), alloc_->lifoAlloc());
         } else if (*GetNextPc(pc) == JSOP_POS) {
             // Note: this is lame, overspecialized on the code patterns used
             // by asm.js and should be replaced by a more general mechanism.
             // See bug 870847.
-            if (!observed->addType(types::Type::DoubleType(), alloc_->lifoAlloc()))
-                return false;
+            observed->addType(types::Type::DoubleType(), alloc_->lifoAlloc());
         }
     }
 
     int calleeDepth = -((int)argc + 2);
 
     // Acquire known call target if existent.
     ObjectVector originals(alloc());
     bool gotLambda = false;
@@ -7086,18 +7078,17 @@ bool
 IonBuilder::jsop_getelem_dense(MDefinition *obj, MDefinition *index)
 {
     types::TemporaryTypeSet *types = bytecodeTypes(pc);
 
     if (JSOp(*pc) == JSOP_CALLELEM && !index->mightBeType(MIRType_String)) {
         // Indexed call on an element of an array. Populate the observed types
         // with any objects that could be in the array, to avoid extraneous
         // type barriers.
-        if (!AddObjectsForPropertyRead(obj, nullptr, types))
-            return false;
+        AddObjectsForPropertyRead(obj, nullptr, types);
     }
 
     bool barrier = PropertyReadNeedsTypeBarrier(analysisContext, constraints(), obj, nullptr, types);
     bool needsHoleCheck = !ElementAccessIsPacked(constraints(), obj);
 
     // Reads which are on holes in the object do not have to bail out if
     // undefined values have been observed at this access site and the access
     // cannot hit another indexed property on the object or its prototypes.
@@ -9283,18 +9274,17 @@ IonBuilder::jsop_setarg(uint32_t arg)
                 for (MUseDefIterator iter(op); iter; iter++) {
                     MDefinition *def = iter.def();
                     if (def == val)
                         continue;
                     otherUses = true;
                 }
                 if (!otherUses) {
                     JS_ASSERT(op->resultTypeSet() == &argTypes[arg]);
-                    if (!argTypes[arg].addType(types::Type::UnknownType(), alloc_->lifoAlloc()))
-                        return false;
+                    argTypes[arg].addType(types::Type::UnknownType(), alloc_->lifoAlloc());
                     if (val->isMul()) {
                         val->setResultType(MIRType_Double);
                         val->toMul()->setSpecialization(MIRType_Double);
                     } else {
                         JS_ASSERT(val->type() == MIRType_Int32);
                     }
                     val->setResultTypeSet(nullptr);
                 }
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -322,17 +322,17 @@ class IonBuilder : public MIRGenerator
     // IonBuilder.cpp, near the definition for this function.
     bool resume(MInstruction *ins, jsbytecode *pc, MResumePoint::Mode mode);
     bool resumeAt(MInstruction *ins, jsbytecode *pc);
     bool resumeAfter(MInstruction *ins);
     bool maybeInsertResume();
 
     void insertRecompileCheck();
 
-    bool initParameters();
+    void initParameters();
     void rewriteParameter(uint32_t slotIdx, MDefinition *param, int32_t argIndex);
     void rewriteParameters();
     bool initScopeChain(MDefinition *callee = nullptr);
     bool initArgumentsObject();
     bool pushConstant(const Value &v);
 
     MConstant *constant(const Value &v);
     MConstant *constantInt(int32_t i);
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -935,18 +935,17 @@ IonBuilder::inlineMathFRound(CallInfo &c
         return InliningStatus_NotInlined;
 
     // MIRType can't be Float32, as this point, as getInlineReturnType uses JSVal types
     // to infer the returned MIR type.
     types::TemporaryTypeSet *returned = getInlineReturnTypeSet();
     if (returned->empty()) {
         // As there's only one possible returned type, just add it to the observed
         // returned typeset
-        if (!returned->addType(types::Type::DoubleType(), alloc_->lifoAlloc()))
-            return InliningStatus_Error;
+        returned->addType(types::Type::DoubleType(), alloc_->lifoAlloc());
     } else {
         MIRType returnType = getInlineReturnType();
         if (!IsNumberType(returnType))
             return InliningStatus_NotInlined;
     }
 
     MIRType arg = callInfo.getArg(0)->type();
     if (!IsNumberType(arg))
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -2760,20 +2760,18 @@ InlinePropertyTable::hasFunction(JSFunct
 types::TemporaryTypeSet *
 InlinePropertyTable::buildTypeSetForFunction(JSFunction *func) const
 {
     LifoAlloc *alloc = GetIonContext()->temp->lifoAlloc();
     types::TemporaryTypeSet *types = alloc->new_<types::TemporaryTypeSet>();
     if (!types)
         return nullptr;
     for (size_t i = 0; i < numEntries(); i++) {
-        if (entries_[i]->func == func) {
-            if (!types->addType(types::Type::ObjectType(entries_[i]->typeObj), alloc))
-                return nullptr;
-        }
+        if (entries_[i]->func == func)
+            types->addType(types::Type::ObjectType(entries_[i]->typeObj), alloc);
     }
     return types;
 }
 
 void *
 MLoadTypedArrayElementStatic::base() const
 {
     return typedArray_->viewData();
@@ -3167,54 +3165,58 @@ jit::PropertyReadIsIdempotent(types::Com
             if (property.nonData(constraints))
                 return false;
         }
     }
 
     return true;
 }
 
-bool
+void
 jit::AddObjectsForPropertyRead(MDefinition *obj, PropertyName *name,
                                types::TemporaryTypeSet *observed)
 {
     // Add objects to observed which *could* be observed by reading name from obj,
     // to hopefully avoid unnecessary type barriers and code invalidations.
 
     LifoAlloc *alloc = GetIonContext()->temp->lifoAlloc();
 
     types::TemporaryTypeSet *types = obj->resultTypeSet();
-    if (!types || types->unknownObject())
-        return observed->addType(types::Type::AnyObjectType(), alloc);
+    if (!types || types->unknownObject()) {
+        observed->addType(types::Type::AnyObjectType(), alloc);
+        return;
+    }
 
     for (size_t i = 0; i < types->getObjectCount(); i++) {
         types::TypeObjectKey *object = types->getObject(i);
         if (!object)
             continue;
 
-        if (object->unknownProperties())
-            return observed->addType(types::Type::AnyObjectType(), alloc);
+        if (object->unknownProperties()) {
+            observed->addType(types::Type::AnyObjectType(), alloc);
+            return;
+        }
 
         jsid id = name ? NameToId(name) : JSID_VOID;
         types::HeapTypeSetKey property = object->property(id);
         types::HeapTypeSet *types = property.maybeTypes();
         if (!types)
             continue;
 
-        if (types->unknownObject())
-            return observed->addType(types::Type::AnyObjectType(), alloc);
+        if (types->unknownObject()) {
+            observed->addType(types::Type::AnyObjectType(), alloc);
+            return;
+        }
 
         for (size_t i = 0; i < types->getObjectCount(); i++) {
             types::TypeObjectKey *object = types->getObject(i);
-            if (object && !observed->addType(types::Type::ObjectType(object), alloc))
-                return false;
+            if (object)
+                observed->addType(types::Type::ObjectType(object), alloc);
         }
     }
-
-    return true;
 }
 
 static bool
 TryAddTypeBarrierForWrite(TempAllocator &alloc, types::CompilerConstraintList *constraints,
                           MBasicBlock *current, types::TemporaryTypeSet *objTypes,
                           PropertyName *name, MDefinition **pvalue)
 {
     // Return whether pvalue was modified to include a type barrier ensuring
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -9861,17 +9861,17 @@ bool PropertyReadNeedsTypeBarrier(JSCont
                                   types::CompilerConstraintList *constraints,
                                   MDefinition *obj, PropertyName *name,
                                   types::TemporaryTypeSet *observed);
 bool PropertyReadOnPrototypeNeedsTypeBarrier(types::CompilerConstraintList *constraints,
                                              MDefinition *obj, PropertyName *name,
                                              types::TemporaryTypeSet *observed);
 bool PropertyReadIsIdempotent(types::CompilerConstraintList *constraints,
                               MDefinition *obj, PropertyName *name);
-bool AddObjectsForPropertyRead(MDefinition *obj, PropertyName *name,
+void AddObjectsForPropertyRead(MDefinition *obj, PropertyName *name,
                                types::TemporaryTypeSet *observed);
 bool PropertyWriteNeedsTypeBarrier(TempAllocator &alloc, types::CompilerConstraintList *constraints,
                                    MBasicBlock *current, MDefinition **pobj,
                                    PropertyName *name, MDefinition **pvalue,
                                    bool canModify);
 
 } // namespace jit
 } // namespace js
--- a/js/src/jsanalyze.cpp
+++ b/js/src/jsanalyze.cpp
@@ -2201,20 +2201,18 @@ ScriptAnalysis::needsArgsObj(JSContext *
      */
     if (!trackUseChain(v))
         return false;
 
     for (unsigned i = 0; i < seen.length(); i++) {
         if (v == seen[i])
             return false;
     }
-    if (!seen.append(v)) {
-        cx->compartment()->types.setPendingNukeTypes(cx);
+    if (!seen.append(v))
         return true;
-    }
 
     SSAUseChain *use = useChain(v);
     while (use) {
         if (needsArgsObj(cx, seen, use))
             return true;
         use = use->next;
     }
 
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -1360,8 +1360,16 @@ void CompartmentChecker::check(StackFram
 
 void CompartmentChecker::check(AbstractFramePtr frame)
 {
     if (frame)
         check(frame.scopeChain());
 }
 #endif
 
+void
+js::CrashAtUnhandlableOOM(const char *reason)
+{
+    char msgbuf[1024];
+    JS_snprintf(msgbuf, sizeof(msgbuf), "[unhandlable oom] %s", reason);
+    MOZ_ReportAssertionFailure(msgbuf, __FILE__, __LINE__);
+    MOZ_CRASH();
+}
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -1088,15 +1088,18 @@ class AutoLockForExclusiveAccess
         // An empty destructor is needed to avoid warnings from clang about
         // unused local variables of this type.
     }
 #endif // JS_THREADSAFE
 
     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 
+void
+CrashAtUnhandlableOOM(const char *reason);
+
 } /* namespace js */
 
 #ifdef _MSC_VER
 #pragma warning(pop)
 #endif
 
 #endif /* jscntxt_h */
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -369,53 +369,55 @@ TypeSet::enumerateTypes(TypeList *list)
             if (!list->append(Type::ObjectType(object)))
                 return false;
         }
     }
 
     return true;
 }
 
-inline void
+inline bool
 TypeSet::addTypesToConstraint(JSContext *cx, TypeConstraint *constraint)
 {
     /*
      * Build all types in the set into a vector before triggering the
      * constraint, as doing so may modify this type set.
      */
     TypeList types;
     if (!enumerateTypes(&types))
-        cx->compartment()->types.setPendingNukeTypes(cx);
+        return false;
 
     for (unsigned i = 0; i < types.length(); i++)
         constraint->newType(cx, this, types[i]);
+
+    return true;
 }
 
-void
-ConstraintTypeSet::add(JSContext *cx, TypeConstraint *constraint, bool callExisting)
+bool
+ConstraintTypeSet::addConstraint(JSContext *cx, TypeConstraint *constraint, bool callExisting)
 {
     if (!constraint) {
         /* OOM failure while constructing the constraint. */
-        cx->compartment()->types.setPendingNukeTypes(cx);
-        return;
+        return false;
     }
 
     JS_ASSERT(cx->compartment()->activeAnalysis);
 
     InferSpew(ISpewOps, "addConstraint: %sT%p%s %sC%p%s %s",
               InferSpewColor(this), this, InferSpewColorReset(),
               InferSpewColor(constraint), constraint, InferSpewColorReset(),
               constraint->kind());
 
     JS_ASSERT(constraint->next == nullptr);
     constraint->next = constraintList;
     constraintList = constraint;
 
     if (callExisting)
-        addTypesToConstraint(cx, constraint);
+        return addTypesToConstraint(cx, constraint);
+    return true;
 }
 
 void
 TypeSet::print()
 {
     if (flags & TYPE_FLAG_NON_DATA_PROPERTY)
         fprintf(stderr, " [non-data]");
 
@@ -497,24 +499,22 @@ TypeSet::unionSets(TypeSet *a, TypeSet *
 {
     TemporaryTypeSet *res = alloc->new_<TemporaryTypeSet>(a->baseFlags() | b->baseFlags(),
                                                           static_cast<TypeObjectKey**>(nullptr));
     if (!res)
         return nullptr;
 
     if (!res->unknownObject()) {
         for (size_t i = 0; i < a->getObjectCount() && !res->unknownObject(); i++) {
-            TypeObjectKey *key = a->getObject(i);
-            if (key && !res->addType(Type::ObjectType(key), alloc))
-                return nullptr;
+            if (TypeObjectKey *key = a->getObject(i))
+                res->addType(Type::ObjectType(key), alloc);
         }
         for (size_t i = 0; i < b->getObjectCount() && !res->unknownObject(); i++) {
-            TypeObjectKey *key = b->getObject(i);
-            if (key && !res->addType(Type::ObjectType(key), alloc))
-                return nullptr;
+            if (TypeObjectKey *key = b->getObject(i))
+                res->addType(Type::ObjectType(key), alloc);
         }
     }
 
     return res;
 }
 
 /////////////////////////////////////////////////////////////////////
 // Compiler constraints
@@ -756,42 +756,39 @@ class TypeCompilerConstraint : public Ty
     void newObjectState(JSContext *cx, TypeObject *object) {
         // Note: Once the object has unknown properties, no more notifications
         // will be sent on changes to its state, so always invalidate any
         // associated compilations.
         if (object->unknownProperties() || data.invalidateOnNewObjectState(object))
             cx->zone()->types.addPendingRecompile(cx, compilation);
     }
 
-    TypeConstraint *sweep(TypeZone &zone) {
+    bool sweep(TypeZone &zone, TypeConstraint **res) {
         if (data.shouldSweep() || compilation.shouldSweep(zone))
-            return nullptr;
-        TypeConstraint *res = zone.typeLifoAlloc.new_<TypeCompilerConstraint<T> >(compilation, data);
-        if (!res)
-            zone.setPendingNukeTypes();
-        return res;
+            return false;
+        *res = zone.typeLifoAlloc.new_<TypeCompilerConstraint<T> >(compilation, data);
+        return true;
     }
 };
 
 template <typename T>
 bool
 CompilerConstraintInstance<T>::generateTypeConstraint(JSContext *cx, RecompileInfo recompileInfo)
 {
     if (property.object()->unknownProperties())
         return false;
 
     if (!property.instantiate(cx))
         return false;
 
     if (!data.constraintHolds(cx, property, expected))
         return false;
 
-    property.maybeTypes()->add(cx, cx->typeLifoAlloc().new_<TypeCompilerConstraint<T> >(recompileInfo, data),
-                               /* callExisting = */ false);
-    return true;
+    return property.maybeTypes()->addConstraint(cx, cx->typeLifoAlloc().new_<TypeCompilerConstraint<T> >(recompileInfo, data),
+                                                /* callExisting = */ false);
 }
 
 } /* anonymous namespace */
 
 const Class *
 TypeObjectKey::clasp()
 {
     return isTypeObject() ? asTypeObject()->clasp() : asSingleObject()->getClass();
@@ -936,23 +933,21 @@ class TypeConstraintFreezeStack : public
     void newType(JSContext *cx, TypeSet *source, Type type) {
         /*
          * Unlike TypeConstraintFreeze, triggering this constraint once does
          * not disable it on future changes to the type set.
          */
         cx->zone()->types.addPendingRecompile(cx, script_);
     }
 
-    TypeConstraint *sweep(TypeZone &zone) {
+    bool sweep(TypeZone &zone, TypeConstraint **res) {
         if (IsScriptAboutToBeFinalized(&script_))
-            return nullptr;
-        TypeConstraint *res = zone.typeLifoAlloc.new_<TypeConstraintFreezeStack>(script_);
-        if (!res)
-            zone.setPendingNukeTypes();
-        return res;
+            return false;
+        *res = zone.typeLifoAlloc.new_<TypeConstraintFreezeStack>(script_);
+        return true;
     }
 };
 
 } /* anonymous namespace */
 
 bool
 types::FinishCompilation(JSContext *cx, HandleScript script, ExecutionMode executionMode,
                          CompilerConstraintList *constraints, RecompileInfo *precompileInfo)
@@ -1012,18 +1007,20 @@ types::FinishCompilation(JSContext *cx, 
         // after any future changes to the stack type sets.
         if (entry.script->hasFreezeConstraints())
             continue;
         entry.script->setHasFreezeConstraints();
 
         size_t count = TypeScript::NumTypeSets(entry.script);
 
         StackTypeSet *array = entry.script->types->typeArray();
-        for (size_t i = 0; i < count; i++)
-            array[i].add(cx, cx->typeLifoAlloc().new_<TypeConstraintFreezeStack>(entry.script), false);
+        for (size_t i = 0; i < count; i++) {
+            if (!array[i].addConstraint(cx, cx->typeLifoAlloc().new_<TypeConstraintFreezeStack>(entry.script), false))
+                succeeded = false;
+        }
     }
 
     if (!succeeded || types.compilerOutputs->back().pendingInvalidation()) {
         types.compilerOutputs->back().invalidate();
         script->resetUseCount();
         return false;
     }
 
@@ -1971,17 +1968,17 @@ FindPreviousInnerInitializer(HandleScrip
 TypeObject *
 TypeCompartment::addAllocationSiteTypeObject(JSContext *cx, AllocationSiteKey key)
 {
     AutoEnterAnalysis enter(cx);
 
     if (!allocationSiteTable) {
         allocationSiteTable = cx->new_<AllocationSiteTable>();
         if (!allocationSiteTable || !allocationSiteTable->init()) {
-            cx->compartment()->types.setPendingNukeTypes(cx);
+            js_delete(allocationSiteTable);
             return nullptr;
         }
     }
 
     AllocationSiteTable::AddPtr p = allocationSiteTable->lookupForAdd(key);
     JS_ASSERT(!p);
 
     TypeObject *res = nullptr;
@@ -2007,39 +2004,35 @@ TypeCompartment::addAllocationSiteTypeOb
 
     if (!res) {
         RootedObject proto(cx);
         if (!js_GetClassPrototype(cx, key.kind, &proto))
             return nullptr;
 
         Rooted<TaggedProto> tagged(cx, TaggedProto(proto));
         res = newTypeObject(cx, GetClassForProtoKey(key.kind), tagged, OBJECT_FLAG_FROM_ALLOCATION_SITE);
-        if (!res) {
-            cx->compartment()->types.setPendingNukeTypes(cx);
+        if (!res)
             return nullptr;
-        }
         key.script = keyScript;
     }
 
     if (JSOp(*pc) == JSOP_NEWOBJECT) {
         /*
          * This object is always constructed the same way and will not be
          * observed by other code before all properties have been added. Mark
          * all the properties as definite properties of the object.
          */
         RootedObject baseobj(cx, key.script->getObject(GET_UINT32_INDEX(pc)));
 
         if (!res->addDefiniteProperties(cx, baseobj))
             return nullptr;
     }
 
-    if (!allocationSiteTable->add(p, key, res)) {
-        cx->compartment()->types.setPendingNukeTypes(cx);
+    if (!allocationSiteTable->add(p, key, res))
         return nullptr;
-    }
 
     return res;
 }
 
 static inline jsid
 GetAtomId(JSContext *cx, JSScript *script, const jsbytecode *pc, unsigned offset)
 {
     PropertyName *name = script->getName(GET_UINT32_INDEX(pc + offset));
@@ -2205,93 +2198,35 @@ TypeZone::processPendingRecompiles(FreeO
 #ifdef JS_ION
     jit::Invalidate(*this, fop, *pending);
 #endif
 
     fop->delete_(pending);
 }
 
 void
-TypeCompartment::setPendingNukeTypes(ExclusiveContext *cx)
-{
-    TypeZone *zone = &compartment()->zone()->types;
-    if (!zone->pendingNukeTypes) {
-        if (cx->compartment())
-            js_ReportOutOfMemory(cx);
-        zone->pendingNukeTypes = true;
-    }
-}
-
-void
-TypeZone::setPendingNukeTypes()
-{
-    pendingNukeTypes = true;
-}
-
-void
-TypeZone::nukeTypes(FreeOp *fop)
-{
-    /*
-     * This is the usual response if we encounter an OOM while adding a type
-     * or resolving type constraints. Reset the compartment to not use type
-     * inference, and recompile all scripts.
-     *
-     * Because of the nature of constraint-based analysis (add constraints, and
-     * iterate them until reaching a fixpoint), we can't undo an add of a type set,
-     * and merely aborting the operation which triggered the add will not be
-     * sufficient for correct behavior as we will be leaving the types in an
-     * inconsistent state.
-     */
-    JS_ASSERT(pendingNukeTypes);
-
-    if (pendingRecompiles) {
-        fop->free_(pendingRecompiles);
-        pendingRecompiles = nullptr;
-    }
-
-    inferenceEnabled = false;
-
-#ifdef JS_ION
-    jit::InvalidateAll(fop, zone());
-
-    /* Throw away all JIT code in the compartment, but leave everything else alone. */
-
-    for (gc::CellIter i(zone(), gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
-        JSScript *script = i.get<JSScript>();
-        jit::FinishInvalidation(fop, script);
-    }
-#endif /* JS_ION */
-
-    pendingNukeTypes = false;
-}
-
-void
 TypeZone::addPendingRecompile(JSContext *cx, const RecompileInfo &info)
 {
     CompilerOutput *co = info.compilerOutput(cx);
     if (!co || !co->isValid() || co->pendingInvalidation())
         return;
 
-    if (!pendingRecompiles) {
-        pendingRecompiles = cx->new_< Vector<RecompileInfo> >(cx);
-        if (!pendingRecompiles) {
-            cx->compartment()->types.setPendingNukeTypes(cx);
-            return;
-        }
-    }
-
-    if (!pendingRecompiles->append(info)) {
-        cx->compartment()->types.setPendingNukeTypes(cx);
-        return;
-    }
-
     InferSpew(ISpewOps, "addPendingRecompile: %p:%s:%d",
               co->script(), co->script()->filename(), co->script()->lineno());
 
     co->setPendingInvalidation();
+
+    if (!pendingRecompiles) {
+        pendingRecompiles = cx->new_< Vector<RecompileInfo> >(cx);
+        if (!pendingRecompiles)
+            CrashAtUnhandlableOOM("Could not update pendingRecompiles");
+    }
+
+    if (!pendingRecompiles->append(info))
+        CrashAtUnhandlableOOM("Could not update pendingRecompiles");
 }
 
 void
 TypeZone::addPendingRecompile(JSContext *cx, JSScript *script)
 {
     JS_ASSERT(script);
 
 #ifdef JS_ION
@@ -2320,42 +2255,28 @@ TypeCompartment::markSetsUnknown(JSConte
 {
     JS_ASSERT(this == &cx->compartment()->types);
     JS_ASSERT(!(target->flags() & OBJECT_FLAG_SETS_MARKED_UNKNOWN));
     JS_ASSERT(!target->singleton());
     JS_ASSERT(target->unknownProperties());
 
     AutoEnterAnalysis enter(cx);
 
-    /*
-     * Mark both persistent and transient type sets which contain obj as having
-     * a generic object type. It is not sufficient to mark just the persistent
-     * sets, as analysis of individual opcodes can pull type objects from
-     * static information (like initializer objects at various offsets).
-     *
-     * We make a list of properties to update and fix them afterwards, as adding
-     * types can't be done while iterating over cells as it can potentially make
-     * new type objects as well or trigger GC.
-     */
-    Vector<ConstraintTypeSet *> pending(cx);
+    /* Mark type sets which contain obj as having a generic object types. */
+
     for (gc::CellIter i(cx->zone(), gc::FINALIZE_TYPE_OBJECT); !i.done(); i.next()) {
         TypeObject *object = i.get<TypeObject>();
         unsigned count = object->getPropertyCount();
         for (unsigned i = 0; i < count; i++) {
             Property *prop = object->getProperty(i);
-            if (prop && prop->types.hasType(Type::ObjectType(target))) {
-                if (!pending.append(&prop->types))
-                    cx->compartment()->types.setPendingNukeTypes(cx);
-            }
+            if (prop && prop->types.hasType(Type::ObjectType(target)))
+                prop->types.addType(cx, Type::AnyObjectType());
         }
     }
 
-    for (unsigned i = 0; i < pending.length(); i++)
-        pending[i]->addType(cx, Type::AnyObjectType());
-
     for (gc::CellIter i(cx->zone(), gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
         RootedScript script(cx, i.get<JSScript>());
         if (script->types) {
             unsigned count = TypeScript::NumTypeSets(script);
             StackTypeSet *typeArray = script->types->typeArray();
             for (unsigned i = 0; i < count; i++) {
                 if (typeArray[i].hasType(Type::ObjectType(target)))
                     typeArray[i].addType(cx, Type::AnyObjectType());
@@ -2456,43 +2377,37 @@ TypeCompartment::setTypeToHomogenousArra
                                           JSObject *obj, Type elementType)
 {
     JS_ASSERT(cx->compartment()->activeAnalysis);
 
     if (!arrayTypeTable) {
         arrayTypeTable = cx->new_<ArrayTypeTable>();
         if (!arrayTypeTable || !arrayTypeTable->init()) {
             arrayTypeTable = nullptr;
-            cx->compartment()->types.setPendingNukeTypes(cx);
             return;
         }
     }
 
     ArrayTableKey key(elementType, obj->getProto());
     DependentAddPtr<ArrayTypeTable> p(cx, *arrayTypeTable, key);
     if (p) {
         obj->setType(p->value());
     } else {
         /* Make a new type to use for future arrays with the same elements. */
         RootedObject objProto(cx, obj->getProto());
         TypeObject *objType = newTypeObject(cx, &ArrayObject::class_, objProto);
-        if (!objType) {
-            cx->compartment()->types.setPendingNukeTypes(cx);
+        if (!objType)
             return;
-        }
         obj->setType(objType);
 
         if (!objType->unknownProperties())
             objType->addPropertyType(cx, JSID_VOID, elementType);
 
         key.proto = objProto;
-        if (!p.add(cx, *arrayTypeTable, key, objType)) {
-            cx->compartment()->types.setPendingNukeTypes(cx);
-            return;
-        }
+        (void) p.add(cx, *arrayTypeTable, key, objType);
     }
 }
 
 void
 TypeCompartment::fixArrayType(ExclusiveContext *cx, JSObject *obj)
 {
     AutoEnterAnalysis enter(cx);
 
@@ -2620,18 +2535,18 @@ UpdateObjectTableEntryTypes(ExclusiveCon
 void
 TypeCompartment::fixObjectType(ExclusiveContext *cx, JSObject *obj)
 {
     AutoEnterAnalysis enter(cx);
 
     if (!objectTypeTable) {
         objectTypeTable = cx->new_<ObjectTypeTable>();
         if (!objectTypeTable || !objectTypeTable->init()) {
+            js_delete(objectTypeTable);
             objectTypeTable = nullptr;
-            cx->compartment()->types.setPendingNukeTypes(cx);
             return;
         }
     }
 
     /*
      * Use the same type object for all singleton/JSON objects with the same
      * base shape, i.e. the same fields written in the same order.
      */
@@ -2641,20 +2556,18 @@ TypeCompartment::fixObjectType(Exclusive
      * Exclude some objects we can't readily associate common types for based on their
      * shape. Objects with metadata are excluded so that the metadata does not need to
      * be included in the table lookup (the metadata object might be in the nursery).
      */
     if (obj->slotSpan() == 0 || obj->inDictionaryMode() || !obj->hasEmptyElements() || obj->getMetadata())
         return;
 
     Vector<IdValuePair> properties(cx);
-    if (!properties.resize(obj->slotSpan())) {
-        cx->compartment()->types.setPendingNukeTypes(cx);
+    if (!properties.resize(obj->slotSpan()))
         return;
-    }
 
     Shape *shape = obj->lastProperty();
     while (!shape->isEmptyShape()) {
         IdValuePair &entry = properties[shape->slot()];
         entry.id = shape->propid();
         entry.value = obj->getSlot(shape->slot());
         shape = shape->previous();
     }
@@ -2669,35 +2582,29 @@ TypeCompartment::fixObjectType(Exclusive
         UpdateObjectTableEntryTypes(cx, p->value(), properties.begin(), properties.length());
         obj->setType(p->value().object);
         return;
     }
 
     /* Make a new type to use for the object and similar future ones. */
     Rooted<TaggedProto> objProto(cx, obj->getTaggedProto());
     TypeObject *objType = newTypeObject(cx, &JSObject::class_, objProto);
-    if (!objType || !objType->addDefiniteProperties(cx, obj)) {
-        cx->compartment()->types.setPendingNukeTypes(cx);
+    if (!objType || !objType->addDefiniteProperties(cx, obj))
         return;
-    }
 
     if (obj->isIndexed())
         objType->setFlags(cx, OBJECT_FLAG_SPARSE_INDEXES);
 
-    jsid *ids = cx->pod_calloc<jsid>(properties.length());
-    if (!ids) {
-        cx->compartment()->types.setPendingNukeTypes(cx);
+    ScopedJSFreePtr<jsid> ids(cx->pod_calloc<jsid>(properties.length()));
+    if (!ids)
         return;
-    }
-
-    Type *types = cx->pod_calloc<Type>(properties.length());
-    if (!types) {
-        cx->compartment()->types.setPendingNukeTypes(cx);
+
+    ScopedJSFreePtr<Type> types(cx->pod_calloc<Type>(properties.length()));
+    if (!types)
         return;
-    }
 
     for (size_t i = 0; i < properties.length(); i++) {
         ids[i] = properties[i].id;
         types[i] = GetValueTypeForTable(obj->getSlot(i));
         if (!objType->unknownProperties())
             objType->addPropertyType(cx, IdToTypeId(ids[i]), types[i]);
     }
 
@@ -2707,35 +2614,35 @@ TypeCompartment::fixObjectType(Exclusive
     key.nfixed = obj->numFixedSlots();
     JS_ASSERT(ObjectTableKey::match(key, lookup));
 
     ObjectTableEntry entry;
     entry.object = objType;
     entry.shape = obj->lastProperty();
     entry.types = types;
 
+    obj->setType(objType);
+
     p = objectTypeTable->lookupForAdd(lookup);
-    if (!objectTypeTable->add(p, key, entry)) {
-        cx->compartment()->types.setPendingNukeTypes(cx);
-        return;
+    if (objectTypeTable->add(p, key, entry)) {
+        ids.forget();
+        types.forget();
     }
-
-    obj->setType(objType);
 }
 
 JSObject *
 TypeCompartment::newTypedObject(JSContext *cx, IdValuePair *properties, size_t nproperties)
 {
     AutoEnterAnalysis enter(cx);
 
     if (!objectTypeTable) {
         objectTypeTable = cx->new_<ObjectTypeTable>();
         if (!objectTypeTable || !objectTypeTable->init()) {
+            js_delete(objectTypeTable);
             objectTypeTable = nullptr;
-            cx->compartment()->types.setPendingNukeTypes(cx);
             return nullptr;
         }
     }
 
     /*
      * Use the object type table to allocate an object with the specified
      * properties, filling in its final type and shape and failing if no cache
      * entry could be found for the properties.
@@ -2802,46 +2709,42 @@ static inline void
 UpdatePropertyType(ExclusiveContext *cx, HeapTypeSet *types, JSObject *obj, Shape *shape,
                    bool indexed)
 {
     if (!shape->writable())
         types->setNonWritableProperty(cx);
 
     if (shape->hasGetterValue() || shape->hasSetterValue()) {
         types->setNonDataProperty(cx);
-        if (!types->TypeSet::addType(Type::UnknownType(), &cx->typeLifoAlloc()))
-            cx->compartment()->types.setPendingNukeTypes(cx);
+        types->TypeSet::addType(Type::UnknownType(), &cx->typeLifoAlloc());
     } else if (shape->hasDefaultGetter() && shape->hasSlot()) {
         if (!indexed && types->canSetDefinite(shape->slot()))
             types->setDefinite(shape->slot());
 
         const Value &value = obj->nativeGetSlot(shape->slot());
 
         /*
          * Don't add initial undefined types for properties of global objects
          * that are not collated into the JSID_VOID property (see propertySet
          * comment).
          */
         if (indexed || !value.isUndefined() || !CanHaveEmptyPropertyTypesForOwnProperty(obj)) {
             Type type = GetValueType(value);
-            if (!types->TypeSet::addType(type, &cx->typeLifoAlloc()))
-                cx->compartment()->types.setPendingNukeTypes(cx);
+            types->TypeSet::addType(type, &cx->typeLifoAlloc());
         }
     }
 }
 
 bool
 TypeObject::addProperty(ExclusiveContext *cx, jsid id, Property **pprop)
 {
     JS_ASSERT(!*pprop);
     Property *base = cx->typeLifoAlloc().new_<Property>(id);
-    if (!base) {
-        cx->compartment()->types.setPendingNukeTypes(cx);
+    if (!base)
         return false;
-    }
 
     if (singleton() && singleton()->isNative()) {
         /*
          * Fill the property in with any type the object already has in an own
          * property. We are only interested in plain native properties and
          * dense elements which don't go through a barrier when read by the VM
          * or jitcode.
          */
@@ -2855,18 +2758,17 @@ TypeObject::addProperty(ExclusiveContext
                 shape = shape->previous();
             }
 
             /* Also get values of any dense elements in the object. */
             for (size_t i = 0; i < singleton()->getDenseInitializedLength(); i++) {
                 const Value &value = singleton()->getDenseElement(i);
                 if (!value.isMagic(JS_ELEMENTS_HOLE)) {
                     Type type = GetValueType(value);
-                    if (!base->types.TypeSet::addType(type, &cx->typeLifoAlloc()))
-                        cx->compartment()->types.setPendingNukeTypes(cx);
+                    base->types.TypeSet::addType(type, &cx->typeLifoAlloc());
                 }
             }
         } else if (!JSID_IS_EMPTY(id)) {
             RootedId rootedId(cx, id);
             Shape *shape = singleton()->nativeLookup(cx, rootedId);
             if (shape)
                 UpdatePropertyType(cx, &base->types, singleton(), shape, false);
         }
@@ -2965,38 +2867,16 @@ TypeObject::addPropertyType(ExclusiveCon
 
 void
 TypeObject::addPropertyType(ExclusiveContext *cx, jsid id, const Value &value)
 {
     InlineAddTypeProperty(cx, this, id, GetValueType(value));
 }
 
 void
-TypeObject::addPropertyType(ExclusiveContext *cx, const char *name, Type type)
-{
-    jsid id = JSID_VOID;
-    if (name) {
-        JSAtom *atom = Atomize(cx, name, strlen(name));
-        if (!atom) {
-            AutoEnterAnalysis enter(cx);
-            cx->compartment()->types.setPendingNukeTypes(cx);
-            return;
-        }
-        id = AtomToId(atom);
-    }
-    InlineAddTypeProperty(cx, this, id, type);
-}
-
-void
-TypeObject::addPropertyType(ExclusiveContext *cx, const char *name, const Value &value)
-{
-    addPropertyType(cx, name, GetValueType(value));
-}
-
-void
 TypeObject::markPropertyNonData(ExclusiveContext *cx, jsid id)
 {
     AutoEnterAnalysis enter(cx);
 
     id = IdToTypeId(id);
 
     HeapTypeSet *types = getProperty(cx, id);
     if (types)
@@ -3237,20 +3117,18 @@ TypeObject::clearNewScriptAddendum(Exclu
                     }
                 } else {
                     JS_ASSERT(init->kind == TypeNewScript::Initializer::DONE);
                     finished = true;
                     break;
                 }
             }
 
-            if (!finished) {
-                if (!JSObject::rollbackProperties(cx, obj, numProperties))
-                    cx->compartment()->types.setPendingNukeTypes(cx);
-            }
+            if (!finished)
+                (void) JSObject::rollbackProperties(cx, obj, numProperties);
         }
     } else {
         // Threads with an ExclusiveContext are not allowed to run scripts.
         JS_ASSERT(!cx->perThreadData->activation());
     }
 }
 
 void
@@ -3334,23 +3212,21 @@ class TypeConstraintClearDefiniteGetterS
             (source->nonDataProperty() || source->nonWritableProperty()))
         {
             object->clearAddendum(cx);
         }
     }
 
     void newType(JSContext *cx, TypeSet *source, Type type) {}
 
-    TypeConstraint *sweep(TypeZone &zone) {
+    bool sweep(TypeZone &zone, TypeConstraint **res) {
         if (IsTypeObjectAboutToBeFinalized(&object))
-            return nullptr;
-        TypeConstraint *res = zone.typeLifoAlloc.new_<TypeConstraintClearDefiniteGetterSetter>(object);
-        if (!res)
-            zone.setPendingNukeTypes();
-        return res;
+            return false;
+        *res = zone.typeLifoAlloc.new_<TypeConstraintClearDefiniteGetterSetter>(object);
+        return true;
     }
 };
 
 bool
 types::AddClearDefiniteGetterSetterForPrototypeChain(JSContext *cx, TypeObject *type, HandleId id)
 {
     /*
      * Ensure that if the properties named here could have a getter, setter or
@@ -3360,17 +3236,18 @@ types::AddClearDefiniteGetterSetterForPr
     RootedObject parent(cx, type->proto().toObjectOrNull());
     while (parent) {
         TypeObject *parentObject = parent->getType(cx);
         if (!parentObject || parentObject->unknownProperties())
             return false;
         HeapTypeSet *parentTypes = parentObject->getProperty(cx, id);
         if (!parentTypes || parentTypes->nonDataProperty() || parentTypes->nonWritableProperty())
             return false;
-        parentTypes->add(cx, cx->typeLifoAlloc().new_<TypeConstraintClearDefiniteGetterSetter>(type));
+        if (!parentTypes->addConstraint(cx, cx->typeLifoAlloc().new_<TypeConstraintClearDefiniteGetterSetter>(type)))
+            return false;
         parent = parent->getProto();
     }
     return true;
 }
 
 /*
  * Constraint which clears definite properties on an object should a type set
  * contain any types other than a single object.
@@ -3389,27 +3266,25 @@ class TypeConstraintClearDefiniteSingle 
     void newType(JSContext *cx, TypeSet *source, Type type) {
         if (object->flags() & OBJECT_FLAG_ADDENDUM_CLEARED)
             return;
 
         if (source->baseFlags() || source->getObjectCount() > 1)
             object->clearAddendum(cx);
     }
 
-    TypeConstraint *sweep(TypeZone &zone) {
+    bool sweep(TypeZone &zone, TypeConstraint **res) {
         if (IsTypeObjectAboutToBeFinalized(&object))
-            return nullptr;
-        TypeConstraint *res = zone.typeLifoAlloc.new_<TypeConstraintClearDefiniteSingle>(object);
-        if (!res)
-            zone.setPendingNukeTypes();
-        return res;
+            return false;
+        *res = zone.typeLifoAlloc.new_<TypeConstraintClearDefiniteSingle>(object);
+        return true;
     }
 };
 
-void
+bool
 types::AddClearDefiniteFunctionUsesInScript(JSContext *cx, TypeObject *type,
                                             JSScript *script, JSScript *calleeScript)
 {
     // Look for any uses of the specified calleeScript in type sets for
     // |script|, and add constraints to ensure that if the type sets' contents
     // change then the definite properties are cleared from the type.
     // This ensures that the inlining performed when the definite properties
     // analysis was done is stable.
@@ -3432,20 +3307,22 @@ types::AddClearDefiniteFunctionUsesInScr
                 JSFunction *fun = &singleton->as<JSFunction>();
                 if (!fun->isNative())
                     continue;
                 if (fun->native() != js_fun_call && fun->native() != js_fun_apply)
                     continue;
             }
             // This is a type set that might have been used when inlining
             // |calleeScript| into |script|.
-            types->add(cx,
-                cx->typeLifoAlloc().new_<TypeConstraintClearDefiniteSingle>(type));
+            if (!types->addConstraint(cx, cx->typeLifoAlloc().new_<TypeConstraintClearDefiniteSingle>(type)))
+                return false;
         }
     }
+
+    return true;
 }
 
 /*
  * Either make the newScript information for type when it is constructed
  * by the specified script, or regenerate the constraints for an existing
  * newScript on the type after they were cleared by a GC.
  */
 static void
@@ -3459,22 +3336,18 @@ CheckNewScriptProperties(JSContext *cx, 
 
     /* Strawman object to add properties to and watch for duplicates. */
     RootedObject baseobj(cx, NewBuiltinClassInstance(cx, &JSObject::class_, gc::FINALIZE_OBJECT16));
     if (!baseobj)
         return;
 
     Vector<TypeNewScript::Initializer> initializerList(cx);
 
-    if (!jit::AnalyzeNewScriptProperties(cx, fun, type, baseobj, &initializerList)) {
-        cx->compartment()->types.setPendingNukeTypes(cx);
-        return;
-    }
-
-    if (baseobj->slotSpan() == 0 ||
+    if (!jit::AnalyzeNewScriptProperties(cx, fun, type, baseobj, &initializerList) ||
+        baseobj->slotSpan() == 0 ||
         !!(type->flags() & OBJECT_FLAG_ADDENDUM_CLEARED))
     {
         if (type->hasNewScript())
             type->clearAddendum(cx);
         return;
     }
 
     /*
@@ -3504,42 +3377,39 @@ CheckNewScriptProperties(JSContext *cx, 
      */
     Rooted<TypeObject *> rootedType(cx, type);
     RootedShape shape(cx, baseobj->lastProperty());
     baseobj = NewReshapedObject(cx, rootedType, baseobj->getParent(), kind, shape, MaybeSingletonObject);
     if (!baseobj ||
         !type->addDefiniteProperties(cx, baseobj) ||
         !initializerList.append(done))
     {
-        cx->compartment()->types.setPendingNukeTypes(cx);
         return;
     }
 
     size_t numBytes = sizeof(TypeNewScript)
                     + (initializerList.length() * sizeof(TypeNewScript::Initializer));
     TypeNewScript *newScript;
 #ifdef JSGC_ROOT_ANALYSIS
     // calloc can legitimately return a pointer that appears to be poisoned.
     void *p;
     do {
         p = cx->calloc_(numBytes);
     } while (IsPoisonedPtr(p));
     newScript = (TypeNewScript *) p;
 #else
     newScript = (TypeNewScript *) cx->calloc_(numBytes);
 #endif
+    if (!newScript)
+        return;
+
     new (newScript) TypeNewScript();
 
     type->setAddendum(newScript);
 
-    if (!newScript) {
-        cx->compartment()->types.setPendingNukeTypes(cx);
-        return;
-    }
-
     newScript->fun = fun;
     newScript->templateObject = baseobj;
 
     newScript->initializerList = (TypeNewScript::Initializer *)
         ((char *) newScript + sizeof(TypeNewScript));
     PodCopy(newScript->initializerList,
             initializerList.begin(),
             initializerList.length());
@@ -3679,20 +3549,18 @@ JSScript::makeTypes(JSContext *cx)
         return analyzedArgsUsage() || ensureRanAnalysis(cx);
     }
 
     AutoEnterAnalysis enter(cx);
 
     unsigned count = TypeScript::NumTypeSets(this);
 
     TypeScript *typeScript = (TypeScript *) cx->calloc_(sizeof(TypeScript) + (sizeof(StackTypeSet) * count));
-    if (!typeScript) {
-        cx->compartment()->types.setPendingNukeTypes(cx);
+    if (!typeScript)
         return false;
-    }
 
     new(typeScript) TypeScript();
 
     TypeSet *typeArray = typeScript->typeArray();
 
     for (unsigned i = 0; i < count; i++)
         new (&typeArray[i]) StackTypeSet();
 
@@ -3831,16 +3699,17 @@ JSObject::splicePrototype(JSContext *cx,
     return true;
 }
 
 /* static */ TypeObject *
 JSObject::makeLazyType(JSContext *cx, HandleObject obj)
 {
     JS_ASSERT(obj->hasLazyType());
     JS_ASSERT(cx->compartment() == obj->compartment());
+    JS_ASSERT(cx->typeInferenceEnabled());
 
     /* De-lazification of functions can GC, so we need to do it up here. */
     if (obj->is<JSFunction>() && obj->as<JSFunction>().isInterpretedLazy()) {
         RootedFunction fun(cx, &obj->as<JSFunction>());
         if (!fun->getOrCreateScript(cx))
             return nullptr;
     }
 
@@ -3854,27 +3723,18 @@ JSObject::makeLazyType(JSContext *cx, Ha
     if (obj->isIndexed())
         initialFlags |= OBJECT_FLAG_SPARSE_INDEXES;
 
     if (obj->is<ArrayObject>() && obj->as<ArrayObject>().length() > INT32_MAX)
         initialFlags |= OBJECT_FLAG_LENGTH_OVERFLOW;
 
     Rooted<TaggedProto> proto(cx, obj->getTaggedProto());
     TypeObject *type = cx->compartment()->types.newTypeObject(cx, obj->getClass(), proto, initialFlags);
-    if (!type) {
-        if (cx->typeInferenceEnabled())
-            cx->compartment()->types.setPendingNukeTypes(cx);
+    if (!type)
         return nullptr;
-    }
-
-    if (!cx->typeInferenceEnabled()) {
-        /* This can only happen if types were previously nuked. */
-        obj->type_ = type;
-        return type;
-    }
 
     AutoEnterAnalysis enter(cx);
 
     /* Fill in the type according to the state of this object. */
 
     type->initSingleton(obj);
 
     if (obj->is<JSFunction>() && obj->as<JSFunction>().isInterpreted())
@@ -4043,32 +3903,32 @@ ExclusiveContext::getNewType(const Class
         /*
          * Some builtin objects have slotful native properties baked in at
          * creation via the Shape::{insert,get}initialShape mechanism. Since
          * these properties are never explicitly defined on new objects, update
          * the type information for them here.
          */
 
         if (obj->is<RegExpObject>()) {
-            AddTypeProperty(this, type, "source", types::Type::StringType());
-            AddTypeProperty(this, type, "global", types::Type::BooleanType());
-            AddTypeProperty(this, type, "ignoreCase", types::Type::BooleanType());
-            AddTypeProperty(this, type, "multiline", types::Type::BooleanType());
-            AddTypeProperty(this, type, "sticky", types::Type::BooleanType());
-            AddTypeProperty(this, type, "lastIndex", types::Type::Int32Type());
+            AddTypePropertyId(this, type, NameToId(names().source), Type::StringType());
+            AddTypePropertyId(this, type, NameToId(names().global), Type::BooleanType());
+            AddTypePropertyId(this, type, NameToId(names().ignoreCase), Type::BooleanType());
+            AddTypePropertyId(this, type, NameToId(names().multiline), Type::BooleanType());
+            AddTypePropertyId(this, type, NameToId(names().sticky), Type::BooleanType());
+            AddTypePropertyId(this, type, NameToId(names().lastIndex), Type::Int32Type());
         }
 
         if (obj->is<StringObject>())
-            AddTypeProperty(this, type, "length", Type::Int32Type());
+            AddTypePropertyId(this, type, NameToId(names().length), Type::Int32Type());
 
         if (obj->is<ErrorObject>()) {
-            AddTypeProperty(this, type, "fileName", types::Type::StringType());
-            AddTypeProperty(this, type, "lineNumber", types::Type::Int32Type());
-            AddTypeProperty(this, type, "columnNumber", types::Type::Int32Type());
-            AddTypeProperty(this, type, "stack", types::Type::StringType());
+            AddTypePropertyId(this, type, NameToId(names().fileName), Type::StringType());
+            AddTypePropertyId(this, type, NameToId(names().lineNumber), Type::Int32Type());
+            AddTypePropertyId(this, type, NameToId(names().columnNumber), Type::Int32Type());
+            AddTypePropertyId(this, type, NameToId(names().stack), Type::StringType());
         }
     }
 
     return type;
 }
 
 #if defined(JSGC_GENERATIONAL) && defined(JS_GC_ZEAL)
 void
@@ -4147,20 +4007,19 @@ ConstraintTypeSet::sweep(Zone *zone)
         clearObjects();
         objectCount = 0;
         for (unsigned i = 0; i < oldCapacity; i++) {
             TypeObjectKey *object = oldArray[i];
             if (object && !IsAboutToBeFinalized(object)) {
                 TypeObjectKey **pentry =
                     HashSetInsert<TypeObjectKey *,TypeObjectKey,TypeObjectKey>
                         (zone->types.typeLifoAlloc, objectSet, objectCount, object);
-                if (pentry)
-                    *pentry = object;
-                else
-                    zone->types.setPendingNukeTypes();
+                if (!pentry)
+                    CrashAtUnhandlableOOM("OOM in ConstraintTypeSet::sweep");
+                *pentry = object;
             }
         }
         setBaseObjectCount(objectCount);
     } else if (objectCount == 1) {
         TypeObjectKey *object = (TypeObjectKey *) objectSet;
         if (IsAboutToBeFinalized(object)) {
             objectSet = nullptr;
             setBaseObjectCount(0);
@@ -4169,17 +4028,20 @@ ConstraintTypeSet::sweep(Zone *zone)
 
     /*
      * Type constraints only hold weak references. Copy constraints referring
      * to data that is still live into the zone's new arena.
      */
     TypeConstraint *constraint = constraintList;
     constraintList = nullptr;
     while (constraint) {
-        if (TypeConstraint *copy = constraint->sweep(zone->types)) {
+        TypeConstraint *copy;
+        if (constraint->sweep(zone->types, &copy)) {
+            if (!copy)
+                CrashAtUnhandlableOOM("OOM in ConstraintTypeSet::sweep");
             copy->next = constraintList;
             constraintList = copy;
         }
         constraint = constraint->next;
     }
 }
 
 inline void
@@ -4225,46 +4087,44 @@ TypeObject::sweep(FreeOp *fop)
                     /*
                      * Don't copy over properties of singleton objects when their
                      * presence will not be required by jitcode or type constraints
                      * (i.e. for the definite properties analysis). The contents of
                      * these type sets will be regenerated as necessary.
                      */
                     continue;
                 }
+
                 Property *newProp = typeLifoAlloc.new_<Property>(*prop);
-                if (newProp) {
-                    Property **pentry =
-                        HashSetInsert<jsid,Property,Property>
-                            (typeLifoAlloc, propertySet, propertyCount, prop->id);
-                    if (pentry) {
-                        *pentry = newProp;
-                        newProp->types.sweep(zone());
-                    } else {
-                        zone()->types.setPendingNukeTypes();
-                    }
-                } else {
-                    zone()->types.setPendingNukeTypes();
-                }
+                if (!newProp)
+                    CrashAtUnhandlableOOM("OOM in TypeObject::sweep");
+
+                Property **pentry =
+                    HashSetInsert<jsid,Property,Property>
+                        (typeLifoAlloc, propertySet, propertyCount, prop->id);
+                if (!pentry)
+                    CrashAtUnhandlableOOM("OOM in TypeObject::sweep");
+
+                *pentry = newProp;
+                newProp->types.sweep(zone());
             }
         }
         setBasePropertyCount(propertyCount);
     } else if (propertyCount == 1) {
         Property *prop = (Property *) propertySet;
         if (singleton() && !prop->types.constraintList && !zone()->isPreservingCode()) {
             // Skip, as above.
             clearProperties();
         } else {
             Property *newProp = typeLifoAlloc.new_<Property>(*prop);
-            if (newProp) {
-                propertySet = (Property **) newProp;
-                newProp->types.sweep(zone());
-            } else {
-                zone()->types.setPendingNukeTypes();
-            }
+            if (!newProp)
+                CrashAtUnhandlableOOM("OOM in TypeObject::sweep");
+
+            propertySet = (Property **) newProp;
+            newProp->types.sweep(zone());
         }
     }
 
     if (basePropertyCount() <= SET_ARRAY_SIZE) {
         for (unsigned i = 0; i < basePropertyCount(); i++)
             JS_ASSERT(propertySet[i]);
     }
 }
@@ -4444,17 +4304,16 @@ TypeObject::sizeOfExcludingThis(mozilla:
     return mallocSizeOf(addendum);
 }
 
 TypeZone::TypeZone(Zone *zone)
   : zone_(zone),
     typeLifoAlloc(TYPE_LIFO_ALLOC_PRIMARY_CHUNK_SIZE),
     compilerOutputs(nullptr),
     pendingRecompiles(nullptr),
-    pendingNukeTypes(false),
     inferenceEnabled(false)
 {
 }
 
 TypeZone::~TypeZone()
 {
     js_delete(compilerOutputs);
     js_delete(pendingRecompiles);
--- a/js/src/jsinfer.h
+++ b/js/src/jsinfer.h
@@ -237,16 +237,20 @@ class Type
 
     /* Accessors for types that are either JSObject or TypeObject. */
 
     bool isObject() const {
         JS_ASSERT(!isAnyObject() && !isUnknown());
         return data > JSVAL_TYPE_UNKNOWN;
     }
 
+    bool isObjectUnchecked() const {
+        return data > JSVAL_TYPE_UNKNOWN;
+    }
+
     inline TypeObjectKey *objectKey() const;
 
     /* Accessors for JSObject types */
 
     bool isSingleObject() const {
         return isObject() && !!(data & 1);
     }
 
@@ -330,17 +334,17 @@ public:
      * state.
      */
     virtual void newObjectState(JSContext *cx, TypeObject *object) {}
 
     /*
      * If the data this constraint refers to is still live, copy it into the
      * zone's new allocator. Type constraints only hold weak references.
      */
-    virtual TypeConstraint *sweep(TypeZone &zone) = 0;
+    virtual bool sweep(TypeZone &zone, TypeConstraint **res) = 0;
 };
 
 /* Flags and other state stored in TypeSet::flags */
 enum MOZ_ENUM_TYPE(uint32_t) {
     TYPE_FLAG_UNDEFINED =  0x1,
     TYPE_FLAG_NULL      =  0x2,
     TYPE_FLAG_BOOLEAN   =  0x4,
     TYPE_FLAG_INT32     =  0x8,
@@ -523,32 +527,31 @@ class TypeSet
         JS_ASSERT(definiteProperty());
         return (flags >> TYPE_FLAG_DEFINITE_SHIFT) - 1;
     }
 
     /* Join two type sets into a new set. The result should not be modified further. */
     static TemporaryTypeSet *unionSets(TypeSet *a, TypeSet *b, LifoAlloc *alloc);
 
     /* Add a type to this set using the specified allocator. */
-    inline bool addType(Type type, LifoAlloc *alloc);
+    inline void addType(Type type, LifoAlloc *alloc);
 
     /* Get a list of all types in this set. */
     typedef Vector<Type, 1, SystemAllocPolicy> TypeList;
     bool enumerateTypes(TypeList *list);
 
     /*
      * Iterate through the objects in this set. getObjectCount overapproximates
      * in the hash case (see SET_ARRAY_SIZE in jsinferinlines.h), and getObject
      * may return nullptr.
      */
     inline unsigned getObjectCount() const;
     inline TypeObjectKey *getObject(unsigned i) const;
     inline JSObject *getSingleObject(unsigned i) const;
     inline TypeObject *getTypeObject(unsigned i) const;
-    inline bool getTypeOrSingleObject(JSContext *cx, unsigned i, TypeObject **obj) const;
 
     /* The Class of an object in this set. */
     inline const Class *getObjectClass(unsigned i) const;
 
     bool canSetDefinite(unsigned slot) {
         // Note: the cast is required to work around an MSVC issue.
         return (slot + 1) <= (unsigned(TYPE_FLAG_DEFINITE_MASK) >> TYPE_FLAG_DEFINITE_SHIFT);
     }
@@ -563,17 +566,17 @@ class TypeSet
 
     /*
      * Get whether this type set is known to be a subset of other.
      * This variant doesn't freeze constraints. That variant is called knownSubset
      */
     bool isSubset(TypeSet *other);
 
     /* Forward all types in this set to the specified constraint. */
-    void addTypesToConstraint(JSContext *cx, TypeConstraint *constraint);
+    bool addTypesToConstraint(JSContext *cx, TypeConstraint *constraint);
 
     // Clone a type set into an arbitrary allocator.
     TemporaryTypeSet *clone(LifoAlloc *alloc) const;
     bool clone(LifoAlloc *alloc, TemporaryTypeSet *result) const;
 
   protected:
     uint32_t baseObjectCount() const {
         return (flags & TYPE_FLAG_OBJECT_COUNT_MASK) >> TYPE_FLAG_OBJECT_COUNT_SHIFT;
@@ -594,17 +597,17 @@ class ConstraintTypeSet : public TypeSet
 
     /*
      * Add a type to this set, calling any constraint handlers if this is a new
      * possible type.
      */
     inline void addType(ExclusiveContext *cx, Type type);
 
     /* Add a new constraint to this set. */
-    void add(JSContext *cx, TypeConstraint *constraint, bool callExisting = true);
+    bool addConstraint(JSContext *cx, TypeConstraint *constraint, bool callExisting = true);
 
     inline void sweep(JS::Zone *zone);
 };
 
 class StackTypeSet : public ConstraintTypeSet
 {
   public:
 };
@@ -734,17 +737,17 @@ class TemporaryTypeSet : public TypeSet
      * objects in this type set.
      */
     DoubleConversion convertDoubleElements(CompilerConstraintList *constraints);
 };
 
 bool
 AddClearDefiniteGetterSetterForPrototypeChain(JSContext *cx, TypeObject *type, HandleId id);
 
-void
+bool
 AddClearDefiniteFunctionUsesInScript(JSContext *cx, TypeObject *type,
                                      JSScript *script, JSScript *calleeScript);
 
 /* Is this a reasonable PC to be doing inlining on? */
 inline bool isInlinableCall(jsbytecode *pc);
 
 /* Type information about a property. */
 struct Property
@@ -1103,18 +1106,16 @@ struct TypeObject : gc::BarrieredCell<Ty
     /* Helpers */
 
     bool addProperty(ExclusiveContext *cx, jsid id, Property **pprop);
     bool addDefiniteProperties(ExclusiveContext *cx, JSObject *obj);
     bool matchDefiniteProperties(HandleObject obj);
     void addPrototype(JSContext *cx, TypeObject *proto);
     void addPropertyType(ExclusiveContext *cx, jsid id, Type type);
     void addPropertyType(ExclusiveContext *cx, jsid id, const Value &value);
-    void addPropertyType(ExclusiveContext *cx, const char *name, Type type);
-    void addPropertyType(ExclusiveContext *cx, const char *name, const Value &value);
     void markPropertyNonData(ExclusiveContext *cx, jsid id);
     void markPropertyNonWritable(ExclusiveContext *cx, jsid id);
     void markStateChange(ExclusiveContext *cx);
     void setFlags(ExclusiveContext *cx, TypeObjectFlags flags);
     void markUnknown(ExclusiveContext *cx);
     void clearAddendum(ExclusiveContext *cx);
     void clearNewScriptAddendum(ExclusiveContext *cx);
     void clearTypedObjectAddendum(ExclusiveContext *cx);
@@ -1522,19 +1523,16 @@ struct TypeCompartment
      * js_ObjectClass).
      */
     TypeObject *newTypeObject(ExclusiveContext *cx, const Class *clasp, Handle<TaggedProto> proto,
                               TypeObjectFlags initialFlags = 0);
 
     /* Get or make an object for an allocation site, and add to the allocation site table. */
     TypeObject *addAllocationSiteTypeObject(JSContext *cx, AllocationSiteKey key);
 
-    /* Mark all types as needing destruction once inference has 'finished'. */
-    void setPendingNukeTypes(ExclusiveContext *cx);
-
     /* Mark any type set containing obj as having a generic object type. */
     void markSetsUnknown(JSContext *cx, TypeObject *obj);
 
     void sweep(FreeOp *fop);
     void finalizeObjects();
 
     void addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf,
                                 size_t *allocationSiteTables,
@@ -1557,43 +1555,32 @@ struct TypeZone
      * RecompileInfo. This includes both valid and invalid compilations, though
      * invalidated compilations are swept on GC.
      */
     Vector<CompilerOutput> *compilerOutputs;
 
     /* Pending recompilations to perform before execution of JIT code can resume. */
     Vector<RecompileInfo> *pendingRecompiles;
 
-    /*
-     * Bit set if all current types must be marked as unknown, and all scripts
-     * recompiled. Caused by OOM failure within inference operations.
-     */
-    bool                         pendingNukeTypes;
-
     /* Whether type inference is enabled in this compartment. */
     bool                         inferenceEnabled;
 
     TypeZone(JS::Zone *zone);
     ~TypeZone();
     void init(JSContext *cx);
 
     JS::Zone *zone() const { return zone_; }
 
     void sweep(FreeOp *fop, bool releaseTypes);
 
-    /* Mark all types as needing destruction once inference has 'finished'. */
-    void setPendingNukeTypes();
-
     /* Mark a script as needing recompilation once inference has finished. */
     void addPendingRecompile(JSContext *cx, const RecompileInfo &info);
     void addPendingRecompile(JSContext *cx, JSScript *script);
 
     void processPendingRecompiles(FreeOp *fop);
-
-    void nukeTypes(FreeOp *fop);
 };
 
 enum SpewChannel {
     ISpewOps,      /* ops: New constraints and types. */
     ISpewResult,   /* result: Final type sets. */
     SPEW_COUNT
 };
 
--- a/js/src/jsinferinlines.h
+++ b/js/src/jsinferinlines.h
@@ -242,19 +242,17 @@ struct AutoEnterAnalysis
 
         /*
          * If there are no more type inference activations on the stack,
          * process any triggered recompilations. Note that we should not be
          * invoking any scripted code while type inference is running.
          */
         if (!compartment->activeAnalysis) {
             TypeZone &types = compartment->zone()->types;
-            if (types.pendingNukeTypes)
-                types.nukeTypes(freeOp);
-            else if (types.pendingRecompiles)
+            if (types.pendingRecompiles)
                 types.processPendingRecompiles(freeOp);
         }
     }
 
   private:
     void init(FreeOp *fop, JSCompartment *comp) {
         freeOp = fop;
         compartment = comp;
@@ -380,22 +378,21 @@ EnsureTrackPropertyTypes(JSContext *cx, 
     if (!cx->typeInferenceEnabled())
         return;
 
     id = IdToTypeId(id);
 
     if (obj->hasSingletonType()) {
         AutoEnterAnalysis enter(cx);
         if (obj->hasLazyType() && !obj->getType(cx)) {
-            cx->compartment()->types.setPendingNukeTypes(cx);
-            cx->clearPendingException();
+            CrashAtUnhandlableOOM("Could not allocate TypeObject in EnsureTrackPropertyTypes");
             return;
         }
         if (!obj->type()->unknownProperties() && !obj->type()->getProperty(cx, id)) {
-            cx->compartment()->types.setPendingNukeTypes(cx);
+            obj->type()->markUnknown(cx);
             return;
         }
     }
 
     JS_ASSERT(obj->type()->unknownProperties() || TrackPropertyTypes(cx, obj, id));
 }
 
 inline bool
@@ -445,27 +442,27 @@ AddTypePropertyId(ExclusiveContext *cx, 
     if (cx->typeInferenceEnabled()) {
         id = IdToTypeId(id);
         if (TrackPropertyTypes(cx, obj, id))
             obj->type()->addPropertyType(cx, id, value);
     }
 }
 
 inline void
-AddTypeProperty(ExclusiveContext *cx, TypeObject *obj, const char *name, Type type)
+AddTypePropertyId(ExclusiveContext *cx, TypeObject *obj, jsid id, Type type)
 {
     if (cx->typeInferenceEnabled() && !obj->unknownProperties())
-        obj->addPropertyType(cx, name, type);
+        obj->addPropertyType(cx, id, type);
 }
 
 inline void
-AddTypeProperty(ExclusiveContext *cx, TypeObject *obj, const char *name, const Value &value)
+AddTypePropertyId(ExclusiveContext *cx, TypeObject *obj, jsid id, const Value &value)
 {
     if (cx->typeInferenceEnabled() && !obj->unknownProperties())
-        obj->addPropertyType(cx, name, value);
+        obj->addPropertyType(cx, id, value);
 }
 
 /* Set one or more dynamic flags on a type object. */
 inline void
 MarkTypeObjectFlags(ExclusiveContext *cx, JSObject *obj, TypeObjectFlags flags)
 {
     if (cx->typeInferenceEnabled() && !obj->hasLazyType() && !obj->type()->hasAllFlags(flags))
         obj->type()->setFlags(cx, flags);
@@ -1050,56 +1047,56 @@ TypeSet::setBaseObjectCount(uint32_t cou
 
 inline void
 TypeSet::clearObjects()
 {
     setBaseObjectCount(0);
     objectSet = nullptr;
 }
 
-bool
+void
 TypeSet::addType(Type type, LifoAlloc *alloc)
 {
     if (unknown())
-        return true;
+        return;
 
     if (type.isUnknown()) {
         flags |= TYPE_FLAG_BASE_MASK;
         clearObjects();
         JS_ASSERT(unknown());
-        return true;
+        return;
     }
 
     if (type.isPrimitive()) {
         TypeFlags flag = PrimitiveTypeFlag(type.primitive());
         if (flags & flag)
-            return true;
+            return;
 
         /* If we add float to a type set it is also considered to contain int. */
         if (flag == TYPE_FLAG_DOUBLE)
             flag |= TYPE_FLAG_INT32;
 
         flags |= flag;
-        return true;
+        return;
     }
 
     if (flags & TYPE_FLAG_ANYOBJECT)
-        return true;
+        return;
     if (type.isAnyObject())
         goto unknownObject;
 
     {
         uint32_t objectCount = baseObjectCount();
         TypeObjectKey *object = type.objectKey();
         TypeObjectKey **pentry = HashSetInsert<TypeObjectKey *,TypeObjectKey,TypeObjectKey>
                                      (*alloc, objectSet, objectCount, object);
         if (!pentry)
-            return false;
+            goto unknownObject;
         if (*pentry)
-            return true;
+            return;
         *pentry = object;
 
         setBaseObjectCount(objectCount);
 
         if (objectCount == TYPE_FLAG_OBJECT_COUNT_LIMIT)
             goto unknownObject;
     }
 
@@ -1111,32 +1108,30 @@ TypeSet::addType(Type type, LifoAlloc *a
     }
 
     if (false) {
     unknownObject:
         type = Type::AnyObjectType();
         flags |= TYPE_FLAG_ANYOBJECT;
         clearObjects();
     }
-
-    return true;
 }
 
 inline void
 ConstraintTypeSet::addType(ExclusiveContext *cxArg, Type type)
 {
     JS_ASSERT(cxArg->compartment()->activeAnalysis);
 
     if (hasType(type))
         return;
 
-    if (!TypeSet::addType(type, &cxArg->typeLifoAlloc())) {
-        cxArg->compartment()->types.setPendingNukeTypes(cxArg);
-        return;
-    }
+    TypeSet::addType(type, &cxArg->typeLifoAlloc());
+
+    if (type.isObjectUnchecked() && unknownObject())
+        type = Type::AnyObjectType();
 
     InferSpew(ISpewOps, "addType: %sT%p%s %s",
               InferSpewColor(this), this, InferSpewColorReset(),
               TypeString(type));
 
     /* Propagate the type to all constraints. */
     if (JSContext *cx = cxArg->maybeJSContext()) {
         TypeConstraint *constraint = constraintList;
@@ -1214,40 +1209,16 @@ TypeSet::getSingleObject(unsigned i) con
 
 inline TypeObject *
 TypeSet::getTypeObject(unsigned i) const
 {
     TypeObjectKey *key = getObject(i);
     return (key && key->isTypeObject()) ? key->asTypeObject() : nullptr;
 }
 
-inline bool
-TypeSet::getTypeOrSingleObject(JSContext *cx, unsigned i, TypeObject **result) const
-{
-    JS_ASSERT(result);
-    JS_ASSERT(cx->compartment()->activeAnalysis);
-
-    *result = nullptr;
-
-    TypeObject *type = getTypeObject(i);
-    if (!type) {
-        JSObject *singleton = getSingleObject(i);
-        if (!singleton)
-            return true;
-
-        type = singleton->uninlinedGetType(cx);
-        if (!type) {
-            cx->compartment()->types.setPendingNukeTypes(cx);
-            return false;
-        }
-    }
-    *result = type;
-    return true;
-}
-
 inline const Class *
 TypeSet::getObjectClass(unsigned i) const
 {
     if (JSObject *object = getSingleObject(i))
         return object->getClass();
     if (TypeObject *object = getTypeObject(i))
         return object->clasp();
     return nullptr;
@@ -1297,26 +1268,25 @@ TypeObject::getProperty(ExclusiveContext
 
     if (HeapTypeSet *types = maybeGetProperty(id))
         return types;
 
     uint32_t propertyCount = basePropertyCount();
     Property **pprop = HashSetInsert<jsid,Property,Property>
         (cx->typeLifoAlloc(), propertySet, propertyCount, id);
     if (!pprop) {
-        cx->compartment()->types.setPendingNukeTypes(cx);
+        markUnknown(cx);
         return nullptr;
     }
 
     JS_ASSERT(!*pprop);
 
     setBasePropertyCount(propertyCount);
     if (!addProperty(cx, id, pprop)) {
-        setBasePropertyCount(0);
-        propertySet = nullptr;
+        markUnknown(cx);
         return nullptr;
     }
 
     if (propertyCount == OBJECT_FLAG_PROPERTY_COUNT_LIMIT) {
         markUnknown(cx);
 
         /*
          * Return an arbitrary property in the object, as all have unknown
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -3204,17 +3204,17 @@ SplitHelper(JSContext *cx, Handle<JSLine
                 if (!matches[i + 1].isUndefined()) {
                     JSSubString parsub;
                     res->getParen(i + 1, &parsub);
                     sub = js_NewStringCopyN<CanGC>(cx, parsub.chars, parsub.length);
                     if (!sub || !splits.append(StringValue(sub)))
                         return nullptr;
                 } else {
                     /* Only string entries have been accounted for so far. */
-                    AddTypeProperty(cx, type, nullptr, UndefinedValue());
+                    AddTypePropertyId(cx, type, JSID_VOID, UndefinedValue());
                     if (!splits.append(UndefinedValue()))
                         return nullptr;
                 }
 
                 /* Step 13(c)(iii)(7)(d). */
                 if (splits.length() == limit)
                     return NewDenseCopiedArray(cx, splits.length(), splits.begin());
             }
@@ -3339,17 +3339,17 @@ js::str_split(JSContext *cx, unsigned ar
     /* Steps 1-2. */
     RootedString str(cx, ThisToStringForStringProto(cx, args));
     if (!str)
         return false;
 
     RootedTypeObject type(cx, GetTypeCallerInitObject(cx, JSProto_Array));
     if (!type)
         return false;
-    AddTypeProperty(cx, type, nullptr, Type::StringType());
+    AddTypePropertyId(cx, type, JSID_VOID, Type::StringType());
 
     /* Step 5: Use the second argument as the split limit, if given. */
     uint32_t limit;
     if (args.hasDefined(1)) {
         double d;
         if (!ToNumber(cx, args[1], &d))
             return false;
         limit = ToUint32(d);
--- a/js/xpconnect/src/XPCJSContextStack.cpp
+++ b/js/xpconnect/src/XPCJSContextStack.cpp
@@ -171,19 +171,16 @@ XPCJSContextStack::InitSafeJSContext()
     if (!rt)
         MOZ_CRASH();
 
     mSafeJSContext = JS_NewContext(rt, 8192);
     if (!mSafeJSContext)
         MOZ_CRASH();
     JSAutoRequest req(mSafeJSContext);
     ContextOptionsRef(mSafeJSContext).setNoDefaultCompartmentObject(true);
-#ifdef DEBUG
-    ContextOptionsRef(mSafeJSContext).setExtraWarnings(true);
-#endif
 
     JS_SetErrorReporter(mSafeJSContext, xpc::SystemErrorReporter);
 
     JS::CompartmentOptions options;
     options.setZone(JS::SystemZone);
     mSafeJSContextGlobal = CreateGlobalObject(mSafeJSContext,
                                               &SafeJSContextGlobalClass,
                                               principal, options);
rename from media/webrtc/signaling/src/media-conduit/MediaEngineWrapper.h
rename to media/webrtc/signaling/src/common/MediaEngineWrapper.h
--- a/media/webrtc/signaling/src/common/Wrapper.h
+++ b/media/webrtc/signaling/src/common/Wrapper.h
@@ -31,19 +31,17 @@
  *
  * Future enhancements:
  * - For now, objects remain in the map forever.  Better would be to add a releaseHandle() function which would
  *   allow the map to be emptied as underlying handles expired.  While we can't force the client to give up its
  *   shared_ptr<Foo> objects, we can remove our own copy, for instance on a call ended event.
  */
 
 #include <map>
-#include "SharedPtr.h"
 #include "prlock.h"
-#include "base/lock.h"
 #include "mozilla/Assertions.h"
 
 /*
  * Wrapper has its own autolock class because the instances are declared
  * statically and mozilla::Mutex will not work properly when instantiated
  * in a static constructor.
  */
 
--- a/media/webrtc/signaling/src/media-conduit/AudioConduit.cpp
+++ b/media/webrtc/signaling/src/media-conduit/AudioConduit.cpp
@@ -69,64 +69,43 @@ WebrtcAudioConduit::~WebrtcAudioConduit(
 #endif
 
   CSFLogDebug(logTag,  "%s ", __FUNCTION__);
   for(std::vector<AudioCodecConfig*>::size_type i=0;i < mRecvCodecList.size();i++)
   {
     delete mRecvCodecList[i];
   }
   delete mCurSendCodecConfig;
-  if (mPtrVoERTP_RTCP) {
-    mPtrVoERTP_RTCP->Release();
-  }
 
   // The first one of a pair to be deleted shuts down media for both
   if(mPtrVoEXmedia)
   {
     if (!mShutDown) {
       mPtrVoEXmedia->SetExternalRecordingStatus(false);
       mPtrVoEXmedia->SetExternalPlayoutStatus(false);
     }
-    mPtrVoEXmedia->Release();
-  }
-
-  if(mPtrVoEProcessing)
-  {
-    mPtrVoEProcessing->Release();
   }
 
   //Deal with the transport
   if(mPtrVoENetwork)
   {
     if (!mShutDown) {
       mPtrVoENetwork->DeRegisterExternalTransport(mChannel);
     }
-    mPtrVoENetwork->Release();
-  }
-
-  if(mPtrVoECodec)
-  {
-    mPtrVoECodec->Release();
   }
 
   if(mPtrVoEBase)
   {
     if (!mShutDown) {
       mPtrVoEBase->StopPlayout(mChannel);
       mPtrVoEBase->StopSend(mChannel);
       mPtrVoEBase->StopReceive(mChannel);
       mPtrVoEBase->DeleteChannel(mChannel);
       mPtrVoEBase->Terminate();
     }
-    mPtrVoEBase->Release();
-  }
-
-  if (mPtrRTP)
-  {
-    mPtrRTP->Release();
   }
 
   if (mOtherDirection)
   {
     // mOtherDirection owns these now!
     mOtherDirection->mOtherDirection = nullptr;
     // let other side we terminated the channel
     mOtherDirection->mShutDown = true;
--- a/media/webrtc/signaling/src/media-conduit/AudioConduit.h
+++ b/media/webrtc/signaling/src/media-conduit/AudioConduit.h
@@ -6,16 +6,17 @@
 #ifndef AUDIO_SESSION_H_
 #define AUDIO_SESSION_H_
 
 #include "mozilla/Attributes.h"
 #include "mozilla/TimeStamp.h"
 #include "nsTArray.h"
 
 #include "MediaConduitInterface.h"
+#include "MediaEngineWrapper.h"
 
 // Audio Engine Includes
 #include "webrtc/common_types.h"
 #include "webrtc/voice_engine/include/voe_base.h"
 #include "webrtc/voice_engine/include/voe_volume_control.h"
 #include "webrtc/voice_engine/include/voe_codec.h"
 #include "webrtc/voice_engine/include/voe_file.h"
 #include "webrtc/voice_engine/include/voe_network.h"
@@ -151,17 +152,16 @@ public:
 
 
 
   WebrtcAudioConduit():
                       mOtherDirection(nullptr),
                       mShutDown(false),
                       mVoiceEngine(nullptr),
                       mTransport(nullptr),
-                      mPtrRTP(nullptr),
                       mEngineTransmitting(false),
                       mEngineReceiving(false),
                       mChannel(-1),
                       mCurSendCodecConfig(nullptr),
                       mCaptureDelay(150),
                       mEchoOn(true),
                       mEchoCancel(webrtc::kEcAec)
 #ifdef MOZILLA_INTERNAL_API
@@ -225,24 +225,24 @@ private:
   WebrtcAudioConduit*  mOtherDirection;
   // Other side has shut down our channel and related items already
   bool mShutDown;
 
   // These are shared by both directions.  They're released by the last
   // conduit to die
   webrtc::VoiceEngine* mVoiceEngine;
   mozilla::RefPtr<TransportInterface> mTransport;
-  webrtc::VoENetwork*  mPtrVoENetwork;
-  webrtc::VoEBase*     mPtrVoEBase;
-  webrtc::VoECodec*    mPtrVoECodec;
-  webrtc::VoEExternalMedia* mPtrVoEXmedia;
-  webrtc::VoEAudioProcessing* mPtrVoEProcessing;
-  webrtc::VoEVideoSync* mPtrVoEVideoSync;
-  webrtc::VoERTP_RTCP* mPtrVoERTP_RTCP;
-  webrtc::VoERTP_RTCP* mPtrRTP;
+  ScopedCustomReleasePtr<webrtc::VoENetwork>   mPtrVoENetwork;
+  ScopedCustomReleasePtr<webrtc::VoEBase>      mPtrVoEBase;
+  ScopedCustomReleasePtr<webrtc::VoECodec>     mPtrVoECodec;
+  ScopedCustomReleasePtr<webrtc::VoEExternalMedia> mPtrVoEXmedia;
+  ScopedCustomReleasePtr<webrtc::VoEAudioProcessing> mPtrVoEProcessing;
+  ScopedCustomReleasePtr<webrtc::VoEVideoSync> mPtrVoEVideoSync;
+  ScopedCustomReleasePtr<webrtc::VoERTP_RTCP>  mPtrVoERTP_RTCP;
+  ScopedCustomReleasePtr<webrtc::VoERTP_RTCP>  mPtrRTP;
   //engine states of our interets
   bool mEngineTransmitting; // If true => VoiceEngine Send-subsystem is up
   bool mEngineReceiving;    // If true => VoiceEngine Receive-subsystem is up
                             // and playout is enabled
   // Keep track of each inserted RTP block and the time it was inserted
   // so we can estimate the clock time for a specific TimeStamp coming out
   // (for when we send data to MediaStreamTracks).  Blocks are aged out as needed.
   struct Processing {
--- a/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp
+++ b/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp
@@ -71,59 +71,45 @@ WebrtcVideoConduit::~WebrtcVideoConduit(
   {
     if (!mShutDown) {
       mPtrViECapture->DisconnectCaptureDevice(mCapId);
       mPtrViECapture->ReleaseCaptureDevice(mCapId);
       mPtrExtCapture = nullptr;
       if (mOtherDirection)
         mOtherDirection->mPtrExtCapture = nullptr;
     }
-    mPtrViECapture->Release();
   }
 
   //Deal with External Renderer
   if(mPtrViERender)
   {
     if (!mShutDown) {
       if(mRenderer) {
         mPtrViERender->StopRender(mChannel);
       }
       mPtrViERender->RemoveRenderer(mChannel);
     }
-    mPtrViERender->Release();
   }
 
   //Deal with the transport
   if(mPtrViENetwork)
   {
     if (!mShutDown) {
       mPtrViENetwork->DeregisterSendTransport(mChannel);
     }
-    mPtrViENetwork->Release();
-  }
-
-  if(mPtrViECodec)
-  {
-    mPtrViECodec->Release();
   }
 
   if(mPtrViEBase)
   {
     if (!mShutDown) {
       mPtrViEBase->StopSend(mChannel);
       mPtrViEBase->StopReceive(mChannel);
       SyncTo(nullptr);
       mPtrViEBase->DeleteChannel(mChannel);
     }
-    mPtrViEBase->Release();
-  }
-
-  if (mPtrRTP)
-  {
-    mPtrRTP->Release();
   }
 
   if (mOtherDirection)
   {
     // mOtherDirection owns these now!
     mOtherDirection->mOtherDirection = nullptr;
     // let other side we terminated the channel
     mOtherDirection->mShutDown = true;
--- a/media/webrtc/signaling/src/media-conduit/VideoConduit.h
+++ b/media/webrtc/signaling/src/media-conduit/VideoConduit.h
@@ -3,16 +3,17 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef VIDEO_SESSION_H_
 #define VIDEO_SESSION_H_
 
 #include "mozilla/Attributes.h"
 
 #include "MediaConduitInterface.h"
+#include "MediaEngineWrapper.h"
 
 // Video Engine Includes
 #include "webrtc/common_types.h"
 #include "webrtc/video_engine/include/vie_base.h"
 #include "webrtc/video_engine/include/vie_capture.h"
 #include "webrtc/video_engine/include/vie_codec.h"
 #include "webrtc/video_engine/include/vie_render.h"
 #include "webrtc/video_engine/include/vie_network.h"
@@ -180,23 +181,17 @@ public:
   }
 
   WebrtcVideoConduit():
                       mOtherDirection(nullptr),
                       mShutDown(false),
                       mVideoEngine(nullptr),
                       mTransport(nullptr),
                       mRenderer(nullptr),
-                      mPtrViEBase(nullptr),
-                      mPtrViECapture(nullptr),
-                      mPtrViECodec(nullptr),
-                      mPtrViENetwork(nullptr),
-                      mPtrViERender(nullptr),
                       mPtrExtCapture(nullptr),
-                      mPtrRTP(nullptr),
                       mEngineTransmitting(false),
                       mEngineReceiving(false),
                       mChannel(-1),
                       mCapId(-1),
                       mCurSendCodecConfig(nullptr),
                       mSendingWidth(0),
                       mSendingHeight(0)
   {
@@ -255,23 +250,24 @@ private:
   bool mShutDown;
 
   // A few of these are shared by both directions.  They're released by the last
   // conduit to die.
   webrtc::VideoEngine* mVideoEngine;          // shared
   mozilla::RefPtr<TransportInterface> mTransport;
   mozilla::RefPtr<VideoRenderer> mRenderer;
 
-  webrtc::ViEBase* mPtrViEBase;
-  webrtc::ViECapture* mPtrViECapture;
-  webrtc::ViECodec* mPtrViECodec;
-  webrtc::ViENetwork* mPtrViENetwork;
-  webrtc::ViERender* mPtrViERender;
-  webrtc::ViEExternalCapture*  mPtrExtCapture; // shared
-  webrtc::ViERTP_RTCP* mPtrRTP;
+  ScopedCustomReleasePtr<webrtc::ViEBase> mPtrViEBase;
+  ScopedCustomReleasePtr<webrtc::ViECapture> mPtrViECapture;
+  ScopedCustomReleasePtr<webrtc::ViECodec> mPtrViECodec;
+  ScopedCustomReleasePtr<webrtc::ViENetwork> mPtrViENetwork;
+  ScopedCustomReleasePtr<webrtc::ViERender> mPtrViERender;
+  ScopedCustomReleasePtr<webrtc::ViERTP_RTCP> mPtrRTP;
+
+  webrtc::ViEExternalCapture* mPtrExtCapture; // shared
 
   // Engine state we are concerned with.
   bool mEngineTransmitting; //If true ==> Transmit Sub-system is up and running
   bool mEngineReceiving;    // if true ==> Receive Sus-sysmtem up and running
 
   int mChannel; // Video Channel for this conduit
   int mCapId;   // Capturer for this conduit
   RecvCodecList    mRecvCodecList;
new file mode 100644
--- /dev/null
+++ b/mfbt/ChaosMode.h
@@ -0,0 +1,41 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#ifndef mozilla_ChaosMode_h
+#define mozilla_ChaosMode_h
+
+#include <stdint.h>
+#include <stdlib.h>
+
+namespace mozilla {
+
+/**
+ * When "chaos mode" is activated, code that makes implicitly nondeterministic
+ * choices is encouraged to make random and extreme choices, to test more
+ * code paths and uncover bugs.
+ */
+class ChaosMode
+{
+  public:
+    static bool isActive()
+    {
+      // Flip this to true to activate chaos mode
+      return false;
+    }
+
+    /**
+     * Returns a somewhat (but not uniformly) random uint32_t < aBound.
+     * Not to be used for anything except ChaosMode, since it's not very random.
+     */
+    static uint32_t randomUint32LessThan(uint32_t aBound)
+    {
+      return uint32_t(rand()) % aBound;
+    }
+};
+
+} /* namespace mozilla */
+
+#endif /* mozilla_ChaosMode_h */
--- a/mfbt/RefPtr.h
+++ b/mfbt/RefPtr.h
@@ -9,16 +9,23 @@
 #ifndef mozilla_RefPtr_h
 #define mozilla_RefPtr_h
 
 #include "mozilla/Assertions.h"
 #include "mozilla/Atomics.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/RefCountType.h"
 #include "mozilla/TypeTraits.h"
+#if defined(MOZILLA_INTERNAL_API)
+#include "nsXPCOM.h"
+#endif
+
+#if defined(MOZILLA_INTERNAL_API) && (defined(DEBUG) || defined(FORCE_BUILD_REFCNT_LOGGING))
+#define MOZ_REFCOUNTED_LEAK_CHECKING
+#endif
 
 namespace mozilla {
 
 template<typename T> class RefCounted;
 template<typename T> class RefPtr;
 template<typename T> class TemporaryRef;
 template<typename T> class OutParamRef;
 template<typename T> OutParamRef<T> byRef(RefPtr<T>&);
@@ -48,16 +55,38 @@ template<typename T> OutParamRef<T> byRe
  * should add MOZ_DECLARE_REFCOUNTED_TYPENAME(ClassName) to the public
  * section of your class, where ClassName is the name of your class.
  */
 namespace detail {
 #ifdef DEBUG
 const MozRefCountType DEAD = 0xffffdead;
 #endif
 
+// When building code that gets compiled into Gecko, try to use the
+// trace-refcount leak logging facilities.
+#ifdef MOZ_REFCOUNTED_LEAK_CHECKING
+class RefCountLogger
+{
+  public:
+    static void logAddRef(const void* aPointer, MozRefCountType aRefCount,
+                          const char* aTypeName, uint32_t aInstanceSize)
+    {
+      MOZ_ASSERT(aRefCount != DEAD);
+      NS_LogAddRef(const_cast<void*>(aPointer), aRefCount, aTypeName, aInstanceSize);
+    }
+
+    static void logRelease(const void* aPointer, MozRefCountType aRefCount,
+                           const char* aTypeName)
+    {
+      MOZ_ASSERT(aRefCount != DEAD);
+      NS_LogRelease(const_cast<void*>(aPointer), aRefCount, aTypeName);
+    }
+};
+#endif
+
 // This is used WeakPtr.h as well as this file.
 enum RefCountAtomicity
 {
   AtomicRefCount,
   NonAtomicRefCount
 };
 
 template<typename T, RefCountAtomicity Atomicity>
@@ -71,21 +100,31 @@ class RefCounted
       MOZ_ASSERT(refCnt == detail::DEAD);
     }
 
   public:
     // Compatibility with nsRefPtr.
     void AddRef() const {
       MOZ_ASSERT(int32_t(refCnt) >= 0);
       ++refCnt;
+#ifdef MOZ_REFCOUNTED_LEAK_CHECKING
+      detail::RefCountLogger::logAddRef(static_cast<const T*>(this), refCnt,
+                                        static_cast<const T*>(this)->typeName(),
+                                        static_cast<const T*>(this)->typeSize());
+#endif
     }
 
     void Release() const {
       MOZ_ASSERT(int32_t(refCnt) > 0);
-      if (0 == --refCnt) {
+      --refCnt;
+#ifdef MOZ_REFCOUNTED_LEAK_CHECKING
+      detail::RefCountLogger::logRelease(static_cast<const T*>(this), refCnt,
+                                         static_cast<const T*>(this)->typeName());
+#endif
+      if (0 == refCnt) {
 #ifdef DEBUG
         refCnt = detail::DEAD;
 #endif
         delete static_cast<const T*>(this);
       }
     }
 
     // Compatibility with wtf::RefPtr.
@@ -96,17 +135,17 @@ class RefCounted
       MOZ_ASSERT(refCnt > 0);
       return refCnt == 1;
     }
 
   private:
     mutable typename Conditional<Atomicity == AtomicRefCount, Atomic<MozRefCountType>, MozRefCountType>::Type refCnt;
 };
 
-#if defined(MOZILLA_INTERNAL_API) && (defined(DEBUG) || defined(FORCE_BUILD_REFCNT_LOGGING))
+#ifdef MOZ_REFCOUNTED_LEAK_CHECKING
 #define MOZ_DECLARE_REFCOUNTED_TYPENAME(T) \
   const char* typeName() const { return #T; } \
   size_t typeSize() const { return sizeof(*this); }
 
 #define MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(T) \
   virtual const char* typeName() const { return #T; } \
   virtual size_t typeSize() const { return sizeof(*this); }
 #else
--- a/mfbt/WeakPtr.h
+++ b/mfbt/WeakPtr.h
@@ -59,21 +59,24 @@
  *
  * The API was loosely inspired by Chromium's weak_ptr.h:
  * http://src.chromium.org/svn/trunk/src/base/memory/weak_ptr.h
  */
 
 #ifndef mozilla_WeakPtr_h
 #define mozilla_WeakPtr_h
 
+#include "mozilla/ArrayUtils.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/NullPtr.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/TypeTraits.h"
 
+#include <string.h>
+
 namespace mozilla {
 
 template <typename T, class WeakReference> class WeakPtrBase;
 template <typename T, class WeakReference> class SupportsWeakPtrBase;
 
 namespace detail {
 
 // This can live beyond the lifetime of the class derived from SupportsWeakPtrBase.
@@ -81,16 +84,39 @@ template<class T>
 class WeakReference : public ::mozilla::RefCounted<WeakReference<T> >
 {
   public:
     explicit WeakReference(T* p) : ptr(p) {}
     T* get() const {
       return ptr;
     }
 
+#ifdef MOZ_REFCOUNTED_LEAK_CHECKING
+#ifdef XP_WIN
+#define snprintf _snprintf
+#endif
+    const char* typeName() const {
+      static char nameBuffer[1024];
+      const char* innerType = ptr->typeName();
+      // We could do fancier length checks at runtime, but innerType is
+      // controlled by us so we can ensure that this never causes a buffer
+      // overflow by this assertion.
+      MOZ_ASSERT(strlen(innerType) + sizeof("WeakReference<>") < ArrayLength(nameBuffer),
+                 "Exceedingly large type name");
+      snprintf(nameBuffer, ArrayLength(nameBuffer), "WeakReference<%s>", innerType);
+      // This is usually not OK, but here we are returning a pointer to a static
+      // buffer which will immediately be used by the caller.
+      return nameBuffer;
+    }
+    size_t typeSize() const {
+      return sizeof(*this);
+    }
+#undef snprintf
+#endif
+
   private:
     friend class WeakPtrBase<T, WeakReference<T> >;
     friend class SupportsWeakPtrBase<T, WeakReference<T> >;
     void detach() {
       ptr = nullptr;
     }
     T* ptr;
 };
--- a/mfbt/moz.build
+++ b/mfbt/moz.build
@@ -13,16 +13,17 @@ EXPORTS.mozilla = [
     'AllocPolicy.h',
     'Array.h',
     'ArrayUtils.h',
     'Assertions.h',
     'Atomics.h',
     'Attributes.h',
     'BloomFilter.h',
     'Casting.h',
+    'ChaosMode.h',
     'Char16.h',
     'CheckedInt.h',
     'Compiler.h',
     'Compression.h',
     'Constants.h',
     'DebugOnly.h',
     'decimal/Decimal.h',
     'Endian.h',
--- a/netwerk/base/src/nsSocketTransportService2.cpp
+++ b/netwerk/base/src/nsSocketTransportService2.cpp
@@ -16,16 +16,18 @@
 #include "nsIPrefBranch.h"
 #include "nsServiceManagerUtils.h"
 #include "NetworkActivityMonitor.h"
 #include "nsIObserverService.h"
 #include "mozilla/Services.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Likely.h"
 #include "mozilla/PublicSSL.h"
+#include "mozilla/ChaosMode.h"
+#include "mozilla/PodOperations.h"
 #include "nsThreadUtils.h"
 #include "nsIFile.h"
 
 using namespace mozilla;
 using namespace mozilla::net;
 
 #if defined(PR_LOGGING)
 PRLogModuleInfo *gSocketTransportLog = nullptr;
@@ -222,22 +224,30 @@ nsSocketTransportService::AddToPollList(
     if (mActiveCount == mActiveListSize) {
         SOCKET_LOG(("  Active List size of %d met\n", mActiveCount));
         if (!GrowActiveList()) {
             NS_ERROR("too many active sockets");
             return NS_ERROR_OUT_OF_MEMORY;
         }
     }
     
-    mActiveList[mActiveCount] = *sock;
+    uint32_t newSocketIndex = mActiveCount;
+    if (ChaosMode::isActive()) {
+      newSocketIndex = ChaosMode::randomUint32LessThan(mActiveCount + 1);
+      PodMove(mActiveList + newSocketIndex + 1, mActiveList + newSocketIndex,
+              mActiveCount - newSocketIndex);
+      PodMove(mPollList + newSocketIndex + 2, mPollList + newSocketIndex + 1,
+              mActiveCount - newSocketIndex);
+    }
+    mActiveList[newSocketIndex] = *sock;
     mActiveCount++;
 
-    mPollList[mActiveCount].fd = sock->mFD;
-    mPollList[mActiveCount].in_flags = sock->mHandler->mPollFlags;
-    mPollList[mActiveCount].out_flags = 0;
+    mPollList[newSocketIndex + 1].fd = sock->mFD;
+    mPollList[newSocketIndex + 1].in_flags = sock->mHandler->mPollFlags;
+    mPollList[newSocketIndex + 1].out_flags = 0;
 
     SOCKET_LOG(("  active=%u idle=%u\n", mActiveCount, mIdleCount));
     return NS_OK;
 }
 
 void
 nsSocketTransportService::RemoveFromPollList(SocketContext *sock)
 {
--- a/netwerk/protocol/http/nsHttpConnection.cpp
+++ b/netwerk/protocol/http/nsHttpConnection.cpp
@@ -25,16 +25,17 @@
 #include "nsStringStream.h"
 #include "nsProxyRelease.h"
 #include "nsPreloadedStream.h"
 #include "ASpdySession.h"
 #include "mozilla/Telemetry.h"
 #include "nsISupportsPriority.h"
 #include "nsHttpPipeline.h"
 #include <algorithm>
+#include "mozilla/ChaosMode.h"
 
 #ifdef DEBUG
 // defined by the socket transport service while active
 extern PRThread *gSocketThread;
 #endif
 
 namespace mozilla {
 namespace net {
@@ -1427,16 +1428,21 @@ nsHttpConnection::OnWriteSegment(char *b
     if (count == 0) {
         // some WriteSegments implementations will erroneously call the reader
         // to provide 0 bytes worth of data.  we must protect against this case
         // or else we'd end up closing the socket prematurely.
         NS_ERROR("bad WriteSegments implementation");
         return NS_ERROR_FAILURE; // stop iterating
     }
 
+    if (ChaosMode::isActive() && ChaosMode::randomUint32LessThan(2)) {
+        // read 1...count bytes
+        count = ChaosMode::randomUint32LessThan(count) + 1;
+    }
+
     nsresult rv = mSocketIn->Read(buf, count, countWritten);
     if (NS_FAILED(rv))
         mSocketInCondition = rv;
     else if (*countWritten == 0)
         mSocketInCondition = NS_BASE_STREAM_CLOSED;
     else
         mSocketInCondition = NS_OK; // reset condition
 
--- a/netwerk/protocol/http/nsHttpConnectionMgr.cpp
+++ b/netwerk/protocol/http/nsHttpConnectionMgr.cpp
@@ -25,16 +25,17 @@
 #include "nsISSLSocketControl.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/net/DashboardTypes.h"
 #include "NullHttpTransaction.h"
 #include "nsITransport.h"
 #include "nsISocketTransportService.h"
 #include <algorithm>
 #include "Http2Compression.h"
+#include "mozilla/ChaosMode.h"
 
 // defined by the socket transport service while active
 extern PRThread *gSocketThread;
 
 namespace mozilla {
 namespace net {
 
 //-----------------------------------------------------------------------------
@@ -46,16 +47,26 @@ InsertTransactionSorted(nsTArray<nsHttpT
 {
     // insert into queue with smallest valued number first.  search in reverse
     // order under the assumption that many of the existing transactions will
     // have the same priority (usually 0).
 
     for (int32_t i=pendingQ.Length()-1; i>=0; --i) {
         nsHttpTransaction *t = pendingQ[i];
         if (trans->Priority() >= t->Priority()) {
+            if (ChaosMode::isActive()) {
+                int32_t samePriorityCount;
+                for (samePriorityCount = 0; i - samePriorityCount >= 0; ++samePriorityCount) {
+                    if (pendingQ[i - samePriorityCount]->Priority() != trans->Priority()) {
+                        break;
+                    }
+                }
+                // skip over 0...all of the elements with the same priority.
+                i -= ChaosMode::randomUint32LessThan(samePriorityCount + 1);
+            }
             pendingQ.InsertElementAt(i+1, trans);
             return;
         }
     }
     pendingQ.InsertElementAt(0, trans);
 }
 
 //-----------------------------------------------------------------------------
--- a/testing/profiles/prefs_general.js
+++ b/testing/profiles/prefs_general.js
@@ -56,17 +56,18 @@ user_pref("extensions.enabledScopes", 5)
 // Disable metadata caching for installed add-ons by default
 user_pref("extensions.getAddons.cache.enabled", false);
 // Disable intalling any distribution add-ons
 user_pref("extensions.installDistroAddons", false);
 // XPI extensions are required for test harnesses to load
 user_pref("extensions.defaultProviders.enabled", true);
 
 user_pref("geo.wifi.uri", "http://%(server)s/tests/dom/tests/mochitest/geolocation/network_geolocation.sjs");
-user_pref("geo.wifi.testing", true);
+user_pref("geo.wifi.timeToWaitBeforeSending", 200);
+user_pref("geo.wifi.scan", false);
 user_pref("geo.wifi.logging.enabled", true);
 
 user_pref("camino.warn_when_closing", false); // Camino-only, harmless to others
 
 // Make url-classifier updates so rare that they won't affect tests
 user_pref("urlclassifier.updateinterval", 172800);
 // Point the url-classifier to the local testing server for fast failures
 user_pref("browser.safebrowsing.gethashURL", "http://%(server)s/safebrowsing-dummy/gethash");
--- a/xpcom/glue/pldhash.cpp
+++ b/xpcom/glue/pldhash.cpp
@@ -11,16 +11,17 @@
 #include <string.h>
 #include "pldhash.h"
 #include "mozilla/HashFunctions.h"
 #include "mozilla/MathAlgorithms.h"
 #include "nsDebug.h"     /* for PR_ASSERT */
 #include "nsAlgorithm.h"
 #include "mozilla/Likely.h"
 #include "mozilla/MemoryReporting.h"
+#include "mozilla/ChaosMode.h"
 
 #ifdef PL_DHASHMETER
 # define METER(x)       x
 #else
 # define METER(x)       /* nothing */
 #endif
 
 /*
@@ -635,32 +636,47 @@ PL_DHashTableRawRemove(PLDHashTable *tab
 uint32_t
 PL_DHashTableEnumerate(PLDHashTable *table, PLDHashEnumerator etor, void *arg)
 {
     INCREMENT_RECURSION_LEVEL(table);
 
     char *entryAddr = table->entryStore;
     uint32_t entrySize = table->entrySize;
     uint32_t capacity = PL_DHASH_TABLE_SIZE(table);
-    char *entryLimit = entryAddr + capacity * entrySize;
+    uint32_t tableSize = capacity * entrySize;
+    char *entryLimit = entryAddr + tableSize;
     uint32_t i = 0;
     bool didRemove = false;
-    while (entryAddr < entryLimit) {
+
+    if (ChaosMode::isActive()) {
+        // Start iterating at a random point in the hashtable. It would be
+        // even more chaotic to iterate in fully random order, but that's a lot
+        // more work.
+        entryAddr += ChaosMode::randomUint32LessThan(capacity) * entrySize;
+        if (entryAddr >= entryLimit) {
+            entryAddr -= tableSize;
+        }
+    }
+
+    for (uint32_t e = 0; e < capacity; ++e) {
         PLDHashEntryHdr *entry = (PLDHashEntryHdr *)entryAddr;
         if (ENTRY_IS_LIVE(entry)) {
             PLDHashOperator op = etor(table, entry, i++, arg);
             if (op & PL_DHASH_REMOVE) {
                 METER(table->stats.removeEnums++);
                 PL_DHashTableRawRemove(table, entry);
                 didRemove = true;
             }
             if (op & PL_DHASH_STOP)
                 break;
         }
         entryAddr += entrySize;
+        if (entryAddr >= entryLimit) {
+            entryAddr -= tableSize;
+        }
     }
 
     MOZ_ASSERT(!didRemove || table->recursionLevel == 1);
 
     /*
      * Shrink or compress if a quarter or more of all entries are removed, or
      * if the table is underloaded according to the minimum alpha, and is not
      * minimal-size already.  Do this only if we removed above, so non-removing
--- a/xpcom/threads/TimerThread.cpp
+++ b/xpcom/threads/TimerThread.cpp
@@ -7,29 +7,32 @@
 #include "TimerThread.h"
 
 #include "nsThreadUtils.h"
 #include "pratom.h"
 
 #include "nsIObserverService.h"
 #include "nsIServiceManager.h"
 #include "mozilla/Services.h"
+#include "mozilla/ChaosMode.h"
+#include "mozilla/ArrayUtils.h"
 
 #include <math.h>
 
 using namespace mozilla;
 
 NS_IMPL_ISUPPORTS2(TimerThread, nsIRunnable, nsIObserver)
 
 TimerThread::TimerThread() :
   mInitInProgress(false),
   mInitialized(false),
   mMonitor("TimerThread.mMonitor"),
   mShutdown(false),
   mWaiting(false),
+  mNotified(false),
   mSleeping(false)
 {
 }
 
 TimerThread::~TimerThread()
 {
   mThread = nullptr;
 
@@ -128,18 +131,20 @@ nsresult TimerThread::Shutdown()
 
   nsTArray<nsTimerImpl*> timers;
   {   // lock scope
     MonitorAutoLock lock(mMonitor);
 
     mShutdown = true;
 
     // notify the cond var so that Run() can return
-    if (mWaiting)
+    if (mWaiting) {
+      mNotified = true;
       mMonitor.Notify();
+    }
 
     // Need to copy content of mTimers array to a local array
     // because call to timers' ReleaseCallback() (and release its self)
     // must not be done under the lock. Destructor of a callback
     // might potentially call some code reentering the same lock
     // that leads to unexpected behavior or deadlock.
     // See bug 422472.
     timers.AppendElements(mTimers);
@@ -194,33 +199,40 @@ NS_IMETHODIMP TimerThread::Run()
       low = mid;
     else
       high = mid;
   }
 
   // Half of the amount of microseconds needed to get positive PRIntervalTime.
   // We use this to decide how to round our wait times later
   int32_t halfMicrosecondsIntervalResolution = high >> 1;
+  bool forceRunNextTimer = false;
 
   while (!mShutdown) {
     // Have to use PRIntervalTime here, since PR_WaitCondVar takes it
     PRIntervalTime waitFor;
+    bool forceRunThisTimer = forceRunNextTimer;
+    forceRunNextTimer = false;
 
     if (mSleeping) {
       // Sleep for 0.1 seconds while not firing timers.
-      waitFor = PR_MillisecondsToInterval(100);
+      uint32_t milliseconds = 100;
+      if (ChaosMode::isActive()) {
+        milliseconds = ChaosMode::randomUint32LessThan(200);
+      }
+      waitFor = PR_MillisecondsToInterval(milliseconds);
     } else {
       waitFor = PR_INTERVAL_NO_TIMEOUT;
       TimeStamp now = TimeStamp::Now();
       nsTimerImpl *timer = nullptr;
 
       if (!mTimers.IsEmpty()) {
         timer = mTimers[0];
 
-        if (now >= timer->mTimeout) {
+        if (now >= timer->mTimeout || forceRunThisTimer) {
     next:
           // NB: AddRef before the Release under RemoveTimerInternal to avoid
           // mRefCnt passing through zero, in case all other refs than the one
           // from mTimers have gone away (the last non-mTimers[i]-ref's Release
           // must be racing with us, blocked in gThread->RemoveTimer waiting
           // for TimerThread::mMonitor, under nsTimerImpl::Release.
 
           NS_ADDREF(timer);
@@ -278,18 +290,32 @@ NS_IMETHODIMP TimerThread::Run()
         // Don't wait at all (even for PR_INTERVAL_NO_WAIT) if the next timer
         // is due now or overdue.
         //
         // Note that we can only sleep for integer values of a certain
         // resolution. We use halfMicrosecondsIntervalResolution, calculated
         // before, to do the optimal rounding (i.e., of how to decide what
         // interval is so small we should not wait at all).
         double microseconds = (timeout - now).ToMilliseconds()*1000;
-        if (microseconds < halfMicrosecondsIntervalResolution)
+
+        if (ChaosMode::isActive()) {
+          // The mean value of sFractions must be 1 to ensure that
+          // the average of a long sequence of timeouts converges to the
+          // actual sum of their times.
+          static const float sFractions[] = {
+            0.0f, 0.25f, 0.5f, 0.75f, 1.0f, 1.75f, 2.75f
+          };
+          microseconds *= sFractions[ChaosMode::randomUint32LessThan(ArrayLength(sFractions))];
+          forceRunNextTimer = true;
+        }
+
+        if (microseconds < halfMicrosecondsIntervalResolution) {
+          forceRunNextTimer = false;
           goto next; // round down; execute event now
+        }
         waitFor = PR_MicrosecondsToInterval(static_cast<uint32_t>(microseconds)); // Floor is accurate enough.
         if (waitFor == 0)
           waitFor = 1; // round up, wait the minimum time we can wait
       }
 
 #ifdef DEBUG_TIMERS
       if (PR_LOG_TEST(GetTimerLog(), PR_LOG_DEBUG)) {
         if (waitFor == PR_INTERVAL_NO_TIMEOUT)
@@ -298,35 +324,41 @@ NS_IMETHODIMP TimerThread::Run()
         else
           PR_LOG(GetTimerLog(), PR_LOG_DEBUG,
                  ("waiting for %u\n", PR_IntervalToMilliseconds(waitFor)));
       }
 #endif
     }
 
     mWaiting = true;
+    mNotified = false;
     mMonitor.Wait(waitFor);
+    if (mNotified) {
+      forceRunNextTimer = false;
+    }
     mWaiting = false;
   }
 
   return NS_OK;
 }
 
 nsresult TimerThread::AddTimer(nsTimerImpl *aTimer)
 {
   MonitorAutoLock lock(mMonitor);
 
   // Add the timer to our list.
   int32_t i = AddTimerInternal(aTimer);
   if (i < 0)
     return NS_ERROR_OUT_OF_MEMORY;
 
   // Awaken the timer thread.
-  if (mWaiting && i == 0)
+  if (mWaiting && i == 0) {
+    mNotified = true;
     mMonitor.Notify();
+  }
 
   return NS_OK;
 }
 
 nsresult TimerThread::TimerDelayChanged(nsTimerImpl *aTimer)
 {
   MonitorAutoLock lock(mMonitor);
 
@@ -334,18 +366,20 @@ nsresult TimerThread::TimerDelayChanged(
   // ReleaseTimerInternal.
   RemoveTimerInternal(aTimer);
 
   int32_t i = AddTimerInternal(aTimer);
   if (i < 0)
     return NS_ERROR_OUT_OF_MEMORY;
 
   // Awaken the timer thread.
-  if (mWaiting && i == 0)
+  if (mWaiting && i == 0) {
+    mNotified = true;
     mMonitor.Notify();
+  }
 
   return NS_OK;
 }
 
 nsresult TimerThread::RemoveTimer(nsTimerImpl *aTimer)
 {
   MonitorAutoLock lock(mMonitor);
 
@@ -355,18 +389,20 @@ nsresult TimerThread::RemoveTimer(nsTime
   // aTimer param, specifically when nsTimerImpl::Release loses a race with
   // TimerThread::Run, must wait for the mMonitor auto-lock here, and during the
   // wait Run drops the only remaining ref to aTimer via RemoveTimerInternal.
 
   if (!RemoveTimerInternal(aTimer))
     return NS_ERROR_NOT_AVAILABLE;
 
   // Awaken the timer thread.
-  if (mWaiting)
+  if (mWaiting) {
+    mNotified = true;
     mMonitor.Notify();
+  }
 
   return NS_OK;
 }
 
 // This function must be called from within a lock
 int32_t TimerThread::AddTimerInternal(nsTimerImpl *aTimer)
 {
   if (mShutdown)
--- a/xpcom/threads/TimerThread.h
+++ b/xpcom/threads/TimerThread.h
@@ -66,16 +66,17 @@ private:
   bool    RemoveTimerInternal(nsTimerImpl *aTimer);
   void    ReleaseTimerInternal(nsTimerImpl *aTimer);
 
   nsCOMPtr<nsIThread> mThread;
   Monitor mMonitor;
 
   bool mShutdown;
   bool mWaiting;
+  bool mNotified;
   bool mSleeping;
 
   nsTArray<nsTimerImpl*> mTimers;
 };
 
 struct TimerAdditionComparator {
   TimerAdditionComparator(const mozilla::TimeStamp &aNow,
                           nsTimerImpl *aTimerToInsert) :
--- a/xpcom/threads/nsEventQueue.cpp
+++ b/xpcom/threads/nsEventQueue.cpp
@@ -3,16 +3,18 @@
 /* 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/. */
 
 #include "nsEventQueue.h"
 #include "nsAutoPtr.h"
 #include "prlog.h"
 #include "nsThreadUtils.h"
+#include "prthread.h"
+#include "mozilla/ChaosMode.h"
 
 using namespace mozilla;
 
 #ifdef PR_LOGGING
 static PRLogModuleInfo *
 GetLog()
 {
   static PRLogModuleInfo *sLog;
@@ -80,16 +82,24 @@ nsEventQueue::GetEvent(bool mayWait, nsI
 
 bool
 nsEventQueue::PutEvent(nsIRunnable *runnable)
 {
   // Avoid calling AddRef+Release while holding our monitor.
   nsRefPtr<nsIRunnable> event(runnable);
   bool rv = true;
   {
+    if (ChaosMode::isActive()) {
+      // With probability 0.5, yield so other threads have a chance to
+      // dispatch events to this queue first.
+      if (ChaosMode::randomUint32LessThan(2)) {
+        PR_Sleep(PR_INTERVAL_NO_WAIT);
+      }
+    }
+
     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
 
     if (!mHead) {
       mHead = NewPage();
       if (!mHead) {
         rv = false;
       } else {
         mTail = mHead;
--- a/xpcom/threads/nsThread.cpp
+++ b/xpcom/threads/nsThread.cpp
@@ -21,21 +21,32 @@
 #include "nsAutoPtr.h"
 #include "nsCOMPtr.h"
 #include "pratom.h"
 #include "prlog.h"
 #include "nsIObserverService.h"
 #include "mozilla/HangMonitor.h"
 #include "mozilla/Services.h"
 #include "nsXPCOMPrivate.h"
+#include "mozilla/ChaosMode.h"
+
+#ifdef XP_LINUX
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sched.h>
+#endif
 
 #define HAVE_UALARM _BSD_SOURCE || (_XOPEN_SOURCE >= 500 ||                 \
                       _XOPEN_SOURCE && _XOPEN_SOURCE_EXTENDED) &&           \
                       !(_POSIX_C_SOURCE >= 200809L || _XOPEN_SOURCE >= 700)
 
+#if defined(XP_LINUX) && !defined(ANDROID) && defined(_GNU_SOURCE)
+#define HAVE_SCHED_SETAFFINITY
+#endif
+
 #ifdef MOZ_CANARY
 # include <unistd.h>
 # include <execinfo.h>
 # include <signal.h>
 # include <fcntl.h>
 # include "nsXULAppAPI.h"
 #endif
 
@@ -227,21 +238,60 @@ public:
   }
 private:
   nsRefPtr<nsThread>       mThread;
   nsThreadShutdownContext *mShutdownContext;
 };
 
 //-----------------------------------------------------------------------------
 
+static void
+SetupCurrentThreadForChaosMode()
+{
+  if (!ChaosMode::isActive()) {
+    return;
+  }
+
+#ifdef XP_LINUX
+  // PR_SetThreadPriority doesn't really work since priorities >
+  // PR_PRIORITY_NORMAL can't be set by non-root users. Instead we'll just use
+  // setpriority(2) to set random 'nice values'. In regular Linux this is only
+  // a dynamic adjustment so it still doesn't really do what we want, but tools
+  // like 'rr' can be more aggressive about honoring these values.
+  // Some of these calls may fail due to trying to lower the priority
+  // (e.g. something may have already called setpriority() for this thread).
+  // This makes it hard to have non-main threads with higher priority than the
+  // main thread, but that's hard to fix. Tools like rr can choose to honor the
+  // requested values anyway.
+  // Use just 4 priorities so there's a reasonable chance of any two threads
+  // having equal priority.
+  setpriority(PRIO_PROCESS, 0, ChaosMode::randomUint32LessThan(4));
+#else
+  // We should set the affinity here but NSPR doesn't provide a way to expose it.
+  PR_SetThreadPriority(PR_GetCurrentThread(),
+    PRThreadPriority(ChaosMode::randomUint32LessThan(PR_PRIORITY_LAST + 1)));
+#endif
+
+#ifdef HAVE_SCHED_SETAFFINITY
+  // Force half the threads to CPU 0 so they compete for CPU
+  if (ChaosMode::randomUint32LessThan(2)) {
+    cpu_set_t cpus;
+    CPU_ZERO(&cpus);
+    CPU_SET(0, &cpus);
+    sched_setaffinity(0, sizeof(cpus), &cpus);
+  }
+#endif
+}
+
 /*static*/ void
 nsThread::ThreadFunc(void *arg)
 {
   nsThread *self = static_cast<nsThread *>(arg);  // strong reference
   self->mThread = PR_GetCurrentThread();
+  SetupCurrentThreadForChaosMode();
 
   // Inform the ThreadManager
   nsThreadManager::get()->RegisterCurrentThread(self);
 
   // Wait for and process startup event
   nsCOMPtr<nsIRunnable> event;
   if (!self->GetEvent(true, getter_AddRefs(event))) {
     NS_WARNING("failed waiting for thread startup event");
@@ -347,16 +397,17 @@ nsThread::Init()
   startup->Wait();
   return NS_OK;
 }
 
 nsresult
 nsThread::InitCurrentThread()
 {
   mThread = PR_GetCurrentThread();
+  SetupCurrentThreadForChaosMode();
 
   nsThreadManager::get()->RegisterCurrentThread(this);
   return NS_OK;
 }
 
 nsresult
 nsThread::PutEvent(nsIRunnable *event, nsNestedEventTarget *target)
 {
@@ -692,17 +743,20 @@ nsThread::SetPriority(int32_t priority)
     pri = PR_PRIORITY_URGENT;
   } else if (mPriority < PRIORITY_NORMAL) {
     pri = PR_PRIORITY_HIGH;
   } else if (mPriority > PRIORITY_NORMAL) {
     pri = PR_PRIORITY_LOW;
   } else {
     pri = PR_PRIORITY_NORMAL;
   }
-  PR_SetThreadPriority(mThread, pri);
+  // If chaos mode is active, retain the randomly chosen priority
+  if (!ChaosMode::isActive()) {
+    PR_SetThreadPriority(mThread, pri);
+  }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsThread::AdjustPriority(int32_t delta)
 {
   return SetPriority(mPriority + delta);