mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 19:35:51 +00:00
Merge inbound to mozilla-central. a=merge
This commit is contained in:
commit
0bb5e5ba36
@ -1,9 +1,9 @@
|
||||
This is the debugger.html project output.
|
||||
See https://github.com/devtools-html/debugger.html
|
||||
|
||||
Version 55
|
||||
Version 56
|
||||
|
||||
Comparison: https://github.com/devtools-html/debugger.html/compare/release-54...release-55
|
||||
Comparison: https://github.com/devtools-html/debugger.html/compare/release-55...release-56
|
||||
|
||||
Packages:
|
||||
- babel-plugin-transform-es2015-modules-commonjs @6.26.2
|
||||
|
113
devtools/client/debugger/new/dist/debugger.css
vendored
113
devtools/client/debugger/new/dist/debugger.css
vendored
@ -577,7 +577,6 @@ menuseparator {
|
||||
|
||||
.folder,
|
||||
.domain,
|
||||
.source-icon,
|
||||
.file,
|
||||
.extension {
|
||||
background-color: var(--theme-comment);
|
||||
@ -586,7 +585,7 @@ menuseparator {
|
||||
.worker,
|
||||
.file,
|
||||
.folder,
|
||||
.source-icon,
|
||||
.sources-list .source-icon,
|
||||
.extension {
|
||||
position: relative;
|
||||
top: 2px;
|
||||
@ -608,8 +607,7 @@ menuseparator {
|
||||
}
|
||||
|
||||
img.domain,
|
||||
img.folder,
|
||||
img.source-icon {
|
||||
img.folder {
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
}
|
||||
@ -666,7 +664,7 @@ img.file {
|
||||
img.domain,
|
||||
img.folder,
|
||||
img.file,
|
||||
img.source-icon,
|
||||
.sources-list img.source-icon,
|
||||
img.extension {
|
||||
mask-size: 100%;
|
||||
margin-inline-end: 5px;
|
||||
@ -1499,7 +1497,9 @@ html .toggle-button.end.vertical svg {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.tree:not(.object-inspector) .tree-node[data-expandable="false"] .tree-indent:last-of-type {
|
||||
.tree:not(.object-inspector)
|
||||
.tree-node[data-expandable="false"]
|
||||
.tree-indent:last-of-type {
|
||||
margin-inline-end: 4px;
|
||||
}
|
||||
|
||||
@ -1525,7 +1525,9 @@ html .toggle-button.end.vertical svg {
|
||||
}
|
||||
|
||||
/* Removes start margin when a custom root is used */
|
||||
.sources-list-custom-root .tree > .tree-node[data-expandable="false"][aria-level="0"] {
|
||||
.sources-list-custom-root
|
||||
.tree
|
||||
> .tree-node[data-expandable="false"][aria-level="0"] {
|
||||
padding-inline-start: 4px;
|
||||
}
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
@ -1719,7 +1721,7 @@ menuseparator {
|
||||
}
|
||||
|
||||
.theme-dark .outline-footer button {
|
||||
color: var(--theme-body-color);
|
||||
color: var(--theme-body-color);
|
||||
}
|
||||
|
||||
.outline-footer button.active {
|
||||
@ -2887,6 +2889,37 @@ debug-expression-error {
|
||||
border-radius: 2px;
|
||||
margin: 0 -1px -1px -1px;
|
||||
}
|
||||
.source-icon {
|
||||
position: relative;
|
||||
background-color: var(--theme-comment);
|
||||
mask-size: 100%;
|
||||
display: inline-block;
|
||||
margin-inline-end: 5px;
|
||||
}
|
||||
|
||||
.source-icon,
|
||||
.source-icon svg {
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
}
|
||||
|
||||
.source-icon.prettyPrint {
|
||||
mask: url("chrome://devtools/skin/images/debugger/prettyPrint.svg") no-repeat;
|
||||
mask-size: 100%;
|
||||
background: var(--theme-highlight-blue);
|
||||
fill: var(--theme-textbox-box-shadow);
|
||||
}
|
||||
|
||||
.source-icon.blackBox {
|
||||
mask: url("chrome://devtools/skin/images/debugger/blackBox.svg") no-repeat;
|
||||
mask-size: 100%;
|
||||
background: var(--theme-highlight-blue);
|
||||
}
|
||||
|
||||
.source-icon.react {
|
||||
mask-size: 100%;
|
||||
background: var(--theme-highlight-bluegrey);
|
||||
}
|
||||
/* 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/>. */
|
||||
@ -2906,7 +2939,14 @@ debug-expression-error {
|
||||
.breakpoints-list .breakpoint-heading {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
padding-top: 0.75em;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* temporary until we refactor the sources tree and tab icon styles */
|
||||
.breakpoints-list .breakpoint-heading .source-icon.file {
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.breakpoints-list .breakpoint-heading,
|
||||
@ -2931,7 +2971,7 @@ debug-expression-error {
|
||||
}
|
||||
|
||||
.breakpoints-list .breakpoint {
|
||||
height: var(--breakpoint-expression-height);
|
||||
min-height: var(--breakpoint-expression-height);
|
||||
}
|
||||
|
||||
.breakpoints-exceptions-caught {
|
||||
@ -3193,7 +3233,7 @@ html[dir="rtl"] .breakpoints-list .breakpoint .breakpoint-line {
|
||||
background-color: var(--theme-body-background);
|
||||
display: block;
|
||||
position: relative;
|
||||
height: var(--breakpoint-expression-height);
|
||||
min-height: var(--breakpoint-expression-height);
|
||||
}
|
||||
|
||||
.expression-container > .tree {
|
||||
@ -3209,7 +3249,7 @@ html[dir="rtl"] .breakpoints-list .breakpoint .breakpoint-line {
|
||||
background-color: var(--theme-selection-background-hover);
|
||||
}
|
||||
|
||||
.tree .tree-node:not(.focused):hover {
|
||||
.tree .tree-node:not(.focused):hover {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
@ -3713,7 +3753,7 @@ img.skipPausing {
|
||||
}
|
||||
|
||||
.command-bar .active .skipPausing {
|
||||
background-color: var(--theme-highlight-blue);
|
||||
background-color: var(--theme-highlight-blue);
|
||||
}
|
||||
|
||||
.bottom {
|
||||
@ -3749,6 +3789,14 @@ img.skipPausing {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.object-node {
|
||||
padding-left: 4px;
|
||||
}
|
||||
|
||||
html[dir="rtl"] .object-node {
|
||||
padding-right: 4px;
|
||||
}
|
||||
|
||||
.object-label {
|
||||
color: var(--theme-highlight-blue);
|
||||
}
|
||||
@ -3772,10 +3820,6 @@ img.skipPausing {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.scopes-list {
|
||||
padding-inline-start: 4px;
|
||||
}
|
||||
|
||||
.scopes-list .tree:focus {
|
||||
outline: none;
|
||||
}
|
||||
@ -3806,8 +3850,8 @@ img.skipPausing {
|
||||
white-space: nowrap;
|
||||
-moz-user-select: none;
|
||||
user-select: none;
|
||||
--breakpoint-expression-right-clear-space: 36px;
|
||||
--breakpoint-expression-height: 2.4em;
|
||||
--breakpoint-expression-right-clear-space: 36px;
|
||||
--breakpoint-expression-height: 2.4em;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -4029,40 +4073,28 @@ html .welcomebox .toggle-button-end.collapsed {
|
||||
fill: var(--theme-body-color);
|
||||
}
|
||||
|
||||
.source-tab img.prettyPrint {
|
||||
mask: url("chrome://devtools/skin/images/debugger/prettyPrint.svg") no-repeat;
|
||||
mask-size: 100%;
|
||||
padding-top: 12px;
|
||||
.source-tab .source-icon {
|
||||
margin-inline-end: 0;
|
||||
}
|
||||
|
||||
.source-tab img.prettyPrint,
|
||||
.source-tab .source-icon.blackBox {
|
||||
height: 12px;
|
||||
width: 12px;
|
||||
background: var(--theme-highlight-blue);
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.source-tab .prettyPrint path {
|
||||
fill: var(--theme-textbox-box-shadow);
|
||||
}
|
||||
|
||||
.source-tab .blackBox,
|
||||
.source-tab .prettyPrint {
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.source-tab img.blackBox {
|
||||
mask: url("chrome://devtools/skin/images/debugger/blackBox.svg") no-repeat;
|
||||
mask-size: 100%;
|
||||
padding-top: 12px;
|
||||
height: 12px;
|
||||
width: 12px;
|
||||
background: var(--theme-highlight-blue);
|
||||
}
|
||||
|
||||
.source-tab img.react {
|
||||
mask: url("chrome://devtools/skin/images/debugger/react.svg") no-repeat;
|
||||
mask-size: 100%;
|
||||
padding-top: 12px;
|
||||
height: 14px;
|
||||
width: 14px;
|
||||
background: var(--theme-highlight-bluegrey);
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.source-tab .blackBox path {
|
||||
@ -4093,7 +4125,7 @@ html[dir="rtl"] img.moreTabs {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
padding: 0 4px;
|
||||
align-self: flex-start;
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.source-tab .close-btn {
|
||||
@ -4187,7 +4219,6 @@ html[dir="rtl"] .dropdown {
|
||||
mask: url("chrome://devtools/skin/images/debugger/file.svg") no-repeat;
|
||||
mask-size: 100%;
|
||||
margin-bottom: 7px;
|
||||
|
||||
}
|
||||
|
||||
.dropdown ul {
|
||||
|
@ -25005,7 +25005,9 @@ const {
|
||||
isOriginalId
|
||||
} = __webpack_require__(3652);
|
||||
|
||||
const { workerUtils: { WorkerDispatcher } } = __webpack_require__(3651);
|
||||
const {
|
||||
workerUtils: { WorkerDispatcher }
|
||||
} = __webpack_require__(3651);
|
||||
|
||||
const dispatcher = new WorkerDispatcher();
|
||||
|
||||
|
@ -100,7 +100,6 @@
|
||||
|
||||
.folder,
|
||||
.domain,
|
||||
.source-icon,
|
||||
.file,
|
||||
.extension {
|
||||
background-color: var(--theme-comment);
|
||||
@ -109,7 +108,7 @@
|
||||
.worker,
|
||||
.file,
|
||||
.folder,
|
||||
.source-icon,
|
||||
.sources-list .source-icon,
|
||||
.extension {
|
||||
position: relative;
|
||||
top: 2px;
|
||||
@ -131,8 +130,7 @@
|
||||
}
|
||||
|
||||
img.domain,
|
||||
img.folder,
|
||||
img.source-icon {
|
||||
img.folder {
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
}
|
||||
@ -189,7 +187,7 @@ img.file {
|
||||
img.domain,
|
||||
img.folder,
|
||||
img.file,
|
||||
img.source-icon,
|
||||
.sources-list img.source-icon,
|
||||
img.extension {
|
||||
mask-size: 100%;
|
||||
margin-inline-end: 5px;
|
||||
|
@ -94,7 +94,7 @@ function updatePreview(target, editor) {
|
||||
match = (0, _ast.findBestMatchExpression)(symbols, tokenPos);
|
||||
}
|
||||
|
||||
if (!match || !match.expression) {
|
||||
if (!match) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,7 @@ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { va
|
||||
|
||||
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
||||
|
||||
const blacklist = ["SET_POPUP_OBJECT_PROPERTIES", "SET_PAUSE_POINTS", "SET_SYMBOLS", "OUT_OF_SCOPE_LOCATIONS", "MAP_SCOPES", "MAP_FRAMES", "ADD_SCOPES", "IN_SCOPE_LINES", "REMOVE_BREAKPOINT", "ADD_BREAKPOINT"];
|
||||
const blacklist = ["SET_POPUP_OBJECT_PROPERTIES", "SET_PAUSE_POINTS", "SET_SYMBOLS", "OUT_OF_SCOPE_LOCATIONS", "MAP_SCOPES", "MAP_FRAMES", "ADD_SCOPES", "IN_SCOPE_LINES", "REMOVE_BREAKPOINT"];
|
||||
|
||||
function cloneAction(action) {
|
||||
action = action || {};
|
||||
|
@ -106,6 +106,10 @@ class ConditionalPanel extends _react.PureComponent {
|
||||
return this.clearConditionalPanel();
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
this.keepFocusOnInput();
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
// This is called if CodeMirror is re-initializing itself before the
|
||||
// user closes the conditional panel. Clear the widget, and re-render it
|
||||
@ -150,8 +154,6 @@ class ConditionalPanel extends _react.PureComponent {
|
||||
this.scrollParent.addEventListener("scroll", this.repositionOnScroll);
|
||||
this.repositionOnScroll();
|
||||
}
|
||||
|
||||
this.input.focus();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -183,7 +183,7 @@ class Popup extends _react.Component {
|
||||
}));
|
||||
}
|
||||
|
||||
renderReact(react, roots) {
|
||||
renderReact(react) {
|
||||
const reactHeader = react.displayName || "React Component";
|
||||
return _react2.default.createElement("div", {
|
||||
className: "header-container"
|
||||
@ -264,19 +264,19 @@ class Popup extends _react.Component {
|
||||
}
|
||||
|
||||
renderPreview() {
|
||||
// We don't have to check and
|
||||
// return on `false`, `""`, `0`, `undefined` etc,
|
||||
// these falsy simple typed value because we want to
|
||||
// do `renderSimplePreview` on these values below.
|
||||
const {
|
||||
value
|
||||
} = this.props;
|
||||
|
||||
if (!value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (value.class === "Function") {
|
||||
if (value && value.class === "Function") {
|
||||
return this.renderFunctionPreview();
|
||||
}
|
||||
|
||||
if (value.type === "object") {
|
||||
if (value && value.type === "object") {
|
||||
return _react2.default.createElement("div", null, this.renderObjectPreview());
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,10 @@ var _reactRedux = require("devtools/client/shared/vendor/react-redux");
|
||||
|
||||
var _devtoolsContextmenu = require("devtools/client/debugger/new/dist/vendors").vendored["devtools-contextmenu"];
|
||||
|
||||
var _SourceIcon = require("../shared/SourceIcon");
|
||||
|
||||
var _SourceIcon2 = _interopRequireDefault(_SourceIcon);
|
||||
|
||||
var _Button = require("../shared/Button/index");
|
||||
|
||||
var _actions = require("../../actions/index");
|
||||
@ -131,15 +135,13 @@ class Tab extends _react.PureComponent {
|
||||
selectedSource,
|
||||
selectSpecificSource,
|
||||
closeTab,
|
||||
source,
|
||||
sourceMetaData
|
||||
source
|
||||
} = this.props;
|
||||
const src = source.toJS();
|
||||
const filename = (0, _source.getFilename)(src);
|
||||
const sourceId = source.id;
|
||||
const active = selectedSource && sourceId == selectedSource.get("id") && !this.isProjectSearchEnabled() && !this.isSourceSearchEnabled();
|
||||
const isPrettyCode = (0, _source.isPretty)(source);
|
||||
const sourceAnnotation = (0, _tabs.getSourceAnnotation)(source, sourceMetaData);
|
||||
|
||||
function onClickClose(e) {
|
||||
e.stopPropagation();
|
||||
@ -167,7 +169,10 @@ class Tab extends _react.PureComponent {
|
||||
onMouseUp: handleTabClick,
|
||||
onContextMenu: e => this.onTabContextMenu(e, sourceId),
|
||||
title: (0, _source.getFileURL)(src)
|
||||
}, sourceAnnotation, _react2.default.createElement("div", {
|
||||
}, _react2.default.createElement(_SourceIcon2.default, {
|
||||
source: source,
|
||||
shouldHide: icon => ["file", "javascript"].includes(icon)
|
||||
}), _react2.default.createElement("div", {
|
||||
className: "filename"
|
||||
}, filename), _react2.default.createElement(_Button.CloseButton, {
|
||||
handleClick: onClickClose,
|
||||
@ -184,7 +189,6 @@ const mapStateToProps = (state, {
|
||||
return {
|
||||
tabSources: (0, _selectors.getSourcesForTabs)(state),
|
||||
selectedSource: selectedSource,
|
||||
sourceMetaData: (0, _selectors.getSourceMetaData)(state, source.id),
|
||||
activeSearch: (0, _selectors.getActiveSearch)(state)
|
||||
};
|
||||
};
|
||||
|
@ -26,6 +26,10 @@ var _Breakpoint = require("./Breakpoint");
|
||||
|
||||
var _Breakpoint2 = _interopRequireDefault(_Breakpoint);
|
||||
|
||||
var _SourceIcon = require("../shared/SourceIcon");
|
||||
|
||||
var _SourceIcon2 = _interopRequireDefault(_SourceIcon);
|
||||
|
||||
var _actions = require("../../actions/index");
|
||||
|
||||
var _actions2 = _interopRequireDefault(_actions);
|
||||
@ -136,7 +140,7 @@ class Breakpoints extends _react.Component {
|
||||
pauseOnExceptions
|
||||
} = this.props;
|
||||
const isEmpty = breakpoints.size == 0;
|
||||
const exceptionsBox = createExceptionOption(L10N.getStr("pauseOnExceptionsItem2"), shouldPauseOnExceptions, () => pauseOnExceptions(!shouldPauseOnExceptions, false), "breakpoints-exceptions");
|
||||
const exceptionsBox = createExceptionOption(L10N.getStr("pauseOnExceptionsItem"), shouldPauseOnExceptions, () => pauseOnExceptions(!shouldPauseOnExceptions, false), "breakpoints-exceptions");
|
||||
const ignoreCaughtBox = createExceptionOption(L10N.getStr("pauseOnCaughtExceptionsItem"), shouldPauseOnCaughtExceptions, () => pauseOnExceptions(true, !shouldPauseOnCaughtExceptions), "breakpoints-exceptions-caught");
|
||||
return _react2.default.createElement("div", {
|
||||
className: (0, _classnames2.default)("breakpoints-exceptions-options", {
|
||||
@ -170,7 +174,9 @@ class Breakpoints extends _react.Component {
|
||||
title: url,
|
||||
key: url,
|
||||
onClick: () => this.props.selectSource(source.id)
|
||||
}, (0, _source.getFilename)(source)), ...groupBreakpoints.map(bp => this.renderBreakpoint(bp))];
|
||||
}, _react2.default.createElement(_SourceIcon2.default, {
|
||||
source: source
|
||||
}), (0, _source.getFilename)(source)), ...groupBreakpoints.map(bp => this.renderBreakpoint(bp))];
|
||||
})];
|
||||
}
|
||||
|
||||
|
@ -135,6 +135,7 @@ class Expressions extends _react.Component {
|
||||
return _react2.default.createElement("li", {
|
||||
className: "expression-container",
|
||||
key: input,
|
||||
title: expression.input,
|
||||
onDoubleClick: (items, options) => this.editExpression(expression, index)
|
||||
}, _react2.default.createElement("div", {
|
||||
className: "expression-content"
|
||||
|
@ -0,0 +1,46 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
|
||||
var _react = require("devtools/client/shared/vendor/react");
|
||||
|
||||
var _react2 = _interopRequireDefault(_react);
|
||||
|
||||
var _reactRedux = require("devtools/client/shared/vendor/react-redux");
|
||||
|
||||
var _source = require("../../utils/source");
|
||||
|
||||
var _selectors = require("../../selectors/index");
|
||||
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
|
||||
class SourceIcon extends _react.PureComponent {
|
||||
render() {
|
||||
const {
|
||||
shouldHide,
|
||||
source,
|
||||
sourceMetaData
|
||||
} = this.props;
|
||||
const iconClass = (0, _source.getSourceClassnames)(source, sourceMetaData);
|
||||
|
||||
if (shouldHide && shouldHide(iconClass)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return _react2.default.createElement("img", {
|
||||
className: `source-icon ${iconClass}`
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
exports.default = (0, _reactRedux.connect)((state, props) => {
|
||||
return {
|
||||
sourceMetaData: (0, _selectors.getSourceMetaData)(state, props.source.id)
|
||||
};
|
||||
})(SourceIcon);
|
@ -18,5 +18,6 @@ DevToolsModules(
|
||||
'PreviewFunction.js',
|
||||
'ResultList.js',
|
||||
'SearchInput.js',
|
||||
'SourceIcon.js',
|
||||
'Svg.js',
|
||||
)
|
||||
|
@ -432,10 +432,25 @@ function getTextAtPosition(source, location) {
|
||||
return lineText.slice(column, column + 100).trim();
|
||||
}
|
||||
|
||||
function getSourceClassnames(source) {
|
||||
if (source && source.isBlackBoxed) {
|
||||
function getSourceClassnames(source, sourceMetaData) {
|
||||
// Conditionals should be ordered by priority of icon!
|
||||
const defaultClassName = "file";
|
||||
|
||||
if (!source || !source.url) {
|
||||
return defaultClassName;
|
||||
}
|
||||
|
||||
if (sourceMetaData && sourceMetaData.framework) {
|
||||
return sourceMetaData.framework.toLowerCase();
|
||||
}
|
||||
|
||||
if (isPretty(source)) {
|
||||
return "prettyPrint";
|
||||
}
|
||||
|
||||
if (source.isBlackBoxed) {
|
||||
return "blackBox";
|
||||
}
|
||||
|
||||
return sourceTypes[(0, _sourcesTree.getExtension)(source)] || "file";
|
||||
return sourceTypes[(0, _sourcesTree.getExtension)(source)] || defaultClassName;
|
||||
}
|
@ -4,17 +4,8 @@ Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.getHiddenTabs = getHiddenTabs;
|
||||
exports.getSourceAnnotation = getSourceAnnotation;
|
||||
exports.getTabMenuItems = getTabMenuItems;
|
||||
|
||||
var _react = require("devtools/client/shared/vendor/react");
|
||||
|
||||
var _react2 = _interopRequireDefault(_react);
|
||||
|
||||
var _source = require("./source");
|
||||
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
|
||||
@ -49,28 +40,6 @@ function getHiddenTabs(sourceTabs, sourceTabEls) {
|
||||
});
|
||||
}
|
||||
|
||||
function getSourceAnnotation(source, sourceMetaData) {
|
||||
const framework = sourceMetaData && sourceMetaData.framework ? sourceMetaData.framework : false;
|
||||
|
||||
if (framework) {
|
||||
return _react2.default.createElement("img", {
|
||||
className: framework.toLowerCase()
|
||||
});
|
||||
}
|
||||
|
||||
if ((0, _source.isPretty)(source)) {
|
||||
return _react2.default.createElement("img", {
|
||||
className: "prettyPrint"
|
||||
});
|
||||
}
|
||||
|
||||
if (source.isBlackBoxed) {
|
||||
return _react2.default.createElement("img", {
|
||||
className: "blackBox"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function getTabMenuItems() {
|
||||
return {
|
||||
closeTab: {
|
||||
|
@ -23,7 +23,10 @@ add_task(async function() {
|
||||
|
||||
// Create a dbg context
|
||||
const dbg = createDebuggerContext(toolbox);
|
||||
const { selectors: { getSelectedSource }, getState } = dbg;
|
||||
const {
|
||||
selectors: { getSelectedSource },
|
||||
getState
|
||||
} = dbg;
|
||||
|
||||
// Make sure the thread is paused in the right source and location
|
||||
await waitForPaused(dbg);
|
||||
|
@ -5,7 +5,10 @@
|
||||
|
||||
add_task(async function() {
|
||||
const dbg = await initDebugger("doc-scripts.html");
|
||||
const { selectors: { getSelectedSource }, getState } = dbg;
|
||||
const {
|
||||
selectors: { getSelectedSource },
|
||||
getState
|
||||
} = dbg;
|
||||
|
||||
// Make sure we can set a top-level breakpoint and it will be hit on
|
||||
// reload.
|
||||
|
@ -2,7 +2,10 @@
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
function findBreakpoint(dbg, url, line) {
|
||||
const { selectors: { getBreakpoint }, getState } = dbg;
|
||||
const {
|
||||
selectors: { getBreakpoint },
|
||||
getState
|
||||
} = dbg;
|
||||
const source = findSource(dbg, url);
|
||||
return getBreakpoint(getState(), { sourceId: source.id, line });
|
||||
}
|
||||
|
@ -26,7 +26,10 @@ function assertEditorBreakpoint(dbg, line) {
|
||||
|
||||
add_task(async function() {
|
||||
const dbg = await initDebugger("doc-scripts.html");
|
||||
const { selectors: { getBreakpoints, getBreakpoint }, getState } = dbg;
|
||||
const {
|
||||
selectors: { getBreakpoints, getBreakpoint },
|
||||
getState
|
||||
} = dbg;
|
||||
const source = findSource(dbg, "simple1.js");
|
||||
|
||||
await selectSource(dbg, source.url);
|
||||
|
@ -36,13 +36,19 @@ function enableBreakpoints(dbg, count) {
|
||||
}
|
||||
|
||||
function findBreakpoint(dbg, url, line) {
|
||||
const { selectors: { getBreakpoint }, getState } = dbg;
|
||||
const {
|
||||
selectors: { getBreakpoint },
|
||||
getState
|
||||
} = dbg;
|
||||
const source = findSource(dbg, url);
|
||||
return getBreakpoint(getState(), { sourceId: source.id, line });
|
||||
}
|
||||
|
||||
function findBreakpoints(dbg) {
|
||||
const { selectors: { getBreakpoints }, getState } = dbg;
|
||||
const {
|
||||
selectors: { getBreakpoints },
|
||||
getState
|
||||
} = dbg;
|
||||
return getBreakpoints(getState());
|
||||
}
|
||||
|
||||
|
@ -32,7 +32,10 @@ async function enableBreakpoint(dbg, index) {
|
||||
}
|
||||
|
||||
function findBreakpoint(dbg, url, line) {
|
||||
const { selectors: { getBreakpoint }, getState } = dbg;
|
||||
const {
|
||||
selectors: { getBreakpoint },
|
||||
getState
|
||||
} = dbg;
|
||||
const source = findSource(dbg, url);
|
||||
return getBreakpoint(getState(), { sourceId: source.id, line });
|
||||
}
|
||||
|
@ -9,7 +9,9 @@
|
||||
|
||||
// There are shutdown issues for which multiple rejections are left uncaught.
|
||||
// See bug 1018184 for resolving these issues.
|
||||
const { PromiseTestUtils } = scopedCuImport("resource://testing-common/PromiseTestUtils.jsm");
|
||||
const { PromiseTestUtils } = scopedCuImport(
|
||||
"resource://testing-common/PromiseTestUtils.jsm"
|
||||
);
|
||||
PromiseTestUtils.whitelistRejectionsGlobally(/File closed/);
|
||||
PromiseTestUtils.whitelistRejectionsGlobally(/NS_ERROR_FAILURE/);
|
||||
|
||||
|
@ -27,7 +27,10 @@ function assertEditorBreakpoint(dbg, line, shouldExist) {
|
||||
|
||||
add_task(async function() {
|
||||
const dbg = await initDebugger("doc-scripts.html");
|
||||
const { selectors: { getBreakpoints, getBreakpoint }, getState } = dbg;
|
||||
const {
|
||||
selectors: { getBreakpoints, getBreakpoint },
|
||||
getState
|
||||
} = dbg;
|
||||
const source = findSource(dbg, "simple1.js");
|
||||
|
||||
await selectSource(dbg, source.url);
|
||||
|
@ -7,14 +7,17 @@
|
||||
|
||||
add_task(async function() {
|
||||
const dbg = await initDebugger("doc-scripts.html");
|
||||
const { selectors: { getSource }, getState } = dbg;
|
||||
const {
|
||||
selectors: { getSource },
|
||||
getState
|
||||
} = dbg;
|
||||
const sourceUrl = EXAMPLE_URL + "long.js";
|
||||
|
||||
// The source itself doesn't even exist yet, and using
|
||||
// `selectSourceURL` will set a pending request to load this source
|
||||
// and highlight a specific line.
|
||||
|
||||
await selectSource(dbg, sourceUrl, 66)
|
||||
await selectSource(dbg, sourceUrl, 66);
|
||||
|
||||
// TODO: revisit highlighting lines when the debugger opens
|
||||
// assertHighlightLocation(dbg, "long.js", 66);
|
||||
|
@ -10,7 +10,10 @@ add_task(async function() {
|
||||
// which is the slowest part of this and make it run faster, but to
|
||||
// fix a frequent failure allow a longer timeout.
|
||||
const dbg = await initDebugger("doc-scripts.html");
|
||||
const { selectors: { getSelectedSource }, getState } = dbg;
|
||||
const {
|
||||
selectors: { getSelectedSource },
|
||||
getState
|
||||
} = dbg;
|
||||
const simple1 = findSource(dbg, "simple1.js");
|
||||
const simple2 = findSource(dbg, "simple2.js");
|
||||
|
||||
|
@ -1,15 +1,20 @@
|
||||
|
||||
add_task(async function() {
|
||||
await pushPref("devtools.debugger.features.map-scopes", true);
|
||||
|
||||
const dbg = await initDebugger("ember/quickstart/dist/");
|
||||
|
||||
await invokeWithBreakpoint(dbg, "mapTestFunction", "quickstart/router.js", { line: 13, column: 2 }, async () => {
|
||||
await assertScopes(dbg, [
|
||||
"Module",
|
||||
["config", "{\u2026}"],
|
||||
"EmberRouter:Class()",
|
||||
"Router:Class()",
|
||||
]);
|
||||
});
|
||||
await invokeWithBreakpoint(
|
||||
dbg,
|
||||
"mapTestFunction",
|
||||
"quickstart/router.js",
|
||||
{ line: 13, column: 2 },
|
||||
async () => {
|
||||
await assertScopes(dbg, [
|
||||
"Module",
|
||||
["config", "{\u2026}"],
|
||||
"EmberRouter:Class()",
|
||||
"Router:Class()"
|
||||
]);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
@ -24,7 +24,7 @@ function getValue(dbg, index) {
|
||||
|
||||
async function addExpression(dbg, input) {
|
||||
const plusIcon = findElementWithSelector(dbg, expressionSelectors.plusIcon);
|
||||
if(plusIcon) {
|
||||
if (plusIcon) {
|
||||
plusIcon.click();
|
||||
}
|
||||
|
||||
|
@ -36,7 +36,7 @@ async function addExpression(dbg, input) {
|
||||
info("Adding an expression");
|
||||
|
||||
const plusIcon = findElementWithSelector(dbg, expressionSelectors.plusIcon);
|
||||
if(plusIcon) {
|
||||
if (plusIcon) {
|
||||
plusIcon.click();
|
||||
}
|
||||
findElementWithSelector(dbg, expressionSelectors.input).focus();
|
||||
|
@ -29,7 +29,9 @@ server.registerPathHandler("/inline-cache.html", (request, response) => {
|
||||
`);
|
||||
});
|
||||
|
||||
const SOURCE_URL = `http://localhost:${server.identity.primaryPort}/inline-cache.html`;
|
||||
const SOURCE_URL = `http://localhost:${
|
||||
server.identity.primaryPort
|
||||
}/inline-cache.html`;
|
||||
|
||||
/**
|
||||
* This is meant to simulate the developer editing the inline source and saving.
|
||||
@ -40,7 +42,7 @@ function makeChanges() {
|
||||
}
|
||||
|
||||
function getPageValue(tab) {
|
||||
return ContentTask.spawn(tab.linkedBrowser, {}, function () {
|
||||
return ContentTask.spawn(tab.linkedBrowser, {}, function() {
|
||||
return content.document.querySelector("script").textContent.trim();
|
||||
});
|
||||
}
|
||||
@ -49,10 +51,10 @@ async function reloadTabAndDebugger(tab, dbg) {
|
||||
let navigated = waitForDispatch(dbg, "NAVIGATE");
|
||||
let loaded = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
|
||||
await reload(dbg, "inline-cache.html");
|
||||
return Promise.all([ navigated, loaded ]);
|
||||
return Promise.all([navigated, loaded]);
|
||||
}
|
||||
|
||||
add_task(async function () {
|
||||
add_task(async function() {
|
||||
info("Load document with inline script");
|
||||
const tab = await addTab(SOURCE_URL);
|
||||
info("Open debugger");
|
||||
@ -68,8 +70,10 @@ add_task(async function () {
|
||||
await waitForLoadedSource(dbg, "inline-cache.html");
|
||||
let dbgValue = await findSource(dbg, "inline-cache.html");
|
||||
info(`Debugger text: ${dbgValue.text}`);
|
||||
ok(dbgValue.text.includes(pageValue),
|
||||
"Debugger loads from cache, gets value 1 like page");
|
||||
ok(
|
||||
dbgValue.text.includes(pageValue),
|
||||
"Debugger loads from cache, gets value 1 like page"
|
||||
);
|
||||
|
||||
info("Disable HTTP cache for page");
|
||||
await toolbox.target.activeTab.reconfigure({ cacheDisabled: true });
|
||||
@ -82,8 +86,10 @@ add_task(async function () {
|
||||
await waitForLoadedSource(dbg, "inline-cache.html");
|
||||
dbgValue = await findSource(dbg, "inline-cache.html");
|
||||
info(`Debugger text: ${dbgValue.text}`);
|
||||
ok(dbgValue.text.includes(pageValue),
|
||||
"Debugger loads from network, gets value 2 like page");
|
||||
ok(
|
||||
dbgValue.text.includes(pageValue),
|
||||
"Debugger loads from network, gets value 2 like page"
|
||||
);
|
||||
|
||||
makeChanges();
|
||||
|
||||
@ -94,8 +100,10 @@ add_task(async function () {
|
||||
await waitForLoadedSource(dbg, "inline-cache.html");
|
||||
dbgValue = await findSource(dbg, "inline-cache.html");
|
||||
info(`Debugger text: ${dbgValue.text}`);
|
||||
ok(dbgValue.text.includes(pageValue),
|
||||
"Debugger loads from network, gets value 3 like page");
|
||||
ok(
|
||||
dbgValue.text.includes(pageValue),
|
||||
"Debugger loads from network, gets value 3 like page"
|
||||
);
|
||||
|
||||
info("Enable HTTP cache for page");
|
||||
await toolbox.target.activeTab.reconfigure({ cacheDisabled: false });
|
||||
@ -112,8 +120,10 @@ add_task(async function () {
|
||||
await waitForLoadedSource(dbg, "inline-cache.html");
|
||||
dbgValue = await findSource(dbg, "inline-cache.html");
|
||||
info(`Debugger text: ${dbgValue.text}`);
|
||||
ok(dbgValue.text.includes(pageValue),
|
||||
"Debugger loads from cache, gets value 4 like page");
|
||||
ok(
|
||||
dbgValue.text.includes(pageValue),
|
||||
"Debugger loads from cache, gets value 4 like page"
|
||||
);
|
||||
|
||||
makeChanges();
|
||||
|
||||
@ -124,8 +134,10 @@ add_task(async function () {
|
||||
await waitForLoadedSource(dbg, "inline-cache.html");
|
||||
dbgValue = await findSource(dbg, "inline-cache.html");
|
||||
info(`Debugger text: ${dbgValue.text}`);
|
||||
ok(dbgValue.text.includes(pageValue),
|
||||
"Debugger loads from cache, gets value 5 like page");
|
||||
ok(
|
||||
dbgValue.text.includes(pageValue),
|
||||
"Debugger loads from cache, gets value 5 like page"
|
||||
);
|
||||
|
||||
await toolbox.destroy();
|
||||
await removeTab(tab);
|
||||
|
@ -20,7 +20,10 @@ const sources = [
|
||||
*/
|
||||
add_task(async function() {
|
||||
const dbg = await initDebugger("doc-script-switching.html");
|
||||
const { selectors: { getSelectedSource, isPaused }, getState } = dbg;
|
||||
const {
|
||||
selectors: { getSelectedSource, isPaused },
|
||||
getState
|
||||
} = dbg;
|
||||
|
||||
invokeInTab("firstCall");
|
||||
await waitForPaused(dbg);
|
||||
|
@ -14,7 +14,10 @@ function getNthItem(dbg, index) {
|
||||
|
||||
add_task(async function() {
|
||||
const dbg = await initDebugger("doc-scripts.html");
|
||||
const { selectors: { getSelectedSource }, getState } = dbg;
|
||||
const {
|
||||
selectors: { getSelectedSource },
|
||||
getState
|
||||
} = dbg;
|
||||
|
||||
await selectSource(dbg, "simple1", 1);
|
||||
|
||||
@ -28,13 +31,31 @@ add_task(async function() {
|
||||
assertHighlightLocation(dbg, "simple1", 15);
|
||||
|
||||
// Ensure "main()" is the first function listed
|
||||
const firstFunction = findElementWithSelector(dbg, '.outline-list__element .function-signature');
|
||||
is(firstFunction.innerText, "main()", "Natural first function is first listed");
|
||||
const firstFunction = findElementWithSelector(
|
||||
dbg,
|
||||
".outline-list__element .function-signature"
|
||||
);
|
||||
is(
|
||||
firstFunction.innerText,
|
||||
"main()",
|
||||
"Natural first function is first listed"
|
||||
);
|
||||
// Sort the list
|
||||
findElementWithSelector(dbg, ".outline-footer button").click();
|
||||
// Button becomes active to show alphabetization
|
||||
is(findElementWithSelector(dbg, ".outline-footer button").className, "active", "Alphabetize button is highlighted when active");
|
||||
is(
|
||||
findElementWithSelector(dbg, ".outline-footer button").className,
|
||||
"active",
|
||||
"Alphabetize button is highlighted when active"
|
||||
);
|
||||
// Ensure "doEval()" is the first function listed after alphabetization
|
||||
const firstAlphaFunction = findElementWithSelector(dbg, '.outline-list__element .function-signature');
|
||||
is(firstAlphaFunction.innerText.replace("λ", ""), "doEval()", "Alphabetized first function is correct");
|
||||
const firstAlphaFunction = findElementWithSelector(
|
||||
dbg,
|
||||
".outline-list__element .function-signature"
|
||||
);
|
||||
is(
|
||||
firstAlphaFunction.innerText.replace("λ", ""),
|
||||
"doEval()",
|
||||
"Alphabetized first function is correct"
|
||||
);
|
||||
});
|
||||
|
@ -31,25 +31,21 @@ add_task(async function() {
|
||||
await resume(dbg);
|
||||
await waitForActive(dbg);
|
||||
|
||||
|
||||
log("3. Test pausing on a caught Error");
|
||||
caughtException();
|
||||
await waitForPaused(dbg);
|
||||
assertPausedLocation(dbg);
|
||||
|
||||
|
||||
log("3.b Test pausing in the catch statement");
|
||||
await resume(dbg);
|
||||
await waitForPaused(dbg);
|
||||
assertPausedLocation(dbg);
|
||||
await resume(dbg);
|
||||
|
||||
|
||||
log("4. Test skipping a caught error");
|
||||
await togglePauseOnExceptions(dbg, true, false);
|
||||
caughtException();
|
||||
|
||||
|
||||
log("4.b Test pausing in the catch statement");
|
||||
await waitForPaused(dbg);
|
||||
assertPausedLocation(dbg);
|
||||
|
@ -7,7 +7,7 @@ add_task(async function() {
|
||||
const dbg = await initDebugger("doc-scripts.html");
|
||||
|
||||
clickElement(dbg, "pause");
|
||||
await waitForState(dbg, state => dbg.selectors.getIsWaitingOnBreak(state))
|
||||
await waitForState(dbg, state => dbg.selectors.getIsWaitingOnBreak(state));
|
||||
invokeInTab("simple");
|
||||
|
||||
await waitForPaused(dbg, "simple3");
|
||||
|
@ -1,31 +1,30 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
requestLongerTimeout(2);
|
||||
|
||||
async function stepOvers(dbg, count, onStep = () => {}) {
|
||||
let i = 0;
|
||||
while (i++ <= count) {
|
||||
await dbg.actions.stepOver();
|
||||
await waitForPaused(dbg);
|
||||
onStep(dbg.getState());
|
||||
}
|
||||
}
|
||||
requestLongerTimeout(2);
|
||||
|
||||
async function stepOvers(dbg, count, onStep = () => {}) {
|
||||
let i = 0;
|
||||
while (i++ <= count) {
|
||||
await dbg.actions.stepOver();
|
||||
await waitForPaused(dbg);
|
||||
onStep(dbg.getState());
|
||||
}
|
||||
}
|
||||
|
||||
async function testCase(dbg, { name, count, steps }) {
|
||||
invokeInTab(name);
|
||||
let locations = []
|
||||
let locations = [];
|
||||
|
||||
await stepOvers(dbg, count, state => {
|
||||
locations.push(dbg.selectors.getTopFrame(state).location)
|
||||
locations.push(dbg.selectors.getTopFrame(state).location);
|
||||
});
|
||||
|
||||
const formattedSteps = locations.map(
|
||||
({line, column}) => `(${line},${column})`
|
||||
).join(", ")
|
||||
const formattedSteps = locations
|
||||
.map(({ line, column }) => `(${line},${column})`)
|
||||
.join(", ");
|
||||
|
||||
is(formattedSteps, steps, name)
|
||||
is(formattedSteps, steps, name);
|
||||
|
||||
await resume(dbg);
|
||||
}
|
||||
@ -54,6 +53,7 @@ add_task(async function test() {
|
||||
await testCase(dbg, {
|
||||
name: "flow",
|
||||
count: 8,
|
||||
steps: "(16,2), (17,12), (18,6), (19,8), (19,17), (19,8), (19,17), (19,8), (20,0)"
|
||||
steps:
|
||||
"(16,2), (17,12), (18,6), (19,8), (19,17), (19,8), (19,17), (19,8), (20,0)"
|
||||
});
|
||||
});
|
||||
|
@ -30,7 +30,7 @@ add_task(async function() {
|
||||
invokeInTab("arithmetic");
|
||||
|
||||
info("Switch to console and check message");
|
||||
await waitForConsoleLink(dbg, "math.min.js:3:65");
|
||||
await waitForConsoleLink(dbg, "math.min.js:3:65");
|
||||
|
||||
info("Switch back to debugger and pretty-print");
|
||||
await dbg.toolbox.selectTool("jsdebugger");
|
||||
|
@ -5,7 +5,10 @@
|
||||
// and doesn't have functions.
|
||||
add_task(async function() {
|
||||
const dbg = await initDebugger("doc-scripts.html");
|
||||
const { selectors: { getSelectedSource }, getState } = dbg;
|
||||
const {
|
||||
selectors: { getSelectedSource },
|
||||
getState
|
||||
} = dbg;
|
||||
|
||||
navigate(dbg, "doc-on-load.html");
|
||||
|
||||
|
@ -1,11 +1,10 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
|
||||
async function assertNoTooltip(dbg) {
|
||||
await waitForTime(200);
|
||||
const el = findElement(dbg, "tooltip");
|
||||
is(el, null, "Tooltip should not exist")
|
||||
is(el, null, "Tooltip should not exist");
|
||||
}
|
||||
|
||||
function assertPreviewTooltip(dbg, { result, expression }) {
|
||||
@ -35,7 +34,10 @@ function assertPreviewPopup(dbg, { field, value, expression }) {
|
||||
|
||||
add_task(async function() {
|
||||
const dbg = await initDebugger("doc-sourcemaps.html");
|
||||
const { selectors: { getSelectedSource }, getState } = dbg;
|
||||
const {
|
||||
selectors: { getSelectedSource },
|
||||
getState
|
||||
} = dbg;
|
||||
|
||||
await waitForSources(dbg, "entry.js", "output.js", "times2.js", "opts.js");
|
||||
await selectSource(dbg, "times2");
|
||||
@ -45,21 +47,20 @@ add_task(async function() {
|
||||
await waitForPaused(dbg);
|
||||
await waitForSelectedSource(dbg, "times2");
|
||||
|
||||
info(`Test previewing in the original location`)
|
||||
info(`Test previewing in the original location`);
|
||||
await assertPreviews(dbg, [
|
||||
{ line: 2, column: 10, result: 4, expression: "x" }
|
||||
]);
|
||||
|
||||
info(`Test previewing in the generated location`)
|
||||
info(`Test previewing in the generated location`);
|
||||
await dbg.actions.jumpToMappedSelectedLocation();
|
||||
await waitForSelectedSource(dbg, "bundle.js");
|
||||
await assertPreviews(dbg, [
|
||||
{ line: 70, column: 11, result: 4, expression: "x" }
|
||||
]);
|
||||
|
||||
|
||||
info(`Test that you can not preview in another original file`);
|
||||
await selectSource(dbg, "output");
|
||||
await hoverAtPos(dbg, { line: 2, ch: 16 });
|
||||
await assertNoTooltip(dbg)
|
||||
await assertNoTooltip(dbg);
|
||||
});
|
||||
|
@ -25,7 +25,7 @@ add_task(async function() {
|
||||
await addBreakpoint(dbg, "sjs_code_reload", 2);
|
||||
|
||||
await reload(dbg, "sjs_code_reload.sjs");
|
||||
await waitForSelectedSource(dbg, "sjs_code_reload.sjs")
|
||||
await waitForSelectedSource(dbg, "sjs_code_reload.sjs");
|
||||
|
||||
const source = findSource(dbg, "sjs_code_reload");
|
||||
const location = { sourceId: source.id, line: 6 };
|
||||
|
@ -43,7 +43,10 @@ async function clickResume(dbg) {
|
||||
}
|
||||
|
||||
function assertHistoryPosition(dbg, position) {
|
||||
const { selectors: { getHistoryPosition, getHistoryFrame }, getState } = dbg;
|
||||
const {
|
||||
selectors: { getHistoryPosition, getHistoryFrame },
|
||||
getState
|
||||
} = dbg;
|
||||
|
||||
ok(
|
||||
getHistoryPosition(getState()) === position - 1,
|
||||
|
@ -1,11 +1,21 @@
|
||||
|
||||
async function evalInConsoleAtPoint(dbg, fixture, { line, column }, statements) {
|
||||
async function evalInConsoleAtPoint(
|
||||
dbg,
|
||||
fixture,
|
||||
{ line, column },
|
||||
statements
|
||||
) {
|
||||
const filename = `fixtures/${fixture}/input.js`;
|
||||
const fnName = fixture.replace(/-([a-z])/g, (s, c) => c.toUpperCase());
|
||||
|
||||
await invokeWithBreakpoint(dbg, fnName, filename, { line, column }, async () => {
|
||||
await assertConsoleEval(dbg, statements);
|
||||
});
|
||||
await invokeWithBreakpoint(
|
||||
dbg,
|
||||
fnName,
|
||||
filename,
|
||||
{ line, column },
|
||||
async () => {
|
||||
await assertConsoleEval(dbg, statements);
|
||||
}
|
||||
);
|
||||
|
||||
ok(true, `Ran tests for ${fixture} at line ${line} column ${column}`);
|
||||
}
|
||||
@ -34,24 +44,30 @@ add_task(async function() {
|
||||
await evalInConsoleAtPoint(dbg, "babel-eval-maps", { line: 14, column: 4 }, [
|
||||
"one === 1",
|
||||
"two === 4",
|
||||
"three === 5",
|
||||
"three === 5"
|
||||
]);
|
||||
|
||||
await evalInConsoleAtPoint(dbg, "babel-modules-cjs", { line: 20, column: 2 }, [
|
||||
`aDefault === "a-default"`,
|
||||
`anAliased === "an-original"`,
|
||||
`aNamed === "a-named"`,
|
||||
`aDefault2 === "a-default2"`,
|
||||
`anAliased2 === "an-original2"`,
|
||||
`aNamed2 === "a-named2"`,
|
||||
`aDefault3 === "a-default3"`,
|
||||
`anAliased3 === "an-original3"`,
|
||||
`aNamed3 === "a-named3"`,
|
||||
]);
|
||||
await evalInConsoleAtPoint(
|
||||
dbg,
|
||||
"babel-modules-cjs",
|
||||
{ line: 20, column: 2 },
|
||||
[
|
||||
`aDefault === "a-default"`,
|
||||
`anAliased === "an-original"`,
|
||||
`aNamed === "a-named"`,
|
||||
`aDefault2 === "a-default2"`,
|
||||
`anAliased2 === "an-original2"`,
|
||||
`aNamed2 === "a-named2"`,
|
||||
`aDefault3 === "a-default3"`,
|
||||
`anAliased3 === "an-original3"`,
|
||||
`aNamed3 === "a-named3"`
|
||||
]
|
||||
);
|
||||
|
||||
await evalInConsoleAtPoint(dbg, "babel-shadowed-vars", { line: 18, column: 6 }, [
|
||||
`aVar === "var3"`,
|
||||
`aLet === "let3"`,
|
||||
`aConst === "const3"`,
|
||||
]);
|
||||
await evalInConsoleAtPoint(
|
||||
dbg,
|
||||
"babel-shadowed-vars",
|
||||
{ line: 18, column: 6 },
|
||||
[`aVar === "var3"`, `aLet === "let3"`, `aConst === "const3"`]
|
||||
);
|
||||
});
|
||||
|
@ -10,9 +10,15 @@ async function breakpointPreviews(dbg, fixture, { line, column }, previews) {
|
||||
|
||||
log(`Starting ${fixture} tests`);
|
||||
|
||||
await invokeWithBreakpoint(dbg, fnName, filename, { line, column }, async () => {
|
||||
await assertPreviews(dbg, previews);
|
||||
});
|
||||
await invokeWithBreakpoint(
|
||||
dbg,
|
||||
fnName,
|
||||
filename,
|
||||
{ line, column },
|
||||
async () => {
|
||||
await assertPreviews(dbg, previews);
|
||||
}
|
||||
);
|
||||
|
||||
ok(true, `Ran tests for ${fixture} at line ${line} column ${column}`);
|
||||
}
|
||||
@ -23,25 +29,29 @@ function testForOf(dbg) {
|
||||
line: 5,
|
||||
column: 7,
|
||||
expression: "doThing",
|
||||
result: "doThing(arg)",
|
||||
result: "doThing(arg)"
|
||||
},
|
||||
{
|
||||
line: 5,
|
||||
column: 13,
|
||||
expression: "x",
|
||||
result: "1",
|
||||
result: "1"
|
||||
},
|
||||
{
|
||||
line: 8,
|
||||
column: 16,
|
||||
expression: "doThing",
|
||||
result: "doThing(arg)",
|
||||
},
|
||||
result: "doThing(arg)"
|
||||
}
|
||||
]);
|
||||
}
|
||||
|
||||
function testShadowing(dbg) {
|
||||
return breakpointPreviews(dbg, "babel-shadowed-vars", { line: 18, column: 6 }, [
|
||||
return breakpointPreviews(
|
||||
dbg,
|
||||
"babel-shadowed-vars",
|
||||
{ line: 18, column: 6 },
|
||||
[
|
||||
// These aren't what the user would expect, but we test them anyway since
|
||||
// they reflect what this actually returns. These shadowed bindings read
|
||||
// the binding closest to the current frame's scope even though their
|
||||
@ -50,37 +60,37 @@ function testShadowing(dbg) {
|
||||
line: 2,
|
||||
column: 9,
|
||||
expression: "aVar",
|
||||
result: '"var3"',
|
||||
result: '"var3"'
|
||||
},
|
||||
{
|
||||
line: 3,
|
||||
column: 9,
|
||||
expression: "_aLet2;",
|
||||
result: '"let3"',
|
||||
result: '"let3"'
|
||||
},
|
||||
{
|
||||
line: 4,
|
||||
column: 11,
|
||||
expression: "_aConst2;",
|
||||
result: '"const3"',
|
||||
result: '"const3"'
|
||||
},
|
||||
{
|
||||
line: 10,
|
||||
column: 11,
|
||||
expression: "aVar",
|
||||
result: '"var3"',
|
||||
result: '"var3"'
|
||||
},
|
||||
{
|
||||
line: 11,
|
||||
column: 11,
|
||||
expression: "_aLet2;",
|
||||
result: '"let3"',
|
||||
result: '"let3"'
|
||||
},
|
||||
{
|
||||
line: 12,
|
||||
column: 13,
|
||||
expression: "_aConst2;",
|
||||
result: '"const3"',
|
||||
result: '"const3"'
|
||||
},
|
||||
|
||||
// These actually result in the values the user would expect.
|
||||
@ -88,100 +98,94 @@ function testShadowing(dbg) {
|
||||
line: 14,
|
||||
column: 13,
|
||||
expression: "aVar",
|
||||
result: '"var3"',
|
||||
result: '"var3"'
|
||||
},
|
||||
{
|
||||
line: 15,
|
||||
column: 13,
|
||||
expression: "_aLet2;",
|
||||
result: '"let3"',
|
||||
result: '"let3"'
|
||||
},
|
||||
{
|
||||
line: 16,
|
||||
column: 13,
|
||||
expression: "_aConst2;",
|
||||
result: '"const3"',
|
||||
},
|
||||
]);
|
||||
result: '"const3"'
|
||||
}
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
function testImportedBindings(dbg) {
|
||||
return breakpointPreviews(dbg, "babel-modules-cjs", { line: 20, column: 2 }, [
|
||||
{
|
||||
line: 22,
|
||||
column: 16,
|
||||
expression: "_mod2.default;",
|
||||
result: '"a-default"',
|
||||
},
|
||||
{
|
||||
line: 23,
|
||||
column: 16,
|
||||
expression: "_mod4.original;",
|
||||
result: '"an-original"',
|
||||
},
|
||||
{
|
||||
line: 24,
|
||||
column: 16,
|
||||
expression: "_mod3.aNamed;",
|
||||
result: '"a-named"',
|
||||
},
|
||||
{
|
||||
line: 25,
|
||||
column: 16,
|
||||
expression: "_mod3.aNamed;",
|
||||
result: '"a-named"',
|
||||
},
|
||||
{
|
||||
line: 26,
|
||||
column: 16,
|
||||
expression: "aNamespace",
|
||||
fields: [
|
||||
['aNamed', 'a-named'],
|
||||
['default', 'a-default'],
|
||||
],
|
||||
},
|
||||
{
|
||||
line: 31,
|
||||
column: 20,
|
||||
expression: "_mod7.default;",
|
||||
result: '"a-default2"',
|
||||
},
|
||||
{
|
||||
line: 32,
|
||||
column: 20,
|
||||
expression: "_mod9.original;",
|
||||
result: '"an-original2"',
|
||||
},
|
||||
{
|
||||
line: 33,
|
||||
column: 20,
|
||||
expression: "_mod8.aNamed2;",
|
||||
result: '"a-named2"',
|
||||
},
|
||||
{
|
||||
line: 34,
|
||||
column: 20,
|
||||
expression: "_mod8.aNamed2;",
|
||||
result: '"a-named2"',
|
||||
},
|
||||
{
|
||||
line: 35,
|
||||
column: 20,
|
||||
expression: "aNamespace2",
|
||||
fields: [
|
||||
['aNamed', 'a-named2'],
|
||||
['default', 'a-default2'],
|
||||
],
|
||||
},
|
||||
]);
|
||||
{
|
||||
line: 22,
|
||||
column: 16,
|
||||
expression: "_mod2.default;",
|
||||
result: '"a-default"'
|
||||
},
|
||||
{
|
||||
line: 23,
|
||||
column: 16,
|
||||
expression: "_mod4.original;",
|
||||
result: '"an-original"'
|
||||
},
|
||||
{
|
||||
line: 24,
|
||||
column: 16,
|
||||
expression: "_mod3.aNamed;",
|
||||
result: '"a-named"'
|
||||
},
|
||||
{
|
||||
line: 25,
|
||||
column: 16,
|
||||
expression: "_mod3.aNamed;",
|
||||
result: '"a-named"'
|
||||
},
|
||||
{
|
||||
line: 26,
|
||||
column: 16,
|
||||
expression: "aNamespace",
|
||||
fields: [["aNamed", "a-named"], ["default", "a-default"]]
|
||||
},
|
||||
{
|
||||
line: 31,
|
||||
column: 20,
|
||||
expression: "_mod7.default;",
|
||||
result: '"a-default2"'
|
||||
},
|
||||
{
|
||||
line: 32,
|
||||
column: 20,
|
||||
expression: "_mod9.original;",
|
||||
result: '"an-original2"'
|
||||
},
|
||||
{
|
||||
line: 33,
|
||||
column: 20,
|
||||
expression: "_mod8.aNamed2;",
|
||||
result: '"a-named2"'
|
||||
},
|
||||
{
|
||||
line: 34,
|
||||
column: 20,
|
||||
expression: "_mod8.aNamed2;",
|
||||
result: '"a-named2"'
|
||||
},
|
||||
{
|
||||
line: 35,
|
||||
column: 20,
|
||||
expression: "aNamespace2",
|
||||
fields: [["aNamed", "a-named2"], ["default", "a-default2"]]
|
||||
}
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
add_task(async function() {
|
||||
await pushPref("devtools.debugger.features.map-scopes", true);
|
||||
const dbg = await initDebugger("doc-sourcemapped.html");
|
||||
|
||||
await testForOf(dbg)
|
||||
await testShadowing(dbg)
|
||||
await testImportedBindings(dbg)
|
||||
await testForOf(dbg);
|
||||
await testShadowing(dbg);
|
||||
await testImportedBindings(dbg);
|
||||
});
|
||||
|
@ -10,9 +10,15 @@ async function breakpointScopes(dbg, fixture, { line, column }, scopes) {
|
||||
const filename = `fixtures/${fixture}/input.`;
|
||||
const fnName = fixture.replace(/-([a-z])/g, (s, c) => c.toUpperCase());
|
||||
|
||||
await invokeWithBreakpoint(dbg, fnName, filename, { line, column }, async () => {
|
||||
await assertScopes(dbg, scopes);
|
||||
});
|
||||
await invokeWithBreakpoint(
|
||||
dbg,
|
||||
fnName,
|
||||
filename,
|
||||
{ line, column },
|
||||
async () => {
|
||||
await assertScopes(dbg, scopes);
|
||||
}
|
||||
);
|
||||
|
||||
ok(true, `Ran tests for ${fixture} at line ${line} column ${column}`);
|
||||
}
|
||||
@ -31,7 +37,7 @@ add_task(async function() {
|
||||
"ExportedOther()",
|
||||
"ExpressionClass:Foo()",
|
||||
"fn()",
|
||||
["ns", '{\u2026}'],
|
||||
["ns", "{\u2026}"],
|
||||
"SubDecl()",
|
||||
"SubVar:SubExpr()"
|
||||
]);
|
||||
@ -81,7 +87,7 @@ add_task(async function() {
|
||||
{ line: 19, column: 4 },
|
||||
[
|
||||
"Block",
|
||||
["<this>", '{\u2026}'],
|
||||
["<this>", "{\u2026}"],
|
||||
["one", "1"],
|
||||
["two", "2"],
|
||||
"root",
|
||||
@ -227,31 +233,37 @@ add_task(async function() {
|
||||
"thirdModuleScoped()"
|
||||
]);
|
||||
|
||||
await breakpointScopes(dbg, "babel-out-of-order-declarations-cjs", { line: 8, column: 4 }, [
|
||||
"callback",
|
||||
"fn()",
|
||||
["val", "undefined"],
|
||||
"root",
|
||||
["callback", "(optimized away)"],
|
||||
["fn", "(optimized away)"],
|
||||
["val", "(optimized away)"],
|
||||
"Module",
|
||||
await breakpointScopes(
|
||||
dbg,
|
||||
"babel-out-of-order-declarations-cjs",
|
||||
{ line: 8, column: 4 },
|
||||
[
|
||||
"callback",
|
||||
"fn()",
|
||||
["val", "undefined"],
|
||||
"root",
|
||||
["callback", "(optimized away)"],
|
||||
["fn", "(optimized away)"],
|
||||
["val", "(optimized away)"],
|
||||
"Module",
|
||||
|
||||
// This value is currently optimized away, which isn't 100% accurate.
|
||||
// Because import declarations is the last thing in the file, our current
|
||||
// logic doesn't cover _both_ 'var' statements that it generates,
|
||||
// making us use the first, optimized-out binding. Given that imports
|
||||
// are almost never the last thing in a file though, this is probably not
|
||||
// a huge deal for now.
|
||||
["aDefault", "(optimized away)"],
|
||||
["root", "(optimized away)"],
|
||||
["val", "(optimized away)"],
|
||||
]);
|
||||
await breakpointScopes(dbg, "babel-flowtype-bindings", { line: 8, column: 2 }, [
|
||||
"Module",
|
||||
["aConst", '"a-const"'],
|
||||
"root()"
|
||||
]);
|
||||
// This value is currently optimized away, which isn't 100% accurate.
|
||||
// Because import declarations is the last thing in the file, our current
|
||||
// logic doesn't cover _both_ 'var' statements that it generates,
|
||||
// making us use the first, optimized-out binding. Given that imports
|
||||
// are almost never the last thing in a file though, this is probably not
|
||||
// a huge deal for now.
|
||||
["aDefault", "(optimized away)"],
|
||||
["root", "(optimized away)"],
|
||||
["val", "(optimized away)"]
|
||||
]
|
||||
);
|
||||
await breakpointScopes(
|
||||
dbg,
|
||||
"babel-flowtype-bindings",
|
||||
{ line: 8, column: 2 },
|
||||
["Module", ["aConst", '"a-const"'], "root()"]
|
||||
);
|
||||
|
||||
await breakpointScopes(dbg, "babel-switches", { line: 7, column: 6 }, [
|
||||
"Switch",
|
||||
@ -284,49 +296,59 @@ add_task(async function() {
|
||||
"root()"
|
||||
]);
|
||||
|
||||
await breakpointScopes(dbg, "babel-modules-webpack", { line: 20, column: 2 }, [
|
||||
"Module",
|
||||
["aDefault", '"a-default"'],
|
||||
["aDefault2", '"a-default2"'],
|
||||
["aDefault3", '"a-default3"'],
|
||||
["anAliased", "Getter"],
|
||||
["anAliased2", "Getter"],
|
||||
["anAliased3", "Getter"],
|
||||
["aNamed", "Getter"],
|
||||
["aNamed2", "Getter"],
|
||||
["aNamed3", "Getter"],
|
||||
["aNamespace", "{\u2026}"],
|
||||
["aNamespace2", "{\u2026}"],
|
||||
["aNamespace3", "{\u2026}"],
|
||||
["anotherNamed", "Getter"],
|
||||
["anotherNamed2", "Getter"],
|
||||
["anotherNamed3", "Getter"],
|
||||
["example", "(optimized away)"],
|
||||
["optimizedOut", "(optimized away)"],
|
||||
"root()"
|
||||
]);
|
||||
await breakpointScopes(
|
||||
dbg,
|
||||
"babel-modules-webpack",
|
||||
{ line: 20, column: 2 },
|
||||
[
|
||||
"Module",
|
||||
["aDefault", '"a-default"'],
|
||||
["aDefault2", '"a-default2"'],
|
||||
["aDefault3", '"a-default3"'],
|
||||
["anAliased", "Getter"],
|
||||
["anAliased2", "Getter"],
|
||||
["anAliased3", "Getter"],
|
||||
["aNamed", "Getter"],
|
||||
["aNamed2", "Getter"],
|
||||
["aNamed3", "Getter"],
|
||||
["aNamespace", "{\u2026}"],
|
||||
["aNamespace2", "{\u2026}"],
|
||||
["aNamespace3", "{\u2026}"],
|
||||
["anotherNamed", "Getter"],
|
||||
["anotherNamed2", "Getter"],
|
||||
["anotherNamed3", "Getter"],
|
||||
["example", "(optimized away)"],
|
||||
["optimizedOut", "(optimized away)"],
|
||||
"root()"
|
||||
]
|
||||
);
|
||||
|
||||
await breakpointScopes(dbg, "babel-modules-webpack-es6", { line: 20, column: 2 }, [
|
||||
"Module",
|
||||
["aDefault", '"a-default"'],
|
||||
["aDefault2", '"a-default2"'],
|
||||
["aDefault3", '"a-default3"'],
|
||||
["anAliased", '"an-original"'],
|
||||
["anAliased2", '"an-original2"'],
|
||||
["anAliased3", '"an-original3"'],
|
||||
["aNamed", '"a-named"'],
|
||||
["aNamed2", '"a-named2"'],
|
||||
["aNamed3", '"a-named3"'],
|
||||
["aNamespace", "{\u2026}"],
|
||||
["aNamespace2", "{\u2026}"],
|
||||
["aNamespace3", "{\u2026}"],
|
||||
["anotherNamed", '"a-named"'],
|
||||
["anotherNamed2", '"a-named2"'],
|
||||
["anotherNamed3", '"a-named3"'],
|
||||
["example", "(optimized away)"],
|
||||
["optimizedOut", "(optimized away)"],
|
||||
"root()"
|
||||
]);
|
||||
await breakpointScopes(
|
||||
dbg,
|
||||
"babel-modules-webpack-es6",
|
||||
{ line: 20, column: 2 },
|
||||
[
|
||||
"Module",
|
||||
["aDefault", '"a-default"'],
|
||||
["aDefault2", '"a-default2"'],
|
||||
["aDefault3", '"a-default3"'],
|
||||
["anAliased", '"an-original"'],
|
||||
["anAliased2", '"an-original2"'],
|
||||
["anAliased3", '"an-original3"'],
|
||||
["aNamed", '"a-named"'],
|
||||
["aNamed2", '"a-named2"'],
|
||||
["aNamed3", '"a-named3"'],
|
||||
["aNamespace", "{\u2026}"],
|
||||
["aNamespace2", "{\u2026}"],
|
||||
["aNamespace3", "{\u2026}"],
|
||||
["anotherNamed", '"a-named"'],
|
||||
["anotherNamed2", '"a-named2"'],
|
||||
["anotherNamed3", '"a-named3"'],
|
||||
["example", "(optimized away)"],
|
||||
["optimizedOut", "(optimized away)"],
|
||||
"root()"
|
||||
]
|
||||
);
|
||||
|
||||
await breakpointScopes(
|
||||
dbg,
|
||||
|
@ -8,15 +8,24 @@ async function breakpointSteps(dbg, fixture, { line, column }, steps) {
|
||||
const filename = `fixtures/${fixture}/input.js`;
|
||||
const fnName = fixture.replace(/-([a-z])/g, (s, c) => c.toUpperCase());
|
||||
|
||||
await invokeWithBreakpoint(dbg, fnName, filename, { line, column }, async source => {
|
||||
await runSteps(dbg, source, steps);
|
||||
});
|
||||
await invokeWithBreakpoint(
|
||||
dbg,
|
||||
fnName,
|
||||
filename,
|
||||
{ line, column },
|
||||
async source => {
|
||||
await runSteps(dbg, source, steps);
|
||||
}
|
||||
);
|
||||
|
||||
ok(true, `Ran tests for ${fixture} at line ${line} column ${column}`);
|
||||
}
|
||||
|
||||
async function runSteps(dbg, source, steps) {
|
||||
const { selectors: { getVisibleSelectedFrame }, getState } = dbg;
|
||||
const {
|
||||
selectors: { getVisibleSelectedFrame },
|
||||
getState
|
||||
} = dbg;
|
||||
|
||||
for (const [i, [type, position]] of steps.entries()) {
|
||||
switch (type) {
|
||||
@ -41,29 +50,39 @@ async function runSteps(dbg, source, steps) {
|
||||
}
|
||||
|
||||
function testStepOverForOf(dbg) {
|
||||
return breakpointSteps(dbg, "babel-step-over-for-of", { line: 4, column: 2 }, [
|
||||
["stepOver", { line: 6, column: 2 }],
|
||||
["stepOver", { line: 7, column: 4 }],
|
||||
["stepOver", { line: 6, column: 2 }],
|
||||
["stepOver", { line: 7, column: 4 }],
|
||||
["stepOver", { line: 6, column: 2 }],
|
||||
["stepOver", { line: 10, column: 2 }]
|
||||
]);
|
||||
return breakpointSteps(
|
||||
dbg,
|
||||
"babel-step-over-for-of",
|
||||
{ line: 4, column: 2 },
|
||||
[
|
||||
["stepOver", { line: 6, column: 2 }],
|
||||
["stepOver", { line: 7, column: 4 }],
|
||||
["stepOver", { line: 6, column: 2 }],
|
||||
["stepOver", { line: 7, column: 4 }],
|
||||
["stepOver", { line: 6, column: 2 }],
|
||||
["stepOver", { line: 10, column: 2 }]
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
// This codifies the current behavior, but stepping twice over the for
|
||||
// header isn't ideal.
|
||||
function testStepOverForOfArray(dbg) {
|
||||
return breakpointSteps(dbg, "babel-step-over-for-of-array", { line: 3, column: 2 }, [
|
||||
["stepOver", { line: 5, column: 2 }],
|
||||
["stepOver", { line: 5, column: 7 }],
|
||||
["stepOver", { line: 6, column: 4 }],
|
||||
["stepOver", { line: 5, column: 2 }],
|
||||
["stepOver", { line: 5, column: 7 }],
|
||||
["stepOver", { line: 6, column: 4 }],
|
||||
["stepOver", { line: 5, column: 2 }],
|
||||
["stepOver", { line: 9, column: 2 }]
|
||||
]);
|
||||
return breakpointSteps(
|
||||
dbg,
|
||||
"babel-step-over-for-of-array",
|
||||
{ line: 3, column: 2 },
|
||||
[
|
||||
["stepOver", { line: 5, column: 2 }],
|
||||
["stepOver", { line: 5, column: 7 }],
|
||||
["stepOver", { line: 6, column: 4 }],
|
||||
["stepOver", { line: 5, column: 2 }],
|
||||
["stepOver", { line: 5, column: 7 }],
|
||||
["stepOver", { line: 6, column: 4 }],
|
||||
["stepOver", { line: 5, column: 2 }],
|
||||
["stepOver", { line: 9, column: 2 }]
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
// The closure means it isn't actually possible to step into the for body,
|
||||
|
@ -8,7 +8,10 @@ requestLongerTimeout(2);
|
||||
add_task(async function() {
|
||||
// NOTE: the CORS call makes the test run times inconsistent
|
||||
const dbg = await initDebugger("doc-sourcemap-bogus.html");
|
||||
const { selectors: { getSources }, getState } = dbg;
|
||||
const {
|
||||
selectors: { getSources },
|
||||
getState
|
||||
} = dbg;
|
||||
|
||||
await selectSource(dbg, "bogus-map.js");
|
||||
|
||||
|
@ -25,11 +25,11 @@ function getBreakpoints(dbg) {
|
||||
add_task(async function() {
|
||||
const dbg = await initDebugger("doc-minified.html");
|
||||
|
||||
dump(`>> meh`)
|
||||
dump(`>> meh`);
|
||||
|
||||
await navigate(dbg, "sourcemaps-reload/doc-sourcemaps-reload.html", "v1");
|
||||
|
||||
dump(`>> select v1`)
|
||||
dump(`>> select v1`);
|
||||
await selectSource(dbg, "v1");
|
||||
await addBreakpoint(dbg, "v1", 6);
|
||||
let breakpoint = getBreakpoints(dbg)[0];
|
||||
|
@ -12,7 +12,10 @@ async function waitForBreakpointCount(dbg, count) {
|
||||
add_task(async function() {
|
||||
// NOTE: the CORS call makes the test run times inconsistent
|
||||
const dbg = await initDebugger("doc-sourcemaps.html");
|
||||
const { selectors: { getBreakpoint, getBreakpoints }, getState } = dbg;
|
||||
const {
|
||||
selectors: { getBreakpoint, getBreakpoints },
|
||||
getState
|
||||
} = dbg;
|
||||
|
||||
await waitForSources(dbg, "entry.js", "output.js", "times2.js", "opts.js");
|
||||
ok(true, "Original sources exist");
|
||||
@ -20,7 +23,9 @@ add_task(async function() {
|
||||
|
||||
await selectSource(dbg, entrySrc);
|
||||
ok(
|
||||
getCM(dbg).getValue().includes("window.keepMeAlive"),
|
||||
getCM(dbg)
|
||||
.getValue()
|
||||
.includes("window.keepMeAlive"),
|
||||
"Original source text loaded correctly"
|
||||
);
|
||||
|
||||
|
@ -6,7 +6,10 @@
|
||||
requestLongerTimeout(2);
|
||||
|
||||
function assertBreakpointExists(dbg, source, line) {
|
||||
const { selectors: { getBreakpoint }, getState } = dbg;
|
||||
const {
|
||||
selectors: { getBreakpoint },
|
||||
getState
|
||||
} = dbg;
|
||||
|
||||
ok(
|
||||
getBreakpoint(getState(), { sourceId: source.id, line }),
|
||||
@ -37,7 +40,10 @@ function clickGutter(dbg, line) {
|
||||
add_task(async function() {
|
||||
// NOTE: the CORS call makes the test run times inconsistent
|
||||
const dbg = await initDebugger("doc-sourcemaps.html");
|
||||
const { selectors: { getBreakpoint, getBreakpoints }, getState } = dbg;
|
||||
const {
|
||||
selectors: { getBreakpoint, getBreakpoints },
|
||||
getState
|
||||
} = dbg;
|
||||
|
||||
await waitForSources(dbg, "entry.js", "output.js", "times2.js", "opts.js");
|
||||
ok(true, "Original sources exist");
|
||||
@ -57,7 +63,9 @@ add_task(async function() {
|
||||
|
||||
await selectSource(dbg, entrySrc);
|
||||
ok(
|
||||
getCM(dbg).getValue().includes("window.keepMeAlive"),
|
||||
getCM(dbg)
|
||||
.getValue()
|
||||
.includes("window.keepMeAlive"),
|
||||
"Original source text loaded correctly"
|
||||
);
|
||||
|
||||
|
@ -19,7 +19,10 @@ function assertBpInGutter(dbg, lineNumber) {
|
||||
add_task(async function() {
|
||||
// NOTE: the CORS call makes the test run times inconsistent
|
||||
const dbg = await initDebugger("doc-sourcemaps2.html");
|
||||
const { selectors: { getBreakpoint, getBreakpoints }, getState } = dbg;
|
||||
const {
|
||||
selectors: { getBreakpoint, getBreakpoints },
|
||||
getState
|
||||
} = dbg;
|
||||
|
||||
await waitForSources(dbg, "main.js", "main.min.js");
|
||||
|
||||
|
@ -11,7 +11,10 @@ add_task(async function() {
|
||||
await pushPref("devtools.debugger.features.map-scopes", true);
|
||||
|
||||
const dbg = await initDebugger("doc-sourcemaps3.html");
|
||||
const { selectors: { getBreakpoint, getBreakpoints }, getState } = dbg;
|
||||
const {
|
||||
selectors: { getBreakpoint, getBreakpoints },
|
||||
getState
|
||||
} = dbg;
|
||||
|
||||
await waitForSources(dbg, "bundle.js", "sorted.js", "test.js");
|
||||
|
||||
|
@ -19,7 +19,10 @@ function getLabel(dbg, index) {
|
||||
|
||||
add_task(async function() {
|
||||
const dbg = await initDebugger("doc-sources.html");
|
||||
const { selectors: { getSelectedSource }, getState } = dbg;
|
||||
const {
|
||||
selectors: { getSelectedSource },
|
||||
getState
|
||||
} = dbg;
|
||||
|
||||
await waitForSources(dbg, "simple1", "simple2", "nested-source", "long.js");
|
||||
|
||||
|
@ -24,7 +24,10 @@ function getLabel(dbg, index) {
|
||||
|
||||
add_task(async function() {
|
||||
const dbg = await initDebugger("doc-sources.html");
|
||||
const { selectors: { getSelectedSource }, getState } = dbg;
|
||||
const {
|
||||
selectors: { getSelectedSource },
|
||||
getState
|
||||
} = dbg;
|
||||
|
||||
await waitForSources(dbg, "simple1", "simple2", "nested-source", "long.js");
|
||||
|
||||
@ -49,10 +52,7 @@ add_task(async function() {
|
||||
const selectedSource = getSelectedSource(getState()).get("url");
|
||||
|
||||
ok(fourthNode.classList.contains("focused"), "4th node is focused");
|
||||
ok(
|
||||
selectedSource.includes("nested-source.js"),
|
||||
"nested-source is selected"
|
||||
);
|
||||
ok(selectedSource.includes("nested-source.js"), "nested-source is selected");
|
||||
|
||||
await waitForSelectedSource(dbg, "nested-source");
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// This test can be really slow on debug platforms
|
||||
requestLongerTimeout(5);
|
||||
// This test can be really slow on debug platforms
|
||||
requestLongerTimeout(5);
|
||||
|
||||
add_task(async function test() {
|
||||
const dbg = await initDebugger("big-sourcemap.html", "big-sourcemap");
|
||||
|
@ -16,8 +16,5 @@
|
||||
// it's not immediately garbage collected.
|
||||
inline_script = function () { var x = 5; };
|
||||
</script>
|
||||
|
||||
<button onclick="empties()">Empties</button>
|
||||
<button onclick="smalls()">Smalls</button>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -40,7 +40,8 @@ Services.scriptloader.loadSubScript(
|
||||
|
||||
Services.scriptloader.loadSubScript(
|
||||
"chrome://mochitests/content/browser/devtools/client/debugger/new/test/mochitest/helpers.js",
|
||||
this);
|
||||
this
|
||||
);
|
||||
|
||||
const EXAMPLE_URL =
|
||||
"http://example.com/browser/devtools/client/debugger/new/test/mochitest/examples/";
|
||||
|
@ -156,7 +156,10 @@ function waitForState(dbg, predicate, msg) {
|
||||
* @static
|
||||
*/
|
||||
async function waitForSources(dbg, ...sources) {
|
||||
const { selectors: { getSources }, store } = dbg;
|
||||
const {
|
||||
selectors: { getSources },
|
||||
store
|
||||
} = dbg;
|
||||
if (sources.length === 0) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
@ -211,7 +214,6 @@ function waitForSelectedSource(dbg, url) {
|
||||
return waitForState(
|
||||
dbg,
|
||||
state => {
|
||||
|
||||
const source = dbg.selectors.getSelectedSource(state);
|
||||
const isLoaded = source && sourceUtils.isLoaded(source);
|
||||
if (!isLoaded) {
|
||||
@ -259,7 +261,10 @@ function assertPaused(dbg) {
|
||||
}
|
||||
|
||||
function getVisibleSelectedFrameLine(dbg) {
|
||||
const { selectors: { getVisibleSelectedFrame }, getState } = dbg;
|
||||
const {
|
||||
selectors: { getVisibleSelectedFrame },
|
||||
getState
|
||||
} = dbg;
|
||||
const frame = getVisibleSelectedFrame(getState());
|
||||
return frame && frame.location.line;
|
||||
}
|
||||
@ -274,7 +279,10 @@ function getVisibleSelectedFrameLine(dbg) {
|
||||
* @static
|
||||
*/
|
||||
function assertPausedLocation(dbg) {
|
||||
const { selectors: { getSelectedSource }, getState } = dbg;
|
||||
const {
|
||||
selectors: { getSelectedSource },
|
||||
getState
|
||||
} = dbg;
|
||||
|
||||
ok(
|
||||
isSelectedFrameSelected(dbg, getState()),
|
||||
@ -344,7 +352,10 @@ function assertDebugLine(dbg, line) {
|
||||
* @static
|
||||
*/
|
||||
function assertHighlightLocation(dbg, source, line) {
|
||||
const { selectors: { getSelectedSource }, getState } = dbg;
|
||||
const {
|
||||
selectors: { getSelectedSource },
|
||||
getState
|
||||
} = dbg;
|
||||
source = findSource(dbg, source);
|
||||
|
||||
// Check the selected source
|
||||
@ -381,7 +392,10 @@ function assertHighlightLocation(dbg, source, line) {
|
||||
* @static
|
||||
*/
|
||||
function isPaused(dbg) {
|
||||
const { selectors: { isPaused }, getState } = dbg;
|
||||
const {
|
||||
selectors: { isPaused },
|
||||
getState
|
||||
} = dbg;
|
||||
return !!isPaused(getState());
|
||||
}
|
||||
|
||||
@ -687,8 +701,8 @@ async function reload(dbg, ...sources) {
|
||||
* @static
|
||||
*/
|
||||
async function navigate(dbg, url, ...sources) {
|
||||
info(`Navigating to ${url}`)
|
||||
const navigated = waitForDispatch(dbg, "NAVIGATE");
|
||||
info(`Navigating to ${url}`);
|
||||
const navigated = waitForDispatch(dbg, "NAVIGATE");
|
||||
await dbg.client.navigate(url);
|
||||
await navigated;
|
||||
return waitForSources(dbg, ...sources);
|
||||
@ -720,7 +734,10 @@ function disableBreakpoint(dbg, source, line, column) {
|
||||
}
|
||||
|
||||
async function loadAndAddBreakpoint(dbg, filename, line, column) {
|
||||
const { selectors: { getBreakpoint, getBreakpoints }, getState } = dbg;
|
||||
const {
|
||||
selectors: { getBreakpoint, getBreakpoints },
|
||||
getState
|
||||
} = dbg;
|
||||
|
||||
await waitForSources(dbg, filename);
|
||||
|
||||
@ -741,8 +758,17 @@ async function loadAndAddBreakpoint(dbg, filename, line, column) {
|
||||
return source;
|
||||
}
|
||||
|
||||
async function invokeWithBreakpoint(dbg, fnName, filename, { line, column }, handler) {
|
||||
const { selectors: { getBreakpoints }, getState } = dbg;
|
||||
async function invokeWithBreakpoint(
|
||||
dbg,
|
||||
fnName,
|
||||
filename,
|
||||
{ line, column },
|
||||
handler
|
||||
) {
|
||||
const {
|
||||
selectors: { getBreakpoints },
|
||||
getState
|
||||
} = dbg;
|
||||
|
||||
const source = await loadAndAddBreakpoint(dbg, filename, line, column);
|
||||
|
||||
@ -1003,7 +1029,7 @@ const selectors = {
|
||||
`.expressions-list .expression-container:nth-child(${i}) .object-delimiter + *`,
|
||||
expressionClose: i =>
|
||||
`.expressions-list .expression-container:nth-child(${i}) .close`,
|
||||
expressionInput: '.expressions-list input.input-expression',
|
||||
expressionInput: ".expressions-list input.input-expression",
|
||||
expressionNodes: ".expressions-list .tree-node",
|
||||
scopesHeader: ".scopes-pane ._header",
|
||||
breakpointItem: i => `.breakpoints-list .breakpoint:nth-of-type(${i})`,
|
||||
@ -1047,7 +1073,7 @@ const selectors = {
|
||||
`.outline-list__element:nth-child(${i}) .function-signature`,
|
||||
outlineItems: ".outline-list__element",
|
||||
conditionalPanelInput: ".conditional-breakpoint-panel input",
|
||||
searchField: ".search-field",
|
||||
searchField: ".search-field"
|
||||
};
|
||||
|
||||
function getSelector(elementName, ...args) {
|
||||
@ -1168,11 +1194,10 @@ function getScopeValue(dbg, index) {
|
||||
}
|
||||
|
||||
function toggleObjectInspectorNode(node) {
|
||||
|
||||
const objectInspector = node.closest(".object-inspector");
|
||||
const properties = objectInspector.querySelectorAll(".node").length;
|
||||
|
||||
log(`Toggling node ${node.innerText}`)
|
||||
log(`Toggling node ${node.innerText}`);
|
||||
node.click();
|
||||
return waitUntil(
|
||||
() => objectInspector.querySelectorAll(".node").length !== properties
|
||||
@ -1264,7 +1289,7 @@ async function assertPreviewPopup(
|
||||
const properties =
|
||||
preview.result.preview.ownProperties || preview.result.preview.items;
|
||||
const property = properties[field];
|
||||
const propertyValue = property.value || property
|
||||
const propertyValue = property.value || property;
|
||||
|
||||
is(`${propertyValue}`, value, "Preview.result");
|
||||
is(preview.updating, false, "Preview.updating");
|
||||
@ -1294,4 +1319,4 @@ async function assertPreviews(dbg, previews) {
|
||||
|
||||
dbg.actions.clearPreview();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -97,9 +97,9 @@ ignoreExceptionsItem=Ignore exceptions
|
||||
# item shown when a user is adding a new breakpoint.
|
||||
pauseOnUncaughtExceptionsItem=Pause on uncaught exceptions
|
||||
|
||||
# LOCALIZATION NOTE (pauseOnExceptionsItem2): The pause on exceptions checkbox description
|
||||
# LOCALIZATION NOTE (pauseOnExceptionsItem): The pause on exceptions checkbox description
|
||||
# when the debugger will pause on all exceptions.
|
||||
pauseOnExceptionsItem2=Pause on exceptions
|
||||
pauseOnExceptionsItem=Pause on exceptions
|
||||
|
||||
# LOCALIZATION NOTE (ignoreCaughtExceptionsItem): The pause on exceptions checkbox description
|
||||
# when the debugger will not pause on any caught exception
|
||||
|
@ -1612,7 +1612,9 @@ const { nodeIsError, nodeIsPrimitive } = node;
|
||||
const selection = __webpack_require__(3698);
|
||||
|
||||
const { MODE } = __webpack_require__(3645);
|
||||
const { REPS: { Rep, Grip } } = __webpack_require__(3647);
|
||||
const {
|
||||
REPS: { Rep, Grip }
|
||||
} = __webpack_require__(3647);
|
||||
|
||||
|
||||
function shouldRenderRootsInReps(roots) {
|
||||
@ -3084,7 +3086,9 @@ function nodeNeedsNumericalBuckets(item) {
|
||||
}
|
||||
|
||||
function makeNodesForPromiseProperties(item) {
|
||||
const { promiseState: { reason, value, state } } = getValue(item);
|
||||
const {
|
||||
promiseState: { reason, value, state }
|
||||
} = getValue(item);
|
||||
|
||||
const properties = [];
|
||||
|
||||
|
@ -430,7 +430,9 @@ const {
|
||||
isOriginalId
|
||||
} = __webpack_require__(3652);
|
||||
|
||||
const { workerUtils: { WorkerDispatcher } } = __webpack_require__(3651);
|
||||
const {
|
||||
workerUtils: { WorkerDispatcher }
|
||||
} = __webpack_require__(3651);
|
||||
|
||||
const dispatcher = new WorkerDispatcher();
|
||||
|
||||
|
@ -1985,7 +1985,9 @@ const {
|
||||
|
||||
const { clearSourceMaps } = __webpack_require__(3704);
|
||||
|
||||
const { workerUtils: { workerHandler } } = __webpack_require__(3651);
|
||||
const {
|
||||
workerUtils: { workerHandler }
|
||||
} = __webpack_require__(3651);
|
||||
|
||||
// The interface is implemented in source-map to be
|
||||
// easier to unit test.
|
||||
|
@ -134,6 +134,18 @@ static const RedirEntry kRedirMap[] = {
|
||||
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
|
||||
nsIAboutModule::HIDE_FROM_ABOUTABOUT |
|
||||
nsIAboutModule::URI_CAN_LOAD_IN_CHILD
|
||||
},
|
||||
{
|
||||
"crashparent", "about:blank",
|
||||
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
|
||||
nsIAboutModule::HIDE_FROM_ABOUTABOUT
|
||||
},
|
||||
{
|
||||
"crashcontent", "about:blank",
|
||||
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
|
||||
nsIAboutModule::HIDE_FROM_ABOUTABOUT |
|
||||
nsIAboutModule::URI_CAN_LOAD_IN_CHILD |
|
||||
nsIAboutModule::URI_MUST_LOAD_IN_CHILD
|
||||
}
|
||||
};
|
||||
static const int kRedirTotal = mozilla::ArrayLength(kRedirMap);
|
||||
@ -154,6 +166,14 @@ nsAboutRedirector::NewChannel(nsIURI* aURI,
|
||||
nsCOMPtr<nsIIOService> ioService = do_GetIOService(&rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (XRE_IsParentProcess() && path.EqualsASCII("crashparent")) {
|
||||
MOZ_CRASH("Crash via about:crashparent");
|
||||
}
|
||||
|
||||
if (XRE_IsContentProcess() && path.EqualsASCII("crashcontent")) {
|
||||
MOZ_CRASH("Crash via about:crashcontent");
|
||||
}
|
||||
|
||||
for (int i = 0; i < kRedirTotal; i++) {
|
||||
if (!strcmp(path.get(), kRedirMap[i].id)) {
|
||||
nsCOMPtr<nsIChannel> tempChannel;
|
||||
|
@ -178,6 +178,8 @@ const mozilla::Module::ContractIDEntry kDocShellContracts[] = {
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "crashes", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
|
||||
#endif
|
||||
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "crashparent", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
|
||||
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "crashcontent", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
|
||||
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "credits", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
|
||||
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "license", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
|
||||
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "logo", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
|
||||
|
@ -246,18 +246,6 @@ nsSHEntryShared::GetID(uint64_t* aID)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsSHEntryShared::NodeWillBeDestroyed(const nsINode* aNode)
|
||||
{
|
||||
NS_NOTREACHED("Document destroyed while we're holding a strong ref to it");
|
||||
}
|
||||
|
||||
void
|
||||
nsSHEntryShared::CharacterDataWillChange(nsIContent* aContent,
|
||||
const CharacterDataChangeInfo&)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
nsSHEntryShared::CharacterDataChanged(nsIContent* aContent,
|
||||
const CharacterDataChangeInfo&)
|
||||
@ -265,21 +253,6 @@ nsSHEntryShared::CharacterDataChanged(nsIContent* aContent,
|
||||
RemoveFromBFCacheAsync();
|
||||
}
|
||||
|
||||
void
|
||||
nsSHEntryShared::AttributeWillChange(dom::Element* aContent,
|
||||
int32_t aNameSpaceID,
|
||||
nsAtom* aAttribute,
|
||||
int32_t aModType,
|
||||
const nsAttrValue* aNewValue)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
nsSHEntryShared::NativeAnonymousChildListChange(nsIContent* aContent,
|
||||
bool aIsRemove)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
nsSHEntryShared::AttributeChanged(dom::Element* aElement,
|
||||
int32_t aNameSpaceID,
|
||||
@ -308,8 +281,3 @@ nsSHEntryShared::ContentRemoved(nsIContent* aChild,
|
||||
{
|
||||
RemoveFromBFCacheAsync();
|
||||
}
|
||||
|
||||
void
|
||||
nsSHEntryShared::ParentChainChanged(nsIContent* aContent)
|
||||
{
|
||||
}
|
||||
|
@ -12,9 +12,9 @@
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsExpirationTracker.h"
|
||||
#include "nsIBFCacheEntry.h"
|
||||
#include "nsIMutationObserver.h"
|
||||
#include "nsRect.h"
|
||||
#include "nsString.h"
|
||||
#include "nsStubMutationObserver.h"
|
||||
#include "nsWeakPtr.h"
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
@ -36,7 +36,7 @@ class nsIMutableArray;
|
||||
// nsSHEntryShared is the vehicle for this sharing.
|
||||
class nsSHEntryShared final
|
||||
: public nsIBFCacheEntry
|
||||
, public nsIMutationObserver
|
||||
, public nsStubMutationObserver
|
||||
{
|
||||
public:
|
||||
static void EnsureHistoryTracker();
|
||||
@ -45,9 +45,15 @@ public:
|
||||
nsSHEntryShared();
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIMUTATIONOBSERVER
|
||||
NS_DECL_NSIBFCACHEENTRY
|
||||
|
||||
// The nsIMutationObserver bits we actually care about.
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED
|
||||
NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
|
||||
|
||||
nsExpirationState *GetExpirationState() { return &mExpirationState; }
|
||||
|
||||
private:
|
||||
|
@ -565,7 +565,7 @@ CandidateFinder::OrderedCandidates()
|
||||
|
||||
nsTArray<nsCOMPtr<Element>> orderedElements(mCandidates.Count());
|
||||
for (Element* child = mDoc->GetFirstElementChild(); child; child = child->GetNextElementSibling()) {
|
||||
if (!Traverse(child->AsElement(), orderedElements)) {
|
||||
if (!Traverse(child, orderedElements)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -648,59 +648,18 @@ CustomElementRegistry::GetDocGroup() const
|
||||
return mWindow ? mWindow->GetDocGroup() : nullptr;
|
||||
}
|
||||
|
||||
static const char* kLifeCycleCallbackNames[] = {
|
||||
"connectedCallback",
|
||||
"disconnectedCallback",
|
||||
"adoptedCallback",
|
||||
"attributeChangedCallback"
|
||||
};
|
||||
|
||||
static void
|
||||
CheckLifeCycleCallbacks(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aConstructor,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
for (size_t i = 0; i < ArrayLength(kLifeCycleCallbackNames); ++i) {
|
||||
const char* callbackName = kLifeCycleCallbackNames[i];
|
||||
JS::Rooted<JS::Value> callbackValue(aCx);
|
||||
if (!JS_GetProperty(aCx, aConstructor, callbackName, &callbackValue)) {
|
||||
aRv.StealExceptionFromJSContext(aCx);
|
||||
return;
|
||||
}
|
||||
if (!callbackValue.isUndefined()) {
|
||||
if (!callbackValue.isObject()) {
|
||||
aRv.ThrowTypeError<MSG_NOT_OBJECT>(NS_ConvertASCIItoUTF16(callbackName));
|
||||
return;
|
||||
}
|
||||
JS::Rooted<JSObject*> callback(aCx, &callbackValue.toObject());
|
||||
if (!JS::IsCallable(callback)) {
|
||||
aRv.ThrowTypeError<MSG_NOT_CALLABLE>(NS_ConvertASCIItoUTF16(callbackName));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/scripting.html#element-definition
|
||||
void
|
||||
CustomElementRegistry::Define(const nsAString& aName,
|
||||
CustomElementRegistry::Define(JSContext* aCx,
|
||||
const nsAString& aName,
|
||||
Function& aFunctionConstructor,
|
||||
const ElementDefinitionOptions& aOptions,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
aRv.MightThrowJSException();
|
||||
|
||||
AutoJSAPI jsapi;
|
||||
if (NS_WARN_IF(!jsapi.Init(mWindow))) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
|
||||
JSContext *cx = jsapi.cx();
|
||||
// Note: No calls that might run JS or trigger CC before this point, or
|
||||
// there's a (vanishingly small) chance of our constructor being nulled
|
||||
// before we access it.
|
||||
JS::Rooted<JSObject*> constructor(cx, aFunctionConstructor.CallableOrNull());
|
||||
JS::Rooted<JSObject*> constructor(aCx, aFunctionConstructor.CallableOrNull());
|
||||
|
||||
/**
|
||||
* 1. If IsConstructor(constructor) is false, then throw a TypeError and abort
|
||||
@ -708,7 +667,7 @@ CustomElementRegistry::Define(const nsAString& aName,
|
||||
*/
|
||||
// For now, all wrappers are constructable if they are callable. So we need to
|
||||
// unwrap constructor to check it is really constructable.
|
||||
JS::Rooted<JSObject*> constructorUnwrapped(cx, js::CheckedUnwrap(constructor));
|
||||
JS::Rooted<JSObject*> constructorUnwrapped(aCx, js::CheckedUnwrap(constructor));
|
||||
if (!constructorUnwrapped) {
|
||||
// If the caller's compartment does not have permission to access the
|
||||
// unwrapped constructor then throw.
|
||||
@ -816,8 +775,7 @@ CustomElementRegistry::Define(const nsAString& aName,
|
||||
return;
|
||||
}
|
||||
|
||||
JS::Rooted<JS::Value> constructorPrototype(cx);
|
||||
nsAutoPtr<LifecycleCallbacks> callbacksHolder(new LifecycleCallbacks());
|
||||
auto callbacksHolder = MakeUnique<LifecycleCallbacks>();
|
||||
nsTArray<RefPtr<nsAtom>> observedAttributes;
|
||||
{ // Set mIsCustomDefinitionRunning.
|
||||
/**
|
||||
@ -825,131 +783,105 @@ CustomElementRegistry::Define(const nsAString& aName,
|
||||
*/
|
||||
AutoSetRunningFlag as(this);
|
||||
|
||||
{ // Enter constructor's realm.
|
||||
/**
|
||||
* 10.1. Let prototype be Get(constructor, "prototype"). Rethrow any exceptions.
|
||||
*/
|
||||
JSAutoRealm ar(cx, constructor);
|
||||
// The .prototype on the constructor passed could be an "expando" of a
|
||||
// wrapper. So we should get it from wrapper instead of the underlying
|
||||
// object.
|
||||
if (!JS_GetProperty(cx, constructor, "prototype", &constructorPrototype)) {
|
||||
aRv.StealExceptionFromJSContext(cx);
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* 10.2. If Type(prototype) is not Object, then throw a TypeError exception.
|
||||
*/
|
||||
if (!constructorPrototype.isObject()) {
|
||||
aRv.ThrowTypeError<MSG_NOT_OBJECT>(NS_LITERAL_STRING("constructor.prototype"));
|
||||
return;
|
||||
}
|
||||
} // Leave constructor's realm.
|
||||
|
||||
JS::Rooted<JSObject*> constructorProtoUnwrapped(
|
||||
cx, js::CheckedUnwrap(&constructorPrototype.toObject()));
|
||||
if (!constructorProtoUnwrapped) {
|
||||
// If the caller's compartment does not have permission to access the
|
||||
// unwrapped prototype then throw.
|
||||
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
|
||||
/**
|
||||
* 10.1. Let prototype be Get(constructor, "prototype"). Rethrow any exceptions.
|
||||
*/
|
||||
// The .prototype on the constructor passed could be an "expando" of a
|
||||
// wrapper. So we should get it from wrapper instead of the underlying
|
||||
// object.
|
||||
JS::Rooted<JS::Value> prototype(aCx);
|
||||
if (!JS_GetProperty(aCx, constructor, "prototype", &prototype)) {
|
||||
aRv.NoteJSContextException(aCx);
|
||||
return;
|
||||
}
|
||||
|
||||
{ // Enter constructorProtoUnwrapped's compartment
|
||||
JSAutoRealm ar(cx, constructorProtoUnwrapped);
|
||||
/**
|
||||
* 10.2. If Type(prototype) is not Object, then throw a TypeError exception.
|
||||
*/
|
||||
if (!prototype.isObject()) {
|
||||
aRv.ThrowTypeError<MSG_NOT_OBJECT>(NS_LITERAL_STRING("constructor.prototype"));
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* 10.3. Let lifecycleCallbacks be a map with the four keys
|
||||
* "connectedCallback", "disconnectedCallback", "adoptedCallback", and
|
||||
* "attributeChangedCallback", each of which belongs to an entry whose
|
||||
* value is null.
|
||||
* 10.4. For each of the four keys callbackName in lifecycleCallbacks:
|
||||
* 1. Let callbackValue be Get(prototype, callbackName). Rethrow any
|
||||
* exceptions.
|
||||
* 2. If callbackValue is not undefined, then set the value of the
|
||||
* entry in lifecycleCallbacks with key callbackName to the result
|
||||
* of converting callbackValue to the Web IDL Function callback type.
|
||||
* Rethrow any exceptions from the conversion.
|
||||
*/
|
||||
// Will do the same checking for the life cycle callbacks from v0 spec.
|
||||
CheckLifeCycleCallbacks(cx, constructorProtoUnwrapped, aRv);
|
||||
if (aRv.Failed()) {
|
||||
/**
|
||||
* 10.3. Let lifecycleCallbacks be a map with the four keys
|
||||
* "connectedCallback", "disconnectedCallback", "adoptedCallback", and
|
||||
* "attributeChangedCallback", each of which belongs to an entry whose
|
||||
* value is null.
|
||||
* 10.4. For each of the four keys callbackName in lifecycleCallbacks:
|
||||
* 1. Let callbackValue be Get(prototype, callbackName). Rethrow any
|
||||
* exceptions.
|
||||
* 2. If callbackValue is not undefined, then set the value of the
|
||||
* entry in lifecycleCallbacks with key callbackName to the result
|
||||
* of converting callbackValue to the Web IDL Function callback type.
|
||||
* Rethrow any exceptions from the conversion.
|
||||
*/
|
||||
if (!callbacksHolder->Init(aCx, prototype)) {
|
||||
aRv.NoteJSContextException(aCx);
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* 10.5. Let observedAttributes be an empty sequence<DOMString>.
|
||||
* 10.6. If the value of the entry in lifecycleCallbacks with key
|
||||
* "attributeChangedCallback" is not null, then:
|
||||
* 1. Let observedAttributesIterable be Get(constructor,
|
||||
* "observedAttributes"). Rethrow any exceptions.
|
||||
* 2. If observedAttributesIterable is not undefined, then set
|
||||
* observedAttributes to the result of converting
|
||||
* observedAttributesIterable to a sequence<DOMString>. Rethrow
|
||||
* any exceptions from the conversion.
|
||||
*/
|
||||
if (callbacksHolder->mAttributeChangedCallback.WasPassed()) {
|
||||
JS::Rooted<JS::Value> observedAttributesIterable(aCx);
|
||||
|
||||
if (!JS_GetProperty(aCx, constructor, "observedAttributes",
|
||||
&observedAttributesIterable)) {
|
||||
aRv.NoteJSContextException(aCx);
|
||||
return;
|
||||
}
|
||||
|
||||
// Note: We call the init from the constructorProtoUnwrapped's compartment
|
||||
// here.
|
||||
JS::RootedValue rootedv(cx, JS::ObjectValue(*constructorProtoUnwrapped));
|
||||
if (!JS_WrapValue(cx, &rootedv) || !callbacksHolder->Init(cx, rootedv)) {
|
||||
aRv.StealExceptionFromJSContext(cx);
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* 10.5. Let observedAttributes be an empty sequence<DOMString>.
|
||||
* 10.6. If the value of the entry in lifecycleCallbacks with key
|
||||
* "attributeChangedCallback" is not null, then:
|
||||
* 1. Let observedAttributesIterable be Get(constructor,
|
||||
* "observedAttributes"). Rethrow any exceptions.
|
||||
* 2. If observedAttributesIterable is not undefined, then set
|
||||
* observedAttributes to the result of converting
|
||||
* observedAttributesIterable to a sequence<DOMString>. Rethrow
|
||||
* any exceptions from the conversion.
|
||||
*/
|
||||
if (callbacksHolder->mAttributeChangedCallback.WasPassed()) {
|
||||
// Enter constructor's realm.
|
||||
JSAutoRealm ar(cx, constructor);
|
||||
JS::Rooted<JS::Value> observedAttributesIterable(cx);
|
||||
|
||||
if (!JS_GetProperty(cx, constructor, "observedAttributes",
|
||||
&observedAttributesIterable)) {
|
||||
aRv.StealExceptionFromJSContext(cx);
|
||||
if (!observedAttributesIterable.isUndefined()) {
|
||||
if (!observedAttributesIterable.isObject()) {
|
||||
aRv.ThrowTypeError<MSG_NOT_SEQUENCE>(NS_LITERAL_STRING("observedAttributes"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!observedAttributesIterable.isUndefined()) {
|
||||
if (!observedAttributesIterable.isObject()) {
|
||||
aRv.ThrowTypeError<MSG_NOT_SEQUENCE>(NS_LITERAL_STRING("observedAttributes"));
|
||||
JS::ForOfIterator iter(aCx);
|
||||
if (!iter.init(observedAttributesIterable, JS::ForOfIterator::AllowNonIterable)) {
|
||||
aRv.NoteJSContextException(aCx);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!iter.valueIsIterable()) {
|
||||
aRv.ThrowTypeError<MSG_NOT_SEQUENCE>(NS_LITERAL_STRING("observedAttributes"));
|
||||
return;
|
||||
}
|
||||
|
||||
JS::Rooted<JS::Value> attribute(aCx);
|
||||
while (true) {
|
||||
bool done;
|
||||
if (!iter.next(&attribute, &done)) {
|
||||
aRv.NoteJSContextException(aCx);
|
||||
return;
|
||||
}
|
||||
if (done) {
|
||||
break;
|
||||
}
|
||||
|
||||
nsAutoString attrStr;
|
||||
if (!ConvertJSValueToString(aCx, attribute, eStringify, eStringify, attrStr)) {
|
||||
aRv.NoteJSContextException(aCx);
|
||||
return;
|
||||
}
|
||||
|
||||
JS::ForOfIterator iter(cx);
|
||||
if (!iter.init(observedAttributesIterable, JS::ForOfIterator::AllowNonIterable)) {
|
||||
aRv.StealExceptionFromJSContext(cx);
|
||||
if (!observedAttributes.AppendElement(NS_Atomize(attrStr))) {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!iter.valueIsIterable()) {
|
||||
aRv.ThrowTypeError<MSG_NOT_SEQUENCE>(NS_LITERAL_STRING("observedAttributes"));
|
||||
return;
|
||||
}
|
||||
|
||||
JS::Rooted<JS::Value> attribute(cx);
|
||||
while (true) {
|
||||
bool done;
|
||||
if (!iter.next(&attribute, &done)) {
|
||||
aRv.StealExceptionFromJSContext(cx);
|
||||
return;
|
||||
}
|
||||
if (done) {
|
||||
break;
|
||||
}
|
||||
|
||||
nsAutoString attrStr;
|
||||
if (!ConvertJSValueToString(cx, attribute, eStringify, eStringify, attrStr)) {
|
||||
aRv.StealExceptionFromJSContext(cx);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!observedAttributes.AppendElement(NS_Atomize(attrStr))) {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // Leave constructor's realm.
|
||||
} // Leave constructorProtoUnwrapped's compartment.
|
||||
}
|
||||
}
|
||||
} // Unset mIsCustomDefinitionRunning
|
||||
|
||||
/**
|
||||
@ -960,7 +892,6 @@ CustomElementRegistry::Define(const nsAString& aName,
|
||||
*/
|
||||
// Associate the definition with the custom element.
|
||||
RefPtr<nsAtom> localNameAtom(NS_Atomize(localName));
|
||||
LifecycleCallbacks* callbacks = callbacksHolder.forget();
|
||||
|
||||
/**
|
||||
* 12. Add definition to this CustomElementRegistry.
|
||||
@ -975,7 +906,7 @@ CustomElementRegistry::Define(const nsAString& aName,
|
||||
localNameAtom,
|
||||
&aFunctionConstructor,
|
||||
Move(observedAttributes),
|
||||
callbacks);
|
||||
Move(callbacksHolder));
|
||||
|
||||
CustomElementDefinition* def = definition.get();
|
||||
mCustomDefinitions.Put(nameAtom, definition.forget());
|
||||
@ -1392,12 +1323,12 @@ CustomElementDefinition::CustomElementDefinition(nsAtom* aType,
|
||||
nsAtom* aLocalName,
|
||||
Function* aConstructor,
|
||||
nsTArray<RefPtr<nsAtom>>&& aObservedAttributes,
|
||||
LifecycleCallbacks* aCallbacks)
|
||||
UniquePtr<LifecycleCallbacks>&& aCallbacks)
|
||||
: mType(aType),
|
||||
mLocalName(aLocalName),
|
||||
mConstructor(new CustomElementConstructor(aConstructor)),
|
||||
mObservedAttributes(Move(aObservedAttributes)),
|
||||
mCallbacks(aCallbacks)
|
||||
mCallbacks(Move(aCallbacks))
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -152,7 +152,7 @@ struct CustomElementDefinition
|
||||
nsAtom* aLocalName,
|
||||
Function* aConstructor,
|
||||
nsTArray<RefPtr<nsAtom>>&& aObservedAttributes,
|
||||
mozilla::dom::LifecycleCallbacks* aCallbacks);
|
||||
UniquePtr<LifecycleCallbacks>&& aCallbacks);
|
||||
|
||||
// The type (name) for this custom element, for <button is="x-foo"> or <x-foo>
|
||||
// this would be x-foo.
|
||||
@ -168,7 +168,7 @@ struct CustomElementDefinition
|
||||
nsTArray<RefPtr<nsAtom>> mObservedAttributes;
|
||||
|
||||
// The lifecycle callbacks to call for this custom element.
|
||||
UniquePtr<mozilla::dom::LifecycleCallbacks> mCallbacks;
|
||||
UniquePtr<LifecycleCallbacks> mCallbacks;
|
||||
|
||||
// A construction stack. Use nullptr to represent an "already constructed marker".
|
||||
nsTArray<RefPtr<Element>> mConstructionStack;
|
||||
@ -510,7 +510,8 @@ public:
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
void Define(const nsAString& aName, Function& aFunctionConstructor,
|
||||
void Define(JSContext* aCx, const nsAString& aName,
|
||||
Function& aFunctionConstructor,
|
||||
const ElementDefinitionOptions& aOptions, ErrorResult& aRv);
|
||||
|
||||
void Get(JSContext* cx, const nsAString& name,
|
||||
|
@ -509,7 +509,6 @@ private:
|
||||
|
||||
static nsCheapSetOperator SetNodeDirection(nsPtrHashKey<Element>* aEntry, void* aDir)
|
||||
{
|
||||
MOZ_ASSERT(aEntry->GetKey()->IsElement(), "Must be an Element");
|
||||
aEntry->GetKey()->SetDirectionality(*reinterpret_cast<Directionality*>(aDir),
|
||||
true);
|
||||
return OpNext;
|
||||
@ -523,7 +522,6 @@ private:
|
||||
|
||||
static nsCheapSetOperator ResetNodeDirection(nsPtrHashKey<Element>* aEntry, void* aData)
|
||||
{
|
||||
MOZ_ASSERT(aEntry->GetKey()->IsElement(), "Must be an Element");
|
||||
// run the downward propagation algorithm
|
||||
// and remove the text node from the map
|
||||
nsTextNodeDirectionalityMapAndElement* data =
|
||||
|
@ -1964,6 +1964,10 @@ private:
|
||||
nsIScrollableFrame* GetScrollFrame(nsIFrame **aStyledFrame = nullptr,
|
||||
FlushType aFlushType = FlushType::Layout);
|
||||
|
||||
// Prevent people from doing pointless checks/casts on Element instances.
|
||||
void IsElement() = delete;
|
||||
void AsElement() = delete;
|
||||
|
||||
// Data members
|
||||
EventStates mState;
|
||||
// Per-node data managed by Servo.
|
||||
|
@ -7996,6 +7996,10 @@ nsIDocument::CollectDescendantDocuments(
|
||||
bool
|
||||
nsIDocument::CanSavePresentation(nsIRequest *aNewRequest)
|
||||
{
|
||||
if (!IsBFCachingAllowed()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (EventHandlingSuppressed()) {
|
||||
return false;
|
||||
}
|
||||
@ -11259,7 +11263,7 @@ nsIDocument::ApplyFullscreen(const FullscreenRequest& aRequest)
|
||||
break;
|
||||
}
|
||||
nsIDocument* parent = child->GetParentDocument();
|
||||
Element* element = parent->FindContentForSubDocument(child)->AsElement();
|
||||
Element* element = parent->FindContentForSubDocument(child);
|
||||
if (static_cast<nsDocument*>(parent)->FullScreenStackPush(element)) {
|
||||
changed.AppendElement(parent);
|
||||
child = parent;
|
||||
|
@ -210,6 +210,10 @@ DOMInterfaces = {
|
||||
'binaryNames': { 'ownerRule': 'DOMOwnerRule' },
|
||||
},
|
||||
|
||||
'CustomElementRegistry': {
|
||||
'implicitJSContext': ['define'],
|
||||
},
|
||||
|
||||
'DedicatedWorkerGlobalScope': {
|
||||
'headerFile': 'mozilla/dom/WorkerScope.h',
|
||||
},
|
||||
|
@ -534,7 +534,7 @@ HTMLSelectElement::GetFirstOptionIndex(nsIContent* aOptions)
|
||||
int32_t listIndex = -1;
|
||||
HTMLOptionElement* optElement = HTMLOptionElement::FromNode(aOptions);
|
||||
if (optElement) {
|
||||
mOptions->GetOptionIndex(optElement->AsElement(), 0, true, &listIndex);
|
||||
mOptions->GetOptionIndex(optElement, 0, true, &listIndex);
|
||||
return listIndex;
|
||||
}
|
||||
|
||||
|
@ -156,7 +156,7 @@ protected:
|
||||
nsTObserverArray<PerformanceObserver*> mObservers;
|
||||
|
||||
protected:
|
||||
static const uint64_t kDefaultResourceTimingBufferSize = 150;
|
||||
static const uint64_t kDefaultResourceTimingBufferSize = 250;
|
||||
|
||||
// When kDefaultResourceTimingBufferSize is increased or removed, these should
|
||||
// be changed to use SegmentedVector
|
||||
|
@ -86,6 +86,8 @@ static decltype(ImmAssociateContextEx)* sImm32ImmAssociateContextExStub =
|
||||
nullptr;
|
||||
static PluginInstanceChild* sCurrentPluginInstance = nullptr;
|
||||
static const HIMC sHookIMC = (const HIMC)0xefefefef;
|
||||
static bool sPopupMenuHookSet;
|
||||
static bool sSetWindowLongHookSet;
|
||||
|
||||
using mozilla::gfx::SharedDIB;
|
||||
|
||||
@ -1897,8 +1899,15 @@ PluginInstanceChild::SetWindowLongWHook(HWND hWnd,
|
||||
void
|
||||
PluginInstanceChild::HookSetWindowLongPtr()
|
||||
{
|
||||
if (!(GetQuirks() & QUIRK_FLASH_HOOK_SETLONGPTR))
|
||||
if (!(GetQuirks() & QUIRK_FLASH_HOOK_SETLONGPTR)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Only pass through here once
|
||||
if (sSetWindowLongHookSet) {
|
||||
return;
|
||||
}
|
||||
sSetWindowLongHookSet = true;
|
||||
|
||||
sUser32Intercept.Init("user32.dll");
|
||||
#ifdef _WIN64
|
||||
@ -1978,19 +1987,23 @@ PluginInstanceChild::TrackPopupHookProc(HMENU hMenu,
|
||||
void
|
||||
PluginInstanceChild::InitPopupMenuHook()
|
||||
{
|
||||
if (!(GetQuirks() & QUIRK_WINLESS_TRACKPOPUP_HOOK) ||
|
||||
sUser32TrackPopupMenuStub)
|
||||
if (!(GetQuirks() & QUIRK_WINLESS_TRACKPOPUP_HOOK)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Only pass through here once
|
||||
if (sPopupMenuHookSet) {
|
||||
return;
|
||||
}
|
||||
sPopupMenuHookSet = true;
|
||||
|
||||
// Note, once WindowsDllInterceptor is initialized for a module,
|
||||
// it remains initialized for that particular module for it's
|
||||
// lifetime. Additional instances are needed if other modules need
|
||||
// to be hooked.
|
||||
if (!sUser32TrackPopupMenuStub) {
|
||||
sUser32Intercept.Init("user32.dll");
|
||||
sUser32Intercept.AddHook("TrackPopupMenu", reinterpret_cast<intptr_t>(TrackPopupHookProc),
|
||||
(void**) &sUser32TrackPopupMenuStub);
|
||||
}
|
||||
sUser32Intercept.Init("user32.dll");
|
||||
sUser32Intercept.AddHook("TrackPopupMenu", reinterpret_cast<intptr_t>(TrackPopupHookProc),
|
||||
(void**) &sUser32TrackPopupMenuStub);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -20,8 +20,8 @@ callback LifecycleAttributeChangedCallback = void(DOMString attrName,
|
||||
DOMString? namespaceURI);
|
||||
|
||||
dictionary LifecycleCallbacks {
|
||||
LifecycleConnectedCallback? connectedCallback;
|
||||
LifecycleDisconnectedCallback? disconnectedCallback;
|
||||
LifecycleAdoptedCallback? adoptedCallback;
|
||||
LifecycleAttributeChangedCallback? attributeChangedCallback;
|
||||
LifecycleConnectedCallback connectedCallback;
|
||||
LifecycleDisconnectedCallback disconnectedCallback;
|
||||
LifecycleAdoptedCallback adoptedCallback;
|
||||
LifecycleAttributeChangedCallback attributeChangedCallback;
|
||||
};
|
||||
|
@ -5125,7 +5125,7 @@ HTMLEditRules::ConvertListType(Element* aList,
|
||||
}
|
||||
|
||||
if (aList->IsHTMLElement(aListType)) {
|
||||
RefPtr<dom::Element> list = aList->AsElement();
|
||||
RefPtr<dom::Element> list = aList;
|
||||
return list.forget();
|
||||
}
|
||||
|
||||
@ -7407,7 +7407,7 @@ HTMLEditRules::SplitParagraph(
|
||||
}
|
||||
|
||||
// Remove ID attribute on the paragraph from the existing right node.
|
||||
rv = htmlEditor->RemoveAttributeWithTransaction(*aParentDivOrP.AsElement(),
|
||||
rv = htmlEditor->RemoveAttributeWithTransaction(aParentDivOrP,
|
||||
*nsGkAtoms::id);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
|
@ -7,7 +7,6 @@
|
||||
#ifndef js_HashTable_h
|
||||
#define js_HashTable_h
|
||||
|
||||
#include "mozilla/Alignment.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/Casting.h"
|
||||
@ -30,7 +29,7 @@ class TempAllocPolicy;
|
||||
template <class> struct DefaultHasher;
|
||||
template <class, class> class HashMapEntry;
|
||||
namespace detail {
|
||||
template <class T> class HashTableEntry;
|
||||
template <typename T> class HashTableEntry;
|
||||
template <class T, class HashPolicy, class AllocPolicy> class HashTable;
|
||||
} // namespace detail
|
||||
|
||||
@ -773,9 +772,6 @@ class HashMapEntry
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
template <typename T>
|
||||
struct IsPod<js::detail::HashTableEntry<T> > : IsPod<T> {};
|
||||
|
||||
template <typename K, typename V>
|
||||
struct IsPod<js::HashMapEntry<K, V> >
|
||||
: IntegralConstant<bool, IsPod<K>::value && IsPod<V>::value>
|
||||
@ -790,19 +786,28 @@ namespace detail {
|
||||
template <class T, class HashPolicy, class AllocPolicy>
|
||||
class HashTable;
|
||||
|
||||
template <class T>
|
||||
template <typename T>
|
||||
class HashTableEntry
|
||||
{
|
||||
template <class, class, class> friend class HashTable;
|
||||
typedef typename mozilla::RemoveConst<T>::Type NonConstT;
|
||||
|
||||
HashNumber keyHash;
|
||||
mozilla::AlignedStorage2<NonConstT> mem;
|
||||
private:
|
||||
using NonConstT = typename mozilla::RemoveConst<T>::Type;
|
||||
|
||||
static const HashNumber sFreeKey = 0;
|
||||
static const HashNumber sRemovedKey = 1;
|
||||
static const HashNumber sCollisionBit = 1;
|
||||
|
||||
HashNumber keyHash = sFreeKey;
|
||||
alignas(NonConstT) unsigned char valueData_[sizeof(NonConstT)];
|
||||
|
||||
private:
|
||||
template <class, class, class> friend class HashTable;
|
||||
|
||||
// Some versions of GCC treat it as a -Wstrict-aliasing violation (ergo a
|
||||
// -Werror compile error) to reinterpret_cast<> |valueData_| to |T*|, even
|
||||
// through |void*|. Placing the latter cast in these separate functions
|
||||
// breaks the chain such that affected GCC versions no longer warn/error.
|
||||
void* rawValuePtr() { return valueData_; }
|
||||
|
||||
static bool isLiveHash(HashNumber hash)
|
||||
{
|
||||
return hash > sRemovedKey;
|
||||
@ -810,19 +815,23 @@ class HashTableEntry
|
||||
|
||||
HashTableEntry(const HashTableEntry&) = delete;
|
||||
void operator=(const HashTableEntry&) = delete;
|
||||
~HashTableEntry() = delete;
|
||||
|
||||
NonConstT* valuePtr() { return reinterpret_cast<NonConstT*>(rawValuePtr()); }
|
||||
|
||||
void destroyStoredT() {
|
||||
mem.addr()->~T();
|
||||
MOZ_MAKE_MEM_UNDEFINED(mem.addr(), sizeof(*mem.addr()));
|
||||
NonConstT* ptr = valuePtr();
|
||||
ptr->~T();
|
||||
MOZ_MAKE_MEM_UNDEFINED(ptr, sizeof(*ptr));
|
||||
}
|
||||
|
||||
public:
|
||||
// NB: HashTableEntry is treated as a POD: no constructor or destructor calls.
|
||||
HashTableEntry() = default;
|
||||
|
||||
void destroyIfLive() {
|
||||
~HashTableEntry() {
|
||||
if (isLive())
|
||||
destroyStoredT();
|
||||
|
||||
MOZ_MAKE_MEM_UNDEFINED(this, sizeof(*this));
|
||||
}
|
||||
|
||||
void destroy() {
|
||||
@ -835,9 +844,9 @@ class HashTableEntry
|
||||
return;
|
||||
MOZ_ASSERT(isLive());
|
||||
if (other->isLive()) {
|
||||
mozilla::Swap(*mem.addr(), *other->mem.addr());
|
||||
mozilla::Swap(*valuePtr(), *other->valuePtr());
|
||||
} else {
|
||||
*other->mem.addr() = mozilla::Move(*mem.addr());
|
||||
*other->valuePtr() = mozilla::Move(*valuePtr());
|
||||
destroy();
|
||||
}
|
||||
mozilla::Swap(keyHash, other->keyHash);
|
||||
@ -845,12 +854,12 @@ class HashTableEntry
|
||||
|
||||
T& get() {
|
||||
MOZ_ASSERT(isLive());
|
||||
return *mem.addr();
|
||||
return *valuePtr();
|
||||
}
|
||||
|
||||
NonConstT& getMutable() {
|
||||
MOZ_ASSERT(isLive());
|
||||
return *mem.addr();
|
||||
return *valuePtr();
|
||||
}
|
||||
|
||||
bool isFree() const {
|
||||
@ -911,7 +920,7 @@ class HashTableEntry
|
||||
{
|
||||
MOZ_ASSERT(!isLive());
|
||||
keyHash = hn;
|
||||
new(mem.addr()) T(mozilla::Forward<Args>(args)...);
|
||||
new (valuePtr()) T(mozilla::Forward<Args>(args)...);
|
||||
MOZ_ASSERT(isLive());
|
||||
}
|
||||
};
|
||||
@ -926,7 +935,7 @@ class HashTable : private AllocPolicy
|
||||
typedef typename HashPolicy::Lookup Lookup;
|
||||
|
||||
public:
|
||||
typedef HashTableEntry<T> Entry;
|
||||
using Entry = HashTableEntry<T>;
|
||||
|
||||
// A nullable pointer to a hash table element. A Ptr |p| can be tested
|
||||
// either explicitly |if (p.found()) p->...| or using boolean conversion
|
||||
@ -1285,26 +1294,31 @@ class HashTable : private AllocPolicy
|
||||
static Entry* createTable(AllocPolicy& alloc, uint32_t capacity,
|
||||
FailureBehavior reportFailure = ReportFailure)
|
||||
{
|
||||
static_assert(sFreeKey == 0,
|
||||
"newly-calloc'd tables have to be considered empty");
|
||||
if (reportFailure)
|
||||
return alloc.template pod_calloc<Entry>(capacity);
|
||||
|
||||
return alloc.template maybe_pod_calloc<Entry>(capacity);
|
||||
Entry* table = reportFailure
|
||||
? alloc.template pod_malloc<Entry>(capacity)
|
||||
: alloc.template maybe_pod_malloc<Entry>(capacity);
|
||||
if (table) {
|
||||
for (uint32_t i = 0; i < capacity; i++)
|
||||
new (&table[i]) Entry();
|
||||
}
|
||||
return table;
|
||||
}
|
||||
|
||||
static Entry* maybeCreateTable(AllocPolicy& alloc, uint32_t capacity)
|
||||
{
|
||||
static_assert(sFreeKey == 0,
|
||||
"newly-calloc'd tables have to be considered empty");
|
||||
return alloc.template maybe_pod_calloc<Entry>(capacity);
|
||||
Entry* table = alloc.template maybe_pod_malloc<Entry>(capacity);
|
||||
if (table) {
|
||||
for (uint32_t i = 0; i < capacity; i++)
|
||||
new (&table[i]) Entry();
|
||||
}
|
||||
return table;
|
||||
}
|
||||
|
||||
static void destroyTable(AllocPolicy& alloc, Entry* oldTable, uint32_t capacity)
|
||||
{
|
||||
Entry* end = oldTable + capacity;
|
||||
for (Entry* e = oldTable; e < end; ++e)
|
||||
e->destroyIfLive();
|
||||
e->~Entry();
|
||||
alloc.free_(oldTable);
|
||||
}
|
||||
|
||||
@ -1567,8 +1581,9 @@ class HashTable : private AllocPolicy
|
||||
HashNumber hn = src->getKeyHash();
|
||||
findFreeEntry(hn).setLive(
|
||||
hn, mozilla::Move(const_cast<typename Entry::NonConstT&>(src->get())));
|
||||
src->destroy();
|
||||
}
|
||||
|
||||
src->~Entry();
|
||||
}
|
||||
|
||||
// All entries have been destroyed, no need to destroyTable.
|
||||
|
@ -6,6 +6,8 @@
|
||||
|
||||
#include "ds/Bitmap.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
using namespace js;
|
||||
|
||||
SparseBitmap::~SparseBitmap()
|
||||
@ -33,7 +35,7 @@ SparseBitmap::createBlock(Data::AddPtr p, size_t blockId)
|
||||
BitBlock* block = js_new<BitBlock>();
|
||||
if (!block || !data.add(p, blockId, block))
|
||||
oomUnsafe.crash("Bitmap OOM");
|
||||
PodZero(block);
|
||||
std::fill(block->begin(), block->end(), 0);
|
||||
return *block;
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,14 @@
|
||||
#ifndef ds_Bitmap_h
|
||||
#define ds_Bitmap_h
|
||||
|
||||
#include "mozilla/Array.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/MemoryChecking.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "js/AllocPolicy.h"
|
||||
#include "js/HashTable.h"
|
||||
@ -26,7 +33,8 @@ namespace js {
|
||||
|
||||
class DenseBitmap
|
||||
{
|
||||
typedef Vector<uintptr_t, 0, SystemAllocPolicy> Data;
|
||||
using Data = Vector<uintptr_t, 0, SystemAllocPolicy>;
|
||||
|
||||
Data data;
|
||||
|
||||
public:
|
||||
@ -45,7 +53,9 @@ class DenseBitmap
|
||||
|
||||
void copyBitsFrom(size_t wordStart, size_t numWords, uintptr_t* source) {
|
||||
MOZ_ASSERT(wordStart + numWords <= data.length());
|
||||
mozilla::PodCopy(&data[wordStart], source, numWords);
|
||||
// Use std::copy and not std::copy_n because the former requires no
|
||||
// overlap and so provides extra opportunity to optimize.
|
||||
std::copy(source, source + numWords, &data[wordStart]);
|
||||
}
|
||||
|
||||
void bitwiseOrRangeInto(size_t wordStart, size_t numWords, uintptr_t* target) const {
|
||||
@ -62,8 +72,9 @@ class SparseBitmap
|
||||
// which are expected to be very sparse should have a small block size.
|
||||
static const size_t WordsInBlock = 4096 / sizeof(uintptr_t);
|
||||
|
||||
typedef mozilla::Array<uintptr_t, WordsInBlock> BitBlock;
|
||||
typedef HashMap<size_t, BitBlock*, DefaultHasher<size_t>, SystemAllocPolicy> Data;
|
||||
using BitBlock = mozilla::Array<uintptr_t, WordsInBlock>;
|
||||
using Data = HashMap<size_t, BitBlock*, DefaultHasher<size_t>, SystemAllocPolicy>;
|
||||
|
||||
Data data;
|
||||
|
||||
static size_t blockStartWord(size_t word) {
|
||||
|
@ -8,13 +8,13 @@
|
||||
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/PodOperations.h"
|
||||
#include "mozilla/Sprintf.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <type_traits>
|
||||
|
||||
#include "jsutil.h"
|
||||
|
||||
@ -32,7 +32,6 @@ using namespace js::gcstats;
|
||||
|
||||
using mozilla::DebugOnly;
|
||||
using mozilla::EnumeratedArray;
|
||||
using mozilla::PodZero;
|
||||
using mozilla::TimeStamp;
|
||||
using mozilla::TimeDuration;
|
||||
|
||||
@ -711,7 +710,26 @@ Statistics::Statistics(JSRuntime* rt)
|
||||
{
|
||||
for (auto& count : counts)
|
||||
count = 0;
|
||||
PodZero(&totalTimes_);
|
||||
|
||||
#ifdef DEBUG
|
||||
for (const auto& duration : totalTimes_) {
|
||||
#if defined(XP_WIN) || defined(XP_MACOSX) || (defined(XP_UNIX) && !defined(__clang__))
|
||||
// build-linux64-asan/debug and static-analysis-linux64-st-an/debug
|
||||
// currently use an STL that lacks std::is_trivially_constructible.
|
||||
// This #ifdef probably isn't as precise as it could be, but given
|
||||
// |totalTimes_| contains |TimeDuration| defined platform-independently
|
||||
// it's not worth the trouble to nail down a more exact condition.
|
||||
using ElementType = typename mozilla::RemoveReference<decltype(duration)>::Type;
|
||||
static_assert(!std::is_trivially_constructible<ElementType>::value,
|
||||
"Statistics::Statistics will only initialize "
|
||||
"totalTimes_'s elements if their default constructor is "
|
||||
"non-trivial");
|
||||
#endif // mess'o'tests
|
||||
MOZ_ASSERT(duration.IsZero(),
|
||||
"totalTimes_ default-initialization should have "
|
||||
"default-initialized every element of totalTimes_ to zero");
|
||||
}
|
||||
#endif
|
||||
|
||||
MOZ_ALWAYS_TRUE(phaseStack.reserve(MAX_PHASE_NESTING));
|
||||
MOZ_ALWAYS_TRUE(suspendedPhases.reserve(MAX_SUSPENDED_PHASES));
|
||||
@ -1098,13 +1116,19 @@ Statistics::endSlice()
|
||||
// Clear the timers at the end of a GC, preserving the data for PhaseKind::MUTATOR.
|
||||
auto mutatorStartTime = phaseStartTimes[Phase::MUTATOR];
|
||||
auto mutatorTime = phaseTimes[Phase::MUTATOR];
|
||||
|
||||
for (mozilla::TimeStamp& t : phaseStartTimes)
|
||||
t = TimeStamp();
|
||||
#ifdef DEBUG
|
||||
for (mozilla::TimeStamp& t : phaseEndTimes)
|
||||
t = TimeStamp();
|
||||
#endif
|
||||
PodZero(&phaseTimes);
|
||||
|
||||
for (TimeDuration& duration : phaseTimes) {
|
||||
duration = TimeDuration();
|
||||
MOZ_ASSERT(duration.IsZero());
|
||||
}
|
||||
|
||||
phaseStartTimes[Phase::MUTATOR] = mutatorStartTime;
|
||||
phaseTimes[Phase::MUTATOR] = mutatorTime;
|
||||
}
|
||||
|
@ -1941,14 +1941,6 @@ BaselineCacheIRCompiler::emitReturnFromIC()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BaselineCacheIRCompiler::emitLoadObject()
|
||||
{
|
||||
Register reg = allocator.defineRegister(masm, reader.objOperandId());
|
||||
masm.loadPtr(stubAddress(reader.stubOffset()), reg);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BaselineCacheIRCompiler::emitLoadStackValue()
|
||||
{
|
||||
|
@ -2995,6 +2995,9 @@ void CacheIRCompiler::emitLoadStubFieldConstant(StubFieldOffset val, Register de
|
||||
case StubField::Type::ObjectGroup:
|
||||
masm.movePtr(ImmGCPtr(groupStubField(val.getOffset())), dest);
|
||||
break;
|
||||
case StubField::Type::JSObject:
|
||||
masm.movePtr(ImmGCPtr(objectStubField(val.getOffset())), dest);
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("Unhandled stub field constant type");
|
||||
}
|
||||
@ -3131,4 +3134,13 @@ CacheIRCompiler::emitGuardGroupHasUnanalyzedNewScript()
|
||||
emitLoadStubField(group, scratch1);
|
||||
masm.guardGroupHasUnanalyzedNewScript(scratch1, scratch2, failure->label());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CacheIRCompiler::emitLoadObject()
|
||||
{
|
||||
Register reg = allocator.defineRegister(masm, reader.objOperandId());
|
||||
StubFieldOffset obj(reader.stubOffset(), StubField::Type::JSObject);
|
||||
emitLoadStubField(obj, reg);
|
||||
return true;
|
||||
}
|
@ -41,6 +41,7 @@ namespace jit {
|
||||
_(GuardAndGetIndexFromString) \
|
||||
_(GuardIndexIsNonNegative) \
|
||||
_(GuardTagNotEqual) \
|
||||
_(LoadObject) \
|
||||
_(LoadProto) \
|
||||
_(LoadEnclosingEnvironment) \
|
||||
_(LoadWrapperTarget) \
|
||||
|
@ -9879,7 +9879,7 @@ CodeGenerator::visitIteratorMore(LIteratorMore* lir)
|
||||
masm.loadPtr(Address(temp, 0), temp);
|
||||
|
||||
// Increase the cursor.
|
||||
masm.addPtr(Imm32(sizeof(JSString*)), cursorAddr);
|
||||
masm.addPtr(Imm32(sizeof(GCPtrFlatString)), cursorAddr);
|
||||
|
||||
masm.tagValue(JSVAL_TYPE_STRING, temp, output);
|
||||
masm.jump(ool->rejoin());
|
||||
@ -9923,8 +9923,9 @@ CodeGenerator::visitIteratorEnd(LIteratorEnd* lir)
|
||||
masm.and32(Imm32(~JSITER_ACTIVE), Address(temp1, offsetof(NativeIterator, flags)));
|
||||
|
||||
// Reset property cursor.
|
||||
masm.loadPtr(Address(temp1, offsetof(NativeIterator, props_array)), temp2);
|
||||
masm.storePtr(temp2, Address(temp1, offsetof(NativeIterator, props_cursor)));
|
||||
Address propCursor(temp1, offsetof(NativeIterator, props_cursor));
|
||||
masm.computeEffectiveAddress(Address(temp1, sizeof(NativeIterator)), temp2);
|
||||
masm.storePtr(temp2, propCursor);
|
||||
|
||||
// Unlink from the iterator list.
|
||||
const Register next = temp2;
|
||||
|
@ -2272,15 +2272,6 @@ IonCacheIRCompiler::emitReturnFromIC()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
IonCacheIRCompiler::emitLoadObject()
|
||||
{
|
||||
Register reg = allocator.defineRegister(masm, reader.objOperandId());
|
||||
JSObject* obj = objectStubField(reader.stubOffset());
|
||||
masm.movePtr(ImmGCPtr(obj), reg);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
IonCacheIRCompiler::emitLoadStackValue()
|
||||
{
|
||||
|
@ -911,7 +911,7 @@ class SpecializedRegSet<Accessors, RegisterSet> : public Accessors
|
||||
}
|
||||
|
||||
void take(Register reg) {
|
||||
MOZ_ASSERT(has(reg));
|
||||
MOZ_ASSERT(this->has(reg));
|
||||
takeUnchecked(reg);
|
||||
}
|
||||
void take(FloatRegister reg) {
|
||||
|
@ -5894,11 +5894,11 @@ namespace JS {
|
||||
* CloseAsmJSCacheEntryForReadOp, passing the same base address, size and
|
||||
* handle.
|
||||
*/
|
||||
typedef bool
|
||||
(* OpenAsmJSCacheEntryForReadOp)(HandleObject global, const char16_t* begin, const char16_t* limit,
|
||||
size_t* size, const uint8_t** memory, intptr_t* handle);
|
||||
typedef void
|
||||
(* CloseAsmJSCacheEntryForReadOp)(size_t size, const uint8_t* memory, intptr_t handle);
|
||||
using OpenAsmJSCacheEntryForReadOp =
|
||||
bool (*)(HandleObject global, const char16_t* begin, const char16_t* limit, size_t* size,
|
||||
const uint8_t** memory, intptr_t* handle);
|
||||
using CloseAsmJSCacheEntryForReadOp =
|
||||
void (*)(size_t size, const uint8_t* memory, intptr_t handle);
|
||||
|
||||
/** The list of reasons why an asm.js module may not be stored in the cache. */
|
||||
enum AsmJSCacheResult
|
||||
@ -5926,19 +5926,18 @@ enum AsmJSCacheResult
|
||||
* to CloseAsmJSCacheEntryForWriteOp passing the same base address, size and
|
||||
* handle.
|
||||
*/
|
||||
typedef AsmJSCacheResult
|
||||
(* OpenAsmJSCacheEntryForWriteOp)(HandleObject global, const char16_t* begin,
|
||||
const char16_t* end, size_t size,
|
||||
uint8_t** memory, intptr_t* handle);
|
||||
typedef void
|
||||
(* CloseAsmJSCacheEntryForWriteOp)(size_t size, uint8_t* memory, intptr_t handle);
|
||||
using OpenAsmJSCacheEntryForWriteOp =
|
||||
AsmJSCacheResult (*)(HandleObject global, const char16_t* begin, const char16_t* end,
|
||||
size_t size, uint8_t** memory, intptr_t* handle);
|
||||
using CloseAsmJSCacheEntryForWriteOp =
|
||||
void (*)(size_t size, uint8_t* memory, intptr_t handle);
|
||||
|
||||
struct AsmJSCacheOps
|
||||
{
|
||||
OpenAsmJSCacheEntryForReadOp openEntryForRead;
|
||||
CloseAsmJSCacheEntryForReadOp closeEntryForRead;
|
||||
OpenAsmJSCacheEntryForWriteOp openEntryForWrite;
|
||||
CloseAsmJSCacheEntryForWriteOp closeEntryForWrite;
|
||||
OpenAsmJSCacheEntryForReadOp openEntryForRead = nullptr;
|
||||
CloseAsmJSCacheEntryForReadOp closeEntryForRead = nullptr;
|
||||
OpenAsmJSCacheEntryForWriteOp openEntryForWrite = nullptr;
|
||||
CloseAsmJSCacheEntryForWriteOp closeEntryForWrite = nullptr;
|
||||
};
|
||||
|
||||
extern JS_PUBLIC_API(void)
|
||||
|
@ -507,8 +507,8 @@ ClampDoubleToUint8(const double x);
|
||||
struct uint8_clamped {
|
||||
uint8_t val;
|
||||
|
||||
uint8_clamped() { }
|
||||
uint8_clamped(const uint8_clamped& other) : val(other.val) { }
|
||||
uint8_clamped() = default;
|
||||
uint8_clamped(const uint8_clamped& other) = default;
|
||||
|
||||
// invoke our assignment helpers for constructor conversion
|
||||
explicit uint8_clamped(uint8_t x) { *this = x; }
|
||||
@ -519,10 +519,7 @@ struct uint8_clamped {
|
||||
explicit uint8_clamped(int32_t x) { *this = x; }
|
||||
explicit uint8_clamped(double x) { *this = x; }
|
||||
|
||||
uint8_clamped& operator=(const uint8_clamped& x) {
|
||||
val = x.val;
|
||||
return *this;
|
||||
}
|
||||
uint8_clamped& operator=(const uint8_clamped& x) = default;
|
||||
|
||||
uint8_clamped& operator=(uint8_t x) {
|
||||
val = x;
|
||||
|
@ -14,6 +14,8 @@
|
||||
#include "mozilla/PodOperations.h"
|
||||
#include "mozilla/Unused.h"
|
||||
|
||||
#include <new>
|
||||
|
||||
#include "jstypes.h"
|
||||
#include "jsutil.h"
|
||||
|
||||
@ -46,7 +48,6 @@ using mozilla::DebugOnly;
|
||||
using mozilla::Maybe;
|
||||
using mozilla::PodCopy;
|
||||
using mozilla::PodEqual;
|
||||
using mozilla::PodZero;
|
||||
|
||||
typedef Rooted<PropertyIteratorObject*> RootedPropertyIteratorObject;
|
||||
|
||||
@ -59,8 +60,9 @@ NativeIterator::trace(JSTracer* trc)
|
||||
TraceNullableEdge(trc, str, "prop");
|
||||
TraceNullableEdge(trc, &obj, "obj");
|
||||
|
||||
HeapReceiverGuard* guards = guardArray();
|
||||
for (size_t i = 0; i < guard_length; i++)
|
||||
guard_array[i].trace(trc);
|
||||
guards[i].trace(trc);
|
||||
|
||||
// The SuppressDeletedPropertyHelper loop can GC, so make sure that if the
|
||||
// GC removes any elements from the list, it won't remove this one.
|
||||
@ -533,7 +535,17 @@ js::GetPropertyKeys(JSContext* cx, HandleObject obj, unsigned flags, AutoIdVecto
|
||||
props);
|
||||
}
|
||||
|
||||
static inline PropertyIteratorObject*
|
||||
static inline void
|
||||
RegisterEnumerator(JSContext* cx, NativeIterator* ni)
|
||||
{
|
||||
/* Register non-escaping native enumerators (for-in) with the current context. */
|
||||
ni->link(cx->compartment()->enumerators);
|
||||
|
||||
MOZ_ASSERT(!(ni->flags & JSITER_ACTIVE));
|
||||
ni->flags |= JSITER_ACTIVE;
|
||||
}
|
||||
|
||||
static PropertyIteratorObject*
|
||||
NewPropertyIteratorObject(JSContext* cx)
|
||||
{
|
||||
RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, &PropertyIteratorObject::class_,
|
||||
@ -562,116 +574,139 @@ NewPropertyIteratorObject(JSContext* cx)
|
||||
return res;
|
||||
}
|
||||
|
||||
NativeIterator*
|
||||
NativeIterator::allocateIterator(JSContext* cx, uint32_t numGuards, uint32_t plength)
|
||||
static PropertyIteratorObject*
|
||||
CreatePropertyIterator(JSContext* cx, Handle<JSObject*> objBeingIterated,
|
||||
const AutoIdVector& props, uint32_t numGuards, uint32_t guardKey)
|
||||
{
|
||||
JS_STATIC_ASSERT(sizeof(ReceiverGuard) == 2 * sizeof(void*));
|
||||
Rooted<PropertyIteratorObject*> propIter(cx, NewPropertyIteratorObject(cx));
|
||||
if (!propIter)
|
||||
return nullptr;
|
||||
|
||||
size_t extraLength = plength + numGuards * 2;
|
||||
NativeIterator* ni = cx->zone()->pod_malloc_with_extra<NativeIterator, void*>(extraLength);
|
||||
if (!ni) {
|
||||
static_assert(sizeof(ReceiverGuard) == 2 * sizeof(GCPtrFlatString),
|
||||
"NativeIterators are allocated in space for 1) themselves, "
|
||||
"2) the properties a NativeIterator iterates (as "
|
||||
"GCPtrFlatStrings), and 3) |numGuards| HeapReceiverGuard "
|
||||
"objects; the additional-length calculation below assumes "
|
||||
"this size-relationship when determining the extra space to "
|
||||
"allocate");
|
||||
|
||||
size_t extraCount = props.length() + numGuards * 2;
|
||||
void* mem =
|
||||
cx->zone()->pod_malloc_with_extra<NativeIterator, GCPtrFlatString>(extraCount);
|
||||
if (!mem) {
|
||||
ReportOutOfMemory(cx);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void** extra = reinterpret_cast<void**>(ni + 1);
|
||||
PodZero(ni);
|
||||
PodZero(extra, extraLength);
|
||||
ni->props_array = ni->props_cursor = reinterpret_cast<GCPtrFlatString*>(extra);
|
||||
ni->props_end = ni->props_array + plength;
|
||||
return ni;
|
||||
// This also registers |ni| with |propIter|.
|
||||
bool hadError = false;
|
||||
NativeIterator* ni =
|
||||
new (mem) NativeIterator(cx, propIter, objBeingIterated, props, numGuards, guardKey,
|
||||
&hadError);
|
||||
if (hadError)
|
||||
return nullptr;
|
||||
|
||||
RegisterEnumerator(cx, ni);
|
||||
return propIter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a sentinel NativeIterator whose purpose is only to act as the
|
||||
* start/end of the circular linked list of NativeIterators in
|
||||
* JSCompartment::enumerators.
|
||||
*/
|
||||
NativeIterator::NativeIterator()
|
||||
{
|
||||
// Do our best to enforce that nothing in |this| except the two fields set
|
||||
// below is ever observed.
|
||||
JS_POISON(static_cast<void*>(this), 0xCC, sizeof(*this), MemCheckKind::MakeUndefined);
|
||||
|
||||
// These are the only two fields in sentinel NativeIterators that are
|
||||
// examined, in JSCompartment::sweepNativeIterators. Everything else is
|
||||
// only examined *if* it's a NativeIterator being traced by a
|
||||
// PropertyIteratorObject that owns it, and nothing owns this iterator.
|
||||
prev_ = next_ = this;
|
||||
}
|
||||
|
||||
NativeIterator*
|
||||
NativeIterator::allocateSentinel(JSContext* maybecx)
|
||||
{
|
||||
NativeIterator* ni = js_pod_malloc<NativeIterator>();
|
||||
NativeIterator* ni = js_new<NativeIterator>();
|
||||
if (!ni) {
|
||||
if (maybecx)
|
||||
ReportOutOfMemory(maybecx);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PodZero(ni);
|
||||
|
||||
ni->next_ = ni;
|
||||
ni->prev_ = ni;
|
||||
return ni;
|
||||
}
|
||||
|
||||
inline void
|
||||
NativeIterator::init(JSObject* obj, JSObject* iterObj, uint32_t numGuards, uint32_t key)
|
||||
/**
|
||||
* Initialize a fresh NativeIterator.
|
||||
*
|
||||
* This definition is a bit tricky: some parts of initializing are fallible, so
|
||||
* as we initialize, we must carefully keep this in GC-safe state (see
|
||||
* NativeIterator::trace).
|
||||
*/
|
||||
NativeIterator::NativeIterator(JSContext* cx, Handle<PropertyIteratorObject*> propIter,
|
||||
Handle<JSObject*> objBeingIterated, const AutoIdVector& props,
|
||||
uint32_t numGuards, uint32_t guardKey, bool* hadError)
|
||||
: obj(objBeingIterated),
|
||||
iterObj_(propIter),
|
||||
// NativeIterator initially acts as if it contains no properties.
|
||||
props_cursor(begin()),
|
||||
props_end(props_cursor),
|
||||
// ...and no HeapReceiverGuards.
|
||||
guard_length(0),
|
||||
guard_key(guardKey),
|
||||
flags(0)
|
||||
{
|
||||
this->obj.init(obj);
|
||||
this->iterObj_ = iterObj;
|
||||
this->flags = 0;
|
||||
this->guard_array = (HeapReceiverGuard*) this->props_end;
|
||||
this->guard_length = numGuards;
|
||||
this->guard_key = key;
|
||||
}
|
||||
MOZ_ASSERT(!*hadError);
|
||||
|
||||
bool
|
||||
NativeIterator::initProperties(JSContext* cx, Handle<PropertyIteratorObject*> obj,
|
||||
const AutoIdVector& props)
|
||||
{
|
||||
// The obj parameter is just so that we can ensure that this object will get
|
||||
// traced if we GC.
|
||||
MOZ_ASSERT(this == obj->getNativeIterator());
|
||||
// NOTE: This must be done first thing: PropertyIteratorObject::finalize
|
||||
// can only free |this| (and not leak it) if this has happened.
|
||||
propIter->setNativeIterator(this);
|
||||
|
||||
size_t plength = props.length();
|
||||
MOZ_ASSERT(plength == size_t(end() - begin()));
|
||||
|
||||
for (size_t i = 0; i < plength; i++) {
|
||||
for (size_t i = 0, len = props.length(); i < len; i++) {
|
||||
JSFlatString* str = IdToString(cx, props[i]);
|
||||
if (!str)
|
||||
return false;
|
||||
props_array[i].init(str);
|
||||
if (!str) {
|
||||
*hadError = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Placement-new the next property string at the end of the currently
|
||||
// computed property strings.
|
||||
GCPtrFlatString* loc = props_end;
|
||||
|
||||
// Increase the overall property string count before initializing the
|
||||
// property string, so this construction isn't on a location not known
|
||||
// to the GC yet.
|
||||
props_end++;
|
||||
|
||||
new (loc) GCPtrFlatString(str);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline void
|
||||
RegisterEnumerator(JSContext* cx, NativeIterator* ni)
|
||||
{
|
||||
/* Register non-escaping native enumerators (for-in) with the current context. */
|
||||
ni->link(cx->compartment()->enumerators);
|
||||
|
||||
MOZ_ASSERT(!(ni->flags & JSITER_ACTIVE));
|
||||
ni->flags |= JSITER_ACTIVE;
|
||||
}
|
||||
|
||||
static inline PropertyIteratorObject*
|
||||
VectorToKeyIterator(JSContext* cx, HandleObject obj, AutoIdVector& keys, uint32_t numGuards)
|
||||
{
|
||||
if (obj->isSingleton() && !JSObject::setIteratedSingleton(cx, obj))
|
||||
return nullptr;
|
||||
MarkObjectGroupFlags(cx, obj, OBJECT_FLAG_ITERATED);
|
||||
|
||||
Rooted<PropertyIteratorObject*> iterobj(cx, NewPropertyIteratorObject(cx));
|
||||
if (!iterobj)
|
||||
return nullptr;
|
||||
|
||||
NativeIterator* ni = NativeIterator::allocateIterator(cx, numGuards, keys.length());
|
||||
if (!ni)
|
||||
return nullptr;
|
||||
|
||||
iterobj->setNativeIterator(ni);
|
||||
ni->init(obj, iterobj, numGuards, 0);
|
||||
if (!ni->initProperties(cx, iterobj, keys))
|
||||
return nullptr;
|
||||
|
||||
if (numGuards) {
|
||||
// Fill in the guard array from scratch. Also recompute the guard key
|
||||
// as we might have reshaped the object (see for instance the
|
||||
// setIteratedSingleton call above) or GC might have moved shapes and
|
||||
// groups in memory.
|
||||
JSObject* pobj = obj;
|
||||
size_t ind = 0;
|
||||
if (numGuards > 0) {
|
||||
// Construct guards into the guard array. Also recompute the guard key,
|
||||
// which incorporates Shape* and ObjectGroup* addresses that could have
|
||||
// changed during a GC triggered in (among other places) |IdToString|
|
||||
//. above.
|
||||
JSObject* pobj = objBeingIterated;
|
||||
uint32_t key = 0;
|
||||
HeapReceiverGuard* guards = guardArray();
|
||||
do {
|
||||
ReceiverGuard guard(pobj);
|
||||
ni->guard_array[ind++].init(guard);
|
||||
|
||||
// Placement-new the next HeapReceiverGuard at the end of the
|
||||
// currently initialized HeapReceiverGuards.
|
||||
uint32_t index = guard_length;
|
||||
|
||||
// Increase the overall guard-count before initializing the
|
||||
// HeapReceiverGuard, so this construction isn't on a location not
|
||||
// known to the GC.
|
||||
guard_length++;
|
||||
|
||||
new (&guards[index]) HeapReceiverGuard(guard);
|
||||
|
||||
key = mozilla::AddToHash(key, guard.hash());
|
||||
|
||||
// The one caller of this method that passes |numGuards > 0|, does
|
||||
@ -679,12 +714,22 @@ VectorToKeyIterator(JSContext* cx, HandleObject obj, AutoIdVector& keys, uint32_
|
||||
// necessarily have static prototypes).
|
||||
pobj = pobj->staticPrototype();
|
||||
} while (pobj);
|
||||
ni->guard_key = key;
|
||||
MOZ_ASSERT(ind == numGuards);
|
||||
|
||||
guard_key = key;
|
||||
MOZ_ASSERT(guard_length == numGuards);
|
||||
}
|
||||
|
||||
RegisterEnumerator(cx, ni);
|
||||
return iterobj;
|
||||
MOZ_ASSERT(!*hadError);
|
||||
}
|
||||
|
||||
static inline PropertyIteratorObject*
|
||||
VectorToKeyIterator(JSContext* cx, HandleObject obj, AutoIdVector& props, uint32_t numGuards)
|
||||
{
|
||||
if (obj->isSingleton() && !JSObject::setIteratedSingleton(cx, obj))
|
||||
return nullptr;
|
||||
MarkObjectGroupFlags(cx, obj, OBJECT_FLAG_ITERATED);
|
||||
|
||||
return CreatePropertyIterator(cx, obj, props, numGuards, 0);
|
||||
}
|
||||
|
||||
|
||||
@ -698,22 +743,8 @@ js::EnumeratedIdVectorToIterator(JSContext* cx, HandleObject obj, AutoIdVector&
|
||||
JSObject*
|
||||
js::NewEmptyPropertyIterator(JSContext* cx)
|
||||
{
|
||||
Rooted<PropertyIteratorObject*> iterobj(cx, NewPropertyIteratorObject(cx));
|
||||
if (!iterobj)
|
||||
return nullptr;
|
||||
|
||||
AutoIdVector keys(cx); // Empty
|
||||
NativeIterator* ni = NativeIterator::allocateIterator(cx, 0, keys.length());
|
||||
if (!ni)
|
||||
return nullptr;
|
||||
|
||||
iterobj->setNativeIterator(ni);
|
||||
ni->init(nullptr, iterobj, 0, 0);
|
||||
if (!ni->initProperties(cx, iterobj, keys))
|
||||
return nullptr;
|
||||
|
||||
RegisterEnumerator(cx, ni);
|
||||
return iterobj;
|
||||
AutoIdVector props(cx); // Empty
|
||||
return CreatePropertyIterator(cx, nullptr, props, 0, 0);
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
@ -723,7 +754,7 @@ IteratorHashPolicy::match(PropertyIteratorObject* obj, const Lookup& lookup)
|
||||
if (ni->guard_key != lookup.key || ni->guard_length != lookup.numGuards)
|
||||
return false;
|
||||
|
||||
return PodEqual(reinterpret_cast<ReceiverGuard*>(ni->guard_array), lookup.guards,
|
||||
return PodEqual(reinterpret_cast<ReceiverGuard*>(ni->guardArray()), lookup.guards,
|
||||
ni->guard_length);
|
||||
}
|
||||
|
||||
@ -823,8 +854,9 @@ StoreInIteratorCache(JSContext* cx, JSObject* obj, PropertyIteratorObject* itero
|
||||
NativeIterator* ni = iterobj->getNativeIterator();
|
||||
MOZ_ASSERT(ni->guard_length > 0);
|
||||
|
||||
IteratorHashPolicy::Lookup lookup(reinterpret_cast<ReceiverGuard*>(ni->guard_array),
|
||||
ni->guard_length, ni->guard_key);
|
||||
IteratorHashPolicy::Lookup lookup(reinterpret_cast<ReceiverGuard*>(ni->guardArray()),
|
||||
ni->guard_length,
|
||||
ni->guard_key);
|
||||
|
||||
JSCompartment::IteratorCache& cache = cx->compartment()->iteratorCache;
|
||||
bool ok;
|
||||
@ -1136,7 +1168,7 @@ js::CloseIterator(JSObject* obj)
|
||||
* Reset the enumerator; it may still be in the cached iterators
|
||||
* for this thread, and can be reused.
|
||||
*/
|
||||
ni->props_cursor = ni->props_array;
|
||||
ni->props_cursor = ni->begin();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -31,30 +31,77 @@ class PropertyIteratorObject;
|
||||
|
||||
struct NativeIterator
|
||||
{
|
||||
GCPtrObject obj; // Object being iterated.
|
||||
JSObject* iterObj_; // Internal iterator object.
|
||||
GCPtrFlatString* props_array;
|
||||
GCPtrFlatString* props_cursor;
|
||||
GCPtrFlatString* props_end;
|
||||
HeapReceiverGuard* guard_array;
|
||||
uint32_t guard_length;
|
||||
uint32_t guard_key;
|
||||
uint32_t flags;
|
||||
// Object being iterated.
|
||||
GCPtrObject obj = {};
|
||||
|
||||
// Internal iterator object.
|
||||
JSObject* iterObj_ = nullptr;
|
||||
|
||||
// The next property, pointing into an array of strings directly after this
|
||||
// NativeIterator as part of the overall allocation containing |*this|.
|
||||
GCPtrFlatString* props_cursor; // initialized by constructor
|
||||
|
||||
// The limit/end of properties to iterate. (This is also, after casting,
|
||||
// the start of an array of HeapReceiverGuards included in the overall
|
||||
// allocation that stores |*this| and the iterated strings.)
|
||||
GCPtrFlatString* props_end; // initialized by constructor
|
||||
|
||||
uint32_t guard_length = 0;
|
||||
uint32_t guard_key = 0;
|
||||
uint32_t flags = 0;
|
||||
|
||||
private:
|
||||
/* While in compartment->enumerators, these form a doubly linked list. */
|
||||
NativeIterator* next_;
|
||||
NativeIterator* prev_;
|
||||
NativeIterator* next_ = nullptr;
|
||||
NativeIterator* prev_ = nullptr;
|
||||
|
||||
// No further fields appear after here *in NativeIterator*, but this class
|
||||
// is always allocated with space tacked on immediately after |this| to
|
||||
// store iterated property names up to |props_end| and |guard_length|
|
||||
// HeapReceiverGuards after that.
|
||||
|
||||
public:
|
||||
inline GCPtrFlatString* begin() const {
|
||||
return props_array;
|
||||
/**
|
||||
* Initialize a NativeIterator properly allocated for |props.length()|
|
||||
* properties and |numGuards| guards.
|
||||
*
|
||||
* Despite being a constructor, THIS FUNCTION CAN REPORT ERRORS. Users
|
||||
* MUST set |*hadError = false| on entry and consider |*hadError| on return
|
||||
* to mean this function failed.
|
||||
*/
|
||||
NativeIterator(JSContext* cx, Handle<PropertyIteratorObject*> propIter,
|
||||
Handle<JSObject*> objBeingIterated, const AutoIdVector& props,
|
||||
uint32_t numGuards, uint32_t guardKey, bool* hadError);
|
||||
|
||||
/** Initialize a |JSCompartment::enumerators| sentinel. */
|
||||
NativeIterator();
|
||||
|
||||
GCPtrFlatString* begin() const {
|
||||
static_assert(alignof(NativeIterator) >= alignof(GCPtrFlatString),
|
||||
"GCPtrFlatStrings for properties must be able to appear "
|
||||
"directly after NativeIterator, with no padding space "
|
||||
"required for correct alignment");
|
||||
|
||||
// Note that JIT code inlines this computation to reset |props_cursor|
|
||||
// when an iterator ends: see |CodeGenerator::visitIteratorEnd|.
|
||||
const NativeIterator* immediatelyAfter = this + 1;
|
||||
auto* afterNonConst = const_cast<NativeIterator*>(immediatelyAfter);
|
||||
return reinterpret_cast<GCPtrFlatString*>(afterNonConst);
|
||||
}
|
||||
|
||||
inline GCPtrFlatString* end() const {
|
||||
GCPtrFlatString* end() const {
|
||||
return props_end;
|
||||
}
|
||||
|
||||
HeapReceiverGuard* guardArray() const {
|
||||
static_assert(alignof(ReceiverGuard) == alignof(GCPtrFlatString),
|
||||
"the end of all properties must be exactly aligned "
|
||||
"adequate to begin storing ReceiverGuards, else the "
|
||||
"full tacked-on memory won't be enough to store all "
|
||||
"properties/guards");
|
||||
return reinterpret_cast<HeapReceiverGuard*>(props_end);
|
||||
}
|
||||
|
||||
size_t numKeys() const {
|
||||
return end() - begin();
|
||||
}
|
||||
@ -98,16 +145,8 @@ struct NativeIterator
|
||||
}
|
||||
|
||||
static NativeIterator* allocateSentinel(JSContext* maybecx);
|
||||
static NativeIterator* allocateIterator(JSContext* cx, uint32_t slength, uint32_t plength);
|
||||
void init(JSObject* obj, JSObject* iterObj, uint32_t slength, uint32_t key);
|
||||
bool initProperties(JSContext* cx, Handle<PropertyIteratorObject*> obj,
|
||||
const js::AutoIdVector& props);
|
||||
|
||||
void trace(JSTracer* trc);
|
||||
|
||||
static void destroy(NativeIterator* iter) {
|
||||
js_free(iter);
|
||||
}
|
||||
};
|
||||
|
||||
class PropertyIteratorObject : public NativeObject
|
||||
|
@ -204,7 +204,7 @@ JSScript::ensureHasAnalyzedArgsUsage(JSContext* cx)
|
||||
inline bool
|
||||
JSScript::isDebuggee() const
|
||||
{
|
||||
return realm_->debuggerObservesAllExecution() || hasDebugScript_;
|
||||
return realm_->debuggerObservesAllExecution() || bitFields_.hasDebugScript_;
|
||||
}
|
||||
|
||||
#endif /* vm_JSScript_inl_h */
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "mozilla/Vector.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <new>
|
||||
#include <string.h>
|
||||
|
||||
#include "jsapi.h"
|
||||
@ -68,7 +69,6 @@ using namespace js::frontend;
|
||||
|
||||
using mozilla::Maybe;
|
||||
using mozilla::PodCopy;
|
||||
using mozilla::PodZero;
|
||||
|
||||
|
||||
// Check that JSScript::data hasn't experienced obvious memory corruption.
|
||||
@ -558,39 +558,39 @@ js::XDRScript(XDRState<mode>* xdr, HandleScope scriptEnclosingScope,
|
||||
scriptp.set(script);
|
||||
|
||||
if (scriptBits & (1 << Strict))
|
||||
script->strict_ = true;
|
||||
script->bitFields_.strict_ = true;
|
||||
if (scriptBits & (1 << ExplicitUseStrict))
|
||||
script->explicitUseStrict_ = true;
|
||||
script->bitFields_.explicitUseStrict_ = true;
|
||||
if (scriptBits & (1 << ContainsDynamicNameAccess))
|
||||
script->bindingsAccessedDynamically_ = true;
|
||||
script->bitFields_.bindingsAccessedDynamically_ = true;
|
||||
if (scriptBits & (1 << FunHasExtensibleScope))
|
||||
script->funHasExtensibleScope_ = true;
|
||||
script->bitFields_.funHasExtensibleScope_ = true;
|
||||
if (scriptBits & (1 << FunHasAnyAliasedFormal))
|
||||
script->funHasAnyAliasedFormal_ = true;
|
||||
script->bitFields_.funHasAnyAliasedFormal_ = true;
|
||||
if (scriptBits & (1 << ArgumentsHasVarBinding))
|
||||
script->setArgumentsHasVarBinding();
|
||||
if (scriptBits & (1 << NeedsArgsObj))
|
||||
script->setNeedsArgsObj(true);
|
||||
if (scriptBits & (1 << HasMappedArgsObj))
|
||||
script->hasMappedArgsObj_ = true;
|
||||
script->bitFields_.hasMappedArgsObj_ = true;
|
||||
if (scriptBits & (1 << FunctionHasThisBinding))
|
||||
script->functionHasThisBinding_ = true;
|
||||
script->bitFields_.functionHasThisBinding_ = true;
|
||||
if (scriptBits & (1 << FunctionHasExtraBodyVarScope))
|
||||
script->functionHasExtraBodyVarScope_ = true;
|
||||
script->bitFields_.functionHasExtraBodyVarScope_ = true;
|
||||
if (scriptBits & (1 << HasSingleton))
|
||||
script->hasSingletons_ = true;
|
||||
script->bitFields_.hasSingletons_ = true;
|
||||
if (scriptBits & (1 << TreatAsRunOnce))
|
||||
script->treatAsRunOnce_ = true;
|
||||
script->bitFields_.treatAsRunOnce_ = true;
|
||||
if (scriptBits & (1 << HasNonSyntacticScope))
|
||||
script->hasNonSyntacticScope_ = true;
|
||||
script->bitFields_.hasNonSyntacticScope_ = true;
|
||||
if (scriptBits & (1 << HasInnerFunctions))
|
||||
script->hasInnerFunctions_ = true;
|
||||
script->bitFields_.hasInnerFunctions_ = true;
|
||||
if (scriptBits & (1 << NeedsHomeObject))
|
||||
script->needsHomeObject_ = true;
|
||||
script->bitFields_.needsHomeObject_ = true;
|
||||
if (scriptBits & (1 << IsDerivedClassConstructor))
|
||||
script->isDerivedClassConstructor_ = true;
|
||||
script->bitFields_.isDerivedClassConstructor_ = true;
|
||||
if (scriptBits & (1 << IsDefaultClassConstructor))
|
||||
script->isDefaultClassConstructor_ = true;
|
||||
script->bitFields_.isDefaultClassConstructor_ = true;
|
||||
if (scriptBits & (1 << IsGenerator))
|
||||
script->setGeneratorKind(GeneratorKind::Generator);
|
||||
if (scriptBits & (1 << IsAsync))
|
||||
@ -1086,7 +1086,7 @@ JSScript::initScriptCounts(JSContext* cx)
|
||||
}
|
||||
|
||||
// safe to set this; we can't fail after this point.
|
||||
hasScriptCounts_ = true;
|
||||
bitFields_.hasScriptCounts_ = true;
|
||||
guardScriptCounts.release();
|
||||
|
||||
// Enable interrupts in any interpreter frames running on this script. This
|
||||
@ -1298,7 +1298,7 @@ JSScript::takeOverScriptCountsMapEntry(ScriptCounts* entryValue)
|
||||
ScriptCountsMap::Ptr p = GetScriptCountsMapEntry(this);
|
||||
MOZ_ASSERT(entryValue == p->value());
|
||||
#endif
|
||||
hasScriptCounts_ = false;
|
||||
bitFields_.hasScriptCounts_ = false;
|
||||
}
|
||||
|
||||
void
|
||||
@ -1308,7 +1308,7 @@ JSScript::releaseScriptCounts(ScriptCounts* counts)
|
||||
*counts = Move(*p->value());
|
||||
js_delete(p->value());
|
||||
compartment()->scriptCountsMap->remove(p);
|
||||
hasScriptCounts_ = false;
|
||||
bitFields_.hasScriptCounts_ = false;
|
||||
}
|
||||
|
||||
void
|
||||
@ -2626,10 +2626,23 @@ ScriptDataSize(uint32_t nscopes, uint32_t nconsts, uint32_t nobjects,
|
||||
return size;
|
||||
}
|
||||
|
||||
/* static */ JSScript*
|
||||
JSScript::Create(JSContext* cx, const ReadOnlyCompileOptions& options,
|
||||
HandleObject sourceObject, uint32_t bufStart, uint32_t bufEnd,
|
||||
uint32_t toStringStart, uint32_t toStringEnd)
|
||||
JSScript::JSScript(JS::Realm* realm, uint8_t* stubEntry, const ReadOnlyCompileOptions& options,
|
||||
HandleObject sourceObject, uint32_t bufStart, uint32_t bufEnd,
|
||||
uint32_t toStringStart, uint32_t toStringEnd)
|
||||
:
|
||||
#ifndef JS_CODEGEN_NONE
|
||||
jitCodeRaw_(stubEntry),
|
||||
jitCodeSkipArgCheck_(stubEntry),
|
||||
#endif
|
||||
realm_(realm),
|
||||
sourceStart_(bufStart),
|
||||
sourceEnd_(bufEnd),
|
||||
toStringStart_(toStringStart),
|
||||
toStringEnd_(toStringEnd),
|
||||
#ifdef MOZ_VTUNE
|
||||
vtuneMethodId_(vtune::GenerateUniqueMethodID()),
|
||||
#endif
|
||||
bitFields_{} // zeroes everything -- some fields custom-assigned below
|
||||
{
|
||||
// bufStart and bufEnd specify the range of characters parsed by the
|
||||
// Parser to produce this script. toStringStart and toStringEnd specify
|
||||
@ -2639,37 +2652,50 @@ JSScript::Create(JSContext* cx, const ReadOnlyCompileOptions& options,
|
||||
MOZ_ASSERT(toStringStart <= bufStart);
|
||||
MOZ_ASSERT(toStringEnd >= bufEnd);
|
||||
|
||||
RootedScript script(cx, Allocate<JSScript>(cx));
|
||||
bitFields_.noScriptRval_ = options.noScriptRval;
|
||||
bitFields_.selfHosted_ = options.selfHostingMode;
|
||||
bitFields_.treatAsRunOnce_ = options.isRunOnce;
|
||||
bitFields_.hideScriptFromDebugger_ = options.hideScriptFromDebugger;
|
||||
|
||||
setSourceObject(sourceObject);
|
||||
}
|
||||
|
||||
/* static */ JSScript*
|
||||
JSScript::createInitialized(JSContext* cx, const ReadOnlyCompileOptions& options,
|
||||
HandleObject sourceObject,
|
||||
uint32_t bufStart, uint32_t bufEnd,
|
||||
uint32_t toStringStart, uint32_t toStringEnd)
|
||||
{
|
||||
void* script = Allocate<JSScript>(cx);
|
||||
if (!script)
|
||||
return nullptr;
|
||||
|
||||
PodZero(script.get());
|
||||
|
||||
script->realm_ = cx->realm();
|
||||
|
||||
uint8_t* stubEntry =
|
||||
#ifndef JS_CODEGEN_NONE
|
||||
uint8_t* stubEntry = cx->runtime()->jitRuntime()->interpreterStub().value;
|
||||
script->jitCodeRaw_ = stubEntry;
|
||||
script->jitCodeSkipArgCheck_ = stubEntry;
|
||||
cx->runtime()->jitRuntime()->interpreterStub().value
|
||||
#else
|
||||
nullptr
|
||||
#endif
|
||||
;
|
||||
|
||||
script->selfHosted_ = options.selfHostingMode;
|
||||
script->noScriptRval_ = options.noScriptRval;
|
||||
script->treatAsRunOnce_ = options.isRunOnce;
|
||||
return new (script) JSScript(cx->realm(), stubEntry, options, sourceObject,
|
||||
bufStart, bufEnd, toStringStart, toStringEnd);
|
||||
}
|
||||
|
||||
script->setSourceObject(sourceObject);
|
||||
if (cx->runtime()->lcovOutput().isEnabled() && !script->initScriptName(cx))
|
||||
/* static */ JSScript*
|
||||
JSScript::Create(JSContext* cx, const ReadOnlyCompileOptions& options,
|
||||
HandleObject sourceObject, uint32_t bufStart, uint32_t bufEnd,
|
||||
uint32_t toStringStart, uint32_t toStringEnd)
|
||||
{
|
||||
RootedScript script(cx, createInitialized(cx, options, sourceObject, bufStart, bufEnd,
|
||||
toStringStart, toStringEnd));
|
||||
if (!script)
|
||||
return nullptr;
|
||||
script->sourceStart_ = bufStart;
|
||||
script->sourceEnd_ = bufEnd;
|
||||
script->toStringStart_ = toStringStart;
|
||||
script->toStringEnd_ = toStringEnd;
|
||||
|
||||
script->hideScriptFromDebugger_ = options.hideScriptFromDebugger;
|
||||
|
||||
#ifdef MOZ_VTUNE
|
||||
script->vtuneMethodId_ = vtune::GenerateUniqueMethodID();
|
||||
#endif
|
||||
if (cx->runtime()->lcovOutput().isEnabled()) {
|
||||
if (!script->initScriptName(cx))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return script;
|
||||
}
|
||||
@ -2882,9 +2908,9 @@ JSScript::initFromFunctionBox(HandleScript script, frontend::FunctionBox* funbox
|
||||
else
|
||||
fun->setScript(script);
|
||||
|
||||
script->funHasExtensibleScope_ = funbox->hasExtensibleScope();
|
||||
script->needsHomeObject_ = funbox->needsHomeObject();
|
||||
script->isDerivedClassConstructor_ = funbox->isDerivedClassConstructor();
|
||||
script->bitFields_.funHasExtensibleScope_ = funbox->hasExtensibleScope();
|
||||
script->bitFields_.needsHomeObject_ = funbox->needsHomeObject();
|
||||
script->bitFields_.isDerivedClassConstructor_ = funbox->isDerivedClassConstructor();
|
||||
|
||||
if (funbox->argumentsHasLocalBinding()) {
|
||||
script->setArgumentsHasVarBinding();
|
||||
@ -2893,10 +2919,10 @@ JSScript::initFromFunctionBox(HandleScript script, frontend::FunctionBox* funbox
|
||||
} else {
|
||||
MOZ_ASSERT(!funbox->definitelyNeedsArgsObj());
|
||||
}
|
||||
script->hasMappedArgsObj_ = funbox->hasMappedArgsObj();
|
||||
script->bitFields_.hasMappedArgsObj_ = funbox->hasMappedArgsObj();
|
||||
|
||||
script->functionHasThisBinding_ = funbox->hasThisBinding();
|
||||
script->functionHasExtraBodyVarScope_ = funbox->hasExtraBodyVarScope();
|
||||
script->bitFields_.functionHasThisBinding_ = funbox->hasThisBinding();
|
||||
script->bitFields_.functionHasExtraBodyVarScope_ = funbox->hasExtraBodyVarScope();
|
||||
|
||||
script->funLength_ = funbox->length;
|
||||
|
||||
@ -2908,7 +2934,7 @@ JSScript::initFromFunctionBox(HandleScript script, frontend::FunctionBox* funbox
|
||||
PositionalFormalParameterIter fi(script);
|
||||
while (fi && !fi.closedOver())
|
||||
fi++;
|
||||
script->funHasAnyAliasedFormal_ = !!fi;
|
||||
script->bitFields_.funHasAnyAliasedFormal_ = !!fi;
|
||||
|
||||
script->setHasInnerFunctions(funbox->hasInnerFunctions());
|
||||
}
|
||||
@ -2916,9 +2942,9 @@ JSScript::initFromFunctionBox(HandleScript script, frontend::FunctionBox* funbox
|
||||
/* static */ void
|
||||
JSScript::initFromModuleContext(HandleScript script)
|
||||
{
|
||||
script->funHasExtensibleScope_ = false;
|
||||
script->needsHomeObject_ = false;
|
||||
script->isDerivedClassConstructor_ = false;
|
||||
script->bitFields_.funHasExtensibleScope_ = false;
|
||||
script->bitFields_.needsHomeObject_ = false;
|
||||
script->bitFields_.isDerivedClassConstructor_ = false;
|
||||
script->funLength_ = 0;
|
||||
|
||||
script->setGeneratorKind(GeneratorKind::NotGenerator);
|
||||
@ -2977,10 +3003,10 @@ JSScript::fullyInitFromEmitter(JSContext* cx, HandleScript script, BytecodeEmitt
|
||||
bce->tryNoteList.finish(script->trynotes());
|
||||
if (bce->scopeNoteList.length() != 0)
|
||||
bce->scopeNoteList.finish(script->scopeNotes(), prologueLength);
|
||||
script->strict_ = bce->sc->strict();
|
||||
script->explicitUseStrict_ = bce->sc->hasExplicitUseStrict();
|
||||
script->bindingsAccessedDynamically_ = bce->sc->bindingsAccessedDynamically();
|
||||
script->hasSingletons_ = bce->hasSingletons;
|
||||
script->bitFields_.strict_ = bce->sc->strict();
|
||||
script->bitFields_.explicitUseStrict_ = bce->sc->hasExplicitUseStrict();
|
||||
script->bitFields_.bindingsAccessedDynamically_ = bce->sc->bindingsAccessedDynamically();
|
||||
script->bitFields_.hasSingletons_ = bce->hasSingletons;
|
||||
|
||||
uint64_t nslots = bce->maxFixedSlots + static_cast<uint64_t>(bce->maxStackDepth);
|
||||
if (nslots > UINT32_MAX) {
|
||||
@ -2991,7 +3017,8 @@ JSScript::fullyInitFromEmitter(JSContext* cx, HandleScript script, BytecodeEmitt
|
||||
script->nfixed_ = bce->maxFixedSlots;
|
||||
script->nslots_ = nslots;
|
||||
script->bodyScopeIndex_ = bce->bodyScopeIndex;
|
||||
script->hasNonSyntacticScope_ = bce->outermostScope()->hasOnChain(ScopeKind::NonSyntactic);
|
||||
script->bitFields_.hasNonSyntacticScope_ =
|
||||
bce->outermostScope()->hasOnChain(ScopeKind::NonSyntactic);
|
||||
|
||||
if (bce->sc->isFunctionBox())
|
||||
initFromFunctionBox(script, bce->sc->asFunctionBox());
|
||||
@ -3538,26 +3565,26 @@ js::detail::CopyScript(JSContext* cx, HandleScript src, HandleScript dst,
|
||||
if (src->analyzedArgsUsage())
|
||||
dst->setNeedsArgsObj(src->needsArgsObj());
|
||||
}
|
||||
dst->hasMappedArgsObj_ = src->hasMappedArgsObj();
|
||||
dst->functionHasThisBinding_ = src->functionHasThisBinding();
|
||||
dst->functionHasExtraBodyVarScope_ = src->functionHasExtraBodyVarScope();
|
||||
dst->bitFields_.hasMappedArgsObj_ = src->hasMappedArgsObj();
|
||||
dst->bitFields_.functionHasThisBinding_ = src->functionHasThisBinding();
|
||||
dst->bitFields_.functionHasExtraBodyVarScope_ = src->functionHasExtraBodyVarScope();
|
||||
dst->cloneHasArray(src);
|
||||
dst->strict_ = src->strict();
|
||||
dst->explicitUseStrict_ = src->explicitUseStrict();
|
||||
dst->hasNonSyntacticScope_ = scopes[0]->hasOnChain(ScopeKind::NonSyntactic);
|
||||
dst->bindingsAccessedDynamically_ = src->bindingsAccessedDynamically();
|
||||
dst->funHasExtensibleScope_ = src->funHasExtensibleScope();
|
||||
dst->funHasAnyAliasedFormal_ = src->funHasAnyAliasedFormal();
|
||||
dst->hasSingletons_ = src->hasSingletons();
|
||||
dst->treatAsRunOnce_ = src->treatAsRunOnce();
|
||||
dst->hasInnerFunctions_ = src->hasInnerFunctions();
|
||||
dst->bitFields_.strict_ = src->strict();
|
||||
dst->bitFields_.explicitUseStrict_ = src->explicitUseStrict();
|
||||
dst->bitFields_.hasNonSyntacticScope_ = scopes[0]->hasOnChain(ScopeKind::NonSyntactic);
|
||||
dst->bitFields_.bindingsAccessedDynamically_ = src->bindingsAccessedDynamically();
|
||||
dst->bitFields_.funHasExtensibleScope_ = src->funHasExtensibleScope();
|
||||
dst->bitFields_.funHasAnyAliasedFormal_ = src->funHasAnyAliasedFormal();
|
||||
dst->bitFields_.hasSingletons_ = src->hasSingletons();
|
||||
dst->bitFields_.treatAsRunOnce_ = src->treatAsRunOnce();
|
||||
dst->bitFields_.hasInnerFunctions_ = src->hasInnerFunctions();
|
||||
dst->setGeneratorKind(src->generatorKind());
|
||||
dst->isDerivedClassConstructor_ = src->isDerivedClassConstructor();
|
||||
dst->needsHomeObject_ = src->needsHomeObject();
|
||||
dst->isDefaultClassConstructor_ = src->isDefaultClassConstructor();
|
||||
dst->isAsync_ = src->isAsync_;
|
||||
dst->hasRest_ = src->hasRest_;
|
||||
dst->hideScriptFromDebugger_ = src->hideScriptFromDebugger_;
|
||||
dst->bitFields_.isDerivedClassConstructor_ = src->isDerivedClassConstructor();
|
||||
dst->bitFields_.needsHomeObject_ = src->needsHomeObject();
|
||||
dst->bitFields_.isDefaultClassConstructor_ = src->isDefaultClassConstructor();
|
||||
dst->bitFields_.isAsync_ = src->bitFields_.isAsync_;
|
||||
dst->bitFields_.hasRest_ = src->bitFields_.hasRest_;
|
||||
dst->bitFields_.hideScriptFromDebugger_ = src->bitFields_.hideScriptFromDebugger_;
|
||||
|
||||
if (nconsts != 0) {
|
||||
GCPtrValue* vector = Rebase<GCPtrValue>(dst, src, src->consts()->vector);
|
||||
@ -3700,7 +3727,7 @@ js::CloneScriptIntoFunction(JSContext* cx, HandleScope enclosingScope, HandleFun
|
||||
DebugScript*
|
||||
JSScript::debugScript()
|
||||
{
|
||||
MOZ_ASSERT(hasDebugScript_);
|
||||
MOZ_ASSERT(bitFields_.hasDebugScript_);
|
||||
DebugScriptMap* map = compartment()->debugScriptMap;
|
||||
MOZ_ASSERT(map);
|
||||
DebugScriptMap::Ptr p = map->lookup(this);
|
||||
@ -3711,21 +3738,21 @@ JSScript::debugScript()
|
||||
DebugScript*
|
||||
JSScript::releaseDebugScript()
|
||||
{
|
||||
MOZ_ASSERT(hasDebugScript_);
|
||||
MOZ_ASSERT(bitFields_.hasDebugScript_);
|
||||
DebugScriptMap* map = compartment()->debugScriptMap;
|
||||
MOZ_ASSERT(map);
|
||||
DebugScriptMap::Ptr p = map->lookup(this);
|
||||
MOZ_ASSERT(p);
|
||||
DebugScript* debug = p->value();
|
||||
map->remove(p);
|
||||
hasDebugScript_ = false;
|
||||
bitFields_.hasDebugScript_ = false;
|
||||
return debug;
|
||||
}
|
||||
|
||||
void
|
||||
JSScript::destroyDebugScript(FreeOp* fop)
|
||||
{
|
||||
if (hasDebugScript_) {
|
||||
if (bitFields_.hasDebugScript_) {
|
||||
#ifdef DEBUG
|
||||
for (jsbytecode* pc = code(); pc < codeEnd(); pc++) {
|
||||
if (BreakpointSite* site = getBreakpointSite(pc)) {
|
||||
@ -3742,7 +3769,7 @@ JSScript::destroyDebugScript(FreeOp* fop)
|
||||
bool
|
||||
JSScript::ensureHasDebugScript(JSContext* cx)
|
||||
{
|
||||
if (hasDebugScript_)
|
||||
if (bitFields_.hasDebugScript_)
|
||||
return true;
|
||||
|
||||
size_t nbytes = offsetof(DebugScript, breakpoints) + length() * sizeof(BreakpointSite*);
|
||||
@ -3766,7 +3793,7 @@ JSScript::ensureHasDebugScript(JSContext* cx)
|
||||
js_free(debug);
|
||||
return false;
|
||||
}
|
||||
hasDebugScript_ = true; // safe to set this; we can't fail after this point
|
||||
bitFields_.hasDebugScript_ = true; // safe to set this; we can't fail after this point
|
||||
|
||||
/*
|
||||
* Ensure that any Interpret() instances running on this script have
|
||||
@ -4033,16 +4060,16 @@ JSScript::innermostScope(jsbytecode* pc)
|
||||
void
|
||||
JSScript::setArgumentsHasVarBinding()
|
||||
{
|
||||
argsHasVarBinding_ = true;
|
||||
needsArgsAnalysis_ = true;
|
||||
bitFields_.argsHasVarBinding_ = true;
|
||||
bitFields_.needsArgsAnalysis_ = true;
|
||||
}
|
||||
|
||||
void
|
||||
JSScript::setNeedsArgsObj(bool needsArgsObj)
|
||||
{
|
||||
MOZ_ASSERT_IF(needsArgsObj, argumentsHasVarBinding());
|
||||
needsArgsAnalysis_ = false;
|
||||
needsArgsObj_ = needsArgsObj;
|
||||
bitFields_.needsArgsAnalysis_ = false;
|
||||
bitFields_.needsArgsObj_ = needsArgsObj;
|
||||
}
|
||||
|
||||
void
|
||||
@ -4105,7 +4132,7 @@ JSScript::argumentsOptimizationFailed(JSContext* cx, HandleScript script)
|
||||
MOZ_ASSERT(!script->isGenerator());
|
||||
MOZ_ASSERT(!script->isAsync());
|
||||
|
||||
script->needsArgsObj_ = true;
|
||||
script->bitFields_.needsArgsObj_ = true;
|
||||
|
||||
/*
|
||||
* Since we can't invalidate baseline scripts, set a flag that's checked from
|
||||
@ -4446,7 +4473,7 @@ JSScript::AutoDelazify::holdScript(JS::HandleFunction fun)
|
||||
JSAutoRealm ar(cx_, fun);
|
||||
script_ = JSFunction::getOrCreateScript(cx_, fun);
|
||||
if (script_) {
|
||||
oldDoNotRelazify_ = script_->doNotRelazify_;
|
||||
oldDoNotRelazify_ = script_->bitFields_.doNotRelazify_;
|
||||
script_->setDoNotRelazify(true);
|
||||
}
|
||||
}
|
||||
|
@ -900,40 +900,31 @@ FreeScriptData(JSRuntime* rt);
|
||||
|
||||
class JSScript : public js::gc::TenuredCell
|
||||
{
|
||||
template <js::XDRMode mode>
|
||||
friend
|
||||
js::XDRResult
|
||||
js::XDRScript(js::XDRState<mode>* xdr, js::HandleScope enclosingScope,
|
||||
js::HandleScriptSourceObject sourceObject, js::HandleFunction fun,
|
||||
js::MutableHandleScript scriptp);
|
||||
|
||||
friend bool
|
||||
js::detail::CopyScript(JSContext* cx, js::HandleScript src, js::HandleScript dst,
|
||||
js::MutableHandle<JS::GCVector<js::Scope*>> scopes);
|
||||
|
||||
private:
|
||||
// Pointer to baseline->method()->raw(), ion->method()->raw(), a wasm jit
|
||||
// entry, the JIT's EnterInterpreter stub, or the lazy link stub. Must be
|
||||
// non-null.
|
||||
uint8_t* jitCodeRaw_;
|
||||
uint8_t* jitCodeSkipArgCheck_;
|
||||
uint8_t* jitCodeRaw_ = nullptr;
|
||||
uint8_t* jitCodeSkipArgCheck_ = nullptr;
|
||||
|
||||
js::SharedScriptData* scriptData_ = nullptr;
|
||||
|
||||
js::SharedScriptData* scriptData_;
|
||||
public:
|
||||
uint8_t* data; /* pointer to variable-length data array (see
|
||||
comment above Create() for details) */
|
||||
// Pointer to variable-length data array (see comment above Create() for
|
||||
// details).
|
||||
uint8_t* data = nullptr;
|
||||
|
||||
JS::Realm* realm_;
|
||||
JS::Realm* realm_ = nullptr;
|
||||
|
||||
private:
|
||||
/* Persistent type information retained across GCs. */
|
||||
js::TypeScript* types_;
|
||||
js::TypeScript* types_ = nullptr;
|
||||
|
||||
// This script's ScriptSourceObject, or a CCW thereof.
|
||||
//
|
||||
// (When we clone a JSScript into a new compartment, we don't clone its
|
||||
// source object. Instead, the clone refers to a wrapper.)
|
||||
js::GCPtrObject sourceObject_;
|
||||
js::GCPtrObject sourceObject_ = {};
|
||||
|
||||
/*
|
||||
* Information attached by Ion. Nexto a valid IonScript this could be
|
||||
@ -941,28 +932,36 @@ class JSScript : public js::gc::TenuredCell
|
||||
* The later is a ion compilation that is ready, but hasn't been linked
|
||||
* yet.
|
||||
*/
|
||||
js::jit::IonScript* ion;
|
||||
js::jit::IonScript* ion = nullptr;
|
||||
|
||||
/* Information attached by Baseline. */
|
||||
js::jit::BaselineScript* baseline;
|
||||
js::jit::BaselineScript* baseline = nullptr;
|
||||
|
||||
/* Information used to re-lazify a lazily-parsed interpreted function. */
|
||||
js::LazyScript* lazyScript;
|
||||
js::LazyScript* lazyScript = nullptr;
|
||||
|
||||
// 32-bit fields.
|
||||
|
||||
uint32_t dataSize_; /* size of the used part of the data array */
|
||||
/* Size of the used part of the data array. */
|
||||
uint32_t dataSize_ = 0;
|
||||
|
||||
uint32_t lineno_; /* base line number of script */
|
||||
uint32_t column_; /* base column of script, optionally set */
|
||||
/* Base line number of script. */
|
||||
uint32_t lineno_ = 0;
|
||||
|
||||
uint32_t mainOffset_;/* offset of main entry point from code, after
|
||||
predef'ing prologue */
|
||||
/* Base column of script, optionally set. */
|
||||
uint32_t column_ = 0;
|
||||
|
||||
uint32_t nfixed_; /* fixed frame slots */
|
||||
uint32_t nslots_; /* slots plus maximum stack depth */
|
||||
/* Offset of main entry point from code, after predef'ing prologue. */
|
||||
uint32_t mainOffset_ = 0;
|
||||
|
||||
uint32_t bodyScopeIndex_; /* index into the scopes array of the body scope */
|
||||
/* Fixed frame slots. */
|
||||
uint32_t nfixed_ = 0;
|
||||
|
||||
/* Slots plus maximum stack depth. */
|
||||
uint32_t nslots_ = 0;
|
||||
|
||||
/* Index into the scopes array of the body scope */
|
||||
uint32_t bodyScopeIndex_ = 0;
|
||||
|
||||
// Range of characters in scriptSource which contains this script's
|
||||
// source, that is, the range used by the Parser to produce this script.
|
||||
@ -990,34 +989,37 @@ class JSScript : public js::gc::TenuredCell
|
||||
// | sourceStart_ sourceEnd_ |
|
||||
// | |
|
||||
// toStringStart_ toStringEnd_
|
||||
uint32_t sourceStart_;
|
||||
uint32_t sourceEnd_;
|
||||
uint32_t toStringStart_;
|
||||
uint32_t toStringEnd_;
|
||||
uint32_t sourceStart_ = 0;
|
||||
uint32_t sourceEnd_ = 0;
|
||||
uint32_t toStringStart_ = 0;
|
||||
uint32_t toStringEnd_ = 0;
|
||||
|
||||
#ifdef MOZ_VTUNE
|
||||
// Unique Method ID passed to the VTune profiler, or 0 if unset.
|
||||
// Allows attribution of different jitcode to the same source script.
|
||||
uint32_t vtuneMethodId_;
|
||||
uint32_t vtuneMethodId_ = 0;
|
||||
// Extra padding to maintain JSScript as a multiple of gc::CellAlignBytes.
|
||||
uint32_t __vtune_unused_padding_;
|
||||
uint32_t __vtune_unused_padding_;
|
||||
#endif
|
||||
|
||||
// Number of times the script has been called or has had backedges taken.
|
||||
// When running in ion, also increased for any inlined scripts. Reset if
|
||||
// the script's JIT code is forcibly discarded.
|
||||
mozilla::Atomic<uint32_t, mozilla::Relaxed> warmUpCount;
|
||||
mozilla::Atomic<uint32_t, mozilla::Relaxed> warmUpCount = {};
|
||||
|
||||
// 16-bit fields.
|
||||
|
||||
uint16_t warmUpResetCount; /* Number of times the |warmUpCount| was
|
||||
* forcibly discarded. The counter is reset when
|
||||
* a script is successfully jit-compiled. */
|
||||
/**
|
||||
* Number of times the |warmUpCount| was forcibly discarded. The counter is
|
||||
* reset when a script is successfully jit-compiled.
|
||||
*/
|
||||
uint16_t warmUpResetCount = 0;
|
||||
|
||||
uint16_t funLength_; /* ES6 function length */
|
||||
/* ES6 function length. */
|
||||
uint16_t funLength_ = 0;
|
||||
|
||||
uint16_t nTypeSets_; /* number of type sets used in this script for
|
||||
dynamic type monitoring */
|
||||
/* Number of type sets used in this script for dynamic type monitoring. */
|
||||
uint16_t nTypeSets_ = 0;
|
||||
|
||||
// Bit fields.
|
||||
|
||||
@ -1032,129 +1034,148 @@ class JSScript : public js::gc::TenuredCell
|
||||
};
|
||||
|
||||
private:
|
||||
// The bits in this field indicate the presence/non-presence of several
|
||||
// optional arrays in |data|. See the comments above Create() for details.
|
||||
uint8_t hasArrayBits:ARRAY_KIND_BITS;
|
||||
struct BitFields
|
||||
{
|
||||
/*
|
||||
* Bit-fields can't have member initializers til C++2a, i.e. probably
|
||||
* C++20, so we can't initialize these to zero in place. Instead we
|
||||
* braced-init this to all zeroes in the JSScript constructor, then
|
||||
* custom-assign particular bit-fields in the constructor body.
|
||||
*/
|
||||
|
||||
// 1-bit fields.
|
||||
// The bits in this field indicate the presence/non-presence of several
|
||||
// optional arrays in |data|. See the comments above Create() for details.
|
||||
uint8_t hasArrayBits_ : ARRAY_KIND_BITS;
|
||||
|
||||
// No need for result value of last expression statement.
|
||||
bool noScriptRval_:1;
|
||||
/*
|
||||
* All remaining bit-fields are single-bit bools.
|
||||
*/
|
||||
|
||||
// Code is in strict mode.
|
||||
bool strict_:1;
|
||||
// No need for result value of last expression statement.
|
||||
bool noScriptRval_ : 1;
|
||||
|
||||
// Code has "use strict"; explicitly.
|
||||
bool explicitUseStrict_:1;
|
||||
// Code is in strict mode.
|
||||
bool strict_ : 1;
|
||||
|
||||
// True if the script has a non-syntactic scope on its dynamic scope chain.
|
||||
// That is, there are objects about which we know nothing between the
|
||||
// outermost syntactic scope and the global.
|
||||
bool hasNonSyntacticScope_:1;
|
||||
// Code has "use strict"; explicitly.
|
||||
bool explicitUseStrict_ : 1;
|
||||
|
||||
// see Parser::selfHostingMode.
|
||||
bool selfHosted_:1;
|
||||
// True if the script has a non-syntactic scope on its dynamic scope chain.
|
||||
// That is, there are objects about which we know nothing between the
|
||||
// outermost syntactic scope and the global.
|
||||
bool hasNonSyntacticScope_ : 1;
|
||||
|
||||
// See FunctionBox.
|
||||
bool bindingsAccessedDynamically_:1;
|
||||
bool funHasExtensibleScope_:1;
|
||||
// see Parser::selfHostingMode.
|
||||
bool selfHosted_ : 1;
|
||||
|
||||
// True if any formalIsAliased(i).
|
||||
bool funHasAnyAliasedFormal_:1;
|
||||
// See FunctionBox.
|
||||
bool bindingsAccessedDynamically_ : 1;
|
||||
bool funHasExtensibleScope_ : 1;
|
||||
|
||||
// Have warned about uses of undefined properties in this script.
|
||||
bool warnedAboutUndefinedProp_:1;
|
||||
// True if any formalIsAliased(i).
|
||||
bool funHasAnyAliasedFormal_ : 1;
|
||||
|
||||
// Script has singleton objects.
|
||||
bool hasSingletons_:1;
|
||||
// Have warned about uses of undefined properties in this script.
|
||||
bool warnedAboutUndefinedProp_ : 1;
|
||||
|
||||
// Script is a lambda to treat as running once or a global or eval script
|
||||
// that will only run once. Which one it is can be disambiguated by
|
||||
// checking whether function() is null.
|
||||
bool treatAsRunOnce_:1;
|
||||
// Script has singleton objects.
|
||||
bool hasSingletons_ : 1;
|
||||
|
||||
// If treatAsRunOnce, whether script has executed.
|
||||
bool hasRunOnce_:1;
|
||||
// Script is a lambda to treat as running once or a global or eval script
|
||||
// that will only run once. Which one it is can be disambiguated by
|
||||
// checking whether function() is null.
|
||||
bool treatAsRunOnce_ : 1;
|
||||
|
||||
// Script has been reused for a clone.
|
||||
bool hasBeenCloned_:1;
|
||||
// If treatAsRunOnce, whether script has executed.
|
||||
bool hasRunOnce_ : 1;
|
||||
|
||||
// Script came from eval(), and is still active.
|
||||
bool isActiveEval_:1;
|
||||
// Script has been reused for a clone.
|
||||
bool hasBeenCloned_ : 1;
|
||||
|
||||
// Script came from eval(), and is in eval cache.
|
||||
bool isCachedEval_:1;
|
||||
// Script came from eval(), and is still active.
|
||||
bool isActiveEval_ : 1;
|
||||
|
||||
// 'this', 'arguments' and f.apply() are used. This is likely to be a wrapper.
|
||||
bool isLikelyConstructorWrapper_:1;
|
||||
// Script came from eval(), and is in eval cache.
|
||||
bool isCachedEval_ : 1;
|
||||
|
||||
// IonMonkey compilation hints.
|
||||
bool failedBoundsCheck_:1; /* script has had hoisted bounds checks fail */
|
||||
bool failedShapeGuard_:1; /* script has had hoisted shape guard fail */
|
||||
bool hadFrequentBailouts_:1;
|
||||
bool hadOverflowBailout_:1;
|
||||
bool uninlineable_:1; /* explicitly marked as uninlineable */
|
||||
// 'this', 'arguments' and f.apply() are used. This is likely to be a wrapper.
|
||||
bool isLikelyConstructorWrapper_ : 1;
|
||||
|
||||
// Idempotent cache has triggered invalidation.
|
||||
bool invalidatedIdempotentCache_:1;
|
||||
// IonMonkey compilation hints.
|
||||
|
||||
// Lexical check did fail and bail out.
|
||||
bool failedLexicalCheck_:1;
|
||||
/* Script has had hoisted bounds checks fail. */
|
||||
bool failedBoundsCheck_ : 1;
|
||||
|
||||
// Script has an entry in JSCompartment::scriptCountsMap.
|
||||
bool hasScriptCounts_:1;
|
||||
/* Script has had hoisted shape guard fail. */
|
||||
bool failedShapeGuard_ : 1;
|
||||
|
||||
// Script has an entry in JSCompartment::debugScriptMap.
|
||||
bool hasDebugScript_:1;
|
||||
bool hadFrequentBailouts_ : 1;
|
||||
bool hadOverflowBailout_ : 1;
|
||||
|
||||
// Freeze constraints for stack type sets have been generated.
|
||||
bool hasFreezeConstraints_:1;
|
||||
/* Explicitly marked as uninlineable. */
|
||||
bool uninlineable_ : 1;
|
||||
|
||||
/* See comments below. */
|
||||
bool argsHasVarBinding_:1;
|
||||
bool needsArgsAnalysis_:1;
|
||||
bool needsArgsObj_:1;
|
||||
bool functionHasThisBinding_:1;
|
||||
bool functionHasExtraBodyVarScope_:1;
|
||||
// Idempotent cache has triggered invalidation.
|
||||
bool invalidatedIdempotentCache_ : 1;
|
||||
|
||||
// Whether the arguments object for this script, if it needs one, should be
|
||||
// mapped (alias formal parameters).
|
||||
bool hasMappedArgsObj_:1;
|
||||
// Lexical check did fail and bail out.
|
||||
bool failedLexicalCheck_ : 1;
|
||||
|
||||
// Generation for this script's TypeScript. If out of sync with the
|
||||
// TypeZone's generation, the TypeScript needs to be swept.
|
||||
//
|
||||
// This should be a uint32 but is instead a bool so that MSVC packs it
|
||||
// correctly.
|
||||
bool typesGeneration_:1;
|
||||
// Script has an entry in JSCompartment::scriptCountsMap.
|
||||
bool hasScriptCounts_ : 1;
|
||||
|
||||
// Do not relazify this script. This is used by the relazify() testing
|
||||
// function for scripts that are on the stack and also by the AutoDelazify
|
||||
// RAII class. Usually we don't relazify functions in compartments with
|
||||
// scripts on the stack, but the relazify() testing function overrides that,
|
||||
// and sometimes we're working with a cross-compartment function and need to
|
||||
// keep it from relazifying.
|
||||
bool doNotRelazify_:1;
|
||||
// Script has an entry in JSCompartment::debugScriptMap.
|
||||
bool hasDebugScript_ : 1;
|
||||
|
||||
// Script contains inner functions. Used to check if we can relazify the
|
||||
// script.
|
||||
bool hasInnerFunctions_:1;
|
||||
// Freeze constraints for stack type sets have been generated.
|
||||
bool hasFreezeConstraints_ : 1;
|
||||
|
||||
bool needsHomeObject_:1;
|
||||
/* See comments below. */
|
||||
bool argsHasVarBinding_ : 1;
|
||||
bool needsArgsAnalysis_ : 1;
|
||||
bool needsArgsObj_ : 1;
|
||||
bool functionHasThisBinding_ : 1;
|
||||
bool functionHasExtraBodyVarScope_ : 1;
|
||||
|
||||
bool isDerivedClassConstructor_:1;
|
||||
bool isDefaultClassConstructor_:1;
|
||||
// Whether the arguments object for this script, if it needs one, should be
|
||||
// mapped (alias formal parameters).
|
||||
bool hasMappedArgsObj_ : 1;
|
||||
|
||||
// True if this function is a generator function or async generator.
|
||||
bool isGenerator_:1;
|
||||
// Generation for this script's TypeScript. If out of sync with the
|
||||
// TypeZone's generation, the TypeScript needs to be swept.
|
||||
//
|
||||
// This should be a uint32 but is instead a bool so that MSVC packs it
|
||||
// correctly.
|
||||
bool typesGeneration_ : 1;
|
||||
|
||||
// True if this function is an async function or async generator.
|
||||
bool isAsync_:1;
|
||||
// Do not relazify this script. This is used by the relazify() testing
|
||||
// function for scripts that are on the stack and also by the AutoDelazify
|
||||
// RAII class. Usually we don't relazify functions in compartments with
|
||||
// scripts on the stack, but the relazify() testing function overrides that,
|
||||
// and sometimes we're working with a cross-compartment function and need to
|
||||
// keep it from relazifying.
|
||||
bool doNotRelazify_ : 1;
|
||||
|
||||
bool hasRest_:1;
|
||||
// Script contains inner functions. Used to check if we can relazify the
|
||||
// script.
|
||||
bool hasInnerFunctions_ : 1;
|
||||
|
||||
// True if the debugger's onNewScript hook has not yet been called.
|
||||
bool hideScriptFromDebugger_:1;
|
||||
bool needsHomeObject_ : 1;
|
||||
|
||||
bool isDerivedClassConstructor_ : 1;
|
||||
bool isDefaultClassConstructor_ : 1;
|
||||
|
||||
// True if this function is a generator function or async generator.
|
||||
bool isGenerator_ : 1;
|
||||
|
||||
// True if this function is an async function or async generator.
|
||||
bool isAsync_ : 1;
|
||||
|
||||
bool hasRest_ : 1;
|
||||
|
||||
// True if the debugger's onNewScript hook has not yet been called.
|
||||
bool hideScriptFromDebugger_ : 1;
|
||||
} bitFields_;
|
||||
|
||||
// Add padding so JSScript is gc::Cell aligned. Make padding protected
|
||||
// instead of private to suppress -Wunused-private-field compiler warnings.
|
||||
@ -1167,6 +1188,28 @@ class JSScript : public js::gc::TenuredCell
|
||||
// End of fields. Start methods.
|
||||
//
|
||||
|
||||
private:
|
||||
template <js::XDRMode mode>
|
||||
friend
|
||||
js::XDRResult
|
||||
js::XDRScript(js::XDRState<mode>* xdr, js::HandleScope enclosingScope,
|
||||
js::HandleScriptSourceObject sourceObject, js::HandleFunction fun,
|
||||
js::MutableHandleScript scriptp);
|
||||
|
||||
friend bool
|
||||
js::detail::CopyScript(JSContext* cx, js::HandleScript src, js::HandleScript dst,
|
||||
js::MutableHandle<JS::GCVector<js::Scope*>> scopes);
|
||||
|
||||
private:
|
||||
JSScript(JS::Realm* realm, uint8_t* stubEntry, const JS::ReadOnlyCompileOptions& options,
|
||||
js::HandleObject sourceObject, uint32_t bufStart, uint32_t bufEnd,
|
||||
uint32_t toStringStart, uint32_t toStringend);
|
||||
|
||||
static JSScript* createInitialized(JSContext* cx, const JS::ReadOnlyCompileOptions& options,
|
||||
js::HandleObject sourceObject,
|
||||
uint32_t bufStart, uint32_t bufEnd,
|
||||
uint32_t toStringStart, uint32_t toStringEnd);
|
||||
|
||||
public:
|
||||
static JSScript* Create(JSContext* cx,
|
||||
const JS::ReadOnlyCompileOptions& options,
|
||||
@ -1327,111 +1370,113 @@ class JSScript : public js::gc::TenuredCell
|
||||
}
|
||||
|
||||
bool noScriptRval() const {
|
||||
return noScriptRval_;
|
||||
return bitFields_.noScriptRval_;
|
||||
}
|
||||
|
||||
bool strict() const {
|
||||
return strict_;
|
||||
return bitFields_.strict_;
|
||||
}
|
||||
|
||||
bool explicitUseStrict() const { return explicitUseStrict_; }
|
||||
bool explicitUseStrict() const { return bitFields_.explicitUseStrict_; }
|
||||
|
||||
bool hasNonSyntacticScope() const {
|
||||
return hasNonSyntacticScope_;
|
||||
return bitFields_.hasNonSyntacticScope_;
|
||||
}
|
||||
|
||||
bool selfHosted() const { return selfHosted_; }
|
||||
bool bindingsAccessedDynamically() const { return bindingsAccessedDynamically_; }
|
||||
bool selfHosted() const { return bitFields_.selfHosted_; }
|
||||
bool bindingsAccessedDynamically() const { return bitFields_.bindingsAccessedDynamically_; }
|
||||
bool funHasExtensibleScope() const {
|
||||
return funHasExtensibleScope_;
|
||||
return bitFields_.funHasExtensibleScope_;
|
||||
}
|
||||
bool funHasAnyAliasedFormal() const {
|
||||
return funHasAnyAliasedFormal_;
|
||||
return bitFields_.funHasAnyAliasedFormal_;
|
||||
}
|
||||
|
||||
bool hasSingletons() const { return hasSingletons_; }
|
||||
bool hasSingletons() const { return bitFields_.hasSingletons_; }
|
||||
bool treatAsRunOnce() const {
|
||||
return treatAsRunOnce_;
|
||||
return bitFields_.treatAsRunOnce_;
|
||||
}
|
||||
bool hasRunOnce() const { return hasRunOnce_; }
|
||||
bool hasBeenCloned() const { return hasBeenCloned_; }
|
||||
bool hasRunOnce() const { return bitFields_.hasRunOnce_; }
|
||||
bool hasBeenCloned() const { return bitFields_.hasBeenCloned_; }
|
||||
|
||||
void setTreatAsRunOnce() { treatAsRunOnce_ = true; }
|
||||
void setHasRunOnce() { hasRunOnce_ = true; }
|
||||
void setHasBeenCloned() { hasBeenCloned_ = true; }
|
||||
void setTreatAsRunOnce() { bitFields_.treatAsRunOnce_ = true; }
|
||||
void setHasRunOnce() { bitFields_.hasRunOnce_ = true; }
|
||||
void setHasBeenCloned() { bitFields_.hasBeenCloned_ = true; }
|
||||
|
||||
bool isActiveEval() const { return isActiveEval_; }
|
||||
bool isCachedEval() const { return isCachedEval_; }
|
||||
bool isActiveEval() const { return bitFields_.isActiveEval_; }
|
||||
bool isCachedEval() const { return bitFields_.isCachedEval_; }
|
||||
|
||||
void cacheForEval() {
|
||||
MOZ_ASSERT(isActiveEval() && !isCachedEval());
|
||||
isActiveEval_ = false;
|
||||
isCachedEval_ = true;
|
||||
MOZ_ASSERT(isActiveEval());
|
||||
MOZ_ASSERT(!isCachedEval());
|
||||
bitFields_.isActiveEval_ = false;
|
||||
bitFields_.isCachedEval_ = true;
|
||||
// IsEvalCacheCandidate will make sure that there's nothing in this
|
||||
// script that would prevent reexecution even if isRunOnce is
|
||||
// true. So just pretend like we never ran this script.
|
||||
hasRunOnce_ = false;
|
||||
bitFields_.hasRunOnce_ = false;
|
||||
}
|
||||
|
||||
void uncacheForEval() {
|
||||
MOZ_ASSERT(isCachedEval() && !isActiveEval());
|
||||
isCachedEval_ = false;
|
||||
isActiveEval_ = true;
|
||||
MOZ_ASSERT(isCachedEval());
|
||||
MOZ_ASSERT(!isActiveEval());
|
||||
bitFields_.isCachedEval_ = false;
|
||||
bitFields_.isActiveEval_ = true;
|
||||
}
|
||||
|
||||
void setActiveEval() { isActiveEval_ = true; }
|
||||
void setActiveEval() { bitFields_.isActiveEval_ = true; }
|
||||
|
||||
bool isLikelyConstructorWrapper() const {
|
||||
return isLikelyConstructorWrapper_;
|
||||
return bitFields_.isLikelyConstructorWrapper_;
|
||||
}
|
||||
void setLikelyConstructorWrapper() { isLikelyConstructorWrapper_ = true; }
|
||||
void setLikelyConstructorWrapper() { bitFields_.isLikelyConstructorWrapper_ = true; }
|
||||
|
||||
bool failedBoundsCheck() const {
|
||||
return failedBoundsCheck_;
|
||||
return bitFields_.failedBoundsCheck_;
|
||||
}
|
||||
bool failedShapeGuard() const {
|
||||
return failedShapeGuard_;
|
||||
return bitFields_.failedShapeGuard_;
|
||||
}
|
||||
bool hadFrequentBailouts() const {
|
||||
return hadFrequentBailouts_;
|
||||
return bitFields_.hadFrequentBailouts_;
|
||||
}
|
||||
bool hadOverflowBailout() const {
|
||||
return hadOverflowBailout_;
|
||||
return bitFields_.hadOverflowBailout_;
|
||||
}
|
||||
bool uninlineable() const {
|
||||
return uninlineable_;
|
||||
return bitFields_.uninlineable_;
|
||||
}
|
||||
bool invalidatedIdempotentCache() const {
|
||||
return invalidatedIdempotentCache_;
|
||||
return bitFields_.invalidatedIdempotentCache_;
|
||||
}
|
||||
bool failedLexicalCheck() const {
|
||||
return failedLexicalCheck_;
|
||||
return bitFields_.failedLexicalCheck_;
|
||||
}
|
||||
bool isDefaultClassConstructor() const {
|
||||
return isDefaultClassConstructor_;
|
||||
return bitFields_.isDefaultClassConstructor_;
|
||||
}
|
||||
|
||||
void setFailedBoundsCheck() { failedBoundsCheck_ = true; }
|
||||
void setFailedShapeGuard() { failedShapeGuard_ = true; }
|
||||
void setHadFrequentBailouts() { hadFrequentBailouts_ = true; }
|
||||
void setHadOverflowBailout() { hadOverflowBailout_ = true; }
|
||||
void setUninlineable() { uninlineable_ = true; }
|
||||
void setInvalidatedIdempotentCache() { invalidatedIdempotentCache_ = true; }
|
||||
void setFailedLexicalCheck() { failedLexicalCheck_ = true; }
|
||||
void setIsDefaultClassConstructor() { isDefaultClassConstructor_ = true; }
|
||||
void setFailedBoundsCheck() { bitFields_.failedBoundsCheck_ = true; }
|
||||
void setFailedShapeGuard() { bitFields_.failedShapeGuard_ = true; }
|
||||
void setHadFrequentBailouts() { bitFields_.hadFrequentBailouts_ = true; }
|
||||
void setHadOverflowBailout() { bitFields_.hadOverflowBailout_ = true; }
|
||||
void setUninlineable() { bitFields_.uninlineable_ = true; }
|
||||
void setInvalidatedIdempotentCache() { bitFields_.invalidatedIdempotentCache_ = true; }
|
||||
void setFailedLexicalCheck() { bitFields_.failedLexicalCheck_ = true; }
|
||||
void setIsDefaultClassConstructor() { bitFields_.isDefaultClassConstructor_ = true; }
|
||||
|
||||
bool hasScriptCounts() const { return hasScriptCounts_; }
|
||||
bool hasScriptCounts() const { return bitFields_.hasScriptCounts_; }
|
||||
bool hasScriptName();
|
||||
|
||||
bool hasFreezeConstraints() const { return hasFreezeConstraints_; }
|
||||
void setHasFreezeConstraints() { hasFreezeConstraints_ = true; }
|
||||
bool hasFreezeConstraints() const { return bitFields_.hasFreezeConstraints_; }
|
||||
void setHasFreezeConstraints() { bitFields_.hasFreezeConstraints_ = true; }
|
||||
|
||||
bool warnedAboutUndefinedProp() const { return warnedAboutUndefinedProp_; }
|
||||
void setWarnedAboutUndefinedProp() { warnedAboutUndefinedProp_ = true; }
|
||||
bool warnedAboutUndefinedProp() const { return bitFields_.warnedAboutUndefinedProp_; }
|
||||
void setWarnedAboutUndefinedProp() { bitFields_.warnedAboutUndefinedProp_ = true; }
|
||||
|
||||
/* See ContextFlags::funArgumentsHasLocalBinding comment. */
|
||||
bool argumentsHasVarBinding() const {
|
||||
return argsHasVarBinding_;
|
||||
return bitFields_.argsHasVarBinding_;
|
||||
}
|
||||
void setArgumentsHasVarBinding();
|
||||
bool argumentsAliasesFormals() const {
|
||||
@ -1439,52 +1484,52 @@ class JSScript : public js::gc::TenuredCell
|
||||
}
|
||||
|
||||
js::GeneratorKind generatorKind() const {
|
||||
return isGenerator_ ? js::GeneratorKind::Generator : js::GeneratorKind::NotGenerator;
|
||||
return bitFields_.isGenerator_ ? js::GeneratorKind::Generator : js::GeneratorKind::NotGenerator;
|
||||
}
|
||||
bool isGenerator() const { return isGenerator_; }
|
||||
bool isGenerator() const { return bitFields_.isGenerator_; }
|
||||
void setGeneratorKind(js::GeneratorKind kind) {
|
||||
// A script only gets its generator kind set as part of initialization,
|
||||
// so it can only transition from not being a generator.
|
||||
MOZ_ASSERT(!isGenerator());
|
||||
isGenerator_ = kind == js::GeneratorKind::Generator;
|
||||
bitFields_.isGenerator_ = kind == js::GeneratorKind::Generator;
|
||||
}
|
||||
|
||||
js::FunctionAsyncKind asyncKind() const {
|
||||
return isAsync_
|
||||
return bitFields_.isAsync_
|
||||
? js::FunctionAsyncKind::AsyncFunction
|
||||
: js::FunctionAsyncKind::SyncFunction;
|
||||
}
|
||||
bool isAsync() const {
|
||||
return isAsync_;
|
||||
return bitFields_.isAsync_;
|
||||
}
|
||||
|
||||
void setAsyncKind(js::FunctionAsyncKind kind) {
|
||||
isAsync_ = kind == js::FunctionAsyncKind::AsyncFunction;
|
||||
bitFields_.isAsync_ = kind == js::FunctionAsyncKind::AsyncFunction;
|
||||
}
|
||||
|
||||
bool hasRest() const {
|
||||
return hasRest_;
|
||||
return bitFields_.hasRest_;
|
||||
}
|
||||
void setHasRest() {
|
||||
hasRest_ = true;
|
||||
bitFields_.hasRest_ = true;
|
||||
}
|
||||
|
||||
bool hideScriptFromDebugger() const {
|
||||
return hideScriptFromDebugger_;
|
||||
return bitFields_.hideScriptFromDebugger_;
|
||||
}
|
||||
void clearHideScriptFromDebugger() {
|
||||
hideScriptFromDebugger_ = false;
|
||||
bitFields_.hideScriptFromDebugger_ = false;
|
||||
}
|
||||
|
||||
void setNeedsHomeObject() {
|
||||
needsHomeObject_ = true;
|
||||
bitFields_.needsHomeObject_ = true;
|
||||
}
|
||||
bool needsHomeObject() const {
|
||||
return needsHomeObject_;
|
||||
return bitFields_.needsHomeObject_;
|
||||
}
|
||||
|
||||
bool isDerivedClassConstructor() const {
|
||||
return isDerivedClassConstructor_;
|
||||
return bitFields_.isDerivedClassConstructor_;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1497,21 +1542,21 @@ class JSScript : public js::gc::TenuredCell
|
||||
* maintain the invariant that needsArgsObj is only called after the script
|
||||
* has been analyzed.
|
||||
*/
|
||||
bool analyzedArgsUsage() const { return !needsArgsAnalysis_; }
|
||||
bool analyzedArgsUsage() const { return !bitFields_.needsArgsAnalysis_; }
|
||||
inline bool ensureHasAnalyzedArgsUsage(JSContext* cx);
|
||||
bool needsArgsObj() const {
|
||||
MOZ_ASSERT(analyzedArgsUsage());
|
||||
return needsArgsObj_;
|
||||
return bitFields_.needsArgsObj_;
|
||||
}
|
||||
void setNeedsArgsObj(bool needsArgsObj);
|
||||
static bool argumentsOptimizationFailed(JSContext* cx, js::HandleScript script);
|
||||
|
||||
bool hasMappedArgsObj() const {
|
||||
return hasMappedArgsObj_;
|
||||
return bitFields_.hasMappedArgsObj_;
|
||||
}
|
||||
|
||||
bool functionHasThisBinding() const {
|
||||
return functionHasThisBinding_;
|
||||
return bitFields_.functionHasThisBinding_;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1527,24 +1572,24 @@ class JSScript : public js::gc::TenuredCell
|
||||
}
|
||||
|
||||
uint32_t typesGeneration() const {
|
||||
return (uint32_t) typesGeneration_;
|
||||
return (uint32_t) bitFields_.typesGeneration_;
|
||||
}
|
||||
|
||||
void setTypesGeneration(uint32_t generation) {
|
||||
MOZ_ASSERT(generation <= 1);
|
||||
typesGeneration_ = (bool) generation;
|
||||
bitFields_.typesGeneration_ = (bool) generation;
|
||||
}
|
||||
|
||||
void setDoNotRelazify(bool b) {
|
||||
doNotRelazify_ = b;
|
||||
bitFields_.doNotRelazify_ = b;
|
||||
}
|
||||
|
||||
void setHasInnerFunctions(bool b) {
|
||||
hasInnerFunctions_ = b;
|
||||
bitFields_.hasInnerFunctions_ = b;
|
||||
}
|
||||
|
||||
bool hasInnerFunctions() const {
|
||||
return hasInnerFunctions_;
|
||||
return bitFields_.hasInnerFunctions_;
|
||||
}
|
||||
|
||||
bool hasAnyIonScript() const {
|
||||
@ -1609,11 +1654,11 @@ class JSScript : public js::gc::TenuredCell
|
||||
}
|
||||
|
||||
bool isRelazifiable() const {
|
||||
return (selfHosted() || lazyScript) && !hasInnerFunctions_ && !types_ &&
|
||||
return (selfHosted() || lazyScript) && !bitFields_.hasInnerFunctions_ && !types_ &&
|
||||
!isGenerator() && !isAsync() &&
|
||||
!isDefaultClassConstructor() &&
|
||||
!hasBaselineScript() && !hasAnyIonScript() &&
|
||||
!doNotRelazify_;
|
||||
!bitFields_.doNotRelazify_;
|
||||
}
|
||||
void setLazyScript(js::LazyScript* lazy) {
|
||||
lazyScript = lazy;
|
||||
@ -1739,8 +1784,8 @@ class JSScript : public js::gc::TenuredCell
|
||||
}
|
||||
|
||||
bool functionHasExtraBodyVarScope() const {
|
||||
MOZ_ASSERT_IF(functionHasExtraBodyVarScope_, functionHasParameterExprs());
|
||||
return functionHasExtraBodyVarScope_;
|
||||
MOZ_ASSERT_IF(bitFields_.functionHasExtraBodyVarScope_, functionHasParameterExprs());
|
||||
return bitFields_.functionHasExtraBodyVarScope_;
|
||||
}
|
||||
|
||||
js::VarScope* functionExtraBodyVarScope() const {
|
||||
@ -1820,10 +1865,12 @@ class JSScript : public js::gc::TenuredCell
|
||||
size_t sizeOfTypeScript(mozilla::MallocSizeOf mallocSizeOf) const;
|
||||
|
||||
bool hasArray(ArrayKind kind) const {
|
||||
return hasArrayBits & (1 << kind);
|
||||
return bitFields_.hasArrayBits_ & (1 << kind);
|
||||
}
|
||||
void setHasArray(ArrayKind kind) { bitFields_.hasArrayBits_ |= (1 << kind); }
|
||||
void cloneHasArray(JSScript* script) {
|
||||
bitFields_.hasArrayBits_ = script->bitFields_.hasArrayBits_;
|
||||
}
|
||||
void setHasArray(ArrayKind kind) { hasArrayBits |= (1 << kind); }
|
||||
void cloneHasArray(JSScript* script) { hasArrayBits = script->hasArrayBits; }
|
||||
|
||||
bool hasConsts() const { return hasArray(CONSTS); }
|
||||
bool hasObjects() const { return hasArray(OBJECTS); }
|
||||
@ -1998,7 +2045,7 @@ class JSScript : public js::gc::TenuredCell
|
||||
|
||||
public:
|
||||
bool hasBreakpointsAt(jsbytecode* pc);
|
||||
bool hasAnyBreakpointsOrStepMode() { return hasDebugScript_; }
|
||||
bool hasAnyBreakpointsOrStepMode() { return bitFields_.hasDebugScript_; }
|
||||
|
||||
// See comment above 'debugMode' in JSCompartment.h for explanation of
|
||||
// invariants of debuggee compartments, scripts, and frames.
|
||||
@ -2006,7 +2053,7 @@ class JSScript : public js::gc::TenuredCell
|
||||
|
||||
js::BreakpointSite* getBreakpointSite(jsbytecode* pc)
|
||||
{
|
||||
return hasDebugScript_ ? debugScript()->breakpoints[pcToOffset(pc)] : nullptr;
|
||||
return bitFields_.hasDebugScript_ ? debugScript()->breakpoints[pcToOffset(pc)] : nullptr;
|
||||
}
|
||||
|
||||
js::BreakpointSite* getOrCreateBreakpointSite(JSContext* cx, jsbytecode* pc);
|
||||
@ -2024,10 +2071,10 @@ class JSScript : public js::gc::TenuredCell
|
||||
bool incrementStepModeCount(JSContext* cx);
|
||||
void decrementStepModeCount(js::FreeOp* fop);
|
||||
|
||||
bool stepModeEnabled() { return hasDebugScript_ && !!debugScript()->stepMode; }
|
||||
bool stepModeEnabled() { return bitFields_.hasDebugScript_ && !!debugScript()->stepMode; }
|
||||
|
||||
#ifdef DEBUG
|
||||
uint32_t stepModeCount() { return hasDebugScript_ ? debugScript()->stepMode : 0; }
|
||||
uint32_t stepModeCount() { return bitFields_.hasDebugScript_ ? debugScript()->stepMode : 0; }
|
||||
#endif
|
||||
|
||||
void finalize(js::FreeOp* fop);
|
||||
|
@ -28,26 +28,21 @@
|
||||
|
||||
using namespace js;
|
||||
|
||||
using mozilla::PodZero;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// ObjectGroup
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
ObjectGroup::ObjectGroup(const Class* clasp, TaggedProto proto, JS::Realm* realm,
|
||||
ObjectGroupFlags initialFlags)
|
||||
: clasp_(clasp),
|
||||
proto_(proto),
|
||||
realm_(realm),
|
||||
flags_(initialFlags)
|
||||
{
|
||||
PodZero(this);
|
||||
|
||||
/* Windows may not appear on prototype chains. */
|
||||
MOZ_ASSERT_IF(proto.isObject(), !IsWindow(proto.toObject()));
|
||||
MOZ_ASSERT(JS::StringIsASCII(clasp->name));
|
||||
|
||||
this->clasp_ = clasp;
|
||||
this->proto_ = proto;
|
||||
this->realm_ = realm;
|
||||
this->flags_ = initialFlags;
|
||||
|
||||
setGeneration(zone()->types.generation);
|
||||
}
|
||||
|
||||
@ -1619,11 +1614,6 @@ ObjectGroup::findAllocationSite(JSContext* cx, ObjectGroup* group,
|
||||
// ObjectGroupCompartment
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
ObjectGroupCompartment::ObjectGroupCompartment()
|
||||
{
|
||||
PodZero(this);
|
||||
}
|
||||
|
||||
ObjectGroupCompartment::~ObjectGroupCompartment()
|
||||
{
|
||||
js_delete(defaultNewTable);
|
||||
|
@ -87,17 +87,97 @@ enum NewObjectKind {
|
||||
/* Type information about an object accessed by a script. */
|
||||
class ObjectGroup : public gc::TenuredCell
|
||||
{
|
||||
public:
|
||||
class Property;
|
||||
|
||||
private:
|
||||
/* Class shared by objects in this group. */
|
||||
const Class* clasp_; // set by constructor
|
||||
|
||||
/* Prototype shared by objects in this group. */
|
||||
GCPtr<TaggedProto> proto_; // set by constructor
|
||||
|
||||
/* Realm shared by objects in this group. */
|
||||
JS::Realm* realm_;; // set by constructor
|
||||
|
||||
/* Flags for this group. */
|
||||
ObjectGroupFlags flags_; // set by constructor
|
||||
|
||||
// If non-null, holds additional information about this object, whose
|
||||
// format is indicated by the object's addendum kind.
|
||||
void* addendum_ = nullptr;
|
||||
|
||||
/*
|
||||
* Properties of this object.
|
||||
*
|
||||
* The type sets in the properties of a group describe the possible values
|
||||
* that can be read out of that property in actual JS objects. In native
|
||||
* objects, property types account for plain data properties (those with a
|
||||
* slot and no getter or setter hook) and dense elements. In typed objects
|
||||
* and unboxed objects, property types account for object and value
|
||||
* properties and elements in the object, and expando properties in unboxed
|
||||
* objects.
|
||||
*
|
||||
* For accesses on these properties, the correspondence is as follows:
|
||||
*
|
||||
* 1. If the group has unknownProperties(), the possible properties and
|
||||
* value types for associated JSObjects are unknown.
|
||||
*
|
||||
* 2. Otherwise, for any |obj| in |group|, and any |id| which is a property
|
||||
* in |obj|, before obj->getProperty(id) the property in |group| for
|
||||
* |id| must reflect the result of the getProperty.
|
||||
*
|
||||
* There are several exceptions to this:
|
||||
*
|
||||
* 1. For properties of global JS objects which are undefined at the point
|
||||
* where the property was (lazily) generated, the property type set will
|
||||
* remain empty, and the 'undefined' type will only be added after a
|
||||
* subsequent assignment or deletion. After these properties have been
|
||||
* assigned a defined value, the only way they can become undefined
|
||||
* again is after such an assign or deletion.
|
||||
*
|
||||
* 2. Array lengths are special cased by the compiler and VM and are not
|
||||
* reflected in property types.
|
||||
*
|
||||
* 3. In typed objects (but not unboxed objects), the initial values of
|
||||
* properties (null pointers and undefined values) are not reflected in
|
||||
* the property types. These values are always possible when reading the
|
||||
* property.
|
||||
*
|
||||
* We establish these by using write barriers on calls to setProperty and
|
||||
* defineProperty which are on native properties, and on any jitcode which
|
||||
* might update the property with a new type.
|
||||
*/
|
||||
Property** propertySet = nullptr;
|
||||
|
||||
// END OF PROPERTIES
|
||||
|
||||
private:
|
||||
static inline uint32_t offsetOfClasp() {
|
||||
return offsetof(ObjectGroup, clasp_);
|
||||
}
|
||||
|
||||
static inline uint32_t offsetOfProto() {
|
||||
return offsetof(ObjectGroup, proto_);
|
||||
}
|
||||
|
||||
static inline uint32_t offsetOfRealm() {
|
||||
return offsetof(ObjectGroup, realm_);
|
||||
}
|
||||
|
||||
static inline uint32_t offsetOfFlags() {
|
||||
return offsetof(ObjectGroup, flags_);
|
||||
}
|
||||
|
||||
static inline uint32_t offsetOfAddendum() {
|
||||
return offsetof(ObjectGroup, addendum_);
|
||||
}
|
||||
|
||||
friend class gc::GCRuntime;
|
||||
friend class gc::GCTrace;
|
||||
|
||||
/* Class shared by objects in this group. */
|
||||
const Class* clasp_;
|
||||
|
||||
/* Prototype shared by objects in this group. */
|
||||
GCPtr<TaggedProto> proto_;
|
||||
|
||||
/* Realm shared by objects in this group. */
|
||||
JS::Realm* realm_;
|
||||
// See JSObject::offsetOfGroup() comment.
|
||||
friend class js::jit::MacroAssembler;
|
||||
|
||||
public:
|
||||
const Class* clasp() const {
|
||||
@ -156,10 +236,6 @@ class ObjectGroup : public gc::TenuredCell
|
||||
JSCompartment* maybeCompartment() const { return compartment(); }
|
||||
JS::Realm* realm() const { return realm_; }
|
||||
|
||||
private:
|
||||
/* Flags for this group. */
|
||||
ObjectGroupFlags flags_;
|
||||
|
||||
public:
|
||||
// Kinds of addendums which can be attached to ObjectGroups.
|
||||
enum AddendumKind {
|
||||
@ -191,10 +267,6 @@ class ObjectGroup : public gc::TenuredCell
|
||||
};
|
||||
|
||||
private:
|
||||
// If non-null, holds additional information about this object, whose
|
||||
// format is indicated by the object's addendum kind.
|
||||
void* addendum_;
|
||||
|
||||
void setAddendum(AddendumKind kind, void* addendum, bool writeBarrier = true);
|
||||
|
||||
AddendumKind addendumKind() const {
|
||||
@ -333,49 +405,6 @@ class ObjectGroup : public gc::TenuredCell
|
||||
static jsid getKey(Property* p) { return p->id; }
|
||||
};
|
||||
|
||||
private:
|
||||
/*
|
||||
* Properties of this object.
|
||||
*
|
||||
* The type sets in the properties of a group describe the possible values
|
||||
* that can be read out of that property in actual JS objects. In native
|
||||
* objects, property types account for plain data properties (those with a
|
||||
* slot and no getter or setter hook) and dense elements. In typed objects
|
||||
* and unboxed objects, property types account for object and value
|
||||
* properties and elements in the object, and expando properties in unboxed
|
||||
* objects.
|
||||
*
|
||||
* For accesses on these properties, the correspondence is as follows:
|
||||
*
|
||||
* 1. If the group has unknownProperties(), the possible properties and
|
||||
* value types for associated JSObjects are unknown.
|
||||
*
|
||||
* 2. Otherwise, for any |obj| in |group|, and any |id| which is a property
|
||||
* in |obj|, before obj->getProperty(id) the property in |group| for
|
||||
* |id| must reflect the result of the getProperty.
|
||||
*
|
||||
* There are several exceptions to this:
|
||||
*
|
||||
* 1. For properties of global JS objects which are undefined at the point
|
||||
* where the property was (lazily) generated, the property type set will
|
||||
* remain empty, and the 'undefined' type will only be added after a
|
||||
* subsequent assignment or deletion. After these properties have been
|
||||
* assigned a defined value, the only way they can become undefined
|
||||
* again is after such an assign or deletion.
|
||||
*
|
||||
* 2. Array lengths are special cased by the compiler and VM and are not
|
||||
* reflected in property types.
|
||||
*
|
||||
* 3. In typed objects (but not unboxed objects), the initial values of
|
||||
* properties (null pointers and undefined values) are not reflected in
|
||||
* the property types. These values are always possible when reading the
|
||||
* property.
|
||||
*
|
||||
* We establish these by using write barriers on calls to setProperty and
|
||||
* defineProperty which are on native properties, and on any jitcode which
|
||||
* might update the property with a new type.
|
||||
*/
|
||||
Property** propertySet;
|
||||
public:
|
||||
|
||||
inline ObjectGroup(const Class* clasp, TaggedProto proto, JS::Realm* realm,
|
||||
@ -464,30 +493,6 @@ class ObjectGroup : public gc::TenuredCell
|
||||
|
||||
static const JS::TraceKind TraceKind = JS::TraceKind::ObjectGroup;
|
||||
|
||||
private:
|
||||
// See JSObject::offsetOfGroup() comment.
|
||||
friend class js::jit::MacroAssembler;
|
||||
|
||||
static inline uint32_t offsetOfClasp() {
|
||||
return offsetof(ObjectGroup, clasp_);
|
||||
}
|
||||
|
||||
static inline uint32_t offsetOfProto() {
|
||||
return offsetof(ObjectGroup, proto_);
|
||||
}
|
||||
|
||||
static inline uint32_t offsetOfRealm() {
|
||||
return offsetof(ObjectGroup, realm_);
|
||||
}
|
||||
|
||||
static inline uint32_t offsetOfAddendum() {
|
||||
return offsetof(ObjectGroup, addendum_);
|
||||
}
|
||||
|
||||
static inline uint32_t offsetOfFlags() {
|
||||
return offsetof(ObjectGroup, flags_);
|
||||
}
|
||||
|
||||
public:
|
||||
const ObjectGroupFlags* addressOfFlags() const {
|
||||
return &flags_;
|
||||
@ -587,36 +592,9 @@ class ObjectGroup : public gc::TenuredCell
|
||||
// Structure used to manage the groups in a compartment.
|
||||
class ObjectGroupCompartment
|
||||
{
|
||||
friend class ObjectGroup;
|
||||
|
||||
private:
|
||||
class NewTable;
|
||||
|
||||
// Set of default 'new' or lazy groups in the compartment.
|
||||
NewTable* defaultNewTable;
|
||||
NewTable* lazyTable;
|
||||
|
||||
// Cache for defaultNewGroup. Purged on GC.
|
||||
class DefaultNewGroupCache
|
||||
{
|
||||
ObjectGroup* group_;
|
||||
JSObject* associated_;
|
||||
|
||||
public:
|
||||
DefaultNewGroupCache() { purge(); }
|
||||
|
||||
void purge() {
|
||||
group_ = nullptr;
|
||||
}
|
||||
void put(ObjectGroup* group, JSObject* associated) {
|
||||
group_ = group;
|
||||
associated_ = associated;
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_INLINE ObjectGroup* lookup(const Class* clasp, TaggedProto proto,
|
||||
JSObject* associated);
|
||||
};
|
||||
DefaultNewGroupCache defaultNewGroupCache;
|
||||
|
||||
struct ArrayObjectKey;
|
||||
using ArrayObjectTable = js::GCRekeyableHashMap<ArrayObjectKey,
|
||||
ReadBarrieredObjectGroup,
|
||||
@ -634,6 +612,34 @@ class ObjectGroupCompartment
|
||||
SystemAllocPolicy,
|
||||
PlainObjectTableSweepPolicy>;
|
||||
|
||||
class AllocationSiteTable;
|
||||
|
||||
private:
|
||||
// Set of default 'new' or lazy groups in the compartment.
|
||||
NewTable* defaultNewTable = nullptr;
|
||||
NewTable* lazyTable = nullptr;
|
||||
|
||||
// This cache is purged on GC.
|
||||
class DefaultNewGroupCache
|
||||
{
|
||||
ObjectGroup* group_;
|
||||
JSObject* associated_;
|
||||
|
||||
public:
|
||||
DefaultNewGroupCache() { purge(); }
|
||||
|
||||
void purge() {
|
||||
group_ = nullptr;
|
||||
}
|
||||
void put(ObjectGroup* group, JSObject* associated) {
|
||||
group_ = group;
|
||||
associated_ = associated;
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_INLINE ObjectGroup* lookup(const Class* clasp, TaggedProto proto,
|
||||
JSObject* associated);
|
||||
} defaultNewGroupCache = {};
|
||||
|
||||
// Tables for managing groups common to the contents of large script
|
||||
// singleton objects and JSON objects. These are vanilla ArrayObjects and
|
||||
// PlainObjects, so we distinguish the groups of different ones by looking
|
||||
@ -643,14 +649,11 @@ class ObjectGroupCompartment
|
||||
// and of the same element type will share a group. All singleton/JSON
|
||||
// objects which have the same shape and property types will also share a
|
||||
// group. We don't try to collate arrays or objects with type mismatches.
|
||||
ArrayObjectTable* arrayObjectTable;
|
||||
PlainObjectTable* plainObjectTable;
|
||||
|
||||
struct AllocationSiteKey;
|
||||
class AllocationSiteTable;
|
||||
ArrayObjectTable* arrayObjectTable = nullptr;
|
||||
PlainObjectTable* plainObjectTable = nullptr;
|
||||
|
||||
// Table for referencing types of objects keyed to an allocation site.
|
||||
AllocationSiteTable* allocationSiteTable;
|
||||
AllocationSiteTable* allocationSiteTable = nullptr;
|
||||
|
||||
// A single per-compartment ObjectGroup for all calls to StringSplitString.
|
||||
// StringSplitString is always called from self-hosted code, and conceptually
|
||||
@ -658,12 +661,19 @@ class ObjectGroupCompartment
|
||||
// unified type. Having a global group for this also allows us to remove
|
||||
// the hash-table lookup that would be required if we allocated this group
|
||||
// on the basis of call-site pc.
|
||||
ReadBarrieredObjectGroup stringSplitStringGroup;
|
||||
ReadBarrieredObjectGroup stringSplitStringGroup = {};
|
||||
|
||||
// END OF PROPERTIES
|
||||
|
||||
private:
|
||||
friend class ObjectGroup;
|
||||
|
||||
struct AllocationSiteKey;
|
||||
|
||||
public:
|
||||
struct NewEntry;
|
||||
|
||||
ObjectGroupCompartment();
|
||||
ObjectGroupCompartment() = default;
|
||||
~ObjectGroupCompartment();
|
||||
|
||||
void replaceAllocationSiteGroup(JSScript* script, jsbytecode* pc,
|
||||
|
@ -180,9 +180,6 @@ JSRuntime::JSRuntime(JSRuntime* parentRuntime)
|
||||
JS_COUNT_CTOR(JSRuntime);
|
||||
liveRuntimesCount++;
|
||||
|
||||
/* Initialize infallibly first, so we can goto bad and JS_DestroyRuntime. */
|
||||
|
||||
PodZero(&asmJSCacheOps);
|
||||
lcovOutput().init();
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,8 @@
|
||||
#include "mozilla/PodOperations.h"
|
||||
#include "mozilla/Sprintf.h"
|
||||
|
||||
#include <new>
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "builtin/String.h"
|
||||
|
||||
@ -872,10 +874,8 @@ TypeSet::IsTypeAboutToBeFinalized(TypeSet::Type* v)
|
||||
}
|
||||
|
||||
bool
|
||||
TypeSet::clone(LifoAlloc* alloc, TemporaryTypeSet* result) const
|
||||
TypeSet::cloneIntoUninitialized(LifoAlloc* alloc, TemporaryTypeSet* result) const
|
||||
{
|
||||
MOZ_ASSERT(result->empty());
|
||||
|
||||
unsigned objectCount = baseObjectCount();
|
||||
unsigned capacity = (objectCount >= 2) ? TypeHashSet::Capacity(objectCount) : 0;
|
||||
|
||||
@ -890,15 +890,15 @@ TypeSet::clone(LifoAlloc* alloc, TemporaryTypeSet* result) const
|
||||
PodCopy(newSet - 1, objectSet - 1, capacity + 1);
|
||||
}
|
||||
|
||||
new(result) TemporaryTypeSet(flags, capacity ? newSet : objectSet);
|
||||
new (result) TemporaryTypeSet(flags, capacity ? newSet : objectSet);
|
||||
return true;
|
||||
}
|
||||
|
||||
TemporaryTypeSet*
|
||||
TypeSet::clone(LifoAlloc* alloc) const
|
||||
{
|
||||
TemporaryTypeSet* res = alloc->new_<TemporaryTypeSet>();
|
||||
if (!res || !clone(alloc, res))
|
||||
TemporaryTypeSet* res = alloc->pod_malloc<TemporaryTypeSet>();
|
||||
if (!res || !cloneIntoUninitialized(alloc, res))
|
||||
return nullptr;
|
||||
return res;
|
||||
}
|
||||
@ -1167,10 +1167,9 @@ TypeScript::FreezeTypeSets(CompilerConstraintList* constraints, JSScript* script
|
||||
TemporaryTypeSet* types = alloc->newArrayUninitialized<TemporaryTypeSet>(count);
|
||||
if (!types)
|
||||
return false;
|
||||
PodZero(types, count);
|
||||
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
if (!existing[i].clone(alloc, &types[i]))
|
||||
if (!existing[i].cloneIntoUninitialized(alloc, &types[i]))
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -4547,7 +4546,7 @@ JSScript::sweepTypes(const js::AutoSweepTypeScript& sweep, AutoClearTypeInferenc
|
||||
|
||||
// Freeze constraints on stack type sets need to be regenerated the
|
||||
// next time the script is analyzed.
|
||||
hasFreezeConstraints_ = false;
|
||||
bitFields_.hasFreezeConstraints_ = false;
|
||||
|
||||
return;
|
||||
}
|
||||
@ -4562,7 +4561,7 @@ JSScript::sweepTypes(const js::AutoSweepTypeScript& sweep, AutoClearTypeInferenc
|
||||
if (oom->hadOOM()) {
|
||||
// It's possible we OOM'd while copying freeze constraints, so they
|
||||
// need to be regenerated.
|
||||
hasFreezeConstraints_ = false;
|
||||
bitFields_.hasFreezeConstraints_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -508,7 +508,10 @@ class TypeSet
|
||||
|
||||
// Clone a type set into an arbitrary allocator.
|
||||
TemporaryTypeSet* clone(LifoAlloc* alloc) const;
|
||||
bool clone(LifoAlloc* alloc, TemporaryTypeSet* result) const;
|
||||
|
||||
// |*result| is not even partly initialized when this function is called:
|
||||
// this function placement-new's its contents into existence.
|
||||
bool cloneIntoUninitialized(LifoAlloc* alloc, TemporaryTypeSet* result) const;
|
||||
|
||||
// Create a new TemporaryTypeSet where undefined and/or null has been filtered out.
|
||||
TemporaryTypeSet* filter(LifoAlloc* alloc, bool filterUndefined, bool filterNull) const;
|
||||
|
@ -14,7 +14,8 @@
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Compiler.h"
|
||||
#include "mozilla/FloatingPoint.h"
|
||||
#include "mozilla/PodOperations.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "jsnum.h"
|
||||
|
||||
@ -216,12 +217,24 @@ class UnsharedOps
|
||||
|
||||
template<typename T>
|
||||
static void podCopy(SharedMem<T*> dest, SharedMem<T*> src, size_t nelem) {
|
||||
mozilla::PodCopy(dest.unwrapUnshared(), src.unwrapUnshared(), nelem);
|
||||
// std::copy_n better matches the argument values/types of this
|
||||
// function, but as noted below it allows the input/output ranges to
|
||||
// overlap. std::copy does not, so use it so the compiler has extra
|
||||
// ability to optimize.
|
||||
const auto* first = src.unwrapUnshared();
|
||||
const auto* last = first + nelem;
|
||||
auto* result = dest.unwrapUnshared();
|
||||
std::copy(first, last, result);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void podMove(SharedMem<T*> dest, SharedMem<T*> src, size_t nelem) {
|
||||
mozilla::PodMove(dest.unwrapUnshared(), src.unwrapUnshared(), nelem);
|
||||
static void podMove(SharedMem<T*> dest, SharedMem<T*> src, size_t n) {
|
||||
// std::copy_n copies from |src| to |dest| starting from |src|, so
|
||||
// input/output ranges *may* permissibly overlap, as this function
|
||||
// allows.
|
||||
const auto* start = src.unwrapUnshared();
|
||||
auto* result = dest.unwrapUnshared();
|
||||
std::copy_n(start, n, result);
|
||||
}
|
||||
|
||||
static SharedMem<void*> extract(TypedArrayObject* obj) {
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "nsIWritablePropertyBag2.h"
|
||||
#include "nsSubDocumentFrame.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
#include "nsStubMutationObserver.h"
|
||||
|
||||
#include "nsILinkHandler.h"
|
||||
#include "nsISelectionListener.h"
|
||||
@ -203,6 +204,108 @@ private:
|
||||
nsDocumentViewer* mDocViewer;
|
||||
};
|
||||
|
||||
namespace viewer_detail {
|
||||
|
||||
/**
|
||||
* Mutation observer for use until we hand ourselves over to our SHEntry.
|
||||
*/
|
||||
class BFCachePreventionObserver final : public nsStubMutationObserver
|
||||
{
|
||||
public:
|
||||
explicit BFCachePreventionObserver(nsIDocument* aDocument)
|
||||
: mDocument(aDocument)
|
||||
{
|
||||
}
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED
|
||||
NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
|
||||
NS_DECL_NSIMUTATIONOBSERVER_NODEWILLBEDESTROYED
|
||||
|
||||
// Stop observing the document.
|
||||
void Disconnect();
|
||||
|
||||
private:
|
||||
~BFCachePreventionObserver() = default;
|
||||
|
||||
// Helper for the work that needs to happen when mutations happen.
|
||||
void MutationHappened();
|
||||
|
||||
nsIDocument* mDocument; // Weak; we get notified if it dies
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(BFCachePreventionObserver, nsIMutationObserver)
|
||||
|
||||
void
|
||||
BFCachePreventionObserver::CharacterDataChanged(nsIContent* aContent,
|
||||
const CharacterDataChangeInfo&)
|
||||
{
|
||||
MutationHappened();
|
||||
}
|
||||
|
||||
void
|
||||
BFCachePreventionObserver::AttributeChanged(Element* aElement,
|
||||
int32_t aNameSpaceID,
|
||||
nsAtom* aAttribute,
|
||||
int32_t aModType,
|
||||
const nsAttrValue* aOldValue)
|
||||
{
|
||||
MutationHappened();
|
||||
}
|
||||
|
||||
void
|
||||
BFCachePreventionObserver::ContentAppended(nsIContent* aFirstNewContent)
|
||||
{
|
||||
MutationHappened();
|
||||
}
|
||||
|
||||
void
|
||||
BFCachePreventionObserver::ContentInserted(nsIContent* aChild)
|
||||
{
|
||||
MutationHappened();
|
||||
}
|
||||
|
||||
void
|
||||
BFCachePreventionObserver::ContentRemoved(nsIContent* aChild,
|
||||
nsIContent* aPreviousSibling)
|
||||
{
|
||||
MutationHappened();
|
||||
}
|
||||
|
||||
void
|
||||
BFCachePreventionObserver::NodeWillBeDestroyed(const nsINode* aNode)
|
||||
{
|
||||
mDocument = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
BFCachePreventionObserver::Disconnect()
|
||||
{
|
||||
if (mDocument) {
|
||||
mDocument->RemoveMutationObserver(this);
|
||||
// It will no longer tell us when it goes away, so make sure we're
|
||||
// not holding a dangling ref.
|
||||
mDocument = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BFCachePreventionObserver::MutationHappened()
|
||||
{
|
||||
MOZ_ASSERT(mDocument,
|
||||
"How can we not have a document but be getting notified for mutations?");
|
||||
mDocument->DisallowBFCaching();
|
||||
Disconnect();
|
||||
}
|
||||
|
||||
|
||||
} // namespace viewer_detail
|
||||
|
||||
using viewer_detail::BFCachePreventionObserver;
|
||||
|
||||
//-------------------------------------------------------------
|
||||
class nsDocumentViewer final : public nsIContentViewer,
|
||||
@ -340,6 +443,9 @@ protected:
|
||||
|
||||
nsCOMPtr<nsIContentViewer> mPreviousViewer;
|
||||
nsCOMPtr<nsISHEntry> mSHEntry;
|
||||
// Observer that will prevent bfcaching if it gets notified. This
|
||||
// is non-null precisely when mSHEntry is non-null.
|
||||
RefPtr<BFCachePreventionObserver> mBFCachePreventionObserver;
|
||||
|
||||
nsIWidget* mParentWidget; // purposely won't be ref counted. May be null
|
||||
bool mAttachedToParent; // view is attached to the parent widget
|
||||
@ -1562,6 +1668,14 @@ nsDocumentViewer::Close(nsISHEntry *aSHEntry)
|
||||
if (!mDocument)
|
||||
return NS_OK;
|
||||
|
||||
if (mSHEntry) {
|
||||
if (mBFCachePreventionObserver) {
|
||||
mBFCachePreventionObserver->Disconnect();
|
||||
}
|
||||
mBFCachePreventionObserver = new BFCachePreventionObserver(mDocument);
|
||||
mDocument->AddMutationObserver(mBFCachePreventionObserver);
|
||||
}
|
||||
|
||||
#if defined(NS_PRINTING) && defined(NS_PRINT_PREVIEW)
|
||||
// Turn scripting back on
|
||||
// after PrintPreview had turned it off
|
||||
@ -1664,6 +1778,24 @@ nsDocumentViewer::Destroy()
|
||||
mAutoBeforeAndAfterPrint = nullptr;
|
||||
#endif
|
||||
|
||||
// We want to make sure to disconnect mBFCachePreventionObserver before we
|
||||
// Sanitize() below.
|
||||
if (mBFCachePreventionObserver) {
|
||||
mBFCachePreventionObserver->Disconnect();
|
||||
mBFCachePreventionObserver = nullptr;
|
||||
}
|
||||
|
||||
if (mSHEntry && mDocument && !mDocument->IsBFCachingAllowed()) {
|
||||
// Just drop the SHEntry now and pretend like we never even tried to bfcache
|
||||
// this viewer. This should only happen when someone calls
|
||||
// DisallowBFCaching() after CanSavePresentation() already ran. Ensure that
|
||||
// the SHEntry has no viewer and its state is synced up. We want to do this
|
||||
// via a stack reference, in case those calls mess with our members.
|
||||
nsCOMPtr<nsISHEntry> shEntry = mSHEntry.forget();
|
||||
shEntry->SetContentViewer(nullptr);
|
||||
shEntry->SyncPresentationState();
|
||||
}
|
||||
|
||||
// If we were told to put ourselves into session history instead of destroy
|
||||
// the presentation, do that now.
|
||||
if (mSHEntry) {
|
||||
@ -1674,8 +1806,6 @@ nsDocumentViewer::Destroy()
|
||||
mSHEntry->SetSticky(mIsSticky);
|
||||
mIsSticky = true;
|
||||
|
||||
bool savePresentation = mDocument ? mDocument->IsBFCachingAllowed() : true;
|
||||
|
||||
// Remove our root view from the view hierarchy.
|
||||
if (mPresShell) {
|
||||
nsViewManager *vm = mPresShell->GetViewManager();
|
||||
@ -1706,12 +1836,9 @@ nsDocumentViewer::Destroy()
|
||||
|
||||
// Grab a reference to mSHEntry before calling into things like
|
||||
// SyncPresentationState that might mess with our members.
|
||||
nsCOMPtr<nsISHEntry> shEntry = mSHEntry; // we'll need this below
|
||||
mSHEntry = nullptr;
|
||||
nsCOMPtr<nsISHEntry> shEntry = mSHEntry.forget(); // we'll need this below
|
||||
|
||||
if (savePresentation) {
|
||||
shEntry->SetContentViewer(this);
|
||||
}
|
||||
shEntry->SetContentViewer(this);
|
||||
|
||||
// Always sync the presentation state. That way even if someone screws up
|
||||
// and shEntry has no window state at this point we'll be ok; we just won't
|
||||
|
@ -584,7 +584,7 @@ nsNumberControlFrame::IsFocused() const
|
||||
// Normally this depends on the state of our anonymous text control (which
|
||||
// takes focus for us), but in the case that it does not have a frame we will
|
||||
// have focus ourself.
|
||||
return mTextField->AsElement()->State().HasState(NS_EVENT_STATE_FOCUS) ||
|
||||
return mTextField->State().HasState(NS_EVENT_STATE_FOCUS) ||
|
||||
mContent->AsElement()->State().HasState(NS_EVENT_STATE_FOCUS);
|
||||
}
|
||||
|
||||
|
@ -5990,6 +5990,11 @@ nsGridContainerFrame::Reflow(nsPresContext* aPresContext,
|
||||
computedISize, bSize);
|
||||
|
||||
if (!prevInFlow) {
|
||||
if (computedBSize == NS_AUTOHEIGHT && stylePos->mRowGap.HasPercent()) {
|
||||
// Re-resolve the row-gap now that we know our intrinsic block-size.
|
||||
gridReflowInput.mRows.mGridGap =
|
||||
nsLayoutUtils::ResolveGapToLength(stylePos->mRowGap, bSize);
|
||||
}
|
||||
// Apply 'align/justify-content' to the grid.
|
||||
// CalculateTrackSizes did the columns.
|
||||
gridReflowInput.mRows.AlignJustifyContent(stylePos, wm, contentArea.Size(wm));
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user