Merge mozilla-central to autoland a=merge on a CLOSED TREE

This commit is contained in:
Coroiu Cristina 2018-11-28 23:56:03 +02:00
Родитель f1dd32d581 d4aafa8e1c
Коммит 47323ec73b
145 изменённых файлов: 12169 добавлений и 2524 удалений

Просмотреть файл

@ -76,17 +76,17 @@
<body>
<a target="_blank"
<a target="_blank" rel="opener"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=506389"
title="Some same page links do not fire EVENT_SYSTEM_SCROLLINGSTART">
Mozilla Bug 506389
</a><br>
<a target="_blank"
<a target="_blank" rel="opener"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=437607"
title="Clicking the 'Skip to main content' link once works, second time fails to initiate a V cursor jump">
Mozilla Bug 437607
</a><br>
<a target="_blank"
<a target="_blank" rel="opener"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=519303"
title="Same page links to targets with content fires scrolling start accessible event on leaf text node">
Mozilla Bug 519303

Просмотреть файл

@ -135,7 +135,7 @@
<body>
<a target="_blank"
<a target="_blank" rel="opener"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=410765"
title="nsIAccessible actions testing">
Mozilla Bug 410765

Просмотреть файл

@ -77,7 +77,7 @@
<body>
<a target="_blank"
<a target="_blank" rel="opener"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=477975"
title="nsIAccessible actions testing">
Mozilla Bug 477975

Просмотреть файл

@ -63,17 +63,17 @@
<body>
<a target="_blank"
<a target="_blank" rel="opener"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=523789"
title="nsHTMLLiAccessible shouldn't be inherited from linkable accessible">
Mozilla Bug 523789
</a><br>
<a target="_blank"
<a target="_blank" rel="opener"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=423409"
title="Expose click action if mouseup and mousedown are registered">
Mozilla Bug 423409
</a>
<a target="_blank"
<a target="_blank" rel="opener"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=659620"
title="hang when trying to edit a page on wikimo with NVDA running">
Mozilla Bug 659620

Просмотреть файл

@ -92,12 +92,12 @@
<hbox flex="1" style="overflow: auto;">
<body xmlns="http://www.w3.org/1999/xhtml">
<a target="_blank"
<a target="_blank" rel="opener"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=410765"
title="nsIAccessible actions testing">
Mozilla Bug 410765
</a>
<a target="_blank"
<a target="_blank" rel="opener"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=504252"
title="Expose STATE_HASPOPUP on XUL elements that have an @popup attribute">
Mozilla Bug 504252

Просмотреть файл

@ -38,7 +38,7 @@
<body>
<a target="_blank"
<a target="_blank" rel="opener"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=381599"
title="Inverse relations cache">
Mozilla Bug 381599

Просмотреть файл

@ -66,7 +66,7 @@
<hbox flex="1" style="overflow: auto;">
<body xmlns="http://www.w3.org/1999/xhtml">
<a target="_blank"
<a target="_blank" rel="opener"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=672092"
title="Reorganize access key and keyboard shortcut handling code">
Mozilla Bug 672092

Просмотреть файл

@ -116,7 +116,7 @@
<body>
<a target="_blank"
<a target="_blank" rel="opener"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=423409"
title="Expose click action if mouseup and mousedown are registered">
Mozilla Bug 423409
@ -126,7 +126,7 @@
<pre id="test">
</pre>
<a href="about:mozilla" id="link1" target="_blank">
<a href="about:mozilla" id="link1" target="_blank" rel="opener">
<img src="../moz.png" id="img1">
</a>
<a id="link2" onmousedown="">

Просмотреть файл

@ -116,7 +116,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=483573
</head>
<body>
<a target="_blank"
<a target="_blank" rel="opener"
title="Expose HTML5 video and audio elements' embedded controls through accessibility APIs"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=483573">Mozilla Bug 483573</a>
<p id="display"></p>

Просмотреть файл

@ -81,7 +81,7 @@
<body>
<a target="_blank"
<a target="_blank" rel="opener"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=673958"
title="Rework accessible focus handling">
Mozilla Bug 673958

Просмотреть файл

@ -100,7 +100,7 @@
<hbox flex="1" style="overflow: auto;">
<body xmlns="http://www.w3.org/1999/xhtml">
<a target="_blank"
<a target="_blank" rel="opener"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=503727"
title="Reorganize implementation of XUL tree accessibility">
Mozilla Bug 503727

Просмотреть файл

@ -165,7 +165,7 @@
<hbox flex="1" style="overflow: auto;">
<body xmlns="http://www.w3.org/1999/xhtml">
<a target="_blank"
<a target="_blank" rel="opener"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=503727"
title="Reorganize implementation of XUL tree accessibility">
Mozilla Bug 503727

Просмотреть файл

@ -559,17 +559,13 @@ html|input.urlbar-input:-moz-locale-dir(rtl) {
direction: ltr !important;
text-align: right !important;
}
/* Make sure that the location bar's alignment in RTL mode changes according
to the input box direction if the user switches the text direction using
cmd_switchTextDirection (which applies a dir attribute to the <input>). */
html|input.urlbar-input[dir=ltr]:-moz-locale-dir(rtl) {
text-align: left !important;
}
/* Show placeholder text in URL bar using correct direction */
html|input.urlbar-input:-moz-locale-dir(rtl):placeholder-shown {
direction: rtl !important;
}
/*
* Display visual cue that browser is under remote control by Marionette.

Просмотреть файл

@ -11,7 +11,7 @@ requestLongerTimeout(2);
function frame_script() {
content.document.body.innerHTML = `
<a href="http://example.com/" target="_blank" id="testAnchor">Open a window</a>
<a href="http://example.com/" target="_blank" rel="opener" id="testAnchor">Open a window</a>
`;
let element = content.document.getElementById("testAnchor");

Просмотреть файл

@ -33,7 +33,7 @@
<li>
<a id="test-create-new-tab-from-targetblank-click"
href="webNav_createdTarget.html#new-tab-from-targetblank-click"
target="_blank">
target="_blank" rel="opener">
Open a target page in a new tab from click to link with target="_blank"
</a>
</li>

Просмотреть файл

@ -33,7 +33,7 @@
<li>
<a id="test-create-new-tab-from-targetblank-click-subframe"
href="webNav_createdTarget.html#new-tab-from-targetblank-click-subframe"
target="_blank">
target="_blank" rel="opener">
Open a target page in a new tab from click to link with target="_blank"
</a>
</li>

Просмотреть файл

@ -113,7 +113,6 @@ included_inclnames_to_ignore = set([
# ignore #includes of them when checking #include ordering.
oddly_ordered_inclnames = set([
'ctypes/typedefs.h', # Included multiple times in the body of ctypes/CTypes.h
'frontend/BinSource-auto.h', # Included in the body of frontend/BinSource.h
# Included in the body of frontend/TokenStream.h
'frontend/ReservedWordsGenerated.h',
'gc/StatsPhasesGenerated.h', # Included in the body of gc/Statistics.h

Просмотреть файл

@ -1,9 +1,9 @@
This is the debugger.html project output.
See https://github.com/devtools-html/debugger.html
Version 103
Version 104
Comparison: https://github.com/devtools-html/debugger.html/compare/release-102...release-103
Comparison: https://github.com/devtools-html/debugger.html/compare/release-103...release-104
Packages:
- babel-plugin-transform-es2015-modules-commonjs @6.26.2

Просмотреть файл

@ -2286,16 +2286,6 @@ menuseparator {
background: var(--theme-body-color);
}
.source-footer .commands .coverage {
color: var(--theme-body-color);
}
.coverage-on .source-footer .commands .coverage {
color: var(--theme-highlight-blue);
border: 1px solid var(--theme-body-color-inactive);
border-radius: 2px;
}
.source-footer > .commands > .blackboxed > img.blackBox {
background: var(--theme-highlight-blue);
}
@ -2872,11 +2862,6 @@ html[dir="rtl"] .editor-mount {
background: var(--theme-selection-background-hover);
}
.coverage-on .CodeMirror-code :not(.hit-marker) .CodeMirror-line,
.coverage-on .CodeMirror-code :not(.hit-marker) .CodeMirror-gutter-wrapper {
opacity: 0.5;
}
.editor.new-breakpoint svg {
fill: var(--theme-selection-background);
width: 60px;

Просмотреть файл

@ -15,7 +15,10 @@ import {
import { mapFrames, fetchExtra } from "./pause";
import { updateTab } from "./tabs";
import { PROMISE } from "./utils/middleware/promise";
import { setInScopeLines } from "./ast/setInScopeLines";
import { updateSymbolLocations } from "./utils/symbols";
import {
getSymbols,
findOutOfScopeLocations,
@ -24,7 +27,6 @@ import {
type AstPosition
} from "../workers/parser";
import { PROMISE } from "./utils/middleware/promise";
import { features } from "../utils/prefs";
import { isLoaded, isGenerated } from "../utils/source";
@ -56,7 +58,7 @@ export function setSourceMetaData(sourceId: SourceId) {
}
export function setSymbols(sourceId: SourceId) {
return async ({ dispatch, getState }: ThunkArgs) => {
return async ({ dispatch, getState, sourceMaps }: ThunkArgs) => {
const source = getSourceFromId(getState(), sourceId);
if (source.isWasm || hasSymbols(getState(), source) || !isLoaded(source)) {
@ -66,7 +68,15 @@ export function setSymbols(sourceId: SourceId) {
await dispatch({
type: "SET_SYMBOLS",
sourceId,
[PROMISE]: getSymbols(sourceId)
[PROMISE]: (async function() {
const symbols = await getSymbols(sourceId);
const mappedSymbols = updateSymbolLocations(
symbols,
source,
sourceMaps
);
return mappedSymbols;
})()
});
if (isPaused(getState())) {

Просмотреть файл

@ -45,7 +45,7 @@ async function addBreakpointPromise(getState, client, sourceMaps, breakpoint) {
return { breakpoint: newBreakpoint };
}
const { id, hitCount, actualLocation } = await client.setBreakpoint(
const { id, actualLocation } = await client.setBreakpoint(
generatedLocation,
breakpoint.condition,
isOriginalId(location.sourceId)
@ -70,7 +70,6 @@ async function addBreakpointPromise(getState, client, sourceMaps, breakpoint) {
condition: breakpoint.condition,
location: newLocation,
astLocation,
hitCount,
generatedLocation: newGeneratedLocation,
text,
originalText

Просмотреть файл

@ -12,7 +12,6 @@ import * as navigation from "./navigation";
import * as ui from "./ui";
import * as fileSearch from "./file-search";
import * as ast from "./ast";
import * as coverage from "./coverage";
import * as projectTextSearch from "./project-text-search";
import * as quickOpen from "./quick-open";
import * as sourceTree from "./source-tree";
@ -33,7 +32,6 @@ export default {
...ui,
...fileSearch,
...ast,
...coverage,
...projectTextSearch,
...quickOpen,
...sourceTree,

Просмотреть файл

@ -13,7 +13,6 @@ DIRS += [
DebuggerModules(
'ast.js',
'coverage.js',
'debuggee.js',
'event-listeners.js',
'expressions.js',

Просмотреть файл

@ -83,12 +83,18 @@ function loadSourceMap(sourceId: SourceId) {
}
if (!urls) {
// The source might have changed while we looked up the URLs, so we need
// to load it again before dispatching. We ran into an issue here because
// this was previously using 'source' and was at risk of resetting the
// 'loadedState' field to 'loading', putting it in an inconsistent state.
const currentSource = getSource(getState(), sourceId);
// If this source doesn't have a sourcemap, enable it for pretty printing
dispatch(
({
type: "UPDATE_SOURCE",
// NOTE: Flow https://github.com/facebook/flow/issues/6342 issue
source: (({ ...source, sourceMapURL: "" }: any): Source)
source: (({ ...currentSource, sourceMapURL: "" }: any): Source)
}: Action)
);
return;

Просмотреть файл

@ -9,4 +9,5 @@ DIRS += [
DebuggerModules(
'create-store.js',
'symbols.js',
)

Просмотреть файл

@ -0,0 +1,50 @@
/* 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/>. */
// @flow
import {
type SymbolDeclaration,
type SymbolDeclarations
} from "../../workers/parser";
import type { Source } from "../../types";
function updateSymbolLocation(
site: SymbolDeclaration,
source: Source,
sourceMaps: any
) {
return sourceMaps
.getGeneratedLocation(
{ ...site.location.start, sourceId: source.id },
source
)
.then(loc => {
return {
...site,
generatedLocation: { line: loc.line, column: loc.column }
};
});
}
export async function updateSymbolLocations(
symbols: SymbolDeclarations,
source: Source,
sourceMaps: any
): Promise<SymbolDeclarations> {
if (!symbols || !symbols.callExpressions) {
return Promise.resolve(symbols);
}
const mappedCallExpressions = await Promise.all(
symbols.callExpressions.map(site =>
updateSymbolLocation(site, source, sourceMaps)
)
);
const newSymbols = { ...symbols, callExpressions: mappedCallExpressions };
return Promise.resolve(newSymbols);
}

Просмотреть файл

@ -242,6 +242,15 @@ class App extends Component<Props, State> {
}));
}
// Important so that the tabs chevron updates appropriately when
// the user resizes the left or right columns
triggerEditorPaneResize() {
const editorPane = window.document.querySelector(".editor-pane");
if (editorPane) {
editorPane.dispatchEvent(new Event("resizeend"));
}
}
renderLayout = () => {
const { startPanelCollapsed, endPanelCollapsed } = this.props;
const horizontal = this.isHorizontal();
@ -282,6 +291,7 @@ class App extends Component<Props, State> {
/>
}
endPanelCollapsed={endPanelCollapsed}
onResizeEnd={this.triggerEditorPaneResize}
/>
);
};

Просмотреть файл

@ -5,7 +5,7 @@
import React, { Component } from "react";
import { connect } from "react-redux";
import { range, keyBy, isEqualWith } from "lodash";
import { range, keyBy, isEqualWith, uniqBy, groupBy, flatten } from "lodash";
import CallSite from "./CallSite";
@ -121,23 +121,43 @@ class CallSites extends Component {
filterCallSitesByLineNumber() {
const { callSites, breakpoints } = this.props;
const breakpointLines = new Set(breakpoints.map(bp => bp.location.line));
// Get unique lines from breakpoints so we can filter out unwated call sites
const uniqueBreakpointLines = new Set(
breakpoints.map(bp => bp.location.line)
);
return callSites.filter(({ location }) =>
breakpointLines.has(location.start.line)
// Get call sites based on activated breakpoint lines
const callSitesInRange = callSites.filter(({ location }) =>
uniqueBreakpointLines.has(location.start.line)
);
// Group call sites by line
const callSitesByLineObj = groupBy(callSitesInRange, "location.start.line");
// Per group, ensure all call sites are unique
return flatten(
Object.values(callSitesByLineObj).map(arr => {
const uniques = uniqBy(
arr,
site =>
`${site.generatedLocation.line}:${site.generatedLocation.column}`
);
// Only return call sites for a line when more than 1 is found
return uniques.length > 1 ? uniques : [];
})
);
}
render() {
const { editor, callSites, selectedSource } = this.props;
const { editor, callSites, selectedSource, breakpoints } = this.props;
let sites;
if (!callSites || (selectedSource && selectedSource.isPrettyPrinted)) {
if (!callSites || breakpoints.length === 0) {
return null;
}
const callSitesFiltered = this.filterCallSitesByLineNumber();
let sites;
editor.codeMirror.operation(() => {
const childCallSites = callSitesFiltered.map((callSite, index) => {
const props = {

Просмотреть файл

@ -14,7 +14,6 @@ import {
getPaneCollapse
} from "../../selectors";
import { features } from "../../utils/prefs";
import {
isPretty,
isLoaded,
@ -39,7 +38,6 @@ type Props = {
togglePrettyPrint: string => void,
toggleBlackBox: Object => void,
jumpToMappedLocation: (Source: any) => void,
recordCoverage: () => void,
togglePaneCollapse: () => void
};
@ -122,25 +120,6 @@ class SourceFooter extends PureComponent<Props> {
);
}
coverageButton() {
const { recordCoverage } = this.props;
if (!features.codeCoverage) {
return;
}
return (
<button
className="coverage action"
title={L10N.getStr("sourceFooter.codeCoverage")}
onClick={() => recordCoverage()}
aria-label={L10N.getStr("sourceFooter.codeCoverage")}
>
C
</button>
);
}
renderToggleButton() {
if (this.props.horizontal) {
return;
@ -162,7 +141,6 @@ class SourceFooter extends PureComponent<Props> {
{this.prettyPrintButton()}
{this.blackBoxButton()}
{this.blackBoxSummary()}
{this.coverageButton()}
</div>
);
}
@ -231,7 +209,6 @@ export default connect(
togglePrettyPrint: actions.togglePrettyPrint,
toggleBlackBox: actions.toggleBlackBox,
jumpToMappedLocation: actions.jumpToMappedLocation,
recordCoverage: actions.recordCoverage,
togglePaneCollapse: actions.togglePaneCollapse
}
)(SourceFooter);

Просмотреть файл

@ -76,10 +76,12 @@ class Tabs extends PureComponent<Props, State> {
componentDidMount() {
window.requestIdleCallback(this.updateHiddenTabs);
window.addEventListener("resize", this.onResize);
window.document.querySelector(".editor-pane").addEventListener("resizeend", this.onResize);
}
componentWillUnmount() {
window.removeEventListener("resize", this.onResize);
window.document.querySelector(".editor-pane").removeEventListener("resizeend", this.onResize);
}
/*

Просмотреть файл

@ -18,8 +18,6 @@ import {
getActiveSearch,
getSelectedLocation,
getSelectedSource,
getHitCountForSource,
getCoverageEnabled,
getConditionalPanelLine,
getSymbols
} from "../../selectors";
@ -32,7 +30,6 @@ import SearchBar from "./SearchBar";
import HighlightLines from "./HighlightLines";
import Preview from "./Preview";
import Breakpoints from "./Breakpoints";
import HitMarker from "./HitMarker";
import CallSites from "./CallSites";
import DebugLine from "./DebugLine";
import HighlightLine from "./HighlightLine";
@ -76,11 +73,9 @@ const cssVars = {
};
export type Props = {
hitCount: Object,
selectedLocation: ?Location,
selectedSource: ?Source,
searchOn: boolean,
coverageOn: boolean,
horizontal: boolean,
startPanelSize: number,
endPanelSize: number,
@ -533,29 +528,6 @@ class Editor extends PureComponent<Props, State> {
};
}
renderHitCounts() {
const { hitCount, selectedSource } = this.props;
if (
!selectedSource ||
!isLoaded(selectedSource) ||
!hitCount ||
!this.state.editor
) {
return;
}
return hitCount
.filter(marker => marker.get("count") > 0)
.map(marker => (
<HitMarker
key={marker.get("line")}
hitData={marker.toJS()}
editor={this.state.editor.codeMirror}
/>
));
}
renderItems() {
const { horizontal, selectedSource } = this.props;
const { editor } = this.state;
@ -577,7 +549,6 @@ class Editor extends PureComponent<Props, State> {
<GutterMenu editor={editor} />
<ConditionalPanel editor={editor} />
{features.columnBreakpoints ? <CallSites editor={editor} /> : null}
{this.renderHitCounts()}
</div>
);
}
@ -593,13 +564,9 @@ class Editor extends PureComponent<Props, State> {
}
render() {
const { coverageOn } = this.props;
return (
<div
className={classnames("editor-wrapper", {
"coverage-on": coverageOn
})}
className={classnames("editor-wrapper")}
ref={c => (this.$editorWrapper = c)}
>
<div
@ -619,14 +586,11 @@ Editor.contextTypes = {
const mapStateToProps = state => {
const selectedSource = getSelectedSource(state);
const sourceId = selectedSource ? selectedSource.id : "";
return {
selectedLocation: getSelectedLocation(state),
selectedSource,
searchOn: getActiveSearch(state) === "file",
hitCount: getHitCountForSource(state, sourceId),
coverageOn: getCoverageEnabled(state),
conditionalPanelLine: getConditionalPanelLine(state),
symbols: getSymbols(state, selectedSource)
};

Просмотреть файл

@ -20,7 +20,6 @@ DebuggerModules(
'GutterMenu.js',
'HighlightLine.js',
'HighlightLines.js',
'HitMarker.js',
'index.js',
'SearchBar.js',
'Tab.js',

Просмотреть файл

@ -35,6 +35,10 @@ export default class OutlineFilter extends Component<Props, State> {
// also bound to the ESC key
e.preventDefault();
this.props.updateFilter("");
} else if (e.key === "Enter") {
// We must prevent the form submission from taking any action
// https://github.com/devtools-html/debugger.html/pull/7308
e.preventDefault();
}
};

Просмотреть файл

@ -49,6 +49,7 @@ type Props = {
removeBreakpoints: typeof actions.removeBreakpoints,
removeAllBreakpoints: typeof actions.removeAllBreakpoints,
disableBreakpoint: typeof actions.disableBreakpoint,
setBreakpointCondition: typeof actions.setBreakpointCondition,
toggleAllBreakpoints: typeof actions.toggleAllBreakpoints,
toggleBreakpoints: typeof actions.toggleBreakpoints,
openConditionalPanel: typeof actions.openConditionalPanel,
@ -201,6 +202,7 @@ export default connect(
disableBreakpoint: actions.disableBreakpoint,
selectSpecificLocation: actions.selectSpecificLocation,
selectLocation: actions.selectLocation,
setBreakpointCondition: actions.setBreakpointCondition,
toggleAllBreakpoints: actions.toggleAllBreakpoints,
toggleBreakpoints: actions.toggleBreakpoints,
openConditionalPanel: actions.openConditionalPanel

Просмотреть файл

@ -18,7 +18,6 @@ import pause from "./pause";
import ui from "./ui";
import fileSearch from "./file-search";
import ast from "./ast";
import coverage from "./coverage";
import projectTextSearch from "./project-text-search";
import quickOpen from "./quick-open";
import sourceTree from "./source-tree";
@ -37,7 +36,6 @@ export default {
ui,
fileSearch,
ast,
coverage,
projectTextSearch,
quickOpen,
sourceTree,

Просмотреть файл

@ -11,7 +11,6 @@ DebuggerModules(
'ast.js',
'async-requests.js',
'breakpoints.js',
'coverage.js',
'debuggee.js',
'event-listeners.js',
'expressions.js',

Просмотреть файл

@ -431,13 +431,19 @@ function getSourcesByUrlInSources(
return urls[url].map(id => sources[id]);
}
export function getSourcesUrlsInSources(state: OuterState, url: string) {
export function getSourcesUrlsInSources(
state: OuterState,
url: string
): string[] {
const urls = getUrls(state);
if (!url || !urls[url]) {
return [];
}
const plainUrl = url.split("?")[0];
return [...new Set(Object.keys(urls).filter(Boolean))];
return Object.keys(urls)
.filter(Boolean)
.filter(sourceUrl => sourceUrl.split("?")[0] === plainUrl);
}
export function getHasSiblingOfSameName(state: OuterState, source: ?Source) {

Просмотреть файл

@ -14,7 +14,6 @@ export * from "../reducers/pending-breakpoints";
export * from "../reducers/ui";
export * from "../reducers/file-search";
export * from "../reducers/ast";
export * from "../reducers/coverage";
export * from "../reducers/project-text-search";
export * from "../reducers/source-tree";

Просмотреть файл

@ -18,12 +18,12 @@ type AnnotatedFrame =
| Frame;
export function annotateFrames(frames: Frame[]): AnnotatedFrame[] {
const annotatedFrames = frames.map(annotateFrame);
const annotatedFrames = frames.map(f => annotateFrame(f, frames));
return annotateBabelAsyncFrames(annotatedFrames);
}
function annotateFrame(frame: Frame): AnnotatedFrame {
const library = getLibraryFromUrl(frame);
function annotateFrame(frame: Frame, frames: Frame[]): AnnotatedFrame {
const library = getLibraryFromUrl(frame, frames);
if (library) {
return { ...frame, library };
}

Просмотреть файл

@ -128,9 +128,15 @@ export function getLibraryFromUrl(frame: Frame, callStack: Array<Frame> = []) {
o => o.contextPattern && frameUrl.match(o.contextPattern)
);
if (match) {
const contextMatch = callStack.some(f =>
libraryMap.find(o => frameUrl.match(o.pattern))
);
const contextMatch = callStack.some(f => {
const url = getFrameUrl(f);
if (!url) {
return false;
}
return libraryMap.some(o => url.match(o.pattern));
});
if (contextMatch) {
return match.label;
}

Просмотреть файл

@ -50,7 +50,6 @@ if (isDevelopment()) {
pref("devtools.debugger.features.root", true);
pref("devtools.debugger.features.map-scopes", true);
pref("devtools.debugger.features.remove-command-bar-options", true);
pref("devtools.debugger.features.code-coverage", false);
pref("devtools.debugger.features.event-listeners", false);
pref("devtools.debugger.features.code-folding", false);
pref("devtools.debugger.features.outline", true);
@ -105,7 +104,6 @@ export const features = new PrefsHelper("devtools.debugger.features", {
mapScopes: ["Bool", "map-scopes"],
removeCommandBarOptions: ["Bool", "remove-command-bar-options"],
workers: ["Bool", "workers"],
codeCoverage: ["Bool", "code-coverage"],
eventListeners: ["Bool", "event-listeners"],
outline: ["Bool", "outline"],
codeFolding: ["Bool", "code-folding"],

Просмотреть файл

@ -81,4 +81,13 @@ add_task(async function() {
bp = findBreakpoint(dbg, "simple2", 5);
is(bp.condition, "1", "breakpoint is created with the condition");
assertEditorBreakpoint(dbg, 5, true);
const bpCondition = waitForDispatch(dbg, "SET_BREAKPOINT_CONDITION");
//right click breakpoint in breakpoints list
rightClickElement(dbg, "breakpointItem", 3)
// select "remove condition";
selectMenuItem(dbg, 8);
await bpCondition;
bp = findBreakpoint(dbg, "simple2", 5);
is(bp.condition, undefined, "breakpoint condition removed");
});

Просмотреть файл

@ -52,5 +52,5 @@ add_task(async function() {
is(getValue(dbg, 4), 2);
await toggleExpressionNode(dbg, 1);
is(findAllElements(dbg, "expressionNodes").length, 20);
is(findAllElements(dbg, "expressionNodes").length, 37);
});

Просмотреть файл

@ -88,7 +88,7 @@ add_task(async function() {
await resume(dbg);
await addExpression(dbg, "location");
is(findAllElements(dbg, "expressionNodes").length, 17);
is(findAllElements(dbg, "expressionNodes").length, 34);
await toggleExpressionNode(dbg, 1);
is(findAllElements(dbg, "expressionNodes").length, 1);

Просмотреть файл

@ -70,6 +70,10 @@ add_task(async function() {
pressKey(dbg, "Escape");
is(getItems(dbg).length, 9, "9 items in the list after escape pressed");
// Ensure no action is taken when Enter key is pressed
pressKey(dbg, "Enter");
is(getItems(dbg).length, 9, "9 items in the list after enter pressed");
// check that the term 'todo' includes items with todo
type(dbg, "todo");
is(getItems(dbg).length, 2, "2 items in the list after 'todo' filter");

Просмотреть файл

@ -104,51 +104,6 @@ class FlexboxInspector {
this.walker = null;
}
/**
* If the current selected node is a flex container, check if it is also a flex item of
* a parent flex container and get its parent flex container if any and returns an
* object that consists of the parent flex container's items and properties.
*
* @param {NodeFront} containerNodeFront
* The current flex container of the selected node.
* @return {Object} consiting of the parent flex container's flex items and properties.
*/
async getAsFlexItem(containerNodeFront) {
// If the current selected node is not a flex container, we know it is a flex item.
// No need to look for the parent flex container.
if (containerNodeFront !== this.selection.nodeFront) {
return null;
}
const flexboxFront = await this.layoutInspector.getCurrentFlexbox(
this.selection.nodeFront, true);
if (!flexboxFront) {
return null;
}
containerNodeFront = flexboxFront.containerNodeFront;
if (!containerNodeFront) {
containerNodeFront = await this.walker.getNodeFromActor(flexboxFront.actorID,
["containerEl"]);
}
let flexItemContainer = null;
if (flexboxFront) {
const flexItems = await this.getFlexItems(flexboxFront);
flexItemContainer = {
actorID: flexboxFront.actorID,
flexItems,
flexItemShown: this.selection.nodeFront.actorID,
isFlexItemContainer: true,
nodeFront: containerNodeFront,
properties: flexboxFront.properties,
};
}
return flexItemContainer;
}
getComponentProps() {
return {
onSetFlexboxOverlayColor: this.onSetFlexboxOverlayColor,
@ -172,6 +127,58 @@ class FlexboxInspector {
return this._customHostColors;
}
/**
* Returns the flex container properties for a given node. If the given node is a flex
* item, it attempts to fetch the flex container of the parent node of the given node.
*
* @param {NodeFront} nodeFront
* The NodeFront to fetch the flex container properties.
* @param {Boolean} onlyLookAtParents
* Whether or not to only consider the parent node of the given node.
* @return {Object} consisting of the given node's flex container's properties.
*/
async getFlexContainerProps(nodeFront, onlyLookAtParents = false) {
const flexboxFront = await this.layoutInspector.getCurrentFlexbox(nodeFront,
onlyLookAtParents);
if (!flexboxFront) {
return null;
}
// If the FlexboxFront doesn't yet have access to the NodeFront for its container,
// then get it from the walker. This happens when the walker hasn't seen this
// particular DOM Node in the tree yet or when we are connected to an older server.
let containerNodeFront = flexboxFront.containerNodeFront;
if (!containerNodeFront) {
containerNodeFront = await this.walker.getNodeFromActor(flexboxFront.actorID,
["containerEl"]);
}
const flexItems = await this.getFlexItems(flexboxFront);
// If the current selected node is a flex item, display its flex item sizing
// properties.
let flexItemShown = null;
if (onlyLookAtParents) {
flexItemShown = this.selection.nodeFront.actorID;
} else {
const selectedFlexItem = flexItems.find(item =>
item.nodeFront === this.selection.nodeFront);
if (selectedFlexItem) {
flexItemShown = selectedFlexItem.nodeFront.actorID;
}
}
return {
actorID: flexboxFront.actorID,
flexItems,
flexItemShown,
isFlexItemContainer: onlyLookAtParents,
nodeFront: containerNodeFront,
properties: flexboxFront.properties,
};
}
/**
* Returns an array of flex items object for the given flex container front.
*
@ -303,25 +310,36 @@ class FlexboxInspector {
}
try {
const flexboxFront = await this.layoutInspector.getCurrentFlexbox(
this.selection.nodeFront);
const flexContainer = await this.getFlexContainerProps(this.selection.nodeFront);
// Clear the flexbox panel if there is no flex container for the current node
// selection.
if (!flexboxFront) {
if (!flexContainer) {
this.store.dispatch(clearFlexbox());
return;
}
const { flexbox } = this.store.getState();
// Do nothing because the same flex container is still selected.
if (flexbox.actorID == flexboxFront.actorID) {
// Compare the new flexbox state of the current selected nodeFront with the old
// flexbox state to determine if we need to update.
if (hasFlexContainerChanged(flexbox.flexContainer, flexContainer)) {
this.update(flexContainer);
return;
}
// Update the flexbox panel with the new flexbox front contents.
this.update(flexboxFront);
let flexItemContainer = null;
// If the current selected node is also the flex container node, check if it is
// a flex item of a parent flex container.
if (flexContainer.nodeFront === this.selection.nodeFront) {
flexItemContainer = await this.getFlexContainerProps(this.selection.nodeFront,
true);
}
// Compare the new and old state of the parent flex container properties.
if (hasFlexContainerChanged(flexbox.flexItemContainer, flexItemContainer)) {
this.update(flexContainer, flexItemContainer);
}
} catch (e) {
// This call might fail if called asynchrously after the toolbox is finished
// closing.
@ -427,10 +445,14 @@ class FlexboxInspector {
* the layout view becomes visible or a new node is selected and needs to be update
* with new flexbox data.
*
* @param {FlexboxFront|null} flexboxFront
* The FlexboxFront of the flex container for the current node selection.
* @param {Object|null} flexContainer
* An object consisting of the current flex container's flex items and
* properties.
* @param {Object|null} flexItemContainer
* An object consisting of the parent flex container's flex items and
* properties.
*/
async update(flexboxFront) {
async update(flexContainer, flexItemContainer) {
// Stop refreshing if the inspector or store is already destroyed or no node is
// selected.
if (!this.inspector ||
@ -442,53 +464,35 @@ class FlexboxInspector {
try {
// Fetch the current flexbox if no flexbox front was passed into this update.
if (!flexboxFront) {
flexboxFront = await this.layoutInspector.getCurrentFlexbox(
this.selection.nodeFront);
if (!flexContainer) {
flexContainer = await this.getFlexContainerProps(this.selection.nodeFront);
}
// Clear the flexbox panel if there is no flex container for the current node
// selection.
if (!flexboxFront) {
if (!flexContainer) {
this.store.dispatch(clearFlexbox());
return;
}
// If the FlexboxFront doesn't yet have access to the NodeFront for its container,
// then get it from the walker. This happens when the walker hasn't seen this
// particular DOM Node in the tree yet or when we are connected to an older server.
let containerNodeFront = flexboxFront.containerNodeFront;
if (!containerNodeFront) {
containerNodeFront = await this.walker.getNodeFromActor(flexboxFront.actorID,
["containerEl"]);
if (!flexItemContainer && flexContainer.nodeFront === this.selection.nodeFront) {
flexItemContainer = await this.getFlexContainerProps(this.selection.nodeFront,
true);
}
const flexItemContainer = await this.getAsFlexItem(containerNodeFront);
const flexItems = await this.getFlexItems(flexboxFront);
// If the current selected node is a flex item, display its flex item sizing
// properties.
const flexItemShown = flexItems.find(item =>
item.nodeFront === this.selection.nodeFront);
const highlighted = this._highlighters &&
containerNodeFront == this.highlighters.flexboxHighlighterShown;
flexContainer.nodeFront === this.highlighters.flexboxHighlighterShown;
const color = await this.getOverlayColor();
this.store.dispatch(updateFlexbox({
color,
flexContainer: {
actorID: flexboxFront.actorID,
flexItems,
flexItemShown: flexItemShown ? flexItemShown.nodeFront.actorID : null,
isFlexItemContainer: false,
nodeFront: containerNodeFront,
properties: flexboxFront.properties,
},
flexContainer,
flexItemContainer,
highlighted,
}));
const isContainerInfoShown = !flexItemShown || !!flexItemContainer;
const isItemInfoShown = !!flexItemShown || !!flexItemContainer;
const isContainerInfoShown = !flexContainer.flexItemShown || !!flexItemContainer;
const isItemInfoShown = !!flexContainer.flexItemShown || !!flexItemContainer;
this.sendTelemetryProbes(isContainerInfoShown, isItemInfoShown);
} catch (e) {
// This call might fail if called asynchrously after the toolbox is finished
@ -497,4 +501,57 @@ class FlexboxInspector {
}
}
/**
* For a given flex container object, returns the flex container properties that can be
* used to check if 2 flex container objects are the same.
*
* @param {Object|null} flexContainer
* Object consisting of the flex container's properties.
* @return {Object|null} consisting of the comparable flex container's properties.
*/
function getComparableFlexContainerProperties(flexContainer) {
if (!flexContainer) {
return null;
}
return {
flexItems: getComparableFlexItemsProperties(flexContainer.flexItems),
nodeFront: flexContainer.nodeFront.actorID,
properties: flexContainer.properties,
};
}
/**
* Given an array of flex item objects, returns the relevant flex item properties that can
* be compared to check if any changes has occurred.
*
* @param {Array} flexItems
* Array of objects containing the flex item properties.
* @return {Array} of objects consisting of the comparable flex item's properties.
*/
function getComparableFlexItemsProperties(flexItems) {
return flexItems.map(item => {
return {
computedStyle: item.computedStyle,
flexItemSizing: item.flexItemSizing,
nodeFront: item.nodeFront.actorID,
properties: item.properties,
};
});
}
/**
* Compares the old and new flex container properties
*
* @param {Object} oldFlexContainer
* Object consisting of the old flex container's properties.
* @param {Object} newFlexContainer
* Object consisting of the new flex container's properties.
* @return {Boolean} true if the flex container properties are the same, false otherwise.
*/
function hasFlexContainerChanged(oldFlexContainer, newFlexContainer) {
return JSON.stringify(getComparableFlexContainerProperties(oldFlexContainer)) !==
JSON.stringify(getComparableFlexContainerProperties(newFlexContainer));
}
module.exports = FlexboxInspector;

Просмотреть файл

@ -20,6 +20,7 @@ support-files =
[browser_flexbox_accordion_state.js]
[browser_flexbox_container_and_item.js]
[browser_flexbox_container_and_item_updates_on_change.js]
[browser_flexbox_container_element_rep.js]
[browser_flexbox_container_properties.js]
[browser_flexbox_empty_state.js]
@ -27,6 +28,7 @@ support-files =
[browser_flexbox_highlighter_color_picker_on_RETURN.js]
[browser_flexbox_item_list_01.js]
[browser_flexbox_item_list_02.js]
[browser_flexbox_item_list_updates_on_change.js]
[browser_flexbox_item_outline_exists.js]
[browser_flexbox_item_outline_has_correct_layout.js]
[browser_flexbox_item_outline_hidden_when_useless.js]
@ -41,6 +43,7 @@ support-files =
[browser_flexbox_sizing_info_for_text_nodes.js]
[browser_flexbox_sizing_info_has_correct_sections.js]
[browser_flexbox_sizing_info_matches_properties_with_!important.js]
[browser_flexbox_sizing_info_updates_on_change.js]
[browser_flexbox_sizing_wanted_to_grow_but_was_clamped.js]
[browser_flexbox_text_nodes_are_listed.js]
[browser_flexbox_toggle_flexbox_highlighter_01.js]

Просмотреть файл

@ -0,0 +1,46 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test that the flex container accordion is rendered when a flex item is updated to
// also be a flex container.
const TEST_URI = `
<style>
.container {
display: flex;
}
</style>
<div id="container" class="container">
<div id="item">
<div></div>
</div>
</div>
`;
add_task(async function() {
await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
const { inspector, flexboxInspector, testActor } = await openLayoutView();
const { document: doc } = flexboxInspector;
const onFlexItemSizingRendered = waitForDOM(doc, "ul.flex-item-sizing");
await selectNode("#item", inspector);
const [flexSizingContainer] = await onFlexItemSizingRendered;
ok(flexSizingContainer, "The flex sizing info is rendered.");
info("Changing the flexbox in the page.");
const onAccordionsChanged = waitForDOM(doc, ".accordion > div", 4);
testActor.eval(`
document.getElementById("item").className = "container";
`);
const [flexItemPane, flexContainerPane] = await onAccordionsChanged;
ok(flexItemPane, "The flex item accordion pane is rendered.");
ok(flexContainerPane, "The flex container accordion pane is rendered.");
is(flexItemPane.children[0].textContent, "Flex Item of div#container.container",
"Got the correct header for the flex item pane.");
is(flexContainerPane.children[0].textContent, "Flex Container",
"Got the correct header for the flex container pane.");
});

Просмотреть файл

@ -0,0 +1,44 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test that the flex item list updates on changes to the number of flex items in the
// flex container.
const TEST_URI = `
<style>
#container {
display: flex;
}
</style>
<div id="container">
<div></div>
</div>
`;
add_task(async function() {
await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
const { inspector, flexboxInspector, testActor } = await openLayoutView();
const { document: doc } = flexboxInspector;
const onFlexItemListRendered = waitForDOM(doc, ".flex-item-list");
await selectNode("#container", inspector);
const [flexItemList] = await onFlexItemListRendered;
info("Checking the initial state of the flex item list.");
ok(flexItemList, "The flex item list is rendered.");
is(flexItemList.querySelectorAll("button").length, 1,
"Got the correct number of flex items in the list.");
info("Changing the flexbox in the page.");
const onFlexItemListChanged = waitForDOM(doc, ".flex-item-list > button", 2);
testActor.eval(`
const div = document.createElement("div");
document.getElementById("container").appendChild(div);
`);
const elements = await onFlexItemListChanged;
info("Checking the flex item list is correct.");
is(elements.length, 2, "Flex item list was changed.");
});

Просмотреть файл

@ -0,0 +1,41 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test that the flexbox sizing info updates on changes to the flex item properties.
const TEST_URI = `
<style>
#container {
display: flex;
}
</style>
<div id="container">
<div id="item"></div>
</div>
`;
add_task(async function() {
await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
const { inspector, flexboxInspector, testActor } = await openLayoutView();
const { document: doc } = flexboxInspector;
const onFlexItemSizingRendered = waitForDOM(doc, "ul.flex-item-sizing");
await selectNode("#item", inspector);
const [flexItemSizingContainer] = await onFlexItemSizingRendered;
info("Checking the initial state of the flex item list.");
is(flexItemSizingContainer.querySelectorAll("li").length, 2,
"Got the correct number of flex item sizing properties in the list.");
info("Changing the flexbox in the page.");
const onFlexItemSizingChanged = waitForDOM(doc, "ul.flex-item-sizing > li", 3);
testActor.eval(`
document.getElementById("item").style.minWidth = "100px";
`);
const elements = await onFlexItemSizingChanged;
info("Checking the flex item sizing info is correct.");
is(elements.length, 3, "Flex item sizing info was changed.");
});

Просмотреть файл

@ -3283,32 +3283,6 @@ function getNodeSetter(item) {
return item && item.contents ? item.contents.set : undefined;
}
function makeNodesForAccessors(item) {
const accessors = [];
const getter = getNodeGetter(item);
if (getter && getter.type !== "undefined") {
accessors.push(createNode({
parent: item,
name: "<get>",
contents: { value: getter },
type: NODE_TYPES.GET
}));
}
const setter = getNodeSetter(item);
if (setter && setter.type !== "undefined") {
accessors.push(createNode({
parent: item,
name: "<set>",
contents: { value: setter },
type: NODE_TYPES.SET
}));
}
return accessors;
}
function sortProperties(properties) {
return properties.sort((a, b) => {
// Sort numbers in ascending order and sort strings lexicographically
@ -3442,6 +3416,18 @@ function makeNodesForProperties(objProps, parent) {
nodes.push(makeNodesForEntries(parent));
}
// Add accessor nodes if needed
for (const name of propertiesNames) {
const property = allProperties[name];
if (property.get && property.get.type !== "undefined") {
nodes.push(createGetterNode({ parent, property, name }));
}
if (property.set && property.set.type !== "undefined") {
nodes.push(createSetterNode({ parent, property, name }));
}
}
// Add the prototype if it exists and is not null
if (prototype && prototype.type !== "null") {
nodes.push(makeNodeForPrototype(objProps, parent));
@ -3511,6 +3497,24 @@ function createNode(options) {
};
}
function createGetterNode({ parent, property, name }) {
return createNode({
parent,
name: `<get ${name}()>`,
contents: { value: property.get },
type: NODE_TYPES.GET
});
}
function createSetterNode({ parent, property, name }) {
return createNode({
parent,
name: `<set ${name}()>`,
contents: { value: property.set },
type: NODE_TYPES.SET
});
}
function getSymbolDescriptor(symbol) {
return symbol.toString().replace(/^(Symbol\()(.*)(\))$/, "$2");
}
@ -3552,10 +3556,6 @@ function getChildren(options) {
return addToCache(item.contents);
}
if (nodeHasAccessors(item)) {
return addToCache(makeNodesForAccessors(item));
}
if (nodeIsMapEntry(item)) {
return addToCache(makeNodesForMapEntry(item));
}
@ -3647,6 +3647,8 @@ function getClosestNonBucketNode(item) {
module.exports = {
createNode,
createGetterNode,
createSetterNode,
getActor,
getChildren,
getClosestGripNode,
@ -6487,7 +6489,7 @@ class ObjectInspector extends Component {
const parentElementProps = {
className: classnames("node object-node", {
focused,
lessen: !expanded && (nodeIsDefaultProperties(item) || nodeIsPrototype(item) || dimTopLevelWindow === true && nodeIsWindow(item) && depth === 0),
lessen: !expanded && (nodeIsDefaultProperties(item) || nodeIsPrototype(item) || nodeIsGetter(item) || nodeIsSetter(item) || dimTopLevelWindow === true && nodeIsWindow(item) && depth === 0),
block: nodeIsBlock(item)
}),
onClick: e => {
@ -6557,7 +6559,9 @@ class ObjectInspector extends Component {
autoExpandDepth,
isExpanded: item => expandedPaths && expandedPaths.has(item.path),
isExpandable: item => nodeIsPrimitive(item) === false,
// TODO: We don't want property with getters to be expandable until we
// do have a mechanism to invoke the getter (See #6140).
isExpandable: item => !nodeIsPrimitive(item) && !nodeHasAccessors(item),
focused: this.focusedItem,
getRoots: this.getRoots,

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

@ -13282,18 +13282,43 @@ nsDocShell::OnLinkClickSync(nsIContent* aContent,
nsAutoString referrer;
aContent->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::rel, referrer);
nsWhitespaceTokenizerTemplate<nsContentUtils::IsHTMLWhitespace> tok(referrer);
bool targetBlank = aTargetSpec.LowerCaseEqualsLiteral("_blank");
bool explicitOpenerSet = false;
// The opener behaviour follows a hierarchy, such that if a higher priority
// behaviour is specified, it always takes priority. That priority is
// currently: norefrerer > noopener > opener > default
while (tok.hasMoreTokens()) {
const nsAString& token = tok.nextToken();
if (token.LowerCaseEqualsLiteral("noreferrer")) {
flags |= INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER |
INTERNAL_LOAD_FLAGS_NO_OPENER;
// We now have all the flags we could possibly have, so just stop.
// noreferrer cannot be overwritten by a 'rel=opener'.
explicitOpenerSet = true;
break;
}
if (token.LowerCaseEqualsLiteral("noopener")) {
flags |= INTERNAL_LOAD_FLAGS_NO_OPENER;
explicitOpenerSet = true;
}
if (targetBlank &&
StaticPrefs::dom_targetBlankNoOpener_enabled() &&
token.LowerCaseEqualsLiteral("opener") &&
!explicitOpenerSet) {
explicitOpenerSet = true;
}
}
if (targetBlank &&
StaticPrefs::dom_targetBlankNoOpener_enabled() &&
!explicitOpenerSet) {
flags |= INTERNAL_LOAD_FLAGS_NO_OPENER;
}
if (aNoOpenerImplied) {
flags |= INTERNAL_LOAD_FLAGS_NO_OPENER;
}

Просмотреть файл

@ -116,6 +116,7 @@ function test6() {
function test7() {
testlink.href = "javascript:opener.activationListener(); window.close();";
testlink.target = "_blank";
testlink.rel = "opener";
activationListener =
function() {
ok(true, "Click() should activate a link");
@ -127,6 +128,7 @@ function test7() {
function test8() {
testlink.href = "javascript:opener.activationListener(); window.close();";
testlink.target = "_blank";
testlink.rel = "opener";
activationListener =
function() {
ok(false, "Click() should not activate a link");

Просмотреть файл

@ -1,6 +1,6 @@
<html>
<body>
<a id='link' target='_blank' href="http://example.com">Click me</a>
<a id='link' target='_blank' href="http://example.com" rel="opener">Click me</a>
<script>
function clickLink() {

Просмотреть файл

@ -37,3 +37,7 @@ skip-if = os == 'mac' # bug 1494843
[browser_refresh_wyciwyg_url.js]
support-files =
file_refresh_wyciwyg_url.html
[browser_targetBlankNoOpener.js]
support-files =
empty.html
image_yellow.png

Просмотреть файл

@ -0,0 +1,83 @@
const TEST_URL = "http://mochi.test:8888/browser/dom/html/test/empty.html";
async function checkOpener(browser, elm, name, rel) {
let p = BrowserTestUtils.waitForNewTab(gBrowser, null, true, true);
await ContentTask.spawn(browser, {url: TEST_URL, name, rel, elm }, async obj => {
let element;
if (obj.elm == "anchor") {
element = content.document.createElement("a");
content.document.body.appendChild(element);
element.appendChild(content.document.createTextNode(obj.name));
} else {
let img = content.document.createElement('img');
img.src = "image_yellow.png";
content.document.body.appendChild(img);
element = content.document.createElement("area");
img.appendChild(element);
element.setAttribute("shape", "rect");
element.setAttribute("coords", "0,0,100,100");
}
element.setAttribute("target", "_blank");
element.setAttribute("href", obj.url);
if (obj.rel) {
element.setAttribute("rel", obj.rel);
}
element.click();
});
let newTab = await p;
let newBrowser = gBrowser.getBrowserForTab(newTab);
let hasOpener = await ContentTask.spawn(newTab.linkedBrowser, null, _ => !!content.window.opener);
BrowserTestUtils.removeTab(newTab);
return hasOpener;
}
async function runTests(browser, elm) {
info("Creating an " + elm + " with target=_blank rel=opener");
ok(!!(await checkOpener(browser, elm, "rel=opener", "opener")), "We want the opener with rel=opener");
info("Creating an " + elm + " with target=_blank rel=noopener");
ok(!(await checkOpener(browser, elm, "rel=noopener", "noopener")), "We don't want the opener with rel=noopener");
info("Creating an " + elm + " with target=_blank");
ok(!(await checkOpener(browser, elm, "no rel", null)), "We don't want the opener with no rel is passed");
info("Creating an " + elm + " with target=_blank rel='noopener opener'");
ok(!(await checkOpener(browser, elm, "rel=noopener+opener", "noopener opener")), "noopener wins with rel=noopener+opener");
info("Creating an " + elm + " with target=_blank rel='noreferrer opener'");
ok(!(await checkOpener(browser, elm, "noreferrer wins", "noreferrer opener")), "We don't want the opener with rel=noreferrer+opener");
info("Creating an " + elm + " with target=_blank rel='opener noreferrer'");
ok(!(await checkOpener(browser, elm, "noreferrer wins again", "noreferrer opener")), "We don't want the opener with rel=opener+noreferrer");
}
add_task(async _ => {
await SpecialPowers.flushPrefEnv();
await SpecialPowers.pushPrefEnv({"set": [
["dom.block_multiple_popups", false],
["dom.disable_open_during_load", true],
["dom.targetBlankNoOpener.enabled", true],
]});
let tab = BrowserTestUtils.addTab(gBrowser, TEST_URL);
gBrowser.selectedTab = tab;
let browser = gBrowser.getBrowserForTab(tab);
await BrowserTestUtils.browserLoaded(browser);
await runTests(browser, 'anchor');
await runTests(browser, 'area');
info("Removing the tab");
BrowserTestUtils.removeTab(tab);
});

1
dom/html/test/empty.html Normal file
Просмотреть файл

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

Просмотреть файл

@ -1,5 +1,5 @@
<!DOCTYPE html>
<body onload="document.querySelector('a').click();">
<a href="javascript:opener.document.getElementById('result').textContent = document.cookie;" target="_blank">test</a>
<a href="javascript:opener.document.getElementById('result').textContent = document.cookie;" target="_blank" rel="opener">test</a>
<div id="result">not tested yet</div>
</body>

Просмотреть файл

@ -1,4 +1,4 @@
<!DOCTYPE html>
<meta charset="UTF-8">
<a id="link" href="about:blank" target="_blank"
<a id="link" href="about:blank" target="_blank" rel="opener"
onclick="document.body.requestFullscreen()">Click here</a>

Просмотреть файл

@ -30,7 +30,7 @@
<body onLoad="doStuff()">
I am sandboxed but with "allow-scripts allow-same-origin"
<a href="file_iframe_sandbox_open_window_fail.html" target="_blank" id="target_blank">open window</a>
<a href="file_iframe_sandbox_open_window_fail.html" target="_blank" id="target_blank" rel="opener">open window</a>
<a href="file_iframe_sandbox_open_window_fail.html" target="BC341604" id="target_BC341604">open window</a>
</body>
</html>

Просмотреть файл

@ -28,7 +28,7 @@
<body onLoad="doStuff()">
I am sandboxed but with "allow-popups allow-scripts allow-same-origin"
<a href="file_iframe_sandbox_open_window_pass.html" target="_blank" id="target_blank">open window</a>
<a href="file_iframe_sandbox_open_window_pass.html" target="_blank" rel="opener" id="target_blank">open window</a>
<a href="file_iframe_sandbox_open_window_pass.html?BC766282" target="BC766282" id="target_BC766282">open window</a>
</body>
</html>

Просмотреть файл

@ -41,7 +41,7 @@
This was opened in an iframe with "allow-scripts allow-popups allow-same-origin".
However allow-same-origin was removed from the iframe before navigating to me,
so I should only have "allow-scripts allow-popups" in force.
<a href="file_iframe_sandbox_k_if2.html" target="_blank" id="target_blank_if2">open window</a>
<a href="file_iframe_sandbox_k_if2.html" target="_blank" id="target_blank_if2" rel="opener">open window</a>
<a href="file_iframe_sandbox_k_if2.html" target="BC766282_if2" id="target_BC766282_if2">open window</a>
</body>
</html>

Просмотреть файл

@ -25,10 +25,10 @@
<body onLoad="doStuff()">
I am sandboxed with "allow-scripts allow-popups allow-same-origin allow-forms allow-top-navigation".
<a href="file_iframe_sandbox_k_if5.html" target="_blank" id="target_blank_if5">open window</a>
<a href="file_iframe_sandbox_k_if5.html" target="_blank" id="target_blank_if5" rel="opener">open window</a>
<a href="file_iframe_sandbox_k_if5.html" target="BC766282_if5" id="target_BC766282_if5">open window</a>
<a href="file_iframe_sandbox_k_if7.html" target="_blank" id="target_blank_if7">open window</a>
<a href="file_iframe_sandbox_k_if7.html" target="_blank" id="target_blank_if7" rel="opener">open window</a>
<a href="file_iframe_sandbox_k_if7.html" target="BC766282_if7" id="target_BC766282_if7">open window</a>
</body>
</html>

Просмотреть файл

@ -26,7 +26,7 @@
After my initial load, "allow-same-origin" is removed and then I open file_iframe_sandbox_k_if9.html
in 3 different ways, which attemps to call a function in my parent.
This should succeed since the new sandbox flags shouldn't have taken affect on me until I'm reloaded.
<a href="file_iframe_sandbox_k_if9.html" target="_blank" id="target_blank_if9">open window</a>
<a href="file_iframe_sandbox_k_if9.html" target="_blank" id="target_blank_if9" rel="opener">open window</a>
<a href="file_iframe_sandbox_k_if9.html" target="BC766282_if9" id="target_BC766282_if9">open window</a>
Now navigate to file_iframe_sandbox_k_if1.html to do tests for a sandbox opening a window

Просмотреть файл

@ -1,5 +1,5 @@
<html>
<body>
<a id="link" href="file_window_open_close_inner.html" target="_blank" onclick="setTimeout(function () { window.close() }, 0)">link</a>
<a id="link" href="file_window_open_close_inner.html" target="_blank" rel="opener" onclick="setTimeout(function () { window.close() }, 0)">link</a>
</html>
</body>

Двоичные данные
dom/html/test/image_yellow.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 95 B

Просмотреть файл

@ -119,7 +119,7 @@ class RemoteVideoDecoder : public RemoteDataDecoder {
if (ok && (size > 0 || presentationTimeUs >= 0)) {
RefPtr<layers::Image> img = new SurfaceTextureImage(
mDecoder->mImageHandle, inputInfo.mImageSize,
mDecoder->mSurfaceHandle, inputInfo.mImageSize,
false /* NOT continuous */, gl::OriginPos::BottomLeft);
RefPtr<VideoData> v = VideoData::CreateFromImage(
@ -168,7 +168,7 @@ class RemoteVideoDecoder : public RemoteDataDecoder {
__func__);
}
mImageHandle = mSurface->GetImageHandle();
mSurfaceHandle = mSurface->GetHandle();
// Register native methods.
JavaCallbacksSupport::Init();
@ -256,7 +256,7 @@ class RemoteVideoDecoder : public RemoteDataDecoder {
private:
const VideoInfo mConfig;
GeckoSurface::GlobalRef mSurface;
AndroidSurfaceTextureHandle mImageHandle;
AndroidSurfaceTextureHandle mSurfaceHandle;
// Only accessed on reader's task queue.
bool mIsCodecSupportAdaptivePlayback = false;
// Can be accessed on any thread, but only written on during init.

Просмотреть файл

@ -9,7 +9,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=841850
<title>Tests for Mixed Content Frame Navigation</title>
</head>
<body>
<a href="http://example.com/tests/dom/security/test/mixedcontentblocker/file_frameNavigation_innermost.html?blankTarget" id="blankTarget" target="_blank">Go to http site</a>
<a href="http://example.com/tests/dom/security/test/mixedcontentblocker/file_frameNavigation_innermost.html?blankTarget" id="blankTarget" target="_blank" rel="opener">Go to http site</a>
<script>
var blankTarget = document.getElementById("blankTarget");

Просмотреть файл

@ -8,7 +8,7 @@
<p><a id="winOpenNonDefault" href="#" onclick="return openWindow('resizable=no, location=no, personalbar=no, toolbar=no, scrollbars=no, menubar=no, status=no, directories=no, height=100, width=500');">Open a new window via window.open with non-default features.</a></p>
<p><a id="winOpenDialog" href="#" onclick="return openWindow('dialog=yes');">Open a new window via window.open with dialog=1.</a></p>
<p><a id="winOpenNoURLNonDefault" href="#" onclick="return openBlankWindow('location=no, toolbar=no, height=100, width=100');">Open a blank new window via window.open with non-default features.</a></p>
<p><a id="targetBlank" href="dummy.html" target="_blank">Open a new window via target="_blank".</a></p>
<p><a id="targetBlank" href="dummy.html" target="_blank" rel="opener">Open a new window via target="_blank".</a></p>
</body>
</html>

Просмотреть файл

@ -1,4 +1,4 @@
<a id="test1" href="test_noopener_target.html" target="_blank">1</a>
<a id="test1" href="test_noopener_target.html" target="_blank" rel="opener">1</a>
<a id="test2" href="test_noopener_target.html" target="_blank" rel="noopener">2</a>
<a id="test3" href="test_noopener_target.html" target="_blank" rel="noreferrer">3</a>

Просмотреть файл

@ -16,8 +16,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=458091
</div>
<pre id="test">
<a id="testlink1" target="_blank" href="javascript:window.opener.finish(sessionStorage['testItem']);window.close();">Javascript Link</a>
<a id="testlink2" target="_blank" href="bug458091_child.html">HTTP Link</a>
<a id="testlink1" target="_blank" rel="opener" href="javascript:window.opener.finish(sessionStorage['testItem']);window.close();">Javascript Link</a>
<a id="testlink2" target="_blank" rel="opener" href="bug458091_child.html">HTTP Link</a>
<a id="testlink3" target="alreadyOpened" href="bug458091_child.html">Target Link</a>
<script type="application/javascript">

Просмотреть файл

@ -8,13 +8,6 @@
#include "AndroidSurfaceTexture.h"
#include "GeneratedJNINatives.h"
#include "AndroidNativeWindow.h"
#include "GLContextEGL.h"
#include "GLBlitHelper.h"
#include "GLImages.h"
using namespace mozilla;
namespace mozilla {
@ -36,184 +29,6 @@ AndroidSurfaceTexture::GetTransformMatrix(java::sdk::SurfaceTexture::Param surfa
env->ReleaseFloatArrayElements(jarray.Get(), array, 0);
}
class SharedGL {
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SharedGL);
SharedGL(AndroidNativeWindow& window)
{
MutexAutoLock lock(sMutex);
if (!sContext) {
MOZ_ASSERT(sInstanceCount == 0);
sContext = CreateContext();
if (!sContext) {
return;
}
}
InitSurface(window);
++sInstanceCount;
}
void Blit(const AndroidSurfaceTextureHandle& sourceTextureHandle,
const gfx::IntSize& imageSize)
{
MutexAutoLock lock(sMutex);
MOZ_ASSERT(sContext);
// Setting overide also makes conext and surface current.
sContext->SetEGLSurfaceOverride(mTargetSurface);
RefPtr<layers::SurfaceTextureImage> img =
new layers::SurfaceTextureImage(sourceTextureHandle,
imageSize,
false,
OriginPos::TopLeft);
sContext->BlitHelper()->BlitImage(img, imageSize, OriginPos::BottomLeft);
sContext->SwapBuffers();
// This method is called through binder IPC and could run on any thread in
// the pool. Release the context and surface from this thread after use so
// they can be bound to another thread later.
UnmakeCurrent(sContext);
}
private:
~SharedGL()
{
MutexAutoLock lock(sMutex);
if (mTargetSurface != EGL_NO_SURFACE) {
GLLibraryEGL::Get()->fDestroySurface(EGL_DISPLAY(), mTargetSurface);
}
// Destroy shared GL context when no one uses it.
if (--sInstanceCount == 0) {
sContext.reset();
}
}
static UniquePtr<GLContextEGL> CreateContext()
{
sMutex.AssertCurrentThreadOwns();
MOZ_ASSERT(!sContext);
auto* egl = gl::GLLibraryEGL::Get();
EGLDisplay eglDisplay = egl->fGetDisplay(EGL_DEFAULT_DISPLAY);
EGLConfig eglConfig;
CreateConfig(&eglConfig, /* bpp */ 24, /* depth buffer? */ false);
EGLint attributes[] = {
LOCAL_EGL_CONTEXT_CLIENT_VERSION, 2,
LOCAL_EGL_NONE
};
EGLContext eglContext =
egl->fCreateContext(eglDisplay, eglConfig, EGL_NO_CONTEXT, attributes);
UniquePtr<GLContextEGL> gl = MakeUnique<GLContextEGL>(CreateContextFlags::NONE,
SurfaceCaps::Any(),
/* offscreen? */ false,
eglConfig,
EGL_NO_SURFACE,
eglContext);
if (!gl->Init()) {
NS_WARNING("Fail to create GL context for native blitter.");
return nullptr;
}
// Yield the current state made in constructor.
UnmakeCurrent(gl);
return gl;
}
void InitSurface(AndroidNativeWindow& window)
{
sMutex.AssertCurrentThreadOwns();
MOZ_ASSERT(sContext);
mTargetSurface = gl::GLLibraryEGL::Get()->fCreateWindowSurface(sContext->GetEGLDisplay(),
sContext->mConfig,
window.NativeWindow(),
0);
}
static bool UnmakeCurrent(UniquePtr<GLContextEGL>& gl)
{
sMutex.AssertCurrentThreadOwns();
MOZ_ASSERT(gl);
if (!gl->IsCurrent()) {
return true;
}
return gl::GLLibraryEGL::Get()->fMakeCurrent(EGL_DISPLAY(),
EGL_NO_SURFACE,
EGL_NO_SURFACE,
EGL_NO_CONTEXT);
}
static Mutex sMutex;
static UniquePtr<GLContextEGL> sContext;
static size_t sInstanceCount;
EGLSurface mTargetSurface;
};
Mutex SharedGL::sMutex("SharedGLContext::sMutex");
UniquePtr<GLContextEGL> SharedGL::sContext(nullptr);
size_t SharedGL::sInstanceCount = 0;
class GLBlitterSupport final
: public java::GeckoSurfaceTexture::NativeGLBlitHelper::Natives<GLBlitterSupport>
{
public:
using Base = java::GeckoSurfaceTexture::NativeGLBlitHelper::Natives<GLBlitterSupport>;
using Base::AttachNative;
using Base::GetNative;
using Base::DisposeNative;
static java::GeckoSurfaceTexture::NativeGLBlitHelper::LocalRef
Create(jint sourceTextureHandle,
jni::Object::Param targetSurface,
jint width,
jint height)
{
AndroidNativeWindow win(java::GeckoSurface::Ref::From(targetSurface));
auto helper = java::GeckoSurfaceTexture::NativeGLBlitHelper::New();
RefPtr<SharedGL> gl = new SharedGL(win);
GLBlitterSupport::AttachNative(
helper,
MakeUnique<GLBlitterSupport>(std::move(gl),
sourceTextureHandle,
width,
height));
return helper;
}
GLBlitterSupport(RefPtr<SharedGL>&& gl,
jint sourceTextureHandle,
jint width,
jint height)
: mGl(gl)
, mSourceTextureHandle(sourceTextureHandle)
, mSize(width, height)
{
}
void Blit()
{
mGl->Blit(mSourceTextureHandle, mSize);
}
private:
const RefPtr<SharedGL> mGl;
const AndroidSurfaceTextureHandle mSourceTextureHandle;
const gfx::IntSize mSize;
};
void
AndroidSurfaceTexture::Init()
{
GLBlitterSupport::Init();
}
} // gl
} // mozilla
#endif // MOZ_WIDGET_ANDROID

Просмотреть файл

@ -18,7 +18,6 @@ namespace gl {
class AndroidSurfaceTexture {
public:
static void Init();
static void GetTransformMatrix(java::sdk::SurfaceTexture::Param surfaceTexture,
mozilla::gfx::Matrix4x4* outMatrix);

Просмотреть файл

@ -280,7 +280,7 @@ bool
SharedSurface_SurfaceTexture::ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor)
{
*out_descriptor =
layers::SurfaceTextureDescriptor(mSurface->GetImageHandle(),
layers::SurfaceTextureDescriptor(mSurface->GetHandle(),
mSize,
gfx::SurfaceFormat::R8G8B8A8,
false /* NOT continuous */,

Просмотреть файл

@ -170,7 +170,7 @@ AndroidNativeWindowTextureData::FillInfo(TextureData::Info& aInfo) const
bool
AndroidNativeWindowTextureData::Serialize(SurfaceDescriptor& aOutDescriptor)
{
aOutDescriptor = SurfaceTextureDescriptor(mSurface->GetImageHandle(),
aOutDescriptor = SurfaceTextureDescriptor(mSurface->GetHandle(),
mSize,
mFormat,
false /* not continuous */,

Просмотреть файл

@ -324,6 +324,7 @@ AnimationFrameDiscardingQueue::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf
AnimationFrameRecyclingQueue::AnimationFrameRecyclingQueue(AnimationFrameRetainedBuffer&& aQueue)
: AnimationFrameDiscardingQueue(std::move(aQueue))
, mForceUseFirstFrameRefreshArea(false)
{
// In an ideal world, we would always save the already displayed frames for
// recycling but none of the frames were marked as recyclable. We will incur
@ -361,31 +362,20 @@ AnimationFrameRecyclingQueue::AdvanceInternal()
MOZ_ASSERT(!mDisplay.empty());
MOZ_ASSERT(mDisplay.front());
// We have advanced past the first frame. That means the next frame we are
// putting in the queue to recycling is the first frame in the animation,
// and we no longer need to worry about having looped around.
if (mGetIndex == 1) {
mForceUseFirstFrameRefreshArea = false;
}
RefPtr<imgFrame>& front = mDisplay.front();
// The first frame should always have a dirty rect that matches the frame
// rect. As such, we should use mFirstFrameRefreshArea instead for recycle
// rect calculations.
MOZ_ASSERT_IF(mGetIndex == 1,
front->GetRect().IsEqualEdges(front->GetDirtyRect()));
RecycleEntry newEntry(mGetIndex == 1 ? mFirstFrameRefreshArea
: front->GetDirtyRect());
RecycleEntry newEntry(mForceUseFirstFrameRefreshArea ? mFirstFrameRefreshArea
: front->GetDirtyRect());
// If we are allowed to recycle the frame, then we should save it before the
// base class's AdvanceInternal discards it.
if (front->ShouldRecycle()) {
// Calculate the recycle rect for the recycled frame. This is the cumulative
// dirty rect of all of the frames ahead of us to be displayed, and to be
// used for recycling. Or in other words, the dirty rect between the
// recycled frame and the decoded frame which reuses the buffer.
for (const RefPtr<imgFrame>& frame : mDisplay) {
newEntry.mRecycleRect = newEntry.mRecycleRect.Union(frame->GetDirtyRect());
}
for (const RecycleEntry& entry : mRecycle) {
newEntry.mRecycleRect = newEntry.mRecycleRect.Union(entry.mDirtyRect);
}
newEntry.mFrame = std::move(front);
}
@ -428,20 +418,62 @@ AnimationFrameRecyclingQueue::ResetInternal()
RawAccessFrameRef
AnimationFrameRecyclingQueue::RecycleFrame(gfx::IntRect& aRecycleRect)
{
if (mInsertIndex == 0) {
// If we are recreating the first frame, then we actually have already
// precomputed aggregate of the dirty rects as the first frame refresh
// area. We know that all of the frames still in the recycling queue
// need to take into account the same dirty rect because they are also
// frames which cross the boundary.
MOZ_ASSERT(mSizeKnown);
MOZ_ASSERT(!mFirstFrameRefreshArea.IsEmpty());
for (RecycleEntry& entry : mRecycle) {
MOZ_ASSERT(mFirstFrameRefreshArea.Contains(entry.mDirtyRect));
entry.mDirtyRect = mFirstFrameRefreshArea;
}
// Until we advance to the first frame again, any subsequent recycled
// frames should also use the first frame refresh area.
mForceUseFirstFrameRefreshArea = true;
}
if (mRecycle.empty()) {
return RawAccessFrameRef();
}
RawAccessFrameRef frame;
RawAccessFrameRef recycledFrame;
if (mRecycle.front().mFrame) {
frame = mRecycle.front().mFrame->RawAccessRef();
if (frame) {
aRecycleRect = mRecycle.front().mRecycleRect;
recycledFrame = mRecycle.front().mFrame->RawAccessRef();
MOZ_ASSERT(recycledFrame);
mRecycle.pop_front();
if (mForceUseFirstFrameRefreshArea) {
// We are still crossing the loop boundary and cannot rely upon the dirty
// rects of entries in mDisplay to be representative. E.g. The first frame
// is probably has a full frame dirty rect.
aRecycleRect = mFirstFrameRefreshArea;
} else {
// Calculate the recycle rect for the recycled frame. This is the
// cumulative dirty rect of all of the frames ahead of us to be displayed,
// and to be used for recycling. Or in other words, the dirty rect between
// the recycled frame and the decoded frame which reuses the buffer.
//
// We know at this point that mRecycle contains either frames from the end
// of the animation with the first frame refresh area as the dirty rect
// (plus the first frame likewise) and frames with their actual dirty rect
// from the start. mDisplay should also only contain frames from the start
// of the animation onwards.
aRecycleRect.SetRect(0, 0, 0, 0);
for (const RefPtr<imgFrame>& frame : mDisplay) {
aRecycleRect = aRecycleRect.Union(frame->GetDirtyRect());
}
for (const RecycleEntry& entry : mRecycle) {
aRecycleRect = aRecycleRect.Union(entry.mDirtyRect);
}
}
} else {
mRecycle.pop_front();
}
mRecycle.pop_front();
return frame;
return recycledFrame;
}
bool

Просмотреть файл

@ -449,15 +449,12 @@ public:
RecycleEntry(RecycleEntry&& aOther)
: mFrame(std::move(aOther.mFrame))
, mDirtyRect(aOther.mDirtyRect)
, mRecycleRect(aOther.mRecycleRect)
{
}
{ }
RecycleEntry& operator=(RecycleEntry&& aOther)
{
mFrame = std::move(aOther.mFrame);
mDirtyRect = aOther.mDirtyRect;
mRecycleRect = aOther.mRecycleRect;
return *this;
}
@ -466,8 +463,6 @@ public:
RefPtr<imgFrame> mFrame; // The frame containing the buffer to recycle.
gfx::IntRect mDirtyRect; // The dirty rect of the frame itself.
gfx::IntRect mRecycleRect; // The dirty rect between the recycled frame and
// the future frame that will be written to it.
};
const std::deque<RecycleEntry>& Recycle() const { return mRecycle; }
@ -488,6 +483,11 @@ protected:
/// The first frame refresh area. This is used instead of the dirty rect for
/// the last frame when transitioning back to the first frame.
gfx::IntRect mFirstFrameRefreshArea;
/// Force recycled frames to use the first frame refresh area as their dirty
/// rect. This is used when we are recycling frames from the end of an
/// animation to produce frames at the beginning of an animation.
bool mForceUseFirstFrameRefreshArea;
};
} // namespace image

Просмотреть файл

@ -27,6 +27,9 @@ CreateEmptyFrame(const IntSize& aSize = IntSize(1, 1),
EXPECT_TRUE(NS_SUCCEEDED(rv));
RawAccessFrameRef frameRef = frame->RawAccessRef();
frame->SetRawAccessOnly();
// Normally the blend animation filter would set the dirty rect, but since
// we aren't producing an actual animation here, we need to fake it.
frame->SetDirtyRect(aFrameRect);
frame->Finish();
return frame.forget();
}
@ -105,16 +108,13 @@ VerifyAdvance(AnimationFrameBuffer& aQueue,
if (aQueue.IsRecycling()) {
const AnimationFrameRecyclingQueue& queue =
*static_cast<AnimationFrameRecyclingQueue*>(&aQueue);
EXPECT_FALSE(queue.Recycle().back().mDirtyRect.IsEmpty());
EXPECT_TRUE(queue.Recycle().back().mDirtyRect.Contains(oldFrame->GetDirtyRect()));
EXPECT_EQ(totalRecycled + 1, queue.Recycle().size());
if (oldFrame->ShouldRecycle()) {
EXPECT_EQ(oldFrame.get(), queue.Recycle().back().mFrame.get());
EXPECT_FALSE(queue.Recycle().back().mDirtyRect.IsEmpty());
EXPECT_FALSE(queue.Recycle().back().mRecycleRect.IsEmpty());
EXPECT_EQ(totalRecycled + 1, queue.Recycle().size());
} else {
EXPECT_EQ(totalRecycled, queue.Recycle().size());
if (!queue.Recycle().empty()) {
EXPECT_NE(oldFrame.get(), queue.Recycle().back().mFrame.get());
}
EXPECT_EQ(nullptr, queue.Recycle().back().mFrame.get());
}
}
}
@ -584,7 +584,7 @@ TEST_F(ImageAnimationFrameBuffer, RecyclingLoop)
// All the frames we inserted should have been recycleable.
ASSERT_FALSE(buffer.Recycle().empty());
while (!buffer.Recycle().empty()) {
IntRect expectedRect = buffer.Recycle().front().mRecycleRect;
IntRect expectedRect(0, 0, 1, 1);
RefPtr<imgFrame> expectedFrame = buffer.Recycle().front().mFrame;
EXPECT_FALSE(expectedRect.IsEmpty());
EXPECT_TRUE(expectedFrame.get() != nullptr);
@ -646,3 +646,109 @@ TEST_F(ImageAnimationFrameBuffer, RecyclingReset)
AnimationFrameRecyclingQueue buffer(std::move(retained));
TestDiscardingQueueReset(buffer, firstFrame, kThreshold, kBatch, kStartFrame);
}
TEST_F(ImageAnimationFrameBuffer, RecyclingRect)
{
const size_t kThreshold = 5;
const size_t kBatch = 2;
const size_t kStartFrame = 0;
const IntSize kImageSize(100, 100);
AnimationFrameRetainedBuffer retained(kThreshold, kBatch, kStartFrame);
// Let's get to the recycling state while marking all of the frames as not
// recyclable, just like AnimationFrameBuffer / the decoders would do.
RefPtr<imgFrame> frame;
frame = CreateEmptyFrame(kImageSize, IntRect(IntPoint(0, 0), kImageSize), false);
AnimationFrameBuffer::InsertStatus status = retained.Insert(std::move(frame));
EXPECT_EQ(AnimationFrameBuffer::InsertStatus::CONTINUE, status);
frame = CreateEmptyFrame(kImageSize, IntRect(IntPoint(0, 0), kImageSize), false);
status = retained.Insert(std::move(frame));
EXPECT_EQ(AnimationFrameBuffer::InsertStatus::CONTINUE, status);
frame = CreateEmptyFrame(kImageSize, IntRect(IntPoint(0, 0), kImageSize), false);
status = retained.Insert(std::move(frame));
EXPECT_EQ(AnimationFrameBuffer::InsertStatus::CONTINUE, status);
frame = CreateEmptyFrame(kImageSize, IntRect(IntPoint(0, 0), kImageSize), false);
status = retained.Insert(std::move(frame));
EXPECT_EQ(AnimationFrameBuffer::InsertStatus::YIELD, status);
VerifyAdvance(retained, 1, false);
VerifyAdvance(retained, 2, true);
VerifyAdvance(retained, 3, false);
frame = CreateEmptyFrame(kImageSize, IntRect(IntPoint(0, 0), kImageSize), false);
status = retained.Insert(std::move(frame));
EXPECT_EQ(AnimationFrameBuffer::InsertStatus::DISCARD_CONTINUE, status);
AnimationFrameRecyclingQueue buffer(std::move(retained));
// The first frame is now the candidate for recycling. Since it was marked as
// not recyclable, we should get nothing.
VerifyAdvance(buffer, 4, false);
IntRect recycleRect;
EXPECT_FALSE(buffer.Recycle().empty());
RawAccessFrameRef frameRef = buffer.RecycleFrame(recycleRect);
EXPECT_FALSE(frameRef);
EXPECT_TRUE(recycleRect.IsEmpty());
EXPECT_TRUE(buffer.Recycle().empty());
// Insert a recyclable partial frame. Its dirty rect shouldn't matter since
// the previous frame was not recyclable.
frame = CreateEmptyFrame(kImageSize, IntRect(0, 0, 25, 25));
status = buffer.Insert(std::move(frame));
EXPECT_EQ(AnimationFrameBuffer::InsertStatus::YIELD, status);
VerifyAdvance(buffer, 5, true);
EXPECT_FALSE(buffer.Recycle().empty());
frameRef = buffer.RecycleFrame(recycleRect);
EXPECT_FALSE(frameRef);
EXPECT_TRUE(recycleRect.IsEmpty());
EXPECT_TRUE(buffer.Recycle().empty());
// Insert a recyclable partial frame. Its dirty rect should match the recycle
// rect since it is the only frame in the buffer.
frame = CreateEmptyFrame(kImageSize, IntRect(25, 0, 50, 50));
status = buffer.Insert(std::move(frame));
EXPECT_EQ(AnimationFrameBuffer::InsertStatus::YIELD, status);
VerifyAdvance(buffer, 6, true);
EXPECT_FALSE(buffer.Recycle().empty());
frameRef = buffer.RecycleFrame(recycleRect);
EXPECT_TRUE(frameRef);
EXPECT_EQ(IntRect(25, 0, 50, 50), recycleRect);
EXPECT_TRUE(buffer.Recycle().empty());
// Insert the last frame and mark us as complete. The next recycled frame is
// producing the first frame again, so we should use the first frame refresh
// area instead of its dirty rect.
frame = CreateEmptyFrame(kImageSize, IntRect(10, 10, 60, 10));
status = buffer.Insert(std::move(frame));
EXPECT_EQ(AnimationFrameBuffer::InsertStatus::YIELD, status);
bool continueDecoding = buffer.MarkComplete(IntRect(0, 0, 75, 50));
EXPECT_FALSE(continueDecoding);
VerifyAdvance(buffer, 7, true);
EXPECT_FALSE(buffer.Recycle().empty());
frameRef = buffer.RecycleFrame(recycleRect);
EXPECT_TRUE(frameRef);
EXPECT_EQ(IntRect(0, 0, 75, 50), recycleRect);
EXPECT_TRUE(buffer.Recycle().empty());
// Now let's reinsert the first frame. The recycle rect should still be the
// first frame refresh area instead of the dirty rect of the first frame (e.g.
// the full frame).
frame = CreateEmptyFrame(kImageSize, IntRect(IntPoint(0, 0), kImageSize), false);
status = buffer.Insert(std::move(frame));
EXPECT_EQ(AnimationFrameBuffer::InsertStatus::YIELD, status);
VerifyAdvance(buffer, 0, true);
EXPECT_FALSE(buffer.Recycle().empty());
frameRef = buffer.RecycleFrame(recycleRect);
EXPECT_TRUE(frameRef);
EXPECT_EQ(IntRect(0, 0, 75, 50), recycleRect);
EXPECT_TRUE(buffer.Recycle().empty());
}

Просмотреть файл

@ -0,0 +1,147 @@
// This file was autogenerated by binjs_generate_spidermonkey,
// please DO NOT EDIT BY HAND.
/* -*- 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/. */
// To generate this file, see the documentation in
// js/src/frontend/binsource/README.md.
#ifndef frontend_BinASTEnum_h
#define frontend_BinASTEnum_h
namespace js {
namespace frontend {
namespace binast {
// ----- Declaring string enums (by lexicographical order)
enum class AssertedDeclaredKind {
// "var"
Var,
// "non-const lexical"
NonConstLexical,
// "const lexical"
ConstLexical,
};
enum class BinaryOperator {
// ","
Comma,
// "||"
LogicalOr,
// "&&"
LogicalAnd,
// "|"
BitOr,
// "^"
BitXor,
// "&"
BitAnd,
// "=="
Eq,
// "!="
Neq,
// "==="
StrictEq,
// "!=="
StrictNeq,
// "<"
LessThan,
// "<="
LeqThan,
// ">"
GreaterThan,
// ">="
GeqThan,
// "in"
In,
// "instanceof"
Instanceof,
// "<<"
Lsh,
// ">>"
Rsh,
// ">>>"
Ursh,
// "+"
Plus,
// "-"
Minus,
// "*"
Mul,
// "/"
Div,
// "%"
Mod,
// "**"
Pow,
};
enum class CompoundAssignmentOperator {
// "+="
PlusAssign,
// "-="
MinusAssign,
// "*="
MulAssign,
// "/="
DivAssign,
// "%="
ModAssign,
// "**="
PowAssign,
// "<<="
LshAssign,
// ">>="
RshAssign,
// ">>>="
UrshAssign,
// "|="
BitOrAssign,
// "^="
BitXorAssign,
// "&="
BitAndAssign,
};
enum class UnaryOperator {
// "+"
Plus,
// "-"
Minus,
// "!"
Not,
// "~"
BitNot,
// "typeof"
Typeof,
// "void"
Void,
// "delete"
Delete,
};
enum class UpdateOperator {
// "++"
Incr,
// "--"
Decr,
};
enum class VariableDeclarationKind {
// "var"
Var,
// "let"
Let,
// "const"
Const,
};
} // namespace binast
} // namespace frontend
} // namespace js
#endif // frontend_BinASTEnum_h

Просмотреть файл

@ -9,6 +9,8 @@
// To generate this file, see the documentation in
// js/src/frontend/binsource/README.md.
#include "frontend/BinASTParser.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/Casting.h"
#include "mozilla/Maybe.h"
@ -17,7 +19,6 @@
#include "mozilla/Vector.h"
#include "frontend/BinSource-macros.h"
#include "frontend/BinSource.h"
#include "frontend/BinTokenReaderTester.h"
#include "frontend/FullParseHandler.h"
#include "frontend/ParseNode.h"
@ -2954,7 +2955,7 @@ BinASTParser<Tok>::parseInterfaceGetterContents(const size_t start, const BinKin
(void) isThisCaptured;
MOZ_TRY(parseAssertedVarScope());
BINJS_TRY_DECL(params, new_<ListNode>(ParseNodeKind::ParamsBody, tokenizer_->pos(start)));
BINJS_TRY_DECL(params, this->template new_<ListNode>(ParseNodeKind::ParamsBody, tokenizer_->pos(start)));
BINJS_MOZ_TRY_DECL(body, parseFunctionBody());
*paramsOut = params;
@ -3494,7 +3495,7 @@ BinASTParser<Tok>::parseInterfaceSetterContents(const size_t start, const BinKin
&positionalParams));
BINJS_MOZ_TRY_DECL(param, parseParameter());
BINJS_TRY_DECL(params, new_<ListNode>(ParseNodeKind::ParamsBody, param->pn_pos));
BINJS_TRY_DECL(params, this->template new_<ListNode>(ParseNodeKind::ParamsBody, param->pn_pos));
factory_.addList(params, param);
MOZ_TRY(checkPositionalParameterIndices(positionalParams, params));
MOZ_TRY(parseAssertedVarScope());
@ -4516,7 +4517,7 @@ BinASTParser<Tok>::parseListOfParameter()
const auto start = tokenizer_->offset();
MOZ_TRY(tokenizer_->enterList(length, guard));
BINJS_TRY_DECL(result, new_<ListNode>(ParseNodeKind::ParamsBody, tokenizer_->pos(start)));
BINJS_TRY_DECL(result, this->template new_<ListNode>(ParseNodeKind::ParamsBody, tokenizer_->pos(start)));
for (uint32_t i = 0; i < length; ++i) {
BINJS_MOZ_TRY_DECL(item, parseParameter());

Просмотреть файл

@ -0,0 +1,353 @@
// This file was autogenerated by binjs_generate_spidermonkey,
// please DO NOT EDIT BY HAND.
/* -*- 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/. */
// To generate this file, see the documentation in
// js/src/frontend/binsource/README.md.
#ifndef frontend_BinASTParser_h
#define frontend_BinASTParser_h
#include "mozilla/Maybe.h"
#include "frontend/BCEParserHandle.h"
#include "frontend/BinASTParserPerTokenizer.h"
#include "frontend/BinToken.h"
#include "frontend/BinTokenReaderMultipart.h"
#include "frontend/BinTokenReaderTester.h"
#include "frontend/FullParseHandler.h"
#include "frontend/ParseContext.h"
#include "frontend/ParseNode.h"
#include "frontend/SharedContext.h"
#include "js/CompileOptions.h"
#include "js/GCHashTable.h"
#include "js/GCVector.h"
#include "js/Result.h"
namespace js {
namespace frontend {
template<typename Tok>
class BinASTParser : public BinASTParserPerTokenizer<Tok>
{
public:
using Base = BinASTParserPerTokenizer<Tok>;
using Tokenizer = Tok;
using BinFields = typename Tokenizer::BinFields;
using AutoList = typename Tokenizer::AutoList;
using AutoTaggedTuple = typename Tokenizer::AutoTaggedTuple;
using AutoTuple = typename Tokenizer::AutoTuple;
using Chars = typename Tokenizer::Chars;
public:
// Auto-generated types.
using AssertedDeclaredKind = binast::AssertedDeclaredKind;
using BinaryOperator = binast::BinaryOperator;
using CompoundAssignmentOperator = binast::CompoundAssignmentOperator;
using UnaryOperator = binast::UnaryOperator;
using UpdateOperator = binast::UpdateOperator;
using VariableDeclarationKind = binast::VariableDeclarationKind;
public:
// BinASTParserPerTokenizer types.
using AssertedScopeKind = typename Base::AssertedScopeKind;
public:
BinASTParser(JSContext* cx, LifoAlloc& alloc, UsedNameTracker& usedNames,
const JS::ReadOnlyCompileOptions& options,
HandleScriptSourceObject sourceObject,
Handle<LazyScript*> lazyScript = nullptr)
: BinASTParserPerTokenizer<Tok>(cx, alloc, usedNames, options, sourceObject, lazyScript)
{}
~BinASTParser()
{}
protected:
// BinASTParserBase fields.
using Base::cx_;
using Base::alloc_;
using Base::usedNames_;
using Base::sourceObject_;
using Base::parseContext_;
using Base::factory_;
protected:
// BinASTParserPerTokenizer types.
using AutoVariableDeclarationKind = typename Base::AutoVariableDeclarationKind;
protected:
// BinASTParserPerTokenizer fields.
using Base::tokenizer_;
using Base::variableDeclarationKind_;
protected:
// BinASTParserPerTokenizer methods.
using Base::raiseInvalidClosedVar;
using Base::raiseMissingVariableInAssertedScope;
using Base::raiseMissingDirectEvalInAssertedScope;
using Base::raiseInvalidKind;
using Base::raiseInvalidVariant;
using Base::raiseMissingField;
using Base::raiseEmpty;
using Base::raiseOOM;
using Base::raiseError;
using Base::makeEmptyFunctionNode;
using Base::buildFunction;
using Base::buildFunctionBox;
using Base::addScopeName;
using Base::captureFunctionName;
using Base::getDeclaredScope;
using Base::getBoundScope;
using Base::checkBinding;
using Base::checkPositionalParameterIndices;
using Base::checkFunctionLength;
using Base::checkClosedVars;
using Base::prependDirectivesToBody;
using Base::forceStrictIfNecessary;
public:
// ----- Sums of interfaces (by lexicographical order)
// `ParseNode*` may never be nullptr
JS::Result<Ok> parseAssertedMaybePositionalParameterName(
AssertedScopeKind scopeKind,
MutableHandle<GCVector<JSAtom*>> positionalParams);
JS::Result<ParseNode*> parseAssignmentTarget();
JS::Result<ParseNode*> parseBinding();
JS::Result<ParseNode*> parseExpression();
JS::Result<ParseNode*> parseExpressionOrSuper();
JS::Result<ParseNode*> parseForInOfBindingOrAssignmentTarget();
JS::Result<ParseNode*> parseObjectProperty();
JS::Result<ParseNode*> parseParameter();
JS::Result<ParseNode*> parseProgram();
JS::Result<ParseNode*> parsePropertyName();
JS::Result<ParseNode*> parseSimpleAssignmentTarget();
JS::Result<ParseNode*> parseSpreadElementOrExpression();
JS::Result<ParseNode*> parseStatement();
JS::Result<Ok> parseSumAssertedMaybePositionalParameterName(const size_t start, const BinKind kind, const BinFields& fields,
AssertedScopeKind scopeKind,
MutableHandle<GCVector<JSAtom*>> positionalParams);
JS::Result<ParseNode*> parseSumAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseSumBinding(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseSumExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseSumExpressionOrSuper(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseSumForInOfBindingOrAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseSumObjectProperty(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseSumParameter(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseSumProgram(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseSumPropertyName(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseSumSimpleAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseSumSpreadElementOrExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseSumStatement(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseSumVariableDeclarationOrExpression(const size_t start, const BinKind kind, const BinFields& fields);
// ----- Interfaces (by lexicographical order)
// `ParseNode*` may never be nullptr
JS::Result<Ok> parseAssertedBlockScope();
JS::Result<Ok> parseAssertedBoundName(
AssertedScopeKind scopeKind);
JS::Result<Ok> parseAssertedBoundNamesScope();
JS::Result<Ok> parseAssertedDeclaredName(
AssertedScopeKind scopeKind);
JS::Result<Ok> parseAssertedParameterScope(
MutableHandle<GCVector<JSAtom*>> positionalParams);
JS::Result<Ok> parseAssertedScriptGlobalScope();
JS::Result<Ok> parseAssertedVarScope();
JS::Result<ParseNode*> parseBindingIdentifier();
JS::Result<ParseNode*> parseBlock();
JS::Result<LexicalScopeNode*> parseCatchClause();
JS::Result<ParseNode*> parseDirective();
JS::Result<ListNode*> parseFormalParameters();
JS::Result<Ok> parseFunctionExpressionContents(
uint32_t funLength,
ListNode** paramsOut,
ListNode** bodyOut);
JS::Result<Ok> parseFunctionOrMethodContents(
uint32_t funLength,
ListNode** paramsOut,
ListNode** bodyOut);
JS::Result<Ok> parseGetterContents(
uint32_t funLength,
ListNode** paramsOut,
ListNode** bodyOut);
JS::Result<ParseNode*> parseIdentifierExpression();
JS::Result<Ok> parseSetterContents(
uint32_t funLength,
ListNode** paramsOut,
ListNode** bodyOut);
JS::Result<CaseClause*> parseSwitchCase();
JS::Result<ParseNode*> parseSwitchDefault();
JS::Result<ParseNode*> parseVariableDeclarator();
JS::Result<ParseNode*> parseInterfaceArrayAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceArrayBinding(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceArrayExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<Ok> parseInterfaceAssertedBlockScope(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<Ok> parseInterfaceAssertedBoundName(const size_t start, const BinKind kind, const BinFields& fields,
AssertedScopeKind scopeKind);
JS::Result<Ok> parseInterfaceAssertedBoundNamesScope(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<Ok> parseInterfaceAssertedDeclaredName(const size_t start, const BinKind kind, const BinFields& fields,
AssertedScopeKind scopeKind);
JS::Result<Ok> parseInterfaceAssertedParameterScope(const size_t start, const BinKind kind, const BinFields& fields,
MutableHandle<GCVector<JSAtom*>> positionalParams);
JS::Result<Ok> parseInterfaceAssertedPositionalParameterName(const size_t start, const BinKind kind, const BinFields& fields,
AssertedScopeKind scopeKind,
MutableHandle<GCVector<JSAtom*>> positionalParams);
JS::Result<Ok> parseInterfaceAssertedScriptGlobalScope(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<Ok> parseInterfaceAssertedVarScope(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceAssignmentExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceAssignmentTargetIdentifier(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceAwaitExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceBinaryExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceBindingIdentifier(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceBindingWithInitializer(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceBlock(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceBreakStatement(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceCallExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<LexicalScopeNode*> parseInterfaceCatchClause(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceClassDeclaration(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceClassExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceCompoundAssignmentExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceComputedMemberAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceComputedMemberExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceComputedPropertyName(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceConditionalExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceContinueStatement(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceDataProperty(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceDebuggerStatement(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceDirective(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceDoWhileStatement(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceEagerArrowExpressionWithExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceEagerArrowExpressionWithFunctionBody(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceEagerFunctionDeclaration(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceEagerFunctionExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceEagerGetter(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceEagerMethod(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceEagerSetter(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceEmptyStatement(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceExpressionStatement(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceForInOfBinding(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceForInStatement(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceForOfStatement(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceForStatement(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ListNode*> parseInterfaceFormalParameters(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<Ok> parseInterfaceFunctionExpressionContents(const size_t start, const BinKind kind, const BinFields& fields,
uint32_t funLength,
ListNode** paramsOut,
ListNode** bodyOut);
JS::Result<Ok> parseInterfaceFunctionOrMethodContents(const size_t start, const BinKind kind, const BinFields& fields,
uint32_t funLength,
ListNode** paramsOut,
ListNode** bodyOut);
JS::Result<Ok> parseInterfaceGetterContents(const size_t start, const BinKind kind, const BinFields& fields,
uint32_t funLength,
ListNode** paramsOut,
ListNode** bodyOut);
JS::Result<ParseNode*> parseInterfaceIdentifierExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceIfStatement(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceLabelledStatement(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceLazyArrowExpressionWithExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceLazyArrowExpressionWithFunctionBody(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceLazyFunctionDeclaration(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceLazyFunctionExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceLazyGetter(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceLazyMethod(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceLazySetter(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceLiteralBooleanExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceLiteralInfinityExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceLiteralNullExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceLiteralNumericExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceLiteralPropertyName(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceLiteralRegExpExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceLiteralStringExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceModule(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceNewExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceNewTargetExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceObjectAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceObjectBinding(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceObjectExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceReturnStatement(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceScript(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<Ok> parseInterfaceSetterContents(const size_t start, const BinKind kind, const BinFields& fields,
uint32_t funLength,
ListNode** paramsOut,
ListNode** bodyOut);
JS::Result<ParseNode*> parseInterfaceShorthandProperty(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceSpreadElement(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceStaticMemberAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceStaticMemberExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceSuper(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<CaseClause*> parseInterfaceSwitchCase(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceSwitchDefault(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceSwitchStatement(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceSwitchStatementWithDefault(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceTemplateExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceThisExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceThrowStatement(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceTryCatchStatement(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceTryFinallyStatement(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceUnaryExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceUpdateExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceVariableDeclaration(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceVariableDeclarator(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceWhileStatement(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceWithStatement(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceYieldExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceYieldStarExpression(const size_t start, const BinKind kind, const BinFields& fields);
// ----- String enums (by lexicographical order)
JS::Result<typename BinASTParser<Tok>::AssertedDeclaredKind> parseAssertedDeclaredKind();
JS::Result<typename BinASTParser<Tok>::BinaryOperator> parseBinaryOperator();
JS::Result<typename BinASTParser<Tok>::CompoundAssignmentOperator> parseCompoundAssignmentOperator();
JS::Result<typename BinASTParser<Tok>::UnaryOperator> parseUnaryOperator();
JS::Result<typename BinASTParser<Tok>::UpdateOperator> parseUpdateOperator();
JS::Result<typename BinASTParser<Tok>::VariableDeclarationKind> parseVariableDeclarationKind();
// ----- Lists (by lexicographical order)
JS::Result<ParseNode*> parseArguments();
JS::Result<ListNode*> parseFunctionBody();
JS::Result<Ok> parseListOfAssertedBoundName(
AssertedScopeKind scopeKind);
JS::Result<Ok> parseListOfAssertedDeclaredName(
AssertedScopeKind scopeKind);
JS::Result<Ok> parseListOfAssertedMaybePositionalParameterName(
AssertedScopeKind scopeKind,
MutableHandle<GCVector<JSAtom*>> positionalParams);
JS::Result<ListNode*> parseListOfDirective();
JS::Result<ListNode*> parseListOfObjectProperty();
JS::Result<ListNode*> parseListOfOptionalSpreadElementOrExpression();
JS::Result<ListNode*> parseListOfParameter();
JS::Result<ListNode*> parseListOfStatement();
JS::Result<ListNode*> parseListOfSwitchCase();
JS::Result<ListNode*> parseListOfVariableDeclarator();
// ----- Default values (by lexicographical order)
JS::Result<ParseNode*> parseOptionalBinding();
JS::Result<ParseNode*> parseOptionalBindingIdentifier();
JS::Result<LexicalScopeNode*> parseOptionalCatchClause();
JS::Result<ParseNode*> parseOptionalExpression();
JS::Result<ParseNode*> parseOptionalSpreadElementOrExpression();
JS::Result<ParseNode*> parseOptionalStatement();
JS::Result<ParseNode*> parseOptionalVariableDeclarationOrExpression();
};
extern template class BinASTParser<BinTokenReaderMultipart>;
extern template class BinASTParser<BinTokenReaderTester>;
} // namespace frontend
} // namespace js
#endif // frontend_BinASTParser_h

Просмотреть файл

@ -0,0 +1,61 @@
/* -*- 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 "frontend/BinASTParserBase.h"
#include "vm/JSContext-inl.h"
namespace js {
namespace frontend {
using UsedNamePtr = UsedNameTracker::UsedNameMap::Ptr;
BinASTParserBase::BinASTParserBase(JSContext* cx, LifoAlloc& alloc, UsedNameTracker& usedNames,
HandleScriptSourceObject sourceObject,
Handle<LazyScript*> lazyScript)
: AutoGCRooter(cx, AutoGCRooter::Tag::BinParser)
, cx_(cx)
, alloc_(alloc)
, traceListHead_(nullptr)
, usedNames_(usedNames)
, nodeAlloc_(cx, alloc)
, keepAtoms_(cx)
, sourceObject_(cx, sourceObject)
, lazyScript_(cx, lazyScript)
, parseContext_(nullptr)
, factory_(cx, alloc, nullptr, SourceKind::Binary)
{
MOZ_ASSERT_IF(lazyScript, lazyScript->isBinAST());
cx->frontendCollectionPool().addActiveCompilation();
tempPoolMark_ = alloc.mark();
}
BinASTParserBase::~BinASTParserBase()
{
alloc_.release(tempPoolMark_);
/*
* The parser can allocate enormous amounts of memory for large functions.
* Eagerly free the memory now (which otherwise won't be freed until the
* next GC) to avoid unnecessary OOMs.
*/
alloc_.freeAllIfHugeAndUnused();
cx_->frontendCollectionPool().removeActiveCompilation();
}
bool
BinASTParserBase::hasUsedName(HandlePropertyName name)
{
if (UsedNamePtr p = usedNames_.lookup(name)) {
return p->value().isUsedInScript(parseContext_->scriptId());
}
return false;
}
} // namespace frontend
} // namespace js

Просмотреть файл

@ -0,0 +1,89 @@
/* -*- 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/. */
#ifndef frontend_BinASTParserBase_h
#define frontend_BinASTParserBase_h
#include <stddef.h>
#include "ds/LifoAlloc.h"
#include "frontend/BinTokenReaderMultipart.h"
#include "frontend/BinTokenReaderTester.h"
#include "frontend/FullParseHandler.h"
#include "frontend/ParseContext.h"
#include "frontend/ParseNode.h"
#include "frontend/SharedContext.h"
#include "js/RootingAPI.h"
#include "js/TracingAPI.h"
#include "js/Utility.h"
#include "vm/JSContext.h"
#include "vm/JSScript.h"
namespace js {
namespace frontend {
class BinASTParserBase : private JS::AutoGCRooter
{
public:
BinASTParserBase(JSContext* cx, LifoAlloc& alloc, UsedNameTracker& usedNames,
HandleScriptSourceObject sourceObject, Handle<LazyScript*> lazyScript);
~BinASTParserBase();
public:
// Names
bool hasUsedName(HandlePropertyName name);
// --- GC.
virtual void doTrace(JSTracer* trc) {}
void trace(JSTracer* trc) {
TraceListNode::TraceList(trc, traceListHead_);
doTrace(trc);
}
public:
ParseNode* allocParseNode(size_t size) {
MOZ_ASSERT(size == sizeof(ParseNode));
return static_cast<ParseNode*>(nodeAlloc_.allocNode());
}
JS_DECLARE_NEW_METHODS(new_, allocParseNode, inline)
// Needs access to AutoGCRooter.
friend void TraceBinParser(JSTracer* trc, JS::AutoGCRooter* parser);
protected:
JSContext* cx_;
// ---- Memory-related stuff
protected:
LifoAlloc& alloc_;
TraceListNode* traceListHead_;
UsedNameTracker& usedNames_;
private:
LifoAlloc::Mark tempPoolMark_;
ParseNodeAllocator nodeAlloc_;
// ---- Parsing-related stuff
protected:
// Root atoms and objects allocated for the parse tree.
AutoKeepAtoms keepAtoms_;
RootedScriptSourceObject sourceObject_;
Rooted<LazyScript*> lazyScript_;
ParseContext* parseContext_;
FullParseHandler factory_;
friend class BinParseContext;
};
} // namespace frontend
} // namespace js
#endif // frontend_BinASTParserBase_h

Просмотреть файл

@ -4,7 +4,7 @@
* 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 "frontend/BinSource.h"
#include "frontend/BinASTParserPerTokenizer.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/Casting.h"
@ -14,6 +14,7 @@
#include "mozilla/ScopeExit.h"
#include "mozilla/Vector.h"
#include "frontend/BinASTParser.h"
#include "frontend/BinSource-macros.h"
#include "frontend/BinTokenReaderTester.h"
#include "frontend/FullParseHandler.h"
@ -77,51 +78,19 @@ namespace frontend {
using UsedNamePtr = UsedNameTracker::UsedNameMap::Ptr;
BinASTParserBase::BinASTParserBase(JSContext* cx, LifoAlloc& alloc, UsedNameTracker& usedNames,
HandleScriptSourceObject sourceObject, Handle<LazyScript*> lazyScript)
: AutoGCRooter(cx, AutoGCRooter::Tag::BinParser)
, cx_(cx)
, alloc_(alloc)
, traceListHead_(nullptr)
, usedNames_(usedNames)
, nodeAlloc_(cx, alloc)
, keepAtoms_(cx)
, sourceObject_(cx, sourceObject)
, lazyScript_(cx, lazyScript)
, parseContext_(nullptr)
, factory_(cx, alloc, nullptr, SourceKind::Binary)
{
MOZ_ASSERT_IF(lazyScript, lazyScript->isBinAST());
cx->frontendCollectionPool().addActiveCompilation();
tempPoolMark_ = alloc.mark();
}
BinASTParserBase::~BinASTParserBase()
{
alloc_.release(tempPoolMark_);
/*
* The parser can allocate enormous amounts of memory for large functions.
* Eagerly free the memory now (which otherwise won't be freed until the
* next GC) to avoid unnecessary OOMs.
*/
alloc_.freeAllIfHugeAndUnused();
cx_->frontendCollectionPool().removeActiveCompilation();
}
// ------------- Toplevel constructions
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parse(GlobalSharedContext* globalsc, const Vector<uint8_t>& data,
BinASTSourceMetadata** metadataPtr)
BinASTParserPerTokenizer<Tok>::parse(GlobalSharedContext* globalsc, const Vector<uint8_t>& data,
BinASTSourceMetadata** metadataPtr)
{
return parse(globalsc, data.begin(), data.length(), metadataPtr);
}
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parse(GlobalSharedContext* globalsc, const uint8_t* start, const size_t length,
BinASTSourceMetadata** metadataPtr)
BinASTParserPerTokenizer<Tok>::parse(GlobalSharedContext* globalsc, const uint8_t* start,
const size_t length,
BinASTSourceMetadata** metadataPtr)
{
auto result = parseAux(globalsc, start, length, metadataPtr);
poison(); // Make sure that the parser is never used again accidentally.
@ -130,9 +99,9 @@ BinASTParser<Tok>::parse(GlobalSharedContext* globalsc, const uint8_t* start, co
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseAux(GlobalSharedContext* globalsc,
const uint8_t* start, const size_t length,
BinASTSourceMetadata** metadataPtr)
BinASTParserPerTokenizer<Tok>::parseAux(GlobalSharedContext* globalsc,
const uint8_t* start, const size_t length,
BinASTSourceMetadata** metadataPtr)
{
MOZ_ASSERT(globalsc);
@ -151,7 +120,7 @@ BinASTParser<Tok>::parseAux(GlobalSharedContext* globalsc,
MOZ_TRY(tokenizer_->readHeader());
ParseNode* result(nullptr);
MOZ_TRY_VAR(result, parseProgram());
MOZ_TRY_VAR(result, asFinalParser()->parseProgram());
mozilla::Maybe<GlobalScope::Data*> bindings = NewGlobalScopeData(cx_, varScope, alloc_,
parseContext_);
@ -168,7 +137,8 @@ BinASTParser<Tok>::parseAux(GlobalSharedContext* globalsc,
}
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseLazyFunction(ScriptSource* scriptSource, const size_t firstOffset)
BinASTParserPerTokenizer<Tok>::parseLazyFunction(ScriptSource* scriptSource,
const size_t firstOffset)
{
MOZ_ASSERT(lazyScript_);
MOZ_ASSERT(scriptSource->length() > firstOffset);
@ -203,9 +173,9 @@ BinASTParser<Tok>::parseLazyFunction(ScriptSource* scriptSource, const size_t fi
BINJS_TRY(lexicalScope.init(parseContext_));
ListNode* params;
ListNode* tmpBody;
auto parseFunc = isExpr ? &BinASTParser::parseFunctionExpressionContents
: &BinASTParser::parseFunctionOrMethodContents;
MOZ_TRY((this->*parseFunc)(func->nargs(), &params, &tmpBody));
auto parseFunc = isExpr ? &FinalParser::parseFunctionExpressionContents
: &FinalParser::parseFunctionOrMethodContents;
MOZ_TRY((asFinalParser()->*parseFunc)(func->nargs(), &params, &tmpBody));
BINJS_TRY_DECL(lexicalScopeData, NewLexicalScopeData(cx_, lexicalScope, alloc_, parseContext_));
BINJS_TRY_DECL(body, factory_.newLexicalScope(*lexicalScopeData, tmpBody));
@ -215,7 +185,7 @@ BinASTParser<Tok>::parseLazyFunction(ScriptSource* scriptSource, const size_t fi
}
template<typename Tok> void
BinASTParser<Tok>::forceStrictIfNecessary(SharedContext* sc, ListNode* directives)
BinASTParserPerTokenizer<Tok>::forceStrictIfNecessary(SharedContext* sc, ListNode* directives)
{
JSAtom* useStrict = cx_->names().useStrict;
@ -228,10 +198,10 @@ BinASTParser<Tok>::forceStrictIfNecessary(SharedContext* sc, ListNode* directive
}
template<typename Tok> JS::Result<FunctionBox*>
BinASTParser<Tok>::buildFunctionBox(GeneratorKind generatorKind,
FunctionAsyncKind functionAsyncKind,
FunctionSyntaxKind syntax,
ParseNode* name)
BinASTParserPerTokenizer<Tok>::buildFunctionBox(GeneratorKind generatorKind,
FunctionAsyncKind functionAsyncKind,
FunctionSyntaxKind syntax,
ParseNode* name)
{
MOZ_ASSERT_IF(!parseContext_, lazyScript_);
@ -288,7 +258,8 @@ BinASTParser<Tok>::buildFunctionBox(GeneratorKind generatorKind,
}
template<typename Tok> JS::Result<CodeNode*>
BinASTParser<Tok>::makeEmptyFunctionNode(const size_t start, const BinKind kind, FunctionBox* funbox)
BinASTParserPerTokenizer<Tok>::makeEmptyFunctionNode(const size_t start, const BinKind kind,
FunctionBox* funbox)
{
// LazyScript compilation requires basically none of the fields filled out.
TokenPos pos = tokenizer_->pos(start);
@ -305,8 +276,9 @@ BinASTParser<Tok>::makeEmptyFunctionNode(const size_t start, const BinKind kind,
}
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::buildFunction(const size_t start, const BinKind kind, ParseNode* name,
ListNode* params, ParseNode* body, FunctionBox* funbox)
BinASTParserPerTokenizer<Tok>::buildFunction(const size_t start, const BinKind kind,
ParseNode* name, ListNode* params, ParseNode* body,
FunctionBox* funbox)
{
// Set the argument count for building argument packets. Function.length is handled
// by setting the appropriate funbox field during argument parsing.
@ -404,9 +376,9 @@ BinASTParser<Tok>::buildFunction(const size_t start, const BinKind kind, ParseNo
}
template<typename Tok> JS::Result<Ok>
BinASTParser<Tok>::addScopeName(AssertedScopeKind scopeKind, HandleAtom name,
ParseContext::Scope* scope, DeclarationKind declKind,
bool isCaptured, bool allowDuplicateName)
BinASTParserPerTokenizer<Tok>::addScopeName(AssertedScopeKind scopeKind, HandleAtom name,
ParseContext::Scope* scope, DeclarationKind declKind,
bool isCaptured, bool allowDuplicateName)
{
auto ptr = scope->lookupDeclaredNameForAdd(name);
if (ptr) {
@ -429,7 +401,7 @@ BinASTParser<Tok>::addScopeName(AssertedScopeKind scopeKind, HandleAtom name,
}
template<typename Tok> void
BinASTParser<Tok>::captureFunctionName()
BinASTParserPerTokenizer<Tok>::captureFunctionName()
{
MOZ_ASSERT(parseContext_->isFunctionBox());
MOZ_ASSERT(parseContext_->functionBox()->function()->isNamedLambda());
@ -443,8 +415,10 @@ BinASTParser<Tok>::captureFunctionName()
}
template<typename Tok> JS::Result<Ok>
BinASTParser<Tok>::getDeclaredScope(AssertedScopeKind scopeKind, AssertedDeclaredKind kind,
ParseContext::Scope*& scope, DeclarationKind& declKind)
BinASTParserPerTokenizer<Tok>::getDeclaredScope(AssertedScopeKind scopeKind,
AssertedDeclaredKind kind,
ParseContext::Scope*& scope,
DeclarationKind& declKind)
{
MOZ_ASSERT(scopeKind == AssertedScopeKind::Block ||
scopeKind == AssertedScopeKind::Global ||
@ -471,8 +445,9 @@ BinASTParser<Tok>::getDeclaredScope(AssertedScopeKind scopeKind, AssertedDeclare
}
template<typename Tok> JS::Result<Ok>
BinASTParser<Tok>::getBoundScope(AssertedScopeKind scopeKind,
ParseContext::Scope*& scope, DeclarationKind& declKind)
BinASTParserPerTokenizer<Tok>::getBoundScope(AssertedScopeKind scopeKind,
ParseContext::Scope*& scope,
DeclarationKind& declKind)
{
MOZ_ASSERT(scopeKind == AssertedScopeKind::Catch ||
scopeKind == AssertedScopeKind::Parameter);
@ -495,7 +470,7 @@ BinASTParser<Tok>::getBoundScope(AssertedScopeKind scopeKind,
}
template<typename Tok> JS::Result<Ok>
BinASTParser<Tok>::checkBinding(JSAtom* name)
BinASTParserPerTokenizer<Tok>::checkBinding(JSAtom* name)
{
// Check that the variable appears in the corresponding scope.
ParseContext::Scope& scope =
@ -514,8 +489,8 @@ BinASTParser<Tok>::checkBinding(JSAtom* name)
// Binary AST (revision 8eab67e0c434929a66ff6abe99ff790bca087dda)
// 3.1.5 CheckPositionalParameterIndices.
template<typename Tok> JS::Result<Ok>
BinASTParser<Tok>::checkPositionalParameterIndices(Handle<GCVector<JSAtom*>> positionalParams,
ListNode* params)
BinASTParserPerTokenizer<Tok>::checkPositionalParameterIndices(Handle<GCVector<JSAtom*>> positionalParams,
ListNode* params)
{
// positionalParams should have the corresponding entry up to the last
// positional parameter.
@ -601,7 +576,7 @@ BinASTParser<Tok>::checkPositionalParameterIndices(Handle<GCVector<JSAtom*>> pos
// Binary AST (revision 8eab67e0c434929a66ff6abe99ff790bca087dda)
// 3.1.13 CheckFunctionLength.
template<typename Tok> JS::Result<Ok>
BinASTParser<Tok>::checkFunctionLength(uint32_t expectedLength)
BinASTParserPerTokenizer<Tok>::checkFunctionLength(uint32_t expectedLength)
{
if (parseContext_->functionBox()->length != expectedLength) {
return raiseError("Function length does't match");
@ -610,7 +585,7 @@ BinASTParser<Tok>::checkFunctionLength(uint32_t expectedLength)
}
template<typename Tok> JS::Result<Ok>
BinASTParser<Tok>::checkClosedVars(ParseContext::Scope& scope)
BinASTParserPerTokenizer<Tok>::checkClosedVars(ParseContext::Scope& scope)
{
for (ParseContext::Scope::BindingIter bi = scope.bindings(parseContext_); bi; bi++) {
if (UsedNamePtr p = usedNames_.lookup(bi.name())) {
@ -626,7 +601,7 @@ BinASTParser<Tok>::checkClosedVars(ParseContext::Scope& scope)
}
template<typename Tok> JS::Result<Ok>
BinASTParser<Tok>::checkFunctionClosedVars()
BinASTParserPerTokenizer<Tok>::checkFunctionClosedVars()
{
MOZ_ASSERT(parseContext_->isFunctionBox());
@ -640,7 +615,7 @@ BinASTParser<Tok>::checkFunctionClosedVars()
}
template<typename Tok> JS::Result<Ok>
BinASTParser<Tok>::prependDirectivesToBody(ListNode* body, ListNode* directives)
BinASTParserPerTokenizer<Tok>::prependDirectivesToBody(ListNode* body, ListNode* directives)
{
if (!directives) {
return Ok();
@ -656,7 +631,7 @@ BinASTParser<Tok>::prependDirectivesToBody(ListNode* body, ListNode* directives)
}
template<typename Tok> JS::Result<Ok>
BinASTParser<Tok>::prependDirectivesImpl(ListNode* body, ParseNode* directive)
BinASTParserPerTokenizer<Tok>::prependDirectivesImpl(ListNode* body, ParseNode* directive)
{
BINJS_TRY(CheckRecursionLimit(cx_));
@ -673,13 +648,13 @@ BinASTParser<Tok>::prependDirectivesImpl(ListNode* body, ParseNode* directive)
}
template<typename Tok> mozilla::GenericErrorResult<JS::Error&>
BinASTParser<Tok>::raiseInvalidClosedVar(JSAtom* name)
BinASTParserPerTokenizer<Tok>::raiseInvalidClosedVar(JSAtom* name)
{
return raiseError("Captured variable was not declared as captured");
}
template<typename Tok> mozilla::GenericErrorResult<JS::Error&>
BinASTParser<Tok>::raiseMissingVariableInAssertedScope(JSAtom* name)
BinASTParserPerTokenizer<Tok>::raiseMissingVariableInAssertedScope(JSAtom* name)
{
// For the moment, we don't trust inputs sufficiently to put the name
// in an error message.
@ -687,13 +662,13 @@ BinASTParser<Tok>::raiseMissingVariableInAssertedScope(JSAtom* name)
}
template<typename Tok> mozilla::GenericErrorResult<JS::Error&>
BinASTParser<Tok>::raiseMissingDirectEvalInAssertedScope()
BinASTParserPerTokenizer<Tok>::raiseMissingDirectEvalInAssertedScope()
{
return raiseError("Direct call to `eval` was not declared in AssertedScope");
}
template<typename Tok> mozilla::GenericErrorResult<JS::Error&>
BinASTParser<Tok>::raiseInvalidKind(const char* superKind, const BinKind kind)
BinASTParserPerTokenizer<Tok>::raiseInvalidKind(const char* superKind, const BinKind kind)
{
Sprinter out(cx_);
BINJS_TRY(out.init());
@ -702,7 +677,7 @@ BinASTParser<Tok>::raiseInvalidKind(const char* superKind, const BinKind kind)
}
template<typename Tok> mozilla::GenericErrorResult<JS::Error&>
BinASTParser<Tok>::raiseInvalidVariant(const char* kind, const BinVariant value)
BinASTParserPerTokenizer<Tok>::raiseInvalidVariant(const char* kind, const BinVariant value)
{
Sprinter out(cx_);
BINJS_TRY(out.init());
@ -712,7 +687,7 @@ BinASTParser<Tok>::raiseInvalidVariant(const char* kind, const BinVariant value)
}
template<typename Tok> mozilla::GenericErrorResult<JS::Error&>
BinASTParser<Tok>::raiseMissingField(const char* kind, const BinField field)
BinASTParserPerTokenizer<Tok>::raiseMissingField(const char* kind, const BinField field)
{
Sprinter out(cx_);
BINJS_TRY(out.init());
@ -722,7 +697,7 @@ BinASTParser<Tok>::raiseMissingField(const char* kind, const BinField field)
}
template<typename Tok> mozilla::GenericErrorResult<JS::Error&>
BinASTParser<Tok>::raiseEmpty(const char* description)
BinASTParserPerTokenizer<Tok>::raiseEmpty(const char* description)
{
Sprinter out(cx_);
BINJS_TRY(out.init());
@ -732,13 +707,13 @@ BinASTParser<Tok>::raiseEmpty(const char* description)
}
template<typename Tok> mozilla::GenericErrorResult<JS::Error&>
BinASTParser<Tok>::raiseOOM()
BinASTParserPerTokenizer<Tok>::raiseOOM()
{
return tokenizer_->raiseOOM();
}
template<typename Tok> mozilla::GenericErrorResult<JS::Error&>
BinASTParser<Tok>::raiseError(BinKind kind, const char* description)
BinASTParserPerTokenizer<Tok>::raiseError(BinKind kind, const char* description)
{
Sprinter out(cx_);
BINJS_TRY(out.init());
@ -747,19 +722,19 @@ BinASTParser<Tok>::raiseError(BinKind kind, const char* description)
}
template<typename Tok> mozilla::GenericErrorResult<JS::Error&>
BinASTParser<Tok>::raiseError(const char* description)
BinASTParserPerTokenizer<Tok>::raiseError(const char* description)
{
return tokenizer_->raiseError(description);
}
template<typename Tok> void
BinASTParser<Tok>::poison()
BinASTParserPerTokenizer<Tok>::poison()
{
tokenizer_.reset();
}
template<typename Tok> void
BinASTParser<Tok>::reportErrorNoOffsetVA(unsigned errorNumber, va_list args)
BinASTParserPerTokenizer<Tok>::reportErrorNoOffsetVA(unsigned errorNumber, va_list args)
{
ErrorMetadata metadata;
metadata.filename = getFilename();
@ -770,7 +745,7 @@ BinASTParser<Tok>::reportErrorNoOffsetVA(unsigned errorNumber, va_list args)
}
template<typename Tok> void
BinASTParser<Tok>::errorAtVA(uint32_t offset, unsigned errorNumber, va_list* args)
BinASTParserPerTokenizer<Tok>::errorAtVA(uint32_t offset, unsigned errorNumber, va_list* args)
{
ErrorMetadata metadata;
metadata.filename = getFilename();
@ -781,7 +756,9 @@ BinASTParser<Tok>::errorAtVA(uint32_t offset, unsigned errorNumber, va_list* arg
}
template<typename Tok> bool
BinASTParser<Tok>::reportExtraWarningErrorNumberVA(UniquePtr<JSErrorNotes> notes, uint32_t offset, unsigned errorNumber, va_list* args)
BinASTParserPerTokenizer<Tok>::reportExtraWarningErrorNumberVA(UniquePtr<JSErrorNotes> notes,
uint32_t offset,
unsigned errorNumber, va_list* args)
{
if (!options().extraWarningsOption) {
return true;
@ -801,16 +778,6 @@ BinASTParser<Tok>::reportExtraWarningErrorNumberVA(UniquePtr<JSErrorNotes> notes
return ReportCompileWarning(cx_, std::move(metadata), std::move(notes), JSREPORT_STRICT | JSREPORT_WARNING, errorNumber, *args);
}
bool
BinASTParserBase::hasUsedName(HandlePropertyName name)
{
if (UsedNamePtr p = usedNames_.lookup(name)) {
return p->value().isUsedInScript(parseContext_->scriptId());
}
return false;
}
void
TraceBinParser(JSTracer* trc, JS::AutoGCRooter* parser)
{
@ -819,18 +786,40 @@ TraceBinParser(JSTracer* trc, JS::AutoGCRooter* parser)
template<typename Tok>
void
BinASTParser<Tok>::doTrace(JSTracer* trc)
BinASTParserPerTokenizer<Tok>::doTrace(JSTracer* trc)
{
if (tokenizer_) {
tokenizer_->traceMetadata(trc);
}
}
template<typename Tok>
inline typename BinASTParserPerTokenizer<Tok>::FinalParser*
BinASTParserPerTokenizer<Tok>::asFinalParser()
{
// Same as GeneralParser::asFinalParser, verify the inheritance to
// make sure the static downcast works.
static_assert(mozilla::IsBaseOf<BinASTParserPerTokenizer<Tok>, FinalParser>::value,
"inheritance relationship required by the static_cast<> below");
return static_cast<FinalParser*>(this);
}
template<typename Tok>
inline const typename BinASTParserPerTokenizer<Tok>::FinalParser*
BinASTParserPerTokenizer<Tok>::asFinalParser() const
{
static_assert(mozilla::IsBaseOf<BinASTParserPerTokenizer<Tok>, FinalParser>::value,
"inheritance relationship required by the static_cast<> below");
return static_cast<const FinalParser*>(this);
}
// Force class instantiation.
// This ensures that the symbols are built, without having to export all our
// code (and its baggage of #include and macros) in the header.
template class BinASTParser<BinTokenReaderMultipart>;
template class BinASTParser<BinTokenReaderTester>;
template class BinASTParserPerTokenizer<BinTokenReaderMultipart>;
template class BinASTParserPerTokenizer<BinTokenReaderTester>;
} // namespace frontend
} // namespace js

Просмотреть файл

@ -4,8 +4,8 @@
* 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/. */
#ifndef frontend_BinSource_h
#define frontend_BinSource_h
#ifndef frontend_BinASTParserPerTokenizer_h
#define frontend_BinASTParserPerTokenizer_h
/**
* A Binary AST parser.
@ -17,6 +17,8 @@
#include "mozilla/Maybe.h"
#include "frontend/BCEParserHandle.h"
#include "frontend/BinASTEnum.h"
#include "frontend/BinASTParserBase.h"
#include "frontend/BinToken.h"
#include "frontend/BinTokenReaderMultipart.h"
#include "frontend/BinTokenReaderTester.h"
@ -33,64 +35,8 @@
namespace js {
namespace frontend {
class BinASTParserBase: private JS::AutoGCRooter
{
public:
BinASTParserBase(JSContext* cx, LifoAlloc& alloc, UsedNameTracker& usedNames,
HandleScriptSourceObject sourceObject, Handle<LazyScript*> lazyScript);
~BinASTParserBase();
public:
// Names
bool hasUsedName(HandlePropertyName name);
// --- GC.
virtual void doTrace(JSTracer* trc) {}
void trace(JSTracer* trc) {
TraceListNode::TraceList(trc, traceListHead_);
doTrace(trc);
}
public:
ParseNode* allocParseNode(size_t size) {
MOZ_ASSERT(size == sizeof(ParseNode));
return static_cast<ParseNode*>(nodeAlloc_.allocNode());
}
JS_DECLARE_NEW_METHODS(new_, allocParseNode, inline)
// Needs access to AutoGCRooter.
friend void TraceBinParser(JSTracer* trc, JS::AutoGCRooter* parser);
protected:
JSContext* cx_;
// ---- Memory-related stuff
protected:
LifoAlloc& alloc_;
TraceListNode* traceListHead_;
UsedNameTracker& usedNames_;
private:
LifoAlloc::Mark tempPoolMark_;
ParseNodeAllocator nodeAlloc_;
// ---- Parsing-related stuff
protected:
// Root atoms and objects allocated for the parse tree.
AutoKeepAtoms keepAtoms_;
RootedScriptSourceObject sourceObject_;
Rooted<LazyScript*> lazyScript_;
ParseContext* parseContext_;
FullParseHandler factory_;
friend class BinParseContext;
};
template<typename Tok>
class BinASTParser;
/**
* The parser for a Binary AST.
@ -99,7 +45,7 @@ class BinASTParserBase: private JS::AutoGCRooter
* recoverable.
*/
template<typename Tok>
class BinASTParser : public BinASTParserBase, public ErrorReporter, public BCEParserHandle
class BinASTParserPerTokenizer : public BinASTParserBase, public ErrorReporter, public BCEParserHandle
{
public:
using Tokenizer = Tok;
@ -111,14 +57,21 @@ class BinASTParser : public BinASTParserBase, public ErrorReporter, public BCEPa
using Chars = typename Tokenizer::Chars;
public:
BinASTParser(JSContext* cx, LifoAlloc& alloc, UsedNameTracker& usedNames, const JS::ReadOnlyCompileOptions& options,
HandleScriptSourceObject sourceObject, Handle<LazyScript*> lazyScript = nullptr)
// Auto-generated types.
using AssertedDeclaredKind = binast::AssertedDeclaredKind;
using VariableDeclarationKind = binast::VariableDeclarationKind;
public:
BinASTParserPerTokenizer(JSContext* cx, LifoAlloc& alloc, UsedNameTracker& usedNames,
const JS::ReadOnlyCompileOptions& options,
HandleScriptSourceObject sourceObject,
Handle<LazyScript*> lazyScript = nullptr)
: BinASTParserBase(cx, alloc, usedNames, sourceObject, lazyScript)
, options_(options)
, variableDeclarationKind_(VariableDeclarationKind::Var)
{
}
~BinASTParser()
~BinASTParserPerTokenizer()
{
}
@ -126,8 +79,9 @@ class BinASTParser : public BinASTParserBase, public ErrorReporter, public BCEPa
* Parse a buffer, returning a node (which may be nullptr) in case of success
* or Nothing() in case of error.
*
* The instance of `ParseNode` MAY NOT survive the `BinASTParser`. Indeed,
* destruction of the `BinASTParser` will also destroy the `ParseNode`.
* The instance of `ParseNode` MAY NOT survive the
* `BinASTParserPerTokenizer`. Indeed, destruction of the
* `BinASTParserPerTokenizer` will also destroy the `ParseNode`.
*
* In case of error, the parser reports the JS error.
*/
@ -139,7 +93,7 @@ class BinASTParser : public BinASTParserBase, public ErrorReporter, public BCEPa
JS::Result<ParseNode*> parseLazyFunction(ScriptSource* src, const size_t firstOffset);
private:
protected:
MOZ_MUST_USE JS::Result<ParseNode*> parseAux(GlobalSharedContext* globalsc,
const uint8_t* start, const size_t length,
BinASTSourceMetadata** metadataPtr = nullptr);
@ -176,9 +130,6 @@ class BinASTParser : public BinASTParserBase, public ErrorReporter, public BCEPa
Var,
};
// Auto-generated methods
#include "frontend/BinSource-auto.h"
// --- Auxiliary parsing functions
// Build a function object for a function-producing production. Called AFTER creating the scope.
@ -235,7 +186,7 @@ class BinASTParser : public BinASTParserBase, public ErrorReporter, public BCEPa
// directive.
void forceStrictIfNecessary(SharedContext* sc, ListNode* directives);
private: // Implement ErrorReporter
protected: // Implement ErrorReporter
const JS::ReadOnlyCompileOptions& options_;
const JS::ReadOnlyCompileOptions& options() const override {
@ -319,7 +270,7 @@ class BinASTParser : public BinASTParserBase, public ErrorReporter, public BCEPa
return this->options_.filename();
}
private: // Implement ErrorReporter
protected: // Implement ErrorReporter
mozilla::Maybe<Tokenizer> tokenizer_;
VariableDeclarationKind variableDeclarationKind_;
@ -329,7 +280,7 @@ class BinASTParser : public BinASTParserBase, public ErrorReporter, public BCEPa
// Helper class: Restore field `variableDeclarationKind` upon leaving a scope.
class MOZ_RAII AutoVariableDeclarationKind {
public:
explicit AutoVariableDeclarationKind(BinASTParser<Tok>* parser
explicit AutoVariableDeclarationKind(BinASTParserPerTokenizer<Tok>* parser
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: parser_(parser)
, kind(parser->variableDeclarationKind_)
@ -340,17 +291,27 @@ class BinASTParser : public BinASTParserBase, public ErrorReporter, public BCEPa
parser_->variableDeclarationKind_ = kind;
}
private:
BinASTParser<Tok>* parser_;
BinASTParser<Tok>::VariableDeclarationKind kind;
BinASTParserPerTokenizer<Tok>* parser_;
BinASTParserPerTokenizer<Tok>::VariableDeclarationKind kind;
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
};
private:
// Some methods in this class require access to auto-generated methods in
// BinASTParser which derives this class.
// asFinalParser methods provide the access to BinASTParser class methods
// of this instance.
using FinalParser = BinASTParser<Tok>;
inline FinalParser* asFinalParser();
inline const FinalParser* asFinalParser() const;
};
class BinParseContext : public ParseContext
{
public:
template<typename Tok>
BinParseContext(JSContext* cx, BinASTParser<Tok>* parser, SharedContext* sc,
BinParseContext(JSContext* cx, BinASTParserPerTokenizer<Tok>* parser, SharedContext* sc,
Directives* newDirectives)
: ParseContext(cx, parser->parseContext_, sc, *parser,
parser->usedNames_, newDirectives, /* isFull = */ true)
@ -358,10 +319,10 @@ class BinParseContext : public ParseContext
};
extern template class BinASTParser<BinTokenReaderMultipart>;
extern template class BinASTParser<BinTokenReaderTester>;
extern template class BinASTParserPerTokenizer<BinTokenReaderMultipart>;
extern template class BinASTParserPerTokenizer<BinTokenReaderTester>;
} // namespace frontend
} // namespace js
#endif // frontend_BinSource_h
#endif // frontend_BinASTParserPerTokenizer_h

Просмотреть файл

@ -1,319 +0,0 @@
// This file was autogenerated by binjs_generate_spidermonkey,
// please DO NOT EDIT BY HAND.
/* -*- 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/. */
// To generate this file, see the documentation in
// js/src/frontend/binsource/README.md.
// This file is meant to be included from the declaration
// of class `BinASTParser`. The include may be public or private.
// ----- Declaring string enums (by lexicographical order)
enum class AssertedDeclaredKind {
Var /* "var" */,
NonConstLexical /* "non-const lexical" */,
ConstLexical /* "const lexical" */
};
enum class BinaryOperator {
Comma /* "," */,
LogicalOr /* "||" */,
LogicalAnd /* "&&" */,
BitOr /* "|" */,
BitXor /* "^" */,
BitAnd /* "&" */,
Eq /* "==" */,
Neq /* "!=" */,
StrictEq /* "===" */,
StrictNeq /* "!==" */,
LessThan /* "<" */,
LeqThan /* "<=" */,
GreaterThan /* ">" */,
GeqThan /* ">=" */,
In /* "in" */,
Instanceof /* "instanceof" */,
Lsh /* "<<" */,
Rsh /* ">>" */,
Ursh /* ">>>" */,
Plus /* "+" */,
Minus /* "-" */,
Mul /* "*" */,
Div /* "/" */,
Mod /* "%" */,
Pow /* "**" */
};
enum class CompoundAssignmentOperator {
PlusAssign /* "+=" */,
MinusAssign /* "-=" */,
MulAssign /* "*=" */,
DivAssign /* "/=" */,
ModAssign /* "%=" */,
PowAssign /* "**=" */,
LshAssign /* "<<=" */,
RshAssign /* ">>=" */,
UrshAssign /* ">>>=" */,
BitOrAssign /* "|=" */,
BitXorAssign /* "^=" */,
BitAndAssign /* "&=" */
};
enum class UnaryOperator {
Plus /* "+" */,
Minus /* "-" */,
Not /* "!" */,
BitNot /* "~" */,
Typeof /* "typeof" */,
Void /* "void" */,
Delete /* "delete" */
};
enum class UpdateOperator {
Incr /* "++" */,
Decr /* "--" */
};
enum class VariableDeclarationKind {
Var /* "var" */,
Let /* "let" */,
Const /* "const" */
};
// ----- Sums of interfaces (by lexicographical order)
// Implementations are autogenerated
// `ParseNode*` may never be nullptr
JS::Result<Ok> parseAssertedMaybePositionalParameterName(
AssertedScopeKind scopeKind,
MutableHandle<GCVector<JSAtom*>> positionalParams);
JS::Result<ParseNode*> parseAssignmentTarget();
JS::Result<ParseNode*> parseBinding();
JS::Result<ParseNode*> parseExpression();
JS::Result<ParseNode*> parseExpressionOrSuper();
JS::Result<ParseNode*> parseForInOfBindingOrAssignmentTarget();
JS::Result<ParseNode*> parseObjectProperty();
JS::Result<ParseNode*> parseParameter();
JS::Result<ParseNode*> parseProgram();
JS::Result<ParseNode*> parsePropertyName();
JS::Result<ParseNode*> parseSimpleAssignmentTarget();
JS::Result<ParseNode*> parseSpreadElementOrExpression();
JS::Result<ParseNode*> parseStatement();
JS::Result<Ok> parseSumAssertedMaybePositionalParameterName(const size_t start, const BinKind kind, const BinFields& fields,
AssertedScopeKind scopeKind,
MutableHandle<GCVector<JSAtom*>> positionalParams);
JS::Result<ParseNode*> parseSumAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseSumBinding(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseSumExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseSumExpressionOrSuper(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseSumForInOfBindingOrAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseSumObjectProperty(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseSumParameter(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseSumProgram(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseSumPropertyName(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseSumSimpleAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseSumSpreadElementOrExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseSumStatement(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseSumVariableDeclarationOrExpression(const size_t start, const BinKind kind, const BinFields& fields);
// ----- Interfaces (by lexicographical order)
// Implementations are autogenerated
// `ParseNode*` may never be nullptr
JS::Result<Ok> parseAssertedBlockScope();
JS::Result<Ok> parseAssertedBoundName(
AssertedScopeKind scopeKind);
JS::Result<Ok> parseAssertedBoundNamesScope();
JS::Result<Ok> parseAssertedDeclaredName(
AssertedScopeKind scopeKind);
JS::Result<Ok> parseAssertedParameterScope(
MutableHandle<GCVector<JSAtom*>> positionalParams);
JS::Result<Ok> parseAssertedScriptGlobalScope();
JS::Result<Ok> parseAssertedVarScope();
JS::Result<ParseNode*> parseBindingIdentifier();
JS::Result<ParseNode*> parseBlock();
JS::Result<LexicalScopeNode*> parseCatchClause();
JS::Result<ParseNode*> parseDirective();
JS::Result<ListNode*> parseFormalParameters();
JS::Result<Ok> parseFunctionExpressionContents(
uint32_t funLength,
ListNode** paramsOut,
ListNode** bodyOut);
JS::Result<Ok> parseFunctionOrMethodContents(
uint32_t funLength,
ListNode** paramsOut,
ListNode** bodyOut);
JS::Result<Ok> parseGetterContents(
uint32_t funLength,
ListNode** paramsOut,
ListNode** bodyOut);
JS::Result<ParseNode*> parseIdentifierExpression();
JS::Result<Ok> parseSetterContents(
uint32_t funLength,
ListNode** paramsOut,
ListNode** bodyOut);
JS::Result<CaseClause*> parseSwitchCase();
JS::Result<ParseNode*> parseSwitchDefault();
JS::Result<ParseNode*> parseVariableDeclarator();
JS::Result<ParseNode*> parseInterfaceArrayAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceArrayBinding(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceArrayExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<Ok> parseInterfaceAssertedBlockScope(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<Ok> parseInterfaceAssertedBoundName(const size_t start, const BinKind kind, const BinFields& fields,
AssertedScopeKind scopeKind);
JS::Result<Ok> parseInterfaceAssertedBoundNamesScope(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<Ok> parseInterfaceAssertedDeclaredName(const size_t start, const BinKind kind, const BinFields& fields,
AssertedScopeKind scopeKind);
JS::Result<Ok> parseInterfaceAssertedParameterScope(const size_t start, const BinKind kind, const BinFields& fields,
MutableHandle<GCVector<JSAtom*>> positionalParams);
JS::Result<Ok> parseInterfaceAssertedPositionalParameterName(const size_t start, const BinKind kind, const BinFields& fields,
AssertedScopeKind scopeKind,
MutableHandle<GCVector<JSAtom*>> positionalParams);
JS::Result<Ok> parseInterfaceAssertedScriptGlobalScope(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<Ok> parseInterfaceAssertedVarScope(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceAssignmentExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceAssignmentTargetIdentifier(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceAwaitExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceBinaryExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceBindingIdentifier(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceBindingWithInitializer(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceBlock(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceBreakStatement(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceCallExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<LexicalScopeNode*> parseInterfaceCatchClause(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceClassDeclaration(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceClassExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceCompoundAssignmentExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceComputedMemberAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceComputedMemberExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceComputedPropertyName(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceConditionalExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceContinueStatement(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceDataProperty(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceDebuggerStatement(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceDirective(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceDoWhileStatement(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceEagerArrowExpressionWithExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceEagerArrowExpressionWithFunctionBody(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceEagerFunctionDeclaration(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceEagerFunctionExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceEagerGetter(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceEagerMethod(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceEagerSetter(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceEmptyStatement(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceExpressionStatement(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceForInOfBinding(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceForInStatement(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceForOfStatement(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceForStatement(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ListNode*> parseInterfaceFormalParameters(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<Ok> parseInterfaceFunctionExpressionContents(const size_t start, const BinKind kind, const BinFields& fields,
uint32_t funLength,
ListNode** paramsOut,
ListNode** bodyOut);
JS::Result<Ok> parseInterfaceFunctionOrMethodContents(const size_t start, const BinKind kind, const BinFields& fields,
uint32_t funLength,
ListNode** paramsOut,
ListNode** bodyOut);
JS::Result<Ok> parseInterfaceGetterContents(const size_t start, const BinKind kind, const BinFields& fields,
uint32_t funLength,
ListNode** paramsOut,
ListNode** bodyOut);
JS::Result<ParseNode*> parseInterfaceIdentifierExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceIfStatement(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceLabelledStatement(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceLazyArrowExpressionWithExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceLazyArrowExpressionWithFunctionBody(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceLazyFunctionDeclaration(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceLazyFunctionExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceLazyGetter(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceLazyMethod(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceLazySetter(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceLiteralBooleanExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceLiteralInfinityExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceLiteralNullExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceLiteralNumericExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceLiteralPropertyName(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceLiteralRegExpExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceLiteralStringExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceModule(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceNewExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceNewTargetExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceObjectAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceObjectBinding(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceObjectExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceReturnStatement(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceScript(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<Ok> parseInterfaceSetterContents(const size_t start, const BinKind kind, const BinFields& fields,
uint32_t funLength,
ListNode** paramsOut,
ListNode** bodyOut);
JS::Result<ParseNode*> parseInterfaceShorthandProperty(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceSpreadElement(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceStaticMemberAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceStaticMemberExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceSuper(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<CaseClause*> parseInterfaceSwitchCase(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceSwitchDefault(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceSwitchStatement(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceSwitchStatementWithDefault(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceTemplateExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceThisExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceThrowStatement(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceTryCatchStatement(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceTryFinallyStatement(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceUnaryExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceUpdateExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceVariableDeclaration(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceVariableDeclarator(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceWhileStatement(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceWithStatement(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceYieldExpression(const size_t start, const BinKind kind, const BinFields& fields);
JS::Result<ParseNode*> parseInterfaceYieldStarExpression(const size_t start, const BinKind kind, const BinFields& fields);
// ----- String enums (by lexicographical order)
// Implementations are autogenerated
JS::Result<typename BinASTParser<Tok>::AssertedDeclaredKind> parseAssertedDeclaredKind();
JS::Result<typename BinASTParser<Tok>::BinaryOperator> parseBinaryOperator();
JS::Result<typename BinASTParser<Tok>::CompoundAssignmentOperator> parseCompoundAssignmentOperator();
JS::Result<typename BinASTParser<Tok>::UnaryOperator> parseUnaryOperator();
JS::Result<typename BinASTParser<Tok>::UpdateOperator> parseUpdateOperator();
JS::Result<typename BinASTParser<Tok>::VariableDeclarationKind> parseVariableDeclarationKind();
// ----- Lists (by lexicographical order)
// Implementations are autogenerated
JS::Result<ParseNode*> parseArguments();
JS::Result<ListNode*> parseFunctionBody();
JS::Result<Ok> parseListOfAssertedBoundName(
AssertedScopeKind scopeKind);
JS::Result<Ok> parseListOfAssertedDeclaredName(
AssertedScopeKind scopeKind);
JS::Result<Ok> parseListOfAssertedMaybePositionalParameterName(
AssertedScopeKind scopeKind,
MutableHandle<GCVector<JSAtom*>> positionalParams);
JS::Result<ListNode*> parseListOfDirective();
JS::Result<ListNode*> parseListOfObjectProperty();
JS::Result<ListNode*> parseListOfOptionalSpreadElementOrExpression();
JS::Result<ListNode*> parseListOfParameter();
JS::Result<ListNode*> parseListOfStatement();
JS::Result<ListNode*> parseListOfSwitchCase();
JS::Result<ListNode*> parseListOfVariableDeclarator();
// ----- Default values (by lexicographical order)
// Implementations are autogenerated
JS::Result<ParseNode*> parseOptionalBinding();
JS::Result<ParseNode*> parseOptionalBindingIdentifier();
JS::Result<LexicalScopeNode*> parseOptionalCatchClause();
JS::Result<ParseNode*> parseOptionalExpression();
JS::Result<ParseNode*> parseOptionalSpreadElementOrExpression();
JS::Result<ParseNode*> parseOptionalStatement();
JS::Result<ParseNode*> parseOptionalVariableDeclarationOrExpression();

Просмотреть файл

@ -15,7 +15,7 @@ parser:
append: |
result->appendWithoutOrderAssumption(item);
# Rules for generating BinSource-auto.cpp
# Rules for generating BinASTParser.cpp
cpp:
header: |
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
@ -27,6 +27,8 @@ cpp:
// To generate this file, see the documentation in
// js/src/frontend/binsource/README.md.
#include "frontend/BinASTParser.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/Casting.h"
#include "mozilla/Maybe.h"
@ -35,7 +37,6 @@ cpp:
#include "mozilla/Vector.h"
#include "frontend/BinSource-macros.h"
#include "frontend/BinSource.h"
#include "frontend/BinTokenReaderTester.h"
#include "frontend/FullParseHandler.h"
#include "frontend/ParseNode.h"
@ -70,7 +71,7 @@ cpp:
hpp:
# Rules for generating BinSource-class.h
# Rules for generating BinASTParser.h
class:
header: |
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
@ -82,8 +83,150 @@ hpp:
// To generate this file, see the documentation in
// js/src/frontend/binsource/README.md.
// This file is meant to be included from the declaration
// of class `BinASTParser`. The include may be public or private.
#ifndef frontend_BinASTParser_h
#define frontend_BinASTParser_h
#include "mozilla/Maybe.h"
#include "frontend/BCEParserHandle.h"
#include "frontend/BinASTParserPerTokenizer.h"
#include "frontend/BinToken.h"
#include "frontend/BinTokenReaderMultipart.h"
#include "frontend/BinTokenReaderTester.h"
#include "frontend/FullParseHandler.h"
#include "frontend/ParseContext.h"
#include "frontend/ParseNode.h"
#include "frontend/SharedContext.h"
#include "js/CompileOptions.h"
#include "js/GCHashTable.h"
#include "js/GCVector.h"
#include "js/Result.h"
namespace js {
namespace frontend {
template<typename Tok>
class BinASTParser : public BinASTParserPerTokenizer<Tok>
{
public:
using Base = BinASTParserPerTokenizer<Tok>;
using Tokenizer = Tok;
using BinFields = typename Tokenizer::BinFields;
using AutoList = typename Tokenizer::AutoList;
using AutoTaggedTuple = typename Tokenizer::AutoTaggedTuple;
using AutoTuple = typename Tokenizer::AutoTuple;
using Chars = typename Tokenizer::Chars;
public:
// Auto-generated types.
using AssertedDeclaredKind = binast::AssertedDeclaredKind;
using BinaryOperator = binast::BinaryOperator;
using CompoundAssignmentOperator = binast::CompoundAssignmentOperator;
using UnaryOperator = binast::UnaryOperator;
using UpdateOperator = binast::UpdateOperator;
using VariableDeclarationKind = binast::VariableDeclarationKind;
public:
// BinASTParserPerTokenizer types.
using AssertedScopeKind = typename Base::AssertedScopeKind;
public:
BinASTParser(JSContext* cx, LifoAlloc& alloc, UsedNameTracker& usedNames,
const JS::ReadOnlyCompileOptions& options,
HandleScriptSourceObject sourceObject,
Handle<LazyScript*> lazyScript = nullptr)
: BinASTParserPerTokenizer<Tok>(cx, alloc, usedNames, options, sourceObject, lazyScript)
{}
~BinASTParser()
{}
protected:
// BinASTParserBase fields.
using Base::cx_;
using Base::alloc_;
using Base::usedNames_;
using Base::sourceObject_;
using Base::parseContext_;
using Base::factory_;
protected:
// BinASTParserPerTokenizer types.
using AutoVariableDeclarationKind = typename Base::AutoVariableDeclarationKind;
protected:
// BinASTParserPerTokenizer fields.
using Base::tokenizer_;
using Base::variableDeclarationKind_;
protected:
// BinASTParserPerTokenizer methods.
using Base::raiseInvalidClosedVar;
using Base::raiseMissingVariableInAssertedScope;
using Base::raiseMissingDirectEvalInAssertedScope;
using Base::raiseInvalidKind;
using Base::raiseInvalidVariant;
using Base::raiseMissingField;
using Base::raiseEmpty;
using Base::raiseOOM;
using Base::raiseError;
using Base::makeEmptyFunctionNode;
using Base::buildFunction;
using Base::buildFunctionBox;
using Base::addScopeName;
using Base::captureFunctionName;
using Base::getDeclaredScope;
using Base::getBoundScope;
using Base::checkBinding;
using Base::checkPositionalParameterIndices;
using Base::checkFunctionLength;
using Base::checkClosedVars;
using Base::prependDirectivesToBody;
using Base::forceStrictIfNecessary;
public:
footer: |
};
extern template class BinASTParser<BinTokenReaderMultipart>;
extern template class BinASTParser<BinTokenReaderTester>;
} // namespace frontend
} // namespace js
#endif // frontend_BinASTParser_h
enums:
header: |
/* -*- 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/. */
// To generate this file, see the documentation in
// js/src/frontend/binsource/README.md.
#ifndef frontend_BinASTEnum_h
#define frontend_BinASTEnum_h
namespace js {
namespace frontend {
namespace binast {
footer: |
} // namespace binast
} // namespace frontend
} // namespace js
#endif // frontend_BinASTEnum_h
# Rules for generating BinToken.h
tokens:
@ -120,14 +263,14 @@ hpp:
*
* (sorted by alphabetical order)
*/
field:
variants:
doc: |
/**
* The different variants of Binary AST string enums, as per
* the specifications of Binary AST, as a single macro and
* `enum class`.
*
* Separate enum classes are also defined in BinSource-auto.h.
* Separate enum classes are also defined in BinASTParser.h.
*
* Usage:
*
@ -700,14 +843,14 @@ GetterContents:
fields:
body:
before: |
BINJS_TRY_DECL(params, new_<ListNode>(ParseNodeKind::ParamsBody, tokenizer_->pos(start)));
BINJS_TRY_DECL(params, this->template new_<ListNode>(ParseNodeKind::ParamsBody, tokenizer_->pos(start)));
SetterContents:
inherits: FunctionExpressionContents
fields:
param:
after: |
BINJS_TRY_DECL(params, new_<ListNode>(ParseNodeKind::ParamsBody, param->pn_pos));
BINJS_TRY_DECL(params, this->template new_<ListNode>(ParseNodeKind::ParamsBody, param->pn_pos));
factory_.addList(params, param);
MOZ_TRY(checkPositionalParameterIndices(positionalParams, params));
@ -999,7 +1142,7 @@ ListOfParameter:
type-ok:
ListNode*
init: |
BINJS_TRY_DECL(result, new_<ListNode>(ParseNodeKind::ParamsBody, tokenizer_->pos(start)));
BINJS_TRY_DECL(result, this->template new_<ListNode>(ParseNodeKind::ParamsBody, tokenizer_->pos(start)));
append:
factory_.addList(/* list = */ result, /* kid = */ item);
@ -1016,7 +1159,7 @@ ListOfStatement:
# type-ok:
# ListNode*
# init:
# BINJS_TRY_DECL(result, new_<ListNode>(ParseNodeKind::ParamsBody, tokenizer_->pos()));
# BINJS_TRY_DECL(result, this->template new_<ListNode>(ParseNodeKind::ParamsBody, tokenizer_->pos()));
# append:
# result->appendWithoutOrderAssumption(item);

Просмотреть файл

@ -275,17 +275,14 @@ const size_t BINKIND_LIMIT = 200;
/**
* The different variants of Binary AST string enums, as per
* the specifications of Binary AST, as a single macro and
* `enum class`.
*
* Separate enum classes are also defined in BinSource-auto.h.
* The different fields of Binary AST nodes, as per the specifications of
* Binary AST.
*
* Usage:
*
* ```c++
* #define WITH_VARIANT(CPP_NAME, SPEC_NAME) ...
* FOR_EACH_BIN_VARIANT(WITH_VARIANT)
* #define WITH_FIELD(CPP_NAME, SPEC_NAME) ...
* FOR_EACH_BIN_FIELD(WITH_FIELD)
* ```
*
* (sorted by alphabetical order)
@ -371,7 +368,22 @@ enum class BinField {
const size_t BINFIELD_LIMIT = 69;
/**
* The different variants of Binary AST string enums, as per
* the specifications of Binary AST, as a single macro and
* `enum class`.
*
* Separate enum classes are also defined in BinASTParser.h.
*
* Usage:
*
* ```c++
* #define WITH_VARIANT(CPP_NAME, SPEC_NAME) ...
* FOR_EACH_BIN_VARIANT(WITH_VARIANT)
* ```
*
* (sorted by alphabetical order)
*/
#define FOR_EACH_BIN_VARIANT(F) \
F(AssertedDeclaredKindConstLexical, "const lexical") \
F(AssertedDeclaredKindNonConstLexical, "non-const lexical") \

Просмотреть файл

@ -13,7 +13,7 @@
#include "builtin/ModuleObject.h"
#if defined(JS_BUILD_BINAST)
# include "frontend/BinSource.h"
# include "frontend/BinASTParser.h"
#endif // JS_BUILD_BINAST
#include "frontend/BytecodeCompilation.h"
#include "frontend/BytecodeEmitter.h"

Просмотреть файл

@ -131,7 +131,8 @@ TraceParser(JSTracer* trc, JS::AutoGCRooter* parser);
#if defined(JS_BUILD_BINAST)
/* Trace all GC things reachable from binjs parser. Defined in BinSource.cpp. */
/* Trace all GC things reachable from binjs parser. Defined in
* BinASTParserPerTokenizer.cpp. */
void
TraceBinParser(JSTracer* trc, JS::AutoGCRooter* parser);

Просмотреть файл

@ -26,7 +26,7 @@ namespace frontend {
enum class SourceKind {
// We are parsing from a text source (Parser.h)
Text,
// We are parsing from a binary source (BinSource.h)
// We are parsing from a binary source (BinASTParser.h)
Binary,
};
@ -108,7 +108,7 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS)
#undef DECLARE_AS
// The FullParseHandler may be used to create nodes for text sources
// (from Parser.h) or for binary sources (from BinSource.h). In the latter
// (from Parser.h) or for binary sources (from BinASTParser.h). In the latter
// case, some common assumptions on offsets are incorrect, e.g. in `a + b`,
// `a`, `b` and `+` may be stored in any order. We use `sourceKind()`
// to determine whether we need to check these assumptions.

Просмотреть файл

@ -3,6 +3,7 @@
cargo run -- \
../BinSource.webidl_ \
../BinSource.yaml \
--out-class ../BinSource-auto.h \
--out-impl ../BinSource-auto.cpp \
--out-class ../BinASTParser.h \
--out-impl ../BinASTParser.cpp \
--out-enum ../BinASTEnum.h \
--out-token ../BinToken.h

Просмотреть файл

@ -139,10 +139,22 @@ struct GlobalRules {
/// Header to add at the end of the .cpp file.
cpp_footer: Option<String>,
/// Header to add at the start of the .hpp file
/// defining the class data/methods.
/// Header to add at the start of the .hpp file.
/// defining the class.
hpp_class_header: Option<String>,
/// Footer to add at the end of the .hpp file
/// defining the class.
hpp_class_footer: Option<String>,
/// Header to add at the start of the .hpp file.
/// defining the enums.
hpp_enums_header: Option<String>,
/// Footer to add at the end of the .hpp file
/// defining the enums.
hpp_enums_footer: Option<String>,
/// Header to add at the start of the .hpp file.
/// defining the tokens.
hpp_tokens_header: Option<String>,
@ -176,6 +188,9 @@ impl GlobalRules {
let mut cpp_header = None;
let mut cpp_footer = None;
let mut hpp_class_header = None;
let mut hpp_class_footer = None;
let mut hpp_enums_header = None;
let mut hpp_enums_footer = None;
let mut hpp_tokens_header = None;
let mut hpp_tokens_footer = None;
let mut hpp_tokens_kind_doc = None;
@ -211,6 +226,12 @@ impl GlobalRules {
"hpp" => {
update_rule(&mut hpp_class_header, &node_entries["class"]["header"])
.unwrap_or_else(|_| panic!("Rule hpp.class.header must be a string"));
update_rule(&mut hpp_class_footer, &node_entries["class"]["footer"])
.unwrap_or_else(|_| panic!("Rule hpp.class.footer must be a string"));
update_rule(&mut hpp_enums_header, &node_entries["enums"]["header"])
.unwrap_or_else(|_| panic!("Rule hpp.enum.header must be a string"));
update_rule(&mut hpp_enums_footer, &node_entries["enums"]["footer"])
.unwrap_or_else(|_| panic!("Rule hpp.enum.footer must be a string"));
update_rule(&mut hpp_tokens_header, &node_entries["tokens"]["header"])
.unwrap_or_else(|_| panic!("Rule hpp.tokens.header must be a string"));
update_rule(&mut hpp_tokens_footer, &node_entries["tokens"]["footer"])
@ -398,6 +419,9 @@ impl GlobalRules {
cpp_header,
cpp_footer,
hpp_class_header,
hpp_class_footer,
hpp_enums_header,
hpp_enums_footer,
hpp_tokens_header,
hpp_tokens_footer,
hpp_tokens_kind_doc,
@ -982,19 +1006,26 @@ enum class BinVariant {
}
/// Declare string enums
fn export_declare_string_enums_classes(&self, buffer: &mut String) {
buffer.push_str("\n\n// ----- Declaring string enums (by lexicographical order)\n");
fn export_declare_string_enums(&self, buffer: &mut String) {
buffer.push_str("
// ----- Declaring string enums (by lexicographical order)
");
let string_enums_by_name = self.syntax.string_enums_by_name()
.iter()
.sorted_by(|a, b| str::cmp(a.0.to_str(), b.0.to_str()));
for (name, enum_) in string_enums_by_name {
let rendered_cases = enum_.strings()
.iter()
.map(|str| format!("{case:<20} /* \"{original}\" */",
.map(|str| format!(" // \"{original}\"
{case},",
case = str.to_cpp_enum_case(),
original = str))
.format(",\n ");
let rendered = format!("enum class {name} {{\n {cases}\n}};\n\n",
.format("\n");
let rendered = format!("
enum class {name} {{
{cases}
}};
",
cases = rendered_cases,
name = name.to_class_cases());
buffer.push_str(&rendered);
@ -1005,9 +1036,10 @@ enum class BinVariant {
let sums_of_interfaces = self.syntax.resolved_sums_of_interfaces_by_name()
.iter()
.sorted_by(|a, b| a.0.cmp(&b.0));
buffer.push_str("\n\n// ----- Sums of interfaces (by lexicographical order)\n");
buffer.push_str("// Implementations are autogenerated\n");
buffer.push_str("// `ParseNode*` may never be nullptr\n");
buffer.push_str("
// ----- Sums of interfaces (by lexicographical order)
// `ParseNode*` may never be nullptr
");
for &(ref name, _) in &sums_of_interfaces {
if !self.refgraph.is_used(name.to_rc_string().clone()) {
continue;
@ -1017,7 +1049,7 @@ enum class BinVariant {
let extra_params = rules_for_this_sum.extra_params;
let rendered = self.get_method_signature(name, "", "",
&extra_params);
buffer.push_str(&rendered.reindent("")
buffer.push_str(&rendered.reindent(" ")
.newline_if_not_empty());
}
for (name, _) in sums_of_interfaces {
@ -1031,15 +1063,16 @@ enum class BinVariant {
let rendered = self.get_method_signature(name, prefix,
INTERFACE_PARAMS,
&extra_params);
buffer.push_str(&rendered.reindent("")
buffer.push_str(&rendered.reindent(" ")
.newline_if_not_empty());
}
}
fn export_declare_single_interface_methods(&self, buffer: &mut String) {
buffer.push_str("\n\n// ----- Interfaces (by lexicographical order)\n");
buffer.push_str("// Implementations are autogenerated\n");
buffer.push_str("// `ParseNode*` may never be nullptr\n");
buffer.push_str("
// ----- Interfaces (by lexicographical order)
// `ParseNode*` may never be nullptr
");
let interfaces_by_name = self.syntax.interfaces_by_name()
.iter()
.sorted_by(|a, b| str::cmp(a.0.to_str(), b.0.to_str()));
@ -1053,7 +1086,7 @@ enum class BinVariant {
if self.refgraph.is_used(name.to_rc_string().clone()) {
let outer = self.get_method_signature(name, "", "", &extra_params);
outer_parsers.push(outer.reindent(""));
outer_parsers.push(outer.reindent(" "));
}
let inner_prefix = "Interface";
@ -1063,7 +1096,7 @@ enum class BinVariant {
let inner = self.get_method_signature(name, inner_prefix,
INTERFACE_PARAMS,
&extra_params);
inner_parsers.push(inner.reindent(""));
inner_parsers.push(inner.reindent(" "));
}
for parser in outer_parsers.drain(..) {
@ -1078,8 +1111,9 @@ enum class BinVariant {
}
fn export_declare_string_enums_methods(&self, buffer: &mut String) {
buffer.push_str("\n\n// ----- String enums (by lexicographical order)\n");
buffer.push_str("// Implementations are autogenerated\n");
buffer.push_str("
// ----- String enums (by lexicographical order)
");
let string_enums_by_name = self.syntax.string_enums_by_name()
.iter()
.sorted_by(|a, b| str::cmp(a.0.to_str(), b.0.to_str()));
@ -1089,14 +1123,15 @@ enum class BinVariant {
}
let rendered = self.get_method_signature(kind, "", "", &None);
buffer.push_str(&rendered.reindent(""));
buffer.push_str(&rendered.reindent(" "));
buffer.push_str("\n");
}
}
fn export_declare_list_methods(&self, buffer: &mut String) {
buffer.push_str("\n\n// ----- Lists (by lexicographical order)\n");
buffer.push_str("// Implementations are autogenerated\n");
buffer.push_str("
// ----- Lists (by lexicographical order)
");
for parser in &self.list_parsers_to_generate {
if !self.refgraph.is_used(parser.name.to_rc_string().clone()) {
continue;
@ -1106,14 +1141,15 @@ enum class BinVariant {
let extra_params = rules_for_this_node.extra_params;
let rendered = self.get_method_signature(&parser.name, "", "",
&extra_params);
buffer.push_str(&rendered.reindent(""));
buffer.push_str(&rendered.reindent(" "));
buffer.push_str("\n");
}
}
fn export_declare_option_methods(&self, buffer: &mut String) {
buffer.push_str("\n\n// ----- Default values (by lexicographical order)\n");
buffer.push_str("// Implementations are autogenerated\n");
buffer.push_str("
// ----- Default values (by lexicographical order)
");
for parser in &self.option_parsers_to_generate {
if !self.refgraph.is_used(parser.name.to_rc_string().clone()) {
continue;
@ -1123,7 +1159,7 @@ enum class BinVariant {
let extra_params = rules_for_this_node.extra_params;
let rendered = self.get_method_signature(&parser.name, "", "",
&extra_params);
buffer.push_str(&rendered.reindent(""));
buffer.push_str(&rendered.reindent(" "));
buffer.push_str("\n");
}
}
@ -1154,13 +1190,30 @@ enum class BinVariant {
buffer.push_str(&self.rules.hpp_class_header.reindent(""));
buffer.push_str("\n");
self.export_declare_string_enums_classes(&mut buffer);
self.export_declare_sums_of_interface_methods(&mut buffer);
self.export_declare_single_interface_methods(&mut buffer);
self.export_declare_string_enums_methods(&mut buffer);
self.export_declare_list_methods(&mut buffer);
self.export_declare_option_methods(&mut buffer);
buffer.push_str("\n");
buffer.push_str(&self.rules.hpp_class_footer.reindent(""));
buffer.push_str("\n");
buffer
}
fn to_spidermonkey_enum_hpp(&self) -> String {
let mut buffer = String::new();
buffer.push_str(&self.generate_autogenerated_warning());
buffer.push_str(&self.rules.hpp_enums_header.reindent(""));
buffer.push_str("\n");
self.export_declare_string_enums(&mut buffer);
buffer.push_str("\n");
buffer.push_str(&self.rules.hpp_enums_footer.reindent(""));
buffer.push_str("\n");
buffer
}
@ -1994,7 +2047,12 @@ fn main() {
.long("out-class")
.required(true)
.takes_value(true)
.help("Output header file (.h, designed to be included from within the class file)"),
.help("Output header file for class (.h)"),
Arg::with_name("OUT_HEADER_ENUM_FILE")
.long("out-enum")
.required(true)
.takes_value(true)
.help("Output header file for enum (.h)"),
Arg::with_name("OUT_TOKEN_FILE")
.long("out-token")
.required(true)
@ -2101,6 +2159,8 @@ fn main() {
write_to("C++ class header code", "OUT_HEADER_CLASS_FILE",
&exporter.to_spidermonkey_class_hpp());
write_to("C++ enum header code", "OUT_HEADER_ENUM_FILE",
&exporter.to_spidermonkey_enum_hpp());
write_to("C++ token header code", "OUT_TOKEN_FILE",
&exporter.to_spidermonkey_token_hpp());
write_to("C++ token implementation code", "OUT_IMPL_FILE",

Просмотреть файл

@ -67,8 +67,9 @@ if CONFIG['JS_BUILD_BINAST']:
SOURCES += ['BinTokenReaderTester.cpp']
# These parts of BinAST should eventually move to release.
SOURCES += [
'BinSource-auto.cpp',
'BinSource.cpp',
'BinASTParser.cpp',
'BinASTParserBase.cpp',
'BinASTParserPerTokenizer.cpp',
'BinSourceRuntimeSupport.cpp',
'BinToken.cpp',
'BinTokenReaderBase.cpp',
@ -79,8 +80,9 @@ if CONFIG['JS_BUILD_BINAST']:
if CONFIG['FUZZING_INTERFACES'] and CONFIG['LIBFUZZER']:
include('/tools/fuzzing/libfuzzer-flags.mozbuild')
SOURCES['BinSource-auto.cpp'].flags += libfuzzer_flags
SOURCES['BinSource.cpp'].flags += libfuzzer_flags
SOURCES['BinASTParser.cpp'].flags += libfuzzer_flags
SOURCES['BinASTParserBase.cpp'].flags += libfuzzer_flags
SOURCES['BinASTParserPerTokenizer.cpp'].flags += libfuzzer_flags
SOURCES['BinToken.cpp'].flags += libfuzzer_flags
SOURCES['BinTokenReaderBase.cpp'].flags += libfuzzer_flags
SOURCES['BinTokenReaderMultipart.cpp'].flags += libfuzzer_flags

Просмотреть файл

@ -10,7 +10,7 @@
#include "jsapi.h"
#include "frontend/BinSource.h"
#include "frontend/BinASTParser.h"
#include "frontend/FullParseHandler.h"
#include "frontend/ParseContext.h"
#include "frontend/Parser.h"

Просмотреть файл

@ -23,7 +23,7 @@
#include "jsapi.h"
#include "frontend/BinSource.h"
#include "frontend/BinASTParser.h"
#include "frontend/FullParseHandler.h"
#include "frontend/ParseContext.h"
#include "frontend/Parser.h"

Просмотреть файл

@ -68,7 +68,7 @@
#include "builtin/RegExp.h"
#include "builtin/TestingFunctions.h"
#if defined(JS_BUILD_BINAST)
# include "frontend/BinSource.h"
# include "frontend/BinASTParser.h"
#endif // defined(JS_BUILD_BINAST)
#include "frontend/ModuleSharedContext.h"
#include "frontend/Parser.h"

Просмотреть файл

@ -720,6 +720,20 @@ wasm::ExecuteCompileTaskFromHelperThread(CompileTask* task)
taskState.notify_one(/* failed or finished */);
}
bool
ModuleGenerator::locallyCompileCurrentTask()
{
if (!ExecuteCompileTask(currentTask_, error_)) {
return false;
}
if (!finishTask(currentTask_)) {
return false;
}
currentTask_ = nullptr;
batchedBytecode_ = 0;
return true;
}
bool
ModuleGenerator::finishTask(CompileTask* task)
{
@ -756,20 +770,14 @@ ModuleGenerator::launchBatchCompile()
return false;
}
if (parallel_) {
if (!StartOffThreadWasmCompile(currentTask_, mode())) {
return false;
}
outstanding_++;
} else {
if (!ExecuteCompileTask(currentTask_, error_)) {
return false;
}
if (!finishTask(currentTask_)) {
return false;
}
if (!parallel_) {
return locallyCompileCurrentTask();
}
if (!StartOffThreadWasmCompile(currentTask_, mode())) {
return false;
}
outstanding_++;
currentTask_ = nullptr;
batchedBytecode_ = 0;
return true;
@ -843,7 +851,7 @@ ModuleGenerator::finishFuncDefs()
{
MOZ_ASSERT(!finishedFuncDefs_);
if (currentTask_ && !launchBatchCompile()) {
if (currentTask_ && !locallyCompileCurrentTask()) {
return false;
}

Просмотреть файл

@ -196,6 +196,7 @@ class MOZ_STACK_CLASS ModuleGenerator
bool linkCallSites();
void noteCodeRange(uint32_t codeRangeIndex, const CodeRange& codeRange);
bool linkCompiledCode(const CompiledCode& code);
bool locallyCompileCurrentTask();
bool finishTask(CompileTask* task);
bool launchBatchCompile();
bool finishOutstandingTask();

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше