Merge inbound to mozilla-central. a=merge
authorarthur.iakab <aiakab@mozilla.com>
Tue, 27 Feb 2018 11:58:55 +0200
changeset 405495 bd6e200b5a6b
parent 405462 c4425fcdfb5b (current diff)
parent 405494 691c61d4dc61 (diff)
child 405496 b184be598740
child 405521 eb170a9cf68c
child 405547 b9dc720c70b8
push id33520
push useraiakab@mozilla.com
push dateTue, 27 Feb 2018 09:59:32 +0000
treeherdermozilla-central@bd6e200b5a6b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone60.0a1
first release with
nightly linux32
bd6e200b5a6b / 60.0a1 / 20180227100126 / files
nightly linux64
bd6e200b5a6b / 60.0a1 / 20180227100126 / files
nightly mac
bd6e200b5a6b / 60.0a1 / 20180227100126 / files
nightly win32
bd6e200b5a6b / 60.0a1 / 20180227100126 / files
nightly win64
bd6e200b5a6b / 60.0a1 / 20180227100126 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to mozilla-central. a=merge
build/Makefile.in
config/makefiles/test/Makefile.in
config/makefiles/test/check-arglist.mk
config/makefiles/test/check-autotargets.mk
config/makefiles/test/check_XinY.mk
config/makefiles/test/moz.build
devtools/client/debugger/new/test/mochitest/browser_dbg-babel.js
mobile/android/geckoview/build.gradle
modules/libpref/init/all.js
new file mode 100644
--- /dev/null
+++ b/browser/config/mozconfigs/linux64/stylo-only
@@ -0,0 +1,3 @@
+. "$topsrcdir/browser/config/mozconfigs/linux64/nightly"
+
+ac_add_options --enable-stylo=only
new file mode 100644
--- /dev/null
+++ b/browser/config/mozconfigs/linux64/stylo-only-debug
@@ -0,0 +1,3 @@
+. "$topsrcdir/browser/config/mozconfigs/linux64/debug"
+
+ac_add_options --enable-stylo=only
deleted file mode 100644
--- a/build/Makefile.in
+++ /dev/null
@@ -1,20 +0,0 @@
-#
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-ifdef MOZTTDIR
-# Install the Firefox OS fonts.
-include $(MOZTTDIR)/fonts.mk
-MOZTT_DEST = $(FINAL_TARGET)/fonts
-MOZTT_FILES = $(patsubst external/moztt/%,$(MOZTTDIR)/%,$(filter external/moztt/%,$(subst :, ,$(PRODUCT_COPY_FILES))))
-INSTALL_TARGETS += MOZTT
-endif
-
-include $(topsrcdir)/config/rules.mk
-
-TARGET_DEPTH = ..
-include $(srcdir)/automation-build.mk
-
-libs:: automation.py
-
deleted file mode 100644
--- a/config/makefiles/test/Makefile.in
+++ /dev/null
@@ -1,98 +0,0 @@
-# -*- makefile -*-
-#
-# 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/.
-
-STANDALONE_MAKEFILE := 1
-USE_AUTOTARGETS_MK  = 1
-MAKEUTILS_UNIT_TEST = 1
-include $(topsrcdir)/config/makefiles/makeutils.mk
-
-dir-ts = .deps/test
-check-arglist        = $(dir-ts)/arglist.ts
-check-autotargets    = $(dir-ts)/autotargets_mk.ts
-check-XinY           = $(dir-ts)/check_XinY_mk.ts
-check-tests =\
-  $(check-arglist) \
-  $(check-autotargets) \
-  $(check-XinY) \
-  $(NULL)
-
-
-##------------------_##
-##---]  TARGETS  [---##
-##------------------_##
-all::
-
-clean:
-	$(RM) $(check-tests)
-
-###########################################################################
-## Logic processed at compile time so be selective about when to test
-## $(MAKE) check VERBOSE=1
-ifneq ($(NULL),$(findstring check,$(MAKECMDGOALS))) #
-
-check-preqs =\
-  $(call mkdir_deps,$(dir-ts)) \
-  $(check-tests) \
-  $(NULL)
-
-check:: $(check-preqs)
-	@true
-
-
-ifdef VERBOSE #{ gmake check VERBOSE=1
-  $(info ===========================================================================)
-  $(info Running test: $(MAKECMDGOALS): pwd=$(CURDIR))
-  $(info ===========================================================================)
-endif #}
-
-ifndef requiredfunction
-  $(error requiredfunction is not defined)
-endif
-
-
-##################
-check-XinY-preqs=\
-  $(call mkdir_deps,$(dir-ts)) \
-  $(topsrcdir)/config/makefiles/makeutils.mk \
-  $(srcdir)/check_XinY.mk \
-  $(eval include $(srcdir)/check_XinY.mk) \
-  $(NULL)
-
-$(check-XinY): $(check-XinY-preqs)
-	@$(TOUCH) $@
-# </check-XinY.mk>
-
-
-###########################################################################
-## check-arglist.mk always invoked as a compile time test
-## maintain real file dependencies for use later on.
-check-arglist-preqs=\
-  $(call mkdir_deps,$(dir-ts)) \
-  $(topsrcdir)/config/makefiles/makeutils.mk \
-  $(srcdir)/check-arglist.mk \
-  $(eval include $(srcdir)/check-arglist.mk) \
-  $(NULL)
-
-$(check-arglist): $(check-arglist-preqs)
-	@$(TOUCH) $@
-# </check-arglist.mk>
-
-
-###########################################################################
-# <CHECK: autotargets.mk>
-check-autotargets-preqs=\
-  $(call mkdir_deps,$(dir-ts)) \
-  $(topsrcdir)/config/makefiles/makeutils.mk \
-  $(topsrcdir)/config/makefiles/autotargets.mk \
-  $(srcdir)/check-autotargets.mk \
-  $(eval include $(srcdir)/check-autotargets.mk) \
-  $(NULL)
-
-$(check-autotargets): $(check-autotargets-preqs)
-	@$(TOUCH) $@
-# </CHECK: autotargets.mk>
-
-endif #} findstring MAKECMDGOAL
deleted file mode 100644
--- a/config/makefiles/test/check-arglist.mk
+++ /dev/null
@@ -1,100 +0,0 @@
-# -*- makefile -*-
-#
-# 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/.
-
-ifdef VERBOSE
-  $(warning loading test)
-endif
-
-
-$(call requiredfunction,getargv)
-$(call requiredfunction,subargv)
-$(call requiredfunction,istype isval isvar)
-
-# arg_scalar = [scalar|literal]
-arg_list = foo bar
-arg_ref  = arg_list
-
-## Identify type of function argument(s)
-########################################
-ifneq (scalar,$(call istype,arg_scalar))
-  $(error istype(arg_scalar)=scalar, found [$(call istype,arg_scalar)])
-endif
-ifneq (list,$(call istype,arg_list))
-  $(error istype(arg_list)=list, found [$(call istype,arg_list)])
-endif
-ifneq (list,$(call istype,arg_ref))
-  $(error istype(arg_ref)=list, found [$(call istype,arg_ref)])
-endif
-
-## Type == scalar or a list of values
-#####################################
-ifneq (true,$(call isval,scalar))
-  $(error isval(scalar)=true, found [$(call isval,scalar)])
-endif
-ifneq ($(NULL),$(call isval,arg_list))
-  $(error isval(arg_list)=null, found [$(call isval,arg_list)])
-endif
-
-## type == reference: macro=>macro => $($(1))
-#############################################
-ifneq ($(NULL),$(call isvar,scalar))
-  $(error isvar(scalar)=$(NULL), found [$(call isvar,scalar)])
-endif
-ifneq (true,$(call isvar,arg_list))
-  $(error isvar(arg_list)=true, found [$(call isvar,arg_list)])
-endif
-ifneq (true,$(call isvar,arg_ref))
-  $(error isvar(arg_ref)=true, found [$(call isvar,arg_ref)])
-endif
-
-# Verify getargv expansion
-##########################
-ifneq (scalar,$(call getargv,scalar))
-  $(error getargv(scalar)=scalar, found [$(call getargv,scalar)])
-endif
-ifneq ($(arg_list),$(call getargv,arg_list))
-  $(error getargv(arg_list)=list, found [$(call getargv,arg_list)])
-endif
-ifneq (arg_list,$(call getargv,arg_ref))
-  $(error getargv(arg_ref)=list, found [$(call getargv,arg_ref)])
-endif
-
-###########################################################################
-##
-###########################################################################
-ifdef MANUAL_TEST #{
-  # For automated testing a callback is needed that can set an external status
-  # variable that can be tested.  Syntax is tricky to get correct functionality.
-  ifdef VERBOSE
-    $(info )
-    $(info ===========================================================================)
-    $(info Running test: checkIfEmpty)
-    $(info ===========================================================================)
-  endif
-
-  #status =
-  #setTRUE =status=true
-  #setFALSE =status=$(NULL)
-  #$(call checkIfEmpty,setFALSE NULL)
-  #$(if $(status),$(error checkIfEmpty(xyz) failed))
-  #$(call checkIfEmpty,setTRUE xyz)
-  #$(if $(status),$(error checkIfEmpty(xyz) failed))
-  xyz=abc
-  $(info STATUS: warnIfEmpty - two vars)
-  $(call warnIfEmpty,foo xyz bar)
-  $(info STATUS: errorIfEmpty - on first var)
-  $(call errorIfEmpty,foo xyz bar)
-  $(error TEST FAILED: processing should not reach this point)
-endif #}
-
-# Verify subargv expansion
-##########################
-subargs=foo bar tans fans
-subargs_exp=tans fans
-subargs_found=$(call subargv,4,$(subargs))
-ifneq ($(subargs_exp),$(subargs_found))
-  $(error subargv(4,$(subargs)): expected [$(subargs_exp)] found [$(subargs_found)])
-endif
deleted file mode 100644
--- a/config/makefiles/test/check-autotargets.mk
+++ /dev/null
@@ -1,84 +0,0 @@
-# -*- makefile -*-
-#
-# 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/.
-
-ifdef VERBOSE
-  $(warning loading test)
-endif
-
-space=$(null) $(null)
-GENERATED_DIRS = bogus # test data
-
-undefine USE_AUTOTARGETS_MK
-undefine INCLUDED_AUTOTARGETS_MK
-include $(topsrcdir)/config/makefiles/autotargets.mk
-
-ifndef INCLUDED_AUTOTARGETS_MK
-  $(error autotargets.mk was not included
-endif
-
-$(call requiredfunction,mkdir_deps)
-
-
-# Verify test data populated makefile vars correctly
-vars = AUTO_DEPS GARBAGE_DIRS GENERATED_DIRS_DEPS
-$(foreach var,$(vars),$(call errorIfEmpty,$(var)))
-
-# Data should also be valid
-ifneq (bogus,$(findstring bogus,$(AUTO_DEPS)))
-  $(error AUTO_DEPS=[$(AUTO_DEPS)] is not set correctly)
-endif
-
-
-# relpath
-path  := foo/bar.c
-exp   := foo/.mkdir.done
-found := $(call mkdir_deps,$(dir $(path)))
-ifneq ($(exp),$(found))
-  $(error mkdir_deps($(path))=$(exp) not set correctly [$(found)])
-endif
-
-# abspath
-path  := /foo//bar/
-exp   := /foo/bar/.mkdir.done
-found := $(call mkdir_deps,$(path))
-ifneq ($(exp),$(found))
-  $(error mkdir_deps($(path))=$(exp) not set correctly [$(found)])
-endif
-
-
-## verify strip_slash
-#####################
-
-path  := a/b//c///d////e/////
-exp   := a/b/c/d/e/.mkdir.done
-found := $(call mkdir_deps,$(path))
-ifneq ($(exp),$(found))
-  $(error mkdir_deps($(path))=$(exp) not set correctly [$(found)])
-endif
-
-
-## verify mkdir_stem()
-######################
-path  := verify/mkdir_stem
-pathD = $(call mkdir_deps,$(path))
-pathS = $(call mkdir_stem,$(pathD))
-exp   := $(path)
-
-ifeq ($(pathD),$(pathS))
-  $(error mkdir_deps and mkdir_stem should not match [$(pathD)])
-endif
-ifneq ($(pathS),$(exp))
-  $(error mkdir_stem=[$(pathS)] != exp=[$(exp)])
-endif
-
-
-## Verify embedded whitespace has been protected
-path  := a/b$(space)c//d
-exp   := a/b$(space)c/d
-found := $(call slash_strip,$(path))
-ifneq ($(exp),$(found))
-  $(error slash_strip($(path))=$(exp) not set correctly [$(found)])
-endif
deleted file mode 100644
--- a/config/makefiles/test/check_XinY.mk
+++ /dev/null
@@ -1,70 +0,0 @@
-# -*- makefile -*-
-#
-# 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/.
-
-# Verify dependencies are available
-$(call requiredfunction,getargv subargv is_XinY errorifneq)
-
-ifdef VERBOSE
-  $(warning loading test)
-endif
-
-zero := 0
-one  := 1
-
-# Verify 'invalid' is not matched
-val  := invalid
-$(call errorifneq,$(zero),$(words $(call is_XinY,foo,$(val))))
-$(call errorifneq,$(zero),$(words $(call is_XinY,clean,$(val))))
-$(call errorifneq,$(zero),$(words $(call is_XinY,clean%,$(val))))
-
-# verify strcmp('clean')
-val  := clean
-$(call errorifneq,$(zero),$(words $(call is_XinY,foo,$(val))))
-$(call errorifneq,$(one),$(words $(call is_XinY,clean,$(val))))
-$(call errorifneq,$(one),$(words $(call is_XinY,clean%,$(val))))
-$(call errorifneq,$(one),$(words $(call is_XinY,%clean,$(val))))
-
-# List match for 'clean'
-val     := blah clean distclean FcleanG clean-level-1
-wanted  := clean distclean clean-level-1
-$(call errorifneq,$(zero),$(words $(call is_XinY_debug,foo,$(val))))
-$(call errorifneq,$(one),$(words $(call is_XinY,clean,$(val))))
-$(call errorifneq,$(one),$(words $(call is_XinY,distclean,$(val))))
-
-# pattern match 'clean'
-#     match: clean, distclean, clean-level-1
-#   exclude: FcleanG
-TEST_MAKECMDGOALS := $(val)
-$(call errorifneq,3,$(words $(call isTargetStemClean)))
-
-TEST_MAKECMDGOALS := invalid
-$(call errorifneq,$(zero),$(words $(call isTargetStemClean)))
-
-
-#############################
-ifdef VERBOSE
-  $(call banner,Unit test: isTargetStem)
-endif
-
-# Verify list argument processing
-TEST_MAKECMDGOALS := echo
-$(call errorifneq,$(one),$(words $(call isTargetStem,echo,show)))
-
-TEST_MAKECMDGOALS := echo-123
-$(call errorifneq,$(one),$(words $(call isTargetStem,echo,show)))
-
-TEST_MAKECMDGOALS := show
-$(call errorifneq,$(one),$(words $(call isTargetStem,echo,show)))
-
-TEST_MAKECMDGOALS := show-123
-$(call errorifneq,$(one),$(words $(call isTargetStem,echo,show)))
-
-TEST_MAKECMDGOALS := show-123-echo
-$(call errorifneq,$(one),$(words $(call isTargetStem,echo,show)))
-
-TEST_MAKECMDGOALS := invalid
-$(call errorifneq,$(zero),$(words $(call isTargetStem,echo,show)))
-
deleted file mode 100644
--- a/config/makefiles/test/moz.build
+++ /dev/null
@@ -1,6 +0,0 @@
-# -*- 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/.
-
--- a/config/moz.build
+++ b/config/moz.build
@@ -11,17 +11,16 @@ with Files('mozunit.py'):
     BUG_COMPONENT = ('Testing', 'Python Test')
 
 DIST_INSTALL = False
 # For sanity's sake, we compile nsinstall without the wrapped system
 # headers, so that we can use it to set up the wrapped system headers.
 NoVisibilityFlags()
 
 CONFIGURE_SUBST_FILES += [
-    'makefiles/test/Makefile',
     'tests/src-simple/Makefile',
 ]
 
 if CONFIG['HOST_OS_ARCH'] != 'WINNT':
     HOST_SOURCES += [
         'nsinstall.c',
         'pathsub.c',
     ]
--- a/devtools/client/debugger/new/README.mozilla
+++ b/devtools/client/debugger/new/README.mozilla
@@ -1,12 +1,12 @@
 This is the debugger.html project output.
 See https://github.com/devtools-html/debugger.html
 
-Version 18.0
-Comparison: https://github.com/devtools-html/debugger.html/compare/release-17...release-18
+Version 19.0
+Comparison: https://github.com/devtools-html/debugger.html/compare/release-18...release-19
 
 Packages:
 - babel-plugin-transform-es2015-modules-commonjs @6.26.0
 - babel-preset-react @6.24.1
 - react @15.6.2
 - react-dom @15.6.2
 - webpack @3.10.0
--- a/devtools/client/debugger/new/debugger.css
+++ b/devtools/client/debugger/new/debugger.css
@@ -1923,16 +1923,19 @@ html .toggle-button.end.vertical svg {
 
 .source-footer .blackbox-summary {
   color: var(--theme-body-color);
 }
 
 .source-footer .mapped-source {
   color: var(--theme-body-color);
   padding: 2.5px;
+  white-space: nowrap;
+  overflow: hidden;
+  text-overflow: ellipsis;
 }
 /* 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/>. */
 
 .search-bar {
   display: flex;
   flex-direction: column;
--- a/devtools/client/debugger/new/debugger.js
+++ b/devtools/client/debugger/new/debugger.js
@@ -10097,17 +10097,17 @@ const prefs = new PrefsHelper("devtools"
   tabs: ["Json", "debugger.tabs", []],
   pendingSelectedLocation: ["Json", "debugger.pending-selected-location", {}],
   pendingBreakpoints: ["Json", "debugger.pending-breakpoints", {}],
   expressions: ["Json", "debugger.expressions", []],
   fileSearchCaseSensitive: ["Bool", "debugger.file-search-case-sensitive"],
   fileSearchWholeWord: ["Bool", "debugger.file-search-whole-word"],
   fileSearchRegexMatch: ["Bool", "debugger.file-search-regex-match"],
   debuggerPrefsSchemaVersion: ["Char", "debugger.prefs-schema-version"],
-  projectDirectoryRoot: ["Char", "project-directory-root", ""]
+  projectDirectoryRoot: ["Char", "debugger.project-directory-root", ""]
 });
 /* harmony export (immutable) */ __webpack_exports__["prefs"] = prefs;
 
 
 const features = new PrefsHelper("devtools.debugger.features", {
   asyncStepping: ["Bool", "async-stepping"],
   wasm: ["Bool", "wasm"],
   shortcuts: ["Bool", "shortcuts"],
@@ -17916,17 +17916,17 @@ function createPendingBreakpoint(bp) {
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
-exports.replaceOriginalVariableName = exports.getFramework = exports.hasSyntaxError = exports.clearSources = exports.setSource = exports.hasSource = exports.getEmptyLines = exports.getNextStep = exports.clearASTs = exports.clearScopes = exports.clearSymbols = exports.findOutOfScopeLocations = exports.getVariablesInScope = exports.getScopes = exports.getSymbols = exports.getClosestExpression = exports.stopParserWorker = exports.startParserWorker = undefined;
+exports.replaceOriginalVariableName = exports.getFramework = exports.hasSyntaxError = exports.clearSources = exports.setSource = exports.hasSource = exports.getEmptyLines = exports.isInvalidPauseLocation = exports.getNextStep = exports.clearASTs = exports.clearScopes = exports.clearSymbols = exports.findOutOfScopeLocations = exports.getVariablesInScope = exports.getScopes = exports.getSymbols = exports.getClosestExpression = exports.stopParserWorker = exports.startParserWorker = undefined;
 
 var _devtoolsUtils = __webpack_require__(1363);
 
 const { WorkerDispatcher } = _devtoolsUtils.workerUtils; /* 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/>. */
 
 const dispatcher = new WorkerDispatcher();
@@ -17937,16 +17937,17 @@ const getClosestExpression = exports.get
 const getSymbols = exports.getSymbols = dispatcher.task("getSymbols");
 const getScopes = exports.getScopes = dispatcher.task("getScopes");
 const getVariablesInScope = exports.getVariablesInScope = dispatcher.task("getVariablesInScope");
 const findOutOfScopeLocations = exports.findOutOfScopeLocations = dispatcher.task("findOutOfScopeLocations");
 const clearSymbols = exports.clearSymbols = dispatcher.task("clearSymbols");
 const clearScopes = exports.clearScopes = dispatcher.task("clearScopes");
 const clearASTs = exports.clearASTs = dispatcher.task("clearASTs");
 const getNextStep = exports.getNextStep = dispatcher.task("getNextStep");
+const isInvalidPauseLocation = exports.isInvalidPauseLocation = dispatcher.task("isInvalidPauseLocation");
 const getEmptyLines = exports.getEmptyLines = dispatcher.task("getEmptyLines");
 const hasSource = exports.hasSource = dispatcher.task("hasSource");
 const setSource = exports.setSource = dispatcher.task("setSource");
 const clearSources = exports.clearSources = dispatcher.task("clearSources");
 const hasSyntaxError = exports.hasSyntaxError = dispatcher.task("hasSyntaxError");
 const getFramework = exports.getFramework = dispatcher.task("getFramework");
 const replaceOriginalVariableName = exports.replaceOriginalVariableName = dispatcher.task("replaceOriginalVariableName");
 
@@ -19155,16 +19156,26 @@ const arrowBtn = (onClick, type, classNa
   );
 }; /* 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/>. */
 
 class SearchInput extends _react.Component {
 
   componentDidMount() {
+    this.setFocus();
+  }
+
+  componentDidUpdate(prevProps) {
+    if (this.props.shouldFocus && !prevProps.shouldFocus) {
+      this.setFocus();
+    }
+  }
+
+  setFocus() {
     if (this.$input) {
       const input = this.$input;
       input.focus();
 
       if (!input.value) {
         return;
       }
 
@@ -19948,25 +19959,25 @@ exports.closeConditionalPanel = closeCon
 exports.clearProjectDirectoryRoot = clearProjectDirectoryRoot;
 exports.setProjectDirectoryRoot = setProjectDirectoryRoot;
 exports.setOrientation = setOrientation;
 
 var _selectors = __webpack_require__(1352);
 
 var _ui = __webpack_require__(1421);
 
-/* 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/>. */
+var _source = __webpack_require__(1356);
 
 function setContextMenu(type, event) {
   return ({ dispatch }) => {
     dispatch({ type: "SET_CONTEXT_MENU", contextMenu: { type, event } });
   };
-}
+} /* 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 setPrimaryPaneTab(tabName) {
   return { type: "SET_PRIMARY_PANE_TAB", tabName };
 }
 
 function closeActiveSearch() {
   return {
     type: "TOGGLE_ACTIVE_SEARCH",
@@ -19976,16 +19987,20 @@ function closeActiveSearch() {
 
 function setActiveSearch(activeSearch) {
   return ({ dispatch, getState }) => {
     const activeSearchState = (0, _selectors.getActiveSearch)(getState());
     if (activeSearchState === activeSearch) {
       return;
     }
 
+    if ((0, _selectors.getQuickOpenEnabled)(getState())) {
+      dispatch({ type: "CLOSE_QUICK_OPEN" });
+    }
+
     dispatch({
       type: "TOGGLE_ACTIVE_SEARCH",
       value: activeSearch
     });
   };
 }
 
 function toggleFrameworkGrouping(toggleValue) {
@@ -20004,17 +20019,17 @@ function showSource(sourceId) {
     dispatch(setPrimaryPaneTab("sources"));
     dispatch({
       type: "SHOW_SOURCE",
       sourceUrl: ""
     });
 
     dispatch({
       type: "SHOW_SOURCE",
-      sourceUrl: source.get("url")
+      sourceUrl: (0, _source.getRawSourceURL)(source.get("url"))
     });
   };
 }
 
 function togglePaneCollapse(position, paneCollapsed) {
   return ({ dispatch, getState }) => {
     const prevPaneCollapse = (0, _selectors.getPaneCollapse)(getState(), position);
     if (prevPaneCollapse === paneCollapsed) {
@@ -20325,16 +20340,17 @@ var _extends = Object.assign || function
 /**
  * Pause reducer
  * @module reducers/pause
  */
 
 exports.getPauseReason = getPauseReason;
 exports.isStepping = isStepping;
 exports.isPaused = isPaused;
+exports.getPreviousPauseFrameLocation = getPreviousPauseFrameLocation;
 exports.isEvaluatingExpression = isEvaluatingExpression;
 exports.getPopupObjectProperties = getPopupObjectProperties;
 exports.getIsWaitingOnBreak = getIsWaitingOnBreak;
 exports.getShouldPauseOnExceptions = getShouldPauseOnExceptions;
 exports.getShouldIgnoreCaughtExceptions = getShouldIgnoreCaughtExceptions;
 exports.getCanRewind = getCanRewind;
 exports.getFrames = getFrames;
 exports.getGeneratedFrameScope = getGeneratedFrameScope;
@@ -20363,28 +20379,30 @@ const createPauseState = exports.createP
     generated: {},
     original: {}
   },
   loadedObjects: {},
   shouldPauseOnExceptions: _prefs.prefs.pauseOnExceptions,
   shouldIgnoreCaughtExceptions: _prefs.prefs.ignoreCaughtExceptions,
   canRewind: false,
   debuggeeUrl: "",
-  command: ""
+  command: "",
+  previousLocation: null
 });
 
 const emptyPauseState = {
   pause: null,
   frames: null,
   frameScopes: {
     generated: {},
     original: {}
   },
   selectedFrameId: null,
-  loadedObjects: {}
+  loadedObjects: {},
+  previousLocation: null
 };
 
 function update(state = createPauseState(), action) {
   switch (action.type) {
     case "PAUSED":
       {
         const { selectedFrameId, frames, loadedObjects, why } = action;
 
@@ -20480,17 +20498,22 @@ function update(state = createPauseState
       _prefs.prefs.ignoreCaughtExceptions = shouldIgnoreCaughtExceptions;
 
       return _extends({}, state, {
         shouldPauseOnExceptions,
         shouldIgnoreCaughtExceptions
       });
 
     case "COMMAND":
-      return action.status === "start" ? _extends({}, state, emptyPauseState, { command: action.command }) : _extends({}, state, { command: "" });
+      {
+        return action.status === "start" ? _extends({}, state, emptyPauseState, {
+          command: action.command,
+          previousLocation: buildPreviousLocation(state, action)
+        }) : _extends({}, state, { command: "" });
+      }
 
     case "RESUME":
       // We clear why on resume because we need it to decide if
       // we shoul re-evaluate watch expressions.
       return _extends({}, state, { why: null });
 
     case "EVALUATE_EXPRESSION":
       return _extends({}, state, {
@@ -20499,16 +20522,34 @@ function update(state = createPauseState
 
     case "NAVIGATE":
       return _extends({}, state, emptyPauseState, { debuggeeUrl: action.url });
   }
 
   return state;
 }
 
+function buildPreviousLocation(state, action) {
+  const { frames, previousLocation } = state;
+
+  if (action.command !== "stepOver") {
+    return null;
+  }
+
+  const frame = frames && frames.length > 0 ? frames[0] : null;
+  if (!frame) {
+    return previousLocation;
+  }
+
+  return {
+    location: frame.location,
+    generatedLocation: frame.generatedLocation
+  };
+}
+
 // Selectors
 
 // Unfortunately, it's really hard to make these functions accept just
 // the state that we care about and still type it with Flow. The
 // problem is that we want to re-export all selectors from a single
 // module for the UI, and all of those selectors should take the
 // top-level app state, so we'd have to "wrap" them to automatically
 // pick off the piece of state we're interested in. It's impossible
@@ -20526,16 +20567,20 @@ function getPauseReason(state) {
 function isStepping(state) {
   return ["stepIn", "stepOver", "stepOut"].includes(state.pause.command);
 }
 
 function isPaused(state) {
   return !!getFrames(state);
 }
 
+function getPreviousPauseFrameLocation(state) {
+  return state.pause.previousLocation;
+}
+
 function isEvaluatingExpression(state) {
   return state.pause.command === "expression";
 }
 
 function getPopupObjectProperties(state, objectId) {
   return getAllPopupObjectProperties(state)[objectId];
 }
 
@@ -21324,84 +21369,17 @@ function setOutOfScopeLocations() {
       locations
     });
 
     dispatch((0, _setInScopeLines.setInScopeLines)());
   };
 }
 
 /***/ }),
-/* 1400 */
-/***/ (function(module, exports, __webpack_require__) {
-
-"use strict";
-
-
-Object.defineProperty(exports, "__esModule", {
-  value: true
-});
-exports.getPauseReason = getPauseReason;
-exports.isException = isException;
-exports.isInterrupted = isInterrupted;
-exports.inDebuggerEval = inDebuggerEval;
-
-
-// Map protocol pause "why" reason to a valid L10N key
-// These are the known unhandled reasons:
-// "breakpointConditionThrown", "clientEvaluated"
-// "interrupted", "attached"
-const reasons = {
-  debuggerStatement: "whyPaused.debuggerStatement",
-  breakpoint: "whyPaused.breakpoint",
-  exception: "whyPaused.exception",
-  resumeLimit: "whyPaused.resumeLimit",
-  pauseOnDOMEvents: "whyPaused.pauseOnDOMEvents",
-  breakpointConditionThrown: "whyPaused.breakpointConditionThrown",
-
-  // V8
-  DOM: "whyPaused.breakpoint",
-  EventListener: "whyPaused.pauseOnDOMEvents",
-  XHR: "whyPaused.xhr",
-  promiseRejection: "whyPaused.promiseRejection",
-  assert: "whyPaused.assert",
-  debugCommand: "whyPaused.debugCommand",
-  other: "whyPaused.other"
-}; /* 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 getPauseReason(why) {
-  if (!why) {
-    return null;
-  }
-
-  const reasonType = why.type;
-  if (!reasons[reasonType]) {
-    console.log("Please file an issue: reasonType=", reasonType);
-  }
-  return reasons[reasonType];
-}
-
-function isException(why) {
-  return why && why.type && why.type === "exception";
-}
-
-function isInterrupted(why) {
-  return why && why.type && why.type === "interrupted";
-}
-
-function inDebuggerEval(why) {
-  if (why && why.type === "exception" && why.exception && why.exception.preview && why.exception.preview.fileName) {
-    return why.exception.preview.fileName === "debugger eval code";
-  }
-
-  return false;
-}
-
-/***/ }),
+/* 1400 */,
 /* 1401 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
 Object.defineProperty(exports, "__esModule", {
   value: true
@@ -35205,40 +35183,43 @@ class SearchBar extends _react.Component
       const { editor: ed, query, modifiers } = this.props;
       if (ed && modifiers) {
         const ctx = { ed, cm: ed.codeMirror };
         (0, _editor.removeOverlay)(ctx, query, modifiers.toJS());
       }
     };
 
     this.closeSearch = e => {
-      const { editor, searchOn } = this.props;
-
+      const { closeFileSearch, editor, searchOn } = this.props;
       if (editor && searchOn) {
         this.clearSearch();
-        this.props.closeFileSearch(editor);
+        closeFileSearch(editor);
         e.stopPropagation();
         e.preventDefault();
       }
+      this.setState({ query: "", inputFocused: false });
     };
 
     this.toggleSearch = e => {
       e.stopPropagation();
       e.preventDefault();
-      const { editor } = this.props;
-
-      if (!this.props.searchOn) {
-        this.props.setActiveSearch("file");
-      }
-
-      if (this.props.searchOn && editor) {
-        const selection = editor.codeMirror.getSelection();
-        this.setState({ query: selection });
-        if (selection !== "") {
-          this.doSearch(selection);
+      const { editor, searchOn, setActiveSearch } = this.props;
+
+      if (!searchOn) {
+        setActiveSearch("file");
+      }
+
+      if (searchOn && editor) {
+        const query = editor.codeMirror.getSelection() || this.state.query;
+
+        if (query !== "") {
+          this.setState({ query, inputFocused: true });
+          this.doSearch(query);
+        } else {
+          this.setState({ query: "", inputFocused: true });
         }
       }
     };
 
     this.doSearch = query => {
       const { selectedSource } = this.props;
       if (!selectedSource || !selectedSource.get("text")) {
         return;
@@ -35269,16 +35250,20 @@ class SearchBar extends _react.Component
     };
 
     this.onChange = e => {
       this.setState({ query: e.target.value });
 
       return this.doSearch(e.target.value);
     };
 
+    this.onBlur = e => {
+      this.setState({ inputFocused: false });
+    };
+
     this.onKeyDown = e => {
       if (e.key !== "Enter" && e.key !== "F3") {
         return;
       }
 
       this.traverseResults(e, e.shiftKey);
       e.preventDefault();
     };
@@ -35333,17 +35318,18 @@ class SearchBar extends _react.Component
         })
       );
     };
 
     this.state = {
       query: props.query,
       selectedResultIndex: 0,
       count: 0,
-      index: -1
+      index: -1,
+      inputFocused: false
     };
   }
 
   componentWillUnmount() {
     const shortcuts = this.context.shortcuts;
     const {
       searchShortcut,
       searchAgainShortcut,
@@ -35417,21 +35403,23 @@ class SearchBar extends _react.Component
       "div",
       { className: "search-bar" },
       _react2.default.createElement(_SearchInput2.default, {
         query: this.state.query,
         count: count,
         placeholder: L10N.getStr("sourceSearch.search.placeholder"),
         summaryMsg: this.buildSummaryMsg(),
         onChange: this.onChange,
+        onBlur: this.onBlur,
         showErrorEmoji: this.shouldShowErrorEmoji(),
         onKeyDown: this.onKeyDown,
         handleNext: e => this.traverseResults(e, false),
         handlePrev: e => this.traverseResults(e, true),
-        handleClose: this.closeSearch
+        handleClose: this.closeSearch,
+        shouldFocus: this.state.inputFocused
       }),
       _react2.default.createElement(
         "div",
         { className: "search-bottom-bar" },
         this.renderSearchModifiers()
       )
     );
   }
@@ -39250,17 +39238,17 @@ Object.defineProperty(exports, "__esModu
 exports.DebugLine = undefined;
 
 var _react = __webpack_require__(0);
 
 var _editor = __webpack_require__(1358);
 
 var _source = __webpack_require__(1356);
 
-var _pause = __webpack_require__(1400);
+var _pause = __webpack_require__(2419);
 
 var _indentation = __webpack_require__(1438);
 
 var _reactRedux = __webpack_require__(1189);
 
 var _selectors = __webpack_require__(1352);
 
 function isDocumentReady(selectedSource, selectedFrame) {
@@ -39722,17 +39710,17 @@ function getMenuItems(event, {
     disabled: !isMapped && !isPrettified,
     click: () => jumpToMappedLocation(sourceLocation)
   };
 
   const showSourceMenuItem = {
     id: "node-menu-show-source",
     label: revealInTreeLabel,
     accesskey: revealInTreeKey,
-    disabled: isPrettyPrinted,
+    disabled: false,
     click: () => showSource(sourceId)
   };
 
   const blackBoxMenuItem = {
     id: "node-menu-blackbox",
     label: toggleBlackBoxLabel,
     accesskey: blackboxKey,
     disabled: isOriginal || isPrettyPrinted || hasSourceMap,
@@ -40449,17 +40437,17 @@ var _Close2 = _interopRequireDefault(_Cl
 var _utils = __webpack_require__(1366);
 
 var _prefs = __webpack_require__(226);
 
 var _source = __webpack_require__(1356);
 
 var _selectors = __webpack_require__(1352);
 
-var _pause = __webpack_require__(1400);
+var _pause = __webpack_require__(2419);
 
 var _breakpoint = __webpack_require__(1364);
 
 var _BreakpointsContextMenu = __webpack_require__(1805);
 
 var _BreakpointsContextMenu2 = _interopRequireDefault(_BreakpointsContextMenu);
 
 __webpack_require__(1334);
@@ -41216,17 +41204,17 @@ Object.defineProperty(exports, "__esModu
   value: true
 });
 exports.default = renderWhyPaused;
 
 var _react = __webpack_require__(0);
 
 var _react2 = _interopRequireDefault(_react);
 
-var _pause = __webpack_require__(1400);
+var _pause = __webpack_require__(2419);
 
 __webpack_require__(1337);
 
 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
 function renderExceptionSummary(exception) {
   if (typeof exception === "string") {
     return exception;
@@ -43358,17 +43346,19 @@ function reverseStepOut() {
  * not at an async expression.
  */
 function hasAwait(source, pauseLocation) {
   const { line, column } = pauseLocation;
   if (!source.text) {
     return false;
   }
 
-  return source.text.split("\n")[line - 1].slice(column, column + 200).match(/(yield|await)/);
+  const snippet = source.text.split("\n")[line - 1].slice(column - 50, column + 50);
+
+  return !!snippet.match(/(yield|await)/);
 }
 
 /**
  * @memberOf actions/pause
  * @static
  * @param stepType
  * @returns {function(ThunkArgs)}
  */
@@ -43377,16 +43367,17 @@ function astCommand(stepType) {
     if (!_prefs.features.asyncStepping) {
       return dispatch(command(stepType));
     }
 
     if (stepType == "stepOver") {
       // This type definition is ambiguous:
       const frame = (0, _selectors.getTopFrame)(getState());
       const source = (0, _selectors.getSelectedSource)(getState()).toJS();
+
       if (source && hasAwait(source, frame.location)) {
         const nextLocation = await (0, _parser.getNextStep)(source.id, frame.location);
         if (nextLocation) {
           await dispatch((0, _breakpoints.addHiddenBreakpoint)(nextLocation));
           return dispatch(command("resume"));
         }
       }
     }
@@ -43588,38 +43579,61 @@ var _ = __webpack_require__(1639);
 var _breakpoints = __webpack_require__(1396);
 
 var _expressions = __webpack_require__(1398);
 
 var _sources = __webpack_require__(1797);
 
 var _ui = __webpack_require__(1385);
 
+var _commands = __webpack_require__(1637);
+
+var _pause = __webpack_require__(2419);
+
+var _mapFrames = __webpack_require__(1804);
+
 var _fetchScopes = __webpack_require__(1655);
 
+async function getOriginalSourceForFrame(state, frame) {
+  return (0, _selectors.getSources)(state).get(frame.location.sourceId);
+}
 /**
  * Debugger has just paused
  *
  * @param {object} pauseInfo
  * @memberof actions/pause
  * @static
  */
 /* 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 paused(pauseInfo) {
   return async function ({ dispatch, getState, client, sourceMaps }) {
     const { frames, why, loadedObjects } = pauseInfo;
+    const rootFrame = frames.length > 0 ? frames[0] : null;
+
+    if (rootFrame) {
+      const mappedFrame = await (0, _mapFrames.updateFrameLocation)(rootFrame, sourceMaps);
+      const source = await getOriginalSourceForFrame(getState(), mappedFrame);
+
+      // Ensure that the original file has loaded if there is one.
+      await dispatch((0, _sources.loadSourceText)(source));
+
+      if (await (0, _pause.shouldStep)(mappedFrame, getState(), sourceMaps)) {
+        dispatch((0, _commands.command)("stepOver"));
+        return;
+      }
+    }
 
     dispatch({
       type: "PAUSED",
       why,
       frames,
-      selectedFrameId: frames[0] ? frames[0].id : undefined,
+      selectedFrameId: rootFrame ? rootFrame.id : undefined,
       loadedObjects: loadedObjects || []
     });
 
     const hiddenBreakpointLocation = (0, _selectors.getHiddenBreakpointLocation)(getState());
     if (hiddenBreakpointLocation) {
       dispatch((0, _breakpoints.removeBreakpoint)(hiddenBreakpointLocation));
     }
 
@@ -43652,17 +43666,17 @@ Object.defineProperty(exports, "__esModu
   value: true
 });
 exports.resumed = resumed;
 
 var _selectors = __webpack_require__(1352);
 
 var _expressions = __webpack_require__(1398);
 
-var _pause = __webpack_require__(1400);
+var _pause = __webpack_require__(2419);
 
 /**
  * Debugger has just resumed
  *
  * @memberof actions/pause
  * @static
  */
 function resumed() {
@@ -43996,17 +44010,17 @@ class QuickOpenModal extends _react.Comp
       }
     };
 
     this.updateResults = query => {
       if (this.isGotoQuery()) {
         return;
       }
 
-      if (query == "") {
+      if (query == "" && !this.isShortcutQuery()) {
         return this.showTopSources();
       }
 
       if (this.isSymbolSearch()) {
         return this.searchSymbols(query);
       }
 
       if (this.isShortcutQuery()) {
@@ -48479,16 +48493,17 @@ var _extends = Object.assign || function
                                                                                                                                                                                                                                                                    * 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/>. */
 
 /**
  * Redux actions for the sources state
  * @module actions/sources
  */
 
+exports.loadSourceMap = loadSourceMap;
 exports.newSource = newSource;
 exports.newSources = newSources;
 
 var _breakpoints = __webpack_require__(1396);
 
 var _loadSourceText = __webpack_require__(1435);
 
 var _prettyPrint = __webpack_require__(1798);
@@ -48505,35 +48520,35 @@ function createOriginalSource(originalUr
     id: sourceMaps.generatedToOriginalId(generatedSource.id, originalUrl),
     isPrettyPrinted: false,
     isWasm: false,
     isBlackBoxed: false,
     loadedState: "unloaded"
   };
 }
 
-// TODO: It would be nice to make getOriginalURLs a safer api
-async function loadOriginalSourceUrls(sourceMaps, generatedSource) {
-  try {
-    return await sourceMaps.getOriginalURLs(generatedSource);
-  } catch (e) {
-    console.error(e);
-    return null;
-  }
-}
-
 /**
  * @memberof actions/sources
  * @static
  */
 function loadSourceMap(generatedSource) {
   return async function ({ dispatch, getState, sourceMaps }) {
-    const urls = await loadOriginalSourceUrls(sourceMaps, generatedSource);
+    let urls;
+    try {
+      urls = await sourceMaps.getOriginalURLs(generatedSource);
+    } catch (e) {
+      console.error(e);
+      urls = null;
+    }
     if (!urls) {
-      // If this source doesn't have a sourcemap, do nothing.
+      // If this source doesn't have a sourcemap, enable it for pretty printing
+      dispatch({
+        type: "UPDATE_SOURCE",
+        source: _extends({}, generatedSource, { sourceMapURL: "" })
+      });
       return;
     }
 
     const originalSources = urls.map(url => createOriginalSource(url, generatedSource, sourceMaps));
 
     // TODO: check if this line is really needed, it introduces
     // a lot of lag to the application.
     const generatedSourceRecord = (0, _selectors.getSource)(getState(), generatedSource.id);
@@ -48831,16 +48846,17 @@ function jumpToMappedSelectedLocation() 
 
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
 
 var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
 
+exports.updateFrameLocation = updateFrameLocation;
 exports.mapFrames = mapFrames;
 
 var _selectors = __webpack_require__(1352);
 
 function updateFrameLocation(frame, sourceMaps) {
   return sourceMaps.getOriginalLocation(frame.location).then(loc => _extends({}, frame, {
     location: loc,
     generatedLocation: frame.generatedLocation || frame.location
@@ -50356,16 +50372,17 @@ class ProjectSearch extends _react.Compo
       const { closeProjectSearch, setActiveSearch } = this.props;
       if (e) {
         e.preventDefault();
       }
 
       if (this.isProjectSearchEnabled()) {
         return closeProjectSearch();
       }
+
       return setActiveSearch("project");
     };
 
     this.isProjectSearchEnabled = () => this.props.activeSearch === "project";
 
     this.selectMatchItem = matchItem => {
       this.props.selectLocation(_extends({}, matchItem));
     };
@@ -50875,22 +50892,22 @@ class Tab extends _react.PureComponent {
     }, {
       item: _extends({}, tabMenuItems.closeAllTabs, { click: () => closeTabs(tabURLs) })
     }, { item: { type: "separator" } }, {
       item: _extends({}, tabMenuItems.copySourceUri2, {
         click: () => (0, _clipboard.copyToTheClipboard)((0, _source.getRawSourceURL)(sourceTab.get("url")))
       })
     }];
 
+    items.push({
+      item: _extends({}, tabMenuItems.showSource, { click: () => showSource(tab) })
+    });
+
     if (!isPrettySource) {
       items.push({
-        item: _extends({}, tabMenuItems.showSource, { click: () => showSource(tab) })
-      });
-
-      items.push({
         item: _extends({}, tabMenuItems.prettyPrint, {
           click: () => togglePrettyPrint(tab)
         })
       });
     }
 
     (0, _devtoolsContextmenu.showMenu)(e, (0, _devtoolsContextmenu.buildMenu)(items));
   }
@@ -52105,11 +52122,218 @@ function getExpressionFromCoords(cm, coo
 
   const location = {
     start: { line: lineNumber, column: startHighlight },
     end: { line: lineNumber, column: endHighlight }
   };
   return { expression, location };
 }
 
+/***/ }),
+/* 2361 */,
+/* 2362 */,
+/* 2363 */,
+/* 2364 */,
+/* 2365 */,
+/* 2366 */,
+/* 2367 */,
+/* 2368 */,
+/* 2369 */,
+/* 2370 */,
+/* 2371 */,
+/* 2372 */,
+/* 2373 */,
+/* 2374 */,
+/* 2375 */,
+/* 2376 */,
+/* 2377 */,
+/* 2378 */,
+/* 2379 */,
+/* 2380 */,
+/* 2381 */,
+/* 2382 */,
+/* 2383 */,
+/* 2384 */,
+/* 2385 */,
+/* 2386 */,
+/* 2387 */,
+/* 2388 */,
+/* 2389 */,
+/* 2390 */,
+/* 2391 */,
+/* 2392 */,
+/* 2393 */,
+/* 2394 */,
+/* 2395 */,
+/* 2396 */,
+/* 2397 */,
+/* 2398 */,
+/* 2399 */,
+/* 2400 */,
+/* 2401 */,
+/* 2402 */,
+/* 2403 */,
+/* 2404 */,
+/* 2405 */,
+/* 2406 */,
+/* 2407 */,
+/* 2408 */,
+/* 2409 */,
+/* 2410 */,
+/* 2411 */,
+/* 2412 */,
+/* 2413 */,
+/* 2414 */,
+/* 2415 */,
+/* 2416 */,
+/* 2417 */,
+/* 2418 */,
+/* 2419 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+
+var _why = __webpack_require__(2420);
+
+Object.keys(_why).forEach(function (key) {
+  if (key === "default" || key === "__esModule") return;
+  Object.defineProperty(exports, key, {
+    enumerable: true,
+    get: function () {
+      return _why[key];
+    }
+  });
+});
+
+var _stepping = __webpack_require__(2421);
+
+Object.keys(_stepping).forEach(function (key) {
+  if (key === "default" || key === "__esModule") return;
+  Object.defineProperty(exports, key, {
+    enumerable: true,
+    get: function () {
+      return _stepping[key];
+    }
+  });
+});
+
+/***/ }),
+/* 2420 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports.getPauseReason = getPauseReason;
+exports.isException = isException;
+exports.isInterrupted = isInterrupted;
+exports.inDebuggerEval = inDebuggerEval;
+
+
+// Map protocol pause "why" reason to a valid L10N key
+// These are the known unhandled reasons:
+// "breakpointConditionThrown", "clientEvaluated"
+// "interrupted", "attached"
+const reasons = {
+  debuggerStatement: "whyPaused.debuggerStatement",
+  breakpoint: "whyPaused.breakpoint",
+  exception: "whyPaused.exception",
+  resumeLimit: "whyPaused.resumeLimit",
+  pauseOnDOMEvents: "whyPaused.pauseOnDOMEvents",
+  breakpointConditionThrown: "whyPaused.breakpointConditionThrown",
+
+  // V8
+  DOM: "whyPaused.breakpoint",
+  EventListener: "whyPaused.pauseOnDOMEvents",
+  XHR: "whyPaused.xhr",
+  promiseRejection: "whyPaused.promiseRejection",
+  assert: "whyPaused.assert",
+  debugCommand: "whyPaused.debugCommand",
+  other: "whyPaused.other"
+}; /* 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 getPauseReason(why) {
+  if (!why) {
+    return null;
+  }
+
+  const reasonType = why.type;
+  if (!reasons[reasonType]) {
+    console.log("Please file an issue: reasonType=", reasonType);
+  }
+  return reasons[reasonType];
+}
+
+function isException(why) {
+  return why && why.type && why.type === "exception";
+}
+
+function isInterrupted(why) {
+  return why && why.type && why.type === "interrupted";
+}
+
+function inDebuggerEval(why) {
+  if (why && why.type === "exception" && why.exception && why.exception.preview && why.exception.preview.fileName) {
+    return why.exception.preview.fileName === "debugger eval code";
+  }
+
+  return false;
+}
+
+/***/ }),
+/* 2421 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports.shouldStep = shouldStep;
+
+var _lodash = __webpack_require__(2);
+
+var _devtoolsSourceMap = __webpack_require__(1360);
+
+var _selectors = __webpack_require__(1352);
+
+var _parser = __webpack_require__(1365);
+
+/* 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/>. */
+
+async function shouldStep(rootFrame, state, sourceMaps) {
+  if (!rootFrame) {
+    return false;
+  }
+
+  const selectedSource = (0, _selectors.getSelectedSource)(state);
+  const previousFrameInfo = (0, _selectors.getPreviousPauseFrameLocation)(state);
+
+  let previousFrameLoc;
+  let currentFrameLoc;
+
+  if (selectedSource && (0, _devtoolsSourceMap.isOriginalId)(selectedSource.get("id"))) {
+    currentFrameLoc = rootFrame.location;
+    previousFrameLoc = previousFrameInfo && previousFrameInfo.location;
+  } else {
+    currentFrameLoc = rootFrame.generatedLocation;
+    previousFrameLoc = previousFrameInfo && previousFrameInfo.generatedLocation;
+  }
+
+  return (0, _devtoolsSourceMap.isOriginalId)(currentFrameLoc.sourceId) && (previousFrameLoc && (0, _lodash.isEqual)(previousFrameLoc, currentFrameLoc) || (await (0, _parser.isInvalidPauseLocation)(currentFrameLoc)));
+}
+
 /***/ })
 /******/ ]);
 });
\ No newline at end of file
--- a/devtools/client/debugger/new/parser-worker.js
+++ b/devtools/client/debugger/new/parser-worker.js
@@ -34592,37 +34592,38 @@ var _steps = __webpack_require__(1625);
 var _getEmptyLines = __webpack_require__(1628);
 
 var _getEmptyLines2 = _interopRequireDefault(_getEmptyLines);
 
 var _validate = __webpack_require__(1629);
 
 var _frameworks = __webpack_require__(1703);
 
+var _pauseLocation = __webpack_require__(2422);
+
 var _devtoolsUtils = __webpack_require__(1363);
 
 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/>. */
-
-const { workerHandler } = _devtoolsUtils.workerUtils;
+const { workerHandler } = _devtoolsUtils.workerUtils; /* 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/>. */
 
 self.onmessage = workerHandler({
   getClosestExpression: _closest.getClosestExpression,
   findOutOfScopeLocations: _findOutOfScopeLocations2.default,
   getSymbols: _getSymbols2.default,
   getScopes: _getScopes2.default,
   clearSymbols: _getSymbols.clearSymbols,
   clearScopes: _getScopes.clearScopes,
   clearASTs: _ast.clearASTs,
   hasSource: _sources.hasSource,
   setSource: _sources.setSource,
   clearSources: _sources.clearSources,
+  isInvalidPauseLocation: _pauseLocation.isInvalidPauseLocation,
   getVariablesInScope: _scopes.getVariablesInScope,
   getNextStep: _steps.getNextStep,
   getEmptyLines: _getEmptyLines2.default,
   hasSyntaxError: _validate.hasSyntaxError,
   getFramework: _frameworks.getFramework
 });
 
 /***/ }),
@@ -60813,11 +60814,87 @@ function stripModuleScope(rootScope) {
     }
   });
   rootLexicalScope.children = moduleScope.children;
   rootLexicalScope.children.forEach(child => {
     child.parent = rootLexicalScope;
   });
 }
 
+/***/ }),
+/* 2415 */,
+/* 2416 */,
+/* 2417 */,
+/* 2418 */,
+/* 2419 */,
+/* 2420 */,
+/* 2421 */,
+/* 2422 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports.isInvalidPauseLocation = isInvalidPauseLocation;
+
+var _types = __webpack_require__(2268);
+
+var t = _interopRequireWildcard(_types);
+
+var _ast = __webpack_require__(1375);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+/* 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/>. */
+
+const STOP = {};
+
+function isInvalidPauseLocation(location) {
+  const state = {
+    invalid: false,
+    location
+  };
+
+  try {
+    (0, _ast.fastTraverseAst)(location.sourceId, { enter: invalidLocationVisitor }, state);
+  } catch (e) {
+    if (e !== STOP) {
+      throw e;
+    }
+  }
+
+  return state.invalid;
+}
+
+function invalidLocationVisitor(node, ancestors, state) {
+  const { location } = state;
+
+  if (node.loc.end.line < location.line) {
+    return;
+  }
+  if (node.loc.start.line > location.line) {
+    throw STOP;
+  }
+
+  if (location.line === node.loc.start.line && location.column >= node.loc.start.column && t.isFunction(node) && !t.isArrowFunctionExpression(node) && (location.line < node.body.loc.start.line || location.line === node.body.loc.start.line && location.column <= node.body.loc.start.column)) {
+    // Disallow pausing _inside_ in function arguments to avoid pausing inside
+    // of destructuring and other logic.
+    state.invalid = true;
+    throw STOP;
+  }
+
+  if (location.line === node.loc.start.line && location.column === node.loc.start.column && t.isBlockStatement(node)) {
+    // Disallow pausing directly before the opening curly of a block statement.
+    // Babel occasionally maps statements with unknown original positions to
+    // this location.
+    state.invalid = true;
+    throw STOP;
+  }
+}
+
 /***/ })
 /******/ ]);
 });
\ No newline at end of file
--- a/devtools/client/debugger/new/test/mochitest/browser.ini
+++ b/devtools/client/debugger/new/test/mochitest/browser.ini
@@ -112,18 +112,19 @@ support-files =
   examples/frames.js
   examples/script-mutate.js
   examples/script-switching-02.js
   examples/script-switching-01.js
   examples/times2.js
 
 [browser_dbg-asm.js]
 [browser_dbg-async-stepping.js]
-[browser_dbg-babel.js]
+[browser_dbg-babel-scopes.js]
 skip-if = (os == "win" && ccov) # bug 1438797
+[browser_dbg-babel-stepping.js]
 [browser_dbg-breaking.js]
 [browser_dbg-breaking-from-console.js]
 [browser_dbg-breakpoints.js]
 [browser_dbg-breakpoints-toggle.js]
 [browser_dbg-breakpoints-reloading.js]
 [browser_dbg-breakpoints-cond.js]
 [browser_dbg-browser-content-toolbox.js]
 skip-if = !e10s # This test is only valid in e10s
rename from devtools/client/debugger/new/test/mochitest/browser_dbg-babel.js
rename to devtools/client/debugger/new/test/mochitest/browser_dbg-babel-scopes.js
new file mode 100644
--- /dev/null
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-babel-stepping.js
@@ -0,0 +1,154 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests for stepping through Babel's compile output.
+
+async function breakpointSteps(dbg, fixture, { line, column }, steps) {
+  const { selectors: { getBreakpoint, getBreakpoints }, getState } = dbg;
+
+  const filename = `fixtures/${fixture}/input.js`;
+  await waitForSources(dbg, filename);
+
+  ok(true, "Original sources exist");
+  const source = findSource(dbg, filename);
+
+  await selectSource(dbg, source);
+
+  // Test that breakpoint is not off by a line.
+  await addBreakpoint(dbg, source, line);
+
+  is(getBreakpoints(getState()).size, 1, "One breakpoint exists");
+  ok(
+    getBreakpoint(getState(), { sourceId: source.id, line, column }),
+    "Breakpoint has correct line"
+  );
+
+  const fnName = fixture.replace(/-([a-z])/g, (s, c) => c.toUpperCase());
+
+  const invokeResult = invokeInTab(fnName);
+
+  let invokeFailed = await Promise.race([
+    waitForPaused(dbg),
+    invokeResult.then(() => new Promise(() => {}), () => true)
+  ]);
+
+  if (invokeFailed) {
+    return invokeResult;
+  }
+
+  assertPausedLocation(dbg);
+
+  await removeBreakpoint(dbg, source.id, line, column);
+
+  is(getBreakpoints(getState()).size, 0, "Breakpoint reverted");
+
+  await runSteps(dbg, source, steps);
+
+  await resume(dbg);
+
+  // If the invoke errored later somehow, capture here so the error is
+  // reported nicely.
+  await invokeResult;
+
+  ok(true, `Ran tests for ${fixture} at line ${line} column ${column}`);
+}
+
+async function runSteps(dbg, source, steps) {
+  const { selectors: { getVisibleSelectedFrame }, getState } = dbg;
+
+  for (const [i, [type, position]] of steps.entries()) {
+    switch (type) {
+      case "stepOver":
+        await stepOver(dbg);
+        break;
+      case "stepIn":
+        await stepIn(dbg);
+        break;
+      default:
+        throw new Error("Unknown stepping type");
+    }
+
+    const { location } = getVisibleSelectedFrame(getState());
+
+    is(location.sourceId, source.id, `Step ${i} has correct sourceId`);
+    is(location.line, position.line, `Step ${i} has correct line`);
+    is(location.column, position.column, `Step ${i} has correct column`);
+
+    assertPausedLocation(dbg);
+  }
+}
+
+add_task(async function() {
+  requestLongerTimeout(4);
+
+  const dbg = await initDebugger("doc-babel.html");
+
+  await breakpointSteps(dbg, "step-over-for-of", { line: 4, column: 2 }, [
+    ["stepOver", { line: 6, column: 2 }],
+    ["stepOver", { line: 7, column: 4 }],
+    ["stepOver", { line: 6, column: 2 }],
+    ["stepOver", { line: 7, column: 4 }],
+    ["stepOver", { line: 6, column: 2 }],
+    ["stepOver", { line: 10, column: 2 }]
+  ]);
+
+  // This codifies the current behavior, but stepping twice over the for
+  // header isn't ideal.
+  await breakpointSteps(dbg, "step-over-for-of-array", { line: 3, column: 2 }, [
+    ["stepOver", { line: 5, column: 2 }],
+    ["stepOver", { line: 5, column: 7 }],
+    ["stepOver", { line: 6, column: 4 }],
+    ["stepOver", { line: 5, column: 2 }],
+    ["stepOver", { line: 5, column: 7 }],
+    ["stepOver", { line: 6, column: 4 }],
+    ["stepOver", { line: 5, column: 2 }],
+    ["stepOver", { line: 9, column: 2 }]
+  ]);
+
+  // The closure means it isn't actually possible to step into the for body,
+  // and Babel doesn't map the _loop() call, so we step past it automatically.
+  await breakpointSteps(
+    dbg,
+    "step-over-for-of-closure",
+    { line: 6, column: 2 },
+    [
+      ["stepOver", { line: 8, column: 2 }],
+      ["stepOver", { line: 12, column: 2 }]
+    ]
+  );
+
+  // Same as the previous, not possible to step into the body. The less
+  // complicated array logic makes it possible to step into the header at least,
+  // but this does end up double-visiting the for head.
+  await breakpointSteps(
+    dbg,
+    "step-over-for-of-array-closure",
+    { line: 3, column: 2 },
+    [
+      ["stepOver", { line: 5, column: 2 }],
+      ["stepOver", { line: 5, column: 7 }],
+      ["stepOver", { line: 5, column: 2 }],
+      ["stepOver", { line: 5, column: 7 }],
+      ["stepOver", { line: 5, column: 2 }],
+      ["stepOver", { line: 9, column: 2 }]
+    ]
+  );
+
+  await breakpointSteps(
+    dbg,
+    "step-over-function-params",
+    { line: 6, column: 2 },
+    [["stepOver", { line: 7, column: 2 }], ["stepIn", { line: 2, column: 2 }]]
+  );
+
+  await breakpointSteps(
+    dbg,
+    "step-over-regenerator-await",
+    { line: 2, column: 2 },
+    [
+      // Won't work until a fix to regenerator lands and we rebuild.
+      // https://github.com/facebook/regenerator/issues/342
+      // ["stepOver", { line: 4, column: 2 }],
+    ]
+  );
+});
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-breaking-from-console.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-breaking-from-console.js
@@ -21,13 +21,13 @@ add_task(async function() {
   await waitOnToolbox(toolbox, "jsdebugger-selected");
   is(toolbox.threadClient.state, "paused");
 
   // Create a dbg context
   const dbg = createDebuggerContext(toolbox);
   const { selectors: { getSelectedSource }, getState } = dbg;
 
   // Make sure the thread is paused in the right source and location
-  await waitForDispatch(dbg, "LOAD_SOURCE_TEXT");
+  await waitForPaused(dbg);
   is(dbg.win.cm.getValue(), "debugger");
   const source = getSelectedSource(getState()).toJS();
   assertPausedLocation(dbg);
 });
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-sourcemaps-reload.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-sourcemaps-reload.js
@@ -48,12 +48,11 @@ add_task(async function() {
   await resume(dbg);
   syncBp = waitForDispatch(dbg, "SYNC_BREAKPOINT", 2);
   await selectSource(dbg, "v1");
   await addBreakpoint(dbg, "v1", 13);
 
   await reload(dbg);
   await waitForSource(dbg, "v1");
   await syncBp;
-  await waitForSelectedSource(dbg, "v1");
 
   is(getBreakpoints(dbg).length, 0, "No breakpoints");
 });
