Merge autoland to mozilla-central. a=merge

This commit is contained in:
Iulian Moraru 2022-03-24 23:53:10 +02:00
Родитель d9779ca563 ca24fb4eb2
Коммит 3f782c2587
305 изменённых файлов: 5790 добавлений и 5043 удалений

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

@ -973,9 +973,9 @@ dependencies = [
[[package]]
name = "crossbeam-channel"
version = "0.5.2"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e54ea8bc3fb1ee042f5aace6e3c6e025d3874866da222930f70ce62aceba0bfa"
checksum = "5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53"
dependencies = [
"cfg-if 1.0.0",
"crossbeam-utils 0.8.6",

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

@ -201,6 +201,13 @@ class AboutReaderParent extends JSWindowActorParent {
break;
}
case "RedirectTo": {
gCachedArticles.set(message.data.newURL, message.data.article);
// This is setup as a query so we can navigate the page after we've
// cached the relevant info in the parent.
return true;
}
default:
this.callListeners(message);
break;

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

@ -377,6 +377,7 @@ class ContextMenuChild extends JSWindowActorChild {
this.context.linkProtocol &&
!(
this.context.linkProtocol == "mailto" ||
this.context.linkProtocol == "tel" ||
this.context.linkProtocol == "javascript" ||
this.context.linkProtocol == "news" ||
this.context.linkProtocol == "snews"
@ -872,6 +873,7 @@ class ContextMenuChild extends JSWindowActorChild {
context.onLink = false;
context.onLoadedImage = false;
context.onMailtoLink = false;
context.onTelLink = false;
context.onMozExtLink = false;
context.onNumeric = false;
context.onPassword = false;
@ -1157,6 +1159,7 @@ class ContextMenuChild extends JSWindowActorChild {
context.linkTextStr = this._getLinkText();
context.linkProtocol = this._getLinkProtocol();
context.onMailtoLink = context.linkProtocol == "mailto";
context.onTelLink = context.linkProtocol == "tel";
context.onMozExtLink = context.linkProtocol == "moz-extension";
context.onSaveableLink = this._isLinkSaveable(context.link);

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

@ -106,6 +106,9 @@
<menuitem id="context-copyemail"
data-l10n-id="main-context-menu-copy-email"
oncommand="gContextMenu.copyEmail();"/>
<menuitem id="context-copyphone"
data-l10n-id="main-context-menu-copy-phone"
oncommand="gContextMenu.copyPhone();"/>
<menuitem id="context-copylink"
data-l10n-id="main-context-menu-copy-link-simple"
oncommand="gContextMenu.copyLink();"/>

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

@ -43,25 +43,11 @@ var gDataNotificationInfoBar = {
return;
}
let brandBundle = document.getElementById("bundle_brand");
let appName = brandBundle.getString("brandShortName");
let vendorName = brandBundle.getString("vendorShortName");
let message = gNavigatorBundle.getFormattedString(
"dataReportingNotification.message",
[appName, vendorName]
);
this._actionTaken = false;
let buttons = [
{
label: gNavigatorBundle.getString(
"dataReportingNotification.button.label"
),
accessKey: gNavigatorBundle.getString(
"dataReportingNotification.button.accessKey"
),
"l10n-id": "data-reporting-notification-button",
popup: null,
callback: () => {
this._actionTaken = true;
@ -74,7 +60,9 @@ var gDataNotificationInfoBar = {
gNotificationBox.appendNotification(
this._DATA_REPORTING_NOTIFICATION,
{
label: message,
label: {
"l10n-id": "data-reporting-notification-message",
},
priority: gNotificationBox.PRIORITY_INFO_HIGH,
eventCallback: event => {
if (event == "removed") {

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

@ -224,6 +224,7 @@ class nsContextMenu {
this.onLink = context.onLink;
this.onLoadedImage = context.onLoadedImage;
this.onMailtoLink = context.onMailtoLink;
this.onTelLink = context.onTelLink;
this.onMozExtLink = context.onMozExtLink;
this.onNumeric = context.onNumeric;
this.onPassword = context.onPassword;
@ -712,7 +713,10 @@ class nsContextMenu {
this.showItem(
"context-bookmarklink",
(this.onLink && !this.onMailtoLink && !this.onMozExtLink) ||
(this.onLink &&
!this.onMailtoLink &&
!this.onTelLink &&
!this.onMozExtLink) ||
this.onPlainTextLink
);
this.showItem("context-keywordfield", this.shouldShowAddKeyword());
@ -836,14 +840,25 @@ class nsContextMenu {
// Copy email link depends on whether we're on an email link.
this.showItem("context-copyemail", this.onMailtoLink);
// Copy phone link depends on whether we're on a phone link.
this.showItem("context-copyphone", this.onTelLink);
// Copy link location depends on whether we're on a non-mailto link.
this.showItem("context-copylink", this.onLink && !this.onMailtoLink);
this.showItem(
"context-copylink",
this.onLink && !this.onMailtoLink && !this.onTelLink
);
let copyLinkSeparator = document.getElementById("context-sep-copylink");
// Show "Copy Link" and "Copy" with no divider, and "copy link" and "Send link to Device" with no divider between.
// Other cases will show a divider.
copyLinkSeparator.toggleAttribute(
"ensureHidden",
this.onLink && !this.onMailtoLink && !this.onImage && this.syncItemsShown
this.onLink &&
!this.onMailtoLink &&
!this.onTelLink &&
!this.onImage &&
this.syncItemsShown
);
this.showItem("context-copyvideourl", this.onVideo);
@ -1923,6 +1938,26 @@ class nsContextMenu {
clipboard.copyString(addresses);
}
// Extract phone and put it on clipboard
copyPhone() {
// Copies the phone number only. We won't be doing any complex parsing
var url = this.linkURL;
var phone = url.substr(4);
// Let's try to unescape it using a character set
// in case the phone number is not ASCII.
try {
phone = Services.textToSubURI.unEscapeURIForUI(phone);
} catch (ex) {
// Do nothing.
}
var clipboard = Cc["@mozilla.org/widget/clipboardhelper;1"].getService(
Ci.nsIClipboardHelper
);
clipboard.copyString(phone);
}
copyLink() {
// If we're in a view source tab, remove the view-source: prefix
let linkURL = this.linkURL.replace(/^view-source:/, "");

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

@ -234,6 +234,19 @@ add_task(async function test_mailto() {
]);
});
add_task(async function test_tel() {
await test_contextmenu("#test-tel", [
"context-copyphone",
true,
"---",
null,
"context-searchselect",
true,
"context-searchselect-private",
true,
]);
});
add_task(async function test_image() {
for (let selector of ["#test-image", "#test-svg-image"]) {
await test_contextmenu(

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

@ -19,6 +19,7 @@ document.getElementById("shadow-host-in-link").attachShadow({ mode: "closed" }).
"<span>Click the monkey!</span>";
</script>
<a id="test-mailto" href="mailto:codemonkey@mozilla.com">Mail the monkey!</a><br>
<a id="test-tel" href="tel:555-123-4567">Call random number!</a><br>
<input id="test-input"><br>
<img id="test-image" src="ctxmenu-image.png">
<svg>

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

@ -5,4 +5,3 @@
brandShorterName=Firefox
brandShortName=Firefox Developer Edition
brandFullName=Firefox Developer Edition
vendorShortName=Mozilla

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

@ -5,4 +5,3 @@
brandShorterName=Nightly
brandShortName=Nightly
brandFullName=Firefox Nightly
vendorShortName=Mozilla

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

@ -5,4 +5,3 @@
brandShorterName=Firefox
brandShortName=Firefox
brandFullName=Mozilla Firefox
vendorShortName=Mozilla

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

@ -5,4 +5,3 @@
brandShorterName=Nightly
brandShortName=Nightly
brandFullName=Nightly
vendorShortName=Mozilla

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

@ -778,97 +778,6 @@ let JSWINDOWACTORS = {
},
};
(function earlyBlankFirstPaint() {
let startTime = Cu.now();
if (
AppConstants.platform == "macosx" ||
Services.startup.wasSilentlyStarted ||
!Services.prefs.getBoolPref("browser.startup.blankWindow", false)
) {
return;
}
// Until bug 1450626 and bug 1488384 are fixed, skip the blank window when
// using a non-default theme.
if (
!Services.startup.showedPreXULSkeletonUI &&
Services.prefs.getCharPref(
"extensions.activeThemeID",
"default-theme@mozilla.org"
) != "default-theme@mozilla.org"
) {
return;
}
let store = Services.xulStore;
let getValue = attr =>
store.getValue(AppConstants.BROWSER_CHROME_URL, "main-window", attr);
let width = getValue("width");
let height = getValue("height");
// The clean profile case isn't handled yet. Return early for now.
if (!width || !height) {
return;
}
let browserWindowFeatures =
"chrome,all,dialog=no,extrachrome,menubar,resizable,scrollbars,status," +
"location,toolbar,personalbar";
let win = Services.ww.openWindow(
null,
"about:blank",
null,
browserWindowFeatures,
null
);
// Hide the titlebar if the actual browser window will draw in it.
let hiddenTitlebar = Services.appinfo.drawInTitlebar;
if (hiddenTitlebar) {
win.windowUtils.setChromeMargin(0, 2, 2, 2);
}
let docElt = win.document.documentElement;
docElt.setAttribute("screenX", getValue("screenX"));
docElt.setAttribute("screenY", getValue("screenY"));
// The sizemode="maximized" attribute needs to be set before first paint.
let sizemode = getValue("sizemode");
if (sizemode == "maximized") {
docElt.setAttribute("sizemode", sizemode);
// Set the size to use when the user leaves the maximized mode.
// The persisted size is the outer size, but the height/width
// attributes set the inner size.
let appWin = win.docShell.treeOwner
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIAppWindow);
height -= appWin.outerToInnerHeightDifferenceInCSSPixels;
width -= appWin.outerToInnerWidthDifferenceInCSSPixels;
docElt.setAttribute("height", height);
docElt.setAttribute("width", width);
} else {
// Setting the size of the window in the features string instead of here
// causes the window to grow by the size of the titlebar.
win.resizeTo(width, height);
}
// Set this before showing the window so that graphics code can use it to
// decide to skip some expensive code paths (eg. starting the GPU process).
docElt.setAttribute("windowtype", "navigator:blank");
// The window becomes visible after OnStopRequest, so make this happen now.
win.stop();
ChromeUtils.addProfilerMarker("earlyBlankFirstPaint", startTime);
win.openTime = Cu.now();
let { TelemetryTimestamps } = ChromeUtils.import(
"resource://gre/modules/TelemetryTimestamps.jsm"
);
TelemetryTimestamps.add("blankWindowShown");
})();
XPCOMUtils.defineLazyGetter(
this,
"WeaveService",
@ -1187,6 +1096,9 @@ BrowserGlue.prototype = {
// Allow certain viewable internally types to be opened from downloads.
DownloadsViewableInternally.register();
break;
case "app-startup":
this._earlyBlankFirstPaint(subject);
break;
}
},
@ -1524,6 +1436,104 @@ BrowserGlue.prototype = {
);
},
_earlyBlankFirstPaint(cmdLine) {
let startTime = Cu.now();
if (
AppConstants.platform == "macosx" ||
Services.startup.wasSilentlyStarted ||
!Services.prefs.getBoolPref("browser.startup.blankWindow", false)
) {
return;
}
// Until bug 1450626 and bug 1488384 are fixed, skip the blank window when
// using a non-default theme.
if (
!Services.startup.showedPreXULSkeletonUI &&
Services.prefs.getCharPref(
"extensions.activeThemeID",
"default-theme@mozilla.org"
) != "default-theme@mozilla.org"
) {
return;
}
let store = Services.xulStore;
let getValue = attr =>
store.getValue(AppConstants.BROWSER_CHROME_URL, "main-window", attr);
let width = getValue("width");
let height = getValue("height");
// The clean profile case isn't handled yet. Return early for now.
if (!width || !height) {
return;
}
let browserWindowFeatures =
"chrome,all,dialog=no,extrachrome,menubar,resizable,scrollbars,status," +
"location,toolbar,personalbar";
// This needs to be set when opening the window to ensure that the AppUserModelID
// is set correctly on Windows. Without it, initial launches with `-private-window`
// will show up under the regular Firefox taskbar icon first, and then switch
// to the Private Browsing icon shortly thereafter.
if (cmdLine.findFlag("private-window", false) != -1) {
browserWindowFeatures += ",private";
}
let win = Services.ww.openWindow(
null,
"about:blank",
null,
browserWindowFeatures,
null
);
// Hide the titlebar if the actual browser window will draw in it.
let hiddenTitlebar = Services.appinfo.drawInTitlebar;
if (hiddenTitlebar) {
win.windowUtils.setChromeMargin(0, 2, 2, 2);
}
let docElt = win.document.documentElement;
docElt.setAttribute("screenX", getValue("screenX"));
docElt.setAttribute("screenY", getValue("screenY"));
// The sizemode="maximized" attribute needs to be set before first paint.
let sizemode = getValue("sizemode");
if (sizemode == "maximized") {
docElt.setAttribute("sizemode", sizemode);
// Set the size to use when the user leaves the maximized mode.
// The persisted size is the outer size, but the height/width
// attributes set the inner size.
let appWin = win.docShell.treeOwner
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIAppWindow);
height -= appWin.outerToInnerHeightDifferenceInCSSPixels;
width -= appWin.outerToInnerWidthDifferenceInCSSPixels;
docElt.setAttribute("height", height);
docElt.setAttribute("width", width);
} else {
// Setting the size of the window in the features string instead of here
// causes the window to grow by the size of the titlebar.
win.resizeTo(width, height);
}
// Set this before showing the window so that graphics code can use it to
// decide to skip some expensive code paths (eg. starting the GPU process).
docElt.setAttribute("windowtype", "navigator:blank");
// The window becomes visible after OnStopRequest, so make this happen now.
win.stop();
ChromeUtils.addProfilerMarker("earlyBlankFirstPaint", startTime);
win.openTime = Cu.now();
let { TelemetryTimestamps } = ChromeUtils.import(
"resource://gre/modules/TelemetryTimestamps.jsm"
);
TelemetryTimestamps.add("blankWindowShown");
},
_firstWindowTelemetry(aWindow) {
let scaling = aWindow.devicePixelRatio * 100;
try {

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

@ -33,6 +33,22 @@ hr {
line-height: 1.23em;
}
.header_small {
margin: 12px 0 8px;
font-size: 0.84em;
line-height: 1.07em;
}
.header_flex {
display: flex;
align-items: center;
justify-content: space-between;
}
.header_center {
text-align: center;
}
p {
margin: 8px 0;
font-size: 0.84em;

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

@ -417,6 +417,22 @@ hr {
line-height: 1.23em;
}
.header_small {
margin: 12px 0 8px;
font-size: 0.84em;
line-height: 1.07em;
}
.header_flex {
display: flex;
align-items: center;
justify-content: space-between;
}
.header_center {
text-align: center;
}
p {
margin: 8px 0;
font-size: 0.84em;
@ -2070,6 +2086,7 @@ body.theme_dark .stp_popular_topics .stp_popular_topic .stp_popular_topic_link {
padding: 0;
list-style: none;
}
.stp_article_list .stp_article_list_saved_article,
.stp_article_list .stp_article_list_link {
display: flex;
border-radius: 4px;
@ -2091,6 +2108,10 @@ body.theme_dark .stp_article_list .stp_article_list_link:hover {
margin-inline-end: 8px;
background-color: #ECECEE;
}
.stp_article_list .stp_article_list_thumb:-moz-broken,
.stp_article_list .stp_article_list_thumb_placeholder:-moz-broken {
display: none;
}
.stp_article_list .stp_article_list_header {
font-style: normal;
font-weight: 600;
@ -2098,6 +2119,11 @@ body.theme_dark .stp_article_list .stp_article_list_link:hover {
line-height: 1.27em;
color: #15141A;
margin: 0 0 4px;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
display: -webkit-box;
overflow: hidden;
word-break: break-word;
}
body.theme_dark .stp_article_list .stp_article_list_header {
color: #FBFBFE;
@ -2219,4 +2245,16 @@ body.stp_signup_body {
margin-inline-start: 16px;
}
.stp_panel_error {
margin: 23px 0 32px;
}
.stp_panel_error .stp_panel_error_icon {
float: inline-start;
margin-block: 6px 16px;
margin-inline: 7px 17px;
background-image: url(../img/pocketerror@1x.png);
height: 44px;
width: 44px;
}
/*# sourceMappingURL=main.compiled.css.map */

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

@ -14,3 +14,4 @@
@import "../js/components/Header/Header";
@import "../js/components/Button/Button";
@import "../js/components/Signup/Signup";
@import "../js/components/Saved/Saved";

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

@ -4,29 +4,66 @@
import React from "react";
function ArticleUrl(props) {
// We turn off the link if we're either a saved article, or if the url doesn't exist.
if (props.savedArticle || !props.url) {
return (
<div className="stp_article_list_saved_article">{props.children}</div>
);
}
return (
<a className="stp_article_list_link" href={props.url}>
{props.children}
</a>
);
}
function Article(props) {
function encodeThumbnail(rawSource) {
return rawSource
? `https://img-getpocket.cdn.mozilla.net/80x80/filters:format(jpeg):quality(60):no_upscale():strip_exif()/${encodeURIComponent(
rawSource
)}`
: null;
}
const { article } = props;
const url = article.url || article.resolved_url;
// Using array notation because there is a key titled `1` (`images` is an object)
const thumbnail =
article.thumbnail ||
encodeThumbnail(article?.top_image_url || article?.images?.["1"]?.src);
const alt = article.alt || "thumbnail image";
const title = article.title || article.resolved_title;
// Sometimes domain_metadata is not there, depending on the source.
const publisher =
article.publisher ||
article.domain_metadata?.name ||
article.resolved_domain;
return (
<li className="stp_article_list_item">
<ArticleUrl url={url} savedArticle={props.savedArticle}>
<>
{thumbnail ? (
<img className="stp_article_list_thumb" src={thumbnail} alt={alt} />
) : (
<div className="stp_article_list_thumb_placeholder" />
)}
<div className="stp_article_list_meta">
<header className="stp_article_list_header">{title}</header>
<p className="stp_article_list_publisher">{publisher}</p>
</div>
</>
</ArticleUrl>
</li>
);
}
function ArticleList(props) {
return (
<ul className="stp_article_list">
{props.articles?.map(article => (
<li className="stp_article_list_item">
<a className="stp_article_list_link" href={article.url}>
{article.thumbnail ? (
<img
className="stp_article_list_thumb"
src={article.thumbnail}
alt={article.alt}
/>
) : (
<div className="stp_article_list_thumb_placeholder" />
)}
<div className="stp_article_list_meta">
<header className="stp_article_list_header">
{article.title}
</header>
<p className="stp_article_list_publisher">{article.publisher}</p>
</div>
</a>
</li>
<Article article={article} savedArticle={props.savedArticle} />
))}
</ul>
);

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

@ -2,11 +2,14 @@
padding: 0;
list-style: none;
.stp_article_list_saved_article,
.stp_article_list_link {
display: flex;
border-radius: 4px;
padding: 8px;
}
.stp_article_list_link {
&:hover {
text-decoration: none;
background-color: #ECECEE;
@ -24,6 +27,9 @@
border-radius: 4px;
margin-inline-end: 8px;
background-color: #ECECEE;
&:-moz-broken {
display: none;
}
}
.stp_article_list_header {
@ -34,6 +40,12 @@
color: #15141A;
margin: 0 0 4px;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
display: -webkit-box;
overflow: hidden;
word-break: break-word;
@include theme_dark {
color: #FBFBFE;
}

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

@ -8,6 +8,7 @@ function Button(props) {
return (
<a
href={props.url}
onClick={props.onClick}
className={`stp_button${props?.style && ` stp_button_${props.style}`}`}
>
{props.children}

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

@ -9,14 +9,6 @@ import PopularTopics from "../PopularTopics/PopularTopics";
import Button from "../Button/Button";
import panelMessaging from "../../messages";
function encodeThumbnail(rawSource) {
return rawSource
? `https://img-getpocket.cdn.mozilla.net/80x80/filters:format(jpeg):quality(60):no_upscale():strip_exif()/${encodeURIComponent(
rawSource
)}`
: null;
}
function Home(props) {
const { locale, topics, pockethost, hideRecentSaves } = props;
const [{ articles, status }, setArticlesState] = useState({
@ -52,16 +44,7 @@ function Home(props) {
}
setArticlesState({
articles: data.map(item => ({
url: item.resolved_url,
// Using array notation because there is a key titled `1` (`images` is an object)
thumbnail: encodeThumbnail(
item?.top_image_url || item?.images?.["1"]?.src
),
alt: "thumbnail image",
title: item.resolved_title,
publisher: item.domain_metadata?.name,
})),
articles: data,
status: "success",
});
});

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

@ -2,31 +2,165 @@
* 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/. */
import React from "react";
import React, { useState, useEffect } from "react";
import Header from "../Header/Header";
import Button from "../Button/Button";
import ArticleList from "../ArticleList/ArticleList";
import panelMessaging from "../../messages";
function Saved(props) {
const { similarRecs, savedStory } = props;
const { locale } = props;
// savedStatus can be success, loading, or error.
const [
{ savedStatus, savedErrorId, itemId },
setSavedStatusState,
] = useState({ savedStatus: "loading" });
// removedStatus can be removed, removing, or error.
const [
{ removedStatus, removedErrorMessage },
setRemovedStatusState,
] = useState({});
const [savedStory, setSavedStoryState] = useState();
const [similarRecs, setSimilarRecsState] = useState();
function removeItem(event) {
event.preventDefault();
setRemovedStatusState({ removedStatus: "removing" });
panelMessaging.sendMessage(
"PKT_deleteItem",
{
itemId,
},
function(resp) {
const { data } = resp;
if (data.status == "success") {
setRemovedStatusState({ removedStatus: "removed" });
} else if (data.status == "error") {
let errorMessage = "";
// The server returns English error messages, so in the case of
// non English, we do our best with a generic translated error.
if (data.error.message && locale?.startsWith("en")) {
errorMessage = data.error.message;
}
setRemovedStatusState({
removedStatus: "error",
removedErrorMessage: errorMessage,
});
}
}
);
}
useEffect(() => {
// Wait confirmation of save before flipping to final saved state
panelMessaging.addMessageListener("PKT_saveLink", function(resp) {
const { data } = resp;
if (data.status == "error") {
// Use localizedKey or fallback to a generic catch all error.
setSavedStatusState({
savedStatus: "error",
savedErrorId:
data?.error?.localizedKey || "pocket-panel-saved-error-generic",
});
return;
}
// Success, so no localized error id needed.
setSavedStatusState({
savedStatus: "success",
itemId: data.item.item_id,
savedErrorId: "",
});
});
panelMessaging.addMessageListener("PKT_renderSavedStory", function(resp) {
setSavedStoryState(resp?.data?.item_preview);
});
panelMessaging.addMessageListener("PKT_renderItemRecs", function(resp) {
const { data } = resp;
setSimilarRecsState(data?.recommendations?.map(rec => rec.item));
});
// tell back end we're ready
panelMessaging.sendMessage("PKT_show_saved");
}, []);
if (savedStatus === "error") {
return (
<div className="stp_panel_container">
<div className="stp_panel stp_panel_error">
<div className="stp_panel_error_icon" />
<h3
className="header_large"
data-l10n-id="pocket-panel-saved-error-not-saved"
/>
<p data-l10n-id={savedErrorId} />
</div>
</div>
);
}
return (
<div className="stp_panel_container">
<div className="stp_panel stp_panel_home">
<div className="stp_panel stp_panel_saved">
<Header>
<a>
<Button style="primary">
<span data-l10n-id="pocket-panel-header-my-list"></span>
</a>
</Button>
</Header>
<hr />
{savedStory && (
{!removedStatus && savedStatus === "success" && (
<>
<p data-l10n-id="pocket-panel-saved-page-saved"></p>
<ArticleList articles={[savedStory]} />
<span data-l10n-id="pocket-panel-button-add-tags"></span>
<span data-l10n-id="pocket-panel-saved-remove-page"></span>
<h3 className="header_large header_flex">
<span data-l10n-id="pocket-panel-saved-page-saved-b" />
<Button style="text" url="google.com" onClick={removeItem}>
<span data-l10n-id="pocket-panel-button-remove"></span>
</Button>
</h3>
{savedStory && (
<ArticleList articles={[savedStory]} savedArticle={true} />
)}
<h3
className="header_small"
data-l10n-id="pocket-panel-cta-add-tags"
/>
{similarRecs?.length && locale?.startsWith("en") && (
<>
<hr />
<h3 className="header_medium">Similar Stories</h3>
<ArticleList articles={similarRecs} />
</>
)}
</>
)}
{savedStatus === "loading" && (
<h3
className="header_large"
data-l10n-id="pocket-panel-saved-saving-tags"
/>
)}
{removedStatus === "removing" && (
<h3
className="header_large header_center"
data-l10n-id="pocket-panel-saved-processing-remove"
/>
)}
{removedStatus === "removed" && (
<h3
className="header_large header_center"
data-l10n-id="pocket-panel-saved-removed"
/>
)}
{removedStatus === "error" && (
<>
<h3
className="header_large"
data-l10n-id="pocket-panel-saved-error-remove"
/>
{removedErrorMessage && <p>{removedErrorMessage}</p>}
</>
)}
<hr />
{similarRecs?.length && <ArticleList articles={similarRecs} />}
</div>
</div>
);

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

@ -0,0 +1,11 @@
.stp_panel_error {
margin: 23px 0 32px;
.stp_panel_error_icon {
float: inline-start;
margin-block: 6px 16px;
margin-inline: 7px 17px;
background-image: url(../img/pocketerror@1x.png);
height: 44px;
width: 44px;
}
}

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

@ -55,27 +55,62 @@ function Header(props) {
* You can obtain one at http://mozilla.org/MPL/2.0/. */
function ArticleList(props) {
return /*#__PURE__*/react.createElement("ul", {
className: "stp_article_list"
}, props.articles?.map(article => /*#__PURE__*/react.createElement("li", {
className: "stp_article_list_item"
}, /*#__PURE__*/react.createElement("a", {
function ArticleUrl(props) {
// We turn off the link if we're either a saved article, or if the url doesn't exist.
if (props.savedArticle || !props.url) {
return /*#__PURE__*/react.createElement("div", {
className: "stp_article_list_saved_article"
}, props.children);
}
return /*#__PURE__*/react.createElement("a", {
className: "stp_article_list_link",
href: article.url
}, article.thumbnail ? /*#__PURE__*/react.createElement("img", {
href: props.url
}, props.children);
}
function Article(props) {
function encodeThumbnail(rawSource) {
return rawSource ? `https://img-getpocket.cdn.mozilla.net/80x80/filters:format(jpeg):quality(60):no_upscale():strip_exif()/${encodeURIComponent(rawSource)}` : null;
}
const {
article
} = props;
const url = article.url || article.resolved_url; // Using array notation because there is a key titled `1` (`images` is an object)
const thumbnail = article.thumbnail || encodeThumbnail(article?.top_image_url || article?.images?.["1"]?.src);
const alt = article.alt || "thumbnail image";
const title = article.title || article.resolved_title; // Sometimes domain_metadata is not there, depending on the source.
const publisher = article.publisher || article.domain_metadata?.name || article.resolved_domain;
return /*#__PURE__*/react.createElement("li", {
className: "stp_article_list_item"
}, /*#__PURE__*/react.createElement(ArticleUrl, {
url: url,
savedArticle: props.savedArticle
}, /*#__PURE__*/react.createElement(react.Fragment, null, thumbnail ? /*#__PURE__*/react.createElement("img", {
className: "stp_article_list_thumb",
src: article.thumbnail,
alt: article.alt
src: thumbnail,
alt: alt
}) : /*#__PURE__*/react.createElement("div", {
className: "stp_article_list_thumb_placeholder"
}), /*#__PURE__*/react.createElement("div", {
className: "stp_article_list_meta"
}, /*#__PURE__*/react.createElement("header", {
className: "stp_article_list_header"
}, article.title), /*#__PURE__*/react.createElement("p", {
}, title), /*#__PURE__*/react.createElement("p", {
className: "stp_article_list_publisher"
}, article.publisher))))));
}, publisher)))));
}
function ArticleList(props) {
return /*#__PURE__*/react.createElement("ul", {
className: "stp_article_list"
}, props.articles?.map(article => /*#__PURE__*/react.createElement(Article, {
article: article,
savedArticle: props.savedArticle
})));
}
/* harmony default export */ const ArticleList_ArticleList = (ArticleList);
@ -107,6 +142,7 @@ function PopularTopics(props) {
function Button(props) {
return /*#__PURE__*/react.createElement("a", {
href: props.url,
onClick: props.onClick,
className: `stp_button${props?.style && ` stp_button_${props.style}`}`
}, props.children);
}
@ -177,10 +213,6 @@ var pktPanelMessaging = {
function encodeThumbnail(rawSource) {
return rawSource ? `https://img-getpocket.cdn.mozilla.net/80x80/filters:format(jpeg):quality(60):no_upscale():strip_exif()/${encodeURIComponent(rawSource)}` : null;
}
function Home(props) {
const {
locale,
@ -220,14 +252,7 @@ function Home(props) {
}
setArticlesState({
articles: data.map(item => ({
url: item.resolved_url,
// Using array notation because there is a key titled `1` (`images` is an object)
thumbnail: encodeThumbnail(item?.top_image_url || item?.images?.["1"]?.src),
alt: "thumbnail image",
title: item.resolved_title,
publisher: item.domain_metadata?.name
})),
articles: data,
status: "success"
});
});
@ -580,28 +605,152 @@ var SignupOverlay = function (options) {
function Saved(props) {
const {
similarRecs,
savedStory
} = props;
locale
} = props; // savedStatus can be success, loading, or error.
const [{
savedStatus,
savedErrorId,
itemId
}, setSavedStatusState] = (0,react.useState)({
savedStatus: "loading"
}); // removedStatus can be removed, removing, or error.
const [{
removedStatus,
removedErrorMessage
}, setRemovedStatusState] = (0,react.useState)({});
const [savedStory, setSavedStoryState] = (0,react.useState)();
const [similarRecs, setSimilarRecsState] = (0,react.useState)();
function removeItem(event) {
event.preventDefault();
setRemovedStatusState({
removedStatus: "removing"
});
messages.sendMessage("PKT_deleteItem", {
itemId
}, function (resp) {
const {
data
} = resp;
if (data.status == "success") {
setRemovedStatusState({
removedStatus: "removed"
});
} else if (data.status == "error") {
let errorMessage = ""; // The server returns English error messages, so in the case of
// non English, we do our best with a generic translated error.
if (data.error.message && locale?.startsWith("en")) {
errorMessage = data.error.message;
}
setRemovedStatusState({
removedStatus: "error",
removedErrorMessage: errorMessage
});
}
});
}
(0,react.useEffect)(() => {
// Wait confirmation of save before flipping to final saved state
messages.addMessageListener("PKT_saveLink", function (resp) {
const {
data
} = resp;
if (data.status == "error") {
// Use localizedKey or fallback to a generic catch all error.
setSavedStatusState({
savedStatus: "error",
savedErrorId: data?.error?.localizedKey || "pocket-panel-saved-error-generic"
});
return;
} // Success, so no localized error id needed.
setSavedStatusState({
savedStatus: "success",
itemId: data.item.item_id,
savedErrorId: ""
});
});
messages.addMessageListener("PKT_renderSavedStory", function (resp) {
setSavedStoryState(resp?.data?.item_preview);
});
messages.addMessageListener("PKT_renderItemRecs", function (resp) {
const {
data
} = resp;
setSimilarRecsState(data?.recommendations?.map(rec => rec.item));
}); // tell back end we're ready
messages.sendMessage("PKT_show_saved");
}, []);
if (savedStatus === "error") {
return /*#__PURE__*/react.createElement("div", {
className: "stp_panel_container"
}, /*#__PURE__*/react.createElement("div", {
className: "stp_panel stp_panel_error"
}, /*#__PURE__*/react.createElement("div", {
className: "stp_panel_error_icon"
}), /*#__PURE__*/react.createElement("h3", {
className: "header_large",
"data-l10n-id": "pocket-panel-saved-error-not-saved"
}), /*#__PURE__*/react.createElement("p", {
"data-l10n-id": savedErrorId
})));
}
return /*#__PURE__*/react.createElement("div", {
className: "stp_panel_container"
}, /*#__PURE__*/react.createElement("div", {
className: "stp_panel stp_panel_home"
}, /*#__PURE__*/react.createElement(Header_Header, null, /*#__PURE__*/react.createElement("a", null, /*#__PURE__*/react.createElement("span", {
className: "stp_panel stp_panel_saved"
}, /*#__PURE__*/react.createElement(Header_Header, null, /*#__PURE__*/react.createElement(Button_Button, {
style: "primary"
}, /*#__PURE__*/react.createElement("span", {
"data-l10n-id": "pocket-panel-header-my-list"
}))), /*#__PURE__*/react.createElement("hr", null), savedStory && /*#__PURE__*/react.createElement(react.Fragment, null, /*#__PURE__*/react.createElement("p", {
"data-l10n-id": "pocket-panel-saved-page-saved"
}), /*#__PURE__*/react.createElement(ArticleList_ArticleList, {
articles: [savedStory]
}), /*#__PURE__*/react.createElement("span", {
"data-l10n-id": "pocket-panel-button-add-tags"
}), /*#__PURE__*/react.createElement("span", {
"data-l10n-id": "pocket-panel-saved-remove-page"
})), /*#__PURE__*/react.createElement("hr", null), similarRecs?.length && /*#__PURE__*/react.createElement(ArticleList_ArticleList, {
}))), /*#__PURE__*/react.createElement("hr", null), !removedStatus && savedStatus === "success" && /*#__PURE__*/react.createElement(react.Fragment, null, /*#__PURE__*/react.createElement("h3", {
className: "header_large header_flex"
}, /*#__PURE__*/react.createElement("span", {
"data-l10n-id": "pocket-panel-saved-page-saved-b"
}), /*#__PURE__*/react.createElement(Button_Button, {
style: "text",
url: "google.com",
onClick: removeItem
}, /*#__PURE__*/react.createElement("span", {
"data-l10n-id": "pocket-panel-button-remove"
}))), savedStory && /*#__PURE__*/react.createElement(ArticleList_ArticleList, {
articles: [savedStory],
savedArticle: true
}), /*#__PURE__*/react.createElement("h3", {
className: "header_small",
"data-l10n-id": "pocket-panel-cta-add-tags"
}), similarRecs?.length && locale?.startsWith("en") && /*#__PURE__*/react.createElement(react.Fragment, null, /*#__PURE__*/react.createElement("hr", null), /*#__PURE__*/react.createElement("h3", {
className: "header_medium"
}, "Similar Stories"), /*#__PURE__*/react.createElement(ArticleList_ArticleList, {
articles: similarRecs
})));
}))), savedStatus === "loading" && /*#__PURE__*/react.createElement("h3", {
className: "header_large",
"data-l10n-id": "pocket-panel-saved-saving-tags"
}), removedStatus === "removing" && /*#__PURE__*/react.createElement("h3", {
className: "header_large header_center",
"data-l10n-id": "pocket-panel-saved-processing-remove"
}), removedStatus === "removed" && /*#__PURE__*/react.createElement("h3", {
className: "header_large header_center",
"data-l10n-id": "pocket-panel-saved-removed"
}), removedStatus === "error" && /*#__PURE__*/react.createElement(react.Fragment, null, /*#__PURE__*/react.createElement("h3", {
className: "header_large",
"data-l10n-id": "pocket-panel-saved-error-remove"
}), removedErrorMessage && /*#__PURE__*/react.createElement("p", null, removedErrorMessage))));
}
/* harmony default export */ const Saved_Saved = (Saved);
@ -1129,10 +1278,14 @@ SavedOverlay.prototype = {
const layoutRefresh = searchParams.get(`layoutRefresh`) === `true`;
if (layoutRefresh) {
// Create actual content
// For now, we need to do a little work on the body element
// to support both old and new versions.
document.querySelector(`.pkt_ext_containersaved`)?.classList.add(`stp_saved_body`);
document.querySelector(`.pkt_ext_containersaved`)?.classList.remove(`pkt_ext_containersaved`); // Create actual content
react_dom.render( /*#__PURE__*/react.createElement(Saved_Saved, {
pockethost: pockethost,
savedStory: {}
locale: locale
}), document.querySelector(`body`));
} else {
// set host
@ -1183,11 +1336,10 @@ SavedOverlay.prototype = {
data
} = resp;
myself.renderItemRecs(data);
});
} // tell back end we're ready
}); // tell back end we're ready
messages.sendMessage("PKT_show_saved");
messages.sendMessage("PKT_show_saved");
}
}
};

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

@ -667,9 +667,17 @@ SavedOverlay.prototype = {
const layoutRefresh = searchParams.get(`layoutRefresh`) === `true`;
if (layoutRefresh) {
// For now, we need to do a little work on the body element
// to support both old and new versions.
document
.querySelector(`.pkt_ext_containersaved`)
?.classList.add(`stp_saved_body`);
document
.querySelector(`.pkt_ext_containersaved`)
?.classList.remove(`pkt_ext_containersaved`);
// Create actual content
ReactDOM.render(
<Saved pockethost={pockethost} savedStory={{}} />,
<Saved pockethost={pockethost} locale={locale} />,
document.querySelector(`body`)
);
} else {
@ -748,10 +756,10 @@ SavedOverlay.prototype = {
const { data } = resp;
myself.renderItemRecs(data);
});
}
// tell back end we're ready
pktPanelMessaging.sendMessage("PKT_show_saved");
// tell back end we're ready
pktPanelMessaging.sendMessage("PKT_show_saved");
}
},
};

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

@ -367,6 +367,14 @@ var pktUI = (function() {
pktUIMessaging.sendMessageToPanel(saveLinkMessageId, successResponse);
SaveToPocket.itemSaved();
if (item?.resolved_id && item?.resolved_id !== "0") {
pktApi.getArticleInfo(item.resolved_url, {
success(data) {
pktUIMessaging.sendMessageToPanel("PKT_renderSavedStory", data);
},
});
}
getAndShowRecsForItem(item, {
success(data) {
pktUIMessaging.sendMessageToPanel("PKT_renderItemRecs", data);

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

@ -47,6 +47,10 @@ class PictureInPictureVideoWrapper {
});
}
}
shouldHideToggle(video) {
return !!video.classList.contains("tst-video-overlay-player-html5");
}
}
this.PictureInPictureVideoWrapper = PictureInPictureVideoWrapper;

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

@ -15,9 +15,12 @@ pocket-panel-saved-error-tag-length = Tags are limited to 25 characters
pocket-panel-saved-error-only-links = Only links can be saved
pocket-panel-saved-error-not-saved = Page Not Saved
pocket-panel-saved-error-no-internet = You must be connected to the Internet in order to save to { -pocket-brand-name }. Please connect to the Internet and try again.
pocket-panel-saved-error-remove = There was an error while trying to remove this page.
pocket-panel-saved-page-removed = Page Removed
pocket-panel-saved-page-saved = Saved to { -pocket-brand-name }
pocket-panel-saved-page-saved-b = Saved to { -pocket-brand-name }!
pocket-panel-saved-processing-remove = Removing Page…
pocket-panel-saved-removed = Page Removed from My List
pocket-panel-saved-processing-tags = Adding tags…
pocket-panel-saved-remove-page = Remove Page
pocket-panel-saved-save-tags = Save
@ -26,6 +29,9 @@ pocket-panel-saved-suggested-tags = Suggested Tags
pocket-panel-saved-tags-saved = Tags Added
pocket-panel-signup-view-list = View List
# This is displayed above a field where the user can add tags
pocket-panel-signup-add-tags = Add Tags:
## about:pocket-signup panel
pocket-panel-signup-already-have = Already a { -pocket-brand-name } user?
@ -65,5 +71,5 @@ pocket-panel-header-sign-in = Sign In
## Pocket panel buttons
pocket-panel-button-show-all = Show All
pocket-panel-button-add-tags = Add Tags
pocket-panel-button-activate = Activate { -pocket-brand-name } in { -brand-product-name }
pocket-panel-button-remove = Remove

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

@ -829,3 +829,10 @@ tabs-toolbar-list-all-tabs =
# <img data-l10n-name="icon"/> will be replaced by the application menu icon
restore-session-startup-suggestion-message = <strong>Open previous tabs?</strong> You can restore your previous session from the { -brand-short-name } application menu <img data-l10n-name="icon"/>, under History.
restore-session-startup-suggestion-button = Show me how
## Mozilla data reporting notification (Telemetry, Firefox Health Report, etc)
data-reporting-notification-message = { -brand-short-name } automatically sends some data to { -vendor-short-name } so that we can improve your experience.
data-reporting-notification-button =
.label = Choose What I Share
.accesskey = C

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

@ -173,6 +173,10 @@ main-context-menu-copy-email =
.label = Copy Email Address
.accesskey = l
main-context-menu-copy-phone =
.label = Copy Phone Number
.accesskey = o
main-context-menu-copy-link-simple =
.label = Copy Link
.accesskey = L

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

@ -4,6 +4,7 @@
# Dialog close button
spotlight-dialog-close-button =
.title = Close
.aria-label = Close
## Mobile download button strings
@ -16,6 +17,6 @@ spotlight-ios-marketplace-button =
## Firefox Focus promo message strings
spotlight-focus-promo-title = Get { -focus-brand-name }
spotlight-focus-promo-subtitle = Scan the QR code to download
spotlight-focus-promo-subtitle = Scan the QR code to download.
spotlight-focus-promo-qr-code =
.alt = Scan the QR code to get { -focus-brand-name }

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

@ -673,11 +673,6 @@ troubleshootModeRestartButton=Restart
# menu, set this to "true". Otherwise, you can leave it as "false".
browser.menu.showCharacterEncoding=false
# Mozilla data reporting notification (Telemetry, Firefox Health Report, etc)
dataReportingNotification.message = %1$S automatically sends some data to %2$S so that we can improve your experience.
dataReportingNotification.button.label = Choose What I Share
dataReportingNotification.button.accessKey = C
# Process hang reporter
# LOCALIZATION NOTE (processHang.selected_tab.label): %1$S is the name of the product (e.g., Firefox)
processHang.selected_tab.label = This page is slowing down %1$S. To speed up your browser, stop this page.

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

@ -1,37 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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/. -->
<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 64 64">
<defs>
<style>
.style-puzzle-piece {
fill: url('#gradient-linear-puzzle-piece');
}
.style-badge-shadow {
fill: #0d131a;
fill-opacity: .15;
}
.style-badge-background {
fill: #fff;
}
.style-badge-inside {
fill: #e62117;
}
.style-badge-icon {
fill: #fff;
}
</style>
<linearGradient id="gradient-linear-puzzle-piece" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" stop-color="#999999" stop-opacity="1"/>
<stop offset="100%" stop-color="#8c8c8c" stop-opacity="1"/>
</linearGradient>
</defs>
<path class="style-puzzle-piece" d="M42,62c2.2,0,4-1.8,4-4l0-14.2c0,0,0.4-3.7,2.8-3.7c2.4,0,2.2,3.9,6.7,3.9c2.3,0,6.2-1.2,6.2-8.2 c0-7-3.9-7.9-6.2-7.9c-4.5,0-4.3,3.7-6.7,3.7c-2.4,0-2.8-3.8-2.8-3.8V22c0-2.2-1.8-4-4-4H31.5c0,0-3.4-0.6-3.4-3 c0-2.4,3.8-2.6,3.8-7.1c0-2.3-1.3-5.9-8.3-5.9s-8,3.6-8,5.9c0,4.5,3.4,4.7,3.4,7.1c0,2.4-3.4,3-3.4,3H6c-2.2,0-4,1.8-4,4l0,7.8 c0,0-0.4,6,4.4,6c3.1,0,3.2-4.1,7.3-4.1c2,0,4,1.9,4,6c0,4.2-2,6.3-4,6.3c-4,0-4.2-4.1-7.3-4.1c-4.8,0-4.4,5.8-4.4,5.8L2,58 c0,2.2,1.8,4,4,4H19c0,0,6.3,0.4,6.3-4.4c0-3.1-4-3.6-4-7.7c0-2,2.2-4.5,6.4-4.5c4.2,0,6.6,2.5,6.6,4.5c0,4-3.9,4.6-3.9,7.7 c0,4.9,6.3,4.4,6.3,4.4H42z"/>
<svg width="32" height="32" x="32" y="0">
<ellipse class="style-badge-shadow" rx="14" ry="15" cx="16" cy="17" />
<circle class="style-badge-background" r="15" cy="15" cx="16" />
<circle class="style-badge-inside" r="12" cy="15" cx="16" />
<path class="style-badge-icon" d="M14.9,16.2c0,0,0.1,0.8,1.1,0.8c1,0,1.1-0.8,1.1-0.8 s0.7-3.5,0.8-5.2C18,9.3,18.4,7,16,7s-2,2.4-1.9,4C14.2,12.7,14.9,16.2,14.9,16.2z M16,19c-1.1,0-2,0.9-2,2c0,1.1,0.9,2,2,2 c1.1,0,2-0.9,2-2C18,19.9,17.1,19,16,19z" />
</svg>
</svg>

До

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

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

@ -1,37 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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/. -->
<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 64 64">
<defs>
<style>
.style-puzzle-piece {
fill: url('#gradient-linear-puzzle-piece');
}
.style-badge-shadow {
fill: #0d131a;
fill-opacity: .15;
}
.style-badge-background {
fill: #fff;
}
.style-badge-inside {
fill: #ffcd02;
}
.style-badge-icon {
fill: #fff;
}
</style>
<linearGradient id="gradient-linear-puzzle-piece" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" stop-color="#999999" stop-opacity="1"/>
<stop offset="100%" stop-color="#8c8c8c" stop-opacity="1"/>
</linearGradient>
</defs>
<path class="style-puzzle-piece" d="M42,62c2.2,0,4-1.8,4-4l0-14.2c0,0,0.4-3.7,2.8-3.7c2.4,0,2.2,3.9,6.7,3.9c2.3,0,6.2-1.2,6.2-8.2 c0-7-3.9-7.9-6.2-7.9c-4.5,0-4.3,3.7-6.7,3.7c-2.4,0-2.8-3.8-2.8-3.8V22c0-2.2-1.8-4-4-4H31.5c0,0-3.4-0.6-3.4-3 c0-2.4,3.8-2.6,3.8-7.1c0-2.3-1.3-5.9-8.3-5.9s-8,3.6-8,5.9c0,4.5,3.4,4.7,3.4,7.1c0,2.4-3.4,3-3.4,3H6c-2.2,0-4,1.8-4,4l0,7.8 c0,0-0.4,6,4.4,6c3.1,0,3.2-4.1,7.3-4.1c2,0,4,1.9,4,6c0,4.2-2,6.3-4,6.3c-4,0-4.2-4.1-7.3-4.1c-4.8,0-4.4,5.8-4.4,5.8L2,58 c0,2.2,1.8,4,4,4H19c0,0,6.3,0.4,6.3-4.4c0-3.1-4-3.6-4-7.7c0-2,2.2-4.5,6.4-4.5c4.2,0,6.6,2.5,6.6,4.5c0,4-3.9,4.6-3.9,7.7 c0,4.9,6.3,4.4,6.3,4.4H42z"/>
<svg width="32" height="32" x="32" y="0">
<path class="style-badge-shadow" d="M29.5,25.8L18.7,4c-0.6-1.2-1.6-2-2.7-2c-1.1,0-2.1,0.7-2.7,2L2.5,25.8 c-0.6,1.2-0.6,2.5-0.1,3.6C2.9,30.4,4,31,5.2,31h21.6c1.2,0,2.3-0.6,2.8-1.6C30.2,28.4,30.1,27.1,29.5,25.8z" />
<path class="style-badge-background" d="M16,0c-1.7,0-3.2,1-4.1,2.7L1.7,21.9c-0.9,1.7-0.9,3.4,0,4.8C2.5,28.2,4.1,29,5.9,29H26 c1.9,0,3.4-0.8,4.3-2.2c0.9-1.4,0.8-3.2,0-4.8L20.1,2.7C19.2,1,17.7,0,16,0L16,0z" />
<path class="style-badge-inside" d="M5.9,26c-1.7,0-2.4-1.2-1.6-2.7L14.6,4.1c0.8-1.5,2.1-1.5,2.8,0l10.3,19.3 c0.8,1.5,0.1,2.7-1.6,2.7H5.9z" />
<path class="style-badge-icon" d="M14.9,17.6c0,0,0.1,0.7,1.1,0.7c1,0,1.1-0.7,1.1-0.7 s0.7-2.9,0.8-4.2c0.1-1.3,0.5-3.2-1.9-3.2c-2.4,0-2,1.9-1.9,3.2C14.2,14.8,14.9,17.6,14.9,17.6z M16,20c-1.1,0-2,0.9-2,2 c0,1.1,0.9,2,2,2c1.1,0,2-0.9,2-2C18,20.9,17.1,20,16,20z" />
</svg>
</svg>

До

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

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

@ -36,9 +36,7 @@
skin/classic/browser/webRTC-indicator.css (../shared/webRTC-indicator.css)
skin/classic/browser/addons/addon-install-blocked.svg (../shared/addons/addon-install-blocked.svg)
skin/classic/browser/addons/addon-install-downloading.svg (../shared/addons/addon-install-downloading.svg)
skin/classic/browser/addons/addon-install-error.svg (../shared/addons/addon-install-error.svg)
skin/classic/browser/addons/addon-install-installed.svg (../shared/addons/addon-install-installed.svg)
skin/classic/browser/addons/addon-install-warning.svg (../shared/addons/addon-install-warning.svg)
skin/classic/browser/addons/extension-controlled.css (../shared/addons/extension-controlled.css)
skin/classic/browser/controlcenter/3rdpartycookies.svg (../shared/controlcenter/3rdpartycookies.svg)
skin/classic/browser/controlcenter/cryptominers.svg (../shared/controlcenter/cryptominers.svg)

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

@ -52,12 +52,10 @@
list-style-image: url(chrome://global/skin/icons/info.svg);
}
.popup-notification-icon[popupid="storage-access"],
.storage-access-icon {
list-style-image: url(chrome://browser/skin/controlcenter/3rdpartycookies.svg);
}
.popup-notification-icon[popupid="persistent-storage"],
.persistent-storage-icon {
list-style-image: url(chrome://browser/skin/notification-icons/persistent-storage.svg);
}
@ -66,7 +64,6 @@
list-style-image: url(chrome://browser/skin/notification-icons/persistent-storage-blocked.svg);
}
.popup-notification-icon[popupid="web-notifications"],
.desktop-notification-icon {
list-style-image: url(chrome://browser/skin/notification-icons/desktop-notification.svg);
}
@ -83,10 +80,6 @@
list-style-image: url(chrome://browser/skin/notification-icons/geo-blocked.svg);
}
.popup-notification-icon[popupid="geolocation"] {
list-style-image: url(chrome://browser/skin/notification-icons/geo.svg);
}
.open-protocol-handler-icon {
list-style-image: url(chrome://global/skin/icons/open-in-new.svg);
}
@ -103,18 +96,10 @@
list-style-image: url(chrome://browser/skin/notification-icons/xr-blocked.svg);
}
.popup-notification-icon[popupid="xr"] {
list-style-image: url(chrome://browser/skin/notification-icons/xr.svg);
}
.autoplay-media-icon {
list-style-image: url(chrome://browser/skin/notification-icons/autoplay-media.svg);
}
.popup-notification-icon[popupid="autoplay-media"] {
list-style-image: url(chrome://browser/skin/notification-icons/autoplay-media.svg);
}
.autoplay-media-icon.blocked-permission-icon {
list-style-image: url(chrome://browser/skin/notification-icons/autoplay-media-blocked.svg);
}
@ -137,12 +122,10 @@
padding: 20px;
}
.popup-notification-icon[popupid="indexedDB-permissions-prompt"],
.indexedDB-icon {
list-style-image: url(chrome://browser/skin/notification-icons/persistent-storage.svg);
}
.popup-notification-icon[popupid="password"],
#password-notification-icon {
list-style-image: url(chrome://browser/skin/login.svg);
}
@ -197,14 +180,11 @@
}
.midi-icon,
.midi-sysex-icon,
.popup-notification-icon[popupid="midi"],
.popup-notification-icon[popupid="midi-sysex"] {
.midi-sysex-icon {
list-style-image: url(chrome://browser/skin/notification-icons/midi.svg);
}
#canvas-notification-icon,
.popup-notification-icon[popupid="canvas-permissions-prompt"],
.canvas-icon {
list-style-image: url(chrome://browser/skin/canvas.svg);
}
@ -294,7 +274,6 @@
/* EME */
.popup-notification-icon[popupid="drmContentPlaying"],
.drm-icon {
list-style-image: url("chrome://browser/skin/drm-icon.svg");
}
@ -317,39 +296,10 @@
list-style-image: url(chrome://mozapps/skin/extensions/extension.svg);
}
.install-icon.blocked-permission-icon,
.popup-notification-icon[popupid="xpinstall-disabled"],
.popup-notification-icon[popupid="addon-install-blocked"],
.popup-notification-icon[popupid="addon-install-origin-blocked"] {
.install-icon.blocked-permission-icon {
list-style-image: url(chrome://browser/skin/addons/addon-install-blocked.svg);
}
.popup-notification-icon[popupid="addon-progress"] {
list-style-image: url(chrome://browser/skin/addons/addon-install-downloading.svg);
}
.popup-notification-icon[popupid="addon-install-failed"] {
list-style-image: url(chrome://browser/skin/addons/addon-install-error.svg);
}
.popup-notification-icon[popupid="addon-install-confirmation"] {
list-style-image: url(chrome://mozapps/skin/extensions/extension.svg);
}
#addon-install-confirmation-notification[warning] .popup-notification-icon[popupid="addon-install-confirmation"] {
list-style-image: url(chrome://browser/skin/addons/addon-install-warning.svg);
}
.popup-notification-icon[popupid="addon-install-complete"] {
list-style-image: url(chrome://browser/skin/addons/addon-install-installed.svg);
}
/* OFFLINE APPS */
.popup-notification-icon[popupid="offline-app-usage"] {
list-style-image: url(chrome://global/skin/icons/help.svg);
}
/* PLUGINS */
.plugin-icon {
@ -436,20 +386,3 @@
-moz-image-region: rect(0px, 64px, 32px, 32px);
}
}
/* UPDATE */
.popup-notification-icon[popupid="update-available"],
.popup-notification-icon[popupid="update-downloading"],
.popup-notification-icon[popupid="update-manual"],
.popup-notification-icon[popupid="update-other-instance"],
.popup-notification-icon[popupid="update-restart"] {
background: url(chrome://browser/skin/update-badge.svg) no-repeat center;
-moz-context-properties: fill;
fill: var(--panel-banner-item-update-supported-bgcolor);
}
.popup-notification-icon[popupid="update-unsupported"] {
background: url(chrome://global/skin/icons/warning.svg) no-repeat center;
-moz-context-properties: fill;
fill: var(--warning-icon-bgcolor);
}

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

@ -305,6 +305,10 @@ checkbox {
font-size: 90%;
}
#colors {
margin-inline-start: 5px;
}
#FontsDialog menulist:empty {
/* When there's no menupopup, while the font builder is running,
* the height of the menulist would otherwise shrink. This throws

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

@ -7,9 +7,6 @@ path:build/moz.configure/init.configure
path:build/moz.configure/util.configure
# Used for bootstrapping the mach driver.
path:build/mach_initialize.py
path:build/build_virtualenv_packages.txt
path:build/common_virtualenv_packages.txt
path:build/mach_virtualenv_packages.txt
path:build/psutil_requirements.txt
path:build/zstandard_requirements.txt
path:mach

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

@ -2,7 +2,7 @@
[include]
# List of dependencies for the command
path:build/docs_virtualenv_packages.txt
path:python/sites/docs.txt
# Code for generating docs.
glob:docs/**

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

@ -66,6 +66,19 @@ const FIREFOX_DEFAULT_HEADERS = [
"Upgrade",
"Via",
];
const HTTP_METHODS = [
"GET",
"HEAD",
"POST",
"DELETE",
"PUT",
"CONNECT",
"OPTIONS",
"TRACE",
"PATH",
];
/*
* HTTP Custom request panel component
* A network request panel which enables creating and sending new requests
@ -95,7 +108,7 @@ class HTTPCustomRequestPanel extends Component {
}
if (request.requestPostData?.postData?.text) {
request.requestPostData = request.requestPostData.postData.text;
request.postBody = request.requestPostData.postData.text;
}
this.URLTextareaRef = createRef();
@ -120,11 +133,11 @@ class HTTPCustomRequestPanel extends Component {
});
this.state = {
method: request.method || "",
method: request.method || HTTP_METHODS[0],
url: request.url || "",
urlQueryParams: this.createQueryParamsListFromURL(request.url),
headers: requestHeaders || [],
requestPostData: request.requestPostData || "",
postBody: request.postBody || "",
};
Services.prefs.setCharPref(
@ -147,6 +160,19 @@ class HTTPCustomRequestPanel extends Component {
this.getStateFromPref = this.getStateFromPref.bind(this);
}
async componentWillMount() {
const { connector, request } = this.props;
if (request?.requestPostDataAvailable && !this.state.postBody) {
const requestData = await connector.requestData(
request.id,
"requestPostData"
);
this.setState({
postBody: requestData.postData.text,
});
}
}
componentDidUpdate(prevProps, prevState) {
// This is when the query params change in the url params input map
if (
@ -273,35 +299,18 @@ class HTTPCustomRequestPanel extends Component {
handleClear() {
this.updateStateAndPref({
method: "",
method: HTTP_METHODS[0],
url: "",
urlQueryParams: [],
headers: [],
requestPostData: "",
postBody: "",
});
}
render() {
const { sendCustomRequest } = this.props;
const {
method,
urlQueryParams,
requestPostData,
url,
headers,
} = this.state;
const { method, urlQueryParams, postBody, url, headers } = this.state;
const methods = [
"GET",
"HEAD",
"POST",
"DELETE",
"PUT",
"CONNECT",
"OPTIONS",
"TRACE",
"PATH",
];
return div(
{ className: "http-custom-request-panel" },
div(
@ -321,7 +330,7 @@ class HTTPCustomRequestPanel extends Component {
value: method,
},
methods.map(item =>
HTTP_METHODS.map(item =>
option(
{
value: item,
@ -438,11 +447,11 @@ class HTTPCustomRequestPanel extends Component {
textarea({
className: "tabpanel-summary-input",
id: "http-custom-postdata-value",
name: "requestPostData",
name: "postBody",
placeholder: CUSTOM_POSTDATA_PLACEHOLDER,
onChange: this.handleInputChange,
rows: 6,
value: requestPostData,
value: postBody,
wrap: "off",
})
),
@ -462,14 +471,27 @@ class HTTPCustomRequestPanel extends Component {
{
className: "devtools-button",
id: "http-custom-request-send-button",
disabled: !this.state.url,
onClick: () =>
sendCustomRequest({
disabled: !this.state.url || !this.state.method,
onClick: () => {
const customRequestDetails = {
...this.state,
headers: this.state.headers.filter(
({ checked }) => checked
urlQueryParams: urlQueryParams.map(
({ checked, ...params }) => params
),
}),
headers: headers
.filter(({ checked }) => checked)
.map(({ checked, ...headersValues }) => headersValues),
};
if (postBody) {
customRequestDetails.requestPostData = {
postData: {
text: postBody,
},
};
}
delete customRequestDetails.postBody;
sendCustomRequest(customRequestDetails);
},
},
CUSTOM_SEND
)

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

@ -190,7 +190,7 @@ class RequestPanel extends Component {
const { request, targetSearchResult } = this.props;
const { filterText, rawRequestPayloadDisplayed } = this.state;
const { formDataSections, mimeType, requestPostData } = request;
const postData = requestPostData ? requestPostData.postData.text : null;
const postData = requestPostData ? requestPostData.postData?.text : null;
if ((!formDataSections || formDataSections.length === 0) && !postData) {
return div({ className: "empty-notice" }, REQUEST_EMPTY_TEXT);

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

@ -201,6 +201,9 @@ skip-if = verify # Bug 1607678
[browser_net_large-response.js]
[browser_net_leak_on_tab_close.js]
[browser_net_new_request_panel.js]
[browser_net_new_request_panel_clear_button.js]
[browser_net_new_request_panel_context_menu.js]
[browser_net_new_request_panel_send_request.js]
[browser_net_new_request_panel_persisted_content.js]
[browser_net_new_request_panel_sync_url_params.js]
[browser_net_open_in_debugger.js]

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

@ -4,11 +4,11 @@
"use strict";
/**
* Test if the New Request panel shows in the left when the pref is true
* Test if the New Request panel shows up as a expected when opened from the toolbar
*/
add_task(async function() {
// Turn true the pref
// Turn on the pref
await pushPref("devtools.netmonitor.features.newEditAndResend", true);
// Resetting the pref
await pushPref("devtools.netmonitor.customRequest", "");
@ -24,18 +24,15 @@ add_task(async function() {
const Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
store.dispatch(Actions.batchEnable(false));
info("open the left panel");
const waitForPanels = waitForDOM(
document,
".monitor-panel .network-action-bar"
);
info("switching to new HTTP Custom Request panel");
info("Open the HTTP Custom Panel through the toolbar button");
let HTTPCustomRequestButton = document.querySelector(
"#netmonitor-toolbar-container .devtools-http-custom-request-icon"
);
ok(HTTPCustomRequestButton, "The Toolbar button should be visible.");
const waitForPanels = waitForDOM(
document,
".monitor-panel .network-action-bar"
);
HTTPCustomRequestButton.click();
await waitForPanels;
@ -44,184 +41,15 @@ add_task(async function() {
true,
"The 'New Request' header should be visible when the pref is true."
);
// Turn false the pref
await pushPref("devtools.netmonitor.features.newEditAndResend", false);
// Close the panel to updated after changing the pref
const closePanel = document.querySelector(
".network-action-bar .tabs-navigation .sidebar-toggle"
);
closePanel.click();
// Check if the toolbar is hidden when tre pref is false
HTTPCustomRequestButton = document.querySelector(
"#netmonitor-toolbar-container .devtools-http-custom-request-icon"
);
is(
!!HTTPCustomRequestButton,
false,
"The toolbar button should be hidden when the pref is false."
);
await teardown(monitor);
});
/**
* Test if the context menu open the new HTTP Custom Request Panel
* when the pref is true
*/
add_task(async function() {
// Turn true the pref
await pushPref("devtools.netmonitor.features.newEditAndResend", true);
// Resetting the pref
await pushPref("devtools.netmonitor.customRequest", "");
const { tab, monitor } = await initNetMonitor(HTTPS_CUSTOM_GET_URL, {
requestCount: 1,
});
info("Starting test... ");
const { document, store, windowRequire } = monitor.panelWin;
// Action should be processed synchronously in tests.
const Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
store.dispatch(Actions.batchEnable(false));
await performRequests(monitor, tab, 1);
info("selecting first request");
const firstRequestItem = document.querySelectorAll(".request-list-item")[0];
EventUtils.sendMouseEvent({ type: "mousedown" }, firstRequestItem);
EventUtils.sendMouseEvent({ type: "contextmenu" }, firstRequestItem);
// Cheking if the item "Resend" is hidden
is(
!!getContextMenuItem(monitor, "request-list-context-resend-only"),
false,
"The'Resend' item should be hidden when the pref is true."
);
info("opening the new request panel");
const waitForPanels = waitForDOM(
document,
".monitor-panel .network-action-bar"
);
getContextMenuItem(monitor, "request-list-context-resend").click();
await waitForPanels;
is(
!!document.querySelector("#network-action-bar-HTTP-custom-request-panel"),
!!document.querySelector(
".devtools-button.devtools-http-custom-request-icon.checked"
),
true,
"The 'New Request' header should be visible when the pref is true."
"The toolbar button should be highlighted"
);
await teardown(monitor);
});
/**
* Test if the content it is not connected to the current selection.
*/
add_task(async function() {
// Turn true the pref
await pushPref("devtools.netmonitor.features.newEditAndResend", true);
// Resetting the pref
await pushPref("devtools.netmonitor.customRequest", "");
const { tab, monitor } = await initNetMonitor(HTTPS_CUSTOM_GET_URL, {
requestCount: 1,
});
info("Starting test... ");
const { document, store, windowRequire } = monitor.panelWin;
// Action should be processed synchronously in tests.
const Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
store.dispatch(Actions.batchEnable(false));
await performRequests(monitor, tab, 2);
info("selecting first request");
const firstRequestItem = document.querySelectorAll(".request-list-item")[0];
EventUtils.sendMouseEvent({ type: "mousedown" }, firstRequestItem);
EventUtils.sendMouseEvent({ type: "contextmenu" }, firstRequestItem);
info("opening the new request panel");
const waitForPanels = waitForDOM(
document,
".monitor-panel .network-action-bar"
);
getContextMenuItem(monitor, "request-list-context-resend").click();
await waitForPanels;
const urlValue = document.querySelector("http-custom-url-value");
const request = document.querySelectorAll(".request-list-item")[1];
EventUtils.sendMouseEvent({ type: "mousedown" }, request);
const urlValueChanged = document.querySelector("http-custom-url-value");
is(
urlValue,
urlValueChanged,
"The url should not change when click on a new request"
);
await teardown(monitor);
});
/**
* Test cleaning a custom request.
*/
add_task(async function() {
// Turn on the pref
await pushPref("devtools.netmonitor.features.newEditAndResend", true);
// Resetting the pref
await pushPref("devtools.netmonitor.customRequest", "");
const { monitor, tab } = await initNetMonitor(HTTPS_CUSTOM_GET_URL, {
requestCount: 1,
});
info("Starting test... ");
const { document, store, windowRequire } = monitor.panelWin;
// Action should be processed synchronously in tests.
const Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
store.dispatch(Actions.batchEnable(false));
const { getSelectedRequest } = windowRequire(
"devtools/client/netmonitor/src/selectors/index"
);
await performRequests(monitor, tab, 1);
info("selecting first request");
const firstRequestItem = document.querySelectorAll(".request-list-item")[0];
EventUtils.sendMouseEvent({ type: "mousedown" }, firstRequestItem);
EventUtils.sendMouseEvent({ type: "contextmenu" }, firstRequestItem);
info("Opening the new request panel");
const waitForPanels = waitForDOM(
document,
".monitor-panel .network-action-bar"
);
getContextMenuItem(monitor, "request-list-context-resend").click();
await waitForPanels;
const request = getSelectedRequest(store.getState());
// Check if the panel is updated with the content by the request clicked
const urlValue = document.querySelector(".http-custom-url-value");
is(
urlValue.textContent,
request.url,
"The URL in the form should match the request we clicked"
);
info("Clicking on the clear button");
document.querySelector("#http-custom-request-clear-button").click();
info("if the default state is empty");
is(
document.querySelector(".http-custom-method-value").value,
"GET",
@ -246,5 +74,23 @@ add_task(async function() {
"The Post body input should be empty"
);
// Turn off the pref
await pushPref("devtools.netmonitor.features.newEditAndResend", false);
info("Close the panel to update the interface after changing the pref");
const closePanel = document.querySelector(
".network-action-bar .tabs-navigation .sidebar-toggle"
);
closePanel.click();
info("Check if the toolbar button is hidden when the pref is false");
HTTPCustomRequestButton = document.querySelector(
"#netmonitor-toolbar-container .devtools-http-custom-request-icon"
);
is(
!!HTTPCustomRequestButton,
false,
"The toolbar button should be hidden when the pref is false."
);
await teardown(monitor);
});

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

@ -0,0 +1,82 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
/**
* Test cleaning a custom request.
*/
add_task(async function() {
// Turn on the pref
await pushPref("devtools.netmonitor.features.newEditAndResend", true);
// Resetting the pref
await pushPref("devtools.netmonitor.customRequest", "");
const { monitor, tab } = await initNetMonitor(HTTPS_CUSTOM_GET_URL, {
requestCount: 1,
});
info("Starting test... ");
const { document, store, windowRequire } = monitor.panelWin;
// Action should be processed synchronously in tests.
const Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
store.dispatch(Actions.batchEnable(false));
const { getSelectedRequest } = windowRequire(
"devtools/client/netmonitor/src/selectors/index"
);
await performRequests(monitor, tab, 1);
info("selecting first request");
const firstRequestItem = document.querySelectorAll(".request-list-item")[0];
EventUtils.sendMouseEvent({ type: "mousedown" }, firstRequestItem);
EventUtils.sendMouseEvent({ type: "contextmenu" }, firstRequestItem);
info("Opening the new request panel");
const waitForPanels = waitForDOM(
document,
".monitor-panel .network-action-bar"
);
getContextMenuItem(monitor, "request-list-context-resend").click();
await waitForPanels;
const request = getSelectedRequest(store.getState());
// Check if the panel is updated with the content by the request clicked
const urlValue = document.querySelector(".http-custom-url-value");
is(
urlValue.textContent,
request.url,
"The URL in the form should match the request we clicked"
);
info("Clicking on the clear button");
document.querySelector("#http-custom-request-clear-button").click();
is(
document.querySelector(".http-custom-method-value").value,
"GET",
"The method input should be 'GET' by default"
);
is(
document.querySelector(".http-custom-url-value").textContent,
"",
"The URL input should be empty"
);
const urlParametersValue = document.querySelectorAll(
"#http-custom-query .tabpanel-summary-container.http-custom-input"
);
is(urlParametersValue.length, 0, "The URL Parameters input should be empty");
const headersValue = document.querySelectorAll(
"#http-custom-headers .tabpanel-summary-container.http-custom-input"
);
is(headersValue.length, 0, "The Headers input should be empty");
is(
document.querySelector("#http-custom-postdata-value").textContent,
"",
"The Post body input should be empty"
);
await teardown(monitor);
});

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

@ -0,0 +1,213 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
/**
* Test if the New Request Panel shows up as a expected
* when opened from an existing request
*/
add_task(async function() {
// Turn true the pref
await pushPref("devtools.netmonitor.features.newEditAndResend", true);
// Resetting the pref
await pushPref("devtools.netmonitor.customRequest", "");
const { tab, monitor } = await initNetMonitor(POST_DATA_URL, {
requestCount: 1,
});
info("Starting test... ");
const { document, store, windowRequire } = monitor.panelWin;
// Action should be processed synchronously in tests.
const Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
store.dispatch(Actions.batchEnable(false));
await performRequests(monitor, tab, 1);
const { getSelectedRequest } = windowRequire(
"devtools/client/netmonitor/src/selectors/index"
);
const expectedURLQueryParams = [
{
name: "foo",
value: "bar",
},
{ name: "baz", value: "42" },
{ name: "type", value: "urlencoded" },
];
info("selecting first request");
const firstRequestItem = document.querySelectorAll(".request-list-item")[0];
const waitForHeaders = waitUntil(() =>
document.querySelector(".headers-overview")
);
EventUtils.sendMouseEvent({ type: "mousedown" }, firstRequestItem);
await waitForHeaders;
EventUtils.sendMouseEvent({ type: "contextmenu" }, firstRequestItem);
info("if the item 'Resend' is hidden");
is(
!!getContextMenuItem(monitor, "request-list-context-resend-only"),
false,
"The 'Resend' item should be hidden when the pref is true."
);
info("Opening the new request panel");
const waitForPanels = waitForDOM(
document,
".monitor-panel .network-action-bar"
);
const menuItem = getContextMenuItem(monitor, "request-list-context-resend");
const menuPopup = menuItem.parentNode;
const onHidden = new Promise(resolve => {
menuPopup.addEventListener("popuphidden", resolve, { once: true });
});
menuItem.click();
menuPopup.hidePopup();
await onHidden;
await waitForPanels;
is(
!!document.querySelector(
".devtools-button.devtools-http-custom-request-icon.checked"
),
true,
"The toolbar button should be highlighted"
);
const request = getSelectedRequest(store.getState());
// Verify if the default state contains the data from the request
const methodValue = document.querySelector(".http-custom-method-value");
is(
methodValue.value,
request.method,
"The method in the form should match the request we clicked"
);
const urlValue = document.querySelector(".http-custom-url-value");
is(
urlValue.textContent,
request.url,
"The URL in the form should match the request we clicked"
);
const urlParametersValues = document.querySelectorAll(
"#http-custom-query .tabpanel-summary-container.http-custom-input"
);
is(
urlParametersValues.length,
3,
"The URL Parameters length in the form should match the request we clicked"
);
for (let i = 0; i < urlParametersValues.length; i++) {
const { name, value } = expectedURLQueryParams[i];
const [formName, formValue] = urlParametersValues[i].querySelectorAll(
"textarea"
);
is(
name,
formName.value,
"The query param name in the form should match the request we clicked"
);
is(
value,
formValue.value,
"The query param value in the form should match the request we clicked"
);
}
const headersValues = document.querySelectorAll(
"#http-custom-headers .tabpanel-summary-container.http-custom-input"
);
ok(
headersValues.length >= 6,
"The headers length in the form should match the request we clicked"
);
for (const { name, value } of request.requestHeaders.headers) {
const found = Array.from(headersValues).find(item => {
const [formName, formValue] = item.querySelectorAll("textarea");
if (formName.value === name && formValue.value === value) {
return true;
}
return false;
});
ok(found, "The header was found in the form");
}
// Wait to the post body because it is only updated in the componentWillMount
const postValue = document.querySelector("#http-custom-postdata-value");
await waitUntil(() => postValue.textContent !== "");
is(
postValue.value,
request.requestPostData.postData.text,
"The Post body input value in the form should match the request we clicked"
);
info(
"Uncheck the header an make sure the header is removed from the new request"
);
const headers = document.querySelectorAll(
"#http-custom-headers .tabpanel-summary-container.http-custom-input"
);
const lastHeader = Array.from(headers).pop();
const checkbox = lastHeader.querySelector("input");
checkbox.click();
info("Click on the button to send a new request");
const waitUntilEventsDisplayed = waitForNetworkEvents(monitor, 1);
const buttonSend = document.querySelector("#http-custom-request-send-button");
buttonSend.click();
await waitUntilEventsDisplayed;
const newRequestSelected = getSelectedRequest(store.getState());
let found = newRequestSelected.requestHeaders.headers.some(
item => item.name == "My-header-2" && item.value == "my-value-2"
);
is(
found,
false,
"The header unchecked should not be found on the headers list"
);
info(
"Delete the header and make sure the header is removed in the custom request panel"
);
const buttonDelete = lastHeader.querySelector("button");
buttonDelete.click();
const headersValue = document.querySelectorAll(
"#http-custom-headers .tabpanel-summary-container.http-custom-input textarea"
);
found = Array.from(headersValue).some(
item => item.name == "My-header-2" && item.value == "my-value-2"
);
is(found, false, "The header delete should not be found on the headers form");
info(
"Change the request selected to make sure the request in the custom request panel does not change"
);
const previousRequest = document.querySelectorAll(".request-list-item")[0];
EventUtils.sendMouseEvent({ type: "mousedown" }, previousRequest);
const urlValueChanged = document.querySelector(".http-custom-url-value");
is(
urlValue.textContent,
urlValueChanged.textContent,
"The url should not change when click on a new request"
);
await teardown(monitor);
});

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

@ -0,0 +1,159 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
/**
* Test sending a custom request.
*/
add_task(async function() {
// Turn on the pref
await pushPref("devtools.netmonitor.features.newEditAndResend", true);
await pushPref("devtools.netmonitor.customRequest", "");
const { monitor } = await initNetMonitor(CORS_URL, {
requestCount: 1,
});
info("Starting test... ");
const { document, store, windowRequire, connector } = monitor.panelWin;
const { sendHTTPRequest } = connector;
// Action should be processed synchronously in tests.
const Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
store.dispatch(Actions.batchEnable(false));
const { getSelectedRequest } = windowRequire(
"devtools/client/netmonitor/src/selectors/index"
);
// Build request with known information so that we can check later
const request = {
url: "https://test1.example.com" + CORS_SJS_PATH,
method: "POST",
headers: [
{ name: "Host", value: "fakehost.example.com" },
{ name: "User-Agent", value: "Testzilla" },
{ name: "Referer", value: "http://example.com/referrer" },
{ name: "Accept", value: "application/jarda" },
{ name: "Accept-Encoding", value: "compress, identity, funcoding" },
{ name: "Accept-Language", value: "cs-CZ" },
],
body: "Hello",
cause: {
loadingDocumentUri: "http://example.com",
stacktraceAvailable: true,
type: "xhr",
},
};
const waitUntilRequestDisplayed = waitForNetworkEvents(monitor, 1);
sendHTTPRequest(request);
await waitUntilRequestDisplayed;
info("selecting first request");
const firstRequestItem = document.querySelectorAll(".request-list-item")[0];
const waitForHeaders = waitUntil(() =>
document.querySelector(".headers-overview")
);
EventUtils.sendMouseEvent({ type: "mousedown" }, firstRequestItem);
await waitForHeaders;
EventUtils.sendMouseEvent({ type: "contextmenu" }, firstRequestItem);
info("Opening the new request panel");
const waitForPanels = waitForDOM(
document,
".monitor-panel .network-action-bar"
);
const menuItem = getContextMenuItem(monitor, "request-list-context-resend");
const menuPopup = menuItem.parentNode;
const onHidden = new Promise(resolve => {
menuPopup.addEventListener("popuphidden", resolve, { once: true });
});
menuItem.click();
menuPopup.hidePopup();
await onHidden;
await waitForPanels;
info(
"Change the request method to send a new custom request with a different method"
);
const methodValue = document.querySelector("#http-custom-method-value");
methodValue.value = "PUT";
methodValue.dispatchEvent(new Event("change", { bubbles: true }));
info("Change the URL to send a custom request with a different URL");
const urlValue = document.querySelector(".http-custom-url-value");
urlValue.focus();
urlValue.value = "";
EventUtils.sendString(`${request.url}?hello=world`);
info("Check if the parameter section was updated");
is(
document.querySelectorAll(
"#http-custom-query .tabpanel-summary-container.http-custom-input"
).length,
1,
"The parameter section should be updated"
);
info("Adding new headers");
const newHeaderName = document.querySelector(
"#http-custom-headers .map-add-new-inputs .http-custom-input-name"
);
newHeaderName.focus();
EventUtils.sendString("My-header");
const newHeaderValue = Array.from(
document.querySelectorAll(
"#http-custom-headers #http-custom-name-and-value .http-custom-input-value"
)
).pop();
newHeaderValue.focus();
EventUtils.sendString("my-value");
const postValue = document.querySelector("#http-custom-postdata-value");
postValue.focus();
postValue.value = "";
EventUtils.sendString("{'name': 'value'}");
// Close the details panel to see if after sending a new request
// this request will be selected by default and
// if the deitails panel will be open automatically.
const waitForDetailsPanelToClose = waitUntil(
() => !document.querySelector(".monitor-panel .network-details-bar")
);
store.dispatch(Actions.toggleNetworkDetails());
await waitForDetailsPanelToClose;
info("Click on the button to send a new request");
const waitUntilEventsDisplayed = waitForNetworkEvents(monitor, 1);
const buttonSend = document.querySelector("#http-custom-request-send-button");
buttonSend.click();
await waitUntilEventsDisplayed;
const newRequestSelectedId = getSelectedRequest(store.getState()).id;
await connector.requestData(newRequestSelectedId, "requestPostData");
const updatedSelectedRequest = getSelectedRequest(store.getState());
is(updatedSelectedRequest.method, "PUT", "The request has the right method");
is(
updatedSelectedRequest.url,
urlValue.value,
"The request has the right URL"
);
const found = updatedSelectedRequest.requestHeaders.headers.some(
item => item.name === "My-header" && item.value === "my-value"
);
is(found, true, "The header was found in the form");
is(
updatedSelectedRequest.requestPostData.postData.text,
"{'name': 'value'}",
"The request has the right post body"
);
await teardown(monitor);
});

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

@ -63,9 +63,7 @@ int32_t nsScreen::GetPixelDepth(ErrorResult& aRv) {
return -1;
}
uint32_t depth;
context->GetDepth(depth);
return depth;
return context->GetDepth();
}
nsPIDOMWindowOuter* nsScreen::GetOuter() const {

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

@ -9,6 +9,8 @@
#include "nsCycleCollectionParticipant.h"
#include "mozilla/Assertions.h"
#include "mozilla/ServoUtils.h"
#include "mozilla/RustCell.h"
#include "js/HeapAPI.h"
#include "js/TracingAPI.h"
#include "js/TypeDecls.h"
@ -89,15 +91,7 @@ class JS_HAZ_ROOTED nsWrapperCache {
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_WRAPPERCACHE_IID)
nsWrapperCache()
: mWrapper(nullptr),
mFlags(0)
#ifdef BOOL_FLAGS_ON_WRAPPER_CACHE
,
mBoolFlags(0)
#endif
{
}
nsWrapperCache() = default;
~nsWrapperCache() {
// Preserved wrappers should never end up getting cleared, but this can
// happen during shutdown when a leaked wrapper object is finalized, causing
@ -256,33 +250,43 @@ class JS_HAZ_ROOTED nsWrapperCache {
using FlagsType = uint32_t;
FlagsType GetFlags() const { return mFlags & ~kWrapperFlagsMask; }
FlagsType GetFlags() const {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!mozilla::IsInServoTraversal());
return mFlags.Get() & ~kWrapperFlagsMask;
}
// This can be called from stylo threads too, so it needs to be atomic, as
// this value may be mutated from multiple threads during servo traversal from
// rust.
bool HasFlag(FlagsType aFlag) const {
MOZ_ASSERT((aFlag & kWrapperFlagsMask) == 0, "Bad flag mask");
return !!(mFlags & aFlag);
return __atomic_load_n(mFlags.AsPtr(), __ATOMIC_RELAXED) & aFlag;
}
// Identical to HasFlag, but more explicit about its handling of multiple
// flags.
bool HasAnyOfFlags(FlagsType aFlags) const {
MOZ_ASSERT((aFlags & kWrapperFlagsMask) == 0, "Bad flag mask");
return !!(mFlags & aFlags);
}
// flags. This can be called from stylo threads too.
bool HasAnyOfFlags(FlagsType aFlags) const { return HasFlag(aFlags); }
// This can also be called from stylo, in the sequential part of the
// traversal, though it's probably not worth differentiating them for the
// purposes of assertions.
bool HasAllFlags(FlagsType aFlags) const {
MOZ_ASSERT((aFlags & kWrapperFlagsMask) == 0, "Bad flag mask");
return (mFlags & aFlags) == aFlags;
return (__atomic_load_n(mFlags.AsPtr(), __ATOMIC_RELAXED) & aFlags) ==
aFlags;
}
void SetFlags(FlagsType aFlagsToSet) {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT((aFlagsToSet & kWrapperFlagsMask) == 0, "Bad flag mask");
mFlags |= aFlagsToSet;
mFlags.Set(mFlags.Get() | aFlagsToSet);
}
void UnsetFlags(FlagsType aFlagsToUnset) {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT((aFlagsToUnset & kWrapperFlagsMask) == 0, "Bad flag mask");
mFlags &= ~aFlagsToUnset;
mFlags.Set(mFlags.Get() & ~aFlagsToUnset);
}
void PreserveWrapper(nsISupports* aScriptObjectHolder) {
@ -335,23 +339,30 @@ class JS_HAZ_ROOTED nsWrapperCache {
private:
void SetWrapperJSObject(JSObject* aWrapper);
FlagsType GetWrapperFlags() const { return mFlags & kWrapperFlagsMask; }
// We'd like to assert that these aren't used from servo threads, but we don't
// have a great way to do that because:
// * We can't just assert that they get used on the main thread, because
// these are used from workers.
// * We can't just assert that they aren't used when IsInServoTraversal(),
// because the traversal has a sequential, main-thread-only phase, where we
// run animations that can fiddle with JS promises.
FlagsType GetWrapperFlags() const { return mFlags.Get() & kWrapperFlagsMask; }
bool HasWrapperFlag(FlagsType aFlag) const {
MOZ_ASSERT((aFlag & ~kWrapperFlagsMask) == 0, "Bad wrapper flag bits");
return !!(mFlags & aFlag);
return !!(mFlags.Get() & aFlag);
}
void SetWrapperFlags(FlagsType aFlagsToSet) {
MOZ_ASSERT((aFlagsToSet & ~kWrapperFlagsMask) == 0,
"Bad wrapper flag bits");
mFlags |= aFlagsToSet;
mFlags.Set(mFlags.Get() | aFlagsToSet);
}
void UnsetWrapperFlags(FlagsType aFlagsToUnset) {
MOZ_ASSERT((aFlagsToUnset & ~kWrapperFlagsMask) == 0,
"Bad wrapper flag bits");
mFlags &= ~aFlagsToUnset;
mFlags.Set(mFlags.Get() & ~aFlagsToUnset);
}
void HoldJSObjects(void* aScriptObjectHolder, nsScriptObjectTracer* aTracer,
@ -379,12 +390,22 @@ class JS_HAZ_ROOTED nsWrapperCache {
enum { kWrapperFlagsMask = WRAPPER_BIT_PRESERVED };
JSObject* mWrapper;
FlagsType mFlags;
JSObject* mWrapper = nullptr;
// Rust code needs to read and write some flags atomically, but we don't want
// to make the wrapper flags atomic whole-sale because main-thread code would
// become more expensive (loads wouldn't change, but flag setting /
// unsetting could become slower enough to be noticeable). Making this an
// Atomic whole-sale needs more measuring.
//
// In order to not mess with aliasing rules the type should not be frozen, so
// we use a RustCell, which contains an UnsafeCell internally. See also the
// handling of ServoData (though that's a bit different).
mozilla::RustCell<FlagsType> mFlags{0};
protected:
#ifdef BOOL_FLAGS_ON_WRAPPER_CACHE
uint32_t mBoolFlags;
uint32_t mBoolFlags = 0;
#endif
};

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

@ -3962,10 +3962,9 @@ nsresult ArrayBufferBuilder::MapToFileInPackage(const nsCString& aFile,
nsresult rv;
// Open Jar file to get related attributes of target file.
RefPtr<nsZipArchive> zip = new nsZipArchive();
rv = zip->OpenArchive(aJarFile);
if (NS_FAILED(rv)) {
return rv;
RefPtr<nsZipArchive> zip = nsZipArchive::OpenArchive(aJarFile);
if (!zip) {
return NS_ERROR_FAILURE;
}
nsZipItem* zipItem = zip->GetItem(aFile.get());
if (!zipItem) {

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

@ -211,7 +211,7 @@ already_AddRefed<gfxContext> nsDeviceContext::CreateRenderingContextCommon(
return pContext.forget();
}
nsresult nsDeviceContext::GetDepth(uint32_t& aDepth) {
uint32_t nsDeviceContext::GetDepth() {
nsCOMPtr<nsIScreen> screen;
FindScreen(getter_AddRefs(screen));
if (!screen) {
@ -219,9 +219,9 @@ nsresult nsDeviceContext::GetDepth(uint32_t& aDepth) {
screenManager.GetPrimaryScreen(getter_AddRefs(screen));
MOZ_ASSERT(screen);
}
screen->GetColorDepth(reinterpret_cast<int32_t*>(&aDepth));
return NS_OK;
int32_t depth = 0;
screen->GetColorDepth(&depth);
return uint32_t(depth);
}
nsresult nsDeviceContext::GetDeviceSurfaceDimensions(nscoord& aWidth,

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

@ -110,7 +110,7 @@ class nsDeviceContext final {
/**
* Return the bit depth of the device.
*/
nsresult GetDepth(uint32_t& aDepth);
uint32_t GetDepth();
/**
* Get the size of the displayable area of the output device

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

@ -522,6 +522,8 @@ bool gfxPlatformFontList::InitFontList() {
// unless InitFontListForPlatform() fails and we reset it below.
mFontlistInitCount++;
InitializeCodepointsWithNoFonts();
// Try to initialize the cross-process shared font list if enabled by prefs,
// but not if we're running in Safe Mode.
if (StaticPrefs::gfx_e10s_font_list_shared_AtStartup() &&

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

@ -1484,7 +1484,6 @@ static bool BytecodeIsEffectful(JSOp op) {
case JSOp::InitHiddenElemGetter:
case JSOp::InitElemSetter:
case JSOp::InitHiddenElemSetter:
case JSOp::FunCall:
case JSOp::SpreadCall:
case JSOp::Call:
case JSOp::CallIgnoresRv:

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

@ -146,10 +146,6 @@ function treatAsSafeArgument(entry, varName, csuName)
[/^Gecko_/, null, "nsStyleImageLayers"],
[/^Gecko_/, null, /FontFamilyList/],
// RawGeckoBorrowedNode thread-mutable parameters.
["Gecko_SetNodeFlags", "aNode", null],
["Gecko_UnsetNodeFlags", "aNode", null],
// Various Servo binding out parameters. This is a mess and there needs
// to be a way to indicate which params are out parameters, either using
// an attribute or a naming convention.

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

@ -8070,7 +8070,7 @@ ParseNode* BytecodeEmitter::getCoordNode(ParseNode* callNode,
ParseNode* calleeNode, JSOp op,
ListNode* argsList) {
ParseNode* coordNode = callNode;
if (op == JSOp::Call || op == JSOp::SpreadCall || op == JSOp::FunCall) {
if (op == JSOp::Call || op == JSOp::SpreadCall) {
// Default to using the location of the `(` itself.
// obj[expr]() // expression
// ^ // column coord

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

@ -280,7 +280,7 @@ class MOZ_STACK_CLASS CallOrNewEmitter {
private:
[[nodiscard]] bool isCall() const {
return op_ == JSOp::Call || op_ == JSOp::CallIgnoresRv ||
op_ == JSOp::SpreadCall || isEval() || isFunCall();
op_ == JSOp::SpreadCall || isEval();
}
[[nodiscard]] bool isNew() const {
@ -296,8 +296,6 @@ class MOZ_STACK_CLASS CallOrNewEmitter {
op_ == JSOp::SpreadEval || op_ == JSOp::StrictSpreadEval;
}
[[nodiscard]] bool isFunCall() const { return op_ == JSOp::FunCall; }
[[nodiscard]] bool isSpread() const { return IsSpreadOp(op_); }
[[nodiscard]] bool isSingleSpread() const {

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

@ -10730,13 +10730,7 @@ typename ParseHandler::Node GeneralParser<ParseHandler, Unit>::memberCall(
JSOp op = JSOp::Call;
bool maybeAsyncArrow = false;
if (auto prop = handler_.maybeDottedProperty(lhs)) {
// Use the JSOp::FunCall optimizations given the right syntax.
if (prop == TaggedParserAtomIndex::WellKnown::call()) {
op = JSOp::FunCall;
}
} else if (tt == TokenKind::LeftParen &&
optionalKind == OptionalKind::NonOptional) {
if (tt == TokenKind::LeftParen && optionalKind == OptionalKind::NonOptional) {
if (handler_.isAsyncKeyword(lhs)) {
// |async (| can be the start of an async arrow
// function, so we need to defer reporting possible

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

@ -34,11 +34,7 @@ gczeal(0);
assertEqPreciseStacks(
endProfiling(),
[
// Expected output for (simulator+via-Ion).
['', '!>', '0,!>', '<,0,!>', 'filtering GC postbarrier,0,!>',
'<,0,!>', '0,!>', '!>', ''],
// Expected output for (simulator+baseline).
// Expected output for (simulator+via-Ion/baseline).
['', '!>', '0,!>', '<,0,!>', 'GC postbarrier,0,!>',
'<,0,!>', '0,!>', '!>', ''],
@ -55,8 +51,8 @@ gczeal(0);
assertEqPreciseStacks(
endProfiling(),
[
// Expected output for (simulator+via-Ion).
['', '!>', '0,!>', '', '0,!>', '<,0,!>', 'filtering GC postbarrier,0,!>',
// Expected output for (simulator+via-Ion/baseline).
['', '!>', '0,!>', '', '0,!>', '<,0,!>', 'GC postbarrier,0,!>',
'<,0,!>', '0,!>', '!>', ''],
// Expected output for other configurations.

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

@ -0,0 +1,21 @@
// Add test for issue with a post-write barrier that doesn't remove
// store buffer entries when used on a table that may grow.
let {set, table} = wasmEvalText(`(module
(table (export "table") 1 externref)
(func (export "set") (param externref)
i32.const 0
local.get 0
table.set
)
)`).exports;
let tenured = {};
gc(tenured);
assertEq(isNurseryAllocated(tenured), false);
let nursery = {};
assertEq(isNurseryAllocated(nursery), true);
set(nursery);
set(null);
assertEq(table.grow(1000), 1, 'table grows');
gc();

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

@ -225,6 +225,12 @@ class ExceptionBailoutInfo {
[[nodiscard]] bool FinishBailoutToBaseline(BaselineBailoutInfo* bailoutInfoArg);
#ifdef DEBUG
[[nodiscard]] bool AssertBailoutStackDepth(JSContext* cx, JSScript* script,
jsbytecode* pc, ResumeMode mode,
uint32_t exprStackSlots);
#endif
} // namespace jit
} // namespace js

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

@ -10,6 +10,7 @@
#include "builtin/ModuleObject.h"
#include "debugger/DebugAPI.h"
#include "jit/arm/Simulator-arm.h"
#include "jit/Bailouts.h"
#include "jit/BaselineFrame.h"
#include "jit/BaselineIC.h"
#include "jit/BaselineJIT.h"
@ -114,6 +115,7 @@ class MOZ_STACK_CLASS BaselineStackBuilder {
jsbytecode* pc_ = nullptr;
JSOp op_ = JSOp::Nop;
mozilla::Maybe<ResumeMode> resumeMode_;
uint32_t exprStackSlots_ = 0;
void* prevFramePtr_ = nullptr;
Maybe<BufferPointer<BaselineFrame>> blFrame_;
@ -224,8 +226,10 @@ class MOZ_STACK_CLASS BaselineStackBuilder {
return !catchingException() && iter_.resumeAfter();
}
ResumeMode resumeMode() const { return *resumeMode_; }
bool needToSaveCallerArgs() const {
return IsIonInlinableGetterOrSetterOp(op_);
return resumeMode() == ResumeMode::InlinedAccessor;
}
[[nodiscard]] bool enlarge() {
@ -546,6 +550,7 @@ bool BaselineStackBuilder::initFrame() {
pc_ = catchingException() ? excInfo_->resumePC()
: script_->offsetToPC(iter_.pcOffset());
op_ = JSOp(*pc_);
resumeMode_ = mozilla::Some(iter_.resumeMode());
return true;
}
@ -744,7 +749,7 @@ bool BaselineStackBuilder::buildFixedSlots() {
return true;
}
// The caller side of inlined JSOp::FunCall and accessors must look
// The caller side of inlined js::fun_call and accessors must look
// like the function wasn't inlined.
bool BaselineStackBuilder::fixUpCallerArgs(
MutableHandleValueVector savedCallerArgs, bool* fixedUp) {
@ -753,18 +758,20 @@ bool BaselineStackBuilder::fixUpCallerArgs(
// Inlining of SpreadCall-like frames not currently supported.
MOZ_ASSERT(!IsSpreadOp(op_));
if (op_ != JSOp::FunCall && !needToSaveCallerArgs()) {
if (resumeMode() != ResumeMode::InlinedFunCall && !needToSaveCallerArgs()) {
return true;
}
// Calculate how many arguments are consumed by the inlined call.
// All calls pass |callee| and |this|.
uint32_t inlinedArgs = 2;
if (op_ == JSOp::FunCall) {
if (resumeMode() == ResumeMode::InlinedFunCall) {
// The first argument to an inlined FunCall becomes |this|,
// if it exists. The rest are passed normally.
MOZ_ASSERT(IsInvokeOp(op_));
inlinedArgs += GET_ARGC(pc_) > 0 ? GET_ARGC(pc_) - 1 : 0;
} else {
MOZ_ASSERT(resumeMode() == ResumeMode::InlinedAccessor);
MOZ_ASSERT(IsIonInlinableGetterOrSetterOp(op_));
// Setters are passed one argument. Getters are passed none.
if (IsSetPropOp(op_)) {
@ -787,11 +794,11 @@ bool BaselineStackBuilder::fixUpCallerArgs(
}
}
// When we inline JSOp::FunCall, we bypass the native and inline the
// When we inline js::fun_call, we bypass the native and inline the
// target directly. When rebuilding the stack, we need to fill in
// the right number of slots to make it look like the js_native was
// actually called.
if (op_ == JSOp::FunCall) {
if (resumeMode() == ResumeMode::InlinedFunCall) {
// We must transform the stack from |target, this, args| to
// |js_fun_call, target, this, args|. The value of |js_fun_call|
// will never be observed, so we push |undefined| for it, followed
@ -994,7 +1001,7 @@ bool BaselineStackBuilder::buildStubFrame(uint32_t frameSize,
return false;
}
}
} else if (op_ == JSOp::FunCall && GET_ARGC(pc_) == 0) {
} else if (resumeMode() == ResumeMode::InlinedFunCall && GET_ARGC(pc_) == 0) {
// When calling FunCall with 0 arguments, we push |undefined|
// for this. See BaselineCacheIRCompiler::pushFunCallArguments.
MOZ_ASSERT(!pushedNewTarget);
@ -1012,8 +1019,10 @@ bool BaselineStackBuilder::buildStubFrame(uint32_t frameSize,
callee = *blFrame()->valueSlot(calleeSlot);
} else {
MOZ_ASSERT(resumeMode() == ResumeMode::InlinedStandardCall ||
resumeMode() == ResumeMode::InlinedFunCall);
actualArgc = GET_ARGC(pc_);
if (op_ == JSOp::FunCall) {
if (resumeMode() == ResumeMode::InlinedFunCall) {
// See BaselineCacheIRCompiler::pushFunCallArguments.
MOZ_ASSERT(actualArgc > 0);
actualArgc--;
@ -1278,6 +1287,61 @@ bool BaselineStackBuilder::envChainSlotCanBeOptimized() {
return true;
}
bool jit::AssertBailoutStackDepth(JSContext* cx, JSScript* script,
jsbytecode* pc, ResumeMode mode,
uint32_t exprStackSlots) {
if (mode == ResumeMode::ResumeAfter) {
pc = GetNextPc(pc);
}
uint32_t expectedDepth;
bool reachablePC;
if (!ReconstructStackDepth(cx, script, pc, &expectedDepth, &reachablePC)) {
return false;
}
if (!reachablePC) {
return true;
}
JSOp op = JSOp(*pc);
if (mode == ResumeMode::InlinedFunCall) {
// For inlined fun.call(this, ...); the reconstructed stack depth will
// include the |this|, but the exprStackSlots won't.
// Exception: if there are no arguments, the depths do match.
MOZ_ASSERT(IsInvokeOp(op));
if (GET_ARGC(pc) > 0) {
MOZ_ASSERT(expectedDepth == exprStackSlots + 1);
} else {
MOZ_ASSERT(expectedDepth == exprStackSlots);
}
return true;
}
if (mode == ResumeMode::InlinedAccessor) {
// Accessors coming out of ion are inlined via a complete lie perpetrated by
// the compiler internally. Ion just rearranges the stack, and pretends that
// it looked like a call all along.
// This means that the depth is actually one *more* than expected by the
// interpreter, as there is now a JSFunction, |this| and [arg], rather than
// the expected |this| and [arg].
// If the inlined accessor is a GetElem operation, the numbers do match, but
// that's just because GetElem expects one more item on the stack. Note that
// none of that was pushed, but it's still reflected in exprStackSlots.
MOZ_ASSERT(IsIonInlinableGetterOrSetterOp(op));
if (IsGetElemOp(op)) {
MOZ_ASSERT(exprStackSlots == expectedDepth);
} else {
MOZ_ASSERT(exprStackSlots == expectedDepth + 1);
}
return true;
}
// In all other cases, the depth must match.
MOZ_ASSERT(exprStackSlots == expectedDepth);
return true;
}
bool BaselineStackBuilder::validateFrame() {
const uint32_t frameSize = framePushed();
blFrame()->setDebugFrameSize(frameSize);
@ -1287,38 +1351,8 @@ bool BaselineStackBuilder::validateFrame() {
MOZ_ASSERT(blFrame()->debugNumValueSlots() >= script_->nfixed());
MOZ_ASSERT(blFrame()->debugNumValueSlots() <= script_->nslots());
uint32_t expectedDepth;
bool reachablePC;
jsbytecode* pcForStackDepth = resumeAfter() ? GetNextPc(pc_) : pc_;
if (!ReconstructStackDepth(cx_, script_, pcForStackDepth, &expectedDepth,
&reachablePC)) {
return false;
}
if (!reachablePC) {
return true;
}
if (op_ == JSOp::FunCall) {
// For fun.call(this, ...); the reconstructed stack depth will
// include the this. When inlining that is not included.
// So the exprStackSlots will be one less.
MOZ_ASSERT(expectedDepth - exprStackSlots() <= 1);
} else if (iter_.moreFrames() && IsIonInlinableGetterOrSetterOp(op_)) {
// Accessors coming out of ion are inlined via a complete
// lie perpetrated by the compiler internally. Ion just rearranges
// the stack, and pretends that it looked like a call all along.
// This means that the depth is actually one *more* than expected
// by the interpreter, as there is now a JSFunction, |this| and [arg],
// rather than the expected |this| and [arg].
// If the inlined accessor is a getelem operation, the numbers do match,
// but that's just because getelem expects one more item on the stack.
// Note that none of that was pushed, but it's still reflected
// in exprStackSlots.
MOZ_ASSERT(exprStackSlots() - expectedDepth == (IsGetElemOp(op_) ? 0 : 1));
} else {
MOZ_ASSERT(exprStackSlots() == expectedDepth);
}
return true;
return AssertBailoutStackDepth(cx_, script_, pc_, resumeMode(),
exprStackSlots());
}
#endif

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

@ -4494,11 +4494,6 @@ bool BaselineCodeGen<Handler>::emit_SuperCall() {
return emitCall(JSOp::SuperCall);
}
template <typename Handler>
bool BaselineCodeGen<Handler>::emit_FunCall() {
return emitCall(JSOp::FunCall);
}
template <typename Handler>
bool BaselineCodeGen<Handler>::emit_Eval() {
return emitCall(JSOp::Eval);

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

@ -295,7 +295,6 @@ class MOZ_STATIC_CLASS OpToFallbackKindTable {
setKind(JSOp::Call, BaselineICFallbackKind::Call);
setKind(JSOp::CallIgnoresRv, BaselineICFallbackKind::Call);
setKind(JSOp::CallIter, BaselineICFallbackKind::Call);
setKind(JSOp::FunCall, BaselineICFallbackKind::Call);
setKind(JSOp::Eval, BaselineICFallbackKind::Call);
setKind(JSOp::StrictEval, BaselineICFallbackKind::Call);
@ -1582,8 +1581,8 @@ bool DoCallFallback(JSContext* cx, BaselineFrame* frame, ICFallbackStub* stub,
}
} else {
MOZ_ASSERT(op == JSOp::Call || op == JSOp::CallIgnoresRv ||
op == JSOp::CallIter || op == JSOp::FunCall ||
op == JSOp::Eval || op == JSOp::StrictEval);
op == JSOp::CallIter || op == JSOp::Eval ||
op == JSOp::StrictEval);
if (op == JSOp::CallIter && callee.isPrimitive()) {
MOZ_ASSERT(argc == 0, "thisv must be on top of the stack");
ReportValueError(cx, JSMSG_NOT_ITERABLE, -1, callArgs.thisv(), nullptr);

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

@ -9843,7 +9843,6 @@ AttachDecision CallIRGenerator::tryAttachStub() {
case JSOp::SpreadNew:
case JSOp::SuperCall:
case JSOp::SpreadSuperCall:
case JSOp::FunCall:
break;
default:
return AttachDecision::NoAction;
@ -9874,7 +9873,7 @@ AttachDecision CallIRGenerator::tryAttachStub() {
// Try inlining Function.prototype.{call,apply}. We don't use the
// InlinableNative mechanism for this because we want to optimize these more
// aggressively than other natives.
if (op_ == JSOp::FunCall || op_ == JSOp::Call || op_ == JSOp::CallIgnoresRv) {
if (op_ == JSOp::Call || op_ == JSOp::CallIgnoresRv) {
TRY_ATTACH(tryAttachFunCall(calleeFunc));
TRY_ATTACH(tryAttachFunApply(calleeFunc));
}

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

@ -8178,11 +8178,26 @@ void CodeGenerator::visitWasmStoreSlot(LWasmStoreSlot* ins) {
}
}
void CodeGenerator::visitWasmLoadTableElement(LWasmLoadTableElement* ins) {
Register elements = ToRegister(ins->elements());
Register index = ToRegister(ins->index());
Register output = ToRegister(ins->output());
masm.loadPtr(BaseIndex(elements, index, ScalePointer), output);
}
void CodeGenerator::visitWasmDerivedPointer(LWasmDerivedPointer* ins) {
masm.movePtr(ToRegister(ins->base()), ToRegister(ins->output()));
masm.addPtr(Imm32(int32_t(ins->offset())), ToRegister(ins->output()));
}
void CodeGenerator::visitWasmDerivedIndexPointer(
LWasmDerivedIndexPointer* ins) {
Register base = ToRegister(ins->base());
Register index = ToRegister(ins->index());
Register output = ToRegister(ins->output());
masm.computeEffectiveAddress(BaseIndex(base, index, ins->scale()), output);
}
void CodeGenerator::visitWasmStoreRef(LWasmStoreRef* ins) {
Register tls = ToRegister(ins->tls());
Register valueAddr = ToRegister(ins->valueAddr());

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

@ -907,7 +907,7 @@ static void EliminateTriviallyDeadResumePointOperands(MIRGraph& graph,
MResumePoint* rp) {
// If we will pop the top of the stack immediately after resuming,
// then don't preserve the top value in the resume point.
if (rp->mode() != MResumePoint::ResumeAt || JSOp(*rp->pc()) != JSOp::Pop) {
if (rp->mode() != ResumeMode::ResumeAt || JSOp(*rp->pc()) != JSOp::Pop) {
return;
}

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

@ -991,6 +991,42 @@ constexpr T SplatByteToUInt(uint8_t val, uint8_t x) {
return splatted;
}
// Resume information for a frame, stored in a resume point.
enum class ResumeMode : uint8_t {
// Innermost frame. Resume at the next bytecode op when bailing out.
ResumeAfter,
// Innermost frame. Resume at the current bytecode op when bailing out.
ResumeAt,
// Outer frame for an inlined "standard" call at an IsInvokeOp bytecode op.
InlinedStandardCall,
// Outer frame for an inlined js::fun_call at an IsInvokeOp bytecode op.
InlinedFunCall,
// Outer frame for an inlined getter/setter at a Get*/Set* bytecode op.
InlinedAccessor,
Last = InlinedAccessor
};
inline const char* ResumeModeToString(ResumeMode mode) {
switch (mode) {
case ResumeMode::ResumeAfter:
return "ResumeAfter";
case ResumeMode::ResumeAt:
return "ResumeAt";
case ResumeMode::InlinedStandardCall:
return "InlinedStandardCall";
case ResumeMode::InlinedFunCall:
return "InlinedFunCall";
case ResumeMode::InlinedAccessor:
return "InlinedAccessor";
}
MOZ_CRASH("Invalid mode");
}
} // namespace jit
} // namespace js

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

@ -476,14 +476,12 @@ class SnapshotIterator {
public:
// Exhibits frame properties contained in the snapshot.
uint32_t pcOffset() const;
[[nodiscard]] inline bool resumeAfter() const {
// Inline frames are inlined on calls, which are considered as being
// resumed on the Call as baseline will push the pc once we return from
// the call.
if (moreFrames()) {
return false;
}
return recover_.resumeAfter();
ResumeMode resumeMode() const;
bool resumeAfter() const {
// Calls in outer frames are never considered resume-after.
MOZ_ASSERT_IF(moreFrames(), resumeMode() != ResumeMode::ResumeAfter);
return resumeMode() == ResumeMode::ResumeAfter;
}
inline BailoutKind bailoutKind() const { return snapshot_.bailoutKind(); }

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

@ -45,17 +45,7 @@ void JSONSpewer::spewMResumePoint(MResumePoint* rp) {
property("caller", rp->caller()->block()->id());
}
switch (rp->mode()) {
case MResumePoint::ResumeAt:
property("mode", "At");
break;
case MResumePoint::ResumeAfter:
property("mode", "After");
break;
case MResumePoint::Outer:
property("mode", "Outer");
break;
}
property("mode", ResumeModeToString(rp->mode()));
beginListProperty("operands");
for (MResumePoint* iter = rp; iter; iter = iter->caller()) {

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

@ -1817,6 +1817,10 @@ uint32_t SnapshotIterator::pcOffset() const {
return resumePoint()->pcOffset();
}
ResumeMode SnapshotIterator::resumeMode() const {
return resumePoint()->mode();
}
void SnapshotIterator::skipInstruction() {
MOZ_ASSERT(snapshot_.numAllocationsRead() == 0);
size_t numOperands = instruction()->numOperands();
@ -2043,18 +2047,23 @@ void InlineFrameIterator::findNextFrame() {
size_t i = 1;
for (; i <= remaining && si_.moreFrames(); i++) {
ResumeMode mode = si_.resumeMode();
MOZ_ASSERT(IsIonInlinableOp(JSOp(*pc_)));
// Recover the number of actual arguments from the script.
if (IsInvokeOp(JSOp(*pc_))) {
MOZ_ASSERT(mode == ResumeMode::InlinedStandardCall ||
mode == ResumeMode::InlinedFunCall);
numActualArgs_ = GET_ARGC(pc_);
if (JSOp(*pc_) == JSOp::FunCall && numActualArgs_ > 0) {
if (mode == ResumeMode::InlinedFunCall && numActualArgs_ > 0) {
numActualArgs_--;
}
} else if (IsGetPropPC(pc_) || IsGetElemPC(pc_)) {
MOZ_ASSERT(mode == ResumeMode::InlinedAccessor);
numActualArgs_ = 0;
} else {
MOZ_RELEASE_ASSERT(IsSetPropPC(pc_));
MOZ_ASSERT(mode == ResumeMode::InlinedAccessor);
numActualArgs_ = 1;
}

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

@ -2723,9 +2723,18 @@
arguments:
offset: size_t
- name: WasmLoadTableElement
result_type: WordSized
operands:
elements: WordSized
index: WordSized
- name: WasmDerivedPointer
gen_boilerplate: false
- name: WasmDerivedIndexPointer
gen_boilerplate: false
- name: WasmStoreRef
operands:
tls: WordSized

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

@ -5116,6 +5116,12 @@ void LIRGenerator::visitWasmLoadGlobalCell(MWasmLoadGlobalCell* ins) {
}
}
void LIRGenerator::visitWasmLoadTableElement(MWasmLoadTableElement* ins) {
LAllocation elements = useRegisterAtStart(ins->elements());
LAllocation index = useRegisterAtStart(ins->index());
define(new (alloc()) LWasmLoadTableElement(elements, index), ins);
}
void LIRGenerator::visitWasmStoreGlobalVar(MWasmStoreGlobalVar* ins) {
MDefinition* value = ins->value();
size_t offs = wasm::Instance::offsetOfGlobalArea() + ins->globalDataOffset();
@ -5178,6 +5184,12 @@ void LIRGenerator::visitWasmDerivedPointer(MWasmDerivedPointer* ins) {
define(new (alloc()) LWasmDerivedPointer(base), ins);
}
void LIRGenerator::visitWasmDerivedIndexPointer(MWasmDerivedIndexPointer* ins) {
LAllocation base = useRegisterAtStart(ins->base());
LAllocation index = useRegisterAtStart(ins->index());
define(new (alloc()) LWasmDerivedIndexPointer(base, index), ins);
}
void LIRGenerator::visitWasmStoreRef(MWasmStoreRef* ins) {
LAllocation tls = useRegister(ins->tls());
LAllocation valueAddr = useFixed(ins->valueAddr(), PreBarrierReg);

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

@ -3340,7 +3340,7 @@ MUrsh* MUrsh::NewWasm(TempAllocator& alloc, MDefinition* left,
}
MResumePoint* MResumePoint::New(TempAllocator& alloc, MBasicBlock* block,
jsbytecode* pc, Mode mode) {
jsbytecode* pc, ResumeMode mode) {
MResumePoint* resume = new (alloc) MResumePoint(block, pc, mode);
if (!resume->init(alloc)) {
block->discardPreAllocatedResumePoint(resume);
@ -3350,7 +3350,7 @@ MResumePoint* MResumePoint::New(TempAllocator& alloc, MBasicBlock* block,
return resume;
}
MResumePoint::MResumePoint(MBasicBlock* block, jsbytecode* pc, Mode mode)
MResumePoint::MResumePoint(MBasicBlock* block, jsbytecode* pc, ResumeMode mode)
: MNode(block, Kind::ResumePoint),
pc_(pc),
instruction_(nullptr),
@ -3400,18 +3400,15 @@ void MResumePoint::dump(GenericPrinter& out) const {
out.printf("resumepoint mode=");
switch (mode()) {
case MResumePoint::ResumeAt:
case ResumeMode::ResumeAt:
if (instruction_) {
out.printf("At(%u)", instruction_->id());
out.printf("ResumeAt(%u)", instruction_->id());
} else {
out.printf("At");
out.printf("ResumeAt");
}
break;
case MResumePoint::ResumeAfter:
out.printf("After");
break;
case MResumePoint::Outer:
out.printf("Outer");
default:
out.put(ResumeModeToString(mode()));
break;
}

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

@ -333,32 +333,34 @@ class AliasSet {
1 << 9, // An array buffer view's length or byteOffset
WasmGlobalCell = 1 << 10, // A wasm global cell
WasmTableElement = 1 << 11, // An element of a wasm table
WasmStackResult = 1 << 12, // A stack result from the current function
WasmTableMeta = 1 << 12, // A wasm table elements pointer and
// length field, in Tls.
WasmStackResult = 1 << 13, // A stack result from the current function
// JSContext's exception state. This is used on instructions like MThrow
// or MNewArrayDynamicLength that throw exceptions (other than OOM) but have
// no other side effect, to ensure that they get their own up-to-date resume
// point. (This resume point will be used when constructing the Baseline
// frame during exception bailouts.)
ExceptionState = 1 << 13,
ExceptionState = 1 << 14,
// Used for instructions that load the privateSlot of DOM proxies and
// the ExpandoAndGeneration.
DOMProxyExpando = 1 << 14,
DOMProxyExpando = 1 << 15,
// Hash table of a Map or Set object.
MapOrSetHashTable = 1 << 15,
MapOrSetHashTable = 1 << 16,
// Internal state of the random number generator
RNG = 1 << 16,
RNG = 1 << 17,
// The pendingException slot on the wasm tls object.
WasmPendingException = 1 << 17,
WasmPendingException = 1 << 18,
Last = WasmPendingException,
Any = Last | (Last - 1),
NumCategories = 18,
NumCategories = 19,
// Indicates load or store.
Store_ = 1 << 31
@ -8444,13 +8446,6 @@ class MResumePoint final : public MNode
public InlineForwardListNode<MResumePoint>
#endif
{
public:
enum Mode {
ResumeAt, // Resume until before the current instruction
ResumeAfter, // Resume after the current instruction
Outer // State before inlining.
};
private:
friend class MBasicBlock;
friend void AssertBasicGraphCoherency(MIRGraph& graph, bool force);
@ -8464,9 +8459,9 @@ class MResumePoint final : public MNode
jsbytecode* pc_;
MInstruction* instruction_;
Mode mode_;
ResumeMode mode_;
MResumePoint(MBasicBlock* block, jsbytecode* pc, Mode mode);
MResumePoint(MBasicBlock* block, jsbytecode* pc, ResumeMode mode);
void inherit(MBasicBlock* state);
// Calling isDefinition or isResumePoint on MResumePoint is unnecessary.
@ -8490,7 +8485,7 @@ class MResumePoint final : public MNode
public:
static MResumePoint* New(TempAllocator& alloc, MBasicBlock* block,
jsbytecode* pc, Mode mode);
jsbytecode* pc, ResumeMode mode);
MBasicBlock* block() const { return resumePointBlock(); }
@ -8535,7 +8530,7 @@ class MResumePoint final : public MNode
MOZ_ASSERT(instruction_);
instruction_ = nullptr;
}
Mode mode() const { return mode_; }
ResumeMode mode() const { return mode_; }
void releaseUses() {
for (size_t i = 0, e = numOperands(); i < e; i++) {
@ -8988,11 +8983,12 @@ class MWasmLoadTls : public MUnaryInstruction, public NoTypePolicy::Data {
aliases_(aliases) {
// Different Tls data have different alias classes and only those classes
// are allowed.
MOZ_ASSERT(aliases_.flags() ==
AliasSet::Load(AliasSet::WasmHeapMeta).flags() ||
aliases_.flags() ==
AliasSet::Load(AliasSet::WasmPendingException).flags() ||
aliases_.flags() == AliasSet::None().flags());
MOZ_ASSERT(
aliases_.flags() == AliasSet::Load(AliasSet::WasmHeapMeta).flags() ||
aliases_.flags() == AliasSet::Load(AliasSet::WasmTableMeta).flags() ||
aliases_.flags() ==
AliasSet::Load(AliasSet::WasmPendingException).flags() ||
aliases_.flags() == AliasSet::None().flags());
// The only types supported at the moment.
MOZ_ASSERT(type == MIRType::Pointer || type == MIRType::Int32 ||
@ -9081,12 +9077,21 @@ class MWasmHeapBase : public MUnaryInstruction, public NoTypePolicy::Data {
// For memory64, bounds check nodes are always of type Int64.
class MWasmBoundsCheck : public MBinaryInstruction, public NoTypePolicy::Data {
public:
enum Target {
Memory,
Table,
};
private:
wasm::BytecodeOffset bytecodeOffset_;
Target target_;
explicit MWasmBoundsCheck(MDefinition* index, MDefinition* boundsCheckLimit,
wasm::BytecodeOffset bytecodeOffset)
wasm::BytecodeOffset bytecodeOffset, Target target)
: MBinaryInstruction(classOpcode, index, boundsCheckLimit),
bytecodeOffset_(bytecodeOffset) {
bytecodeOffset_(bytecodeOffset),
target_(target) {
MOZ_ASSERT(index->type() == boundsCheckLimit->type());
// Bounds check is effectful: it throws for OOB.
@ -9104,6 +9109,8 @@ class MWasmBoundsCheck : public MBinaryInstruction, public NoTypePolicy::Data {
AliasSet getAliasSet() const override { return AliasSet::None(); }
bool isMemory() const { return target_ == MWasmBoundsCheck::Memory; }
bool isRedundant() const { return !isGuard(); }
void setRedundant() { setNotGuard(); }
@ -9578,6 +9585,25 @@ class MWasmLoadGlobalCell : public MUnaryInstruction,
AliasType mightAlias(const MDefinition* def) const override;
};
class MWasmLoadTableElement : public MBinaryInstruction,
public NoTypePolicy::Data {
MWasmLoadTableElement(MDefinition* elements, MDefinition* index)
: MBinaryInstruction(classOpcode, elements, index) {
setResultType(MIRType::RefOrNull);
setMovable();
}
public:
INSTRUCTION_HEADER(WasmLoadTableElement)
TRIVIAL_NEW_WRAPPERS
NAMED_OPERANDS((0, elements))
NAMED_OPERANDS((1, index))
AliasSet getAliasSet() const override {
return AliasSet::Load(AliasSet::WasmTableElement);
}
};
class MWasmStoreGlobalVar : public MBinaryInstruction,
public NoTypePolicy::Data {
MWasmStoreGlobalVar(unsigned globalDataOffset, MDefinition* value,
@ -9668,6 +9694,38 @@ class MWasmDerivedPointer : public MUnaryInstruction,
ALLOW_CLONE(MWasmDerivedPointer)
};
class MWasmDerivedIndexPointer : public MBinaryInstruction,
public NoTypePolicy::Data {
MWasmDerivedIndexPointer(MDefinition* base, MDefinition* index, Scale scale)
: MBinaryInstruction(classOpcode, base, index), scale_(scale) {
setResultType(MIRType::Pointer);
setMovable();
}
Scale scale_;
public:
INSTRUCTION_HEADER(WasmDerivedIndexPointer)
TRIVIAL_NEW_WRAPPERS
NAMED_OPERANDS((0, base))
NAMED_OPERANDS((1, index))
Scale scale() const { return scale_; }
AliasSet getAliasSet() const override { return AliasSet::None(); }
bool congruentTo(const MDefinition* ins) const override {
return congruentIfOperandsEqual(ins) &&
ins->toWasmDerivedIndexPointer()->scale() == scale();
}
ALLOW_CLONE(MWasmDerivedIndexPointer)
};
// Stores a reference to an address. This performs a pre-barrier on the address,
// but not a post-barrier. A post-barrier must be performed separately, if it's
// required.
class MWasmStoreRef : public MAryInstruction<3>, public NoTypePolicy::Data {
AliasSet::Flag aliasSet_;

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

@ -219,7 +219,7 @@ MBasicBlock* MBasicBlock::NewSplitEdge(MIRGraph& graph, MBasicBlock* pred,
// Create a resume point using our initial stack position.
MResumePoint* splitEntry = new (graph.alloc())
MResumePoint(split, succEntry->pc(), MResumePoint::ResumeAt);
MResumePoint(split, succEntry->pc(), ResumeMode::ResumeAt);
if (!splitEntry->init(graph.alloc())) {
return nullptr;
}
@ -462,7 +462,7 @@ bool MBasicBlock::inherit(TempAllocator& alloc, size_t stackDepth,
// Create a resume point using our initial stack state.
entryResumePoint_ =
new (alloc) MResumePoint(this, pc(), MResumePoint::ResumeAt);
new (alloc) MResumePoint(this, pc(), ResumeMode::ResumeAt);
if (!entryResumePoint_->init(alloc)) {
return false;
}
@ -512,7 +512,7 @@ bool MBasicBlock::initEntrySlots(TempAllocator& alloc) {
// Create a resume point using our initial stack state.
entryResumePoint_ =
MResumePoint::New(alloc, this, pc(), MResumePoint::ResumeAt);
MResumePoint::New(alloc, this, pc(), ResumeMode::ResumeAt);
if (!entryResumePoint_) {
return false;
}

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

@ -2607,6 +2607,9 @@
- name: WasmLoadGlobalCell
gen_boilerplate: false
- name: WasmLoadTableElement
gen_boilerplate: false
- name: WasmStoreGlobalVar
gen_boilerplate: false
@ -2619,6 +2622,9 @@
- name: WasmDerivedPointer
gen_boilerplate: false
- name: WasmDerivedIndexPointer
gen_boilerplate: false
- name: WasmStoreRef
gen_boilerplate: false

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

@ -10,6 +10,7 @@
#include "builtin/RegExp.h"
#include "builtin/String.h"
#include "jit/Bailouts.h"
#include "jit/CompileInfo.h"
#include "jit/Ion.h"
#include "jit/JitSpewer.h"
@ -68,37 +69,10 @@ bool MResumePoint::writeRecoverData(CompactBufferWriter& writer) const {
#ifdef DEBUG
// Ensure that all snapshot which are encoded can safely be used for
// bailouts.
if (GetJitContext()->cx) {
uint32_t stackDepth;
bool reachablePC;
jsbytecode* bailPC = pc();
if (mode() == MResumePoint::ResumeAfter) {
bailPC = GetNextPc(pc());
}
if (!ReconstructStackDepth(GetJitContext()->cx, script, bailPC, &stackDepth,
&reachablePC)) {
if (JSContext* cx = GetJitContext()->cx) {
if (!AssertBailoutStackDepth(cx, script, pc(), mode(), exprStack)) {
return false;
}
if (reachablePC) {
JSOp bailOp = JSOp(*bailPC);
if (bailOp == JSOp::FunCall) {
// For fun.call(this, ...); the reconstructStackDepth will
// include the this. When inlining that is not included. So the
// exprStackSlots will be one less.
MOZ_ASSERT(stackDepth - exprStack <= 1);
} else {
// With accessors, we have different stack depths depending on
// whether or not we inlined the accessor, as the inlined stack
// contains a callee function that should never have been there
// and we might just be capturing an uneventful property site,
// in which case there won't have been any violence.
MOZ_ASSERT_IF(!IsIonInlinableGetterOrSetterOp(bailOp),
exprStack == stackDepth);
}
}
}
#endif
@ -119,19 +93,26 @@ bool MResumePoint::writeRecoverData(CompactBufferWriter& writer) const {
"Starting frame; implicit %u, formals %u, fixed %zu, exprs %u",
implicit, formalArgs - implicit, script->nfixed(), exprStack);
uint32_t pcoff = script->pcToOffset(pc());
JitSpew(JitSpew_IonSnapshots, "Writing pc offset %u, nslots %u", pcoff,
nallocs);
writer.writeUnsigned(pcoff);
uint32_t pcOff = script->pcToOffset(pc());
JitSpew(JitSpew_IonSnapshots, "Writing pc offset %u, mode %s, nslots %u",
pcOff, ResumeModeToString(mode()), nallocs);
uint32_t pcOffAndMode =
(pcOff << RResumePoint::PCOffsetShift) | uint32_t(mode());
MOZ_RELEASE_ASSERT((pcOffAndMode >> RResumePoint::PCOffsetShift) == pcOff,
"pcOff doesn't fit in pcOffAndMode");
writer.writeUnsigned(pcOffAndMode);
writer.writeUnsigned(nallocs);
return true;
}
RResumePoint::RResumePoint(CompactBufferReader& reader) {
pcOffset_ = reader.readUnsigned();
pcOffsetAndMode_ = reader.readUnsigned();
numOperands_ = reader.readUnsigned();
JitSpew(JitSpew_IonSnapshots, "Read RResumePoint (pc offset %u, nslots %u)",
pcOffset_, numOperands_);
JitSpew(JitSpew_IonSnapshots,
"Read RResumePoint (pc offset %u, mode %s, nslots %u)", pcOffset(),
ResumeModeToString(mode()), numOperands_);
}
bool RResumePoint::recover(JSContext* cx, SnapshotIterator& iter) const {

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

@ -207,13 +207,22 @@ class MOZ_NON_PARAM RInstruction {
class RResumePoint final : public RInstruction {
private:
uint32_t pcOffset_; // Offset from script->code.
uint32_t numOperands_; // Number of slots.
uint32_t pcOffsetAndMode_; // Offset from script->code and ResumeMode.
uint32_t numOperands_; // Number of slots.
public:
RINSTRUCTION_HEADER_(ResumePoint)
uint32_t pcOffset() const { return pcOffset_; }
// Used to encode/decode pcOffsetAndMode_.
static constexpr uint32_t PCOffsetShift = 4;
static constexpr uint32_t ResumeModeMask = 0b1111;
static_assert(uint32_t(ResumeMode::Last) <= ResumeModeMask);
uint32_t pcOffset() const { return pcOffsetAndMode_ >> PCOffsetShift; }
ResumeMode mode() const {
return ResumeMode(pcOffsetAndMode_ & ResumeModeMask);
}
uint32_t numOperands() const override { return numOperands_; }
[[nodiscard]] bool recover(JSContext* cx,
SnapshotIterator& iter) const override;

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

@ -404,17 +404,6 @@ static const uint32_t SNAPSHOT_ROFFSET_SHIFT =
static const uint32_t SNAPSHOT_ROFFSET_BITS = 32 - SNAPSHOT_ROFFSET_SHIFT;
static const uint32_t SNAPSHOT_ROFFSET_MASK = COMPUTE_MASK_(SNAPSHOT_ROFFSET);
// Details of recover header packing.
static const uint32_t RECOVER_RESUMEAFTER_SHIFT = 0;
static const uint32_t RECOVER_RESUMEAFTER_BITS = 1;
static const uint32_t RECOVER_RESUMEAFTER_MASK =
COMPUTE_MASK_(RECOVER_RESUMEAFTER);
static const uint32_t RECOVER_RINSCOUNT_SHIFT =
COMPUTE_SHIFT_AFTER_(RECOVER_RESUMEAFTER);
static const uint32_t RECOVER_RINSCOUNT_BITS = 32 - RECOVER_RINSCOUNT_SHIFT;
static const uint32_t RECOVER_RINSCOUNT_MASK = COMPUTE_MASK_(RECOVER_RINSCOUNT);
#undef COMPUTE_MASK_
#undef COMPUTE_SHIFT_AFTER_
@ -478,10 +467,7 @@ SnapshotWriter::SnapshotWriter()
RecoverReader::RecoverReader(SnapshotReader& snapshot, const uint8_t* recovers,
uint32_t size)
: reader_(nullptr, nullptr),
numInstructions_(0),
numInstructionsRead_(0),
resumeAfter_(false) {
: reader_(nullptr, nullptr), numInstructions_(0), numInstructionsRead_(0) {
if (!recovers) {
return;
}
@ -494,8 +480,7 @@ RecoverReader::RecoverReader(SnapshotReader& snapshot, const uint8_t* recovers,
RecoverReader::RecoverReader(const RecoverReader& rr)
: reader_(rr.reader_),
numInstructions_(rr.numInstructions_),
numInstructionsRead_(rr.numInstructionsRead_),
resumeAfter_(rr.resumeAfter_) {
numInstructionsRead_(rr.numInstructionsRead_) {
if (reader_.currentPosition()) {
rr.instruction()->cloneInto(&rawData_);
}
@ -505,7 +490,6 @@ RecoverReader& RecoverReader::operator=(const RecoverReader& rr) {
reader_ = rr.reader_;
numInstructions_ = rr.numInstructions_;
numInstructionsRead_ = rr.numInstructionsRead_;
resumeAfter_ = rr.resumeAfter_;
if (reader_.currentPosition()) {
rr.instruction()->cloneInto(&rawData_);
}
@ -513,15 +497,11 @@ RecoverReader& RecoverReader::operator=(const RecoverReader& rr) {
}
void RecoverReader::readRecoverHeader() {
uint32_t bits = reader_.readUnsigned();
numInstructions_ = (bits & RECOVER_RINSCOUNT_MASK) >> RECOVER_RINSCOUNT_SHIFT;
resumeAfter_ = (bits & RECOVER_RESUMEAFTER_MASK) >> RECOVER_RESUMEAFTER_SHIFT;
numInstructions_ = reader_.readUnsigned();
MOZ_ASSERT(numInstructions_);
JitSpew(JitSpew_IonSnapshots,
"Read recover header with instructionCount %u (ra: %d)",
numInstructions_, resumeAfter_);
JitSpew(JitSpew_IonSnapshots, "Read recover header with instructionCount %u",
numInstructions_);
}
void RecoverReader::readInstruction() {
@ -600,8 +580,7 @@ void SnapshotWriter::endSnapshot() {
uint32_t(writer_.length() - lastStart_), lastStart_);
}
RecoverOffset RecoverWriter::startRecover(uint32_t instructionCount,
bool resumeAfter) {
RecoverOffset RecoverWriter::startRecover(uint32_t instructionCount) {
MOZ_ASSERT(instructionCount);
instructionCount_ = instructionCount;
instructionsWritten_ = 0;
@ -609,13 +588,8 @@ RecoverOffset RecoverWriter::startRecover(uint32_t instructionCount,
JitSpew(JitSpew_IonSnapshots, "starting recover with %u instruction(s)",
instructionCount);
MOZ_ASSERT(!(uint32_t(resumeAfter) & ~RECOVER_RESUMEAFTER_MASK));
MOZ_ASSERT(instructionCount < uint32_t(1 << RECOVER_RINSCOUNT_BITS));
uint32_t bits = (uint32_t(resumeAfter) << RECOVER_RESUMEAFTER_SHIFT) |
(instructionCount << RECOVER_RINSCOUNT_SHIFT);
RecoverOffset recoverOffset = writer_.length();
writer_.writeUnsigned(bits);
writer_.writeUnsigned(instructionCount);
return recoverOffset;
}

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

@ -402,7 +402,7 @@ class RecoverWriter {
uint32_t instructionsWritten_;
public:
SnapshotOffset startRecover(uint32_t instructionCount, bool resumeAfter);
SnapshotOffset startRecover(uint32_t instructionCount);
void writeInstruction(const MNode* rp);
@ -496,10 +496,6 @@ class RecoverReader {
// Number of instruction read.
uint32_t numInstructionsRead_;
// True if we need to resume after the Resume Point instruction of the
// innermost frame.
bool resumeAfter_;
// Space is reserved as part of the RecoverReader to avoid allocations of
// data which is needed to decode the current instruction.
RInstructionStorage rawData_;
@ -525,8 +521,6 @@ class RecoverReader {
const RInstruction* instruction() const {
return reinterpret_cast<const RInstruction*>(rawData_.addr());
}
bool resumeAfter() const { return resumeAfter_; }
};
} // namespace jit

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

@ -162,7 +162,7 @@ ICCacheIRStub* TrialInliner::maybeSingleStub(const ICEntry& entry) {
Maybe<InlinableOpData> FindInlinableOpData(ICCacheIRStub* stub,
BytecodeLocation loc) {
if (loc.isInvokeOp()) {
Maybe<InlinableCallData> call = FindInlinableCallData(stub, loc);
Maybe<InlinableCallData> call = FindInlinableCallData(stub);
if (call.isSome()) {
return call;
}
@ -182,8 +182,7 @@ Maybe<InlinableOpData> FindInlinableOpData(ICCacheIRStub* stub,
return mozilla::Nothing();
}
Maybe<InlinableCallData> FindInlinableCallData(ICCacheIRStub* stub,
BytecodeLocation loc) {
Maybe<InlinableCallData> FindInlinableCallData(ICCacheIRStub* stub) {
Maybe<InlinableCallData> data;
const CacheIRStubInfo* stubInfo = stub->stubInfo();
@ -273,15 +272,6 @@ Maybe<InlinableCallData> FindInlinableCallData(ICCacheIRStub* stub,
flags.getArgFormat() != CallFlags::FunCall) {
return mozilla::Nothing();
}
// Warp assumes any inlining at JSOp::FunCall ops is for js::fun_call and
// that any fun-call-specific inlining is at JSOp::FunCall ops. Bailouts and
// numActualArgs recovery (in InlineFrameIterator::findNextFrame) depend on
// this.
bool isFunCallOp = loc.getOp() == JSOp::FunCall;
bool isFunCall = flags.getArgFormat() == CallFlags::FunCall;
if (isFunCallOp != isFunCall) {
return mozilla::Nothing();
}
data->calleeOperand = calleeGuardOperand;
data->callFlags = flags;
data->target = target;
@ -422,9 +412,10 @@ Maybe<InlinableSetterData> FindInlinableSetterData(ICCacheIRStub* stub) {
return data;
}
// Return the number of actual arguments that will be passed to the
// target function.
static uint32_t GetCalleeNumActuals(BytecodeLocation loc) {
// Return the maximum number of actual arguments that will be passed to the
// target function. This may be an overapproximation, for example when inlining
// js::fun_call we may omit an argument.
static uint32_t GetMaxCalleeNumActuals(BytecodeLocation loc) {
switch (loc.getOp()) {
case JSOp::GetProp:
case JSOp::GetElem:
@ -436,12 +427,6 @@ static uint32_t GetCalleeNumActuals(BytecodeLocation loc) {
// Setters pass 1 argument.
return 1;
case JSOp::FunCall: {
// If FunCall is passed arguments, one of them will become |this|.
uint32_t callArgc = loc.getCallArgc();
return callArgc > 0 ? callArgc - 1 : 0;
}
case JSOp::Call:
case JSOp::CallIgnoresRv:
case JSOp::CallIter:
@ -484,12 +469,12 @@ bool TrialInliner::canInline(JSFunction* target, HandleScript caller,
return false;
}
uint32_t calleeNumActuals = GetCalleeNumActuals(loc);
uint32_t maxCalleeNumActuals = GetMaxCalleeNumActuals(loc);
if (script->needsArgsObj() &&
calleeNumActuals > ArgumentsObject::MaxInlinedArgs) {
maxCalleeNumActuals > ArgumentsObject::MaxInlinedArgs) {
JitSpew(JitSpew_WarpTrialInlining,
"SKIP: needs arguments object with %u actual args (maximum %u)",
calleeNumActuals, ArgumentsObject::MaxInlinedArgs);
maxCalleeNumActuals, ArgumentsObject::MaxInlinedArgs);
return false;
}
@ -499,7 +484,7 @@ bool TrialInliner::canInline(JSFunction* target, HandleScript caller,
return false;
}
if (TooManyFormalArguments(calleeNumActuals)) {
if (TooManyFormalArguments(maxCalleeNumActuals)) {
JitSpew(JitSpew_WarpTrialInlining, "SKIP: argc too large: %u",
unsigned(loc.getCallArgc()));
return false;
@ -637,7 +622,7 @@ bool TrialInliner::maybeInlineCall(ICEntry& entry, ICFallbackStub* fallback,
MOZ_ASSERT(!icScript_->hasInlinedChild(fallback->pcOffset()));
// Look for a CallScriptedFunction with a known target.
Maybe<InlinableCallData> data = FindInlinableCallData(stub, loc);
Maybe<InlinableCallData> data = FindInlinableCallData(stub);
if (data.isNothing()) {
return true;
}
@ -649,10 +634,6 @@ bool TrialInliner::maybeInlineCall(ICEntry& entry, ICFallbackStub* fallback,
return true;
}
// We only inline FunCall if we are calling the js::fun_call builtin.
MOZ_ASSERT_IF(loc.getOp() == JSOp::FunCall,
data->callFlags.getArgFormat() == CallFlags::FunCall);
ICScript* newICScript = createInlinedICScript(data->target, loc);
if (!newICScript) {
return false;
@ -762,7 +743,6 @@ bool TrialInliner::tryInlining() {
case JSOp::Call:
case JSOp::CallIgnoresRv:
case JSOp::CallIter:
case JSOp::FunCall:
case JSOp::New:
case JSOp::SuperCall:
if (!maybeInlineCall(entry, fallback, loc)) {

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

@ -135,8 +135,7 @@ class InlinableSetterData : public InlinableOpData {
mozilla::Maybe<InlinableOpData> FindInlinableOpData(ICCacheIRStub* stub,
BytecodeLocation loc);
mozilla::Maybe<InlinableCallData> FindInlinableCallData(ICCacheIRStub* stub,
BytecodeLocation loc);
mozilla::Maybe<InlinableCallData> FindInlinableCallData(ICCacheIRStub* stub);
mozilla::Maybe<InlinableGetterData> FindInlinableGetterData(
ICCacheIRStub* stub);
mozilla::Maybe<InlinableSetterData> FindInlinableSetterData(

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

@ -1871,10 +1871,6 @@ bool WarpBuilder::build_CallIter(BytecodeLocation loc) {
return buildCallOp(loc);
}
bool WarpBuilder::build_FunCall(BytecodeLocation loc) {
return buildCallOp(loc);
}
bool WarpBuilder::build_New(BytecodeLocation loc) { return buildCallOp(loc); }
bool WarpBuilder::build_SuperCall(BytecodeLocation loc) {
@ -3391,7 +3387,7 @@ bool WarpBuilder::buildInlinedCall(BytecodeLocation loc,
return false;
}
MResumePoint* outerResumePoint =
MResumePoint::New(alloc(), current, pc, MResumePoint::Outer);
MResumePoint::New(alloc(), current, pc, callInfo.inliningResumeMode());
if (!outerResumePoint) {
return false;
}

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

@ -28,7 +28,7 @@ bool WarpBuilderShared::resumeAfter(MInstruction* ins, BytecodeLocation loc) {
MOZ_ASSERT(!ins->isMovable());
MResumePoint* resumePoint = MResumePoint::New(
alloc(), ins->block(), loc.toRawBytecode(), MResumePoint::ResumeAfter);
alloc(), ins->block(), loc.toRawBytecode(), ResumeMode::ResumeAfter);
if (!resumePoint) {
return false;
}

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

@ -8,6 +8,7 @@
#define jit_WarpBuilderShared_h
#include "mozilla/Attributes.h"
#include "mozilla/Maybe.h"
#include "jit/MIRGraph.h"
#include "js/Value.h"
@ -54,6 +55,7 @@ class MOZ_STACK_CLASS CallInfo {
private:
ArgFormat argFormat_ = ArgFormat::Standard;
mozilla::Maybe<ResumeMode> inliningMode_;
public:
CallInfo(TempAllocator& alloc, bool constructing, bool ignoresReturnValue,
@ -234,6 +236,17 @@ class MOZ_STACK_CLASS CallInfo {
bool isInlined() const { return inlined_; }
void markAsInlined() { inlined_ = true; }
ResumeMode inliningResumeMode() const {
MOZ_ASSERT(isInlined());
return *inliningMode_;
}
void setInliningResumeMode(ResumeMode mode) {
MOZ_ASSERT(isInlined());
MOZ_ASSERT(inliningMode_.isNothing());
inliningMode_.emplace(mode);
}
MDefinition* callee() const {
MOZ_ASSERT(callee_);
return callee_;

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

@ -4798,6 +4798,13 @@ bool WarpCacheIRTranspiler::emitCallInlinedFunction(ObjOperandId calleeId,
thisArg->type() == MIRType::MagicUninitializedLexical);
}
if (flags.getArgFormat() == CallFlags::FunCall) {
callInfo_->setInliningResumeMode(ResumeMode::InlinedFunCall);
} else {
MOZ_ASSERT(flags.getArgFormat() == CallFlags::Standard);
callInfo_->setInliningResumeMode(ResumeMode::InlinedStandardCall);
}
switch (callInfo_->argFormat()) {
case CallInfo::ArgFormat::Standard:
break;
@ -5001,6 +5008,7 @@ bool WarpCacheIRTranspiler::emitCallInlinedGetterResult(
MDefinition* receiver = getOperand(receiverId);
MDefinition* getter = objectStubField(getterOffset);
callInfo_->initForGetterCall(getter, receiver);
callInfo_->setInliningResumeMode(ResumeMode::InlinedAccessor);
// Make sure there's enough room to push the arguments on the stack.
if (!current->ensureHasSlots(2)) {
@ -5072,6 +5080,7 @@ bool WarpCacheIRTranspiler::emitCallInlinedSetter(
MDefinition* setter = objectStubField(setterOffset);
MDefinition* rhs = getOperand(rhsId);
callInfo_->initForSetterCall(setter, receiver, rhs);
callInfo_->setInliningResumeMode(ResumeMode::InlinedAccessor);
// Make sure there's enough room to push the arguments on the stack.
if (!current->ensureHasSlots(3)) {
@ -5158,7 +5167,7 @@ bool WarpCacheIRTranspiler::emitAssertRecoveredOnBailoutResult(
add(nop);
auto* resumePoint = MResumePoint::New(
alloc(), nop->block(), loc_.toRawBytecode(), MResumePoint::ResumeAfter);
alloc(), nop->block(), loc_.toRawBytecode(), ResumeMode::ResumeAfter);
if (!resumePoint) {
return false;
}

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

@ -470,7 +470,6 @@ AbortReasonOr<WarpScriptSnapshot*> WarpScriptOracle::createScriptSnapshot() {
case JSOp::Call:
case JSOp::CallIgnoresRv:
case JSOp::CallIter:
case JSOp::FunCall:
case JSOp::New:
case JSOp::SuperCall:
case JSOp::SpreadCall:

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

@ -45,7 +45,13 @@ bool jit::EliminateBoundsChecks(MIRGenerator* mir, MIRGraph& graph) {
MWasmBoundsCheck* bc = def->toWasmBoundsCheck();
MDefinition* addr = bc->index();
// Eliminate constant-address bounds checks to addresses below
// We only support bounds check elimination on wasm memory, not
// tables. See bug 1625891.
if (!bc->isMemory()) {
continue;
}
// Eliminate constant-address memory bounds checks to addresses below
// the heap minimum.
//
// The payload of the MConstant will be Double if the constant

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

@ -522,11 +522,7 @@ void CodeGeneratorShared::encode(LRecoverInfo* recover) {
"Encoding LRecoverInfo %p (frameCount %u, instructions %u)",
(void*)recover, recover->mir()->frameCount(), numInstructions);
MResumePoint::Mode mode = recover->mir()->mode();
MOZ_ASSERT(mode != MResumePoint::Outer);
bool resumeAfter = (mode == MResumePoint::ResumeAfter);
RecoverOffset offset = recovers_.startRecover(numInstructions, resumeAfter);
RecoverOffset offset = recovers_.startRecover(numInstructions);
for (MNode* insn : *recover) {
recovers_.writeInstruction(insn);

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

@ -3157,6 +3157,20 @@ class LWasmDerivedPointer : public LInstructionHelper<1, 1, 0> {
size_t offset() { return mirRaw()->toWasmDerivedPointer()->offset(); }
};
class LWasmDerivedIndexPointer : public LInstructionHelper<1, 2, 0> {
public:
LIR_HEADER(WasmDerivedIndexPointer);
explicit LWasmDerivedIndexPointer(const LAllocation& base,
const LAllocation& index)
: LInstructionHelper(classOpcode) {
setOperand(0, base);
setOperand(1, index);
}
const LAllocation* base() { return getOperand(0); }
const LAllocation* index() { return getOperand(1); }
Scale scale() { return mirRaw()->toWasmDerivedIndexPointer()->scale(); }
};
class LWasmParameterI64 : public LInstructionHelper<INT64_PIECES, 0, 0> {
public:
LIR_HEADER(WasmParameterI64);

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

@ -1965,8 +1965,7 @@ bool ExpressionDecompiler::decompilePC(jsbytecode* pc, uint8_t defIndex) {
return write("new.target");
case JSOp::Call:
case JSOp::CallIgnoresRv:
case JSOp::CallIter:
case JSOp::FunCall: {
case JSOp::CallIter: {
uint16_t argc = GET_ARGC(pc);
return decompilePCForStackOperand(pc, -int32_t(argc + 2)) &&
write(argc ? "(...)" : "()");

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

@ -348,7 +348,7 @@ MOZ_ALWAYS_INLINE unsigned StackUses(jsbytecode* pc) {
/* stack: fun, this, [argc arguments] */
MOZ_ASSERT(op == JSOp::Call || op == JSOp::CallIgnoresRv ||
op == JSOp::Eval || op == JSOp::CallIter ||
op == JSOp::StrictEval || op == JSOp::FunCall);
op == JSOp::StrictEval);
return 2 + GET_ARGC(pc);
}
}

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

@ -3255,8 +3255,7 @@ static MOZ_NEVER_INLINE JS_HAZ_JSNATIVE_CALLER bool Interpret(JSContext* cx,
CASE(Call)
CASE(CallIgnoresRv)
CASE(CallIter)
CASE(SuperCall)
CASE(FunCall) {
CASE(SuperCall) {
static_assert(JSOpLength_Call == JSOpLength_New,
"call and new must be the same size");
static_assert(JSOpLength_Call == JSOpLength_CallIgnoresRv,
@ -3265,8 +3264,6 @@ static MOZ_NEVER_INLINE JS_HAZ_JSNATIVE_CALLER bool Interpret(JSContext* cx,
"call and calliter must be the same size");
static_assert(JSOpLength_Call == JSOpLength_SuperCall,
"call and supercall must be the same size");
static_assert(JSOpLength_Call == JSOpLength_FunCall,
"call and funcall must be the same size");
if (REGS.fp()->hasPushedGeckoProfilerFrame()) {
cx->geckoProfiler().updatePC(cx, script, REGS.pc);

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

@ -1739,9 +1739,6 @@
* iterable") rather than `JSMSG_NOT_FUNCTION` ("x[Symbol.iterator] is not
* a function"). The `argc` operand must be 0 for this variation.
*
* `JSOp::FunCall` hints to the VM that the callee is likely
* `Function.prototype.call`.
*
* `JSOp::CallIgnoresRv` hints to the VM that the return value is ignored.
* This allows alternate faster implementations to be used that avoid
* unnecesary allocations.
@ -1757,7 +1754,6 @@
*/ \
MACRO(Call, call, NULL, 3, -1, 1, JOF_ARGC|JOF_INVOKE|JOF_IC) \
MACRO(CallIter, call_iter, NULL, 3, -1, 1, JOF_ARGC|JOF_INVOKE|JOF_IC) \
MACRO(FunCall, fun_call, NULL, 3, -1, 1, JOF_ARGC|JOF_INVOKE|JOF_IC) \
MACRO(CallIgnoresRv, call_ignores_rv, NULL, 3, -1, 1, JOF_ARGC|JOF_INVOKE|JOF_IC) \
/*
* Like `JSOp::Call`, but the arguments are provided in an array rather than
@ -3541,13 +3537,14 @@
* a power of two. Use this macro to do so.
*/
#define FOR_EACH_TRAILING_UNUSED_OPCODE(MACRO) \
IF_RECORD_TUPLE(/* empty */, MACRO(225)) \
IF_RECORD_TUPLE(/* empty */, MACRO(226)) \
IF_RECORD_TUPLE(/* empty */, MACRO(227)) \
IF_RECORD_TUPLE(/* empty */, MACRO(228)) \
IF_RECORD_TUPLE(/* empty */, MACRO(229)) \
IF_RECORD_TUPLE(/* empty */, MACRO(230)) \
IF_RECORD_TUPLE(/* empty */, MACRO(231)) \
IF_RECORD_TUPLE(/* empty */, MACRO(232)) \
MACRO(232) \
MACRO(233) \
MACRO(234) \
MACRO(235) \

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

@ -2658,6 +2658,7 @@ class MOZ_STACK_CLASS FunctionValidator : public FunctionValidatorShared {
}
[[nodiscard]] bool writeCall(ParseNode* pn, Op op) {
MOZ_ASSERT(op == Op::Call);
if (!encoder().writeOp(op)) {
return false;
}
@ -2665,6 +2666,7 @@ class MOZ_STACK_CLASS FunctionValidator : public FunctionValidatorShared {
return appendCallSiteLineNumber(pn);
}
[[nodiscard]] bool writeCall(ParseNode* pn, MozOp op) {
MOZ_ASSERT(op == MozOp::OldCallDirect || op == MozOp::OldCallIndirect);
if (!encoder().writeOp(op)) {
return false;
}

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

@ -150,6 +150,16 @@ struct FunctionCall {
size_t stackArgAreaSize;
};
enum class PostBarrierKind {
// Remove an existing store buffer entry if the new value does not require
// one. This is required to preserve invariants with HeapPtr when used for
// movable storage.
Precise,
// Add a store buffer entry if the new value requires it, but do not attempt
// to remove a pre-existing entry.
Imprecise,
};
//////////////////////////////////////////////////////////////////////////////
//
// Wasm baseline compiler proper.
@ -1078,6 +1088,15 @@ struct BaseCompiler final {
Address addressOfGlobalVar(const GlobalDesc& global, RegPtr tmp);
//////////////////////////////////////////////////////////////////////
//
// Table access.
Address addressOfTableField(const TableDesc& table, uint32_t fieldOffset,
RegPtr tls);
void loadTableLength(const TableDesc& table, RegPtr tls, RegI32 length);
void loadTableElements(const TableDesc& table, RegPtr tls, RegPtr elements);
//////////////////////////////////////////////////////////////////////
//
// Heap access.
@ -1239,7 +1258,7 @@ struct BaseCompiler final {
////////////////////////////////////////////////////////////
//
// Object support.
// Barriers support.
// This emits a GC pre-write barrier. The pre-barrier is needed when we
// replace a member field with a new value, and the previous field value
@ -1254,15 +1273,39 @@ struct BaseCompiler final {
// update. This function preserves that register.
void emitPreBarrier(RegPtr valueAddr);
// This frees the register `valueAddr`.
[[nodiscard]] bool emitPostBarrierCall(RegPtr valueAddr);
// This emits a GC post-write barrier. The post-barrier is needed when we
// replace a member field with a new value, the new value is in the nursery,
// and the containing object is a tenured object. The field must then be
// added to the store buffer so that the nursery can be correctly collected.
// The field might belong to an object or be a stack slot or a register or a
// heap allocated value.
//
// For the difference between 'precise' and 'imprecise', look at the
// documentation on PostBarrierKind.
//
// `object` is a pointer to the object that contains the field. It is used, if
// present, to skip adding a store buffer entry when the containing object is
// in the nursery. This register is preserved by this function.
// `valueAddr` is the address of the location that we are writing to. This
// register is consumed by this function.
// `prevValue` is the value that existed in the field before `value` was
// stored. This register is consumed by this function.
// `value` is the value that was stored in the field. This register is
// preserved by this function.
[[nodiscard]] bool emitPostBarrierImprecise(const Maybe<RegRef>& object,
RegPtr valueAddr, RegRef value);
[[nodiscard]] bool emitPostBarrierPrecise(const Maybe<RegRef>& object,
RegPtr valueAddr, RegRef prevValue, RegRef value);
// Emits a store to a JS object pointer at the address valueAddr, which is
// inside the GC cell `object`. Preserves `object` and `value`.
// Emits a store to a JS object pointer at the address `valueAddr`, which is
// inside the GC cell `object`.
//
// Preserves `object` and `value`. Consumes `valueAddr`.
[[nodiscard]] bool emitBarrieredStore(const Maybe<RegRef>& object,
RegPtr valueAddr, RegRef value);
RegPtr valueAddr, RegRef value,
PostBarrierKind kind);
// Emits a store of nullptr to a JS object pointer at the address valueAddr,
// Emits a store of nullptr to a JS object pointer at the address valueAddr.
// Preserves `valueAddr`.
void emitBarrieredClear(RegPtr valueAddr);
@ -1542,6 +1585,10 @@ struct BaseCompiler final {
[[nodiscard]] bool emitTableSet();
[[nodiscard]] bool emitTableSize();
void emitTableBoundsCheck(const TableDesc& table, RegI32 index, RegPtr tls);
[[nodiscard]] bool emitTableGetAnyRef(uint32_t tableIndex);
[[nodiscard]] bool emitTableSetAnyRef(uint32_t tableIndex);
#ifdef ENABLE_WASM_GC
[[nodiscard]] bool emitStructNewWithRtt();
[[nodiscard]] bool emitStructNewDefaultWithRtt();

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

@ -2103,6 +2103,29 @@ Address BaseCompiler::addressOfGlobalVar(const GlobalDesc& global, RegPtr tmp) {
return Address(tmp, globalToTlsOffset);
}
//////////////////////////////////////////////////////////////////////
//
// Table access.
Address BaseCompiler::addressOfTableField(const TableDesc& table,
uint32_t fieldOffset, RegPtr tls) {
uint32_t tableToTlsOffset =
wasm::Instance::offsetOfGlobalArea() + table.globalDataOffset + fieldOffset;
return Address(tls, tableToTlsOffset);
}
void BaseCompiler::loadTableLength(const TableDesc& table, RegPtr tls,
RegI32 length) {
masm.load32(addressOfTableField(table, offsetof(TableInstanceData, length), tls),
length);
}
void BaseCompiler::loadTableElements(const TableDesc& table, RegPtr tls,
RegPtr elements) {
masm.loadPtr(addressOfTableField(table, offsetof(TableInstanceData, elements), tls),
elements);
}
//////////////////////////////////////////////////////////////////////////////
//
// Basic emitters for simple operators.
@ -4267,7 +4290,8 @@ bool BaseCompiler::emitThrow() {
RegRef rv = popRef();
pushPtr(data);
// emitBarrieredStore preserves exn, rv
if (!emitBarrieredStore(Some(exn), valueAddr, rv)) {
if (!emitBarrieredStore(Some(exn), valueAddr, rv,
PostBarrierKind::Imprecise)) {
return false;
}
popPtr(data);
@ -5134,7 +5158,8 @@ bool BaseCompiler::emitSetGlobal() {
}
RegRef rv = popRef();
// emitBarrieredStore preserves rv
if (!emitBarrieredStore(Nothing(), valueAddr, rv)) {
if (!emitBarrieredStore(Nothing(), valueAddr, rv,
PostBarrierKind::Imprecise)) {
return false;
}
freeRef(rv);
@ -5811,12 +5836,21 @@ bool BaseCompiler::emitTableFill() {
}
bool BaseCompiler::emitTableGet() {
uint32_t lineOrBytecode = readCallSiteLineOrBytecode();
uint32_t tableIndex;
Nothing nothing;
if (!iter_.readTableGet(&tableIndex, &nothing)) {
return false;
}
if (deadCode_) {
return true;
}
if (moduleEnv_.tables[tableIndex].elemType.tableRepr() == TableRepr::Ref) {
return emitTableGetAnyRef(tableIndex);
}
pushI32(tableIndex);
// get(index:u32, table:u32) -> AnyRef
return emitInstanceCallOp<uint32_t>(
SASigTableGet, [this](uint32_t* tableIndex) -> bool {
Nothing nothing;
return iter_.readTableGet(tableIndex, &nothing);
});
return emitInstanceCall(lineOrBytecode, SASigTableGetFunc);
}
bool BaseCompiler::emitTableGrow() {
@ -5829,20 +5863,112 @@ bool BaseCompiler::emitTableGrow() {
}
bool BaseCompiler::emitTableSet() {
uint32_t lineOrBytecode = readCallSiteLineOrBytecode();
uint32_t tableIndex;
Nothing nothing;
if (!iter_.readTableSet(&tableIndex, &nothing, &nothing)) {
return false;
}
if (deadCode_) {
return true;
}
if (moduleEnv_.tables[tableIndex].elemType.tableRepr() == TableRepr::Ref) {
return emitTableSetAnyRef(tableIndex);
}
pushI32(tableIndex);
// set(index:u32, value:ref, table:u32) -> void
return emitInstanceCallOp<uint32_t>(
SASigTableSet, [this](uint32_t* tableIndex) -> bool {
Nothing nothing;
return iter_.readTableSet(tableIndex, &nothing, &nothing);
});
return emitInstanceCall(lineOrBytecode, SASigTableSetFunc);
}
bool BaseCompiler::emitTableSize() {
// size(table:u32) -> u32
return emitInstanceCallOp<uint32_t>(SASigTableSize,
[this](uint32_t* tableIndex) -> bool {
return iter_.readTableSize(tableIndex);
});
uint32_t tableIndex;
if (!iter_.readTableSize(&tableIndex)) {
return false;
}
if (deadCode_) {
return true;
}
const TableDesc& table = moduleEnv_.tables[tableIndex];
RegPtr tls = needPtr();
RegI32 length = needI32();
fr.loadTlsPtr(tls);
loadTableLength(table, tls, length);
pushI32(length);
freePtr(tls);
return true;
}
void BaseCompiler::emitTableBoundsCheck(const TableDesc& table, RegI32 index,
RegPtr tls) {
Label ok;
masm.wasmBoundsCheck32(
Assembler::Condition::Below, index,
addressOfTableField(table, offsetof(TableInstanceData, length), tls), &ok);
masm.wasmTrap(wasm::Trap::OutOfBounds, bytecodeOffset());
masm.bind(&ok);
}
bool BaseCompiler::emitTableGetAnyRef(uint32_t tableIndex) {
const TableDesc& table = moduleEnv_.tables[tableIndex];
RegPtr tls = needPtr();
RegPtr elements = needPtr();
RegI32 index = popI32();
fr.loadTlsPtr(tls);
emitTableBoundsCheck(table, index, tls);
loadTableElements(table, tls, elements);
masm.loadPtr(BaseIndex(elements, index, ScalePointer), elements);
pushRef(RegRef(elements));
freeI32(index);
freePtr(tls);
return true;
}
bool BaseCompiler::emitTableSetAnyRef(uint32_t tableIndex) {
const TableDesc& table = moduleEnv_.tables[tableIndex];
// Create temporaries for valueAddr that is not in the prebarrier register
// and can be consumed by the barrier operation
RegPtr valueAddr = RegPtr(PreBarrierReg);
needPtr(valueAddr);
RegPtr tls = needPtr();
RegPtr elements = needPtr();
RegRef value = popRef();
RegI32 index = popI32();
// x86 is one register too short for this operation, shuffle `value` back
// onto the stack until it is needed.
#ifdef JS_CODEGEN_X86
pushRef(value);
#endif
fr.loadTlsPtr(tls);
emitTableBoundsCheck(table, index, tls);
loadTableElements(table, tls, elements);
masm.computeEffectiveAddress(BaseIndex(elements, index, ScalePointer),
valueAddr);
freeI32(index);
freePtr(elements);
freePtr(tls);
#ifdef JS_CODEGEN_X86
value = popRef();
#endif
if (!emitBarrieredStore(Nothing(), valueAddr, value,
PostBarrierKind::Precise)) {
return false;
}
freeRef(value);
return true;
}
//////////////////////////////////////////////////////////////////////////////
@ -5889,48 +6015,35 @@ void BaseCompiler::emitPreBarrier(RegPtr valueAddr) {
masm.bind(&skipBarrier);
}
// This frees the register `valueAddr`.
bool BaseCompiler::emitPostBarrierCall(RegPtr valueAddr) {
bool BaseCompiler::emitPostBarrierImprecise(const Maybe<RegRef>& object,
RegPtr valueAddr, RegRef value) {
uint32_t bytecodeOffset = iter_.lastOpcodeOffset();
// The `valueAddr` is a raw pointer to the cell within some GC object or
// TLS area, and we guarantee that the GC will not run while the
// postbarrier call is active, so push a uintptr_t value.
pushPtr(valueAddr);
return emitInstanceCall(bytecodeOffset, SASigPostBarrier);
}
// Emits a store to a JS object pointer at the address valueAddr, which is
// inside the GC cell `object`. Preserves `object` and `value`.
bool BaseCompiler::emitBarrieredStore(const Maybe<RegRef>& object,
RegPtr valueAddr, RegRef value) {
// TODO/AnyRef-boxing: With boxed immediates and strings, the write
// barrier is going to have to be more complicated.
ASSERT_ANYREF_IS_JSOBJECT;
emitPreBarrier(valueAddr); // Preserves valueAddr
masm.storePtr(value, Address(valueAddr, 0));
Label skipBarrier;
// We must force a sync before the guard so that locals are in a consistent
// location for whether or not the post-barrier call is taken.
sync();
RegRef otherScratch = needRef();
// Emit a guard to skip the post-barrier call if it is not needed.
Label skipBarrier;
RegPtr otherScratch = needPtr();
EmitWasmPostBarrierGuard(masm, object, otherScratch, value, &skipBarrier);
freeRef(otherScratch);
freePtr(otherScratch);
// Push `object` and `value` to preserve them across the call.
if (object) {
pushRef(*object);
}
pushRef(value);
// Consumes valueAddr
if (!emitPostBarrierCall(valueAddr)) {
// The `valueAddr` is a raw pointer to the cell within some GC object or
// TLS area, and we are careful so that the GC will not run while the
// post-barrier call is active, so push a uintptr_t value.
pushPtr(valueAddr);
if (!emitInstanceCall(bytecodeOffset, SASigPostBarrier)) {
return false;
}
// Consume all other operands as they may have been clobbered by the post
// barrier call
// Restore `object` and `value`.
popRef(value);
if (object) {
popRef(*object);
@ -5940,15 +6053,72 @@ bool BaseCompiler::emitBarrieredStore(const Maybe<RegRef>& object,
return true;
}
// Emits a store of nullptr to a JS object pointer at the address valueAddr.
// Preserves `valueAddr`.
bool BaseCompiler::emitPostBarrierPrecise(const Maybe<RegRef>& object,
RegPtr valueAddr, RegRef prevValue, RegRef value) {
uint32_t bytecodeOffset = iter_.lastOpcodeOffset();
// Push `object` and `value` to preserve them across the call.
if (object) {
pushRef(*object);
}
pushRef(value);
// Push the arguments and call the precise post-barrier
pushPtr(valueAddr);
pushRef(prevValue);
if (!emitInstanceCall(bytecodeOffset, SASigPostBarrierPrecise)) {
return false;
}
// Restore `object` and `value`.
popRef(value);
if (object) {
popRef(*object);
}
return true;
}
bool BaseCompiler::emitBarrieredStore(const Maybe<RegRef>& object,
RegPtr valueAddr, RegRef value,
PostBarrierKind kind) {
// TODO/AnyRef-boxing: With boxed immediates and strings, the write
// barrier is going to have to be more complicated.
ASSERT_ANYREF_IS_JSOBJECT;
// The pre-barrier preserves all allocated registers.
emitPreBarrier(valueAddr);
// The precise post-barrier requires the previous value stored in the field,
// in order to know if the previous store buffer entry needs to be removed.
RegRef prevValue;
if (kind == PostBarrierKind::Precise) {
prevValue = needRef();
masm.loadPtr(Address(valueAddr, 0), prevValue);
}
// Store the value
masm.storePtr(value, Address(valueAddr, 0));
// The post-barrier preserves object and value.
if (kind == PostBarrierKind::Precise) {
return emitPostBarrierPrecise(object, valueAddr, prevValue, value);
}
return emitPostBarrierImprecise(object, valueAddr, value);
}
void BaseCompiler::emitBarrieredClear(RegPtr valueAddr) {
// TODO/AnyRef-boxing: With boxed immediates and strings, the write
// barrier is going to have to be more complicated.
ASSERT_ANYREF_IS_JSOBJECT;
emitPreBarrier(valueAddr); // Preserves valueAddr
// The pre-barrier preserves all allocated registers.
emitPreBarrier(valueAddr);
// Store null
masm.storePtr(ImmWord(0), Address(valueAddr, 0));
// No post-barrier is needed, as null does not require a store buffer entry
}
//////////////////////////////////////////////////////////////////////////////
@ -6136,7 +6306,8 @@ bool BaseCompiler::emitGcStructSet(RegRef object, RegPtr data,
pushPtr(data);
// emitBarrieredStore preserves object and value
if (!emitBarrieredStore(Some(object), valueAddr, value.ref())) {
if (!emitBarrieredStore(Some(object), valueAddr, value.ref(),
PostBarrierKind::Imprecise)) {
return false;
}
freeRef(value.ref());
@ -6187,7 +6358,8 @@ bool BaseCompiler::emitGcArraySet(RegRef object, RegPtr data, RegI32 index,
pushI32(index);
// emitBarrieredStore preserves object and value
if (!emitBarrieredStore(Some(object), valueAddr, value.ref())) {
if (!emitBarrieredStore(Some(object), valueAddr, value.ref(),
PostBarrierKind::Imprecise)) {
return false;
}

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

@ -228,11 +228,12 @@ const SymbolicAddressSignature SASigTableFill = {
_FailOnNegI32,
5,
{_PTR, _I32, _RoN, _I32, _I32, _END}};
const SymbolicAddressSignature SASigTableGet = {SymbolicAddress::TableGet,
_RoN,
_FailOnInvalidRef,
3,
{_PTR, _I32, _I32, _END}};
const SymbolicAddressSignature SASigTableGetFunc = {
SymbolicAddress::TableGetFunc,
_RoN,
_FailOnInvalidRef,
3,
{_PTR, _I32, _I32, _END}};
const SymbolicAddressSignature SASigTableGrow = {
SymbolicAddress::TableGrow,
_I32,
@ -245,13 +246,12 @@ const SymbolicAddressSignature SASigTableInit = {
_FailOnNegI32,
6,
{_PTR, _I32, _I32, _I32, _I32, _I32, _END}};
const SymbolicAddressSignature SASigTableSet = {SymbolicAddress::TableSet,
_VOID,
_FailOnNegI32,
4,
{_PTR, _I32, _RoN, _I32, _END}};
const SymbolicAddressSignature SASigTableSize = {
SymbolicAddress::TableSize, _I32, _Infallible, 2, {_PTR, _I32, _END}};
const SymbolicAddressSignature SASigTableSetFunc = {
SymbolicAddress::TableSetFunc,
_VOID,
_FailOnNegI32,
4,
{_PTR, _I32, _RoN, _I32, _END}};
const SymbolicAddressSignature SASigRefFunc = {
SymbolicAddress::RefFunc, _RoN, _FailOnInvalidRef, 2, {_PTR, _I32, _END}};
const SymbolicAddressSignature SASigPreBarrierFiltering = {
@ -262,6 +262,12 @@ const SymbolicAddressSignature SASigPreBarrierFiltering = {
{_PTR, _PTR, _END}};
const SymbolicAddressSignature SASigPostBarrier = {
SymbolicAddress::PostBarrier, _VOID, _Infallible, 2, {_PTR, _PTR, _END}};
const SymbolicAddressSignature SASigPostBarrierPrecise = {
SymbolicAddress::PostBarrierPrecise,
_VOID,
_Infallible,
3,
{_PTR, _PTR, _RoN, _END}};
const SymbolicAddressSignature SASigPostBarrierFiltering = {
SymbolicAddress::PostBarrierFiltering,
_VOID,
@ -1221,22 +1227,18 @@ void* wasm::AddressOf(SymbolicAddress imm, ABIFunctionType* abiType) {
*abiType = Args_Int32_GeneralInt32Int32Int32Int32Int32;
MOZ_ASSERT(*abiType == ToABIType(SASigTableInit));
return FuncCast(Instance::tableInit, *abiType);
case SymbolicAddress::TableGet:
case SymbolicAddress::TableGetFunc:
*abiType = Args_General_GeneralInt32Int32;
MOZ_ASSERT(*abiType == ToABIType(SASigTableGet));
return FuncCast(Instance::tableGet, *abiType);
MOZ_ASSERT(*abiType == ToABIType(SASigTableGetFunc));
return FuncCast(Instance::tableGetFunc, *abiType);
case SymbolicAddress::TableGrow:
*abiType = Args_Int32_GeneralGeneralInt32Int32;
MOZ_ASSERT(*abiType == ToABIType(SASigTableGrow));
return FuncCast(Instance::tableGrow, *abiType);
case SymbolicAddress::TableSet:
case SymbolicAddress::TableSetFunc:
*abiType = Args_Int32_GeneralInt32GeneralInt32;
MOZ_ASSERT(*abiType == ToABIType(SASigTableSet));
return FuncCast(Instance::tableSet, *abiType);
case SymbolicAddress::TableSize:
*abiType = Args_Int32_GeneralInt32;
MOZ_ASSERT(*abiType == ToABIType(SASigTableSize));
return FuncCast(Instance::tableSize, *abiType);
MOZ_ASSERT(*abiType == ToABIType(SASigTableSetFunc));
return FuncCast(Instance::tableSetFunc, *abiType);
case SymbolicAddress::RefFunc:
*abiType = Args_General_GeneralInt32;
MOZ_ASSERT(*abiType == ToABIType(SASigRefFunc));
@ -1245,6 +1247,10 @@ void* wasm::AddressOf(SymbolicAddress imm, ABIFunctionType* abiType) {
*abiType = Args_Int32_GeneralGeneral;
MOZ_ASSERT(*abiType == ToABIType(SASigPostBarrier));
return FuncCast(Instance::postBarrier, *abiType);
case SymbolicAddress::PostBarrierPrecise:
*abiType = Args_Int32_GeneralGeneralGeneral;
MOZ_ASSERT(*abiType == ToABIType(SASigPostBarrierPrecise));
return FuncCast(Instance::postBarrierPrecise, *abiType);
case SymbolicAddress::PreBarrierFiltering:
*abiType = Args_Int32_GeneralGeneral;
MOZ_ASSERT(*abiType == ToABIType(SASigPreBarrierFiltering));
@ -1438,14 +1444,14 @@ bool wasm::NeedsBuiltinThunk(SymbolicAddress sym) {
case SymbolicAddress::TableCopy:
case SymbolicAddress::ElemDrop:
case SymbolicAddress::TableFill:
case SymbolicAddress::TableGet:
case SymbolicAddress::TableGetFunc:
case SymbolicAddress::TableGrow:
case SymbolicAddress::TableInit:
case SymbolicAddress::TableSet:
case SymbolicAddress::TableSize:
case SymbolicAddress::TableSetFunc:
case SymbolicAddress::RefFunc:
case SymbolicAddress::PreBarrierFiltering:
case SymbolicAddress::PostBarrier:
case SymbolicAddress::PostBarrierPrecise:
case SymbolicAddress::PostBarrierFiltering:
case SymbolicAddress::StructNew:
#ifdef ENABLE_WASM_EXCEPTIONS

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

@ -112,16 +112,16 @@ enum class SymbolicAddress {
TableCopy,
ElemDrop,
TableFill,
TableGet,
TableGetFunc,
TableGrow,
TableInit,
TableSet,
TableSize,
TableSetFunc,
RefFunc,
RefTest,
RttSub,
PreBarrierFiltering,
PostBarrier,
PostBarrierPrecise,
PostBarrierFiltering,
StructNew,
#if defined(ENABLE_WASM_EXCEPTIONS)
@ -236,14 +236,14 @@ extern const SymbolicAddressSignature SASigMemInitM64;
extern const SymbolicAddressSignature SASigTableCopy;
extern const SymbolicAddressSignature SASigElemDrop;
extern const SymbolicAddressSignature SASigTableFill;
extern const SymbolicAddressSignature SASigTableGet;
extern const SymbolicAddressSignature SASigTableGetFunc;
extern const SymbolicAddressSignature SASigTableGrow;
extern const SymbolicAddressSignature SASigTableInit;
extern const SymbolicAddressSignature SASigTableSet;
extern const SymbolicAddressSignature SASigTableSize;
extern const SymbolicAddressSignature SASigTableSetFunc;
extern const SymbolicAddressSignature SASigRefFunc;
extern const SymbolicAddressSignature SASigPreBarrierFiltering;
extern const SymbolicAddressSignature SASigPostBarrier;
extern const SymbolicAddressSignature SASigPostBarrierPrecise;
extern const SymbolicAddressSignature SASigPostBarrierFiltering;
extern const SymbolicAddressSignature SASigStructNew;
#ifdef ENABLE_WASM_EXCEPTIONS

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

@ -604,7 +604,7 @@ class CalleeDesc {
uint32_t tableFunctionBaseGlobalDataOffset() const {
MOZ_ASSERT(isTable());
return u.table.globalDataOffset_ +
offsetof(TableInstanceData, functionBase);
offsetof(TableInstanceData, elements);
}
TypeIdDesc wasmTableSigId() const {
MOZ_ASSERT(which_ == WasmTable);

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

@ -1578,24 +1578,22 @@ static const char* ThunkedNativeToDescription(SymbolicAddress func) {
return "call to native table.fill function";
case SymbolicAddress::ElemDrop:
return "call to native elem.drop function";
case SymbolicAddress::TableGet:
case SymbolicAddress::TableGetFunc:
return "call to native table.get function";
case SymbolicAddress::TableGrow:
return "call to native table.grow function";
case SymbolicAddress::TableInit:
return "call to native table.init function";
case SymbolicAddress::TableSet:
case SymbolicAddress::TableSetFunc:
return "call to native table.set function";
case SymbolicAddress::TableSize:
return "call to native table.size function";
case SymbolicAddress::RefFunc:
return "call to native ref.func function";
case SymbolicAddress::PreBarrierFiltering:
return "call to native filtering GC prebarrier (in wasm)";
case SymbolicAddress::PostBarrier:
return "call to native GC postbarrier (in wasm)";
case SymbolicAddress::PostBarrierPrecise:
case SymbolicAddress::PostBarrierFiltering:
return "call to native filtering GC postbarrier (in wasm)";
return "call to native GC postbarrier (in wasm)";
case SymbolicAddress::StructNew:
return "call to native struct.new (in wasm)";
#if defined(ENABLE_WASM_EXCEPTIONS)

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