Merge inbound to mozilla-central. a=merge
authorMargareta Eliza Balazs <ebalazs@mozilla.com>
Fri, 29 Jun 2018 12:41:54 +0300
changeset 812437 bf149090f6b5db3fe86618b5f1047b70b1bff8b5
parent 812436 7f2d9870614484433ef66a83639907a33f9c2852 (current diff)
parent 812404 9b715408b60b0ef2402c13c0ce917558e2830614 (diff)
child 812438 cc8c21478e6ca403629e91d22efbd398b08c9a14
child 812442 b69a4186516bac1dfd51cb94068188daa3a9ae5d
child 812443 3b639c1c62fb9181b6625e18499a938b5f93d684
child 812444 ceca8dcc1986b4827c097cc95e82352857454552
child 812447 11c74bfa5cb246ba6a45646896dc01728257d2aa
child 812449 c079e3687427d5ddd192e4d14237b609d67427d4
child 812454 6c40ff372b9d777151af86ac8e6672f91469afee
child 812461 6abe8018c00b4ae69e45bb28e9bb2534f73164c9
child 812465 4f91b877499cb62eb6cc6b958e2d5439b3adc30e
child 812471 0e2aab274751716619a1298ef971f86a1f7b8591
child 812472 97c18e1125c490f3e9aa3b9d5c864f99da6fd265
child 812476 605f4e56eb71e75293897b383cd3ff4900d1d7e3
child 812477 87f4ccc002eb8a8d2c5dc3c5d2f6e47b86d13134
child 812493 fdd509dddae212daf00014822a9c9ed690917132
child 812494 1de90eddf23f0929d9998653408e9468b33c484d
child 812517 28534c22986ec6ffeeca04d6e1cd405dd5b44b90
child 812542 2be4930547501db5462cddfa9851325c8468ddf2
child 812552 b24708f98a7e5517c36d3a79bb7ce4e75d01e59a
child 812656 bfe33b8a9238fc2c83fefbdbd4c30f9fc78da429
child 812912 e9e1c6332eb506e9d03109b88545c82ba792b280
child 813382 5435eafd69a774ad400762898feebd7f7db7ea33
push id114542
push userjdescottes@mozilla.com
push dateFri, 29 Jun 2018 10:33:35 +0000
reviewersmerge
milestone63.0a1
Merge inbound to mozilla-central. a=merge
browser/base/content/test/general/browser_bug408415.js
browser/base/content/test/general/browser_bug550565.js
browser/base/content/test/general/browser_favicon_change.js
browser/base/content/test/general/browser_favicon_change_not_in_document.js
browser/base/content/test/general/browser_subframe_favicons_not_used.js
browser/base/content/test/general/file_bug970276_favicon1.ico
browser/base/content/test/general/file_bug970276_popup1.html
browser/base/content/test/general/file_bug970276_popup2.html
browser/base/content/test/general/file_favicon_change.html
browser/base/content/test/general/file_favicon_change_not_in_document.html
browser/base/content/test/general/file_with_favicon.html
dom/canvas/test/crash/mochitest.ini
dom/canvas/test/webgl-conf/generate-wrappers-and-manifest.py
dom/canvas/test/webgl-conf/generated-mochitest.ini
dom/canvas/test/webgl-conf/mochitest-errata.ini
python/mozbuild/mozbuild/action/generate_builtin_addons.py
taskcluster/ci/test/mochitest.yml
taskcluster/ci/test/test-sets.yml
taskcluster/taskgraph/test/test_try_option_syntax.py
testing/mozbase/moztest/moztest/resolve.py
testing/mozharness/configs/android/android_common.py
testing/mozharness/configs/android/android_hw.py
testing/mozharness/configs/unittests/linux_unittest.py
testing/mozharness/configs/unittests/mac_unittest.py
testing/mozharness/configs/unittests/win_taskcluster_unittest.py
testing/mozharness/configs/unittests/win_unittest.py
testing/mozharness/mozharness/mozilla/testing/errors.py
testing/mozharness/mozharness/mozilla/testing/per_test_base.py
testing/mozharness/mozharness/mozilla/testing/testbase.py
--- a/browser/app/Makefile.in
+++ b/browser/app/Makefile.in
@@ -74,17 +74,17 @@ endif
 LPROJ := Contents/Resources/$(LPROJ_ROOT).lproj
 
 clean clobber repackage::
 	$(RM) -r $(dist_dest)
 
 MAC_BUNDLE_VERSION = $(shell $(PYTHON) $(srcdir)/macversion.py --version=$(MOZ_APP_VERSION) --buildid=$(DEPTH)/buildid.h)
 
 .PHONY: repackage
-tools repackage:: $(DIST)/bin/$(MOZ_APP_NAME) features
+tools repackage:: $(DIST)/bin/$(MOZ_APP_NAME)
 	rm -rf $(dist_dest)
 	$(MKDIR) -p '$(dist_dest)/Contents/MacOS'
 	$(MKDIR) -p '$(dist_dest)/$(LPROJ)'
 	rsync -a --exclude '*.in' $(srcdir)/macbuild/Contents '$(dist_dest)' --exclude English.lproj
 	rsync -a --exclude '*.in' $(srcdir)/macbuild/Contents/Resources/English.lproj/ '$(dist_dest)/$(LPROJ)'
 	sed -e 's/%APP_VERSION%/$(MOZ_APP_VERSION)/' -e 's/%MAC_APP_NAME%/$(MAC_APP_NAME)/' -e 's/%MOZ_MACBUNDLE_ID%/$(MOZ_MACBUNDLE_ID)/' -e 's/%MAC_BUNDLE_VERSION%/$(MAC_BUNDLE_VERSION)/' -e 's|%MOZ_DEVELOPER_REPO_PATH%|$(topsrcdir)|' -e 's|%MOZ_DEVELOPER_OBJ_PATH%|$(topobjdir)|' $(srcdir)/macbuild/Contents/Info.plist.in > '$(dist_dest)/Contents/Info.plist'
 	sed -e 's/%MAC_APP_NAME%/$(MAC_APP_NAME)/' $(srcdir)/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in | iconv -f UTF-8 -t UTF-16 > '$(dist_dest)/$(LPROJ)/InfoPlist.strings'
 	rsync -a --exclude-from='$(srcdir)/macbuild/Contents/MacOS-files.in' $(DIST)/bin/ '$(dist_dest)/Contents/Resources'
