зеркало из https://github.com/mozilla/gecko-dev.git
Merge inbound to mozilla-central. a=merge
This commit is contained in:
Коммит
d117255a14
|
@ -51,7 +51,6 @@ var whitelist = [
|
|||
{file: "chrome://pippki/content/load_device.xul"},
|
||||
|
||||
// Add-on compat
|
||||
{file: "chrome://global/content/XPCNativeWrapper.js"},
|
||||
{file: "chrome://global/locale/brand.dtd"},
|
||||
|
||||
// The l10n build system can't package string files only for some platforms.
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
This is the debugger.html project output.
|
||||
See https://github.com/devtools-html/debugger.html
|
||||
|
||||
Version 28.0
|
||||
Version 29.0
|
||||
|
||||
Comparison: https://github.com/devtools-html/debugger.html/compare/release-28...release-27
|
||||
Comparison: https://github.com/devtools-html/debugger.html/compare/release-28...release-29
|
||||
|
||||
Packages:
|
||||
- babel-plugin-transform-es2015-modules-commonjs @6.26.0
|
||||
|
|
|
@ -1218,6 +1218,7 @@ html[dir="rtl"] .tree-node img.arrow {
|
|||
.sources-list {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.sources-list .tree:focus {
|
||||
|
@ -3982,6 +3983,10 @@ html .welcomebox .toggle-button-end.collapsed {
|
|||
border-bottom: 1px solid var(--theme-splitter-color);
|
||||
}
|
||||
|
||||
.result-list.small li {
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.result-list li:hover {
|
||||
background: var(--theme-tab-toolbar-background);
|
||||
}
|
||||
|
|
|
@ -5405,6 +5405,7 @@ var _extends = Object.assign || function (target) { for (var i = 1; i < argument
|
|||
*/
|
||||
|
||||
exports.getPauseReason = getPauseReason;
|
||||
exports.getPauseCommand = getPauseCommand;
|
||||
exports.isStepping = isStepping;
|
||||
exports.isPaused = isPaused;
|
||||
exports.getPreviousPauseFrameLocation = getPreviousPauseFrameLocation;
|
||||
|
@ -5414,6 +5415,7 @@ exports.getIsWaitingOnBreak = getIsWaitingOnBreak;
|
|||
exports.getShouldPauseOnExceptions = getShouldPauseOnExceptions;
|
||||
exports.getShouldIgnoreCaughtExceptions = getShouldIgnoreCaughtExceptions;
|
||||
exports.getCanRewind = getCanRewind;
|
||||
exports.getExtra = getExtra;
|
||||
exports.getFrames = getFrames;
|
||||
exports.getGeneratedFrameScope = getGeneratedFrameScope;
|
||||
exports.getOriginalFrameScope = getOriginalFrameScope;
|
||||
|
@ -5435,6 +5437,7 @@ var _prefs = __webpack_require__(226);
|
|||
var _sources = __webpack_require__(1369);
|
||||
|
||||
const createPauseState = exports.createPauseState = () => ({
|
||||
extra: {},
|
||||
why: null,
|
||||
isWaitingOnBreak: false,
|
||||
frames: undefined,
|
||||
|
@ -5449,7 +5452,7 @@ const createPauseState = exports.createPauseState = () => ({
|
|||
shouldIgnoreCaughtExceptions: _prefs.prefs.ignoreCaughtExceptions,
|
||||
canRewind: false,
|
||||
debuggeeUrl: "",
|
||||
command: "",
|
||||
command: null,
|
||||
previousLocation: null
|
||||
});
|
||||
|
||||
|
@ -5495,7 +5498,7 @@ function update(state = createPauseState(), action) {
|
|||
|
||||
case "ADD_SCOPES":
|
||||
{
|
||||
const { frame, status, value } = action;
|
||||
const { frame, extra, status, value } = action;
|
||||
const selectedFrameId = frame.id;
|
||||
|
||||
const generated = _extends({}, state.frameScopes.generated, {
|
||||
|
@ -5505,6 +5508,7 @@ function update(state = createPauseState(), action) {
|
|||
}
|
||||
});
|
||||
return _extends({}, state, {
|
||||
extra: extra,
|
||||
frameScopes: _extends({}, state.frameScopes, {
|
||||
generated
|
||||
})
|
||||
|
@ -5578,7 +5582,7 @@ function update(state = createPauseState(), action) {
|
|||
return action.status === "start" ? _extends({}, state, emptyPauseState, {
|
||||
command: action.command,
|
||||
previousLocation: buildPreviousLocation(state, action)
|
||||
}) : _extends({}, state, { command: "" });
|
||||
}) : _extends({}, state, { command: null });
|
||||
}
|
||||
|
||||
case "RESUME":
|
||||
|
@ -5588,7 +5592,7 @@ function update(state = createPauseState(), action) {
|
|||
|
||||
case "EVALUATE_EXPRESSION":
|
||||
return _extends({}, state, {
|
||||
command: action.status === "start" ? "expression" : ""
|
||||
command: action.status === "start" ? "expression" : null
|
||||
});
|
||||
|
||||
case "NAVIGATE":
|
||||
|
@ -5635,8 +5639,12 @@ function getPauseReason(state) {
|
|||
return state.pause.why;
|
||||
}
|
||||
|
||||
function getPauseCommand(state) {
|
||||
return state.pause && state.pause.command;
|
||||
}
|
||||
|
||||
function isStepping(state) {
|
||||
return ["stepIn", "stepOver", "stepOut"].includes(state.pause.command);
|
||||
return ["stepIn", "stepOver", "stepOut"].includes(getPauseCommand(state));
|
||||
}
|
||||
|
||||
function isPaused(state) {
|
||||
|
@ -5671,6 +5679,10 @@ function getCanRewind(state) {
|
|||
return state.pause.canRewind;
|
||||
}
|
||||
|
||||
function getExtra(state) {
|
||||
return state.pause.extra;
|
||||
}
|
||||
|
||||
function getFrames(state) {
|
||||
return state.pause.frames;
|
||||
}
|
||||
|
@ -6388,16 +6400,14 @@ exports.setPausePoints = setPausePoints;
|
|||
|
||||
var _selectors = __webpack_require__(3590);
|
||||
|
||||
var _pause = __webpack_require__(1639);
|
||||
|
||||
var _setInScopeLines = __webpack_require__(1781);
|
||||
|
||||
var _parser = __webpack_require__(1365);
|
||||
|
||||
var _promise = __webpack_require__(1653);
|
||||
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
|
||||
|
||||
function setSourceMetaData(sourceId) {
|
||||
return async ({ dispatch, getState }) => {
|
||||
const source = (0, _selectors.getSource)(getState(), sourceId);
|
||||
|
@ -6414,7 +6424,9 @@ function setSourceMetaData(sourceId) {
|
|||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
} /* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
|
||||
|
||||
function setSymbols(sourceId) {
|
||||
return async ({ dispatch, getState }) => {
|
||||
|
@ -6429,6 +6441,10 @@ function setSymbols(sourceId) {
|
|||
[_promise.PROMISE]: (0, _parser.getSymbols)(source.id)
|
||||
});
|
||||
|
||||
if ((0, _selectors.isPaused)(getState())) {
|
||||
await dispatch((0, _pause.mapFrames)());
|
||||
}
|
||||
|
||||
await dispatch(setPausePoints(sourceId));
|
||||
await dispatch(setSourceMetaData(sourceId));
|
||||
};
|
||||
|
@ -7712,45 +7728,16 @@ module.exports = {
|
|||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.containsPosition = containsPosition;
|
||||
exports.findClosestScope = findClosestScope;
|
||||
exports.getASTLocation = getASTLocation;
|
||||
exports.findScopeByName = findScopeByName;
|
||||
|
||||
var _parser = __webpack_require__(1365);
|
||||
|
||||
function containsPosition(a, b) {
|
||||
const startsBefore = a.start.line < b.line || a.start.line === b.line && a.start.column <= b.column;
|
||||
const endsAfter = a.end.line > b.line || a.end.line === b.line && a.end.column >= b.column;
|
||||
var _ast = __webpack_require__(1638);
|
||||
|
||||
return startsBefore && endsAfter;
|
||||
} /* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
|
||||
|
||||
function findClosestScope(functions, location) {
|
||||
return functions.reduce((found, currNode) => {
|
||||
if (currNode.name === "anonymous" || !containsPosition(currNode.location, {
|
||||
line: location.line,
|
||||
column: location.column || 0
|
||||
})) {
|
||||
return found;
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
return currNode;
|
||||
}
|
||||
|
||||
if (found.location.start.line > currNode.location.start.line) {
|
||||
return found;
|
||||
}
|
||||
if (found.location.start.line === currNode.location.start.line && found.location.start.column > currNode.location.start.column) {
|
||||
return found;
|
||||
}
|
||||
|
||||
return currNode;
|
||||
}, null);
|
||||
}
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
|
||||
|
||||
function getASTLocation(source, symbols, location) {
|
||||
if (source.isWasm || !symbols || symbols.loading) {
|
||||
|
@ -7759,7 +7746,7 @@ function getASTLocation(source, symbols, location) {
|
|||
|
||||
const functions = [...symbols.functions];
|
||||
|
||||
const scope = findClosestScope(functions, location);
|
||||
const scope = (0, _ast.findClosestFunction)(functions, location);
|
||||
if (scope) {
|
||||
// we only record the line, but at some point we may
|
||||
// also do column offsets
|
||||
|
@ -21930,7 +21917,7 @@ var _clipboard = __webpack_require__(1388);
|
|||
|
||||
var _function = __webpack_require__(1597);
|
||||
|
||||
var _astBreakpointLocation = __webpack_require__(1416);
|
||||
var _ast = __webpack_require__(1638);
|
||||
|
||||
var _editor = __webpack_require__(1358);
|
||||
|
||||
|
@ -22138,8 +22125,8 @@ exports.default = (0, _reactRedux.connect)(state => {
|
|||
selectedSource,
|
||||
hasPrettyPrint: !!(0, _selectors.getPrettySource)(state, selectedSource.get("id")),
|
||||
contextMenu: (0, _selectors.getContextMenu)(state),
|
||||
getFunctionText: line => (0, _function.findFunctionText)(line, selectedSource.toJS(), (0, _selectors.getSymbols)(state, selectedSource.toJS())),
|
||||
getFunctionLocation: line => (0, _astBreakpointLocation.findClosestScope)((0, _selectors.getSymbols)(state, selectedSource.toJS()).functions, {
|
||||
getFunctionText: line => (0, _function.findFunctionText)(line, selectedSource.toJS(), (0, _selectors.getSymbols)(state, selectedSource)),
|
||||
getFunctionLocation: line => (0, _ast.findClosestFunction)((0, _selectors.getSymbols)(state, selectedSource).functions, {
|
||||
line,
|
||||
column: Infinity
|
||||
})
|
||||
|
@ -22167,7 +22154,7 @@ Object.defineProperty(exports, "__esModule", {
|
|||
});
|
||||
exports.findFunctionText = findFunctionText;
|
||||
|
||||
var _astBreakpointLocation = __webpack_require__(1416);
|
||||
var _ast = __webpack_require__(1638);
|
||||
|
||||
var _indentation = __webpack_require__(1438);
|
||||
|
||||
|
@ -22176,7 +22163,10 @@ var _indentation = __webpack_require__(1438);
|
|||
* file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
|
||||
|
||||
function findFunctionText(line, source, symbols) {
|
||||
const func = (0, _astBreakpointLocation.findClosestScope)(symbols.functions, { line, column: Infinity });
|
||||
const func = (0, _ast.findClosestFunction)(symbols.functions, {
|
||||
line,
|
||||
column: Infinity
|
||||
});
|
||||
if (!func) {
|
||||
return null;
|
||||
}
|
||||
|
@ -22471,6 +22461,10 @@ var _BreakpointsDropdown = __webpack_require__(1790);
|
|||
|
||||
var _BreakpointsDropdown2 = _interopRequireDefault(_BreakpointsDropdown);
|
||||
|
||||
var _FrameworkComponent = __webpack_require__(3623);
|
||||
|
||||
var _FrameworkComponent2 = _interopRequireDefault(_FrameworkComponent);
|
||||
|
||||
var _ChromeScopes = __webpack_require__(1610);
|
||||
|
||||
var _ChromeScopes2 = _interopRequireDefault(_ChromeScopes);
|
||||
|
@ -22483,11 +22477,9 @@ __webpack_require__(1342);
|
|||
|
||||
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/>. */
|
||||
|
||||
const Scopes = _prefs.features.chromeScopes ? _ChromeScopes2.default : _Scopes3.default;
|
||||
const Scopes = _prefs.features.chromeScopes ? _ChromeScopes2.default : _Scopes3.default; /* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
|
||||
|
||||
function debugBtn(onClick, type, className, tooltip) {
|
||||
return _react2.default.createElement(
|
||||
|
@ -22558,6 +22550,20 @@ class SecondaryPanes extends _react.Component {
|
|||
};
|
||||
}
|
||||
|
||||
getComponentItem() {
|
||||
const { extra: { react } } = this.props;
|
||||
|
||||
return {
|
||||
header: react.displayName,
|
||||
className: "component-pane",
|
||||
component: _react2.default.createElement(_FrameworkComponent2.default, null),
|
||||
opened: _prefs.prefs.componentVisible,
|
||||
onToggle: opened => {
|
||||
_prefs.prefs.componentVisible = opened;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
getWatchItem() {
|
||||
return {
|
||||
header: L10N.getStr("watchExpressions.header"),
|
||||
|
@ -22625,7 +22631,7 @@ class SecondaryPanes extends _react.Component {
|
|||
}
|
||||
|
||||
getStartItems() {
|
||||
const { workers } = this.props;
|
||||
const { extra, workers } = this.props;
|
||||
|
||||
const items = [];
|
||||
if (this.props.horizontal) {
|
||||
|
@ -22640,7 +22646,12 @@ class SecondaryPanes extends _react.Component {
|
|||
|
||||
if (this.props.hasFrames) {
|
||||
items.push(this.getCallStackItem());
|
||||
|
||||
if (this.props.horizontal) {
|
||||
if (extra && extra.react) {
|
||||
items.push(this.getComponentItem());
|
||||
}
|
||||
|
||||
items.push(this.getScopeItem());
|
||||
}
|
||||
}
|
||||
|
@ -22661,7 +22672,7 @@ class SecondaryPanes extends _react.Component {
|
|||
}
|
||||
|
||||
getEndItems() {
|
||||
const { workers } = this.props;
|
||||
const { extra, workers } = this.props;
|
||||
|
||||
let items = [];
|
||||
|
||||
|
@ -22675,6 +22686,10 @@ class SecondaryPanes extends _react.Component {
|
|||
|
||||
items.push(this.getWatchItem());
|
||||
|
||||
if (extra && extra.react) {
|
||||
items.push(this.getComponentItem());
|
||||
}
|
||||
|
||||
if (this.props.hasFrames) {
|
||||
items = [...items, this.getScopeItem()];
|
||||
}
|
||||
|
@ -22728,6 +22743,7 @@ SecondaryPanes.contextTypes = {
|
|||
};
|
||||
|
||||
exports.default = (0, _reactRedux.connect)(state => ({
|
||||
extra: (0, _selectors.getExtra)(state),
|
||||
hasFrames: !!(0, _selectors.getTopFrame)(state),
|
||||
breakpoints: (0, _selectors.getBreakpoints)(state),
|
||||
breakpointsDisabled: (0, _selectors.getBreakpointsDisabled)(state),
|
||||
|
@ -26375,6 +26391,8 @@ Object.defineProperty(exports, "__esModule", {
|
|||
});
|
||||
exports.findBestMatchExpression = findBestMatchExpression;
|
||||
exports.findEmptyLines = findEmptyLines;
|
||||
exports.containsPosition = containsPosition;
|
||||
exports.findClosestFunction = findClosestFunction;
|
||||
|
||||
var _lodash = __webpack_require__(2);
|
||||
|
||||
|
@ -26410,6 +26428,37 @@ function findEmptyLines(selectedSource, pausePoints) {
|
|||
return (0, _lodash.without)(sourceLines, ...breakpointLines);
|
||||
}
|
||||
|
||||
function containsPosition(a, b) {
|
||||
const startsBefore = a.start.line < b.line || a.start.line === b.line && a.start.column <= b.column;
|
||||
const endsAfter = a.end.line > b.line || a.end.line === b.line && a.end.column >= b.column;
|
||||
|
||||
return startsBefore && endsAfter;
|
||||
}
|
||||
|
||||
function findClosestFunction(functions, location) {
|
||||
return functions.reduce((found, currNode) => {
|
||||
if (currNode.name === "anonymous" || !containsPosition(currNode.location, {
|
||||
line: location.line,
|
||||
column: location.column || 0
|
||||
})) {
|
||||
return found;
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
return currNode;
|
||||
}
|
||||
|
||||
if (found.location.start.line > currNode.location.start.line) {
|
||||
return found;
|
||||
}
|
||||
if (found.location.start.line === currNode.location.start.line && found.location.start.column > currNode.location.start.column) {
|
||||
return found;
|
||||
}
|
||||
|
||||
return currNode;
|
||||
}, null);
|
||||
}
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 1639:
|
||||
|
@ -27179,7 +27228,10 @@ class QuickOpenModal extends _react.Component {
|
|||
let results = functions;
|
||||
if (this.isVariableQuery()) {
|
||||
results = variables;
|
||||
} else {
|
||||
results = results.filter(result => result.title !== "anonymous");
|
||||
}
|
||||
|
||||
if (query === "@" || query === "#") {
|
||||
return this.setState({ results });
|
||||
}
|
||||
|
@ -27595,8 +27647,14 @@ var _selectors = __webpack_require__(3590);
|
|||
|
||||
var _mapScopes = __webpack_require__(1634);
|
||||
|
||||
var _preview = __webpack_require__(1786);
|
||||
|
||||
var _promise = __webpack_require__(1653);
|
||||
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
|
||||
|
||||
function fetchScopes() {
|
||||
return async function ({ dispatch, getState, client, sourceMaps }) {
|
||||
const frame = (0, _selectors.getSelectedFrame)(getState());
|
||||
|
@ -27604,17 +27662,18 @@ function fetchScopes() {
|
|||
return;
|
||||
}
|
||||
|
||||
const extra = await dispatch((0, _preview.getExtra)("this;", frame.this, frame));
|
||||
|
||||
const scopes = dispatch({
|
||||
type: "ADD_SCOPES",
|
||||
frame,
|
||||
extra,
|
||||
[_promise.PROMISE]: client.getFrameScopes(frame)
|
||||
});
|
||||
|
||||
await dispatch((0, _mapScopes.mapScopes)(scopes, frame));
|
||||
};
|
||||
} /* 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/>. */
|
||||
}
|
||||
|
||||
/***/ }),
|
||||
|
||||
|
@ -30168,6 +30227,7 @@ var _extends = Object.assign || function (target) { for (var i = 1; i < argument
|
|||
* 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/>. */
|
||||
|
||||
exports.getExtra = getExtra;
|
||||
exports.updatePreview = updatePreview;
|
||||
exports.setPreview = setPreview;
|
||||
exports.clearPreview = clearPreview;
|
||||
|
@ -30242,6 +30302,14 @@ function isInvalidTarget(target) {
|
|||
return invalidTarget || invalidToken || invaildType;
|
||||
}
|
||||
|
||||
function getExtra(expression, result, selectedFrame) {
|
||||
return async ({ dispatch, getState, client, sourceMaps }) => {
|
||||
const extra = await getExtraProps(expression, result, expr => client.evaluateInFrame(selectedFrame.id, expr));
|
||||
|
||||
return extra;
|
||||
};
|
||||
}
|
||||
|
||||
function updatePreview(target, editor) {
|
||||
return ({ dispatch, getState, client, sourceMaps }) => {
|
||||
const tokenPos = (0, _editor.getTokenLocation)(editor.codeMirror, target);
|
||||
|
@ -30322,7 +30390,7 @@ function setPreview(expression, location, tokenPos, cursorPos) {
|
|||
return;
|
||||
}
|
||||
|
||||
const extra = await getExtraProps(expression, result, expr => client.evaluateInFrame(selectedFrame.id, expr));
|
||||
const extra = await dispatch(getExtra(expression, result, selectedFrame));
|
||||
|
||||
return {
|
||||
expression,
|
||||
|
@ -30750,27 +30818,61 @@ function isDocumentReady(selectedSource, selectedLocation) {
|
|||
return selectedLocation && (0, _source.isLoaded)(selectedSource) && (0, _sourceDocuments.hasDocument)(selectedLocation.sourceId);
|
||||
}
|
||||
|
||||
class HighlightLine extends _react.PureComponent {
|
||||
class HighlightLine extends _react.Component {
|
||||
constructor(...args) {
|
||||
var _temp;
|
||||
|
||||
return _temp = super(...args), this.isStepping = false, this.previousEditorLine = null, _temp;
|
||||
}
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
const { selectedLocation, selectedSource } = nextProps;
|
||||
return this.shouldSetHighlightLine(selectedLocation, selectedSource);
|
||||
}
|
||||
|
||||
shouldSetHighlightLine(selectedLocation, selectedSource) {
|
||||
const { sourceId, line } = selectedLocation;
|
||||
const editorLine = (0, _editor.toEditorLine)(sourceId, line);
|
||||
|
||||
if (!isDocumentReady(selectedSource, selectedLocation)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.isStepping && editorLine === this.previousEditorLine) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
const { selectedLocation, selectedFrame, selectedSource } = this.props;
|
||||
const {
|
||||
pauseCommand,
|
||||
selectedLocation,
|
||||
selectedFrame,
|
||||
selectedSource
|
||||
} = this.props;
|
||||
if (pauseCommand) {
|
||||
this.isStepping = true;
|
||||
}
|
||||
|
||||
this.clearHighlightLine(prevProps.selectedLocation, prevProps.selectedSource);
|
||||
|
||||
this.setHighlightLine(selectedLocation, selectedFrame, selectedSource);
|
||||
}
|
||||
|
||||
setHighlightLine(selectedLocation, selectedFrame, selectedSource) {
|
||||
if (!isDocumentReady(selectedSource, selectedLocation)) {
|
||||
const { sourceId, line } = selectedLocation;
|
||||
if (!this.shouldSetHighlightLine(selectedLocation, selectedSource)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { sourceId, line } = selectedLocation;
|
||||
this.isStepping = false;
|
||||
const editorLine = (0, _editor.toEditorLine)(sourceId, line);
|
||||
this.previousEditorLine = editorLine;
|
||||
|
||||
if (!line || isDebugLine(selectedFrame, selectedLocation)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const editorLine = (0, _editor.toEditorLine)(sourceId, line);
|
||||
const doc = (0, _sourceDocuments.getDocument)(sourceId);
|
||||
doc.addLineClass(editorLine, "line", "highlight-line");
|
||||
}
|
||||
|
@ -30793,6 +30895,7 @@ class HighlightLine extends _react.PureComponent {
|
|||
|
||||
exports.HighlightLine = HighlightLine;
|
||||
exports.default = (0, _reactRedux.connect)(state => ({
|
||||
pauseCommand: (0, _selectors.getPauseCommand)(state),
|
||||
selectedFrame: (0, _selectors.getVisibleSelectedFrame)(state),
|
||||
selectedLocation: (0, _selectors.getSelectedLocation)(state),
|
||||
selectedSource: (0, _selectors.getSelectedSource)(state)
|
||||
|
@ -31581,10 +31684,13 @@ Object.defineProperty(exports, "__esModule", {
|
|||
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
|
||||
|
||||
exports.updateFrameLocation = updateFrameLocation;
|
||||
exports.mapDisplayNames = mapDisplayNames;
|
||||
exports.mapFrames = mapFrames;
|
||||
|
||||
var _selectors = __webpack_require__(3590);
|
||||
|
||||
var _ast = __webpack_require__(1638);
|
||||
|
||||
function updateFrameLocation(frame, sourceMaps) {
|
||||
return sourceMaps.getOriginalLocation(frame.location).then(loc => _extends({}, frame, {
|
||||
location: loc,
|
||||
|
@ -31600,12 +31706,32 @@ function updateFrameLocations(frames, sourceMaps) {
|
|||
return Promise.all(frames.map(frame => updateFrameLocation(frame, sourceMaps)));
|
||||
}
|
||||
|
||||
function mapDisplayNames(frames, getState) {
|
||||
return frames.map(frame => {
|
||||
const source = (0, _selectors.getSource)(getState(), frame.location.sourceId);
|
||||
const symbols = (0, _selectors.getSymbols)(getState(), source);
|
||||
|
||||
if (!symbols || !symbols.functions) {
|
||||
return frame;
|
||||
}
|
||||
|
||||
const originalFunction = (0, _ast.findClosestFunction)(symbols.functions, frame.location);
|
||||
|
||||
if (!originalFunction) {
|
||||
return frame;
|
||||
}
|
||||
|
||||
const originalDisplayName = originalFunction.name;
|
||||
return _extends({}, frame, { originalDisplayName });
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Map call stack frame locations to original locations.
|
||||
* Map call stack frame locations and display names to originals.
|
||||
* e.g.
|
||||
* 1. When the debuggee pauses
|
||||
* 2. When a source is pretty printed
|
||||
*
|
||||
* 3. When symbols are loaded
|
||||
* @memberof actions/pause
|
||||
* @static
|
||||
*/
|
||||
|
@ -31616,7 +31742,8 @@ function mapFrames() {
|
|||
return;
|
||||
}
|
||||
|
||||
const mappedFrames = await updateFrameLocations(frames, sourceMaps);
|
||||
let mappedFrames = await updateFrameLocations(frames, sourceMaps);
|
||||
mappedFrames = mapDisplayNames(mappedFrames, getState);
|
||||
|
||||
dispatch({
|
||||
type: "MAP_FRAMES",
|
||||
|
@ -33926,6 +34053,7 @@ if (isDevelopment()) {
|
|||
pref("devtools.debugger.ignore-caught-exceptions", false);
|
||||
pref("devtools.debugger.call-stack-visible", true);
|
||||
pref("devtools.debugger.scopes-visible", true);
|
||||
pref("devtools.debugger.component-visible", true);
|
||||
pref("devtools.debugger.workers-visible", true);
|
||||
pref("devtools.debugger.expressions-visible", true);
|
||||
pref("devtools.debugger.breakpoints-visible", true);
|
||||
|
@ -33968,6 +34096,7 @@ const prefs = new PrefsHelper("devtools", {
|
|||
ignoreCaughtExceptions: ["Bool", "debugger.ignore-caught-exceptions"],
|
||||
callStackVisible: ["Bool", "debugger.call-stack-visible"],
|
||||
scopesVisible: ["Bool", "debugger.scopes-visible"],
|
||||
componentVisible: ["Bool", "debugger.component-visible"],
|
||||
workersVisible: ["Bool", "debugger.workers-visible"],
|
||||
breakpointsVisible: ["Bool", "debugger.breakpoints-visible"],
|
||||
expressionsVisible: ["Bool", "debugger.expressions-visible"],
|
||||
|
@ -37221,9 +37350,22 @@ function annotateBabelAsyncFrames(frames) {
|
|||
// Receives an array of frames and looks for babel async
|
||||
// call stack groups.
|
||||
function getBabelFrameIndexes(frames) {
|
||||
const startIndexes = getFrameIndices(frames, (displayName, url) => url.match(/regenerator-runtime/i) && displayName === "tryCatch");
|
||||
const startIndexes = frames.reduce((accumulator, frame, index) => {
|
||||
if ((0, _getFrameUrl.getFrameUrl)(frame).match(/regenerator-runtime/i) && frame.displayName === "tryCatch") {
|
||||
return [...accumulator, index];
|
||||
}
|
||||
return accumulator;
|
||||
}, []);
|
||||
|
||||
const endIndexes = getFrameIndices(frames, (displayName, url) => displayName === "_asyncToGenerator/<" || url.match(/_microtask/i) && displayName === "flush");
|
||||
const endIndexes = frames.reduce((accumulator, frame, index) => {
|
||||
if ((0, _getFrameUrl.getFrameUrl)(frame).match(/_microtask/i) && frame.displayName === "flush") {
|
||||
return [...accumulator, index];
|
||||
}
|
||||
if (frame.displayName === "_asyncToGenerator/<") {
|
||||
return [...accumulator, index + 1];
|
||||
}
|
||||
return accumulator;
|
||||
}, []);
|
||||
|
||||
if (startIndexes.length != endIndexes.length || startIndexes.length === 0) {
|
||||
return frames;
|
||||
|
@ -37235,10 +37377,6 @@ function getBabelFrameIndexes(frames) {
|
|||
return (0, _lodash.flatMap)((0, _lodash.zip)(startIndexes, endIndexes), ([startIndex, endIndex]) => (0, _lodash.range)(startIndex, endIndex + 1));
|
||||
}
|
||||
|
||||
function getFrameIndices(frames, predicate) {
|
||||
return frames.reduce((accumulator, frame, index) => predicate(frame.displayName, (0, _getFrameUrl.getFrameUrl)(frame)) ? [...accumulator, index] : accumulator, []);
|
||||
}
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 3609:
|
||||
|
@ -37402,7 +37540,8 @@ function mapDisplayNames(frame, library) {
|
|||
}
|
||||
|
||||
function formatDisplayName(frame, { shouldMapDisplayName = true } = {}) {
|
||||
let { displayName, library } = frame;
|
||||
let { displayName, originalDisplayName, library } = frame;
|
||||
displayName = originalDisplayName || displayName;
|
||||
if (library && shouldMapDisplayName) {
|
||||
displayName = mapDisplayNames(frame, library);
|
||||
}
|
||||
|
@ -38306,6 +38445,111 @@ function formatPausePoints(text, nodes) {
|
|||
|
||||
/***/ }),
|
||||
|
||||
/***/ 3623:
|
||||
/***/ (function(module, exports, __webpack_require__) {
|
||||
|
||||
"use strict";
|
||||
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
|
||||
var _react = __webpack_require__(0);
|
||||
|
||||
var _react2 = _interopRequireDefault(_react);
|
||||
|
||||
var _redux = __webpack_require__(3593);
|
||||
|
||||
var _reactRedux = __webpack_require__(3592);
|
||||
|
||||
var _actions = __webpack_require__(1354);
|
||||
|
||||
var _actions2 = _interopRequireDefault(_actions);
|
||||
|
||||
var _firefox = __webpack_require__(1500);
|
||||
|
||||
var _selectors = __webpack_require__(3590);
|
||||
|
||||
var _devtoolsReps = __webpack_require__(1408);
|
||||
|
||||
var _preview = __webpack_require__(1807);
|
||||
|
||||
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/>. */
|
||||
|
||||
const { createNode, getChildren } = _devtoolsReps.ObjectInspectorUtils.node;
|
||||
const { loadItemProperties } = _devtoolsReps.ObjectInspectorUtils.loadProperties;
|
||||
|
||||
class FrameworkComponent extends _react.PureComponent {
|
||||
async componentWillMount() {
|
||||
const expression = "this;";
|
||||
const { selectedFrame, setPopupObjectProperties } = this.props;
|
||||
const value = selectedFrame.this;
|
||||
|
||||
const root = createNode(null, expression, expression, { value });
|
||||
const properties = await loadItemProperties(root, _firefox.createObjectClient);
|
||||
if (properties) {
|
||||
setPopupObjectProperties(value, properties);
|
||||
}
|
||||
}
|
||||
|
||||
renderReactComponent() {
|
||||
const { selectedFrame, popupObjectProperties } = this.props;
|
||||
const expression = "this;";
|
||||
const value = selectedFrame.this;
|
||||
const root = {
|
||||
name: expression,
|
||||
path: expression,
|
||||
contents: { value }
|
||||
};
|
||||
|
||||
const loadedRootProperties = popupObjectProperties[value.actor];
|
||||
|
||||
let roots = getChildren({
|
||||
item: root,
|
||||
loadedProperties: new Map([[root.path, loadedRootProperties]])
|
||||
});
|
||||
|
||||
roots = roots.filter(r => ["state", "props"].includes(r.name));
|
||||
|
||||
return _react2.default.createElement(
|
||||
"div",
|
||||
{ className: "pane framework-component" },
|
||||
_react2.default.createElement(_devtoolsReps.ObjectInspector, {
|
||||
roots: roots,
|
||||
autoExpandAll: false,
|
||||
autoExpandDepth: 0,
|
||||
disableWrap: true,
|
||||
disabledFocus: true,
|
||||
dimTopLevelWindow: true,
|
||||
createObjectClient: grip => (0, _firefox.createObjectClient)(grip)
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { selectedFrame } = this.props;
|
||||
if ((0, _preview.isReactComponent)(selectedFrame.this)) {
|
||||
return this.renderReactComponent();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
exports.default = (0, _reactRedux.connect)(state => {
|
||||
return {
|
||||
selectedFrame: (0, _selectors.getSelectedFrame)(state),
|
||||
popupObjectProperties: (0, _selectors.getAllPopupObjectProperties)(state)
|
||||
};
|
||||
}, dispatch => (0, _redux.bindActionCreators)(_actions2.default, dispatch))(FrameworkComponent);
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 363:
|
||||
/***/ (function(module, exports) {
|
||||
|
||||
|
|
|
@ -997,10 +997,7 @@ function _parse(code, opts) {
|
|||
|
||||
const sourceOptions = {
|
||||
generated: {
|
||||
tokens: true,
|
||||
plugins: [
|
||||
"objectRestSpread"
|
||||
]
|
||||
tokens: true
|
||||
},
|
||||
original: {
|
||||
sourceType: "unambiguous",
|
||||
|
@ -40565,4 +40562,4 @@ module.exports = listCacheHas;
|
|||
/***/ })
|
||||
|
||||
/******/ });
|
||||
});
|
||||
});
|
|
@ -29,6 +29,7 @@ pref("devtools.debugger.ui.variables-searchbox-visible", false);
|
|||
pref("devtools.debugger.ui.framework-grouping-on", true);
|
||||
pref("devtools.debugger.call-stack-visible", true);
|
||||
pref("devtools.debugger.scopes-visible", true);
|
||||
pref("devtools.debugger.component-visible", true);
|
||||
pref("devtools.debugger.workers-visible", true);
|
||||
pref("devtools.debugger.breakpoints-visible", true);
|
||||
pref("devtools.debugger.expressions-visible", true);
|
||||
|
|
|
@ -123,6 +123,17 @@ StructuredCloneCallbacksFreeTransfer(uint32_t aTag,
|
|||
aExtraData);
|
||||
}
|
||||
|
||||
bool
|
||||
StructuredCloneCallbacksCanTransfer(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aObject,
|
||||
void* aClosure)
|
||||
{
|
||||
StructuredCloneHolderBase* holder =
|
||||
static_cast<StructuredCloneHolderBase*>(aClosure);
|
||||
MOZ_ASSERT(holder);
|
||||
return holder->CustomCanTransferHandler(aCx, aObject);
|
||||
}
|
||||
|
||||
void
|
||||
StructuredCloneCallbacksError(JSContext* aCx,
|
||||
uint32_t aErrorId)
|
||||
|
@ -138,7 +149,8 @@ const JSStructuredCloneCallbacks StructuredCloneHolder::sCallbacks = {
|
|||
StructuredCloneCallbacksError,
|
||||
StructuredCloneCallbacksReadTransfer,
|
||||
StructuredCloneCallbacksWriteTransfer,
|
||||
StructuredCloneCallbacksFreeTransfer
|
||||
StructuredCloneCallbacksFreeTransfer,
|
||||
StructuredCloneCallbacksCanTransfer,
|
||||
};
|
||||
|
||||
// StructuredCloneHolderBase class
|
||||
|
@ -240,6 +252,13 @@ StructuredCloneHolderBase::CustomFreeTransferHandler(uint32_t aTag,
|
|||
MOZ_CRASH("Nothing to free.");
|
||||
}
|
||||
|
||||
bool
|
||||
StructuredCloneHolderBase::CustomCanTransferHandler(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aObj)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// StructuredCloneHolder class
|
||||
|
||||
StructuredCloneHolder::StructuredCloneHolder(CloningSupport aSupportsCloning,
|
||||
|
@ -1221,6 +1240,10 @@ StructuredCloneHolder::CustomWriteTransferHandler(JSContext* aCx,
|
|||
*aExtraData = mPortIdentifiers.Length();
|
||||
MessagePortIdentifier* identifier = mPortIdentifiers.AppendElement();
|
||||
|
||||
if (!port->CanBeCloned()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
port->CloneAndDisentangle(*identifier);
|
||||
|
||||
*aTag = SCTAG_DOM_MAP_MESSAGEPORT;
|
||||
|
@ -1237,6 +1260,10 @@ StructuredCloneHolder::CustomWriteTransferHandler(JSContext* aCx,
|
|||
if (NS_SUCCEEDED(rv)) {
|
||||
MOZ_ASSERT(canvas);
|
||||
|
||||
if (canvas->IsNeutered()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*aExtraData = 0;
|
||||
*aTag = SCTAG_DOM_CANVAS;
|
||||
*aOwnership = JS::SCTAG_TMO_CUSTOM;
|
||||
|
@ -1314,6 +1341,42 @@ StructuredCloneHolder::CustomFreeTransferHandler(uint32_t aTag,
|
|||
}
|
||||
}
|
||||
|
||||
bool
|
||||
StructuredCloneHolder::CustomCanTransferHandler(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aObj)
|
||||
{
|
||||
if (!mSupportsTransferring) {
|
||||
return false;
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> obj(aCx, aObj);
|
||||
|
||||
{
|
||||
MessagePort* port = nullptr;
|
||||
nsresult rv = UNWRAP_OBJECT(MessagePort, &obj, port);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mStructuredCloneScope == StructuredCloneScope::SameProcessSameThread ||
|
||||
mStructuredCloneScope == StructuredCloneScope::SameProcessDifferentThread) {
|
||||
OffscreenCanvas* canvas = nullptr;
|
||||
rv = UNWRAP_OBJECT(OffscreenCanvas, &obj, canvas);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
ImageBitmap* bitmap = nullptr;
|
||||
rv = UNWRAP_OBJECT(ImageBitmap, &obj, bitmap);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
StructuredCloneHolder::TakeTransferredPortsAsSequence(Sequence<OwningNonNull<mozilla::dom::MessagePort>>& aPorts)
|
||||
{
|
||||
|
|
|
@ -88,6 +88,10 @@ public:
|
|||
void* aContent,
|
||||
uint64_t aExtraData);
|
||||
|
||||
virtual bool
|
||||
CustomCanTransferHandler(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aObj);
|
||||
|
||||
// These methods are what you should use to read/write data.
|
||||
|
||||
// Execute the serialization of aValue using the Structured Clone Algorithm.
|
||||
|
@ -283,6 +287,9 @@ public:
|
|||
void* aContent,
|
||||
uint64_t aExtraData) override;
|
||||
|
||||
virtual bool CustomCanTransferHandler(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aObj) override;
|
||||
|
||||
// These 2 static methods are useful to read/write fully serializable objects.
|
||||
// They can be used by custom StructuredCloneHolderBase classes to
|
||||
// serialize objects such as ImageData, CryptoKey, RTCCertificate, etc.
|
||||
|
|
|
@ -613,9 +613,11 @@ public:
|
|||
}
|
||||
|
||||
/**
|
||||
* This method returns the owner doc if the node is in the
|
||||
* composed document (as defined in the Shadow DOM spec), otherwise
|
||||
* it returns null.
|
||||
* This method returns the owner document if the node is connected to it
|
||||
* (as defined in the DOM spec), otherwise it returns null.
|
||||
* In other words, returns non-null even in the case the node is in
|
||||
* Shadow DOM, if there is a possibly shadow boundary crossing path from
|
||||
* the node to its owner document.
|
||||
*/
|
||||
nsIDocument* GetComposedDoc() const
|
||||
{
|
||||
|
|
|
@ -700,7 +700,8 @@ GetAddInfoCallback(JSContext* aCx, void* aClosure)
|
|||
nullptr /* reportError */,
|
||||
nullptr /* readTransfer */,
|
||||
nullptr /* writeTransfer */,
|
||||
nullptr /* freeTransfer */
|
||||
nullptr /* freeTransfer */,
|
||||
nullptr /* canTransfer */
|
||||
};
|
||||
|
||||
MOZ_ASSERT(aCx);
|
||||
|
@ -1323,6 +1324,7 @@ IDBObjectStore::DeserializeValue(JSContext* aCx,
|
|||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr
|
||||
};
|
||||
|
||||
|
@ -1496,6 +1498,7 @@ private:
|
|||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr
|
||||
};
|
||||
|
||||
|
@ -1609,6 +1612,7 @@ private:
|
|||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr
|
||||
};
|
||||
|
||||
|
|
|
@ -204,6 +204,7 @@ MessagePort::MessagePort(nsIGlobalObject* aGlobal)
|
|||
, mInnerID(0)
|
||||
, mMessageQueueEnabled(false)
|
||||
, mIsKeptAlive(false)
|
||||
, mHasBeenTransferredOrClosed(false)
|
||||
{
|
||||
MOZ_ASSERT(aGlobal);
|
||||
|
||||
|
@ -501,6 +502,7 @@ MessagePort::Dispatch()
|
|||
void
|
||||
MessagePort::Close()
|
||||
{
|
||||
mHasBeenTransferredOrClosed = true;
|
||||
CloseInternal(true /* aSoftly */);
|
||||
}
|
||||
|
||||
|
@ -725,6 +727,9 @@ void
|
|||
MessagePort::CloneAndDisentangle(MessagePortIdentifier& aIdentifier)
|
||||
{
|
||||
MOZ_ASSERT(mIdentifier);
|
||||
MOZ_ASSERT(!mHasBeenTransferredOrClosed);
|
||||
|
||||
mHasBeenTransferredOrClosed = true;
|
||||
|
||||
// We can clone a port that has already been transfered. In this case, on the
|
||||
// otherside will have a neutered port. Here we set neutered to true so that
|
||||
|
|
|
@ -74,6 +74,11 @@ public:
|
|||
|
||||
void UnshippedEntangle(MessagePort* aEntangledPort);
|
||||
|
||||
bool CanBeCloned() const
|
||||
{
|
||||
return !mHasBeenTransferredOrClosed;
|
||||
}
|
||||
|
||||
void CloneAndDisentangle(MessagePortIdentifier& aIdentifier);
|
||||
|
||||
void CloseForced();
|
||||
|
@ -182,6 +187,12 @@ private:
|
|||
bool mMessageQueueEnabled;
|
||||
|
||||
bool mIsKeptAlive;
|
||||
|
||||
// mHasBeenTransferredOrClosed is used to know if this port has been manually
|
||||
// closed or transferred via postMessage. Note that if the entangled port is
|
||||
// closed, this port is closed as well (see mState) but, just because close()
|
||||
// has not been called directly, by spec, this port can still be transferred.
|
||||
bool mHasBeenTransferredOrClosed;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -240,6 +240,13 @@ public:
|
|||
RefPtr<FilterNode> filter = mFilter;
|
||||
if (mFilter->GetBackendType() == FilterBackend::FILTER_BACKEND_CAPTURE) {
|
||||
filter = static_cast<FilterNodeCapture*>(filter.get())->Validate(aDT);
|
||||
|
||||
// This can happen if the FilterNodeCapture is unable to create a
|
||||
// backing FilterNode on the target backend. Normally this would be
|
||||
// handled by the painting code, but here there's not much we can do.
|
||||
if (!filter) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
aDT->DrawFilter(filter, mSourceRect, mDestPoint, mOptions);
|
||||
}
|
||||
|
|
|
@ -202,6 +202,8 @@ uint32_t ConvertValue(FilterType aType, uint32_t aAttribute, uint32_t aValue)
|
|||
aValue = D2DFilterCompositionMode(aValue);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return aValue;
|
||||
|
@ -218,6 +220,8 @@ void ConvertValue(FilterType aType, uint32_t aAttribute, IntSize &aValue)
|
|||
aValue.height += 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -441,6 +445,8 @@ GetD2D1PropForAttribute(FilterType aType, uint32_t aIndex)
|
|||
CONVERT_PROP(CROP_RECT, CROP_PROP_RECT);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return UINT32_MAX;
|
||||
|
@ -457,6 +463,8 @@ GetD2D1PropsForIntSize(FilterType aType, uint32_t aIndex, UINT32 *aPropWidth, UI
|
|||
return true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -514,6 +522,8 @@ static inline REFCLSID GetCLDIDForFilterType(FilterType aType)
|
|||
return CLSID_D2D1Premultiply;
|
||||
case FilterType::UNPREMULTIPLY:
|
||||
return CLSID_D2D1UnPremultiply;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return GUID_NULL;
|
||||
}
|
||||
|
|
|
@ -865,7 +865,7 @@ SourceSurfaceImage::GetTextureClient(KnowsCompositor* aForwarder)
|
|||
}
|
||||
|
||||
// Remove the speculatively added entry.
|
||||
mTextureClients.Remove(aForwarder->GetSerial());
|
||||
entry.OrRemove();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
|
@ -867,7 +867,8 @@ APZCTreeManager::PrepareNodeForLayer(const ScrollNode& aLayer,
|
|||
apzc = insertResult.first->second;
|
||||
PrintAPZCInfo(aLayer, apzc);
|
||||
}
|
||||
APZCTM_LOG("Found APZC %p for layer %p with identifiers %" PRId64 " %" PRId64 "\n", apzc, aLayer.GetLayer(), guid.mLayersId, guid.mScrollId);
|
||||
APZCTM_LOG("Found APZC %p for layer %p with identifiers %" PRIx64 " %" PRId64 "\n",
|
||||
apzc, aLayer.GetLayer(), uint64_t(guid.mLayersId), guid.mScrollId);
|
||||
|
||||
// If we haven't encountered a layer already with the same metrics, then we need to
|
||||
// do the full reuse-or-make-an-APZC algorithm, which is contained inside the block
|
||||
|
@ -938,7 +939,8 @@ APZCTreeManager::PrepareNodeForLayer(const ScrollNode& aLayer,
|
|||
node->SetLastChild(nullptr);
|
||||
}
|
||||
|
||||
APZCTM_LOG("Using APZC %p for layer %p with identifiers %" PRId64 " %" PRId64 "\n", apzc, aLayer.GetLayer(), aLayersId, aMetrics.GetScrollId());
|
||||
APZCTM_LOG("Using APZC %p for layer %p with identifiers %" PRIx64 " %" PRId64 "\n",
|
||||
apzc, aLayer.GetLayer(), uint64_t(aLayersId), aMetrics.GetScrollId());
|
||||
|
||||
apzc->NotifyLayersUpdated(aLayer.Metadata(), aState.mIsFirstPaint,
|
||||
aLayersId == aState.mOriginatingLayersId);
|
||||
|
@ -1087,7 +1089,7 @@ APZCTreeManager::FlushApzRepaints(LayersId aLayersId)
|
|||
// Previously, paints were throttled and therefore this method was used to
|
||||
// ensure any pending paints were flushed. Now, paints are flushed
|
||||
// immediately, so it is safe to simply send a notification now.
|
||||
APZCTM_LOG("Flushing repaints for layers id 0x%" PRIx64 "\n", aLayersId);
|
||||
APZCTM_LOG("Flushing repaints for layers id 0x%" PRIx64 "\n", uint64_t(aLayersId));
|
||||
RefPtr<GeckoContentController> controller = GetContentController(aLayersId);
|
||||
MOZ_ASSERT(controller);
|
||||
controller->DispatchToRepaintThread(
|
||||
|
|
|
@ -675,15 +675,9 @@ PrepareForSetTargetAPZCNotification(nsIWidget* aWidget,
|
|||
}
|
||||
|
||||
if (!scrollAncestor) {
|
||||
MOZ_ASSERT(false); // If you hit this, please file a bug with STR.
|
||||
|
||||
// Attempt some sort of graceful handling based on a theory as to why we
|
||||
// reach this point...
|
||||
// If we get here, the document element is non-null, valid, but doesn't have
|
||||
// a displayport. It's possible that the init code in ChromeProcessController
|
||||
// failed for some reason, or the document element got swapped out at some
|
||||
// later time. In this case let's try to set a displayport on the document
|
||||
// element again and bail out on this operation.
|
||||
// This can happen if the document element gets swapped out after ChromeProcessController
|
||||
// runs InitializeRootDisplayport. In this case let's try to set a displayport again and
|
||||
// bail out on this operation.
|
||||
APZCCH_LOG("Widget %p's document element %p didn't have a displayport\n",
|
||||
aWidget, dpElement.get());
|
||||
APZCCallbackHelper::InitializeRootDisplayport(aRootFrame->PresShell());
|
||||
|
|
|
@ -108,7 +108,6 @@ WebRenderLayerManager::DoDestroy(bool aIsSync)
|
|||
|
||||
if (WrBridge()) {
|
||||
// Just clear ImageKeys, they are deleted during WebRenderAPI destruction.
|
||||
mImageKeysToDeleteLater.Clear();
|
||||
mImageKeysToDelete.Clear();
|
||||
// CompositorAnimations are cleared by WebRenderBridgeParent.
|
||||
mDiscardedCompositorAnimationsIds.Clear();
|
||||
|
@ -298,7 +297,6 @@ WebRenderLayerManager::EndTransactionWithoutLayer(nsDisplayList* aDisplayList,
|
|||
resourceUpdates.DeleteImage(key);
|
||||
}
|
||||
mImageKeysToDelete.Clear();
|
||||
mImageKeysToDelete.SwapElements(mImageKeysToDeleteLater);
|
||||
|
||||
WrBridge()->RemoveExpiredFontKeys(resourceUpdates);
|
||||
|
||||
|
@ -406,20 +404,16 @@ WebRenderLayerManager::MakeSnapshotIfRequired(LayoutDeviceIntSize aSize)
|
|||
void
|
||||
WebRenderLayerManager::AddImageKeyForDiscard(wr::ImageKey key)
|
||||
{
|
||||
mImageKeysToDeleteLater.AppendElement(key);
|
||||
mImageKeysToDelete.AppendElement(key);
|
||||
}
|
||||
|
||||
void
|
||||
WebRenderLayerManager::DiscardImages()
|
||||
{
|
||||
wr::IpcResourceUpdateQueue resources(WrBridge());
|
||||
for (const auto& key : mImageKeysToDeleteLater) {
|
||||
resources.DeleteImage(key);
|
||||
}
|
||||
for (const auto& key : mImageKeysToDelete) {
|
||||
resources.DeleteImage(key);
|
||||
}
|
||||
mImageKeysToDeleteLater.Clear();
|
||||
mImageKeysToDelete.Clear();
|
||||
WrBridge()->UpdateResources(resources);
|
||||
}
|
||||
|
@ -462,7 +456,6 @@ WebRenderLayerManager::DiscardLocalImages()
|
|||
// Removes images but doesn't tell the parent side about them
|
||||
// This is useful in empty / failed transactions where we created
|
||||
// image keys but didn't tell the parent about them yet.
|
||||
mImageKeysToDeleteLater.Clear();
|
||||
mImageKeysToDelete.Clear();
|
||||
}
|
||||
|
||||
|
|
|
@ -175,11 +175,6 @@ private:
|
|||
private:
|
||||
nsIWidget* MOZ_NON_OWNING_REF mWidget;
|
||||
nsTArray<wr::ImageKey> mImageKeysToDelete;
|
||||
// TODO - This is needed because we have some code that creates image keys
|
||||
// and enqueues them for deletion right away which is bad not only because
|
||||
// of poor texture cache usage, but also because images end up deleted before
|
||||
// they are used. This should hopfully be temporary.
|
||||
nsTArray<wr::ImageKey> mImageKeysToDeleteLater;
|
||||
|
||||
// Set of compositor animation ids for which there are active animations (as
|
||||
// of the last transaction) on the compositor side.
|
||||
|
|
|
@ -31,6 +31,8 @@
|
|||
#define fopen(path,mode) hnjFopen(path,mode)
|
||||
#define fclose(file) hnjFclose(file)
|
||||
#define fgets(buf,count,file) hnjFgets(buf,count,file)
|
||||
#define feof(file) hnjFeof(file)
|
||||
#define fgetc(file) hnjFgetc(file)
|
||||
|
||||
typedef struct hnjFile_ hnjFile;
|
||||
|
||||
|
@ -44,6 +46,10 @@ int hnjFclose(hnjFile* f);
|
|||
|
||||
char* hnjFgets(char* s, int n, hnjFile* f);
|
||||
|
||||
int hnjFeof(hnjFile* f);
|
||||
|
||||
int hnjFgetc(hnjFile* f);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -22,6 +22,7 @@ struct hnjFile_ {
|
|||
char mBuffer[BUFSIZE];
|
||||
uint32_t mCurPos;
|
||||
uint32_t mLimit;
|
||||
bool mEOF;
|
||||
};
|
||||
|
||||
// replacement for fopen()
|
||||
|
@ -58,6 +59,7 @@ hnjFopen(const char* aURISpec, const char* aMode)
|
|||
f->mStream = instream;
|
||||
f->mCurPos = 0;
|
||||
f->mLimit = 0;
|
||||
f->mEOF = false;
|
||||
|
||||
return f;
|
||||
}
|
||||
|
@ -79,6 +81,27 @@ hnjFclose(hnjFile* f)
|
|||
return result;
|
||||
}
|
||||
|
||||
// replacement for fgetc()
|
||||
int
|
||||
hnjFgetc(hnjFile* f)
|
||||
{
|
||||
if (f->mCurPos >= f->mLimit) {
|
||||
f->mCurPos = 0;
|
||||
|
||||
nsresult rv = f->mStream->Read(f->mBuffer, BUFSIZE, &f->mLimit);
|
||||
if (NS_FAILED(rv)) {
|
||||
f->mLimit = 0;
|
||||
}
|
||||
|
||||
if (f->mLimit == 0) {
|
||||
f->mEOF = true;
|
||||
return EOF;
|
||||
}
|
||||
}
|
||||
|
||||
return f->mBuffer[f->mCurPos++];
|
||||
}
|
||||
|
||||
// replacement for fgets()
|
||||
// (not a full reimplementation, but sufficient for libhyphen's needs)
|
||||
char*
|
||||
|
@ -88,24 +111,15 @@ hnjFgets(char* s, int n, hnjFile* f)
|
|||
|
||||
int i = 0;
|
||||
while (i < n - 1) {
|
||||
if (f->mCurPos < f->mLimit) {
|
||||
char c = f->mBuffer[f->mCurPos++];
|
||||
s[i++] = c;
|
||||
if (c == '\n' || c == '\r') {
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
int c = hnjFgetc(f);
|
||||
|
||||
if (c == EOF) {
|
||||
break;
|
||||
}
|
||||
|
||||
f->mCurPos = 0;
|
||||
s[i++] = c;
|
||||
|
||||
nsresult rv = f->mStream->Read(f->mBuffer, BUFSIZE, &f->mLimit);
|
||||
if (NS_FAILED(rv)) {
|
||||
f->mLimit = 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (f->mLimit == 0) {
|
||||
if (c == '\n' || c == '\r') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -117,3 +131,9 @@ hnjFgets(char* s, int n, hnjFile* f)
|
|||
s[i] = '\0'; // null-terminate the returned string
|
||||
return s;
|
||||
}
|
||||
|
||||
int
|
||||
hnjFeof(hnjFile* f)
|
||||
{
|
||||
return f->mEOF ? EOF : 0;
|
||||
}
|
||||
|
|
|
@ -438,11 +438,25 @@ for (k = 0; k < 2; k++) {
|
|||
}
|
||||
|
||||
if (k == 0 || nextlevel) {
|
||||
while (fgets (buf, sizeof(buf), f) != NULL) {
|
||||
while (fgets(buf, sizeof(buf), f) != NULL) {
|
||||
|
||||
/* discard lines that don't fit in buffer */
|
||||
if (!feof(f) && strchr(buf, '\n') == NULL) {
|
||||
int c;
|
||||
while ((c = fgetc(f)) != '\n' && c != EOF);
|
||||
/* issue warning if not a comment */
|
||||
if (buf[0] != '%') {
|
||||
fprintf(stderr, "Warning: skipping too long pattern (more than %lu chars)\n", sizeof(buf));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strncmp(buf, "NEXTLEVEL", 9) == 0) {
|
||||
nextlevel = 1;
|
||||
break;
|
||||
} else if (buf[0] != '%') hnj_hyphen_load_line(buf, dict[k], hashtab);
|
||||
nextlevel = 1;
|
||||
break;
|
||||
} else if (buf[0] != '%') {
|
||||
hnj_hyphen_load_line(buf, dict[k], hashtab);
|
||||
}
|
||||
}
|
||||
} else if (k == 1) {
|
||||
/* default first level: hyphen and ASCII apostrophe */
|
||||
|
|
|
@ -295,6 +295,14 @@ typedef bool (*TransferStructuredCloneOp)(JSContext* cx,
|
|||
typedef void (*FreeTransferStructuredCloneOp)(uint32_t tag, JS::TransferableOwnership ownership,
|
||||
void* content, uint64_t extraData, void* closure);
|
||||
|
||||
/**
|
||||
* Called when the transferring objects are checked. If this function returns false, the
|
||||
* serialization ends throwing a DataCloneError exception.
|
||||
*/
|
||||
typedef bool (*CanTransferStructuredCloneOp)(JSContext* cx,
|
||||
JS::Handle<JSObject*> obj,
|
||||
void* closure);
|
||||
|
||||
struct JSStructuredCloneCallbacks {
|
||||
ReadStructuredCloneOp read;
|
||||
WriteStructuredCloneOp write;
|
||||
|
@ -302,6 +310,7 @@ struct JSStructuredCloneCallbacks {
|
|||
ReadTransferStructuredCloneOp readTransfer;
|
||||
TransferStructuredCloneOp writeTransfer;
|
||||
FreeTransferStructuredCloneOp freeTransfer;
|
||||
CanTransferStructuredCloneOp canTransfer;
|
||||
};
|
||||
|
||||
enum OwnTransferablePolicy {
|
||||
|
|
|
@ -38,7 +38,6 @@ namespace JS {
|
|||
\
|
||||
_(GetElem_TypedObject) \
|
||||
_(GetElem_Dense) \
|
||||
_(GetElem_TypedStatic) \
|
||||
_(GetElem_TypedArray) \
|
||||
_(GetElem_String) \
|
||||
_(GetElem_Arguments) \
|
||||
|
@ -47,7 +46,6 @@ namespace JS {
|
|||
_(GetElem_InlineCache) \
|
||||
\
|
||||
_(SetElem_TypedObject) \
|
||||
_(SetElem_TypedStatic) \
|
||||
_(SetElem_TypedArray) \
|
||||
_(SetElem_Dense) \
|
||||
_(SetElem_Arguments) \
|
||||
|
@ -123,8 +121,6 @@ namespace JS {
|
|||
_(OperandNotStringOrNumber) \
|
||||
_(OperandNotSimpleArith) \
|
||||
_(OperandNotEasilyCoercibleToString) \
|
||||
_(StaticTypedArrayUint32) \
|
||||
_(StaticTypedArrayCantComputeMask) \
|
||||
_(OutOfBounds) \
|
||||
_(GetElemStringNotCached) \
|
||||
_(NonNativeReceiver) \
|
||||
|
|
|
@ -188,9 +188,13 @@ function GetModuleNamespace(module)
|
|||
// Step 1
|
||||
assert(IsModule(module), "GetModuleNamespace called with non-module");
|
||||
|
||||
// Until issue https://github.com/tc39/ecma262/issues/1155 is resolved,
|
||||
// violate the spec here and throw if called on an errored module.
|
||||
if (module.status === MODULE_STATUS_EVALUATED_ERROR)
|
||||
throw GetModuleEvaluationError(module);
|
||||
|
||||
// Steps 2-3
|
||||
assert(module.status !== MODULE_STATUS_UNINSTANTIATED &&
|
||||
module.status !== MODULE_STATUS_EVALUATED_ERROR,
|
||||
assert(module.status !== MODULE_STATUS_UNINSTANTIATED,
|
||||
"Bad module state in GetModuleNamespace");
|
||||
|
||||
// Step 4
|
||||
|
|
|
@ -1755,32 +1755,6 @@ obj_getOwnPropertySymbols(JSContext* cx, unsigned argc, Value* vp)
|
|||
args.rval());
|
||||
}
|
||||
|
||||
/* ES6 draft rev 32 (2015 Feb 2) 19.1.2.4: Object.defineProperty(O, P, Attributes) */
|
||||
bool
|
||||
js::obj_defineProperty(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
// Steps 1-3.
|
||||
RootedObject obj(cx);
|
||||
if (!GetFirstArgumentAsObject(cx, args, "Object.defineProperty", &obj))
|
||||
return false;
|
||||
RootedId id(cx);
|
||||
if (!ToPropertyKey(cx, args.get(1), &id))
|
||||
return false;
|
||||
|
||||
// Steps 4-5.
|
||||
Rooted<PropertyDescriptor> desc(cx);
|
||||
if (!ToPropertyDescriptor(cx, args.get(2), true, &desc))
|
||||
return false;
|
||||
|
||||
// Steps 6-8.
|
||||
if (!DefineProperty(cx, obj, id, desc))
|
||||
return false;
|
||||
args.rval().setObject(*obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ES5 15.2.3.7: Object.defineProperties(O, Properties) */
|
||||
static bool
|
||||
obj_defineProperties(JSContext* cx, unsigned argc, Value* vp)
|
||||
|
|
|
@ -22,9 +22,6 @@ namespace js {
|
|||
MOZ_MUST_USE bool
|
||||
obj_construct(JSContext* cx, unsigned argc, JS::Value* vp);
|
||||
|
||||
MOZ_MUST_USE bool
|
||||
obj_propertyIsEnumerable(JSContext* cx, unsigned argc, Value* vp);
|
||||
|
||||
PlainObject*
|
||||
ObjectCreateImpl(JSContext* cx, HandleObject proto, NewObjectKind newKind = GenericObject,
|
||||
HandleObjectGroup group = nullptr);
|
||||
|
@ -33,29 +30,21 @@ PlainObject*
|
|||
ObjectCreateWithTemplate(JSContext* cx, HandlePlainObject templateObj);
|
||||
|
||||
// Object methods exposed so they can be installed in the self-hosting global.
|
||||
MOZ_MUST_USE bool
|
||||
obj_propertyIsEnumerable(JSContext* cx, unsigned argc, Value* vp);
|
||||
|
||||
MOZ_MUST_USE bool
|
||||
obj_create(JSContext* cx, unsigned argc, JS::Value* vp);
|
||||
|
||||
MOZ_MUST_USE bool
|
||||
obj_defineProperty(JSContext* cx, unsigned argc, JS::Value* vp);
|
||||
|
||||
MOZ_MUST_USE bool
|
||||
obj_getOwnPropertyNames(JSContext* cx, unsigned argc, JS::Value* vp);
|
||||
|
||||
MOZ_MUST_USE bool
|
||||
obj_getPrototypeOf(JSContext* cx, unsigned argc, JS::Value* vp);
|
||||
|
||||
|
||||
MOZ_MUST_USE bool
|
||||
obj_isExtensible(JSContext* cx, unsigned argc, JS::Value* vp);
|
||||
|
||||
MOZ_MUST_USE bool
|
||||
obj_toString(JSContext* cx, unsigned argc, JS::Value* vp);
|
||||
|
||||
JSString*
|
||||
ObjectClassToString(JSContext* cx, HandleObject obj);
|
||||
|
||||
// Exposed so SelfHosting.cpp can use it in the OwnPropertyKeys intrinsic
|
||||
MOZ_MUST_USE bool
|
||||
GetOwnPropertyKeys(JSContext* cx, HandleObject obj, unsigned flags, JS::MutableHandleValue rval);
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ function ObjectGetOwnPropertyDescriptors(O) {
|
|||
var obj = ToObject(O);
|
||||
|
||||
// Step 2.
|
||||
var keys = OwnPropertyKeys(obj);
|
||||
var keys = std_Reflect_ownKeys(obj);
|
||||
|
||||
// Step 3.
|
||||
var descriptors = {};
|
||||
|
|
|
@ -87,8 +87,8 @@ js::Reflect_isExtensible(JSContext* cx, unsigned argc, Value* vp)
|
|||
|
||||
// ES2018 draft rev c164be80f7ea91de5526b33d54e5c9321ed03d3f
|
||||
// 26.1.10 Reflect.ownKeys ( target )
|
||||
static bool
|
||||
Reflect_ownKeys(JSContext* cx, unsigned argc, Value* vp)
|
||||
bool
|
||||
js::Reflect_ownKeys(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
|
|
|
@ -24,6 +24,9 @@ Reflect_getPrototypeOf(JSContext* cx, unsigned argc, Value* vp);
|
|||
extern MOZ_MUST_USE bool
|
||||
Reflect_isExtensible(JSContext* cx, unsigned argc, Value* vp);
|
||||
|
||||
extern MOZ_MUST_USE bool
|
||||
Reflect_ownKeys(JSContext* cx, unsigned argc, Value* vp);
|
||||
|
||||
}
|
||||
|
||||
#endif /* builtin_Reflect_h */
|
||||
|
|
|
@ -219,67 +219,78 @@ function GetInternalError(msg) {
|
|||
// To be used when a function is required but calling it shouldn't do anything.
|
||||
function NullFunction() {}
|
||||
|
||||
// Object Rest/Spread Properties proposal
|
||||
// Abstract operation: CopyDataProperties (target, source, excluded)
|
||||
function CopyDataProperties(target, source, excluded) {
|
||||
// ES2019 draft rev 4c2df13f4194057f09b920ee88712e5a70b1a556
|
||||
// 7.3.23 CopyDataProperties (target, source, excludedItems)
|
||||
function CopyDataProperties(target, source, excludedItems) {
|
||||
// Step 1.
|
||||
assert(IsObject(target), "target is an object");
|
||||
|
||||
// Step 2.
|
||||
assert(IsObject(excluded), "excluded is an object");
|
||||
assert(IsObject(excludedItems), "excludedItems is an object");
|
||||
|
||||
// Steps 3, 6.
|
||||
// Steps 3 and 7.
|
||||
if (source === undefined || source === null)
|
||||
return;
|
||||
|
||||
// Step 4.a.
|
||||
source = ToObject(source);
|
||||
|
||||
// Step 4.b.
|
||||
var keys = OwnPropertyKeys(source);
|
||||
// Step 4.
|
||||
var from = ToObject(source);
|
||||
|
||||
// Step 5.
|
||||
var keys = CopyDataPropertiesOrGetOwnKeys(target, from, excludedItems);
|
||||
|
||||
// Return if we copied all properties in native code.
|
||||
if (keys === null)
|
||||
return;
|
||||
|
||||
// Step 6.
|
||||
for (var index = 0; index < keys.length; index++) {
|
||||
var key = keys[index];
|
||||
|
||||
// We abbreviate this by calling propertyIsEnumerable which is faster
|
||||
// and returns false for not defined properties.
|
||||
if (!hasOwn(key, excluded) && callFunction(std_Object_propertyIsEnumerable, source, key))
|
||||
_DefineDataProperty(target, key, source[key]);
|
||||
if (!hasOwn(key, excludedItems) &&
|
||||
callFunction(std_Object_propertyIsEnumerable, from, key))
|
||||
{
|
||||
_DefineDataProperty(target, key, from[key]);
|
||||
}
|
||||
}
|
||||
|
||||
// Step 6 (Return).
|
||||
// Step 7 (Return).
|
||||
}
|
||||
|
||||
// Object Rest/Spread Properties proposal
|
||||
// Abstract operation: CopyDataProperties (target, source, excluded)
|
||||
// ES2019 draft rev 4c2df13f4194057f09b920ee88712e5a70b1a556
|
||||
// 7.3.23 CopyDataProperties (target, source, excludedItems)
|
||||
function CopyDataPropertiesUnfiltered(target, source) {
|
||||
// Step 1.
|
||||
assert(IsObject(target), "target is an object");
|
||||
|
||||
// Step 2 (Not applicable).
|
||||
|
||||
// Steps 3, 6.
|
||||
// Steps 3 and 7.
|
||||
if (source === undefined || source === null)
|
||||
return;
|
||||
|
||||
// Step 4.a.
|
||||
source = ToObject(source);
|
||||
|
||||
// Step 4.b.
|
||||
var keys = OwnPropertyKeys(source);
|
||||
// Step 4.
|
||||
var from = ToObject(source);
|
||||
|
||||
// Step 5.
|
||||
var keys = CopyDataPropertiesOrGetOwnKeys(target, from, null);
|
||||
|
||||
// Return if we copied all properties in native code.
|
||||
if (keys === null)
|
||||
return;
|
||||
|
||||
// Step 6.
|
||||
for (var index = 0; index < keys.length; index++) {
|
||||
var key = keys[index];
|
||||
|
||||
// We abbreviate this by calling propertyIsEnumerable which is faster
|
||||
// and returns false for not defined properties.
|
||||
if (callFunction(std_Object_propertyIsEnumerable, source, key))
|
||||
_DefineDataProperty(target, key, source[key]);
|
||||
if (callFunction(std_Object_propertyIsEnumerable, from, key))
|
||||
_DefineDataProperty(target, key, from[key]);
|
||||
}
|
||||
|
||||
// Step 6 (Return).
|
||||
// Step 7 (Return).
|
||||
}
|
||||
|
||||
/*************************************** Testing functions ***************************************/
|
||||
|
|
|
@ -5489,20 +5489,7 @@ BytecodeEmitter::setOrEmitSetFunName(ParseNode* maybeFun, HandleAtom name,
|
|||
// Function doesn't have 'name' property at this point.
|
||||
// Set function's name at compile time.
|
||||
JSFunction* fun = maybeFun->pn_funbox->function();
|
||||
|
||||
// Single node can be emitted multiple times if it appears in
|
||||
// array destructuring default. If function already has a name,
|
||||
// just return.
|
||||
if (fun->hasInferredName()) {
|
||||
#ifdef DEBUG
|
||||
RootedFunction rootedFun(cx, fun);
|
||||
JSAtom* funName = NameToFunctionName(cx, name, prefixKind);
|
||||
if (!funName)
|
||||
return false;
|
||||
MOZ_ASSERT(funName == rootedFun->inferredName());
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
MOZ_ASSERT(!fun->hasInferredName());
|
||||
|
||||
fun->setInferredName(name);
|
||||
return true;
|
||||
|
|
|
@ -1290,9 +1290,11 @@ FoldElement(JSContext* cx, ParseNode** nodePtr, PerHandlerParser<FullParseHandle
|
|||
// Optimization 2: We have something like expr[3.14]. The number
|
||||
// isn't an array index, so it converts to a string ("3.14"),
|
||||
// enabling optimization 3 below.
|
||||
JSAtom* atom = ToAtom<NoGC>(cx, DoubleValue(number));
|
||||
if (!atom)
|
||||
JSAtom* atom = NumberToAtom(cx, number);
|
||||
if (!atom) {
|
||||
cx->recoverFromOutOfMemory();
|
||||
return false;
|
||||
}
|
||||
name = atom->asPropertyName();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9309,14 +9309,6 @@ GeneralParser<ParseHandler, CharT>::arrayInitializer(YieldHandling yieldHandling
|
|||
return literal;
|
||||
}
|
||||
|
||||
static JSAtom*
|
||||
DoubleToAtom(JSContext* cx, double value)
|
||||
{
|
||||
// This is safe because doubles can not be moved.
|
||||
Value tmp = DoubleValue(value);
|
||||
return ToAtom<CanGC>(cx, HandleValue::fromMarkedLocation(&tmp));
|
||||
}
|
||||
|
||||
template <class ParseHandler, typename CharT>
|
||||
typename ParseHandler::Node
|
||||
GeneralParser<ParseHandler, CharT>::propertyName(YieldHandling yieldHandling,
|
||||
|
@ -9374,7 +9366,7 @@ GeneralParser<ParseHandler, CharT>::propertyName(YieldHandling yieldHandling,
|
|||
Node propName;
|
||||
switch (ltok) {
|
||||
case TokenKind::Number:
|
||||
propAtom.set(DoubleToAtom(context, anyChars.currentToken().number()));
|
||||
propAtom.set(NumberToAtom(context, anyChars.currentToken().number()));
|
||||
if (!propAtom.get())
|
||||
return null();
|
||||
propName = newNumber(anyChars.currentToken());
|
||||
|
@ -9438,7 +9430,7 @@ GeneralParser<ParseHandler, CharT>::propertyName(YieldHandling yieldHandling,
|
|||
|
||||
uint32_t index;
|
||||
if (propAtom->isIndex(&index)) {
|
||||
propAtom.set(DoubleToAtom(context, index));
|
||||
propAtom.set(NumberToAtom(context, index));
|
||||
if (!propAtom.get())
|
||||
return null();
|
||||
return handler.newNumber(index, NoDecimal, pos());
|
||||
|
@ -9448,7 +9440,7 @@ GeneralParser<ParseHandler, CharT>::propertyName(YieldHandling yieldHandling,
|
|||
if (tt == TokenKind::Number) {
|
||||
tokenStream.consumeKnownToken(TokenKind::Number);
|
||||
|
||||
propAtom.set(DoubleToAtom(context, anyChars.currentToken().number()));
|
||||
propAtom.set(NumberToAtom(context, anyChars.currentToken().number()));
|
||||
if (!propAtom.get())
|
||||
return null();
|
||||
return newNumber(anyChars.currentToken());
|
||||
|
|
|
@ -9,6 +9,7 @@ GeckoProgram('fuzz-tests', linkage=None)
|
|||
UNIFIED_SOURCES += [
|
||||
'testExample.cpp',
|
||||
'tests.cpp',
|
||||
'testStructuredCloneReader.cpp',
|
||||
]
|
||||
|
||||
if CONFIG['JS_BUILD_BINAST']:
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
*/
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
|
||||
#include "mozilla/ScopeExit.h"
|
||||
|
||||
#include "jsapi.h"
|
||||
|
||||
#include "fuzz-tests/tests.h"
|
||||
#include "vm/Interpreter.h"
|
||||
|
||||
#include "vm/JSContext-inl.h"
|
||||
|
||||
using namespace js;
|
||||
|
||||
// These are defined and pre-initialized by the harness (in tests.cpp).
|
||||
extern JS::PersistentRootedObject gGlobal;
|
||||
extern JSContext* gCx;
|
||||
|
||||
static int
|
||||
testStructuredCloneReaderInit(int *argc, char ***argv) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
testStructuredCloneReaderFuzz(const uint8_t* buf, size_t size) {
|
||||
auto gcGuard = mozilla::MakeScopeExit([&] {
|
||||
JS::PrepareForFullGC(gCx);
|
||||
JS::GCForReason(gCx, GC_NORMAL, JS::gcreason::API);
|
||||
});
|
||||
|
||||
if (!size) return 0;
|
||||
|
||||
// Make sure to pad the buffer to a multiple of kSegmentAlignment
|
||||
const size_t kSegmentAlignment = 8;
|
||||
size_t buf_size = JS_ROUNDUP(size, kSegmentAlignment);
|
||||
|
||||
auto clonebuf = MakeUnique<JSStructuredCloneData>(0, 0, buf_size);
|
||||
if (!clonebuf || !clonebuf->Init(buf_size, buf_size)) {
|
||||
ReportOutOfMemory(gCx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Initialize with zeros, including padding, then copy buffer
|
||||
memset(clonebuf->Start(), '\0', buf_size);
|
||||
js_memcpy(clonebuf->Start(), buf, size);
|
||||
|
||||
JS::StructuredCloneScope scope = JS::StructuredCloneScope::DifferentProcess;
|
||||
|
||||
RootedValue deserialized(gCx);
|
||||
if (!JS_ReadStructuredClone(gCx, *clonebuf,
|
||||
JS_STRUCTURED_CLONE_VERSION,
|
||||
scope,
|
||||
&deserialized, nullptr, nullptr))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If we succeeded in deserializing, we should try to reserialize the data.
|
||||
This has two main advantages:
|
||||
|
||||
1) It tests parts of the serializer as well.
|
||||
2) The deserialized data is actually used, making it more likely to detect
|
||||
further memory-related problems.
|
||||
|
||||
Tests show that this also doesn't cause a serious performance penalty.
|
||||
*/
|
||||
mozilla::Maybe<JSAutoStructuredCloneBuffer> clonebufOut;
|
||||
JS::CloneDataPolicy policy;
|
||||
|
||||
clonebufOut.emplace(scope, nullptr, nullptr);
|
||||
if (!clonebufOut->write(gCx, deserialized, UndefinedHandleValue, policy))
|
||||
return 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
MOZ_FUZZING_INTERFACE_RAW(
|
||||
testStructuredCloneReaderInit,
|
||||
testStructuredCloneReaderFuzz,
|
||||
StructuredCloneReader
|
||||
);
|
|
@ -0,0 +1,21 @@
|
|||
// Overview:
|
||||
// - The outer function is an IIFE which gets marked as a singleton.
|
||||
// - The |o[index]| inner function is then also marked as a singleton.
|
||||
// - The |o[index]| inner function has a dynamic name from a computed property name.
|
||||
// - The |self| inner function uses |Function.prototype.caller| to reinvoke the outer function.
|
||||
//
|
||||
// When we reinvoke outer, we end up cloning a previously reused, i.e. non-cloned,
|
||||
// function which triggered an assertion in js::SetFunctionNameIfNoOwnName().
|
||||
|
||||
(function(index) {
|
||||
var o = {
|
||||
[index]: function() {}
|
||||
};
|
||||
|
||||
// Reinvoke the IIFE through |Function.prototype.caller|.
|
||||
if (index === 0) {
|
||||
(function self() {
|
||||
self.caller(1);
|
||||
})();
|
||||
}
|
||||
})(0);
|
|
@ -0,0 +1,25 @@
|
|||
// Overview:
|
||||
// - The outer function is an IIFE which gets marked as a singleton.
|
||||
// - The |o[index]| inner function is then also marked as a singleton.
|
||||
// - The |o[index]| inner function has a dynamic name from a computed property name.
|
||||
// - The |self| inner function uses |Function.prototype.caller| to reinvoke the outer function.
|
||||
//
|
||||
// When we reinvoke outer, we end up cloning a previously reused, i.e. non-cloned,
|
||||
// function which triggered an assertion in js::SetFunctionNameIfNoOwnName().
|
||||
|
||||
(function(index) {
|
||||
var o = {
|
||||
[index]: function() {}
|
||||
};
|
||||
|
||||
// Accessing |.name| sets the resolved-name flag, which triggered yet
|
||||
// another assertion when compared to bug1448582-1.js
|
||||
assertEq(o[index].name, String(index));
|
||||
|
||||
// Reinvoke the IIFE through |Function.prototype.caller|.
|
||||
if (index === 0) {
|
||||
(function self() {
|
||||
self.caller(1);
|
||||
})();
|
||||
}
|
||||
})(0);
|
|
@ -0,0 +1,22 @@
|
|||
// Overview:
|
||||
// - The outer function is an IIFE which gets marked as a singleton.
|
||||
// - The |fn| inner function is then also marked as a singleton.
|
||||
// - The |self| inner function uses |Function.prototype.caller| to reinvoke the outer function.
|
||||
//
|
||||
// When we reinvoke outer, we end up cloning a previously reused, i.e. non-cloned,
|
||||
// function.
|
||||
|
||||
(function(index) {
|
||||
var fn = function() {};
|
||||
|
||||
// Accessing |.name| sets the resolved-name flag, which should not be
|
||||
// copied over to the function clone.
|
||||
assertEq(fn.name, "fn");
|
||||
|
||||
// Reinvoke the IIFE through |Function.prototype.caller|.
|
||||
if (index === 0) {
|
||||
(function self() {
|
||||
self.caller(1);
|
||||
})();
|
||||
}
|
||||
})(0);
|
|
@ -0,0 +1,22 @@
|
|||
// Overview:
|
||||
// - The outer function is an IIFE which gets marked as a singleton.
|
||||
// - The |fn| inner function is then also marked as a singleton.
|
||||
// - The |self| inner function uses |Function.prototype.caller| to reinvoke the outer function.
|
||||
//
|
||||
// When we reinvoke outer, we end up cloning a previously reused, i.e. non-cloned,
|
||||
// function.
|
||||
|
||||
(function(index) {
|
||||
var fn = function(a) {};
|
||||
|
||||
// Accessing |.length| sets the resolved-length flag, which should not be
|
||||
// copied over to the function clone.
|
||||
assertEq(fn.length, 1);
|
||||
|
||||
// Reinvoke the IIFE through |Function.prototype.caller|.
|
||||
if (index === 0) {
|
||||
(function self() {
|
||||
self.caller(1);
|
||||
})();
|
||||
}
|
||||
})(0);
|
|
@ -0,0 +1,133 @@
|
|||
// Repeat 1448582-{1,3,4}.js for classes.
|
||||
|
||||
(function(index) {
|
||||
// Does not assert.
|
||||
var c = class { constructor(){} };
|
||||
|
||||
if (index === 0) {
|
||||
(function self() {
|
||||
self.caller(1);
|
||||
})();
|
||||
}
|
||||
})(0);
|
||||
|
||||
(function(index) {
|
||||
var c = class { constructor(){} };
|
||||
|
||||
// Accessing |.name| sets the resolved-name flag, which should not be
|
||||
// copied over to the function clone.
|
||||
assertEq(c.name, "c");
|
||||
|
||||
if (index === 0) {
|
||||
(function self() {
|
||||
self.caller(1);
|
||||
})();
|
||||
}
|
||||
})(0);
|
||||
|
||||
(function(index) {
|
||||
var c = class { constructor(a){} };
|
||||
|
||||
// Accessing |.length| sets the resolved-length flag, which should not be
|
||||
// copied over to the function clone.
|
||||
assertEq(c.length, 1);
|
||||
|
||||
if (index === 0) {
|
||||
(function self() {
|
||||
self.caller(1);
|
||||
})();
|
||||
}
|
||||
})(0);
|
||||
|
||||
|
||||
// Repeat 1448582-{3,4}.js for generator functions.
|
||||
|
||||
(function(index) {
|
||||
function* f() {}
|
||||
|
||||
// Accessing |.name| sets the resolved-name flag, which should not be
|
||||
// copied over to the function clone.
|
||||
assertEq(f.name, "f");
|
||||
|
||||
if (index === 0) {
|
||||
(function self() {
|
||||
self.caller(1);
|
||||
})();
|
||||
}
|
||||
})(0);
|
||||
|
||||
(function(index) {
|
||||
function* f(a) {}
|
||||
|
||||
// Accessing |.length| sets the resolved-length flag, which should not be
|
||||
// copied over to the function clone.
|
||||
assertEq(f.length, 1);
|
||||
|
||||
if (index === 0) {
|
||||
(function self() {
|
||||
self.caller(1);
|
||||
})();
|
||||
}
|
||||
})(0);
|
||||
|
||||
|
||||
// Repeat 1448582-{3,4}.js for async functions.
|
||||
|
||||
(function(index) {
|
||||
async function f() {}
|
||||
|
||||
// Accessing |.name| sets the resolved-name flag, which should not be
|
||||
// copied over to the function clone.
|
||||
assertEq(f.name, "f");
|
||||
|
||||
if (index === 0) {
|
||||
(function self() {
|
||||
self.caller(1);
|
||||
})();
|
||||
}
|
||||
})(0);
|
||||
|
||||
(function(index) {
|
||||
async function f(a) {}
|
||||
|
||||
// Accessing |.length| sets the resolved-length flag, which should not be
|
||||
// copied over to the function clone.
|
||||
assertEq(f.length, 1);
|
||||
|
||||
if (index === 0) {
|
||||
(function self() {
|
||||
self.caller(1);
|
||||
})();
|
||||
}
|
||||
})(0);
|
||||
|
||||
|
||||
// Repeat 1448582-{3,4}.js for async generator functions.
|
||||
|
||||
(function(index) {
|
||||
async function* f() {}
|
||||
|
||||
// Accessing |.name| sets the resolved-name flag, which should not be
|
||||
// copied over to the function clone.
|
||||
assertEq(f.name, "f");
|
||||
|
||||
if (index === 0) {
|
||||
(function self() {
|
||||
self.caller(1);
|
||||
})();
|
||||
}
|
||||
})(0);
|
||||
|
||||
(function(index) {
|
||||
async function* f(a) {}
|
||||
|
||||
// Accessing |.length| sets the resolved-length flag, which should not be
|
||||
// copied over to the function clone.
|
||||
assertEq(f.length, 1);
|
||||
|
||||
if (index === 0) {
|
||||
(function self() {
|
||||
self.caller(1);
|
||||
})();
|
||||
}
|
||||
})(0);
|
|
@ -0,0 +1,27 @@
|
|||
// Overview:
|
||||
// - The outer function is an IIFE which gets marked as a singleton.
|
||||
// - The |o[index]| inner function is then also marked as a singleton.
|
||||
// - The |o[index]| inner function has a dynamic name from a computed property name.
|
||||
// - The |self| inner function uses |Function.prototype.caller| to reinvoke the outer function.
|
||||
|
||||
(function(index) {
|
||||
var o = {
|
||||
[index]: class {
|
||||
constructor() {}
|
||||
|
||||
// Prevent adding an inferred name at index = 1 by creating a
|
||||
// static method named "name".
|
||||
static [(index === 0 ? "not-name" : "name")]() {}
|
||||
}
|
||||
}
|
||||
|
||||
// At index = 0 the class will get the inferred name "0".
|
||||
// At index = 1 the class should have no inferred name.
|
||||
assertEq(displayName(o[index]), index === 0 ? "0" : "");
|
||||
|
||||
if (index === 0) {
|
||||
(function self() {
|
||||
self.caller(1);
|
||||
})();
|
||||
}
|
||||
})(0);
|
|
@ -10,7 +10,8 @@ function tryCreateUnboxedObject() {
|
|||
for (var i = 0; i < 1000; ++i) {
|
||||
obj = new Unboxed();
|
||||
}
|
||||
|
||||
if (unboxedObjectsEnabled())
|
||||
assertEq(isUnboxedObject(obj), true);
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
load(libdir + "asserts.js");
|
||||
|
||||
function Unboxed() {
|
||||
this.a = 0;
|
||||
this.b = true;
|
||||
}
|
||||
|
||||
function tryCreateUnboxedObject() {
|
||||
var obj;
|
||||
for (var i = 0; i < 1000; ++i) {
|
||||
obj = new Unboxed();
|
||||
}
|
||||
if (unboxedObjectsEnabled())
|
||||
assertEq(isUnboxedObject(obj), true);
|
||||
return obj;
|
||||
}
|
||||
|
||||
function basic() {
|
||||
var unboxed = tryCreateUnboxedObject();
|
||||
|
||||
var {...target} = unboxed;
|
||||
assertDeepEq(target, {a: 0, b: true});
|
||||
|
||||
var {a, c, ...target} = unboxed;
|
||||
assertDeepEq(a, 0);
|
||||
assertDeepEq(c, undefined);
|
||||
assertDeepEq(target, {b: true});
|
||||
}
|
||||
|
||||
function expando() {
|
||||
var unboxed = tryCreateUnboxedObject();
|
||||
unboxed.c = 3.5;
|
||||
|
||||
var {...target} = unboxed;
|
||||
assertDeepEq(target, {a: 0, b: true, c: 3.5});
|
||||
|
||||
var {a, d, ...target} = unboxed;
|
||||
assertDeepEq(a, 0);
|
||||
assertDeepEq(d, undefined);
|
||||
assertDeepEq(target, {b: true, c: 3.5});
|
||||
}
|
||||
|
||||
basic();
|
||||
expando();
|
|
@ -0,0 +1,90 @@
|
|||
function test() {
|
||||
var from, to;
|
||||
|
||||
// From values.
|
||||
from = {x: 1, y: 2};
|
||||
({...to} = from);
|
||||
assertEq(to.y, 2);
|
||||
|
||||
var z;
|
||||
from = {x: 1, y: 2};
|
||||
({x: z, ...to} = from);
|
||||
assertEq(z, 1);
|
||||
assertEq(to.y, 2);
|
||||
|
||||
// From getter.
|
||||
var c = 7;
|
||||
from = {x: 1, get y() { return ++c; }};
|
||||
({...to} = from);
|
||||
assertEq(c, 8);
|
||||
assertEq(to.y, 8);
|
||||
|
||||
from = {x: 1, get y() { return ++c; }};
|
||||
({y: z, ...to} = from);
|
||||
assertEq(c, 9);
|
||||
assertEq(z, 9);
|
||||
assertEq(to.y, undefined);
|
||||
|
||||
// Array with dense elements.
|
||||
from = [1, 2, 3];
|
||||
({...to} = from);
|
||||
assertEq(to[2], 3);
|
||||
assertEq("length" in to, false);
|
||||
|
||||
from = [1, 2, 3];
|
||||
({2: z, ...to} = from);
|
||||
assertEq(z, 3);
|
||||
assertEq(to[2], undefined);
|
||||
assertEq(to[0], 1);
|
||||
assertEq("length" in to, false);
|
||||
|
||||
// Object with sparse elements and symbols.
|
||||
from = {x: 1, 1234567: 2, 1234560: 3, [Symbol.iterator]: 5, z: 3};
|
||||
({...to} = from);
|
||||
assertEq(to[1234567], 2);
|
||||
assertEq(Object.keys(to).toString(), "1234560,1234567,x,z");
|
||||
assertEq(to[Symbol.iterator], 5);
|
||||
|
||||
from = {x: 1, 1234567: 2, 1234560: 3, [Symbol.iterator]: 5, z: 3};
|
||||
({[Symbol.iterator]: z, ...to} = from);
|
||||
assertEq(to[1234567], 2);
|
||||
assertEq(Object.keys(to).toString(), "1234560,1234567,x,z");
|
||||
assertEq(to[Symbol.iterator], undefined);
|
||||
assertEq(z, 5);
|
||||
|
||||
// Typed array.
|
||||
from = new Int32Array([1, 2, 3]);
|
||||
({...to} = from);
|
||||
assertEq(to[1], 2);
|
||||
|
||||
from = new Int32Array([1, 2, 3]);
|
||||
({1: z, ...to} = from);
|
||||
assertEq(z, 2);
|
||||
assertEq(to[1], undefined);
|
||||
assertEq(to[2], 3);
|
||||
|
||||
// Primitive string.
|
||||
from = "foo";
|
||||
({...to} = from);
|
||||
assertEq(to[0], "f");
|
||||
|
||||
from = "foo";
|
||||
({0: z, ...to} = from);
|
||||
assertEq(z, "f");
|
||||
assertEq(to[0], undefined);
|
||||
assertEq(to[1], "o");
|
||||
|
||||
// String object.
|
||||
from = new String("bar");
|
||||
({...to} = from);
|
||||
assertEq(to[2], "r");
|
||||
|
||||
from = new String("bar");
|
||||
({1: z, ...to} = from);
|
||||
assertEq(z, "a");
|
||||
assertEq(to[1], undefined);
|
||||
assertEq(to[2], "r");
|
||||
}
|
||||
test();
|
||||
test();
|
||||
test();
|
|
@ -0,0 +1,40 @@
|
|||
load(libdir + "asserts.js");
|
||||
|
||||
function Unboxed() {
|
||||
this.a = 0;
|
||||
this.b = true;
|
||||
}
|
||||
|
||||
function tryCreateUnboxedObject() {
|
||||
var obj;
|
||||
for (var i = 0; i < 1000; ++i) {
|
||||
obj = new Unboxed();
|
||||
}
|
||||
if (unboxedObjectsEnabled())
|
||||
assertEq(isUnboxedObject(obj), true);
|
||||
return obj;
|
||||
}
|
||||
|
||||
function basic() {
|
||||
var unboxed = tryCreateUnboxedObject();
|
||||
|
||||
var target = {...unboxed};
|
||||
assertDeepEq(target, {a: 0, b: true});
|
||||
|
||||
target = {a: 1, c: 3, ...unboxed};
|
||||
assertDeepEq(target, {a: 0, c: 3, b: true});
|
||||
}
|
||||
|
||||
function expando() {
|
||||
var unboxed = tryCreateUnboxedObject();
|
||||
unboxed.c = 3.5;
|
||||
|
||||
var target = {...unboxed};
|
||||
assertDeepEq(target, {a: 0, b: true, c: 3.5});
|
||||
|
||||
target = {a: 1, d: 3, ...unboxed};
|
||||
assertDeepEq(target, {a: 0, d: 3, b: true, c: 3.5});
|
||||
}
|
||||
|
||||
basic();
|
||||
expando();
|
|
@ -0,0 +1,49 @@
|
|||
function test() {
|
||||
var from, to;
|
||||
|
||||
// From values.
|
||||
from = {x: 1, y: 2};
|
||||
to = {...from};
|
||||
assertEq(to.y, 2);
|
||||
to = {...from, ...from};
|
||||
assertEq(to.y, 2);
|
||||
|
||||
// From getter.
|
||||
var c = 7;
|
||||
from = {x: 1, get y() { return ++c; }};
|
||||
to = {...from};
|
||||
assertEq(to.y, 8);
|
||||
to = {...from, ...from};
|
||||
assertEq(to.y, 10);
|
||||
|
||||
// Array with dense elements.
|
||||
from = [1, 2, 3];
|
||||
to = {...from};
|
||||
assertEq(to[2], 3);
|
||||
assertEq("length" in to, false);
|
||||
|
||||
// Object with sparse elements and symbols.
|
||||
from = {x: 1, 1234567: 2, 1234560: 3, [Symbol.iterator]: 5, z: 3};
|
||||
to = {...from};
|
||||
assertEq(to[1234567], 2);
|
||||
assertEq(Object.keys(to).toString(), "1234560,1234567,x,z");
|
||||
assertEq(to[Symbol.iterator], 5);
|
||||
|
||||
// Typed array.
|
||||
from = new Int32Array([1, 2, 3]);
|
||||
to = {...from};
|
||||
assertEq(to[1], 2);
|
||||
|
||||
// Primitive string.
|
||||
from = "foo";
|
||||
to = {...from};
|
||||
assertEq(to[0], "f");
|
||||
|
||||
// String object.
|
||||
from = new String("bar");
|
||||
to = {...from};
|
||||
assertEq(to[2], "r");
|
||||
}
|
||||
test();
|
||||
test();
|
||||
test();
|
|
@ -0,0 +1,35 @@
|
|||
// Test performing GetModuleNamespace on an errored module.
|
||||
|
||||
class MyError {}
|
||||
|
||||
function assertThrowsMyError(f)
|
||||
{
|
||||
let caught = false;
|
||||
try {
|
||||
f();
|
||||
} catch (e) {
|
||||
caught = true;
|
||||
assertEq(e.constructor, MyError);
|
||||
}
|
||||
assertEq(caught, true);
|
||||
}
|
||||
|
||||
let moduleRepo = {};
|
||||
setModuleResolveHook(function(module, specifier) {
|
||||
return moduleRepo[specifier];
|
||||
});
|
||||
|
||||
moduleRepo["a"] = parseModule(`
|
||||
throw new MyError();
|
||||
`);
|
||||
|
||||
let c = moduleRepo["c"] = parseModule(`
|
||||
import "a";
|
||||
`);
|
||||
c.declarationInstantiation();
|
||||
assertThrowsMyError(() => c.evaluation());
|
||||
|
||||
let b = moduleRepo['b'] = parseModule(`
|
||||
import * as ns0 from 'a'
|
||||
`);
|
||||
assertThrowsMyError(() => b.declarationInstantiation());
|
|
@ -32,4 +32,27 @@ new WebAssembly.Module(wasmTextToBinary(`
|
|||
unreachable
|
||||
)
|
||||
)
|
||||
`))
|
||||
`));
|
||||
|
||||
new WebAssembly.Module(wasmTextToBinary(`
|
||||
(module
|
||||
(global $g (mut i32) (i32.const 42))
|
||||
(func (param $i i32)
|
||||
get_global $g
|
||||
get_global $g
|
||||
get_global $g
|
||||
get_global $g
|
||||
get_global $g
|
||||
get_global $g
|
||||
get_global $g
|
||||
get_global $g
|
||||
get_global $g
|
||||
get_global $g
|
||||
get_global $g
|
||||
get_global $g
|
||||
get_local $i
|
||||
set_global $g
|
||||
unreachable
|
||||
)
|
||||
)
|
||||
`));
|
||||
|
|
|
@ -123,8 +123,6 @@ GetObject(const MDefinition* ins)
|
|||
object = ins->getOperand(0);
|
||||
break;
|
||||
case MDefinition::Opcode::GetPropertyCache:
|
||||
case MDefinition::Opcode::LoadTypedArrayElementStatic:
|
||||
case MDefinition::Opcode::StoreTypedArrayElementStatic:
|
||||
case MDefinition::Opcode::GetDOMProperty:
|
||||
case MDefinition::Opcode::GetDOMMember:
|
||||
case MDefinition::Opcode::Call:
|
||||
|
|
|
@ -1380,9 +1380,11 @@ BaselineCacheIRCompiler::emitStoreDenseElement()
|
|||
// Load obj->elements in scratch.
|
||||
masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), scratch);
|
||||
|
||||
// Bounds check.
|
||||
// Bounds check. Unfortunately we don't have more registers available on
|
||||
// x86, so use InvalidReg and emit slightly slower code on x86.
|
||||
Register spectreTemp = InvalidReg;
|
||||
Address initLength(scratch, ObjectElements::offsetOfInitializedLength());
|
||||
masm.branch32(Assembler::BelowOrEqual, initLength, index, failure->label());
|
||||
masm.spectreBoundsCheck32(index, initLength, spectreTemp, failure->label());
|
||||
|
||||
// Hole check.
|
||||
BaseObjectElementIndex element(scratch, index);
|
||||
|
@ -1471,18 +1473,30 @@ BaselineCacheIRCompiler::emitStoreDenseElementHole()
|
|||
ObjectElements::FROZEN),
|
||||
failure->label());
|
||||
|
||||
// We don't have enough registers on x86 so use InvalidReg. This will emit
|
||||
// slightly less efficient code on x86.
|
||||
Register spectreTemp = InvalidReg;
|
||||
|
||||
if (handleAdd) {
|
||||
// Fail if index > initLength.
|
||||
masm.branch32(Assembler::Below, initLength, index, failure->label());
|
||||
// Bounds check.
|
||||
Label capacityOk, outOfBounds;
|
||||
masm.spectreBoundsCheck32(index, initLength, spectreTemp, &outOfBounds);
|
||||
masm.jump(&capacityOk);
|
||||
|
||||
// If we're out-of-bounds, only handle the index == initLength case.
|
||||
masm.bind(&outOfBounds);
|
||||
masm.branch32(Assembler::NotEqual, initLength, index, failure->label());
|
||||
|
||||
// If index < capacity, we can add a dense element inline. If not we
|
||||
// need to allocate more elements.
|
||||
Label capacityOk;
|
||||
Label allocElement;
|
||||
Address capacity(scratch, ObjectElements::offsetOfCapacity());
|
||||
masm.branch32(Assembler::Above, capacity, index, &capacityOk);
|
||||
masm.spectreBoundsCheck32(index, capacity, spectreTemp, &allocElement);
|
||||
masm.jump(&capacityOk);
|
||||
|
||||
// Check for non-writable array length. We only have to do this if
|
||||
// index >= capacity.
|
||||
masm.bind(&allocElement);
|
||||
masm.branchTest32(Assembler::NonZero, elementsFlags,
|
||||
Imm32(ObjectElements::NONWRITABLE_ARRAY_LENGTH),
|
||||
failure->label());
|
||||
|
@ -1510,7 +1524,7 @@ BaselineCacheIRCompiler::emitStoreDenseElementHole()
|
|||
// the type update code doesn't read uninitialized memory.
|
||||
} else {
|
||||
// Fail if index >= initLength.
|
||||
masm.branch32(Assembler::BelowOrEqual, initLength, index, failure->label());
|
||||
masm.spectreBoundsCheck32(index, initLength, spectreTemp, failure->label());
|
||||
}
|
||||
|
||||
// Check if we have to convert a double element.
|
||||
|
@ -1595,10 +1609,9 @@ BaselineCacheIRCompiler::emitArrayPush()
|
|||
|
||||
// Load obj->elements in scratch.
|
||||
masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), scratch);
|
||||
masm.load32(Address(scratch, ObjectElements::offsetOfLength()), scratchLength);
|
||||
|
||||
BaseObjectElementIndex element(scratch, scratchLength);
|
||||
Address initLength(scratch, ObjectElements::offsetOfInitializedLength());
|
||||
Address elementsInitLength(scratch, ObjectElements::offsetOfInitializedLength());
|
||||
Address elementsLength(scratch, ObjectElements::offsetOfLength());
|
||||
Address elementsFlags(scratch, ObjectElements::offsetOfFlags());
|
||||
|
||||
// Check for copy-on-write or frozen elements.
|
||||
|
@ -1608,16 +1621,19 @@ BaselineCacheIRCompiler::emitArrayPush()
|
|||
failure->label());
|
||||
|
||||
// Fail if length != initLength.
|
||||
masm.branch32(Assembler::NotEqual, initLength, scratchLength, failure->label());
|
||||
masm.load32(elementsInitLength, scratchLength);
|
||||
masm.branch32(Assembler::NotEqual, elementsLength, scratchLength, failure->label());
|
||||
|
||||
// If scratchLength < capacity, we can add a dense element inline. If not we
|
||||
// need to allocate more elements.
|
||||
Label capacityOk;
|
||||
Label capacityOk, allocElement;
|
||||
Address capacity(scratch, ObjectElements::offsetOfCapacity());
|
||||
masm.branch32(Assembler::Above, capacity, scratchLength, &capacityOk);
|
||||
masm.spectreBoundsCheck32(scratchLength, capacity, InvalidReg, &allocElement);
|
||||
masm.jump(&capacityOk);
|
||||
|
||||
// Check for non-writable array length. We only have to do this if
|
||||
// index >= capacity.
|
||||
masm.bind(&allocElement);
|
||||
masm.branchTest32(Assembler::NonZero, elementsFlags,
|
||||
Imm32(ObjectElements::NONWRITABLE_ARRAY_LENGTH),
|
||||
failure->label());
|
||||
|
@ -1672,12 +1688,12 @@ BaselineCacheIRCompiler::emitArrayPush()
|
|||
masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), scratch);
|
||||
|
||||
// Increment initLength and length.
|
||||
Address length(scratch, ObjectElements::offsetOfLength());
|
||||
masm.add32(Imm32(1), initLength);
|
||||
masm.load32(length, scratchLength);
|
||||
masm.add32(Imm32(1), length);
|
||||
masm.add32(Imm32(1), elementsInitLength);
|
||||
masm.load32(elementsLength, scratchLength);
|
||||
masm.add32(Imm32(1), elementsLength);
|
||||
|
||||
// Store the value.
|
||||
BaseObjectElementIndex element(scratch, scratchLength);
|
||||
masm.storeValue(val, element);
|
||||
emitPostBarrierElement(obj, val, scratch, scratchLength);
|
||||
|
||||
|
@ -1708,7 +1724,11 @@ BaselineCacheIRCompiler::emitStoreTypedElement()
|
|||
// Bounds check.
|
||||
Label done;
|
||||
LoadTypedThingLength(masm, layout, obj, scratch1);
|
||||
masm.branch32(Assembler::BelowOrEqual, scratch1, index, handleOOB ? &done : failure->label());
|
||||
|
||||
// Unfortunately we don't have more registers available on x86, so use
|
||||
// InvalidReg and emit slightly slower code on x86.
|
||||
Register spectreTemp = InvalidReg;
|
||||
masm.spectreBoundsCheck32(index, scratch1, spectreTemp, handleOOB ? &done : failure->label());
|
||||
|
||||
// Load the elements vector.
|
||||
LoadTypedThingData(masm, layout, obj, scratch1);
|
||||
|
|
|
@ -6858,16 +6858,24 @@ CodeGenerator::visitArrayLength(LArrayLength* lir)
|
|||
masm.load32(length, ToRegister(lir->output()));
|
||||
}
|
||||
|
||||
static void
|
||||
SetLengthFromIndex(MacroAssembler& masm, const LAllocation* index, const Address& length)
|
||||
{
|
||||
if (index->isConstant()) {
|
||||
masm.store32(Imm32(ToInt32(index) + 1), length);
|
||||
} else {
|
||||
Register newLength = ToRegister(index);
|
||||
masm.add32(Imm32(1), newLength);
|
||||
masm.store32(newLength, length);
|
||||
masm.sub32(Imm32(1), newLength);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenerator::visitSetArrayLength(LSetArrayLength* lir)
|
||||
{
|
||||
Address length(ToRegister(lir->elements()), ObjectElements::offsetOfLength());
|
||||
RegisterOrInt32Constant newLength = ToRegisterOrInt32Constant(lir->index());
|
||||
|
||||
masm.inc32(&newLength);
|
||||
masm.store32(newLength, length);
|
||||
// Restore register value if it is used/captured after.
|
||||
masm.dec32(&newLength);
|
||||
SetLengthFromIndex(masm, lir->index(), length);
|
||||
}
|
||||
|
||||
template <class OrderedHashTable>
|
||||
|
@ -8898,12 +8906,7 @@ void
|
|||
CodeGenerator::visitSetInitializedLength(LSetInitializedLength* lir)
|
||||
{
|
||||
Address initLength(ToRegister(lir->elements()), ObjectElements::offsetOfInitializedLength());
|
||||
RegisterOrInt32Constant index = ToRegisterOrInt32Constant(lir->index());
|
||||
|
||||
masm.inc32(&index);
|
||||
masm.store32(index, initLength);
|
||||
// Restore register value if it is used/captured after.
|
||||
masm.dec32(&index);
|
||||
SetLengthFromIndex(masm, lir->index(), initLength);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -9223,18 +9226,18 @@ CodeGenerator::emitStoreElementHoleT(T* lir)
|
|||
addOutOfLineCode(ool, lir->mir());
|
||||
|
||||
Register elements = ToRegister(lir->elements());
|
||||
const LAllocation* index = lir->index();
|
||||
RegisterOrInt32Constant key = ToRegisterOrInt32Constant(index);
|
||||
Register index = ToRegister(lir->index());
|
||||
Register spectreTemp = ToTempRegisterOrInvalid(lir->spectreTemp());
|
||||
|
||||
Address initLength(elements, ObjectElements::offsetOfInitializedLength());
|
||||
masm.branch32(Assembler::BelowOrEqual, initLength, key, ool->entry());
|
||||
masm.spectreBoundsCheck32(index, initLength, spectreTemp, ool->entry());
|
||||
|
||||
if (lir->mir()->needsBarrier())
|
||||
emitPreBarrier(elements, index, 0);
|
||||
emitPreBarrier(elements, lir->index(), 0);
|
||||
|
||||
masm.bind(ool->rejoinStore());
|
||||
emitStoreElementTyped(lir->value(), lir->mir()->value()->type(), lir->mir()->elementType(),
|
||||
elements, index, 0);
|
||||
elements, lir->index(), 0);
|
||||
|
||||
masm.bind(ool->rejoin());
|
||||
}
|
||||
|
@ -9256,21 +9259,18 @@ CodeGenerator::emitStoreElementHoleV(T* lir)
|
|||
addOutOfLineCode(ool, lir->mir());
|
||||
|
||||
Register elements = ToRegister(lir->elements());
|
||||
const LAllocation* index = lir->index();
|
||||
Register index = ToRegister(lir->index());
|
||||
const ValueOperand value = ToValue(lir, T::Value);
|
||||
RegisterOrInt32Constant key = ToRegisterOrInt32Constant(index);
|
||||
Register spectreTemp = ToTempRegisterOrInvalid(lir->spectreTemp());
|
||||
|
||||
Address initLength(elements, ObjectElements::offsetOfInitializedLength());
|
||||
masm.branch32(Assembler::BelowOrEqual, initLength, key, ool->entry());
|
||||
masm.spectreBoundsCheck32(index, initLength, spectreTemp, ool->entry());
|
||||
|
||||
if (lir->mir()->needsBarrier())
|
||||
emitPreBarrier(elements, index, 0);
|
||||
emitPreBarrier(elements, lir->index(), 0);
|
||||
|
||||
masm.bind(ool->rejoinStore());
|
||||
if (index->isConstant())
|
||||
masm.storeValue(value, Address(elements, ToInt32(index) * sizeof(js::Value)));
|
||||
else
|
||||
masm.storeValue(value, BaseIndex(elements, ToRegister(index), TimesEight));
|
||||
masm.storeValue(value, BaseIndex(elements, index, TimesEight));
|
||||
|
||||
masm.bind(ool->rejoin());
|
||||
}
|
||||
|
@ -9362,6 +9362,7 @@ CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool)
|
|||
const LAllocation* index;
|
||||
MIRType valueType;
|
||||
ConstantOrRegister value;
|
||||
Register spectreTemp;
|
||||
|
||||
if (ins->isStoreElementHoleV()) {
|
||||
LStoreElementHoleV* store = ins->toStoreElementHoleV();
|
||||
|
@ -9370,6 +9371,7 @@ CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool)
|
|||
index = store->index();
|
||||
valueType = store->mir()->value()->type();
|
||||
value = TypedOrValueRegister(ToValue(store, LStoreElementHoleV::Value));
|
||||
spectreTemp = ToTempRegisterOrInvalid(store->spectreTemp());
|
||||
} else if (ins->isFallibleStoreElementV()) {
|
||||
LFallibleStoreElementV* store = ins->toFallibleStoreElementV();
|
||||
object = ToRegister(store->object());
|
||||
|
@ -9377,6 +9379,7 @@ CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool)
|
|||
index = store->index();
|
||||
valueType = store->mir()->value()->type();
|
||||
value = TypedOrValueRegister(ToValue(store, LFallibleStoreElementV::Value));
|
||||
spectreTemp = ToTempRegisterOrInvalid(store->spectreTemp());
|
||||
} else if (ins->isStoreElementHoleT()) {
|
||||
LStoreElementHoleT* store = ins->toStoreElementHoleT();
|
||||
object = ToRegister(store->object());
|
||||
|
@ -9387,6 +9390,7 @@ CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool)
|
|||
value = ConstantOrRegister(store->value()->toConstant()->toJSValue());
|
||||
else
|
||||
value = TypedOrValueRegister(valueType, ToAnyRegister(store->value()));
|
||||
spectreTemp = ToTempRegisterOrInvalid(store->spectreTemp());
|
||||
} else { // ins->isFallibleStoreElementT()
|
||||
LFallibleStoreElementT* store = ins->toFallibleStoreElementT();
|
||||
object = ToRegister(store->object());
|
||||
|
@ -9397,39 +9401,42 @@ CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool)
|
|||
value = ConstantOrRegister(store->value()->toConstant()->toJSValue());
|
||||
else
|
||||
value = TypedOrValueRegister(valueType, ToAnyRegister(store->value()));
|
||||
spectreTemp = ToTempRegisterOrInvalid(store->spectreTemp());
|
||||
}
|
||||
|
||||
RegisterOrInt32Constant key = ToRegisterOrInt32Constant(index);
|
||||
Register indexReg = ToRegister(index);
|
||||
|
||||
// If index == initializedLength, try to bump the initialized length inline.
|
||||
// If index > initializedLength, call a stub. Note that this relies on the
|
||||
// condition flags sticking from the incoming branch.
|
||||
// Also note: this branch does not need Spectre mitigations, doing that for
|
||||
// the capacity check below is sufficient.
|
||||
Label callStub;
|
||||
#if defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
|
||||
// Had to reimplement for MIPS because there are no flags.
|
||||
Address initLength(elements, ObjectElements::offsetOfInitializedLength());
|
||||
masm.branch32(Assembler::NotEqual, initLength, key, &callStub);
|
||||
masm.branch32(Assembler::NotEqual, initLength, indexReg, &callStub);
|
||||
#else
|
||||
masm.j(Assembler::NotEqual, &callStub);
|
||||
#endif
|
||||
|
||||
// Check array capacity.
|
||||
masm.branch32(Assembler::BelowOrEqual, Address(elements, ObjectElements::offsetOfCapacity()),
|
||||
key, &callStub);
|
||||
masm.spectreBoundsCheck32(indexReg, Address(elements, ObjectElements::offsetOfCapacity()),
|
||||
spectreTemp, &callStub);
|
||||
|
||||
// Update initialized length. The capacity guard above ensures this won't overflow,
|
||||
// due to MAX_DENSE_ELEMENTS_COUNT.
|
||||
masm.inc32(&key);
|
||||
masm.store32(key, Address(elements, ObjectElements::offsetOfInitializedLength()));
|
||||
masm.add32(Imm32(1), indexReg);
|
||||
masm.store32(indexReg, Address(elements, ObjectElements::offsetOfInitializedLength()));
|
||||
|
||||
// Update length if length < initializedLength.
|
||||
Label dontUpdate;
|
||||
masm.branch32(Assembler::AboveOrEqual, Address(elements, ObjectElements::offsetOfLength()),
|
||||
key, &dontUpdate);
|
||||
masm.store32(key, Address(elements, ObjectElements::offsetOfLength()));
|
||||
indexReg, &dontUpdate);
|
||||
masm.store32(indexReg, Address(elements, ObjectElements::offsetOfLength()));
|
||||
masm.bind(&dontUpdate);
|
||||
|
||||
masm.dec32(&key);
|
||||
masm.sub32(Imm32(1), indexReg);
|
||||
|
||||
if ((ins->isStoreElementHoleT() || ins->isFallibleStoreElementT()) &&
|
||||
valueType != MIRType::Double)
|
||||
|
@ -9560,13 +9567,13 @@ CodeGenerator::emitArrayPopShift(LInstruction* lir, const MArrayPopShift* mir, R
|
|||
// VM call if a write barrier is necessary.
|
||||
masm.branchTestNeedsIncrementalBarrier(Assembler::NonZero, ool->entry());
|
||||
|
||||
// Load elements and length, and VM call if length != initializedLength.
|
||||
RegisterOrInt32Constant key = RegisterOrInt32Constant(lengthTemp);
|
||||
// Load elements and initializedLength, and VM call if
|
||||
// length != initializedLength.
|
||||
masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), elementsTemp);
|
||||
masm.load32(Address(elementsTemp, ObjectElements::offsetOfLength()), lengthTemp);
|
||||
masm.load32(Address(elementsTemp, ObjectElements::offsetOfInitializedLength()), lengthTemp);
|
||||
|
||||
Address initLength(elementsTemp, ObjectElements::offsetOfInitializedLength());
|
||||
masm.branch32(Assembler::NotEqual, initLength, key, ool->entry());
|
||||
Address lengthAddr(elementsTemp, ObjectElements::offsetOfLength());
|
||||
masm.branch32(Assembler::NotEqual, lengthAddr, lengthTemp, ool->entry());
|
||||
|
||||
// Test for length != 0. On zero length either take a VM call or generate
|
||||
// an undefined value, depending on whether the call is known to produce
|
||||
|
@ -9590,7 +9597,7 @@ CodeGenerator::emitArrayPopShift(LInstruction* lir, const MArrayPopShift* mir, R
|
|||
masm.branchTest32(Assembler::Zero, lengthTemp, lengthTemp, ool->entry());
|
||||
}
|
||||
|
||||
masm.dec32(&key);
|
||||
masm.sub32(Imm32(1), lengthTemp);
|
||||
|
||||
if (mir->mode() == MArrayPopShift::Pop) {
|
||||
BaseIndex addr(elementsTemp, lengthTemp, TimesEight);
|
||||
|
@ -9658,28 +9665,27 @@ static const VMFunction ArrayPushDenseInfo =
|
|||
|
||||
void
|
||||
CodeGenerator::emitArrayPush(LInstruction* lir, Register obj,
|
||||
const ConstantOrRegister& value, Register elementsTemp, Register length)
|
||||
const ConstantOrRegister& value, Register elementsTemp, Register length,
|
||||
Register spectreTemp)
|
||||
{
|
||||
OutOfLineCode* ool = oolCallVM(ArrayPushDenseInfo, lir, ArgList(obj, value), StoreRegisterTo(length));
|
||||
|
||||
RegisterOrInt32Constant key = RegisterOrInt32Constant(length);
|
||||
|
||||
// Load elements and length.
|
||||
masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), elementsTemp);
|
||||
masm.load32(Address(elementsTemp, ObjectElements::offsetOfLength()), length);
|
||||
|
||||
// Guard length == initializedLength.
|
||||
Address initLength(elementsTemp, ObjectElements::offsetOfInitializedLength());
|
||||
masm.branch32(Assembler::NotEqual, initLength, key, ool->entry());
|
||||
masm.branch32(Assembler::NotEqual, initLength, length, ool->entry());
|
||||
|
||||
// Guard length < capacity.
|
||||
Address capacity(elementsTemp, ObjectElements::offsetOfCapacity());
|
||||
masm.branch32(Assembler::BelowOrEqual, capacity, key, ool->entry());
|
||||
masm.spectreBoundsCheck32(length, capacity, spectreTemp, ool->entry());
|
||||
|
||||
// Do the store.
|
||||
masm.storeConstantOrRegister(value, BaseIndex(elementsTemp, length, TimesEight));
|
||||
|
||||
masm.inc32(&key);
|
||||
masm.add32(Imm32(1), length);
|
||||
|
||||
// Update length and initialized length.
|
||||
masm.store32(length, Address(elementsTemp, ObjectElements::offsetOfLength()));
|
||||
|
@ -9695,7 +9701,8 @@ CodeGenerator::visitArrayPushV(LArrayPushV* lir)
|
|||
Register elementsTemp = ToRegister(lir->temp());
|
||||
Register length = ToRegister(lir->output());
|
||||
ConstantOrRegister value = TypedOrValueRegister(ToValue(lir, LArrayPushV::Value));
|
||||
emitArrayPush(lir, obj, value, elementsTemp, length);
|
||||
Register spectreTemp = ToTempRegisterOrInvalid(lir->spectreTemp());
|
||||
emitArrayPush(lir, obj, value, elementsTemp, length, spectreTemp);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -9709,7 +9716,8 @@ CodeGenerator::visitArrayPushT(LArrayPushT* lir)
|
|||
value = ConstantOrRegister(lir->value()->toConstant()->toJSValue());
|
||||
else
|
||||
value = TypedOrValueRegister(lir->mir()->value()->type(), ToAnyRegister(lir->value()));
|
||||
emitArrayPush(lir, obj, value, elementsTemp, length);
|
||||
Register spectreTemp = ToTempRegisterOrInvalid(lir->spectreTemp());
|
||||
emitArrayPush(lir, obj, value, elementsTemp, length, spectreTemp);
|
||||
}
|
||||
|
||||
typedef JSObject* (*ArraySliceDenseFn)(JSContext*, HandleObject, int32_t, int32_t, HandleObject);
|
||||
|
@ -11820,42 +11828,20 @@ CodeGenerator::visitStoreTypedArrayElementHole(LStoreTypedArrayElementHole* lir)
|
|||
Scalar::Type arrayType = lir->mir()->arrayType();
|
||||
int width = Scalar::byteSize(arrayType);
|
||||
|
||||
const LAllocation* index = lir->index();
|
||||
Register index = ToRegister(lir->index());
|
||||
const LAllocation* length = lir->length();
|
||||
Register spectreTemp = ToTempRegisterOrInvalid(lir->spectreTemp());
|
||||
|
||||
bool guardLength = true;
|
||||
if (index->isConstant() && length->isConstant()) {
|
||||
uint32_t idx = ToInt32(index);
|
||||
uint32_t len = ToInt32(length);
|
||||
if (idx >= len)
|
||||
return;
|
||||
guardLength = false;
|
||||
}
|
||||
Label skip;
|
||||
if (index->isConstant()) {
|
||||
uint32_t idx = ToInt32(index);
|
||||
if (guardLength) {
|
||||
if (length->isRegister())
|
||||
masm.branch32(Assembler::BelowOrEqual, ToRegister(length), Imm32(idx), &skip);
|
||||
else
|
||||
masm.branch32(Assembler::BelowOrEqual, ToAddress(length), Imm32(idx), &skip);
|
||||
}
|
||||
Address dest(elements, idx * width);
|
||||
StoreToTypedArray(masm, arrayType, value, dest);
|
||||
} else {
|
||||
Register idxReg = ToRegister(index);
|
||||
MOZ_ASSERT(guardLength);
|
||||
if (length->isConstant())
|
||||
masm.branch32(Assembler::AboveOrEqual, idxReg, Imm32(ToInt32(length)), &skip);
|
||||
else if (length->isRegister())
|
||||
masm.branch32(Assembler::BelowOrEqual, ToRegister(length), idxReg, &skip);
|
||||
else
|
||||
masm.branch32(Assembler::BelowOrEqual, ToAddress(length), idxReg, &skip);
|
||||
BaseIndex dest(elements, ToRegister(index), ScaleFromElemWidth(width));
|
||||
StoreToTypedArray(masm, arrayType, value, dest);
|
||||
}
|
||||
if (guardLength)
|
||||
masm.bind(&skip);
|
||||
if (length->isRegister())
|
||||
masm.spectreBoundsCheck32(index, ToRegister(length), spectreTemp, &skip);
|
||||
else
|
||||
masm.spectreBoundsCheck32(index, ToAddress(length), spectreTemp, &skip);
|
||||
|
||||
BaseIndex dest(elements, index, ScaleFromElemWidth(width));
|
||||
StoreToTypedArray(masm, arrayType, value, dest);
|
||||
|
||||
masm.bind(&skip);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -163,7 +163,8 @@ class CodeGenerator final : public CodeGeneratorSpecific
|
|||
void emitArrayPopShift(LInstruction* lir, const MArrayPopShift* mir, Register obj,
|
||||
Register elementsTemp, Register lengthTemp, TypedOrValueRegister out);
|
||||
void emitArrayPush(LInstruction* lir, Register obj,
|
||||
const ConstantOrRegister& value, Register elementsTemp, Register length);
|
||||
const ConstantOrRegister& value, Register elementsTemp, Register length,
|
||||
Register spectreTemp);
|
||||
|
||||
void emitRest(LInstruction* lir, Register array, Register numActuals,
|
||||
Register temp0, Register temp1, unsigned numFormals,
|
||||
|
|
|
@ -1681,7 +1681,7 @@ TypeAnalyzer::adjustInputs(MDefinition* def)
|
|||
return true;
|
||||
|
||||
MInstruction* ins = def->toInstruction();
|
||||
TypePolicy* policy = ins->typePolicy();
|
||||
const TypePolicy* policy = ins->typePolicy();
|
||||
if (policy && !policy->adjustInputs(alloc(), ins))
|
||||
return false;
|
||||
return true;
|
||||
|
|
|
@ -7801,11 +7801,6 @@ IonBuilder::jsop_getelem()
|
|||
if (emitted)
|
||||
return Ok();
|
||||
|
||||
trackOptimizationAttempt(TrackedStrategy::GetElem_TypedStatic);
|
||||
MOZ_TRY(getElemTryTypedStatic(&emitted, obj, index));
|
||||
if (emitted)
|
||||
return Ok();
|
||||
|
||||
trackOptimizationAttempt(TrackedStrategy::GetElem_TypedArray);
|
||||
MOZ_TRY(getElemTryTypedArray(&emitted, obj, index));
|
||||
if (emitted)
|
||||
|
@ -8229,102 +8224,6 @@ IonBuilder::getElemTryDense(bool* emitted, MDefinition* obj, MDefinition* index)
|
|||
return Ok();
|
||||
}
|
||||
|
||||
AbortReasonOr<JSObject*>
|
||||
IonBuilder::getStaticTypedArrayObject(MDefinition* obj, MDefinition* index)
|
||||
{
|
||||
Scalar::Type arrayType;
|
||||
if (!ElementAccessIsTypedArray(constraints(), obj, index, &arrayType)) {
|
||||
trackOptimizationOutcome(TrackedOutcome::AccessNotTypedArray);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!LIRGenerator::allowStaticTypedArrayAccesses()) {
|
||||
trackOptimizationOutcome(TrackedOutcome::Disabled);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool hasExtraIndexedProperty;
|
||||
MOZ_TRY_VAR(hasExtraIndexedProperty, ElementAccessHasExtraIndexedProperty(this, obj));
|
||||
if (hasExtraIndexedProperty) {
|
||||
trackOptimizationOutcome(TrackedOutcome::ProtoIndexedProps);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!obj->resultTypeSet()) {
|
||||
trackOptimizationOutcome(TrackedOutcome::NoTypeInfo);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
JSObject* tarrObj = obj->resultTypeSet()->maybeSingleton();
|
||||
if (!tarrObj) {
|
||||
trackOptimizationOutcome(TrackedOutcome::NotSingleton);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
TypeSet::ObjectKey* tarrKey = TypeSet::ObjectKey::get(tarrObj);
|
||||
if (tarrKey->unknownProperties()) {
|
||||
trackOptimizationOutcome(TrackedOutcome::UnknownProperties);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return tarrObj;
|
||||
}
|
||||
|
||||
AbortReasonOr<Ok>
|
||||
IonBuilder::getElemTryTypedStatic(bool* emitted, MDefinition* obj, MDefinition* index)
|
||||
{
|
||||
MOZ_ASSERT(*emitted == false);
|
||||
|
||||
JSObject* tarrObj;
|
||||
MOZ_TRY_VAR(tarrObj, getStaticTypedArrayObject(obj, index));
|
||||
if (!tarrObj)
|
||||
return Ok();
|
||||
|
||||
// LoadTypedArrayElementStatic currently treats uint32 arrays as int32.
|
||||
Scalar::Type viewType = tarrObj->as<TypedArrayObject>().type();
|
||||
if (viewType == Scalar::Uint32) {
|
||||
trackOptimizationOutcome(TrackedOutcome::StaticTypedArrayUint32);
|
||||
return Ok();
|
||||
}
|
||||
|
||||
MDefinition* ptr = convertShiftToMaskForStaticTypedArray(index, viewType);
|
||||
if (!ptr)
|
||||
return Ok();
|
||||
|
||||
// Emit LoadTypedArrayElementStatic.
|
||||
|
||||
if (tarrObj->is<TypedArrayObject>()) {
|
||||
TypeSet::ObjectKey* tarrKey = TypeSet::ObjectKey::get(tarrObj);
|
||||
tarrKey->watchStateChangeForTypedArrayData(constraints());
|
||||
}
|
||||
|
||||
obj->setImplicitlyUsedUnchecked();
|
||||
index->setImplicitlyUsedUnchecked();
|
||||
|
||||
MLoadTypedArrayElementStatic* load = MLoadTypedArrayElementStatic::New(alloc(), tarrObj, ptr);
|
||||
current->add(load);
|
||||
current->push(load);
|
||||
|
||||
// The load is infallible if an undefined result will be coerced to the
|
||||
// appropriate numeric type if the read is out of bounds. The truncation
|
||||
// analysis picks up some of these cases, but is incomplete with respect
|
||||
// to others. For now, sniff the bytecode for simple patterns following
|
||||
// the load which guarantee a truncation or numeric conversion.
|
||||
if (viewType == Scalar::Float32 || viewType == Scalar::Float64) {
|
||||
jsbytecode* next = pc + JSOP_GETELEM_LENGTH;
|
||||
if (*next == JSOP_POS)
|
||||
load->setInfallible();
|
||||
} else {
|
||||
jsbytecode* next = pc + JSOP_GETELEM_LENGTH;
|
||||
if (*next == JSOP_ZERO && *(next + JSOP_ZERO_LENGTH) == JSOP_BITOR)
|
||||
load->setInfallible();
|
||||
}
|
||||
|
||||
trackOptimizationSuccess();
|
||||
*emitted = true;
|
||||
return Ok();
|
||||
}
|
||||
|
||||
AbortReasonOr<Ok>
|
||||
IonBuilder::getElemTryTypedArray(bool* emitted, MDefinition* obj, MDefinition* index)
|
||||
{
|
||||
|
@ -8787,50 +8686,6 @@ IonBuilder::addTypedArrayLengthAndData(MDefinition* obj,
|
|||
}
|
||||
}
|
||||
|
||||
MDefinition*
|
||||
IonBuilder::convertShiftToMaskForStaticTypedArray(MDefinition* id,
|
||||
Scalar::Type viewType)
|
||||
{
|
||||
trackOptimizationOutcome(TrackedOutcome::StaticTypedArrayCantComputeMask);
|
||||
|
||||
// No shifting is necessary if the typed array has single byte elements.
|
||||
if (TypedArrayShift(viewType) == 0)
|
||||
return id;
|
||||
|
||||
// If the index is an already shifted constant, undo the shift to get the
|
||||
// absolute offset being accessed.
|
||||
if (MConstant* idConst = id->maybeConstantValue()) {
|
||||
if (idConst->type() == MIRType::Int32) {
|
||||
int32_t index = idConst->toInt32();
|
||||
MConstant* offset = MConstant::New(alloc(), Int32Value(index << TypedArrayShift(viewType)));
|
||||
current->add(offset);
|
||||
return offset;
|
||||
}
|
||||
}
|
||||
|
||||
if (!id->isRsh() || id->isEffectful())
|
||||
return nullptr;
|
||||
|
||||
MConstant* shiftAmount = id->toRsh()->rhs()->maybeConstantValue();
|
||||
if (!shiftAmount || shiftAmount->type() != MIRType::Int32)
|
||||
return nullptr;
|
||||
if (uint32_t(shiftAmount->toInt32()) != TypedArrayShift(viewType))
|
||||
return nullptr;
|
||||
|
||||
// Instead of shifting, mask off the low bits of the index so that
|
||||
// a non-scaled access on the typed array can be performed.
|
||||
MConstant* mask = MConstant::New(alloc(), Int32Value(~((1 << shiftAmount->toInt32()) - 1)));
|
||||
MBitAnd* ptr = MBitAnd::New(alloc(), id->getOperand(0), mask);
|
||||
|
||||
ptr->infer(nullptr, nullptr);
|
||||
MOZ_ASSERT(!ptr->isEffectful());
|
||||
|
||||
current->add(mask);
|
||||
current->add(ptr);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
AbortReasonOr<Ok>
|
||||
IonBuilder::jsop_getelem_typed(MDefinition* obj, MDefinition* index,
|
||||
Scalar::Type arrayType)
|
||||
|
@ -8933,11 +8788,6 @@ IonBuilder::jsop_setelem()
|
|||
}
|
||||
|
||||
if (!forceInlineCaches()) {
|
||||
trackOptimizationAttempt(TrackedStrategy::SetElem_TypedStatic);
|
||||
MOZ_TRY(setElemTryTypedStatic(&emitted, object, index, value));
|
||||
if (emitted)
|
||||
return Ok();
|
||||
|
||||
trackOptimizationAttempt(TrackedStrategy::SetElem_TypedArray);
|
||||
MOZ_TRY(setElemTryTypedArray(&emitted, object, index, value));
|
||||
if (emitted)
|
||||
|
@ -9074,54 +8924,6 @@ IonBuilder::setElemTryScalarElemOfTypedObject(bool* emitted,
|
|||
return setPropTryScalarTypedObjectValue(emitted, obj, indexAsByteOffset, elemType, value);
|
||||
}
|
||||
|
||||
AbortReasonOr<Ok>
|
||||
IonBuilder::setElemTryTypedStatic(bool* emitted, MDefinition* object,
|
||||
MDefinition* index, MDefinition* value)
|
||||
{
|
||||
MOZ_ASSERT(*emitted == false);
|
||||
|
||||
JSObject* tarrObj;
|
||||
MOZ_TRY_VAR(tarrObj, getStaticTypedArrayObject(object, index));
|
||||
if (!tarrObj)
|
||||
return Ok();
|
||||
|
||||
SharedMem<void*> viewData = tarrObj->as<TypedArrayObject>().viewDataEither();
|
||||
if (tarrObj->zone()->group()->nursery().isInside(viewData))
|
||||
return Ok();
|
||||
|
||||
Scalar::Type viewType = tarrObj->as<TypedArrayObject>().type();
|
||||
MDefinition* ptr = convertShiftToMaskForStaticTypedArray(index, viewType);
|
||||
if (!ptr)
|
||||
return Ok();
|
||||
|
||||
// Emit StoreTypedArrayElementStatic.
|
||||
|
||||
if (tarrObj->is<TypedArrayObject>()) {
|
||||
TypeSet::ObjectKey* tarrKey = TypeSet::ObjectKey::get(tarrObj);
|
||||
tarrKey->watchStateChangeForTypedArrayData(constraints());
|
||||
}
|
||||
|
||||
object->setImplicitlyUsedUnchecked();
|
||||
index->setImplicitlyUsedUnchecked();
|
||||
|
||||
// Clamp value to [0, 255] for Uint8ClampedArray.
|
||||
MDefinition* toWrite = value;
|
||||
if (viewType == Scalar::Uint8Clamped) {
|
||||
toWrite = MClampToUint8::New(alloc(), value);
|
||||
current->add(toWrite->toInstruction());
|
||||
}
|
||||
|
||||
MInstruction* store = MStoreTypedArrayElementStatic::New(alloc(), tarrObj, ptr, toWrite);
|
||||
current->add(store);
|
||||
current->push(value);
|
||||
|
||||
MOZ_TRY(resumeAfter(store));
|
||||
|
||||
trackOptimizationSuccess();
|
||||
*emitted = true;
|
||||
return Ok();
|
||||
}
|
||||
|
||||
AbortReasonOr<Ok>
|
||||
IonBuilder::setElemTryTypedArray(bool* emitted, MDefinition* object,
|
||||
MDefinition* index, MDefinition* value)
|
||||
|
|
|
@ -209,9 +209,6 @@ class IonBuilder
|
|||
MInstruction*
|
||||
addGuardReceiverPolymorphic(MDefinition* obj, const BaselineInspector::ReceiverVector& receivers);
|
||||
|
||||
MDefinition* convertShiftToMaskForStaticTypedArray(MDefinition* id,
|
||||
Scalar::Type viewType);
|
||||
|
||||
bool invalidatedIdempotentCache();
|
||||
|
||||
bool hasStaticEnvironmentObject(JSObject** pcall);
|
||||
|
@ -391,15 +388,12 @@ class IonBuilder
|
|||
const LinearSum& byteOffset,
|
||||
ReferenceTypeDescr::Type type,
|
||||
PropertyName* name);
|
||||
AbortReasonOr<JSObject*> getStaticTypedArrayObject(MDefinition* obj, MDefinition* index);
|
||||
|
||||
// jsop_setelem() helpers.
|
||||
AbortReasonOr<Ok> setElemTryTypedArray(bool* emitted, MDefinition* object,
|
||||
MDefinition* index, MDefinition* value);
|
||||
AbortReasonOr<Ok> setElemTryTypedObject(bool* emitted, MDefinition* obj,
|
||||
MDefinition* index, MDefinition* value);
|
||||
AbortReasonOr<Ok> setElemTryTypedStatic(bool* emitted, MDefinition* object,
|
||||
MDefinition* index, MDefinition* value);
|
||||
AbortReasonOr<Ok> initOrSetElemTryDense(bool* emitted, MDefinition* object,
|
||||
MDefinition* index, MDefinition* value,
|
||||
bool writeHole);
|
||||
|
@ -425,7 +419,6 @@ class IonBuilder
|
|||
// jsop_getelem() helpers.
|
||||
AbortReasonOr<Ok> getElemTryDense(bool* emitted, MDefinition* obj, MDefinition* index);
|
||||
AbortReasonOr<Ok> getElemTryGetProp(bool* emitted, MDefinition* obj, MDefinition* index);
|
||||
AbortReasonOr<Ok> getElemTryTypedStatic(bool* emitted, MDefinition* obj, MDefinition* index);
|
||||
AbortReasonOr<Ok> getElemTryTypedArray(bool* emitted, MDefinition* obj, MDefinition* index);
|
||||
AbortReasonOr<Ok> getElemTryTypedObject(bool* emitted, MDefinition* obj, MDefinition* index);
|
||||
AbortReasonOr<Ok> getElemTryString(bool* emitted, MDefinition* obj, MDefinition* index);
|
||||
|
|
|
@ -1901,7 +1901,8 @@ IonCacheIRCompiler::emitStoreDenseElement()
|
|||
Register index = allocator.useRegister(masm, reader.int32OperandId());
|
||||
ConstantOrRegister val = allocator.useConstantOrRegister(masm, reader.valOperandId());
|
||||
|
||||
AutoScratchRegister scratch(allocator, masm);
|
||||
AutoScratchRegister scratch1(allocator, masm);
|
||||
AutoScratchRegister scratch2(allocator, masm);
|
||||
|
||||
FailurePath* failure;
|
||||
if (!addFailurePath(&failure))
|
||||
|
@ -1910,20 +1911,20 @@ IonCacheIRCompiler::emitStoreDenseElement()
|
|||
EmitCheckPropertyTypes(masm, typeCheckInfo_, obj, val, *liveRegs_, failure->label());
|
||||
|
||||
// Load obj->elements in scratch.
|
||||
masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), scratch);
|
||||
masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), scratch1);
|
||||
|
||||
// Bounds check.
|
||||
Address initLength(scratch, ObjectElements::offsetOfInitializedLength());
|
||||
masm.branch32(Assembler::BelowOrEqual, initLength, index, failure->label());
|
||||
Address initLength(scratch1, ObjectElements::offsetOfInitializedLength());
|
||||
masm.spectreBoundsCheck32(index, initLength, scratch2, failure->label());
|
||||
|
||||
// Hole check.
|
||||
BaseObjectElementIndex element(scratch, index);
|
||||
BaseObjectElementIndex element(scratch1, index);
|
||||
masm.branchTestMagic(Assembler::Equal, element, failure->label());
|
||||
|
||||
EmitPreBarrier(masm, element, MIRType::Value);
|
||||
EmitStoreDenseElement(masm, val, scratch, element);
|
||||
EmitStoreDenseElement(masm, val, scratch1, element);
|
||||
if (needsPostBarrier())
|
||||
emitPostBarrierElement(obj, val, scratch, index);
|
||||
emitPostBarrierElement(obj, val, scratch1, index);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1939,7 +1940,8 @@ IonCacheIRCompiler::emitStoreDenseElementHole()
|
|||
// track this.
|
||||
reader.readBool();
|
||||
|
||||
AutoScratchRegister scratch(allocator, masm);
|
||||
AutoScratchRegister scratch1(allocator, masm);
|
||||
AutoScratchRegister scratch2(allocator, masm);
|
||||
|
||||
FailurePath* failure;
|
||||
if (!addFailurePath(&failure))
|
||||
|
@ -1947,45 +1949,51 @@ IonCacheIRCompiler::emitStoreDenseElementHole()
|
|||
|
||||
EmitCheckPropertyTypes(masm, typeCheckInfo_, obj, val, *liveRegs_, failure->label());
|
||||
|
||||
// Load obj->elements in scratch.
|
||||
masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), scratch);
|
||||
// Load obj->elements in scratch1.
|
||||
masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), scratch1);
|
||||
|
||||
Address initLength(scratch, ObjectElements::offsetOfInitializedLength());
|
||||
BaseObjectElementIndex element(scratch, index);
|
||||
Address initLength(scratch1, ObjectElements::offsetOfInitializedLength());
|
||||
BaseObjectElementIndex element(scratch1, index);
|
||||
|
||||
Label inBounds, doStore;
|
||||
masm.branch32(Assembler::Above, initLength, index, &inBounds);
|
||||
Label inBounds, outOfBounds;
|
||||
Register spectreTemp = scratch2;
|
||||
masm.spectreBoundsCheck32(index, initLength, spectreTemp, &outOfBounds);
|
||||
masm.jump(&inBounds);
|
||||
|
||||
masm.bind(&outOfBounds);
|
||||
masm.branch32(Assembler::NotEqual, initLength, index, failure->label());
|
||||
|
||||
// If index < capacity, we can add a dense element inline. If not we
|
||||
// need to allocate more elements.
|
||||
Label capacityOk;
|
||||
Address capacity(scratch, ObjectElements::offsetOfCapacity());
|
||||
masm.branch32(Assembler::Above, capacity, index, &capacityOk);
|
||||
Label capacityOk, allocElement;
|
||||
Address capacity(scratch1, ObjectElements::offsetOfCapacity());
|
||||
masm.spectreBoundsCheck32(index, capacity, spectreTemp, &allocElement);
|
||||
masm.jump(&capacityOk);
|
||||
|
||||
// Check for non-writable array length. We only have to do this if
|
||||
// index >= capacity.
|
||||
Address elementsFlags(scratch, ObjectElements::offsetOfFlags());
|
||||
masm.bind(&allocElement);
|
||||
Address elementsFlags(scratch1, ObjectElements::offsetOfFlags());
|
||||
masm.branchTest32(Assembler::NonZero, elementsFlags,
|
||||
Imm32(ObjectElements::NONWRITABLE_ARRAY_LENGTH),
|
||||
failure->label());
|
||||
|
||||
LiveRegisterSet save(GeneralRegisterSet::Volatile(), liveVolatileFloatRegs());
|
||||
save.takeUnchecked(scratch);
|
||||
save.takeUnchecked(scratch1);
|
||||
masm.PushRegsInMask(save);
|
||||
|
||||
masm.setupUnalignedABICall(scratch);
|
||||
masm.loadJSContext(scratch);
|
||||
masm.passABIArg(scratch);
|
||||
masm.setupUnalignedABICall(scratch1);
|
||||
masm.loadJSContext(scratch1);
|
||||
masm.passABIArg(scratch1);
|
||||
masm.passABIArg(obj);
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, NativeObject::addDenseElementDontReportOOM));
|
||||
masm.mov(ReturnReg, scratch);
|
||||
masm.mov(ReturnReg, scratch1);
|
||||
|
||||
masm.PopRegsInMask(save);
|
||||
masm.branchIfFalseBool(scratch, failure->label());
|
||||
masm.branchIfFalseBool(scratch1, failure->label());
|
||||
|
||||
// Load the reallocated elements pointer.
|
||||
masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), scratch);
|
||||
masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), scratch1);
|
||||
|
||||
masm.bind(&capacityOk);
|
||||
|
||||
|
@ -1994,12 +2002,13 @@ IonCacheIRCompiler::emitStoreDenseElementHole()
|
|||
|
||||
// If length is now <= index, increment length too.
|
||||
Label skipIncrementLength;
|
||||
Address length(scratch, ObjectElements::offsetOfLength());
|
||||
Address length(scratch1, ObjectElements::offsetOfLength());
|
||||
masm.branch32(Assembler::Above, length, index, &skipIncrementLength);
|
||||
masm.add32(Imm32(1), length);
|
||||
masm.bind(&skipIncrementLength);
|
||||
|
||||
// Skip EmitPreBarrier as the memory is uninitialized.
|
||||
Label doStore;
|
||||
masm.jump(&doStore);
|
||||
|
||||
masm.bind(&inBounds);
|
||||
|
@ -2007,9 +2016,9 @@ IonCacheIRCompiler::emitStoreDenseElementHole()
|
|||
EmitPreBarrier(masm, element, MIRType::Value);
|
||||
|
||||
masm.bind(&doStore);
|
||||
EmitStoreDenseElement(masm, val, scratch, element);
|
||||
EmitStoreDenseElement(masm, val, scratch1, element);
|
||||
if (needsPostBarrier())
|
||||
emitPostBarrierElement(obj, val, scratch, index);
|
||||
emitPostBarrierElement(obj, val, scratch1, index);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2032,10 +2041,7 @@ IonCacheIRCompiler::emitStoreTypedElement()
|
|||
bool handleOOB = reader.readBool();
|
||||
|
||||
AutoScratchRegister scratch1(allocator, masm);
|
||||
|
||||
Maybe<AutoScratchRegister> scratch2;
|
||||
if (arrayType != Scalar::Float32 && arrayType != Scalar::Float64)
|
||||
scratch2.emplace(allocator, masm);
|
||||
AutoScratchRegister scratch2(allocator, masm);
|
||||
|
||||
FailurePath* failure;
|
||||
if (!addFailurePath(&failure))
|
||||
|
@ -2044,7 +2050,7 @@ IonCacheIRCompiler::emitStoreTypedElement()
|
|||
// Bounds check.
|
||||
Label done;
|
||||
LoadTypedThingLength(masm, layout, obj, scratch1);
|
||||
masm.branch32(Assembler::BelowOrEqual, scratch1, index, handleOOB ? &done : failure->label());
|
||||
masm.spectreBoundsCheck32(index, scratch1, scratch2, handleOOB ? &done : failure->label());
|
||||
|
||||
// Load the elements vector.
|
||||
LoadTypedThingData(masm, layout, obj, scratch1);
|
||||
|
@ -2066,7 +2072,7 @@ IonCacheIRCompiler::emitStoreTypedElement()
|
|||
return false;
|
||||
masm.storeToTypedFloatArray(arrayType, maybeTempDouble, dest);
|
||||
} else {
|
||||
Register valueToStore = scratch2.ref();
|
||||
Register valueToStore = scratch2;
|
||||
if (arrayType == Scalar::Uint8Clamped) {
|
||||
if (!masm.clampConstantOrRegisterToUint8(cx_, val, maybeTempDouble, valueToStore,
|
||||
failure->label()))
|
||||
|
|
|
@ -3419,6 +3419,18 @@ LIRGenerator::visitStoreElement(MStoreElement* ins)
|
|||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
BoundsCheckNeedsSpectreTemp()
|
||||
{
|
||||
// On x86, spectreBoundsCheck32 can emit better code if it has a scratch
|
||||
// register and index masking is enabled.
|
||||
#ifdef JS_CODEGEN_X86
|
||||
return JitOptions.spectreIndexMasking;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
LIRGenerator::visitStoreElementHole(MStoreElementHole* ins)
|
||||
{
|
||||
|
@ -3427,18 +3439,21 @@ LIRGenerator::visitStoreElementHole(MStoreElementHole* ins)
|
|||
|
||||
const LUse object = useRegister(ins->object());
|
||||
const LUse elements = useRegister(ins->elements());
|
||||
const LAllocation index = useRegisterOrConstant(ins->index());
|
||||
const LAllocation index = useRegister(ins->index());
|
||||
|
||||
LDefinition spectreTemp = BoundsCheckNeedsSpectreTemp() ? temp() : LDefinition::BogusTemp();
|
||||
|
||||
LInstruction* lir;
|
||||
switch (ins->value()->type()) {
|
||||
case MIRType::Value:
|
||||
lir = new(alloc()) LStoreElementHoleV(object, elements, index, useBox(ins->value()));
|
||||
lir = new(alloc()) LStoreElementHoleV(object, elements, index, useBox(ins->value()),
|
||||
spectreTemp);
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
const LAllocation value = useRegisterOrNonDoubleConstant(ins->value());
|
||||
lir = new(alloc()) LStoreElementHoleT(object, elements, index, value);
|
||||
lir = new(alloc()) LStoreElementHoleT(object, elements, index, value, spectreTemp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -3455,16 +3470,20 @@ LIRGenerator::visitFallibleStoreElement(MFallibleStoreElement* ins)
|
|||
|
||||
const LUse object = useRegister(ins->object());
|
||||
const LUse elements = useRegister(ins->elements());
|
||||
const LAllocation index = useRegisterOrConstant(ins->index());
|
||||
const LAllocation index = useRegister(ins->index());
|
||||
|
||||
LDefinition spectreTemp = BoundsCheckNeedsSpectreTemp() ? temp() : LDefinition::BogusTemp();
|
||||
|
||||
LInstruction* lir;
|
||||
switch (ins->value()->type()) {
|
||||
case MIRType::Value:
|
||||
lir = new(alloc()) LFallibleStoreElementV(object, elements, index, useBox(ins->value()));
|
||||
lir = new(alloc()) LFallibleStoreElementV(object, elements, index, useBox(ins->value()),
|
||||
spectreTemp);
|
||||
break;
|
||||
default:
|
||||
const LAllocation value = useRegisterOrNonDoubleConstant(ins->value());
|
||||
lir = new(alloc()) LFallibleStoreElementT(object, elements, index, value);
|
||||
lir = new(alloc()) LFallibleStoreElementT(object, elements, index, value,
|
||||
spectreTemp);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -3563,10 +3582,13 @@ LIRGenerator::visitArrayPush(MArrayPush* ins)
|
|||
|
||||
LUse object = useRegister(ins->object());
|
||||
|
||||
LDefinition spectreTemp = BoundsCheckNeedsSpectreTemp() ? temp() : LDefinition::BogusTemp();
|
||||
|
||||
switch (ins->value()->type()) {
|
||||
case MIRType::Value:
|
||||
{
|
||||
LArrayPushV* lir = new(alloc()) LArrayPushV(object, useBox(ins->value()), temp());
|
||||
LArrayPushV* lir = new(alloc()) LArrayPushV(object, useBox(ins->value()), temp(),
|
||||
spectreTemp);
|
||||
define(lir, ins);
|
||||
assignSafepoint(lir, ins);
|
||||
break;
|
||||
|
@ -3575,7 +3597,7 @@ LIRGenerator::visitArrayPush(MArrayPush* ins)
|
|||
default:
|
||||
{
|
||||
const LAllocation value = useRegisterOrNonDoubleConstant(ins->value());
|
||||
LArrayPushT* lir = new(alloc()) LArrayPushT(object, value, temp());
|
||||
LArrayPushT* lir = new(alloc()) LArrayPushT(object, value, temp(), spectreTemp);
|
||||
define(lir, ins);
|
||||
assignSafepoint(lir, ins);
|
||||
break;
|
||||
|
@ -3730,18 +3752,6 @@ LIRGenerator::visitLoadTypedArrayElementHole(MLoadTypedArrayElementHole* ins)
|
|||
assignSafepoint(lir, ins);
|
||||
}
|
||||
|
||||
void
|
||||
LIRGenerator::visitLoadTypedArrayElementStatic(MLoadTypedArrayElementStatic* ins)
|
||||
{
|
||||
LLoadTypedArrayElementStatic* lir =
|
||||
new(alloc()) LLoadTypedArrayElementStatic(useRegisterAtStart(ins->ptr()));
|
||||
|
||||
// In case of out of bounds, may bail out, or may jump to ool code.
|
||||
if (ins->fallible())
|
||||
assignSnapshot(lir, Bailout_BoundsCheck);
|
||||
define(lir, ins);
|
||||
}
|
||||
|
||||
void
|
||||
LIRGenerator::visitStoreUnboxedScalar(MStoreUnboxedScalar* ins)
|
||||
{
|
||||
|
@ -3801,16 +3811,19 @@ LIRGenerator::visitStoreTypedArrayElementHole(MStoreTypedArrayElementHole* ins)
|
|||
}
|
||||
|
||||
LUse elements = useRegister(ins->elements());
|
||||
LAllocation length = useAnyOrConstant(ins->length());
|
||||
LAllocation index = useRegisterOrConstant(ins->index());
|
||||
LAllocation value;
|
||||
|
||||
LAllocation length = useAny(ins->length());
|
||||
LAllocation index = useRegister(ins->index());
|
||||
// For byte arrays, the value has to be in a byte register on x86.
|
||||
LAllocation value;
|
||||
if (ins->isByteWrite())
|
||||
value = useByteOpRegisterOrNonDoubleConstant(ins->value());
|
||||
else
|
||||
value = useRegisterOrNonDoubleConstant(ins->value());
|
||||
add(new(alloc()) LStoreTypedArrayElementHole(elements, length, index, value), ins);
|
||||
|
||||
LDefinition spectreTemp = BoundsCheckNeedsSpectreTemp() ? temp() : LDefinition::BogusTemp();
|
||||
auto* lir =
|
||||
new(alloc()) LStoreTypedArrayElementHole(elements, length, index, value, spectreTemp);
|
||||
add(lir, ins);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -5771,41 +5771,6 @@ InlinePropertyTable::appendRoots(MRootList& roots) const
|
|||
return true;
|
||||
}
|
||||
|
||||
SharedMem<void*>
|
||||
MLoadTypedArrayElementStatic::base() const
|
||||
{
|
||||
return someTypedArray_->as<TypedArrayObject>().viewDataEither();
|
||||
}
|
||||
|
||||
size_t
|
||||
MLoadTypedArrayElementStatic::length() const
|
||||
{
|
||||
return someTypedArray_->as<TypedArrayObject>().byteLength();
|
||||
}
|
||||
|
||||
bool
|
||||
MLoadTypedArrayElementStatic::congruentTo(const MDefinition* ins) const
|
||||
{
|
||||
if (!ins->isLoadTypedArrayElementStatic())
|
||||
return false;
|
||||
const MLoadTypedArrayElementStatic* other = ins->toLoadTypedArrayElementStatic();
|
||||
if (offset() != other->offset())
|
||||
return false;
|
||||
if (needsBoundsCheck() != other->needsBoundsCheck())
|
||||
return false;
|
||||
if (accessType() != other->accessType())
|
||||
return false;
|
||||
if (base() != other->base())
|
||||
return false;
|
||||
return congruentIfOperandsEqual(other);
|
||||
}
|
||||
|
||||
SharedMem<void*>
|
||||
MStoreTypedArrayElementStatic::base() const
|
||||
{
|
||||
return someTypedArray_->as<TypedArrayObject>().viewDataEither();
|
||||
}
|
||||
|
||||
bool
|
||||
MGetPropertyCache::allowDoubleResult() const
|
||||
{
|
||||
|
@ -5815,12 +5780,6 @@ MGetPropertyCache::allowDoubleResult() const
|
|||
return resultTypeSet()->hasType(TypeSet::DoubleType());
|
||||
}
|
||||
|
||||
size_t
|
||||
MStoreTypedArrayElementStatic::length() const
|
||||
{
|
||||
return someTypedArray_->as<TypedArrayObject>().byteLength();
|
||||
}
|
||||
|
||||
MDefinition::AliasType
|
||||
MGetPropertyPolymorphic::mightAlias(const MDefinition* store) const
|
||||
{
|
||||
|
|
127
js/src/jit/MIR.h
127
js/src/jit/MIR.h
|
@ -1218,7 +1218,7 @@ class MInstruction
|
|||
|
||||
// Instructions needing to hook into type analysis should return a
|
||||
// TypePolicy.
|
||||
virtual TypePolicy* typePolicy() = 0;
|
||||
virtual const TypePolicy* typePolicy() = 0;
|
||||
virtual MIRType typePolicySpecialization() = 0;
|
||||
};
|
||||
|
||||
|
@ -1230,7 +1230,7 @@ class MInstruction
|
|||
|
||||
#define INSTRUCTION_HEADER(opcode) \
|
||||
INSTRUCTION_HEADER_WITHOUT_TYPEPOLICY(opcode) \
|
||||
virtual TypePolicy* typePolicy() override; \
|
||||
virtual const TypePolicy* typePolicy() override; \
|
||||
virtual MIRType typePolicySpecialization() override;
|
||||
|
||||
#define ALLOW_CLONE(typename) \
|
||||
|
@ -7938,7 +7938,7 @@ class MPhi final
|
|||
|
||||
public:
|
||||
INSTRUCTION_HEADER_WITHOUT_TYPEPOLICY(Phi)
|
||||
virtual TypePolicy* typePolicy();
|
||||
virtual const TypePolicy* typePolicy();
|
||||
virtual MIRType typePolicySpecialization();
|
||||
|
||||
MPhi(TempAllocator& alloc, MIRType resultType)
|
||||
|
@ -10586,73 +10586,6 @@ class MLoadTypedArrayElementHole
|
|||
ALLOW_CLONE(MLoadTypedArrayElementHole)
|
||||
};
|
||||
|
||||
// Load a value fallibly or infallibly from a statically known typed array.
|
||||
class MLoadTypedArrayElementStatic
|
||||
: public MUnaryInstruction,
|
||||
public ConvertToInt32Policy<0>::Data
|
||||
{
|
||||
MLoadTypedArrayElementStatic(JSObject* someTypedArray, MDefinition* ptr,
|
||||
int32_t offset = 0, bool needsBoundsCheck = true)
|
||||
: MUnaryInstruction(classOpcode, ptr), someTypedArray_(someTypedArray), offset_(offset),
|
||||
needsBoundsCheck_(needsBoundsCheck), fallible_(true)
|
||||
{
|
||||
int type = accessType();
|
||||
if (type == Scalar::Float32)
|
||||
setResultType(MIRType::Float32);
|
||||
else if (type == Scalar::Float64)
|
||||
setResultType(MIRType::Double);
|
||||
else
|
||||
setResultType(MIRType::Int32);
|
||||
}
|
||||
|
||||
CompilerObject someTypedArray_;
|
||||
|
||||
// An offset to be encoded in the load instruction - taking advantage of the
|
||||
// addressing modes. This is only non-zero when the access is proven to be
|
||||
// within bounds.
|
||||
int32_t offset_;
|
||||
bool needsBoundsCheck_;
|
||||
bool fallible_;
|
||||
|
||||
public:
|
||||
INSTRUCTION_HEADER(LoadTypedArrayElementStatic)
|
||||
TRIVIAL_NEW_WRAPPERS
|
||||
|
||||
Scalar::Type accessType() const {
|
||||
return someTypedArray_->as<TypedArrayObject>().type();
|
||||
}
|
||||
SharedMem<void*> base() const;
|
||||
size_t length() const;
|
||||
|
||||
MDefinition* ptr() const { return getOperand(0); }
|
||||
int32_t offset() const { return offset_; }
|
||||
void setOffset(int32_t offset) { offset_ = offset; }
|
||||
bool congruentTo(const MDefinition* ins) const override;
|
||||
AliasSet getAliasSet() const override {
|
||||
return AliasSet::Load(AliasSet::UnboxedElement);
|
||||
}
|
||||
|
||||
bool needsBoundsCheck() const { return needsBoundsCheck_; }
|
||||
void setNeedsBoundsCheck(bool v) { needsBoundsCheck_ = v; }
|
||||
|
||||
bool fallible() const {
|
||||
return fallible_;
|
||||
}
|
||||
|
||||
void setInfallible() {
|
||||
fallible_ = false;
|
||||
}
|
||||
|
||||
void computeRange(TempAllocator& alloc) override;
|
||||
bool needTruncation(TruncateKind kind) override;
|
||||
bool canProduceFloat32() const override { return accessType() == Scalar::Float32; }
|
||||
void collectRangeInfoPreTrunc() override;
|
||||
|
||||
bool appendRoots(MRootList& roots) const override {
|
||||
return roots.append(someTypedArray_);
|
||||
}
|
||||
};
|
||||
|
||||
// Base class for MIR ops that write unboxed scalar values.
|
||||
class StoreUnboxedScalarBase
|
||||
{
|
||||
|
@ -10812,60 +10745,6 @@ class MStoreTypedArrayElementHole
|
|||
ALLOW_CLONE(MStoreTypedArrayElementHole)
|
||||
};
|
||||
|
||||
// Store a value infallibly to a statically known typed array.
|
||||
class MStoreTypedArrayElementStatic :
|
||||
public MBinaryInstruction,
|
||||
public StoreUnboxedScalarBase,
|
||||
public StoreTypedArrayElementStaticPolicy::Data
|
||||
{
|
||||
MStoreTypedArrayElementStatic(JSObject* someTypedArray, MDefinition* ptr, MDefinition* v,
|
||||
int32_t offset = 0, bool needsBoundsCheck = true)
|
||||
: MBinaryInstruction(classOpcode, ptr, v),
|
||||
StoreUnboxedScalarBase(someTypedArray->as<TypedArrayObject>().type()),
|
||||
someTypedArray_(someTypedArray),
|
||||
offset_(offset), needsBoundsCheck_(needsBoundsCheck)
|
||||
{}
|
||||
|
||||
CompilerObject someTypedArray_;
|
||||
|
||||
// An offset to be encoded in the store instruction - taking advantage of the
|
||||
// addressing modes. This is only non-zero when the access is proven to be
|
||||
// within bounds.
|
||||
int32_t offset_;
|
||||
bool needsBoundsCheck_;
|
||||
|
||||
public:
|
||||
INSTRUCTION_HEADER(StoreTypedArrayElementStatic)
|
||||
TRIVIAL_NEW_WRAPPERS
|
||||
|
||||
Scalar::Type accessType() const {
|
||||
return writeType();
|
||||
}
|
||||
|
||||
SharedMem<void*> base() const;
|
||||
size_t length() const;
|
||||
|
||||
MDefinition* ptr() const { return getOperand(0); }
|
||||
MDefinition* value() const { return getOperand(1); }
|
||||
bool needsBoundsCheck() const { return needsBoundsCheck_; }
|
||||
void setNeedsBoundsCheck(bool v) { needsBoundsCheck_ = v; }
|
||||
int32_t offset() const { return offset_; }
|
||||
void setOffset(int32_t offset) { offset_ = offset; }
|
||||
AliasSet getAliasSet() const override {
|
||||
return AliasSet::Store(AliasSet::UnboxedElement);
|
||||
}
|
||||
TruncateKind operandTruncateKind(size_t index) const override;
|
||||
|
||||
bool canConsumeFloat32(MUse* use) const override {
|
||||
return use == getUseFor(1) && accessType() == Scalar::Float32;
|
||||
}
|
||||
void collectRangeInfoPreTrunc() override;
|
||||
|
||||
bool appendRoots(MRootList& roots) const override {
|
||||
return roots.append(someTypedArray_);
|
||||
}
|
||||
};
|
||||
|
||||
// Compute an "effective address", i.e., a compound computation of the form:
|
||||
// base + index * scale + displacement
|
||||
class MEffectiveAddress
|
||||
|
|
|
@ -332,52 +332,9 @@ MacroAssembler::addPtr(ImmPtr imm, Register dest)
|
|||
addPtr(ImmWord(uintptr_t(imm.value)), dest);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::inc32(RegisterOrInt32Constant* key)
|
||||
{
|
||||
if (key->isRegister())
|
||||
add32(Imm32(1), key->reg());
|
||||
else
|
||||
key->bumpConstant(1);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::dec32(RegisterOrInt32Constant* key)
|
||||
{
|
||||
if (key->isRegister())
|
||||
add32(Imm32(-1), key->reg());
|
||||
else
|
||||
key->bumpConstant(-1);
|
||||
}
|
||||
|
||||
// ===============================================================
|
||||
// Branch functions
|
||||
|
||||
void
|
||||
MacroAssembler::branch32(Condition cond, Register length, const RegisterOrInt32Constant& key,
|
||||
Label* label)
|
||||
{
|
||||
branch32Impl(cond, length, key, label);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::branch32(Condition cond, const Address& length, const RegisterOrInt32Constant& key,
|
||||
Label* label)
|
||||
{
|
||||
branch32Impl(cond, length, key, label);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
MacroAssembler::branch32Impl(Condition cond, const T& length, const RegisterOrInt32Constant& key,
|
||||
Label* label)
|
||||
{
|
||||
if (key.isRegister())
|
||||
branch32(cond, length, key.reg(), label);
|
||||
else
|
||||
branch32(cond, length, Imm32(key.constant()), label);
|
||||
}
|
||||
|
||||
template <class L>
|
||||
void
|
||||
MacroAssembler::branchIfFalseBool(Register reg, L label)
|
||||
|
|
|
@ -820,11 +820,8 @@ class MacroAssembler : public MacroAssemblerSpecific
|
|||
inline void divFloat32(FloatRegister src, FloatRegister dest) PER_SHARED_ARCH;
|
||||
inline void divDouble(FloatRegister src, FloatRegister dest) PER_SHARED_ARCH;
|
||||
|
||||
inline void inc32(RegisterOrInt32Constant* key);
|
||||
inline void inc64(AbsoluteAddress dest) PER_ARCH;
|
||||
|
||||
inline void dec32(RegisterOrInt32Constant* key);
|
||||
|
||||
inline void neg32(Register reg) PER_SHARED_ARCH;
|
||||
inline void neg64(Register64 reg) DEFINED_ON(x86, x64, arm, mips32, mips64);
|
||||
|
||||
|
@ -938,13 +935,9 @@ class MacroAssembler : public MacroAssemblerSpecific
|
|||
inline void branch32(Condition cond, Register lhs, Register rhs, L label) PER_SHARED_ARCH;
|
||||
template <class L>
|
||||
inline void branch32(Condition cond, Register lhs, Imm32 rhs, L label) PER_SHARED_ARCH;
|
||||
inline void branch32(Condition cond, Register length, const RegisterOrInt32Constant& key,
|
||||
Label* label);
|
||||
|
||||
inline void branch32(Condition cond, const Address& lhs, Register rhs, Label* label) PER_SHARED_ARCH;
|
||||
inline void branch32(Condition cond, const Address& lhs, Imm32 rhs, Label* label) PER_SHARED_ARCH;
|
||||
inline void branch32(Condition cond, const Address& length, const RegisterOrInt32Constant& key,
|
||||
Label* label);
|
||||
|
||||
inline void branch32(Condition cond, const AbsoluteAddress& lhs, Register rhs, Label* label)
|
||||
DEFINED_ON(arm, arm64, mips_shared, x86, x64);
|
||||
|
@ -1278,11 +1271,6 @@ class MacroAssembler : public MacroAssemblerSpecific
|
|||
|
||||
private:
|
||||
|
||||
// Implementation for branch* methods.
|
||||
template <typename T>
|
||||
inline void branch32Impl(Condition cond, const T& length, const RegisterOrInt32Constant& key,
|
||||
Label* label);
|
||||
|
||||
template <typename T, typename S, typename L>
|
||||
inline void branchPtrImpl(Condition cond, const T& lhs, const S& rhs, L label)
|
||||
DEFINED_ON(x86_shared);
|
||||
|
@ -1362,12 +1350,20 @@ class MacroAssembler : public MacroAssemblerSpecific
|
|||
|
||||
// Performs a bounds check and zeroes the index register if out-of-bounds
|
||||
// (to mitigate Spectre).
|
||||
inline void spectreBoundsCheck32(Register index, Register length, Register scratch,
|
||||
private:
|
||||
|
||||
inline void spectreBoundsCheck32(Register index, const Operand& length, Register maybeScratch,
|
||||
Label* failure)
|
||||
DEFINED_ON(arm, arm64, mips_shared, x86_shared);
|
||||
inline void spectreBoundsCheck32(Register index, const Address& length, Register scratch,
|
||||
DEFINED_ON(x86);
|
||||
|
||||
public:
|
||||
|
||||
inline void spectreBoundsCheck32(Register index, Register length, Register maybeScratch,
|
||||
Label* failure)
|
||||
DEFINED_ON(arm, arm64, mips_shared, x86_shared);
|
||||
DEFINED_ON(arm, arm64, mips_shared, x86, x64);
|
||||
inline void spectreBoundsCheck32(Register index, const Address& length, Register maybeScratch,
|
||||
Label* failure)
|
||||
DEFINED_ON(arm, arm64, mips_shared, x86, x64);
|
||||
|
||||
// ========================================================================
|
||||
// Canonicalization primitives.
|
||||
|
@ -2121,14 +2117,6 @@ class MacroAssembler : public MacroAssemblerSpecific
|
|||
|
||||
inline void storeCallResultValue(TypedOrValueRegister dest);
|
||||
|
||||
using MacroAssemblerSpecific::store32;
|
||||
void store32(const RegisterOrInt32Constant& key, const Address& dest) {
|
||||
if (key.isRegister())
|
||||
store32(key.reg(), dest);
|
||||
else
|
||||
store32(Imm32(key.constant()), dest);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void guardedCallPreBarrier(const T& address, MIRType type) {
|
||||
Label done;
|
||||
|
|
|
@ -1801,16 +1801,6 @@ MLoadUnboxedScalar::computeRange(TempAllocator& alloc)
|
|||
setRange(GetTypedArrayRange(alloc, readType()));
|
||||
}
|
||||
|
||||
void
|
||||
MLoadTypedArrayElementStatic::computeRange(TempAllocator& alloc)
|
||||
{
|
||||
// We don't currently use MLoadTypedArrayElementStatic for uint32, so we
|
||||
// don't have to worry about it returning a value outside our type.
|
||||
MOZ_ASSERT(someTypedArray_->as<TypedArrayObject>().type() != Scalar::Uint32);
|
||||
|
||||
setRange(GetTypedArrayRange(alloc, someTypedArray_->as<TypedArrayObject>().type()));
|
||||
}
|
||||
|
||||
void
|
||||
MArrayLength::computeRange(TempAllocator& alloc)
|
||||
{
|
||||
|
@ -2672,18 +2662,6 @@ MToDouble::truncate()
|
|||
}
|
||||
}
|
||||
|
||||
bool
|
||||
MLoadTypedArrayElementStatic::needTruncation(TruncateKind kind)
|
||||
{
|
||||
// IndirectTruncate not possible, since it returns 'undefined'
|
||||
// upon out of bounds read. Doing arithmetic on 'undefined' gives wrong
|
||||
// results. So only set infallible if explicitly truncated.
|
||||
if (kind == Truncate)
|
||||
setInfallible();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
MLimitedTruncate::needTruncation(TruncateKind kind)
|
||||
{
|
||||
|
@ -2804,13 +2782,6 @@ MStoreTypedArrayElementHole::operandTruncateKind(size_t index) const
|
|||
return index == 3 && isIntegerWrite() ? Truncate : NoTruncate;
|
||||
}
|
||||
|
||||
MDefinition::TruncateKind
|
||||
MStoreTypedArrayElementStatic::operandTruncateKind(size_t index) const
|
||||
{
|
||||
// An integer store truncates the stored value.
|
||||
return index == 1 && isIntegerWrite() ? Truncate : NoTruncate;
|
||||
}
|
||||
|
||||
MDefinition::TruncateKind
|
||||
MDiv::operandTruncateKind(size_t index) const
|
||||
{
|
||||
|
@ -3268,36 +3239,6 @@ MLoadElementHole::collectRangeInfoPreTrunc()
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
MLoadTypedArrayElementStatic::collectRangeInfoPreTrunc()
|
||||
{
|
||||
Range range(ptr());
|
||||
|
||||
if (range.hasInt32LowerBound() && range.hasInt32UpperBound()) {
|
||||
int64_t offset = this->offset();
|
||||
int64_t lower = range.lower() + offset;
|
||||
int64_t upper = range.upper() + offset;
|
||||
int64_t length = this->length();
|
||||
if (lower >= 0 && upper < length)
|
||||
setNeedsBoundsCheck(false);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MStoreTypedArrayElementStatic::collectRangeInfoPreTrunc()
|
||||
{
|
||||
Range range(ptr());
|
||||
|
||||
if (range.hasInt32LowerBound() && range.hasInt32UpperBound()) {
|
||||
int64_t offset = this->offset();
|
||||
int64_t lower = range.lower() + offset;
|
||||
int64_t upper = range.upper() + offset;
|
||||
int64_t length = this->length();
|
||||
if (lower >= 0 && upper < length)
|
||||
setNeedsBoundsCheck(false);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MClz::collectRangeInfoPreTrunc()
|
||||
{
|
||||
|
|
|
@ -282,41 +282,6 @@ class ConstantOrRegister
|
|||
}
|
||||
};
|
||||
|
||||
struct RegisterOrInt32Constant {
|
||||
bool isRegister_;
|
||||
union {
|
||||
Register reg_;
|
||||
int32_t constant_;
|
||||
};
|
||||
|
||||
explicit RegisterOrInt32Constant(Register reg)
|
||||
: isRegister_(true), reg_(reg)
|
||||
{ }
|
||||
|
||||
explicit RegisterOrInt32Constant(int32_t index)
|
||||
: isRegister_(false), constant_(index)
|
||||
{ }
|
||||
|
||||
inline void bumpConstant(int diff) {
|
||||
MOZ_ASSERT(!isRegister_);
|
||||
constant_ += diff;
|
||||
}
|
||||
inline Register reg() const {
|
||||
MOZ_ASSERT(isRegister_);
|
||||
return reg_;
|
||||
}
|
||||
inline int32_t constant() const {
|
||||
MOZ_ASSERT(!isRegister_);
|
||||
return constant_;
|
||||
}
|
||||
inline bool isRegister() const {
|
||||
return isRegister_;
|
||||
}
|
||||
inline bool isConstant() const {
|
||||
return !isRegister_;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class TypedRegisterSet
|
||||
{
|
||||
|
|
|
@ -66,7 +66,7 @@ BoxInputsPolicy::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins)
|
|||
}
|
||||
|
||||
bool
|
||||
ArithPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins)
|
||||
ArithPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) const
|
||||
{
|
||||
MIRType specialization = ins->typePolicySpecialization();
|
||||
if (specialization == MIRType::None)
|
||||
|
@ -121,7 +121,7 @@ AllDoublePolicy::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins)
|
|||
}
|
||||
|
||||
bool
|
||||
ComparePolicy::adjustInputs(TempAllocator& alloc, MInstruction* def)
|
||||
ComparePolicy::adjustInputs(TempAllocator& alloc, MInstruction* def) const
|
||||
{
|
||||
MOZ_ASSERT(def->isCompare());
|
||||
MCompare* compare = def->toCompare();
|
||||
|
@ -269,7 +269,7 @@ ComparePolicy::adjustInputs(TempAllocator& alloc, MInstruction* def)
|
|||
}
|
||||
|
||||
bool
|
||||
SameValuePolicy::adjustInputs(TempAllocator& alloc, MInstruction* def)
|
||||
SameValuePolicy::adjustInputs(TempAllocator& alloc, MInstruction* def) const
|
||||
{
|
||||
MOZ_ASSERT(def->isSameValue());
|
||||
MSameValue* sameValue = def->toSameValue();
|
||||
|
@ -300,7 +300,7 @@ SameValuePolicy::adjustInputs(TempAllocator& alloc, MInstruction* def)
|
|||
}
|
||||
|
||||
bool
|
||||
TypeBarrierPolicy::adjustInputs(TempAllocator& alloc, MInstruction* def)
|
||||
TypeBarrierPolicy::adjustInputs(TempAllocator& alloc, MInstruction* def) const
|
||||
{
|
||||
MTypeBarrier* ins = def->toTypeBarrier();
|
||||
MIRType inputType = ins->getOperand(0)->type();
|
||||
|
@ -355,7 +355,7 @@ TypeBarrierPolicy::adjustInputs(TempAllocator& alloc, MInstruction* def)
|
|||
}
|
||||
|
||||
bool
|
||||
TestPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins)
|
||||
TestPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) const
|
||||
{
|
||||
MDefinition* op = ins->getOperand(0);
|
||||
switch (op->type()) {
|
||||
|
@ -386,7 +386,7 @@ TestPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins)
|
|||
}
|
||||
|
||||
bool
|
||||
BitwisePolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins)
|
||||
BitwisePolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) const
|
||||
{
|
||||
MIRType specialization = ins->typePolicySpecialization();
|
||||
if (specialization == MIRType::None)
|
||||
|
@ -413,7 +413,7 @@ BitwisePolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins)
|
|||
}
|
||||
|
||||
bool
|
||||
PowPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins)
|
||||
PowPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) const
|
||||
{
|
||||
MIRType specialization = ins->typePolicySpecialization();
|
||||
MOZ_ASSERT(specialization == MIRType::Int32 ||
|
||||
|
@ -586,7 +586,7 @@ template bool Float32Policy<2>::staticAdjustInputs(TempAllocator& alloc, MInstru
|
|||
|
||||
template <unsigned Op>
|
||||
bool
|
||||
FloatingPointPolicy<Op>::adjustInputs(TempAllocator& alloc, MInstruction* def)
|
||||
FloatingPointPolicy<Op>::adjustInputs(TempAllocator& alloc, MInstruction* def) const
|
||||
{
|
||||
MIRType policyType = def->typePolicySpecialization();
|
||||
if (policyType == MIRType::Double)
|
||||
|
@ -594,7 +594,7 @@ FloatingPointPolicy<Op>::adjustInputs(TempAllocator& alloc, MInstruction* def)
|
|||
return Float32Policy<Op>::staticAdjustInputs(alloc, def);
|
||||
}
|
||||
|
||||
template bool FloatingPointPolicy<0>::adjustInputs(TempAllocator& alloc, MInstruction* def);
|
||||
template bool FloatingPointPolicy<0>::adjustInputs(TempAllocator& alloc, MInstruction* def) const;
|
||||
|
||||
template <unsigned Op>
|
||||
bool
|
||||
|
@ -611,16 +611,16 @@ template bool NoFloatPolicy<3>::staticAdjustInputs(TempAllocator& alloc, MInstru
|
|||
|
||||
template <unsigned FirstOp>
|
||||
bool
|
||||
NoFloatPolicyAfter<FirstOp>::adjustInputs(TempAllocator& alloc, MInstruction* def)
|
||||
NoFloatPolicyAfter<FirstOp>::adjustInputs(TempAllocator& alloc, MInstruction* def) const
|
||||
{
|
||||
for (size_t op = FirstOp, e = def->numOperands(); op < e; op++)
|
||||
EnsureOperandNotFloat32(alloc, def, op);
|
||||
return true;
|
||||
}
|
||||
|
||||
template bool NoFloatPolicyAfter<0>::adjustInputs(TempAllocator& alloc, MInstruction* def);
|
||||
template bool NoFloatPolicyAfter<1>::adjustInputs(TempAllocator& alloc, MInstruction* def);
|
||||
template bool NoFloatPolicyAfter<2>::adjustInputs(TempAllocator& alloc, MInstruction* def);
|
||||
template bool NoFloatPolicyAfter<0>::adjustInputs(TempAllocator& alloc, MInstruction* def) const;
|
||||
template bool NoFloatPolicyAfter<1>::adjustInputs(TempAllocator& alloc, MInstruction* def) const;
|
||||
template bool NoFloatPolicyAfter<2>::adjustInputs(TempAllocator& alloc, MInstruction* def) const;
|
||||
|
||||
template <unsigned Op>
|
||||
bool
|
||||
|
@ -856,7 +856,7 @@ template bool
|
|||
SimdSameAsReturnedTypePolicy<1>::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins);
|
||||
|
||||
bool
|
||||
SimdAllPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins)
|
||||
SimdAllPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) const
|
||||
{
|
||||
for (unsigned i = 0, e = ins->numOperands(); i < e; i++)
|
||||
MOZ_ASSERT(ins->getOperand(i)->type() == ins->typePolicySpecialization());
|
||||
|
@ -865,17 +865,17 @@ SimdAllPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins)
|
|||
|
||||
template <unsigned Op>
|
||||
bool
|
||||
SimdPolicy<Op>::adjustInputs(TempAllocator& alloc, MInstruction* ins)
|
||||
SimdPolicy<Op>::adjustInputs(TempAllocator& alloc, MInstruction* ins) const
|
||||
{
|
||||
MOZ_ASSERT(ins->typePolicySpecialization() == ins->getOperand(Op)->type());
|
||||
return true;
|
||||
}
|
||||
|
||||
template bool
|
||||
SimdPolicy<0>::adjustInputs(TempAllocator& alloc, MInstruction* ins);
|
||||
SimdPolicy<0>::adjustInputs(TempAllocator& alloc, MInstruction* ins) const;
|
||||
|
||||
bool
|
||||
SimdShufflePolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins)
|
||||
SimdShufflePolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) const
|
||||
{
|
||||
MSimdGeneralShuffle* s = ins->toSimdGeneralShuffle();
|
||||
|
||||
|
@ -899,7 +899,7 @@ SimdShufflePolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins)
|
|||
}
|
||||
|
||||
bool
|
||||
SimdSelectPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins)
|
||||
SimdSelectPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) const
|
||||
{
|
||||
// First input is the mask, which has to be a boolean.
|
||||
MOZ_ASSERT(IsBooleanSimdType(ins->getOperand(0)->type()));
|
||||
|
@ -912,7 +912,7 @@ SimdSelectPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins)
|
|||
}
|
||||
|
||||
bool
|
||||
CallPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins)
|
||||
CallPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) const
|
||||
{
|
||||
MCall* call = ins->toCall();
|
||||
|
||||
|
@ -936,7 +936,7 @@ CallPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins)
|
|||
}
|
||||
|
||||
bool
|
||||
CallSetElementPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins)
|
||||
CallSetElementPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) const
|
||||
{
|
||||
// The first operand should be an object.
|
||||
if (!SingleObjectPolicy::staticAdjustInputs(alloc, ins))
|
||||
|
@ -953,7 +953,7 @@ CallSetElementPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins)
|
|||
}
|
||||
|
||||
bool
|
||||
InstanceOfPolicy::adjustInputs(TempAllocator& alloc, MInstruction* def)
|
||||
InstanceOfPolicy::adjustInputs(TempAllocator& alloc, MInstruction* def) const
|
||||
{
|
||||
// Box first operand if it isn't object
|
||||
if (def->getOperand(0)->type() != MIRType::Object)
|
||||
|
@ -1054,7 +1054,7 @@ StoreUnboxedScalarPolicy::adjustValueInput(TempAllocator& alloc, MInstruction* i
|
|||
}
|
||||
|
||||
bool
|
||||
StoreUnboxedScalarPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins)
|
||||
StoreUnboxedScalarPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) const
|
||||
{
|
||||
if (!SingleObjectPolicy::staticAdjustInputs(alloc, ins))
|
||||
return false;
|
||||
|
@ -1067,7 +1067,7 @@ StoreUnboxedScalarPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins)
|
|||
}
|
||||
|
||||
bool
|
||||
StoreTypedArrayHolePolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins)
|
||||
StoreTypedArrayHolePolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) const
|
||||
{
|
||||
MStoreTypedArrayElementHole* store = ins->toStoreTypedArrayElementHole();
|
||||
MOZ_ASSERT(store->elements()->type() == MIRType::Elements);
|
||||
|
@ -1078,16 +1078,7 @@ StoreTypedArrayHolePolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins)
|
|||
}
|
||||
|
||||
bool
|
||||
StoreTypedArrayElementStaticPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins)
|
||||
{
|
||||
MStoreTypedArrayElementStatic* store = ins->toStoreTypedArrayElementStatic();
|
||||
|
||||
return ConvertToInt32Policy<0>::staticAdjustInputs(alloc, ins) &&
|
||||
StoreUnboxedScalarPolicy::adjustValueInput(alloc, ins, store->accessType(), store->value(), 1);
|
||||
}
|
||||
|
||||
bool
|
||||
StoreUnboxedObjectOrNullPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins)
|
||||
StoreUnboxedObjectOrNullPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) const
|
||||
{
|
||||
if (!ObjectPolicy<0>::staticAdjustInputs(alloc, ins))
|
||||
return false;
|
||||
|
@ -1128,7 +1119,7 @@ StoreUnboxedObjectOrNullPolicy::adjustInputs(TempAllocator& alloc, MInstruction*
|
|||
}
|
||||
|
||||
bool
|
||||
StoreUnboxedStringPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins)
|
||||
StoreUnboxedStringPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) const
|
||||
{
|
||||
if (!ObjectPolicy<0>::staticAdjustInputs(alloc, ins))
|
||||
return false;
|
||||
|
@ -1155,7 +1146,7 @@ StoreUnboxedStringPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins)
|
|||
}
|
||||
|
||||
bool
|
||||
ClampPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins)
|
||||
ClampPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) const
|
||||
{
|
||||
MDefinition* in = ins->toClampToUint8()->input();
|
||||
|
||||
|
@ -1173,7 +1164,7 @@ ClampPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins)
|
|||
}
|
||||
|
||||
bool
|
||||
FilterTypeSetPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins)
|
||||
FilterTypeSetPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) const
|
||||
{
|
||||
MOZ_ASSERT(ins->numOperands() == 1);
|
||||
MIRType inputType = ins->getOperand(0)->type();
|
||||
|
@ -1266,7 +1257,6 @@ FilterTypeSetPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins)
|
|||
_(SimdAllPolicy) \
|
||||
_(SimdSelectPolicy) \
|
||||
_(SimdShufflePolicy) \
|
||||
_(StoreTypedArrayElementStaticPolicy) \
|
||||
_(StoreTypedArrayHolePolicy) \
|
||||
_(StoreUnboxedScalarPolicy) \
|
||||
_(StoreUnboxedObjectOrNullPolicy) \
|
||||
|
@ -1352,10 +1342,10 @@ namespace jit {
|
|||
//
|
||||
// This Macro use __VA_ARGS__ to account for commas of template parameters.
|
||||
#define DEFINE_TYPE_POLICY_SINGLETON_INSTANCES_(...) \
|
||||
TypePolicy * \
|
||||
const TypePolicy* \
|
||||
__VA_ARGS__::Data::thisTypePolicy() \
|
||||
{ \
|
||||
static __VA_ARGS__ singletonType; \
|
||||
static constexpr __VA_ARGS__ singletonType; \
|
||||
return &singletonType; \
|
||||
}
|
||||
|
||||
|
@ -1388,7 +1378,7 @@ thisTypeSpecialization()
|
|||
// inherited from the TypePolicy::Data structure, or a member inherited from
|
||||
// NoTypePolicy if the MIR instruction has no type policy.
|
||||
#define DEFINE_MIR_TYPEPOLICY_MEMBERS_(op) \
|
||||
TypePolicy * \
|
||||
const TypePolicy* \
|
||||
js::jit::M##op::typePolicy() \
|
||||
{ \
|
||||
return M##op::thisTypePolicy(); \
|
||||
|
|
|
@ -32,7 +32,7 @@ class TypePolicy
|
|||
// * If untyped, optionally ask the input to try and specialize its value.
|
||||
// * Replace the operand with a conversion instruction.
|
||||
// * Insert an unconditional deoptimization (no conversion possible).
|
||||
virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) = 0;
|
||||
virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) const = 0;
|
||||
};
|
||||
|
||||
struct TypeSpecializationData
|
||||
|
@ -56,13 +56,13 @@ struct TypeSpecializationData
|
|||
#define EMPTY_DATA_ \
|
||||
struct Data \
|
||||
{ \
|
||||
static TypePolicy* thisTypePolicy(); \
|
||||
static const TypePolicy* thisTypePolicy(); \
|
||||
}
|
||||
|
||||
#define INHERIT_DATA_(DATA_TYPE) \
|
||||
struct Data : public DATA_TYPE \
|
||||
{ \
|
||||
static TypePolicy* thisTypePolicy(); \
|
||||
static const TypePolicy* thisTypePolicy(); \
|
||||
}
|
||||
|
||||
#define SPECIALIZATION_DATA_ INHERIT_DATA_(TypeSpecializationData)
|
||||
|
@ -72,7 +72,7 @@ class NoTypePolicy
|
|||
public:
|
||||
struct Data
|
||||
{
|
||||
static TypePolicy* thisTypePolicy() {
|
||||
static const TypePolicy* thisTypePolicy() {
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
@ -83,7 +83,7 @@ class BoxInputsPolicy final : public TypePolicy
|
|||
public:
|
||||
SPECIALIZATION_DATA_;
|
||||
static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
|
||||
virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override {
|
||||
MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) const override {
|
||||
return staticAdjustInputs(alloc, def);
|
||||
}
|
||||
};
|
||||
|
@ -92,7 +92,7 @@ class ArithPolicy final : public TypePolicy
|
|||
{
|
||||
public:
|
||||
SPECIALIZATION_DATA_;
|
||||
virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override;
|
||||
MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) const override;
|
||||
};
|
||||
|
||||
class AllDoublePolicy final : public TypePolicy
|
||||
|
@ -100,7 +100,7 @@ class AllDoublePolicy final : public TypePolicy
|
|||
public:
|
||||
EMPTY_DATA_;
|
||||
static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
|
||||
MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override {
|
||||
MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) const override {
|
||||
return staticAdjustInputs(alloc, def);
|
||||
}
|
||||
};
|
||||
|
@ -109,21 +109,21 @@ class BitwisePolicy final : public TypePolicy
|
|||
{
|
||||
public:
|
||||
SPECIALIZATION_DATA_;
|
||||
virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override;
|
||||
MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) const override;
|
||||
};
|
||||
|
||||
class ComparePolicy final : public TypePolicy
|
||||
{
|
||||
public:
|
||||
EMPTY_DATA_;
|
||||
virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override;
|
||||
MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) const override;
|
||||
};
|
||||
|
||||
class SameValuePolicy final : public TypePolicy
|
||||
{
|
||||
public:
|
||||
EMPTY_DATA_;
|
||||
virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override;
|
||||
MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) const override;
|
||||
};
|
||||
|
||||
// Policy for MTest instructions.
|
||||
|
@ -131,21 +131,21 @@ class TestPolicy final : public TypePolicy
|
|||
{
|
||||
public:
|
||||
EMPTY_DATA_;
|
||||
virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override;
|
||||
MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) const override;
|
||||
};
|
||||
|
||||
class TypeBarrierPolicy final : public TypePolicy
|
||||
{
|
||||
public:
|
||||
EMPTY_DATA_;
|
||||
virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override;
|
||||
MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) const override;
|
||||
};
|
||||
|
||||
class CallPolicy final : public TypePolicy
|
||||
{
|
||||
public:
|
||||
EMPTY_DATA_;
|
||||
virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override;
|
||||
MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) const override;
|
||||
};
|
||||
|
||||
// Policy for MPow. First operand Double; second Double or Int32.
|
||||
|
@ -153,7 +153,7 @@ class PowPolicy final : public TypePolicy
|
|||
{
|
||||
public:
|
||||
SPECIALIZATION_DATA_;
|
||||
virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override;
|
||||
MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) const override;
|
||||
};
|
||||
|
||||
// Expect a string for operand Op. If the input is a Value, it is unboxed.
|
||||
|
@ -163,7 +163,7 @@ class StringPolicy final : public TypePolicy
|
|||
public:
|
||||
EMPTY_DATA_;
|
||||
static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
|
||||
virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override {
|
||||
MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) const override {
|
||||
return staticAdjustInputs(alloc, def);
|
||||
}
|
||||
};
|
||||
|
@ -175,7 +175,7 @@ class ConvertToStringPolicy final : public TypePolicy
|
|||
public:
|
||||
EMPTY_DATA_;
|
||||
static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
|
||||
virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override {
|
||||
MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) const override {
|
||||
return staticAdjustInputs(alloc, def);
|
||||
}
|
||||
};
|
||||
|
@ -187,7 +187,7 @@ class BooleanPolicy final : private TypePolicy
|
|||
public:
|
||||
EMPTY_DATA_;
|
||||
static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
|
||||
virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override {
|
||||
MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) const override {
|
||||
return staticAdjustInputs(alloc, def);
|
||||
}
|
||||
};
|
||||
|
@ -199,7 +199,7 @@ class UnboxedInt32Policy final : private TypePolicy
|
|||
public:
|
||||
EMPTY_DATA_;
|
||||
static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
|
||||
virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override {
|
||||
MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) const override {
|
||||
return staticAdjustInputs(alloc, def);
|
||||
}
|
||||
};
|
||||
|
@ -211,7 +211,7 @@ class ConvertToInt32Policy final : public TypePolicy
|
|||
public:
|
||||
EMPTY_DATA_;
|
||||
static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
|
||||
virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override {
|
||||
MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) const override {
|
||||
return staticAdjustInputs(alloc, def);
|
||||
}
|
||||
};
|
||||
|
@ -223,7 +223,7 @@ class TruncateToInt32Policy final : public TypePolicy
|
|||
public:
|
||||
EMPTY_DATA_;
|
||||
static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
|
||||
virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override {
|
||||
MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) const override {
|
||||
return staticAdjustInputs(alloc, def);
|
||||
}
|
||||
};
|
||||
|
@ -235,7 +235,7 @@ class DoublePolicy final : public TypePolicy
|
|||
public:
|
||||
EMPTY_DATA_;
|
||||
static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
|
||||
virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override {
|
||||
MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) const override {
|
||||
return staticAdjustInputs(alloc, def);
|
||||
}
|
||||
};
|
||||
|
@ -247,7 +247,7 @@ class Float32Policy final : public TypePolicy
|
|||
public:
|
||||
EMPTY_DATA_;
|
||||
static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
|
||||
virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override {
|
||||
MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) const override {
|
||||
return staticAdjustInputs(alloc, def);
|
||||
}
|
||||
};
|
||||
|
@ -259,7 +259,7 @@ class FloatingPointPolicy final : public TypePolicy
|
|||
{
|
||||
public:
|
||||
SPECIALIZATION_DATA_;
|
||||
virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override;
|
||||
MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) const override;
|
||||
};
|
||||
|
||||
template <unsigned Op>
|
||||
|
@ -268,7 +268,7 @@ class NoFloatPolicy final : public TypePolicy
|
|||
public:
|
||||
EMPTY_DATA_;
|
||||
static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
|
||||
virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override {
|
||||
MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) const override {
|
||||
return staticAdjustInputs(alloc, def);
|
||||
}
|
||||
};
|
||||
|
@ -280,7 +280,7 @@ class NoFloatPolicyAfter final : public TypePolicy
|
|||
{
|
||||
public:
|
||||
EMPTY_DATA_;
|
||||
virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override;
|
||||
MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) const override;
|
||||
};
|
||||
|
||||
// Box objects or strings as an input to a ToDouble instruction.
|
||||
|
@ -289,7 +289,7 @@ class ToDoublePolicy final : public TypePolicy
|
|||
public:
|
||||
EMPTY_DATA_;
|
||||
static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
|
||||
virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override {
|
||||
MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) const override {
|
||||
return staticAdjustInputs(alloc, def);
|
||||
}
|
||||
};
|
||||
|
@ -300,7 +300,7 @@ class ToInt32Policy final : public TypePolicy
|
|||
public:
|
||||
EMPTY_DATA_;
|
||||
static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
|
||||
virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override {
|
||||
MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) const override {
|
||||
return staticAdjustInputs(alloc, def);
|
||||
}
|
||||
};
|
||||
|
@ -311,7 +311,7 @@ class ToStringPolicy final : public TypePolicy
|
|||
public:
|
||||
EMPTY_DATA_;
|
||||
static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
|
||||
virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override {
|
||||
MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) const override {
|
||||
return staticAdjustInputs(alloc, def);
|
||||
}
|
||||
};
|
||||
|
@ -322,7 +322,7 @@ class ObjectPolicy final : public TypePolicy
|
|||
public:
|
||||
EMPTY_DATA_;
|
||||
static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* ins);
|
||||
virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override {
|
||||
MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) const override {
|
||||
return staticAdjustInputs(alloc, ins);
|
||||
}
|
||||
};
|
||||
|
@ -339,7 +339,7 @@ class SimdScalarPolicy final : public TypePolicy
|
|||
public:
|
||||
EMPTY_DATA_;
|
||||
static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
|
||||
virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override {
|
||||
MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) const override {
|
||||
return staticAdjustInputs(alloc, def);
|
||||
}
|
||||
};
|
||||
|
@ -348,7 +348,7 @@ class SimdAllPolicy final : public TypePolicy
|
|||
{
|
||||
public:
|
||||
SPECIALIZATION_DATA_;
|
||||
virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override;
|
||||
MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) const override;
|
||||
};
|
||||
|
||||
template <unsigned Op>
|
||||
|
@ -356,21 +356,21 @@ class SimdPolicy final : public TypePolicy
|
|||
{
|
||||
public:
|
||||
SPECIALIZATION_DATA_;
|
||||
virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override;
|
||||
MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) const override;
|
||||
};
|
||||
|
||||
class SimdSelectPolicy final : public TypePolicy
|
||||
{
|
||||
public:
|
||||
SPECIALIZATION_DATA_;
|
||||
virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override;
|
||||
MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) const override;
|
||||
};
|
||||
|
||||
class SimdShufflePolicy final : public TypePolicy
|
||||
{
|
||||
public:
|
||||
SPECIALIZATION_DATA_;
|
||||
virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override;
|
||||
MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) const override;
|
||||
};
|
||||
|
||||
// SIMD value-type policy, use the returned type of the instruction to determine
|
||||
|
@ -381,7 +381,7 @@ class SimdSameAsReturnedTypePolicy final : public TypePolicy
|
|||
public:
|
||||
EMPTY_DATA_;
|
||||
static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* ins);
|
||||
virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override {
|
||||
MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) const override {
|
||||
return staticAdjustInputs(alloc, ins);
|
||||
}
|
||||
};
|
||||
|
@ -392,7 +392,7 @@ class BoxPolicy final : public TypePolicy
|
|||
public:
|
||||
EMPTY_DATA_;
|
||||
static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* ins);
|
||||
virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override {
|
||||
MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) const override {
|
||||
return staticAdjustInputs(alloc, ins);
|
||||
}
|
||||
};
|
||||
|
@ -404,7 +404,7 @@ class BoxExceptPolicy final : public TypePolicy
|
|||
public:
|
||||
EMPTY_DATA_;
|
||||
static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* ins);
|
||||
MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override {
|
||||
MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) const override {
|
||||
return staticAdjustInputs(alloc, ins);
|
||||
}
|
||||
};
|
||||
|
@ -416,7 +416,7 @@ class CacheIdPolicy final : public TypePolicy
|
|||
public:
|
||||
EMPTY_DATA_;
|
||||
static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* ins);
|
||||
MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override {
|
||||
MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) const override {
|
||||
return staticAdjustInputs(alloc, ins);
|
||||
}
|
||||
};
|
||||
|
@ -442,7 +442,7 @@ class MixPolicy final : public TypePolicy
|
|||
static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* ins) {
|
||||
return MixPolicy::staticAdjustInputsHelper<Policies...>(alloc, ins);
|
||||
}
|
||||
virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override {
|
||||
MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) const override {
|
||||
return staticAdjustInputs(alloc, ins);
|
||||
}
|
||||
};
|
||||
|
@ -451,7 +451,7 @@ class CallSetElementPolicy final : public TypePolicy
|
|||
{
|
||||
public:
|
||||
EMPTY_DATA_;
|
||||
virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override;
|
||||
MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) const override;
|
||||
};
|
||||
|
||||
// First operand will be boxed to a Value (except for an object)
|
||||
|
@ -460,11 +460,10 @@ class InstanceOfPolicy final : public TypePolicy
|
|||
{
|
||||
public:
|
||||
EMPTY_DATA_;
|
||||
virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override;
|
||||
MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) const override;
|
||||
};
|
||||
|
||||
class StoreTypedArrayHolePolicy;
|
||||
class StoreTypedArrayElementStaticPolicy;
|
||||
|
||||
class StoreUnboxedScalarPolicy : public TypePolicy
|
||||
{
|
||||
|
@ -474,39 +473,31 @@ class StoreUnboxedScalarPolicy : public TypePolicy
|
|||
int valueOperand);
|
||||
|
||||
friend class StoreTypedArrayHolePolicy;
|
||||
friend class StoreTypedArrayElementStaticPolicy;
|
||||
|
||||
public:
|
||||
EMPTY_DATA_;
|
||||
virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override;
|
||||
MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) const override;
|
||||
};
|
||||
|
||||
class StoreTypedArrayHolePolicy final : public StoreUnboxedScalarPolicy
|
||||
{
|
||||
public:
|
||||
EMPTY_DATA_;
|
||||
virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override;
|
||||
};
|
||||
|
||||
class StoreTypedArrayElementStaticPolicy final : public StoreUnboxedScalarPolicy
|
||||
{
|
||||
public:
|
||||
EMPTY_DATA_;
|
||||
virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override;
|
||||
MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) const override;
|
||||
};
|
||||
|
||||
class StoreUnboxedObjectOrNullPolicy final : public TypePolicy
|
||||
{
|
||||
public:
|
||||
EMPTY_DATA_;
|
||||
virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override;
|
||||
MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) const override;
|
||||
};
|
||||
|
||||
class StoreUnboxedStringPolicy final : public TypePolicy
|
||||
{
|
||||
public:
|
||||
EMPTY_DATA_;
|
||||
virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override;
|
||||
MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) const override;
|
||||
};
|
||||
|
||||
// Accepts integers and doubles. Everything else is boxed.
|
||||
|
@ -514,14 +505,14 @@ class ClampPolicy final : public TypePolicy
|
|||
{
|
||||
public:
|
||||
EMPTY_DATA_;
|
||||
virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override;
|
||||
MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) const override;
|
||||
};
|
||||
|
||||
class FilterTypeSetPolicy final : public TypePolicy
|
||||
{
|
||||
public:
|
||||
EMPTY_DATA_;
|
||||
virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override;
|
||||
MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) const override;
|
||||
};
|
||||
|
||||
#undef SPECIALIZATION_DATA_
|
||||
|
|
|
@ -1766,18 +1766,6 @@ CodeGeneratorARM::generateInvalidateEpilogue()
|
|||
masm.assumeUnreachable("Should have returned directly to its caller instead of here.");
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenerator::visitLoadTypedArrayElementStatic(LLoadTypedArrayElementStatic* ins)
|
||||
{
|
||||
MOZ_CRASH("NYI");
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenerator::visitStoreTypedArrayElementStatic(LStoreTypedArrayElementStatic* ins)
|
||||
{
|
||||
MOZ_CRASH("NYI");
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenerator::visitCompareExchangeTypedArrayElement(LCompareExchangeTypedArrayElement* lir)
|
||||
{
|
||||
|
|
|
@ -784,12 +784,6 @@ LIRGeneratorARM::lowerTruncateFToInt32(MTruncateToInt32* ins)
|
|||
define(new(alloc()) LTruncateFToInt32(useRegister(opd), LDefinition::BogusTemp()), ins);
|
||||
}
|
||||
|
||||
void
|
||||
LIRGenerator::visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic* ins)
|
||||
{
|
||||
MOZ_CRASH("NYI");
|
||||
}
|
||||
|
||||
void
|
||||
LIRGenerator::visitAtomicExchangeTypedArrayElement(MAtomicExchangeTypedArrayElement* ins)
|
||||
{
|
||||
|
|
|
@ -2194,37 +2194,31 @@ MacroAssembler::spectreZeroRegister(Condition cond, Register, Register dest)
|
|||
}
|
||||
|
||||
void
|
||||
MacroAssembler::spectreBoundsCheck32(Register index, Register length, Register scratch,
|
||||
MacroAssembler::spectreBoundsCheck32(Register index, Register length, Register maybeScratch,
|
||||
Label* failure)
|
||||
{
|
||||
MOZ_ASSERT(index != length);
|
||||
MOZ_ASSERT(length != scratch);
|
||||
MOZ_ASSERT(index != scratch);
|
||||
|
||||
if (JitOptions.spectreIndexMasking)
|
||||
move32(Imm32(0), scratch);
|
||||
MOZ_ASSERT(length != maybeScratch);
|
||||
MOZ_ASSERT(index != maybeScratch);
|
||||
|
||||
branch32(Assembler::BelowOrEqual, length, index, failure);
|
||||
|
||||
if (JitOptions.spectreIndexMasking)
|
||||
ma_mov(scratch, index, LeaveCC, Assembler::BelowOrEqual);
|
||||
ma_mov(Imm32(0), index, Assembler::BelowOrEqual);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::spectreBoundsCheck32(Register index, const Address& length, Register scratch,
|
||||
MacroAssembler::spectreBoundsCheck32(Register index, const Address& length, Register maybeScratch,
|
||||
Label* failure)
|
||||
{
|
||||
MOZ_ASSERT(index != length.base);
|
||||
MOZ_ASSERT(length.base != scratch);
|
||||
MOZ_ASSERT(index != scratch);
|
||||
|
||||
if (JitOptions.spectreIndexMasking)
|
||||
move32(Imm32(0), scratch);
|
||||
MOZ_ASSERT(length.base != maybeScratch);
|
||||
MOZ_ASSERT(index != maybeScratch);
|
||||
|
||||
branch32(Assembler::BelowOrEqual, length, index, failure);
|
||||
|
||||
if (JitOptions.spectreIndexMasking)
|
||||
ma_mov(scratch, index, LeaveCC, Assembler::BelowOrEqual);
|
||||
ma_mov(Imm32(0), index, Assembler::BelowOrEqual);
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
|
|
|
@ -568,18 +568,6 @@ getBase(U* mir)
|
|||
return InvalidReg;
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenerator::visitLoadTypedArrayElementStatic(LLoadTypedArrayElementStatic* ins)
|
||||
{
|
||||
MOZ_CRASH("CodeGenerator::visitLoadTypedArrayElementStatic");
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenerator::visitStoreTypedArrayElementStatic(LStoreTypedArrayElementStatic* ins)
|
||||
{
|
||||
MOZ_CRASH("CodeGenerator::visitStoreTypedArrayElementStatic");
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenerator::visitAsmJSLoadHeap(LAsmJSLoadHeap* ins)
|
||||
{
|
||||
|
|
|
@ -280,12 +280,6 @@ LIRGeneratorARM64::lowerTruncateFToInt32(MTruncateToInt32* ins)
|
|||
MOZ_CRASH("lowerTruncateFToInt32");
|
||||
}
|
||||
|
||||
void
|
||||
LIRGenerator::visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic* ins)
|
||||
{
|
||||
MOZ_CRASH("NYI");
|
||||
}
|
||||
|
||||
void
|
||||
LIRGenerator::visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop* ins)
|
||||
{
|
||||
|
|
|
@ -1875,12 +1875,12 @@ MacroAssembler::spectreZeroRegister(Condition cond, Register, Register dest)
|
|||
}
|
||||
|
||||
void
|
||||
MacroAssembler::spectreBoundsCheck32(Register index, Register length, Register scratch,
|
||||
MacroAssembler::spectreBoundsCheck32(Register index, Register length, Register maybeScratch,
|
||||
Label* failure)
|
||||
{
|
||||
MOZ_ASSERT(index != length);
|
||||
MOZ_ASSERT(length != scratch);
|
||||
MOZ_ASSERT(index != scratch);
|
||||
MOZ_ASSERT(length != maybeScratch);
|
||||
MOZ_ASSERT(index != maybeScratch);
|
||||
|
||||
branch32(Assembler::BelowOrEqual, length, index, failure);
|
||||
|
||||
|
@ -1889,12 +1889,12 @@ MacroAssembler::spectreBoundsCheck32(Register index, Register length, Register s
|
|||
}
|
||||
|
||||
void
|
||||
MacroAssembler::spectreBoundsCheck32(Register index, const Address& length, Register scratch,
|
||||
MacroAssembler::spectreBoundsCheck32(Register index, const Address& length, Register maybeScratch,
|
||||
Label* failure)
|
||||
{
|
||||
MOZ_ASSERT(index != length.base);
|
||||
MOZ_ASSERT(length.base != scratch);
|
||||
MOZ_ASSERT(index != scratch);
|
||||
MOZ_ASSERT(length.base != maybeScratch);
|
||||
MOZ_ASSERT(index != maybeScratch);
|
||||
|
||||
branch32(Assembler::BelowOrEqual, length, index, failure);
|
||||
|
||||
|
|
|
@ -1800,18 +1800,6 @@ CodeGeneratorMIPSShared::generateInvalidateEpilogue()
|
|||
masm.assumeUnreachable("Should have returned directly to its caller instead of here.");
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenerator::visitLoadTypedArrayElementStatic(LLoadTypedArrayElementStatic* ins)
|
||||
{
|
||||
MOZ_CRASH("NYI");
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenerator::visitStoreTypedArrayElementStatic(LStoreTypedArrayElementStatic* ins)
|
||||
{
|
||||
MOZ_CRASH("NYI");
|
||||
}
|
||||
|
||||
class js::jit::OutOfLineTableSwitch : public OutOfLineCodeBase<CodeGeneratorMIPSShared>
|
||||
{
|
||||
MTableSwitch* mir_;
|
||||
|
|
|
@ -557,12 +557,6 @@ LIRGenerator::visitSubstr(MSubstr* ins)
|
|||
assignSafepoint(lir, ins);
|
||||
}
|
||||
|
||||
void
|
||||
LIRGenerator::visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic* ins)
|
||||
{
|
||||
MOZ_CRASH("NYI");
|
||||
}
|
||||
|
||||
void
|
||||
LIRGenerator::visitCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement* ins)
|
||||
{
|
||||
|
|
|
@ -1017,7 +1017,7 @@ MacroAssembler::test32MovePtr(Condition cond, const Address& addr, Imm32 mask, R
|
|||
}
|
||||
|
||||
void
|
||||
MacroAssembler::spectreBoundsCheck32(Register index, Register length, Register scratch,
|
||||
MacroAssembler::spectreBoundsCheck32(Register index, Register length, Register maybeScratch,
|
||||
Label* failure)
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(!JitOptions.spectreIndexMasking);
|
||||
|
@ -1025,7 +1025,7 @@ MacroAssembler::spectreBoundsCheck32(Register index, Register length, Register s
|
|||
}
|
||||
|
||||
void
|
||||
MacroAssembler::spectreBoundsCheck32(Register index, const Address& length, Register scratch,
|
||||
MacroAssembler::spectreBoundsCheck32(Register index, const Address& length, Register maybeScratch,
|
||||
Label* failure)
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(!JitOptions.spectreIndexMasking);
|
||||
|
|
|
@ -184,14 +184,6 @@ ToAnyRegister(const LDefinition* def)
|
|||
return ToAnyRegister(def->output());
|
||||
}
|
||||
|
||||
static inline RegisterOrInt32Constant
|
||||
ToRegisterOrInt32Constant(const LAllocation* a)
|
||||
{
|
||||
if (a->isConstant())
|
||||
return RegisterOrInt32Constant(ToInt32(a));
|
||||
return RegisterOrInt32Constant(ToRegister(a));
|
||||
}
|
||||
|
||||
static inline ValueOperand
|
||||
ToOutValue(LInstruction* ins)
|
||||
{
|
||||
|
|
|
@ -6440,19 +6440,21 @@ class LStoreElementT : public LInstructionHelper<0, 3, 0>
|
|||
};
|
||||
|
||||
// Like LStoreElementV, but supports indexes >= initialized length.
|
||||
class LStoreElementHoleV : public LInstructionHelper<0, 3 + BOX_PIECES, 0>
|
||||
class LStoreElementHoleV : public LInstructionHelper<0, 3 + BOX_PIECES, 1>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(StoreElementHoleV)
|
||||
|
||||
LStoreElementHoleV(const LAllocation& object, const LAllocation& elements,
|
||||
const LAllocation& index, const LBoxAllocation& value)
|
||||
const LAllocation& index, const LBoxAllocation& value,
|
||||
const LDefinition& spectreTemp)
|
||||
: LInstructionHelper(classOpcode)
|
||||
{
|
||||
setOperand(0, object);
|
||||
setOperand(1, elements);
|
||||
setOperand(2, index);
|
||||
setBoxOperand(Value, value);
|
||||
setTemp(0, spectreTemp);
|
||||
}
|
||||
|
||||
static const size_t Value = 3;
|
||||
|
@ -6469,22 +6471,27 @@ class LStoreElementHoleV : public LInstructionHelper<0, 3 + BOX_PIECES, 0>
|
|||
const LAllocation* index() {
|
||||
return getOperand(2);
|
||||
}
|
||||
const LDefinition* spectreTemp() {
|
||||
return getTemp(0);
|
||||
}
|
||||
};
|
||||
|
||||
// Like LStoreElementT, but supports indexes >= initialized length.
|
||||
class LStoreElementHoleT : public LInstructionHelper<0, 4, 0>
|
||||
class LStoreElementHoleT : public LInstructionHelper<0, 4, 1>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(StoreElementHoleT)
|
||||
|
||||
LStoreElementHoleT(const LAllocation& object, const LAllocation& elements,
|
||||
const LAllocation& index, const LAllocation& value)
|
||||
const LAllocation& index, const LAllocation& value,
|
||||
const LDefinition& spectreTemp)
|
||||
: LInstructionHelper(classOpcode)
|
||||
{
|
||||
setOperand(0, object);
|
||||
setOperand(1, elements);
|
||||
setOperand(2, index);
|
||||
setOperand(3, value);
|
||||
setTemp(0, spectreTemp);
|
||||
}
|
||||
|
||||
const MStoreElementHole* mir() const {
|
||||
|
@ -6502,22 +6509,27 @@ class LStoreElementHoleT : public LInstructionHelper<0, 4, 0>
|
|||
const LAllocation* value() {
|
||||
return getOperand(3);
|
||||
}
|
||||
const LDefinition* spectreTemp() {
|
||||
return getTemp(0);
|
||||
}
|
||||
};
|
||||
|
||||
// Like LStoreElementV, but can just ignore assignment (for eg. frozen objects)
|
||||
class LFallibleStoreElementV : public LInstructionHelper<0, 3 + BOX_PIECES, 0>
|
||||
class LFallibleStoreElementV : public LInstructionHelper<0, 3 + BOX_PIECES, 1>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(FallibleStoreElementV)
|
||||
|
||||
LFallibleStoreElementV(const LAllocation& object, const LAllocation& elements,
|
||||
const LAllocation& index, const LBoxAllocation& value)
|
||||
const LAllocation& index, const LBoxAllocation& value,
|
||||
const LDefinition& spectreTemp)
|
||||
: LInstructionHelper(classOpcode)
|
||||
{
|
||||
setOperand(0, object);
|
||||
setOperand(1, elements);
|
||||
setOperand(2, index);
|
||||
setBoxOperand(Value, value);
|
||||
setTemp(0, spectreTemp);
|
||||
}
|
||||
|
||||
static const size_t Value = 3;
|
||||
|
@ -6534,22 +6546,27 @@ class LFallibleStoreElementV : public LInstructionHelper<0, 3 + BOX_PIECES, 0>
|
|||
const LAllocation* index() {
|
||||
return getOperand(2);
|
||||
}
|
||||
const LDefinition* spectreTemp() {
|
||||
return getTemp(0);
|
||||
}
|
||||
};
|
||||
|
||||
// Like LStoreElementT, but can just ignore assignment (for eg. frozen objects)
|
||||
class LFallibleStoreElementT : public LInstructionHelper<0, 4, 0>
|
||||
class LFallibleStoreElementT : public LInstructionHelper<0, 4, 1>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(FallibleStoreElementT)
|
||||
|
||||
LFallibleStoreElementT(const LAllocation& object, const LAllocation& elements,
|
||||
const LAllocation& index, const LAllocation& value)
|
||||
const LAllocation& index, const LAllocation& value,
|
||||
const LDefinition& spectreTemp)
|
||||
: LInstructionHelper(classOpcode)
|
||||
{
|
||||
setOperand(0, object);
|
||||
setOperand(1, elements);
|
||||
setOperand(2, index);
|
||||
setOperand(3, value);
|
||||
setTemp(0, spectreTemp);
|
||||
}
|
||||
|
||||
const MFallibleStoreElement* mir() const {
|
||||
|
@ -6567,6 +6584,9 @@ class LFallibleStoreElementT : public LInstructionHelper<0, 4, 0>
|
|||
const LAllocation* value() {
|
||||
return getOperand(3);
|
||||
}
|
||||
const LDefinition* spectreTemp() {
|
||||
return getTemp(0);
|
||||
}
|
||||
};
|
||||
|
||||
class LStoreUnboxedPointer : public LInstructionHelper<0, 3, 0>
|
||||
|
@ -6681,17 +6701,19 @@ class LArrayPopShiftT : public LInstructionHelper<1, 1, 2>
|
|||
}
|
||||
};
|
||||
|
||||
class LArrayPushV : public LInstructionHelper<1, 1 + BOX_PIECES, 1>
|
||||
class LArrayPushV : public LInstructionHelper<1, 1 + BOX_PIECES, 2>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(ArrayPushV)
|
||||
|
||||
LArrayPushV(const LAllocation& object, const LBoxAllocation& value, const LDefinition& temp)
|
||||
LArrayPushV(const LAllocation& object, const LBoxAllocation& value, const LDefinition& temp,
|
||||
const LDefinition& spectreTemp)
|
||||
: LInstructionHelper(classOpcode)
|
||||
{
|
||||
setOperand(0, object);
|
||||
setBoxOperand(Value, value);
|
||||
setTemp(0, temp);
|
||||
setTemp(1, spectreTemp);
|
||||
}
|
||||
|
||||
static const size_t Value = 1;
|
||||
|
@ -6705,19 +6727,24 @@ class LArrayPushV : public LInstructionHelper<1, 1 + BOX_PIECES, 1>
|
|||
const LDefinition* temp() {
|
||||
return getTemp(0);
|
||||
}
|
||||
const LDefinition* spectreTemp() {
|
||||
return getTemp(1);
|
||||
}
|
||||
};
|
||||
|
||||
class LArrayPushT : public LInstructionHelper<1, 2, 1>
|
||||
class LArrayPushT : public LInstructionHelper<1, 2, 2>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(ArrayPushT)
|
||||
|
||||
LArrayPushT(const LAllocation& object, const LAllocation& value, const LDefinition& temp)
|
||||
LArrayPushT(const LAllocation& object, const LAllocation& value, const LDefinition& temp,
|
||||
const LDefinition& spectreTemp)
|
||||
: LInstructionHelper(classOpcode)
|
||||
{
|
||||
setOperand(0, object);
|
||||
setOperand(1, value);
|
||||
setTemp(0, temp);
|
||||
setTemp(1, spectreTemp);
|
||||
}
|
||||
|
||||
const MArrayPush* mir() const {
|
||||
|
@ -6732,6 +6759,9 @@ class LArrayPushT : public LInstructionHelper<1, 2, 1>
|
|||
const LDefinition* temp() {
|
||||
return getTemp(0);
|
||||
}
|
||||
const LDefinition* spectreTemp() {
|
||||
return getTemp(1);
|
||||
}
|
||||
};
|
||||
|
||||
class LArraySlice : public LCallInstructionHelper<1, 3, 2>
|
||||
|
@ -6854,23 +6884,6 @@ class LLoadTypedArrayElementHole : public LInstructionHelper<BOX_PIECES, 2, 1>
|
|||
}
|
||||
};
|
||||
|
||||
class LLoadTypedArrayElementStatic : public LInstructionHelper<1, 1, 0>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(LoadTypedArrayElementStatic);
|
||||
explicit LLoadTypedArrayElementStatic(const LAllocation& ptr)
|
||||
: LInstructionHelper(classOpcode)
|
||||
{
|
||||
setOperand(0, ptr);
|
||||
}
|
||||
MLoadTypedArrayElementStatic* mir() const {
|
||||
return mir_->toLoadTypedArrayElementStatic();
|
||||
}
|
||||
const LAllocation* ptr() {
|
||||
return getOperand(0);
|
||||
}
|
||||
};
|
||||
|
||||
class LStoreUnboxedScalar : public LInstructionHelper<0, 3, 0>
|
||||
{
|
||||
public:
|
||||
|
@ -6899,19 +6912,21 @@ class LStoreUnboxedScalar : public LInstructionHelper<0, 3, 0>
|
|||
}
|
||||
};
|
||||
|
||||
class LStoreTypedArrayElementHole : public LInstructionHelper<0, 4, 0>
|
||||
class LStoreTypedArrayElementHole : public LInstructionHelper<0, 4, 1>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(StoreTypedArrayElementHole)
|
||||
|
||||
LStoreTypedArrayElementHole(const LAllocation& elements, const LAllocation& length,
|
||||
const LAllocation& index, const LAllocation& value)
|
||||
const LAllocation& index, const LAllocation& value,
|
||||
const LDefinition& spectreTemp)
|
||||
: LInstructionHelper(classOpcode)
|
||||
{
|
||||
setOperand(0, elements);
|
||||
setOperand(1, length);
|
||||
setOperand(2, index);
|
||||
setOperand(3, value);
|
||||
setTemp(0, spectreTemp);
|
||||
}
|
||||
|
||||
const MStoreTypedArrayElementHole* mir() const {
|
||||
|
@ -6929,26 +6944,8 @@ class LStoreTypedArrayElementHole : public LInstructionHelper<0, 4, 0>
|
|||
const LAllocation* value() {
|
||||
return getOperand(3);
|
||||
}
|
||||
};
|
||||
|
||||
class LStoreTypedArrayElementStatic : public LInstructionHelper<0, 2, 0>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(StoreTypedArrayElementStatic);
|
||||
LStoreTypedArrayElementStatic(const LAllocation& ptr, const LAllocation& value)
|
||||
: LInstructionHelper(classOpcode)
|
||||
{
|
||||
setOperand(0, ptr);
|
||||
setOperand(1, value);
|
||||
}
|
||||
MStoreTypedArrayElementStatic* mir() const {
|
||||
return mir_->toStoreTypedArrayElementStatic();
|
||||
}
|
||||
const LAllocation* ptr() {
|
||||
return getOperand(0);
|
||||
}
|
||||
const LAllocation* value() {
|
||||
return getOperand(1);
|
||||
const LDefinition* spectreTemp() {
|
||||
return getTemp(0);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -290,11 +290,6 @@ class LIRGeneratorShared
|
|||
static bool allowTypedElementHoleCheck() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Whether to generate typed array accesses on statically known objects.
|
||||
static bool allowStaticTypedArrayAccesses() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace jit
|
||||
|
|
|
@ -382,18 +382,6 @@ CodeGenerator::visitWasmUint32ToFloat32(LWasmUint32ToFloat32* lir)
|
|||
masm.convertUInt32ToFloat32(ToRegister(lir->input()), ToFloatRegister(lir->output()));
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenerator::visitLoadTypedArrayElementStatic(LLoadTypedArrayElementStatic* ins)
|
||||
{
|
||||
MOZ_CRASH("NYI");
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenerator::visitStoreTypedArrayElementStatic(LStoreTypedArrayElementStatic* ins)
|
||||
{
|
||||
MOZ_CRASH("NYI");
|
||||
}
|
||||
|
||||
void
|
||||
CodeGeneratorX64::wasmStore(const wasm::MemoryAccessDesc& access, const LAllocation* value,
|
||||
Operand dstAddr)
|
||||
|
|
|
@ -416,12 +416,6 @@ LIRGenerator::visitSubstr(MSubstr* ins)
|
|||
assignSafepoint(lir, ins);
|
||||
}
|
||||
|
||||
void
|
||||
LIRGenerator::visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic* ins)
|
||||
{
|
||||
MOZ_CRASH("NYI");
|
||||
}
|
||||
|
||||
void
|
||||
LIRGenerator::visitRandom(MRandom* ins)
|
||||
{
|
||||
|
|
|
@ -852,6 +852,50 @@ MacroAssembler::spectreMovePtr(Condition cond, Register src, Register dest)
|
|||
cmovCCq(cond, Operand(src), dest);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::spectreBoundsCheck32(Register index, Register length, Register maybeScratch,
|
||||
Label* failure)
|
||||
{
|
||||
MOZ_ASSERT(index != length);
|
||||
MOZ_ASSERT(length != maybeScratch);
|
||||
MOZ_ASSERT(index != maybeScratch);
|
||||
|
||||
ScratchRegisterScope scratch(*this);
|
||||
MOZ_ASSERT(index != scratch);
|
||||
MOZ_ASSERT(length != scratch);
|
||||
|
||||
if (JitOptions.spectreIndexMasking)
|
||||
move32(Imm32(0), scratch);
|
||||
|
||||
cmp32(index, length);
|
||||
j(Assembler::AboveOrEqual, failure);
|
||||
|
||||
if (JitOptions.spectreIndexMasking)
|
||||
cmovCCl(Assembler::AboveOrEqual, scratch, index);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::spectreBoundsCheck32(Register index, const Address& length, Register maybeScratch,
|
||||
Label* failure)
|
||||
{
|
||||
MOZ_ASSERT(index != length.base);
|
||||
MOZ_ASSERT(length.base != maybeScratch);
|
||||
MOZ_ASSERT(index != maybeScratch);
|
||||
|
||||
ScratchRegisterScope scratch(*this);
|
||||
MOZ_ASSERT(index != scratch);
|
||||
MOZ_ASSERT(length.base != scratch);
|
||||
|
||||
if (JitOptions.spectreIndexMasking)
|
||||
move32(Imm32(0), scratch);
|
||||
|
||||
cmp32(index, Operand(length));
|
||||
j(Assembler::AboveOrEqual, failure);
|
||||
|
||||
if (JitOptions.spectreIndexMasking)
|
||||
cmovCCl(Assembler::AboveOrEqual, scratch, index);
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// Truncate floating point.
|
||||
|
||||
|
|
|
@ -1118,42 +1118,6 @@ MacroAssembler::spectreZeroRegister(Condition cond, Register scratch, Register d
|
|||
spectreMovePtr(cond, scratch, dest);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::spectreBoundsCheck32(Register index, Register length, Register scratch,
|
||||
Label* failure)
|
||||
{
|
||||
MOZ_ASSERT(index != length);
|
||||
MOZ_ASSERT(length != scratch);
|
||||
MOZ_ASSERT(index != scratch);
|
||||
|
||||
if (JitOptions.spectreIndexMasking)
|
||||
move32(Imm32(0), scratch);
|
||||
|
||||
cmp32(index, length);
|
||||
j(Assembler::AboveOrEqual, failure);
|
||||
|
||||
if (JitOptions.spectreIndexMasking)
|
||||
cmovCCl(Assembler::AboveOrEqual, scratch, index);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::spectreBoundsCheck32(Register index, const Address& length, Register scratch,
|
||||
Label* failure)
|
||||
{
|
||||
MOZ_ASSERT(index != length.base);
|
||||
MOZ_ASSERT(length.base != scratch);
|
||||
MOZ_ASSERT(index != scratch);
|
||||
|
||||
if (JitOptions.spectreIndexMasking)
|
||||
move32(Imm32(0), scratch);
|
||||
|
||||
cmp32(index, Operand(length));
|
||||
j(Assembler::AboveOrEqual, failure);
|
||||
|
||||
if (JitOptions.spectreIndexMasking)
|
||||
cmovCCl(Assembler::AboveOrEqual, scratch, index);
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// Canonicalization primitives.
|
||||
void
|
||||
|
|
|
@ -259,55 +259,6 @@ CodeGenerator::visitWasmUint32ToFloat32(LWasmUint32ToFloat32* lir)
|
|||
masm.convertUInt32ToFloat32(temp, output);
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenerator::visitLoadTypedArrayElementStatic(LLoadTypedArrayElementStatic* ins)
|
||||
{
|
||||
const MLoadTypedArrayElementStatic* mir = ins->mir();
|
||||
Scalar::Type accessType = mir->accessType();
|
||||
MOZ_ASSERT_IF(accessType == Scalar::Float32, mir->type() == MIRType::Float32);
|
||||
|
||||
Register ptr = ToRegister(ins->ptr());
|
||||
AnyRegister out = ToAnyRegister(ins->output());
|
||||
OutOfLineLoadTypedArrayOutOfBounds* ool = nullptr;
|
||||
uint32_t offset = mir->offset();
|
||||
|
||||
if (mir->needsBoundsCheck()) {
|
||||
MOZ_ASSERT(offset == 0);
|
||||
if (!mir->fallible()) {
|
||||
ool = new(alloc()) OutOfLineLoadTypedArrayOutOfBounds(out, accessType);
|
||||
addOutOfLineCode(ool, ins->mir());
|
||||
}
|
||||
|
||||
masm.cmpPtr(ptr, ImmWord(mir->length()));
|
||||
if (ool)
|
||||
masm.j(Assembler::AboveOrEqual, ool->entry());
|
||||
else
|
||||
bailoutIf(Assembler::AboveOrEqual, ins->snapshot());
|
||||
}
|
||||
|
||||
Operand srcAddr(ptr, int32_t(mir->base().asValue()) + int32_t(offset));
|
||||
switch (accessType) {
|
||||
case Scalar::Int8: masm.movsblWithPatch(srcAddr, out.gpr()); break;
|
||||
case Scalar::Uint8Clamped:
|
||||
case Scalar::Uint8: masm.movzblWithPatch(srcAddr, out.gpr()); break;
|
||||
case Scalar::Int16: masm.movswlWithPatch(srcAddr, out.gpr()); break;
|
||||
case Scalar::Uint16: masm.movzwlWithPatch(srcAddr, out.gpr()); break;
|
||||
case Scalar::Int32:
|
||||
case Scalar::Uint32: masm.movlWithPatch(srcAddr, out.gpr()); break;
|
||||
case Scalar::Float32: masm.vmovssWithPatch(srcAddr, out.fpu()); break;
|
||||
case Scalar::Float64: masm.vmovsdWithPatch(srcAddr, out.fpu()); break;
|
||||
default: MOZ_CRASH("Unexpected type");
|
||||
}
|
||||
|
||||
if (accessType == Scalar::Float64)
|
||||
masm.canonicalizeDouble(out.fpu());
|
||||
if (accessType == Scalar::Float32)
|
||||
masm.canonicalizeFloat(out.fpu());
|
||||
|
||||
if (ool)
|
||||
masm.bind(ool->rejoin());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
CodeGeneratorX86::emitWasmLoad(T* ins)
|
||||
|
@ -420,55 +371,6 @@ CodeGenerator::visitAsmJSLoadHeap(LAsmJSLoadHeap* ins)
|
|||
masm.bind(ool->rejoin());
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenerator::visitStoreTypedArrayElementStatic(LStoreTypedArrayElementStatic* ins)
|
||||
{
|
||||
MStoreTypedArrayElementStatic* mir = ins->mir();
|
||||
Scalar::Type accessType = mir->accessType();
|
||||
Register ptr = ToRegister(ins->ptr());
|
||||
const LAllocation* value = ins->value();
|
||||
|
||||
canonicalizeIfDeterministic(accessType, value);
|
||||
|
||||
uint32_t offset = mir->offset();
|
||||
MOZ_ASSERT_IF(mir->needsBoundsCheck(), offset == 0);
|
||||
|
||||
Label rejoin;
|
||||
if (mir->needsBoundsCheck()) {
|
||||
MOZ_ASSERT(offset == 0);
|
||||
masm.cmpPtr(ptr, ImmWord(mir->length()));
|
||||
masm.j(Assembler::AboveOrEqual, &rejoin);
|
||||
}
|
||||
|
||||
Operand dstAddr(ptr, int32_t(mir->base().asValue()) + int32_t(offset));
|
||||
switch (accessType) {
|
||||
case Scalar::Int8:
|
||||
case Scalar::Uint8Clamped:
|
||||
case Scalar::Uint8:
|
||||
masm.movbWithPatch(ToRegister(value), dstAddr);
|
||||
break;
|
||||
case Scalar::Int16:
|
||||
case Scalar::Uint16:
|
||||
masm.movwWithPatch(ToRegister(value), dstAddr);
|
||||
break;
|
||||
case Scalar::Int32:
|
||||
case Scalar::Uint32:
|
||||
masm.movlWithPatch(ToRegister(value), dstAddr);
|
||||
break;
|
||||
case Scalar::Float32:
|
||||
masm.vmovssWithPatch(ToFloatRegister(value), dstAddr);
|
||||
break;
|
||||
case Scalar::Float64:
|
||||
masm.vmovsdWithPatch(ToFloatRegister(value), dstAddr);
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("unexpected type");
|
||||
}
|
||||
|
||||
if (rejoin.used())
|
||||
masm.bind(&rejoin);
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenerator::visitAsmJSStoreHeap(LAsmJSStoreHeap* ins)
|
||||
{
|
||||
|
|
|
@ -469,30 +469,6 @@ LIRGenerator::visitAsmJSStoreHeap(MAsmJSStoreHeap* ins)
|
|||
add(lir, ins);
|
||||
}
|
||||
|
||||
void
|
||||
LIRGenerator::visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic* ins)
|
||||
{
|
||||
// The code generated for StoreTypedArrayElementStatic is identical to that
|
||||
// for AsmJSStoreHeap, and the same concerns apply.
|
||||
LStoreTypedArrayElementStatic* lir;
|
||||
switch (ins->accessType()) {
|
||||
case Scalar::Int8: case Scalar::Uint8:
|
||||
case Scalar::Uint8Clamped:
|
||||
lir = new(alloc()) LStoreTypedArrayElementStatic(useRegister(ins->ptr()),
|
||||
useFixed(ins->value(), eax));
|
||||
break;
|
||||
case Scalar::Int16: case Scalar::Uint16:
|
||||
case Scalar::Int32: case Scalar::Uint32:
|
||||
case Scalar::Float32: case Scalar::Float64:
|
||||
lir = new(alloc()) LStoreTypedArrayElementStatic(useRegisterAtStart(ins->ptr()),
|
||||
useRegisterAtStart(ins->value()));
|
||||
break;
|
||||
default: MOZ_CRASH("unexpected array type");
|
||||
}
|
||||
|
||||
add(lir, ins);
|
||||
}
|
||||
|
||||
void
|
||||
LIRGenerator::visitWasmCompareExchangeHeap(MWasmCompareExchangeHeap* ins)
|
||||
{
|
||||
|
|
|
@ -60,9 +60,6 @@ class LIRGeneratorX86 : public LIRGeneratorX86Shared
|
|||
static bool allowTypedElementHoleCheck() {
|
||||
return true;
|
||||
}
|
||||
static bool allowStaticTypedArrayAccesses() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
typedef LIRGeneratorX86 LIRGeneratorSpecific;
|
||||
|
|
|
@ -1041,6 +1041,64 @@ MacroAssembler::spectreMovePtr(Condition cond, Register src, Register dest)
|
|||
cmovCCl(cond, Operand(src), dest);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::spectreBoundsCheck32(Register index, const Operand& length, Register maybeScratch,
|
||||
Label* failure)
|
||||
{
|
||||
Label failurePopValue;
|
||||
bool pushedValue = false;
|
||||
if (JitOptions.spectreIndexMasking) {
|
||||
if (maybeScratch == InvalidReg) {
|
||||
push(Imm32(0));
|
||||
pushedValue = true;
|
||||
} else {
|
||||
move32(Imm32(0), maybeScratch);
|
||||
}
|
||||
}
|
||||
|
||||
cmp32(index, length);
|
||||
j(Assembler::AboveOrEqual, pushedValue ? &failurePopValue : failure);
|
||||
|
||||
if (JitOptions.spectreIndexMasking) {
|
||||
if (maybeScratch == InvalidReg) {
|
||||
Label done;
|
||||
cmovCCl(Assembler::AboveOrEqual, Operand(StackPointer, 0), index);
|
||||
lea(Operand(StackPointer, sizeof(void*)), StackPointer);
|
||||
jump(&done);
|
||||
|
||||
bind(&failurePopValue);
|
||||
lea(Operand(StackPointer, sizeof(void*)), StackPointer);
|
||||
jump(failure);
|
||||
|
||||
bind(&done);
|
||||
} else {
|
||||
cmovCCl(Assembler::AboveOrEqual, maybeScratch, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::spectreBoundsCheck32(Register index, Register length, Register maybeScratch,
|
||||
Label* failure)
|
||||
{
|
||||
MOZ_ASSERT(index != length);
|
||||
MOZ_ASSERT(length != maybeScratch);
|
||||
MOZ_ASSERT(index != maybeScratch);
|
||||
|
||||
spectreBoundsCheck32(index, Operand(length), maybeScratch, failure);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::spectreBoundsCheck32(Register index, const Address& length, Register maybeScratch,
|
||||
Label* failure)
|
||||
{
|
||||
MOZ_ASSERT(index != length.base);
|
||||
MOZ_ASSERT(length.base != maybeScratch);
|
||||
MOZ_ASSERT(index != maybeScratch);
|
||||
|
||||
spectreBoundsCheck32(index, Operand(length), maybeScratch, failure);
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// Truncate floating point.
|
||||
|
||||
|
|
|
@ -49,15 +49,31 @@ if not CONFIG['JS_DISABLE_SHELL']:
|
|||
TEST_DIRS += ['jsapi-tests', 'tests', 'gdb']
|
||||
|
||||
if CONFIG['FUZZING_INTERFACES']:
|
||||
if CONFIG['LIBFUZZER']:
|
||||
# Add trace-pc coverage for libfuzzer
|
||||
CFLAGS += ['-fsanitize-coverage=trace-pc-guard']
|
||||
CXXFLAGS += ['-fsanitize-coverage=trace-pc-guard']
|
||||
|
||||
TEST_DIRS += [
|
||||
'fuzz-tests',
|
||||
]
|
||||
|
||||
if CONFIG['FUZZING_INTERFACES'] and CONFIG['LIBFUZZER']:
|
||||
# In addition to regular coverage provided by trace-pc-guard,
|
||||
# LibFuzzer can use trace-cmp to instrument various compare instructions.
|
||||
# Only use this feature on source files that do a lot of constant
|
||||
# comparisons that would otherwise be hard to guess by LibFuzzer,
|
||||
# as it comes with a larger overhead (requires -use_value_profile=1).
|
||||
libfuzzer_flags = ['-fsanitize-coverage=trace-pc-guard']
|
||||
libfuzzer_flags_cmp = ['-fsanitize-coverage=trace-pc-guard', '-fsanitize-coverage=trace-cmp']
|
||||
|
||||
# Any files that are targeted by LibFuzzer should be added here so they can
|
||||
# be built with the necessary instrumentation flags, rather than just building
|
||||
# the whole JS engine with instrumentation, to reduce the amount of noise.
|
||||
SOURCES += [
|
||||
'vm/StructuredClone.cpp',
|
||||
]
|
||||
SOURCES['vm/StructuredClone.cpp'].flags += libfuzzer_flags_cmp
|
||||
else:
|
||||
UNIFIED_SOURCES += [
|
||||
'vm/StructuredClone.cpp',
|
||||
]
|
||||
|
||||
CONFIGURE_SUBST_FILES += [
|
||||
'devtools/rootAnalysis/Makefile',
|
||||
]
|
||||
|
@ -374,7 +390,6 @@ UNIFIED_SOURCES += [
|
|||
'vm/Stack.cpp',
|
||||
'vm/Stopwatch.cpp',
|
||||
'vm/StringType.cpp',
|
||||
'vm/StructuredClone.cpp',
|
||||
'vm/SymbolType.cpp',
|
||||
'vm/TaggedProto.cpp',
|
||||
'vm/Time.cpp',
|
||||
|
@ -697,9 +712,9 @@ if CONFIG['JS_BUILD_BINAST']:
|
|||
|
||||
# Instrument BinAST files for fuzzing as we have a fuzzing target for BinAST.
|
||||
if CONFIG['FUZZING_INTERFACES'] and CONFIG['LIBFUZZER']:
|
||||
SOURCES['frontend/BinSource.cpp'].flags += ['-fsanitize-coverage=trace-pc-guard']
|
||||
SOURCES['frontend/BinToken.cpp'].flags += ['-fsanitize-coverage=trace-pc-guard']
|
||||
SOURCES['frontend/BinTokenReaderTester.cpp'].flags += ['-fsanitize-coverage=trace-pc-guard']
|
||||
SOURCES['frontend/BinSource.cpp'].flags += libfuzzer_flags_cmp
|
||||
SOURCES['frontend/BinToken.cpp'].flags += libfuzzer_flags_cmp
|
||||
SOURCES['frontend/BinTokenReaderTester.cpp'].flags += libfuzzer_flags_cmp
|
||||
|
||||
# Wasm code should use WASM_HUGE_MEMORY instead of JS_CODEGEN_X64
|
||||
# so that it is easy to use the huge-mapping optimization for other
|
||||
|
|
|
@ -21,16 +21,6 @@ GetFunctionNameBytes(JSContext* cx, JSFunction* fun, JSAutoByteString* bytes)
|
|||
return js_anonymous_str;
|
||||
}
|
||||
|
||||
static inline JSObject*
|
||||
SkipEnvironmentObjects(JSObject* env)
|
||||
{
|
||||
if (!env)
|
||||
return nullptr;
|
||||
while (env->is<EnvironmentObject>())
|
||||
env = &env->as<EnvironmentObject>().enclosingEnvironment();
|
||||
return env;
|
||||
}
|
||||
|
||||
inline bool
|
||||
CanReuseFunctionForClone(JSContext* cx, HandleFunction fun)
|
||||
{
|
||||
|
@ -68,7 +58,6 @@ CloneFunctionObjectIfNotSingleton(JSContext* cx, HandleFunction fun, HandleObjec
|
|||
* the function's script.
|
||||
*/
|
||||
if (CanReuseFunctionForClone(cx, fun)) {
|
||||
RootedObject obj(cx, SkipEnvironmentObjects(parent));
|
||||
ObjectOpResult succeeded;
|
||||
if (proto && !SetPrototype(cx, fun, proto, succeeded))
|
||||
return nullptr;
|
||||
|
|
|
@ -2033,6 +2033,16 @@ js::NewScriptedFunction(JSContext* cx, unsigned nargs,
|
|||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
static JSObject*
|
||||
SkipEnvironmentObjects(JSObject* env)
|
||||
{
|
||||
if (!env)
|
||||
return nullptr;
|
||||
while (env->is<EnvironmentObject>())
|
||||
env = &env->as<EnvironmentObject>().enclosingEnvironment();
|
||||
return env;
|
||||
}
|
||||
|
||||
static bool
|
||||
NewFunctionEnvironmentIsWellFormed(JSContext* cx, HandleObject env)
|
||||
{
|
||||
|
@ -2137,7 +2147,17 @@ NewFunctionClone(JSContext* cx, HandleFunction fun, NewObjectKind newKind,
|
|||
return nullptr;
|
||||
RootedFunction clone(cx, &cloneobj->as<JSFunction>());
|
||||
|
||||
uint16_t flags = fun->flags() & ~JSFunction::EXTENDED;
|
||||
// JSFunction::HAS_INFERRED_NAME can be set at compile-time and at
|
||||
// runtime. In the latter case we should actually clear the flag before
|
||||
// cloning the function, but since we can't differentiate between both
|
||||
// cases here, we'll end up with a momentarily incorrect function name.
|
||||
// This will be fixed up in SetFunctionNameIfNoOwnName(), which should
|
||||
// happen through JSOP_SETFUNNAME directly after JSOP_LAMBDA.
|
||||
constexpr uint16_t NonCloneableFlags = JSFunction::EXTENDED |
|
||||
JSFunction::RESOLVED_LENGTH |
|
||||
JSFunction::RESOLVED_NAME;
|
||||
|
||||
uint16_t flags = fun->flags() & ~NonCloneableFlags;
|
||||
if (allocKind == AllocKind::FUNCTION_EXTENDED)
|
||||
flags |= JSFunction::EXTENDED;
|
||||
|
||||
|
@ -2311,6 +2331,31 @@ SymbolToFunctionName(JSContext* cx, JS::Symbol* symbol, FunctionPrefixKind prefi
|
|||
return sb.finishAtom();
|
||||
}
|
||||
|
||||
static JSAtom*
|
||||
NameToFunctionName(JSContext* cx, HandleValue name, FunctionPrefixKind prefixKind)
|
||||
{
|
||||
MOZ_ASSERT(name.isString() || name.isNumber());
|
||||
|
||||
if (prefixKind == FunctionPrefixKind::None)
|
||||
return ToAtom<CanGC>(cx, name);
|
||||
|
||||
JSString* nameStr = ToString(cx, name);
|
||||
if (!nameStr)
|
||||
return nullptr;
|
||||
|
||||
StringBuffer sb(cx);
|
||||
if (prefixKind == FunctionPrefixKind::Get) {
|
||||
if (!sb.append("get "))
|
||||
return nullptr;
|
||||
} else {
|
||||
if (!sb.append("set "))
|
||||
return nullptr;
|
||||
}
|
||||
if (!sb.append(nameStr))
|
||||
return nullptr;
|
||||
return sb.finishAtom();
|
||||
}
|
||||
|
||||
/*
|
||||
* Return an atom for use as the name of a builtin method with the given
|
||||
* property id.
|
||||
|
@ -2325,6 +2370,8 @@ JSAtom*
|
|||
js::IdToFunctionName(JSContext* cx, HandleId id,
|
||||
FunctionPrefixKind prefixKind /* = FunctionPrefixKind::None */)
|
||||
{
|
||||
MOZ_ASSERT(JSID_IS_STRING(id) || JSID_IS_SYMBOL(id) || JSID_IS_INT(id));
|
||||
|
||||
// No prefix fastpath.
|
||||
if (JSID_IS_ATOM(id) && prefixKind == FunctionPrefixKind::None)
|
||||
return JSID_TO_ATOM(id);
|
||||
|
@ -2335,33 +2382,9 @@ js::IdToFunctionName(JSContext* cx, HandleId id,
|
|||
if (JSID_IS_SYMBOL(id))
|
||||
return SymbolToFunctionName(cx, JSID_TO_SYMBOL(id), prefixKind);
|
||||
|
||||
RootedValue idv(cx, IdToValue(id));
|
||||
RootedAtom name(cx, ToAtom<CanGC>(cx, idv));
|
||||
if (!name)
|
||||
return nullptr;
|
||||
|
||||
// Step 5.
|
||||
return NameToFunctionName(cx, name, prefixKind);
|
||||
}
|
||||
|
||||
JSAtom*
|
||||
js::NameToFunctionName(JSContext* cx, HandleAtom name,
|
||||
FunctionPrefixKind prefixKind /* = FunctionPrefixKind::None */)
|
||||
{
|
||||
if (prefixKind == FunctionPrefixKind::None)
|
||||
return name;
|
||||
|
||||
StringBuffer sb(cx);
|
||||
if (prefixKind == FunctionPrefixKind::Get) {
|
||||
if (!sb.append("get "))
|
||||
return nullptr;
|
||||
} else {
|
||||
if (!sb.append("set "))
|
||||
return nullptr;
|
||||
}
|
||||
if (!sb.append(name))
|
||||
return nullptr;
|
||||
return sb.finishAtom();
|
||||
RootedValue idv(cx, IdToValue(id));
|
||||
return NameToFunctionName(cx, idv, prefixKind);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -2370,6 +2393,14 @@ js::SetFunctionNameIfNoOwnName(JSContext* cx, HandleFunction fun, HandleValue na
|
|||
{
|
||||
MOZ_ASSERT(name.isString() || name.isSymbol() || name.isNumber());
|
||||
|
||||
// An inferred name may already be set if this function is a clone of a
|
||||
// singleton function. Clear the inferred name in all cases, even if we
|
||||
// end up not adding a new inferred name if |fun| is a class constructor.
|
||||
if (fun->hasInferredName()) {
|
||||
MOZ_ASSERT(fun->isSingleton());
|
||||
fun->clearInferredName();
|
||||
}
|
||||
|
||||
if (fun->isClassConstructor()) {
|
||||
// A class may have static 'name' method or accessor.
|
||||
if (fun->contains(cx, cx->names().name))
|
||||
|
@ -2379,20 +2410,20 @@ js::SetFunctionNameIfNoOwnName(JSContext* cx, HandleFunction fun, HandleValue na
|
|||
MOZ_ASSERT(!fun->containsPure(cx->names().name));
|
||||
}
|
||||
|
||||
JSAtom* funNameAtom;
|
||||
if (name.isSymbol()) {
|
||||
funNameAtom = SymbolToFunctionName(cx, name.toSymbol(), prefixKind);
|
||||
} else {
|
||||
RootedAtom nameAtom(cx, ToAtom<CanGC>(cx, name));
|
||||
if (!nameAtom)
|
||||
return false;
|
||||
funNameAtom = NameToFunctionName(cx, nameAtom, prefixKind);
|
||||
}
|
||||
if (!funNameAtom)
|
||||
JSAtom* funName = name.isSymbol()
|
||||
? SymbolToFunctionName(cx, name.toSymbol(), prefixKind)
|
||||
: NameToFunctionName(cx, name, prefixKind);
|
||||
if (!funName)
|
||||
return false;
|
||||
|
||||
// RESOLVED_NAME shouldn't yet be set, at least as long as we don't
|
||||
// support the "static public fields" or "decorators" proposal.
|
||||
// These two proposals allow to access class constructors before
|
||||
// JSOP_SETFUNNAME is executed, which means user code may have set the
|
||||
// RESOLVED_NAME flag when we reach this point.
|
||||
MOZ_ASSERT(!fun->hasResolvedName());
|
||||
fun->setInferredName(funNameAtom);
|
||||
|
||||
fun->setInferredName(funName);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -61,7 +61,8 @@ class JSFunction : public js::NativeObject
|
|||
BOUND_FUN = 0x0008, /* function was created with Function.prototype.bind. */
|
||||
WASM_OPTIMIZED = 0x0010, /* asm.js/wasm function that has a jit entry */
|
||||
HAS_GUESSED_ATOM = 0x0020, /* function had no explicit name, but a
|
||||
name was guessed for it anyway */
|
||||
name was guessed for it anyway. See
|
||||
atom_ for more info about this flag. */
|
||||
HAS_BOUND_FUNCTION_NAME_PREFIX = 0x0020, /* bound functions reuse the HAS_GUESSED_ATOM
|
||||
flag to track if atom_ already contains the
|
||||
"bound " function name prefix */
|
||||
|
@ -72,7 +73,8 @@ class JSFunction : public js::NativeObject
|
|||
decompilable nor constructible. */
|
||||
HAS_INFERRED_NAME = 0x0100, /* function had no explicit name, but a name was
|
||||
set by SetFunctionName at compile time or
|
||||
SetFunctionNameIfNoOwnName at runtime. */
|
||||
SetFunctionNameIfNoOwnName at runtime. See
|
||||
atom_ for more info about this flag. */
|
||||
INTERPRETED_LAZY = 0x0200, /* function is interpreted but doesn't have a script yet */
|
||||
RESOLVED_LENGTH = 0x0400, /* f.length has been resolved (see fun_resolve). */
|
||||
RESOLVED_NAME = 0x0800, /* f.name has been resolved (see fun_resolve). */
|
||||
|
@ -141,7 +143,42 @@ class JSFunction : public js::NativeObject
|
|||
} s;
|
||||
} scripted;
|
||||
} u;
|
||||
js::GCPtrAtom atom_; /* name for diagnostics and decompiling */
|
||||
|
||||
// The |atom_| field can have different meanings depending on the function
|
||||
// type and flags. It is used for diagnostics, decompiling, and
|
||||
//
|
||||
// 1. If the function is not a bound function:
|
||||
// a. If HAS_GUESSED_ATOM is not set, to store the initial value of the
|
||||
// "name" property of functions. But also see RESOLVED_NAME.
|
||||
// b. If HAS_GUESSED_ATOM is set, |atom_| is only used for diagnostics,
|
||||
// but must not be used for the "name" property.
|
||||
// c. If HAS_INFERRED_NAME is set, the function wasn't given an explicit
|
||||
// name in the source text, e.g. |function fn(){}|, but instead it
|
||||
// was inferred based on how the function was defined in the source
|
||||
// text. The exact name inference rules are defined in the ECMAScript
|
||||
// specification.
|
||||
// Name inference can happen at compile-time, for example in
|
||||
// |var fn = function(){}|, or it can happen at runtime, for example
|
||||
// in |var o = {[Symbol.iterator]: function(){}}|. When it happens at
|
||||
// compile-time, the HAS_INFERRED_NAME is set directly in the
|
||||
// bytecode emitter, when it happens at runtime, the flag is set when
|
||||
// evaluating the JSOP_SETFUNNAME bytecode.
|
||||
// d. HAS_GUESSED_ATOM and HAS_INFERRED_NAME cannot both be set.
|
||||
// e. |atom_| can be null if neither an explicit, nor inferred, nor a
|
||||
// guessed name was set.
|
||||
// f. HAS_INFERRED_NAME can be set for cloned singleton function, even
|
||||
// though the clone shouldn't receive an inferred name. See the
|
||||
// comments in NewFunctionClone() and SetFunctionNameIfNoOwnName()
|
||||
// for details.
|
||||
//
|
||||
// 2. If the function is a bound function:
|
||||
// a. To store the initial value of the "name" property.
|
||||
// b. If HAS_BOUND_FUNCTION_NAME_PREFIX is not set, |atom_| doesn't
|
||||
// contain the "bound " prefix which is prepended to the "name"
|
||||
// property of bound functions per ECMAScript.
|
||||
// c. Bound functions can never have an inferred or guessed name.
|
||||
// d. |atom_| is never null for bound functions.
|
||||
js::GCPtrAtom atom_;
|
||||
|
||||
public:
|
||||
/* Call objects must be created for each invocation of this function. */
|
||||
|
@ -804,10 +841,6 @@ extern JSAtom*
|
|||
IdToFunctionName(JSContext* cx, HandleId id,
|
||||
FunctionPrefixKind prefixKind = FunctionPrefixKind::None);
|
||||
|
||||
extern JSAtom*
|
||||
NameToFunctionName(JSContext* cx, HandleAtom name,
|
||||
FunctionPrefixKind prefixKind = FunctionPrefixKind::None);
|
||||
|
||||
extern bool
|
||||
SetFunctionNameIfNoOwnName(JSContext* cx, HandleFunction fun, HandleValue name,
|
||||
FunctionPrefixKind prefixKind);
|
||||
|
|
|
@ -2382,7 +2382,6 @@ js::SharedScriptData::new_(JSContext* cx, uint32_t codeLength,
|
|||
entry->codeLength_ = codeLength;
|
||||
entry->noteLength_ = srcnotesLength;
|
||||
|
||||
|
||||
/*
|
||||
* Call constructors to initialize the storage that will be accessed as a
|
||||
* GCPtrAtom array via atoms().
|
||||
|
@ -2399,6 +2398,20 @@ js::SharedScriptData::new_(JSContext* cx, uint32_t codeLength,
|
|||
return entry;
|
||||
}
|
||||
|
||||
inline
|
||||
js::ScriptBytecodeHasher::Lookup::Lookup(SharedScriptData* data)
|
||||
: scriptData(data),
|
||||
hash(mozilla::HashBytes(scriptData->data(), scriptData->dataLength()))
|
||||
{
|
||||
scriptData->incRefCount();
|
||||
}
|
||||
|
||||
inline
|
||||
js::ScriptBytecodeHasher::Lookup::~Lookup()
|
||||
{
|
||||
scriptData->decRefCount();
|
||||
}
|
||||
|
||||
bool
|
||||
JSScript::createScriptData(JSContext* cx, uint32_t codeLength, uint32_t srcnotesLength,
|
||||
uint32_t natoms)
|
||||
|
@ -2415,7 +2428,6 @@ JSScript::createScriptData(JSContext* cx, uint32_t codeLength, uint32_t srcnotes
|
|||
void
|
||||
JSScript::freeScriptData()
|
||||
{
|
||||
MOZ_ASSERT(scriptData_->refCount() == 1);
|
||||
scriptData_->decRefCount();
|
||||
scriptData_ = nullptr;
|
||||
}
|
||||
|
@ -2441,9 +2453,13 @@ JSScript::shareScriptData(JSContext* cx)
|
|||
MOZ_ASSERT(ssd);
|
||||
MOZ_ASSERT(ssd->refCount() == 1);
|
||||
|
||||
// Calculate the hash before taking the lock. Because the data is reference
|
||||
// counted, it also will be freed after releasing the lock if necessary.
|
||||
ScriptBytecodeHasher::Lookup lookup(ssd);
|
||||
|
||||
AutoLockScriptData lock(cx->runtime());
|
||||
|
||||
ScriptDataTable::AddPtr p = cx->scriptDataTable(lock).lookupForAdd(*ssd);
|
||||
ScriptDataTable::AddPtr p = cx->scriptDataTable(lock).lookupForAdd(lookup);
|
||||
if (p) {
|
||||
MOZ_ASSERT(ssd != *p);
|
||||
freeScriptData();
|
||||
|
|
|
@ -856,19 +856,29 @@ class SharedScriptData
|
|||
|
||||
struct ScriptBytecodeHasher
|
||||
{
|
||||
typedef SharedScriptData Lookup;
|
||||
class Lookup {
|
||||
friend struct ScriptBytecodeHasher;
|
||||
|
||||
SharedScriptData* scriptData;
|
||||
HashNumber hash;
|
||||
|
||||
public:
|
||||
explicit Lookup(SharedScriptData* data);
|
||||
~Lookup();
|
||||
};
|
||||
|
||||
static HashNumber hash(const Lookup& l) {
|
||||
return mozilla::HashBytes(l.data(), l.dataLength());
|
||||
return l.hash;
|
||||
}
|
||||
static bool match(SharedScriptData* entry, const Lookup& lookup) {
|
||||
if (entry->natoms() != lookup.natoms())
|
||||
const SharedScriptData* data = lookup.scriptData;
|
||||
if (entry->natoms() != data->natoms())
|
||||
return false;
|
||||
if (entry->codeLength() != lookup.codeLength())
|
||||
if (entry->codeLength() != data->codeLength())
|
||||
return false;
|
||||
if (entry->numNotes() != lookup.numNotes())
|
||||
if (entry->numNotes() != data->numNotes())
|
||||
return false;
|
||||
return mozilla::PodEqual<uint8_t>(entry->data(), lookup.data(), lookup.dataLength());
|
||||
return mozilla::PodEqual<uint8_t>(entry->data(), data->data(), data->dataLength());
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -9,17 +9,20 @@
|
|||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/Casting.h"
|
||||
#include "mozilla/CheckedInt.h"
|
||||
#include "mozilla/DebugOnly.h"
|
||||
|
||||
#include "gc/Marking.h"
|
||||
#include "js/Value.h"
|
||||
#include "vm/Debugger.h"
|
||||
#include "vm/TypedArrayObject.h"
|
||||
#include "vm/UnboxedObject.h"
|
||||
|
||||
#include "gc/Nursery-inl.h"
|
||||
#include "vm/ArrayObject-inl.h"
|
||||
#include "vm/EnvironmentObject-inl.h"
|
||||
#include "vm/JSObject-inl.h"
|
||||
#include "vm/Shape-inl.h"
|
||||
#include "vm/UnboxedObject-inl.h"
|
||||
|
||||
using namespace js;
|
||||
|
||||
|
@ -1498,8 +1501,8 @@ AddOrChangeProperty(JSContext* cx, HandleNativeObject obj, HandleId id,
|
|||
return CallAddPropertyHook(cx, obj, id, desc.value());
|
||||
}
|
||||
|
||||
// Version of AddOrChangeProperty optimized for adding a plain data property.
|
||||
// This function doesn't handle integer ids as we may have to store them in
|
||||
// Versions of AddOrChangeProperty optimized for adding a plain data property.
|
||||
// These function doesn't handle integer ids as we may have to store them in
|
||||
// dense elements.
|
||||
static MOZ_ALWAYS_INLINE bool
|
||||
AddDataProperty(JSContext* cx, HandleNativeObject obj, HandleId id, HandleValue v)
|
||||
|
@ -1518,6 +1521,24 @@ AddDataProperty(JSContext* cx, HandleNativeObject obj, HandleId id, HandleValue
|
|||
return CallAddPropertyHook(cx, obj, id, v);
|
||||
}
|
||||
|
||||
static MOZ_ALWAYS_INLINE bool
|
||||
AddDataPropertyNonDelegate(JSContext* cx, HandlePlainObject obj, HandleId id, HandleValue v)
|
||||
{
|
||||
MOZ_ASSERT(!JSID_IS_INT(id));
|
||||
MOZ_ASSERT(!obj->isDelegate());
|
||||
|
||||
// If we know this is a new property we can call addProperty instead of
|
||||
// the slower putProperty.
|
||||
Shape* shape = NativeObject::addEnumerableDataProperty(cx, obj, id);
|
||||
if (!shape)
|
||||
return false;
|
||||
|
||||
UpdateShapeTypeAndValueForWritableDataProp(cx, obj, shape, id, v);
|
||||
|
||||
MOZ_ASSERT(!obj->getClass()->getAddProperty());
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool IsConfigurable(unsigned attrs) { return (attrs & JSPROP_PERMANENT) == 0; }
|
||||
static bool IsEnumerable(unsigned attrs) { return (attrs & JSPROP_ENUMERATE) != 0; }
|
||||
static bool IsWritable(unsigned attrs) { return (attrs & JSPROP_READONLY) == 0; }
|
||||
|
@ -2895,3 +2916,143 @@ js::NativeDeleteProperty(JSContext* cx, HandleNativeObject obj, HandleId id,
|
|||
|
||||
return SuppressDeletedProperty(cx, obj, id);
|
||||
}
|
||||
|
||||
bool
|
||||
js::CopyDataPropertiesNative(JSContext* cx, HandlePlainObject target, HandleNativeObject from,
|
||||
HandlePlainObject excludedItems, bool* optimized)
|
||||
{
|
||||
MOZ_ASSERT(!target->isDelegate(),
|
||||
"CopyDataPropertiesNative should only be called during object literal construction"
|
||||
"which precludes that |target| is the prototype of any other object");
|
||||
|
||||
*optimized = false;
|
||||
|
||||
// Don't use the fast path if |from| may have extra indexed or lazy
|
||||
// properties.
|
||||
if (from->getDenseInitializedLength() > 0 ||
|
||||
from->isIndexed() ||
|
||||
from->is<TypedArrayObject>() ||
|
||||
from->getClass()->getNewEnumerate() ||
|
||||
from->getClass()->getEnumerate())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Collect all enumerable data properties.
|
||||
using ShapeVector = GCVector<Shape*, 8>;
|
||||
Rooted<ShapeVector> shapes(cx, ShapeVector(cx));
|
||||
|
||||
RootedShape fromShape(cx, from->lastProperty());
|
||||
for (Shape::Range<NoGC> r(fromShape); !r.empty(); r.popFront()) {
|
||||
Shape* shape = &r.front();
|
||||
jsid id = shape->propid();
|
||||
MOZ_ASSERT(!JSID_IS_INT(id));
|
||||
|
||||
if (!shape->enumerable())
|
||||
continue;
|
||||
if (excludedItems && excludedItems->contains(cx, id))
|
||||
continue;
|
||||
|
||||
// Don't use the fast path if |from| contains non-data properties.
|
||||
//
|
||||
// This enables two optimizations:
|
||||
// 1. We don't need to handle the case when accessors modify |from|.
|
||||
// 2. String and symbol properties can be added in one go.
|
||||
if (!shape->isDataProperty())
|
||||
return true;
|
||||
|
||||
if (!shapes.append(shape))
|
||||
return false;
|
||||
}
|
||||
|
||||
*optimized = true;
|
||||
|
||||
// If |target| contains no own properties, we can directly call
|
||||
// addProperty instead of the slower putProperty.
|
||||
const bool targetHadNoOwnProperties = target->lastProperty()->isEmptyShape();
|
||||
|
||||
RootedId key(cx);
|
||||
RootedValue value(cx);
|
||||
for (size_t i = shapes.length(); i > 0; i--) {
|
||||
Shape* shape = shapes[i - 1];
|
||||
MOZ_ASSERT(shape->isDataProperty());
|
||||
MOZ_ASSERT(shape->enumerable());
|
||||
|
||||
key = shape->propid();
|
||||
MOZ_ASSERT(!JSID_IS_INT(key));
|
||||
|
||||
MOZ_ASSERT(from->isNative());
|
||||
MOZ_ASSERT(from->lastProperty() == fromShape);
|
||||
|
||||
value = from->getSlot(shape->slot());
|
||||
if (targetHadNoOwnProperties) {
|
||||
MOZ_ASSERT(!target->contains(cx, key),
|
||||
"didn't expect to find an existing property");
|
||||
|
||||
if (!AddDataPropertyNonDelegate(cx, target, key, value))
|
||||
return false;
|
||||
} else {
|
||||
if (!NativeDefineDataProperty(cx, target, key, value, JSPROP_ENUMERATE))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
js::CopyDataPropertiesNative(JSContext* cx, HandlePlainObject target,
|
||||
Handle<UnboxedPlainObject*> from, HandlePlainObject excludedItems,
|
||||
bool* optimized)
|
||||
{
|
||||
MOZ_ASSERT(!target->isDelegate(),
|
||||
"CopyDataPropertiesNative should only be called during object literal construction"
|
||||
"which precludes that |target| is the prototype of any other object");
|
||||
|
||||
*optimized = false;
|
||||
|
||||
// Don't use the fast path for unboxed objects with expandos.
|
||||
if (from->maybeExpando())
|
||||
return true;
|
||||
|
||||
*optimized = true;
|
||||
|
||||
// If |target| contains no own properties, we can directly call
|
||||
// addProperty instead of the slower putProperty.
|
||||
const bool targetHadNoOwnProperties = target->lastProperty()->isEmptyShape();
|
||||
|
||||
#ifdef DEBUG
|
||||
RootedObjectGroup fromGroup(cx, from->group());
|
||||
#endif
|
||||
|
||||
RootedId key(cx);
|
||||
RootedValue value(cx);
|
||||
const UnboxedLayout& layout = from->layout();
|
||||
for (size_t i = 0; i < layout.properties().length(); i++) {
|
||||
const UnboxedLayout::Property& property = layout.properties()[i];
|
||||
key = NameToId(property.name);
|
||||
MOZ_ASSERT(!JSID_IS_INT(key));
|
||||
|
||||
if (excludedItems && excludedItems->contains(cx, key))
|
||||
continue;
|
||||
|
||||
// Ensure the object stays unboxed.
|
||||
MOZ_ASSERT(from->group() == fromGroup);
|
||||
|
||||
// All unboxed properties are enumerable.
|
||||
value = from->getValue(property);
|
||||
|
||||
if (targetHadNoOwnProperties) {
|
||||
MOZ_ASSERT(!target->contains(cx, key),
|
||||
"didn't expect to find an existing property");
|
||||
|
||||
if (!AddDataPropertyNonDelegate(cx, target, key, value))
|
||||
return false;
|
||||
} else {
|
||||
if (!NativeDefineDataProperty(cx, target, key, value, JSPROP_ENUMERATE))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ namespace js {
|
|||
|
||||
class Shape;
|
||||
class TenuringTracer;
|
||||
class UnboxedPlainObject;
|
||||
|
||||
/*
|
||||
* To really poison a set of values, using 'magic' or 'undefined' isn't good
|
||||
|
@ -1607,6 +1608,16 @@ bool IsPackedArray(JSObject* obj);
|
|||
extern void
|
||||
AddPropertyTypesAfterProtoChange(JSContext* cx, NativeObject* obj, ObjectGroup* oldGroup);
|
||||
|
||||
// Specializations of 7.3.23 CopyDataProperties(...) for NativeObjects.
|
||||
extern bool
|
||||
CopyDataPropertiesNative(JSContext* cx, HandlePlainObject target, HandleNativeObject from,
|
||||
HandlePlainObject excludedItems, bool* optimized);
|
||||
|
||||
extern bool
|
||||
CopyDataPropertiesNative(JSContext* cx, HandlePlainObject target,
|
||||
Handle<UnboxedPlainObject*> from, HandlePlainObject excludedItems,
|
||||
bool* optimized);
|
||||
|
||||
} // namespace js
|
||||
|
||||
|
||||
|
|
|
@ -262,17 +262,6 @@ intrinsic_SubstringKernel(JSContext* cx, unsigned argc, Value* vp)
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
intrinsic_OwnPropertyKeys(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
MOZ_ASSERT(args.length() == 1);
|
||||
MOZ_ASSERT(args[0].isObject());
|
||||
RootedObject obj(cx, &args[0].toObject());
|
||||
return GetOwnPropertyKeys(cx, obj, JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS,
|
||||
args.rval());
|
||||
}
|
||||
|
||||
static void
|
||||
ThrowErrorWithType(JSContext* cx, JSExnType type, const CallArgs& args)
|
||||
{
|
||||
|
@ -2159,6 +2148,59 @@ intrinsic_PromiseResolve(JSContext* cx, unsigned argc, Value* vp)
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
intrinsic_CopyDataPropertiesOrGetOwnKeys(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
MOZ_ASSERT(args.length() == 3);
|
||||
MOZ_ASSERT(args[0].isObject());
|
||||
MOZ_ASSERT(args[1].isObject());
|
||||
MOZ_ASSERT(args[2].isObjectOrNull());
|
||||
|
||||
RootedObject target(cx, &args[0].toObject());
|
||||
RootedObject from(cx, &args[1].toObject());
|
||||
RootedObject excludedItems(cx, args[2].toObjectOrNull());
|
||||
|
||||
if (from->isNative() &&
|
||||
target->is<PlainObject>() &&
|
||||
(!excludedItems || excludedItems->is<PlainObject>()))
|
||||
{
|
||||
bool optimized;
|
||||
if (!CopyDataPropertiesNative(cx, target.as<PlainObject>(), from.as<NativeObject>(),
|
||||
(excludedItems ? excludedItems.as<PlainObject>() : nullptr),
|
||||
&optimized))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (optimized) {
|
||||
args.rval().setNull();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (from->is<UnboxedPlainObject>() &&
|
||||
target->is<PlainObject>() &&
|
||||
(!excludedItems || excludedItems->is<PlainObject>()))
|
||||
{
|
||||
bool optimized;
|
||||
if (!CopyDataPropertiesNative(cx, target.as<PlainObject>(), from.as<UnboxedPlainObject>(),
|
||||
(excludedItems ? excludedItems.as<PlainObject>() : nullptr),
|
||||
&optimized))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (optimized) {
|
||||
args.rval().setNull();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return GetOwnPropertyKeys(cx, from, JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS,
|
||||
args.rval());
|
||||
}
|
||||
|
||||
// The self-hosting global isn't initialized with the normal set of builtins.
|
||||
// Instead, individual C++-implemented functions that're required by
|
||||
// self-hosted code are defined as global functions. Accessing these
|
||||
|
@ -2205,6 +2247,7 @@ static const JSFunctionSpec intrinsic_functions[] = {
|
|||
JS_INLINABLE_FN("std_Reflect_getPrototypeOf", Reflect_getPrototypeOf, 1,0,
|
||||
ReflectGetPrototypeOf),
|
||||
JS_FN("std_Reflect_isExtensible", Reflect_isExtensible, 1,0),
|
||||
JS_FN("std_Reflect_ownKeys", Reflect_ownKeys, 1,0),
|
||||
|
||||
JS_FN("std_Set_has", SetObject::has, 1,0),
|
||||
JS_FN("std_Set_iterator", SetObject::values, 0,0),
|
||||
|
@ -2272,7 +2315,6 @@ static const JSFunctionSpec intrinsic_functions[] = {
|
|||
JS_FN("CreateModuleSyntaxError", intrinsic_CreateModuleSyntaxError, 4,0),
|
||||
JS_FN("AssertionFailed", intrinsic_AssertionFailed, 1,0),
|
||||
JS_FN("DumpMessage", intrinsic_DumpMessage, 1,0),
|
||||
JS_FN("OwnPropertyKeys", intrinsic_OwnPropertyKeys, 1,0),
|
||||
JS_FN("MakeDefaultConstructor", intrinsic_MakeDefaultConstructor, 2,0),
|
||||
JS_FN("_ConstructorForTypedArray", intrinsic_ConstructorForTypedArray, 1,0),
|
||||
JS_FN("_NameForTypedArray", intrinsic_NameForTypedArray, 1,0),
|
||||
|
@ -2284,6 +2326,7 @@ static const JSFunctionSpec intrinsic_functions[] = {
|
|||
JS_FN("AddContentTelemetry", intrinsic_AddContentTelemetry, 2,0),
|
||||
JS_FN("_DefineDataProperty", intrinsic_DefineDataProperty, 4,0),
|
||||
JS_FN("_DefineProperty", intrinsic_DefineProperty, 6,0),
|
||||
JS_FN("CopyDataPropertiesOrGetOwnKeys", intrinsic_CopyDataPropertiesOrGetOwnKeys, 3,0),
|
||||
|
||||
JS_INLINABLE_FN("_IsConstructing", intrinsic_IsConstructing, 0,0,
|
||||
IntrinsicIsConstructing),
|
||||
|
|
|
@ -1102,21 +1102,40 @@ JSStructuredCloneWriter::parseTransferable()
|
|||
return reportDataCloneError(JS_SCERR_TRANSFERABLE);
|
||||
tObj = &v.toObject();
|
||||
|
||||
RootedObject unwrappedObj(cx, CheckedUnwrap(tObj));
|
||||
if (!unwrappedObj) {
|
||||
ReportAccessDenied(cx);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Shared memory cannot be transferred because it is not possible (nor
|
||||
// desirable) to detach the memory in agents that already hold a
|
||||
// reference to it.
|
||||
|
||||
if (tObj->is<SharedArrayBufferObject>())
|
||||
if (unwrappedObj->is<SharedArrayBufferObject>())
|
||||
return reportDataCloneError(JS_SCERR_SHMEM_TRANSFERABLE);
|
||||
|
||||
if (tObj->is<WasmMemoryObject>() && tObj->as<WasmMemoryObject>().isShared())
|
||||
return reportDataCloneError(JS_SCERR_SHMEM_TRANSFERABLE);
|
||||
else if (unwrappedObj->is<WasmMemoryObject>()) {
|
||||
if (unwrappedObj->as<WasmMemoryObject>().isShared())
|
||||
return reportDataCloneError(JS_SCERR_SHMEM_TRANSFERABLE);
|
||||
}
|
||||
|
||||
// External array buffers may be able to be transferred in the future,
|
||||
// but that is not currently implemented.
|
||||
|
||||
if (tObj->is<ArrayBufferObject>() && tObj->as<ArrayBufferObject>().isExternal())
|
||||
return reportDataCloneError(JS_SCERR_TRANSFERABLE);
|
||||
else if (unwrappedObj->is<ArrayBufferObject>()) {
|
||||
if (unwrappedObj->as<ArrayBufferObject>().isExternal())
|
||||
return reportDataCloneError(JS_SCERR_TRANSFERABLE);
|
||||
}
|
||||
|
||||
else {
|
||||
if (!callbacks || !callbacks->canTransfer)
|
||||
return reportDataCloneError(JS_SCERR_TRANSFERABLE);
|
||||
|
||||
JSAutoCompartment ac(cx, unwrappedObj);
|
||||
if (!callbacks->canTransfer(cx, unwrappedObj, closure))
|
||||
return false;
|
||||
}
|
||||
|
||||
// No duplicates allowed
|
||||
auto p = transferableObjects.lookupForAdd(tObj);
|
||||
|
@ -1686,6 +1705,12 @@ JSStructuredCloneWriter::transferOwnership()
|
|||
// lend itself well to generic manipulation via proxies.
|
||||
Rooted<ArrayBufferObject*> arrayBuffer(cx, &CheckedUnwrap(obj)->as<ArrayBufferObject>());
|
||||
JSAutoCompartment ac(cx, arrayBuffer);
|
||||
|
||||
if (arrayBuffer->isDetached()) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t nbytes = arrayBuffer->byteLength();
|
||||
|
||||
if (arrayBuffer->isWasm() || arrayBuffer->isPreparedForAsmJS()) {
|
||||
|
|
|
@ -7992,28 +7992,31 @@ BaseCompiler::emitSetGlobal()
|
|||
|
||||
const GlobalDesc& global = env_.globals[id];
|
||||
|
||||
ScratchI32 tmp(*this);
|
||||
switch (global.type()) {
|
||||
case ValType::I32: {
|
||||
RegI32 rv = popI32();
|
||||
ScratchI32 tmp(*this);
|
||||
masm.store32(rv, addressOfGlobalVar(global, tmp));
|
||||
freeI32(rv);
|
||||
break;
|
||||
}
|
||||
case ValType::I64: {
|
||||
RegI64 rv = popI64();
|
||||
ScratchI32 tmp(*this);
|
||||
masm.store64(rv, addressOfGlobalVar(global, tmp));
|
||||
freeI64(rv);
|
||||
break;
|
||||
}
|
||||
case ValType::F32: {
|
||||
RegF32 rv = popF32();
|
||||
ScratchI32 tmp(*this);
|
||||
masm.storeFloat32(rv, addressOfGlobalVar(global, tmp));
|
||||
freeF32(rv);
|
||||
break;
|
||||
}
|
||||
case ValType::F64: {
|
||||
RegF64 rv = popF64();
|
||||
ScratchI32 tmp(*this);
|
||||
masm.storeDouble(rv, addressOfGlobalVar(global, tmp));
|
||||
freeF64(rv);
|
||||
break;
|
||||
|
|
|
@ -23,7 +23,8 @@
|
|||
*
|
||||
* CSS_NON_INHERITING_ANON_BOX is used for anon boxes that never inherit style
|
||||
* from anything. This means all their property values are the initial values
|
||||
* of those properties.
|
||||
* of those properties. These ones must come first! Code relies on this.
|
||||
* If this macro is not defined, it will default to CSS_ANON_BOX.
|
||||
*
|
||||
* CSS_WRAPPER_ANON_BOX is used for anon boxes that are used as wrappers around
|
||||
* other frames during frametree fixup (e.g. table anonymous boxes, ruby
|
||||
|
@ -51,13 +52,33 @@
|
|||
# define DEFINED_CSS_WRAPPER_ANON_BOX
|
||||
#endif /* CSS_WRAPPER_ANON_BOX */
|
||||
|
||||
// ::-moz-text, ::-moz-oof-placeholder, and ::-moz-first-letter-continuation are
|
||||
// non-elements which no rule will match.
|
||||
CSS_ANON_BOX(mozText, ":-moz-text")
|
||||
// placeholder frames for out of flows. Note that :-moz-placeholder is used for
|
||||
//---------------------------------------------------------------------------
|
||||
// Non-inheriting ones, which must come first
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
// Placeholder frames for out of flows. Note that :-moz-placeholder is used for
|
||||
// the pseudo-element that represents the placeholder text in <input
|
||||
// placeholder="foo">, so we need a different string here.
|
||||
CSS_NON_INHERITING_ANON_BOX(oofPlaceholder, ":-moz-oof-placeholder")
|
||||
|
||||
// Framesets
|
||||
CSS_NON_INHERITING_ANON_BOX(horizontalFramesetBorder, ":-moz-hframeset-border")
|
||||
CSS_NON_INHERITING_ANON_BOX(verticalFramesetBorder, ":-moz-vframeset-border")
|
||||
|
||||
CSS_NON_INHERITING_ANON_BOX(framesetBlank, ":-moz-frameset-blank")
|
||||
|
||||
CSS_NON_INHERITING_ANON_BOX(tableColGroup, ":-moz-table-column-group")
|
||||
CSS_NON_INHERITING_ANON_BOX(tableCol, ":-moz-table-column")
|
||||
|
||||
CSS_NON_INHERITING_ANON_BOX(pageBreak, ":-moz-pagebreak")
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Other ones
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
// ::-moz-text, ::-moz-oof-placeholder, and ::-moz-first-letter-continuation are
|
||||
// non-elements which no rule will match.
|
||||
CSS_ANON_BOX(mozText, ":-moz-text")
|
||||
// nsFirstLetterFrames for content outside the ::first-letter.
|
||||
CSS_ANON_BOX(firstLetterContinuation, ":-moz-first-letter-continuation")
|
||||
|
||||
|
@ -65,31 +86,23 @@ CSS_ANON_BOX(mozBlockInsideInlineWrapper, ":-moz-block-inside-inline-wrapper")
|
|||
CSS_WRAPPER_ANON_BOX(mozMathMLAnonymousBlock, ":-moz-mathml-anonymous-block")
|
||||
CSS_ANON_BOX(mozXULAnonymousBlock, ":-moz-xul-anonymous-block")
|
||||
|
||||
// Framesets
|
||||
CSS_NON_INHERITING_ANON_BOX(horizontalFramesetBorder, ":-moz-hframeset-border")
|
||||
CSS_NON_INHERITING_ANON_BOX(verticalFramesetBorder, ":-moz-vframeset-border")
|
||||
|
||||
CSS_ANON_BOX(mozLineFrame, ":-moz-line-frame")
|
||||
|
||||
CSS_ANON_BOX(buttonContent, ":-moz-button-content")
|
||||
CSS_ANON_BOX(cellContent, ":-moz-cell-content")
|
||||
CSS_ANON_BOX(dropDownList, ":-moz-dropdown-list")
|
||||
CSS_ANON_BOX(fieldsetContent, ":-moz-fieldset-content")
|
||||
CSS_NON_INHERITING_ANON_BOX(framesetBlank, ":-moz-frameset-blank")
|
||||
CSS_ANON_BOX(mozDisplayComboboxControlFrame, ":-moz-display-comboboxcontrol-frame")
|
||||
CSS_ANON_BOX(htmlCanvasContent, ":-moz-html-canvas-content")
|
||||
|
||||
CSS_WRAPPER_ANON_BOX(inlineTable, ":-moz-inline-table")
|
||||
CSS_WRAPPER_ANON_BOX(table, ":-moz-table")
|
||||
CSS_WRAPPER_ANON_BOX(tableCell, ":-moz-table-cell")
|
||||
CSS_NON_INHERITING_ANON_BOX(tableColGroup, ":-moz-table-column-group")
|
||||
CSS_NON_INHERITING_ANON_BOX(tableCol, ":-moz-table-column")
|
||||
CSS_ANON_BOX(tableWrapper, ":-moz-table-wrapper")
|
||||
CSS_WRAPPER_ANON_BOX(tableRowGroup, ":-moz-table-row-group")
|
||||
CSS_WRAPPER_ANON_BOX(tableRow, ":-moz-table-row")
|
||||
|
||||
CSS_ANON_BOX(canvas, ":-moz-canvas")
|
||||
CSS_NON_INHERITING_ANON_BOX(pageBreak, ":-moz-pagebreak")
|
||||
CSS_ANON_BOX(page, ":-moz-page")
|
||||
CSS_ANON_BOX(pageContent, ":-moz-pagecontent")
|
||||
CSS_ANON_BOX(pageSequence, ":-moz-page-sequence")
|
||||
|
|
|
@ -39,21 +39,12 @@ MOZ_POP_DISABLE_INTEGRAL_CONSTANT_OVERFLOW_WARNING
|
|||
#undef CSS_ANON_BOX
|
||||
|
||||
static const nsStaticAtomSetup sCSSAnonBoxAtomSetup[] = {
|
||||
// Put the non-inheriting anon boxes first, so we can index into them easily.
|
||||
#define CSS_ANON_BOX(name_, value_) /* nothing */
|
||||
#define CSS_NON_INHERITING_ANON_BOX(name_, value_) \
|
||||
NS_STATIC_ATOM_SUBCLASS_SETUP( \
|
||||
mozilla::detail::gCSSAnonBoxAtoms, nsCSSAnonBoxes, name_)
|
||||
#include "nsCSSAnonBoxList.h"
|
||||
#undef CSS_NON_INHERITING_ANON_BOX
|
||||
#undef CSS_ANON_BOX
|
||||
|
||||
// Non-inheriting boxes must come first in nsCSSAnonBoxList.h so that
|
||||
// `NonInheriting` values can index into this array and other similar arrays.
|
||||
#define CSS_ANON_BOX(name_, value_) \
|
||||
NS_STATIC_ATOM_SUBCLASS_SETUP( \
|
||||
mozilla::detail::gCSSAnonBoxAtoms, nsCSSAnonBoxes, name_)
|
||||
#define CSS_NON_INHERITING_ANON_BOX(name_, value_) /* nothing */
|
||||
#include "nsCSSAnonBoxList.h"
|
||||
#undef CSS_NON_INHERITING_ANON_BOX
|
||||
#undef CSS_ANON_BOX
|
||||
};
|
||||
|
||||
|
@ -86,10 +77,3 @@ nsCSSAnonBoxes::NonInheritingTypeForPseudoTag(nsAtom* aPseudo)
|
|||
MOZ_RELEASE_ASSERT(index.isSome());
|
||||
return static_cast<NonInheriting>(*index);
|
||||
}
|
||||
|
||||
/* static */ nsAtom*
|
||||
nsCSSAnonBoxes::GetNonInheritingPseudoAtom(NonInheriting aBoxType)
|
||||
{
|
||||
MOZ_ASSERT(aBoxType < NonInheriting::_Count);
|
||||
return *sCSSAnonBoxAtomSetup[static_cast<NonInheritingBase>(aBoxType)].mAtomp;
|
||||
}
|
||||
|
|
|
@ -118,10 +118,6 @@ public:
|
|||
// Get the NonInheriting type for a given pseudo tag. The pseudo tag must
|
||||
// test true for IsNonInheritingAnonBox.
|
||||
static NonInheriting NonInheritingTypeForPseudoTag(nsAtom* aPseudo);
|
||||
|
||||
// Get the atom for a given non-inheriting anon box type. aBoxType must be <
|
||||
// NonInheriting::_Count.
|
||||
static nsAtom* GetNonInheritingPseudoAtom(NonInheriting aBoxType);
|
||||
};
|
||||
|
||||
#endif /* nsCSSAnonBoxes_h___ */
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче