merge mozilla-inbound to mozilla-central. r=merge a=merge

MozReview-Commit-ID: 4EWdTlEncz7
This commit is contained in:
Sebastian Hengst 2017-07-22 11:38:42 +02:00
commit f16a7f8371
172 changed files with 7210 additions and 3843 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -29870,6 +29870,10 @@ return /******/ (function(modules) { // webpackBootstrap
/* 900 */
/***/ function(module, exports, __webpack_require__) {
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const networkRequest = __webpack_require__(901);
const workerUtils = __webpack_require__(902);
@ -29882,6 +29886,10 @@ return /******/ (function(modules) { // webpackBootstrap
/* 901 */
/***/ function(module, exports) {
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
function networkRequest(url, opts) {
return new Promise((resolve, reject) => {
const req = new XMLHttpRequest();
@ -29891,7 +29899,7 @@ return /******/ (function(modules) { // webpackBootstrap
if (req.status === 200) {
resolve({ content: req.responseText });
} else {
resolve(req.statusText);
reject(req.statusText);
}
}
});
@ -29921,7 +29929,9 @@ return /******/ (function(modules) { // webpackBootstrap
function WorkerDispatcher() {
this.msgId = 1;
this.worker = null;
}
} /* 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/. */
WorkerDispatcher.prototype = {
start(url) {
@ -29952,7 +29962,6 @@ return /******/ (function(modules) { // webpackBootstrap
}
this.worker.removeEventListener("message", listener);
if (result.error) {
reject(result.error);
} else {
@ -30070,6 +30079,7 @@ return /******/ (function(modules) { // webpackBootstrap
getClosestExpression: _closest.getClosestExpression,
getOutOfScopeLocations: _getOutOfScopeLocations2.default,
getSymbols: _getSymbols2.default,
clearSymbols: _getSymbols.clearSymbols,
getVariablesInScope: _scopes.getVariablesInScope
});
@ -30473,6 +30483,8 @@ return /******/ (function(modules) { // webpackBootstrap
value: true
});
exports.default = getSymbols;
exports.formatSymbols = formatSymbols;
exports.clearSymbols = clearSymbols;
var _ast = __webpack_require__(1051);
@ -30519,26 +30531,32 @@ return /******/ (function(modules) { // webpackBootstrap
}));
}
function getSymbols(source) {
if (symbolDeclarations.has(source.id)) {
var _symbols = symbolDeclarations.get(source.id);
if (_symbols) {
return _symbols;
}
function getComments(ast) {
if (!ast || !ast.comments) {
return [];
}
return ast.comments.map(comment => ({
name: comment.location,
location: comment.loc
}));
}
var symbols = { functions: [], variables: [] };
function extractSymbols(source) {
var functions = [];
var variables = [];
var memberExpressions = [];
var callExpressions = [];
var objectProperties = [];
var identifiers = [];
(0, _ast.traverseAst)(source, {
var ast = (0, _ast.traverseAst)(source, {
enter(path) {
if ((0, _helpers.isVariable)(path)) {
var _symbols$variables;
(_symbols$variables = symbols.variables).push.apply(_symbols$variables, _toConsumableArray(getVariableNames(path)));
variables.push.apply(variables, _toConsumableArray(getVariableNames(path)));
}
if ((0, _helpers.isFunction)(path)) {
symbols.functions.push({
functions.push({
name: (0, _getFunctionName2.default)(path),
location: path.node.loc,
parameterNames: getFunctionParameterNames(path),
@ -30547,18 +30565,291 @@ return /******/ (function(modules) { // webpackBootstrap
}
if (t.isClassDeclaration(path)) {
symbols.variables.push({
variables.push({
name: path.node.id.name,
location: path.node.loc
});
}
if (t.isObjectProperty(path)) {
var _path$node$key$loc = path.node.key.loc,
start = _path$node$key$loc.start,
end = _path$node$key$loc.end,
identifierName = _path$node$key$loc.identifierName;
objectProperties.push({
name: identifierName,
location: { start, end },
expression: getSnippet(path)
});
}
if (t.isMemberExpression(path)) {
var _path$node$property$l = path.node.property.loc,
_start = _path$node$property$l.start,
_end = _path$node$property$l.end;
memberExpressions.push({
name: path.node.property.name,
location: { start: _start, end: _end },
expressionLocation: path.node.loc,
expression: getSnippet(path)
});
}
if (t.isCallExpression(path)) {
var callee = path.node.callee;
if (!t.isMemberExpression(callee)) {
var _callee$loc = callee.loc,
_start2 = _callee$loc.start,
_end2 = _callee$loc.end,
_identifierName = _callee$loc.identifierName;
callExpressions.push({
name: _identifierName,
location: { start: _start2, end: _end2 }
});
}
}
if (t.isIdentifier(path)) {
var _path$node$loc = path.node.loc,
_start3 = _path$node$loc.start,
_end3 = _path$node$loc.end;
identifiers.push({
name: path.node.name,
expression: path.node.name,
location: { start: _start3, end: _end3 }
});
}
if (t.isThisExpression(path.node)) {
var _path$node$loc2 = path.node.loc,
_start4 = _path$node$loc2.start,
_end4 = _path$node$loc2.end;
identifiers.push({
name: "this",
location: { start: _start4, end: _end4 },
expressionLocation: path.node.loc,
expression: "this"
});
}
if (t.isVariableDeclarator(path)) {
var node = path.node.id;
var _path$node$loc3 = path.node.loc,
_start5 = _path$node$loc3.start,
_end5 = _path$node$loc3.end;
identifiers.push({
name: node.name,
expression: node.name,
location: { start: _start5, end: _end5 }
});
}
}
});
// comments are extracted separately from the AST
var comments = getComments(ast);
return {
functions,
variables,
callExpressions,
memberExpressions,
objectProperties,
comments,
identifiers
};
}
function getSymbols(source) {
if (symbolDeclarations.has(source.id)) {
var _symbols = symbolDeclarations.get(source.id);
if (_symbols) {
return _symbols;
}
}
var symbols = extractSymbols(source);
symbolDeclarations.set(source.id, symbols);
return symbols;
}
function extendSnippet(name, expression, path, prevPath) {
var computed = path && path.node.computed;
var prevComputed = prevPath && prevPath.node.computed;
var prevArray = t.isArrayExpression(prevPath);
var array = t.isArrayExpression(path);
if (expression === "") {
if (computed) {
return `[${name}]`;
}
return name;
}
if (computed || array) {
if (prevComputed || prevArray) {
return `[${name}]${expression}`;
}
return `[${name}].${expression}`;
}
if (prevComputed || prevArray) {
return `${name}${expression}`;
}
return `${name}.${expression}`;
}
function getMemberSnippet(node) {
var expression = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "";
if (t.isMemberExpression(node)) {
var _name = node.property.name;
return getMemberSnippet(node.object, extendSnippet(_name, expression));
}
if (t.isCallExpression(node)) {
return "";
}
if (t.isThisExpression(node)) {
return `this.${expression}`;
}
if (t.isIdentifier(node)) {
return `${node.name}.${expression}`;
}
return expression;
}
function getObjectSnippet(path, prevPath) {
var expression = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : "";
if (!path) {
return expression;
}
var name = path.node.key.name;
var extendedExpression = extendSnippet(name, expression, path, prevPath);
var nextPrevPath = path;
var nextPath = path.parentPath && path.parentPath.parentPath;
return getSnippet(nextPath, nextPrevPath, extendedExpression);
}
function getArraySnippet(path, prevPath, expression) {
var index = prevPath.parentPath.key;
var extendedExpression = extendSnippet(index, expression, path, prevPath);
var nextPrevPath = path;
var nextPath = path.parentPath && path.parentPath.parentPath;
return getSnippet(nextPath, nextPrevPath, extendedExpression);
}
function getSnippet(path, prevPath) {
var expression = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : "";
if (t.isVariableDeclaration(path)) {
var node = path.node.declarations[0];
var _name2 = node.id.name;
return extendSnippet(_name2, expression, path, prevPath);
}
if (t.isVariableDeclarator(path)) {
var _node = path.node.id;
if (t.isObjectPattern(_node)) {
return expression;
}
var _name3 = _node.name;
var prop = extendSnippet(_name3, expression, path, prevPath);
return prop;
}
if (t.isAssignmentExpression(path)) {
var _node2 = path.node.left;
var _name4 = t.isMemberExpression(_node2) ? getMemberSnippet(_node2) : _node2.name;
var _prop = extendSnippet(_name4, expression, path, prevPath);
return _prop;
}
if ((0, _helpers.isFunction)(path)) {
return expression;
}
if (t.isIdentifier(path)) {
var _node3 = path.node;
return `${_node3.name}.${expression}`;
}
if (t.isObjectProperty(path)) {
return getObjectSnippet(path, prevPath, expression);
}
if (t.isObjectExpression(path)) {
var parentPath = prevPath && prevPath.parentPath;
return getObjectSnippet(parentPath, prevPath, expression);
}
if (t.isMemberExpression(path)) {
return getMemberSnippet(path.node, expression);
}
if (t.isArrayExpression(path)) {
return getArraySnippet(path, prevPath, expression);
}
}
function formatSymbols(source) {
var _getSymbols = getSymbols(source),
objectProperties = _getSymbols.objectProperties,
memberExpressions = _getSymbols.memberExpressions,
callExpressions = _getSymbols.callExpressions,
identifiers = _getSymbols.identifiers,
variables = _getSymbols.variables;
function formatLocation(loc) {
if (!loc) {
return "";
}
var start = loc.start,
end = loc.end;
var startLoc = `(${start.line}, ${start.column})`;
var endLoc = `(${end.line}, ${end.column})`;
return `[${startLoc}, ${endLoc}]`;
}
function summarize(symbol) {
var loc = formatLocation(symbol.location);
var exprLoc = formatLocation(symbol.expressionLocation);
var params = symbol.parameterNames ? symbol.parameterNames.join(", ") : "";
var expression = symbol.expression || "";
return `${loc} ${exprLoc} ${expression} ${symbol.name} ${params}`;
}
return ["properties", objectProperties.map(summarize).join("\n"), "member expressions", memberExpressions.map(summarize).join("\n"), "call expressions", callExpressions.map(summarize).join("\n"), "identifiers", identifiers.map(summarize).join("\n"), "variables", variables.map(summarize).join("\n")].join("\n");
}
function clearSymbols() {
symbolDeclarations = new Map();
}
/***/ },
/* 1051 */
/***/ function(module, exports, __webpack_require__) {
@ -30621,39 +30912,45 @@ return /******/ (function(modules) { // webpackBootstrap
return ast;
}
function getAst(sourceText) {
if (ASTs.has(sourceText.id)) {
return ASTs.get(sourceText.id);
// Custom parser for parse-script-tags that adapts its input structure to
// our parser's signature
function htmlParser(_ref) {
var source = _ref.source,
line = _ref.line;
return parse(source, {
startLine: line
});
}
function getAst(source) {
if (!source || !source.text) {
return {};
}
if (ASTs.has(source.id)) {
return ASTs.get(source.id);
}
var ast = {};
if (sourceText.contentType == "text/html") {
// Custom parser for parse-script-tags that adapts its input structure to
// our parser's signature
var parser = (_ref) => {
var source = _ref.source,
line = _ref.line;
return parse(source, {
startLine: line
});
};
ast = (0, _parseScriptTags2.default)(sourceText.text, parser) || {};
} else if (sourceText.contentType == "text/javascript") {
ast = parse(sourceText.text);
if (source.contentType == "text/html") {
ast = (0, _parseScriptTags2.default)(source.text, htmlParser) || {};
} else if (source.contentType == "text/javascript") {
ast = parse(source.text);
}
ASTs.set(sourceText.id, ast);
ASTs.set(source.id, ast);
return ast;
}
function traverseAst(sourceText, visitor) {
var ast = getAst(sourceText);
function traverseAst(source, visitor) {
var ast = getAst(source);
if ((0, _isEmpty2.default)(ast)) {
return null;
}
(0, _babelTraverse2.default)(ast, visitor);
return ast;
}
/***/ },
@ -30980,15 +31277,18 @@ return /******/ (function(modules) { // webpackBootstrap
var _helpers = __webpack_require__(1052);
var _getSymbols = __webpack_require__(1050);
var _getSymbols2 = __webpack_require__(1050);
var _getSymbols2 = _interopRequireDefault(_getSymbols);
var _getSymbols3 = _interopRequireDefault(_getSymbols2);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function findFunctions(source) {
var symbols = (0, _getSymbols2.default)(source);
return symbols.functions;
function findSymbols(source) {
var _getSymbols = (0, _getSymbols3.default)(source),
functions = _getSymbols.functions,
comments = _getSymbols.comments;
return { functions, comments };
}
/**
@ -31047,7 +31347,13 @@ return /******/ (function(modules) { // webpackBootstrap
* location.
*/
function getOutOfScopeLocations(source, position) {
return findFunctions(source).map(getLocation).filter(loc => !(0, _helpers.containsPosition)(loc, position)).reduce(removeOverlaps, []).sort(sortByStart);
var _findSymbols = findSymbols(source),
functions = _findSymbols.functions,
comments = _findSymbols.comments;
var commentLocations = comments.map(c => c.location);
return functions.map(getLocation).concat(commentLocations).filter(loc => !(0, _helpers.containsPosition)(loc, position)).reduce(removeOverlaps, []).sort(sortByStart);
}
exports.default = getOutOfScopeLocations;

View File

@ -5838,6 +5838,10 @@ return /******/ (function(modules) { // webpackBootstrap
/***/ 900:
/***/ function(module, exports, __webpack_require__) {
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const networkRequest = __webpack_require__(901);
const workerUtils = __webpack_require__(902);
@ -5851,6 +5855,10 @@ return /******/ (function(modules) { // webpackBootstrap
/***/ 901:
/***/ function(module, exports) {
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
function networkRequest(url, opts) {
return new Promise((resolve, reject) => {
const req = new XMLHttpRequest();
@ -5860,7 +5868,7 @@ return /******/ (function(modules) { // webpackBootstrap
if (req.status === 200) {
resolve({ content: req.responseText });
} else {
resolve(req.statusText);
reject(req.statusText);
}
}
});
@ -5891,7 +5899,9 @@ return /******/ (function(modules) { // webpackBootstrap
function WorkerDispatcher() {
this.msgId = 1;
this.worker = null;
}
} /* 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/. */
WorkerDispatcher.prototype = {
start(url) {
@ -5922,7 +5932,6 @@ return /******/ (function(modules) { // webpackBootstrap
}
this.worker.removeEventListener("message", listener);
if (result.error) {
reject(result.error);
} else {

View File

@ -472,6 +472,10 @@ return /******/ (function(modules) { // webpackBootstrap
/***/ 900:
/***/ function(module, exports, __webpack_require__) {
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const networkRequest = __webpack_require__(901);
const workerUtils = __webpack_require__(902);
@ -485,6 +489,10 @@ return /******/ (function(modules) { // webpackBootstrap
/***/ 901:
/***/ function(module, exports) {
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
function networkRequest(url, opts) {
return new Promise((resolve, reject) => {
const req = new XMLHttpRequest();
@ -494,7 +502,7 @@ return /******/ (function(modules) { // webpackBootstrap
if (req.status === 200) {
resolve({ content: req.responseText });
} else {
resolve(req.statusText);
reject(req.statusText);
}
}
});
@ -525,7 +533,9 @@ return /******/ (function(modules) { // webpackBootstrap
function WorkerDispatcher() {
this.msgId = 1;
this.worker = null;
}
} /* 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/. */
WorkerDispatcher.prototype = {
start(url) {
@ -556,7 +566,6 @@ return /******/ (function(modules) { // webpackBootstrap
}
this.worker.removeEventListener("message", listener);
if (result.error) {
reject(result.error);
} else {
@ -589,7 +598,31 @@ return /******/ (function(modules) { // webpackBootstrap
/***/ },
/***/ 1116:
/***/ 1123:
/***/ function(module, exports, __webpack_require__) {
"use strict";
var _getMatches = __webpack_require__(1173);
var _getMatches2 = _interopRequireDefault(_getMatches);
var _projectSearch = __webpack_require__(1140);
var _projectSearch2 = _interopRequireDefault(_projectSearch);
var _devtoolsUtils = __webpack_require__(900);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var workerHandler = _devtoolsUtils.workerUtils.workerHandler;
self.onmessage = workerHandler({ getMatches: _getMatches2.default, searchSources: _projectSearch2.default });
/***/ },
/***/ 1138:
/***/ function(module, exports, __webpack_require__) {
"use strict";
@ -676,7 +709,65 @@ return /******/ (function(modules) { // webpackBootstrap
/***/ },
/***/ 1123:
/***/ 1140:
/***/ function(module, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.searchSource = searchSource;
exports.default = searchSources;
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
// Maybe reuse file search's functions?
function searchSource(source, queryText) {
var _ref;
var text = source.text,
loading = source.loading;
if (loading || !text || queryText == "") {
return [];
}
var lines = text.split("\n");
var result = undefined;
var query = new RegExp(queryText, "g");
var matches = lines.map((_text, line) => {
var indices = [];
while (result = query.exec(_text)) {
indices.push({
line: line + 1,
column: result.index,
match: result[0],
value: _text,
text: result.input
});
}
return indices;
}).filter(_matches => _matches.length > 0);
matches = (_ref = []).concat.apply(_ref, _toConsumableArray(matches));
return matches;
}
function searchSources(query, sources) {
var validSources = sources.valueSeq().filter(s => s.has("text")).toJS();
return validSources.map(source => ({
source,
filepath: source.url,
matches: searchSource(source, query)
}));
}
/***/ },
/***/ 1173:
/***/ function(module, exports, __webpack_require__) {
"use strict";
@ -684,27 +775,29 @@ return /******/ (function(modules) { // webpackBootstrap
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.countMatches = countMatches;
exports.default = getMatches;
var _buildQuery = __webpack_require__(1116);
var _buildQuery = __webpack_require__(1138);
var _buildQuery2 = _interopRequireDefault(_buildQuery);
var _devtoolsUtils = __webpack_require__(900);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var workerHandler = _devtoolsUtils.workerUtils.workerHandler;
function countMatches(query, text, modifiers) {
function getMatches(query, text, modifiers) {
var regexQuery = (0, _buildQuery2.default)(query, modifiers, {
isGlobal: true
});
var match = text.match(regexQuery);
return match ? match.length : 0;
var matchedLocations = [];
var lines = text.split("\n");
for (var i = 0; i < lines.length; i++) {
var singleMatch = void 0;
while ((singleMatch = regexQuery.exec(lines[i])) !== null) {
matchedLocations.push({ line: i, ch: singleMatch.index });
}
}
return matchedLocations;
}
self.onmessage = workerHandler({ countMatches });
/***/ }
/******/ })

View File

@ -5,7 +5,11 @@
// initializes and it properly highlights the right location in the
// debugger.
add_task(function* () {
async function waitOnToolbox(toolbox, event) {
return new Promise(resolve => toolbox.on(event, resolve));
}
add_task(function*() {
const url = EXAMPLE_URL + "doc-script-switching.html";
const toolbox = yield openNewTabAndToolbox(url, "webconsole");
@ -14,9 +18,7 @@ add_task(function* () {
jsterm.execute("debugger");
// Wait for the debugger to be selected and make sure it's paused
yield new Promise((resolve) => {
toolbox.on("jsdebugger-selected", resolve);
});
yield waitOnToolbox(toolbox, "jsdebugger-selected");
is(toolbox.threadClient.state, "paused");
// Create a dbg context

View File

@ -46,6 +46,8 @@ add_task(function*() {
clickElement(dbg, "gutter", 5);
yield waitForDispatch(dbg, "ADD_BREAKPOINT");
yield setConditionalBreakpoint(dbg, 5, "1");
yield waitForDispatch(dbg, "SET_BREAKPOINT_CONDITION");
bp = findBreakpoint(dbg, "simple2", 5);
is(bp.condition, "1", "breakpoint is created with the condition");
});

View File

@ -34,6 +34,7 @@ add_task(function*() {
yield reload(dbg, "simple1");
yield waitForSelectedSource(dbg);
yield waitForDispatch(dbg, "SYNC_BREAKPOINT", 2);
assertEditorBreakpoint(dbg, 4);
assertEditorBreakpoint(dbg, 5);
});

View File

@ -29,11 +29,18 @@ function enableBreakpoint(dbg, index) {
});
}
function toggleBreakpoints(dbg) {
return Task.spawn(function*() {
clickElement(dbg, "toggleBreakpoints");
yield waitForDispatch(dbg, "TOGGLE_BREAKPOINTS");
});
function toggleBreakpoints(dbg, count) {
clickElement(dbg, "toggleBreakpoints");
}
function disableBreakpoints(dbg, count) {
toggleBreakpoints(dbg);
return waitForDispatch(dbg, "DISABLE_BREAKPOINT", count);
}
function enableBreakpoints(dbg, count) {
toggleBreakpoints(dbg);
return waitForDispatch(dbg, "ENABLE_BREAKPOINT", count);
}
function findBreakpoint(dbg, url, line) {
@ -79,14 +86,14 @@ add_task(function*() {
yield addBreakpoint(dbg, "simple2", 5);
// Disable all of the breakpoints
yield toggleBreakpoints(dbg);
yield disableBreakpoints(dbg, 2);
let bp1 = findBreakpoint(dbg, "simple2", 3);
let bp2 = findBreakpoint(dbg, "simple2", 5);
is(bp1.disabled, true, "first breakpoint is disabled");
is(bp2.disabled, true, "second breakpoint is disabled");
// Enable all of the breakpoints
yield toggleBreakpoints(dbg);
yield enableBreakpoints(dbg, 2);
bp1 = findBreakpoint(dbg, "simple2", 3);
bp2 = findBreakpoint(dbg, "simple2", 5);
is(bp1.disabled, false, "first breakpoint is enabled");

View File

@ -11,7 +11,7 @@ function isElementVisible(dbg, elementName) {
return bpLine && isVisibleWithin(cm, bpLine);
}
add_task(function* () {
add_task(function*() {
// This test runs too slowly on linux debug. I'd like to figure out
// which is the slowest part of this and make it run faster, but to
// fix a frequent failure allow a longer timeout.

View File

@ -4,6 +4,35 @@
// Tests loading sourcemapped sources, setting breakpoints, and
// stepping in them.
function assertBreakpointExists(dbg, source, line) {
const { selectors: { getBreakpoint }, getState } = dbg;
ok(
getBreakpoint(getState(), { sourceId: source.id, line }),
"Breakpoint has correct line"
);
}
function assertEditorBreakpoint(dbg, line, shouldExist) {
const exists = !!getLineEl(dbg, line).querySelector(".new-breakpoint");
ok(
exists === shouldExist,
"Breakpoint " +
(shouldExist ? "exists" : "does not exist") +
" on line " +
line
);
}
function getLineEl(dbg, line) {
const lines = dbg.win.document.querySelectorAll(".CodeMirror-code > div");
return lines[line - 1];
}
function clickGutter(dbg, line) {
clickElement(dbg, "gutter", line);
}
add_task(function*() {
// NOTE: the CORS call makes the test run times inconsistent
requestLongerTimeout(2);
@ -13,6 +42,18 @@ add_task(function*() {
yield waitForSources(dbg, "entry.js", "output.js", "times2.js", "opts.js");
ok(true, "Original sources exist");
const bundleSrc = findSource(dbg, "bundle.js");
yield selectSource(dbg, bundleSrc);
yield clickGutter(dbg, 13);
yield waitForDispatch(dbg, "ADD_BREAKPOINT");
assertEditorBreakpoint(dbg, 13, true);
yield clickGutter(dbg, 13);
yield waitForDispatch(dbg, "REMOVE_BREAKPOINT");
is(getBreakpoints(getState()).size, 0, "No breakpoints exists");
const entrySrc = findSource(dbg, "entry.js");
yield selectSource(dbg, entrySrc);
@ -25,18 +66,12 @@ add_task(function*() {
// should not move anywhere.
yield addBreakpoint(dbg, entrySrc, 13);
is(getBreakpoints(getState()).size, 1, "One breakpoint exists");
ok(
getBreakpoint(getState(), { sourceId: entrySrc.id, line: 13 }),
"Breakpoint has correct line"
);
assertBreakpointExists(dbg, entrySrc, 13);
// Test breaking on a breakpoint
yield addBreakpoint(dbg, "entry.js", 15);
is(getBreakpoints(getState()).size, 2, "Two breakpoints exist");
ok(
getBreakpoint(getState(), { sourceId: entrySrc.id, line: 15 }),
"Breakpoint has correct line"
);
assertBreakpointExists(dbg, entrySrc, 15);
invokeInTab("keepMeAlive");
yield waitForPaused(dbg);

View File

@ -24,7 +24,7 @@ add_task(function*() {
yield addBreakpoint(dbg, mainSrc, 4);
is(getBreakpoints(getState()).size, 1, "One breakpoint exists");
ok(
getBreakpoint(getState(), { sourceId: mainSrc.id, line: 4 }),
getBreakpoint(getState(), { sourceId: mainSrc.id, line: 4, column: 2 }),
"Breakpoint has correct line"
);

View File

@ -136,6 +136,10 @@ sources.search.key2=CmdOrCtrl+P
# search for searching all the source files the debugger has seen.
sources.search.alt.key=CmdOrCtrl+O
# LOCALIZATION NOTE (projectTextSearch.key): A key shortcut to open the
# full project text search for searching all the files the debugger has seen.
projectTextSearch.key=CmdOrCtrl+Shift+F
# LOCALIZATION NOTE (sources.noSourcesAvailable): Text shown when the debugger
# does not have any sources.
sources.noSourcesAvailable=This page has no sources

View File

@ -37,5 +37,5 @@ pref("devtools.debugger.pending-selected-location", "{}");
pref("devtools.debugger.pending-breakpoints", "{}");
pref("devtools.debugger.expressions", "[]");
pref("devtools.debugger.file-search-case-sensitive", false);
pref("devtools.debugger.file-search-whole-word", false );
pref("devtools.debugger.file-search-whole-word", false);
pref("devtools.debugger.file-search-regex-match", false);

View File

@ -247,8 +247,6 @@ CustomElementRegistry::RegisterUnresolvedElement(Element* aElement, nsIAtom* aTy
nsWeakPtr* elem = unresolved->AppendElement();
*elem = do_GetWeakReference(aElement);
aElement->AddStates(NS_EVENT_STATE_UNRESOLVED);
return;
}
void
@ -773,7 +771,6 @@ CustomElementRegistry::Get(JSContext* aCx, const nsAString& aName,
}
aRetVal.setObject(*data->mConstructor);
return;
}
already_AddRefed<Promise>

View File

@ -114,8 +114,6 @@ NSResultToNameAndMessage(nsresult aNSResult,
}
NS_WARNING("Huh, someone is throwing non-DOM errors using the DOM module!");
return;
}
nsresult

View File

@ -113,7 +113,6 @@ public:
virtual void UnbindFromTree(bool aDeep, bool aNullParent) override
{
NS_ASSERTION(false, "Trying to unbind a fragment from a tree");
return;
}
virtual Element* GetNameSpaceElement() override

View File

@ -1305,7 +1305,6 @@ Element::SetAttribute(const nsAString& aName,
aError = SetAttr(name->NamespaceID(), name->LocalName(), name->GetPrefix(),
aValue, true);
return;
}
void
@ -2726,8 +2725,6 @@ Element::PreIdMaybeChange(int32_t aNamespaceID, nsIAtom* aName,
return;
}
RemoveFromIdTable();
return;
}
void
@ -2746,8 +2743,6 @@ Element::PostIdMaybeChange(int32_t aNamespaceID, nsIAtom* aName,
} else {
ClearHasID();
}
return;
}
EventListenerManager*

View File

@ -41,19 +41,11 @@ NodeInfo::~NodeInfo()
NodeInfo::NodeInfo(nsIAtom *aName, nsIAtom *aPrefix, int32_t aNamespaceID,
uint16_t aNodeType, nsIAtom* aExtraName,
nsNodeInfoManager *aOwnerManager)
: mDocument(aOwnerManager->GetDocument()),
mInner(aName, aPrefix, aNamespaceID, aNodeType, aExtraName),
mOwnerManager(aOwnerManager)
{
CheckValidNodeInfo(aNodeType, aName, aNamespaceID, aExtraName);
MOZ_ASSERT(aOwnerManager, "Invalid aOwnerManager");
// Initialize mInner
mInner.mName = aName;
mInner.mPrefix = aPrefix;
mInner.mNamespaceID = aNamespaceID;
mInner.mNodeType = aNodeType;
mOwnerManager = aOwnerManager;
mInner.mExtraName = aExtraName;
mDocument = aOwnerManager->GetDocument();
// Now compute our cached members.

View File

@ -246,28 +246,33 @@ protected:
public:
NodeInfoInner()
: mName(nullptr), mPrefix(nullptr), mNamespaceID(kNameSpaceID_Unknown),
mNodeType(0), mNameString(nullptr), mExtraName(nullptr)
mNodeType(0), mNameString(nullptr), mExtraName(nullptr),
mHash(0), mHashInitialized(false)
{
}
NodeInfoInner(nsIAtom *aName, nsIAtom *aPrefix, int32_t aNamespaceID,
uint16_t aNodeType, nsIAtom* aExtraName)
: mName(aName), mPrefix(aPrefix), mNamespaceID(aNamespaceID),
mNodeType(aNodeType), mNameString(nullptr), mExtraName(aExtraName)
mNodeType(aNodeType), mNameString(nullptr), mExtraName(aExtraName),
mHash(aName->hash()), mHashInitialized(true)
{
}
NodeInfoInner(const nsAString& aTmpName, nsIAtom *aPrefix,
int32_t aNamespaceID, uint16_t aNodeType)
: mName(nullptr), mPrefix(aPrefix), mNamespaceID(aNamespaceID),
mNodeType(aNodeType), mNameString(&aTmpName), mExtraName(nullptr)
mNodeType(aNodeType), mNameString(&aTmpName), mExtraName(nullptr),
mHash(0), mHashInitialized(false)
{
}
nsCOMPtr<nsIAtom> mName;
const nsCOMPtr<nsIAtom> mName;
nsCOMPtr<nsIAtom> mPrefix;
int32_t mNamespaceID;
uint16_t mNodeType; // As defined by nsIDOMNode.nodeType
const nsAString* mNameString;
const nsAString* const mNameString;
nsCOMPtr<nsIAtom> mExtraName; // Only used by PIs and DocTypes
PLHashNumber mHash;
bool mHashInitialized;
};
// nsNodeInfoManager needs to pass mInner to the hash table.

View File

@ -1303,7 +1303,7 @@ nsAttrValue::ParseAtomArray(const nsAString& aValue)
AtomArray* array = GetAtomArrayValue();
if (!array->AppendElement(classAtom)) {
if (!array->AppendElement(Move(classAtom))) {
Reset();
return;
}
@ -1318,7 +1318,7 @@ nsAttrValue::ParseAtomArray(const nsAString& aValue)
classAtom = NS_AtomizeMainThread(Substring(start, iter));
if (!array->AppendElement(classAtom)) {
if (!array->AppendElement(Move(classAtom))) {
Reset();
return;
}
@ -1330,7 +1330,6 @@ nsAttrValue::ParseAtomArray(const nsAString& aValue)
}
SetMiscAtomOrString(&aValue);
return;
}
void

View File

@ -4895,7 +4895,6 @@ nsGlobalWindow::GetContentOuter(JSContext* aCx,
}
aRetval.set(nullptr);
return;
}
void

View File

@ -44,9 +44,14 @@ nsNodeInfoManager::GetNodeInfoInnerHashValue(const void *key)
{
MOZ_ASSERT(key, "Null key passed to NodeInfo::GetHashValue!");
auto *node = reinterpret_cast<const NodeInfo::NodeInfoInner*>(key);
auto *node = const_cast<NodeInfo::NodeInfoInner*>
(reinterpret_cast<const NodeInfo::NodeInfoInner*>(key));
if (!node->mHashInitialized) {
node->mHash = node->mName ? node->mName->hash() : HashString(*(node->mNameString));
node->mHashInitialized = true;
}
return node->mName ? node->mName->hash() : HashString(*(node->mNameString));
return node->mHash;
}

View File

@ -208,7 +208,6 @@ WebGLContext::GetQuery(JSContext* cx, GLenum target, GLenum pname,
}
ErrorInvalidEnum("%s: Bad pname.", funcName);
return;
}
void

View File

@ -219,7 +219,6 @@ class WebGLImageConverter
}
mSuccess = true;
return;
}
template<WebGLTexelFormat SrcFormat,

View File

@ -16,6 +16,7 @@
#include "mozilla/TextComposition.h"
#include "mozilla/TextEvents.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/Selection.h"
#include "nsContentUtils.h"
#include "nsGkAtoms.h"
#include "nsIAtom.h"
@ -333,10 +334,9 @@ IMEContentObserver::InitWithEditor(nsPresContext* aPresContext,
return false;
}
nsCOMPtr<nsIDOMRange> selDomRange;
if (NS_SUCCEEDED(mSelection->GetRangeAt(0, getter_AddRefs(selDomRange)))) {
nsRange* selRange = static_cast<nsRange*>(selDomRange.get());
if (NS_WARN_IF(!selRange) || NS_WARN_IF(!selRange->GetStartContainer())) {
auto selection = static_cast<mozilla::dom::Selection*>(mSelection.get());
if (nsRange* selRange = selection->GetRangeAt(0)) {
if (NS_WARN_IF(!selRange->GetStartContainer())) {
return false;
}

View File

@ -345,8 +345,6 @@ HTMLFieldSetElement::UpdateValidity(bool aElementValidity)
if (mFieldSet) {
mFieldSet->UpdateValidity(aElementValidity);
}
return;
}
EventStates

View File

@ -3418,7 +3418,6 @@ HTMLInputElement::Focus(ErrorResult& aError)
}
}
return;
}
#if !defined(ANDROID) && !defined(XP_MACOSX)

View File

@ -494,8 +494,6 @@ HTMLLinkElement::GetStyleSheetInfo(nsAString& aTitle,
// If we get here we assume that we're loading a css file, so set the
// type to 'text/css'
aType.AssignLiteral("text/css");
return;
}
CORSMode

View File

@ -296,10 +296,8 @@ nsHTMLDocument::TryHintCharset(nsIContentViewer* aCv,
aCharsetSource = requestCharsetSource;
aEncoding = WrapNotNull(requestCharset);
}
return;
}
}
return;
}
@ -836,7 +834,6 @@ nsHTMLDocument::StopDocumentLoad()
nsDocument::StopDocumentLoad();
UnblockOnload(false);
return;
}
void

View File

@ -791,8 +791,6 @@ nsJSChannel::EvaluateScript()
} else if (mIsAsync) {
NotifyListener();
}
return;
}
void

View File

@ -2541,7 +2541,6 @@ MediaFormatReader::SkipVideoDemuxToNextKeyFrame(TimeUnit aTimeThreshold)
&MediaFormatReader::OnVideoSkipCompleted,
&MediaFormatReader::OnVideoSkipFailed)
->Track(mSkipRequest);
return;
}
void

View File

@ -1418,9 +1418,7 @@ MediaRecorder::NotifyError(nsresult aRv)
rv = DispatchDOMEvent(nullptr, event, nullptr, nullptr);
if (NS_FAILED(rv)) {
NS_ERROR("Failed to dispatch the error event!!!");
return;
}
return;
}
void

View File

@ -123,7 +123,6 @@ TestOuputProtectionAPIs()
{
RunOutputProtectionAPITests();
FakeDecryptor::Message("OP tests completed");
return;
}
} // namespace gmptest

View File

@ -840,7 +840,6 @@ TrackBuffersManager::CreateDemuxerforMIMEType()
}
#endif
NS_WARNING("Not supported (yet)");
return;
}
// We reset the demuxer by creating a new one and initializing it.

View File

@ -103,14 +103,12 @@ public:
if (aChannelCount != ChannelCount()) {
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
}
return;
}
void SetChannelCountModeValue(ChannelCountMode aMode, ErrorResult& aRv) override
{
if (aMode != ChannelCountMode::Explicit) {
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
}
return;
}
uint32_t BufferSize() const

View File

@ -58,14 +58,12 @@ void
MediaEngineDefaultVideoSource::GetName(nsAString& aName) const
{
aName.AssignLiteral(u"Default Video Device");
return;
}
void
MediaEngineDefaultVideoSource::GetUUID(nsACString& aUUID) const
{
aUUID.AssignLiteral("1041FCBD-3F12-4F7B-9E9B-1EC556DD5676");
return;
}
uint32_t
@ -382,14 +380,12 @@ void
MediaEngineDefaultAudioSource::GetName(nsAString& aName) const
{
aName.AssignLiteral(u"Default Audio Device");
return;
}
void
MediaEngineDefaultAudioSource::GetUUID(nsACString& aUUID) const
{
aUUID.AssignLiteral("B7CBD7C1-53EF-42F9-8353-73F61C70C092");
return;
}
uint32_t
@ -533,8 +529,6 @@ MediaEngineDefault::EnumerateVideoDevices(dom::MediaSourceEnum aMediaSource,
RefPtr<MediaEngineVideoSource> newSource = new MediaEngineDefaultVideoSource();
mVSources.AppendElement(newSource);
aVSources->AppendElement(newSource);
return;
}
void
@ -559,7 +553,6 @@ MediaEngineDefault::EnumerateAudioDevices(dom::MediaSourceEnum aMediaSource,
mASources.AppendElement(newSource);
aASources->AppendElement(newSource);
}
return;
}
} // namespace mozilla

View File

@ -61,8 +61,6 @@ MediaEngineRemoteVideoSource::Init()
SetUUID(uniqueId);
mInitDone = true;
return;
}
void
@ -99,7 +97,6 @@ MediaEngineRemoteVideoSource::Shutdown()
MOZ_ASSERT(mState == kReleased);
mInitDone = false;
return;
}
nsresult

View File

@ -209,14 +209,12 @@ void
MediaEngineWebRTCMicrophoneSource::GetName(nsAString& aName) const
{
aName.Assign(mDeviceName);
return;
}
void
MediaEngineWebRTCMicrophoneSource::GetUUID(nsACString& aUUID) const
{
aUUID.Assign(mDeviceUUID);
return;
}
// GetBestFitnessDistance returns the best distance the capture device can offer
@ -942,7 +940,6 @@ MediaEngineWebRTCMicrophoneSource::Process(int channel,
uint32_t channels = isStereo ? 2 : 1;
InsertInGraph<int16_t>(audio10ms, length, channels);
return;
}
void

View File

@ -53,14 +53,12 @@ void
SpeechGrammar::GetSrc(nsString& aRetVal, ErrorResult& aRv) const
{
aRetVal = mSrc;
return;
}
void
SpeechGrammar::SetSrc(const nsAString& aArg, ErrorResult& aRv)
{
mSrc = aArg;
return;
}
float
@ -74,7 +72,6 @@ void
SpeechGrammar::SetWeight(float aArg, ErrorResult& aRv)
{
aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
return;
}
} // namespace dom

View File

@ -71,7 +71,6 @@ SpeechGrammarList::AddFromURI(const nsAString& aSrc,
ErrorResult& aRv)
{
aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
return;
}
void
@ -82,7 +81,6 @@ SpeechGrammarList::AddFromString(const nsAString& aString,
SpeechGrammar* speechGrammar = new SpeechGrammar(mParent);
speechGrammar->SetSrc(aString, aRv);
mItems.AppendElement(speechGrammar);
return;
}
already_AddRefed<SpeechGrammar>

View File

@ -147,7 +147,6 @@ SpeechRecognition::SetState(FSMState state)
{
mCurrentState = state;
SR_LOG("Transitioned to state %s", GetName(mCurrentState));
return;
}
JSObject*
@ -375,8 +374,6 @@ SpeechRecognition::Transition(SpeechEvent* aEvent)
case STATE_COUNT:
MOZ_CRASH("Invalid state STATE_COUNT");
}
return;
}
/*
@ -559,8 +556,6 @@ SpeechRecognition::NotifyError(SpeechEvent* aEvent)
bool defaultActionEnabled;
this->DispatchEvent(aEvent->mError, &defaultActionEnabled);
return;
}
/**************************************
@ -641,8 +636,6 @@ SpeechRecognition::ProcessTestEventRequest(nsISupports* aSubject, const nsAStrin
// let the fake recognition service handle the request
}
return;
}
already_AddRefed<SpeechGrammarList>
@ -681,7 +674,6 @@ void
SpeechRecognition::SetContinuous(bool aArg, ErrorResult& aRv)
{
aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
return;
}
bool
@ -694,7 +686,6 @@ void
SpeechRecognition::SetInterimResults(bool aArg)
{
mInterimResults = aArg;
return;
}
uint32_t
@ -707,21 +698,18 @@ void
SpeechRecognition::SetMaxAlternatives(uint32_t aArg)
{
mMaxAlternatives = aArg;
return;
}
void
SpeechRecognition::GetServiceURI(nsString& aRetVal, ErrorResult& aRv) const
{
aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
return;
}
void
SpeechRecognition::SetServiceURI(const nsAString& aArg, ErrorResult& aRv)
{
aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
return;
}
void
@ -997,8 +985,6 @@ SpeechRecognition::FeedAudioData(already_AddRefed<SharedBuffer> aSamples,
event->mProvider = aProvider;
event->mTrackRate = aTrackRate;
NS_DispatchToMainThread(event);
return;
}
const char*

View File

@ -182,8 +182,6 @@ SpeechSynthesis::AdvanceQueue()
if (mCurrentTask) {
mCurrentTask->SetSpeechSynthesis(this);
}
return;
}
void

View File

@ -658,7 +658,6 @@ nsPluginStreamListenerPeer::MakeByteRangeString(NPByteRange* aRangeList, nsACStr
rangeRequest = string;
*numRequests = requestCnt;
return;
}
// XXX: Converting the channel within nsPluginStreamListenerPeer

View File

@ -162,7 +162,6 @@ BrowserStreamParent::StreamAsFile(const char* fname)
}
Unused << SendNPP_StreamAsFile(nsCString(fname));
return;
}
} // namespace plugins

View File

@ -2403,7 +2403,6 @@ PluginModuleChild::NPN_ReleaseObject(NPObject* aNPObj)
if (doe)
doe->mDeleted = true;
}
return;
}
void

View File

@ -213,7 +213,6 @@ GetUnitString(nsAString& unit, uint16_t unitType)
return;
}
NS_NOTREACHED("Unknown unit type"); // Someone's using an SVGLength with an invalid unit?
return;
}
static uint16_t

View File

@ -295,8 +295,6 @@ SVGStyleElement::GetStyleSheetInfo(nsAString& aTitle,
*aIsScoped = HasAttr(kNameSpaceID_None, nsGkAtoms::scoped) &&
OwnerDoc()->IsScopedStyleEnabled();
return;
}
CORSMode

View File

@ -59,7 +59,6 @@ GetUnitString(nsAString& unit, uint16_t unitType)
}
NS_NOTREACHED("Unknown unit type");
return;
}
static uint16_t

View File

@ -63,7 +63,6 @@ GetUnitString(nsAString& unit, uint16_t unitType)
}
NS_NOTREACHED("Unknown unit type");
return;
}
static uint16_t

View File

@ -240,6 +240,19 @@ private:
~ExternalRunnableWrapper()
{ }
virtual bool
PreDispatch(WorkerPrivate* aWorkerPrivate) override
{
// Silence bad assertions.
return true;
}
virtual void
PostDispatch(WorkerPrivate* aWorkerPrivate, bool aDispatchResult) override
{
// Silence bad assertions.
}
virtual bool
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
{
@ -884,7 +897,6 @@ private:
override
{
aWorkerPrivate->ModifyBusyCountFromWorker(false);
return;
}
virtual bool
@ -1612,15 +1624,21 @@ public:
nsresult
Cancel() override
{
// First run the default cancelation code
WorkerControlRunnable::Cancel();
// Attempt to cancel the inner runnable as well
nsCOMPtr<nsICancelableRunnable> cr = do_QueryInterface(mInner);
if (cr) {
return cr->Cancel();
// If the inner runnable is not cancellable, then just do the normal
// WorkerControlRunnable thing. This will end up calling Run().
if (!cr) {
WorkerControlRunnable::Cancel();
return NS_OK;
}
return NS_OK;
// Otherwise call the inner runnable's Cancel() and treat this like
// a WorkerRunnable cancel. We can't call WorkerControlRunnable::Cancel()
// in this case since that would result in both Run() and the inner
// Cancel() being called.
Unused << cr->Cancel();
return WorkerRunnable::Cancel();
}
};
@ -1628,17 +1646,36 @@ public:
BEGIN_WORKERS_NAMESPACE
class WorkerControlEventTarget final : public nsIEventTarget
class WorkerEventTarget final : public nsISerialEventTarget
{
public:
// The WorkerEventTarget supports different dispatch behaviors:
//
// * Hybrid targets will attempt to dispatch as a normal runnable,
// but fallback to a control runnable if that fails. This is
// often necessary for code that wants normal dispatch order, but
// also needs to execute while the worker is shutting down (possibly
// with a holder in place.)
//
// * ControlOnly targets will simply dispatch a control runnable.
enum class Behavior : uint8_t {
Hybrid,
ControlOnly
};
private:
mozilla::Mutex mMutex;
WorkerPrivate* mWorkerPrivate;
const Behavior mBehavior;
~WorkerControlEventTarget() = default;
~WorkerEventTarget() = default;
public:
explicit WorkerControlEventTarget(WorkerPrivate* aWorkerPrivate)
: mMutex("WorkerControlEventTarget")
WorkerEventTarget(WorkerPrivate* aWorkerPrivate,
Behavior aBehavior)
: mMutex("WorkerEventTarget")
, mWorkerPrivate(aWorkerPrivate)
, mBehavior(aBehavior)
{
MOZ_DIAGNOSTIC_ASSERT(mWorkerPrivate);
}
@ -1647,7 +1684,7 @@ public:
ForgetWorkerPrivate(WorkerPrivate* aWorkerPrivate)
{
MutexAutoLock lock(mMutex);
MOZ_DIAGNOSTIC_ASSERT(mWorkerPrivate == aWorkerPrivate);
MOZ_DIAGNOSTIC_ASSERT(!mWorkerPrivate || mWorkerPrivate == aWorkerPrivate);
mWorkerPrivate = nullptr;
}
@ -1667,8 +1704,20 @@ public:
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIRunnable> runnable(aRunnable);
if (mBehavior == Behavior::Hybrid) {
RefPtr<WorkerRunnable> r =
mWorkerPrivate->MaybeWrapAsWorkerRunnable(runnable.forget());
if (r->Dispatch()) {
return NS_OK;
}
runnable = r.forget();
}
RefPtr<WorkerControlRunnable> r = new WrappedControlRunnable(mWorkerPrivate,
Move(aRunnable));
runnable.forget());
if (!r->Dispatch()) {
return NS_ERROR_FAILURE;
}
@ -1704,7 +1753,8 @@ public:
NS_DECL_THREADSAFE_ISUPPORTS
};
NS_IMPL_ISUPPORTS(WorkerControlEventTarget, nsIEventTarget)
NS_IMPL_ISUPPORTS(WorkerEventTarget, nsIEventTarget,
nsISerialEventTarget)
END_WORKERS_NAMESPACE
@ -2973,45 +3023,6 @@ WorkerPrivateParent<Derived>::MaybeWrapAsWorkerRunnable(already_AddRefed<nsIRunn
return workerRunnable.forget();
}
template <class Derived>
already_AddRefed<nsISerialEventTarget>
WorkerPrivateParent<Derived>::GetEventTarget()
{
WorkerPrivate* self = ParentAsWorkerPrivate();
nsCOMPtr<nsISerialEventTarget> target;
bool needAutoDisable = false;
{
MutexAutoLock lock(mMutex);
if (!mEventTarget) {
mEventTarget = new EventTarget(self);
// If the worker is already shutting down then we want to
// immediately disable the event target. This will cause
// the Dispatch() method to fail, but the event target
// will still exist.
if (self->mStatus > Running) {
needAutoDisable = true;
}
}
target = mEventTarget;
}
// Make sure to call Disable() outside of the mutex since it
// also internally locks a mutex.
if (needAutoDisable) {
mEventTarget->Disable();
}
MOZ_DIAGNOSTIC_ASSERT(target);
return target.forget();
}
template <class Derived>
bool
WorkerPrivateParent<Derived>::Start()
@ -4425,7 +4436,10 @@ WorkerPrivate::WorkerPrivate(WorkerPrivate* aParent,
, mNumHoldersPreventingShutdownStart(0)
, mDebuggerEventLoopLevel(0)
, mMainThreadEventTarget(GetMainThreadEventTarget())
, mWorkerControlEventTarget(new WorkerControlEventTarget(this))
, mWorkerControlEventTarget(new WorkerEventTarget(this,
WorkerEventTarget::Behavior::ControlOnly))
, mWorkerHybridEventTarget(new WorkerEventTarget(this,
WorkerEventTarget::Behavior::Hybrid))
, mErrorHandlerRecursionCount(0)
, mNextTimeoutId(1)
, mStatus(Pending)
@ -4488,6 +4502,12 @@ WorkerPrivate::WorkerPrivate(WorkerPrivate* aParent,
WorkerPrivate::~WorkerPrivate()
{
mWorkerControlEventTarget->ForgetWorkerPrivate(this);
// We force the hybrid event target to forget the thread when we
// enter the Killing state, but we do it again here to be safe.
// Its possible that we may be created and destroyed without progressing
// to Killing via some obscure code path.
mWorkerHybridEventTarget->ForgetWorkerPrivate(this);
}
// static
@ -5050,7 +5070,7 @@ WorkerPrivate::DoRunLoop(JSContext* aCx)
// After mStatus is set to Dead there can be no more
// WorkerControlRunnables so no need to lock here.
if (!mControlQueue.IsEmpty()) {
WorkerControlRunnable* runnable;
WorkerControlRunnable* runnable = nullptr;
while (mControlQueue.Pop(runnable)) {
runnable->Cancel();
runnable->Release();
@ -5071,7 +5091,7 @@ WorkerPrivate::DoRunLoop(JSContext* aCx)
}
if (debuggerRunnablesPending) {
WorkerRunnable* runnable;
WorkerRunnable* runnable = nullptr;
{
MutexAutoLock lock(mMutex);
@ -5189,12 +5209,18 @@ WorkerPrivate::DispatchToMainThread(already_AddRefed<nsIRunnable> aRunnable,
return mMainThreadEventTarget->Dispatch(runnable.forget(), aFlags);
}
nsIEventTarget*
nsISerialEventTarget*
WorkerPrivate::ControlEventTarget()
{
return mWorkerControlEventTarget;
}
nsISerialEventTarget*
WorkerPrivate::HybridEventTarget()
{
return mWorkerHybridEventTarget;
}
void
WorkerPrivate::InitializeGCTimers()
{
@ -5520,7 +5546,7 @@ void
WorkerPrivate::ClearDebuggerEventQueue()
{
while (!mDebuggerQueue.IsEmpty()) {
WorkerRunnable* runnable;
WorkerRunnable* runnable = nullptr;
mDebuggerQueue.Pop(runnable);
// It should be ok to simply release the runnable, without running it.
runnable->Release();
@ -6070,7 +6096,7 @@ WorkerPrivate::EnterDebuggerEventLoop()
// Start the periodic GC timer if it is not already running.
SetGCTimerMode(PeriodicTimer);
WorkerRunnable* runnable;
WorkerRunnable* runnable = nullptr;
{
MutexAutoLock lock(mMutex);
@ -6158,16 +6184,11 @@ WorkerPrivate::NotifyInternal(JSContext* aCx, Status aStatus)
Close();
}
eventTarget = mEventTarget;
}
// Disable the event target, if it exists.
if (eventTarget) {
// Since we'll no longer process events, make sure we no longer allow anyone
// to post them. We have to do this without mMutex held, since our mutex
// must be acquired *after* the WorkerEventTarget's mutex when they're both
// held.
eventTarget->Disable();
// Make sure the hybrid event target stops dispatching runnables
// once we reaching the killing state.
if (aStatus == Killing) {
mWorkerHybridEventTarget->ForgetWorkerPrivate(this);
}
}
if (mCrossThreadDispatcher) {

View File

@ -87,7 +87,7 @@ BEGIN_WORKERS_NAMESPACE
class AutoSyncLoopHolder;
class SharedWorker;
class ServiceWorkerClientInfo;
class WorkerControlEventTarget;
class WorkerEventTarget;
class WorkerControlRunnable;
class WorkerDebugger;
class WorkerPrivate;
@ -212,7 +212,6 @@ protected:
mozilla::CondVar mCondVar;
// Protected by mMutex.
RefPtr<EventTarget> mEventTarget;
nsTArray<RefPtr<WorkerRunnable>> mPreStartRunnables;
private:
@ -336,9 +335,6 @@ public:
already_AddRefed<WorkerRunnable>
MaybeWrapAsWorkerRunnable(already_AddRefed<nsIRunnable> aRunnable);
already_AddRefed<nsISerialEventTarget>
GetEventTarget();
// May be called on any thread...
bool
Start();
@ -1004,7 +1000,8 @@ class WorkerPrivate : public WorkerPrivateParent<WorkerPrivate>
uint32_t mDebuggerEventLoopLevel;
RefPtr<ThrottledEventQueue> mMainThreadThrottledEventQueue;
nsCOMPtr<nsIEventTarget> mMainThreadEventTarget;
RefPtr<WorkerControlEventTarget> mWorkerControlEventTarget;
RefPtr<WorkerEventTarget> mWorkerControlEventTarget;
RefPtr<WorkerEventTarget> mWorkerHybridEventTarget;
struct SyncLoopInfo
{
@ -1461,9 +1458,14 @@ public:
// Get an event target that will dispatch runnables as control runnables on
// the worker thread. Implement nsICancelableRunnable if you wish to take
// action on cancelation.
nsIEventTarget*
nsISerialEventTarget*
ControlEventTarget();
// Get an event target that will attempt to dispatch a normal WorkerRunnable,
// but if that fails will then fall back to a control runnable.
nsISerialEventTarget*
HybridEventTarget();
private:
WorkerPrivate(WorkerPrivate* aParent,
const nsAString& aScriptURL, bool aIsChromeWorker,

View File

@ -72,7 +72,7 @@ using mozilla::dom::cache::CacheStorage;
using mozilla::ipc::PrincipalInfo;
WorkerGlobalScope::WorkerGlobalScope(WorkerPrivate* aWorkerPrivate)
: mSerialEventTarget(aWorkerPrivate->GetEventTarget())
: mSerialEventTarget(aWorkerPrivate->HybridEventTarget())
, mWindowInteractionsAllowed(0)
, mWorkerPrivate(aWorkerPrivate)
{
@ -860,7 +860,7 @@ ServiceWorkerGlobalScope::OpenWindowEnabled(JSContext* aCx, JSObject* aObj)
WorkerDebuggerGlobalScope::WorkerDebuggerGlobalScope(
WorkerPrivate* aWorkerPrivate)
: mWorkerPrivate(aWorkerPrivate)
, mSerialEventTarget(aWorkerPrivate->GetEventTarget())
, mSerialEventTarget(aWorkerPrivate->HybridEventTarget())
{
mWorkerPrivate->AssertIsOnWorkerThread();

View File

@ -82,7 +82,6 @@ nsXBLContentSink::Init(nsIDocument* aDoc,
void
nsXBLContentSink::MaybeStartLayout(bool aIgnorePendingSheets)
{
return;
}
nsresult

View File

@ -178,8 +178,6 @@ XMLStylesheetProcessingInstruction::GetStyleSheetInfo(nsAString& aTitle,
// If we get here we assume that we're loading a css file, so set the
// type to 'text/css'
aType.AssignLiteral("text/css");
return;
}
nsGenericDOMDataNode*

View File

@ -240,7 +240,6 @@ nsXMLFragmentContentSink::CloseElement(nsIContent* aContent)
void
nsXMLFragmentContentSink::MaybeStartLayout(bool aIgnorePendingSheets)
{
return;
}
////////////////////////////////////////////////////////////////////////

View File

@ -434,7 +434,6 @@ RangeUpdater::SelAdjInsertText(Text& aTextNode,
item->mEndOffset += len;
}
}
return;
}
nsresult

View File

@ -1258,7 +1258,7 @@ TextEditRules::WillOutputText(Selection* aSelection,
return NS_OK;
}
RefPtr<Element> root = mTextEditor->GetRoot();
Element* root = mTextEditor->GetRoot();
if (!root) { // Don't warn it, this is possible, e.g., 997805.html
aOutString->Truncate();
*aHandled = true;

View File

@ -134,8 +134,6 @@ void JapaneseContextAnalysis::HandleData(const char* aBuf, uint32_t aLen)
mLastCharOrder = order;
}
}
return;
}
void JapaneseContextAnalysis::Reset()

View File

@ -236,5 +236,4 @@ void nsUniversalDetector::DataEnd()
default:
;
}
return;
}

View File

@ -75,7 +75,6 @@ EnsureSurfaceStoredRecording(DrawEventRecorderPrivate *aRecorder, SourceSurface
userData->recorder = aRecorder;
aSurface->AddUserData(reinterpret_cast<UserDataKey*>(aRecorder),
userData, &RecordingSourceSurfaceUserDataFunc);
return;
}
class SourceSurfaceRecording : public SourceSurface

View File

@ -75,7 +75,6 @@ EnsureSurfaceStored(DrawEventRecorderPrivate *aRecorder, SourceSurface *aSurface
userData->recorder = aRecorder;
aSurface->AddUserData(reinterpret_cast<UserDataKey*>(aRecorder),
userData, &WrapAndRecordSourceSurfaceUserDataFunc);
return;
}
class SourceSurfaceWrapAndRecord : public SourceSurface

View File

@ -442,8 +442,6 @@ FindInflectionPoints(const BezierControlPoints &aControlPoints,
*aCount = 2;
}
}
return;
}
void

View File

@ -2503,7 +2503,6 @@ SplitByChar(const nsACString& str, const char delim, std::vector<nsCString>* con
out->push_back(nsCString(substr));
start = end + 1;
continue;
}
nsDependentCSubstring substr(str, start);

View File

@ -942,7 +942,6 @@ GPUProcessManager::CreateContentVideoDecoderManager(base::ProcessId aOtherProces
mGPUChild->SendNewContentVideoDecoderManager(Move(parentPipe));
*aOutEndpoint = Move(childPipe);
return;
}
already_AddRefed<IAPZCTreeManager>

View File

@ -572,8 +572,6 @@ AsyncCompositionManager::AlignFixedAndStickyLayers(Layer* aTransformedSubtreeRoo
aPreviousTransformForRoot, newTransform, aFixedLayerMargins, aClipPartsCache);
}
}
return;
}
static void

View File

@ -1472,7 +1472,6 @@ LayerComposite::AddBlendModeEffect(EffectChain& aEffectChain)
}
aEffectChain.mSecondaryEffects[EffectTypes::BLEND_MODE] = new EffectBlendMode(blendMode);
return;
}
bool

View File

@ -80,7 +80,6 @@ void
WebRenderTextureHost::Unlock()
{
MOZ_ASSERT_UNREACHABLE("unexpected to be called");
return;
}
bool

View File

@ -32,7 +32,6 @@ FindVisualAndDepth(Display* aDisplay, VisualID aVisualID,
NS_ASSERTION(aVisualID == X11None, "VisualID not on Screen.");
*aVisual = nullptr;
*aDepth = 0;
return;
}
void

View File

@ -177,6 +177,7 @@ MessageLoop::MessageLoop(Type type, nsIThread* aThread)
exception_restoration_(false),
state_(NULL),
run_depth_base_(1),
shutting_down_(false),
#ifdef OS_WIN
os_modal_loop_(false),
#endif // OS_WIN
@ -377,6 +378,9 @@ void MessageLoop::PostTask_Helper(already_AddRefed<nsIRunnable> task, int delay_
return;
}
// Tasks should only be queued before or during the Run loop, not after.
MOZ_ASSERT(!shutting_down_);
#ifdef MOZ_TASK_TRACER
nsCOMPtr<nsIRunnable> tracedTask = task;
if (mozilla::tasktracer::IsStartLogging()) {
@ -567,6 +571,9 @@ bool MessageLoop::DoIdleWork() {
// MessageLoop::AutoRunState
MessageLoop::AutoRunState::AutoRunState(MessageLoop* loop) : loop_(loop) {
// Top-level Run should only get called once.
MOZ_ASSERT(!loop_->shutting_down_);
// Make the loop reference us.
previous_state_ = loop_->state_;
if (previous_state_) {
@ -585,6 +592,9 @@ MessageLoop::AutoRunState::AutoRunState(MessageLoop* loop) : loop_(loop) {
MessageLoop::AutoRunState::~AutoRunState() {
loop_->state_ = previous_state_;
// If exiting a top-level Run, then we're shutting down.
loop_->shutting_down_ = !previous_state_;
}
//------------------------------------------------------------------------------

View File

@ -112,9 +112,16 @@ public:
// The MessageLoop takes ownership of the Task, and deletes it after it has
// been Run().
//
// New tasks should not be posted after the invocation of a MessageLoop's
// Run method. Otherwise, they may fail to actually run. Callers should check
// if the MessageLoop is processing tasks if necessary by calling
// IsAcceptingTasks().
//
// NOTE: These methods may be called on any thread. The Task will be invoked
// on the thread that executes MessageLoop::Run().
bool IsAcceptingTasks() const { return !shutting_down_; }
void PostTask(already_AddRefed<nsIRunnable> task);
void PostDelayedTask(already_AddRefed<nsIRunnable> task, int delay_ms);
@ -429,6 +436,7 @@ public:
RunState* state_;
int run_depth_base_;
bool shutting_down_;
#if defined(OS_WIN)
// Should be set to true before calling Windows APIs like TrackPopupMenu, etc

View File

@ -127,7 +127,9 @@ void CALLBACK ObjectWatcher::DoneWaiting(void* param, BOOLEAN timed_out) {
// We rely on the locking in PostTask() to ensure that a memory barrier is
// provided, which in turn ensures our change to did_signal can be observed
// on the target thread.
watch->origin_loop->PostTask(addrefedWatch.forget());
if (watch->origin_loop->IsAcceptingTasks()) {
watch->origin_loop->PostTask(addrefedWatch.forget());
}
}
void ObjectWatcher::WillDestroyCurrentMessageLoop() {

View File

@ -135,11 +135,9 @@ CrossProcessSemaphore::Wait(const Maybe<TimeDuration>& aWaitTime)
ts.tv_nsec %= kNsPerSec;
while ((ret = sem_timedwait(mSemaphore, &ts)) == -1 && errno == EINTR) {
continue;
}
} else {
while ((ret = sem_wait(mSemaphore)) == -1 && errno == EINTR) {
continue;
}
}
return ret == 0;

View File

@ -56,7 +56,7 @@ private:
IGlobalInterfaceTable* ObtainGit();
private:
REFIID mIid;
IID mIid;
RefPtr<IAgileReference> mAgileRef;
DWORD mGitCookie;
};

View File

@ -194,7 +194,6 @@ js::Nursery::enable()
#endif
MOZ_ALWAYS_TRUE(runtime()->gc.storeBuffer().enable());
return;
}
void

View File

@ -900,7 +900,6 @@ class BackReferenceNode : public SeqRegExpNode
RegExpCompiler* compiler,
int characters_filled_in,
bool not_at_start) {
return;
}
virtual bool FillInBMInfo(int offset,
int budget,

View File

@ -292,6 +292,42 @@ BaselineCacheIRCompiler::emitGuardCompartment()
return true;
}
bool
BaselineCacheIRCompiler::emitGuardAnyClass()
{
Register obj = allocator.useRegister(masm, reader.objOperandId());
AutoScratchRegister scratch(allocator, masm);
FailurePath* failure;
if (!addFailurePath(&failure))
return false;
Address testAddr(stubAddress(reader.stubOffset()));
masm.loadObjGroup(obj, scratch);
masm.loadPtr(Address(scratch, ObjectGroup::offsetOfClasp()), scratch);
masm.branchPtr(Assembler::NotEqual, testAddr, scratch, failure->label());
return true;
}
bool
BaselineCacheIRCompiler::emitGuardHasProxyHandler()
{
Register obj = allocator.useRegister(masm, reader.objOperandId());
AutoScratchRegister scratch(allocator, masm);
FailurePath* failure;
if (!addFailurePath(&failure))
return false;
Address testAddr(stubAddress(reader.stubOffset()));
masm.loadPtr(testAddr, scratch);
Address handlerAddr(obj, ProxyObject::offsetOfHandler());
masm.branchPtr(Assembler::NotEqual, handlerAddr, scratch, failure->label());
return true;
}
bool
BaselineCacheIRCompiler::emitGuardSpecificObject()
{
@ -367,6 +403,54 @@ BaselineCacheIRCompiler::emitGuardSpecificSymbol()
return true;
}
bool
BaselineCacheIRCompiler::emitGuardXrayExpandoShapeAndDefaultProto()
{
Register obj = allocator.useRegister(masm, reader.objOperandId());
bool hasExpando = reader.readBool();
Address shapeWrapperAddress(stubAddress(reader.stubOffset()));
AutoScratchRegister scratch(allocator, masm);
Maybe<AutoScratchRegister> scratch2;
if (hasExpando)
scratch2.emplace(allocator, masm);
FailurePath* failure;
if (!addFailurePath(&failure))
return false;
masm.loadPtr(Address(obj, ProxyObject::offsetOfReservedSlots()), scratch);
Address holderAddress(scratch, sizeof(Value) * GetXrayJitInfo()->xrayHolderSlot);
Address expandoAddress(scratch, NativeObject::getFixedSlotOffset(GetXrayJitInfo()->holderExpandoSlot));
if (hasExpando) {
masm.branchTestObject(Assembler::NotEqual, holderAddress, failure->label());
masm.unboxObject(holderAddress, scratch);
masm.branchTestObject(Assembler::NotEqual, expandoAddress, failure->label());
masm.unboxObject(expandoAddress, scratch);
// Unwrap the expando before checking its shape.
masm.loadPtr(Address(scratch, ProxyObject::offsetOfReservedSlots()), scratch);
masm.unboxObject(Address(scratch, detail::ProxyReservedSlots::offsetOfPrivateSlot()), scratch);
masm.loadPtr(shapeWrapperAddress, scratch2.ref());
LoadShapeWrapperContents(masm, scratch2.ref(), scratch2.ref(), failure->label());
masm.branchTestObjShape(Assembler::NotEqual, scratch, scratch2.ref(), failure->label());
// The reserved slots on the expando should all be in fixed slots.
Address protoAddress(scratch, NativeObject::getFixedSlotOffset(GetXrayJitInfo()->expandoProtoSlot));
masm.branchTestUndefined(Assembler::NotEqual, protoAddress, failure->label());
} else {
Label done;
masm.branchTestObject(Assembler::NotEqual, holderAddress, &done);
masm.unboxObject(holderAddress, scratch);
masm.branchTestObject(Assembler::Equal, expandoAddress, failure->label());
masm.bind(&done);
}
return true;
}
bool
BaselineCacheIRCompiler::emitLoadFixedSlotResult()
{

View File

@ -16,6 +16,7 @@
#include "vm/SelfHosting.h"
#include "jsobjinlines.h"
#include "jit/MacroAssembler-inl.h"
#include "vm/EnvironmentObject-inl.h"
#include "vm/UnboxedObject-inl.h"
@ -177,6 +178,8 @@ GetPropIRGenerator::tryAttachStub()
return true;
if (tryAttachCrossCompartmentWrapper(obj, objId, id))
return true;
if (tryAttachXrayCrossCompartmentWrapper(obj, objId, id))
return true;
if (tryAttachFunction(obj, objId, id))
return true;
if (tryAttachProxy(obj, objId, id))
@ -752,7 +755,7 @@ GetPropIRGenerator::tryAttachCrossCompartmentWrapper(HandleObject obj, ObjOperan
maybeEmitIdGuard(id);
writer.guardIsProxy(objId);
writer.guardIsCrossCompartmentWrapper(objId);
writer.guardHasProxyHandler(objId, Wrapper::wrapperHandler(obj));
// Load the object wrapped by the CCW
ObjOperandId wrapperTargetId = writer.loadWrapperTarget(objId);
@ -776,6 +779,114 @@ GetPropIRGenerator::tryAttachCrossCompartmentWrapper(HandleObject obj, ObjOperan
return true;
}
static bool
GetXrayExpandoShapeWrapper(JSContext* cx, HandleObject xray, MutableHandleObject wrapper)
{
Value v = GetProxyReservedSlot(xray, GetXrayJitInfo()->xrayHolderSlot);
if (v.isObject()) {
NativeObject* holder = &v.toObject().as<NativeObject>();
v = holder->getFixedSlot(GetXrayJitInfo()->holderExpandoSlot);
if (v.isObject()) {
RootedNativeObject expando(cx, &UncheckedUnwrap(&v.toObject())->as<NativeObject>());
wrapper.set(NewWrapperWithObjectShape(cx, expando));
return wrapper != nullptr;
}
}
wrapper.set(nullptr);
return true;
}
bool
GetPropIRGenerator::tryAttachXrayCrossCompartmentWrapper(HandleObject obj, ObjOperandId objId,
HandleId id)
{
if (!IsProxy(obj))
return false;
XrayJitInfo* info = GetXrayJitInfo();
if (!info || !info->isCrossCompartmentXray(GetProxyHandler(obj)))
return false;
if (!info->globalHasExclusiveExpandos(cx_->global()))
return false;
RootedObject target(cx_, UncheckedUnwrap(obj));
RootedObject expandoShapeWrapper(cx_);
if (!GetXrayExpandoShapeWrapper(cx_, obj, &expandoShapeWrapper)) {
cx_->recoverFromOutOfMemory();
return false;
}
// Look for a getter we can call on the xray or its prototype chain.
Rooted<PropertyDescriptor> desc(cx_);
RootedObject holder(cx_, obj);
AutoObjectVector prototypes(cx_);
AutoObjectVector prototypeExpandoShapeWrappers(cx_);
while (true) {
if (!GetOwnPropertyDescriptor(cx_, holder, id, &desc)) {
cx_->clearPendingException();
return false;
}
if (desc.object())
break;
if (!GetPrototype(cx_, holder, &holder)) {
cx_->clearPendingException();
return false;
}
if (!holder || !IsProxy(holder) || !info->isCrossCompartmentXray(GetProxyHandler(holder)))
return false;
RootedObject prototypeExpandoShapeWrapper(cx_);
if (!GetXrayExpandoShapeWrapper(cx_, holder, &prototypeExpandoShapeWrapper) ||
!prototypes.append(holder) ||
!prototypeExpandoShapeWrappers.append(prototypeExpandoShapeWrapper))
{
cx_->recoverFromOutOfMemory();
return false;
}
}
if (!desc.isAccessorDescriptor())
return false;
RootedObject getter(cx_, desc.getterObject());
if (!getter || !getter->is<JSFunction>() || !getter->as<JSFunction>().isNative())
return false;
maybeEmitIdGuard(id);
writer.guardIsProxy(objId);
writer.guardHasProxyHandler(objId, GetProxyHandler(obj));
// Load the object wrapped by the CCW
ObjOperandId wrapperTargetId = writer.loadWrapperTarget(objId);
// Test the wrapped object's class. The properties held by xrays or their
// prototypes will be invariant for objects of a given class, except for
// changes due to xray expandos or xray prototype mutations.
writer.guardAnyClass(wrapperTargetId, target->getClass());
// Make sure the expandos on the xray and its prototype chain match up with
// what we expect. The expando shape needs to be consistent, to ensure it
// has not had any shadowing properties added, and the expando cannot have
// any custom prototype (xray prototypes are stable otherwise).
//
// We can only do this for xrays with exclusive access to their expandos
// (as we checked earlier), which store a pointer to their expando
// directly. Xrays in other compartments may share their expandos with each
// other and a VM call is needed just to find the expando.
writer.guardXrayExpandoShapeAndDefaultProto(objId, expandoShapeWrapper);
for (size_t i = 0; i < prototypes.length(); i++) {
JSObject* proto = prototypes[i];
ObjOperandId protoId = writer.loadObject(proto);
writer.guardXrayExpandoShapeAndDefaultProto(protoId, prototypeExpandoShapeWrappers[i]);
}
writer.callNativeGetterResult(objId, &getter->as<JSFunction>());
writer.typeMonitorResult();
trackAttached("XrayGetter");
return true;
}
bool
GetPropIRGenerator::tryAttachGenericProxy(HandleObject obj, ObjOperandId objId, HandleId id,
bool handleDOMProxies)
@ -3877,3 +3988,40 @@ CompareIRGenerator::trackNotAttached()
}
#endif
}
// Class which holds a shape pointer for use when caches might reference data in other zones.
static const Class shapeContainerClass = {
"ShapeContainer",
JSCLASS_HAS_RESERVED_SLOTS(1)
};
static const size_t SHAPE_CONTAINER_SLOT = 0;
JSObject*
jit::NewWrapperWithObjectShape(JSContext* cx, HandleNativeObject obj)
{
MOZ_ASSERT(cx->compartment() != obj->compartment());
RootedObject wrapper(cx);
{
AutoCompartment ac(cx, obj);
wrapper = NewObjectWithClassProto(cx, &shapeContainerClass, nullptr);
if (!obj)
return nullptr;
wrapper->as<NativeObject>().setSlot(SHAPE_CONTAINER_SLOT, PrivateGCThingValue(obj->lastProperty()));
}
if (!JS_WrapObject(cx, &wrapper))
return nullptr;
MOZ_ASSERT(IsWrapper(wrapper));
return wrapper;
}
void
jit::LoadShapeWrapperContents(MacroAssembler& masm, Register obj, Register dst, Label* failure)
{
masm.loadPtr(Address(obj, ProxyObject::offsetOfReservedSlots()), dst);
Address privateAddr(dst, detail::ProxyReservedSlots::offsetOfPrivateSlot());
masm.branchTestObject(Assembler::NotEqual, privateAddr, failure);
masm.unboxObject(privateAddr, dst);
masm.unboxNonDouble(Address(dst, NativeObject::getFixedSlotOffset(SHAPE_CONTAINER_SLOT)), dst);
}

View File

@ -168,11 +168,12 @@ extern const char* CacheKindNames[];
_(GuardShape) \
_(GuardGroup) \
_(GuardProto) \
_(GuardClass) \
_(GuardClass) /* Guard an object class, per GuardClassKind */ \
_(GuardAnyClass) /* Guard an arbitrary class for an object */ \
_(GuardCompartment) \
_(GuardIsNativeFunction) \
_(GuardIsProxy) \
_(GuardIsCrossCompartmentWrapper) \
_(GuardHasProxyHandler) \
_(GuardNotDOMProxy) \
_(GuardSpecificObject) \
_(GuardSpecificAtom) \
@ -188,6 +189,8 @@ extern const char* CacheKindNames[];
_(GuardAndGetIterator) \
_(GuardHasGetterSetter) \
_(GuardGroupHasUnanalyzedNewScript) \
_(GuardIndexIsNonNegative) \
_(GuardXrayExpandoShapeAndDefaultProto) \
_(LoadStackValue) \
_(LoadObject) \
_(LoadProto) \
@ -349,6 +352,14 @@ enum class GuardClassKind : uint8_t
JSFunction,
};
// Some ops refer to shapes that might be in other zones. Instead of putting
// cross-zone pointers in the caches themselves (which would complicate tracing
// enormously), these ops instead contain wrappers for objects in the target
// zone, which refer to the actual shape via a reserved slot.
JSObject* NewWrapperWithObjectShape(JSContext* cx, HandleNativeObject obj);
void LoadShapeWrapperContents(MacroAssembler& masm, Register obj, Register dst, Label* failure);
// Class to record CacheIR + some additional metadata for code generation.
class MOZ_RAII CacheIRWriter : public JS::CustomAutoRooter
{
@ -517,6 +528,10 @@ class MOZ_RAII CacheIRWriter : public JS::CustomAutoRooter
writeOpWithOperandId(CacheOp::GuardShape, obj);
addStubField(uintptr_t(shape), StubField::Type::Shape);
}
void guardXrayExpandoShapeAndDefaultProto(ObjOperandId obj, JSObject* shapeWrapper) {
writeOpWithOperandId(CacheOp::GuardXrayExpandoShapeAndDefaultProto, obj);
buffer_.writeByte(uint32_t(!!shapeWrapper)); addStubField(uintptr_t(shapeWrapper), StubField::Type::JSObject);
}
void guardGroup(ObjOperandId obj, ObjectGroup* group) {
writeOpWithOperandId(CacheOp::GuardGroup, obj);
addStubField(uintptr_t(group), StubField::Type::ObjectGroup);
@ -531,6 +546,10 @@ class MOZ_RAII CacheIRWriter : public JS::CustomAutoRooter
writeOpWithOperandId(CacheOp::GuardClass, obj);
buffer_.writeByte(uint32_t(kind));
}
void guardAnyClass(ObjOperandId obj, const Class* clasp) {
writeOpWithOperandId(CacheOp::GuardAnyClass, obj);
addStubField(uintptr_t(clasp), StubField::Type::RawWord);
}
void guardIsNativeFunction(ObjOperandId obj, JSNative nativeFunc) {
writeOpWithOperandId(CacheOp::GuardIsNativeFunction, obj);
writePointer(JS_FUNC_TO_DATA_PTR(void*, nativeFunc));
@ -538,8 +557,9 @@ class MOZ_RAII CacheIRWriter : public JS::CustomAutoRooter
void guardIsProxy(ObjOperandId obj) {
writeOpWithOperandId(CacheOp::GuardIsProxy, obj);
}
void guardIsCrossCompartmentWrapper(ObjOperandId obj) {
writeOpWithOperandId(CacheOp::GuardIsCrossCompartmentWrapper, obj);
void guardHasProxyHandler(ObjOperandId obj, const void* handler) {
writeOpWithOperandId(CacheOp::GuardHasProxyHandler, obj);
addStubField(uintptr_t(handler), StubField::Type::RawWord);
}
void guardNotDOMProxy(ObjOperandId obj) {
writeOpWithOperandId(CacheOp::GuardNotDOMProxy, obj);
@ -605,6 +625,10 @@ class MOZ_RAII CacheIRWriter : public JS::CustomAutoRooter
addStubField(uintptr_t(group), StubField::Type::ObjectGroup);
}
void guardIndexIsNonNegative(Int32OperandId index) {
writeOpWithOperandId(CacheOp::GuardIndexIsNonNegative, index);
}
void loadFrameCalleeResult() {
writeOp(CacheOp::LoadFrameCalleeResult);
}
@ -1137,6 +1161,7 @@ class MOZ_RAII GetPropIRGenerator : public IRGenerator
bool tryAttachModuleNamespace(HandleObject obj, ObjOperandId objId, HandleId id);
bool tryAttachWindowProxy(HandleObject obj, ObjOperandId objId, HandleId id);
bool tryAttachCrossCompartmentWrapper(HandleObject obj, ObjOperandId objId, HandleId id);
bool tryAttachXrayCrossCompartmentWrapper(HandleObject obj, ObjOperandId objId, HandleId id);
bool tryAttachFunction(HandleObject obj, ObjOperandId objId, HandleId id);
bool tryAttachGenericProxy(HandleObject obj, ObjOperandId objId, HandleId id,

View File

@ -1435,22 +1435,6 @@ CacheIRCompiler::emitGuardIsProxy()
return true;
}
bool
CacheIRCompiler::emitGuardIsCrossCompartmentWrapper()
{
Register obj = allocator.useRegister(masm, reader.objOperandId());
AutoScratchRegister scratch(allocator, masm);
FailurePath* failure;
if (!addFailurePath(&failure))
return false;
Address handlerAddr(obj, ProxyObject::offsetOfHandler());
masm.branchPtr(Assembler::NotEqual, handlerAddr, ImmPtr(&CrossCompartmentWrapper::singleton),
failure->label());
return true;
}
bool
CacheIRCompiler::emitGuardNotDOMProxy()
{
@ -1927,6 +1911,19 @@ CacheIRCompiler::emitLoadDenseElementResult()
return true;
}
bool
CacheIRCompiler::emitGuardIndexIsNonNegative()
{
Register index = allocator.useRegister(masm, reader.int32OperandId());
FailurePath* failure;
if (!addFailurePath(&failure))
return false;
masm.branch32(Assembler::LessThan, index, Imm32(0), failure->label());
return true;
}
bool
CacheIRCompiler::emitLoadDenseElementHoleResult()
{

View File

@ -24,7 +24,6 @@ namespace jit {
_(GuardClass) \
_(GuardIsNativeFunction) \
_(GuardIsProxy) \
_(GuardIsCrossCompartmentWrapper) \
_(GuardNotDOMProxy) \
_(GuardSpecificInt32Immediate) \
_(GuardMagicValue) \
@ -33,6 +32,7 @@ namespace jit {
_(GuardNoDetachedTypedObjects) \
_(GuardNoDenseElements) \
_(GuardAndGetIndexFromString) \
_(GuardIndexIsNonNegative) \
_(LoadProto) \
_(LoadEnclosingEnvironment) \
_(LoadWrapperTarget) \

View File

@ -106,6 +106,12 @@ class MOZ_RAII IonCacheIRCompiler : public CacheIRCompiler
JSCompartment* compartmentStubField(uint32_t offset) {
return (JSCompartment*)readStubWord(offset, StubField::Type::RawWord);
}
const Class* classStubField(uintptr_t offset) {
return (const Class*)readStubWord(offset, StubField::Type::RawWord);
}
const void* proxyHandlerStubField(uintptr_t offset) {
return (const void*)readStubWord(offset, StubField::Type::RawWord);
}
jsid idStubField(uint32_t offset) {
return mozilla::BitwiseCast<jsid>(readStubWord(offset, StubField::Type::Id));
}
@ -647,6 +653,37 @@ IonCacheIRCompiler::emitGuardCompartment()
return true;
}
bool
IonCacheIRCompiler::emitGuardAnyClass()
{
Register obj = allocator.useRegister(masm, reader.objOperandId());
AutoScratchRegister scratch(allocator, masm);
const Class* clasp = classStubField(reader.stubOffset());
FailurePath* failure;
if (!addFailurePath(&failure))
return false;
masm.branchTestObjClass(Assembler::NotEqual, obj, scratch, clasp, failure->label());
return true;
}
bool
IonCacheIRCompiler::emitGuardHasProxyHandler()
{
Register obj = allocator.useRegister(masm, reader.objOperandId());
const void* handler = proxyHandlerStubField(reader.stubOffset());
FailurePath* failure;
if (!addFailurePath(&failure))
return false;
Address handlerAddr(obj, ProxyObject::offsetOfHandler());
masm.branchPtr(Assembler::NotEqual, handlerAddr, ImmPtr(handler), failure->label());
return true;
}
bool
IonCacheIRCompiler::emitGuardSpecificObject()
{
@ -720,6 +757,55 @@ IonCacheIRCompiler::emitGuardSpecificSymbol()
return true;
}
bool
IonCacheIRCompiler::emitGuardXrayExpandoShapeAndDefaultProto()
{
Register obj = allocator.useRegister(masm, reader.objOperandId());
bool hasExpando = reader.readBool();
JSObject* shapeWrapper = objectStubField(reader.stubOffset());
MOZ_ASSERT(hasExpando == !!shapeWrapper);
AutoScratchRegister scratch(allocator, masm);
Maybe<AutoScratchRegister> scratch2;
if (hasExpando)
scratch2.emplace(allocator, masm);
FailurePath* failure;
if (!addFailurePath(&failure))
return false;
masm.loadPtr(Address(obj, ProxyObject::offsetOfReservedSlots()), scratch);
Address holderAddress(scratch, sizeof(Value) * GetXrayJitInfo()->xrayHolderSlot);
Address expandoAddress(scratch, NativeObject::getFixedSlotOffset(GetXrayJitInfo()->holderExpandoSlot));
if (hasExpando) {
masm.branchTestObject(Assembler::NotEqual, holderAddress, failure->label());
masm.unboxObject(holderAddress, scratch);
masm.branchTestObject(Assembler::NotEqual, expandoAddress, failure->label());
masm.unboxObject(expandoAddress, scratch);
// Unwrap the expando before checking its shape.
masm.loadPtr(Address(scratch, ProxyObject::offsetOfReservedSlots()), scratch);
masm.unboxObject(Address(scratch, detail::ProxyReservedSlots::offsetOfPrivateSlot()), scratch);
masm.movePtr(ImmGCPtr(shapeWrapper), scratch2.ref());
LoadShapeWrapperContents(masm, scratch2.ref(), scratch2.ref(), failure->label());
masm.branchTestObjShape(Assembler::NotEqual, scratch, scratch2.ref(), failure->label());
// The reserved slots on the expando should all be in fixed slots.
Address protoAddress(scratch, NativeObject::getFixedSlotOffset(GetXrayJitInfo()->expandoProtoSlot));
masm.branchTestUndefined(Assembler::NotEqual, protoAddress, failure->label());
} else {
Label done;
masm.branchTestObject(Assembler::NotEqual, holderAddress, &done);
masm.unboxObject(holderAddress, scratch);
masm.branchTestObject(Assembler::Equal, expandoAddress, failure->label());
masm.bind(&done);
}
return true;
}
bool
IonCacheIRCompiler::emitLoadFixedSlotResult()
{

View File

@ -319,8 +319,6 @@ LIRGeneratorShared::defineSinCos(LInstructionHelper<2, Ops, Temps> *lir, MDefini
lir->setMir(mir);
mir->setVirtualRegister(vreg);
add(lir);
return;
}
// In LIR, we treat booleans and integers as the same low-level type (INTEGER).

View File

@ -362,7 +362,6 @@ js::jit::RegionLock::acquire(void* addr)
uint32_t one = 1;
while (!__atomic_compare_exchange(&spinlock, &zero, &one, false, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE)) {
zero = 0;
continue;
}
# endif
}

View File

@ -363,7 +363,6 @@ CodeGeneratorX86Shared::visitWasmSelect(LWasmSelect* ins)
}
masm.bind(&done);
return;
}
void

View File

@ -1305,6 +1305,20 @@ js::GetDOMProxyShadowsCheck()
return gDOMProxyShadowsCheck;
}
static XrayJitInfo* gXrayJitInfo = nullptr;
JS_FRIEND_API(void)
js::SetXrayJitInfo(XrayJitInfo* info)
{
gXrayJitInfo = info;
}
XrayJitInfo*
js::GetXrayJitInfo()
{
return gXrayJitInfo;
}
bool
js::detail::IdMatchesAtom(jsid id, JSAtom* atom)
{

View File

@ -1319,6 +1319,34 @@ inline bool DOMProxyIsShadowing(DOMProxyShadowsResult result) {
result == ShadowsViaIndirectExpando;
}
// Callbacks and other information for use by the JITs when optimizing accesses
// on xray wrappers.
struct XrayJitInfo {
// Test whether a proxy handler is a cross compartment xray with no
// security checks.
bool (*isCrossCompartmentXray)(const BaseProxyHandler* handler);
// Test whether xrays with a global object's compartment have expandos of
// their own, instead of sharing them with Xrays from other compartments.
bool (*globalHasExclusiveExpandos)(JSObject* obj);
// Proxy reserved slot used by xrays in sandboxes to store their holder
// object.
size_t xrayHolderSlot;
// Reserved slot used by xray holders to store the xray's expando object.
size_t holderExpandoSlot;
// Reserved slot used by xray expandos to store a custom prototype.
size_t expandoProtoSlot;
};
JS_FRIEND_API(void)
SetXrayJitInfo(XrayJitInfo* info);
XrayJitInfo*
GetXrayJitInfo();
/* Implemented in jsdate.cpp. */
/** Detect whether the internal date value is NaN. */

View File

@ -4684,8 +4684,6 @@ class MOZ_STACK_CLASS Debugger::ScriptQuery
return;
}
}
return;
}
/*

View File

@ -197,9 +197,6 @@ ForOfIterator::closeThrow()
// Step 6.
cx_->setPendingException(completionException);
// Steps 7-9 (skipped).
return;
}
bool

View File

@ -1488,15 +1488,9 @@ struct StackShape
}
HashNumber hash() const {
HashNumber hash = uintptr_t(base);
/* Accumulate from least to most random so the low bits are most random. */
hash = mozilla::RotateLeft(hash, 4) ^ attrs;
hash = mozilla::RotateLeft(hash, 4) ^ slot_;
hash = mozilla::RotateLeft(hash, 4) ^ HashId(propid);
hash = mozilla::RotateLeft(hash, 4) ^ uintptr_t(rawGetter);
hash = mozilla::RotateLeft(hash, 4) ^ uintptr_t(rawSetter);
return hash;
HashNumber hash = HashId(propid);
return mozilla::AddToHash(hash,
mozilla::HashGeneric(base, attrs, slot_, rawGetter, rawSetter));
}
// Traceable implementation.

View File

@ -3225,5 +3225,4 @@ js::unicode::AppendUpperCaseSpecialCasing(char16_t ch, char16_t* elements, size_
}
MOZ_ASSERT_UNREACHABLE("Bad character input.");
return;
}

View File

@ -188,8 +188,6 @@ SendCodeRangesToProfiler(const CodeSegment& cs, const Bytes& bytecode, const Met
vtune::MarkWasm(vtune::GenerateUniqueMethodID(), name.begin(), (void*)start, size);
#endif
}
return;
}
/* static */ UniqueConstCodeSegment

View File

@ -111,8 +111,9 @@ this.XPCOMUtils = {
if (interfaces) {
for (let i = 0; i < interfaces.length; i++) {
let iface = interfaces[i];
if (Ci[iface]) {
a.push(Ci[iface].name);
let name = (iface && iface.name) || String(iface);
if (name in Ci) {
a.push(name);
}
}
}

View File

@ -2847,6 +2847,7 @@ XPCJSRuntime::Initialize(JSContext* cx)
js::SetPreserveWrapperCallback(cx, PreserveWrapper);
JS_SetAccumulateTelemetryCallback(cx, AccumulateTelemetryCallback);
js::SetWindowProxyClass(cx, &OuterWindowProxyClass);
js::SetXrayJitInfo(&gXrayJitInfo);
JS::SetProcessLargeAllocationFailureCallback(OnLargeAllocationFailureCallback);
// The JS engine needs to keep the source code around in order to implement

View File

@ -32,6 +32,7 @@ support-files =
!/js/xpconnect/tests/mochitest/file_expandosharing.html
!/js/xpconnect/tests/mochitest/file_nodelists.html
!/js/xpconnect/tests/mochitest/file_evalInSandbox.html
!/js/xpconnect/tests/mochitest/file_xrayic.html
[test_APIExposer.xul]
[test_bug361111.xul]
@ -115,5 +116,6 @@ skip-if = os == 'win' || os == 'mac' || (os == 'linux' && !debug) # bug 1131110,
[test_weakref.xul]
[test_windowProxyDeadWrapper.html]
[test_wrappers.xul]
[test_xrayic.xul]
[test_xrayToJS.xul]
[test_asyncIteration.xul]

View File

@ -0,0 +1,76 @@
<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1355109
-->
<window title="Mozilla Bug 1355109"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
<!-- test results are displayed in the html:body -->
<body xmlns="http://www.w3.org/1999/xhtml">
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=758415"
target="_blank">Mozilla Bug 758415</a>
</body>
<!-- test code goes here -->
<script type="application/javascript">
<![CDATA[
SimpleTest.waitForExplicitFinish();
const Cu = Components.utils;
// Import our test JSM. We first strip the filename off
// the chrome url, then append the jsm filename.
var base = /.*\//.exec(window.location.href)[0];
Cu.import(base + "file_expandosharing.jsm");
// Wait for all child frames to load.
var gLoadCount = 0;
function frameLoaded() {
if (++gLoadCount == window.frames.length)
go();
}
function go() {
testSandbox(1);
testSandbox(100);
testSandbox(1000);
SimpleTest.finish();
}
function testSandbox(iterations) {
var sandbox = new Cu.Sandbox(window);
sandbox.iframes = document.getElementsByTagName('iframe');
Cu.evalInSandbox(testClassName.toSource(), sandbox);
Cu.evalInSandbox(testIC.toSource(), sandbox);
is(Cu.evalInSandbox("testIC(" + iterations + ");", sandbox), true, "sandbox test");
}
// This is in a separate function to provide a common source location for ICs.
function testClassName(obj, expected) {
var className = obj.className;
if (className != expected)
throw new Error("Got " + className + ", expected " + expected);
}
function testIC(iterations) {
for (var i = 0; i < this.iframes.length; i++) {
var win = this.iframes[i].contentWindow;
var spans = win.document.getElementsByTagName('span');
for (var j = 0; j < spans.length; j++) {
var span = spans[j];
for (var k = 0; k < iterations; k++)
testClassName(span, "iamaspan");
Object.defineProperty(span, "className", { value: "what" });
testClassName(span, "what");
}
}
return true;
}
]]>
</script>
<iframe id="inlineFrame1" onload="frameLoaded();" type="content" src="http://test1.example.org/tests/js/xpconnect/tests/mochitest/file_xrayic.html" />
<iframe id="inlineFrame2" onload="frameLoaded();" type="content" src="http://test1.example.org/tests/js/xpconnect/tests/mochitest/file_xrayic.html" />
</window>

View File

@ -0,0 +1,7 @@
<html>
<body>
<script>
parent.f = function() { return this; };
</script>
</body>
</html>

View File

@ -0,0 +1,5 @@
<html>
<body>
1
</body>
</html>

View File

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html>
<head>
<script type="application/javascript">
function setup() {
// Set up targets for sandbox expandos.
window.targetDOM = [document.getElementById("hello"), document.getElementById("there")];
}
</script>
</head>
<body onload="setup();">
<span id="hello" class="iamaspan">Hello</span>
<span id="there" class="iamaspan">There</span>
</body>
</html>

View File

@ -9,10 +9,12 @@ support-files =
file1_bug629227.html
file2_bug629227.html
file_bug505915.html
file_bug605167.html
file_bug650273.html
file_bug658560.html
file_bug706301.html
file_bug720619.html
file_bug731471.html
file_bug738244.html
file_bug760131.html
file_bug781476.html
@ -32,6 +34,7 @@ support-files =
file_matches.html
file_nodelists.html
file_wrappers-2.html
file_xrayic.html
inner.html
test1_bug629331.html
test2_bug629331.html

Some files were not shown because too many files have changed in this diff Show More