--- a/devtools/client/sourceeditor/README
+++ b/devtools/client/sourceeditor/README
@@ -1,16 +1,16 @@
 This is the CodeMirror editor packaged for the Mozilla Project. CodeMirror
 is a JavaScript component that provides a code editor in the browser. When
 a mode is available for the language you are coding in, it will color your
 code, and optionally help with indentation.
 
 # Upgrade
 
-Currently used version is 5.34.0. To upgrade: download a new version of
+Currently used version is 5.35.0. To upgrade: download a new version of
 CodeMirror from the project's page [1] and replace all JavaScript and
 CSS files inside the codemirror directory [2].
 
 Then to recreate codemirror.bundle.js:
  > cd devtools/client/sourceeditor
  > npm install
  > webpack
 
--- a/devtools/client/sourceeditor/codemirror/addon/search/match-highlighter.js
+++ b/devtools/client/sourceeditor/codemirror/addon/search/match-highlighter.js
@@ -85,17 +85,17 @@
     clearTimeout(state.timeout);
     state.timeout = setTimeout(function() {highlightMatches(cm);}, state.options.delay);
   }
 
   function addOverlay(cm, query, hasBoundary, style) {
     var state = cm.state.matchHighlighter;
     cm.addOverlay(state.overlay = makeOverlay(query, hasBoundary, style));
     if (state.options.annotateScrollbar && cm.showMatchesOnScrollbar) {
-      var searchFor = hasBoundary ? new RegExp("\\b" + query + "\\b") : query;
+      var searchFor = hasBoundary ? new RegExp("\\b" + query.replace(/[\\\[+*?(){|^$]/g, "\\$&") + "\\b") : query;
       state.matchesonscroll = cm.showMatchesOnScrollbar(searchFor, false,
         {className: "CodeMirror-selection-highlight-scrollbar"});
     }
   }
 
   function removeOverlay(cm) {
     var state = cm.state.matchHighlighter;
     if (state.overlay) {
--- a/devtools/client/sourceeditor/codemirror/addon/search/searchcursor.js
+++ b/devtools/client/sourceeditor/codemirror/addon/search/searchcursor.js
@@ -14,48 +14,52 @@
 
   function regexpFlags(regexp) {
     var flags = regexp.flags
     return flags != null ? flags : (regexp.ignoreCase ? "i" : "")
       + (regexp.global ? "g" : "")
       + (regexp.multiline ? "m" : "")
   }
 
-  function ensureGlobal(regexp) {
-    return regexp.global ? regexp : new RegExp(regexp.source, regexpFlags(regexp) + "g")
+  function ensureFlags(regexp, flags) {
+    var current = regexpFlags(regexp), target = current
+    for (var i = 0; i < flags.length; i++) if (target.indexOf(flags.charAt(i)) == -1)
+      target += flags.charAt(i)
+    return current == target ? regexp : new RegExp(regexp.source, target)
   }
 
   function maybeMultiline(regexp) {
     return /\\s|\\n|\n|\\W|\\D|\[\^/.test(regexp.source)
   }
 
   function searchRegexpForward(doc, regexp, start) {
-    regexp = ensureGlobal(regexp)
+    regexp = ensureFlags(regexp, "g")
     for (var line = start.line, ch = start.ch, last = doc.lastLine(); line <= last; line++, ch = 0) {
       regexp.lastIndex = ch
       var string = doc.getLine(line), match = regexp.exec(string)
       if (match)
         return {from: Pos(line, match.index),
                 to: Pos(line, match.index + match[0].length),
                 match: match}
     }
   }
 
   function searchRegexpForwardMultiline(doc, regexp, start) {
     if (!maybeMultiline(regexp)) return searchRegexpForward(doc, regexp, start)
 
-    regexp = ensureGlobal(regexp)
+    regexp = ensureFlags(regexp, "gm")
     var string, chunk = 1
     for (var line = start.line, last = doc.lastLine(); line <= last;) {
       // This grows the search buffer in exponentially-sized chunks
       // between matches, so that nearby matches are fast and don't
       // require concatenating the whole document (in case we're
       // searching for something that has tons of matches), but at the
       // same time, the amount of retries is limited.
       for (var i = 0; i < chunk; i++) {
+        if (line > last) break
         var curLine = doc.getLine(line++)
         string = string == null ? curLine : string + "\n" + curLine
       }
       chunk = chunk * 2
       regexp.lastIndex = start.ch
       var match = regexp.exec(string)
       if (match) {
         var before = string.slice(0, match.index).split("\n"), inside = match[0].split("\n")
@@ -76,30 +80,30 @@
       if (!newMatch) return match
       match = newMatch
       cutOff = match.index + (match[0].length || 1)
       if (cutOff == string.length) return match
     }
   }
 
   function searchRegexpBackward(doc, regexp, start) {
-    regexp = ensureGlobal(regexp)
+    regexp = ensureFlags(regexp, "g")
     for (var line = start.line, ch = start.ch, first = doc.firstLine(); line >= first; line--, ch = -1) {
       var string = doc.getLine(line)
       if (ch > -1) string = string.slice(0, ch)
       var match = lastMatchIn(string, regexp)
       if (match)
         return {from: Pos(line, match.index),
                 to: Pos(line, match.index + match[0].length),
                 match: match}
     }
   }
 
   function searchRegexpBackwardMultiline(doc, regexp, start) {
-    regexp = ensureGlobal(regexp)
+    regexp = ensureFlags(regexp, "gm")
     var string, chunk = 1
     for (var line = start.line, first = doc.firstLine(); line >= first;) {
       for (var i = 0; i < chunk; i++) {
         var curLine = doc.getLine(line--)
         string = string == null ? curLine.slice(0, start.ch) : curLine + "\n" + string
       }
       chunk *= 2
 
@@ -208,17 +212,17 @@
     }
 
     if (typeof query == "string") {
       if (caseFold == null) caseFold = false
       this.matches = function(reverse, pos) {
         return (reverse ? searchStringBackward : searchStringForward)(doc, query, pos, caseFold)
       }
     } else {
-      query = ensureGlobal(query)
+      query = ensureFlags(query, "gm")
       if (!options || options.multiline !== false)
         this.matches = function(reverse, pos) {
           return (reverse ? searchRegexpBackwardMultiline : searchRegexpForwardMultiline)(doc, query, pos)
         }
       else
         this.matches = function(reverse, pos) {
           return (reverse ? searchRegexpBackward : searchRegexpForward)(doc, query, pos)
         }
--- a/devtools/client/sourceeditor/codemirror/codemirror.bundle.js
+++ b/devtools/client/sourceeditor/codemirror/codemirror.bundle.js
@@ -5449,17 +5449,18 @@ var CodeMirror =
 	      rebased.push(doc.history)
 	    }
 	    makeChangeSingleDoc(doc, change, null, stretchSpansOverChange(doc, change))
 	  })
 	}
 
 	// Revert a change stored in a document's history.
 	function makeChangeFromHistory(doc, type, allowSelectionOnly) {
-	  if (doc.cm && doc.cm.state.suppressEdits && !allowSelectionOnly) { return }
+	  var suppress = doc.cm && doc.cm.state.suppressEdits
+	  if (suppress && !allowSelectionOnly) { return }
 
 	  var hist = doc.history, event, selAfter = doc.sel
 	  var source = type == "undo" ? hist.done : hist.undone, dest = type == "undo" ? hist.undone : hist.done
 
 	  // Verify that there is a useable event (so that ctrl-z won't
 	  // needlessly clear selection events)
 	  var i = 0
 	  for (; i < source.length; i++) {
@@ -5474,18 +5475,20 @@ var CodeMirror =
 	    event = source.pop()
 	    if (event.ranges) {
 	      pushSelectionToHistory(event, dest)
 	      if (allowSelectionOnly && !event.equals(doc.sel)) {
 	        setSelection(doc, event, {clearRedo: false})
 	        return
 	      }
 	      selAfter = event
-	    }
-	    else { break }
+	    } else if (suppress) {
+	      source.push(event)
+	      return
+	    } else { break }
 	  }
 
 	  // Build up a reverse change object to add to the opposite history
 	  // stack (redo when undoing, and vice versa).
 	  var antiChanges = []
 	  pushSelectionToHistory(selAfter, dest)
 	  dest.push({changes: antiChanges, generation: hist.generation})
 	  hist.generation = event.generation || ++hist.maxGeneration
@@ -5951,17 +5954,17 @@ var CodeMirror =
 	    if (cm && !lineIsHidden(doc, line)) {
 	      var aboveVisible = heightAtLine(line) < doc.scrollTop
 	      updateLineHeight(line, line.height + widgetHeight(widget))
 	      if (aboveVisible) { addToScrollTop(cm, widget.height) }
 	      cm.curOp.forceUpdate = true
 	    }
 	    return true
 	  })
-	  signalLater(cm, "lineWidgetAdded", cm, widget, typeof handle == "number" ? handle : lineNo(handle))
+	  if (cm) { signalLater(cm, "lineWidgetAdded", cm, widget, typeof handle == "number" ? handle : lineNo(handle)) }
 	  return widget
 	}
 
 	// TEXTMARKERS
 
 	// Created with markText and setBookmark methods. A TextMarker is a
 	// handle that can be used to clear or find a marked position in the
 	// document. Line objects hold arrays (markedSpans) containing
@@ -9887,17 +9890,17 @@ var CodeMirror =
 	CodeMirror.defineDocExtension = function (name, func) {
 	  Doc.prototype[name] = func
 	}
 
 	CodeMirror.fromTextArea = fromTextArea
 
 	addLegacyProps(CodeMirror)
 
-	CodeMirror.version = "5.34.0"
+	CodeMirror.version = "5.35.0"
 
 	return CodeMirror;
 
 	})));
 
 /***/ }),
 /* 3 */
 /***/ (function(module, exports, __webpack_require__) {
@@ -9918,48 +9921,52 @@ var CodeMirror =
 
 	  function regexpFlags(regexp) {
 	    var flags = regexp.flags
 	    return flags != null ? flags : (regexp.ignoreCase ? "i" : "")
 	      + (regexp.global ? "g" : "")
 	      + (regexp.multiline ? "m" : "")
 	  }
 
-	  function ensureGlobal(regexp) {
-	    return regexp.global ? regexp : new RegExp(regexp.source, regexpFlags(regexp) + "g")
+	  function ensureFlags(regexp, flags) {
+	    var current = regexpFlags(regexp), target = current
+	    for (var i = 0; i < flags.length; i++) if (target.indexOf(flags.charAt(i)) == -1)
+	      target += flags.charAt(i)
+	    return current == target ? regexp : new RegExp(regexp.source, target)
 	  }
 
 	  function maybeMultiline(regexp) {
 	    return /\\s|\\n|\n|\\W|\\D|\[\^/.test(regexp.source)
 	  }
 
 	  function searchRegexpForward(doc, regexp, start) {
-	    regexp = ensureGlobal(regexp)
+	    regexp = ensureFlags(regexp, "g")
 	    for (var line = start.line, ch = start.ch, last = doc.lastLine(); line <= last; line++, ch = 0) {
 	      regexp.lastIndex = ch
 	      var string = doc.getLine(line), match = regexp.exec(string)
 	      if (match)
 	        return {from: Pos(line, match.index),
 	                to: Pos(line, match.index + match[0].length),
 	                match: match}
 	    }
 	  }
 
 	  function searchRegexpForwardMultiline(doc, regexp, start) {
 	    if (!maybeMultiline(regexp)) return searchRegexpForward(doc, regexp, start)
 
-	    regexp = ensureGlobal(regexp)
+	    regexp = ensureFlags(regexp, "gm")
 	    var string, chunk = 1
 	    for (var line = start.line, last = doc.lastLine(); line <= last;) {
 	      // This grows the search buffer in exponentially-sized chunks
 	      // between matches, so that nearby matches are fast and don't
 	      // require concatenating the whole document (in case we're
 	      // searching for something that has tons of matches), but at the
 	      // same time, the amount of retries is limited.
 	      for (var i = 0; i < chunk; i++) {
+	        if (line > last) break
 	        var curLine = doc.getLine(line++)
 	        string = string == null ? curLine : string + "\n" + curLine
 	      }
 	      chunk = chunk * 2
 	      regexp.lastIndex = start.ch
 	      var match = regexp.exec(string)
 	      if (match) {
 	        var before = string.slice(0, match.index).split("\n"), inside = match[0].split("\n")
@@ -9980,30 +9987,30 @@ var CodeMirror =
 	      if (!newMatch) return match
 	      match = newMatch
 	      cutOff = match.index + (match[0].length || 1)
 	      if (cutOff == string.length) return match
 	    }
 	  }
 
 	  function searchRegexpBackward(doc, regexp, start) {
-	    regexp = ensureGlobal(regexp)
+	    regexp = ensureFlags(regexp, "g")
 	    for (var line = start.line, ch = start.ch, first = doc.firstLine(); line >= first; line--, ch = -1) {
 	      var string = doc.getLine(line)
 	      if (ch > -1) string = string.slice(0, ch)
 	      var match = lastMatchIn(string, regexp)
 	      if (match)
 	        return {from: Pos(line, match.index),
 	                to: Pos(line, match.index + match[0].length),
 	                match: match}
 	    }
 	  }
 
 	  function searchRegexpBackwardMultiline(doc, regexp, start) {
-	    regexp = ensureGlobal(regexp)
+	    regexp = ensureFlags(regexp, "gm")
 	    var string, chunk = 1
 	    for (var line = start.line, first = doc.firstLine(); line >= first;) {
 	      for (var i = 0; i < chunk; i++) {
 	        var curLine = doc.getLine(line--)
 	        string = string == null ? curLine.slice(0, start.ch) : curLine + "\n" + string
 	      }
 	      chunk *= 2
 
@@ -10112,17 +10119,17 @@ var CodeMirror =
 	    }
 
 	    if (typeof query == "string") {
 	      if (caseFold == null) caseFold = false
 	      this.matches = function(reverse, pos) {
 	        return (reverse ? searchStringBackward : searchStringForward)(doc, query, pos, caseFold)
 	      }
 	    } else {
-	      query = ensureGlobal(query)
+	      query = ensureFlags(query, "gm")
 	      if (!options || options.multiline !== false)
 	        this.matches = function(reverse, pos) {
 	          return (reverse ? searchRegexpBackwardMultiline : searchRegexpForwardMultiline)(doc, query, pos)
 	        }
 	      else
 	        this.matches = function(reverse, pos) {
 	          return (reverse ? searchRegexpBackward : searchRegexpForward)(doc, query, pos)
 	        }
@@ -11433,16 +11440,17 @@ var CodeMirror =
 	    if (type == "class" || (isTS && value == "interface")) { cx.marked = "keyword"; return cont(pushlex("form"), classExpression, poplex); }
 	    if (type == "keyword c" || type == "async") return cont(noComma ? expressionNoComma : expression);
 	    if (type == "(") return cont(pushlex(")"), maybeexpression, expect(")"), poplex, maybeop);
 	    if (type == "operator" || type == "spread") return cont(noComma ? expressionNoComma : expression);
 	    if (type == "[") return cont(pushlex("]"), arrayLiteral, poplex, maybeop);
 	    if (type == "{") return contCommasep(objprop, "}", null, maybeop);
 	    if (type == "quasi") return pass(quasi, maybeop);
 	    if (type == "new") return cont(maybeTarget(noComma));
+	    if (type == "import") return cont(expression);
 	    return cont();
 	  }
 	  function maybeexpression(type) {
 	    if (type.match(/[;\}\)\],]/)) return pass();
 	    return pass(expression);
 	  }
 
 	  function maybeoperatorComma(type, value) {
@@ -11627,17 +11635,17 @@ var CodeMirror =
 	    }
 	  }
 	  function typearg(type) {
 	    if (type == "variable") return cont(typearg)
 	    else if (type == ":") return cont(typeexpr)
 	  }
 	  function afterType(type, value) {
 	    if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, afterType)
-	    if (value == "|" || type == ".") return cont(typeexpr)
+	    if (value == "|" || type == "." || value == "&") return cont(typeexpr)
 	    if (type == "[") return cont(expect("]"), afterType)
 	    if (value == "extends" || value == "implements") { cx.marked = "keyword"; return cont(typeexpr) }
 	  }
 	  function maybeTypeArgs(_, value) {
 	    if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, afterType)
 	  }
 	  function typeparam() {
 	    return pass(typeexpr, maybeTypeDefault)
@@ -11670,17 +11678,18 @@ var CodeMirror =
 	    if (value == "=") return cont(expressionNoComma);
 	  }
 	  function vardefCont(type) {
 	    if (type == ",") return cont(vardef);
 	  }
 	  function maybeelse(type, value) {
 	    if (type == "keyword b" && value == "else") return cont(pushlex("form", "else"), statement, poplex);
 	  }
-	  function forspec(type) {
+	  function forspec(type, value) {
+	    if (value == "await") return cont(forspec);
 	    if (type == "(") return cont(pushlex(")"), forspec1, expect(")"), poplex);
 	  }
 	  function forspec1(type) {
 	    if (type == "var") return cont(vardef, expect(";"), forspec2);
 	    if (type == ";") return cont(forspec2);
 	    if (type == "variable") return cont(formaybeinof);
 	    return pass(expression, expect(";"), forspec2);
 	  }
@@ -11759,16 +11768,17 @@ var CodeMirror =
 	    return pass(statement);
 	  }
 	  function exportField(type, value) {
 	    if (value == "as") { cx.marked = "keyword"; return cont(expect("variable")); }
 	    if (type == "variable") return pass(expressionNoComma, exportField);
 	  }
 	  function afterImport(type) {
 	    if (type == "string") return cont();
+	    if (type == "(") return pass(expression);
 	    return pass(importSpec, maybeMoreImports, maybeFrom);
 	  }
 	  function importSpec(type, value) {
 	    if (type == "{") return contCommasep(importSpec, "}");
 	    if (type == "variable") register(value);
 	    if (value == "*") cx.marked = "keyword";
 	    return cont(maybeAs);
 	  }
@@ -14411,33 +14421,33 @@ var CodeMirror =
 	    name: "clike",
 	    keywords: words(cKeywords),
 	    types: words(cTypes + " bool _Complex _Bool float_t double_t intptr_t intmax_t " +
 	                 "int8_t int16_t int32_t int64_t uintptr_t uintmax_t uint8_t uint16_t " +
 	                 "uint32_t uint64_t"),
 	    blockKeywords: words("case do else for if switch while struct"),
 	    defKeywords: words("struct"),
 	    typeFirstDefinitions: true,
-	    atoms: words("null true false"),
+	    atoms: words("NULL true false"),
 	    hooks: {"#": cppHook, "*": pointerHook},
 	    modeProps: {fold: ["brace", "include"]}
 	  });
 
 	  def(["text/x-c++src", "text/x-c++hdr"], {
 	    name: "clike",
 	    keywords: words(cKeywords + " asm dynamic_cast namespace reinterpret_cast try explicit new " +
 	                    "static_cast typeid catch operator template typename class friend private " +
 	                    "this using const_cast inline public throw virtual delete mutable protected " +
 	                    "alignas alignof constexpr decltype nullptr noexcept thread_local final " +
 	                    "static_assert override"),
 	    types: words(cTypes + " bool wchar_t"),
 	    blockKeywords: words("catch class do else finally for if struct switch try while"),
 	    defKeywords: words("class namespace struct enum union"),
 	    typeFirstDefinitions: true,
-	    atoms: words("true false null"),
+	    atoms: words("true false NULL"),
 	    dontIndentStatements: /^template$/,
 	    isIdentifierChar: /[\w\$_~\xa1-\uffff]/,
 	    hooks: {
 	      "#": cppHook,
 	      "*": pointerHook,
 	      "u": cpp11StringHook,
 	      "U": cpp11StringHook,
 	      "L": cpp11StringHook,
@@ -14634,32 +14644,34 @@ var CodeMirror =
 	      return "string";
 	    }
 	  }
 
 	  def("text/x-kotlin", {
 	    name: "clike",
 	    keywords: words(
 	      /*keywords*/
-	      "package as typealias class interface this super val " +
-	      "var fun for is in This throw return " +
+	      "package as typealias class interface this super val operator " +
+	      "var fun for is in This throw return annotation " +
 	      "break continue object if else while do try when !in !is as? " +
 
 	      /*soft keywords*/
 	      "file import where by get set abstract enum open inner override private public internal " +
 	      "protected catch finally out final vararg reified dynamic companion constructor init " +
 	      "sealed field property receiver param sparam lateinit data inline noinline tailrec " +
-	      "external annotation crossinline const operator infix suspend actual expect"
+	      "external annotation crossinline const operator infix suspend actual expect setparam"
 	    ),
 	    types: words(
 	      /* package java.lang */
 	      "Boolean Byte Character CharSequence Class ClassLoader Cloneable Comparable " +
 	      "Compiler Double Exception Float Integer Long Math Number Object Package Pair Process " +
 	      "Runtime Runnable SecurityManager Short StackTraceElement StrictMath String " +
-	      "StringBuffer System Thread ThreadGroup ThreadLocal Throwable Triple Void"
+	      "StringBuffer System Thread ThreadGroup ThreadLocal Throwable Triple Void Annotation Any BooleanArray " +
+	      "ByteArray Char CharArray DeprecationLevel DoubleArray Enum FloatArray Function Int IntArray Lazy " +
+	      "LazyThreadSafetyMode LongArray Nothing ShortArray Unit"
 	    ),
 	    intendSwitch: false,
 	    indentStatements: false,
 	    multiLineStrings: true,
 	    number: /^(?:0x[a-f\d_]+|0b[01_]+|(?:[\d_]+(\.\d+)?|\.\d+)(?:e[-+]?[\d_]+)?)(u|ll?|l|f)?/i,
 	    blockKeywords: words("catch class do else finally for if where try while enum"),
 	    defKeywords: words("class val var object interface fun"),
 	    atoms: words("true false null this"),
@@ -16443,17 +16455,17 @@ var CodeMirror =
 	            }
 	            vimGlobalState.macroModeState.lastInsertModeChanges.changes.pop();
 	          }
 	          clearInputState(cm);
 	          return match.command;
 	        }
 
 	        function handleKeyNonInsertMode() {
-	          if (handleMacroRecording() || handleEsc()) { return true; };
+	          if (handleMacroRecording() || handleEsc()) { return true; }
 
 	          var keys = vim.inputState.keyBuffer = vim.inputState.keyBuffer + key;
 	          if (/^[1-9]\d*$/.test(keys)) { return true; }
 
 	          var keysMatcher = /^(\d*)(.*)$/.exec(keys);
 	          if (!keysMatcher) { clearInputState(cm); return false; }
 	          var context = vim.visualMode ? 'visual' :
 	                                         'normal';
@@ -17028,17 +17040,17 @@ var CodeMirror =
 	          }
 	        }
 	        if (command.type == 'keyToEx') {
 	          // Handle user defined Ex to Ex mappings
 	          exCommandDispatcher.processCommand(cm, command.exArgs.input);
 	        } else {
 	          if (vim.visualMode) {
 	            showPrompt(cm, { onClose: onPromptClose, prefix: ':', value: '\'<,\'>',
-	                onKeyDown: onPromptKeyDown});
+	                onKeyDown: onPromptKeyDown, selectValueOnOpen: false});
 	          } else {
 	            showPrompt(cm, { onClose: onPromptClose, prefix: ':',
 	                onKeyDown: onPromptKeyDown});
 	          }
 	        }
 	      },
 	      evalInput: function(cm, vim) {
 	        // If the motion command is set, execute both the operator and motion.
@@ -19285,34 +19297,45 @@ var CodeMirror =
 	            onKeyDown: options.onKeyDown, onKeyUp: options.onKeyUp,
 	            selectValueOnOpen: false});
 	      }
 	      else {
 	        onClose(prompt(shortText, ''));
 	      }
 	    }
 	    function splitBySlash(argString) {
-	      var slashes = findUnescapedSlashes(argString) || [];
+	      return splitBySeparator(argString, '/');
+	    }
+
+	    function findUnescapedSlashes(argString) {
+	      return findUnescapedSeparators(argString, '/');
+	    }
+
+	    function splitBySeparator(argString, separator) {
+	      var slashes = findUnescapedSeparators(argString, separator) || [];
 	      if (!slashes.length) return [];
 	      var tokens = [];
 	      // in case of strings like foo/bar
 	      if (slashes[0] !== 0) return;
 	      for (var i = 0; i < slashes.length; i++) {
 	        if (typeof slashes[i] == 'number')
 	          tokens.push(argString.substring(slashes[i] + 1, slashes[i+1]));
 	      }
 	      return tokens;
 	    }
 
-	    function findUnescapedSlashes(str) {
+	    function findUnescapedSeparators(str, separator) {
+	      if (!separator)
+	        separator = '/';
+
 	      var escapeNextChar = false;
 	      var slashes = [];
 	      for (var i = 0; i < str.length; i++) {
 	        var c = str.charAt(i);
-	        if (!escapeNextChar && c == '/') {
+	        if (!escapeNextChar && c == separator) {
 	          slashes.push(i);
 	        }
 	        escapeNextChar = !escapeNextChar && (c == '\\');
 	      }
 	      return slashes;
 	    }
 
 	    // Translates a search string from ex (vim) syntax into javascript form.
@@ -20168,17 +20191,17 @@ var CodeMirror =
 	        nextCommand();
 	      },
 	      substitute: function(cm, params) {
 	        if (!cm.getSearchCursor) {
 	          throw new Error('Search feature not available. Requires searchcursor.js or ' +
 	              'any other getSearchCursor implementation.');
 	        }
 	        var argString = params.argString;
-	        var tokens = argString ? splitBySlash(argString) : [];
+	        var tokens = argString ? splitBySeparator(argString, argString[0]) : [];
 	        var regexPart, replacePart = '', trailing, flagsPart, count;
 	        var confirm = false; // Whether to confirm each replace.
 	        var global = false; // True to replace all instances on a line, false to replace only 1.
 	        if (tokens.length) {
 	          regexPart = tokens[0];
 	          replacePart = tokens[1];
 	          if (regexPart && regexPart[regexPart.length - 1] === '$') {
 	            regexPart = regexPart.slice(0, regexPart.length - 1) + '\\n';
@@ -20212,17 +20235,17 @@ var CodeMirror =
 	            if (flagsPart.indexOf('c') != -1) {
 	              confirm = true;
 	              flagsPart.replace('c', '');
 	            }
 	            if (flagsPart.indexOf('g') != -1) {
 	              global = true;
 	              flagsPart.replace('g', '');
 	            }
-	            regexPart = regexPart + '/' + flagsPart;
+	            regexPart = regexPart.replace(/\//g, "\\/") + '/' + flagsPart;
 	          }
 	        }
 	        if (regexPart) {
 	          // If regex part is empty, then use the previous query. Otherwise use
 	          // the regex part as the new query.
 	          try {
 	            updateSearchQuery(cm, regexPart, true /** ignoreCase */,
 	              true /** smartCase */);
@@ -20428,17 +20451,17 @@ var CodeMirror =
 	      // Actually do replace.
 	      next();
 	      if (done) {
 	        showConfirm(cm, 'No matches for ' + query.source);
 	        return;
 	      }
 	      if (!confirm) {
 	        replaceAll();
-	        if (callback) { callback(); };
+	        if (callback) { callback(); }
 	        return;
 	      }
 	      showPrompt(cm, {
 	        prefix: 'replace with <strong>' + replaceWith + '</strong> (y/n/a/q/l)',
 	        onKeyDown: onPromptKeyDown
 	      });
 	    }
 
@@ -20564,17 +20587,17 @@ var CodeMirror =
 	          if (vim.insertMode) {
 	            var changes = register.insertModeChanges[imc++].changes;
 	            vimGlobalState.macroModeState.lastInsertModeChanges.changes =
 	                changes;
 	            repeatInsertModeChanges(cm, changes, 1);
 	            exitInsertMode(cm);
 	          }
 	        }
-	      };
+	      }
 	      macroModeState.isPlaying = false;
 	    }
 
 	    function logKey(macroModeState, key) {
 	      if (macroModeState.isPlaying) { return; }
 	      var registerName = macroModeState.latestRegister;
 	      var register = vimGlobalState.registerController.getRegister(registerName);
 	      if (register) {
@@ -20768,17 +20791,17 @@ var CodeMirror =
 	      }
 	      vim.inputState = cachedInputState;
 	      if (vim.insertMode && !repeatForInsert) {
 	        // Don't exit insert mode twice. If repeatForInsert is set, then we
 	        // were called by an exitInsertMode call lower on the stack.
 	        exitInsertMode(cm);
 	      }
 	      macroModeState.isPlaying = false;
-	    };
+	    }
 
 	    function repeatInsertModeChanges(cm, changes, repeat) {
 	      function keyHandler(binding) {
 	        if (typeof binding == 'string') {
 	          CodeMirror.commands[binding](cm);
 	        } else {
 	          binding(cm);
 	        }
@@ -20983,18 +21006,24 @@ var CodeMirror =
 	    if (fullWord)
 	      cm.state.sublimeFindFullWord = cm.doc.sel;
 	  };
 
 	  function addCursorToSelection(cm, dir) {
 	    var ranges = cm.listSelections(), newRanges = [];
 	    for (var i = 0; i < ranges.length; i++) {
 	      var range = ranges[i];
-	      var newAnchor = cm.findPosV(range.anchor, dir, "line");
-	      var newHead = cm.findPosV(range.head, dir, "line");
+	      var newAnchor = cm.findPosV(
+	          range.anchor, dir, "line", range.anchor.goalColumn);
+	      var newHead = cm.findPosV(
+	          range.head, dir, "line", range.head.goalColumn);
+	      newAnchor.goalColumn = range.anchor.goalColumn != null ?
+	          range.anchor.goalColumn : cm.cursorCoords(range.anchor, "div").left;
+	      newHead.goalColumn = range.head.goalColumn != null ?
+	          range.head.goalColumn : cm.cursorCoords(range.head, "div").left;
 	      var newRange = {anchor: newAnchor, head: newHead};
 	      newRanges.push(range);
 	      newRanges.push(newRange);
 	    }
 	    cm.setSelections(newRanges);
 	  }
 	  cmds.addCursorToPrevLine = function(cm) { addCursorToSelection(cm, -1); };
 	  cmds.addCursorToNextLine = function(cm) { addCursorToSelection(cm, 1); };
--- a/devtools/client/sourceeditor/codemirror/keymap/sublime.js
+++ b/devtools/client/sourceeditor/codemirror/keymap/sublime.js
@@ -151,18 +151,24 @@
     if (fullWord)
       cm.state.sublimeFindFullWord = cm.doc.sel;
   };
 
   function addCursorToSelection(cm, dir) {
     var ranges = cm.listSelections(), newRanges = [];
     for (var i = 0; i < ranges.length; i++) {
       var range = ranges[i];
-      var newAnchor = cm.findPosV(range.anchor, dir, "line");
-      var newHead = cm.findPosV(range.head, dir, "line");
+      var newAnchor = cm.findPosV(
+          range.anchor, dir, "line", range.anchor.goalColumn);
+      var newHead = cm.findPosV(
+          range.head, dir, "line", range.head.goalColumn);
+      newAnchor.goalColumn = range.anchor.goalColumn != null ?
+          range.anchor.goalColumn : cm.cursorCoords(range.anchor, "div").left;
+      newHead.goalColumn = range.head.goalColumn != null ?
+          range.head.goalColumn : cm.cursorCoords(range.head, "div").left;
       var newRange = {anchor: newAnchor, head: newHead};
       newRanges.push(range);
       newRanges.push(newRange);
     }
     cm.setSelections(newRanges);
   }
   cmds.addCursorToPrevLine = function(cm) { addCursorToSelection(cm, -1); };
   cmds.addCursorToNextLine = function(cm) { addCursorToSelection(cm, 1); };
--- a/devtools/client/sourceeditor/codemirror/keymap/vim.js
+++ b/devtools/client/sourceeditor/codemirror/keymap/vim.js
@@ -836,17 +836,17 @@
             }
             vimGlobalState.macroModeState.lastInsertModeChanges.changes.pop();
           }
           clearInputState(cm);
           return match.command;
         }
 
         function handleKeyNonInsertMode() {
-          if (handleMacroRecording() || handleEsc()) { return true; };
+          if (handleMacroRecording() || handleEsc()) { return true; }
 
           var keys = vim.inputState.keyBuffer = vim.inputState.keyBuffer + key;
           if (/^[1-9]\d*$/.test(keys)) { return true; }
 
           var keysMatcher = /^(\d*)(.*)$/.exec(keys);
           if (!keysMatcher) { clearInputState(cm); return false; }
           var context = vim.visualMode ? 'visual' :
                                          'normal';
@@ -1421,17 +1421,17 @@
           }
         }
         if (command.type == 'keyToEx') {
           // Handle user defined Ex to Ex mappings
           exCommandDispatcher.processCommand(cm, command.exArgs.input);
         } else {
           if (vim.visualMode) {
             showPrompt(cm, { onClose: onPromptClose, prefix: ':', value: '\'<,\'>',
-                onKeyDown: onPromptKeyDown});
+                onKeyDown: onPromptKeyDown, selectValueOnOpen: false});
           } else {
             showPrompt(cm, { onClose: onPromptClose, prefix: ':',
                 onKeyDown: onPromptKeyDown});
           }
         }
       },
       evalInput: function(cm, vim) {
         // If the motion command is set, execute both the operator and motion.
@@ -3678,34 +3678,45 @@
             onKeyDown: options.onKeyDown, onKeyUp: options.onKeyUp,
             selectValueOnOpen: false});
       }
       else {
         onClose(prompt(shortText, ''));
       }
     }
     function splitBySlash(argString) {
-      var slashes = findUnescapedSlashes(argString) || [];
+      return splitBySeparator(argString, '/');
+    }
+
+    function findUnescapedSlashes(argString) {
+      return findUnescapedSeparators(argString, '/');
+    }
+
+    function splitBySeparator(argString, separator) {
+      var slashes = findUnescapedSeparators(argString, separator) || [];
       if (!slashes.length) return [];
       var tokens = [];
       // in case of strings like foo/bar
       if (slashes[0] !== 0) return;
       for (var i = 0; i < slashes.length; i++) {
         if (typeof slashes[i] == 'number')
           tokens.push(argString.substring(slashes[i] + 1, slashes[i+1]));
       }
       return tokens;
     }
 
-    function findUnescapedSlashes(str) {
+    function findUnescapedSeparators(str, separator) {
+      if (!separator)
+        separator = '/';
+
       var escapeNextChar = false;
       var slashes = [];
       for (var i = 0; i < str.length; i++) {
         var c = str.charAt(i);
-        if (!escapeNextChar && c == '/') {
+        if (!escapeNextChar && c == separator) {
           slashes.push(i);
         }
         escapeNextChar = !escapeNextChar && (c == '\\');
       }
       return slashes;
     }
 
     // Translates a search string from ex (vim) syntax into javascript form.
@@ -4561,17 +4572,17 @@
         nextCommand();
       },
       substitute: function(cm, params) {
         if (!cm.getSearchCursor) {
           throw new Error('Search feature not available. Requires searchcursor.js or ' +
               'any other getSearchCursor implementation.');
         }
         var argString = params.argString;
-        var tokens = argString ? splitBySlash(argString) : [];
+        var tokens = argString ? splitBySeparator(argString, argString[0]) : [];
         var regexPart, replacePart = '', trailing, flagsPart, count;
         var confirm = false; // Whether to confirm each replace.
         var global = false; // True to replace all instances on a line, false to replace only 1.
         if (tokens.length) {
           regexPart = tokens[0];
           replacePart = tokens[1];
           if (regexPart && regexPart[regexPart.length - 1] === '$') {
             regexPart = regexPart.slice(0, regexPart.length - 1) + '\\n';
@@ -4605,17 +4616,17 @@
             if (flagsPart.indexOf('c') != -1) {
               confirm = true;
               flagsPart.replace('c', '');
             }
             if (flagsPart.indexOf('g') != -1) {
               global = true;
               flagsPart.replace('g', '');
             }
-            regexPart = regexPart + '/' + flagsPart;
+            regexPart = regexPart.replace(/\//g, "\\/") + '/' + flagsPart;
           }
         }
         if (regexPart) {
           // If regex part is empty, then use the previous query. Otherwise use
           // the regex part as the new query.
           try {
             updateSearchQuery(cm, regexPart, true /** ignoreCase */,
               true /** smartCase */);
@@ -4821,17 +4832,17 @@
       // Actually do replace.
       next();
       if (done) {
         showConfirm(cm, 'No matches for ' + query.source);
         return;
       }
       if (!confirm) {
         replaceAll();
-        if (callback) { callback(); };
+        if (callback) { callback(); }
         return;
       }
       showPrompt(cm, {
         prefix: 'replace with <strong>' + replaceWith + '</strong> (y/n/a/q/l)',
         onKeyDown: onPromptKeyDown
       });
     }
 
@@ -4957,17 +4968,17 @@
           if (vim.insertMode) {
             var changes = register.insertModeChanges[imc++].changes;
             vimGlobalState.macroModeState.lastInsertModeChanges.changes =
                 changes;
             repeatInsertModeChanges(cm, changes, 1);
             exitInsertMode(cm);
           }
         }
-      };
+      }
       macroModeState.isPlaying = false;
     }
 
     function logKey(macroModeState, key) {
       if (macroModeState.isPlaying) { return; }
       var registerName = macroModeState.latestRegister;
       var register = vimGlobalState.registerController.getRegister(registerName);
       if (register) {
@@ -5161,17 +5172,17 @@
       }
       vim.inputState = cachedInputState;
       if (vim.insertMode && !repeatForInsert) {
         // Don't exit insert mode twice. If repeatForInsert is set, then we
         // were called by an exitInsertMode call lower on the stack.
         exitInsertMode(cm);
       }
       macroModeState.isPlaying = false;
-    };
+    }
 
     function repeatInsertModeChanges(cm, changes, repeat) {
       function keyHandler(binding) {
         if (typeof binding == 'string') {
           CodeMirror.commands[binding](cm);
         } else {
           binding(cm);
         }
--- a/devtools/client/sourceeditor/codemirror/lib/codemirror.js
+++ b/devtools/client/sourceeditor/codemirror/lib/codemirror.js
@@ -5207,17 +5207,18 @@ function makeChangeInner(doc, change) {
       rebased.push(doc.history)
     }
     makeChangeSingleDoc(doc, change, null, stretchSpansOverChange(doc, change))
   })
 }
 
 // Revert a change stored in a document's history.
 function makeChangeFromHistory(doc, type, allowSelectionOnly) {
-  if (doc.cm && doc.cm.state.suppressEdits && !allowSelectionOnly) { return }
+  var suppress = doc.cm && doc.cm.state.suppressEdits
+  if (suppress && !allowSelectionOnly) { return }
 
   var hist = doc.history, event, selAfter = doc.sel
   var source = type == "undo" ? hist.done : hist.undone, dest = type == "undo" ? hist.undone : hist.done
 
   // Verify that there is a useable event (so that ctrl-z won't
   // needlessly clear selection events)
   var i = 0
   for (; i < source.length; i++) {
@@ -5232,18 +5233,20 @@ function makeChangeFromHistory(doc, type
     event = source.pop()
     if (event.ranges) {
       pushSelectionToHistory(event, dest)
       if (allowSelectionOnly && !event.equals(doc.sel)) {
         setSelection(doc, event, {clearRedo: false})
         return
       }
       selAfter = event
-    }
-    else { break }
+    } else if (suppress) {
+      source.push(event)
+      return
+    } else { break }
   }
 
   // Build up a reverse change object to add to the opposite history
   // stack (redo when undoing, and vice versa).
   var antiChanges = []
   pushSelectionToHistory(selAfter, dest)
   dest.push({changes: antiChanges, generation: hist.generation})
   hist.generation = event.generation || ++hist.maxGeneration
@@ -5709,17 +5712,17 @@ function addLineWidget(doc, handle, node
     if (cm && !lineIsHidden(doc, line)) {
       var aboveVisible = heightAtLine(line) < doc.scrollTop
       updateLineHeight(line, line.height + widgetHeight(widget))
       if (aboveVisible) { addToScrollTop(cm, widget.height) }
       cm.curOp.forceUpdate = true
     }
     return true
   })
-  signalLater(cm, "lineWidgetAdded", cm, widget, typeof handle == "number" ? handle : lineNo(handle))
+  if (cm) { signalLater(cm, "lineWidgetAdded", cm, widget, typeof handle == "number" ? handle : lineNo(handle)) }
   return widget
 }
 
 // TEXTMARKERS
 
 // Created with markText and setBookmark methods. A TextMarker is a
 // handle that can be used to clear or find a marked position in the
 // document. Line objects hold arrays (markedSpans) containing
@@ -9645,13 +9648,13 @@ CodeMirror.defineExtension = function (n
 CodeMirror.defineDocExtension = function (name, func) {
   Doc.prototype[name] = func
 }
 
 CodeMirror.fromTextArea = fromTextArea
 
 addLegacyProps(CodeMirror)
 
-CodeMirror.version = "5.34.0"
+CodeMirror.version = "5.35.0"
 
 return CodeMirror;
 
 })));
