Merge inbound to m-c.
authorRyan VanderMeulen <ryanvm@gmail.com>
Sat, 12 Oct 2013 14:26:17 -0400
changeset 164385 4861dbac22db9021d92801539aafffcf4166679b
parent 164368 97700fc8b02b7d2cd8342d33a3bd1b7b0629372a (current diff)
parent 164384 40fbd6880056ff39979702152e1316dc631949e3 (diff)
child 164386 a50141faaab983470c1a6e6cd6d93a6d5bf57707
child 164400 daf7a1febf6807757522a57752e9763005196148
child 164412 d530e25f5c1f7acd17054b58c49fb93c29c90810
child 164427 f049ed12bbd7a54c6c0c7d9c4f3fcfe51dc93de5
push id3066
push userakeybl@mozilla.com
push dateMon, 09 Dec 2013 19:58:46 +0000
treeherdermozilla-beta@a31a0dce83aa [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone27.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 inbound to m-c.
dom/interfaces/contacts/nsIDOMMozContactChangeEvent.idl
--- a/content/base/src/nsFrameMessageManager.cpp
+++ b/content/base/src/nsFrameMessageManager.cpp
@@ -29,16 +29,17 @@
 #include "nsIDOMClassInfo.h"
 #include "nsIDOMFile.h"
 #include "xpcpublic.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/dom/StructuredCloneUtils.h"
 #include "JavaScriptChild.h"
 #include "JavaScriptParent.h"
 #include "nsDOMLists.h"
+#include "nsPrintfCString.h"
 #include <algorithm>
 
 #ifdef ANDROID
 #include <android/log.h>
 #endif
 #ifdef XP_WIN
 #include <windows.h>
 # if defined(SendMessage)
@@ -1004,24 +1005,188 @@ nsFrameMessageManager::Disconnect(bool a
   mParentManager = nullptr;
   mCallback = nullptr;
   mOwnedCallback = nullptr;
   if (!mHandlingMessage) {
     mListeners.Clear();
   }
 }
 
+namespace {
+
+struct MessageManagerReferentCount {
+  MessageManagerReferentCount() : strong(0), weakAlive(0), weakDead(0) {}
+  size_t strong;
+  size_t weakAlive;
+  size_t weakDead;
+  nsCOMArray<nsIAtom> suspectMessages;
+  nsDataHashtable<nsPtrHashKey<nsIAtom>, uint32_t> messageCounter;
+};
+
+} // anonymous namespace
+
+namespace mozilla {
+namespace dom {
+
+class MessageManagerReporter MOZ_FINAL : public nsIMemoryReporter
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIMEMORYREPORTER
+protected:
+  static const size_t kSuspectReferentCount = 300;
+  void CountReferents(nsFrameMessageManager* aMessageManager,
+                      MessageManagerReferentCount* aReferentCount);
+};
+
+NS_IMPL_ISUPPORTS1(MessageManagerReporter, nsIMemoryReporter)
+
+void
+MessageManagerReporter::CountReferents(nsFrameMessageManager* aMessageManager,
+                                       MessageManagerReferentCount* aReferentCount)
+{
+  for (uint32_t i = 0; i < aMessageManager->mListeners.Length(); i++) {
+    const nsMessageListenerInfo& listenerInfo = aMessageManager->mListeners[i];
+
+    if (listenerInfo.mWeakListener) {
+      nsCOMPtr<nsISupports> referent =
+        do_QueryReferent(listenerInfo.mWeakListener);
+      if (referent) {
+        aReferentCount->weakAlive++;
+      } else {
+        aReferentCount->weakDead++;
+      }
+    } else {
+      aReferentCount->strong++;
+    }
+
+    uint32_t oldCount = 0;
+    aReferentCount->messageCounter.Get(listenerInfo.mMessage, &oldCount);
+    uint32_t currentCount = oldCount + 1;
+    aReferentCount->messageCounter.Put(listenerInfo.mMessage, currentCount);
+
+    // Keep track of messages that have a suspiciously large
+    // number of referents (symptom of leak).
+    if (currentCount == kSuspectReferentCount) {
+      aReferentCount->suspectMessages.AppendElement(listenerInfo.mMessage);
+    }
+  }
+
+  // Add referent count in child managers because the listeners
+  // participate in messages dispatched from parent message manager.
+  for (uint32_t i = 0; i < aMessageManager->mChildManagers.Length(); i++) {
+    nsRefPtr<nsFrameMessageManager> mm =
+      static_cast<nsFrameMessageManager*>(aMessageManager->mChildManagers[i]);
+    CountReferents(mm, aReferentCount);
+  }
+}
+
+NS_IMETHODIMP
+MessageManagerReporter::GetName(nsACString& aName)
+{
+  aName.AssignLiteral("message-manager");
+  return NS_OK;
+}
+
+static nsresult
+ReportReferentCount(const char* aManagerType,
+                    const MessageManagerReferentCount& aReferentCount,
+                    nsIMemoryReporterCallback* aCb,
+                    nsISupports* aClosure)
+{
+#define REPORT(_path, _amount, _desc)                                         \
+    do {                                                                      \
+      nsresult rv;                                                            \
+      rv = aCb->Callback(EmptyCString(), _path,                               \
+                         nsIMemoryReporter::KIND_OTHER,                       \
+                         nsIMemoryReporter::UNITS_COUNT, _amount,             \
+                         _desc, aClosure);                                    \
+      NS_ENSURE_SUCCESS(rv, rv);                                              \
+    } while (0)
+
+  REPORT(nsPrintfCString("message-manager/referent/%s/strong", aManagerType),
+         aReferentCount.strong,
+         nsPrintfCString("The number of strong referents held by the message "
+                         "manager in the %s manager.", aManagerType));
+  REPORT(nsPrintfCString("message-manager/referent/%s/weak/alive", aManagerType),
+         aReferentCount.weakAlive,
+         nsPrintfCString("The number of weak referents that are still alive "
+                         "held by the message manager in the %s manager.",
+                         aManagerType));
+  REPORT(nsPrintfCString("message-manager/referent/%s/weak/dead", aManagerType),
+         aReferentCount.weakDead,
+         nsPrintfCString("The number of weak referents that are dead "
+                         "held by the message manager in the %s manager.",
+                         aManagerType));
+
+  for (uint32_t i = 0; i < aReferentCount.suspectMessages.Length(); i++) {
+    uint32_t totalReferentCount = 0;
+    aReferentCount.messageCounter.Get(aReferentCount.suspectMessages[i],
+                                      &totalReferentCount);
+    nsAtomCString suspect(aReferentCount.suspectMessages[i]);
+    REPORT(nsPrintfCString("message-manager-suspect/%s/referent(message=%s)",
+                           aManagerType, suspect.get()), totalReferentCount,
+           nsPrintfCString("A message in the %s message manager with a "
+                           "suspiciously large number of referents (symptom "
+                           "of a leak).", aManagerType));
+  }
+
+#undef REPORT
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+MessageManagerReporter::CollectReports(nsIMemoryReporterCallback* aCb,
+                                       nsISupports* aClosure)
+{
+  nsresult rv;
+
+  if (XRE_GetProcessType() == GeckoProcessType_Default) {
+    nsCOMPtr<nsIMessageBroadcaster> globalmm =
+      do_GetService("@mozilla.org/globalmessagemanager;1");
+    if (globalmm) {
+      nsRefPtr<nsFrameMessageManager> mm =
+        static_cast<nsFrameMessageManager*>(globalmm.get());
+      MessageManagerReferentCount count;
+      CountReferents(mm, &count);
+      rv = ReportReferentCount("global-manager", count, aCb, aClosure);
+      NS_ENSURE_SUCCESS(rv, rv);
+    }
+  }
+
+  if (nsFrameMessageManager::sParentProcessManager) {
+    MessageManagerReferentCount count;
+    CountReferents(nsFrameMessageManager::sParentProcessManager, &count);
+    rv = ReportReferentCount("parent-process-manager", count, aCb, aClosure);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  if (nsFrameMessageManager::sChildProcessManager) {
+    MessageManagerReferentCount count;
+    CountReferents(nsFrameMessageManager::sChildProcessManager, &count);
+    rv = ReportReferentCount("child-process-manager", count, aCb, aClosure);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  return NS_OK;
+}
+
+} // namespace dom
+} // namespace mozilla
+
 nsresult
 NS_NewGlobalMessageManager(nsIMessageBroadcaster** aResult)
 {
   NS_ENSURE_TRUE(XRE_GetProcessType() == GeckoProcessType_Default,
                  NS_ERROR_NOT_AVAILABLE);
   nsFrameMessageManager* mm = new nsFrameMessageManager(nullptr,
                                                         nullptr,
                                                         MM_CHROME | MM_GLOBAL | MM_BROADCASTER);
+  NS_RegisterMemoryReporter(new MessageManagerReporter());
   return CallQueryInterface(mm, aResult);
 }
 
 nsDataHashtable<nsStringHashKey, nsFrameJSScriptExecutorHolder*>*
   nsFrameScriptExecutor::sCachedScripts = nullptr;
 nsScriptCacheCleaner* nsFrameScriptExecutor::sScriptCacheCleaner = nullptr;
 
 void
@@ -1533,16 +1698,17 @@ NS_NewChildProcessMessageManager(nsISync
   NS_ASSERTION(!nsFrameMessageManager::sChildProcessManager,
                "Re-creating sChildProcessManager");
 
   MessageManagerCallback* cb;
   if (XRE_GetProcessType() == GeckoProcessType_Default) {
     cb = new SameChildProcessMessageManagerCallback();
   } else {
     cb = new ChildProcessMessageManagerCallback();
+    NS_RegisterMemoryReporter(new MessageManagerReporter());
   }
   nsFrameMessageManager* mm = new nsFrameMessageManager(cb,
                                                         nullptr,
                                                         MM_PROCESSMANAGER | MM_OWNSCALLBACK);
   nsFrameMessageManager::sChildProcessManager = mm;
   return CallQueryInterface(mm, aResult);
 }
 
--- a/content/base/src/nsFrameMessageManager.h
+++ b/content/base/src/nsFrameMessageManager.h
@@ -27,16 +27,17 @@
 
 namespace mozilla {
 namespace dom {
 
 class ContentParent;
 class ContentChild;
 struct StructuredCloneData;
 class ClonedMessageData;
+class MessageManagerReporter;
 
 namespace ipc {
 
 enum MessageManagerFlags {
   MM_CHILD = 0,
   MM_CHROME = 1,
   MM_GLOBAL = 2,
   MM_PROCESSMANAGER = 4,
@@ -138,16 +139,17 @@ class MOZ_STACK_CLASS SameProcessCpowHol
     JS::Rooted<JSObject*> mObj;
 };
 
 class nsFrameMessageManager MOZ_FINAL : public nsIContentFrameMessageManager,
                                         public nsIMessageBroadcaster,
                                         public nsIFrameScriptLoader,
                                         public nsIProcessChecker
 {
+  friend class mozilla::dom::MessageManagerReporter;
   typedef mozilla::dom::StructuredCloneData StructuredCloneData;
 public:
   nsFrameMessageManager(mozilla::dom::ipc::MessageManagerCallback* aCallback,
                         nsFrameMessageManager* aParentManager,
                         /* mozilla::dom::ipc::MessageManagerFlags */ uint32_t aFlags)
   : mChrome(!!(aFlags & mozilla::dom::ipc::MM_CHROME)),
     mGlobal(!!(aFlags & mozilla::dom::ipc::MM_GLOBAL)),
     mIsProcessManager(!!(aFlags & mozilla::dom::ipc::MM_PROCESSMANAGER)),
--- a/dom/interfaces/contacts/moz.build
+++ b/dom/interfaces/contacts/moz.build
@@ -2,15 +2,14 @@
 # vim: set filetype=python:
 # 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/.
 
 XPIDL_SOURCES += [
     'nsIContactProperties.idl',
     'nsIDOMContactManager.idl',
-    'nsIDOMMozContactChangeEvent.idl',
 ]
 
 XPIDL_MODULE = 'dom_contacts'
 
 MODULE = 'dom'
 
deleted file mode 100644
--- a/dom/interfaces/contacts/nsIDOMMozContactChangeEvent.idl
+++ /dev/null
@@ -1,24 +0,0 @@
-/* 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 "nsIDOMEvent.idl"
-
-[scriptable, builtinclass, uuid(7ee758eb-9353-4ade-8715-9953ea512ee2)]
-interface nsIDOMMozContactChangeEvent : nsIDOMEvent
-{
-  readonly attribute DOMString contactID;
-  readonly attribute DOMString reason;
-
-  [noscript] void initMozContactChangeEvent(in DOMString aType,
-                                            in boolean aCanBubble,
-                                            in boolean aCancelable,
-                                            in DOMString aContactID,
-                                            in DOMString aReason);
-};
-
-dictionary MozContactChangeEventInit : EventInit
-{
-  DOMString contactID;
-  DOMString reason;
-};
--- a/dom/moz.build
+++ b/dom/moz.build
@@ -2,21 +2,21 @@
 # vim: set filetype=python:
 # 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/.
 
 interfaces = [
     'base',
     'canvas',
+    'contacts',
     'core',
     'html',
     'events',
     'devicestorage',
-    'contacts',
     'settings',
     'stylesheets',
     'sidebar',
     'css',
     'traversal',
     'range',
     'xbl',
     'xpath',
--- a/dom/webidl/MozContactChangeEvent.webidl
+++ b/dom/webidl/MozContactChangeEvent.webidl
@@ -1,15 +1,15 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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/.
  */
 
-[Constructor(DOMString type, optional MozContactChangeEventInit eventInitDict), HeaderFile="GeneratedEventClasses.h"]
+[Constructor(DOMString type, optional MozContactChangeEventInit eventInitDict)]
 interface MozContactChangeEvent : Event
 {
   readonly attribute DOMString? contactID;
   readonly attribute DOMString? reason;
 };
 
 dictionary MozContactChangeEventInit : EventInit
 {
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -471,17 +471,16 @@ WEBIDL_FILES += [
     'CloseEvent.webidl',
     'CustomEvent.webidl',
     'DOMTransactionEvent.webidl',
     'DeviceOrientationEvent.webidl',
     'DeviceStorageChangeEvent.webidl',
     'ElementReplaceEvent.webidl',
     'HashChangeEvent.webidl',
     'MozApplicationEvent.webidl',
-    'MozContactChangeEvent.webidl',
     'MozMmsEvent.webidl',
     'MozSettingsEvent.webidl',
     'MozSmsEvent.webidl',
     'PageTransitionEvent.webidl',
     'PopStateEvent.webidl',
     'PopupBlockedEvent.webidl',
     'ProgressEvent.webidl',
     'RecordErrorEvent.webidl',
@@ -541,16 +540,17 @@ if CONFIG['ENABLE_TESTS']:
 
 GENERATED_EVENTS_WEBIDL_FILES = [
     'BlobEvent.webidl',
     'DataStoreChangeEvent.webidl',
     'DeviceLightEvent.webidl',
     'DeviceProximityEvent.webidl',
     'ErrorEvent.webidl',
     'MediaStreamEvent.webidl',
+    'MozContactChangeEvent.webidl',
     'MozInterAppMessageEvent.webidl',
     'RTCDataChannelEvent.webidl',
     'RTCPeerConnectionIceEvent.webidl',
     'TrackEvent.webidl',
     'UserProximityEvent.webidl',
 ]
 
 if CONFIG['MOZ_GAMEPAD']:
--- a/js/ipc/JavaScriptChild.cpp
+++ b/js/ipc/JavaScriptChild.cpp
@@ -127,19 +127,19 @@ JavaScriptChild::fail(JSContext *cx, Ret
     // that would crash.
     JS_ClearPendingException(cx);
 
     if (JS_IsStopIteration(exn)) {
         *rs = ReturnStatus(ReturnStopIteration());
         return true;
     }
 
-    if (!toVariant(cx, exn, &rs->get_ReturnException().exn()))
-        return true;
-
+    // If this fails, we still don't want to exit. Just return an invalid
+    // exception.
+    (void) toVariant(cx, exn, &rs->get_ReturnException().exn());
     return true;
 }
 
 bool
 JavaScriptChild::ok(ReturnStatus *rs)
 {
     *rs = ReturnStatus(ReturnSuccess());
     return true;
@@ -372,17 +372,17 @@ JavaScriptChild::AnswerGet(const ObjectI
         return false;
 
     JSAutoCompartment comp(cx, obj);
 
     RootedId internedId(cx);
     if (!convertGeckoStringToId(cx, id, &internedId))
         return fail(cx, rs);
 
-    JS::Rooted<JS::Value> val(cx);
+    JS::RootedValue val(cx);
     if (!JS_ForwardGetPropertyTo(cx, obj, internedId, receiver, &val))
         return fail(cx, rs);
 
     if (!toVariant(cx, val, result))
         return fail(cx, rs);
 
     return ok(rs);
 }
@@ -532,17 +532,17 @@ JavaScriptChild::AnswerCall(const Object
         if (!vals.append(v))
             return fail(cx, rs);
     }
 
     // Copy the outparams. If any outparam is already set to a void_t, we
     // treat this as the outparam never having been set.
     for (size_t i = 0; i < vals.length(); i++) {
         JSVariant variant;
-        if (!toVariant(cx, vals[i], &variant))
+        if (!toVariant(cx, vals.handleAt(i), &variant))
             return fail(cx, rs);
         outparams->ReplaceElementAt(i, JSParam(variant));
     }
 
     return ok(rs);
 }
 
 bool
--- a/js/ipc/JavaScriptShared.cpp
+++ b/js/ipc/JavaScriptShared.cpp
@@ -147,17 +147,17 @@ JavaScriptShared::convertGeckoStringToId
     RootedString str(cx, JS_NewUCStringCopyN(cx, from.BeginReading(), from.Length()));
     if (!str)
         return false;
 
     return JS_ValueToId(cx, StringValue(str), to.address());
 }
 
 bool
-JavaScriptShared::toVariant(JSContext *cx, jsval from, JSVariant *to)
+JavaScriptShared::toVariant(JSContext *cx, JS::HandleValue from, JSVariant *to)
 {
     switch (JS_TypeOfValue(cx, from)) {
       case JSTYPE_VOID:
         *to = void_t();
         return true;
 
       case JSTYPE_NULL:
       {
--- a/js/ipc/JavaScriptShared.h
+++ b/js/ipc/JavaScriptShared.h
@@ -86,17 +86,17 @@ class JavaScriptShared
 
     static const uint32_t OBJECT_EXTRA_BITS  = 1;
     static const uint32_t OBJECT_IS_CALLABLE = (1 << 0);
 
     bool Unwrap(JSContext *cx, const InfallibleTArray<CpowEntry> &aCpows, JSObject **objp);
     bool Wrap(JSContext *cx, JS::HandleObject aObj, InfallibleTArray<CpowEntry> *outCpows);
 
   protected:
-    bool toVariant(JSContext *cx, jsval from, JSVariant *to);
+    bool toVariant(JSContext *cx, JS::HandleValue from, JSVariant *to);
     bool toValue(JSContext *cx, const JSVariant &from, JS::MutableHandleValue to);
     bool fromDescriptor(JSContext *cx, JS::Handle<JSPropertyDescriptor> desc, PPropertyDescriptor *out);
     bool toDescriptor(JSContext *cx, const PPropertyDescriptor &in,
                       JS::MutableHandle<JSPropertyDescriptor> out);
     bool convertIdToGeckoString(JSContext *cx, JS::HandleId id, nsString *to);
     bool convertGeckoStringToId(JSContext *cx, const nsString &from, JS::MutableHandleId id);
 
     bool toValue(JSContext *cx, const JSVariant &from, jsval *to) {
--- a/js/src/builtin/TypedObject.cpp
+++ b/js/src/builtin/TypedObject.cpp
@@ -314,56 +314,16 @@ TypeEquivalent(JSContext *cx, unsigned i
     nullptr,                                                                  \
     nullptr                                                                   \
 },
 
 const Class js::NumericTypeClasses[ScalarTypeRepresentation::TYPE_MAX] = {
     JS_FOR_EACH_SCALAR_TYPE_REPR(BINARYDATA_NUMERIC_CLASSES)
 };
 
-template <typename Domain, typename Input>
-static bool
-InRange(Input x)
-{
-    return std::numeric_limits<Domain>::min() <= x &&
-           x <= std::numeric_limits<Domain>::max();
-}
-
-template <>
-bool
-InRange<float, int>(int x)
-{
-    return -std::numeric_limits<float>::max() <= x &&
-           x <= std::numeric_limits<float>::max();
-}
-
-template <>
-bool
-InRange<double, int>(int x)
-{
-    return -std::numeric_limits<double>::max() <= x &&
-           x <= std::numeric_limits<double>::max();
-}
-
-template <>
-bool
-InRange<float, double>(double x)
-{
-    return -std::numeric_limits<float>::max() <= x &&
-           x <= std::numeric_limits<float>::max();
-}
-
-template <>
-bool
-InRange<double, double>(double x)
-{
-    return -std::numeric_limits<double>::max() <= x &&
-           x <= std::numeric_limits<double>::max();
-}
-
 #define BINARYDATA_TYPE_TO_CLASS(constant_, type_, name_)                     \
     template <>                                                               \
     const Class *                                                             \
     NumericType<constant_, type_>::typeToClass()                              \
     {                                                                         \
         return &NumericTypeClasses[constant_];                                \
     }
 
--- a/js/src/devtools/rootAnalysis/analyze.py
+++ b/js/src/devtools/rootAnalysis/analyze.py
@@ -192,17 +192,17 @@ data = config.copy()
 
 parser = argparse.ArgumentParser(description='Statically analyze build tree for rooting hazards.')
 parser.add_argument('step', metavar='STEP', type=str, nargs='?',
                     help='run starting from this step')
 parser.add_argument('--source', metavar='SOURCE', type=str, nargs='?',
                     help='source code to analyze')
 parser.add_argument('--upto', metavar='UPTO', type=str, nargs='?',
                     help='last step to execute')
-parser.add_argument('--jobs', '-j', default=4, metavar='JOBS', type=int,
+parser.add_argument('--jobs', '-j', default=None, metavar='JOBS', type=int,
                     help='number of simultaneous analyzeRoots.js jobs')
 parser.add_argument('--list', const=True, nargs='?', type=bool,
                     help='display available steps')
 parser.add_argument('--buildcommand', '--build', '-b', type=str, nargs='?',
                     help='command to build the tree being analyzed')
 parser.add_argument('--tag', '-t', type=str, nargs='?',
                     help='name of job, also sets build command to "build.<tag>"')
 
--- a/js/src/devtools/rootAnalysis/analyzeRoots.js
+++ b/js/src/devtools/rootAnalysis/analyzeRoots.js
@@ -551,21 +551,21 @@ var N = (maxStream - minStream) + 1;
 var each = Math.floor(N/numBatches);
 var start = minStream + each * (batch - 1);
 var end = Math.min(minStream + each * batch - 1, maxStream);
 
 for (var nameIndex = start; nameIndex <= end; nameIndex++) {
     var name = xdb.read_key(nameIndex);
     var functionName = name.readString();
     var data = xdb.read_entry(name);
-    functionBodies = JSON.parse(data.readString());
+    xdb.free_string(name);
+    var json = data.readString();
+    xdb.free_string(data);
+    functionBodies = JSON.parse(json);
 
     for (var body of functionBodies)
         body.suppressed = [];
     for (var body of functionBodies) {
         for (var [pbody, id] of allRAIIGuardedCallPoints(body, isSuppressConstructor))
             pbody.suppressed[id] = true;
     }
     processBodies(functionName);
-
-    xdb.free_string(name);
-    xdb.free_string(data);
 }
--- a/js/src/devtools/rootAnalysis/run_complete
+++ b/js/src/devtools/rootAnalysis/run_complete
@@ -19,16 +19,17 @@
 
 # do a complete run of the system from raw source to reports. this requires
 # various run_monitor processes to be running in the background (maybe on other
 # machines) and watching a shared poll_file for jobs. if the output directory
 # for this script already exists then an incremental analysis will be performed
 # and the reports will only reflect the changes since the earlier run.
 
 use strict;
+use warnings;
 use IO::Handle;
 use File::Basename qw(dirname);
 use Getopt::Long;
 use Cwd;
 
 #################################
 # environment specific settings #
 #################################
@@ -188,17 +189,17 @@ sub get_manager_address
     my $log_file = shift or die;
 
     # give the manager one second to start, any longer and something's broken.
     sleep(1);
 
     my $log_data = `cat $log_file`;
     my ($port) = $log_data =~ /Listening on ([\.\:0-9]*)/
       or die "no manager found";
-    print OUT "Connecting to manager on port $port\n";
+    print OUT "Connecting to manager on port $port\n" unless $suppress_logs;
     print "Connecting to manager on port $port.\n";
     return $1;
 }
 
 sub run_build
 {
     print "build started: ";
     print scalar(localtime());
@@ -305,17 +306,17 @@ sub run_pass
     unlink($poll_file);
 
     print "$name finished: ";
     print scalar(localtime());
     print "\n";
 
     # collate the worker's output into a single file. make this asynchronous
     # so we can wait a bit and make sure we get all worker output.
-    defined(my $pid = fork) or die;
+    defined($pid = fork) or die;
 
     if (!$pid) {
         sleep(20);
         exec("cat $name.*.log > $name.log");
     }
 
     push(@waitpids, $pid);
 }
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -89,17 +89,17 @@ PushStatementPC(ParseContext<ParseHandle
     stmt->blockid = pc->blockid();
     PushStatement(pc, stmt, type);
 }
 
 // See comment on member function declaration.
 template <>
 bool
 ParseContext<FullParseHandler>::define(TokenStream &ts,
-                                       PropertyName *name, ParseNode *pn, Definition::Kind kind)
+                                       HandlePropertyName name, ParseNode *pn, Definition::Kind kind)
 {
     JS_ASSERT(!pn->isUsed());
     JS_ASSERT_IF(pn->isDefn(), pn->isPlaceholder());
 
     Definition *prevDef = nullptr;
     if (kind == Definition::LET)
         prevDef = decls_.lookupFirst(name);
     else
@@ -181,17 +181,17 @@ ParseContext<FullParseHandler>::define(T
         MOZ_ASSUME_UNREACHABLE("unexpected kind");
     }
 
     return true;
 }
 
 template <>
 bool
-ParseContext<SyntaxParseHandler>::define(TokenStream &ts, PropertyName *name, Node pn,
+ParseContext<SyntaxParseHandler>::define(TokenStream &ts, HandlePropertyName name, Node pn,
                                          Definition::Kind kind)
 {
     JS_ASSERT(!decls_.lookupFirst(name));
 
     if (lexdeps.lookupDefn<SyntaxParseHandler>(name))
         lexdeps->remove(name);
 
     // Keep track of the number of arguments in args_, for fun->nargs.
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -162,17 +162,17 @@ struct ParseContext : public GenericPars
      *    non-placeholder definition.
      *  + If this is a function scope (sc->inFunction), 'pn' is bound to a
      *    particular local/argument slot.
      *  + PND_CONST is set for Definition::COSNT
      *  + Pre-existing uses of pre-existing placeholders have been linked to
      *    'pn' if they are in the scope of 'pn'.
      *  + Pre-existing placeholders in the scope of 'pn' have been removed.
      */
-    bool define(TokenStream &ts, PropertyName *name, Node pn, Definition::Kind);
+    bool define(TokenStream &ts, HandlePropertyName name, Node pn, Definition::Kind);
 
     /*
      * Let definitions may shadow same-named definitions in enclosing scopes.
      * To represesent this, 'decls' is not a plain map, but actually:
      *   decls :: name -> stack of definitions
      * New bindings are pushed onto the stack, name lookup always refers to the
      * top of the stack, and leaving a block scope calls popLetDecl for each
      * name in the block's scope.
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -6147,17 +6147,18 @@ CodeGenerator::visitGetPropertyParIC(Out
 }
 
 bool
 CodeGenerator::addGetElementCache(LInstruction *ins, Register obj, ConstantOrRegister index,
                                   TypedOrValueRegister output, bool monitoredResult)
 {
     switch (gen->info().executionMode()) {
       case SequentialExecution: {
-        GetElementIC cache(obj, index, output, monitoredResult);
+        RegisterSet liveRegs = ins->safepoint()->liveRegs();
+        GetElementIC cache(liveRegs, obj, index, output, monitoredResult);
         return addCache(ins, allocateCache(cache));
       }
       case ParallelExecution: {
         GetElementParIC cache(obj, index, output, monitoredResult);
         return addCache(ins, allocateCache(cache));
       }
       default:
         MOZ_ASSUME_UNREACHABLE("No such execution mode");
--- a/js/src/jit/IonCaches.cpp
+++ b/js/src/jit/IonCaches.cpp
@@ -835,16 +835,17 @@ GenerateReadSlot(JSContext *cx, IonScrip
 static bool
 EmitGetterCall(JSContext *cx, MacroAssembler &masm,
                IonCache::StubAttacher &attacher, JSObject *obj,
                JSObject *holder, HandleShape shape,
                RegisterSet liveRegs, Register object,
                Register scratchReg, TypedOrValueRegister output,
                void *returnAddr)
 {
+    JS_ASSERT(output.hasValue());
     // saveLive()
     MacroAssembler::AfterICSaveLive aic = masm.icSaveLive(liveRegs);
 
     // Remaining registers should basically be free, but we need to use |object| still
     // so leave it alone.
     RegisterSet regSet(RegisterSet::All());
     regSet.take(AnyRegister(object));
 
@@ -978,49 +979,53 @@ EmitGetterCall(JSContext *cx, MacroAssem
 
     return true;
 }
 
 static bool
 GenerateCallGetter(JSContext *cx, IonScript *ion, MacroAssembler &masm,
                    IonCache::StubAttacher &attacher, JSObject *obj, PropertyName *name,
                    JSObject *holder, HandleShape shape, RegisterSet &liveRegs, Register object,
-                   TypedOrValueRegister output, void *returnAddr)
+                   TypedOrValueRegister output, void *returnAddr, Label *failures = NULL)
 {
     JS_ASSERT(obj->isNative());
+    JS_ASSERT(output.hasValue());
+
+    // Use the passed in label if there was one. Otherwise, we'll have to make our own.
+    Label stubFailure;
+    failures = failures ? failures : &stubFailure;
+
     // Initial shape check.
-    Label stubFailure;
     masm.branchPtr(Assembler::NotEqual, Address(object, JSObject::offsetOfShape()),
-                   ImmGCPtr(obj->lastProperty()), &stubFailure);
-
-    JS_ASSERT(output.hasValue());
+                   ImmGCPtr(obj->lastProperty()), failures);
+
     Register scratchReg = output.valueReg().scratchReg();
 
     // Note: this may clobber the object register if it's used as scratch.
     if (obj != holder)
-        GeneratePrototypeGuards(cx, ion, masm, obj, holder, object, scratchReg, &stubFailure);
+        GeneratePrototypeGuards(cx, ion, masm, obj, holder, object, scratchReg, failures);
 
     // Guard on the holder's shape.
     Register holderReg = scratchReg;
     masm.moveNurseryPtr(ImmMaybeNurseryPtr(holder), holderReg);
     masm.branchPtr(Assembler::NotEqual,
                    Address(holderReg, JSObject::offsetOfShape()),
                    ImmGCPtr(holder->lastProperty()),
-                   &stubFailure);
+                   failures);
 
     // Now we're good to go to invoke the native call.
     if (!EmitGetterCall(cx, masm, attacher, obj, holder, shape, liveRegs, object,
                         scratchReg, output, returnAddr))
         return false;
 
     // Rejoin jump.
     attacher.jumpRejoin(masm);
 
     // Jump to next stub.
-    masm.bind(&stubFailure);
+    masm.bind(failures);
     attacher.jumpNextStub(masm);
 
     return true;
 }
 
 static bool
 GenerateArrayLength(JSContext *cx, MacroAssembler &masm, IonCache::StubAttacher &attacher,
                     JSObject *obj, Register object, TypedOrValueRegister output)
@@ -1115,17 +1120,18 @@ IsCacheableArrayLength(JSContext *cx, Ha
 
     return true;
 }
 
 template <class GetPropCache>
 static GetPropertyIC::NativeGetPropCacheability
 CanAttachNativeGetProp(typename GetPropCache::Context cx, const GetPropCache &cache,
                        HandleObject obj, HandlePropertyName name,
-                       MutableHandleObject holder, MutableHandleShape shape)
+                       MutableHandleObject holder, MutableHandleShape shape,
+                       bool skipArrayLen = false)
 {
     if (!obj || !obj->isNative())
         return GetPropertyIC::CanAttachNone;
 
     // The lookup needs to be universally pure, otherwise we risk calling hooks out
     // of turn. We don't mind doing this even when purity isn't required, because we
     // only miss out on shape hashification, which is only a temporary perf cost.
     // The limits were arbitrarily set, anyways.
@@ -1141,26 +1147,32 @@ CanAttachNativeGetProp(typename GetPropC
         // TI infers the possible types of native object properties. There's one
         // edge case though: for singleton objects it does not add the initial
         // "undefined" type, see the propertySet comment in jsinfer.h.
         if (!cache.canMonitorSingletonUndefinedSlot(holder, shape))
             return GetPropertyIC::CanAttachNone;
         return GetPropertyIC::CanAttachReadSlot;
     }
 
-    if (cx->names().length == name && cache.allowArrayLength(cx, obj) &&
+    // |length| is a non-configurable getter property on ArrayObjects. Any time this
+    // check would have passed, we can install a getter stub instead. Allow people to
+    // make that decision themselves with skipArrayLen
+    if (!skipArrayLen && cx->names().length == name && cache.allowArrayLength(cx, obj) &&
         IsCacheableArrayLength(cx, obj, name, cache.output()))
     {
         // The array length property is non-configurable, which means both that
         // checking the class of the object and the name of the property is enough
         // and that we don't need to worry about monitoring, since we know the
         // return type statically.
         return GetPropertyIC::CanAttachArrayLength;
     }
 
+    // IonBuilder guarantees that it's impossible to generate a GetPropertyIC with
+    // allowGetters() true and cache.output().hasValue() false. If this isn't true,
+    // we will quickly assert during stub generation.
     if (cache.allowGetters() &&
         (IsCacheableGetPropCallNative(obj, holder, shape) ||
          IsCacheableGetPropCallPropertyOp(obj, holder, shape)))
     {
         // Don't enable getter call if cache is parallel or idempotent, since
         // they can be effectful. This is handled by allowGetters()
         return GetPropertyIC::CanAttachCallGetter;
     }
@@ -1413,28 +1425,33 @@ GetPropertyIC::tryAttachDOMProxyShadowed
 bool
 GetPropertyIC::tryAttachDOMProxyUnshadowed(JSContext *cx, IonScript *ion, HandleObject obj,
                                            HandlePropertyName name, bool resetNeeded,
                                            void *returnAddr, bool *emitted)
 {
     JS_ASSERT(canAttachStub());
     JS_ASSERT(!*emitted);
     JS_ASSERT(IsCacheableDOMProxy(obj));
-    JS_ASSERT(output().hasValue());
 
     RootedObject checkObj(cx, obj->getTaggedProto().toObjectOrNull());
     RootedObject holder(cx);
     RootedShape shape(cx);
 
     NativeGetPropCacheability canCache =
-        CanAttachNativeGetProp(cx, *this, checkObj, name, &holder, &shape);
+        CanAttachNativeGetProp(cx, *this, checkObj, name, &holder, &shape,
+                               /* skipArrayLen = */true);
+    JS_ASSERT(canCache != CanAttachArrayLength);
 
     if (canCache == CanAttachNone)
         return true;
 
+    // Make sure we observe our invariants if we're gonna deoptimize.
+    if (!holder && (idempotent() || !output().hasValue()))
+        return true;
+
     *emitted = true;
 
     if (resetNeeded) {
         // If we know that we have a DoesntShadowUnique object, then
         // we reset the cache to clear out an existing IC for the object
         // (if there is one). The generation is a constant in the generated
         // code and we will not have the same generation again for this
         // object, so the generation check in the existing IC would always
@@ -1474,26 +1491,28 @@ GetPropertyIC::tryAttachDOMProxyUnshadow
                     &failures);
 
         if (canCache == CanAttachReadSlot) {
             EmitLoadSlot(masm, holder, shape, holderReg, output(), scratchReg);
         } else {
             // EmitGetterCall() expects |obj| to be the object the property is
             // on to do some checks. Since we actually looked at checkObj, and
             // no extra guards will be generated, we can just pass that instead.
-            JS_ASSERT_IF(canCache != CanAttachCallGetter, canCache == CanAttachArrayLength);
+            JS_ASSERT(canCache == CanAttachCallGetter);
+            JS_ASSERT(!idempotent());
             if (!EmitGetterCall(cx, masm, attacher, checkObj, holder, shape, liveRegs_,
                                 object(), scratchReg, output(), returnAddr))
             {
                 return false;
             }
         }
     } else {
         // Property was not found on the prototype chain. Deoptimize down to
         // proxy get call
+        JS_ASSERT(!idempotent());
         if (!EmitCallProxyGet(cx, masm, attacher, name, liveRegs_, object(), output(),
                               returnAddr))
         {
             return false;
         }
     }
 
     attacher.jumpRejoin(masm);
@@ -1509,19 +1528,16 @@ GetPropertyIC::tryAttachProxy(JSContext 
                               bool *emitted)
 {
     JS_ASSERT(canAttachStub());
     JS_ASSERT(!*emitted);
 
     if (!obj->is<ProxyObject>())
         return true;
 
-    if (!output().hasValue())
-        return true;
-
     // Skim off DOM proxies.
     if (IsCacheableDOMProxy(obj)) {
         RootedId id(cx, NameToId(name));
         DOMProxyShadowsResult shadows = GetDOMProxyShadowsCheck()(cx, obj, id);
         if (shadows == ShadowCheckFailed)
             return false;
         if (shadows == Shadows)
             return tryAttachDOMProxyShadowed(cx, ion, obj, returnAddr, emitted);
@@ -1555,16 +1571,19 @@ GetPropertyIC::tryAttachGenericProxy(JSC
 {
     JS_ASSERT(canAttachStub());
     JS_ASSERT(!*emitted);
     JS_ASSERT(obj->is<ProxyObject>());
 
     if (hasGenericProxyStub())
         return true;
 
+    if (idempotent() || !output().hasValue())
+        return true;
+
     *emitted = true;
 
     Label failures;
     MacroAssembler masm(cx);
     RepatchStubAppender attacher(*this);
 
     Register scratchReg = output().valueReg().scratchReg();
 
@@ -2945,43 +2964,60 @@ GetElementIC::canAttachGetProp(JSObject 
     return (obj->isNative() &&
             idval.isString() &&
             JSID_IS_ATOM(id) &&
             !JSID_TO_ATOM(id)->isIndex(&dummy));
 }
 
 bool
 GetElementIC::attachGetProp(JSContext *cx, IonScript *ion, HandleObject obj,
-                            const Value &idval, HandlePropertyName name)
+                            const Value &idval, HandlePropertyName name,
+                            void *returnAddr)
 {
     JS_ASSERT(index().reg().hasValue());
 
     RootedObject holder(cx);
     RootedShape shape(cx);
 
     GetPropertyIC::NativeGetPropCacheability canCache =
-        CanAttachNativeGetProp(cx, *this, obj, name, &holder, &shape);
-
-    if (canCache != GetPropertyIC::CanAttachReadSlot) {
+        CanAttachNativeGetProp(cx, *this, obj, name, &holder, &shape,
+                               /* skipArrayLen =*/true);
+
+    bool cacheable = canCache == GetPropertyIC::CanAttachReadSlot ||
+                     (canCache == GetPropertyIC::CanAttachCallGetter &&
+                      output().hasValue());
+
+    if (!cacheable) {
         IonSpew(IonSpew_InlineCaches, "GETELEM uncacheable property");
         return true;
     }
 
     JS_ASSERT(idval.isString());
 
     Label failures;
     MacroAssembler masm(cx);
 
     // Guard on the index value.
     ValueOperand val = index().reg().valueReg();
     masm.branchTestValue(Assembler::NotEqual, val, idval, &failures);
 
     RepatchStubAppender attacher(*this);
-    GenerateReadSlot(cx, ion, masm, attacher, obj, holder, shape, object(), output(),
-                     &failures);
+    if (canCache == GetPropertyIC::CanAttachReadSlot) {
+        GenerateReadSlot(cx, ion, masm, attacher, obj, holder, shape, object(), output(),
+                         &failures);
+    } else {
+        JS_ASSERT(canCache == GetPropertyIC::CanAttachCallGetter);
+        // Set the frame for bailout safety of the OOL call.
+        masm.setFramePushed(ion->frameSize());
+        if (!GenerateCallGetter(cx, ion, masm, attacher, obj, name, holder, shape, liveRegs_,
+                                object(), output(), returnAddr, &failures))
+        {
+            return false;
+        }
+    }
 
     return linkAndAttachStub(cx, masm, attacher, ion, "property");
 }
 
 /* static */ bool
 GetElementIC::canAttachDenseElement(JSObject *obj, const Value &idval)
 {
     return obj->isNative() && idval.isInt32();
@@ -3296,17 +3332,18 @@ GetElementIC::attachArgumentsElement(JSC
     hasNormalArgumentsStub_ = true;
     return linkAndAttachStub(cx, masm, attacher, ion, "ArgsObj element (normal)");
 }
 
 bool
 GetElementIC::update(JSContext *cx, size_t cacheIndex, HandleObject obj,
                      HandleValue idval, MutableHandleValue res)
 {
-    IonScript *ion = GetTopIonJSScript(cx)->ionScript();
+    void *returnAddr;
+    IonScript *ion = GetTopIonJSScript(cx, &returnAddr)->ionScript();
     GetElementIC &cache = ion->getCache(cacheIndex).toGetElement();
     RootedScript script(cx);
     jsbytecode *pc;
     cache.getScriptedLocation(&script, &pc);
     RootedValue lval(cx, ObjectValue(*obj));
 
     if (cache.isDisabled()) {
         if (!GetElementOperation(cx, JSOp(*pc), &lval, idval, res))
@@ -3333,17 +3370,17 @@ GetElementIC::update(JSContext *cx, size
             (cache.output().hasValue() || !cache.output().typedReg().isFloat()))
         {
             if (!cache.attachArgumentsElement(cx, ion, obj))
                 return false;
             attachedStub = true;
         }
         if (!attachedStub && cache.monitoredResult() && canAttachGetProp(obj, idval, id)) {
             RootedPropertyName name(cx, JSID_TO_ATOM(id)->asPropertyName());
-            if (!cache.attachGetProp(cx, ion, obj, idval, name))
+            if (!cache.attachGetProp(cx, ion, obj, idval, name, returnAddr))
                 return false;
             attachedStub = true;
         }
         if (!attachedStub && !cache.hasDenseStub() && canAttachDenseElement(obj, idval)) {
             if (!cache.attachDenseElement(cx, ion, obj, idval))
                 return false;
             attachedStub = true;
         }
--- a/js/src/jit/IonCaches.h
+++ b/js/src/jit/IonCaches.h
@@ -700,33 +700,36 @@ class SetPropertyIC : public RepatchIonC
 
     static bool
     update(JSContext *cx, size_t cacheIndex, HandleObject obj, HandleValue value);
 };
 
 class GetElementIC : public RepatchIonCache
 {
   protected:
+    RegisterSet liveRegs_;
+
     Register object_;
     ConstantOrRegister index_;
     TypedOrValueRegister output_;
 
     bool monitoredResult_ : 1;
     bool hasDenseStub_ : 1;
     bool hasStrictArgumentsStub_ : 1;
     bool hasNormalArgumentsStub_ : 1;
 
     size_t failedUpdates_;
 
     static const size_t MAX_FAILED_UPDATES;
 
   public:
-    GetElementIC(Register object, ConstantOrRegister index,
+    GetElementIC(RegisterSet liveRegs, Register object, ConstantOrRegister index,
                  TypedOrValueRegister output, bool monitoredResult)
-      : object_(object),
+      : liveRegs_(liveRegs),
+        object_(object),
         index_(index),
         output_(output),
         monitoredResult_(monitoredResult),
         hasDenseStub_(false),
         hasStrictArgumentsStub_(false),
         hasNormalArgumentsStub_(false),
         failedUpdates_(0)
     {
@@ -756,28 +759,29 @@ class GetElementIC : public RepatchIonCa
     }
     void setHasDenseStub() {
         JS_ASSERT(!hasDenseStub());
         hasDenseStub_ = true;
     }
 
     // Helpers for CanAttachNativeGetProp
     typedef JSContext * Context;
-    bool allowGetters() const { return false; }
+    bool allowGetters() const { JS_ASSERT(!idempotent()); return true; }
     bool allowArrayLength(Context, HandleObject) const { return false; }
     bool canMonitorSingletonUndefinedSlot(HandleObject holder, HandleShape shape) const {
         return monitoredResult();
     }
 
     static bool canAttachGetProp(JSObject *obj, const Value &idval, jsid id);
     static bool canAttachDenseElement(JSObject *obj, const Value &idval);
     static bool canAttachTypedArrayElement(JSObject *obj, const Value &idval,
                                            TypedOrValueRegister output);
 
-    bool attachGetProp(JSContext *cx, IonScript *ion, HandleObject obj, const Value &idval, HandlePropertyName name);
+    bool attachGetProp(JSContext *cx, IonScript *ion, HandleObject obj, const Value &idval,
+                       HandlePropertyName name, void *returnAddr);
     bool attachDenseElement(JSContext *cx, IonScript *ion, JSObject *obj, const Value &idval);
     bool attachTypedArrayElement(JSContext *cx, IonScript *ion, TypedArrayObject *tarr,
                                  const Value &idval);
     bool attachArgumentsElement(JSContext *cx, IonScript *ion, JSObject *obj);
 
     static bool
     update(JSContext *cx, size_t cacheIndex, HandleObject obj, HandleValue idval,
            MutableHandleValue vp);
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -611,49 +611,68 @@ JS_IsBuiltinFunctionConstructor(JSFuncti
  * Initializing that subsystem from JS_Init eliminates the problem, but
  * initialization can take a comparatively long time (15ms or so), so we
  * really don't want to do it in JS_Init, and we really do want to do it only
  * when PRMJ_Now is eventually called.
  */
 enum InitState { Uninitialized, Running, ShutDown };
 static InitState jsInitState = Uninitialized;
 
+#ifdef DEBUG
+static void
+CheckMessageNumbering()
+{
+    // Assert that the numbers associated with the error names in js.msg are
+    // monotonically increasing.  It's not a compile-time check, but it's
+    // better than nothing.
+    int errorNumber = 0;
+# define MSG_DEF(name, number, count, exception, format)                      \
+    JS_ASSERT(name == errorNumber++);
+# include "js.msg"
+# undef MSG_DEF
+}
+
+static unsigned
+MessageParameterCount(const char *format)
+{
+    unsigned numfmtspecs = 0;
+    for (const char *fmt = format; *fmt != '\0'; fmt++) {
+        if (*fmt == '{' && isdigit(fmt[1]))
+            ++numfmtspecs;
+    }
+    return numfmtspecs;
+}
+
+static void
+CheckMessageParameterCounts()
+{
+    // Assert that each message format has the correct number of braced
+    // parameters.
+# define MSG_DEF(name, number, count, exception, format)                      \
+    JS_BEGIN_MACRO                                                            \
+        JS_ASSERT(MessageParameterCount(format) == count);                    \
+    JS_END_MACRO;
+# include "js.msg"
+# undef MSG_DEF
+}
+#endif /* DEBUG */
+
 JS_PUBLIC_API(bool)
 JS_Init(void)
 {
     MOZ_ASSERT(jsInitState == Uninitialized,
                "must call JS_Init once before any JSAPI operation except "
                "JS_SetICUMemoryFunctions");
     MOZ_ASSERT(!JSRuntime::hasLiveRuntimes(),
                "how do we have live runtimes before JS_Init?");
 
 #ifdef DEBUG
-    // Assert that the numbers associated with the error names in js.msg are
-    // monotonically increasing.  It's not a compile-time check, but it's
-    // better than nothing.
-    int errorNumber = 0;
-#define MSG_DEF(name, number, count, exception, format)                       \
-    JS_ASSERT(name == errorNumber++);
-#include "js.msg"
-#undef MSG_DEF
-
-    // Assert that each message format has the correct number of braced
-    // parameters.
-#define MSG_DEF(name, number, count, exception, format)                       \
-    JS_BEGIN_MACRO                                                            \
-        unsigned numfmtspecs = 0;                                             \
-        for (const char *fmt = format; *fmt != '\0'; fmt++) {                 \
-            if (*fmt == '{' && isdigit(fmt[1]))                               \
-                ++numfmtspecs;                                                \
-        }                                                                     \
-        JS_ASSERT(count == numfmtspecs);                                      \
-    JS_END_MACRO;
-#include "js.msg"
-#undef MSG_DEF
-#endif /* DEBUG */
+    CheckMessageNumbering();
+    CheckMessageParameterCounts();
+#endif
 
     using js::TlsPerThreadData;
     if (!TlsPerThreadData.initialized() && !TlsPerThreadData.init())
         return false;
 
 #if defined(JS_ION)
     if (!jit::InitializeIon())
         return false;
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -1081,24 +1081,24 @@ ArrayJoin(JSContext *cx, CallArgs &args)
 
     // Steps 2 and 3
     uint32_t length;
     if (!GetLengthProperty(cx, obj, &length))
         return false;
 
     // Steps 4 and 5
     RootedString sepstr(cx, nullptr);
+    JS::Anchor<JSString *> anchor(nullptr);
+    const jschar *sepchars;
+    size_t seplen;
     if (!Locale && args.hasDefined(0)) {
         sepstr = ToString<CanGC>(cx, args[0]);
         if (!sepstr)
             return false;
-    }
-    const jschar *sepchars;
-    size_t seplen;
-    if (sepstr) {
+        anchor = sepstr;
         sepchars = sepstr->getChars(cx);
         if (!sepchars)
             return false;
         seplen = sepstr->length();
     } else {
         static const jschar comma = ',';
         sepchars = &comma;
         seplen = 1;
--- a/js/src/jsproxy.cpp
+++ b/js/src/jsproxy.cpp
@@ -3247,17 +3247,17 @@ proxy_createFunction(JSContext *cx, unsi
     proto = parent->global().getOrCreateFunctionPrototype(cx);
     if (!proto)
         return false;
     parent = proto->getParent();
 
     RootedObject call(cx, ValueToCallable(cx, vp[3], argc - 2));
     if (!call)
         return false;
-    JSObject *construct = nullptr;
+    RootedObject construct(cx, nullptr);
     if (argc > 2) {
         construct = ValueToCallable(cx, vp[4], argc - 3);
         if (!construct)
             return false;
     } else {
         construct = call;
     }
 
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -588,16 +588,17 @@ bool
 js::ExecuteKernel(JSContext *cx, HandleScript script, JSObject &scopeChainArg, const Value &thisv,
                   ExecuteType type, AbstractFramePtr evalInFrame, Value *result)
 {
     JS_ASSERT_IF(evalInFrame, type == EXECUTE_DEBUG);
     JS_ASSERT_IF(type == EXECUTE_GLOBAL, !scopeChainArg.is<ScopeObject>());
 #ifdef DEBUG
     if (thisv.isObject()) {
         RootedObject thisObj(cx, &thisv.toObject());
+        AutoSuppressGC nogc(cx);
         JS_ASSERT(GetOuterObject(cx, thisObj) == thisObj);
     }
 #endif
 
     if (script->isEmpty()) {
         if (result)
             result->setUndefined();
         return true;
--- a/js/xpconnect/src/event_impl_gen.conf.in
+++ b/js/xpconnect/src/event_impl_gen.conf.in
@@ -12,17 +12,16 @@ simple_events = [
     'StorageEvent',
     'MozSettingsEvent',
     'CustomEvent',
     'PageTransitionEvent',
     'DOMTransactionEvent',
     'PopStateEvent',
     'HashChangeEvent',
     'CloseEvent',
-    'MozContactChangeEvent',
     'DeviceOrientationEvent',
     'MozApplicationEvent',
     'SmartCardEvent',
     'StyleRuleChangeEvent',
     'StyleSheetChangeEvent',
     'StyleSheetApplicableStateChangeEvent',
 #ifdef MOZ_B2G_BT
     'BluetoothDeviceEvent',
--- a/media/webrtc/signaling/test/mediaconduit_unittests.cpp
+++ b/media/webrtc/signaling/test/mediaconduit_unittests.cpp
@@ -744,17 +744,17 @@ TEST_F(TransportConduitTest, TestVideoCo
   TestVideoConduitCodecAPI();
  }
 
 }  // end namespace
 
 int main(int argc, char **argv)
 {
   // This test can cause intermittent oranges on the builders
-  CHECK_ENVIRONMENT_FLAG("MOZ_WEBRTC_TESTS")
+  CHECK_ENVIRONMENT_FLAG("MOZ_WEBRTC_MEDIACONDUIT_TESTS")
 
   test_utils = new MtransportTestUtils();
   ::testing::InitGoogleTest(&argc, argv);
   int rv = RUN_ALL_TESTS();
   delete test_utils;
   return rv;
 }