diff --git a/browser/app/Makefile.in b/browser/app/Makefile.in
index bfe906d821bc..767353a26f02 100644
--- a/browser/app/Makefile.in
+++ b/browser/app/Makefile.in
@@ -79,7 +79,7 @@ clean clobber repackage::
MAC_BUNDLE_VERSION = $(shell $(PYTHON) $(srcdir)/macversion.py --version=$(MOZ_APP_VERSION) --buildid=$(DEPTH)/buildid.h)
.PHONY: repackage
-tools repackage:: $(DIST)/bin/$(MOZ_APP_NAME) features
+tools repackage:: $(DIST)/bin/$(MOZ_APP_NAME)
rm -rf $(dist_dest)
$(MKDIR) -p '$(dist_dest)/Contents/MacOS'
$(MKDIR) -p '$(dist_dest)/$(LPROJ)'
@@ -100,7 +100,3 @@ ifdef MOZ_UPDATER
endif
printf APPLMOZB > '$(dist_dest)/Contents/PkgInfo'
endif
-
-.PHONY: features
-tools features::
- $(call py_action,generate_builtin_addons,--features=browser/features browser/chrome/browser/content/browser/built_in_addons.json)
diff --git a/config/faster/rules.mk b/config/faster/rules.mk
index 7ae9947a5fcd..3ca16dad317e 100644
--- a/config/faster/rules.mk
+++ b/config/faster/rules.mk
@@ -96,23 +96,3 @@ $(addprefix install-,$(INSTALL_MANIFESTS)): install-%: $(addprefix $(TOPOBJDIR)/
# that are not supported by data in moz.build.
$(TOPOBJDIR)/build/application.ini: $(TOPOBJDIR)/buildid.h $(TOPOBJDIR)/source-repo.h
-
-# The manifest of allowed system add-ons should be re-built when using
-# "build faster".
-#
-# Note the dependency on install-dist/bin. The form of this
-# dependency is critical: it's triggering the stem rule (install-%)
-# above to force the dist/bin manifest to be processed. The more
-# obvious `$(TOPOBJDIR)/install-dist_bin` doesn't work because
-# dist/bin isn't in $(INSTALL_MANIFESTS) in the
-# FasterMake+RecursiveMake (artifact build) situation.
-ifeq ($(MOZ_BUILD_APP),browser)
-$(TOPOBJDIR)/browser/app/features: install-dist/bin
-
-default: $(TOPOBJDIR)/browser/app/features
-endif
-ifeq ($(MOZ_BUILD_APP),mobile/android)
-$(TOPOBJDIR)/mobile/android/base/features: install-dist/bin
-
-default: $(TOPOBJDIR)/mobile/android/base/features
-endif
diff --git a/devtools/client/debugger/new/src/actions/ast.js b/devtools/client/debugger/new/src/actions/ast.js
index ef445bd41462..a244eea3fce2 100644
--- a/devtools/client/debugger/new/src/actions/ast.js
+++ b/devtools/client/debugger/new/src/actions/ast.js
@@ -101,12 +101,14 @@ function setOutOfScopeLocations() {
}
function compressPausePoints(pausePoints) {
- const compressed = {}
+ const compressed = {};
+
for (const line in pausePoints) {
- compressed[line] = {}
+ compressed[line] = {};
+
for (const col in pausePoints[line]) {
- const point = pausePoints[line][col]
- compressed[line][col] = (point.break && 1) | (point.step && 2)
+ const point = pausePoints[line][col];
+ compressed[line][col] = (point.break && 1) | (point.step && 2);
}
}
diff --git a/devtools/client/debugger/new/src/actions/preview.js b/devtools/client/debugger/new/src/actions/preview.js
index 14dd38c2bbd3..91ba7c28c989 100644
--- a/devtools/client/debugger/new/src/actions/preview.js
+++ b/devtools/client/debugger/new/src/actions/preview.js
@@ -11,8 +11,6 @@ var _preview = require("../utils/preview");
var _ast = require("../utils/ast");
-var _editor = require("../utils/editor/index");
-
var _devtoolsSourceMap = require("devtools/client/shared/source-map/index.js");
var _promise = require("./utils/middleware/promise");
@@ -25,74 +23,37 @@ var _expressions = require("./expressions");
var _pause = require("./pause/index");
-var _lodash = require("devtools/client/shared/vendor/lodash");
-
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at . */
-function isInvalidTarget(target) {
- if (!target || !target.innerText) {
- return true;
+function findExpressionMatch(state, codeMirror, tokenPos) {
+ const source = (0, _selectors.getSelectedSource)(state);
+ const symbols = (0, _selectors.getSymbols)(state, source);
+ let match;
+
+ if (!symbols || symbols.loading) {
+ match = (0, _getExpression.getExpressionFromCoords)(codeMirror, tokenPos);
+ } else {
+ match = (0, _ast.findBestMatchExpression)(symbols, tokenPos);
}
- const tokenText = target.innerText.trim();
- const cursorPos = target.getBoundingClientRect(); // exclude literal tokens where it does not make sense to show a preview
-
- const invalidType = ["cm-atom", ""].includes(target.className); // exclude syntax where the expression would be a syntax error
-
- const invalidToken = tokenText === "" || tokenText.match(/^[(){}\|&%,.;=<>\+-/\*\s](?=)/);
- const isPresentation = target.attributes.role && target.attributes.getNamedItem("role").value == "presentation"; // exclude codemirror elements that are not tokens
-
- const invalidTarget = target.parentElement && !target.parentElement.closest(".CodeMirror-line") || cursorPos.top == 0;
- return invalidTarget || invalidToken || invalidType || isPresentation;
+ return match;
}
-function updatePreview(target, editor) {
+function updatePreview(target, tokenPos, codeMirror) {
return ({
dispatch,
getState,
client,
sourceMaps
}) => {
- const tokenPos = (0, _editor.getTokenLocation)(editor.codeMirror, target);
const cursorPos = target.getBoundingClientRect();
- const preview = (0, _selectors.getPreview)(getState());
- if ((0, _selectors.getCanRewind)(getState())) {
+ if ((0, _selectors.getCanRewind)(getState()) || !(0, _selectors.isSelectedFrameVisible)(getState()) || !(0, _selectors.isLineInScope)(getState(), tokenPos.line)) {
return;
}
- if (preview) {
- // Return early if we are currently showing another preview or
- // if we are mousing over the same token as before
- if (preview.updating || (0, _lodash.isEqual)(preview.tokenPos, tokenPos)) {
- return;
- } // We are mousing over a new token that is not in the preview
-
-
- if (!target.classList.contains("debug-expression")) {
- dispatch(clearPreview());
- }
- }
-
- if (isInvalidTarget(target)) {
- dispatch(clearPreview());
- return;
- }
-
- if (!(0, _selectors.isSelectedFrameVisible)(getState()) || !(0, _selectors.isLineInScope)(getState(), tokenPos.line)) {
- return;
- }
-
- const source = (0, _selectors.getSelectedSource)(getState());
- const symbols = (0, _selectors.getSymbols)(getState(), source);
- let match;
-
- if (!symbols || symbols.loading) {
- match = (0, _getExpression.getExpressionFromCoords)(editor.codeMirror, tokenPos);
- } else {
- match = (0, _ast.findBestMatchExpression)(symbols, tokenPos);
- }
+ const match = findExpressionMatch(getState(), codeMirror, tokenPos);
if (!match) {
return;
diff --git a/devtools/client/debugger/new/src/components/Editor/Preview/Popup.js b/devtools/client/debugger/new/src/components/Editor/Preview/Popup.js
index 312760caf278..0eb7a4026f63 100644
--- a/devtools/client/debugger/new/src/components/Editor/Preview/Popup.js
+++ b/devtools/client/debugger/new/src/components/Editor/Preview/Popup.js
@@ -29,8 +29,6 @@ var _PreviewFunction = require("../../shared/PreviewFunction");
var _PreviewFunction2 = _interopRequireDefault(_PreviewFunction);
-var _editor = require("../../../utils/editor/index");
-
var _preview = require("../../../utils/preview");
var _Svg = require("devtools/client/debugger/new/dist/vendors").vendored["Svg"];
@@ -63,6 +61,18 @@ const {
loadItemProperties
} = ObjectInspectorUtils.loadProperties;
+function inPreview(event) {
+ const relatedTarget = event.relatedTarget;
+
+ if (!relatedTarget || relatedTarget.classList.contains("preview-expression")) {
+ return true;
+ } // $FlowIgnore
+
+
+ const inPreviewSelection = document.elementsFromPoint(event.clientX, event.clientY).some(el => el.classList.contains("preview-selection"));
+ return inPreviewSelection;
+}
+
class Popup extends _react.Component {
constructor(...args) {
var _temp;
@@ -70,11 +80,13 @@ class Popup extends _react.Component {
return _temp = super(...args), this.onMouseLeave = e => {
const relatedTarget = e.relatedTarget;
- if (relatedTarget && relatedTarget.classList && (relatedTarget.classList.contains("popover") || relatedTarget.classList.contains("debug-expression") || relatedTarget.classList.contains("editor-mount"))) {
- return;
+ if (!relatedTarget) {
+ return this.props.onClose();
}
- this.props.onClose();
+ if (!inPreview(e)) {
+ this.props.onClose();
+ }
}, _temp;
}
@@ -96,26 +108,6 @@ class Popup extends _react.Component {
}
}
- componentDidMount() {
- const {
- value,
- editor,
- range
- } = this.props;
-
- if (!value || !value.type == "object") {
- return;
- }
-
- this.marker = (0, _editor.markText)(editor, "preview-selection", range);
- }
-
- componentWillUnmount() {
- if (this.marker) {
- this.marker.clear();
- }
- }
-
getRoot() {
const {
expression,
diff --git a/devtools/client/debugger/new/src/components/Editor/Preview/index.js b/devtools/client/debugger/new/src/components/Editor/Preview/index.js
index e37029d5e75a..72299c6a6c7c 100644
--- a/devtools/client/debugger/new/src/components/Editor/Preview/index.js
+++ b/devtools/client/debugger/new/src/components/Editor/Preview/index.js
@@ -27,15 +27,40 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
/* 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 inPopup(e) {
+ const {
+ relatedTarget
+ } = e;
+
+ if (!relatedTarget) {
+ return true;
+ }
+
+ const pop = relatedTarget.closest(".popover") || relatedTarget.classList.contains("debug-expression");
+ return pop;
+}
+
+function getElementFromPos(pos) {
+ // $FlowIgnore
+ return document.elementFromPoint(pos.x + pos.width / 2, pos.y + pos.height / 2);
+}
+
class Preview extends _react.PureComponent {
constructor(props) {
super(props);
+ this.target = null;
- this.onMouseOver = e => {
- const {
- target
- } = e;
- this.props.updatePreview(target, this.props.editor);
+ this.onTokenEnter = ({
+ target,
+ tokenPos
+ }) => {
+ this.props.updatePreview(target, tokenPos, this.props.editor.codeMirror);
+ };
+
+ this.onTokenLeave = e => {
+ if (!inPopup(e)) {
+ this.props.clearPreview();
+ }
};
this.onMouseUp = () => {
@@ -52,17 +77,11 @@ class Preview extends _react.PureComponent {
return true;
};
- this.onMouseLeave = e => {
- const target = e.target;
-
- if (target.classList.contains("CodeMirror")) {
- return;
- }
-
+ this.onScroll = () => {
this.props.clearPreview();
};
- this.onClose = () => {
+ this.onClose = e => {
this.props.clearPreview();
};
@@ -72,30 +91,54 @@ class Preview extends _react.PureComponent {
}
componentDidMount() {
+ this.updateListeners();
+ }
+
+ componentDidUpdate(prevProps) {
+ this.updateListeners(prevProps);
+ this.updateHighlight(prevProps);
+ }
+
+ updateListeners(prevProps) {
+ const {
+ isPaused
+ } = this.props;
const {
codeMirror
} = this.props.editor;
const codeMirrorWrapper = codeMirror.getWrapperElement();
- codeMirrorWrapper.addEventListener("mouseover", this.onMouseOver);
- codeMirrorWrapper.addEventListener("mouseup", this.onMouseUp);
- codeMirrorWrapper.addEventListener("mousedown", this.onMouseDown);
- codeMirrorWrapper.addEventListener("mouseleave", this.onMouseLeave);
+ const wasNotPaused = !prevProps || !prevProps.isPaused;
+ const wasPaused = prevProps && prevProps.isPaused;
- if (document.body) {
- document.body.addEventListener("mouseleave", this.onMouseLeave);
+ if (isPaused && wasNotPaused) {
+ codeMirror.on("scroll", this.onScroll);
+ codeMirror.on("tokenenter", this.onTokenEnter);
+ codeMirror.on("tokenleave", this.onTokenLeave);
+ codeMirrorWrapper.addEventListener("mouseup", this.onMouseUp);
+ codeMirrorWrapper.addEventListener("mousedown", this.onMouseDown);
+ }
+
+ if (!isPaused && wasPaused) {
+ codeMirror.off("tokenenter", this.onTokenEnter);
+ codeMirror.off("tokenleave", this.onTokenLeave);
+ codeMirrorWrapper.removeEventListener("mouseup", this.onMouseUp);
+ codeMirrorWrapper.removeEventListener("mousedown", this.onMouseDown);
}
}
- componentWillUnmount() {
- const codeMirror = this.props.editor.codeMirror;
- const codeMirrorWrapper = codeMirror.getWrapperElement();
- codeMirrorWrapper.removeEventListener("mouseover", this.onMouseOver);
- codeMirrorWrapper.removeEventListener("mouseup", this.onMouseUp);
- codeMirrorWrapper.removeEventListener("mousedown", this.onMouseDown);
- codeMirrorWrapper.removeEventListener("mouseleave", this.onMouseLeave);
+ updateHighlight(prevProps) {
+ const {
+ preview
+ } = this.props;
- if (document.body) {
- document.body.removeEventListener("mouseleave", this.onMouseLeave);
+ if (preview && !preview.updating) {
+ const target = getElementFromPos(preview.cursorPos);
+ target && target.classList.add("preview-selection");
+ }
+
+ if (prevProps.preview && !prevProps.preview.updating) {
+ const target = getElementFromPos(prevProps.preview.cursorPos);
+ target && target.classList.remove("preview-selection");
}
}
@@ -143,6 +186,7 @@ class Preview extends _react.PureComponent {
const mapStateToProps = state => ({
preview: (0, _selectors.getPreview)(state),
+ isPaused: (0, _selectors.getIsPaused)(state),
selectedSource: (0, _selectors.getSelectedSource)(state)
});
diff --git a/devtools/client/debugger/new/src/components/Editor/index.js b/devtools/client/debugger/new/src/components/Editor/index.js
index 4ff680a9ef92..7eaf8727cc1c 100644
--- a/devtools/client/debugger/new/src/components/Editor/index.js
+++ b/devtools/client/debugger/new/src/components/Editor/index.js
@@ -261,6 +261,7 @@ class Editor extends _react.PureComponent {
codeMirrorWrapper.tabIndex = 0;
codeMirrorWrapper.addEventListener("keydown", e => this.onKeyDown(e));
codeMirrorWrapper.addEventListener("click", e => this.onClick(e));
+ codeMirrorWrapper.addEventListener("mouseover", (0, _editor.onMouseOver)(codeMirror));
const toggleFoldMarkerVisibility = e => {
if (node instanceof HTMLElement) {
diff --git a/devtools/client/debugger/new/src/components/SecondaryPanes/Breakpoints/Breakpoint.js b/devtools/client/debugger/new/src/components/SecondaryPanes/Breakpoints/Breakpoint.js
index 9f23d40030b9..5c972b2a3c38 100644
--- a/devtools/client/debugger/new/src/components/SecondaryPanes/Breakpoints/Breakpoint.js
+++ b/devtools/client/debugger/new/src/components/SecondaryPanes/Breakpoints/Breakpoint.js
@@ -152,6 +152,8 @@ class Breakpoint extends _react.PureComponent {
__html: node.innerHTML
};
}
+ /* eslint-disable react/no-danger */
+
render() {
const {
diff --git a/devtools/client/debugger/new/src/components/shared/Popover.js b/devtools/client/debugger/new/src/components/shared/Popover.js
index 1d9ee2c2cab9..a5bb7ad61c93 100644
--- a/devtools/client/debugger/new/src/components/shared/Popover.js
+++ b/devtools/client/debugger/new/src/components/shared/Popover.js
@@ -57,18 +57,6 @@ class Popover extends _react.Component {
return this.calculateTopForRightOrientation(target, editor, popover);
};
- this.onMouseLeave = e => {
- const {
- onMouseLeave
- } = this.props;
-
- if (/^(bracket-arrow|gap)$/.test(e.currentTarget.className)) {
- return;
- }
-
- onMouseLeave(e);
- };
-
this.state = {
left: 0,
top: 0,
@@ -260,7 +248,7 @@ class Popover extends _react.Component {
className: (0, _classnames2.default)("popover", `orientation-${orientation}`, {
up: orientation === "up"
}),
- onMouseLeave: this.onMouseLeave,
+ onMouseLeave: this.props.onMouseLeave,
style: {
top,
left
diff --git a/devtools/client/debugger/new/src/reducers/ast.js b/devtools/client/debugger/new/src/reducers/ast.js
index 9bf70204dfb7..f3b502b8a22d 100644
--- a/devtools/client/debugger/new/src/reducers/ast.js
+++ b/devtools/client/debugger/new/src/reducers/ast.js
@@ -103,11 +103,16 @@ function update(state = initialASTState(), action) {
if (!action.value) {
return state.set("preview", null);
+ } // NOTE: if the preview does not exist, it has been cleared
+
+
+ if (state.get("preview")) {
+ return state.set("preview", _objectSpread({}, action.value, {
+ updating: false
+ }));
}
- return state.set("preview", _objectSpread({}, action.value, {
- updating: false
- }));
+ return state;
}
case "RESUME":
diff --git a/devtools/client/debugger/new/src/reducers/pause.js b/devtools/client/debugger/new/src/reducers/pause.js
index 5c2a2e11a7be..e53cde05a6b1 100644
--- a/devtools/client/debugger/new/src/reducers/pause.js
+++ b/devtools/client/debugger/new/src/reducers/pause.js
@@ -8,6 +8,7 @@ exports.getPauseReason = getPauseReason;
exports.getPauseCommand = getPauseCommand;
exports.isStepping = isStepping;
exports.isPaused = isPaused;
+exports.getIsPaused = getIsPaused;
exports.getPreviousPauseFrameLocation = getPreviousPauseFrameLocation;
exports.isEvaluatingExpression = isEvaluatingExpression;
exports.getPopupObjectProperties = getPopupObjectProperties;
@@ -304,6 +305,10 @@ function isPaused(state) {
return !!getFrames(state);
}
+function getIsPaused(state) {
+ return !!getFrames(state);
+}
+
function getPreviousPauseFrameLocation(state) {
return state.pause.previousLocation;
}
diff --git a/devtools/client/debugger/new/src/utils/editor/index.js b/devtools/client/debugger/new/src/utils/editor/index.js
index f56f27ec4237..d0a61fa57371 100644
--- a/devtools/client/debugger/new/src/utils/editor/index.js
+++ b/devtools/client/debugger/new/src/utils/editor/index.js
@@ -3,6 +3,7 @@
Object.defineProperty(exports, "__esModule", {
value: true
});
+exports.onMouseOver = undefined;
var _sourceDocuments = require("./source-documents");
@@ -51,6 +52,15 @@ Object.keys(_ui).forEach(function (key) {
}
});
});
+
+var _tokenEvents = require("./token-events");
+
+Object.defineProperty(exports, "onMouseOver", {
+ enumerable: true,
+ get: function () {
+ return _tokenEvents.onMouseOver;
+ }
+});
exports.getEditor = getEditor;
exports.removeEditor = removeEditor;
exports.shouldShowPrettyPrint = shouldShowPrettyPrint;
diff --git a/devtools/client/debugger/new/src/utils/editor/moz.build b/devtools/client/debugger/new/src/utils/editor/moz.build
index 5197e883430f..0910fd9f41af 100644
--- a/devtools/client/debugger/new/src/utils/editor/moz.build
+++ b/devtools/client/debugger/new/src/utils/editor/moz.build
@@ -15,4 +15,5 @@ DevToolsModules(
'source-documents.js',
'source-editor.js',
'source-search.js',
+ 'token-events.js',
)
diff --git a/devtools/client/debugger/new/src/utils/editor/token-events.js b/devtools/client/debugger/new/src/utils/editor/token-events.js
new file mode 100644
index 000000000000..1a6d1987a132
--- /dev/null
+++ b/devtools/client/debugger/new/src/utils/editor/token-events.js
@@ -0,0 +1,93 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.onMouseOver = onMouseOver;
+
+var _ = require("./index");
+
+var _lodash = require("devtools/client/shared/vendor/lodash");
+
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at . */
+function isInvalidTarget(target) {
+ if (!target || !target.innerText) {
+ return true;
+ }
+
+ const tokenText = target.innerText.trim();
+ const cursorPos = target.getBoundingClientRect(); // exclude literal tokens where it does not make sense to show a preview
+
+ const invalidType = ["cm-atom", ""].includes(target.className); // exclude syntax where the expression would be a syntax error
+
+ const invalidToken = tokenText === "" || tokenText.match(/^[(){}\|&%,.;=<>\+-/\*\s](?=)/); // exclude codemirror elements that are not tokens
+
+ const invalidTarget = target.parentElement && !target.parentElement.closest(".CodeMirror-line") || cursorPos.top == 0;
+ const invalidClasses = ["editor-mount"];
+
+ if (invalidClasses.some(className => target.classList.contains(className))) {
+ return true;
+ }
+
+ if (target.closest(".popover")) {
+ return true;
+ }
+
+ return invalidTarget || invalidToken || invalidType;
+}
+
+function dispatch(codeMirror, eventName, data) {
+ codeMirror.constructor.signal(codeMirror, eventName, data);
+}
+
+function invalidLeaveTarget(target) {
+ if (!target || target.closest(".popover")) {
+ return true;
+ }
+
+ return false;
+}
+
+function onMouseOver(codeMirror) {
+ let prevTokenPos = null;
+
+ function onMouseLeave(event) {
+ if (invalidLeaveTarget(event.relatedTarget)) {
+ return addMouseLeave(event.target);
+ }
+
+ prevTokenPos = null;
+ dispatch(codeMirror, "tokenleave", event);
+ }
+
+ function addMouseLeave(target) {
+ target.addEventListener("mouseleave", onMouseLeave, {
+ capture: true,
+ once: true
+ });
+ }
+
+ return enterEvent => {
+ const {
+ target
+ } = enterEvent;
+
+ if (isInvalidTarget(target)) {
+ return;
+ }
+
+ const tokenPos = (0, _.getTokenLocation)(codeMirror, target);
+
+ if (!(0, _lodash.isEqual)(prevTokenPos, tokenPos)) {
+ addMouseLeave(target);
+ dispatch(codeMirror, "tokenenter", {
+ event: enterEvent,
+ target,
+ tokenPos
+ });
+ prevTokenPos = tokenPos;
+ }
+ };
+}
\ No newline at end of file
diff --git a/devtools/client/debugger/new/test/mochitest/browser.ini b/devtools/client/debugger/new/test/mochitest/browser.ini
index 9affd8b99d43..240e1d96f94d 100644
--- a/devtools/client/debugger/new/test/mochitest/browser.ini
+++ b/devtools/client/debugger/new/test/mochitest/browser.ini
@@ -158,7 +158,7 @@ skip-if = (os == "win" && ccov) # Bug 1453549
skip-if = ccov || (verify && debug && (os == 'linux')) # Bug 1441545
[browser_dbg-sourcemapped-stepping.js]
[browser_dbg-sourcemapped-preview.js]
-skip-if = (os == "win" && ccov) || (os == "win" && !debug) # Bug 1448523, Bug 1448450
+skip-if = os == "win" # Bug 1448523, Bug 1448450
[browser_dbg-breaking.js]
[browser_dbg-breaking-from-console.js]
[browser_dbg-breakpoints.js]
diff --git a/devtools/client/debugger/new/test/mochitest/browser_dbg-pause-points.js b/devtools/client/debugger/new/test/mochitest/browser_dbg-pause-points.js
index 1817f758daac..10f5a4088197 100644
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-pause-points.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-pause-points.js
@@ -32,6 +32,7 @@ async function testCase(dbg, { name, count, steps }) {
add_task(async function test() {
const dbg = await initDebugger("doc-pause-points.html");
+ await selectSource(dbg, "pause-points.js")
await testCase(dbg, {
name: "statements",
count: 7,
diff --git a/devtools/client/debugger/new/test/mochitest/browser_dbg-preview-module.js b/devtools/client/debugger/new/test/mochitest/browser_dbg-preview-module.js
index 81cc9b245b58..365639c78599 100644
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-preview-module.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-preview-module.js
@@ -5,10 +5,7 @@
// and doesn't have functions.
add_task(async function() {
const dbg = await initDebugger("doc-scripts.html");
- const {
- selectors: { getSelectedSource },
- getState
- } = dbg;
+ const { selectors: { getSelectedSource }, getState } = dbg;
navigate(dbg, "doc-on-load.html");
diff --git a/devtools/client/debugger/new/test/mochitest/helpers.js b/devtools/client/debugger/new/test/mochitest/helpers.js
index d1146f2581c0..56941f1af947 100644
--- a/devtools/client/debugger/new/test/mochitest/helpers.js
+++ b/devtools/client/debugger/new/test/mochitest/helpers.js
@@ -1213,18 +1213,31 @@ function getCoordsFromPosition(cm, { line, ch }) {
return cm.charCoords({ line: ~~line, ch: ~~ch });
}
-function hoverAtPos(dbg, { line, ch }) {
+async function waitForScrolling(codeMirror) {
+ return new Promise(resolve => {
+ codeMirror.on("scroll", resolve);
+ setTimeout(resolve, 500);
+ })
+}
+
+
+async function hoverAtPos(dbg, { line, ch }) {
info(`Hovering at ${line}, ${ch}`);
const cm = getCM(dbg);
// Ensure the line is visible with margin because the bar at the bottom of
// the editor overlaps into what the editor things is its own space, blocking
// the click event below.
- cm.scrollIntoView({ line: line - 1, ch }, 100);
+ cm.scrollIntoView({ line: line - 1, ch }, 0);
+ await waitForScrolling(cm);
const coords = getCoordsFromPosition(cm, { line: line - 1, ch });
const tokenEl = dbg.win.document.elementFromPoint(coords.left, coords.top);
+ if (!tokenEl) {
+ return false;
+ }
+
tokenEl.dispatchEvent(
new MouseEvent("mouseover", {
bubbles: true,
@@ -1234,6 +1247,9 @@ function hoverAtPos(dbg, { line, ch }) {
);
}
+// tryHovering will hover at a position every second until we
+// see a preview element (popup, tooltip) appear. Once it appears,
+// it considers it a success.
function tryHovering(dbg, line, column, elementName) {
return new Promise((resolve, reject) => {
const element = waitForElement(dbg, elementName);
@@ -1251,7 +1267,7 @@ function tryHovering(dbg, line, column, elementName) {
}
hoverAtPos(dbg, { line, ch: column - 1 });
- }, 200);
+ }, 1000);
});
}
diff --git a/devtools/server/actors/thread.js b/devtools/server/actors/thread.js
index 5dafc2bfd907..e11cb9bec19a 100644
--- a/devtools/server/actors/thread.js
+++ b/devtools/server/actors/thread.js
@@ -536,6 +536,7 @@ const ThreadActor = ActorClassWithSpec(threadSpec, {
// When pause points are specified for the source,
// we should pause when we are at a stepOver pause point
const pausePoint = findPausePointForLocation(pausePoints, newLocation);
+
if (pausePoint) {
if (pausePoint.step) {
return pauseAndRespond(this);
diff --git a/dom/base/nsINode.cpp b/dom/base/nsINode.cpp
index 2bf26d0a4c11..673d1c537993 100644
--- a/dom/base/nsINode.cpp
+++ b/dom/base/nsINode.cpp
@@ -1313,18 +1313,6 @@ ReparentWrappersInSubtree(nsIContent* aRoot)
JSContext* cx = jsapi.cx();
- nsIGlobalObject* docGlobal = aRoot->OwnerDoc()->GetScopeObject();
- if (NS_WARN_IF(!docGlobal)) {
- return NS_ERROR_UNEXPECTED;
- }
-
- JS::Rooted rootedGlobal(cx, docGlobal->GetGlobalJSObject());
- if (NS_WARN_IF(!rootedGlobal)) {
- return NS_ERROR_UNEXPECTED;
- }
-
- rootedGlobal = xpc::GetXBLScope(cx, rootedGlobal);
-
ErrorResult rv;
JS::Rooted reflector(cx);
for (nsIContent* cur = aRoot; cur; cur = cur->GetNextNode(aRoot)) {
diff --git a/dom/clients/manager/ClientManagerService.cpp b/dom/clients/manager/ClientManagerService.cpp
index 6af08849c111..c6f20464890b 100644
--- a/dom/clients/manager/ClientManagerService.cpp
+++ b/dom/clients/manager/ClientManagerService.cpp
@@ -475,6 +475,8 @@ ClaimOnMainThread(const ClientInfo& aClientInfo,
}, [promise] (nsresult aRv) {
promise->Reject(aRv, __func__);
});
+
+ scopeExit.release();
});
MOZ_ALWAYS_SUCCEEDS(SystemGroup::Dispatch(TaskCategory::Other, r.forget()));
diff --git a/dom/clients/manager/ClientSource.cpp b/dom/clients/manager/ClientSource.cpp
index 3bbc417b9136..5bb18b7719bf 100644
--- a/dom/clients/manager/ClientSource.cpp
+++ b/dom/clients/manager/ClientSource.cpp
@@ -124,6 +124,28 @@ ClientSource::GetDocShell() const
return mOwner.as>();
}
+nsIGlobalObject*
+ClientSource::GetGlobal() const
+{
+ NS_ASSERT_OWNINGTHREAD(ClientSource);
+ nsPIDOMWindowInner* win = GetInnerWindow();
+ if (win) {
+ return win->AsGlobal();
+ }
+
+ WorkerPrivate* wp = GetWorkerPrivate();
+ if (wp) {
+ return wp->GlobalScope();
+ }
+
+ // Note, ClientSource objects attached to docshell for conceptual
+ // initial about:blank will get nullptr here. The caller should
+ // use MaybeCreateIntitialDocument() to create the window before
+ // GetGlobal() if it wants this before.
+
+ return nullptr;
+}
+
void
ClientSource::MaybeCreateInitialDocument()
{
@@ -431,10 +453,47 @@ ClientSource::Control(const ClientControlledArgs& aArgs)
{
NS_ASSERT_OWNINGTHREAD(ClientSource);
+ // Determine if the client is allowed to be controlled. Currently we
+ // prevent service workers from controlling clients that cannot access
+ // storage. We exempt this restriction for local URL clients, like about:blank
+ // and blob:, since access to service workers is dictated by their parent.
+ //
+ // Note, we default to allowing the client to be controlled in the case
+ // where we are not execution ready yet. This can only happen if the
+ // the non-subresource load is intercepted by a service worker. Since
+ // ServiceWorkerInterceptController() uses StorageAllowedForChannel()
+ // it should be fine to accept these control messages.
+ //
+ // Its also fine to default to allowing ClientSource attached to a docshell
+ // to be controlled. These clients represent inital about:blank windows
+ // that do not have an inner window created yet. We explicitly allow initial
+ // about:blank.
+ bool controlAllowed = true;
+ if (GetInnerWindow()) {
+
+ // Local URL windows and windows with access to storage can be controlled.
+ controlAllowed = Info().URL().LowerCaseEqualsLiteral("about:blank") ||
+ StringBeginsWith(Info().URL(), NS_LITERAL_CSTRING("blob:")) ||
+ nsContentUtils::StorageAllowedForWindow(GetInnerWindow()) ==
+ nsContentUtils::StorageAccess::eAllow;
+ } else if (GetWorkerPrivate()) {
+ // Local URL workers and workers with access to storage cna be controlled.
+ controlAllowed = GetWorkerPrivate()->IsStorageAllowed() ||
+ StringBeginsWith(GetWorkerPrivate()->ScriptURL(),
+ NS_LITERAL_STRING("blob:"));
+ }
+
+ RefPtr ref;
+
+ if (NS_WARN_IF(!controlAllowed)) {
+ ref = ClientOpPromise::CreateAndReject(NS_ERROR_DOM_INVALID_STATE_ERR,
+ __func__);
+ return ref.forget();
+ }
+
SetController(ServiceWorkerDescriptor(aArgs.serviceWorker()));
- RefPtr ref =
- ClientOpPromise::CreateAndResolve(NS_OK, __func__);
+ ref = ClientOpPromise::CreateAndResolve(NS_OK, __func__);
return ref.forget();
}
@@ -670,35 +729,55 @@ ClientSource::PostMessage(const ClientPostMessageArgs& aArgs)
RefPtr
ClientSource::Claim(const ClientClaimArgs& aArgs)
{
+ // The ClientSource::Claim method is only needed in the legacy
+ // mode where the ServiceWorkerManager is run in each child-process.
+ // In parent-process mode this method should not be called.
+ MOZ_DIAGNOSTIC_ASSERT(!ServiceWorkerParentInterceptEnabled());
+
RefPtr ref;
+ nsIGlobalObject* global = GetGlobal();
+ if (NS_WARN_IF(!global)) {
+ ref = ClientOpPromise::CreateAndReject(NS_ERROR_DOM_INVALID_STATE_ERR,
+ __func__);
+ return ref.forget();
+ }
+
+ // Note, we cannot just mark the ClientSource controlled. We must go through
+ // the SWM so that it can keep track of which clients are controlled by each
+ // registration. We must tell the child-process SWM in legacy child-process
+ // mode. In parent-process service worker mode the SWM is notified in the
+ // parent-process in ClientManagerService::Claim().
+
+ RefPtr innerPromise =
+ new GenericPromise::Private(__func__);
ServiceWorkerDescriptor swd(aArgs.serviceWorker());
- // Today the ServiceWorkerManager maintains its own list of
- // nsIDocument objects controlled by each service worker. We
- // need to try to update that data structure for now. If we
- // can't, however, then simply mark the Client as controlled.
- // In the future this will be enough for the SWM as well since
- // it will eventually hold ClientHandle objects instead of
- // nsIDocuments.
- nsPIDOMWindowInner* innerWindow = GetInnerWindow();
- nsIDocument* doc = innerWindow ? innerWindow->GetExtantDoc() : nullptr;
- RefPtr swm = doc ? ServiceWorkerManager::GetInstance()
- : nullptr;
- if (!swm || !doc) {
- SetController(swd);
- ref = ClientOpPromise::CreateAndResolve(NS_OK, __func__);
- return ref.forget();
+ nsCOMPtr r = NS_NewRunnableFunction(
+ "ClientSource::Claim",
+ [innerPromise, clientInfo = mClientInfo, swd] () mutable {
+ RefPtr swm = ServiceWorkerManager::GetInstance();
+ if (NS_WARN_IF(!swm)) {
+ innerPromise->Reject(NS_ERROR_DOM_INVALID_STATE_ERR, __func__);
+ return;
+ }
+
+ RefPtr p = swm->MaybeClaimClient(clientInfo, swd);
+ p->ChainTo(innerPromise.forget(), __func__);
+ });
+
+ if (NS_IsMainThread()) {
+ r->Run();
+ } else {
+ MOZ_ALWAYS_SUCCEEDS(SystemGroup::Dispatch(TaskCategory::Other, r.forget()));
}
RefPtr outerPromise =
new ClientOpPromise::Private(__func__);
- auto holder =
- MakeRefPtr>(innerWindow->AsGlobal());
+ auto holder = MakeRefPtr>(global);
- RefPtr p = swm->MaybeClaimClient(mClientInfo, swd);
- p->Then(mEventTarget, __func__,
+ innerPromise->Then(mEventTarget, __func__,
[outerPromise, holder] (bool aResult) {
holder->Complete();
outerPromise->Resolve(NS_OK, __func__);
diff --git a/dom/clients/manager/ClientSource.h b/dom/clients/manager/ClientSource.h
index 671f40ccae83..471945194d00 100644
--- a/dom/clients/manager/ClientSource.h
+++ b/dom/clients/manager/ClientSource.h
@@ -17,6 +17,7 @@
#endif
class nsIDocShell;
+class nsIGlobalObject;
class nsISerialEventTarget;
class nsPIDOMWindowInner;
@@ -78,6 +79,9 @@ class ClientSource final : public ClientThing
nsIDocShell*
GetDocShell() const;
+ nsIGlobalObject*
+ GetGlobal() const;
+
void
MaybeCreateInitialDocument();
diff --git a/dom/clients/manager/ClientSourceOpParent.cpp b/dom/clients/manager/ClientSourceOpParent.cpp
index 9dfb2cd1d367..67d5dcdec81c 100644
--- a/dom/clients/manager/ClientSourceOpParent.cpp
+++ b/dom/clients/manager/ClientSourceOpParent.cpp
@@ -6,6 +6,8 @@
#include "ClientSourceOpParent.h"
+#include "ClientSourceParent.h"
+
namespace mozilla {
namespace dom {
@@ -25,10 +27,22 @@ ClientSourceOpParent::Recv__delete__(const ClientOpResult& aResult)
{
if (aResult.type() == ClientOpResult::Tnsresult &&
NS_FAILED(aResult.get_nsresult())) {
+
+ // If a control message fails then clear the controller from
+ // the ClientSourceParent. We eagerly marked it controlled at
+ // the start of the operation.
+ if (mArgs.type() == ClientOpConstructorArgs::TClientControlledArgs) {
+ auto source = static_cast(Manager());
+ if (source) {
+ source->ClearController();
+ }
+ }
+
mPromise->Reject(aResult.get_nsresult(), __func__);
mPromise = nullptr;
return IPC_OK();
}
+
mPromise->Resolve(aResult, __func__);
mPromise = nullptr;
return IPC_OK();
@@ -36,7 +50,8 @@ ClientSourceOpParent::Recv__delete__(const ClientOpResult& aResult)
ClientSourceOpParent::ClientSourceOpParent(const ClientOpConstructorArgs& aArgs,
ClientOpPromise::Private* aPromise)
- : mPromise(aPromise)
+ : mArgs(aArgs)
+ , mPromise(aPromise)
{
MOZ_DIAGNOSTIC_ASSERT(mPromise);
}
diff --git a/dom/clients/manager/ClientSourceOpParent.h b/dom/clients/manager/ClientSourceOpParent.h
index 7ebd9d24ce11..356b041c9076 100644
--- a/dom/clients/manager/ClientSourceOpParent.h
+++ b/dom/clients/manager/ClientSourceOpParent.h
@@ -14,6 +14,7 @@ namespace dom {
class ClientSourceOpParent final : public PClientSourceOpParent
{
+ const ClientOpConstructorArgs mArgs;
RefPtr mPromise;
// PClientSourceOpParent interface
diff --git a/dom/clients/manager/ClientSourceParent.cpp b/dom/clients/manager/ClientSourceParent.cpp
index a46f5ba49121..5818108e3e6d 100644
--- a/dom/clients/manager/ClientSourceParent.cpp
+++ b/dom/clients/manager/ClientSourceParent.cpp
@@ -274,6 +274,12 @@ ClientSourceParent::GetController() const
return mController;
}
+void
+ClientSourceParent::ClearController()
+{
+ mController.reset();
+}
+
void
ClientSourceParent::AttachHandle(ClientHandleParent* aClientHandle)
{
@@ -298,7 +304,11 @@ ClientSourceParent::StartOp(const ClientOpConstructorArgs& aArgs)
new ClientOpPromise::Private(__func__);
// If we are being controlled, remember that data before propagating
- // on to the ClientSource.
+ // on to the ClientSource. This must be set prior to triggering
+ // the controllerchange event from the ClientSource since some tests
+ // expect matchAll() to find the controlled client immediately after.
+ // If the control operation fails, then we reset the controller value
+ // to reflect the final state.
if (aArgs.type() == ClientOpConstructorArgs::TClientControlledArgs) {
mController.reset();
mController.emplace(aArgs.get_ClientControlledArgs().serviceWorker());
diff --git a/dom/clients/manager/ClientSourceParent.h b/dom/clients/manager/ClientSourceParent.h
index d618d5ee5cda..b1fc26d806e9 100644
--- a/dom/clients/manager/ClientSourceParent.h
+++ b/dom/clients/manager/ClientSourceParent.h
@@ -79,6 +79,9 @@ public:
const Maybe&
GetController() const;
+ void
+ ClearController();
+
void
AttachHandle(ClientHandleParent* aClientSource);
diff --git a/dom/serviceworkers/ServiceWorkerManager.cpp b/dom/serviceworkers/ServiceWorkerManager.cpp
index 96f092949ba3..72e0a9d84715 100644
--- a/dom/serviceworkers/ServiceWorkerManager.cpp
+++ b/dom/serviceworkers/ServiceWorkerManager.cpp
@@ -317,6 +317,7 @@ ServiceWorkerManager::StartControllingClient(const ClientInfo& aClientInfo,
MOZ_DIAGNOSTIC_ASSERT(aRegistrationInfo->GetActive());
RefPtr ref;
+ RefPtr self(this);
const ServiceWorkerDescriptor& active =
aRegistrationInfo->GetActive()->Descriptor();
@@ -326,7 +327,12 @@ ServiceWorkerManager::StartControllingClient(const ClientInfo& aClientInfo,
RefPtr old =
entry.Data()->mRegistrationInfo.forget();
- ref = entry.Data()->mClientHandle->Control(active);
+ if (aControlClientHandle) {
+ ref = entry.Data()->mClientHandle->Control(active);
+ } else {
+ ref = GenericPromise::CreateAndResolve(false, __func__);
+ }
+
entry.Data()->mRegistrationInfo = aRegistrationInfo;
if (old != aRegistrationInfo) {
@@ -336,6 +342,17 @@ ServiceWorkerManager::StartControllingClient(const ClientInfo& aClientInfo,
Telemetry::Accumulate(Telemetry::SERVICE_WORKER_CONTROLLED_DOCUMENTS, 1);
+ // Always check to see if we failed to actually control the client. In
+ // that case removed the client from our list of controlled clients.
+ ref->Then(
+ SystemGroup::EventTargetFor(TaskCategory::Other), __func__,
+ [] (bool) {
+ // do nothing on success
+ }, [self, aClientInfo] (nsresult aRv) {
+ // failed to control, forget about this client
+ self->StopControllingClient(aClientInfo);
+ });
+
return ref;
}
@@ -355,15 +372,25 @@ ServiceWorkerManager::StartControllingClient(const ClientInfo& aClientInfo,
return new ControlledClientData(clientHandle, aRegistrationInfo);
});
- RefPtr self(this);
clientHandle->OnDetach()->Then(
SystemGroup::EventTargetFor(TaskCategory::Other), __func__,
- [self = std::move(self), aClientInfo] {
+ [self, aClientInfo] {
self->StopControllingClient(aClientInfo);
});
Telemetry::Accumulate(Telemetry::SERVICE_WORKER_CONTROLLED_DOCUMENTS, 1);
+ // Always check to see if we failed to actually control the client. In
+ // that case removed the client from our list of controlled clients.
+ ref->Then(
+ SystemGroup::EventTargetFor(TaskCategory::Other), __func__,
+ [] (bool) {
+ // do nothing on success
+ }, [self, aClientInfo] (nsresult aRv) {
+ // failed to control, forget about this client
+ self->StopControllingClient(aClientInfo);
+ });
+
return ref;
}
@@ -2695,7 +2722,20 @@ ServiceWorkerManager::UpdateClientControllers(ServiceWorkerRegistrationInfo* aRe
// Fire event after iterating mControlledClients is done to prevent
// modification by reentering from the event handlers during iteration.
for (auto& handle : handleList) {
- handle->Control(activeWorker->Descriptor());
+ RefPtr p = handle->Control(activeWorker->Descriptor());
+
+ RefPtr self = this;
+
+ // If we fail to control the client, then automatically remove it
+ // from our list of controlled clients.
+ p->Then(
+ SystemGroup::EventTargetFor(TaskCategory::Other), __func__,
+ [] (bool) {
+ // do nothing on success
+ }, [self, clientInfo = handle->Info()] (nsresult aRv) {
+ // failed to control, forget about this client
+ self->StopControllingClient(clientInfo);
+ });
}
}
diff --git a/dom/websocket/WebSocket.cpp b/dom/websocket/WebSocket.cpp
index 8d81615da18e..fe4a4b4666cc 100644
--- a/dom/websocket/WebSocket.cpp
+++ b/dom/websocket/WebSocket.cpp
@@ -820,6 +820,11 @@ WebSocketImpl::ScheduleConnectionCloseEvents(nsISupports* aContext,
aStatusCode = NS_OK;
}
+ if (aStatusCode == NS_ERROR_NET_INADEQUATE_SECURITY) {
+ // TLS negotiation failed so we need to set status code to 1015.
+ mCloseEventCode = 1015;
+ }
+
if (NS_FAILED(aStatusCode)) {
ConsoleError();
mFailed = true;
diff --git a/gfx/layers/wr/WebRenderLayerManager.cpp b/gfx/layers/wr/WebRenderLayerManager.cpp
index 0103476c893f..29bcbb62636e 100644
--- a/gfx/layers/wr/WebRenderLayerManager.cpp
+++ b/gfx/layers/wr/WebRenderLayerManager.cpp
@@ -240,16 +240,15 @@ WebRenderLayerManager::EndTransaction(DrawPaintedLayerCallback aCallback,
void
WebRenderLayerManager::EndTransactionWithoutLayer(nsDisplayList* aDisplayList,
nsDisplayListBuilder* aDisplayListBuilder,
- const nsTArray& aFilters)
+ const nsTArray& aFilters,
+ WebRenderBackgroundData* aBackground)
{
- MOZ_ASSERT(aDisplayList && aDisplayListBuilder);
-
AUTO_PROFILER_TRACING("Paint", "RenderLayers");
#if DUMP_LISTS
// Useful for debugging, it dumps the display list *before* we try to build
// WR commands from it
- if (XRE_IsContentProcess()) nsFrame::PrintDisplayList(aDisplayListBuilder, *aDisplayList);
+ if (XRE_IsContentProcess() && aDisplayList) nsFrame::PrintDisplayList(aDisplayListBuilder, *aDisplayList);
#endif
#ifdef XP_WIN
@@ -266,7 +265,9 @@ WebRenderLayerManager::EndTransactionWithoutLayer(nsDisplayList* aDisplayList,
wr::DisplayListBuilder builder(WrBridge()->GetPipeline(), contentSize, mLastDisplayListSize);
wr::IpcResourceUpdateQueue resourceUpdates(WrBridge());
- { // Record the time spent "layerizing". WR doesn't actually layerize but
+ if (aDisplayList) {
+ MOZ_ASSERT(aDisplayListBuilder && !aBackground);
+ // Record the time spent "layerizing". WR doesn't actually layerize but
// generating the WR display list is the closest equivalent
PaintTelemetry::AutoRecord record(PaintTelemetry::Metric::Layerization);
@@ -277,6 +278,10 @@ WebRenderLayerManager::EndTransactionWithoutLayer(nsDisplayList* aDisplayList,
mScrollData,
contentSize,
aFilters);
+ } else {
+ // ViewToPaint does not have frame yet, then render only background clolor.
+ MOZ_ASSERT(!aDisplayListBuilder && aBackground);
+ aBackground->AddWebRenderCommands(builder);
}
DiscardCompositorAnimations();
diff --git a/gfx/layers/wr/WebRenderLayerManager.h b/gfx/layers/wr/WebRenderLayerManager.h
index bba7f02fc825..f7e1f4be3bf8 100644
--- a/gfx/layers/wr/WebRenderLayerManager.h
+++ b/gfx/layers/wr/WebRenderLayerManager.h
@@ -71,7 +71,8 @@ public:
virtual bool EndEmptyTransaction(EndTransactionFlags aFlags = END_DEFAULT) override;
void EndTransactionWithoutLayer(nsDisplayList* aDisplayList,
nsDisplayListBuilder* aDisplayListBuilder,
- const nsTArray& aFilters = nsTArray());
+ const nsTArray& aFilters = nsTArray(),
+ WebRenderBackgroundData* aBackground = nullptr);
virtual void EndTransaction(DrawPaintedLayerCallback aCallback,
void* aCallbackData,
EndTransactionFlags aFlags = END_DEFAULT) override;
diff --git a/gfx/layers/wr/WebRenderUserData.cpp b/gfx/layers/wr/WebRenderUserData.cpp
index 5204d2def528..cafca3521d6b 100644
--- a/gfx/layers/wr/WebRenderUserData.cpp
+++ b/gfx/layers/wr/WebRenderUserData.cpp
@@ -20,6 +20,15 @@
namespace mozilla {
namespace layers {
+void
+WebRenderBackgroundData::AddWebRenderCommands(wr::DisplayListBuilder& aBuilder)
+{
+ aBuilder.PushRect(mBounds,
+ mBounds,
+ true,
+ mColor);
+}
+
/* static */ bool
WebRenderUserData::SupportsAsyncUpdate(nsIFrame* aFrame)
{
diff --git a/gfx/layers/wr/WebRenderUserData.h b/gfx/layers/wr/WebRenderUserData.h
index baa5cf09cc8a..b69098370e13 100644
--- a/gfx/layers/wr/WebRenderUserData.h
+++ b/gfx/layers/wr/WebRenderUserData.h
@@ -37,6 +37,19 @@ class WebRenderFallbackData;
class WebRenderLayerManager;
class WebRenderGroupData;
+class WebRenderBackgroundData
+{
+public:
+ WebRenderBackgroundData(wr::LayoutRect aBounds, wr::ColorF aColor)
+ : mBounds(aBounds)
+ , mColor(aColor)
+ { }
+ void AddWebRenderCommands(wr::DisplayListBuilder& aBuilder);
+protected:
+ wr::LayoutRect mBounds;
+ wr::ColorF mColor;
+};
+
class WebRenderUserData
{
public:
diff --git a/gfx/webrender_bindings/RenderCompositorANGLE.cpp b/gfx/webrender_bindings/RenderCompositorANGLE.cpp
index bec4d84fefac..c1a1cb070790 100644
--- a/gfx/webrender_bindings/RenderCompositorANGLE.cpp
+++ b/gfx/webrender_bindings/RenderCompositorANGLE.cpp
@@ -55,6 +55,10 @@ ID3D11Device*
RenderCompositorANGLE::GetDeviceOfEGLDisplay()
{
auto* egl = gl::GLLibraryEGL::Get();
+ MOZ_ASSERT(egl);
+ if (!egl || !egl->IsExtensionSupported(gl::GLLibraryEGL::EXT_device_query)) {
+ return nullptr;
+ }
// Fetch the D3D11 device.
EGLDeviceEXT eglDevice = nullptr;
diff --git a/js/public/CallArgs.h b/js/public/CallArgs.h
index e32d5c8fc7f3..8506346ac139 100644
--- a/js/public/CallArgs.h
+++ b/js/public/CallArgs.h
@@ -5,6 +5,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
+ * [SMDOC] JS::CallArgs API
+ *
* Helper classes encapsulating access to the callee, |this| value, arguments,
* and argument count for a call/construct operation.
*
@@ -46,10 +48,7 @@
*
* It's possible (albeit deprecated) to manually index into |vp| to access the
* callee, |this|, and arguments of a function, and to set its return value.
- * It's also possible to use the supported API of JS_CALLEE, JS_THIS, JS_ARGV,
- * JS_RVAL, and JS_SET_RVAL to the same ends.
- *
- * But neither API has the error-handling or moving-GC correctness of CallArgs.
+ * This does not have the error-handling or moving-GC correctness of CallArgs.
* New code should use CallArgs instead whenever possible.
*
* The eventual plan is to change JSNative to take |const CallArgs&| directly,
diff --git a/js/public/Debug.h b/js/public/Debug.h
index 68db73a82cb3..0c8a47133c8c 100644
--- a/js/public/Debug.h
+++ b/js/public/Debug.h
@@ -27,6 +27,8 @@ class Debugger;
namespace JS {
namespace dbg {
+// [SMDOC] Debugger builder API
+//
// Helping embedding code build objects for Debugger
// -------------------------------------------------
//
diff --git a/js/public/Proxy.h b/js/public/Proxy.h
index 96eaa4d0f21a..647e65cdaac0 100644
--- a/js/public/Proxy.h
+++ b/js/public/Proxy.h
@@ -37,6 +37,8 @@ class RegExpShared;
class JS_FRIEND_API(Wrapper);
/*
+ * [SMDOC] Proxy Objects
+ *
* A proxy is a JSObject with highly customizable behavior. ES6 specifies a
* single kind of proxy, but the customization mechanisms we use to implement
* ES6 Proxy objects are also useful wherever an object with weird behavior is
diff --git a/js/public/Result.h b/js/public/Result.h
index 346a1e6443d8..5d22c46a8839 100644
--- a/js/public/Result.h
+++ b/js/public/Result.h
@@ -5,6 +5,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
+ * [SMDOC] JS::Result
+ *
* `Result` is used as the return type of many SpiderMonkey functions that
* can either succeed or fail. See "/mfbt/Result.h".
*
diff --git a/js/public/RootingAPI.h b/js/public/RootingAPI.h
index b0d138acd7c0..b1414e000f4c 100644
--- a/js/public/RootingAPI.h
+++ b/js/public/RootingAPI.h
@@ -28,6 +28,8 @@
#include "js/Utility.h"
/*
+ * [SMDOC] Stack Rooting
+ *
* Moving GC Stack Rooting
*
* A moving GC may change the physical location of GC allocated things, even
diff --git a/js/public/UbiNode.h b/js/public/UbiNode.h
index c02dcad3be36..a4f8d9cb8e9f 100644
--- a/js/public/UbiNode.h
+++ b/js/public/UbiNode.h
@@ -29,7 +29,7 @@
#include "js/Value.h"
#include "js/Vector.h"
-// JS::ubi::Node
+// [SMDOC] ubi::Node (Heap Analysis framework)
//
// JS::ubi::Node is a pointer-like type designed for internal use by heap
// analysis tools. A ubi::Node can refer to:
diff --git a/js/public/Value.h b/js/public/Value.h
index 20470b22ba07..325c393e7761 100644
--- a/js/public/Value.h
+++ b/js/public/Value.h
@@ -268,6 +268,8 @@ CanonicalizeNaN(double d)
}
/**
+ * [SMDOC] JS::Value type
+ *
* JS::Value is the interface for a single JavaScript Engine value. A few
* general notes on JS::Value:
*
diff --git a/js/src/builtin/Array.cpp b/js/src/builtin/Array.cpp
index 74cc2c70658a..1b02e4b5556e 100644
--- a/js/src/builtin/Array.cpp
+++ b/js/src/builtin/Array.cpp
@@ -939,16 +939,6 @@ js::ArraySetLength(JSContext* cx, Handle arr, HandleId id,
return result.succeed();
}
-bool
-js::WouldDefinePastNonwritableLength(HandleNativeObject obj, uint32_t index)
-{
- if (!obj->is())
- return false;
-
- ArrayObject* arr = &obj->as();
- return !arr->lengthIsWritable() && index >= arr->length();
-}
-
static bool
array_addProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v)
{
diff --git a/js/src/builtin/Array.h b/js/src/builtin/Array.h
index 8a733c9e570b..1d110510a398 100644
--- a/js/src/builtin/Array.h
+++ b/js/src/builtin/Array.h
@@ -113,14 +113,6 @@ extern ArrayObject*
NewCopiedArrayForCallingAllocationSite(JSContext* cx, const Value* vp, size_t length,
HandleObject proto = nullptr);
-/*
- * Determines whether a write to the given element on |obj| should fail because
- * |obj| is an Array with a non-writable length, and writing that element would
- * increase the length of the array.
- */
-extern bool
-WouldDefinePastNonwritableLength(HandleNativeObject obj, uint32_t index);
-
extern bool
GetLengthProperty(JSContext* cx, HandleObject obj, uint32_t* lengthp);
diff --git a/js/src/builtin/TypedObject.h b/js/src/builtin/TypedObject.h
index 9606fba3c866..7999b3a46c5c 100644
--- a/js/src/builtin/TypedObject.h
+++ b/js/src/builtin/TypedObject.h
@@ -18,7 +18,7 @@
/*
* -------------
- * Typed Objects
+ * [SMDOC] Typed Objects
* -------------
*
* Typed objects are a special kind of JS object where the data is
diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h
index 5e62626dae50..000dfb465395 100644
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -10,6 +10,8 @@
#define frontend_Parser_h
/*
+ * [SMDOC] JS Parser
+ *
* JS parsers capable of generating ASTs from source text.
*
* A parser embeds token stream information, then gets and matches tokens to
diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h
index eebd79ec3b48..18b9cc583716 100644
--- a/js/src/frontend/TokenStream.h
+++ b/js/src/frontend/TokenStream.h
@@ -16,6 +16,8 @@
#define frontend_TokenStream_h
/*
+ * [SMDOC] Parser Token Stream
+ *
* A token stream exposes the raw tokens -- operators, names, numbers,
* keywords, and so on -- of JavaScript source code.
*
diff --git a/js/src/gc/AtomMarking.cpp b/js/src/gc/AtomMarking.cpp
index d20ab05cf67d..3f3c0bac3a66 100644
--- a/js/src/gc/AtomMarking.cpp
+++ b/js/src/gc/AtomMarking.cpp
@@ -15,7 +15,7 @@
namespace js {
namespace gc {
-// Atom Marking Overview
+// [SMDOC] GC Atom Marking
//
// Things in the atoms zone (which includes atomized strings and other things,
// all of which we will refer to as 'atoms' here) may be pointed to freely by
diff --git a/js/src/gc/Barrier.h b/js/src/gc/Barrier.h
index e3ac5797444a..ae279ce9981b 100644
--- a/js/src/gc/Barrier.h
+++ b/js/src/gc/Barrier.h
@@ -17,6 +17,8 @@
#include "js/Value.h"
/*
+ * [SMDOC] GC Barriers
+ *
* A write barrier is a mechanism used by incremental or generation GCs to
* ensure that every value that needs to be marked is marked. In general, the
* write barrier should be invoked whenever a write can cause the set of things
diff --git a/js/src/gc/GC.cpp b/js/src/gc/GC.cpp
index 2c6068a67c62..feea77754aa9 100644
--- a/js/src/gc/GC.cpp
+++ b/js/src/gc/GC.cpp
@@ -5,6 +5,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
+ * [SMDOC] Garbage Collector
+ *
* This code implements an incremental mark-and-sweep garbage collector, with
* most sweeping carried out in the background on a parallel thread.
*
diff --git a/js/src/gc/Marking.cpp b/js/src/gc/Marking.cpp
index 17344b7e5167..b7d38bcfc64a 100644
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -54,6 +54,8 @@ using mozilla::IsBaseOf;
using mozilla::IsSame;
using mozilla::PodCopy;
+// [SMDOC] GC Tracing
+//
// Tracing Overview
// ================
//
diff --git a/js/src/gc/Scheduling.h b/js/src/gc/Scheduling.h
index dc5ea3a9552f..b4aaab9ea3bd 100644
--- a/js/src/gc/Scheduling.h
+++ b/js/src/gc/Scheduling.h
@@ -5,6 +5,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
+ * [SMDOC] GC Scheduling
+ *
* GC Scheduling Overview
* ======================
*
diff --git a/js/src/gc/Zone.h b/js/src/gc/Zone.h
index ffc6ec6ee3af..853872dbb34b 100644
--- a/js/src/gc/Zone.h
+++ b/js/src/gc/Zone.h
@@ -99,6 +99,8 @@ class MOZ_NON_TEMPORARY_CLASS FunctionToStringCache
namespace JS {
+// [SMDOC] GC Zones
+//
// A zone is a collection of compartments. Every compartment belongs to exactly
// one zone. In Firefox, there is roughly one zone per tab along with a system
// zone for everything else. Zones mainly serve as boundaries for garbage
diff --git a/js/src/irregexp/RegExpEngine.cpp b/js/src/irregexp/RegExpEngine.cpp
index 0dc2be88ecf9..d381dc1e454e 100644
--- a/js/src/irregexp/RegExpEngine.cpp
+++ b/js/src/irregexp/RegExpEngine.cpp
@@ -1326,6 +1326,7 @@ Analysis::VisitAssertion(AssertionNode* that)
EnsureAnalyzed(that->on_success());
}
+// [SMDOC] Irregexp internals
// -------------------------------------------------------------------
// Implementation of the Irregexp regular expression engine.
//
diff --git a/js/src/jit-test/tests/realms/switch-realms-native.js b/js/src/jit-test/tests/realms/switch-realms-native.js
index 18599a4e64e7..e4ae74cffcd7 100644
--- a/js/src/jit-test/tests/realms/switch-realms-native.js
+++ b/js/src/jit-test/tests/realms/switch-realms-native.js
@@ -45,3 +45,16 @@ function testException1() {
}
}
testException1();
+
+function testDOMCalls() {
+ var g = newGlobal({sameCompartmentAs: this});
+ var obj = g.evaluate("new FakeDOMObject()");
+ for (var i = 0; i < 2000; i++) {
+ assertCorrectRealm();
+ assertEq(obj.doFoo(1), 1);
+ assertEq(typeof obj.x, "number");
+ assertEq(obj.global, g);
+ obj.global = g; // Throws if not setter's global.
+ }
+}
+testDOMCalls();
diff --git a/js/src/jit-test/tests/wasm/grow-memory.js b/js/src/jit-test/tests/wasm/grow-memory.js
index 0b15cd08a688..d506dda7be50 100644
--- a/js/src/jit-test/tests/wasm/grow-memory.js
+++ b/js/src/jit-test/tests/wasm/grow-memory.js
@@ -1,11 +1,11 @@
-function linearModule(min, max, ops) {
+function linearModule(min, max, ops, current_memory, grow_memory) {
var opsText = ops.map(function (op) {
if (op[0] == "CM") {
- res = `(if i32 (i32.ne (current_memory) (i32.const ${op[1]}))
+ res = `(if i32 (i32.ne (${current_memory}) (i32.const ${op[1]}))
(i32.load offset=10 (i32.const 4294967295))
(i32.const 0))`
} else if (op[0] == "GM") {
- res = `(if i32 (i32.ne (grow_memory (i32.const ${op[1]})) (i32.const ${op[2]}))
+ res = `(if i32 (i32.ne (${grow_memory} (i32.const ${op[1]})) (i32.const ${op[2]}))
(i32.load offset=10 (i32.const 4294967295))
(i32.const 0))`
} else if (op[0] == "L") {
@@ -35,11 +35,12 @@ function linearModule(min, max, ops) {
`
(func (result i32)
(drop ` + opsText + `)
- (current_memory)
+ (${current_memory})
) (export "run" 0))`;
return text;
}
// Just grow some memory
-wasmFullPass(linearModule(3,5, [["CM", 3]]), 3);
+wasmFullPass(linearModule(3,5, [["CM", 3]], "current_memory", "grow_memory"), 3); // Old opcode names
+wasmFullPass(linearModule(3,5, [["CM", 3]], "memory.size", "memory.grow"), 3); // New opcode names
diff --git a/js/src/jit/AliasAnalysis.cpp b/js/src/jit/AliasAnalysis.cpp
index ebb13ac8502d..befd7e4f033e 100644
--- a/js/src/jit/AliasAnalysis.cpp
+++ b/js/src/jit/AliasAnalysis.cpp
@@ -116,6 +116,8 @@ IonSpewAliasInfo(const char* pre, MInstruction* ins, const char* post)
#endif
}
+// [SMDOC] IonMonkey Alias Analysis
+//
// This pass annotates every load instruction with the last store instruction
// on which it depends. The algorithm is optimistic in that it ignores explicit
// dependencies and only considers loads and stores.
diff --git a/js/src/jit/AtomicOperations.h b/js/src/jit/AtomicOperations.h
index a8970b0d37e1..c645ecc3a4c6 100644
--- a/js/src/jit/AtomicOperations.h
+++ b/js/src/jit/AtomicOperations.h
@@ -15,6 +15,8 @@ namespace js {
namespace jit {
/*
+ * [SMDOC] Atomic Operations
+ *
* The atomic operations layer defines types and functions for
* JIT-compatible atomic operation.
*
diff --git a/js/src/jit/Bailouts.h b/js/src/jit/Bailouts.h
index 1674a194cf00..dc5a3d1e56a8 100644
--- a/js/src/jit/Bailouts.h
+++ b/js/src/jit/Bailouts.h
@@ -16,8 +16,10 @@
namespace js {
namespace jit {
-// A "bailout" is a condition in which we need to recover an interpreter frame
-// from an IonFrame. Bailouts can happen for the following reasons:
+// [SMDOC] IonMonkey Bailouts
+//
+// A "bailout" is a condition in which we need to recover a baseline frame from
+// an IonFrame. Bailouts can happen for the following reasons:
// (1) A deoptimization guard, for example, an add overflows or a type check
// fails.
// (2) A check or assumption held by the JIT is invalidated by the VM, and
@@ -36,7 +38,7 @@ namespace jit {
// jmp _bailout
//
// The bailout target needs to somehow translate the Ion frame (whose state
-// will differ at each program point) to an interpreter frame. This state is
+// will differ at each program point) to a baseline frame. This state is
// captured into the IonScript's snapshot buffer, and for each bailout we know
// which snapshot corresponds to its state.
//
@@ -49,7 +51,7 @@ namespace jit {
// to find the structure of the frame, and then use the stack and spilled
// registers to perform frame conversion.
// (5) Bailout() returns, and the JIT must immediately return to the
-// interpreter (all frames are converted at once).
+// baseline JIT code (all frames are converted at once).
//
// (2) and (3) are implemented by a trampoline held in the compartment.
// Naively, we could implement (1) like:
diff --git a/js/src/jit/CacheIR.cpp b/js/src/jit/CacheIR.cpp
index 95c932e83617..71d572db5c00 100644
--- a/js/src/jit/CacheIR.cpp
+++ b/js/src/jit/CacheIR.cpp
@@ -625,7 +625,7 @@ GeneratePrototypeGuards(CacheIRWriter& writer, JSObject* obj, JSObject* holder,
// [[GetOwnProperty]] has no definition of the target property.
//
//
- // Shape Teleporting Optimization
+ // [SMDOC] Shape Teleporting Optimization
// ------------------------------
//
// Starting with the assumption (and guideline to developers) that mutating
diff --git a/js/src/jit/CacheIR.h b/js/src/jit/CacheIR.h
index 1dd7b5972891..2546f591d52d 100644
--- a/js/src/jit/CacheIR.h
+++ b/js/src/jit/CacheIR.h
@@ -22,6 +22,8 @@ namespace jit {
enum class BaselineCacheIRStubKind;
+// [SMDOC] CacheIR
+//
// CacheIR is an (extremely simple) linear IR language for inline caches.
// From this IR, we can generate machine code for Baseline or Ion IC stubs.
//
diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp
index 630adc2c591a..b9151713a660 100644
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -4418,6 +4418,12 @@ CodeGenerator::visitCallDOMNative(LCallDOMNative* call)
masm.Push(argObj);
masm.moveStackPtrTo(argObj);
+ if (call->mir()->maybeCrossRealm()) {
+ // We use argJSContext as scratch register here.
+ masm.movePtr(ImmGCPtr(target->rawJSFunction()), argJSContext);
+ masm.switchToObjectRealm(argJSContext, argJSContext);
+ }
+
// Construct native exit frame.
uint32_t safepointOffset = masm.buildFakeExitFrame(argJSContext);
masm.loadJSContext(argJSContext);
@@ -4447,6 +4453,14 @@ CodeGenerator::visitCallDOMNative(LCallDOMNative* call)
JSReturnOperand);
}
+ // Switch back to the current realm if needed. Note: if the DOM method threw
+ // an exception, the exception handler will do this.
+ if (call->mir()->maybeCrossRealm()) {
+ static_assert(!JSReturnOperand.aliases(ReturnReg),
+ "Clobbering ReturnReg should not affect the return value");
+ masm.switchToRealm(gen->realm->realmPtr(), ReturnReg);
+ }
+
// Until C++ code is instrumented against Spectre, prevent speculative
// execution from returning any private data.
if (JitOptions.spectreJitToCxxCalls && call->mir()->hasLiveDefUses())
@@ -12255,6 +12269,12 @@ CodeGenerator::visitGetDOMProperty(LGetDOMProperty* ins)
// Rooting will happen at GC time.
masm.moveStackPtrTo(ObjectReg);
+ Realm* getterRealm = ins->mir()->getterRealm();
+ if (gen->realm->realmPtr() != getterRealm) {
+ // We use JSContextReg as scratch register here.
+ masm.switchToRealm(getterRealm, JSContextReg);
+ }
+
uint32_t safepointOffset = masm.buildFakeExitFrame(JSContextReg);
masm.loadJSContext(JSContextReg);
masm.enterFakeExitFrame(JSContextReg, JSContextReg, ExitFrameType::IonDOMGetter);
@@ -12280,6 +12300,14 @@ CodeGenerator::visitGetDOMProperty(LGetDOMProperty* ins)
JSReturnOperand);
}
+ // Switch back to the current realm if needed. Note: if the getter threw an
+ // exception, the exception handler will do this.
+ if (gen->realm->realmPtr() != getterRealm) {
+ static_assert(!JSReturnOperand.aliases(ReturnReg),
+ "Clobbering ReturnReg should not affect the return value");
+ masm.switchToRealm(gen->realm->realmPtr(), ReturnReg);
+ }
+
// Until C++ code is instrumented against Spectre, prevent speculative
// execution from returning any private data.
if (JitOptions.spectreJitToCxxCalls && ins->mir()->hasLiveDefUses())
@@ -12360,6 +12388,12 @@ CodeGenerator::visitSetDOMProperty(LSetDOMProperty* ins)
// Rooting will happen at GC time.
masm.moveStackPtrTo(ObjectReg);
+ Realm* setterRealm = ins->mir()->setterRealm();
+ if (gen->realm->realmPtr() != setterRealm) {
+ // We use JSContextReg as scratch register here.
+ masm.switchToRealm(setterRealm, JSContextReg);
+ }
+
uint32_t safepointOffset = masm.buildFakeExitFrame(JSContextReg);
masm.loadJSContext(JSContextReg);
masm.enterFakeExitFrame(JSContextReg, JSContextReg, ExitFrameType::IonDOMSetter);
@@ -12377,6 +12411,11 @@ CodeGenerator::visitSetDOMProperty(LSetDOMProperty* ins)
masm.branchIfFalseBool(ReturnReg, masm.exceptionLabel());
+ // Switch back to the current realm if needed. Note: if the setter threw an
+ // exception, the exception handler will do this.
+ if (gen->realm->realmPtr() != setterRealm)
+ masm.switchToRealm(gen->realm->realmPtr(), ReturnReg);
+
masm.adjustStack(IonDOMExitFrameLayout::Size());
MOZ_ASSERT(masm.framePushed() == initialStack);
diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp
index 2b9ace14f602..c9955e49aa8c 100644
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -11004,7 +11004,8 @@ IonBuilder::getPropTryCommonGetter(bool* emitted, MDefinition* obj, PropertyName
// needed.
get = MGetDOMMember::New(alloc(), jitinfo, obj, guard, globalGuard);
} else {
- get = MGetDOMProperty::New(alloc(), jitinfo, objKind, obj, guard, globalGuard);
+ get = MGetDOMProperty::New(alloc(), jitinfo, objKind, commonGetter->realm(), obj,
+ guard, globalGuard);
}
if (!get)
return abort(AbortReason::Alloc);
@@ -11693,7 +11694,7 @@ IonBuilder::setPropTryCommonDOMSetter(bool* emitted, MDefinition* obj,
// Emit SetDOMProperty.
MOZ_ASSERT(setter->jitInfo()->type() == JSJitInfo::Setter);
MSetDOMProperty* set = MSetDOMProperty::New(alloc(), setter->jitInfo()->setter, objKind,
- obj, value);
+ setter->realm(), obj, value);
current->add(set);
current->push(value);
diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h
index 8fe508ceab1c..d5a3f4e17454 100644
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -12385,12 +12385,14 @@ class MSetDOMProperty
public MixPolicy, BoxPolicy<1> >::Data
{
const JSJitSetterOp func_;
+ Realm* setterRealm_;
DOMObjectKind objectKind_;
- MSetDOMProperty(const JSJitSetterOp func, DOMObjectKind objectKind, MDefinition* obj,
- MDefinition* val)
+ MSetDOMProperty(const JSJitSetterOp func, DOMObjectKind objectKind, Realm* setterRealm,
+ MDefinition* obj, MDefinition* val)
: MBinaryInstruction(classOpcode, obj, val),
func_(func),
+ setterRealm_(setterRealm),
objectKind_(objectKind)
{ }
@@ -12402,6 +12404,9 @@ class MSetDOMProperty
JSJitSetterOp fun() const {
return func_;
}
+ Realm* setterRealm() const {
+ return setterRealm_;
+ }
DOMObjectKind objectKind() const {
return objectKind_;
}
@@ -12517,11 +12522,14 @@ class MGetDOMPropertyBase
class MGetDOMProperty
: public MGetDOMPropertyBase
{
+ Realm* getterRealm_;
DOMObjectKind objectKind_;
protected:
- MGetDOMProperty(const JSJitInfo* jitinfo, DOMObjectKind objectKind)
+ MGetDOMProperty(const JSJitInfo* jitinfo, DOMObjectKind objectKind,
+ Realm* getterRealm)
: MGetDOMPropertyBase(classOpcode, jitinfo),
+ getterRealm_(getterRealm),
objectKind_(objectKind)
{}
@@ -12529,14 +12537,18 @@ class MGetDOMProperty
INSTRUCTION_HEADER(GetDOMProperty)
static MGetDOMProperty* New(TempAllocator& alloc, const JSJitInfo* info, DOMObjectKind objectKind,
- MDefinition* obj, MDefinition* guard, MDefinition* globalGuard)
+ Realm* getterRealm, MDefinition* obj, MDefinition* guard,
+ MDefinition* globalGuard)
{
- auto* res = new(alloc) MGetDOMProperty(info, objectKind);
+ auto* res = new(alloc) MGetDOMProperty(info, objectKind, getterRealm);
if (!res || !res->init(alloc, obj, guard, globalGuard))
return nullptr;
return res;
}
+ Realm* getterRealm() const {
+ return getterRealm_;
+ }
DOMObjectKind objectKind() const {
return objectKind_;
}
@@ -12545,6 +12557,9 @@ class MGetDOMProperty
if (!ins->isGetDOMProperty())
return false;
+ if (ins->toGetDOMProperty()->getterRealm() != getterRealm())
+ return false;
+
return baseCongruentTo(ins->toGetDOMProperty());
}
diff --git a/js/src/jit/MacroAssembler.h b/js/src/jit/MacroAssembler.h
index 107c11fca5a1..bd5c3f2fe0bc 100644
--- a/js/src/jit/MacroAssembler.h
+++ b/js/src/jit/MacroAssembler.h
@@ -41,6 +41,8 @@
#include "vm/TypedArrayObject.h"
#include "vm/UnboxedObject.h"
+// [SMDOC] MacroAssembler multi-platform overview
+//
// * How to read/write MacroAssembler method declarations:
//
// The following macros are made to avoid #ifdef around each method declarations
diff --git a/js/src/jit/RangeAnalysis.cpp b/js/src/jit/RangeAnalysis.cpp
index 5c8e95aac967..df67307eceaf 100644
--- a/js/src/jit/RangeAnalysis.cpp
+++ b/js/src/jit/RangeAnalysis.cpp
@@ -37,6 +37,8 @@ using mozilla::Swap;
using JS::GenericNaN;
using JS::ToInt32;
+// [SMDOC] IonMonkey Range Analysis
+//
// This algorithm is based on the paper "Eliminating Range Checks Using
// Static Single Assignment Form" by Gough and Klaren.
//
diff --git a/js/src/jit/Recover.h b/js/src/jit/Recover.h
index c00b49710e51..696472f9ac2d 100644
--- a/js/src/jit/Recover.h
+++ b/js/src/jit/Recover.h
@@ -17,6 +17,8 @@
namespace js {
namespace jit {
+// [SMDOC] IonMonkey Recover Instructions
+//
// This file contains all recover instructions.
//
// A recover instruction is an equivalent of a MIR instruction which is executed
diff --git a/js/src/jit/RegisterSets.h b/js/src/jit/RegisterSets.h
index fe14305e9d7a..9473cb5dd873 100644
--- a/js/src/jit/RegisterSets.h
+++ b/js/src/jit/RegisterSets.h
@@ -466,6 +466,8 @@ class RegisterSet {
}
};
+// [SMDOC] JIT Register-Set overview
+//
// There are 2 use cases for register sets:
//
// 1. To serve as a pool of allocatable register. This is useful for working
@@ -504,6 +506,8 @@ class AllocatableSet;
template
class LiveSet;
+// [SMDOC] JIT Register-Set (Allocatable)
+//
// Base accessors classes have the minimal set of raw methods to manipulate the register set
// given as parameter in a consistent manner. These methods are:
//
@@ -620,6 +624,8 @@ class AllocatableSetAccessors
};
+// [SMDOC] JIT Register-Set (Live)
+//
// The LiveSet accessors are used to collect a list of allocated
// registers. Taking or adding a register should *not* consider the aliases, as
// we care about interpreting the registers with the correct type. For example,
diff --git a/js/src/jit/SharedIC.h b/js/src/jit/SharedIC.h
index 20a421332e8b..b077309ca5dc 100644
--- a/js/src/jit/SharedIC.h
+++ b/js/src/jit/SharedIC.h
@@ -22,6 +22,7 @@
namespace js {
namespace jit {
+// [SMDOC] JIT Inline Caches (ICs)
//
// Baseline Inline Caches are polymorphic caches that aggressively
// share their stub code.
diff --git a/js/src/jit/Snapshots.cpp b/js/src/jit/Snapshots.cpp
index a062e50f1729..47dd04e3fea5 100644
--- a/js/src/jit/Snapshots.cpp
+++ b/js/src/jit/Snapshots.cpp
@@ -19,6 +19,8 @@
using namespace js;
using namespace js::jit;
+// [SMDOC] IonMonkey Snapshot encoding
+//
// Encodings:
// [ptr] A fixed-size pointer.
// [vwu] A variable-width unsigned integer.
diff --git a/js/src/jit/ValueNumbering.cpp b/js/src/jit/ValueNumbering.cpp
index e480ad2d3175..9a2f96541c08 100644
--- a/js/src/jit/ValueNumbering.cpp
+++ b/js/src/jit/ValueNumbering.cpp
@@ -15,6 +15,8 @@ using namespace js;
using namespace js::jit;
/*
+ * [SMDOC] IonMonkey Value Numbering
+ *
* Some notes on the main algorithm here:
* - The SSA identifier id() is the value number. We do replaceAllUsesWith as
* we go, so there's always at most one visible value with a given number.
diff --git a/js/src/jit/shared/IonAssemblerBufferWithConstantPools.h b/js/src/jit/shared/IonAssemblerBufferWithConstantPools.h
index b0256526f7f2..cfeb3e1b774f 100644
--- a/js/src/jit/shared/IonAssemblerBufferWithConstantPools.h
+++ b/js/src/jit/shared/IonAssemblerBufferWithConstantPools.h
@@ -14,6 +14,8 @@
#include "jit/JitSpewer.h"
#include "jit/shared/IonAssemblerBuffer.h"
+// [SMDOC] JIT AssemblerBuffer constant pooling (ARM/ARM64/MIPS)
+//
// This code extends the AssemblerBuffer to support the pooling of values loaded
// using program-counter relative addressing modes. This is necessary with the
// ARM instruction set because it has a fixed instruction size that can not
diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp
index 66a76ec626e0..89994a4b6bba 100644
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -6137,36 +6137,21 @@ JS_EncodeStringToBuffer(JSContext* cx, JSString* str, char* buffer, size_t lengt
AssertHeapIsIdle();
CHECK_REQUEST(cx);
- /*
- * FIXME bug 612141 - fix DeflateStringToBuffer interface so the result
- * would allow to distinguish between insufficient buffer and encoding
- * error.
- */
- size_t writtenLength = length;
JSLinearString* linear = str->ensureLinear(cx);
if (!linear)
return size_t(-1);
- bool res;
+ JS::AutoCheckCannotGC nogc;
+ size_t writeLength = Min(linear->length(), length);
if (linear->hasLatin1Chars()) {
- JS::AutoCheckCannotGC nogc;
- res = DeflateStringToBuffer(nullptr, linear->latin1Chars(nogc), linear->length(), buffer,
- &writtenLength);
+ mozilla::PodCopy(reinterpret_cast(buffer), linear->latin1Chars(nogc),
+ writeLength);
} else {
- JS::AutoCheckCannotGC nogc;
- res = DeflateStringToBuffer(nullptr, linear->twoByteChars(nogc), linear->length(), buffer,
- &writtenLength);
+ const char16_t* src = linear->twoByteChars(nogc);
+ for (size_t i = 0; i < writeLength; i++)
+ buffer[i] = char(src[i]);
}
- if (res) {
- MOZ_ASSERT(writtenLength <= length);
- return writtenLength;
- }
- MOZ_ASSERT(writtenLength <= length);
- size_t necessaryLength = str->length();
- if (necessaryLength == size_t(-1))
- return size_t(-1);
- MOZ_ASSERT(writtenLength == length); // C strings are NOT encoded.
- return necessaryLength;
+ return linear->length();
}
JS_PUBLIC_API(JS::Symbol*)
diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp
index 8e01dba29254..718c6a8a9627 100644
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -7839,11 +7839,43 @@ dom_set_x(JSContext* cx, HandleObject obj, void* self, JSJitSetterCallArgs args)
return true;
}
+static bool
+dom_get_global(JSContext* cx, HandleObject obj, void* self, JSJitGetterCallArgs args)
+{
+ MOZ_ASSERT(JS_GetClass(obj) == GetDomClass());
+ MOZ_ASSERT(self == (void*)0x1234);
+
+ // Return the current global (instead of obj->global()) to test cx->realm
+ // switching in the JIT.
+ args.rval().setObject(*ToWindowProxyIfWindow(cx->global()));
+
+ return true;
+}
+
+static bool
+dom_set_global(JSContext* cx, HandleObject obj, void* self, JSJitSetterCallArgs args)
+{
+ MOZ_ASSERT(JS_GetClass(obj) == GetDomClass());
+ MOZ_ASSERT(self == (void*)0x1234);
+
+ // Throw an exception if our argument is not the current global. This lets
+ // us test cx->realm switching.
+ if (!args[0].isObject() ||
+ ToWindowIfWindowProxy(&args[0].toObject()) != cx->global())
+ {
+ JS_ReportErrorASCII(cx, "Setter not called with matching global argument");
+ return false;
+ }
+
+ return true;
+}
+
static bool
dom_doFoo(JSContext* cx, HandleObject obj, void* self, const JSJitMethodCallArgs& args)
{
MOZ_ASSERT(JS_GetClass(obj) == GetDomClass());
MOZ_ASSERT(self == (void*)0x1234);
+ MOZ_ASSERT(cx->realm() == args.callee().as().realm());
/* Just return args.length(). */
args.rval().setInt32(args.length());
@@ -7854,8 +7886,8 @@ static const JSJitInfo dom_x_getterinfo = {
{ (JSJitGetterOp)dom_get_x },
{ 0 }, /* protoID */
{ 0 }, /* depth */
- JSJitInfo::AliasNone, /* aliasSet */
JSJitInfo::Getter,
+ JSJitInfo::AliasNone, /* aliasSet */
JSVAL_TYPE_UNKNOWN, /* returnType */
true, /* isInfallible. False in setters. */
true, /* isMovable */
@@ -7882,6 +7914,41 @@ static const JSJitInfo dom_x_setterinfo = {
0 /* slotIndex */
};
+// Note: this getter uses AliasEverything and is marked as fallible and
+// non-movable (1) to prevent Ion from getting too clever optimizing it and
+// (2) it's nice to have a few different kinds of getters in the shell.
+static const JSJitInfo dom_global_getterinfo = {
+ { (JSJitGetterOp)dom_get_global },
+ { 0 }, /* protoID */
+ { 0 }, /* depth */
+ JSJitInfo::Getter,
+ JSJitInfo::AliasEverything, /* aliasSet */
+ JSVAL_TYPE_OBJECT, /* returnType */
+ false, /* isInfallible. False in setters. */
+ false, /* isMovable */
+ false, /* isEliminatable */
+ false, /* isAlwaysInSlot */
+ false, /* isLazilyCachedInSlot */
+ false, /* isTypedMethod */
+ 0 /* slotIndex */
+};
+
+static const JSJitInfo dom_global_setterinfo = {
+ { (JSJitGetterOp)dom_set_global },
+ { 0 }, /* protoID */
+ { 0 }, /* depth */
+ JSJitInfo::Setter,
+ JSJitInfo::AliasEverything, /* aliasSet */
+ JSVAL_TYPE_UNKNOWN, /* returnType */
+ false, /* isInfallible. False in setters. */
+ false, /* isMovable. */
+ false, /* isEliminatable. */
+ false, /* isAlwaysInSlot */
+ false, /* isLazilyCachedInSlot */
+ false, /* isTypedMethod */
+ 0 /* slotIndex */
+};
+
static const JSJitInfo doFoo_methodinfo = {
{ (JSJitGetterOp)dom_doFoo },
{ 0 }, /* protoID */
@@ -7906,6 +7973,13 @@ static const JSPropertySpec dom_props[] = {
{ { dom_genericSetter, &dom_x_setterinfo } }
} },
},
+ {"global",
+ JSPROP_ENUMERATE,
+ { {
+ { { dom_genericGetter, &dom_global_getterinfo } },
+ { { dom_genericSetter, &dom_global_setterinfo } }
+ } },
+ },
JS_PS_END
};
diff --git a/js/src/threading/ExclusiveData.h b/js/src/threading/ExclusiveData.h
index d64e854d4a80..4733f8431dbf 100644
--- a/js/src/threading/ExclusiveData.h
+++ b/js/src/threading/ExclusiveData.h
@@ -17,6 +17,8 @@
namespace js {
/**
+ * [SMDOC] ExclusiveData API
+ *
* A mutual exclusion lock class.
*
* `ExclusiveData` provides an RAII guard to automatically lock and unlock when
diff --git a/js/src/util/Text.cpp b/js/src/util/Text.cpp
index fee1f7bbd819..6d3599469a07 100644
--- a/js/src/util/Text.cpp
+++ b/js/src/util/Text.cpp
@@ -119,36 +119,6 @@ js::InflateString(JSContext* cx, const char* bytes, size_t length)
return chars;
}
-template
-bool
-js::DeflateStringToBuffer(JSContext* maybecx, const CharT* src, size_t srclen,
- char* dst, size_t* dstlenp)
-{
- size_t dstlen = *dstlenp;
- if (srclen > dstlen) {
- for (size_t i = 0; i < dstlen; i++)
- dst[i] = char(src[i]);
- if (maybecx) {
- AutoSuppressGC suppress(maybecx);
- JS_ReportErrorNumberASCII(maybecx, GetErrorMessage, nullptr,
- JSMSG_BUFFER_TOO_SMALL);
- }
- return false;
- }
- for (size_t i = 0; i < srclen; i++)
- dst[i] = char(src[i]);
- *dstlenp = srclen;
- return true;
-}
-
-template bool
-js::DeflateStringToBuffer(JSContext* maybecx, const Latin1Char* src, size_t srclen,
- char* dst, size_t* dstlenp);
-
-template bool
-js::DeflateStringToBuffer(JSContext* maybecx, const char16_t* src, size_t srclen,
- char* dst, size_t* dstlenp);
-
/*
* Convert one UCS-4 char and write it into a UTF-8 buffer, which must be at
* least 4 bytes long. Return the number of UTF-8 bytes of data written.
diff --git a/js/src/util/Text.h b/js/src/util/Text.h
index f9a5deeb4a94..da48d0bbcd51 100644
--- a/js/src/util/Text.h
+++ b/js/src/util/Text.h
@@ -152,17 +152,6 @@ CopyAndInflateChars(char16_t* dst, const JS::Latin1Char* src, size_t srclen)
dst[i] = src[i];
}
-/*
- * Deflate JS chars to bytes into a buffer. 'bytes' must be large enough for
- * 'length chars. The buffer is NOT null-terminated. The destination length
- * must to be initialized with the buffer size and will contain on return the
- * number of copied bytes.
- */
-template
-extern bool
-DeflateStringToBuffer(JSContext* maybecx, const CharT* chars,
- size_t charsLength, char* bytes, size_t* length);
-
/*
* Convert one UCS-4 char and write it into a UTF-8 buffer, which must be at
* least 4 bytes long. Return the number of UTF-8 bytes of data written.
diff --git a/js/src/vm/ArgumentsObject.h b/js/src/vm/ArgumentsObject.h
index fb8389478cf5..28e319c14916 100644
--- a/js/src/vm/ArgumentsObject.h
+++ b/js/src/vm/ArgumentsObject.h
@@ -98,6 +98,8 @@ struct ArgumentsData
static const unsigned ARGS_LENGTH_MAX = 500 * 1000;
/*
+ * [SMDOC] ArgumentsObject
+ *
* ArgumentsObject instances represent |arguments| objects created to store
* function arguments when a function is called. It's expensive to create such
* objects if they're never used, so they're only created when they are
diff --git a/js/src/vm/ArrayBufferObject.cpp b/js/src/vm/ArrayBufferObject.cpp
index 96aeb9100701..1b3ec7bc5e0d 100644
--- a/js/src/vm/ArrayBufferObject.cpp
+++ b/js/src/vm/ArrayBufferObject.cpp
@@ -592,6 +592,8 @@ ArrayBufferObject::changeContents(JSContext* cx, BufferContents newContents,
}
/*
+ * [SMDOC] WASM Linear Memory structure
+ *
* Wasm Raw Buf Linear Memory Structure
*
* The linear heap in Wasm is an mmaped array buffer. Several
diff --git a/js/src/vm/BytecodeUtil.h b/js/src/vm/BytecodeUtil.h
index 8707fe9c0ea7..ec4fb4da9a99 100644
--- a/js/src/vm/BytecodeUtil.h
+++ b/js/src/vm/BytecodeUtil.h
@@ -35,7 +35,7 @@ FOR_EACH_OPCODE(ENUMERATE_OPCODE)
} JSOp;
/*
- * JS bytecode formats.
+ * [SMDOC] Bytecode Format flags (JOF_*)
*/
enum {
JOF_BYTE = 0, /* single bytecode, no immediates */
diff --git a/js/src/vm/EnvironmentObject.h b/js/src/vm/EnvironmentObject.h
index 8f9cb5a42f2b..415a0ced0568 100644
--- a/js/src/vm/EnvironmentObject.h
+++ b/js/src/vm/EnvironmentObject.h
@@ -45,6 +45,8 @@ EnvironmentCoordinateFunctionScript(JSScript* script, jsbytecode* pc);
/*** Environment objects *****************************************************/
/*
+ * [SMDOC] Environment Objects
+ *
* About environments
* ------------------
*
diff --git a/js/src/vm/JSObject.h b/js/src/vm/JSObject.h
index 313c2d898407..16728c289de6 100644
--- a/js/src/vm/JSObject.h
+++ b/js/src/vm/JSObject.h
@@ -49,6 +49,8 @@ bool SetImmutablePrototype(JSContext* cx, JS::HandleObject obj, bool* succeeded)
} /* namespace js */
/*
+ * [SMDOC] JSObject layout
+ *
* A JavaScript object.
*
* This is the base class for all objects exposed to JS script (as well as some
diff --git a/js/src/vm/JSScript.cpp b/js/src/vm/JSScript.cpp
index 4bd158f80028..0735975dca55 100644
--- a/js/src/vm/JSScript.cpp
+++ b/js/src/vm/JSScript.cpp
@@ -2332,6 +2332,8 @@ ScriptSource::setSourceMapURL(JSContext* cx, const char16_t* sourceMapURL)
}
/*
+ * [SMDOC] JSScript data layout (shared)
+ *
* Shared script data management.
*
* SharedScriptData::data contains data that can be shared within a
@@ -2505,6 +2507,8 @@ js::FreeScriptData(JSRuntime* rt)
}
/*
+ * [SMDOC] JSScript data layout (unshared)
+ *
* JSScript::data and SharedScriptData::data have complex,
* manually-controlled, memory layouts.
*
diff --git a/js/src/vm/NativeObject.cpp b/js/src/vm/NativeObject.cpp
index 54d85b43ba83..2a56eebb6413 100644
--- a/js/src/vm/NativeObject.cpp
+++ b/js/src/vm/NativeObject.cpp
@@ -1194,6 +1194,17 @@ CallAddPropertyHookDense(JSContext* cx, HandleNativeObject obj, uint32_t index,
return true;
}
+/**
+ * Determines whether a write to the given element on |arr| should fail
+ * because |arr| has a non-writable length, and writing that element would
+ * increase the length of the array.
+ */
+static bool
+WouldDefinePastNonwritableLength(ArrayObject* arr, uint32_t index)
+{
+ return !arr->lengthIsWritable() && index >= arr->length();
+}
+
static MOZ_ALWAYS_INLINE void
UpdateShapeTypeAndValue(JSContext* cx, NativeObject* obj, Shape* shape, jsid id,
const Value& value)
@@ -1621,7 +1632,7 @@ js::NativeDefineProperty(JSContext* cx, HandleNativeObject obj, HandleId id,
// 9.4.2.1 step 3. Don't extend a fixed-length array.
uint32_t index;
if (IdIsIndex(id, &index)) {
- if (WouldDefinePastNonwritableLength(obj, index))
+ if (WouldDefinePastNonwritableLength(arr, index))
return result.fail(JSMSG_CANT_DEFINE_PAST_ARRAY_LENGTH);
}
} else if (obj->is()) {
@@ -1923,7 +1934,7 @@ DefineNonexistentProperty(JSContext* cx, HandleNativeObject obj, HandleId id,
// 9.4.2.1 step 3. Don't extend a fixed-length array.
uint32_t index;
if (IdIsIndex(id, &index)) {
- if (WouldDefinePastNonwritableLength(obj, index))
+ if (WouldDefinePastNonwritableLength(&obj->as(), index))
return result.fail(JSMSG_CANT_DEFINE_PAST_ARRAY_LENGTH);
}
} else if (obj->is()) {
@@ -2647,11 +2658,14 @@ SetDenseOrTypedArrayElement(JSContext* cx, HandleNativeObject obj, uint32_t inde
return result.succeed();
}
- return result.failSoft(JSMSG_BAD_INDEX);
+ // A previously existing typed array element can only be out-of-bounds
+ // if the above ToNumber call detached the typed array's buffer.
+ MOZ_ASSERT(obj->as().hasDetachedBuffer());
+
+ return result.failSoft(JSMSG_TYPED_ARRAY_DETACHED);
}
- if (WouldDefinePastNonwritableLength(obj, index))
- return result.fail(JSMSG_CANT_DEFINE_PAST_ARRAY_LENGTH);
+ MOZ_ASSERT(obj->containsDenseElement(index));
if (!obj->maybeCopyElementsForWrite(cx))
return false;
@@ -2669,9 +2683,8 @@ SetDenseOrTypedArrayElement(JSContext* cx, HandleNativeObject obj, uint32_t inde
* dense or typed array element (i.e. not actually a pointer to a Shape).
*/
static bool
-SetExistingProperty(JSContext* cx, HandleNativeObject obj, HandleId id, HandleValue v,
- HandleValue receiver, HandleNativeObject pobj, Handle prop,
- ObjectOpResult& result)
+SetExistingProperty(JSContext* cx, HandleId id, HandleValue v, HandleValue receiver,
+ HandleNativeObject pobj, Handle prop, ObjectOpResult& result)
{
// Step 5 for dense elements.
if (prop.isDenseOrTypedArrayElement()) {
@@ -2744,7 +2757,7 @@ js::NativeSetProperty(JSContext* cx, HandleNativeObject obj, HandleId id, Handle
if (prop) {
// Steps 5-6.
- return SetExistingProperty(cx, obj, id, v, receiver, pobj, prop, result);
+ return SetExistingProperty(cx, id, v, receiver, pobj, prop, result);
}
// Steps 4.a-b. The check for 'done' on this next line is tricky.
diff --git a/js/src/vm/NativeObject.h b/js/src/vm/NativeObject.h
index a010c91e3149..9b5bcf585dfa 100644
--- a/js/src/vm/NativeObject.h
+++ b/js/src/vm/NativeObject.h
@@ -92,6 +92,8 @@ ArraySetLength(JSContext* cx, Handle obj, HandleId id,
unsigned attrs, HandleValue value, ObjectOpResult& result);
/*
+ * [SMDOC] NativeObject Elements layout
+ *
* Elements header used for native objects. The elements component of such objects
* offers an efficient representation for all or some of the indexed properties
* of the object, using a flat array of Values rather than a shape hierarchy
@@ -159,6 +161,9 @@ ArraySetLength(JSContext* cx, Handle obj, HandleId id,
* of an object does not necessarily visit indexes in the order they were
* created.
*
+ *
+ * [SMDOC] NativeObject shifted elements optimization
+ *
* Shifted elements
* ----------------
* It's pretty common to use an array as a queue, like this:
@@ -432,6 +437,8 @@ enum class ShouldUpdateTypes {
};
/*
+ * [SMDOC] NativeObject layout
+ *
* NativeObject specifies the internal implementation of a native object.
*
* Native objects use ShapedObject::shape to record property information. Two
diff --git a/js/src/vm/ObjectGroup.h b/js/src/vm/ObjectGroup.h
index d1e161cae311..a651b32b6a3f 100644
--- a/js/src/vm/ObjectGroup.h
+++ b/js/src/vm/ObjectGroup.h
@@ -65,7 +65,7 @@ enum NewObjectKind {
};
/*
- * Lazy object groups overview.
+ * [SMDOC] Type-Inference lazy ObjectGroup
*
* Object groups which represent at most one JS object are constructed lazily.
* These include groups for native functions, standard classes, scripted
@@ -109,6 +109,8 @@ class ObjectGroup : public gc::TenuredCell
void* addendum_ = nullptr;
/*
+ * [SMDOC] Type-Inference object properties
+ *
* Properties of this object.
*
* The type sets in the properties of a group describe the possible values
diff --git a/js/src/vm/Opcodes.h b/js/src/vm/Opcodes.h
index 28d30bef3fcb..111dbcdb1929 100644
--- a/js/src/vm/Opcodes.h
+++ b/js/src/vm/Opcodes.h
@@ -13,6 +13,8 @@
#include
/*
+ * [SMDOC] Bytecode Definitions
+ *
* JavaScript operation bytecodes. Add a new bytecode by claiming one of the
* JSOP_UNUSED* here or by extracting the first unused opcode from
* FOR_EACH_TRAILING_UNUSED_OPCODE and updating js::detail::LastDefinedOpcode
diff --git a/js/src/vm/Printer.cpp b/js/src/vm/Printer.cpp
index fa400c37c156..6d696778fe1c 100644
--- a/js/src/vm/Printer.cpp
+++ b/js/src/vm/Printer.cpp
@@ -223,9 +223,8 @@ Sprinter::putString(JSString* s)
InvariantChecker ic(this);
size_t length = s->length();
- size_t size = length;
- char* buffer = reserve(size);
+ char* buffer = reserve(length);
if (!buffer)
return false;
@@ -234,12 +233,15 @@ Sprinter::putString(JSString* s)
return false;
JS::AutoCheckCannotGC nogc;
- if (linear->hasLatin1Chars())
+ if (linear->hasLatin1Chars()) {
PodCopy(reinterpret_cast(buffer), linear->latin1Chars(nogc), length);
- else
- DeflateStringToBuffer(nullptr, linear->twoByteChars(nogc), length, buffer, &size);
+ } else {
+ const char16_t* src = linear->twoByteChars(nogc);
+ for (size_t i = 0; i < length; i++)
+ buffer[i] = char(src[i]);
+ }
- buffer[size] = 0;
+ buffer[length] = 0;
return true;
}
diff --git a/js/src/vm/Realm.h b/js/src/vm/Realm.h
index 9431e4f83cd3..810aedeef08d 100644
--- a/js/src/vm/Realm.h
+++ b/js/src/vm/Realm.h
@@ -119,6 +119,8 @@ class NewProxyCache
}
};
+// [SMDOC] Object MetadataBuilder API
+//
// We must ensure that all newly allocated JSObjects get their metadata
// set. However, metadata builders may require the new object be in a sane
// state (eg, have its reserved slots initialized so they can get the
diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h
index bd1f6d055d7e..ff2aba956240 100644
--- a/js/src/vm/Runtime.h
+++ b/js/src/vm/Runtime.h
@@ -107,7 +107,7 @@ class Simulator;
#endif
} // namespace jit
-// JS Engine Threading
+// [SMDOC] JS Engine Threading
//
// Threads interacting with a runtime are divided into two categories:
//
diff --git a/js/src/vm/Shape.h b/js/src/vm/Shape.h
index 309d3c52b05c..7d5419b8be63 100644
--- a/js/src/vm/Shape.h
+++ b/js/src/vm/Shape.h
@@ -34,6 +34,8 @@
#include "vm/SymbolType.h"
/*
+ * [SMDOC] Shapes
+ *
* In isolation, a Shape represents a property that exists in one or more
* objects; it has an id, flags, etc. (But it doesn't represent the property's
* value.) However, Shapes are always stored in linked linear sequence of
diff --git a/js/src/vm/Stack.h b/js/src/vm/Stack.h
index ed6ff34f7528..4c071eca603e 100644
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -69,7 +69,7 @@ class DebugFrame;
class Instance;
}
-// VM stack layout
+// [SMDOC] VM stack layout
//
// A JSRuntime's stack consists of a linked list of activations. Every activation
// contains a number of scripted frames that are either running in the interpreter
diff --git a/js/src/vm/StringType.h b/js/src/vm/StringType.h
index 8638fe7ff8b3..7d5e87e7c91c 100644
--- a/js/src/vm/StringType.h
+++ b/js/src/vm/StringType.h
@@ -44,7 +44,7 @@ static const size_t UINT32_CHAR_BUFFER_LENGTH = sizeof("4294967295") - 1;
} /* namespace js */
/*
- * JavaScript strings
+ * [SMDOC] JavaScript Strings
*
* Conceptually, a JS string is just an array of chars and a length. This array
* of chars may or may not be null-terminated and, if it is, the null character
diff --git a/js/src/vm/SymbolType.h b/js/src/vm/SymbolType.h
index 49413805452e..88405162f133 100644
--- a/js/src/vm/SymbolType.h
+++ b/js/src/vm/SymbolType.h
@@ -122,6 +122,8 @@ struct HashSymbolsByDescription
};
/*
+ * [SMDOC] Symbol.for() registry (ES6 GlobalSymbolRegistry)
+ *
* The runtime-wide symbol registry, used to implement Symbol.for().
*
* ES6 draft rev 25 (2014 May 22) calls this the GlobalSymbolRegistry List. In
diff --git a/js/src/vm/TypeInference.h b/js/src/vm/TypeInference.h
index 5280308da4df..6a06c6437f23 100644
--- a/js/src/vm/TypeInference.h
+++ b/js/src/vm/TypeInference.h
@@ -213,6 +213,8 @@ class HeapTypeSet;
class TemporaryTypeSet;
/*
+ * [SMDOC] Type-Inference TypeSet
+ *
* Information about the set of types associated with an lvalue. There are
* three kinds of type sets:
*
diff --git a/js/src/wasm/WasmBaselineCompile.cpp b/js/src/wasm/WasmBaselineCompile.cpp
index 69df2144f501..138a4666df18 100644
--- a/js/src/wasm/WasmBaselineCompile.cpp
+++ b/js/src/wasm/WasmBaselineCompile.cpp
@@ -16,7 +16,8 @@
* limitations under the License.
*/
-/* WebAssembly baseline compiler ("RabaldrMonkey")
+/*
+ * [SMDOC] WebAssembly baseline compiler (RabaldrMonkey)
*
* General assumptions for 32-bit vs 64-bit code:
*
diff --git a/js/src/wasm/WasmTextToBinary.cpp b/js/src/wasm/WasmTextToBinary.cpp
index df066677be6d..d6bce593b843 100644
--- a/js/src/wasm/WasmTextToBinary.cpp
+++ b/js/src/wasm/WasmTextToBinary.cpp
@@ -1656,15 +1656,19 @@ WasmTokenStream::next()
break;
case 'm':
-#ifdef ENABLE_WASM_BULKMEM_OPS
if (consume(u"memory.")) {
+#ifdef ENABLE_WASM_BULKMEM_OPS
if (consume(u"copy"))
return WasmToken(WasmToken::MemCopy, begin, cur_);
if (consume(u"fill"))
return WasmToken(WasmToken::MemFill, begin, cur_);
+#endif
+ if (consume(u"grow"))
+ return WasmToken(WasmToken::GrowMemory, begin, cur_);
+ if (consume(u"size"))
+ return WasmToken(WasmToken::CurrentMemory, begin, cur_);
break;
}
-#endif
if (consume(u"module"))
return WasmToken(WasmToken::Module, begin, cur_);
if (consume(u"memory"))
diff --git a/layout/base/PresShell.cpp b/layout/base/PresShell.cpp
index 4f80119de79b..4c523c79d0ec 100644
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -176,6 +176,8 @@
#include "nsLayoutStylesheetCache.h"
#include "mozilla/layers/InputAPZContext.h"
#include "mozilla/layers/FocusTarget.h"
+#include "mozilla/layers/WebRenderLayerManager.h"
+#include "mozilla/layers/WebRenderUserData.h"
#include "mozilla/ServoBindings.h"
#include "mozilla/ServoStyleSet.h"
#include "mozilla/StyleSheet.h"
@@ -6319,7 +6321,15 @@ PresShell::Paint(nsView* aViewToPaint,
}
if (layerManager->GetBackendType() == layers::LayersBackend::LAYERS_WR) {
- // TODO: bug 1405465 - create a WR display list which simulates the color layer below.
+ nsPresContext* pc = GetPresContext();
+ LayoutDeviceRect bounds =
+ LayoutDeviceRect::FromAppUnits(pc->GetVisibleArea(), pc->AppUnitsPerDevPixel());
+ bgcolor = NS_ComposeColors(bgcolor, mCanvasBackgroundColor);
+ WebRenderBackgroundData data(wr::ToLayoutRect(bounds), wr::ToColorF(ToDeviceColor(bgcolor)));
+ nsTArray wrFilters;
+
+ MaybeSetupTransactionIdAllocator(layerManager, presContext);
+ layerManager->AsWebRenderLayerManager()->EndTransactionWithoutLayer(nullptr, nullptr, wrFilters, &data);
return;
}
diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp
index 2202c6ae7177..672097f8ae8b 100644
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -1916,6 +1916,11 @@ nsCSSFrameConstructor::CreateGeneratedContentItem(nsFrameConstructorState& aStat
CreateGeneratedContent(aState, aParentContent, pseudoComputedStyle,
contentIndex);
if (content) {
+ // We don't strictly have to set NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE
+ // here; it would get set under AppendChildTo. But AppendChildTo might
+ // think that we're going from not being anonymous to being anonymous and
+ // do some extra work; setting the flag here avoids that.
+ content->SetFlags(NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE);
container->AppendChildTo(content, false);
if (content->IsElement()) {
// If we created any children elements, Servo needs to traverse them, but
diff --git a/layout/reftests/border-radius/reftest.list b/layout/reftests/border-radius/reftest.list
index 9ff5d49ce5d6..450e8feac85b 100644
--- a/layout/reftests/border-radius/reftest.list
+++ b/layout/reftests/border-radius/reftest.list
@@ -58,7 +58,7 @@ fuzzy-if(cocoaWidget,1,4) fuzzy-if(d2d,59,342) fuzzy-if(d3d11&&advancedLayers&&!
== intersecting-clipping-1-image.html intersecting-clipping-1-refi.html
== intersecting-clipping-1-overflow-hidden.html intersecting-clipping-1-ref.html
fuzzy-if(Android,5,105) fuzzy-if(d2d,1,20) fuzzy-if(skiaContent,1,300) == intersecting-clipping-1-refi.html intersecting-clipping-1-ref.html
-fuzzy-if(true,1,33) fuzzy-if(d2d,59,350) fuzzy-if(cocoaWidget,1,332) fuzzy-if(Android,124,440) fuzzy-if(skiaContent,1,135) fuzzy-if(d3d11&&advancedLayers,81,353) == intersecting-clipping-1-refc.html intersecting-clipping-1-ref.html # bug 732535
+fuzzy-if(true,1,33) fuzzy-if(d2d,59,350) fuzzy-if(cocoaWidget,1,332) fuzzy-if(Android,124,440) fuzzy-if(skiaContent,1,135) fuzzy-if(d3d11&&advancedLayers,81,353) skip-if(winWidget) == intersecting-clipping-1-refc.html intersecting-clipping-1-ref.html # bug 732535 # Disable on Windows bug 1451808
# Inheritance
== inherit-1.html inherit-1-ref.html # border-radius shouldn't inherit
diff --git a/media/libcubeb/cubeb-pulse-rs/README_MOZILLA b/media/libcubeb/cubeb-pulse-rs/README_MOZILLA
index 8a9dd50be1ab..259be71b228d 100644
--- a/media/libcubeb/cubeb-pulse-rs/README_MOZILLA
+++ b/media/libcubeb/cubeb-pulse-rs/README_MOZILLA
@@ -5,4 +5,4 @@ Makefile.in build files for the Mozilla build system.
The cubeb-pulse-rs git repository is: https://github.com/djg/cubeb-pulse-rs.git
-The git commit ID used was f90aecf00ed6e5c67f593b3ecf412a8f3ffc0b1f (2018-04-18 08:06:35 +1000)
+The git commit ID used was d0bdf51ebd0a653cc4276d2346db852a3060ade0 (2018-06-29 10:09:52 +1000)
diff --git a/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/stream.rs b/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/stream.rs
index 780c3eb300cb..785ee1be485d 100644
--- a/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/stream.rs
+++ b/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/stream.rs
@@ -323,8 +323,8 @@ impl Stream {
Ok(unsafe { operation::from_raw_ptr(r) })
}
- pub fn get_time(&self) -> Result<(u64)> {
- let mut usec: u64 = 0;
+ pub fn get_time(&self) -> Result<(USec)> {
+ let mut usec: USec = 0;
let r = unsafe { ffi::pa_stream_get_time(self.raw_mut(), &mut usec) };
error_result!(usec, r)
}
diff --git a/media/libcubeb/cubeb-pulse-rs/src/backend/stream.rs b/media/libcubeb/cubeb-pulse-rs/src/backend/stream.rs
index 3c6136968dd6..96bee058f0b6 100644
--- a/media/libcubeb/cubeb-pulse-rs/src/backend/stream.rs
+++ b/media/libcubeb/cubeb-pulse-rs/src/backend/stream.rs
@@ -438,7 +438,7 @@ impl<'ctx> StreamOps for PulseStream<'ctx> {
let stm = self.output_stream.as_ref().unwrap();
let r = match stm.get_time() {
Ok(r_usec) => {
- let bytes = r_usec.to_bytes(&self.output_sample_spec);
+ let bytes = USecExt::to_bytes(r_usec, &self.output_sample_spec);
Ok((bytes / self.output_sample_spec.frame_size()) as u64)
}
Err(_) => Err(Error::error()),
diff --git a/mobile/android/base/Makefile.in b/mobile/android/base/Makefile.in
index 3c43a0ff2ade..ab5ebd537cc2 100644
--- a/mobile/android/base/Makefile.in
+++ b/mobile/android/base/Makefile.in
@@ -46,10 +46,6 @@ $(ABS_DIST)/fennec/$(OMNIJAR_NAME): FORCE
rsync --update $(DIST)/fennec/$(notdir $(OMNIJAR_NAME)) $@
$(RM) $(DIST)/fennec/$(notdir $(OMNIJAR_NAME))
-.PHONY: features
-features::
- $(call py_action,generate_builtin_addons,--features=features chrome/chrome/content/built_in_addons.json)
-
ifndef MOZILLA_OFFICIAL
# Targets built very early during a Gradle build. In automation,
# these are built before Gradle is invoked, and gradle-targets is not
diff --git a/mozglue/build/WindowsDllBlocklistCommon.h b/mozglue/build/WindowsDllBlocklistCommon.h
index bc5e96f2b9b5..1b2f871eca7e 100644
--- a/mozglue/build/WindowsDllBlocklistCommon.h
+++ b/mozglue/build/WindowsDllBlocklistCommon.h
@@ -53,6 +53,15 @@ struct DllBlockInfoT {
// Convert the 4 (decimal) components of a DLL version number into a
// single unsigned long long, as needed by the blocklist
+#if defined(_MSC_VER) && !defined(__clang__)
+
+// MSVC does not properly handle the constexpr MAKE_VERSION, so we use a macro
+// instead (ugh).
+#define MAKE_VERSION(a,b,c,d) \
+ ((a##ULL << 48) + (b##ULL << 32) + (c##ULL << 16) + d##ULL)
+
+#else
+
static inline constexpr uint64_t
MAKE_VERSION(uint16_t a, uint16_t b, uint16_t c, uint16_t d)
{
@@ -62,6 +71,8 @@ MAKE_VERSION(uint16_t a, uint16_t b, uint16_t c, uint16_t d)
static_cast(d);
}
+#endif
+
#if !defined(DLL_BLOCKLIST_CHAR_TYPE)
#error "You must define DLL_BLOCKLIST_CHAR_TYPE"
#endif // !defined(DLL_BLOCKLIST_CHAR_TYPE)
diff --git a/netwerk/protocol/websocket/WebSocketChannel.cpp b/netwerk/protocol/websocket/WebSocketChannel.cpp
index 4bf4982fb888..ca5cc2cfd2b9 100644
--- a/netwerk/protocol/websocket/WebSocketChannel.cpp
+++ b/netwerk/protocol/websocket/WebSocketChannel.cpp
@@ -59,6 +59,7 @@
#include "mozilla/Telemetry.h"
#include "mozilla/TimeStamp.h"
#include "nsSocketTransportService2.h"
+#include "nsINSSErrorsService.h"
#include "plbase64.h"
#include "prmem.h"
@@ -3817,9 +3818,25 @@ WebSocketChannel::OnStartRequest(nsIRequest *aRequest,
rv = mHttpChannel->GetResponseStatus(&status);
if (NS_FAILED(rv)) {
+ nsresult httpStatus;
+ rv = NS_ERROR_CONNECTION_REFUSED;
+
+ // If we failed to connect due to unsuccessful TLS handshake, we must
+ // propagate a specific error to mozilla::dom::WebSocketImpl so it can set
+ // status code to 1015. Otherwise return NS_ERROR_CONNECTION_REFUSED.
+ if (NS_SUCCEEDED(mHttpChannel->GetStatus(&httpStatus))) {
+ uint32_t errorClass;
+ nsCOMPtr errSvc =
+ do_GetService("@mozilla.org/nss_errors_service;1");
+ // If GetErrorClass succeeds httpStatus is TLS related failure.
+ if (errSvc && NS_SUCCEEDED(errSvc->GetErrorClass(httpStatus, &errorClass))) {
+ rv = NS_ERROR_NET_INADEQUATE_SECURITY;
+ }
+ }
+
LOG(("WebSocketChannel::OnStartRequest: No HTTP Response\n"));
- AbortSession(NS_ERROR_CONNECTION_REFUSED);
- return NS_ERROR_CONNECTION_REFUSED;
+ AbortSession(rv);
+ return rv;
}
LOG(("WebSocketChannel::OnStartRequest: HTTP status %d\n", status));
diff --git a/python/mozbuild/mozbuild/action/generate_builtin_addons.py b/python/mozbuild/mozbuild/action/generate_builtin_addons.py
deleted file mode 100644
index c65795b7486c..000000000000
--- a/python/mozbuild/mozbuild/action/generate_builtin_addons.py
+++ /dev/null
@@ -1,52 +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/.
-
-from __future__ import absolute_import, print_function, unicode_literals
-from mozbuild.util import ensureParentDir
-
-import argparse
-import json
-import os.path
-import sys
-
-import buildconfig
-
-
-def main(argv):
- parser = argparse.ArgumentParser(
- description='Produces a JSON manifest of built-in add-ons')
- parser.add_argument('--features', type=str, dest='featuresdir',
- action='store', help=('The distribution sub-directory '
- 'containing feature add-ons'))
- parser.add_argument('outputfile', help='File to write output to')
- args = parser.parse_args(argv)
-
- bindir = os.path.join(buildconfig.topobjdir, 'dist/bin')
-
- def find_dictionaries(path):
- dicts = {}
- for filename in os.listdir(os.path.join(bindir, path)):
- base, ext = os.path.splitext(filename)
- if ext == '.dic':
- dicts[base] = '%s/%s' % (path, filename)
- return dicts
-
- listing = {
- "dictionaries": find_dictionaries("dictionaries"),
- }
- if args.featuresdir:
- listing["system"] = sorted(os.listdir(os.path.join(bindir,
- args.featuresdir)))
- if len(listing["system"]) == 0:
- raise IOError("featuresdir is empty, we lost a race")
-
- outputfilepath = os.path.join(bindir, args.outputfile)
- ensureParentDir(outputfilepath)
-
- with open(outputfilepath, 'w') as fh:
- json.dump(listing, fh, sort_keys=True)
-
-
-if __name__ == '__main__':
- sys.exit(main(sys.argv[1:]))
diff --git a/python/mozbuild/mozbuild/backend/tup.py b/python/mozbuild/mozbuild/backend/tup.py
index 94ebf296b74b..af481a33ff4c 100644
--- a/python/mozbuild/mozbuild/backend/tup.py
+++ b/python/mozbuild/mozbuild/backend/tup.py
@@ -99,6 +99,7 @@ class BackendTupfile(object):
# These files are special, ignore anything that generates them or
# depends on them.
self._skip_files = [
+ 'built_in_addons.json',
'signmar',
]
diff --git a/taskcluster/docs/docker-images.rst b/taskcluster/docs/docker-images.rst
index aa9f38c4a45e..da2cd25a7274 100644
--- a/taskcluster/docs/docker-images.rst
+++ b/taskcluster/docs/docker-images.rst
@@ -107,11 +107,9 @@ Example:
image: taskcluster/decision:0.1.10@sha256:c5451ee6c655b3d97d4baa3b0e29a5115f23e0991d4f7f36d2a8f793076d6854
-Each image has a repo digest, an image hash, and a version. The repo digest is
-stored in the ``HASH`` file in the image directory and used to refer to the
-image as above. The version is in ``VERSION``. The image hash is used in
-`chain-of-trust verification `_
-in `scriptworker `_.
+Each image has a repo digest and a version. The repo digest is stored in the
+``HASH`` file in the image directory and used to refer to the image as above.
+The version is in ``VERSION``.
The version file only serves to provide convenient names, such that old
versions are easy to discover in the registry (and ensuring old versions aren't
@@ -171,12 +169,7 @@ the docker registry and make note of the resulting repo digest. Put this value
in the ``HASH`` file, and update any references to the image in the code or
task definitions.
-The change is now safe to use in Try pushes. However, if the image is used in
-building releases then it is *not* safe to land to an integration branch until
-the whitelists in `scriptworker's constants.py
-`_
-have also been updated. These whitelists use the image hash, not the repo
-digest.
+The change is now safe to use in Try pushes.
Special Dockerfile Syntax
-------------------------
diff --git a/testing/mozharness/scripts/desktop_unittest.py b/testing/mozharness/scripts/desktop_unittest.py
index ea8ff30d625b..7674890632bf 100755
--- a/testing/mozharness/scripts/desktop_unittest.py
+++ b/testing/mozharness/scripts/desktop_unittest.py
@@ -894,7 +894,7 @@ class DesktopUnittest(TestingMixin, MercurialScript, MozbaseMixin,
# Per-test reset/dump is only supported for xpcshell and
# Linux for the time being.
if not is_baseline_test and suite == 'xpcshell' and self._is_linux():
- env['GCOV_RESULTS_DIR'] = gcov_dir = tempfile.mkdtemp()
+ env['GCOV_RESULTS_DIR'] = tempfile.mkdtemp()
return_code = self.run_command(final_cmd, cwd=dirs['abs_work_dir'],
output_timeout=cmd_timeout,
@@ -903,8 +903,13 @@ class DesktopUnittest(TestingMixin, MercurialScript, MozbaseMixin,
if self.per_test_coverage:
self.add_per_test_coverage_report(
- gcov_dir, jsvm_dir, suite, per_test_args[-1]
+ env['GCOV_RESULTS_DIR'] if 'GCOV_RESULTS_DIR' in env else gcov_dir,
+ jsvm_dir,
+ suite,
+ per_test_args[-1]
)
+ if 'GCOV_RESULTS_DIR' in env:
+ shutil.rmtree(gcov_dir)
# mochitest, reftest, and xpcshell suites do not return
# appropriate return codes. Therefore, we must parse the output
diff --git a/testing/xpcshell/head.js b/testing/xpcshell/head.js
index 9c1a813c73e5..3a32b7f852f0 100644
--- a/testing/xpcshell/head.js
+++ b/testing/xpcshell/head.js
@@ -511,21 +511,9 @@ function _execute_test() {
this[func] = Assert[func].bind(Assert);
}
- let perTestCoverageEnabled = false;
- try {
- ChromeUtils.import("resource://testing-common/PerTestCoverageUtils.jsm");
- perTestCoverageEnabled = true;
- } catch (e) {
- // If the module doesn't exist, code coverage is disabled.
- // Otherwise, rethrow the exception.
- if (e.result != Cr.NS_ERROR_FILE_NOT_FOUND) {
- throw e;
- }
- }
+ const {PerTestCoverageUtils} = ChromeUtils.import("resource://testing-common/PerTestCoverageUtils.jsm", {});
- if (perTestCoverageEnabled) {
- PerTestCoverageUtils.beforeTest();
- }
+ PerTestCoverageUtils.beforeTestSync();
try {
do_test_pending("MAIN run_test");
@@ -546,9 +534,7 @@ function _execute_test() {
coverageCollector.recordTestCoverage(_TEST_FILE[0]);
}
- if (perTestCoverageEnabled) {
- PerTestCoverageUtils.afterTest();
- }
+ PerTestCoverageUtils.afterTestSync();
} catch (e) {
_passed = false;
// do_check failures are already logged and set _quit to true and throw
diff --git a/toolkit/components/downloads/DownloadIntegration.jsm b/toolkit/components/downloads/DownloadIntegration.jsm
index 1649eb71ed3e..ba240f4d1ed2 100644
--- a/toolkit/components/downloads/DownloadIntegration.jsm
+++ b/toolkit/components/downloads/DownloadIntegration.jsm
@@ -595,7 +595,7 @@ var DownloadIntegration = {
}
let isWindowsExe = AppConstants.platform == "win" &&
- fileExtension.toLowerCase() == "exe";
+ fileExtension && fileExtension.toLowerCase() == "exe";
// Ask for confirmation if the file is executable, except for .exe on
// Windows where the operating system will show the prompt based on the
diff --git a/toolkit/mozapps/extensions/gen_built_in_addons.py b/toolkit/mozapps/extensions/gen_built_in_addons.py
new file mode 100644
index 000000000000..416f0d52dd18
--- /dev/null
+++ b/toolkit/mozapps/extensions/gen_built_in_addons.py
@@ -0,0 +1,94 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+from __future__ import absolute_import, print_function, unicode_literals
+
+import argparse
+import json
+import os.path
+import sys
+
+import buildconfig
+import mozpack.path as mozpath
+
+from mozpack.copier import FileRegistry
+from mozpack.manifests import InstallManifest
+
+
+# A list of build manifests, and their relative base paths, from which to
+# extract lists of install files. These vary depending on which backend we're
+# using, so nonexistent manifests are ignored.
+manifest_paths = (
+ ('', '_build_manifests/install/dist_bin'),
+ ('', 'faster/install_dist_bin'),
+ ('browser', 'faster/install_dist_bin_browser'),
+)
+
+
+def get_registry(paths):
+ used_paths = set()
+
+ registry = FileRegistry()
+ for base, path in paths:
+ full_path = mozpath.join(buildconfig.topobjdir, path)
+ if not os.path.exists(full_path):
+ continue
+
+ used_paths.add(full_path)
+
+ reg = FileRegistry()
+ InstallManifest(full_path).populate_registry(reg)
+
+ for p, f in reg:
+ path = mozpath.join(base, p)
+ if not registry.contains(path):
+ registry.add(path, f)
+
+ return registry, used_paths
+
+
+def get_child(base, path):
+ """Returns the nearest parent of `path` which is an immediate child of
+ `base`"""
+
+ dirname = mozpath.dirname(path)
+ while dirname != base:
+ path = dirname
+ dirname = mozpath.dirname(path)
+ return path
+
+
+def main(output, *args):
+ parser = argparse.ArgumentParser(
+ description='Produces a JSON manifest of built-in add-ons')
+ parser.add_argument('--features', type=str, dest='featuresdir',
+ action='store', help=('The distribution sub-directory '
+ 'containing feature add-ons'))
+ args = parser.parse_args(args)
+
+ registry, inputs = get_registry(manifest_paths)
+
+ dicts = {}
+ for path in registry.match('dictionaries/*.dic'):
+ base, ext = os.path.splitext(mozpath.basename(path))
+ dicts[base] = path
+
+ listing = {
+ "dictionaries": dicts,
+ }
+
+ if args.featuresdir:
+ features = set()
+ for p in registry.match('%s/*' % args.featuresdir):
+ features.add(mozpath.basename(get_child(args.featuresdir, p)))
+
+ listing["system"] = sorted(features)
+
+ json.dump(listing, output)
+
+ return inputs
+
+
+if __name__ == '__main__':
+ main(sys.stdout, *sys.argv[1:])
diff --git a/toolkit/mozapps/extensions/moz.build b/toolkit/mozapps/extensions/moz.build
index d9714ab2c454..ee2cc3d8a766 100644
--- a/toolkit/mozapps/extensions/moz.build
+++ b/toolkit/mozapps/extensions/moz.build
@@ -25,6 +25,24 @@ XPIDL_SOURCES += [
XPIDL_MODULE = 'extensions'
+built_in_addons = 'built_in_addons.json'
+GENERATED_FILES += [built_in_addons]
+manifest = GENERATED_FILES[built_in_addons]
+manifest.script = 'gen_built_in_addons.py'
+
+if CONFIG['MOZ_BUILD_APP'] == 'browser':
+ manifest.flags = ['--features=browser/features']
+
+ FINAL_TARGET_FILES.browser.chrome.browser.content.browser += [
+ '!%s' % built_in_addons,
+ ]
+elif CONFIG['MOZ_BUILD_APP'] == 'mobile/android':
+ manifest.flags = ['--features=features']
+
+ FINAL_TARGET_FILES.chrome.chrome.content += [
+ '!%s' % built_in_addons,
+ ]
+
EXTRA_COMPONENTS += [
'addonManager.js',
'amContentHandler.js',
diff --git a/tools/code-coverage/PerTestCoverageUtils.jsm b/tools/code-coverage/PerTestCoverageUtils.jsm
index c804aaa89b00..b82b00bd3cad 100644
--- a/tools/code-coverage/PerTestCoverageUtils.jsm
+++ b/tools/code-coverage/PerTestCoverageUtils.jsm
@@ -10,55 +10,66 @@ var EXPORTED_SYMBOLS = ["PerTestCoverageUtils"];
ChromeUtils.defineModuleGetter(this, "Services", "resource://gre/modules/Services.jsm");
-class PerTestCoverageUtilsClass {
- constructor(tmp_gcov_dir, gcov_dir) {
- this.tmp_gcov_dir = tmp_gcov_dir;
- this.gcov_dir = gcov_dir;
-
- this.codeCoverageService = Cc["@mozilla.org/tools/code-coverage;1"].getService(Ci.nsICodeCoverage);
- }
-
- _awaitPromise(promise) {
- let ret;
- let complete = false;
- let error = null;
- promise.catch(e => error = e).then(v => {
- ret = v;
- complete = true;
- });
- Services.tm.spinEventLoopUntil(() => complete);
- if (error) {
- throw new Error(error);
- }
- return ret;
- }
-
- // Resets the counters to 0.
- beforeTest() {
- this._awaitPromise(this.codeCoverageService.resetCounters());
- }
-
- // Dumps counters and moves the gcda files in the directory expected by codecoverage.py.
- afterTest() {
- this._awaitPromise(this.codeCoverageService.dumpCounters());
-
- let srcDir = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
- srcDir.initWithPath(this.tmp_gcov_dir);
-
- let destDir = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
- destDir.initWithPath(this.gcov_dir);
-
- let srcDirEntries = srcDir.directoryEntries;
- while (srcDirEntries.hasMoreElements()) {
- srcDirEntries.nextFile.moveTo(destDir, null);
- }
- }
-}
-
const env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment);
// This is the directory where gcov is emitting the gcda files.
const tmp_gcov_dir = env.get("GCOV_PREFIX");
// This is the directory where codecoverage.py is expecting to see the gcda files.
const gcov_dir = env.get("GCOV_RESULTS_DIR");
-const PerTestCoverageUtils = gcov_dir ? new PerTestCoverageUtilsClass(tmp_gcov_dir, gcov_dir) : null;
+const enabled = !!gcov_dir;
+
+function awaitPromise(promise) {
+ let ret;
+ let complete = false;
+ let error = null;
+ promise.catch(e => error = e).then(v => {
+ ret = v;
+ complete = true;
+ });
+ Services.tm.spinEventLoopUntil(() => complete);
+ if (error) {
+ throw new Error(error);
+ }
+ return ret;
+}
+
+var PerTestCoverageUtils = class PerTestCoverageUtilsClass {
+ // Resets the counters to 0.
+ static async beforeTest() {
+ if (!enabled) {
+ return;
+ }
+
+ let codeCoverageService = Cc["@mozilla.org/tools/code-coverage;1"].getService(Ci.nsICodeCoverage);
+ await codeCoverageService.resetCounters();
+ }
+
+ static beforeTestSync() {
+ awaitPromise(this.beforeTest());
+ }
+
+ // Dumps counters and moves the gcda files in the directory expected by codecoverage.py.
+ static async afterTest() {
+ if (!enabled) {
+ return;
+ }
+
+ let codeCoverageService = Cc["@mozilla.org/tools/code-coverage;1"].getService(Ci.nsICodeCoverage);
+ await codeCoverageService.dumpCounters();
+
+ let srcDir = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
+ srcDir.initWithPath(tmp_gcov_dir);
+
+ let destDir = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
+ destDir.initWithPath(gcov_dir);
+
+ let srcDirEntries = srcDir.directoryEntries;
+ while (srcDirEntries.hasMoreElements()) {
+ srcDirEntries.nextFile.moveTo(destDir, null);
+ }
+ }
+
+ static afterTestSync() {
+ awaitPromise(this.afterTest());
+ }
+};
diff --git a/tools/code-coverage/moz.build b/tools/code-coverage/moz.build
index d66699a740a1..103899924b43 100644
--- a/tools/code-coverage/moz.build
+++ b/tools/code-coverage/moz.build
@@ -4,6 +4,8 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+TESTING_JS_MODULES += ['PerTestCoverageUtils.jsm']
+
if CONFIG['MOZ_CODE_COVERAGE']:
XPIDL_MODULE = 'code-coverage'
@@ -31,6 +33,4 @@ if CONFIG['MOZ_CODE_COVERAGE']:
XPCSHELL_TESTS_MANIFESTS += ['tests/xpcshell/xpcshell.ini']
MOCHITEST_MANIFESTS += ['tests/mochitest/mochitest.ini']
- TESTING_JS_MODULES += ['PerTestCoverageUtils.jsm']
-
FINAL_LIBRARY = 'xul'
diff --git a/tools/code-coverage/tests/xpcshell/test_basic.js b/tools/code-coverage/tests/xpcshell/test_basic.js
index 5fe36a5948b7..f584ed30fb08 100644
--- a/tools/code-coverage/tests/xpcshell/test_basic.js
+++ b/tools/code-coverage/tests/xpcshell/test_basic.js
@@ -2,7 +2,9 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-function run_test() {
+async function run_test() {
+ do_test_pending();
+
Assert.ok("@mozilla.org/tools/code-coverage;1" in Cc);
let codeCoverageCc = Cc["@mozilla.org/tools/code-coverage;1"];
@@ -11,7 +13,9 @@ function run_test() {
let codeCoverage = codeCoverageCc.getService(Ci.nsICodeCoverage);
Assert.ok(!!codeCoverage);
- codeCoverage.dumpCounters();
+ await codeCoverage.dumpCounters();
- codeCoverage.resetCounters();
+ await codeCoverage.resetCounters();
+
+ do_test_finished();
}
diff --git a/tools/code-coverage/tests/xpcshell/test_basic_child_and_parent.js b/tools/code-coverage/tests/xpcshell/test_basic_child_and_parent.js
index 88161f197c9b..8cac17844b71 100644
--- a/tools/code-coverage/tests/xpcshell/test_basic_child_and_parent.js
+++ b/tools/code-coverage/tests/xpcshell/test_basic_child_and_parent.js
@@ -6,11 +6,11 @@ function run_test() {
do_load_child_test_harness();
do_test_pending();
- sendCommand("let v = 'test';", function() {
+ sendCommand("let v = 'test';", async function() {
let codeCoverage = Cc["@mozilla.org/tools/code-coverage;1"].getService(Ci.nsICodeCoverage);
- codeCoverage.dumpCounters();
- codeCoverage.resetCounters();
+ await codeCoverage.dumpCounters();
+ await codeCoverage.resetCounters();
do_test_finished();
});
diff --git a/widget/cocoa/nsCocoaFeatures.h b/widget/cocoa/nsCocoaFeatures.h
index a6a60e26bbdb..c823a5f55463 100644
--- a/widget/cocoa/nsCocoaFeatures.h
+++ b/widget/cocoa/nsCocoaFeatures.h
@@ -20,9 +20,10 @@ public:
static int32_t OSXVersionBugFix();
static bool OnYosemiteOrLater();
static bool OnElCapitanOrLater();
+ static bool OnSierraExactly();
static bool OnSierraOrLater();
static bool OnHighSierraOrLater();
- static bool OnSierraExactly();
+ static bool OnMojaveOrLater();
static bool IsAtLeastVersion(int32_t aMajor, int32_t aMinor, int32_t aBugFix=0);
diff --git a/widget/cocoa/nsCocoaFeatures.mm b/widget/cocoa/nsCocoaFeatures.mm
index 17e33d342242..1022264a7d05 100644
--- a/widget/cocoa/nsCocoaFeatures.mm
+++ b/widget/cocoa/nsCocoaFeatures.mm
@@ -20,6 +20,7 @@
#define MAC_OS_X_VERSION_10_11_HEX 0x000010B0
#define MAC_OS_X_VERSION_10_12_HEX 0x000010C0
#define MAC_OS_X_VERSION_10_13_HEX 0x000010D0
+#define MAC_OS_X_VERSION_10_14_HEX 0x000010E0
#include "nsCocoaFeatures.h"
#include "nsCocoaUtils.h"
@@ -162,18 +163,6 @@ nsCocoaFeatures::OnElCapitanOrLater()
return (OSXVersion() >= MAC_OS_X_VERSION_10_11_HEX);
}
-/* static */ bool
-nsCocoaFeatures::OnSierraOrLater()
-{
- return (OSXVersion() >= MAC_OS_X_VERSION_10_12_HEX);
-}
-
-/* static */ bool
-nsCocoaFeatures::OnHighSierraOrLater()
-{
- return (OSXVersion() >= MAC_OS_X_VERSION_10_13_HEX);
-}
-
/* static */ bool
nsCocoaFeatures::OnSierraExactly()
{
@@ -188,12 +177,30 @@ Gecko_OnSierraExactly()
return nsCocoaFeatures::OnSierraExactly();
}
+/* static */ bool
+nsCocoaFeatures::OnSierraOrLater()
+{
+ return (OSXVersion() >= MAC_OS_X_VERSION_10_12_HEX);
+}
+
+/* static */ bool
+nsCocoaFeatures::OnHighSierraOrLater()
+{
+ return (OSXVersion() >= MAC_OS_X_VERSION_10_13_HEX);
+}
+
bool
Gecko_OnHighSierraOrLater()
{
return nsCocoaFeatures::OnHighSierraOrLater();
}
+/* static */ bool
+nsCocoaFeatures::OnMojaveOrLater()
+{
+ return (OSXVersion() >= MAC_OS_X_VERSION_10_14_HEX);
+}
+
/* static */ bool
nsCocoaFeatures::IsAtLeastVersion(int32_t aMajor, int32_t aMinor, int32_t aBugFix)
{
diff --git a/widget/cocoa/nsLookAndFeel.mm b/widget/cocoa/nsLookAndFeel.mm
index 3d88ae779d80..0291396795cb 100644
--- a/widget/cocoa/nsLookAndFeel.mm
+++ b/widget/cocoa/nsLookAndFeel.mm
@@ -594,10 +594,13 @@ bool nsLookAndFeel::AllowOverlayScrollbarsOverlap()
bool nsLookAndFeel::SystemWantsDarkTheme()
{
- // This returns true if the macOS system appearance is set to dark mode, false
- // otherwise.
- return !![[NSUserDefaults standardUserDefaults]
- stringForKey:@"AppleInterfaceStyle"];
+ // This returns true if the macOS system appearance is set to dark mode on
+ // 10.14+, false otherwise.
+ if (nsCocoaFeatures::OnMojaveOrLater()) {
+ return !![[NSUserDefaults standardUserDefaults]
+ stringForKey:@"AppleInterfaceStyle"];
+ }
+ return false;
}
bool