diff --git a/browser/config/mozconfigs/linux64/stylo-only b/browser/config/mozconfigs/linux64/stylo-only
new file mode 100644
index 000000000000..2e2394a21170
--- /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
diff --git a/browser/config/mozconfigs/linux64/stylo-only-debug b/browser/config/mozconfigs/linux64/stylo-only-debug
new file mode 100644
index 000000000000..61e8fec3b41e
--- /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
diff --git a/build/Makefile.in b/build/Makefile.in
deleted file mode 100644
index 2f284c253e24..000000000000
--- 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
-
diff --git a/config/makefiles/test/Makefile.in b/config/makefiles/test/Makefile.in
deleted file mode 100644
index 6c66d820e900..000000000000
--- 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-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-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) $@
-#
-
-endif #} findstring MAKECMDGOAL
diff --git a/config/makefiles/test/check-arglist.mk b/config/makefiles/test/check-arglist.mk
deleted file mode 100644
index fb720ee42c0e..000000000000
--- 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
diff --git a/config/makefiles/test/check-autotargets.mk b/config/makefiles/test/check-autotargets.mk
deleted file mode 100644
index c103f1d02dbe..000000000000
--- 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
diff --git a/config/makefiles/test/check_XinY.mk b/config/makefiles/test/check_XinY.mk
deleted file mode 100644
index 1e7a19f0e747..000000000000
--- 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)))
-
diff --git a/config/makefiles/test/moz.build b/config/makefiles/test/moz.build
deleted file mode 100644
index 28919c271d33..000000000000
--- 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/.
-
diff --git a/config/moz.build b/config/moz.build
index 7bac5e6fe993..0108b977bff8 100644
--- a/config/moz.build
+++ b/config/moz.build
@@ -16,7 +16,6 @@ DIST_INSTALL = False
NoVisibilityFlags()
CONFIGURE_SUBST_FILES += [
- 'makefiles/test/Makefile',
'tests/src-simple/Makefile',
]
diff --git a/devtools/client/debugger/new/README.mozilla b/devtools/client/debugger/new/README.mozilla
index fb037fa31b08..a7f074d21986 100644
--- a/devtools/client/debugger/new/README.mozilla
+++ b/devtools/client/debugger/new/README.mozilla
@@ -1,8 +1,8 @@
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
diff --git a/devtools/client/debugger/new/debugger.css b/devtools/client/debugger/new/debugger.css
index ff31a07fed06..241a8cea38a2 100644
--- a/devtools/client/debugger/new/debugger.css
+++ b/devtools/client/debugger/new/debugger.css
@@ -1928,6 +1928,9 @@ html .toggle-button.end.vertical svg {
.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
diff --git a/devtools/client/debugger/new/debugger.js b/devtools/client/debugger/new/debugger.js
index 7f60dd630b04..c74c61448829 100644
--- a/devtools/client/debugger/new/debugger.js
+++ b/devtools/client/debugger/new/debugger.js
@@ -10102,7 +10102,7 @@ const prefs = new PrefsHelper("devtools", {
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;
@@ -17921,7 +17921,7 @@ function createPendingBreakpoint(bp) {
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);
@@ -17942,6 +17942,7 @@ 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");
@@ -19160,6 +19161,16 @@ const arrowBtn = (onClick, type, className, tooltip) => {
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();
@@ -19953,15 +19964,15 @@ 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 . */
+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 . */
function setPrimaryPaneTab(tabName) {
return { type: "SET_PRIMARY_PANE_TAB", tabName };
@@ -19981,6 +19992,10 @@ function setActiveSearch(activeSearch) {
return;
}
+ if ((0, _selectors.getQuickOpenEnabled)(getState())) {
+ dispatch({ type: "CLOSE_QUICK_OPEN" });
+ }
+
dispatch({
type: "TOGGLE_ACTIVE_SEARCH",
value: activeSearch
@@ -20009,7 +20024,7 @@ function showSource(sourceId) {
dispatch({
type: "SHOW_SOURCE",
- sourceUrl: source.get("url")
+ sourceUrl: (0, _source.getRawSourceURL)(source.get("url"))
});
};
}
@@ -20330,6 +20345,7 @@ var _extends = Object.assign || function (target) { for (var i = 1; i < argument
exports.getPauseReason = getPauseReason;
exports.isStepping = isStepping;
exports.isPaused = isPaused;
+exports.getPreviousPauseFrameLocation = getPreviousPauseFrameLocation;
exports.isEvaluatingExpression = isEvaluatingExpression;
exports.getPopupObjectProperties = getPopupObjectProperties;
exports.getIsWaitingOnBreak = getIsWaitingOnBreak;
@@ -20368,7 +20384,8 @@ const createPauseState = exports.createPauseState = () => ({
shouldIgnoreCaughtExceptions: _prefs.prefs.ignoreCaughtExceptions,
canRewind: false,
debuggeeUrl: "",
- command: ""
+ command: "",
+ previousLocation: null
});
const emptyPauseState = {
@@ -20379,7 +20396,8 @@ const emptyPauseState = {
original: {}
},
selectedFrameId: null,
- loadedObjects: {}
+ loadedObjects: {},
+ previousLocation: null
};
function update(state = createPauseState(), action) {
@@ -20485,7 +20503,12 @@ function update(state = createPauseState(), action) {
});
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
@@ -20504,6 +20527,24 @@ function update(state = createPauseState(), action) {
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
@@ -20531,6 +20572,10 @@ function isPaused(state) {
return !!getFrames(state);
}
+function getPreviousPauseFrameLocation(state) {
+ return state.pause.previousLocation;
+}
+
function isEvaluatingExpression(state) {
return state.pause.command === "expression";
}
@@ -21329,74 +21374,7 @@ function setOutOfScopeLocations() {
}
/***/ }),
-/* 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 . */
-
-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__) {
@@ -35210,30 +35188,33 @@ class SearchBar extends _react.Component {
};
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;
+ const { editor, searchOn, setActiveSearch } = this.props;
- if (!this.props.searchOn) {
- this.props.setActiveSearch("file");
+ if (!searchOn) {
+ setActiveSearch("file");
}
- if (this.props.searchOn && editor) {
- const selection = editor.codeMirror.getSelection();
- this.setState({ query: selection });
- if (selection !== "") {
- this.doSearch(selection);
+ 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 });
}
}
};
@@ -35274,6 +35255,10 @@ class SearchBar extends _react.Component {
return this.doSearch(e.target.value);
};
+ this.onBlur = e => {
+ this.setState({ inputFocused: false });
+ };
+
this.onKeyDown = e => {
if (e.key !== "Enter" && e.key !== "F3") {
return;
@@ -35338,7 +35323,8 @@ class SearchBar extends _react.Component {
query: props.query,
selectedResultIndex: 0,
count: 0,
- index: -1
+ index: -1,
+ inputFocused: false
};
}
@@ -35422,11 +35408,13 @@ class SearchBar extends _react.Component {
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",
@@ -39255,7 +39243,7 @@ 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);
@@ -39727,7 +39715,7 @@ function getMenuItems(event, {
id: "node-menu-show-source",
label: revealInTreeLabel,
accesskey: revealInTreeKey,
- disabled: isPrettyPrinted,
+ disabled: false,
click: () => showSource(sourceId)
};
@@ -40454,7 +40442,7 @@ 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);
@@ -41221,7 +41209,7 @@ var _react = __webpack_require__(0);
var _react2 = _interopRequireDefault(_react);
-var _pause = __webpack_require__(1400);
+var _pause = __webpack_require__(2419);
__webpack_require__(1337);
@@ -43363,7 +43351,9 @@ function hasAwait(source, pauseLocation) {
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)/);
}
/**
@@ -43382,6 +43372,7 @@ function astCommand(stepType) {
// 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) {
@@ -43593,8 +43584,17 @@ 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
*
@@ -43609,12 +43609,26 @@ var _fetchScopes = __webpack_require__(1655);
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 || []
});
@@ -43657,7 +43671,7 @@ var _selectors = __webpack_require__(1352);
var _expressions = __webpack_require__(1398);
-var _pause = __webpack_require__(1400);
+var _pause = __webpack_require__(2419);
/**
* Debugger has just resumed
@@ -44001,7 +44015,7 @@ class QuickOpenModal extends _react.Component {
return;
}
- if (query == "") {
+ if (query == "" && !this.isShortcutQuery()) {
return this.showTopSources();
}
@@ -48484,6 +48498,7 @@ var _extends = Object.assign || function (target) { for (var i = 1; i < argument
* @module actions/sources
*/
+exports.loadSourceMap = loadSourceMap;
exports.newSource = newSource;
exports.newSources = newSources;
@@ -48510,25 +48525,25 @@ function createOriginalSource(originalUrl, generatedSource, sourceMaps) {
};
}
-// 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;
}
@@ -48836,6 +48851,7 @@ Object.defineProperty(exports, "__esModule", {
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);
@@ -50361,6 +50377,7 @@ class ProjectSearch extends _react.Component {
if (this.isProjectSearchEnabled()) {
return closeProjectSearch();
}
+
return setActiveSearch("project");
};
@@ -50880,11 +50897,11 @@ class Tab extends _react.PureComponent {
})
}];
- if (!isPrettySource) {
- items.push({
- item: _extends({}, tabMenuItems.showSource, { click: () => showSource(tab) })
- });
+ items.push({
+ item: _extends({}, tabMenuItems.showSource, { click: () => showSource(tab) })
+ });
+ if (!isPrettySource) {
items.push({
item: _extends({}, tabMenuItems.prettyPrint, {
click: () => togglePrettyPrint(tab)
@@ -52110,6 +52127,213 @@ function getExpressionFromCoords(cm, coord) {
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 . */
+
+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 . */
+
+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
diff --git a/devtools/client/debugger/new/parser-worker.js b/devtools/client/debugger/new/parser-worker.js
index 2b2faeab3d8c..e90ee9f6d2a8 100644
--- a/devtools/client/debugger/new/parser-worker.js
+++ b/devtools/client/debugger/new/parser-worker.js
@@ -34597,15 +34597,15 @@ 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 . */
-
-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 . */
self.onmessage = workerHandler({
getClosestExpression: _closest.getClosestExpression,
@@ -34618,6 +34618,7 @@ self.onmessage = workerHandler({
hasSource: _sources.hasSource,
setSource: _sources.setSource,
clearSources: _sources.clearSources,
+ isInvalidPauseLocation: _pauseLocation.isInvalidPauseLocation,
getVariablesInScope: _scopes.getVariablesInScope,
getNextStep: _steps.getNextStep,
getEmptyLines: _getEmptyLines2.default,
@@ -60818,6 +60819,82 @@ function stripModuleScope(rootScope) {
});
}
+/***/ }),
+/* 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 . */
+
+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
diff --git a/devtools/client/debugger/new/test/mochitest/browser.ini b/devtools/client/debugger/new/test/mochitest/browser.ini
index 381d9b9395a9..04245303e25e 100644
--- a/devtools/client/debugger/new/test/mochitest/browser.ini
+++ b/devtools/client/debugger/new/test/mochitest/browser.ini
@@ -117,8 +117,9 @@ support-files =
[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]
diff --git a/devtools/client/debugger/new/test/mochitest/browser_dbg-babel.js b/devtools/client/debugger/new/test/mochitest/browser_dbg-babel-scopes.js
similarity index 100%
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
diff --git a/devtools/client/debugger/new/test/mochitest/browser_dbg-babel-stepping.js b/devtools/client/debugger/new/test/mochitest/browser_dbg-babel-stepping.js
new file mode 100644
index 000000000000..2c29d45536d6
--- /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 }],
+ ]
+ );
+});
diff --git 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
index 883a297c19b5..dd41c9c6957f 100644
--- 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
@@ -26,7 +26,7 @@ add_task(async function() {
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);
diff --git a/devtools/client/debugger/new/test/mochitest/browser_dbg-sourcemaps-reload.js b/devtools/client/debugger/new/test/mochitest/browser_dbg-sourcemaps-reload.js
index 9899ffd47468..c879192c05d2 100644
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-sourcemaps-reload.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-sourcemaps-reload.js
@@ -53,7 +53,6 @@ add_task(async function() {
await reload(dbg);
await waitForSource(dbg, "v1");
await syncBp;
- await waitForSelectedSource(dbg, "v1");
is(getBreakpoints(dbg).length, 0, "No breakpoints");
});
diff --git a/devtools/client/sourceeditor/README b/devtools/client/sourceeditor/README
index a49eb315fa97..85fe6417c4ba 100644
--- a/devtools/client/sourceeditor/README
+++ b/devtools/client/sourceeditor/README
@@ -5,7 +5,7 @@ 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].
diff --git a/devtools/client/sourceeditor/codemirror/addon/search/match-highlighter.js b/devtools/client/sourceeditor/codemirror/addon/search/match-highlighter.js
index 73ba0e053709..35221711790e 100644
--- a/devtools/client/sourceeditor/codemirror/addon/search/match-highlighter.js
+++ b/devtools/client/sourceeditor/codemirror/addon/search/match-highlighter.js
@@ -90,7 +90,7 @@
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"});
}
diff --git a/devtools/client/sourceeditor/codemirror/addon/search/searchcursor.js b/devtools/client/sourceeditor/codemirror/addon/search/searchcursor.js
index 58bc47c2c3e6..e606c5e7cf59 100644
--- a/devtools/client/sourceeditor/codemirror/addon/search/searchcursor.js
+++ b/devtools/client/sourceeditor/codemirror/addon/search/searchcursor.js
@@ -19,8 +19,11 @@
+ (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) {
@@ -28,7 +31,7 @@
}
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)
@@ -42,7 +45,7 @@
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
@@ -51,6 +54,7 @@
// 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
}
@@ -81,7 +85,7 @@
}
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)
@@ -94,7 +98,7 @@
}
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++) {
@@ -213,7 +217,7 @@
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)
diff --git a/devtools/client/sourceeditor/codemirror/codemirror.bundle.js b/devtools/client/sourceeditor/codemirror/codemirror.bundle.js
index 0f81ea6dd2ce..83229e726b75 100644
--- a/devtools/client/sourceeditor/codemirror/codemirror.bundle.js
+++ b/devtools/client/sourceeditor/codemirror/codemirror.bundle.js
@@ -5454,7 +5454,8 @@ var CodeMirror =
// 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
@@ -5479,8 +5480,10 @@ var CodeMirror =
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
@@ -5956,7 +5959,7 @@ var CodeMirror =
}
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
}
@@ -9892,7 +9895,7 @@ var CodeMirror =
addLegacyProps(CodeMirror)
- CodeMirror.version = "5.34.0"
+ CodeMirror.version = "5.35.0"
return CodeMirror;
@@ -9923,8 +9926,11 @@ var CodeMirror =
+ (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) {
@@ -9932,7 +9938,7 @@ var CodeMirror =
}
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)
@@ -9946,7 +9952,7 @@ var CodeMirror =
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
@@ -9955,6 +9961,7 @@ var CodeMirror =
// 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
}
@@ -9985,7 +9992,7 @@ var CodeMirror =
}
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)
@@ -9998,7 +10005,7 @@ var CodeMirror =
}
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++) {
@@ -10117,7 +10124,7 @@ var CodeMirror =
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)
@@ -11438,6 +11445,7 @@ var CodeMirror =
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) {
@@ -11632,7 +11640,7 @@ var CodeMirror =
}
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) }
}
@@ -11675,7 +11683,8 @@ var CodeMirror =
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) {
@@ -11764,6 +11773,7 @@ var CodeMirror =
}
function afterImport(type) {
if (type == "string") return cont();
+ if (type == "(") return pass(expression);
return pass(importSpec, maybeMoreImports, maybeFrom);
}
function importSpec(type, value) {
@@ -14416,7 +14426,7 @@ var CodeMirror =
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"]}
});
@@ -14432,7 +14442,7 @@ var CodeMirror =
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: {
@@ -14639,22 +14649,24 @@ var CodeMirror =
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,
@@ -16448,7 +16460,7 @@ var CodeMirror =
}
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; }
@@ -17033,7 +17045,7 @@ var CodeMirror =
} else {
if (vim.visualMode) {
showPrompt(cm, { onClose: onPromptClose, prefix: ':', value: '\'<,\'>',
- onKeyDown: onPromptKeyDown});
+ onKeyDown: onPromptKeyDown, selectValueOnOpen: false});
} else {
showPrompt(cm, { onClose: onPromptClose, prefix: ':',
onKeyDown: onPromptKeyDown});
@@ -19290,7 +19302,15 @@ var CodeMirror =
}
}
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
@@ -19302,12 +19322,15 @@ var CodeMirror =
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 == '\\');
@@ -20173,7 +20196,7 @@ var CodeMirror =
'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.
@@ -20217,7 +20240,7 @@ var CodeMirror =
global = true;
flagsPart.replace('g', '');
}
- regexPart = regexPart + '/' + flagsPart;
+ regexPart = regexPart.replace(/\//g, "\\/") + '/' + flagsPart;
}
}
if (regexPart) {
@@ -20433,7 +20456,7 @@ var CodeMirror =
}
if (!confirm) {
replaceAll();
- if (callback) { callback(); };
+ if (callback) { callback(); }
return;
}
showPrompt(cm, {
@@ -20569,7 +20592,7 @@ var CodeMirror =
exitInsertMode(cm);
}
}
- };
+ }
macroModeState.isPlaying = false;
}
@@ -20773,7 +20796,7 @@ var CodeMirror =
exitInsertMode(cm);
}
macroModeState.isPlaying = false;
- };
+ }
function repeatInsertModeChanges(cm, changes, repeat) {
function keyHandler(binding) {
@@ -20988,8 +21011,14 @@ var CodeMirror =
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);
diff --git a/devtools/client/sourceeditor/codemirror/keymap/sublime.js b/devtools/client/sourceeditor/codemirror/keymap/sublime.js
index 7a9aadd33097..aa9b65e3b16d 100644
--- a/devtools/client/sourceeditor/codemirror/keymap/sublime.js
+++ b/devtools/client/sourceeditor/codemirror/keymap/sublime.js
@@ -156,8 +156,14 @@
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);
diff --git a/devtools/client/sourceeditor/codemirror/keymap/vim.js b/devtools/client/sourceeditor/codemirror/keymap/vim.js
index b08226818372..529654a3b538 100644
--- a/devtools/client/sourceeditor/codemirror/keymap/vim.js
+++ b/devtools/client/sourceeditor/codemirror/keymap/vim.js
@@ -841,7 +841,7 @@
}
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; }
@@ -1426,7 +1426,7 @@
} else {
if (vim.visualMode) {
showPrompt(cm, { onClose: onPromptClose, prefix: ':', value: '\'<,\'>',
- onKeyDown: onPromptKeyDown});
+ onKeyDown: onPromptKeyDown, selectValueOnOpen: false});
} else {
showPrompt(cm, { onClose: onPromptClose, prefix: ':',
onKeyDown: onPromptKeyDown});
@@ -3683,7 +3683,15 @@
}
}
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
@@ -3695,12 +3703,15 @@
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 == '\\');
@@ -4566,7 +4577,7 @@
'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.
@@ -4610,7 +4621,7 @@
global = true;
flagsPart.replace('g', '');
}
- regexPart = regexPart + '/' + flagsPart;
+ regexPart = regexPart.replace(/\//g, "\\/") + '/' + flagsPart;
}
}
if (regexPart) {
@@ -4826,7 +4837,7 @@
}
if (!confirm) {
replaceAll();
- if (callback) { callback(); };
+ if (callback) { callback(); }
return;
}
showPrompt(cm, {
@@ -4962,7 +4973,7 @@
exitInsertMode(cm);
}
}
- };
+ }
macroModeState.isPlaying = false;
}
@@ -5166,7 +5177,7 @@
exitInsertMode(cm);
}
macroModeState.isPlaying = false;
- };
+ }
function repeatInsertModeChanges(cm, changes, repeat) {
function keyHandler(binding) {
diff --git a/devtools/client/sourceeditor/codemirror/lib/codemirror.js b/devtools/client/sourceeditor/codemirror/lib/codemirror.js
index f22567442124..e942fe63728b 100644
--- a/devtools/client/sourceeditor/codemirror/lib/codemirror.js
+++ b/devtools/client/sourceeditor/codemirror/lib/codemirror.js
@@ -5212,7 +5212,8 @@ function makeChangeInner(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
@@ -5237,8 +5238,10 @@ function makeChangeFromHistory(doc, type, allowSelectionOnly) {
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
@@ -5714,7 +5717,7 @@ function addLineWidget(doc, handle, node, options) {
}
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
}
@@ -9650,7 +9653,7 @@ CodeMirror.fromTextArea = fromTextArea
addLegacyProps(CodeMirror)
-CodeMirror.version = "5.34.0"
+CodeMirror.version = "5.35.0"
return CodeMirror;
diff --git a/devtools/client/sourceeditor/codemirror/mode/clike/clike.js b/devtools/client/sourceeditor/codemirror/mode/clike/clike.js
index b89ddf0d59bf..da7a6bf5b669 100644
--- a/devtools/client/sourceeditor/codemirror/mode/clike/clike.js
+++ b/devtools/client/sourceeditor/codemirror/mode/clike/clike.js
@@ -374,7 +374,7 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
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"]}
});
@@ -390,7 +390,7 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
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: {
@@ -597,22 +597,24 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
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,
diff --git a/devtools/client/sourceeditor/codemirror/mode/javascript/javascript.js b/devtools/client/sourceeditor/codemirror/mode/javascript/javascript.js
index 9eb50ba974e8..52da9e23532a 100644
--- a/devtools/client/sourceeditor/codemirror/mode/javascript/javascript.js
+++ b/devtools/client/sourceeditor/codemirror/mode/javascript/javascript.js
@@ -400,6 +400,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
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) {
@@ -594,7 +595,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
}
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) }
}
@@ -637,7 +638,8 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
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) {
@@ -726,6 +728,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
}
function afterImport(type) {
if (type == "string") return cont();
+ if (type == "(") return pass(expression);
return pass(importSpec, maybeMoreImports, maybeFrom);
}
function importSpec(type, value) {
diff --git a/devtools/client/sourceeditor/test/codemirror/mode/javascript/test.js b/devtools/client/sourceeditor/test/codemirror/mode/javascript/test.js
index 14a5183cab41..f770bd77f6b1 100644
--- a/devtools/client/sourceeditor/test/codemirror/mode/javascript/test.js
+++ b/devtools/client/sourceeditor/test/codemirror/mode/javascript/test.js
@@ -63,6 +63,12 @@
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] ]];",
@@ -71,6 +77,9 @@
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])",
diff --git a/devtools/client/sourceeditor/test/codemirror/test.js b/devtools/client/sourceeditor/test/codemirror/test.js
index 87615d06300b..415dd9f0bc5d 100644
--- a/devtools/client/sourceeditor/test/codemirror/test.js
+++ b/devtools/client/sourceeditor/test/codemirror/test.js
@@ -2330,7 +2330,7 @@ testCM("lineSeparator", function(cm) {
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) {
@@ -2356,7 +2356,7 @@ function testMoveBidi(str) {
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';
}
diff --git a/devtools/client/sourceeditor/test/codemirror/vim_test.js b/devtools/client/sourceeditor/test/codemirror/vim_test.js
index e5bf1f208135..6433134c21d6 100644
--- a/devtools/client/sourceeditor/test/codemirror/vim_test.js
+++ b/devtools/client/sourceeditor/test/codemirror/vim_test.js
@@ -153,7 +153,7 @@ function testVim(name, run, opts, expectedFail) {
// 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));
}
}
@@ -255,7 +255,7 @@ function testJumplist(name, keys, endPos, startPos, dialog) {
helpers.doKeys.apply(null, keys);
helpers.assertCursorAt(endPos);
}, {value: jumplistScene});
-};
+}
testJumplist('jumplist_H', ['H', ''], [5,2], [5,2]);
testJumplist('jumplist_M', ['M', ''], [2,2], [2,2]);
testJumplist('jumplist_L', ['L', ''], [2,2], [2,2]);
@@ -299,15 +299,15 @@ function testMotion(name, keys, endPos, 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));
@@ -3648,6 +3648,11 @@ testVim('ex_substitute_same_line', function(cm, vim, helpers) {
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');
@@ -3904,7 +3909,7 @@ function testSubstituteConfirm(name, command, initialValue, expectedValue, keys,
cm.openDialog = savedOpenDialog;
}
}, { value: initialValue });
-};
+}
testSubstituteConfirm('ex_substitute_confirm_emptydoc',
'%s/x/b/c', '', '', '', makeCursor(0, 0));
testSubstituteConfirm('ex_substitute_confirm_nomatch',
diff --git a/devtools/server/tests/unit/test_blackboxing-01.js b/devtools/server/tests/unit/test_blackboxing-01.js
index 7d002f304e9e..00bc8bd077e8 100644
--- a/devtools/server/tests/unit/test_blackboxing-01.js
+++ b/devtools/server/tests/unit/test_blackboxing-01.js
@@ -96,7 +96,7 @@ 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,
diff --git a/devtools/server/tests/unit/test_stepping-08.js b/devtools/server/tests/unit/test_stepping-08.js
index 6a82e890013e..a5a69a0327e0 100644
--- a/devtools/server/tests/unit/test_stepping-08.js
+++ b/devtools/server/tests/unit/test_stepping-08.js
@@ -60,8 +60,8 @@ function evaluateTestCode() {
} // 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
diff --git a/dom/bindings/moz.build b/dom/bindings/moz.build
index b814676bbf06..dfe45219913b 100644
--- a/dom/bindings/moz.build
+++ b/dom/bindings/moz.build
@@ -121,7 +121,7 @@ SOURCES += [
# 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",
diff --git a/dom/cache/test/mochitest/browser_cache_pb_window.js b/dom/cache/test/mochitest/browser_cache_pb_window.js
index 81619e5e57f2..09ac5c45df23 100644
--- a/dom/cache/test/mochitest/browser_cache_pb_window.js
+++ b/dom/cache/test/mochitest/browser_cache_pb_window.js
@@ -70,6 +70,30 @@ function testKeys(browser) {
});
}
+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();
@@ -88,6 +112,7 @@ function test() {
testOpen(privateTab.linkedBrowser),
testDelete(privateTab.linkedBrowser),
testKeys(privateTab.linkedBrowser),
+ testOpen_worker(privateTab.linkedBrowser),
]);
}).then(() => {
return BrowserTestUtils.closeWindow(privateWin);
diff --git a/dom/fetch/FetchDriver.cpp b/dom/fetch/FetchDriver.cpp
index f00ab1029074..fc5619dd0e43 100644
--- a/dom/fetch/FetchDriver.cpp
+++ b/dom/fetch/FetchDriver.cpp
@@ -797,6 +797,11 @@ FetchDriver::OnStartRequest(nsIRequest* aRequest,
// 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)) {
diff --git a/dom/webidl/moz.build b/dom/webidl/moz.build
index d5e58ff02567..a4168e825a54 100644
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -1034,7 +1034,7 @@ WEBIDL_FILES += [
# 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',
diff --git a/dom/xul/nsXULPrototypeDocument.cpp b/dom/xul/nsXULPrototypeDocument.cpp
index 55073fb45317..68d1148ed828 100644
--- a/dom/xul/nsXULPrototypeDocument.cpp
+++ b/dom/xul/nsXULPrototypeDocument.cpp
@@ -108,27 +108,25 @@ NS_NewXULPrototypeDocument(nsXULPrototypeDocument** aResult)
NS_IMETHODIMP
nsXULPrototypeDocument::Read(nsIObjectInputStream* aStream)
{
- nsresult rv;
-
nsCOMPtr 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 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);
@@ -136,12 +134,11 @@ nsXULPrototypeDocument::Read(nsIObjectInputStream* aStream)
// nsIPrincipal mNodeInfoManager->mPrincipal
- nsCOMPtr 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 principal = do_QueryInterface(supports);
// Better safe than sorry....
mNodeInfoManager->SetDocumentPrincipal(principal);
@@ -150,45 +147,45 @@ nsXULPrototypeDocument::Read(nsIObjectInputStream* aStream)
// mozilla::dom::NodeInfo table
nsTArray> 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 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 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);
}
@@ -196,41 +193,36 @@ nsXULPrototypeDocument::Read(nsIObjectInputStream* aStream)
// 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 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
diff --git a/js/public/StructuredClone.h b/js/public/StructuredClone.h
index 5244f45a5fcf..f26d2c750f93 100644
--- a/js/public/StructuredClone.h
+++ b/js/public/StructuredClone.h
@@ -20,16 +20,143 @@
#include "js/Value.h"
#include "js/Vector.h"
+/*
+ * API for safe passing of structured data, HTML 2018 Feb 21 section 2.7.
+ *
+ *
+ * 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 .
+ * 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
};
@@ -168,12 +295,6 @@ typedef bool (*TransferStructuredCloneOp)(JSContext* cx,
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;
@@ -257,7 +378,11 @@ public:
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,
@@ -265,6 +390,9 @@ JS_ReadStructuredClone(JSContext* cx, JSStructuredCloneData& data, uint32_t vers
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.
diff --git a/js/src/builtin/SelfHostingDefines.h b/js/src/builtin/SelfHostingDefines.h
index 5ca1b7514d77..81e51aa34875 100644
--- a/js/src/builtin/SelfHostingDefines.h
+++ b/js/src/builtin/SelfHostingDefines.h
@@ -23,6 +23,9 @@
// 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]
diff --git a/js/src/builtin/String.js b/js/src/builtin/String.js
index 8708d16394ae..572dfc88818b 100644
--- a/js/src/builtin/String.js
+++ b/js/src/builtin/String.js
@@ -68,8 +68,7 @@ function String_generic_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);
@@ -83,21 +82,28 @@ function String_pad(maxLength, fillString, padEnd = false) {
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)
@@ -503,11 +509,14 @@ function String_repeat(count) {
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 = "";
diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp
index a6b7b010fe27..e0cb7c5d1947 100644
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -2911,7 +2911,7 @@ const Class CloneBufferObject::class_ = {
const JSPropertySpec CloneBufferObject::props_[] = {
JS_PSGS("clonebuffer", getCloneBuffer, setCloneBuffer, 0),
- JS_PSG("arraybuffer", getCloneBufferAsArrayBuffer, 0),
+ JS_PSGS("arraybuffer", getCloneBufferAsArrayBuffer, setCloneBuffer, 0),
JS_PS_END
};
diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp
index 59fb359e84a1..fe0969fae6da 100644
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -895,7 +895,7 @@ BytecodeEmitter::EmitterScope::enterLexical(BytecodeEmitter* bce, ScopeKind kind
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
@@ -6831,24 +6831,12 @@ BytecodeEmitter::emitLexicalScope(ParseNode* pn)
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;
}
diff --git a/js/src/jit-test/lib/stepping.js b/js/src/jit-test/lib/stepping.js
new file mode 100644
index 000000000000..122fd9631936
--- /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(","));
+}
diff --git a/js/src/jit-test/tests/debug/Frame-onStep-19.js b/js/src/jit-test/tests/debug/Frame-onStep-19.js
index 3997b21182cd..019c026a8e49 100644
--- a/js/src/jit-test/tests/debug/Frame-onStep-19.js
+++ b/js/src/jit-test/tests/debug/Frame-onStep-19.js
@@ -6,48 +6,25 @@
// 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
@@ -59,5 +36,6 @@ runTest(
class Car {} // 8
return x; // 9
} // 10
+ f
`,
- [2, 3, 8, 9, 10]);
+ [1, 2, 3, 8, 9, 10]);
diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp
index bb78da3d47dd..6c482e6694f4 100644
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -4532,9 +4532,16 @@ LIRGenerator::visitWasmBoundsCheck(MWasmBoundsCheck* ins)
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
}
diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h
index f318568dce75..1b5f5b7aa9f3 100644
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -14236,6 +14236,9 @@ class MWasmBoundsCheck
{
// Bounds check is effectful: it throws for OOB.
setGuard();
+
+ if (JitOptions.spectreIndexMasking)
+ setResultType(MIRType::Int32);
}
public:
diff --git a/js/src/jit/MacroAssembler.h b/js/src/jit/MacroAssembler.h
index 00b74fdcdf07..6d3aa79a5950 100644
--- a/js/src/jit/MacroAssembler.h
+++ b/js/src/jit/MacroAssembler.h
@@ -1470,8 +1470,10 @@ class MacroAssembler : public MacroAssemblerSpecific
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
inline void wasmBoundsCheck(Condition cond, Register index, Register boundsCheckLimit, L label)
DEFINED_ON(arm, arm64, mips32, mips64, x86);
diff --git a/js/src/jit/WasmBCE.cpp b/js/src/jit/WasmBCE.cpp
index 424c5441dc72..af5e5f44b684 100644
--- a/js/src/jit/WasmBCE.cpp
+++ b/js/src/jit/WasmBCE.cpp
@@ -15,6 +15,8 @@ using namespace mozilla;
typedef js::HashMap, 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.
@@ -60,13 +62,25 @@ jit::EliminateBoundsChecks(MIRGenerator* mir, MIRGraph& graph)
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;
@@ -90,6 +104,13 @@ jit::EliminateBoundsChecks(MIRGenerator* mir, MIRGraph& graph)
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;
diff --git a/js/src/jit/arm/MacroAssembler-arm-inl.h b/js/src/jit/arm/MacroAssembler-arm-inl.h
index b67636e71e28..fc325d79c03f 100644
--- a/js/src/jit/arm/MacroAssembler-arm-inl.h
+++ b/js/src/jit/arm/MacroAssembler-arm-inl.h
@@ -2301,6 +2301,8 @@ MacroAssembler::wasmBoundsCheck(Condition cond, Register index, Register boundsC
{
as_cmp(index, O2Reg(boundsCheckLimit));
as_b(label, cond);
+ if (JitOptions.spectreIndexMasking)
+ ma_mov(boundsCheckLimit, index, LeaveCC, cond);
}
template
@@ -2312,6 +2314,8 @@ MacroAssembler::wasmBoundsCheck(Condition cond, Register index, Address boundsCh
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
diff --git a/js/src/jit/shared/LIR-shared.h b/js/src/jit/shared/LIR-shared.h
index bd33bd99bd63..92846a917466 100644
--- a/js/src/jit/shared/LIR-shared.h
+++ b/js/src/jit/shared/LIR-shared.h
@@ -8428,7 +8428,7 @@ class LWasmAddOffset : public LInstructionHelper<1, 1, 0>
}
};
-class LWasmBoundsCheck : public LInstructionHelper<0, 2, 0>
+class LWasmBoundsCheck : public LInstructionHelper<1, 2, 0>
{
public:
LIR_HEADER(WasmBoundsCheck);
diff --git a/js/src/jit/x86/MacroAssembler-x86-inl.h b/js/src/jit/x86/MacroAssembler-x86-inl.h
index 43e5df690faf..5206028a8c24 100644
--- a/js/src/jit/x86/MacroAssembler-x86-inl.h
+++ b/js/src/jit/x86/MacroAssembler-x86-inl.h
@@ -1109,6 +1109,8 @@ MacroAssembler::wasmBoundsCheck(Condition cond, Register index, Register boundsC
{
cmp32(index, boundsCheckLimit);
j(cond, label);
+ if (JitOptions.spectreIndexMasking)
+ cmovCCl(cond, Operand(boundsCheckLimit), index);
}
template
@@ -1117,6 +1119,8 @@ MacroAssembler::wasmBoundsCheck(Condition cond, Register index, Address boundsCh
{
cmp32(index, Operand(boundsCheckLimit));
j(cond, label);
+ if (JitOptions.spectreIndexMasking)
+ cmovCCl(cond, Operand(boundsCheckLimit), index);
}
//}}} check_macroassembler_style
diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp
index daa8fb04062e..c6a7383585a7 100644
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -1683,11 +1683,11 @@ 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;
diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp
index bcb633fdfb83..0d93d85053e6 100644
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -42,6 +42,7 @@
#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"
@@ -3194,3 +3195,9 @@ js::GetSelfHostedFunctionName(JSFunction* fun)
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");
diff --git a/js/src/vm/StructuredClone.cpp b/js/src/vm/StructuredClone.cpp
index c7ddb7801cf4..c7cfd1d34015 100644
--- a/js/src/vm/StructuredClone.cpp
+++ b/js/src/vm/StructuredClone.cpp
@@ -5,26 +5,25 @@
* 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 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.
+ * The spec is in two parts:
*
- * 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.
+ * - StructuredSerialize examines a JS value and produces a graph of Records.
+ * - StructuredDeserialize walks the Records and produces a new JS value.
*
- * 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.
+ * The differences between our implementation and the spec are minor:
+ *
+ * - 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"
@@ -71,7 +70,7 @@ using JS::CanonicalizeNaN;
// 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,
@@ -119,11 +118,9 @@ enum StructuredDataType : uint32_t {
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,
@@ -380,7 +377,7 @@ class SCInput {
BufferIterator point;
};
-} /* namespace js */
+} // namespace js
struct JSStructuredCloneReader {
public:
@@ -432,7 +429,17 @@ struct JSStructuredCloneReader {
// 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.
@@ -736,7 +743,7 @@ 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());
@@ -748,7 +755,7 @@ 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();
@@ -844,9 +851,7 @@ SCInput::readArray(T* p, size_t nelems)
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 = mozilla::CheckedInt(nelems) * sizeof(T);
if (!size.isValid())
return reportTruncated();
@@ -915,15 +920,13 @@ SCOutput::write(uint64_t 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));
}
@@ -1031,7 +1034,7 @@ SCOutput::discardTransferables(const JSStructuredCloneCallbacks* cb, void* cbClo
DiscardTransferables(buf, cb, cbClosure);
}
-} /* namespace js */
+} // namespace js
JSStructuredCloneData::~JSStructuredCloneData()
{
@@ -1152,7 +1155,7 @@ 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);
@@ -1296,7 +1299,7 @@ JSStructuredCloneWriter::writeSharedWasmMemory(HandleObject obj)
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());
@@ -1317,10 +1320,8 @@ JSStructuredCloneWriter::startObject(HandleObject obj, bool* backref)
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;
@@ -1332,13 +1333,13 @@ JSStructuredCloneWriter::traverseObject(HandleObject obj)
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;
@@ -1365,13 +1366,13 @@ JSStructuredCloneWriter::traverseMap(HandleObject obj)
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);
}
@@ -1395,13 +1396,13 @@ JSStructuredCloneWriter::traverseSet(HandleObject obj)
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);
}
@@ -1587,7 +1588,7 @@ JSStructuredCloneWriter::startWrite(HandleValue v)
if (callbacks && callbacks->write)
return callbacks->write(context(), this, obj, closure);
- /* else fall through */
+ // else fall through
}
return reportDataCloneError(JS_SCERR_UNSUPPORTED_TYPE);
@@ -1786,11 +1787,9 @@ JSStructuredCloneWriter::write(HandleValue v)
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;
@@ -1852,7 +1851,7 @@ class Chars {
void forget() { p = nullptr; }
};
-} /* anonymous namespace */
+} // anonymous namespace
template
JSString*
@@ -1897,7 +1896,7 @@ JSStructuredCloneReader::readTypedArray(uint32_t arrayType, uint32_t nelems, Mut
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))
diff --git a/js/src/wasm/WasmCompile.cpp b/js/src/wasm/WasmCompile.cpp
index 396af8b68a3c..6d957e7f2726 100644
--- a/js/src/wasm/WasmCompile.cpp
+++ b/js/src/wasm/WasmCompile.cpp
@@ -414,6 +414,8 @@ InitialCompileFlags(const CompileArgs& args, Decoder& d, CompileMode* mode, Tier
*debug = debugEnabled ? DebugEnabled::True : DebugEnabled::False;
}
+extern unsigned redundantCount;
+
SharedModule
wasm::CompileBuffer(const CompileArgs& args, const ShareableBytes& bytecode, UniqueChars* error)
{
@@ -441,7 +443,11 @@ wasm::CompileBuffer(const CompileArgs& args, const ShareableBytes& bytecode, Uni
if (!DecodeModuleTail(d, &env))
return nullptr;
- return mg.finishModule(bytecode);
+ auto module = mg.finishModule(bytecode);
+
+ printf("# redundant: %u\n", redundantCount);
+
+ return module;
}
bool
diff --git a/js/src/wasm/WasmIonCompile.cpp b/js/src/wasm/WasmIonCompile.cpp
index baf00251f0cf..13f34c5e3135 100644
--- a/js/src/wasm/WasmIonCompile.cpp
+++ b/js/src/wasm/WasmIonCompile.cpp
@@ -832,8 +832,12 @@ class FunctionCompiler
}
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) {
diff --git a/mobile/android/geckoview/build.gradle b/mobile/android/geckoview/build.gradle
index 8e2662f97b9e..9f26fd85d7c4 100644
--- a/mobile/android/geckoview/build.gradle
+++ b/mobile/android/geckoview/build.gradle
@@ -184,7 +184,8 @@ android.libraryVariants.all { variant ->
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)
@@ -195,6 +196,7 @@ android.libraryVariants.all { variant ->
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"
diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java
index 58c3608e0bb5..65d14071fcd3 100644
--- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java
@@ -353,7 +353,7 @@ public class GeckoSession extends LayerSession
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;
@@ -1405,17 +1405,6 @@ public class GeckoSession extends LayerSession
}
}
- 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.
diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/TextInputController.java b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/TextInputController.java
index 18c63f3729cd..7f95bb589c43 100644
--- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/TextInputController.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/TextInputController.java
@@ -107,7 +107,7 @@ public final class TextInputController {
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 {
diff --git a/modules/libpref/Preferences.cpp b/modules/libpref/Preferences.cpp
index 491aeec95733..487313481571 100644
--- a/modules/libpref/Preferences.cpp
+++ b/modules/libpref/Preferences.cpp
@@ -326,8 +326,9 @@ static ArenaAllocator<8192, 1> gPrefNameArena;
class Pref
{
public:
- explicit Pref()
- : mType(static_cast(PrefType::None))
+ explicit Pref(const char* aName)
+ : mName(ArenaStrdup(aName, gPrefNameArena))
+ , mType(static_cast(PrefType::None))
, mIsSticky(false)
, mIsLocked(false)
, mHasDefaultValue(false)
@@ -340,10 +341,15 @@ public:
~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(mType); }
@@ -395,6 +401,15 @@ public:
// 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()) {
@@ -454,16 +469,11 @@ public:
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;
@@ -492,6 +502,7 @@ public:
void FromDomPref(const dom::Pref& aDomPref, bool* aValueChanged)
{
MOZ_ASSERT(!XRE_IsParentProcess());
+ MOZ_ASSERT(strcmp(mName, aDomPref.name().get()) == 0);
mIsLocked = aDomPref.isLocked();
@@ -677,6 +688,7 @@ public:
void AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf, PrefsSizes& aSizes)
{
+ // Note: mName is allocated in gPrefNameArena, measured elsewhere.
aSizes.mPrefValues += aMallocSizeOf(this);
if (IsTypeString()) {
if (mHasDefaultValue) {
@@ -689,6 +701,8 @@ public:
}
private:
+ const char* mName; // allocated in gPrefNameArena
+
uint32_t mType : 2;
uint32_t mIsSticky : 1;
uint32_t mIsLocked : 1;
@@ -700,6 +714,36 @@ private:
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(aEntry);
+ auto prefName = static_cast(aKey);
+
+ return entry->mPref->MatchEntry(prefName);
+ }
+
+ static void InitEntry(PLDHashEntryHdr* aEntry, const void* aKey)
+ {
+ auto entry = static_cast(aEntry);
+ auto prefName = static_cast(aKey);
+
+ entry->mPref = new Pref(prefName);
+ }
+
+ static void ClearEntry(PLDHashTable* aTable, PLDHashEntryHdr* aEntry)
+ {
+ auto entry = static_cast(aEntry);
+
+ delete entry->mPref;
+ entry->mPref = nullptr;
+ }
+};
+
struct CallbackNode
{
CallbackNode(const char* aDomain,
@@ -725,21 +769,7 @@ struct CallbackNode
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;
-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.
@@ -752,6 +782,14 @@ static bool gIsAnyPrefLocked = false;
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);
@@ -765,10 +803,10 @@ 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(iter.Get())->mPref;
nsAutoCString prefValueStr;
if (!pref->UserValueToStringForSaving(prefValueStr)) {
@@ -776,7 +814,7 @@ pref_savePrefs()
}
nsAutoCString prefNameStr;
- StrEscape(iter.Key(), prefNameStr);
+ StrEscape(pref->Name(), prefNameStr);
nsPrintfCString str(
"user_pref(%s, %s);", prefNameStr.get(), prefValueStr.get());
@@ -827,7 +865,7 @@ IsEarlyPref(const char* aPrefName)
#endif // DEBUG
-static PrefsTable::LookupResult
+static PrefEntry*
pref_HashTableLookupInner(const char* aPrefName)
{
MOZ_ASSERT(NS_IsMainThread() || mozilla::ServoStyleSet::IsInServoTraversal());
@@ -850,14 +888,14 @@ pref_HashTableLookupInner(const char* aPrefName)
}
#endif
- return gHashTable->Lookup(aPrefName);
+ return static_cast(gHashTable->Search(aPrefName));
}
static Pref*
pref_HashTableLookup(const char* aPrefName)
{
- PrefsTable::LookupResult entry = pref_HashTableLookupInner(aPrefName);
- return entry ? static_cast(entry.Data()) : nullptr;
+ PrefEntry* entry = pref_HashTableLookupInner(aPrefName);
+ return entry ? entry->mPref : nullptr;
}
static nsresult
@@ -874,7 +912,12 @@ pref_SetPref(const char* aPrefName,
return NS_ERROR_OUT_OF_MEMORY;
}
- Pref* pref = gHashTable->LookupOrAdd(aPrefName);
+ auto entry = static_cast(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);
@@ -1987,11 +2030,13 @@ nsPrefBranch::DeleteBranch(const char* aStartingAt)
Substring(branchName, 0, branchName.Length() - 1);
for (auto iter = gHashTable->Iter(); !iter.Done(); iter.Next()) {
+ Pref* pref = static_cast(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();
}
@@ -2026,8 +2071,9 @@ nsPrefBranch::GetChildList(const char* aStartingAt,
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(iter.Get())->mPref;
+ if (strncmp(pref->Name(), parent.get(), parentLen) == 0) {
+ prefArray.AppendElement(pref->Name());
}
}
@@ -2639,7 +2685,7 @@ PreferenceServiceReporter::CollectReports(
if (gHashTable) {
sizes.mHashTable += gHashTable->ShallowSizeOfIncludingThis(mallocSizeOf);
for (auto iter = gHashTable->Iter(); !iter.Done(); iter.Next()) {
- Pref* pref = iter.Data();
+ Pref* pref = static_cast(iter.Get())->mPref;
pref->AddSizeOfIncludingThis(mallocSizeOf, sizes);
}
}
@@ -2832,7 +2878,8 @@ Preferences::GetInstanceForService()
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();
@@ -3087,7 +3134,7 @@ 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;
@@ -3102,10 +3149,10 @@ Preferences::ResetUserPrefs()
Vector prefNames;
for (auto iter = gHashTable->Iter(); !iter.Done(); iter.Next()) {
- Pref* pref = iter.Data();
+ Pref* pref = static_cast(iter.Get())->mPref;
if (pref->HasUserValue()) {
- if (!prefNames.append(iter.Key())) {
+ if (!prefNames.append(pref->Name())) {
return NS_ERROR_OUT_OF_MEMORY;
}
@@ -3179,7 +3226,12 @@ Preferences::SetPreference(const dom::Pref& aDomPref)
const char* prefName = aDomPref.name().get();
- Pref* pref = gHashTable->LookupOrAdd(prefName);
+ auto entry = static_cast(gHashTable->Add(prefName, fallible));
+ if (!entry) {
+ return;
+ }
+
+ Pref* pref = entry->mPref;
bool valueChanged = false;
pref->FromDomPref(aDomPref, &valueChanged);
@@ -3195,7 +3247,7 @@ Preferences::SetPreference(const dom::Pref& aDomPref)
// 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
@@ -3223,9 +3275,9 @@ Preferences::GetPreferences(InfallibleTArray* 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(iter.Get())->mPref;
if (!pref->MustSendToContentProcesses()) {
// The pref value hasn't changed since it was initialized at startup.
@@ -3236,7 +3288,7 @@ Preferences::GetPreferences(InfallibleTArray* aDomPrefs)
if (pref->HasAdvisablySizedValues()) {
dom::Pref* setting = aDomPrefs->AppendElement();
- pref->ToDomPref(setting, iter.Key());
+ pref->ToDomPref(setting);
}
}
}
@@ -4132,13 +4184,13 @@ 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);
diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js
index 7199aa8f0a91..d003cb0c4bd4 100644
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -6012,3 +6012,8 @@ 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);
diff --git a/taskcluster/ci/beetmover-cdns/kind.yml b/taskcluster/ci/beetmover-cdns/kind.yml
index 218bb84f61a3..a3a5e0d07f05 100644
--- a/taskcluster/ci/beetmover-cdns/kind.yml
+++ b/taskcluster/ci/beetmover-cdns/kind.yml
@@ -12,6 +12,7 @@ transforms:
kind-dependencies:
- release-generate-checksums
+ - release-update-verify
job-defaults:
worker-type:
diff --git a/taskcluster/ci/build/linux.yml b/taskcluster/ci/build/linux.yml
index e7f341ffb64d..cbb238ee7f41 100644
--- a/taskcluster/ci/build/linux.yml
+++ b/taskcluster/ci/build/linux.yml
@@ -803,3 +803,65 @@ linux64-add-on-devel/opt:
- 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
diff --git a/taskcluster/taskgraph/transforms/tests.py b/taskcluster/taskgraph/transforms/tests.py
index a66c38592377..c131fd405672 100644
--- a/taskcluster/taskgraph/transforms/tests.py
+++ b/taskcluster/taskgraph/transforms/tests.py
@@ -1018,8 +1018,8 @@ def make_job_description(config, tests):
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
diff --git a/testing/gtest/mozilla/MozGTestBench.h b/testing/gtest/mozilla/MozGTestBench.h
index 082a61ad06ac..d7d98c489ab2 100644
--- a/testing/gtest/mozilla/MozGTestBench.h
+++ b/testing/gtest/mozilla/MozGTestBench.h
@@ -19,4 +19,9 @@ 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
diff --git a/testing/marionette/doc/PythonTests.md b/testing/marionette/doc/PythonTests.md
index 9c6b8dbc9407..f52ea5531b8e 100644
--- a/testing/marionette/doc/PythonTests.md
+++ b/testing/marionette/doc/PythonTests.md
@@ -7,7 +7,7 @@ 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
@@ -36,9 +36,8 @@ The test structure is illustrated here:
# 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
@@ -62,10 +61,9 @@ The API
-------
The full API documentation is found at
-http://marionette-client.readthedocs.io/en/master/, but the key
-objects are:
+, 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.
diff --git a/testing/marionette/doc/SeleniumAtoms.md b/testing/marionette/doc/SeleniumAtoms.md
index dc3b1c867b9d..9e73d079ceaa 100644
--- 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.
diff --git a/testing/marionette/doc/index.rst b/testing/marionette/doc/index.rst
index 6a60b92de814..0b8ffb18aa05 100644
--- a/testing/marionette/doc/index.rst
+++ b/testing/marionette/doc/index.rst
@@ -5,11 +5,6 @@ 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
diff --git a/testing/mozbase/mozlog/mozlog/commandline.py b/testing/mozbase/mozlog/mozlog/commandline.py
index 64e25f22c798..456692ec794c 100644
--- a/testing/mozbase/mozlog/mozlog/commandline.py
+++ b/testing/mozbase/mozlog/mozlog/commandline.py
@@ -15,12 +15,18 @@ 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),
}
@@ -28,6 +34,9 @@ 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)
@@ -121,7 +130,9 @@ def add_logging_group(parser, include_formatters=None):
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())
diff --git a/testing/talos/talos/tests/layout/benchmarks/displaylist_inactive_mutate.html b/testing/talos/talos/tests/layout/benchmarks/displaylist_inactive_mutate.html
new file mode 100644
index 000000000000..dd74a2617dc3
--- /dev/null
+++ b/testing/talos/talos/tests/layout/benchmarks/displaylist_inactive_mutate.html
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
+
diff --git a/testing/talos/talos/tests/layout/benchmarks/displaylist_mutate.html b/testing/talos/talos/tests/layout/benchmarks/displaylist_mutate.html
index b1668e402db6..22120c4bd8a2 100644
--- a/testing/talos/talos/tests/layout/benchmarks/displaylist_mutate.html
+++ b/testing/talos/talos/tests/layout/benchmarks/displaylist_mutate.html
@@ -37,9 +37,6 @@ function runFrame() {
if (window.tpRecordTime) {
window.tpRecordTime(end - start, start);
}
- if (parent.reportResults) {
- parent.reportResults(end - start, start);
- }
return;
}
diff --git a/testing/talos/talos/tests/layout/displaylist_mutate.manifest b/testing/talos/talos/tests/layout/displaylist_mutate.manifest
index 0e09c83d3d40..277ab4f259e6 100644
--- a/testing/talos/talos/tests/layout/displaylist_mutate.manifest
+++ b/testing/talos/talos/tests/layout/displaylist_mutate.manifest
@@ -1 +1,2 @@
% http://localhost/tests/layout/benchmarks/displaylist_mutate.html
+% http://localhost/tests/layout/benchmarks/displaylist_inactive_mutate.html
diff --git a/toolkit/modules/RemoteFinder.jsm b/toolkit/modules/RemoteFinder.jsm
index b6c5902f96cf..8c107bf1d640 100644
--- a/toolkit/modules/RemoteFinder.jsm
+++ b/toolkit/modules/RemoteFinder.jsm
@@ -209,10 +209,6 @@ function RemoteFinderListener(global) {
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);
@@ -318,7 +314,8 @@ RemoteFinderListener.prototype = {
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":
diff --git a/uriloader/base/nsURILoader.cpp b/uriloader/base/nsURILoader.cpp
index 90d56dee15c0..ff0d8079c099 100644
--- a/uriloader/base/nsURILoader.cpp
+++ b/uriloader/base/nsURILoader.cpp
@@ -49,6 +49,7 @@
#include "mozilla/Attributes.h"
#include "mozilla/IntegerPrintfMacros.h"
#include "mozilla/Preferences.h"
+#include "mozilla/Unused.h"
#include "nsContentUtils.h"
mozilla::LazyLogModule nsURILoader::mLog("URILoader");
@@ -60,6 +61,17 @@ mozilla::LazyLogModule nsURILoader::mLog("URILoader");
#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...
@@ -157,6 +169,11 @@ protected:
* nsIURIContentListeners.
*/
RefPtr mURILoader;
+
+ /**
+ * Limit of data conversion depth to prevent infinite conversion loops
+ */
+ uint32_t mDataConversionDepthLimit;
};
NS_IMPL_ADDREF(nsDocumentOpenInfo)
@@ -179,7 +196,8 @@ nsDocumentOpenInfo::nsDocumentOpenInfo(nsIInterfaceRequestor* aWindowContext,
nsURILoader* aURILoader)
: m_originalContext(aWindowContext),
mFlags(aFlags),
- mURILoader(aURILoader)
+ mURILoader(aURILoader),
+ mDataConversionDepthLimit(sConvertDataLimit)
{
}
@@ -625,6 +643,12 @@ nsDocumentOpenInfo::ConvertData(nsIRequest *request,
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;
@@ -648,6 +672,9 @@ nsDocumentOpenInfo::ConvertData(nsIRequest *request,
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;
@@ -885,6 +912,9 @@ nsresult nsURILoader::OpenChannel(nsIChannel* channel,
}
}
+ 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 loader =
diff --git a/xpcom/ds/nsISerializable.idl b/xpcom/ds/nsISerializable.idl
index f525f3a8f3d1..1920fa1b16d4 100644
--- a/xpcom/ds/nsISerializable.idl
+++ b/xpcom/ds/nsISerializable.idl
@@ -17,7 +17,7 @@ interface nsISerializable : nsISupports
* 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
diff --git a/xpcom/io/nsLocalFileWin.cpp b/xpcom/io/nsLocalFileWin.cpp
index a2e8e366b55c..3b62e4835ea3 100644
--- a/xpcom/io/nsLocalFileWin.cpp
+++ b/xpcom/io/nsLocalFileWin.cpp
@@ -1188,7 +1188,7 @@ nsLocalFile::OpenNSPRFileDesc(int32_t aFlags, int32_t aMode,
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;
}
@@ -1210,7 +1210,7 @@ nsLocalFile::Create(uint32_t aType, uint32_t aAttributes)
return NS_ERROR_FILE_UNKNOWN_TYPE;
}
- nsresult rv = ResolveAndStat();
+ nsresult rv = Resolve();
if (NS_FAILED(rv) && rv != NS_ERROR_FILE_NOT_FOUND) {
return rv;
}
@@ -1625,7 +1625,7 @@ typedef struct
NS_IMETHODIMP
nsLocalFile::GetVersionInfoField(const char* aField, nsAString& aResult)
{
- nsresult rv = ResolveAndStat();
+ nsresult rv = Resolve();
if (NS_FAILED(rv)) {
return rv;
}
@@ -2312,7 +2312,7 @@ nsLocalFile::SetLastModifiedTime(PRTime aLastModifiedTime)
// Check we are correctly initialized.
CHECK_mWorkingPath();
- nsresult rv = ResolveAndStat();
+ nsresult rv = Resolve();
if (NS_FAILED(rv)) {
return rv;
}
@@ -2458,7 +2458,7 @@ nsLocalFile::SetPermissions(uint32_t aPermissions)
// 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;
}
@@ -2547,7 +2547,7 @@ nsLocalFile::SetFileSize(int64_t aFileSize)
// Check we are correctly initialized.
CHECK_mWorkingPath();
- nsresult rv = ResolveAndStat();
+ nsresult rv = Resolve();
if (NS_FAILED(rv)) {
return rv;
}
@@ -3051,7 +3051,7 @@ nsLocalFile::GetTarget(nsAString& aResult)
return NS_ERROR_FILE_INVALID_PATH;
}
#endif
- ResolveAndStat();
+ Resolve();
aResult = mResolvedPath;
return NS_OK;