зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to inbound. a=merge CLOSED TREE
This commit is contained in:
Коммит
775c1e3f87
|
@ -1,5 +1,5 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<blocklist lastupdate="1550866974800" xmlns="http://www.mozilla.org/2006/addons-blocklist">
|
||||
<blocklist lastupdate="1551250023025" xmlns="http://www.mozilla.org/2006/addons-blocklist">
|
||||
<emItems>
|
||||
<emItem blockID="i334" id="{0F827075-B026-42F3-885D-98981EE7B1AE}">
|
||||
<prefs/>
|
||||
|
@ -2512,6 +2512,26 @@
|
|||
<prefs/>
|
||||
<versionRange minVersion="0" maxVersion="*" severity="3"/>
|
||||
</emItem>
|
||||
<emItem blockID="5b3fe8de-6d05-4d95-a6d2-cd5695f1b0c0" id="{157cd8f9-48f0-43a1-9bcf-c4316753e083}">
|
||||
<prefs/>
|
||||
<versionRange minVersion="0" maxVersion="*" severity="3"/>
|
||||
</emItem>
|
||||
<emItem blockID="32227de6-a7bf-454c-bf44-4478ddd96abe" id="{4603d01d-ae80-4653-9288-d5ef98b99a17}">
|
||||
<prefs/>
|
||||
<versionRange minVersion="0" maxVersion="*" severity="3"/>
|
||||
</emItem>
|
||||
<emItem blockID="ec121e9e-d56d-436b-bb2d-735fdcff3c03" id="/^((\{8387ccbe-b9ac-438d-b049-c86b30a6dacb\})|(\{2ef58672-740c-46bd-a50d-b9880986b574\})|(\{7ff51e81-f4b1-4682-9f45-43a771d80748\})|(\{ecb03616-f3c2-4580-99dd-6a233047abdd\})|(\{850be3a2-ca5f-47ad-838c-fe39b006e0da\})|(\{df9f6ab1-c82c-41d4-85ce-86dcfe839ce9\})|(\{a59679da-f097-4db4-b2bc-6ad7b645e127\}))$/">
|
||||
<prefs/>
|
||||
<versionRange minVersion="0" maxVersion="*" severity="3"/>
|
||||
</emItem>
|
||||
<emItem blockID="7bb234b0-cfda-4a23-bf02-9c82fb3500a3" id="{9d7cfde2-39ae-11e9-bde0-02427e2eba50}">
|
||||
<prefs/>
|
||||
<versionRange minVersion="0" maxVersion="*" severity="3"/>
|
||||
</emItem>
|
||||
<emItem blockID="37252271-9e38-46a9-b23a-2b6d7048c0db" id="/^((\{e0686c32-99b4-44d8-972f-88bf08b68f88\})|(\{b2225e4c-9d1d-472b-8aeb-5ff203bcff9a\}))$/">
|
||||
<prefs/>
|
||||
<versionRange minVersion="0" maxVersion="*" severity="3"/>
|
||||
</emItem>
|
||||
</emItems>
|
||||
<pluginItems>
|
||||
<pluginItem blockID="p332">
|
||||
|
|
|
@ -93,8 +93,9 @@ var tabPreviewPanelHelper = {
|
|||
if (host._prevFocus) {
|
||||
Services.focus.setFocus(host._prevFocus, Ci.nsIFocusManager.FLAG_NOSCROLL);
|
||||
host._prevFocus = null;
|
||||
} else
|
||||
} else {
|
||||
gBrowser.selectedBrowser.focus();
|
||||
}
|
||||
|
||||
if (host.tabToSelect) {
|
||||
gBrowser.selectedTab = host.tabToSelect;
|
||||
|
|
|
@ -517,9 +517,9 @@ var FullScreen = {
|
|||
// toggles chrome when moving mouse to the top, it doesn't go away again.
|
||||
if (aEvent.type == "popupshown" && !FullScreen._isChromeCollapsed &&
|
||||
aEvent.target.localName != "tooltip" && aEvent.target.localName != "window" &&
|
||||
aEvent.target.getAttribute("nopreventnavboxhide") != "true")
|
||||
aEvent.target.getAttribute("nopreventnavboxhide") != "true") {
|
||||
FullScreen._isPopupOpen = true;
|
||||
else if (aEvent.type == "popuphidden" && aEvent.target.localName != "tooltip" &&
|
||||
} else if (aEvent.type == "popuphidden" && aEvent.target.localName != "tooltip" &&
|
||||
aEvent.target.localName != "window") {
|
||||
FullScreen._isPopupOpen = false;
|
||||
// Try again to hide toolbar when we close the popup.
|
||||
|
|
|
@ -794,9 +794,9 @@ var BookmarksEventHandler = {
|
|||
// Check whether the tooltipNode is a Places node.
|
||||
// In such a case use it, otherwise check for targetURI attribute.
|
||||
var tooltipNode = aDocument.tooltipNode;
|
||||
if (tooltipNode._placesNode)
|
||||
if (tooltipNode._placesNode) {
|
||||
node = tooltipNode._placesNode;
|
||||
else {
|
||||
} else {
|
||||
// This is a static non-Places node.
|
||||
targetURI = tooltipNode.getAttribute("targetURI");
|
||||
}
|
||||
|
|
|
@ -2791,8 +2791,9 @@ function UpdateUrlbarSearchSplitterState() {
|
|||
splitter.className = "chromeclass-toolbar-additional";
|
||||
}
|
||||
urlbar.parentNode.insertBefore(splitter, ibefore);
|
||||
} else if (splitter)
|
||||
} else if (splitter) {
|
||||
splitter.remove();
|
||||
}
|
||||
}
|
||||
|
||||
function UpdatePageProxyState() {
|
||||
|
@ -3970,9 +3971,9 @@ const BrowserSearch = {
|
|||
get icon() { return browser.mIconURL; },
|
||||
});
|
||||
|
||||
if (hidden)
|
||||
if (hidden) {
|
||||
browser.hiddenEngines = engines;
|
||||
else {
|
||||
} else {
|
||||
browser.engines = engines;
|
||||
if (browser == gBrowser.selectedBrowser)
|
||||
this.updateOpenSearchBadge();
|
||||
|
@ -5406,9 +5407,9 @@ nsBrowserAccess.prototype = {
|
|||
let win, needToFocusWin;
|
||||
|
||||
// try the current window. if we're in a popup, fall back on the most recent browser window
|
||||
if (window.toolbar.visible)
|
||||
if (window.toolbar.visible) {
|
||||
win = window;
|
||||
else {
|
||||
} else {
|
||||
win = BrowserWindowTracker.getTopWindow({private: aIsPrivate});
|
||||
needToFocusWin = true;
|
||||
}
|
||||
|
|
|
@ -479,9 +479,9 @@ async function makeGeneralTab(metaViewRows, docInfo) {
|
|||
let length = metaViewRows.length;
|
||||
|
||||
var metaGroup = document.getElementById("metaTags");
|
||||
if (!length)
|
||||
if (!length) {
|
||||
metaGroup.style.visibility = "hidden";
|
||||
else {
|
||||
} else {
|
||||
document.l10n.setAttributes(document.getElementById("metaTagsCaption"),
|
||||
"general-meta-tags", {"tags": length});
|
||||
|
||||
|
@ -916,19 +916,20 @@ function makeBlockImage(url) {
|
|||
|
||||
var checkbox = document.getElementById("blockImage");
|
||||
var imagePref = Services.prefs.getIntPref("permissions.default.image");
|
||||
if (!(/^https?:/.test(url)) || imagePref == 2)
|
||||
if (!(/^https?:/.test(url)) || imagePref == 2) {
|
||||
// We can't block the images from this host because either is is not
|
||||
// for http(s) or we don't load images at all
|
||||
checkbox.hidden = true;
|
||||
else {
|
||||
} else {
|
||||
var uri = Services.io.newURI(url);
|
||||
if (uri.host) {
|
||||
checkbox.hidden = false;
|
||||
document.l10n.setAttributes(checkbox, "media-block-image", {"website": uri.host});
|
||||
var perm = permissionManager.testPermission(uri, "image");
|
||||
checkbox.checked = perm == nsIPermissionManager.DENY_ACTION;
|
||||
} else
|
||||
} else {
|
||||
checkbox.hidden = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -965,8 +966,9 @@ function setItemValue(id, value) {
|
|||
if (value) {
|
||||
item.parentNode.collapsed = false;
|
||||
item.value = value;
|
||||
} else
|
||||
} else {
|
||||
item.parentNode.collapsed = true;
|
||||
}
|
||||
}
|
||||
|
||||
function formatNumber(number) {
|
||||
|
|
|
@ -38,13 +38,15 @@ function onLoadPermission(uri, principal) {
|
|||
var hostText = document.getElementById("hostText");
|
||||
hostText.value = gPermURI.displayPrePath;
|
||||
|
||||
for (var i of gPermissions)
|
||||
for (var i of gPermissions) {
|
||||
initRow(i);
|
||||
}
|
||||
Services.obs.addObserver(permissionObserver, "perm-changed");
|
||||
onUnloadRegistry.push(onUnloadPermission);
|
||||
permTab.hidden = false;
|
||||
} else
|
||||
} else {
|
||||
permTab.hidden = true;
|
||||
}
|
||||
}
|
||||
|
||||
function onUnloadPermission() {
|
||||
|
|
|
@ -238,8 +238,9 @@ function securityOnLoad(uri, windowInfo) {
|
|||
if (info.cert) {
|
||||
security._cert = info.cert;
|
||||
viewCert.collapsed = false;
|
||||
} else
|
||||
} else {
|
||||
viewCert.collapsed = true;
|
||||
}
|
||||
|
||||
/* Set Privacy & History section text */
|
||||
|
||||
|
@ -316,9 +317,8 @@ function setText(id, value) {
|
|||
return;
|
||||
if (element.localName == "textbox" || element.localName == "label")
|
||||
element.value = value;
|
||||
else {
|
||||
else
|
||||
element.textContent = value;
|
||||
}
|
||||
}
|
||||
|
||||
function viewCertHelper(parent, cert) {
|
||||
|
|
|
@ -172,9 +172,10 @@ function checkMenuItem(actualItem, actualEnabled, expectedItem, expectedEnabled,
|
|||
"checking item #" + index / 2 + " (" + expectedItem + ") has checked attr");
|
||||
is(actualEnabled.disabled, expectedEnabled.disabled,
|
||||
"checking item #" + index / 2 + " (" + expectedItem + ") has disabled attr");
|
||||
} else if (expectedEnabled != null)
|
||||
} else if (expectedEnabled != null) {
|
||||
is(actualEnabled, expectedEnabled,
|
||||
"checking item #" + index / 2 + " (" + expectedItem + ") enabled state");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -277,9 +277,9 @@ var gTests = [
|
|||
let Perms = Services.perms;
|
||||
let uri = gBrowser.selectedBrowser.documentURI;
|
||||
let devicePerms = Perms.testExactPermission(uri, aDevice);
|
||||
if (aExpected === undefined)
|
||||
if (aExpected === undefined) {
|
||||
is(devicePerms, Perms.UNKNOWN_ACTION, "no " + aDevice + " persistent permissions");
|
||||
else {
|
||||
} else {
|
||||
is(devicePerms, aExpected ? Perms.ALLOW_ACTION : Perms.DENY_ACTION,
|
||||
aDevice + " persistently " + (aExpected ? "allowed" : "denied"));
|
||||
}
|
||||
|
|
|
@ -389,31 +389,33 @@ nsBrowserContentHandler.prototype = {
|
|||
chromeParam == "chrome://browser/content/preferences/preferences.xul") {
|
||||
openPreferences(cmdLine, {origin: "commandLineLegacy"});
|
||||
cmdLine.preventDefault = true;
|
||||
} else try {
|
||||
let resolvedURI = resolveURIInternal(cmdLine, chromeParam);
|
||||
let isLocal = uri => {
|
||||
let localSchemes = new Set(["chrome", "file", "resource"]);
|
||||
if (uri instanceof Ci.nsINestedURI) {
|
||||
uri = uri.QueryInterface(Ci.nsINestedURI).innerMostURI;
|
||||
} else {
|
||||
try {
|
||||
let resolvedURI = resolveURIInternal(cmdLine, chromeParam);
|
||||
let isLocal = uri => {
|
||||
let localSchemes = new Set(["chrome", "file", "resource"]);
|
||||
if (uri instanceof Ci.nsINestedURI) {
|
||||
uri = uri.QueryInterface(Ci.nsINestedURI).innerMostURI;
|
||||
}
|
||||
return localSchemes.has(uri.scheme);
|
||||
};
|
||||
if (isLocal(resolvedURI)) {
|
||||
// If the URI is local, we are sure it won't wrongly inherit chrome privs
|
||||
let features = "chrome,dialog=no,all" + this.getFeatures(cmdLine);
|
||||
// Provide 1 null argument, as openWindow has a different behavior
|
||||
// when the arg count is 0.
|
||||
let argArray = Cc["@mozilla.org/array;1"]
|
||||
.createInstance(Ci.nsIMutableArray);
|
||||
argArray.appendElement(null);
|
||||
Services.ww.openWindow(null, resolvedURI.spec, "_blank", features, argArray);
|
||||
cmdLine.preventDefault = true;
|
||||
} else {
|
||||
dump("*** Preventing load of web URI as chrome\n");
|
||||
dump(" If you're trying to load a webpage, do not pass --chrome.\n");
|
||||
}
|
||||
return localSchemes.has(uri.scheme);
|
||||
};
|
||||
if (isLocal(resolvedURI)) {
|
||||
// If the URI is local, we are sure it won't wrongly inherit chrome privs
|
||||
let features = "chrome,dialog=no,all" + this.getFeatures(cmdLine);
|
||||
// Provide 1 null argument, as openWindow has a different behavior
|
||||
// when the arg count is 0.
|
||||
let argArray = Cc["@mozilla.org/array;1"]
|
||||
.createInstance(Ci.nsIMutableArray);
|
||||
argArray.appendElement(null);
|
||||
Services.ww.openWindow(null, resolvedURI.spec, "_blank", features, argArray);
|
||||
cmdLine.preventDefault = true;
|
||||
} else {
|
||||
dump("*** Preventing load of web URI as chrome\n");
|
||||
dump(" If you're trying to load a webpage, do not pass --chrome.\n");
|
||||
} catch (e) {
|
||||
Cu.reportError(e);
|
||||
}
|
||||
} catch (e) {
|
||||
Cu.reportError(e);
|
||||
}
|
||||
}
|
||||
if (cmdLine.handleFlag("preferences", false)) {
|
||||
|
|
|
@ -18,7 +18,7 @@ add_task(async function() {
|
|||
ok(!navbar.hasAttribute("overflowing"), "Should start with a non-overflowing toolbar.");
|
||||
window.resizeTo(400, window.outerHeight);
|
||||
|
||||
await waitForCondition(() => navbar.hasAttribute("overflowing"));
|
||||
await TestUtils.waitForCondition(() => navbar.hasAttribute("overflowing"));
|
||||
ok(navbar.hasAttribute("overflowing"), "Should have an overflowing toolbar.");
|
||||
|
||||
let chevron = document.getElementById("nav-bar-overflow-button");
|
||||
|
@ -61,7 +61,7 @@ add_task(async function() {
|
|||
CustomizableUI.reset();
|
||||
|
||||
// In some cases, it can take a tick for the navbar to overflow again. Wait for it:
|
||||
await waitForCondition(() => navbar.hasAttribute("overflowing"));
|
||||
await TestUtils.waitForCondition(() => navbar.hasAttribute("overflowing"));
|
||||
ok(navbar.hasAttribute("overflowing"), "Should have an overflowing toolbar.");
|
||||
|
||||
sidebarButtonPlacement = CustomizableUI.getPlacementOfWidget("sidebar-button");
|
||||
|
|
|
@ -57,7 +57,7 @@ skip-if = os == 'linux'
|
|||
[browser_ext_browserAction_pageAction_icon.js]
|
||||
[browser_ext_browserAction_pageAction_icon_permissions.js]
|
||||
[browser_ext_browserAction_popup.js]
|
||||
skip-if = (debug && os == 'linux' && bits == 32) || (os == 'win' && !debug) # Bug 1313372, win: Bug 1285500
|
||||
skip-if = (debug && os == 'linux' && bits == 32) # Bug 1313372
|
||||
[browser_ext_browserAction_popup_port.js]
|
||||
[browser_ext_browserAction_popup_preload.js]
|
||||
skip-if = (os == 'win' && !debug) || (verify && debug && (os == 'mac')) # bug 1352668
|
||||
|
|
|
@ -9,7 +9,7 @@ add_task(async function testBrowserActionClickCanceled() {
|
|||
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "http://example.com/");
|
||||
|
||||
// Make sure the mouse isn't hovering over the browserAction widget.
|
||||
EventUtils.synthesizeMouseAtCenter(gURLBar, {type: "mouseover"}, window);
|
||||
EventUtils.synthesizeMouseAtCenter(gURLBar.textbox, {type: "mouseover"}, window);
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
|
@ -87,7 +87,7 @@ add_task(async function testBrowserActionClickCanceled() {
|
|||
|
||||
add_task(async function testBrowserActionDisabled() {
|
||||
// Make sure the mouse isn't hovering over the browserAction widget.
|
||||
EventUtils.synthesizeMouseAtCenter(gURLBar, {type: "mouseover"}, window);
|
||||
EventUtils.synthesizeMouseAtCenter(gURLBar.textbox, {type: "mouseover"}, window);
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
|
@ -195,7 +195,7 @@ add_task(async function testBrowserActionTabPopulation() {
|
|||
await BrowserTestUtils.browserLoaded(win.gBrowser.selectedBrowser);
|
||||
|
||||
// Make sure the mouse isn't hovering over the browserAction widget.
|
||||
EventUtils.synthesizeMouseAtCenter(win.gURLBar, {type: "mouseover"}, win);
|
||||
EventUtils.synthesizeMouseAtCenter(win.gURLBar.textbox, {type: "mouseover"}, win);
|
||||
|
||||
await extension.startup();
|
||||
|
||||
|
@ -231,7 +231,7 @@ add_task(async function testClosePopupDuringPreload() {
|
|||
});
|
||||
|
||||
// Make sure the mouse isn't hovering over the browserAction widget.
|
||||
EventUtils.synthesizeMouseAtCenter(gURLBar, {type: "mouseover"}, window);
|
||||
EventUtils.synthesizeMouseAtCenter(gURLBar.textbox, {type: "mouseover"}, window);
|
||||
|
||||
await extension.startup();
|
||||
|
||||
|
|
|
@ -189,7 +189,7 @@ add_task(async function testBrowserActionTelemetryResults() {
|
|||
await extension.startup();
|
||||
|
||||
// Make sure the mouse isn't hovering over the browserAction widget to start.
|
||||
EventUtils.synthesizeMouseAtCenter(gURLBar, {type: "mouseover"}, window);
|
||||
EventUtils.synthesizeMouseAtCenter(gURLBar.textbox, {type: "mouseover"}, window);
|
||||
|
||||
let widget = getBrowserActionWidget(extension).forWindow(window);
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
async function testExecuteBrowserActionWithOptions(options = {}) {
|
||||
// Make sure the mouse isn't hovering over the browserAction widget.
|
||||
EventUtils.synthesizeMouseAtCenter(gURLBar, {type: "mouseover"}, window);
|
||||
EventUtils.synthesizeMouseAtCenter(gURLBar.textbox, {type: "mouseover"}, window);
|
||||
|
||||
let extensionOptions = {};
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
add_task(async function testIncognitoViews() {
|
||||
// Make sure the mouse isn't hovering over the browserAction widget.
|
||||
EventUtils.synthesizeMouseAtCenter(gURLBar, {type: "mouseover"}, window);
|
||||
EventUtils.synthesizeMouseAtCenter(gURLBar.textbox, {type: "mouseover"}, window);
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
/* vim: set sts=2 sw=2 et tw=80: */
|
||||
"use strict";
|
||||
|
||||
const {UrlbarTestUtils} = ChromeUtils.import("resource://testing-common/UrlbarTestUtils.jsm");
|
||||
|
||||
add_task(async function() {
|
||||
// This keyword needs to be unique to prevent history entries from unrelated
|
||||
// tests from appearing in the suggestions list.
|
||||
|
@ -81,25 +83,22 @@ add_task(async function() {
|
|||
}
|
||||
}
|
||||
|
||||
async function waitForAutocompleteResultAt(index) {
|
||||
let searchString = gURLBar.controller.searchString;
|
||||
await BrowserTestUtils.waitForCondition(
|
||||
() => gURLBar.popup.richlistbox.itemChildren.length > index &&
|
||||
gURLBar.popup.richlistbox.itemChildren[index].getAttribute("ac-text") == searchString,
|
||||
`Waiting for the autocomplete result for "${searchString}" at [${index}] to appear`);
|
||||
async function waitForResult(index, searchString) {
|
||||
let result = await UrlbarTestUtils.getDetailsOfResultAt(window, index);
|
||||
// Ensure the addition is complete, for proper mouse events on the entries.
|
||||
await new Promise(resolve => window.requestIdleCallback(resolve, {timeout: 1000}));
|
||||
return gURLBar.popup.richlistbox.itemChildren[index];
|
||||
return result;
|
||||
}
|
||||
|
||||
async function promiseClickOnItem(item, details) {
|
||||
async function promiseClickOnItem(index, details) {
|
||||
// The Address Bar panel is animated and updated on a timer, thus it may not
|
||||
// yet be listening to events when we try to click on it. This uses a
|
||||
// polling strategy to repeat the click, if it doesn't go through.
|
||||
let clicked = false;
|
||||
item.addEventListener("mousedown", () => { clicked = true; }, {once: true});
|
||||
let element = await UrlbarTestUtils.waitForAutocompleteResultAt(window, index);
|
||||
element.addEventListener("mousedown", () => { clicked = true; }, {once: true});
|
||||
while (!clicked) {
|
||||
EventUtils.synthesizeMouseAtCenter(item, details);
|
||||
EventUtils.synthesizeMouseAtCenter(element, details);
|
||||
await new Promise(r => window.requestIdleCallback(r, {timeout: 1000}));
|
||||
}
|
||||
}
|
||||
|
@ -111,7 +110,7 @@ add_task(async function() {
|
|||
EventUtils.sendString(" ");
|
||||
await expectEvent("on-input-started-fired");
|
||||
// Always use a different input at every invokation, so that
|
||||
// waitForAutocompleteResultAt can distinguish different cases.
|
||||
// waitForResult can distinguish different cases.
|
||||
let char = ((inputSessionSerial++) % 10).toString();
|
||||
EventUtils.sendString(char);
|
||||
|
||||
|
@ -187,27 +186,25 @@ add_task(async function() {
|
|||
}
|
||||
|
||||
let text = await startInputSession();
|
||||
await waitForAutocompleteResultAt(0);
|
||||
let result = await waitForResult(0);
|
||||
|
||||
let item = gURLBar.popup.richlistbox.itemChildren[0];
|
||||
Assert.equal(result.displayed.title, expectedText,
|
||||
`Expected heuristic result to have title: "${expectedText}".`);
|
||||
|
||||
is(item.getAttribute("title"), expectedText,
|
||||
`Expected heuristic result to have title: "${expectedText}".`);
|
||||
|
||||
is(item.getAttribute("displayurl"), `${keyword} ${text}`,
|
||||
`Expected heuristic result to have displayurl: "${keyword} ${text}".`);
|
||||
Assert.equal(result.displayed.action, `${keyword} ${text}`,
|
||||
`Expected heuristic result to have displayurl: "${keyword} ${text}".`);
|
||||
|
||||
let promiseEvent = expectEvent("on-input-entered-fired", {
|
||||
text,
|
||||
disposition: "currentTab",
|
||||
});
|
||||
await promiseClickOnItem(item, {});
|
||||
await promiseClickOnItem(0, {});
|
||||
await promiseEvent;
|
||||
}
|
||||
|
||||
async function testDisposition(suggestionIndex, expectedDisposition, expectedText) {
|
||||
await startInputSession();
|
||||
await waitForAutocompleteResultAt(suggestionIndex);
|
||||
await waitForResult(suggestionIndex);
|
||||
|
||||
// Select the suggestion.
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown", {repeat: suggestionIndex});
|
||||
|
@ -217,13 +214,12 @@ add_task(async function() {
|
|||
disposition: expectedDisposition,
|
||||
});
|
||||
|
||||
let item = gURLBar.popup.richlistbox.itemChildren[suggestionIndex];
|
||||
if (expectedDisposition == "currentTab") {
|
||||
await promiseClickOnItem(item, {});
|
||||
await promiseClickOnItem(suggestionIndex, {});
|
||||
} else if (expectedDisposition == "newForegroundTab") {
|
||||
await promiseClickOnItem(item, {accelKey: true});
|
||||
await promiseClickOnItem(suggestionIndex, {accelKey: true});
|
||||
} else if (expectedDisposition == "newBackgroundTab") {
|
||||
await promiseClickOnItem(item, {shiftKey: true, accelKey: true});
|
||||
await promiseClickOnItem(suggestionIndex, {shiftKey: true, accelKey: true});
|
||||
}
|
||||
await promiseEvent;
|
||||
}
|
||||
|
@ -232,33 +228,33 @@ add_task(async function() {
|
|||
extension.sendMessage("set-synchronous", {synchronous: false});
|
||||
await extension.awaitMessage("set-synchronous-set");
|
||||
|
||||
function expectSuggestion({content, description}, index) {
|
||||
let item = gURLBar.popup.richlistbox.itemChildren[index + 1]; // Skip the heuristic result.
|
||||
|
||||
ok(!!item, "Expected item to exist");
|
||||
is(item.getAttribute("title"), description,
|
||||
`Expected suggestion to have title: "${description}".`);
|
||||
|
||||
is(item.getAttribute("displayurl"), `${keyword} ${content}`,
|
||||
`Expected suggestion to have displayurl: "${keyword} ${content}".`);
|
||||
}
|
||||
|
||||
let text = await startInputSession();
|
||||
// Even if the results are generated asynchronously,
|
||||
// the heuristic result should always be present.
|
||||
await waitForAutocompleteResultAt(0);
|
||||
if (!UrlbarPrefs.get("quantumbar")) {
|
||||
// TODO Bug 1530338: We can't yet wait for a specific result for the
|
||||
// quantumbar. Therefore we just skip this for now.
|
||||
await waitForResult(0);
|
||||
}
|
||||
|
||||
extension.sendMessage(info.test);
|
||||
await extension.awaitMessage("test-ready");
|
||||
|
||||
await waitForAutocompleteResultAt(info.suggestions.length - 1);
|
||||
info.suggestions.forEach(expectSuggestion);
|
||||
await waitForResult(info.suggestions.length - 1);
|
||||
// Skip the heuristic result.
|
||||
let index = 1;
|
||||
for (let {content, description} of info.suggestions) {
|
||||
let item = await UrlbarTestUtils.getDetailsOfResultAt(window, index);
|
||||
Assert.equal(item.displayed.title, description,
|
||||
`Expected suggestion to have title: "${description}".`);
|
||||
Assert.equal(item.displayed.action, `${keyword} ${content}`,
|
||||
`Expected suggestion to have displayurl: "${keyword} ${content}".`);
|
||||
index++;
|
||||
}
|
||||
|
||||
let promiseEvent = expectEvent("on-input-entered-fired", {
|
||||
text,
|
||||
disposition: "currentTab",
|
||||
});
|
||||
await promiseClickOnItem(gURLBar.popup.richlistbox.itemChildren[0], {});
|
||||
await promiseClickOnItem(0, {});
|
||||
await promiseEvent;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,13 +2,12 @@
|
|||
/* vim: set sts=2 sw=2 et tw=80: */
|
||||
"use strict";
|
||||
|
||||
async function testIncognito(incognitoOverride) {
|
||||
add_task(async function test_sidebarAction_not_allowed() {
|
||||
SpecialPowers.pushPrefEnv({set: [
|
||||
["extensions.allowPrivateBrowsingByDefault", false],
|
||||
]});
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
incognitoOverride,
|
||||
manifest: {
|
||||
sidebar_action: {
|
||||
default_panel: "sidebar.html",
|
||||
|
@ -18,40 +17,40 @@ async function testIncognito(incognitoOverride) {
|
|||
browser.test.onMessage.addListener(async pbw => {
|
||||
await browser.test.assertRejects(browser.sidebarAction.setTitle({
|
||||
windowId: pbw.windowId, title: "test",
|
||||
}), /Invalid window ID/, "should not be able to set title");
|
||||
}), /Invalid window ID/, "should not be able to set title with windowId");
|
||||
await browser.test.assertRejects(browser.sidebarAction.setTitle({
|
||||
tabId: pbw.tabId, title: "test",
|
||||
}), /Invalid tab ID/, "should not be able to set title");
|
||||
await browser.test.assertRejects(browser.sidebarAction.getTitle({
|
||||
windowId: pbw.windowId,
|
||||
}), /Invalid window ID/, "should not be able to get title");
|
||||
}), /Invalid window ID/, "should not be able to get title with windowId");
|
||||
await browser.test.assertRejects(browser.sidebarAction.getTitle({
|
||||
tabId: pbw.tabId,
|
||||
}), /Invalid tab ID/, "should not be able to get title");
|
||||
}), /Invalid tab ID/, "should not be able to get title with tabId");
|
||||
|
||||
await browser.test.assertRejects(browser.sidebarAction.setIcon({
|
||||
windowId: pbw.windowId, path: "test",
|
||||
}), /Invalid window ID/, "should not be able to set icon");
|
||||
}), /Invalid window ID/, "should not be able to set icon with windowId");
|
||||
await browser.test.assertRejects(browser.sidebarAction.setIcon({
|
||||
tabId: pbw.tabId, path: "test",
|
||||
}), /Invalid tab ID/, "should not be able to set icon");
|
||||
}), /Invalid tab ID/, "should not be able to set icon with tabId");
|
||||
|
||||
await browser.test.assertRejects(browser.sidebarAction.setPanel({
|
||||
windowId: pbw.windowId, panel: "test",
|
||||
}), /Invalid window ID/, "should not be able to set panel");
|
||||
}), /Invalid window ID/, "should not be able to set panel with windowId");
|
||||
await browser.test.assertRejects(browser.sidebarAction.setPanel({
|
||||
tabId: pbw.tabId, panel: "test",
|
||||
}), /Invalid tab ID/, "should not be able to set panel");
|
||||
}), /Invalid tab ID/, "should not be able to set panel with tabId");
|
||||
await browser.test.assertRejects(browser.sidebarAction.getPanel({
|
||||
windowId: pbw.windowId,
|
||||
}), /Invalid window ID/, "should not be able to get panel");
|
||||
}), /Invalid window ID/, "should not be able to get panel with windowId");
|
||||
await browser.test.assertRejects(browser.sidebarAction.getPanel({
|
||||
tabId: pbw.tabId,
|
||||
}), /Invalid tab ID/, "should not be able to get panel");
|
||||
}), /Invalid tab ID/, "should not be able to get panel with tabId");
|
||||
|
||||
await browser.test.assertRejects(browser.sidebarAction.isOpen({
|
||||
windowId: pbw.windowId,
|
||||
}), /Invalid window ID/, "should not be able to determine openness");
|
||||
}), /Invalid window ID/, "should not be able to determine openness with windowId");
|
||||
|
||||
browser.test.notifyPass("pass");
|
||||
});
|
||||
|
@ -81,26 +80,14 @@ async function testIncognito(incognitoOverride) {
|
|||
let sidebarID = `${makeWidgetId(extension.id)}-sidebar-action`;
|
||||
ok(SidebarUI.sidebars.has(sidebarID), "sidebar exists in non-private window");
|
||||
|
||||
let winData = await getIncognitoWindow("about:blank");
|
||||
let winData = await getIncognitoWindow();
|
||||
|
||||
let hasSidebar = winData.win.SidebarUI.sidebars.has(sidebarID);
|
||||
if (incognitoOverride == "spanning") {
|
||||
ok(hasSidebar, "sidebar exists in private window");
|
||||
} else {
|
||||
ok(!hasSidebar, "sidebar does not exist in private window");
|
||||
// Test API access to private window data.
|
||||
extension.sendMessage(winData.details);
|
||||
await extension.awaitFinish("pass");
|
||||
}
|
||||
ok(!hasSidebar, "sidebar does not exist in private window");
|
||||
// Test API access to private window data.
|
||||
extension.sendMessage(winData.details);
|
||||
await extension.awaitFinish("pass");
|
||||
|
||||
await BrowserTestUtils.closeWindow(winData.win);
|
||||
await extension.unload();
|
||||
}
|
||||
|
||||
add_task(async function test_sidebarAction_not_allowed() {
|
||||
await testIncognito();
|
||||
});
|
||||
|
||||
add_task(async function test_sidebarAction_allowed() {
|
||||
await testIncognito("spanning");
|
||||
});
|
||||
|
|
|
@ -672,7 +672,7 @@ async function startIncognitoMonitorExtension() {
|
|||
return extension;
|
||||
}
|
||||
|
||||
async function getIncognitoWindow(url) {
|
||||
async function getIncognitoWindow(url = "about:privatebrowsing") {
|
||||
// Since events will be limited based on incognito, we need a
|
||||
// spanning extension to get the tab id so we can test access failure.
|
||||
|
||||
|
|
|
@ -751,8 +751,9 @@ var PlacesUIUtils = {
|
|||
// Use (no title) for non-standard URIs (data:, javascript:, ...)
|
||||
title = "";
|
||||
}
|
||||
} else
|
||||
} else {
|
||||
title = aNode.title;
|
||||
}
|
||||
|
||||
return title || this.getString("noTitle");
|
||||
},
|
||||
|
|
|
@ -369,8 +369,9 @@ PlacesViewBase.prototype = {
|
|||
}
|
||||
|
||||
this._domNodes.set(aPlacesNode, popup);
|
||||
} else
|
||||
} else {
|
||||
throw "Unexpected node";
|
||||
}
|
||||
|
||||
element.setAttribute("label", PlacesUIUtils.getBestTitle(aPlacesNode));
|
||||
|
||||
|
@ -1573,9 +1574,9 @@ PlacesToolbar.prototype = {
|
|||
halfInd = Math.ceil(halfInd);
|
||||
translateX = 0 - this._rootElt.getBoundingClientRect().right - halfInd;
|
||||
if (this._rootElt.firstElementChild) {
|
||||
if (dropPoint.beforeIndex == -1)
|
||||
if (dropPoint.beforeIndex == -1) {
|
||||
translateX += this._rootElt.lastElementChild.getBoundingClientRect().left;
|
||||
else {
|
||||
} else {
|
||||
translateX += this._rootElt.children[dropPoint.beforeIndex]
|
||||
.getBoundingClientRect().right;
|
||||
}
|
||||
|
@ -1585,9 +1586,9 @@ PlacesToolbar.prototype = {
|
|||
translateX = 0 - this._rootElt.getBoundingClientRect().left +
|
||||
halfInd;
|
||||
if (this._rootElt.firstElementChild) {
|
||||
if (dropPoint.beforeIndex == -1)
|
||||
if (dropPoint.beforeIndex == -1) {
|
||||
translateX += this._rootElt.lastElementChild.getBoundingClientRect().right;
|
||||
else {
|
||||
} else {
|
||||
translateX += this._rootElt.children[dropPoint.beforeIndex]
|
||||
.getBoundingClientRect().left;
|
||||
}
|
||||
|
|
|
@ -443,8 +443,9 @@
|
|||
elt = elt.nextElementSibling;
|
||||
newMarginTop = elt ? elt.screenY - this._scrollBox.screenY :
|
||||
scrollbox.height;
|
||||
} else if (scrollDir == 1)
|
||||
} else if (scrollDir == 1) {
|
||||
newMarginTop = scrollbox.height;
|
||||
}
|
||||
|
||||
// Set the new marginTop based on arrowscrollbox.
|
||||
newMarginTop += scrollbox.y - this._scrollBox.boxObject.y;
|
||||
|
|
|
@ -460,9 +460,9 @@
|
|||
for (var i = 0; i < container.childCount; ++i) {
|
||||
var child = container.getChild(i);
|
||||
var childURI = child.uri;
|
||||
if (childURI == placeURI)
|
||||
if (childURI == placeURI) {
|
||||
return child;
|
||||
else if (PlacesUtils.nodeIsContainer(child)) {
|
||||
} else if (PlacesUtils.nodeIsContainer(child)) {
|
||||
var nested = findNode(PlacesUtils.asContainer(child), nodesURIChecked);
|
||||
if (nested)
|
||||
return nested;
|
||||
|
@ -481,9 +481,9 @@
|
|||
return;
|
||||
|
||||
var child = findNode(container, []);
|
||||
if (child)
|
||||
if (child) {
|
||||
this.selectNode(child);
|
||||
else {
|
||||
} else {
|
||||
// If the specified child could not be located, clear the selection
|
||||
var selection = this.view.selection;
|
||||
selection.clearSelection();
|
||||
|
|
|
@ -66,8 +66,9 @@ PlacesTreeView.prototype = {
|
|||
// This triggers containerStateChanged which then builds the visible
|
||||
// section.
|
||||
this._rootNode.containerOpen = true;
|
||||
} else
|
||||
} else {
|
||||
this.invalidateContainer(this._rootNode);
|
||||
}
|
||||
|
||||
// "Activate" the sorting column and update commands.
|
||||
this.sortingChanged(this._result.sortingMode);
|
||||
|
@ -1191,9 +1192,9 @@ PlacesTreeView.prototype = {
|
|||
break;
|
||||
}
|
||||
}
|
||||
} else if (nodeType == Ci.nsINavHistoryResultNode.RESULT_TYPE_SEPARATOR)
|
||||
} else if (nodeType == Ci.nsINavHistoryResultNode.RESULT_TYPE_SEPARATOR) {
|
||||
properties += " separator";
|
||||
else if (PlacesUtils.nodeIsURI(node)) {
|
||||
} else if (PlacesUtils.nodeIsURI(node)) {
|
||||
properties += " " + PlacesUIUtils.guessUrlSchemeForUI(node.uri);
|
||||
}
|
||||
|
||||
|
|
|
@ -436,8 +436,9 @@ function open_properties_dialog(test) {
|
|||
command = "placesCmd_new:bookmark";
|
||||
else
|
||||
Assert.ok(false, "You didn't set a valid itemType for adding an item");
|
||||
} else
|
||||
} else {
|
||||
command = "placesCmd_createBookmark";
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Assert.ok(false, "You didn't set a valid action for this test");
|
||||
|
|
|
@ -138,9 +138,9 @@ var pktApi = (function() {
|
|||
// TODO : Move this to sqlite or a local file so it's not editable (and is safer)
|
||||
// https://developer.mozilla.org/en-US/Add-ons/Overlay_Extensions/XUL_School/Local_Storage
|
||||
|
||||
if (!value)
|
||||
if (!value) {
|
||||
prefBranch.clearUserPref(key);
|
||||
else {
|
||||
} else {
|
||||
// We use complexValue as tags can have utf-8 characters in them
|
||||
prefBranch.setStringPref(key, value);
|
||||
}
|
||||
|
|
|
@ -1552,9 +1552,9 @@ var gMainPane = {
|
|||
let type = wrappedHandlerInfo.type;
|
||||
|
||||
let handlerInfoWrapper;
|
||||
if (type in this._handledTypes)
|
||||
if (type in this._handledTypes) {
|
||||
handlerInfoWrapper = this._handledTypes[type];
|
||||
else {
|
||||
} else {
|
||||
handlerInfoWrapper = new HandlerInfoWrapper(type, wrappedHandlerInfo);
|
||||
this._handledTypes[type] = handlerInfoWrapper;
|
||||
}
|
||||
|
|
|
@ -660,15 +660,16 @@ var gPrivacyPane = {
|
|||
let mode;
|
||||
let getVal = aPref => Preferences.get(aPref).value;
|
||||
|
||||
if (getVal("privacy.history.custom"))
|
||||
if (getVal("privacy.history.custom")) {
|
||||
mode = "custom";
|
||||
else if (this._checkHistoryValues(this.prefsForKeepingHistory)) {
|
||||
} else if (this._checkHistoryValues(this.prefsForKeepingHistory)) {
|
||||
if (getVal("browser.privatebrowsing.autostart"))
|
||||
mode = "dontremember";
|
||||
else
|
||||
mode = "remember";
|
||||
} else
|
||||
} else {
|
||||
mode = "custom";
|
||||
}
|
||||
|
||||
document.getElementById("historyMode").value = mode;
|
||||
},
|
||||
|
|
|
@ -186,9 +186,9 @@ var gLanguagesDialog = {
|
|||
|
||||
this._selectedItemID = selectedID;
|
||||
|
||||
if (preference.value == "")
|
||||
if (preference.value == "") {
|
||||
preference.value = selectedID;
|
||||
else {
|
||||
} else {
|
||||
arrayOfPrefs.unshift(selectedID);
|
||||
preference.value = arrayOfPrefs.join(",");
|
||||
}
|
||||
|
|
|
@ -357,8 +357,9 @@ class MozSearchbar extends MozXULElement {
|
|||
// Select the installed engine if the installation succeeds.
|
||||
Services.search.addEngine(target.getAttribute("uri"), null,
|
||||
target.getAttribute("src"), false).then(engine => this.currentEngine = engine);
|
||||
} else
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
this.focus();
|
||||
this.select();
|
||||
|
|
|
@ -95,8 +95,9 @@ function nextTest() {
|
|||
gCurrentTest = gTests.shift();
|
||||
info("Running " + gCurrentTest.name);
|
||||
gCurrentTest.run();
|
||||
} else
|
||||
} else {
|
||||
executeSoon(finish);
|
||||
}
|
||||
}
|
||||
|
||||
function test() {
|
||||
|
|
|
@ -18,8 +18,6 @@ ChromeUtils.defineModuleGetter(this, "ContentRestore",
|
|||
"resource:///modules/sessionstore/ContentRestore.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "SessionHistory",
|
||||
"resource://gre/modules/sessionstore/SessionHistory.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "Utils",
|
||||
"resource://gre/modules/sessionstore/Utils.jsm");
|
||||
|
||||
// A bound to the size of data to store for DOM Storage.
|
||||
const DOM_STORAGE_LIMIT_PREF = "browser.sessionstore.dom_storage_limit";
|
||||
|
@ -33,15 +31,6 @@ const PREF_INTERVAL = "browser.sessionstore.interval";
|
|||
const kNoIndex = Number.MAX_SAFE_INTEGER;
|
||||
const kLastIndex = Number.MAX_SAFE_INTEGER - 1;
|
||||
|
||||
/**
|
||||
* A function that will recursively call |cb| to collect data for all
|
||||
* non-dynamic frames in the current frame/docShell tree.
|
||||
*/
|
||||
function mapFrameTree(mm, callback) {
|
||||
let [data] = Utils.mapFrameTree(mm.content, callback);
|
||||
return data;
|
||||
}
|
||||
|
||||
class Handler {
|
||||
constructor(store) {
|
||||
this.store = store;
|
||||
|
@ -341,7 +330,7 @@ class ScrollPositionListener extends Handler {
|
|||
}
|
||||
|
||||
collect() {
|
||||
return mapFrameTree(this.mm, SessionStoreUtils.collectScrollPosition);
|
||||
return SessionStoreUtils.collectScrollPosition(this.mm.content);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -379,7 +368,7 @@ class FormDataListener extends Handler {
|
|||
}
|
||||
|
||||
collect() {
|
||||
return mapFrameTree(this.mm, SessionStoreUtils.collectFormData);
|
||||
return SessionStoreUtils.collectFormData(this.mm.content);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -207,8 +207,9 @@ function onListClick(aEvent) {
|
|||
!treeView.isContainer(cell.row)) {
|
||||
restoreSingleTab(cell.row, aEvent.shiftKey);
|
||||
aEvent.stopPropagation();
|
||||
} else if (cell.col.id == "restore")
|
||||
} else if (cell.col.id == "restore") {
|
||||
toggleRowChecked(cell.row);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -81,9 +81,9 @@ var workerManager = {
|
|||
// results. Otherwise, reschedule termination until after the next
|
||||
// idle timeout.
|
||||
_flushWorker() {
|
||||
if (this.detectionQueue.length)
|
||||
if (this.detectionQueue.length) {
|
||||
this.flushWorker();
|
||||
else {
|
||||
} else {
|
||||
if (this._worker)
|
||||
this._worker.terminate();
|
||||
|
||||
|
|
|
@ -281,9 +281,9 @@ class MozTranslationNotification extends MozElements.Notification {
|
|||
optionsShowing() {
|
||||
// Get the source language name.
|
||||
let lang;
|
||||
if (this.state == Translation.STATE_OFFER)
|
||||
if (this.state == Translation.STATE_OFFER) {
|
||||
lang = this._getAnonElt("detectedLanguage").value;
|
||||
else {
|
||||
} else {
|
||||
lang = this._getAnonElt("fromLanguage").value;
|
||||
|
||||
// If we have never attempted to translate the page before the
|
||||
|
|
|
@ -13,6 +13,7 @@ const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
|||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
AppConstants: "resource://gre/modules/AppConstants.jsm",
|
||||
BrowserUsageTelemetry: "resource:///modules/BrowserUsageTelemetry.jsm",
|
||||
ExtensionSearchHandler: "resource://gre/modules/ExtensionSearchHandler.jsm",
|
||||
PlacesUtils: "resource://gre/modules/PlacesUtils.jsm",
|
||||
UrlbarPrefs: "resource:///modules/UrlbarPrefs.jsm",
|
||||
UrlbarProvidersManager: "resource:///modules/UrlbarProvidersManager.jsm",
|
||||
|
@ -108,9 +109,12 @@ class UrlbarController {
|
|||
|
||||
/**
|
||||
* Cancels an in-progress query. Note, queries may continue running if they
|
||||
* can't be canceled.
|
||||
* can't be cancelled.
|
||||
*
|
||||
* @param {UrlbarUtils.CANCEL_REASON} [reason]
|
||||
* The reason the query was cancelled.
|
||||
*/
|
||||
cancelQuery() {
|
||||
cancelQuery(reason) {
|
||||
if (!this._lastQueryContext) {
|
||||
return;
|
||||
}
|
||||
|
@ -121,6 +125,11 @@ class UrlbarController {
|
|||
this.manager.cancelQuery(this._lastQueryContext);
|
||||
this._notify("onQueryCancelled", this._lastQueryContext);
|
||||
delete this._lastQueryContext;
|
||||
|
||||
if (reason == UrlbarUtils.CANCEL_REASON.BLUR &&
|
||||
ExtensionSearchHandler.hasActiveInputSession()) {
|
||||
ExtensionSearchHandler.handleInputCancelled();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -153,7 +153,6 @@ class UrlbarInput {
|
|||
}
|
||||
|
||||
closePopup() {
|
||||
this.controller.cancelQuery();
|
||||
this.view.close();
|
||||
}
|
||||
|
||||
|
@ -371,6 +370,9 @@ class UrlbarInput {
|
|||
break;
|
||||
}
|
||||
case UrlbarUtils.RESULT_TYPE.OMNIBOX: {
|
||||
// The urlbar needs to revert to the loaded url when a command is
|
||||
// handled by the extension.
|
||||
this.handleRevert();
|
||||
// We don't directly handle a load when an Omnibox API result is picked,
|
||||
// instead we forward the request to the WebExtension itself, because
|
||||
// the value may not even be a url.
|
||||
|
@ -950,7 +952,7 @@ class UrlbarInput {
|
|||
|
||||
_on_blur(event) {
|
||||
this.formatValue();
|
||||
this.closePopup();
|
||||
this.view.close(UrlbarUtils.CANCEL_REASON.BLUR);
|
||||
}
|
||||
|
||||
_on_focus(event) {
|
||||
|
|
|
@ -114,6 +114,12 @@ var UrlbarUtils = {
|
|||
COMMIT: 3,
|
||||
},
|
||||
|
||||
// This defines possible reasons for canceling a query.
|
||||
CANCEL_REASON: {
|
||||
// 1 is intentionally left in case we want a none/undefined/other later.
|
||||
BLUR: 2,
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds a url to history as long as it isn't in a private browsing window,
|
||||
* and it is valid.
|
||||
|
|
|
@ -172,9 +172,14 @@ class UrlbarView {
|
|||
}
|
||||
|
||||
/**
|
||||
* Closes the autocomplete results popup.
|
||||
* Closes the autocomplete popup, cancelling the query if necessary.
|
||||
*
|
||||
* @param {UrlbarUtils.CANCEL_REASON} [cancelReason]
|
||||
* Indicates if this close is being triggered as a result of a user action
|
||||
* which would cancel a query, e.g. on blur.
|
||||
*/
|
||||
close() {
|
||||
close(cancelReason) {
|
||||
this.controller.cancelQuery(cancelReason);
|
||||
this.panel.hidePopup();
|
||||
}
|
||||
|
||||
|
@ -464,6 +469,9 @@ class UrlbarView {
|
|||
setAction(bundle.GetStringFromName("visit"));
|
||||
}
|
||||
break;
|
||||
case UrlbarUtils.RESULT_TYPE.OMNIBOX:
|
||||
setAction(result.payload.content);
|
||||
break;
|
||||
default:
|
||||
if (result.heuristic) {
|
||||
setAction(bundle.GetStringFromName("visit"));
|
||||
|
|
|
@ -299,7 +299,7 @@ class UrlbarAbstraction {
|
|||
return BrowserTestUtils.waitForCondition(
|
||||
() => this.urlbar.controller.searchStatus >=
|
||||
Ci.nsIAutoCompleteController.STATUS_COMPLETE_NO_MATCH,
|
||||
"waiting urlbar search to complete");
|
||||
"waiting urlbar search to complete", 100, 50);
|
||||
}
|
||||
|
||||
async promiseResultAt(index) {
|
||||
|
|
|
@ -44,9 +44,9 @@ async function clickURLBarSuggestion(resultTitle, button = 1) {
|
|||
if (result.displayed.title == resultTitle) {
|
||||
// This entry is the search suggestion we're looking for.
|
||||
let element = await UrlbarTestUtils.waitForAutocompleteResultAt(window, i);
|
||||
if (button == 1)
|
||||
if (button == 1) {
|
||||
EventUtils.synthesizeMouseAtCenter(element, {});
|
||||
else if (button == 2) {
|
||||
} else if (button == 2) {
|
||||
EventUtils.synthesizeMouseAtCenter(element, {type: "mousedown", button: 2});
|
||||
}
|
||||
return;
|
||||
|
|
|
@ -676,7 +676,7 @@
|
|||
.tabbrowser-arrowscrollbox > .scrollbutton-down {
|
||||
list-style-image: url(chrome://browser/skin/arrow-left.svg) !important;
|
||||
-moz-context-properties: fill, fill-opacity;
|
||||
fill: currentColor;
|
||||
fill: var(--lwt-toolbarbutton-icon-fill, currentColor);
|
||||
fill-opacity: var(--toolbarbutton-icon-fill-opacity);
|
||||
color: inherit;
|
||||
}
|
||||
|
|
|
@ -11,9 +11,6 @@
|
|||
},
|
||||
"homepage": "https://github.com/firefox-devtools/debugger.html#readme",
|
||||
"engineStrict": true,
|
||||
"engines": {
|
||||
"node": ">=10.15.0"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "node bin/dev-server",
|
||||
"start-app": "TARGET=application node bin/dev-server",
|
||||
|
|
|
@ -42,11 +42,12 @@ env.testing = true;
|
|||
const rootPath = path.join(__dirname, "../../");
|
||||
|
||||
function getL10nBundle() {
|
||||
const read = file => readFileSync(path.join(__dirname, file));
|
||||
const read = file => readFileSync(path.join(rootPath, file));
|
||||
|
||||
try {
|
||||
return read("../../assets/panel/debugger.properties");
|
||||
return read("./assets/panel/debugger.properties");
|
||||
} catch (e) {
|
||||
return read("../../../../locales/en-us/debugger.properties");
|
||||
return read("../../locales/en-US/debugger.properties");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -111,3 +112,20 @@ function mockIndexeddDB() {
|
|||
}
|
||||
};
|
||||
}
|
||||
|
||||
// NOTE: We polyfill finally because TRY uses node 8
|
||||
if (!global.Promise.prototype.finally) {
|
||||
global.Promise.prototype.finally = function finallyPolyfill(callback) {
|
||||
var constructor = this.constructor;
|
||||
|
||||
return this.then(function(value) {
|
||||
return constructor.resolve(callback()).then(function() {
|
||||
return value;
|
||||
});
|
||||
}, function(reason) {
|
||||
return constructor.resolve(callback()).then(function() {
|
||||
throw reason;
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
|
|
|
@ -62,6 +62,9 @@ class FontInspector {
|
|||
this.inspector = inspector;
|
||||
// Set of unique keyword values supported by designated font properties.
|
||||
this.keywordValues = new Set(this.getFontPropertyValueKeywords());
|
||||
// Selected node in the markup view. For text nodes, this points to their parent node
|
||||
// element. Font faces and font properties for this node will be shown in the editor.
|
||||
this.node = null;
|
||||
this.nodeComputedStyle = {};
|
||||
this.pageStyle = this.inspector.pageStyle;
|
||||
this.ruleViewTool = this.inspector.getPanel("ruleview");
|
||||
|
@ -162,8 +165,8 @@ class FontInspector {
|
|||
const fromPx = fromUnit === "px";
|
||||
// Determine the target CSS unit for conversion.
|
||||
const unit = toUnit === "px" ? fromUnit : toUnit;
|
||||
// NodeFront instance of selected element.
|
||||
const node = this.inspector.selection.nodeFront;
|
||||
// NodeFront instance of selected/target element.
|
||||
const node = this.node;
|
||||
// Reference node based on which to convert relative sizes like "em" and "%".
|
||||
const referenceNode = (property === "line-height") ? node : node.parentNode();
|
||||
// Default output value to input value for a 1-to-1 conversion as a guard against
|
||||
|
@ -296,6 +299,7 @@ class FontInspector {
|
|||
|
||||
this.document = null;
|
||||
this.inspector = null;
|
||||
this.node = null;
|
||||
this.nodeComputedStyle = {};
|
||||
this.pageStyle = null;
|
||||
this.ruleView = null;
|
||||
|
@ -540,17 +544,6 @@ class FontInspector {
|
|||
this.inspector.sidebar &&
|
||||
this.inspector.sidebar.getCurrentTabID() === "fontinspector";
|
||||
}
|
||||
/**
|
||||
* Check if a selected node exists and fonts can apply to it.
|
||||
*
|
||||
* @return {Boolean}
|
||||
*/
|
||||
isSelectedNodeValid() {
|
||||
return this.inspector &&
|
||||
this.inspector.selection.nodeFront &&
|
||||
this.inspector.selection.isConnected() &&
|
||||
this.inspector.selection.isElementNode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Upon a new node selection, log some interesting telemetry probes.
|
||||
|
@ -654,10 +647,30 @@ class FontInspector {
|
|||
}
|
||||
|
||||
/**
|
||||
* Selection 'new-node' event handler.
|
||||
* Event handler for "new-node-front" event fired when a new node is selected in the
|
||||
* markup view.
|
||||
*
|
||||
* Sets the selected node for which font faces and font properties will be
|
||||
* shown in the font editor. If the selection is a text node, use its parent element.
|
||||
*
|
||||
* Triggers a refresh of the font editor and font overview if the panel is visible.
|
||||
*/
|
||||
onNewNode() {
|
||||
this.ruleView.off("property-value-updated", this.onRulePropertyUpdated);
|
||||
// First, reset the selected node.
|
||||
this.node = null;
|
||||
// Then attempt to assign a selected node according to its type.
|
||||
const selection = this.inspector && this.inspector.selection;
|
||||
if (selection && selection.isConnected()) {
|
||||
if (selection.isElementNode()) {
|
||||
this.node = selection.nodeFront;
|
||||
}
|
||||
|
||||
if (selection.isTextNode()) {
|
||||
this.node = selection.nodeFront.parentNode();
|
||||
}
|
||||
}
|
||||
|
||||
if (this.isPanelVisible()) {
|
||||
Promise.all([this.update(), this.refreshFontEditor()]).then(() => {
|
||||
this.logTelemetryProbesOnNewNode();
|
||||
|
@ -753,9 +766,7 @@ class FontInspector {
|
|||
|
||||
try {
|
||||
if (show) {
|
||||
const node = isForCurrentElement
|
||||
? this.inspector.selection.nodeFront
|
||||
: this.inspector.walker.rootNode;
|
||||
const node = isForCurrentElement ? this.node : this.inspector.walker.rootNode;
|
||||
|
||||
await this.fontsHighlighter.show(node, {
|
||||
CSSFamilyName: font.CSSFamilyName,
|
||||
|
@ -785,21 +796,13 @@ class FontInspector {
|
|||
* - the computed style CSS font properties of the current node.
|
||||
*
|
||||
* This method is called:
|
||||
* - during initial setup;
|
||||
* - when a new node is selected;
|
||||
* - when any property is changed in the Rule view.
|
||||
* For the latter case, we compare between the latest computed style font properties
|
||||
* and the ones already in the store to decide if to update the font editor state.
|
||||
*/
|
||||
async refreshFontEditor() {
|
||||
if (!this.store || !this.isSelectedNodeValid()) {
|
||||
// If the selection is a TextNode, switch selection to be its parent node.
|
||||
if (this.inspector.selection.isTextNode()) {
|
||||
const selection = this.inspector.selection;
|
||||
selection.setNodeFront(selection.nodeFront.parentNode());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.node) {
|
||||
this.store.dispatch(resetFontEditor());
|
||||
return;
|
||||
}
|
||||
|
@ -809,12 +812,11 @@ class FontInspector {
|
|||
options.includeVariations = true;
|
||||
}
|
||||
|
||||
const node = this.inspector.selection.nodeFront;
|
||||
const fonts = await this.getFontsForNode(node, options);
|
||||
const fonts = await this.getFontsForNode(this.node, options);
|
||||
|
||||
try {
|
||||
// Get computed styles for the selected node, but filter by CSS font properties.
|
||||
this.nodeComputedStyle = await this.pageStyle.getComputed(node, {
|
||||
this.nodeComputedStyle = await this.pageStyle.getComputed(this.node, {
|
||||
filterProperties: FONT_PROPERTIES,
|
||||
});
|
||||
} catch (e) {
|
||||
|
@ -842,7 +844,7 @@ class FontInspector {
|
|||
// been created yet. For example, in 2-pane mode when Fonts is opened as the default
|
||||
// panel. Select the current node to force the Rule view to create the rule models.
|
||||
if (!this.ruleViewTool.isSidebarActive()) {
|
||||
await this.ruleView.selectElement(node, false);
|
||||
await this.ruleView.selectElement(this.node, false);
|
||||
}
|
||||
|
||||
// Select the node's inline style as the rule where to write property value changes.
|
||||
|
@ -856,9 +858,8 @@ class FontInspector {
|
|||
this.writers.set(axis, this.getWriterForAxis(axis));
|
||||
});
|
||||
|
||||
this.store.dispatch(updateFontEditor(fonts, properties, node.actorID));
|
||||
const isPseudo = this.inspector.selection.isPseudoElementNode();
|
||||
this.store.dispatch(setEditorDisabled(isPseudo));
|
||||
this.store.dispatch(updateFontEditor(fonts, properties, this.node.actorID));
|
||||
this.store.dispatch(setEditorDisabled(this.node.isPseudoElement));
|
||||
|
||||
this.inspector.emit("fonteditor-updated");
|
||||
// Listen to manual changes in the Rule view that could update the Font Editor state
|
||||
|
@ -882,7 +883,7 @@ class FontInspector {
|
|||
|
||||
let allFonts = [];
|
||||
|
||||
if (!this.isSelectedNodeValid()) {
|
||||
if (!this.node) {
|
||||
this.store.dispatch(updateFonts(allFonts));
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ add_task(async function() {
|
|||
const bodyNode = await getNodeFront("body", inspector);
|
||||
const { nodes } = await inspector.walker.children(bodyNode);
|
||||
const onInspectorUpdated = inspector.once("fontinspector-updated");
|
||||
info("Select the text node");
|
||||
await selectNode(nodes[0], inspector);
|
||||
|
||||
info("Waiting for font editor to render");
|
||||
|
|
|
@ -936,7 +936,7 @@ netmonitor.context.copyRequestHeaders=Copy Request Headers
|
|||
|
||||
# LOCALIZATION NOTE (netmonitor.context.copyRequestHeaders.accesskey): This is the access key
|
||||
# for the Copy Request Headers menu item displayed in the context menu for a request
|
||||
netmonitor.context.copyRequestHeaders.accesskey=Q
|
||||
netmonitor.context.copyRequestHeaders.accesskey=q
|
||||
|
||||
# LOCALIZATION NOTE (netmonitor.context.copyResponseHeaders): This is the label displayed
|
||||
# on the context menu that copies the selected item's response headers
|
||||
|
@ -944,7 +944,7 @@ netmonitor.context.copyResponseHeaders=Copy Response Headers
|
|||
|
||||
# LOCALIZATION NOTE (netmonitor.context.copyResponseHeaders.accesskey): This is the access key
|
||||
# for the Copy Response Headers menu item displayed in the context menu for a response
|
||||
netmonitor.context.copyResponseHeaders.accesskey=S
|
||||
netmonitor.context.copyResponseHeaders.accesskey=s
|
||||
|
||||
# LOCALIZATION NOTE (netmonitor.context.copyResponse): This is the label displayed
|
||||
# on the context menu that copies the selected response as a string
|
||||
|
@ -968,7 +968,7 @@ netmonitor.context.saveImageAs=Save Image As
|
|||
|
||||
# LOCALIZATION NOTE (netmonitor.context.saveImageAs.accesskey): This is the access key
|
||||
# for the Copy Image As Data URI menu item displayed in the context menu for a request
|
||||
netmonitor.context.saveImageAs.accesskey=V
|
||||
netmonitor.context.saveImageAs.accesskey=v
|
||||
|
||||
# LOCALIZATION NOTE (netmonitor.context.copyAllAsHar): This is the label displayed
|
||||
# on the context menu that copies all as HAR format
|
||||
|
@ -976,7 +976,7 @@ netmonitor.context.copyAllAsHar=Copy All As HAR
|
|||
|
||||
# LOCALIZATION NOTE (netmonitor.context.copyAllAsHar.accesskey): This is the access key
|
||||
# for the Copy All As HAR menu item displayed in the context menu for a network panel
|
||||
netmonitor.context.copyAllAsHar.accesskey=O
|
||||
netmonitor.context.copyAllAsHar.accesskey=o
|
||||
|
||||
# LOCALIZATION NOTE (netmonitor.context.saveAllAsHar): This is the label displayed
|
||||
# on the context menu that saves all as HAR format
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
* [`xpcshell`](tests/xpcshell.md)
|
||||
* [Chrome mochitests](tests/mochitest-chrome.md)
|
||||
* [DevTools mochitests](tests/mochitest-devtools.md)
|
||||
* [Tips](tests/tips.md)
|
||||
* [Writing tests](tests/writing-tests.md)
|
||||
* [Debugging intermittent failures](tests/debugging-intermittents.md)
|
||||
* [Performance tests (DAMP)](tests/performance-tests.md)
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
# Automated tests: Tips
|
||||
|
||||
If you run tests in debug mode, e.g. when debugging memory leaks, the test logs are often dominated by `++DOMWINDOW`, `++DOCSHELL`, `--DOMWINDOW`, `--DOCSHELL` lines.
|
||||
|
||||
These lines pollute the test logs making it difficult to find real problems. They also slow down our tests because they are not useful for debugging DevTools issues.
|
||||
|
||||
You can add this to your `.zshrc` or `.bashrc` to disable them:
|
||||
|
||||
```bash
|
||||
# Disable those annoying +++DOMWINDOW and +++DOCSHELL printfs from Firefox logs
|
||||
export MOZ_QUIET=1
|
||||
```
|
||||
|
||||
You can also send `MOZ_QUIET` when you push to try… it makes the logs easier to read and makes the tests run faster because there is so much less logging.
|
||||
|
||||
Example try syntax containing `MOZ_QUIET`:
|
||||
|
||||
```
|
||||
./mach try -b do -p linux,linux64,macosx64,win32,win64 \
|
||||
-u xpcshell,mochitest-bc,mochitest-e10s-bc,mochitest-dt,mochitest-chrome \
|
||||
-t damp-e10s --setenv MOZ_QUIET=1
|
||||
```
|
|
@ -30,6 +30,17 @@ const addonTargetSpec = generateActorSpec({
|
|||
response: RetVal("json"),
|
||||
},
|
||||
},
|
||||
|
||||
events: {
|
||||
// The thread actor is no longer emitting newSource event in the name of the target
|
||||
// actor (bug 1269919), but as we may still connect to older servers which still do,
|
||||
// we have to keep it being mentioned here. Otherwise the event is considered as a
|
||||
// response to a request and confuses the packet ordering.
|
||||
// We can remove that once FF57 is no longer supported.
|
||||
newSource: {
|
||||
type: "newSource",
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
exports.addonTargetSpec = addonTargetSpec;
|
||||
|
|
|
@ -136,6 +136,15 @@ const browsingContextTargetSpecPrototype = {
|
|||
workerListChanged: {
|
||||
type: "workerListChanged",
|
||||
},
|
||||
|
||||
// The thread actor is no longer emitting newSource event in the name of the target
|
||||
// actor (bug 1269919), but as we may still connect to older servers which still do,
|
||||
// we have to keep it being mentioned here. Otherwise the event is considered as a
|
||||
// response to a request and confuses the packet ordering.
|
||||
// We can remove that once FF57 is no longer supported.
|
||||
newSource: {
|
||||
type: "newSource",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -24,6 +24,15 @@ const contentProcessTargetSpec = generateActorSpec({
|
|||
workerListChanged: {
|
||||
type: "workerListChanged",
|
||||
},
|
||||
|
||||
// The thread actor is no longer emitting newSource event in the name of the target
|
||||
// actor (bug 1269919), but as we may still connect to older servers which still do,
|
||||
// we have to keep it being mentioned here. Otherwise the event is considered as a
|
||||
// response to a request and confuses the packet ordering.
|
||||
// We can remove that once FF57 is no longer supported.
|
||||
newSource: {
|
||||
type: "newSource",
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
@ -36,6 +36,15 @@ const workerTargetSpec = generateActorSpec({
|
|||
"worker-close": {
|
||||
type: "close",
|
||||
},
|
||||
|
||||
// The thread actor is no longer emitting newSource event in the name of the target
|
||||
// actor (bug 1269919), but as we may still connect to older servers which still do,
|
||||
// we have to keep it being mentioned here. Otherwise the event is considered as a
|
||||
// response to a request and confuses the packet ordering.
|
||||
// We can remove that once FF57 is no longer supported.
|
||||
newSource: {
|
||||
type: "newSource",
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
@ -77,7 +77,7 @@ namespace SessionStoreUtils {
|
|||
* Returns null when there is no scroll data we want to store for the
|
||||
* given |frame|.
|
||||
*/
|
||||
SSScrollPositionDict collectScrollPosition(Document document);
|
||||
CollectedData? collectScrollPosition(WindowProxy window);
|
||||
|
||||
/**
|
||||
* Restores scroll position data for any given |frame| in the frame hierarchy.
|
||||
|
@ -85,7 +85,7 @@ namespace SessionStoreUtils {
|
|||
* @param frame (DOMWindow)
|
||||
* @param value (object, see collectScrollPosition())
|
||||
*/
|
||||
void restoreScrollPosition(Window frame, optional SSScrollPositionDict data);
|
||||
void restoreScrollPosition(Window frame, optional CollectedData data);
|
||||
|
||||
/**
|
||||
* Collect form data for a given |frame| *not* including any subframes.
|
||||
|
@ -105,13 +105,12 @@ namespace SessionStoreUtils {
|
|||
* }
|
||||
* }
|
||||
*
|
||||
* @param doc
|
||||
* DOMDocument instance to obtain form data for.
|
||||
* @return object
|
||||
* Form data encoded in an object.
|
||||
* Returns null when there is no scroll data
|
||||
*/
|
||||
CollectedFormData collectFormData(Document document);
|
||||
boolean restoreFormData(Document document, optional CollectedFormData data);
|
||||
CollectedData? collectFormData(WindowProxy window);
|
||||
|
||||
boolean restoreFormData(Document document, optional CollectedData data);
|
||||
|
||||
/**
|
||||
* Updates all sessionStorage "super cookies"
|
||||
|
@ -135,10 +134,6 @@ namespace SessionStoreUtils {
|
|||
void restoreSessionStorage(nsIDocShell docShell, record<DOMString, record<DOMString, DOMString>> data);
|
||||
};
|
||||
|
||||
dictionary SSScrollPositionDict {
|
||||
ByteString scroll;
|
||||
};
|
||||
|
||||
dictionary CollectedFileListValue
|
||||
{
|
||||
required DOMString type;
|
||||
|
@ -154,10 +149,13 @@ dictionary CollectedNonMultipleSelectValue
|
|||
// object contains either a CollectedFileListValue or a CollectedNonMultipleSelectValue or Sequence<DOMString>
|
||||
typedef (DOMString or boolean or object) CollectedFormDataValue;
|
||||
|
||||
dictionary CollectedFormData
|
||||
dictionary CollectedData
|
||||
{
|
||||
ByteString scroll;
|
||||
record<DOMString, CollectedFormDataValue> id;
|
||||
record<DOMString, CollectedFormDataValue> xpath;
|
||||
DOMString innerHTML;
|
||||
ByteString url;
|
||||
// mChildren contains CollectedData instances
|
||||
sequence<object?> children;
|
||||
};
|
||||
|
|
|
@ -1979,6 +1979,10 @@ bool nsGenericHTMLFormElement::IsElementDisabledForEvents(WidgetEvent* aEvent,
|
|||
case ePointerOut:
|
||||
case ePointerEnter:
|
||||
case ePointerLeave:
|
||||
case eTransitionCancel:
|
||||
case eTransitionEnd:
|
||||
case eTransitionRun:
|
||||
case eTransitionStart:
|
||||
case eWheel:
|
||||
case eLegacyMouseLineOrPageScroll:
|
||||
case eLegacyMousePixelScroll:
|
||||
|
|
|
@ -67,14 +67,15 @@ bool AudioData::AdjustForStartTime(int64_t aStartTime) {
|
|||
}
|
||||
|
||||
bool AudioData::SetTrimWindow(const media::TimeInterval& aTrim) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(aTrim.mStart.IsValid() && aTrim.mEnd.IsValid(),
|
||||
"An overflow occurred on the provided TimeInterval");
|
||||
if (!mAudioData) {
|
||||
// MoveableData got called. Can no longer work on it.
|
||||
return false;
|
||||
}
|
||||
const size_t originalFrames = mAudioData.Length() / mChannels;
|
||||
const TimeUnit originalDuration = FramesToTimeUnit(originalFrames, mRate);
|
||||
if (!aTrim.mStart.IsValid() || !aTrim.mEnd.IsValid() ||
|
||||
aTrim.mStart < mOriginalTime ||
|
||||
if (aTrim.mStart < mOriginalTime ||
|
||||
aTrim.mEnd > mOriginalTime + originalDuration) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -409,7 +409,10 @@ Index::Index(const IndiceWrapper& aIndices, ByteStream* aSource,
|
|||
if (!haveSync) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (indice.start_composition == indice.end_composition) {
|
||||
// Ignore this sample as it doesn't account for the buffered range.
|
||||
continue;
|
||||
}
|
||||
Sample sample;
|
||||
sample.mByteRange =
|
||||
MediaByteRange(indice.start_offset, indice.end_offset);
|
||||
|
|
|
@ -142,9 +142,9 @@ function runTest() {
|
|||
}
|
||||
|
||||
var isMac = ("nsILocalFileMac" in SpecialPowers.Ci);
|
||||
if (isMac)
|
||||
if (isMac) {
|
||||
SimpleTest.waitForFocus(runTest);
|
||||
else {
|
||||
} else {
|
||||
// This test is not yet supported on non-Mac platforms, see bug 574005.
|
||||
todo(false, "Test not supported on this platform");
|
||||
SimpleTest.finish();
|
||||
|
|
|
@ -539,9 +539,9 @@ var tests = [
|
|||
|
||||
function doNextTest() {
|
||||
/* global testCounter:true */
|
||||
if (typeof testCounter == "undefined")
|
||||
if (typeof testCounter == "undefined") {
|
||||
testCounter = 0;
|
||||
else if (++testCounter == tests.length) {
|
||||
} else if (++testCounter == tests.length) {
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
}
|
||||
|
@ -561,8 +561,9 @@ function runTest(test) {
|
|||
if ("isIFrame" in test) {
|
||||
elem.contentDocument.designMode = "on";
|
||||
elem.contentWindow.focus();
|
||||
} else
|
||||
} else {
|
||||
elem.focus();
|
||||
}
|
||||
|
||||
var trans = SpecialPowers.Cc["@mozilla.org/widget/transferable;1"]
|
||||
.createInstance(SpecialPowers.Ci.nsITransferable);
|
||||
|
|
|
@ -1468,6 +1468,7 @@ nsEventStatus APZCTreeManager::ReceiveInputEvent(
|
|||
break;
|
||||
}
|
||||
case KEYBOARD_INPUT: {
|
||||
aEvent.mLayersId = mFocusState.GetFocusLayersId();
|
||||
// Disable async keyboard scrolling when accessibility.browsewithcaret is
|
||||
// enabled
|
||||
if (!gfxPrefs::APZKeyboardEnabled() ||
|
||||
|
|
|
@ -184,6 +184,7 @@ nsEventStatus APZInputBridge::ReceiveInputEvent(
|
|||
|
||||
keyboardEvent.mFlags.mHandledByAPZ = input.mHandledByAPZ;
|
||||
keyboardEvent.mFocusSequenceNumber = input.mFocusSequenceNumber;
|
||||
aEvent.mLayersId = input.mLayersId;
|
||||
return status;
|
||||
}
|
||||
default: {
|
||||
|
|
|
@ -220,5 +220,11 @@ bool FocusState::CanIgnoreKeyboardShortcutMisses() const {
|
|||
return IsCurrent(lock) && !mFocusHasKeyEventListeners;
|
||||
}
|
||||
|
||||
LayersId FocusState::GetFocusLayersId() const {
|
||||
MutexAutoLock lock(mMutex);
|
||||
|
||||
return mFocusLayersId;
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -125,6 +125,8 @@ class FocusState final {
|
|||
*/
|
||||
bool CanIgnoreKeyboardShortcutMisses() const;
|
||||
|
||||
LayersId GetFocusLayersId() const;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Whether the current focus state is known to be current or else if an event
|
||||
|
|
|
@ -23,10 +23,10 @@ function ArrayIndexOf(searchElement/*, fromIndex*/) {
|
|||
|
||||
var k;
|
||||
/* Step 7. */
|
||||
if (n >= 0)
|
||||
if (n >= 0) {
|
||||
k = n;
|
||||
/* Step 8. */
|
||||
else {
|
||||
} else {
|
||||
/* Step a. */
|
||||
k = len + n;
|
||||
/* Step b. */
|
||||
|
|
|
@ -1939,8 +1939,7 @@ bool ASTSerializer::variableDeclarator(ParseNode* pn, MutableHandleValue dst) {
|
|||
|
||||
if (pn->isKind(ParseNodeKind::Name)) {
|
||||
patternNode = pn;
|
||||
initNode = pn->as<NameNode>().initializer();
|
||||
MOZ_ASSERT_IF(initNode, pn->pn_pos.encloses(initNode->pn_pos));
|
||||
initNode = nullptr;
|
||||
} else if (pn->isKind(ParseNodeKind::AssignExpr)) {
|
||||
AssignmentNode* assignNode = &pn->as<AssignmentNode>();
|
||||
patternNode = assignNode->left();
|
||||
|
|
|
@ -2629,7 +2629,11 @@ JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceEagerGetter(
|
|||
ListNode* body;
|
||||
MOZ_TRY(parseGetterContents(length, ¶ms, &body));
|
||||
MOZ_TRY(prependDirectivesToBody(body, directives));
|
||||
BINJS_MOZ_TRY_DECL(method, buildFunction(start, kind, name, params, body));
|
||||
BINJS_TRY_DECL(lexicalScopeData,
|
||||
NewLexicalScopeData(cx_, lexicalScope, alloc_, pc_));
|
||||
BINJS_TRY_DECL(bodyScope, handler_.newLexicalScope(*lexicalScopeData, body));
|
||||
BINJS_MOZ_TRY_DECL(method,
|
||||
buildFunction(start, kind, name, params, bodyScope));
|
||||
BINJS_TRY_DECL(result, handler_.newObjectMethodOrPropertyDefinition(
|
||||
name, method, accessorType));
|
||||
return result;
|
||||
|
@ -2691,7 +2695,11 @@ JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceEagerMethod(
|
|||
ListNode* body;
|
||||
MOZ_TRY(parseFunctionOrMethodContents(length, ¶ms, &body));
|
||||
MOZ_TRY(prependDirectivesToBody(body, directives));
|
||||
BINJS_MOZ_TRY_DECL(method, buildFunction(start, kind, name, params, body));
|
||||
BINJS_TRY_DECL(lexicalScopeData,
|
||||
NewLexicalScopeData(cx_, lexicalScope, alloc_, pc_));
|
||||
BINJS_TRY_DECL(bodyScope, handler_.newLexicalScope(*lexicalScopeData, body));
|
||||
BINJS_MOZ_TRY_DECL(method,
|
||||
buildFunction(start, kind, name, params, bodyScope));
|
||||
BINJS_TRY_DECL(result, handler_.newObjectMethodOrPropertyDefinition(
|
||||
name, method, accessorType));
|
||||
return result;
|
||||
|
@ -2746,7 +2754,11 @@ JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceEagerSetter(
|
|||
ListNode* body;
|
||||
MOZ_TRY(parseSetterContents(length, ¶ms, &body));
|
||||
MOZ_TRY(prependDirectivesToBody(body, directives));
|
||||
BINJS_MOZ_TRY_DECL(method, buildFunction(start, kind, name, params, body));
|
||||
BINJS_TRY_DECL(lexicalScopeData,
|
||||
NewLexicalScopeData(cx_, lexicalScope, alloc_, pc_));
|
||||
BINJS_TRY_DECL(bodyScope, handler_.newLexicalScope(*lexicalScopeData, body));
|
||||
BINJS_MOZ_TRY_DECL(method,
|
||||
buildFunction(start, kind, name, params, bodyScope));
|
||||
BINJS_TRY_DECL(result, handler_.newObjectMethodOrPropertyDefinition(
|
||||
name, method, accessorType));
|
||||
return result;
|
||||
|
@ -4244,9 +4256,11 @@ JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceVariableDeclarator(
|
|||
// `var foo [= bar]``
|
||||
NameNode* bindingNameNode = &binding->template as<NameNode>();
|
||||
MOZ_TRY(checkBinding(bindingNameNode->atom()->asPropertyName()));
|
||||
result = bindingNameNode;
|
||||
if (init) {
|
||||
BINJS_TRY(handler_.finishInitializerAssignment(bindingNameNode, init));
|
||||
BINJS_TRY_VAR(
|
||||
result, handler_.finishInitializerAssignment(bindingNameNode, init));
|
||||
} else {
|
||||
result = bindingNameNode;
|
||||
}
|
||||
} else {
|
||||
// `var pattern = bar`
|
||||
|
|
|
@ -1006,8 +1006,12 @@ EagerMethod:
|
|||
const auto accessorType = AccessorType::None;
|
||||
inherits: EagerFunctionExpression
|
||||
build: |
|
||||
BINJS_TRY_DECL(lexicalScopeData,
|
||||
NewLexicalScopeData(cx_, lexicalScope, alloc_, pc_));
|
||||
BINJS_TRY_DECL(bodyScope,
|
||||
handler_.newLexicalScope(*lexicalScopeData, body));
|
||||
BINJS_MOZ_TRY_DECL(method,
|
||||
buildFunction(start, kind, name, params, body));
|
||||
buildFunction(start, kind, name, params, bodyScope));
|
||||
BINJS_TRY_DECL(result,
|
||||
handler_.newObjectMethodOrPropertyDefinition(name, method,
|
||||
accessorType));
|
||||
|
@ -1603,9 +1607,11 @@ VariableDeclarator:
|
|||
// `var foo [= bar]``
|
||||
NameNode* bindingNameNode = &binding->template as<NameNode>();
|
||||
MOZ_TRY(checkBinding(bindingNameNode->atom()->asPropertyName()));
|
||||
result = bindingNameNode;
|
||||
if (init) {
|
||||
BINJS_TRY(handler_.finishInitializerAssignment(bindingNameNode, init));
|
||||
BINJS_TRY_VAR(result,
|
||||
handler_.finishInitializerAssignment(bindingNameNode, init));
|
||||
} else {
|
||||
result = bindingNameNode;
|
||||
}
|
||||
} else {
|
||||
// `var pattern = bar`
|
||||
|
|
|
@ -4025,36 +4025,49 @@ bool BytecodeEmitter::emitDeclarationList(ListNode* declList) {
|
|||
MOZ_ASSERT(declList->isOp(JSOP_NOP));
|
||||
|
||||
for (ParseNode* decl : declList->contents()) {
|
||||
if (decl->isKind(ParseNodeKind::AssignExpr)) {
|
||||
ParseNode* pattern;
|
||||
ParseNode* initializer;
|
||||
if (decl->isKind(ParseNodeKind::Name)) {
|
||||
pattern = decl;
|
||||
initializer = nullptr;
|
||||
} else {
|
||||
MOZ_ASSERT(decl->isOp(JSOP_NOP));
|
||||
|
||||
AssignmentNode* assignNode = &decl->as<AssignmentNode>();
|
||||
ListNode* pattern = &assignNode->left()->as<ListNode>();
|
||||
pattern = assignNode->left();
|
||||
initializer = assignNode->right();
|
||||
}
|
||||
|
||||
if (pattern->isKind(ParseNodeKind::Name)) {
|
||||
// initializer can be null here.
|
||||
if (!emitSingleDeclaration(declList, &pattern->as<NameNode>(),
|
||||
initializer)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
MOZ_ASSERT(decl->isOp(JSOP_NOP));
|
||||
MOZ_ASSERT(pattern->isKind(ParseNodeKind::ArrayExpr) ||
|
||||
pattern->isKind(ParseNodeKind::ObjectExpr));
|
||||
MOZ_ASSERT(initializer != nullptr);
|
||||
|
||||
if (!updateSourceCoordNotes(assignNode->right()->pn_pos.begin)) {
|
||||
if (!updateSourceCoordNotes(initializer->pn_pos.begin)) {
|
||||
return false;
|
||||
}
|
||||
if (!markStepBreakpoint()) {
|
||||
return false;
|
||||
}
|
||||
if (!emitTree(assignNode->right())) {
|
||||
if (!emitTree(initializer)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!emitDestructuringOps(pattern, DestructuringDeclaration)) {
|
||||
if (!emitDestructuringOps(&pattern->as<ListNode>(),
|
||||
DestructuringDeclaration)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!emit1(JSOP_POP)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
NameNode* name = &decl->as<NameNode>();
|
||||
if (!emitSingleDeclaration(declList, name, name->initializer())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
@ -5306,8 +5319,17 @@ bool BytecodeEmitter::emitInitializeForInOrOfTarget(TernaryNode* forHead) {
|
|||
target = parser->astGenerator().singleBindingFromDeclaration(
|
||||
&target->as<ListNode>());
|
||||
|
||||
NameNode* nameNode = nullptr;
|
||||
if (target->isKind(ParseNodeKind::Name)) {
|
||||
NameNode* nameNode = &target->as<NameNode>();
|
||||
nameNode = &target->as<NameNode>();
|
||||
} else if (target->isKind(ParseNodeKind::AssignExpr)) {
|
||||
AssignmentNode* assignNode = &target->as<AssignmentNode>();
|
||||
if (assignNode->left()->is<NameNode>()) {
|
||||
nameNode = &assignNode->left()->as<NameNode>();
|
||||
}
|
||||
}
|
||||
|
||||
if (nameNode) {
|
||||
NameOpEmitter noe(this, nameNode->name(), NameOpEmitter::Kind::Initialize);
|
||||
if (!noe.prepareForRhs()) {
|
||||
return false;
|
||||
|
@ -5440,8 +5462,11 @@ bool BytecodeEmitter::emitForIn(ForNode* forInLoop,
|
|||
if (parser->astGenerator().isDeclarationList(forInTarget)) {
|
||||
ParseNode* decl = parser->astGenerator().singleBindingFromDeclaration(
|
||||
&forInTarget->as<ListNode>());
|
||||
if (decl->isKind(ParseNodeKind::Name)) {
|
||||
if (ParseNode* initializer = decl->as<NameNode>().initializer()) {
|
||||
if (decl->isKind(ParseNodeKind::AssignExpr)) {
|
||||
AssignmentNode* assignNode = &decl->as<AssignmentNode>();
|
||||
if (assignNode->left()->is<NameNode>()) {
|
||||
NameNode* nameNode = &assignNode->left()->as<NameNode>();
|
||||
ParseNode* initializer = assignNode->right();
|
||||
MOZ_ASSERT(
|
||||
forInTarget->isKind(ParseNodeKind::VarStmt),
|
||||
"for-in initializers are only permitted for |var| declarations");
|
||||
|
@ -5450,13 +5475,12 @@ bool BytecodeEmitter::emitForIn(ForNode* forInLoop,
|
|||
return false;
|
||||
}
|
||||
|
||||
NameNode* nameNode = &decl->as<NameNode>();
|
||||
NameOpEmitter noe(this, nameNode->name(),
|
||||
NameOpEmitter::Kind::Initialize);
|
||||
if (!noe.prepareForRhs()) {
|
||||
return false;
|
||||
}
|
||||
if (!emitInitializer(initializer, decl)) {
|
||||
if (!emitInitializer(initializer, nameNode)) {
|
||||
return false;
|
||||
}
|
||||
if (!noe.emitAssignment()) {
|
||||
|
|
|
@ -879,8 +879,15 @@ class FullParseHandler {
|
|||
node->isKind(ParseNodeKind::ComputedName);
|
||||
}
|
||||
|
||||
inline MOZ_MUST_USE bool finishInitializerAssignment(NameNodeType nameNode,
|
||||
Node init);
|
||||
AssignmentNodeType finishInitializerAssignment(NameNodeType nameNode,
|
||||
Node init) {
|
||||
MOZ_ASSERT(nameNode->isKind(ParseNodeKind::Name));
|
||||
MOZ_ASSERT(!nameNode->isInParens());
|
||||
|
||||
checkAndSetIsDirectRHSAnonFunction(init);
|
||||
|
||||
return newAssignment(ParseNodeKind::AssignExpr, nameNode, init);
|
||||
}
|
||||
|
||||
void setBeginPosition(Node pn, Node oth) {
|
||||
setBeginPosition(pn, oth->pn_pos.begin);
|
||||
|
@ -1027,21 +1034,6 @@ inline bool FullParseHandler::setLastFunctionFormalParameterDefault(
|
|||
return true;
|
||||
}
|
||||
|
||||
inline bool FullParseHandler::finishInitializerAssignment(NameNodeType nameNode,
|
||||
Node init) {
|
||||
MOZ_ASSERT(nameNode->isKind(ParseNodeKind::Name));
|
||||
MOZ_ASSERT(!nameNode->isInParens());
|
||||
|
||||
checkAndSetIsDirectRHSAnonFunction(init);
|
||||
|
||||
nameNode->setInitializer(init);
|
||||
nameNode->setOp(JSOP_SETNAME);
|
||||
|
||||
/* The declarator's position must include the initializer. */
|
||||
nameNode->pn_pos.end = init->pn_pos.end;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace frontend
|
||||
} // namespace js
|
||||
|
||||
|
|
|
@ -419,9 +419,7 @@ class NameResolver : public ParseNodeVisitor<NameResolver> {
|
|||
MOZ_ASSERT(spec->isKind(isImport ? ParseNodeKind::ImportSpec
|
||||
: ParseNodeKind::ExportSpec));
|
||||
MOZ_ASSERT(spec->left()->isKind(ParseNodeKind::Name));
|
||||
MOZ_ASSERT(!spec->left()->as<NameNode>().initializer());
|
||||
MOZ_ASSERT(spec->right()->isKind(ParseNodeKind::Name));
|
||||
MOZ_ASSERT(!spec->right()->as<NameNode>().initializer());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -311,12 +311,8 @@ void NameNode::dumpImpl(GenericPrinter& out, int indent) {
|
|||
out.put("#<null name>");
|
||||
} else if (getOp() == JSOP_GETARG && atom()->length() == 0) {
|
||||
// Dump destructuring parameter.
|
||||
static const char ZeroLengthPrefix[] = "(#<zero-length name> ";
|
||||
constexpr size_t ZeroLengthPrefixLength =
|
||||
ArrayLength(ZeroLengthPrefix) - 1;
|
||||
out.put(ZeroLengthPrefix);
|
||||
DumpParseTree(initializer(), out, indent + ZeroLengthPrefixLength);
|
||||
out.printf(")");
|
||||
static const char ZeroLengthName[] = "(#<zero-length name>)";
|
||||
out.put(ZeroLengthName);
|
||||
} else {
|
||||
JS::AutoCheckCannotGC nogc;
|
||||
if (atom()->hasLatin1Chars()) {
|
||||
|
@ -328,26 +324,28 @@ void NameNode::dumpImpl(GenericPrinter& out, int indent) {
|
|||
return;
|
||||
|
||||
case ParseNodeKind::LabelStmt: {
|
||||
const char* name = parseNodeNames[size_t(getKind())];
|
||||
out.printf("(%s ", name);
|
||||
atom()->dumpCharsNoNewline(out);
|
||||
indent += strlen(name) + atom()->length() + 2;
|
||||
DumpParseTree(initializer(), out, indent);
|
||||
out.printf(")");
|
||||
this->as<LabeledStatement>().dumpImpl(out, indent);
|
||||
return;
|
||||
}
|
||||
|
||||
default: {
|
||||
const char* name = parseNodeNames[size_t(getKind())];
|
||||
out.printf("(%s ", name);
|
||||
indent += strlen(name) + 2;
|
||||
DumpParseTree(initializer(), out, indent);
|
||||
out.printf(")");
|
||||
out.printf("(%s)", name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LabeledStatement::dumpImpl(GenericPrinter& out, int indent) {
|
||||
const char* name = parseNodeNames[size_t(getKind())];
|
||||
out.printf("(%s ", name);
|
||||
atom()->dumpCharsNoNewline(out);
|
||||
out.printf(" ");
|
||||
indent += strlen(name) + atom()->length() + 3;
|
||||
DumpParseTree(statement(), out, indent);
|
||||
out.printf(")");
|
||||
}
|
||||
|
||||
void LexicalScopeNode::dumpImpl(GenericPrinter& out, int indent) {
|
||||
const char* name = parseNodeNames[size_t(getKind())];
|
||||
out.printf("(%s [", name);
|
||||
|
|
|
@ -796,20 +796,11 @@ class NullaryNode : public ParseNode {
|
|||
};
|
||||
|
||||
class NameNode : public ParseNode {
|
||||
JSAtom* atom_; /* lexical name or label atom */
|
||||
ParseNode* initOrStmt; /* var initializer, argument default, or label
|
||||
statement target */
|
||||
|
||||
protected:
|
||||
NameNode(ParseNodeKind kind, JSOp op, JSAtom* atom, ParseNode* initOrStmt,
|
||||
const TokenPos& pos)
|
||||
: ParseNode(kind, op, pos), atom_(atom), initOrStmt(initOrStmt) {
|
||||
MOZ_ASSERT(is<NameNode>());
|
||||
}
|
||||
JSAtom* atom_; /* lexical name or label atom */
|
||||
|
||||
public:
|
||||
NameNode(ParseNodeKind kind, JSOp op, JSAtom* atom, const TokenPos& pos)
|
||||
: ParseNode(kind, op, pos), atom_(atom), initOrStmt(nullptr) {
|
||||
: ParseNode(kind, op, pos), atom_(atom) {
|
||||
MOZ_ASSERT(is<NameNode>());
|
||||
}
|
||||
|
||||
|
@ -821,11 +812,6 @@ class NameNode : public ParseNode {
|
|||
|
||||
template <typename Visitor>
|
||||
bool accept(Visitor& visitor) {
|
||||
if (initOrStmt) {
|
||||
if (!visitor.visit(initOrStmt)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -840,11 +826,7 @@ class NameNode : public ParseNode {
|
|||
return atom()->asPropertyName();
|
||||
}
|
||||
|
||||
ParseNode* initializer() const { return initOrStmt; }
|
||||
|
||||
void setAtom(JSAtom* atom) { atom_ = atom; }
|
||||
|
||||
void setInitializer(ParseNode* init) { initOrStmt = init; }
|
||||
};
|
||||
|
||||
inline bool ParseNode::isName(PropertyName* name) const {
|
||||
|
@ -1596,18 +1578,35 @@ class LexicalScopeNode : public ParseNode {
|
|||
};
|
||||
|
||||
class LabeledStatement : public NameNode {
|
||||
ParseNode* statement_;
|
||||
|
||||
public:
|
||||
LabeledStatement(PropertyName* label, ParseNode* stmt, uint32_t begin)
|
||||
: NameNode(ParseNodeKind::LabelStmt, JSOP_NOP, label, stmt,
|
||||
TokenPos(begin, stmt->pn_pos.end)) {}
|
||||
: NameNode(ParseNodeKind::LabelStmt, JSOP_NOP, label,
|
||||
TokenPos(begin, stmt->pn_pos.end)),
|
||||
statement_(stmt) {}
|
||||
|
||||
PropertyName* label() const { return atom()->asPropertyName(); }
|
||||
|
||||
ParseNode* statement() const { return initializer(); }
|
||||
ParseNode* statement() const { return statement_; }
|
||||
|
||||
static bool test(const ParseNode& node) {
|
||||
return node.isKind(ParseNodeKind::LabelStmt);
|
||||
}
|
||||
|
||||
template <typename Visitor>
|
||||
bool accept(Visitor& visitor) {
|
||||
if (statement_) {
|
||||
if (!visitor.visit(statement_)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void dumpImpl(GenericPrinter& out, int indent);
|
||||
#endif
|
||||
};
|
||||
|
||||
// Inside a switch statement, a CaseClause is a case-label and the subsequent
|
||||
|
|
|
@ -4097,7 +4097,8 @@ GeneralParser<ParseHandler, Unit>::declarationPattern(
|
|||
}
|
||||
|
||||
template <class ParseHandler, typename Unit>
|
||||
bool GeneralParser<ParseHandler, Unit>::initializerInNameDeclaration(
|
||||
typename ParseHandler::Node
|
||||
GeneralParser<ParseHandler, Unit>::initializerInNameDeclaration(
|
||||
NameNodeType binding, DeclarationKind declKind, bool initialDeclaration,
|
||||
YieldHandling yieldHandling, ParseNodeKind* forHeadKind,
|
||||
Node* forInOrOfExpression) {
|
||||
|
@ -4105,19 +4106,19 @@ bool GeneralParser<ParseHandler, Unit>::initializerInNameDeclaration(
|
|||
|
||||
uint32_t initializerOffset;
|
||||
if (!tokenStream.peekOffset(&initializerOffset, TokenStream::Operand)) {
|
||||
return false;
|
||||
return null();
|
||||
}
|
||||
|
||||
Node initializer = assignExpr(forHeadKind ? InProhibited : InAllowed,
|
||||
yieldHandling, TripledotProhibited);
|
||||
if (!initializer) {
|
||||
return false;
|
||||
return null();
|
||||
}
|
||||
|
||||
if (forHeadKind && initialDeclaration) {
|
||||
bool isForIn, isForOf;
|
||||
if (!matchInOrOf(&isForIn, &isForOf)) {
|
||||
return false;
|
||||
return null();
|
||||
}
|
||||
|
||||
// An initialized declaration can't appear in a for-of:
|
||||
|
@ -4125,7 +4126,7 @@ bool GeneralParser<ParseHandler, Unit>::initializerInNameDeclaration(
|
|||
// for (var/let/const x = ... of ...); // BAD
|
||||
if (isForOf) {
|
||||
errorAt(initializerOffset, JSMSG_OF_AFTER_FOR_LOOP_DECL);
|
||||
return false;
|
||||
return null();
|
||||
}
|
||||
|
||||
if (isForIn) {
|
||||
|
@ -4134,7 +4135,7 @@ bool GeneralParser<ParseHandler, Unit>::initializerInNameDeclaration(
|
|||
// for (let/const x = ... in ...); // BAD
|
||||
if (DeclarationKindIsLexical(declKind)) {
|
||||
errorAt(initializerOffset, JSMSG_IN_AFTER_LEXICAL_FOR_DECL);
|
||||
return false;
|
||||
return null();
|
||||
}
|
||||
|
||||
// This leaves only initialized for-in |var| declarations. ES6
|
||||
|
@ -4142,13 +4143,13 @@ bool GeneralParser<ParseHandler, Unit>::initializerInNameDeclaration(
|
|||
*forHeadKind = ParseNodeKind::ForIn;
|
||||
if (!strictModeErrorAt(initializerOffset,
|
||||
JSMSG_INVALID_FOR_IN_DECL_WITH_INIT)) {
|
||||
return false;
|
||||
return null();
|
||||
}
|
||||
|
||||
*forInOrOfExpression =
|
||||
expressionAfterForInOrOf(ParseNodeKind::ForIn, yieldHandling);
|
||||
if (!*forInOrOfExpression) {
|
||||
return false;
|
||||
return null();
|
||||
}
|
||||
} else {
|
||||
*forHeadKind = ParseNodeKind::ForHead;
|
||||
|
@ -4159,13 +4160,10 @@ bool GeneralParser<ParseHandler, Unit>::initializerInNameDeclaration(
|
|||
}
|
||||
|
||||
template <class ParseHandler, typename Unit>
|
||||
typename ParseHandler::NameNodeType
|
||||
GeneralParser<ParseHandler, Unit>::declarationName(DeclarationKind declKind,
|
||||
TokenKind tt,
|
||||
bool initialDeclaration,
|
||||
YieldHandling yieldHandling,
|
||||
ParseNodeKind* forHeadKind,
|
||||
Node* forInOrOfExpression) {
|
||||
typename ParseHandler::Node GeneralParser<ParseHandler, Unit>::declarationName(
|
||||
DeclarationKind declKind, TokenKind tt, bool initialDeclaration,
|
||||
YieldHandling yieldHandling, ParseNodeKind* forHeadKind,
|
||||
Node* forInOrOfExpression) {
|
||||
// Anything other than possible identifier is an error.
|
||||
if (!TokenKindIsPossibleIdentifier(tt)) {
|
||||
error(JSMSG_NO_VARIABLE_NAME);
|
||||
|
@ -4197,13 +4195,17 @@ GeneralParser<ParseHandler, Unit>::declarationName(DeclarationKind declKind,
|
|||
return null();
|
||||
}
|
||||
|
||||
Node declaration;
|
||||
if (matched) {
|
||||
if (!initializerInNameDeclaration(binding, declKind, initialDeclaration,
|
||||
yieldHandling, forHeadKind,
|
||||
forInOrOfExpression)) {
|
||||
declaration = initializerInNameDeclaration(
|
||||
binding, declKind, initialDeclaration, yieldHandling, forHeadKind,
|
||||
forInOrOfExpression);
|
||||
if (!declaration) {
|
||||
return null();
|
||||
}
|
||||
} else {
|
||||
declaration = binding;
|
||||
|
||||
if (initialDeclaration && forHeadKind) {
|
||||
bool isForIn, isForOf;
|
||||
if (!matchInOrOf(&isForIn, &isForOf)) {
|
||||
|
@ -4241,7 +4243,7 @@ GeneralParser<ParseHandler, Unit>::declarationName(DeclarationKind declKind,
|
|||
return null();
|
||||
}
|
||||
|
||||
return binding;
|
||||
return declaration;
|
||||
}
|
||||
|
||||
template <class ParseHandler, typename Unit>
|
||||
|
|
|
@ -1200,18 +1200,16 @@ class MOZ_STACK_CLASS GeneralParser : public PerHandlerParser<ParseHandler> {
|
|||
bool initialDeclaration, YieldHandling yieldHandling,
|
||||
ParseNodeKind* forHeadKind,
|
||||
Node* forInOrOfExpression);
|
||||
NameNodeType declarationName(DeclarationKind declKind, TokenKind tt,
|
||||
bool initialDeclaration,
|
||||
YieldHandling yieldHandling,
|
||||
ParseNodeKind* forHeadKind,
|
||||
Node* forInOrOfExpression);
|
||||
Node declarationName(DeclarationKind declKind, TokenKind tt,
|
||||
bool initialDeclaration, YieldHandling yieldHandling,
|
||||
ParseNodeKind* forHeadKind, Node* forInOrOfExpression);
|
||||
|
||||
// Having parsed a name (not found in a destructuring pattern) declared by
|
||||
// a declaration, with the current token being the '=' separating the name
|
||||
// from its initializer, parse and bind that initializer -- and possibly
|
||||
// consume trailing in/of and subsequent expression, if so directed by
|
||||
// |forHeadKind|.
|
||||
bool initializerInNameDeclaration(NameNodeType binding,
|
||||
Node initializerInNameDeclaration(NameNodeType binding,
|
||||
DeclarationKind declKind,
|
||||
bool initialDeclaration,
|
||||
YieldHandling yieldHandling,
|
||||
|
|
|
@ -517,9 +517,9 @@ class SyntaxParseHandler {
|
|||
return NodeGeneric;
|
||||
}
|
||||
|
||||
MOZ_MUST_USE bool finishInitializerAssignment(NameNodeType nameNode,
|
||||
Node init) {
|
||||
return true;
|
||||
AssignmentNodeType finishInitializerAssignment(NameNodeType nameNode,
|
||||
Node init) {
|
||||
return NodeUnparenthesizedAssignment;
|
||||
}
|
||||
|
||||
void setBeginPosition(Node pn, Node oth) {}
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
|
||||
#include "jit/BaselineFrameInfo-inl.h"
|
||||
#include "jit/MacroAssembler-inl.h"
|
||||
#include "jit/VMFunctionList-inl.h"
|
||||
#include "vm/Interpreter-inl.h"
|
||||
#include "vm/JSScript-inl.h"
|
||||
#include "vm/NativeObject-inl.h"
|
||||
|
@ -584,10 +585,8 @@ void BaselineInterpreterCodeGen::storeFrameSizeAndPushDescriptor(
|
|||
}
|
||||
|
||||
template <typename Handler>
|
||||
bool BaselineCodeGen<Handler>::callVM(const VMFunction& fun,
|
||||
CallVMPhase phase) {
|
||||
TrampolinePtr code = cx->runtime()->jitRuntime()->getVMWrapper(fun);
|
||||
|
||||
bool BaselineCodeGen<Handler>::callVM(const VMFunctionData& fun,
|
||||
TrampolinePtr code, CallVMPhase phase) {
|
||||
#ifdef DEBUG
|
||||
// Assert prepareVMCall() has been called.
|
||||
MOZ_ASSERT(inCall_);
|
||||
|
@ -665,6 +664,21 @@ bool BaselineCodeGen<Handler>::callVM(const VMFunction& fun,
|
|||
return handler.appendRetAddrEntry(cx, RetAddrEntry::Kind::CallVM, callOffset);
|
||||
}
|
||||
|
||||
template <typename Handler>
|
||||
bool BaselineCodeGen<Handler>::callVM(const VMFunction& fun,
|
||||
CallVMPhase phase) {
|
||||
TrampolinePtr code = cx->runtime()->jitRuntime()->getVMWrapper(fun);
|
||||
return callVM(fun, code, phase);
|
||||
}
|
||||
|
||||
template <typename Handler>
|
||||
template <typename Fn, Fn fn>
|
||||
bool BaselineCodeGen<Handler>::callVM(CallVMPhase phase) {
|
||||
VMFunctionId fnId = VMFunctionToId<Fn, fn>::id;
|
||||
TrampolinePtr code = cx->runtime()->jitRuntime()->getVMWrapper(fnId);
|
||||
return callVM(GetVMFunction(fnId), code, phase);
|
||||
}
|
||||
|
||||
typedef bool (*CheckOverRecursedBaselineFn)(JSContext*, BaselineFrame*);
|
||||
static const VMFunction CheckOverRecursedBaselineInfo =
|
||||
FunctionInfo<CheckOverRecursedBaselineFn>(CheckOverRecursedBaseline,
|
||||
|
@ -887,10 +901,6 @@ void BaselineInterpreterCodeGen::loadResumeIndexBytecodeOperand(Register dest) {
|
|||
MOZ_CRASH("NYI: interpreter loadResumeIndexBytecodeOperand");
|
||||
}
|
||||
|
||||
typedef bool (*DebugPrologueFn)(JSContext*, BaselineFrame*, jsbytecode*, bool*);
|
||||
static const VMFunction DebugPrologueInfo =
|
||||
FunctionInfo<DebugPrologueFn>(jit::DebugPrologue, "DebugPrologue");
|
||||
|
||||
template <typename Handler>
|
||||
bool BaselineCodeGen<Handler>::emitDebugPrologue() {
|
||||
auto ifDebuggee = [this]() {
|
||||
|
@ -900,7 +910,9 @@ bool BaselineCodeGen<Handler>::emitDebugPrologue() {
|
|||
prepareVMCall();
|
||||
pushBytecodePCArg();
|
||||
pushArg(R0.scratchReg());
|
||||
if (!callVM(DebugPrologueInfo)) {
|
||||
|
||||
using Fn = bool (*)(JSContext*, BaselineFrame*, jsbytecode*, bool*);
|
||||
if (!callVM<Fn, jit::DebugPrologue>()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1009,10 +1021,6 @@ bool BaselineInterpreterCodeGen::initEnvironmentChain() {
|
|||
MOZ_CRASH("NYI: interpreter initEnvironmentChain");
|
||||
}
|
||||
|
||||
typedef bool (*InterruptCheckFn)(JSContext*);
|
||||
static const VMFunction InterruptCheckInfo =
|
||||
FunctionInfo<InterruptCheckFn>(InterruptCheck, "InterruptCheck");
|
||||
|
||||
template <typename Handler>
|
||||
bool BaselineCodeGen<Handler>::emitInterruptCheck() {
|
||||
frame.syncStack(0);
|
||||
|
@ -1022,7 +1030,9 @@ bool BaselineCodeGen<Handler>::emitInterruptCheck() {
|
|||
Imm32(0), &done);
|
||||
|
||||
prepareVMCall();
|
||||
if (!callVM(InterruptCheckInfo)) {
|
||||
|
||||
using Fn = bool (*)(JSContext*);
|
||||
if (!callVM<Fn, InterruptCheck>()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1030,12 +1040,6 @@ bool BaselineCodeGen<Handler>::emitInterruptCheck() {
|
|||
return true;
|
||||
}
|
||||
|
||||
typedef bool (*IonCompileScriptForBaselineFn)(JSContext*, BaselineFrame*,
|
||||
jsbytecode*);
|
||||
static const VMFunction IonCompileScriptForBaselineInfo =
|
||||
FunctionInfo<IonCompileScriptForBaselineFn>(IonCompileScriptForBaseline,
|
||||
"IonCompileScriptForBaseline");
|
||||
|
||||
template <>
|
||||
bool BaselineCompilerCodeGen::emitWarmUpCounterIncrement() {
|
||||
// Emit no warm-up counter increments or bailouts if Ion is not
|
||||
|
@ -1099,7 +1103,8 @@ bool BaselineCompilerCodeGen::emitWarmUpCounterIncrement() {
|
|||
pushBytecodePCArg();
|
||||
masm.PushBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
|
||||
|
||||
if (!callVM(IonCompileScriptForBaselineInfo)) {
|
||||
using Fn = bool (*)(JSContext*, BaselineFrame*, jsbytecode*);
|
||||
if (!callVM<Fn, IonCompileScriptForBaseline>()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1782,11 +1787,6 @@ bool BaselineCodeGen<Handler>::emit_JSOP_NULL() {
|
|||
return true;
|
||||
}
|
||||
|
||||
typedef bool (*ThrowCheckIsObjectFn)(JSContext*, CheckIsObjectKind);
|
||||
static const VMFunction ThrowCheckIsObjectInfo =
|
||||
FunctionInfo<ThrowCheckIsObjectFn>(ThrowCheckIsObject,
|
||||
"ThrowCheckIsObject");
|
||||
|
||||
template <typename Handler>
|
||||
bool BaselineCodeGen<Handler>::emit_JSOP_CHECKISOBJ() {
|
||||
frame.syncStack(0);
|
||||
|
@ -1798,7 +1798,9 @@ bool BaselineCodeGen<Handler>::emit_JSOP_CHECKISOBJ() {
|
|||
prepareVMCall();
|
||||
|
||||
pushUint8BytecodeOperandArg();
|
||||
if (!callVM(ThrowCheckIsObjectInfo)) {
|
||||
|
||||
using Fn = bool (*)(JSContext*, CheckIsObjectKind);
|
||||
if (!callVM<Fn, ThrowCheckIsObject>()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1806,10 +1808,6 @@ bool BaselineCodeGen<Handler>::emit_JSOP_CHECKISOBJ() {
|
|||
return true;
|
||||
}
|
||||
|
||||
typedef bool (*CheckIsCallableFn)(JSContext*, HandleValue, CheckIsCallableKind);
|
||||
static const VMFunction CheckIsCallableInfo =
|
||||
FunctionInfo<CheckIsCallableFn>(CheckIsCallable, "CheckIsCallable");
|
||||
|
||||
template <typename Handler>
|
||||
bool BaselineCodeGen<Handler>::emit_JSOP_CHECKISCALLABLE() {
|
||||
frame.syncStack(0);
|
||||
|
@ -1819,23 +1817,15 @@ bool BaselineCodeGen<Handler>::emit_JSOP_CHECKISCALLABLE() {
|
|||
|
||||
pushUint8BytecodeOperandArg();
|
||||
pushArg(R0);
|
||||
if (!callVM(CheckIsCallableInfo)) {
|
||||
|
||||
using Fn = bool (*)(JSContext*, HandleValue, CheckIsCallableKind);
|
||||
if (!callVM<Fn, CheckIsCallable>()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
typedef bool (*ThrowUninitializedThisFn)(JSContext*, BaselineFrame* frame);
|
||||
static const VMFunction ThrowUninitializedThisInfo =
|
||||
FunctionInfo<ThrowUninitializedThisFn>(BaselineThrowUninitializedThis,
|
||||
"BaselineThrowUninitializedThis");
|
||||
|
||||
typedef bool (*ThrowInitializedThisFn)(JSContext*);
|
||||
static const VMFunction ThrowInitializedThisInfo =
|
||||
FunctionInfo<ThrowInitializedThisFn>(BaselineThrowInitializedThis,
|
||||
"BaselineThrowInitializedThis");
|
||||
|
||||
template <typename Handler>
|
||||
bool BaselineCodeGen<Handler>::emit_JSOP_CHECKTHIS() {
|
||||
frame.syncStack(0);
|
||||
|
@ -1864,14 +1854,16 @@ bool BaselineCodeGen<Handler>::emitCheckThis(ValueOperand val, bool reinit) {
|
|||
prepareVMCall();
|
||||
|
||||
if (reinit) {
|
||||
if (!callVM(ThrowInitializedThisInfo)) {
|
||||
using Fn = bool (*)(JSContext*);
|
||||
if (!callVM<Fn, BaselineThrowInitializedThis>()) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
masm.loadBaselineFramePtr(BaselineFrameReg, val.scratchReg());
|
||||
pushArg(val.scratchReg());
|
||||
|
||||
if (!callVM(ThrowUninitializedThisInfo)) {
|
||||
using Fn = bool (*)(JSContext*, BaselineFrame*);
|
||||
if (!callVM<Fn, BaselineThrowUninitializedThis>()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -1880,11 +1872,6 @@ bool BaselineCodeGen<Handler>::emitCheckThis(ValueOperand val, bool reinit) {
|
|||
return true;
|
||||
}
|
||||
|
||||
typedef bool (*ThrowBadDerivedReturnFn)(JSContext*, HandleValue);
|
||||
static const VMFunction ThrowBadDerivedReturnInfo =
|
||||
FunctionInfo<ThrowBadDerivedReturnFn>(jit::ThrowBadDerivedReturn,
|
||||
"ThrowBadDerivedReturn");
|
||||
|
||||
template <typename Handler>
|
||||
bool BaselineCodeGen<Handler>::emit_JSOP_CHECKRETURN() {
|
||||
MOZ_ASSERT_IF(handler.maybeScript(),
|
||||
|
@ -1900,7 +1887,9 @@ bool BaselineCodeGen<Handler>::emit_JSOP_CHECKRETURN() {
|
|||
|
||||
prepareVMCall();
|
||||
pushArg(R1);
|
||||
if (!callVM(ThrowBadDerivedReturnInfo)) {
|
||||
|
||||
using Fn = bool (*)(JSContext*, HandleValue);
|
||||
if (!callVM<Fn, ThrowBadDerivedReturn>()) {
|
||||
return false;
|
||||
}
|
||||
masm.assumeUnreachable("Should throw on bad derived constructor return");
|
||||
|
@ -1919,11 +1908,6 @@ bool BaselineCodeGen<Handler>::emit_JSOP_CHECKRETURN() {
|
|||
return true;
|
||||
}
|
||||
|
||||
typedef bool (*GetFunctionThisFn)(JSContext*, BaselineFrame*,
|
||||
MutableHandleValue);
|
||||
static const VMFunction GetFunctionThisInfo = FunctionInfo<GetFunctionThisFn>(
|
||||
jit::BaselineGetFunctionThis, "BaselineGetFunctionThis");
|
||||
|
||||
template <typename Handler>
|
||||
bool BaselineCodeGen<Handler>::emit_JSOP_FUNCTIONTHIS() {
|
||||
MOZ_ASSERT_IF(handler.maybeFunction(), !handler.maybeFunction()->isArrow());
|
||||
|
@ -1941,7 +1925,8 @@ bool BaselineCodeGen<Handler>::emit_JSOP_FUNCTIONTHIS() {
|
|||
|
||||
pushArg(R1.scratchReg());
|
||||
|
||||
if (!callVM(GetFunctionThisInfo)) {
|
||||
using Fn = bool (*)(JSContext*, BaselineFrame*, MutableHandleValue);
|
||||
if (!callVM<Fn, BaselineGetFunctionThis>()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1955,12 +1940,6 @@ bool BaselineCodeGen<Handler>::emit_JSOP_FUNCTIONTHIS() {
|
|||
R2.scratchReg());
|
||||
}
|
||||
|
||||
typedef void (*GetNonSyntacticGlobalThisFn)(JSContext*, HandleObject,
|
||||
MutableHandleValue);
|
||||
static const VMFunction GetNonSyntacticGlobalThisInfo =
|
||||
FunctionInfo<GetNonSyntacticGlobalThisFn>(js::GetNonSyntacticGlobalThis,
|
||||
"GetNonSyntacticGlobalThis");
|
||||
|
||||
template <typename Handler>
|
||||
bool BaselineCodeGen<Handler>::emit_JSOP_GLOBALTHIS() {
|
||||
frame.syncStack(0);
|
||||
|
@ -1971,7 +1950,8 @@ bool BaselineCodeGen<Handler>::emit_JSOP_GLOBALTHIS() {
|
|||
masm.loadPtr(frame.addressOfEnvironmentChain(), R0.scratchReg());
|
||||
pushArg(R0.scratchReg());
|
||||
|
||||
if (!callVM(GetNonSyntacticGlobalThisInfo)) {
|
||||
using Fn = void (*)(JSContext*, HandleObject, MutableHandleValue);
|
||||
if (!callVM<Fn, GetNonSyntacticGlobalThis>()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -346,8 +346,13 @@ class BaselineCodeGen {
|
|||
Register scratch1, Register scratch2);
|
||||
|
||||
enum CallVMPhase { POST_INITIALIZE, CHECK_OVER_RECURSED };
|
||||
bool callVM(const VMFunctionData& fun, TrampolinePtr code,
|
||||
CallVMPhase phase = POST_INITIALIZE);
|
||||
bool callVM(const VMFunction& fun, CallVMPhase phase = POST_INITIALIZE);
|
||||
|
||||
template <typename Fn, Fn fn>
|
||||
bool callVM(CallVMPhase phase = POST_INITIALIZE);
|
||||
|
||||
bool callVMNonOp(const VMFunction& fun, CallVMPhase phase = POST_INITIALIZE) {
|
||||
if (!callVM(fun, phase)) {
|
||||
return false;
|
||||
|
|
|
@ -8912,8 +8912,8 @@ void JitRuntime::generateDoubleToInt32ValueStub(MacroAssembler& masm) {
|
|||
masm.abiret();
|
||||
}
|
||||
|
||||
bool JitRuntime::generateTLEventVM(MacroAssembler& masm, const VMFunction& f,
|
||||
bool enter) {
|
||||
bool JitRuntime::generateTLEventVM(MacroAssembler& masm,
|
||||
const VMFunctionData& f, bool enter) {
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
bool vmEventEnabled = TraceLogTextIdEnabled(TraceLogger_VM);
|
||||
bool vmSpecificEventEnabled = TraceLogTextIdEnabled(TraceLogger_VMSpecific);
|
||||
|
|
|
@ -286,13 +286,22 @@ bool JitRuntime::initialize(JSContext* cx) {
|
|||
generateDoubleToInt32ValueStub(masm);
|
||||
|
||||
JitSpew(JitSpew_Codegen, "# Emitting VM function wrappers");
|
||||
if (!generateVMWrappers(cx, masm)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO(bug 1530937): remove this after converting all VM functions.
|
||||
for (VMFunction* fun = VMFunction::functions; fun; fun = fun->next) {
|
||||
if (functionWrappers_->has(fun)) {
|
||||
// Duplicate VMFunction definition. See VMFunction::hash.
|
||||
continue;
|
||||
}
|
||||
JitSpew(JitSpew_Codegen, "# VM function wrapper (%s)", fun->name());
|
||||
if (!generateVMWrapper(cx, masm, *fun)) {
|
||||
uint32_t offset;
|
||||
if (!generateVMWrapper(cx, masm, *fun, &offset)) {
|
||||
return false;
|
||||
}
|
||||
if (!functionWrappers_->putNew(fun, offset)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1022,7 +1022,8 @@ uint8_t* alignDoubleSpillWithOffset(uint8_t* pointer, int32_t offset) {
|
|||
return reinterpret_cast<uint8_t*>(address);
|
||||
}
|
||||
|
||||
static void TraceJitExitFrameCopiedArguments(JSTracer* trc, const VMFunction* f,
|
||||
static void TraceJitExitFrameCopiedArguments(JSTracer* trc,
|
||||
const VMFunctionData* f,
|
||||
ExitFooterFrame* footer) {
|
||||
uint8_t* doubleArgs = reinterpret_cast<uint8_t*>(footer);
|
||||
doubleArgs = alignDoubleSpillWithOffset(doubleArgs, sizeof(intptr_t));
|
||||
|
@ -1044,7 +1045,8 @@ static void TraceJitExitFrameCopiedArguments(JSTracer* trc, const VMFunction* f,
|
|||
}
|
||||
}
|
||||
#else
|
||||
static void TraceJitExitFrameCopiedArguments(JSTracer* trc, const VMFunction* f,
|
||||
static void TraceJitExitFrameCopiedArguments(JSTracer* trc,
|
||||
const VMFunctionData* f,
|
||||
ExitFooterFrame* footer) {
|
||||
// This is NO-OP on other platforms.
|
||||
}
|
||||
|
@ -1127,7 +1129,7 @@ static void TraceJitExitFrame(JSTracer* trc, const JSJitFrameIter& frame) {
|
|||
|
||||
MOZ_ASSERT(frame.exitFrame()->isWrapperExit());
|
||||
|
||||
const VMFunction* f = footer->function();
|
||||
const VMFunctionData* f = footer->function();
|
||||
MOZ_ASSERT(f);
|
||||
|
||||
// Trace arguments of the VM wrapper.
|
||||
|
|
|
@ -17,6 +17,7 @@ namespace js {
|
|||
namespace jit {
|
||||
|
||||
struct SafepointSlotEntry;
|
||||
struct VMFunctionData;
|
||||
|
||||
enum CalleeTokenTag {
|
||||
CalleeToken_Function = 0x0, // untagged
|
||||
|
@ -418,7 +419,7 @@ enum class ExitFrameType : uint8_t {
|
|||
// GC related data used to keep alive data surrounding the Exit frame.
|
||||
class ExitFooterFrame {
|
||||
// Stores the ExitFrameType or, for ExitFrameType::VMFunction, the
|
||||
// VMFunction*.
|
||||
// VMFunctionData*.
|
||||
uintptr_t data_;
|
||||
|
||||
public:
|
||||
|
@ -433,9 +434,9 @@ class ExitFooterFrame {
|
|||
MOZ_ASSERT(ExitFrameType(data_) != ExitFrameType::VMFunction);
|
||||
return ExitFrameType(data_);
|
||||
}
|
||||
inline const VMFunction* function() const {
|
||||
inline const VMFunctionData* function() const {
|
||||
MOZ_ASSERT(type() == ExitFrameType::VMFunction);
|
||||
return reinterpret_cast<const VMFunction*>(data_);
|
||||
return reinterpret_cast<const VMFunctionData*>(data_);
|
||||
}
|
||||
|
||||
// This should only be called for function()->outParam == Type_Handle
|
||||
|
|
|
@ -28,6 +28,8 @@ namespace js {
|
|||
namespace jit {
|
||||
|
||||
class FrameSizeClass;
|
||||
struct VMFunctionData;
|
||||
enum class VMFunctionId;
|
||||
|
||||
struct EnterJitData {
|
||||
explicit EnterJitData(JSContext* cx)
|
||||
|
@ -143,6 +145,10 @@ class JitRuntime {
|
|||
using VMWrapperMap = HashMap<const VMFunction*, uint32_t, VMFunction>;
|
||||
WriteOnceData<VMWrapperMap*> functionWrappers_;
|
||||
|
||||
// Maps VMFunctionId to the offset of the wrapper code in trampolineCode_.
|
||||
using VMWrapperOffsets = Vector<uint32_t, 0, SystemAllocPolicy>;
|
||||
VMWrapperOffsets functionWrapperOffsets_;
|
||||
|
||||
// Global table of jitcode native address => bytecode address mappings.
|
||||
UnprotectedData<JitcodeGlobalTable*> jitcodeGlobalTable_;
|
||||
|
||||
|
@ -190,15 +196,18 @@ class JitRuntime {
|
|||
JitCode* generateDebugTrapHandler(JSContext* cx);
|
||||
JitCode* generateBaselineDebugModeOSRHandler(
|
||||
JSContext* cx, uint32_t* noFrameRegPopOffsetOut);
|
||||
|
||||
bool generateVMWrapper(JSContext* cx, MacroAssembler& masm,
|
||||
const VMFunction& f);
|
||||
const VMFunctionData& f, uint32_t* wrapperOffset);
|
||||
bool generateVMWrappers(JSContext* cx, MacroAssembler& masm);
|
||||
|
||||
bool generateTLEventVM(MacroAssembler& masm, const VMFunction& f, bool enter);
|
||||
bool generateTLEventVM(MacroAssembler& masm, const VMFunctionData& f,
|
||||
bool enter);
|
||||
|
||||
inline bool generateTLEnterVM(MacroAssembler& masm, const VMFunction& f) {
|
||||
inline bool generateTLEnterVM(MacroAssembler& masm, const VMFunctionData& f) {
|
||||
return generateTLEventVM(masm, f, /* enter = */ true);
|
||||
}
|
||||
inline bool generateTLExitVM(MacroAssembler& masm, const VMFunction& f) {
|
||||
inline bool generateTLExitVM(MacroAssembler& masm, const VMFunctionData& f) {
|
||||
return generateTLEventVM(masm, f, /* enter = */ false);
|
||||
}
|
||||
|
||||
|
@ -227,6 +236,12 @@ class JitRuntime {
|
|||
}
|
||||
|
||||
TrampolinePtr getVMWrapper(const VMFunction& f) const;
|
||||
|
||||
TrampolinePtr getVMWrapper(const VMFunctionId funId) const {
|
||||
MOZ_ASSERT(trampolineCode_);
|
||||
return trampolineCode(functionWrapperOffsets_[size_t(funId)]);
|
||||
}
|
||||
|
||||
JitCode* debugTrapHandler(JSContext* cx);
|
||||
JitCode* getBaselineDebugModeOSRHandler(JSContext* cx);
|
||||
void* getBaselineDebugModeOSRHandlerAddress(JSContext* cx, bool popFrameReg);
|
||||
|
|
|
@ -260,7 +260,7 @@ uint32_t MacroAssembler::buildFakeExitFrame(Register scratch) {
|
|||
// Exit frame footer.
|
||||
|
||||
void MacroAssembler::enterExitFrame(Register cxreg, Register scratch,
|
||||
const VMFunction* f) {
|
||||
const VMFunctionData* f) {
|
||||
MOZ_ASSERT(f);
|
||||
linkExitFrame(cxreg, scratch);
|
||||
// Push VMFunction pointer, to mark arguments.
|
||||
|
|
|
@ -714,9 +714,9 @@ class MacroAssembler : public MacroAssemblerSpecific {
|
|||
//
|
||||
// See JitFrames.h, and MarkJitExitFrame in JitFrames.cpp.
|
||||
|
||||
// Push stub code and the VMFunction pointer.
|
||||
// Push stub code and the VMFunctionData pointer.
|
||||
inline void enterExitFrame(Register cxreg, Register scratch,
|
||||
const VMFunction* f);
|
||||
const VMFunctionData* f);
|
||||
|
||||
// Push an exit frame token to identify which fake exit frame this footer
|
||||
// corresponds to.
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: set ts=8 sts=2 et sw=2 tw=80:
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "jit/BaselineIC.h"
|
||||
#include "jit/JitRealm.h"
|
||||
#include "jit/VMFunctions.h"
|
||||
#include "vm/Interpreter.h"
|
||||
|
||||
#include "jit/BaselineFrame-inl.h"
|
||||
#include "vm/Interpreter-inl.h"
|
||||
|
||||
namespace js {
|
||||
namespace jit {
|
||||
|
||||
// List of all VM functions to be used with callVM. Each entry stores the name
|
||||
// (must be unique, used for the VMFunctionId enum and profiling) and the C++
|
||||
// function to be called. This list must be sorted on the name field.
|
||||
#define VMFUNCTION_LIST(_) \
|
||||
_(BaselineDebugPrologue, js::jit::DebugPrologue) \
|
||||
_(BaselineGetFunctionThis, js::jit::BaselineGetFunctionThis) \
|
||||
_(BaselineThrowInitializedThis, js::jit::BaselineThrowInitializedThis) \
|
||||
_(BaselineThrowUninitializedThis, js::jit::BaselineThrowUninitializedThis) \
|
||||
_(CheckIsCallable, js::jit::CheckIsCallable) \
|
||||
_(CheckOverRecursedBaseline, js::jit::CheckOverRecursedBaseline) \
|
||||
_(GetNonSyntacticGlobalThis, js::GetNonSyntacticGlobalThis) \
|
||||
_(InterruptCheck, js::jit::InterruptCheck) \
|
||||
_(IonCompileScriptForBaseline, js::jit::IonCompileScriptForBaseline) \
|
||||
_(ThrowBadDerivedReturn, js::jit::ThrowBadDerivedReturn) \
|
||||
_(ThrowCheckIsObject, js::ThrowCheckIsObject)
|
||||
|
||||
enum class VMFunctionId {
|
||||
#define DEF_ID(name, fp) name,
|
||||
VMFUNCTION_LIST(DEF_ID)
|
||||
#undef DEF_ID
|
||||
Count
|
||||
};
|
||||
|
||||
// Define the VMFunctionToId template to map from signature + function to
|
||||
// the VMFunctionId. This lets us verify the consumer/codegen code matches
|
||||
// the C++ signature.
|
||||
template <typename Function, Function fun>
|
||||
struct VMFunctionToId; // Error on this line? Forgot to update VMFUNCTION_LIST?
|
||||
|
||||
// GCC warns when the signature does not have matching attributes (for example
|
||||
// MOZ_MUST_USE). Squelch this warning to avoid a GCC-only footgun.
|
||||
#if MOZ_IS_GCC
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wignored-attributes"
|
||||
#endif
|
||||
|
||||
// Note: the use of ::fp instead of fp is intentional to enforce use of
|
||||
// fully-qualified names in the list above.
|
||||
#define DEF_TEMPLATE(name, fp) \
|
||||
template <> \
|
||||
struct VMFunctionToId<decltype(&(::fp)), ::fp> { \
|
||||
static constexpr VMFunctionId id = VMFunctionId::name; \
|
||||
};
|
||||
VMFUNCTION_LIST(DEF_TEMPLATE)
|
||||
#undef DEF_TEMPLATE
|
||||
|
||||
#if MOZ_IS_GCC
|
||||
# pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
} // namespace jit
|
||||
} // namespace js
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
#include "jit/BaselineFrame-inl.h"
|
||||
#include "jit/JitFrames-inl.h"
|
||||
#include "jit/VMFunctionList-inl.h"
|
||||
#include "vm/Debugger-inl.h"
|
||||
#include "vm/Interpreter-inl.h"
|
||||
#include "vm/NativeObject-inl.h"
|
||||
|
@ -37,6 +38,113 @@ using namespace js::jit;
|
|||
namespace js {
|
||||
namespace jit {
|
||||
|
||||
// Helper template to build the VMFunctionData for a function.
|
||||
template <typename... Args>
|
||||
struct VMFunctionDataHelper;
|
||||
|
||||
template <class R, typename... Args>
|
||||
struct VMFunctionDataHelper<R (*)(JSContext*, Args...)>
|
||||
: public VMFunctionData {
|
||||
using Fun = R (*)(JSContext*, Args...);
|
||||
|
||||
static constexpr DataType returnType() { return TypeToDataType<R>::result; }
|
||||
static constexpr DataType outParam() {
|
||||
return OutParamToDataType<typename LastArg<Args...>::Type>::result;
|
||||
}
|
||||
static constexpr RootType outParamRootType() {
|
||||
return OutParamToRootType<typename LastArg<Args...>::Type>::result;
|
||||
}
|
||||
static constexpr size_t NbArgs() { return LastArg<Args...>::nbArgs; }
|
||||
static constexpr size_t explicitArgs() {
|
||||
return NbArgs() - (outParam() != Type_Void ? 1 : 0);
|
||||
}
|
||||
static constexpr uint32_t argumentProperties() {
|
||||
return BitMask<TypeToArgProperties, uint32_t, 2, Args...>::result;
|
||||
}
|
||||
static constexpr uint32_t argumentPassedInFloatRegs() {
|
||||
return BitMask<TypeToPassInFloatReg, uint32_t, 2, Args...>::result;
|
||||
}
|
||||
static constexpr uint64_t argumentRootTypes() {
|
||||
return BitMask<TypeToRootType, uint64_t, 3, Args...>::result;
|
||||
}
|
||||
constexpr VMFunctionDataHelper(Fun fun, const char* name,
|
||||
PopValues extraValuesToPop = PopValues(0))
|
||||
: VMFunctionData((void*)fun, name, explicitArgs(), argumentProperties(),
|
||||
argumentPassedInFloatRegs(), argumentRootTypes(),
|
||||
outParam(), outParamRootType(), returnType(),
|
||||
extraValuesToPop.numValues, NonTailCall) {}
|
||||
constexpr VMFunctionDataHelper(Fun fun, const char* name,
|
||||
MaybeTailCall expectTailCall,
|
||||
PopValues extraValuesToPop = PopValues(0))
|
||||
: VMFunctionData((void*)fun, name, explicitArgs(), argumentProperties(),
|
||||
argumentPassedInFloatRegs(), argumentRootTypes(),
|
||||
outParam(), outParamRootType(), returnType(),
|
||||
extraValuesToPop.numValues, expectTailCall) {}
|
||||
};
|
||||
|
||||
// GCC warns when the signature does not have matching attributes (for example
|
||||
// MOZ_MUST_USE). Squelch this warning to avoid a GCC-only footgun.
|
||||
#if MOZ_IS_GCC
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wignored-attributes"
|
||||
#endif
|
||||
|
||||
// Generate VMFunctionData array.
|
||||
static constexpr VMFunctionData vmFunctions[] = {
|
||||
#define DEF_VMFUNCTION(name, fp) \
|
||||
VMFunctionDataHelper<decltype(&(::fp))>(::fp, #name),
|
||||
VMFUNCTION_LIST(DEF_VMFUNCTION)
|
||||
#undef DEF_VMFUNCTION
|
||||
};
|
||||
|
||||
#if MOZ_IS_GCC
|
||||
# pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
const VMFunctionData& GetVMFunction(VMFunctionId id) {
|
||||
return vmFunctions[size_t(id)];
|
||||
}
|
||||
|
||||
bool JitRuntime::generateVMWrappers(JSContext* cx, MacroAssembler& masm) {
|
||||
// Generate all VM function wrappers.
|
||||
|
||||
static constexpr size_t NumVMFunctions = size_t(VMFunctionId::Count);
|
||||
|
||||
if (!functionWrapperOffsets_.reserve(NumVMFunctions)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
const char* lastName = nullptr;
|
||||
#endif
|
||||
|
||||
for (size_t i = 0; i < NumVMFunctions; i++) {
|
||||
VMFunctionId id = VMFunctionId(i);
|
||||
const VMFunctionData& fun = GetVMFunction(id);
|
||||
|
||||
#ifdef DEBUG
|
||||
// Assert the list is sorted by name.
|
||||
if (lastName) {
|
||||
MOZ_ASSERT(strcmp(lastName, fun.name()) < 0,
|
||||
"VM function list must be sorted by name");
|
||||
}
|
||||
lastName = fun.name();
|
||||
#endif
|
||||
|
||||
JitSpew(JitSpew_Codegen, "# VM function wrapper (%s)", fun.name());
|
||||
|
||||
uint32_t offset;
|
||||
if (!generateVMWrapper(cx, masm, fun, &offset)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(functionWrapperOffsets_.length() == size_t(id));
|
||||
functionWrapperOffsets_.infallibleAppend(offset);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Statics are initialized to null.
|
||||
/* static */ VMFunction* VMFunction::functions;
|
||||
|
||||
|
|
|
@ -55,6 +55,8 @@ enum MaybeTailCall : bool { TailCall, NonTailCall };
|
|||
|
||||
// [SMDOC] JIT-to-C++ Function Calls. (callVM)
|
||||
//
|
||||
// TODO(bug 1530937): update this comment after converting all VM functions.
|
||||
//
|
||||
// Sometimes it is easier to reuse C++ code by calling VM's functions. Calling a
|
||||
// function from the VM can be achieved with the use of callWithABI but this is
|
||||
// discouraged when the called functions might trigger exceptions and/or
|
||||
|
@ -123,11 +125,9 @@ enum MaybeTailCall : bool { TailCall, NonTailCall };
|
|||
// }
|
||||
//
|
||||
// After this, the result value is in the return value register.
|
||||
struct VMFunction {
|
||||
// Global linked list of all VMFunctions.
|
||||
static VMFunction* functions;
|
||||
VMFunction* next;
|
||||
|
||||
// Data for a VM function. All VMFunctionDatas are stored in a constexpr array.
|
||||
struct VMFunctionData {
|
||||
// Address of the C function.
|
||||
void* wrapped;
|
||||
|
||||
|
@ -293,15 +293,14 @@ struct VMFunction {
|
|||
return count;
|
||||
}
|
||||
|
||||
constexpr VMFunction(void* wrapped, const char* name, uint32_t explicitArgs,
|
||||
uint32_t argumentProperties,
|
||||
uint32_t argumentPassedInFloatRegs,
|
||||
uint64_t argRootTypes, DataType outParam,
|
||||
RootType outParamRootType, DataType returnType,
|
||||
uint8_t extraValuesToPop = 0,
|
||||
MaybeTailCall expectTailCall = NonTailCall)
|
||||
: next(nullptr),
|
||||
wrapped(wrapped),
|
||||
constexpr VMFunctionData(void* wrapped, const char* name,
|
||||
uint32_t explicitArgs, uint32_t argumentProperties,
|
||||
uint32_t argumentPassedInFloatRegs,
|
||||
uint64_t argRootTypes, DataType outParam,
|
||||
RootType outParamRootType, DataType returnType,
|
||||
uint8_t extraValuesToPop = 0,
|
||||
MaybeTailCall expectTailCall = NonTailCall)
|
||||
: wrapped(wrapped),
|
||||
#if defined(JS_JITSPEW) || defined(JS_TRACE_LOGGING)
|
||||
name_(name),
|
||||
#endif
|
||||
|
@ -314,11 +313,18 @@ struct VMFunction {
|
|||
returnType(returnType),
|
||||
extraValuesToPop(extraValuesToPop),
|
||||
expectTailCall(expectTailCall) {
|
||||
// Check for valid failure/return type.
|
||||
MOZ_ASSERT_IF(outParam != Type_Void,
|
||||
returnType == Type_Void || returnType == Type_Bool);
|
||||
MOZ_ASSERT(returnType == Type_Void || returnType == Type_Bool ||
|
||||
returnType == Type_Object);
|
||||
}
|
||||
|
||||
VMFunction(const VMFunction& o)
|
||||
: next(functions),
|
||||
wrapped(o.wrapped),
|
||||
// Note: clang-tidy suggests using |= auto| here but that generates extra
|
||||
// static initializers for old-style VMFunction definitions with Clang. We can
|
||||
// do this after bug 1530937 converts all of them.
|
||||
constexpr VMFunctionData(const VMFunctionData& o)
|
||||
: wrapped(o.wrapped),
|
||||
#if defined(JS_JITSPEW) || defined(JS_TRACE_LOGGING)
|
||||
name_(o.name_),
|
||||
#endif
|
||||
|
@ -331,14 +337,32 @@ struct VMFunction {
|
|||
returnType(o.returnType),
|
||||
extraValuesToPop(o.extraValuesToPop),
|
||||
expectTailCall(o.expectTailCall) {
|
||||
}
|
||||
};
|
||||
|
||||
// TODO(bug 1530937): remove VMFunction and FunctionInfo after converting all VM
|
||||
// functions to the new design.
|
||||
struct VMFunction : public VMFunctionData {
|
||||
// Global linked list of all VMFunctions.
|
||||
static VMFunction* functions;
|
||||
VMFunction* next;
|
||||
|
||||
constexpr VMFunction(void* wrapped, const char* name, uint32_t explicitArgs,
|
||||
uint32_t argumentProperties,
|
||||
uint32_t argumentPassedInFloatRegs,
|
||||
uint64_t argRootTypes, DataType outParam,
|
||||
RootType outParamRootType, DataType returnType,
|
||||
uint8_t extraValuesToPop = 0,
|
||||
MaybeTailCall expectTailCall = NonTailCall)
|
||||
: VMFunctionData(wrapped, name, explicitArgs, argumentProperties,
|
||||
argumentPassedInFloatRegs, argRootTypes, outParam,
|
||||
outParamRootType, returnType, extraValuesToPop,
|
||||
expectTailCall),
|
||||
next(nullptr) {}
|
||||
|
||||
VMFunction(const VMFunction& o) : VMFunctionData(o), next(functions) {
|
||||
// Add this to the global list of VMFunctions.
|
||||
functions = this;
|
||||
|
||||
// Check for valid failure/return type.
|
||||
MOZ_ASSERT_IF(outParam != Type_Void,
|
||||
returnType == Type_Void || returnType == Type_Bool);
|
||||
MOZ_ASSERT(returnType == Type_Void || returnType == Type_Bool ||
|
||||
returnType == Type_Object);
|
||||
}
|
||||
|
||||
typedef const VMFunction* Lookup;
|
||||
|
@ -781,13 +805,6 @@ struct OutParamToRootType<MutableHandleString> {
|
|||
static const VMFunction::RootType result = VMFunction::RootString;
|
||||
};
|
||||
|
||||
template <class>
|
||||
struct MatchContext {};
|
||||
template <>
|
||||
struct MatchContext<JSContext*> {
|
||||
static const bool valid = true;
|
||||
};
|
||||
|
||||
// Extract the last element of a list of types.
|
||||
template <typename... ArgTypes>
|
||||
struct LastArg;
|
||||
|
@ -844,9 +861,9 @@ struct BitMask<Each, ResultType, Shift, HeadType, TailTypes...> {
|
|||
template <typename... Args>
|
||||
struct FunctionInfo;
|
||||
|
||||
template <class R, class Context, typename... Args>
|
||||
struct FunctionInfo<R (*)(Context, Args...)> : public VMFunction {
|
||||
typedef R (*pf)(Context, Args...);
|
||||
template <class R, typename... Args>
|
||||
struct FunctionInfo<R (*)(JSContext*, Args...)> : public VMFunction {
|
||||
using pf = R (*)(JSContext*, Args...);
|
||||
|
||||
static DataType returnType() { return TypeToDataType<R>::result; }
|
||||
static DataType outParam() {
|
||||
|
@ -874,8 +891,6 @@ struct FunctionInfo<R (*)(Context, Args...)> : public VMFunction {
|
|||
argumentProperties(), argumentPassedInFloatRegs(),
|
||||
argumentRootTypes(), outParam(), outParamRootType(),
|
||||
returnType(), extraValuesToPop.numValues, NonTailCall) {
|
||||
static_assert(MatchContext<Context>::valid,
|
||||
"Invalid cx type in VMFunction");
|
||||
}
|
||||
explicit FunctionInfo(pf fun, const char* name, MaybeTailCall expectTailCall,
|
||||
PopValues extraValuesToPop = PopValues(0))
|
||||
|
@ -883,8 +898,6 @@ struct FunctionInfo<R (*)(Context, Args...)> : public VMFunction {
|
|||
argumentProperties(), argumentPassedInFloatRegs(),
|
||||
argumentRootTypes(), outParam(), outParamRootType(),
|
||||
returnType(), extraValuesToPop.numValues, expectTailCall) {
|
||||
static_assert(MatchContext<Context>::valid,
|
||||
"Invalid cx type in VMFunction");
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1226,6 +1239,10 @@ extern const VMFunction ToNumericInfo;
|
|||
// TailCall VMFunctions
|
||||
extern const VMFunction DoConcatStringObjectInfo;
|
||||
|
||||
enum class VMFunctionId;
|
||||
|
||||
extern const VMFunctionData& GetVMFunction(VMFunctionId id);
|
||||
|
||||
} // namespace jit
|
||||
} // namespace js
|
||||
|
||||
|
|
|
@ -704,10 +704,11 @@ void JitRuntime::generateBailoutHandler(MacroAssembler& masm,
|
|||
}
|
||||
|
||||
bool JitRuntime::generateVMWrapper(JSContext* cx, MacroAssembler& masm,
|
||||
const VMFunction& f) {
|
||||
const VMFunctionData& f,
|
||||
uint32_t* wrapperOffset) {
|
||||
MOZ_ASSERT(functionWrappers_);
|
||||
|
||||
uint32_t wrapperOffset = startTrampolineCode(masm);
|
||||
*wrapperOffset = startTrampolineCode(masm);
|
||||
|
||||
AllocatableGeneralRegisterSet regs(Register::Codes::WrapperMask);
|
||||
|
||||
|
@ -893,7 +894,7 @@ bool JitRuntime::generateVMWrapper(JSContext* cx, MacroAssembler& masm,
|
|||
f.explicitStackSlots() * sizeof(void*) +
|
||||
f.extraValuesToPop * sizeof(Value)));
|
||||
|
||||
return functionWrappers_->putNew(&f, wrapperOffset);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t JitRuntime::generatePreBarrier(JSContext* cx, MacroAssembler& masm,
|
||||
|
|
|
@ -533,10 +533,11 @@ void JitRuntime::generateBailoutHandler(MacroAssembler& masm,
|
|||
}
|
||||
|
||||
bool JitRuntime::generateVMWrapper(JSContext* cx, MacroAssembler& masm,
|
||||
const VMFunction& f) {
|
||||
const VMFunctionData& f,
|
||||
uint32_t* wrapperOffset) {
|
||||
MOZ_ASSERT(functionWrappers_);
|
||||
|
||||
uint32_t wrapperOffset = startTrampolineCode(masm);
|
||||
*wrapperOffset = startTrampolineCode(masm);
|
||||
|
||||
// Avoid conflicts with argument registers while discarding the result after
|
||||
// the function call.
|
||||
|
@ -733,7 +734,7 @@ bool JitRuntime::generateVMWrapper(JSContext* cx, MacroAssembler& masm,
|
|||
f.explicitStackSlots() * sizeof(void*) +
|
||||
f.extraValuesToPop * sizeof(Value)));
|
||||
|
||||
return functionWrappers_->putNew(&f, wrapperOffset);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t JitRuntime::generatePreBarrier(JSContext* cx, MacroAssembler& masm,
|
||||
|
|
|
@ -40,7 +40,7 @@ void JitRuntime::generateProfilerExitFrameTailStub(MacroAssembler&, Label*) {
|
|||
}
|
||||
|
||||
bool JitRuntime::generateVMWrapper(JSContext*, MacroAssembler&,
|
||||
const VMFunction&) {
|
||||
const VMFunctionData&, uint32_t*) {
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
|
|
|
@ -591,10 +591,11 @@ void JitRuntime::generateBailoutHandler(MacroAssembler& masm,
|
|||
}
|
||||
|
||||
bool JitRuntime::generateVMWrapper(JSContext* cx, MacroAssembler& masm,
|
||||
const VMFunction& f) {
|
||||
const VMFunctionData& f,
|
||||
uint32_t* wrapperOffset) {
|
||||
MOZ_ASSERT(functionWrappers_);
|
||||
|
||||
uint32_t wrapperOffset = startTrampolineCode(masm);
|
||||
*wrapperOffset = startTrampolineCode(masm);
|
||||
|
||||
// Avoid conflicts with argument registers while discarding the result after
|
||||
// the function call.
|
||||
|
@ -772,7 +773,7 @@ bool JitRuntime::generateVMWrapper(JSContext* cx, MacroAssembler& masm,
|
|||
f.explicitStackSlots() * sizeof(void*) +
|
||||
f.extraValuesToPop * sizeof(Value)));
|
||||
|
||||
return functionWrappers_->putNew(&f, wrapperOffset);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t JitRuntime::generatePreBarrier(JSContext* cx, MacroAssembler& masm,
|
||||
|
|
|
@ -608,10 +608,11 @@ void JitRuntime::generateBailoutHandler(MacroAssembler& masm,
|
|||
}
|
||||
|
||||
bool JitRuntime::generateVMWrapper(JSContext* cx, MacroAssembler& masm,
|
||||
const VMFunction& f) {
|
||||
const VMFunctionData& f,
|
||||
uint32_t* wrapperOffset) {
|
||||
MOZ_ASSERT(functionWrappers_);
|
||||
|
||||
uint32_t wrapperOffset = startTrampolineCode(masm);
|
||||
*wrapperOffset = startTrampolineCode(masm);
|
||||
|
||||
// Avoid conflicts with argument registers while discarding the result after
|
||||
// the function call.
|
||||
|
@ -786,7 +787,7 @@ bool JitRuntime::generateVMWrapper(JSContext* cx, MacroAssembler& masm,
|
|||
f.explicitStackSlots() * sizeof(void*) +
|
||||
f.extraValuesToPop * sizeof(Value)));
|
||||
|
||||
return functionWrappers_->putNew(&f, wrapperOffset);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t JitRuntime::generatePreBarrier(JSContext* cx, MacroAssembler& masm,
|
||||
|
|
|
@ -36,7 +36,16 @@ inline double NumberMod(double a, double b) {
|
|||
if (b == 0) {
|
||||
return JS::GenericNaN();
|
||||
}
|
||||
return fmod(a, b);
|
||||
double r = fmod(a, b);
|
||||
#if defined(XP_WIN)
|
||||
// Some versions of Windows (Win 10 v1803, v1809) miscompute the sign of zero
|
||||
// results from fmod. The sign should match the sign of the LHS. This bug
|
||||
// only affects 64-bit builds. See bug 1527007.
|
||||
if (mozilla::IsPositiveZero(r) && mozilla::IsNegative(a)) {
|
||||
return -0.0;
|
||||
}
|
||||
#endif
|
||||
return r;
|
||||
}
|
||||
|
||||
} // namespace js
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
var BUGNUMBER = 1499448;
|
||||
var summary = "Constant folder should fold labeled statements";
|
||||
|
||||
print(BUGNUMBER + ": " + summary);
|
||||
|
||||
if (typeof disassemble === "function") {
|
||||
var code = disassemble(() => { x: 2+2; });
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, /int8 4/.test(code));
|
||||
}
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
|
@ -609,10 +609,6 @@ static inline ParseNode* ObjectNormalFieldInitializer(ParseNode* pn) {
|
|||
return BinaryRight(pn);
|
||||
}
|
||||
|
||||
static inline ParseNode* MaybeInitializer(ParseNode* pn) {
|
||||
return pn->as<NameNode>().initializer();
|
||||
}
|
||||
|
||||
static inline bool IsUseOfName(ParseNode* pn, PropertyName* name) {
|
||||
return pn->isName(name);
|
||||
}
|
||||
|
@ -3040,8 +3036,15 @@ static bool CheckGlobalDotImport(ModuleValidatorShared& m,
|
|||
return m.addFFI(varName, field);
|
||||
}
|
||||
|
||||
static bool CheckModuleGlobal(ModuleValidatorShared& m, ParseNode* var,
|
||||
static bool CheckModuleGlobal(ModuleValidatorShared& m, ParseNode* decl,
|
||||
bool isConst) {
|
||||
if (!decl->isKind(ParseNodeKind::AssignExpr)) {
|
||||
return m.fail(decl, "module import needs initializer");
|
||||
}
|
||||
AssignmentNode* assignNode = &decl->as<AssignmentNode>();
|
||||
|
||||
ParseNode* var = assignNode->left();
|
||||
|
||||
if (!var->isKind(ParseNodeKind::Name)) {
|
||||
return m.fail(var, "import variable is not a plain name");
|
||||
}
|
||||
|
@ -3051,10 +3054,7 @@ static bool CheckModuleGlobal(ModuleValidatorShared& m, ParseNode* var,
|
|||
return false;
|
||||
}
|
||||
|
||||
ParseNode* initNode = MaybeInitializer(var);
|
||||
if (!initNode) {
|
||||
return m.fail(var, "module import needs initializer");
|
||||
}
|
||||
ParseNode* initNode = assignNode->right();
|
||||
|
||||
if (IsNumericLiteral(m, initNode)) {
|
||||
return CheckGlobalVariableInitConstant(m, varName, initNode, isConst);
|
||||
|
@ -3254,8 +3254,17 @@ static bool CheckFinalReturn(FunctionValidatorShared& f,
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool CheckVariable(FunctionValidatorShared& f, ParseNode* var,
|
||||
static bool CheckVariable(FunctionValidatorShared& f, ParseNode* decl,
|
||||
ValTypeVector* types, Vector<NumLit>* inits) {
|
||||
if (!decl->isKind(ParseNodeKind::AssignExpr)) {
|
||||
return f.failName(
|
||||
decl, "var '%s' needs explicit type declaration via an initial value",
|
||||
decl->as<NameNode>().name());
|
||||
}
|
||||
AssignmentNode* assignNode = &decl->as<AssignmentNode>();
|
||||
|
||||
ParseNode* var = assignNode->left();
|
||||
|
||||
if (!var->isKind(ParseNodeKind::Name)) {
|
||||
return f.fail(var, "local variable is not a plain name");
|
||||
}
|
||||
|
@ -3266,12 +3275,7 @@ static bool CheckVariable(FunctionValidatorShared& f, ParseNode* var,
|
|||
return false;
|
||||
}
|
||||
|
||||
ParseNode* initNode = MaybeInitializer(var);
|
||||
if (!initNode) {
|
||||
return f.failName(
|
||||
var, "var '%s' needs explicit type declaration via an initial value",
|
||||
name);
|
||||
}
|
||||
ParseNode* initNode = assignNode->right();
|
||||
|
||||
NumLit lit;
|
||||
if (!IsLiteralOrConst(f, initNode, &lit)) {
|
||||
|
@ -6154,13 +6158,21 @@ static bool CheckFunctions(ModuleValidator<Unit>& m) {
|
|||
}
|
||||
|
||||
template <typename Unit>
|
||||
static bool CheckFuncPtrTable(ModuleValidator<Unit>& m, ParseNode* var) {
|
||||
static bool CheckFuncPtrTable(ModuleValidator<Unit>& m, ParseNode* decl) {
|
||||
if (!decl->isKind(ParseNodeKind::AssignExpr)) {
|
||||
return m.fail(decl, "function-pointer table must have initializer");
|
||||
}
|
||||
AssignmentNode* assignNode = &decl->as<AssignmentNode>();
|
||||
|
||||
ParseNode* var = assignNode->left();
|
||||
|
||||
if (!var->isKind(ParseNodeKind::Name)) {
|
||||
return m.fail(var, "function-pointer table name is not a plain name");
|
||||
}
|
||||
|
||||
ParseNode* arrayLiteral = MaybeInitializer(var);
|
||||
if (!arrayLiteral || !arrayLiteral->isKind(ParseNodeKind::ArrayExpr)) {
|
||||
ParseNode* arrayLiteral = assignNode->right();
|
||||
|
||||
if (!arrayLiteral->isKind(ParseNodeKind::ArrayExpr)) {
|
||||
return m.fail(
|
||||
var, "function-pointer table's initializer must be an array literal");
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "js/PropertySpec.h"
|
||||
#include "mozilla/ChaosMode.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "mozilla/IOInterposer.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
|
@ -1075,6 +1076,10 @@ int XRE_XPCShellMain(int argc, char** argv, char** envp,
|
|||
|
||||
mozilla::LogModule::Init(argc, argv);
|
||||
|
||||
// This guard ensures that all threads that attempt to register themselves
|
||||
// with the IOInterposer will be properly tracked.
|
||||
mozilla::IOInterposerInit ioInterposerGuard;
|
||||
|
||||
#ifdef MOZ_GECKO_PROFILER
|
||||
char aLocal;
|
||||
profiler_init(&aLocal);
|
||||
|
|
|
@ -183,7 +183,7 @@ class InfallibleAllocPolicy {
|
|||
}
|
||||
|
||||
template <class T, typename P1>
|
||||
static T* new_(P1 aP1) {
|
||||
static T* new_(const P1& aP1) {
|
||||
void* mem = malloc_(sizeof(T));
|
||||
return new (mem) T(aP1);
|
||||
}
|
||||
|
|
|
@ -94,9 +94,8 @@ class GeckoViewContentChild extends GeckoViewChildModule {
|
|||
|
||||
collectSessionState() {
|
||||
let history = SessionHistory.collect(docShell);
|
||||
let [formdata, scrolldata] = this.Utils.mapFrameTree(
|
||||
content, SessionStoreUtils.collectFormData,
|
||||
SessionStoreUtils.collectScrollPosition);
|
||||
let formdata = SessionStoreUtils.collectFormData(content);
|
||||
let scrolldata = SessionStoreUtils.collectScrollPosition(content);
|
||||
|
||||
// Save the current document resolution.
|
||||
let zoom = 1;
|
||||
|
|
|
@ -877,7 +877,7 @@ SessionStore.prototype = {
|
|||
|
||||
// Store the form data.
|
||||
let content = aBrowser.contentWindow;
|
||||
let [formdata] = Utils.mapFrameTree(content, SessionStoreUtils.collectFormData);
|
||||
let formdata = SessionStoreUtils.collectFormData(content);
|
||||
formdata = PrivacyFilter.filterFormData(formdata || {});
|
||||
|
||||
// If we found any form data, main content or frames, let's save it
|
||||
|
@ -916,8 +916,7 @@ SessionStore.prototype = {
|
|||
|
||||
// Save the scroll position itself.
|
||||
let content = aBrowser.contentWindow;
|
||||
let [scrolldata] =
|
||||
Utils.mapFrameTree(content, SessionStoreUtils.collectScrollPosition);
|
||||
let scrolldata = SessionStoreUtils.collectScrollPosition(content);
|
||||
scrolldata = scrolldata || {};
|
||||
|
||||
// Save the current document resolution.
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче