Merge autoland to mozilla-central. a=merge

This commit is contained in:
smolnar 2022-07-23 12:13:40 +03:00
Родитель 147aa99ada 2e3ac6e721
Коммит 7b9d23ece4
158 изменённых файлов: 3154 добавлений и 1631 удалений

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

@ -25,7 +25,7 @@ rev = "3bfc47d9a571d0842676043ba60716318e946c06"
[source."https://github.com/mozilla/midir.git"]
git = "https://github.com/mozilla/midir.git"
replace-with = "vendored-sources"
rev = "4c11f0ffb5d6a10de4aff40a7b81218b33b94e6f"
rev = "e1b4dcb767f9e69afe95a860374aaa9635d81e3d"
[source."https://github.com/mozilla/cubeb-pulse-rs"]
git = "https://github.com/mozilla/cubeb-pulse-rs"

2
Cargo.lock сгенерированный
Просмотреть файл

@ -3291,7 +3291,7 @@ dependencies = [
[[package]]
name = "midir"
version = "0.7.0"
source = "git+https://github.com/mozilla/midir.git?rev=4c11f0ffb5d6a10de4aff40a7b81218b33b94e6f#4c11f0ffb5d6a10de4aff40a7b81218b33b94e6f"
source = "git+https://github.com/mozilla/midir.git?rev=e1b4dcb767f9e69afe95a860374aaa9635d81e3d#e1b4dcb767f9e69afe95a860374aaa9635d81e3d"
dependencies = [
"alsa",
"bitflags",

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

@ -146,7 +146,7 @@ coremidi = { git = "https://github.com/chris-zen/coremidi.git", rev="fc68464b544
fog = { path = "toolkit/components/glean/api" }
libudev-sys = { path = "dom/webauthn/libudev-sys" }
packed_simd = { package = "packed_simd_2", git = "https://github.com/hsivonen/packed_simd", rev="c149d0a519bf878567c7630096737669ec2ff15f" }
midir = { git = "https://github.com/mozilla/midir.git", rev = "4c11f0ffb5d6a10de4aff40a7b81218b33b94e6f" }
midir = { git = "https://github.com/mozilla/midir.git", rev = "e1b4dcb767f9e69afe95a860374aaa9635d81e3d" }
minidump_writer_linux = { git = "https://github.com/rust-minidump/minidump-writer.git", rev = "75ada456c92a429704691a85e1cb42fef8cafc0d" }
# application-services overrides to make updating them all simpler.

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

@ -2707,3 +2707,7 @@ pref("browser.snapshots.relevancy.timeOfDayIntervalSeconds", 3600);
pref("browser.places.snapshots.expiration.days", 210);
// For user managed snapshots we use more than a year, to support yearly tasks.
pref("browser.places.snapshots.expiration.userManaged.days", 420);
// If the user has seen the Firefox View feature tour this value reflects the tour
// message id, the id of the last screen they saw, and whether they completed the tour
pref("browser.browser.firefoxView.featureTour", "default, default, true");

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

@ -65,6 +65,7 @@ figure > img {
margin-block-start: 2rem;
max-width: var(--figure-height);
max-height: var(--figure-width);
object-fit: scale-down;
}
#colorway-customization-panel {

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

@ -232,6 +232,7 @@ body > main > aside {
#colorways-collection-figure {
max-width: var(--colorways-figure-size);
max-height: var(--colorways-figure-size);
object-fit: scale-down;
}
[hidden] {

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

@ -196,23 +196,27 @@ const MultiStageAboutWelcome = props => {
}
}); // Remember that a new screen has loaded for browser navigation
if (index > window.history.state) {
if (props.updateHistory && index > window.history.state) {
window.history.pushState(index, "");
}
}, [index]);
(0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
// Switch to the screen tracked in state (null for initial state)
// or last screen index if a user navigates by pressing back
// button from about:home
const handler = ({
state
}) => setScreenIndex(Math.min(state, screens.length - 1)); // Handle page load, e.g., going back to about:welcome from about:home
if (props.updateHistory) {
// Switch to the screen tracked in state (null for initial state)
// or last screen index if a user navigates by pressing back
// button from about:home
const handler = ({
state
}) => setScreenIndex(Math.min(state, screens.length - 1)); // Handle page load, e.g., going back to about:welcome from about:home
handler(window.history); // Watch for browser back/forward button navigation events
handler(window.history); // Watch for browser back/forward button navigation events
window.addEventListener("popstate", handler);
return () => window.removeEventListener("popstate", handler);
window.addEventListener("popstate", handler);
return () => window.removeEventListener("popstate", handler);
}
return false;
}, []);
const [flowParams, setFlowParams] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(null);
const {
@ -1711,6 +1715,7 @@ class AboutWelcome extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureCom
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_components_MultiStageAboutWelcome__WEBPACK_IMPORTED_MODULE_3__.MultiStageAboutWelcome, {
message_id: props.messageId,
screens: props.screens,
updateHistory: !props.disableHistoryUpdates,
metricsFlowUri: this.state.metricsFlowUri,
utm_term: props.UTMTerm,
transitions: props.transitions,

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

@ -71,6 +71,7 @@ class AboutWelcome extends React.PureComponent {
<MultiStageAboutWelcome
message_id={props.messageId}
screens={props.screens}
updateHistory={!props.disableHistoryUpdates}
metricsFlowUri={this.state.metricsFlowUri}
utm_term={props.UTMTerm}
transitions={props.transitions}

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

@ -30,24 +30,27 @@ export const MultiStageAboutWelcome = props => {
});
// Remember that a new screen has loaded for browser navigation
if (index > window.history.state) {
if (props.updateHistory && index > window.history.state) {
window.history.pushState(index, "");
}
}, [index]);
useEffect(() => {
// Switch to the screen tracked in state (null for initial state)
// or last screen index if a user navigates by pressing back
// button from about:home
const handler = ({ state }) =>
setScreenIndex(Math.min(state, screens.length - 1));
if (props.updateHistory) {
// Switch to the screen tracked in state (null for initial state)
// or last screen index if a user navigates by pressing back
// button from about:home
const handler = ({ state }) =>
setScreenIndex(Math.min(state, screens.length - 1));
// Handle page load, e.g., going back to about:welcome from about:home
handler(window.history);
// Handle page load, e.g., going back to about:welcome from about:home
handler(window.history);
// Watch for browser back/forward button navigation events
window.addEventListener("popstate", handler);
return () => window.removeEventListener("popstate", handler);
// Watch for browser back/forward button navigation events
window.addEventListener("popstate", handler);
return () => window.removeEventListener("popstate", handler);
}
return false;
}, []);
const [flowParams, setFlowParams] = useState(null);

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

@ -55,6 +55,7 @@ Please note that some targeting attributes require stricter controls on the tele
* [doesAppNeedPrivatePin](#doesappneedprivatepin)
* [isBackgroundTaskMode](#isbackgroundtaskmode)
* [backgroundTaskName](#backgroundtaskname)
* [userPrefersReducedMotion](#userPrefersReducedMotion)
## Detailed usage
@ -843,3 +844,8 @@ Checks if this invocation is running in background task mode.
A non-empty string task name if this invocation is running in background task
mode, or `null` if this invocation is not running in background task mode.
### `userPrefersReducedMotion`
Checks if user prefers reduced motion as indicated by the value of a media query for `prefers-reduced-motion`.

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

@ -1216,6 +1216,10 @@
"transitions": {
"type": "boolean",
"description": "Show transitions within and between screens"
},
"disableHistoryUpdates": {
"type": "boolean",
"description": "Don't alter the browser session's history stack - used with messaging surfaces like Feature Callouts"
}
},
"additionalProperties": true,

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

@ -127,6 +127,10 @@
"transitions": {
"type": "boolean",
"description": "Show transitions within and between screens"
},
"disableHistoryUpdates": {
"type": "boolean",
"description": "Don't alter the browser session's history stack - used with messaging surfaces like Feature Callouts"
}
},
"additionalProperties": true,

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

@ -214,6 +214,7 @@ export class _DiscoveryStreamBase extends React.PureComponent {
readTime={component.properties.readTime}
saveToPocketCard={component.saveToPocketCard}
pocket_button_enabled={component.pocketButtonEnabled}
recentSavesEnabled={this.props.DiscoveryStream.recentSavesEnabled}
/>
);
case "HorizontalRule":

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

@ -180,10 +180,7 @@ export function RecentSavesContainer({
export class _CardGrid extends React.PureComponent {
renderCards() {
const { DiscoveryStream } = this.props;
const prefs = this.props.Prefs.values;
const { recentSavesEnabled } = DiscoveryStream;
const showRecentSaves = prefs.showRecentSaves && recentSavesEnabled;
const {
items,
hybridLayout,
@ -201,7 +198,9 @@ export class _CardGrid extends React.PureComponent {
essentialReadsHeader,
editorsPicksHeader,
widgets,
recentSavesEnabled,
} = this.props;
const showRecentSaves = prefs.showRecentSaves && recentSavesEnabled;
const recs = this.props.data.recommendations.slice(0, items);
const cards = [];

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

@ -8082,14 +8082,7 @@ class _CardGrid extends (external_React_default()).PureComponent {
renderCards() {
var _widgets$positions, _widgets$data, _essentialReadsCards, _editorsPicksCards;
const {
DiscoveryStream
} = this.props;
const prefs = this.props.Prefs.values;
const {
recentSavesEnabled
} = DiscoveryStream;
const showRecentSaves = prefs.showRecentSaves && recentSavesEnabled;
const {
items,
hybridLayout,
@ -8106,8 +8099,10 @@ class _CardGrid extends (external_React_default()).PureComponent {
readTime,
essentialReadsHeader,
editorsPicksHeader,
widgets
widgets,
recentSavesEnabled
} = this.props;
const showRecentSaves = prefs.showRecentSaves && recentSavesEnabled;
const recs = this.props.data.recommendations.slice(0, items);
const cards = [];
let essentialReadsCards = [];
@ -13628,7 +13623,8 @@ class _DiscoveryStreamBase extends (external_React_default()).PureComponent {
editorsPicksHeader: component.properties.editorsPicksHeader,
readTime: component.properties.readTime,
saveToPocketCard: component.saveToPocketCard,
pocket_button_enabled: component.pocketButtonEnabled
pocket_button_enabled: component.pocketButtonEnabled,
recentSavesEnabled: this.props.DiscoveryStream.recentSavesEnabled
});
case "HorizontalRule":

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

@ -741,6 +741,11 @@ const TargetingGetters = {
);
return bts?.backgroundTaskName();
},
get userPrefersReducedMotion() {
let window = lazy.BrowserWindowTracker.getTopWindow();
return window?.matchMedia("(prefers-reduced-motion: reduce)")?.matches;
},
};
const ASRouterTargeting = {

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

@ -420,3 +420,43 @@ add_task(async function test_aboutwelcome_split_position() {
}
);
});
/**
* Test rendering a message with session history updates disabled
*/
add_task(async function test_aboutwelcome_history_updates_disabled() {
let screens = [];
// we need at least two screens to test the history state
for (let i = 1; i < 3; i++) {
screens.push(makeTestContent(`TEST_PUSH_STATE_STEP_${i}`));
}
let doExperimentCleanup = await ExperimentFakes.enrollWithFeatureConfig({
featureId: "aboutwelcome",
value: {
enabled: true,
disableHistoryUpdates: true,
screens,
},
});
let browser = await openAboutWelcome(JSON.stringify(screens));
let startHistoryLength = await SpecialPowers.spawn(browser, [], () => {
return content.window.history.length;
});
// Advance to second screen
await onButtonClick(browser, "button.primary");
let endHistoryLength = await SpecialPowers.spawn(browser, [], async () => {
// Ensure next screen has rendered
await ContentTaskUtils.waitForCondition(() =>
content.document.querySelector(".TEST_PUSH_STATE_STEP_2")
);
return content.window.history.length;
});
ok(
startHistoryLength === endHistoryLength,
"No entries added to the session's history stack with history updates disabled"
);
await doExperimentCleanup();
});

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

@ -1163,3 +1163,11 @@ add_task(async function check_isBackgroundTaskMode() {
"Has no background task name"
);
});
add_task(async function check_userPrefersReducedMotion() {
is(
typeof (await ASRouterTargeting.Environment.userPrefersReducedMotion),
"boolean",
"Should return a boolean"
);
});

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

@ -4,8 +4,6 @@
## Colorway collections
colorway-collection-life-in-color = Life In Color
colorway-collection-true-colors = True Colors
colorway-collection-independent-voices = Independent Voices
colorway-collection-independent-voices-description = Color can change culture. The latest colorways celebrate voices making the world a better place.
# Used as a subheading for the colorway collection card in about:addons

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

@ -265,3 +265,8 @@ editor_free_text_font_color=Font Color
editor_free_text_font_size=Font Size
editor_ink_line_color=Line Color
editor_ink_line_thickness=Line Thickness
# Editor aria
editor_free_text_aria_label=FreeText Editor
editor_ink_aria_label=Ink Editor
editor_ink_canvas_aria_label=User-created image

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

@ -497,16 +497,10 @@ const ColorwayCollections = [
{
id: "life-in-color",
expiry: "2022-02-08",
l10nId: {
title: "colorway-collection-life-in-color",
},
},
{
id: "true-colors",
expiry: "2022-05-03",
l10nId: {
title: "colorway-collection-true-colors",
},
},
{
id: "independent-voices",

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

@ -109,10 +109,8 @@ skip-if = (os == 'win' && bits == 32 && debug) # bug 1609313
[browser_rules_cubicbezier-revert-on-ESC.js]
[browser_rules_custom.js]
[browser_rules_cycle-angle.js]
skip-if = (os == "linux") # Bug 1767684
[browser_rules_cycle-color.js]
[browser_rules_edit-display-grid-property.js]
skip-if = (os == "linux") # Bug 1356214
[browser_rules_edit-property-cancel.js]
[browser_rules_edit-property-click.js]
[browser_rules_edit-property-commit.js]

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

@ -20,10 +20,11 @@ add_task(async function() {
await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
const { view } = await openRuleView();
// Bug 1767679 - Frequent intermittents on linux.
const property = await waitFor(() =>
getRuleViewProperty(view, "body", "background")
);
// Bug 1767679 - Use { wait: true } to avoid frequent intermittents on linux.
const property = await getRuleViewProperty(view, "body", "background", {
wait: true,
});
const value = property.valueSpan;
const swatch = value.querySelectorAll(".ruleview-colorswatch")[0];
const url = value.querySelector(".theme-link");

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

@ -90,7 +90,9 @@ add_task(async function() {
selector
);
const prop = getRuleViewProperty(view, selector, propertyName).valueSpan;
const prop = (
await getRuleViewProperty(view, selector, propertyName, { wait: true })
).valueSpan;
const swatches = prop.querySelectorAll(".ruleview-colorswatch");
ok(swatches.length, "Swatches found in the property");

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

@ -41,7 +41,9 @@ async function testColorPickerAppearsOnColorSwatchActivation(
property,
withKeyboard = false
) {
const value = getRuleViewProperty(view, "body", property).valueSpan;
const value = (
await getRuleViewProperty(view, "body", property, { wait: true })
).valueSpan;
const swatch = value.querySelector(".ruleview-colorswatch");
const cPicker = view.tooltips.getTooltip("colorPicker");

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

@ -26,7 +26,10 @@ add_task(async function() {
async function checkAngleCycling(inspector, view) {
await selectNode(".turn", inspector);
const container = getRuleViewProperty(view, ".turn", "filter").valueSpan;
const container = (
await getRuleViewProperty(view, ".turn", "filter", { wait: true })
).valueSpan;
const valueNode = container.querySelector(".ruleview-angle");
const win = view.styleWindow;
@ -59,7 +62,9 @@ async function checkAngleCycling(inspector, view) {
async function checkAngleCyclingPersist(inspector, view) {
await selectNode(".deg", inspector);
let container = getRuleViewProperty(view, ".deg", "filter").valueSpan;
let container = (
await getRuleViewProperty(view, ".deg", "filter", { wait: true })
).valueSpan;
let valueNode = container.querySelector(".ruleview-angle");
const win = view.styleWindow;
@ -79,7 +84,9 @@ async function checkAngleCyclingPersist(inspector, view) {
// We have to query for the container and the swatch because
// they've been re-generated
container = getRuleViewProperty(view, ".deg", "filter").valueSpan;
container = (
await getRuleViewProperty(view, ".deg", "filter", { wait: true })
).valueSpan;
valueNode = container.querySelector(".ruleview-angle");
is(
valueNode.textContent,

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

@ -29,7 +29,9 @@ add_task(async function() {
} = getHighlighterTestHelpers(inspector);
await selectNode("#grid", inspector);
const container = getRuleViewProperty(view, "#grid", "display").valueSpan;
const container = (
await getRuleViewProperty(view, "#grid", "display", { wait: true })
).valueSpan;
let gridToggle = container.querySelector(".js-toggle-grid-highlighter");
info("Toggling ON the CSS grid highlighter from the rule-view.");

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

@ -560,7 +560,7 @@ function getRuleViewRule(view, selectorText, index = 0) {
/**
* Get references to the name and value span nodes corresponding to a given
* selector and property name in the rule-view
* selector and property name in the rule-view.
*
* @param {CssRuleView} view
* The instance of the rule-view panel
@ -568,25 +568,38 @@ function getRuleViewRule(view, selectorText, index = 0) {
* The selector in the rule-view to look for the property in
* @param {String} propertyName
* The name of the property
* @param {Object=} options
* @param {Boolean=} options.wait
* When true, returns a promise which waits until a valid rule view
* property can be retrieved for the provided selectorText & propertyName.
* Defaults to false.
* @return {Object} An object like {nameSpan: DOMNode, valueSpan: DOMNode}
*/
function getRuleViewProperty(view, selectorText, propertyName) {
let prop;
function getRuleViewProperty(view, selectorText, propertyName, options = {}) {
if (options.wait) {
return waitFor(() =>
_syncGetRuleViewProperty(view, selectorText, propertyName)
);
}
return _syncGetRuleViewProperty(view, selectorText, propertyName);
}
function _syncGetRuleViewProperty(view, selectorText, propertyName) {
const rule = getRuleViewRule(view, selectorText);
if (rule) {
// Look for the propertyName in that rule element
for (const p of rule.querySelectorAll(".ruleview-property")) {
const nameSpan = p.querySelector(".ruleview-propertyname");
const valueSpan = p.querySelector(".ruleview-propertyvalue");
if (!rule) {
return null;
}
if (nameSpan.textContent === propertyName) {
prop = { nameSpan: nameSpan, valueSpan: valueSpan };
break;
}
// Look for the propertyName in that rule element
for (const p of rule.querySelectorAll(".ruleview-property")) {
const nameSpan = p.querySelector(".ruleview-propertyname");
const valueSpan = p.querySelector(".ruleview-propertyvalue");
if (nameSpan.textContent === propertyName) {
return { nameSpan: nameSpan, valueSpan: valueSpan };
}
}
return prop;
return null;
}
/**

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

@ -309,3 +309,12 @@
outline: 1px solid var(--theme-contrast-border);
border-radius: 2px;
}
.cm-non-printable-char {
color: var(--theme-comment);
font-size: 0.9em;
border-radius: 2px;
outline: 1px solid currentColor;
margin-inline: 2px;
padding-inline: 2px;
}

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

@ -161,6 +161,24 @@ function Editor(config) {
maxHighlightLength: 1000,
// Disable codeMirror setTimeout-based cursor blinking (will be replaced by a CSS animation)
cursorBlinkRate: 0,
// List of non-printable chars that will be displayed in the editor, showing their
// unicode version. We only add a few characters to the default list:
// - \u202d LEFT-TO-RIGHT OVERRIDE
// - \u202e RIGHT-TO-LEFT OVERRIDE
// - \u2066 LEFT-TO-RIGHT ISOLATE
// - \u2067 RIGHT-TO-LEFT ISOLATE
// - \u2069 POP DIRECTIONAL ISOLATE
// eslint-disable-next-line no-control-regex
specialChars: /[\u0000-\u001f\u007f-\u009f\u00ad\u061c\u200b-\u200f\u2028\u2029\u202d\u202e\u2066\u2067\u2069\ufeff\ufff9-\ufffc]/,
specialCharPlaceholder: char => {
// Use the doc provided to the setup function if we don't have a reference to a codeMirror
// editor yet (this can happen when an Editor is being created with existing content)
const doc = this._ownerDoc;
const el = doc.createElement("span");
el.classList.add("cm-non-printable-char");
el.append(doc.createTextNode(`\\u${char.codePointAt(0).toString(16)}`));
return el;
},
};
// Additional shortcuts.
@ -353,7 +371,7 @@ Editor.prototype = {
* configure CodeMirror with all the right options/modes/etc.
*/
_setup: function(el, doc) {
doc = doc || el.ownerDocument;
this._ownerDoc = doc || el.ownerDocument;
const win = el.ownerDocument.defaultView;
Services.scriptloader.loadSubScript(CM_BUNDLE, win);
@ -421,7 +439,7 @@ Editor.prototype = {
let popup = this.config.contextMenu;
if (typeof popup == "string") {
popup = doc.getElementById(this.config.contextMenu);
popup = this._ownerDoc.getElementById(this.config.contextMenu);
}
this.emit("popupOpen", ev, popup);
@ -1433,6 +1451,7 @@ Editor.prototype = {
this.container = null;
this.config = null;
this.version = null;
this._ownerDoc = null;
if (this._prefObserver) {
this._prefObserver.off(KEYMAP_PREF, this.setKeyMap);

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

@ -57,5 +57,19 @@ async function test() {
ed.setFontSize(ed.getFontSize() + 1);
is(ed.getFontSize(), size + 1, "new font size was set");
info("Check that we display unicode values for non-printable characters");
ed.setText("> \u202e \u2066 - \u2069 \u2066 <");
const doc = win.document.querySelector("iframe").contentWindow.document;
const nonPrintableCharElements = Array.from(
doc.querySelectorAll(".cm-non-printable-char")
);
Assert.deepEqual(
nonPrintableCharElements.map(el => el.textContent),
["\\u202e", "\\u2066", "\\u2069", "\\u2066"],
"non printable chars are displayed as expected"
);
teardown(ed, win);
}

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

@ -0,0 +1,15 @@
<html class="reftest-wait">
<head>
<script>
function test() {
let ac = new AbortController();
scheduler.postTask(()=> { ac.abort(); throw "Foobar"; }, { signal: ac.signal });
scheduler.postTask(()=> document.documentElement.removeAttribute('class'));
}
</script>
<style>
</style>
</head>
<body onload="test()">
</body>
</html>

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

@ -267,3 +267,4 @@ skip-if(ThreadSanitizer||Android) load 1712198.html # Mysterious failure that sh
skip-if(Android) HTTP load 1728670-1.html
load 1757923.html
load 1766472.html
load 1780790.html

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

@ -4633,8 +4633,7 @@ IPCResult ContentChild::RecvFlushFOGData(FlushFOGDataResolver&& aResolver) {
}
IPCResult ContentChild::RecvUpdateMediaCodecsSupported(
RemoteDecodeIn aLocation,
const PDMFactory::MediaCodecsSupported& aSupported) {
RemoteDecodeIn aLocation, const media::MediaCodecsSupported& aSupported) {
RemoteDecoderManagerChild::SetSupported(aLocation, aSupported);
return IPC_OK();

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

@ -803,8 +803,7 @@ class ContentChild final : public PContentChild,
mozilla::ipc::IPCResult RecvFlushFOGData(FlushFOGDataResolver&& aResolver);
mozilla::ipc::IPCResult RecvUpdateMediaCodecsSupported(
RemoteDecodeIn aLocation,
const PDMFactory::MediaCodecsSupported& aSupported);
RemoteDecodeIn aLocation, const media::MediaCodecsSupported& aSupported);
#ifdef NIGHTLY_BUILD
virtual void OnChannelReceivedMessage(const Message& aMsg) override;

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

@ -363,8 +363,7 @@ namespace dom {
LazyLogModule gProcessLog("Process");
static std::map<RemoteDecodeIn, PDMFactory::MediaCodecsSupported>
sCodecsSupported;
static std::map<RemoteDecodeIn, media::MediaCodecsSupported> sCodecsSupported;
/* static */
uint32_t ContentParent::sMaxContentProcesses = 0;
@ -1632,12 +1631,21 @@ void ContentParent::BroadcastThemeUpdate(widget::ThemeChangeKind aKind) {
/*static */
void ContentParent::BroadcastMediaCodecsSupportedUpdate(
RemoteDecodeIn aLocation,
const PDMFactory::MediaCodecsSupported& aSupported) {
sCodecsSupported[aLocation] = aSupported;
RemoteDecodeIn aLocation, const media::MediaCodecsSupported& aSupported) {
// Merge incoming codec support with existing support list
media::MCSInfo::AddSupport(aSupported);
auto support = media::MCSInfo::GetSupport();
// Update processes
sCodecsSupported[aLocation] = support;
for (auto* cp : AllProcesses(eAll)) {
Unused << cp->SendUpdateMediaCodecsSupported(aLocation, aSupported);
Unused << cp->SendUpdateMediaCodecsSupported(aLocation, support);
}
// Generate + save support string for display in about:support
nsCString supportString;
media::MCSInfo::GetMediaCodecsSupportedString(supportString, support);
gfx::gfxVars::SetCodecSupportInfo(supportString);
}
const nsACString& ContentParent::GetRemoteType() const { return mRemoteType; }

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

@ -254,8 +254,7 @@ class ContentParent final : public PContentParent,
static void BroadcastThemeUpdate(widget::ThemeChangeKind);
static void BroadcastMediaCodecsSupportedUpdate(
RemoteDecodeIn aLocation,
const PDMFactory::MediaCodecsSupported& aSupported);
RemoteDecodeIn aLocation, const media::MediaCodecsSupported& aSupported);
const nsACString& GetRemoteType() const override;

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

@ -148,7 +148,7 @@ using mozilla::PermissionDelegateHandler::DelegatedPermissionList from "mozilla/
using class mozilla::dom::SessionHistoryInfo from "mozilla/dom/SessionHistoryEntry.h";
using struct nsPoint from "nsPoint.h";
using struct mozilla::dom::LoadingSessionHistoryInfo from "mozilla/dom/SessionHistoryEntry.h";
using mozilla::PDMFactory::MediaCodecsSupported from "PDMFactory.h";
using mozilla::media::MediaCodecsSupported from "MediaCodecsSupport.h";
using mozilla::RemoteDecodeIn from "mozilla/RemoteDecoderManagerChild.h";
using mozilla::dom::PerformanceTimingData from "mozilla/dom/PerformanceTiming.h";
[RefCounted] using mozilla::dom::FeaturePolicy from "mozilla/dom/FeaturePolicy.h";

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

@ -13,7 +13,8 @@ namespace mozilla {
/* static */
bool ADTSDecoder::IsEnabled() {
RefPtr<PDMFactory> platform = new PDMFactory();
return platform->SupportsMimeType("audio/mp4a-latm"_ns);
return platform->SupportsMimeType("audio/mp4a-latm"_ns) !=
media::DecodeSupport::Unsupported;
}
/* static */

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

@ -1164,7 +1164,8 @@ void MediaFormatReader::OnDemuxerInitDone(const MediaResult& aResult) {
UniquePtr<TrackInfo> videoInfo = mVideo.mTrackDemuxer->GetInfo();
videoActive = videoInfo && videoInfo->IsValid();
if (videoActive) {
if (platform && !platform->SupportsMimeType(videoInfo->mMimeType)) {
if (platform && platform->SupportsMimeType(videoInfo->mMimeType) ==
media::DecodeSupport::Unsupported) {
// We have no decoder for this track. Error.
mMetadataPromise.Reject(NS_ERROR_DOM_MEDIA_METADATA_ERR, __func__);
return;
@ -1195,7 +1196,8 @@ void MediaFormatReader::OnDemuxerInitDone(const MediaResult& aResult) {
// We actively ignore audio tracks that we know we can't play.
audioActive =
audioInfo && audioInfo->IsValid() &&
(!platform || platform->SupportsMimeType(audioInfo->mMimeType));
(!platform || platform->SupportsMimeType(audioInfo->mMimeType) !=
media::DecodeSupport::Unsupported);
if (audioActive) {
mInfo.mAudio = *audioInfo->GetAsAudioInfo();

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

@ -0,0 +1,158 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "gtest/gtest.h"
#include "MediaCodecsSupport.h"
using namespace mozilla;
using namespace media;
// Test MCSInfo::GetDecodeSupportSet function.
// This function is used to retrieve SW/HW support information for a
// given codec from a MediaCodecsSupported EnumSet.
// We validate that SW, HW, SW+HW, or lack of support information is
// properly returned.
TEST(MediaCodecsSupport, GetDecodeSupportSet)
{
// Mock VP8 SW support, VP9 HW support, H264 SW+HW support
MediaCodecsSupported supported{MediaCodecsSupport::VP8SoftwareDecode,
MediaCodecsSupport::VP9HardwareDecode,
MediaCodecsSupport::H264SoftwareDecode,
MediaCodecsSupport::H264HardwareDecode};
MediaCodec codec; // Codec used to generate + filter results
DecodeSupportSet RV; // Return value to check for validity
// Check only SW support returned for VP8
codec = MediaCodec::VP8;
RV = MCSInfo::GetDecodeSupportSet(codec, supported);
EXPECT_TRUE(RV.contains(DecodeSupport::SoftwareDecode));
EXPECT_TRUE(RV.size() == 1);
// Check only HW support returned for VP9
codec = MediaCodec::VP9;
RV = MCSInfo::GetDecodeSupportSet(codec, supported);
EXPECT_TRUE(RV.contains(DecodeSupport::HardwareDecode));
EXPECT_TRUE(RV.size() == 1);
// Check for both SW/HW support returned for H264
codec = MediaCodec::H264;
RV = MCSInfo::GetDecodeSupportSet(codec, supported);
EXPECT_TRUE(RV.contains(DecodeSupport::SoftwareDecode));
EXPECT_TRUE(RV.contains(DecodeSupport::HardwareDecode));
EXPECT_TRUE(RV.size() == 2);
// Check empty return if codec not in list of codecs
codec = MediaCodec::AV1;
RV = MCSInfo::GetDecodeSupportSet(codec, supported);
EXPECT_TRUE(RV.size() == 0);
}
// Test MCSInfo::GetDecodeMediaCodecsSupported function.
// This function is used to generate codec-specific SW/HW
// support information from a generic codec identifier enum and
// generic SW/HW support information.
// We validate that SW, HW, SW+HW, or lack of support information is
// properly returned.
TEST(MediaCodecsSupport, GetDecodeMediaCodecsSupported)
{
MediaCodec codec; // Codec used to generate / filter results
MediaCodecsSupported RV; // Return value to check for validity
DecodeSupportSet dss; // Non codec-specific SW / HW support information
// Check SW support returned for VP8
codec = MediaCodec::VP8;
dss = DecodeSupportSet{DecodeSupport::SoftwareDecode};
RV = MCSInfo::GetDecodeMediaCodecsSupported(codec, dss);
EXPECT_TRUE(RV.contains(MediaCodecsSupport::VP8SoftwareDecode));
EXPECT_TRUE(RV.size() == 1);
// Check HW support returned for AV1
codec = MediaCodec::AV1;
dss = DecodeSupportSet{DecodeSupport::HardwareDecode};
RV = MCSInfo::GetDecodeMediaCodecsSupported(codec, dss);
EXPECT_TRUE(RV.contains(MediaCodecsSupport::AV1HardwareDecode));
EXPECT_TRUE(RV.size() == 1);
// Check SW + HW support returned for VP9
codec = MediaCodec::VP9;
dss = DecodeSupportSet{DecodeSupport::SoftwareDecode,
DecodeSupport::HardwareDecode};
RV = MCSInfo::GetDecodeMediaCodecsSupported(codec, dss);
EXPECT_TRUE(RV.contains(MediaCodecsSupport::VP9SoftwareDecode));
EXPECT_TRUE(RV.contains(MediaCodecsSupport::VP9HardwareDecode));
EXPECT_TRUE(RV.size() == 2);
// Check empty return if codec not supported
codec = MediaCodec::AV1;
dss = DecodeSupportSet{};
RV = MCSInfo::GetDecodeMediaCodecsSupported(codec, dss);
EXPECT_TRUE(RV.size() == 0);
}
// Test MCSInfo::AddSupport function.
// This function is used to store codec support data.
// Incoming support data will be merged with any data that
// has already been stored.
TEST(MediaCodecsSupport, AddSupport)
{
// Make sure we're not storing any existing support information.
MCSInfo::ResetSupport();
EXPECT_TRUE(MCSInfo::GetSupport().size() == 0);
// Add codec support one at a time via individual calls
MCSInfo::AddSupport(MediaCodecsSupport::AACSoftwareDecode);
MCSInfo::AddSupport(MediaCodecsSupport::VP9SoftwareDecode);
MCSInfo::AddSupport(MediaCodecsSupport::AV1HardwareDecode);
// Add multiple codec support via MediaCodecsSupported EnumSet
MCSInfo::AddSupport(
MediaCodecsSupported{MediaCodecsSupport::H264SoftwareDecode,
MediaCodecsSupport::H264HardwareDecode});
// Query MCSInfo for supported codecs
MediaCodecsSupported supported = MCSInfo::GetSupport();
DecodeSupportSet dss;
// AAC should only report software decode support
dss = MCSInfo::GetDecodeSupportSet(MediaCodec::AAC, supported);
EXPECT_TRUE(dss.size() == 1);
EXPECT_TRUE(dss.contains(DecodeSupport::SoftwareDecode));
// AV1 should only report hardware decode support
dss = MCSInfo::GetDecodeSupportSet(MediaCodec::AV1, supported);
EXPECT_TRUE(dss.size() == 1);
EXPECT_TRUE(dss.contains(DecodeSupport::HardwareDecode));
// H264 should report both SW + HW decode support
dss = MCSInfo::GetDecodeSupportSet(MediaCodec::H264, supported);
EXPECT_TRUE(dss.size() == 2);
EXPECT_TRUE(dss.contains(DecodeSupport::SoftwareDecode));
EXPECT_TRUE(dss.contains(DecodeSupport::HardwareDecode));
// Vorbis should report no decode support
dss = MCSInfo::GetDecodeSupportSet(MediaCodec::Vorbis, supported);
EXPECT_TRUE(dss.size() == 0);
}
// Test MCSInfo::GetMediaCodecsSupportedString function.
// This function returns a human-readable string containing codec
// names and SW/HW playback support information.
TEST(MediaCodecsSupport, GetMediaCodecsSupportedString)
{
// Make sure we're not storing any existing support information.
MCSInfo::ResetSupport();
EXPECT_TRUE(MCSInfo::GetSupport().size() == 0);
// Add H264 SW/HW support + VP8 Software decode support.
MCSInfo::AddSupport({MediaCodecsSupport::H264SoftwareDecode,
MediaCodecsSupport::H264HardwareDecode,
MediaCodecsSupport::VP8SoftwareDecode});
nsCString supportString;
MCSInfo::GetMediaCodecsSupportedString(supportString, MCSInfo::GetSupport());
EXPECT_TRUE(supportString.Equals(
"Codec support information:\nH264 SW\nH264 HW\nVP8 SW"_ns));
}

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

@ -46,6 +46,7 @@ UNIFIED_SOURCES += [
"TestGroupId.cpp",
"TestIntervalSet.cpp",
"TestKeyValueStorage.cpp",
"TestMediaCodecsSupport.cpp",
"TestMediaDataDecoder.cpp",
"TestMediaDataEncoder.cpp",
"TestMediaEventSource.cpp",

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

@ -18,7 +18,7 @@ include protocol PSandboxTesting;
include "mozilla/ipc/ByteBufUtils.h";
using mozilla::dom::NativeThreadId from "mozilla/dom/NativeThreadId.h";
using mozilla::PDMFactory::MediaCodecsSupported from "PDMFactory.h";
using mozilla::media::MediaCodecsSupported from "MediaCodecsSupport.h";
#if defined(XP_WIN)
[MoveOnly] using mozilla::UntrustedModulesData from "mozilla/UntrustedModulesData.h";

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

@ -142,7 +142,7 @@ mozilla::ipc::IPCResult RDDChild::RecvGetModulesTrust(
#endif // defined(XP_WIN)
mozilla::ipc::IPCResult RDDChild::RecvUpdateMediaCodecsSupported(
const PDMFactory::MediaCodecsSupported& aSupported) {
const media::MediaCodecsSupported& aSupported) {
dom::ContentParent::BroadcastMediaCodecsSupportedUpdate(
RemoteDecodeIn::RddProcess, aSupported);
return IPC_OK();

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

@ -47,7 +47,7 @@ class RDDChild final : public PRDDChild,
GetModulesTrustResolver&& aResolver);
#endif // defined(XP_WIN)
mozilla::ipc::IPCResult RecvUpdateMediaCodecsSupported(
const PDMFactory::MediaCodecsSupported& aSupported);
const media::MediaCodecsSupported& aSupported);
mozilla::ipc::IPCResult RecvFOGData(ByteBuf&& aBuf);
bool SendRequestMemoryReport(const uint32_t& aGeneration,

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

@ -58,12 +58,12 @@ static StaticRefPtr<RemoteDecoderManagerChild>
sRemoteDecoderManagerChildForGPUProcess;
static UniquePtr<nsTArray<RefPtr<Runnable>>> sRecreateTasks;
static StaticDataMutex<Maybe<PDMFactory::MediaCodecsSupported>> sGPUSupported(
static StaticDataMutex<Maybe<media::MediaCodecsSupported>> sGPUSupported(
"RDMC::sGPUSupported");
static StaticDataMutex<Maybe<PDMFactory::MediaCodecsSupported>> sRDDSupported(
static StaticDataMutex<Maybe<media::MediaCodecsSupported>> sRDDSupported(
"RDMC::sRDDSupported");
static StaticDataMutex<Maybe<PDMFactory::MediaCodecsSupported>>
sUtilitySupported("RDMC::sUtilitySupported");
static StaticDataMutex<Maybe<media::MediaCodecsSupported>> sUtilitySupported(
"RDMC::sUtilitySupported");
class ShutdownObserver final : public nsIObserver {
public:
@ -226,7 +226,7 @@ nsISerialEventTarget* RemoteDecoderManagerChild::GetManagerThread() {
bool RemoteDecoderManagerChild::Supports(
RemoteDecodeIn aLocation, const SupportDecoderParams& aParams,
DecoderDoctorDiagnostics* aDiagnostics) {
Maybe<PDMFactory::MediaCodecsSupported> supported;
Maybe<media::MediaCodecsSupported> supported;
switch (aLocation) {
case RemoteDecodeIn::RddProcess: {
auto supportedRDD = sRDDSupported.Lock();
@ -264,7 +264,8 @@ bool RemoteDecoderManagerChild::Supports(
// We can ignore the SupportDecoderParams argument for now as creation of the
// decoder will actually fail later and fallback PDMs will be tested on later.
return PDMFactory::SupportsMimeType(aParams.MimeType(), *supported,
aLocation);
aLocation) !=
media::DecodeSupport::Unsupported;
}
/* static */
@ -797,8 +798,7 @@ void RemoteDecoderManagerChild::HandleFatalError(const char* aMsg) const {
}
void RemoteDecoderManagerChild::SetSupported(
RemoteDecodeIn aLocation,
const PDMFactory::MediaCodecsSupported& aSupported) {
RemoteDecodeIn aLocation, const media::MediaCodecsSupported& aSupported) {
switch (aLocation) {
case RemoteDecodeIn::GpuProcess: {
auto supported = sGPUSupported.Lock();

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

@ -41,7 +41,7 @@ class RemoteDecoderManagerChild final
static void Init();
static void SetSupported(RemoteDecodeIn aLocation,
const PDMFactory::MediaCodecsSupported& aSupported);
const media::MediaCodecsSupported& aSupported);
// Can be called from any thread.
static bool Supports(RemoteDecodeIn aLocation,

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

@ -255,7 +255,8 @@ already_AddRefed<Promise> MediaCapabilities::DecodingInfo(
InvokeAsync(taskQueue, __func__, [config = std::move(config)]() {
RefPtr<PDMFactory> pdm = new PDMFactory();
SupportDecoderParams params{*config};
if (!pdm->Supports(params, nullptr /* decoder doctor */)) {
if (pdm->Supports(params, nullptr /* decoder doctor */) ==
media::DecodeSupport::Unsupported) {
return CapabilitiesPromise::CreateAndReject(NS_ERROR_FAILURE,
__func__);
}

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

@ -13,7 +13,8 @@ namespace mozilla {
/* static */
bool MP3Decoder::IsEnabled() {
RefPtr<PDMFactory> platform = new PDMFactory();
return platform->SupportsMimeType("audio/mpeg"_ns);
return platform->SupportsMimeType("audio/mpeg"_ns) !=
media::DecodeSupport::Unsupported;
}
/* static */

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

@ -154,7 +154,8 @@ bool MP4Decoder::IsSupportedType(const MediaContainerType& aType,
RefPtr<PDMFactory> platform = new PDMFactory();
for (const auto& track : tracks) {
if (!track ||
!platform->Supports(SupportDecoderParams(*track), aDiagnostics)) {
platform->Supports(SupportDecoderParams(*track), aDiagnostics) ==
media::DecodeSupport::Unsupported) {
return false;
}
}
@ -183,7 +184,8 @@ bool MP4Decoder::IsSupportedType(const MediaContainerType& aType,
RefPtr<PDMFactory> platform = new PDMFactory();
for (const auto& track : tracks) {
if (track &&
platform->Supports(SupportDecoderParams(*track), aDiagnostics)) {
platform->Supports(SupportDecoderParams(*track), aDiagnostics) !=
media::DecodeSupport::Unsupported) {
return true;
}
}

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

@ -0,0 +1,175 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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 <array>
#include "MediaCodecsSupport.h"
#include "PlatformDecoderModule.h"
#include "mozilla/gfx/gfxVars.h"
#include "nsTHashMap.h"
using MediaCodecsSupport = mozilla::media::MediaCodecsSupport;
namespace mozilla::media {
#define CODEC_SUPPORT_LOG(msg, ...) \
MOZ_LOG(sPDMLog, LogLevel::Debug, ("MediaCodecsSupport, " msg, ##__VA_ARGS__))
void MCSInfo::AddSupport(const MediaCodecsSupported& aSupport) {
StaticMutexAutoLock lock(sUpdateMutex);
GetInstance()->mSupport += aSupport;
}
MediaCodecsSupported MCSInfo::GetSupport() {
StaticMutexAutoLock lock(sUpdateMutex);
return GetInstance()->mSupport;
}
void MCSInfo::ResetSupport() {
StaticMutexAutoLock lock(sUpdateMutex);
GetInstance()->mSupport.clear();
}
DecodeSupportSet MCSInfo::GetDecodeSupportSet(
const MediaCodec& aCodec, const MediaCodecsSupported& aSupported) {
DecodeSupportSet support;
const auto supportInfo = GetCodecDefinition(aCodec);
if (aSupported.contains(supportInfo.swDecodeSupport)) {
support += DecodeSupport::SoftwareDecode;
}
if (aSupported.contains(supportInfo.hwDecodeSupport)) {
support += DecodeSupport::HardwareDecode;
}
return support;
}
MediaCodecsSupported MCSInfo::GetDecodeMediaCodecsSupported(
const MediaCodec& aCodec, const DecodeSupportSet& aSupportSet) {
MediaCodecsSupported support;
const auto supportInfo = GetCodecDefinition(aCodec);
if (aSupportSet.contains(DecodeSupport::SoftwareDecode)) {
support += supportInfo.swDecodeSupport;
}
if (aSupportSet.contains(DecodeSupport::HardwareDecode)) {
support += supportInfo.hwDecodeSupport;
}
return support;
}
void MCSInfo::GetMediaCodecsSupportedString(
nsCString& aSupportString, const MediaCodecsSupported& aSupportedCodecs) {
CodecDefinition supportInfo;
aSupportString = "Codec support information:\n"_ns;
for (const auto& it : aSupportedCodecs) {
if (!GetInstance()->mHashTableMCS->Get(it, &supportInfo)) {
CODEC_SUPPORT_LOG(
"Could not find string matching MediaCodecsSupported enum: %d",
static_cast<int>(it));
aSupportString.Append("Unknown codec entry found!\n"_ns);
continue;
}
// Get codec name string and append SW/HW support info
aSupportString.Append(supportInfo.commonName);
if (it == supportInfo.swDecodeSupport) {
aSupportString.Append(" SW"_ns);
}
if (it == supportInfo.hwDecodeSupport) {
aSupportString.Append(" HW"_ns);
}
aSupportString.Append("\n"_ns);
}
// Remove any trailing newline characters
if (!aSupportString.IsEmpty()) {
aSupportString.Truncate(aSupportString.Length() - 1);
}
}
MCSInfo* MCSInfo::GetInstance() {
StaticMutexAutoLock lock(sInitMutex);
if (!sInstance) {
sInstance.reset(new MCSInfo());
}
return sInstance.get();
}
MCSInfo::MCSInfo() {
// Initialize hash tables
mHashTableMCS.reset(new nsTHashMap<MediaCodecsSupport, CodecDefinition>());
mHashTableCodec.reset(new nsTHashMap<MediaCodec, CodecDefinition>());
for (const auto& it : GetAllCodecDefinitions()) {
// Insert MediaCodecsSupport values as keys
mHashTableMCS->InsertOrUpdate(it.swDecodeSupport, it);
mHashTableMCS->InsertOrUpdate(it.hwDecodeSupport, it);
// Insert codec enum values as keys
mHashTableCodec->InsertOrUpdate(it.codec, it);
}
GetMainThreadSerialEventTarget()->Dispatch(
NS_NewRunnableFunction("MCSInfo::MCSInfo", [&] {
// Ensure hash tables freed on shutdown
RunOnShutdown(
[&] {
mHashTableMCS.reset();
mHashTableCodec.reset();
},
ShutdownPhase::XPCOMShutdown);
}));
}
CodecDefinition MCSInfo::GetCodecDefinition(const MediaCodec& aCodec) {
CodecDefinition info;
if (!GetInstance()->mHashTableCodec->Get(aCodec, &info)) {
CODEC_SUPPORT_LOG("Could not find codec definition for codec enum: %d!",
static_cast<int>(aCodec));
}
return info;
}
std::array<CodecDefinition, 12> MCSInfo::GetAllCodecDefinitions() {
static constexpr std::array<CodecDefinition, 12> codecDefinitions = {
{{MediaCodec::H264, "H264", "video/avc",
MediaCodecsSupport::H264SoftwareDecode,
MediaCodecsSupport::H264HardwareDecode},
{MediaCodec::VP9, "VP9", "video/vp9",
MediaCodecsSupport::VP9SoftwareDecode,
MediaCodecsSupport::VP9HardwareDecode},
{MediaCodec::VP8, "VP8", "video/vp8",
MediaCodecsSupport::VP8SoftwareDecode,
MediaCodecsSupport::VP8HardwareDecode},
{MediaCodec::AV1, "AV1", "video/av1",
MediaCodecsSupport::AV1SoftwareDecode,
MediaCodecsSupport::AV1HardwareDecode},
{MediaCodec::Theora, "Theora", "video/theora",
MediaCodecsSupport::TheoraSoftwareDecode,
MediaCodecsSupport::TheoraHardwareDecode},
{MediaCodec::AAC, "AAC", "audio/mp4a-latm",
MediaCodecsSupport::AACSoftwareDecode,
MediaCodecsSupport::AACHardwareDecode},
{MediaCodec::MP3, "MP3", "audio/mpeg",
MediaCodecsSupport::MP3SoftwareDecode,
MediaCodecsSupport::MP3HardwareDecode},
{MediaCodec::Opus, "Opus", "audio/opus",
MediaCodecsSupport::OpusSoftwareDecode,
MediaCodecsSupport::OpusHardwareDecode},
{MediaCodec::Vorbis, "Vorbis", "audio/vorbis",
MediaCodecsSupport::VorbisSoftwareDecode,
MediaCodecsSupport::VorbisHardwareDecode},
{MediaCodec::FLAC, "FLAC", "audio/flac",
MediaCodecsSupport::FLACSoftwareDecode,
MediaCodecsSupport::FLACHardwareDecode},
{MediaCodec::Wave, "Wave", "audio/x-wav",
MediaCodecsSupport::WaveSoftwareDecode,
MediaCodecsSupport::WaveHardwareDecode},
{MediaCodec::SENTINEL, "Undefined codec name",
"Undefined MIME type string", MediaCodecsSupport::SENTINEL,
MediaCodecsSupport::SENTINEL}}};
return codecDefinitions;
}
} // namespace mozilla::media
#undef CODEC_SUPPORT_LOG

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

@ -5,18 +5,195 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef DOM_MEDIA_PLATFORMS_MEDIACODECSSUPPORT_H_
#define DOM_MEDIA_PLATFORMS_MEDIACODECSSUPPORT_H_
#include <array>
#include "mozilla/Atomics.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/EnumSet.h"
#include "mozilla/StaticMutex.h"
#include "nsString.h"
#include "nsTHashMap.h"
#include "nsThreadUtils.h"
namespace mozilla::media {
// List of codecs we support, used in the below macros
// to generate MediaCodec and MediaCodecSupports enums.
#define CODEC_LIST \
X(H264) \
X(VP8) \
X(VP9) \
X(AV1) \
X(Theora) \
X(AAC) \
X(FLAC) \
X(MP3) \
X(Opus) \
X(Vorbis) \
X(Wave)
enum class DecodeSupport {
// Generate MediaCodec enum with the names of each codec we support.
// Example: MediaCodec::H264
enum class MediaCodec : int {
#define X(name) name,
CODEC_LIST
#undef X
SENTINEL
};
// Helper macros used to create codec-specific SW/HW decode enums below.
#define SW_DECODE(codec) codec##SoftwareDecode
#define HW_DECODE(codec) codec##HardwareDecode
// Generate the MediaCodecsSupport enum, containing
// codec-specific SW/HW decode/encode information.
// Entries for HW audio decode/encode should never be set as we
// don't support HW audio decode/encode, but they are included
// for debug purposes / check for erroneous PDM return values.
// Example: MediaCodecsSupport::AACSoftwareDecode
enum class MediaCodecsSupport : int {
#define X(name) SW_DECODE(name), HW_DECODE(name),
CODEC_LIST
#undef X
SENTINEL
};
#undef SW_DECODE
#undef HW_DECODE
#undef CODEC_LIST // end of macros!
// Enumset containing per-codec SW/HW support
using MediaCodecsSupported = EnumSet<MediaCodecsSupport, uint64_t>;
// Codec-agnostic SW/HW decode support information.
enum class DecodeSupport : int {
Unsupported = 0,
SoftwareDecode,
HardwareDecode,
};
using DecodeSupportSet = EnumSet<DecodeSupport, uint64_t>;
// CodecDefinition stores information needed to convert / index
// codec support information between types. See: GetAllCodecDefinitions()
struct CodecDefinition {
MediaCodec codec = MediaCodec::SENTINEL;
const char* commonName = "Undefined codec name";
const char* mimeTypeString = "Undefined MIME type string";
MediaCodecsSupport swDecodeSupport = MediaCodecsSupport::SENTINEL;
MediaCodecsSupport hwDecodeSupport = MediaCodecsSupport::SENTINEL;
};
// Singleton class used to collect, manage, and report codec support data.
class MCSInfo final {
public:
// Add codec support information to our aggregated list of supported codecs.
// Incoming support info is merged with the current support info.
// This is because different PDMs may report different codec support
// information, so merging their results allows us to maintain a
// cumulative support list without overwriting any existing data.
static void AddSupport(const MediaCodecsSupported& aSupport);
// Return a cumulative list of codec support information.
// Each call to AddSupport adds to or updates this list.
// This support information can be used to create user-readable strings
// to report codec support information in about:support.
static MediaCodecsSupported GetSupport();
// Reset codec support information saved from calls to AddSupport().
static void ResetSupport();
// Query a MediaCodecsSupported EnumSet for codec-specific SW/HW support enums
// and return general support information as stored in a DecodeSupportSet.
//
// Example input:
//
// aCodec: MediaCodec::H264
// aDecode: MediaCodecsSupport {
// MediaCodecsSupport::AACSoftwareDecode
// MediaCodecsSupport::H264HardwareDecode,
// MediaCodecsSupport::H264SoftwareDecode,
// MediaCodecsSupport::VP8SoftwareDecode,
// }
//
// Example output:
//
// DecodeSupportSet {
// DecodeSupport::SoftwareDecode,
// DecodeSupport::HardwareDecode
// }
//
static DecodeSupportSet GetDecodeSupportSet(
const MediaCodec& aCodec, const MediaCodecsSupported& aSupported);
// Return codec-specific SW/HW support enums for a given codec.
// The DecodeSupportSet argument is used which codec-specific SW/HW
// support values are returned, if any.
//
// Example input:
// aCodec: MediaCodec::VP8
// aSupportSet: DecodeSupportSet {DecodeSupport::SoftwareDecode}
//
// Example output:
// MediaCodecsSupported {MediaCodecsSupport::VP8SoftwareDecode}
//
static MediaCodecsSupported GetDecodeMediaCodecsSupported(
const MediaCodec& aCodec, const DecodeSupportSet& aSupportSet);
// Generate a plaintext description for the SW/HW support information
// contained in a MediaCodecsSupported EnumSet.
//
// Example input:
// MediaCodecsSupported {
// MediaCodecsSupport::H264SoftwareDecode,
// MediaCodecsSupport::H264HardwareDecode,
// MediaCodecsSupport::VP8SoftwareDecode
// }
//
// Example output (returned via argument aCodecString)
//
// "SW H264 decode\n
// HW H264 decode\n
// SW VP8 decode"_ns
//
static void GetMediaCodecsSupportedString(
nsCString& aSupportString, const MediaCodecsSupported& aSupportedCodecs);
// Returns array of hardcoded codec definitions used to generate hashtables
// that convert between types
static std::array<CodecDefinition, 12> GetAllCodecDefinitions();
MCSInfo(MCSInfo const&) = delete;
void operator=(MCSInfo const&) = delete;
~MCSInfo() = default;
private:
MCSInfo();
static MCSInfo* GetInstance();
// Returns a codec definition by MIME type name ("media/vp9")
// or "common" name ("VP9")
static CodecDefinition GetCodecDefinition(const MediaCodec& aCodec);
static inline UniquePtr<MCSInfo> sInstance = nullptr;
static inline StaticMutex sInitMutex;
static inline StaticMutex sUpdateMutex;
UniquePtr<nsTHashMap<MediaCodecsSupport, CodecDefinition>> mHashTableMCS =
nullptr;
UniquePtr<nsTHashMap<const char*, CodecDefinition>> mHashTableString =
nullptr;
UniquePtr<nsTHashMap<MediaCodec, CodecDefinition>> mHashTableCodec = nullptr;
MediaCodecsSupported mSupport{};
};
} // namespace mozilla::media
namespace mozilla {
// Used for IPDL serialization.
// The 'value' has to be the biggest enum from MediaCodecsSupport.
template <typename T>
struct MaxEnumValue;
template <>
struct MaxEnumValue<media::MediaCodecsSupport> {
static constexpr unsigned int value =
static_cast<unsigned int>(media::MediaCodecsSupport::SENTINEL);
};
} // namespace mozilla
#endif /* MediaCodecsSupport_h_ */

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

@ -61,6 +61,13 @@
#include <functional>
using DecodeSupport = mozilla::media::DecodeSupport;
using DecodeSupportSet = mozilla::media::DecodeSupportSet;
using MediaCodec = mozilla::media::MediaCodec;
using MediaCodecsSupport = mozilla::media::MediaCodecsSupport;
using MediaCodecsSupported = mozilla::media::MediaCodecsSupported;
using MCSInfo = mozilla::media::MCSInfo;
namespace mozilla {
#define PDM_INIT_LOG(msg, ...) \
@ -440,24 +447,31 @@ PDMFactory::CreateDecoderWithPDM(PlatformDecoderModule* aPDM,
return aPDM->AsyncCreateDecoder(aParams);
}
bool PDMFactory::SupportsMimeType(const nsACString& aMimeType) const {
DecodeSupportSet PDMFactory::SupportsMimeType(
const nsACString& aMimeType) const {
UniquePtr<TrackInfo> trackInfo = CreateTrackInfoWithMIMEType(aMimeType);
if (!trackInfo) {
return false;
return DecodeSupport::Unsupported;
}
return Supports(SupportDecoderParams(*trackInfo), nullptr);
}
bool PDMFactory::Supports(const SupportDecoderParams& aParams,
DecoderDoctorDiagnostics* aDiagnostics) const {
DecodeSupportSet PDMFactory::Supports(
const SupportDecoderParams& aParams,
DecoderDoctorDiagnostics* aDiagnostics) const {
if (mEMEPDM) {
return mEMEPDM->Supports(aParams, aDiagnostics) !=
media::DecodeSupport::Unsupported;
return mEMEPDM->Supports(aParams, aDiagnostics);
}
RefPtr<PlatformDecoderModule> current =
GetDecoderModule(aParams, aDiagnostics);
return !!current;
if (!current) {
return DecodeSupport::Unsupported;
}
// We have a PDM - check for + return SW/HW support info
return current->Supports(aParams, aDiagnostics);
}
void PDMFactory::CreatePDMs() {
@ -744,7 +758,7 @@ void PDMFactory::SetCDMProxy(CDMProxy* aProxy) {
}
/* static */
PDMFactory::MediaCodecsSupported PDMFactory::Supported(bool aForceRefresh) {
media::MediaCodecsSupported PDMFactory::Supported(bool aForceRefresh) {
MOZ_ASSERT(NS_IsMainThread());
static auto calculate = []() {
@ -758,53 +772,25 @@ PDMFactory::MediaCodecsSupported PDMFactory::Supported(bool aForceRefresh) {
// available.
// This logic will have to be revisited if a PDM supporting either codec
// will be added in addition to the WMF and FFmpeg PDM (such as OpenH264)
if (pdm->SupportsMimeType("video/avc"_ns)) {
supported += MediaCodecs::H264;
}
if (pdm->SupportsMimeType("video/vp9"_ns)) {
supported += MediaCodecs::VP9;
}
if (pdm->SupportsMimeType("video/vp8"_ns)) {
supported += MediaCodecs::VP8;
}
if (pdm->SupportsMimeType("video/av1"_ns)) {
supported += MediaCodecs::AV1;
}
if (pdm->SupportsMimeType("video/theora"_ns)) {
supported += MediaCodecs::Theora;
}
if (pdm->SupportsMimeType("audio/mp4a-latm"_ns)) {
supported += MediaCodecs::AAC;
}
// MP3 can be either decoded by ffvpx or WMF/FFmpeg
if (pdm->SupportsMimeType("audio/mpeg"_ns)) {
supported += MediaCodecs::MP3;
}
if (pdm->SupportsMimeType("audio/opus"_ns)) {
supported += MediaCodecs::Opus;
}
if (pdm->SupportsMimeType("audio/vorbis"_ns)) {
supported += MediaCodecs::Vorbis;
}
if (pdm->SupportsMimeType("audio/flac"_ns)) {
supported += MediaCodecs::Flac;
}
if (pdm->SupportsMimeType("audio/x-wav"_ns)) {
supported += MediaCodecs::Wave;
for (const auto& cd : MCSInfo::GetAllCodecDefinitions()) {
supported += MCSInfo::GetDecodeMediaCodecsSupported(
cd.codec, pdm->SupportsMimeType(nsCString(cd.mimeTypeString)));
}
return supported;
};
static MediaCodecsSupported supported = calculate();
if (aForceRefresh) {
supported = calculate();
}
return supported;
}
/* static */
bool PDMFactory::SupportsMimeType(const nsACString& aMimeType,
const MediaCodecsSupported& aSupported,
RemoteDecodeIn aLocation) {
DecodeSupportSet PDMFactory::SupportsMimeType(
const nsACString& aMimeType, const MediaCodecsSupported& aSupported,
RemoteDecodeIn aLocation) {
const bool videoSupport = aLocation != RemoteDecodeIn::UtilityProcess;
const bool audioSupport = (aLocation == RemoteDecodeIn::UtilityProcess &&
StaticPrefs::media_utility_process_enabled()) ||
@ -813,45 +799,44 @@ bool PDMFactory::SupportsMimeType(const nsACString& aMimeType,
if (videoSupport) {
if (MP4Decoder::IsH264(aMimeType)) {
return aSupported.contains(MediaCodecs::H264);
return MCSInfo::GetDecodeSupportSet(MediaCodec::H264, aSupported);
}
if (VPXDecoder::IsVP9(aMimeType)) {
return aSupported.contains(MediaCodecs::VP9);
return MCSInfo::GetDecodeSupportSet(MediaCodec::VP9, aSupported);
}
if (VPXDecoder::IsVP8(aMimeType)) {
return aSupported.contains(MediaCodecs::VP8);
return MCSInfo::GetDecodeSupportSet(MediaCodec::VP8, aSupported);
}
#ifdef MOZ_AV1
if (AOMDecoder::IsAV1(aMimeType)) {
return aSupported.contains(MediaCodecs::AV1);
return MCSInfo::GetDecodeSupportSet(MediaCodec::AV1, aSupported);
}
#endif
if (TheoraDecoder::IsTheora(aMimeType)) {
return aSupported.contains(MediaCodecs::Theora);
return MCSInfo::GetDecodeSupportSet(MediaCodec::Theora, aSupported);
}
}
if (audioSupport) {
if (MP4Decoder::IsAAC(aMimeType)) {
return aSupported.contains(MediaCodecs::AAC);
return MCSInfo::GetDecodeSupportSet(MediaCodec::AAC, aSupported);
}
if (aMimeType.EqualsLiteral("audio/mpeg")) {
return aSupported.contains(MediaCodecs::MP3);
return MCSInfo::GetDecodeSupportSet(MediaCodec::MP3, aSupported);
}
if (OpusDataDecoder::IsOpus(aMimeType)) {
return aSupported.contains(MediaCodecs::Opus);
return MCSInfo::GetDecodeSupportSet(MediaCodec::Opus, aSupported);
}
if (VorbisDataDecoder::IsVorbis(aMimeType)) {
return aSupported.contains(MediaCodecs::Vorbis);
return MCSInfo::GetDecodeSupportSet(MediaCodec::Vorbis, aSupported);
}
if (aMimeType.EqualsLiteral("audio/flac")) {
return aSupported.contains(MediaCodecs::Flac);
return MCSInfo::GetDecodeSupportSet(MediaCodec::FLAC, aSupported);
}
if (WaveDataDecoder::IsWave(aMimeType)) {
return aSupported.contains(MediaCodecs::Wave);
return MCSInfo::GetDecodeSupportSet(MediaCodec::Wave, aSupported);
}
}
return false;
return DecodeSupport::Unsupported;
}
/* static */

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

@ -25,8 +25,6 @@ class CDMProxy;
class MediaDataDecoder;
class MediaResult;
class StaticMutex;
template <typename T>
struct MaxEnumValue;
struct CreateDecoderParams;
struct CreateDecoderParamsForAsync;
struct SupportDecoderParams;
@ -45,9 +43,10 @@ class PDMFactory final {
RefPtr<PDMCreateDecoderPromise> CreateDecoder(
const CreateDecoderParams& aParams);
bool SupportsMimeType(const nsACString& aMimeType) const;
bool Supports(const SupportDecoderParams& aParams,
DecoderDoctorDiagnostics* aDiagnostics) const;
media::DecodeSupportSet SupportsMimeType(const nsACString& aMimeType) const;
media::DecodeSupportSet Supports(
const SupportDecoderParams& aParams,
DecoderDoctorDiagnostics* aDiagnostics) const;
// Creates a PlatformDecoderModule that uses a CDMProxy to decrypt or
// decrypt-and-decode EME encrypted content. If the CDM only decrypts and
@ -61,31 +60,10 @@ class PDMFactory final {
static constexpr int kYUV422 = 2;
static constexpr int kYUV444 = 3;
/*
* All the codecs we support
*/
enum class MediaCodecs {
H264,
VP9,
VP8,
AV1,
Theora,
AAC,
MP3,
Opus,
Vorbis,
Flac,
Wave,
SENTINEL,
};
using MediaCodecsSupported = EnumSet<MediaCodecs>;
static MediaCodecsSupported Supported(bool aForceRefresh = false);
static bool SupportsMimeType(const nsACString& aMimeType,
const MediaCodecsSupported& aSupported,
RemoteDecodeIn aLocation);
static media::MediaCodecsSupported Supported(bool aForceRefresh = false);
static media::DecodeSupportSet SupportsMimeType(
const nsACString& aMimeType,
const media::MediaCodecsSupported& aSupported, RemoteDecodeIn aLocation);
static bool AllDecodersAreRemote();
@ -129,14 +107,6 @@ class PDMFactory final {
static void EnsureInit();
};
// Used for IPDL serialization.
// The 'value' have to be the biggest enum from MediaCodecs.
template <>
struct MaxEnumValue<PDMFactory::MediaCodecs> {
static constexpr unsigned int value =
static_cast<unsigned int>(PDMFactory::MediaCodecs::SENTINEL);
};
} // namespace mozilla
#endif /* PDMFactory_h_ */

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

@ -5,6 +5,7 @@
#include "AndroidDataEncoder.h"
#include "AnnexB.h"
#include "H264.h"
#include "MediaData.h"
#include "MediaInfo.h"
#include "SimpleMap.h"
@ -170,9 +171,9 @@ RefPtr<MediaDataEncoder::EncodePromise> AndroidDataEncoder<ConfigType>::Encode(
static jni::ByteBuffer::LocalRef ConvertI420ToNV12Buffer(
RefPtr<const VideoData> aSample, RefPtr<MediaByteBuffer>& aYUVBuffer) {
const PlanarYCbCrImage* image = aSample->mImage->AsPlanarYCbCrImage();
const layers::PlanarYCbCrImage* image = aSample->mImage->AsPlanarYCbCrImage();
MOZ_ASSERT(image);
const PlanarYCbCrData* yuv = image->GetData();
const layers::PlanarYCbCrData* yuv = image->GetData();
auto ySize = yuv->YDataSize();
auto cbcrSize = yuv->CbCrDataSize();
size_t yLength = yuv->mYStride * ySize.height;

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

@ -38,6 +38,7 @@ UNIFIED_SOURCES += [
"agnostic/VPXDecoder.cpp",
"agnostic/WAVDecoder.cpp",
"AllocationPolicy.cpp",
"MediaCodecsSupport.cpp",
"PDMFactory.cpp",
"PEMFactory.cpp",
"PlatformDecoderModule.cpp",

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

@ -335,9 +335,13 @@ media::DecodeSupportSet WMFDecoderModule::Supports(
}
if (CanCreateMFTDecoder(type)) {
// TODO: Note that we do not yet distinguish between SW/HW decode support.
// Will be done in bug 1754239.
return media::DecodeSupport::SoftwareDecode;
if (StreamTypeIsVideo(type)) {
return sDXVAEnabled ? media::DecodeSupport::HardwareDecode
: media::DecodeSupport::SoftwareDecode;
} else {
// Audio only supports software decode
return media::DecodeSupport::SoftwareDecode;
}
}
return media::DecodeSupport::Unsupported;
@ -430,17 +434,13 @@ media::DecodeSupportSet WMFDecoderModule::SupportsMimeType(
if (!trackInfo) {
return media::DecodeSupport::Unsupported;
}
bool supports = Supports(SupportDecoderParams(*trackInfo), aDiagnostics) !=
media::DecodeSupport::Unsupported;
MOZ_LOG(sPDMLog, LogLevel::Debug,
("WMF decoder %s requested type '%s'",
supports ? "supports" : "rejects", aMimeType.BeginReading()));
if (!supports) {
return media::DecodeSupport::Unsupported;
}
// TODO: Note that we do not yet distinguish between SW/HW decode support.
// Will be done in bug 1754239.
return media::DecodeSupport::SoftwareDecode;
auto supports = Supports(SupportDecoderParams(*trackInfo), aDiagnostics);
MOZ_LOG(
sPDMLog, LogLevel::Debug,
("WMF decoder %s requested type '%s'",
supports != media::DecodeSupport::Unsupported ? "supports" : "rejects",
aMimeType.BeginReading()));
return supports;
}
} // namespace mozilla

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

@ -170,7 +170,7 @@ steps we run before each video. We keep track of which test we are running with
});
}
SpecialPowers.pushPrefEnv({"set": [["media.video_stats.enabled", true]]},
SpecialPowers.pushPrefEnv({"set": [["media.video_stats.enabled", true], ["gfx.core-animation.specialize-video", true]]},
async function() {
// Clear out existing telemetry in case previous tests were displaying
// video.

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

@ -265,7 +265,8 @@ void MediaDecodeTask::OnInitDemuxerCompleted() {
UniquePtr<TrackInfo> audioInfo = mTrackDemuxer->GetInfo();
// We actively ignore audio tracks that we know we can't play.
if (audioInfo && audioInfo->IsValid() &&
platform->SupportsMimeType(audioInfo->mMimeType)) {
platform->SupportsMimeType(audioInfo->mMimeType) !=
media::DecodeSupport::Unsupported) {
mMediaInfo.mAudio = *audioInfo->GetAsAudioInfo();
}
}

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

@ -104,8 +104,9 @@ bool WebMDecoder::IsSupportedType(const MediaContainerType& aContainerType) {
// color depth
RefPtr<PDMFactory> platform = new PDMFactory();
for (const auto& track : tracks) {
if (!track || !platform->Supports(SupportDecoderParams(*track),
nullptr /* diagnostic */)) {
if (!track || platform->Supports(SupportDecoderParams(*track),
nullptr /* diagnostic */) ==
media::DecodeSupport::Unsupported) {
return false;
}
}

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

@ -60,7 +60,7 @@ WebrtcVideoDecoder* MediaDataCodec::CreateDecoder(
return nullptr;
}
RefPtr<PDMFactory> pdm = new PDMFactory();
if (!pdm->SupportsMimeType(codec)) {
if (pdm->SupportsMimeType(codec) == media::DecodeSupport::Unsupported) {
return nullptr;
}

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

@ -102,19 +102,19 @@ bool WebTask::Run() {
error.WouldReportJSException();
#ifdef DEBUG
Promise::PromiseState promiseState = mPromise->State();
// If the state is Rejected, it means the above Call triggers the
// RunAbortAlgorithm method and rejected the promise
MOZ_ASSERT_IF(promiseState != Promise::PromiseState::Pending,
promiseState == Promise::PromiseState::Rejected);
#endif
if (promiseState == Promise::PromiseState::Pending) {
if (error.Failed()) {
mPromise->MaybeReject(std::move(error));
} else {
mPromise->MaybeResolve(returnVal);
}
if (error.Failed()) {
mPromise->MaybeReject(std::move(error));
} else {
mPromise->MaybeResolve(returnVal);
}
MOZ_ASSERT(!isInList());

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

@ -84,6 +84,7 @@ class gfxVarReceiver;
_(UseEGL, bool, false) \
_(DrmRenderDevice, nsCString, nsCString()) \
_(UseDMABuf, bool, false) \
_(CodecSupportInfo, nsCString, nsCString()) \
_(WebRenderRequiresHardwareDriver, bool, false) \
_(SupportsThreadsafeGL, bool, false) \
_(OffscreenCanvasDomainAllowlist, nsCString, nsCString()) \

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

@ -326,7 +326,7 @@ mozilla::ipc::IPCResult GPUChild::RecvBHRThreadHang(
}
mozilla::ipc::IPCResult GPUChild::RecvUpdateMediaCodecsSupported(
const PDMFactory::MediaCodecsSupported& aSupported) {
const media::MediaCodecsSupported& aSupported) {
dom::ContentParent::BroadcastMediaCodecsSupportedUpdate(
RemoteDecodeIn::GpuProcess, aSupported);
return IPC_OK();

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

@ -79,7 +79,7 @@ class GPUChild final : public ipc::CrashReporterHelper<GeckoProcessType_GPU>,
const nsCString& aMessage);
mozilla::ipc::IPCResult RecvBHRThreadHang(const HangDetails& aDetails);
mozilla::ipc::IPCResult RecvUpdateMediaCodecsSupported(
const PDMFactory::MediaCodecsSupported& aSupported);
const media::MediaCodecsSupported& aSupported);
mozilla::ipc::IPCResult RecvFOGData(ByteBuf&& aBuf);
bool SendRequestMemoryReport(const uint32_t& aGeneration,

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

@ -37,7 +37,7 @@ using mozilla::gfx::Feature from "gfxFeature.h";
using mozilla::gfx::Fallback from "gfxFallback.h";
using mozilla::layers::LayersId from "mozilla/layers/LayersTypes.h";
using mozilla::layers::OverlayInfo from "mozilla/layers/OverlayInfo.h";
using mozilla::PDMFactory::MediaCodecsSupported from "PDMFactory.h";
using mozilla::media::MediaCodecsSupported from "MediaCodecsSupport.h";
namespace mozilla {
namespace gfx {

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

@ -154,6 +154,9 @@ class MockGfxInfo final : public nsIGfxInfo {
NS_IMETHOD GetTargetFrameRate(uint32_t* aTargetFrameRate) override {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHOD GetCodecSupportInfo(nsACString& aCodecSupportInfo) override {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHOD GetD2DEnabled(bool* aD2DEnabled) override {
return NS_ERROR_NOT_IMPLEMENTED;
}

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

@ -5,7 +5,7 @@
include protocol PRemoteDecoderManager;
using mozilla::PDMFactory::MediaCodecsSupported from "PDMFactory.h";
using mozilla::media::MediaCodecsSupported from "MediaCodecsSupport.h";
namespace mozilla {

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

@ -40,7 +40,7 @@ RefPtr<UtilityAudioDecoderChild> UtilityAudioDecoderChild::GetSingleton() {
mozilla::ipc::IPCResult
UtilityAudioDecoderChild::RecvUpdateMediaCodecsSupported(
const PDMFactory::MediaCodecsSupported& aSupported) {
const media::MediaCodecsSupported& aSupported) {
dom::ContentParent::BroadcastMediaCodecsSupportedUpdate(
RemoteDecodeIn::UtilityProcess, aSupported);
return IPC_OK();

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

@ -24,7 +24,7 @@ class UtilityAudioDecoderChild final : public PUtilityAudioDecoderChild {
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(UtilityAudioDecoderChild, override);
mozilla::ipc::IPCResult RecvUpdateMediaCodecsSupported(
const PDMFactory::MediaCodecsSupported& aSupported);
const media::MediaCodecsSupported& aSupported);
UtilityActorName GetActorName() { return UtilityActorName::AudioDecoder; }

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

@ -10,6 +10,7 @@
#include "nsDebugImpl.h"
#include "mozilla/RemoteDecoderManagerParent.h"
#include "PDMFactory.h"
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
# include "WMF.h"

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

@ -1691,11 +1691,7 @@ static bool DisassembleNative(JSContext* cx, unsigned argc, Value* vp) {
return false;
}
const Value& v2 =
fun->getExtendedSlot(FunctionExtended::WASM_INSTANCE_OBJ_SLOT);
WasmInstanceObject* instobj = &v2.toObject().as<WasmInstanceObject>();
js::wasm::Instance& inst = instobj->instance();
js::wasm::Instance& inst = fun->wasmInstance();
const js::wasm::Code& code = inst.code();
js::wasm::Tier tier = code.bestTier();

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

@ -175,6 +175,7 @@ const definedOpcodes =
...(wasmExceptionsEnabled() ? [0x06, 0x07, 0x08, 0x09] : []),
0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11,
...(wasmFunctionReferencesEnabled() ? [0x14] : []),
...(wasmExceptionsEnabled() ? [0x18, 0x19] : []),
0x1a, 0x1b, 0x1c,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26,

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

@ -0,0 +1,89 @@
// |jit-test| skip-if: !wasmFunctionReferencesEnabled()
let { plusOne } = wasmEvalText(`(module
(; forward declaration so that ref.func works ;)
(elem declare $plusOneRef)
(func $plusOneRef (param i32) (result i32)
(i32.add
local.get 0
i32.const 1)
)
(func (export "plusOne") (param i32) (result i32)
local.get 0
ref.func $plusOneRef
call_ref
)
)`).exports;
assertEq(plusOne(3), 4);
// pass non-funcref type
wasmFailValidateText(`(module
(func (param $a i32)
local.get $a
call_ref
)
)`, /type mismatch: expression has type i32 but expected a reference type/);
wasmFailValidateText(`(module
(func (param $a (ref extern))
local.get $a
call_ref
)
)`, /type mismatch: reference expected to be a subtype of funcref/);
// pass (non-subtype of) funcref
wasmFailValidateText(`(module
(func (param funcref)
local.get 0
call_ref
)
)`, /type mismatch: reference expected to be a subtype of funcref/);
// signature mismatch
wasmFailValidateText(`(module
(elem declare $plusOneRef)
(func $plusOneRef (param f32) (result f32)
(f32.add
local.get 0
f32.const 1.0)
)
(func (export "plusOne") (param i32) (result i32)
local.get 0
ref.func $plusOneRef
call_ref
)
)`, /type mismatch/);
// TODO fix call_ref is not allowed in dead code
wasmFailValidateText(`(module
(func (param $a i32)
unreachable
call_ref
)
)`, /gc instruction temporarily not allowed in dead code/);
// Cross-instance calls
let { loadInt } = wasmEvalText(`(module
(memory 1 1)
(data (i32.const 0) "\\04\\00\\00\\00")
(func (export "loadInt") (result i32)
i32.const 0
i32.load offset=0
)
)`).exports;
let { callLoadInt } = wasmEvalText(`(module
(elem declare 0)
(import "" "loadInt" (func (result i32)))
(func (export "callLoadInt") (result i32)
ref.func 0
call_ref
)
)`, {"": { loadInt, }}).exports;
assertEq(loadInt(), 4);
assertEq(callLoadInt(), 4);

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

@ -8072,6 +8072,8 @@ void CodeGenerator::visitWasmCall(LWasmCall* lir) {
callBase->builtinMethodFailureMode());
switchRealm = false;
break;
case wasm::CalleeDesc::FuncRef:
MOZ_CRASH("NYI");
}
// Note the assembler offset for the associated LSafePoint.

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

@ -3929,6 +3929,43 @@ void MacroAssembler::wasmCallIndirect(const wasm::CallSiteDesc& desc,
bind(&done);
}
CodeOffset MacroAssembler::wasmCallRef(const wasm::CallSiteDesc& desc,
const wasm::CalleeDesc& callee) {
MOZ_ASSERT(callee.which() == wasm::CalleeDesc::FuncRef);
const Register calleeScratch = WasmCallRefCallScratchReg0;
const Register calleeFnObj = WasmCallRefReg;
storePtr(InstanceReg,
Address(getStackPointer(), WasmCallerInstanceOffsetBeforeCall));
// Get InstanceReg from the function's WASM_INSTANCE_SLOT extended slot.
size_t instanceSlotOffset = FunctionExtended::offsetOfExtendedSlot(
FunctionExtended::WASM_INSTANCE_SLOT);
loadPtr(Address(calleeFnObj, instanceSlotOffset), InstanceReg);
storePtr(InstanceReg,
Address(getStackPointer(), WasmCalleeInstanceOffsetBeforeCall));
loadWasmPinnedRegsFromInstance();
switchToWasmInstanceRealm(WasmCallRefCallScratchReg0,
WasmCallRefCallScratchReg1);
// Get funcUncheckedCallEntry() from the function's
// WASM_FUNC_UNCHECKED_ENTRY_SLOT extended slot.
size_t uncheckedEntrySlotOffset = FunctionExtended::offsetOfExtendedSlot(
FunctionExtended::WASM_FUNC_UNCHECKED_ENTRY_SLOT);
loadPtr(Address(calleeFnObj, uncheckedEntrySlotOffset), calleeScratch);
CodeOffset raOffset = call(desc, calleeScratch);
// Restore registers and realm and back to this caller's.
loadPtr(Address(getStackPointer(), WasmCallerInstanceOffsetBeforeCall),
InstanceReg);
loadWasmPinnedRegsFromInstance();
switchToWasmInstanceRealm(ABINonArgReturnReg0, ABINonArgReturnReg1);
return raOffset;
}
void MacroAssembler::nopPatchableToCall(const wasm::CallSiteDesc& desc) {
CodeOffset offset = nopPatchableToCall();
append(desc, offset);

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

@ -3741,6 +3741,11 @@ class MacroAssembler : public MacroAssemblerSpecific {
mozilla::Maybe<uint32_t> tableSize,
CodeOffset* fastCallOffset, CodeOffset* slowCallOffset);
// This function takes care of loading the callee's instance and address from
// pinned reg.
CodeOffset wasmCallRef(const wasm::CallSiteDesc& desc,
const wasm::CalleeDesc& callee);
// WasmTableCallIndexReg must contain the index of the indirect call.
// This is for asm.js calls only.
CodeOffset asmCallIndirect(const wasm::CallSiteDesc& desc,

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

@ -192,6 +192,11 @@ static constexpr Register WasmTableCallScratchReg1 = ABINonArgReg1;
static constexpr Register WasmTableCallSigReg = ABINonArgReg2;
static constexpr Register WasmTableCallIndexReg = ABINonArgReg3;
// Registers used for ref calls.
static constexpr Register WasmCallRefCallScratchReg0 = ABINonArgReg0;
static constexpr Register WasmCallRefCallScratchReg1 = ABINonArgReg1;
static constexpr Register WasmCallRefReg = ABINonArgReg3;
// Register used as a scratch along the return path in the fast js -> wasm stub
// code. This must not overlap ReturnReg, JSReturnOperand, or InstanceReg.
// It must be a volatile register.

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

@ -710,6 +710,11 @@ static constexpr Register WasmTableCallScratchReg1 = ABINonArgReg1;
static constexpr Register WasmTableCallSigReg = ABINonArgReg2;
static constexpr Register WasmTableCallIndexReg = ABINonArgReg3;
// Registers used for ref calls.
static constexpr Register WasmCallRefCallScratchReg0 = ABINonArgReg0;
static constexpr Register WasmCallRefCallScratchReg1 = ABINonArgReg1;
static constexpr Register WasmCallRefReg = ABINonArgReg3;
// Register used as a scratch along the return path in the fast js -> wasm stub
// code. This must not overlap ReturnReg, JSReturnOperand, or InstanceReg.
// It must be a volatile register.

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

@ -202,6 +202,11 @@ static constexpr Register WasmTableCallScratchReg1 = ABINonArgReg1;
static constexpr Register WasmTableCallSigReg = ABINonArgReg2;
static constexpr Register WasmTableCallIndexReg = ABINonArgReg3;
// Registers used for ref calls.
static constexpr Register WasmCallRefCallScratchReg0 = ABINonArgReg0;
static constexpr Register WasmCallRefCallScratchReg1 = ABINonArgReg1;
static constexpr Register WasmCallRefReg = ABINonArgReg3;
// Register used as a scratch along the return path in the fast js -> wasm stub
// code. This must not overlap ReturnReg, JSReturnOperand, or InstanceReg.
// It must be a volatile register.

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

@ -82,6 +82,11 @@ static constexpr Register WasmTableCallScratchReg1 = ABINonArgReg1;
static constexpr Register WasmTableCallSigReg = ABINonArgReg2;
static constexpr Register WasmTableCallIndexReg = ABINonArgReg3;
// Registers used for ref calls.
static constexpr Register WasmCallRefCallScratchReg0 = ABINonArgReg0;
static constexpr Register WasmCallRefCallScratchReg1 = ABINonArgReg1;
static constexpr Register WasmCallRefReg = ABINonArgReg3;
// Register used as a scratch along the return path in the fast js -> wasm stub
// code. This must not overlap ReturnReg, JSReturnOperand, or InstanceReg.
// It must be a volatile register.

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

@ -70,6 +70,11 @@ static constexpr Register WasmTableCallScratchReg1 = ABINonArgReg1;
static constexpr Register WasmTableCallSigReg = ABINonArgReg2;
static constexpr Register WasmTableCallIndexReg = ABINonArgReg3;
// Registers used for ref calls.
static constexpr Register WasmCallRefCallScratchReg0 = ABINonArgReg0;
static constexpr Register WasmCallRefCallScratchReg1 = ABINonArgReg1;
static constexpr Register WasmCallRefReg = ABINonArgReg3;
// Register used as a scratch along the return path in the fast js -> wasm stub
// code. This must not overlap ReturnReg, JSReturnOperand, or InstanceReg.
// It must be a volatile register.

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

@ -101,6 +101,9 @@ static constexpr Register WasmTableCallSigReg{Registers::invalid_reg};
static constexpr Register WasmTableCallIndexReg{Registers::invalid_reg};
static constexpr Register InstanceReg{Registers::invalid_reg};
static constexpr Register WasmJitEntryReturnScratch{Registers::invalid_reg};
static constexpr Register WasmCallRefCallScratchReg0{Registers::invalid_reg};
static constexpr Register WasmCallRefCallScratchReg1{Registers::invalid_reg};
static constexpr Register WasmCallRefReg{Registers::invalid_reg};
static constexpr uint32_t ABIStackAlignment = 4;
static constexpr uint32_t CodeAlignment = 16;

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

@ -111,6 +111,9 @@ static constexpr Register WasmTableCallSigReg{Registers::invalid_reg};
static constexpr Register WasmTableCallIndexReg{Registers::invalid_reg};
static constexpr Register InstanceReg{Registers::invalid_reg};
static constexpr Register WasmJitEntryReturnScratch{Registers::invalid_reg};
static constexpr Register WasmCallRefCallScratchReg0{Registers::invalid_reg};
static constexpr Register WasmCallRefCallScratchReg1{Registers::invalid_reg};
static constexpr Register WasmCallRefReg{Registers::invalid_reg};
static constexpr uint32_t ABIStackAlignment = 4;
static constexpr uint32_t CodeAlignment = 16;

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

@ -231,6 +231,11 @@ static constexpr Register WasmTableCallScratchReg1 = ABINonArgReg1;
static constexpr Register WasmTableCallSigReg = ABINonArgReg2;
static constexpr Register WasmTableCallIndexReg = ABINonArgReg3;
// Registers used for ref calls.
static constexpr Register WasmCallRefCallScratchReg0 = ABINonArgReg0;
static constexpr Register WasmCallRefCallScratchReg1 = ABINonArgReg1;
static constexpr Register WasmCallRefReg = ABINonArgReg3;
// Register used as a scratch along the return path in the fast js -> wasm stub
// code. This must not overlap ReturnReg, JSReturnOperand, or InstanceReg.
// It must be a volatile register.

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

@ -137,6 +137,11 @@ static constexpr Register WasmTableCallScratchReg1 = ABINonArgReg1;
static constexpr Register WasmTableCallSigReg = ABINonArgReg2;
static constexpr Register WasmTableCallIndexReg = ABINonArgReg3;
// Registers used for ref calls.
static constexpr Register WasmCallRefCallScratchReg0 = ABINonArgReg0;
static constexpr Register WasmCallRefCallScratchReg1 = ABINonArgReg1;
static constexpr Register WasmCallRefReg = ABINonArgReg3;
// Register used as a scratch along the return path in the fast js -> wasm stub
// code. This must not overlap ReturnReg, JSReturnOperand, or InstanceReg.
// It must be a volatile register.

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

@ -662,6 +662,16 @@ inline void JSFunction::trace(JSTracer* trc) {
}
}
}
// wasm/asm.js exported functions need to keep WasmInstantObject alive,
// access it via WASM_INSTANCE_SLOT extended slot.
if (isAsmJSNative() || isWasm()) {
const Value& v = getExtendedSlot(FunctionExtended::WASM_INSTANCE_SLOT);
if (!v.isUndefined()) {
js::wasm::Instance* instance =
static_cast<js::wasm::Instance*>(v.toPrivate());
instance->trace(trc);
}
}
}
static void fun_trace(JSTracer* trc, JSObject* obj) {

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

@ -43,6 +43,11 @@ static constexpr std::string_view FunctionConstructorFinalBrace = "\n}";
extern const JSClass FunctionClass;
extern const JSClass ExtendedFunctionClass;
namespace wasm {
class Instance;
} // namespace wasm
} // namespace js
class JSFunction : public js::NativeObject {
@ -638,6 +643,7 @@ class JSFunction : public js::NativeObject {
MOZ_ASSERT(isWasmWithJitEntry());
return static_cast<void**>(nativeJitInfoOrInterpretedScript());
}
inline js::wasm::Instance& wasmInstance() const;
bool isDerivedClassConstructor() const;
bool isSyntheticFunction() const;
@ -810,9 +816,10 @@ class FunctionExtended : public JSFunction {
// to be resolved eagerly.
static const uint32_t BOUND_FUNCTION_LENGTH_SLOT = 1;
// Exported asm.js/wasm functions store their WasmInstanceObject in the
// first slot.
static const uint32_t WASM_INSTANCE_OBJ_SLOT = 0;
// wasm/asm.js exported functions store a code pointer to their direct entry
// point (see CodeRange::funcUncheckedCallEntry()) to support the call_ref
// instruction.
static const uint32_t WASM_FUNC_UNCHECKED_ENTRY_SLOT = 0;
// wasm/asm.js exported functions store the wasm::Instance pointer of their
// instance.
@ -875,6 +882,14 @@ inline const js::Value& JSFunction::getExtendedSlot(uint32_t which) const {
return getFixedSlot(js::FunctionExtended::FirstExtendedSlot + which);
}
inline js::wasm::Instance& JSFunction::wasmInstance() const {
MOZ_ASSERT(isWasm() || isAsmJSNative());
MOZ_ASSERT(
!getExtendedSlot(js::FunctionExtended::WASM_INSTANCE_SLOT).isUndefined());
return *static_cast<js::wasm::Instance*>(
getExtendedSlot(js::FunctionExtended::WASM_INSTANCE_SLOT).toPrivate());
}
namespace js {
JSString* FunctionToString(JSContext* cx, HandleFunction fun, bool isToSource);

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

@ -944,6 +944,9 @@ struct BaseCompiler final {
const Stk& indexVal, const FunctionCall& call,
CodeOffset* fastCallOffset, CodeOffset* slowCallOffset);
CodeOffset callImport(unsigned globalDataOffset, const FunctionCall& call);
#ifdef ENABLE_WASM_FUNCTION_REFERENCES
CodeOffset callRef(const Stk& calleeRef, const FunctionCall& call);
#endif
CodeOffset builtinCall(SymbolicAddress builtin, const FunctionCall& call);
CodeOffset builtinInstanceMethodCall(const SymbolicAddressSignature& builtin,
const ABIArg& instanceArg,
@ -1553,6 +1556,7 @@ struct BaseCompiler final {
#ifdef ENABLE_WASM_FUNCTION_REFERENCES
[[nodiscard]] bool emitRefAsNonNull();
[[nodiscard]] bool emitBrOnNull();
[[nodiscard]] bool emitCallRef();
#endif
[[nodiscard]] bool emitAtomicCmpXchg(ValType type, Scalar::Type viewType);

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

@ -1607,6 +1607,17 @@ bool BaseCompiler::callIndirect(uint32_t funcTypeIndex, uint32_t tableIndex,
return true;
}
#ifdef ENABLE_WASM_FUNCTION_REFERENCES
CodeOffset BaseCompiler::callRef(const Stk& calleeRef,
const FunctionCall& call) {
CallSiteDesc desc(call.lineOrBytecode, CallSiteDesc::FuncRef);
CalleeDesc callee = CalleeDesc::wasmFuncRef();
loadRef(calleeRef, RegRef(WasmCallRefReg));
return masm.wasmCallRef(desc, callee);
}
#endif
// Precondition: sync()
CodeOffset BaseCompiler::callImport(unsigned globalDataOffset,
@ -4740,6 +4751,61 @@ bool BaseCompiler::emitCallIndirect() {
return pushCallResults(baselineCall, resultType, results);
}
#ifdef ENABLE_WASM_FUNCTION_REFERENCES
bool BaseCompiler::emitCallRef() {
uint32_t lineOrBytecode = readCallSiteLineOrBytecode();
const FuncType* funcType;
Nothing unused_callee;
BaseNothingVector unused_args{};
if (!iter_.readCallRef(&funcType, &unused_callee, &unused_args)) {
return false;
}
if (deadCode_) {
return true;
}
sync();
// Stack: ... arg1 .. argn callee
uint32_t numArgs = funcType->args().length() + 1;
size_t stackArgBytes = stackConsumed(numArgs);
ResultType resultType(ResultType::Vector(funcType->results()));
StackResultsLoc results;
if (!pushStackResultsForCall(resultType, RegPtr(ABINonArgReg0), &results)) {
return false;
}
FunctionCall baselineCall(lineOrBytecode);
// State and realm are restored as needed by by callRef (really by
// MacroAssembler::wasmCallRef).
beginCall(baselineCall, UseABI::Wasm, RestoreRegisterStateAndRealm::False);
if (!emitCallArgs(funcType->args(), results, &baselineCall,
CalleeOnStack::True)) {
return false;
}
const Stk& callee = peek(results.count());
CodeOffset raOffset = callRef(callee, baselineCall);
if (!createStackMap("emitCallRef", raOffset)) {
return false;
}
popStackResultsAfterCall(results, stackArgBytes);
endCall(baselineCall, stackArgBytes);
popValueStackBy(numArgs);
captureCallResultRegisters(resultType);
return pushCallResults(baselineCall, resultType, results);
}
#endif
void BaseCompiler::emitRound(RoundingMode roundingMode, ValType operandType) {
if (operandType == ValType::F32) {
RegF32 f0 = popF32();
@ -8578,6 +8644,13 @@ bool BaseCompiler::emitBody() {
CHECK_NEXT(emitCall());
case uint16_t(Op::CallIndirect):
CHECK_NEXT(emitCallIndirect());
#ifdef ENABLE_WASM_FUNCTION_REFERENCES
case uint16_t(Op::CallRef):
if (!moduleEnv_.functionReferencesEnabled()) {
return iter_.unrecognizedOpcode(&op);
}
CHECK_NEXT(emitCallRef());
#endif
// Locals and globals
case uint16_t(Op::LocalGet):

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

@ -213,3 +213,8 @@ CalleeDesc CalleeDesc::builtinInstanceMethod(SymbolicAddress callee) {
c.u.builtin_ = callee;
return c;
}
CalleeDesc CalleeDesc::wasmFuncRef() {
CalleeDesc c;
c.which_ = FuncRef;
return c;
}

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

@ -400,9 +400,9 @@ extern const CodeRange* LookupInSorted(const CodeRangeVector& codeRanges,
// adds the function index of the callee.
class CallSiteDesc {
static constexpr size_t LINE_OR_BYTECODE_BITS_SIZE = 29;
static constexpr size_t LINE_OR_BYTECODE_BITS_SIZE = 28;
uint32_t lineOrBytecode_ : LINE_OR_BYTECODE_BITS_SIZE;
uint32_t kind_ : 3;
uint32_t kind_ : 4;
WASM_CHECK_CACHEABLE_POD(lineOrBytecode_, kind_);
@ -415,6 +415,7 @@ class CallSiteDesc {
Import, // wasm import call
Indirect, // dynamic callee called via register, context on stack
IndirectFast, // dynamically determined to be same-instance
FuncRef, // call using direct function reference
Symbolic, // call to a single symbolic callee
EnterFrame, // call to a enter frame handler
LeaveFrame, // call to a leave frame handler
@ -433,11 +434,15 @@ class CallSiteDesc {
Kind kind() const { return Kind(kind_); }
bool isImportCall() const { return kind() == CallSiteDesc::Import; }
bool isIndirectCall() const { return kind() == CallSiteDesc::Indirect; }
bool isFuncRefCall() const { return kind() == CallSiteDesc::FuncRef; }
bool mightBeCrossInstance() const {
return isImportCall() || isIndirectCall();
return isImportCall() || isIndirectCall() || isFuncRefCall();
}
};
static_assert(js::wasm::MaxFunctionBytes <=
CallSiteDesc::MAX_LINE_OR_BYTECODE_VALUE);
WASM_DECLARE_CACHEABLE_POD(CallSiteDesc);
class CallSite : public CallSiteDesc {
@ -633,7 +638,10 @@ class CalleeDesc {
Builtin,
// Like Builtin, but automatically passes Instance* as first argument.
BuiltinInstanceMethod
BuiltinInstanceMethod,
// Calls a function reference.
FuncRef,
};
private:
@ -666,6 +674,7 @@ class CalleeDesc {
static CalleeDesc asmJSTable(const TableDesc& desc);
static CalleeDesc builtin(SymbolicAddress callee);
static CalleeDesc builtinInstanceMethod(SymbolicAddress callee);
static CalleeDesc wasmFuncRef();
Which which() const { return which_; }
uint32_t funcIndex() const {
MOZ_ASSERT(which_ == Func);

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

@ -240,6 +240,7 @@ enum class Op {
// Call operators
Call = 0x10,
CallIndirect = 0x11,
CallRef = 0x14,
// Additional exception operators
Delegate = 0x18,

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

@ -487,6 +487,7 @@ bool ModuleGenerator::linkCallSites() {
case CallSiteDesc::Breakpoint:
case CallSiteDesc::EnterFrame:
case CallSiteDesc::LeaveFrame:
case CallSiteDesc::FuncRef:
break;
case CallSiteDesc::Func: {
if (funcIsCompiled(target.funcIndex())) {

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

@ -2488,11 +2488,16 @@ bool WasmInstanceObject::getExportedFunction(
}
}
fun->setExtendedSlot(FunctionExtended::WASM_INSTANCE_OBJ_SLOT,
ObjectValue(*instanceObj));
fun->setExtendedSlot(FunctionExtended::WASM_INSTANCE_SLOT,
PrivateValue((void*)&instance));
PrivateValue(const_cast<Instance*>(&instance)));
const CodeTier& codeTier =
instance.code().codeTier(instance.code().bestTier());
const CodeRange& codeRange = codeTier.metadata().codeRange(funcExport);
fun->setExtendedSlot(FunctionExtended::WASM_FUNC_UNCHECKED_ENTRY_SLOT,
PrivateValue(codeTier.segment().base() +
codeRange.funcUncheckedCallEntry()));
if (!instanceObj->exports().putNew(funcIndex, fun)) {
ReportOutOfMemory(cx);
@ -2565,20 +2570,15 @@ bool wasm::IsWasmExportedFunction(JSFunction* fun) {
}
Instance& wasm::ExportedFunctionToInstance(JSFunction* fun) {
return ExportedFunctionToInstanceObject(fun)->instance();
return fun->wasmInstance();
}
WasmInstanceObject* wasm::ExportedFunctionToInstanceObject(JSFunction* fun) {
MOZ_ASSERT(fun->kind() == FunctionFlags::Wasm ||
fun->kind() == FunctionFlags::AsmJS);
const Value& v =
fun->getExtendedSlot(FunctionExtended::WASM_INSTANCE_OBJ_SLOT);
return &v.toObject().as<WasmInstanceObject>();
return fun->wasmInstance().object();
}
uint32_t wasm::ExportedFunctionToFuncIndex(JSFunction* fun) {
Instance& instance = ExportedFunctionToInstanceObject(fun)->instance();
return instance.code().getFuncIndex(fun);
return fun->wasmInstance().code().getFuncIndex(fun);
}
// ============================================================================

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

@ -252,6 +252,10 @@ OpKind wasm::Classify(OpBytes op) {
return OpKind::Call;
case Op::CallIndirect:
return OpKind::CallIndirect;
# ifdef ENABLE_WASM_FUNCTION_REFERENCES
case Op::CallRef:
return OpKind::CallRef;
# endif
case Op::Return:
case Op::Limit:
// Accept Limit, for use in decoding the end of a function after the body.

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

@ -146,6 +146,9 @@ enum class OpKind {
TeeGlobal,
Call,
CallIndirect,
# ifdef ENABLE_WASM_FUNCTION_REFERENCES
CallRef,
# endif
OldCallDirect,
OldCallIndirect,
Return,
@ -364,6 +367,7 @@ class MOZ_STACK_CLASS OpIter : private Policy {
template <typename ValTypeSpanT>
[[nodiscard]] bool popWithTypes(ValTypeSpanT expected, ValueVector* values);
[[nodiscard]] bool popWithRefType(Value* value, StackType* type);
[[nodiscard]] bool popWithFuncType(Value* value, FuncType** funcType);
[[nodiscard]] bool popWithRttType(Value* rtt, uint32_t* rttTypeIndex,
uint32_t* rttDepth);
[[nodiscard]] bool popWithRttType(Value* rtt, uint32_t rttTypeIndex,
@ -562,6 +566,10 @@ class MOZ_STACK_CLASS OpIter : private Policy {
[[nodiscard]] bool readCallIndirect(uint32_t* funcTypeIndex,
uint32_t* tableIndex, Value* callee,
ValueVector* argValues);
#ifdef ENABLE_WASM_FUNCTION_REFERENCES
[[nodiscard]] bool readCallRef(const FuncType** funcType, Value* callee,
ValueVector* argValues);
#endif
[[nodiscard]] bool readOldCallDirect(uint32_t numFuncImports,
uint32_t* funcTypeIndex,
ValueVector* argValues);
@ -905,6 +913,35 @@ inline bool OpIter<Policy>::popWithRefType(Value* value, StackType* type) {
return fail(error.get());
}
// This function pops exactly one value from the stack, checking that it is a
// subtype of the function type.
template <typename Policy>
inline bool OpIter<Policy>::popWithFuncType(Value* value, FuncType** funcType) {
StackType ty;
if (!popWithRefType(value, &ty)) {
return false;
}
if (ty.isBottom()) {
return fail("gc instruction temporarily not allowed in dead code");
}
if (!ty.valType().isTypeIndex() ||
!env_.types->isFuncType(ty.valType().typeIndex())) {
return fail("type mismatch: reference expected to be a subtype of funcref");
}
*funcType = &env_.types->funcType(ty.valType().typeIndex());
#ifdef WASM_PRIVATE_REFTYPES
if ((*funcType)->exposesTypeIndex()) {
return fail("cannot expose indexed reference type");
}
#endif
return true;
}
// This function pops exactly one value from the stack, checking that it is an
// rtt type with any type index or depth value.
template <typename Policy>
@ -2213,6 +2250,15 @@ inline bool OpIter<Policy>::readRefFunc(uint32_t* funcIndex) {
return fail(
"function index is not declared in a section before the code section");
}
#ifdef ENABLE_WASM_FUNCTION_REFERENCES
// When function references enabled, push type index on the stack, e.g. for
// validation of the call_ref instruction.
if (env_.functionReferencesEnabled()) {
const uint32_t typeIndex = env_.funcs[*funcIndex].typeIndex;
return push(RefType::fromTypeIndex(typeIndex, false));
}
#endif
return push(RefType::func());
}
@ -2374,6 +2420,27 @@ inline bool OpIter<Policy>::readCallIndirect(uint32_t* funcTypeIndex,
return push(ResultType::Vector(funcType.results()));
}
#ifdef ENABLE_WASM_FUNCTION_REFERENCES
template <typename Policy>
inline bool OpIter<Policy>::readCallRef(const FuncType** funcType,
Value* callee, ValueVector* argValues) {
MOZ_ASSERT(Classify(op_) == OpKind::CallRef);
FuncType* funcType_;
if (!popWithFuncType(callee, &funcType_)) {
return false;
}
*funcType = funcType_;
if (!popCallArgs(funcType_->args(), argValues)) {
return false;
}
return push(ResultType::Vector(funcType_->results()));
}
#endif
template <typename Policy>
inline bool OpIter<Policy>::readOldCallDirect(uint32_t numFuncImports,
uint32_t* funcTypeIndex,

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

@ -309,6 +309,12 @@ TypeResult TypeContext::isRefSubtypeOf(RefType subType, RefType superType,
return TypeResult::True;
}
// The ref T <: funcref when T = func-type rule
if (subType.isTypeIndex() && types_[subType.typeIndex()].isFuncType() &&
superType.isFunc()) {
return TypeResult::True;
}
// Type-index references can be subtypes
if (subType.isTypeIndex() && superType.isTypeIndex()) {
return isTypeIndexSubtypeOf(subType.typeIndex(), superType.typeIndex(),

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

@ -223,6 +223,16 @@ static bool DecodeFunctionBodyExprs(const ModuleEnvironment& env,
CHECK(iter.readCallIndirect(&unusedIndex, &unusedIndex2, &nothing,
&unusedArgs));
}
#ifdef ENABLE_WASM_FUNCTION_REFERENCES
case uint16_t(Op::CallRef): {
if (!env.functionReferencesEnabled()) {
return iter.unrecognizedOpcode(&op);
}
const FuncType* unusedType;
NothingVector unusedArgs{};
CHECK(iter.readCallRef(&unusedType, &nothing, &unusedArgs));
}
#endif
case uint16_t(Op::I32Const): {
int32_t unused;
CHECK(iter.readI32Const(&unused));

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

@ -4,7 +4,7 @@
"use strict";
var EXPORTED_SYMBOLS = ["deserialize", "serialize"];
var EXPORTED_SYMBOLS = ["deserialize", "serialize", "stringify"];
const { XPCOMUtils } = ChromeUtils.importESModule(
"resource://gre/modules/XPCOMUtils.sys.mjs"
@ -418,8 +418,32 @@ function serialize(
}
lazy.logger.warn(
`Unsupported type: ${type} for remote value: ${value.toString()}`
`Unsupported type: ${type} for remote value: ${stringify(value)}`
);
return undefined;
}
/**
* Safely stringify a value.
*
* @param {Object} value
* Value of any type to be stringified.
*
* @returns {String} String representation of the value.
*/
function stringify(obj) {
let text;
try {
text =
obj !== null && typeof obj === "object" ? obj.toString() : String(obj);
} catch (e) {
// The error-case will also be handled in `finally {}`.
} finally {
if (typeof text != "string") {
text = Object.prototype.toString.apply(obj);
}
}
return text;
}

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