Merge mozilla-central to autoland a=merge on a CLOSED TREE
authorCoroiu Cristina <ccoroiu@mozilla.com>
Thu, 10 Jan 2019 23:45:07 +0200
changeset 453351 4049f219ced182cfa21194559b2dd17e48312af3
parent 453350 b27229f70e017818a9f8cf5ef8cf476e4a006c0f (current diff)
parent 453278 ed68c008e5d8db0940a1fbc31bfc24efccba6c26 (diff)
child 453352 84a19f32185f609eec44c76af271138182edc4e7
push id35352
push userdvarga@mozilla.com
push dateFri, 11 Jan 2019 04:12:48 +0000
treeherdermozilla-central@65326bd78f83 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone66.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 mozilla-central to autoland a=merge on a CLOSED TREE
layout/base/PresShell.cpp
layout/base/nsIPresShell.h
layout/base/nsLayoutUtils.cpp
testing/web-platform/meta/css/css-scroll-anchoring/abspos-containing-block-outside-scroller.html.ini
testing/web-platform/meta/css/css-scroll-anchoring/abspos-contributes-to-static-parent-bounds.html.ini
testing/web-platform/meta/css/css-scroll-anchoring/ancestor-change-heuristic.html.ini
testing/web-platform/meta/css/css-scroll-anchoring/anchor-updates-after-explicit-scroll.html.ini
testing/web-platform/meta/css/css-scroll-anchoring/anchoring-with-bounds-clamping-div.html.ini
testing/web-platform/meta/css/css-scroll-anchoring/anchoring-with-bounds-clamping.html.ini
testing/web-platform/meta/css/css-scroll-anchoring/anonymous-block-box.html.ini
testing/web-platform/meta/css/css-scroll-anchoring/basic.html.ini
testing/web-platform/meta/css/css-scroll-anchoring/clipped-scrollers-skipped.html.ini
testing/web-platform/meta/css/css-scroll-anchoring/descend-into-container-with-float.html.ini
testing/web-platform/meta/css/css-scroll-anchoring/descend-into-container-with-overflow.html.ini
testing/web-platform/meta/css/css-scroll-anchoring/exclude-fixed-position.html.ini
testing/web-platform/meta/css/css-scroll-anchoring/inline-block.html.ini
testing/web-platform/meta/css/css-scroll-anchoring/opt-out.html.ini
testing/web-platform/meta/css/css-scroll-anchoring/position-change-heuristic.html.ini
testing/web-platform/meta/css/css-scroll-anchoring/subtree-exclusion.html.ini
testing/web-platform/meta/css/css-scroll-anchoring/wrapped-text.html.ini
testing/web-platform/mozilla/meta/__dir__.ini
toolkit/xre/nsAppRunner.cpp
--- a/browser/components/resistfingerprinting/test/browser/browser.ini
+++ b/browser/components/resistfingerprinting/test/browser/browser.ini
@@ -1,11 +1,12 @@
 [DEFAULT]
 tags = resistfingerprinting
 support-files =
+  browser_navigator_header.sjs
   file_dummy.html
   file_keyBoardEvent.sjs
   file_navigator.html
   file_navigatorWorker.js
   file_workerNetInfo.js
   file_workerPerformance.js
   head.js
 
--- a/browser/components/resistfingerprinting/test/browser/browser_navigator.js
+++ b/browser/components/resistfingerprinting/test/browser/browser_navigator.js
@@ -6,17 +6,18 @@
 const CC = Components.Constructor;
 
 ChromeUtils.defineModuleGetter(this, "AppConstants",
   "resource://gre/modules/AppConstants.jsm");
 
 const TEST_PATH = "http://example.net/browser/browser/" +
                   "components/resistfingerprinting/test/browser/";
 
-var spoofedUserAgent;
+var spoofedUserAgentNavigator;
+var spoofedUserAgentHeader;
 
 const SPOOFED_APPNAME = "Netscape";
 
 const SPOOFED_APPVERSION = {
   linux: "5.0 (X11)",
   win: "5.0 (Windows)",
   macosx: "5.0 (Macintosh)",
   android: "5.0 (Android 6.0)",
@@ -31,46 +32,67 @@ const SPOOFED_PLATFORM = {
 };
 const SPOOFED_OSCPU = {
   linux: "Linux x86_64",
   win: "Windows NT 6.1; Win64; x64",
   macosx: "Intel Mac OS X 10.13",
   android: "Linux armv7l",
   other: "Linux x86_64",
 };
-const SPOOFED_UA_OS = {
+const SPOOFED_UA_NAVIGATOR_OS = {
   linux: "X11; Linux x86_64",
   win: "Windows NT 6.1; Win64; x64",
   macosx: "Macintosh; Intel Mac OS X 10.13",
   android: "Android 6.0; Mobile",
   other: "X11; Linux x86_64",
 };
+const SPOOFED_UA_HTTPHEADER_OS = {
+  linux: "Windows NT 6.1",
+  win: "Windows NT 6.1",
+  macosx: "Windows NT 6.1",
+  android: "Android 6.0; Mobile",
+  other: "Windows NT 6.1",
+};
 const SPOOFED_HW_CONCURRENCY = 2;
 
 const CONST_APPCODENAME = "Mozilla";
 const CONST_PRODUCT     = "Gecko";
 const CONST_PRODUCTSUB  = "20100101";
 const CONST_VENDOR      = "";
 const CONST_VENDORSUB   = "";
 
+async function testUserAgentHeader() {
+  const BASE = "http://mochi.test:8888/browser/browser/components/resistfingerprinting/test/browser/";
+  const TEST_TARGET_URL = `${BASE}browser_navigator_header.sjs?`;
+  let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_TARGET_URL);
+
+  let result = await ContentTask.spawn(tab.linkedBrowser, null, function() {
+    return content.document.body.textContent;
+  });
+
+  is(result, spoofedUserAgentHeader, "User Agent HTTP Header is correctly spoofed.");
+
+  BrowserTestUtils.removeTab(tab);
+}
+
 async function testNavigator() {
   // Open a tab to collect result.
   let tab = await BrowserTestUtils.openNewForegroundTab(
     gBrowser, TEST_PATH + "file_navigator.html");
 
   let result = await ContentTask.spawn(tab.linkedBrowser, null, function() {
     return content.document.getElementById("result").innerHTML;
   });
 
   result = JSON.parse(result);
 
   is(result.appName, SPOOFED_APPNAME, "Navigator.appName is correctly spoofed.");
   is(result.appVersion, SPOOFED_APPVERSION[AppConstants.platform], "Navigator.appVersion is correctly spoofed.");
   is(result.platform, SPOOFED_PLATFORM[AppConstants.platform], "Navigator.platform is correctly spoofed.");
-  is(result.userAgent, spoofedUserAgent, "Navigator.userAgent is correctly spoofed.");
+  is(result.userAgent, spoofedUserAgentNavigator, "Navigator.userAgent is correctly spoofed.");
   is(result.mimeTypesLength, 0, "Navigator.mimeTypes has a length of 0.");
   is(result.pluginsLength, 0, "Navigator.plugins has a length of 0.");
   is(result.oscpu, SPOOFED_OSCPU[AppConstants.platform], "Navigator.oscpu is correctly spoofed.");
   is(result.hardwareConcurrency, SPOOFED_HW_CONCURRENCY, "Navigator.hardwareConcurrency is correctly spoofed.");
 
   is(result.appCodeName, CONST_APPCODENAME, "Navigator.appCodeName reports correct constant value.");
   is(result.product, CONST_PRODUCT, "Navigator.product reports correct constant value.");
   is(result.productSub, CONST_PRODUCTSUB, "Navigator.productSub reports correct constant value.");
@@ -97,39 +119,44 @@ async function testWorkerNavigator() {
     return res;
   });
 
   result = JSON.parse(result);
 
   is(result.appName, SPOOFED_APPNAME, "Navigator.appName is correctly spoofed.");
   is(result.appVersion, SPOOFED_APPVERSION[AppConstants.platform], "Navigator.appVersion is correctly spoofed.");
   is(result.platform, SPOOFED_PLATFORM[AppConstants.platform], "Navigator.platform is correctly spoofed.");
-  is(result.userAgent, spoofedUserAgent, "Navigator.userAgent is correctly spoofed.");
+  is(result.userAgent, spoofedUserAgentNavigator, "Navigator.userAgent is correctly spoofed.");
   is(result.hardwareConcurrency, SPOOFED_HW_CONCURRENCY, "Navigator.hardwareConcurrency is correctly spoofed.");
 
   is(result.appCodeName, CONST_APPCODENAME, "Navigator.appCodeName reports correct constant value.");
   is(result.product, CONST_PRODUCT, "Navigator.product reports correct constant value.");
 
   BrowserTestUtils.removeTab(tab);
 }
 
 add_task(async function setup() {
   await SpecialPowers.pushPrefEnv({"set":
     [["privacy.resistFingerprinting", true]],
   });
 
   let appVersion = parseInt(Services.appinfo.version);
   let spoofedVersion = appVersion - ((appVersion - 4) % 7);
-  spoofedUserAgent = `Mozilla/5.0 (${SPOOFED_UA_OS[AppConstants.platform]}; rv:${spoofedVersion}.0) Gecko/20100101 Firefox/${spoofedVersion}.0`;
+  spoofedUserAgentNavigator = `Mozilla/5.0 (${SPOOFED_UA_NAVIGATOR_OS[AppConstants.platform]}; rv:${spoofedVersion}.0) Gecko/20100101 Firefox/${spoofedVersion}.0`;
+  spoofedUserAgentHeader = `Mozilla/5.0 (${SPOOFED_UA_HTTPHEADER_OS[AppConstants.platform]}; rv:${spoofedVersion}.0) Gecko/20100101 Firefox/${spoofedVersion}.0`;
 });
 
 add_task(async function runNavigatorTest() {
   await testNavigator();
 });
 