\ No newline at end of file
--- a/devtools/client/sourceeditor/codemirror/mode/clike/clike.js
+++ b/devtools/client/sourceeditor/codemirror/mode/clike/clike.js
@@ -369,33 +369,33 @@ CodeMirror.defineMode("clike", function(
     name: "clike",
     keywords: words(cKeywords),
     types: words(cTypes + " bool _Complex _Bool float_t double_t intptr_t intmax_t " +
                  "int8_t int16_t int32_t int64_t uintptr_t uintmax_t uint8_t uint16_t " +
                  "uint32_t uint64_t"),
     blockKeywords: words("case do else for if switch while struct"),
     defKeywords: words("struct"),
     typeFirstDefinitions: true,
-    atoms: words("null true false"),
+    atoms: words("NULL true false"),
     hooks: {"#": cppHook, "*": pointerHook},
     modeProps: {fold: ["brace", "include"]}
   });
 
   def(["text/x-c++src", "text/x-c++hdr"], {
     name: "clike",
     keywords: words(cKeywords + " asm dynamic_cast namespace reinterpret_cast try explicit new " +
                     "static_cast typeid catch operator template typename class friend private " +
                     "this using const_cast inline public throw virtual delete mutable protected " +
                     "alignas alignof constexpr decltype nullptr noexcept thread_local final " +
                     "static_assert override"),
     types: words(cTypes + " bool wchar_t"),
     blockKeywords: words("catch class do else finally for if struct switch try while"),
     defKeywords: words("class namespace struct enum union"),
     typeFirstDefinitions: true,
-    atoms: words("true false null"),
+    atoms: words("true false NULL"),
     dontIndentStatements: /^template$/,
     isIdentifierChar: /[\w\$_~\xa1-\uffff]/,
     hooks: {
       "#": cppHook,
       "*": pointerHook,
       "u": cpp11StringHook,
       "U": cpp11StringHook,
       "L": cpp11StringHook,
@@ -592,32 +592,34 @@ CodeMirror.defineMode("clike", function(
       return "string";
     }
   }
 
   def("text/x-kotlin", {
     name: "clike",
     keywords: words(
       /*keywords*/
-      "package as typealias class interface this super val " +
-      "var fun for is in This throw return " +
+      "package as typealias class interface this super val operator " +
+      "var fun for is in This throw return annotation " +
       "break continue object if else while do try when !in !is as? " +
 
       /*soft keywords*/
       "file import where by get set abstract enum open inner override private public internal " +
       "protected catch finally out final vararg reified dynamic companion constructor init " +
       "sealed field property receiver param sparam lateinit data inline noinline tailrec " +
-      "external annotation crossinline const operator infix suspend actual expect"
+      "external annotation crossinline const operator infix suspend actual expect setparam"
     ),
     types: words(
       /* package java.lang */
       "Boolean Byte Character CharSequence Class ClassLoader Cloneable Comparable " +
       "Compiler Double Exception Float Integer Long Math Number Object Package Pair Process " +
       "Runtime Runnable SecurityManager Short StackTraceElement StrictMath String " +
-      "StringBuffer System Thread ThreadGroup ThreadLocal Throwable Triple Void"
+      "StringBuffer System Thread ThreadGroup ThreadLocal Throwable Triple Void Annotation Any BooleanArray " +
+      "ByteArray Char CharArray DeprecationLevel DoubleArray Enum FloatArray Function Int IntArray Lazy " +
+      "LazyThreadSafetyMode LongArray Nothing ShortArray Unit"
     ),
     intendSwitch: false,
     indentStatements: false,
     multiLineStrings: true,
     number: /^(?:0x[a-f\d_]+|0b[01_]+|(?:[\d_]+(\.\d+)?|\.\d+)(?:e[-+]?[\d_]+)?)(u|ll?|l|f)?/i,
     blockKeywords: words("catch class do else finally for if where try while enum"),
     defKeywords: words("class val var object interface fun"),
     atoms: words("true false null this"),
--- a/devtools/client/sourceeditor/codemirror/mode/javascript/javascript.js
+++ b/devtools/client/sourceeditor/codemirror/mode/javascript/javascript.js
@@ -395,16 +395,17 @@ CodeMirror.defineMode("javascript", func
     if (type == "class" || (isTS && value == "interface")) { cx.marked = "keyword"; return cont(pushlex("form"), classExpression, poplex); }
     if (type == "keyword c" || type == "async") return cont(noComma ? expressionNoComma : expression);
     if (type == "(") return cont(pushlex(")"), maybeexpression, expect(")"), poplex, maybeop);
     if (type == "operator" || type == "spread") return cont(noComma ? expressionNoComma : expression);
     if (type == "[") return cont(pushlex("]"), arrayLiteral, poplex, maybeop);
     if (type == "{") return contCommasep(objprop, "}", null, maybeop);
     if (type == "quasi") return pass(quasi, maybeop);
     if (type == "new") return cont(maybeTarget(noComma));
+    if (type == "import") return cont(expression);
     return cont();
   }
   function maybeexpression(type) {
     if (type.match(/[;\}\)\],]/)) return pass();
     return pass(expression);
   }
 
   function maybeoperatorComma(type, value) {
@@ -589,17 +590,17 @@ CodeMirror.defineMode("javascript", func
     }
   }
   function typearg(type) {
     if (type == "variable") return cont(typearg)
     else if (type == ":") return cont(typeexpr)
   }
   function afterType(type, value) {
     if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, afterType)
-    if (value == "|" || type == ".") return cont(typeexpr)
+    if (value == "|" || type == "." || value == "&") return cont(typeexpr)
     if (type == "[") return cont(expect("]"), afterType)
     if (value == "extends" || value == "implements") { cx.marked = "keyword"; return cont(typeexpr) }
   }
   function maybeTypeArgs(_, value) {
     if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, afterType)
   }
   function typeparam() {
     return pass(typeexpr, maybeTypeDefault)
@@ -632,17 +633,18 @@ CodeMirror.defineMode("javascript", func
     if (value == "=") return cont(expressionNoComma);
   }
   function vardefCont(type) {
     if (type == ",") return cont(vardef);
   }
   function maybeelse(type, value) {
     if (type == "keyword b" && value == "else") return cont(pushlex("form", "else"), statement, poplex);
   }
-  function forspec(type) {
+  function forspec(type, value) {
+    if (value == "await") return cont(forspec);
     if (type == "(") return cont(pushlex(")"), forspec1, expect(")"), poplex);
   }
   function forspec1(type) {
     if (type == "var") return cont(vardef, expect(";"), forspec2);
     if (type == ";") return cont(forspec2);
     if (type == "variable") return cont(formaybeinof);
     return pass(expression, expect(";"), forspec2);
   }
@@ -721,16 +723,17 @@ CodeMirror.defineMode("javascript", func
     return pass(statement);
   }
   function exportField(type, value) {
     if (value == "as") { cx.marked = "keyword"; return cont(expect("variable")); }
     if (type == "variable") return pass(expressionNoComma, exportField);
   }
   function afterImport(type) {
     if (type == "string") return cont();
+    if (type == "(") return pass(expression);
     return pass(importSpec, maybeMoreImports, maybeFrom);
   }
   function importSpec(type, value) {
     if (type == "{") return contCommasep(importSpec, "}");
     if (type == "variable") register(value);
     if (value == "*") cx.marked = "keyword";
     return cont(maybeAs);
   }
--- a/devtools/client/sourceeditor/test/codemirror/mode/javascript/test.js
+++ b/devtools/client/sourceeditor/test/codemirror/mode/javascript/test.js
@@ -58,24 +58,33 @@
      "[keyword function] [def foo]() {",
      "  [keyword import] [def $] [keyword from] [string 'jquery'];",
      "  [keyword import] { [def encrypt], [def decrypt] } [keyword from] [string 'crypto'];",
      "}");
 
   MT("import_trailing_comma",
      "[keyword import] {[def foo], [def bar],} [keyword from] [string 'baz']")
 
+  MT("import_dynamic",
+     "[keyword import]([string 'baz']).[property then]")
+
+  MT("import_dynamic",
+     "[keyword const] [def t] [operator =] [keyword import]([string 'baz']).[property then]")
+
   MT("const",
      "[keyword function] [def f]() {",
      "  [keyword const] [[ [def a], [def b] ]] [operator =] [[ [number 1], [number 2] ]];",
      "}");
 
   MT("for/of",
      "[keyword for]([keyword let] [def of] [keyword of] [variable something]) {}");
 
+  MT("for await",
+     "[keyword for] [keyword await]([keyword let] [def of] [keyword of] [variable something]) {}");
+
   MT("generator",
      "[keyword function*] [def repeat]([def n]) {",
      "  [keyword for]([keyword var] [def i] [operator =] [number 0]; [variable-2 i] [operator <] [variable-2 n]; [operator ++][variable-2 i])",
      "    [keyword yield] [variable-2 i];",
      "}");
 
   MT("quotedStringAddition",
      "[keyword let] [def f] [operator =] [variable a] [operator +] [string 'fatarrow'] [operator +] [variable c];");
--- a/devtools/client/sourceeditor/test/codemirror/test.js
+++ b/devtools/client/sourceeditor/test/codemirror/test.js
@@ -2325,17 +2325,17 @@ testCM("lineSeparator", function(cm) {
   eq(cm.getValue("\n"), "foo\nbar\n\nbaz\nquux");
   cm.setOption("lineSeparator", null);
   cm.setValue("foo\nbar\r\nbaz\rquux");
   eq(cm.lineCount(), 4);
 }, {value: "foo\nbar\r\nbaz\rquux",
     lineSeparator: "\n"});
 
 var extendingChars = /[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/
-var getChar = function (noExtending) { var res; do {res = String.fromCharCode(Math.floor(Math.random()*0x8ac)); } while ([0x90].includes(res.charCodeAt(0)) || (noExtending && extendingChars.test(res))); return res }
+var getChar = function (noExtending) { var res; do {res = String.fromCharCode(Math.floor(Math.random()*0x8ac)); } while ([0x90].indexOf(res.charCodeAt(0)) != -1 || (noExtending && extendingChars.test(res))); return res }
 var getString = function (n) { var res = getChar(true); while (--n > 0) res += getChar(); return res }
 
 function makeItWrapAfter(cm, pos) {
   var firstLineTop = cm.cursorCoords(Pos(0, 0)).top;
   for(var w = 0, posTop; posTop != firstLineTop; ++w) {
     cm.setSize(w);
     posTop = cm.charCoords(pos).top;
   }
@@ -2351,17 +2351,17 @@ function testMoveBidi(str) {
   testCM("move_bidi_" + str, function(cm) {
     if (cm.getOption("inputStyle") != "textarea" || !cm.getOption("rtlMoveVisually")) return;
     cm.getScrollerElement().style.fontFamily = "monospace";
     makeItWrapAfter(cm, Pos(0, 5));
 
     var steps = str.length - countIf(str.split(""), function(ch) { return extendingChars.test(ch) });
     var lineBreaks = {}
     lineBreaks[6 - countIf(str.substr(0, 5).split(""), function(ch) { return extendingChars.test(ch) })] = 'w';
-    if (str.includes("\n")) {
+    if (str.indexOf("\n") != -1) {
       lineBreaks[steps - 2] = 'n';
     }
 
     // Make sure we are at the visual beginning of the first line
     cm.execCommand("goLineStart");
 
     var prevCoords = cm.cursorCoords(), coords;
     for(var i = 0; i < steps; ++i) {
--- a/devtools/client/sourceeditor/test/codemirror/vim_test.js
+++ b/devtools/client/sourceeditor/test/codemirror/vim_test.js
@@ -148,17 +148,17 @@ function testVim(name, run, opts, expect
         }
         for (var i = 0; i < arguments.length; i++) {
           var key = arguments[i];
           // Find key in keymap and handle.
           var handled = CodeMirror.lookupKey(key, cm.getOption('keyMap'), executeHandler, cm);
           // Record for insert mode.
           if (handled == "handled" && cm.state.vim.insertMode && arguments[i] != 'Esc') {
             var lastChange = CodeMirror.Vim.getVimGlobalState_().macroModeState.lastInsertModeChanges;
-            if (lastChange && (key.includes('Delete') || key.includes('Backspace'))) {
+            if (lastChange && (key.indexOf('Delete') != -1 || key.indexOf('Backspace') != -1)) {
               lastChange.changes.push(new CodeMirror.Vim.InsertModeKey(key));
             }
           }
         }
       }
     }
     function doExFn(cm) {
       return function(command) {
@@ -250,17 +250,17 @@ function testJumplist(name, keys, endPos
   startPos = makeCursor(startPos[0], startPos[1]);
   testVim(name, function(cm, vim, helpers) {
     CodeMirror.Vim.resetVimGlobalState_();
     if(dialog)cm.openDialog = helpers.fakeOpenDialog('word');
     cm.setCursor(startPos);
     helpers.doKeys.apply(null, keys);
     helpers.assertCursorAt(endPos);
   }, {value: jumplistScene});
-};
+}
 testJumplist('jumplist_H', ['H', '<C-o>'], [5,2], [5,2]);
 testJumplist('jumplist_M', ['M', '<C-o>'], [2,2], [2,2]);
 testJumplist('jumplist_L', ['L', '<C-o>'], [2,2], [2,2]);
 testJumplist('jumplist_[[', ['[', '[', '<C-o>'], [5,2], [5,2]);
 testJumplist('jumplist_]]', [']', ']', '<C-o>'], [2,2], [2,2]);
 testJumplist('jumplist_G', ['G', '<C-o>'], [5,2], [5,2]);
 testJumplist('jumplist_gg', ['g', 'g', '<C-o>'], [5,2], [5,2]);
 testJumplist('jumplist_%', ['%', '<C-o>'], [1,5], [1,5]);
@@ -294,25 +294,25 @@ function testMotion(name, keys, endPos, 
   testVim(name, function(cm, vim, helpers) {
     if (!startPos) {
       startPos = new Pos(0, 0);
     }
     cm.setCursor(startPos);
     helpers.doKeys(keys);
     helpers.assertCursorAt(endPos);
   });
-};
+}
 
 function makeCursor(line, ch) {
   return new Pos(line, ch);
-};
+}
 
 function offsetCursor(cur, offsetLine, offsetCh) {
   return new Pos(cur.line + offsetLine, cur.ch + offsetCh);
-};
+}
 
 // Motion tests
 testMotion('|', '|', makeCursor(0, 0), makeCursor(0,4));
 testMotion('|_repeat', ['3', '|'], makeCursor(0, 2), makeCursor(0,4));
 testMotion('h', 'h', makeCursor(0, 0), word1.start);
 testMotion('h_repeat', ['3', 'h'], offsetCursor(word1.end, 0, -3), word1.end);
 testMotion('l', 'l', makeCursor(0, 1));
 testMotion('l_repeat', ['2', 'l'], makeCursor(0, 2));
@@ -3643,16 +3643,21 @@ testVim('ex_global_confirm', function(cm
   eq('one two\n two two\n one one\n two one\n one one', cm.getValue());
 }, {value: 'one one\n one one\n one one\n one one\n one one'});
 // Basic substitute tests.
 testVim('ex_substitute_same_line', function(cm, vim, helpers) {
   cm.setCursor(1, 0);
   helpers.doEx('s/one/two/g');
   eq('one one\n two two', cm.getValue());
 }, { value: 'one one\n one one'});
+testVim('ex_substitute_alternate_separator', function(cm, vim, helpers) {
+  cm.setCursor(1, 0);
+  helpers.doEx('s#o/e#two#g');
+  eq('o/e o/e\n two two', cm.getValue());
+}, { value: 'o/e o/e\n o/e o/e'});
 testVim('ex_substitute_full_file', function(cm, vim, helpers) {
   cm.setCursor(1, 0);
   helpers.doEx('%s/one/two/g');
   eq('two two\n two two', cm.getValue());
 }, { value: 'one one\n one one'});
 testVim('ex_substitute_input_range', function(cm, vim, helpers) {
   cm.setCursor(1, 0);
   helpers.doEx('1,3s/\\d/0/g');
@@ -3899,17 +3904,17 @@ function testSubstituteConfirm(name, com
     } catch(e) {
       throw e
     } finally {
       // Restore overridden functions.
       CodeMirror.keyName = savedKeyName;
       cm.openDialog = savedOpenDialog;
     }
   }, { value: initialValue });
-};
+}
 testSubstituteConfirm('ex_substitute_confirm_emptydoc',
     '%s/x/b/c', '', '', '', makeCursor(0, 0));
 testSubstituteConfirm('ex_substitute_confirm_nomatch',
     '%s/x/b/c', 'ba a\nbab', 'ba a\nbab', '', makeCursor(0, 0));
 testSubstituteConfirm('ex_substitute_confirm_accept',
     '%s/a/b/cg', 'ba a\nbab', 'bb b\nbbb', 'yyy', makeCursor(1, 1));
 testSubstituteConfirm('ex_substitute_confirm_random_keys',
     '%s/a/b/cg', 'ba a\nbab', 'bb b\nbbb', 'ysdkywerty', makeCursor(1, 1));
--- a/devtools/server/tests/unit/test_blackboxing-01.js
+++ b/devtools/server/tests/unit/test_blackboxing-01.js
@@ -91,17 +91,17 @@ const testBlackBox = async function () {
 
   finishClient(gClient);
 };
 
 function evalCode() {
   /* eslint-disable */
   Components.utils.evalInSandbox(
     "" + function doStuff(k) { // line 1
-      let arg = 15;            // line 2 - Step in here
+      var arg = 15;            // line 2 - Step in here
       k(arg);                  // line 3
     },                         // line 4
     gDebuggee,
     "1.8",
     BLACK_BOXED_URL,
     1
   );
 
--- a/devtools/server/tests/unit/test_stepping-08.js
+++ b/devtools/server/tests/unit/test_stepping-08.js
@@ -55,18 +55,18 @@ function evaluateTestCode() {
   /* eslint-disable */
   Cu.evalInSandbox(
     `                                   //  1
     function outerFunction() {          //  2
       debugger; innerFunction();        //  3
     }                                   //  4
                                         //  5
     function innerFunction() {          //  6
-      let x = 0;                        //  7
-      let y = 72;                       //  8
+      var x = 0;                        //  7
+      var y = 72;                       //  8
       return x+y;                       //  9
     }                                   // 10
     outerFunction();                    // 11
     `,                                  // 12
     gDebuggee,
     "1.8",
     "test_stepping-08-test-code.js",
     1
--- a/dom/bindings/moz.build
+++ b/dom/bindings/moz.build
@@ -116,17 +116,17 @@ SOURCES += [
     'StructuredClone.cpp',
 ]
 
 # Tests for maplike and setlike require bindings to be built, which means they
 # must be included in libxul. This breaks the "no test classes are exported"
 # rule stated in the test/ directory, but it's the only way this will work.
 # Test classes are only built in debug mode, and all tests requiring use of
 # them are only run in debug mode.
-if CONFIG['MOZ_DEBUG']:
+if CONFIG['MOZ_DEBUG'] and CONFIG['ENABLE_TESTS']:
     EXPORTS.mozilla.dom += [
         "test/TestFunctions.h",
         "test/TestInterfaceIterableDouble.h",
         "test/TestInterfaceIterableDoubleUnion.h",
         "test/TestInterfaceIterableSingle.h",
         "test/TestInterfaceMaplike.h",
         "test/TestInterfaceMaplikeObject.h",
         "test/TestInterfaceSetlike.h",
--- a/dom/cache/test/mochitest/browser_cache_pb_window.js
+++ b/dom/cache/test/mochitest/browser_cache_pb_window.js
@@ -65,16 +65,40 @@ function testKeys(browser) {
       }).catch(function(err) {
         is('SecurityError', err.name, 'caches.keys() should throw SecurityError');
         resolve();
       });
     });
   });
 }
 
+function testOpen_worker(browser) {
+  return ContentTask.spawn(browser, {}, function() {
+    let workerFunctionString = function () {
+      caches.open("pb-worker-cache").then(function(cacheObject) {
+        postMessage(cacheObject.toString());
+      }, function (reason) {
+        postMessage(reason.name);
+      });
+    }.toString();
+    let workerBlobURL = content.URL.createObjectURL(
+      new Blob(['(', workerFunctionString, ')()'],
+               { type : 'application/javascript' }));
+    let worker = new content.Worker(workerBlobURL);
+    content.URL.revokeObjectURL(workerBlobURL);
+    return new Promise(function(resolve, reject) {
+      worker.addEventListener("message", function (e) {
+        let isGood = (e.data === "SecurityError");
+        ok(isGood, "caches.open() should throw SecurityError from worker");
+        isGood ? resolve() : reject();
+      });
+    });
+  });
+}
+
 function test() {
   let privateWin, privateTab;
   waitForExplicitFinish();
   SpecialPowers.pushPrefEnv({'set': [['dom.caches.enabled', true],
                                      ['dom.caches.testing.enabled', true]]}
   ).then(() => {
     return BrowserTestUtils.openNewBrowserWindow({private: true});
   }).then(pw => {
@@ -83,13 +107,14 @@ function test() {
     return BrowserTestUtils.browserLoaded(privateTab.linkedBrowser);
   }).then(tab => {
     return Promise.all([
       testMatch(privateTab.linkedBrowser),
       testHas(privateTab.linkedBrowser),
       testOpen(privateTab.linkedBrowser),
       testDelete(privateTab.linkedBrowser),
       testKeys(privateTab.linkedBrowser),
+      testOpen_worker(privateTab.linkedBrowser),
     ]);
   }).then(() => {
     return BrowserTestUtils.closeWindow(privateWin);
   }).then(finish);
 }
--- a/dom/fetch/FetchDriver.cpp
+++ b/dom/fetch/FetchDriver.cpp
@@ -792,16 +792,21 @@ FetchDriver::OnStartRequest(nsIRequest* 
                             nsISupports* aContext)
 {
   AssertIsOnMainThread();
 
   // Note, this can be called multiple times if we are doing an opaqueredirect.
   // In that case we will get a simulated OnStartRequest() and then the real
   // channel will call in with an errored OnStartRequest().
 
+  if (!mChannel) {
+    MOZ_ASSERT(!mObserver);
+    return NS_BINDING_ABORTED;
+  }
+
   nsresult rv;
   aRequest->GetStatus(&rv);
   if (NS_FAILED(rv)) {
     FailWithNetworkError(rv);
     return rv;
   }
 
   // We should only get to the following code once.
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -1029,17 +1029,17 @@ WEBIDL_FILES += [
     'ProgressEvent.webidl',
     'StyleRuleChangeEvent.webidl',
     'StyleSheetApplicableStateChangeEvent.webidl',
     'StyleSheetChangeEvent.webidl',
 ]
 
 # We only expose our prefable test interfaces in debug builds, just to be on
 # the safe side.
-if CONFIG['MOZ_DEBUG']:
+if CONFIG['MOZ_DEBUG'] and CONFIG['ENABLE_TESTS']:
     WEBIDL_FILES += ['TestFunctions.webidl',
                      'TestInterfaceJS.webidl',
                      'TestInterfaceJSDictionaries.webidl',
                      'TestInterfaceJSMaplikeSetlikeIterable.webidl']
 
 WEBIDL_FILES += [
     'InstallTrigger.webidl',
 ]
--- a/dom/xul/nsXULPrototypeDocument.cpp
+++ b/dom/xul/nsXULPrototypeDocument.cpp
@@ -103,139 +103,131 @@ NS_NewXULPrototypeDocument(nsXULPrototyp
 //----------------------------------------------------------------------
 //
 // nsISerializable methods
 //
 
 NS_IMETHODIMP
 nsXULPrototypeDocument::Read(nsIObjectInputStream* aStream)
 {
-    nsresult rv;
-
     nsCOMPtr<nsISupports> supports;
-    rv = aStream->ReadObject(true, getter_AddRefs(supports));
+    nsresult rv = aStream->ReadObject(true, getter_AddRefs(supports));
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
     mURI = do_QueryInterface(supports);
 
     uint32_t count, i;
     nsCOMPtr<nsIURI> styleOverlayURI;
 
-    nsresult tmp = aStream->Read32(&count);
-    if (NS_FAILED(tmp)) {
-      return tmp;
-    }
+    rv = aStream->Read32(&count);
     if (NS_FAILED(rv)) {
       return rv;
     }
 
     for (i = 0; i < count; ++i) {
-        tmp = aStream->ReadObject(true, getter_AddRefs(supports));
-        if (NS_FAILED(tmp)) {
-          rv = tmp;
+        rv = aStream->ReadObject(true, getter_AddRefs(supports));
+        if (NS_FAILED(rv)) {
+          return rv;
         }
         styleOverlayURI = do_QueryInterface(supports);
         mStyleSheetReferences.AppendObject(styleOverlayURI);
     }
 
 
     // nsIPrincipal mNodeInfoManager->mPrincipal
-    nsCOMPtr<nsIPrincipal> principal;
-    tmp = aStream->ReadObject(true, getter_AddRefs(supports));
-    principal = do_QueryInterface(supports);
-    if (NS_FAILED(tmp)) {
-      rv = tmp;
+    rv = aStream->ReadObject(true, getter_AddRefs(supports));
+    if (NS_FAILED(rv)) {
+      return rv;
     }
+    nsCOMPtr<nsIPrincipal> principal = do_QueryInterface(supports);
     // Better safe than sorry....
     mNodeInfoManager->SetDocumentPrincipal(principal);
 
     mRoot = new nsXULPrototypeElement();
 
     // mozilla::dom::NodeInfo table
     nsTArray<RefPtr<mozilla::dom::NodeInfo>> nodeInfos;
 
-    tmp = aStream->Read32(&count);
-    if (NS_FAILED(tmp)) {
-      rv = tmp;
+    rv = aStream->Read32(&count);
+    if (NS_FAILED(rv)) {
+      return rv;
     }
     nsAutoString namespaceURI, prefixStr, localName;
     bool prefixIsNull;
     RefPtr<nsAtom> prefix;
     for (i = 0; i < count; ++i) {
-        tmp = aStream->ReadString(namespaceURI);
-        if (NS_FAILED(tmp)) {
-          rv = tmp;
+        rv = aStream->ReadString(namespaceURI);
+        if (NS_FAILED(rv)) {
+          return rv;
         }
-        tmp = aStream->ReadBoolean(&prefixIsNull);
-        if (NS_FAILED(tmp)) {
-          rv = tmp;
+        rv = aStream->ReadBoolean(&prefixIsNull);
+        if (NS_FAILED(rv)) {
+          return rv;
         }
         if (prefixIsNull) {
             prefix = nullptr;
         } else {
-            tmp = aStream->ReadString(prefixStr);
-            if (NS_FAILED(tmp)) {
-              rv = tmp;
+            rv = aStream->ReadString(prefixStr);
+            if (NS_FAILED(rv)) {
+              return rv;
             }
             prefix = NS_Atomize(prefixStr);
         }
-        tmp = aStream->ReadString(localName);
-        if (NS_FAILED(tmp)) {
-          rv = tmp;
+        rv = aStream->ReadString(localName);
+        if (NS_FAILED(rv)) {
+          return rv;
         }
 
         RefPtr<mozilla::dom::NodeInfo> nodeInfo;
         // Using UINT16_MAX here as we don't know which nodeinfos will be
         // used for attributes and which for elements. And that doesn't really
         // matter.
-        tmp = mNodeInfoManager->GetNodeInfo(localName, prefix, namespaceURI,
-                                            UINT16_MAX,
-                                            getter_AddRefs(nodeInfo));
-        if (NS_FAILED(tmp)) {
-          rv = tmp;
+        rv = mNodeInfoManager->GetNodeInfo(localName, prefix, namespaceURI,
+                                           UINT16_MAX,
+                                           getter_AddRefs(nodeInfo));
+        if (NS_FAILED(rv)) {
+          return rv;
         }
         nodeInfos.AppendElement(nodeInfo);
     }
 
     // Document contents
     uint32_t type;
     while (NS_SUCCEEDED(rv)) {
-        tmp = aStream->Read32(&type);
-        if (NS_FAILED(tmp)) {
-          rv = tmp;
+        rv = aStream->Read32(&type);
+        if (NS_FAILED(rv)) {
+          return rv;
           break;
         }
 
         if ((nsXULPrototypeNode::Type)type == nsXULPrototypeNode::eType_PI) {
             RefPtr<nsXULPrototypePI> pi = new nsXULPrototypePI();
 
-            tmp = pi->Deserialize(aStream, this, mURI, &nodeInfos);
-            if (NS_FAILED(tmp)) {
-              rv = tmp;
+            rv = pi->Deserialize(aStream, this, mURI, &nodeInfos);
+            if (NS_FAILED(rv)) {
+              return rv;
             }
-            tmp = AddProcessingInstruction(pi);
-            if (NS_FAILED(tmp)) {
-              rv = tmp;
+            rv = AddProcessingInstruction(pi);
+            if (NS_FAILED(rv)) {
+              return rv;
             }
         } else if ((nsXULPrototypeNode::Type)type == nsXULPrototypeNode::eType_Element) {
-            tmp = mRoot->Deserialize(aStream, this, mURI, &nodeInfos);
-            if (NS_FAILED(tmp)) {
-              rv = tmp;
+            rv = mRoot->Deserialize(aStream, this, mURI, &nodeInfos);
+            if (NS_FAILED(rv)) {
+              return rv;
             }
             break;
         } else {
             NS_NOTREACHED("Unexpected prototype node type");
-            rv = NS_ERROR_FAILURE;
-            break;
+            return NS_ERROR_FAILURE;
         }
     }
-    tmp = NotifyLoadDone();
-    if (NS_FAILED(tmp)) {
-      rv = tmp;
-    }
 
-    return rv;
+    return NotifyLoadDone();
 }
 
 static nsresult
 GetNodeInfos(nsXULPrototypeElement* aPrototype,
              nsTArray<RefPtr<mozilla::dom::NodeInfo>>& aArray)
 {
     if (aArray.IndexOf(aPrototype->mNodeInfo) == aArray.NoIndex) {
         aArray.AppendElement(aPrototype->mNodeInfo);
--- a/js/public/StructuredClone.h
+++ b/js/public/StructuredClone.h
@@ -15,26 +15,153 @@
 
 #include "jstypes.h"
 
 #include "js/RootingAPI.h"
 #include "js/TypeDecls.h"
 #include "js/Value.h"
 #include "js/Vector.h"
 
+/*
+ * API for safe passing of structured data, HTML 2018 Feb 21 section 2.7.
+ * <https://html.spec.whatwg.org/multipage/structured-data.html>
+ *
+ * This is a serialization scheme for JS values, somewhat like JSON. It
+ * preserves some aspects of JS objects (strings, numbers, own data properties
+ * with string keys, array elements) but not others (methods, getters and
+ * setters, prototype chains). Unlike JSON, structured data:
+ *
+ * -   can contain cyclic references.
+ *
+ * -   handles Maps, Sets, and some other object types.
+ *
+ * -   supports *transferring* objects of certain types from one realm to
+ *     another, rather than cloning them.
+ *
+ * -   is specified by a living standard, and continues to evolve.
+ *
+ * -   is encoded in a nonstandard binary format, and is never exposed to Web
+ *     content in its serialized form. It's used internally by the browser to
+ *     send data from one thread/realm/domain to another, not across the
+ *     network.
+ */
+
 struct JSStructuredCloneReader;
 struct JSStructuredCloneWriter;
 
-// API for the HTML5 internal structured cloning algorithm.
+/**
+ * The structured-clone serialization format version number.
+ *
+ * When serialized data is stored as bytes, e.g. in your Firefox profile, later
+ * versions of the engine may have to read it. When you upgrade Firefox, we
+ * don't crawl through your whole profile converting all saved data from the
+ * previous version of the serialization format to the latest version. So it is
+ * normal to have data in old formats stored in your profile.
+ *
+ * The JS engine can *write* data only in the current format version.
+ *
+ * It can *read* any data written in the current version, and data written for
+ * DifferentProcess scope in earlier versions.
+ *
+ *
+ * ## When to bump this version number
+ *
+ * When making a change so drastic that the JS engine needs to know whether
+ * it's reading old or new serialized data in order to handle both correctly,
+ * increment this version number. Make sure the engine can still read all
+ * old data written with previous versions.
+ *
+ * If StructuredClone.cpp doesn't contain code that distinguishes between
+ * version 8 and version 9, there should not be a version 9.
+ *
+ * Do not increment for changes that only affect SameProcess encoding.
+ *
+ * Increment only for changes that would otherwise break old serialized data.
+ * Do not increment for new data types. (Rationale: Modulo bugs, older versions
+ * of the JS engine can already correctly throw errors when they encounter new,
+ * unrecognized features. A version number bump does not actually help them.)
+ */
+#define JS_STRUCTURED_CLONE_VERSION 8
 
 namespace JS {
 
+/**
+ * Indicates the "scope of validity" of serialized data.
+ *
+ * Writing plain JS data produces an array of bytes that can be copied and
+ * read in another process or whatever. The serialized data is Plain Old Data.
+ * However, HTML also supports `Transferable` objects, which, when cloned, can
+ * be moved from the source object into the clone, like when you take a
+ * photograph of someone and it steals their soul.
+ * See <https://developer.mozilla.org/en-US/docs/Web/API/Transferable>.
+ * We support cloning and transferring objects of many types.
+ *
+ * For example, when we transfer an ArrayBuffer (within a process), we "detach"
+ * the ArrayBuffer, embed the raw buffer pointer in the serialized data, and
+ * later install it in a new ArrayBuffer in the destination realm. Ownership
+ * of that buffer memory is transferred from the original ArrayBuffer to the
+ * serialized data and then to the clone.
+ *
+ * This only makes sense within a single address space. When we transfer an
+ * ArrayBuffer to another process, the contents of the buffer must be copied
+ * into the serialized data. (The original ArrayBuffer is still detached,
+ * though, for consistency; in some cases the caller shouldn't know or care if
+ * the recipient is in the same process.)
+ *
+ * ArrayBuffers are actually a lucky case; some objects (like MessagePorts)
+ * can't reasonably be stored by value in serialized data -- it's pointers or
+ * nothing.
+ *
+ * So there is a tradeoff between scope of validity -- how far away the
+ * serialized data may be sent and still make sense -- and efficiency or
+ * features. The read and write algorithms therefore take an argument of this
+ * type, allowing the user to control those trade-offs.
+ */
 enum class StructuredCloneScope : uint32_t {
+    /**
+     * The most restrictive scope, with greatest efficiency and features.
+     *
+     * When writing, this means we're writing for an audience in the same
+     * process and same thread. The caller promises that the serialized data
+     * will **not** be shipped off to a different thread/process or stored in a
+     * database. It's OK to produce serialized data that contains pointers.  In
+     * Rust terms, the serialized data will be treated as `!Send`.
+     *
+     * When reading, this means: Accept transferred objects and buffers
+     * (pointers). The caller promises that the serialized data was written
+     * using this API (otherwise, the serialized data may contain bogus
+     * pointers, leading to undefined behavior).
+     */
     SameProcessSameThread,
+
+    /**
+     * When writing, this means: The caller promises that the serialized data
+     * will **not** be shipped off to a different process or stored in a
+     * database. However, it may be shipped to another thread. It's OK to
+     * produce serialized data that contains pointers to data that is safe to
+     * send across threads, such as array buffers. In Rust terms, the
+     * serialized data will be treated as `Send` but not `Copy`.
+     *
+     * When reading, this means the same thing as SameProcessSameThread;
+     * the distinction only matters when writing.
+     */
     SameProcessDifferentThread,
+
+    /**
+     * The broadest scope.
+     *
+     * When writing, this means we're writing for an audience in a different
+     * process. Produce serialized data that can be sent to other processes,
+     * bitwise copied, or even stored as bytes in a database and read by later
+     * versions of Firefox years from now. Transferable objects are limited to
+     * ArrayBuffers, whose contents are copied into the serialized data (rather
+     * than just writing a pointer).
+     *
+     * When reading, this means: Do not accept pointers.
+     */
     DifferentProcess
 };
 
 enum TransferableOwnership {
     /** Transferable data has not been filled in yet */
     SCTAG_TMO_UNFILLED = 0,
 
     /** Structured clone buffer does not yet own the data */
@@ -163,22 +290,16 @@ typedef bool (*TransferStructuredCloneOp
 /**
  * Called when freeing an unknown transferable object. Note that it
  * should never trigger a garbage collection (and will assert in a
  * debug build if it does.)
  */
 typedef void (*FreeTransferStructuredCloneOp)(uint32_t tag, JS::TransferableOwnership ownership,
                                               void* content, uint64_t extraData, void* closure);
 
-// The maximum supported structured-clone serialization format version.
-// Increment this when anything at all changes in the serialization format.
-// (Note that this does not need to be bumped for Transferable-only changes,
-// since they are never saved to persistent storage.)
-#define JS_STRUCTURED_CLONE_VERSION 8
-
 struct JSStructuredCloneCallbacks {
     ReadStructuredCloneOp read;
     WriteStructuredCloneOp write;
     StructuredCloneErrorOp reportError;
     ReadTransferStructuredCloneOp readTransfer;
     TransferStructuredCloneOp writeTransfer;
     FreeTransferStructuredCloneOp freeTransfer;
 };
@@ -252,24 +373,31 @@ public:
     {}
     JSStructuredCloneData(JSStructuredCloneData&& other) = default;
     JSStructuredCloneData& operator=(JSStructuredCloneData&& other) = default;
     ~JSStructuredCloneData();
 
     using BufferList::BufferList;
 };
 
-/** Note: if the *data contains transferable objects, it can be read only once. */
+/**
+ * Implements StructuredDeserialize and StructuredDeserializeWithTransfer.
+ *
+ * Note: If `data` contains transferable objects, it can be read only once.
+ */
 JS_PUBLIC_API(bool)
 JS_ReadStructuredClone(JSContext* cx, JSStructuredCloneData& data, uint32_t version,
                        JS::StructuredCloneScope scope,
                        JS::MutableHandleValue vp,
                        const JSStructuredCloneCallbacks* optionalCallbacks, void* closure);
 
 /**
+ * Implements StructuredSerialize, StructuredSerializeForStorage, and
+ * StructuredSerializeWithTransfer.
+ *
  * Note: If the scope is DifferentProcess then the cloneDataPolicy must deny
  * shared-memory objects, or an error will be signaled if a shared memory object
  * is seen.
  */
 JS_PUBLIC_API(bool)
 JS_WriteStructuredClone(JSContext* cx, JS::HandleValue v, JSStructuredCloneData* data,
                         JS::StructuredCloneScope scope,
                         JS::CloneDataPolicy cloneDataPolicy,
--- a/js/src/builtin/SelfHostingDefines.h
+++ b/js/src/builtin/SelfHostingDefines.h
@@ -18,16 +18,19 @@
 
 // Unforgeable version of Function.prototype.apply.
 #define FUN_APPLY(FUN, RECEIVER, ARGS) \
   callFunction(std_Function_apply, FUN, RECEIVER, ARGS)
 
 // NB: keep this in sync with the copy in vm/ArgumentsObject.h.
 #define MAX_ARGS_LENGTH (500 * 1000)
 
+// NB: keep this in sync with the copy in vm/String.h.
+#define MAX_STRING_LENGTH ((1 << 28) - 1)
+
 // Spread non-empty argument list of up to 15 elements.
 #define SPREAD(v, n) SPREAD_##n(v)
 #define SPREAD_1(v) v[0]
 #define SPREAD_2(v) SPREAD_1(v), v[1]
 #define SPREAD_3(v) SPREAD_2(v), v[2]
 #define SPREAD_4(v) SPREAD_3(v), v[3]
 #define SPREAD_5(v) SPREAD_4(v), v[4]
 #define SPREAD_6(v) SPREAD_5(v), v[5]
--- a/js/src/builtin/String.js
+++ b/js/src/builtin/String.js
@@ -63,46 +63,52 @@ function String_generic_match(thisValue,
         ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, "String.match");
     return callFunction(String_match, thisValue, regexp);
 }
 
 /**
  * A helper function implementing the logic for both String.prototype.padStart
  * and String.prototype.padEnd as described in ES7 Draft March 29, 2016
  */
-function String_pad(maxLength, fillString, padEnd = false) {
-
+function String_pad(maxLength, fillString, padEnd) {
     // Steps 1-2.
     RequireObjectCoercible(this);
     let str = ToString(this);
 
     // Steps 3-4.
     let intMaxLength = ToLength(maxLength);
     let strLen = str.length;
 
     // Step 5.
     if (intMaxLength <= strLen)
         return str;
 
     // Steps 6-7.
-    let filler = fillString === undefined ? " " : ToString(fillString);
+    assert(fillString !== undefined, "never called when fillString is undefined");
+    let filler = ToString(fillString);
 
     // Step 8.
     if (filler === "")
         return str;
 
+    // Throw an error if the final string length exceeds the maximum string
+    // length. Perform this check early so we can use int32 operations below.
+    if (intMaxLength > MAX_STRING_LENGTH)
+        ThrowRangeError(JSMSG_RESULTING_STRING_TOO_LARGE);
+
     // Step 9.
     let fillLen = intMaxLength - strLen;
 
     // Step 10.
+    // Perform an int32 division to ensure String_repeat is not called with a
+    // double to avoid repeated bailouts in ToInteger.
     let truncatedStringFiller = callFunction(String_repeat, filler,
-                                             fillLen / filler.length);
+                                             (fillLen / filler.length) | 0);
 
-    truncatedStringFiller += callFunction(String_substr, filler, 0,
-                                          fillLen % filler.length);
+    truncatedStringFiller += Substring(filler, 0, fillLen % filler.length);
 
     // Step 11.
     if (padEnd === true)
         return str + truncatedStringFiller;
     return truncatedStringFiller + str;
 }
 
 function String_pad_start(maxLength, fillString = " ") {
@@ -498,21 +504,24 @@ function String_repeat(count) {
 
     // Steps 4-5.
     var n = ToInteger(count);
 
     // Steps 6-7.
     if (n < 0)
         ThrowRangeError(JSMSG_NEGATIVE_REPETITION_COUNT);
 
-    if (!(n * S.length < (1 << 28)))
+    // Inverted condition to handle |Infinity * 0 = NaN| correctly.
+    if (!(n * S.length <= MAX_STRING_LENGTH))
         ThrowRangeError(JSMSG_RESULTING_STRING_TOO_LARGE);
 
     // Communicate |n|'s possible range to the compiler.
-    n = n & ((1 << 28) - 1);
+    assert((MAX_STRING_LENGTH & (MAX_STRING_LENGTH + 1)) === 0,
+           "MAX_STRING_LENGTH can be used as a bitmask");
+    n = n & MAX_STRING_LENGTH;
 
     // Steps 8-9.
     var T = "";
     for (;;) {
         if (n & 1)
             T += S;
         n >>= 1;
         if (n)
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -2906,17 +2906,17 @@ const Class CloneBufferObject::class_ = 
     "CloneBuffer",
     JSCLASS_HAS_RESERVED_SLOTS(CloneBufferObject::NUM_SLOTS) |
     JSCLASS_FOREGROUND_FINALIZE,
     &CloneBufferObjectClassOps
 };
 
 const JSPropertySpec CloneBufferObject::props_[] = {
     JS_PSGS("clonebuffer", getCloneBuffer, setCloneBuffer, 0),
-    JS_PSG("arraybuffer", getCloneBufferAsArrayBuffer, 0),
+    JS_PSGS("arraybuffer", getCloneBufferAsArrayBuffer, setCloneBuffer, 0),
     JS_PS_END
 };
 
 static mozilla::Maybe<JS::StructuredCloneScope>
 ParseCloneScope(JSContext* cx, HandleString str)
 {
     mozilla::Maybe<JS::StructuredCloneScope> scope;
 
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -890,17 +890,17 @@ BytecodeEmitter::EmitterScope::enterLexi
                                             Handle<LexicalScope::Data*> bindings)
 {
     MOZ_ASSERT(kind != ScopeKind::NamedLambda && kind != ScopeKind::StrictNamedLambda);
     MOZ_ASSERT(this == bce->innermostEmitterScope);
 
     if (!ensureCache(bce))
         return false;
 
-    // Marks all names as closed over if the the context requires it. This
+    // Marks all names as closed over if the context requires it. This
     // cannot be done in the Parser as we may not know if the context requires
     // all bindings to be closed over until after parsing is finished. For
     // example, legacy generators require all bindings to be closed over but
     // it is unknown if a function is a legacy generator until the first
     // 'yield' expression is parsed.
     //
     // This is not a problem with other scopes, as all other scopes with
     // bindings are body-level. At the time of their creation, whether or not
@@ -6826,34 +6826,22 @@ BytecodeEmitter::emitLexicalScope(ParseN
     MOZ_ASSERT(pn->isKind(ParseNodeKind::LexicalScope));
 
     TDZCheckCache tdzCache(this);
 
     ParseNode* body = pn->scopeBody();
     if (pn->isEmptyScope())
         return emitLexicalScopeBody(body);
 
-    // Update line number notes before emitting TDZ poison in
-    // EmitterScope::enterLexical to avoid spurious pausing on seemingly
-    // non-effectful lines in Debugger.
-    //
-    // For example, consider the following code.
-    //
-    // L1: {
-    // L2:   let x = 42;
-    // L3: }
-    //
-    // If line number notes were not updated before the TDZ poison, the TDZ
-    // poison bytecode sequence of 'uninitialized; initlexical' will have line
-    // number L1, and the Debugger will pause there.
+    // We are about to emit some bytecode for what the spec calls "declaration
+    // instantiation". Assign these instructions to the opening `{` of the
+    // block. (Using the location of each declaration we're instantiating is
+    // too weird when stepping in the debugger.)
     if (!ParseNodeRequiresSpecialLineNumberNotes(body)) {
-        ParseNode* pnForPos = body;
-        if (body->isKind(ParseNodeKind::StatementList) && body->pn_head)
-            pnForPos = body->pn_head;
-        if (!updateLineNumberNotes(pnForPos->pn_pos.begin))
+        if (!updateSourceCoordNotes(pn->pn_pos.begin))
             return false;
     }
 
     EmitterScope emitterScope(this);
     ScopeKind kind;
     if (body->isKind(ParseNodeKind::Catch)) {
         kind = (!body->pn_left || body->pn_left->isKind(ParseNodeKind::Name))
                ? ScopeKind::SimpleCatch
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/lib/stepping.js
@@ -0,0 +1,32 @@
+// Test that stepping through a function stops at the expected lines.
+// `script` is a string, some JS code that evaluates to a function.
+// `expected` is the array of line numbers where stepping is expected to stop
+// when we call the function.
+function testStepping(script, expected) {
+    let g = newGlobal();
+    let f = g.eval(script);
+
+    let log = [];
+    function maybePause(frame) {
+        let previousLine = log[log.length - 1]; // note: may be undefined
+        let line = frame.script.getOffsetLocation(frame.offset).lineNumber;
+        if (line !== previousLine)
+            log.push(line);
+    }
+
+    let dbg = new Debugger(g);
+    dbg.onEnterFrame = frame => {
+        // Log this pause (before the first instruction of the function).
+        maybePause(frame);
+
+        // Log future pauses in the same stack frame.
+        frame.onStep = function() { maybePause(this); };
+
+        // Now disable this hook so that we step over function calls, not into them.
+        dbg.onEnterFrame = undefined;
+    };
+
+    f();
+
+    assertEq(log.join(","), expected.join(","));
+}
--- a/js/src/jit-test/tests/debug/Frame-onStep-19.js
+++ b/js/src/jit-test/tests/debug/Frame-onStep-19.js
@@ -1,63 +1,41 @@
 // Stepping should ignore nested function declarations.
 
 // Nested functions are hoisted to the top of the function body,
 // so technically the first thing that happens when you call the outer function
 // is that each inner function is created and bound to a local variable.
 // But users don't actually want to see that happen when they're stepping.
 // It's super confusing.
 
-function runTest(script, expected) {
-    let g = newGlobal();
-    g.eval(script);
+load(libdir + "stepping.js");
 
-    let dbg = new Debugger(g);
-    let log = [];
-    dbg.onEnterFrame = frame => {
-        let previousLine = undefined;
-        frame.onStep = function() {
-            let line = this.script.getOffsetLocation(this.offset).lineNumber;
-            if (line != previousLine) {
-                log.push(line);
-                previousLine = line;
-            }
-        };
-
-        // Now disable this hook so that we step over function calls, not into them.
-        dbg.onEnterFrame = undefined;
-    };
-
-    g.f();
-
-    assertEq(log.join(","), expected.join(","));
-}
-
-runTest(
+testStepping(
     `\
-      var f = (function() {      // line 1
+      (function() {              // line 1
         let x = 1;               // line 2
         funcb("funcb");          // line 3
         function funcb(msg) {    // line 4
           console.log(msg)
         }
-      });                        // line 7
+      })                         // line 7
     `,
-    [2, 3, 7]);
+    [1, 2, 3, 7]);
 
 // Stopping at the ClassDeclaration on line 8 is fine. For that matter,
 // stopping on line 5 wouldn't be so bad if we did it after line 3 and before
 // line 8; alas, the actual order of execution is 5, 2, 3, 8... which is too
 // confusing.
-runTest(
+testStepping(
     `\
       function f() {    //  1
         var x = 0;      //  2
         a();            //  3
 
         function a() {  //  5
           x += 1;       //  6
         }               //  7
         class Car {}    //  8
         return x;       //  9
       }                 // 10
+      f
     `,
-    [2, 3, 8, 9, 10]);
+    [1, 2, 3, 8, 9, 10]);
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -4527,19 +4527,26 @@ LIRGenerator::visitWasmBoundsCheck(MWasm
     MOZ_ASSERT(!ins->isRedundant());
 
     MDefinition* index = ins->index();
     MOZ_ASSERT(index->type() == MIRType::Int32);
 
     MDefinition* boundsCheckLimit = ins->boundsCheckLimit();
     MOZ_ASSERT(boundsCheckLimit->type() == MIRType::Int32);
 
-    auto* lir = new(alloc()) LWasmBoundsCheck(useRegisterAtStart(index),
-                                              useRegisterAtStart(boundsCheckLimit));
-    add(lir, ins);
+
+    if (JitOptions.spectreIndexMasking) {
+        auto* lir = new(alloc()) LWasmBoundsCheck(useRegisterAtStart(index),
+                                                  useRegister(boundsCheckLimit));
+        defineReuseInput(lir, ins, 0);
+    } else {
+        auto* lir = new(alloc()) LWasmBoundsCheck(useRegisterAtStart(index),
+                                                  useRegisterAtStart(boundsCheckLimit));
+        add(lir, ins);
+    }
 #endif
 }
 
 void
 LIRGenerator::visitWasmAlignmentCheck(MWasmAlignmentCheck* ins)
 {
     MDefinition* index = ins->index();
     MOZ_ASSERT(index->type() == MIRType::Int32);
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -14231,16 +14231,19 @@ class MWasmBoundsCheck
 
     explicit MWasmBoundsCheck(MDefinition* index, MDefinition* boundsCheckLimit,
                               wasm::BytecodeOffset bytecodeOffset)
       : MBinaryInstruction(classOpcode, index, boundsCheckLimit),
         bytecodeOffset_(bytecodeOffset)
     {
         // Bounds check is effectful: it throws for OOB.
         setGuard();
+
+        if (JitOptions.spectreIndexMasking)
+            setResultType(MIRType::Int32);
     }
 
   public:
     INSTRUCTION_HEADER(WasmBoundsCheck)
     TRIVIAL_NEW_WRAPPERS
     NAMED_OPERANDS((0, index), (1, boundsCheckLimit))
 
     AliasSet getAliasSet() const override {
--- a/js/src/jit/MacroAssembler.h
+++ b/js/src/jit/MacroAssembler.h
@@ -1465,18 +1465,20 @@ class MacroAssembler : public MacroAssem
   public:
     // ========================================================================
     // wasm support
 
     CodeOffset wasmTrapInstruction() PER_SHARED_ARCH;
 
     void wasmTrap(wasm::Trap trap, wasm::BytecodeOffset bytecodeOffset);
 
-    // Emit a bounds check against the wasm heap limit, jumping to 'label' if 'cond' holds.
-    // Required when WASM_HUGE_MEMORY is not defined.
+    // Emit a bounds check against the wasm heap limit, jumping to 'label' if
+    // 'cond' holds. Required when WASM_HUGE_MEMORY is not defined. If
+    // JitOptions.spectreMaskIndex is true, in speculative executions 'index' is
+    // saturated in-place to 'boundsCheckLimit'.
     template <class L>
     inline void wasmBoundsCheck(Condition cond, Register index, Register boundsCheckLimit, L label)
         DEFINED_ON(arm, arm64, mips32, mips64, x86);
 
     template <class L>
     inline void wasmBoundsCheck(Condition cond, Register index, Address boundsCheckLimit, L label)
         DEFINED_ON(arm, arm64, mips32, mips64, x86);
 
--- a/js/src/jit/WasmBCE.cpp
+++ b/js/src/jit/WasmBCE.cpp
@@ -10,16 +10,18 @@
 
 using namespace js;
 using namespace js::jit;
 using namespace mozilla;
 
 typedef js::HashMap<uint32_t, MDefinition*, DefaultHasher<uint32_t>, SystemAllocPolicy>
     LastSeenMap;
 
+unsigned redundantCount = 0;
+
 // The Wasm Bounds Check Elimination (BCE) pass looks for bounds checks
 // on SSA values that have already been checked. (in the same block or in a
 // dominating block). These bounds checks are redundant and thus eliminated.
 //
 // Note: This is safe in the presense of dynamic memory sizes as long as they
 // can ONLY GROW. If we allow SHRINKING the heap, this pass should be
 // RECONSIDERED.
 //
@@ -55,23 +57,35 @@ jit::EliminateBoundsChecks(MIRGenerator*
                 MOZ_ASSERT(wasm::MaxMemoryAccessSize < wasm::GuardSize,
                            "Guard page handles partial out-of-bounds");
 #endif
 
                 if (addr->isConstant() && addr->toConstant()->type() == MIRType::Int32 &&
                     uint32_t(addr->toConstant()->toInt32()) < mir->minWasmHeapLength())
                 {
                     bc->setRedundant();
+                    redundantCount++;
+                    if (JitOptions.spectreIndexMasking)
+                        bc->replaceAllUsesWith(addr);
+                    else
+                        MOZ_ASSERT(!bc->hasUses());
                 }
                 else
                 {
                     LastSeenMap::AddPtr ptr = lastSeen.lookupForAdd(addr->id());
                     if (ptr) {
-                        if (ptr->value()->block()->dominates(block))
+                        MDefinition* prevCheckOrPhi = ptr->value();
+                        if (prevCheckOrPhi->block()->dominates(block)) {
                             bc->setRedundant();
+                            redundantCount++;
+                            if (JitOptions.spectreIndexMasking)
+                                bc->replaceAllUsesWith(prevCheckOrPhi);
+                            else
+                                MOZ_ASSERT(!bc->hasUses());
+                        }
                     } else {
                         if (!lastSeen.add(ptr, addr->id(), def))
                             return false;
                     }
                 }
                 break;
               }
               case MDefinition::Opcode::Phi: {
@@ -85,16 +99,23 @@ jit::EliminateBoundsChecks(MIRGenerator*
                 // phi node checked.
                 //
                 // Note that any phi that is part of a cycle
                 // will not be "safe" since the value coming on the backedge
                 // cannot be in lastSeen because its block hasn't been traversed yet.
                 for (int i = 0, nOps = phi->numOperands(); i < nOps; i++) {
                     MDefinition* src = phi->getOperand(i);
 
+                    if (JitOptions.spectreIndexMasking) {
+                        if (src->isWasmBoundsCheck())
+                            src = src->toWasmBoundsCheck()->index();
+                    } else {
+                        MOZ_ASSERT(!src->isWasmBoundsCheck());
+                    }
+
                     LastSeenMap::Ptr checkPtr = lastSeen.lookup(src->id());
                     if (!checkPtr || !checkPtr->value()->block()->dominates(block)) {
                         phiChecked = false;
                         break;
                     }
                 }
 
                 if (phiChecked) {
--- a/js/src/jit/arm/MacroAssembler-arm-inl.h
+++ b/js/src/jit/arm/MacroAssembler-arm-inl.h
@@ -2296,27 +2296,31 @@ MacroAssembler::clampIntToUint8(Register
 // wasm support
 
 template <class L>
 void
 MacroAssembler::wasmBoundsCheck(Condition cond, Register index, Register boundsCheckLimit, L label)
 {
     as_cmp(index, O2Reg(boundsCheckLimit));
     as_b(label, cond);
+    if (JitOptions.spectreIndexMasking)
+        ma_mov(boundsCheckLimit, index, LeaveCC, cond);
 }
 
 template <class L>
 void
 MacroAssembler::wasmBoundsCheck(Condition cond, Register index, Address boundsCheckLimit, L label)
 {
     ScratchRegisterScope scratch(*this);
     MOZ_ASSERT(boundsCheckLimit.offset == offsetof(wasm::TlsData, boundsCheckLimit));
     ma_ldr(DTRAddr(boundsCheckLimit.base, DtrOffImm(boundsCheckLimit.offset)), scratch);
     as_cmp(index, O2Reg(scratch));
     as_b(label, cond);
+    if (JitOptions.spectreIndexMasking)
+        ma_mov(scratch, index, LeaveCC, cond);
 }
 
 //}}} check_macroassembler_style
 // ===============================================================
 
 void
 MacroAssemblerARMCompat::incrementInt32Value(const Address& addr)
 {
--- a/js/src/jit/shared/LIR-shared.h
+++ b/js/src/jit/shared/LIR-shared.h
@@ -8423,17 +8423,17 @@ class LWasmAddOffset : public LInstructi
     MWasmAddOffset* mir() const {
         return mir_->toWasmAddOffset();
     }
     const LAllocation* base() {
         return getOperand(0);
     }
 };
 
-class LWasmBoundsCheck : public LInstructionHelper<0, 2, 0>
+class LWasmBoundsCheck : public LInstructionHelper<1, 2, 0>
 {
   public:
     LIR_HEADER(WasmBoundsCheck);
     explicit LWasmBoundsCheck(const LAllocation& ptr,
                               const LAllocation& boundsCheckLimit = LAllocation())
     {
         setOperand(0, ptr);
         setOperand(1, boundsCheckLimit);
--- a/js/src/jit/x86/MacroAssembler-x86-inl.h
+++ b/js/src/jit/x86/MacroAssembler-x86-inl.h
@@ -1104,24 +1104,28 @@ MacroAssembler::truncateDoubleToUInt64(A
 // wasm support
 
 template <class L>
 void
 MacroAssembler::wasmBoundsCheck(Condition cond, Register index, Register boundsCheckLimit, L label)
 {
     cmp32(index, boundsCheckLimit);
     j(cond, label);
+    if (JitOptions.spectreIndexMasking)
+        cmovCCl(cond, Operand(boundsCheckLimit), index);
 }
 
 template <class L>
 void
 MacroAssembler::wasmBoundsCheck(Condition cond, Register index, Address boundsCheckLimit, L label)
 {
     cmp32(index, Operand(boundsCheckLimit));
     j(cond, label);
+    if (JitOptions.spectreIndexMasking)
+        cmovCCl(cond, Operand(boundsCheckLimit), index);
 }
 
 //}}} check_macroassembler_style
 // ===============================================================
 
 // Note: this function clobbers the source register.
 void
 MacroAssemblerX86::convertUInt32ToDouble(Register src, FloatRegister dest)
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -1678,21 +1678,21 @@ class ReservedRooted : public RootedBase
     DECLARE_POINTER_ASSIGN_OPS(ReservedRooted, T)
 };
 
 void
 js::ReportInNotObjectError(JSContext* cx, HandleValue lref, int lindex,
                            HandleValue rref, int rindex)
 {
     auto uniqueCharsFromString = [](JSContext* cx, HandleValue ref) -> UniqueChars {
-        static const size_t MAX_STRING_LENGTH = 16;
+        static const size_t MaxStringLength = 16;
         RootedString str(cx, ref.toString());
-        if (str->length() > MAX_STRING_LENGTH) {
+        if (str->length() > MaxStringLength) {
             StringBuffer buf(cx);
-            if (!buf.appendSubstring(str, 0, MAX_STRING_LENGTH))
+            if (!buf.appendSubstring(str, 0, MaxStringLength))
                 return nullptr;
             if (!buf.append("..."))
                 return nullptr;
             str = buf.finishString();
             if (!str)
                 return nullptr;
         }
         return UniqueChars(JS_EncodeString(cx, str));
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -37,16 +37,17 @@
 #include "gc/HashUtil.h"
 #include "gc/Marking.h"
 #include "gc/Policy.h"
 #include "jit/AtomicOperations.h"
 #include "jit/InlinableNatives.h"
 #include "js/CharacterEncoding.h"
 #include "js/Date.h"
 #include "js/Wrapper.h"
+#include "vm/ArgumentsObject.h"
 #include "vm/Compression.h"
 #include "vm/GeneratorObject.h"
 #include "vm/Interpreter.h"
 #include "vm/Iteration.h"
 #include "vm/JSCompartment.h"
 #include "vm/JSContext.h"
 #include "vm/JSFunction.h"
 #include "vm/Printer.h"
@@ -3189,8 +3190,14 @@ js::GetSelfHostedFunctionName(JSFunction
     if (!name.isString())
         return nullptr;
     return &name.toString()->asAtom();
 }
 
 static_assert(JSString::MAX_LENGTH <= INT32_MAX,
               "StringIteratorNext in builtin/String.js assumes the stored index "
               "into the string is an Int32Value");
+
+static_assert(JSString::MAX_LENGTH == MAX_STRING_LENGTH,
+              "JSString::MAX_LENGTH matches self-hosted constant for maximum string length");
+
+static_assert(ARGS_LENGTH_MAX == MAX_ARGS_LENGTH,
+              "ARGS_LENGTH_MAX matches self-hosted constant for maximum arguments length");
--- a/js/src/vm/StructuredClone.cpp
+++ b/js/src/vm/StructuredClone.cpp
@@ -1,35 +1,34 @@
 /* -*- 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/. */
 
 /*
- * This file implements the structured clone algorithm of
- * http://www.whatwg.org/specs/web-apps/current-work/multipage/common-dom-interfaces.html#safe-passing-of-structured-data
+ * This file implements the structured data algorithms of
+ * https://html.spec.whatwg.org/multipage/structured-data.html
+ *
+ * The spec is in two parts:
  *
- * The implementation differs slightly in that it uses an explicit stack, and
- * the "memory" maps source objects to sequential integer indexes rather than
- * directly pointing to destination objects. As a result, the order in which
- * things are added to the memory must exactly match the order in which they
- * are placed into 'allObjs', an analogous array of back-referenceable
- * destination objects constructed while reading.
+ * -   StructuredSerialize examines a JS value and produces a graph of Records.
+ * -   StructuredDeserialize walks the Records and produces a new JS value.
+ *
+ * The differences between our implementation and the spec are minor:
  *
- * For the most part, this is easy: simply add objects to the memory when first
- * encountering them. But reading in a typed array requires an ArrayBuffer for
- * construction, so objects cannot just be added to 'allObjs' in the order they
- * are created. If they were, ArrayBuffers would come before typed arrays when
- * in fact the typed array was added to 'memory' first.
- *
- * So during writing, we add objects to the memory when first encountering
- * them. When reading a typed array, a placeholder is pushed onto allObjs until
- * the ArrayBuffer has been read, then it is updated with the actual typed
- * array object.
+ * -   We call the two phases "write" and "read".
+ * -   Our algorithms use an explicit work stack, rather than recursion.
+ * -   Serialized data is a flat array of bytes, not a (possibly cyclic) graph
+ *     of "Records".
+ * -   As a consequence, we handle non-treelike object graphs differently.
+ *     We serialize objects that appear in multiple places in the input as
+ *     backreferences, using sequential integer indexes.
+ *     See `JSStructuredCloneReader::allObjs`, our take on the "memory" map
+ *     in the spec's StructuredDeserialize.
  */
 
 #include "js/StructuredClone.h"
 
 #include "mozilla/CheckedInt.h"
 #include "mozilla/EndianUtils.h"
 #include "mozilla/FloatingPoint.h"
 
@@ -66,17 +65,17 @@ using JS::CanonicalizeNaN;
 // likely need to increment the version if anything at all changes in the serialization
 // format.
 //
 // Note that SCTAG_END_OF_KEYS is written into the serialized form and should have
 // a stable ID, it need not be at the end of the list and should not be used for
 // sizing data structures.
 
 enum StructuredDataType : uint32_t {
-    /* Structured data types provided by the engine */
+    // Structured data types provided by the engine
     SCTAG_FLOAT_MAX = 0xFFF00000,
     SCTAG_HEADER = 0xFFF10000,
     SCTAG_NULL = 0xFFFF0000,
     SCTAG_UNDEFINED,
     SCTAG_BOOLEAN,
     SCTAG_INT32,
     SCTAG_STRING,
     SCTAG_DATE_OBJECT,
@@ -114,21 +113,19 @@ enum StructuredDataType : uint32_t {
     SCTAG_TYPED_ARRAY_V1_UINT16 = SCTAG_TYPED_ARRAY_V1_MIN + Scalar::Uint16,
     SCTAG_TYPED_ARRAY_V1_INT32 = SCTAG_TYPED_ARRAY_V1_MIN + Scalar::Int32,
     SCTAG_TYPED_ARRAY_V1_UINT32 = SCTAG_TYPED_ARRAY_V1_MIN + Scalar::Uint32,
     SCTAG_TYPED_ARRAY_V1_FLOAT32 = SCTAG_TYPED_ARRAY_V1_MIN + Scalar::Float32,
     SCTAG_TYPED_ARRAY_V1_FLOAT64 = SCTAG_TYPED_ARRAY_V1_MIN + Scalar::Float64,
     SCTAG_TYPED_ARRAY_V1_UINT8_CLAMPED = SCTAG_TYPED_ARRAY_V1_MIN + Scalar::Uint8Clamped,
     SCTAG_TYPED_ARRAY_V1_MAX = SCTAG_TYPED_ARRAY_V1_MIN + Scalar::MaxTypedArrayViewType - 1,
 
-    /*
-     * Define a separate range of numbers for Transferable-only tags, since
-     * they are not used for persistent clone buffers and therefore do not
-     * require bumping JS_STRUCTURED_CLONE_VERSION.
-     */
+    // Define a separate range of numbers for Transferable-only tags, since
+    // they are not used for persistent clone buffers and therefore do not
+    // require bumping JS_STRUCTURED_CLONE_VERSION.
     SCTAG_TRANSFER_MAP_HEADER = 0xFFFF0200,
     SCTAG_TRANSFER_MAP_PENDING_ENTRY,
     SCTAG_TRANSFER_MAP_ARRAY_BUFFER,
     SCTAG_TRANSFER_MAP_STORED_ARRAY_BUFFER,
     SCTAG_TRANSFER_MAP_END_OF_BUILTIN_TYPES,
 
     SCTAG_END_OF_BUILTIN_TYPES
 };
@@ -375,17 +372,17 @@ class SCInput {
         JS_STATIC_ASSERT(sizeof(char16_t) == 2);
         JS_STATIC_ASSERT(sizeof(uint32_t) == 4);
     }
 
     JSContext* cx;
     BufferIterator point;
 };
 
-} /* namespace js */
+} // namespace js
 
 struct JSStructuredCloneReader {
   public:
     explicit JSStructuredCloneReader(SCInput& in, JS::StructuredCloneScope scope,
                                      const JSStructuredCloneCallbacks* cb,
                                      void* cbClosure)
         : in(in), allowedScope(scope), objs(in.context()), allObjs(in.context()),
           callbacks(cb), closure(cbClosure) { }
@@ -427,17 +424,27 @@ struct JSStructuredCloneReader {
     // format (eg a Transferred ArrayBuffer can be stored as a pointer for
     // SameProcessSameThread but must have its contents in the clone buffer for
     // DifferentProcess.)
     JS::StructuredCloneScope storedScope;
 
     // Stack of objects with properties remaining to be read.
     AutoValueVector objs;
 
-    // Stack of all objects read during this deserialization
+    // Array of all objects read during this deserialization, for resolving
+    // backreferences.
+    //
+    // For backreferences to work correctly, objects must be added to this
+    // array in exactly the order expected by the version of the Writer that
+    // created the serialized data, even across years and format versions. This
+    // is usually no problem, since both algorithms do a single linear pass
+    // over the serialized data. There is one hitch; see readTypedArray.
+    //
+    // The values in this vector are objects, except it can temporarily have
+    // one `undefined` placeholder value (the readTypedArray hack).
     AutoValueVector allObjs;
 
     // The user defined callbacks that will be used for cloning.
     const JSStructuredCloneCallbacks* callbacks;
 
     // Any value passed to JS_ReadStructuredClone.
     void* closure;
 
@@ -731,29 +738,29 @@ SCInput::SCInput(JSContext* cx, JSStruct
                   "structured clone buffer reads should be aligned");
     MOZ_ASSERT(data.Size() % 8 == 0);
 }
 
 bool
 SCInput::read(uint64_t* p)
 {
     if (!point.canPeek()) {
-        *p = 0;  /* initialize to shut GCC up */
+        *p = 0;  // initialize to shut GCC up
         return reportTruncated();
     }
     *p = NativeEndian::swapFromLittleEndian(point.peek());
     point.next();
     return true;
 }
 
 bool
 SCInput::readNativeEndian(uint64_t* p)
 {
     if (!point.canPeek()) {
-        *p = 0;  /* initialize to shut GCC up */
+        *p = 0;  // initialize to shut GCC up
         return reportTruncated();
     }
     *p = point.peek();
     point.next();
     return true;
 }
 
 bool
@@ -839,19 +846,17 @@ template <class T>
 bool
 SCInput::readArray(T* p, size_t nelems)
 {
     if (!nelems)
         return true;
 
     JS_STATIC_ASSERT(sizeof(uint64_t) % sizeof(T) == 0);
 
-    /*
-     * Fail if nelems is so huge that computing the full size will overflow.
-     */
+    // Fail if nelems is so huge that computing the full size will overflow.
     mozilla::CheckedInt<size_t> size = mozilla::CheckedInt<size_t>(nelems) * sizeof(T);
     if (!size.isValid())
         return reportTruncated();
 
     if (!point.readBytes(reinterpret_cast<char*>(p), size.value()))
         return false;
 
     swapFromLittleEndianInPlace(p, nelems);
@@ -910,25 +915,23 @@ SCOutput::write(uint64_t u)
 {
     uint64_t v = NativeEndian::swapToLittleEndian(u);
     return buf.WriteBytes(reinterpret_cast<char*>(&v), sizeof(u));
 }
 
 bool
 SCOutput::writePair(uint32_t tag, uint32_t data)
 {
-    /*
-     * As it happens, the tag word appears after the data word in the output.
-     * This is because exponents occupy the last 2 bytes of doubles on the
-     * little-endian platforms we care most about.
-     *
-     * For example, TrueValue() is written using writePair(SCTAG_BOOLEAN, 1).
-     * PairToUInt64 produces the number 0xFFFF000200000001.
-     * That is written out as the bytes 01 00 00 00 02 00 FF FF.
-     */
+    // As it happens, the tag word appears after the data word in the output.
+    // This is because exponents occupy the last 2 bytes of doubles on the
+    // little-endian platforms we care most about.
+    //
+    // For example, TrueValue() is written using writePair(SCTAG_BOOLEAN, 1).
+    // PairToUInt64 produces the number 0xFFFF000200000001.
+    // That is written out as the bytes 01 00 00 00 02 00 FF FF.
     return write(PairToUInt64(tag, data));
 }
 
 static inline double
 ReinterpretPairAsDouble(uint32_t tag, uint32_t data)
 {
     return BitwiseCast<double>(PairToUInt64(tag, data));
 }
@@ -1026,17 +1029,17 @@ SCOutput::extractBuffer(JSStructuredClon
 }
 
 void
 SCOutput::discardTransferables(const JSStructuredCloneCallbacks* cb, void* cbClosure)
 {
     DiscardTransferables(buf, cb, cbClosure);
 }
 
-} /* namespace js */
+} // namespace js
 
 JSStructuredCloneData::~JSStructuredCloneData()
 {
     if (!Size())
         return;
     if (ownTransferables_ == OwnTransferablePolicy::OwnsTransferablesIfAny)
         DiscardTransferables(*this, callbacks_, closure_);
 }
@@ -1147,17 +1150,17 @@ JSStructuredCloneWriter::writeString(uin
            ? out.writeChars(linear->latin1Chars(nogc), length)
            : out.writeChars(linear->twoByteChars(nogc), length);
 }
 
 inline void
 JSStructuredCloneWriter::checkStack()
 {
 #ifdef DEBUG
-    /* To avoid making serialization O(n^2), limit stack-checking at 10. */
+    // To avoid making serialization O(n^2), limit stack-checking at 10.
     const size_t MAX = 10;
 
     size_t limit = Min(counts.length(), MAX);
     MOZ_ASSERT(objs.length() == counts.length());
     size_t total = 0;
     for (size_t i = 0; i < limit; i++) {
         MOZ_ASSERT(total + counts[i] >= total);
         total += counts[i];
@@ -1291,17 +1294,17 @@ JSStructuredCloneWriter::writeSharedWasm
 
     return out.writePair(SCTAG_SHARED_WASM_MEMORY_OBJECT, 0) &&
            writeSharedArrayBuffer(sab);
 }
 
 bool
 JSStructuredCloneWriter::startObject(HandleObject obj, bool* backref)
 {
-    /* Handle cycles in the object graph. */
+    // Handle cycles in the object graph.
     CloneMemory::AddPtr p = memory.lookupForAdd(obj);
     if ((*backref = p.found()))
         return out.writePair(SCTAG_BACK_REFERENCE_OBJECT, p->value());
     if (!memory.add(p, obj, memory.count())) {
         ReportOutOfMemory(context());
         return false;
     }
 
@@ -1312,38 +1315,36 @@ JSStructuredCloneWriter::startObject(Han
     }
 
     return true;
 }
 
 bool
 JSStructuredCloneWriter::traverseObject(HandleObject obj)
 {
-    /*
-     * Get enumerable property ids and put them in reverse order so that they
-     * will come off the stack in forward order.
-     */
+    // Get enumerable property ids and put them in reverse order so that they
+    // will come off the stack in forward order.
     AutoIdVector properties(context());
     if (!GetPropertyKeys(context(), obj, JSITER_OWNONLY, &properties))
         return false;
 
     for (size_t i = properties.length(); i > 0; --i) {
         MOZ_ASSERT(JSID_IS_STRING(properties[i - 1]) || JSID_IS_INT(properties[i - 1]));
         RootedValue val(context(), IdToValue(properties[i - 1]));
         if (!entries.append(val))
             return false;
     }
 
-    /* Push obj and count to the stack. */
+    // Push obj and count to the stack.
     if (!objs.append(ObjectValue(*obj)) || !counts.append(properties.length()))
         return false;
 
     checkStack();
 
-    /* Write the header for obj. */
+    // Write the header for obj.
     ESClass cls;
     if (!GetBuiltinClass(context(), obj, &cls))
         return false;
     return out.writePair(cls == ESClass::Array ? SCTAG_ARRAY_OBJECT : SCTAG_OBJECT_OBJECT, 0);
 }
 
 bool
 JSStructuredCloneWriter::traverseMap(HandleObject obj)
@@ -1360,23 +1361,23 @@ JSStructuredCloneWriter::traverseMap(Han
     if (!context()->compartment()->wrap(context(), &newEntries))
         return false;
 
     for (size_t i = newEntries.length(); i > 0; --i) {
         if (!entries.append(newEntries[i - 1]))
             return false;
     }
 
-    /* Push obj and count to the stack. */
+    // Push obj and count to the stack.
     if (!objs.append(ObjectValue(*obj)) || !counts.append(newEntries.length()))
         return false;
 
     checkStack();
 
-    /* Write the header for obj. */
+    // Write the header for obj.
     return out.writePair(SCTAG_MAP_OBJECT, 0);
 }
 
 bool
 JSStructuredCloneWriter::traverseSet(HandleObject obj)
 {
     Rooted<GCVector<Value>> keys(context(), GCVector<Value>(context()));
     {
@@ -1390,23 +1391,23 @@ JSStructuredCloneWriter::traverseSet(Han
     if (!context()->compartment()->wrap(context(), &keys))
         return false;
 
     for (size_t i = keys.length(); i > 0; --i) {
         if (!entries.append(keys[i - 1]))
             return false;
     }
 
-    /* Push obj and count to the stack. */
+    // Push obj and count to the stack.
     if (!objs.append(ObjectValue(*obj)) || !counts.append(keys.length()))
         return false;
 
     checkStack();
 
-    /* Write the header for obj. */
+    // Write the header for obj.
     return out.writePair(SCTAG_SET_OBJECT, 0);
 }
 
 // Objects are written as a "preorder" traversal of the object graph: object
 // "headers" (the class tag and any data needed for initial construction) are
 // visited first, then the children are recursed through (where children are
 // properties, Set or Map entries, etc.). So for example
 //
@@ -1582,17 +1583,17 @@ JSStructuredCloneWriter::startWrite(Hand
         } else if (cls == ESClass::Set) {
             return traverseSet(obj);
         } else if (SavedFrame::isSavedFrameOrWrapperAndNotProto(*obj)) {
             return traverseSavedFrame(obj);
         }
 
         if (callbacks && callbacks->write)
             return callbacks->write(context(), this, obj, closure);
-        /* else fall through */
+        // else fall through
     }
 
     return reportDataCloneError(JS_SCERR_UNSUPPORTED_TYPE);
 }
 
 bool
 JSStructuredCloneWriter::writeHeader()
 {
@@ -1781,21 +1782,19 @@ JSStructuredCloneWriter::write(HandleVal
                 if (!startWrite(key))
                     return false;
             } else {
                 RootedId id(context());
                 if (!ValueToId<CanGC>(context(), key, &id))
                   return false;
                 MOZ_ASSERT(JSID_IS_STRING(id) || JSID_IS_INT(id));
 
-                /*
-                 * If obj still has an own property named id, write it out.
-                 * The cost of re-checking could be avoided by using
-                 * NativeIterators.
-                 */
+                // If obj still has an own property named id, write it out.
+                // The cost of re-checking could be avoided by using
+                // NativeIterators.
                 bool found;
                 if (!HasOwnProperty(context(), obj, id, &found))
                     return false;
 
                 if (found) {
                     RootedValue val(context());
                     if (!startWrite(key) ||
                         !GetProperty(context(), obj, obj, id, &val) ||
@@ -1847,17 +1846,17 @@ class Chars {
             return true;
         }
         return false;
     }
     CharT* get() { return p; }
     void forget() { p = nullptr; }
 };
 
-} /* anonymous namespace */
+} // anonymous namespace
 
 template <typename CharT>
 JSString*
 JSStructuredCloneReader::readStringImpl(uint32_t nchars)
 {
     if (nchars > JSString::MAX_LENGTH) {
         JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr, JSMSG_SC_BAD_SERIALIZED_DATA,
                                   "string length");
@@ -1892,17 +1891,17 @@ JSStructuredCloneReader::readTypedArray(
                                         bool v1Read)
 {
     if (arrayType > Scalar::Uint8Clamped) {
         JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr, JSMSG_SC_BAD_SERIALIZED_DATA,
                                   "unhandled typed array element type");
         return false;
     }
 
-    // Push a placeholder onto the allObjs list to stand in for the typed array
+    // Push a placeholder onto the allObjs list to stand in for the typed array.
     uint32_t placeholderIndex = allObjs.length();
     Value dummy = UndefinedValue();
     if (!allObjs.append(dummy))
         return false;
 
     // Read the ArrayBuffer object and its contents (but no properties)
     RootedValue v(context());
     uint32_t byteOffset;
--- a/js/src/wasm/WasmCompile.cpp
+++ b/js/src/wasm/WasmCompile.cpp
@@ -409,16 +409,18 @@ InitialCompileFlags(const CompileArgs& a
     } else {
         *mode = CompileMode::Once;
         *tier = debugEnabled || !ionEnabled ? Tier::Baseline : Tier::Ion;
     }
 
     *debug = debugEnabled ? DebugEnabled::True : DebugEnabled::False;
 }
 
+extern unsigned redundantCount;
+
 SharedModule
 wasm::CompileBuffer(const CompileArgs& args, const ShareableBytes& bytecode, UniqueChars* error)
 {
     MOZ_RELEASE_ASSERT(wasm::HaveSignalHandlers());
 
     Decoder d(bytecode.bytes, 0, error);
 
     CompileMode mode;
@@ -436,17 +438,21 @@ wasm::CompileBuffer(const CompileArgs& a
         return nullptr;
 
     if (!DecodeCodeSection(env, d, mg))
         return nullptr;
 
     if (!DecodeModuleTail(d, &env))
         return nullptr;
 
-    return mg.finishModule(bytecode);
+    auto module = mg.finishModule(bytecode);
+
+    printf("# redundant: %u\n", redundantCount);
+
+    return module;
 }
 
 bool
 wasm::CompileTier2(const CompileArgs& args, Module& module, Atomic<bool>* cancelled)
 {
     MOZ_RELEASE_ASSERT(wasm::HaveSignalHandlers());
 
     UniqueChars error;
--- a/js/src/wasm/WasmIonCompile.cpp
+++ b/js/src/wasm/WasmIonCompile.cpp
@@ -827,18 +827,22 @@ class FunctionCompiler
             *base = computeEffectiveAddress(*base, access);
 
         if (alignmentCheck) {
             curBlock_->add(MWasmAlignmentCheck::New(alloc(), *base, access->byteSize(),
                                                     bytecodeOffset()));
         }
 
         MWasmLoadTls* boundsCheckLimit = maybeLoadBoundsCheckLimit();
-        if (boundsCheckLimit)
-            curBlock_->add(MWasmBoundsCheck::New(alloc(), *base, boundsCheckLimit, bytecodeOffset()));
+        if (boundsCheckLimit) {
+            auto* ins = MWasmBoundsCheck::New(alloc(), *base, boundsCheckLimit, bytecodeOffset());
+            curBlock_->add(ins);
+            if (JitOptions.spectreIndexMasking)
+                *base = ins;
+        }
     }
 
     bool isSmallerAccessForI64(ValType result, const MemoryAccessDesc* access) {
         if (result == ValType::I64 && access->byteSize() <= 4) {
             // These smaller accesses should all be zero-extending.
             MOZ_ASSERT(!isSignedIntType(access->type()));
             return true;
         }
--- a/mobile/android/geckoview/build.gradle
+++ b/mobile/android/geckoview/build.gradle
@@ -179,27 +179,29 @@ android.libraryVariants.all { variant ->
     // and amended from numerous Stackoverflow posts.
     def name = variant.name
     def javadoc = task "javadoc${name.capitalize()}"(type: Javadoc) {
         description = "Generate Javadoc for build variant $name"
         destinationDir = new File(destinationDir, variant.baseName)
         classpath = files(variant.javaCompile.classpath.files)
 
         source = files(variant.javaCompile.source)
-        exclude '**/R.java', '**/BuildConfig.java', 'com/google/**', 'org/webrtc/**'
+        exclude '**/R.java', '**/BuildConfig.java'
+        include 'org/mozilla/geckoview/**'
         options.addPathOption('sourcepath', ':').setValue(
             variant.sourceSets.collect({ it.javaDirectories }).flatten() +
             variant.generateBuildConfig.sourceOutputDir)
 
         // javadoc 8 has a bug that requires the rt.jar file from the JRE to be
         // in the bootclasspath (https://stackoverflow.com/a/30458820).
         options.bootClasspath = [
             file("${System.properties['java.home']}/lib/rt.jar")] + android.bootClasspath
         options.memberLevel = JavadocMemberLevel.PROTECTED
         options.source = 7
+        options.links("https://d.android.com/reference/")
 
         options.docTitle = "GeckoView ${mozconfig.substs.MOZ_APP_VERSION} API"
         options.header = "GeckoView ${mozconfig.substs.MOZ_APP_VERSION} API"
         options.noTimestamp = true
         options.noIndex = true
         options.noQualifiers = ['java.lang']
         options.tags = ['hide:a:']
     }
--- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java
@@ -348,17 +348,17 @@ public class GeckoSession extends LayerS
     public void setPermissionDelegate(final PermissionDelegate delegate) {
         mPermissionHandler.setListener(delegate, this);
     }
 
     private PromptDelegate mPromptDelegate;
 
     private final Listener mListener = new Listener();
 
-    protected static final class Window extends JNIObject implements IInterface {
+    /* package */ static final class Window extends JNIObject implements IInterface {
         private NativeQueue mNativeQueue;
         private Binder mBinder;
 
         public Window(final NativeQueue nativeQueue) {
             mNativeQueue = nativeQueue;
         }
 
         @Override // IInterface
@@ -1400,27 +1400,16 @@ public class GeckoSession extends LayerS
                     NEW,
                     NEW,
                     NEW
                 };
                 return sMap[value];
             }
         }
 
-        enum LoadUriResult {
-            HANDLED(0),
-            LOAD_IN_FRAME(1);
-
-            private int mValue;
-
-            private LoadUriResult(int value) {
-                mValue = value;
-            }
-        }
-
         /**
         * A request to open an URI.
         * @param session The GeckoSession that initiated the callback.
         * @param uri The URI to be loaded.
         * @param where The target window.
         *
         * @return Whether or not the load was handled. Returning false will allow Gecko
         *         to continue the load as normal.
--- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/TextInputController.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/TextInputController.java
@@ -102,17 +102,17 @@ public final class TextInputController {
 
     public TextInputController(final @NonNull GeckoSession session,
                                final @NonNull NativeQueue queue) {
         mSession = session;
         mQueue = queue;
         mEditable.setDefaultEditableChild(mEditableChild);
     }
 
-    public void onWindowChanged(final GeckoSession.Window window) {
+    /* package */ void onWindowChanged(final GeckoSession.Window window) {
         if (mQueue.isReady()) {
             window.attachEditable(mEditable, mEditableChild);
         } else {
             mQueue.queueUntilReady(window, "attachEditable",
                                    IGeckoEditableParent.class, mEditable,
                                    GeckoEditableChild.class, mEditableChild);
         }
     }
--- a/modules/libpref/Preferences.cpp
+++ b/modules/libpref/Preferences.cpp
@@ -321,34 +321,40 @@ struct PrefsSizes
 };
 }
 
 static ArenaAllocator<8192, 1> gPrefNameArena;
 
 class Pref
 {
 public:
-  explicit Pref()
-    : mType(static_cast<uint32_t>(PrefType::None))
+  explicit Pref(const char* aName)
+    : mName(ArenaStrdup(aName, gPrefNameArena))
+    , mType(static_cast<uint32_t>(PrefType::None))
     , mIsSticky(false)
     , mIsLocked(false)
     , mHasDefaultValue(false)
     , mHasUserValue(false)
     , mHasChangedSinceInit(false)
     , mDefaultValue()
     , mUserValue()
   {
   }
 
   ~Pref()
   {
+    // There's no need to free mName because it's allocated in memory owned by
+    // gPrefNameArena.
+
     mDefaultValue.Clear(Type());
     mUserValue.Clear(Type());
   }
 
+  const char* Name() { return mName; }
+
   // Types.
 
   PrefType Type() const { return static_cast<PrefType>(mType); }
   void SetType(PrefType aType) { mType = static_cast<uint32_t>(aType); }
 
   bool IsType(PrefType aType) const { return Type() == aType; }
   bool IsTypeNone() const { return IsType(PrefType::None); }
   bool IsTypeString() const { return IsType(PrefType::String); }
@@ -390,16 +396,25 @@ public:
   bool MustSendToContentProcesses() const
   {
     MOZ_ASSERT(XRE_IsParentProcess());
     return mHasUserValue || mHasChangedSinceInit;
   }
 
   // Other operations.
 
+  bool MatchEntry(const char* aPrefName)
+  {
+    if (!mName || !aPrefName) {
+      return false;
+    }
+
+    return strcmp(mName, aPrefName) == 0;
+  }
+
   nsresult GetBoolValue(PrefValueKind aKind, bool* aResult)
   {
     if (!IsTypeBool()) {
       return NS_ERROR_UNEXPECTED;
     }
 
     if (aKind == PrefValueKind::Default || IsLocked() || !mHasUserValue) {
       // Do we have a default?
@@ -449,26 +464,21 @@ public:
     } else {
       MOZ_ASSERT(mUserValue.mStringVal);
       aResult = mUserValue.mStringVal;
     }
 
     return NS_OK;
   }
 
-  // Fills out a dom pref with the values from this pref.
-  // @param aDomPref The pref to update.
-  // @param aName Optional. Override the dom pref's name with aName.
-  void ToDomPref(dom::Pref* aDomPref, const char* aName = nullptr)
+  void ToDomPref(dom::Pref* aDomPref)
   {
     MOZ_ASSERT(XRE_IsParentProcess());
 
-    if (aName) {
-      aDomPref->name() = aName;
-    }
+    aDomPref->name() = mName;
 
     aDomPref->isLocked() = mIsLocked;
 
     if (mHasDefaultValue) {
       aDomPref->defaultValue() = dom::PrefValue();
       mDefaultValue.ToDomPrefValue(Type(),
                                    &aDomPref->defaultValue().get_PrefValue());
     } else {
@@ -487,16 +497,17 @@ public:
                aDomPref->userValue().type() == dom::MaybePrefValue::Tnull_t ||
                (aDomPref->defaultValue().get_PrefValue().type() ==
                 aDomPref->userValue().get_PrefValue().type()));
   }
 
   void FromDomPref(const dom::Pref& aDomPref, bool* aValueChanged)
   {
     MOZ_ASSERT(!XRE_IsParentProcess());
+    MOZ_ASSERT(strcmp(mName, aDomPref.name().get()) == 0);
 
     mIsLocked = aDomPref.isLocked();
 
     const dom::MaybePrefValue& defaultValue = aDomPref.defaultValue();
     bool defaultValueChanged = false;
     if (defaultValue.type() == dom::MaybePrefValue::TPrefValue) {
       PrefValue value;
       PrefType type = value.FromDomPrefValue(defaultValue.get_PrefValue());
@@ -672,39 +683,72 @@ public:
     }
 
     // Do not save default prefs that haven't changed.
     return false;
   }
 
   void AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf, PrefsSizes& aSizes)
   {
+    // Note: mName is allocated in gPrefNameArena, measured elsewhere.
     aSizes.mPrefValues += aMallocSizeOf(this);
     if (IsTypeString()) {
       if (mHasDefaultValue) {
         aSizes.mStringValues += aMallocSizeOf(mDefaultValue.mStringVal);
       }
       if (mHasUserValue) {
         aSizes.mStringValues += aMallocSizeOf(mUserValue.mStringVal);
       }
     }
   }
 
 private:
+  const char* mName; // allocated in gPrefNameArena
+
   uint32_t mType : 2;
   uint32_t mIsSticky : 1;
   uint32_t mIsLocked : 1;
   uint32_t mHasDefaultValue : 1;
   uint32_t mHasUserValue : 1;
   uint32_t mHasChangedSinceInit : 1;
 
   PrefValue mDefaultValue;
   PrefValue mUserValue;
 };
 
+class PrefEntry : public PLDHashEntryHdr
+{
+public:
+  Pref* mPref;  // Note: this is never null in a live entry.
+
+  static bool MatchEntry(const PLDHashEntryHdr* aEntry, const void* aKey)
+  {
+    auto entry = static_cast<const PrefEntry*>(aEntry);
+    auto prefName = static_cast<const char*>(aKey);
+
+    return entry->mPref->MatchEntry(prefName);
+  }
+
+  static void InitEntry(PLDHashEntryHdr* aEntry, const void* aKey)
+  {
+    auto entry = static_cast<PrefEntry*>(aEntry);
+    auto prefName = static_cast<const char*>(aKey);
+
+    entry->mPref = new Pref(prefName);
+  }
+
+  static void ClearEntry(PLDHashTable* aTable, PLDHashEntryHdr* aEntry)
+  {
+    auto entry = static_cast<PrefEntry*>(aEntry);
+
+    delete entry->mPref;
+    entry->mPref = nullptr;
+  }
+};
+
 struct CallbackNode
 {
   CallbackNode(const char* aDomain,
                PrefChangedFunc aFunc,
                void* aData,
                Preferences::MatchKind aMatchKind)
     : mDomain(moz_xstrdup(aDomain))
     , mFunc(aFunc)
@@ -720,68 +764,62 @@ struct CallbackNode
   // NotifyCallbacks() is running, |func| is set to nullptr. Such nodes will
   // be removed at the end of NotifyCallbacks().
   PrefChangedFunc mFunc;
   void* mData;
   Preferences::MatchKind mMatchKind;
   CallbackNode* mNext;
 };
 
-// Hash key that allocates its string from the `gPrefNameArena`. The base class
-// `nsDepCharHashKey` does not own the string data and no copies are made.
-class StringArenaHashKey : public nsDepCharHashKey
-{
-public:
-  explicit StringArenaHashKey(const char* aKey)
-    : nsDepCharHashKey(ArenaStrdup(aKey, gPrefNameArena))
-  {
-  }
-};
-
-// Hashtable used to map names to pref objects. StringArenaHashKey is used to
-// allocate the strings out of an arena.
-using PrefsTable = nsClassHashtable<StringArenaHashKey, Pref>;
-static PrefsTable* gHashTable;
+static PLDHashTable* gHashTable;
 
 // The callback list contains all the priority callbacks followed by the
 // non-priority callbacks. gLastPriorityNode records where the first part ends.
 static CallbackNode* gFirstCallback = nullptr;
 static CallbackNode* gLastPriorityNode = nullptr;
 
 static bool gIsAnyPrefLocked = false;
 
 // These are only used during the call to NotifyCallbacks().
 static bool gCallbacksInProgress = false;
 static bool gShouldCleanupDeadNodes = false;
 
+static PLDHashTableOps pref_HashTableOps = {
+  PLDHashTable::HashStringKey,
+  PrefEntry::MatchEntry,
+  PLDHashTable::MoveEntryStub,
+  PrefEntry::ClearEntry,
+  PrefEntry::InitEntry,
+};
+
 static Pref*
 pref_HashTableLookup(const char* aPrefName);
 
 static void
 NotifyCallbacks(const char* aPrefName);
 
 #define PREF_HASHTABLE_INITIAL_LENGTH 1024
 
 static PrefSaveData
 pref_savePrefs()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
-  PrefSaveData savedPrefs(gHashTable->Count());
+  PrefSaveData savedPrefs(gHashTable->EntryCount());
 
   for (auto iter = gHashTable->Iter(); !iter.Done(); iter.Next()) {
-    Pref* pref = iter.Data();
+    Pref* pref = static_cast<PrefEntry*>(iter.Get())->mPref;
 
     nsAutoCString prefValueStr;
     if (!pref->UserValueToStringForSaving(prefValueStr)) {
       continue;
     }
 
     nsAutoCString prefNameStr;
-    StrEscape(iter.Key(), prefNameStr);
+    StrEscape(pref->Name(), prefNameStr);
 
     nsPrintfCString str(
       "user_pref(%s, %s);", prefNameStr.get(), prefValueStr.get());
 
     savedPrefs.AppendElement(str);
   }
 
   return savedPrefs;
@@ -822,17 +860,17 @@ IsEarlyPref(const char* aPrefName)
   size_t prefsLen;
   size_t found;
   const char** list = mozilla::dom::ContentPrefs::GetEarlyPrefs(&prefsLen);
   return BinarySearchIf(list, 0, prefsLen, StringComparator(aPrefName), &found);
 }
 
 #endif // DEBUG
 
-static PrefsTable::LookupResult
+static PrefEntry*
 pref_HashTableLookupInner(const char* aPrefName)
 {
   MOZ_ASSERT(NS_IsMainThread() || mozilla::ServoStyleSet::IsInServoTraversal());
 
 #ifdef DEBUG
   if (!XRE_IsParentProcess()) {
     if (gPhase == ContentProcessPhase::eNoPrefsSet) {
       MOZ_CRASH_UNSAFE_PRINTF("accessing pref %s before early prefs are set",
@@ -845,41 +883,46 @@ pref_HashTableLookupInner(const char* aP
       // Consider moving the access later or add the pref to the whitelist of
       // early prefs in ContentPrefs.cpp and get review from a DOM peer.
       MOZ_CRASH_UNSAFE_PRINTF(
         "accessing non-early pref %s before late prefs are set", aPrefName);
     }
   }
 #endif
 
-  return gHashTable->Lookup(aPrefName);
+  return static_cast<PrefEntry*>(gHashTable->Search(aPrefName));
 }
 
 static Pref*
 pref_HashTableLookup(const char* aPrefName)
 {
-  PrefsTable::LookupResult entry = pref_HashTableLookupInner(aPrefName);
-  return entry ? static_cast<Pref*>(entry.Data()) : nullptr;
+  PrefEntry* entry = pref_HashTableLookupInner(aPrefName);
+  return entry ? entry->mPref : nullptr;
 }
 
 static nsresult
 pref_SetPref(const char* aPrefName,
              PrefType aType,
              PrefValueKind aKind,
              PrefValue aValue,
              bool aIsSticky,
              bool aFromFile)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (!gHashTable) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
-  Pref* pref = gHashTable->LookupOrAdd(aPrefName);
+  auto entry = static_cast<PrefEntry*>(gHashTable->Add(aPrefName, fallible));
+  if (!entry) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+
+  Pref* pref = entry->mPref;
   if (pref->IsTypeNone()) {
     // New entry. Set the type.
     pref->SetType(aType);
   }
 
   bool valueChanged = false;
   nsresult rv;
   if (aKind == PrefValueKind::Default) {
@@ -1982,21 +2025,23 @@ nsPrefBranch::DeleteBranch(const char* a
       !StringEndsWith(branchName, NS_LITERAL_CSTRING("."))) {
     branchName += '.';
   }
 
   const nsACString& branchNameNoDot =
     Substring(branchName, 0, branchName.Length() - 1);
 
   for (auto iter = gHashTable->Iter(); !iter.Done(); iter.Next()) {
+    Pref* pref = static_cast<PrefEntry*>(iter.Get())->mPref;
+
     // The first disjunct matches branches: e.g. a branch name "foo.bar."
     // matches a name "foo.bar.baz" (but it won't match "foo.barrel.baz").
     // The second disjunct matches leaf nodes: e.g. a branch name "foo.bar."
     // matches a name "foo.bar" (by ignoring the trailing '.').
-    nsDependentCString name(iter.Key());
+    nsDependentCString name(pref->Name());
     if (StringBeginsWith(name, branchName) || name.Equals(branchNameNoDot)) {
       iter.Remove();
     }
   }
 
   Preferences::HandleDirty();
   return NS_OK;
 }
@@ -2021,18 +2066,19 @@ nsPrefBranch::GetChildList(const char* a
   *aCount = 0;
 
   // This will contain a list of all the pref name strings. Allocated on the
   // stack for speed.
 
   const PrefName& parent = GetPrefName(aStartingAt);
   size_t parentLen = parent.Length();
   for (auto iter = gHashTable->Iter(); !iter.Done(); iter.Next()) {
-    if (strncmp(iter.Key(), parent.get(), parentLen) == 0) {
-      prefArray.AppendElement(iter.Key());
+    Pref* pref = static_cast<PrefEntry*>(iter.Get())->mPref;
+    if (strncmp(pref->Name(), parent.get(), parentLen) == 0) {
+      prefArray.AppendElement(pref->Name());
     }
   }
 
   // Now that we've built up the list, run the callback on all the matching
   // elements.
   numPrefs = prefArray.Length();
 
   if (numPrefs) {
@@ -2634,17 +2680,17 @@ PreferenceServiceReporter::CollectReport
   MallocSizeOf mallocSizeOf = PreferenceServiceMallocSizeOf;
   PrefsSizes sizes;
 
   Preferences::AddSizeOfIncludingThis(mallocSizeOf, sizes);
 
   if (gHashTable) {
     sizes.mHashTable += gHashTable->ShallowSizeOfIncludingThis(mallocSizeOf);
     for (auto iter = gHashTable->Iter(); !iter.Done(); iter.Next()) {
-      Pref* pref = iter.Data();
+      Pref* pref = static_cast<PrefEntry*>(iter.Get())->mPref;
       pref->AddSizeOfIncludingThis(mallocSizeOf, sizes);
     }
   }
 
   if (gCacheData) {
     sizes.mCacheData += gCacheData->ShallowSizeOfIncludingThis(mallocSizeOf);
     for (uint32_t i = 0, count = gCacheData->Length(); i < count; ++i) {
       sizes.mCacheData += mallocSizeOf((*gCacheData)[i]);
@@ -2827,17 +2873,18 @@ Preferences::GetInstanceForService()
   if (sShutdown) {
     gCacheDataDesc = "shutting down in GetInstanceForService()";
     return nullptr;
   }
 
   sPreferences = new Preferences();
 
   MOZ_ASSERT(!gHashTable);
-  gHashTable = new PrefsTable(PREF_HASHTABLE_INITIAL_LENGTH);
+  gHashTable = new PLDHashTable(
+    &pref_HashTableOps, sizeof(PrefEntry), PREF_HASHTABLE_INITIAL_LENGTH);
 
   gTelemetryLoadData =
     new nsDataHashtable<nsCStringHashKey, TelemetryLoadData>();
 
   Result<Ok, const char*> res = InitInitialObjects();
   if (res.isErr()) {
     sPreferences = nullptr;
     gCacheDataDesc = res.unwrapErr();
@@ -3082,35 +3129,35 @@ Preferences::ReadUserPrefsFromFile(nsIFi
   return openPrefFile(aFile);
 }
 
 NS_IMETHODIMP
 Preferences::ResetPrefs()
 {
   ENSURE_PARENT_PROCESS("Preferences::ResetPrefs", "all prefs");
 
-  gHashTable->Clear();
+  gHashTable->ClearAndPrepareForLength(PREF_HASHTABLE_INITIAL_LENGTH);
   gPrefNameArena.Clear();
 
   return InitInitialObjects().isOk() ? NS_OK : NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 Preferences::ResetUserPrefs()
 {
   ENSURE_PARENT_PROCESS("Preferences::ResetUserPrefs", "all prefs");
   NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
   MOZ_ASSERT(NS_IsMainThread());
 
   Vector<const char*> prefNames;
   for (auto iter = gHashTable->Iter(); !iter.Done(); iter.Next()) {
-    Pref* pref = iter.Data();
+    Pref* pref = static_cast<PrefEntry*>(iter.Get())->mPref;
 
     if (pref->HasUserValue()) {
-      if (!prefNames.append(iter.Key())) {
+      if (!prefNames.append(pref->Name())) {
         return NS_ERROR_OUT_OF_MEMORY;
       }
 
       pref->ClearUserValue();
       if (!pref->HasDefaultValue()) {
         iter.Remove();
       }
     }
@@ -3174,33 +3221,38 @@ Preferences::SavePrefFile(nsIFile* aFile
 /* static */ void
 Preferences::SetPreference(const dom::Pref& aDomPref)
 {
   MOZ_ASSERT(!XRE_IsParentProcess());
   NS_ENSURE_TRUE(InitStaticMembers(), (void)0);
 
   const char* prefName = aDomPref.name().get();
 
-  Pref* pref = gHashTable->LookupOrAdd(prefName);
+  auto entry = static_cast<PrefEntry*>(gHashTable->Add(prefName, fallible));
+  if (!entry) {
+    return;
+  }
+
+  Pref* pref = entry->mPref;
 
   bool valueChanged = false;
   pref->FromDomPref(aDomPref, &valueChanged);
 
   // When the parent process clears a pref's user value we get a DomPref here
   // with no default value and no user value. There are two possibilities.
   //
   // - There was an existing pref with only a user value. FromDomPref() will
   //   have just cleared that user value, so the pref can be removed.
   //
   // - There was no existing pref. FromDomPref() will have done nothing, and
   //   `pref` will be valueless. We will end up adding and removing the value
   //   needlessly, but that's ok because this case is rare.
   //
   if (!pref->HasDefaultValue() && !pref->HasUserValue()) {
-    gHashTable->Remove(prefName);
+    gHashTable->RemoveEntry(entry);
   }
 
   // Note: we don't have to worry about HandleDirty() because we are setting
   // prefs in the content process that have come from the parent process.
 
   if (valueChanged) {
     NotifyCallbacks(prefName);
   }
@@ -3218,30 +3270,30 @@ Preferences::GetPreference(dom::Pref* aD
 }
 
 void
 Preferences::GetPreferences(InfallibleTArray<dom::Pref>* aDomPrefs)
 {
   MOZ_ASSERT(XRE_IsParentProcess());
   MOZ_ASSERT(NS_IsMainThread());
 
-  aDomPrefs->SetCapacity(gHashTable->Count());
+  aDomPrefs->SetCapacity(gHashTable->EntryCount());
   for (auto iter = gHashTable->Iter(); !iter.Done(); iter.Next()) {
-    Pref* pref = iter.Data();
+    Pref* pref = static_cast<PrefEntry*>(iter.Get())->mPref;
 
     if (!pref->MustSendToContentProcesses()) {
       // The pref value hasn't changed since it was initialized at startup.
       // Don't bother sending it, because the content process will initialize
       // it the same way.
       continue;
     }
 
     if (pref->HasAdvisablySizedValues()) {
       dom::Pref* setting = aDomPrefs->AppendElement();
-      pref->ToDomPref(setting, iter.Key());
+      pref->ToDomPref(setting);
     }
   }
 }
 
 #ifdef DEBUG
 bool
 Preferences::AreAllPrefsSetInContentProcess()
 {
@@ -4127,23 +4179,23 @@ Preferences::IsLocked(const char* aPrefN
   return false;
 }
 
 /* static */ nsresult
 Preferences::ClearUserInAnyProcess(const char* aPrefName)
 {
   NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
 
-  PrefsTable::LookupResult entry = pref_HashTableLookupInner(aPrefName);
+  PrefEntry* entry = pref_HashTableLookupInner(aPrefName);
   Pref* pref;
-  if (entry && (pref = entry.Data()) && pref->HasUserValue()) {
+  if (entry && (pref = entry->mPref) && pref->HasUserValue()) {
     pref->ClearUserValue();
 
     if (!pref->HasDefaultValue()) {
-      entry.Remove();
+      gHashTable->RemoveEntry(entry);
     }
 
     NotifyCallbacks(aPrefName);
     Preferences::HandleDirty();
   }
   return NS_OK;
 }
 
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -6007,8 +6007,13 @@ pref("layers.omtp.enabled", false);
 #endif
 #if defined(XP_MACOSX)
 pref("layers.omtp.paint-workers", -1);
 #else
 pref("layers.omtp.paint-workers", 1);
 #endif
 pref("layers.omtp.release-capture-on-main-thread", false);
 pref("layers.omtp.dump-capture", false);
+
+// Limits the depth of recursive conversion of data when opening
+// a content to view.  This is mostly intended to prevent infinite
+// loops with faulty converters involved.
+pref("general.document_open_conversion_depth_limit", 20);
--- a/taskcluster/ci/beetmover-cdns/kind.yml
+++ b/taskcluster/ci/beetmover-cdns/kind.yml
@@ -7,16 +7,17 @@ loader: taskgraph.loader.transform:loade
 transforms:
    - taskgraph.transforms.release_deps:transforms
    - taskgraph.transforms.beetmover_cdns:transforms
    - taskgraph.transforms.release_notifications:transforms
    - taskgraph.transforms.task:transforms
 
 kind-dependencies:
    - release-generate-checksums
+   - release-update-verify
 
 job-defaults:
    worker-type:
       by-project:
          mozilla-release: scriptworker-prov-v1/beetmoverworker-v1
          mozilla-beta: scriptworker-prov-v1/beetmoverworker-v1
          default: scriptworker-prov-v1/beetmoverworker-dev
    run-on-projects: []
--- a/taskcluster/ci/build/linux.yml
+++ b/taskcluster/ci/build/linux.yml
@@ -798,8 +798,70 @@ linux64-add-on-devel/opt:
         tooltool-downloads: public
         need-xvfb: true
     run-on-projects: ['mozilla-beta', 'mozilla-release', 'mozilla-esr45']
     toolchains:
         - linux64-clang
         - linux64-gcc
         - linux64-rust
         - linux64-sccache
+
+linux64-stylo-only/opt:
+    description: "Linux64 Stylo Only Opt"
+    index:
+        product: firefox
+        job-name: linux64-stylo-only-opt
+    treeherder:
+        platform: linux64-stylo-only/opt
+        symbol: B
+        tier: 2
+    worker-type: aws-provisioner-v1/gecko-{level}-b-linux
+    worker:
+        max-run-time: 36000
+    run:
+        using: mozharness
+        actions: [get-secrets build check-test update]
+        config:
+            - builds/releng_base_firefox.py
+            - builds/releng_base_linux_64_builds.py
+        script: "mozharness/scripts/fx_desktop_build.py"
+        extra-config:
+            mozconfig_variant: 'stylo-only'
+        secrets: true
+        tooltool-downloads: public
+        need-xvfb: true
+    run-on-projects: ['mozilla-central', 'try', 'mozilla-inbound', 'autoland']
+    toolchains:
+        - linux64-clang
+        - linux64-gcc
+        - linux64-rust
+        - linux64-sccache
+
+linux64-stylo-only/debug:
+    description: "Linux64 Stylo Only Debug"
+    index:
+        product: firefox
+        job-name: linux64-stylo-only-debug
+    treeherder:
+        platform: linux64-stylo-only/debug
+        symbol: B
+        tier: 2
+    worker-type: aws-provisioner-v1/gecko-{level}-b-linux
+    worker:
+        max-run-time: 36000
+    run:
+        using: mozharness
+        actions: [get-secrets build check-test update]
+        config:
+            - builds/releng_base_firefox.py
+            - builds/releng_base_linux_64_builds.py
+        script: "mozharness/scripts/fx_desktop_build.py"
+        extra-config:
+            mozconfig_variant: 'stylo-only-debug'
+        secrets: true
+        tooltool-downloads: public
+        need-xvfb: true
+    run-on-projects: ['mozilla-central', 'try', 'mozilla-inbound', 'autoland']
+    toolchains:
+        - linux64-clang
+        - linux64-gcc
+        - linux64-rust
+        - linux64-sccache
--- a/taskcluster/taskgraph/transforms/tests.py
+++ b/taskcluster/taskgraph/transforms/tests.py
@@ -1013,18 +1013,18 @@ def make_job_description(config, tests):
             # cause it to run are annotated with SCHEDULES in moz.build,
             # so do not include the platform or any other components here
             schedules = [suite]
         else:
             schedules = [suite, platform_family(test['build-platform'])]
 
         if test.get('when'):
             jobdesc['when'] = test['when']
-        elif config.params['project'] != 'try':
-            # for non-try branches, include SETA
+        elif config.params['project'] != 'try' and suite not in INCLUSIVE_COMPONENTS:
+            # for non-try branches and non-inclusive suites, include SETA
             jobdesc['optimization'] = {'skip-unless-schedules-or-seta': schedules}
         else:
             # otherwise just use skip-unless-schedules
             jobdesc['optimization'] = {'skip-unless-schedules': schedules}
 
         run = jobdesc['run'] = {}
         run['using'] = 'mozharness-test'
         run['test'] = test
--- a/testing/gtest/mozilla/MozGTestBench.h
+++ b/testing/gtest/mozilla/MozGTestBench.h
@@ -14,9 +14,14 @@ void GTestBench(const char* aSuite, cons
 
 } //mozilla
 
 #define MOZ_GTEST_BENCH(suite, test, lambdaOrFunc) \
 TEST(suite, test) { \
   mozilla::GTestBench(#suite, #test, lambdaOrFunc); \
 }
 
+#define MOZ_GTEST_BENCH_F(suite, test, lambdaOrFunc) \
+TEST_F(suite, test) { \
+  mozilla::GTestBench(#suite, #test, lambdaOrFunc); \
+}
+
 #endif // GTEST_MOZGTESTBENCH_H
--- a/testing/marionette/doc/PythonTests.md
+++ b/testing/marionette/doc/PythonTests.md
@@ -2,17 +2,17 @@ Mn Python tests
 ===============
 
 _Marionette_ is the codename of a [remote protocol] built in to
 Firefox as well as the name of a functional test framework for
 automating user interface tests.
 
 The in-tree test framework supports tests written in Python, using
 Python’s [unittest] library.  Test cases are written as a subclass
-of [`MarionetteTestCase`], with child tests belonging to instance
+of `MarionetteTestCase`, with child tests belonging to instance
 methods that have a name starting with `test_`.
 
 You can additionally define [`setUp`] and [`tearDown`] instance
 methods to execute code before and after child tests, and
 [`setUpClass`]/[`tearDownClass`] for the parent test.  When you use
 these, it is important to remember calling the [`MarionetteTestCase`]
 superclass’ own `setUp`/`tearDown` methods since they handle
 setup/cleanup of the session.
@@ -31,19 +31,18 @@ The test structure is illustrated here:
 
 	    def test_bar(self):
 	        # run test for 'bar'
 
 	    def tearDown(self):
 	        # code to execute after all tests are run
 	        MarionetteTestCase.tearDown(self)
 
-[remote protocol]: https://developer.mozilla.org/en-US/docs/Mozilla/QA/Marionette/Protocol
+[remote protocol]: Protocol.html
 [unittest]: https://docs.python.org/2.7/library/unittest.html
-[`MarionetteTestCase`]: https://developer.mozilla.org/en-US/docs/Mozilla/QA/Marionette/MarionetteTestCase
 [`setUp`]: https://docs.python.org/2.7/library/unittest.html#unittest.TestCase.setUp
 [`setUpClass`]: https://docs.python.org/2.7/library/unittest.html#unittest.TestCase.setUpClass
 [`tearDown`]: https://docs.python.org/2.7/library/unittest.html#unittest.TestCase.tearDown
 [`tearDownClass`]: https://docs.python.org/2.7/library/unittest.html#unittest.TestCase.tearDownClass
 
 
 Test assertions
 ---------------
@@ -57,17 +56,16 @@ Assertions are provided courtesy of [uni
 	        self.assertEqual(9, 3 * 3, '3 x 3 should be 9')
 	        self.assertTrue(type(2) == int, '2 should be an integer')
 
 
 The API
 -------
 
 The full API documentation is found at
-http://marionette-client.readthedocs.io/en/master/, but the key
-objects are:
+<http://marionette-client.readthedocs.io>, but the key objects are:
 
-  * [`MarionetteTestCase`]: a subclass for `unittest.TestCase`
+  * `MarionetteTestCase`: a subclass for `unittest.TestCase`
     used as a base class for all tests to run.
 
   * [`Marionette`]: client that speaks to Firefox.
 
 [`Marionette`]: http://marionette-client.readthedocs.io/en/master/reference.html#marionette
--- a/testing/marionette/doc/SeleniumAtoms.md
+++ b/testing/marionette/doc/SeleniumAtoms.md
@@ -1,75 +1,84 @@
-# Selenium Atoms
+Selenium atoms
+==============
 
-Marionette uses a small list of [Selenium atoms] to interact with web elements.
-Initially those have been added to ensure a better reliablity due to a wider usage
-inside the Selenium project. But by adding full support for the [WebDriver
-specification] they will be removed step by step.
+Marionette uses a small list of [Selenium atoms] to interact with
+web elements.  Initially those have been added to ensure a better
+reliablity due to a wider usage inside the Selenium project. But
+by adding full support for the [WebDriver specification] they will
+be removed step by step.
 
 Currently the following atoms are in use:
 
-* clearElement
-* getText
-* isDisplayed
-* isEnabled
-* isSelected
+- `getElementText`
+- `isDisplayed`
 
-To use one of those atoms Javascript modules will have to import [atom.js].
+To use one of those atoms Javascript modules will have to import
+[atom.js].
 
 [Selenium atoms]: https://github.com/SeleniumHQ/selenium/tree/master/javascript/webdriver/atoms
 [WebDriver specification]: https://w3c.github.io/webdriver/webdriver-spec.html
-[atom.js]: ../atom.js
+[atom.js]: https://searchfox.org/mozilla-central/source/testing/marionette/atom.js
 
 
-## Update required Selenium Atoms
+Update required Selenium atoms
+------------------------------
 
-In regular intervals the atoms, which are still in use, have to be updated.
-Therefore they have to be exported from the Selenium repository first, and then
-updated in [atom.js].
+In regular intervals the atoms, which are still in use, have to
+be updated.  Therefore they have to be exported from the Selenium
+repository first, and then updated in [atom.js].
+
 
 ### Export Selenium Atoms
 
 The canonical GitHub repository for Selenium is
 
-    https://github.com/SeleniumHQ/selenium.git
+	https://github.com/SeleniumHQ/selenium.git
 
-so make sure to have a local copy of it. For the cloning process it is
-recommended to specify the `--depth=1` argument, so only the last changeset is
-getting downloaded (which itself will already be more than 100 MB). Once the
-clone is ready the export of the atoms can be triggered by running the following
-commands:
+so make sure to have a local copy of it. For the cloning process
+it is recommended to specify the `--depth=1` argument, so only the
+last changeset is getting downloaded (which itself will already be
+more than 100 MB). Once the clone is ready the export of the atoms
+can be triggered by running the following commands:
 
-    % cd selenium
-    % ./go
-    % python buck-out/crazy-fun/%changeset%/buck.pex build --show-output %atom%
+	% cd selenium
+	% ./go
+	% python buck-out/crazy-fun/%changeset%/buck.pex build --show-output %atom%
 
-Hereby `%changeset%` corresponds to the currently used version of buck, and
-`%atom%` to the atom to export. The following targets for exporting are available:
+Hereby `%changeset%` corresponds to the currently used version of
+buck, and `%atom%` to the atom to export. The following targets
+for exporting are available:
 
-* //javascript/webdriver/atoms:clear-element-firefox
-* //javascript/webdriver/atoms:get-text-firefox
-* //javascript/webdriver/atoms:is-displayed-firefox
-* //javascript/webdriver/atoms:is-enabled-firefox
-* //javascript/webdriver/atoms:is-selected-firefox
+  - `//javascript/webdriver/atoms:clear-element-firefox`
+  - `//javascript/webdriver/atoms:get-text-firefox`
+  - `//javascript/webdriver/atoms:is-displayed-firefox`
+  - `//javascript/webdriver/atoms:is-enabled-firefox`
+  - `//javascript/webdriver/atoms:is-selected-firefox`
 
 For each of the exported atoms a file can now be found in the folder
-`buck-out/gen/javascript/webdriver/atoms/`. They contain all the code including
-dependencies for the atom wrapped into a single function.
+`buck-out/gen/javascript/webdriver/atoms/`.  They contain all the
+code including dependencies for the atom wrapped into a single function.
+
 
 ### Update atom.js
 
 To update the atoms for Marionette the `atoms.js` file has to be edited. For
 each atom to be updated the steps as layed out below have to be performed:
 
-1. Open the Javascript file of the exported atom. See above for its location.
-2. Remove the contained license header, which can be found somewhere in the
-   middle of the file.
-3. Update the parameters of the wrapper function (at the very top) so that those
-   are equal with the used parameters in `atom.js`.
-4. Copy the whole content of the file, and replace the existing code for the atom
-   in `atom.js`.
+1. Open the Javascript file of the exported atom. See above for
+   its location.
+
+2. Remove the contained license header, which can be found somewhere
+   in the middle of the file.
+
+3. Update the parameters of the wrapper function (at the very top)
+   so that those are equal with the used parameters in `atom.js`.
+
+4. Copy the whole content of the file, and replace the existing
+   code for the atom in `atom.js`.
+
 
 ### Test the changes
 
-To ensure that the update of the atoms doesn't cause a regression a try build
-should be run including Marionette unit tests, Firefox ui tests, and all the
-web-platform-tests.
+To ensure that the update of the atoms doesn't cause a regression
+a try build should be run including Marionette unit tests, Firefox
+ui tests, and all the web-platform-tests.
--- a/testing/marionette/doc/index.rst
+++ b/testing/marionette/doc/index.rst
@@ -1,20 +1,15 @@
 ==========
 Marionette
 ==========
 
 Marionette is the remote protocol that lets OOP programs communicate
 with, instrument, and control Gecko.
 
-
-Description
-===========
-
-Marionette is an automation driver for Mozilla’s Gecko engine.
 It can remotely control either the UI or the internal JavaScript of
 Gecko-based browsers, such as Firefox and Fennec.  It can control
 both the chrome and the content document, giving a high level of
 control and ability to replicate user interaction.  In addition
 to performing actions on the browser, Marionette can also ready
 properties and attributes of the DOM.
 
 
--- a/testing/mozbase/mozlog/mozlog/commandline.py
+++ b/testing/mozbase/mozlog/mozlog/commandline.py
@@ -10,29 +10,38 @@ import os
 import sys
 from collections import defaultdict
 
 from . import handlers
 from . import formatters
 from .structuredlog import StructuredLogger, set_default_logger
 
 log_formatters = {
-    'raw': (formatters.JSONFormatter, "Raw structured log messages"),
-    'unittest': (formatters.UnittestFormatter, "Unittest style output"),
-    'xunit': (formatters.XUnitFormatter, "xUnit compatible XML"),
-    'html': (formatters.HTMLFormatter, "HTML report"),
-    'mach': (formatters.MachFormatter, "Human-readable output"),
-    'tbpl': (formatters.TbplFormatter, "TBPL style log format"),
+    'raw': (formatters.JSONFormatter, "Raw structured log messages "
+                                      "(provided by mozlog)"),
+    'unittest': (formatters.UnittestFormatter, "Unittest style output "
+                                               "(provided by mozlog)"),
+    'xunit': (formatters.XUnitFormatter, "xUnit compatible XML "
+                                         "(povided by mozlog)"),
+    'html': (formatters.HTMLFormatter, "HTML report "
+                                       "(provided by mozlog)"),
+    'mach': (formatters.MachFormatter, "Human-readable output "
+                                       "(provided by mozlog)"),
+    'tbpl': (formatters.TbplFormatter, "TBPL style log format "
+                                       "(provided by mozlog)"),
     'errorsummary': (formatters.ErrorSummaryFormatter, argparse.SUPPRESS),
 }
 
 TEXT_FORMATTERS = ('raw', 'mach')
 """a subset of formatters for non test harnesses related applications"""
 
 
+DOCS_URL = "https://firefox-source-docs.mozilla.org/mozbase/mozlog.html"
+
+
 def level_filter_wrapper(formatter, level):
     return handlers.LogLevelFilter(formatter, level)
 
 
 def verbose_wrapper(formatter, verbose):
     formatter.verbose = verbose
     return formatter
 
@@ -116,17 +125,19 @@ def add_logging_group(parser, include_fo
                                of this option is to specify
                                :data:`TEXT_FORMATTERS` to include only the
                                most useful formatters for a command line tool
                                that is not related to test harnesses.
     """
     group_name = "Output Logging"
     group_description = ("Each option represents a possible logging format "
                          "and takes a filename to write that format to, "
-                         "or '-' to write to stdout.")
+                         "or '-' to write to stdout. Some options are "
+                         "provided by the mozlog utility; see %s "
+                         "for extended documentation." % DOCS_URL)
 
     if include_formatters is None:
         include_formatters = list(log_formatters.keys())
 
     if isinstance(parser, optparse.OptionParser):
         group = optparse.OptionGroup(parser,
                                      group_name,
                                      group_description)
new file mode 100644
--- /dev/null
+++ b/testing/talos/talos/tests/layout/benchmarks/displaylist_inactive_mutate.html
@@ -0,0 +1,56 @@
+<html>
+<head>
+<style>
+  div {
+    transform: translate(1px);
+    width:10px;
+    height:10px;
+    background-color:green;
+    display: inline-block;
+  }
+</style>
+</head>
+<body id="body">
+</body>
+<script>
+
+var start = null;
+var divCount = 1000;
+var maxIterations = 600;
+
+for (var i = 0; i < divCount; i++) {
+  var div = document.createElement("div");
+  div.id = i;
+  document.getElementById("body").appendChild(div);
+}
+
+var iteration = 0;
+function runFrame() {
+  if (document.getElementById(iteration).style.backgroundColor == "red") {
+    document.getElementById(iteration).style.backgroundColor = "green";
+  } else {
+    document.getElementById(iteration).style.backgroundColor = "red";
+  }
+  iteration++;
+  iteration = iteration % divCount;
+  if (--maxIterations == 0) {
+    var end = performance.now();
+    if (window.tpRecordTime) {
+      window.tpRecordTime(end - start, start);
+    }
+    return;
+  }
+
+  window.requestAnimationFrame(runFrame);
+}
+
+addEventListener("load", function() {
+  TalosContentProfiler.resume("displaylist_inactive_mutate.html loaded", true).then(() => {
+    start = performance.now();
+    window.requestAnimationFrame(runFrame);
+  });
+});
+
+</script>
+<script type="text/javascript" src="chrome://talos-powers-content/content/TalosContentProfiler.js"></script>
+</html>
--- a/testing/talos/talos/tests/layout/benchmarks/displaylist_mutate.html
+++ b/testing/talos/talos/tests/layout/benchmarks/displaylist_mutate.html
@@ -32,19 +32,16 @@ function runFrame() {
   }
   iteration++;
   iteration = iteration % divCount;
   if (--maxIterations == 0) {
     var end = performance.now();
     if (window.tpRecordTime) {
       window.tpRecordTime(end - start, start);
     }
-    if (parent.reportResults) {
-      parent.reportResults(end - start, start);
-    }
     return;
   }
 
   window.requestAnimationFrame(runFrame);
 }
 
 addEventListener("load", function() {
   TalosContentProfiler.resume("displaylist_mutate.html loaded", true).then(() => {
--- a/testing/talos/talos/tests/layout/displaylist_mutate.manifest
+++ b/testing/talos/talos/tests/layout/displaylist_mutate.manifest
@@ -1,1 +1,2 @@
 % http://localhost/tests/layout/benchmarks/displaylist_mutate.html
+% http://localhost/tests/layout/benchmarks/displaylist_inactive_mutate.html
--- a/toolkit/modules/RemoteFinder.jsm
+++ b/toolkit/modules/RemoteFinder.jsm
@@ -204,20 +204,16 @@ RemoteFinder.prototype = {
   }
 };
 
 function RemoteFinderListener(global) {
   let {Finder} = ChromeUtils.import("resource://gre/modules/Finder.jsm", {});
   this._finder = new Finder(global.docShell);
   this._finder.addResultListener(this);
   this._global = global;
-  this.KeyboardEvent =
-    global.docShell
-          .QueryInterface(Ci.nsIInterfaceRequestor)
-          .getInterface(Ci.nsIDOMWindow).KeyboardEvent;
 
   for (let msg of this.MESSAGES) {
     global.addMessageListener(msg, this);
   }
 }
 
 RemoteFinderListener.prototype = {
   MESSAGES: [
@@ -313,17 +309,18 @@ RemoteFinderListener.prototype = {
         this._finder.onFindbarClose();
         break;
 
       case "Finder:FindbarOpen":
         this._finder.onFindbarOpen();
         break;
 
       case "Finder:KeyPress":
-        this._finder.keyPress(new this.KeyboardEvent("keypress", data));
+        var KeyboardEvent = this._finder._getWindow().KeyboardEvent;
+        this._finder.keyPress(new KeyboardEvent("keypress", data));
         break;
 
       case "Finder:MatchesCount":
         this._finder.requestMatchesCount(data.searchString, data.linksOnly);
         break;
 
       case "Finder:ModalHighlightChange":
         this._finder.onModalHighlightChange(data.useModalHighlight);
--- a/uriloader/base/nsURILoader.cpp
+++ b/uriloader/base/nsURILoader.cpp
@@ -44,27 +44,39 @@
 #include "nsNetCID.h"
 
 #include "nsMimeTypes.h"
 
 #include "nsDocLoader.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/IntegerPrintfMacros.h"
 #include "mozilla/Preferences.h"
+#include "mozilla/Unused.h"
 #include "nsContentUtils.h"
 
 mozilla::LazyLogModule nsURILoader::mLog("URILoader");
 
 #define LOG(args) MOZ_LOG(nsURILoader::mLog, mozilla::LogLevel::Debug, args)
 #define LOG_ERROR(args) MOZ_LOG(nsURILoader::mLog, mozilla::LogLevel::Error, args)
 #define LOG_ENABLED() MOZ_LOG_TEST(nsURILoader::mLog, mozilla::LogLevel::Debug)
 
 #define NS_PREF_DISABLE_BACKGROUND_HANDLING \
     "security.exthelperapp.disable_background_handling"
 
+static uint32_t sConvertDataLimit = 20;
+
+static bool InitPreferences()
+{
+  nsresult rv = mozilla::Preferences::AddUintVarCache(
+    &sConvertDataLimit,
+    "general.document_open_conversion_depth_limit",
+    20);
+  return NS_SUCCEEDED(rv);
+}
+
 /**
  * The nsDocumentOpenInfo contains the state required when a single
  * document is being opened in order to discover the content type...
  * Each instance remains alive until its target URL has been loaded
  * (or aborted).
  */
 class nsDocumentOpenInfo final : public nsIStreamListener
                                , public nsIThreadRetargetableStreamListener
@@ -152,16 +164,21 @@ protected:
    */
   nsCString mContentType;
 
   /**
    * Reference to the URILoader service so we can access its list of
    * nsIURIContentListeners.
    */
   RefPtr<nsURILoader> mURILoader;
+
+  /**
+   * Limit of data conversion depth to prevent infinite conversion loops
+   */
+  uint32_t mDataConversionDepthLimit;
 };
 
 NS_IMPL_ADDREF(nsDocumentOpenInfo)
 NS_IMPL_RELEASE(nsDocumentOpenInfo)
 
 NS_INTERFACE_MAP_BEGIN(nsDocumentOpenInfo)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIRequestObserver)
   NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
@@ -174,17 +191,18 @@ nsDocumentOpenInfo::nsDocumentOpenInfo()
   NS_NOTREACHED("This should never be called\n");
 }
 
 nsDocumentOpenInfo::nsDocumentOpenInfo(nsIInterfaceRequestor* aWindowContext,
                                        uint32_t aFlags,
                                        nsURILoader* aURILoader)
   : m_originalContext(aWindowContext),
     mFlags(aFlags),
-    mURILoader(aURILoader)
+    mURILoader(aURILoader),
+    mDataConversionDepthLimit(sConvertDataLimit)
 {
 }
 
 nsDocumentOpenInfo::~nsDocumentOpenInfo()
 {
 }
 
 nsresult nsDocumentOpenInfo::Prepare()
@@ -620,16 +638,22 @@ nsDocumentOpenInfo::ConvertData(nsIReque
                                 nsIURIContentListener* aListener,
                                 const nsACString& aSrcContentType,
                                 const nsACString& aOutContentType)
 {
   LOG(("[0x%p] nsDocumentOpenInfo::ConvertData from '%s' to '%s'", this,
        PromiseFlatCString(aSrcContentType).get(),
        PromiseFlatCString(aOutContentType).get()));
 
+  if (mDataConversionDepthLimit == 0) {
+    LOG(("[0x%p] nsDocumentOpenInfo::ConvertData - reached the recursion limit!", this));
+    // This will fall back to external helper app handling.
+    return NS_ERROR_ABORT;
+  }
+
   NS_PRECONDITION(aSrcContentType != aOutContentType,
                   "ConvertData called when the two types are the same!");
   nsresult rv = NS_OK;
 
   nsCOMPtr<nsIStreamConverterService> StreamConvService = 
     do_GetService(NS_STREAMCONVERTERSERVICE_CONTRACTID, &rv);
   if (NS_FAILED(rv)) return rv;
 
@@ -643,16 +667,19 @@ nsDocumentOpenInfo::ConvertData(nsIReque
   // stream is split up into multiple destination streams.  This
   // intermediate instance is used to target these "decoded" streams...
   //
   RefPtr<nsDocumentOpenInfo> nextLink =
     new nsDocumentOpenInfo(m_originalContext, mFlags, mURILoader);
 
   LOG(("  Downstream DocumentOpenInfo would be: 0x%p", nextLink.get()));
   
+  // Decrease the conversion recursion limit by one to prevent infinite loops.
+  nextLink->mDataConversionDepthLimit = mDataConversionDepthLimit - 1;
+
   // Make sure nextLink starts with the contentListener that said it wanted the
   // results of this decode.
   nextLink->m_contentListener = aListener;
   // Also make sure it has to look for a stream listener to pump data into.
   nextLink->m_targetStreamListener = nullptr;
 
   // Make sure that nextLink treats the data as aOutContentType when
   // dispatching; that way even if the stream converters don't change the type
@@ -880,16 +907,19 @@ nsresult nsURILoader::OpenChannel(nsICha
 
       if (doAbort) {
         LOG(("  OnStartURIOpen aborted load"));
         return NS_ERROR_WONT_HANDLE_CONTENT;
       }
     }
   }
 
+  static bool once = InitPreferences();
+  mozilla::Unused << once;
+
   // we need to create a DocumentOpenInfo object which will go ahead and open
   // the url and discover the content type....
   RefPtr<nsDocumentOpenInfo> loader =
     new nsDocumentOpenInfo(aWindowContext, aFlags, this);
 
   // Set the correct loadgroup on the channel
   nsCOMPtr<nsILoadGroup> loadGroup(do_GetInterface(aWindowContext));
 
--- a/xpcom/ds/nsISerializable.idl
+++ b/xpcom/ds/nsISerializable.idl
@@ -12,17 +12,17 @@ interface nsIObjectOutputStream;
 interface nsISerializable : nsISupports
 {
     /**
      * Initialize the object implementing nsISerializable, which must have
      * been freshly constructed via CreateInstance.  All data members that
      * can't be set to default values must have been serialized by write,
      * and should be read from aInputStream in the same order by this method.
      */
-    void read(in nsIObjectInputStream aInputStream);
+    [must_use] void read(in nsIObjectInputStream aInputStream);
 
     /**
      * Serialize the object implementing nsISerializable to aOutputStream, by
      * writing each data member that must be recovered later to reconstitute
      * a working replica of this object, in a canonical member and byte order,
      * to aOutputStream.
      *
      * NB: a class that implements nsISerializable *must* also implement
--- a/xpcom/io/nsLocalFileWin.cpp
+++ b/xpcom/io/nsLocalFileWin.cpp
@@ -1183,17 +1183,17 @@ nsLocalFile::OpenNSPRFileDesc(int32_t aF
 
   return NS_OK;
 }
 
 
 NS_IMETHODIMP
 nsLocalFile::OpenANSIFileDesc(const char* aMode, FILE** aResult)
 {
-  nsresult rv = ResolveAndStat();
+  nsresult rv = Resolve();
   if (NS_FAILED(rv) && rv != NS_ERROR_FILE_NOT_FOUND) {
     return rv;
   }
 
   *aResult = _wfopen(mResolvedPath.get(), NS_ConvertASCIItoUTF16(aMode).get());
   if (*aResult) {
     return NS_OK;
   }
@@ -1205,17 +1205,17 @@ nsLocalFile::OpenANSIFileDesc(const char
 
 NS_IMETHODIMP
 nsLocalFile::Create(uint32_t aType, uint32_t aAttributes)
 {
   if (aType != NORMAL_FILE_TYPE && aType != DIRECTORY_TYPE) {
     return NS_ERROR_FILE_UNKNOWN_TYPE;
   }
 
-  nsresult rv = ResolveAndStat();
+  nsresult rv = Resolve();
   if (NS_FAILED(rv) && rv != NS_ERROR_FILE_NOT_FOUND) {
     return rv;
   }
 
   // create directories to target
   //
   // A given local file can be either one of these forms:
   //
@@ -1620,17 +1620,17 @@ typedef struct
 {
   WORD wLanguage;
   WORD wCodePage;
 } LANGANDCODEPAGE;
 
 NS_IMETHODIMP
 nsLocalFile::GetVersionInfoField(const char* aField, nsAString& aResult)
 {
-  nsresult rv = ResolveAndStat();
+  nsresult rv = Resolve();
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   rv = NS_ERROR_FAILURE;
 
   const WCHAR* path =
     mFollowSymlinks ? mResolvedPath.get() : mWorkingPath.get();
@@ -2307,17 +2307,17 @@ nsLocalFile::GetLastModifiedTimeOfLink(P
 
 
 NS_IMETHODIMP
 nsLocalFile::SetLastModifiedTime(PRTime aLastModifiedTime)
 {
   // Check we are correctly initialized.
   CHECK_mWorkingPath();
 
-  nsresult rv = ResolveAndStat();
+  nsresult rv = Resolve();
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   // set the modified time of the target as determined by mFollowSymlinks
   // If true, then this will be for the target of the shortcut file,
   // otherwise it will be for the shortcut file itself (i.e. the same
   // results as SetLastModifiedTimeOfLink)
@@ -2453,17 +2453,17 @@ nsLocalFile::SetPermissions(uint32_t aPe
 {
   // Check we are correctly initialized.
   CHECK_mWorkingPath();
 
   // set the permissions of the target as determined by mFollowSymlinks
   // If true, then this will be for the target of the shortcut file,
   // otherwise it will be for the shortcut file itself (i.e. the same
   // results as SetPermissionsOfLink)
-  nsresult rv = ResolveAndStat();
+  nsresult rv = Resolve();
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   // windows only knows about the following permissions
   int mode = 0;
   if (aPermissions & (PR_IRUSR | PR_IRGRP | PR_IROTH)) { // any read
     mode |= _S_IREAD;
@@ -2542,17 +2542,17 @@ nsLocalFile::GetFileSizeOfLink(int64_t* 
 }
 
 NS_IMETHODIMP
 nsLocalFile::SetFileSize(int64_t aFileSize)
 {
   // Check we are correctly initialized.
   CHECK_mWorkingPath();
 
-  nsresult rv = ResolveAndStat();
+  nsresult rv = Resolve();
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   HANDLE hFile = ::CreateFileW(mResolvedPath.get(),// pointer to name of the file
                                GENERIC_WRITE,      // access (write) mode
                                FILE_SHARE_READ,    // share mode
                                nullptr,            // pointer to security attributes
@@ -3046,17 +3046,17 @@ nsLocalFile::GetTarget(nsAString& aResul
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   if (!symLink) {
     return NS_ERROR_FILE_INVALID_PATH;
   }
 #endif
-  ResolveAndStat();
+  Resolve();
 
   aResult = mResolvedPath;
   return NS_OK;
 }
 
 
 NS_IMETHODIMP
 nsLocalFile::GetFollowLinks(bool* aFollowLinks)