@@ -95,12 +95,8 @@ tools repackage:: $(DIST)/bin/$(MOZ_APP_
 	cp -RL $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/document.icns '$(dist_dest)/Contents/Resources/document.icns'
 	$(MKDIR) -p '$(dist_dest)/Contents/Library/LaunchServices'
 ifdef MOZ_UPDATER
 	mv -f '$(dist_dest)/Contents/MacOS/updater.app/Contents/MacOS/org.mozilla.updater' '$(dist_dest)/Contents/Library/LaunchServices'
 	ln -s ../../../../Library/LaunchServices/org.mozilla.updater '$(dist_dest)/Contents/MacOS/updater.app/Contents/MacOS/org.mozilla.updater'
 endif
 	printf APPLMOZB > '$(dist_dest)/Contents/PkgInfo'
 endif
-
-.PHONY: features
-tools features::
-	$(call py_action,generate_builtin_addons,--features=browser/features browser/chrome/browser/content/browser/built_in_addons.json)
--- a/config/faster/rules.mk
+++ b/config/faster/rules.mk
@@ -91,28 +91,8 @@ ACDEFINES += -DBUILD_FASTER
 		$(ACDEFINES) \
 		install_$(subst /,_,$*)
 
 # ============================================================================
 # Below is a set of additional dependencies and variables used to build things
 # that are not supported by data in moz.build.
 
 $(TOPOBJDIR)/build/application.ini: $(TOPOBJDIR)/buildid.h $(TOPOBJDIR)/source-repo.h
-
-# The manifest of allowed system add-ons should be re-built when using
-# "build faster".
-#
-# Note the dependency on install-dist/bin.  The form of this
-# dependency is critical: it's triggering the stem rule (install-%)
-# above to force the dist/bin manifest to be processed.  The more
-# obvious `$(TOPOBJDIR)/install-dist_bin` doesn't work because
-# dist/bin isn't in $(INSTALL_MANIFESTS) in the
-# FasterMake+RecursiveMake (artifact build) situation.
-ifeq ($(MOZ_BUILD_APP),browser)
-$(TOPOBJDIR)/browser/app/features: install-dist/bin
-
-default: $(TOPOBJDIR)/browser/app/features
-endif
-ifeq ($(MOZ_BUILD_APP),mobile/android)
-$(TOPOBJDIR)/mobile/android/base/features: install-dist/bin
-
-default: $(TOPOBJDIR)/mobile/android/base/features
-endif
--- a/devtools/client/debugger/new/src/actions/ast.js
+++ b/devtools/client/debugger/new/src/actions/ast.js
@@ -96,22 +96,24 @@ function setOutOfScopeLocations() {
       type: "OUT_OF_SCOPE_LOCATIONS",
       locations
     });
     dispatch((0, _setInScopeLines.setInScopeLines)());
   };
 }
 
 function compressPausePoints(pausePoints) {
-  const compressed = {}
+  const compressed = {};
+
   for (const line in pausePoints) {
-    compressed[line] = {}
+    compressed[line] = {};
+
     for (const col in pausePoints[line]) {
-      const point = pausePoints[line][col]
-      compressed[line][col] = (point.break && 1) | (point.step && 2)
+      const point = pausePoints[line][col];
+      compressed[line][col] = (point.break && 1) | (point.step && 2);
     }
   }
 
   return compressed;
 }
 
 function setPausePoints(sourceId) {
   return async ({
--- a/devtools/client/debugger/new/src/actions/preview.js
+++ b/devtools/client/debugger/new/src/actions/preview.js
@@ -6,98 +6,59 @@ Object.defineProperty(exports, "__esModu
 exports.updatePreview = updatePreview;
 exports.setPreview = setPreview;
 exports.clearPreview = clearPreview;
 
 var _preview = require("../utils/preview");
 
 var _ast = require("../utils/ast");
 
-var _editor = require("../utils/editor/index");
-
 var _devtoolsSourceMap = require("devtools/client/shared/source-map/index.js");
 
 var _promise = require("./utils/middleware/promise");
 
 var _getExpression = require("../utils/editor/get-expression");
 
 var _selectors = require("../selectors/index");
 
 var _expressions = require("./expressions");
 
 var _pause = require("./pause/index");
 
-var _lodash = require("devtools/client/shared/vendor/lodash");
-
 /* 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/>. */
-function isInvalidTarget(target) {
-  if (!target || !target.innerText) {
-    return true;
+function findExpressionMatch(state, codeMirror, tokenPos) {
+  const source = (0, _selectors.getSelectedSource)(state);
+  const symbols = (0, _selectors.getSymbols)(state, source);
+  let match;
+
+  if (!symbols || symbols.loading) {
+    match = (0, _getExpression.getExpressionFromCoords)(codeMirror, tokenPos);
+  } else {
+    match = (0, _ast.findBestMatchExpression)(symbols, tokenPos);
   }
 
-  const tokenText = target.innerText.trim();
-  const cursorPos = target.getBoundingClientRect(); // exclude literal tokens where it does not make sense to show a preview
-
-  const invalidType = ["cm-atom", ""].includes(target.className); // exclude syntax where the expression would be a syntax error
-
-  const invalidToken = tokenText === "" || tokenText.match(/^[(){}\|&%,.;=<>\+-/\*\s](?=)/);
-  const isPresentation = target.attributes.role && target.attributes.getNamedItem("role").value == "presentation"; // exclude codemirror elements that are not tokens
-
-  const invalidTarget = target.parentElement && !target.parentElement.closest(".CodeMirror-line") || cursorPos.top == 0;
-  return invalidTarget || invalidToken || invalidType || isPresentation;
+  return match;
 }
 
-function updatePreview(target, editor) {
+function updatePreview(target, tokenPos, codeMirror) {
   return ({
     dispatch,
     getState,
     client,
     sourceMaps
   }) => {
-    const tokenPos = (0, _editor.getTokenLocation)(editor.codeMirror, target);
     const cursorPos = target.getBoundingClientRect();
-    const preview = (0, _selectors.getPreview)(getState());
 
-    if ((0, _selectors.getCanRewind)(getState())) {
+    if ((0, _selectors.getCanRewind)(getState()) || !(0, _selectors.isSelectedFrameVisible)(getState()) || !(0, _selectors.isLineInScope)(getState(), tokenPos.line)) {
       return;
     }
 
-    if (preview) {
-      // Return early if we are currently showing another preview or
-      // if we are mousing over the same token as before
-      if (preview.updating || (0, _lodash.isEqual)(preview.tokenPos, tokenPos)) {
-        return;
-      } // We are mousing over a new token that is not in the preview
-
-
-      if (!target.classList.contains("debug-expression")) {
-        dispatch(clearPreview());
-      }
-    }
-
-    if (isInvalidTarget(target)) {
-      dispatch(clearPreview());
-      return;
-    }
-
-    if (!(0, _selectors.isSelectedFrameVisible)(getState()) || !(0, _selectors.isLineInScope)(getState(), tokenPos.line)) {
-      return;
-    }
-
-    const source = (0, _selectors.getSelectedSource)(getState());
-    const symbols = (0, _selectors.getSymbols)(getState(), source);
-    let match;
-
-    if (!symbols || symbols.loading) {
-      match = (0, _getExpression.getExpressionFromCoords)(editor.codeMirror, tokenPos);
-    } else {
-      match = (0, _ast.findBestMatchExpression)(symbols, tokenPos);
-    }
+    const match = findExpressionMatch(getState(), codeMirror, tokenPos);
 
     if (!match) {
       return;
     }
 
     const {
       expression,
       location
--- a/devtools/client/debugger/new/src/components/Editor/Preview/Popup.js
+++ b/devtools/client/debugger/new/src/components/Editor/Preview/Popup.js
@@ -24,18 +24,16 @@ var _selectors = require("../../../selec
 var _Popover = require("../../shared/Popover");
 
 var _Popover2 = _interopRequireDefault(_Popover);
 
 var _PreviewFunction = require("../../shared/PreviewFunction");
 
 var _PreviewFunction2 = _interopRequireDefault(_PreviewFunction);
 
-var _editor = require("../../../utils/editor/index");
-
 var _preview = require("../../../utils/preview");
 
 var _Svg = require("devtools/client/debugger/new/dist/vendors").vendored["Svg"];
 
 var _Svg2 = _interopRequireDefault(_Svg);
 
 var _firefox = require("../../../client/firefox");
 
@@ -58,28 +56,42 @@ const {
   getValue,
   nodeIsPrimitive,
   NODE_TYPES
 } = ObjectInspectorUtils.node;
 const {
   loadItemProperties
 } = ObjectInspectorUtils.loadProperties;
 
+function inPreview(event) {
+  const relatedTarget = event.relatedTarget;
+
+  if (!relatedTarget || relatedTarget.classList.contains("preview-expression")) {
+    return true;
+  } // $FlowIgnore
+
+
+  const inPreviewSelection = document.elementsFromPoint(event.clientX, event.clientY).some(el => el.classList.contains("preview-selection"));
+  return inPreviewSelection;
+}
+
 class Popup extends _react.Component {
   constructor(...args) {
     var _temp;
 
     return _temp = super(...args), this.onMouseLeave = e => {
       const relatedTarget = e.relatedTarget;
 
-      if (relatedTarget && relatedTarget.classList && (relatedTarget.classList.contains("popover") || relatedTarget.classList.contains("debug-expression") || relatedTarget.classList.contains("editor-mount"))) {
-        return;
+      if (!relatedTarget) {
+        return this.props.onClose();
       }
 
-      this.props.onClose();
+      if (!inPreview(e)) {
+        this.props.onClose();
+      }
     }, _temp;
   }
 
   async componentWillMount() {
     const {
       value,
       setPopupObjectProperties,
       popupObjectProperties
@@ -91,36 +103,16 @@ class Popup extends _react.Component {
 
       if (onLoadItemProperties !== null) {
         const properties = await onLoadItemProperties;
         setPopupObjectProperties(root.contents.value, properties);
       }
     }
   }
 
-  componentDidMount() {
-    const {
-      value,
-      editor,
-      range
-    } = this.props;
-
-    if (!value || !value.type == "object") {
-      return;
-    }
-
-    this.marker = (0, _editor.markText)(editor, "preview-selection", range);
-  }
-
-  componentWillUnmount() {
-    if (this.marker) {
-      this.marker.clear();
-    }
-  }
-
   getRoot() {
     const {
       expression,
       value,
       extra
     } = this.props;
     let rootValue = value;
 
--- a/devtools/client/debugger/new/src/components/Editor/Preview/index.js
+++ b/devtools/client/debugger/new/src/components/Editor/Preview/index.js
@@ -22,85 +22,128 @@ var _actions2 = _interopRequireDefault(_
 
 var _editor = require("../../../utils/editor/index");
 
 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
 /* 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/>. */
+function inPopup(e) {
+  const {
+    relatedTarget
+  } = e;
+
+  if (!relatedTarget) {
+    return true;
+  }
+
+  const pop = relatedTarget.closest(".popover") || relatedTarget.classList.contains("debug-expression");
+  return pop;
+}
+
+function getElementFromPos(pos) {
+  // $FlowIgnore
+  return document.elementFromPoint(pos.x + pos.width / 2, pos.y + pos.height / 2);
+}
+
 class Preview extends _react.PureComponent {
   constructor(props) {
     super(props);
+    this.target = null;
 
-    this.onMouseOver = e => {
-      const {
-        target
-      } = e;
-      this.props.updatePreview(target, this.props.editor);
+    this.onTokenEnter = ({
+      target,
+      tokenPos
+    }) => {
+      this.props.updatePreview(target, tokenPos, this.props.editor.codeMirror);
+    };
+
+    this.onTokenLeave = e => {
+      if (!inPopup(e)) {
+        this.props.clearPreview();
+      }
     };
 
     this.onMouseUp = () => {
       this.setState({
         selecting: false
       });
       return true;
     };
 
     this.onMouseDown = () => {
       this.setState({
         selecting: true
       });
       return true;
     };
 
-    this.onMouseLeave = e => {
-      const target = e.target;
-
-      if (target.classList.contains("CodeMirror")) {
-        return;
-      }
-
+    this.onScroll = () => {
       this.props.clearPreview();
     };
 
-    this.onClose = () => {
+    this.onClose = e => {
       this.props.clearPreview();
     };
 
     this.state = {
       selecting: false
     };
   }
 
   componentDidMount() {
+    this.updateListeners();
+  }
+
+  componentDidUpdate(prevProps) {
+    this.updateListeners(prevProps);
+    this.updateHighlight(prevProps);
+  }
+
+  updateListeners(prevProps) {
+    const {
+      isPaused
+    } = this.props;
     const {
       codeMirror
     } = this.props.editor;
     const codeMirrorWrapper = codeMirror.getWrapperElement();
-    codeMirrorWrapper.addEventListener("mouseover", this.onMouseOver);
-    codeMirrorWrapper.addEventListener("mouseup", this.onMouseUp);
-    codeMirrorWrapper.addEventListener("mousedown", this.onMouseDown);
-    codeMirrorWrapper.addEventListener("mouseleave", this.onMouseLeave);
+    const wasNotPaused = !prevProps || !prevProps.isPaused;
+    const wasPaused = prevProps && prevProps.isPaused;
 
-    if (document.body) {
-      document.body.addEventListener("mouseleave", this.onMouseLeave);
+    if (isPaused && wasNotPaused) {
+      codeMirror.on("scroll", this.onScroll);
+      codeMirror.on("tokenenter", this.onTokenEnter);
+      codeMirror.on("tokenleave", this.onTokenLeave);
+      codeMirrorWrapper.addEventListener("mouseup", this.onMouseUp);
+      codeMirrorWrapper.addEventListener("mousedown", this.onMouseDown);
+    }
+
+    if (!isPaused && wasPaused) {
+      codeMirror.off("tokenenter", this.onTokenEnter);
+      codeMirror.off("tokenleave", this.onTokenLeave);
+      codeMirrorWrapper.removeEventListener("mouseup", this.onMouseUp);
+      codeMirrorWrapper.removeEventListener("mousedown", this.onMouseDown);
     }
   }
 
-  componentWillUnmount() {
-    const codeMirror = this.props.editor.codeMirror;
-    const codeMirrorWrapper = codeMirror.getWrapperElement();
-    codeMirrorWrapper.removeEventListener("mouseover", this.onMouseOver);
-    codeMirrorWrapper.removeEventListener("mouseup", this.onMouseUp);
-    codeMirrorWrapper.removeEventListener("mousedown", this.onMouseDown);
-    codeMirrorWrapper.removeEventListener("mouseleave", this.onMouseLeave);
+  updateHighlight(prevProps) {
+    const {
+      preview
+    } = this.props;
 
-    if (document.body) {
-      document.body.removeEventListener("mouseleave", this.onMouseLeave);
+    if (preview && !preview.updating) {
+      const target = getElementFromPos(preview.cursorPos);
+      target && target.classList.add("preview-selection");
+    }
+
+    if (prevProps.preview && !prevProps.preview.updating) {
+      const target = getElementFromPos(prevProps.preview.cursorPos);
+      target && target.classList.remove("preview-selection");
     }
   }
 
   render() {
     const {
       selectedSource,
       preview
     } = this.props;
@@ -138,16 +181,17 @@ class Preview extends _react.PureCompone
       onClose: this.onClose
     });
   }
 
 }
 
 const mapStateToProps = state => ({
   preview: (0, _selectors.getPreview)(state),
+  isPaused: (0, _selectors.getIsPaused)(state),
   selectedSource: (0, _selectors.getSelectedSource)(state)
 });
 
 const {
   addExpression,
   setPopupObjectProperties,
   updatePreview,
   clearPreview
--- a/devtools/client/debugger/new/src/components/Editor/index.js
+++ b/devtools/client/debugger/new/src/components/Editor/index.js
@@ -256,16 +256,17 @@ class Editor extends _react.PureComponen
     const codeMirrorWrapper = codeMirror.getWrapperElement();
     (0, _ui.resizeBreakpointGutter)(codeMirror);
     (0, _ui.resizeToggleButton)(codeMirror);
     codeMirror.on("gutterClick", this.onGutterClick); // Set code editor wrapper to be focusable
 
     codeMirrorWrapper.tabIndex = 0;
     codeMirrorWrapper.addEventListener("keydown", e => this.onKeyDown(e));
     codeMirrorWrapper.addEventListener("click", e => this.onClick(e));
+    codeMirrorWrapper.addEventListener("mouseover", (0, _editor.onMouseOver)(codeMirror));
 
     const toggleFoldMarkerVisibility = e => {
       if (node instanceof HTMLElement) {
         node.querySelectorAll(".CodeMirror-guttermarker-subtle").forEach(elem => {
           elem.classList.toggle("visible");
         });
       }
     };
--- a/devtools/client/debugger/new/src/components/SecondaryPanes/Breakpoints/Breakpoint.js
+++ b/devtools/client/debugger/new/src/components/SecondaryPanes/Breakpoints/Breakpoint.js
@@ -147,16 +147,18 @@ class Breakpoint extends _react.PureComp
     }
 
     const node = document.createElement("div");
     editor.CodeMirror.runMode(text, "application/javascript", node);
     return {
       __html: node.innerHTML
     };
   }
+  /* eslint-disable react/no-danger */
+
 
   render() {
     const {
       breakpoint
     } = this.props;
     return _react2.default.createElement("div", {
       className: (0, _classnames2.default)({
         breakpoint,
--- a/devtools/client/debugger/new/src/components/shared/Popover.js
+++ b/devtools/client/debugger/new/src/components/shared/Popover.js
@@ -52,28 +52,16 @@ class Popover extends _react.Component {
 
       if (orientation === "up") {
         return target.top - popover.height;
       }
 
       return this.calculateTopForRightOrientation(target, editor, popover);
     };
 
-    this.onMouseLeave = e => {
-      const {
-        onMouseLeave
-      } = this.props;
-
-      if (/^(bracket-arrow|gap)$/.test(e.currentTarget.className)) {
-        return;
-      }
-
-      onMouseLeave(e);
-    };
-
     this.state = {
       left: 0,
       top: 0,
       targetMid: {
         x: 0,
         y: 0
       },
       orientation: "up"
@@ -255,17 +243,17 @@ class Popover extends _react.Component {
       orientation,
       targetMid
     } = this.state;
     const arrow = this.getPopoverArrow(orientation, targetMid.x, targetMid.y);
     return _react2.default.createElement("div", {
       className: (0, _classnames2.default)("popover", `orientation-${orientation}`, {
         up: orientation === "up"
       }),
-      onMouseLeave: this.onMouseLeave,
+      onMouseLeave: this.props.onMouseLeave,
       style: {
         top,
         left
       },
       ref: c => this.$popover = c
     }, arrow, this.getChildren());
   }
 
--- a/devtools/client/debugger/new/src/reducers/ast.js
+++ b/devtools/client/debugger/new/src/reducers/ast.js
@@ -98,21 +98,26 @@ function update(state = initialASTState(
         if (action.status == "start") {
           return state.set("preview", {
             updating: true
           });
         }
 
         if (!action.value) {
           return state.set("preview", null);
+        } // NOTE: if the preview does not exist, it has been cleared
+
+
+        if (state.get("preview")) {
+          return state.set("preview", _objectSpread({}, action.value, {
+            updating: false
+          }));
         }
 
-        return state.set("preview", _objectSpread({}, action.value, {
-          updating: false
-        }));
+        return state;
       }
 
     case "RESUME":
       {
         return state.set("outOfScopeLocations", null);
       }
 
     case "NAVIGATE":
--- a/devtools/client/debugger/new/src/reducers/pause.js
+++ b/devtools/client/debugger/new/src/reducers/pause.js
@@ -3,16 +3,17 @@
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
 exports.getSelectedFrame = exports.getAllPopupObjectProperties = exports.createPauseState = undefined;
 exports.getPauseReason = getPauseReason;
 exports.getPauseCommand = getPauseCommand;
 exports.isStepping = isStepping;
 exports.isPaused = isPaused;
+exports.getIsPaused = getIsPaused;
 exports.getPreviousPauseFrameLocation = getPreviousPauseFrameLocation;
 exports.isEvaluatingExpression = isEvaluatingExpression;
 exports.getPopupObjectProperties = getPopupObjectProperties;
 exports.getIsWaitingOnBreak = getIsWaitingOnBreak;
 exports.getShouldPauseOnExceptions = getShouldPauseOnExceptions;
 exports.getShouldPauseOnCaughtExceptions = getShouldPauseOnCaughtExceptions;
 exports.getCanRewind = getCanRewind;
 exports.getExtra = getExtra;
@@ -299,16 +300,20 @@ function getPauseCommand(state) {
 function isStepping(state) {
   return ["stepIn", "stepOver", "stepOut"].includes(getPauseCommand(state));
 }
 
 function isPaused(state) {
   return !!getFrames(state);
 }
 
+function getIsPaused(state) {
+  return !!getFrames(state);
+}
+
 function getPreviousPauseFrameLocation(state) {
   return state.pause.previousLocation;
 }
 
 function isEvaluatingExpression(state) {
   return state.pause.command === "expression";
 }
 
--- a/devtools/client/debugger/new/src/utils/editor/index.js
+++ b/devtools/client/debugger/new/src/utils/editor/index.js
@@ -1,13 +1,14 @@
 "use strict";
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
+exports.onMouseOver = undefined;
 
 var _sourceDocuments = require("./source-documents");
 
 Object.keys(_sourceDocuments).forEach(function (key) {
   if (key === "default" || key === "__esModule") return;
   Object.defineProperty(exports, key, {
     enumerable: true,
     get: function () {
@@ -46,16 +47,25 @@ Object.keys(_ui).forEach(function (key) 
   if (key === "default" || key === "__esModule") return;
   Object.defineProperty(exports, key, {
     enumerable: true,
     get: function () {
       return _ui[key];
     }
   });
 });
+
+var _tokenEvents = require("./token-events");
+
+Object.defineProperty(exports, "onMouseOver", {
+  enumerable: true,
+  get: function () {
+    return _tokenEvents.onMouseOver;
+  }
+});
 exports.getEditor = getEditor;
 exports.removeEditor = removeEditor;
 exports.shouldShowPrettyPrint = shouldShowPrettyPrint;
 exports.shouldShowFooter = shouldShowFooter;
 exports.traverseResults = traverseResults;
 exports.toEditorLine = toEditorLine;
 exports.toEditorPosition = toEditorPosition;
 exports.toEditorRange = toEditorRange;
--- a/devtools/client/debugger/new/src/utils/editor/moz.build
+++ b/devtools/client/debugger/new/src/utils/editor/moz.build
@@ -10,9 +10,10 @@ DIRS += [
 DevToolsModules(
     'create-editor.js',
     'get-expression.js',
     'get-token-location.js',
     'index.js',
     'source-documents.js',
     'source-editor.js',
     'source-search.js',
+    'token-events.js',
 )
new file mode 100644
--- /dev/null
+++ b/devtools/client/debugger/new/src/utils/editor/token-events.js
@@ -0,0 +1,93 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports.onMouseOver = onMouseOver;
+
+var _ = require("./index");
+
+var _lodash = require("devtools/client/shared/vendor/lodash");
+
+/* 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/>. */
+function isInvalidTarget(target) {
+  if (!target || !target.innerText) {
+    return true;
+  }
+
+  const tokenText = target.innerText.trim();
+  const cursorPos = target.getBoundingClientRect(); // exclude literal tokens where it does not make sense to show a preview
+
+  const invalidType = ["cm-atom", ""].includes(target.className); // exclude syntax where the expression would be a syntax error
+
+  const invalidToken = tokenText === "" || tokenText.match(/^[(){}\|&%,.;=<>\+-/\*\s](?=)/); // exclude codemirror elements that are not tokens
+
+  const invalidTarget = target.parentElement && !target.parentElement.closest(".CodeMirror-line") || cursorPos.top == 0;
+  const invalidClasses = ["editor-mount"];
+
+  if (invalidClasses.some(className => target.classList.contains(className))) {
+    return true;
+  }
+
+  if (target.closest(".popover")) {
+    return true;
+  }
+
+  return invalidTarget || invalidToken || invalidType;
+}
+
+function dispatch(codeMirror, eventName, data) {
+  codeMirror.constructor.signal(codeMirror, eventName, data);
+}
+
+function invalidLeaveTarget(target) {
+  if (!target || target.closest(".popover")) {
+    return true;
+  }
+
+  return false;
+}
+
+function onMouseOver(codeMirror) {
+  let prevTokenPos = null;
+
+  function onMouseLeave(event) {
+    if (invalidLeaveTarget(event.relatedTarget)) {
+      return addMouseLeave(event.target);
+    }
+
+    prevTokenPos = null;
+    dispatch(codeMirror, "tokenleave", event);
+  }
+
+  function addMouseLeave(target) {
+    target.addEventListener("mouseleave", onMouseLeave, {
+      capture: true,
+      once: true
+    });
+  }
+
+  return enterEvent => {
+    const {
+      target
+    } = enterEvent;
+
+    if (isInvalidTarget(target)) {
+      return;
+    }
+
+    const tokenPos = (0, _.getTokenLocation)(codeMirror, target);
+
+    if (!(0, _lodash.isEqual)(prevTokenPos, tokenPos)) {
+      addMouseLeave(target);
+      dispatch(codeMirror, "tokenenter", {
+        event: enterEvent,
+        target,
+        tokenPos
+      });
+      prevTokenPos = tokenPos;
+    }
+  };
+}
\ No newline at end of file
--- a/devtools/client/debugger/new/test/mochitest/browser.ini
+++ b/devtools/client/debugger/new/test/mochitest/browser.ini
@@ -153,17 +153,17 @@ support-files =
 [browser_dbg-asm.js]
 [browser_dbg-async-stepping.js]
 [browser_dbg-sourcemapped-breakpoint-console.js]
 skip-if = (os == "win" && ccov) # Bug 1453549
 [browser_dbg-sourcemapped-scopes.js]
 skip-if = ccov || (verify && debug && (os == 'linux')) # Bug 1441545
 [browser_dbg-sourcemapped-stepping.js]
 [browser_dbg-sourcemapped-preview.js]
-skip-if = (os == "win" && ccov) || (os == "win" && !debug) # Bug 1448523, Bug 1448450
+skip-if = os == "win" # Bug 1448523, Bug 1448450
 [browser_dbg-breaking.js]
 [browser_dbg-breaking-from-console.js]
 [browser_dbg-breakpoints.js]
 [browser_dbg-breakpoints-reloading.js]
 [browser_dbg-breakpoints-cond.js]
 [browser_dbg-browser-content-toolbox.js]
 skip-if = !e10s || verify # This test is only valid in e10s
 [browser_dbg-call-stack.js]
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-pause-points.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-pause-points.js
@@ -27,16 +27,17 @@ async function testCase(dbg, { name, cou
   is(formattedSteps, steps, name);
 
   await resume(dbg);
 }
 
 add_task(async function test() {
   const dbg = await initDebugger("doc-pause-points.html");
 
+  await selectSource(dbg, "pause-points.js")
   await testCase(dbg, {
     name: "statements",
     count: 7,
     steps: "(9,2), (10,4), (10,13), (11,2), (11,21), (12,2), (12,12), (13,0)"
   });
 
   await testCase(dbg, {
     name: "expressions",
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-preview-module.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-preview-module.js
@@ -1,19 +1,16 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Test hovering in a script that is paused on load
 // and doesn't have functions.
 add_task(async function() {
   const dbg = await initDebugger("doc-scripts.html");
-  const {
-    selectors: { getSelectedSource },
-    getState
-  } = dbg;
+  const { selectors: { getSelectedSource }, getState } = dbg;
 
   navigate(dbg, "doc-on-load.html");
 
   // wait for `top-level.js` to load and to pause at a debugger statement
   await waitForSelectedSource(dbg, "top-level.js");
   await waitForPaused(dbg);
 
   await assertPreviews(dbg, [
--- a/devtools/client/debugger/new/test/mochitest/helpers.js
+++ b/devtools/client/debugger/new/test/mochitest/helpers.js
@@ -1208,37 +1208,53 @@ function getCM(dbg) {
   const el = dbg.win.document.querySelector(".CodeMirror");
   return el.CodeMirror;
 }
 
 function getCoordsFromPosition(cm, { line, ch }) {
   return cm.charCoords({ line: ~~line, ch: ~~ch });
 }
 
-function hoverAtPos(dbg, { line, ch }) {
+async function waitForScrolling(codeMirror) {
+  return new Promise(resolve => {
+    codeMirror.on("scroll", resolve);
+    setTimeout(resolve, 500);
+  })
+}
+
+
+async function hoverAtPos(dbg, { line, ch }) {
   info(`Hovering at ${line}, ${ch}`);
   const cm = getCM(dbg);
 
   // Ensure the line is visible with margin because the bar at the bottom of
   // the editor overlaps into what the editor things is its own space, blocking
   // the click event below.
-  cm.scrollIntoView({ line: line - 1, ch }, 100);
+  cm.scrollIntoView({ line: line - 1, ch }, 0);
+  await waitForScrolling(cm);
 
   const coords = getCoordsFromPosition(cm, { line: line - 1, ch });
   const tokenEl = dbg.win.document.elementFromPoint(coords.left, coords.top);
 
+  if (!tokenEl) {
+    return false;
+  }
+
   tokenEl.dispatchEvent(
     new MouseEvent("mouseover", {
       bubbles: true,
       cancelable: true,
       view: dbg.win
     })
   );
 }
 
+// tryHovering will hover at a position every second until we
+// see a preview element (popup, tooltip) appear. Once it appears,
+// it considers it a success.
 function tryHovering(dbg, line, column, elementName) {
   return new Promise((resolve, reject) => {
     const element = waitForElement(dbg, elementName);
     let count = 0;
 
     element.then(() => {
       clearInterval(interval);
       resolve(element);
@@ -1246,17 +1262,17 @@ function tryHovering(dbg, line, column, 
 
     const interval = setInterval(() => {
       if (count++ == 5) {
         clearInterval(interval);
         reject("failed to preview");
       }
 
       hoverAtPos(dbg, { line, ch: column - 1 });
-    }, 200);
+    }, 1000);
   });
 }
 
 async function assertPreviewTextValue(dbg, line, column, { text, expression }) {
   const previewEl = await tryHovering(dbg, line, column, "previewPopup");
 
   is(previewEl.innerText, text, "Preview text shown to user");
 
--- a/devtools/server/actors/thread.js
+++ b/devtools/server/actors/thread.js
@@ -531,16 +531,17 @@ const ThreadActor = ActorClassWithSpec(t
       // Case 1.3
       if (!lineChanged && !columnChanged) {
         return undefined;
       }
 
       // When pause points are specified for the source,
       // we should pause when we are at a stepOver pause point
       const pausePoint = findPausePointForLocation(pausePoints, newLocation);
+
       if (pausePoint) {
         if (pausePoint.step) {
           return pauseAndRespond(this);
         }
       } else if (lineChanged) {
         // NOTE: if we do not find a pause point we want to
         // fall back on the old behavior (1.3)
         return pauseAndRespond(this);
--- a/dom/base/nsINode.cpp
+++ b/dom/base/nsINode.cpp
@@ -1308,28 +1308,16 @@ ReparentWrappersInSubtree(nsIContent* aR
 {
   MOZ_ASSERT(ShouldUseXBLScope(aRoot));
   // Start off with no global so we don't fire any error events on failure.
   AutoJSAPI jsapi;
   jsapi.Init();
 
   JSContext* cx = jsapi.cx();
 
-  nsIGlobalObject* docGlobal = aRoot->OwnerDoc()->GetScopeObject();
-  if (NS_WARN_IF(!docGlobal)) {
-    return NS_ERROR_UNEXPECTED;
-  }
-
-  JS::Rooted<JSObject*> rootedGlobal(cx, docGlobal->GetGlobalJSObject());
-  if (NS_WARN_IF(!rootedGlobal)) {
-    return NS_ERROR_UNEXPECTED;
-  }
-
-  rootedGlobal = xpc::GetXBLScope(cx, rootedGlobal);
-
   ErrorResult rv;
   JS::Rooted<JSObject*> reflector(cx);
   for (nsIContent* cur = aRoot; cur; cur = cur->GetNextNode(aRoot)) {
     if ((reflector = cur->GetWrapper())) {
       JSAutoRealm ar(cx, reflector);
       ReparentWrapper(cx, reflector, rv);
       rv.WouldReportJSException();
       if (rv.Failed()) {
--- a/dom/clients/manager/ClientManagerService.cpp
+++ b/dom/clients/manager/ClientManagerService.cpp
@@ -470,16 +470,18 @@ ClaimOnMainThread(const ClientInfo& aCli
 
       RefPtr<GenericPromise> inner = swm->MaybeClaimClient(clientInfo, desc);
       inner->Then(SystemGroup::EventTargetFor(TaskCategory::Other), __func__,
         [promise] (bool aResult) {
           promise->Resolve(NS_OK, __func__);
         }, [promise] (nsresult aRv) {
           promise->Reject(aRv, __func__);
         });
+
+      scopeExit.release();
     });
 
   MOZ_ALWAYS_SUCCEEDS(SystemGroup::Dispatch(TaskCategory::Other, r.forget()));
 
   return promise.forget();
 }
 
 } // anonymous namespace
--- a/dom/clients/manager/ClientSource.cpp
+++ b/dom/clients/manager/ClientSource.cpp
@@ -119,16 +119,38 @@ ClientSource::GetDocShell() const
 {
   NS_ASSERT_OWNINGTHREAD(ClientSource);
   if (!mOwner.is<nsCOMPtr<nsIDocShell>>()) {
     return nullptr;
   }
   return mOwner.as<nsCOMPtr<nsIDocShell>>();
 }
 
+nsIGlobalObject*
+ClientSource::GetGlobal() const
+{
+  NS_ASSERT_OWNINGTHREAD(ClientSource);
+  nsPIDOMWindowInner* win = GetInnerWindow();
+  if (win) {
+    return win->AsGlobal();
+  }
+
+  WorkerPrivate* wp = GetWorkerPrivate();
+  if (wp) {
+    return wp->GlobalScope();
+  }
+
+  // Note, ClientSource objects attached to docshell for conceptual
+  // initial about:blank will get nullptr here.  The caller should
+  // use MaybeCreateIntitialDocument() to create the window before
+  // GetGlobal() if it wants this before.
+
+  return nullptr;
+}
+
 void
 ClientSource::MaybeCreateInitialDocument()
 {
   nsIDocShell* docshell = GetDocShell();
   if (docshell) {
     // Force the create of the initial document if it does not exist yet.
     Unused << docshell->GetDocument();
 
@@ -426,20 +448,57 @@ ClientSource::SetController(const Servic
   }
 }
 
 RefPtr<ClientOpPromise>
 ClientSource::Control(const ClientControlledArgs& aArgs)
 {
   NS_ASSERT_OWNINGTHREAD(ClientSource);
 
+  // Determine if the client is allowed to be controlled.  Currently we
+  // prevent service workers from controlling clients that cannot access
+  // storage.  We exempt this restriction for local URL clients, like about:blank
+  // and blob:, since access to service workers is dictated by their parent.
+  //
+  // Note, we default to allowing the client to be controlled in the case
+  // where we are not execution ready yet.  This can only happen if the
+  // the non-subresource load is intercepted by a service worker.  Since
+  // ServiceWorkerInterceptController() uses StorageAllowedForChannel()
+  // it should be fine to accept these control messages.
+  //
+  // Its also fine to default to allowing ClientSource attached to a docshell
+  // to be controlled.  These clients represent inital about:blank windows
+  // that do not have an inner window created yet.  We explicitly allow initial
+  // about:blank.
+  bool controlAllowed = true;
+  if (GetInnerWindow()) {
+
+    // Local URL windows and windows with access to storage can be controlled.
+    controlAllowed = Info().URL().LowerCaseEqualsLiteral("about:blank") ||
+                     StringBeginsWith(Info().URL(), NS_LITERAL_CSTRING("blob:")) ||
+                     nsContentUtils::StorageAllowedForWindow(GetInnerWindow()) ==
+                      nsContentUtils::StorageAccess::eAllow;
+  } else if (GetWorkerPrivate()) {
+    // Local URL workers and workers with access to storage cna be controlled.
+    controlAllowed = GetWorkerPrivate()->IsStorageAllowed() ||
+                     StringBeginsWith(GetWorkerPrivate()->ScriptURL(),
+                                      NS_LITERAL_STRING("blob:"));
+  }
+
+  RefPtr<ClientOpPromise> ref;
+
+  if (NS_WARN_IF(!controlAllowed)) {
+    ref = ClientOpPromise::CreateAndReject(NS_ERROR_DOM_INVALID_STATE_ERR,
+                                           __func__);
+    return ref.forget();
+  }
+
   SetController(ServiceWorkerDescriptor(aArgs.serviceWorker()));
 
-  RefPtr<ClientOpPromise> ref =
-    ClientOpPromise::CreateAndResolve(NS_OK, __func__);
+  ref = ClientOpPromise::CreateAndResolve(NS_OK, __func__);
   return ref.forget();
 }
 
 void
 ClientSource::InheritController(const ServiceWorkerDescriptor& aServiceWorker)
 {
   NS_ASSERT_OWNINGTHREAD(ClientSource);
 
@@ -665,45 +724,65 @@ ClientSource::PostMessage(const ClientPo
 
   ref = ClientOpPromise::CreateAndResolve(NS_OK, __func__);
   return ref.forget();
 }
 
 RefPtr<ClientOpPromise>
 ClientSource::Claim(const ClientClaimArgs& aArgs)
 {
+  // The ClientSource::Claim method is only needed in the legacy
+  // mode where the ServiceWorkerManager is run in each child-process.
+  // In parent-process mode this method should not be called.
+  MOZ_DIAGNOSTIC_ASSERT(!ServiceWorkerParentInterceptEnabled());
+
   RefPtr<ClientOpPromise> ref;
 
+  nsIGlobalObject* global = GetGlobal();
+  if (NS_WARN_IF(!global)) {
+    ref = ClientOpPromise::CreateAndReject(NS_ERROR_DOM_INVALID_STATE_ERR,
+                                           __func__);
+    return ref.forget();
+  }
+
+  // Note, we cannot just mark the ClientSource controlled.  We must go through
+  // the SWM so that it can keep track of which clients are controlled by each
+  // registration.  We must tell the child-process SWM in legacy child-process
+  // mode.  In parent-process service worker mode the SWM is notified in the
+  // parent-process in ClientManagerService::Claim().
+
+  RefPtr<GenericPromise::Private> innerPromise =
+    new GenericPromise::Private(__func__);
   ServiceWorkerDescriptor swd(aArgs.serviceWorker());
 
-  // Today the ServiceWorkerManager maintains its own list of
-  // nsIDocument objects controlled by each service worker.  We
-  // need to try to update that data structure for now.  If we
-  // can't, however, then simply mark the Client as controlled.
-  // In the future this will be enough for the SWM as well since
-  // it will eventually hold ClientHandle objects instead of
-  // nsIDocuments.
-  nsPIDOMWindowInner* innerWindow = GetInnerWindow();
-  nsIDocument* doc = innerWindow ? innerWindow->GetExtantDoc() : nullptr;
-  RefPtr<ServiceWorkerManager> swm = doc ? ServiceWorkerManager::GetInstance()
-                                         : nullptr;
-  if (!swm || !doc) {
-    SetController(swd);
-    ref = ClientOpPromise::CreateAndResolve(NS_OK, __func__);
-    return ref.forget();
+  nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
+    "ClientSource::Claim",
+    [innerPromise, clientInfo = mClientInfo, swd] () mutable {
+      RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
+      if (NS_WARN_IF(!swm)) {
+        innerPromise->Reject(NS_ERROR_DOM_INVALID_STATE_ERR, __func__);
+        return;
+      }
+
+      RefPtr<GenericPromise> p = swm->MaybeClaimClient(clientInfo, swd);
+      p->ChainTo(innerPromise.forget(), __func__);
+    });
+
+  if (NS_IsMainThread()) {
+    r->Run();
+  } else {
+    MOZ_ALWAYS_SUCCEEDS(SystemGroup::Dispatch(TaskCategory::Other, r.forget()));
   }
 
   RefPtr<ClientOpPromise::Private> outerPromise =
     new ClientOpPromise::Private(__func__);
 
-  auto holder =
-    MakeRefPtr<DOMMozPromiseRequestHolder<GenericPromise>>(innerWindow->AsGlobal());
+  auto holder = MakeRefPtr<DOMMozPromiseRequestHolder<GenericPromise>>(global);
 
-  RefPtr<GenericPromise> p = swm->MaybeClaimClient(mClientInfo, swd);
-  p->Then(mEventTarget, __func__,
+  innerPromise->Then(mEventTarget, __func__,
     [outerPromise, holder] (bool aResult) {
       holder->Complete();
       outerPromise->Resolve(NS_OK, __func__);
     }, [outerPromise, holder] (nsresult aResult) {
       holder->Complete();
       outerPromise->Reject(aResult, __func__);
     })->Track(*holder);
 
--- a/dom/clients/manager/ClientSource.h
+++ b/dom/clients/manager/ClientSource.h
@@ -12,16 +12,17 @@
 #include "mozilla/dom/ServiceWorkerDescriptor.h"
 #include "mozilla/Variant.h"
 
 #ifdef XP_WIN
 #undef PostMessage
 #endif
 
 class nsIDocShell;
+class nsIGlobalObject;
 class nsISerialEventTarget;
 class nsPIDOMWindowInner;
 
 namespace mozilla {
 namespace dom {
 
 class ClientClaimArgs;
 class ClientControlledArgs;
@@ -73,16 +74,19 @@ class ClientSource final : public Client
   ExecutionReady(const ClientSourceExecutionReadyArgs& aArgs);
 
   WorkerPrivate*
   GetWorkerPrivate() const;
 
   nsIDocShell*
   GetDocShell() const;
 
+  nsIGlobalObject*
+  GetGlobal() const;
+
   void
   MaybeCreateInitialDocument();
 
   nsresult
   SnapshotWindowState(ClientState* aStateOut);
 
   // Private methods called by ClientManager
   ClientSource(ClientManager* aManager,
--- a/dom/clients/manager/ClientSourceOpParent.cpp
+++ b/dom/clients/manager/ClientSourceOpParent.cpp
@@ -1,16 +1,18 @@
 /* -*- 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 "ClientSourceOpParent.h"
 
+#include "ClientSourceParent.h"
+
 namespace mozilla {
 namespace dom {
 
 using mozilla::ipc::IPCResult;
 
 void
 ClientSourceOpParent::ActorDestroy(ActorDestroyReason aReason)
 {
@@ -20,28 +22,41 @@ ClientSourceOpParent::ActorDestroy(Actor
   }
 }
 
 IPCResult
 ClientSourceOpParent::Recv__delete__(const ClientOpResult& aResult)
 {
   if (aResult.type() == ClientOpResult::Tnsresult &&
       NS_FAILED(aResult.get_nsresult())) {
+
+    // If a control message fails then clear the controller from
+    // the ClientSourceParent.  We eagerly marked it controlled at
+    // the start of the operation.
+    if (mArgs.type() == ClientOpConstructorArgs::TClientControlledArgs) {
+      auto source = static_cast<ClientSourceParent*>(Manager());
+      if (source) {
+        source->ClearController();
+      }
+    }
+
     mPromise->Reject(aResult.get_nsresult(), __func__);
     mPromise = nullptr;
     return IPC_OK();
   }
+
   mPromise->Resolve(aResult, __func__);
   mPromise = nullptr;
   return IPC_OK();
 }
 
 ClientSourceOpParent::ClientSourceOpParent(const ClientOpConstructorArgs& aArgs,
                                            ClientOpPromise::Private* aPromise)
-  : mPromise(aPromise)
+  : mArgs(aArgs)
+  , mPromise(aPromise)
 {
   MOZ_DIAGNOSTIC_ASSERT(mPromise);
 }
 
 ClientSourceOpParent::~ClientSourceOpParent()
 {
   MOZ_DIAGNOSTIC_ASSERT(!mPromise);
 }
--- a/dom/clients/manager/ClientSourceOpParent.h
+++ b/dom/clients/manager/ClientSourceOpParent.h
@@ -9,16 +9,17 @@
 #include "mozilla/dom/ClientOpPromise.h"
 #include "mozilla/dom/PClientSourceOpParent.h"
 
 namespace mozilla {
 namespace dom {
 
 class ClientSourceOpParent final : public PClientSourceOpParent
 {
+  const ClientOpConstructorArgs mArgs;
   RefPtr<ClientOpPromise::Private> mPromise;
 
   // PClientSourceOpParent interface
   void
   ActorDestroy(ActorDestroyReason aReason) override;
 
   mozilla::ipc::IPCResult
   Recv__delete__(const ClientOpResult& aResult) override;
--- a/dom/clients/manager/ClientSourceParent.cpp
+++ b/dom/clients/manager/ClientSourceParent.cpp
@@ -270,16 +270,22 @@ ClientSourceParent::ExecutionReady() con
 
 const Maybe<ServiceWorkerDescriptor>&
 ClientSourceParent::GetController() const
 {
   return mController;
 }
 
 void
+ClientSourceParent::ClearController()
+{
+  mController.reset();
+}
+
+void
 ClientSourceParent::AttachHandle(ClientHandleParent* aClientHandle)
 {
   MOZ_DIAGNOSTIC_ASSERT(aClientHandle);
   MOZ_DIAGNOSTIC_ASSERT(!mFrozen);
   MOZ_ASSERT(!mHandleList.Contains(aClientHandle));
   mHandleList.AppendElement(aClientHandle);
 }
 
@@ -293,17 +299,21 @@ ClientSourceParent::DetachHandle(ClientH
 
 RefPtr<ClientOpPromise>
 ClientSourceParent::StartOp(const ClientOpConstructorArgs& aArgs)
 {
   RefPtr<ClientOpPromise::Private> promise =
     new ClientOpPromise::Private(__func__);
 
   // If we are being controlled, remember that data before propagating
-  // on to the ClientSource.
+  // on to the ClientSource.  This must be set prior to triggering
+  // the controllerchange event from the ClientSource since some tests
+  // expect matchAll() to find the controlled client immediately after.
+  // If the control operation fails, then we reset the controller value
+  // to reflect the final state.
   if (aArgs.type() == ClientOpConstructorArgs::TClientControlledArgs) {
     mController.reset();
     mController.emplace(aArgs.get_ClientControlledArgs().serviceWorker());
   }
 
   // Constructor failure will reject the promise via ActorDestroy().
   ClientSourceOpParent* actor = new ClientSourceOpParent(aArgs, promise);
   Unused << SendPClientSourceOpConstructor(actor, aArgs);
--- a/dom/clients/manager/ClientSourceParent.h
+++ b/dom/clients/manager/ClientSourceParent.h
@@ -75,16 +75,19 @@ public:
 
   bool
   ExecutionReady() const;
 
   const Maybe<ServiceWorkerDescriptor>&
   GetController() const;
 
   void
+  ClearController();
+
+  void
   AttachHandle(ClientHandleParent* aClientSource);
 
   void
   DetachHandle(ClientHandleParent* aClientSource);
 
   RefPtr<ClientOpPromise>
   StartOp(const ClientOpConstructorArgs& aArgs);
 };
--- a/dom/serviceworkers/ServiceWorkerManager.cpp
+++ b/dom/serviceworkers/ServiceWorkerManager.cpp
@@ -312,35 +312,52 @@ ServiceWorkerManager::Init(ServiceWorker
 RefPtr<GenericPromise>
 ServiceWorkerManager::StartControllingClient(const ClientInfo& aClientInfo,
                                              ServiceWorkerRegistrationInfo* aRegistrationInfo,
                                              bool aControlClientHandle)
 {
   MOZ_DIAGNOSTIC_ASSERT(aRegistrationInfo->GetActive());
 
   RefPtr<GenericPromise> ref;
+  RefPtr<ServiceWorkerManager> self(this);
 
   const ServiceWorkerDescriptor& active =
     aRegistrationInfo->GetActive()->Descriptor();
 
   auto entry = mControlledClients.LookupForAdd(aClientInfo.Id());
   if (entry) {
     RefPtr<ServiceWorkerRegistrationInfo> old =
       entry.Data()->mRegistrationInfo.forget();
 
-    ref = entry.Data()->mClientHandle->Control(active);
+    if (aControlClientHandle) {
+      ref = entry.Data()->mClientHandle->Control(active);
+    } else {
+      ref = GenericPromise::CreateAndResolve(false, __func__);
+    }
+
     entry.Data()->mRegistrationInfo = aRegistrationInfo;
 
     if (old != aRegistrationInfo) {
       StopControllingRegistration(old);
       aRegistrationInfo->StartControllingClient();
     }
 
     Telemetry::Accumulate(Telemetry::SERVICE_WORKER_CONTROLLED_DOCUMENTS, 1);
 
+    // Always check to see if we failed to actually control the client.  In
+    // that case removed the client from our list of controlled clients.
+    ref->Then(
+      SystemGroup::EventTargetFor(TaskCategory::Other), __func__,
+      [] (bool) {
+        // do nothing on success
+      }, [self, aClientInfo] (nsresult aRv) {
+        // failed to control, forget about this client
+        self->StopControllingClient(aClientInfo);
+      });
+
     return ref;
   }
 
   RefPtr<ClientHandle> clientHandle =
     ClientManager::CreateHandle(aClientInfo,
                                 SystemGroup::EventTargetFor(TaskCategory::Other));
 
   if (aControlClientHandle) {
@@ -350,25 +367,35 @@ ServiceWorkerManager::StartControllingCl
   }
 
   aRegistrationInfo->StartControllingClient();
 
   entry.OrInsert([&] {
     return new ControlledClientData(clientHandle, aRegistrationInfo);
   });
 
-  RefPtr<ServiceWorkerManager> self(this);
   clientHandle->OnDetach()->Then(
     SystemGroup::EventTargetFor(TaskCategory::Other), __func__,
-    [self = std::move(self), aClientInfo] {
+    [self, aClientInfo] {
       self->StopControllingClient(aClientInfo);
     });
 
   Telemetry::Accumulate(Telemetry::SERVICE_WORKER_CONTROLLED_DOCUMENTS, 1);
 
+  // Always check to see if we failed to actually control the client.  In
+  // that case removed the client from our list of controlled clients.
+  ref->Then(
+    SystemGroup::EventTargetFor(TaskCategory::Other), __func__,
+    [] (bool) {
+      // do nothing on success
+    }, [self, aClientInfo] (nsresult aRv) {
+      // failed to control, forget about this client
+      self->StopControllingClient(aClientInfo);
+    });
+
   return ref;
 }
 
 void
 ServiceWorkerManager::StopControllingClient(const ClientInfo& aClientInfo)
 {
   auto entry = mControlledClients.Lookup(aClientInfo.Id());
   if (!entry) {
@@ -2690,17 +2717,30 @@ ServiceWorkerManager::UpdateClientContro
     }
 
     handleList.AppendElement(iter.UserData()->mClientHandle);
   }
 
   // Fire event after iterating mControlledClients is done to prevent
   // modification by reentering from the event handlers during iteration.
   for (auto& handle : handleList) {
-    handle->Control(activeWorker->Descriptor());
+    RefPtr<GenericPromise> p = handle->Control(activeWorker->Descriptor());
+
+    RefPtr<ServiceWorkerManager> self = this;
+
+    // If we fail to control the client, then automatically remove it
+    // from our list of controlled clients.
+    p->Then(
+      SystemGroup::EventTargetFor(TaskCategory::Other), __func__,
+      [] (bool) {
+        // do nothing on success
+      }, [self, clientInfo = handle->Info()] (nsresult aRv) {
+        // failed to control, forget about this client
+        self->StopControllingClient(clientInfo);
+      });
   }
 }
 
 already_AddRefed<ServiceWorkerRegistrationInfo>
 ServiceWorkerManager::GetRegistration(nsIPrincipal* aPrincipal,
                                       const nsACString& aScope) const
 {
   MOZ_ASSERT(aPrincipal);
--- a/dom/websocket/WebSocket.cpp
+++ b/dom/websocket/WebSocket.cpp
@@ -815,16 +815,21 @@ WebSocketImpl::ScheduleConnectionCloseEv
   if (!mOnCloseScheduled) {
     mCloseEventWasClean = NS_SUCCEEDED(aStatusCode);
 
     if (aStatusCode == NS_BASE_STREAM_CLOSED) {
       // don't generate an error event just because of an unclean close
       aStatusCode = NS_OK;
     }
 
+    if (aStatusCode == NS_ERROR_NET_INADEQUATE_SECURITY) {
+      // TLS negotiation failed so we need to set status code to 1015.
+      mCloseEventCode = 1015;
+    }
+
     if (NS_FAILED(aStatusCode)) {
       ConsoleError();
       mFailed = true;
     }
 
     mOnCloseScheduled = true;
 
     NS_DispatchToCurrentThread(new CallDispatchConnectionCloseEvents(this));
--- a/gfx/layers/wr/WebRenderLayerManager.cpp
+++ b/gfx/layers/wr/WebRenderLayerManager.cpp
@@ -235,53 +235,58 @@ WebRenderLayerManager::EndTransaction(Dr
   // This should never get called, all callers should use
   // EndTransactionWithoutLayer instead.
   MOZ_ASSERT(false);
 }
 
 void
 WebRenderLayerManager::EndTransactionWithoutLayer(nsDisplayList* aDisplayList,
                                                   nsDisplayListBuilder* aDisplayListBuilder,
-                                                  const nsTArray<wr::WrFilterOp>& aFilters)
+                                                  const nsTArray<wr::WrFilterOp>& aFilters,
+                                                  WebRenderBackgroundData* aBackground)
 {
-  MOZ_ASSERT(aDisplayList && aDisplayListBuilder);
-
   AUTO_PROFILER_TRACING("Paint", "RenderLayers");
 
 #if DUMP_LISTS
   // Useful for debugging, it dumps the display list *before* we try to build
   // WR commands from it
-  if (XRE_IsContentProcess()) nsFrame::PrintDisplayList(aDisplayListBuilder, *aDisplayList);
+  if (XRE_IsContentProcess() && aDisplayList) nsFrame::PrintDisplayList(aDisplayListBuilder, *aDisplayList);
 #endif
 
 #ifdef XP_WIN
   gfxDWriteFont::UpdateClearTypeUsage();
 #endif
 
   // Since we don't do repeat transactions right now, just set the time
   mAnimationReadyTime = TimeStamp::Now();
 
   WrBridge()->BeginTransaction();
 
   LayoutDeviceIntSize size = mWidget->GetClientSize();
   wr::LayoutSize contentSize { (float)size.width, (float)size.height };
   wr::DisplayListBuilder builder(WrBridge()->GetPipeline(), contentSize, mLastDisplayListSize);
   wr::IpcResourceUpdateQueue resourceUpdates(WrBridge());
 
-  { // Record the time spent "layerizing". WR doesn't actually layerize but
+  if (aDisplayList) {
+    MOZ_ASSERT(aDisplayListBuilder && !aBackground);
+    // Record the time spent "layerizing". WR doesn't actually layerize but
     // generating the WR display list is the closest equivalent
     PaintTelemetry::AutoRecord record(PaintTelemetry::Metric::Layerization);
 
     mWebRenderCommandBuilder.BuildWebRenderCommands(builder,
                                                     resourceUpdates,
                                                     aDisplayList,
                                                     aDisplayListBuilder,
                                                     mScrollData,
                                                     contentSize,
                                                     aFilters);
+  } else {
+    // ViewToPaint does not have frame yet, then render only background clolor.
+    MOZ_ASSERT(!aDisplayListBuilder && aBackground);
+    aBackground->AddWebRenderCommands(builder);
   }
 
   DiscardCompositorAnimations();
 
   mWidget->AddWindowOverlayWebRenderCommands(WrBridge(), builder, resourceUpdates);
   mWindowOverlayChanged = false;
 
 #if DUMP_LISTS
--- a/gfx/layers/wr/WebRenderLayerManager.h
+++ b/gfx/layers/wr/WebRenderLayerManager.h
@@ -66,17 +66,18 @@ public:
   // WebRender can handle images larger than the max texture size via tiling.
   virtual int32_t GetMaxTextureSize() const override { return INT32_MAX; }
 
   virtual bool BeginTransactionWithTarget(gfxContext* aTarget) override;
   virtual bool BeginTransaction() override;
   virtual bool EndEmptyTransaction(EndTransactionFlags aFlags = END_DEFAULT) override;
   void EndTransactionWithoutLayer(nsDisplayList* aDisplayList,
                                   nsDisplayListBuilder* aDisplayListBuilder,
-                                  const nsTArray<wr::WrFilterOp>& aFilters = nsTArray<wr::WrFilterOp>());
+                                  const nsTArray<wr::WrFilterOp>& aFilters = nsTArray<wr::WrFilterOp>(),
+                                  WebRenderBackgroundData* aBackground = nullptr);
   virtual void EndTransaction(DrawPaintedLayerCallback aCallback,
                               void* aCallbackData,
                               EndTransactionFlags aFlags = END_DEFAULT) override;
 
   virtual LayersBackend GetBackendType() override { return LayersBackend::LAYERS_WR; }
   virtual void GetBackendName(nsAString& name) override { name.AssignLiteral("WebRender"); }
   virtual const char* Name() const override { return "WebRender"; }
 
--- a/gfx/layers/wr/WebRenderUserData.cpp
+++ b/gfx/layers/wr/WebRenderUserData.cpp
@@ -15,16 +15,25 @@
 #include "mozilla/layers/SharedSurfacesChild.h"
 #include "nsDisplayListInvalidation.h"
 #include "nsIFrame.h"
 #include "WebRenderCanvasRenderer.h"
 
 namespace mozilla {
 namespace layers {
 
+void
+WebRenderBackgroundData::AddWebRenderCommands(wr::DisplayListBuilder& aBuilder)
+{
+  aBuilder.PushRect(mBounds,
+                    mBounds,
+                    true,
+                    mColor);
+}
+
 /* static */ bool
 WebRenderUserData::SupportsAsyncUpdate(nsIFrame* aFrame)
 {
   if (!aFrame) {
     return false;
   }
   RefPtr<WebRenderImageData> data = GetWebRenderUserData<WebRenderImageData>(aFrame, static_cast<uint32_t>(DisplayItemType::TYPE_VIDEO));
   if (data) {
--- a/gfx/layers/wr/WebRenderUserData.h
+++ b/gfx/layers/wr/WebRenderUserData.h
@@ -32,16 +32,29 @@ class ImageContainer;
 class WebRenderBridgeChild;
 class WebRenderCanvasData;
 class WebRenderCanvasRendererAsync;
 class WebRenderImageData;
 class WebRenderFallbackData;
 class WebRenderLayerManager;
 class WebRenderGroupData;
 
+class WebRenderBackgroundData
+{
+public:
+  WebRenderBackgroundData(wr::LayoutRect aBounds, wr::ColorF aColor)
+    : mBounds(aBounds)
+    , mColor(aColor)
+  { }
+  void AddWebRenderCommands(wr::DisplayListBuilder& aBuilder);
+protected:
+  wr::LayoutRect mBounds;
+  wr::ColorF mColor;
+};
+
 class WebRenderUserData
 {
 public:
   typedef nsTHashtable<nsRefPtrHashKey<WebRenderUserData> > WebRenderUserDataRefTable;
 
   static bool SupportsAsyncUpdate(nsIFrame* aFrame);
 
   NS_INLINE_DECL_REFCOUNTING(WebRenderUserData)
--- a/gfx/webrender_bindings/RenderCompositorANGLE.cpp
+++ b/gfx/webrender_bindings/RenderCompositorANGLE.cpp
@@ -50,16 +50,20 @@ RenderCompositorANGLE::~RenderCompositor
   DestroyEGLSurface();
   MOZ_ASSERT(!mEGLSurface);
 }
 
 ID3D11Device*
 RenderCompositorANGLE::GetDeviceOfEGLDisplay()
 {
   auto* egl = gl::GLLibraryEGL::Get();
+  MOZ_ASSERT(egl);
+  if (!egl || !egl->IsExtensionSupported(gl::GLLibraryEGL::EXT_device_query)) {
+    return nullptr;
+  }
 
   // Fetch the D3D11 device.
   EGLDeviceEXT eglDevice = nullptr;
   egl->fQueryDisplayAttribEXT(egl->Display(), LOCAL_EGL_DEVICE_EXT, (EGLAttrib*)&eglDevice);
   MOZ_ASSERT(eglDevice);
   ID3D11Device* device = nullptr;
   egl->fQueryDeviceAttribEXT(eglDevice, LOCAL_EGL_D3D11_DEVICE_ANGLE, (EGLAttrib*)&device);
   if (!device) {
--- a/js/public/CallArgs.h
+++ b/js/public/CallArgs.h
@@ -1,15 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * 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/. */
 
 /*
+ * [SMDOC] JS::CallArgs API
+ *
  * Helper classes encapsulating access to the callee, |this| value, arguments,
  * and argument count for a call/construct operation.
  *
  * JS::CallArgs encapsulates access to a JSNative's un-abstracted
  * |unsigned argc, Value* vp| arguments.  The principal way to create a
  * JS::CallArgs is using JS::CallArgsFromVp:
  *
  *   // If provided no arguments or a non-numeric first argument, return zero.
@@ -41,20 +43,17 @@
  *   }
  *
  * CallArgs is exposed publicly and used internally.  Not all parts of its
  * public interface are meant to be used by embedders!  See inline comments to
  * for details.
  *
  * It's possible (albeit deprecated) to manually index into |vp| to access the
  * callee, |this|, and arguments of a function, and to set its return value.
- * It's also possible to use the supported API of JS_CALLEE, JS_THIS, JS_ARGV,
- * JS_RVAL, and JS_SET_RVAL to the same ends.
- *
- * But neither API has the error-handling or moving-GC correctness of CallArgs.
+ * This does not have the error-handling or moving-GC correctness of CallArgs.
  * New code should use CallArgs instead whenever possible.
  *
  * The eventual plan is to change JSNative to take |const CallArgs&| directly,
  * for automatic assertion of correct use and to make calling functions more
  * efficient.  Embedders should start internally switching away from using
  * |argc| and |vp| directly, except to create a |CallArgs|.  Then, when an
  * eventual release making that change occurs, porting efforts will require
  * changing methods' signatures but won't require invasive changes to the
--- a/js/public/Debug.h
+++ b/js/public/Debug.h
@@ -22,16 +22,18 @@
 
 namespace js {
 class Debugger;
 } // namespace js
 
 namespace JS {
 namespace dbg {
 
+// [SMDOC] Debugger builder API
+//
 // Helping embedding code build objects for Debugger
 // -------------------------------------------------
 //
 // Some Debugger API features lean on the embedding application to construct
 // their result values. For example, Debugger.Frame.prototype.scriptEntryReason
 // calls hooks provided by the embedding to construct values explaining why it
 // invoked JavaScript; if F is a frame called from a mouse click event handler,
 // F.scriptEntryReason would return an object of the form:
--- a/js/public/Proxy.h
+++ b/js/public/Proxy.h
@@ -32,16 +32,18 @@ using JS::PrivateValue;
 using JS::PropertyDescriptor;
 using JS::Value;
 
 class RegExpShared;
 
 class JS_FRIEND_API(Wrapper);
 
 /*
+ * [SMDOC] Proxy Objects
+ *
  * A proxy is a JSObject with highly customizable behavior. ES6 specifies a
  * single kind of proxy, but the customization mechanisms we use to implement
  * ES6 Proxy objects are also useful wherever an object with weird behavior is
  * wanted. Proxies are used to implement:
  *
  * -   the scope objects used by the Debugger's frame.eval() method
  *     (see js::GetDebugScopeForFunction)
  *
--- a/js/public/Result.h
+++ b/js/public/Result.h
@@ -1,15 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * 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/. */
 
 /*
+ * [SMDOC] JS::Result
+ *
  * `Result` is used as the return type of many SpiderMonkey functions that
  * can either succeed or fail. See "/mfbt/Result.h".
  *
  *
  * ## Which return type to use
  *
  * `Result` is for return values. Obviously, if you're writing a function that
  * can't fail, don't use Result. Otherwise:
--- a/js/public/RootingAPI.h
+++ b/js/public/RootingAPI.h
@@ -23,16 +23,18 @@
 #include "js/HeapAPI.h"
 #include "js/ProfilingStack.h"
 #include "js/Realm.h"
 #include "js/TypeDecls.h"
 #include "js/UniquePtr.h"
 #include "js/Utility.h"
 
 /*
+ * [SMDOC] Stack Rooting
+ *
  * Moving GC Stack Rooting
  *
  * A moving GC may change the physical location of GC allocated things, even
  * when they are rooted, updating all pointers to the thing to refer to its new
  * location. The GC must therefore know about all live pointers to a thing,
  * not just one of them, in order to behave correctly.
  *
  * The |Rooted| and |Handle| classes below are used to root stack locations
--- a/js/public/UbiNode.h
+++ b/js/public/UbiNode.h
@@ -24,17 +24,17 @@
 #include "js/HashTable.h"
 #include "js/RootingAPI.h"
 #include "js/TracingAPI.h"
 #include "js/TypeDecls.h"
 #include "js/UniquePtr.h"
 #include "js/Value.h"
 #include "js/Vector.h"
 
-// JS::ubi::Node
+// [SMDOC] ubi::Node (Heap Analysis framework)
 //
 // JS::ubi::Node is a pointer-like type designed for internal use by heap
 // analysis tools. A ubi::Node can refer to:
 //
 // - a JS value, like a string, object, or symbol;
 // - an internal SpiderMonkey structure, like a shape or a scope chain object
 // - an instance of some embedding-provided type: in Firefox, an XPCOM
 //   object, or an internal DOM node class instance
--- a/js/public/Value.h
+++ b/js/public/Value.h
@@ -263,16 +263,18 @@ static inline double
 CanonicalizeNaN(double d)
 {
     if (MOZ_UNLIKELY(mozilla::IsNaN(d)))
         return GenericNaN();
     return d;
 }
 
 /**
+ * [SMDOC] JS::Value type
+ *
  * JS::Value is the interface for a single JavaScript Engine value.  A few
  * general notes on JS::Value:
  *
  * - JS::Value has setX() and isX() members for X in
  *
  *     { Int32, Double, String, Symbol, BigInt, Boolean, Undefined, Null, Object, Magic }
  *
  *   JS::Value also contains toX() for each of the non-singleton types.
--- a/js/src/builtin/Array.cpp
+++ b/js/src/builtin/Array.cpp
@@ -934,26 +934,16 @@ js::ArraySetLength(JSContext* cx, Handle
         arr->setNonWritableLength(cx);
 
     if (!succeeded)
         return result.fail(JSMSG_CANT_TRUNCATE_ARRAY);
 
     return result.succeed();
 }
 
-bool
-js::WouldDefinePastNonwritableLength(HandleNativeObject obj, uint32_t index)
-{
-    if (!obj->is<ArrayObject>())
-        return false;
-
-    ArrayObject* arr = &obj->as<ArrayObject>();
-    return !arr->lengthIsWritable() && index >= arr->length();
-}
-
 static bool
 array_addProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v)
 {
     ArrayObject* arr = &obj->as<ArrayObject>();
 
     uint32_t index;
     if (!IdIsIndex(id, &index))
         return true;
--- a/js/src/builtin/Array.h
+++ b/js/src/builtin/Array.h
@@ -108,24 +108,16 @@ NewCopiedArrayTryUseGroup(JSContext* cx,
                           const Value* vp, size_t length,
                           NewObjectKind newKind = GenericObject,
                           ShouldUpdateTypes updateTypes = ShouldUpdateTypes::Update);
 
 extern ArrayObject*
 NewCopiedArrayForCallingAllocationSite(JSContext* cx, const Value* vp, size_t length,
                                        HandleObject proto = nullptr);
 
-/*
- * Determines whether a write to the given element on |obj| should fail because
- * |obj| is an Array with a non-writable length, and writing that element would
- * increase the length of the array.
- */
-extern bool
-WouldDefinePastNonwritableLength(HandleNativeObject obj, uint32_t index);
-
 extern bool
 GetLengthProperty(JSContext* cx, HandleObject obj, uint32_t* lengthp);
 
 extern bool
 SetLengthProperty(JSContext* cx, HandleObject obj, uint32_t length);
 
 /*
  * Copy 'length' elements from aobj to vp.
--- a/js/src/builtin/TypedObject.h
+++ b/js/src/builtin/TypedObject.h
@@ -13,17 +13,17 @@
 #include "gc/WeakMap.h"
 #include "js/Conversions.h"
 #include "vm/ArrayBufferObject.h"
 #include "vm/JSObject.h"
 #include "vm/ShapedObject.h"
 
 /*
  * -------------
- * Typed Objects
+ * [SMDOC] Typed Objects
  * -------------
  *
  * Typed objects are a special kind of JS object where the data is
  * given well-structured form. To use a typed object, users first
  * create *type objects* (no relation to the type objects used in TI)
  * that define the type layout. For example, a statement like:
  *
  *    var PointType = new StructType({x: uint8, y: uint8});
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -5,16 +5,18 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* JS parser. */
 
 #ifndef frontend_Parser_h
 #define frontend_Parser_h
 
 /*
+ * [SMDOC] JS Parser
+ *
  * JS parsers capable of generating ASTs from source text.
  *
  * A parser embeds token stream information, then gets and matches tokens to
  * generate a syntax tree that, if desired, BytecodeEmitter will use to compile
  * bytecode.
  *
  * Like token streams (see the comment near the top of TokenStream.h), parser
  * classes are heavily templatized -- along the token stream's character-type
--- a/js/src/frontend/TokenStream.h
+++ b/js/src/frontend/TokenStream.h
@@ -11,16 +11,18 @@
  * regular expression *or* a division operator depending on context -- the
  * various token stream classes are mostly not useful outside of the Parser
  * where they reside.  We should probably eventually merge the two concepts.
  */
 #ifndef frontend_TokenStream_h
 #define frontend_TokenStream_h
 
 /*
+ * [SMDOC] Parser Token Stream
+ *
  * A token stream exposes the raw tokens -- operators, names, numbers,
  * keywords, and so on -- of JavaScript source code.
  *
  * These are the components of the overall token stream concept:
  * TokenStreamShared, TokenStreamAnyChars, TokenStreamCharsBase<CharT>,
  * TokenStreamChars<CharT>, and TokenStreamSpecific<CharT, AnyCharsAccess>.
  *
  * == TokenStreamShared → ∅ ==
--- a/js/src/gc/AtomMarking.cpp
+++ b/js/src/gc/AtomMarking.cpp
@@ -10,17 +10,17 @@
 #include "vm/Realm.h"
 
 #include "gc/GC-inl.h"
 #include "gc/Heap-inl.h"
 
 namespace js {
 namespace gc {
 
-// Atom Marking Overview
+// [SMDOC] GC Atom Marking
 //
 // Things in the atoms zone (which includes atomized strings and other things,
 // all of which we will refer to as 'atoms' here) may be pointed to freely by
 // things in other zones. To avoid the need to perform garbage collections of
 // the entire runtime to collect atoms, we compute a separate atom mark bitmap
 // for each zone that is always an overapproximation of the atoms that zone is
 // using. When an atom is not in the mark bitmap for any zone, it can be
 // destroyed.
--- a/js/src/gc/Barrier.h
+++ b/js/src/gc/Barrier.h
@@ -12,16 +12,18 @@
 #include "gc/Cell.h"
 #include "gc/StoreBuffer.h"
 #include "js/HeapAPI.h"
 #include "js/Id.h"
 #include "js/RootingAPI.h"
 #include "js/Value.h"
 
 /*
+ * [SMDOC] GC Barriers
+ *
  * A write barrier is a mechanism used by incremental or generation GCs to
  * ensure that every value that needs to be marked is marked. In general, the
  * write barrier should be invoked whenever a write can cause the set of things
  * traced through by the GC to change. This includes:
  *   - writes to object properties
  *   - writes to array slots
  *   - writes to fields like JSObject::shape_ that we trace through
  *   - writes to fields in private data
--- a/js/src/gc/GC.cpp
+++ b/js/src/gc/GC.cpp
@@ -1,15 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * 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/. */
 
 /*
+ * [SMDOC] Garbage Collector
+ *
  * This code implements an incremental mark-and-sweep garbage collector, with
  * most sweeping carried out in the background on a parallel thread.
  *
  * Full vs. zone GC
  * ----------------
  *
  * The collector can collect all zones at once, or a subset. These types of
  * collection are referred to as a full GC and a zone GC respectively.
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -49,16 +49,18 @@ using namespace js::gc;
 using JS::MapTypeToTraceKind;
 
 using mozilla::DebugOnly;
 using mozilla::IntegerRange;
 using mozilla::IsBaseOf;
 using mozilla::IsSame;
 using mozilla::PodCopy;
 
+// [SMDOC] GC Tracing
+//
 // Tracing Overview
 // ================
 //
 // Tracing, in this context, refers to an abstract visitation of some or all of
 // the GC-controlled heap. The effect of tracing an edge of the graph depends
 // on the subclass of the JSTracer on whose behalf we are tracing.
 //
 // Marking
--- a/js/src/gc/Scheduling.h
+++ b/js/src/gc/Scheduling.h
@@ -1,15 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * 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/. */
 
 /*
+ * [SMDOC] GC Scheduling
+ *
  * GC Scheduling Overview
  * ======================
  *
  * Scheduling GC's in SpiderMonkey/Firefox is tremendously complicated because
  * of the large number of subtle, cross-cutting, and widely dispersed factors
  * that must be taken into account. A summary of some of the more important
  * factors follows.
  *
--- a/js/src/gc/Zone.h
+++ b/js/src/gc/Zone.h
@@ -94,16 +94,18 @@ class MOZ_NON_TEMPORARY_CLASS FunctionTo
     MOZ_ALWAYS_INLINE JSString* lookup(JSScript* script) const;
     MOZ_ALWAYS_INLINE void put(JSScript* script, JSString* string);
 };
 
 } // namespace js
 
 namespace JS {
 
+// [SMDOC] GC Zones
+//
 // A zone is a collection of compartments. Every compartment belongs to exactly
 // one zone. In Firefox, there is roughly one zone per tab along with a system
 // zone for everything else. Zones mainly serve as boundaries for garbage
 // collection. Unlike compartments, they have no special security properties.
 //
 // Every GC thing belongs to exactly one zone. GC things from the same zone but
 // different compartments can share an arena (4k page). GC things from different
 // zones cannot be stored in the same arena. The garbage collector is capable of
--- a/js/src/irregexp/RegExpEngine.cpp
+++ b/js/src/irregexp/RegExpEngine.cpp
@@ -1321,16 +1321,17 @@ Analysis::VisitBackReference(BackReferen
 }
 
 void
 Analysis::VisitAssertion(AssertionNode* that)
 {
     EnsureAnalyzed(that->on_success());
 }
 
+// [SMDOC] Irregexp internals
 // -------------------------------------------------------------------
 // Implementation of the Irregexp regular expression engine.
 //
 // The Irregexp regular expression engine is intended to be a complete
 // implementation of ECMAScript regular expressions.  It generates either
 // bytecodes or native code.
 
 //   The Irregexp regexp engine is structured in three steps.
--- a/js/src/jit-test/tests/realms/switch-realms-native.js
+++ b/js/src/jit-test/tests/realms/switch-realms-native.js
@@ -40,8 +40,21 @@ function testException1() {
         } catch(e) {
             ex = e;
         }
         assertCorrectRealm();
         assertEq(typeof ex, "string");
     }
 }
 testException1();
+
+function testDOMCalls() {
+    var g = newGlobal({sameCompartmentAs: this});
+    var obj = g.evaluate("new FakeDOMObject()");
+    for (var i = 0; i < 2000; i++) {
+        assertCorrectRealm();
+        assertEq(obj.doFoo(1), 1);
+        assertEq(typeof obj.x, "number");
+        assertEq(obj.global, g);
+        obj.global = g; // Throws if not setter's global.
+    }
+}
+testDOMCalls();
--- a/js/src/jit-test/tests/wasm/grow-memory.js
+++ b/js/src/jit-test/tests/wasm/grow-memory.js
@@ -1,16 +1,16 @@
-function linearModule(min, max, ops) {
+function linearModule(min, max, ops, current_memory, grow_memory) {
   var opsText = ops.map(function (op) {
     if (op[0] == "CM") {
-      res = `(if i32 (i32.ne (current_memory) (i32.const ${op[1]}))
+      res = `(if i32 (i32.ne (${current_memory}) (i32.const ${op[1]}))
                   (i32.load offset=10 (i32.const 4294967295))
                   (i32.const 0))`
     } else if (op[0] == "GM") {
-      res = `(if i32 (i32.ne (grow_memory (i32.const ${op[1]})) (i32.const ${op[2]}))
+      res = `(if i32 (i32.ne (${grow_memory} (i32.const ${op[1]})) (i32.const ${op[2]}))
                  (i32.load offset=10 (i32.const 4294967295))
                  (i32.const 0))`
     } else if (op[0] == "L") {
       var type = op[1];
       var ext = op[2];
       var off = op[3];
       var loc = op[4]
       var align = 0;
@@ -30,16 +30,17 @@ function linearModule(min, max, ops) {
     `(module
        (memory ${min} ${max})
          ` + (min != 0 ? `(data (i32.const 0) "\\00\\01\\02\\03\\04\\05\\06\\07\\08\\09\\0a\\0b\\0c\\0d\\0e\\0f")
                           (data (i32.const 16) "\\f0\\f1\\f2\\f3\\f4\\f5\\f6\\f7\\f8\\f9\\fa\\fb\\fc\\fd\\fe\\ff")`
                       : "") +
        `
        (func (result i32)
          (drop ` + opsText + `)
-         (current_memory)
+         (${current_memory})
        ) (export "run" 0))`;
 
   return text;
 }
 
 // Just grow some memory
-wasmFullPass(linearModule(3,5, [["CM", 3]]), 3);
+wasmFullPass(linearModule(3,5, [["CM", 3]], "current_memory", "grow_memory"), 3); // Old opcode names
+wasmFullPass(linearModule(3,5, [["CM", 3]], "memory.size", "memory.grow"), 3);    // New opcode names
--- a/js/src/jit/AliasAnalysis.cpp
+++ b/js/src/jit/AliasAnalysis.cpp
@@ -111,16 +111,18 @@ IonSpewAliasInfo(const char* pre, MInstr
 
     Fprinter& out = JitSpewPrinter();
     out.printf("%s ", pre);
     ins->printName(out);
     out.printf(" %s\n", post);
 #endif
 }
 
+// [SMDOC] IonMonkey Alias Analysis
+//
 // This pass annotates every load instruction with the last store instruction
 // on which it depends. The algorithm is optimistic in that it ignores explicit
 // dependencies and only considers loads and stores.
 //
 // Loads inside loops only have an implicit dependency on a store before the
 // loop header if no instruction inside the loop body aliases it. To calculate
 // this efficiently, we maintain a list of maybe-invariant loads and the combined
 // alias set for all stores inside the loop. When we see the loop's backedge, this
--- a/js/src/jit/AtomicOperations.h
+++ b/js/src/jit/AtomicOperations.h
@@ -10,16 +10,18 @@
 #include "mozilla/Types.h"
 
 #include "vm/SharedMem.h"
 
 namespace js {
 namespace jit {
 
 /*
+ * [SMDOC] Atomic Operations
+ *
  * The atomic operations layer defines types and functions for
  * JIT-compatible atomic operation.
  *
  * The fundamental constraints on the functions are:
  *
  * - That their realization here MUST be compatible with code the JIT
  *   generates for its Atomics operations, so that an atomic access
  *   from the interpreter or runtime - from any C++ code - really is
--- a/js/src/jit/Bailouts.h
+++ b/js/src/jit/Bailouts.h
@@ -11,18 +11,20 @@
 
 #include "jit/JitFrames.h"
 #include "jit/JSJitFrameIter.h"
 #include "vm/Stack.h"
 
 namespace js {
 namespace jit {
 
-// A "bailout" is a condition in which we need to recover an interpreter frame
-// from an IonFrame. Bailouts can happen for the following reasons:
+// [SMDOC] IonMonkey Bailouts
+//
+// A "bailout" is a condition in which we need to recover a baseline frame from
+// an IonFrame. Bailouts can happen for the following reasons:
 //   (1) A deoptimization guard, for example, an add overflows or a type check
 //       fails.
 //   (2) A check or assumption held by the JIT is invalidated by the VM, and
 //       JIT code must be thrown away. This includes the GC possibly deciding
 //       to evict live JIT code, or a Type Inference reflow.
 //
 // Note that bailouts as described here do not include normal Ion frame
 // inspection, for example, if an exception must be built or the GC needs to
@@ -31,30 +33,30 @@ namespace jit {
 // The second type of bailout needs a different name - "deoptimization" or
 // "deep bailout". Here we are concerned with eager (or maybe "shallow")
 // bailouts, that happen from JIT code. These happen from guards, like:
 //
 //  cmp [obj + shape], 0x50M37TH1NG
 //  jmp _bailout
 //
 // The bailout target needs to somehow translate the Ion frame (whose state
-// will differ at each program point) to an interpreter frame. This state is
+// will differ at each program point) to a baseline frame. This state is
 // captured into the IonScript's snapshot buffer, and for each bailout we know
 // which snapshot corresponds to its state.
 //
 // Roughly, the following needs to happen at the bailout target.
 //   (1) Move snapshot ID into a known stack location (registers cannot be
 //       mutated).
 //   (2) Spill all registers to the stack.
 //   (3) Call a Bailout() routine, whose argument is the stack pointer.
 //   (4) Bailout() will find the IonScript on the stack, use the snapshot ID
 //       to find the structure of the frame, and then use the stack and spilled
 //       registers to perform frame conversion.
 //   (5) Bailout() returns, and the JIT must immediately return to the
-//       interpreter (all frames are converted at once).
+//       baseline JIT code (all frames are converted at once).
 //
 // (2) and (3) are implemented by a trampoline held in the compartment.
 // Naively, we could implement (1) like:
 //
 //   _bailout_ID_1:
 //     push 1
 //     jmp _global_bailout_handler
 //   _bailout_ID_2:
--- a/js/src/jit/CacheIR.cpp
+++ b/js/src/jit/CacheIR.cpp
@@ -620,17 +620,17 @@ GeneratePrototypeGuards(CacheIRWriter& w
     // ensure |holder| is still on the prototype chain of |obj| and we haven't
     // introduced any shadowing definitions.
     //
     // For each item in the proto chain before holder, we must ensure that
     // [[GetPrototypeOf]] still has the expected result, and that
     // [[GetOwnProperty]] has no definition of the target property.
     //
     //
-    // Shape Teleporting Optimization
+    // [SMDOC] Shape Teleporting Optimization
     // ------------------------------
     //
     // Starting with the assumption (and guideline to developers) that mutating
     // prototypes is an uncommon and fair-to-penalize operation we move cost
     // from the access side to the mutation side.
     //
     // Consider the following proto chain, with B defining a property 'x':
     //
--- a/js/src/jit/CacheIR.h
+++ b/js/src/jit/CacheIR.h
@@ -17,16 +17,18 @@
 #include "jit/SharedIC.h"
 
 namespace js {
 namespace jit {
 
 
 enum class BaselineCacheIRStubKind;
 
+// [SMDOC] CacheIR
+//
 // CacheIR is an (extremely simple) linear IR language for inline caches.
 // From this IR, we can generate machine code for Baseline or Ion IC stubs.
 //
 // IRWriter
 // --------
 // CacheIR bytecode is written using IRWriter. This class also records some
 // metadata that's used by the Baseline and Ion code generators to generate
 // (efficient) machine code.
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -4413,16 +4413,22 @@ CodeGenerator::visitCallDOMNative(LCallD
     masm.moveStackPtrTo(argArgs);
 
     // Push |this| object for passing HandleObject. We push after argc to
     // maintain the same sp-relative location of the object pointer with other
     // DOMExitFrames.
     masm.Push(argObj);
     masm.moveStackPtrTo(argObj);
 
+    if (call->mir()->maybeCrossRealm()) {
+        // We use argJSContext as scratch register here.
+        masm.movePtr(ImmGCPtr(target->rawJSFunction()), argJSContext);
+        masm.switchToObjectRealm(argJSContext, argJSContext);
+    }
+
     // Construct native exit frame.
     uint32_t safepointOffset = masm.buildFakeExitFrame(argJSContext);
     masm.loadJSContext(argJSContext);
     masm.enterFakeExitFrame(argJSContext, argJSContext, ExitFrameType::IonDOMMethod);
 
     markSafepointAt(safepointOffset, call);
 
     // Construct and execute call.
@@ -4442,16 +4448,24 @@ CodeGenerator::visitCallDOMNative(LCallD
         // Test for failure.
         masm.branchIfFalseBool(ReturnReg, masm.exceptionLabel());
 
         // Load the outparam vp[0] into output register(s).
         masm.loadValue(Address(masm.getStackPointer(), IonDOMMethodExitFrameLayout::offsetOfResult()),
                        JSReturnOperand);
     }
 
+    // Switch back to the current realm if needed. Note: if the DOM method threw
+    // an exception, the exception handler will do this.
+    if (call->mir()->maybeCrossRealm()) {
+        static_assert(!JSReturnOperand.aliases(ReturnReg),
+                      "Clobbering ReturnReg should not affect the return value");
+        masm.switchToRealm(gen->realm->realmPtr(), ReturnReg);
+    }
+
     // Until C++ code is instrumented against Spectre, prevent speculative
     // execution from returning any private data.
     if (JitOptions.spectreJitToCxxCalls && call->mir()->hasLiveDefUses())
         masm.speculationBarrier();
 
     // The next instruction is removing the footer of the exit frame, so there
     // is no need for leaveFakeExitFrame.
 
@@ -12250,16 +12264,22 @@ CodeGenerator::visitGetDOMProperty(LGetD
 
     masm.Push(ObjectReg);
 
     LoadDOMPrivate(masm, ObjectReg, PrivateReg, ins->mir()->objectKind());
 
     // Rooting will happen at GC time.
     masm.moveStackPtrTo(ObjectReg);
 
+    Realm* getterRealm = ins->mir()->getterRealm();
+    if (gen->realm->realmPtr() != getterRealm) {
+        // We use JSContextReg as scratch register here.
+        masm.switchToRealm(getterRealm, JSContextReg);
+    }
+
     uint32_t safepointOffset = masm.buildFakeExitFrame(JSContextReg);
     masm.loadJSContext(JSContextReg);
     masm.enterFakeExitFrame(JSContextReg, JSContextReg, ExitFrameType::IonDOMGetter);
 
     markSafepointAt(safepointOffset, ins);
 
     masm.setupUnalignedABICall(JSContextReg);
     masm.loadJSContext(JSContextReg);
@@ -12275,16 +12295,24 @@ CodeGenerator::visitGetDOMProperty(LGetD
                        JSReturnOperand);
     } else {
         masm.branchIfFalseBool(ReturnReg, masm.exceptionLabel());
 
         masm.loadValue(Address(masm.getStackPointer(), IonDOMExitFrameLayout::offsetOfResult()),
                        JSReturnOperand);
     }
 
+    // Switch back to the current realm if needed. Note: if the getter threw an
+    // exception, the exception handler will do this.
+    if (gen->realm->realmPtr() != getterRealm) {
+        static_assert(!JSReturnOperand.aliases(ReturnReg),
+                      "Clobbering ReturnReg should not affect the return value");
+        masm.switchToRealm(gen->realm->realmPtr(), ReturnReg);
+    }
+
     // Until C++ code is instrumented against Spectre, prevent speculative
     // execution from returning any private data.
     if (JitOptions.spectreJitToCxxCalls && ins->mir()->hasLiveDefUses())
         masm.speculationBarrier();
 
     masm.adjustStack(IonDOMExitFrameLayout::Size());
 
     masm.bind(&haveValue);
@@ -12355,16 +12383,22 @@ CodeGenerator::visitSetDOMProperty(LSetD
 
     masm.Push(ObjectReg);
 
     LoadDOMPrivate(masm, ObjectReg, PrivateReg, ins->mir()->objectKind());
 
     // Rooting will happen at GC time.
     masm.moveStackPtrTo(ObjectReg);
 
+    Realm* setterRealm = ins->mir()->setterRealm();
+    if (gen->realm->realmPtr() != setterRealm) {
+        // We use JSContextReg as scratch register here.
+        masm.switchToRealm(setterRealm, JSContextReg);
+    }
+
     uint32_t safepointOffset = masm.buildFakeExitFrame(JSContextReg);
     masm.loadJSContext(JSContextReg);
     masm.enterFakeExitFrame(JSContextReg, JSContextReg, ExitFrameType::IonDOMSetter);
 
     markSafepointAt(safepointOffset, ins);
 
     masm.setupUnalignedABICall(JSContextReg);
     masm.loadJSContext(JSContextReg);
@@ -12372,16 +12406,21 @@ CodeGenerator::visitSetDOMProperty(LSetD
     masm.passABIArg(ObjectReg);
     masm.passABIArg(PrivateReg);
     masm.passABIArg(ValueReg);
     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, ins->mir()->fun()), MoveOp::GENERAL,
                      CheckUnsafeCallWithABI::DontCheckHasExitFrame);
 
     masm.branchIfFalseBool(ReturnReg, masm.exceptionLabel());
 
+    // Switch back to the current realm if needed. Note: if the setter threw an
+    // exception, the exception handler will do this.
+    if (gen->realm->realmPtr() != setterRealm)
+        masm.switchToRealm(gen->realm->realmPtr(), ReturnReg);
+
     masm.adjustStack(IonDOMExitFrameLayout::Size());
 
     MOZ_ASSERT(masm.framePushed() == initialStack);
 }
 
 class OutOfLineIsCallable : public OutOfLineCodeBase<CodeGenerator>
 {
     Register object_;
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -10999,17 +10999,18 @@ IonBuilder::getPropTryCommonGetter(bool*
                     return Ok();
                 }
 
                 // We can't use MLoadFixedSlot here because it might not have
                 // the right aliasing behavior; we want to alias DOM setters as
                 // needed.
                 get = MGetDOMMember::New(alloc(), jitinfo, obj, guard, globalGuard);
             } else {
-                get = MGetDOMProperty::New(alloc(), jitinfo, objKind, obj, guard, globalGuard);
+                get = MGetDOMProperty::New(alloc(), jitinfo, objKind, commonGetter->realm(), obj,
+                                           guard, globalGuard);
             }
             if (!get)
                 return abort(AbortReason::Alloc);
             current->add(get);
             current->push(get);
 
             if (get->isEffectful())
                 MOZ_TRY(resumeAfter(get));
@@ -11688,17 +11689,17 @@ IonBuilder::setPropTryCommonDOMSetter(bo
     bool isDOM = false;
     MOZ_TRY_VAR(isDOM, testShouldDOMCall(objTypes, setter, JSJitInfo::Setter));
     if (!isDOM)
         return Ok();
 
     // Emit SetDOMProperty.
     MOZ_ASSERT(setter->jitInfo()->type() == JSJitInfo::Setter);
     MSetDOMProperty* set = MSetDOMProperty::New(alloc(), setter->jitInfo()->setter, objKind,
-                                                obj, value);
+                                                setter->realm(), obj, value);
 
     current->add(set);
     current->push(value);
 
     MOZ_TRY(resumeAfter(set));
 
     *emitted = true;
     return Ok();
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -12380,33 +12380,38 @@ class MCallInitElementArray
     }
 };
 
 class MSetDOMProperty
   : public MBinaryInstruction,
     public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >::Data
 {
     const JSJitSetterOp func_;
+    Realm* setterRealm_;
     DOMObjectKind objectKind_;
 
-    MSetDOMProperty(const JSJitSetterOp func, DOMObjectKind objectKind, MDefinition* obj,
-                    MDefinition* val)
+    MSetDOMProperty(const JSJitSetterOp func, DOMObjectKind objectKind, Realm* setterRealm,
+                    MDefinition* obj, MDefinition* val)
       : MBinaryInstruction(classOpcode, obj, val),
         func_(func),
+        setterRealm_(setterRealm),
         objectKind_(objectKind)
     { }
 
   public:
     INSTRUCTION_HEADER(SetDOMProperty)
     TRIVIAL_NEW_WRAPPERS
     NAMED_OPERANDS((0, object), (1, value))
 
     JSJitSetterOp fun() const {
         return func_;
     }
+    Realm* setterRealm() const {
+        return setterRealm_;
+    }
     DOMObjectKind objectKind() const {
         return objectKind_;
     }
 
     bool possiblyCalls() const override {
         return true;
     }
 };
@@ -12512,44 +12517,54 @@ class MGetDOMPropertyBase
         MOZ_ASSERT(aliasSet == JSJitInfo::AliasEverything);
         return AliasSet::Store(AliasSet::Any);
     }
 };
 
 class MGetDOMProperty
   : public MGetDOMPropertyBase
 {
+    Realm* getterRealm_;
     DOMObjectKind objectKind_;
 
   protected:
-    MGetDOMProperty(const JSJitInfo* jitinfo, DOMObjectKind objectKind)
+    MGetDOMProperty(const JSJitInfo* jitinfo, DOMObjectKind objectKind,
+                    Realm* getterRealm)
       : MGetDOMPropertyBase(classOpcode, jitinfo),
+        getterRealm_(getterRealm),
         objectKind_(objectKind)
     {}
 
   public:
     INSTRUCTION_HEADER(GetDOMProperty)
 
     static MGetDOMProperty* New(TempAllocator& alloc, const JSJitInfo* info, DOMObjectKind objectKind,
-                                MDefinition* obj, MDefinition* guard, MDefinition* globalGuard)
-    {
-        auto* res = new(alloc) MGetDOMProperty(info, objectKind);
+                                Realm* getterRealm, MDefinition* obj, MDefinition* guard,
+                                MDefinition* globalGuard)
+    {
+        auto* res = new(alloc) MGetDOMProperty(info, objectKind, getterRealm);
         if (!res || !res->init(alloc, obj, guard, globalGuard))
             return nullptr;
         return res;
     }
 
+    Realm* getterRealm() const {
+        return getterRealm_;
+    }
     DOMObjectKind objectKind() const {
         return objectKind_;
     }
 
     bool congruentTo(const MDefinition* ins) const override {
         if (!ins->isGetDOMProperty())
             return false;
 
+        if (ins->toGetDOMProperty()->getterRealm() != getterRealm())
+            return false;
+
         return baseCongruentTo(ins->toGetDOMProperty());
     }
 
     bool possiblyCalls() const override {
         return true;
     }
 };
 
--- a/js/src/jit/MacroAssembler.h
+++ b/js/src/jit/MacroAssembler.h
@@ -36,16 +36,18 @@
 #include "jit/JitRealm.h"
 #include "jit/TemplateObject.h"
 #include "jit/VMFunctions.h"
 #include "vm/ProxyObject.h"
 #include "vm/Shape.h"
 #include "vm/TypedArrayObject.h"
 #include "vm/UnboxedObject.h"
 
+// [SMDOC] MacroAssembler multi-platform overview
+//
 // * How to read/write MacroAssembler method declarations:
 //
 // The following macros are made to avoid #ifdef around each method declarations
 // of the Macro Assembler, and they are also used as an hint on the location of
 // the implementations of each method.  For example, the following declaration
 //
 //   void Pop(FloatRegister t) DEFINED_ON(x86_shared, arm);
 //
--- a/js/src/jit/RangeAnalysis.cpp
+++ b/js/src/jit/RangeAnalysis.cpp
@@ -32,16 +32,18 @@ using mozilla::IsInfinite;
 using mozilla::IsNaN;
 using mozilla::IsNegativeZero;
 using mozilla::NegativeInfinity;
 using mozilla::PositiveInfinity;
 using mozilla::Swap;
 using JS::GenericNaN;
 using JS::ToInt32;
 
+// [SMDOC] IonMonkey Range Analysis
+//
 // This algorithm is based on the paper "Eliminating Range Checks Using
 // Static Single Assignment Form" by Gough and Klaren.
 //
 // We associate a range object with each SSA name, and the ranges are consulted
 // in order to determine whether overflow is possible for arithmetic
 // computations.
 //
 // An important source of range information that requires care to take
--- a/js/src/jit/Recover.h
+++ b/js/src/jit/Recover.h
@@ -12,16 +12,18 @@
 #include "builtin/Array.h"
 
 #include "jit/MIR.h"
 #include "jit/Snapshots.h"
 
 namespace js {
 namespace jit {
 
+// [SMDOC] IonMonkey Recover Instructions
+//
 // This file contains all recover instructions.
 //
 // A recover instruction is an equivalent of a MIR instruction which is executed
 // before the reconstruction of a baseline frame. Recover instructions are used
 // by resume points to fill the value which are not produced by the code
 // compiled by IonMonkey. For example, if a value is optimized away by
 // IonMonkey, but required by Baseline, then we should have a recover
 // instruction to fill the missing baseline frame slot.
--- a/js/src/jit/RegisterSets.h
+++ b/js/src/jit/RegisterSets.h
@@ -461,16 +461,18 @@ class RegisterSet {
     FloatRegisterSet& fpus() {
         return fpu_;
     }
     bool operator ==(const RegisterSet& other) const {
         return other.gpr_ == gpr_ && other.fpu_ == fpu_;
     }
 };
 
+// [SMDOC] JIT Register-Set overview
+//
 // There are 2 use cases for register sets:
 //
 //   1. To serve as a pool of allocatable register. This is useful for working
 //      on the code produced by some stub where free registers are available, or
 //      when we can release some registers.
 //
 //   2. To serve as a list of typed registers. This is useful for working with
 //      live registers and to manipulate them with the proper instructions. This
@@ -499,16 +501,18 @@ class RegisterSet {
 // false positive.
 
 template <typename RegisterSet>
 class AllocatableSet;
 
 template <typename RegisterSet>
 class LiveSet;
 
+// [SMDOC] JIT Register-Set (Allocatable)
+//
 // Base accessors classes have the minimal set of raw methods to manipulate the register set
 // given as parameter in a consistent manner.  These methods are:
 //
 //    - all<Type>: Returns a bit-set of all the register of a specific type
 //      which are present.
 //
 //    - has: Returns if all the bits needed to take a register are present.
 //
@@ -615,16 +619,18 @@ class AllocatableSetAccessors<RegisterSe
         set_.gprs().takeAllocatable(reg);
     }
     void takeUnchecked(FloatRegister reg) {
         set_.fpus().takeAllocatable(reg);
     }
 };
 
 
+// [SMDOC] JIT Register-Set (Live)
+//
 // The LiveSet accessors are used to collect a list of allocated
 // registers. Taking or adding a register should *not* consider the aliases, as
 // we care about interpreting the registers with the correct type.  For example,
 // on x64, where one float registers can be interpreted as an Simd128, a Double,
 // or a Float, adding xmm0 as an Simd128, does not make the register available
 // as a Double.
 //
 //     LiveFloatRegisterSet regs;
--- a/js/src/jit/SharedIC.h
+++ b/js/src/jit/SharedIC.h
@@ -17,16 +17,17 @@
 #include "vm/JSContext.h"
 #include "vm/Realm.h"
 #include "vm/ReceiverGuard.h"
 #include "vm/TypedArrayObject.h"
 
 namespace js {
 namespace jit {
 
+// [SMDOC] JIT Inline Caches (ICs)
 //
 // Baseline Inline Caches are polymorphic caches that aggressively
 // share their stub code.
 //
 // Every polymorphic site contains a linked list of stubs which are
 // specific to that site.  These stubs are composed of a |StubData|
 // structure that stores parametrization information (e.g.
 // the shape pointer for a shape-check-and-property-get stub), any
--- a/js/src/jit/Snapshots.cpp
+++ b/js/src/jit/Snapshots.cpp
@@ -14,16 +14,18 @@
 #include "jit/MIR.h"
 #include "jit/Recover.h"
 #include "vm/JSScript.h"
 #include "vm/Printer.h"
 
 using namespace js;
 using namespace js::jit;
 
+// [SMDOC] IonMonkey Snapshot encoding
+//
 // Encodings:
 //   [ptr] A fixed-size pointer.
 //   [vwu] A variable-width unsigned integer.
 //   [vws] A variable-width signed integer.
 //    [u8] An 8-bit unsigned integer.
 //   [u8'] An 8-bit unsigned integer which is potentially extended with packed
 //         data.
 //   [u8"] Packed data which is stored and packed in the previous [u8'].
--- a/js/src/jit/ValueNumbering.cpp
+++ b/js/src/jit/ValueNumbering.cpp
@@ -10,16 +10,18 @@
 #include "jit/IonAnalysis.h"
 #include "jit/JitSpewer.h"
 #include "jit/MIRGenerator.h"
 
 using namespace js;
 using namespace js::jit;
 
 /*
+ * [SMDOC] IonMonkey Value Numbering
+ *
  * Some notes on the main algorithm here:
  *  - The SSA identifier id() is the value number. We do replaceAllUsesWith as
  *    we go, so there's always at most one visible value with a given number.
  *
  *  - Consequently, the GVN algorithm is effectively pessimistic. This means it
  *    is not as powerful as an optimistic GVN would be, but it is simpler and
  *    faster.
  *
--- a/js/src/jit/shared/IonAssemblerBufferWithConstantPools.h
+++ b/js/src/jit/shared/IonAssemblerBufferWithConstantPools.h
@@ -9,16 +9,18 @@
 
 #include "mozilla/MathAlgorithms.h"
 
 #include <algorithm>
 
 #include "jit/JitSpewer.h"
 #include "jit/shared/IonAssemblerBuffer.h"
 
+// [SMDOC] JIT AssemblerBuffer constant pooling (ARM/ARM64/MIPS)
+//
 // This code extends the AssemblerBuffer to support the pooling of values loaded
 // using program-counter relative addressing modes. This is necessary with the
 // ARM instruction set because it has a fixed instruction size that can not
 // encode all values as immediate arguments in instructions. Pooling the values
 // allows the values to be placed in large chunks which minimizes the number of
 // forced branches around them in the code. This is used for loading floating
 // point constants, for loading 32 bit constants on the ARMv6, for absolute
 // branch targets, and in future will be needed for large branches on the ARMv6.
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -6132,46 +6132,31 @@ JS_GetStringEncodingLength(JSContext* cx
 }
 
 JS_PUBLIC_API(size_t)
 JS_EncodeStringToBuffer(JSContext* cx, JSString* str, char* buffer, size_t length)
 {
     AssertHeapIsIdle();
     CHECK_REQUEST(cx);
 
-    /*
-     * FIXME bug 612141 - fix DeflateStringToBuffer interface so the result
-     * would allow to distinguish between insufficient buffer and encoding
-     * error.
-     */
-    size_t writtenLength = length;
     JSLinearString* linear = str->ensureLinear(cx);
     if (!linear)
          return size_t(-1);
 
-    bool res;
+    JS::AutoCheckCannotGC nogc;
+    size_t writeLength = Min(linear->length(), length);
     if (linear->hasLatin1Chars()) {
-        JS::AutoCheckCannotGC nogc;
-        res = DeflateStringToBuffer(nullptr, linear->latin1Chars(nogc), linear->length(), buffer,
-                                    &writtenLength);
+        mozilla::PodCopy(reinterpret_cast<Latin1Char*>(buffer), linear->latin1Chars(nogc),
+                         writeLength);
     } else {
-        JS::AutoCheckCannotGC nogc;
-        res = DeflateStringToBuffer(nullptr, linear->twoByteChars(nogc), linear->length(), buffer,
-                                    &writtenLength);
+        const char16_t* src = linear->twoByteChars(nogc);
+        for (size_t i = 0; i < writeLength; i++)
+            buffer[i] = char(src[i]);
     }
-    if (res) {
-        MOZ_ASSERT(writtenLength <= length);
-        return writtenLength;
-    }
-    MOZ_ASSERT(writtenLength <= length);
-    size_t necessaryLength = str->length();
-    if (necessaryLength == size_t(-1))
-        return size_t(-1);
-    MOZ_ASSERT(writtenLength == length); // C strings are NOT encoded.
-    return necessaryLength;
+    return linear->length();
 }
 
 JS_PUBLIC_API(JS::Symbol*)
 JS::NewSymbol(JSContext* cx, HandleString description)
 {
     AssertHeapIsIdle();
     CHECK_REQUEST(cx);
     if (description)
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -7835,32 +7835,64 @@ static bool
 dom_set_x(JSContext* cx, HandleObject obj, void* self, JSJitSetterCallArgs args)
 {
     MOZ_ASSERT(JS_GetClass(obj) == GetDomClass());
     MOZ_ASSERT(self == (void*)0x1234);
     return true;
 }
 
 static bool
+dom_get_global(JSContext* cx, HandleObject obj, void* self, JSJitGetterCallArgs args)
+{
+    MOZ_ASSERT(JS_GetClass(obj) == GetDomClass());
+    MOZ_ASSERT(self == (void*)0x1234);
+
+    // Return the current global (instead of obj->global()) to test cx->realm
+    // switching in the JIT.
+    args.rval().setObject(*ToWindowProxyIfWindow(cx->global()));
+
+    return true;
+}
+
+static bool
+dom_set_global(JSContext* cx, HandleObject obj, void* self, JSJitSetterCallArgs args)
+{
+    MOZ_ASSERT(JS_GetClass(obj) == GetDomClass());
+    MOZ_ASSERT(self == (void*)0x1234);
+
+    // Throw an exception if our argument is not the current global. This lets
+    // us test cx->realm switching.
+    if (!args[0].isObject() ||
+        ToWindowIfWindowProxy(&args[0].toObject()) != cx->global())
+    {
+        JS_ReportErrorASCII(cx, "Setter not called with matching global argument");
+        return false;
+    }
+
+    return true;
+}
+
+static bool
 dom_doFoo(JSContext* cx, HandleObject obj, void* self, const JSJitMethodCallArgs& args)
 {
     MOZ_ASSERT(JS_GetClass(obj) == GetDomClass());
     MOZ_ASSERT(self == (void*)0x1234);
+    MOZ_ASSERT(cx->realm() == args.callee().as<JSFunction>().realm());
 
     /* Just return args.length(). */
     args.rval().setInt32(args.length());
     return true;
 }
 
 static const JSJitInfo dom_x_getterinfo = {
     { (JSJitGetterOp)dom_get_x },
     { 0 },    /* protoID */
     { 0 },    /* depth */
+    JSJitInfo::Getter,
     JSJitInfo::AliasNone, /* aliasSet */
-    JSJitInfo::Getter,
     JSVAL_TYPE_UNKNOWN, /* returnType */
     true,     /* isInfallible. False in setters. */
     true,     /* isMovable */
     true,     /* isEliminatable */
     false,    /* isAlwaysInSlot */
     false,    /* isLazilyCachedInSlot */
     false,    /* isTypedMethod */
     0         /* slotIndex */
@@ -7877,16 +7909,51 @@ static const JSJitInfo dom_x_setterinfo 
     false,    /* isMovable. */
     false,    /* isEliminatable. */
     false,    /* isAlwaysInSlot */
     false,    /* isLazilyCachedInSlot */
     false,    /* isTypedMethod */
     0         /* slotIndex */
 };
 
+// Note: this getter uses AliasEverything and is marked as fallible and
+// non-movable (1) to prevent Ion from getting too clever optimizing it and
+// (2) it's nice to have a few different kinds of getters in the shell.
+static const JSJitInfo dom_global_getterinfo = {
+    { (JSJitGetterOp)dom_get_global },
+    { 0 },    /* protoID */
+    { 0 },    /* depth */
+    JSJitInfo::Getter,
+    JSJitInfo::AliasEverything, /* aliasSet */
+    JSVAL_TYPE_OBJECT, /* returnType */
+    false,    /* isInfallible. False in setters. */
+    false,    /* isMovable */
+    false,    /* isEliminatable */
+    false,    /* isAlwaysInSlot */
+    false,    /* isLazilyCachedInSlot */
+    false,    /* isTypedMethod */
+    0         /* slotIndex */
+};
+
+static const JSJitInfo dom_global_setterinfo = {
+    { (JSJitGetterOp)dom_set_global },
+    { 0 },    /* protoID */
+    { 0 },    /* depth */
+    JSJitInfo::Setter,
+    JSJitInfo::AliasEverything, /* aliasSet */
+    JSVAL_TYPE_UNKNOWN, /* returnType */
+    false,    /* isInfallible. False in setters. */
+    false,    /* isMovable. */
+    false,    /* isEliminatable. */
+    false,    /* isAlwaysInSlot */
+    false,    /* isLazilyCachedInSlot */
+    false,    /* isTypedMethod */
+    0         /* slotIndex */
+};
+
 static const JSJitInfo doFoo_methodinfo = {
     { (JSJitGetterOp)dom_doFoo },
     { 0 },    /* protoID */
     { 0 },    /* depth */
     JSJitInfo::Method,
     JSJitInfo::AliasEverything, /* aliasSet */
     JSVAL_TYPE_UNKNOWN, /* returnType */
     false,    /* isInfallible. False in setters. */
@@ -7901,16 +7968,23 @@ static const JSJitInfo doFoo_methodinfo 
 static const JSPropertySpec dom_props[] = {
     {"x",
      JSPROP_ENUMERATE,
      { {
         { { dom_genericGetter, &dom_x_getterinfo } },
         { { dom_genericSetter, &dom_x_setterinfo } }
      } },
     },
+    {"global",
+     JSPROP_ENUMERATE,
+     { {
+        { { dom_genericGetter, &dom_global_getterinfo } },
+        { { dom_genericSetter, &dom_global_setterinfo } }
+     } },
+    },
     JS_PS_END
 };
 
 static const JSFunctionSpec dom_methods[] = {
     JS_FNINFO("doFoo", dom_genericMethod, &doFoo_methodinfo, 3, JSPROP_ENUMERATE),
     JS_FS_END
 };
 
--- a/js/src/threading/ExclusiveData.h
+++ b/js/src/threading/ExclusiveData.h
@@ -12,16 +12,18 @@
 #include "mozilla/OperatorNewExtensions.h"
 
 #include "threading/ConditionVariable.h"
 #include "threading/Mutex.h"
 
 namespace js {
 
 /**
+ * [SMDOC] ExclusiveData API
+ *
  * A mutual exclusion lock class.
  *
  * `ExclusiveData` provides an RAII guard to automatically lock and unlock when
  * accessing the protected inner value.
  *
  * Unlike the STL's `std::mutex`, the protected value is internal to this
  * class. This is a huge win: one no longer has to rely on documentation to
  * explain the relationship between a lock and its protected data, and the type
--- a/js/src/util/Text.cpp
+++ b/js/src/util/Text.cpp
@@ -114,46 +114,16 @@ js::InflateString(JSContext* cx, const c
     char16_t* chars = cx->pod_malloc<char16_t>(length + 1);
     if (!chars)
         return nullptr;
     CopyAndInflateChars(chars, bytes, length);
     chars[length] = 0;
     return chars;
 }
 
-template <typename CharT>
-bool
-js::DeflateStringToBuffer(JSContext* maybecx, const CharT* src, size_t srclen,
-                          char* dst, size_t* dstlenp)
-{
-    size_t dstlen = *dstlenp;
-    if (srclen > dstlen) {
-        for (size_t i = 0; i < dstlen; i++)
-            dst[i] = char(src[i]);
-        if (maybecx) {
-            AutoSuppressGC suppress(maybecx);
-            JS_ReportErrorNumberASCII(maybecx, GetErrorMessage, nullptr,
-                                      JSMSG_BUFFER_TOO_SMALL);
-        }
-        return false;
-    }
-    for (size_t i = 0; i < srclen; i++)
-        dst[i] = char(src[i]);
-    *dstlenp = srclen;
-    return true;
-}
-
-template bool
-js::DeflateStringToBuffer(JSContext* maybecx, const Latin1Char* src, size_t srclen,
-                          char* dst, size_t* dstlenp);
-
-template bool
-js::DeflateStringToBuffer(JSContext* maybecx, const char16_t* src, size_t srclen,
-                          char* dst, size_t* dstlenp);
-
 /*
  * Convert one UCS-4 char and write it into a UTF-8 buffer, which must be at
  * least 4 bytes long.  Return the number of UTF-8 bytes of data written.
  */
 uint32_t
 js::OneUcs4ToUtf8Char(uint8_t* utf8Buffer, uint32_t ucs4Char)
 {
     MOZ_ASSERT(ucs4Char <= unicode::NonBMPMax);
--- a/js/src/util/Text.h
+++ b/js/src/util/Text.h
@@ -148,27 +148,16 @@ CopyAndInflateChars(char16_t* dst, const
 inline void
 CopyAndInflateChars(char16_t* dst, const JS::Latin1Char* src, size_t srclen)
 {
     for (size_t i = 0; i < srclen; i++)
         dst[i] = src[i];
 }
 
 /*
- * Deflate JS chars to bytes into a buffer. 'bytes' must be large enough for
- * 'length chars. The buffer is NOT null-terminated. The destination length
- * must to be initialized with the buffer size and will contain on return the
- * number of copied bytes.
- */
-template <typename CharT>
-extern bool
-DeflateStringToBuffer(JSContext* maybecx, const CharT* chars,
-                      size_t charsLength, char* bytes, size_t* length);
-
-/*
  * Convert one UCS-4 char and write it into a UTF-8 buffer, which must be at
  * least 4 bytes long.  Return the number of UTF-8 bytes of data written.
  */
 extern uint32_t
 OneUcs4ToUtf8Char(uint8_t* utf8Buffer, uint32_t ucs4Char);
 
 extern size_t
 PutEscapedStringImpl(char* buffer, size_t size, GenericPrinter* out, JSLinearString* str,
--- a/js/src/vm/ArgumentsObject.h
+++ b/js/src/vm/ArgumentsObject.h
@@ -93,16 +93,18 @@ struct ArgumentsData
 // Maximum supported value of arguments.length. This bounds the maximum
 // number of arguments that can be supplied to Function.prototype.apply.
 // This value also bounds the number of elements parsed in an array
 // initializer.
 // NB: keep this in sync with the copy in builtin/SelfHostingDefines.h.
 static const unsigned ARGS_LENGTH_MAX = 500 * 1000;
 
 /*
+ * [SMDOC] ArgumentsObject
+ *
  * ArgumentsObject instances represent |arguments| objects created to store
  * function arguments when a function is called.  It's expensive to create such
  * objects if they're never used, so they're only created when they are
  * potentially used.
  *
  * Arguments objects are complicated because, for non-strict mode code, they
  * must alias any named arguments which were provided to the function.  Gnarly
  * example:
--- a/js/src/vm/ArrayBufferObject.cpp
+++ b/js/src/vm/ArrayBufferObject.cpp
@@ -587,16 +587,18 @@ ArrayBufferObject::changeContents(JSCont
         for (size_t i = 0; i < views->length(); i++)
             changeViewContents(cx, (*views)[i], oldDataPointer, newContents);
     }
     if (firstView())
         changeViewContents(cx, firstView(), oldDataPointer, newContents);
 }
 
 /*
+ * [SMDOC] WASM Linear Memory structure
+ *
  * Wasm Raw Buf Linear Memory Structure
  *
  * The linear heap in Wasm is an mmaped array buffer. Several
  * constants manage its lifetime:
  *
  *  - length - the wasm-visible current length of the buffer. Accesses in the
  *    range [0, length] succeed. May only increase.
  *
--- a/js/src/vm/BytecodeUtil.h
+++ b/js/src/vm/BytecodeUtil.h
@@ -30,17 +30,17 @@ typedef enum JSOp {
 #define ENUMERATE_OPCODE(op, val, ...) op = val,
 FOR_EACH_OPCODE(ENUMERATE_OPCODE)
 #undef ENUMERATE_OPCODE
 
     JSOP_LIMIT
 } JSOp;
 
 /*
- * JS bytecode formats.
+ * [SMDOC] Bytecode Format flags (JOF_*)
  */
 enum {
     JOF_BYTE            = 0,        /* single bytecode, no immediates */
     JOF_JUMP            = 1,        /* signed 16-bit jump offset immediate */
     JOF_ATOM            = 2,        /* unsigned 16-bit constant index */
     JOF_UINT16          = 3,        /* unsigned 16-bit immediate operand */
     JOF_TABLESWITCH     = 4,        /* table switch */
     /* 5 is unused */
--- a/js/src/vm/EnvironmentObject.h
+++ b/js/src/vm/EnvironmentObject.h
@@ -40,16 +40,18 @@ EnvironmentCoordinateFunctionScript(JSSc
 
 
 /*** Environment objects *****************************************************/
 
 
 /*** Environment objects *****************************************************/
 
 /*
+ * [SMDOC] Environment Objects
+ *
  * About environments
  * ------------------
  *
  * (See also: ecma262 rev c7952de (19 Aug 2016) 8.1 "Lexical Environments".)
  *
  * Scoping in ES is specified in terms of "Environment Records". There's a
  * global Environment Record per realm, and a new Environment Record is created
  * whenever control enters a function, block, or other scope.
--- a/js/src/vm/JSObject.h
+++ b/js/src/vm/JSObject.h
@@ -44,16 +44,18 @@ enum class IntegrityLevel {
 
 // Forward declarations, required for later friend declarations.
 bool PreventExtensions(JSContext* cx, JS::HandleObject obj, JS::ObjectOpResult& result);
 bool SetImmutablePrototype(JSContext* cx, JS::HandleObject obj, bool* succeeded);
 
 }  /* namespace js */
 
 /*
+ * [SMDOC] JSObject layout
+ *
  * A JavaScript object.
  *
  * This is the base class for all objects exposed to JS script (as well as some
  * objects that are only accessed indirectly). Subclasses add additional fields
  * and execution semantics. The runtime class of an arbitrary JSObject is
  * identified by JSObject::getClass().
  *
  * The members common to all objects are as follows:
--- a/js/src/vm/JSScript.cpp
+++ b/js/src/vm/JSScript.cpp
@@ -2327,16 +2327,18 @@ ScriptSource::setSourceMapURL(JSContext*
     if (len == 1)
         return true;
 
     sourceMapURL_ = DuplicateString(cx, sourceMapURL);
     return sourceMapURL_ != nullptr;
 }
 
 /*
+ * [SMDOC] JSScript data layout (shared)
+ *
  * Shared script data management.
  *
  * SharedScriptData::data contains data that can be shared within a
  * runtime. The atoms() data is placed first to simplify its alignment.
  *
  * Array elements   Pointed to by         Length
  * --------------   -------------         ------
  * GCPtrAtom        atoms()               natoms()
@@ -2500,16 +2502,18 @@ js::FreeScriptData(JSRuntime* rt)
 #endif
         js_free(e.front());
     }
 
     table.clear();
 }
 
 /*
+ * [SMDOC] JSScript data layout (unshared)
+ *
  * JSScript::data and SharedScriptData::data have complex,
  * manually-controlled, memory layouts.
  *
  * JSScript::data begins with some optional array headers. They are optional
  * because they often aren't needed, i.e. the corresponding arrays often have
  * zero elements. Each header has a bit in JSScript::hasArrayBits that
  * indicates if it's present within |data|; from this the offset of each
  * present array header can be computed. Each header has an accessor function
--- a/js/src/vm/NativeObject.cpp
+++ b/js/src/vm/NativeObject.cpp
@@ -1189,16 +1189,27 @@ CallAddPropertyHookDense(JSContext* cx, 
         if (!CallJSAddPropertyOp(cx, addProperty, obj, id, value)) {
             obj->setDenseElementHole(cx, index);
             return false;
         }
     }
     return true;
 }
 
+/**
+ * Determines whether a write to the given element on |arr| should fail
+ * because |arr| has a non-writable length, and writing that element would
+ * increase the length of the array.
+ */
+static bool
+WouldDefinePastNonwritableLength(ArrayObject* arr, uint32_t index)
+{
+    return !arr->lengthIsWritable() && index >= arr->length();
+}
+
 static MOZ_ALWAYS_INLINE void
 UpdateShapeTypeAndValue(JSContext* cx, NativeObject* obj, Shape* shape, jsid id,
                         const Value& value)
 {
     MOZ_ASSERT(id == shape->propid());
 
     if (shape->isDataProperty()) {
         obj->setSlotWithType(cx, shape, value, /* overwriting = */ false);
@@ -1616,17 +1627,17 @@ js::NativeDefineProperty(JSContext* cx, 
 
             MOZ_ASSERT(!cx->helperThread());
             return ArraySetLength(cx, arr, id, desc_.attributes(), desc_.value(), result);
         }
 
         // 9.4.2.1 step 3. Don't extend a fixed-length array.
         uint32_t index;
         if (IdIsIndex(id, &index)) {
-            if (WouldDefinePastNonwritableLength(obj, index))
+            if (WouldDefinePastNonwritableLength(arr, index))
                 return result.fail(JSMSG_CANT_DEFINE_PAST_ARRAY_LENGTH);
         }
     } else if (obj->is<TypedArrayObject>()) {
         // 9.4.5.3 step 3. Indexed properties of typed arrays are special.
         uint64_t index;
         if (IsTypedArrayIndex(id, &index)) {
             MOZ_ASSERT(!cx->helperThread());
             return DefineTypedArrayElement(cx, obj, index, desc_, result);
@@ -1918,17 +1929,17 @@ DefineNonexistentProperty(JSContext* cx,
     if (obj->is<ArrayObject>()) {
         // Array's length property is non-configurable, so we shouldn't
         // encounter it in this function.
         MOZ_ASSERT(id != NameToId(cx->names().length));
 
         // 9.4.2.1 step 3. Don't extend a fixed-length array.
         uint32_t index;
         if (IdIsIndex(id, &index)) {
-            if (WouldDefinePastNonwritableLength(obj, index))
+            if (WouldDefinePastNonwritableLength(&obj->as<ArrayObject>(), index))
                 return result.fail(JSMSG_CANT_DEFINE_PAST_ARRAY_LENGTH);
         }
     } else if (obj->is<TypedArrayObject>()) {
         // 9.4.5.3 step 3. Indexed properties of typed arrays are special.
         uint64_t index;
         if (IsTypedArrayIndex(id, &index)) {
             // This method is only called for non-existent properties, which
             // means any absent indexed property must be out of range.
@@ -2642,21 +2653,24 @@ SetDenseOrTypedArrayElement(JSContext* c
         // current behavior.  (ES6 currently says to throw for this in
         // strict mode code, so we may eventually need to change.)
         uint32_t len = obj->as<TypedArrayObject>().length();
         if (index < len) {
             TypedArrayObject::setElement(obj->as<TypedArrayObject>(), index, d);
             return result.succeed();
         }
 
-        return result.failSoft(JSMSG_BAD_INDEX);
+        // A previously existing typed array element can only be out-of-bounds
+        // if the above ToNumber call detached the typed array's buffer.
+        MOZ_ASSERT(obj->as<TypedArrayObject>().hasDetachedBuffer());
+
+        return result.failSoft(JSMSG_TYPED_ARRAY_DETACHED);
     }
 
-    if (WouldDefinePastNonwritableLength(obj, index))
-        return result.fail(JSMSG_CANT_DEFINE_PAST_ARRAY_LENGTH);
+    MOZ_ASSERT(obj->containsDenseElement(index));
 
     if (!obj->maybeCopyElementsForWrite(cx))
         return false;
 
     obj->setDenseElementWithType(cx, index, v);
     return result.succeed();
 }
 
@@ -2664,19 +2678,18 @@ SetDenseOrTypedArrayElement(JSContext* c
  * Finish the assignment `receiver[id] = v` when an existing property (shape)
  * has been found on a native object (pobj). This implements ES6 draft rev 32
  * (2015 Feb 2) 9.1.9 steps 5 and 6.
  *
  * It is necessary to pass both id and shape because shape could be an implicit
  * dense or typed array element (i.e. not actually a pointer to a Shape).
  */
 static bool
-SetExistingProperty(JSContext* cx, HandleNativeObject obj, HandleId id, HandleValue v,
-                    HandleValue receiver, HandleNativeObject pobj, Handle<PropertyResult> prop,
-                    ObjectOpResult& result)
+SetExistingProperty(JSContext* cx, HandleId id, HandleValue v, HandleValue receiver,
+                    HandleNativeObject pobj, Handle<PropertyResult> prop, ObjectOpResult& result)
 {
     // Step 5 for dense elements.
     if (prop.isDenseOrTypedArrayElement()) {
         // Step 5.a.
         if (pobj->denseElementsAreFrozen())
             return result.fail(JSMSG_READ_ONLY);
 
         // Pure optimization for the common case:
@@ -2739,17 +2752,17 @@ js::NativeSetProperty(JSContext* cx, Han
     for (;;) {
         // Steps 2-3. ('done' is a SpiderMonkey-specific thing, used below.)
         bool done;
         if (!LookupOwnPropertyInline<CanGC>(cx, pobj, id, &prop, &done))
             return false;
 
         if (prop) {
             // Steps 5-6.
-            return SetExistingProperty(cx, obj, id, v, receiver, pobj, prop, result);
+            return SetExistingProperty(cx, id, v, receiver, pobj, prop, result);
         }
 
         // Steps 4.a-b. The check for 'done' on this next line is tricky.
         // done can be true in exactly these unlikely-sounding cases:
         // - We're looking up an element, and pobj is a TypedArray that
         //   doesn't have that many elements.
         // - We're being called from a resolve hook to assign to the property
         //   being resolved.
--- a/js/src/vm/NativeObject.h
+++ b/js/src/vm/NativeObject.h
@@ -87,16 +87,18 @@ class ArrayObject;
  * changed length property, |value| is the value for the new length, and
  * |result| receives an error code if the change is invalid.
  */
 extern bool
 ArraySetLength(JSContext* cx, Handle<ArrayObject*> obj, HandleId id,
                unsigned attrs, HandleValue value, ObjectOpResult& result);
 
 /*
+ * [SMDOC] NativeObject Elements layout
+ *
  * Elements header used for native objects. The elements component of such objects
  * offers an efficient representation for all or some of the indexed properties
  * of the object, using a flat array of Values rather than a shape hierarchy
  * stored in the object's slots. This structure is immediately followed by an
  * array of elements, with the elements member in an object pointing to the
  * beginning of that array (the end of this structure).
  * See below for usage of this structure.
  *
@@ -154,16 +156,19 @@ ArraySetLength(JSContext* cx, Handle<Arr
  * as small as possible: if the object is known to have no hole values below
  * its initialized length, then it is "packed" and can be accessed much faster
  * by JIT code.
  *
  * Elements do not track property creation order, so enumerating the elements
  * of an object does not necessarily visit indexes in the order they were
  * created.
  *
+ *
+ * [SMDOC] NativeObject shifted elements optimization
+ *
  * Shifted elements
  * ----------------
  * It's pretty common to use an array as a queue, like this:
  *
  *    while (arr.length > 0)
  *        foo(arr.shift());
  *
  * To ensure we don't get quadratic behavior on this, elements can be 'shifted'
@@ -427,16 +432,18 @@ enum class DenseElementResult {
 };
 
 enum class ShouldUpdateTypes {
     Update,
     DontUpdate
 };
 
 /*
+ * [SMDOC] NativeObject layout
+ *
  * NativeObject specifies the internal implementation of a native object.
  *
  * Native objects use ShapedObject::shape to record property information. Two
  * native objects with the same shape are guaranteed to have the same number of
  * fixed slots.
  *
  * Native objects extend the base implementation of an object with storage for
  * the object's named properties and indexed elements.
--- a/js/src/vm/ObjectGroup.h
+++ b/js/src/vm/ObjectGroup.h
@@ -60,17 +60,17 @@ enum NewObjectKind {
      * Objects which will not benefit from being allocated in the nursery
      * (e.g. because they are known to have a long lifetime) may be allocated
      * with this kind to place them immediately into the tenured generation.
      */
     TenuredObject
 };
 
 /*
- * Lazy object groups overview.
+ * [SMDOC] Type-Inference lazy ObjectGroup
  *
  * Object groups which represent at most one JS object are constructed lazily.
  * These include groups for native functions, standard classes, scripted
  * functions defined at the top level of global/eval scripts, objects which
  * dynamically become the prototype of some other object, and in some other
  * cases. Typical web workloads often create many windows (and many copies of
  * standard natives) and many scripts, with comparatively few non-singleton
  * groups.
@@ -104,16 +104,18 @@ class ObjectGroup : public gc::TenuredCe
     /* Flags for this group. */
     ObjectGroupFlags flags_; // set by constructor
 
     // If non-null, holds additional information about this object, whose
     // format is indicated by the object's addendum kind.
     void* addendum_ = nullptr;
 
     /*
+     * [SMDOC] Type-Inference object properties
+     *
      * Properties of this object.
      *
      * The type sets in the properties of a group describe the possible values
      * that can be read out of that property in actual JS objects. In native
      * objects, property types account for plain data properties (those with a
      * slot and no getter or setter hook) and dense elements. In typed objects
      * and unboxed objects, property types account for object and value
      * properties and elements in the object, and expando properties in unboxed
--- a/js/src/vm/Opcodes.h
+++ b/js/src/vm/Opcodes.h
@@ -8,16 +8,18 @@
 #ifndef vm_Opcodes_h
 #define vm_Opcodes_h
 
 #include "mozilla/Attributes.h"
 
 #include <stddef.h>
 
 /*
+ * [SMDOC] Bytecode Definitions
+ *
  * JavaScript operation bytecodes.  Add a new bytecode by claiming one of the
  * JSOP_UNUSED* here or by extracting the first unused opcode from
  * FOR_EACH_TRAILING_UNUSED_OPCODE and updating js::detail::LastDefinedOpcode
  * below.
  *
  * Includers must define a macro with the following form:
  *
  * #define MACRO(op,val,name,image,length,nuses,ndefs,format) ...
--- a/js/src/vm/Printer.cpp
+++ b/js/src/vm/Printer.cpp
@@ -218,33 +218,35 @@ Sprinter::put(const char* s, size_t len)
 }
 
 bool
 Sprinter::putString(JSString* s)
 {
     InvariantChecker ic(this);
 
     size_t length = s->length();
-    size_t size = length;
 
-    char* buffer = reserve(size);
+    char* buffer = reserve(length);
     if (!buffer)
         return false;
 
     JSLinearString* linear = s->ensureLinear(context);
     if (!linear)
         return false;
 
     JS::AutoCheckCannotGC nogc;
-    if (linear->hasLatin1Chars())
+    if (linear->hasLatin1Chars()) {
         PodCopy(reinterpret_cast<Latin1Char*>(buffer), linear->latin1Chars(nogc), length);
-    else
-        DeflateStringToBuffer(nullptr, linear->twoByteChars(nogc), length, buffer, &size);
+    } else {
+        const char16_t* src = linear->twoByteChars(nogc);
+        for (size_t i = 0; i < length; i++)
+            buffer[i] = char(src[i]);
+    }
 
-    buffer[size] = 0;
+    buffer[length] = 0;
     return true;
 }
 
 ptrdiff_t
 Sprinter::getOffset() const
 {
     return offset;
 }
--- a/js/src/vm/Realm.h
+++ b/js/src/vm/Realm.h
@@ -114,16 +114,18 @@ class NewProxyCache
         entries_[0].group = group;
         entries_[0].shape = shape;
     }
     void purge() {
         entries_.reset();
     }
 };
 
+// [SMDOC] Object MetadataBuilder API
+//
 // We must ensure that all newly allocated JSObjects get their metadata
 // set. However, metadata builders may require the new object be in a sane
 // state (eg, have its reserved slots initialized so they can get the
 // sizeOfExcludingThis of the object). Therefore, for objects of certain
 // JSClasses (those marked with JSCLASS_DELAY_METADATA_BUILDER), it is not safe
 // for the allocation paths to call the object metadata builder
 // immediately. Instead, the JSClass-specific "constructor" C++ function up the
 // stack makes a promise that it will ensure that the new object has its
--- a/js/src/vm/Runtime.h
+++ b/js/src/vm/Runtime.h
@@ -102,17 +102,17 @@ class CompileRuntime;
 
 #ifdef JS_SIMULATOR_ARM64
 typedef vixl::Simulator Simulator;
 #elif defined(JS_SIMULATOR)
 class Simulator;
 #endif
 } // namespace jit
 
-// JS Engine Threading
+// [SMDOC] JS Engine Threading
 //
 // Threads interacting with a runtime are divided into two categories:
 //
 // - The main thread is capable of running JS. There's at most one main thread
 //   per runtime.
 //
 // - Helper threads do not run JS, and are controlled or triggered by activity
 //   on the main thread (or main threads, since all runtimes in a process share
--- a/js/src/vm/Shape.h
+++ b/js/src/vm/Shape.h
@@ -29,16 +29,18 @@
 #include "js/UbiNode.h"
 #include "vm/JSAtom.h"
 #include "vm/ObjectGroup.h"
 #include "vm/Printer.h"
 #include "vm/StringType.h"
 #include "vm/SymbolType.h"
 
 /*
+ * [SMDOC] Shapes
+ *
  * In isolation, a Shape represents a property that exists in one or more
  * objects; it has an id, flags, etc. (But it doesn't represent the property's
  * value.)  However, Shapes are always stored in linked linear sequence of
  * Shapes, called "shape lineages". Each shape lineage represents the layout of
  * an entire object.
  *
  * Every JSObject has a pointer, |shape_|, accessible via lastProperty(), to
  * the last Shape in a shape lineage, which identifies the property most
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -64,17 +64,17 @@ class SavedFrame;
 namespace jit {
 class CommonFrameLayout;
 }
 namespace wasm {
 class DebugFrame;
 class Instance;
 }
 
-// VM stack layout
+// [SMDOC] VM stack layout
 //
 // A JSRuntime's stack consists of a linked list of activations. Every activation
 // contains a number of scripted frames that are either running in the interpreter
 // (InterpreterActivation) or JIT code (JitActivation). The frames inside a single
 // activation are contiguous: whenever C++ calls back into JS, a new activation is
 // pushed.
 //
 // Every activation is tied to a single JSContext and JS::Compartment. This means we
--- a/js/src/vm/StringType.h
+++ b/js/src/vm/StringType.h
@@ -39,17 +39,17 @@ class StaticStrings;
 class PropertyName;
 
 /* The buffer length required to contain any unsigned 32-bit integer. */
 static const size_t UINT32_CHAR_BUFFER_LENGTH = sizeof("4294967295") - 1;
 
 } /* namespace js */
 
 /*
- * JavaScript strings
+ * [SMDOC] JavaScript Strings
  *
  * Conceptually, a JS string is just an array of chars and a length. This array
  * of chars may or may not be null-terminated and, if it is, the null character
  * is not included in the length.
  *
  * To improve performance of common operations, the following optimizations are
  * made which affect the engine's representation of strings:
  *
--- a/js/src/vm/SymbolType.h
+++ b/js/src/vm/SymbolType.h
@@ -117,16 +117,18 @@ struct HashSymbolsByDescription
         return HashNumber(l->hash());
     }
     static bool match(Key sym, Lookup l) {
         return sym->description() == l;
     }
 };
 
 /*
+ * [SMDOC] Symbol.for() registry (ES6 GlobalSymbolRegistry)
+ *
  * The runtime-wide symbol registry, used to implement Symbol.for().
  *
  * ES6 draft rev 25 (2014 May 22) calls this the GlobalSymbolRegistry List. In
  * our implementation, it is not global. There is one per JSRuntime. The
  * symbols in the symbol registry, like all symbols, are allocated in the atoms
  * compartment and can be directly referenced from any compartment. They are
  * never shared across runtimes.
  *
--- a/js/src/vm/TypeInference.h
+++ b/js/src/vm/TypeInference.h
@@ -208,16 +208,18 @@ enum : uint32_t {
 };
 typedef uint32_t ObjectGroupFlags;
 
 class StackTypeSet;
 class HeapTypeSet;
 class TemporaryTypeSet;
 
 /*
+ * [SMDOC] Type-Inference TypeSet
+ *
  * Information about the set of types associated with an lvalue. There are
  * three kinds of type sets:
  *
  * - StackTypeSet are associated with TypeScripts, for arguments and values
  *   observed at property reads. These are implicitly frozen on compilation
  *   and only have constraints added to them which can trigger invalidation of
  *   TypeNewScript information.
  *
--- a/js/src/wasm/WasmBaselineCompile.cpp
+++ b/js/src/wasm/WasmBaselineCompile.cpp
@@ -11,17 +11,18 @@
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
-/* WebAssembly baseline compiler ("RabaldrMonkey")
+/*
+ * [SMDOC] WebAssembly baseline compiler (RabaldrMonkey)
  *
  * General assumptions for 32-bit vs 64-bit code:
  *
  * - A 32-bit register can be extended in-place to a 64-bit register on 64-bit
  *   systems.
  *
  * - Code that knows that Register64 has a '.reg' member on 64-bit systems and
  *   '.high' and '.low' members on 32-bit systems, or knows the implications
--- a/js/src/wasm/WasmTextToBinary.cpp
+++ b/js/src/wasm/WasmTextToBinary.cpp
@@ -1651,25 +1651,29 @@ WasmTokenStream::next()
       case 'l':
         if (consume(u"local"))
             return WasmToken(WasmToken::Local, begin, cur_);
         if (consume(u"loop"))
             return WasmToken(WasmToken::Loop, begin, cur_);
         break;
 
       case 'm':
+        if (consume(u"memory.")) {
 #ifdef ENABLE_WASM_BULKMEM_OPS
-        if (consume(u"memory.")) {
             if (consume(u"copy"))
                 return WasmToken(WasmToken::MemCopy, begin, cur_);
             if (consume(u"fill"))
                 return WasmToken(WasmToken::MemFill, begin, cur_);
+#endif
+            if (consume(u"grow"))
+                return WasmToken(WasmToken::GrowMemory, begin, cur_);
+            if (consume(u"size"))
+                return WasmToken(WasmToken::CurrentMemory, begin, cur_);
             break;
         }
-#endif
         if (consume(u"module"))
             return WasmToken(WasmToken::Module, begin, cur_);
         if (consume(u"memory"))
             return WasmToken(WasmToken::Memory, begin, cur_);
         if (consume(u"mut"))
             return WasmToken(WasmToken::Mutable, begin, cur_);
         break;
 
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -171,16 +171,18 @@
 #include "nsIDragSession.h"
 #include "nsIFrameInlines.h"
 #include "mozilla/gfx/2D.h"
 #include "nsSubDocumentFrame.h"
 #include "nsQueryObject.h"
 #include "nsLayoutStylesheetCache.h"
 #include "mozilla/layers/InputAPZContext.h"
 #include "mozilla/layers/FocusTarget.h"
+#include "mozilla/layers/WebRenderLayerManager.h"
+#include "mozilla/layers/WebRenderUserData.h"
 #include "mozilla/ServoBindings.h"
 #include "mozilla/ServoStyleSet.h"
 #include "mozilla/StyleSheet.h"
 #include "mozilla/StyleSheetInlines.h"
 #include "mozilla/dom/ImageTracker.h"
 #include "nsIDocShellTreeOwner.h"
 #include "nsBindingManager.h"
 #include "nsClassHashtable.h"
@@ -6314,17 +6316,25 @@ PresShell::Paint(nsView*         aViewTo
   if (frame) {
     // We can paint directly into the widget using its layer manager.
     nsLayoutUtils::PaintFrame(nullptr, frame, aDirtyRegion, bgcolor,
                               nsDisplayListBuilderMode::PAINTING, flags);
     return;
   }
 
   if (layerManager->GetBackendType() == layers::LayersBackend::LAYERS_WR) {
-    // TODO: bug 1405465 - create a WR display list which simulates the color layer below.
+    nsPresContext* pc = GetPresContext();
+    LayoutDeviceRect bounds =
+      LayoutDeviceRect::FromAppUnits(pc->GetVisibleArea(), pc->AppUnitsPerDevPixel());
+    bgcolor = NS_ComposeColors(bgcolor, mCanvasBackgroundColor);
+    WebRenderBackgroundData data(wr::ToLayoutRect(bounds), wr::ToColorF(ToDeviceColor(bgcolor)));
+    nsTArray<wr::WrFilterOp> wrFilters;
+
+    MaybeSetupTransactionIdAllocator(layerManager, presContext);
+    layerManager->AsWebRenderLayerManager()->EndTransactionWithoutLayer(nullptr, nullptr, wrFilters, &data);
     return;
   }
 
   RefPtr<ColorLayer> root = layerManager->CreateColorLayer();
   if (root) {
     nsPresContext* pc = GetPresContext();
     nsIntRect bounds =
       pc->GetVisibleArea().ToOutsidePixels(pc->AppUnitsPerDevPixel());
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -1911,16 +1911,21 @@ nsCSSFrameConstructor::CreateGeneratedCo
   }
 
   uint32_t contentCount = pseudoComputedStyle->StyleContent()->ContentCount();
   for (uint32_t contentIndex = 0; contentIndex < contentCount; contentIndex++) {
     nsCOMPtr<nsIContent> content =
       CreateGeneratedContent(aState, aParentContent, pseudoComputedStyle,
                              contentIndex);
     if (content) {
+      // We don't strictly have to set NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE
+      // here; it would get set under AppendChildTo.  But AppendChildTo might
+      // think that we're going from not being anonymous to being anonymous and
+      // do some extra work; setting the flag here avoids that.
+      content->SetFlags(NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE);
       container->AppendChildTo(content, false);
       if (content->IsElement()) {
         // If we created any children elements, Servo needs to traverse them, but
         // the root is already set up.
         mPresShell->StyleSet()->StyleNewSubtree(content->AsElement());
       }
     }
   }
--- a/layout/reftests/border-radius/reftest.list
+++ b/layout/reftests/border-radius/reftest.list
@@ -53,17 +53,17 @@ fuzzy-if(/^Windows\x20NT\x206\.2/.test(h
 fuzzy-if(true,1,7) fuzzy-if(d2d,55,95) fuzzy-if(cocoaWidget,1,99) fuzzy-if(Android,99,115) fuzzy-if(skiaContent,1,77) == clipping-5-refc.html clipping-5-ref.html # bug 732535
 fuzzy-if(Android,8,469) fuzzy-if(skiaContent,21,74) fuzzy-if(winWidget,144,335) fuzzy-if(webrender&&cocoaWidget,98-98,279-279) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == clipping-6.html clipping-6-ref.html # PaintedLayer and MaskLayer with transforms that aren't identical, bug 1392106
 fuzzy-if(true,2,29) fuzzy-if(d2d,46,71) fuzzy-if(Android,255,586) fuzzy-if(skiaContent,28,96) == clipping-7.html clipping-7-ref.html # ColorLayer and MaskLayer with transforms that aren't identical. Reference image rendered without using layers (which causes fuzzy failures).
 fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,5) == clipping-and-zindex-1.html clipping-and-zindex-1-ref.html
 fuzzy-if(cocoaWidget,1,4) fuzzy-if(d2d,59,342) fuzzy-if(d3d11&&advancedLayers&&!d2d,30,3) == intersecting-clipping-1-canvas.html intersecting-clipping-1-refc.html
 == intersecting-clipping-1-image.html intersecting-clipping-1-refi.html
 == intersecting-clipping-1-overflow-hidden.html intersecting-clipping-1-ref.html
 fuzzy-if(Android,5,105) fuzzy-if(d2d,1,20) fuzzy-if(skiaContent,1,300) == intersecting-clipping-1-refi.html intersecting-clipping-1-ref.html
-fuzzy-if(true,1,33) fuzzy-if(d2d,59,350) fuzzy-if(cocoaWidget,1,332) fuzzy-if(Android,124,440) fuzzy-if(skiaContent,1,135) fuzzy-if(d3d11&&advancedLayers,81,353) == intersecting-clipping-1-refc.html intersecting-clipping-1-ref.html # bug 732535
+fuzzy-if(true,1,33) fuzzy-if(d2d,59,350) fuzzy-if(cocoaWidget,1,332) fuzzy-if(Android,124,440) fuzzy-if(skiaContent,1,135) fuzzy-if(d3d11&&advancedLayers,81,353) skip-if(winWidget) == intersecting-clipping-1-refc.html intersecting-clipping-1-ref.html # bug 732535 # Disable on Windows bug 1451808
 
 # Inheritance
 == inherit-1.html inherit-1-ref.html # border-radius shouldn't inherit
 
 # Table elements
 == table-collapse-1.html table-collapse-1-ref.html # border-radius is ignored on internal table elements
 # when border-collapse: collapse
 
--- a/media/libcubeb/cubeb-pulse-rs/README_MOZILLA
+++ b/media/libcubeb/cubeb-pulse-rs/README_MOZILLA
@@ -1,8 +1,8 @@
 The source from this directory was copied from the cubeb-pulse-rs
 git repository using the update.sh script.  The only changes
 made were those applied by update.sh and the addition of
 Makefile.in build files for the Mozilla build system.
 
 The cubeb-pulse-rs git repository is: https://github.com/djg/cubeb-pulse-rs.git
 
-The git commit ID used was f90aecf00ed6e5c67f593b3ecf412a8f3ffc0b1f (2018-04-18 08:06:35 +1000)
+The git commit ID used was d0bdf51ebd0a653cc4276d2346db852a3060ade0 (2018-06-29 10:09:52 +1000)
--- a/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/stream.rs
+++ b/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/stream.rs
@@ -318,18 +318,18 @@ impl Stream {
             } else {
                 ffi::PA_ERR_UNKNOWN
             };
             return Err(ErrorCode::from_error_code(err));
         }
         Ok(unsafe { operation::from_raw_ptr(r) })
     }
 
-    pub fn get_time(&self) -> Result<(u64)> {
-        let mut usec: u64 = 0;
+    pub fn get_time(&self) -> Result<(USec)> {
+        let mut usec: USec = 0;
         let r = unsafe { ffi::pa_stream_get_time(self.raw_mut(), &mut usec) };
         error_result!(usec, r)
     }
 
     pub fn get_latency(&self) -> Result<StreamLatency> {
         let mut usec: u64 = 0;
         let mut negative: i32 = 0;
         let r = unsafe { ffi::pa_stream_get_latency(self.raw_mut(), &mut usec, &mut negative) };
--- a/media/libcubeb/cubeb-pulse-rs/src/backend/stream.rs
+++ b/media/libcubeb/cubeb-pulse-rs/src/backend/stream.rs
@@ -433,17 +433,17 @@ impl<'ctx> StreamOps for PulseStream<'ct
 
         if self.output_stream.is_none() {
             return Err(Error::error());
         }
 
         let stm = self.output_stream.as_ref().unwrap();
         let r = match stm.get_time() {
             Ok(r_usec) => {
-                let bytes = r_usec.to_bytes(&self.output_sample_spec);
+                let bytes = USecExt::to_bytes(r_usec, &self.output_sample_spec);
                 Ok((bytes / self.output_sample_spec.frame_size()) as u64)
             }
             Err(_) => Err(Error::error()),
         };
 
         if !in_thread {
             self.context.mainloop.unlock();
         }
--- a/mobile/android/base/Makefile.in
+++ b/mobile/android/base/Makefile.in
@@ -41,20 +41,16 @@ include $(topsrcdir)/config/android-comm
 $(ABS_DIST)/fennec/$(OMNIJAR_NAME): FORCE
 	$(REPORT_BUILD)
 	$(MAKE) -C ../../../faster
 	$(MAKE) -C ../installer stage-package
 	$(MKDIR) -p $(@D)
 	rsync --update $(DIST)/fennec/$(notdir $(OMNIJAR_NAME)) $@
 	$(RM) $(DIST)/fennec/$(notdir $(OMNIJAR_NAME))
 
-.PHONY: features
-features::
-	$(call py_action,generate_builtin_addons,--features=features chrome/chrome/content/built_in_addons.json)
-
 ifndef MOZILLA_OFFICIAL
 # Targets built very early during a Gradle build.  In automation,
 # these are built before Gradle is invoked, and gradle-targets is not
 # made at all.  This is required to avoid building gradle-targets with
 # AB_CD=multi during multi-l10n builds.
 gradle-targets: $(generated_resources) $(generated_files)
 
 # Local developers update omni.ja during their builds.  There's a
--- a/mozglue/build/WindowsDllBlocklistCommon.h
+++ b/mozglue/build/WindowsDllBlocklistCommon.h
@@ -48,25 +48,36 @@ struct DllBlockInfoT {
   // any versioned instance.
   static const uint64_t UNVERSIONED = 0ULL;
 };
 
 } // namespace mozilla
 
 // Convert the 4 (decimal) components of a DLL version number into a
 // single unsigned long long, as needed by the blocklist
+#if defined(_MSC_VER) && !defined(__clang__)
+
+// MSVC does not properly handle the constexpr MAKE_VERSION, so we use a macro
+// instead (ugh).
+#define MAKE_VERSION(a,b,c,d) \
+  ((a##ULL << 48) + (b##ULL << 32) + (c##ULL << 16) + d##ULL)
+
+#else
+
 static inline constexpr uint64_t
 MAKE_VERSION(uint16_t a, uint16_t b, uint16_t c, uint16_t d)
 {
   return static_cast<uint64_t>(a) << 48 |
          static_cast<uint64_t>(b) << 32 |
          static_cast<uint64_t>(c) << 16 |
          static_cast<uint64_t>(d);
 }
 
+#endif
+
 #if !defined(DLL_BLOCKLIST_CHAR_TYPE)
 #error "You must define DLL_BLOCKLIST_CHAR_TYPE"
 #endif // !defined(DLL_BLOCKLIST_CHAR_TYPE)
 
 #define DLL_BLOCKLIST_DEFINITIONS_BEGIN \
   using DllBlockInfo = mozilla::DllBlockInfoT<DLL_BLOCKLIST_CHAR_TYPE>; \
   static const DllBlockInfo gWindowsDllBlocklist[] = {
 
--- a/netwerk/protocol/websocket/WebSocketChannel.cpp
+++ b/netwerk/protocol/websocket/WebSocketChannel.cpp
@@ -54,16 +54,17 @@
 #include "nsAlgorithm.h"
 #include "nsProxyRelease.h"
 #include "nsNetUtil.h"
 #include "nsINode.h"
 #include "mozilla/StaticMutex.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/TimeStamp.h"
 #include "nsSocketTransportService2.h"
+#include "nsINSSErrorsService.h"
 
 #include "plbase64.h"
 #include "prmem.h"
 #include "prnetdb.h"
 #include "zlib.h"
 #include <algorithm>
 
 // rather than slurp up all of nsIWebSocket.idl, which lives outside necko, just
@@ -3812,19 +3813,35 @@ WebSocketChannel::OnStartRequest(nsIRequ
   }
 
   nsresult rv;
   uint32_t status;
   char *val, *token;
 
   rv = mHttpChannel->GetResponseStatus(&status);
   if (NS_FAILED(rv)) {
+    nsresult httpStatus;
+    rv = NS_ERROR_CONNECTION_REFUSED;
+
+    // If we failed to connect due to unsuccessful TLS handshake, we must
+    // propagate a specific error to mozilla::dom::WebSocketImpl so it can set
+    // status code to 1015. Otherwise return NS_ERROR_CONNECTION_REFUSED.
+    if (NS_SUCCEEDED(mHttpChannel->GetStatus(&httpStatus))) {
+      uint32_t errorClass;
+      nsCOMPtr<nsINSSErrorsService> errSvc =
+        do_GetService("@mozilla.org/nss_errors_service;1");
+      // If GetErrorClass succeeds httpStatus is TLS related failure.
+      if (errSvc && NS_SUCCEEDED(errSvc->GetErrorClass(httpStatus, &errorClass))) {
+        rv = NS_ERROR_NET_INADEQUATE_SECURITY;
+      }
+    }
+
     LOG(("WebSocketChannel::OnStartRequest: No HTTP Response\n"));
-    AbortSession(NS_ERROR_CONNECTION_REFUSED);
-    return NS_ERROR_CONNECTION_REFUSED;
+    AbortSession(rv);
+    return rv;
   }
 
   LOG(("WebSocketChannel::OnStartRequest: HTTP status %d\n", status));
   if (status != 101) {
     AbortSession(NS_ERROR_CONNECTION_REFUSED);
     return NS_ERROR_CONNECTION_REFUSED;
   }
 
--- a/python/mozbuild/mozbuild/backend/tup.py
+++ b/python/mozbuild/mozbuild/backend/tup.py
@@ -94,16 +94,17 @@ class BackendTupfile(object):
         self.programs = []
         self.host_programs = []
         self.host_library = None
         self.exports = set()
 
         # These files are special, ignore anything that generates them or
         # depends on them.
         self._skip_files = [
+            'built_in_addons.json',
             'signmar',
         ]
 
         self.fh = FileAvoidWrite(self.name, capture_diff=True, dry_run=dry_run)
         self.fh.write('# THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT EDIT.\n')
         self.fh.write('\n')
 
     def write(self, buf):
--- a/taskcluster/docs/docker-images.rst
+++ b/taskcluster/docs/docker-images.rst
@@ -102,21 +102,19 @@ by specifying the docker image name in t
 referred to by a ``<repo>@<repodigest>`` string:
 
 Example:
 
 .. code-block:: none
 
     image: taskcluster/decision:0.1.10@sha256:c5451ee6c655b3d97d4baa3b0e29a5115f23e0991d4f7f36d2a8f793076d6854
 
-Each image has a repo digest, an image hash, and a version. The repo digest is
-stored in the ``HASH`` file in the image directory  and used to refer to the
-image as above.  The version is in ``VERSION``.  The image hash is used in
-`chain-of-trust verification <https://scriptworker.readthedocs.io/en/latest/chain_of_trust.html>`_
-in `scriptworker <https://github.com/mozilla-releng/scriptworker>`_.
+Each image has a repo digest and a version. The repo digest is stored in the
+``HASH`` file in the image directory and used to refer to the image as above.
+The version is in ``VERSION``.
 
 The version file only serves to provide convenient names, such that old
 versions are easy to discover in the registry (and ensuring old versions aren't
 deleted by garbage-collection).
 
 Each image directory also has a ``REGISTRY``, defaulting to the ``REGISTRY`` in
 the ``taskcluster/docker`` directory, and specifying the image registry to
 which the completed image should be uploaded.
@@ -166,22 +164,17 @@ Docker Registry Images
 
 Landing docker registry images takes a little more care.
 
 Once a new version of the image has been built and tested locally, push it to
 the docker registry and make note of the resulting repo digest.  Put this value
 in the ``HASH`` file, and update any references to the image in the code or
 task definitions.
 
-The change is now safe to use in Try pushes.  However, if the image is used in
-building releases then it is *not* safe to land to an integration branch until
-the whitelists in `scriptworker's constants.py
-<https://github.com/mozilla-releng/scriptworker/blob/master/scriptworker/constants.py>`_
-have also been updated. These whitelists use the image hash, not the repo
-digest.
+The change is now safe to use in Try pushes.
 
 Special Dockerfile Syntax
 -------------------------
 
 Dockerfile syntax has been extended to allow *any* file from the
 source checkout to be added to the image build *context*. (Traditionally
 you can only ``ADD`` files from the same directory as the Dockerfile.)
 
--- a/testing/mozharness/scripts/desktop_unittest.py
+++ b/testing/mozharness/scripts/desktop_unittest.py
@@ -889,27 +889,32 @@ class DesktopUnittest(TestingMixin, Merc
                     final_cmd = copy.copy(cmd)
                     final_cmd.extend(per_test_args)
 
                     if self.per_test_coverage:
                         gcov_dir, jsvm_dir = self.set_coverage_env(env)
                         # Per-test reset/dump is only supported for xpcshell and
                         # Linux for the time being.
                         if not is_baseline_test and suite == 'xpcshell' and self._is_linux():
-                            env['GCOV_RESULTS_DIR'] = gcov_dir = tempfile.mkdtemp()
+                            env['GCOV_RESULTS_DIR'] = tempfile.mkdtemp()
 
                     return_code = self.run_command(final_cmd, cwd=dirs['abs_work_dir'],
                                                    output_timeout=cmd_timeout,
                                                    output_parser=parser,
                                                    env=env)
 
                     if self.per_test_coverage:
                         self.add_per_test_coverage_report(
-                            gcov_dir, jsvm_dir, suite, per_test_args[-1]
+                            env['GCOV_RESULTS_DIR'] if 'GCOV_RESULTS_DIR' in env else gcov_dir,
+                            jsvm_dir,
+                            suite,
+                            per_test_args[-1]
                         )
+                        if 'GCOV_RESULTS_DIR' in env:
+                            shutil.rmtree(gcov_dir)
 
                     # mochitest, reftest, and xpcshell suites do not return
                     # appropriate return codes. Therefore, we must parse the output
                     # to determine what the tbpl_status and worst_log_level must
                     # be. We do this by:
                     # 1) checking to see if our mozharness script ran into any
                     #    errors itself with 'num_errors' <- OutputParser
                     # 2) if num_errors is 0 then we look in the subclassed 'parser'
--- a/testing/xpcshell/head.js
+++ b/testing/xpcshell/head.js
@@ -506,31 +506,19 @@ function _execute_test() {
   _load_files(_TEST_FILE);
 
   // Tack Assert.jsm methods to the current scope.
   this.Assert = Assert;
   for (let func in Assert) {
     this[func] = Assert[func].bind(Assert);
   }
 
-  let perTestCoverageEnabled = false;
-  try {
-    ChromeUtils.import("resource://testing-common/PerTestCoverageUtils.jsm");
-    perTestCoverageEnabled = true;
-  } catch (e) {
-    // If the module doesn't exist, code coverage is disabled.
-    // Otherwise, rethrow the exception.
-    if (e.result != Cr.NS_ERROR_FILE_NOT_FOUND) {
-      throw e;
-    }
-  }
+  const {PerTestCoverageUtils} = ChromeUtils.import("resource://testing-common/PerTestCoverageUtils.jsm", {});
 
-  if (perTestCoverageEnabled) {
-    PerTestCoverageUtils.beforeTest();
-  }
+  PerTestCoverageUtils.beforeTestSync();
 
   try {
     do_test_pending("MAIN run_test");
     // Check if run_test() is defined. If defined, run it.
     // Else, call run_next_test() directly to invoke tests
     // added by add_test() and add_task().
     if (typeof run_test === "function") {
       run_test();
@@ -541,19 +529,17 @@ function _execute_test() {
     do_test_finished("MAIN run_test");
     _do_main();
     _PromiseTestUtils.assertNoUncaughtRejections();
 
     if (coverageCollector != null) {
       coverageCollector.recordTestCoverage(_TEST_FILE[0]);
     }
 
-    if (perTestCoverageEnabled) {
-      PerTestCoverageUtils.afterTest();
-    }
+    PerTestCoverageUtils.afterTestSync();
   } catch (e) {
     _passed = false;
     // do_check failures are already logged and set _quit to true and throw
     // NS_ERROR_ABORT. If both of those are true it is likely this exception
     // has already been logged so there is no need to log it again. It's
     // possible that this will mask an NS_ERROR_ABORT that happens after a
     // do_check failure though.
 
--- a/toolkit/components/downloads/DownloadIntegration.jsm
+++ b/toolkit/components/downloads/DownloadIntegration.jsm
@@ -590,17 +590,17 @@ var DownloadIntegration = {
     // handle multiple extensions.
     let fileExtension = null, mimeInfo = null;
     let match = file.leafName.match(/\.([^.]+)$/);
     if (match) {
       fileExtension = match[1];
     }
 
     let isWindowsExe = AppConstants.platform == "win" &&
-      fileExtension.toLowerCase() == "exe";
+      fileExtension && fileExtension.toLowerCase() == "exe";
 
     // Ask for confirmation if the file is executable, except for .exe on
     // Windows where the operating system will show the prompt based on the
     // security zone.  We do this here, instead of letting the caller handle
     // the prompt separately in the user interface layer, for two reasons.  The
     // first is because of its security nature, so that add-ons cannot forget
     // to do this check.  The second is that the system-level security prompt
     // would be displayed at launch time in any case.
rename from python/mozbuild/mozbuild/action/generate_builtin_addons.py
rename to toolkit/mozapps/extensions/gen_built_in_addons.py
--- a/python/mozbuild/mozbuild/action/generate_builtin_addons.py
+++ b/toolkit/mozapps/extensions/gen_built_in_addons.py
@@ -1,52 +1,94 @@
 # 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/.
 
 from __future__ import absolute_import, print_function, unicode_literals
-from mozbuild.util import ensureParentDir
 
 import argparse
 import json
 import os.path
 import sys
 
 import buildconfig
+import mozpack.path as mozpath
+
+from mozpack.copier import FileRegistry
+from mozpack.manifests import InstallManifest
+
+
+# A list of build manifests, and their relative base paths, from which to
+# extract lists of install files. These vary depending on which backend we're
+# using, so nonexistent manifests are ignored.
+manifest_paths = (
+    ('', '_build_manifests/install/dist_bin'),
+    ('', 'faster/install_dist_bin'),
+    ('browser', 'faster/install_dist_bin_browser'),
+)
 
 
-def main(argv):
+def get_registry(paths):
+    used_paths = set()
+
+    registry = FileRegistry()
+    for base, path in paths:
+        full_path = mozpath.join(buildconfig.topobjdir, path)
+        if not os.path.exists(full_path):
+            continue
+
+        used_paths.add(full_path)
+
+        reg = FileRegistry()
+        InstallManifest(full_path).populate_registry(reg)
+
+        for p, f in reg:
+            path = mozpath.join(base, p)
+            if not registry.contains(path):
+                registry.add(path, f)
+
+    return registry, used_paths
+
+
+def get_child(base, path):
+    """Returns the nearest parent of `path` which is an immediate child of
+    `base`"""
+
+    dirname = mozpath.dirname(path)
+    while dirname != base:
+        path = dirname
+        dirname = mozpath.dirname(path)
+    return path
+
+
+def main(output, *args):
     parser = argparse.ArgumentParser(
         description='Produces a JSON manifest of built-in add-ons')
     parser.add_argument('--features', type=str, dest='featuresdir',
                         action='store', help=('The distribution sub-directory '
                                               'containing feature add-ons'))
-    parser.add_argument('outputfile', help='File to write output to')
-    args = parser.parse_args(argv)
+    args = parser.parse_args(args)
 
-    bindir = os.path.join(buildconfig.topobjdir, 'dist/bin')
+    registry, inputs = get_registry(manifest_paths)
 
-    def find_dictionaries(path):
-        dicts = {}
-        for filename in os.listdir(os.path.join(bindir, path)):
-            base, ext = os.path.splitext(filename)
-            if ext == '.dic':
-                dicts[base] = '%s/%s' % (path, filename)
-        return dicts
+    dicts = {}
+    for path in registry.match('dictionaries/*.dic'):
+        base, ext = os.path.splitext(mozpath.basename(path))
+        dicts[base] = path
 
     listing = {
-        "dictionaries": find_dictionaries("dictionaries"),
+        "dictionaries": dicts,
     }
+
     if args.featuresdir:
-        listing["system"] = sorted(os.listdir(os.path.join(bindir,
-                                                           args.featuresdir)))
-        if len(listing["system"]) == 0:
-            raise IOError("featuresdir is empty, we lost a race")
+        features = set()
+        for p in registry.match('%s/*' % args.featuresdir):
+            features.add(mozpath.basename(get_child(args.featuresdir, p)))
 
-    outputfilepath = os.path.join(bindir, args.outputfile)
-    ensureParentDir(outputfilepath)
+        listing["system"] = sorted(features)
 
-    with open(outputfilepath, 'w') as fh:
-        json.dump(listing, fh, sort_keys=True)
+    json.dump(listing, output)
+
+    return inputs
 
 
 if __name__ == '__main__':
-    sys.exit(main(sys.argv[1:]))
+    main(sys.stdout, *sys.argv[1:])
--- a/toolkit/mozapps/extensions/moz.build
+++ b/toolkit/mozapps/extensions/moz.build
@@ -20,16 +20,34 @@ TEST_DIRS += ['test']
 
 XPIDL_SOURCES += [
     'amIAddonManagerStartup.idl',
     'amIWebInstallPrompt.idl',
 ]
 
 XPIDL_MODULE = 'extensions'
 
+built_in_addons = 'built_in_addons.json'
+GENERATED_FILES += [built_in_addons]
+manifest = GENERATED_FILES[built_in_addons]
+manifest.script = 'gen_built_in_addons.py'
+
+if CONFIG['MOZ_BUILD_APP'] == 'browser':
+    manifest.flags = ['--features=browser/features']
+
+    FINAL_TARGET_FILES.browser.chrome.browser.content.browser += [
+        '!%s' % built_in_addons,
+    ]
+elif CONFIG['MOZ_BUILD_APP'] == 'mobile/android':
+    manifest.flags = ['--features=features']
+
+    FINAL_TARGET_FILES.chrome.chrome.content += [
+        '!%s' % built_in_addons,
+    ]
+
 EXTRA_COMPONENTS += [
     'addonManager.js',
     'amContentHandler.js',
     'amInstallTrigger.js',
     'amWebAPI.js',
 ]
 
 EXTRA_PP_COMPONENTS += [
--- a/tools/code-coverage/PerTestCoverageUtils.jsm
+++ b/tools/code-coverage/PerTestCoverageUtils.jsm
@@ -5,60 +5,71 @@
 /* exported PerTestCoverageUtils */
 
 "use strict";
 
 var EXPORTED_SYMBOLS = ["PerTestCoverageUtils"];
 
 ChromeUtils.defineModuleGetter(this, "Services", "resource://gre/modules/Services.jsm");
 
-class PerTestCoverageUtilsClass {
-  constructor(tmp_gcov_dir, gcov_dir) {
-    this.tmp_gcov_dir = tmp_gcov_dir;
-    this.gcov_dir = gcov_dir;
+const env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment);
+// This is the directory where gcov is emitting the gcda files.
+const tmp_gcov_dir = env.get("GCOV_PREFIX");
+// This is the directory where codecoverage.py is expecting to see the gcda files.
+const gcov_dir = env.get("GCOV_RESULTS_DIR");
+
+const enabled = !!gcov_dir;
 
-    this.codeCoverageService = Cc["@mozilla.org/tools/code-coverage;1"].getService(Ci.nsICodeCoverage);
+function awaitPromise(promise) {
+  let ret;
+  let complete = false;
+  let error = null;
+  promise.catch(e => error = e).then(v => {
+    ret = v;
+    complete = true;
+  });
+  Services.tm.spinEventLoopUntil(() => complete);
+  if (error) {
+    throw new Error(error);
+  }
+  return ret;
+}
+
+var PerTestCoverageUtils = class PerTestCoverageUtilsClass {
+  // Resets the counters to 0.
+  static async beforeTest() {
+    if (!enabled) {
+      return;
+    }
+
+    let codeCoverageService = Cc["@mozilla.org/tools/code-coverage;1"].getService(Ci.nsICodeCoverage);
+    await codeCoverageService.resetCounters();
   }
 
-  _awaitPromise(promise) {
-    let ret;
-    let complete = false;
-    let error = null;
-    promise.catch(e => error = e).then(v => {
-      ret = v;
-      complete = true;
-    });
-    Services.tm.spinEventLoopUntil(() => complete);
-    if (error) {
-      throw new Error(error);
-    }
-    return ret;
-  }
-
-  // Resets the counters to 0.
-  beforeTest() {
-    this._awaitPromise(this.codeCoverageService.resetCounters());
+  static beforeTestSync() {
+    awaitPromise(this.beforeTest());
   }
 
   // Dumps counters and moves the gcda files in the directory expected by codecoverage.py.
-  afterTest() {
-    this._awaitPromise(this.codeCoverageService.dumpCounters());
+  static async afterTest() {
+    if (!enabled) {
+      return;
+    }
+
+    let codeCoverageService = Cc["@mozilla.org/tools/code-coverage;1"].getService(Ci.nsICodeCoverage);
+    await codeCoverageService.dumpCounters();
 
     let srcDir = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
-    srcDir.initWithPath(this.tmp_gcov_dir);
+    srcDir.initWithPath(tmp_gcov_dir);
 
     let destDir = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
-    destDir.initWithPath(this.gcov_dir);
+    destDir.initWithPath(gcov_dir);
 
     let srcDirEntries = srcDir.directoryEntries;
     while (srcDirEntries.hasMoreElements()) {
       srcDirEntries.nextFile.moveTo(destDir, null);
     }
   }
-}
 
-const env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment);
-// This is the directory where gcov is emitting the gcda files.
-const tmp_gcov_dir = env.get("GCOV_PREFIX");
-// This is the directory where codecoverage.py is expecting to see the gcda files.
-const gcov_dir = env.get("GCOV_RESULTS_DIR");
-
-const PerTestCoverageUtils = gcov_dir ? new PerTestCoverageUtilsClass(tmp_gcov_dir, gcov_dir) : null;
+  static afterTestSync() {
+    awaitPromise(this.afterTest());
+  }
+};
--- a/tools/code-coverage/moz.build
+++ b/tools/code-coverage/moz.build
@@ -1,14 +1,16 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
+TESTING_JS_MODULES += ['PerTestCoverageUtils.jsm']
+
 if CONFIG['MOZ_CODE_COVERAGE']:
     XPIDL_MODULE = 'code-coverage'
 
     XPIDL_SOURCES += [
         'nsICodeCoverage.idl',
     ]
 
     SOURCES += [
@@ -26,11 +28,9 @@ if CONFIG['MOZ_CODE_COVERAGE']:
         '/xpcom/base',
     ]
 
     include('/ipc/chromium/chromium-config.mozbuild')
 
     XPCSHELL_TESTS_MANIFESTS += ['tests/xpcshell/xpcshell.ini']
     MOCHITEST_MANIFESTS += ['tests/mochitest/mochitest.ini']
 
-    TESTING_JS_MODULES += ['PerTestCoverageUtils.jsm']
-
     FINAL_LIBRARY = 'xul'
--- a/tools/code-coverage/tests/xpcshell/test_basic.js
+++ b/tools/code-coverage/tests/xpcshell/test_basic.js
@@ -1,17 +1,21 @@
 /* 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/. */
 
-function run_test() {
+async function run_test() {
+  do_test_pending();
+
   Assert.ok("@mozilla.org/tools/code-coverage;1" in Cc);
 
   let codeCoverageCc = Cc["@mozilla.org/tools/code-coverage;1"];
   Assert.ok(!!codeCoverageCc);
 
   let codeCoverage = codeCoverageCc.getService(Ci.nsICodeCoverage);
   Assert.ok(!!codeCoverage);
 
-  codeCoverage.dumpCounters();
+  await codeCoverage.dumpCounters();
 
-  codeCoverage.resetCounters();
+  await codeCoverage.resetCounters();
+
+  do_test_finished();
 }
--- a/tools/code-coverage/tests/xpcshell/test_basic_child_and_parent.js
+++ b/tools/code-coverage/tests/xpcshell/test_basic_child_and_parent.js
@@ -1,17 +1,17 @@
 /* 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/. */
 
 function run_test() {
   do_load_child_test_harness();
   do_test_pending();
 
-  sendCommand("let v = 'test';", function() {
+  sendCommand("let v = 'test';", async function() {
       let codeCoverage = Cc["@mozilla.org/tools/code-coverage;1"].getService(Ci.nsICodeCoverage);
 
-      codeCoverage.dumpCounters();
-      codeCoverage.resetCounters();
+      await codeCoverage.dumpCounters();
+      await codeCoverage.resetCounters();
 
       do_test_finished();
   });
 }
--- a/widget/cocoa/nsCocoaFeatures.h
+++ b/widget/cocoa/nsCocoaFeatures.h
@@ -15,19 +15,20 @@
 class nsCocoaFeatures {
 public:
   static int32_t OSXVersion();
   static int32_t OSXVersionMajor();
   static int32_t OSXVersionMinor();
   static int32_t OSXVersionBugFix();
   static bool OnYosemiteOrLater();
   static bool OnElCapitanOrLater();
+  static bool OnSierraExactly();
   static bool OnSierraOrLater();
   static bool OnHighSierraOrLater();
-  static bool OnSierraExactly();
+  static bool OnMojaveOrLater();
 
   static bool IsAtLeastVersion(int32_t aMajor, int32_t aMinor, int32_t aBugFix=0);
 
   // These are utilities that do not change or depend on the value of mOSXVersion
   // and instead just encapsulate the encoding algorithm.  Note that GetVersion
   // actually adjusts to the lowest supported OS, so it will always return
   // a "supported" version.  GetSystemVersion does not make any modifications.
   static void GetSystemVersion(int &aMajor, int &aMinor, int &aBugFix);
--- a/widget/cocoa/nsCocoaFeatures.mm
+++ b/widget/cocoa/nsCocoaFeatures.mm
@@ -15,16 +15,17 @@
 #define MAC_OS_X_VERSION_10_0_HEX  0x00001000
 #define MAC_OS_X_VERSION_10_7_HEX  0x00001070
 #define MAC_OS_X_VERSION_10_8_HEX  0x00001080
 #define MAC_OS_X_VERSION_10_9_HEX  0x00001090
 #define MAC_OS_X_VERSION_10_10_HEX 0x000010A0
 #define MAC_OS_X_VERSION_10_11_HEX 0x000010B0
 #define MAC_OS_X_VERSION_10_12_HEX 0x000010C0
 #define MAC_OS_X_VERSION_10_13_HEX 0x000010D0
+#define MAC_OS_X_VERSION_10_14_HEX 0x000010E0
 
 #include "nsCocoaFeatures.h"
 #include "nsCocoaUtils.h"
 #include "nsDebug.h"
 #include "nsObjCExceptions.h"
 
 #import <Cocoa/Cocoa.h>
 
@@ -158,44 +159,50 @@ nsCocoaFeatures::OnYosemiteOrLater()
 
 /* static */ bool
 nsCocoaFeatures::OnElCapitanOrLater()
 {
     return (OSXVersion() >= MAC_OS_X_VERSION_10_11_HEX);
 }
 
 /* static */ bool
-nsCocoaFeatures::OnSierraOrLater()
-{
-    return (OSXVersion() >= MAC_OS_X_VERSION_10_12_HEX);
-}
-
-/* static */ bool
-nsCocoaFeatures::OnHighSierraOrLater()
-{
-    return (OSXVersion() >= MAC_OS_X_VERSION_10_13_HEX);
-}
-
-/* static */ bool
 nsCocoaFeatures::OnSierraExactly()
 {
     return (OSXVersion() >= MAC_OS_X_VERSION_10_12_HEX) &&
            (OSXVersion() < MAC_OS_X_VERSION_10_13_HEX);
 }
 
 /* Version of OnSierraExactly as global function callable from cairo & skia */
 bool
 Gecko_OnSierraExactly()
 {
     return nsCocoaFeatures::OnSierraExactly();
 }
 
+/* static */ bool
+nsCocoaFeatures::OnSierraOrLater()
+{
+    return (OSXVersion() >= MAC_OS_X_VERSION_10_12_HEX);
+}
+
+/* static */ bool
+nsCocoaFeatures::OnHighSierraOrLater()
+{
+    return (OSXVersion() >= MAC_OS_X_VERSION_10_13_HEX);
+}
+
 bool
 Gecko_OnHighSierraOrLater()
 {
     return nsCocoaFeatures::OnHighSierraOrLater();
 }
 
 /* static */ bool
+nsCocoaFeatures::OnMojaveOrLater()
+{
+    return (OSXVersion() >= MAC_OS_X_VERSION_10_14_HEX);
+}
+
+/* static */ bool
 nsCocoaFeatures::IsAtLeastVersion(int32_t aMajor, int32_t aMinor, int32_t aBugFix)
 {
     return OSXVersion() >= GetVersion(aMajor, aMinor, aBugFix);
 }
--- a/widget/cocoa/nsLookAndFeel.mm
+++ b/widget/cocoa/nsLookAndFeel.mm
@@ -589,20 +589,23 @@ bool nsLookAndFeel::SystemWantsOverlaySc
 
 bool nsLookAndFeel::AllowOverlayScrollbarsOverlap()
 {
   return (UseOverlayScrollbars());
 }
 
 bool nsLookAndFeel::SystemWantsDarkTheme()
 {
-  // This returns true if the macOS system appearance is set to dark mode, false
-  // otherwise.
-  return !![[NSUserDefaults standardUserDefaults]
-             stringForKey:@"AppleInterfaceStyle"];
+  // This returns true if the macOS system appearance is set to dark mode on
+  // 10.14+, false otherwise.
+  if (nsCocoaFeatures::OnMojaveOrLater()) {
+    return !![[NSUserDefaults standardUserDefaults]
+               stringForKey:@"AppleInterfaceStyle"];
+  }
+  return false;
 }
 
 bool
 nsLookAndFeel::GetFontImpl(FontID aID, nsString &aFontName,
                            gfxFontStyle &aFontStyle,
                            float aDevPixPerCSSPixel)
 {
     NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;