Merge inbound to mozilla-central. a=merge

This commit is contained in:
Margareta Eliza Balazs 2018-05-19 12:39:28 +03:00
commit 0bb5e5ba36
142 changed files with 2192 additions and 2401 deletions

View File

@ -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

View File

@ -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 {

View File

@ -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();

View File

@ -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;

View File

@ -94,7 +94,7 @@ function updatePreview(target, editor) {
match = (0, _ast.findBestMatchExpression)(symbols, tokenPos);
}
if (!match || !match.expression) {
if (!match) {
return;
}

View File

@ -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 || {};

View File

@ -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();
}
}

View File

@ -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());
}

View File

@ -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)
};
};

View File

@ -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))];
})];
}

View File

@ -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"

View File

@ -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);

View File

@ -18,5 +18,6 @@ DevToolsModules(
'PreviewFunction.js',
'ResultList.js',
'SearchInput.js',
'SourceIcon.js',
'Svg.js',
)

View File

@ -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;
}

View File

@ -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: {

View File

@ -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);

View File

@ -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.

View File

@ -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 });
}

View File

@ -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);

View File

@ -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());
}

View File

@ -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 });
}

View File

@ -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/);

View File

@ -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);

View File

@ -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);

View File

@ -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");

View File

@ -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()"
]);
}
);
});

View File

@ -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();
}

View File

@ -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();

View File

@ -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);

View File

@ -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);

View File

@ -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"
);
});

View File

@ -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);

View File

@ -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");

View File

@ -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)"
});
});

View File

@ -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");

View File

@ -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");

View File

@ -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);
});

View File

@ -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 };

View File

@ -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,

View File

@ -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"`]
);
});

View File

@ -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);
});

View File

@ -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,

View File

@ -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,

View File

@ -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");

View File

@ -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];

View File

@ -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"
);

View File

@ -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"
);

View File

@ -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");

View File

@ -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");

View File

@ -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");

View File

@ -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");

View File

@ -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");

View File

@ -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>

View File

@ -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/";

View File

@ -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();
}
}
}

View File

@ -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

View File

@ -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 = [];

View File

@ -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();

View File

@ -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.

View File

@ -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;

View File

@ -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 },

View File

@ -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)
{
}

View File

@ -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:

View File

@ -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))
{
}

View File

@ -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,

View File

@ -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 =

View File

@ -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.

View File

@ -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;

View File

@ -210,6 +210,10 @@ DOMInterfaces = {
'binaryNames': { 'ownerRule': 'DOMOwnerRule' },
},
'CustomElementRegistry': {
'implicitJSContext': ['define'],
},
'DedicatedWorkerGlobalScope': {
'headerFile': 'mozilla/dom/WorkerScope.h',
},

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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;
};

View File

@ -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);

View File

@ -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.

View File

@ -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;
}

View File

@ -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) {

View File

@ -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;
}

View File

@ -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()
{

View File

@ -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;
}

View File

@ -41,6 +41,7 @@ namespace jit {
_(GuardAndGetIndexFromString) \
_(GuardIndexIsNonNegative) \
_(GuardTagNotEqual) \
_(LoadObject) \
_(LoadProto) \
_(LoadEnclosingEnvironment) \
_(LoadWrapperTarget) \

View File

@ -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;

View File

@ -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()
{

View File

@ -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) {

View File

@ -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)

View File

@ -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;

View File

@ -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();
}
}

View File

@ -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

View File

@ -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 */

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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);

View File

@ -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,

View File

@ -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();
}

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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) {

View File

@ -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

View File

@ -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);
}

View File

@ -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