зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to autoland. a=merge CLOSED TREE
This commit is contained in:
Коммит
614b78ae36
|
@ -2361,15 +2361,19 @@ name = "webrender_bindings"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"app_units 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bincode 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"core-foundation 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"core-graphics 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"dwrote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"euclid 0.17.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"foreign-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gleam 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"nsstring 0.1.0",
|
||||
"rayon 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"thread_profiler 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"uuid 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"webrender 0.57.2",
|
||||
]
|
||||
|
||||
|
|
|
@ -1253,15 +1253,6 @@ nsScriptSecurityManager::GetDocShellCodebasePrincipal(nsIURI* aURI,
|
|||
return *aPrincipal ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// static
|
||||
nsIPrincipal*
|
||||
nsScriptSecurityManager::doGetObjectPrincipal(JSObject *aObj)
|
||||
{
|
||||
JSCompartment *compartment = js::GetObjectCompartment(aObj);
|
||||
JSPrincipals *principals = JS_GetCompartmentPrincipals(compartment);
|
||||
return nsJSPrincipals::get(principals);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsScriptSecurityManager::CanCreateWrapper(JSContext *cx,
|
||||
const nsIID &aIID,
|
||||
|
|
|
@ -93,10 +93,6 @@ private:
|
|||
static bool
|
||||
JSPrincipalsSubsume(JSPrincipals *first, JSPrincipals *second);
|
||||
|
||||
// Returns null if a principal cannot be found; generally callers
|
||||
// should error out at that point.
|
||||
static nsIPrincipal* doGetObjectPrincipal(JSObject* obj);
|
||||
|
||||
nsresult
|
||||
Init();
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
This is the debugger.html project output.
|
||||
See https://github.com/devtools-html/debugger.html
|
||||
|
||||
Version 60
|
||||
Version 61
|
||||
|
||||
Comparison: https://github.com/devtools-html/debugger.html/compare/release-59...release-60
|
||||
Comparison: https://github.com/devtools-html/debugger.html/compare/release-60...release-61
|
||||
|
||||
Packages:
|
||||
- babel-plugin-transform-es2015-modules-commonjs @6.26.2
|
||||
|
|
|
@ -2117,6 +2117,10 @@ menuseparator {
|
|||
padding: 0 2px;
|
||||
}
|
||||
|
||||
.objectBox-node.clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
.objectBox-event,
|
||||
|
@ -2223,6 +2227,7 @@ button.open-inspector {
|
|||
height: 16px;
|
||||
margin-left: 0.25em;
|
||||
vertical-align: middle;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.objectBox-node:hover .open-inspector,
|
||||
|
|
|
@ -1222,7 +1222,7 @@ function isYieldExpression(path) {
|
|||
}
|
||||
|
||||
function isObjectShorthand(parent) {
|
||||
return t.isObjectProperty(parent) && parent.key.start == parent.value.start && parent.key.loc.identifierName === parent.value.loc.identifierName;
|
||||
return t.isObjectProperty(parent) && parent.value && parent.key.start == parent.value.start && parent.key.loc.identifierName === parent.value.loc.identifierName;
|
||||
}
|
||||
|
||||
function getObjectExpressionValue(node) {
|
||||
|
|
|
@ -8174,7 +8174,7 @@ function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj;
|
|||
// (eg. "my-module/Test") which is why they are nested in "vendored".
|
||||
// The keys of the vendored object should match the module names
|
||||
// !!! Should remain synchronized with .babel/transform-mc.js !!!
|
||||
const vendored = {
|
||||
const vendored = exports.vendored = {
|
||||
classnames: _classnames2.default,
|
||||
"devtools-components": devtoolsComponents,
|
||||
"devtools-config": devtoolsConfig,
|
||||
|
@ -8210,7 +8210,6 @@ const vendored = {
|
|||
*/
|
||||
|
||||
// Modules imported with destructuring
|
||||
exports.vendored = vendored;
|
||||
|
||||
/***/ }),
|
||||
|
||||
|
|
|
@ -91,7 +91,7 @@ function getExtra(expression, result) {
|
|||
const selectedFrame = (0, _selectors.getSelectedFrame)(getState());
|
||||
|
||||
if (!selectedFrame) {
|
||||
return;
|
||||
return {};
|
||||
}
|
||||
|
||||
const extra = await getExtraProps(getState, expression, result, expr => client.evaluateInFrame(expr, selectedFrame.id));
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.onConnect = undefined;
|
||||
exports.onConnect = onConnect;
|
||||
|
||||
var _firefox = require("./firefox");
|
||||
|
||||
|
@ -68,6 +68,4 @@ async function onConnect(connection, {
|
|||
selectors,
|
||||
client: commands
|
||||
};
|
||||
}
|
||||
|
||||
exports.onConnect = onConnect;
|
||||
}
|
|
@ -237,7 +237,7 @@ class Popup extends _react.Component {
|
|||
roots = roots.filter(r => r.type != NODE_TYPES.PROTOTYPE);
|
||||
}
|
||||
|
||||
if ((0, _preview.isReactComponent)(this.getObjectProperties())) {
|
||||
if (extra.react && (0, _preview.isReactComponent)(this.getObjectProperties())) {
|
||||
header = this.renderReact(extra.react);
|
||||
roots = roots.filter(r => ["state", "props"].includes(r.name));
|
||||
}
|
||||
|
|
|
@ -124,6 +124,18 @@ class SourcesTree extends _react.Component {
|
|||
}
|
||||
}
|
||||
|
||||
// NOTE: we get the source from sources because item.contents is cached
|
||||
getSource(item) {
|
||||
return this.props.sources.get(item.contents.id);
|
||||
}
|
||||
|
||||
isEmpty() {
|
||||
const {
|
||||
sourceTree
|
||||
} = this.state;
|
||||
return sourceTree.contents.length === 0;
|
||||
}
|
||||
|
||||
renderItemName(name) {
|
||||
const hosts = {
|
||||
"ng://": "Angular",
|
||||
|
@ -135,69 +147,56 @@ class SourcesTree extends _react.Component {
|
|||
|
||||
renderEmptyElement(message) {
|
||||
return _react2.default.createElement("div", {
|
||||
key: "empty",
|
||||
className: "no-sources-message"
|
||||
}, message);
|
||||
}
|
||||
|
||||
render() {
|
||||
renderProjectRootHeader() {
|
||||
const {
|
||||
expanded,
|
||||
projectRoot
|
||||
} = this.props;
|
||||
const {
|
||||
focusedItem,
|
||||
highlightItems,
|
||||
listItems,
|
||||
parentMap,
|
||||
sourceTree
|
||||
} = this.state;
|
||||
|
||||
const onExpand = (item, expandedState) => {
|
||||
this.props.setExpandedState(expandedState);
|
||||
};
|
||||
|
||||
const onCollapse = (item, expandedState) => {
|
||||
this.props.setExpandedState(expandedState);
|
||||
};
|
||||
|
||||
const isEmpty = sourceTree.contents.length === 0;
|
||||
const isCustomRoot = projectRoot !== "";
|
||||
|
||||
let roots = () => sourceTree.contents;
|
||||
|
||||
let clearProjectRootButton = null; // The "sourceTree.contents[0]" check ensures that there are contents
|
||||
// A custom root with no existing sources will be ignored
|
||||
|
||||
if (isCustomRoot) {
|
||||
const sourceContents = sourceTree.contents[0];
|
||||
let rootLabel = projectRoot.split("/").pop();
|
||||
|
||||
roots = () => sourceContents.contents;
|
||||
|
||||
if (sourceContents && sourceContents.name !== rootLabel) {
|
||||
rootLabel = sourceContents.contents[0].name;
|
||||
|
||||
roots = () => sourceContents.contents[0].contents;
|
||||
}
|
||||
|
||||
clearProjectRootButton = _react2.default.createElement("button", {
|
||||
className: "sources-clear-root",
|
||||
onClick: () => this.props.clearProjectDirectoryRoot(),
|
||||
title: L10N.getStr("removeDirectoryRoot.label")
|
||||
}, _react2.default.createElement(_Svg2.default, {
|
||||
name: "home"
|
||||
}), _react2.default.createElement(_Svg2.default, {
|
||||
name: "breadcrumb",
|
||||
"class": true
|
||||
}), _react2.default.createElement("span", {
|
||||
className: "sources-clear-root-label"
|
||||
}, rootLabel));
|
||||
if (!projectRoot) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (isEmpty && !isCustomRoot) {
|
||||
return this.renderEmptyElement(L10N.getStr("sources.noSourcesAvailable"));
|
||||
const sourceContents = sourceTree.contents[0];
|
||||
let rootLabel = projectRoot.split("/").pop();
|
||||
|
||||
if (sourceContents && sourceContents.name !== rootLabel) {
|
||||
rootLabel = sourceContents.contents[0].name;
|
||||
}
|
||||
|
||||
return _react2.default.createElement("div", {
|
||||
key: "root",
|
||||
className: "sources-clear-root-container"
|
||||
}, _react2.default.createElement("button", {
|
||||
className: "sources-clear-root",
|
||||
onClick: () => this.props.clearProjectDirectoryRoot(),
|
||||
title: L10N.getStr("removeDirectoryRoot.label")
|
||||
}, _react2.default.createElement(_Svg2.default, {
|
||||
name: "home"
|
||||
}), _react2.default.createElement(_Svg2.default, {
|
||||
name: "breadcrumb",
|
||||
"class": true
|
||||
}), _react2.default.createElement("span", {
|
||||
className: "sources-clear-root-label"
|
||||
}, rootLabel)));
|
||||
}
|
||||
|
||||
renderTree() {
|
||||
const {
|
||||
expanded
|
||||
} = this.props;
|
||||
const {
|
||||
highlightItems,
|
||||
listItems,
|
||||
parentMap
|
||||
} = this.state;
|
||||
const treeProps = {
|
||||
autoExpandAll: false,
|
||||
autoExpandDepth: expanded ? 0 : 1,
|
||||
|
@ -205,35 +204,49 @@ class SourcesTree extends _react.Component {
|
|||
getChildren: item => (0, _sourcesTree.nodeHasChildren)(item) ? item.contents : [],
|
||||
getParent: item => parentMap.get(item),
|
||||
getPath: this.getPath,
|
||||
getRoots: roots,
|
||||
getRoots: this.getRoots,
|
||||
highlightItems,
|
||||
itemHeight: 21,
|
||||
key: isEmpty ? "empty" : "full",
|
||||
key: this.isEmpty() ? "empty" : "full",
|
||||
listItems,
|
||||
onCollapse,
|
||||
onExpand,
|
||||
onCollapse: this.onCollapse,
|
||||
onExpand: this.onExpand,
|
||||
onFocus: this.focusItem,
|
||||
renderItem: this.renderItem
|
||||
};
|
||||
return _react2.default.createElement(_ManagedTree2.default, treeProps);
|
||||
}
|
||||
|
||||
const tree = _react2.default.createElement(_ManagedTree2.default, treeProps);
|
||||
|
||||
const onKeyDown = e => {
|
||||
if (e.keyCode === 13 && focusedItem) {
|
||||
this.selectItem(focusedItem);
|
||||
}
|
||||
};
|
||||
|
||||
renderPane(...children) {
|
||||
const {
|
||||
projectRoot
|
||||
} = this.props;
|
||||
return _react2.default.createElement("div", {
|
||||
key: "pane",
|
||||
className: (0, _classnames2.default)("sources-pane", {
|
||||
"sources-list-custom-root": isCustomRoot
|
||||
"sources-list-custom-root": projectRoot
|
||||
})
|
||||
}, isCustomRoot ? _react2.default.createElement("div", {
|
||||
className: "sources-clear-root-container"
|
||||
}, clearProjectRootButton) : null, isEmpty ? this.renderEmptyElement(L10N.getStr("sources.noSourcesAvailableRoot")) : _react2.default.createElement("div", {
|
||||
}, children);
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
projectRoot
|
||||
} = this.props;
|
||||
|
||||
if (this.isEmpty()) {
|
||||
if (projectRoot) {
|
||||
return this.renderPane(this.renderProjectRootHeader(), this.renderEmptyElement(L10N.getStr("sources.noSourcesAvailableRoot")));
|
||||
}
|
||||
|
||||
return this.renderPane(this.renderEmptyElement(L10N.getStr("sources.noSourcesAvailable")));
|
||||
}
|
||||
|
||||
return this.renderPane(this.renderProjectRootHeader(), _react2.default.createElement("div", {
|
||||
key: "tree",
|
||||
className: "sources-list",
|
||||
onKeyDown: onKeyDown
|
||||
}, tree));
|
||||
onKeyDown: this.onKeyDown
|
||||
}, this.renderTree()));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -246,25 +259,21 @@ var _initialiseProps = function () {
|
|||
};
|
||||
|
||||
this.selectItem = item => {
|
||||
if (!(0, _sourcesTree.nodeHasChildren)(item)) {
|
||||
this.props.selectLocation({
|
||||
sourceId: item.contents.get("id")
|
||||
});
|
||||
if (!(0, _sourcesTree.isDirectory)(item)) {
|
||||
this.props.selectSource(item.contents.id);
|
||||
}
|
||||
};
|
||||
|
||||
this.getPath = item => {
|
||||
const {
|
||||
sources
|
||||
} = this.props;
|
||||
const obj = item.contents.get && item.contents.get("id");
|
||||
let blackBoxedPart = "";
|
||||
const path = `${item.path}/${item.name}`;
|
||||
|
||||
if (typeof obj !== "undefined" && sources.has(obj) && sources.get(obj).get("isBlackBoxed")) {
|
||||
blackBoxedPart = "update";
|
||||
if ((0, _sourcesTree.isDirectory)(item)) {
|
||||
return path;
|
||||
}
|
||||
|
||||
return `${item.path}/${item.name}/${blackBoxedPart}`;
|
||||
const source = this.getSource(item);
|
||||
const blackBoxedPart = source.isBlackBoxed ? ":blackboxed" : "";
|
||||
return `${path}${blackBoxedPart}`;
|
||||
};
|
||||
|
||||
this.getIcon = (sources, item, depth) => {
|
||||
|
@ -295,17 +304,15 @@ var _initialiseProps = function () {
|
|||
});
|
||||
}
|
||||
|
||||
if (!(0, _sourcesTree.nodeHasChildren)(item)) {
|
||||
const obj = item.contents.get("id");
|
||||
const source = sources.get(obj);
|
||||
const className = (0, _classnames2.default)((0, _source.getSourceClassnames)(source), "source-icon");
|
||||
if ((0, _sourcesTree.isDirectory)(item)) {
|
||||
return _react2.default.createElement("img", {
|
||||
className: className
|
||||
className: "folder"
|
||||
});
|
||||
}
|
||||
|
||||
const source = this.getSource(item);
|
||||
return _react2.default.createElement("img", {
|
||||
className: "folder"
|
||||
className: (0, _classnames2.default)((0, _source.getSourceClassnames)(source), "source-icon")
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -320,13 +327,12 @@ var _initialiseProps = function () {
|
|||
const menuOptions = [];
|
||||
|
||||
if (!(0, _sourcesTree.isDirectory)(item)) {
|
||||
const source = item.contents.get("url");
|
||||
const copySourceUri2 = {
|
||||
id: "node-menu-copy-source",
|
||||
label: copySourceUri2Label,
|
||||
accesskey: copySourceUri2Key,
|
||||
disabled: false,
|
||||
click: () => (0, _clipboard.copyToTheClipboard)(source)
|
||||
click: () => (0, _clipboard.copyToTheClipboard)(item.contents.url)
|
||||
};
|
||||
menuOptions.push(copySourceUri2);
|
||||
}
|
||||
|
@ -360,6 +366,24 @@ var _initialiseProps = function () {
|
|||
(0, _devtoolsContextmenu.showMenu)(event, menuOptions);
|
||||
};
|
||||
|
||||
this.onExpand = (item, expandedState) => {
|
||||
this.props.setExpandedState(expandedState);
|
||||
};
|
||||
|
||||
this.onCollapse = (item, expandedState) => {
|
||||
this.props.setExpandedState(expandedState);
|
||||
};
|
||||
|
||||
this.onKeyDown = e => {
|
||||
const {
|
||||
focusedItem
|
||||
} = this.state;
|
||||
|
||||
if (e.keyCode === 13 && focusedItem) {
|
||||
this.selectItem(focusedItem);
|
||||
}
|
||||
};
|
||||
|
||||
this.renderItem = (item, depth, focused, _, expanded, {
|
||||
setExpanded
|
||||
}) => {
|
||||
|
@ -393,6 +417,28 @@ var _initialiseProps = function () {
|
|||
className: "label"
|
||||
}, " ", this.renderItemName(item.name), " "));
|
||||
};
|
||||
|
||||
this.getRoots = () => {
|
||||
const {
|
||||
projectRoot
|
||||
} = this.props;
|
||||
const {
|
||||
sourceTree
|
||||
} = this.state;
|
||||
const sourceContents = sourceTree.contents[0];
|
||||
const rootLabel = projectRoot.split("/").pop(); // The "sourceTree.contents[0]" check ensures that there are contents
|
||||
// A custom root with no existing sources will be ignored
|
||||
|
||||
if (projectRoot) {
|
||||
if (sourceContents && sourceContents.name !== rootLabel) {
|
||||
return sourceContents.contents[0].contents;
|
||||
}
|
||||
|
||||
return sourceContents.contents;
|
||||
}
|
||||
|
||||
return sourceTree.contents;
|
||||
};
|
||||
};
|
||||
|
||||
const mapStateToProps = state => {
|
||||
|
@ -408,7 +454,7 @@ const mapStateToProps = state => {
|
|||
|
||||
const actionCreators = {
|
||||
setExpandedState: _sourceTree.setExpandedState,
|
||||
selectLocation: _sources.selectLocation,
|
||||
selectSource: _sources.selectSource,
|
||||
setProjectDirectoryRoot: _ui.setProjectDirectoryRoot,
|
||||
clearProjectDirectoryRoot: _ui.clearProjectDirectoryRoot
|
||||
};
|
||||
|
|
|
@ -3,7 +3,17 @@
|
|||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.showLoading = exports.showErrorMessage = exports.showSourceText = exports.clearEditor = exports.updateDocument = exports.updateLineNumberFormat = exports.clearDocuments = exports.removeDocument = exports.hasDocument = exports.setDocument = exports.getDocument = undefined;
|
||||
exports.getDocument = getDocument;
|
||||
exports.hasDocument = hasDocument;
|
||||
exports.setDocument = setDocument;
|
||||
exports.removeDocument = removeDocument;
|
||||
exports.clearDocuments = clearDocuments;
|
||||
exports.updateLineNumberFormat = updateLineNumberFormat;
|
||||
exports.updateDocument = updateDocument;
|
||||
exports.clearEditor = clearEditor;
|
||||
exports.showLoading = showLoading;
|
||||
exports.showErrorMessage = showErrorMessage;
|
||||
exports.showSourceText = showSourceText;
|
||||
|
||||
var _source = require("../source");
|
||||
|
||||
|
@ -168,16 +178,4 @@ function showSourceText(editor, source, symbols) {
|
|||
setEditorText(editor, source);
|
||||
editor.setMode((0, _source.getMode)(source, symbols));
|
||||
updateLineNumberFormat(editor, source.id);
|
||||
}
|
||||
|
||||
exports.getDocument = getDocument;
|
||||
exports.setDocument = setDocument;
|
||||
exports.hasDocument = hasDocument;
|
||||
exports.removeDocument = removeDocument;
|
||||
exports.clearDocuments = clearDocuments;
|
||||
exports.updateLineNumberFormat = updateLineNumberFormat;
|
||||
exports.updateDocument = updateDocument;
|
||||
exports.clearEditor = clearEditor;
|
||||
exports.showSourceText = showSourceText;
|
||||
exports.showErrorMessage = showErrorMessage;
|
||||
exports.showLoading = showLoading;
|
||||
}
|
|
@ -3,6 +3,11 @@
|
|||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.basename = basename;
|
||||
exports.dirname = dirname;
|
||||
exports.isURL = isURL;
|
||||
exports.isAbsolute = isAbsolute;
|
||||
exports.join = join;
|
||||
|
||||
/* 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
|
||||
|
@ -26,10 +31,4 @@ function isAbsolute(str) {
|
|||
|
||||
function join(base, dir) {
|
||||
return `${base}/${dir}`;
|
||||
}
|
||||
|
||||
exports.basename = basename;
|
||||
exports.dirname = dirname;
|
||||
exports.isURL = isURL;
|
||||
exports.isAbsolute = isAbsolute;
|
||||
exports.join = join;
|
||||
}
|
|
@ -3,7 +3,7 @@
|
|||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.scrollList = undefined;
|
||||
exports.scrollList = scrollList;
|
||||
|
||||
var _devtoolsEnvironment = require("devtools/client/debugger/new/dist/vendors").vendored["devtools-environment"];
|
||||
|
||||
|
@ -53,6 +53,4 @@ function chromeScrollList(elem, index) {
|
|||
const itemOffset = resultsHeight % itemHeight;
|
||||
const scroll = positionsToScroll * (itemHeight + 2) + itemOffset;
|
||||
resultsEl.scrollTop = Math.max(0, scroll);
|
||||
}
|
||||
|
||||
exports.scrollList = scrollList;
|
||||
}
|
|
@ -426,17 +426,12 @@ function isLoading(source) {
|
|||
}
|
||||
|
||||
function getTextAtPosition(source, location) {
|
||||
if (!source || !source.text) {
|
||||
if (!source || !source.text || source.isWasm) {
|
||||
return "";
|
||||
}
|
||||
|
||||
const line = location.line;
|
||||
const column = location.column || 0;
|
||||
|
||||
if (source.isWasm) {
|
||||
return "";
|
||||
}
|
||||
|
||||
const lineText = source.text.split("\n")[line - 1];
|
||||
|
||||
if (!lineText) {
|
||||
|
@ -466,5 +461,5 @@ function getSourceClassnames(source, sourceMetaData) {
|
|||
return "blackBox";
|
||||
}
|
||||
|
||||
return sourceTypes[(0, _sourcesTree.getExtension)(source.url)] || defaultClassName;
|
||||
return sourceTypes[(0, _sourcesTree.getFileExtension)(source.url)] || defaultClassName;
|
||||
}
|
|
@ -129,7 +129,7 @@ function addSourceToNode(node, url, source) {
|
|||
|
||||
|
||||
function addToTree(tree, source, debuggeeUrl, projectRoot) {
|
||||
const url = (0, _getURL.getURL)(source.get("url"), debuggeeUrl);
|
||||
const url = (0, _getURL.getURL)(source.get ? source.get("url") : source.url, debuggeeUrl);
|
||||
const debuggeeHost = (0, _treeOrder.getDomain)(debuggeeUrl);
|
||||
|
||||
if ((0, _utils.isInvalidUrl)(url, source) || !isUnderRoot(url, projectRoot)) {
|
||||
|
|
|
@ -102,6 +102,12 @@ Object.defineProperty(exports, "createParentMap", {
|
|||
return _utils.createParentMap;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "getFileExtension", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _utils.getFileExtension;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "getRelativePath", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
|
@ -131,10 +137,4 @@ Object.defineProperty(exports, "nodeHasChildren", {
|
|||
get: function () {
|
||||
return _utils.nodeHasChildren;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "getExtension", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _utils.getExtension;
|
||||
}
|
||||
});
|
|
@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", {
|
|||
exports.nodeHasChildren = nodeHasChildren;
|
||||
exports.isExactUrlMatch = isExactUrlMatch;
|
||||
exports.isDirectory = isDirectory;
|
||||
exports.getExtension = getExtension;
|
||||
exports.getFileExtension = getFileExtension;
|
||||
exports.isNotJavaScript = isNotJavaScript;
|
||||
exports.isInvalidUrl = isInvalidUrl;
|
||||
exports.partIsFile = partIsFile;
|
||||
|
@ -47,7 +47,7 @@ function isDirectory(url) {
|
|||
return (parts.length === 0 || url.path.slice(-1) === "/" || nodeHasChildren(url)) && url.name != "(index)";
|
||||
}
|
||||
|
||||
function getExtension(url = "") {
|
||||
function getFileExtension(url = "") {
|
||||
const parsedUrl = (0, _url.parse)(url).pathname;
|
||||
|
||||
if (!parsedUrl) {
|
||||
|
@ -58,11 +58,11 @@ function getExtension(url = "") {
|
|||
}
|
||||
|
||||
function isNotJavaScript(source) {
|
||||
return ["css", "svg", "png"].includes(getExtension(source.url));
|
||||
return ["css", "svg", "png"].includes(getFileExtension(source.url));
|
||||
}
|
||||
|
||||
function isInvalidUrl(url, source) {
|
||||
return IGNORED_URLS.indexOf(url) != -1 || !source.get("url") || !url.group || (0, _source.isPretty)(source) || isNotJavaScript(source);
|
||||
return IGNORED_URLS.indexOf(url) != -1 || !(source.get ? source.get("url") : source.url) || !url.group || (0, _source.isPretty)(source) || isNotJavaScript(source);
|
||||
}
|
||||
|
||||
function partIsFile(index, parts, url) {
|
||||
|
|
|
@ -15,7 +15,7 @@ Object.defineProperty(exports, "__esModule", {
|
|||
/**
|
||||
* This object provides the public module functions.
|
||||
*/
|
||||
const Task = {
|
||||
const Task = exports.Task = {
|
||||
// XXX: Not sure if this works in all cases...
|
||||
async: function (task) {
|
||||
return function () {
|
||||
|
@ -49,5 +49,4 @@ const Task = {
|
|||
callNext(undefined);
|
||||
});
|
||||
}
|
||||
};
|
||||
exports.Task = Task;
|
||||
};
|
|
@ -3,7 +3,8 @@
|
|||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.truncateMiddleText = exports.formatKeyShortcut = undefined;
|
||||
exports.formatKeyShortcut = formatKeyShortcut;
|
||||
exports.truncateMiddleText = truncateMiddleText;
|
||||
|
||||
var _devtoolsModules = require("devtools/client/debugger/new/dist/vendors").vendored["devtools-modules"];
|
||||
|
||||
|
@ -59,7 +60,4 @@ function truncateMiddleText(sourceText, maxLength) {
|
|||
}
|
||||
|
||||
return truncatedText;
|
||||
}
|
||||
|
||||
exports.formatKeyShortcut = formatKeyShortcut;
|
||||
exports.truncateMiddleText = truncateMiddleText;
|
||||
}
|
|
@ -3,6 +3,10 @@
|
|||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.handleError = handleError;
|
||||
exports.promisify = promisify;
|
||||
exports.endTruncateStr = endTruncateStr;
|
||||
exports.waitForMs = waitForMs;
|
||||
|
||||
/* 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
|
||||
|
@ -54,9 +58,4 @@ function endTruncateStr(str, size) {
|
|||
|
||||
function waitForMs(ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
exports.handleError = handleError;
|
||||
exports.promisify = promisify;
|
||||
exports.endTruncateStr = endTruncateStr;
|
||||
exports.waitForMs = waitForMs;
|
||||
}
|
|
@ -3,7 +3,13 @@
|
|||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.renderWasmText = exports.clearWasmStates = exports.wasmOffsetToLine = exports.lineToWasmOffset = exports.isWasm = exports.getWasmLineNumberFormatter = exports.getWasmText = undefined;
|
||||
exports.getWasmText = getWasmText;
|
||||
exports.getWasmLineNumberFormatter = getWasmLineNumberFormatter;
|
||||
exports.isWasm = isWasm;
|
||||
exports.lineToWasmOffset = lineToWasmOffset;
|
||||
exports.wasmOffsetToLine = wasmOffsetToLine;
|
||||
exports.clearWasmStates = clearWasmStates;
|
||||
exports.renderWasmText = renderWasmText;
|
||||
|
||||
var _WasmParser = require("devtools/client/shared/vendor/WasmParser");
|
||||
|
||||
|
@ -179,12 +185,4 @@ function renderWasmText(sourceId, {
|
|||
}
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
exports.getWasmText = getWasmText;
|
||||
exports.getWasmLineNumberFormatter = getWasmLineNumberFormatter;
|
||||
exports.isWasm = isWasm;
|
||||
exports.lineToWasmOffset = lineToWasmOffset;
|
||||
exports.wasmOffsetToLine = wasmOffsetToLine;
|
||||
exports.clearWasmStates = clearWasmStates;
|
||||
exports.renderWasmText = renderWasmText;
|
||||
}
|
|
@ -56,7 +56,7 @@ function isYieldExpression(path) {
|
|||
}
|
||||
|
||||
function isObjectShorthand(parent) {
|
||||
return t.isObjectProperty(parent) && parent.key.start == parent.value.start && parent.key.loc.identifierName === parent.value.loc.identifierName;
|
||||
return t.isObjectProperty(parent) && parent.value && parent.key.start == parent.value.start && parent.key.loc.identifierName === parent.value.loc.identifierName;
|
||||
}
|
||||
|
||||
function getObjectExpressionValue(node) {
|
||||
|
|
|
@ -226,6 +226,10 @@ html[dir="rtl"] .tree-node img.arrow {
|
|||
padding: 0 2px;
|
||||
}
|
||||
|
||||
.objectBox-node.clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
.objectBox-event,
|
||||
|
@ -332,6 +336,7 @@ button.open-inspector {
|
|||
height: 16px;
|
||||
margin-left: 0.25em;
|
||||
vertical-align: middle;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.objectBox-node:hover .open-inspector,
|
||||
|
|
|
@ -5680,7 +5680,8 @@ function ElementNode(props) {
|
|||
if (isInTree) {
|
||||
if (onDOMNodeClick) {
|
||||
Object.assign(baseConfig, {
|
||||
onClick: _ => onDOMNodeClick(object)
|
||||
onClick: _ => onDOMNodeClick(object),
|
||||
className: `${baseConfig.className} clickable`
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -503,8 +503,15 @@ const AccessibleWalkerActor = ActorClassWithSpec(accessibleWalkerSpec, {
|
|||
* A helper method. Accessibility walker is assumed to have only 1 child which
|
||||
* is the top level document.
|
||||
*/
|
||||
children() {
|
||||
return Promise.all([this.getDocument()]);
|
||||
async children() {
|
||||
if (this._childrenPromise) {
|
||||
return this._childrenPromise;
|
||||
}
|
||||
|
||||
this._childrenPromise = Promise.all([this.getDocument()]);
|
||||
let children = await this._childrenPromise;
|
||||
this._childrenPromise = null;
|
||||
return children;
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -162,7 +162,7 @@ SendPing(void* aClosure, nsIContent* aContent, nsIURI* aURI,
|
|||
|
||||
if (sm && info->referrer) {
|
||||
bool referrerIsSecure;
|
||||
uint32_t flags = nsIProtocolHandler::URI_SAFE_TO_LOAD_IN_SECURE_CONTEXT;
|
||||
uint32_t flags = nsIProtocolHandler::URI_IS_POTENTIALLY_TRUSTWORTHY;
|
||||
rv = NS_URIChainHasFlags(info->referrer, flags, &referrerIsSecure);
|
||||
|
||||
// Default to sending less data if NS_URIChainHasFlags() fails.
|
||||
|
|
|
@ -184,5 +184,17 @@ DocGroup::MoveSignalSlotListTo(nsTArray<RefPtr<HTMLSlotElement>>& aDest)
|
|||
mSignalSlotList.Clear();
|
||||
}
|
||||
|
||||
bool
|
||||
DocGroup::IsActive() const
|
||||
{
|
||||
for (nsIDocument* doc : mDocuments) {
|
||||
if (doc->IsCurrentActiveDocument()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -122,6 +122,9 @@ public:
|
|||
// List of DocGroups that has non-empty signal slot list.
|
||||
static AutoTArray<RefPtr<DocGroup>, 2>* sPendingDocGroups;
|
||||
|
||||
// Returns true if any of its documents are active but not in the bfcache.
|
||||
bool IsActive() const;
|
||||
|
||||
private:
|
||||
DocGroup(TabGroup* aTabGroup, const nsACString& aKey);
|
||||
~DocGroup();
|
||||
|
|
|
@ -306,5 +306,22 @@ TabGroup::IsBackground() const
|
|||
return mForegroundCount == 0;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
TabGroup::Count(bool aActiveOnly) const
|
||||
{
|
||||
if (!aActiveOnly) {
|
||||
return mDocGroups.Count();
|
||||
}
|
||||
|
||||
uint32_t count = 0;
|
||||
for (auto iter = mDocGroups.ConstIter(); !iter.Done(); iter.Next()) {
|
||||
if (iter.Get()->mDocGroup->IsActive()) {
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -100,6 +100,10 @@ public:
|
|||
return mDocGroups.Iter();
|
||||
}
|
||||
|
||||
// Returns the size of the set of "similar-origin" DocGroups. To
|
||||
// only consider DocGroups with at least one active document, call
|
||||
// Count with 'aActiveOnly' = true
|
||||
uint32_t Count(bool aActiveOnly = false) const;
|
||||
|
||||
// Returns the nsIDocShellTreeItem with the given name, searching each of the
|
||||
// docShell trees which are within this TabGroup. It will pass itself as
|
||||
|
|
|
@ -172,7 +172,6 @@
|
|||
#include "nsIStreamConverterService.h"
|
||||
#include "nsIStringBundle.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsIURIWithPrincipal.h"
|
||||
#include "nsIURL.h"
|
||||
#include "nsIWebNavigation.h"
|
||||
#include "nsIWindowMediator.h"
|
||||
|
@ -3085,12 +3084,12 @@ nsContentUtils::SubjectPrincipal(JSContext* aCx)
|
|||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// As opposed to SubjectPrincipal(), we do in fact assume that
|
||||
// we're in a compartment here; anyone who calls this function
|
||||
// in situations where that's not the case is doing it wrong.
|
||||
JSCompartment* compartment = js::GetContextCompartment(aCx);
|
||||
MOZ_ASSERT(compartment);
|
||||
// we're in a realm here; anyone who calls this function in
|
||||
// situations where that's not the case is doing it wrong.
|
||||
JS::Realm* realm = js::GetContextRealm(aCx);
|
||||
MOZ_ASSERT(realm);
|
||||
|
||||
JSPrincipals* principals = JS_GetCompartmentPrincipals(compartment);
|
||||
JSPrincipals* principals = JS::GetRealmPrincipals(realm);
|
||||
return nsJSPrincipals::get(principals);
|
||||
}
|
||||
|
||||
|
@ -3105,9 +3104,9 @@ nsContentUtils::SubjectPrincipal()
|
|||
MOZ_CRASH("Accessing the Subject Principal without an AutoJSAPI on the stack is forbidden");
|
||||
}
|
||||
|
||||
JSCompartment *compartment = js::GetContextCompartment(cx);
|
||||
JS::Realm* realm = js::GetContextRealm(cx);
|
||||
|
||||
// When an AutoJSAPI is instantiated, we are in a null compartment until the
|
||||
// When an AutoJSAPI is instantiated, we are in a null realm until the
|
||||
// first JSAutoRealm, which is kind of a purgatory as far as permissions
|
||||
// go. It would be nice to just hard-abort if somebody does a security check
|
||||
// in this purgatory zone, but that would be too fragile, since it could be
|
||||
|
@ -3125,9 +3124,9 @@ nsContentUtils::SubjectPrincipal()
|
|||
//
|
||||
// So we use a singleton null principal. To avoid it being accidentally
|
||||
// inherited and becoming a "real" subject or object principal, we do a
|
||||
// release-mode assert during compartment creation against using this
|
||||
// principal on an actual global.
|
||||
if (!compartment) {
|
||||
// release-mode assert during realm creation against using this principal on
|
||||
// an actual global.
|
||||
if (!realm) {
|
||||
return sNullSubjectPrincipal;
|
||||
}
|
||||
|
||||
|
@ -6285,21 +6284,24 @@ nsContentUtils::GetASCIIOrigin(nsIURI* aURI, nsACString& aOrigin)
|
|||
{
|
||||
MOZ_ASSERT(aURI, "missing uri");
|
||||
|
||||
// For Blob URI we have to return the origin of page using its principal.
|
||||
nsCOMPtr<nsIURIWithPrincipal> uriWithPrincipal = do_QueryInterface(aURI);
|
||||
if (uriWithPrincipal) {
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
uriWithPrincipal->GetPrincipal(getter_AddRefs(principal));
|
||||
bool isBlobURL = false;
|
||||
nsresult rv = aURI->SchemeIs(BLOBURI_SCHEME, &isBlobURL);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (principal) {
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
nsresult rv = principal->GetURI(getter_AddRefs(uri));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
// For Blob URI, the path is the URL of the owning page.
|
||||
if (isBlobURL) {
|
||||
nsAutoCString path;
|
||||
rv = aURI->GetPathQueryRef(path);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (uri && uri != aURI) {
|
||||
return GetASCIIOrigin(uri, aOrigin);
|
||||
}
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
nsresult rv = NS_NewURI(getter_AddRefs(uri), path);
|
||||
if (NS_FAILED(rv)) {
|
||||
aOrigin.AssignLiteral("null");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return GetASCIIOrigin(uri, aOrigin);
|
||||
}
|
||||
|
||||
aOrigin.Truncate();
|
||||
|
@ -6308,7 +6310,7 @@ nsContentUtils::GetASCIIOrigin(nsIURI* aURI, nsACString& aOrigin)
|
|||
NS_ENSURE_TRUE(uri, NS_ERROR_UNEXPECTED);
|
||||
|
||||
nsCString host;
|
||||
nsresult rv = uri->GetAsciiHost(host);
|
||||
rv = uri->GetAsciiHost(host);
|
||||
|
||||
if (NS_SUCCEEDED(rv) && !host.IsEmpty()) {
|
||||
nsCString scheme;
|
||||
|
|
|
@ -2364,9 +2364,9 @@ nsIDocument::ResetToURI(nsIURI* aURI,
|
|||
mFontFaceSet->RefreshStandardFontLoadPrincipal();
|
||||
}
|
||||
|
||||
// Refresh the principal on the compartment.
|
||||
// Refresh the principal on the realm.
|
||||
if (nsPIDOMWindowInner* win = GetInnerWindow()) {
|
||||
nsGlobalWindowInner::Cast(win)->RefreshCompartmentPrincipal();
|
||||
nsGlobalWindowInner::Cast(win)->RefreshRealmPrincipal();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8495,6 +8495,18 @@ static void ClearPendingFullscreenRequests(nsIDocument* aDoc);
|
|||
void
|
||||
nsIDocument::OnPageHide(bool aPersisted, EventTarget* aDispatchStartTarget)
|
||||
{
|
||||
if (mDocGroup && Telemetry::CanRecordExtended() &&
|
||||
IsTopLevelContentDocument()) {
|
||||
TabGroup* tabGroup = mDocGroup->GetTabGroup();
|
||||
|
||||
if (tabGroup) {
|
||||
Telemetry::Accumulate(Telemetry::ACTIVE_DOCGROUPS_PER_TABGROUP,
|
||||
tabGroup->Count(true /* aActiveOnly */));
|
||||
Telemetry::Accumulate(Telemetry::TOTAL_DOCGROUPS_PER_TABGROUP,
|
||||
tabGroup->Count());
|
||||
}
|
||||
}
|
||||
|
||||
// Send out notifications that our <link> elements are detached,
|
||||
// but only if this is not a full unload.
|
||||
Element* root = GetRootElement();
|
||||
|
|
|
@ -3632,10 +3632,10 @@ nsGlobalWindowInner::GetChildWindow(const nsAString& aName)
|
|||
}
|
||||
|
||||
void
|
||||
nsGlobalWindowInner::RefreshCompartmentPrincipal()
|
||||
nsGlobalWindowInner::RefreshRealmPrincipal()
|
||||
{
|
||||
JS_SetCompartmentPrincipals(js::GetObjectCompartment(GetWrapperPreserveColor()),
|
||||
nsJSPrincipals::get(mDoc->NodePrincipal()));
|
||||
JS::SetRealmPrincipals(js::GetNonCCWObjectRealm(GetWrapperPreserveColor()),
|
||||
nsJSPrincipals::get(mDoc->NodePrincipal()));
|
||||
}
|
||||
|
||||
already_AddRefed<nsIWidget>
|
||||
|
|
|
@ -377,7 +377,7 @@ public:
|
|||
virtual void MaybeUpdateTouchState() override;
|
||||
|
||||
// Inner windows only.
|
||||
void RefreshCompartmentPrincipal();
|
||||
void RefreshRealmPrincipal();
|
||||
|
||||
// For accessing protected field mFullScreen
|
||||
friend class FullscreenTransitionTask;
|
||||
|
|
|
@ -1747,24 +1747,26 @@ nsGlobalWindowOuter::SetNewDocument(nsIDocument* aDocument,
|
|||
}
|
||||
|
||||
// Inner windows are only reused for same-origin principals, but the principals
|
||||
// don't necessarily match exactly. Update the principal on the compartment to
|
||||
// match the new document.
|
||||
// NB: We don't just call currentInner->RefreshCompartmentPrincipals() here
|
||||
// don't necessarily match exactly. Update the principal on the realm to match
|
||||
// the new document.
|
||||
// NB: We don't just call currentInner->RefreshRealmPrincipals() here
|
||||
// because we haven't yet set its mDoc to aDocument.
|
||||
JSCompartment *compartment = js::GetObjectCompartment(newInnerGlobal);
|
||||
JS::Realm* realm = js::GetNonCCWObjectRealm(newInnerGlobal);
|
||||
#ifdef DEBUG
|
||||
bool sameOrigin = false;
|
||||
nsIPrincipal *existing =
|
||||
nsJSPrincipals::get(JS_GetCompartmentPrincipals(compartment));
|
||||
nsJSPrincipals::get(JS::GetRealmPrincipals(realm));
|
||||
aDocument->NodePrincipal()->Equals(existing, &sameOrigin);
|
||||
MOZ_ASSERT(sameOrigin);
|
||||
#endif
|
||||
|
||||
JSCompartment* compartment = JS::GetCompartmentForRealm(realm);
|
||||
MOZ_ASSERT_IF(aDocument == oldDoc,
|
||||
xpc::GetCompartmentPrincipal(compartment) ==
|
||||
aDocument->NodePrincipal());
|
||||
#endif
|
||||
if (aDocument != oldDoc) {
|
||||
JS_SetCompartmentPrincipals(compartment,
|
||||
nsJSPrincipals::get(aDocument->NodePrincipal()));
|
||||
JS::SetRealmPrincipals(realm,
|
||||
nsJSPrincipals::get(aDocument->NodePrincipal()));
|
||||
// Make sure we clear out the old content XBL scope, so the new one will
|
||||
// get created with a principal that subsumes our new principal.
|
||||
xpc::ClearContentXBLScope(newInnerGlobal);
|
||||
|
@ -1980,13 +1982,13 @@ nsGlobalWindowOuter::SetNewDocument(nsIDocument* aDocument,
|
|||
currentInner = nullptr;
|
||||
|
||||
// Ask the JS engine to assert that it's valid to access our DocGroup whenever
|
||||
// it runs JS code for this compartment. We skip the check if this window is
|
||||
// for chrome JS or an add-on.
|
||||
// it runs JS code for this realm. We skip the check if this window is for
|
||||
// chrome JS or an add-on.
|
||||
nsCOMPtr<nsIPrincipal> principal = mDoc->NodePrincipal();
|
||||
if (GetDocGroup() && !nsContentUtils::IsSystemPrincipal(principal) &&
|
||||
!BasePrincipal::Cast(principal)->AddonPolicy()) {
|
||||
js::SetCompartmentValidAccessPtr(cx, newInnerGlobal,
|
||||
newInnerWindow->GetDocGroup()->GetValidAccessPtr());
|
||||
js::SetRealmValidAccessPtr(cx, newInnerGlobal,
|
||||
newInnerWindow->GetDocGroup()->GetValidAccessPtr());
|
||||
}
|
||||
|
||||
kungFuDeathGrip->DidInitializeContext();
|
||||
|
|
|
@ -2563,7 +2563,7 @@ AsmJSCacheOpenEntryForRead(JS::Handle<JSObject*> aGlobal,
|
|||
intptr_t *aHandle)
|
||||
{
|
||||
nsIPrincipal* principal =
|
||||
nsJSPrincipals::get(JS_GetCompartmentPrincipals(js::GetObjectCompartment(aGlobal)));
|
||||
nsJSPrincipals::get(JS::GetRealmPrincipals(js::GetNonCCWObjectRealm(aGlobal)));
|
||||
return asmjscache::OpenEntryForRead(principal, aBegin, aLimit, aSize, aMemory,
|
||||
aHandle);
|
||||
}
|
||||
|
@ -2577,7 +2577,7 @@ AsmJSCacheOpenEntryForWrite(JS::Handle<JSObject*> aGlobal,
|
|||
intptr_t* aHandle)
|
||||
{
|
||||
nsIPrincipal* principal =
|
||||
nsJSPrincipals::get(JS_GetCompartmentPrincipals(js::GetObjectCompartment(aGlobal)));
|
||||
nsJSPrincipals::get(JS::GetRealmPrincipals(js::GetNonCCWObjectRealm(aGlobal)));
|
||||
return asmjscache::OpenEntryForWrite(principal, aBegin, aEnd, aSize, aMemory,
|
||||
aHandle);
|
||||
}
|
||||
|
|
|
@ -2462,9 +2462,9 @@ GlobalObject::GetSubjectPrincipal() const
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
JSCompartment* compartment = js::GetContextCompartment(mCx);
|
||||
MOZ_ASSERT(compartment);
|
||||
JSPrincipals* principals = JS_GetCompartmentPrincipals(compartment);
|
||||
JS::Realm* realm = js::GetContextRealm(mCx);
|
||||
MOZ_ASSERT(realm);
|
||||
JSPrincipals* principals = JS::GetRealmPrincipals(realm);
|
||||
return nsJSPrincipals::get(principals);
|
||||
}
|
||||
|
||||
|
|
|
@ -133,10 +133,10 @@ CallbackObject::CallSetup::CallSetup(CallbackObject* aCallback,
|
|||
ErrorResult& aRv,
|
||||
const char* aExecutionReason,
|
||||
ExceptionHandling aExceptionHandling,
|
||||
JSCompartment* aCompartment,
|
||||
JS::Realm* aRealm,
|
||||
bool aIsJSImplementedWebIDL)
|
||||
: mCx(nullptr)
|
||||
, mCompartment(aCompartment)
|
||||
, mRealm(aRealm)
|
||||
, mErrorResult(aRv)
|
||||
, mExceptionHandling(aExceptionHandling)
|
||||
, mIsMainThread(NS_IsMainThread())
|
||||
|
@ -261,35 +261,35 @@ bool
|
|||
CallbackObject::CallSetup::ShouldRethrowException(JS::Handle<JS::Value> aException)
|
||||
{
|
||||
if (mExceptionHandling == eRethrowExceptions) {
|
||||
if (!mCompartment) {
|
||||
if (!mRealm) {
|
||||
// Caller didn't ask us to filter for only exceptions we subsume.
|
||||
return true;
|
||||
}
|
||||
|
||||
// On workers, we don't have nsIPrincipals to work with. But we also only
|
||||
// have one compartment, so check whether mCompartment is the same as the
|
||||
// current compartment of mCx.
|
||||
if (mCompartment == js::GetContextCompartment(mCx)) {
|
||||
// have one realm, so check whether mRealm is the same as the current realm
|
||||
// of mCx.
|
||||
if (mRealm == js::GetContextRealm(mCx)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// At this point mCx is in the compartment of our unwrapped callback, so
|
||||
// just check whether the principal of mCompartment subsumes that of the
|
||||
// current compartment/global of mCx.
|
||||
// At this point mCx is in the realm of our unwrapped callback, so just
|
||||
// check whether the principal of mRealm subsumes that of the current
|
||||
// realm/global of mCx.
|
||||
nsIPrincipal* callerPrincipal =
|
||||
nsJSPrincipals::get(JS_GetCompartmentPrincipals(mCompartment));
|
||||
nsJSPrincipals::get(JS::GetRealmPrincipals(mRealm));
|
||||
nsIPrincipal* calleePrincipal = nsContentUtils::SubjectPrincipal();
|
||||
if (callerPrincipal->SubsumesConsideringDomain(calleePrincipal)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mCompartment);
|
||||
MOZ_ASSERT(mRealm);
|
||||
|
||||
// Now we only want to throw an exception to the caller if the object that was
|
||||
// thrown is in the caller compartment (which we stored in mCompartment).
|
||||
// thrown is in the caller realm (which we stored in mRealm).
|
||||
|
||||
if (!aException.isObject()) {
|
||||
return false;
|
||||
|
@ -297,7 +297,7 @@ CallbackObject::CallSetup::ShouldRethrowException(JS::Handle<JS::Value> aExcepti
|
|||
|
||||
JS::Rooted<JSObject*> obj(mCx, &aException.toObject());
|
||||
obj = js::UncheckedUnwrap(obj, /* stopAtWindowProxy = */ false);
|
||||
return js::GetObjectCompartment(obj) == mCompartment;
|
||||
return js::GetNonCCWObjectRealm(obj) == mRealm;
|
||||
}
|
||||
|
||||
CallbackObject::CallSetup::~CallSetup()
|
||||
|
@ -313,7 +313,7 @@ CallbackObject::CallSetup::~CallSetup()
|
|||
// were told to re-throw them.
|
||||
if (mCx) {
|
||||
bool needToDealWithException = mAutoEntryScript->HasException();
|
||||
if ((mCompartment && mExceptionHandling == eRethrowContentExceptions) ||
|
||||
if ((mRealm && mExceptionHandling == eRethrowContentExceptions) ||
|
||||
mExceptionHandling == eRethrowExceptions) {
|
||||
mErrorResult.MightThrowJSException();
|
||||
if (needToDealWithException) {
|
||||
|
@ -349,7 +349,7 @@ CallbackObject::CallSetup::~CallSetup()
|
|||
mAutoEntryScript.reset();
|
||||
|
||||
// It is important that this is the last thing we do, after leaving the
|
||||
// compartment and undoing all our entry/incumbent script changes
|
||||
// realm and undoing all our entry/incumbent script changes
|
||||
CycleCollectedJSContext* ccjs = CycleCollectedJSContext::Get();
|
||||
if (ccjs) {
|
||||
ccjs->LeaveMicroTask();
|
||||
|
|
|
@ -94,7 +94,7 @@ public:
|
|||
}
|
||||
|
||||
// Like CallbackOrNull(), but will return a new dead proxy object in the
|
||||
// caller's compartment if the callback is null.
|
||||
// caller's realm if the callback is null.
|
||||
JSObject* Callback(JSContext* aCx);
|
||||
|
||||
JSObject* GetCreationStack() const
|
||||
|
@ -146,10 +146,9 @@ public:
|
|||
// binding object for a DOMException from the caller's scope, otherwise
|
||||
// report it.
|
||||
eRethrowContentExceptions,
|
||||
// Throw exceptions to the caller code, unless the caller compartment is
|
||||
// Throw exceptions to the caller code, unless the caller realm is
|
||||
// provided, the exception is not a DOMException from the caller
|
||||
// compartment, and the caller compartment does not subsume our unwrapped
|
||||
// callback.
|
||||
// realm, and the caller realm does not subsume our unwrapped callback.
|
||||
eRethrowExceptions
|
||||
};
|
||||
|
||||
|
@ -295,17 +294,17 @@ protected:
|
|||
* non-null.
|
||||
*/
|
||||
public:
|
||||
// If aExceptionHandling == eRethrowContentExceptions then aCompartment
|
||||
// needs to be set to the compartment in which exceptions will be rethrown.
|
||||
// If aExceptionHandling == eRethrowContentExceptions then aRealm
|
||||
// needs to be set to the realm in which exceptions will be rethrown.
|
||||
//
|
||||
// If aExceptionHandling == eRethrowExceptions then aCompartment may be set
|
||||
// to the compartment in which exceptions will be rethrown. In that case
|
||||
// they will only be rethrown if that compartment's principal subsumes the
|
||||
// If aExceptionHandling == eRethrowExceptions then aRealm may be set
|
||||
// to the realm in which exceptions will be rethrown. In that case
|
||||
// they will only be rethrown if that realm's principal subsumes the
|
||||
// principal of our (unwrapped) callback.
|
||||
CallSetup(CallbackObject* aCallback, ErrorResult& aRv,
|
||||
const char* aExecutionReason,
|
||||
ExceptionHandling aExceptionHandling,
|
||||
JSCompartment* aCompartment = nullptr,
|
||||
JS::Realm* aRealm = nullptr,
|
||||
bool aIsJSImplementedWebIDL = false);
|
||||
~CallSetup();
|
||||
|
||||
|
@ -323,9 +322,9 @@ protected:
|
|||
// Members which can go away whenever
|
||||
JSContext* mCx;
|
||||
|
||||
// Caller's compartment. This will only have a sensible value if
|
||||
// Caller's realm. This will only have a sensible value if
|
||||
// mExceptionHandling == eRethrowContentExceptions or eRethrowExceptions.
|
||||
JSCompartment* mCompartment;
|
||||
JS::Realm* mRealm;
|
||||
|
||||
// And now members whose construction/destruction order we need to control.
|
||||
Maybe<AutoEntryScript> mAutoEntryScript;
|
||||
|
|
|
@ -7236,9 +7236,9 @@ class CGCallGenerator(CGThing):
|
|||
|
||||
getPrincipal = fill(
|
||||
"""
|
||||
JSCompartment* compartment = js::GetContextCompartment(cx);
|
||||
MOZ_ASSERT(compartment);
|
||||
JSPrincipals* principals = JS_GetCompartmentPrincipals(compartment);
|
||||
JS::Realm* realm = js::GetContextRealm(cx);
|
||||
MOZ_ASSERT(realm);
|
||||
JSPrincipals* principals = JS::GetRealmPrincipals(realm);
|
||||
nsIPrincipal* principal = nsJSPrincipals::get(principals);
|
||||
${checkPrincipal}
|
||||
""",
|
||||
|
@ -7563,7 +7563,7 @@ class CGPerSignatureCall(CGThing):
|
|||
if not idlNode.isStatic():
|
||||
needsUnwrap = True
|
||||
needsUnwrappedVar = True
|
||||
argsPost.append("js::GetObjectCompartment(unwrappedObj ? *unwrappedObj : obj)")
|
||||
argsPost.append("(unwrappedObj ? js::GetNonCCWObjectRealm(*unwrappedObj) : js::GetContextRealm(cx))")
|
||||
elif needScopeObject(returnType, arguments, self.extendedAttributes,
|
||||
descriptor.wrapperCache, True,
|
||||
idlNode.getExtendedAttribute("StoreInSlot")):
|
||||
|
@ -15009,7 +15009,7 @@ class CGJSImplMember(CGNativeMember):
|
|||
|
||||
def getArgs(self, returnType, argList):
|
||||
args = CGNativeMember.getArgs(self, returnType, argList)
|
||||
args.append(Argument("JSCompartment*", "aCompartment", "nullptr"))
|
||||
args.append(Argument("JS::Realm*", "aRealm", "nullptr"))
|
||||
return args
|
||||
|
||||
|
||||
|
@ -15058,7 +15058,7 @@ class CGJSImplMethod(CGJSImplMember):
|
|||
assert args[-1].argType == 'JS::Handle<JSObject*>'
|
||||
assert args[-1].name == 'aGivenProto'
|
||||
constructorArgs = [arg.name for arg in args[2:-1]]
|
||||
constructorArgs.append("js::GetObjectCompartment(scopeObj)")
|
||||
constructorArgs.append("js::GetNonCCWObjectRealm(scopeObj)")
|
||||
initCall = fill(
|
||||
"""
|
||||
// Wrap the object before calling __Init so that __DOM_IMPL__ is available.
|
||||
|
@ -15506,9 +15506,9 @@ class CGCallback(CGClass):
|
|||
"nullptr"))
|
||||
|
||||
# Make copies of the arg list for the two "without rv" overloads. Note
|
||||
# that those don't need aExceptionHandling or aCompartment arguments
|
||||
# because those would make not sense anyway: the only sane thing to do
|
||||
# with exceptions in the "without rv" cases is to report them.
|
||||
# that those don't need aExceptionHandling or aRealm arguments because
|
||||
# those would make not sense anyway: the only sane thing to do with
|
||||
# exceptions in the "without rv" cases is to report them.
|
||||
argsWithoutRv = list(args)
|
||||
argsWithoutRv.pop(rvIndex)
|
||||
argsWithoutThisAndRv = list(argsWithoutRv)
|
||||
|
@ -15519,10 +15519,10 @@ class CGCallback(CGClass):
|
|||
"eReportExceptions"))
|
||||
# And the argument for communicating when exceptions should really be
|
||||
# rethrown. In particular, even when aExceptionHandling is
|
||||
# eRethrowExceptions they won't get rethrown if aCompartment is provided
|
||||
# eRethrowExceptions they won't get rethrown if aRealm is provided
|
||||
# and its principal doesn't subsume either the callback or the
|
||||
# exception.
|
||||
args.append(Argument("JSCompartment*", "aCompartment", "nullptr"))
|
||||
args.append(Argument("JS::Realm*", "aRealm", "nullptr"))
|
||||
# And now insert our template argument.
|
||||
argsWithoutThis = list(args)
|
||||
args.insert(0, Argument("const T&", "thisVal"))
|
||||
|
@ -15533,8 +15533,8 @@ class CGCallback(CGClass):
|
|||
# If we just leave things like that, and have no actual arguments in the
|
||||
# IDL, we will end up trying to call the templated "without rv" overload
|
||||
# with "rv" as the thisVal. That's no good. So explicitly append the
|
||||
# aExceptionHandling and aCompartment values we need to end up matching
|
||||
# the signature of our non-templated "with rv" overload.
|
||||
# aExceptionHandling and aRealm values we need to end up matching the
|
||||
# signature of our non-templated "with rv" overload.
|
||||
argnamesWithoutThisAndRv.extend(["eReportExceptions", "nullptr"])
|
||||
|
||||
argnamesWithoutRv = [arg.name for arg in argsWithoutRv]
|
||||
|
@ -15550,7 +15550,7 @@ class CGCallback(CGClass):
|
|||
if (!aExecutionReason) {
|
||||
aExecutionReason = "${executionReason}";
|
||||
}
|
||||
CallSetup s(this, aRv, aExecutionReason, aExceptionHandling, aCompartment);
|
||||
CallSetup s(this, aRv, aExecutionReason, aExceptionHandling, aRealm);
|
||||
if (!s.GetContext()) {
|
||||
MOZ_ASSERT(aRv.Failed());
|
||||
return${errorReturn};
|
||||
|
@ -15961,7 +15961,7 @@ class CallbackMember(CGNativeMember):
|
|||
"nullptr"))
|
||||
args.append(Argument("ExceptionHandling", "aExceptionHandling",
|
||||
"eReportExceptions"))
|
||||
args.append(Argument("JSCompartment*", "aCompartment", "nullptr"))
|
||||
args.append(Argument("JS::Realm*", "aRealm", "nullptr"))
|
||||
return args
|
||||
# We want to allow the caller to pass in a "this" value, as
|
||||
# well as a JSContext.
|
||||
|
@ -15975,11 +15975,11 @@ class CallbackMember(CGNativeMember):
|
|||
callSetup = "CallSetup s(this, aRv"
|
||||
if self.rethrowContentException:
|
||||
# getArgs doesn't add the aExceptionHandling argument but does add
|
||||
# aCompartment for us.
|
||||
callSetup += ', "%s", eRethrowContentExceptions, aCompartment, /* aIsJSImplementedWebIDL = */ ' % self.getPrettyName()
|
||||
# aRealm for us.
|
||||
callSetup += ', "%s", eRethrowContentExceptions, aRealm, /* aIsJSImplementedWebIDL = */ ' % self.getPrettyName()
|
||||
callSetup += toStringBool(isJSImplementedDescriptor(self.descriptorProvider))
|
||||
else:
|
||||
callSetup += ', "%s", aExceptionHandling, aCompartment' % self.getPrettyName()
|
||||
callSetup += ', "%s", aExceptionHandling, aRealm' % self.getPrettyName()
|
||||
callSetup += ");\n"
|
||||
return fill(
|
||||
"""
|
||||
|
|
|
@ -189,7 +189,7 @@ GetCurrentJSStack(int32_t aMaxDepth)
|
|||
// is there a current context available?
|
||||
JSContext* cx = nsContentUtils::GetCurrentJSContext();
|
||||
|
||||
if (!cx || !js::GetContextCompartment(cx)) {
|
||||
if (!cx || !js::GetContextRealm(cx)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
|
@ -73,6 +73,8 @@ skip-if = debug == false
|
|||
skip-if = debug == false
|
||||
[test_jsimplemented_eventhandler.html]
|
||||
skip-if = debug == false
|
||||
[test_jsimplemented_cross_realm_this.html]
|
||||
skip-if = debug == false
|
||||
[test_iterable.html]
|
||||
skip-if = debug == false
|
||||
[test_oom_reporting.html]
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1464374-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 1464374</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1464374">Mozilla Bug 1464374</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
|
||||
<iframe></iframe>
|
||||
<script type="application/javascript">
|
||||
/** Test for Bug 1464374 **/
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function doTest() {
|
||||
var frame = frames[0];
|
||||
var obj = new frame.TestInterfaceJS();
|
||||
var ex;
|
||||
try {
|
||||
TestInterfaceJS.prototype.testThrowTypeError.call(obj);
|
||||
} catch(e) {
|
||||
ex = e;
|
||||
}
|
||||
ok(ex, "Should have an exception");
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
SpecialPowers.pushPrefEnv({set: [['dom.expose_test_interfaces', true]]},
|
||||
doTest);
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -1537,10 +1537,10 @@ nsHTMLDocument::Open(JSContext* cx,
|
|||
SetReadyStateInternal(nsIDocument::READYSTATE_LOADING);
|
||||
|
||||
// After changing everything around, make sure that the principal on the
|
||||
// document's compartment exactly matches NodePrincipal().
|
||||
// document's realm exactly matches NodePrincipal().
|
||||
DebugOnly<JSObject*> wrapper = GetWrapperPreserveColor();
|
||||
MOZ_ASSERT_IF(wrapper,
|
||||
JS_GetCompartmentPrincipals(js::GetObjectCompartment(wrapper)) ==
|
||||
JS::GetRealmPrincipals(js::GetNonCCWObjectRealm(wrapper)) ==
|
||||
nsJSPrincipals::get(NodePrincipal()));
|
||||
|
||||
return kungFuDeathGrip.forget();
|
||||
|
|
|
@ -618,7 +618,7 @@ AutoJSAPI::PeekException(JS::MutableHandle<JS::Value> aVal)
|
|||
{
|
||||
MOZ_ASSERT_IF(mIsMainThread, IsStackTop());
|
||||
MOZ_ASSERT(HasException());
|
||||
MOZ_ASSERT(js::GetContextCompartment(cx()));
|
||||
MOZ_ASSERT(js::GetContextRealm(cx()));
|
||||
if (!JS_GetPendingException(cx(), aVal)) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -890,12 +890,16 @@ nsContentSecurityManager::IsOriginPotentiallyTrustworthy(nsIPrincipal* aPrincipa
|
|||
// which is technically a substituting protocol handler that is not limited to
|
||||
// local resource mapping, but in practice is never mapped remotely as this
|
||||
// would violate assumptions a lot of code makes.
|
||||
if (scheme.EqualsLiteral("https") ||
|
||||
scheme.EqualsLiteral("file") ||
|
||||
scheme.EqualsLiteral("resource") ||
|
||||
scheme.EqualsLiteral("app") ||
|
||||
scheme.EqualsLiteral("moz-extension") ||
|
||||
scheme.EqualsLiteral("wss")) {
|
||||
// We use nsIProtocolHandler flags to determine which protocols we consider a priori
|
||||
// authenticated.
|
||||
bool aPrioriAuthenticated = false;
|
||||
if (NS_FAILED(NS_URIChainHasFlags(uri,
|
||||
nsIProtocolHandler::URI_IS_POTENTIALLY_TRUSTWORTHY,
|
||||
&aPrioriAuthenticated))) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
if (aPrioriAuthenticated) {
|
||||
*aIsTrustWorthy = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -597,7 +597,7 @@ nsMixedContentBlocker::ShouldLoad(bool aHadInsecureImageRedirect,
|
|||
* "moz-icon"
|
||||
* URI_INHERITS_SECURITY_CONTEXT - e.g.
|
||||
* "javascript"
|
||||
* URI_SAFE_TO_LOAD_IN_SECURE_CONTEXT - e.g.
|
||||
* URI_IS_POTENTIALLY_TRUSTWORTHY - e.g.
|
||||
* "https",
|
||||
* "moz-safe-about"
|
||||
*
|
||||
|
@ -609,7 +609,7 @@ nsMixedContentBlocker::ShouldLoad(bool aHadInsecureImageRedirect,
|
|||
if (NS_FAILED(NS_URIChainHasFlags(innerContentLocation, nsIProtocolHandler::URI_IS_LOCAL_RESOURCE , &schemeLocal)) ||
|
||||
NS_FAILED(NS_URIChainHasFlags(innerContentLocation, nsIProtocolHandler::URI_DOES_NOT_RETURN_DATA, &schemeNoReturnData)) ||
|
||||
NS_FAILED(NS_URIChainHasFlags(innerContentLocation, nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT, &schemeInherits)) ||
|
||||
NS_FAILED(NS_URIChainHasFlags(innerContentLocation, nsIProtocolHandler::URI_SAFE_TO_LOAD_IN_SECURE_CONTEXT, &schemeSecure))) {
|
||||
NS_FAILED(NS_URIChainHasFlags(innerContentLocation, nsIProtocolHandler::URI_IS_POTENTIALLY_TRUSTWORTHY, &schemeSecure))) {
|
||||
*aDecision = REJECT_REQUEST;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "nsContentSecurityManager.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsIPrincipal.h"
|
||||
#include "nsScriptSecurityManager.h"
|
||||
#include "NullPrincipal.h"
|
||||
|
||||
static const uint32_t kURIMaxLength = 64;
|
||||
|
||||
struct TestExpectations {
|
||||
char uri[kURIMaxLength ];
|
||||
bool expectedResult;
|
||||
};
|
||||
|
||||
// ============================= TestDirectives ========================
|
||||
|
||||
TEST(SecureContext, IsOriginPotentiallyTrustworthyWithCodeBasePrincipal)
|
||||
{
|
||||
//boolean isOriginPotentiallyTrustworthy(in nsIPrincipal aPrincipal);
|
||||
|
||||
static const TestExpectations uris[] = {
|
||||
{ "http://example.com/", false },
|
||||
{ "https://example.com/", true },
|
||||
{ "ws://example.com/", false },
|
||||
{ "wss://example.com/", true },
|
||||
{ "file:///xyzzy", true },
|
||||
{ "ftp://example.com", false },
|
||||
{ "about:config", false },
|
||||
{ "http://localhost", true },
|
||||
{ "http://xyzzy.localhost", false },
|
||||
{ "http://127.0.0.1", true },
|
||||
{ "resource://xyzzy", true },
|
||||
{ "moz-extension://xyzzy", true },
|
||||
{ "data:data:text/plain;charset=utf-8;base64,eHl6enk=", false },
|
||||
{ "blob://unique-id", false },
|
||||
{ "mailto:foo@bar.com", false },
|
||||
{ "moz-icon://example.com", false },
|
||||
{ "javascript:42", false },
|
||||
};
|
||||
|
||||
uint32_t numExpectations = sizeof(uris) / sizeof(TestExpectations);
|
||||
nsCOMPtr<nsIContentSecurityManager> csManager = do_GetService(NS_CONTENTSECURITYMANAGER_CONTRACTID);
|
||||
ASSERT_TRUE(!!csManager);
|
||||
|
||||
nsresult rv;
|
||||
for (uint32_t i = 0; i < numExpectations; i++) {
|
||||
nsCOMPtr<nsIPrincipal> prin;
|
||||
nsAutoCString uri(uris[i].uri);
|
||||
rv = nsScriptSecurityManager::GetScriptSecurityManager()->
|
||||
CreateCodebasePrincipalFromOrigin(uri, getter_AddRefs(prin));
|
||||
bool isPotentiallyTrustworthy = false;
|
||||
rv = csManager->IsOriginPotentiallyTrustworthy(prin, &isPotentiallyTrustworthy);
|
||||
ASSERT_EQ(NS_OK, rv);
|
||||
ASSERT_EQ(isPotentiallyTrustworthy, uris[i].expectedResult);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(SecureContext, IsOriginPotentiallyTrustworthyWithSystemPrincipal)
|
||||
{
|
||||
RefPtr<nsScriptSecurityManager> ssManager = nsScriptSecurityManager::GetScriptSecurityManager();
|
||||
ASSERT_TRUE(!!ssManager);
|
||||
nsCOMPtr<nsIContentSecurityManager> csManager = do_GetService(NS_CONTENTSECURITYMANAGER_CONTRACTID);
|
||||
ASSERT_TRUE(!!csManager);
|
||||
|
||||
nsCOMPtr<nsIPrincipal> sysPrin = nsContentUtils::GetSystemPrincipal();
|
||||
bool isPotentiallyTrustworthy;
|
||||
nsresult rv = csManager->IsOriginPotentiallyTrustworthy(sysPrin, &isPotentiallyTrustworthy);
|
||||
ASSERT_EQ(rv, NS_OK);
|
||||
ASSERT_TRUE(isPotentiallyTrustworthy);
|
||||
}
|
||||
|
||||
TEST(SecureContext, IsOriginPotentiallyTrustworthyWithNullPrincipal)
|
||||
{
|
||||
RefPtr<nsScriptSecurityManager> ssManager = nsScriptSecurityManager::GetScriptSecurityManager();
|
||||
ASSERT_TRUE(!!ssManager);
|
||||
nsCOMPtr<nsIContentSecurityManager> csManager = do_GetService(NS_CONTENTSECURITYMANAGER_CONTRACTID);
|
||||
ASSERT_TRUE(!!csManager);
|
||||
|
||||
RefPtr<NullPrincipal> nullPrin = NullPrincipal::CreateWithoutOriginAttributes();
|
||||
bool isPotentiallyTrustworthy;
|
||||
nsresult rv = csManager->IsOriginPotentiallyTrustworthy(nullPrin, &isPotentiallyTrustworthy);
|
||||
ASSERT_EQ(rv, NS_OK);
|
||||
ASSERT_TRUE(!isPotentiallyTrustworthy);
|
||||
}
|
|
@ -6,6 +6,11 @@
|
|||
|
||||
UNIFIED_SOURCES += [
|
||||
'TestCSPParser.cpp',
|
||||
'TestSecureContext.cpp',
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'xul-gtest'
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
'/caps',
|
||||
]
|
||||
|
|
|
@ -46,12 +46,10 @@ tags = fullscreen
|
|||
[test_bug830858.xul]
|
||||
[test_bug1224790-1.xul]
|
||||
tags = openwindow
|
||||
# synthesizeNativeOSXClick does not work on 10.6
|
||||
skip-if = os != 'mac' || os_version == '10.6'
|
||||
skip-if = os != 'mac'
|
||||
[test_bug1224790-2.xul]
|
||||
tags = openwindow
|
||||
# synthesizeNativeOSXClick does not work on 10.6
|
||||
skip-if = os != 'mac' || os_version == '10.6'
|
||||
skip-if = os != 'mac'
|
||||
[test_callback_wrapping.xul]
|
||||
[test_clonewrapper.xul]
|
||||
[test_cyclecollector.xul]
|
||||
|
|
|
@ -1206,15 +1206,12 @@ public:
|
|||
// aRealmStats->extra is a xpc::RealmStatsExtras pointer.
|
||||
xpc::RealmStatsExtras* extras = new xpc::RealmStatsExtras;
|
||||
|
||||
// This is the |jsPathPrefix|. Each worker has exactly two realms:
|
||||
// one for atoms, and one for everything else.
|
||||
// This is the |jsPathPrefix|. Each worker has exactly one realm.
|
||||
JSCompartment* compartment = JS::GetCompartmentForRealm(aRealm);
|
||||
extras->jsPathPrefix.Assign(mRtPath);
|
||||
extras->jsPathPrefix += nsPrintfCString("zone(0x%p)/",
|
||||
(void *)js::GetCompartmentZone(compartment));
|
||||
extras->jsPathPrefix += js::IsAtomsRealm(aRealm)
|
||||
? NS_LITERAL_CSTRING("realm(web-worker-atoms)/")
|
||||
: NS_LITERAL_CSTRING("realm(web-worker)/");
|
||||
extras->jsPathPrefix += NS_LITERAL_CSTRING("realm(web-worker)/");
|
||||
|
||||
// This should never be used when reporting with workers (hence the "?!").
|
||||
extras->domPathPrefix.AssignLiteral("explicit/workers/?!/");
|
||||
|
|
|
@ -39,9 +39,11 @@ class gfxVarReceiver;
|
|||
_(UseWebRenderANGLE, bool, false) \
|
||||
_(UseWebRenderDCompWin, bool, false) \
|
||||
_(UseWebRenderProgramBinary, bool, false) \
|
||||
_(UseWebRenderProgramBinaryDisk, bool, false) \
|
||||
_(WebRenderDebugFlags, int32_t, 0) \
|
||||
_(ScreenDepth, int32_t, 0) \
|
||||
_(GREDirectory, nsString, nsString()) \
|
||||
_(ProfDirectory, nsString, nsString()) \
|
||||
_(UseOMTP, bool, false) \
|
||||
_(AllowD3D11KeyedMutex, bool, false) \
|
||||
|
||||
|
|
|
@ -326,7 +326,6 @@ void ClientMultiTiledLayerBuffer::Update(const nsIntRegion& newValidRegion,
|
|||
}
|
||||
|
||||
bool edgePaddingEnabled = gfxPrefs::TileEdgePaddingEnabled();
|
||||
|
||||
for (uint32_t i = 0; i < mRetainedTiles.Length(); ++i) {
|
||||
TileClient& tile = mRetainedTiles[i];
|
||||
|
||||
|
@ -442,6 +441,8 @@ ClientMultiTiledLayerBuffer::ValidateTile(TileClient& aTile,
|
|||
return false;
|
||||
}
|
||||
|
||||
// Get the targets to draw into, and create a dual target
|
||||
// if we are using component alpha
|
||||
RefPtr<DrawTarget> dt = backBuffer->BorrowDrawTarget();
|
||||
RefPtr<DrawTarget> dtOnWhite;
|
||||
if (backBufferOnWhite) {
|
||||
|
@ -460,12 +461,18 @@ ClientMultiTiledLayerBuffer::ValidateTile(TileClient& aTile,
|
|||
drawTarget = dt;
|
||||
}
|
||||
|
||||
auto clear = CapturedTiledPaintState::Clear{
|
||||
dt,
|
||||
dtOnWhite,
|
||||
tileDirtyRegion
|
||||
};
|
||||
// We need to clear the dirty region of the tile before painting
|
||||
// if we are painting non-opaque content
|
||||
Maybe<CapturedTiledPaintState::Clear> clear = Nothing();
|
||||
if (mode != SurfaceMode::SURFACE_OPAQUE) {
|
||||
clear = Some(CapturedTiledPaintState::Clear{
|
||||
dt,
|
||||
dtOnWhite,
|
||||
tileDirtyRegion
|
||||
});
|
||||
}
|
||||
|
||||
// Queue or execute the paint operation
|
||||
gfx::Tile paintTile;
|
||||
paintTile.mTileOrigin = gfx::IntPoint(aTileOrigin.x, aTileOrigin.y);
|
||||
|
||||
|
@ -481,7 +488,9 @@ ClientMultiTiledLayerBuffer::ValidateTile(TileClient& aTile,
|
|||
asyncPaint->mCapture = captureDT;
|
||||
|
||||
asyncPaint->mCopies = std::move(asyncPaintCopies);
|
||||
asyncPaint->mClears.push_back(clear);
|
||||
if (clear) {
|
||||
asyncPaint->mClears.push_back(*clear);
|
||||
}
|
||||
|
||||
asyncPaint->mClients = std::move(asyncPaintClients);
|
||||
asyncPaint->mClients.push_back(backBuffer);
|
||||
|
@ -492,7 +501,9 @@ ClientMultiTiledLayerBuffer::ValidateTile(TileClient& aTile,
|
|||
mPaintStates.push_back(asyncPaint);
|
||||
} else {
|
||||
paintTile.mDrawTarget = drawTarget;
|
||||
clear.ClearBuffer();
|
||||
if (clear) {
|
||||
clear->ClearBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
mPaintTiles.push_back(paintTile);
|
||||
|
|
|
@ -197,68 +197,21 @@ ClientSingleTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion,
|
|||
copyableRegion.And(aNewValidRegion, discardedValidRegion);
|
||||
copyableRegion.SubOut(aDirtyRegion);
|
||||
|
||||
if (!copyableRegion.IsEmpty()) {
|
||||
OpenMode asyncFlags = asyncPaint ? OpenMode::OPEN_ASYNC
|
||||
: OpenMode::OPEN_NONE;
|
||||
if (!mTile.CopyFromBuffer(discardedFrontBuffer,
|
||||
discardedFrontBufferOnWhite,
|
||||
discardedValidRegion.GetBounds().TopLeft(),
|
||||
mTilingOrigin,
|
||||
copyableRegion,
|
||||
aFlags,
|
||||
&paintCopies)) {
|
||||
gfxWarning() << "[Tiling:Client] Failed to aquire the discarded front buffer's draw target";
|
||||
} else {
|
||||
TILING_LOG("TILING %p: Region copied from discarded frontbuffer %s\n", &mPaintedLayer, Stringify(copyableRegion).c_str());
|
||||
|
||||
TextureClientAutoLock frontLock(discardedFrontBuffer,
|
||||
OpenMode::OPEN_READ | asyncFlags);
|
||||
Maybe<TextureClientAutoLock> frontOnWhiteLock;
|
||||
if (discardedFrontBufferOnWhite && backBufferOnWhite) {
|
||||
frontOnWhiteLock.emplace(discardedFrontBufferOnWhite, OpenMode::OPEN_READ | asyncFlags);
|
||||
}
|
||||
|
||||
// Copy to both backBuffer and backBufferOnWhite if required, or copy to neither.
|
||||
if (frontLock.Succeeded() && (!frontOnWhiteLock || frontOnWhiteLock->Succeeded())) {
|
||||
RefPtr<gfx::DrawTarget> frontBuffer = discardedFrontBuffer->BorrowDrawTarget();
|
||||
|
||||
if (frontBuffer) {
|
||||
for (auto iter = copyableRegion.RectIter(); !iter.Done(); iter.Next()) {
|
||||
const gfx::IntRect rect = iter.Get() - discardedValidRegion.GetBounds().TopLeft();
|
||||
const gfx::IntPoint dest = iter.Get().TopLeft() - mTilingOrigin;
|
||||
|
||||
auto copy = CapturedTiledPaintState::Copy{
|
||||
frontBuffer, dt, rect, dest
|
||||
};
|
||||
if (asyncPaint) {
|
||||
paintCopies.push_back(copy);
|
||||
} else {
|
||||
copy.CopyBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
if (frontOnWhiteLock) {
|
||||
RefPtr<gfx::DrawTarget> frontBufferOnWhite = discardedFrontBufferOnWhite->BorrowDrawTarget();
|
||||
|
||||
if (frontBufferOnWhite) {
|
||||
for (auto iter = copyableRegion.RectIter(); !iter.Done(); iter.Next()) {
|
||||
const gfx::IntRect rect = iter.Get() - discardedValidRegion.GetBounds().TopLeft();
|
||||
const gfx::IntPoint dest = iter.Get().TopLeft() - mTilingOrigin;
|
||||
|
||||
auto copy = CapturedTiledPaintState::Copy{
|
||||
frontBufferOnWhite, dtOnWhite, rect, dest
|
||||
};
|
||||
if (asyncPaint) {
|
||||
paintCopies.push_back(copy);
|
||||
} else {
|
||||
copy.CopyBuffer();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
gfxWarning() << "[Tiling:Client] Failed to aquire the discarded front buffer's draw target";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
gfxWarning() << "[Tiling:Client] Failed to aquire the discarded front buffer's draw target";
|
||||
}
|
||||
|
||||
TILING_LOG("TILING %p: Region copied from discarded frontbuffer %s\n", &mPaintedLayer, Stringify(copyableRegion).c_str());
|
||||
|
||||
// We don't need to repaint valid content that was just copied.
|
||||
paintRegion.SubOut(copyableRegion);
|
||||
copyableRegion.MoveBy(-mTilingOrigin);
|
||||
tileDirtyRegion.SubOut(copyableRegion);
|
||||
}
|
||||
// We don't need to repaint valid content that was just copied.
|
||||
paintRegion.SubOut(copyableRegion);
|
||||
copyableRegion.MoveBy(-mTilingOrigin);
|
||||
tileDirtyRegion.SubOut(copyableRegion);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -483,45 +483,49 @@ TileClient::ValidateBackBufferFromFront(const nsIntRegion& aDirtyRegion,
|
|||
std::vector<CapturedTiledPaintState::Copy>* aCopies,
|
||||
std::vector<RefPtr<TextureClient>>* aClients)
|
||||
{
|
||||
if (mBackBuffer && mFrontBuffer) {
|
||||
gfx::IntSize tileSize = mFrontBuffer->GetSize();
|
||||
const IntRect tileRect = IntRect(0, 0, tileSize.width, tileSize.height);
|
||||
if (!mBackBuffer || !mFrontBuffer) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (aDirtyRegion.Contains(tileRect)) {
|
||||
// The dirty region means that we no longer need the front buffer, so
|
||||
// discard it.
|
||||
DiscardFrontBuffer();
|
||||
} else {
|
||||
// Region that needs copying.
|
||||
nsIntRegion regionToCopy = mInvalidBack;
|
||||
gfx::IntSize tileSize = mFrontBuffer->GetSize();
|
||||
const IntRect tileRect = IntRect(0, 0, tileSize.width, tileSize.height);
|
||||
|
||||
regionToCopy.Sub(regionToCopy, aDirtyRegion);
|
||||
regionToCopy.And(regionToCopy, aVisibleRegion);
|
||||
if (aDirtyRegion.Contains(tileRect)) {
|
||||
// The dirty region means that we no longer need the front buffer, so
|
||||
// discard it.
|
||||
DiscardFrontBuffer();
|
||||
return;
|
||||
}
|
||||
|
||||
aAddPaintedRegion = regionToCopy;
|
||||
// Region that needs copying.
|
||||
nsIntRegion regionToCopy = mInvalidBack;
|
||||
|
||||
if (regionToCopy.IsEmpty()) {
|
||||
// Just redraw it all.
|
||||
return;
|
||||
}
|
||||
regionToCopy.Sub(regionToCopy, aDirtyRegion);
|
||||
regionToCopy.And(regionToCopy, aVisibleRegion);
|
||||
|
||||
// Copy the bounding rect of regionToCopy. As tiles are quite small, it
|
||||
// is unlikely that we'd save much by copying each individual rect of the
|
||||
// region, but we can reevaluate this if it becomes an issue.
|
||||
const IntRect rectToCopy = regionToCopy.GetBounds();
|
||||
gfx::IntRect gfxRectToCopy(rectToCopy.X(), rectToCopy.Y(), rectToCopy.Width(), rectToCopy.Height());
|
||||
if (CopyFrontToBack(mFrontBuffer, mBackBuffer, gfxRectToCopy, aFlags, aCopies, aClients)) {
|
||||
if (mBackBufferOnWhite) {
|
||||
MOZ_ASSERT(mFrontBufferOnWhite);
|
||||
if (CopyFrontToBack(mFrontBufferOnWhite, mBackBufferOnWhite, gfxRectToCopy, aFlags, aCopies, aClients)) {
|
||||
mInvalidBack.Sub(mInvalidBack, aVisibleRegion);
|
||||
}
|
||||
} else {
|
||||
mInvalidBack.Sub(mInvalidBack, aVisibleRegion);
|
||||
}
|
||||
}
|
||||
aAddPaintedRegion = regionToCopy;
|
||||
|
||||
if (regionToCopy.IsEmpty()) {
|
||||
// Just redraw it all.
|
||||
return;
|
||||
}
|
||||
|
||||
// Copy the bounding rect of regionToCopy. As tiles are quite small, it
|
||||
// is unlikely that we'd save much by copying each individual rect of the
|
||||
// region, but we can reevaluate this if it becomes an issue.
|
||||
const IntRect rectToCopy = regionToCopy.GetBounds();
|
||||
if (!CopyFrontToBack(mFrontBuffer, mBackBuffer, rectToCopy, aFlags, aCopies, aClients)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mBackBufferOnWhite) {
|
||||
MOZ_ASSERT(mFrontBufferOnWhite);
|
||||
if (!CopyFrontToBack(mFrontBufferOnWhite, mBackBufferOnWhite, rectToCopy, aFlags, aCopies, aClients)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
mInvalidBack.Sub(mInvalidBack, aVisibleRegion);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -580,6 +584,59 @@ TileClient::DiscardBackBuffer()
|
|||
}
|
||||
}
|
||||
|
||||
bool
|
||||
TileClient::CopyFromBuffer(RefPtr<TextureClient> aBuffer,
|
||||
RefPtr<TextureClient> aBufferOnWhite,
|
||||
nsIntPoint aBufferOrigin,
|
||||
nsIntPoint aTileOrigin,
|
||||
const nsIntRegion& aRegion,
|
||||
TilePaintFlags aFlags,
|
||||
std::vector<CapturedTiledPaintState::Copy>* aCopies)
|
||||
{
|
||||
if (aRegion.IsEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool asyncPaint = !!(aFlags & TilePaintFlags::Async);
|
||||
auto CopyBuffer = [&aRegion, asyncPaint, &aCopies] (auto aSrc, auto aSrcOrigin, auto aDest, auto aDestOrigin) {
|
||||
MOZ_ASSERT(aDest->IsLocked());
|
||||
|
||||
OpenMode asyncFlags = asyncPaint ? OpenMode::OPEN_ASYNC
|
||||
: OpenMode::OPEN_NONE;
|
||||
TextureClientAutoLock lock(aSrc, OpenMode::OPEN_READ | asyncFlags);
|
||||
if (!lock.Succeeded()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RefPtr<gfx::DrawTarget> srcTarget = aSrc->BorrowDrawTarget();
|
||||
RefPtr<gfx::DrawTarget> destTarget = aDest->BorrowDrawTarget();
|
||||
if (!srcTarget || !destTarget) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto iter = aRegion.RectIter(); !iter.Done(); iter.Next()) {
|
||||
const gfx::IntRect src = iter.Get() - aSrcOrigin;
|
||||
const gfx::IntPoint dest = iter.Get().TopLeft() - aDestOrigin;
|
||||
|
||||
auto copy = CapturedTiledPaintState::Copy{
|
||||
srcTarget, destTarget, src, dest
|
||||
};
|
||||
|
||||
if (asyncPaint) {
|
||||
aCopies->push_back(copy);
|
||||
} else {
|
||||
copy.CopyBuffer();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
return CopyBuffer(aBuffer, aBufferOrigin, mBackBuffer, aTileOrigin) &&
|
||||
(!aBufferOnWhite ||
|
||||
!mBackBufferOnWhite ||
|
||||
CopyBuffer(aBufferOnWhite, aBufferOrigin, mBackBufferOnWhite, aTileOrigin));
|
||||
}
|
||||
|
||||
static already_AddRefed<TextureClient>
|
||||
CreateBackBufferTexture(TextureClient* aCurrentTexture,
|
||||
CompositableClient& aCompositable,
|
||||
|
|
|
@ -140,6 +140,18 @@ struct TileClient
|
|||
|
||||
void DiscardBackBuffer();
|
||||
|
||||
/*
|
||||
* Copy aRegion from aBuffer and aBufferOnWhite positioned at aBufferOrigin
|
||||
* into ourselves assuming we are positioned at aTileOrigin.
|
||||
*/
|
||||
bool CopyFromBuffer(RefPtr<TextureClient> aBuffer,
|
||||
RefPtr<TextureClient> aBufferOnWhite,
|
||||
nsIntPoint aBufferOrigin,
|
||||
nsIntPoint aTileOrigin,
|
||||
const nsIntRegion& aRegion,
|
||||
TilePaintFlags aFlags,
|
||||
std::vector<CapturedTiledPaintState::Copy>* aCopies);
|
||||
|
||||
/* We wrap the back buffer in a class that disallows assignment
|
||||
* so that we can track when ever it changes so that we can update
|
||||
* the expiry tracker for expiring the back buffers */
|
||||
|
@ -168,8 +180,10 @@ struct TileClient
|
|||
nsIntRegion mInvalidBack;
|
||||
nsExpirationState mExpirationState;
|
||||
private:
|
||||
// Copies dirty pixels from the front buffer into the back buffer,
|
||||
// and records the copied region in aAddPaintedRegion.
|
||||
/*
|
||||
* Copies dirty pixels from the front buffer into the back buffer,
|
||||
* and records the copied region in aAddPaintedRegion.
|
||||
*/
|
||||
void ValidateBackBufferFromFront(const nsIntRegion &aDirtyRegion,
|
||||
const nsIntRegion& aVisibleRegion,
|
||||
nsIntRegion& aAddPaintedRegion,
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
#include "mozilla/Logging.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "nsAppDirectoryServiceDefs.h"
|
||||
|
||||
#include "gfxCrashReporterUtils.h"
|
||||
#include "gfxPlatform.h"
|
||||
|
@ -866,6 +867,18 @@ gfxPlatform::Init()
|
|||
Preferences::SetBool(FONT_VARIATIONS_PREF, false);
|
||||
Preferences::Lock(FONT_VARIATIONS_PREF);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> profDir;
|
||||
rv = NS_GetSpecialDirectory(NS_APP_PROFILE_DIR_STARTUP, getter_AddRefs(profDir));
|
||||
if (NS_FAILED(rv)) {
|
||||
gfxVars::SetProfDirectory(nsString());
|
||||
} else {
|
||||
nsAutoString path;
|
||||
profDir->GetPath(path);
|
||||
gfxVars::SetProfDirectory(nsString(path));
|
||||
}
|
||||
|
||||
gfxUtils::RemoveShaderCacheFromDiskIfNecessary();
|
||||
}
|
||||
|
||||
if (obs) {
|
||||
|
@ -2626,7 +2639,10 @@ gfxPlatform::InitWebRenderConfig()
|
|||
#endif
|
||||
|
||||
if (Preferences::GetBool("gfx.webrender.program-binary", false)) {
|
||||
gfx::gfxVars::SetUseWebRenderProgramBinary(gfxConfig::IsEnabled(Feature::WEBRENDER));
|
||||
gfxVars::SetUseWebRenderProgramBinary(gfxConfig::IsEnabled(Feature::WEBRENDER));
|
||||
if (Preferences::GetBool("gfx.webrender.program-binary-disk", false)) {
|
||||
gfxVars::SetUseWebRenderProgramBinaryDisk(gfxConfig::IsEnabled(Feature::WEBRENDER));
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
|
|
|
@ -22,11 +22,14 @@
|
|||
#include "mozilla/gfx/Logging.h"
|
||||
#include "mozilla/gfx/PathHelpers.h"
|
||||
#include "mozilla/gfx/Swizzle.h"
|
||||
#include "mozilla/gfx/gfxVars.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/UniquePtrExtensions.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "mozilla/Vector.h"
|
||||
#include "mozilla/webrender/webrender_ffi.h"
|
||||
#include "nsAppRunner.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsIClipboardHelper.h"
|
||||
#include "nsIFile.h"
|
||||
|
@ -1468,6 +1471,54 @@ gfxUtils::ThreadSafeGetFeatureStatus(const nsCOMPtr<nsIGfxInfo>& gfxInfo,
|
|||
return gfxInfo->GetFeatureStatus(feature, failureId, status);
|
||||
}
|
||||
|
||||
#define GFX_SHADER_CHECK_BUILD_VERSION_PREF "gfx-shader-check.build-version"
|
||||
#define GFX_SHADER_CHECK_DEVICE_ID_PREF "gfx-shader-check.device-id"
|
||||
#define GFX_SHADER_CHECK_DRIVER_VERSION_PREF "gfx-shader-check.driver-version"
|
||||
|
||||
/* static */ void
|
||||
gfxUtils::RemoveShaderCacheFromDiskIfNecessary()
|
||||
{
|
||||
if (!gfxVars::UseWebRenderProgramBinaryDisk()) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
|
||||
|
||||
// Get current values
|
||||
nsCString buildID(mozilla::PlatformBuildID());
|
||||
nsString deviceID, driverVersion;
|
||||
gfxInfo->GetAdapterDeviceID(deviceID);
|
||||
gfxInfo->GetAdapterDriverVersion(driverVersion);
|
||||
|
||||
// Get pref stored values
|
||||
nsAutoCString buildIDChecked;
|
||||
Preferences::GetCString(GFX_SHADER_CHECK_BUILD_VERSION_PREF, buildIDChecked);
|
||||
nsAutoString deviceIDChecked, driverVersionChecked;
|
||||
Preferences::GetString(GFX_SHADER_CHECK_DEVICE_ID_PREF, deviceIDChecked);
|
||||
Preferences::GetString(GFX_SHADER_CHECK_DRIVER_VERSION_PREF, driverVersionChecked);
|
||||
|
||||
if (buildID == buildIDChecked &&
|
||||
deviceID == deviceIDChecked &&
|
||||
driverVersion == driverVersionChecked) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsAutoString path(gfx::gfxVars::ProfDirectory());
|
||||
|
||||
if (!wr::remove_program_binary_disk_cache(&path)) {
|
||||
// Failed to remove program binary disk cache. The disk cache might have
|
||||
// invalid data. Disable program binary disk cache usage.
|
||||
gfxVars::SetUseWebRenderProgramBinaryDisk(false);
|
||||
return;
|
||||
}
|
||||
|
||||
Preferences::SetCString(GFX_SHADER_CHECK_BUILD_VERSION_PREF, buildID);
|
||||
Preferences::SetString(GFX_SHADER_CHECK_DEVICE_ID_PREF, deviceID);
|
||||
Preferences::SetString(GFX_SHADER_CHECK_DRIVER_VERSION_PREF, driverVersion);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* static */ bool
|
||||
gfxUtils::DumpDisplayList() {
|
||||
return gfxPrefs::LayoutDumpDisplayList() ||
|
||||
|
|
|
@ -295,6 +295,8 @@ public:
|
|||
nsACString& failureId,
|
||||
int32_t* status);
|
||||
|
||||
static void RemoveShaderCacheFromDiskIfNecessary();
|
||||
|
||||
/**
|
||||
* Copy to the clipboard as a PNG encoded Data URL.
|
||||
*/
|
||||
|
|
|
@ -11,12 +11,16 @@ euclid = { version = "0.17", features = ["serde"] }
|
|||
app_units = "0.6"
|
||||
gleam = "0.5"
|
||||
log = "0.4"
|
||||
nsstring = { path = "../../servo/support/gecko/nsstring" }
|
||||
bincode = "1.0"
|
||||
uuid = {version = "0.1.18"}
|
||||
fxhash = "0.2.1"
|
||||
|
||||
[dependencies.webrender]
|
||||
path = "../webrender"
|
||||
version = "0.57.2"
|
||||
default-features = false
|
||||
features = ["capture"]
|
||||
features = ["capture", "serialize_program"]
|
||||
|
||||
[target.'cfg(target_os = "windows")'.dependencies]
|
||||
dwrote = "0.4.1"
|
||||
|
|
|
@ -70,6 +70,16 @@ RenderThread::Start()
|
|||
widget::WinCompositorWindowThread::Start();
|
||||
#endif
|
||||
layers::SharedSurfacesParent::Initialize();
|
||||
|
||||
if (XRE_IsGPUProcess() &&
|
||||
gfx::gfxVars::UseWebRenderProgramBinary()) {
|
||||
MOZ_ASSERT(gfx::gfxVars::UseWebRender());
|
||||
// Initialize program cache if necessary
|
||||
RefPtr<Runnable> runnable = WrapRunnable(
|
||||
RefPtr<RenderThread>(sRenderThread.get()),
|
||||
&RenderThread::ProgramCacheTask);
|
||||
sRenderThread->Loop()->PostTask(runnable.forget());
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
|
@ -511,13 +521,19 @@ RenderThread::GetRenderTexture(wr::WrExternalImageId aExternalImageId)
|
|||
return mRenderTextures.GetWeak(aExternalImageId.mHandle);
|
||||
}
|
||||
|
||||
void
|
||||
RenderThread::ProgramCacheTask()
|
||||
{
|
||||
ProgramCache();
|
||||
}
|
||||
|
||||
WebRenderProgramCache*
|
||||
RenderThread::ProgramCache()
|
||||
{
|
||||
MOZ_ASSERT(IsInRenderThread());
|
||||
|
||||
if (!mProgramCache) {
|
||||
mProgramCache = MakeUnique<WebRenderProgramCache>();
|
||||
mProgramCache = MakeUnique<WebRenderProgramCache>(ThreadPool().Raw());
|
||||
}
|
||||
return mProgramCache.get();
|
||||
}
|
||||
|
@ -532,9 +548,16 @@ WebRenderThreadPool::~WebRenderThreadPool()
|
|||
wr_thread_pool_delete(mThreadPool);
|
||||
}
|
||||
|
||||
WebRenderProgramCache::WebRenderProgramCache()
|
||||
WebRenderProgramCache::WebRenderProgramCache(wr::WrThreadPool* aThreadPool)
|
||||
{
|
||||
mProgramCache = wr_program_cache_new();
|
||||
MOZ_ASSERT(aThreadPool);
|
||||
|
||||
nsAutoString path;
|
||||
if (gfxVars::UseWebRenderProgramBinaryDisk()) {
|
||||
path.Append(gfx::gfxVars::ProfDirectory());
|
||||
}
|
||||
mProgramCache = wr_program_cache_new(&path, aThreadPool);
|
||||
wr_try_load_shader_from_disk(mProgramCache);
|
||||
}
|
||||
|
||||
WebRenderProgramCache::~WebRenderProgramCache()
|
||||
|
|
|
@ -42,7 +42,7 @@ protected:
|
|||
|
||||
class WebRenderProgramCache {
|
||||
public:
|
||||
WebRenderProgramCache();
|
||||
explicit WebRenderProgramCache(wr::WrThreadPool* aThreadPool);
|
||||
|
||||
~WebRenderProgramCache();
|
||||
|
||||
|
@ -170,6 +170,7 @@ private:
|
|||
|
||||
void DeferredRenderTextureHostDestroy(RefPtr<RenderTextureHost> aTexture);
|
||||
void ShutDownTask(layers::SynchronousTask* aTask);
|
||||
void ProgramCacheTask();
|
||||
|
||||
~RenderThread();
|
||||
|
||||
|
|
|
@ -13,12 +13,14 @@ use webrender::{ExternalImage, ExternalImageHandler, ExternalImageSource};
|
|||
use webrender::DebugFlags;
|
||||
use webrender::{ApiRecordingReceiver, BinaryRecorder};
|
||||
use webrender::{AsyncPropertySampler, PipelineInfo, SceneBuilderHooks};
|
||||
use webrender::{ProgramCache, UploadMethod, VertexUsageHint};
|
||||
use webrender::{UploadMethod, VertexUsageHint};
|
||||
use thread_profiler::register_thread_with_profiler;
|
||||
use moz2d_renderer::Moz2dImageRenderer;
|
||||
use program_cache::{WrProgramCache, remove_disk_cache};
|
||||
use app_units::Au;
|
||||
use rayon;
|
||||
use euclid::SideOffsets2D;
|
||||
use nsstring::nsAString;
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
use dwrote::{FontDescriptor, FontWeight, FontStretch, FontStyle};
|
||||
|
@ -827,23 +829,40 @@ pub unsafe extern "C" fn wr_thread_pool_delete(thread_pool: *mut WrThreadPool) {
|
|||
Box::from_raw(thread_pool);
|
||||
}
|
||||
|
||||
pub struct WrProgramCache(Rc<ProgramCache>);
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wr_program_cache_new() -> *mut WrProgramCache {
|
||||
let program_cache = ProgramCache::new(None);
|
||||
Box::into_raw(Box::new(WrProgramCache(program_cache)))
|
||||
pub unsafe extern "C" fn wr_program_cache_new(prof_path: &nsAString, thread_pool: *mut WrThreadPool) -> *mut WrProgramCache {
|
||||
let workers = &(*thread_pool).0;
|
||||
let program_cache = WrProgramCache::new(prof_path, workers);
|
||||
Box::into_raw(Box::new(program_cache))
|
||||
}
|
||||
|
||||
/// cbindgen:postfix=WR_DESTRUCTOR_SAFE_FUNC
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wr_program_cache_delete(program_cache: *mut WrProgramCache) {
|
||||
Rc::from_raw(program_cache);
|
||||
Box::from_raw(program_cache);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wr_try_load_shader_from_disk(program_cache: *mut WrProgramCache) {
|
||||
if !program_cache.is_null() {
|
||||
(*program_cache).try_load_from_disk();
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn remove_program_binary_disk_cache(prof_path: &nsAString) -> bool {
|
||||
match remove_disk_cache(prof_path) {
|
||||
Ok(_) => true,
|
||||
Err(_) => {
|
||||
error!("Failed to remove program binary disk cache");
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn wr_renderer_update_program_cache(renderer: &mut Renderer, program_cache: &mut WrProgramCache) {
|
||||
let program_cache = Rc::clone(&program_cache.0);
|
||||
let program_cache = Rc::clone(&program_cache.rc_get());
|
||||
renderer.update_program_cache(program_cache);
|
||||
}
|
||||
|
||||
|
|
|
@ -8,8 +8,12 @@ extern crate webrender;
|
|||
extern crate euclid;
|
||||
extern crate app_units;
|
||||
extern crate gleam;
|
||||
extern crate nsstring;
|
||||
extern crate rayon;
|
||||
extern crate thread_profiler;
|
||||
extern crate bincode;
|
||||
extern crate uuid;
|
||||
extern crate fxhash;
|
||||
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
|
@ -17,6 +21,7 @@ extern crate log;
|
|||
#[cfg(target_os = "windows")]
|
||||
extern crate dwrote;
|
||||
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
extern crate core_foundation;
|
||||
#[cfg(target_os = "macos")]
|
||||
|
@ -24,6 +29,8 @@ extern crate core_graphics;
|
|||
#[cfg(target_os = "macos")]
|
||||
extern crate foreign_types;
|
||||
|
||||
mod program_cache;
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub mod bindings;
|
||||
pub mod moz2d_renderer;
|
||||
|
|
|
@ -0,0 +1,298 @@
|
|||
use std::cell::RefCell;
|
||||
use std::io::{Error, ErrorKind};
|
||||
use std::fs::{File, create_dir_all, read_dir};
|
||||
use std::io::{Read, Write};
|
||||
use std::path::{PathBuf};
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
|
||||
use webrender::{ProgramBinary, ProgramCache, ProgramCacheObserver};
|
||||
use bincode;
|
||||
use fxhash;
|
||||
use nsstring::nsAString;
|
||||
use rayon::ThreadPool;
|
||||
use uuid::Uuid;
|
||||
|
||||
const MAX_LOAD_TIME_MS: u64 = 400;
|
||||
const MAX_CACHED_PROGRAM_COUNT: u32 = 15;
|
||||
|
||||
fn deserialize_program_binary(path: &PathBuf) -> Result<Arc<ProgramBinary>, Error> {
|
||||
let mut buf = vec![];
|
||||
let mut file = File::open(path)?;
|
||||
file.read_to_end(&mut buf)?;
|
||||
|
||||
if buf.len() <= 8 {
|
||||
return Err(Error::new(ErrorKind::InvalidData, "File size is too small"));
|
||||
}
|
||||
let hash = &buf[0 .. 8];
|
||||
let data = &buf[8 ..];
|
||||
|
||||
// Check if hash is correct
|
||||
let hash:u64 = bincode::deserialize(&hash).unwrap();
|
||||
let hash_data = fxhash::hash64(&data);
|
||||
if hash != hash_data {
|
||||
return Err(Error::new(ErrorKind::InvalidData, "File data is invalid"));
|
||||
}
|
||||
|
||||
// Deserialize ProgramBinary
|
||||
let binary = match bincode::deserialize(&data) {
|
||||
Ok(binary) => binary,
|
||||
Err(_) => return Err(Error::new(ErrorKind::InvalidData, "Failed to deserialize ProgramBinary")),
|
||||
};
|
||||
|
||||
Ok(Arc::new(binary))
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
fn get_cache_path_from_prof_path(prof_path: &nsAString) -> Option<PathBuf> {
|
||||
if prof_path.is_empty() {
|
||||
// Empty means that we do not use disk cache.
|
||||
return None;
|
||||
}
|
||||
|
||||
use std::ffi::OsString;
|
||||
use std::os::windows::prelude::*;
|
||||
|
||||
let prof_path = OsString::from_wide(prof_path.as_ref());
|
||||
let mut cache_path = PathBuf::from(&prof_path);
|
||||
cache_path.push("shader-cache");
|
||||
|
||||
Some(cache_path)
|
||||
}
|
||||
|
||||
#[cfg(not(target_os="windows"))]
|
||||
fn get_cache_path_from_prof_path(_prof_path: &nsAString) -> Option<PathBuf> {
|
||||
// Not supported yet.
|
||||
None
|
||||
}
|
||||
|
||||
struct WrProgramBinaryDiskCache {
|
||||
cache_path: Option<PathBuf>,
|
||||
program_count: u32,
|
||||
is_enabled: bool,
|
||||
workers: Arc<ThreadPool>,
|
||||
}
|
||||
|
||||
impl WrProgramBinaryDiskCache {
|
||||
#[allow(dead_code)]
|
||||
fn new(prof_path: &nsAString, workers: &Arc<ThreadPool>) -> Self {
|
||||
let cache_path = get_cache_path_from_prof_path(prof_path);
|
||||
let is_enabled = cache_path.is_some();
|
||||
let workers = Arc::clone(workers);
|
||||
|
||||
WrProgramBinaryDiskCache{
|
||||
cache_path,
|
||||
program_count: 0,
|
||||
is_enabled,
|
||||
workers,
|
||||
}
|
||||
}
|
||||
|
||||
fn notify_binary_added(&mut self, program_binary: &Arc<ProgramBinary>) {
|
||||
if !self.is_enabled {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(ref cache_path) = self.cache_path {
|
||||
if let Err(_) = create_dir_all(&cache_path) {
|
||||
error!("failed to create dir for shader disk cache");
|
||||
return;
|
||||
}
|
||||
|
||||
self.program_count += 1;
|
||||
if self.program_count > MAX_CACHED_PROGRAM_COUNT {
|
||||
// Disable disk cache to avoid storing more shader programs to disk
|
||||
self.is_enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Use uuid for file name
|
||||
let uuid1 = Uuid::new_v4();
|
||||
let file_name = uuid1.to_hyphenated_string();
|
||||
let program_binary = Arc::clone(program_binary);
|
||||
let file_path = cache_path.join(&file_name);
|
||||
|
||||
let program_count = self.program_count;
|
||||
|
||||
// Save to disk on worker thread
|
||||
self.workers.spawn(move || {
|
||||
|
||||
use std::time::{Instant};
|
||||
let start = Instant::now();
|
||||
|
||||
let data: Vec<u8> = match bincode::serialize(&*program_binary) {
|
||||
Ok(data) => data,
|
||||
Err(err) => {
|
||||
error!("Failed to serialize program binary error: {}", err);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let mut file = match File::create(&file_path) {
|
||||
Ok(file) => file,
|
||||
Err(err) => {
|
||||
error!("Unable to create file for program binary error: {}", err);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
// Write hash
|
||||
let hash = fxhash::hash64(&data);
|
||||
let hash = bincode::serialize(&hash).unwrap();
|
||||
assert!(hash.len() == 8);
|
||||
match file.write_all(&hash) {
|
||||
Err(err) => {
|
||||
error!("Failed to write hash to file error: {}", err);
|
||||
}
|
||||
_ => {},
|
||||
};
|
||||
|
||||
// Write serialized data
|
||||
match file.write_all(&data) {
|
||||
Err(err) => {
|
||||
error!("Failed to write program binary to file error: {}", err);
|
||||
}
|
||||
_ => {},
|
||||
};
|
||||
|
||||
let elapsed = start.elapsed();
|
||||
info!("notify_binary_added: {} ms program_count {}",
|
||||
(elapsed.as_secs() * 1_000) + (elapsed.subsec_nanos() / 1_000_000) as u64, program_count);
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_load_from_disk(&mut self, program_cache: &Rc<ProgramCache>) {
|
||||
if !self.is_enabled {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(ref cache_path) = self.cache_path {
|
||||
use std::time::{Instant};
|
||||
let start = Instant::now();
|
||||
|
||||
// Load program binaries if exist
|
||||
if cache_path.exists() && cache_path.is_dir() {
|
||||
for entry in read_dir(cache_path).unwrap() {
|
||||
let entry = entry.unwrap();
|
||||
let path = entry.path();
|
||||
|
||||
info!("loading shader file");
|
||||
|
||||
match deserialize_program_binary(&path) {
|
||||
Ok(program) => {
|
||||
program_cache.load_program_binary(program);
|
||||
}
|
||||
Err(err) => {
|
||||
error!("Failed to desriralize program binary error: {}", err);
|
||||
}
|
||||
};
|
||||
|
||||
self.program_count += 1;
|
||||
|
||||
let elapsed = start.elapsed();
|
||||
let elapsed_ms = (elapsed.as_secs() * 1_000) + (elapsed.subsec_nanos() / 1_000_000) as u64;
|
||||
info!("deserialize_program_binary: {} ms program_count {}", elapsed_ms, self.program_count);
|
||||
|
||||
if self.program_count > MAX_CACHED_PROGRAM_COUNT || elapsed_ms > MAX_LOAD_TIME_MS {
|
||||
// Disable disk cache to avoid storing more shader programs to disk
|
||||
self.is_enabled = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct WrProgramCacheObserver {
|
||||
disk_cache: Rc<RefCell<WrProgramBinaryDiskCache>>,
|
||||
}
|
||||
|
||||
impl WrProgramCacheObserver {
|
||||
#[allow(dead_code)]
|
||||
fn new(disk_cache: Rc<RefCell<WrProgramBinaryDiskCache>>) -> Self {
|
||||
WrProgramCacheObserver{
|
||||
disk_cache,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ProgramCacheObserver for WrProgramCacheObserver {
|
||||
fn notify_binary_added(&self, program_binary: &Arc<ProgramBinary>) {
|
||||
self.disk_cache.borrow_mut().notify_binary_added(program_binary);
|
||||
}
|
||||
|
||||
fn notify_program_binary_failed(&self, _program_binary: &Arc<ProgramBinary>) {
|
||||
error!("Failed program_binary");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub struct WrProgramCache {
|
||||
program_cache: Rc<ProgramCache>,
|
||||
disk_cache: Option<Rc<RefCell<WrProgramBinaryDiskCache>>>,
|
||||
}
|
||||
|
||||
impl WrProgramCache {
|
||||
#[cfg(target_os = "windows")]
|
||||
pub fn new(prof_path: &nsAString, workers: &Arc<ThreadPool>) -> Self {
|
||||
let disk_cache = Rc::new(RefCell::new(WrProgramBinaryDiskCache::new(prof_path, workers)));
|
||||
let program_cache_observer = Box::new(WrProgramCacheObserver::new(Rc::clone(&disk_cache)));
|
||||
let program_cache = ProgramCache::new(Some(program_cache_observer));
|
||||
|
||||
WrProgramCache {
|
||||
program_cache,
|
||||
disk_cache: Some(disk_cache),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_os="windows"))]
|
||||
pub fn new(_prof_path: &nsAString, _: &Arc<ThreadPool>) -> Self {
|
||||
let program_cache = ProgramCache::new(None);
|
||||
|
||||
WrProgramCache {
|
||||
program_cache,
|
||||
disk_cache: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rc_get(&self) -> &Rc<ProgramCache> {
|
||||
&self.program_cache
|
||||
}
|
||||
|
||||
pub fn try_load_from_disk(&self) {
|
||||
if let Some(ref disk_cache) = self.disk_cache {
|
||||
disk_cache.borrow_mut().try_load_from_disk(&self.program_cache);
|
||||
} else {
|
||||
error!("Shader disk cache is not supported");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
pub fn remove_disk_cache(prof_path: &nsAString) -> Result<(), Error> {
|
||||
use std::fs::remove_dir_all;
|
||||
use std::time::{Instant};
|
||||
|
||||
if let Some(cache_path) = get_cache_path_from_prof_path(prof_path) {
|
||||
if cache_path.exists() {
|
||||
let start = Instant::now();
|
||||
|
||||
remove_dir_all(&cache_path)?;
|
||||
|
||||
let elapsed = start.elapsed();
|
||||
let elapsed_ms = (elapsed.as_secs() * 1_000) + (elapsed.subsec_nanos() / 1_000_000) as u64;
|
||||
info!("remove_disk_cache: {} ms", elapsed_ms);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(not(target_os="windows"))]
|
||||
pub fn remove_disk_cache(_prof_path: &nsAString) -> Result<(), Error> {
|
||||
error!("Shader disk cache is not supported");
|
||||
return Err(Error::new(ErrorKind::Other, "Not supported"))
|
||||
}
|
||||
|
|
@ -17,6 +17,10 @@
|
|||
namespace mozilla {
|
||||
namespace wr {
|
||||
|
||||
static const uint32_t MAX_CACHED_PROGRAM_COUNT = 15;
|
||||
|
||||
static const uint64_t MAX_LOAD_TIME_MS = 400;
|
||||
|
||||
enum class BorderStyle : uint32_t {
|
||||
None = 0,
|
||||
Solid = 1,
|
||||
|
@ -1000,6 +1004,10 @@ extern bool is_in_main_thread();
|
|||
|
||||
extern bool is_in_render_thread();
|
||||
|
||||
WR_INLINE
|
||||
bool remove_program_binary_disk_cache(const nsAString *aProfPath)
|
||||
WR_FUNC;
|
||||
|
||||
WR_INLINE
|
||||
const VecU8 *wr_add_ref_arc(const ArcVecU8 *aArc)
|
||||
WR_FUNC;
|
||||
|
@ -1411,7 +1419,8 @@ void wr_program_cache_delete(WrProgramCache *aProgramCache)
|
|||
WR_DESTRUCTOR_SAFE_FUNC;
|
||||
|
||||
WR_INLINE
|
||||
WrProgramCache *wr_program_cache_new()
|
||||
WrProgramCache *wr_program_cache_new(const nsAString *aProfPath,
|
||||
WrThreadPool *aThreadPool)
|
||||
WR_FUNC;
|
||||
|
||||
WR_INLINE
|
||||
|
@ -1662,6 +1671,10 @@ void wr_transaction_update_epoch(Transaction *aTxn,
|
|||
WrEpoch aEpoch)
|
||||
WR_FUNC;
|
||||
|
||||
WR_INLINE
|
||||
void wr_try_load_shader_from_disk(WrProgramCache *aProgramCache)
|
||||
WR_FUNC;
|
||||
|
||||
WR_INLINE
|
||||
void wr_vec_u8_free(WrVecU8 aV)
|
||||
WR_FUNC;
|
||||
|
|
|
@ -34,6 +34,8 @@ struct IPCRemoteStream
|
|||
bool delayedStart;
|
||||
|
||||
IPCRemoteStreamType stream;
|
||||
|
||||
int64_t length;
|
||||
};
|
||||
|
||||
// Use IPCStream or OptionalIPCStream in your ipdl to represent serialized
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "IPCStreamDestination.h"
|
||||
#include "mozilla/InputStreamLengthWrapper.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "nsIAsyncInputStream.h"
|
||||
#include "nsIAsyncOutputStream.h"
|
||||
|
@ -264,6 +265,9 @@ NS_INTERFACE_MAP_END
|
|||
IPCStreamDestination::IPCStreamDestination()
|
||||
: mOwningThread(NS_GetCurrentThread())
|
||||
, mDelayedStart(false)
|
||||
#ifdef MOZ_DEBUG
|
||||
, mLengthSet(false)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -302,6 +306,24 @@ IPCStreamDestination::SetDelayedStart(bool aDelayedStart)
|
|||
mDelayedStart = aDelayedStart;
|
||||
}
|
||||
|
||||
void
|
||||
IPCStreamDestination::SetLength(int64_t aLength)
|
||||
{
|
||||
MOZ_ASSERT(mReader);
|
||||
MOZ_ASSERT(!mLengthSet);
|
||||
|
||||
#ifdef DEBUG
|
||||
mLengthSet = true;
|
||||
#endif
|
||||
|
||||
if (aLength != -1) {
|
||||
nsCOMPtr<nsIInputStream> finalStream;
|
||||
finalStream = new InputStreamLengthWrapper(mReader.forget(), aLength);
|
||||
mReader = do_QueryInterface(finalStream);
|
||||
MOZ_ASSERT(mReader);
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<nsIInputStream>
|
||||
IPCStreamDestination::TakeReader()
|
||||
{
|
||||
|
|
|
@ -39,6 +39,9 @@ public:
|
|||
void
|
||||
SetDelayedStart(bool aDelayedStart);
|
||||
|
||||
void
|
||||
SetLength(int64_t aLength);
|
||||
|
||||
already_AddRefed<nsIInputStream>
|
||||
TakeReader();
|
||||
|
||||
|
@ -96,6 +99,10 @@ private:
|
|||
|
||||
nsCOMPtr<nsIThread> mOwningThread;
|
||||
bool mDelayedStart;
|
||||
|
||||
#ifdef MOZ_DEBUG
|
||||
bool mLengthSet;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace ipc
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "nsIIPCSerializableInputStream.h"
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/InputStreamLengthHelper.h"
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
|
@ -137,6 +138,14 @@ SerializeInputStream(nsIInputStream* aStream, IPCStream& aValue, M* aManager,
|
|||
MOZ_ASSERT(aStream);
|
||||
MOZ_ASSERT(aManager);
|
||||
|
||||
// Let's try to take the length using InputStreamLengthHelper. If the length
|
||||
// cannot be taken synchronously, and its length is needed, the stream needs
|
||||
// to be fully copied in memory on the deserialization side.
|
||||
int64_t length;
|
||||
if (!InputStreamLengthHelper::GetSyncLength(aStream, &length)) {
|
||||
length = -1;
|
||||
}
|
||||
|
||||
// As a fallback, attempt to stream the data across using a IPCStream
|
||||
// actor. For blocking streams, create a nonblocking pipe instead,
|
||||
nsCOMPtr<nsIAsyncInputStream> asyncStream = do_QueryInterface(aStream);
|
||||
|
@ -168,6 +177,7 @@ SerializeInputStream(nsIInputStream* aStream, IPCStream& aValue, M* aManager,
|
|||
IPCRemoteStream remoteStream;
|
||||
remoteStream.delayedStart() = aDelayedStart;
|
||||
remoteStream.stream() = IPCStreamSource::Create(asyncStream, aManager);
|
||||
remoteStream.length() = length;
|
||||
aValue = remoteStream;
|
||||
|
||||
return true;
|
||||
|
@ -379,6 +389,7 @@ DeserializeIPCStream(const IPCStream& aValue)
|
|||
}
|
||||
|
||||
destinationStream->SetDelayedStart(remoteStream.delayedStart());
|
||||
destinationStream->SetLength(remoteStream.length());
|
||||
return destinationStream->TakeReader();
|
||||
}
|
||||
|
||||
|
|
|
@ -61,6 +61,7 @@ union InputStreamParams
|
|||
MultiplexInputStreamParams;
|
||||
SlicedInputStreamParams;
|
||||
IPCBlobInputStreamParams;
|
||||
InputStreamLengthWrapperParams;
|
||||
};
|
||||
|
||||
union OptionalInputStreamParams
|
||||
|
@ -82,5 +83,12 @@ struct MIMEInputStreamParams
|
|||
bool startedReading;
|
||||
};
|
||||
|
||||
struct InputStreamLengthWrapperParams
|
||||
{
|
||||
InputStreamParams stream;
|
||||
int64_t length;
|
||||
bool consumed;
|
||||
};
|
||||
|
||||
} // namespace ipc
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "mozilla/dom/ipc/IPCBlobInputStream.h"
|
||||
#include "mozilla/dom/ipc/IPCBlobInputStreamStorage.h"
|
||||
#include "mozilla/SlicedInputStream.h"
|
||||
#include "mozilla/InputStreamLengthWrapper.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsDebug.h"
|
||||
#include "nsID.h"
|
||||
|
@ -100,6 +101,10 @@ InputStreamHelper::DeserializeInputStream(const InputStreamParams& aParams,
|
|||
serializable = new mozilla::SlicedInputStream();
|
||||
break;
|
||||
|
||||
case InputStreamParams::TInputStreamLengthWrapperParams:
|
||||
serializable = new mozilla::InputStreamLengthWrapper();
|
||||
break;
|
||||
|
||||
default:
|
||||
MOZ_ASSERT(false, "Unknown params!");
|
||||
return nullptr;
|
||||
|
|
|
@ -97,8 +97,8 @@ typedef void
|
|||
extern JS_PUBLIC_API(void)
|
||||
SetRealmNameCallback(JSContext* cx, RealmNameCallback callback);
|
||||
|
||||
// Get the global object for the given realm. Returns null only if `realm` is
|
||||
// the atoms realm.
|
||||
// Get the global object for the given realm. This only returns nullptr during
|
||||
// GC, between collecting the global object and destroying the Realm.
|
||||
extern JS_PUBLIC_API(JSObject*)
|
||||
GetRealmGlobalOrNull(Handle<Realm*> realm);
|
||||
|
||||
|
|
|
@ -884,7 +884,7 @@ class RootingContext
|
|||
return reinterpret_cast<RootingContext*>(cx);
|
||||
}
|
||||
|
||||
friend JSCompartment* js::GetContextCompartment(const JSContext* cx);
|
||||
friend JS::Realm* js::GetContextRealm(const JSContext* cx);
|
||||
friend JS::Zone* js::GetContextZone(const JSContext* cx);
|
||||
};
|
||||
|
||||
|
@ -1054,10 +1054,16 @@ namespace js {
|
|||
* usable without resorting to jsfriendapi.h, and when JSContext is an
|
||||
* incomplete type.
|
||||
*/
|
||||
inline JS::Realm*
|
||||
GetContextRealm(const JSContext* cx)
|
||||
{
|
||||
return JS::RootingContext::get(cx)->realm_;
|
||||
}
|
||||
|
||||
inline JSCompartment*
|
||||
GetContextCompartment(const JSContext* cx)
|
||||
{
|
||||
return GetCompartmentForRealm(JS::RootingContext::get(cx)->realm_);
|
||||
return GetCompartmentForRealm(GetContextRealm(cx));
|
||||
}
|
||||
|
||||
inline JS::Zone*
|
||||
|
|
|
@ -378,9 +378,6 @@ UncheckedUnwrapWithoutExpose(JSObject* obj);
|
|||
void
|
||||
ReportAccessDenied(JSContext* cx);
|
||||
|
||||
JS_FRIEND_API(bool)
|
||||
IsCrossCompartmentWrapper(JSObject* obj);
|
||||
|
||||
JS_FRIEND_API(void)
|
||||
NukeCrossCompartmentWrapper(JSContext* cx, JSObject* wrapper);
|
||||
|
||||
|
|
|
@ -174,6 +174,7 @@ const WHITELIST_TYPES: &'static [&'static str] = &[
|
|||
"JSAutoStructuredCloneBuffer",
|
||||
"JSClass",
|
||||
"JSClassOps",
|
||||
"JSCompartment",
|
||||
"JSContext",
|
||||
"JSErrNum",
|
||||
"JSErrorCallback",
|
||||
|
|
|
@ -1055,7 +1055,7 @@ pub unsafe fn get_object_class(obj: *mut JSObject) -> *const JSClass {
|
|||
|
||||
#[inline]
|
||||
pub unsafe fn get_object_compartment(obj: *mut JSObject) -> *mut JSCompartment {
|
||||
(*get_object_group(obj)).compartment
|
||||
(*get_object_group(obj)).realm as *mut JSCompartment
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
|
@ -1999,7 +1999,7 @@ CreateObjectConstructor(JSContext* cx, JSProtoKey key)
|
|||
static JSObject*
|
||||
CreateObjectPrototype(JSContext* cx, JSProtoKey key)
|
||||
{
|
||||
MOZ_ASSERT(!cx->realm()->isAtomsRealm());
|
||||
MOZ_ASSERT(!cx->zone()->isAtomsZone());
|
||||
MOZ_ASSERT(cx->global()->isNative());
|
||||
|
||||
/*
|
||||
|
|
|
@ -1507,7 +1507,8 @@ BytecodeEmitter::TDZCheckCache::noteTDZCheck(BytecodeEmitter* bce, JSAtom* name,
|
|||
// Usage: (check for the return value is omitted for simplicity)
|
||||
//
|
||||
// `try { try_block } catch (ex) { catch_block }`
|
||||
// TryEmitter tryCatch(this, TryEmitter::TryCatch);
|
||||
// TryEmitter tryCatch(this, TryEmitter::Kind::TryCatch,
|
||||
// TryEmitter::ControlKind::Syntactic);
|
||||
// tryCatch.emitTry();
|
||||
// emit(try_block);
|
||||
// tryCatch.emitCatch();
|
||||
|
@ -1515,7 +1516,8 @@ BytecodeEmitter::TDZCheckCache::noteTDZCheck(BytecodeEmitter* bce, JSAtom* name,
|
|||
// tryCatch.emitEnd();
|
||||
//
|
||||
// `try { try_block } finally { finally_block }`
|
||||
// TryEmitter tryCatch(this, TryEmitter::TryFinally);
|
||||
// TryEmitter tryCatch(this, TryEmitter::Kind::TryFinally,
|
||||
// TryEmitter::ControlKind::Syntactic);
|
||||
// tryCatch.emitTry();
|
||||
// emit(try_block);
|
||||
// // finally_pos: The "{" character's position in the source code text.
|
||||
|
@ -1524,7 +1526,8 @@ BytecodeEmitter::TDZCheckCache::noteTDZCheck(BytecodeEmitter* bce, JSAtom* name,
|
|||
// tryCatch.emitEnd();
|
||||
//
|
||||
// `try { try_block } catch (ex) {catch_block} finally { finally_block }`
|
||||
// TryEmitter tryCatch(this, TryEmitter::TryCatchFinally);
|
||||
// TryEmitter tryCatch(this, TryEmitter::Kind::TryCatchFinally,
|
||||
// TryEmitter::ControlKind::Syntactic);
|
||||
// tryCatch.emitTry();
|
||||
// emit(try_block);
|
||||
// tryCatch.emitCatch();
|
||||
|
@ -1536,17 +1539,23 @@ BytecodeEmitter::TDZCheckCache::noteTDZCheck(BytecodeEmitter* bce, JSAtom* name,
|
|||
class MOZ_STACK_CLASS TryEmitter
|
||||
{
|
||||
public:
|
||||
enum Kind {
|
||||
enum class Kind {
|
||||
TryCatch,
|
||||
TryCatchFinally,
|
||||
TryFinally
|
||||
};
|
||||
|
||||
// Whether the catch and finally blocks handle the frame's return value.
|
||||
// If UseRetVal is specified, the bytecode marked with "*" are emitted
|
||||
// to clear return value with `undefined` before the catch block and the
|
||||
// finally block, and also to save/restore the return value before/after
|
||||
// the finally block.
|
||||
// Syntactic try-catch-finally and internally used non-syntactic
|
||||
// try-catch-finally behave differently for 2 points.
|
||||
//
|
||||
// The first one is whether TryFinallyControl is used or not.
|
||||
// See the comment for `controlInfo_`.
|
||||
//
|
||||
// The second one is whether the catch and finally blocks handle the frame's
|
||||
// return value. For syntactic try-catch-finally, the bytecode marked with
|
||||
// "*" are emitted to clear return value with `undefined` before the catch
|
||||
// block and the finally block, and also to save/restore the return value
|
||||
// before/after the finally block.
|
||||
//
|
||||
// JSOP_TRY
|
||||
//
|
||||
|
@ -1581,27 +1590,17 @@ class MOZ_STACK_CLASS TryEmitter
|
|||
// end:
|
||||
// JSOP_JUMPTARGET
|
||||
//
|
||||
// For syntactic try-catch-finally, UseRetVal should be used.
|
||||
// For non-syntactic try-catch-finally, DontUseRetVal should be used.
|
||||
enum ShouldUseRetVal {
|
||||
UseRetVal,
|
||||
DontUseRetVal
|
||||
};
|
||||
|
||||
// Whether this class should use TryFinallyControl.
|
||||
// See the comment for `controlInfo_`.
|
||||
//
|
||||
// For syntactic try-catch-finally, UseControl should be used.
|
||||
// For non-syntactic try-catch-finally, DontUseControl should be used.
|
||||
enum ShouldUseControl {
|
||||
UseControl,
|
||||
DontUseControl,
|
||||
// For syntactic try-catch-finally, Syntactic should be used.
|
||||
// For non-syntactic try-catch-finally, NonSyntactic should be used.
|
||||
enum class ControlKind {
|
||||
Syntactic,
|
||||
NonSyntactic
|
||||
};
|
||||
|
||||
private:
|
||||
BytecodeEmitter* bce_;
|
||||
Kind kind_;
|
||||
ShouldUseRetVal retValKind_;
|
||||
ControlKind controlKind_;
|
||||
|
||||
// Track jumps-over-catches and gosubs-to-finally for later fixup.
|
||||
//
|
||||
|
@ -1609,19 +1608,17 @@ class MOZ_STACK_CLASS TryEmitter
|
|||
// jumps-over-catches) result in a GOSUB being written into the bytecode
|
||||
// stream and fixed-up later.
|
||||
//
|
||||
// If ShouldUseControl is DontUseControl, all that handling is skipped.
|
||||
// DontUseControl is used by yield* and the internal try-catch around
|
||||
// IteratorClose. These internal uses must:
|
||||
// For non-syntactic try-catch-finally, all that handling is skipped.
|
||||
// The non-syntactic try-catch-finally must:
|
||||
// * have only one catch block
|
||||
// * have JSOP_GOTO at the end of catch-block
|
||||
// * have no non-local-jump
|
||||
// * don't use finally block for normal completion of try-block and
|
||||
// catch-block
|
||||
//
|
||||
// Additionally, a finally block may be emitted when ShouldUseControl is
|
||||
// DontUseControl, even if the kind is not TryCatchFinally or TryFinally,
|
||||
// because GOSUBs are not emitted. This internal use shares the
|
||||
// requirements as above.
|
||||
// Additionally, a finally block may be emitted for non-syntactic
|
||||
// try-catch-finally, even if the kind is TryCatch, because GOSUBs are not
|
||||
// emitted.
|
||||
Maybe<TryFinallyControl> controlInfo_;
|
||||
|
||||
// The stack depth before emitting JSOP_TRY.
|
||||
|
@ -1642,6 +1639,7 @@ class MOZ_STACK_CLASS TryEmitter
|
|||
// The offset of JSOP_JUMPTARGET at the beginning of the finally block.
|
||||
JumpTarget finallyStart_;
|
||||
|
||||
#ifdef DEBUG
|
||||
// The state of this emitter.
|
||||
//
|
||||
// +-------+ emitTry +-----+ emitCatch +-------+ emitEnd +-----+
|
||||
|
@ -1653,7 +1651,7 @@ class MOZ_STACK_CLASS TryEmitter
|
|||
// | v emitFinally +---------+ |
|
||||
// +->+------------>| Finally |--+
|
||||
// +---------+
|
||||
enum State {
|
||||
enum class State {
|
||||
// The initial state.
|
||||
Start,
|
||||
|
||||
|
@ -1670,40 +1668,42 @@ class MOZ_STACK_CLASS TryEmitter
|
|||
End
|
||||
};
|
||||
State state_;
|
||||
#endif
|
||||
|
||||
bool hasCatch() const {
|
||||
return kind_ == TryCatch || kind_ == TryCatchFinally;
|
||||
return kind_ == Kind::TryCatch || kind_ == Kind::TryCatchFinally;
|
||||
}
|
||||
bool hasFinally() const {
|
||||
return kind_ == TryCatchFinally || kind_ == TryFinally;
|
||||
return kind_ == Kind::TryCatchFinally || kind_ == Kind::TryFinally;
|
||||
}
|
||||
|
||||
public:
|
||||
TryEmitter(BytecodeEmitter* bce, Kind kind, ShouldUseRetVal retValKind = UseRetVal,
|
||||
ShouldUseControl controlKind = UseControl)
|
||||
TryEmitter(BytecodeEmitter* bce, Kind kind, ControlKind controlKind)
|
||||
: bce_(bce),
|
||||
kind_(kind),
|
||||
retValKind_(retValKind),
|
||||
controlKind_(controlKind),
|
||||
depth_(0),
|
||||
noteIndex_(0),
|
||||
tryStart_(0),
|
||||
state_(Start)
|
||||
tryStart_(0)
|
||||
#ifdef DEBUG
|
||||
, state_(State::Start)
|
||||
#endif
|
||||
{
|
||||
if (controlKind == UseControl)
|
||||
if (controlKind_ == ControlKind::Syntactic)
|
||||
controlInfo_.emplace(bce_, hasFinally() ? StatementKind::Finally : StatementKind::Try);
|
||||
finallyStart_.offset = 0;
|
||||
}
|
||||
|
||||
// Emits JSOP_GOTO to the end of try-catch-finally.
|
||||
// Used in `yield*`.
|
||||
bool emitJumpOverCatchAndFinally() {
|
||||
MOZ_MUST_USE bool emitJumpOverCatchAndFinally() {
|
||||
if (!bce_->emitJump(JSOP_GOTO, &catchAndFinallyJump_))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool emitTry() {
|
||||
MOZ_ASSERT(state_ == Start);
|
||||
MOZ_MUST_USE bool emitTry() {
|
||||
MOZ_ASSERT(state_ == State::Start);
|
||||
|
||||
// Since an exception can be thrown at any place inside the try block,
|
||||
// we need to restore the stack and the scope chain before we transfer
|
||||
|
@ -1721,13 +1721,15 @@ class MOZ_STACK_CLASS TryEmitter
|
|||
return false;
|
||||
tryStart_ = bce_->offset();
|
||||
|
||||
state_ = Try;
|
||||
#ifdef DEBUG
|
||||
state_ = State::Try;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
bool emitTryEnd() {
|
||||
MOZ_ASSERT(state_ == Try);
|
||||
MOZ_MUST_USE bool emitTryEnd() {
|
||||
MOZ_ASSERT(state_ == State::Try);
|
||||
MOZ_ASSERT(depth_ == bce_->stackDepth);
|
||||
|
||||
// GOSUB to finally, if present.
|
||||
|
@ -1751,14 +1753,14 @@ class MOZ_STACK_CLASS TryEmitter
|
|||
}
|
||||
|
||||
public:
|
||||
bool emitCatch() {
|
||||
MOZ_ASSERT(state_ == Try);
|
||||
MOZ_MUST_USE bool emitCatch() {
|
||||
MOZ_ASSERT(state_ == State::Try);
|
||||
if (!emitTryEnd())
|
||||
return false;
|
||||
|
||||
MOZ_ASSERT(bce_->stackDepth == depth_);
|
||||
|
||||
if (retValKind_ == UseRetVal) {
|
||||
if (controlKind_ == ControlKind::Syntactic) {
|
||||
// Clear the frame's return value that might have been set by the
|
||||
// try block:
|
||||
//
|
||||
|
@ -1769,13 +1771,15 @@ class MOZ_STACK_CLASS TryEmitter
|
|||
return false;
|
||||
}
|
||||
|
||||
state_ = Catch;
|
||||
#ifdef DEBUG
|
||||
state_ = State::Catch;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
bool emitCatchEnd() {
|
||||
MOZ_ASSERT(state_ == Catch);
|
||||
MOZ_MUST_USE bool emitCatchEnd() {
|
||||
MOZ_ASSERT(state_ == State::Catch);
|
||||
|
||||
if (!controlInfo_)
|
||||
return true;
|
||||
|
@ -1799,24 +1803,26 @@ class MOZ_STACK_CLASS TryEmitter
|
|||
// "{" character in the source code text, to improve line:column number in
|
||||
// the error reporting.
|
||||
// For non-syntactic try-catch-finally, `finallyPos` can be omitted.
|
||||
bool emitFinally(const Maybe<uint32_t>& finallyPos = Nothing()) {
|
||||
MOZ_MUST_USE bool emitFinally(const Maybe<uint32_t>& finallyPos = Nothing()) {
|
||||
// If we are using controlInfo_ (i.e., emitting a syntactic try
|
||||
// blocks), we must have specified up front if there will be a finally
|
||||
// close. For internal try blocks, like those emitted for yield* and
|
||||
// IteratorClose inside for-of loops, we can emitFinally even without
|
||||
// specifying up front, since the internal try blocks emit no GOSUBs.
|
||||
// close. For internal non-syntactic try blocks, like those emitted for
|
||||
// yield* and IteratorClose inside for-of loops, we can emitFinally even
|
||||
// without specifying up front, since the internal non-syntactic try
|
||||
// blocks emit no GOSUBs.
|
||||
if (!controlInfo_) {
|
||||
if (kind_ == TryCatch)
|
||||
kind_ = TryCatchFinally;
|
||||
if (kind_ == Kind::TryCatch)
|
||||
kind_ = Kind::TryCatchFinally;
|
||||
} else {
|
||||
MOZ_ASSERT(hasFinally());
|
||||
}
|
||||
|
||||
if (state_ == Try) {
|
||||
if (!hasCatch()) {
|
||||
MOZ_ASSERT(state_ == State::Try);
|
||||
if (!emitTryEnd())
|
||||
return false;
|
||||
} else {
|
||||
MOZ_ASSERT(state_ == Catch);
|
||||
MOZ_ASSERT(state_ == State::Catch);
|
||||
if (!emitCatchEnd())
|
||||
return false;
|
||||
}
|
||||
|
@ -1841,7 +1847,7 @@ class MOZ_STACK_CLASS TryEmitter
|
|||
if (!bce_->emit1(JSOP_FINALLY))
|
||||
return false;
|
||||
|
||||
if (retValKind_ == UseRetVal) {
|
||||
if (controlKind_ == ControlKind::Syntactic) {
|
||||
if (!bce_->emit1(JSOP_GETRVAL))
|
||||
return false;
|
||||
|
||||
|
@ -1855,15 +1861,17 @@ class MOZ_STACK_CLASS TryEmitter
|
|||
return false;
|
||||
}
|
||||
|
||||
state_ = Finally;
|
||||
#ifdef DEBUG
|
||||
state_ = State::Finally;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
bool emitFinallyEnd() {
|
||||
MOZ_ASSERT(state_ == Finally);
|
||||
MOZ_MUST_USE bool emitFinallyEnd() {
|
||||
MOZ_ASSERT(state_ == State::Finally);
|
||||
|
||||
if (retValKind_ == UseRetVal) {
|
||||
if (controlKind_ == ControlKind::Syntactic) {
|
||||
if (!bce_->emit1(JSOP_SETRVAL))
|
||||
return false;
|
||||
}
|
||||
|
@ -1876,14 +1884,13 @@ class MOZ_STACK_CLASS TryEmitter
|
|||
}
|
||||
|
||||
public:
|
||||
bool emitEnd() {
|
||||
if (state_ == Catch) {
|
||||
MOZ_ASSERT(!hasFinally());
|
||||
MOZ_MUST_USE bool emitEnd() {
|
||||
if (!hasFinally()) {
|
||||
MOZ_ASSERT(state_ == State::Catch);
|
||||
if (!emitCatchEnd())
|
||||
return false;
|
||||
} else {
|
||||
MOZ_ASSERT(state_ == Finally);
|
||||
MOZ_ASSERT(hasFinally());
|
||||
MOZ_ASSERT(state_ == State::Finally);
|
||||
if (!emitFinallyEnd())
|
||||
return false;
|
||||
}
|
||||
|
@ -1914,34 +1921,53 @@ class MOZ_STACK_CLASS TryEmitter
|
|||
return false;
|
||||
}
|
||||
|
||||
state_ = End;
|
||||
#ifdef DEBUG
|
||||
state_ = State::End;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// Class for emitting bytecode for blocks like if-then-else.
|
||||
//
|
||||
// This class can be used to emit single if-then-else block. Cascading
|
||||
// elseif's need multiple instances of this class.
|
||||
// This class can be used to emit single if-then-else block, or cascading
|
||||
// else-if blocks.
|
||||
//
|
||||
// Usage: (check for the return value is omitted for simplicity)
|
||||
//
|
||||
// `if (cond) then_block`
|
||||
// IfThenElseEmitter ifThen(this);
|
||||
// emit(cond);
|
||||
// ifThen.emitIf();
|
||||
// ifThen.emitThen();
|
||||
// emit(then_block);
|
||||
// ifThen.emitEnd();
|
||||
//
|
||||
// `if (cond) then_block else else_block`
|
||||
// IfThenElseEmitter ifThenElse(this);
|
||||
// emit(cond);
|
||||
// ifThenElse.emitIfElse();
|
||||
// ifThenElse.emitThenElse();
|
||||
// emit(then_block);
|
||||
// ifThenElse.emitElse();
|
||||
// emit(else_block);
|
||||
// ifThenElse.emitEnd();
|
||||
//
|
||||
// `if (c1) b1 else if (c2) b2 else if (c3) b3 else b4`
|
||||
// IfThenElseEmitter ifThenElse(this);
|
||||
// emit(c1);
|
||||
// ifThenElse.emitThenElse();
|
||||
// emit(b1);
|
||||
// ifThenElse.emitElseIf();
|
||||
// emit(c2);
|
||||
// ifThenElse.emitThenElse();
|
||||
// emit(b2);
|
||||
// ifThenElse.emitElseIf();
|
||||
// emit(c3);
|
||||
// ifThenElse.emitThenElse();
|
||||
// emit(b3);
|
||||
// ifThenElse.emitElse();
|
||||
// emit(b4);
|
||||
// ifThenElse.emitEnd();
|
||||
//
|
||||
// `cond ? then_expr : else_expr`
|
||||
// IfThenElseEmitter condElse(this);
|
||||
// emit(cond);
|
||||
|
@ -1955,7 +1981,10 @@ class MOZ_STACK_CLASS IfThenElseEmitter
|
|||
{
|
||||
BytecodeEmitter* bce_;
|
||||
|
||||
// Jump around the then clause, to the beginning of the else clause.
|
||||
JumpList jumpAroundThen_;
|
||||
|
||||
// Jump around the else clause, to the end of the entire branch.
|
||||
JumpList jumpsAroundElse_;
|
||||
|
||||
// The stack depth before emitting the then block.
|
||||
|
@ -1968,67 +1997,70 @@ class MOZ_STACK_CLASS IfThenElseEmitter
|
|||
// The number of values pushed in the then and else blocks.
|
||||
int32_t pushed_;
|
||||
bool calculatedPushed_;
|
||||
#endif
|
||||
|
||||
// The state of this emitter.
|
||||
//
|
||||
// +-------+ emitIf +----+ emitEnd +-----+
|
||||
// | Start |-+----------->| If |-------------------------+-------->| End |
|
||||
// +-------+ | +----+ | +-----+
|
||||
// +-------+ emitCond +------+ emitElse +------+ emitEnd +-----+
|
||||
// | Start |-+--------->| Cond |--------->| Else |------>+------->| End |
|
||||
// +-------+ | +------+ +------+ ^ +-----+
|
||||
// | |
|
||||
// | emitCond +------+ emitElse +------+ |
|
||||
// +----------->| Cond |---+--------->| Else |-+
|
||||
// | +------+ | +------+
|
||||
// | |
|
||||
// | emitIfElse +--------+ |
|
||||
// +----------->| IfElse |-+
|
||||
// +--------+
|
||||
enum State {
|
||||
// v emitThen +------+ |
|
||||
// +->+--------->| Then |------------------------>+
|
||||
// ^ | +------+ ^
|
||||
// | | |
|
||||
// | | +---+
|
||||
// | | |
|
||||
// | | emitThenElse +----------+ emitElse +------+ |
|
||||
// | +------------->| ThenElse |-+--------->| Else |-+
|
||||
// | +----------+ | +------+
|
||||
// | |
|
||||
// | | emitElseIf +--------+
|
||||
// | +----------->| ElseIf |-+
|
||||
// | +--------+ |
|
||||
// | |
|
||||
// +------------------------------------------------------+
|
||||
enum class State {
|
||||
// The initial state.
|
||||
Start,
|
||||
|
||||
// After calling emitIf.
|
||||
If,
|
||||
// After calling emitThen.
|
||||
Then,
|
||||
|
||||
// After calling emitCond.
|
||||
Cond,
|
||||
|
||||
// After calling emitIfElse.
|
||||
IfElse,
|
||||
// After calling emitThenElse.
|
||||
ThenElse,
|
||||
|
||||
// After calling Else.
|
||||
// After calling emitElse.
|
||||
Else,
|
||||
|
||||
// After calling emitElseIf.
|
||||
ElseIf,
|
||||
|
||||
// After calling emitEnd.
|
||||
End
|
||||
};
|
||||
State state_;
|
||||
#endif
|
||||
|
||||
public:
|
||||
explicit IfThenElseEmitter(BytecodeEmitter* bce)
|
||||
: bce_(bce),
|
||||
thenDepth_(0),
|
||||
thenDepth_(0)
|
||||
#ifdef DEBUG
|
||||
pushed_(0),
|
||||
calculatedPushed_(false),
|
||||
, pushed_(0)
|
||||
, calculatedPushed_(false)
|
||||
, state_(State::Start)
|
||||
#endif
|
||||
state_(Start)
|
||||
{}
|
||||
|
||||
~IfThenElseEmitter()
|
||||
{}
|
||||
|
||||
private:
|
||||
bool emitIf(State nextState) {
|
||||
MOZ_ASSERT(state_ == Start || state_ == Else);
|
||||
MOZ_ASSERT(nextState == If || nextState == IfElse || nextState == Cond);
|
||||
|
||||
// Clear jumpAroundThen_ offset that points previous JSOP_IFEQ.
|
||||
if (state_ == Else)
|
||||
jumpAroundThen_ = JumpList();
|
||||
|
||||
MOZ_MUST_USE bool emitIfInternal(SrcNoteType type) {
|
||||
// Emit an annotated branch-if-false around the then part.
|
||||
SrcNoteType type = nextState == If ? SRC_IF : nextState == IfElse ? SRC_IF_ELSE : SRC_COND;
|
||||
if (!bce_->newSrcNote(type))
|
||||
return false;
|
||||
if (!bce_->emitJump(JSOP_IFEQ, &jumpAroundThen_))
|
||||
|
@ -2039,10 +2071,9 @@ class MOZ_STACK_CLASS IfThenElseEmitter
|
|||
// If DEBUG, this is also necessary to calculate |pushed_|.
|
||||
thenDepth_ = bce_->stackDepth;
|
||||
#else
|
||||
if (nextState == IfElse || nextState == Cond)
|
||||
if (type == SRC_COND || type == SRC_IF_ELSE)
|
||||
thenDepth_ = bce_->stackDepth;
|
||||
#endif
|
||||
state_ = nextState;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2058,21 +2089,41 @@ class MOZ_STACK_CLASS IfThenElseEmitter
|
|||
}
|
||||
|
||||
public:
|
||||
bool emitIf() {
|
||||
return emitIf(If);
|
||||
MOZ_MUST_USE bool emitThen() {
|
||||
MOZ_ASSERT(state_ == State::Start || state_ == State::ElseIf);
|
||||
if (!emitIfInternal(SRC_IF))
|
||||
return false;
|
||||
|
||||
#ifdef DEBUG
|
||||
state_ = State::Then;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool emitCond() {
|
||||
return emitIf(Cond);
|
||||
MOZ_MUST_USE bool emitCond() {
|
||||
MOZ_ASSERT(state_ == State::Start);
|
||||
if (!emitIfInternal(SRC_COND))
|
||||
return false;
|
||||
|
||||
#ifdef DEBUG
|
||||
state_ = State::Cond;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool emitIfElse() {
|
||||
return emitIf(IfElse);
|
||||
MOZ_MUST_USE bool emitThenElse() {
|
||||
MOZ_ASSERT(state_ == State::Start || state_ == State::ElseIf);
|
||||
if (!emitIfInternal(SRC_IF_ELSE))
|
||||
return false;
|
||||
|
||||
#ifdef DEBUG
|
||||
state_ = State::ThenElse;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool emitElse() {
|
||||
MOZ_ASSERT(state_ == IfElse || state_ == Cond);
|
||||
|
||||
private:
|
||||
MOZ_MUST_USE bool emitElseInternal() {
|
||||
calculateOrCheckPushed();
|
||||
|
||||
// Emit a jump from the end of our then part around the else part. The
|
||||
|
@ -2085,19 +2136,54 @@ class MOZ_STACK_CLASS IfThenElseEmitter
|
|||
if (!bce_->emitJumpTargetAndPatch(jumpAroundThen_))
|
||||
return false;
|
||||
|
||||
// Clear jumpAroundThen_ offset, to tell emitEnd there was an else part.
|
||||
jumpAroundThen_ = JumpList();
|
||||
|
||||
// Restore stack depth of the then part.
|
||||
bce_->stackDepth = thenDepth_;
|
||||
state_ = Else;
|
||||
#ifdef DEBUG
|
||||
state_ = State::Else;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool emitEnd() {
|
||||
MOZ_ASSERT(state_ == If || state_ == Else);
|
||||
public:
|
||||
MOZ_MUST_USE bool emitElse() {
|
||||
MOZ_ASSERT(state_ == State::ThenElse || state_ == State::Cond);
|
||||
|
||||
if (!emitElseInternal())
|
||||
return false;
|
||||
|
||||
#ifdef DEBUG
|
||||
state_ = State::Else;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
MOZ_MUST_USE bool emitElseIf() {
|
||||
MOZ_ASSERT(state_ == State::ThenElse);
|
||||
|
||||
if (!emitElseInternal())
|
||||
return false;
|
||||
|
||||
#ifdef DEBUG
|
||||
state_ = State::ElseIf;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
MOZ_MUST_USE bool emitEnd() {
|
||||
MOZ_ASSERT(state_ == State::Then || state_ == State::Else);
|
||||
// If there was an else part for the last branch, jumpAroundThen_ is
|
||||
// already fixed up when emitting the else part.
|
||||
MOZ_ASSERT_IF(state_ == State::Then, jumpAroundThen_.offset != -1);
|
||||
MOZ_ASSERT_IF(state_ == State::Else, jumpAroundThen_.offset == -1);
|
||||
|
||||
calculateOrCheckPushed();
|
||||
|
||||
if (state_ == If) {
|
||||
// No else part, fixup the branch-if-false to come here.
|
||||
if (jumpAroundThen_.offset != -1) {
|
||||
// No else part for the last branch, fixup the branch-if-false to
|
||||
// come here.
|
||||
if (!bce_->emitJumpTargetAndPatch(jumpAroundThen_))
|
||||
return false;
|
||||
}
|
||||
|
@ -2106,7 +2192,9 @@ class MOZ_STACK_CLASS IfThenElseEmitter
|
|||
if (!bce_->emitJumpTargetAndPatch(jumpsAroundElse_))
|
||||
return false;
|
||||
|
||||
state_ = End;
|
||||
#ifdef DEBUG
|
||||
state_ = State::End;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2186,8 +2274,7 @@ class ForOfLoopControl : public LoopControl
|
|||
}
|
||||
|
||||
bool emitBeginCodeNeedingIteratorClose(BytecodeEmitter* bce) {
|
||||
tryCatch_.emplace(bce, TryEmitter::TryCatch, TryEmitter::DontUseRetVal,
|
||||
TryEmitter::DontUseControl);
|
||||
tryCatch_.emplace(bce, TryEmitter::Kind::TryCatch, TryEmitter::ControlKind::NonSyntactic);
|
||||
|
||||
if (!tryCatch_->emitTry())
|
||||
return false;
|
||||
|
@ -2217,7 +2304,7 @@ class ForOfLoopControl : public LoopControl
|
|||
return false;
|
||||
|
||||
IfThenElseEmitter ifIteratorIsNotClosed(bce);
|
||||
if (!ifIteratorIsNotClosed.emitIf()) // ITER ... EXCEPTION
|
||||
if (!ifIteratorIsNotClosed.emitThen()) // ITER ... EXCEPTION
|
||||
return false;
|
||||
|
||||
MOZ_ASSERT(slotFromTop == unsigned(bce->stackDepth - iterDepth_));
|
||||
|
@ -2243,7 +2330,7 @@ class ForOfLoopControl : public LoopControl
|
|||
IfThenElseEmitter ifGeneratorClosing(bce);
|
||||
if (!bce->emit1(JSOP_ISGENCLOSING)) // ITER ... FTYPE FVALUE CLOSING
|
||||
return false;
|
||||
if (!ifGeneratorClosing.emitIf()) // ITER ... FTYPE FVALUE
|
||||
if (!ifGeneratorClosing.emitThen()) // ITER ... FTYPE FVALUE
|
||||
return false;
|
||||
if (!bce->emitDupAt(slotFromTop + 1)) // ITER ... FTYPE FVALUE ITER
|
||||
return false;
|
||||
|
@ -5423,7 +5510,7 @@ BytecodeEmitter::emitIteratorCloseInScope(EmitterScope& currentScope,
|
|||
if (!emitPushNotUndefinedOrNull()) // ... ITER RET NOT-UNDEF-OR-NULL
|
||||
return false;
|
||||
|
||||
if (!ifReturnMethodIsDefined.emitIfElse()) // ... ITER RET
|
||||
if (!ifReturnMethodIsDefined.emitThenElse()) // ... ITER RET
|
||||
return false;
|
||||
|
||||
if (completionKind == CompletionKind::Throw) {
|
||||
|
@ -5459,8 +5546,7 @@ BytecodeEmitter::emitIteratorCloseInScope(EmitterScope& currentScope,
|
|||
Maybe<TryEmitter> tryCatch;
|
||||
|
||||
if (completionKind == CompletionKind::Throw) {
|
||||
tryCatch.emplace(this, TryEmitter::TryCatch, TryEmitter::DontUseRetVal,
|
||||
TryEmitter::DontUseControl);
|
||||
tryCatch.emplace(this, TryEmitter::Kind::TryCatch, TryEmitter::ControlKind::NonSyntactic);
|
||||
|
||||
// Mutate stack to balance stack for try-catch.
|
||||
if (!emit1(JSOP_UNDEFINED)) // ... RET ITER UNDEF
|
||||
|
@ -5804,7 +5890,7 @@ BytecodeEmitter::emitDestructuringOpsArray(ParseNode* pattern, DestructuringFlav
|
|||
// If spread is not the first element of the pattern,
|
||||
// iterator can already be completed.
|
||||
// ... OBJ NEXT ITER *LREF DONE
|
||||
if (!ifThenElse.emitIfElse()) // ... OBJ NEXT ITER *LREF
|
||||
if (!ifThenElse.emitThenElse()) // ... OBJ NEXT ITER *LREF
|
||||
return false;
|
||||
|
||||
if (!emitUint32Operand(JSOP_NEWARRAY, 0)) // ... OBJ NEXT ITER *LREF ARRAY
|
||||
|
@ -5859,7 +5945,7 @@ BytecodeEmitter::emitDestructuringOpsArray(ParseNode* pattern, DestructuringFlav
|
|||
IfThenElseEmitter ifAlreadyDone(this);
|
||||
if (!isFirst) {
|
||||
// ... OBJ NEXT ITER *LREF DONE
|
||||
if (!ifAlreadyDone.emitIfElse()) // ... OBJ NEXT ITER *LREF
|
||||
if (!ifAlreadyDone.emitThenElse()) // ... OBJ NEXT ITER *LREF
|
||||
return false;
|
||||
|
||||
if (!emit1(JSOP_UNDEFINED)) // ... OBJ NEXT ITER *LREF UNDEF
|
||||
|
@ -5894,7 +5980,7 @@ BytecodeEmitter::emitDestructuringOpsArray(ParseNode* pattern, DestructuringFlav
|
|||
return false;
|
||||
|
||||
IfThenElseEmitter ifDone(this);
|
||||
if (!ifDone.emitIfElse()) // ... OBJ NEXT ITER DONE *LREF RESULT
|
||||
if (!ifDone.emitThenElse()) // ... OBJ NEXT ITER DONE *LREF RESULT
|
||||
return false;
|
||||
|
||||
if (!emit1(JSOP_POP)) // ... OBJ NEXT ITER DONE *LREF
|
||||
|
@ -5946,7 +6032,7 @@ BytecodeEmitter::emitDestructuringOpsArray(ParseNode* pattern, DestructuringFlav
|
|||
// IteratorClose.
|
||||
// ... OBJ NEXT ITER DONE
|
||||
IfThenElseEmitter ifDone(this);
|
||||
if (!ifDone.emitIfElse()) // ... OBJ NEXT ITER
|
||||
if (!ifDone.emitThenElse()) // ... OBJ NEXT ITER
|
||||
return false;
|
||||
if (!emitPopN(2)) // ... OBJ
|
||||
return false;
|
||||
|
@ -6788,14 +6874,14 @@ BytecodeEmitter::emitTry(ParseNode* pn)
|
|||
TryEmitter::Kind kind;
|
||||
if (catchScope) {
|
||||
if (finallyNode)
|
||||
kind = TryEmitter::TryCatchFinally;
|
||||
kind = TryEmitter::Kind::TryCatchFinally;
|
||||
else
|
||||
kind = TryEmitter::TryCatch;
|
||||
kind = TryEmitter::Kind::TryCatch;
|
||||
} else {
|
||||
MOZ_ASSERT(finallyNode);
|
||||
kind = TryEmitter::TryFinally;
|
||||
kind = TryEmitter::Kind::TryFinally;
|
||||
}
|
||||
TryEmitter tryCatch(this, kind);
|
||||
TryEmitter tryCatch(this, kind, TryEmitter::ControlKind::Syntactic);
|
||||
|
||||
if (!tryCatch.emitTry())
|
||||
return false;
|
||||
|
@ -6852,10 +6938,10 @@ BytecodeEmitter::emitIf(ParseNode* pn)
|
|||
|
||||
ParseNode* elseNode = pn->pn_kid3;
|
||||
if (elseNode) {
|
||||
if (!ifThenElse.emitIfElse())
|
||||
if (!ifThenElse.emitThenElse())
|
||||
return false;
|
||||
} else {
|
||||
if (!ifThenElse.emitIf())
|
||||
if (!ifThenElse.emitThen())
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -6864,14 +6950,18 @@ BytecodeEmitter::emitIf(ParseNode* pn)
|
|||
return false;
|
||||
|
||||
if (elseNode) {
|
||||
if (!ifThenElse.emitElse())
|
||||
return false;
|
||||
|
||||
if (elseNode->isKind(ParseNodeKind::If)) {
|
||||
pn = elseNode;
|
||||
|
||||
if (!ifThenElse.emitElseIf())
|
||||
return false;
|
||||
|
||||
goto if_again;
|
||||
}
|
||||
|
||||
if (!ifThenElse.emitElse())
|
||||
return false;
|
||||
|
||||
/* Emit code for the else part. */
|
||||
if (!emitTreeInBranch(elseNode))
|
||||
return false;
|
||||
|
@ -7074,7 +7164,7 @@ BytecodeEmitter::emitAsyncIterator()
|
|||
return false;
|
||||
if (!emit1(JSOP_NOT)) // OBJ ITERFN UNDEF-OR-NULL
|
||||
return false;
|
||||
if (!ifAsyncIterIsUndefined.emitIfElse()) // OBJ ITERFN
|
||||
if (!ifAsyncIterIsUndefined.emitThenElse()) // OBJ ITERFN
|
||||
return false;
|
||||
|
||||
if (!emit1(JSOP_POP)) // OBJ
|
||||
|
@ -7389,7 +7479,7 @@ BytecodeEmitter::emitForOf(ParseNode* forOfLoop, EmitterScope* headLexicalEmitte
|
|||
|
||||
IfThenElseEmitter ifDone(this);
|
||||
|
||||
if (!ifDone.emitIf()) // NEXT ITER RESULT
|
||||
if (!ifDone.emitThen()) // NEXT ITER RESULT
|
||||
return false;
|
||||
|
||||
// Remove RESULT from the stack to release it.
|
||||
|
@ -8537,8 +8627,8 @@ BytecodeEmitter::emitYieldStar(ParseNode* iter)
|
|||
int32_t startDepth = stackDepth;
|
||||
MOZ_ASSERT(startDepth >= 3);
|
||||
|
||||
TryEmitter tryCatch(this, TryEmitter::TryCatchFinally, TryEmitter::DontUseRetVal,
|
||||
TryEmitter::DontUseControl);
|
||||
TryEmitter tryCatch(this, TryEmitter::Kind::TryCatchFinally,
|
||||
TryEmitter::ControlKind::NonSyntactic);
|
||||
if (!tryCatch.emitJumpOverCatchAndFinally()) // NEXT ITER RESULT
|
||||
return false;
|
||||
|
||||
|
@ -8582,7 +8672,7 @@ BytecodeEmitter::emitYieldStar(ParseNode* iter)
|
|||
return false;
|
||||
|
||||
IfThenElseEmitter ifThrowMethodIsNotDefined(this);
|
||||
if (!ifThrowMethodIsNotDefined.emitIf()) // NEXT ITER RESULT EXCEPTION ITER THROW
|
||||
if (!ifThrowMethodIsNotDefined.emitThen()) // NEXT ITER RESULT EXCEPTION ITER THROW
|
||||
return false;
|
||||
savedDepthTemp = stackDepth;
|
||||
if (!emit1(JSOP_POP)) // NEXT ITER RESULT EXCEPTION ITER
|
||||
|
@ -8640,7 +8730,7 @@ BytecodeEmitter::emitYieldStar(ParseNode* iter)
|
|||
IfThenElseEmitter ifGeneratorClosing(this);
|
||||
if (!emit1(JSOP_ISGENCLOSING)) // NEXT ITER RESULT FTYPE FVALUE CLOSING
|
||||
return false;
|
||||
if (!ifGeneratorClosing.emitIf()) // NEXT ITER RESULT FTYPE FVALUE
|
||||
if (!ifGeneratorClosing.emitThen()) // NEXT ITER RESULT FTYPE FVALUE
|
||||
return false;
|
||||
|
||||
// Step ii.
|
||||
|
@ -8664,7 +8754,7 @@ BytecodeEmitter::emitYieldStar(ParseNode* iter)
|
|||
//
|
||||
// Call "return" with the argument passed to Generator.prototype.return,
|
||||
// which is currently in rval.value.
|
||||
if (!ifReturnMethodIsDefined.emitIfElse()) // NEXT ITER OLDRESULT FTYPE FVALUE ITER RET
|
||||
if (!ifReturnMethodIsDefined.emitThenElse()) // NEXT ITER OLDRESULT FTYPE FVALUE ITER RET
|
||||
return false;
|
||||
if (!emit1(JSOP_SWAP)) // NEXT ITER OLDRESULT FTYPE FVALUE RET ITER
|
||||
return false;
|
||||
|
@ -8694,7 +8784,7 @@ BytecodeEmitter::emitYieldStar(ParseNode* iter)
|
|||
return false;
|
||||
if (!emitAtomOp(cx->names().done, JSOP_GETPROP)) // NEXT ITER OLDRESULT FTYPE FVALUE RESULT DONE
|
||||
return false;
|
||||
if (!ifReturnDone.emitIfElse()) // NEXT ITER OLDRESULT FTYPE FVALUE RESULT
|
||||
if (!ifReturnDone.emitThenElse()) // NEXT ITER OLDRESULT FTYPE FVALUE RESULT
|
||||
return false;
|
||||
if (!emitAtomOp(cx->names().value, JSOP_GETPROP)) // NEXT ITER OLDRESULT FTYPE FVALUE VALUE
|
||||
return false;
|
||||
|
@ -9453,7 +9543,7 @@ BytecodeEmitter::emitCallOrNew(ParseNode* pn, ValueUsage valueUsage /* = ValueUs
|
|||
if (!emit1(JSOP_NOT))
|
||||
return false;
|
||||
|
||||
if (!ifNotOptimizable.emitIf())
|
||||
if (!ifNotOptimizable.emitThen())
|
||||
return false;
|
||||
|
||||
if (!emit1(JSOP_POP))
|
||||
|
@ -10581,7 +10671,7 @@ BytecodeEmitter::emitClass(ParseNode* pn)
|
|||
return false;
|
||||
|
||||
// [THEN] funProto = heritage, objProto = heritage.prototype
|
||||
if (!ifThenElse.emitIfElse())
|
||||
if (!ifThenElse.emitThenElse())
|
||||
return false;
|
||||
if (!emit1(JSOP_DUP)) // ... HERITAGE HERITAGE
|
||||
return false;
|
||||
|
|
|
@ -86,7 +86,7 @@ GCRuntime::tryNewNurseryObject(JSContext* cx, size_t thingSize, size_t nDynamicS
|
|||
|
||||
MOZ_ASSERT(cx->isNurseryAllocAllowed());
|
||||
MOZ_ASSERT(!cx->isNurseryAllocSuppressed());
|
||||
MOZ_ASSERT(!cx->realm()->isAtomsRealm());
|
||||
MOZ_ASSERT(!cx->zone()->isAtomsZone());
|
||||
|
||||
JSObject* obj = cx->nursery().allocateObject(cx, thingSize, nDynamicSlots, clasp);
|
||||
if (obj)
|
||||
|
@ -140,7 +140,7 @@ GCRuntime::tryNewNurseryString(JSContext* cx, size_t thingSize, AllocKind kind)
|
|||
MOZ_ASSERT(cx->isNurseryAllocAllowed());
|
||||
MOZ_ASSERT(!cx->helperThread());
|
||||
MOZ_ASSERT(!cx->isNurseryAllocSuppressed());
|
||||
MOZ_ASSERT(!cx->realm()->isAtomsRealm());
|
||||
MOZ_ASSERT(!cx->zone()->isAtomsZone());
|
||||
|
||||
Cell* cell = cx->nursery().allocateString(cx->zone(), thingSize, kind);
|
||||
if (cell)
|
||||
|
@ -275,13 +275,13 @@ GCRuntime::checkAllocatorState(JSContext* cx, AllocKind kind)
|
|||
}
|
||||
|
||||
#if defined(JS_GC_ZEAL) || defined(DEBUG)
|
||||
MOZ_ASSERT_IF(cx->realm()->isAtomsRealm(),
|
||||
MOZ_ASSERT_IF(cx->zone()->isAtomsZone(),
|
||||
kind == AllocKind::ATOM ||
|
||||
kind == AllocKind::FAT_INLINE_ATOM ||
|
||||
kind == AllocKind::SYMBOL ||
|
||||
kind == AllocKind::JITCODE ||
|
||||
kind == AllocKind::SCOPE);
|
||||
MOZ_ASSERT_IF(!cx->realm()->isAtomsRealm(),
|
||||
MOZ_ASSERT_IF(!cx->zone()->isAtomsZone(),
|
||||
kind != AllocKind::ATOM &&
|
||||
kind != AllocKind::FAT_INLINE_ATOM);
|
||||
MOZ_ASSERT(!JS::CurrentThreadIsHeapBusy());
|
||||
|
|
|
@ -83,7 +83,7 @@ AtomMarkingRuntime::computeBitmapFromChunkMarkBits(JSRuntime* runtime, DenseBitm
|
|||
if (!bitmap.ensureSpace(allocatedWords))
|
||||
return false;
|
||||
|
||||
Zone* atomsZone = runtime->unsafeAtomsRealm()->zone();
|
||||
Zone* atomsZone = runtime->unsafeAtomsZone();
|
||||
for (auto thingKind : AllAllocKinds()) {
|
||||
for (ArenaIter aiter(atomsZone, thingKind); !aiter.done(); aiter.next()) {
|
||||
Arena* arena = aiter.get();
|
||||
|
@ -117,7 +117,7 @@ AddBitmapToChunkMarkBits(JSRuntime* runtime, Bitmap& bitmap)
|
|||
static_assert(ArenaBitmapBits == ArenaBitmapWords * JS_BITS_PER_WORD,
|
||||
"ArenaBitmapWords must evenly divide ArenaBitmapBits");
|
||||
|
||||
Zone* atomsZone = runtime->unsafeAtomsRealm()->zone();
|
||||
Zone* atomsZone = runtime->unsafeAtomsZone();
|
||||
for (auto thingKind : AllAllocKinds()) {
|
||||
for (ArenaIter aiter(atomsZone, thingKind); !aiter.done(); aiter.next()) {
|
||||
Arena* arena = aiter.get();
|
||||
|
|
|
@ -3852,7 +3852,6 @@ Zone::sweepCompartments(FreeOp* fop, bool keepAtleastOne, bool destroyingRuntime
|
|||
while (read < end) {
|
||||
JSCompartment* comp = *read++;
|
||||
Realm* realm = JS::GetRealmForCompartment(comp);
|
||||
MOZ_ASSERT(!realm->isAtomsRealm());
|
||||
|
||||
/*
|
||||
* Don't delete the last compartment and realm if all the ones before
|
||||
|
@ -4126,7 +4125,7 @@ CompartmentCheckTracer::onChild(const JS::GCCellPtr& thing)
|
|||
{
|
||||
JSCompartment* comp = DispatchTyped(MaybeCompartmentFunctor(), thing);
|
||||
if (comp && compartment) {
|
||||
MOZ_ASSERT(comp == compartment || runtime()->isAtomsCompartment(comp) ||
|
||||
MOZ_ASSERT(comp == compartment ||
|
||||
(srcKind == JS::TraceKind::Object &&
|
||||
InCrossCompartmentMap(static_cast<JSObject*>(src), thing)));
|
||||
} else {
|
||||
|
@ -4223,7 +4222,7 @@ GCRuntime::prepareZonesForCollection(JS::gcreason::Reason reason, bool* isFullOu
|
|||
/* Assert that zone state is as we expect */
|
||||
for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) {
|
||||
MOZ_ASSERT(!zone->isCollecting());
|
||||
MOZ_ASSERT(!zone->compartments().empty());
|
||||
MOZ_ASSERT_IF(!zone->isAtomsZone(), !zone->compartments().empty());
|
||||
for (auto i : AllAllocKinds())
|
||||
MOZ_ASSERT(!zone->arenas.arenaListsToSweep(i));
|
||||
}
|
||||
|
@ -4251,7 +4250,7 @@ GCRuntime::prepareZonesForCollection(JS::gcreason::Reason reason, bool* isFullOu
|
|||
// executable code limit.
|
||||
bool canAllocateMoreCode = jit::CanLikelyAllocateMoreExecutableMemory();
|
||||
|
||||
for (CompartmentsIter c(rt, WithAtoms); !c.done(); c.next()) {
|
||||
for (CompartmentsIter c(rt); !c.done(); c.next()) {
|
||||
c->scheduledForDestruction = false;
|
||||
c->maybeAlive = false;
|
||||
for (RealmsInCompartmentIter r(c); !r.done(); r.next()) {
|
||||
|
@ -4478,7 +4477,7 @@ GCRuntime::markCompartments()
|
|||
|
||||
Vector<JSCompartment*, 0, js::SystemAllocPolicy> workList;
|
||||
|
||||
for (CompartmentsIter comp(rt, SkipAtoms); !comp.done(); comp.next()) {
|
||||
for (CompartmentsIter comp(rt); !comp.done(); comp.next()) {
|
||||
if (comp->maybeAlive) {
|
||||
if (!workList.append(comp))
|
||||
return;
|
||||
|
@ -4895,7 +4894,7 @@ DropStringWrappers(JSRuntime* rt)
|
|||
* us to sweep the wrappers in all compartments every time we sweep a
|
||||
* compartment group.
|
||||
*/
|
||||
for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) {
|
||||
for (CompartmentsIter c(rt); !c.done(); c.next()) {
|
||||
for (JSCompartment::StringWrapperEnum e(c); !e.empty(); e.popFront()) {
|
||||
MOZ_ASSERT(e.front().key().is<JSString*>());
|
||||
e.removeFront();
|
||||
|
@ -5137,7 +5136,7 @@ static void
|
|||
AssertNoWrappersInGrayList(JSRuntime* rt)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) {
|
||||
for (CompartmentsIter c(rt); !c.done(); c.next()) {
|
||||
MOZ_ASSERT(!c->gcIncomingGrayPointers);
|
||||
for (JSCompartment::NonStringWrapperEnum e(c); !e.empty(); e.popFront())
|
||||
AssertNotOnGrayList(&e.front().value().unbarrieredGet().toObject());
|
||||
|
@ -5412,7 +5411,7 @@ UpdateAtomsBitmap(GCParallelTask* task)
|
|||
// For convenience sweep these tables non-incrementally as part of bitmap
|
||||
// sweeping; they are likely to be much smaller than the main atoms table.
|
||||
runtime->unsafeSymbolRegistry().sweep();
|
||||
for (RealmsIter realm(runtime, SkipAtoms); !realm.done(); realm.next())
|
||||
for (RealmsIter realm(runtime); !realm.done(); realm.next())
|
||||
realm->sweepVarNames();
|
||||
}
|
||||
|
||||
|
@ -6888,7 +6887,7 @@ GCRuntime::resetIncrementalGC(gc::AbortReason reason, AutoTraceSession& session)
|
|||
case State::Sweep: {
|
||||
marker.reset();
|
||||
|
||||
for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next())
|
||||
for (CompartmentsIter c(rt); !c.done(); c.next())
|
||||
c->scheduledForDestruction = false;
|
||||
|
||||
/* Finish sweeping the current sweep group, then abort. */
|
||||
|
@ -7552,7 +7551,7 @@ GCRuntime::maybeDoCycleCollection()
|
|||
|
||||
size_t realmsTotal = 0;
|
||||
size_t realmsGray = 0;
|
||||
for (RealmsIter realm(rt, SkipAtoms); !realm.done(); realm.next()) {
|
||||
for (RealmsIter realm(rt); !realm.done(); realm.next()) {
|
||||
++realmsTotal;
|
||||
GlobalObject* global = realm->unsafeUnbarrieredMaybeGlobal();
|
||||
if (global && global->isMarkedGray())
|
||||
|
@ -7602,7 +7601,7 @@ GCRuntime::shouldRepeatForDeadZone(JS::gcreason::Reason reason)
|
|||
if (!isIncremental)
|
||||
return false;
|
||||
|
||||
for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) {
|
||||
for (CompartmentsIter c(rt); !c.done(); c.next()) {
|
||||
if (c->scheduledForDestruction)
|
||||
return true;
|
||||
}
|
||||
|
@ -7961,7 +7960,7 @@ js::NewRealm(JSContext* cx, JSPrincipals* principals, const JS::RealmOptions& op
|
|||
return nullptr;
|
||||
|
||||
// Set up the principals.
|
||||
JS_SetCompartmentPrincipals(JS::GetCompartmentForRealm(realm), principals);
|
||||
JS::SetRealmPrincipals(realm, principals);
|
||||
|
||||
JSCompartment* comp = realm->compartment();
|
||||
if (!comp->realms().append(realm)) {
|
||||
|
@ -8488,7 +8487,7 @@ js::gc::CheckHashTablesAfterMovingGC(JSRuntime* rt)
|
|||
}
|
||||
}
|
||||
|
||||
for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) {
|
||||
for (CompartmentsIter c(rt); !c.done(); c.next()) {
|
||||
c->checkWrapperMapAfterMovingGC();
|
||||
|
||||
for (RealmsInCompartmentIter r(c); !r.done(); r.next()) {
|
||||
|
|
|
@ -1029,7 +1029,7 @@ js::Nursery::sweep(JSTracer* trc)
|
|||
}
|
||||
cellsWithUid_.clear();
|
||||
|
||||
for (CompartmentsIter c(runtime(), SkipAtoms); !c.done(); c.next())
|
||||
for (CompartmentsIter c(runtime()); !c.done(); c.next())
|
||||
c->sweepAfterMinorGC(trc);
|
||||
|
||||
sweepDictionaryModeObjects();
|
||||
|
|
|
@ -67,7 +67,7 @@ class GCZonesIter
|
|||
MOZ_ASSERT_IF(rt->gc.atomsZone->isCollectingFromAnyThread(),
|
||||
!rt->hasHelperThreadZones());
|
||||
|
||||
if (!zone->isCollectingFromAnyThread())
|
||||
if (!done() && !zone->isCollectingFromAnyThread())
|
||||
next();
|
||||
}
|
||||
|
||||
|
@ -95,11 +95,22 @@ using GCRealmsIter = CompartmentsOrRealmsIterT<GCZonesIter, RealmsInZoneIter>;
|
|||
/* Iterates over all zones in the current sweep group. */
|
||||
class SweepGroupZonesIter {
|
||||
JS::Zone* current;
|
||||
ZoneSelector selector;
|
||||
|
||||
public:
|
||||
explicit SweepGroupZonesIter(JSRuntime* rt) {
|
||||
explicit SweepGroupZonesIter(JSRuntime* rt, ZoneSelector selector = WithAtoms)
|
||||
: selector(selector)
|
||||
{
|
||||
MOZ_ASSERT(CurrentThreadIsPerformingGC());
|
||||
current = rt->gc.getCurrentSweepGroup();
|
||||
maybeSkipAtomsZone();
|
||||
}
|
||||
|
||||
void maybeSkipAtomsZone() {
|
||||
if (selector == SkipAtoms && current && current->isAtomsZone()) {
|
||||
current = current->nextNodeInGroup();
|
||||
MOZ_ASSERT_IF(current, !current->isAtomsZone());
|
||||
}
|
||||
}
|
||||
|
||||
bool done() const { return !current; }
|
||||
|
@ -107,6 +118,7 @@ class SweepGroupZonesIter {
|
|||
void next() {
|
||||
MOZ_ASSERT(!done());
|
||||
current = current->nextNodeInGroup();
|
||||
maybeSkipAtomsZone();
|
||||
}
|
||||
|
||||
JS::Zone* get() const {
|
||||
|
|
|
@ -141,7 +141,7 @@ JS_IterateCompartments(JSContext* cx, void* data,
|
|||
{
|
||||
AutoTraceSession session(cx->runtime());
|
||||
|
||||
for (CompartmentsIter c(cx->runtime(), WithAtoms); !c.done(); c.next())
|
||||
for (CompartmentsIter c(cx->runtime()); !c.done(); c.next())
|
||||
(*compartmentCallback)(cx, data, c);
|
||||
}
|
||||
|
||||
|
@ -151,7 +151,7 @@ JS::IterateRealms(JSContext* cx, void* data, JS::IterateRealmCallback realmCallb
|
|||
AutoTraceSession session(cx->runtime());
|
||||
|
||||
Rooted<Realm*> realm(cx);
|
||||
for (RealmsIter r(cx->runtime(), WithAtoms); !r.done(); r.next()) {
|
||||
for (RealmsIter r(cx->runtime()); !r.done(); r.next()) {
|
||||
realm = r;
|
||||
(*realmCallback)(cx, data, realm);
|
||||
}
|
||||
|
|
|
@ -193,14 +193,7 @@ class CompartmentsOrRealmsIterT
|
|||
|
||||
public:
|
||||
explicit CompartmentsOrRealmsIterT(JSRuntime* rt)
|
||||
: iterMarker(&rt->gc), zone(rt)
|
||||
{
|
||||
if (!zone.done())
|
||||
inner.emplace(zone);
|
||||
}
|
||||
|
||||
CompartmentsOrRealmsIterT(JSRuntime* rt, ZoneSelector selector)
|
||||
: iterMarker(&rt->gc), zone(rt, selector)
|
||||
: iterMarker(&rt->gc), zone(rt, SkipAtoms)
|
||||
{
|
||||
if (!zone.done())
|
||||
inner.emplace(zone);
|
||||
|
|
|
@ -369,7 +369,7 @@ js::gc::GCRuntime::traceRuntimeCommon(JSTracer* trc, TraceOrMarkRuntime traceOrM
|
|||
|
||||
// Trace all realm roots, but not the realm itself; it is traced via the
|
||||
// parent pointer if traceRoots actually traces anything.
|
||||
for (RealmsIter r(rt, SkipAtoms); !r.done(); r.next())
|
||||
for (RealmsIter r(rt); !r.done(); r.next())
|
||||
r->traceRoots(trc, traceOrMark);
|
||||
|
||||
// Trace helper thread roots.
|
||||
|
@ -427,7 +427,7 @@ js::gc::GCRuntime::finishRoots()
|
|||
|
||||
rt->finishSelfHosting();
|
||||
|
||||
for (RealmsIter r(rt, SkipAtoms); !r.done(); r.next())
|
||||
for (RealmsIter r(rt); !r.done(); r.next())
|
||||
r->finishRoots();
|
||||
|
||||
#ifdef DEBUG
|
||||
|
|
|
@ -163,7 +163,7 @@ struct TraceIncomingFunctor {
|
|||
JS_PUBLIC_API(void)
|
||||
JS::TraceIncomingCCWs(JSTracer* trc, const JS::CompartmentSet& compartments)
|
||||
{
|
||||
for (js::CompartmentsIter comp(trc->runtime(), SkipAtoms); !comp.done(); comp.next()) {
|
||||
for (js::CompartmentsIter comp(trc->runtime()); !comp.done(); comp.next()) {
|
||||
if (compartments.has(comp))
|
||||
continue;
|
||||
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
var g = newGlobal();
|
||||
var dbg = Debugger(g);
|
||||
dbg.onEnterFrame = function(frame) {};
|
||||
|
||||
var g2 = newGlobal();
|
||||
g2[g] = g;
|
||||
g2.evaluate("grayRoot()")
|
||||
g2 = undefined;
|
||||
|
||||
g = undefined;
|
||||
dbg = undefined;
|
||||
|
||||
gc();
|
||||
startgc(100000);
|
|
@ -1043,7 +1043,7 @@ JitRuntime::getBaselineDebugModeOSRHandler(JSContext* cx)
|
|||
{
|
||||
if (!baselineDebugModeOSRHandler_) {
|
||||
AutoLockForExclusiveAccess lock(cx);
|
||||
AutoAtomsRealm ar(cx, lock);
|
||||
AutoAtomsZone az(cx, lock);
|
||||
uint32_t offset;
|
||||
if (JitCode* code = generateBaselineDebugModeOSRHandler(cx, &offset)) {
|
||||
baselineDebugModeOSRHandler_ = code;
|
||||
|
|
|
@ -108,6 +108,7 @@ JitContext::JitContext(CompileRuntime* rt, CompileRealm* realm, TempAllocator* t
|
|||
temp(temp),
|
||||
runtime(rt),
|
||||
realm(realm),
|
||||
zone(realm ? realm->zone() : nullptr),
|
||||
prev_(CurrentJitContext()),
|
||||
assemblerCount_(0)
|
||||
{
|
||||
|
@ -119,6 +120,7 @@ JitContext::JitContext(JSContext* cx, TempAllocator* temp)
|
|||
temp(temp),
|
||||
runtime(CompileRuntime::get(cx->runtime())),
|
||||
realm(CompileRealm::get(cx->realm())),
|
||||
zone(CompileZone::get(cx->zone())),
|
||||
prev_(CurrentJitContext()),
|
||||
assemblerCount_(0)
|
||||
{
|
||||
|
@ -211,13 +213,10 @@ JitRuntime::startTrampolineCode(MacroAssembler& masm)
|
|||
bool
|
||||
JitRuntime::initialize(JSContext* cx, AutoLockForExclusiveAccess& lock)
|
||||
{
|
||||
AutoAtomsRealm ar(cx, lock);
|
||||
AutoAtomsZone az(cx, lock);
|
||||
|
||||
JitContext jctx(cx, nullptr);
|
||||
|
||||
if (!cx->realm()->ensureJitRealmExists(cx))
|
||||
return false;
|
||||
|
||||
functionWrappers_ = cx->new_<VMWrapperMap>(cx);
|
||||
if (!functionWrappers_ || !functionWrappers_->init())
|
||||
return false;
|
||||
|
@ -339,7 +338,7 @@ JitRuntime::debugTrapHandler(JSContext* cx)
|
|||
// JitRuntime code stubs are shared across compartments and have to
|
||||
// be allocated in the atoms zone.
|
||||
AutoLockForExclusiveAccess lock(cx);
|
||||
AutoAtomsRealm ar(cx, lock);
|
||||
AutoAtomsZone az(cx, lock);
|
||||
debugTrapHandler_ = generateDebugTrapHandler(cx);
|
||||
}
|
||||
return debugTrapHandler_;
|
||||
|
@ -592,7 +591,7 @@ JitRuntime::Trace(JSTracer* trc, AutoLockForExclusiveAccess& lock)
|
|||
if (trc->runtime()->atomsAreFinished())
|
||||
return;
|
||||
|
||||
Zone* zone = trc->runtime()->atomsRealm(lock)->zone();
|
||||
Zone* zone = trc->runtime()->atomsZone(lock);
|
||||
for (auto i = zone->cellIter<JitCode>(); !i.done(); i.next()) {
|
||||
JitCode* code = i;
|
||||
TraceRoot(trc, &code, "wrapper");
|
||||
|
|
|
@ -72,6 +72,7 @@ class JitContext
|
|||
// during compilation.
|
||||
CompileRuntime* runtime;
|
||||
CompileRealm* realm;
|
||||
CompileZone* zone;
|
||||
|
||||
int getNextAssemblerId() {
|
||||
return assemblerCount_++;
|
||||
|
|
|
@ -346,9 +346,7 @@ class RInstructionResults
|
|||
|
||||
MOZ_MUST_USE bool init(JSContext* cx, uint32_t numResults);
|
||||
bool isInitialized() const;
|
||||
#ifdef DEBUG
|
||||
size_t length() const;
|
||||
#endif
|
||||
|
||||
JitFrameLayout* frame() const;
|
||||
|
||||
|
|
|
@ -1494,13 +1494,11 @@ RInstructionResults::isInitialized() const
|
|||
return initialized_;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
size_t
|
||||
RInstructionResults::length() const
|
||||
{
|
||||
return results_->length();
|
||||
}
|
||||
#endif
|
||||
|
||||
JitFrameLayout*
|
||||
RInstructionResults::frame() const
|
||||
|
@ -1953,7 +1951,7 @@ SnapshotIterator::initInstructionResults(MaybeReadFallback& fallback)
|
|||
}
|
||||
|
||||
MOZ_ASSERT(results->isInitialized());
|
||||
MOZ_ASSERT(results->length() == recover_.numInstructions() - 1);
|
||||
MOZ_RELEASE_ASSERT(results->length() == recover_.numInstructions() - 1);
|
||||
instructionResults_ = results;
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -157,8 +157,8 @@ struct Imm64
|
|||
static inline bool
|
||||
IsCompilingWasm()
|
||||
{
|
||||
// wasm compilation pushes a JitContext with a null Realm.
|
||||
return GetJitContext()->realm == nullptr;
|
||||
// wasm compilation pushes a JitContext with a null Zone.
|
||||
return GetJitContext()->zone == nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -797,7 +797,7 @@ ReleaseAssertObjectHasNoWrappers(JSContext* cx, HandleObject target)
|
|||
{
|
||||
RootedValue origv(cx, ObjectValue(*target));
|
||||
|
||||
for (CompartmentsIter c(cx->runtime(), SkipAtoms); !c.done(); c.next()) {
|
||||
for (CompartmentsIter c(cx->runtime()); !c.done(); c.next()) {
|
||||
if (c->lookupWrapper(origv))
|
||||
MOZ_CRASH("wrapper found for target object");
|
||||
}
|
||||
|
@ -954,7 +954,7 @@ JS_RefreshCrossCompartmentWrappers(JSContext* cx, HandleObject obj)
|
|||
JS_PUBLIC_API(bool)
|
||||
JS_InitStandardClasses(JSContext* cx, HandleObject obj)
|
||||
{
|
||||
MOZ_ASSERT(!cx->realm()->isAtomsRealm());
|
||||
MOZ_ASSERT(!cx->zone()->isAtomsZone());
|
||||
AssertHeapIsIdle();
|
||||
CHECK_REQUEST(cx);
|
||||
|
||||
|
@ -1974,7 +1974,7 @@ JS_FireOnNewGlobalObject(JSContext* cx, JS::HandleObject global)
|
|||
JS_PUBLIC_API(JSObject*)
|
||||
JS_NewObject(JSContext* cx, const JSClass* jsclasp)
|
||||
{
|
||||
MOZ_ASSERT(!cx->realm()->isAtomsRealm());
|
||||
MOZ_ASSERT(!cx->zone()->isAtomsZone());
|
||||
AssertHeapIsIdle();
|
||||
CHECK_REQUEST(cx);
|
||||
|
||||
|
@ -1991,7 +1991,7 @@ JS_NewObject(JSContext* cx, const JSClass* jsclasp)
|
|||
JS_PUBLIC_API(JSObject*)
|
||||
JS_NewObjectWithGivenProto(JSContext* cx, const JSClass* jsclasp, HandleObject proto)
|
||||
{
|
||||
MOZ_ASSERT(!cx->realm()->isAtomsRealm());
|
||||
MOZ_ASSERT(!cx->zone()->isAtomsZone());
|
||||
AssertHeapIsIdle();
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, proto);
|
||||
|
@ -2009,7 +2009,7 @@ JS_NewObjectWithGivenProto(JSContext* cx, const JSClass* jsclasp, HandleObject p
|
|||
JS_PUBLIC_API(JSObject*)
|
||||
JS_NewPlainObject(JSContext* cx)
|
||||
{
|
||||
MOZ_ASSERT(!cx->realm()->isAtomsRealm());
|
||||
MOZ_ASSERT(!cx->zone()->isAtomsZone());
|
||||
AssertHeapIsIdle();
|
||||
CHECK_REQUEST(cx);
|
||||
|
||||
|
@ -2909,7 +2909,7 @@ JS_PUBLIC_API(bool)
|
|||
JS_CallFunctionValue(JSContext* cx, HandleObject obj, HandleValue fval, const HandleValueArray& args,
|
||||
MutableHandleValue rval)
|
||||
{
|
||||
MOZ_ASSERT(!cx->realm()->isAtomsRealm());
|
||||
MOZ_ASSERT(!cx->zone()->isAtomsZone());
|
||||
AssertHeapIsIdle();
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, obj, fval, args);
|
||||
|
@ -2926,7 +2926,7 @@ JS_PUBLIC_API(bool)
|
|||
JS_CallFunction(JSContext* cx, HandleObject obj, HandleFunction fun, const HandleValueArray& args,
|
||||
MutableHandleValue rval)
|
||||
{
|
||||
MOZ_ASSERT(!cx->realm()->isAtomsRealm());
|
||||
MOZ_ASSERT(!cx->zone()->isAtomsZone());
|
||||
AssertHeapIsIdle();
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, obj, fun, args);
|
||||
|
@ -2944,7 +2944,7 @@ JS_PUBLIC_API(bool)
|
|||
JS_CallFunctionName(JSContext* cx, HandleObject obj, const char* name, const HandleValueArray& args,
|
||||
MutableHandleValue rval)
|
||||
{
|
||||
MOZ_ASSERT(!cx->realm()->isAtomsRealm());
|
||||
MOZ_ASSERT(!cx->zone()->isAtomsZone());
|
||||
AssertHeapIsIdle();
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, obj, args);
|
||||
|
@ -3378,7 +3378,7 @@ JS_SetReservedSlot(JSObject* obj, uint32_t index, const Value& value)
|
|||
JS_PUBLIC_API(JSObject*)
|
||||
JS_NewArrayObject(JSContext* cx, const JS::HandleValueArray& contents)
|
||||
{
|
||||
MOZ_ASSERT(!cx->realm()->isAtomsRealm());
|
||||
MOZ_ASSERT(!cx->zone()->isAtomsZone());
|
||||
AssertHeapIsIdle();
|
||||
CHECK_REQUEST(cx);
|
||||
|
||||
|
@ -3389,7 +3389,7 @@ JS_NewArrayObject(JSContext* cx, const JS::HandleValueArray& contents)
|
|||
JS_PUBLIC_API(JSObject*)
|
||||
JS_NewArrayObject(JSContext* cx, size_t length)
|
||||
{
|
||||
MOZ_ASSERT(!cx->realm()->isAtomsRealm());
|
||||
MOZ_ASSERT(!cx->zone()->isAtomsZone());
|
||||
AssertHeapIsIdle();
|
||||
CHECK_REQUEST(cx);
|
||||
|
||||
|
@ -3512,7 +3512,7 @@ JS_PUBLIC_API(JSFunction*)
|
|||
JS_NewFunction(JSContext* cx, JSNative native, unsigned nargs, unsigned flags,
|
||||
const char* name)
|
||||
{
|
||||
MOZ_ASSERT(!cx->realm()->isAtomsRealm());
|
||||
MOZ_ASSERT(!cx->zone()->isAtomsZone());
|
||||
|
||||
AssertHeapIsIdle();
|
||||
CHECK_REQUEST(cx);
|
||||
|
@ -3532,7 +3532,7 @@ JS_NewFunction(JSContext* cx, JSNative native, unsigned nargs, unsigned flags,
|
|||
JS_PUBLIC_API(JSFunction*)
|
||||
JS::GetSelfHostedFunction(JSContext* cx, const char* selfHostedName, HandleId id, unsigned nargs)
|
||||
{
|
||||
MOZ_ASSERT(!cx->realm()->isAtomsRealm());
|
||||
MOZ_ASSERT(!cx->zone()->isAtomsZone());
|
||||
AssertHeapIsIdle();
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, id);
|
||||
|
@ -3788,7 +3788,7 @@ JS_IsConstructor(JSFunction* fun)
|
|||
JS_PUBLIC_API(bool)
|
||||
JS_DefineFunctions(JSContext* cx, HandleObject obj, const JSFunctionSpec* fs)
|
||||
{
|
||||
MOZ_ASSERT(!cx->realm()->isAtomsRealm());
|
||||
MOZ_ASSERT(!cx->zone()->isAtomsZone());
|
||||
AssertHeapIsIdle();
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, obj);
|
||||
|
@ -3800,7 +3800,7 @@ JS_PUBLIC_API(JSFunction*)
|
|||
JS_DefineFunction(JSContext* cx, HandleObject obj, const char* name, JSNative call,
|
||||
unsigned nargs, unsigned attrs)
|
||||
{
|
||||
MOZ_ASSERT(!cx->realm()->isAtomsRealm());
|
||||
MOZ_ASSERT(!cx->zone()->isAtomsZone());
|
||||
AssertHeapIsIdle();
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, obj);
|
||||
|
@ -3816,7 +3816,7 @@ JS_DefineUCFunction(JSContext* cx, HandleObject obj,
|
|||
const char16_t* name, size_t namelen, JSNative call,
|
||||
unsigned nargs, unsigned attrs)
|
||||
{
|
||||
MOZ_ASSERT(!cx->realm()->isAtomsRealm());
|
||||
MOZ_ASSERT(!cx->zone()->isAtomsZone());
|
||||
AssertHeapIsIdle();
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, obj);
|
||||
|
@ -3831,7 +3831,7 @@ extern JS_PUBLIC_API(JSFunction*)
|
|||
JS_DefineFunctionById(JSContext* cx, HandleObject obj, HandleId id, JSNative call,
|
||||
unsigned nargs, unsigned attrs)
|
||||
{
|
||||
MOZ_ASSERT(!cx->realm()->isAtomsRealm());
|
||||
MOZ_ASSERT(!cx->zone()->isAtomsZone());
|
||||
AssertHeapIsIdle();
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, obj, id);
|
||||
|
@ -4082,7 +4082,7 @@ Compile(JSContext* cx, const ReadOnlyCompileOptions& options,
|
|||
{
|
||||
ScopeKind scopeKind = options.nonSyntacticScope ? ScopeKind::NonSyntactic : ScopeKind::Global;
|
||||
|
||||
MOZ_ASSERT(!cx->realm()->isAtomsRealm());
|
||||
MOZ_ASSERT(!cx->zone()->isAtomsZone());
|
||||
AssertHeapIsIdle();
|
||||
CHECK_REQUEST(cx);
|
||||
|
||||
|
@ -4223,7 +4223,7 @@ JSScript*
|
|||
JS::DecodeBinAST(JSContext* cx, const ReadOnlyCompileOptions& options,
|
||||
const uint8_t* buf, size_t length)
|
||||
{
|
||||
MOZ_ASSERT(!cx->realm()->isAtomsRealm());
|
||||
MOZ_ASSERT(!cx->zone()->isAtomsZone());
|
||||
AssertHeapIsIdle();
|
||||
CHECK_REQUEST(cx);
|
||||
|
||||
|
@ -4547,7 +4547,7 @@ CompileFunction(JSContext* cx, const ReadOnlyCompileOptions& optionsArg,
|
|||
HandleObject enclosingEnv, HandleScope enclosingScope,
|
||||
MutableHandleFunction fun)
|
||||
{
|
||||
MOZ_ASSERT(!cx->realm()->isAtomsRealm());
|
||||
MOZ_ASSERT(!cx->zone()->isAtomsZone());
|
||||
AssertHeapIsIdle();
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, enclosingEnv);
|
||||
|
@ -4716,7 +4716,7 @@ JS::ExposeScriptToDebugger(JSContext* cx, HandleScript script)
|
|||
JS_PUBLIC_API(JSString*)
|
||||
JS_DecompileScript(JSContext* cx, HandleScript script)
|
||||
{
|
||||
MOZ_ASSERT(!cx->realm()->isAtomsRealm());
|
||||
MOZ_ASSERT(!cx->zone()->isAtomsZone());
|
||||
|
||||
AssertHeapIsIdle();
|
||||
CHECK_REQUEST(cx);
|
||||
|
@ -4734,7 +4734,7 @@ JS_DecompileScript(JSContext* cx, HandleScript script)
|
|||
JS_PUBLIC_API(JSString*)
|
||||
JS_DecompileFunction(JSContext* cx, HandleFunction fun)
|
||||
{
|
||||
MOZ_ASSERT(!cx->realm()->isAtomsRealm());
|
||||
MOZ_ASSERT(!cx->zone()->isAtomsZone());
|
||||
AssertHeapIsIdle();
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, fun);
|
||||
|
@ -4744,7 +4744,7 @@ JS_DecompileFunction(JSContext* cx, HandleFunction fun)
|
|||
MOZ_NEVER_INLINE static bool
|
||||
ExecuteScript(JSContext* cx, HandleObject scope, HandleScript script, Value* rval)
|
||||
{
|
||||
MOZ_ASSERT(!cx->realm()->isAtomsRealm());
|
||||
MOZ_ASSERT(!cx->zone()->isAtomsZone());
|
||||
AssertHeapIsIdle();
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, scope, script);
|
||||
|
@ -4838,7 +4838,7 @@ Evaluate(JSContext* cx, ScopeKind scopeKind, HandleObject env,
|
|||
SourceBufferHolder& srcBuf, MutableHandleValue rval)
|
||||
{
|
||||
CompileOptions options(cx, optionsArg);
|
||||
MOZ_ASSERT(!cx->realm()->isAtomsRealm());
|
||||
MOZ_ASSERT(!cx->zone()->isAtomsZone());
|
||||
AssertHeapIsIdle();
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, env);
|
||||
|
@ -4979,7 +4979,7 @@ JS_PUBLIC_API(bool)
|
|||
JS::CompileModule(JSContext* cx, const ReadOnlyCompileOptions& options,
|
||||
SourceBufferHolder& srcBuf, JS::MutableHandleObject module)
|
||||
{
|
||||
MOZ_ASSERT(!cx->realm()->isAtomsRealm());
|
||||
MOZ_ASSERT(!cx->zone()->isAtomsZone());
|
||||
AssertHeapIsIdle();
|
||||
CHECK_REQUEST(cx);
|
||||
|
||||
|
@ -5137,7 +5137,7 @@ JS::SetPromiseRejectionTrackerCallback(JSContext* cx, JSPromiseRejectionTrackerC
|
|||
JS_PUBLIC_API(JSObject*)
|
||||
JS::NewPromiseObject(JSContext* cx, HandleObject executor, HandleObject proto /* = nullptr */)
|
||||
{
|
||||
MOZ_ASSERT(!cx->realm()->isAtomsRealm());
|
||||
MOZ_ASSERT(!cx->zone()->isAtomsZone());
|
||||
AssertHeapIsIdle();
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, executor, proto);
|
||||
|
@ -5391,7 +5391,7 @@ JS::NewReadableDefaultStreamObject(JSContext* cx,
|
|||
double highWaterMark /* = 1 */,
|
||||
JS::HandleObject proto /* = nullptr */)
|
||||
{
|
||||
MOZ_ASSERT(!cx->realm()->isAtomsRealm());
|
||||
MOZ_ASSERT(!cx->zone()->isAtomsZone());
|
||||
AssertHeapIsIdle();
|
||||
CHECK_REQUEST(cx);
|
||||
|
||||
|
@ -5413,7 +5413,7 @@ JS::NewReadableByteStreamObject(JSContext* cx,
|
|||
double highWaterMark /* = 1 */,
|
||||
JS::HandleObject proto /* = nullptr */)
|
||||
{
|
||||
MOZ_ASSERT(!cx->realm()->isAtomsRealm());
|
||||
MOZ_ASSERT(!cx->zone()->isAtomsZone());
|
||||
AssertHeapIsIdle();
|
||||
CHECK_REQUEST(cx);
|
||||
|
||||
|
@ -5472,7 +5472,7 @@ JS::NewReadableExternalSourceStreamObject(JSContext* cx, void* underlyingSource,
|
|||
uint8_t flags /* = 0 */,
|
||||
HandleObject proto /* = nullptr */)
|
||||
{
|
||||
MOZ_ASSERT(!cx->realm()->isAtomsRealm());
|
||||
MOZ_ASSERT(!cx->zone()->isAtomsZone());
|
||||
AssertHeapIsIdle();
|
||||
CHECK_REQUEST(cx);
|
||||
|
||||
|
@ -7627,9 +7627,8 @@ GetScriptedCallerGlobal(JSContext* cx)
|
|||
|
||||
GlobalObject* global = realm->maybeGlobal();
|
||||
|
||||
// No one should be running code in the atoms realm or running code in a
|
||||
// realm without any live objects, so there should definitely be a live
|
||||
// global.
|
||||
// No one should be running code in a realm without any live objects, so
|
||||
// there should definitely be a live global.
|
||||
MOZ_ASSERT(global);
|
||||
|
||||
return global;
|
||||
|
|
|
@ -162,11 +162,16 @@ JS_GetCompartmentPrincipals(JSCompartment* compartment)
|
|||
return realm->principals();
|
||||
}
|
||||
|
||||
JS_FRIEND_API(JSPrincipals*)
|
||||
JS::GetRealmPrincipals(JS::Realm* realm)
|
||||
{
|
||||
return realm->principals();
|
||||
}
|
||||
|
||||
JS_FRIEND_API(void)
|
||||
JS_SetCompartmentPrincipals(JSCompartment* compartment, JSPrincipals* principals)
|
||||
JS::SetRealmPrincipals(JS::Realm* realm, JSPrincipals* principals)
|
||||
{
|
||||
// Short circuit if there's no change.
|
||||
Realm* realm = JS::GetRealmForCompartment(compartment);
|
||||
if (principals == realm->principals())
|
||||
return;
|
||||
|
||||
|
@ -246,7 +251,7 @@ DefineHelpProperty(JSContext* cx, HandleObject obj, const char* prop, const char
|
|||
JS_FRIEND_API(bool)
|
||||
JS_DefineFunctionsWithHelp(JSContext* cx, HandleObject obj, const JSFunctionSpecWithHelp* fs)
|
||||
{
|
||||
MOZ_ASSERT(!cx->realm()->isAtomsRealm());
|
||||
MOZ_ASSERT(!cx->zone()->isAtomsZone());
|
||||
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, obj);
|
||||
|
@ -351,12 +356,6 @@ js::IsSystemZone(Zone* zone)
|
|||
return zone->isSystem;
|
||||
}
|
||||
|
||||
JS_FRIEND_API(bool)
|
||||
js::IsAtomsRealm(JS::Realm* realm)
|
||||
{
|
||||
return realm->isAtomsRealm();
|
||||
}
|
||||
|
||||
JS_FRIEND_API(bool)
|
||||
js::IsAtomsZone(JS::Zone* zone)
|
||||
{
|
||||
|
@ -433,7 +432,7 @@ js::DefineFunctionWithReserved(JSContext* cx, JSObject* objArg, const char* name
|
|||
unsigned nargs, unsigned attrs)
|
||||
{
|
||||
RootedObject obj(cx, objArg);
|
||||
MOZ_ASSERT(!cx->realm()->isAtomsRealm());
|
||||
MOZ_ASSERT(!cx->zone()->isAtomsZone());
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, obj);
|
||||
JSAtom* atom = Atomize(cx, name, strlen(name));
|
||||
|
@ -447,7 +446,7 @@ JS_FRIEND_API(JSFunction*)
|
|||
js::NewFunctionWithReserved(JSContext* cx, JSNative native, unsigned nargs, unsigned flags,
|
||||
const char* name)
|
||||
{
|
||||
MOZ_ASSERT(!cx->realm()->isAtomsRealm());
|
||||
MOZ_ASSERT(!cx->zone()->isAtomsZone());
|
||||
|
||||
CHECK_REQUEST(cx);
|
||||
|
||||
|
@ -468,7 +467,7 @@ js::NewFunctionByIdWithReserved(JSContext* cx, JSNative native, unsigned nargs,
|
|||
jsid id)
|
||||
{
|
||||
MOZ_ASSERT(JSID_IS_STRING(id));
|
||||
MOZ_ASSERT(!cx->realm()->isAtomsRealm());
|
||||
MOZ_ASSERT(!cx->zone()->isAtomsZone());
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, id);
|
||||
|
||||
|
@ -1275,6 +1274,9 @@ JS::NotifyGCRootsRemoved(JSContext* cx)
|
|||
JS_FRIEND_API(JS::Realm*)
|
||||
js::GetAnyRealmInZone(JS::Zone* zone)
|
||||
{
|
||||
if (zone->isAtomsZone())
|
||||
return nullptr;
|
||||
|
||||
RealmsInZoneIter realm(zone);
|
||||
MOZ_ASSERT(!realm.done());
|
||||
return realm.get();
|
||||
|
@ -1543,8 +1545,9 @@ js::EnableAccessValidation(JSContext* cx, bool enabled)
|
|||
}
|
||||
|
||||
JS_FRIEND_API(void)
|
||||
js::SetCompartmentValidAccessPtr(JSContext* cx, JS::HandleObject global, bool* accessp)
|
||||
js::SetRealmValidAccessPtr(JSContext* cx, JS::HandleObject global, bool* accessp)
|
||||
{
|
||||
MOZ_ASSERT(global->is<GlobalObject>());
|
||||
global->realm()->setValidAccessPtr(accessp);
|
||||
}
|
||||
|
||||
|
|
|
@ -190,9 +190,6 @@ JS_GetIsSecureContext(JSCompartment* compartment);
|
|||
extern JS_FRIEND_API(JSPrincipals*)
|
||||
JS_GetCompartmentPrincipals(JSCompartment* compartment);
|
||||
|
||||
extern JS_FRIEND_API(void)
|
||||
JS_SetCompartmentPrincipals(JSCompartment* compartment, JSPrincipals* principals);
|
||||
|
||||
extern JS_FRIEND_API(JSPrincipals*)
|
||||
JS_GetScriptPrincipals(JSScript* script);
|
||||
|
||||
|
@ -325,6 +322,12 @@ ForceLexicalInitialization(JSContext *cx, HandleObject obj);
|
|||
extern JS_FRIEND_API(int)
|
||||
IsGCPoisoning();
|
||||
|
||||
extern JS_FRIEND_API(JSPrincipals*)
|
||||
GetRealmPrincipals(JS::Realm* realm);
|
||||
|
||||
extern JS_FRIEND_API(void)
|
||||
SetRealmPrincipals(JS::Realm* realm, JSPrincipals* principals);
|
||||
|
||||
} // namespace JS
|
||||
|
||||
/**
|
||||
|
@ -483,9 +486,6 @@ IsSystemCompartment(JSCompartment* comp);
|
|||
extern JS_FRIEND_API(bool)
|
||||
IsSystemZone(JS::Zone* zone);
|
||||
|
||||
extern JS_FRIEND_API(bool)
|
||||
IsAtomsRealm(JS::Realm* realm);
|
||||
|
||||
extern JS_FRIEND_API(bool)
|
||||
IsAtomsZone(JS::Zone* zone);
|
||||
|
||||
|
@ -553,6 +553,7 @@ extern JS_FRIEND_API(size_t)
|
|||
SizeOfDataIfCDataObject(mozilla::MallocSizeOf mallocSizeOf, JSObject* obj);
|
||||
#endif
|
||||
|
||||
// Note: this returns nullptr iff |zone| is the atoms zone.
|
||||
extern JS_FRIEND_API(JS::Realm*)
|
||||
GetAnyRealmInZone(JS::Zone* zone);
|
||||
|
||||
|
@ -566,8 +567,8 @@ namespace shadow {
|
|||
|
||||
struct ObjectGroup {
|
||||
const Class* clasp;
|
||||
JSObject* proto;
|
||||
JSCompartment* compartment;
|
||||
JSObject* proto;
|
||||
JS::Realm* realm;
|
||||
};
|
||||
|
||||
struct BaseShape {
|
||||
|
@ -670,10 +671,23 @@ InheritanceProtoKeyForStandardClass(JSProtoKey key)
|
|||
JS_FRIEND_API(bool)
|
||||
IsFunctionObject(JSObject* obj);
|
||||
|
||||
JS_FRIEND_API(bool)
|
||||
IsCrossCompartmentWrapper(JSObject* obj);
|
||||
|
||||
static MOZ_ALWAYS_INLINE JSCompartment*
|
||||
GetObjectCompartment(JSObject* obj)
|
||||
{
|
||||
return reinterpret_cast<shadow::Object*>(obj)->group->compartment;
|
||||
JS::Realm* realm = reinterpret_cast<shadow::Object*>(obj)->group->realm;
|
||||
return JS::GetCompartmentForRealm(realm);
|
||||
}
|
||||
|
||||
// CrossCompartmentWrappers are shared by all realms within the compartment, so
|
||||
// getting a wrapper's realm usually doesn't make sense.
|
||||
static MOZ_ALWAYS_INLINE JS::Realm*
|
||||
GetNonCCWObjectRealm(JSObject* obj)
|
||||
{
|
||||
MOZ_ASSERT(!js::IsCrossCompartmentWrapper(obj));
|
||||
return reinterpret_cast<shadow::Object*>(obj)->group->realm;
|
||||
}
|
||||
|
||||
JS_FRIEND_API(JSObject*)
|
||||
|
@ -3093,9 +3107,9 @@ class MOZ_STACK_CLASS JS_FRIEND_API(AutoAssertNoContentJS)
|
|||
};
|
||||
|
||||
// Turn on assertions so that we assert that
|
||||
// !comp->validAccessPtr || *comp->validAccessPtr
|
||||
// is true for every |comp| that we run JS code in. The compartment's validAccessPtr
|
||||
// is set via SetCompartmentValidAccessPtr.
|
||||
// !realm->validAccessPtr || *realm->validAccessPtr
|
||||
// is true for every |realm| that we run JS code in. The realm's validAccessPtr
|
||||
// is set via SetRealmValidAccessPtr.
|
||||
extern JS_FRIEND_API(void)
|
||||
EnableAccessValidation(JSContext* cx, bool enabled);
|
||||
|
||||
|
@ -3104,7 +3118,7 @@ EnableAccessValidation(JSContext* cx, bool enabled);
|
|||
// threads that are allowed to run code on |global|, so all changes to *accessp
|
||||
// should be made from whichever thread owns |global| at a given time.
|
||||
extern JS_FRIEND_API(void)
|
||||
SetCompartmentValidAccessPtr(JSContext* cx, JS::HandleObject global, bool* accessp);
|
||||
SetRealmValidAccessPtr(JSContext* cx, JS::HandleObject global, bool* accessp);
|
||||
|
||||
// Returns true if the system zone is available (i.e., if no cooperative contexts
|
||||
// are using it now).
|
||||
|
|
|
@ -85,6 +85,7 @@ typedef JSConstScalarSpec<int32_t> JSConstIntegerSpec;
|
|||
|
||||
namespace js {
|
||||
|
||||
inline JS::Realm* GetContextRealm(const JSContext* cx);
|
||||
inline JSCompartment* GetContextCompartment(const JSContext* cx);
|
||||
inline JS::Zone* GetContextZone(const JSContext* cx);
|
||||
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче