Merge mozilla-central to autoland. a=merge CLOSED TREE
authorBrindusan Cristian <cbrindusan@mozilla.com>
Tue, 15 Jan 2019 06:40:07 +0200
changeset 510999 27db609ff5ea151d921696cc0d5f1525a7d0ac19
parent 510998 89bf8ea5967c52f2e9f1bcc174dfdd81d0062143 (current diff)
parent 510954 e49161da578400faf8e938324caff120b95f4863 (diff)
child 511000 73cd4b7b53ba8edbc148e40d101fd9427846ea26
push id10547
push userffxbld-merge
push dateMon, 21 Jan 2019 13:03:58 +0000
treeherdermozilla-beta@24ec1916bffe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone66.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-central to autoland. a=merge CLOSED TREE
--- a/browser/branding/nightly/pref/firefox-branding.js
+++ b/browser/branding/nightly/pref/firefox-branding.js
@@ -1,12 +1,13 @@
 /* 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/. */
 
+pref("startup.homepage_override_nightly.20190116", "https://www.mozilla.org/firefox/dedicated-profiles/");
 pref("startup.homepage_override_url", "https://www.mozilla.org/projects/firefox/%VERSION%/whatsnew/?oldversion=%OLD_VERSION%");
 pref("startup.homepage_welcome_url", "https://www.mozilla.org/projects/firefox/%VERSION%/firstrun/");
 pref("startup.homepage_welcome_url.additional", "");
 // The time interval between checks for a new version (in seconds)
 pref("app.update.interval", 7200); // 2 hours
 // Give the user x seconds to react before showing the big UI. default=12 hours
 pref("app.update.promptWaitTime", 43200);
 // URL user can browse to manually if for some reason all update installation
--- a/browser/components/nsBrowserContentHandler.js
+++ b/browser/components/nsBrowserContentHandler.js
@@ -56,31 +56,48 @@ function resolveURIInternal(aCmdLine, aA
     Cu.reportError(e);
   }
 
   return uri;
 }
 
 var gFirstWindow = false;
 
+function getNormalizedDate() {
+  let pad = num => ("" + num).padStart(2, "0");
+
+  let date = new Date();
+  return `${date.getFullYear()}${pad(date.getMonth() + 1)}${pad(date.getDate())}`;
+}
+
 const OVERRIDE_NONE        = 0;
 const OVERRIDE_NEW_PROFILE = 1;
 const OVERRIDE_NEW_MSTONE  = 2;
 const OVERRIDE_NEW_BUILD_ID = 3;
+const OVERRIDE_NIGHTLY     = 4;
 /**
  * Determines whether a home page override is needed.
  * Returns:
  *  OVERRIDE_NEW_PROFILE if this is the first run with a new profile.
  *  OVERRIDE_NEW_MSTONE if this is the first run with a build with a different
  *                      Gecko milestone (i.e. right after an upgrade).
  *  OVERRIDE_NEW_BUILD_ID if this is the first run with a new build ID of the
  *                        same Gecko milestone (i.e. after a nightly upgrade).
  *  OVERRIDE_NONE otherwise.
  */
 function needHomepageOverride(prefb) {
+  let isInTests = Cu.isInAutomation || Services.prefs.getBoolPref("marionette.enabled", false);
+  if (AppConstants.NIGHTLY_BUILD && !isInTests) {
+    let pref = `startup.homepage_override_nightly.${getNormalizedDate()}`;
+    let url = Services.prefs.getCharPref(pref, "");
+    if (url) {
+      return OVERRIDE_NIGHTLY;
+    }
+  }
+
   var savedmstone = prefb.getCharPref("browser.startup.homepage_override.mstone", "");
 
   if (savedmstone == "ignore")
     return OVERRIDE_NONE;
 
   var mstone = Services.appinfo.platformVersion;
 
   var savedBuildID = prefb.getCharPref("browser.startup.homepage_override.buildID", "");
@@ -539,16 +556,22 @@ nsBrowserContentHandler.prototype = {
             overridePage = overridePage.replace("%OLD_VERSION%", old_mstone);
             break;
           case OVERRIDE_NEW_BUILD_ID:
             if (prefb.prefHasUserValue("app.update.postupdate")) {
               // Send the update ping to signal that the update was successful.
               UpdatePing.handleUpdateSuccess(old_mstone, old_buildId);
             }
             break;
+          case OVERRIDE_NIGHTLY:
+            // Opens a page on the first startup on a particular day.
+            let pref = `startup.homepage_override_nightly.${getNormalizedDate()}`;
+            overridePage = Services.prefs.getCharPref(pref);
+            Services.prefs.setCharPref(pref, "");
+            break;
         }
       }
     } catch (ex) {}
 
     // formatURLPref might return "about:blank" if getting the pref fails
     if (overridePage == "about:blank")
       overridePage = "";
 
