merge mozilla-inbound to mozilla-central a=merge

This commit is contained in:
Carsten "Tomcat" Book 2015-02-11 14:58:16 +01:00
commit 1da4eb2ea5
272 changed files with 5871 additions and 3325 deletions

View file

@ -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

View file

@ -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

View file

@ -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;

View file

@ -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) {

View file

@ -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");

View file

@ -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

View file

@ -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");

View file

@ -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();
});

View file

@ -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);
});
}

View file

@ -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) {

View file

@ -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);
}

View file

@ -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);

View file

@ -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;

View file

@ -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;

View file

@ -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;
}

View file

@ -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)) {

View file

@ -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");

View file

@ -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()

View file

@ -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;

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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',

View file

@ -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

View file

@ -677,7 +677,7 @@ VFY_DestroyContext
VFY_End
VFY_Update
VFY_VerifyData
VFY_VerifyDataDirect
VFY_VerifyDataWithAlgorithmID
VFY_VerifyDigestDirect
_SGN_VerifyPKCS1DigestInfo
PK11_PQG_ParamGenV2

View file

@ -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

View file

@ -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"

View file

@ -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()
{

View file

@ -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.

View file

@ -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();

View file

@ -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);
}
}

View file

@ -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();
}

View file

@ -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();
}
}

View file

@ -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);

View file

@ -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

View file

@ -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

View file

@ -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;

View file

@ -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;

View file

@ -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();
}
}

View file

@ -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

View file

@ -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()) {

View file

@ -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

View file

@ -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
{

View file

@ -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)]

View file

@ -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

View file

@ -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);

View file

@ -240,6 +240,8 @@ private:
PLDHashTable mGlobalNames;
PLDHashTable mNavigatorNames;
bool mIsInitialized;
};
#endif /* nsScriptNameSpaceManager_h__ */

View file

@ -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"

View file

@ -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,
});
});

View file

@ -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();
}

View file

@ -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

View file

@ -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;

View file

@ -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.

View file

@ -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);
}
}

View file

@ -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;
}

View file

@ -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)
{

View file

@ -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

View file

@ -499,3 +499,11 @@ nsGenericHTMLFrameElement::AllowCreateFrameLoader()
mFrameLoaderCreationDisallowed = false;
return NS_OK;
}
NS_IMETHODIMP
nsGenericHTMLFrameElement::InitializeBrowserAPI()
{
MOZ_ASSERT(mFrameLoader);
InitBrowserElementAPI();
return NS_OK;
}

View file

@ -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();
};

View file

@ -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;

View file

@ -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);

View file

@ -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;

View file

@ -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

View file

@ -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();
}

View file

@ -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;
}

View file

@ -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:

View file

@ -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

View file

@ -52,7 +52,7 @@ public:
virtual void OpenComplete(GMPErr aStatus, GMPRecord* aRecord) = 0;
};
GMPErr
void
GMPOpenRecord(const std::string& aRecordName,
OpenContinuation* aContinuation);

View file

@ -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;
}

View file

@ -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

View file

@ -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;
}

View file

@ -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;

View file

@ -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]

View file

@ -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>

View file

@ -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;
}

View file

@ -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();
});
});
});
});

View file

@ -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
});
}
}

View file

@ -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;

View file

@ -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);

View file

@ -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;

View file

@ -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;

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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;

View file

@ -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);

View file

@ -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"

View file

@ -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"

View file

@ -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,

View file

@ -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) \

View file

@ -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 */

View file

@ -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)

View file

@ -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)

View file

@ -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) \

View file

@ -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:

View file

@ -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;
}
}

View file

@ -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);

View file

@ -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 *

View file

@ -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;

View file

@ -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