Merge inbound to mozilla-central. a=merge
authorshindli <shindli@mozilla.com>
Tue, 29 Jan 2019 23:37:33 +0200
changeset 455962 4440fbf71c72e13cfcb6257bbae6024052ffd46d
parent 455919 e54fff25332417ae1cf18b933882798a33d24ec9 (current diff)
parent 455961 efb5e5425e2bc9baebb2a86730adbccf68deaa87 (diff)
child 455963 58b77413fd917d29a8975f87903309056e8affe4
child 455980 7418e2fbef99190b81168fb874318fab26c0cba4
child 456013 9f5f935c3f2739c5cba8e8c9407446b8dfff59b5
push id35463
push usershindli@mozilla.com
push dateTue, 29 Jan 2019 21:38:17 +0000
treeherdermozilla-central@4440fbf71c72 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone67.0a1
first release with
nightly linux32
4440fbf71c72 / 67.0a1 / 20190129213817 / files
nightly linux64
4440fbf71c72 / 67.0a1 / 20190129213817 / files
nightly mac
4440fbf71c72 / 67.0a1 / 20190129213817 / files
nightly win32
4440fbf71c72 / 67.0a1 / 20190129213817 / files
nightly win64
4440fbf71c72 / 67.0a1 / 20190129213817 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to mozilla-central. a=merge
caps/nsScriptSecurityManager.cpp
docshell/base/nsCDefaultURIFixup.idl
dom/base/nsGlobalWindowInner.cpp
netwerk/protocol/res/ExtensionProtocolHandler.cpp
toolkit/xre/nsAppRunner.cpp
uriloader/prefetch/nsCPrefetchService.h
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1036,20 +1036,21 @@ pref("security.sandbox.windows.log.stack
 
 // This controls the strength of the Windows GPU process sandbox.  Changes
 // will require restart.
 // For information on what the level number means, see
 // SetSecurityLevelForGPUProcess() in
 // security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp
 pref("security.sandbox.gpu.level", 0);
 
-// Controls whether we disable win32k for the GMP processes.
+// Controls whether we disable win32k for the processes.
 // true means that win32k system calls are not permitted.
-// Note: win32k is currently _not_ disabled due to intermittent test failures,
-// where the GMP process fails very early. See bug 1449348.
+pref("security.sandbox.rdd.win32k-disable", true);
+// Note: win32k is currently _not_ disabled for GMP due to intermittent test
+// failures, where the GMP process fails very early. See bug 1449348.
 pref("security.sandbox.gmp.win32k-disable", false);
 #endif
 
 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
 // Start the Mac sandbox early during child process startup instead
 // of when messaged by the parent after the message loop is running.
 pref("security.sandbox.content.mac.earlyinit", true);
 #endif
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -1017,19 +1017,30 @@ ifdef RUST_LIBRARY_FEATURES
 rust_features_flag := --features "$(RUST_LIBRARY_FEATURES)"
 endif
 
 # Assume any system libraries rustc links against are already in the target's LIBS.
 #
 # We need to run cargo unconditionally, because cargo is the only thing that
 # has full visibility into how changes in Rust sources might affect the final
 # build.
+#
+# When we are building in --enable-release mode; we add an additional check to confirm
+# that we are not importing any networking-related functions in rust code. This reduces
+# the chance of proxy bypasses originating from rust code.
 force-cargo-library-build:
 	$(REPORT_BUILD)
 	$(call CARGO_BUILD,$(target_cargo_env_vars)) --lib $(cargo_target_flag) $(rust_features_flag) -- $(cargo_rustc_flags)
+ifndef DEVELOPER_OPTIONS
+ifndef MOZ_DEBUG_RUST
+ifeq ($(OS_ARCH), Linux)
+	$(call py_action,check_binary,--target --networking $(RUST_LIBRARY_FILE))
+endif
+endif
+endif
 
 $(RUST_LIBRARY_FILE): force-cargo-library-build
 
 force-cargo-library-check:
 	$(call CARGO_CHECK,$(target_cargo_env_vars)) --lib $(cargo_target_flag) $(rust_features_flag)
 else
 force-cargo-library-check:
 	@true
--- a/devtools/client/inspector/rules/actions/index.js
+++ b/devtools/client/inspector/rules/actions/index.js
@@ -14,16 +14,19 @@ createEnum([
 
   // Sets the entire pseudo class state with the new list of applied pseudo-class
   // locks.
   "SET_PSEUDO_CLASSES",
 
   // Toggles on or off the given pseudo class value for the current selected element.
   "TOGGLE_PSEUDO_CLASS",
 
+  // Updates whether or not the add new rule button should be enabled.
+  "UPDATE_ADD_RULE_ENABLED",
+
   // Updates the entire class list state with the new list of classes.
   "UPDATE_CLASSES",
 
   // Updates whether or not the class list panel is expanded.
   "UPDATE_CLASS_PANEL_EXPANDED",
 
   // Updates the highlighted selector.
   "UPDATE_HIGHLIGHTED_SELECTOR",
--- a/devtools/client/inspector/rules/actions/rules.js
+++ b/devtools/client/inspector/rules/actions/rules.js
@@ -1,22 +1,36 @@
 /* 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/. */
 
 "use strict";
 
 const {
+  UPDATE_ADD_RULE_ENABLED,
   UPDATE_HIGHLIGHTED_SELECTOR,
   UPDATE_RULES,
 } = require("./index");
 
 module.exports = {
 
   /**
+   * Updates whether or not the add new rule button should be enabled.
+   *
+   * @param  {Boolean} enabled
+   *         Whether or not the add new rule button is enabled.
+   */
+  updateAddRuleEnabled(enabled) {
+    return {
+      type: UPDATE_ADD_RULE_ENABLED,
+      enabled,
+    };
+  },
+
+  /**
    * Updates the highlighted selector.
    *
    * @param  {String} highlightedSelector
    *         The selector of the element to be highlighted by the selector highlighter.
    */
   updateHighlightedSelector(highlightedSelector) {
     return {
       type: UPDATE_HIGHLIGHTED_SELECTOR,
--- a/devtools/client/inspector/rules/components/RulesApp.js
+++ b/devtools/client/inspector/rules/components/RulesApp.js
@@ -24,16 +24,17 @@ const { getStr } = require("../utils/l10
 const Types = require("../types");
 
 const SHOW_PSEUDO_ELEMENTS_PREF = "devtools.inspector.show_pseudo_elements";
 
 class RulesApp extends PureComponent {
   static get propTypes() {
     return {
       onAddClass: PropTypes.func.isRequired,
+      onAddRule: PropTypes.func.isRequired,
       onSetClassState: PropTypes.func.isRequired,
       onToggleClassPanelExpanded: PropTypes.func.isRequired,
       onToggleDeclaration: PropTypes.func.isRequired,
       onTogglePseudoClass: PropTypes.func.isRequired,
       onToggleSelectorHighlighter: PropTypes.func.isRequired,
       rules: PropTypes.arrayOf(PropTypes.shape(Types.rule)).isRequired,
       showDeclarationNameEditor: PropTypes.func.isRequired,
       showDeclarationValueEditor: PropTypes.func.isRequired,
@@ -170,16 +171,17 @@ class RulesApp extends PureComponent {
     return (
       dom.div(
         {
           id: "sidebar-panel-ruleview",
           className: "theme-sidebar inspector-tabpanel",
         },
         Toolbar({
           onAddClass: this.props.onAddClass,
+          onAddRule: this.props.onAddRule,
           onSetClassState: this.props.onSetClassState,
           onToggleClassPanelExpanded: this.props.onToggleClassPanelExpanded,
           onTogglePseudoClass: this.props.onTogglePseudoClass,
         }),
         dom.div(
           {
             id: "ruleview-container",
             className: "ruleview",
--- a/devtools/client/inspector/rules/components/Toolbar.js
+++ b/devtools/client/inspector/rules/components/Toolbar.js
@@ -18,36 +18,44 @@ loader.lazyGetter(this, "PseudoClassPane
   return createFactory(require("./PseudoClassPanel"));
 });
 
 const { getStr } = require("../utils/l10n");
 
 class Toolbar extends PureComponent {
   static get propTypes() {
     return {
+      isAddRuleEnabled: PropTypes.bool.isRequired,
       isClassPanelExpanded: PropTypes.bool.isRequired,
       onAddClass: PropTypes.func.isRequired,
+      onAddRule: PropTypes.func.isRequired,
       onSetClassState: PropTypes.func.isRequired,
       onToggleClassPanelExpanded: PropTypes.func.isRequired,
       onTogglePseudoClass: PropTypes.func.isRequired,
     };
   }
 
   constructor(props) {
     super(props);
 
     this.state = {
       // Whether or not the pseudo class panel is expanded.
       isPseudoClassPanelExpanded: false,
     };
 
+    this.onAddRuleClick = this.onAddRuleClick.bind(this);
     this.onClassPanelToggle = this.onClassPanelToggle.bind(this);
     this.onPseudoClassPanelToggle = this.onPseudoClassPanelToggle.bind(this);
   }
 
+  onAddRuleClick(event) {
+    event.stopPropagation();
+    this.props.onAddRule();
+  }
+
   onClassPanelToggle(event) {
     event.stopPropagation();
 
     const isClassPanelExpanded = !this.props.isClassPanelExpanded;
     this.props.onToggleClassPanelExpanded(isClassPanelExpanded);
     this.setState(prevState => {
       return {
         isPseudoClassPanelExpanded: isClassPanelExpanded ?
@@ -65,31 +73,33 @@ class Toolbar extends PureComponent {
     if (isPseudoClassPanelExpanded) {
       this.props.onToggleClassPanelExpanded(false);
     }
 
     this.setState({ isPseudoClassPanelExpanded });
   }
 
   render() {
-    const { isClassPanelExpanded } = this.props;
+    const { isAddRuleEnabled, isClassPanelExpanded } = this.props;
     const { isPseudoClassPanelExpanded } = this.state;
 
     return (
       dom.div(
         {
           id: "ruleview-toolbar-container",
           className: "devtools-toolbar",
         },
         dom.div({ id: "ruleview-toolbar" },
           SearchBox({}),
           dom.div({ id: "ruleview-command-toolbar" },
             dom.button({
               id: "ruleview-add-rule-button",
               className: "devtools-button",
+              disabled: !isAddRuleEnabled,
+              onClick: this.onAddRuleClick,
               title: getStr("rule.addRule.tooltip"),
             }),
             dom.button({
               id: "pseudo-class-panel-toggle",
               className: "devtools-button" +
                           (isPseudoClassPanelExpanded ? " checked" : ""),
               onClick: this.onPseudoClassPanelToggle,
               title: getStr("rule.togglePseudo.tooltip"),
@@ -118,13 +128,14 @@ class Toolbar extends PureComponent {
           null
       )
     );
   }
 }
 
 const mapStateToProps = state => {
   return {
+    isAddRuleEnabled: state.rules.isAddRuleEnabled,
     isClassPanelExpanded: state.classList.isClassPanelExpanded,
   };
 };
 
 module.exports = connect(mapStateToProps)(Toolbar);
--- a/devtools/client/inspector/rules/models/element-style.js
+++ b/devtools/client/inspector/rules/models/element-style.js
@@ -47,31 +47,41 @@ function ElementStyle(element, ruleView,
   // if it doesn't already exist.
   if (!("userProperties" in this.store)) {
     this.store.userProperties = new UserProperties();
   }
 
   if (!("disabled" in this.store)) {
     this.store.disabled = new WeakMap();
   }
+
+  this.onStyleSheetUpdated = this.onStyleSheetUpdated.bind(this);
+
+  if (this.ruleView.isNewRulesView) {
+    this.pageStyle.on("stylesheet-updated", this.onStyleSheetUpdated);
+  }
 }
 
 ElementStyle.prototype = {
   destroy: function() {
     if (this.destroyed) {
       return;
     }
 
     this.destroyed = true;
 
     for (const rule of this.rules) {
       if (rule.editor) {
         rule.editor.destroy();
       }
     }
+
+    if (this.ruleView.isNewRulesView) {
+      this.pageStyle.off("stylesheet-updated", this.onStyleSheetUpdated);
+    }
   },
 
   /**
    * Called by the Rule object when it has been changed through the
    * setProperty* methods.
    */
   _changed: function() {
     if (this.onChanged) {
@@ -330,16 +340,25 @@ ElementStyle.prototype = {
       // overridden state has changed for the text property.
       if (this._updatePropertyOverridden(textProp)) {
         textProp.updateEditor();
       }
     }
   },
 
   /**
+   * Adds a new rule. The rules view is updated from a "stylesheet-updated" event
+   * emitted the PageStyleActor as a result of the rule being inserted into the
+   * the stylesheet.
+   */
+  async addNewRule() {
+    await this.pageStyle.addNewRule(this.element, this.element.pseudoClassLocks);
+  },
+
+  /**
    * Given the id of the rule and the new declaration name, modifies the existing
    * declaration name to the new given value.
    *
    * @param  {String} ruleID
    *         The Rule id of the given CSS declaration.
    * @param  {String} declarationId
    *         The TextProperty id for the CSS declaration.
    * @param  {String} name
@@ -588,11 +607,29 @@ ElementStyle.prototype = {
   * @param  {String} name
   *         The name of the variable.
   * @return {String} the variable's value or null if the variable is
   *         not defined.
   */
   getVariable: function(name) {
     return this.variables.get(name);
   },
+
+  /**
+   * Handler for page style events "stylesheet-updated". Refreshes the list of rules on
+   * the page.
+   */
+  onStyleSheetUpdated: async function() {
+    // Repopulate the element style once the current modifications are done.
+    const promises = [];
+    for (const rule of this.rules) {
+      if (rule._applyingModifications) {
+        promises.push(rule._applyingModifications);
+      }
+    }
+
+    await Promise.all(promises);
+    await this.populate();
+    this._changed();
+  },
 };
 
 module.exports = ElementStyle;
--- a/devtools/client/inspector/rules/models/rule.js
+++ b/devtools/client/inspector/rules/models/rule.js
@@ -556,17 +556,21 @@ Rule.prototype = {
 
     // The element style rule behaves differently on refresh. We basically need to update
     // it to reflect the new text properties exactly. The order might have changed, some
     // properties might have been removed, etc. And we don't need to mark anything as
     // disabled here. The element style rule should always reflect the content of the
     // style attribute.
     if (this.domRule.type === ELEMENT_STYLE) {
       this.textProps = newTextProps;
-      this.editor.populate(true);
+
+      if (this.editor) {
+        this.editor.populate(true);
+      }
+
       return;
     }
 
     // Update current properties for each property present on the style.
     // This will mark any touched properties with _visited so we
     // can detect properties that weren't touched (because they were
     // removed from the style).
     // Also keep track of properties that didn't exist in the current set
--- a/devtools/client/inspector/rules/new-rules.js
+++ b/devtools/client/inspector/rules/new-rules.js
@@ -15,16 +15,17 @@ const {
   updateClassPanelExpanded,
 } = require("./actions/class-list");
 const {
   disableAllPseudoClasses,
   setPseudoClassLocks,
   togglePseudoClass,
 } = require("./actions/pseudo-classes");
 const {
+  updateAddRuleEnabled,
   updateHighlightedSelector,
   updateRules,
 } = require("./actions/rules");
 
 const RulesApp = createFactory(require("./components/RulesApp"));
 
 const { LocalizationHelper } = require("devtools/shared/l10n");
 const INSPECTOR_L10N =
@@ -42,20 +43,22 @@ class RulesView {
     this.cssProperties = inspector.cssProperties;
     this.doc = window.document;
     this.inspector = inspector;
     this.pageStyle = inspector.pageStyle;
     this.selection = inspector.selection;
     this.store = inspector.store;
     this.telemetry = inspector.telemetry;
     this.toolbox = inspector.toolbox;
+    this.isNewRulesView = true;
 
     this.showUserAgentStyles = Services.prefs.getBoolPref(PREF_UA_STYLES);
 
     this.onAddClass = this.onAddClass.bind(this);
+    this.onAddRule = this.onAddRule.bind(this);
     this.onSelection = this.onSelection.bind(this);
     this.onSetClassState = this.onSetClassState.bind(this);
     this.onToggleClassPanelExpanded = this.onToggleClassPanelExpanded.bind(this);
     this.onToggleDeclaration = this.onToggleDeclaration.bind(this);
     this.onTogglePseudoClass = this.onTogglePseudoClass.bind(this);
     this.onToggleSelectorHighlighter = this.onToggleSelectorHighlighter.bind(this);
     this.showDeclarationNameEditor = this.showDeclarationNameEditor.bind(this);
     this.showDeclarationValueEditor = this.showDeclarationValueEditor.bind(this);
@@ -74,16 +77,17 @@ class RulesView {
 
   init() {
     if (!this.inspector) {
       return;
     }
 
     const rulesApp = RulesApp({
       onAddClass: this.onAddClass,
+      onAddRule: this.onAddRule,
       onSetClassState: this.onSetClassState,
       onToggleClassPanelExpanded: this.onToggleClassPanelExpanded,
       onToggleDeclaration: this.onToggleDeclaration,
       onTogglePseudoClass: this.onTogglePseudoClass,
       onToggleSelectorHighlighter: this.onToggleSelectorHighlighter,
       showDeclarationNameEditor: this.showDeclarationNameEditor,
       showDeclarationValueEditor: this.showDeclarationValueEditor,
       showSelectorEditor: this.showSelectorEditor,
@@ -265,16 +269,23 @@ class RulesView {
    *         The string that contains all classes.
    */
   async onAddClass(value) {
     await this.classList.addClassName(value);
     this.updateClassList();
   }
 
   /**
+   * Handler for adding a new CSS rule.
+   */
+  async onAddRule() {
+    await this.elementStyle.addNewRule();
+  }
+
+  /**
    * Handler for selection events "detached-front" and "new-node-front" and inspector
    * sidbar "select" event. Updates the rules view with the selected node if the panel
    * is visible.
    */
   onSelection() {
     if (!this.isPanelVisible()) {
       return;
     }
@@ -501,26 +512,30 @@ class RulesView {
    * selection.
    *
    * @param  {NodeFront|null} element
    *         The NodeFront of the current selected element.
    */
   async update(element) {
     if (!element) {
       this.store.dispatch(disableAllPseudoClasses());
+      this.store.dispatch(updateAddRuleEnabled(false));
       this.store.dispatch(updateClasses([]));
       this.store.dispatch(updateRules([]));
       return;
     }
 
     this.elementStyle = new ElementStyle(element, this, {}, this.pageStyle,
       this.showUserAgentStyles);
     this.elementStyle.onChanged = this.updateRules;
     await this.elementStyle.populate();
 
+    const isAddRuleEnabled = this.selection.isElementNode() &&
+                             !this.selection.isAnonymousNode();
+    this.store.dispatch(updateAddRuleEnabled(isAddRuleEnabled));
     this.store.dispatch(setPseudoClassLocks(this.elementStyle.element.pseudoClassLocks));
     this.updateClassList();
     this.updateRules();
   }
 
   /**
    * Updates the class list panel with the current list of CSS classes.
    */
--- a/devtools/client/inspector/rules/reducers/rules.js
+++ b/devtools/client/inspector/rules/reducers/rules.js
@@ -1,22 +1,25 @@
 /* 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/. */
 
 "use strict";
 
 const {
+  UPDATE_ADD_RULE_ENABLED,
   UPDATE_RULES,
   UPDATE_HIGHLIGHTED_SELECTOR,
 } = require("../actions/index");
 
 const INITIAL_RULES = {
   // The selector of the node that is highlighted by the selector highlighter.
   highlightedSelector: "",
+  // Whether or not the add new rule button should be enabled.
+  isAddRuleEnabled: false,
   // Array of CSS rules.
   rules: [],
 };
 
 /**
  * Given a rule's TextProperty, returns the properties that are needed to render a
  * CSS declaration.
  *
@@ -84,26 +87,34 @@ function getRuleState(rule) {
     sourceLink: rule.sourceLink,
     // The CSS rule type.
     type: rule.domRule.type,
   };
 }
 
 const reducers = {
 
+  [UPDATE_ADD_RULE_ENABLED](rules, { enabled }) {
+    return {
+      ...rules,
+      isAddRuleEnabled: enabled,
+    };
+  },
+
   [UPDATE_HIGHLIGHTED_SELECTOR](rules, { highlightedSelector }) {
     return {
       ...rules,
       highlightedSelector,
     };
   },
 
   [UPDATE_RULES](rules, { rules: newRules }) {
     return {
       highlightedSelector: rules.highlightedSelector,
+      isAddRuleEnabled: rules.isAddRuleEnabled,
       rules: newRules.map(rule => getRuleState(rule)),
     };
   },
 
 };
 
 module.exports = function(rules = INITIAL_RULES, action) {
   const reducer = reducers[action.type];
--- a/dom/media/ipc/RDDProcessImpl.h
+++ b/dom/media/ipc/RDDProcessImpl.h
@@ -24,18 +24,13 @@ class RDDProcessImpl final : public ipc:
 
   bool Init(int aArgc, char* aArgv[]) override;
   void CleanUp() override;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(RDDProcessImpl);
 
   RDDParent mRDD;
-
-#if defined(XP_WIN)
-  // This object initializes and configures COM.
-  mozilla::mscom::MainThreadRuntime mCOMRuntime;
-#endif
 };
 
 }  // namespace mozilla
 
 #endif  // _include_dom_media_ipc_RDDProcessImpl_h__
--- a/ipc/glue/WindowsMessageLoop.cpp
+++ b/ipc/glue/WindowsMessageLoop.cpp
@@ -629,37 +629,28 @@ bool TimeoutHasExpired(const TimeoutData
 }
 
 }  // namespace
 
 namespace mozilla {
 namespace ipc {
 namespace windows {
 
-static bool ProcessTypeRequiresWinEventHook() {
-  switch (XRE_GetProcessType()) {
-    case GeckoProcessType_GMPlugin:
-      return false;
-    default:
-      return true;
-  }
-}
-
 void InitUIThread() {
   // If we aren't setup before a call to NotifyWorkerThread, we'll hang
   // on startup.
   if (!gUIThreadId) {
     gUIThreadId = GetCurrentThreadId();
   }
 
   MOZ_ASSERT(gUIThreadId);
   MOZ_ASSERT(gUIThreadId == GetCurrentThreadId(),
              "Called InitUIThread multiple times on different threads!");
 
-  if (!gWinEventHook && ProcessTypeRequiresWinEventHook()) {
+  if (!gWinEventHook && XRE_Win32kCallsAllowed()) {
     gWinEventHook = SetWinEventHook(EVENT_OBJECT_CREATE, EVENT_OBJECT_DESTROY,
                                     NULL, &WinEventHook, GetCurrentProcessId(),
                                     gUIThreadId, WINEVENT_OUTOFCONTEXT);
     MOZ_ASSERT(gWinEventHook);
 
     // We need to execute this after setting the hook in case the OLE window
     // already existed.
     gCOMWindow = FindCOMWindow();
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -1322,105 +1322,105 @@ void Scope::traceChildren(JSTracer* trc)
       as<WasmInstanceScope>().data().trace(trc);
       break;
     case ScopeKind::WasmFunction:
       as<WasmFunctionScope>().data().trace(trc);
       break;
   }
 }
 inline void js::GCMarker::eagerlyMarkChildren(Scope* scope) {
-  if (scope->enclosing_) {
-    traverseEdge(scope, scope->enclosing_.get());
-  }
-  if (scope->environmentShape_) {
-    traverseEdge(scope, scope->environmentShape_.get());
-  }
-  TrailingNamesArray* names = nullptr;
-  uint32_t length = 0;
-  switch (scope->kind()) {
-    case ScopeKind::Function: {
-      FunctionScope::Data& data = scope->as<FunctionScope>().data();
-      traverseObjectEdge(scope, data.canonicalFunction);
-      names = &data.trailingNames;
-      length = data.length;
-      break;
-    }
-
-    case ScopeKind::FunctionBodyVar:
-    case ScopeKind::ParameterExpressionVar: {
-      VarScope::Data& data = scope->as<VarScope>().data();
-      names = &data.trailingNames;
-      length = data.length;
-      break;
-    }
-
-    case ScopeKind::Lexical:
-    case ScopeKind::SimpleCatch:
-    case ScopeKind::Catch:
-    case ScopeKind::NamedLambda:
-    case ScopeKind::StrictNamedLambda: {
-      LexicalScope::Data& data = scope->as<LexicalScope>().data();
-      names = &data.trailingNames;
-      length = data.length;
-      break;
+  do {
+    if (scope->environmentShape_) {
+      traverseEdge(scope, scope->environmentShape_.get());
     }
-
-    case ScopeKind::Global:
-    case ScopeKind::NonSyntactic: {
-      GlobalScope::Data& data = scope->as<GlobalScope>().data();
-      names = &data.trailingNames;
-      length = data.length;
-      break;
-    }
-
-    case ScopeKind::Eval:
-    case ScopeKind::StrictEval: {
-      EvalScope::Data& data = scope->as<EvalScope>().data();
-      names = &data.trailingNames;
-      length = data.length;
-      break;
-    }
-
-    case ScopeKind::Module: {
-      ModuleScope::Data& data = scope->as<ModuleScope>().data();
-      traverseObjectEdge(scope, data.module);
-      names = &data.trailingNames;
-      length = data.length;
-      break;
-    }
-
-    case ScopeKind::With:
-      break;
-
-    case ScopeKind::WasmInstance: {
-      WasmInstanceScope::Data& data = scope->as<WasmInstanceScope>().data();
-      traverseObjectEdge(scope, data.instance);
-      names = &data.trailingNames;
-      length = data.length;
-      break;
-    }
-
-    case ScopeKind::WasmFunction: {
-      WasmFunctionScope::Data& data = scope->as<WasmFunctionScope>().data();
-      names = &data.trailingNames;
-      length = data.length;
-      break;
-    }
-  }
-  if (scope->kind_ == ScopeKind::Function) {
-    for (uint32_t i = 0; i < length; i++) {
-      if (JSAtom* name = names->get(i).name()) {
-        traverseStringEdge(scope, name);
+    TrailingNamesArray* names = nullptr;
+    uint32_t length = 0;
+    switch (scope->kind()) {
+      case ScopeKind::Function: {
+        FunctionScope::Data& data = scope->as<FunctionScope>().data();
+        traverseObjectEdge(scope, data.canonicalFunction);
+        names = &data.trailingNames;
+        length = data.length;
+        break;
+      }
+
+      case ScopeKind::FunctionBodyVar:
+      case ScopeKind::ParameterExpressionVar: {
+        VarScope::Data& data = scope->as<VarScope>().data();
+        names = &data.trailingNames;
+        length = data.length;
+        break;
+      }
+
+      case ScopeKind::Lexical:
+      case ScopeKind::SimpleCatch:
+      case ScopeKind::Catch:
+      case ScopeKind::NamedLambda:
+      case ScopeKind::StrictNamedLambda: {
+        LexicalScope::Data& data = scope->as<LexicalScope>().data();
+        names = &data.trailingNames;
+        length = data.length;
+        break;
+      }
+
+      case ScopeKind::Global:
+      case ScopeKind::NonSyntactic: {
+        GlobalScope::Data& data = scope->as<GlobalScope>().data();
+        names = &data.trailingNames;
+        length = data.length;
+        break;
+      }
+
+      case ScopeKind::Eval:
+      case ScopeKind::StrictEval: {
+        EvalScope::Data& data = scope->as<EvalScope>().data();
+        names = &data.trailingNames;
+        length = data.length;
+        break;
+      }
+
+      case ScopeKind::Module: {
+        ModuleScope::Data& data = scope->as<ModuleScope>().data();
+        traverseObjectEdge(scope, data.module);
+        names = &data.trailingNames;
+        length = data.length;
+        break;
+      }
+
+      case ScopeKind::With:
+        break;
+
+      case ScopeKind::WasmInstance: {
+        WasmInstanceScope::Data& data = scope->as<WasmInstanceScope>().data();
+        traverseObjectEdge(scope, data.instance);
+        names = &data.trailingNames;
+        length = data.length;
+        break;
+      }
+
+      case ScopeKind::WasmFunction: {
+        WasmFunctionScope::Data& data = scope->as<WasmFunctionScope>().data();
+        names = &data.trailingNames;
+        length = data.length;
+        break;
       }
     }
-  } else {
-    for (uint32_t i = 0; i < length; i++) {
-      traverseStringEdge(scope, names->get(i).name());
+    if (scope->kind_ == ScopeKind::Function) {
+      for (uint32_t i = 0; i < length; i++) {
+        if (JSAtom* name = names->get(i).name()) {
+          traverseStringEdge(scope, name);
+        }
+      }
+    } else {
+      for (uint32_t i = 0; i < length; i++) {
+        traverseStringEdge(scope, names->get(i).name());
+      }
     }
-  }
+    scope = scope->enclosing_;
+  } while (scope && mark(scope));
 }
 
 void js::ObjectGroup::traceChildren(JSTracer* trc) {
   AutoSweepObjectGroup sweep(this);
 
   if (!trc->canSkipJsids()) {
     unsigned count = getPropertyCount(sweep);
     for (unsigned i = 0; i < count; i++) {
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -12991,20 +12991,19 @@ typedef bool (*ForcedRecompileFn)(JSCont
 static const VMFunction ForcedRecompileFnInfo =
     FunctionInfo<ForcedRecompileFn>(ForcedRecompile, "ForcedRecompile");
 
 void CodeGenerator::visitRecompileCheck(LRecompileCheck* ins) {
   Label done;
   Register tmp = ToRegister(ins->scratch());
   OutOfLineCode* ool;
   if (ins->mir()->forceRecompilation()) {
-    ool =
-        oolCallVM(ForcedRecompileFnInfo, ins, ArgList(), StoreRegisterTo(tmp));
-  } else {
-    ool = oolCallVM(RecompileFnInfo, ins, ArgList(), StoreRegisterTo(tmp));
+    ool = oolCallVM(ForcedRecompileFnInfo, ins, ArgList(), StoreNothing());
+  } else {
+    ool = oolCallVM(RecompileFnInfo, ins, ArgList(), StoreNothing());
   }
 
   // Check if warm-up counter is high enough.
   AbsoluteAddress warmUpCount =
       AbsoluteAddress(ins->mir()->script()->addressOfWarmUpCounter());
   if (ins->mir()->increaseWarmUpCounter()) {
     masm.load32(warmUpCount, tmp);
     masm.add32(Imm32(1), tmp);
--- a/js/src/jit/VMFunctions.h
+++ b/js/src/jit/VMFunctions.h
@@ -205,17 +205,17 @@ struct VMFunction {
     return 1 + explicitArgc() + ((outParam == Type_Void) ? 0 : 1);
   }
 
   DataType failType() const { return returnType; }
 
   // Whether this function returns anything more than a boolean flag for
   // failures.
   bool returnsData() const {
-    return returnType == Type_Pointer || outParam != Type_Void;
+    return returnType == Type_Object || outParam != Type_Void;
   }
 
   ArgProperties argProperties(uint32_t explicitArg) const {
     return ArgProperties((argumentProperties >> (2 * explicitArg)) & 3);
   }
 
   RootType argRootType(uint32_t explicitArg) const {
     return RootType((argumentRootTypes >> (3 * explicitArg)) & 7);
--- a/js/src/jit/shared/CodeGenerator-shared.h
+++ b/js/src/jit/shared/CodeGenerator-shared.h
@@ -572,16 +572,20 @@ template <typename... ArgTypes>
 class ArgSeq;
 
 template <>
 class ArgSeq<> {
  public:
   ArgSeq() {}
 
   inline void generate(CodeGeneratorShared* codegen) const {}
+
+#ifdef DEBUG
+  static constexpr size_t numArgs = 0;
+#endif
 };
 
 template <typename HeadType, typename... TailTypes>
 class ArgSeq<HeadType, TailTypes...> : public ArgSeq<TailTypes...> {
  private:
   using RawHeadType = typename mozilla::RemoveReference<HeadType>::Type;
   RawHeadType head_;
 
@@ -592,16 +596,20 @@ class ArgSeq<HeadType, TailTypes...> : p
         head_(std::forward<ProvidedHead>(head)) {}
 
   // Arguments are pushed in reverse order, from last argument to first
   // argument.
   inline void generate(CodeGeneratorShared* codegen) const {
     this->ArgSeq<TailTypes...>::generate(codegen);
     codegen->pushArg(head_);
   }
+
+#ifdef DEBUG
+  static constexpr size_t numArgs = sizeof...(TailTypes) + 1;
+#endif
 };
 
 template <typename... ArgTypes>
 inline ArgSeq<ArgTypes...> ArgList(ArgTypes&&... args) {
   return ArgSeq<ArgTypes...>(std::forward<ArgTypes>(args)...);
 }
 
 // Store wrappers, to generate the right move of data after the VM call.
@@ -697,16 +705,19 @@ class OutOfLineCallVM : public OutOfLine
 
 template <class ArgSeq, class StoreOutputTo>
 inline OutOfLineCode* CodeGeneratorShared::oolCallVM(const VMFunction& fun,
                                                      LInstruction* lir,
                                                      const ArgSeq& args,
                                                      const StoreOutputTo& out) {
   MOZ_ASSERT(lir->mirRaw());
   MOZ_ASSERT(lir->mirRaw()->isInstruction());
+  MOZ_ASSERT(fun.explicitArgs == args.numArgs);
+  MOZ_ASSERT(fun.returnsData() !=
+             (mozilla::IsSame<StoreOutputTo, StoreNothing>::value));
 
   OutOfLineCode* ool =
       new (alloc()) OutOfLineCallVM<ArgSeq, StoreOutputTo>(lir, fun, args, out);
   addOutOfLineCode(ool, lir->mirRaw()->toInstruction());
   return ool;
 }
 
 template <class ArgSeq, class StoreOutputTo>
--- a/layout/generic/ReflowInput.cpp
+++ b/layout/generic/ReflowInput.cpp
@@ -26,16 +26,17 @@
 #include "nsLayoutUtils.h"
 #include "mozilla/Preferences.h"
 #include "nsFontInflationData.h"
 #include "StickyScrollContainer.h"
 #include "nsIFrameInlines.h"
 #include "CounterStyleManager.h"
 #include <algorithm>
 #include "mozilla/dom/HTMLInputElement.h"
+#include "nsGridContainerFrame.h"
 
 #ifdef DEBUG
 #  undef NOISY_VERTICAL_ALIGN
 #else
 #  undef NOISY_VERTICAL_ALIGN
 #endif
 
 using namespace mozilla;
@@ -1332,32 +1333,32 @@ static bool AreAllEarlierInFlowFramesEmp
 }
 
 // Calculate the position of the hypothetical box that the element would have
 // if it were in the flow.
 // The values returned are relative to the padding edge of the absolute
 // containing block. The writing-mode of the hypothetical box position will
 // have the same block direction as the absolute containing block, but may
 // differ in inline-bidi direction.
-// In the code below, |aReflowInput->frame| is the absolute containing block,
+// In the code below, |aCBReflowInput->frame| is the absolute containing block,
 // while |containingBlock| is the nearest block container of the placeholder
 // frame, which may be different from the absolute containing block.
 void ReflowInput::CalculateHypotheticalPosition(
     nsPresContext* aPresContext, nsPlaceholderFrame* aPlaceholderFrame,
-    const ReflowInput* aReflowInput, nsHypotheticalPosition& aHypotheticalPos,
+    const ReflowInput* aCBReflowInput, nsHypotheticalPosition& aHypotheticalPos,
     LayoutFrameType aFrameType) const {
   NS_ASSERTION(mStyleDisplay->mOriginalDisplay != StyleDisplay::None,
                "mOriginalDisplay has not been properly initialized");
 
   // Find the nearest containing block frame to the placeholder frame,
   // and its inline-start edge and width.
   nscoord blockIStartContentEdge;
   // Dummy writing mode for blockContentSize, will be changed as needed by
   // GetHypotheticalBoxContainer.
-  WritingMode cbwm = aReflowInput->GetWritingMode();
+  WritingMode cbwm = aCBReflowInput->GetWritingMode();
   LogicalSize blockContentSize(cbwm);
   nsIFrame* containingBlock = GetHypotheticalBoxContainer(
       aPlaceholderFrame, blockIStartContentEdge, blockContentSize);
   // Now blockContentSize is in containingBlock's writing mode.
 
   // If it's a replaced element and it has a 'auto' value for
   //'inline size', see if we can get the intrinsic size. This will allow
   // us to exactly determine both the inline edges
@@ -1419,17 +1420,17 @@ void ReflowInput::CalculateHypotheticalP
   }
 
   // Get the placeholder x-offset and y-offset in the coordinate
   // space of its containing block
   // XXXbz the placeholder is not fully reflowed yet if our containing block is
   // relatively positioned...
   nsSize containerSize =
       containingBlock->GetStateBits() & NS_FRAME_IN_REFLOW
-          ? aReflowInput->ComputedSizeAsContainerIfConstrained()
+          ? aCBReflowInput->ComputedSizeAsContainerIfConstrained()
           : containingBlock->GetSize();
   LogicalPoint placeholderOffset(
       wm, aPlaceholderFrame->GetOffsetToIgnoringScrolling(containingBlock),
       containerSize);
 
   // First, determine the hypothetical box's mBStart.  We want to check the
   // content insertion frame of containingBlock for block-ness, but make
   // sure to compute all coordinates in the coordinate system of
@@ -1534,29 +1535,29 @@ void ReflowInput::CalculateHypotheticalP
   } else {
     aHypotheticalPos.mIStart = blockIStartContentEdge;
   }
 
   // The current coordinate space is that of the nearest block to the
   // placeholder. Convert to the coordinate space of the absolute containing
   // block.
   nsPoint cbOffset =
-      containingBlock->GetOffsetToIgnoringScrolling(aReflowInput->mFrame);
+      containingBlock->GetOffsetToIgnoringScrolling(aCBReflowInput->mFrame);
 
-  nsSize reflowSize = aReflowInput->ComputedSizeAsContainerIfConstrained();
+  nsSize reflowSize = aCBReflowInput->ComputedSizeAsContainerIfConstrained();
   LogicalPoint logCBOffs(wm, cbOffset, reflowSize - containerSize);
   aHypotheticalPos.mIStart += logCBOffs.I(wm);
   aHypotheticalPos.mBStart += logCBOffs.B(wm);
 
   // The specified offsets are relative to the absolute containing block's
   // padding edge and our current values are relative to the border edge, so
   // translate.
-  LogicalMargin border = aReflowInput->ComputedLogicalBorderPadding() -
-                         aReflowInput->ComputedLogicalPadding();
-  border = border.ConvertTo(wm, aReflowInput->GetWritingMode());
+  LogicalMargin border = aCBReflowInput->ComputedLogicalBorderPadding() -
+                         aCBReflowInput->ComputedLogicalPadding();
+  border = border.ConvertTo(wm, aCBReflowInput->GetWritingMode());
   aHypotheticalPos.mIStart -= border.IStart(wm);
   aHypotheticalPos.mBStart -= border.BStart(wm);
 
   // At this point, we have computed aHypotheticalPos using the writing mode
   // of the placeholder's containing block.
 
   if (cbwm.GetBlockDir() != wm.GetBlockDir()) {
     // If the block direction we used in calculating aHypotheticalPos does not
@@ -1612,21 +1613,21 @@ void ReflowInput::CalculateHypotheticalP
     aHypotheticalPos.mBStart = origin.B(cbwm);
     aHypotheticalPos.mWritingMode = cbwm;
   } else {
     aHypotheticalPos.mWritingMode = wm;
   }
 }
 
 void ReflowInput::InitAbsoluteConstraints(nsPresContext* aPresContext,
-                                          const ReflowInput* aReflowInput,
+                                          const ReflowInput* aCBReflowInput,
                                           const LogicalSize& aCBSize,
                                           LayoutFrameType aFrameType) {
   WritingMode wm = GetWritingMode();
-  WritingMode cbwm = aReflowInput->GetWritingMode();
+  WritingMode cbwm = aCBReflowInput->GetWritingMode();
   NS_WARNING_ASSERTION(aCBSize.BSize(cbwm) != NS_AUTOHEIGHT,
                        "containing block bsize must be constrained");
 
   NS_ASSERTION(aFrameType != LayoutFrameType::Table,
                "InitAbsoluteConstraints should not be called on table frames");
   NS_ASSERTION(mFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW,
                "Why are we here?");
 
@@ -1658,18 +1659,38 @@ void ReflowInput::InitAbsoluteConstraint
       mFlags.mBOffsetsNeedCSSAlign = (bStartIsAuto && bEndIsAuto);
     }
 
     if (mFlags.mStaticPosIsCBOrigin) {
       hypotheticalPos.mWritingMode = cbwm;
       hypotheticalPos.mIStart = nscoord(0);
       hypotheticalPos.mBStart = nscoord(0);
     } else {
+      // XXXmats all this is broken for orthogonal writing-modes: bug 1521988.
       CalculateHypotheticalPosition(aPresContext, placeholderFrame,
-                                    aReflowInput, hypotheticalPos, aFrameType);
+                                    aCBReflowInput, hypotheticalPos,
+                                    aFrameType);
+      if (aCBReflowInput->mFrame->IsGridContainerFrame()) {
+        // 'hypotheticalPos' is relative to the padding rect of the CB *frame*.
+        // In grid layout the CB is the grid area rectangle, so we translate
+        // 'hypotheticalPos' to be relative that rectangle here.
+        nsRect cb = nsGridContainerFrame::GridItemCB(mFrame);
+        nscoord left(0);
+        nscoord right(0);
+        if (cbwm.IsBidiLTR()) {
+          left = cb.X();
+        } else {
+          right = aCBReflowInput->ComputedWidth() +
+                  aCBReflowInput->ComputedPhysicalPadding().LeftRight() -
+                  cb.XMost();
+        }
+        LogicalMargin offsets(cbwm, nsMargin(cb.Y(), right, nscoord(0), left));
+        hypotheticalPos.mIStart -= offsets.IStart(cbwm);
+        hypotheticalPos.mBStart -= offsets.BStart(cbwm);
+      }
     }
   }
 
   // Initialize the 'left' and 'right' computed offsets
   // XXX Handle new 'static-position' value...
 
   // Size of the containing block in its writing mode
   LogicalSize cbSize = aCBSize;
--- a/layout/generic/ReflowInput.h
+++ b/layout/generic/ReflowInput.h
@@ -997,25 +997,25 @@ struct ReflowInput : public SizeComputat
   nsIFrame* GetHypotheticalBoxContainer(nsIFrame* aFrame,
                                         nscoord& aCBIStartEdge,
                                         mozilla::LogicalSize& aCBSize) const;
 
   // Calculate a "hypothetical box" position where the placeholder frame
   // (for a position:fixed/absolute element) would have been placed if it were
   // positioned statically. The hypothetical box position will have a writing
   // mode with the same block direction as the absolute containing block
-  // (aReflowInput->frame), though it may differ in inline direction.
+  // (aCBReflowInput->frame), though it may differ in inline direction.
   void CalculateHypotheticalPosition(nsPresContext* aPresContext,
                                      nsPlaceholderFrame* aPlaceholderFrame,
-                                     const ReflowInput* aReflowInput,
+                                     const ReflowInput* aCBReflowInput,
                                      nsHypotheticalPosition& aHypotheticalPos,
                                      mozilla::LayoutFrameType aFrameType) const;
 
   void InitAbsoluteConstraints(nsPresContext* aPresContext,
-                               const ReflowInput* aReflowInput,
+                               const ReflowInput* aCBReflowInput,
                                const mozilla::LogicalSize& aContainingBlockSize,
                                mozilla::LayoutFrameType aFrameType);
 
   // Calculates the computed values for the 'min-Width', 'max-Width',
   // 'min-Height', and 'max-Height' properties, and stores them in the assorted
   // data members
   void ComputeMinMaxValues(const mozilla::LogicalSize& aContainingBlockSize);
 
--- a/layout/generic/nsAbsoluteContainingBlock.cpp
+++ b/layout/generic/nsAbsoluteContainingBlock.cpp
@@ -724,32 +724,18 @@ void nsAbsoluteContainingBlock::ReflowAb
       border.IStart(outerWM) + offsets.IStart(outerWM) + margin.IStart(outerWM),
       border.BStart(outerWM) + offsets.BStart(outerWM) + margin.BStart(outerWM),
       kidSize.ISize(outerWM), kidSize.BSize(outerWM));
   nsRect r = rect.GetPhysicalRect(
       outerWM, logicalCBSize.GetPhysicalSize(wm) +
                    border.Size(outerWM).GetPhysicalSize(outerWM));
 
   // Offset the frame rect by the given origin of the absolute containing block.
-  // If the frame is auto-positioned on both sides of an axis, it will be
-  // positioned based on its containing block and we don't need to offset
-  // (unless the caller demands it (the STATIC_POS_IS_CB_ORIGIN case)).
-  if (aContainingBlock.TopLeft() != nsPoint(0, 0)) {
-    const nsStyleSides& offsets = kidReflowInput.mStylePosition->mOffset;
-    if (!(offsets.GetLeftUnit() == eStyleUnit_Auto &&
-          offsets.GetRightUnit() == eStyleUnit_Auto) ||
-        (rsFlags & ReflowInput::STATIC_POS_IS_CB_ORIGIN)) {
-      r.x += aContainingBlock.x;
-    }
-    if (!(offsets.GetTopUnit() == eStyleUnit_Auto &&
-          offsets.GetBottomUnit() == eStyleUnit_Auto) ||
-        (rsFlags & ReflowInput::STATIC_POS_IS_CB_ORIGIN)) {
-      r.y += aContainingBlock.y;
-    }
-  }
+  r.x += aContainingBlock.x;
+  r.y += aContainingBlock.y;
 
   aKidFrame->SetRect(r);
 
   nsView* view = aKidFrame->GetView();
   if (view) {
     // Size and position the view and set its opacity, visibility, content
     // transparency, and clip
     nsContainerFrame::SyncFrameViewAfterReflow(aPresContext, aKidFrame, view,
--- a/modules/libpref/init/StaticPrefList.h
+++ b/modules/libpref/init/StaticPrefList.h
@@ -496,27 +496,21 @@ VARCACHE_PREF(
 VARCACHE_PREF(
   "dom.block_multiple_popups",
    dom_block_multiple_popups,
   bool, true
 )
 
 // For area and anchor elements with target=_blank and no rel set to
 // opener/noopener, this pref sets noopener by default.
-#ifdef EARLY_BETA_OR_EARLIER
-#define PREF_VALUE true
-#else
-#define PREF_VALUE false
-#endif
 VARCACHE_PREF(
   "dom.targetBlankNoOpener.enabled",
    dom_targetBlankNoOpener_enabled,
-  bool, PREF_VALUE
+  bool, true
 )
-#undef PREF_VALUE
 
 VARCACHE_PREF(
   "dom.disable_open_during_load",
    dom_disable_open_during_load,
   bool, false
 )
 
 // Storage-access API.
@@ -1952,16 +1946,37 @@ VARCACHE_PREF(
 
 // Password protection
 VARCACHE_PREF(
   "browser.safebrowsing.passwords.enabled",
    browser_safebrowsing_passwords_enabled,
   bool, false
 )
 
+// Malware protection
+VARCACHE_PREF(
+  "browser.safebrowsing.malware.enabled",
+   browser_safebrowsing_malware_enabled,
+  bool, true
+)
+
+// Phishing protection
+VARCACHE_PREF(
+  "browser.safebrowsing.phishing.enabled",
+   browser_safebrowsing_phishing_enabled,
+  bool, true
+)
+
+// Blocked plugin content
+VARCACHE_PREF(
+  "browser.safebrowsing.blockedURIs.enabled",
+   browser_safebrowsing_blockedURIs_enabled,
+  bool, true
+)
+
 //---------------------------------------------------------------------------
 // ChannelClassifier prefs
 //---------------------------------------------------------------------------
 
 VARCACHE_PREF(
   "channelclassifier.allowlist_example",
    channelclassifier_allowlist_example,
   bool, false
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -5580,19 +5580,17 @@ pref("urlclassifier.gethash.timeout_ms",
 // Update server response timeout for Safe Browsing
 pref("urlclassifier.update.response_timeout_ms", 30000);
 // Download update timeout for Safe Browsing
 pref("urlclassifier.update.timeout_ms", 90000);
 
 // Name of the about: page to display Safe Browsing warnings (bug 399233)
 pref("urlclassifier.alternate_error_page", "blocked");
 
-// Enable phishing & malware protection.
-pref("browser.safebrowsing.phishing.enabled", true);
-pref("browser.safebrowsing.malware.enabled", true);
+// Enable safe-browsing debugging
 pref("browser.safebrowsing.debug", false);
 
 // Allow users to ignore Safe Browsing warnings.
 pref("browser.safebrowsing.allowOverride", true);
 
 // These names are approved by the Google Safe Browsing team.
 // Any changes must be coordinated with them.
 #ifdef MOZILLA_OFFICIAL
@@ -5645,17 +5643,16 @@ pref("browser.safebrowsing.provider.mozi
 // Set to a date in the past to force immediate download in new profiles.
 pref("browser.safebrowsing.provider.mozilla.nextupdatetime", "1");
 // Block lists for tracking protection. The name values will be used as the keys
 // to lookup the localized name in preferences.properties.
 pref("browser.safebrowsing.provider.mozilla.lists.base", "moz-std");
 pref("browser.safebrowsing.provider.mozilla.lists.content", "moz-full");
 
 // The table and global pref for blocking plugin content
-pref("browser.safebrowsing.blockedURIs.enabled", true);
 pref("urlclassifier.blockedTable", "test-block-simple,mozplugin-block-digest256");
 
 // Flash blocking tables
 pref("urlclassifier.flashAllowTable", "allow-flashallow-digest256");
 pref("urlclassifier.flashAllowExceptTable", "except-flashallow-digest256");
 pref("urlclassifier.flashTable", "block-flash-digest256");
 pref("urlclassifier.flashExceptTable", "except-flash-digest256");
 pref("urlclassifier.flashSubDocTable", "block-flashsubdoc-digest256");
--- a/netwerk/url-classifier/UrlClassifierFeatureFactory.cpp
+++ b/netwerk/url-classifier/UrlClassifierFeatureFactory.cpp
@@ -6,16 +6,17 @@
 
 #include "mozilla/net/UrlClassifierFeatureFactory.h"
 
 // List of Features
 #include "UrlClassifierFeatureCryptomining.h"
 #include "UrlClassifierFeatureFingerprinting.h"
 #include "UrlClassifierFeatureFlash.h"
 #include "UrlClassifierFeatureLoginReputation.h"
+#include "UrlClassifierFeaturePhishingProtection.h"
 #include "UrlClassifierFeatureTrackingProtection.h"
 #include "UrlClassifierFeatureTrackingAnnotation.h"
 #include "UrlClassifierFeatureCustomTables.h"
 
 #include "nsAppRunner.h"
 
 namespace mozilla {
 namespace net {
@@ -25,16 +26,17 @@ namespace net {
   if (!XRE_IsParentProcess()) {
     return;
   }
 
   UrlClassifierFeatureCryptomining::MaybeShutdown();
   UrlClassifierFeatureFingerprinting::MaybeShutdown();
   UrlClassifierFeatureFlash::MaybeShutdown();
   UrlClassifierFeatureLoginReputation::MaybeShutdown();
+  UrlClassifierFeaturePhishingProtection::MaybeShutdown();
   UrlClassifierFeatureTrackingAnnotation::MaybeShutdown();
   UrlClassifierFeatureTrackingProtection::MaybeShutdown();
 }
 
 /* static */ void UrlClassifierFeatureFactory::GetFeaturesFromChannel(
     nsIChannel* aChannel,
     nsTArray<nsCOMPtr<nsIUrlClassifierFeature>>& aFeatures) {
   MOZ_ASSERT(XRE_IsParentProcess());
@@ -72,16 +74,21 @@ namespace net {
   }
 
   // Flash
   nsTArray<nsCOMPtr<nsIUrlClassifierFeature>> flashFeatures;
   UrlClassifierFeatureFlash::MaybeCreate(aChannel, flashFeatures);
   aFeatures.AppendElements(flashFeatures);
 }
 
+/* static */ void UrlClassifierFeatureFactory::GetPhishingProtectionFeatures(
+    nsTArray<RefPtr<nsIUrlClassifierFeature>>& aFeatures) {
+  UrlClassifierFeaturePhishingProtection::MaybeCreate(aFeatures);
+}
+
 /* static */
 nsIUrlClassifierFeature*
 UrlClassifierFeatureFactory::GetFeatureLoginReputation() {
   return UrlClassifierFeatureLoginReputation::MaybeGetOrCreate();
 }
 
 /* static */ already_AddRefed<nsIUrlClassifierFeature>
 UrlClassifierFeatureFactory::GetFeatureByName(const nsACString& aName) {
@@ -122,16 +129,22 @@ UrlClassifierFeatureFactory::GetFeatureB
   }
 
   // We use Flash feature just for document loading.
   feature = UrlClassifierFeatureFlash::GetIfNameMatches(aName);
   if (feature) {
     return feature.forget();
   }
 
+  // PhishingProtection features
+  feature = UrlClassifierFeaturePhishingProtection::GetIfNameMatches(aName);
+  if (feature) {
+    return feature.forget();
+  }
+
   return nullptr;
 }
 
 /* static */ void UrlClassifierFeatureFactory::GetFeatureNames(
     nsTArray<nsCString>& aArray) {
   if (!XRE_IsParentProcess()) {
     return;
   }
@@ -163,19 +176,28 @@ UrlClassifierFeatureFactory::GetFeatureB
 
   // Login reputation
   name.Assign(UrlClassifierFeatureLoginReputation::Name());
   if (!name.IsEmpty()) {
     aArray.AppendElement(name);
   }
 
   // Flash features
-  nsTArray<nsCString> features;
-  UrlClassifierFeatureFlash::GetFeatureNames(features);
-  aArray.AppendElements(features);
+  {
+    nsTArray<nsCString> features;
+    UrlClassifierFeatureFlash::GetFeatureNames(features);
+    aArray.AppendElements(features);
+  }
+
+  // PhishingProtection features
+  {
+    nsTArray<nsCString> features;
+    UrlClassifierFeaturePhishingProtection::GetFeatureNames(features);
+    aArray.AppendElements(features);
+  }
 }
 
 /* static */ already_AddRefed<nsIUrlClassifierFeature>
 UrlClassifierFeatureFactory::CreateFeatureWithTables(
     const nsACString& aName, const nsTArray<nsCString>& aBlacklistTables,
     const nsTArray<nsCString>& aWhitelistTables) {
   nsCOMPtr<nsIUrlClassifierFeature> feature =
       new UrlClassifierFeatureCustomTables(aName, aBlacklistTables,
--- a/netwerk/url-classifier/UrlClassifierFeatureFactory.h
+++ b/netwerk/url-classifier/UrlClassifierFeatureFactory.h
@@ -19,16 +19,19 @@ namespace net {
 class UrlClassifierFeatureFactory final {
  public:
   static void Shutdown();
 
   static void GetFeaturesFromChannel(
       nsIChannel* aChannel,
       nsTArray<nsCOMPtr<nsIUrlClassifierFeature>>& aFeatures);
 
+  static void GetPhishingProtectionFeatures(
+      nsTArray<RefPtr<nsIUrlClassifierFeature>>& aFeatures);
+
   static nsIUrlClassifierFeature* GetFeatureLoginReputation();
 
   static already_AddRefed<nsIUrlClassifierFeature> GetFeatureByName(
       const nsACString& aFeatureName);
 
   static void GetFeatureNames(nsTArray<nsCString>& aArray);
 
   static already_AddRefed<nsIUrlClassifierFeature> CreateFeatureWithTables(
new file mode 100644
--- /dev/null
+++ b/netwerk/url-classifier/UrlClassifierFeaturePhishingProtection.cpp
@@ -0,0 +1,121 @@
+/* -*- 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/. */
+
+#include "UrlClassifierFeaturePhishingProtection.h"
+
+namespace mozilla {
+namespace net {
+
+struct UrlClassifierFeaturePhishingProtection::PhishingProtectionFeature {
+  const char* mName;
+  const char* mBlacklistPrefTables;
+  bool (*mPref)();
+
+  RefPtr<UrlClassifierFeaturePhishingProtection> mFeature;
+};
+
+namespace {
+
+struct UrlClassifierFeaturePhishingProtection::PhishingProtectionFeature
+    sPhishingProtectionFeaturesMap[] = {
+        {"malware", "urlclassifier.malwareTable",
+         StaticPrefs::browser_safebrowsing_malware_enabled},
+        {"phishing", "urlclassifier.phishTable",
+         StaticPrefs::browser_safebrowsing_phishing_enabled},
+        {"blockedURIs", "urlclassifier.blockedTable",
+         StaticPrefs::browser_safebrowsing_blockedURIs_enabled},
+};
+
+}  // namespace
+
+UrlClassifierFeaturePhishingProtection::UrlClassifierFeaturePhishingProtection(
+    const UrlClassifierFeaturePhishingProtection::PhishingProtectionFeature&
+        aFeature)
+    : UrlClassifierFeatureBase(
+          nsDependentCString(aFeature.mName),
+          nsDependentCString(aFeature.mBlacklistPrefTables),
+          EmptyCString(),    // aPrefWhitelistPrefTbles,
+          EmptyCString(),    // aPrefBlacklistHosts
+          EmptyCString(),    // aPrefWhitelistHosts
+          EmptyCString(),    // aPrefBlacklistTableName
+          EmptyCString(),    // aPrefWhitelistTableName
+          EmptyCString()) {  // aPrefSkipHosts
+}
+
+/* static */ void UrlClassifierFeaturePhishingProtection::GetFeatureNames(
+    nsTArray<nsCString>& aArray) {
+  for (const PhishingProtectionFeature& feature :
+       sPhishingProtectionFeaturesMap) {
+    if (feature.mPref()) {
+      aArray.AppendElement(nsDependentCString(feature.mName));
+    }
+  }
+}
+
+/* static */ void UrlClassifierFeaturePhishingProtection::MaybeInitialize() {
+  for (PhishingProtectionFeature& feature : sPhishingProtectionFeaturesMap) {
+    if (!feature.mFeature && feature.mPref()) {
+      feature.mFeature = new UrlClassifierFeaturePhishingProtection(feature);
+      feature.mFeature->InitializePreferences();
+    }
+  }
+}
+
+/* static */ void UrlClassifierFeaturePhishingProtection::MaybeShutdown() {
+  for (PhishingProtectionFeature& feature : sPhishingProtectionFeaturesMap) {
+    if (feature.mFeature) {
+      feature.mFeature->ShutdownPreferences();
+      feature.mFeature = nullptr;
+    }
+  }
+}
+
+/* static */ void UrlClassifierFeaturePhishingProtection::MaybeCreate(
+    nsTArray<RefPtr<nsIUrlClassifierFeature>>& aFeatures) {
+  MaybeInitialize();
+
+  for (const PhishingProtectionFeature& feature :
+       sPhishingProtectionFeaturesMap) {
+    if (feature.mPref()) {
+      MOZ_ASSERT(feature.mFeature);
+      aFeatures.AppendElement(feature.mFeature);
+    }
+  }
+}
+
+/* static */ already_AddRefed<nsIUrlClassifierFeature>
+UrlClassifierFeaturePhishingProtection::GetIfNameMatches(
+    const nsACString& aName) {
+  MaybeInitialize();
+
+  for (const PhishingProtectionFeature& feature :
+       sPhishingProtectionFeaturesMap) {
+    if (feature.mPref() && aName.Equals(feature.mName)) {
+      MOZ_ASSERT(feature.mFeature);
+      nsCOMPtr<nsIUrlClassifierFeature> self = feature.mFeature.get();
+      return self.forget();
+    }
+  }
+
+  return nullptr;
+}
+
+NS_IMETHODIMP
+UrlClassifierFeaturePhishingProtection::ProcessChannel(nsIChannel* aChannel,
+                                                       const nsACString& aList,
+                                                       bool* aShouldContinue) {
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+UrlClassifierFeaturePhishingProtection::GetURIByListType(
+    nsIChannel* aChannel, nsIUrlClassifierFeature::listType aListType,
+    nsIURI** aURI) {
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+}  // namespace net
+}  // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/netwerk/url-classifier/UrlClassifierFeaturePhishingProtection.h
@@ -0,0 +1,48 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_UrlClassifierFeaturePhishingProtection_h
+#define mozilla_UrlClassifierFeaturePhishingProtection_h
+
+#include "UrlClassifierFeatureBase.h"
+
+namespace mozilla {
+namespace net {
+
+class UrlClassifierFeaturePhishingProtection final
+    : public UrlClassifierFeatureBase {
+ public:
+  struct PhishingProtectionFeature;
+
+  static void GetFeatureNames(nsTArray<nsCString>& aNames);
+
+  static void MaybeShutdown();
+
+  static void MaybeCreate(
+      nsTArray<RefPtr<nsIUrlClassifierFeature>>& aFeatures);
+
+  static already_AddRefed<nsIUrlClassifierFeature> GetIfNameMatches(
+      const nsACString& aName);
+
+  NS_IMETHOD
+  ProcessChannel(nsIChannel* aChannel, const nsACString& aList,
+                 bool* aShouldContinue) override;
+
+  NS_IMETHOD GetURIByListType(nsIChannel* aChannel,
+                              nsIUrlClassifierFeature::listType aListType,
+                              nsIURI** aURI) override;
+
+ private:
+  explicit UrlClassifierFeaturePhishingProtection(
+      const PhishingProtectionFeature& aFeature);
+
+  static void MaybeInitialize();
+};
+
+}  // namespace net
+}  // namespace mozilla
+
+#endif  // mozilla_UrlClassifierFeaturePhishingProtection_h
--- a/netwerk/url-classifier/moz.build
+++ b/netwerk/url-classifier/moz.build
@@ -23,16 +23,17 @@ UNIFIED_SOURCES += [
     'UrlClassifierCommon.cpp',
     'UrlClassifierFeatureBase.cpp',
     'UrlClassifierFeatureCryptomining.cpp',
     'UrlClassifierFeatureCustomTables.cpp',
     'UrlClassifierFeatureFactory.cpp',
     'UrlClassifierFeatureFingerprinting.cpp',
     'UrlClassifierFeatureFlash.cpp',
     'UrlClassifierFeatureLoginReputation.cpp',
+    'UrlClassifierFeaturePhishingProtection.cpp',
     'UrlClassifierFeatureResult.cpp',
     'UrlClassifierFeatureTrackingAnnotation.cpp',
     'UrlClassifierFeatureTrackingProtection.cpp',
 ]
 
 EXPORTS.mozilla.net += [
     'AsyncUrlChannelClassifier.h',
     'UrlClassifierCommon.h',
--- a/python/mozbuild/mozbuild/action/check_binary.py
+++ b/python/mozbuild/mozbuild/action/check_binary.py
@@ -312,16 +312,53 @@ def check_mozglue_order(target, binary):
         if libc is None:
             raise RuntimeError('libc.so is not linked?')
         if mozglue is not None and libc < mozglue:
             raise RuntimeError('libmozglue.so must be linked before libc.so')
     except Empty:
         raise RuntimeError('Could not parse readelf output?')
 
 
+def check_networking(binary):
+    retcode = 0
+    networking_functions = set([
+        # socketpair is not concerning; it is restricted to AF_UNIX
+        "socket", "connect", "accept", "bind", "listen",
+        "getsockname", "getsockopt", "setsockopt",
+        "recv", "recvfrom",
+        "send", "sendto",
+        # We would be concerned by recvmsg and sendmsg; but we believe
+        # they are okay as documented in 1376621#c23
+        "gethostbyname", "gethostbyaddr", "gethostent", "sethostent", "endhostent",
+        "gethostent_r", "gethostbyname2", "gethostbyaddr_r", "gethostbyname_r",
+        "gethostbyname2_r",
+        "getaddrinfo", "getservent", "getservbyname", "getservbyport", "setservent",
+        "getprotoent", "getprotobyname", "getprotobynumber", "setprotoent",
+        "endprotoent"])
+    bad_occurences_names = set()
+
+    try:
+        for sym in at_least_one(iter_symbols(binary)):
+            if sym['addr'] == 0 and sym['name'] in networking_functions:
+                bad_occurences_names.add(sym['name'])
+    except Empty:
+        raise RuntimeError('Could not parse llvm-objdump output?')
+
+    basename = os.path.basename(binary)
+    if bad_occurences_names:
+        s = 'TEST-UNEXPECTED-FAIL | check_networking | {} | Identified {} ' + \
+            'networking function(s) being imported in the rust static library ({})'
+        print(s.format(basename, len(bad_occurences_names),
+            ",".join(sorted(bad_occurences_names))),
+            file=sys.stderr)
+        retcode = 1
+    elif buildconfig.substs.get('MOZ_AUTOMATION'):
+        print('TEST-PASS | check_networking | {}'.format(basename))
+    return retcode
+
 def checks(target, binary):
     # The clang-plugin is built as target but is really a host binary.
     # Cheat and pretend we were passed the right argument.
     if 'clang-plugin' in binary:
         target = HOST
     checks = []
     if target['MOZ_LIBSTDCXX_VERSION']:
         checks.append(check_stdcxx)
@@ -357,27 +394,36 @@ def checks(target, binary):
 def main(args):
     parser = argparse.ArgumentParser(
         description='Check built binaries')
 
     parser.add_argument('--host', action='store_true',
                         help='Perform checks for a host binary')
     parser.add_argument('--target', action='store_true',
                         help='Perform checks for a target binary')
+    parser.add_argument('--networking', action='store_true',
+                        help='Perform checks for networking functions')
 
     parser.add_argument('binary', metavar='PATH',
                         help='Location of the binary to check')
 
     options = parser.parse_args(args)
 
     if options.host == options.target:
         print('Exactly one of --host or --target must be given',
               file=sys.stderr)
         return 1
 
-    if options.host:
+    if options.networking and options.host:
+        print('--networking is only valid with --target',
+               file=sys.stderr)
+        return 1
+
+    if options.networking:
+        return check_networking(options.binary)
+    elif options.host:
         return checks(HOST, options.binary)
     elif options.target:
         return checks(TARGET, options.binary)
 
 
 if __name__ == '__main__':
     sys.exit(main(sys.argv[1:]))
--- a/security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp
+++ b/security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp
@@ -47,16 +47,17 @@ static UniquePtr<nsString> sPluginTempDi
 static UniquePtr<nsString> sRoamingAppDataDir;
 static UniquePtr<nsString> sLocalAppDataDir;
 static UniquePtr<nsString> sUserExtensionsDevDir;
 #ifdef ENABLE_SYSTEM_EXTENSION_DIRS
 static UniquePtr<nsString> sUserExtensionsDir;
 #endif
 
 // Cached prefs which are needed off main thread.
+static bool sRddWin32kDisable = false;
 static bool sGmpWin32kDisable = false;
 
 static LazyLogModule sSandboxBrokerLog("SandboxBroker");
 
 #define LOG_E(...) MOZ_LOG(sSandboxBrokerLog, LogLevel::Error, (__VA_ARGS__))
 #define LOG_W(...) MOZ_LOG(sSandboxBrokerLog, LogLevel::Warning, (__VA_ARGS__))
 
 // Used to store whether we have accumulated an error combination for this
@@ -124,16 +125,18 @@ void SandboxBroker::GeckoDependentInitia
 #endif
 
   // Create sLaunchErrors up front because ClearOnShutdown must be called on the
   // main thread.
   sLaunchErrors = MakeUnique<nsTHashtable<nsCStringHashKey>>();
   ClearOnShutdown(&sLaunchErrors);
 
   // Cache prefs that are needed off main thread.
+  Preferences::AddBoolVarCache(&sRddWin32kDisable,
+                               "security.sandbox.rdd.win32k-disable");
   Preferences::AddBoolVarCache(&sGmpWin32kDisable,
                                "security.sandbox.gmp.win32k-disable");
 }
 
 SandboxBroker::SandboxBroker() {
   if (sBrokerService) {
     scoped_refptr<sandbox::TargetPolicy> policy =
         sBrokerService->CreatePolicy();
@@ -490,16 +493,21 @@ void SandboxBroker::SetSecurityLevelForC
   if (aSandboxLevel == 1 || aIsFileProcess) {
     result =
         mPolicy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES,
                          sandbox::TargetPolicy::FILES_ALLOW_READONLY, L"*");
     MOZ_RELEASE_ASSERT(sandbox::SBOX_ALL_OK == result,
                        "With these static arguments AddRule should never fail, "
                        "what happened?");
   } else {
+    // Add rule to allow access to user specific fonts.
+    AddCachedDirRule(mPolicy, sandbox::TargetPolicy::FILES_ALLOW_READONLY,
+                     sLocalAppDataDir,
+                     NS_LITERAL_STRING("\\Microsoft\\Windows\\Fonts\\*"));
+
     // Add rule to allow read access to installation directory.
     AddCachedDirRule(mPolicy, sandbox::TargetPolicy::FILES_ALLOW_READONLY,
                      sBinDir, NS_LITERAL_STRING("\\*"));
 
     // Add rule to allow read access to the chrome directory within profile.
     AddCachedDirRule(mPolicy, sandbox::TargetPolicy::FILES_ALLOW_READONLY,
                      sProfileDir, NS_LITERAL_STRING("\\chrome\\*"));
 
@@ -715,23 +723,31 @@ bool SandboxBroker::SetSecurityLevelForR
   SANDBOX_ENSURE_SUCCESS(result,
                          "SetDelayedIntegrityLevel should never fail with "
                          "these arguments, what happened?");
 
   sandbox::MitigationFlags mitigations =
       sandbox::MITIGATION_BOTTOM_UP_ASLR | sandbox::MITIGATION_HEAP_TERMINATE |
       sandbox::MITIGATION_SEHOP | sandbox::MITIGATION_EXTENSION_POINT_DISABLE |
       sandbox::MITIGATION_DEP_NO_ATL_THUNK | sandbox::MITIGATION_DEP |
-      sandbox::MITIGATION_DYNAMIC_CODE_DISABLE |
       sandbox::MITIGATION_IMAGE_LOAD_PREFER_SYS32;
 
+  if (sRddWin32kDisable) {
+    mitigations |= sandbox::MITIGATION_WIN32K_DISABLE;
+    result =
+        mPolicy->AddRule(sandbox::TargetPolicy::SUBSYS_WIN32K_LOCKDOWN,
+                         sandbox::TargetPolicy::FAKE_USER_GDI_INIT, nullptr);
+    SANDBOX_ENSURE_SUCCESS(result, "Failed to set FAKE_USER_GDI_INIT policy.");
+  }
+
   result = mPolicy->SetProcessMitigations(mitigations);
   SANDBOX_ENSURE_SUCCESS(result, "Invalid flags for SetProcessMitigations.");
 
   mitigations = sandbox::MITIGATION_STRICT_HANDLE_CHECKS |
+                sandbox::MITIGATION_DYNAMIC_CODE_DISABLE |
                 sandbox::MITIGATION_DLL_SEARCH_ORDER;
 
   result = mPolicy->SetDelayedProcessMitigations(mitigations);
   SANDBOX_ENSURE_SUCCESS(result,
                          "Invalid flags for SetDelayedProcessMitigations.");
 
   // Add the policy for the client side of a pipe. It is just a file
   // in the \pipe\ namespace. We restrict it to pipes that start with
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-grid/abspos/descendant-static-position-001-ref.html
@@ -0,0 +1,71 @@
+<!DOCTYPE html>
+<html><head>
+<meta charset="utf-8">
+<title>CSS Grid Layout Reference: Grid aligned descendants with static position</title>
+<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
+<style>
+.grid {
+  position: relative;
+  display: grid;
+  grid: 40px / 40px;
+  border: 2px solid;
+  border-top-width: 5px;
+  border-left-width: 3px;
+  width: 20px;
+  padding: 2px 4px 6px 1px;
+}
+.absolute {
+  position: absolute;
+  grid-column: 1 / 2;
+}
+.content {
+  float: left;
+  width: 20px;
+  height: 40px;
+  background: green;
+}
+.content:nth-child(2) {
+  background: grey;
+}
+
+</style></head>
+<body>
+There should be no red:
+
+<div class="grid">
+    <div class="absolute" style="margin-top:2px">
+      <div class="content"></div>
+      <div class="content"></div>
+    </div>
+</div>
+
+<div class="grid" style="grid-template-columns: 43px">
+    <div class="absolute" style="margin-top:2px; margin-left:3px">
+      <div class="content"></div>
+      <div class="content"></div>
+    </div>
+</div>
+
+<div class="grid" style="grid-template-columns: 43px">
+    <div class="absolute" style="margin-top:2px; border-left:2px solid black; padding-left:1px">
+      <div class="content"></div>
+      <div class="content"></div>
+    </div>
+</div>
+
+<div class="grid" style="padding-bottom: 14px">
+    <div class="absolute" style="margin-top:10px">
+      <div class="content"></div>
+      <div class="content"></div>
+    </div>
+</div>
+
+<div class="grid" style="grid-template-columns: 43px; padding-left:8px">
+    <div class="absolute" style="margin-top:2px; margin-left:3px">
+      <div class="content"></div>
+      <div class="content"></div>
+    </div>
+</div>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-grid/abspos/descendant-static-position-001.html
@@ -0,0 +1,90 @@
+<!DOCTYPE html>
+<html><head>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: Grid aligned descendants with static position</title>
+<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
+<link rel="help" href="https://drafts.csswg.org/css-grid-1/#abspos" title="Absolute Positioning">
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#staticpos-rect" title="Appendix A: Static Position Terminology">
+<link rel="match" href="descendant-static-position-001-ref.html">
+<meta name="assert" content="This test checks that the position and size of the abs.pos. descendant is correct.">
+<style>
+.grid {
+  position: relative;
+  display: grid;
+  grid: 40px / 40px;
+  border: 2px solid;
+  border-top-width: 5px;
+  border-left-width: 3px;
+  width: 20px;
+  padding: 2px 4px 6px 1px;
+}
+.grid > div {
+  background: red;
+  background-clip: content-box;
+}
+.absolute {
+  position: absolute;
+  background: red;
+  grid-column: 1 / 2;
+}
+.content {
+  float: left;
+  width: 20px;
+  height: 40px;
+  background: green;
+}
+.content:nth-child(2) {
+  background: grey;
+}
+
+</style></head>
+<body>
+There should be no red:
+
+<div class="grid">
+  <div>
+    <div class="absolute">
+      <div class="content"></div>
+      <div class="content"></div>
+    </div>
+  </div>
+</div>
+
+<div class="grid" style="grid-template-columns: 43px">
+  <div style="padding-left:3px">
+    <div class="absolute">
+      <div class="content"></div>
+      <div class="content"></div>
+    </div>
+  </div>
+</div>
+
+<div class="grid" style="grid-template-columns: 43px">
+  <div style="border-left:2px solid black; padding-left:1px">
+    <div class="absolute">
+      <div class="content"></div>
+      <div class="content"></div>
+    </div>
+  </div>
+</div>
+
+<div class="grid" style="padding-top:10px">
+  <div>
+    <div class="absolute">
+      <div class="content"></div>
+      <div class="content"></div>
+    </div>
+  </div>
+</div>
+
+<div class="grid" style="grid-template-columns: 10px 33px; padding-left:8px">
+  <div style="padding-left:3px">
+    <div class="absolute" style="grid-column: 2 / 3">
+      <div class="content"></div>
+      <div class="content"></div>
+    </div>
+  </div>
+</div>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-grid/abspos/descendant-static-position-002-ref.html
@@ -0,0 +1,80 @@
+<!DOCTYPE html>
+<html><head>
+<meta charset="utf-8">
+<title>CSS Grid Layout Reference: Grid aligned descendants with static position (direction: rtl)</title>
+<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
+<style>
+.grid {
+  position: relative;
+  display: grid;
+  grid: 40px / 40px;
+  border: 2px solid;
+  border-top-width: 5px;
+  border-left-width: 3px;
+  width: 20px;
+  padding: 2px 4px 6px 1px;
+  direction: rtl;
+  margin-left: 40px;
+}
+.absolute {
+  position: absolute;
+  grid-column: 1 / 2;
+}
+.content {
+  float: right;
+  width: 20px;
+  height: 40px;
+  background: green;
+}
+.content:nth-child(2) {
+  background: grey;
+}
+
+</style></head>
+<body>
+There should be no red:
+
+<div class="grid">
+    <div class="absolute" style="margin-top:2px">
+      <div class="content"></div>
+      <div class="content"></div>
+    </div>
+</div>
+
+<div class="grid" style="grid-template-columns: 43px">
+    <div class="absolute" style="margin-top:2px; margin-left:3px">
+      <div class="content"></div>
+      <div class="content"></div>
+    </div>
+</div>
+
+<div class="grid" style="grid-template-columns: 43px">
+    <div class="absolute" style="margin-top:2px; border-left:2px solid black; padding-left:1px">
+      <div class="content"></div>
+      <div class="content"></div>
+    </div>
+</div>
+
+<div class="grid" style="padding-bottom: 14px">
+    <div class="absolute" style="margin-top:10px">
+      <div class="content"></div>
+      <div class="content"></div>
+    </div>
+</div>
+
+<div class="grid" style="grid-template-columns: 43px; padding-right:8px">
+    <div class="absolute" style="margin-top:2px; margin-left:3px">
+      <div class="content"></div>
+      <div class="content"></div>
+    </div>
+</div>
+
+<div class="grid" style="grid-template-columns: 43px; padding-right:8px; padding-left:10px">
+    <div class="absolute" style="margin-top:2px;">
+      <div class="content"></div>
+      <div class="content"></div>
+    </div>
+</div>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-grid/abspos/descendant-static-position-002.html
@@ -0,0 +1,101 @@
+<!DOCTYPE html>
+<html><head>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: Grid aligned descendants with static position (direction: rtl)</title>
+<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
+<link rel="help" href="https://drafts.csswg.org/css-grid-1/#abspos" title="Absolute Positioning">
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#staticpos-rect" title="Appendix A: Static Position Terminology">
+<link rel="match" href="descendant-static-position-002-ref.html">
+<meta name="assert" content="This test checks that the position and size of the abs.pos. descendant is correct.">
+<style>
+.grid {
+  position: relative;
+  display: grid;
+  grid: 40px / 40px;
+  border: 2px solid;
+  border-top-width: 5px;
+  border-left-width: 3px;
+  width: 20px;
+  padding: 2px 4px 6px 1px;
+  direction: rtl;
+  margin-left: 40px;
+}
+.grid > div {
+  background: red;
+  background-clip: content-box;
+}
+.absolute {
+  position: absolute;
+  background: red;
+  grid-column: 1 / 2;
+}
+.content {
+  float: right;
+  width: 20px;
+  height: 40px;
+  background: green;
+}
+.content:nth-child(2) {
+  background: grey;
+}
+
+</style></head>
+<body>
+There should be no red:
+
+<div class="grid">
+  <div>
+    <div class="absolute">
+      <div class="content"></div>
+      <div class="content"></div>
+    </div>
+  </div>
+</div>
+
+<div class="grid" style="grid-template-columns: 43px">
+  <div style="padding-left:3px">
+    <div class="absolute">
+      <div class="content"></div>
+      <div class="content"></div>
+    </div>
+  </div>
+</div>
+
+<div class="grid" style="grid-template-columns: 43px">
+  <div style="border-left:2px solid black; padding-left:1px">
+    <div class="absolute">
+      <div class="content"></div>
+      <div class="content"></div>
+    </div>
+  </div>
+</div>
+
+<div class="grid" style="padding-top:10px">
+  <div>
+    <div class="absolute">
+      <div class="content"></div>
+      <div class="content"></div>
+    </div>
+  </div>
+</div>
+
+<div class="grid" style="grid-template-columns: 10px 33px; padding-right:8px">
+  <div style="padding-left:3px">
+    <div class="absolute" style="grid-column: 2 / 3">
+      <div class="content"></div>
+      <div class="content"></div>
+    </div>
+  </div>
+</div>
+
+<div class="grid" style="grid-template-columns: 10px 33px; padding-right:8px; padding-left:10px">
+  <div style="padding-left:3px">
+    <div class="absolute" style="grid-column: 2 / 3">
+      <div class="content"></div>
+      <div class="content"></div>
+    </div>
+  </div>
+</div>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-grid/abspos/descendant-static-position-003-ref.html
@@ -0,0 +1,72 @@
+<!DOCTYPE html>
+<html><head>
+<meta charset="utf-8">
+<title>CSS Grid Layout Reference: Grid aligned descendants with static position</title>
+<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
+<style>
+.grid {
+  position: relative;
+  display: grid;
+  grid: 40px / 40px;
+  border: 2px solid;
+  border-top-width: 5px;
+  border-left-width: 3px;
+  width: 100px;
+  justify-content: end;
+  padding: 2px 4px 6px 1px;
+}
+.absolute {
+  position: absolute;
+  grid-column: 1 / 2;
+}
+.content {
+  float: left;
+  width: 20px;
+  height: 40px;
+  background: green;
+}
+.content:nth-child(2) {
+  background: grey;
+}
+
+</style></head>
+<body>
+There should be no red:
+
+<div class="grid">
+    <div class="absolute" style="margin-top:2px">
+      <div class="content"></div>
+      <div class="content"></div>
+    </div>
+</div>
+
+<div class="grid" style="grid-template-columns: 43px">
+    <div class="absolute" style="margin-top:2px; margin-left:3px">
+      <div class="content"></div>
+      <div class="content"></div>
+    </div>
+</div>
+
+<div class="grid" style="grid-template-columns: 43px">
+    <div class="absolute" style="margin-top:2px; border-left:2px solid black; padding-left:1px">
+      <div class="content"></div>
+      <div class="content"></div>
+    </div>
+</div>
+
+<div class="grid" style="padding-bottom: 14px">
+    <div class="absolute" style="margin-top:10px">
+      <div class="content"></div>
+      <div class="content"></div>
+    </div>
+</div>
+
+<div class="grid" style="grid-template-columns: 43px; padding-left:8px">
+    <div class="absolute" style="margin-top:2px; margin-left:3px">
+      <div class="content"></div>
+      <div class="content"></div>
+    </div>
+</div>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-grid/abspos/descendant-static-position-003.html
@@ -0,0 +1,91 @@
+<!DOCTYPE html>
+<html><head>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: Grid aligned descendants with static position</title>
+<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
+<link rel="help" href="https://drafts.csswg.org/css-grid-1/#abspos" title="Absolute Positioning">
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#staticpos-rect" title="Appendix A: Static Position Terminology">
+<link rel="match" href="descendant-static-position-003-ref.html">
+<meta name="assert" content="This test checks that the position and size of the abs.pos. descendant is correct.">
+<style>
+.grid {
+  position: relative;
+  display: grid;
+  grid: 40px / 40px;
+  border: 2px solid;
+  border-top-width: 5px;
+  border-left-width: 3px;
+  width: 100px;
+  justify-content: end;
+  padding: 2px 4px 6px 1px;
+}
+.grid > div {
+  background: red;
+  background-clip: content-box;
+}
+.absolute {
+  position: absolute;
+  background: red;
+  grid-column: 1 / 2;
+}
+.content {
+  float: left;
+  width: 20px;
+  height: 40px;
+  background: green;
+}
+.content:nth-child(2) {
+  background: grey;
+}
+
+</style></head>
+<body>
+There should be no red:
+
+<div class="grid">
+  <div>
+    <div class="absolute">
+      <div class="content"></div>
+      <div class="content"></div>
+    </div>
+  </div>
+</div>
+
+<div class="grid" style="grid-template-columns: 43px">
+  <div style="padding-left:3px">
+    <div class="absolute">
+      <div class="content"></div>
+      <div class="content"></div>
+    </div>
+  </div>
+</div>
+
+<div class="grid" style="grid-template-columns: 43px">
+  <div style="border-left:2px solid black; padding-left:1px">
+    <div class="absolute">
+      <div class="content"></div>
+      <div class="content"></div>
+    </div>
+  </div>
+</div>
+
+<div class="grid" style="padding-top:10px">
+  <div>
+    <div class="absolute">
+      <div class="content"></div>
+      <div class="content"></div>
+    </div>
+  </div>
+</div>
+
+<div class="grid" style="grid-template-columns: 10px 33px; padding-left:8px">
+  <div style="padding-left:3px">
+    <div class="absolute" style="grid-column: 2 / 3">
+      <div class="content"></div>
+      <div class="content"></div>
+    </div>
+  </div>
+</div>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-grid/abspos/descendant-static-position-004-ref.html
@@ -0,0 +1,81 @@
+<!DOCTYPE html>
+<html><head>
+<meta charset="utf-8">
+<title>CSS Grid Layout Reference: Grid aligned descendants with static position (direction: rtl)</title>
+<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
+<style>
+.grid {
+  position: relative;
+  display: grid;
+  grid: 40px / 40px;
+  border: 2px solid;
+  border-top-width: 5px;
+  border-left-width: 3px;
+  width: 100px;
+  justify-content: center;
+  padding: 2px 4px 6px 1px;
+  direction: rtl;
+  margin-left: 40px;
+}
+.absolute {
+  position: absolute;
+  grid-column: 1 / 2;
+}
+.content {
+  float: right;
+  width: 20px;
+  height: 40px;
+  background: green;
+}
+.content:nth-child(2) {
+  background: grey;
+}
+
+</style></head>
+<body>
+There should be no red:
+
+<div class="grid">
+    <div class="absolute" style="margin-top:2px">
+      <div class="content"></div>
+      <div class="content"></div>
+    </div>
+</div>
+
+<div class="grid" style="grid-template-columns: 43px">
+    <div class="absolute" style="margin-top:2px; margin-left:3px">
+      <div class="content"></div>
+      <div class="content"></div>
+    </div>
+</div>
+
+<div class="grid" style="grid-template-columns: 43px">
+    <div class="absolute" style="margin-top:2px; border-left:2px solid black; padding-left:1px">
+      <div class="content"></div>
+      <div class="content"></div>
+    </div>
+</div>
+
+<div class="grid" style="padding-bottom: 14px">
+    <div class="absolute" style="margin-top:10px">
+      <div class="content"></div>
+      <div class="content"></div>
+    </div>
+</div>
+
+<div class="grid" style="grid-template-columns: 43px; padding-right:8px">
+    <div class="absolute" style="margin-top:2px; margin-left:3px">
+      <div class="content"></div>
+      <div class="content"></div>
+    </div>
+</div>
+
+<div class="grid" style="grid-template-columns: 43px; padding-right:8px; padding-left:10px">
+    <div class="absolute" style="margin-top:2px;">
+      <div class="content"></div>
+      <div class="content"></div>
+    </div>
+</div>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-grid/abspos/descendant-static-position-004.html
@@ -0,0 +1,102 @@
+<!DOCTYPE html>
+<html><head>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: Grid aligned descendants with static position (direction: rtl)</title>
+<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
+<link rel="help" href="https://drafts.csswg.org/css-grid-1/#abspos" title="Absolute Positioning">
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#staticpos-rect" title="Appendix A: Static Position Terminology">
+<link rel="match" href="descendant-static-position-004-ref.html">
+<meta name="assert" content="This test checks that the position and size of the abs.pos. descendant is correct.">
+<style>
+.grid {
+  position: relative;
+  display: grid;
+  grid: 40px / 40px;
+  border: 2px solid;
+  border-top-width: 5px;
+  border-left-width: 3px;
+  width: 100px;
+  justify-content: center;
+  padding: 2px 4px 6px 1px;
+  direction: rtl;
+  margin-left: 40px;
+}
+.grid > div {
+  background: red;
+  background-clip: content-box;
+}
+.absolute {
+  position: absolute;
+  background: red;
+  grid-column: 1 / 2;
+}
+.content {
+  float: right;
+  width: 20px;
+  height: 40px;
+  background: green;
+}
+.content:nth-child(2) {
+  background: grey;
+}
+
+</style></head>
+<body>
+There should be no red:
+
+<div class="grid">
+  <div>
+    <div class="absolute">
+      <div class="content"></div>
+      <div class="content"></div>
+    </div>
+  </div>
+</div>
+
+<div class="grid" style="grid-template-columns: 43px">
+  <div style="padding-left:3px">
+    <div class="absolute">
+      <div class="content"></div>
+      <div class="content"></div>
+    </div>
+  </div>
+</div>
+
+<div class="grid" style="grid-template-columns: 43px">
+  <div style="border-left:2px solid black; padding-left:1px">
+    <div class="absolute">
+      <div class="content"></div>
+      <div class="content"></div>
+    </div>
+  </div>
+</div>
+
+<div class="grid" style="padding-top:10px">
+  <div>
+    <div class="absolute">
+      <div class="content"></div>
+      <div class="content"></div>
+    </div>
+  </div>
+</div>
+
+<div class="grid" style="grid-template-columns: 10px 33px; padding-right:8px">
+  <div style="padding-left:3px">
+    <div class="absolute" style="grid-column: 2 / 3">
+      <div class="content"></div>
+      <div class="content"></div>
+    </div>
+  </div>
+</div>
+
+<div class="grid" style="grid-template-columns: 10px 33px; padding-right:8px; padding-left:10px">
+  <div style="padding-left:3px">
+    <div class="absolute" style="grid-column: 2 / 3">
+      <div class="content"></div>
+      <div class="content"></div>
+    </div>
+  </div>
+</div>
+
+</body>
+</html>
--- a/toolkit/components/reader/Readability.js
+++ b/toolkit/components/reader/Readability.js
@@ -540,17 +540,26 @@ Readability.prototype = {
     while (node.firstChild) {
       replacement.appendChild(node.firstChild);
     }
     node.parentNode.replaceChild(replacement, node);
     if (node.readability)
       replacement.readability = node.readability;
 
     for (var i = 0; i < node.attributes.length; i++) {
-      replacement.setAttribute(node.attributes[i].name, node.attributes[i].value);
+      try {
+        replacement.setAttribute(node.attributes[i].name, node.attributes[i].value);
+      } catch (ex) {
+        /* it's possible for setAttribute() to throw if the attribute name
+         * isn't a valid XML Name. Such attributes can however be parsed from
+         * source in HTML docs, see https://github.com/whatwg/html/issues/4275,
+         * so we can hit them here and then throw. We don't care about such
+         * attributes so we ignore them.
+         */
+      }
     }
     return replacement;
   },
 
   /**
    * Prepare the article node for display. Clean out any inline styles,
    * iframes, forms, strip extraneous <p> tags, etc.
    *
@@ -1215,16 +1224,19 @@ Readability.prototype = {
     // name is a single value
     var namePattern = /^\s*(?:(dc|dcterm|og|twitter|weibo:(article|webpage))\s*[\.:]\s*)?(author|creator|description|title|site_name)\s*$/i;
 
     // Find description tags.
     this._forEachNode(metaElements, function(element) {
       var elementName = element.getAttribute("name");
       var elementProperty = element.getAttribute("property");
       var content = element.getAttribute("content");
+      if (!content) {
+        return;
+      }
       var matches = null;
       var name = null;
 
       if (elementProperty) {
         matches = elementProperty.match(propertyPattern);
         if (matches) {
           for (var i = matches.length - 1; i >= 0; i--) {
             // Convert to lowercase, and remove any whitespace
--- a/toolkit/components/url-classifier/Classifier.cpp
+++ b/toolkit/components/url-classifier/Classifier.cpp
@@ -399,40 +399,16 @@ void Classifier::TableRequest(nsACString
     aResult.Append(metadata);
   }
 
   // Update the TableRequest result in-memory cache.
   mTableRequestResult = aResult;
   mIsTableRequestResultOutdated = false;
 }
 
-nsresult Classifier::CheckURI(const nsACString& aSpec,
-                              const nsTArray<nsCString>& aTables,
-                              LookupResultArray& aResults) {
-  Telemetry::AutoTimer<Telemetry::URLCLASSIFIER_CL_CHECK_TIME> timer;
-
-  // Get the set of fragments based on the url. This is necessary because we
-  // only look up at most 5 URLs per aSpec, even if aSpec has more than 5
-  // components.
-  nsTArray<nsCString> fragments;
-  nsresult rv = LookupCache::GetLookupFragments(aSpec, &fragments);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  LookupCacheArray cacheArray;
-  for (const nsCString& table : aTables) {
-    LookupResultArray results;
-    rv = CheckURIFragments(fragments, table, results);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    aResults.AppendElements(results);
-  }
-
-  return NS_OK;
-}
-
 nsresult Classifier::CheckURIFragments(
     const nsTArray<nsCString>& aSpecFragments, const nsACString& aTable,
     LookupResultArray& aResults) {
   // A URL can form up to 30 different fragments
   MOZ_ASSERT(aSpecFragments.Length() <=
              (MAX_HOST_COMPONENTS * (MAX_PATH_COMPONENTS + 2)));
 
   LOG(("Checking table %s", aTable.BeginReading()));
--- a/toolkit/components/url-classifier/Classifier.h
+++ b/toolkit/components/url-classifier/Classifier.h
@@ -52,22 +52,16 @@ class Classifier {
   void TableRequest(nsACString& aResult);
 
   /*
    * Get all tables that we know about.
    */
   nsresult ActiveTables(nsTArray<nsCString>& aTables) const;
 
   /**
-   * Check a URL against the specified tables.
-   */
-  nsresult CheckURI(const nsACString& aSpec, const nsTArray<nsCString>& tables,
-                    LookupResultArray& aResults);
-
-  /**
    * Check URL fragments against a specified table.
    * The fragments should be generated by |LookupCache::GetLookupFragments|
    */
   nsresult CheckURIFragments(const nsTArray<nsCString>& aSpecFragments,
                              const nsACString& table,
                              LookupResultArray& aResults);
 
   /**
--- a/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp
+++ b/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp
@@ -88,31 +88,30 @@ nsresult TablesToResponse(const nsACStri
     return NS_ERROR_BLOCKED_URI;
   }
   return NS_OK;
 }
 
 }  // namespace safebrowsing
 }  // namespace mozilla
 
-namespace {
-
 // This class holds a list of features, their tables, and it stores the lookup
 // results.
-class FeatureHolder final {
+class nsUrlClassifierDBService::FeatureHolder final {
  public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FeatureHolder);
 
   // In order to avoid multiple lookup for the same table, we have a special
   // array for tables and their results. The Features are stored in a separate
   // array together with the references to their tables.
 
   class TableData {
    public:
-    NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FeatureHolder::TableData);
+    NS_INLINE_DECL_THREADSAFE_REFCOUNTING(
+        nsUrlClassifierDBService::FeatureHolder::TableData);
 
     explicit TableData(const nsACString& aTable) : mTable(aTable) {}
 
     nsCString mTable;
     LookupResultArray mResults;
 
    private:
     ~TableData() = default;
@@ -153,16 +152,20 @@ class FeatureHolder final {
     return holder.forget();
   }
 
   nsresult DoLocalLookup(const nsACString& aSpec,
                          nsUrlClassifierDBServiceWorker* aWorker) {
     MOZ_ASSERT(!NS_IsMainThread());
     MOZ_ASSERT(aWorker);
 
+    mozilla::Telemetry::AutoTimer<
+        mozilla::Telemetry::URLCLASSIFIER_CL_CHECK_TIME>
+        timer;
+
     // Get the set of fragments based on the url. This is necessary because we
     // only look up at most 5 URLs per aSpec, even if aSpec has more than 5
     // components.
     nsTArray<nsCString> fragments;
     nsresult rv = LookupCache::GetLookupFragments(aSpec, &fragments);
     NS_ENSURE_SUCCESS(rv, rv);
 
     for (TableData* tableData : mTableData) {
@@ -201,16 +204,30 @@ class FeatureHolder final {
 
       RefPtr<mozilla::net::UrlClassifierFeatureResult> result =
           new mozilla::net::UrlClassifierFeatureResult(
               mURI, featureData.mFeature, list);
       aResults.AppendElement(result);
     }
   }
 
+  mozilla::UniquePtr<LookupResultArray> GetTableResults() const {
+    mozilla::UniquePtr<LookupResultArray> results =
+        mozilla::MakeUnique<LookupResultArray>();
+    if (NS_WARN_IF(!results)) {
+      return nullptr;
+    }
+
+    for (TableData* tableData : mTableData) {
+      results->AppendElements(tableData->mResults);
+    }
+
+    return results;
+  }
+
  private:
   explicit FeatureHolder(nsIURI* aURI) : mURI(aURI) {
     MOZ_ASSERT(NS_IsMainThread());
   }
 
   ~FeatureHolder() {
     for (FeatureData& featureData : mFeatureData) {
       NS_ReleaseOnMainThreadSystemGroup("FeatureHolder:mFeatureData",
@@ -232,18 +249,16 @@ class FeatureHolder final {
     return tableData;
   }
 
   nsCOMPtr<nsIURI> mURI;
   nsTArray<FeatureData> mFeatureData;
   nsTArray<RefPtr<TableData>> mTableData;
 };
 
-}  // namespace
-
 using namespace mozilla;
 using namespace mozilla::safebrowsing;
 
 // MOZ_LOG=UrlClassifierDbService:5
 LazyLogModule gUrlClassifierDbServiceLog("UrlClassifierDbService");
 #define LOG(args) \
   MOZ_LOG(gUrlClassifierDbServiceLog, mozilla::LogLevel::Debug, args)
 #define LOG_ENABLED() \
@@ -289,30 +304,34 @@ nsresult nsUrlClassifierDBServiceWorker:
   mDBService = aDBService;
 
   ResetUpdate();
 
   return NS_OK;
 }
 
 nsresult nsUrlClassifierDBServiceWorker::QueueLookup(
-    const nsACString& spec, const nsACString& tables,
-    nsIUrlClassifierLookupCallback* callback) {
+    const nsACString& aKey,
+    nsUrlClassifierDBService::FeatureHolder* aFeatureHolder,
+    nsIUrlClassifierLookupCallback* aCallback) {
+  MOZ_ASSERT(aFeatureHolder);
+  MOZ_ASSERT(aCallback);
+
   MutexAutoLock lock(mPendingLookupLock);
   if (gShuttingDownThread) {
     return NS_ERROR_ABORT;
   }
 
   PendingLookup* lookup = mPendingLookups.AppendElement(fallible);
-  if (!lookup) return NS_ERROR_OUT_OF_MEMORY;
+  if (NS_WARN_IF(!lookup)) return NS_ERROR_OUT_OF_MEMORY;
 
   lookup->mStartTime = TimeStamp::Now();
-  lookup->mKey = spec;
-  lookup->mCallback = callback;
-  lookup->mTables = tables;
+  lookup->mKey = aKey;
+  lookup->mCallback = aCallback;
+  lookup->mFeatureHolder = aFeatureHolder;
 
   return NS_OK;
 }
 
 nsresult nsUrlClassifierDBServiceWorker::DoSingleLocalLookupWithURIFragments(
     const nsTArray<nsCString>& aSpecFragments, const nsACString& aTable,
     LookupResultArray& aResults) {
   if (gShuttingDownThread) {
@@ -333,91 +352,58 @@ nsresult nsUrlClassifierDBServiceWorker:
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   LOG(("Found %zu results.", aResults.Length()));
   return NS_OK;
 }
 
-nsresult nsUrlClassifierDBServiceWorker::DoLocalLookupWithURI(
-    const nsACString& aSpec, const nsTArray<nsCString>& aTables,
-    LookupResultArray& aResults) {
-  if (gShuttingDownThread) {
-    return NS_ERROR_ABORT;
-  }
-
-  MOZ_ASSERT(
-      !NS_IsMainThread(),
-      "DoSingleLocalLookupWithURIFragments must be on background thread");
-
-  // Bail if we haven't been initialized on the background thread.
-  if (!mClassifier) {
-    return NS_ERROR_NOT_AVAILABLE;
-  }
-
-  nsresult rv = mClassifier->CheckURI(aSpec, aTables, aResults);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  LOG(("Found %zu results.", aResults.Length()));
-  return NS_OK;
-}
-
 /**
  * Lookup up a key in the database is a two step process:
  *
  * a) First we look for any Entries in the database that might apply to this
  *    url.  For each URL there are one or two possible domain names to check:
  *    the two-part domain name (example.com) and the three-part name
  *    (www.example.com).  We check the database for both of these.
  * b) If we find any entries, we check the list of fragments for that entry
  *    against the possible subfragments of the URL as described in the
  *    "Simplified Regular Expression Lookup" section of the protocol doc.
  */
 nsresult nsUrlClassifierDBServiceWorker::DoLookup(
-    const nsACString& spec, const nsACString& tables,
+    const nsACString& spec,
+    nsUrlClassifierDBService::FeatureHolder* aFeatureHolder,
     nsIUrlClassifierLookupCallback* c) {
   if (gShuttingDownThread) {
     c->LookupComplete(nullptr);
     return NS_ERROR_NOT_INITIALIZED;
   }
 
   PRIntervalTime clockStart = 0;
   if (LOG_ENABLED()) {
     clockStart = PR_IntervalNow();
   }
 
-  UniquePtr<LookupResultArray> results = MakeUnique<LookupResultArray>();
-  if (!results) {
-    c->LookupComplete(nullptr);
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
-
-  nsTArray<nsCString> tableArray;
-  Classifier::SplitTables(tables, tableArray);
-
-  nsresult rv = DoLocalLookupWithURI(spec, tableArray, *results);
-  if (NS_FAILED(rv)) {
-    MOZ_ASSERT(
-        results->IsEmpty(),
-        "DoLocalLookupWithURI() should not return any results if it fails.");
-    c->LookupComplete(nullptr);
-    return rv;
-  }
-
-  LOG(("Found %zu results.", results->Length()));
+  nsresult rv = aFeatureHolder->DoLocalLookup(spec, this);
+  NS_ENSURE_SUCCESS(rv, rv);
 
   if (LOG_ENABLED()) {
     PRIntervalTime clockEnd = PR_IntervalNow();
     LOG(("query took %dms\n",
          PR_IntervalToMilliseconds(clockEnd - clockStart)));
   }
 
+  UniquePtr<LookupResultArray> results = aFeatureHolder->GetTableResults();
+  if (NS_WARN_IF(!results)) {
+    c->LookupComplete(nullptr);
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+
+  LOG(("Found %zu results.", results->Length()));
+
   for (const RefPtr<const LookupResult> lookupResult : *results) {
     if (!lookupResult->Confirmed() &&
         mDBService->CanComplete(lookupResult->mTableName)) {
       // We're going to be doing a gethash request, add some extra entries.
       // Note that we cannot pass the first two by reference, because we
       // add to completes, which can cause completes to reallocate and move.
       AddNoise(lookupResult->hash.fixedLengthPrefix, lookupResult->mTableName,
                mGethashNoise, *results);
@@ -437,17 +423,17 @@ nsresult nsUrlClassifierDBServiceWorker:
   }
 
   MutexAutoLock lock(mPendingLookupLock);
   while (mPendingLookups.Length() > 0) {
     PendingLookup lookup = mPendingLookups[0];
     mPendingLookups.RemoveElementAt(0);
     {
       MutexAutoUnlock unlock(mPendingLookupLock);
-      DoLookup(lookup.mKey, lookup.mTables, lookup.mCallback);
+      DoLookup(lookup.mKey, lookup.mFeatureHolder, lookup.mCallback);
     }
     double lookupTime = (TimeStamp::Now() - lookup.mStartTime).ToMilliseconds();
     Telemetry::Accumulate(Telemetry::URLCLASSIFIER_LOOKUP_TIME_2,
                           static_cast<uint32_t>(lookupTime));
   }
 
   return NS_OK;
 }
@@ -1612,82 +1598,25 @@ NS_INTERFACE_MAP_END
     }
   } else {
     // Already exists, just add a ref
     NS_ADDREF(sUrlClassifierDBService);  // addref the return result
   }
   return sUrlClassifierDBService;
 }
 
-nsUrlClassifierDBService::nsUrlClassifierDBService()
-    : mCheckMalware(CHECK_MALWARE_DEFAULT),
-      mCheckPhishing(CHECK_PHISHING_DEFAULT),
-      mCheckBlockedURIs(CHECK_BLOCKED_DEFAULT),
-      mInUpdate(false) {}
+nsUrlClassifierDBService::nsUrlClassifierDBService() : mInUpdate(false) {}
 
 nsUrlClassifierDBService::~nsUrlClassifierDBService() {
   sUrlClassifierDBService = nullptr;
 }
 
-void AppendTables(const nsCString& aTables, nsCString& outTables) {
-  if (!aTables.IsEmpty()) {
-    if (!outTables.IsEmpty()) {
-      outTables.Append(',');
-    }
-    outTables.Append(aTables);
-  }
-}
-
-nsresult nsUrlClassifierDBService::ReadTablesFromPrefs() {
-  mCheckMalware =
-      Preferences::GetBool(CHECK_MALWARE_PREF, CHECK_MALWARE_DEFAULT);
-  mCheckPhishing =
-      Preferences::GetBool(CHECK_PHISHING_PREF, CHECK_PHISHING_DEFAULT);
-  mCheckBlockedURIs =
-      Preferences::GetBool(CHECK_BLOCKED_PREF, CHECK_BLOCKED_DEFAULT);
-
-  nsAutoCString allTables;
+nsresult nsUrlClassifierDBService::ReadDisallowCompletionsTablesFromPrefs() {
   nsAutoCString tables;
 
-  mBaseTables.Truncate();
-
-  Preferences::GetCString(PHISH_TABLE_PREF, allTables);
-  if (mCheckPhishing) {
-    AppendTables(allTables, mBaseTables);
-  }
-
-  Preferences::GetCString(MALWARE_TABLE_PREF, tables);
-  AppendTables(tables, allTables);
-  if (mCheckMalware) {
-    AppendTables(tables, mBaseTables);
-  }
-
-  Preferences::GetCString(BLOCKED_TABLE_PREF, tables);
-  AppendTables(tables, allTables);
-  if (mCheckBlockedURIs) {
-    AppendTables(tables, mBaseTables);
-  }
-
-  Preferences::GetCString(DOWNLOAD_BLOCK_TABLE_PREF, tables);
-  AppendTables(tables, allTables);
-
-  Preferences::GetCString(DOWNLOAD_ALLOW_TABLE_PREF, tables);
-  AppendTables(tables, allTables);
-
-  Preferences::GetCString(PASSWORD_ALLOW_TABLE_PREF, tables);
-  AppendTables(tables, allTables);
-
-  Preferences::GetCString(TRACKING_TABLE_PREF, tables);
-  AppendTables(tables, allTables);
-
-  Preferences::GetCString(TRACKING_WHITELIST_TABLE_PREF, tables);
-  AppendTables(tables, allTables);
-
-  Classifier::SplitTables(allTables, mGethashTables);
-
   Preferences::GetCString(DISALLOW_COMPLETION_TABLE_PREF, tables);
   Classifier::SplitTables(tables, mDisallowCompletionsTables);
 
   return NS_OK;
 }
 
 nsresult nsUrlClassifierDBService::Init() {
   MOZ_ASSERT(NS_IsMainThread(), "Must initialize DB service on main thread");
@@ -1713,17 +1642,17 @@ nsresult nsUrlClassifierDBService::Init(
       return NS_OK;
     default:
       // No other process type is supported!
       return NS_ERROR_NOT_AVAILABLE;
   }
 
   sGethashNoise =
       Preferences::GetUint(GETHASH_NOISE_PREF, GETHASH_NOISE_DEFAULT);
-  ReadTablesFromPrefs();
+  ReadDisallowCompletionsTablesFromPrefs();
   nsresult rv;
 
   {
     // Force nsIUrlClassifierUtils loading on main thread.
     nsCOMPtr<nsIUrlClassifierUtils> dummy =
         do_GetService(NS_URLCLASSIFIERUTILS_CONTRACTID, &rv);
     NS_ENSURE_SUCCESS(rv, rv);
   }
@@ -1766,87 +1695,125 @@ nsresult nsUrlClassifierDBService::Init(
   nsCOMPtr<nsIObserverService> observerService =
       mozilla::services::GetObserverService();
   if (!observerService) return NS_ERROR_FAILURE;
 
   // The application is about to quit
   observerService->AddObserver(this, "quit-application", false);
   observerService->AddObserver(this, "profile-before-change", false);
 
-  // XXX: Do we *really* need to be able to change all of these at runtime?
-  // Note: These observers should only be added when everything else above has
-  //       succeeded. Failing to do so can cause long shutdown times in certain
-  //       situations. See Bug 1247798 and Bug 1244803.
   Preferences::AddUintVarCache(&sGethashNoise, GETHASH_NOISE_PREF,
                                GETHASH_NOISE_DEFAULT);
-
-  for (uint8_t i = 0; i < kObservedPrefs.Length(); i++) {
-    Preferences::AddStrongObserver(this, kObservedPrefs[i]);
-  }
+  Preferences::AddStrongObserver(this, DISALLOW_COMPLETION_TABLE_PREF);
 
   return NS_OK;
 }
 
 // nsChannelClassifier is the only consumer of this interface.
 NS_IMETHODIMP
 nsUrlClassifierDBService::Classify(nsIPrincipal* aPrincipal,
                                    nsIEventTarget* aEventTarget,
-                                   nsIURIClassifierCallback* c, bool* result) {
+                                   nsIURIClassifierCallback* c, bool* aResult) {
   NS_ENSURE_ARG(aPrincipal);
+  NS_ENSURE_ARG(aResult);
+
+  if (nsContentUtils::IsSystemPrincipal(aPrincipal)) {
+    *aResult = false;
+    return NS_OK;
+  }
 
   if (XRE_IsContentProcess()) {
     using namespace mozilla::dom;
 
     ContentChild* content = ContentChild::GetSingleton();
     MOZ_ASSERT(content);
 
     auto actor = static_cast<URLClassifierChild*>(
-        content->AllocPURLClassifierChild(IPC::Principal(aPrincipal), result));
+        content->AllocPURLClassifierChild(IPC::Principal(aPrincipal), aResult));
     MOZ_ASSERT(actor);
 
     if (aEventTarget) {
       content->SetEventTargetForActor(actor, aEventTarget);
     } else {
       // In the case null event target we should use systemgroup event target
       NS_WARNING(
           ("Null event target, we should use SystemGroup to do labelling"));
       nsCOMPtr<nsIEventTarget> systemGroupEventTarget =
           mozilla::SystemGroup::EventTargetFor(mozilla::TaskCategory::Other);
       content->SetEventTargetForActor(actor, systemGroupEventTarget);
     }
     if (!content->SendPURLClassifierConstructor(
-            actor, IPC::Principal(aPrincipal), result)) {
-      *result = false;
+            actor, IPC::Principal(aPrincipal), aResult)) {
+      *aResult = false;
       return NS_ERROR_FAILURE;
     }
 
     actor->SetCallback(c);
     return NS_OK;
   }
 
   NS_ENSURE_TRUE(gDbBackgroundThread, NS_ERROR_NOT_INITIALIZED);
 
-  if (!(mCheckMalware || mCheckPhishing || mCheckBlockedURIs)) {
-    *result = false;
+  nsCOMPtr<nsIPermissionManager> permissionManager =
+      services::GetPermissionManager();
+  if (NS_WARN_IF(!permissionManager)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  uint32_t perm;
+  nsresult rv = permissionManager->TestPermissionFromPrincipal(
+      aPrincipal, "safe-browsing", &perm);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (perm == nsIPermissionManager::ALLOW_ACTION) {
+    *aResult = false;
+    return NS_OK;
+  }
+
+  nsTArray<RefPtr<nsIUrlClassifierFeature>> features;
+  mozilla::net::UrlClassifierFeatureFactory::GetPhishingProtectionFeatures(
+      features);
+  if (features.IsEmpty()) {
+    *aResult = false;
     return NS_OK;
   }
 
+  nsCOMPtr<nsIURI> uri;
+  rv = aPrincipal->GetURI(getter_AddRefs(uri));
+  NS_ENSURE_SUCCESS(rv, rv);
+  NS_ENSURE_TRUE(uri, NS_ERROR_FAILURE);
+
+  // Let's keep the features alive and release them on the correct thread.
+  RefPtr<FeatureHolder> holder =
+      FeatureHolder::Create(uri, features, nsIUrlClassifierFeature::blacklist);
+  if (NS_WARN_IF(!holder)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  uri = NS_GetInnermostURI(uri);
+  NS_ENSURE_TRUE(uri, NS_ERROR_FAILURE);
+
+  nsAutoCString key;
+  // Canonicalize the url
+  nsCOMPtr<nsIUrlClassifierUtils> utilsService =
+      do_GetService(NS_URLCLASSIFIERUTILS_CONTRACTID);
+  rv = utilsService->GetKeyForURI(uri, key);
+  NS_ENSURE_SUCCESS(rv, rv);
+
   RefPtr<nsUrlClassifierClassifyCallback> callback =
       new (fallible) nsUrlClassifierClassifyCallback(c);
-
-  if (!callback) return NS_ERROR_OUT_OF_MEMORY;
-
-  nsresult rv = LookupURI(aPrincipal, mBaseTables, callback, false, result);
-  if (rv == NS_ERROR_MALFORMED_URI) {
-    *result = false;
-    // The URI had no hostname, don't try to classify it.
-    return NS_OK;
+  if (NS_WARN_IF(!callback)) {
+    return NS_ERROR_OUT_OF_MEMORY;
   }
+
+  // The rest is done async.
+  rv = LookupURI(key, holder, callback);
   NS_ENSURE_SUCCESS(rv, rv);
 
+  *aResult = true;
   return NS_OK;
 }
 
 class ThreatHitReportListener final : public nsIStreamListener {
  public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIREQUESTOBSERVER
   NS_DECL_NSISTREAMLISTENER
@@ -2066,84 +2033,78 @@ nsUrlClassifierDBService::SendThreatHitR
 }
 
 NS_IMETHODIMP
 nsUrlClassifierDBService::Lookup(nsIPrincipal* aPrincipal,
                                  const nsACString& tables,
                                  nsIUrlClassifierCallback* c) {
   NS_ENSURE_TRUE(gDbBackgroundThread, NS_ERROR_NOT_INITIALIZED);
 
-  bool dummy;
-  return LookupURI(aPrincipal, tables, c, true, &dummy);
-}
-
-nsresult nsUrlClassifierDBService::LookupURI(nsIPrincipal* aPrincipal,
-                                             const nsACString& tables,
-                                             nsIUrlClassifierCallback* c,
-                                             bool forceLookup,
-                                             bool* didLookup) {
-  NS_ENSURE_TRUE(gDbBackgroundThread, NS_ERROR_NOT_INITIALIZED);
-  NS_ENSURE_ARG(aPrincipal);
-
   if (nsContentUtils::IsSystemPrincipal(aPrincipal)) {
-    *didLookup = false;
+    // FIXME: we don't call 'c' here!
     return NS_OK;
   }
 
+  nsTArray<nsCString> tableArray;
+  Classifier::SplitTables(tables, tableArray);
+
+  nsCOMPtr<nsIUrlClassifierFeature> feature;
+  nsresult rv =
+      CreateFeatureWithTables(NS_LITERAL_CSTRING("lookup"), tableArray,
+                              nsTArray<nsCString>(), getter_AddRefs(feature));
+  NS_ENSURE_SUCCESS(rv, rv);
+
   nsCOMPtr<nsIURI> uri;
-  nsresult rv = aPrincipal->GetURI(getter_AddRefs(uri));
+  rv = aPrincipal->GetURI(getter_AddRefs(uri));
   NS_ENSURE_SUCCESS(rv, rv);
   NS_ENSURE_TRUE(uri, NS_ERROR_FAILURE);
 
+  nsTArray<RefPtr<nsIUrlClassifierFeature>> features;
+  features.AppendElement(feature.get());
+
+  // Let's keep the features alive and release them on the correct thread.
+  RefPtr<FeatureHolder> holder =
+      FeatureHolder::Create(uri, features, nsIUrlClassifierFeature::blacklist);
+  if (NS_WARN_IF(!holder)) {
+    return NS_ERROR_FAILURE;
+  }
+
   uri = NS_GetInnermostURI(uri);
   NS_ENSURE_TRUE(uri, NS_ERROR_FAILURE);
 
   nsAutoCString key;
   // Canonicalize the url
   nsCOMPtr<nsIUrlClassifierUtils> utilsService =
       do_GetService(NS_URLCLASSIFIERUTILS_CONTRACTID);
   rv = utilsService->GetKeyForURI(uri, key);
-  if (NS_FAILED(rv)) return rv;
-
-  if (forceLookup) {
-    *didLookup = true;
-  } else {
-    nsCOMPtr<nsIPermissionManager> permissionManager =
-        services::GetPermissionManager();
-    if (NS_WARN_IF(!permissionManager)) {
-      return NS_ERROR_FAILURE;
-    }
-
-    uint32_t perm;
-    rv = permissionManager->TestPermissionFromPrincipal(aPrincipal,
-                                                        "safe-browsing", &perm);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    bool clean = (perm == nsIPermissionManager::ALLOW_ACTION);
-    *didLookup = !clean;
-    if (clean) {
-      return NS_OK;
-    }
-  }
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return LookupURI(key, holder, c);
+}
+
+nsresult nsUrlClassifierDBService::LookupURI(
+    const nsACString& aKey, FeatureHolder* aHolder,
+    nsIUrlClassifierCallback* aCallback) {
+  MOZ_ASSERT(aHolder);
+  MOZ_ASSERT(aCallback);
+
+  NS_ENSURE_TRUE(gDbBackgroundThread, NS_ERROR_NOT_INITIALIZED);
 
   // Create an nsUrlClassifierLookupCallback object.  This object will
   // take care of confirming partial hash matches if necessary before
   // calling the client's callback.
   nsCOMPtr<nsIUrlClassifierLookupCallback> callback =
-      new (fallible) nsUrlClassifierLookupCallback(this, c);
-  if (!callback) {
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
+      new nsUrlClassifierLookupCallback(this, aCallback);
 
   nsCOMPtr<nsIUrlClassifierLookupCallback> proxyCallback =
       new UrlClassifierLookupCallbackProxy(callback);
 
   // Queue this lookup and call the lookup function to flush the queue if
   // necessary.
-  rv = mWorker->QueueLookup(key, tables, proxyCallback);
+  nsresult rv = mWorker->QueueLookup(aKey, aHolder, proxyCallback);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // This seems to just call HandlePendingLookups.
   nsAutoCString dummy;
   return mWorkerProxy->Lookup(nullptr, dummy, nullptr);
 }
 
 NS_IMETHODIMP
@@ -2302,18 +2263,17 @@ nsUrlClassifierDBService::GetCacheInfo(
 nsresult nsUrlClassifierDBService::CacheCompletions(
     const ConstCacheResultArray& results) {
   NS_ENSURE_TRUE(gDbBackgroundThread, NS_ERROR_NOT_INITIALIZED);
 
   return mWorkerProxy->CacheCompletions(results);
 }
 
 bool nsUrlClassifierDBService::CanComplete(const nsACString& aTableName) {
-  return mGethashTables.Contains(aTableName) &&
-         !mDisallowCompletionsTables.Contains(aTableName);
+  return !mDisallowCompletionsTables.Contains(aTableName);
 }
 
 bool nsUrlClassifierDBService::GetCompleter(
     const nsACString& tableName, nsIUrlClassifierHashCompleter** completer) {
   // If we have specified a completer, go ahead and query it. This is only
   // used by tests.
   if (mCompleters.Get(tableName, completer)) {
     return true;
@@ -2327,24 +2287,17 @@ bool nsUrlClassifierDBService::GetComple
   return NS_SUCCEEDED(
       CallGetService(NS_URLCLASSIFIERHASHCOMPLETER_CONTRACTID, completer));
 }
 
 NS_IMETHODIMP
 nsUrlClassifierDBService::Observe(nsISupports* aSubject, const char* aTopic,
                                   const char16_t* aData) {
   if (!strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
-    nsresult rv;
-    nsCOMPtr<nsIPrefBranch> prefs(do_QueryInterface(aSubject, &rv));
-    NS_ENSURE_SUCCESS(rv, rv);
-    Unused << prefs;
-
-    if (kObservedPrefs.Contains(NS_ConvertUTF16toUTF8(aData))) {
-      ReadTablesFromPrefs();
-    }
+    ReadDisallowCompletionsTablesFromPrefs();
   } else if (!strcmp(aTopic, "quit-application")) {
     // Tell the update thread to finish as soon as possible.
     gShuttingDownThread = true;
 
     // The code in ::Shutdown() is run on a 'profile-before-change' event and
     // ensures that objects are freed by blocking on this freeing.
     // We can however speed up the shutdown time by using the worker thread to
     // release, in an earlier event, any objects that cannot affect an ongoing
@@ -2384,19 +2337,17 @@ nsresult nsUrlClassifierDBService::Shutd
   }
 
   Telemetry::AutoTimer<Telemetry::URLCLASSIFIER_SHUTDOWN_TIME> timer;
 
   mCompleters.Clear();
 
   nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
   if (prefs) {
-    for (uint8_t i = 0; i < kObservedPrefs.Length(); i++) {
-      prefs->RemoveObserver(kObservedPrefs[i], this);
-    }
+    prefs->RemoveObserver(DISALLOW_COMPLETION_TABLE_PREF, this);
   }
 
   // 1. Synchronize with worker thread and update thread by
   //    *synchronously* dispatching an event to worker thread
   //    for shutting down the update thread. The reason not
   //    shutting down update thread directly from main thread
   //    is to avoid racing for Classifier::mUpdateThread
   //    between main thread and the worker thread. (Both threads
--- a/toolkit/components/url-classifier/nsUrlClassifierDBService.h
+++ b/toolkit/components/url-classifier/nsUrlClassifierDBService.h
@@ -38,36 +38,18 @@
 #define DOMAIN_LENGTH 4
 
 // The hash length of a partial hash entry.
 #define PARTIAL_LENGTH 4
 
 // The hash length of a complete hash entry.
 #define COMPLETE_LENGTH 32
 
-// Prefs for implementing nsIURIClassifier to block page loads
-#define CHECK_MALWARE_PREF "browser.safebrowsing.malware.enabled"
-#define CHECK_MALWARE_DEFAULT false
-
-#define CHECK_PHISHING_PREF "browser.safebrowsing.phishing.enabled"
-#define CHECK_PHISHING_DEFAULT false
-
-#define CHECK_BLOCKED_PREF "browser.safebrowsing.blockedURIs.enabled"
-#define CHECK_BLOCKED_DEFAULT false
-
 // Comma-separated lists
-#define MALWARE_TABLE_PREF "urlclassifier.malwareTable"
-#define PHISH_TABLE_PREF "urlclassifier.phishTable"
-#define TRACKING_TABLE_PREF "urlclassifier.trackingTable"
-#define TRACKING_WHITELIST_TABLE_PREF "urlclassifier.trackingWhitelistTable"
-#define BLOCKED_TABLE_PREF "urlclassifier.blockedTable"
-#define DOWNLOAD_BLOCK_TABLE_PREF "urlclassifier.downloadBlockTable"
-#define DOWNLOAD_ALLOW_TABLE_PREF "urlclassifier.downloadAllowTable"
 #define DISALLOW_COMPLETION_TABLE_PREF "urlclassifier.disallow_completions"
-#define PASSWORD_ALLOW_TABLE_PREF "urlclassifier.passwordAllowTable"
 
 using namespace mozilla::safebrowsing;
 
 class nsUrlClassifierDBServiceWorker;
 class nsIThread;
 class nsIURI;
 class UrlClassifierDBServiceWorkerProxy;
 
@@ -91,16 +73,18 @@ class AsyncUrlChannelClassifier;
 // calls to the background thread.
 class nsUrlClassifierDBService final : public nsIUrlClassifierDBService,
                                        public nsIURIClassifier,
                                        public nsIUrlClassifierInfo,
                                        public nsIObserver {
   friend class mozilla::net::AsyncUrlChannelClassifier;
 
  public:
+  class FeatureHolder;
+
   // This is thread safe. It throws an exception if the thread is busy.
   nsUrlClassifierDBService();
 
   nsresult Init();
 
   static nsUrlClassifierDBService* GetInstance(nsresult* result);
 
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_URLCLASSIFIERDBSERVICE_CID)
@@ -121,119 +105,84 @@ class nsUrlClassifierDBService final : p
 
   static bool ShutdownHasStarted();
 
  private:
   // This method is used only by AsyncUrlChannelClassifier. If you want to use
   // it, please contact a safebrowsing/URL-Classifier peer.
   static nsUrlClassifierDBServiceWorker* GetWorker();
 
-  const nsTArray<nsCString> kObservedPrefs = {
-      NS_LITERAL_CSTRING(CHECK_MALWARE_PREF),
-      NS_LITERAL_CSTRING(CHECK_PHISHING_PREF),
-      NS_LITERAL_CSTRING(CHECK_BLOCKED_PREF),
-      NS_LITERAL_CSTRING(MALWARE_TABLE_PREF),
-      NS_LITERAL_CSTRING(PHISH_TABLE_PREF),
-      NS_LITERAL_CSTRING(TRACKING_TABLE_PREF),
-      NS_LITERAL_CSTRING(TRACKING_WHITELIST_TABLE_PREF),
-      NS_LITERAL_CSTRING(BLOCKED_TABLE_PREF),
-      NS_LITERAL_CSTRING(DOWNLOAD_BLOCK_TABLE_PREF),
-      NS_LITERAL_CSTRING(DOWNLOAD_ALLOW_TABLE_PREF),
-      NS_LITERAL_CSTRING(DISALLOW_COMPLETION_TABLE_PREF)};
-
   // No subclassing
   ~nsUrlClassifierDBService();
 
   // Disallow copy constructor
   nsUrlClassifierDBService(nsUrlClassifierDBService&);
 
-  nsresult LookupURI(nsIPrincipal* aPrincipal, const nsACString& tables,
-                     nsIUrlClassifierCallback* c, bool forceCheck,
-                     bool* didCheck);
+  nsresult LookupURI(const nsACString& aKey, FeatureHolder* aHolder,
+                     nsIUrlClassifierCallback* c);
 
   // Post an event to worker thread to release objects when receive
   // 'quit-application'
   nsresult PreShutdown();
 
   // Close db connection and join the background thread if it exists.
   nsresult Shutdown();
 
-  nsresult ReadTablesFromPrefs();
+  nsresult ReadDisallowCompletionsTablesFromPrefs();
 
   // This method checks if the classification can be done just using
   // preferences. It returns true if the operation has been completed.
   bool AsyncClassifyLocalWithFeaturesUsingPreferences(
       nsIURI* aURI, const nsTArray<RefPtr<nsIUrlClassifierFeature>>& aFeatures,
       nsIUrlClassifierFeature::listType aListType,
       nsIUrlClassifierFeatureCallback* aCallback);
 
   RefPtr<nsUrlClassifierDBServiceWorker> mWorker;
   RefPtr<UrlClassifierDBServiceWorkerProxy> mWorkerProxy;
 
   nsInterfaceHashtable<nsCStringHashKey, nsIUrlClassifierHashCompleter>
       mCompleters;
 
-  // TRUE if the nsURIClassifier implementation should check for malware
-  // uris on document loads.
-  bool mCheckMalware;
-
-  // TRUE if the nsURIClassifier implementation should check for phishing
-  // uris on document loads.
-  bool mCheckPhishing;
-
-  // TRUE if the nsURIClassifier implementation should check for blocked
-  // uris on document loads.
-  bool mCheckBlockedURIs;
-
   // TRUE if a BeginUpdate() has been called without an accompanying
   // CancelUpdate()/FinishUpdate().  This is used to prevent competing
   // updates, not to determine whether an update is still being
   // processed.
   bool mInUpdate;
 
-  // The list of tables that can use the default hash completer object.
-  nsTArray<nsCString> mGethashTables;
-
   // The list of tables that should never be hash completed.
   nsTArray<nsCString> mDisallowCompletionsTables;
 
-  // Comma-separated list of tables to use in lookups.
-  nsCString mBaseTables;
-
   // Thread that we do the updates on.
   static nsIThread* gDbBackgroundThread;
 };
 
 class nsUrlClassifierDBServiceWorker final : public nsIUrlClassifierDBService {
  public:
   nsUrlClassifierDBServiceWorker();
 
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSIURLCLASSIFIERDBSERVICE
 
   nsresult Init(uint32_t aGethashNoise, nsCOMPtr<nsIFile> aCacheDir,
                 nsUrlClassifierDBService* aDBService);
 
   // Queue a lookup for the worker to perform, called in the main thread.
-  // tables is a comma-separated list of tables to query
-  nsresult QueueLookup(const nsACString& lookupKey, const nsACString& tables,
-                       nsIUrlClassifierLookupCallback* callback);
+  nsresult QueueLookup(const nsACString& aLookupKey,
+                       nsUrlClassifierDBService::FeatureHolder* aFeatureHolder,
+                       nsIUrlClassifierLookupCallback* aLallback);
 
   // Handle any queued-up lookups.  We call this function during long-running
   // update operations to prevent lookups from blocking for too long.
   nsresult HandlePendingLookups();
 
   // Perform a blocking classifier lookup for a given url fragments set.
   // Can be called on either the main thread or the worker thread.
   nsresult DoSingleLocalLookupWithURIFragments(
       const nsTArray<nsCString>& aSpecFragments, const nsACString& aTable,
       LookupResultArray& aResults);
-  nsresult DoLocalLookupWithURI(const nsACString& aSpec,
-                                const nsTArray<nsCString>& aTables,
-                                LookupResultArray& aResults);
 
   // Open the DB connection
   nsresult GCC_MANGLING_WORKAROUND OpenDb();
 
   // Provide a way to forcibly close the db connection.
   nsresult GCC_MANGLING_WORKAROUND CloseDb();
 
   nsresult GCC_MANGLING_WORKAROUND PreShutdown();
@@ -270,17 +219,18 @@ class nsUrlClassifierDBServiceWorker fin
 
   // Reset the in-progress update stream
   void ResetStream();
 
   // Reset the in-progress update
   void ResetUpdate();
 
   // Perform a classifier lookup for a given url.
-  nsresult DoLookup(const nsACString& spec, const nsACString& tables,
+  nsresult DoLookup(const nsACString& spec,
+                    nsUrlClassifierDBService::FeatureHolder* aFeatureHolder,
                     nsIUrlClassifierLookupCallback* c);
 
   nsresult AddNoise(const Prefix aPrefix, const nsCString tableName,
                     uint32_t aCount, LookupResultArray& results);
 
   nsresult CacheResultToTableUpdate(RefPtr<const CacheResult> aCacheResult,
                                     RefPtr<TableUpdate> aUpdate);
 
@@ -314,17 +264,17 @@ class nsUrlClassifierDBServiceWorker fin
   // Pending lookups are stored in a queue for processing.  The queue
   // is protected by mPendingLookupLock.
   mozilla::Mutex mPendingLookupLock;
 
   class PendingLookup {
    public:
     mozilla::TimeStamp mStartTime;
     nsCString mKey;
-    nsCString mTables;
+    RefPtr<nsUrlClassifierDBService::FeatureHolder> mFeatureHolder;
     nsCOMPtr<nsIUrlClassifierLookupCallback> mCallback;
   };
 
   // list of pending lookups
   nsTArray<PendingLookup> mPendingLookups;
 
 #ifdef MOZ_SAFEBROWSING_DUMP_FAILED_UPDATES
   // The raw update response for debugging.
--- a/toolkit/components/url-classifier/nsUrlClassifierProxies.cpp
+++ b/toolkit/components/url-classifier/nsUrlClassifierProxies.cpp
@@ -98,39 +98,16 @@ NS_IMETHODIMP
 UrlClassifierDBServiceWorkerProxy::FinishStream() {
   nsCOMPtr<nsIRunnable> r =
       NewRunnableMethod("nsUrlClassifierDBServiceWorker::FinishStream", mTarget,
                         &nsUrlClassifierDBServiceWorker::FinishStream);
   return DispatchToWorkerThread(r);
 }
 
 NS_IMETHODIMP
-UrlClassifierDBServiceWorkerProxy::DoLocalLookupRunnable::Run() {
-  mTarget->DoLocalLookupWithURI(mSpec, mTables, mResults);
-  return NS_OK;
-}
-
-nsresult UrlClassifierDBServiceWorkerProxy::DoLocalLookupWithURI(
-    const nsACString& spec, const nsTArray<nsCString>& tables,
-    LookupResultArray& results) const
-
-{
-  // Run synchronously on background thread. NS_DISPATCH_SYNC does *not* do
-  // what we want -- it continues processing events on the main thread loop
-  // before the Dispatch returns.
-  nsCOMPtr<nsIRunnable> r =
-      new DoLocalLookupRunnable(mTarget, spec, tables, results);
-  nsIThread* t = nsUrlClassifierDBService::BackgroundThread();
-  if (!t) return NS_ERROR_FAILURE;
-
-  mozilla::SyncRunnable::DispatchToThread(t, r);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
 UrlClassifierDBServiceWorkerProxy::FinishUpdate() {
   nsCOMPtr<nsIRunnable> r =
       NewRunnableMethod("nsUrlClassifierDBServiceWorker::FinishUpdate", mTarget,
                         &nsUrlClassifierDBServiceWorker::FinishUpdate);
   return DispatchToWorkerThread(r);
 }
 
 NS_IMETHODIMP
--- a/toolkit/components/url-classifier/nsUrlClassifierProxies.h
+++ b/toolkit/components/url-classifier/nsUrlClassifierProxies.h
@@ -127,37 +127,16 @@ class UrlClassifierDBServiceWorkerProxy 
 
     NS_DECL_NSIRUNNABLE
 
    private:
     const RefPtr<nsUrlClassifierDBServiceWorker> mTarget;
     const mozilla::safebrowsing::ConstCacheResultArray mEntries;
   };
 
-  class DoLocalLookupRunnable : public mozilla::Runnable {
-   public:
-    DoLocalLookupRunnable(nsUrlClassifierDBServiceWorker* aTarget,
-                          const nsACString& spec,
-                          const nsTArray<nsCString>& tables,
-                          mozilla::safebrowsing::LookupResultArray& results)
-        : mozilla::Runnable(
-              "UrlClassifierDBServiceWorkerProxy::DoLocalLookupRunnable"),
-          mTarget(aTarget),
-          mSpec(spec),
-          mTables(tables),
-          mResults(results) {}
-
-    NS_DECL_NSIRUNNABLE
-   private:
-    const RefPtr<nsUrlClassifierDBServiceWorker> mTarget;
-    const nsCString mSpec;
-    const nsTArray<nsCString> mTables;
-    mozilla::safebrowsing::LookupResultArray& mResults;
-  };
-
   class ClearLastResultsRunnable : public mozilla::Runnable {
    public:
     explicit ClearLastResultsRunnable(nsUrlClassifierDBServiceWorker* aTarget)
         : mozilla::Runnable(
               "UrlClassifierDBServiceWorkerProxy::ClearLastResultsRunnable"),
           mTarget(aTarget) {}
 
     NS_DECL_NSIRUNNABLE
@@ -200,20 +179,16 @@ class UrlClassifierDBServiceWorkerProxy 
 
     NS_DECL_NSIRUNNABLE
    private:
     nsCOMPtr<nsIUrlClassifierCacheInfo> mCache;
     const nsMainThreadPtrHandle<nsIUrlClassifierGetCacheCallback> mCallback;
   };
 
  public:
-  nsresult DoLocalLookupWithURI(
-      const nsACString& spec, const nsTArray<nsCString>& tables,
-      mozilla::safebrowsing::LookupResultArray& results) const;
-
   nsresult OpenDb() const;
   nsresult CloseDb() const;
   nsresult PreShutdown() const;
 
   nsresult CacheCompletions(
       const mozilla::safebrowsing::ConstCacheResultArray& aEntries) const;
 
   nsresult GetCacheInfo(const nsACString& aTable,
--- a/toolkit/recordreplay/ipc/ParentForwarding.cpp
+++ b/toolkit/recordreplay/ipc/ParentForwarding.cpp
@@ -7,16 +7,17 @@
 // This file has the logic which the middleman process uses to forward IPDL
 // messages from the recording process to the UI process, and from the UI
 // process to either itself, the recording process, or both.
 
 #include "ParentInternal.h"
 
 #include "mozilla/dom/PBrowserChild.h"
 #include "mozilla/dom/ContentChild.h"
+#include "mozilla/dom/PWindowGlobalChild.h"
 #include "mozilla/layers/CompositorBridgeChild.h"
 
 namespace mozilla {
 namespace recordreplay {
 namespace parent {
 
 static bool ActiveChildIsRecording() {
   ChildProcessInfo* child = GetActiveChild();
@@ -117,16 +118,32 @@ static bool HandleMessageInMiddleman(ipc
       type <= layers::PCompositorBridge::PCompositorBridgeEnd) {
     layers::CompositorBridgeChild* compositorChild =
         layers::CompositorBridgeChild::Get();
     ipc::IProtocol::Result r = compositorChild->OnMessageReceived(aMessage);
     MOZ_RELEASE_ASSERT(r == ipc::IProtocol::MsgProcessed);
     return true;
   }
 
+  // PWindowGlobal messages could be going to actors in either process.
+  // Receive them here if there is an actor with the right routing ID.
+  if (type >= dom::PWindowGlobal::PWindowGlobalStart &&
+      type <= dom::PWindowGlobal::PWindowGlobalEnd) {
+    dom::ContentChild* contentChild = dom::ContentChild::GetSingleton();
+
+    ipc::IProtocol* actor = contentChild->Lookup(aMessage.routing_id());
+    if (actor) {
+      ipc::IProtocol::Result r =
+          contentChild->PContentChild::OnMessageReceived(aMessage);
+      MOZ_RELEASE_ASSERT(r == ipc::IProtocol::MsgProcessed);
+      return true;
+    }
+    return false;
+  }
+
   return false;
 }
 
 // Return whether a message should be sent to the recording child, even if it
 // is not currently active.
 static bool AlwaysForwardMessage(const IPC::Message& aMessage) {
   // Always forward messages in repaint stress mode, as the active child is
   // almost always a replaying child and lost messages make it hard to load
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -4712,17 +4712,17 @@ bool XRE_IsE10sParentProcess() {
 #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 defined(XP_MACOSX) || defined(XP_WIN)
   if (XRE_IsRDDProcess() || XRE_IsSocketProcess()) {
     return false;
   }
 #endif
   if (XRE_IsContentProcess()) {
     static bool sInited = false;
     static bool sUseNativeEventProcessing = false;
     if (!sInited) {
@@ -4732,16 +4732,28 @@ bool XRE_UseNativeEventProcessing() {
     }
 
     return sUseNativeEventProcessing;
   }
 
   return true;
 }
 
+#if defined(XP_WIN)
+bool XRE_Win32kCallsAllowed() {
+  switch (XRE_GetProcessType()) {
+    case GeckoProcessType_GMPlugin:
+    case GeckoProcessType_RDD:
+      return false;
+    default:
+      return true;
+  }
+}
+#endif
+
 // If you add anything to this enum, please update about:support to reflect it
 enum {
   kE10sEnabledByUser = 0,
   kE10sEnabledByDefault = 1,
   kE10sDisabledByUser = 2,
   // kE10sDisabledInSafeMode = 3, was removed in bug 1172491.
   // kE10sDisabledForAccessibility = 4,
   // kE10sDisabledForMacGfx = 5, was removed in bug 1068674.
--- a/widget/windows/nsAppShell.cpp
+++ b/widget/windows/nsAppShell.cpp
@@ -318,19 +318,21 @@ nsAppShell::Observe(nsISupports* aSubjec
 
 nsresult nsAppShell::Init() {
   LSPAnnotate();
 
   hal::Init();
 
   mozilla::ipc::windows::InitUIThread();
 
-  sTaskbarButtonCreatedMsg = ::RegisterWindowMessageW(kTaskbarButtonEventId);
-  NS_ASSERTION(sTaskbarButtonCreatedMsg,
-               "Could not register taskbar button creation message");
+  if (XRE_Win32kCallsAllowed()) {
+    sTaskbarButtonCreatedMsg = ::RegisterWindowMessageW(kTaskbarButtonEventId);
+    NS_ASSERTION(sTaskbarButtonCreatedMsg,
+                 "Could not register taskbar button creation message");
+  }
 
   // The hidden message window is used for interrupting the processing of native
   // events, so that we can process gecko events. Therefore, we only need it if
   // we are processing native events.
   if (XRE_UseNativeEventProcessing()) {
     mLastNativeEventScheduled = TimeStamp::NowLoRes();
 
     WNDCLASSW wc;
@@ -349,17 +351,17 @@ nsresult nsAppShell::Init() {
       wc.lpszMenuName = (LPCWSTR) nullptr;
       wc.lpszClassName = kWindowClass;
       RegisterClassW(&wc);
     }
 
     mEventWnd = CreateWindowW(kWindowClass, L"nsAppShell:EventWindow", 0, 0, 0,
                               10, 10, HWND_MESSAGE, nullptr, module, nullptr);
     NS_ENSURE_STATE(mEventWnd);
-  } else {
+  } else if (XRE_IsContentProcess()) {
     // We're not generally processing native events, but still using GDI and we
     // still have some internal windows, e.g. from calling CoInitializeEx.
     // So we use a class that will do a single event pump where previously we
     // might have processed multiple events to make sure any occasional messages
     // to these windows are processed. This also allows any internal Windows
     // messages to be processed to ensure the GDI data remains fresh.
     nsCOMPtr<nsIThreadInternal> threadInt =
         do_QueryInterface(NS_GetCurrentThread());
--- a/xpcom/build/nsXULAppAPI.h
+++ b/xpcom/build/nsXULAppAPI.h
@@ -446,16 +446,24 @@ XRE_API(bool, XRE_IsE10sParentProcess, (
 XRE_API(bool, XRE_IsSocketProcess, ())
 
 /**
  * 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, ())
 
+#if defined(XP_WIN)
+/**
+ * @returns true if win32k calls are allowed in this process type, false if
+ *          win32k is (or should be) disabled.
+ */
+XRE_API(bool, XRE_Win32kCallsAllowed, ())
+#endif
+
 typedef void (*MainFunction)(void* aData);
 
 XRE_API(nsresult, XRE_InitParentProcess,
         (int aArgc, char* aArgv[], MainFunction aMainFunction,
          void* aMainFunctionExtraData))
 
 XRE_API(int, XRE_RunIPDLTest, (int aArgc, char* aArgv[]))