--- a/devtools/client/inspector/reducers.js
+++ b/devtools/client/inspector/reducers.js
@@ -12,9 +12,10 @@ exports.boxModel = require("devtools/cli
 exports.changes = require("devtools/client/inspector/changes/reducers/changes");
 exports.extensionsSidebar = require("devtools/client/inspector/extensions/reducers/sidebar");
 exports.flexbox = require("devtools/client/inspector/flexbox/reducers/flexbox");
 exports.fontOptions = require("devtools/client/inspector/fonts/reducers/font-options");
 exports.fontData = require("devtools/client/inspector/fonts/reducers/fonts");
 exports.fontEditor = require("devtools/client/inspector/fonts/reducers/font-editor");
 exports.grids = require("devtools/client/inspector/grids/reducers/grids");
 exports.highlighterSettings = require("devtools/client/inspector/grids/reducers/highlighter-settings");
+exports.pseudoClasses = require("devtools/client/inspector/rules/reducers/pseudo-classes");
 exports.rules = require("devtools/client/inspector/rules/reducers/rules");
--- a/devtools/client/inspector/rules/actions/index.js
+++ b/devtools/client/inspector/rules/actions/index.js
@@ -3,12 +3,23 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const { createEnum } = require("devtools/client/shared/enum");
 
 createEnum([
 
+  // Disables all the pseudo class checkboxes because the current selection is not an
+  // element node.
+  "DISABLE_ALL_PSEUDO_CLASSES",
+
+  // 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 the rules state with the new list of CSS rules for the selected element.
   "UPDATE_RULES",
 
 ], module.exports);
--- a/devtools/client/inspector/rules/actions/moz.build
+++ b/devtools/client/inspector/rules/actions/moz.build
@@ -1,8 +1,9 @@
 # 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/.
 
 DevToolsModules(
     'index.js',
+    'pseudo-classes.js',
     'rules.js',
 )
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/rules/actions/pseudo-classes.js
@@ -0,0 +1,52 @@
+/* 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 {
+  DISABLE_ALL_PSEUDO_CLASSES,
+  SET_PSEUDO_CLASSES,
+  TOGGLE_PSEUDO_CLASS,
+} = require("./index");
+
+module.exports = {
+
+  /**
+   * Disables all the pseudo class checkboxes because the current selection is not an
+   * element node.
+   */
+  disableAllPseudoClasses() {
+    return {
+      type: DISABLE_ALL_PSEUDO_CLASSES,
+    };
+  },
+
+  /**
+   * Sets the entire pseudo class state with the new list of applied pseudo-class
+   * locks.
+   *
+   * @param  {Array<String>} pseudoClassLocks
+   *         Array of all pseudo class locks applied to the current selected element.
+   */
+  setPseudoClassLocks(pseudoClassLocks) {
+    return {
+      type: SET_PSEUDO_CLASSES,
+      pseudoClassLocks,
+    };
+  },
+
+  /**
+   * Toggles on or off the given pseudo class value for the current selected element.
+   *
+   * @param  {String} pseudoClass
+   *         The pseudo class value to toggle on or off.
+   */
+  togglePseudoClass(pseudoClass) {
+    return {
+      type: TOGGLE_PSEUDO_CLASS,
+      pseudoClass,
+    };
+  },
+
+};
--- a/devtools/client/inspector/rules/components/PseudoClassPanel.js
+++ b/devtools/client/inspector/rules/components/PseudoClassPanel.js
@@ -1,57 +1,68 @@
 /* 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 { PureComponent } = require("devtools/client/shared/vendor/react");
 const dom = require("devtools/client/shared/vendor/react-dom-factories");
+const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
+const { connect } = require("devtools/client/shared/vendor/react-redux");
+
+const Types = require("../types");
 
 class PseudoClassPanel extends PureComponent {
   static get propTypes() {
-    return {};
+    return {
+      onTogglePseudoClass: PropTypes.func.isRequired,
+      pseudoClasses: PropTypes.shape(Types.pseudoClasses).isRequired,
+    };
+  }
+
+  constructor(props) {
+    super(props);
+    this.onInputChange = this.onInputChange.bind(this);
+  }
+
+  onInputChange(event) {
+    this.props.onTogglePseudoClass(event.target.value);
   }
 
   render() {
+    const { pseudoClasses } = this.props;
+
     return (
       dom.div(
         {
           id: "pseudo-class-panel",
           className: "ruleview-reveal-panel",
         },
-        dom.label({},
-          dom.input({
-            id: "pseudo-hover-toggle",
-            checked: false,
-            tabIndex: -1,
-            type: "checkbox",
-            value: ":hover",
-          }),
-          ":hover"
-        ),
-        dom.label({},
-          dom.input({
-            id: "pseudo-active-toggle",
-            checked: false,
-            tabIndex: -1,
-            type: "checkbox",
-            value: ":active",
-          }),
-          ":active"
-        ),
-        dom.label({},
-          dom.input({
-            id: "pseudo-focus-toggle",
-            checked: false,
-            tabIndex: -1,
-            type: "checkbox",
-            value: ":focus",
-          }),
-          ":focus"
-        )
+        Object.entries(pseudoClasses).map(([value, { isChecked, isDisabled }]) => {
+          return (
+            dom.label({},
+              dom.input({
+                key: value,
+                id: `pseudo-${value.slice(1)}-toggle`,
+                checked: isChecked,
+                disabled: isDisabled,
+                onChange: this.onInputChange,
+                tabIndex: 0,
+                type: "checkbox",
+                value,
+              }),
+              value
+            )
+          );
+        })
       )
     );
   }
 }
 
-module.exports = PseudoClassPanel;
+const mapStateToProps = state => {
+  return {
+    pseudoClasses: state.pseudoClasses,
+  };
+};
+
+module.exports = connect(mapStateToProps)(PseudoClassPanel);
--- a/devtools/client/inspector/rules/components/RulesApp.js
+++ b/devtools/client/inspector/rules/components/RulesApp.js
@@ -23,16 +23,17 @@ const Toolbar = createFactory(require(".
 const { getStr } = require("../utils/l10n");
 const Types = require("../types");
 
 const SHOW_PSEUDO_ELEMENTS_PREF = "devtools.inspector.show_pseudo_elements";
 
 class RulesApp extends PureComponent {
   static get propTypes() {
     return {
+      onTogglePseudoClass: PropTypes.func.isRequired,
       rules: PropTypes.arrayOf(PropTypes.shape(Types.rule)).isRequired,
     };
   }
 
   renderInheritedRules(rules) {
     if (!rules.length) {
       return null;
     }
@@ -139,17 +140,19 @@ class RulesApp extends PureComponent {
     }
 
     return (
       dom.div(
         {
           id: "sidebar-panel-ruleview",
           className: "theme-sidebar inspector-tabpanel",
         },
-        Toolbar({}),
+        Toolbar({
+          onTogglePseudoClass: this.props.onTogglePseudoClass,
+        }),
         dom.div(
           {
             id: "ruleview-container",
             className: "ruleview",
           },
           dom.div(
             {
               id: "ruleview-container-focusable",
--- a/devtools/client/inspector/rules/components/Toolbar.js
+++ b/devtools/client/inspector/rules/components/Toolbar.js
@@ -1,31 +1,34 @@
 /* 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 { createFactory, PureComponent } = require("devtools/client/shared/vendor/react");
 const dom = require("devtools/client/shared/vendor/react-dom-factories");
+const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
 
 const SearchBox = createFactory(require("./SearchBox"));
 
 loader.lazyGetter(this, "ClassListPanel", function() {
   return createFactory(require("./ClassListPanel"));
 });
 loader.lazyGetter(this, "PseudoClassPanel", function() {
   return createFactory(require("./PseudoClassPanel"));
 });
 
 const { getStr } = require("../utils/l10n");
 
 class Toolbar extends PureComponent {
   static get propTypes() {
-    return {};
+    return {
+      onTogglePseudoClass: PropTypes.func.isRequired,
+    };
   }
 
   constructor(props) {
     super(props);
 
     this.state = {
       // Whether or not the class panel is expanded.
       isClassPanelExpanded: false,
@@ -103,17 +106,19 @@ class Toolbar extends PureComponent {
             })
           )
         ),
         isClassPanelExpanded ?
           ClassListPanel({})
           :
           null,
         isPseudoClassPanelExpanded ?
-          PseudoClassPanel({})
+          PseudoClassPanel({
+            onTogglePseudoClass: this.props.onTogglePseudoClass,
+          })
           :
           null
       )
     );
   }
 }
 
 module.exports = Toolbar;
--- a/devtools/client/inspector/rules/new-rules.js
+++ b/devtools/client/inspector/rules/new-rules.js
@@ -4,16 +4,21 @@
 
 "use strict";
 
 const Services = require("Services");
 const ElementStyle = require("devtools/client/inspector/rules/models/element-style");
 const { createFactory, createElement } = require("devtools/client/shared/vendor/react");
 const { Provider } = require("devtools/client/shared/vendor/react-redux");
 
+const {
+  disableAllPseudoClasses,
+  setPseudoClassLocks,
+  togglePseudoClass,
+} = require("./actions/pseudo-classes");
 const { updateRules } = require("./actions/rules");
 
 const RulesApp = createFactory(require("./components/RulesApp"));
 
 const { LocalizationHelper } = require("devtools/shared/l10n");
 const INSPECTOR_L10N =
   new LocalizationHelper("devtools/client/locales/inspector.properties");
 
@@ -27,30 +32,33 @@ class RulesView {
     this.pageStyle = inspector.pageStyle;
     this.selection = inspector.selection;
     this.store = inspector.store;
     this.toolbox = inspector.toolbox;
 
     this.showUserAgentStyles = Services.prefs.getBoolPref(PREF_UA_STYLES);
 
     this.onSelection = this.onSelection.bind(this);
+    this.onTogglePseudoClass = this.onTogglePseudoClass.bind(this);
 
     this.inspector.sidebar.on("select", this.onSelection);
     this.selection.on("detached-front", this.onSelection);
     this.selection.on("new-node-front", this.onSelection);
 
     this.init();
   }
 
   init() {
     if (!this.inspector) {
       return;
     }
 
-    const rulesApp = RulesApp({});
+    const rulesApp = RulesApp({
+      onTogglePseudoClass: this.onTogglePseudoClass,
+    });
 
     const provider = createElement(Provider, {
       id: "ruleview",
       key: "ruleview",
       store: this.store,
       title: INSPECTOR_L10N.getStr("inspector.sidebar.ruleViewTitle"),
     }, rulesApp);
 
@@ -120,30 +128,44 @@ class RulesView {
       this.update();
       return;
     }
 
     this.update(this.selection.nodeFront);
   }
 
   /**
+   * Handler for toggling a pseudo class in the pseudo class panel. Toggles on and off
+   * a given pseudo class value.
+   *
+   * @param  {String} value
+   *         The pseudo class to toggle on or off.
+   */
+  onTogglePseudoClass(value) {
+    this.store.dispatch(togglePseudoClass(value));
+    this.inspector.togglePseudoClass(value);
+  }
+
+  /**
    * Updates the rules view by dispatching the new rules data of the newly selected
    * element. This is called when the rules view becomes visible or upon new node
    * selection.
    *
    * @param  {NodeFront|null} element
    *         The NodeFront of the current selected element.
    */
   async update(element) {
     if (!element) {
+      this.store.dispatch(disableAllPseudoClasses());
       this.store.dispatch(updateRules([]));
       return;
     }
 
     this.elementStyle = new ElementStyle(element, this, {}, this.pageStyle,
       this.showUserAgentStyles);
     await this.elementStyle.populate();
 
+    this.store.dispatch(setPseudoClassLocks(this.elementStyle.element.pseudoClassLocks));
     this.store.dispatch(updateRules(this.elementStyle.rules));
   }
 }
 
 module.exports = RulesView;
--- a/devtools/client/inspector/rules/reducers/moz.build
+++ b/devtools/client/inspector/rules/reducers/moz.build
@@ -1,7 +1,8 @@
 # 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/.
 
 DevToolsModules(
+    'pseudo-classes.js',
     'rules.js',
 )
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/rules/reducers/pseudo-classes.js
@@ -0,0 +1,62 @@
+/* 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 {
+  DISABLE_ALL_PSEUDO_CLASSES,
+  SET_PSEUDO_CLASSES,
+  TOGGLE_PSEUDO_CLASS,
+} = require("../actions/index");
+const { PSEUDO_CLASSES } = require("devtools/client/inspector/rules/constants");
+
+const INITIAL_PSEUDO_CLASSES = PSEUDO_CLASSES.reduce((accumulator, pseudoClass) => {
+  accumulator[pseudoClass] = {
+    isChecked: false,
+    isDisabled: false,
+  };
+  return accumulator;
+}, {});
+
+const reducers = {
+
+  [DISABLE_ALL_PSEUDO_CLASSES]() {
+    return PSEUDO_CLASSES.reduce((accumulator, pseudoClass) => {
+      accumulator[pseudoClass] = {
+        isChecked: false,
+        isDisabled: true,
+      };
+      return accumulator;
+    }, {});
+  },
+
+  [SET_PSEUDO_CLASSES](_, { pseudoClassLocks }) {
+    return PSEUDO_CLASSES.reduce((accumulator, pseudoClass) => {
+      accumulator[pseudoClass] = {
+        isChecked: pseudoClassLocks.includes(pseudoClass),
+        isDisabled: false,
+      };
+      return accumulator;
+    }, {});
+  },
+
+  [TOGGLE_PSEUDO_CLASS](pseudoClasses, { pseudoClass }) {
+    return {
+      ...pseudoClasses,
+      [pseudoClass]: {
+        ...pseudoClasses[pseudoClass],
+        isChecked: !pseudoClasses[pseudoClass].isChecked,
+      },
+    };
+  },
+
+};
+
+module.exports = function(pseudoClasses = INITIAL_PSEUDO_CLASSES, action) {
+  const reducer = reducers[action.type];
+  if (!reducer) {
+    return pseudoClasses;
+  }
+  return reducer(pseudoClasses, action);
+};
--- a/devtools/client/inspector/rules/types.js
+++ b/devtools/client/inspector/rules/types.js
@@ -40,16 +40,53 @@ const declaration = exports.declaration 
   // The declaration's priority (either "important" or an empty string).
   priority: PropTypes.string,
 
   // The declaration's property value.
   value: PropTypes.string,
 };
 
 /**
+ * The pseudo classes redux structure.
+ */
+exports.pseudoClasses = {
+  // An object containing the :active pseudo class toggle state.
+  ":active": PropTypes.shape({
+    // Whether or not the :active pseudo class is checked.
+    isChecked: PropTypes.bool,
+    // Whether or not the :active pseudo class is disabled.
+    isDisabled: PropTypes.bool,
+  }),
+
+  // An object containing the :focus pseudo class toggle state.
+  ":focus": PropTypes.shape({
+    // Whether or not the :focus pseudo class is checked
+    isChecked: PropTypes.bool,
+    // Whether or not the :focus pseudo class is disabled.
+    isDisabled: PropTypes.bool,
+  }),
+
+  // An object containing the :focus-within pseudo class toggle state.
+  ":focus-within": PropTypes.shape({
+    // Whether or not the :focus-within pseudo class is checked
+    isChecked: PropTypes.bool,
+    // Whether or not the :focus-within pseudo class is disabled.
+    isDisabled: PropTypes.bool,
+  }),
+
+  // An object containing the :hover pseudo class toggle state.
+  ":hover": PropTypes.shape({
+    // Whether or not the :hover pseudo class is checked.
+    isChecked: PropTypes.bool,
+    // Whether or not the :hover pseudo class is disabled.
+    isDisabled: PropTypes.bool,
+  }),
+};
+
+/**
  * A CSS selector.
  */
 const selector = exports.selector = {
   // Array of the selectors that match the selected element.
   matchedSelectors: PropTypes.arrayOf(PropTypes.string),
   // The CSS rule's selector text content.
   selectorText: PropTypes.string,
   // Array of the CSS rule's selectors.
--- a/dom/media/webaudio/AudioNodeEngineNEON.cpp
+++ b/dom/media/webaudio/AudioNodeEngineNEON.cpp
@@ -1,15 +1,15 @@
 /* -*- mode: c++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* this source code form is subject to the terms of the mozilla public
  * license, v. 2.0. if a copy of the mpl was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "AudioNodeEngineNEON.h"
-#if defined(_MSC_VER) && defined(_M_ARM64)
+#if defined(_MSC_VER) && defined(_M_ARM64) && !defined(__clang__)
 #include <arm64_neon.h>
 #else
 #include <arm_neon.h>
 #endif
 
 //#ifdef DEBUG
 #if 0  // see bug 921099
 #define ASSERT_ALIGNED(ptr)                                     \
--- a/js/src/gc/GCMarker.h
+++ b/js/src/gc/GCMarker.h
@@ -312,16 +312,19 @@ class GCMarker : public JSTracer {
   size_t getMarkCount() const { return markCount; }
   void clearMarkCount() { markCount = 0; }
 
   static GCMarker* fromTracer(JSTracer* trc) {
     MOZ_ASSERT(trc->isMarkingTracer());
     return static_cast<GCMarker*>(trc);
   }
 
+  template <typename T>
+  void markImplicitEdges(T* oldThing);
+
  private:
 #ifdef DEBUG
   void checkZone(void* p);
 #else
   void checkZone(void* p) {}
 #endif
 
   // Push an object onto the stack for later tracing and assert that it has
@@ -331,18 +334,16 @@ class GCMarker : public JSTracer {
   template <typename T>
   void markAndTraceChildren(T* thing);
   template <typename T>
   void markAndPush(T* thing);
   template <typename T>
   void markAndScan(T* thing);
   template <typename T>
   void markImplicitEdgesHelper(T oldThing);
-  template <typename T>
-  void markImplicitEdges(T* oldThing);
   void eagerlyMarkChildren(JSLinearString* str);
   void eagerlyMarkChildren(JSRope* rope);
   void eagerlyMarkChildren(JSString* str);
   void eagerlyMarkChildren(LazyScript* thing);
   void eagerlyMarkChildren(Shape* shape);
   void eagerlyMarkChildren(Scope* scope);
   void lazilyMarkChildren(ObjectGroup* group);
 
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -672,16 +672,20 @@ void GCMarker::markImplicitEdgesHelper(T
 template <>
 void GCMarker::markImplicitEdgesHelper(HasNoImplicitEdgesType) {}
 
 template <typename T>
 void GCMarker::markImplicitEdges(T* thing) {
   markImplicitEdgesHelper<typename ImplicitEdgeHolderType<T*>::Type>(thing);
 }
 
+template void GCMarker::markImplicitEdges(JSObject*);
+template void GCMarker::markImplicitEdges(JSScript*);
+template void GCMarker::markImplicitEdges(LazyScript*);
+
 }  // namespace js
 
 template <typename T>
 static inline bool ShouldMark(GCMarker* gcmarker, T thing) {
   // Don't trace things that are owned by another runtime.
   if (IsOwnedByOtherRuntime(gcmarker->runtime(), thing)) {
     return false;
   }
@@ -861,17 +865,16 @@ void GCMarker::traverse(js::Scope* thing
 // included for historical reasons. JSScript normally cannot recurse, but may
 // be used as a weakmap key and thereby recurse into weakmapped values.
 template <typename T>
 void js::GCMarker::markAndPush(T* thing) {
   if (!mark(thing)) {
     return;
   }
   pushTaggedPtr(thing);
-  markImplicitEdges(thing);
 }
 namespace js {
 template <>
 void GCMarker::traverse(JSObject* thing) {
   markAndPush(thing);
 }
 template <>
 void GCMarker::traverse(ObjectGroup* thing) {
@@ -1022,16 +1025,20 @@ void LazyScript::traceChildren(JSTracer*
                                  "closedOverBinding");
     }
   }
 
   GCPtrFunction* innerFunctions = this->innerFunctions();
   for (auto i : IntegerRange(numInnerFunctions())) {
     TraceEdge(trc, &innerFunctions[i], "lazyScriptInnerFunction");
   }
+
+  if (trc->isMarkingTracer()) {
+    return GCMarker::fromTracer(trc)->markImplicitEdges(this);
+  }
 }
 inline void js::GCMarker::eagerlyMarkChildren(LazyScript* thing) {
   if (thing->script_) {
     noteWeakEdge(thing->script_.unsafeUnbarrieredForTracing());
   }
 
   if (thing->function_) {
     traverseEdge(thing, static_cast<JSObject*>(thing->function_));
--- a/js/src/vm/JSScript.cpp
+++ b/js/src/vm/JSScript.cpp
@@ -4380,16 +4380,20 @@ void JSScript::traceChildren(JSTracer* t
     TraceManuallyBarrieredEdge(trc, &lazyScript, "lazyScript");
   }
 
   if (trc->isMarkingTracer()) {
     realm()->mark();
   }
 
   jit::TraceJitScripts(trc, this);
+
+  if (trc->isMarkingTracer()) {
+    return GCMarker::fromTracer(trc)->markImplicitEdges(this);
+  }
 }
 
 void LazyScript::finalize(FreeOp* fop) { fop->free_(table_); }
 
 size_t JSScript::calculateLiveFixed(jsbytecode* pc) {
   size_t nlivefixed = numAlwaysLiveFixedSlots();
 
   if (nfixed() != nlivefixed) {