+add_task(async function runHTTPHeaderTest() {
+  await testUserAgentHeader();
+});
+
 add_task(async function runWorkerNavigatorTest() {
   await testWorkerNavigator();
 });
 
 // This tests that 'general.*.override' should not override spoofed values.
 add_task(async function runOverrideTest() {
   await SpecialPowers.pushPrefEnv({"set":
     [
@@ -139,9 +166,11 @@ add_task(async function runOverrideTest(
       ["general.useragent.override", "userAgent overridden"],
       ["general.oscpu.override", "oscpu overridden"],
     ],
   });
 
   await testNavigator();
 
   await testWorkerNavigator();
+
+  await testUserAgentHeader();
 });
new file mode 100644
--- /dev/null
+++ b/browser/components/resistfingerprinting/test/browser/browser_navigator_header.sjs
@@ -0,0 +1,11 @@
+"use strict";
+
+function handleRequest(request, response) {
+  response.setHeader("Content-Type", "text/plain; charset=UTF-8", false);
+
+  if (request.hasHeader("user-agent")) {
+    response.write(request.getHeader("user-agent"));
+  } else {
+    response.write("no user agent header");
+  }
+}
\ No newline at end of file
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -1678,16 +1678,29 @@ nsresult Navigator::GetUserAgent(nsPIDOM
         mozilla::Preferences::GetString("general.useragent.override", override);
 
     if (NS_SUCCEEDED(rv)) {
       aUserAgent = override;
       return NS_OK;
     }
   }
 
+  // When the caller is content and 'privacy.resistFingerprinting' is true,
+  // return a spoofed userAgent which reveals the platform but not the
+  // specific OS version, etc.
+  if (!aIsCallerChrome && nsContentUtils::ShouldResistFingerprinting()) {
+    nsAutoCString spoofedUA;
+    nsresult rv = nsRFPService::GetSpoofedUserAgent(spoofedUA, false);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+    CopyASCIItoUTF16(spoofedUA, aUserAgent);
+    return NS_OK;
+  }
+
   nsresult rv;
   nsCOMPtr<nsIHttpProtocolHandler> service(
       do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   nsAutoCString ua;
--- a/ipc/glue/CrashReporterHost.cpp
+++ b/ipc/glue/CrashReporterHost.cpp
@@ -8,16 +8,44 @@
 #include "CrashReporterMetadataShmem.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/recordreplay/ParentIPC.h"
 #include "mozilla/Sprintf.h"
 #include "mozilla/SyncRunnable.h"
 #include "mozilla/Telemetry.h"
 #include "nsIAsyncShutdown.h"
 #include "nsICrashService.h"
+#include "nsXULAppAPI.h"
+
+// Consistency checking for nsICrashService constants.  We depend on the
+// equivalence between nsICrashService values and GeckoProcessType values
+// in the code below.  Making them equal also ensures that if new process
+// types are added, people will know they may need to add crash reporting
+// support in various places because compilation errors will be triggered here.
+static_assert(nsICrashService::PROCESS_TYPE_MAIN == (int)GeckoProcessType_Default,
+              "GeckoProcessType enum is out of sync with nsICrashService!");
+static_assert(nsICrashService::PROCESS_TYPE_PLUGIN == (int)GeckoProcessType_Plugin,
+              "GeckoProcessType enum is out of sync with nsICrashService!");
+static_assert(nsICrashService::PROCESS_TYPE_CONTENT == (int)GeckoProcessType_Content,
+              "GeckoProcessType enum is out of sync with nsICrashService!");
+static_assert(nsICrashService::PROCESS_TYPE_IPDLUNITTEST == (int)GeckoProcessType_IPDLUnitTest,
+              "GeckoProcessType enum is out of sync with nsICrashService!");
+static_assert(nsICrashService::PROCESS_TYPE_GMPLUGIN == (int)GeckoProcessType_GMPlugin,
+              "GeckoProcessType enum is out of sync with nsICrashService!");
+static_assert(nsICrashService::PROCESS_TYPE_GPU == (int)GeckoProcessType_GPU,
+              "GeckoProcessType enum is out of sync with nsICrashService!");
+static_assert(nsICrashService::PROCESS_TYPE_VR == (int)GeckoProcessType_VR,
+              "GeckoProcessType enum is out of sync with nsICrashService!");
+static_assert(nsICrashService::PROCESS_TYPE_RDD == (int)GeckoProcessType_RDD,
+              "GeckoProcessType enum is out of sync with nsICrashService!");
+// Add new static asserts here if you add more process types.
+// Update this static assert as well.
+static_assert(nsICrashService::PROCESS_TYPE_RDD + 1 == (int)GeckoProcessType_End,
+              "GeckoProcessType enum is out of sync with nsICrashService!");
+
 
 namespace mozilla {
 namespace ipc {
 
 CrashReporterHost::CrashReporterHost(GeckoProcessType aProcessType,
                                      const Shmem& aShmem,
                                      CrashReporter::ThreadId aThreadId)
     : mProcessType(aProcessType),
@@ -72,33 +100,34 @@ int32_t CrashReporterHost::GetCrashType(
 
 bool CrashReporterHost::FinalizeCrashReport() {
   MOZ_ASSERT(!mFinalized);
   MOZ_ASSERT(HasMinidump());
 
   CrashReporter::AnnotationTable annotations;
 
   nsAutoCString type;
-  switch (mProcessType) {
-    case GeckoProcessType_Content:
-      type = NS_LITERAL_CSTRING("content");
-      break;
-    case GeckoProcessType_Plugin:
-    case GeckoProcessType_GMPlugin:
-      type = NS_LITERAL_CSTRING("plugin");
-      break;
-    case GeckoProcessType_GPU:
-      type = NS_LITERAL_CSTRING("gpu");
-      break;
-    case GeckoProcessType_RDD:
-      type = NS_LITERAL_CSTRING("rdd");
-      break;
+  // The gecko media plugin and normal plugin processes are lumped together
+  // as a historical artifact.
+  if (mProcessType == GeckoProcessType_GMPlugin) {
+    type.AssignLiteral("plugin");
+  } else {
+    // This check will pick up some cases that will never happen (e.g. IPDL
+    // unit tests), but that's OK.
+    switch (mProcessType) {
+#define GECKO_PROCESS_TYPE(enum_name, string_name, xre_name) \
+      case GeckoProcessType_##enum_name: \
+        type.AssignLiteral(string_name); \
+        break;
+#include "mozilla/GeckoProcessTypes.h"
+#undef GECKO_PROCESS_TYPE
     default:
       NS_ERROR("unknown process type");
       break;
+    }
   }
   annotations[CrashReporter::Annotation::ProcessType] = type;
 
   char startTime[32];
   SprintfLiteral(startTime, "%lld", static_cast<long long>(mStartTime));
   annotations[CrashReporter::Annotation::StartupTime] =
       nsDependentCString(startTime);
 
@@ -137,43 +166,42 @@ bool CrashReporterHost::FinalizeCrashRep
   if (!crashService) {
     return;
   }
 
   int32_t processType;
   nsCString telemetryKey;
 
   switch (aProcessType) {
-    case GeckoProcessType_Content:
-      processType = nsICrashService::PROCESS_TYPE_CONTENT;
-      telemetryKey.AssignLiteral("content");
-      break;
-    case GeckoProcessType_Plugin:
-      processType = nsICrashService::PROCESS_TYPE_PLUGIN;
-      if (aCrashType == nsICrashService::CRASH_TYPE_HANG) {
-        telemetryKey.AssignLiteral("pluginhang");
-      } else {
-        telemetryKey.AssignLiteral("plugin");
-      }
-      break;
-    case GeckoProcessType_GMPlugin:
-      processType = nsICrashService::PROCESS_TYPE_GMPLUGIN;
-      telemetryKey.AssignLiteral("gmplugin");
-      break;
-    case GeckoProcessType_GPU:
-      processType = nsICrashService::PROCESS_TYPE_GPU;
-      telemetryKey.AssignLiteral("gpu");
-      break;
-    case GeckoProcessType_RDD:
-      processType = nsICrashService::PROCESS_TYPE_RDD;
-      telemetryKey.AssignLiteral("rdd");
-      break;
-    default:
+    case GeckoProcessType_IPDLUnitTest:
+    case GeckoProcessType_Default:
       NS_ERROR("unknown process type");
       return;
+    default:
+      processType = (int)aProcessType;
+      break;
+  }
+
+  if (aProcessType == GeckoProcessType_Plugin &&
+      aCrashType == nsICrashService::CRASH_TYPE_HANG) {
+    telemetryKey.AssignLiteral("pluginhang");
+  } else {
+    switch (aProcessType) {
+#define GECKO_PROCESS_TYPE(enum_name, string_name, xre_name) \
+      case GeckoProcessType_##enum_name:                     \
+        telemetryKey.AssignLiteral(string_name);             \
+        break;
+#include "mozilla/GeckoProcessTypes.h"
+#undef GECKO_PROCESS_TYPE
+      // We can't really hit this, thanks to the above switch, but having it here
+      // will placate the compiler.
+      default:
+        NS_ERROR("unknown process type");
+        return;
+    }
   }
 
   RefPtr<Promise> promise;
   crashService->AddCrash(processType, aCrashType, aChildDumpID,
                          getter_AddRefs(promise));
   Telemetry::Accumulate(Telemetry::SUBPROCESS_CRASHES_WITH_DUMP, telemetryKey,
                         1);
 }
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/typedarray/bug1518764.js
@@ -0,0 +1,8 @@
+// |jit-test| error:dead object
+
+var g = newGlobal();
+var ta = new g.Int32Array(1);
+Int32Array.prototype.filter.call(ta, function() {
+    nukeAllCCWs();
+    return true;
+});
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -12682,28 +12682,18 @@ void CodeGenerator::visitGuardToClass(LG
   Register temp = ToRegister(ins->temp());
 
   Label notEqual;
 
   masm.branchTestObjClass(Assembler::NotEqual, lhs, ins->mir()->getClass(),
                           temp, output, &notEqual);
   masm.mov(lhs, output);
 
-  if (ins->mir()->type() == MIRType::Object) {
-    // Can't return null-return here, so bail
-    bailoutFrom(&notEqual, ins->snapshot());
-  } else {
-    Label done;
-    masm.jump(&done);
-
-    masm.bind(&notEqual);
-    masm.mov(ImmPtr(0), output);
-
-    masm.bind(&done);
-  }
+  // Can't return null-return here, so bail.
+  bailoutFrom(&notEqual, ins->snapshot());
 }
 
 typedef JSString* (*ObjectClassToStringFn)(JSContext*, HandleObject);
 static const VMFunction ObjectClassToStringInfo =
     FunctionInfo<ObjectClassToStringFn>(js::ObjectClassToString,
                                         "ObjectClassToString");
 
 void CodeGenerator::visitObjectClassToString(LObjectClassToString* lir) {
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -4201,18 +4201,17 @@ void LIRGenerator::visitIsObject(MIsObje
 void LIRGenerator::visitHasClass(MHasClass* ins) {
   MOZ_ASSERT(ins->object()->type() == MIRType::Object);
   MOZ_ASSERT(ins->type() == MIRType::Boolean);
   define(new (alloc()) LHasClass(useRegister(ins->object())), ins);
 }
 
 void LIRGenerator::visitGuardToClass(MGuardToClass* ins) {
   MOZ_ASSERT(ins->object()->type() == MIRType::Object);
-  MOZ_ASSERT(ins->type() == MIRType::ObjectOrNull ||
-             ins->type() == MIRType::Object);
+  MOZ_ASSERT(ins->type() == MIRType::Object);
   LGuardToClass* lir =
       new (alloc()) LGuardToClass(useRegister(ins->object()), temp());
   assignSnapshot(lir, Bailout_TypeBarrierO);
   define(lir, ins);
 }
 
 void LIRGenerator::visitObjectClassToString(MObjectClassToString* ins) {
   MOZ_ASSERT(ins->object()->type() == MIRType::Object);
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -2801,30 +2801,29 @@ IonBuilder::InliningResult IonBuilder::i
                                                           const Class* clasp) {
   MOZ_ASSERT(!callInfo.constructing());
   MOZ_ASSERT(callInfo.argc() == 1);
 
   if (callInfo.getArg(0)->type() != MIRType::Object) {
     return InliningStatus_NotInlined;
   }
 
-  if (getInlineReturnType() != MIRType::ObjectOrNull &&
-      getInlineReturnType() != MIRType::Object) {
+  if (getInlineReturnType() != MIRType::Object) {
     return InliningStatus_NotInlined;
   }
 
   TemporaryTypeSet* types = callInfo.getArg(0)->resultTypeSet();
   const Class* knownClass =
       types ? types->getKnownClass(constraints()) : nullptr;
 
   if (knownClass && knownClass == clasp) {
     current->push(callInfo.getArg(0));
   } else {
-    MGuardToClass* guardToClass = MGuardToClass::New(
-        alloc(), callInfo.getArg(0), clasp, getInlineReturnType());
+    MGuardToClass* guardToClass =
+        MGuardToClass::New(alloc(), callInfo.getArg(0), clasp);
     current->add(guardToClass);
     current->push(guardToClass);
   }
 
   callInfo.setImplicitlyUsedUnchecked();
   return InliningStatus_Inlined;
 }
 
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -10722,30 +10722,25 @@ class MHasClass : public MUnaryInstructi
     return congruentIfOperandsEqual(ins);
   }
 };
 
 class MGuardToClass : public MUnaryInstruction,
                       public SingleObjectPolicy::Data {
   const Class* class_;
 
-  MGuardToClass(MDefinition* object, const Class* clasp, MIRType resultType)
+  MGuardToClass(MDefinition* object, const Class* clasp)
       : MUnaryInstruction(classOpcode, object), class_(clasp) {
-    MOZ_ASSERT(object->type() == MIRType::Object ||
-               (object->type() == MIRType::Value &&
-                object->mightBeType(MIRType::Object)));
-    MOZ_ASSERT(resultType == MIRType::Object ||
-               resultType == MIRType::ObjectOrNull);
-    setResultType(resultType);
-    setMovable();
-    if (resultType == MIRType::Object) {
-      // We will bail out if the class type is incorrect,
-      // so we need to ensure we don't eliminate this instruction
-      setGuard();
-    }
+    MOZ_ASSERT(object->type() == MIRType::Object);
+    setResultType(MIRType::Object);
+    setMovable();
+
+    // We will bail out if the class type is incorrect, so we need to ensure we
+    // don't eliminate this instruction
+    setGuard();
   }
 
  public:
   INSTRUCTION_HEADER(GuardToClass)
   TRIVIAL_NEW_WRAPPERS
   NAMED_OPERANDS((0, object))
 
   const Class* getClass() const { return class_; }
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -53,16 +53,17 @@
 #include "vm/Realm.h"
 #include "vm/RegExpObject.h"
 #include "vm/StringType.h"
 #include "vm/TypedArrayObject.h"
 #include "vm/WrapperObject.h"
 
 #include "gc/PrivateIterators-inl.h"
 #include "vm/BooleanObject-inl.h"
+#include "vm/Compartment-inl.h"
 #include "vm/JSAtom-inl.h"
 #include "vm/JSFunction-inl.h"
 #include "vm/JSObject-inl.h"
 #include "vm/JSScript-inl.h"
 #include "vm/NativeObject-inl.h"
 #include "vm/NumberObject-inl.h"
 #include "vm/StringObject-inl.h"
 
@@ -2102,19 +2103,20 @@ static bool intrinsic_IsConstructing(JSC
 }
 
 static bool intrinsic_ConstructorForTypedArray(JSContext* cx, unsigned argc,
                                                Value* vp) {
   CallArgs args = CallArgsFromVp(argc, vp);
   MOZ_ASSERT(args.length() == 1);
   MOZ_ASSERT(args[0].isObject());
 
-  RootedObject object(cx, &args[0].toObject());
-  object = CheckedUnwrap(object);
-  MOZ_ASSERT(object->is<TypedArrayObject>());
+  auto* object = UnwrapAndDowncastValue<TypedArrayObject>(cx, args[0]);
+  if (!object) {
+    return false;
+  }
 
   JSProtoKey protoKey = StandardProtoKeyOrNull(object);
   MOZ_ASSERT(protoKey);
 
   // While it may seem like an invariant that in any compartment,
   // seeing a typed array object implies that the TypedArray constructor
   // for that type is initialized on the compartment's global, this is not
   // the case. When we construct a typed array given a cross-compartment
--- a/modules/libpref/init/StaticPrefList.h
+++ b/modules/libpref/init/StaticPrefList.h
@@ -1780,28 +1780,40 @@ VARCACHE_PREF(
 // Annotate channels based on the tracking protection list in all modes
 VARCACHE_PREF(
   "privacy.trackingprotection.annotate_channels",
    privacy_trackingprotection_annotate_channels,
   bool, true
 )
 
 // Block 3rd party fingerprinting resources.
+#ifdef NIGHTLY_BUILD
+# define PREF_VALUE true
+#else
+# define PREF_VALUE false
+#endif
 VARCACHE_PREF(
   "privacy.trackingprotection.fingerprinting.enabled",
    privacy_trackingprotection_fingerprinting_enabled,
-  bool, true
+  bool, PREF_VALUE
 )
+#undef PREF_VALUE
 
 // Block 3rd party cryptomining resources.
+#ifdef NIGHTLY_BUILD
+# define PREF_VALUE true
+#else
+# define PREF_VALUE false
+#endif
 VARCACHE_PREF(
   "privacy.trackingprotection.cryptomining.enabled",
    privacy_trackingprotection_cryptomining_enabled,
-  bool, true
+  bool, PREF_VALUE
 )
+#undef PREF_VALUE
 
 // Lower the priority of network loads for resources on the tracking protection
 // list.  Note that this requires the
 // privacy.trackingprotection.annotate_channels pref to be on in order to have
 // any effect.
 #ifdef NIGHTLY_BUILD
 # define PREF_VALUE true
 #else
--- a/netwerk/protocol/http/nsHttpHandler.cpp
+++ b/netwerk/protocol/http/nsHttpHandler.cpp
@@ -493,17 +493,17 @@ nsresult nsHttpHandler::Init() {
     }
     appInfo->GetVersion(mAppVersion);
     mAppName.StripChars(R"( ()<>@,;:\"/[]?={})");
   } else {
     mAppVersion.AssignLiteral(MOZ_APP_UA_VERSION);
   }
 
   // Generating the spoofed User Agent for fingerprinting resistance.
-  rv = nsRFPService::GetSpoofedUserAgent(mSpoofedUserAgent);
+  rv = nsRFPService::GetSpoofedUserAgent(mSpoofedUserAgent, true);
   if (NS_FAILED(rv)) {
     // Empty mSpoofedUserAgent to make sure the unsuccessful spoofed UA string
     // will not be used anywhere.
     mSpoofedUserAgent.Truncate();
   }
 
   mSessionStartTime = NowInSeconds();
   mHandlerActive = true;
--- a/testing/mochitest/mochitest_options.py
+++ b/testing/mochitest/mochitest_options.py
@@ -593,19 +593,19 @@ class MochitestArguments(ArgumentContain
         [["--verify-max-time"],
          {"type": int,
           "default": 3600,
           "help": "Maximum time, in seconds, to run in --verify mode.",
           }],
     ]
 
     defaults = {
-        # Bug 1065098 - The geckomediaplugin process fails to produce a leak
+        # Bug 1065098 - The gmplugin process fails to produce a leak
         # log for some reason.
-        'ignoreMissingLeaks': ["geckomediaplugin"],
+        'ignoreMissingLeaks': ["gmplugin"],
         'extensionsToExclude': ['specialpowers'],
         # Set server information on the args object
         'webServer': '127.0.0.1',
         'httpPort': DEFAULT_PORTS['http'],
         'sslPort': DEFAULT_PORTS['https'],
         'webSocketPort': '9988',
         # The default websocket port is incorrect in mozprofile; it is
         # set to the SSL proxy setting. See:
@@ -820,17 +820,17 @@ class MochitestArguments(ArgumentContain
 
         if options.nested_oop:
             options.e10s = True
 
         options.leakThresholds = {
             "default": options.defaultLeakThreshold,
             "tab": options.defaultLeakThreshold,
             # GMP rarely gets a log, but when it does, it leaks a little.
-            "geckomediaplugin": 20000,
+            "gmplugin": 20000,
             "rdd": 400,
         }
 
         # See the dependencies of bug 1401764.
         if mozinfo.isWin:
             options.leakThresholds["tab"] = 1000
 
         # XXX We can't normalize test_paths in the non build_obj case here,
--- a/testing/mozbase/mozleak/mozleak/leaklog.py
+++ b/testing/mozbase/mozleak/mozleak/leaklog.py
@@ -159,17 +159,17 @@ def process_leak_log(leak_log_file, leak
     log.info("leakcheck | Processing log file %s%s" %
              (leakLogFile, (" for scope %s" % scope) if scope is not None else ""))
 
     leakThresholds = leak_thresholds or {}
     ignoreMissingLeaks = ignore_missing_leaks or []
 
     # This list is based on kGeckoProcessTypeString. ipdlunittest processes likely
     # are not going to produce leak logs we will ever see.
-    knownProcessTypes = ["default", "plugin", "tab", "geckomediaplugin", "gpu", "rdd"]
+    knownProcessTypes = ["default", "plugin", "tab", "gmplugin", "gpu", "rdd"]
 
     for processType in knownProcessTypes:
         log.info("TEST-INFO | leakcheck | %s process: leak threshold set at %d bytes"
                  % (processType, leakThresholds.get(processType, 0)))
 
     for processType in leakThresholds:
         if processType not in knownProcessTypes:
             log.error("TEST-UNEXPECTED-FAIL | leakcheck | "
--- a/testing/web-platform/meta/__dir__.ini
+++ b/testing/web-platform/meta/__dir__.ini
@@ -1,6 +1,6 @@
 lsan-allowed: [js_pod_malloc, js_pod_calloc, js_pod_realloc, js_arena_calloc,js_pod_arena_calloc, maybe_pod_calloc, pod_calloc, make_zeroed_pod_array, js_arena_malloc]
 leak-threshold:
-  if webrender: [tab:10000, gpu: 10000, geckomediaplugin:20000, default:16000]
-  if os == "mac": [tab:10000, geckomediaplugin:20000, default:2000, rdd:400]
-  [tab:10000, geckomediaplugin:20000, rdd:400]
+  if webrender: [tab:10000, gpu: 10000, gmplugin:20000, default:16000]
+  if os == "mac": [tab:10000, gmplugin:20000, default:2000, rdd:400]
+  [tab:10000, gmplugin:20000, rdd:400]
 
--- a/testing/web-platform/mozilla/meta/__dir__.ini
+++ b/testing/web-platform/mozilla/meta/__dir__.ini
@@ -1,5 +1,5 @@
 leak-threshold:
-  if webrender: [tab:10000, geckomediaplugin:20000, default:16000]
-  if os == "mac": [tab:10000, geckomediaplugin:20000, default:2000, rdd:400]
-  [tab:10000, geckomediaplugin:20000, rdd:400]
+  if webrender: [tab:10000, gmplugin:20000, default:16000]
+  if os == "mac": [tab:10000, gmplugin:20000, default:2000, rdd:400]
+  [tab:10000, gmplugin:20000, rdd:400]
 
--- a/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/firefox.py
+++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/firefox.py
@@ -353,17 +353,17 @@ class FirefoxBrowser(Browser):
     def process_leaks(self):
         self.logger.info("PROCESS LEAKS %s" % self.leak_report_file)
         if self.lsan_handler:
             self.lsan_handler.process()
         if self.leak_report_file is not None:
             mozleak.process_leak_log(
                 self.leak_report_file,
                 leak_thresholds=self.mozleak_thresholds,
-                ignore_missing_leaks=["geckomediaplugin"],
+                ignore_missing_leaks=["gmplugin"],
                 log=self.logger,
                 stack_fixer=self.stack_fixer,
                 scope=self.group_metadata.get("scope"),
                 allowed=self.mozleak_allowed
             )
 
     def pid(self):
         if self.runner.process_handler is None:
--- a/toolkit/components/crashes/CrashService.js
+++ b/toolkit/components/crashes/CrashService.js
@@ -177,16 +177,19 @@ CrashService.prototype = Object.freeze({
       processType = Services.crashmanager.PROCESS_TYPE_GMPLUGIN;
       break;
     case Ci.nsICrashService.PROCESS_TYPE_GPU:
       processType = Services.crashmanager.PROCESS_TYPE_GPU;
       break;
     case Ci.nsICrashService.PROCESS_TYPE_RDD:
       processType = Services.crashmanager.PROCESS_TYPE_RDD;
       break;
+    case Ci.nsICrashService.PROCESS_TYPE_IPDLUNITTEST:
+      // We'll never send crash reports for this type of process.
+      return;
     default:
       throw new Error("Unrecognized PROCESS_TYPE: " + processType);
     }
 
     let allThreads = false;
 
     switch (crashType) {
     case Ci.nsICrashService.CRASH_TYPE_CRASH:
--- a/toolkit/components/crashes/nsICrashService.idl
+++ b/toolkit/components/crashes/nsICrashService.idl
@@ -17,17 +17,20 @@ interface nsICrashService : nsISupports
    * @param id
    *        Crash ID. Likely a UUID.
    *
    * @return A promise that resolves after the crash has been stored
    */
   Promise addCrash(in long processType, in long crashType, in AString id);
 
   const long PROCESS_TYPE_MAIN = 0;
-  const long PROCESS_TYPE_CONTENT = 1;
-  const long PROCESS_TYPE_PLUGIN = 2;
-  const long PROCESS_TYPE_GMPLUGIN = 3;
-  const long PROCESS_TYPE_GPU = 4;
-  const long PROCESS_TYPE_RDD = 5;
+  const long PROCESS_TYPE_PLUGIN = 1;
+  const long PROCESS_TYPE_CONTENT = 2;
+  const long PROCESS_TYPE_IPDLUNITTEST = 3;
+  const long PROCESS_TYPE_GMPLUGIN = 4;
+  const long PROCESS_TYPE_GPU = 5;
+  const long PROCESS_TYPE_VR = 6;
+  const long PROCESS_TYPE_RDD = 7;
+  // New process types should be added at the end of the above list.
 
   const long CRASH_TYPE_CRASH = 0;
   const long CRASH_TYPE_HANG = 1;
 };
--- a/toolkit/components/resistfingerprinting/nsRFPService.cpp
+++ b/toolkit/components/resistfingerprinting/nsRFPService.cpp
@@ -648,17 +648,18 @@ uint32_t nsRFPService::GetSpoofedPresent
   // Bound the dropped ratio from 0 to 100.
   uint32_t boundedDroppedRatio = min(sVideoDroppedRatio, 100u);
 
   return NSToIntFloor(time * sVideoFramesPerSec *
                       ((100 - boundedDroppedRatio) / 100.0));
 }
 
 /* static */
-nsresult nsRFPService::GetSpoofedUserAgent(nsACString& userAgent) {
+nsresult nsRFPService::GetSpoofedUserAgent(nsACString& userAgent,
+                                           bool isForHTTPHeader) {
   // This function generates the spoofed value of User Agent.
   // We spoof the values of the platform and Firefox version, which could be
   // used as fingerprinting sources to identify individuals.
   // Reference of the format of User Agent:
   // https://developer.mozilla.org/en-US/docs/Web/API/NavigatorID/userAgent
   // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent
 
   nsresult rv;
@@ -684,18 +685,19 @@ nsresult nsRFPService::GetSpoofedUserAge
                "Please udpate ESR version formula in nsRFPService.cpp");
   }
 
   // Starting from Firefox 10, Firefox ESR was released once every seven
   // Firefox releases, e.g. Firefox 10, 17, 24, 31, and so on.
   // Except we used 60 as an ESR instead of 59.
   // We infer the last and closest ESR version based on this rule.
   uint32_t spoofedVersion = firefoxVersion - ((firefoxVersion - 4) % 7);
+  const char* spoofedOS = isForHTTPHeader ? SPOOFED_HTTP_UA_OS : SPOOFED_UA_OS;
   userAgent.Assign(nsPrintfCString(
-      "Mozilla/5.0 (%s; rv:%d.0) Gecko/%s Firefox/%d.0", SPOOFED_UA_OS,
+      "Mozilla/5.0 (%s; rv:%d.0) Gecko/%s Firefox/%d.0", spoofedOS,
       spoofedVersion, LEGACY_UA_GECKO_TRAIL, spoofedVersion));
 
   return rv;
 }
 
 static const char* gCallbackPrefs[] = {
     RESIST_FINGERPRINTING_PREF, RFP_TIMER_PREF, RFP_TIMER_VALUE_PREF,
     RFP_JITTER_VALUE_PREF,      nullptr,
--- a/toolkit/components/resistfingerprinting/nsRFPService.h
+++ b/toolkit/components/resistfingerprinting/nsRFPService.h
@@ -46,16 +46,24 @@
 #endif
 
 #define SPOOFED_APPNAME "Netscape"
 #define LEGACY_BUILD_ID "20181001000000"
 #define LEGACY_UA_GECKO_TRAIL "20100101"
 
 #define SPOOFED_POINTER_INTERFACE MouseEvent_Binding::MOZ_SOURCE_MOUSE
 
+// For the HTTP User-Agent header, we use a simpler set of spoofed values
+// that do not reveal the specific desktop platform.
+#if defined(MOZ_WIDGET_ANDROID)
+#define SPOOFED_HTTP_UA_OS "Android 6.0; Mobile"
+#else
+#define SPOOFED_HTTP_UA_OS "Windows NT 6.1"
+#endif
+
 // Forward declare LRUCache, defined in nsRFPService.cpp
 class LRUCache;
 
 namespace mozilla {
 
 enum KeyboardLang { EN = 0x01 };
 
 #define RFP_KEYBOARD_LANG_STRING_EN "en"
@@ -172,17 +180,18 @@ class nsRFPService final : public nsIObs
   // depend on the video resolution.
   static uint32_t GetSpoofedTotalFrames(double aTime);
   static uint32_t GetSpoofedDroppedFrames(double aTime, uint32_t aWidth,
                                           uint32_t aHeight);
   static uint32_t GetSpoofedPresentedFrames(double aTime, uint32_t aWidth,
                                             uint32_t aHeight);
 
   // This method generates the spoofed value of User Agent.
-  static nsresult GetSpoofedUserAgent(nsACString& userAgent);
+  static nsresult GetSpoofedUserAgent(nsACString& userAgent,
+                                      bool isForHTTPHeader);
 
   /**
    * This method for getting spoofed modifier states for the given keyboard
    * event.
    *
    * @param aDoc           [in]  the owner's document for getting content
    *                             language.
    * @param aKeyboardEvent [in]  the keyboard event that needs to be spoofed.
--- a/toolkit/crashreporter/CrashAnnotations.yaml
+++ b/toolkit/crashreporter/CrashAnnotations.yaml
@@ -557,18 +557,18 @@ PluginName:
 PluginVersion:
   description: >
     Version of a plugin, only the process holding the plugin has this
     annotation.
   type: string
 
 ProcessType:
   description: >
-    Type of the process that crashed, can hold the values "content", "plugin",
-    "gpu" or "rdd" currently.
+    Type of the process that crashed, the possible values are defined in
+    GeckoProcessTypes.h.
   type: string
 
 ProductName:
   description: >
     Application name (e.g. Firefox).
   type: string
   ping: true
 
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -4923,41 +4923,26 @@ nsresult XRE_DeinitCommandLine() {
 
   return rv;
 }
 
 GeckoProcessType XRE_GetProcessType() {
   return mozilla::startup::sChildProcessType;
 }
 
-bool XRE_IsGPUProcess() { return XRE_GetProcessType() == GeckoProcessType_GPU; }
-
-bool XRE_IsRDDProcess() { return XRE_GetProcessType() == GeckoProcessType_RDD; }
-
-bool XRE_IsVRProcess() { return XRE_GetProcessType() == GeckoProcessType_VR; }
-
-/**
- * Returns true in the e10s parent process and in the main process when e10s
- * is disabled.
- */
-bool XRE_IsParentProcess() {
-  return XRE_GetProcessType() == GeckoProcessType_Default;
-}
-
 bool XRE_IsE10sParentProcess() {
   return XRE_IsParentProcess() && BrowserTabsRemoteAutostart();
 }
 
-bool XRE_IsContentProcess() {
-  return XRE_GetProcessType() == GeckoProcessType_Content;
-}
-
-bool XRE_IsPluginProcess() {
-  return XRE_GetProcessType() == GeckoProcessType_Plugin;
-}
+#define GECKO_PROCESS_TYPE(enum_name, string_name, xre_name)     \
+  bool XRE_Is##xre_name##Process() {                             \
+    return XRE_GetProcessType() == GeckoProcessType_##enum_name; \
+  }
+#include "mozilla/GeckoProcessTypes.h"
+#undef GECKO_PROCESS_TYPE
 
 bool XRE_UseNativeEventProcessing() {
 #ifdef XP_MACOSX
   if (XRE_IsRDDProcess()) {
     return false;
   }
 #endif
   if (XRE_IsContentProcess()) {
new file mode 100644
--- /dev/null
+++ b/xpcom/build/GeckoProcessTypes.h
@@ -0,0 +1,28 @@
+/* -*- 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/. */
+
+// GECKO_PROCESS_TYPE(enum-name, string-name, XRE_Is${NAME}Process)
+// Note that string-name is exposed to various things like telemetry
+// and the crash reporter, so it should not be changed casually.
+//
+// The values generated for the GeckoProcessType enum are dependent on
+// the ordering of the GECKO_PROCESS_TYPE invocations in this file, and
+// said values are exposed to things like telemetry as well, so please
+// do not reorder lines in this file.
+//
+// Please add new process types at the end of this list.
+GECKO_PROCESS_TYPE(Default, "default", Parent)
+GECKO_PROCESS_TYPE(Plugin, "plugin", Plugin)
+GECKO_PROCESS_TYPE(Content, "tab", Content)
+GECKO_PROCESS_TYPE(IPDLUnitTest, "ipdlunittest", IPDLUnitTest)
+// Gecko Media Plugin process.
+GECKO_PROCESS_TYPE(GMPlugin, "gmplugin", GMPlugin)
+// GPU and compositor process.
+GECKO_PROCESS_TYPE(GPU, "gpu", GPU)
+// VR process.
+GECKO_PROCESS_TYPE(VR, "vr", VR)
+// Remote Data Decoder process.
+GECKO_PROCESS_TYPE(RDD, "rdd", RDD)
--- a/xpcom/build/moz.build
+++ b/xpcom/build/moz.build
@@ -12,16 +12,17 @@ EXPORTS += [
     'XREChildData.h',
     'xrecore.h',
     'XREShellData.h',
 ]
 
 EXPORTS.mozilla += [
     '!Services.h',
     'FileLocation.h',
+    'GeckoProcessTypes.h',
     'IOInterposer.h',
     'LateWriteChecks.h',
     'Omnijar.h',
     'PoisonIOInterposer.h',
     'XPCOM.h',
     'XREAppData.h',
 ]
 
--- a/xpcom/build/nsXULAppAPI.h
+++ b/xpcom/build/nsXULAppAPI.h
@@ -360,35 +360,30 @@ XRE_API(void, XRE_TermEmbedding, ())
  *
  * @param aINIFile The INI file to parse
  * @param aAppData The nsXREAppData structure to fill.
  */
 XRE_API(nsresult, XRE_ParseAppData,
         (nsIFile * aINIFile, mozilla::XREAppData& aAppData))
 
 enum GeckoProcessType {
-  GeckoProcessType_Default = 0,
-
-  GeckoProcessType_Plugin,
-  GeckoProcessType_Content,
-
-  GeckoProcessType_IPDLUnitTest,
-
-  GeckoProcessType_GMPlugin,  // Gecko Media Plugin
-
-  GeckoProcessType_GPU,  // GPU and compositor process
-  GeckoProcessType_VR,   // VR process
-  GeckoProcessType_RDD,  // RDD (RemoteDataDecoder process)
+#define GECKO_PROCESS_TYPE(enum_name, string_name, xre_name) \
+  GeckoProcessType_##enum_name,
+#include "mozilla/GeckoProcessTypes.h"
+#undef GECKO_PROCESS_TYPE
   GeckoProcessType_End,
   GeckoProcessType_Invalid = GeckoProcessType_End
 };
 
 static const char* const kGeckoProcessTypeString[] = {
-    "default",          "plugin", "tab", "ipdlunittest",
-    "geckomediaplugin", "gpu",    "vr",  "rdd"};
+#define GECKO_PROCESS_TYPE(enum_name, string_name, xre_name) \
+  string_name,
+#include "mozilla/GeckoProcessTypes.h"
+#undef GECKO_PROCESS_TYPE
+};
 
 static_assert(MOZ_ARRAY_LENGTH(kGeckoProcessTypeString) == GeckoProcessType_End,
               "Array length mismatch");
 
 XRE_API(const char*, XRE_ChildProcessTypeToString,
         (GeckoProcessType aProcessType))
 
 #if defined(MOZ_WIDGET_ANDROID)
@@ -433,30 +428,26 @@ XRE_API(GeckoProcessType, XRE_GetProcess
 
 /**
  * Returns true when called in the e10s parent process.  Does *NOT* return true
  * when called in the main process if e10s is disabled.
  */
 XRE_API(bool, XRE_IsE10sParentProcess, ())
 
 /**
- * Returns true when called in the e10s parent process or called in the main
- * process when e10s is disabled.
+ * Defines XRE_IsParentProcess, XRE_IsContentProcess, etc.
+ *
+ * XRE_IsParentProcess is unique in that it returns true when called in
+ * the e10s parent process or called in the main process when e10s is
+ * disabled.
  */
-XRE_API(bool, XRE_IsParentProcess, ())
-
-XRE_API(bool, XRE_IsContentProcess, ())
-
-XRE_API(bool, XRE_IsGPUProcess, ())
-
-XRE_API(bool, XRE_IsRDDProcess, ())
-
-XRE_API(bool, XRE_IsVRProcess, ())
-
-XRE_API(bool, XRE_IsPluginProcess, ())
+#define GECKO_PROCESS_TYPE(enum_name, string_name, xre_name) \
+  XRE_API(bool, XRE_Is##xre_name##Process, ())
+#include "mozilla/GeckoProcessTypes.h"
+#undef GECKO_PROCESS_TYPE
 
 /**
  * Returns true if the appshell should run its own native event loop. Returns
  * false if we should rely solely on the Gecko event loop.
  */
 XRE_API(bool, XRE_UseNativeEventProcessing, ())
 
 typedef void (*MainFunction)(void* aData);
--- a/xpcom/threads/AbstractEventQueue.h
+++ b/xpcom/threads/AbstractEventQueue.h
@@ -59,16 +59,19 @@ class AbstractEventQueue {
   // Returns true if the queue is empty. Implies !HasReadyEvent().
   virtual bool IsEmpty(const MutexAutoLock& aProofOfLock) = 0;
 
   // Returns true if the queue is non-empty and if the event in front is ready
   // to run. Implies !IsEmpty(). This should return true iff GetEvent returns a
   // non-null value.
   virtual bool HasReadyEvent(const MutexAutoLock& aProofOfLock) = 0;
 
+  virtual bool HasPendingHighPriorityEvents(
+      const MutexAutoLock& aProofOfLock) = 0;
+
   // Returns the number of events in the queue.
   virtual size_t Count(const MutexAutoLock& aProofOfLock) const = 0;
 
   virtual void EnableInputEventPrioritization(
       const MutexAutoLock& aProofOfLock) = 0;
   virtual void FlushInputEventPrioritization(
       const MutexAutoLock& aProofOfLock) = 0;
   virtual void SuspendInputEventPrioritization(
--- a/xpcom/threads/EventQueue.h
+++ b/xpcom/threads/EventQueue.h
@@ -24,16 +24,20 @@ class EventQueue final : public Abstract
 
   void PutEvent(already_AddRefed<nsIRunnable>&& aEvent, EventPriority aPriority,
                 const MutexAutoLock& aProofOfLock) final;
   already_AddRefed<nsIRunnable> GetEvent(
       EventPriority* aPriority, const MutexAutoLock& aProofOfLock) final;
 
   bool IsEmpty(const MutexAutoLock& aProofOfLock) final;
   bool HasReadyEvent(const MutexAutoLock& aProofOfLock) final;
+  bool HasPendingHighPriorityEvents(const MutexAutoLock& aProofOfLock) final {
+    // EventQueue doesn't support any prioritization.
+    return false;
+  }
 
   size_t Count(const MutexAutoLock& aProofOfLock) const final;
   already_AddRefed<nsIRunnable> PeekEvent(const MutexAutoLock& aProofOfLock);
 
   void EnableInputEventPrioritization(const MutexAutoLock& aProofOfLock) final {
   }
   void FlushInputEventPrioritization(const MutexAutoLock& aProofOfLock) final {}
   void SuspendInputEventPrioritization(
--- a/xpcom/threads/LabeledEventQueue.h
+++ b/xpcom/threads/LabeledEventQueue.h
@@ -36,16 +36,20 @@ class LabeledEventQueue final : public A
   void PutEvent(already_AddRefed<nsIRunnable>&& aEvent, EventPriority aPriority,
                 const MutexAutoLock& aProofOfLock) final;
   already_AddRefed<nsIRunnable> GetEvent(
       EventPriority* aPriority, const MutexAutoLock& aProofOfLock) final;
 
   bool IsEmpty(const MutexAutoLock& aProofOfLock) final;
   size_t Count(const MutexAutoLock& aProofOfLock) const final;
   bool HasReadyEvent(const MutexAutoLock& aProofOfLock) final;
+  bool HasPendingHighPriorityEvents(const MutexAutoLock& aProofOfLock) final {
+    // LabeledEventQueue itself isn't prioritized.
+    return false;
+  }
 
   void EnableInputEventPrioritization(const MutexAutoLock& aProofOfLock) final {
   }
   void FlushInputEventPrioritization(const MutexAutoLock& aProofOfLock) final {}
   void SuspendInputEventPrioritization(
       const MutexAutoLock& aProofOfLock) final {}
   void ResumeInputEventPrioritization(const MutexAutoLock& aProofOfLock) final {
   }
--- a/xpcom/threads/LazyIdleThread.cpp
+++ b/xpcom/threads/LazyIdleThread.cpp
@@ -473,16 +473,24 @@ NS_IMETHODIMP
 LazyIdleThread::HasPendingEvents(bool* aHasPendingEvents) {
   // This is only supposed to be called from the thread itself so it's not
   // implemented here.
   MOZ_ASSERT_UNREACHABLE("Shouldn't ever call this!");
   return NS_ERROR_UNEXPECTED;
 }
 
 NS_IMETHODIMP
+LazyIdleThread::HasPendingHighPriorityEvents(bool* aHasPendingEvents) {
+  // This is only supposed to be called from the thread itself so it's not
+  // implemented here.
+  MOZ_ASSERT_UNREACHABLE("Shouldn't ever call this!");
+  return NS_ERROR_UNEXPECTED;
+}
+
+NS_IMETHODIMP
 LazyIdleThread::IdleDispatch(already_AddRefed<nsIRunnable> aEvent) {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
 LazyIdleThread::ProcessNextEvent(bool aMayWait, bool* aEventWasProcessed) {
   // This is only supposed to be called from the thread itself so it's not
   // implemented here.
--- a/xpcom/threads/PrioritizedEventQueue.cpp
+++ b/xpcom/threads/PrioritizedEventQueue.cpp
@@ -280,16 +280,22 @@ bool PrioritizedEventQueue<InnerQueueT>:
     mHasPendingEventsPromisedIdleEvent = true;
     return true;
   }
 
   return false;
 }
 
 template <class InnerQueueT>
+bool PrioritizedEventQueue<InnerQueueT>::HasPendingHighPriorityEvents(
+    const MutexAutoLock& aProofOfLock) {
+  return !mHighQueue->IsEmpty(aProofOfLock);
+}
+
+template <class InnerQueueT>
 size_t PrioritizedEventQueue<InnerQueueT>::Count(
     const MutexAutoLock& aProofOfLock) const {
   MOZ_CRASH("unimplemented");
 }
 
 template <class InnerQueueT>
 void PrioritizedEventQueue<InnerQueueT>::EnableInputEventPrioritization(
     const MutexAutoLock& aProofOfLock) {
--- a/xpcom/threads/PrioritizedEventQueue.h
+++ b/xpcom/threads/PrioritizedEventQueue.h
@@ -50,16 +50,17 @@ class PrioritizedEventQueue final : publ
   void PutEvent(already_AddRefed<nsIRunnable>&& aEvent, EventPriority aPriority,
                 const MutexAutoLock& aProofOfLock) final;
   already_AddRefed<nsIRunnable> GetEvent(
       EventPriority* aPriority, const MutexAutoLock& aProofOfLock) final;
 
   bool IsEmpty(const MutexAutoLock& aProofOfLock) final;
   size_t Count(const MutexAutoLock& aProofOfLock) const final;
   bool HasReadyEvent(const MutexAutoLock& aProofOfLock) final;
+  bool HasPendingHighPriorityEvents(const MutexAutoLock& aProofOfLock) final;
 
   // When checking the idle deadline, we need to drop whatever mutex protects
   // this queue. This method allows that mutex to be stored so that we can drop
   // it and reacquire it when checking the idle deadline. The mutex must live at
   // least as long as the queue.
   void SetMutexRef(Mutex& aMutex) { mMutex = &aMutex; }
 
 #ifndef RELEASE_OR_BETA
--- a/xpcom/threads/Scheduler.cpp
+++ b/xpcom/threads/Scheduler.cpp
@@ -46,16 +46,19 @@ class SchedulerEventQueue final : public
 
   void Disconnect(const MutexAutoLock& aProofOfLock) final {}
 
   already_AddRefed<nsIRunnable> GetEvent(bool aMayWait,
                                          EventPriority* aPriority) final;
   bool HasPendingEvent() final;
   bool HasPendingEvent(const MutexAutoLock& aProofOfLock);
 
+  bool HasPendingHighPriorityEvents() final;
+  bool HasPendingHighPriorityEvents(const MutexAutoLock& aProofOfLock);
+
   bool ShutdownIfNoPendingEvents() final;
 
   already_AddRefed<nsIThreadObserver> GetObserver() final;
   already_AddRefed<nsIThreadObserver> GetObserverOnThread() final;
   void SetObserver(nsIThreadObserver* aObserver) final;
 
   void EnableInputEventPrioritization() final;
   void FlushInputEventPrioritization() final;
@@ -299,16 +302,26 @@ bool SchedulerEventQueue::HasPendingEven
   MutexAutoLock lock(mLock);
   return HasPendingEvent(lock);
 }
 
 bool SchedulerEventQueue::HasPendingEvent(const MutexAutoLock& aProofOfLock) {
   return mQueue->HasReadyEvent(aProofOfLock);
 }
 
+bool SchedulerEventQueue::HasPendingHighPriorityEvents() {
+  MutexAutoLock lock(mLock);
+  return HasPendingHighPriorityEvents(lock);
+}
+
+bool SchedulerEventQueue::HasPendingHighPriorityEvents(
+    const MutexAutoLock& aProofOfLock) {
+  return mQueue->HasPendingHighPriorityEvents(aProofOfLock);
+}
+
 bool SchedulerEventQueue::ShutdownIfNoPendingEvents() {
   MutexAutoLock lock(mLock);
 
   MOZ_ASSERT(!mScheduler);
 
   if (mQueue->IsEmpty(lock)) {
     mEventsAreDoomed = true;
     return true;
--- a/xpcom/threads/SynchronizedEventQueue.h
+++ b/xpcom/threads/SynchronizedEventQueue.h
@@ -53,16 +53,18 @@ class ThreadTargetSink {
 };
 
 class SynchronizedEventQueue : public ThreadTargetSink {
  public:
   virtual already_AddRefed<nsIRunnable> GetEvent(bool aMayWait,
                                                  EventPriority* aPriority) = 0;
   virtual bool HasPendingEvent() = 0;
 
+  virtual bool HasPendingHighPriorityEvents() = 0;
+
   // This method atomically checks if there are pending events and, if there are
   // none, forbids future events from being posted. It returns true if there
   // were no pending events.
   virtual bool ShutdownIfNoPendingEvents() = 0;
 
   // These methods provide access to an nsIThreadObserver, whose methods are
   // called when posting and processing events. SetObserver should only be
   // called on the thread that processes events. GetObserver can be called from
--- a/xpcom/threads/ThreadEventQueue.cpp
+++ b/xpcom/threads/ThreadEventQueue.cpp
@@ -159,16 +159,29 @@ bool ThreadEventQueue<InnerQueueT>::HasP
   if (mNestedQueues.IsEmpty()) {
     return mBaseQueue->HasReadyEvent(lock);
   } else {
     return mNestedQueues.LastElement().mQueue->HasReadyEvent(lock);
   }
 }
 
 template <class InnerQueueT>
+bool ThreadEventQueue<InnerQueueT>::HasPendingHighPriorityEvents() {
+  MutexAutoLock lock(mLock);
+
+  // We always get events from the topmost queue when there are nested queues.
+  if (mNestedQueues.IsEmpty()) {
+    return mBaseQueue->HasPendingHighPriorityEvents(lock);
+  } else {
+    return mNestedQueues.LastElement().mQueue->HasPendingHighPriorityEvents(
+        lock);
+  }
+}
+
+template <class InnerQueueT>
 bool ThreadEventQueue<InnerQueueT>::ShutdownIfNoPendingEvents() {
   MutexAutoLock lock(mLock);
   if (mNestedQueues.IsEmpty() && mBaseQueue->IsEmpty(lock)) {
     mEventsAreDoomed = true;
     return true;
   }
   return false;
 }
--- a/xpcom/threads/ThreadEventQueue.h
+++ b/xpcom/threads/ThreadEventQueue.h
@@ -39,16 +39,17 @@ class ThreadEventQueue final : public Sy
   explicit ThreadEventQueue(UniquePtr<InnerQueueT> aQueue);
 
   bool PutEvent(already_AddRefed<nsIRunnable>&& aEvent,
                 EventPriority aPriority) final;
 
   already_AddRefed<nsIRunnable> GetEvent(bool aMayWait,
                                          EventPriority* aPriority) final;
   bool HasPendingEvent() final;
+  bool HasPendingHighPriorityEvents() final;
 
   bool ShutdownIfNoPendingEvents() final;
 
   void Disconnect(const MutexAutoLock& aProofOfLock) final {}
 
   void EnableInputEventPrioritization() final;
   void FlushInputEventPrioritization() final;
   void SuspendInputEventPrioritization() final;
--- a/xpcom/threads/nsIThread.idl
+++ b/xpcom/threads/nsIThread.idl
@@ -79,16 +79,21 @@ interface nsIThread : nsISerialEventTarg
    *
    * @throws NS_ERROR_UNEXPECTED
    *   Indicates that this method was erroneously called when this thread was
    *   not the current thread.
    */
   boolean hasPendingEvents();
 
   /**
+   * Similar to above, but checks only possible high priority queue.
+   */
+  boolean hasPendingHighPriorityEvents();
+
+  /**
    * Process the next event.  If there are no pending events, then this method
    * may wait -- depending on the value of the mayWait parameter -- until an
    * event is dispatched to this thread.  This method is re-entrant but may
    * only be called if this thread is the current thread.
    *
    * @param mayWait
    *   A boolean parameter that if "true" indicates that the method may block
    *   the calling thread to wait for a pending event.
--- a/xpcom/threads/nsThread.cpp
+++ b/xpcom/threads/nsThread.cpp
@@ -886,16 +886,26 @@ nsThread::HasPendingEvents(bool* aResult
     return NS_ERROR_NOT_SAME_THREAD;
   }
 
   *aResult = mEvents->HasPendingEvent();
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsThread::HasPendingHighPriorityEvents(bool* aResult) {
+  if (NS_WARN_IF(PR_GetCurrentThread() != mThread)) {
+    return NS_ERROR_NOT_SAME_THREAD;
+  }
+
+  *aResult = mEvents->HasPendingHighPriorityEvents();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsThread::IdleDispatch(already_AddRefed<nsIRunnable> aEvent) {
   nsCOMPtr<nsIRunnable> event = aEvent;
 
   if (NS_WARN_IF(!event)) {
     return NS_ERROR_INVALID_ARG;
   }
 
   if (!mEvents->PutEvent(event.forget(), EventPriority::Idle)) {
--- a/xpcom/threads/nsThreadManager.cpp
+++ b/xpcom/threads/nsThreadManager.cpp
@@ -580,16 +580,26 @@ void nsThreadManager::SuspendInputEventP
   mMainThread->SuspendInputEventPrioritization();
 }
 
 void nsThreadManager::ResumeInputEventPrioritization() {
   MOZ_ASSERT(NS_IsMainThread());
   mMainThread->ResumeInputEventPrioritization();
 }
 
+// static
+bool nsThreadManager::MainThreadHasPendingHighPriorityEvents() {
+  MOZ_ASSERT(NS_IsMainThread());
+  bool retVal = false;
+  if (get().mMainThread) {
+    get().mMainThread->HasPendingHighPriorityEvents(&retVal);
+  }
+  return retVal;
+}
+
 NS_IMETHODIMP
 nsThreadManager::IdleDispatchToMainThread(nsIRunnable* aEvent,
                                           uint32_t aTimeout) {
   // Note: C++ callers should instead use NS_IdleDispatchToThread or
   // NS_IdleDispatchToCurrentThread.
   MOZ_ASSERT(NS_IsMainThread());
 
   nsCOMPtr<nsIRunnable> event(aEvent);
--- a/xpcom/threads/nsThreadManager.h
+++ b/xpcom/threads/nsThreadManager.h
@@ -61,16 +61,18 @@ class nsThreadManager : public nsIThread
   // class with older compilers (e.g., egcs-2.91.66).
   ~nsThreadManager() {}
 
   void EnableMainThreadEventPrioritization();
   void FlushInputEventPrioritization();
   void SuspendInputEventPrioritization();
   void ResumeInputEventPrioritization();
 
+  static bool MainThreadHasPendingHighPriorityEvents();
+
  private:
   nsThreadManager()
       : mCurThreadIndex(0), mMainPRThread(nullptr), mInitialized(false) {}
 
   nsresult SpinEventLoopUntilInternal(nsINestedEventLoopCondition* aCondition,
                                       bool aCheckingShutdown);
 
   static void ReleaseThread(void* aData);