forked from mirrors/gecko-dev
merge mozilla-inbound to mozilla-central a=merge
This commit is contained in:
commit
1da4eb2ea5
272 changed files with 5871 additions and 3325 deletions
|
|
@ -319,7 +319,7 @@ pref("media.fragmented-mp4.gonk.enabled", true);
|
|||
pref("media.video-queue.default-size", 3);
|
||||
|
||||
// optimize images' memory usage
|
||||
pref("image.mem.decodeondraw", false);
|
||||
pref("image.mem.decodeondraw", true);
|
||||
pref("image.mem.allow_locking_in_content_processes", false); /* don't allow image locking */
|
||||
// Limit the surface cache to 1/8 of main memory or 128MB, whichever is smaller.
|
||||
// Almost everything that was factored into 'max_decoded_image_kb' is now stored
|
||||
|
|
|
|||
|
|
@ -1651,9 +1651,15 @@ pref("pdfjs.firstRun", true);
|
|||
pref("pdfjs.previousHandler.preferredAction", 0);
|
||||
pref("pdfjs.previousHandler.alwaysAskBeforeHandling", false);
|
||||
|
||||
// Shumway is only bundled in Nightly.
|
||||
#ifdef NIGHTLY_BUILD
|
||||
// Shumway component (SWF player) is disabled by default. Also see bug 904346.
|
||||
// By default, Shumway (SWF player) is only enabled for whitelisted SWFs on Windows + OS X.
|
||||
#ifdef UNIX_BUT_NOT_MAC
|
||||
pref("shumway.disabled", true);
|
||||
#else
|
||||
pref("shumway.disabled", false);
|
||||
pref("shumway.swf.whitelist", "http://g-ecx.images-amazon.com/*/AiryBasicRenderer*.swf");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// The maximum amount of decoded image data we'll willingly keep around (we
|
||||
|
|
|
|||
|
|
@ -877,7 +877,22 @@ function LoadInOtherProcess(browser, loadOptions, historyIndex = -1) {
|
|||
// Called when a docshell has attempted to load a page in an incorrect process.
|
||||
// This function is responsible for loading the page in the correct process.
|
||||
function RedirectLoad({ target: browser, data }) {
|
||||
LoadInOtherProcess(browser, data.loadOptions, data.historyIndex);
|
||||
// We should only start the redirection if the browser window has finished
|
||||
// starting up. Otherwise, we should wait until the startup is done.
|
||||
if (gBrowserInit.delayedStartupFinished) {
|
||||
LoadInOtherProcess(browser, data.loadOptions, data.historyIndex);
|
||||
} else {
|
||||
let delayedStartupFinished = (subject, topic) => {
|
||||
if (topic == "browser-delayed-startup-finished" &&
|
||||
subject == window) {
|
||||
Services.obs.removeObserver(delayedStartupFinished, topic);
|
||||
LoadInOtherProcess(browser, data.loadOptions, data.historyIndex);
|
||||
}
|
||||
};
|
||||
Services.obs.addObserver(delayedStartupFinished,
|
||||
"browser-delayed-startup-finished",
|
||||
false);
|
||||
}
|
||||
}
|
||||
|
||||
var gBrowserInit = {
|
||||
|
|
@ -906,6 +921,8 @@ var gBrowserInit = {
|
|||
mm.loadFrameScript("chrome://browser/content/content.js", true);
|
||||
mm.loadFrameScript("chrome://browser/content/content-UITour.js", true);
|
||||
|
||||
window.messageManager.addMessageListener("Browser:LoadURI", RedirectLoad);
|
||||
|
||||
// initialize observers and listeners
|
||||
// and give C++ access to gBrowser
|
||||
XULBrowserWindow.init();
|
||||
|
|
@ -923,8 +940,6 @@ var gBrowserInit = {
|
|||
Cc["@mozilla.org/eventlistenerservice;1"]
|
||||
.getService(Ci.nsIEventListenerService)
|
||||
.addSystemEventListener(gBrowser, "click", contentAreaClick, true);
|
||||
} else {
|
||||
gBrowser.updateBrowserRemoteness(gBrowser.selectedBrowser, true);
|
||||
}
|
||||
|
||||
// hook up UI through progress listener
|
||||
|
|
@ -1181,13 +1196,29 @@ var gBrowserInit = {
|
|||
else if (uriToLoad instanceof XULElement) {
|
||||
// swap the given tab with the default about:blank tab and then close
|
||||
// the original tab in the other window.
|
||||
let tabToOpen = uriToLoad;
|
||||
|
||||
// Stop the about:blank load
|
||||
gBrowser.stop();
|
||||
// make sure it has a docshell
|
||||
gBrowser.docShell;
|
||||
|
||||
gBrowser.swapBrowsersAndCloseOther(gBrowser.selectedTab, uriToLoad);
|
||||
// If the browser that we're swapping in was remote, then we'd better
|
||||
// be able to support remote browsers, and then make our selectedTab
|
||||
// remote.
|
||||
try {
|
||||
if (tabToOpen.linkedBrowser.isRemoteBrowser) {
|
||||
if (!gMultiProcessBrowser) {
|
||||
throw new Error("Cannot drag a remote browser into a window " +
|
||||
"without the remote tabs load context.");
|
||||
}
|
||||
|
||||
gBrowser.updateBrowserRemoteness(gBrowser.selectedBrowser, true);
|
||||
}
|
||||
gBrowser.swapBrowsersAndCloseOther(gBrowser.selectedTab, tabToOpen);
|
||||
} catch(e) {
|
||||
Cu.reportError(e);
|
||||
}
|
||||
}
|
||||
// window.arguments[2]: referrer (nsIURI)
|
||||
// [3]: postData (nsIInputStream)
|
||||
|
|
@ -1216,7 +1247,6 @@ var gBrowserInit = {
|
|||
Services.obs.addObserver(gXPInstallObserver, "addon-install-failed", false);
|
||||
Services.obs.addObserver(gXPInstallObserver, "addon-install-complete", false);
|
||||
window.messageManager.addMessageListener("Browser:URIFixup", gKeywordURIFixup);
|
||||
window.messageManager.addMessageListener("Browser:LoadURI", RedirectLoad);
|
||||
|
||||
BrowserOffline.init();
|
||||
OfflineApps.init();
|
||||
|
|
@ -4082,6 +4112,13 @@ var XULBrowserWindow = {
|
|||
// unsupported
|
||||
},
|
||||
|
||||
forceInitialBrowserRemote: function() {
|
||||
let initBrowser =
|
||||
document.getAnonymousElementByAttribute(gBrowser, "anonid", "initialBrowser");
|
||||
gBrowser.updateBrowserRemoteness(initBrowser, true);
|
||||
return initBrowser.frameLoader.tabParent;
|
||||
},
|
||||
|
||||
setDefaultStatus: function (status) {
|
||||
this.defaultStatus = status;
|
||||
this.updateStatusField();
|
||||
|
|
@ -4737,7 +4774,7 @@ function nsBrowserAccess() { }
|
|||
nsBrowserAccess.prototype = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIBrowserDOMWindow, Ci.nsISupports]),
|
||||
|
||||
_openURIInNewTab: function(aURI, aReferrer, aIsPrivate, aIsExternal) {
|
||||
_openURIInNewTab: function(aURI, aReferrer, aIsPrivate, aIsExternal, aForceNotRemote=false) {
|
||||
let win, needToFocusWin;
|
||||
|
||||
// try the current window. if we're in a popup, fall back on the most recent browser window
|
||||
|
|
@ -4764,7 +4801,8 @@ nsBrowserAccess.prototype = {
|
|||
let tab = win.gBrowser.loadOneTab(aURI ? aURI.spec : "about:blank", {
|
||||
referrerURI: aReferrer,
|
||||
fromExternal: aIsExternal,
|
||||
inBackground: loadInBackground});
|
||||
inBackground: loadInBackground,
|
||||
forceNotRemote: aForceNotRemote});
|
||||
let browser = win.gBrowser.getBrowserForTab(tab);
|
||||
|
||||
if (needToFocusWin || (!loadInBackground && aIsExternal))
|
||||
|
|
@ -4774,9 +4812,23 @@ nsBrowserAccess.prototype = {
|
|||
},
|
||||
|
||||
openURI: function (aURI, aOpener, aWhere, aContext) {
|
||||
// This function should only ever be called if we're opening a URI
|
||||
// from a non-remote browser window (via nsContentTreeOwner).
|
||||
if (aOpener && Cu.isCrossProcessWrapper(aOpener)) {
|
||||
Cu.reportError("nsBrowserAccess.openURI was passed a CPOW for aOpener. " +
|
||||
"openURI should only ever be called from non-remote browsers.");
|
||||
throw Cr.NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
var newWindow = null;
|
||||
var isExternal = (aContext == Ci.nsIBrowserDOMWindow.OPEN_EXTERNAL);
|
||||
|
||||
if (aOpener && isExternal) {
|
||||
Cu.reportError("nsBrowserAccess.openURI did not expect an opener to be " +
|
||||
"passed if the context is OPEN_EXTERNAL.");
|
||||
throw Cr.NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (isExternal && aURI && aURI.schemeIs("chrome")) {
|
||||
dump("use --chrome command-line option to load external chrome urls\n");
|
||||
return null;
|
||||
|
|
@ -4805,7 +4857,14 @@ nsBrowserAccess.prototype = {
|
|||
break;
|
||||
case Ci.nsIBrowserDOMWindow.OPEN_NEWTAB :
|
||||
let referrer = aOpener ? makeURI(aOpener.location.href) : null;
|
||||
let browser = this._openURIInNewTab(aURI, referrer, isPrivate, isExternal);
|
||||
// If we have an opener, that means that the caller is expecting access
|
||||
// to the nsIDOMWindow of the opened tab right away. For e10s windows,
|
||||
// this means forcing the newly opened browser to be non-remote so that
|
||||
// we can hand back the nsIDOMWindow. The XULBrowserWindow.shouldLoadURI
|
||||
// will do the job of shuttling off the newly opened browser to run in
|
||||
// the right process once it starts loading a URI.
|
||||
let forceNotRemote = !!aOpener;
|
||||
let browser = this._openURIInNewTab(aURI, referrer, isPrivate, isExternal, forceNotRemote);
|
||||
if (browser)
|
||||
newWindow = browser.contentWindow;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -332,9 +332,9 @@ nsContextMenu.prototype = {
|
|||
}
|
||||
|
||||
// BiDi UI
|
||||
this.showItem("context-sep-bidi", top.gBidiUI);
|
||||
this.showItem("context-sep-bidi", !this.onNumeric && top.gBidiUI);
|
||||
this.showItem("context-bidi-text-direction-toggle",
|
||||
this.onTextInput && top.gBidiUI);
|
||||
this.onTextInput && !this.onNumeric && top.gBidiUI);
|
||||
this.showItem("context-bidi-page-direction-toggle",
|
||||
!this.onTextInput && top.gBidiUI);
|
||||
|
||||
|
|
@ -563,6 +563,7 @@ nsContextMenu.prototype = {
|
|||
this.onVideo = false;
|
||||
this.onAudio = false;
|
||||
this.onTextInput = false;
|
||||
this.onNumeric = false;
|
||||
this.onKeywordField = false;
|
||||
this.mediaURL = "";
|
||||
this.onLink = false;
|
||||
|
|
@ -658,6 +659,7 @@ nsContextMenu.prototype = {
|
|||
}
|
||||
else if (editFlags & (SpellCheckHelper.INPUT | SpellCheckHelper.TEXTAREA)) {
|
||||
this.onTextInput = (editFlags & SpellCheckHelper.TEXTINPUT) !== 0;
|
||||
this.onNumeric = (editFlags & SpellCheckHelper.NUMERIC) !== 0;
|
||||
this.onEditableArea = (editFlags & SpellCheckHelper.EDITABLE) !== 0;
|
||||
if (this.onEditableArea) {
|
||||
if (this.isRemote) {
|
||||
|
|
|
|||
|
|
@ -1366,6 +1366,7 @@
|
|||
var aRelatedToCurrent;
|
||||
var aAllowMixedContent;
|
||||
var aSkipAnimation;
|
||||
var aForceNotRemote;
|
||||
if (arguments.length == 2 &&
|
||||
typeof arguments[1] == "object" &&
|
||||
!(arguments[1] instanceof Ci.nsIURI)) {
|
||||
|
|
@ -1379,6 +1380,7 @@
|
|||
aRelatedToCurrent = params.relatedToCurrent;
|
||||
aAllowMixedContent = params.allowMixedContent;
|
||||
aSkipAnimation = params.skipAnimation;
|
||||
aForceNotRemote = params.forceNotRemote;
|
||||
}
|
||||
|
||||
var bgLoad = (aLoadInBackground != null) ? aLoadInBackground :
|
||||
|
|
@ -1393,7 +1395,8 @@
|
|||
fromExternal: aFromExternal,
|
||||
relatedToCurrent: aRelatedToCurrent,
|
||||
skipAnimation: aSkipAnimation,
|
||||
allowMixedContent: aAllowMixedContent });
|
||||
allowMixedContent: aAllowMixedContent,
|
||||
forceNotRemote: aForceNotRemote });
|
||||
if (!bgLoad)
|
||||
this.selectedTab = tab;
|
||||
|
||||
|
|
@ -1672,6 +1675,7 @@
|
|||
var aRelatedToCurrent;
|
||||
var aSkipAnimation;
|
||||
var aAllowMixedContent;
|
||||
var aForceNotRemote;
|
||||
if (arguments.length == 2 &&
|
||||
typeof arguments[1] == "object" &&
|
||||
!(arguments[1] instanceof Ci.nsIURI)) {
|
||||
|
|
@ -1685,6 +1689,7 @@
|
|||
aRelatedToCurrent = params.relatedToCurrent;
|
||||
aSkipAnimation = params.skipAnimation;
|
||||
aAllowMixedContent = params.allowMixedContent;
|
||||
aForceNotRemote = params.forceNotRemote;
|
||||
}
|
||||
|
||||
// if we're adding tabs, we're past interrupt mode, ditch the owner
|
||||
|
|
@ -1702,6 +1707,7 @@
|
|||
// The new browser should be remote if this is an e10s window and
|
||||
// the uri to load can be loaded remotely.
|
||||
let remote = gMultiProcessBrowser &&
|
||||
!aForceNotRemote &&
|
||||
E10SUtils.canLoadURIInProcess(aURI, Ci.nsIXULRuntime.PROCESS_TYPE_CONTENT);
|
||||
if (remote)
|
||||
t.setAttribute("remote", "true");
|
||||
|
|
|
|||
|
|
@ -213,7 +213,6 @@ skip-if = e10s
|
|||
[browser_bug561636.js]
|
||||
skip-if = e10s # Bug 1093677 - automated form submission from the test doesn't seem to quite work yet
|
||||
[browser_bug562649.js]
|
||||
skip-if = e10s # Bug 940195 - XULBrowserWindow.isBusy is false as a remote tab starts loading
|
||||
[browser_bug563588.js]
|
||||
[browser_bug565575.js]
|
||||
skip-if = e10s
|
||||
|
|
@ -260,7 +259,6 @@ skip-if = buildapp == 'mulet' || os == "mac" # mac: Intermittent failures, bug 9
|
|||
[browser_bug678392.js]
|
||||
skip-if = e10s # bug 1102331 - does focus things on the content window which break in e10s mode
|
||||
[browser_bug710878.js]
|
||||
skip-if = e10s # Bug 1100653 - test uses waitForFocus on content
|
||||
[browser_bug719271.js]
|
||||
skip-if = e10s # Bug 1056146 - zoom tests use FullZoomHelper and break in e10s
|
||||
[browser_bug724239.js]
|
||||
|
|
@ -268,7 +266,6 @@ skip-if = e10s # Bug 1056146 - zoom tests use FullZoomHelper and break in e10s
|
|||
skip-if = e10s # Bug 1093155 - tries to use context menu from browser-chrome and gets in a mess when in e10s mode
|
||||
[browser_bug735471.js]
|
||||
[browser_bug749738.js]
|
||||
skip-if = e10s # Bug 921935 - focusmanager issues with e10s
|
||||
[browser_bug763468_perwindowpb.js]
|
||||
skip-if = e10s
|
||||
[browser_bug767836_perwindowpb.js]
|
||||
|
|
@ -279,6 +276,7 @@ skip-if = e10s
|
|||
[browser_bug832435.js]
|
||||
[browser_bug839103.js]
|
||||
[browser_bug880101.js]
|
||||
skip-if = e10s # Bug 1126316 - New e10s windows erroneously fire initial about:blank location through nsIWebProgressListener
|
||||
[browser_bug882977.js]
|
||||
[browser_bug902156.js]
|
||||
[browser_bug906190.js]
|
||||
|
|
@ -427,6 +425,8 @@ skip-if = e10s
|
|||
[browser_tabs_isActive.js]
|
||||
skip-if = e10s # Bug 1100664 - test relies on linkedBrowser.docShell
|
||||
[browser_tabs_owner.js]
|
||||
[browser_testOpenNewRemoteTabsFromNonRemoteBrowsers.js]
|
||||
skip-if = !e10s && os == "linux" # Bug 994541 - Need OMTC enabled by default on Linux, or else we get blocked by an alert dialog when opening e10s window.
|
||||
[browser_trackingUI.js]
|
||||
support-files =
|
||||
trackingPage.html
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ function test() {
|
|||
Ci.nsIBrowserDOMWindow.OPEN_NEWTAB,
|
||||
Ci.nsIBrowserDOMWindow.OPEN_EXTERNAL);
|
||||
|
||||
ok(XULBrowserWindow.isBusy, "window is busy loading a page");
|
||||
is(gBrowser.userTypedValue, URI, "userTypedValue matches test URI");
|
||||
is(gURLBar.value, URI, "location bar value matches test URI");
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,124 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
const OPEN_LOCATION_PREF = "browser.link.open_newwindow";
|
||||
const NON_REMOTE_PAGE = "about:welcomeback";
|
||||
|
||||
Cu.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
|
||||
|
||||
function frame_script() {
|
||||
content.document.body.innerHTML = `
|
||||
<a href="about:home" target="_blank" id="testAnchor">Open a window</a>
|
||||
`;
|
||||
|
||||
let element = content.document.getElementById("testAnchor");
|
||||
element.click();
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes some browser in some window, and forces that browser
|
||||
* to become non-remote, and then navigates it to a page that
|
||||
* we're not supposed to be displaying remotely. Returns a
|
||||
* Promise that resolves when the browser is no longer remote.
|
||||
*/
|
||||
function prepareNonRemoteBrowser(aWindow, browser) {
|
||||
browser.loadURI(NON_REMOTE_PAGE);
|
||||
return waitForDocLoadComplete(browser);
|
||||
}
|
||||
|
||||
registerCleanupFunction(() => {
|
||||
Services.prefs.clearUserPref(OPEN_LOCATION_PREF);
|
||||
});
|
||||
|
||||
/**
|
||||
* Test that if we open a new tab from a link in a non-remote
|
||||
* browser in an e10s window, that the new tab will load properly.
|
||||
*/
|
||||
add_task(function* test_new_tab() {
|
||||
let normalWindow = yield promiseOpenAndLoadWindow({
|
||||
remote: true
|
||||
}, true);
|
||||
let privateWindow = yield promiseOpenAndLoadWindow({
|
||||
remote: true,
|
||||
private: true,
|
||||
}, true);
|
||||
|
||||
for (let testWindow of [normalWindow, privateWindow]) {
|
||||
yield promiseWaitForFocus(testWindow);
|
||||
let testBrowser = testWindow.gBrowser.selectedBrowser;
|
||||
info("Preparing non-remote browser");
|
||||
yield prepareNonRemoteBrowser(testWindow, testBrowser);
|
||||
info("Non-remote browser prepared - sending frame script");
|
||||
|
||||
// Get our framescript ready
|
||||
let mm = testBrowser.messageManager;
|
||||
mm.loadFrameScript("data:,(" + frame_script.toString() + ")();", true);
|
||||
|
||||
let tabOpenEvent = yield waitForNewTabEvent(testWindow.gBrowser);
|
||||
let newTab = tabOpenEvent.target;
|
||||
|
||||
yield promiseTabLoadEvent(newTab);
|
||||
|
||||
// Our framescript opens to about:home which means that the
|
||||
// tab should eventually become remote.
|
||||
ok(newTab.linkedBrowser.isRemoteBrowser,
|
||||
"The opened browser never became remote.");
|
||||
|
||||
testWindow.gBrowser.removeTab(newTab);
|
||||
}
|
||||
|
||||
normalWindow.close();
|
||||
privateWindow.close();
|
||||
});
|
||||
|
||||
/**
|
||||
* Test that if we open a new window from a link in a non-remote
|
||||
* browser in an e10s window, that the new window is not an e10s
|
||||
* window. Also tests with a private browsing window.
|
||||
*/
|
||||
add_task(function* test_new_window() {
|
||||
let normalWindow = yield promiseOpenAndLoadWindow({
|
||||
remote: true
|
||||
}, true);
|
||||
let privateWindow = yield promiseOpenAndLoadWindow({
|
||||
remote: true,
|
||||
private: true,
|
||||
}, true);
|
||||
|
||||
// Fiddle with the prefs so that we open target="_blank" links
|
||||
// in new windows instead of new tabs.
|
||||
Services.prefs.setIntPref(OPEN_LOCATION_PREF,
|
||||
Ci.nsIBrowserDOMWindow.OPEN_NEWWINDOW);
|
||||
|
||||
for (let testWindow of [normalWindow, privateWindow]) {
|
||||
yield promiseWaitForFocus(testWindow);
|
||||
let testBrowser = testWindow.gBrowser.selectedBrowser;
|
||||
yield prepareNonRemoteBrowser(testWindow, testBrowser);
|
||||
|
||||
// Get our framescript ready
|
||||
let mm = testBrowser.messageManager;
|
||||
mm.loadFrameScript("data:,(" + frame_script.toString() + ")();", true);
|
||||
|
||||
// Click on the link in the browser, and wait for the new window.
|
||||
let {subject: newWindow} =
|
||||
yield promiseTopicObserved("browser-delayed-startup-finished");
|
||||
|
||||
is(PrivateBrowsingUtils.isWindowPrivate(testWindow),
|
||||
PrivateBrowsingUtils.isWindowPrivate(newWindow),
|
||||
"Private browsing state of new window does not match the original!");
|
||||
|
||||
let newTab = newWindow.gBrowser.selectedTab;
|
||||
|
||||
yield promiseTabLoadEvent(newTab);
|
||||
|
||||
// Our framescript opens to about:home which means that the
|
||||
// tab should eventually become remote.
|
||||
ok(newTab.linkedBrowser.isRemoteBrowser,
|
||||
"The opened browser never became remote.");
|
||||
newWindow.close();
|
||||
}
|
||||
|
||||
normalWindow.close();
|
||||
privateWindow.close();
|
||||
});
|
||||
|
|
@ -123,6 +123,23 @@ function promiseWaitForEvent(object, eventName, capturing = false, chrome = fals
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows setting focus on a window, and waiting for that window to achieve
|
||||
* focus.
|
||||
*
|
||||
* @param aWindow
|
||||
* The window to focus and wait for.
|
||||
*
|
||||
* @return {Promise}
|
||||
* @resolves When the window is focused.
|
||||
* @rejects Never.
|
||||
*/
|
||||
function promiseWaitForFocus(aWindow) {
|
||||
return new Promise((resolve) => {
|
||||
waitForFocus(resolve, aWindow);
|
||||
});
|
||||
}
|
||||
|
||||
function getTestPlugin(aName) {
|
||||
var pluginName = aName || "Test Plug-in";
|
||||
var ph = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
|
||||
|
|
@ -572,6 +589,21 @@ function promiseTabLoadEvent(tab, url, eventType="load")
|
|||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Promise that resolves once a new tab has been opened in
|
||||
* a xul:tabbrowser.
|
||||
*
|
||||
* @param aTabBrowser
|
||||
* The xul:tabbrowser to monitor for a new tab.
|
||||
* @return {Promise}
|
||||
* Resolved when the new tab has been opened.
|
||||
* @resolves to the TabOpen event that was fired.
|
||||
* @rejects Never.
|
||||
*/
|
||||
function waitForNewTabEvent(aTabBrowser) {
|
||||
return promiseWaitForEvent(aTabBrowser.tabContainer, "TabOpen");
|
||||
}
|
||||
|
||||
function assertWebRTCIndicatorStatus(expected) {
|
||||
let ui = Cu.import("resource:///modules/webrtcUI.jsm", {}).webrtcUI;
|
||||
let expectedState = expected ? "visible" : "hidden";
|
||||
|
|
@ -745,3 +777,26 @@ function promiseAutocompleteResultPopup(inputText, win = window) {
|
|||
|
||||
return promiseSearchComplete(win);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows waiting for an observer notification once.
|
||||
*
|
||||
* @param aTopic
|
||||
* Notification topic to observe.
|
||||
*
|
||||
* @return {Promise}
|
||||
* @resolves An object with subject and data properties from the observed
|
||||
* notification.
|
||||
* @rejects Never.
|
||||
*/
|
||||
function promiseTopicObserved(aTopic)
|
||||
{
|
||||
return new Promise((resolve) => {
|
||||
Services.obs.addObserver(
|
||||
function PTO_observe(aSubject, aTopic, aData) {
|
||||
Services.obs.removeObserver(PTO_observe, aTopic);
|
||||
resolve({subject: aSubject, data: aData});
|
||||
}, aTopic, false);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -160,7 +160,8 @@ function runTest(testNum) {
|
|||
case 8: // email
|
||||
case 9: // url
|
||||
case 10: // tel
|
||||
// Context menu for tel, password, email and url input fields.
|
||||
case 11: // type='number'
|
||||
// Context menu for tel, password, email, url and number input fields.
|
||||
checkContextMenu(["context-undo", false,
|
||||
"---", null,
|
||||
"context-cut", false,
|
||||
|
|
@ -181,15 +182,16 @@ function runTest(testNum) {
|
|||
} else if (testNum == 9) {
|
||||
input.type = 'tel';
|
||||
} else if (testNum == 10) {
|
||||
input.type = 'number';
|
||||
} else if (testNum == 11) {
|
||||
input.type = 'date';
|
||||
}
|
||||
|
||||
openContextMenuFor(input); // Invoke context menu for next test.
|
||||
break;
|
||||
|
||||
case 11: // type='date'
|
||||
case 12: // type='time'
|
||||
case 13: // type='number'
|
||||
case 12: // type='date'
|
||||
case 13: // type='time'
|
||||
case 14: // type='color'
|
||||
case 15: // type='range'
|
||||
checkContextMenu(["context-navigation", null,
|
||||
|
|
@ -209,10 +211,8 @@ function runTest(testNum) {
|
|||
"context-inspect", true]);
|
||||
closeContextMenu();
|
||||
|
||||
if (testNum == 11) {
|
||||
if (testNum == 12) {
|
||||
input.type = 'time';
|
||||
} else if (testNum == 12) {
|
||||
input.type = 'number';
|
||||
} else if (testNum == 13) {
|
||||
input.type = 'color';
|
||||
} else if (testNum == 14) {
|
||||
|
|
|
|||
|
|
@ -39,11 +39,23 @@ function test() {
|
|||
let url = "http://example.com/?window=" + windowsToOpen.length;
|
||||
|
||||
provideWindow(function onTestURLLoaded(win) {
|
||||
win.close();
|
||||
// Give it time to close
|
||||
executeSoon(function() {
|
||||
openWindowRec(windowsToOpen, expectedResults, recCallback);
|
||||
});
|
||||
let tabReady = () => {
|
||||
win.close();
|
||||
// Give it time to close
|
||||
executeSoon(function() {
|
||||
openWindowRec(windowsToOpen, expectedResults, recCallback);
|
||||
});
|
||||
};
|
||||
|
||||
if (win.gMultiProcessBrowser) {
|
||||
let tab = win.gBrowser.selectedTab;
|
||||
tab.addEventListener("SSTabRestored", function onTabRestored() {
|
||||
tab.removeEventListener("SSTabRestored", onTabRestored);
|
||||
tabReady();
|
||||
});
|
||||
} else {
|
||||
tabReady();
|
||||
}
|
||||
}, url, settings);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,44 +30,53 @@ function test() {
|
|||
newWin.gBrowser.loadURI(testURL, null, null);
|
||||
|
||||
promiseBrowserLoaded(newWin.gBrowser.selectedBrowser).then(() => {
|
||||
// get the sessionstore state for the window
|
||||
TabState.flush(newWin.gBrowser.selectedBrowser);
|
||||
let state = ss.getWindowState(newWin);
|
||||
let ready = () => {
|
||||
// get the sessionstore state for the window
|
||||
TabState.flush(newWin.gBrowser.selectedBrowser);
|
||||
let state = ss.getWindowState(newWin);
|
||||
|
||||
// verify our cookie got set during pageload
|
||||
let e = cs.enumerator;
|
||||
let cookie;
|
||||
let i = 0;
|
||||
while (e.hasMoreElements()) {
|
||||
cookie = e.getNext().QueryInterface(Ci.nsICookie);
|
||||
i++;
|
||||
// verify our cookie got set during pageload
|
||||
let e = cs.enumerator;
|
||||
let cookie;
|
||||
let i = 0;
|
||||
while (e.hasMoreElements()) {
|
||||
cookie = e.getNext().QueryInterface(Ci.nsICookie);
|
||||
i++;
|
||||
}
|
||||
is(i, 1, "expected one cookie");
|
||||
|
||||
// remove the cookie
|
||||
cs.removeAll();
|
||||
|
||||
// restore the window state
|
||||
ss.setWindowState(newWin, state, true);
|
||||
|
||||
// at this point, the cookie should be restored...
|
||||
e = cs.enumerator;
|
||||
let cookie2;
|
||||
while (e.hasMoreElements()) {
|
||||
cookie2 = e.getNext().QueryInterface(Ci.nsICookie);
|
||||
if (cookie.name == cookie2.name)
|
||||
break;
|
||||
}
|
||||
is(cookie.name, cookie2.name, "cookie name successfully restored");
|
||||
is(cookie.value, cookie2.value, "cookie value successfully restored");
|
||||
is(cookie.path, cookie2.path, "cookie path successfully restored");
|
||||
|
||||
// clean up
|
||||
if (gPrefService.prefHasUserValue("browser.sessionstore.interval"))
|
||||
gPrefService.clearUserPref("browser.sessionstore.interval");
|
||||
cs.removeAll();
|
||||
newWin.close();
|
||||
finish();
|
||||
};
|
||||
|
||||
if (newWin.gMultiProcessBrowser) {
|
||||
let tab = newWin.gBrowser.selectedTab;
|
||||
promiseTabRestored(tab).then(ready);
|
||||
} else {
|
||||
ready();
|
||||
}
|
||||
is(i, 1, "expected one cookie");
|
||||
|
||||
// remove the cookie
|
||||
cs.removeAll();
|
||||
|
||||
// restore the window state
|
||||
ss.setWindowState(newWin, state, true);
|
||||
|
||||
// at this point, the cookie should be restored...
|
||||
e = cs.enumerator;
|
||||
let cookie2;
|
||||
while (e.hasMoreElements()) {
|
||||
cookie2 = e.getNext().QueryInterface(Ci.nsICookie);
|
||||
if (cookie.name == cookie2.name)
|
||||
break;
|
||||
}
|
||||
is(cookie.name, cookie2.name, "cookie name successfully restored");
|
||||
is(cookie.value, cookie2.value, "cookie value successfully restored");
|
||||
is(cookie.path, cookie2.path, "cookie path successfully restored");
|
||||
|
||||
// clean up
|
||||
if (gPrefService.prefHasUserValue("browser.sessionstore.interval"))
|
||||
gPrefService.clearUserPref("browser.sessionstore.interval");
|
||||
cs.removeAll();
|
||||
newWin.close();
|
||||
finish();
|
||||
}, true, testURL);
|
||||
});
|
||||
}, false);
|
||||
|
|
|
|||
|
|
@ -416,10 +416,17 @@ let SnapshotsListView = Heritage.extend(WidgetMethods, {
|
|||
return;
|
||||
}
|
||||
|
||||
let channel = NetUtil.newChannel(fp.file);
|
||||
let channel = NetUtil.newChannel2(fp.file,
|
||||
null,
|
||||
null,
|
||||
window.document,
|
||||
null, // aLoadingPrincipal
|
||||
null, // aTriggeringPrincipal
|
||||
Ci.nsILoadInfo.SEC_NORMAL,
|
||||
Ci.nsIContentPolicy.TYPE_OTHER);
|
||||
channel.contentType = "text/plain";
|
||||
|
||||
NetUtil.asyncFetch(channel, (inputStream, status) => {
|
||||
NetUtil.asyncFetch2(channel, (inputStream, status) => {
|
||||
if (!Components.isSuccessCode(status)) {
|
||||
console.error("Could not import recorded animation frame snapshot file.");
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -326,10 +326,17 @@ function saveRecordingToFile(recordingItem, file) {
|
|||
function loadRecordingFromFile(file) {
|
||||
let deferred = promise.defer();
|
||||
|
||||
let channel = NetUtil.newChannel(file);
|
||||
let channel = NetUtil.newChannel2(file,
|
||||
null,
|
||||
null,
|
||||
window.document,
|
||||
null, // aLoadingPrincipal
|
||||
null, // aTriggeringPrincipal
|
||||
Ci.nsILoadInfo.SEC_NORMAL,
|
||||
Ci.nsIContentPolicy.TYPE_OTHER);
|
||||
channel.contentType = "text/plain";
|
||||
|
||||
NetUtil.asyncFetch(channel, (inputStream, status) => {
|
||||
NetUtil.asyncFetch2(channel, (inputStream, status) => {
|
||||
if (!Components.isSuccessCode(status)) {
|
||||
deferred.reject(new Error("Could not import recording data file."));
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -260,7 +260,7 @@ function* getFileData(file) {
|
|||
}
|
||||
let def = promise.defer();
|
||||
|
||||
NetUtil.asyncFetch(file, function(inputStream, status) {
|
||||
NetUtil.asyncFetch2(file, function(inputStream, status) {
|
||||
if (!Components.isSuccessCode(status)) {
|
||||
info("ERROR READING TEMP FILE", status);
|
||||
}
|
||||
|
|
@ -275,7 +275,12 @@ function* getFileData(file) {
|
|||
|
||||
var data = NetUtil.readInputStreamToString(inputStream, inputStream.available());
|
||||
def.resolve(data);
|
||||
});
|
||||
},
|
||||
null, // aLoadingNode
|
||||
Services.scriptSecurityManager.getSystemPrincipal(),
|
||||
null, // aTriggeringPrincipal
|
||||
Ci.nsILoadInfo.SEC_NORMAL,
|
||||
Ci.nsIContentPolicy.TYPE_OTHER);
|
||||
|
||||
return def.promise;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1133,12 +1133,19 @@ var Scratchpad = {
|
|||
importFromFile: function SP_importFromFile(aFile, aSilentError, aCallback)
|
||||
{
|
||||
// Prevent file type detection.
|
||||
let channel = NetUtil.newChannel(aFile);
|
||||
let channel = NetUtil.newChannel2(aFile,
|
||||
null,
|
||||
null,
|
||||
window.document,
|
||||
null, // aLoadingPrincipal
|
||||
null, // aTriggeringPrincipal
|
||||
Ci.nsILoadInfo.SEC_NORMAL,
|
||||
Ci.nsIContentPolicy.TYPE_OTHER);
|
||||
channel.contentType = "application/javascript";
|
||||
|
||||
this.notificationBox.removeAllNotifications(false);
|
||||
|
||||
NetUtil.asyncFetch(channel, (aInputStream, aStatus) => {
|
||||
NetUtil.asyncFetch2(channel, (aInputStream, aStatus) => {
|
||||
let content = null;
|
||||
|
||||
if (Components.isSuccessCode(aStatus)) {
|
||||
|
|
|
|||
|
|
@ -214,10 +214,17 @@ function writeFile(file, content, callback)
|
|||
|
||||
function readFile(file, callback)
|
||||
{
|
||||
let channel = NetUtil.newChannel(file);
|
||||
let channel = NetUtil.newChannel2(file,
|
||||
null,
|
||||
null,
|
||||
null, // aLoadingNode
|
||||
Services.scriptSecurityManager.getSystemPrincipal(),
|
||||
null, // aTriggeringPrincipal
|
||||
Ci.nsILoadInfo.SEC_NORMAL,
|
||||
Ci.nsIContentPolicy.TYPE_OTHER);
|
||||
channel.contentType = "application/javascript";
|
||||
|
||||
NetUtil.asyncFetch(channel, function(inputStream, status) {
|
||||
NetUtil.asyncFetch2(channel, function(inputStream, status) {
|
||||
ok(Components.isSuccessCode(status),
|
||||
"file was read successfully");
|
||||
|
||||
|
|
|
|||
|
|
@ -91,11 +91,18 @@ function fileExported(aStatus)
|
|||
|
||||
gFileContent = oldContent;
|
||||
|
||||
let channel = NetUtil.newChannel(gFile);
|
||||
let channel = NetUtil.newChannel2(gFile,
|
||||
null,
|
||||
null,
|
||||
null, // aLoadingNode
|
||||
Services.scriptSecurityManager.getSystemPrincipal(),
|
||||
null, // aTriggeringPrincipal
|
||||
Ci.nsILoadInfo.SEC_NORMAL,
|
||||
Ci.nsIContentPolicy.TYPE_OTHER);
|
||||
channel.contentType = "application/javascript";
|
||||
|
||||
// Read back the temporary file.
|
||||
NetUtil.asyncFetch(channel, fileRead);
|
||||
NetUtil.asyncFetch2(channel, fileRead);
|
||||
}
|
||||
|
||||
function fileExported2()
|
||||
|
|
|
|||
|
|
@ -185,7 +185,14 @@ AppCacheUtils.prototype = {
|
|||
.createInstance(Ci.nsIScriptableInputStream);
|
||||
let deferred = promise.defer();
|
||||
let buffer = "";
|
||||
let channel = Services.io.newChannel(uri, null, null);
|
||||
let channel = Services.io.newChannel2(uri,
|
||||
null,
|
||||
null,
|
||||
null, // aLoadingNode
|
||||
Services.scriptSecurityManager.getSystemPrincipal(),
|
||||
null, // aTriggeringPrincipal
|
||||
Ci.nsILoadInfo.SEC_NORMAL,
|
||||
Ci.nsIContentPolicy.TYPE_OTHER);
|
||||
|
||||
// Avoid the cache:
|
||||
channel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE;
|
||||
|
|
|
|||
|
|
@ -87,7 +87,14 @@ function read(url) {
|
|||
let scriptableStream = Cc["@mozilla.org/scriptableinputstream;1"]
|
||||
.getService(Ci.nsIScriptableInputStream);
|
||||
|
||||
let channel = Services.io.newChannel(url, null, null);
|
||||
let channel = Services.io.newChannel2(url,
|
||||
null,
|
||||
null,
|
||||
null, // aLoadingNode
|
||||
Services.scriptSecurityManager.getSystemPrincipal(),
|
||||
null, // aTriggeringPrincipal
|
||||
Ci.nsILoadInfo.SEC_NORMAL,
|
||||
Ci.nsIContentPolicy.TYPE_OTHER);
|
||||
let input = channel.open();
|
||||
scriptableStream.init(input);
|
||||
|
||||
|
|
|
|||
|
|
@ -339,7 +339,7 @@ StyleEditorUI.prototype = {
|
|||
// nothing selected
|
||||
return;
|
||||
}
|
||||
NetUtil.asyncFetch(file, (stream, status) => {
|
||||
NetUtil.asyncFetch2(file, (stream, status) => {
|
||||
if (!Components.isSuccessCode(status)) {
|
||||
this.emit("error", { key: LOAD_ERROR });
|
||||
return;
|
||||
|
|
@ -350,8 +350,12 @@ StyleEditorUI.prototype = {
|
|||
this._debuggee.addStyleSheet(source).then((styleSheet) => {
|
||||
this._onStyleSheetCreated(styleSheet, file);
|
||||
});
|
||||
});
|
||||
|
||||
},
|
||||
this._window.document,
|
||||
null, // aLoadingPrincipal
|
||||
null, // aTriggeringPrincipal
|
||||
Ci.nsILoadInfo.SEC_NORMAL,
|
||||
Ci.nsIContentPolicy.TYPE_OTHER);
|
||||
};
|
||||
|
||||
showFilePicker(file, false, parentWindow, onFileSelected);
|
||||
|
|
|
|||
|
|
@ -65,7 +65,14 @@ function read(aSrcChromeURL)
|
|||
let scriptableStream = Cc["@mozilla.org/scriptableinputstream;1"]
|
||||
.getService(Ci.nsIScriptableInputStream);
|
||||
|
||||
let channel = Services.io.newChannel(aSrcChromeURL, null, null);
|
||||
let channel = Services.io.newChannel2(aSrcChromeURL,
|
||||
null,
|
||||
null,
|
||||
null, // aLoadingNode
|
||||
Services.scriptSecurityManager.getSystemPrincipal(),
|
||||
null, // aTriggeringPrincipal
|
||||
Ci.nsILoadInfo.SEC_NORMAL,
|
||||
Ci.nsIContentPolicy.TYPE_OTHER);
|
||||
let input = channel.open();
|
||||
scriptableStream.init(input);
|
||||
|
||||
|
|
|
|||
|
|
@ -150,7 +150,14 @@ function read(aSrcChromeURL)
|
|||
let scriptableStream = Cc["@mozilla.org/scriptableinputstream;1"]
|
||||
.getService(Ci.nsIScriptableInputStream);
|
||||
|
||||
let channel = Services.io.newChannel(aSrcChromeURL, null, null);
|
||||
let channel = Services.io.newChannel2(aSrcChromeURL,
|
||||
null,
|
||||
null,
|
||||
null, // aLoadingNode
|
||||
Services.scriptSecurityManager.getSystemPrincipal(),
|
||||
null, // aTriggeringPrincipal
|
||||
Ci.nsILoadInfo.SEC_NORMAL,
|
||||
Ci.nsIContentPolicy.TYPE_OTHER);
|
||||
let input = channel.open();
|
||||
scriptableStream.init(input);
|
||||
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ SEARCH_PATHS = [
|
|||
'testing/xpcshell',
|
||||
'testing/web-platform',
|
||||
'testing/web-platform/harness',
|
||||
'testing/marionette/client',
|
||||
'testing/marionette/client/marionette',
|
||||
'testing/marionette/transport',
|
||||
'testing/mozbase/mozcrash',
|
||||
|
|
|
|||
|
|
@ -81,6 +81,10 @@ automation/upload: automation/update-packaging
|
|||
# binaries/libs, and that's what we package/test.
|
||||
automation/pretty-package: automation/buildsymbols
|
||||
|
||||
# The installer and packager both run stage-package, and may conflict
|
||||
# with each other.
|
||||
automation/installer: automation/package
|
||||
|
||||
# The 'pretty' versions of targets run before the regular ones to avoid
|
||||
# conflicts in writing to the same files.
|
||||
automation/installer: automation/pretty-installer
|
||||
|
|
|
|||
2
config/external/nss/nss.def
vendored
2
config/external/nss/nss.def
vendored
|
|
@ -677,7 +677,7 @@ VFY_DestroyContext
|
|||
VFY_End
|
||||
VFY_Update
|
||||
VFY_VerifyData
|
||||
VFY_VerifyDataDirect
|
||||
VFY_VerifyDataWithAlgorithmID
|
||||
VFY_VerifyDigestDirect
|
||||
_SGN_VerifyPKCS1DigestInfo
|
||||
PK11_PQG_ParamGenV2
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
// For some reason, Apple's GCC refuses to honor -fno-exceptions when
|
||||
// compiling ObjC.
|
||||
#if __EXCEPTIONS && !(__OBJC__ && __GNUC__ && XP_IOS)
|
||||
#if defined(__EXCEPTIONS) && __EXCEPTIONS && !(__OBJC__ && __GNUC__ && XP_IOS)
|
||||
# error "STL code can only be used with -fno-exceptions"
|
||||
#endif
|
||||
|
||||
|
|
|
|||
14
configure.in
14
configure.in
|
|
@ -622,8 +622,8 @@ See https://developer.mozilla.org/en/Windows_Build_Prerequisites.])
|
|||
])
|
||||
if test "$ac_cv_have_dllimport_exception_bug" = "no"; then
|
||||
WRAP_STL_INCLUDES=1
|
||||
MOZ_MSVC_STL_WRAP__Throw=1
|
||||
AC_DEFINE(MOZ_MSVC_STL_WRAP__Throw)
|
||||
MOZ_MSVC_STL_WRAP_Throw=1
|
||||
AC_DEFINE(MOZ_MSVC_STL_WRAP_Throw)
|
||||
fi
|
||||
else
|
||||
AC_CACHE_CHECK(for overridable _RAISE,
|
||||
|
|
@ -646,8 +646,8 @@ See https://developer.mozilla.org/en/Windows_Build_Prerequisites.])
|
|||
])
|
||||
if test "$ac_cv_have__RAISE" = "yes"; then
|
||||
WRAP_STL_INCLUDES=1
|
||||
MOZ_MSVC_STL_WRAP__RAISE=1
|
||||
AC_DEFINE(MOZ_MSVC_STL_WRAP__RAISE)
|
||||
MOZ_MSVC_STL_WRAP_RAISE=1
|
||||
AC_DEFINE(MOZ_MSVC_STL_WRAP_RAISE)
|
||||
else
|
||||
AC_MSG_ERROR([Gecko exception wrapping doesn't understand your your MSVC/SDK. Please file a bug describing this error and your build configuration.])
|
||||
fi
|
||||
|
|
@ -767,8 +767,8 @@ AC_SUBST(INTEL_CXX)
|
|||
|
||||
AC_SUBST(STL_FLAGS)
|
||||
AC_SUBST(WRAP_STL_INCLUDES)
|
||||
AC_SUBST(MOZ_MSVC_STL_WRAP__Throw)
|
||||
AC_SUBST(MOZ_MSVC_STL_WRAP__RAISE)
|
||||
AC_SUBST(MOZ_MSVC_STL_WRAP_Throw)
|
||||
AC_SUBST(MOZ_MSVC_STL_WRAP_RAISE)
|
||||
|
||||
dnl ========================================================
|
||||
dnl Checks for programs.
|
||||
|
|
@ -7283,7 +7283,7 @@ dnl our own linker.
|
|||
if test "$OS_TARGET" = Android; then
|
||||
MOZ_GLUE_WRAP_LDFLAGS="${MOZ_GLUE_WRAP_LDFLAGS} -Wl,--wrap=PR_GetEnv,--wrap=PR_SetEnv"
|
||||
if test "$MOZ_WIDGET_TOOLKIT" = gonk -a -n "$MOZ_NUWA_PROCESS"; then
|
||||
MOZ_GLUE_WRAP_LDFLAGS="${MOZ_GLUE_WRAP_LDFLAGS} -Wl,--wrap=pthread_create,--wrap=epoll_wait,--wrap=poll,--wrap=pthread_cond_timedwait,--wrap=pthread_cond_wait,--wrap=epoll_create,--wrap=epoll_ctl,--wrap=close,--wrap=pthread_key_create,--wrap=pthread_key_delete,--wrap=socketpair,--wrap=pthread_self,--wrap=pthread_mutex_lock,--wrap=pthread_join,--wrap=pipe,--wrap=pipe2"
|
||||
MOZ_GLUE_WRAP_LDFLAGS="${MOZ_GLUE_WRAP_LDFLAGS} -Wl,--wrap=pthread_create,--wrap=epoll_wait,--wrap=poll,--wrap=pthread_cond_timedwait,--wrap=pthread_cond_wait,--wrap=epoll_create,--wrap=epoll_ctl,--wrap=close,--wrap=pthread_key_create,--wrap=pthread_key_delete,--wrap=socketpair,--wrap=pthread_self,--wrap=pthread_mutex_lock,--wrap=pthread_mutex_trylock,--wrap=pthread_join,--wrap=pipe,--wrap=pipe2"
|
||||
fi
|
||||
if test "$MOZ_WIDGET_TOOLKIT" = android; then
|
||||
MOZ_GLUE_WRAP_LDFLAGS="${MOZ_GLUE_WRAP_LDFLAGS} -Wl,--wrap=getaddrinfo,--wrap=freeaddrinfo,--wrap=gai_strerror"
|
||||
|
|
|
|||
|
|
@ -13754,19 +13754,6 @@ nsDocShell::GetOpener()
|
|||
return opener;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShell::SetOpenedRemote(nsITabParent* aOpenedRemote)
|
||||
{
|
||||
mOpenedRemote = do_GetWeakReference(aOpenedRemote);
|
||||
}
|
||||
|
||||
nsITabParent*
|
||||
nsDocShell::GetOpenedRemote()
|
||||
{
|
||||
nsCOMPtr<nsITabParent> openedRemote(do_QueryReferent(mOpenedRemote));
|
||||
return openedRemote;
|
||||
}
|
||||
|
||||
URLSearchParams*
|
||||
nsDocShell::GetURLSearchParams()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -963,7 +963,6 @@ private:
|
|||
nsTObserverArray<nsWeakPtr> mScrollObservers;
|
||||
nsCString mOriginalUriString;
|
||||
nsWeakPtr mOpener;
|
||||
nsWeakPtr mOpenedRemote;
|
||||
|
||||
// A depth count of how many times NotifyRunToCompletionStart
|
||||
// has been called without a matching NotifyRunToCompletionStop.
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ interface nsITabParent;
|
|||
|
||||
typedef unsigned long nsLoadFlags;
|
||||
|
||||
[scriptable, builtinclass, uuid(888fcf04-a69b-11e4-8d33-6fbb72d2eb03)]
|
||||
[scriptable, builtinclass, uuid(f84b1ae4-2f78-4bad-b36a-6a8516ee6e40)]
|
||||
interface nsIDocShell : nsIDocShellTreeItem
|
||||
{
|
||||
/**
|
||||
|
|
@ -1025,13 +1025,6 @@ interface nsIDocShell : nsIDocShellTreeItem
|
|||
[noscript,notxpcom,nostdcall] void setOpener(in nsITabParent aOpener);
|
||||
[noscript,notxpcom,nostdcall] nsITabParent getOpener();
|
||||
|
||||
/**
|
||||
* See the documentation for setOpener and getOpener about why we
|
||||
* don't use attribute here instead.
|
||||
*/
|
||||
[noscript,notxpcom,nostdcall] void setOpenedRemote(in nsITabParent aOpenedRemote);
|
||||
[noscript,notxpcom,nostdcall] nsITabParent getOpenedRemote();
|
||||
|
||||
// URLSearchParams for the window.location is owned by the docShell.
|
||||
[noscript,notxpcom] URLSearchParams getURLSearchParams();
|
||||
|
||||
|
|
|
|||
|
|
@ -992,6 +992,8 @@ Element::CreateShadowRoot(ErrorResult& aError)
|
|||
nsRefPtr<ShadowRoot> shadowRoot = new ShadowRoot(this, nodeInfo.forget(),
|
||||
protoBinding);
|
||||
|
||||
shadowRoot->SetIsComposedDocParticipant(IsInComposedDoc());
|
||||
|
||||
// Replace the old ShadowRoot with the new one and let the old
|
||||
// ShadowRoot know about the younger ShadowRoot because the old
|
||||
// ShadowRoot is projected into the younger ShadowRoot's shadow
|
||||
|
|
@ -1007,6 +1009,8 @@ Element::CreateShadowRoot(ErrorResult& aError)
|
|||
child = child->GetNextSibling()) {
|
||||
child->UnbindFromTree(true, false);
|
||||
}
|
||||
|
||||
olderShadow->SetIsComposedDocParticipant(false);
|
||||
}
|
||||
|
||||
// xblBinding takes ownership of docInfo.
|
||||
|
|
@ -1469,13 +1473,6 @@ Element::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
|||
// Being added to a document.
|
||||
SetInDocument();
|
||||
|
||||
// Attached callback must be enqueued whenever custom element is inserted into a
|
||||
// document and this document has a browsing context.
|
||||
if (GetCustomElementData() && aDocument->GetDocShell()) {
|
||||
// Enqueue an attached callback for the custom element.
|
||||
aDocument->EnqueueLifecycleCallback(nsIDocument::eAttached, this);
|
||||
}
|
||||
|
||||
// Unset this flag since we now really are in a document.
|
||||
UnsetFlags(NODE_FORCE_XBL_BINDINGS |
|
||||
// And clear the lazy frame construction bits.
|
||||
|
|
@ -1498,6 +1495,16 @@ Element::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
|||
SetSubtreeRootPointer(aParent->SubtreeRoot());
|
||||
}
|
||||
|
||||
nsIDocument* composedDoc = GetComposedDoc();
|
||||
if (composedDoc) {
|
||||
// Attached callback must be enqueued whenever custom element is inserted into a
|
||||
// document and this document has a browsing context.
|
||||
if (GetCustomElementData() && composedDoc->GetDocShell()) {
|
||||
// Enqueue an attached callback for the custom element.
|
||||
composedDoc->EnqueueLifecycleCallback(nsIDocument::eAttached, this);
|
||||
}
|
||||
}
|
||||
|
||||
// Propagate scoped style sheet tracking bit.
|
||||
if (mParent->IsContent()) {
|
||||
nsIContent* parent;
|
||||
|
|
@ -1578,6 +1585,7 @@ Element::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
|||
// Call BindToTree on shadow root children.
|
||||
ShadowRoot* shadowRoot = GetShadowRoot();
|
||||
if (shadowRoot) {
|
||||
shadowRoot->SetIsComposedDocParticipant(IsInComposedDoc());
|
||||
for (nsIContent* child = shadowRoot->GetFirstChild(); child;
|
||||
child = child->GetNextSibling()) {
|
||||
rv = child->BindToTree(nullptr, shadowRoot,
|
||||
|
|
@ -1635,8 +1643,7 @@ Element::UnbindFromTree(bool aDeep, bool aNullParent)
|
|||
|
||||
// Make sure to unbind this node before doing the kids
|
||||
nsIDocument* document =
|
||||
HasFlag(NODE_FORCE_XBL_BINDINGS) || IsInShadowTree() ?
|
||||
OwnerDoc() : GetUncomposedDoc();
|
||||
HasFlag(NODE_FORCE_XBL_BINDINGS) ? OwnerDoc() : GetComposedDoc();
|
||||
|
||||
if (aNullParent) {
|
||||
if (IsFullScreenAncestor()) {
|
||||
|
|
@ -1756,6 +1763,8 @@ Element::UnbindFromTree(bool aDeep, bool aNullParent)
|
|||
child = child->GetNextSibling()) {
|
||||
child->UnbindFromTree(true, false);
|
||||
}
|
||||
|
||||
shadowRoot->SetIsComposedDocParticipant(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -642,6 +642,10 @@ File::Constructor(const GlobalObject& aGlobal,
|
|||
}
|
||||
MOZ_ASSERT(impl->IsFile());
|
||||
|
||||
if (aBag.mLastModified.WasPassed()) {
|
||||
impl->SetLastModified(aBag.mLastModified.Value());
|
||||
}
|
||||
|
||||
nsRefPtr<File> domFile = new File(aGlobal.GetAsSupports(), impl);
|
||||
return domFile.forget();
|
||||
}
|
||||
|
|
@ -667,6 +671,10 @@ File::Constructor(const GlobalObject& aGlobal,
|
|||
}
|
||||
MOZ_ASSERT(impl->IsFile());
|
||||
|
||||
if (aBag.mLastModified.WasPassed()) {
|
||||
impl->SetLastModified(aBag.mLastModified.Value());
|
||||
}
|
||||
|
||||
nsRefPtr<File> domFile = new File(aGlobal.GetAsSupports(), impl);
|
||||
return domFile.forget();
|
||||
}
|
||||
|
|
@ -691,6 +699,10 @@ File::Constructor(const GlobalObject& aGlobal,
|
|||
}
|
||||
MOZ_ASSERT(impl->IsFile());
|
||||
|
||||
if (aBag.mLastModified.WasPassed()) {
|
||||
impl->SetLastModified(aBag.mLastModified.Value());
|
||||
}
|
||||
|
||||
nsRefPtr<File> domFile = new File(aGlobal.GetAsSupports(), impl);
|
||||
return domFile.forget();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -189,6 +189,8 @@ MultipartFileImpl::SetLengthAndModifiedDate()
|
|||
MOZ_ASSERT(mLastModificationDate == UINT64_MAX);
|
||||
|
||||
uint64_t totalLength = 0;
|
||||
uint64_t lastModified = 0;
|
||||
bool lastModifiedSet = false;
|
||||
|
||||
for (uint32_t index = 0, count = mBlobImpls.Length(); index < count; index++) {
|
||||
nsRefPtr<FileImpl>& blob = mBlobImpls[index];
|
||||
|
|
@ -204,6 +206,16 @@ MultipartFileImpl::SetLengthAndModifiedDate()
|
|||
|
||||
MOZ_ASSERT(UINT64_MAX - subBlobLength >= totalLength);
|
||||
totalLength += subBlobLength;
|
||||
|
||||
if (blob->IsFile()) {
|
||||
uint64_t partLastModified = blob->GetLastModified(error);
|
||||
MOZ_ALWAYS_TRUE(!error.Failed());
|
||||
|
||||
if (lastModified < partLastModified) {
|
||||
lastModified = partLastModified;
|
||||
lastModifiedSet = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mLength = totalLength;
|
||||
|
|
@ -213,7 +225,8 @@ MultipartFileImpl::SetLengthAndModifiedDate()
|
|||
// var x = new Date(); var f = new File(...);
|
||||
// x.getTime() < f.dateModified.getTime()
|
||||
// could fail.
|
||||
mLastModificationDate = JS_Now();
|
||||
mLastModificationDate =
|
||||
lastModifiedSet ? lastModified * PR_USEC_PER_MSEC : JS_Now();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ ShadowRoot::ShadowRoot(nsIContent* aContent,
|
|||
nsXBLPrototypeBinding* aProtoBinding)
|
||||
: DocumentFragment(aNodeInfo), mPoolHost(aContent),
|
||||
mProtoBinding(aProtoBinding), mShadowElement(nullptr),
|
||||
mInsertionPointChanged(false)
|
||||
mInsertionPointChanged(false), mIsComposedDocParticipant(false)
|
||||
{
|
||||
SetHost(aContent);
|
||||
|
||||
|
|
|
|||
|
|
@ -127,6 +127,12 @@ public:
|
|||
Element* Host();
|
||||
ShadowRoot* GetOlderShadowRoot() { return mOlderShadow; }
|
||||
void StyleSheetChanged();
|
||||
|
||||
bool IsComposedDocParticipant() { return mIsComposedDocParticipant; }
|
||||
void SetIsComposedDocParticipant(bool aIsComposedDocParticipant)
|
||||
{
|
||||
mIsComposedDocParticipant = aIsComposedDocParticipant;
|
||||
}
|
||||
protected:
|
||||
virtual ~ShadowRoot();
|
||||
|
||||
|
|
@ -171,6 +177,12 @@ protected:
|
|||
// the insertion points. After this flag is set, nodes will be distributed
|
||||
// on the next mutation event.
|
||||
bool mInsertionPointChanged;
|
||||
|
||||
// Flag to indicate whether the descendants of this shadow root are part of the
|
||||
// composed document. Ideally, we would use a node flag on nodes to
|
||||
// mark whether it is in the composed document, but we have run out of flags
|
||||
// so instead we track it here.
|
||||
bool mIsComposedDocParticipant;
|
||||
};
|
||||
|
||||
class ShadowRootStyleSheetList : public StyleSheetList
|
||||
|
|
|
|||
|
|
@ -224,7 +224,7 @@ NS_GetContentList(nsINode* aRootNode,
|
|||
// First we look in our hashtable. Then we create a content list if needed
|
||||
if (gContentListHashTable.IsInitialized()) {
|
||||
entry = static_cast<ContentListHashEntry *>
|
||||
(PL_DHashTableAdd(&gContentListHashTable, &hashKey, fallible));
|
||||
(PL_DHashTableAdd(&gContentListHashTable, &hashKey));
|
||||
if (entry)
|
||||
list = entry->mContentList;
|
||||
}
|
||||
|
|
@ -332,7 +332,8 @@ GetFuncStringContentList(nsINode* aRootNode,
|
|||
nsFuncStringCacheKey hashKey(aRootNode, aFunc, aString);
|
||||
|
||||
entry = static_cast<FuncStringContentListHashEntry *>
|
||||
(PL_DHashTableAdd(&gFuncStringContentListHashTable, &hashKey, fallible));
|
||||
(PL_DHashTableAdd(&gFuncStringContentListHashTable,
|
||||
&hashKey));
|
||||
if (entry) {
|
||||
list = entry->mContentList;
|
||||
#ifdef DEBUG
|
||||
|
|
|
|||
|
|
@ -3964,7 +3964,7 @@ nsContentUtils::GetListenerManagerForNode(nsINode *aNode)
|
|||
|
||||
EventListenerManagerMapEntry *entry =
|
||||
static_cast<EventListenerManagerMapEntry *>
|
||||
(PL_DHashTableAdd(&sEventListenerManagersHash, aNode, fallible));
|
||||
(PL_DHashTableAdd(&sEventListenerManagersHash, aNode));
|
||||
|
||||
if (!entry) {
|
||||
return nullptr;
|
||||
|
|
|
|||
|
|
@ -458,7 +458,7 @@ CustomElementCallback::Call()
|
|||
|
||||
// If ELEMENT is in a document and this document has a browsing context,
|
||||
// enqueue attached callback for ELEMENT.
|
||||
nsIDocument* document = mThisObject->GetUncomposedDoc();
|
||||
nsIDocument* document = mThisObject->GetComposedDoc();
|
||||
if (document && document->GetDocShell()) {
|
||||
document->EnqueueLifecycleCallback(nsIDocument::eAttached, mThisObject);
|
||||
}
|
||||
|
|
@ -1715,8 +1715,8 @@ nsDocument::~nsDocument()
|
|||
// Kill the subdocument map, doing this will release its strong
|
||||
// references, if any.
|
||||
if (mSubDocuments) {
|
||||
PL_DHashTableFinish(mSubDocuments);
|
||||
delete mSubDocuments;
|
||||
PL_DHashTableDestroy(mSubDocuments);
|
||||
|
||||
mSubDocuments = nullptr;
|
||||
}
|
||||
|
||||
|
|
@ -2126,8 +2126,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDocument)
|
|||
}
|
||||
|
||||
if (tmp->mSubDocuments) {
|
||||
PL_DHashTableFinish(tmp->mSubDocuments);
|
||||
delete tmp->mSubDocuments;
|
||||
PL_DHashTableDestroy(tmp->mSubDocuments);
|
||||
tmp->mSubDocuments = nullptr;
|
||||
}
|
||||
|
||||
|
|
@ -2332,8 +2331,8 @@ nsDocument::ResetToURI(nsIURI *aURI, nsILoadGroup *aLoadGroup,
|
|||
// Delete references to sub-documents and kill the subdocument map,
|
||||
// if any. It holds strong references
|
||||
if (mSubDocuments) {
|
||||
PL_DHashTableFinish(mSubDocuments);
|
||||
delete mSubDocuments;
|
||||
PL_DHashTableDestroy(mSubDocuments);
|
||||
|
||||
mSubDocuments = nullptr;
|
||||
}
|
||||
|
||||
|
|
@ -4002,13 +4001,16 @@ nsDocument::SetSubDocumentFor(Element* aElement, nsIDocument* aSubDoc)
|
|||
SubDocInitEntry
|
||||
};
|
||||
|
||||
mSubDocuments = new PLDHashTable();
|
||||
PL_DHashTableInit(mSubDocuments, &hash_table_ops, sizeof(SubDocMapEntry));
|
||||
mSubDocuments = PL_NewDHashTable(&hash_table_ops, sizeof(SubDocMapEntry));
|
||||
if (!mSubDocuments) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
// Add a mapping to the hash table
|
||||
SubDocMapEntry *entry = static_cast<SubDocMapEntry*>
|
||||
(PL_DHashTableAdd(mSubDocuments, aElement, fallible));
|
||||
SubDocMapEntry *entry =
|
||||
static_cast<SubDocMapEntry*>
|
||||
(PL_DHashTableAdd(mSubDocuments, aElement));
|
||||
|
||||
if (!entry) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
|
|
|||
|
|
@ -169,14 +169,12 @@ nsFrameLoader::nsFrameLoader(Element* aOwner, bool aNetworkCreated)
|
|||
, mRemoteFrame(false)
|
||||
, mClipSubdocument(true)
|
||||
, mClampScrollPosition(true)
|
||||
, mRemoteBrowserInitialized(false)
|
||||
, mObservingOwnerContent(false)
|
||||
, mVisible(true)
|
||||
, mCurrentRemoteFrame(nullptr)
|
||||
, mRemoteBrowser(nullptr)
|
||||
, mChildID(0)
|
||||
, mEventMode(EVENT_MODE_NORMAL_DISPATCH)
|
||||
, mPendingFrameSent(false)
|
||||
{
|
||||
ResetPermissionManagerStatus();
|
||||
}
|
||||
|
|
@ -363,15 +361,6 @@ nsFrameLoader::ReallyStartLoadingInternal()
|
|||
|
||||
if (mRemoteFrame) {
|
||||
if (!mRemoteBrowser) {
|
||||
if (!mPendingFrameSent) {
|
||||
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
|
||||
if (os && !mRemoteBrowserInitialized) {
|
||||
os->NotifyObservers(NS_ISUPPORTS_CAST(nsIFrameLoader*, this),
|
||||
"remote-browser-pending", nullptr);
|
||||
mPendingFrameSent = true;
|
||||
}
|
||||
}
|
||||
|
||||
TryRemoteBrowser();
|
||||
|
||||
if (!mRemoteBrowser) {
|
||||
|
|
@ -913,16 +902,11 @@ nsFrameLoader::ShowRemoteFrame(const nsIntSize& size,
|
|||
|
||||
EnsureMessageManager();
|
||||
|
||||
InitializeBrowserAPI();
|
||||
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
|
||||
if (os && !mRemoteBrowserInitialized) {
|
||||
if (!mPendingFrameSent) {
|
||||
os->NotifyObservers(NS_ISUPPORTS_CAST(nsIFrameLoader*, this),
|
||||
"remote-browser-pending", nullptr);
|
||||
mPendingFrameSent = true;
|
||||
}
|
||||
if (os) {
|
||||
os->NotifyObservers(NS_ISUPPORTS_CAST(nsIFrameLoader*, this),
|
||||
"remote-browser-shown", nullptr);
|
||||
mRemoteBrowserInitialized = true;
|
||||
}
|
||||
} else {
|
||||
nsIntRect dimensions;
|
||||
|
|
@ -1785,6 +1769,7 @@ nsFrameLoader::MaybeCreateDocShell()
|
|||
mDocShell->SetIsBrowserInsideApp(containingAppId);
|
||||
}
|
||||
|
||||
InitializeBrowserAPI();
|
||||
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
|
||||
if (os) {
|
||||
os->NotifyObservers(NS_ISUPPORTS_CAST(nsIFrameLoader*, this),
|
||||
|
|
@ -2205,7 +2190,6 @@ nsFrameLoader::TryRemoteBrowser()
|
|||
eCaseMatters)) {
|
||||
unused << mRemoteBrowser->SendSetUpdateHitRegion(true);
|
||||
}
|
||||
parentDocShell->SetOpenedRemote(mRemoteBrowser);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
@ -2749,3 +2733,12 @@ nsFrameLoader::GetLoadContext(nsILoadContext** aLoadContext)
|
|||
loadContext.forget(aLoadContext);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsFrameLoader::InitializeBrowserAPI()
|
||||
{
|
||||
nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(mOwnerContent);
|
||||
if (browserFrame) {
|
||||
browserFrame->InitializeBrowserAPI();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -312,6 +312,8 @@ private:
|
|||
// own-or-containing-app.
|
||||
void ResetPermissionManagerStatus();
|
||||
|
||||
void InitializeBrowserAPI();
|
||||
|
||||
nsCOMPtr<nsIDocShell> mDocShell;
|
||||
nsCOMPtr<nsIURI> mURIToLoad;
|
||||
mozilla::dom::Element* mOwnerContent; // WEAK
|
||||
|
|
@ -351,7 +353,6 @@ private:
|
|||
bool mRemoteFrame : 1;
|
||||
bool mClipSubdocument : 1;
|
||||
bool mClampScrollPosition : 1;
|
||||
bool mRemoteBrowserInitialized : 1;
|
||||
bool mObservingOwnerContent : 1;
|
||||
|
||||
// Backs nsIFrameLoader::{Get,Set}Visible. Visibility state here relates to
|
||||
|
|
@ -369,9 +370,6 @@ private:
|
|||
// See nsIFrameLoader.idl. EVENT_MODE_NORMAL_DISPATCH automatically
|
||||
// forwards some input events to out-of-process content.
|
||||
uint32_t mEventMode;
|
||||
|
||||
// Indicate if we have sent 'remote-browser-pending'.
|
||||
bool mPendingFrameSent;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -113,6 +113,10 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
|||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGenericDOMDataNode)
|
||||
nsINode::Unlink(tmp);
|
||||
|
||||
// Clear flag here because unlinking slots will clear the
|
||||
// containing shadow root pointer.
|
||||
tmp->UnsetFlags(NODE_IS_IN_SHADOW_TREE);
|
||||
|
||||
nsDataSlots *slots = tmp->GetExistingDataSlots();
|
||||
if (slots) {
|
||||
slots->Unlink();
|
||||
|
|
@ -562,8 +566,7 @@ nsGenericDOMDataNode::UnbindFromTree(bool aDeep, bool aNullParent)
|
|||
NS_REFRAME_IF_WHITESPACE);
|
||||
|
||||
nsIDocument* document =
|
||||
HasFlag(NODE_FORCE_XBL_BINDINGS) || IsInShadowTree() ?
|
||||
OwnerDoc() : GetUncomposedDoc();
|
||||
HasFlag(NODE_FORCE_XBL_BINDINGS) ? OwnerDoc() : GetComposedDoc();
|
||||
|
||||
if (aNullParent) {
|
||||
if (GetParent()) {
|
||||
|
|
|
|||
|
|
@ -390,17 +390,8 @@ nsINode::GetComposedDocInternal() const
|
|||
MOZ_ASSERT(HasFlag(NODE_IS_IN_SHADOW_TREE) && IsContent(),
|
||||
"Should only be caled on nodes in the shadow tree.");
|
||||
|
||||
// Cross ShadowRoot boundary.
|
||||
ShadowRoot* containingShadow = AsContent()->GetContainingShadow();
|
||||
|
||||
nsIContent* poolHost = containingShadow->GetPoolHost();
|
||||
if (!poolHost) {
|
||||
// This node is in an older shadow root that does not get projected into
|
||||
// an insertion point, thus this node can not be in the composed document.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return poolHost->GetComposedDoc();
|
||||
return containingShadow->IsComposedDocParticipant() ? OwnerDoc() : nullptr;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
|
|
|||
|
|
@ -520,11 +520,9 @@ public:
|
|||
}
|
||||
|
||||
/**
|
||||
* This method gets the current doc of the node hosting this content
|
||||
* or the current doc of this content if it is not being hosted. This
|
||||
* method walks through ShadowRoot boundaries until it reach the host
|
||||
* that is located in the root of the "tree of trees" (see Shadow DOM
|
||||
* spec) and returns the current doc for that host.
|
||||
* This method returns the owner doc if the node is in the
|
||||
* composed document (as defined in the Shadow DOM spec), otherwise
|
||||
* it returns null.
|
||||
*/
|
||||
nsIDocument* GetComposedDoc() const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ interface nsISlowScriptDebugCallback : nsISupports
|
|||
};
|
||||
|
||||
[scriptable, function, uuid(b1c6ecd0-8fa4-11e4-b4a9-0800200c9a66)]
|
||||
interface nsISlowScriptDebugerStartupCallback : nsISupports
|
||||
interface nsISlowScriptDebuggerStartupCallback : nsISupports
|
||||
{
|
||||
void finishDebuggerStartup();
|
||||
};
|
||||
|
|
@ -23,7 +23,7 @@ interface nsISlowScriptDebugerStartupCallback : nsISupports
|
|||
interface nsISlowScriptDebugRemoteCallback : nsISupports
|
||||
{
|
||||
void handleSlowScriptDebug(in nsIDOMEventTarget aBrowser,
|
||||
in nsISlowScriptDebugerStartupCallback aCallback);
|
||||
in nsISlowScriptDebuggerStartupCallback aCallback);
|
||||
};
|
||||
|
||||
[scriptable, uuid(f75d4164-3aa7-4395-ba44-a5f95b2e8427)]
|
||||
|
|
|
|||
|
|
@ -230,7 +230,7 @@ nsPropertyTable::SetPropertyInternal(nsPropertyOwner aObject,
|
|||
// value is destroyed
|
||||
nsresult result = NS_OK;
|
||||
PropertyListMapEntry *entry = static_cast<PropertyListMapEntry*>
|
||||
(PL_DHashTableAdd(&propertyList->mObjectValueMap, aObject, fallible));
|
||||
(PL_DHashTableAdd(&propertyList->mObjectValueMap, aObject));
|
||||
if (!entry)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
// A nullptr entry->key is the sign that the entry has just been allocated
|
||||
|
|
|
|||
|
|
@ -122,16 +122,19 @@ NS_IMPL_ISUPPORTS(
|
|||
nsIMemoryReporter)
|
||||
|
||||
nsScriptNameSpaceManager::nsScriptNameSpaceManager()
|
||||
: mIsInitialized(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsScriptNameSpaceManager);
|
||||
}
|
||||
|
||||
nsScriptNameSpaceManager::~nsScriptNameSpaceManager()
|
||||
{
|
||||
UnregisterWeakMemoryReporter(this);
|
||||
// Destroy the hash
|
||||
PL_DHashTableFinish(&mGlobalNames);
|
||||
PL_DHashTableFinish(&mNavigatorNames);
|
||||
if (mIsInitialized) {
|
||||
UnregisterWeakMemoryReporter(this);
|
||||
// Destroy the hash
|
||||
PL_DHashTableFinish(&mGlobalNames);
|
||||
PL_DHashTableFinish(&mNavigatorNames);
|
||||
}
|
||||
MOZ_COUNT_DTOR(nsScriptNameSpaceManager);
|
||||
}
|
||||
|
||||
|
|
@ -139,8 +142,9 @@ nsGlobalNameStruct *
|
|||
nsScriptNameSpaceManager::AddToHash(PLDHashTable *aTable, const nsAString *aKey,
|
||||
const char16_t **aClassName)
|
||||
{
|
||||
GlobalNameMapEntry *entry = static_cast<GlobalNameMapEntry *>
|
||||
(PL_DHashTableAdd(aTable, aKey, fallible));
|
||||
GlobalNameMapEntry *entry =
|
||||
static_cast<GlobalNameMapEntry *>
|
||||
(PL_DHashTableAdd(aTable, aKey));
|
||||
|
||||
if (!entry) {
|
||||
return nullptr;
|
||||
|
|
@ -322,13 +326,21 @@ nsScriptNameSpaceManager::Init()
|
|||
GlobalNameHashInitEntry
|
||||
};
|
||||
|
||||
PL_DHashTableInit(&mGlobalNames, &hash_table_ops,
|
||||
sizeof(GlobalNameMapEntry),
|
||||
GLOBALNAME_HASHTABLE_INITIAL_LENGTH);
|
||||
mIsInitialized = PL_DHashTableInit(&mGlobalNames, &hash_table_ops,
|
||||
sizeof(GlobalNameMapEntry),
|
||||
fallible,
|
||||
GLOBALNAME_HASHTABLE_INITIAL_LENGTH);
|
||||
NS_ENSURE_TRUE(mIsInitialized, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
PL_DHashTableInit(&mNavigatorNames, &hash_table_ops,
|
||||
sizeof(GlobalNameMapEntry),
|
||||
GLOBALNAME_HASHTABLE_INITIAL_LENGTH);
|
||||
mIsInitialized = PL_DHashTableInit(&mNavigatorNames, &hash_table_ops,
|
||||
sizeof(GlobalNameMapEntry),
|
||||
fallible,
|
||||
GLOBALNAME_HASHTABLE_INITIAL_LENGTH);
|
||||
if (!mIsInitialized) {
|
||||
PL_DHashTableFinish(&mGlobalNames);
|
||||
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
RegisterWeakMemoryReporter(this);
|
||||
|
||||
|
|
|
|||
|
|
@ -240,6 +240,8 @@ private:
|
|||
|
||||
PLDHashTable mGlobalNames;
|
||||
PLDHashTable mNavigatorNames;
|
||||
|
||||
bool mIsInitialized;
|
||||
};
|
||||
|
||||
#endif /* nsScriptNameSpaceManager_h__ */
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
#include "nsWrapperCacheInlines.h"
|
||||
|
||||
#include "jsproxy.h"
|
||||
#include "js/Proxy.h"
|
||||
#include "mozilla/dom/DOMJSProxyHandler.h"
|
||||
#include "mozilla/HoldDropJSObjects.h"
|
||||
#include "nsCycleCollectionTraversalCallback.h"
|
||||
|
|
|
|||
|
|
@ -11,5 +11,7 @@ addMessageListener("file.open", function () {
|
|||
sendAsyncMessage("file.opened", {
|
||||
file: new File(testFile),
|
||||
mtime: testFile.lastModifiedTime,
|
||||
fileWithDate: new File(testFile, { lastModified: 123 }),
|
||||
fileDate: 123,
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ function onOpened(message) {
|
|||
ok("lastModifiedDate" in domFile, "lastModifiedDate must be present");
|
||||
|
||||
var d = new Date(message.mtime);
|
||||
todo(d.getTime() == domFile.lastModifiedDate.getTime(), "lastModifiedDate should be the same (FIXME: bug 1121722)");
|
||||
is(d.getTime(), domFile.lastModifiedDate.getTime(), "lastModifiedDate should be the same");
|
||||
|
||||
var x = new Date();
|
||||
|
||||
|
|
@ -51,6 +51,11 @@ function onOpened(message) {
|
|||
var z = new Date();
|
||||
|
||||
ok((x.getTime() <= y.getTime()) && (y.getTime() <= z.getTime()), "lastModifiedDate of file which does not have last modified date should be current time");
|
||||
|
||||
|
||||
var d = new Date(message.fileDate);
|
||||
is(d.getTime(), message.fileWithDate.lastModifiedDate.getTime(), "lastModifiedDate should be the same when lastModified is set: " + message.fileWithDate.lastModified);
|
||||
|
||||
script.destroy();
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
#include "mozilla/Likely.h"
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "jsproxy.h"
|
||||
#include "js/Proxy.h"
|
||||
#include "nsString.h"
|
||||
|
||||
#define DOM_PROXY_OBJECT_SLOT js::PROXY_PRIVATE_SLOT
|
||||
|
|
|
|||
|
|
@ -224,6 +224,17 @@ TextComposition::DispatchCompositionEvent(
|
|||
dispatchEvent = dispatchDOMTextEvent = false;
|
||||
}
|
||||
|
||||
// widget may dispatch redundant NS_COMPOSITION_CHANGE event
|
||||
// which modifies neither composition string, clauses nor caret
|
||||
// position. In such case, we shouldn't dispatch DOM events.
|
||||
if (dispatchDOMTextEvent &&
|
||||
aCompositionEvent->message == NS_COMPOSITION_CHANGE &&
|
||||
mLastData == aCompositionEvent->mData &&
|
||||
mRanges && aCompositionEvent->mRanges &&
|
||||
mRanges->Equals(*aCompositionEvent->mRanges)) {
|
||||
dispatchEvent = dispatchDOMTextEvent = false;
|
||||
}
|
||||
|
||||
if (dispatchDOMTextEvent) {
|
||||
if (!MaybeDispatchCompositionUpdate(aCompositionEvent)) {
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -224,6 +224,8 @@ nsGeolocationSettings::HandleGeolocationAlaEnabledChange(const JS::Value& aVal)
|
|||
void
|
||||
nsGeolocationSettings::HandleGeolocationPerOriginSettingsChange(const JS::Value& aVal)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!aVal.isObject()) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -231,11 +233,17 @@ nsGeolocationSettings::HandleGeolocationPerOriginSettingsChange(const JS::Value&
|
|||
// clear the hash table
|
||||
mPerOriginSettings.Clear();
|
||||
|
||||
// enumerate the array
|
||||
AutoJSAPI jsapi;
|
||||
jsapi.Init();
|
||||
JSContext* cx = jsapi.cx();
|
||||
JS::Rooted<JSObject*> obj(cx, &aVal.toObject());
|
||||
// root the object and get the global
|
||||
JS::Rooted<JSObject*> obj(nsContentUtils::RootingCx(), &aVal.toObject());
|
||||
MOZ_ASSERT(obj);
|
||||
nsIGlobalObject* global = xpc::NativeGlobal(obj);
|
||||
NS_ENSURE_TRUE_VOID(global && global->GetGlobalJSObject());
|
||||
|
||||
// because the spec requires calling getters when enumerating the key of a
|
||||
// dictionary
|
||||
AutoEntryScript aes(global);
|
||||
aes.TakeOwnershipOfErrorReporting();
|
||||
JSContext *cx = aes.cx();
|
||||
JS::AutoIdArray ids(cx, JS_Enumerate(cx, obj));
|
||||
|
||||
// if we get no ids then the exception list is empty and we can return here.
|
||||
|
|
|
|||
|
|
@ -146,6 +146,8 @@ HTMLShadowElement::BindToTree(nsIDocument* aDocument,
|
|||
// Propagate BindToTree calls to projected shadow root children.
|
||||
ShadowRoot* projectedShadow = containingShadow->GetOlderShadowRoot();
|
||||
if (projectedShadow) {
|
||||
projectedShadow->SetIsComposedDocParticipant(IsInComposedDoc());
|
||||
|
||||
for (nsIContent* child = projectedShadow->GetFirstChild(); child;
|
||||
child = child->GetNextSibling()) {
|
||||
rv = child->BindToTree(nullptr, projectedShadow,
|
||||
|
|
@ -173,6 +175,8 @@ HTMLShadowElement::UnbindFromTree(bool aDeep, bool aNullParent)
|
|||
child = child->GetNextSibling()) {
|
||||
child->UnbindFromTree(true, false);
|
||||
}
|
||||
|
||||
projectedShadow->SetIsComposedDocParticipant(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -157,15 +157,14 @@ void
|
|||
HTMLStyleElement::UnbindFromTree(bool aDeep, bool aNullParent)
|
||||
{
|
||||
nsCOMPtr<nsIDocument> oldDoc = GetUncomposedDoc();
|
||||
nsCOMPtr<nsIDocument> oldComposedDoc = GetComposedDoc();
|
||||
ShadowRoot* oldShadow = GetContainingShadow();
|
||||
|
||||
nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
|
||||
|
||||
if (GetContainingShadow() && !oldComposedDoc) {
|
||||
// The style is in a shadow tree and was already not
|
||||
// in the composed document. Thus the sheet does not
|
||||
// need to be updated.
|
||||
if (oldShadow && GetContainingShadow()) {
|
||||
// The style is in a shadow tree and is still in the
|
||||
// shadow tree. Thus the sheets in the shadow DOM
|
||||
// do not need to be updated.
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,91 +19,12 @@
|
|||
#include "nsIDOMDOMRequest.h"
|
||||
#include "nsIDOMElement.h"
|
||||
#include "nsINode.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsIPrincipal.h"
|
||||
#include "nsWeakReference.h"
|
||||
|
||||
using namespace mozilla::dom;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
static const char kRemoteBrowserPending[] = "remote-browser-pending";
|
||||
static const char kInprocessBrowserShown[] = "inprocess-browser-shown";
|
||||
|
||||
class nsBrowserElement::BrowserShownObserver : public nsIObserver
|
||||
, public nsSupportsWeakReference
|
||||
{
|
||||
public:
|
||||
explicit BrowserShownObserver(nsBrowserElement* aBrowserElement);
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIOBSERVER
|
||||
void AddObserver();
|
||||
void RemoveObserver();
|
||||
private:
|
||||
virtual ~BrowserShownObserver();
|
||||
|
||||
// Weak reference to the browser element. nsBrowserElement has a
|
||||
// reference to us. nsBrowserElement's destructor is responsible to
|
||||
// null out this weak reference via RemoveObserver()
|
||||
nsBrowserElement* mBrowserElement;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsBrowserElement::BrowserShownObserver, nsIObserver, nsISupportsWeakReference)
|
||||
|
||||
nsBrowserElement::BrowserShownObserver::BrowserShownObserver(nsBrowserElement* aBrowserElement)
|
||||
: mBrowserElement(aBrowserElement)
|
||||
{
|
||||
}
|
||||
|
||||
nsBrowserElement::BrowserShownObserver::~BrowserShownObserver()
|
||||
{
|
||||
RemoveObserver();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBrowserElement::BrowserShownObserver::Observe(nsISupports* aSubject,
|
||||
const char* aTopic,
|
||||
const char16_t* aData)
|
||||
{
|
||||
NS_ENSURE_TRUE(mBrowserElement, NS_OK);
|
||||
|
||||
if (!strcmp(aTopic, kRemoteBrowserPending) ||
|
||||
!strcmp(aTopic, kInprocessBrowserShown)) {
|
||||
nsCOMPtr<nsIFrameLoader> frameLoader = do_QueryInterface(aSubject);
|
||||
nsCOMPtr<nsIFrameLoader> myFrameLoader = mBrowserElement->GetFrameLoader();
|
||||
// The browser element API needs the frameloader to
|
||||
// initialize. We still use the observer to get notified when the
|
||||
// frameloader is created. So we check if the frameloader created
|
||||
// is ours, then initialize the browser element API.
|
||||
if (frameLoader && frameLoader == myFrameLoader) {
|
||||
mBrowserElement->InitBrowserElementAPI();
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsBrowserElement::BrowserShownObserver::AddObserver()
|
||||
{
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
if (obs) {
|
||||
obs->AddObserver(this, kRemoteBrowserPending, true);
|
||||
obs->AddObserver(this, kInprocessBrowserShown, true);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsBrowserElement::BrowserShownObserver::RemoveObserver()
|
||||
{
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
if (obs) {
|
||||
obs->RemoveObserver(this, kRemoteBrowserPending);
|
||||
obs->RemoveObserver(this, kInprocessBrowserShown);
|
||||
}
|
||||
mBrowserElement = nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
nsBrowserElement::IsBrowserElementOrThrow(ErrorResult& aRv)
|
||||
{
|
||||
|
|
@ -145,18 +66,6 @@ nsBrowserElement::InitBrowserElementAPI()
|
|||
}
|
||||
}
|
||||
|
||||
nsBrowserElement::nsBrowserElement()
|
||||
: mOwnerIsWidget(false)
|
||||
{
|
||||
mObserver = new BrowserShownObserver(this);
|
||||
mObserver->AddObserver();
|
||||
}
|
||||
|
||||
nsBrowserElement::~nsBrowserElement()
|
||||
{
|
||||
mObserver->RemoveObserver();
|
||||
}
|
||||
|
||||
void
|
||||
nsBrowserElement::SetVisible(bool aVisible, ErrorResult& aRv)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@
|
|||
#include "nsIBrowserElementAPI.h"
|
||||
|
||||
class nsFrameLoader;
|
||||
class nsIObserver;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
|
@ -31,8 +30,8 @@ class ErrorResult;
|
|||
class nsBrowserElement
|
||||
{
|
||||
public:
|
||||
nsBrowserElement();
|
||||
virtual ~nsBrowserElement();
|
||||
nsBrowserElement() : mOwnerIsWidget(false) {}
|
||||
virtual ~nsBrowserElement() {}
|
||||
|
||||
void SetVisible(bool aVisible, ErrorResult& aRv);
|
||||
already_AddRefed<dom::DOMRequest> GetVisible(ErrorResult& aRv);
|
||||
|
|
@ -94,17 +93,13 @@ public:
|
|||
|
||||
protected:
|
||||
NS_IMETHOD_(already_AddRefed<nsFrameLoader>) GetFrameLoader() = 0;
|
||||
void InitBrowserElementAPI();
|
||||
nsCOMPtr<nsIBrowserElementAPI> mBrowserElementAPI;
|
||||
|
||||
private:
|
||||
void InitBrowserElementAPI();
|
||||
bool IsBrowserElementOrThrow(ErrorResult& aRv);
|
||||
bool IsNotWidgetOrThrow(ErrorResult& aRv);
|
||||
bool mOwnerIsWidget;
|
||||
|
||||
class BrowserShownObserver;
|
||||
friend class BrowserShownObserver;
|
||||
nsRefPtr<BrowserShownObserver> mObserver;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
|||
|
|
@ -499,3 +499,11 @@ nsGenericHTMLFrameElement::AllowCreateFrameLoader()
|
|||
mFrameLoaderCreationDisallowed = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsGenericHTMLFrameElement::InitializeBrowserAPI()
|
||||
{
|
||||
MOZ_ASSERT(mFrameLoader);
|
||||
InitBrowserElementAPI();
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -85,4 +85,10 @@ interface nsIMozBrowserFrame : nsIDOMMozBrowserFrame
|
|||
* It is an error to call this method if we already have a frame loader.
|
||||
*/
|
||||
void createRemoteFrameLoader(in nsITabParent aTabParent);
|
||||
|
||||
/**
|
||||
* Initialize the API, and add frame message listener to listen to API
|
||||
* invocations.
|
||||
*/
|
||||
[noscript] void initializeBrowserAPI();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -471,6 +471,13 @@ already_AddRefed<ParticularProcessPriorityManager>
|
|||
ProcessPriorityManagerImpl::GetParticularProcessPriorityManager(
|
||||
ContentParent* aContentParent)
|
||||
{
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
// Do not attempt to change the priority of the Nuwa process
|
||||
if (aContentParent->IsNuwaProcess()) {
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
nsRefPtr<ParticularProcessPriorityManager> pppm;
|
||||
uint64_t cpId = aContentParent->ChildID();
|
||||
mParticularManagers.Get(cpId, &pppm);
|
||||
|
|
@ -494,7 +501,9 @@ ProcessPriorityManagerImpl::SetProcessPriority(ContentParent* aContentParent,
|
|||
MOZ_ASSERT(aContentParent);
|
||||
nsRefPtr<ParticularProcessPriorityManager> pppm =
|
||||
GetParticularProcessPriorityManager(aContentParent);
|
||||
pppm->SetPriorityNow(aPriority, aBackgroundLRU);
|
||||
if (pppm) {
|
||||
pppm->SetPriorityNow(aPriority, aBackgroundLRU);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -532,18 +541,17 @@ ProcessPriorityManagerImpl::ObserveContentParentDestroyed(nsISupports* aSubject)
|
|||
|
||||
nsRefPtr<ParticularProcessPriorityManager> pppm;
|
||||
mParticularManagers.Get(childID, &pppm);
|
||||
MOZ_ASSERT(pppm);
|
||||
if (pppm) {
|
||||
pppm->ShutDown();
|
||||
}
|
||||
|
||||
mParticularManagers.Remove(childID);
|
||||
mParticularManagers.Remove(childID);
|
||||
|
||||
if (mHighPriorityChildIDs.Contains(childID)) {
|
||||
mHighPriorityChildIDs.RemoveEntry(childID);
|
||||
if (mHighPriorityChildIDs.Contains(childID)) {
|
||||
mHighPriorityChildIDs.RemoveEntry(childID);
|
||||
|
||||
// We just lost a high-priority process; reset everyone's CPU priorities.
|
||||
ResetAllCPUPriorities();
|
||||
// We just lost a high-priority process; reset everyone's CPU priorities.
|
||||
ResetAllCPUPriorities();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -806,13 +814,6 @@ ParticularProcessPriorityManager::OnRemoteBrowserFrameShown(nsISupports* aSubjec
|
|||
nsCOMPtr<nsIFrameLoader> fl = do_QueryInterface(aSubject);
|
||||
NS_ENSURE_TRUE_VOID(fl);
|
||||
|
||||
// Ignore notifications that aren't from a BrowserOrApp
|
||||
bool isBrowserOrApp;
|
||||
fl->GetOwnerIsBrowserOrAppFrame(&isBrowserOrApp);
|
||||
if (!isBrowserOrApp) {
|
||||
return;
|
||||
}
|
||||
|
||||
TabParent* tp = TabParent::GetFrom(fl);
|
||||
NS_ENSURE_TRUE_VOID(tp);
|
||||
|
||||
|
|
@ -821,7 +822,17 @@ ParticularProcessPriorityManager::OnRemoteBrowserFrameShown(nsISupports* aSubjec
|
|||
return;
|
||||
}
|
||||
|
||||
ResetPriority();
|
||||
// Ignore notifications that aren't from a BrowserOrApp
|
||||
bool isBrowserOrApp;
|
||||
fl->GetOwnerIsBrowserOrAppFrame(&isBrowserOrApp);
|
||||
if (isBrowserOrApp) {
|
||||
ResetPriority();
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
|
||||
if (os) {
|
||||
os->RemoveObserver(this, "remote-browser-shown");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -1039,13 +1050,6 @@ ParticularProcessPriorityManager::SetPriorityNow(ProcessPriority aPriority,
|
|||
ProcessCPUPriority aCPUPriority,
|
||||
uint32_t aBackgroundLRU)
|
||||
{
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
// Do not attempt to change the priority of the Nuwa process
|
||||
if (mContentParent->IsNuwaProcess()) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (aPriority == PROCESS_PRIORITY_UNKNOWN) {
|
||||
MOZ_ASSERT(false);
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -647,11 +647,22 @@ TabParent::RecvCreateWindow(PBrowserParent* aNewTab,
|
|||
nsCOMPtr<nsPIDOMWindow> pwindow = do_QueryInterface(window);
|
||||
NS_ENSURE_TRUE(pwindow, false);
|
||||
|
||||
nsRefPtr<nsIDocShell> newDocShell = pwindow->GetDocShell();
|
||||
NS_ENSURE_TRUE(newDocShell, false);
|
||||
nsCOMPtr<nsIDocShell> windowDocShell = pwindow->GetDocShell();
|
||||
NS_ENSURE_TRUE(windowDocShell, false);
|
||||
|
||||
nsCOMPtr<nsITabParent> newRemoteTab = newDocShell->GetOpenedRemote();
|
||||
NS_ENSURE_TRUE(newRemoteTab, false);
|
||||
nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
|
||||
windowDocShell->GetTreeOwner(getter_AddRefs(treeOwner));
|
||||
|
||||
nsCOMPtr<nsIXULWindow> xulWin = do_GetInterface(treeOwner);
|
||||
NS_ENSURE_TRUE(xulWin, false);
|
||||
|
||||
nsCOMPtr<nsIXULBrowserWindow> xulBrowserWin;
|
||||
xulWin->GetXULBrowserWindow(getter_AddRefs(xulBrowserWin));
|
||||
NS_ENSURE_TRUE(xulBrowserWin, false);
|
||||
|
||||
nsCOMPtr<nsITabParent> newRemoteTab;
|
||||
rv = xulBrowserWin->ForceInitialBrowserRemote(getter_AddRefs(newRemoteTab));
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
MOZ_ASSERT(TabParent::GetFrom(newRemoteTab) == newTab);
|
||||
|
||||
|
|
|
|||
|
|
@ -314,8 +314,7 @@ MediaDecoderReader::Shutdown()
|
|||
} else {
|
||||
// If we don't own our task queue, we resolve immediately (though
|
||||
// asynchronously).
|
||||
p = new ShutdownPromise(__func__);
|
||||
p->Resolve(true, __func__);
|
||||
p = ShutdownPromise::CreateAndResolve(true, __func__);
|
||||
}
|
||||
|
||||
return p;
|
||||
|
|
|
|||
|
|
@ -62,6 +62,10 @@ public:
|
|||
typedef RejectValueT RejectValueType;
|
||||
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaPromise)
|
||||
|
||||
protected:
|
||||
// MediaPromise is the public type, and never constructed directly. Construct
|
||||
// a MediaPromise::Private, defined below.
|
||||
explicit MediaPromise(const char* aCreationSite)
|
||||
: mCreationSite(aCreationSite)
|
||||
, mMutex("MediaPromise Mutex")
|
||||
|
|
@ -70,20 +74,30 @@ public:
|
|||
PROMISE_LOG("%s creating MediaPromise (%p)", mCreationSite, this);
|
||||
}
|
||||
|
||||
public:
|
||||
// MediaPromise::Private allows us to separate the public interface (upon which
|
||||
// consumers of the promise may invoke methods like Then()) from the private
|
||||
// interface (upon which the creator of the promise may invoke Resolve() or
|
||||
// Reject()). APIs should create and store a MediaPromise::Private (usually
|
||||
// via a MediaPromiseHolder), and return a MediaPromise to consumers.
|
||||
//
|
||||
// NB: We can include the definition of this class inline once B2G ICS is gone.
|
||||
class Private;
|
||||
|
||||
static nsRefPtr<MediaPromise>
|
||||
CreateAndResolve(ResolveValueType aResolveValue, const char* aResolveSite)
|
||||
{
|
||||
nsRefPtr<MediaPromise> p = new MediaPromise(aResolveSite);
|
||||
nsRefPtr<typename MediaPromise::Private> p = new MediaPromise::Private(aResolveSite);
|
||||
p->Resolve(aResolveValue, aResolveSite);
|
||||
return p;
|
||||
return Move(p);
|
||||
}
|
||||
|
||||
static nsRefPtr<MediaPromise>
|
||||
CreateAndReject(RejectValueType aRejectValue, const char* aRejectSite)
|
||||
{
|
||||
nsRefPtr<MediaPromise> p = new MediaPromise(aRejectSite);
|
||||
nsRefPtr<typename MediaPromise::Private> p = new MediaPromise::Private(aRejectSite);
|
||||
p->Reject(aRejectValue, aRejectSite);
|
||||
return p;
|
||||
return Move(p);
|
||||
}
|
||||
|
||||
class Consumer
|
||||
|
|
@ -328,12 +342,12 @@ public:
|
|||
return;
|
||||
}
|
||||
|
||||
void ChainTo(already_AddRefed<MediaPromise> aChainedPromise, const char* aCallSite)
|
||||
void ChainTo(already_AddRefed<Private> aChainedPromise, const char* aCallSite)
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
MOZ_DIAGNOSTIC_ASSERT(!IsExclusive || !mHaveConsumer);
|
||||
mHaveConsumer = true;
|
||||
nsRefPtr<MediaPromise> chainedPromise = aChainedPromise;
|
||||
nsRefPtr<Private> chainedPromise = aChainedPromise;
|
||||
PROMISE_LOG("%s invoking Chain() [this=%p, chainedPromise=%p, isPending=%d]",
|
||||
aCallSite, this, chainedPromise.get(), (int) IsPending());
|
||||
if (!IsPending()) {
|
||||
|
|
@ -343,24 +357,6 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void Resolve(ResolveValueType aResolveValue, const char* aResolveSite)
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
MOZ_ASSERT(IsPending());
|
||||
PROMISE_LOG("%s resolving MediaPromise (%p created at %s)", aResolveSite, this, mCreationSite);
|
||||
mResolveValue.emplace(aResolveValue);
|
||||
DispatchAll();
|
||||
}
|
||||
|
||||
void Reject(RejectValueType aRejectValue, const char* aRejectSite)
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
MOZ_ASSERT(IsPending());
|
||||
PROMISE_LOG("%s rejecting MediaPromise (%p created at %s)", aRejectSite, this, mCreationSite);
|
||||
mRejectValue.emplace(aRejectValue);
|
||||
DispatchAll();
|
||||
}
|
||||
|
||||
protected:
|
||||
bool IsPending() { return mResolveValue.isNothing() && mRejectValue.isNothing(); }
|
||||
void DispatchAll()
|
||||
|
|
@ -377,7 +373,7 @@ protected:
|
|||
mChainedPromises.Clear();
|
||||
}
|
||||
|
||||
void ForwardTo(MediaPromise* aOther)
|
||||
void ForwardTo(Private* aOther)
|
||||
{
|
||||
MOZ_ASSERT(!IsPending());
|
||||
if (mResolveValue.isSome()) {
|
||||
|
|
@ -400,10 +396,36 @@ protected:
|
|||
Maybe<ResolveValueType> mResolveValue;
|
||||
Maybe<RejectValueType> mRejectValue;
|
||||
nsTArray<nsRefPtr<ThenValueBase>> mThenValues;
|
||||
nsTArray<nsRefPtr<MediaPromise>> mChainedPromises;
|
||||
nsTArray<nsRefPtr<Private>> mChainedPromises;
|
||||
bool mHaveConsumer;
|
||||
};
|
||||
|
||||
template<typename ResolveValueT, typename RejectValueT, bool IsExclusive>
|
||||
class MediaPromise<ResolveValueT, RejectValueT, IsExclusive>::Private
|
||||
: public MediaPromise<ResolveValueT, RejectValueT, IsExclusive>
|
||||
{
|
||||
public:
|
||||
explicit Private(const char* aCreationSite) : MediaPromise(aCreationSite) {}
|
||||
|
||||
void Resolve(ResolveValueT aResolveValue, const char* aResolveSite)
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
MOZ_ASSERT(IsPending());
|
||||
PROMISE_LOG("%s resolving MediaPromise (%p created at %s)", aResolveSite, this, mCreationSite);
|
||||
mResolveValue.emplace(aResolveValue);
|
||||
DispatchAll();
|
||||
}
|
||||
|
||||
void Reject(RejectValueT aRejectValue, const char* aRejectSite)
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
MOZ_ASSERT(IsPending());
|
||||
PROMISE_LOG("%s rejecting MediaPromise (%p created at %s)", aRejectSite, this, mCreationSite);
|
||||
mRejectValue.emplace(aRejectValue);
|
||||
DispatchAll();
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Class to encapsulate a promise for a particular role. Use this as the member
|
||||
* variable for a class whose method returns a promise.
|
||||
|
|
@ -422,9 +444,9 @@ public:
|
|||
mMonitor->AssertCurrentThreadOwns();
|
||||
}
|
||||
if (!mPromise) {
|
||||
mPromise = new PromiseType(aMethodName);
|
||||
mPromise = new (typename PromiseType::Private)(aMethodName);
|
||||
}
|
||||
nsRefPtr<PromiseType> p = mPromise;
|
||||
nsRefPtr<PromiseType> p = mPromise.get();
|
||||
return p.forget();
|
||||
}
|
||||
|
||||
|
|
@ -439,13 +461,13 @@ public:
|
|||
return !mPromise;
|
||||
}
|
||||
|
||||
already_AddRefed<PromiseType> Steal()
|
||||
already_AddRefed<typename PromiseType::Private> Steal()
|
||||
{
|
||||
if (mMonitor) {
|
||||
mMonitor->AssertCurrentThreadOwns();
|
||||
}
|
||||
|
||||
nsRefPtr<PromiseType> p = mPromise;
|
||||
nsRefPtr<typename PromiseType::Private> p = mPromise;
|
||||
mPromise = nullptr;
|
||||
return p.forget();
|
||||
}
|
||||
|
|
@ -490,7 +512,7 @@ public:
|
|||
|
||||
private:
|
||||
Monitor* mMonitor;
|
||||
nsRefPtr<PromiseType> mPromise;
|
||||
nsRefPtr<typename PromiseType::Private> mPromise;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -590,7 +612,7 @@ template<typename PromiseType>
|
|||
class ProxyRunnable : public nsRunnable
|
||||
{
|
||||
public:
|
||||
ProxyRunnable(PromiseType* aProxyPromise, MethodCallBase<PromiseType>* aMethodCall)
|
||||
ProxyRunnable(typename PromiseType::Private* aProxyPromise, MethodCallBase<PromiseType>* aMethodCall)
|
||||
: mProxyPromise(aProxyPromise), mMethodCall(aMethodCall) {}
|
||||
|
||||
NS_IMETHODIMP Run()
|
||||
|
|
@ -602,7 +624,7 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<PromiseType> mProxyPromise;
|
||||
nsRefPtr<typename PromiseType::Private> mProxyPromise;
|
||||
nsAutoPtr<MethodCallBase<PromiseType>> mMethodCall;
|
||||
};
|
||||
|
||||
|
|
@ -610,11 +632,11 @@ template<typename PromiseType, typename TargetType>
|
|||
static nsRefPtr<PromiseType>
|
||||
ProxyInternal(TargetType* aTarget, MethodCallBase<PromiseType>* aMethodCall, const char* aCallerName)
|
||||
{
|
||||
nsRefPtr<PromiseType> p = new PromiseType(aCallerName);
|
||||
nsRefPtr<typename PromiseType::Private> p = new (typename PromiseType::Private)(aCallerName);
|
||||
nsRefPtr<ProxyRunnable<PromiseType>> r = new ProxyRunnable<PromiseType>(p, aMethodCall);
|
||||
nsresult rv = detail::DispatchMediaPromiseRunnable(aTarget, r);
|
||||
MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
|
||||
return p;
|
||||
return Move(p);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
|
|
|||
|
|
@ -82,6 +82,7 @@ CloseSessions(const nsAString& aKey,
|
|||
void* aClosure)
|
||||
{
|
||||
aSession->OnClosed();
|
||||
((MediaKeys*)aClosure)->Release();
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
|
|
@ -111,7 +112,9 @@ MediaKeys::Shutdown()
|
|||
mProxy = nullptr;
|
||||
}
|
||||
|
||||
mPromises.Enumerate(&RejectPromises, nullptr);
|
||||
nsRefPtr<MediaKeys> kungFuDeathGrip = this;
|
||||
|
||||
mPromises.Enumerate(&RejectPromises, this);
|
||||
mPromises.Clear();
|
||||
}
|
||||
|
||||
|
|
@ -169,6 +172,11 @@ MediaKeys::StorePromise(Promise* aPromise)
|
|||
static uint32_t sEMEPromiseCount = 1;
|
||||
MOZ_ASSERT(aPromise);
|
||||
uint32_t id = sEMEPromiseCount++;
|
||||
|
||||
// Keep MediaKeys alive for the lifetime of its promises. Any still-pending
|
||||
// promises are rejected in Shutdown().
|
||||
AddRef();
|
||||
|
||||
mPromises.Put(id, aPromise);
|
||||
return id;
|
||||
}
|
||||
|
|
@ -179,6 +187,7 @@ MediaKeys::RetrievePromise(PromiseId aId)
|
|||
MOZ_ASSERT(mPromises.Contains(aId));
|
||||
nsRefPtr<Promise> promise;
|
||||
mPromises.Remove(aId, getter_AddRefs(promise));
|
||||
Release();
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -556,10 +556,7 @@ MP4Reader::RequestVideoData(bool aSkipToNextKeyframe,
|
|||
|
||||
if (mShutdown) {
|
||||
NS_WARNING("RequestVideoData on shutdown MP4Reader!");
|
||||
MonitorAutoLock lock(mVideo.mMonitor);
|
||||
nsRefPtr<VideoDataPromise> p = mVideo.mPromise.Ensure(__func__);
|
||||
p->Reject(CANCELED, __func__);
|
||||
return p;
|
||||
return VideoDataPromise::CreateAndReject(CANCELED, __func__);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(HasVideo() && mPlatform && mVideo.mDecoder);
|
||||
|
|
@ -590,14 +587,14 @@ MP4Reader::RequestAudioData()
|
|||
{
|
||||
MOZ_ASSERT(GetTaskQueue()->IsCurrentThreadIn());
|
||||
VLOG("RequestAudioData");
|
||||
if (mShutdown) {
|
||||
NS_WARNING("RequestAudioData on shutdown MP4Reader!");
|
||||
return AudioDataPromise::CreateAndReject(CANCELED, __func__);
|
||||
}
|
||||
|
||||
MonitorAutoLock lock(mAudio.mMonitor);
|
||||
nsRefPtr<AudioDataPromise> p = mAudio.mPromise.Ensure(__func__);
|
||||
if (!mShutdown) {
|
||||
ScheduleUpdate(kAudio);
|
||||
} else {
|
||||
NS_WARNING("RequestAudioData on shutdown MP4Reader!");
|
||||
p->Reject(CANCELED, __func__);
|
||||
}
|
||||
ScheduleUpdate(kAudio);
|
||||
return p;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -271,17 +271,20 @@ public:
|
|||
explicit OpenedSecondTimeContinuation(GMPRecord* aRecord,
|
||||
TestManager* aTestManager,
|
||||
const string& aTestID)
|
||||
: mRecord(aRecord), mTestmanager(aTestManager), mTestID(aTestID) {}
|
||||
: mRecord(aRecord), mTestmanager(aTestManager), mTestID(aTestID) {
|
||||
MOZ_ASSERT(aRecord);
|
||||
}
|
||||
|
||||
virtual void OpenComplete(GMPErr aStatus, GMPRecord* aRecord) MOZ_OVERRIDE {
|
||||
if (GMP_SUCCEEDED(aStatus)) {
|
||||
FakeDecryptor::Message("FAIL OpenSecondTimeContinuation should not be able to re-open record.");
|
||||
}
|
||||
|
||||
if (aRecord) {
|
||||
aRecord->Close();
|
||||
}
|
||||
// Succeeded, open should have failed.
|
||||
mTestmanager->EndTest(mTestID);
|
||||
mRecord->Close();
|
||||
delete this;
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
@ -301,12 +304,14 @@ public:
|
|||
if (GMP_FAILED(aStatus)) {
|
||||
FakeDecryptor::Message("FAIL OpenAgainContinuation to open record initially.");
|
||||
mTestmanager->EndTest(mTestID);
|
||||
if (aRecord) {
|
||||
aRecord->Close();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
auto cont = new OpenedSecondTimeContinuation(aRecord, mTestmanager, mTestID);
|
||||
GMPOpenRecord(mID, cont);
|
||||
delete this;
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -171,44 +171,58 @@ GMPRunOnMainThread(GMPTask* aTask)
|
|||
|
||||
class OpenRecordClient : public GMPRecordClient {
|
||||
public:
|
||||
GMPErr Init(GMPRecord* aRecord,
|
||||
OpenContinuation* aContinuation) {
|
||||
mRecord = aRecord;
|
||||
mContinuation = aContinuation;
|
||||
return mRecord->Open();
|
||||
/*
|
||||
* This function will take the memory ownership of the parameters and
|
||||
* delete them when done.
|
||||
*/
|
||||
static void Open(const std::string& aRecordName,
|
||||
OpenContinuation* aContinuation) {
|
||||
MOZ_ASSERT(aContinuation);
|
||||
(new OpenRecordClient(aContinuation))->Do(aRecordName);
|
||||
}
|
||||
|
||||
virtual void OpenComplete(GMPErr aStatus) MOZ_OVERRIDE {
|
||||
mContinuation->OpenComplete(aStatus, mRecord);
|
||||
delete this;
|
||||
Done(aStatus);
|
||||
}
|
||||
|
||||
virtual void ReadComplete(GMPErr aStatus,
|
||||
const uint8_t* aData,
|
||||
uint32_t aDataSize) MOZ_OVERRIDE { }
|
||||
uint32_t aDataSize) MOZ_OVERRIDE {
|
||||
MOZ_CRASH("Should not reach here.");
|
||||
}
|
||||
|
||||
virtual void WriteComplete(GMPErr aStatus) MOZ_OVERRIDE { }
|
||||
virtual void WriteComplete(GMPErr aStatus) MOZ_OVERRIDE {
|
||||
MOZ_CRASH("Should not reach here.");
|
||||
}
|
||||
|
||||
private:
|
||||
explicit OpenRecordClient(OpenContinuation* aContinuation)
|
||||
: mRecord(nullptr), mContinuation(aContinuation) {}
|
||||
|
||||
void Do(const std::string& aName) {
|
||||
auto err = GMPOpenRecord(aName.c_str(), aName.size(), &mRecord, this);
|
||||
if (GMP_FAILED(err) ||
|
||||
GMP_FAILED(err = mRecord->Open())) {
|
||||
Done(err);
|
||||
}
|
||||
}
|
||||
|
||||
void Done(GMPErr err) {
|
||||
// mContinuation is responsible for closing mRecord.
|
||||
mContinuation->OpenComplete(err, mRecord);
|
||||
delete mContinuation;
|
||||
delete this;
|
||||
}
|
||||
|
||||
GMPRecord* mRecord;
|
||||
OpenContinuation* mContinuation;
|
||||
};
|
||||
|
||||
GMPErr
|
||||
void
|
||||
GMPOpenRecord(const std::string& aRecordName,
|
||||
OpenContinuation* aContinuation)
|
||||
{
|
||||
MOZ_ASSERT(aContinuation);
|
||||
GMPRecord* record;
|
||||
OpenRecordClient* client = new OpenRecordClient();
|
||||
auto err = GMPOpenRecord(aRecordName.c_str(),
|
||||
aRecordName.size(),
|
||||
&record,
|
||||
client);
|
||||
if (GMP_FAILED(err)) {
|
||||
return err;
|
||||
}
|
||||
return client->Init(record, aContinuation);
|
||||
OpenRecordClient::Open(aRecordName, aContinuation);
|
||||
}
|
||||
|
||||
GMPErr
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ public:
|
|||
virtual void OpenComplete(GMPErr aStatus, GMPRecord* aRecord) = 0;
|
||||
};
|
||||
|
||||
GMPErr
|
||||
void
|
||||
GMPOpenRecord(const std::string& aRecordName,
|
||||
OpenContinuation* aContinuation);
|
||||
|
||||
|
|
|
|||
|
|
@ -269,11 +269,9 @@ GMPDecryptorParent::RecvKeyStatusChanged(const nsCString& aSessionId,
|
|||
InfallibleTArray<uint8_t>&& aKeyId,
|
||||
const GMPMediaKeyStatus& aStatus)
|
||||
{
|
||||
if (!mIsOpen) {
|
||||
NS_WARNING("Trying to use a dead GMP decrypter!");
|
||||
return false;
|
||||
if (mIsOpen) {
|
||||
mCallback->KeyStatusChanged(aSessionId, aKeyId, aStatus);
|
||||
}
|
||||
mCallback->KeyStatusChanged(aSessionId, aKeyId, aStatus);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -109,6 +109,11 @@ GMPStorageChild::CreateRecord(const nsCString& aRecordName,
|
|||
}
|
||||
|
||||
MOZ_ASSERT(aRecordName.Length() && aOutRecord);
|
||||
|
||||
if (HasRecord(aRecordName)) {
|
||||
return GMPRecordInUse;
|
||||
}
|
||||
|
||||
nsRefPtr<GMPRecordImpl> record(new GMPRecordImpl(this, aRecordName, aClient));
|
||||
mRecords.Put(aRecordName, record); // Addrefs
|
||||
|
||||
|
|
|
|||
|
|
@ -190,7 +190,7 @@ TrackBuffer::AppendData(LargeDataBuffer* aData, int64_t aTimestampOffset)
|
|||
if (!gotInit) {
|
||||
// We need a new decoder, but we can't initialize it yet.
|
||||
nsRefPtr<SourceBufferDecoder> decoder =
|
||||
NewDecoder(aTimestampOffset - mAdjustedTimestamp);
|
||||
NewDecoder(aTimestampOffset);
|
||||
// The new decoder is stored in mDecoders/mCurrentDecoder, so we
|
||||
// don't need to do anything with 'decoder'. It's only a placeholder.
|
||||
if (!decoder) {
|
||||
|
|
@ -198,7 +198,7 @@ TrackBuffer::AppendData(LargeDataBuffer* aData, int64_t aTimestampOffset)
|
|||
return p;
|
||||
}
|
||||
} else {
|
||||
if (!decoders.NewDecoder(aTimestampOffset - mAdjustedTimestamp)) {
|
||||
if (!decoders.NewDecoder(aTimestampOffset)) {
|
||||
mInitializationPromise.Reject(NS_ERROR_FAILURE, __func__);
|
||||
return p;
|
||||
}
|
||||
|
|
@ -211,7 +211,7 @@ TrackBuffer::AppendData(LargeDataBuffer* aData, int64_t aTimestampOffset)
|
|||
}
|
||||
|
||||
if (gotMedia) {
|
||||
if (mLastEndTimestamp &&
|
||||
if (mParser->IsMediaSegmentPresent(aData) && mLastEndTimestamp &&
|
||||
(!mParser->TimestampsFuzzyEqual(start, mLastEndTimestamp.value()) ||
|
||||
mLastTimestampOffset != aTimestampOffset ||
|
||||
mDecoderPerSegment ||
|
||||
|
|
@ -224,7 +224,7 @@ TrackBuffer::AppendData(LargeDataBuffer* aData, int64_t aTimestampOffset)
|
|||
// processed or not continuous, so we must create a new decoder
|
||||
// to handle the decoding.
|
||||
if (!hadCompleteInitData ||
|
||||
!decoders.NewDecoder(aTimestampOffset - mAdjustedTimestamp)) {
|
||||
!decoders.NewDecoder(aTimestampOffset)) {
|
||||
mInitializationPromise.Reject(NS_ERROR_FAILURE, __func__);
|
||||
return p;
|
||||
}
|
||||
|
|
@ -240,8 +240,9 @@ TrackBuffer::AppendData(LargeDataBuffer* aData, int64_t aTimestampOffset)
|
|||
mLastEndTimestamp.emplace(end);
|
||||
}
|
||||
|
||||
if (gotMedia && start > 0 &&
|
||||
(start < FUZZ_TIMESTAMP_OFFSET || start < mAdjustedTimestamp)) {
|
||||
if (gotMedia && start != mAdjustedTimestamp &&
|
||||
((start < 0 && -start < FUZZ_TIMESTAMP_OFFSET && start < mAdjustedTimestamp) ||
|
||||
(start > 0 && (start < FUZZ_TIMESTAMP_OFFSET || start < mAdjustedTimestamp)))) {
|
||||
AdjustDecodersTimestampOffset(mAdjustedTimestamp - start);
|
||||
mAdjustedTimestamp = start;
|
||||
}
|
||||
|
|
@ -255,11 +256,12 @@ TrackBuffer::AppendData(LargeDataBuffer* aData, int64_t aTimestampOffset)
|
|||
// We're going to have to wait for the decoder to initialize, the promise
|
||||
// will be resolved once initialization completes.
|
||||
return p;
|
||||
} else if (gotMedia) {
|
||||
// Tell our reader that we have more data to ensure that playback starts if
|
||||
// required when data is appended.
|
||||
mParentDecoder->GetReader()->MaybeNotifyHaveData();
|
||||
}
|
||||
|
||||
// Tell our reader that we have more data to ensure that playback starts if
|
||||
// required when data is appended.
|
||||
mParentDecoder->GetReader()->MaybeNotifyHaveData();
|
||||
|
||||
mInitializationPromise.Resolve(gotMedia, __func__);
|
||||
return p;
|
||||
}
|
||||
|
|
@ -455,7 +457,8 @@ TrackBuffer::NewDecoder(int64_t aTimestampOffset)
|
|||
|
||||
DiscardCurrentDecoder();
|
||||
|
||||
nsRefPtr<SourceBufferDecoder> decoder = mParentDecoder->CreateSubDecoder(mType, aTimestampOffset);
|
||||
nsRefPtr<SourceBufferDecoder> decoder =
|
||||
mParentDecoder->CreateSubDecoder(mType, aTimestampOffset - mAdjustedTimestamp);
|
||||
if (!decoder) {
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1872,7 +1872,7 @@ nsNPObjWrapper::GetNewOrUsed(NPP npp, JSContext *cx, NPObject *npobj)
|
|||
}
|
||||
|
||||
NPObjWrapperHashEntry *entry = static_cast<NPObjWrapperHashEntry *>
|
||||
(PL_DHashTableAdd(&sNPObjWrappers, npobj, fallible));
|
||||
(PL_DHashTableAdd(&sNPObjWrappers, npobj));
|
||||
|
||||
if (!entry) {
|
||||
// Out of memory
|
||||
|
|
@ -2035,7 +2035,7 @@ LookupNPP(NPObject *npobj)
|
|||
}
|
||||
|
||||
NPObjWrapperHashEntry *entry = static_cast<NPObjWrapperHashEntry *>
|
||||
(PL_DHashTableAdd(&sNPObjWrappers, npobj, fallible));
|
||||
(PL_DHashTableAdd(&sNPObjWrappers, npobj));
|
||||
|
||||
if (!entry) {
|
||||
return nullptr;
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ support-files =
|
|||
[test_custom_element_clone_callbacks.html]
|
||||
[test_custom_element_clone_callbacks_extended.html]
|
||||
[test_custom_element_import_node_created_callback.html]
|
||||
[test_custom_element_in_shadow.html]
|
||||
[test_nested_content_element.html]
|
||||
[test_dest_insertion_points.html]
|
||||
[test_dest_insertion_points_shadow.html]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,132 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1087460
|
||||
-->
|
||||
<head>
|
||||
<title>Test for custom element callbacks in shadow DOM.</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1087460">Bug 1087460</a>
|
||||
<div id="container"></div>
|
||||
|
||||
<script>
|
||||
|
||||
// Test callback for custom element when used after registration.
|
||||
|
||||
var createdCallbackCount = 0;
|
||||
var attachedCallbackCount = 0;
|
||||
var detachedCallbackCount = 0;
|
||||
var attributeChangedCallbackCount = 0;
|
||||
|
||||
var p1 = Object.create(HTMLElement.prototype);
|
||||
|
||||
p1.createdCallback = function() {
|
||||
createdCallbackCount++;
|
||||
};
|
||||
|
||||
p1.attachedCallback = function() {
|
||||
attachedCallbackCount++;
|
||||
};
|
||||
|
||||
p1.detachedCallback = function() {
|
||||
detachedCallbackCount++;
|
||||
};
|
||||
|
||||
p1.attributeChangedCallback = function(name, oldValue, newValue) {
|
||||
attributeChangedCallbackCount++;
|
||||
};
|
||||
|
||||
document.registerElement("x-foo", { prototype: p1 });
|
||||
|
||||
var container = document.getElementById("container");
|
||||
var shadow = container.createShadowRoot();
|
||||
|
||||
is(createdCallbackCount, 0, "createdCallback should not be called more than once in this test.");
|
||||
var customElem = document.createElement("x-foo");
|
||||
is(createdCallbackCount, 1, "createdCallback should be called after creating custom element.");
|
||||
|
||||
is(attributeChangedCallbackCount, 0, "attributeChangedCallback should not be called after just creating an element.");
|
||||
customElem.setAttribute("data-foo", "bar");
|
||||
is(attributeChangedCallbackCount, 1, "attributeChangedCallback should be called after setting an attribute.");
|
||||
|
||||
is(attachedCallbackCount, 0, "attachedCallback should not be called on an element that is not in a document/composed document.");
|
||||
shadow.appendChild(customElem);
|
||||
is(attachedCallbackCount, 1, "attachedCallback should be called after attaching custom element to the composed document.");
|
||||
|
||||
is(detachedCallbackCount, 0, "detachedCallback should not be called without detaching custom element.");
|
||||
shadow.removeChild(customElem);
|
||||
is(detachedCallbackCount, 1, "detachedCallback should be called after detaching custom element from the composed document.");
|
||||
|
||||
// Test callback for custom element already in the composed doc when created.
|
||||
|
||||
createdCallbackCount = 0;
|
||||
attachedCallbackCount = 0;
|
||||
detachedCallbackCount = 0;
|
||||
attributeChangedCallbackCount = 0;
|
||||
|
||||
shadow.innerHTML = "<x-foo></x-foo>";
|
||||
is(createdCallbackCount, 1, "createdCallback should be called after creating a custom element.");
|
||||
is(attachedCallbackCount, 1, "attachedCallback should be called after creating an element in the composed document.");
|
||||
|
||||
shadow.innerHTML = "";
|
||||
is(detachedCallbackCount, 1, "detachedCallback should be called after detaching custom element from the composed document.");
|
||||
|
||||
// Test callback for custom element in shadow DOM when host attached/detached to/from document.
|
||||
|
||||
createdCallbackCount = 0;
|
||||
attachedCallbackCount = 0;
|
||||
detachedCallbackCount = 0;
|
||||
attributeChangedCallbackCount = 0;
|
||||
|
||||
var host = document.createElement("div");
|
||||
shadow = host.createShadowRoot();
|
||||
customElem = document.createElement("x-foo");
|
||||
|
||||
is(attachedCallbackCount, 0, "attachedCallback should not be called on newly created element.");
|
||||
shadow.appendChild(customElem);
|
||||
is(attachedCallbackCount, 0, "attachedCallback should not be called on attaching to a tree that is not in the composed document.");
|
||||
|
||||
is(attachedCallbackCount, 0, "detachedCallback should not be called.");
|
||||
shadow.removeChild(customElem);
|
||||
is(detachedCallbackCount, 0, "detachedCallback should not be called when detaching from a tree that is not in the composed document.");
|
||||
|
||||
shadow.appendChild(customElem);
|
||||
is(attachedCallbackCount, 0, "attachedCallback should still not be called after reattaching to a shadow tree that is not in the composed document.");
|
||||
|
||||
container.appendChild(host);
|
||||
is(attachedCallbackCount, 1, "attachedCallback should be called after host is inserted into document.");
|
||||
|
||||
container.removeChild(host);
|
||||
is(detachedCallbackCount, 1, "detachedCallback should be called after host is removed from document.");
|
||||
|
||||
// Test callback for custom element for upgraded element.
|
||||
|
||||
createdCallbackCount = 0;
|
||||
attachedCallbackCount = 0;
|
||||
detachedCallbackCount = 0;
|
||||
attributeChangedCallbackCount = 0;
|
||||
|
||||
shadow = container.shadowRoot;
|
||||
shadow.innerHTML = "<x-bar></x-bar>";
|
||||
|
||||
var p2 = Object.create(HTMLElement.prototype);
|
||||
|
||||
p2.createdCallback = function() {
|
||||
createdCallbackCount++;
|
||||
};
|
||||
|
||||
p2.attachedCallback = function() {
|
||||
attachedCallbackCount++;
|
||||
};
|
||||
|
||||
document.registerElement("x-bar", { prototype: p2 });
|
||||
is(createdCallbackCount, 1, "createdCallback should be called after registering element.");
|
||||
is(attachedCallbackCount, 1, "attachedCallback should be called after upgrading element in composed document.");
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1996,7 +1996,7 @@ ServiceWorkerManager::CreateServiceWorker(const nsACString& aScriptSpec,
|
|||
}
|
||||
|
||||
nsRefPtr<ServiceWorker> serviceWorker;
|
||||
RuntimeService* rs = RuntimeService::GetService();
|
||||
RuntimeService* rs = RuntimeService::GetOrCreateService();
|
||||
if (!rs) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ var ecmaGlobals =
|
|||
"Int32Array",
|
||||
"Int8Array",
|
||||
"InternalError",
|
||||
{name: "Intl", desktop: true},
|
||||
{name: "Intl", b2g: false, android: false},
|
||||
"Iterator",
|
||||
"JSON",
|
||||
"Map",
|
||||
|
|
@ -167,11 +167,11 @@ var interfaceNamesInGlobalScope =
|
|||
];
|
||||
// IMPORTANT: Do not change the list above without review from a DOM peer!
|
||||
|
||||
function createInterfaceMap(prefMap, permissionMap, version, userAgent) {
|
||||
function createInterfaceMap(prefMap, permissionMap, version, userAgent, isB2G) {
|
||||
var isNightly = version.endsWith("a1");
|
||||
var isRelease = !version.contains("a");
|
||||
var isDesktop = !/Mobile|Tablet/.test(userAgent);
|
||||
var isB2G = !isDesktop && !userAgent.contains("Android");
|
||||
var isAndroid = !!navigator.userAgent.contains("Android");
|
||||
|
||||
var interfaceMap = {};
|
||||
|
||||
|
|
@ -182,6 +182,7 @@ function createInterfaceMap(prefMap, permissionMap, version, userAgent) {
|
|||
interfaceMap[entry] = true;
|
||||
} else if ((entry.nightly === !isNightly) ||
|
||||
(entry.desktop === !isDesktop) ||
|
||||
(entry.android === !isAndroid) ||
|
||||
(entry.b2g === !isB2G) ||
|
||||
(entry.release === !isRelease) ||
|
||||
(entry.pref && !prefMap[entry.pref]) ||
|
||||
|
|
@ -199,8 +200,8 @@ function createInterfaceMap(prefMap, permissionMap, version, userAgent) {
|
|||
return interfaceMap;
|
||||
}
|
||||
|
||||
function runTest(prefMap, permissionMap, version, userAgent) {
|
||||
var interfaceMap = createInterfaceMap(prefMap, permissionMap, version, userAgent);
|
||||
function runTest(prefMap, permissionMap, version, userAgent, isB2G) {
|
||||
var interfaceMap = createInterfaceMap(prefMap, permissionMap, version, userAgent, isB2G);
|
||||
for (var name of Object.getOwnPropertyNames(self)) {
|
||||
// An interface name should start with an upper case character.
|
||||
if (!/^[A-Z]/.test(name)) {
|
||||
|
|
@ -252,8 +253,10 @@ workerTestGetPrefs(prefs, function(prefMap) {
|
|||
workerTestGetPermissions(permissions, function(permissionMap) {
|
||||
workerTestGetVersion(function(version) {
|
||||
workerTestGetUserAgent(function(userAgent) {
|
||||
runTest(prefMap, permissionMap, version, userAgent);
|
||||
workerTestDone();
|
||||
workerTestGetIsB2G(function(isB2G) {
|
||||
runTest(prefMap, permissionMap, version, userAgent, isB2G);
|
||||
workerTestDone();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -76,6 +76,11 @@ function workerTestExec(script) {
|
|||
type: 'returnOSCPU',
|
||||
result: navigator.oscpu
|
||||
});
|
||||
} else if (event.data.type == 'getIsB2G') {
|
||||
worker.postMessage({
|
||||
type: 'returnIsB2G',
|
||||
result: SpecialPowers.isB2G
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -99,6 +99,19 @@ function workerTestGetOSCPU(cb) {
|
|||
});
|
||||
}
|
||||
|
||||
function workerTestGetIsB2G(cb) {
|
||||
addEventListener('message', function workerTestGetIsB2GCB(e) {
|
||||
if (e.data.type !== 'returnIsB2G') {
|
||||
return;
|
||||
}
|
||||
removeEventListener('message', workerTestGetIsB2GCB);
|
||||
cb(e.data.result);
|
||||
});
|
||||
postMessage({
|
||||
type: 'getIsB2G'
|
||||
});
|
||||
}
|
||||
|
||||
addEventListener('message', function workerWrapperOnMessage(e) {
|
||||
removeEventListener('message', workerWrapperOnMessage);
|
||||
var data = e.data;
|
||||
|
|
|
|||
|
|
@ -216,8 +216,7 @@ XULDocument::~XULDocument()
|
|||
|
||||
// Destroy our broadcaster map.
|
||||
if (mBroadcasterMap) {
|
||||
PL_DHashTableFinish(mBroadcasterMap);
|
||||
delete mBroadcasterMap;
|
||||
PL_DHashTableDestroy(mBroadcasterMap);
|
||||
}
|
||||
|
||||
delete mTemplateBuilderTable;
|
||||
|
|
@ -769,8 +768,12 @@ XULDocument::AddBroadcastListenerFor(Element& aBroadcaster, Element& aListener,
|
|||
};
|
||||
|
||||
if (! mBroadcasterMap) {
|
||||
mBroadcasterMap = new PLDHashTable();
|
||||
PL_DHashTableInit(mBroadcasterMap, &gOps, sizeof(BroadcasterMapEntry));
|
||||
mBroadcasterMap = PL_NewDHashTable(&gOps, sizeof(BroadcasterMapEntry));
|
||||
|
||||
if (! mBroadcasterMap) {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
BroadcasterMapEntry* entry =
|
||||
|
|
@ -778,8 +781,9 @@ XULDocument::AddBroadcastListenerFor(Element& aBroadcaster, Element& aListener,
|
|||
(PL_DHashTableSearch(mBroadcasterMap, &aBroadcaster));
|
||||
|
||||
if (!entry) {
|
||||
entry = static_cast<BroadcasterMapEntry*>
|
||||
(PL_DHashTableAdd(mBroadcasterMap, &aBroadcaster, fallible));
|
||||
entry =
|
||||
static_cast<BroadcasterMapEntry*>
|
||||
(PL_DHashTableAdd(mBroadcasterMap, &aBroadcaster));
|
||||
|
||||
if (! entry) {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@ public:
|
|||
if (!mMap.IsInitialized())
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
PLDHashEntryHdr* hdr =
|
||||
PL_DHashTableAdd(&mMap, aElement, mozilla::fallible);
|
||||
PLDHashEntryHdr* hdr = PL_DHashTableAdd(&mMap, aElement);
|
||||
if (!hdr)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
|
|
|
|||
|
|
@ -37,8 +37,7 @@ public:
|
|||
NS_ASSERTION(!PL_DHashTableSearch(&mTable, aContent),
|
||||
"aContent already in map");
|
||||
|
||||
Entry* entry = static_cast<Entry*>
|
||||
(PL_DHashTableAdd(&mTable, aContent, fallible));
|
||||
Entry* entry = static_cast<Entry*>(PL_DHashTableAdd(&mTable, aContent));
|
||||
|
||||
if (entry) {
|
||||
entry->mContent = aContent;
|
||||
|
|
|
|||
|
|
@ -230,8 +230,7 @@ nsCommandParams::GetOrMakeEntry(const char* aName, uint8_t entryType)
|
|||
return foundEntry;
|
||||
}
|
||||
|
||||
foundEntry = static_cast<HashEntry*>
|
||||
(PL_DHashTableAdd(&mValuesHash, (void *)aName, fallible));
|
||||
foundEntry = (HashEntry *)PL_DHashTableAdd(&mValuesHash, (void *)aName);
|
||||
if (!foundEntry) {
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
#include <stdint.h> // for uint16_t, uint32_t
|
||||
#include <sys/types.h> // for int32_t
|
||||
#include "gfxPlatform.h" // for GetTileWidth/GetTileHeight
|
||||
#include "mozilla/gfx/Logging.h" // for gfxCriticalError
|
||||
#include "nsDebug.h" // for NS_ASSERTION
|
||||
#include "nsPoint.h" // for nsIntPoint
|
||||
#include "nsRect.h" // for nsIntRect
|
||||
|
|
@ -340,7 +341,7 @@ TiledLayerBuffer<Derived, Tile>::Dump(std::stringstream& aStream,
|
|||
}
|
||||
|
||||
template<typename Derived, typename Tile> void
|
||||
TiledLayerBuffer<Derived, Tile>::Update(const nsIntRegion& aNewValidRegion,
|
||||
TiledLayerBuffer<Derived, Tile>::Update(const nsIntRegion& newValidRegion,
|
||||
const nsIntRegion& aPaintRegion)
|
||||
{
|
||||
gfx::IntSize scaledTileSize = GetScaledTileSize();
|
||||
|
|
@ -348,13 +349,15 @@ TiledLayerBuffer<Derived, Tile>::Update(const nsIntRegion& aNewValidRegion,
|
|||
nsTArray<Tile> newRetainedTiles;
|
||||
nsTArray<Tile>& oldRetainedTiles = mRetainedTiles;
|
||||
const nsIntRect oldBound = mValidRegion.GetBounds();
|
||||
const nsIntRect newBound = aNewValidRegion.GetBounds();
|
||||
const nsIntRect newBound = newValidRegion.GetBounds();
|
||||
const nsIntPoint oldBufferOrigin(RoundDownToTileEdge(oldBound.x, scaledTileSize.width),
|
||||
RoundDownToTileEdge(oldBound.y, scaledTileSize.height));
|
||||
const nsIntPoint newBufferOrigin(RoundDownToTileEdge(newBound.x, scaledTileSize.width),
|
||||
RoundDownToTileEdge(newBound.y, scaledTileSize.height));
|
||||
|
||||
// This is the reason we break the style guide with newValidRegion instead
|
||||
// of aNewValidRegion - so that the names match better and code easier to read
|
||||
const nsIntRegion& oldValidRegion = mValidRegion;
|
||||
const nsIntRegion& newValidRegion = aNewValidRegion;
|
||||
const int oldRetainedHeight = mRetainedHeight;
|
||||
|
||||
// Pass 1: Recycle valid content from the old buffer
|
||||
|
|
@ -446,12 +449,23 @@ TiledLayerBuffer<Derived, Tile>::Update(const nsIntRegion& aNewValidRegion,
|
|||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT(aNewValidRegion.Contains(aPaintRegion), "Painting a region outside the visible region");
|
||||
if (!newValidRegion.Contains(aPaintRegion)) {
|
||||
gfxCriticalError() << "Painting outside visible:"
|
||||
<< " paint " << aPaintRegion.ToString().get()
|
||||
<< " old valid " << oldValidRegion.ToString().get()
|
||||
<< " new valid " << newValidRegion.ToString().get();
|
||||
}
|
||||
#ifdef DEBUG
|
||||
nsIntRegion oldAndPainted(oldValidRegion);
|
||||
oldAndPainted.Or(oldAndPainted, aPaintRegion);
|
||||
if (!oldAndPainted.Contains(newValidRegion)) {
|
||||
gfxCriticalError() << "Not fully painted:"
|
||||
<< " paint " << aPaintRegion.ToString().get()
|
||||
<< " old valid " << oldValidRegion.ToString().get()
|
||||
<< " old painted " << oldAndPainted.ToString().get()
|
||||
<< " new valid " << newValidRegion.ToString().get();
|
||||
}
|
||||
#endif
|
||||
MOZ_ASSERT(oldAndPainted.Contains(newValidRegion), "newValidRegion has not been fully painted");
|
||||
|
||||
nsIntRegion regionToPaint(aPaintRegion);
|
||||
|
||||
|
|
@ -553,7 +567,7 @@ TiledLayerBuffer<Derived, Tile>::Update(const nsIntRegion& aNewValidRegion,
|
|||
// At this point, oldTileCount should be zero
|
||||
MOZ_ASSERT(oldTileCount == 0, "Failed to release old tiles");
|
||||
|
||||
mValidRegion = aNewValidRegion;
|
||||
mValidRegion = newValidRegion;
|
||||
mPaintedRegion.Or(mPaintedRegion, aPaintRegion);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -688,8 +688,9 @@ public:
|
|||
}
|
||||
uint32_t filesize = strtoul(beginning, nullptr, 10);
|
||||
|
||||
FNCMapEntry* mapEntry = static_cast<FNCMapEntry*>
|
||||
(PL_DHashTableAdd(&mMap, filename.get(), fallible));
|
||||
FNCMapEntry* mapEntry =
|
||||
static_cast<FNCMapEntry*>
|
||||
(PL_DHashTableAdd(&mMap, filename.get()));
|
||||
if (mapEntry) {
|
||||
mapEntry->mFilename.Assign(filename);
|
||||
mapEntry->mTimestamp = timestamp;
|
||||
|
|
@ -736,8 +737,9 @@ public:
|
|||
if (!mMap.IsInitialized()) {
|
||||
return;
|
||||
}
|
||||
FNCMapEntry* entry = static_cast<FNCMapEntry*>
|
||||
(PL_DHashTableAdd(&mMap, aFileName.get(), fallible));
|
||||
FNCMapEntry* entry =
|
||||
static_cast<FNCMapEntry*>
|
||||
(PL_DHashTableAdd(&mMap, aFileName.get()));
|
||||
if (entry) {
|
||||
entry->mFilename.Assign(aFileName);
|
||||
entry->mTimestamp = aTimestamp;
|
||||
|
|
|
|||
|
|
@ -1184,6 +1184,7 @@ RasterImage::NotifyForDecodeOnDrawOnly()
|
|||
nsCOMPtr<nsIRunnable> runnable =
|
||||
NS_NewRunnableMethod(this, &RasterImage::NotifyForDecodeOnDrawOnly);
|
||||
NS_DispatchToMainThread(runnable);
|
||||
return;
|
||||
}
|
||||
|
||||
NotifyProgress(FLAG_DECODE_STARTED | FLAG_ONLOAD_BLOCKED);
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
#include <algorithm>
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Attributes.h" // for MOZ_THIS_IN_INITIALIZER_LIST
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/Likely.h"
|
||||
#include "mozilla/Move.h"
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@
|
|||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "nsJSUtils.h"
|
||||
#include "jsfriendapi.h"
|
||||
#include "jsproxy.h"
|
||||
#include "jswrapper.h"
|
||||
#include "js/Proxy.h"
|
||||
#include "HeapAPI.h"
|
||||
#include "xpcprivate.h"
|
||||
#include "mozilla/Casting.h"
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
#include "mozilla/ipc/ProtocolUtils.h"
|
||||
#include "mozilla/jsipc/CrossProcessObjectWrappers.h"
|
||||
#include "js/Class.h"
|
||||
#include "jsproxy.h"
|
||||
#include "js/Proxy.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace jsipc {
|
||||
|
|
@ -28,7 +28,7 @@ class WrapperOwner : public virtual JavaScriptShared
|
|||
bool init();
|
||||
|
||||
// Standard internal methods.
|
||||
// (The traps should be in the same order like js/src/jsproxy.h)
|
||||
// (The traps should be in the same order like js/Proxy.h)
|
||||
bool getOwnPropertyDescriptor(JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
|
||||
JS::MutableHandle<JSPropertyDescriptor> desc);
|
||||
bool defineProperty(JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ namespace JS {
|
|||
D(FULL_STORE_BUFFER) \
|
||||
D(SHARED_MEMORY_LIMIT) \
|
||||
D(PERIODIC_FULL_GC) \
|
||||
D(INCREMENTAL_TOO_SLOW) \
|
||||
\
|
||||
/* These are reserved for future use. */ \
|
||||
D(RESERVED0) \
|
||||
|
|
@ -78,7 +79,6 @@ namespace JS {
|
|||
D(RESERVED14) \
|
||||
D(RESERVED15) \
|
||||
D(RESERVED16) \
|
||||
D(RESERVED17) \
|
||||
\
|
||||
/* Reasons from Firefox */ \
|
||||
D(DOM_WINDOW_UTILS) \
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef jsproxy_h
|
||||
#define jsproxy_h
|
||||
#ifndef js_Proxy_h
|
||||
#define js_Proxy_h
|
||||
|
||||
#include "mozilla/Maybe.h"
|
||||
|
||||
|
|
@ -679,4 +679,4 @@ inline void assertEnteredPolicy(JSContext *cx, JSObject *obj, jsid id,
|
|||
extern JS_FRIEND_API(JSObject *)
|
||||
js_InitProxyClass(JSContext *cx, JS::HandleObject obj);
|
||||
|
||||
#endif /* jsproxy_h */
|
||||
#endif /* js_Proxy_h */
|
||||
|
|
@ -180,346 +180,40 @@ static inline char* js_strdup(const char* s)
|
|||
* on another thread.
|
||||
*/
|
||||
|
||||
#define JS_NEW_BODY(allocator, t, parms) \
|
||||
void *memory = allocator(sizeof(t)); \
|
||||
return memory ? new(memory) t parms : nullptr;
|
||||
#define JS_MAKE_BODY(newname, T, parms) \
|
||||
T *ptr = newname<T> parms; \
|
||||
return mozilla::UniquePtr<T, JS::DeletePolicy<T>>(ptr);
|
||||
|
||||
/*
|
||||
* Given a class which should provide 'new' methods, add
|
||||
* JS_DECLARE_NEW_METHODS (see JSContext for a usage example). This
|
||||
* adds news with up to 12 parameters. Add more versions of new below if
|
||||
* you need more than 12 parameters.
|
||||
* Given a class which should provide a 'new' method, add
|
||||
* JS_DECLARE_NEW_METHODS (see js::MallocProvider for an example).
|
||||
*
|
||||
* Note: Do not add a ; at the end of a use of JS_DECLARE_NEW_METHODS,
|
||||
* or the build will break.
|
||||
*/
|
||||
#define JS_DECLARE_NEW_METHODS(NEWNAME, ALLOCATOR, QUALIFIERS)\
|
||||
template <class T>\
|
||||
QUALIFIERS T *NEWNAME() MOZ_HEAP_ALLOCATOR {\
|
||||
JS_NEW_BODY(ALLOCATOR, T, ())\
|
||||
}\
|
||||
\
|
||||
template <class T, class P1>\
|
||||
QUALIFIERS T *NEWNAME(P1 &&p1) MOZ_HEAP_ALLOCATOR {\
|
||||
JS_NEW_BODY(ALLOCATOR, T,\
|
||||
(mozilla::Forward<P1>(p1)))\
|
||||
}\
|
||||
\
|
||||
template <class T, class P1, class P2>\
|
||||
QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2) MOZ_HEAP_ALLOCATOR {\
|
||||
JS_NEW_BODY(ALLOCATOR, T,\
|
||||
(mozilla::Forward<P1>(p1),\
|
||||
mozilla::Forward<P2>(p2)))\
|
||||
}\
|
||||
\
|
||||
template <class T, class P1, class P2, class P3>\
|
||||
QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2, P3 &&p3) MOZ_HEAP_ALLOCATOR {\
|
||||
JS_NEW_BODY(ALLOCATOR, T,\
|
||||
(mozilla::Forward<P1>(p1),\
|
||||
mozilla::Forward<P2>(p2),\
|
||||
mozilla::Forward<P3>(p3)))\
|
||||
}\
|
||||
\
|
||||
template <class T, class P1, class P2, class P3, class P4>\
|
||||
QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4) MOZ_HEAP_ALLOCATOR {\
|
||||
JS_NEW_BODY(ALLOCATOR, T,\
|
||||
(mozilla::Forward<P1>(p1),\
|
||||
mozilla::Forward<P2>(p2),\
|
||||
mozilla::Forward<P3>(p3),\
|
||||
mozilla::Forward<P4>(p4)))\
|
||||
}\
|
||||
\
|
||||
template <class T, class P1, class P2, class P3, class P4, class P5>\
|
||||
QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5) MOZ_HEAP_ALLOCATOR {\
|
||||
JS_NEW_BODY(ALLOCATOR, T,\
|
||||
(mozilla::Forward<P1>(p1),\
|
||||
mozilla::Forward<P2>(p2),\
|
||||
mozilla::Forward<P3>(p3),\
|
||||
mozilla::Forward<P4>(p4),\
|
||||
mozilla::Forward<P5>(p5)))\
|
||||
}\
|
||||
\
|
||||
template <class T, class P1, class P2, class P3, class P4, class P5, class P6>\
|
||||
QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5, P6 &&p6) MOZ_HEAP_ALLOCATOR {\
|
||||
JS_NEW_BODY(ALLOCATOR, T,\
|
||||
(mozilla::Forward<P1>(p1),\
|
||||
mozilla::Forward<P2>(p2),\
|
||||
mozilla::Forward<P3>(p3),\
|
||||
mozilla::Forward<P4>(p4),\
|
||||
mozilla::Forward<P5>(p5),\
|
||||
mozilla::Forward<P6>(p6)))\
|
||||
}\
|
||||
\
|
||||
template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7>\
|
||||
QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5, P6 &&p6, P7 &&p7) MOZ_HEAP_ALLOCATOR {\
|
||||
JS_NEW_BODY(ALLOCATOR, T,\
|
||||
(mozilla::Forward<P1>(p1),\
|
||||
mozilla::Forward<P2>(p2),\
|
||||
mozilla::Forward<P3>(p3),\
|
||||
mozilla::Forward<P4>(p4),\
|
||||
mozilla::Forward<P5>(p5),\
|
||||
mozilla::Forward<P6>(p6),\
|
||||
mozilla::Forward<P7>(p7)))\
|
||||
}\
|
||||
\
|
||||
template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8>\
|
||||
QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5, P6 &&p6, P7 &&p7, P8 &&p8) MOZ_HEAP_ALLOCATOR {\
|
||||
JS_NEW_BODY(ALLOCATOR, T,\
|
||||
(mozilla::Forward<P1>(p1),\
|
||||
mozilla::Forward<P2>(p2),\
|
||||
mozilla::Forward<P3>(p3),\
|
||||
mozilla::Forward<P4>(p4),\
|
||||
mozilla::Forward<P5>(p5),\
|
||||
mozilla::Forward<P6>(p6),\
|
||||
mozilla::Forward<P7>(p7),\
|
||||
mozilla::Forward<P8>(p8)))\
|
||||
}\
|
||||
\
|
||||
template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9>\
|
||||
QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5, P6 &&p6, P7 &&p7, P8 &&p8, P9 &&p9) MOZ_HEAP_ALLOCATOR {\
|
||||
JS_NEW_BODY(ALLOCATOR, T,\
|
||||
(mozilla::Forward<P1>(p1),\
|
||||
mozilla::Forward<P2>(p2),\
|
||||
mozilla::Forward<P3>(p3),\
|
||||
mozilla::Forward<P4>(p4),\
|
||||
mozilla::Forward<P5>(p5),\
|
||||
mozilla::Forward<P6>(p6),\
|
||||
mozilla::Forward<P7>(p7),\
|
||||
mozilla::Forward<P8>(p8),\
|
||||
mozilla::Forward<P9>(p9)))\
|
||||
}\
|
||||
\
|
||||
template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9, class P10>\
|
||||
QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5, P6 &&p6, P7 &&p7, P8 &&p8, P9 &&p9, P10 &&p10) MOZ_HEAP_ALLOCATOR {\
|
||||
JS_NEW_BODY(ALLOCATOR, T,\
|
||||
(mozilla::Forward<P1>(p1),\
|
||||
mozilla::Forward<P2>(p2),\
|
||||
mozilla::Forward<P3>(p3),\
|
||||
mozilla::Forward<P4>(p4),\
|
||||
mozilla::Forward<P5>(p5),\
|
||||
mozilla::Forward<P6>(p6),\
|
||||
mozilla::Forward<P7>(p7),\
|
||||
mozilla::Forward<P8>(p8),\
|
||||
mozilla::Forward<P9>(p9),\
|
||||
mozilla::Forward<P10>(p10)))\
|
||||
}\
|
||||
\
|
||||
template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9, class P10, class P11>\
|
||||
QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5, P6 &&p6, P7 &&p7, P8 &&p8, P9 &&p9, P10 &&p10, P11 &&p11) MOZ_HEAP_ALLOCATOR {\
|
||||
JS_NEW_BODY(ALLOCATOR, T,\
|
||||
(mozilla::Forward<P1>(p1),\
|
||||
mozilla::Forward<P2>(p2),\
|
||||
mozilla::Forward<P3>(p3),\
|
||||
mozilla::Forward<P4>(p4),\
|
||||
mozilla::Forward<P5>(p5),\
|
||||
mozilla::Forward<P6>(p6),\
|
||||
mozilla::Forward<P7>(p7),\
|
||||
mozilla::Forward<P8>(p8),\
|
||||
mozilla::Forward<P9>(p9),\
|
||||
mozilla::Forward<P10>(p10),\
|
||||
mozilla::Forward<P11>(p11)))\
|
||||
}\
|
||||
\
|
||||
template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9, class P10, class P11, class P12>\
|
||||
QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5, P6 &&p6, P7 &&p7, P8 &&p8, P9 &&p9, P10 &&p10, P11 &&p11, P12 &&p12) MOZ_HEAP_ALLOCATOR {\
|
||||
JS_NEW_BODY(ALLOCATOR, T,\
|
||||
(mozilla::Forward<P1>(p1),\
|
||||
mozilla::Forward<P2>(p2),\
|
||||
mozilla::Forward<P3>(p3),\
|
||||
mozilla::Forward<P4>(p4),\
|
||||
mozilla::Forward<P5>(p5),\
|
||||
mozilla::Forward<P6>(p6),\
|
||||
mozilla::Forward<P7>(p7),\
|
||||
mozilla::Forward<P8>(p8),\
|
||||
mozilla::Forward<P9>(p9),\
|
||||
mozilla::Forward<P10>(p10),\
|
||||
mozilla::Forward<P11>(p11),\
|
||||
mozilla::Forward<P12>(p12)))\
|
||||
}\
|
||||
template <class T, typename... Args> \
|
||||
QUALIFIERS T * \
|
||||
NEWNAME(Args&&... args) MOZ_HEAP_ALLOCATOR { \
|
||||
void *memory = ALLOCATOR(sizeof(T)); \
|
||||
return memory \
|
||||
? new(memory) T(mozilla::Forward<Args>(args)...) \
|
||||
: nullptr; \
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a class which should provide 'make' methods, add
|
||||
* JS_DECLARE_MAKE_METHODS (see JSContext for a usage example). This method
|
||||
* is functionally the same as JS_DECLARE_NEW_METHODS: it just declares methods
|
||||
* that return mozilla::UniquePtr instances that will singly-manage ownership
|
||||
* of the created object. This adds makes with up to 12 parameters. Add more
|
||||
* versions below if you need more than 12 parameters.
|
||||
* JS_DECLARE_MAKE_METHODS (see js::MallocProvider for an example). This
|
||||
* method is functionally the same as JS_DECLARE_NEW_METHODS: it just declares
|
||||
* methods that return mozilla::UniquePtr instances that will singly-manage
|
||||
* ownership of the created object.
|
||||
*
|
||||
* Note: Do not add a ; at the end of a use of JS_DECLARE_MAKE_METHODS,
|
||||
* or the build will break.
|
||||
*/
|
||||
#define JS_DECLARE_MAKE_METHODS(MAKENAME, NEWNAME, QUALIFIERS)\
|
||||
template <class T> \
|
||||
QUALIFIERS \
|
||||
mozilla::UniquePtr<T, JS::DeletePolicy<T>> \
|
||||
MAKENAME() MOZ_HEAP_ALLOCATOR {\
|
||||
JS_MAKE_BODY(NEWNAME, T, ())\
|
||||
}\
|
||||
\
|
||||
template <class T, class P1> \
|
||||
QUALIFIERS \
|
||||
mozilla::UniquePtr<T, JS::DeletePolicy<T>> \
|
||||
MAKENAME(P1 &&p1) MOZ_HEAP_ALLOCATOR {\
|
||||
JS_MAKE_BODY(NEWNAME, T,\
|
||||
(mozilla::Forward<P1>(p1)))\
|
||||
}\
|
||||
\
|
||||
template <class T, class P1, class P2> \
|
||||
QUALIFIERS \
|
||||
mozilla::UniquePtr<T, JS::DeletePolicy<T>> \
|
||||
MAKENAME(P1 &&p1, P2 &&p2) MOZ_HEAP_ALLOCATOR {\
|
||||
JS_MAKE_BODY(NEWNAME, T,\
|
||||
(mozilla::Forward<P1>(p1),\
|
||||
mozilla::Forward<P2>(p2)))\
|
||||
}\
|
||||
\
|
||||
template <class T, class P1, class P2, class P3> \
|
||||
QUALIFIERS \
|
||||
mozilla::UniquePtr<T, JS::DeletePolicy<T>> \
|
||||
MAKENAME(P1 &&p1, P2 &&p2, P3 &&p3) MOZ_HEAP_ALLOCATOR {\
|
||||
JS_MAKE_BODY(NEWNAME, T,\
|
||||
(mozilla::Forward<P1>(p1),\
|
||||
mozilla::Forward<P2>(p2),\
|
||||
mozilla::Forward<P3>(p3)))\
|
||||
}\
|
||||
\
|
||||
template <class T, class P1, class P2, class P3, class P4> \
|
||||
QUALIFIERS \
|
||||
mozilla::UniquePtr<T, JS::DeletePolicy<T>> \
|
||||
MAKENAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4) MOZ_HEAP_ALLOCATOR {\
|
||||
JS_MAKE_BODY(NEWNAME, T,\
|
||||
(mozilla::Forward<P1>(p1),\
|
||||
mozilla::Forward<P2>(p2),\
|
||||
mozilla::Forward<P3>(p3),\
|
||||
mozilla::Forward<P4>(p4)))\
|
||||
}\
|
||||
\
|
||||
template <class T, class P1, class P2, class P3, class P4, class P5> \
|
||||
QUALIFIERS \
|
||||
mozilla::UniquePtr<T, JS::DeletePolicy<T>> \
|
||||
MAKENAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5) MOZ_HEAP_ALLOCATOR {\
|
||||
JS_MAKE_BODY(NEWNAME, T,\
|
||||
(mozilla::Forward<P1>(p1),\
|
||||
mozilla::Forward<P2>(p2),\
|
||||
mozilla::Forward<P3>(p3),\
|
||||
mozilla::Forward<P4>(p4),\
|
||||
mozilla::Forward<P5>(p5)))\
|
||||
}\
|
||||
\
|
||||
template <class T, class P1, class P2, class P3, class P4, class P5, class P6> \
|
||||
QUALIFIERS \
|
||||
mozilla::UniquePtr<T, JS::DeletePolicy<T>> \
|
||||
MAKENAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5, P6 &&p6) MOZ_HEAP_ALLOCATOR {\
|
||||
JS_MAKE_BODY(NEWNAME, T,\
|
||||
(mozilla::Forward<P1>(p1),\
|
||||
mozilla::Forward<P2>(p2),\
|
||||
mozilla::Forward<P3>(p3),\
|
||||
mozilla::Forward<P4>(p4),\
|
||||
mozilla::Forward<P5>(p5),\
|
||||
mozilla::Forward<P6>(p6)))\
|
||||
}\
|
||||
\
|
||||
template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7> \
|
||||
QUALIFIERS \
|
||||
mozilla::UniquePtr<T, JS::DeletePolicy<T>> \
|
||||
MAKENAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5, P6 &&p6, P7 &&p7) MOZ_HEAP_ALLOCATOR {\
|
||||
JS_MAKE_BODY(NEWNAME, T,\
|
||||
(mozilla::Forward<P1>(p1),\
|
||||
mozilla::Forward<P2>(p2),\
|
||||
mozilla::Forward<P3>(p3),\
|
||||
mozilla::Forward<P4>(p4),\
|
||||
mozilla::Forward<P5>(p5),\
|
||||
mozilla::Forward<P6>(p6),\
|
||||
mozilla::Forward<P7>(p7)))\
|
||||
}\
|
||||
\
|
||||
template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8> \
|
||||
QUALIFIERS \
|
||||
mozilla::UniquePtr<T, JS::DeletePolicy<T>> \
|
||||
MAKENAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5, P6 &&p6, P7 &&p7, P8 &&p8) MOZ_HEAP_ALLOCATOR {\
|
||||
JS_MAKE_BODY(NEWNAME, T,\
|
||||
(mozilla::Forward<P1>(p1),\
|
||||
mozilla::Forward<P2>(p2),\
|
||||
mozilla::Forward<P3>(p3),\
|
||||
mozilla::Forward<P4>(p4),\
|
||||
mozilla::Forward<P5>(p5),\
|
||||
mozilla::Forward<P6>(p6),\
|
||||
mozilla::Forward<P7>(p7),\
|
||||
mozilla::Forward<P8>(p8)))\
|
||||
}\
|
||||
\
|
||||
template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9> \
|
||||
QUALIFIERS \
|
||||
mozilla::UniquePtr<T, JS::DeletePolicy<T>> \
|
||||
MAKENAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5, P6 &&p6, P7 &&p7, P8 &&p8, P9 &&p9) MOZ_HEAP_ALLOCATOR {\
|
||||
JS_MAKE_BODY(NEWNAME, T,\
|
||||
(mozilla::Forward<P1>(p1),\
|
||||
mozilla::Forward<P2>(p2),\
|
||||
mozilla::Forward<P3>(p3),\
|
||||
mozilla::Forward<P4>(p4),\
|
||||
mozilla::Forward<P5>(p5),\
|
||||
mozilla::Forward<P6>(p6),\
|
||||
mozilla::Forward<P7>(p7),\
|
||||
mozilla::Forward<P8>(p8),\
|
||||
mozilla::Forward<P9>(p9)))\
|
||||
}\
|
||||
\
|
||||
template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9, class P10> \
|
||||
QUALIFIERS \
|
||||
mozilla::UniquePtr<T, JS::DeletePolicy<T>> \
|
||||
MAKENAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5, P6 &&p6, P7 &&p7, P8 &&p8, P9 &&p9, P10 &&p10) MOZ_HEAP_ALLOCATOR {\
|
||||
JS_MAKE_BODY(NEWNAME, T,\
|
||||
(mozilla::Forward<P1>(p1),\
|
||||
mozilla::Forward<P2>(p2),\
|
||||
mozilla::Forward<P3>(p3),\
|
||||
mozilla::Forward<P4>(p4),\
|
||||
mozilla::Forward<P5>(p5),\
|
||||
mozilla::Forward<P6>(p6),\
|
||||
mozilla::Forward<P7>(p7),\
|
||||
mozilla::Forward<P8>(p8),\
|
||||
mozilla::Forward<P9>(p9),\
|
||||
mozilla::Forward<P10>(p10)))\
|
||||
}\
|
||||
\
|
||||
template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9, class P10, class P11> \
|
||||
QUALIFIERS \
|
||||
mozilla::UniquePtr<T, JS::DeletePolicy<T>> \
|
||||
MAKENAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5, P6 &&p6, P7 &&p7, P8 &&p8, P9 &&p9, P10 &&p10, P11 &&p11) MOZ_HEAP_ALLOCATOR {\
|
||||
JS_MAKE_BODY(NEWNAME, T,\
|
||||
(mozilla::Forward<P1>(p1),\
|
||||
mozilla::Forward<P2>(p2),\
|
||||
mozilla::Forward<P3>(p3),\
|
||||
mozilla::Forward<P4>(p4),\
|
||||
mozilla::Forward<P5>(p5),\
|
||||
mozilla::Forward<P6>(p6),\
|
||||
mozilla::Forward<P7>(p7),\
|
||||
mozilla::Forward<P8>(p8),\
|
||||
mozilla::Forward<P9>(p9),\
|
||||
mozilla::Forward<P10>(p10),\
|
||||
mozilla::Forward<P11>(p11)))\
|
||||
}\
|
||||
\
|
||||
template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9, class P10, class P11, class P12> \
|
||||
QUALIFIERS \
|
||||
mozilla::UniquePtr<T, JS::DeletePolicy<T>> \
|
||||
MAKENAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5, P6 &&p6, P7 &&p7, P8 &&p8, P9 &&p9, P10 &&p10, P11 &&p11, P12 &&p12) MOZ_HEAP_ALLOCATOR {\
|
||||
JS_MAKE_BODY(NEWNAME, T,\
|
||||
(mozilla::Forward<P1>(p1),\
|
||||
mozilla::Forward<P2>(p2),\
|
||||
mozilla::Forward<P3>(p3),\
|
||||
mozilla::Forward<P4>(p4),\
|
||||
mozilla::Forward<P5>(p5),\
|
||||
mozilla::Forward<P6>(p6),\
|
||||
mozilla::Forward<P7>(p7),\
|
||||
mozilla::Forward<P8>(p8),\
|
||||
mozilla::Forward<P9>(p9),\
|
||||
mozilla::Forward<P10>(p10),\
|
||||
mozilla::Forward<P11>(p11),\
|
||||
mozilla::Forward<P12>(p12)))\
|
||||
}\
|
||||
template <class T, typename... Args> \
|
||||
QUALIFIERS mozilla::UniquePtr<T, JS::DeletePolicy<T>> \
|
||||
MAKENAME(Args&&... args) MOZ_HEAP_ALLOCATOR { \
|
||||
T *ptr = NEWNAME<T>(mozilla::Forward<Args>(args)...); \
|
||||
return mozilla::UniquePtr<T, JS::DeletePolicy<T>>(ptr); \
|
||||
}
|
||||
|
||||
JS_DECLARE_NEW_METHODS(js_new, js_malloc, static MOZ_ALWAYS_INLINE)
|
||||
|
||||
|
|
|
|||
|
|
@ -183,6 +183,114 @@ CaseBody(ParseNode *pn)
|
|||
return BinaryRight(pn);
|
||||
}
|
||||
|
||||
static inline ParseNode *
|
||||
BinaryOpLeft(ParseNode *pn)
|
||||
{
|
||||
MOZ_ASSERT(pn->isBinaryOperation());
|
||||
MOZ_ASSERT(pn->isArity(PN_LIST));
|
||||
MOZ_ASSERT(pn->pn_count == 2);
|
||||
return ListHead(pn);
|
||||
}
|
||||
|
||||
static inline ParseNode *
|
||||
BinaryOpRight(ParseNode *pn)
|
||||
{
|
||||
MOZ_ASSERT(pn->isBinaryOperation());
|
||||
MOZ_ASSERT(pn->isArity(PN_LIST));
|
||||
MOZ_ASSERT(pn->pn_count == 2);
|
||||
return NextNode(ListHead(pn));
|
||||
}
|
||||
|
||||
static inline ParseNode *
|
||||
BitwiseLeft(ParseNode *pn)
|
||||
{
|
||||
return BinaryOpLeft(pn);
|
||||
}
|
||||
|
||||
static inline ParseNode *
|
||||
BitwiseRight(ParseNode *pn)
|
||||
{
|
||||
return BinaryOpRight(pn);
|
||||
}
|
||||
|
||||
static inline ParseNode *
|
||||
MultiplyLeft(ParseNode *pn)
|
||||
{
|
||||
MOZ_ASSERT(pn->isKind(PNK_STAR));
|
||||
return BinaryOpLeft(pn);
|
||||
}
|
||||
|
||||
static inline ParseNode *
|
||||
MultiplyRight(ParseNode *pn)
|
||||
{
|
||||
MOZ_ASSERT(pn->isKind(PNK_STAR));
|
||||
return BinaryOpRight(pn);
|
||||
}
|
||||
|
||||
static inline ParseNode *
|
||||
AddSubLeft(ParseNode *pn)
|
||||
{
|
||||
MOZ_ASSERT(pn->isKind(PNK_ADD) || pn->isKind(PNK_SUB));
|
||||
return BinaryOpLeft(pn);
|
||||
}
|
||||
|
||||
static inline ParseNode *
|
||||
AddSubRight(ParseNode *pn)
|
||||
{
|
||||
MOZ_ASSERT(pn->isKind(PNK_ADD) || pn->isKind(PNK_SUB));
|
||||
return BinaryOpRight(pn);
|
||||
}
|
||||
|
||||
static inline ParseNode *
|
||||
DivOrModLeft(ParseNode *pn)
|
||||
{
|
||||
MOZ_ASSERT(pn->isKind(PNK_DIV) || pn->isKind(PNK_MOD));
|
||||
return BinaryOpLeft(pn);
|
||||
}
|
||||
|
||||
static inline ParseNode *
|
||||
DivOrModRight(ParseNode *pn)
|
||||
{
|
||||
MOZ_ASSERT(pn->isKind(PNK_DIV) || pn->isKind(PNK_MOD));
|
||||
return BinaryOpRight(pn);
|
||||
}
|
||||
|
||||
static inline ParseNode *
|
||||
ComparisonLeft(ParseNode *pn)
|
||||
{
|
||||
return BinaryOpLeft(pn);
|
||||
}
|
||||
|
||||
static inline ParseNode *
|
||||
ComparisonRight(ParseNode *pn)
|
||||
{
|
||||
return BinaryOpRight(pn);
|
||||
}
|
||||
|
||||
static inline ParseNode *
|
||||
AndOrLeft(ParseNode *pn)
|
||||
{
|
||||
return BinaryOpLeft(pn);
|
||||
}
|
||||
|
||||
static inline ParseNode *
|
||||
AndOrRight(ParseNode *pn)
|
||||
{
|
||||
return BinaryOpRight(pn);
|
||||
}
|
||||
|
||||
static inline ParseNode *
|
||||
RelationalLeft(ParseNode *pn)
|
||||
{
|
||||
return BinaryOpLeft(pn);
|
||||
}
|
||||
|
||||
static inline ParseNode *
|
||||
RelationalRight(ParseNode *pn)
|
||||
{
|
||||
return BinaryOpRight(pn);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
IsExpressionStatement(ParseNode *pn)
|
||||
{
|
||||
|
|
@ -3712,13 +3820,13 @@ CheckTypeAnnotation(ModuleCompiler &m, ParseNode *coercionNode, AsmJSCoercion *c
|
|||
{
|
||||
switch (coercionNode->getKind()) {
|
||||
case PNK_BITOR: {
|
||||
ParseNode *rhs = BinaryRight(coercionNode);
|
||||
ParseNode *rhs = BitwiseRight(coercionNode);
|
||||
uint32_t i;
|
||||
if (!IsLiteralInt(m, rhs, &i) || i != 0)
|
||||
return m.fail(rhs, "must use |0 for argument/return coercion");
|
||||
*coercion = AsmJS_ToInt32;
|
||||
if (coercedExpr)
|
||||
*coercedExpr = BinaryLeft(coercionNode);
|
||||
*coercedExpr = BitwiseLeft(coercionNode);
|
||||
return true;
|
||||
}
|
||||
case PNK_POS: {
|
||||
|
|
@ -4329,8 +4437,10 @@ static bool
|
|||
FoldMaskedArrayIndex(FunctionCompiler &f, ParseNode **indexExpr, int32_t *mask,
|
||||
NeedsBoundsCheck *needsBoundsCheck)
|
||||
{
|
||||
ParseNode *indexNode = BinaryLeft(*indexExpr);
|
||||
ParseNode *maskNode = BinaryRight(*indexExpr);
|
||||
MOZ_ASSERT((*indexExpr)->isKind(PNK_BITAND));
|
||||
|
||||
ParseNode *indexNode = BitwiseLeft(*indexExpr);
|
||||
ParseNode *maskNode = BitwiseRight(*indexExpr);
|
||||
|
||||
uint32_t mask2;
|
||||
if (IsLiteralOrConstInt(f, maskNode, &mask2)) {
|
||||
|
|
@ -4388,16 +4498,17 @@ CheckArrayAccess(FunctionCompiler &f, ParseNode *viewName, ParseNode *indexExpr,
|
|||
|
||||
MDefinition *pointerDef;
|
||||
if (indexExpr->isKind(PNK_RSH)) {
|
||||
ParseNode *shiftNode = BinaryRight(indexExpr);
|
||||
ParseNode *pointerNode = BinaryLeft(indexExpr);
|
||||
ParseNode *shiftAmountNode = BitwiseRight(indexExpr);
|
||||
|
||||
uint32_t shift;
|
||||
if (!IsLiteralInt(f.m(), shiftNode, &shift))
|
||||
return f.failf(shiftNode, "shift amount must be constant");
|
||||
if (!IsLiteralInt(f.m(), shiftAmountNode, &shift))
|
||||
return f.failf(shiftAmountNode, "shift amount must be constant");
|
||||
|
||||
unsigned requiredShift = TypedArrayShift(*viewType);
|
||||
if (shift != requiredShift)
|
||||
return f.failf(shiftNode, "shift amount must be %u", requiredShift);
|
||||
return f.failf(shiftAmountNode, "shift amount must be %u", requiredShift);
|
||||
|
||||
ParseNode *pointerNode = BitwiseLeft(indexExpr);
|
||||
|
||||
if (pointerNode->isKind(PNK_BITAND))
|
||||
FoldMaskedArrayIndex(f, &pointerNode, &mask, needsBoundsCheck);
|
||||
|
|
@ -4596,6 +4707,7 @@ static bool
|
|||
CheckAssign(FunctionCompiler &f, ParseNode *assign, MDefinition **def, Type *type)
|
||||
{
|
||||
MOZ_ASSERT(assign->isKind(PNK_ASSIGN));
|
||||
|
||||
ParseNode *lhs = BinaryLeft(assign);
|
||||
ParseNode *rhs = BinaryRight(assign);
|
||||
|
||||
|
|
@ -5094,8 +5206,8 @@ CheckFuncPtrCall(FunctionCompiler &f, ParseNode *callNode, RetType retType, MDef
|
|||
if (!indexExpr->isKind(PNK_BITAND))
|
||||
return f.fail(indexExpr, "function-pointer table index expression needs & mask");
|
||||
|
||||
ParseNode *indexNode = BinaryLeft(indexExpr);
|
||||
ParseNode *maskNode = BinaryRight(indexExpr);
|
||||
ParseNode *indexNode = BitwiseLeft(indexExpr);
|
||||
ParseNode *maskNode = BitwiseRight(indexExpr);
|
||||
|
||||
uint32_t mask;
|
||||
if (!IsLiteralInt(f.m(), maskNode, &mask) || mask == UINT32_MAX || !IsPowerOfTwo(mask + 1))
|
||||
|
|
@ -5740,22 +5852,12 @@ CheckSimdOperationCall(FunctionCompiler &f, ParseNode *call, const ModuleCompile
|
|||
AsmJSSimdType opType = global->simdOperationType();
|
||||
|
||||
switch (global->simdOperation()) {
|
||||
case AsmJSSimdOperation_add:
|
||||
return CheckSimdBinary(f, call, opType, MSimdBinaryArith::Add, def, type);
|
||||
case AsmJSSimdOperation_sub:
|
||||
return CheckSimdBinary(f, call, opType, MSimdBinaryArith::Sub, def, type);
|
||||
case AsmJSSimdOperation_mul:
|
||||
return CheckSimdBinary(f, call, opType, MSimdBinaryArith::Mul, def, type);
|
||||
case AsmJSSimdOperation_div:
|
||||
return CheckSimdBinary(f, call, opType, MSimdBinaryArith::Div, def, type);
|
||||
case AsmJSSimdOperation_max:
|
||||
return CheckSimdBinary(f, call, opType, MSimdBinaryArith::Max, def, type);
|
||||
case AsmJSSimdOperation_min:
|
||||
return CheckSimdBinary(f, call, opType, MSimdBinaryArith::Min, def, type);
|
||||
case AsmJSSimdOperation_maxNum:
|
||||
return CheckSimdBinary(f, call, opType, MSimdBinaryArith::MaxNum, def, type);
|
||||
case AsmJSSimdOperation_minNum:
|
||||
return CheckSimdBinary(f, call, opType, MSimdBinaryArith::MinNum, def, type);
|
||||
#define OP_CHECK_CASE_LIST_(OP) \
|
||||
case AsmJSSimdOperation_##OP: \
|
||||
return CheckSimdBinary(f, call, opType, MSimdBinaryArith::Op_##OP, def, type);
|
||||
ARITH_COMMONX4_SIMD_OP(OP_CHECK_CASE_LIST_)
|
||||
ARITH_FLOAT32X4_SIMD_OP(OP_CHECK_CASE_LIST_)
|
||||
#undef OP_CHECK_CASE_LIST_
|
||||
|
||||
case AsmJSSimdOperation_lessThan:
|
||||
return CheckSimdBinary(f, call, opType, MSimdBinaryComp::lessThan, def, type);
|
||||
|
|
@ -6287,8 +6389,8 @@ static bool
|
|||
CheckMultiply(FunctionCompiler &f, ParseNode *star, MDefinition **def, Type *type)
|
||||
{
|
||||
MOZ_ASSERT(star->isKind(PNK_STAR));
|
||||
ParseNode *lhs = BinaryLeft(star);
|
||||
ParseNode *rhs = BinaryRight(star);
|
||||
ParseNode *lhs = MultiplyLeft(star);
|
||||
ParseNode *rhs = MultiplyRight(star);
|
||||
|
||||
MDefinition *lhsDef;
|
||||
Type lhsType;
|
||||
|
|
@ -6330,8 +6432,8 @@ CheckAddOrSub(FunctionCompiler &f, ParseNode *expr, MDefinition **def, Type *typ
|
|||
JS_CHECK_RECURSION_DONT_REPORT(f.cx(), return f.m().failOverRecursed());
|
||||
|
||||
MOZ_ASSERT(expr->isKind(PNK_ADD) || expr->isKind(PNK_SUB));
|
||||
ParseNode *lhs = BinaryLeft(expr);
|
||||
ParseNode *rhs = BinaryRight(expr);
|
||||
ParseNode *lhs = AddSubLeft(expr);
|
||||
ParseNode *rhs = AddSubRight(expr);
|
||||
|
||||
MDefinition *lhsDef, *rhsDef;
|
||||
Type lhsType, rhsType;
|
||||
|
|
@ -6392,8 +6494,9 @@ static bool
|
|||
CheckDivOrMod(FunctionCompiler &f, ParseNode *expr, MDefinition **def, Type *type)
|
||||
{
|
||||
MOZ_ASSERT(expr->isKind(PNK_DIV) || expr->isKind(PNK_MOD));
|
||||
ParseNode *lhs = BinaryLeft(expr);
|
||||
ParseNode *rhs = BinaryRight(expr);
|
||||
|
||||
ParseNode *lhs = DivOrModLeft(expr);
|
||||
ParseNode *rhs = DivOrModRight(expr);
|
||||
|
||||
MDefinition *lhsDef, *rhsDef;
|
||||
Type lhsType, rhsType;
|
||||
|
|
@ -6446,8 +6549,9 @@ CheckComparison(FunctionCompiler &f, ParseNode *comp, MDefinition **def, Type *t
|
|||
{
|
||||
MOZ_ASSERT(comp->isKind(PNK_LT) || comp->isKind(PNK_LE) || comp->isKind(PNK_GT) ||
|
||||
comp->isKind(PNK_GE) || comp->isKind(PNK_EQ) || comp->isKind(PNK_NE));
|
||||
ParseNode *lhs = BinaryLeft(comp);
|
||||
ParseNode *rhs = BinaryRight(comp);
|
||||
|
||||
ParseNode *lhs = ComparisonLeft(comp);
|
||||
ParseNode *rhs = ComparisonRight(comp);
|
||||
|
||||
MDefinition *lhsDef, *rhsDef;
|
||||
Type lhsType, rhsType;
|
||||
|
|
@ -6484,8 +6588,8 @@ CheckComparison(FunctionCompiler &f, ParseNode *comp, MDefinition **def, Type *t
|
|||
static bool
|
||||
CheckBitwise(FunctionCompiler &f, ParseNode *bitwise, MDefinition **def, Type *type)
|
||||
{
|
||||
ParseNode *lhs = BinaryLeft(bitwise);
|
||||
ParseNode *rhs = BinaryRight(bitwise);
|
||||
ParseNode *lhs = BitwiseLeft(bitwise);
|
||||
ParseNode *rhs = BitwiseRight(bitwise);
|
||||
|
||||
int32_t identityElement;
|
||||
bool onlyOnRight;
|
||||
|
|
@ -7208,20 +7312,20 @@ static bool
|
|||
CheckHeapLengthCondition(ModuleCompiler &m, ParseNode *cond, PropertyName *newBufferName,
|
||||
uint32_t *mask, uint32_t *minLength, uint32_t *maxLength)
|
||||
{
|
||||
if (!cond->isKind(PNK_OR) || !BinaryLeft(cond)->isKind(PNK_OR))
|
||||
if (!cond->isKind(PNK_OR) || !AndOrLeft(cond)->isKind(PNK_OR))
|
||||
return m.fail(cond, "expecting byteLength & K || byteLength <= L || byteLength > M");
|
||||
|
||||
ParseNode *cond1 = BinaryLeft(BinaryLeft(cond));
|
||||
ParseNode *cond2 = BinaryRight(BinaryLeft(cond));
|
||||
ParseNode *cond3 = BinaryRight(cond);
|
||||
ParseNode *cond1 = AndOrLeft(AndOrLeft(cond));
|
||||
ParseNode *cond2 = AndOrRight(AndOrLeft(cond));
|
||||
ParseNode *cond3 = AndOrRight(cond);
|
||||
|
||||
if (!cond1->isKind(PNK_BITAND))
|
||||
return m.fail(cond1, "expecting byteLength & K");
|
||||
|
||||
if (!CheckByteLengthCall(m, BinaryLeft(cond1), newBufferName))
|
||||
if (!CheckByteLengthCall(m, BitwiseLeft(cond1), newBufferName))
|
||||
return false;
|
||||
|
||||
ParseNode *maskNode = BinaryRight(cond1);
|
||||
ParseNode *maskNode = BitwiseRight(cond1);
|
||||
if (!IsLiteralInt(m, maskNode, mask))
|
||||
return m.fail(maskNode, "expecting integer literal mask");
|
||||
if ((*mask & 0xffffff) != 0xffffff)
|
||||
|
|
@ -7230,10 +7334,10 @@ CheckHeapLengthCondition(ModuleCompiler &m, ParseNode *cond, PropertyName *newBu
|
|||
if (!cond2->isKind(PNK_LE))
|
||||
return m.fail(cond2, "expecting byteLength <= L");
|
||||
|
||||
if (!CheckByteLengthCall(m, BinaryLeft(cond2), newBufferName))
|
||||
if (!CheckByteLengthCall(m, RelationalLeft(cond2), newBufferName))
|
||||
return false;
|
||||
|
||||
ParseNode *minLengthNode = BinaryRight(cond2);
|
||||
ParseNode *minLengthNode = RelationalRight(cond2);
|
||||
uint32_t minLengthExclusive;
|
||||
if (!IsLiteralInt(m, minLengthNode, &minLengthExclusive))
|
||||
return m.fail(minLengthNode, "expecting integer literal");
|
||||
|
|
@ -7246,10 +7350,10 @@ CheckHeapLengthCondition(ModuleCompiler &m, ParseNode *cond, PropertyName *newBu
|
|||
if (!cond3->isKind(PNK_GT))
|
||||
return m.fail(cond3, "expecting byteLength > M");
|
||||
|
||||
if (!CheckByteLengthCall(m, BinaryLeft(cond3), newBufferName))
|
||||
if (!CheckByteLengthCall(m, RelationalLeft(cond3), newBufferName))
|
||||
return false;
|
||||
|
||||
ParseNode *maxLengthNode = BinaryRight(cond3);
|
||||
ParseNode *maxLengthNode = RelationalRight(cond3);
|
||||
if (!IsLiteralInt(m, maxLengthNode, maxLength))
|
||||
return m.fail(maxLengthNode, "expecting integer literal");
|
||||
if (*maxLength > 0x80000000)
|
||||
|
|
|
|||
|
|
@ -190,31 +190,37 @@
|
|||
_(shiftLeftByScalar) \
|
||||
_(shiftRightArithmeticByScalar) \
|
||||
_(shiftRightLogicalByScalar)
|
||||
#define FOREACH_FLOAT32X4_SIMD_OP(_) \
|
||||
_(abs) \
|
||||
_(sqrt) \
|
||||
_(reciprocal) \
|
||||
_(reciprocalSqrt) \
|
||||
_(fromInt32x4) \
|
||||
_(fromInt32x4Bits) \
|
||||
#define ARITH_FLOAT32X4_SIMD_OP(_) \
|
||||
_(div) \
|
||||
_(max) \
|
||||
_(min) \
|
||||
_(maxNum) \
|
||||
_(minNum)
|
||||
#define FOREACH_COMMONX4_SIMD_OP(_) \
|
||||
#define FOREACH_FLOAT32X4_SIMD_OP(_) \
|
||||
ARITH_FLOAT32X4_SIMD_OP(_) \
|
||||
_(abs) \
|
||||
_(sqrt) \
|
||||
_(reciprocal) \
|
||||
_(reciprocalSqrt) \
|
||||
_(fromInt32x4) \
|
||||
_(fromInt32x4Bits)
|
||||
#define ARITH_COMMONX4_SIMD_OP(_) \
|
||||
_(add) \
|
||||
_(sub) \
|
||||
_(mul) \
|
||||
_(mul)
|
||||
#define BITWISE_COMMONX4_SIMD_OP(_) \
|
||||
_(and) \
|
||||
_(or) \
|
||||
_(xor)
|
||||
#define FOREACH_COMMONX4_SIMD_OP(_) \
|
||||
ARITH_COMMONX4_SIMD_OP(_) \
|
||||
BITWISE_COMMONX4_SIMD_OP(_) \
|
||||
_(lessThan) \
|
||||
_(lessThanOrEqual) \
|
||||
_(equal) \
|
||||
_(notEqual) \
|
||||
_(greaterThan) \
|
||||
_(greaterThanOrEqual) \
|
||||
_(and) \
|
||||
_(or) \
|
||||
_(xor) \
|
||||
_(bitselect) \
|
||||
_(select) \
|
||||
_(swizzle) \
|
||||
|
|
|
|||
|
|
@ -2039,15 +2039,10 @@ CheckSideEffects(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, bool
|
|||
return true;
|
||||
}
|
||||
|
||||
if (pn->isOp(JSOP_OR) || pn->isOp(JSOP_AND) || pn->isOp(JSOP_STRICTEQ) ||
|
||||
pn->isOp(JSOP_STRICTNE)) {
|
||||
/*
|
||||
* ||, &&, ===, and !== do not convert their operands via
|
||||
* toString or valueOf method calls.
|
||||
*/
|
||||
return CheckSideEffects(cx, bce, pn->pn_left, answer) &&
|
||||
CheckSideEffects(cx, bce, pn->pn_right, answer);
|
||||
}
|
||||
MOZ_ASSERT(!pn->isOp(JSOP_OR), "|| produces a list now");
|
||||
MOZ_ASSERT(!pn->isOp(JSOP_AND), "&& produces a list now");
|
||||
MOZ_ASSERT(!pn->isOp(JSOP_STRICTEQ), "=== produces a list now");
|
||||
MOZ_ASSERT(!pn->isOp(JSOP_STRICTNE), "!== produces a list now");
|
||||
|
||||
/*
|
||||
* We can't easily prove that neither operand ever denotes an
|
||||
|
|
@ -4575,7 +4570,10 @@ EmitTry(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
|||
ptrdiff_t tryEnd = bce->offset();
|
||||
|
||||
// If this try has a catch block, emit it.
|
||||
if (ParseNode *pn2 = pn->pn_kid2) {
|
||||
ParseNode *catchList = pn->pn_kid2;
|
||||
if (catchList) {
|
||||
MOZ_ASSERT(catchList->isKind(PNK_CATCHLIST));
|
||||
|
||||
// The emitted code for a catch block looks like:
|
||||
//
|
||||
// [pushblockscope] only if any local aliased
|
||||
|
|
@ -4601,7 +4599,7 @@ EmitTry(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
|||
// code if appropriate, and is also used for the catch-all trynote for
|
||||
// capturing exceptions thrown from catch{} blocks.
|
||||
//
|
||||
for (ParseNode *pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) {
|
||||
for (ParseNode *pn3 = catchList->pn_head; pn3; pn3 = pn3->pn_next) {
|
||||
MOZ_ASSERT(bce->stackDepth == depth);
|
||||
|
||||
// Emit the lexical scope and catch body.
|
||||
|
|
@ -4676,7 +4674,7 @@ EmitTry(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
|||
|
||||
// Add the try note last, to let post-order give us the right ordering
|
||||
// (first to last for a given nesting level, inner to outer by level).
|
||||
if (pn->pn_kid2 && !bce->tryNoteList.append(JSTRY_CATCH, depth, tryStart, tryEnd))
|
||||
if (catchList && !bce->tryNoteList.append(JSTRY_CATCH, depth, tryStart, tryEnd))
|
||||
return false;
|
||||
|
||||
// If we've got a finally, mark try+catch region with additional
|
||||
|
|
@ -6328,6 +6326,8 @@ EmitCallOrNew(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
|||
static bool
|
||||
EmitLogical(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
||||
{
|
||||
MOZ_ASSERT(pn->isArity(PN_LIST));
|
||||
|
||||
/*
|
||||
* JSOP_OR converts the operand on the stack to boolean, leaves the original
|
||||
* value on the stack and jumps if true; otherwise it falls into the next
|
||||
|
|
@ -6338,26 +6338,6 @@ EmitLogical(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
|||
* otherwise it falls into the right operand's bytecode.
|
||||
*/
|
||||
|
||||
if (pn->isArity(PN_BINARY)) {
|
||||
if (!EmitTree(cx, bce, pn->pn_left))
|
||||
return false;
|
||||
ptrdiff_t top = EmitJump(cx, bce, JSOP_BACKPATCH, 0);
|
||||
if (top < 0)
|
||||
return false;
|
||||
if (Emit1(cx, bce, JSOP_POP) < 0)
|
||||
return false;
|
||||
if (!EmitTree(cx, bce, pn->pn_right))
|
||||
return false;
|
||||
ptrdiff_t off = bce->offset();
|
||||
jsbytecode *pc = bce->code(top);
|
||||
SET_JUMP_OFFSET(pc, off - top);
|
||||
*pc = pn->getOp();
|
||||
return true;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(pn->isArity(PN_LIST));
|
||||
MOZ_ASSERT(pn->pn_head->pn_next->pn_next);
|
||||
|
||||
/* Left-associative operator chain: avoid too much recursion. */
|
||||
ParseNode *pn2 = pn->pn_head;
|
||||
if (!EmitTree(cx, bce, pn2))
|
||||
|
|
@ -7135,29 +7115,21 @@ frontend::EmitTree(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
|||
case PNK_URSH:
|
||||
case PNK_STAR:
|
||||
case PNK_DIV:
|
||||
case PNK_MOD:
|
||||
if (pn->isArity(PN_LIST)) {
|
||||
/* Left-associative operator chain: avoid too much recursion. */
|
||||
ParseNode *pn2 = pn->pn_head;
|
||||
if (!EmitTree(cx, bce, pn2))
|
||||
case PNK_MOD: {
|
||||
MOZ_ASSERT(pn->isArity(PN_LIST));
|
||||
/* Left-associative operator chain: avoid too much recursion. */
|
||||
ParseNode *subexpr = pn->pn_head;
|
||||
if (!EmitTree(cx, bce, subexpr))
|
||||
return false;
|
||||
JSOp op = pn->getOp();
|
||||
while ((subexpr = subexpr->pn_next) != nullptr) {
|
||||
if (!EmitTree(cx, bce, subexpr))
|
||||
return false;
|
||||
JSOp op = pn->getOp();
|
||||
while ((pn2 = pn2->pn_next) != nullptr) {
|
||||
if (!EmitTree(cx, bce, pn2))
|
||||
return false;
|
||||
if (Emit1(cx, bce, op) < 0)
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
/* Binary operators that evaluate both operands unconditionally. */
|
||||
if (!EmitTree(cx, bce, pn->pn_left))
|
||||
return false;
|
||||
if (!EmitTree(cx, bce, pn->pn_right))
|
||||
return false;
|
||||
if (Emit1(cx, bce, pn->getOp()) < 0)
|
||||
if (Emit1(cx, bce, op) < 0)
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case PNK_THROW:
|
||||
case PNK_TYPEOF:
|
||||
|
|
@ -7199,12 +7171,14 @@ frontend::EmitTree(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
|||
ok = EmitLexicalScope(cx, bce, pn);
|
||||
break;
|
||||
|
||||
case PNK_LET:
|
||||
case PNK_LETBLOCK:
|
||||
case PNK_LETEXPR:
|
||||
ok = EmitLet(cx, bce, pn);
|
||||
break;
|
||||
|
||||
case PNK_CONST:
|
||||
MOZ_ASSERT_IF(pn->isKind(PNK_CONST), !pn->isArity(PN_BINARY));
|
||||
ok = pn->isArity(PN_BINARY)
|
||||
? EmitLet(cx, bce, pn)
|
||||
: EmitVariables(cx, bce, pn, InitializeVars);
|
||||
case PNK_LET:
|
||||
ok = EmitVariables(cx, bce, pn, InitializeVars);
|
||||
break;
|
||||
|
||||
case PNK_IMPORT:
|
||||
|
|
|
|||
|
|
@ -29,67 +29,393 @@ using JS::ToInt32;
|
|||
using JS::ToUint32;
|
||||
|
||||
static bool
|
||||
ContainsVarOrConst(ExclusiveContext *cx, ParseNode *pn, ParseNode **resultp)
|
||||
ContainsHoistedDeclaration(ExclusiveContext *cx, ParseNode *node, bool *result);
|
||||
|
||||
static bool
|
||||
ListContainsHoistedDeclaration(ExclusiveContext *cx, ListNode *list, bool *result)
|
||||
{
|
||||
for (ParseNode *node = list->pn_head; node; node = node->pn_next) {
|
||||
if (!ContainsHoistedDeclaration(cx, node, result))
|
||||
return false;
|
||||
if (*result)
|
||||
return true;
|
||||
}
|
||||
|
||||
*result = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Determines whether the given ParseNode contains any declarations whose
|
||||
// visibility will extend outside the node itself -- that is, whether the
|
||||
// ParseNode contains any var statements.
|
||||
//
|
||||
// THIS IS NOT A GENERAL-PURPOSE FUNCTION. It is only written to work in the
|
||||
// specific context of deciding that |node|, as one arm of a PNK_IF controlled
|
||||
// by a constant condition, contains a declaration that forbids |node| being
|
||||
// completely eliminated as dead.
|
||||
static bool
|
||||
ContainsHoistedDeclaration(ExclusiveContext *cx, ParseNode *node, bool *result)
|
||||
{
|
||||
JS_CHECK_RECURSION(cx, return false);
|
||||
|
||||
if (!pn) {
|
||||
*resultp = nullptr;
|
||||
// With a better-typed AST, we would have distinct parse node classes for
|
||||
// expressions and for statements and would characterize expressions with
|
||||
// ExpressionKind and statements with StatementKind. Perhaps someday. In
|
||||
// the meantime we must characterize every ParseNodeKind, even the
|
||||
// expression/sub-expression ones that, if we handle all statement kinds
|
||||
// correctly, we'll never see.
|
||||
switch (node->getKind()) {
|
||||
// Base case.
|
||||
case PNK_VAR:
|
||||
*result = true;
|
||||
return true;
|
||||
}
|
||||
if (pn->isKind(PNK_VAR) || pn->isKind(PNK_CONST)) {
|
||||
*resultp = pn;
|
||||
|
||||
// Non-global lexical declarations are block-scoped (ergo not hoistable).
|
||||
// (Global lexical declarations, in addition to being irrelevant here as
|
||||
// ContainsHoistedDeclaration is only used on the arms of an |if|
|
||||
// statement, are handled by PNK_GLOBALCONST and PNK_VAR.)
|
||||
case PNK_LET:
|
||||
case PNK_CONST:
|
||||
MOZ_ASSERT(node->isArity(PN_LIST));
|
||||
*result = false;
|
||||
return true;
|
||||
}
|
||||
switch (pn->getArity()) {
|
||||
case PN_LIST:
|
||||
for (ParseNode *pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
|
||||
if (!ContainsVarOrConst(cx, pn2, resultp))
|
||||
return false;
|
||||
if (*resultp)
|
||||
|
||||
// ContainsHoistedDeclaration is only called on nested nodes, so any
|
||||
// instance of this can't be function statements at body level. In
|
||||
// SpiderMonkey, a binding induced by a function statement is added when
|
||||
// the function statement is evaluated. Thus any declaration introduced
|
||||
// by a function statement, as observed by this function, isn't a hoisted
|
||||
// declaration.
|
||||
case PNK_FUNCTION:
|
||||
MOZ_ASSERT(node->isArity(PN_CODE));
|
||||
*result = false;
|
||||
return true;
|
||||
|
||||
// Statements with no sub-components at all.
|
||||
case PNK_NOP: // induced by function f() {} function f() {}
|
||||
case PNK_DEBUGGER:
|
||||
MOZ_ASSERT(node->isArity(PN_NULLARY));
|
||||
*result = false;
|
||||
return true;
|
||||
|
||||
// Statements containing only an expression have no declarations.
|
||||
case PNK_SEMI:
|
||||
case PNK_THROW:
|
||||
MOZ_ASSERT(node->isArity(PN_UNARY));
|
||||
*result = false;
|
||||
return true;
|
||||
|
||||
case PNK_RETURN:
|
||||
// These two aren't statements in the spec, but we sometimes insert them
|
||||
// in statement lists anyway.
|
||||
case PNK_YIELD_STAR:
|
||||
case PNK_YIELD:
|
||||
MOZ_ASSERT(node->isArity(PN_BINARY));
|
||||
*result = false;
|
||||
return true;
|
||||
|
||||
// Other statements with no sub-statement components.
|
||||
case PNK_BREAK:
|
||||
case PNK_CONTINUE:
|
||||
case PNK_IMPORT:
|
||||
case PNK_IMPORT_SPEC_LIST:
|
||||
case PNK_IMPORT_SPEC:
|
||||
case PNK_EXPORT_FROM:
|
||||
case PNK_EXPORT_SPEC_LIST:
|
||||
case PNK_EXPORT_SPEC:
|
||||
case PNK_EXPORT:
|
||||
case PNK_EXPORT_BATCH_SPEC:
|
||||
*result = false;
|
||||
return true;
|
||||
|
||||
// Statements possibly containing hoistable declarations only in the left
|
||||
// half, in ParseNode terms -- the loop body in AST terms.
|
||||
case PNK_DOWHILE:
|
||||
return ContainsHoistedDeclaration(cx, node->pn_left, result);
|
||||
|
||||
// Statements possibly containing hoistable declarations only in the
|
||||
// right half, in ParseNode terms -- the loop body or nested statement
|
||||
// (usually a block statement), in AST terms.
|
||||
case PNK_WHILE:
|
||||
case PNK_WITH:
|
||||
return ContainsHoistedDeclaration(cx, node->pn_right, result);
|
||||
|
||||
case PNK_LABEL:
|
||||
return ContainsHoistedDeclaration(cx, node->pn_expr, result);
|
||||
|
||||
// Statements with more complicated structures.
|
||||
|
||||
// if-statement nodes may have hoisted declarations in their consequent
|
||||
// and alternative components.
|
||||
case PNK_IF: {
|
||||
MOZ_ASSERT(node->isArity(PN_TERNARY));
|
||||
|
||||
ParseNode *consequent = node->pn_kid2;
|
||||
if (!ContainsHoistedDeclaration(cx, consequent, result))
|
||||
return false;
|
||||
if (*result)
|
||||
return true;
|
||||
|
||||
if (ParseNode *alternative = node->pn_kid3)
|
||||
return ContainsHoistedDeclaration(cx, alternative, result);
|
||||
|
||||
*result = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Legacy array and generator comprehensions use PNK_IF to represent
|
||||
// conditions specified in the comprehension tail: for example,
|
||||
// [x for (x in obj) if (x)]. The consequent of such PNK_IF nodes is
|
||||
// either PNK_YIELD in a PNK_SEMI statement (generator comprehensions) or
|
||||
// PNK_ARRAYPUSH (array comprehensions) . The first case is consistent
|
||||
// with normal if-statement structure with consequent/alternative as
|
||||
// statements. The second case is abnormal and requires that we not
|
||||
// banish PNK_ARRAYPUSH to the unreachable list, handling it explicitly.
|
||||
//
|
||||
// We could require that this one weird PNK_ARRAYPUSH case be packaged in
|
||||
// a PNK_SEMI, for consistency. That requires careful bytecode emitter
|
||||
// adjustment that seems unwarranted for a deprecated feature.
|
||||
case PNK_ARRAYPUSH:
|
||||
*result = false;
|
||||
return true;
|
||||
|
||||
// try-statements have statements to execute, and one or both of a
|
||||
// catch-list and a finally-block.
|
||||
case PNK_TRY: {
|
||||
MOZ_ASSERT(node->isArity(PN_TERNARY));
|
||||
MOZ_ASSERT(node->pn_kid2 || node->pn_kid3,
|
||||
"must have either catch(es) or finally");
|
||||
|
||||
ParseNode *tryBlock = node->pn_kid1;
|
||||
if (!ContainsHoistedDeclaration(cx, tryBlock, result))
|
||||
return false;
|
||||
if (*result)
|
||||
return true;
|
||||
|
||||
if (ParseNode *catchList = node->pn_kid2) {
|
||||
for (ParseNode *lexicalScope = catchList->pn_head;
|
||||
lexicalScope;
|
||||
lexicalScope = lexicalScope->pn_next)
|
||||
{
|
||||
MOZ_ASSERT(lexicalScope->isKind(PNK_LEXICALSCOPE));
|
||||
|
||||
ParseNode *catchNode = lexicalScope->pn_expr;
|
||||
MOZ_ASSERT(catchNode->isKind(PNK_CATCH));
|
||||
|
||||
ParseNode *catchStatements = catchNode->pn_kid3;
|
||||
if (!ContainsHoistedDeclaration(cx, catchStatements, result))
|
||||
return false;
|
||||
if (*result)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (ParseNode *finallyBlock = node->pn_kid3)
|
||||
return ContainsHoistedDeclaration(cx, finallyBlock, result);
|
||||
|
||||
*result = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// A switch node's left half is an expression; only its right half (a
|
||||
// list of cases/defaults, or a block node) could contain hoisted
|
||||
// declarations.
|
||||
case PNK_SWITCH:
|
||||
MOZ_ASSERT(node->isArity(PN_BINARY));
|
||||
return ContainsHoistedDeclaration(cx, node->pn_right, result);
|
||||
|
||||
// A case/default node's right half is its statements. A default node's
|
||||
// left half is null; a case node's left half is its expression.
|
||||
case PNK_DEFAULT:
|
||||
MOZ_ASSERT(!node->pn_left);
|
||||
case PNK_CASE:
|
||||
MOZ_ASSERT(node->isArity(PN_BINARY));
|
||||
return ContainsHoistedDeclaration(cx, node->pn_right, result);
|
||||
|
||||
// PNK_SEQ has two purposes.
|
||||
//
|
||||
// The first is to prepend destructuring operations to the body of a
|
||||
// deprecated function expression closure: irrelevant here, as this
|
||||
// function doesn't recur into PNK_FUNCTION, and this method's sole
|
||||
// caller acts upon statements nested in if-statements not found in
|
||||
// destructuring operations.
|
||||
//
|
||||
// The second is to provide a place for a hoisted declaration to go, in
|
||||
// the bizarre for-in/of loops that have as target a declaration with an
|
||||
// assignment, e.g. |for (var i = 0 in expr)|. This case is sadly still
|
||||
// relevant, so we can't banish this ParseNodeKind to the unreachable
|
||||
// list and must check every list member.
|
||||
case PNK_SEQ:
|
||||
return ListContainsHoistedDeclaration(cx, &node->as<ListNode>(), result);
|
||||
|
||||
case PNK_FOR: {
|
||||
MOZ_ASSERT(node->isArity(PN_BINARY));
|
||||
|
||||
ParseNode *loopHead = node->pn_left;
|
||||
MOZ_ASSERT(loopHead->isKind(PNK_FORHEAD) ||
|
||||
loopHead->isKind(PNK_FORIN) ||
|
||||
loopHead->isKind(PNK_FOROF));
|
||||
|
||||
if (loopHead->isKind(PNK_FORHEAD)) {
|
||||
// for (init?; cond?; update?), with only init possibly containing
|
||||
// a hoisted declaration. (Note: a lexical-declaration |init| is
|
||||
// (at present) hoisted in SpiderMonkey parlance -- but such
|
||||
// hoisting doesn't extend outside of this statement, so it is not
|
||||
// hoisting in the sense meant by ContainsHoistedDeclaration.)
|
||||
MOZ_ASSERT(loopHead->isArity(PN_TERNARY));
|
||||
|
||||
ParseNode *init = loopHead->pn_kid1;
|
||||
if (init && init->isKind(PNK_VAR)) {
|
||||
*result = true;
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
MOZ_ASSERT(loopHead->isKind(PNK_FORIN) || loopHead->isKind(PNK_FOROF));
|
||||
|
||||
// for each? (target in ...), where only target may introduce
|
||||
// hoisted declarations.
|
||||
//
|
||||
// -- or --
|
||||
//
|
||||
// for (target of ...), where only target may introduce hoisted
|
||||
// declarations.
|
||||
//
|
||||
// Either way, if |target| contains a declaration, it's either
|
||||
// |loopHead|'s first kid, *or* that declaration was hoisted to
|
||||
// become a child of an ancestral PNK_SEQ node. The former case we
|
||||
// detect here. The latter case is handled by this method
|
||||
// recurring on PNK_SEQ, above.
|
||||
MOZ_ASSERT(loopHead->isArity(PN_TERNARY));
|
||||
|
||||
ParseNode *decl = loopHead->pn_kid1;
|
||||
if (decl && decl->isKind(PNK_VAR)) {
|
||||
*result = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PN_TERNARY:
|
||||
if (!ContainsVarOrConst(cx, pn->pn_kid1, resultp))
|
||||
return false;
|
||||
if (*resultp)
|
||||
return true;
|
||||
if (!ContainsVarOrConst(cx, pn->pn_kid2, resultp))
|
||||
return false;
|
||||
if (*resultp)
|
||||
return true;
|
||||
return ContainsVarOrConst(cx, pn->pn_kid3, resultp);
|
||||
ParseNode *loopBody = node->pn_right;
|
||||
return ContainsHoistedDeclaration(cx, loopBody, result);
|
||||
}
|
||||
|
||||
case PN_BINARY:
|
||||
case PN_BINARY_OBJ:
|
||||
// Limit recursion if pn is a binary expression, which can't contain a
|
||||
// var statement.
|
||||
if (!pn->isOp(JSOP_NOP)) {
|
||||
*resultp = nullptr;
|
||||
return true;
|
||||
}
|
||||
if (!ContainsVarOrConst(cx, pn->pn_left, resultp))
|
||||
return false;
|
||||
if (*resultp)
|
||||
return true;
|
||||
return ContainsVarOrConst(cx, pn->pn_right, resultp);
|
||||
case PNK_LETBLOCK: {
|
||||
MOZ_ASSERT(node->isArity(PN_BINARY));
|
||||
MOZ_ASSERT(node->pn_left->isKind(PNK_LET));
|
||||
MOZ_ASSERT(node->pn_right->isKind(PNK_LEXICALSCOPE));
|
||||
return ContainsHoistedDeclaration(cx, node->pn_right, result);
|
||||
}
|
||||
|
||||
case PN_UNARY:
|
||||
if (!pn->isOp(JSOP_NOP)) {
|
||||
*resultp = nullptr;
|
||||
return true;
|
||||
}
|
||||
return ContainsVarOrConst(cx, pn->pn_kid, resultp);
|
||||
case PNK_LEXICALSCOPE: {
|
||||
MOZ_ASSERT(node->isArity(PN_NAME));
|
||||
ParseNode *expr = node->pn_expr;
|
||||
|
||||
case PN_NAME:
|
||||
return ContainsVarOrConst(cx, pn->maybeExpr(), resultp);
|
||||
if (expr->isKind(PNK_FOR))
|
||||
return ContainsHoistedDeclaration(cx, expr, result);
|
||||
|
||||
default:;
|
||||
MOZ_ASSERT(expr->isKind(PNK_STATEMENTLIST));
|
||||
return ListContainsHoistedDeclaration(cx, &node->pn_expr->as<ListNode>(), result);
|
||||
}
|
||||
|
||||
// List nodes with all non-null children.
|
||||
case PNK_STATEMENTLIST:
|
||||
return ListContainsHoistedDeclaration(cx, &node->as<ListNode>(), result);
|
||||
|
||||
// Grammar sub-components that should never be reached directly by this
|
||||
// method, because some parent component should have asserted itself.
|
||||
case PNK_COMPUTED_NAME:
|
||||
case PNK_SPREAD:
|
||||
case PNK_MUTATEPROTO:
|
||||
case PNK_COLON:
|
||||
case PNK_SHORTHAND:
|
||||
case PNK_CONDITIONAL:
|
||||
case PNK_TYPEOF:
|
||||
case PNK_VOID:
|
||||
case PNK_NOT:
|
||||
case PNK_BITNOT:
|
||||
case PNK_DELETE:
|
||||
case PNK_POS:
|
||||
case PNK_NEG:
|
||||
case PNK_PREINCREMENT:
|
||||
case PNK_POSTINCREMENT:
|
||||
case PNK_PREDECREMENT:
|
||||
case PNK_POSTDECREMENT:
|
||||
case PNK_OR:
|
||||
case PNK_AND:
|
||||
case PNK_BITOR:
|
||||
case PNK_BITXOR:
|
||||
case PNK_BITAND:
|
||||
case PNK_STRICTEQ:
|
||||
case PNK_EQ:
|
||||
case PNK_STRICTNE:
|
||||
case PNK_NE:
|
||||
case PNK_LT:
|
||||
case PNK_LE:
|
||||
case PNK_GT:
|
||||
case PNK_GE:
|
||||
case PNK_INSTANCEOF:
|
||||
case PNK_IN:
|
||||
case PNK_LSH:
|
||||
case PNK_RSH:
|
||||
case PNK_URSH:
|
||||
case PNK_ADD:
|
||||
case PNK_SUB:
|
||||
case PNK_STAR:
|
||||
case PNK_DIV:
|
||||
case PNK_MOD:
|
||||
case PNK_ASSIGN:
|
||||
case PNK_ADDASSIGN:
|
||||
case PNK_SUBASSIGN:
|
||||
case PNK_BITORASSIGN:
|
||||
case PNK_BITXORASSIGN:
|
||||
case PNK_BITANDASSIGN:
|
||||
case PNK_LSHASSIGN:
|
||||
case PNK_RSHASSIGN:
|
||||
case PNK_URSHASSIGN:
|
||||
case PNK_MULASSIGN:
|
||||
case PNK_DIVASSIGN:
|
||||
case PNK_MODASSIGN:
|
||||
case PNK_COMMA:
|
||||
case PNK_ARRAY:
|
||||
case PNK_OBJECT:
|
||||
case PNK_DOT:
|
||||
case PNK_ELEM:
|
||||
case PNK_CALL:
|
||||
case PNK_NAME:
|
||||
case PNK_TEMPLATE_STRING:
|
||||
case PNK_TEMPLATE_STRING_LIST:
|
||||
case PNK_TAGGED_TEMPLATE:
|
||||
case PNK_CALLSITEOBJ:
|
||||
case PNK_STRING:
|
||||
case PNK_REGEXP:
|
||||
case PNK_TRUE:
|
||||
case PNK_FALSE:
|
||||
case PNK_NULL:
|
||||
case PNK_THIS:
|
||||
case PNK_LETEXPR:
|
||||
case PNK_ELISION:
|
||||
case PNK_NUMBER:
|
||||
case PNK_NEW:
|
||||
case PNK_GENERATOR:
|
||||
case PNK_GENEXP:
|
||||
case PNK_ARRAYCOMP:
|
||||
case PNK_ARGSBODY:
|
||||
case PNK_CATCHLIST:
|
||||
case PNK_CATCH:
|
||||
case PNK_FORIN:
|
||||
case PNK_FOROF:
|
||||
case PNK_FORHEAD:
|
||||
MOZ_CRASH("ContainsHoistedDeclaration should have indicated false on "
|
||||
"some parent node without recurring to test this node");
|
||||
|
||||
case PNK_GLOBALCONST:
|
||||
MOZ_CRASH("ContainsHoistedDeclaration is only called on nested nodes where "
|
||||
"globalconst nodes should never have been generated");
|
||||
|
||||
case PNK_LIMIT: // invalid sentinel value
|
||||
MOZ_CRASH("unexpected PNK_LIMIT in node");
|
||||
}
|
||||
*resultp = nullptr;
|
||||
return true;
|
||||
|
||||
MOZ_CRASH("invalid node kind");
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -424,7 +750,7 @@ Fold(ExclusiveContext *cx, ParseNode **pnp,
|
|||
// with node indicating a different syntactic form; |delete x| is not
|
||||
// the same as |delete (true && x)|. See bug 888002.
|
||||
//
|
||||
// pn is the immediate child in question. Its descendents were already
|
||||
// pn is the immediate child in question. Its descendants were already
|
||||
// constant-folded above, so we're done.
|
||||
if (sc == SyntacticContext::Delete)
|
||||
return true;
|
||||
|
|
@ -432,15 +758,19 @@ Fold(ExclusiveContext *cx, ParseNode **pnp,
|
|||
switch (pn->getKind()) {
|
||||
case PNK_IF:
|
||||
{
|
||||
ParseNode *decl;
|
||||
if (!ContainsVarOrConst(cx, pn2, &decl))
|
||||
return false;
|
||||
if (decl)
|
||||
break;
|
||||
if (!ContainsVarOrConst(cx, pn3, &decl))
|
||||
return false;
|
||||
if (decl)
|
||||
break;
|
||||
bool result;
|
||||
if (ParseNode *consequent = pn2) {
|
||||
if (!ContainsHoistedDeclaration(cx, consequent, &result))
|
||||
return false;
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
if (ParseNode *alternative = pn3) {
|
||||
if (!ContainsHoistedDeclaration(cx, alternative, &result))
|
||||
return false;
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* FALL THROUGH */
|
||||
|
||||
|
|
@ -495,92 +825,47 @@ Fold(ExclusiveContext *cx, ParseNode **pnp,
|
|||
case PNK_OR:
|
||||
case PNK_AND:
|
||||
if (sc == SyntacticContext::Condition) {
|
||||
if (pn->isArity(PN_LIST)) {
|
||||
ParseNode **listp = &pn->pn_head;
|
||||
MOZ_ASSERT(*listp == pn1);
|
||||
uint32_t orig = pn->pn_count;
|
||||
do {
|
||||
Truthiness t = Boolish(pn1);
|
||||
if (t == Unknown) {
|
||||
listp = &pn1->pn_next;
|
||||
continue;
|
||||
}
|
||||
if ((t == Truthy) == pn->isKind(PNK_OR)) {
|
||||
for (pn2 = pn1->pn_next; pn2; pn2 = pn3) {
|
||||
pn3 = pn2->pn_next;
|
||||
handler.freeTree(pn2);
|
||||
--pn->pn_count;
|
||||
}
|
||||
pn1->pn_next = nullptr;
|
||||
break;
|
||||
}
|
||||
MOZ_ASSERT((t == Truthy) == pn->isKind(PNK_AND));
|
||||
if (pn->pn_count == 1)
|
||||
break;
|
||||
*listp = pn1->pn_next;
|
||||
handler.freeTree(pn1);
|
||||
--pn->pn_count;
|
||||
} while ((pn1 = *listp) != nullptr);
|
||||
|
||||
// We may have to change arity from LIST to BINARY.
|
||||
pn1 = pn->pn_head;
|
||||
if (pn->pn_count == 2) {
|
||||
pn2 = pn1->pn_next;
|
||||
pn1->pn_next = nullptr;
|
||||
MOZ_ASSERT(!pn2->pn_next);
|
||||
pn->setArity(PN_BINARY);
|
||||
pn->pn_left = pn1;
|
||||
pn->pn_right = pn2;
|
||||
} else if (pn->pn_count == 1) {
|
||||
ReplaceNode(pnp, pn1);
|
||||
pn = pn1;
|
||||
} else if (orig != pn->pn_count) {
|
||||
// Adjust list tail.
|
||||
pn2 = pn1->pn_next;
|
||||
for (; pn1; pn2 = pn1, pn1 = pn1->pn_next)
|
||||
;
|
||||
pn->pn_tail = &pn2->pn_next;
|
||||
}
|
||||
} else {
|
||||
ParseNode **listp = &pn->pn_head;
|
||||
MOZ_ASSERT(*listp == pn1);
|
||||
uint32_t orig = pn->pn_count;
|
||||
do {
|
||||
Truthiness t = Boolish(pn1);
|
||||
if (t != Unknown) {
|
||||
if ((t == Truthy) == pn->isKind(PNK_OR)) {
|
||||
handler.freeTree(pn2);
|
||||
ReplaceNode(pnp, pn1);
|
||||
pn = pn1;
|
||||
} else {
|
||||
MOZ_ASSERT((t == Truthy) == pn->isKind(PNK_AND));
|
||||
handler.freeTree(pn1);
|
||||
ReplaceNode(pnp, pn2);
|
||||
pn = pn2;
|
||||
}
|
||||
if (t == Unknown) {
|
||||
listp = &pn1->pn_next;
|
||||
continue;
|
||||
}
|
||||
if ((t == Truthy) == pn->isKind(PNK_OR)) {
|
||||
for (pn2 = pn1->pn_next; pn2; pn2 = pn3) {
|
||||
pn3 = pn2->pn_next;
|
||||
handler.freeTree(pn2);
|
||||
--pn->pn_count;
|
||||
}
|
||||
pn1->pn_next = nullptr;
|
||||
break;
|
||||
}
|
||||
MOZ_ASSERT((t == Truthy) == pn->isKind(PNK_AND));
|
||||
if (pn->pn_count == 1)
|
||||
break;
|
||||
*listp = pn1->pn_next;
|
||||
handler.freeTree(pn1);
|
||||
--pn->pn_count;
|
||||
} while ((pn1 = *listp) != nullptr);
|
||||
|
||||
// We may have to replace a one-element list with its element.
|
||||
pn1 = pn->pn_head;
|
||||
if (pn->pn_count == 1) {
|
||||
ReplaceNode(pnp, pn1);
|
||||
pn = pn1;
|
||||
} else if (orig != pn->pn_count) {
|
||||
// Adjust list tail.
|
||||
pn2 = pn1->pn_next;
|
||||
for (; pn1; pn2 = pn1, pn1 = pn1->pn_next)
|
||||
continue;
|
||||
pn->pn_tail = &pn2->pn_next;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PNK_SUBASSIGN:
|
||||
case PNK_BITORASSIGN:
|
||||
case PNK_BITXORASSIGN:
|
||||
case PNK_BITANDASSIGN:
|
||||
case PNK_LSHASSIGN:
|
||||
case PNK_RSHASSIGN:
|
||||
case PNK_URSHASSIGN:
|
||||
case PNK_MULASSIGN:
|
||||
case PNK_DIVASSIGN:
|
||||
case PNK_MODASSIGN:
|
||||
/*
|
||||
* Compound operators such as *= should be subject to folding, in case
|
||||
* the left-hand side is constant, and so that the decompiler produces
|
||||
* the same string that you get from decompiling a script or function
|
||||
* compiled from that same string. += is special and so must be
|
||||
* handled below.
|
||||
*/
|
||||
goto do_binary_op;
|
||||
|
||||
case PNK_ADDASSIGN:
|
||||
MOZ_ASSERT(pn->isOp(JSOP_ADD));
|
||||
/* FALL THROUGH */
|
||||
case PNK_ADD:
|
||||
if (pn->isArity(PN_LIST)) {
|
||||
bool folded = false;
|
||||
|
|
@ -699,7 +984,13 @@ Fold(ExclusiveContext *cx, ParseNode **pnp,
|
|||
}
|
||||
|
||||
/* Can't concatenate string literals, let's try numbers. */
|
||||
goto do_binary_op;
|
||||
if (!FoldType(cx, pn1, PNK_NUMBER) || !FoldType(cx, pn2, PNK_NUMBER))
|
||||
return false;
|
||||
if (pn1->isKind(PNK_NUMBER) && pn2->isKind(PNK_NUMBER)) {
|
||||
if (!FoldBinaryNumeric(cx, pn->getOp(), pn1, pn2, pn))
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case PNK_SUB:
|
||||
case PNK_STAR:
|
||||
|
|
@ -708,39 +999,27 @@ Fold(ExclusiveContext *cx, ParseNode **pnp,
|
|||
case PNK_URSH:
|
||||
case PNK_DIV:
|
||||
case PNK_MOD:
|
||||
do_binary_op:
|
||||
if (pn->isArity(PN_LIST)) {
|
||||
MOZ_ASSERT(pn->pn_count > 2);
|
||||
for (pn2 = pn1; pn2; pn2 = pn2->pn_next) {
|
||||
if (!FoldType(cx, pn2, PNK_NUMBER))
|
||||
return false;
|
||||
}
|
||||
for (pn2 = pn1; pn2; pn2 = pn2->pn_next) {
|
||||
/* XXX fold only if all operands convert to number */
|
||||
if (!pn2->isKind(PNK_NUMBER))
|
||||
break;
|
||||
}
|
||||
if (!pn2) {
|
||||
JSOp op = pn->getOp();
|
||||
|
||||
pn2 = pn1->pn_next;
|
||||
pn3 = pn2->pn_next;
|
||||
if (!FoldBinaryNumeric(cx, op, pn1, pn2, pn))
|
||||
return false;
|
||||
while ((pn2 = pn3) != nullptr) {
|
||||
pn3 = pn2->pn_next;
|
||||
if (!FoldBinaryNumeric(cx, op, pn, pn2, pn))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
MOZ_ASSERT(pn->isArity(PN_BINARY));
|
||||
if (!FoldType(cx, pn1, PNK_NUMBER) ||
|
||||
!FoldType(cx, pn2, PNK_NUMBER)) {
|
||||
MOZ_ASSERT(pn->getArity() == PN_LIST);
|
||||
MOZ_ASSERT(pn->pn_count >= 2);
|
||||
for (pn2 = pn1; pn2; pn2 = pn2->pn_next) {
|
||||
if (!FoldType(cx, pn2, PNK_NUMBER))
|
||||
return false;
|
||||
}
|
||||
if (pn1->isKind(PNK_NUMBER) && pn2->isKind(PNK_NUMBER)) {
|
||||
if (!FoldBinaryNumeric(cx, pn->getOp(), pn1, pn2, pn))
|
||||
}
|
||||
for (pn2 = pn1; pn2; pn2 = pn2->pn_next) {
|
||||
/* XXX fold only if all operands convert to number */
|
||||
if (!pn2->isKind(PNK_NUMBER))
|
||||
break;
|
||||
}
|
||||
if (!pn2) {
|
||||
JSOp op = pn->getOp();
|
||||
|
||||
pn2 = pn1->pn_next;
|
||||
pn3 = pn2->pn_next;
|
||||
if (!FoldBinaryNumeric(cx, op, pn1, pn2, pn))
|
||||
return false;
|
||||
while ((pn2 = pn3) != nullptr) {
|
||||
pn3 = pn2->pn_next;
|
||||
if (!FoldBinaryNumeric(cx, op, pn, pn2, pn))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@ class FullParseHandler
|
|||
{
|
||||
ParseNodeAllocator allocator;
|
||||
TokenStream &tokenStream;
|
||||
bool foldConstants;
|
||||
|
||||
ParseNode *allocParseNode(size_t size) {
|
||||
MOZ_ASSERT(size == sizeof(ParseNode));
|
||||
|
|
@ -71,11 +70,10 @@ class FullParseHandler
|
|||
typedef Definition *DefinitionNode;
|
||||
|
||||
FullParseHandler(ExclusiveContext *cx, LifoAlloc &alloc,
|
||||
TokenStream &tokenStream, bool foldConstants,
|
||||
Parser<SyntaxParseHandler> *syntaxParser, LazyScript *lazyOuterFunction)
|
||||
TokenStream &tokenStream, Parser<SyntaxParseHandler> *syntaxParser,
|
||||
LazyScript *lazyOuterFunction)
|
||||
: allocator(cx, alloc),
|
||||
tokenStream(tokenStream),
|
||||
foldConstants(foldConstants),
|
||||
lazyOuterFunction_(lazyOuterFunction),
|
||||
lazyInnerFunctionIndex(0),
|
||||
syntaxParser(syntaxParser)
|
||||
|
|
@ -217,10 +215,10 @@ class FullParseHandler
|
|||
TokenPos pos(left->pn_pos.begin, right->pn_pos.end);
|
||||
return new_<BinaryNode>(kind, op, pos, left, right);
|
||||
}
|
||||
ParseNode *newBinaryOrAppend(ParseNodeKind kind, ParseNode *left, ParseNode *right,
|
||||
ParseContext<FullParseHandler> *pc, JSOp op = JSOP_NOP)
|
||||
ParseNode *appendOrCreateList(ParseNodeKind kind, ParseNode *left, ParseNode *right,
|
||||
ParseContext<FullParseHandler> *pc, JSOp op = JSOP_NOP)
|
||||
{
|
||||
return ParseNode::newBinaryOrAppend(kind, op, left, right, this, pc, foldConstants);
|
||||
return ParseNode::appendOrCreateList(kind, op, left, right, this, pc);
|
||||
}
|
||||
|
||||
ParseNode *newTernary(ParseNodeKind kind,
|
||||
|
|
@ -540,10 +538,26 @@ class FullParseHandler
|
|||
block->pn_expr = body;
|
||||
}
|
||||
|
||||
ParseNode *newLetExpression(ParseNode *vars, ParseNode *block, const TokenPos &pos) {
|
||||
ParseNode *letExpr = newBinary(PNK_LETEXPR, vars, block);
|
||||
if (!letExpr)
|
||||
return nullptr;
|
||||
letExpr->pn_pos = pos;
|
||||
return letExpr;
|
||||
}
|
||||
|
||||
ParseNode *newLetBlock(ParseNode *vars, ParseNode *block, const TokenPos &pos) {
|
||||
ParseNode *letBlock = newBinary(PNK_LETBLOCK, vars, block);
|
||||
if (!letBlock)
|
||||
return nullptr;
|
||||
letBlock->pn_pos = pos;
|
||||
return letBlock;
|
||||
}
|
||||
|
||||
ParseNode *newAssignment(ParseNodeKind kind, ParseNode *lhs, ParseNode *rhs,
|
||||
ParseContext<FullParseHandler> *pc, JSOp op)
|
||||
{
|
||||
return newBinaryOrAppend(kind, lhs, rhs, pc, op);
|
||||
return newBinary(kind, lhs, rhs, op);
|
||||
}
|
||||
|
||||
bool isUnparenthesizedYieldExpression(ParseNode *node) {
|
||||
|
|
@ -600,6 +614,9 @@ class FullParseHandler
|
|||
return new_<ListNode>(kind, op, kid);
|
||||
}
|
||||
|
||||
ParseNode *newCatchList() {
|
||||
return new_<ListNode>(PNK_CATCHLIST, JSOP_NOP, pos());
|
||||
}
|
||||
|
||||
ParseNode *newCommaExpressionList(ParseNode *kid) {
|
||||
return newList(PNK_COMMA, kid, JSOP_NOP);
|
||||
|
|
|
|||
|
|
@ -245,54 +245,36 @@ ParseNodeAllocator::allocNode()
|
|||
}
|
||||
|
||||
ParseNode *
|
||||
ParseNode::append(ParseNodeKind kind, JSOp op, ParseNode *left, ParseNode *right,
|
||||
FullParseHandler *handler)
|
||||
ParseNode::appendOrCreateList(ParseNodeKind kind, JSOp op, ParseNode *left, ParseNode *right,
|
||||
FullParseHandler *handler, ParseContext<FullParseHandler> *pc)
|
||||
{
|
||||
if (!left || !right)
|
||||
return nullptr;
|
||||
// The asm.js specification is written in ECMAScript grammar terms that
|
||||
// specify *only* a binary tree. It's a royal pain to implement the asm.js
|
||||
// spec to act upon n-ary lists as created below. So for asm.js, form a
|
||||
// binary tree of lists exactly as ECMAScript would by skipping the
|
||||
// following optimization.
|
||||
if (!pc->useAsmOrInsideUseAsm()) {
|
||||
// Left-associative trees of a given operator (e.g. |a + b + c|) are
|
||||
// binary trees in the spec: (+ (+ a b) c) in Lisp terms. Recursively
|
||||
// processing such a tree, exactly implemented that way, would blow the
|
||||
// the stack. We use a list node that uses O(1) stack to represent
|
||||
// such operations: (+ a b c).
|
||||
if (left->isKind(kind) && left->isOp(op) && (js_CodeSpec[op].format & JOF_LEFTASSOC)) {
|
||||
ListNode *list = &left->as<ListNode>();
|
||||
|
||||
MOZ_ASSERT(left->isKind(kind) && left->isOp(op) && (js_CodeSpec[op].format & JOF_LEFTASSOC));
|
||||
list->append(right);
|
||||
list->pn_pos.end = right->pn_pos.end;
|
||||
|
||||
ListNode *list;
|
||||
if (left->pn_arity == PN_LIST) {
|
||||
list = &left->as<ListNode>();
|
||||
} else {
|
||||
ParseNode *pn1 = left->pn_left, *pn2 = left->pn_right;
|
||||
list = handler->new_<ListNode>(kind, op, pn1);
|
||||
if (!list)
|
||||
return nullptr;
|
||||
list->append(pn2);
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
list->append(right);
|
||||
list->pn_pos.end = right->pn_pos.end;
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
ParseNode *
|
||||
ParseNode::newBinaryOrAppend(ParseNodeKind kind, JSOp op, ParseNode *left, ParseNode *right,
|
||||
FullParseHandler *handler, ParseContext<FullParseHandler> *pc,
|
||||
bool foldConstants)
|
||||
{
|
||||
if (!left || !right)
|
||||
ParseNode *list = handler->new_<ListNode>(kind, op, left);
|
||||
if (!list)
|
||||
return nullptr;
|
||||
|
||||
/*
|
||||
* Ensure that the parse tree is faithful to the source when "use asm" (for
|
||||
* the purpose of type checking).
|
||||
*/
|
||||
if (pc->useAsmOrInsideUseAsm())
|
||||
return handler->new_<BinaryNode>(kind, op, left, right);
|
||||
|
||||
/*
|
||||
* Flatten a left-associative (left-heavy) tree of a given operator into
|
||||
* a list to reduce js::FoldConstants and js::frontend::EmitTree recursion.
|
||||
*/
|
||||
if (left->isKind(kind) && left->isOp(op) && (js_CodeSpec[op].format & JOF_LEFTASSOC))
|
||||
return append(kind, op, left, right, handler);
|
||||
|
||||
return handler->new_<BinaryNode>(kind, op, left, right);
|
||||
list->append(right);
|
||||
return list;
|
||||
}
|
||||
|
||||
const char *
|
||||
|
|
|
|||
|
|
@ -103,7 +103,6 @@ class UpvarCookie
|
|||
F(THIS) \
|
||||
F(FUNCTION) \
|
||||
F(IF) \
|
||||
F(ELSE) \
|
||||
F(SWITCH) \
|
||||
F(CASE) \
|
||||
F(DEFAULT) \
|
||||
|
|
@ -122,7 +121,6 @@ class UpvarCookie
|
|||
F(TRY) \
|
||||
F(CATCH) \
|
||||
F(CATCHLIST) \
|
||||
F(FINALLY) \
|
||||
F(THROW) \
|
||||
F(DEBUGGER) \
|
||||
F(GENERATOR) \
|
||||
|
|
@ -133,6 +131,8 @@ class UpvarCookie
|
|||
F(ARRAYPUSH) \
|
||||
F(LEXICALSCOPE) \
|
||||
F(LET) \
|
||||
F(LETBLOCK) \
|
||||
F(LETEXPR) \
|
||||
F(IMPORT) \
|
||||
F(IMPORT_SPEC_LIST) \
|
||||
F(IMPORT_SPEC) \
|
||||
|
|
@ -287,10 +287,11 @@ enum ParseNodeKind
|
|||
* pn_kid3: update expr after second ';' or nullptr
|
||||
* PNK_THROW unary pn_op: JSOP_THROW, pn_kid: exception
|
||||
* PNK_TRY ternary pn_kid1: try block
|
||||
* pn_kid2: null or PNK_CATCHLIST list of
|
||||
* PNK_LEXICALSCOPE nodes, each with pn_expr pointing
|
||||
* to a PNK_CATCH node
|
||||
* pn_kid2: null or PNK_CATCHLIST list
|
||||
* pn_kid3: null or finally block
|
||||
* PNK_CATCHLIST list pn_head: list of PNK_LEXICALSCOPE nodes, one per
|
||||
* catch-block, each with pn_expr pointing
|
||||
* to a PNK_CATCH node
|
||||
* PNK_CATCH ternary pn_kid1: PNK_NAME, PNK_ARRAY, or PNK_OBJECT catch var node
|
||||
* (PNK_ARRAY or PNK_OBJECT if destructuring)
|
||||
* pn_kid2: null or the catch guard expression
|
||||
|
|
@ -509,6 +510,11 @@ class ParseNode
|
|||
return PNK_ASSIGNMENT_START <= kind && kind <= PNK_ASSIGNMENT_LAST;
|
||||
}
|
||||
|
||||
bool isBinaryOperation() const {
|
||||
ParseNodeKind kind = getKind();
|
||||
return PNK_BINOP_FIRST <= kind && kind <= PNK_BINOP_LAST;
|
||||
}
|
||||
|
||||
/* Boolean attributes. */
|
||||
bool isInParens() const { return pn_parens; }
|
||||
bool isLikelyIIFE() const { return isInParens(); }
|
||||
|
|
@ -640,21 +646,12 @@ class ParseNode
|
|||
|
||||
public:
|
||||
/*
|
||||
* Append right to left, forming a list node. |left| must have the given
|
||||
* kind and op, and op must be left-associative.
|
||||
* If |left| is a list of the given kind/left-associative op, append
|
||||
* |right| to it and return |left|. Otherwise return a [left, right] list.
|
||||
*/
|
||||
static ParseNode *
|
||||
append(ParseNodeKind tt, JSOp op, ParseNode *left, ParseNode *right, FullParseHandler *handler);
|
||||
|
||||
/*
|
||||
* Either append right to left, if left meets the conditions necessary to
|
||||
* append (see append), or form a binary node whose children are right and
|
||||
* left.
|
||||
*/
|
||||
static ParseNode *
|
||||
newBinaryOrAppend(ParseNodeKind kind, JSOp op, ParseNode *left, ParseNode *right,
|
||||
FullParseHandler *handler, ParseContext<FullParseHandler> *pc,
|
||||
bool foldConstants);
|
||||
appendOrCreateList(ParseNodeKind kind, JSOp op, ParseNode *left, ParseNode *right,
|
||||
FullParseHandler *handler, ParseContext<FullParseHandler> *pc);
|
||||
|
||||
inline PropertyName *name() const;
|
||||
inline JSAtom *atom() const;
|
||||
|
|
|
|||
|
|
@ -516,7 +516,7 @@ Parser<ParseHandler>::Parser(ExclusiveContext *cx, LifoAlloc *alloc,
|
|||
sawDeprecatedExpressionClosure(false),
|
||||
sawDeprecatedLetBlock(false),
|
||||
sawDeprecatedLetExpression(false),
|
||||
handler(cx, *alloc, tokenStream, foldConstants, syntaxParser, lazyOuterFunction)
|
||||
handler(cx, *alloc, tokenStream, syntaxParser, lazyOuterFunction)
|
||||
{
|
||||
{
|
||||
AutoLockForExclusiveAccess lock(cx);
|
||||
|
|
@ -1230,20 +1230,10 @@ struct BindData
|
|||
|
||||
template <typename ParseHandler>
|
||||
JSFunction *
|
||||
Parser<ParseHandler>::newFunction(GenericParseContext *pc, HandleAtom atom,
|
||||
FunctionSyntaxKind kind, JSObject *proto)
|
||||
Parser<ParseHandler>::newFunction(HandleAtom atom, FunctionSyntaxKind kind, JSObject *proto)
|
||||
{
|
||||
MOZ_ASSERT_IF(kind == Statement, atom != nullptr);
|
||||
|
||||
/*
|
||||
* Find the global compilation context in order to pre-set the newborn
|
||||
* function's parent slot to pc->sc->as<GlobalObject>()->scopeChain. If the
|
||||
* global context is a compile-and-go one, we leave the pre-set parent
|
||||
* intact; otherwise we clear parent and proto.
|
||||
*/
|
||||
while (pc->parent)
|
||||
pc = pc->parent;
|
||||
|
||||
RootedFunction fun(context);
|
||||
JSFunction::Flags flags = (kind == Expression)
|
||||
? JSFunction::INTERPRETED_LAMBDA
|
||||
|
|
@ -2189,7 +2179,7 @@ Parser<ParseHandler>::functionDef(HandlePropertyName funName,
|
|||
if (!proto)
|
||||
return null();
|
||||
}
|
||||
RootedFunction fun(context, newFunction(pc, funName, kind, proto));
|
||||
RootedFunction fun(context, newFunction(funName, kind, proto));
|
||||
if (!fun)
|
||||
return null();
|
||||
|
||||
|
|
@ -3632,7 +3622,7 @@ Parser<SyntaxParseHandler>::pushLetScope(HandleStaticBlockObject blockObj, StmtI
|
|||
*/
|
||||
template <typename ParseHandler>
|
||||
typename ParseHandler::Node
|
||||
Parser<ParseHandler>::letBlock(LetContext letContext)
|
||||
Parser<ParseHandler>::deprecatedLetBlockOrExpression(LetContext letContext)
|
||||
{
|
||||
MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_LET));
|
||||
|
||||
|
|
@ -3655,11 +3645,6 @@ Parser<ParseHandler>::letBlock(LetContext letContext)
|
|||
if (!block)
|
||||
return null();
|
||||
|
||||
Node pnlet = handler.newBinary(PNK_LET, vars, block);
|
||||
if (!pnlet)
|
||||
return null();
|
||||
handler.setBeginPosition(pnlet, begin);
|
||||
|
||||
bool needExprStmt = false;
|
||||
if (letContext == LetStatement) {
|
||||
bool matched;
|
||||
|
|
@ -3682,16 +3667,16 @@ Parser<ParseHandler>::letBlock(LetContext letContext)
|
|||
*
|
||||
* See bug 569464.
|
||||
*/
|
||||
if (!report(ParseStrictError, pc->sc->strict, pnlet,
|
||||
JSMSG_STRICT_CODE_LET_EXPR_STMT))
|
||||
if (!reportWithOffset(ParseStrictError, pc->sc->strict, begin,
|
||||
JSMSG_STRICT_CODE_LET_EXPR_STMT))
|
||||
{
|
||||
return null();
|
||||
}
|
||||
|
||||
/*
|
||||
* If this is really an expression in let statement guise, then we
|
||||
* need to wrap the PNK_LET node in a PNK_SEMI node so that we pop
|
||||
* the return value of the expression.
|
||||
* need to wrap the PNK_LETEXPR node in a PNK_SEMI node so that we
|
||||
* pop the return value of the expression.
|
||||
*/
|
||||
needExprStmt = true;
|
||||
letContext = LetExpression;
|
||||
|
|
@ -3721,14 +3706,22 @@ Parser<ParseHandler>::letBlock(LetContext letContext)
|
|||
handler.setLexicalScopeBody(block, expr);
|
||||
PopStatementPC(tokenStream, pc);
|
||||
|
||||
handler.setEndPosition(pnlet, pos().end);
|
||||
TokenPos letPos(begin, pos().end);
|
||||
|
||||
if (needExprStmt) {
|
||||
if (!MatchOrInsertSemicolon(tokenStream))
|
||||
if (letContext == LetExpression) {
|
||||
if (needExprStmt) {
|
||||
if (!MatchOrInsertSemicolon(tokenStream))
|
||||
return null();
|
||||
}
|
||||
|
||||
Node letExpr = handler.newLetExpression(vars, block, letPos);
|
||||
if (!letExpr)
|
||||
return null();
|
||||
return handler.newExprStatement(pnlet, pos().end);
|
||||
|
||||
return needExprStmt ? handler.newExprStatement(letExpr, pos().end) : letExpr;
|
||||
}
|
||||
return pnlet;
|
||||
|
||||
return handler.newLetBlock(vars, block, letPos);
|
||||
}
|
||||
|
||||
template <typename ParseHandler>
|
||||
|
|
@ -3888,7 +3881,7 @@ Parser<ParseHandler>::variables(ParseNodeKind kind, bool *psimple,
|
|||
if (!bindBeforeInitializer && !checkDestructuring(&data, pn2))
|
||||
return null();
|
||||
|
||||
pn2 = handler.newBinaryOrAppend(PNK_ASSIGN, pn2, init, pc);
|
||||
pn2 = handler.newBinary(PNK_ASSIGN, pn2, init);
|
||||
if (!pn2)
|
||||
return null();
|
||||
handler.addList(pn, pn2);
|
||||
|
|
@ -4107,27 +4100,44 @@ Parser<SyntaxParseHandler>::lexicalDeclaration(bool)
|
|||
|
||||
template <>
|
||||
ParseNode *
|
||||
Parser<FullParseHandler>::letStatement()
|
||||
Parser<FullParseHandler>::letDeclarationOrBlock()
|
||||
{
|
||||
handler.disableSyntaxParser();
|
||||
|
||||
/* Check for a let statement or let expression. */
|
||||
ParseNode *pn;
|
||||
TokenKind tt;
|
||||
if (!tokenStream.peekToken(&tt))
|
||||
return null();
|
||||
if (tt == TOK_LP) {
|
||||
pn = letBlock(LetStatement);
|
||||
MOZ_ASSERT_IF(pn, pn->isKind(PNK_LET) || pn->isKind(PNK_SEMI));
|
||||
} else {
|
||||
pn = lexicalDeclaration(/* isConst = */ false);
|
||||
ParseNode *node = deprecatedLetBlockOrExpression(LetStatement);
|
||||
if (!node)
|
||||
return nullptr;
|
||||
|
||||
if (node->isKind(PNK_LETBLOCK)) {
|
||||
MOZ_ASSERT(node->isArity(PN_BINARY));
|
||||
} else {
|
||||
MOZ_ASSERT(node->isKind(PNK_SEMI));
|
||||
MOZ_ASSERT(node->pn_kid->isKind(PNK_LETEXPR));
|
||||
MOZ_ASSERT(node->pn_kid->isArity(PN_BINARY));
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
return pn;
|
||||
|
||||
ParseNode *decl = lexicalDeclaration(/* isConst = */ false);
|
||||
if (!decl)
|
||||
return nullptr;
|
||||
|
||||
// let-declarations at global scope are currently treated as plain old var.
|
||||
// See bug 589199.
|
||||
MOZ_ASSERT(decl->isKind(PNK_LET) || decl->isKind(PNK_VAR));
|
||||
MOZ_ASSERT(decl->isArity(PN_LIST));
|
||||
return decl;
|
||||
}
|
||||
|
||||
template <>
|
||||
SyntaxParseHandler::Node
|
||||
Parser<SyntaxParseHandler>::letStatement()
|
||||
Parser<SyntaxParseHandler>::letDeclarationOrBlock()
|
||||
{
|
||||
JS_ALWAYS_FALSE(abortIfSyntaxParser());
|
||||
return SyntaxParseHandler::NodeFailure;
|
||||
|
|
@ -4665,7 +4675,7 @@ Parser<FullParseHandler>::forStatement()
|
|||
if (!tokenStream.peekToken(&tt))
|
||||
return null();
|
||||
if (tt == TOK_LP) {
|
||||
pn1 = letBlock(LetExpression);
|
||||
pn1 = deprecatedLetBlockOrExpression(LetExpression);
|
||||
} else {
|
||||
isForDecl = true;
|
||||
blockObj = StaticBlockObject::create(context);
|
||||
|
|
@ -4938,11 +4948,7 @@ Parser<FullParseHandler>::forStatement()
|
|||
if (forLetImpliedBlock) {
|
||||
forLetImpliedBlock->pn_expr = forLoop;
|
||||
forLetImpliedBlock->pn_pos = forLoop->pn_pos;
|
||||
ParseNode *let = handler.newBinary(PNK_LET, forLetDecl, forLetImpliedBlock);
|
||||
if (!let)
|
||||
return null();
|
||||
let->pn_pos = forLoop->pn_pos;
|
||||
return let;
|
||||
return handler.newLetBlock(forLetDecl, forLetImpliedBlock, forLoop->pn_pos);
|
||||
}
|
||||
return forLoop;
|
||||
}
|
||||
|
|
@ -5639,7 +5645,7 @@ Parser<ParseHandler>::tryStatement()
|
|||
if (!tokenStream.getToken(&tt))
|
||||
return null();
|
||||
if (tt == TOK_CATCH) {
|
||||
catchList = handler.newList(PNK_CATCH);
|
||||
catchList = handler.newCatchList();
|
||||
if (!catchList)
|
||||
return null();
|
||||
|
||||
|
|
@ -5822,7 +5828,7 @@ Parser<ParseHandler>::statement(bool canHaveDirectives)
|
|||
}
|
||||
|
||||
case TOK_LET:
|
||||
return letStatement();
|
||||
return letDeclarationOrBlock();
|
||||
case TOK_IMPORT:
|
||||
return importDeclaration();
|
||||
case TOK_EXPORT:
|
||||
|
|
@ -6077,7 +6083,7 @@ Parser<ParseHandler>::orExpr1(InvokedPrediction invoked)
|
|||
depth--;
|
||||
ParseNodeKind combiningPnk = kindStack[depth];
|
||||
JSOp combiningOp = BinaryOpParseNodeKindToJSOp(combiningPnk);
|
||||
pn = handler.newBinaryOrAppend(combiningPnk, nodeStack[depth], pn, pc, combiningOp);
|
||||
pn = handler.appendOrCreateList(combiningPnk, nodeStack[depth], pn, pc, combiningOp);
|
||||
if (!pn)
|
||||
return pn;
|
||||
}
|
||||
|
|
@ -7062,7 +7068,7 @@ Parser<ParseHandler>::generatorComprehensionLambda(GeneratorKind comprehensionKi
|
|||
return null();
|
||||
}
|
||||
|
||||
RootedFunction fun(context, newFunction(outerpc, /* atom = */ NullPtr(), Expression, proto));
|
||||
RootedFunction fun(context, newFunction(/* atom = */ NullPtr(), Expression, proto));
|
||||
if (!fun)
|
||||
return null();
|
||||
|
||||
|
|
@ -7911,6 +7917,8 @@ Parser<ParseHandler>::objectLiteral()
|
|||
if (!atom)
|
||||
return null();
|
||||
propname = newNumber(tokenStream.currentToken());
|
||||
if (!propname)
|
||||
return null();
|
||||
break;
|
||||
|
||||
case TOK_LB: {
|
||||
|
|
@ -8066,6 +8074,8 @@ Parser<ParseHandler>::objectLiteral()
|
|||
if (!propname)
|
||||
return null();
|
||||
Node ident = identifierName();
|
||||
if (!ident)
|
||||
return null();
|
||||
if (!handler.addPropertyDefinition(literal, propname, ident, true))
|
||||
return null();
|
||||
} else if (tt == TOK_LP) {
|
||||
|
|
@ -8139,7 +8149,7 @@ Parser<ParseHandler>::primaryExpr(TokenKind tt, InvokedPrediction invoked)
|
|||
return objectLiteral();
|
||||
|
||||
case TOK_LET:
|
||||
return letBlock(LetExpression);
|
||||
return deprecatedLetBlockOrExpression(LetExpression);
|
||||
|
||||
case TOK_LP: {
|
||||
TokenKind next;
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue