diff --git a/accessible/tests/mochitest/text/test_atcaretoffset.html b/accessible/tests/mochitest/text/test_atcaretoffset.html index 3f0ccfb5f5ad2..330298a62ffb4 100644 --- a/accessible/tests/mochitest/text/test_atcaretoffset.html +++ b/accessible/tests/mochitest/text/test_atcaretoffset.html @@ -414,26 +414,18 @@ [ "words", "", 10, 15, { words: [ 10, 15 ] } ] ] ); - var line2 = [ // " my " - [ "TextBeforeOffset", BOUNDARY_WORD_END, kTodo, kTodo, kTodo ], - [ "TextAfterOffset", BOUNDARY_WORD_END, kTodo, kTodo, kTodo ] - ]; - var line4 = [ // "riend" - [ "TextBeforeOffset", BOUNDARY_WORD_END, kTodo, kTodo, kTodo ], - [ "TextAfterOffset", BOUNDARY_WORD_END, kTodo, kTodo, kTodo ] - ]; - var line5 = [ // " t " + var line4 = [ // "riend " [ "TextBeforeOffset", BOUNDARY_WORD_END, kTodo, kTodo, kTodo ], [ "TextAfterOffset", BOUNDARY_WORD_END, kTodo, kTodo, kTodo ] ]; traverseTextByLines(gQueue, "ta_wrapped", [ [ "hi ", "", 0, 3, { words: [ 0, 2 ] } ], - [ "hello", "", 3, 8, { words: [ 3, 8 ] } ], - [ " my ", "", 8, 12, { words: [ 9, 11 ], lsf: line2 } ], + [ "hello ", "", 3, 9, { words: [ 3, 8 ] } ], + [ "my ", "", 9, 12, { words: [ 9, 11 ] } ], [ "longf", "", 12, 17, { words: [ 12, 17 ] } ], - [ "riend", "", 17, 22, { words: [ 17, 22 ], lsf: line4 } ], - [ " t ", "", 22, 25, { words: [ 23, 24 ], lsf: line5 } ], - [ "sq t", "", 25, 29, { words: [ 25, 27, 28, 29 ] } ] + [ "riend ", "", 17, 23, { words: [ 17, 22 ], lsf: line4 } ], + [ "t sq ", "", 23, 28, { words: [ 23, 24, 25, 27 ] } ], + [ "t", "", 28, 29, { words: [ 28, 29 ] } ] ] ); gQueue.invoke(); // will call SimpleTest.finish(); diff --git a/browser/app/moz.build b/browser/app/moz.build index 68092c7b12303..520ce4425d044 100644 --- a/browser/app/moz.build +++ b/browser/app/moz.build @@ -33,6 +33,9 @@ USE_LIBS += [ 'mozglue', ] +if CONFIG['LIBFUZZER']: + USE_LIBS += [ 'fuzzer' ] + if CONFIG['_MSC_VER']: # Always enter a Windows program through wmain, whether or not we're # a console application. diff --git a/browser/app/nsBrowserApp.cpp b/browser/app/nsBrowserApp.cpp index cbf39686980ea..2afc42ab8fa8a 100644 --- a/browser/app/nsBrowserApp.cpp +++ b/browser/app/nsBrowserApp.cpp @@ -129,6 +129,10 @@ XRE_GetProcessTypeType XRE_GetProcessType; XRE_SetProcessTypeType XRE_SetProcessType; XRE_InitChildProcessType XRE_InitChildProcess; XRE_EnableSameExecutableForContentProcType XRE_EnableSameExecutableForContentProc; +#ifdef LIBFUZZER +XRE_LibFuzzerSetMainType XRE_LibFuzzerSetMain; +XRE_LibFuzzerGetFuncsType XRE_LibFuzzerGetFuncs; +#endif static const nsDynamicFunctionLoad kXULFuncs[] = { { "XRE_GetFileFromPath", (NSFuncPtr*) &XRE_GetFileFromPath }, @@ -143,9 +147,24 @@ static const nsDynamicFunctionLoad kXULFuncs[] = { { "XRE_SetProcessType", (NSFuncPtr*) &XRE_SetProcessType }, { "XRE_InitChildProcess", (NSFuncPtr*) &XRE_InitChildProcess }, { "XRE_EnableSameExecutableForContentProc", (NSFuncPtr*) &XRE_EnableSameExecutableForContentProc }, +#ifdef LIBFUZZER + { "XRE_LibFuzzerSetMain", (NSFuncPtr*) &XRE_LibFuzzerSetMain }, + { "XRE_LibFuzzerGetFuncs", (NSFuncPtr*) &XRE_LibFuzzerGetFuncs }, +#endif { nullptr, nullptr } }; +#ifdef LIBFUZZER +int libfuzzer_main(int argc, char **argv); + +/* This wrapper is used by the libFuzzer main to call into libxul */ + +void libFuzzerGetFuncs(const char* moduleName, LibFuzzerInitFunc* initFunc, + LibFuzzerTestingFunc* testingFunc) { + return XRE_LibFuzzerGetFuncs(moduleName, initFunc, testingFunc); +} +#endif + static int do_main(int argc, char* argv[], char* envp[], nsIFile *xreDirectory) { nsCOMPtr appini; @@ -256,6 +275,11 @@ static int do_main(int argc, char* argv[], char* envp[], nsIFile *xreDirectory) appData.sandboxBrokerServices = brokerServices; #endif +#ifdef LIBFUZZER + if (getenv("LIBFUZZER")) + XRE_LibFuzzerSetMain(argc, argv, libfuzzer_main); +#endif + return XRE_main(argc, argv, &appData, mainFlags); } diff --git a/browser/base/content/aboutDialog.js b/browser/base/content/aboutDialog.js index ef2bf5024486d..569a65adba070 100644 --- a/browser/base/content/aboutDialog.js +++ b/browser/base/content/aboutDialog.js @@ -2,6 +2,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/. */ +"use strict"; + // Services = object with smart getters for common XPCOM services Components.utils.import("resource://gre/modules/Services.jsm"); Components.utils.import("resource://gre/modules/AppConstants.jsm"); @@ -39,19 +41,30 @@ function init(aEvent) } // Include the build ID and display warning if this is an "a#" (nightly or aurora) build + let versionField = document.getElementById("version"); let version = Services.appinfo.version; if (/a\d+$/.test(version)) { let buildID = Services.appinfo.appBuildID; - let buildDate = buildID.slice(0, 4) + "-" + buildID.slice(4, 6) + "-" + buildID.slice(6, 8); - document.getElementById("version").textContent += " (" + buildDate + ")"; + let year = buildID.slice(0, 4); + let month = buildID.slice(4, 6); + let day = buildID.slice(6, 8); + versionField.textContent += ` (${year}-${month}-${day})`; + document.getElementById("experimental").hidden = false; document.getElementById("communityDesc").hidden = true; } + // Append "(32-bit)" or "(64-bit)" build architecture to the version number: + let bundle = Services.strings.createBundle("chrome://browser/locale/browser.properties"); + let archResource = Services.appinfo.is64Bit + ? "aboutDialog.architecture.sixtyFourBit" + : "aboutDialog.architecture.thirtyTwoBit"; + let arch = bundle.GetStringFromName(archResource); + versionField.textContent += ` (${arch})`; + if (AppConstants.MOZ_UPDATER) { gAppUpdater = new appUpdater(); - let defaults = Services.prefs.getDefaultBranch(""); let channelLabel = document.getElementById("currentChannel"); let currentChannelText = document.getElementById("currentChannelText"); channelLabel.value = UpdateUtils.UpdateChannel; diff --git a/browser/base/content/browser.xul b/browser/base/content/browser.xul index 092d1d61e439c..f1eae4fc0b34c 100644 --- a/browser/base/content/browser.xul +++ b/browser/base/content/browser.xul @@ -691,56 +691,55 @@ consumeanchor="identity-box" onclick="PageProxyClickHandler(event);"/> - + + tooltiptext="&urlbar.geolocationBlocked.tooltip;"/> + tooltiptext="&urlbar.webNotificationsBlocked.tooltip;"/> + tooltiptext="&urlbar.cameraBlocked.tooltip;"/> + tooltiptext="&urlbar.indexedDBBlocked.tooltip;"/> + tooltiptext="&urlbar.microphoneBlocked.tooltip;"/> + tooltiptext="&urlbar.screenBlocked.tooltip;"/> @@ -1047,7 +1046,7 @@ - diff --git a/browser/base/content/test/popupNotifications/browser.ini b/browser/base/content/test/popupNotifications/browser.ini index 6003781fad3ae..334c0118bf361 100644 --- a/browser/base/content/test/popupNotifications/browser.ini +++ b/browser/base/content/test/popupNotifications/browser.ini @@ -12,3 +12,5 @@ skip-if = (os == "linux" && (debug || asan)) skip-if = (os == "linux" && (debug || asan)) [browser_popupNotification_4.js] skip-if = (os == "linux" && (debug || asan)) +[browser_popupNotification_checkbox.js] +skip-if = (os == "linux" && (debug || asan)) diff --git a/browser/base/content/test/popupNotifications/browser_popupNotification_checkbox.js b/browser/base/content/test/popupNotifications/browser_popupNotification_checkbox.js new file mode 100644 index 0000000000000..87beec73e2269 --- /dev/null +++ b/browser/base/content/test/popupNotifications/browser_popupNotification_checkbox.js @@ -0,0 +1,197 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +function test() { + waitForExplicitFinish(); + + ok(PopupNotifications, "PopupNotifications object exists"); + ok(PopupNotifications.panel, "PopupNotifications panel exists"); + + setup(); + goNext(); +} + +function checkCheckbox(checkbox, label, checked=false, hidden=false) { + is(checkbox.label, label, "Checkbox should have the correct label"); + is(checkbox.hidden, hidden, "Checkbox should be shown"); + is(checkbox.checked, checked, "Checkbox should be checked by default"); +} + +function checkMainAction(notification, disabled=false) { + let mainAction = notification.button; + let warningLabel = document.getAnonymousElementByAttribute(notification, "class", "popup-notification-warning"); + is(warningLabel.hidden, !disabled, "Warning label should be shown"); + is(mainAction.disabled, disabled, "MainAction should be disabled"); +} + +var gNotification; + +var tests = [ + // Test that passing the checkbox field shows the checkbox. + { id: "show_checkbox", + run: function () { + this.notifyObj = new BasicNotification(this.id); + this.notifyObj.options.checkbox = { + label: "This is a checkbox", + }; + gNotification = showNotification(this.notifyObj); + }, + onShown: function (popup) { + checkPopup(popup, this.notifyObj); + let notification = popup.childNodes[0]; + checkCheckbox(notification.checkbox, "This is a checkbox"); + triggerMainCommand(popup); + }, + onHidden: function () { } + }, + + // Test checkbox being checked by default + { id: "checkbox_checked", + run: function () { + this.notifyObj = new BasicNotification(this.id); + this.notifyObj.options.checkbox = { + label: "Check this", + checked: true, + }; + gNotification = showNotification(this.notifyObj); + }, + onShown: function (popup) { + checkPopup(popup, this.notifyObj); + let notification = popup.childNodes[0]; + checkCheckbox(notification.checkbox, "Check this", true); + triggerMainCommand(popup); + }, + onHidden: function () { } + }, + + // Test checkbox passing the checkbox state on mainAction + { id: "checkbox_passCheckboxChecked_mainAction", + run: function () { + this.notifyObj = new BasicNotification(this.id); + this.notifyObj.mainAction.callback = ({checkboxChecked}) => this.mainActionChecked = checkboxChecked; + this.notifyObj.options.checkbox = { + label: "This is a checkbox", + }; + gNotification = showNotification(this.notifyObj); + }, + onShown: function (popup) { + checkPopup(popup, this.notifyObj); + let notification = popup.childNodes[0]; + let checkbox = notification.checkbox; + checkCheckbox(checkbox, "This is a checkbox"); + EventUtils.synthesizeMouseAtCenter(checkbox, {}); + checkCheckbox(checkbox, "This is a checkbox", true); + triggerMainCommand(popup); + }, + onHidden: function () { + is(this.mainActionChecked, true, "mainAction callback is passed the correct checkbox value"); + } + }, + + // Test checkbox passing the checkbox state on secondaryAction + { id: "checkbox_passCheckboxChecked_secondaryAction", + run: function () { + this.notifyObj = new BasicNotification(this.id); + this.notifyObj.secondaryActions = [{ + label: "Test Secondary", + accessKey: "T", + callback: ({checkboxChecked}) => this.secondaryActionChecked = checkboxChecked, + }]; + this.notifyObj.options.checkbox = { + label: "This is a checkbox", + }; + gNotification = showNotification(this.notifyObj); + }, + onShown: function (popup) { + checkPopup(popup, this.notifyObj); + let notification = popup.childNodes[0]; + let checkbox = notification.checkbox; + checkCheckbox(checkbox, "This is a checkbox"); + EventUtils.synthesizeMouseAtCenter(checkbox, {}); + checkCheckbox(checkbox, "This is a checkbox", true); + triggerSecondaryCommand(popup, 0); + }, + onHidden: function () { + is(this.secondaryActionChecked, true, "secondaryAction callback is passed the correct checkbox value"); + } + }, + + // Test checkbox preserving its state through re-opening the doorhanger + { id: "checkbox_reopen", + run: function () { + this.notifyObj = new BasicNotification(this.id); + this.notifyObj.options.checkbox = { + label: "This is a checkbox", + checkedState: { + disableMainAction: true, + warningLabel: "Testing disable", + }, + }; + gNotification = showNotification(this.notifyObj); + }, + onShown: function (popup) { + checkPopup(popup, this.notifyObj); + let notification = popup.childNodes[0]; + let checkbox = notification.checkbox; + checkCheckbox(checkbox, "This is a checkbox"); + EventUtils.synthesizeMouseAtCenter(checkbox, {}); + dismissNotification(popup); + }, + onHidden: function (popup) { + let icon = document.getElementById("default-notification-icon"); + EventUtils.synthesizeMouseAtCenter(icon, {}); + let notification = popup.childNodes[0]; + let checkbox = notification.checkbox; + checkCheckbox(checkbox, "This is a checkbox", true); + checkMainAction(notification, true); + gNotification.remove(); + } + }, +]; + +// Test checkbox disabling the main action in different combinations +["checkedState", "uncheckedState"].forEach(function (state) { + [true, false].forEach(function (checked) { + tests.push( + { id: `checkbox_disableMainAction_${state}_${checked ? 'checked' : 'unchecked'}`, + run: function () { + this.notifyObj = new BasicNotification(this.id); + this.notifyObj.options.checkbox = { + label: "This is a checkbox", + checked: checked, + [state]: { + disableMainAction: true, + warningLabel: "Testing disable", + }, + }; + gNotification = showNotification(this.notifyObj); + }, + onShown: function (popup) { + checkPopup(popup, this.notifyObj); + let notification = popup.childNodes[0]; + let checkbox = notification.checkbox; + let disabled = (state === "checkedState" && checked) || + (state === "uncheckedState" && !checked); + + checkCheckbox(checkbox, "This is a checkbox", checked); + checkMainAction(notification, disabled); + EventUtils.synthesizeMouseAtCenter(checkbox, {}); + checkCheckbox(checkbox, "This is a checkbox", !checked); + checkMainAction(notification, !disabled); + EventUtils.synthesizeMouseAtCenter(checkbox, {}); + checkCheckbox(checkbox, "This is a checkbox", checked); + checkMainAction(notification, disabled); + + // Unblock the main command if it's currently disabled. + if (disabled) { + EventUtils.synthesizeMouseAtCenter(checkbox, {}); + } + triggerMainCommand(popup); + }, + onHidden: function () { } + } + ); + }); +}); + diff --git a/browser/locales/en-US/chrome/browser/browser.dtd b/browser/locales/en-US/chrome/browser/browser.dtd index f1beee0f4f9d5..519f9fda2acf5 100644 --- a/browser/locales/en-US/chrome/browser/browser.dtd +++ b/browser/locales/en-US/chrome/browser/browser.dtd @@ -206,26 +206,31 @@ These should match what Safari and other Apple applications use on OS X Lion. -- - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/browser/locales/en-US/chrome/browser/browser.properties b/browser/locales/en-US/chrome/browser/browser.properties index cb997cca725a7..04ee8665ee773 100644 --- a/browser/locales/en-US/chrome/browser/browser.properties +++ b/browser/locales/en-US/chrome/browser/browser.properties @@ -745,3 +745,11 @@ decoder.noHWAcceleration.message = To improve video quality, you may need to ins decoder.noHWAccelerationVista.message = To improve video quality, you may need to install Microsoft’s Platform Update Supplement for Windows Vista. permissions.remove.tooltip = Clear this permission and ask again + +# LOCALIZATION NOTE (aboutDialog.architecture.*): +# The sixtyFourBit and thirtyTwoBit strings describe the architecture of the +# current Firefox build: 32-bit or 64-bit. These strings are used in parentheses +# between the Firefox version and the "What's new" link in the About dialog, +# e.g.: "48.0.2 (32-bit) " or "51.0a1 (2016-09-05) (64-bit)". +aboutDialog.architecture.sixtyFourBit = 64-bit +aboutDialog.architecture.thirtyTwoBit = 32-bit diff --git a/browser/modules/webrtcUI.jsm b/browser/modules/webrtcUI.jsm index 57340591e8b95..b6e84c25a0793 100644 --- a/browser/modules/webrtcUI.jsm +++ b/browser/modules/webrtcUI.jsm @@ -347,8 +347,8 @@ function prompt(aBrowser, aRequest) { secondaryActions.unshift({ label: stringBundle.getString("getUserMedia.always.label"), accessKey: stringBundle.getString("getUserMedia.always.accesskey"), - callback: function () { - mainAction.callback(true); + callback: function (aState) { + mainAction.callback(aState, true); } }); } @@ -519,7 +519,7 @@ function prompt(aBrowser, aRequest) { if (!sharingAudio) listDevices(micMenupopup, audioDevices); - this.mainAction.callback = function(aRemember) { + this.mainAction.callback = function(aState, aRemember) { let allowedDevices = []; let perms = Services.perms; if (videoDevices.length) { diff --git a/browser/themes/linux/browser.css b/browser/themes/linux/browser.css index 9eb35973bc5b0..5727da266445e 100644 --- a/browser/themes/linux/browser.css +++ b/browser/themes/linux/browser.css @@ -55,12 +55,11 @@ content: ""; display: -moz-box; -moz-box-ordinal-group: 101; /* tabs toolbar is 100 */ - height: 1px; - background-color: ThreeDShadow; + border-bottom: 1px solid ThreeDShadow; } #navigator-toolbox:-moz-lwtheme::after { - background-color: rgba(0,0,0,.3); + border-bottom-color: rgba(0,0,0,.3); } #navigator-toolbox > toolbar:not(#toolbar-menubar):not(#TabsToolbar):not(#addon-bar) { @@ -1740,26 +1739,24 @@ toolbarbutton.chevron > .toolbarbutton-icon { } .ctrlTab-preview-inner { - padding-bottom: 10px; + padding: 8px; + border: 2px solid transparent; + border-radius: .5em; +} + +.ctrlTab-preview:not(#ctrlTab-showAll) > * > .ctrlTab-preview-inner { + margin: -10px -10px 0; } #ctrlTab-showAll:not(:focus) > * > .ctrlTab-preview-inner { - padding: 10px; background-color: rgba(255,255,255,.2); - border-radius: .5em; } .ctrlTab-preview:focus > * > .ctrlTab-preview-inner { color: white; background-color: rgba(0,0,0,.6); text-shadow: none; - padding: 8px; - border: 2px solid white; - border-radius: .5em; -} - -.ctrlTab-preview:not(#ctrlTab-showAll):focus > * > .ctrlTab-preview-inner { - margin: -10px -10px 0; + border-color: white; } #ctrlTab-showAll { diff --git a/browser/themes/osx/browser.css b/browser/themes/osx/browser.css index 05988d845c504..4744f5e84ae2b 100644 --- a/browser/themes/osx/browser.css +++ b/browser/themes/osx/browser.css @@ -55,10 +55,10 @@ #navigator-toolbox::after { -moz-box-ordinal-group: 101; /* tabs toolbar is 100 */ - background-image: linear-gradient(to top, hsla(0,0%,0%,.15), hsla(0,0%,0%,.15) 1px, hsla(0,0%,100%,.15) 1px, hsla(0,0%,100%,.15) 2px, transparent 3px); content: ""; display: -moz-box; - height: 2px; + border-top: 1px solid hsla(0,0%,100%,.15); + border-bottom: 1px solid hsla(0,0%,0%,.15); margin-top: -2px; position: relative; z-index: 2; /* navbar is at 1 */ @@ -66,7 +66,9 @@ @media (-moz-mac-yosemite-theme) { #navigator-toolbox:-moz-window-inactive::after { - background-image: linear-gradient(to top, hsla(0,0%,0%,.1), hsla(0,0%,0%,.1) 1px, hsla(0,0%,100%,0) 1px, hsla(0,0%,100%,0) 2px, transparent 3px); + border-top-style: none; + border-bottom-color: hsla(0,0%,0%,.1); + margin-top: -1px; } } @@ -3149,26 +3151,24 @@ menulist.translate-infobar-element > .menulist-dropmarker { } .ctrlTab-preview-inner { - padding-bottom: 10px; + padding: 8px; + border: 2px solid transparent; + border-radius: .5em; +} + +.ctrlTab-preview:not(#ctrlTab-showAll) > * > .ctrlTab-preview-inner { + margin: -10px -10px 0; } #ctrlTab-showAll:not(:focus) > * > .ctrlTab-preview-inner { - padding: 10px; background-color: rgba(255,255,255,.2); - border-radius: .5em; } .ctrlTab-preview:focus > * > .ctrlTab-preview-inner { color: white; background-color: rgba(0,0,0,.6); text-shadow: none; - padding: 8px; - border: 2px solid white; - border-radius: .5em; -} - -.ctrlTab-preview:not(#ctrlTab-showAll):focus > * > .ctrlTab-preview-inner { - margin: -10px -10px 0; + border-color: white; } #ctrlTab-showAll { diff --git a/browser/themes/osx/devedition.css b/browser/themes/osx/devedition.css index 0cce31393d255..8fdbf4f9e66ee 100644 --- a/browser/themes/osx/devedition.css +++ b/browser/themes/osx/devedition.css @@ -10,7 +10,8 @@ /* Use only 1px separator between nav toolbox and page content */ #navigator-toolbox::after { - background: linear-gradient(to top, var(--chrome-navigator-toolbox-separator-color), var(--chrome-navigator-toolbox-separator-color) 1px, transparent 1px); + border-top-style: none; + margin-top: -1px; } /* Include extra space on left/right for dragging since there is no space above diff --git a/browser/themes/shared/devedition.inc.css b/browser/themes/shared/devedition.inc.css index 2c54c1f7b6f9c..c309295a7d09f 100644 --- a/browser/themes/shared/devedition.inc.css +++ b/browser/themes/shared/devedition.inc.css @@ -146,7 +146,7 @@ } #navigator-toolbox:-moz-lwtheme::after { - background: var(--chrome-navigator-toolbox-separator-color); + border-bottom-color: var(--chrome-navigator-toolbox-separator-color); } #navigator-toolbox > toolbar:not(#TabsToolbar):not(#toolbar-menubar), diff --git a/browser/themes/shared/tabs.inc.css b/browser/themes/shared/tabs.inc.css index c8f5493978ff2..c3932b6e2c4e0 100644 --- a/browser/themes/shared/tabs.inc.css +++ b/browser/themes/shared/tabs.inc.css @@ -440,10 +440,20 @@ .tabbrowser-tab::after, .tabbrowser-tab::before { - margin-top: 5px; - margin-bottom: 4px; margin-inline-start: -1px; - border-left: 1px solid currentColor; + /* Vertical margin doesn't work here for positioned pinned tabs, see + bug 1198236 and bug 1300410. We're using linear-gradient instead + to cut off the border at the top and at the bottom. */ + border-left: 1px solid; + border-image: linear-gradient(transparent 6px, + currentColor 6px, + currentColor calc(100% - 5px), + transparent calc(100% - 5px)); + border-image-slice: 1; + /* The 1px border and negative margin may amount to a different number of + device pixels (bug 477157), so we also set a width to match the margin. */ + width: 1px; + box-sizing: border-box; opacity: 0.2; } diff --git a/browser/themes/windows/browser-aero.css b/browser/themes/windows/browser-aero.css index 4d6f61ad97467..5ff9d8250ac2d 100644 --- a/browser/themes/windows/browser-aero.css +++ b/browser/themes/windows/browser-aero.css @@ -335,16 +335,21 @@ (-moz-os-version: windows-win7), (-moz-os-version: windows-win8) { /* Vertical toolbar border */ - #main-window:not([customizing])[sizemode=normal] #navigator-toolbox:not(:-moz-lwtheme)::after, #main-window:not([customizing])[sizemode=normal] #navigator-toolbox > toolbar:not(#toolbar-menubar):not(#TabsToolbar):not(:-moz-lwtheme), #main-window:not([customizing])[sizemode=normal] #navigator-toolbox:-moz-lwtheme, - #main-window[customizing] #navigator-toolbox::after, #main-window[customizing] #navigator-toolbox > toolbar:not(#toolbar-menubar):not(#TabsToolbar) { border-left: 1px solid @toolbarShadowColor@; border-right: 1px solid @toolbarShadowColor@; background-clip: padding-box; } + #main-window:not([customizing])[sizemode=normal] #navigator-toolbox:not(:-moz-lwtheme)::after, + #main-window[customizing] #navigator-toolbox::after { + box-shadow: 1px 0 0 @toolbarShadowColor@, -1px 0 0 @toolbarShadowColor@; + margin-left: 1px; + margin-right: 1px; + } + #main-window[sizemode=normal] #browser-border-start, #main-window[sizemode=normal] #browser-border-end { display: -moz-box; diff --git a/browser/themes/windows/browser.css b/browser/themes/windows/browser.css index 526e04fe536bb..1ef905efa7ece 100644 --- a/browser/themes/windows/browser.css +++ b/browser/themes/windows/browser.css @@ -122,28 +122,27 @@ content: ""; display: -moz-box; -moz-box-ordinal-group: 101; /* tabs toolbar is 100 */ - height: 1px; - background-color: ThreeDShadow; + border-bottom: 1px solid ThreeDShadow; } @media (-moz-windows-default-theme) { @media (-moz-os-version: windows-vista), (-moz-os-version: windows-win7) { #navigator-toolbox::after { - background-color: #aabccf; + border-bottom-color: #aabccf; } } @media (-moz-os-version: windows-win8), (-moz-os-version: windows-win10) { #navigator-toolbox::after { - background-color: #c2c2c2; + border-bottom-color: #c2c2c2; } } } #navigator-toolbox:-moz-lwtheme::after { - background-color: rgba(0,0,0,.3); + border-bottom-color: rgba(0,0,0,.3); } #navigator-toolbox > toolbar { @@ -2422,26 +2421,24 @@ notification[value="translation"] { } .ctrlTab-preview-inner { - padding-bottom: 10px; + padding: 8px; + border: 2px solid transparent; + border-radius: .5em; +} + +.ctrlTab-preview:not(#ctrlTab-showAll) > * > .ctrlTab-preview-inner { + margin: -10px -10px 0; } #ctrlTab-showAll:not(:focus) > * > .ctrlTab-preview-inner { - padding: 10px; background-color: rgba(255,255,255,.2); - border-radius: .5em; } .ctrlTab-preview:focus > * > .ctrlTab-preview-inner { color: white; background-color: rgba(0,0,0,.6); text-shadow: none; - padding: 8px; - border: 2px solid white; - border-radius: .5em; -} - -.ctrlTab-preview:not(#ctrlTab-showAll):focus > * > .ctrlTab-preview-inner { - margin: -10px -10px 0; + border-color: white; } #ctrlTab-showAll { diff --git a/devtools/shared/heapsnapshot/AutoMemMap.cpp b/devtools/shared/heapsnapshot/AutoMemMap.cpp index c9b821d787a76..e725a99c65fe0 100644 --- a/devtools/shared/heapsnapshot/AutoMemMap.cpp +++ b/devtools/shared/heapsnapshot/AutoMemMap.cpp @@ -5,6 +5,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/devtools/AutoMemMap.h" + +#include "mozilla/Unused.h" #include "nsDebug.h" namespace mozilla { @@ -13,17 +15,17 @@ namespace devtools { AutoMemMap::~AutoMemMap() { if (addr) { - NS_WARN_IF(PR_MemUnmap(addr, size()) != PR_SUCCESS); + Unused << NS_WARN_IF(PR_MemUnmap(addr, size()) != PR_SUCCESS); addr = nullptr; } if (fileMap) { - NS_WARN_IF(PR_CloseFileMap(fileMap) != PR_SUCCESS); + Unused << NS_WARN_IF(PR_CloseFileMap(fileMap) != PR_SUCCESS); fileMap = nullptr; } if (fd) { - NS_WARN_IF(PR_Close(fd) != PR_SUCCESS); + Unused << NS_WARN_IF(PR_Close(fd) != PR_SUCCESS); fd = nullptr; } } diff --git a/devtools/shared/heapsnapshot/HeapSnapshot.cpp b/devtools/shared/heapsnapshot/HeapSnapshot.cpp index bb0eecec504a4..d7d33fa1afa79 100644 --- a/devtools/shared/heapsnapshot/HeapSnapshot.cpp +++ b/devtools/shared/heapsnapshot/HeapSnapshot.cpp @@ -29,6 +29,7 @@ #include "mozilla/dom/HeapSnapshotBinding.h" #include "mozilla/RangedPtr.h" #include "mozilla/Telemetry.h" +#include "mozilla/Unused.h" #include "jsapi.h" #include "jsfriendapi.h" @@ -1473,7 +1474,7 @@ class DeleteHeapSnapshotTempFileHelperChild constexpr DeleteHeapSnapshotTempFileHelperChild() { } void operator()(PHeapSnapshotTempFileHelperChild* ptr) const { - NS_WARN_IF(!HeapSnapshotTempFileHelperChild::Send__delete__(ptr)); + Unused << NS_WARN_IF(!HeapSnapshotTempFileHelperChild::Send__delete__(ptr)); } }; diff --git a/devtools/shared/heapsnapshot/ZeroCopyNSIOutputStream.cpp b/devtools/shared/heapsnapshot/ZeroCopyNSIOutputStream.cpp index 1bc9d438e0939..0c29db7f90326 100644 --- a/devtools/shared/heapsnapshot/ZeroCopyNSIOutputStream.cpp +++ b/devtools/shared/heapsnapshot/ZeroCopyNSIOutputStream.cpp @@ -6,6 +6,7 @@ #include "mozilla/devtools/ZeroCopyNSIOutputStream.h" #include "mozilla/DebugOnly.h" +#include "mozilla/Unused.h" namespace mozilla { namespace devtools { @@ -24,7 +25,7 @@ ZeroCopyNSIOutputStream::ZeroCopyNSIOutputStream(nsCOMPtr& out) ZeroCopyNSIOutputStream::~ZeroCopyNSIOutputStream() { if (!failed()) - NS_WARN_IF(NS_FAILED(writeBuffer())); + Unused << NS_WARN_IF(NS_FAILED(writeBuffer())); } nsresult diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index 3d3b33c68d287..b88a2e7d8e001 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -2506,40 +2506,47 @@ nsDocShell::GetFullscreenAllowed(bool* aFullscreenAllowed) if (!win) { return NS_OK; } - nsCOMPtr frameElement = win->GetFrameElementInternal(); - if (frameElement && !frameElement->IsXULElement()) { - // We do not allow document inside any containing element other - // than iframe to enter fullscreen. - if (frameElement->IsHTMLElement(nsGkAtoms::iframe)) { - // If any ancestor iframe does not have allowfullscreen attribute - // set, then fullscreen is not allowed. - if (!frameElement->HasAttr(kNameSpaceID_None, - nsGkAtoms::allowfullscreen) && - !frameElement->HasAttr(kNameSpaceID_None, - nsGkAtoms::mozallowfullscreen)) { + if (nsCOMPtr frameElement = win->GetFrameElementInternal()) { + if (frameElement->IsXULElement()) { + if (frameElement->HasAttr(kNameSpaceID_None, + nsGkAtoms::disablefullscreen)) { + // Document inside this frame is explicitly disabled. return NS_OK; } - } else if (frameElement->IsHTMLElement(nsGkAtoms::embed)) { - // Respect allowfullscreen only if this is a rewritten YouTube embed. - nsCOMPtr objectLoadingContent = - do_QueryInterface(frameElement); - if (!objectLoadingContent) { - return NS_OK; - } - nsObjectLoadingContent* olc = - static_cast(objectLoadingContent.get()); - if (!olc->IsRewrittenYoutubeEmbed()) { - return NS_OK; - } - // We don't have to check prefixed attributes because Flash does not - // support them. - if (!frameElement->HasAttr(kNameSpaceID_None, - nsGkAtoms::allowfullscreen)) { + } else { + // We do not allow document inside any containing element other + // than iframe to enter fullscreen. + if (frameElement->IsHTMLElement(nsGkAtoms::iframe)) { + // If any ancestor iframe does not have allowfullscreen attribute + // set, then fullscreen is not allowed. + if (!frameElement->HasAttr(kNameSpaceID_None, + nsGkAtoms::allowfullscreen) && + !frameElement->HasAttr(kNameSpaceID_None, + nsGkAtoms::mozallowfullscreen)) { + return NS_OK; + } + } else if (frameElement->IsHTMLElement(nsGkAtoms::embed)) { + // Respect allowfullscreen only if this is a rewritten YouTube embed. + nsCOMPtr objectLoadingContent = + do_QueryInterface(frameElement); + if (!objectLoadingContent) { + return NS_OK; + } + nsObjectLoadingContent* olc = + static_cast(objectLoadingContent.get()); + if (!olc->IsRewrittenYoutubeEmbed()) { + return NS_OK; + } + // We don't have to check prefixed attributes because Flash does not + // support them. + if (!frameElement->HasAttr(kNameSpaceID_None, + nsGkAtoms::allowfullscreen)) { + return NS_OK; + } + } else { + // neither iframe nor embed return NS_OK; } - } else { - // neither iframe nor embed - return NS_OK; } } diff --git a/dom/audiochannel/AudioChannelService.cpp b/dom/audiochannel/AudioChannelService.cpp index 0fc238f48b1bb..6a14468b3c6d3 100644 --- a/dom/audiochannel/AudioChannelService.cpp +++ b/dom/audiochannel/AudioChannelService.cpp @@ -1349,8 +1349,8 @@ AudioChannelService::AudioChannelWindow::NotifyAudioAudibleChanged(nsPIDOMWindow { RefPtr runnable = new AudioPlaybackRunnable(aWindow, aAudible, aReason); - nsresult rv = NS_DispatchToCurrentThread(runnable); - NS_WARN_IF(NS_FAILED(rv)); + DebugOnly rv = NS_DispatchToCurrentThread(runnable); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToCurrentThread failed"); } void @@ -1360,6 +1360,6 @@ AudioChannelService::AudioChannelWindow::NotifyChannelActive(uint64_t aWindowID, { RefPtr runnable = new NotifyChannelActiveRunnable(aWindowID, aChannel, aActive); - nsresult rv = NS_DispatchToCurrentThread(runnable); - NS_WARN_IF(NS_FAILED(rv)); + DebugOnly rv = NS_DispatchToCurrentThread(runnable); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToCurrentThread failed"); } diff --git a/dom/base/MultipartBlobImpl.cpp b/dom/base/MultipartBlobImpl.cpp index d1f089b3f02d4..0953101434def 100644 --- a/dom/base/MultipartBlobImpl.cpp +++ b/dom/base/MultipartBlobImpl.cpp @@ -167,7 +167,7 @@ void MultipartBlobImpl::InitializeBlob(ErrorResult& aRv) { SetLengthAndModifiedDate(aRv); - NS_WARN_IF(aRv.Failed()); + NS_WARNING_ASSERTION(!aRv.Failed(), "SetLengthAndModifiedDate failed"); } void @@ -221,7 +221,7 @@ MultipartBlobImpl::InitializeBlob(JSContext* aCx, mBlobImpls = blobSet.GetBlobImpls(); SetLengthAndModifiedDate(aRv); - NS_WARN_IF(aRv.Failed()); + NS_WARNING_ASSERTION(!aRv.Failed(), "SetLengthAndModifiedDate failed"); } void @@ -352,7 +352,7 @@ MultipartBlobImpl::InitializeChromeFile(Blob& aBlob, mBlobImpls = blobSet.GetBlobImpls(); SetLengthAndModifiedDate(aRv); - NS_WARN_IF(aRv.Failed()); + NS_WARNING_ASSERTION(!aRv.Failed(), "SetLengthAndModifiedDate failed"); } void @@ -424,7 +424,7 @@ MultipartBlobImpl::InitializeChromeFile(nsPIDOMWindowInner* aWindow, mBlobImpls = blobSet.GetBlobImpls(); SetLengthAndModifiedDate(aRv); - NS_WARN_IF(aRv.Failed()); + NS_WARNING_ASSERTION(!aRv.Failed(), "SetLengthAndModifiedDate failed"); } void diff --git a/dom/base/Navigator.cpp b/dom/base/Navigator.cpp index e1beae37d53c5..4af94bf28c635 100644 --- a/dom/base/Navigator.cpp +++ b/dom/base/Navigator.cpp @@ -47,6 +47,7 @@ #include "mozilla/dom/Permissions.h" #include "mozilla/dom/Presentation.h" #include "mozilla/dom/ServiceWorkerContainer.h" +#include "mozilla/dom/StorageManager.h" #include "mozilla/dom/TCPSocket.h" #include "mozilla/dom/Telephony.h" #include "mozilla/dom/Voicemail.h" @@ -232,6 +233,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Navigator) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTVManager) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mInputPortManager) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConnection) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStorageManager) #ifdef MOZ_B2G_RIL NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMobileConnections) #endif @@ -276,6 +278,8 @@ Navigator::Invalidate() mPermissions = nullptr; + mStorageManager = nullptr; + // If there is a page transition, make sure delete the geolocation object. if (mGeolocation) { mGeolocation->Shutdown(); @@ -658,6 +662,21 @@ Navigator::GetPermissions(ErrorResult& aRv) return mPermissions; } +StorageManager* +Navigator::Storage() +{ + MOZ_ASSERT(mWindow); + + if(!mStorageManager) { + nsCOMPtr global = do_QueryInterface(mWindow); + MOZ_ASSERT(global); + + mStorageManager = new StorageManager(global); + } + + return mStorageManager; +} + // Values for the network.cookie.cookieBehavior pref are documented in // nsCookieService.cpp. #define COOKIE_BEHAVIOR_REJECT 2 diff --git a/dom/base/Navigator.h b/dom/base/Navigator.h index ab4eb7fb55ed0..c551fa9b5757f 100644 --- a/dom/base/Navigator.h +++ b/dom/base/Navigator.h @@ -101,6 +101,7 @@ class DeviceStorageAreaListener; class Presentation; class LegacyMozTCPSocket; class VRDisplay; +class StorageManager; namespace time { class TimeManager; @@ -287,6 +288,8 @@ class Navigator final : public nsIDOMNavigator bool MozE10sEnabled(); + StorageManager* Storage(); + static void GetAcceptLanguages(nsTArray& aLanguages); // WebIDL helper methods @@ -377,6 +380,7 @@ class Navigator final : public nsIDOMNavigator #endif nsTArray > mVRGetDisplaysPromises; nsTArray mRequestedVibrationPattern; + RefPtr mStorageManager; }; } // namespace dom diff --git a/dom/base/ScreenOrientation.cpp b/dom/base/ScreenOrientation.cpp index 8a5b215298839..bb3ccf5c3346e 100644 --- a/dom/base/ScreenOrientation.cpp +++ b/dom/base/ScreenOrientation.cpp @@ -399,9 +399,11 @@ ScreenOrientation::UnlockDeviceOrientation() // Remove event listener in case of fullscreen lock. nsCOMPtr target = do_QueryInterface(GetOwner()->GetDoc()); if (target) { - nsresult rv = target->RemoveSystemEventListener(NS_LITERAL_STRING("fullscreenchange"), - mFullScreenListener, /* useCapture */ true); - NS_WARN_IF(NS_FAILED(rv)); + DebugOnly rv = + target->RemoveSystemEventListener(NS_LITERAL_STRING("fullscreenchange"), + mFullScreenListener, + /* useCapture */ true); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "RemoveSystemEventListener failed"); } mFullScreenListener = nullptr; @@ -530,18 +532,18 @@ ScreenOrientation::Notify(const hal::ScreenConfiguration& aConfiguration) mAngle = aConfiguration.angle(); mType = InternalOrientationToType(orientation); - nsresult rv; + DebugOnly rv; if (mScreen && mType != previousOrientation) { // Use of mozorientationchange is deprecated. rv = mScreen->DispatchTrustedEvent(NS_LITERAL_STRING("mozorientationchange")); - NS_WARN_IF(NS_FAILED(rv)); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "DispatchTrustedEvent failed"); } if (doc->Hidden() && !mVisibleListener) { mVisibleListener = new VisibleEventListener(); rv = doc->AddSystemEventListener(NS_LITERAL_STRING("visibilitychange"), mVisibleListener, /* useCapture = */ true); - NS_WARN_IF(NS_FAILED(rv)); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "AddSystemEventListener failed"); return; } @@ -557,7 +559,7 @@ ScreenOrientation::Notify(const hal::ScreenConfiguration& aConfiguration) nsCOMPtr runnable = NewRunnableMethod(this, &ScreenOrientation::DispatchChangeEvent); rv = NS_DispatchToMainThread(runnable); - NS_WARN_IF(NS_FAILED(rv)); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToMainThread failed"); } } @@ -567,16 +569,16 @@ ScreenOrientation::UpdateActiveOrientationLock(ScreenOrientationInternal aOrient if (aOrientation == eScreenOrientation_None) { hal::UnlockScreenOrientation(); } else { - bool rv = hal::LockScreenOrientation(aOrientation); - NS_WARN_IF(!rv); + DebugOnly ok = hal::LockScreenOrientation(aOrientation); + NS_WARNING_ASSERTION(ok, "hal::LockScreenOrientation failed"); } } void ScreenOrientation::DispatchChangeEvent() { - nsresult rv = DispatchTrustedEvent(NS_LITERAL_STRING("change")); - NS_WARN_IF(NS_FAILED(rv)); + DebugOnly rv = DispatchTrustedEvent(NS_LITERAL_STRING("change")); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "DispatchTrustedEvent failed"); } JSObject* diff --git a/dom/base/StructuredCloneHolder.cpp b/dom/base/StructuredCloneHolder.cpp index 02176f33e2018..b3fca7c6804bb 100644 --- a/dom/base/StructuredCloneHolder.cpp +++ b/dom/base/StructuredCloneHolder.cpp @@ -31,6 +31,7 @@ #include "mozilla/dom/SubtleCryptoBinding.h" #include "mozilla/dom/ToJSValue.h" #include "mozilla/dom/URLSearchParams.h" +#include "mozilla/dom/URLSearchParamsBinding.h" #include "mozilla/dom/WebCryptoCommon.h" #include "mozilla/gfx/2D.h" #include "mozilla/ipc/BackgroundChild.h" diff --git a/dom/base/nsContentCreatorFunctions.h b/dom/base/nsContentCreatorFunctions.h index a3f0caf2f5ae6..9576d9ba8c309 100644 --- a/dom/base/nsContentCreatorFunctions.h +++ b/dom/base/nsContentCreatorFunctions.h @@ -31,7 +31,7 @@ nsresult NS_NewElement(mozilla::dom::Element** aResult, already_AddRefed&& aNodeInfo, mozilla::dom::FromParser aFromParser, - nsAString* aIs = nullptr); + const nsAString* aIs = nullptr); nsresult NS_NewXMLElement(mozilla::dom::Element** aResult, @@ -41,7 +41,7 @@ nsresult NS_NewHTMLElement(mozilla::dom::Element** aResult, already_AddRefed&& aNodeInfo, mozilla::dom::FromParser aFromParser, - nsAString* aIs = nullptr); + const nsAString* aIs = nullptr); // First argument should be nsHTMLTag, but that adds dependency to parser // for a bunch of files. diff --git a/dom/base/nsContentIterator.cpp b/dom/base/nsContentIterator.cpp index 18fb5419a4715..2854bd84b1776 100644 --- a/dom/base/nsContentIterator.cpp +++ b/dom/base/nsContentIterator.cpp @@ -16,6 +16,8 @@ #include "nsINode.h" #include "nsCycleCollectionParticipant.h" +using mozilla::DebugOnly; + // couple of utility static functs /////////////////////////////////////////////////////////////////////////// @@ -31,7 +33,7 @@ NodeToParentOffset(nsINode* aNode, int32_t* aOffset) if (parent) { *aOffset = parent->IndexOf(aNode); - NS_WARN_IF(*aOffset < 0); + NS_WARNING_ASSERTION(*aOffset >= 0, "bad offset"); } return parent; @@ -73,7 +75,7 @@ NodeIsInTraversalRange(nsINode* aNode, bool aIsPreMode, } int32_t indx = parent->IndexOf(aNode); - NS_WARN_IF(indx == -1); + NS_WARNING_ASSERTION(indx != -1, "bad indx"); if (!aIsPreMode) { ++indx; @@ -275,10 +277,10 @@ nsContentIterator::Init(nsINode* aRoot) if (mPre) { mFirst = aRoot; mLast = GetDeepLastChild(aRoot); - NS_WARN_IF(!mLast); + NS_WARNING_ASSERTION(mLast, "GetDeepLastChild returned null"); } else { mFirst = GetDeepFirstChild(aRoot); - NS_WARN_IF(!mFirst); + NS_WARNING_ASSERTION(mFirst, "GetDeepFirstChild returned null"); mLast = aRoot; } @@ -306,7 +308,7 @@ nsContentIterator::Init(nsIDOMRange* aDOMRange) // get the start node and offset int32_t startIndx = range->StartOffset(); - NS_WARN_IF(startIndx < 0); + NS_WARNING_ASSERTION(startIndx >= 0, "bad startIndx"); nsINode* startNode = range->GetStartParent(); if (NS_WARN_IF(!startNode)) { return NS_ERROR_FAILURE; @@ -314,7 +316,7 @@ nsContentIterator::Init(nsIDOMRange* aDOMRange) // get the end node and offset int32_t endIndx = range->EndOffset(); - NS_WARN_IF(endIndx < 0); + NS_WARNING_ASSERTION(endIndx >= 0, "bad endIndx"); nsINode* endNode = range->GetEndParent(); if (NS_WARN_IF(!endNode)) { return NS_ERROR_FAILURE; @@ -342,8 +344,8 @@ nsContentIterator::Init(nsIDOMRange* aDOMRange) mLast = mFirst; mCurNode = mFirst; - nsresult rv = RebuildIndexStack(); - NS_WARN_IF(NS_FAILED(rv)); + DebugOnly rv = RebuildIndexStack(); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "RebuildIndexStack failed"); return NS_OK; } } @@ -354,7 +356,7 @@ nsContentIterator::Init(nsIDOMRange* aDOMRange) if (!startIsData && startNode->HasChildren()) { cChild = startNode->GetChildAt(startIndx); - NS_WARN_IF(!cChild); + NS_WARNING_ASSERTION(cChild, "GetChildAt returned null"); } if (!cChild) { @@ -373,7 +375,7 @@ nsContentIterator::Init(nsIDOMRange* aDOMRange) // In other words, if the offset is 1, the node should be ignored. if (!startIsData && startIndx) { mFirst = GetNextSibling(startNode); - NS_WARN_IF(!mFirst); + NS_WARNING_ASSERTION(mFirst, "GetNextSibling returned null"); // Does mFirst node really intersect the range? The range could be // 'degenerate', i.e., not collapsed but still contain no content. @@ -400,7 +402,7 @@ nsContentIterator::Init(nsIDOMRange* aDOMRange) } else { // post-order mFirst = GetDeepFirstChild(cChild); - NS_WARN_IF(!mFirst); + NS_WARNING_ASSERTION(mFirst, "GetDeepFirstChild returned null"); // Does mFirst node really intersect the range? The range could be // 'degenerate', i.e., not collapsed but still contain no content. @@ -429,7 +431,7 @@ nsContentIterator::Init(nsIDOMRange* aDOMRange) // include the end node in the range). if (!endIsData && !endNode->HasChildren() && !endIndx) { mLast = GetPrevSibling(endNode); - NS_WARN_IF(!mLast); + NS_WARNING_ASSERTION(mLast, "GetPrevSibling returned null"); if (NS_WARN_IF(!NodeIsInTraversalRange(mLast, mPre, startNode, startIndx, endNode, endIndx))) { @@ -447,7 +449,7 @@ nsContentIterator::Init(nsIDOMRange* aDOMRange) if (!endIsData) { mLast = GetPrevSibling(endNode); - NS_WARN_IF(!mLast); + NS_WARNING_ASSERTION(mLast, "GetPrevSibling returned null"); if (!NodeIsInTraversalRange(mLast, mPre, startNode, startIndx, @@ -471,7 +473,7 @@ nsContentIterator::Init(nsIDOMRange* aDOMRange) if (mPre) { mLast = GetDeepLastChild(cChild); - NS_WARN_IF(!mLast); + NS_WARNING_ASSERTION(mLast, "GetDeepLastChild returned null"); if (NS_WARN_IF(!NodeIsInTraversalRange(mLast, mPre, startNode, startIndx, @@ -497,8 +499,8 @@ nsContentIterator::Init(nsIDOMRange* aDOMRange) if (!mCurNode) { mIndexes.Clear(); } else { - nsresult rv = RebuildIndexStack(); - NS_WARN_IF(NS_FAILED(rv)); + DebugOnly rv = RebuildIndexStack(); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "RebuildIndexStack failed"); } return NS_OK; @@ -654,7 +656,7 @@ nsContentIterator::GetNextSibling(nsINode* aNode, } else { indx = mCachedIndex; } - NS_WARN_IF(indx < 0); + NS_WARNING_ASSERTION(indx >= 0, "bad indx"); // reverify that the index of the current node hasn't changed. // not super cheap, but a lot cheaper than IndexOf(), and still O(1). @@ -663,7 +665,7 @@ nsContentIterator::GetNextSibling(nsINode* aNode, if (sib != aNode) { // someone changed our index - find the new index the painful way indx = parent->IndexOf(aNode); - NS_WARN_IF(indx < 0); + NS_WARNING_ASSERTION(indx >= 0, "bad indx"); } // indx is now canonically correct @@ -724,7 +726,7 @@ nsContentIterator::GetPrevSibling(nsINode* aNode, if (sib != aNode) { // someone changed our index - find the new index the painful way indx = parent->IndexOf(aNode); - NS_WARN_IF(indx < 0); + NS_WARNING_ASSERTION(indx >= 0, "bad indx"); } // indx is now canonically correct @@ -802,7 +804,7 @@ nsContentIterator::NextNode(nsINode* aNode, nsTArray* aIndexes) if (sibling != node) { // someone changed our index - find the new index the painful way indx = parent->IndexOf(node); - NS_WARN_IF(indx < 0); + NS_WARNING_ASSERTION(indx >= 0, "bad indx"); } // indx is now canonically correct @@ -867,13 +869,13 @@ nsContentIterator::PrevNode(nsINode* aNode, nsTArray* aIndexes) // this time - the index may now be out of range. if (indx >= 0) { sibling = parent->GetChildAt(indx); - NS_WARN_IF(!sibling); + NS_WARNING_ASSERTION(sibling, "GetChildAt returned null"); } if (sibling != node) { // someone changed our index - find the new index the painful way indx = parent->IndexOf(node); - NS_WARN_IF(indx < 0); + NS_WARNING_ASSERTION(indx >= 0, "bad indx"); } // indx is now canonically correct @@ -903,12 +905,12 @@ nsContentIterator::PrevNode(nsINode* aNode, nsTArray* aIndexes) // post-order int32_t numChildren = node->GetChildCount(); - NS_WARN_IF(numChildren < 0); + NS_WARNING_ASSERTION(numChildren >= 0, "no children"); // if it has children then prev node is last child if (numChildren) { nsIContent* lastChild = node->GetLastChild(); - NS_WARN_IF(!lastChild); + NS_WARNING_ASSERTION(lastChild, "GetLastChild returned null"); numChildren--; // update cache @@ -1026,15 +1028,15 @@ nsContentIterator::PositionAt(nsINode* aCurNode) if (firstNode && lastNode) { if (mPre) { firstNode = NodeToParentOffset(mFirst, &firstOffset); - NS_WARN_IF(!firstNode); - NS_WARN_IF(firstOffset < 0); + NS_WARNING_ASSERTION(firstNode, "NodeToParentOffset returned null"); + NS_WARNING_ASSERTION(firstOffset >= 0, "bad firstOffset"); if (lastNode->GetChildCount()) { lastOffset = 0; } else { lastNode = NodeToParentOffset(mLast, &lastOffset); - NS_WARN_IF(!lastNode); - NS_WARN_IF(lastOffset < 0); + NS_WARNING_ASSERTION(lastNode, "NodeToParentOffset returned null"); + NS_WARNING_ASSERTION(lastOffset >= 0, "bad lastOffset"); ++lastOffset; } } else { @@ -1042,16 +1044,16 @@ nsContentIterator::PositionAt(nsINode* aCurNode) if (numChildren) { firstOffset = numChildren; - NS_WARN_IF(firstOffset < 0); + NS_WARNING_ASSERTION(firstOffset >= 0, "bad firstOffset"); } else { firstNode = NodeToParentOffset(mFirst, &firstOffset); - NS_WARN_IF(!firstNode); - NS_WARN_IF(firstOffset < 0); + NS_WARNING_ASSERTION(firstNode, "NodeToParentOffset returned null"); + NS_WARNING_ASSERTION(firstOffset >= 0, "bad firstOffset"); } lastNode = NodeToParentOffset(mLast, &lastOffset); - NS_WARN_IF(!lastNode); - NS_WARN_IF(lastOffset < 0); + NS_WARNING_ASSERTION(lastNode, "NodeToParentOffset returned null"); + NS_WARNING_ASSERTION(lastOffset >= 0, "bad lastOffset"); ++lastOffset; } } @@ -1118,7 +1120,7 @@ nsContentIterator::PositionAt(nsINode* aCurNode) } int32_t indx = parent->IndexOf(newCurNode); - NS_WARN_IF(indx < 0); + NS_WARNING_ASSERTION(indx >= 0, "bad indx"); // insert at the head! newIndexes.InsertElementAt(0, indx); diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index de0c8cb077fd1..ecc7765106ba9 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -9421,7 +9421,7 @@ nsContentUtils::HttpsStateIsModern(nsIDocument* aDocument) nsCOMPtr csm = do_GetService(NS_CONTENTSECURITYMANAGER_CONTRACTID); - NS_WARN_IF(!csm); + NS_WARNING_ASSERTION(csm, "csm is null"); if (csm) { bool isTrustworthyOrigin = false; csm->IsOriginPotentiallyTrustworthy(principal, &isTrustworthyOrigin); diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp index 828789c43fe60..074bf66dd73f4 100644 --- a/dom/base/nsDocument.cpp +++ b/dom/base/nsDocument.cpp @@ -5374,7 +5374,9 @@ nsDocument::CreateElement(const nsAString& aTagName, { *aReturn = nullptr; ErrorResult rv; - ElementCreationOptions options; + ElementCreationOptionsOrString options; + + options.SetAsString(); nsCOMPtr element = CreateElement(aTagName, options, rv); NS_ENSURE_FALSE(rv.Failed(), rv.StealNSResult()); return CallQueryInterface(element, aReturn); @@ -5419,7 +5421,7 @@ nsDocument::GetCustomElementsRegistry() already_AddRefed nsDocument::CreateElement(const nsAString& aTagName, - const ElementCreationOptions& aOptions, + const ElementCreationOptionsOrString& aOptions, ErrorResult& rv) { rv = nsContentUtils::CheckQName(aTagName, false); @@ -5433,11 +5435,14 @@ nsDocument::CreateElement(const nsAString& aTagName, nsContentUtils::ASCIIToLower(aTagName, lcTagName); } - // Throw NotFoundError if 'is' is not-null and definition is null - nsString* is = CheckCustomElementName( - aOptions, needsLowercase ? lcTagName : aTagName, mDefaultElementType, rv); - if (rv.Failed()) { - return nullptr; + const nsString* is = nullptr; + if (aOptions.IsElementCreationOptions()) { + // Throw NotFoundError if 'is' is not-null and definition is null + is = CheckCustomElementName(aOptions.GetAsElementCreationOptions(), + needsLowercase ? lcTagName : aTagName, mDefaultElementType, rv); + if (rv.Failed()) { + return nullptr; + } } RefPtr elem = CreateElem( @@ -5477,7 +5482,7 @@ nsDocument::CreateElementNS(const nsAString& aNamespaceURI, } // Throw NotFoundError if 'is' is not-null and definition is null - nsString* is = CheckCustomElementName( + const nsString* is = CheckCustomElementName( aOptions, aQualifiedName, nodeInfo->NamespaceID(), rv); if (rv.Failed()) { return nullptr; @@ -8150,7 +8155,7 @@ nsDocument::RetrieveRelevantHeaders(nsIChannel *aChannel) already_AddRefed nsDocument::CreateElem(const nsAString& aName, nsIAtom *aPrefix, - int32_t aNamespaceID, nsAString* aIs) + int32_t aNamespaceID, const nsAString* aIs) { #ifdef DEBUG nsAutoString qName; @@ -12890,7 +12895,7 @@ nsIDocument::UpdateStyleBackendType() #endif } -nsString* +const nsString* nsDocument::CheckCustomElementName(const ElementCreationOptions& aOptions, const nsAString& aLocalName, uint32_t aNamespaceID, @@ -12903,7 +12908,7 @@ nsDocument::CheckCustomElementName(const ElementCreationOptions& aOptions, return nullptr; } - nsString* is = const_cast(&(aOptions.mIs.Value())); + const nsString* is = &aOptions.mIs.Value(); // Throw NotFoundError if 'is' is not-null and definition is null if (!nsContentUtils::LookupCustomElementDefinition(this, aLocalName, diff --git a/dom/base/nsDocument.h b/dom/base/nsDocument.h index dd9220948d9d7..e21fcda98b058 100644 --- a/dom/base/nsDocument.h +++ b/dom/base/nsDocument.h @@ -828,7 +828,7 @@ class nsDocument : public nsIDocument, virtual already_AddRefed CreateElem(const nsAString& aName, nsIAtom* aPrefix, int32_t aNamespaceID, - nsAString* aIs = nullptr) override; + const nsAString* aIs = nullptr) override; virtual void Sanitize() override; @@ -1131,7 +1131,7 @@ class nsDocument : public nsIDocument, virtual mozilla::dom::DOMStringList* StyleSheetSets() override; virtual void EnableStyleSheetsForSet(const nsAString& aSheetSet) override; virtual already_AddRefed CreateElement(const nsAString& aTagName, - const mozilla::dom::ElementCreationOptions& aOptions, + const mozilla::dom::ElementCreationOptionsOrString& aOptions, ErrorResult& rv) override; virtual already_AddRefed CreateElementNS(const nsAString& aNamespaceURI, const nsAString& aQualifiedName, @@ -1378,7 +1378,7 @@ class nsDocument : public nsIDocument, * If there is no existing custom element definition for this name, throw a * NotFoundError. */ - nsString* CheckCustomElementName( + const nsString* CheckCustomElementName( const mozilla::dom::ElementCreationOptions& aOptions, const nsAString& aLocalName, uint32_t aNamespaceID, diff --git a/dom/base/nsGkAtomList.h b/dom/base/nsGkAtomList.h index 50b2301165e66..2d59e4307eee2 100644 --- a/dom/base/nsGkAtomList.h +++ b/dom/base/nsGkAtomList.h @@ -312,6 +312,7 @@ GK_ATOM(disableOutputEscaping, "disable-output-escaping") GK_ATOM(disabled, "disabled") GK_ATOM(disableglobalhistory, "disableglobalhistory") GK_ATOM(disablehistory, "disablehistory") +GK_ATOM(disablefullscreen, "disablefullscreen") GK_ATOM(display, "display") GK_ATOM(displayMode, "display-mode") GK_ATOM(distinct, "distinct") diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index 73f90f073c5b7..d04433785e836 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -543,7 +543,6 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(nsTimeout) NS_IMPL_CYCLE_COLLECTION_UNLINK_0(nsTimeout) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsTimeout) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPrincipal) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScriptHandler) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsTimeout, AddRef) @@ -2417,7 +2416,7 @@ nsGlobalWindow::ComputeIsSecureContext(nsIDocument* aDocument) nsCOMPtr csm = do_GetService(NS_CONTENTSECURITYMANAGER_CONTRACTID); - NS_WARN_IF(!csm); + NS_WARNING_ASSERTION(csm, "csm is null"); if (csm) { bool isTrustworthyOrigin = false; csm->IsOriginPotentiallyTrustworthy(principal, &isTrustworthyOrigin); @@ -12036,23 +12035,6 @@ nsGlobalWindow::SetTimeoutOrInterval(nsIScriptTimeoutHandler *aHandler, realInterval = std::max(realInterval, uint32_t(DOMMinTimeoutValue())); } - // Get principal of currently executing code, save for execution of timeout. - // If our principals subsume the subject principal then use the subject - // principal. Otherwise, use our principal to avoid running script in - // elevated principals. - // - // Note the direction of this test: We don't allow setTimeouts running with - // chrome privileges on content windows, but we do allow setTimeouts running - // with content privileges on chrome windows (where they can't do very much, - // of course). - nsCOMPtr subjectPrincipal = nsContentUtils::SubjectPrincipal(); - nsCOMPtr ourPrincipal = GetPrincipal(); - if (ourPrincipal->Subsumes(subjectPrincipal)) { - timeout->mPrincipal = subjectPrincipal; - } else { - timeout->mPrincipal = ourPrincipal; - } - TimeDuration delta = TimeDuration::FromMilliseconds(realInterval); if (!IsFrozen() && !mTimeoutsSuspendDepth) { diff --git a/dom/base/nsGlobalWindow.h b/dom/base/nsGlobalWindow.h index 37524c7113cca..387b4200d806d 100644 --- a/dom/base/nsGlobalWindow.h +++ b/dom/base/nsGlobalWindow.h @@ -198,9 +198,6 @@ struct nsTimeout final // Remaining time to wait. Used only when timeouts are suspended. mozilla::TimeDuration mTimeRemaining; - // Principal with which to execute - nsCOMPtr mPrincipal; - // stack depth at which timeout is firing uint32_t mFiringDepth; diff --git a/dom/base/nsHostObjectProtocolHandler.cpp b/dom/base/nsHostObjectProtocolHandler.cpp index d4490af7d0196..8f60b519fdb97 100644 --- a/dom/base/nsHostObjectProtocolHandler.cpp +++ b/dom/base/nsHostObjectProtocolHandler.cpp @@ -140,8 +140,8 @@ BroadcastBlobURLRegistration(const nsACString& aURI, return; } - NS_WARN_IF(!cc->SendStoreAndBroadcastBlobURLRegistration(nsCString(aURI), actor, - IPC::Principal(aPrincipal))); + Unused << NS_WARN_IF(!cc->SendStoreAndBroadcastBlobURLRegistration( + nsCString(aURI), actor, IPC::Principal(aPrincipal))); } void @@ -156,7 +156,8 @@ BroadcastBlobURLUnregistration(const nsACString& aURI, DataInfo* aInfo) } ContentChild* cc = ContentChild::GetSingleton(); - NS_WARN_IF(!cc->SendUnstoreAndBroadcastBlobURLUnregistration(nsCString(aURI))); + Unused << NS_WARN_IF(!cc->SendUnstoreAndBroadcastBlobURLUnregistration( + nsCString(aURI))); } class HostObjectURLsReporter final : public nsIMemoryReporter diff --git a/dom/base/nsIDocument.h b/dom/base/nsIDocument.h index d984c05b28fe7..e21f11626a8dc 100644 --- a/dom/base/nsIDocument.h +++ b/dom/base/nsIDocument.h @@ -24,7 +24,6 @@ #include "nsTHashtable.h" // for member #include "mozilla/net/ReferrerPolicy.h" // for member #include "nsWeakReference.h" -#include "mozilla/dom/DocumentBinding.h" #include "mozilla/UseCounter.h" #include "mozilla/WeakPtr.h" #include "Units.h" @@ -38,6 +37,16 @@ #include "mozilla/StyleSheetHandle.h" #include // for member +#ifdef MOZILLA_INTERNAL_API +#include "mozilla/dom/DocumentBinding.h" +#else +namespace mozilla { +namespace dom { +class ElementCreationOptionsOrString; +} // namespace dom +} // namespace mozilla +#endif // MOZILLA_INTERNAL_API + class gfxUserFontSet; class imgIRequest; class nsAString; @@ -1513,7 +1522,7 @@ class nsIDocument : public nsINode virtual already_AddRefed CreateElem(const nsAString& aName, nsIAtom* aPrefix, int32_t aNamespaceID, - nsAString* aIs = nullptr) = 0; + const nsAString* aIs = nullptr) = 0; /** * Get the security info (i.e. SSL state etc) that the document got @@ -2504,7 +2513,7 @@ class nsIDocument : public nsINode // GetElementById defined above virtual already_AddRefed CreateElement(const nsAString& aTagName, - const mozilla::dom::ElementCreationOptions& aOptions, + const mozilla::dom::ElementCreationOptionsOrString& aOptions, mozilla::ErrorResult& rv) = 0; virtual already_AddRefed CreateElementNS(const nsAString& aNamespaceURI, @@ -2591,6 +2600,7 @@ class nsIDocument : public nsINode { UnlockPointer(this); } +#ifdef MOZILLA_INTERNAL_API bool Hidden() const { return mVisibilityState != mozilla::dom::VisibilityState::Visible; @@ -2609,6 +2619,7 @@ class nsIDocument : public nsINode WarnOnceAbout(ePrefixedVisibilityAPI); return VisibilityState(); } +#endif virtual mozilla::dom::StyleSheetList* StyleSheets() = 0; void GetSelectedStyleSheetSet(nsAString& aSheetSet); virtual void SetSelectedStyleSheetSet(const nsAString& aSheetSet) = 0; @@ -2912,8 +2923,13 @@ class nsIDocument : public nsINode // Our readyState ReadyState mReadyState; +#ifdef MOZILLA_INTERNAL_API // Our visibility state mozilla::dom::VisibilityState mVisibilityState; + static_assert(sizeof(mozilla::dom::VisibilityState) == sizeof(uint32_t), "Error size of mVisibilityState and mDummy"); +#else + uint32_t mDummy; +#endif // Whether this document has (or will have, once we have a pres shell) a // Gecko- or Servo-backed style system. diff --git a/dom/base/nsNameSpaceManager.cpp b/dom/base/nsNameSpaceManager.cpp index 1ce7b3ff73ef8..0130bb5d28a8f 100644 --- a/dom/base/nsNameSpaceManager.cpp +++ b/dom/base/nsNameSpaceManager.cpp @@ -108,7 +108,7 @@ nsNameSpaceManager::RegisterNameSpace(const nsAString& aURI, } NS_POSTCONDITION(aNameSpaceID >= -1, "Bogus namespace ID"); - + return rv; } @@ -169,7 +169,7 @@ nsresult NS_NewElement(Element** aResult, already_AddRefed&& aNodeInfo, FromParser aFromParser, - nsAString* aIs) + const nsAString* aIs) { RefPtr ni = aNodeInfo; int32_t ns = ni->NamespaceID(); diff --git a/dom/bindings/BindingDeclarations.h b/dom/bindings/BindingDeclarations.h index f0c442554e7b3..82f5d014d0d6a 100644 --- a/dom/bindings/BindingDeclarations.h +++ b/dom/bindings/BindingDeclarations.h @@ -500,6 +500,24 @@ struct MOZ_STACK_CLASS ParentObject { bool mUseXBLScope; }; +namespace binding_detail { + +// Class for simple sequence arguments, only used internally by codegen. +template +class AutoSequence : public AutoTArray +{ +public: + AutoSequence() : AutoTArray() + {} + + // Allow converting to const sequences as needed + operator const Sequence&() const { + return *reinterpret_cast*>(this); + } +}; + +} // namespace binding_detail + } // namespace dom } // namespace mozilla diff --git a/dom/bindings/BindingUtils.h b/dom/bindings/BindingUtils.h index a80a21d9144f8..52f2b46180d9b 100644 --- a/dom/bindings/BindingUtils.h +++ b/dom/bindings/BindingUtils.h @@ -38,6 +38,7 @@ #include "qsObjectHelper.h" #include "xpcpublic.h" #include "nsIVariant.h" +#include "mozilla/dom/FakeString.h" #include "nsWrapperCacheInlines.h" @@ -1900,146 +1901,6 @@ AppendNamedPropertyIds(JSContext* cx, JS::Handle proxy, namespace binding_detail { -// A struct that has the same layout as an nsString but much faster -// constructor and destructor behavior. FakeString uses inline storage -// for small strings and a nsStringBuffer for longer strings. -struct FakeString { - FakeString() : - mFlags(nsString::F_TERMINATED) - { - } - - ~FakeString() { - if (mFlags & nsString::F_SHARED) { - nsStringBuffer::FromData(mData)->Release(); - } - } - - void Rebind(const nsString::char_type* aData, nsString::size_type aLength) { - MOZ_ASSERT(mFlags == nsString::F_TERMINATED); - mData = const_cast(aData); - mLength = aLength; - } - - // Share aString's string buffer, if it has one; otherwise, make this string - // depend upon aString's data. aString should outlive this instance of - // FakeString. - void ShareOrDependUpon(const nsAString& aString) { - RefPtr sharedBuffer = nsStringBuffer::FromString(aString); - if (!sharedBuffer) { - Rebind(aString.Data(), aString.Length()); - } else { - AssignFromStringBuffer(sharedBuffer.forget()); - mLength = aString.Length(); - } - } - - void Truncate() { - MOZ_ASSERT(mFlags == nsString::F_TERMINATED); - mData = nsString::char_traits::sEmptyBuffer; - mLength = 0; - } - - void SetIsVoid(bool aValue) { - MOZ_ASSERT(aValue, - "We don't support SetIsVoid(false) on FakeString!"); - Truncate(); - mFlags |= nsString::F_VOIDED; - } - - const nsString::char_type* Data() const - { - return mData; - } - - nsString::char_type* BeginWriting() - { - return mData; - } - - nsString::size_type Length() const - { - return mLength; - } - - // Reserve space to write aLength chars, not including null-terminator. - bool SetLength(nsString::size_type aLength, mozilla::fallible_t const&) { - // Use mInlineStorage for small strings. - if (aLength < sInlineCapacity) { - SetData(mInlineStorage); - } else { - RefPtr buf = nsStringBuffer::Alloc((aLength + 1) * sizeof(nsString::char_type)); - if (MOZ_UNLIKELY(!buf)) { - return false; - } - - AssignFromStringBuffer(buf.forget()); - } - mLength = aLength; - mData[mLength] = char16_t(0); - return true; - } - - // If this ever changes, change the corresponding code in the - // Optional specialization as well. - const nsAString* ToAStringPtr() const { - return reinterpret_cast(this); - } - -operator const nsAString& () const { - return *reinterpret_cast(this); - } - -private: - nsAString* ToAStringPtr() { - return reinterpret_cast(this); - } - - nsString::char_type* mData; - nsString::size_type mLength; - uint32_t mFlags; - - static const size_t sInlineCapacity = 64; - nsString::char_type mInlineStorage[sInlineCapacity]; - - FakeString(const FakeString& other) = delete; - void operator=(const FakeString& other) = delete; - - void SetData(nsString::char_type* aData) { - MOZ_ASSERT(mFlags == nsString::F_TERMINATED); - mData = const_cast(aData); - } - void AssignFromStringBuffer(already_AddRefed aBuffer) { - SetData(static_cast(aBuffer.take()->Data())); - mFlags = nsString::F_SHARED | nsString::F_TERMINATED; - } - - friend class NonNull; - - // A class to use for our static asserts to ensure our object layout - // matches that of nsString. - class StringAsserter; - friend class StringAsserter; - - class StringAsserter : public nsString { - public: - static void StaticAsserts() { - static_assert(offsetof(FakeString, mInlineStorage) == - sizeof(nsString), - "FakeString should include all nsString members"); - static_assert(offsetof(FakeString, mData) == - offsetof(StringAsserter, mData), - "Offset of mData should match"); - static_assert(offsetof(FakeString, mLength) == - offsetof(StringAsserter, mLength), - "Offset of mLength should match"); - static_assert(offsetof(FakeString, mFlags) == - offsetof(StringAsserter, mFlags), - "Offset of mFlags should match"); - } - }; -}; - class FastErrorResult : public mozilla::binding_danger::TErrorResult< mozilla::binding_danger::JustAssertCleanupPolicy> @@ -2128,24 +1989,6 @@ void DoTraceSequence(JSTracer* trc, FallibleTArray& seq); template void DoTraceSequence(JSTracer* trc, InfallibleTArray& seq); -// Class for simple sequence arguments, only used internally by codegen. -namespace binding_detail { - -template -class AutoSequence : public AutoTArray -{ -public: - AutoSequence() : AutoTArray() - {} - - // Allow converting to const sequences as needed - operator const Sequence&() const { - return *reinterpret_cast*>(this); - } -}; - -} // namespace binding_detail - // Class used to trace sequences, with specializations for various // sequence types. template 0 - bindingDeclareHeaders["mozilla/dom/BindingUtils.h"] = len(unionStructs) > 0 + bindingDeclareHeaders["mozilla/dom/FakeString.h"] = len(unionStructs) > 0 + # BindingUtils.h is only needed for SetToObject. + # If it stops being inlined or stops calling CallerSubsumes + # both this bit and the bit in UnionTypes can be removed. + bindingDeclareHeaders["mozilla/dom/BindingUtils.h"] = any(d.isObject() for t in unionTypes + for d in t.flatMemberTypes) bindingDeclareHeaders["mozilla/dom/IterableIterator.h"] = any(d.interface.isIteratorInterface() or d.interface.isIterable() for d in descriptors) @@ -16359,7 +16363,9 @@ def UnionTypes(config): includes.add("mozilla/OwningNonNull.h") includes.add("mozilla/dom/UnionMember.h") includes.add("mozilla/dom/BindingDeclarations.h") - # Need BindingUtils.h for FakeString + # BindingUtils.h is only needed for SetToObject. + # If it stops being inlined or stops calling CallerSubsumes + # both this bit and the bit in CGBindingRoot can be removed. includes.add("mozilla/dom/BindingUtils.h") implincludes.add("mozilla/dom/PrimitiveConversions.h") diff --git a/dom/bindings/FakeString.h b/dom/bindings/FakeString.h new file mode 100644 index 0000000000000..bd92a1bca1278 --- /dev/null +++ b/dom/bindings/FakeString.h @@ -0,0 +1,160 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_FakeString_h__ +#define mozilla_dom_FakeString_h__ + +#include "nsString.h" +#include "nsStringBuffer.h" +#include "mozilla/RefPtr.h" + +namespace mozilla { +namespace dom { +namespace binding_detail { +// A struct that has the same layout as an nsString but much faster +// constructor and destructor behavior. FakeString uses inline storage +// for small strings and a nsStringBuffer for longer strings. +struct FakeString { + FakeString() : + mFlags(nsString::F_TERMINATED) + { + } + + ~FakeString() { + if (mFlags & nsString::F_SHARED) { + nsStringBuffer::FromData(mData)->Release(); + } + } + + void Rebind(const nsString::char_type* aData, nsString::size_type aLength) { + MOZ_ASSERT(mFlags == nsString::F_TERMINATED); + mData = const_cast(aData); + mLength = aLength; + } + + // Share aString's string buffer, if it has one; otherwise, make this string + // depend upon aString's data. aString should outlive this instance of + // FakeString. + void ShareOrDependUpon(const nsAString& aString) { + RefPtr sharedBuffer = nsStringBuffer::FromString(aString); + if (!sharedBuffer) { + Rebind(aString.Data(), aString.Length()); + } else { + AssignFromStringBuffer(sharedBuffer.forget()); + mLength = aString.Length(); + } + } + + void Truncate() { + MOZ_ASSERT(mFlags == nsString::F_TERMINATED); + mData = nsString::char_traits::sEmptyBuffer; + mLength = 0; + } + + void SetIsVoid(bool aValue) { + MOZ_ASSERT(aValue, + "We don't support SetIsVoid(false) on FakeString!"); + Truncate(); + mFlags |= nsString::F_VOIDED; + } + + const nsString::char_type* Data() const + { + return mData; + } + + nsString::char_type* BeginWriting() + { + return mData; + } + + nsString::size_type Length() const + { + return mLength; + } + + // Reserve space to write aLength chars, not including null-terminator. + bool SetLength(nsString::size_type aLength, mozilla::fallible_t const&) { + // Use mInlineStorage for small strings. + if (aLength < sInlineCapacity) { + SetData(mInlineStorage); + } else { + RefPtr buf = nsStringBuffer::Alloc((aLength + 1) * sizeof(nsString::char_type)); + if (MOZ_UNLIKELY(!buf)) { + return false; + } + + AssignFromStringBuffer(buf.forget()); + } + mLength = aLength; + mData[mLength] = char16_t(0); + return true; + } + + // If this ever changes, change the corresponding code in the + // Optional specialization as well. + const nsAString* ToAStringPtr() const { + return reinterpret_cast(this); + } + +operator const nsAString& () const { + return *reinterpret_cast(this); + } + +private: + nsAString* ToAStringPtr() { + return reinterpret_cast(this); + } + + nsString::char_type* mData; + nsString::size_type mLength; + uint32_t mFlags; + + static const size_t sInlineCapacity = 64; + nsString::char_type mInlineStorage[sInlineCapacity]; + + FakeString(const FakeString& other) = delete; + void operator=(const FakeString& other) = delete; + + void SetData(nsString::char_type* aData) { + MOZ_ASSERT(mFlags == nsString::F_TERMINATED); + mData = const_cast(aData); + } + void AssignFromStringBuffer(already_AddRefed aBuffer) { + SetData(static_cast(aBuffer.take()->Data())); + mFlags = nsString::F_SHARED | nsString::F_TERMINATED; + } + + friend class NonNull; + + // A class to use for our static asserts to ensure our object layout + // matches that of nsString. + class StringAsserter; + friend class StringAsserter; + + class StringAsserter : public nsString { + public: + static void StaticAsserts() { + static_assert(offsetof(FakeString, mInlineStorage) == + sizeof(nsString), + "FakeString should include all nsString members"); + static_assert(offsetof(FakeString, mData) == + offsetof(StringAsserter, mData), + "Offset of mData should match"); + static_assert(offsetof(FakeString, mLength) == + offsetof(StringAsserter, mLength), + "Offset of mLength should match"); + static_assert(offsetof(FakeString, mFlags) == + offsetof(StringAsserter, mFlags), + "Offset of mFlags should match"); + } + }; +}; +} // namespace binding_detail +} // namespace dom +} // namespace mozilla + +#endif /* mozilla_dom_FakeString_h__ */ \ No newline at end of file diff --git a/dom/bindings/moz.build b/dom/bindings/moz.build index 4efb849f1cf1a..dd829a2f98f19 100644 --- a/dom/bindings/moz.build +++ b/dom/bindings/moz.build @@ -29,6 +29,7 @@ EXPORTS.mozilla.dom += [ 'DOMString.h', 'Errors.msg', 'Exceptions.h', + 'FakeString.h', 'IterableIterator.h', 'JSSlots.h', 'MozMap.h', diff --git a/dom/bluetooth/bluedroid/BluetoothMapSmsManager.cpp b/dom/bluetooth/bluedroid/BluetoothMapSmsManager.cpp index 01abfd84e465c..1d12b7b90ad91 100644 --- a/dom/bluetooth/bluedroid/BluetoothMapSmsManager.cpp +++ b/dom/bluetooth/bluedroid/BluetoothMapSmsManager.cpp @@ -152,7 +152,7 @@ BluetoothMapSmsManager::Uninit() return; } - NS_WARN_IF(NS_FAILED( + Unused << NS_WARN_IF(NS_FAILED( obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID))); } diff --git a/dom/bluetooth/bluedroid/BluetoothPbapManager.cpp b/dom/bluetooth/bluedroid/BluetoothPbapManager.cpp index 1c80a3bf22470..497475f50a542 100644 --- a/dom/bluetooth/bluedroid/BluetoothPbapManager.cpp +++ b/dom/bluetooth/bluedroid/BluetoothPbapManager.cpp @@ -159,7 +159,7 @@ BluetoothPbapManager::Uninit() return; } - NS_WARN_IF(NS_FAILED( + Unused << NS_WARN_IF(NS_FAILED( obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID))); } diff --git a/dom/bluetooth/bluez/BluetoothSocket.cpp b/dom/bluetooth/bluez/BluetoothSocket.cpp index f618944864c72..0014827d64904 100644 --- a/dom/bluetooth/bluez/BluetoothSocket.cpp +++ b/dom/bluetooth/bluez/BluetoothSocket.cpp @@ -9,10 +9,11 @@ #include "BluetoothSocketObserver.h" #include "BluetoothUnixSocketConnector.h" #include "BluetoothUtils.h" +#include "mozilla/DebugOnly.h" #include "mozilla/RefPtr.h" +#include "mozilla/Unused.h" #include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, MOZ_COUNT_DTOR #include "nsXULAppAPI.h" -#include "mozilla/Unused.h" using namespace mozilla::ipc; @@ -242,7 +243,7 @@ BluetoothSocket::BluetoothSocketIO::Listen() // calls OnListening on success, or OnError otherwise rv = UnixSocketWatcher::Listen( reinterpret_cast(&mAddress), mAddressLength); - NS_WARN_IF(NS_FAILED(rv)); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Listen failed"); } } @@ -266,9 +267,9 @@ BluetoothSocket::BluetoothSocketIO::Connect() } // calls OnConnected() on success, or OnError() otherwise - nsresult rv = UnixSocketWatcher::Connect( + DebugOnly rv = UnixSocketWatcher::Connect( reinterpret_cast(&mAddress), mAddressLength); - NS_WARN_IF(NS_FAILED(rv)); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Connect failed"); } void diff --git a/dom/bluetooth/common/BluetoothUtils.cpp b/dom/bluetooth/common/BluetoothUtils.cpp index 9ac16e64631c6..f584b9afe880d 100644 --- a/dom/bluetooth/common/BluetoothUtils.cpp +++ b/dom/bluetooth/common/BluetoothUtils.cpp @@ -779,7 +779,7 @@ DispatchReplySuccess(BluetoothReplyRunnable* aRunnable, BluetoothReply* reply = new BluetoothReply(BluetoothReplySuccess(aValue)); aRunnable->SetReply(reply); // runnable will delete reply after Run() - NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(aRunnable))); + Unused << NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(aRunnable))); } void @@ -794,7 +794,7 @@ DispatchReplyError(BluetoothReplyRunnable* aRunnable, new BluetoothReply(BluetoothReplyError(STATUS_FAIL, nsString(aErrorStr))); aRunnable->SetReply(reply); - NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(aRunnable))); + Unused << NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(aRunnable))); } void @@ -809,7 +809,7 @@ DispatchReplyError(BluetoothReplyRunnable* aRunnable, new BluetoothReply(BluetoothReplyError(aStatus, EmptyString())); aRunnable->SetReply(reply); - NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(aRunnable))); + Unused << NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(aRunnable))); } void @@ -823,7 +823,7 @@ DispatchReplyError(BluetoothReplyRunnable* aRunnable, new BluetoothReply(BluetoothReplyError(aGattStatus, EmptyString())); aRunnable->SetReply(reply); - NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(aRunnable))); + Unused << NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(aRunnable))); } void diff --git a/dom/cache/test/mochitest/test_cache_orphaned_body.html b/dom/cache/test/mochitest/test_cache_orphaned_body.html index 43e29921f7df3..03dcb5370af34 100644 --- a/dom/cache/test/mochitest/test_cache_orphaned_body.html +++ b/dom/cache/test/mochitest/test_cache_orphaned_body.html @@ -43,6 +43,32 @@ }); } +function groupUsage() { + return new Promise(function(resolve, reject) { + navigator.storage.estimate().then(storageEstimation => { + resolve(storageEstimation.usage, 0); + }); + }); +} + +function workerGroupUsage() { + return new Promise(function(resolve, reject) { + function workerScript() { + navigator.storage.estimate().then(storageEstimation => { + postMessage(storageEstimation.usage); + }); + } + + let url = + URL.createObjectURL(new Blob(["(", workerScript.toSource(), ")()"])); + + let worker = new Worker(url); + worker.onmessage = function (e) { + resolve(e.data, 0); + }; + }); +} + function resetStorage() { return new Promise(function(resolve, reject) { var qms = SpecialPowers.Services.qms; @@ -142,6 +168,26 @@ ok(fullUsage > initialUsage, 'disk usage should have grown'); }) + // Test groupUsage() + .then(function() { + return resetStorage(); + }).then(function() { + return groupUsage(); + }).then(function(usage) { + fullUsage = usage; + ok(fullUsage > initialUsage, 'disk group usage should have grown'); + }) + + // Test workerGroupUsage() + .then(function() { + return resetStorage(); + }).then(function() { + return workerGroupUsage(); + }).then(function(usage) { + fullUsage = usage; + ok(fullUsage > initialUsage, 'disk group usage on worker should have grown'); + }) + // Now perform a new Cache operation that will reopen the origin. This // should clean up the orphaned body. .then(function() { diff --git a/dom/camera/GonkCameraControl.cpp b/dom/camera/GonkCameraControl.cpp index 594b46ee62bbb..d0b4c89edc9e9 100644 --- a/dom/camera/GonkCameraControl.cpp +++ b/dom/camera/GonkCameraControl.cpp @@ -1449,10 +1449,10 @@ nsGonkCameraControl::OnAutoFocusMoving(bool aIsMoving) if (!mAutoFocusPending) { RefPtr timerCb = new AutoFocusMovingTimerCallback(this); - nsresult rv = mAutoFocusCompleteTimer->InitWithCallback(timerCb, - kAutoFocusCompleteTimeoutMs, - nsITimer::TYPE_ONE_SHOT); - NS_WARN_IF(NS_FAILED(rv)); + DebugOnly rv = + mAutoFocusCompleteTimer->InitWithCallback( + timerCb, kAutoFocusCompleteTimeoutMs, nsITimer::TYPE_ONE_SHOT); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "InitWithCallback failed"); } return; } diff --git a/dom/camera/TestGonkCameraHardware.cpp b/dom/camera/TestGonkCameraHardware.cpp index 35bdcc1a94ec8..c330ec3cc5a6f 100644 --- a/dom/camera/TestGonkCameraHardware.cpp +++ b/dom/camera/TestGonkCameraHardware.cpp @@ -22,6 +22,7 @@ #include "mozilla/dom/ErrorEvent.h" #include "mozilla/dom/CameraFacesDetectedEvent.h" #include "mozilla/dom/CameraStateChangeEvent.h" +#include "mozilla/DebugOnly.h" #include "nsNetUtil.h" #include "DOMCameraDetectedFace.h" #include "nsServiceManagerUtils.h" @@ -245,8 +246,8 @@ class TestGonkCameraHardware::ControlMessage : public Runnable MutexAutoLock lock(mTestHw->mMutex); mTestHw->mStatus = RunInline(); - nsresult rv = mTestHw->mCondVar.Notify(); - NS_WARN_IF(NS_FAILED(rv)); + DebugOnly rv = mTestHw->mCondVar.Notify(); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Notify failed"); return NS_OK; } @@ -313,15 +314,15 @@ TestGonkCameraHardware::~TestGonkCameraHardware() { if (mTestHw->mDomListener) { mTestHw->mDomListener = nullptr; - nsresult rv = mJSTestWrapper->SetHandler(nullptr); - NS_WARN_IF(NS_FAILED(rv)); + DebugOnly rv = mJSTestWrapper->SetHandler(nullptr); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "SetHandler failed"); } return NS_OK; } }; - nsresult rv = WaitWhileRunningOnMainThread(new Delegate(this)); - NS_WARN_IF(NS_FAILED(rv)); + DebugOnly rv = WaitWhileRunningOnMainThread(new Delegate(this)); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WaitWhileRunningOnMainThread failed"); DOM_CAMERA_LOGA("^===== Destroyed TestGonkCameraHardware =====^\n"); } @@ -385,8 +386,8 @@ TestGonkCameraHardware::Init() } }; - nsresult rv = WaitWhileRunningOnMainThread(new Delegate(this)); - NS_WARN_IF(NS_FAILED(rv)); + DebugOnly rv = WaitWhileRunningOnMainThread(new Delegate(this)); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WaitWhileRunningOnMainThread failed"); return rv; } @@ -539,8 +540,8 @@ TestGonkCameraHardware::CancelTakePicture() }; DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__); - nsresult rv = WaitWhileRunningOnMainThread(new Delegate(this)); - NS_WARN_IF(NS_FAILED(rv)); + DebugOnly rv = WaitWhileRunningOnMainThread(new Delegate(this)); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WaitWhileRunningOnMainThread failed"); } int @@ -588,8 +589,8 @@ TestGonkCameraHardware::StopPreview() }; DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__); - nsresult rv = WaitWhileRunningOnMainThread(new Delegate(this)); - NS_WARN_IF(NS_FAILED(rv)); + DebugOnly rv = WaitWhileRunningOnMainThread(new Delegate(this)); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WaitWhileRunningOnMainThread failed"); } class TestGonkCameraHardware::PushParametersDelegate : public ControlMessage diff --git a/dom/canvas/test/test_bitmaprenderer.html b/dom/canvas/test/test_bitmaprenderer.html index 5a2cb70b673ed..32361c6454764 100644 --- a/dom/canvas/test/test_bitmaprenderer.html +++ b/dom/canvas/test/test_bitmaprenderer.html @@ -76,8 +76,8 @@ var fuzz = { numDifferentPixels: 0, maxDifference: 0 }; if (SpecialPowers.Services.appinfo.widgetToolkit == "android") { - fuzz.maxDifference = 14; - fuzz.numDifferentPixels = 130; + fuzz.maxDifference = 2; + fuzz.numDifferentPixels = 131; } var results = compareSnapshots(snapshot, snapshotRef, true, fuzz); ok(results[0], "Screenshots should be the same"); diff --git a/dom/console/Console.cpp b/dom/console/Console.cpp index 41f1d10c49372..e11400a54a5c2 100644 --- a/dom/console/Console.cpp +++ b/dom/console/Console.cpp @@ -1381,7 +1381,7 @@ Console::MethodInternal(JSContext* aCx, MethodName aMethodName, RefPtr runnable = new ConsoleCallDataRunnable(this, callData); - NS_WARN_IF(!runnable->Dispatch(aCx)); + Unused << NS_WARN_IF(!runnable->Dispatch(aCx)); } // We store information to lazily compute the stack in the reserved slots of @@ -1478,8 +1478,8 @@ Console::ProcessCallData(JSContext* aCx, ConsoleCallData* aData, } if (aData->mMethodName == MethodClear) { - nsresult rv = mStorage->ClearEvents(innerID); - NS_WARN_IF(NS_FAILED(rv)); + DebugOnly rv = mStorage->ClearEvents(innerID); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "ClearEvents failed"); } if (NS_FAILED(mStorage->RecordEvent(innerID, outerID, eventValue))) { diff --git a/dom/events/DataTransferItem.cpp b/dom/events/DataTransferItem.cpp index 95f275a5d0e8a..5a705d62cf304 100644 --- a/dom/events/DataTransferItem.cpp +++ b/dom/events/DataTransferItem.cpp @@ -426,7 +426,7 @@ DataTransferItem::GetAsString(FunctionStringCallback* aCallback, { ErrorResult rv; mCallback->Call(mStringData, rv); - NS_WARN_IF(rv.Failed()); + NS_WARNING_ASSERTION(!rv.Failed(), "callback failed"); return rv.StealNSResult(); } private: diff --git a/dom/events/PointerEvent.cpp b/dom/events/PointerEvent.cpp index 071e09964671e..e8128d3687bb7 100644 --- a/dom/events/PointerEvent.cpp +++ b/dom/events/PointerEvent.cpp @@ -32,6 +32,9 @@ PointerEvent::PointerEvent(EventTarget* aOwner, mEvent->mRefPoint = LayoutDeviceIntPoint(0, 0); mouseEvent->inputSource = nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN; } + // 5.2 Pointer Event types, for all pointer events, |detail| attribute SHOULD + // be 0. + mDetail = 0; } static uint16_t diff --git a/dom/events/test/pointerevents/mochitest.ini b/dom/events/test/pointerevents/mochitest.ini index 986e41638913e..1f32b1dfa185f 100644 --- a/dom/events/test/pointerevents/mochitest.ini +++ b/dom/events/test/pointerevents/mochitest.ini @@ -8,7 +8,6 @@ support-files = [test_pointerevent_attributes_mouse-manual.html] support-files = pointerevent_attributes_mouse-manual.html - disabled = should be investigated [test_pointerevent_capture_mouse-manual.html] support-files = pointerevent_capture_mouse-manual.html [test_pointerevent_capture_suppressing_mouse-manual.html] diff --git a/dom/fetch/FetchDriver.cpp b/dom/fetch/FetchDriver.cpp index c3e6253e3c065..37de814a8ccf1 100644 --- a/dom/fetch/FetchDriver.cpp +++ b/dom/fetch/FetchDriver.cpp @@ -607,7 +607,7 @@ FetchDriver::OnStartRequest(nsIRequest* aRequest, // Try to retarget off main thread. if (nsCOMPtr rr = do_QueryInterface(aRequest)) { - NS_WARN_IF(NS_FAILED(rr->RetargetDeliveryTo(sts))); + Unused << NS_WARN_IF(NS_FAILED(rr->RetargetDeliveryTo(sts))); } return NS_OK; } diff --git a/dom/filehandle/ActorsChild.cpp b/dom/filehandle/ActorsChild.cpp index 20885683d643d..7a0b622f8ff06 100644 --- a/dom/filehandle/ActorsChild.cpp +++ b/dom/filehandle/ActorsChild.cpp @@ -16,6 +16,7 @@ #include "nsContentUtils.h" #include "nsString.h" #include "xpcpublic.h" +#include "mozilla/dom/BindingUtils.h" namespace mozilla { namespace dom { diff --git a/dom/filesystem/CreateDirectoryTask.cpp b/dom/filesystem/CreateDirectoryTask.cpp index d96d9d9789702..d396b07061977 100644 --- a/dom/filesystem/CreateDirectoryTask.cpp +++ b/dom/filesystem/CreateDirectoryTask.cpp @@ -100,7 +100,7 @@ CreateDirectoryTaskChild::SetSuccessRequestResult(const FileSystemResponseValue& aRv = NS_NewNativeLocalFile(NS_ConvertUTF16toUTF8(r.realPath()), true, getter_AddRefs(mTargetPath)); - NS_WARN_IF(aRv.Failed()); + NS_WARNING_ASSERTION(!aRv.Failed(), "NS_NewNativeLocalFile failed"); } void diff --git a/dom/filesystem/DeviceStorageFileSystem.cpp b/dom/filesystem/DeviceStorageFileSystem.cpp index 2b138c2772381..07f5ca849b453 100644 --- a/dom/filesystem/DeviceStorageFileSystem.cpp +++ b/dom/filesystem/DeviceStorageFileSystem.cpp @@ -11,6 +11,7 @@ #include "mozilla/dom/Directory.h" #include "mozilla/dom/File.h" #include "mozilla/dom/FileSystemUtils.h" +#include "mozilla/Unused.h" #include "nsCOMPtr.h" #include "nsDebug.h" #include "nsDeviceStorage.h" @@ -40,9 +41,9 @@ DeviceStorageFileSystem::DeviceStorageFileSystem(const nsAString& aStorageType, } // Get the permission name required to access the file system. - nsresult rv = + DebugOnly rv = DeviceStorageTypeChecker::GetPermissionForType(mStorageType, mPermission); - NS_WARN_IF(NS_FAILED(rv)); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "GetPermissionForType failed"); // Get the local path of the file system root. nsCOMPtr rootFile; @@ -50,7 +51,9 @@ DeviceStorageFileSystem::DeviceStorageFileSystem(const nsAString& aStorageType, aStorageName, getter_AddRefs(rootFile)); - NS_WARN_IF(!rootFile || NS_FAILED(rootFile->GetPath(mLocalOrDeviceStorageRootPath))); + Unused << + NS_WARN_IF(!rootFile || + NS_FAILED(rootFile->GetPath(mLocalOrDeviceStorageRootPath))); if (!XRE_IsParentProcess()) { return; @@ -140,7 +143,7 @@ DeviceStorageFileSystem::GetDirectoryName(nsIFile* aFile, nsAString& aRetval, } FileSystemBase::GetDirectoryName(aFile, aRetval, aRv); - NS_WARN_IF(aRv.Failed()); + NS_WARNING_ASSERTION(!aRv.Failed(), "GetDirectoryName failed"); } bool diff --git a/dom/filesystem/FileSystemBase.cpp b/dom/filesystem/FileSystemBase.cpp index 0127d8b8b2c37..6c93b93e8ea89 100644 --- a/dom/filesystem/FileSystemBase.cpp +++ b/dom/filesystem/FileSystemBase.cpp @@ -120,7 +120,7 @@ FileSystemBase::GetDirectoryName(nsIFile* aFile, nsAString& aRetval, MOZ_ASSERT(aFile); aRv = aFile->GetLeafName(aRetval); - NS_WARN_IF(aRv.Failed()); + NS_WARNING_ASSERTION(!aRv.Failed(), "GetLeafName failed"); } void diff --git a/dom/filesystem/FileSystemTaskBase.cpp b/dom/filesystem/FileSystemTaskBase.cpp index 594e4c08a631b..5a1edb6574d3b 100644 --- a/dom/filesystem/FileSystemTaskBase.cpp +++ b/dom/filesystem/FileSystemTaskBase.cpp @@ -135,8 +135,8 @@ FileSystemTaskChildBase::Start() if (HasError()) { // In this case we don't want to use IPC at all. RefPtr runnable = new ErrorRunnable(this); - nsresult rv = NS_DispatchToCurrentThread(runnable); - NS_WARN_IF(NS_FAILED(rv)); + DebugOnly rv = NS_DispatchToCurrentThread(runnable); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToCurrentThread failed"); return; } @@ -235,13 +235,13 @@ FileSystemTaskParentBase::Start() mFileSystem->AssertIsOnOwningThread(); if (NeedToGoToMainThread()) { - nsresult rv = NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL); - NS_WARN_IF(NS_FAILED(rv)); + DebugOnly rv = NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToCurrentThread failed"); return; } - nsresult rv = DispatchToIOThread(this); - NS_WARN_IF(NS_FAILED(rv)); + DebugOnly rv = DispatchToIOThread(this); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "DispatchToIOThread failed"); } void diff --git a/dom/filesystem/compat/CallbackRunnables.cpp b/dom/filesystem/compat/CallbackRunnables.cpp index 6eb8a3db32acc..03f80a3693aeb 100644 --- a/dom/filesystem/compat/CallbackRunnables.cpp +++ b/dom/filesystem/compat/CallbackRunnables.cpp @@ -12,6 +12,7 @@ #include "mozilla/dom/FileSystemDirectoryReaderBinding.h" #include "mozilla/dom/FileSystemFileEntry.h" #include "mozilla/dom/Promise.h" +#include "mozilla/Unused.h" #include "nsIGlobalObject.h" #include "nsPIDOMWindow.h" @@ -141,8 +142,8 @@ GetEntryHelper::Error(nsresult aError) if (mErrorCallback) { RefPtr runnable = new ErrorCallbackRunnable(mGlobal, mErrorCallback, aError); - nsresult rv = NS_DispatchToMainThread(runnable); - NS_WARN_IF(NS_FAILED(rv)); + DebugOnly rv = NS_DispatchToMainThread(runnable); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToMainThread failed"); } } @@ -159,8 +160,8 @@ ErrorCallbackHelper::Call(nsIGlobalObject* aGlobal, if (aErrorCallback.WasPassed()) { RefPtr runnable = new ErrorCallbackRunnable(aGlobal, &aErrorCallback.Value(), aError); - nsresult rv = NS_DispatchToMainThread(runnable); - NS_WARN_IF(NS_FAILED(rv)); + DebugOnly rv = NS_DispatchToMainThread(runnable); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToMainThread failed"); } } diff --git a/dom/filesystem/compat/FileSystemDirectoryReader.cpp b/dom/filesystem/compat/FileSystemDirectoryReader.cpp index f7ad2bdfca421..1969cb2b073a0 100644 --- a/dom/filesystem/compat/FileSystemDirectoryReader.cpp +++ b/dom/filesystem/compat/FileSystemDirectoryReader.cpp @@ -98,8 +98,8 @@ class PromiseHandler final : public PromiseNativeHandler RefPtr runnable = new ErrorCallbackRunnable(mGlobal, mErrorCallback, NS_ERROR_DOM_INVALID_STATE_ERR); - nsresult rv = NS_DispatchToMainThread(runnable); - NS_WARN_IF(NS_FAILED(rv)); + DebugOnly rv = NS_DispatchToMainThread(runnable); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToMainThread failed"); } } @@ -160,7 +160,7 @@ FileSystemDirectoryReader::ReadEntries(FileSystemEntriesCallback& aSuccessCallba RefPtr runnable = new EmptyEntriesCallbackRunnable(&aSuccessCallback); aRv = NS_DispatchToMainThread(runnable); - NS_WARN_IF(aRv.Failed()); + NS_WARNING_ASSERTION(!aRv.Failed(), "NS_DispatchToMainThread failed"); return; } diff --git a/dom/filesystem/compat/FileSystemFileEntry.cpp b/dom/filesystem/compat/FileSystemFileEntry.cpp index df755b4ece16b..56e5fe056946e 100644 --- a/dom/filesystem/compat/FileSystemFileEntry.cpp +++ b/dom/filesystem/compat/FileSystemFileEntry.cpp @@ -103,8 +103,8 @@ FileSystemFileEntry::GetFile(BlobCallback& aSuccessCallback, { RefPtr runnable = new BlobCallbackRunnable(&aSuccessCallback, mFile); - nsresult rv = NS_DispatchToMainThread(runnable); - NS_WARN_IF(NS_FAILED(rv)); + DebugOnly rv = NS_DispatchToMainThread(runnable); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToMainThread failed"); } } // dom namespace diff --git a/dom/filesystem/compat/FileSystemRootDirectoryEntry.cpp b/dom/filesystem/compat/FileSystemRootDirectoryEntry.cpp index b15ecc1326456..417df7e15f371 100644 --- a/dom/filesystem/compat/FileSystemRootDirectoryEntry.cpp +++ b/dom/filesystem/compat/FileSystemRootDirectoryEntry.cpp @@ -116,8 +116,8 @@ FileSystemRootDirectoryEntry::GetInternal(const nsAString& aPath, if (aSuccessCallback.WasPassed()) { RefPtr runnable = new EntryCallbackRunnable(&aSuccessCallback.Value(), entry); - nsresult rv = NS_DispatchToMainThread(runnable); - NS_WARN_IF(NS_FAILED(rv)); + DebugOnly rv = NS_DispatchToMainThread(runnable); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToMainThread failed"); } return; } diff --git a/dom/filesystem/compat/FileSystemRootDirectoryReader.cpp b/dom/filesystem/compat/FileSystemRootDirectoryReader.cpp index fb715b4fa9db9..16b3417f5364a 100644 --- a/dom/filesystem/compat/FileSystemRootDirectoryReader.cpp +++ b/dom/filesystem/compat/FileSystemRootDirectoryReader.cpp @@ -79,7 +79,7 @@ FileSystemRootDirectoryReader::ReadEntries(FileSystemEntriesCallback& aSuccessCa RefPtr runnable = new EmptyEntriesCallbackRunnable(&aSuccessCallback); aRv = NS_DispatchToMainThread(runnable); - NS_WARN_IF(aRv.Failed()); + NS_WARNING_ASSERTION(!aRv.Failed(), "NS_DispatchToMainThread failed"); return; } @@ -89,7 +89,7 @@ FileSystemRootDirectoryReader::ReadEntries(FileSystemEntriesCallback& aSuccessCa RefPtr runnable = new EntriesCallbackRunnable(&aSuccessCallback, mEntries); aRv = NS_DispatchToMainThread(runnable); - NS_WARN_IF(aRv.Failed()); + NS_WARNING_ASSERTION(!aRv.Failed(), "NS_DispatchToMainThread failed"); } } // dom namespace diff --git a/dom/flyweb/FlyWebService.cpp b/dom/flyweb/FlyWebService.cpp index 8f4ff47f1c659..039b92a41b4bd 100644 --- a/dom/flyweb/FlyWebService.cpp +++ b/dom/flyweb/FlyWebService.cpp @@ -324,12 +324,12 @@ FlyWebMDNSService::OnDiscoveryStarted(const nsACString& aServiceType) // If service discovery is inactive, then stop network discovery immediately. if (!mDiscoveryActive) { // Set the stop timer to fire immediately. - NS_WARN_IF(NS_FAILED(mDiscoveryStopTimer->InitWithCallback(this, 0, nsITimer::TYPE_ONE_SHOT))); + Unused << NS_WARN_IF(NS_FAILED(mDiscoveryStopTimer->InitWithCallback(this, 0, nsITimer::TYPE_ONE_SHOT))); return NS_OK; } // Otherwise, set the stop timer to fire in 5 seconds. - NS_WARN_IF(NS_FAILED(mDiscoveryStopTimer->InitWithCallback(this, 5 * 1000, nsITimer::TYPE_ONE_SHOT))); + Unused << NS_WARN_IF(NS_FAILED(mDiscoveryStopTimer->InitWithCallback(this, 5 * 1000, nsITimer::TYPE_ONE_SHOT))); return NS_OK; } @@ -363,7 +363,7 @@ FlyWebMDNSService::OnDiscoveryStopped(const nsACString& aServiceType) mService->NotifyDiscoveredServicesChanged(); // Start discovery again immediately. - NS_WARN_IF(NS_FAILED(mDiscoveryStartTimer->InitWithCallback(this, 0, nsITimer::TYPE_ONE_SHOT))); + Unused << NS_WARN_IF(NS_FAILED(mDiscoveryStartTimer->InitWithCallback(this, 0, nsITimer::TYPE_ONE_SHOT))); return NS_OK; } @@ -405,7 +405,7 @@ FlyWebMDNSService::OnStartDiscoveryFailed(const nsACString& aServiceType, int32_ // If discovery is active, and the number of consecutive failures is < 3, try starting again. if (mDiscoveryActive && mNumConsecutiveStartDiscoveryFailures < 3) { - NS_WARN_IF(NS_FAILED(mDiscoveryStartTimer->InitWithCallback(this, 0, nsITimer::TYPE_ONE_SHOT))); + Unused << NS_WARN_IF(NS_FAILED(mDiscoveryStartTimer->InitWithCallback(this, 0, nsITimer::TYPE_ONE_SHOT))); } return NS_OK; @@ -420,7 +420,7 @@ FlyWebMDNSService::OnStopDiscoveryFailed(const nsACString& aServiceType, int32_t // If discovery is active, start discovery again immediately. if (mDiscoveryActive) { - NS_WARN_IF(NS_FAILED(mDiscoveryStartTimer->InitWithCallback(this, 0, nsITimer::TYPE_ONE_SHOT))); + Unused << NS_WARN_IF(NS_FAILED(mDiscoveryStartTimer->InitWithCallback(this, 0, nsITimer::TYPE_ONE_SHOT))); } return NS_OK; diff --git a/dom/gamepad/ipc/GamepadEventChannelChild.cpp b/dom/gamepad/ipc/GamepadEventChannelChild.cpp index 15e8cfede3664..4cdb55a92ba5f 100644 --- a/dom/gamepad/ipc/GamepadEventChannelChild.cpp +++ b/dom/gamepad/ipc/GamepadEventChannelChild.cpp @@ -32,9 +32,9 @@ bool GamepadEventChannelChild::RecvGamepadUpdate( const GamepadChangeEvent& aGamepadEvent) { - nsresult rv; - rv = NS_DispatchToMainThread(new GamepadUpdateRunnable(aGamepadEvent)); - NS_WARN_IF(NS_FAILED(rv)); + DebugOnly rv = + NS_DispatchToMainThread(new GamepadUpdateRunnable(aGamepadEvent)); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToMainThread failed"); return true; } diff --git a/dom/grid/Grid.cpp b/dom/grid/Grid.cpp index 54c7e3714ced1..d10d8b581f026 100644 --- a/dom/grid/Grid.cpp +++ b/dom/grid/Grid.cpp @@ -31,53 +31,63 @@ Grid::Grid(nsISupports* aParent, MOZ_ASSERT(aFrame, "Should never be instantiated with a null nsGridContainerFrame"); - const ComputedGridTrackInfo* rowTrackInfo = - aFrame->GetComputedTemplateRows(); - const ComputedGridLineInfo* rowLineInfo = - aFrame->GetComputedTemplateRowLines(); - mRows->SetTrackInfo(rowTrackInfo); - mRows->SetLineInfo(rowTrackInfo, rowLineInfo); - - const ComputedGridTrackInfo* columnTrackInfo = - aFrame->GetComputedTemplateColumns(); - const ComputedGridLineInfo* columnLineInfo = - aFrame->GetComputedTemplateColumnLines(); - mCols->SetTrackInfo(columnTrackInfo); - mCols->SetLineInfo(columnTrackInfo, columnLineInfo); + // Construct areas first, because lines may need to reference them + // to extract additional names for boundary lines. - // Add implicit areas first. + // Add implicit areas first. Track the names that we add here, because + // we will ignore future explicit areas with the same name. + nsTHashtable namesSeen; nsGridContainerFrame::ImplicitNamedAreas* implicitAreas = aFrame->GetImplicitNamedAreas(); if (implicitAreas) { for (auto iter = implicitAreas->Iter(); !iter.Done(); iter.Next()) { - nsStringHashKey* entry = iter.Get(); - + auto& areaInfo = iter.Data(); + namesSeen.PutEntry(areaInfo.mName); GridArea* area = new GridArea(this, - nsString(entry->GetKey()), + areaInfo.mName, GridDeclaration::Implicit, - 0, - 0, - 0, - 0); + areaInfo.mRowStart, + areaInfo.mRowEnd, + areaInfo.mColumnStart, + areaInfo.mColumnEnd); mAreas.AppendElement(area); } } - // Add explicit areas next. + // Add explicit areas next, as long as they don't have the same name + // as the implicit areas, because the implicit values override what was + // initially available in the explicit areas. nsGridContainerFrame::ExplicitNamedAreas* explicitAreas = aFrame->GetExplicitNamedAreas(); if (explicitAreas) { - for (auto areaInfo : *explicitAreas) { - GridArea* area = new GridArea(this, - areaInfo.mName, - GridDeclaration::Explicit, - areaInfo.mRowStart, - areaInfo.mRowEnd, - areaInfo.mColumnStart, - areaInfo.mColumnEnd); - mAreas.AppendElement(area); + for (auto& areaInfo : *explicitAreas) { + if (!namesSeen.Contains(areaInfo.mName)) { + GridArea* area = new GridArea(this, + areaInfo.mName, + GridDeclaration::Explicit, + areaInfo.mRowStart, + areaInfo.mRowEnd, + areaInfo.mColumnStart, + areaInfo.mColumnEnd); + mAreas.AppendElement(area); + } } } + + // Now construct the tracks and lines. + const ComputedGridTrackInfo* rowTrackInfo = + aFrame->GetComputedTemplateRows(); + const ComputedGridLineInfo* rowLineInfo = + aFrame->GetComputedTemplateRowLines(); + mRows->SetTrackInfo(rowTrackInfo); + mRows->SetLineInfo(rowTrackInfo, rowLineInfo, mAreas, true); + + const ComputedGridTrackInfo* columnTrackInfo = + aFrame->GetComputedTemplateColumns(); + const ComputedGridLineInfo* columnLineInfo = + aFrame->GetComputedTemplateColumnLines(); + mCols->SetTrackInfo(columnTrackInfo); + mCols->SetLineInfo(columnTrackInfo, columnLineInfo, mAreas, false); } Grid::~Grid() diff --git a/dom/grid/GridDimension.cpp b/dom/grid/GridDimension.cpp index 9fcc676012253..040f3a3803042 100644 --- a/dom/grid/GridDimension.cpp +++ b/dom/grid/GridDimension.cpp @@ -61,9 +61,11 @@ GridDimension::SetTrackInfo(const ComputedGridTrackInfo* aTrackInfo) void GridDimension::SetLineInfo(const ComputedGridTrackInfo* aTrackInfo, - const ComputedGridLineInfo* aLineInfo) + const ComputedGridLineInfo* aLineInfo, + const nsTArray>& aAreas, + bool aIsRow) { - mLines->SetLineInfo(aTrackInfo, aLineInfo); + mLines->SetLineInfo(aTrackInfo, aLineInfo, aAreas, aIsRow); } } // namespace dom diff --git a/dom/grid/GridDimension.h b/dom/grid/GridDimension.h index 41d771297248d..7a33735216570 100644 --- a/dom/grid/GridDimension.h +++ b/dom/grid/GridDimension.h @@ -43,7 +43,9 @@ class GridDimension : public nsISupports void SetTrackInfo(const ComputedGridTrackInfo* aTrackInfo); void SetLineInfo(const ComputedGridTrackInfo* aTrackInfo, - const ComputedGridLineInfo* aLineInfo); + const ComputedGridLineInfo* aLineInfo, + const nsTArray>& aAreas, + bool aIsRow); protected: RefPtr mParent; diff --git a/dom/grid/GridLines.cpp b/dom/grid/GridLines.cpp index f275fae5e5f88..81cb029ad25c2 100644 --- a/dom/grid/GridLines.cpp +++ b/dom/grid/GridLines.cpp @@ -64,7 +64,9 @@ GridLines::IndexedGetter(uint32_t aIndex, void GridLines::SetLineInfo(const ComputedGridTrackInfo* aTrackInfo, - const ComputedGridLineInfo* aLineInfo) + const ComputedGridLineInfo* aLineInfo, + const nsTArray>& aAreas, + bool aIsRow) { mLines.Clear(); @@ -84,6 +86,8 @@ GridLines::SetLineInfo(const ComputedGridTrackInfo* aTrackInfo, for (uint32_t i = aTrackInfo->mStartFragmentTrack; i < aTrackInfo->mEndFragmentTrack + 1; i++) { + uint32_t line1Index = i + 1; + startOfNextTrack = (i < aTrackInfo->mEndFragmentTrack) ? aTrackInfo->mPositions[i] : endOfLastTrack; @@ -96,12 +100,40 @@ GridLines::SetLineInfo(const ComputedGridTrackInfo* aTrackInfo, lineNames = aLineInfo->mNames.SafeElementAt(i, nsTArray()); } + // Add in names from grid areas where this line is used as a boundary. + for (auto area : aAreas) { + bool haveNameToAdd = false; + nsAutoString nameToAdd; + area->GetName(nameToAdd); + if (aIsRow) { + if (area->RowStart() == line1Index) { + haveNameToAdd = true; + nameToAdd.AppendLiteral("-start"); + } else if (area->RowEnd() == line1Index) { + haveNameToAdd = true; + nameToAdd.AppendLiteral("-end"); + } + } else { + if (area->ColumnStart() == line1Index) { + haveNameToAdd = true; + nameToAdd.AppendLiteral("-start"); + } else if (area->ColumnEnd() == line1Index) { + haveNameToAdd = true; + nameToAdd.AppendLiteral("-end"); + } + } + + if (haveNameToAdd && !lineNames.Contains(nameToAdd)) { + lineNames.AppendElement(nameToAdd); + } + } + line->SetLineValues( lineNames, nsPresContext::AppUnitsToDoubleCSSPixels(endOfLastTrack), nsPresContext::AppUnitsToDoubleCSSPixels(startOfNextTrack - endOfLastTrack), - i + 1, + line1Index, ( // Implicit if there are no explicit tracks, or if the index // is before the first explicit track, or after diff --git a/dom/grid/GridLines.h b/dom/grid/GridLines.h index 0ec13c717d1c0..9bcf2323e247e 100644 --- a/dom/grid/GridLines.h +++ b/dom/grid/GridLines.h @@ -40,7 +40,9 @@ class GridLines : public nsISupports GridLine* IndexedGetter(uint32_t aIndex, bool& aFound); void SetLineInfo(const ComputedGridTrackInfo* aTrackInfo, - const ComputedGridLineInfo* aLineInfo); + const ComputedGridLineInfo* aLineInfo, + const nsTArray>& aAreas, + bool aIsRow); protected: RefPtr mParent; diff --git a/dom/grid/test/chrome/test_grid_areas.html b/dom/grid/test/chrome/test_grid_areas.html index 25795ac7ccfbb..2f5d8ea442f73 100644 --- a/dom/grid/test/chrome/test_grid_areas.html +++ b/dom/grid/test/chrome/test_grid_areas.html @@ -62,7 +62,7 @@ is(grid.areas[1].type, "explicit", "Area 1 is explicit."); is(grid.areas[2].type, "explicit", "Area 2 is explicit."); - // test start and end lines + // test numbers of start and end lines is(grid.areas[0].rowStart, 1, "Area 0 has start row line of 1."); is(grid.areas[0].rowEnd, 2, "Area 0 has end row line of 2."); is(grid.areas[0].columnStart, 1, "Area 0 has start column line of 1."); @@ -77,6 +77,53 @@ is(grid.areas[2].rowEnd, 4, "Area 2 has end row line of 4."); is(grid.areas[2].columnStart, 2, "Area 2 has start column line of 2."); is(grid.areas[2].columnEnd, 4, "Area 2 has end column line of 4."); + + // test names of all the row lines + isnot(grid.rows.lines[0].names.indexOf("areaA-start"), -1, + "Grid row line 1 has the name 'areaA-start'." + ); + + isnot(grid.rows.lines[1].names.indexOf("areaA-end"), -1, + "Grid row line 2 has the name 'areaA-end'." + ); + isnot(grid.rows.lines[1].names.indexOf("areaB-start"), -1, + "Grid row line 2 has the name 'areaB-start'." + ); + isnot(grid.rows.lines[1].names.indexOf("areaC-start"), -1, + "Grid row line 2 has the name 'areaC-start'." + ); + + is(grid.rows.lines[2].names.length, 0, "Grid row line 3 has no names."); + + isnot(grid.rows.lines[3].names.indexOf("areaB-end"), -1, + "Grid row line 4 has the name 'areaB-end'." + ); + isnot(grid.rows.lines[3].names.indexOf("areaC-end"), -1, + "Grid row line 4 has the name 'areaC-end'." + ); + + // test names of all the column lines + isnot(grid.cols.lines[0].names.indexOf("areaA-start"), -1, + "Grid column line 1 has the name 'areaA-start'." + ); + isnot(grid.cols.lines[0].names.indexOf("areaB-start"), -1, + "Grid column line 1 has the name 'areaB-start'." + ); + + isnot(grid.cols.lines[1].names.indexOf("areaB-end"), -1, + "Grid column line 2 has the name 'areaB-end'." + ); + isnot(grid.cols.lines[1].names.indexOf("areaC-start"), -1, + "Grid column line 2 has the name 'areaC-start'." + ); + + isnot(grid.cols.lines[2].names.indexOf("areaA-end"), -1, + "Grid column line 3 has the name 'areaA-end'." + ); + + isnot(grid.cols.lines[3].names.indexOf("areaC-end"), -1, + "Grid column line 4 has the name 'areaC-end'." + ); } } diff --git a/dom/grid/test/chrome/test_grid_implicit.html b/dom/grid/test/chrome/test_grid_implicit.html index 3d329a252fa59..c7782e0e5fc20 100644 --- a/dom/grid/test/chrome/test_grid_implicit.html +++ b/dom/grid/test/chrome/test_grid_implicit.html @@ -11,14 +11,28 @@ .wrapper { display: grid; grid-gap: 10px; - grid-template-columns: 100px 50px 100px; - grid-template-rows: 50px [areaD-start] 50px [areaD-end]; - grid-template-areas: "areaA areaA ....." - "..... areaC areaC"; grid-auto-columns: 20px; grid-auto-rows: 20px; background-color: #f00; } + +.template1 { + grid-template-columns: 100px 50px 100px; + grid-template-rows: 50px [areaD-start middle] 50px [areaD-end]; + grid-template-areas: "areaA areaA ....." + "..... areaC areaC"; +} + +.template2 { + grid-template-areas: "..... areaA ......"; + grid-template-columns: [areaA-start] 50px 50px 50px; +} + +.template3 { + grid-template-columns: [areaA-start areaB-end areaC-end areaD-start] 50px [areaA-end areaB-start areaC-start areaD-end]; + grid-template-rows: [areaA-end areaB-start areaC-end] 50px [areaA-start areaB-end areaC-start]; +} + .box { background-color: #444; color: #fff; @@ -27,7 +41,7 @@ grid-area: areaA; } .b { - grid-row: span 2 / 2; + grid-row: span got-this-name-implicitly / 2; grid-column: areaA-end / span 2; } .c { @@ -44,12 +58,10 @@ SimpleTest.waitForExplicitFinish(); function runTests() { - var wrapper = document.getElementById("wrapper"); - var grid = wrapper.getGridFragments()[0]; - var boxA = document.getElementById("boxA"); - var boxB = document.getElementById("boxB"); - var boxC = document.getElementById("boxC"); - + // test the first grid wrapper + let wrapper = document.getElementById("wrapper1"); + let grid = wrapper.getGridFragments()[0]; + // test column and row line counts is(grid.cols.lines.length, 6, "Grid.cols.lines property has length that respects implicit expansion." @@ -58,17 +70,35 @@ "Grid.rows.lines property has length that respects implicit expansion." ); - if((grid.cols.lines.length == 6) && - (grid.rows.lines.length == 4)) { + if ((grid.cols.lines.length == 6) && + (grid.rows.lines.length == 4)) { // test explicit / implicit lines is(grid.cols.lines[0].type, "explicit", "Grid column line 1 is explicit."); is(grid.cols.lines[4].type, "implicit", "Grid column line 5 is implicit."); is(grid.cols.lines[5].type, "implicit", "Grid column line 6 is implicit."); - + is(grid.rows.lines[0].type, "implicit", "Grid row line 1 is implicit."); is(grid.rows.lines[1].type, "explicit", "Grid row line 2 is explicit."); is(grid.rows.lines[3].type, "explicit", "Grid row line 4 is explicit."); + + // test that row line 1 gets the name forced on it by placement of item B + todo_isnot(grid.rows.lines[0].names.indexOf("got-this-name-implicitly"), -1, + "Grid row line 1 has the name 'got-this-name-implicitly'." + ); + + // test that row line 3 gets its explicit name + isnot(grid.rows.lines[2].names.indexOf("middle"), -1, + "Grid row line 3 has the name 'middle'." + ); + + // test the names of the implicit column lines that were created for area 'areaD' + isnot(grid.cols.lines[4].names.indexOf("areaD-start"), -1, + "Grid column line 5 has the name 'areaD-start'." + ); + isnot(grid.cols.lines[5].names.indexOf("areaD-end"), -1, + "Grid column line 6 has the name 'areaD-end'." + ); } // test column and row track counts @@ -79,8 +109,8 @@ "Grid.rows.tracks property has length that respects implicit expansion." ); - if((grid.cols.tracks.length == 5) && - (grid.rows.tracks.length == 3)) { + if ((grid.cols.tracks.length == 5) && + (grid.rows.tracks.length == 3)) { // test explicit / implicit tracks is(grid.cols.tracks[0].type, "explicit", "Grid column track 1 is explicit."); @@ -97,20 +127,99 @@ "Grid.areas property has length that respects implicit expansion." ); - for(var i = 0; i < grid.areas.length; i++) { + for (var i = 0; i < grid.areas.length; i++) { var area = grid.areas[i]; - if(area.name == "areaD") { + if (area.name == "areaD") { is(area.type, "implicit", area.name + " is implicit."); // test lines of implicit areas - todo_is(area.rowStart, 2, area.name + " has start row line of 2."); - todo_is(area.rowEnd, 3, area.name + " has end row line of 3."); - todo_is(area.columnStart, 4, area.name + " has start column line of 4."); - todo_is(area.columnEnd, 5, area.name + " has end column line of 5."); + is(area.rowStart, 3, area.name + " has start row line of 3."); + is(area.rowEnd, 4, area.name + " has end row line of 4."); + is(area.columnStart, 5, area.name + " has start column line of 5."); + is(area.columnEnd, 6, area.name + " has end column line of 6."); } else { is(area.type, "explicit", area.name + " is explicit."); } } + + + // test the second grid wrapper + wrapper = document.getElementById("wrapper2"); + grid = wrapper.getGridFragments()[0]; + + // test column and row line counts + is(grid.cols.lines.length, 4, + "Grid.cols.lines property doesn't expand due to an explicit line declaration." + ); + is(grid.rows.lines.length, 2, + "Grid.rows.lines property has length that respects implicit expansion." + ); + + // test area count + is(grid.areas.length, 1, + "Grid.areas property has length that respects implicit expansion." + ); + + for (var i = 0; i < grid.areas.length; i++) { + var area = grid.areas[i]; + if (area.name == "areaA") { + is(area.type, "implicit", area.name + " is implicit."); + + // test lines of implicit areas + is(area.rowStart, 1, area.name + " has start row line of 1."); + is(area.rowEnd, 2, area.name + " has end row line of 2."); + is(area.columnStart, 1, area.name + " has start column line of 1."); + is(area.columnEnd, 3, area.name + " has end column line of 3."); + } + } + + + // test the third grid wrapper + wrapper = document.getElementById("wrapper3"); + grid = wrapper.getGridFragments()[0]; + + // test column and row line counts + is(grid.cols.lines.length, 2, + "Grid.cols.lines property doesn't expand due to an explicit line declaration." + ); + is(grid.rows.lines.length, 2, + "Grid.rows.lines property doesn't expand due to an explicit line declaration." + ); + + if (grid.cols.lines.length == 2 && grid.rows.lines.length == 2) { + // check that areaC gets both the explicit line names and the implicit line names + isnot(grid.cols.lines[0].names.indexOf("areaC-start"), -1, + "Grid row line 1 has the name 'areaC-start'." + ); + + isnot(grid.cols.lines[0].names.indexOf("areaC-end"), -1, + "Grid row line 1 has the name 'areaC-end'." + ); + + isnot(grid.cols.lines[1].names.indexOf("areaC-start"), -1, + "Grid row line 2 has the name 'areaC-start'." + ); + + isnot(grid.cols.lines[1].names.indexOf("areaC-end"), -1, + "Grid row line 2 has the name 'areaC-end'." + ); + } + + // test area count + is(grid.areas.length, 4, + "Grid.areas property reports 4 areas." + ); + + for (var i = 0; i < grid.areas.length; i++) { + var area = grid.areas[i]; + if (area.name == "areaC") { + // test lines of implicit area + is(area.rowStart, 1, area.name + " has start row line of 1."); + is(area.rowEnd, 2, area.name + " has end row line of 2."); + is(area.columnStart, 1, area.name + " has start column line of 1."); + is(area.columnEnd, 2, area.name + " has end column line of 2."); + } + } SimpleTest.finish(); } @@ -118,12 +227,24 @@ -
+
A
B
C
D
+ +
+ +
+
A
+
+ +
+ +
+
C
+
diff --git a/dom/html/HTMLInputElement.cpp b/dom/html/HTMLInputElement.cpp index 795237e2df76f..88db78ece81fb 100644 --- a/dom/html/HTMLInputElement.cpp +++ b/dom/html/HTMLInputElement.cpp @@ -253,7 +253,7 @@ class DispatchChangeEventCallback final : public GetFilesCallback } mInputElement->SetFilesOrDirectories(array, true); - NS_WARN_IF(NS_FAILED(DispatchEvents())); + Unused << NS_WARN_IF(NS_FAILED(DispatchEvents())); } nsresult @@ -264,7 +264,7 @@ class DispatchChangeEventCallback final : public GetFilesCallback static_cast(mInputElement.get()), NS_LITERAL_STRING("input"), true, false); - NS_WARN_IF(NS_FAILED(rv)); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "DispatchTrustedEvent failed"); rv = nsContentUtils::DispatchTrustedEvent(mInputElement->OwnerDoc(), static_cast(mInputElement.get()), diff --git a/dom/html/nsHTMLContentSink.cpp b/dom/html/nsHTMLContentSink.cpp index af0e8ad2bfabb..ad217b7b522a7 100644 --- a/dom/html/nsHTMLContentSink.cpp +++ b/dom/html/nsHTMLContentSink.cpp @@ -236,7 +236,7 @@ class SinkContext nsresult NS_NewHTMLElement(Element** aResult, already_AddRefed&& aNodeInfo, - FromParser aFromParser, nsAString* aIs) + FromParser aFromParser, const nsAString* aIs) { *aResult = nullptr; diff --git a/dom/indexedDB/test/mochitest.ini b/dom/indexedDB/test/mochitest.ini index 43bd6a1144c18..cb80a9ac47d2b 100644 --- a/dom/indexedDB/test/mochitest.ini +++ b/dom/indexedDB/test/mochitest.ini @@ -96,6 +96,7 @@ support-files = unit/test_setVersion_events.js unit/test_setVersion_exclusion.js unit/test_setVersion_throw.js + unit/test_storage_manager_estimate.js unit/test_success_events_after_abort.js unit/test_table_locks.js unit/test_table_rollback.js @@ -355,6 +356,8 @@ skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116 [test_setVersion_throw.html] skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116 +[test_storage_manager_estimate.html] +skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116 [test_success_events_after_abort.html] skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116 [test_table_locks.html] diff --git a/dom/indexedDB/test/test_storage_manager_estimate.html b/dom/indexedDB/test/test_storage_manager_estimate.html new file mode 100644 index 0000000000000..37a042b010b65 --- /dev/null +++ b/dom/indexedDB/test/test_storage_manager_estimate.html @@ -0,0 +1,19 @@ + + + + Indexed Database Test for StorageManager + + + + + + + + + + + + diff --git a/dom/indexedDB/test/unit/test_storage_manager_estimate.js b/dom/indexedDB/test/unit/test_storage_manager_estimate.js new file mode 100644 index 0000000000000..b9b58714efbe6 --- /dev/null +++ b/dom/indexedDB/test/unit/test_storage_manager_estimate.js @@ -0,0 +1,56 @@ +var testGenerator = testSteps(); + +function testSteps() +{ + const name = this.window ? window.location.pathname : + "test_storage_manager_estimate.js"; + const objectStoreName = "storagesManager"; + const arraySize = 1e6; + + ok('estimate' in navigator.storage, 'Has estimate function'); + is(typeof navigator.storage.estimate, 'function', 'estimate is function'); + ok(navigator.storage.estimate() instanceof Promise, + 'estimate() method exists and returns a Promise'); + + navigator.storage.estimate().then(estimation => { + testGenerator.send(estimation.usage); + }); + + let before = yield undefined; + + let request = indexedDB.open(name, 1); + request.onerror = errorHandler; + request.onupgradeneeded = grabEventAndContinueHandler; + request.onsuccess = continueToNextStep; + let event = yield undefined; + + let db = event.target.result; + db.onerror = errorHandler; + + let objectStore = db.createObjectStore(objectStoreName, { }); + yield undefined; + + navigator.storage.estimate().then(estimation => { + testGenerator.send(estimation.usage); + }); + let usageAfterCreate = yield undefined; + ok(usageAfterCreate > before, 'estimated usage must increase after createObjectStore'); + + let txn = db.transaction(objectStoreName, "readwrite"); + objectStore = txn.objectStore(objectStoreName); + objectStore.put(new Uint8Array(arraySize), 'k'); + txn.oncomplete = continueToNextStep; + txn.onabort = errorHandler; + txn.onerror = errorHandler; + event = yield undefined; + + navigator.storage.estimate().then(estimation => { + testGenerator.send(estimation.usage); + }); + let usageAfterPut = yield undefined; + ok(usageAfterPut > usageAfterCreate, 'estimated usage must increase after putting large object'); + db.close(); + + finishTest(); + yield undefined; +} diff --git a/dom/ipc/ContentChild.cpp b/dom/ipc/ContentChild.cpp index 329d807e1797c..5b76a797d6b07 100644 --- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -20,6 +20,7 @@ #include "mozilla/LookAndFeel.h" #include "mozilla/Preferences.h" #include "mozilla/ProcessHangMonitorIPC.h" +#include "mozilla/Unused.h" #include "mozilla/devtools/HeapSnapshotTempFileHelperChild.h" #include "mozilla/docshell/OfflineCacheUpdateChild.h" #include "mozilla/dom/ContentBridgeChild.h" @@ -513,6 +514,7 @@ ContentChild::ContentChild() : mID(uint64_t(-1)) , mCanOverrideProcessName(true) , mIsAlive(true) + , mShuttingDown(false) { // This process is a content process, so it's clearly running in // multiprocess mode! @@ -863,6 +865,12 @@ ContentChild::IsAlive() const return mIsAlive; } +bool +ContentChild::IsShuttingDown() const +{ + return mShuttingDown; +} + void ContentChild::GetProcessName(nsACString& aName) const { @@ -1045,7 +1053,7 @@ ContentChild::RecvPMemoryReportRequestConstructor( { MemoryReportRequestChild *actor = static_cast(aChild); - nsresult rv; + DebugOnly rv; if (aMinimizeMemoryUsage) { nsCOMPtr mgr = @@ -1057,7 +1065,7 @@ ContentChild::RecvPMemoryReportRequestConstructor( } // Bug 1295622: don't kill the process just because this failed. - NS_WARN_IF(NS_FAILED(rv)); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "actor operation failed"); return true; } @@ -1082,7 +1090,8 @@ NS_IMETHODIMP MemoryReportRequestChild::Run() mgr->GetReportsForThisProcessExtended(handleReport, nullptr, mAnonymize, FileDescriptorToFILE(mDMDFile, "wb"), finishReporting, nullptr); - NS_WARN_IF(NS_FAILED(rv)); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), + "GetReportsForThisProcessExtended failed"); return rv; } @@ -1603,13 +1612,13 @@ ContentChild::RecvNotifyPresentationReceiverLaunched(PBrowserChild* aIframe, { nsCOMPtr docShell = do_GetInterface(static_cast(aIframe)->WebNavigation()); - NS_WARN_IF(!docShell); + NS_WARNING_ASSERTION(docShell, "WebNavigation failed"); nsCOMPtr service = do_GetService(PRESENTATION_SERVICE_CONTRACTID); - NS_WARN_IF(!service); + NS_WARNING_ASSERTION(service, "presentation service is missing"); - NS_WARN_IF(NS_FAILED(static_cast(service.get())->MonitorResponderLoading(aSessionId, docShell))); + Unused << NS_WARN_IF(NS_FAILED(static_cast(service.get())->MonitorResponderLoading(aSessionId, docShell))); return true; } @@ -1619,9 +1628,9 @@ ContentChild::RecvNotifyPresentationReceiverCleanUp(const nsString& aSessionId) { nsCOMPtr service = do_GetService(PRESENTATION_SERVICE_CONTRACTID); - NS_WARN_IF(!service); + NS_WARNING_ASSERTION(service, "presentation service is missing"); - NS_WARN_IF(NS_FAILED(service->UntrackSessionInfo(aSessionId, nsIPresentationService::ROLE_RECEIVER))); + Unused << NS_WARN_IF(NS_FAILED(service->UntrackSessionInfo(aSessionId, nsIPresentationService::ROLE_RECEIVER))); return true; } @@ -2988,6 +2997,8 @@ ContentChild::RecvShutdown() } } + mShuttingDown = true; + if (mPolicy) { mPolicy->Deactivate(); mPolicy = nullptr; diff --git a/dom/ipc/ContentChild.h b/dom/ipc/ContentChild.h index b5157fae744ae..b86e4e1d312d4 100644 --- a/dom/ipc/ContentChild.h +++ b/dom/ipc/ContentChild.h @@ -116,6 +116,8 @@ class ContentChild final : public PContentChild bool IsAlive() const; + bool IsShuttingDown() const; + static void AppendProcessId(nsACString& aName); ContentBridgeParent* GetLastBridge() @@ -682,7 +684,9 @@ class ContentChild final : public PContentChild // Hashtable to keep track of the pending GetFilesHelper objects. // This GetFilesHelperChild objects are removed when RecvGetFilesResponse is // received. - nsRefPtrHashtable mGetFilesPendingRequests; + nsRefPtrHashtable mGetFilesPendingRequests; + + bool mShuttingDown; DISALLOW_EVIL_CONSTRUCTORS(ContentChild); }; diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index 4ee3c15bc174d..bcdee53d2d3cd 100644 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -358,7 +358,7 @@ MemoryReportRequestParent::MemoryReportRequestParent(uint32_t aGeneration) { MOZ_COUNT_CTOR(MemoryReportRequestParent); mReporterManager = nsMemoryReporterManager::GetOrCreate(); - NS_WARN_IF(!mReporterManager); + NS_WARNING_ASSERTION(mReporterManager, "GetOrCreate failed"); } bool diff --git a/dom/ipc/ContentProcess.cpp b/dom/ipc/ContentProcess.cpp index 4a4697e2c0e99..978534fc3cfa8 100644 --- a/dom/ipc/ContentProcess.cpp +++ b/dom/ipc/ContentProcess.cpp @@ -49,10 +49,10 @@ SetTmpEnvironmentVariable(nsIFile* aValue) if (NS_WARN_IF(NS_FAILED(rv))) { return; } - NS_WARN_IF(!SetEnvironmentVariableW(L"TMP", fullTmpPath.get())); + Unused << NS_WARN_IF(!SetEnvironmentVariableW(L"TMP", fullTmpPath.get())); // We also set TEMP in case there is naughty third-party code that is // referencing the environment variable directly. - NS_WARN_IF(!SetEnvironmentVariableW(L"TEMP", fullTmpPath.get())); + Unused << NS_WARN_IF(!SetEnvironmentVariableW(L"TEMP", fullTmpPath.get())); } #endif @@ -72,7 +72,7 @@ SetTmpEnvironmentVariable(nsIFile* aValue) if (NS_WARN_IF(NS_FAILED(rv))) { return; } - NS_WARN_IF(setenv("TMPDIR", fullTmpPath.get(), 1) != 0); + Unused << NS_WARN_IF(setenv("TMPDIR", fullTmpPath.get(), 1) != 0); } #endif diff --git a/dom/ipc/TabParent.cpp b/dom/ipc/TabParent.cpp index 41d61a20af639..811142f84f057 100644 --- a/dom/ipc/TabParent.cpp +++ b/dom/ipc/TabParent.cpp @@ -1983,8 +1983,9 @@ void TabParent::HandledWindowedPluginKeyEvent(const NativeEventData& aKeyEventData, bool aIsConsumed) { - bool ok = SendHandledWindowedPluginKeyEvent(aKeyEventData, aIsConsumed); - NS_WARN_IF(!ok); + DebugOnly ok = + SendHandledWindowedPluginKeyEvent(aKeyEventData, aIsConsumed); + NS_WARNING_ASSERTION(ok, "SendHandledWindowedPluginKeyEvent failed"); } bool diff --git a/dom/media/AudioStream.cpp b/dom/media/AudioStream.cpp index 9ed2c593c30d7..4abba4f8c97de 100644 --- a/dom/media/AudioStream.cpp +++ b/dom/media/AudioStream.cpp @@ -530,7 +530,8 @@ AudioStream::GetUnprocessed(AudioBufferWriter& aWriter) // TODO: There might be still unprocessed samples in the stretcher. // We should either remove or flush them so they won't be in the output // next time we switch a playback rate other than 1.0. - NS_WARN_IF(mTimeStretcher->numUnprocessedSamples() > 0); + NS_WARNING_ASSERTION( + mTimeStretcher->numUnprocessedSamples() == 0, "no samples"); } while (aWriter.Available() > 0) { diff --git a/dom/media/MediaSegment.h b/dom/media/MediaSegment.h index cac52ba01b8c1..5c4805b30310d 100644 --- a/dom/media/MediaSegment.h +++ b/dom/media/MediaSegment.h @@ -401,6 +401,14 @@ template class MediaSegmentBase : public MediaSegment { return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf); } + Chunk* GetLastChunk() + { + if (mChunks.IsEmpty()) { + return nullptr; + } + return &mChunks[mChunks.Length() - 1]; + } + protected: explicit MediaSegmentBase(Type aType) : MediaSegment(aType) {} @@ -448,14 +456,6 @@ template class MediaSegmentBase : public MediaSegment { return c; } - Chunk* GetLastChunk() - { - if (mChunks.IsEmpty()) { - return nullptr; - } - return &mChunks[mChunks.Length() - 1]; - } - void RemoveLeading(StreamTime aDuration, uint32_t aStartIndex) { NS_ASSERTION(aDuration >= 0, "Can't remove negative duration"); diff --git a/dom/media/MediaStreamGraph.cpp b/dom/media/MediaStreamGraph.cpp index acc4273b96e26..239a74df6fbdc 100644 --- a/dom/media/MediaStreamGraph.cpp +++ b/dom/media/MediaStreamGraph.cpp @@ -2611,7 +2611,7 @@ MediaStream::AddMainThreadListener(MainThreadMediaStreamListener* aListener) }; nsCOMPtr runnable = new NotifyRunnable(this); - NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(runnable.forget()))); + Unused << NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(runnable.forget()))); } SourceMediaStream::SourceMediaStream() : @@ -2889,7 +2889,25 @@ SourceMediaStream::AddDirectTrackListenerImpl(already_AddRefedAsMediaStreamVideoSink(); // Re-send missed VideoSegment to new added MediaStreamVideoSink. if (streamTrack->GetType() == MediaSegment::VIDEO && videoSink) { - videoSink->SetCurrentFrames(*(static_cast(streamTrack->GetSegment()))); + VideoSegment videoSegment; + if (mTracks.GetForgottenDuration() < streamTrack->GetSegment()->GetDuration()) { + videoSegment.AppendSlice(*streamTrack->GetSegment(), + mTracks.GetForgottenDuration(), + streamTrack->GetSegment()->GetDuration()); + } else { + VideoSegment* streamTrackSegment = static_cast(streamTrack->GetSegment()); + VideoChunk* lastChunk = streamTrackSegment->GetLastChunk(); + if (lastChunk) { + StreamTime startTime = streamTrackSegment->GetDuration() - lastChunk->GetDuration(); + videoSegment.AppendSlice(*streamTrackSegment, + startTime, + streamTrackSegment->GetDuration()); + } + } + if (found) { + videoSegment.AppendSlice(*data->mData, 0, data->mData->GetDuration()); + } + videoSink->SetCurrentFrames(videoSegment); } } diff --git a/dom/media/TextTrackList.cpp b/dom/media/TextTrackList.cpp index 822e7c109dc75..eb72e36cd3cc4 100644 --- a/dom/media/TextTrackList.cpp +++ b/dom/media/TextTrackList.cpp @@ -188,7 +188,7 @@ TextTrackList::CreateAndDispatchTrackEventRunner(TextTrack* aTrack, NS_DISPATCH_NORMAL); // If we are shutting down this can file but it's still ok. - NS_WARN_IF(NS_FAILED(rv)); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Dispatch failed"); } HTMLMediaElement* diff --git a/dom/media/VideoSegment.h b/dom/media/VideoSegment.h index 6e871d244b1bb..f6f6043eb0cee 100644 --- a/dom/media/VideoSegment.h +++ b/dom/media/VideoSegment.h @@ -94,7 +94,7 @@ struct VideoChunk { StreamTime mDuration; VideoFrame mFrame; - mozilla::TimeStamp mTimeStamp; + TimeStamp mTimeStamp; }; class VideoSegment : public MediaSegmentBase { diff --git a/dom/media/platforms/wmf/DXVA2Manager.cpp b/dom/media/platforms/wmf/DXVA2Manager.cpp index a1e86d0d040f3..a8c267fcf391e 100644 --- a/dom/media/platforms/wmf/DXVA2Manager.cpp +++ b/dom/media/platforms/wmf/DXVA2Manager.cpp @@ -279,6 +279,11 @@ D3D9DXVA2Manager::Init(nsACString& aFailureReason) NS_ENSURE_TRUE(d3d9lib, E_FAIL); decltype(Direct3DCreate9Ex)* d3d9Create = (decltype(Direct3DCreate9Ex)*) GetProcAddress(d3d9lib, "Direct3DCreate9Ex"); + if (!d3d9Create) { + NS_WARNING("Couldn't find Direct3DCreate9Ex symbol in d3d9.dll"); + aFailureReason.AssignLiteral("Couldn't find Direct3DCreate9Ex symbol in d3d9.dll"); + return E_FAIL; + } RefPtr d3d9Ex; HRESULT hr = d3d9Create(D3D_SDK_VERSION, getter_AddRefs(d3d9Ex)); if (!d3d9Ex) { diff --git a/dom/media/webrtc/MediaTrackConstraints.h b/dom/media/webrtc/MediaTrackConstraints.h index 302d9a1039da8..842fea0d2dccb 100644 --- a/dom/media/webrtc/MediaTrackConstraints.h +++ b/dom/media/webrtc/MediaTrackConstraints.h @@ -14,6 +14,7 @@ #include #include +#include namespace mozilla { diff --git a/dom/mobileconnection/ipc/MobileConnectionIPCSerializer.h b/dom/mobileconnection/ipc/MobileConnectionIPCSerializer.h index f7ee3b6ab1ac5..a3f2907cad5bc 100644 --- a/dom/mobileconnection/ipc/MobileConnectionIPCSerializer.h +++ b/dom/mobileconnection/ipc/MobileConnectionIPCSerializer.h @@ -13,6 +13,7 @@ #include "mozilla/dom/MobileConnectionInfo.h" #include "mozilla/dom/MobileNetworkInfo.h" #include "mozilla/dom/MozMobileConnectionBinding.h" +#include "mozilla/dom/ScriptSettings.h" using mozilla::AutoJSContext; using mozilla::dom::mobileconnection::MobileCallForwardingOptions; diff --git a/dom/mobilemessage/MmsMessage.cpp b/dom/mobilemessage/MmsMessage.cpp index 6d0e0bc33973b..c1dddcd167a11 100644 --- a/dom/mobilemessage/MmsMessage.cpp +++ b/dom/mobilemessage/MmsMessage.cpp @@ -8,6 +8,7 @@ #include "MmsMessageInternal.h" #include "mozilla/dom/MmsMessageBinding.h" +#include "nsPIDOMWindow.h" using namespace mozilla::dom::mobilemessage; diff --git a/dom/network/TCPSocket.cpp b/dom/network/TCPSocket.cpp index 8da501e97e4b2..4eb2f72f61235 100644 --- a/dom/network/TCPSocket.cpp +++ b/dom/network/TCPSocket.cpp @@ -768,7 +768,7 @@ TCPSocket::MaybeReportErrorAndCloseIfOpen(nsresult status) { } } - NS_WARN_IF(NS_FAILED(FireErrorEvent(errName, errorType))); + Unused << NS_WARN_IF(NS_FAILED(FireErrorEvent(errName, errorType))); } return FireEvent(NS_LITERAL_STRING("close")); diff --git a/dom/network/UDPSocket.cpp b/dom/network/UDPSocket.cpp index 22f20cf181c82..e275e39029368 100644 --- a/dom/network/UDPSocket.cpp +++ b/dom/network/UDPSocket.cpp @@ -230,7 +230,7 @@ UDPSocket::JoinMulticastGroup(const nsAString& aMulticastGroupAddress, MOZ_ASSERT(!mSocketChild); aRv = mSocket->JoinMulticast(address, EmptyCString()); - NS_WARN_IF(aRv.Failed()); + NS_WARNING_ASSERTION(!aRv.Failed(), "JoinMulticast failed"); return; } @@ -238,7 +238,7 @@ UDPSocket::JoinMulticastGroup(const nsAString& aMulticastGroupAddress, MOZ_ASSERT(mSocketChild); aRv = mSocketChild->JoinMulticast(address, EmptyCString()); - NS_WARN_IF(aRv.Failed()); + NS_WARNING_ASSERTION(!aRv.Failed(), "JoinMulticast failed"); } void @@ -263,14 +263,14 @@ UDPSocket::LeaveMulticastGroup(const nsAString& aMulticastGroupAddress, MOZ_ASSERT(!mSocketChild); aRv = mSocket->LeaveMulticast(address, EmptyCString()); - NS_WARN_IF(aRv.Failed()); + NS_WARNING_ASSERTION(!aRv.Failed(), "mSocket->LeaveMulticast failed"); return; } MOZ_ASSERT(mSocketChild); aRv = mSocketChild->LeaveMulticast(address, EmptyCString()); - NS_WARN_IF(aRv.Failed()); + NS_WARNING_ASSERTION(!aRv.Failed(), "mSocketChild->LeaveMulticast failed"); } nsresult diff --git a/dom/network/UDPSocketParent.cpp b/dom/network/UDPSocketParent.cpp index 77c6552e62116..739f0e25b20a0 100644 --- a/dom/network/UDPSocketParent.cpp +++ b/dom/network/UDPSocketParent.cpp @@ -293,13 +293,14 @@ bool UDPSocketParent::RecvConnect(const UDPAddressInfo& aAddressInfo) { nsCOMPtr thread(NS_GetCurrentThread()); - NS_WARN_IF(NS_FAILED(GetSTSThread()->Dispatch(WrapRunnable( - this, - &UDPSocketParent::DoConnect, - mSocket, - thread, - aAddressInfo), - NS_DISPATCH_NORMAL))); + Unused << + NS_WARN_IF(NS_FAILED(GetSTSThread()->Dispatch(WrapRunnable( + this, + &UDPSocketParent::DoConnect, + mSocket, + thread, + aAddressInfo), + NS_DISPATCH_NORMAL))); return true; } @@ -314,11 +315,12 @@ void UDPSocketParent::SendConnectResponse(nsIEventTarget *aThread, const UDPAddressInfo& aAddressInfo) { - NS_WARN_IF(NS_FAILED(aThread->Dispatch(WrapRunnable( - this, - &UDPSocketParent::DoSendConnectResponse, - aAddressInfo), - NS_DISPATCH_NORMAL))); + Unused << + NS_WARN_IF(NS_FAILED(aThread->Dispatch(WrapRunnable( + this, + &UDPSocketParent::DoSendConnectResponse, + aAddressInfo), + NS_DISPATCH_NORMAL))); } // Runs on STS thread @@ -623,11 +625,12 @@ UDPSocketParent::SendInternalError(nsIEventTarget *aThread, uint32_t aLineNo) { UDPSOCKET_LOG(("SendInternalError: %u", aLineNo)); - NS_WARN_IF(NS_FAILED(aThread->Dispatch(WrapRunnable( - this, - &UDPSocketParent::FireInternalError, - aLineNo), - NS_DISPATCH_NORMAL))); + Unused << + NS_WARN_IF(NS_FAILED(aThread->Dispatch(WrapRunnable( + this, + &UDPSocketParent::FireInternalError, + aLineNo), + NS_DISPATCH_NORMAL))); } } // namespace dom diff --git a/dom/plugins/base/nsNPAPIPluginInstance.cpp b/dom/plugins/base/nsNPAPIPluginInstance.cpp index 8c80c3efe9c3e..4d67d0e6da0b7 100644 --- a/dom/plugins/base/nsNPAPIPluginInstance.cpp +++ b/dom/plugins/base/nsNPAPIPluginInstance.cpp @@ -1807,7 +1807,7 @@ nsNPAPIPluginInstance::WindowVolumeChanged(float aVolume, bool aMuted) { // We just support mute/unmute nsresult rv = SetMuted(aMuted); - NS_WARN_IF(NS_FAILED(rv)); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "SetMuted failed"); return rv; } diff --git a/dom/plugins/base/nsPluginInstanceOwner.cpp b/dom/plugins/base/nsPluginInstanceOwner.cpp index 36049f71573a8..389a04d71404f 100644 --- a/dom/plugins/base/nsPluginInstanceOwner.cpp +++ b/dom/plugins/base/nsPluginInstanceOwner.cpp @@ -985,9 +985,9 @@ nsPluginInstanceOwner::HandledWindowedPluginKeyEvent( if (NS_WARN_IF(!mInstance)) { return; } - nsresult rv = + DebugOnly rv = mInstance->HandledWindowedPluginKeyEvent(aKeyEventData, aIsConsumed); - NS_WARN_IF(NS_FAILED(rv)); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "HandledWindowedPluginKeyEvent fail"); } void diff --git a/dom/plugins/ipc/PluginInstanceChild.cpp b/dom/plugins/ipc/PluginInstanceChild.cpp index f51fbac8c7c7b..85e8485e04633 100644 --- a/dom/plugins/ipc/PluginInstanceChild.cpp +++ b/dom/plugins/ipc/PluginInstanceChild.cpp @@ -1677,7 +1677,8 @@ PluginInstanceChild::PluginWindowProcInternal(HWND hWnd, // If this gets focus, ensure that there is no pending key events. // Even if there were, we should ignore them for performance reason. // Although, such case shouldn't occur. - NS_WARN_IF(self->mPostingKeyEvents > 0); + NS_WARNING_ASSERTION(self->mPostingKeyEvents == 0, + "pending events"); self->mPostingKeyEvents = 0; self->mLastKeyEventConsumed = false; break; diff --git a/dom/plugins/ipc/PluginWidgetChild.cpp b/dom/plugins/ipc/PluginWidgetChild.cpp index 75c88f6fe393c..9e42b0c9a8cc8 100644 --- a/dom/plugins/ipc/PluginWidgetChild.cpp +++ b/dom/plugins/ipc/PluginWidgetChild.cpp @@ -43,7 +43,7 @@ PluginWidgetChild::RecvSetScrollCaptureId(const uint64_t& aScrollCaptureId, PluginInstanceParent* instance = PluginInstanceParent::LookupPluginInstanceByID(aPluginInstanceId); if (instance) { - NS_WARN_IF(NS_FAILED(instance->SetScrollCaptureId(aScrollCaptureId))); + Unused << NS_WARN_IF(NS_FAILED(instance->SetScrollCaptureId(aScrollCaptureId))); } return true; diff --git a/dom/presentation/PresentationAvailability.cpp b/dom/presentation/PresentationAvailability.cpp index 7cb0ead1b3f3a..9c46bba0802ca 100644 --- a/dom/presentation/PresentationAvailability.cpp +++ b/dom/presentation/PresentationAvailability.cpp @@ -8,6 +8,7 @@ #include "mozilla/dom/PresentationAvailabilityBinding.h" #include "mozilla/dom/Promise.h" +#include "mozilla/Unused.h" #include "nsCycleCollectionParticipant.h" #include "nsIPresentationDeviceManager.h" #include "nsIPresentationService.h" @@ -100,8 +101,8 @@ void PresentationAvailability::Shutdown() return; } - nsresult rv = service->UnregisterAvailabilityListener(this); - NS_WARN_IF(NS_FAILED(rv)); + Unused << + NS_WARN_IF(NS_FAILED(service->UnregisterAvailabilityListener(this))); } /* virtual */ void @@ -186,6 +187,7 @@ PresentationAvailability::UpdateAvailabilityAndDispatchEvent(bool aIsAvailable) } if (isChanged) { - NS_WARN_IF(NS_FAILED(DispatchTrustedEvent(NS_LITERAL_STRING("change")))); + Unused << + NS_WARN_IF(NS_FAILED(DispatchTrustedEvent(NS_LITERAL_STRING("change")))); } } diff --git a/dom/presentation/PresentationConnection.cpp b/dom/presentation/PresentationConnection.cpp index edc317a7ddeec..5d8cafd984bcc 100644 --- a/dom/presentation/PresentationConnection.cpp +++ b/dom/presentation/PresentationConnection.cpp @@ -13,6 +13,7 @@ #include "mozilla/dom/MessageEventBinding.h" #include "mozilla/dom/PresentationConnectionClosedEvent.h" #include "mozilla/ErrorNames.h" +#include "mozilla/DebugOnly.h" #include "nsContentUtils.h" #include "nsCycleCollectionParticipant.h" #include "nsIPresentationService.h" @@ -124,11 +125,11 @@ PresentationConnection::Shutdown() return; } - nsresult rv = service->UnregisterSessionListener(mId, mRole); - NS_WARN_IF(NS_FAILED(rv)); + DebugOnly rv = service->UnregisterSessionListener(mId, mRole); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "UnregisterSessionListener failed"); - rv = RemoveFromLoadGroup(); - NS_WARN_IF(NS_FAILED(rv)); + DebugOnly rv2 = RemoveFromLoadGroup(); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv2), "RemoveFromLoadGroup failed"); if (mRole == nsIPresentationService::ROLE_CONTROLLER) { ControllerConnectionCollection::GetSingleton()->RemoveConnection(this, @@ -139,7 +140,7 @@ PresentationConnection::Shutdown() /* virtual */ void PresentationConnection::DisconnectFromOwner() { - NS_WARN_IF(NS_FAILED(ProcessConnectionWentAway())); + Unused << NS_WARN_IF(NS_FAILED(ProcessConnectionWentAway())); DOMEventTargetHelper::DisconnectFromOwner(); } @@ -207,7 +208,7 @@ PresentationConnection::Close(ErrorResult& aRv) return; } - NS_WARN_IF(NS_FAILED( + Unused << NS_WARN_IF(NS_FAILED( service->CloseSession(mId, mRole, nsIPresentationService::CLOSED_REASON_CLOSED))); @@ -228,7 +229,7 @@ PresentationConnection::Terminate(ErrorResult& aRv) return; } - NS_WARN_IF(NS_FAILED(service->TerminateSession(mId, mRole))); + Unused << NS_WARN_IF(NS_FAILED(service->TerminateSession(mId, mRole))); } bool @@ -319,7 +320,8 @@ PresentationConnection::ProcessStateChanged(nsresult aReason) CopyUTF8toUTF16(message, errorMsg); } - NS_WARN_IF(NS_FAILED(DispatchConnectionClosedEvent(reason, errorMsg))); + Unused << + NS_WARN_IF(NS_FAILED(DispatchConnectionClosedEvent(reason, errorMsg))); return RemoveFromLoadGroup(); } @@ -327,7 +329,7 @@ PresentationConnection::ProcessStateChanged(nsresult aReason) // Ensure onterminate event is fired. RefPtr asyncDispatcher = new AsyncEventDispatcher(this, NS_LITERAL_STRING("terminate"), false); - NS_WARN_IF(NS_FAILED(asyncDispatcher->PostDOMEvent())); + Unused << NS_WARN_IF(NS_FAILED(asyncDispatcher->PostDOMEvent())); nsCOMPtr service = do_GetService(PRESENTATION_SERVICE_CONTRACTID); diff --git a/dom/presentation/PresentationReceiver.cpp b/dom/presentation/PresentationReceiver.cpp index 09c89eedc230f..295eeac0f01a8 100644 --- a/dom/presentation/PresentationReceiver.cpp +++ b/dom/presentation/PresentationReceiver.cpp @@ -76,8 +76,8 @@ void PresentationReceiver::Shutdown() return; } - nsresult rv = service->UnregisterRespondingListener(mWindowId); - NS_WARN_IF(NS_FAILED(rv)); + Unused << + NS_WARN_IF(NS_FAILED(service->UnregisterRespondingListener(mWindowId))); } /* virtual */ JSObject* diff --git a/dom/presentation/PresentationService.cpp b/dom/presentation/PresentationService.cpp index 2479d093855ba..62cde0d16bc89 100644 --- a/dom/presentation/PresentationService.cpp +++ b/dom/presentation/PresentationService.cpp @@ -609,7 +609,8 @@ PresentationService::NotifyAvailableChange(bool aIsAvailable) nsTObserverArray>::ForwardIterator iter(mAvailabilityListeners); while (iter.HasMore()) { nsCOMPtr listener = iter.GetNext(); - NS_WARN_IF(NS_FAILED(listener->NotifyAvailableChange(aIsAvailable))); + Unused << + NS_WARN_IF(NS_FAILED(listener->NotifyAvailableChange(aIsAvailable))); } } @@ -877,7 +878,8 @@ PresentationService::RegisterAvailabilityListener(nsIPresentationAvailabilityLis // Leverage availablility change notification to assign // the initial value of availability object. - NS_WARN_IF(NS_FAILED(aListener->NotifyAvailableChange(mIsAvailable))); + Unused << + NS_WARN_IF(NS_FAILED(aListener->NotifyAvailableChange(mIsAvailable))); return NS_OK; } @@ -937,7 +939,7 @@ PresentationService::UnregisterSessionListener(const nsAString& aSessionId, if (info) { // When content side decide not handling this session anymore, simply // close the connection. Session info is kept for reconnection. - NS_WARN_IF(NS_FAILED(info->Close(NS_OK, nsIPresentationSessionListener::STATE_CLOSED))); + Unused << NS_WARN_IF(NS_FAILED(info->Close(NS_OK, nsIPresentationSessionListener::STATE_CLOSED))); return info->SetListener(nullptr); } return NS_OK; diff --git a/dom/presentation/PresentationSessionInfo.cpp b/dom/presentation/PresentationSessionInfo.cpp index a902e2a12dab4..0c15718b10228 100644 --- a/dom/presentation/PresentationSessionInfo.cpp +++ b/dom/presentation/PresentationSessionInfo.cpp @@ -225,17 +225,17 @@ PresentationSessionInfo::Shutdown(nsresult aReason) PRES_DEBUG("%s:id[%s], reason[%x], role[%d]\n", __func__, NS_ConvertUTF16toUTF8(mSessionId).get(), aReason, mRole); - NS_WARN_IF(NS_FAILED(aReason)); + NS_WARNING_ASSERTION(NS_SUCCEEDED(aReason), "bad reason"); // Close the control channel if any. if (mControlChannel) { - NS_WARN_IF(NS_FAILED(mControlChannel->Disconnect(aReason))); + Unused << NS_WARN_IF(NS_FAILED(mControlChannel->Disconnect(aReason))); } // Close the data transport channel if any. if (mTransport) { // |mIsTransportReady| will be unset once |NotifyTransportClosed| is called. - NS_WARN_IF(NS_FAILED(mTransport->Close(aReason))); + Unused << NS_WARN_IF(NS_FAILED(mTransport->Close(aReason))); } mIsResponderReady = false; @@ -248,7 +248,7 @@ nsresult PresentationSessionInfo::SetListener(nsIPresentationSessionListener* aListener) { if (mListener && aListener) { - NS_WARN_IF(NS_FAILED(mListener->NotifyReplaced())); + Unused << NS_WARN_IF(NS_FAILED(mListener->NotifyReplaced())); } mListener = aListener; @@ -606,7 +606,7 @@ PresentationControllingInfo::Shutdown(nsresult aReason) // Close the server socket if any. if (mServerSocket) { - NS_WARN_IF(NS_FAILED(mServerSocket->Close())); + Unused << NS_WARN_IF(NS_FAILED(mServerSocket->Close())); mServerSocket = nullptr; } @@ -879,7 +879,7 @@ PresentationControllingInfo::NotifyDisconnected(nsresult aReason) nsCOMPtr builder = do_QueryInterface(mBuilder); if (builder) { - NS_WARN_IF(NS_FAILED(builder->NotifyDisconnected(aReason))); + Unused << NS_WARN_IF(NS_FAILED(builder->NotifyDisconnected(aReason))); } } @@ -1152,7 +1152,7 @@ PresentationPresentingInfo::OnSessionTransport(nsIPresentationSessionTransport* // description for the answer, which is not actually checked at requester side. nsCOMPtr selfAddr; rv = mTransport->GetSelfAddress(getter_AddRefs(selfAddr)); - NS_WARN_IF(NS_FAILED(rv)); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "GetSelfAddress failed"); nsCString address; uint16_t port = 0; @@ -1282,7 +1282,7 @@ PresentationPresentingInfo::UntrackFromService() { // Remove the OOP responding info (if it has never been used). if (mContentParent) { - NS_WARN_IF(!static_cast(mContentParent.get())->SendNotifyPresentationReceiverCleanUp(mSessionId)); + Unused << NS_WARN_IF(!static_cast(mContentParent.get())->SendNotifyPresentationReceiverCleanUp(mSessionId)); } // Remove the session info (and the in-process responding info if there's any). @@ -1427,7 +1427,7 @@ PresentationPresentingInfo::NotifyDisconnected(nsresult aReason) nsCOMPtr builder = do_QueryInterface(mBuilder); if (builder) { - NS_WARN_IF(NS_FAILED(builder->NotifyDisconnected(aReason))); + Unused << NS_WARN_IF(NS_FAILED(builder->NotifyDisconnected(aReason))); } } @@ -1502,7 +1502,7 @@ PresentationPresentingInfo::ResolvedCallback(JSContext* aCx, // Notify the content process that a receiver page has launched, so it can // start monitoring the loading progress. mContentParent = tabParent->Manager(); - NS_WARN_IF(!static_cast(mContentParent.get())->SendNotifyPresentationReceiverLaunched(tabParent, mSessionId)); + Unused << NS_WARN_IF(!static_cast(mContentParent.get())->SendNotifyPresentationReceiverLaunched(tabParent, mSessionId)); } else { // In-process frame nsCOMPtr docShell; diff --git a/dom/presentation/PresentationSessionInfo.h b/dom/presentation/PresentationSessionInfo.h index 87e349a619a84..8d9aec7212bd8 100644 --- a/dom/presentation/PresentationSessionInfo.h +++ b/dom/presentation/PresentationSessionInfo.h @@ -11,6 +11,7 @@ #include "mozilla/dom/nsIContentParent.h" #include "mozilla/dom/Promise.h" #include "mozilla/dom/PromiseNativeHandler.h" +#include "mozilla/DebugOnly.h" #include "mozilla/RefPtr.h" #include "nsCOMPtr.h" #include "nsINetworkInfoService.h" @@ -140,8 +141,9 @@ class PresentationSessionInfo : public nsIPresentationSessionTransportCallback // Notify session state change. if (mListener) { - nsresult rv = mListener->NotifyStateChange(mSessionId, mState, aReason); - NS_WARN_IF(NS_FAILED(rv)); + DebugOnly rv = + mListener->NotifyStateChange(mSessionId, mState, aReason); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NotifyStateChanged"); } } diff --git a/dom/presentation/PresentationTCPSessionTransport.cpp b/dom/presentation/PresentationTCPSessionTransport.cpp index c1ab484c507c9..18218e5c8a18c 100644 --- a/dom/presentation/PresentationTCPSessionTransport.cpp +++ b/dom/presentation/PresentationTCPSessionTransport.cpp @@ -331,7 +331,7 @@ PresentationTCPSessionTransport::SetCallback(nsIPresentationSessionTransportCall if (!!mCallback && ReadyState::OPEN == mReadyState) { // Notify the transport channel is ready. - NS_WARN_IF(NS_FAILED(mCallback->NotifyTransportReady())); + Unused << NS_WARN_IF(NS_FAILED(mCallback->NotifyTransportReady())); } return NS_OK; @@ -356,7 +356,7 @@ PresentationTCPSessionTransport::EnsureCopying() mAsyncCopierActive = true; RefPtr callbacks = new CopierCallbacks(this); - NS_WARN_IF(NS_FAILED(mMultiplexStreamCopier->AsyncCopy(callbacks, nullptr))); + Unused << NS_WARN_IF(NS_FAILED(mMultiplexStreamCopier->AsyncCopy(callbacks, nullptr))); } void @@ -458,14 +458,15 @@ PresentationTCPSessionTransport::SetReadyState(ReadyState aReadyState) } // Notify the transport channel is ready. - NS_WARN_IF(NS_FAILED(mCallback->NotifyTransportReady())); + Unused << NS_WARN_IF(NS_FAILED(mCallback->NotifyTransportReady())); } else if (mReadyState == ReadyState::CLOSED && mCallback) { if (NS_WARN_IF(!mCallback)) { return; } // Notify the transport channel has been shut down. - NS_WARN_IF(NS_FAILED(mCallback->NotifyTransportClosed(mCloseStatus))); + Unused << + NS_WARN_IF(NS_FAILED(mCallback->NotifyTransportClosed(mCloseStatus))); mCallback = nullptr; } } diff --git a/dom/presentation/ipc/PresentationBuilderChild.cpp b/dom/presentation/ipc/PresentationBuilderChild.cpp index f6d7f65687a6d..788ebb064af10 100644 --- a/dom/presentation/ipc/PresentationBuilderChild.cpp +++ b/dom/presentation/ipc/PresentationBuilderChild.cpp @@ -10,6 +10,7 @@ #include "PresentationBuilderChild.h" #include "PresentationIPCService.h" #include "nsServiceManagerUtils.h" +#include "mozilla/Unused.h" namespace mozilla { namespace dom { @@ -110,10 +111,10 @@ PresentationBuilderChild::OnSessionTransport(nsIPresentationSessionTransport* aT nsCOMPtr service = do_GetService(PRESENTATION_SERVICE_CONTRACTID); - NS_WARN_IF(!service); + NS_WARNING_ASSERTION(service, "no presentation service"); if (service) { - NS_WARN_IF(NS_FAILED(static_cast(service.get())-> - NotifySessionTransport(mSessionId, mRole, aTransport))); + Unused << NS_WARN_IF(NS_FAILED(static_cast(service.get())-> + NotifySessionTransport(mSessionId, mRole, aTransport))); } mBuilder = nullptr; return NS_OK; diff --git a/dom/presentation/ipc/PresentationBuilderParent.cpp b/dom/presentation/ipc/PresentationBuilderParent.cpp index ed269fcfbae22..7a2e7608ea56e 100644 --- a/dom/presentation/ipc/PresentationBuilderParent.cpp +++ b/dom/presentation/ipc/PresentationBuilderParent.cpp @@ -26,7 +26,7 @@ PresentationBuilderParent::~PresentationBuilderParent() MOZ_COUNT_DTOR(PresentationBuilderParent); if (mNeedDestroyActor) { - NS_WARN_IF(!Send__delete__(this)); + Unused << NS_WARN_IF(!Send__delete__(this)); } } @@ -152,8 +152,9 @@ PresentationBuilderParent::RecvOnSessionTransport() { // To avoid releasing |this| in this method NS_DispatchToMainThread(NS_NewRunnableFunction([this]() -> void { - NS_WARN_IF(!mBuilderListener || - NS_FAILED(mBuilderListener->OnSessionTransport(nullptr))); + Unused << + NS_WARN_IF(!mBuilderListener || + NS_FAILED(mBuilderListener->OnSessionTransport(nullptr))); })); nsCOMPtr diff --git a/dom/presentation/ipc/PresentationChild.cpp b/dom/presentation/ipc/PresentationChild.cpp index 9976a17da0db9..7e430b1140288 100644 --- a/dom/presentation/ipc/PresentationChild.cpp +++ b/dom/presentation/ipc/PresentationChild.cpp @@ -92,7 +92,7 @@ bool PresentationChild::RecvNotifyAvailableChange(const bool& aAvailable) { if (mService) { - NS_WARN_IF(NS_FAILED(mService->NotifyAvailableChange(aAvailable))); + Unused << NS_WARN_IF(NS_FAILED(mService->NotifyAvailableChange(aAvailable))); } return true; } @@ -103,9 +103,9 @@ PresentationChild::RecvNotifySessionStateChange(const nsString& aSessionId, const nsresult& aReason) { if (mService) { - NS_WARN_IF(NS_FAILED(mService->NotifySessionStateChange(aSessionId, - aState, - aReason))); + Unused << NS_WARN_IF(NS_FAILED(mService->NotifySessionStateChange(aSessionId, + aState, + aReason))); } return true; } @@ -115,7 +115,7 @@ PresentationChild::RecvNotifyMessage(const nsString& aSessionId, const nsCString& aData) { if (mService) { - NS_WARN_IF(NS_FAILED(mService->NotifyMessage(aSessionId, aData))); + Unused << NS_WARN_IF(NS_FAILED(mService->NotifyMessage(aSessionId, aData))); } return true; } @@ -125,7 +125,7 @@ PresentationChild::RecvNotifySessionConnect(const uint64_t& aWindowId, const nsString& aSessionId) { if (mService) { - NS_WARN_IF(NS_FAILED(mService->NotifySessionConnect(aWindowId, aSessionId))); + Unused << NS_WARN_IF(NS_FAILED(mService->NotifySessionConnect(aWindowId, aSessionId))); } return true; } @@ -164,7 +164,7 @@ PresentationRequestChild::Recv__delete__(const nsresult& aResult) if (mCallback) { if (NS_FAILED(aResult)) { - NS_WARN_IF(NS_FAILED(mCallback->NotifyError(aResult))); + Unused << NS_WARN_IF(NS_FAILED(mCallback->NotifyError(aResult))); } } @@ -174,6 +174,6 @@ PresentationRequestChild::Recv__delete__(const nsresult& aResult) bool PresentationRequestChild::RecvNotifyRequestUrlSelected(const nsString& aUrl) { - NS_WARN_IF(NS_FAILED(mCallback->NotifySuccess(aUrl))); + Unused << NS_WARN_IF(NS_FAILED(mCallback->NotifySuccess(aUrl))); return true; } diff --git a/dom/presentation/ipc/PresentationIPCService.cpp b/dom/presentation/ipc/PresentationIPCService.cpp index 61a23f31428a4..bf9809971c5e6 100644 --- a/dom/presentation/ipc/PresentationIPCService.cpp +++ b/dom/presentation/ipc/PresentationIPCService.cpp @@ -38,7 +38,8 @@ PresentationIPCService::PresentationIPCService() return; } sPresentationChild = new PresentationChild(this); - NS_WARN_IF(!contentChild->SendPPresentationConstructor(sPresentationChild)); + Unused << + NS_WARN_IF(!contentChild->SendPPresentationConstructor(sPresentationChild)); } /* virtual */ @@ -180,7 +181,7 @@ PresentationIPCService::SendRequest(nsIPresentationServiceCallback* aCallback, { if (sPresentationChild) { PresentationRequestChild* actor = new PresentationRequestChild(aCallback); - NS_WARN_IF(!sPresentationChild->SendPPresentationRequestConstructor(actor, aRequest)); + Unused << NS_WARN_IF(!sPresentationChild->SendPPresentationRequestConstructor(actor, aRequest)); } return NS_OK; } @@ -193,7 +194,8 @@ PresentationIPCService::RegisterAvailabilityListener(nsIPresentationAvailability mAvailabilityListeners.AppendElement(aListener); if (sPresentationChild) { - NS_WARN_IF(!sPresentationChild->SendRegisterAvailabilityHandler()); + Unused << + NS_WARN_IF(!sPresentationChild->SendRegisterAvailabilityHandler()); } return NS_OK; } @@ -206,7 +208,8 @@ PresentationIPCService::UnregisterAvailabilityListener(nsIPresentationAvailabili mAvailabilityListeners.RemoveElement(aListener); if (mAvailabilityListeners.IsEmpty() && sPresentationChild) { - NS_WARN_IF(!sPresentationChild->SendUnregisterAvailabilityHandler()); + Unused << + NS_WARN_IF(!sPresentationChild->SendUnregisterAvailabilityHandler()); } return NS_OK; } @@ -221,14 +224,16 @@ PresentationIPCService::RegisterSessionListener(const nsAString& aSessionId, nsCOMPtr listener; if (mSessionListeners.Get(aSessionId, getter_AddRefs(listener))) { - NS_WARN_IF(NS_FAILED(listener->NotifyReplaced())); + Unused << NS_WARN_IF(NS_FAILED(listener->NotifyReplaced())); mSessionListeners.Put(aSessionId, aListener); return NS_OK; } mSessionListeners.Put(aSessionId, aListener); if (sPresentationChild) { - NS_WARN_IF(!sPresentationChild->SendRegisterSessionHandler(nsString(aSessionId), aRole)); + Unused << + NS_WARN_IF(!sPresentationChild->SendRegisterSessionHandler( + nsString(aSessionId), aRole)); } return NS_OK; } @@ -243,7 +248,9 @@ PresentationIPCService::UnregisterSessionListener(const nsAString& aSessionId, mSessionListeners.Remove(aSessionId); if (sPresentationChild) { - NS_WARN_IF(!sPresentationChild->SendUnregisterSessionHandler(nsString(aSessionId), aRole)); + Unused << + NS_WARN_IF(!sPresentationChild->SendUnregisterSessionHandler( + nsString(aSessionId), aRole)); } return NS_OK; } @@ -256,7 +263,8 @@ PresentationIPCService::RegisterRespondingListener(uint64_t aWindowId, mRespondingListeners.Put(aWindowId, aListener); if (sPresentationChild) { - NS_WARN_IF(!sPresentationChild->SendRegisterRespondingHandler(aWindowId)); + Unused << + NS_WARN_IF(!sPresentationChild->SendRegisterRespondingHandler(aWindowId)); } return NS_OK; } @@ -268,7 +276,9 @@ PresentationIPCService::UnregisterRespondingListener(uint64_t aWindowId) mRespondingListeners.Remove(aWindowId); if (sPresentationChild) { - NS_WARN_IF(!sPresentationChild->SendUnregisterRespondingHandler(aWindowId)); + Unused << + NS_WARN_IF(!sPresentationChild->SendUnregisterRespondingHandler( + aWindowId)); } return NS_OK; } @@ -339,7 +349,7 @@ PresentationIPCService::NotifyTransportClosed(const nsAString& aSessionId, if (NS_WARN_IF(!mSessionInfos.Contains(aSessionId))) { return NS_ERROR_NOT_AVAILABLE; } - NS_WARN_IF(!sPresentationChild->SendNotifyTransportClosed(nsString(aSessionId), aRole, aReason)); + Unused << NS_WARN_IF(!sPresentationChild->SendNotifyTransportClosed(nsString(aSessionId), aRole, aReason)); return NS_OK; } @@ -361,7 +371,7 @@ PresentationIPCService::NotifyAvailableChange(bool aAvailable) nsTObserverArray>::ForwardIterator iter(mAvailabilityListeners); while (iter.HasMore()) { nsIPresentationAvailabilityListener* listener = iter.GetNext(); - NS_WARN_IF(NS_FAILED(listener->NotifyAvailableChange(aAvailable))); + Unused << NS_WARN_IF(NS_FAILED(listener->NotifyAvailableChange(aAvailable))); } return NS_OK; @@ -384,9 +394,9 @@ PresentationIPCService::NotifyReceiverReady(const nsAString& aSessionId, aSessionId, nsIPresentationService::ROLE_RECEIVER); - NS_WARN_IF(!sPresentationChild->SendNotifyReceiverReady(nsString(aSessionId), - aWindowId, - aIsLoading)); + Unused << NS_WARN_IF(!sPresentationChild->SendNotifyReceiverReady(nsString(aSessionId), + aWindowId, + aIsLoading)); // Release mCallback after using aSessionId // because aSessionId is held by mCallback. diff --git a/dom/presentation/ipc/PresentationParent.cpp b/dom/presentation/ipc/PresentationParent.cpp index 6e13265492fce..c617180bbc8b2 100644 --- a/dom/presentation/ipc/PresentationParent.cpp +++ b/dom/presentation/ipc/PresentationParent.cpp @@ -51,19 +51,21 @@ PresentationParent::ActorDestroy(ActorDestroyReason aWhy) mActorDestroyed = true; for (uint32_t i = 0; i < mSessionIdsAtController.Length(); i++) { - NS_WARN_IF(NS_FAILED(mService-> - UnregisterSessionListener(mSessionIdsAtController[i], nsIPresentationService::ROLE_CONTROLLER))); + Unused << NS_WARN_IF(NS_FAILED(mService-> + UnregisterSessionListener(mSessionIdsAtController[i], + nsIPresentationService::ROLE_CONTROLLER))); } mSessionIdsAtController.Clear(); for (uint32_t i = 0; i < mSessionIdsAtReceiver.Length(); i++) { - NS_WARN_IF(NS_FAILED(mService-> + Unused << NS_WARN_IF(NS_FAILED(mService-> UnregisterSessionListener(mSessionIdsAtReceiver[i], nsIPresentationService::ROLE_RECEIVER))); } mSessionIdsAtReceiver.Clear(); for (uint32_t i = 0; i < mWindowIds.Length(); i++) { - NS_WARN_IF(NS_FAILED(mService->UnregisterRespondingListener(mWindowIds[i]))); + Unused << NS_WARN_IF(NS_FAILED(mService-> + UnregisterRespondingListener(mWindowIds[i]))); } mWindowIds.Clear(); @@ -148,7 +150,7 @@ bool PresentationParent::RecvRegisterAvailabilityHandler() { MOZ_ASSERT(mService); - NS_WARN_IF(NS_FAILED(mService->RegisterAvailabilityListener(this))); + Unused << NS_WARN_IF(NS_FAILED(mService->RegisterAvailabilityListener(this))); return true; } @@ -156,7 +158,7 @@ bool PresentationParent::RecvUnregisterAvailabilityHandler() { MOZ_ASSERT(mService); - NS_WARN_IF(NS_FAILED(mService->UnregisterAvailabilityListener(this))); + Unused << NS_WARN_IF(NS_FAILED(mService->UnregisterAvailabilityListener(this))); return true; } @@ -178,7 +180,7 @@ PresentationParent::RecvRegisterSessionHandler(const nsString& aSessionId, } else { mSessionIdsAtReceiver.AppendElement(aSessionId); } - NS_WARN_IF(NS_FAILED(mService->RegisterSessionListener(aSessionId, aRole, this))); + Unused << NS_WARN_IF(NS_FAILED(mService->RegisterSessionListener(aSessionId, aRole, this))); return true; } @@ -192,7 +194,7 @@ PresentationParent::RecvUnregisterSessionHandler(const nsString& aSessionId, } else { mSessionIdsAtReceiver.RemoveElement(aSessionId); } - NS_WARN_IF(NS_FAILED(mService->UnregisterSessionListener(aSessionId, aRole))); + Unused << NS_WARN_IF(NS_FAILED(mService->UnregisterSessionListener(aSessionId, aRole))); return true; } @@ -202,7 +204,7 @@ PresentationParent::RecvRegisterRespondingHandler(const uint64_t& aWindowId) MOZ_ASSERT(mService); mWindowIds.AppendElement(aWindowId); - NS_WARN_IF(NS_FAILED(mService->RegisterRespondingListener(aWindowId, this))); + Unused << NS_WARN_IF(NS_FAILED(mService->RegisterRespondingListener(aWindowId, this))); return true; } @@ -211,7 +213,7 @@ PresentationParent::RecvUnregisterRespondingHandler(const uint64_t& aWindowId) { MOZ_ASSERT(mService); mWindowIds.RemoveElement(aWindowId); - NS_WARN_IF(NS_FAILED(mService->UnregisterRespondingListener(aWindowId))); + Unused << NS_WARN_IF(NS_FAILED(mService->UnregisterRespondingListener(aWindowId))); return true; } @@ -223,7 +225,7 @@ PresentationParent::RegisterTransportBuilder(const nsString& aSessionId, nsCOMPtr builder = new PresentationBuilderParent(this); - NS_WARN_IF(NS_FAILED(static_cast(mService.get())-> + Unused << NS_WARN_IF(NS_FAILED(static_cast(mService.get())-> RegisterTransportBuilder(aSessionId, aRole, builder))); return true; } @@ -289,9 +291,9 @@ PresentationParent::RecvNotifyReceiverReady(const nsString& aSessionId, MOZ_ASSERT(mService); RegisterTransportBuilder(aSessionId, nsIPresentationService::ROLE_RECEIVER); - NS_WARN_IF(NS_FAILED(mService->NotifyReceiverReady(aSessionId, - aWindowId, - aIsLoading))); + Unused << NS_WARN_IF(NS_FAILED(mService->NotifyReceiverReady(aSessionId, + aWindowId, + aIsLoading))); return true; } @@ -302,7 +304,7 @@ PresentationParent::RecvNotifyTransportClosed(const nsString& aSessionId, { MOZ_ASSERT(mService); - NS_WARN_IF(NS_FAILED(mService->NotifyTransportClosed(aSessionId, aRole, aReason))); + Unused << NS_WARN_IF(NS_FAILED(mService->NotifyTransportClosed(aSessionId, aRole, aReason))); return true; } @@ -460,7 +462,7 @@ PresentationRequestParent::NotifySuccess(const nsAString& aUrl) { if (mNeedRegisterBuilder) { RefPtr parent = static_cast(Manager()); - NS_WARN_IF(!parent->RegisterTransportBuilder( + Unused << NS_WARN_IF(!parent->RegisterTransportBuilder( mSessionId, nsIPresentationService::ROLE_CONTROLLER)); } diff --git a/dom/presentation/provider/LegacyMDNSDeviceProvider.cpp b/dom/presentation/provider/LegacyMDNSDeviceProvider.cpp index 91e48527d111a..54849c9e37ecd 100644 --- a/dom/presentation/provider/LegacyMDNSDeviceProvider.cpp +++ b/dom/presentation/provider/LegacyMDNSDeviceProvider.cpp @@ -355,7 +355,7 @@ LegacyMDNSDeviceProvider::ClearUnknownDevices() while (i > 0) { --i; if (mDevices[i]->State() == DeviceState::eUnknown) { - NS_WARN_IF(NS_FAILED(RemoveDevice(i))); + Unused << NS_WARN_IF(NS_FAILED(RemoveDevice(i))); } } } @@ -368,7 +368,7 @@ LegacyMDNSDeviceProvider::ClearDevices() size_t i = mDevices.Length(); while (i > 0) { --i; - NS_WARN_IF(NS_FAILED(RemoveDevice(i))); + Unused << NS_WARN_IF(NS_FAILED(RemoveDevice(i))); } } diff --git a/dom/presentation/provider/MulticastDNSDeviceProvider.cpp b/dom/presentation/provider/MulticastDNSDeviceProvider.cpp index 4bb1e408fcfcc..0cab915ac4c27 100644 --- a/dom/presentation/provider/MulticastDNSDeviceProvider.cpp +++ b/dom/presentation/provider/MulticastDNSDeviceProvider.cpp @@ -566,7 +566,7 @@ MulticastDNSDeviceProvider::ClearUnknownDevices() while (i > 0) { --i; if (mDevices[i]->State() == DeviceState::eUnknown) { - NS_WARN_IF(NS_FAILED(RemoveDevice(i))); + Unused << NS_WARN_IF(NS_FAILED(RemoveDevice(i))); } } } @@ -579,7 +579,7 @@ MulticastDNSDeviceProvider::ClearDevices() size_t i = mDevices.Length(); while (i > 0) { --i; - NS_WARN_IF(NS_FAILED(RemoveDevice(i))); + Unused << NS_WARN_IF(NS_FAILED(RemoveDevice(i))); } } diff --git a/dom/promise/Promise.cpp b/dom/promise/Promise.cpp index 9fb4cce84fe2a..06b6ed980753e 100644 --- a/dom/promise/Promise.cpp +++ b/dom/promise/Promise.cpp @@ -740,7 +740,7 @@ NativeHandlerCallback(JSContext* aCx, unsigned aArgc, JS::Value* aVp) SLOT_NATIVEHANDLER)); MOZ_ASSERT(v.isObject()); - PromiseNativeHandler* handler; + PromiseNativeHandler* handler = nullptr; if (NS_FAILED(UNWRAP_OBJECT(PromiseNativeHandler, &v.toObject(), handler))) { return Throw(aCx, NS_ERROR_UNEXPECTED); @@ -781,6 +781,59 @@ CreateNativeHandlerFunction(JSContext* aCx, JS::Handle aHolder, return obj; } +namespace { + +class PromiseNativeHandlerShim final : public PromiseNativeHandler +{ + RefPtr mInner; + + ~PromiseNativeHandlerShim() + { + } + +public: + explicit PromiseNativeHandlerShim(PromiseNativeHandler* aInner) + : mInner(aInner) + { + MOZ_ASSERT(mInner); + } + + void + ResolvedCallback(JSContext* aCx, JS::Handle aValue) override + { + mInner->ResolvedCallback(aCx, aValue); + mInner = nullptr; + } + + void + RejectedCallback(JSContext* aCx, JS::Handle aValue) override + { + mInner->RejectedCallback(aCx, aValue); + mInner = nullptr; + } + + bool + WrapObject(JSContext* aCx, JS::Handle aGivenProto, + JS::MutableHandle aWrapper) + { + return PromiseNativeHandlerBinding::Wrap(aCx, this, aGivenProto, aWrapper); + } + + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_CLASS(PromiseNativeHandlerShim) +}; + +NS_IMPL_CYCLE_COLLECTION(PromiseNativeHandlerShim, mInner) + +NS_IMPL_CYCLE_COLLECTING_ADDREF(PromiseNativeHandlerShim) +NS_IMPL_CYCLE_COLLECTING_RELEASE(PromiseNativeHandlerShim) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PromiseNativeHandlerShim) + NS_INTERFACE_MAP_ENTRY(nsISupports) +NS_INTERFACE_MAP_END + +} // anonymous namespace + void Promise::AppendNativeHandler(PromiseNativeHandler* aRunnable) { @@ -793,11 +846,18 @@ Promise::AppendNativeHandler(PromiseNativeHandler* aRunnable) return; } + // The self-hosted promise js may keep the object we pass to it alive + // for quite a while depending on when GC runs. Therefore, pass a shim + // object instead. The shim will free its inner PromiseNativeHandler + // after the promise has settled just like our previous c++ promises did. + RefPtr shim = + new PromiseNativeHandlerShim(aRunnable); + JSContext* cx = jsapi.cx(); JS::Rooted handlerWrapper(cx); // Note: PromiseNativeHandler is NOT wrappercached. So we can't use // ToJSValue here, because it will try to do XPConnect wrapping on it, sadly. - if (NS_WARN_IF(!aRunnable->WrapObject(cx, nullptr, &handlerWrapper))) { + if (NS_WARN_IF(!shim->WrapObject(cx, nullptr, &handlerWrapper))) { // Again, no way to report errors. jsapi.ClearException(); return; diff --git a/dom/promise/PromiseNativeHandler.cpp b/dom/promise/PromiseNativeHandler.cpp deleted file mode 100644 index 50d0e1b96c5b6..0000000000000 --- a/dom/promise/PromiseNativeHandler.cpp +++ /dev/null @@ -1,26 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public -* License, v. 2.0. If a copy of the MPL was not distributed with this file, -* You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "mozilla/dom/PromiseNativeHandler.h" -#include "mozilla/dom/PromiseBinding.h" - -namespace mozilla { -namespace dom { - -#ifdef SPIDERMONKEY_PROMISE -bool -PromiseNativeHandler::WrapObject(JSContext* aCx, - JS::Handle aGivenProto, - JS::MutableHandle aWrapper) -{ - return PromiseNativeHandlerBinding::Wrap(aCx, this, aGivenProto, aWrapper); -} -#endif // SPIDERMONKEY_PROMISE - -} // namespace dom -} // namespace mozilla - - diff --git a/dom/promise/PromiseNativeHandler.h b/dom/promise/PromiseNativeHandler.h index 6e91f745c9b03..6ba7142aa1389 100644 --- a/dom/promise/PromiseNativeHandler.h +++ b/dom/promise/PromiseNativeHandler.h @@ -30,12 +30,6 @@ class PromiseNativeHandler : public nsISupports virtual void RejectedCallback(JSContext* aCx, JS::Handle aValue) = 0; - -#ifdef SPIDERMONKEY_PROMISE - bool WrapObject(JSContext* aCx, JS::Handle aGivenProto, - JS::MutableHandle aWrapper); -#endif // SPIDERMONKEY_PROMISE - }; } // namespace dom diff --git a/dom/promise/moz.build b/dom/promise/moz.build index b1cdbcf5c0195..11d2a74962422 100644 --- a/dom/promise/moz.build +++ b/dom/promise/moz.build @@ -15,7 +15,6 @@ UNIFIED_SOURCES += [ 'Promise.cpp', 'PromiseCallback.cpp', 'PromiseDebugging.cpp', - 'PromiseNativeHandler.cpp', ] LOCAL_INCLUDES += [ diff --git a/dom/quota/QuotaManagerService.cpp b/dom/quota/QuotaManagerService.cpp index b03010444d9b8..df061a2e2ae74 100644 --- a/dom/quota/QuotaManagerService.cpp +++ b/dom/quota/QuotaManagerService.cpp @@ -503,7 +503,6 @@ QuotaManagerService::GetUsageForPrincipal(nsIPrincipal* aPrincipal, MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(aPrincipal); MOZ_ASSERT(aCallback); - MOZ_ASSERT(nsContentUtils::IsCallerChrome()); RefPtr request = new UsageRequest(aPrincipal, aCallback); diff --git a/dom/quota/StorageManager.cpp b/dom/quota/StorageManager.cpp new file mode 100644 index 0000000000000..d2d3aa4b899ea --- /dev/null +++ b/dom/quota/StorageManager.cpp @@ -0,0 +1,353 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "StorageManager.h" + +#include "mozilla/dom/PromiseWorkerProxy.h" +#include "mozilla/dom/quota/QuotaManagerService.h" +#include "mozilla/dom/StorageManagerBinding.h" +#include "mozilla/dom/WorkerPrivate.h" +#include "mozilla/ErrorResult.h" +#include "nsIQuotaCallbacks.h" +#include "nsIQuotaRequests.h" +#include "nsPIDOMWindow.h" + +using namespace mozilla::dom::workers; + +namespace mozilla { +namespace dom { + +namespace { + +// This class is used to get quota usage callback. +class EstimateResolver final + : public nsIQuotaUsageCallback +{ + class FinishWorkerRunnable; + + // If this resolver was created for a window then mPromise must be non-null. + // Otherwise mProxy must be non-null. + RefPtr mPromise; + RefPtr mProxy; + + nsresult mResultCode; + StorageEstimate mStorageEstimate; + +public: + explicit EstimateResolver(Promise* aPromise) + : mPromise(aPromise) + , mResultCode(NS_OK) + { + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aPromise); + } + + explicit EstimateResolver(PromiseWorkerProxy* aProxy) + : mProxy(aProxy) + , mResultCode(NS_OK) + { + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aProxy); + } + + void + ResolveOrReject(Promise* aPromise); + + NS_DECL_THREADSAFE_ISUPPORTS + + NS_DECL_NSIQUOTAUSAGECALLBACK + +private: + ~EstimateResolver() + { } +}; + +// This class is used to return promise on worker thread. +class EstimateResolver::FinishWorkerRunnable final + : public WorkerRunnable +{ + RefPtr mResolver; + +public: + explicit FinishWorkerRunnable(EstimateResolver* aResolver) + : WorkerRunnable(aResolver->mProxy->GetWorkerPrivate()) + , mResolver(aResolver) + { + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aResolver); + } + + virtual bool + WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override; +}; + +class EstimateWorkerMainThreadRunnable + : public WorkerMainThreadRunnable +{ + RefPtr mProxy; + +public: + EstimateWorkerMainThreadRunnable(WorkerPrivate* aWorkerPrivate, + PromiseWorkerProxy* aProxy) + : WorkerMainThreadRunnable(aWorkerPrivate, + NS_LITERAL_CSTRING("StorageManager :: Estimate")) + , mProxy(aProxy) + { + MOZ_ASSERT(aWorkerPrivate); + aWorkerPrivate->AssertIsOnWorkerThread(); + MOZ_ASSERT(aProxy); + } + + virtual bool + MainThreadRun() override; +}; + +nsresult +GetUsageForPrincipal(nsIPrincipal* aPrincipal, + nsIQuotaUsageCallback* aCallback, + nsIQuotaUsageRequest** aRequest) +{ + MOZ_ASSERT(aPrincipal); + MOZ_ASSERT(aCallback); + MOZ_ASSERT(aRequest); + + nsCOMPtr qms = QuotaManagerService::GetOrCreate(); + if (NS_WARN_IF(!qms)) { + return NS_ERROR_FAILURE; + } + + nsresult rv = qms->GetUsageForPrincipal(aPrincipal, aCallback, true, aRequest); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + return NS_OK; +}; + +nsresult +GetStorageEstimate(nsIQuotaUsageRequest* aRequest, + StorageEstimate& aStorageEstimate) +{ + MOZ_ASSERT(aRequest); + + uint64_t usage; + nsresult rv = aRequest->GetUsage(&usage); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + uint64_t limit; + rv = aRequest->GetLimit(&limit); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + aStorageEstimate.mUsage.Construct() = usage; + aStorageEstimate.mQuota.Construct() = limit; + return NS_OK; +} + +} // namespace + +/******************************************************************************* + * Local class implementations + ******************************************************************************/ + +void +EstimateResolver::ResolveOrReject(Promise* aPromise) +{ + MOZ_ASSERT(aPromise); + + if (NS_SUCCEEDED(mResultCode)) { + aPromise->MaybeResolve(mStorageEstimate); + } else { + aPromise->MaybeReject(mResultCode); + } +} + +NS_IMPL_ISUPPORTS(EstimateResolver, nsIQuotaUsageCallback) + +NS_IMETHODIMP +EstimateResolver::OnUsageResult(nsIQuotaUsageRequest *aRequest) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aRequest); + + nsresult rv = aRequest->GetResultCode(&mResultCode); + if (NS_WARN_IF(NS_FAILED(rv))) { + mResultCode = rv; + } else if (NS_SUCCEEDED(mResultCode)) { + rv = GetStorageEstimate(aRequest, mStorageEstimate); + if (NS_WARN_IF(NS_FAILED(rv))) { + mResultCode = rv; + } + } + + // In a main thread request. + if (!mProxy) { + MOZ_ASSERT(mPromise); + + ResolveOrReject(mPromise); + return NS_OK; + } + + // In a worker thread request. + MutexAutoLock lock(mProxy->Lock()); + + if (NS_WARN_IF(mProxy->CleanedUp())) { + return NS_ERROR_FAILURE; + } + + RefPtr runnable = new FinishWorkerRunnable(this); + if (NS_WARN_IF(!runnable->Dispatch())) { + return NS_ERROR_FAILURE; + } + + return NS_OK; +} + +bool +EstimateResolver:: +FinishWorkerRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) +{ + MOZ_ASSERT(aWorkerPrivate); + aWorkerPrivate->AssertIsOnWorkerThread(); + + RefPtr proxy = mResolver->mProxy; + MOZ_ASSERT(proxy); + + RefPtr promise = proxy->WorkerPromise(); + MOZ_ASSERT(promise); + + mResolver->ResolveOrReject(promise); + + proxy->CleanUp(); + + return true; +} + +bool +EstimateWorkerMainThreadRunnable::MainThreadRun() +{ + MOZ_ASSERT(NS_IsMainThread()); + + nsCOMPtr principal; + + { + MutexAutoLock lock(mProxy->Lock()); + if (mProxy->CleanedUp()) { + return true; + } + principal = mProxy->GetWorkerPrivate()->GetPrincipal(); + } + + MOZ_ASSERT(principal); + + RefPtr resolver = new EstimateResolver(mProxy); + + RefPtr request; + nsresult rv = + GetUsageForPrincipal(principal, resolver, getter_AddRefs(request)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return false; + } + + return true; +} + +/******************************************************************************* + * StorageManager + ******************************************************************************/ + +StorageManager::StorageManager(nsIGlobalObject* aGlobal) + : mOwner(aGlobal) +{ + MOZ_ASSERT(aGlobal); +} + +StorageManager::~StorageManager() +{ +} + +already_AddRefed +StorageManager::Estimate(ErrorResult& aRv) +{ + MOZ_ASSERT(mOwner); + + RefPtr promise = Promise::Create(mOwner, aRv); + if (NS_WARN_IF(!promise)) { + return nullptr; + } + + if (NS_IsMainThread()) { + nsCOMPtr window = do_QueryInterface(mOwner); + if (NS_WARN_IF(!window)) { + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } + + nsCOMPtr doc = window->GetExtantDoc(); + if (NS_WARN_IF(!doc)) { + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } + + nsCOMPtr principal = doc->NodePrincipal(); + MOZ_ASSERT(principal); + + RefPtr resolver = new EstimateResolver(promise); + + RefPtr request; + nsresult rv = + GetUsageForPrincipal(principal, resolver, getter_AddRefs(request)); + if (NS_WARN_IF(NS_FAILED(rv))) { + aRv.Throw(rv); + return nullptr; + } + + return promise.forget(); + } + + WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); + MOZ_ASSERT(workerPrivate); + + RefPtr promiseProxy = + PromiseWorkerProxy::Create(workerPrivate, promise); + if (NS_WARN_IF(!promiseProxy)) { + return nullptr; + } + + RefPtr runnnable = + new EstimateWorkerMainThreadRunnable(promiseProxy->GetWorkerPrivate(), + promiseProxy); + + runnnable->Dispatch(aRv); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + + return promise.forget(); +} + +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(StorageManager, mOwner) + +NS_IMPL_CYCLE_COLLECTING_ADDREF(StorageManager) +NS_IMPL_CYCLE_COLLECTING_RELEASE(StorageManager) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(StorageManager) + NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY + NS_INTERFACE_MAP_ENTRY(nsISupports) +NS_INTERFACE_MAP_END + +JSObject* +StorageManager::WrapObject(JSContext* aCx, + JS::Handle aGivenProto) +{ + return StorageManagerBinding::Wrap(aCx, this, aGivenProto); +} + +} // namespace dom +} // namespace mozilla diff --git a/dom/quota/StorageManager.h b/dom/quota/StorageManager.h new file mode 100644 index 0000000000000..da4144f44640d --- /dev/null +++ b/dom/quota/StorageManager.h @@ -0,0 +1,55 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_StorageManager_h +#define mozilla_dom_StorageManager_h + +#include "nsCOMPtr.h" +#include "nsCycleCollectionParticipant.h" +#include "nsISupports.h" +#include "nsWrapperCache.h" + +namespace mozilla { +namespace dom { + +class Promise; +struct StorageEstimate; + +class StorageManager final + : public nsISupports + , public nsWrapperCache +{ + nsCOMPtr mOwner; + +public: + explicit + StorageManager(nsIGlobalObject* aGlobal); + + nsIGlobalObject* + GetParentObject() const + { + return mOwner; + } + + // WebIDL + already_AddRefed + Estimate(ErrorResult& aRv); + + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(StorageManager) + + // nsWrapperCache + virtual JSObject* + WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; + +private: + ~StorageManager(); +}; + +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_StorageManager_h diff --git a/dom/quota/moz.build b/dom/quota/moz.build index 53b7ae58ebda2..3e3f73453bb12 100644 --- a/dom/quota/moz.build +++ b/dom/quota/moz.build @@ -12,6 +12,10 @@ XPIDL_SOURCES += [ XPIDL_MODULE = 'dom_quota' +EXPORTS.mozilla.dom += [ + 'StorageManager.h', +] + EXPORTS.mozilla.dom.quota += [ 'ActorsParent.h', 'Client.h', @@ -32,6 +36,7 @@ UNIFIED_SOURCES += [ 'FileStreams.cpp', 'QuotaManagerService.cpp', 'QuotaRequests.cpp', + 'StorageManager.cpp', ] IPDL_SOURCES += [ @@ -44,6 +49,7 @@ include('/ipc/chromium/chromium-config.mozbuild') FINAL_LIBRARY = 'xul' LOCAL_INCLUDES += [ + '../workers', '/caps', ] diff --git a/dom/system/gonk/AudioChannelManager.cpp b/dom/system/gonk/AudioChannelManager.cpp index 942387508affc..977715a29ed43 100644 --- a/dom/system/gonk/AudioChannelManager.cpp +++ b/dom/system/gonk/AudioChannelManager.cpp @@ -173,7 +173,7 @@ AudioChannelManager::GetAllowedAudioChannels( nsBrowserElement::GenerateAllowedAudioChannels(window, nullptr, nullptr, aAudioChannels, aRv); - NS_WARN_IF(aRv.Failed()); + NS_WARNING_ASSERTION(!aRv.Failed(), "GenerateAllowedAudioChannels failed"); } } // namespace system diff --git a/dom/tests/mochitest/general/test_interfaces.html b/dom/tests/mochitest/general/test_interfaces.html index 3294b574308aa..40ff027811d1b 100644 --- a/dom/tests/mochitest/general/test_interfaces.html +++ b/dom/tests/mochitest/general/test_interfaces.html @@ -1069,6 +1069,8 @@ "Storage", // IMPORTANT: Do not change this list without review from a DOM peer! "StorageEvent", +// IMPORTANT: Do not change this list without review from a DOM peer! + "StorageManager", // IMPORTANT: Do not change this list without review from a DOM peer! "StyleSheet", // IMPORTANT: Do not change this list without review from a DOM peer! diff --git a/dom/tv/TVTuner.cpp b/dom/tv/TVTuner.cpp index c9e429694f26e..874890749e672 100644 --- a/dom/tv/TVTuner.cpp +++ b/dom/tv/TVTuner.cpp @@ -235,7 +235,9 @@ TVTuner::CreateSimulatedMediaStream() } ErrorResult error; - ElementCreationOptions options; + ElementCreationOptionsOrString options; + + options.SetAsString(); RefPtr element = doc->CreateElement(VIDEO_TAG, options, error); if (NS_WARN_IF(error.Failed())) { error.SuppressException(); diff --git a/dom/u2f/U2F.cpp b/dom/u2f/U2F.cpp index f3de4b30e2204..f520fab0a3d8d 100644 --- a/dom/u2f/U2F.cpp +++ b/dom/u2f/U2F.cpp @@ -50,7 +50,7 @@ SendError(CB* aCallback, ErrorCode aErrorCode) ErrorResult rv; aCallback->Call(response, rv); - NS_WARN_IF(rv.Failed()); + NS_WARNING_ASSERTION(!rv.Failed(), "callback failed"); // Useful exceptions already got reported. rv.SuppressException(); } @@ -277,7 +277,7 @@ U2FRegisterTask::Run() ErrorResult result; mCallback->Call(response, result); - NS_WARN_IF(result.Failed()); + NS_WARNING_ASSERTION(!result.Failed(), "callback failed"); // Useful exceptions already got reported. result.SuppressException(); return NS_OK; @@ -454,7 +454,7 @@ U2FSignTask::Run() ErrorResult result; mCallback->Call(response, result); - NS_WARN_IF(result.Failed()); + NS_WARNING_ASSERTION(!result.Failed(), "callback failed"); // Useful exceptions already got reported. result.SuppressException(); return NS_OK; diff --git a/dom/url/URL.cpp b/dom/url/URL.cpp index c9300bbd8110d..8be6a93e99b29 100644 --- a/dom/url/URL.cpp +++ b/dom/url/URL.cpp @@ -1821,7 +1821,7 @@ URL::URLSearchParamsUpdated(URLSearchParams* aSearchParams) ErrorResult rv; SetSearchInternal(search, rv); - NS_WARN_IF(rv.Failed()); + NS_WARNING_ASSERTION(!rv.Failed(), "SetSearchInternal failed"); rv.SuppressException(); } diff --git a/dom/webidl/Document.webidl b/dom/webidl/Document.webidl index 028ac336c1212..2db49de08f0e5 100644 --- a/dom/webidl/Document.webidl +++ b/dom/webidl/Document.webidl @@ -53,7 +53,7 @@ interface Document : Node { Element? getElementById(DOMString elementId); [NewObject, Throws] - Element createElement(DOMString localName, optional ElementCreationOptions options); + Element createElement(DOMString localName, optional (ElementCreationOptions or DOMString) options); [NewObject, Throws] Element createElementNS(DOMString? namespace, DOMString qualifiedName, optional ElementCreationOptions options); [NewObject] diff --git a/dom/webidl/Grid.webidl b/dom/webidl/Grid.webidl index d3ca6cd3e8f34..8f0fab5f0aee5 100644 --- a/dom/webidl/Grid.webidl +++ b/dom/webidl/Grid.webidl @@ -105,8 +105,6 @@ interface GridArea /** * These values are 1-indexed line numbers bounding the area. - * FIXME: Bug 1297189 - Implicit grid areas need boundary line numbers - * exposed to dev tools */ readonly attribute unsigned long rowStart; readonly attribute unsigned long rowEnd; diff --git a/dom/webidl/Navigator.webidl b/dom/webidl/Navigator.webidl index 5df92bedee003..f00f4dfc780f1 100644 --- a/dom/webidl/Navigator.webidl +++ b/dom/webidl/Navigator.webidl @@ -30,6 +30,7 @@ Navigator implements NavigatorOnLine; Navigator implements NavigatorContentUtils; Navigator implements NavigatorStorageUtils; Navigator implements NavigatorConcurrentHardware; +Navigator implements NavigatorStorage; [NoInterfaceObject, Exposed=(Window,Worker)] interface NavigatorID { @@ -85,6 +86,11 @@ interface NavigatorContentUtils { //void unregisterContentHandler(DOMString mimeType, DOMString url); }; +[NoInterfaceObject, Exposed=(Window,Worker)] +interface NavigatorStorage { + readonly attribute StorageManager storage; +}; + [NoInterfaceObject] interface NavigatorStorageUtils { // NOT IMPLEMENTED diff --git a/dom/webidl/StorageManager.webidl b/dom/webidl/StorageManager.webidl new file mode 100644 index 0000000000000..6a2dea694a456 --- /dev/null +++ b/dom/webidl/StorageManager.webidl @@ -0,0 +1,24 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * The origin of this IDL file is + * https://storage.spec.whatwg.org/#storagemanager + * + */ + +[Exposed=(Window,Worker)] +interface StorageManager { + // [Throws] + // Promise persisted(); + // [Throws] + // [Exposed=Window] Promise persist(); + [Throws] + Promise estimate(); +}; + +dictionary StorageEstimate { + unsigned long long usage; + unsigned long long quota; +}; diff --git a/dom/webidl/WorkerNavigator.webidl b/dom/webidl/WorkerNavigator.webidl index affbfba82cf17..44d1e29f688ac 100644 --- a/dom/webidl/WorkerNavigator.webidl +++ b/dom/webidl/WorkerNavigator.webidl @@ -11,3 +11,4 @@ WorkerNavigator implements NavigatorID; WorkerNavigator implements NavigatorLanguage; WorkerNavigator implements NavigatorOnLine; WorkerNavigator implements NavigatorConcurrentHardware; +WorkerNavigator implements NavigatorStorage; diff --git a/dom/webidl/moz.build b/dom/webidl/moz.build index 45a3967fe5086..38e0d6dc37f01 100644 --- a/dom/webidl/moz.build +++ b/dom/webidl/moz.build @@ -433,6 +433,7 @@ WEBIDL_FILES = [ 'StereoPannerNode.webidl', 'Storage.webidl', 'StorageEvent.webidl', + 'StorageManager.webidl', 'StorageType.webidl', 'StyleSheet.webidl', 'StyleSheetList.webidl', diff --git a/dom/workers/ServiceWorkerClients.cpp b/dom/workers/ServiceWorkerClients.cpp index 5cbdf0a209bd4..408bbef0b798f 100644 --- a/dom/workers/ServiceWorkerClients.cpp +++ b/dom/workers/ServiceWorkerClients.cpp @@ -554,7 +554,7 @@ class OpenWindowRunnable final : public Runnable RefPtr resolveRunnable = new ResolveOpenWindowRunnable(mPromiseProxy, nullptr, rv); - NS_WARN_IF(!resolveRunnable->Dispatch()); + Unused << NS_WARN_IF(!resolveRunnable->Dispatch()); return NS_OK; } diff --git a/dom/workers/ServiceWorkerPrivate.cpp b/dom/workers/ServiceWorkerPrivate.cpp index 9e1502149eb88..7efefdb4dba4d 100644 --- a/dom/workers/ServiceWorkerPrivate.cpp +++ b/dom/workers/ServiceWorkerPrivate.cpp @@ -1682,7 +1682,7 @@ ServiceWorkerPrivate::SpawnWorkerIfNeeded(WakeUpReason aWhy, // TODO(catalinb): Bug 1192138 - Add telemetry for service worker wake-ups. // Ensure that the IndexedDatabaseManager is initialized - NS_WARN_IF(!IndexedDatabaseManager::GetOrCreate()); + Unused << NS_WARN_IF(!IndexedDatabaseManager::GetOrCreate()); WorkerLoadInfo info; nsresult rv = NS_NewURI(getter_AddRefs(info.mBaseURI), mInfo->ScriptSpec(), @@ -1781,7 +1781,7 @@ ServiceWorkerPrivate::TerminateWorker() } } - NS_WARN_IF(!mWorkerPrivate->Terminate()); + Unused << NS_WARN_IF(!mWorkerPrivate->Terminate()); mWorkerPrivate = nullptr; mSupportsArray.Clear(); diff --git a/dom/workers/ServiceWorkerRegistration.cpp b/dom/workers/ServiceWorkerRegistration.cpp index 90034290f3e62..1f619c42cf73b 100644 --- a/dom/workers/ServiceWorkerRegistration.cpp +++ b/dom/workers/ServiceWorkerRegistration.cpp @@ -1299,7 +1299,7 @@ WorkerListener::UpdateFound() if (mWorkerPrivate) { RefPtr r = new FireUpdateFoundRunnable(mWorkerPrivate, this); - NS_WARN_IF(!r->Dispatch()); + Unused << NS_WARN_IF(!r->Dispatch()); } } diff --git a/dom/workers/WorkerNavigator.cpp b/dom/workers/WorkerNavigator.cpp index 08d7fc656a4b0..682c7a22ca2bb 100644 --- a/dom/workers/WorkerNavigator.cpp +++ b/dom/workers/WorkerNavigator.cpp @@ -7,6 +7,7 @@ #include "mozilla/dom/BindingUtils.h" #include "mozilla/dom/Promise.h" #include "mozilla/dom/PromiseWorkerProxy.h" +#include "mozilla/dom/StorageManager.h" #include "mozilla/dom/WorkerNavigator.h" #include "mozilla/dom/WorkerNavigatorBinding.h" @@ -26,8 +27,7 @@ namespace dom { using namespace mozilla::dom::workers; -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WorkerNavigator) - +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WorkerNavigator, mStorageManager); NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WorkerNavigator, AddRef) NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WorkerNavigator, Release) @@ -164,5 +164,21 @@ WorkerNavigator::HardwareConcurrency() const return rts->ClampedHardwareConcurrency(); } +StorageManager* +WorkerNavigator::Storage() +{ + if (!mStorageManager) { + WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); + MOZ_ASSERT(workerPrivate); + + RefPtr global = workerPrivate->GlobalScope(); + MOZ_ASSERT(global); + + mStorageManager = new StorageManager(global); + } + + return mStorageManager; +} + } // namespace dom } // namespace mozilla diff --git a/dom/workers/WorkerNavigator.h b/dom/workers/WorkerNavigator.h index bca77e19cf628..3a1a3e970e54f 100644 --- a/dom/workers/WorkerNavigator.h +++ b/dom/workers/WorkerNavigator.h @@ -15,12 +15,14 @@ namespace mozilla { namespace dom { class Promise; +class StorageManager; class WorkerNavigator final : public nsWrapperCache { typedef struct workers::RuntimeService::NavigatorProperties NavigatorProperties; NavigatorProperties mProperties; + RefPtr mStorageManager; bool mOnline; WorkerNavigator(const NavigatorProperties& aProperties, @@ -101,6 +103,8 @@ class WorkerNavigator final : public nsWrapperCache void SetLanguages(const nsTArray& aLanguages); uint64_t HardwareConcurrency() const; + + StorageManager* Storage(); }; } // namespace dom diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp index 87ab042223255..51fee89c01a7d 100644 --- a/dom/workers/WorkerPrivate.cpp +++ b/dom/workers/WorkerPrivate.cpp @@ -3069,7 +3069,7 @@ WorkerPrivateParent::MemoryPressure(bool aDummy) RefPtr runnable = new MemoryPressureRunnable(ParentAsWorkerPrivate()); - NS_WARN_IF(!runnable->Dispatch()); + Unused << NS_WARN_IF(!runnable->Dispatch()); } template @@ -4130,7 +4130,7 @@ WorkerPrivate::GetLoadInfo(JSContext* aCx, nsPIDOMWindowInner* aWindow, AssertIsOnMainThread(); // Make sure that the IndexedDatabaseManager is set up - NS_WARN_IF(!IndexedDatabaseManager::GetOrCreate()); + Unused << NS_WARN_IF(!IndexedDatabaseManager::GetOrCreate()); nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager(); MOZ_ASSERT(ssm); diff --git a/dom/workers/WorkerRunnable.cpp b/dom/workers/WorkerRunnable.cpp index d95423652b117..cbbed9aef5de5 100644 --- a/dom/workers/WorkerRunnable.cpp +++ b/dom/workers/WorkerRunnable.cpp @@ -748,7 +748,7 @@ WorkerProxyToMainThreadRunnable::PostDispatchOnMainThread() RefPtr runnable = new ReleaseRunnable(mWorkerPrivate, this); - NS_WARN_IF(!runnable->Dispatch()); + Unused << NS_WARN_IF(!runnable->Dispatch()); } bool diff --git a/dom/workers/test/navigator_worker.js b/dom/workers/test/navigator_worker.js index 35941f8332cf1..875de5d82474f 100644 --- a/dom/workers/test/navigator_worker.js +++ b/dom/workers/test/navigator_worker.js @@ -15,6 +15,7 @@ var supportedProps = [ "language", "languages", "hardwareConcurrency", + "storage" ]; self.onmessage = function(event) { diff --git a/dom/workers/test/serviceworkers/serviceworker_wrapper.js b/dom/workers/test/serviceworkers/serviceworker_wrapper.js index afc08cfb003e2..062c368ad01a1 100644 --- a/dom/workers/test/serviceworkers/serviceworker_wrapper.js +++ b/dom/workers/test/serviceworkers/serviceworker_wrapper.js @@ -98,6 +98,19 @@ function workerTestGetIsB2G(cb) { }); } +function workerTestGetStorageManager(cb) { + addEventListener('message', function workerTestGetStorageManagerCB(e) { + if (e.data.type !== 'returnStorageManager') { + return; + } + removeEventListener('message', workerTestGetStorageManagerCB); + cb(e.data.result); + }); + client.postMessage({ + type: 'getStorageManager' + }); +} + addEventListener('message', function workerWrapperOnMessage(e) { removeEventListener('message', workerWrapperOnMessage); var data = e.data; diff --git a/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js b/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js index 85d3ac8ce6d1b..f892641ef9efb 100644 --- a/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js +++ b/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js @@ -195,6 +195,8 @@ var interfaceNamesInGlobalScope = "ServiceWorkerGlobalScope", // IMPORTANT: Do not change this list without review from a DOM peer! "ServiceWorkerRegistration", +// IMPORTANT: Do not change this list without review from a DOM peer! + "StorageManager", // IMPORTANT: Do not change this list without review from a DOM peer! "SubtleCrypto", // IMPORTANT: Do not change this list without review from a DOM peer! diff --git a/dom/workers/test/test_navigator.html b/dom/workers/test/test_navigator.html index ff037d25be861..585ad74bc6f07 100644 --- a/dom/workers/test/test_navigator.html +++ b/dom/workers/test/test_navigator.html @@ -40,6 +40,11 @@ return; } + if (args.name === "storage") { + is(typeof navigator.storage, typeof args.value, "storage type matches"); + return; + } + is(navigator[args.name], args.value, "Mismatched navigator string for " + args.name + "!"); }; diff --git a/dom/workers/test/test_worker_interfaces.js b/dom/workers/test/test_worker_interfaces.js index c33a9f17bef98..8226078c3aeea 100644 --- a/dom/workers/test/test_worker_interfaces.js +++ b/dom/workers/test/test_worker_interfaces.js @@ -179,6 +179,8 @@ var interfaceNamesInGlobalScope = "Response", // IMPORTANT: Do not change this list without review from a DOM peer! { name: "ServiceWorkerRegistration", b2g: false }, +// IMPORTANT: Do not change this list without review from a DOM peer! + "StorageManager", // IMPORTANT: Do not change this list without review from a DOM peer! "SubtleCrypto", // IMPORTANT: Do not change this list without review from a DOM peer! diff --git a/dom/xbl/nsXBLWindowKeyHandler.cpp b/dom/xbl/nsXBLWindowKeyHandler.cpp index 7a89e3b51c2e0..011b5c36bb56b 100644 --- a/dom/xbl/nsXBLWindowKeyHandler.cpp +++ b/dom/xbl/nsXBLWindowKeyHandler.cpp @@ -825,7 +825,7 @@ nsXBLWindowKeyHandler::GetElementForHandler(nsXBLPrototypeHandler* aHandler, nsCOMPtr chromeHandlerElement = GetElement(); if (!chromeHandlerElement) { - NS_WARN_IF(!keyContent->IsInUncomposedDoc()); + NS_WARNING_ASSERTION(keyContent->IsInUncomposedDoc(), "uncomposed"); nsCOMPtr keyElement = do_QueryInterface(keyContent); keyElement.swap(*aElementForHandler); return true; @@ -836,7 +836,7 @@ nsXBLWindowKeyHandler::GetElementForHandler(nsXBLPrototypeHandler* aHandler, keyContent->GetAttr(kNameSpaceID_None, nsGkAtoms::command, command); if (command.IsEmpty()) { // There is no command element associated with the key element. - NS_WARN_IF(!keyContent->IsInUncomposedDoc()); + NS_WARNING_ASSERTION(keyContent->IsInUncomposedDoc(), "uncomposed"); nsCOMPtr keyElement = do_QueryInterface(keyContent); keyElement.swap(*aElementForHandler); return true; diff --git a/extensions/cookie/nsPermissionManager.cpp b/extensions/cookie/nsPermissionManager.cpp index d2bbbac11ebd4..49962e7a60713 100644 --- a/extensions/cookie/nsPermissionManager.cpp +++ b/extensions/cookie/nsPermissionManager.cpp @@ -540,7 +540,7 @@ UpgradeHostToOriginAndInsert(const nsACString& aHost, const nsAFlatCString& aTyp foundHistory = true; rv = aHelper->Insert(origin, aType, aPermission, aExpireType, aExpireTime, aModificationTime); - NS_WARN_IF(NS_WARN_IF(NS_FAILED(rv))); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Insert failed"); insertedOrigins.PutEntry(origin); } diff --git a/gfx/layers/Compositor.cpp b/gfx/layers/Compositor.cpp index f7ef555fb649d..7532a2ee9097a 100644 --- a/gfx/layers/Compositor.cpp +++ b/gfx/layers/Compositor.cpp @@ -38,9 +38,11 @@ Compositor::Compositor(widget::CompositorWidget* aWidget, #if defined(MOZ_WIDGET_ANDROID) // If the default color isn't white for Fennec, there is a black // flash before the first page of a tab is loaded. - , mBeginFrameClearColor(1.0, 1.0, 1.0, 1.0) + , mClearColor(1.0, 1.0, 1.0, 1.0) + , mDefaultClearColor(1.0, 1.0, 1.0, 1.0) #else - , mBeginFrameClearColor(0.0, 0.0, 0.0, 0.0) + , mClearColor(0.0, 0.0, 0.0, 0.0) + , mDefaultClearColor(0.0, 0.0, 0.0, 0.0) #endif { } diff --git a/gfx/layers/Compositor.h b/gfx/layers/Compositor.h index f67532990b38c..5a433082af26a 100644 --- a/gfx/layers/Compositor.h +++ b/gfx/layers/Compositor.h @@ -349,8 +349,16 @@ class Compositor const gfx::IntRect& aClipRect = gfx::IntRect(), const gfx::Matrix4x4& aTransform = gfx::Matrix4x4()); - void SetBeginFrameClearColor(const gfx::Color& aColor) { - mBeginFrameClearColor = aColor; + void SetClearColor(const gfx::Color& aColor) { + mClearColor = aColor; + } + + void SetDefaultClearColor(const gfx::Color& aColor) { + mDefaultClearColor = aColor; + } + + void SetClearColorToDefault() { + mClearColor = mDefaultClearColor; } /* @@ -642,7 +650,8 @@ class Compositor FenceHandle mReleaseFenceHandle; #endif - gfx::Color mBeginFrameClearColor; + gfx::Color mClearColor; + gfx::Color mDefaultClearColor; private: static LayersBackend sBackend; diff --git a/gfx/layers/ImageContainer.cpp b/gfx/layers/ImageContainer.cpp index d16bf2039c83c..cbf69812ed5ec 100644 --- a/gfx/layers/ImageContainer.cpp +++ b/gfx/layers/ImageContainer.cpp @@ -15,8 +15,8 @@ #include "mozilla/ipc/CrossProcessMutex.h" // for CrossProcessMutex, etc #include "mozilla/layers/CompositorTypes.h" #include "mozilla/layers/ImageBridgeChild.h" // for ImageBridgeChild -#include "mozilla/layers/PImageContainerChild.h" #include "mozilla/layers/ImageClient.h" // for ImageClient +#include "mozilla/layers/ImageContainerChild.h" #include "mozilla/layers/LayersMessages.h" #include "mozilla/layers/SharedPlanarYCbCrImage.h" #include "mozilla/layers/SharedRGBImage.h" @@ -103,84 +103,6 @@ BufferRecycleBin::ClearRecycledBuffers() mRecycledBufferSize = 0; } -/** - * The child side of PImageContainer. It's best to avoid ImageContainer filling - * this role since IPDL objects should be associated with a single thread and - * ImageContainer definitely isn't. This object belongs to (and is always - * destroyed on) the ImageBridge thread, except when we need to destroy it - * during shutdown. - * An ImageContainer owns one of these; we have a weak reference to our - * ImageContainer. - */ -class ImageContainerChild : public PImageContainerChild { -public: - explicit ImageContainerChild(ImageContainer* aImageContainer) - : mLock("ImageContainerChild") - , mImageContainer(aImageContainer) - , mImageContainerReleased(false) - , mIPCOpen(true) - {} - - void ForgetImageContainer() - { - MutexAutoLock lock(mLock); - mImageContainer = nullptr; - } - - // This protects mImageContainer. This is always taken before the - // mImageContainer's monitor (when both need to be held). - Mutex mLock; - ImageContainer* mImageContainer; - // If mImageContainerReleased is false when we try to deallocate this actor, - // it means the ImageContainer is still holding a pointer to this. - // mImageContainerReleased must not be accessed off the ImageBridgeChild thread. - bool mImageContainerReleased; - // If mIPCOpen is false, it means the IPDL code tried to deallocate the actor - // before the ImageContainer released it. When this happens we don't actually - // delete the actor right away because the ImageContainer has a reference to - // it. In this case the actor will be deleted when the ImageContainer lets go - // of it. - // mIPCOpen must not be accessed off the ImageBridgeChild thread. - bool mIPCOpen; -}; - -// static -void -ImageContainer::DeallocActor(PImageContainerChild* aActor) -{ - MOZ_ASSERT(aActor); - MOZ_ASSERT(InImageBridgeChildThread()); - - auto actor = static_cast(aActor); - if (actor->mImageContainerReleased) { - delete actor; - } else { - actor->mIPCOpen = false; - } -} - -// static -void -ImageContainer::AsyncDestroyActor(PImageContainerChild* aActor) -{ - MOZ_ASSERT(aActor); - MOZ_ASSERT(InImageBridgeChildThread()); - - auto actor = static_cast(aActor); - - // Setting mImageContainerReleased to true means next time DeallocActor is - // called, the actor will be deleted. - actor->mImageContainerReleased = true; - - if (actor->mIPCOpen && ImageBridgeChild::IsCreated() && !ImageBridgeChild::IsShutDown()) { - actor->SendAsyncDelete(); - } else { - // The actor is already dead as far as IPDL is concerned, probably because - // of a channel error. We can deallocate it now. - DeallocActor(actor); - } -} - ImageContainer::ImageContainer(Mode flag) : mReentrantMonitor("ImageContainer.mReentrantMonitor"), mGenerationCounter(++sGenerationCounter), @@ -188,10 +110,10 @@ ImageContainer::ImageContainer(Mode flag) mDroppedImageCount(0), mImageFactory(new ImageFactory()), mRecycleBin(new BufferRecycleBin()), - mCurrentProducerID(-1), - mIPDLChild(nullptr) + mCurrentProducerID(-1) { - if (ImageBridgeChild::IsCreated()) { + RefPtr imageBridge = ImageBridgeChild::GetSingleton(); + if (imageBridge) { // the refcount of this ImageClient is 1. we don't use a RefPtr here because the refcount // of this class must be done on the ImageBridge thread. switch (flag) { @@ -199,7 +121,7 @@ ImageContainer::ImageContainer(Mode flag) break; case ASYNCHRONOUS: mIPDLChild = new ImageContainerChild(this); - mImageClient = ImageBridgeChild::GetSingleton()->CreateImageClient(CompositableType::IMAGE, this); + mImageClient = imageBridge->CreateImageClient(CompositableType::IMAGE, this, mIPDLChild); MOZ_ASSERT(mImageClient); break; default: @@ -219,8 +141,7 @@ ImageContainer::ImageContainer(uint64_t aAsyncContainerID) mImageFactory(nullptr), mRecycleBin(nullptr), mAsyncContainerID(aAsyncContainerID), - mCurrentProducerID(-1), - mIPDLChild(nullptr) + mCurrentProducerID(-1) { MOZ_ASSERT(mAsyncContainerID != sInvalidAsyncContainerId); } @@ -860,19 +781,6 @@ ImageContainer::GetPImageContainerChild() return mIPDLChild; } -/* static */ void -ImageContainer::NotifyComposite(const ImageCompositeNotification& aNotification) -{ - ImageContainerChild* child = - static_cast(aNotification.imageContainerChild()); - if (child) { - MutexAutoLock lock(child->mLock); - if (child->mImageContainer) { - child->mImageContainer->NotifyCompositeInternal(aNotification); - } - } -} - ImageContainer::ProducerID ImageContainer::AllocateProducerID() { diff --git a/gfx/layers/ImageContainer.h b/gfx/layers/ImageContainer.h index fa1d0912b5a13..c068b24339667 100644 --- a/gfx/layers/ImageContainer.h +++ b/gfx/layers/ImageContainer.h @@ -354,8 +354,12 @@ class ImageFactory * updates the shared state to point to the new image and the old image * is immediately released (not true in Normal or Asynchronous modes). */ -class ImageContainer final : public SupportsWeakPtr { +class ImageContainer final : public SupportsWeakPtr +{ + friend class ImageContainerChild; + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ImageContainer) + public: MOZ_DECLARE_WEAKREFERENCE_TYPENAME(ImageContainer) @@ -571,19 +575,12 @@ class ImageContainer final : public SupportsWeakPtr { } PImageContainerChild* GetPImageContainerChild(); - static void NotifyComposite(const ImageCompositeNotification& aNotification); /** * Main thread only. */ static ProducerID AllocateProducerID(); - /// ImageBridgeChild thread only. - static void AsyncDestroyActor(PImageContainerChild* aActor); - - /// ImageBridgeChild thread only. - static void DeallocActor(PImageContainerChild* aActor); - private: typedef mozilla::ReentrantMonitor ReentrantMonitor; @@ -647,7 +644,7 @@ class ImageContainer final : public SupportsWeakPtr { // Object must be released on the ImageBridge thread. Field is immutable // after creation of the ImageContainer. - ImageContainerChild* mIPDLChild; + RefPtr mIPDLChild; static mozilla::Atomic sGenerationCounter; }; diff --git a/gfx/layers/composite/LayerManagerComposite.cpp b/gfx/layers/composite/LayerManagerComposite.cpp index 62bf78d8d6089..875cea5229414 100644 --- a/gfx/layers/composite/LayerManagerComposite.cpp +++ b/gfx/layers/composite/LayerManagerComposite.cpp @@ -932,7 +932,9 @@ LayerManagerComposite::Render(const nsIntRegion& aInvalidRegion, const nsIntRegi #if defined(MOZ_WIDGET_ANDROID) LayerMetricsWrapper wrapper = GetRootContentLayer(); if (wrapper) { - mCompositor->SetBeginFrameClearColor(wrapper.Metadata().GetBackgroundColor()); + mCompositor->SetClearColor(wrapper.Metadata().GetBackgroundColor()); + } else { + mCompositor->SetClearColorToDefault(); } #endif if (mRoot->GetClipRect()) { @@ -1002,13 +1004,6 @@ LayerManagerComposite::Render(const nsIntRegion& aInvalidRegion, const nsIntRegi mCompositor->GetWidget()->PostRender(this); RecordFrame(); - -#if defined(MOZ_WIDGET_ANDROID) - // Reset the clear color to white so that if a page is loaded with a different background - // color, the page will be white while the new page is loading instead of the background - // color of the previous page. - mCompositor->SetBeginFrameClearColor(gfx::Color(1.0, 1.0, 1.0, 1.0)); -#endif } #if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK) diff --git a/gfx/layers/ipc/ImageBridgeChild.cpp b/gfx/layers/ipc/ImageBridgeChild.cpp index 1faa46d7dba2f..beffdbb6a8bdb 100644 --- a/gfx/layers/ipc/ImageBridgeChild.cpp +++ b/gfx/layers/ipc/ImageBridgeChild.cpp @@ -28,9 +28,9 @@ #include "mozilla/layers/CompositorThread.h" #include "mozilla/layers/ISurfaceAllocator.h" // for ISurfaceAllocator #include "mozilla/layers/ImageClient.h" // for ImageClient +#include "mozilla/layers/ImageContainerChild.h" #include "mozilla/layers/LayersMessages.h" // for CompositableOperation #include "mozilla/layers/PCompositableChild.h" // for PCompositableChild -#include "mozilla/layers/PImageContainerChild.h" #include "mozilla/layers/TextureClient.h" // for TextureClient #include "mozilla/mozalloc.h" // for operator new, etc #include "nsISupportsImpl.h" // for ImageContainer::AddRef, etc @@ -401,10 +401,58 @@ ImageBridgeChild::FallbackDestroyActors() { } } +// Helper that creates a monitor and a "done" flag, then enters the monitor. +// This can go away when we switch ImageBridge to an XPCOM thread. +class MOZ_STACK_CLASS SynchronousTask +{ + friend class AutoCompleteTask; + +public: + explicit SynchronousTask(const char* name) + : mMonitor(name), + mAutoEnter(mMonitor), + mDone(false) + {} + + void Wait() { + while (!mDone) { + mMonitor.Wait(); + } + } + +private: + void Complete() { + mDone = true; + mMonitor.NotifyAll(); + } + +private: + ReentrantMonitor mMonitor; + ReentrantMonitorAutoEnter mAutoEnter; + bool mDone; +}; + +class MOZ_STACK_CLASS AutoCompleteTask +{ +public: + explicit AutoCompleteTask(SynchronousTask* aTask) + : mTask(aTask), + mAutoEnter(aTask->mMonitor) + { + } + ~AutoCompleteTask() { + mTask->Complete(); + } + +private: + SynchronousTask* mTask; + ReentrantMonitorAutoEnter mAutoEnter; +}; + // dispatched function -static void ImageBridgeShutdownStep1(ReentrantMonitor *aBarrier, bool *aDone) +static void ImageBridgeShutdownStep1(SynchronousTask* aTask) { - ReentrantMonitorAutoEnter autoMon(*aBarrier); + AutoCompleteTask complete(aTask); MOZ_ASSERT(InImageBridgeChildThread(), "Should be in ImageBridgeChild thread."); @@ -436,50 +484,40 @@ static void ImageBridgeShutdownStep1(ReentrantMonitor *aBarrier, bool *aDone) // From now on, no message can be sent through the image bridge from the // client side except the final Stop message. } - - *aDone = true; - aBarrier->NotifyAll(); } // dispatched function -static void ImageBridgeShutdownStep2(ReentrantMonitor *aBarrier, bool *aDone) +static void +ImageBridgeShutdownStep2(SynchronousTask* aTask) { - ReentrantMonitorAutoEnter autoMon(*aBarrier); + AutoCompleteTask complete(aTask); MOZ_ASSERT(InImageBridgeChildThread(), "Should be in ImageBridgeChild thread."); sImageBridgeChildSingleton->Close(); - - *aDone = true; - aBarrier->NotifyAll(); } -// dispatched function -static void CreateImageClientSync(RefPtr* result, - ReentrantMonitor* barrier, - CompositableType aType, - ImageContainer* aImageContainer, - bool *aDone) +/* static */ void +CreateImageClientSync(SynchronousTask* aTask, + RefPtr aChild, + RefPtr* result, + CompositableType aType, + ImageContainer* aImageContainer, + ImageContainerChild* aContainerChild) { - ReentrantMonitorAutoEnter autoMon(*barrier); - *result = sImageBridgeChildSingleton->CreateImageClientNow( - aType, aImageContainer); - *aDone = true; - barrier->NotifyAll(); + AutoCompleteTask complete(aTask); + *result = aChild->CreateImageClientNow(aType, aImageContainer, aContainerChild); } // dispatched function -static void CreateCanvasClientSync(ReentrantMonitor* aBarrier, +static void CreateCanvasClientSync(SynchronousTask* aTask, CanvasClient::CanvasClientType aType, TextureFlags aFlags, - RefPtr* const outResult, - bool* aDone) + RefPtr* const outResult) { - ReentrantMonitorAutoEnter autoMon(*aBarrier); + AutoCompleteTask complete(aTask); *outResult = sImageBridgeChildSingleton->CreateCanvasClientNow(aType, aFlags); - *aDone = true; - aBarrier->NotifyAll(); } static void ConnectImageBridge(ImageBridgeChild * child, ImageBridgeParent * parent) @@ -568,29 +606,29 @@ bool ImageBridgeChild::IsCreated() return GetSingleton() != nullptr; } -static void ReleaseImageContainerNow(PImageContainerChild* aChild) +static void +ReleaseImageContainerNow(RefPtr aBridge, RefPtr aChild) { MOZ_ASSERT(InImageBridgeChildThread()); - if (aChild) { - ImageContainer::AsyncDestroyActor(aChild); - } + aChild->SendAsyncDelete(); } // static -void ImageBridgeChild::DispatchReleaseImageContainer(PImageContainerChild* aChild) +void ImageBridgeChild::DispatchReleaseImageContainer(ImageContainerChild* aChild) { if (!aChild) { return; } - if (!IsCreated()) { - delete aChild; + RefPtr bridge = GetSingleton(); + if (!bridge) { return; } - sImageBridgeChildSingleton->GetMessageLoop()->PostTask( - NewRunnableFunction(&ReleaseImageContainerNow, aChild)); + RefPtr child(aChild); + bridge->GetMessageLoop()->PostTask( + NewRunnableFunction(&ReleaseImageContainerNow, bridge, child)); } static void ReleaseTextureClientNow(TextureClient* aClient) @@ -666,15 +704,12 @@ void ImageBridgeChild::DispatchImageClientUpdate(ImageClient* aClient, RefPtr(aClient), RefPtr(aContainer))); } -static void UpdateAsyncCanvasRendererSync(AsyncCanvasRenderer* aWrapper, - ReentrantMonitor* aBarrier, - bool* const outDone) +static void +UpdateAsyncCanvasRendererSync(SynchronousTask* aTask, AsyncCanvasRenderer* aWrapper) { - ImageBridgeChild::UpdateAsyncCanvasRendererNow(aWrapper); + AutoCompleteTask complete(aTask); - ReentrantMonitorAutoEnter autoMon(*aBarrier); - *outDone = true; - aBarrier->NotifyAll(); + ImageBridgeChild::UpdateAsyncCanvasRendererNow(aWrapper); } // static @@ -687,18 +722,12 @@ void ImageBridgeChild::UpdateAsyncCanvasRenderer(AsyncCanvasRenderer* aWrapper) return; } - ReentrantMonitor barrier("UpdateAsyncCanvasRenderer Lock"); - ReentrantMonitorAutoEnter autoMon(barrier); - bool done = false; + SynchronousTask task("UpdateAsyncCanvasRenderer Lock"); sImageBridgeChildSingleton->GetMessageLoop()->PostTask( - NewRunnableFunction(&UpdateAsyncCanvasRendererSync, aWrapper, &barrier, &done)); + NewRunnableFunction(&UpdateAsyncCanvasRendererSync, &task, aWrapper)); - // should stop the thread until the CanvasClient has been created on - // the other thread - while (!done) { - barrier.Wait(); - } + task.Wait(); } // static @@ -710,17 +739,19 @@ void ImageBridgeChild::UpdateAsyncCanvasRendererNow(AsyncCanvasRenderer* aWrappe sImageBridgeChildSingleton->EndTransaction(); } -static void FlushAllImagesSync(ImageClient* aClient, ImageContainer* aContainer, - RefPtr&& aWaiter, - ReentrantMonitor* aBarrier, - bool* const outDone) +static void +FlushAllImagesSync(SynchronousTask* aTask, + ImageClient* aClient, + ImageContainer* aContainer, + RefPtr&& aWaiter) { #ifdef MOZ_WIDGET_GONK MOZ_ASSERT(aWaiter); #else MOZ_ASSERT(!aWaiter); #endif - ReentrantMonitorAutoEnter autoMon(*aBarrier); + + AutoCompleteTask complete(aTask); if (!ImageBridgeChild::IsCreated() || ImageBridgeChild::IsShutDown()) { // How sad. If we get into this branch it means that the ImageBridge @@ -733,9 +764,6 @@ static void FlushAllImagesSync(ImageClient* aClient, ImageContainer* aContainer, #ifdef MOZ_WIDGET_GONK aWaiter->DecrementWaitCount(); #endif - - *outDone = true; - aBarrier->NotifyAll(); return; } MOZ_ASSERT(aClient); @@ -752,8 +780,6 @@ static void FlushAllImagesSync(ImageClient* aClient, ImageContainer* aContainer, #ifdef MOZ_WIDGET_GONK aWaiter->DecrementWaitCount(); #endif - *outDone = true; - aBarrier->NotifyAll(); } // static @@ -771,9 +797,7 @@ void ImageBridgeChild::FlushAllImages(ImageClient* aClient, return; } - ReentrantMonitor barrier("FlushAllImages Lock"); - ReentrantMonitorAutoEnter autoMon(barrier); - bool done = false; + SynchronousTask task("FlushAllImages Lock"); RefPtr waiter; #ifdef MOZ_WIDGET_GONK @@ -782,11 +806,9 @@ void ImageBridgeChild::FlushAllImages(ImageClient* aClient, waiter->IncrementWaitCount(); #endif sImageBridgeChildSingleton->GetMessageLoop()->PostTask( - NewRunnableFunction(&FlushAllImagesSync, aClient, aContainer, waiter, &barrier, &done)); + NewRunnableFunction(&FlushAllImagesSync, &task, aClient, aContainer, waiter)); - while (!done) { - barrier.Wait(); - } + task.Wait(); #ifdef MOZ_WIDGET_GONK waiter->WaitComplete(); @@ -900,27 +922,21 @@ void ImageBridgeChild::ShutDown() MOZ_ASSERT(!sImageBridgeChildSingleton->mShuttingDown); { - ReentrantMonitor barrier("ImageBridge ShutdownStep1 lock"); - ReentrantMonitorAutoEnter autoMon(barrier); + SynchronousTask task("ImageBridge ShutdownStep1 lock"); - bool done = false; sImageBridgeChildSingleton->GetMessageLoop()->PostTask( - NewRunnableFunction(&ImageBridgeShutdownStep1, &barrier, &done)); - while (!done) { - barrier.Wait(); - } + NewRunnableFunction(&ImageBridgeShutdownStep1, &task)); + + task.Wait(); } { - ReentrantMonitor barrier("ImageBridge ShutdownStep2 lock"); - ReentrantMonitorAutoEnter autoMon(barrier); + SynchronousTask task("ImageBridge ShutdownStep2 lock"); - bool done = false; sImageBridgeChildSingleton->GetMessageLoop()->PostTask( - NewRunnableFunction(&ImageBridgeShutdownStep2, &barrier, &done)); - while (!done) { - barrier.Wait(); - } + NewRunnableFunction(&ImageBridgeShutdownStep2, &task)); + + task.Wait(); } sImageBridgeChildSingleton = nullptr; @@ -996,44 +1012,46 @@ ImageBridgeChild::IdentifyCompositorTextureHost(const TextureFactoryIdentifier& } } -already_AddRefed +RefPtr ImageBridgeChild::CreateImageClient(CompositableType aType, - ImageContainer* aImageContainer) + ImageContainer* aImageContainer, + ImageContainerChild* aContainerChild) { if (InImageBridgeChildThread()) { - return CreateImageClientNow(aType, aImageContainer); + return CreateImageClientNow(aType, aImageContainer, aContainerChild); } - ReentrantMonitor barrier("CreateImageClient Lock"); - ReentrantMonitorAutoEnter autoMon(barrier); - bool done = false; + + SynchronousTask task("CreateImageClient Lock"); RefPtr result = nullptr; GetMessageLoop()->PostTask( - NewRunnableFunction(&CreateImageClientSync, &result, &barrier, aType, - aImageContainer, &done)); - // should stop the thread until the ImageClient has been created on - // the other thread - while (!done) { - barrier.Wait(); - } - return result.forget(); + NewRunnableFunction(&CreateImageClientSync, &task, this, &result, aType, + aImageContainer, aContainerChild)); + + task.Wait(); + + return result; } -already_AddRefed +RefPtr ImageBridgeChild::CreateImageClientNow(CompositableType aType, - ImageContainer* aImageContainer) + ImageContainer* aImageContainer, + ImageContainerChild* aContainerChild) { - MOZ_ASSERT(!sImageBridgeChildSingleton->mShuttingDown); + MOZ_ASSERT(!mShuttingDown); + MOZ_ASSERT(InImageBridgeChildThread()); + if (aImageContainer) { - SendPImageContainerConstructor(aImageContainer->GetPImageContainerChild()); + SendPImageContainerConstructor(aContainerChild); + aContainerChild->RegisterWithIPDL(); } - RefPtr client - = ImageClient::CreateImageClient(aType, this, TextureFlags::NO_FLAGS); + + RefPtr client = ImageClient::CreateImageClient(aType, this, TextureFlags::NO_FLAGS); MOZ_ASSERT(client, "failed to create ImageClient"); if (client) { client->Connect(aImageContainer); } - return client.forget(); + return client; } already_AddRefed @@ -1043,18 +1061,15 @@ ImageBridgeChild::CreateCanvasClient(CanvasClient::CanvasClientType aType, if (InImageBridgeChildThread()) { return CreateCanvasClientNow(aType, aFlag); } - ReentrantMonitor barrier("CreateCanvasClient Lock"); - ReentrantMonitorAutoEnter autoMon(barrier); - bool done = false; + + SynchronousTask task("CreateCanvasClient Lock"); RefPtr result = nullptr; GetMessageLoop()->PostTask(NewRunnableFunction(&CreateCanvasClientSync, - &barrier, aType, aFlag, &result, &done)); - // should stop the thread until the CanvasClient has been created on the - // other thread - while (!done) { - barrier.Wait(); - } + &task, aType, aFlag, &result)); + + task.Wait(); + return result.forget(); } @@ -1109,13 +1124,12 @@ struct AllocShmemParams { bool mSuccess; }; -static void ProxyAllocShmemNow(AllocShmemParams* aParams, - ReentrantMonitor* aBarrier, - bool* aDone) +static void +ProxyAllocShmemNow(SynchronousTask* aTask, AllocShmemParams* aParams) { + AutoCompleteTask complete(aTask); + MOZ_ASSERT(aParams); - MOZ_ASSERT(aDone); - MOZ_ASSERT(aBarrier); auto shmAllocator = aParams->mAllocator->AsShmemAllocator(); if (aParams->mUnsafe) { @@ -1127,10 +1141,6 @@ static void ProxyAllocShmemNow(AllocShmemParams* aParams, aParams->mType, aParams->mShmem); } - - ReentrantMonitorAutoEnter autoMon(*aBarrier); - *aDone = true; - aBarrier->NotifyAll(); } bool @@ -1139,38 +1149,29 @@ ImageBridgeChild::DispatchAllocShmemInternal(size_t aSize, ipc::Shmem* aShmem, bool aUnsafe) { - ReentrantMonitor barrier("AllocatorProxy alloc"); - ReentrantMonitorAutoEnter autoMon(barrier); + SynchronousTask task("AllocatorProxy alloc"); AllocShmemParams params = { this, aSize, aType, aShmem, aUnsafe, true }; - bool done = false; GetMessageLoop()->PostTask(NewRunnableFunction(&ProxyAllocShmemNow, - ¶ms, - &barrier, - &done)); - while (!done) { - barrier.Wait(); - } + &task, ¶ms)); + + task.Wait(); + return params.mSuccess; } -static void ProxyDeallocShmemNow(ISurfaceAllocator* aAllocator, - ipc::Shmem* aShmem, - ReentrantMonitor* aBarrier, - bool* aDone) +static void ProxyDeallocShmemNow(SynchronousTask* aTask, + ISurfaceAllocator* aAllocator, + ipc::Shmem* aShmem) { + AutoCompleteTask complete(aTask); + MOZ_ASSERT(aShmem); - MOZ_ASSERT(aDone); - MOZ_ASSERT(aBarrier); aAllocator->AsShmemAllocator()->DeallocShmem(*aShmem); - - ReentrantMonitorAutoEnter autoMon(*aBarrier); - *aDone = true; - aBarrier->NotifyAll(); } void @@ -1179,18 +1180,14 @@ ImageBridgeChild::DeallocShmem(ipc::Shmem& aShmem) if (InImageBridgeChildThread()) { PImageBridgeChild::DeallocShmem(aShmem); } else { - ReentrantMonitor barrier("AllocatorProxy Dealloc"); - ReentrantMonitorAutoEnter autoMon(barrier); + SynchronousTask task("AllocatorProxy Dealloc"); - bool done = false; GetMessageLoop()->PostTask(NewRunnableFunction(&ProxyDeallocShmemNow, + &task, this, - &aShmem, - &barrier, - &done)); - while (!done) { - barrier.Wait(); - } + &aShmem)); + + task.Wait(); } } @@ -1236,7 +1233,7 @@ ImageBridgeChild::AllocPImageContainerChild() bool ImageBridgeChild::DeallocPImageContainerChild(PImageContainerChild* actor) { - ImageContainer::DeallocActor(actor); + static_cast(actor)->UnregisterFromIPDL(); return true; } @@ -1298,7 +1295,11 @@ bool ImageBridgeChild::RecvDidComposite(InfallibleTArray&& aNotifications) { for (auto& n : aNotifications) { - ImageContainer::NotifyComposite(n); + ImageContainerChild* child = + static_cast(n.imageContainerChild()); + if (child) { + child->NotifyComposite(n); + } } return true; } diff --git a/gfx/layers/ipc/ImageBridgeChild.h b/gfx/layers/ipc/ImageBridgeChild.h index e47bf5a119a9a..86d2bf0ebb596 100644 --- a/gfx/layers/ipc/ImageBridgeChild.h +++ b/gfx/layers/ipc/ImageBridgeChild.h @@ -39,6 +39,7 @@ class AsyncCanvasRenderer; class AsyncTransactionTracker; class ImageClient; class ImageContainer; +class ImageContainerChild; class ImageBridgeParent; class CompositableClient; struct CompositableTransaction; @@ -218,16 +219,24 @@ class ImageBridgeChild final : public PImageBridgeChild virtual bool RecvDidComposite(InfallibleTArray&& aNotifications) override; - already_AddRefed CreateImageClient(CompositableType aType, - ImageContainer* aImageContainer); - already_AddRefed CreateImageClientNow(CompositableType aType, - ImageContainer* aImageContainer); + // Create an ImageClient from any thread. + RefPtr CreateImageClient( + CompositableType aType, + ImageContainer* aImageContainer, + ImageContainerChild* aContainerChild); + + // Create an ImageClient from the ImageBridge thread. + RefPtr CreateImageClientNow( + CompositableType aType, + ImageContainer* aImageContainer, + ImageContainerChild* aContainerChild); + already_AddRefed CreateCanvasClient(CanvasClient::CanvasClientType aType, TextureFlags aFlag); already_AddRefed CreateCanvasClientNow(CanvasClient::CanvasClientType aType, TextureFlags aFlag); - static void DispatchReleaseImageContainer(PImageContainerChild* aChild = nullptr); + static void DispatchReleaseImageContainer(ImageContainerChild* aChild); static void DispatchReleaseTextureClient(TextureClient* aClient); static void DispatchImageClientUpdate(ImageClient* aClient, ImageContainer* aContainer); diff --git a/gfx/layers/ipc/ImageContainerChild.cpp b/gfx/layers/ipc/ImageContainerChild.cpp new file mode 100644 index 0000000000000..c54eb2c419fb1 --- /dev/null +++ b/gfx/layers/ipc/ImageContainerChild.cpp @@ -0,0 +1,70 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "ImageContainerChild.h" +#include "ImageContainer.h" +#include "mozilla/Assertions.h" +#include "mozilla/layers/ImageBridgeChild.h" + +namespace mozilla { +namespace layers { + +ImageContainerChild::ImageContainerChild(ImageContainer* aImageContainer) + : mLock("ImageContainerChild") + , mImageContainer(aImageContainer) + , mIPCOpen(false) +{ +} + +void +ImageContainerChild::ForgetImageContainer() +{ + MutexAutoLock lock(mLock); + mImageContainer = nullptr; +} + +void +ImageContainerChild::NotifyComposite(const ImageCompositeNotification& aNotification) +{ + MOZ_ASSERT(InImageBridgeChildThread()); + + MutexAutoLock lock(mLock); + if (mImageContainer) { + mImageContainer->NotifyCompositeInternal(aNotification); + } +} + +void +ImageContainerChild::RegisterWithIPDL() +{ + MOZ_ASSERT(!mIPCOpen); + MOZ_ASSERT(InImageBridgeChildThread()); + + AddRef(); + mIPCOpen = true; +} + +void +ImageContainerChild::UnregisterFromIPDL() +{ + MOZ_ASSERT(mIPCOpen); + MOZ_ASSERT(InImageBridgeChildThread()); + + mIPCOpen = false; + Release(); +} + +void +ImageContainerChild::SendAsyncDelete() +{ + MOZ_ASSERT(InImageBridgeChildThread()); + + if (mIPCOpen) { + PImageContainerChild::SendAsyncDelete(); + } +} + +} // namespace layers +} // namespace mozilla diff --git a/gfx/layers/ipc/ImageContainerChild.h b/gfx/layers/ipc/ImageContainerChild.h new file mode 100644 index 0000000000000..839540411fbcb --- /dev/null +++ b/gfx/layers/ipc/ImageContainerChild.h @@ -0,0 +1,61 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_gfx_layers_ImageContainerChild_h +#define mozilla_gfx_layers_ImageContainerChild_h + +#include "mozilla/Mutex.h" +#include "mozilla/layers/PImageContainerChild.h" + +namespace mozilla { +namespace layers { + +class ImageContainer; +class ImageCompositeNotification; + +/** + * The child side of PImageContainer. It's best to avoid ImageContainer filling + * this role since IPDL objects should be associated with a single thread and + * ImageContainer definitely isn't. This object belongs to (and is always + * destroyed on) the ImageBridge thread, except when we need to destroy it + * during shutdown. + * An ImageContainer owns one of these; we have a weak reference to our + * ImageContainer. + */ +class ImageContainerChild final : public PImageContainerChild +{ +public: + explicit ImageContainerChild(ImageContainer* aImageContainer); + + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ImageContainerChild) + + void RegisterWithIPDL(); + void UnregisterFromIPDL(); + void SendAsyncDelete(); + + void NotifyComposite(const ImageCompositeNotification& aNotification); + void ForgetImageContainer(); + +private: + ~ImageContainerChild() + {} + +private: + Mutex mLock; + ImageContainer* mImageContainer; + + // If mIPCOpen is false, it means the IPDL code tried to deallocate the actor + // before the ImageContainer released it. When this happens we don't actually + // delete the actor right away because the ImageContainer has a reference to + // it. In this case the actor will be deleted when the ImageContainer lets go + // of it. + // mIPCOpen must not be accessed off the ImageBridgeChild thread. + bool mIPCOpen; +}; + +} // namespace layers +} // namespace mozilla + +#endif // mozilla_gfx_layers_ImageContainerChild_h diff --git a/gfx/layers/moz.build b/gfx/layers/moz.build index 2fed1c32dab17..17396bad50d26 100644 --- a/gfx/layers/moz.build +++ b/gfx/layers/moz.build @@ -170,6 +170,7 @@ EXPORTS.mozilla.layers += [ 'ipc/GonkNativeHandleUtils.h', 'ipc/ImageBridgeChild.h', 'ipc/ImageBridgeParent.h', + 'ipc/ImageContainerChild.h', 'ipc/ImageContainerParent.h', 'ipc/ISurfaceAllocator.h', 'ipc/LayerAnimationUtils.h', @@ -363,6 +364,7 @@ UNIFIED_SOURCES += [ 'ipc/FenceUtils.cpp', 'ipc/ImageBridgeChild.cpp', 'ipc/ImageBridgeParent.cpp', + 'ipc/ImageContainerChild.cpp', 'ipc/ImageContainerParent.cpp', 'ipc/ISurfaceAllocator.cpp', 'ipc/LayerAnimationUtils.cpp', diff --git a/gfx/layers/opengl/CompositorOGL.cpp b/gfx/layers/opengl/CompositorOGL.cpp index 1aafa85946999..dbcf53dcfd132 100644 --- a/gfx/layers/opengl/CompositorOGL.cpp +++ b/gfx/layers/opengl/CompositorOGL.cpp @@ -710,7 +710,7 @@ CompositorOGL::BeginFrame(const nsIntRegion& aInvalidRegion, aClipRectOut->SetRect(0, 0, width, height); } - mGLContext->fClearColor(mBeginFrameClearColor.r, mBeginFrameClearColor.g, mBeginFrameClearColor.b, mBeginFrameClearColor.a); + mGLContext->fClearColor(mClearColor.r, mClearColor.g, mClearColor.b, mClearColor.a); mGLContext->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT); } diff --git a/gfx/thebes/gfxTextRun.cpp b/gfx/thebes/gfxTextRun.cpp index d36210068c876..e1bf9638105ff 100644 --- a/gfx/thebes/gfxTextRun.cpp +++ b/gfx/thebes/gfxTextRun.cpp @@ -838,6 +838,7 @@ gfxTextRun::BreakAndMeasureText(uint32_t aStart, uint32_t aMaxLength, PropertyProvider *aProvider, SuppressBreak aSuppressBreak, gfxFloat *aTrimWhitespace, + bool aWhitespaceCanHang, Metrics *aMetrics, gfxFont::BoundingBoxType aBoundingBoxType, DrawTarget* aRefDrawTarget, @@ -868,7 +869,7 @@ gfxTextRun::BreakAndMeasureText(uint32_t aStart, uint32_t aMaxLength, gfxFloat width = 0; gfxFloat advance = 0; - // The number of space characters that can be trimmed + // The number of space characters that can be trimmed or hang at a soft-wrap uint32_t trimmableChars = 0; // The amount of space removed by ignoring trimmableChars gfxFloat trimmableAdvance = 0; @@ -951,7 +952,7 @@ gfxTextRun::BreakAndMeasureText(uint32_t aStart, uint32_t aMaxLength, } advance += charAdvance; - if (aTrimWhitespace) { + if (aTrimWhitespace || aWhitespaceCanHang) { if (mCharacterGlyphs[i].CharIsSpace()) { ++trimmableChars; trimmableAdvance += charAdvance; @@ -985,13 +986,25 @@ gfxTextRun::BreakAndMeasureText(uint32_t aStart, uint32_t aMaxLength, if (aMetrics) { auto fitEnd = aStart + charsFit; - *aMetrics = MeasureText(Range(aStart, fitEnd), aBoundingBoxType, - aRefDrawTarget, aProvider); - if (trimmableChars) { - Metrics trimMetrics = + // Initially, measure everything, so that our bounding box includes + // any trimmable or hanging whitespace. + *aMetrics = MeasureText(Range(aStart, fitEnd), + aBoundingBoxType, aRefDrawTarget, + aProvider); + if (aTrimWhitespace || aWhitespaceCanHang) { + // Measure trailing whitespace that is to be trimmed/hung. + Metrics trimOrHangMetrics = MeasureText(Range(fitEnd - trimmableChars, fitEnd), - aBoundingBoxType, aRefDrawTarget, aProvider); - aMetrics->mAdvanceWidth -= trimMetrics.mAdvanceWidth; + aBoundingBoxType, aRefDrawTarget, + aProvider); + if (aTrimWhitespace) { + aMetrics->mAdvanceWidth -= trimOrHangMetrics.mAdvanceWidth; + } else if (aMetrics->mAdvanceWidth > aWidth) { + // Restrict width of hanging whitespace so it doesn't overflow. + aMetrics->mAdvanceWidth = + std::max(aWidth, aMetrics->mAdvanceWidth - + trimOrHangMetrics.mAdvanceWidth); + } } } if (aTrimWhitespace) { diff --git a/gfx/thebes/gfxTextRun.h b/gfx/thebes/gfxTextRun.h index 3a5b27c88794d..77fb6c700baa0 100644 --- a/gfx/thebes/gfxTextRun.h +++ b/gfx/thebes/gfxTextRun.h @@ -395,6 +395,7 @@ class gfxTextRun : public gfxShapedText PropertyProvider *aProvider, SuppressBreak aSuppressBreak, gfxFloat *aTrimWhitespace, + bool aHangWhitespace, Metrics *aMetrics, gfxFont::BoundingBoxType aBoundingBoxType, DrawTarget* aDrawTargetForTightBoundingBox, diff --git a/hal/gonk/SystemService.cpp b/hal/gonk/SystemService.cpp index 893fac76ffb35..2b98f5fdd6d42 100644 --- a/hal/gonk/SystemService.cpp +++ b/hal/gonk/SystemService.cpp @@ -36,7 +36,7 @@ SystemServiceIsRunning(const char* aSvcName) } char value[PROPERTY_VALUE_MAX]; - NS_WARN_IF(property_get(key, value, "") < 0); + Unused << NS_WARN_IF(property_get(key, value, "") < 0); return !strcmp(value, "running"); } diff --git a/image/decoders/nsGIFDecoder2.cpp b/image/decoders/nsGIFDecoder2.cpp index ea5f1023154b3..62ae2704ceb2e 100644 --- a/image/decoders/nsGIFDecoder2.cpp +++ b/image/decoders/nsGIFDecoder2.cpp @@ -1034,7 +1034,8 @@ nsGIFDecoder2::ReadLZWData(const char* aData, size_t aLength) continue; case WriteState::FINISHED: - NS_WARN_IF(mGIFStruct.pixels_remaining > 0); + NS_WARNING_ASSERTION(mGIFStruct.pixels_remaining <= 0, + "too many pixels"); mGIFStruct.pixels_remaining = 0; break; diff --git a/image/decoders/nsPNGDecoder.cpp b/image/decoders/nsPNGDecoder.cpp index 9cc2a6150bacb..0556ff97d751c 100644 --- a/image/decoders/nsPNGDecoder.cpp +++ b/image/decoders/nsPNGDecoder.cpp @@ -976,7 +976,7 @@ nsPNGDecoder::frame_info_callback(png_structp png_ptr, png_uint_32 frame_num) png_get_next_frame_height(png_ptr, decoder->mInfo)); const bool isInterlaced = bool(decoder->interlacebuf); -#ifndef PNGLCONF_H +#ifndef MOZ_EMBEDDED_LIBPNG // if using system library, check frame_width and height against 0 if (frameRect.width == 0) png_error(png_ptr, "Frame width must not be 0"); diff --git a/ipc/mscom/EnsureMTA.cpp b/ipc/mscom/EnsureMTA.cpp index 74c0bc8994db8..f4bc911e9b21d 100644 --- a/ipc/mscom/EnsureMTA.cpp +++ b/ipc/mscom/EnsureMTA.cpp @@ -34,7 +34,7 @@ class BackgroundMTAData nsCOMPtr runnable = new EnterMTARunnable(); nsresult rv = NS_NewNamedThread("COM MTA", getter_AddRefs(mThread), runnable); - NS_WARN_IF(NS_FAILED(rv)); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_NewNamedThread failed"); MOZ_ASSERT(NS_SUCCEEDED(rv)); } diff --git a/ipc/mscom/InterceptorLog.cpp b/ipc/mscom/InterceptorLog.cpp index d4ef149aca74b..c2cd3c7df8424 100644 --- a/ipc/mscom/InterceptorLog.cpp +++ b/ipc/mscom/InterceptorLog.cpp @@ -14,6 +14,7 @@ #include "mozilla/Services.h" #include "mozilla/StaticPtr.h" #include "mozilla/TimeStamp.h" +#include "mozilla/Unused.h" #include "nsAppDirectoryServiceDefs.h" #include "nsDirectoryServiceDefs.h" #include "nsDirectoryServiceUtils.h" @@ -40,6 +41,7 @@ using mozilla::services::GetObserverService; using mozilla::StaticAutoPtr; using mozilla::TimeDuration; using mozilla::TimeStamp; +using mozilla::Unused; namespace { @@ -178,10 +180,10 @@ Logger::Shutdown() nsresult rv = mThread->Dispatch(NewNonOwningRunnableMethod(this, &Logger::CloseFile), NS_DISPATCH_NORMAL); - NS_WARN_IF(NS_FAILED(rv)); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Dispatch failed"); rv = mThread->Shutdown(); - NS_WARN_IF(NS_FAILED(rv)); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Shutdown failed"); return NS_OK; } @@ -399,7 +401,7 @@ ShutdownEvent::Observe(nsISupports* aSubject, const char* aTopic, return NS_ERROR_NOT_IMPLEMENTED; } MOZ_ASSERT(sLogger); - NS_WARN_IF(NS_FAILED(sLogger->Shutdown())); + Unused << NS_WARN_IF(NS_FAILED(sLogger->Shutdown())); nsCOMPtr kungFuDeathGrip(this); nsCOMPtr obsSvc = GetObserverService(); obsSvc->RemoveObserver(this, aTopic); diff --git a/ipc/mscom/MainThreadInvoker.cpp b/ipc/mscom/MainThreadInvoker.cpp index 310352f8e4036..2e7ac947110e1 100644 --- a/ipc/mscom/MainThreadInvoker.cpp +++ b/ipc/mscom/MainThreadInvoker.cpp @@ -131,7 +131,7 @@ MainThreadInvoker::Invoke(already_AddRefed&& aRunnable, // check for APCs during event processing. If we omit this then the main // thread will not check its APC queue until it is idle. Note that failing to // dispatch this event is non-fatal, but it will delay execution of the APC. - NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(sAlertRunnable))); + Unused << NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(sAlertRunnable))); return WaitForCompletion(aTimeout); } diff --git a/ipc/ril/RilSocket.cpp b/ipc/ril/RilSocket.cpp index cb5d96e9aabb7..4ff71d253ae7b 100644 --- a/ipc/ril/RilSocket.cpp +++ b/ipc/ril/RilSocket.cpp @@ -219,7 +219,7 @@ void RilSocketIO::ConsumeBuffer() { RefPtr task = new ReceiveTask(this, mBuffer.release()); - NS_WARN_IF(!mDispatcher->PostTask(task)); + Unused << NS_WARN_IF(!mDispatcher->PostTask(task)); } void diff --git a/ipc/unixfd/UnixFdWatcher.cpp b/ipc/unixfd/UnixFdWatcher.cpp index 231ff7e905875..41289a90b82f1 100644 --- a/ipc/unixfd/UnixFdWatcher.cpp +++ b/ipc/unixfd/UnixFdWatcher.cpp @@ -25,7 +25,7 @@ namespace ipc { UnixFdWatcher::~UnixFdWatcher() { - NS_WARN_IF(IsOpen()); /* mFd should have been closed already */ + NS_WARNING_ASSERTION(!IsOpen(), "mFd should have been closed already"); } void diff --git a/ipc/unixsocket/ListenSocket.cpp b/ipc/unixsocket/ListenSocket.cpp index 0c8016378e21a..c05a4d7016cdd 100644 --- a/ipc/unixsocket/ListenSocket.cpp +++ b/ipc/unixsocket/ListenSocket.cpp @@ -9,6 +9,7 @@ #include "ConnectionOrientedSocket.h" #include "DataSocket.h" #include "ListenSocketConsumer.h" +#include "mozilla/DebugOnly.h" #include "mozilla/RefPtr.h" #include "mozilla/Unused.h" #include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, MOZ_COUNT_DTOR @@ -153,8 +154,8 @@ ListenSocketIO::Listen(ConnectionOrientedSocketIO* aCOSocketIO) mCOSocketIO = aCOSocketIO; // calls OnListening on success, or OnError otherwise - nsresult rv = UnixSocketWatcher::Listen(address, mAddressLength); - NS_WARN_IF(NS_FAILED(rv)); + DebugOnly rv = UnixSocketWatcher::Listen(address, mAddressLength); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Listen failed"); } void diff --git a/js/src/asmjs/AsmJS.cpp b/js/src/asmjs/AsmJS.cpp index dd7a89bf91599..a7cfbdd779bfe 100644 --- a/js/src/asmjs/AsmJS.cpp +++ b/js/src/asmjs/AsmJS.cpp @@ -337,8 +337,10 @@ struct js::AsmJSMetadata : Metadata, AsmJSMetadataCacheablePod ScriptSource* maybeScriptSource() const override { return scriptSource.get(); } - bool getFuncName(JSContext* cx, const Bytes*, uint32_t funcIndex, TwoByteName* name) const override { - const char* p = asmJSFuncNames[funcIndex].get(); + bool getFuncDefName(JSContext* cx, const Bytes*, uint32_t funcDefIndex, + TwoByteName* name) const override + { + const char* p = asmJSFuncNames[funcDefIndex].get(); UTF8Chars utf8(p, strlen(p)); size_t twoByteLength; @@ -1775,7 +1777,7 @@ class MOZ_STACK_CLASS ModuleValidator auto genData = MakeUnique(ModuleKind::AsmJS); if (!genData || !genData->sigs.resize(MaxSigs) || - !genData->funcSigs.resize(MaxFuncs) || + !genData->funcDefSigs.resize(MaxFuncs) || !genData->funcImports.resize(MaxImports) || !genData->tables.resize(MaxTables) || !genData->asmJSSigToTableIndex.resize(MaxSigs)) @@ -2068,8 +2070,8 @@ class MOZ_STACK_CLASS ModuleValidator return false; // Declare which function is exported which gives us an index into the - // module FuncExportVector. - if (!mg_.addFuncExport(Move(fieldChars), func.index())) + // module FuncDefExportVector. + if (!mg_.addFuncDefExport(Move(fieldChars), mg_.numFuncImports() + func.index())) return false; // The exported function might have already been exported in which case @@ -2085,7 +2087,7 @@ class MOZ_STACK_CLASS ModuleValidator uint32_t funcIndex = numFunctions(); if (funcIndex >= MaxFuncs) return failCurrentOffset("too many functions"); - mg_.initFuncSig(funcIndex, sigIndex); + mg_.initFuncDefSig(funcIndex, sigIndex); Global* global = validationLifo_.new_(Global::Function); if (!global) return false; @@ -4659,7 +4661,7 @@ CheckFunctionSignature(ModuleValidator& m, ParseNode* usepn, Sig&& sig, Property return m.addFunction(name, usepn->pn_pos.begin, Move(sig), func); } - if (!CheckSignatureAgainstExisting(m, usepn, sig, m.mg().funcSig(existing->index()))) + if (!CheckSignatureAgainstExisting(m, usepn, sig, m.mg().funcDefSig(existing->index()))) return false; *func = existing; @@ -7103,7 +7105,7 @@ CheckFuncPtrTable(ModuleValidator& m, ParseNode* var) if (!func) return m.fail(elem, "function-pointer table's elements must be names of functions"); - const Sig& funcSig = m.mg().funcSig(func->index()); + const Sig& funcSig = m.mg().funcDefSig(func->index()); if (sig) { if (*sig != funcSig) return m.fail(elem, "all functions in table must have same signature"); @@ -8788,7 +8790,7 @@ js::AsmJSFunctionToString(JSContext* cx, HandleFunction fun) MOZ_ASSERT(IsAsmJSFunction(fun)); const AsmJSMetadata& metadata = ExportedFunctionToInstance(fun).metadata().asAsmJS(); - const AsmJSExport& f = metadata.lookupAsmJSExport(ExportedFunctionToIndex(fun)); + const AsmJSExport& f = metadata.lookupAsmJSExport(ExportedFunctionToDefinitionIndex(fun)); uint32_t begin = metadata.srcStart + f.startOffsetInModule(); uint32_t end = metadata.srcStart + f.endOffsetInModule(); diff --git a/js/src/asmjs/WasmAST.h b/js/src/asmjs/WasmAST.h index 1f9439dc3f8df..b519ce18eb7dd 100644 --- a/js/src/asmjs/WasmAST.h +++ b/js/src/asmjs/WasmAST.h @@ -646,14 +646,15 @@ class AstExport : public AstNode class AstDataSegment : public AstNode { - uint32_t offset_; + AstExpr* offset_; AstName text_; public: - AstDataSegment(uint32_t offset, AstName text) + AstDataSegment(AstExpr* offset, AstName text) : offset_(offset), text_(text) {} - uint32_t offset() const { return offset_; } + + AstExpr* offset() const { return offset_; } AstName text() const { return text_; } }; diff --git a/js/src/asmjs/WasmBaselineCompile.cpp b/js/src/asmjs/WasmBaselineCompile.cpp index 172f31d78221c..8074e3b63f561 100644 --- a/js/src/asmjs/WasmBaselineCompile.cpp +++ b/js/src/asmjs/WasmBaselineCompile.cpp @@ -1787,8 +1787,8 @@ class BaseCompiler void beginFunction() { JitSpew(JitSpew_Codegen, "# Emitting wasm baseline code"); - wasm::GenerateFunctionPrologue(masm, localSize_, mg_.funcSigs[func_.index()]->id, - &compileResults_.offsets()); + SigIdDesc sigId = mg_.funcDefSigs[func_.defIndex()]->id; + wasm::GenerateFunctionPrologue(masm, localSize_, sigId, &compileResults_.offsets()); MOZ_ASSERT(masm.framePushed() == uint32_t(localSize_)); @@ -2122,10 +2122,10 @@ class BaseCompiler } } - void callDirect(uint32_t calleeIndex, const FunctionCall& call) + void callDefinition(uint32_t funcDefIndex, const FunctionCall& call) { CallSiteDesc desc(call.lineOrBytecode_, CallSiteDesc::Relative); - masm.call(desc, calleeIndex); + masm.call(desc, funcDefIndex); } void callSymbolic(wasm::SymbolicAddress callee, const FunctionCall& call) { @@ -3372,12 +3372,14 @@ class BaseCompiler MOZ_MUST_USE bool skipCall(const ValTypeVector& args, ExprType maybeReturnType = ExprType::Limit); MOZ_MUST_USE - bool emitCall(uint32_t callOffset); + bool emitCallImportCommon(uint32_t lineOrBytecode, uint32_t funcImportIndex); MOZ_MUST_USE - bool emitCallIndirect(uint32_t callOffset); + bool emitCall(uint32_t callOffset); MOZ_MUST_USE bool emitCallImport(uint32_t callOffset); MOZ_MUST_USE + bool emitCallIndirect(uint32_t callOffset); + MOZ_MUST_USE bool emitUnaryMathBuiltinCall(uint32_t callOffset, SymbolicAddress callee, ValType operandType); MOZ_MUST_USE bool emitBinaryMathBuiltinCall(uint32_t callOffset, SymbolicAddress callee, ValType operandType); @@ -5258,16 +5260,10 @@ BaseCompiler::pushReturned(const FunctionCall& call, ExprType type) // for outgoing arguments. A sync() is just simpler. bool -BaseCompiler::emitCall(uint32_t callOffset) +BaseCompiler::emitCallImportCommon(uint32_t lineOrBytecode, uint32_t funcImportIndex) { - uint32_t lineOrBytecode = readCallSiteLineOrBytecode(callOffset); - - uint32_t calleeIndex; - uint32_t arity; - if (!iter_.readCall(&calleeIndex, &arity)) - return false; - - const Sig& sig = *mg_.funcSigs[calleeIndex]; + const FuncImportGenDesc& funcImport = mg_.funcImports[funcImportIndex]; + const Sig& sig = *funcImport.sig; if (deadCode_) return skipCall(sig.args(), sig.ret()); @@ -5278,7 +5274,7 @@ BaseCompiler::emitCall(uint32_t callOffset) size_t stackSpace = stackConsumed(numArgs); FunctionCall baselineCall(lineOrBytecode); - beginCall(baselineCall, EscapesSandbox(false), IsBuiltinCall(false)); + beginCall(baselineCall, EscapesSandbox(true), IsBuiltinCall(false)); if (!emitCallArgs(sig.args(), baselineCall)) return false; @@ -5286,7 +5282,7 @@ BaseCompiler::emitCall(uint32_t callOffset) if (!iter_.readCallReturn(sig.ret())) return false; - callDirect(calleeIndex, baselineCall); + callImport(funcImport.globalDataOffset, baselineCall); endCall(baselineCall); @@ -5302,30 +5298,31 @@ BaseCompiler::emitCall(uint32_t callOffset) } bool -BaseCompiler::emitCallIndirect(uint32_t callOffset) +BaseCompiler::emitCall(uint32_t callOffset) { uint32_t lineOrBytecode = readCallSiteLineOrBytecode(callOffset); - uint32_t sigIndex; + uint32_t calleeIndex; uint32_t arity; - if (!iter_.readCallIndirect(&sigIndex, &arity)) + if (!iter_.readCall(&calleeIndex, &arity)) return false; - Nothing callee_; + // For asm.js and old-format wasm code, imports are not part of the function + // index space so in these cases firstFuncDefIndex is fixed to 0, even if + // there are function imports. + if (calleeIndex < mg_.firstFuncDefIndex) + return emitCallImportCommon(lineOrBytecode, calleeIndex); - const SigWithId& sig = mg_.sigs[sigIndex]; + uint32_t funcDefIndex = calleeIndex - mg_.firstFuncDefIndex; + const Sig& sig = *mg_.funcDefSigs[funcDefIndex]; - if (deadCode_) { - return skipCall(sig.args()) && iter_.readCallIndirectCallee(&callee_) && - iter_.readCallReturn(sig.ret()); - } + if (deadCode_) + return skipCall(sig.args(), sig.ret()); sync(); - // Stack: ... index arg1 .. argn - uint32_t numArgs = sig.args().length(); - size_t stackSpace = stackConsumed(numArgs+1); + size_t stackSpace = stackConsumed(numArgs); FunctionCall baselineCall(lineOrBytecode); beginCall(baselineCall, EscapesSandbox(false), IsBuiltinCall(false)); @@ -5333,22 +5330,17 @@ BaseCompiler::emitCallIndirect(uint32_t callOffset) if (!emitCallArgs(sig.args(), baselineCall)) return false; - if (!iter_.readCallIndirectCallee(&callee_)) - return false; - if (!iter_.readCallReturn(sig.ret())) return false; - Stk& callee = peek(numArgs); - - callIndirect(sigIndex, callee, baselineCall); + callDefinition(funcDefIndex, baselineCall); endCall(baselineCall); // TODO / OPTIMIZE: It would be better to merge this freeStack() // into the one in endCall, if we can. - popValueStackBy(numArgs+1); + popValueStackBy(numArgs); masm.freeStack(stackSpace); pushReturned(baselineCall, sig.ret()); @@ -5359,6 +5351,8 @@ BaseCompiler::emitCallIndirect(uint32_t callOffset) bool BaseCompiler::emitCallImport(uint32_t callOffset) { + MOZ_ASSERT(!mg_.firstFuncDefIndex); + uint32_t lineOrBytecode = readCallSiteLineOrBytecode(callOffset); uint32_t funcImportIndex; @@ -5366,34 +5360,57 @@ BaseCompiler::emitCallImport(uint32_t callOffset) if (!iter_.readCallImport(&funcImportIndex, &arity)) return false; - const FuncImportGenDesc& funcImport = mg_.funcImports[funcImportIndex]; - const Sig& sig = *funcImport.sig; + return emitCallImportCommon(lineOrBytecode, funcImportIndex); +} - if (deadCode_) - return skipCall(sig.args(), sig.ret()); +bool +BaseCompiler::emitCallIndirect(uint32_t callOffset) +{ + uint32_t lineOrBytecode = readCallSiteLineOrBytecode(callOffset); + + uint32_t sigIndex; + uint32_t arity; + if (!iter_.readCallIndirect(&sigIndex, &arity)) + return false; + + Nothing callee_; + + const SigWithId& sig = mg_.sigs[sigIndex]; + + if (deadCode_) { + return skipCall(sig.args()) && iter_.readCallIndirectCallee(&callee_) && + iter_.readCallReturn(sig.ret()); + } sync(); + // Stack: ... index arg1 .. argn + uint32_t numArgs = sig.args().length(); - size_t stackSpace = stackConsumed(numArgs); + size_t stackSpace = stackConsumed(numArgs+1); FunctionCall baselineCall(lineOrBytecode); - beginCall(baselineCall, EscapesSandbox(true), IsBuiltinCall(false)); + beginCall(baselineCall, EscapesSandbox(false), IsBuiltinCall(false)); if (!emitCallArgs(sig.args(), baselineCall)) return false; + if (!iter_.readCallIndirectCallee(&callee_)) + return false; + if (!iter_.readCallReturn(sig.ret())) return false; - callImport(funcImport.globalDataOffset, baselineCall); + Stk& callee = peek(numArgs); + + callIndirect(sigIndex, callee, baselineCall); endCall(baselineCall); // TODO / OPTIMIZE: It would be better to merge this freeStack() // into the one in endCall, if we can. - popValueStackBy(numArgs); + popValueStackBy(numArgs+1); masm.freeStack(stackSpace); pushReturned(baselineCall, sig.ret()); diff --git a/js/src/asmjs/WasmBinaryToAST.cpp b/js/src/asmjs/WasmBinaryToAST.cpp index 01d1c380b8ce9..be750d0fe9b94 100644 --- a/js/src/asmjs/WasmBinaryToAST.cpp +++ b/js/src/asmjs/WasmBinaryToAST.cpp @@ -1655,16 +1655,12 @@ AstDecodeDataSection(AstDecodeContext &c) return AstDecodeFail(c, "failed to read number of data segments"); const uint32_t heapLength = c.module().hasMemory() ? c.module().memory().initial() : 0; - uint32_t prevEnd = 0; for (uint32_t i = 0; i < numSegments; i++) { uint32_t dstOffset; if (!c.d.readVarU32(&dstOffset)) return AstDecodeFail(c, "expected segment destination offset"); - if (dstOffset < prevEnd) - return AstDecodeFail(c, "data segments must be disjoint and ordered"); - uint32_t numBytes; if (!c.d.readVarU32(&numBytes)) return AstDecodeFail(c, "expected segment size"); @@ -1680,12 +1676,14 @@ AstDecodeDataSection(AstDecodeContext &c) for (size_t i = 0; i < numBytes; i++) buffer[i] = src[i]; + AstExpr* offset = new(c.lifo) AstConst(Val(dstOffset)); + if (!offset) + return false; + AstName name(buffer, numBytes); - AstDataSegment* segment = new(c.lifo) AstDataSegment(dstOffset, name); + AstDataSegment* segment = new(c.lifo) AstDataSegment(offset, name); if (!segment || !c.module().append(segment)) return false; - - prevEnd = dstOffset + numBytes; } if (!c.d.finishSection(sectionStart, sectionSize)) diff --git a/js/src/asmjs/WasmBinaryToExperimentalText.cpp b/js/src/asmjs/WasmBinaryToExperimentalText.cpp index 391fec4d692f5..7a4ed9f98fda4 100644 --- a/js/src/asmjs/WasmBinaryToExperimentalText.cpp +++ b/js/src/asmjs/WasmBinaryToExperimentalText.cpp @@ -1739,7 +1739,7 @@ PrintDataSection(WasmPrintContext& c, const AstModule& module) return false; if (!c.buffer.append("segment ")) return false; - if (!PrintInt32(c, segment->offset())) + if (!PrintInt32(c, segment->offset()->as().val().i32())) return false; if (!c.buffer.append(" \"")) return false; diff --git a/js/src/asmjs/WasmBinaryToText.cpp b/js/src/asmjs/WasmBinaryToText.cpp index 30414ac3f989d..164c982c65b1e 100644 --- a/js/src/asmjs/WasmBinaryToText.cpp +++ b/js/src/asmjs/WasmBinaryToText.cpp @@ -1334,7 +1334,7 @@ RenderDataSection(WasmRenderContext& c, const AstModule& module) return false; if (!c.buffer.append("(segment ")) return false; - if (!RenderInt32(c, segment->offset())) + if (!RenderInt32(c, segment->offset()->as().val().i32())) return false; if (!c.buffer.append(" \"")) return false; diff --git a/js/src/asmjs/WasmCode.cpp b/js/src/asmjs/WasmCode.cpp index 1a351ff28fb6d..e54bb3b6f9f4a 100644 --- a/js/src/asmjs/WasmCode.cpp +++ b/js/src/asmjs/WasmCode.cpp @@ -152,7 +152,7 @@ SendCodeRangesToProfiler(JSContext* cx, CodeSegment& cs, const Bytes& bytecode, uintptr_t size = end - start; TwoByteName name(cx); - if (!metadata.getFuncName(cx, &bytecode, codeRange.funcIndex(), &name)) + if (!metadata.getFuncDefName(cx, &bytecode, codeRange.funcDefIndex(), &name)) return false; UniqueChars chars( @@ -259,14 +259,14 @@ CodeSegment::~CodeSegment() } size_t -FuncExport::serializedSize() const +FuncDefExport::serializedSize() const { return sig_.serializedSize() + sizeof(pod); } uint8_t* -FuncExport::serialize(uint8_t* cursor) const +FuncDefExport::serialize(uint8_t* cursor) const { cursor = sig_.serialize(cursor); cursor = WriteBytes(cursor, &pod, sizeof(pod)); @@ -274,7 +274,7 @@ FuncExport::serialize(uint8_t* cursor) const } const uint8_t* -FuncExport::deserialize(const uint8_t* cursor) +FuncDefExport::deserialize(const uint8_t* cursor) { (cursor = sig_.deserialize(cursor)) && (cursor = ReadBytes(cursor, &pod, sizeof(pod))); @@ -282,7 +282,7 @@ FuncExport::deserialize(const uint8_t* cursor) } size_t -FuncExport::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const +FuncDefExport::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const { return sig_.sizeOfExcludingThis(mallocSizeOf); } @@ -320,7 +320,7 @@ CodeRange::CodeRange(Kind kind, Offsets offsets) : begin_(offsets.begin), profilingReturn_(0), end_(offsets.end), - funcIndex_(0), + funcDefIndex_(0), funcLineOrBytecode_(0), funcBeginToTableEntry_(0), funcBeginToTableProfilingJump_(0), @@ -337,7 +337,7 @@ CodeRange::CodeRange(Kind kind, ProfilingOffsets offsets) : begin_(offsets.begin), profilingReturn_(offsets.profilingReturn), end_(offsets.end), - funcIndex_(0), + funcDefIndex_(0), funcLineOrBytecode_(0), funcBeginToTableEntry_(0), funcBeginToTableProfilingJump_(0), @@ -351,11 +351,11 @@ CodeRange::CodeRange(Kind kind, ProfilingOffsets offsets) MOZ_ASSERT(kind_ == ImportJitExit || kind_ == ImportInterpExit); } -CodeRange::CodeRange(uint32_t funcIndex, uint32_t funcLineOrBytecode, FuncOffsets offsets) +CodeRange::CodeRange(uint32_t funcDefIndex, uint32_t funcLineOrBytecode, FuncOffsets offsets) : begin_(offsets.begin), profilingReturn_(offsets.profilingReturn), end_(offsets.end), - funcIndex_(funcIndex), + funcDefIndex_(funcDefIndex), funcLineOrBytecode_(funcLineOrBytecode), funcBeginToTableEntry_(offsets.tableEntry - begin_), funcBeginToTableProfilingJump_(offsets.tableProfilingJump - begin_), @@ -424,7 +424,7 @@ Metadata::serializedSize() const { return sizeof(pod()) + SerializedVectorSize(funcImports) + - SerializedVectorSize(funcExports) + + SerializedVectorSize(funcDefExports) + SerializedVectorSize(sigIds) + SerializedPodVectorSize(globals) + SerializedPodVectorSize(tables) + @@ -443,7 +443,7 @@ Metadata::serialize(uint8_t* cursor) const { cursor = WriteBytes(cursor, &pod(), sizeof(pod())); cursor = SerializeVector(cursor, funcImports); - cursor = SerializeVector(cursor, funcExports); + cursor = SerializeVector(cursor, funcDefExports); cursor = SerializeVector(cursor, sigIds); cursor = SerializePodVector(cursor, globals); cursor = SerializePodVector(cursor, tables); @@ -463,7 +463,7 @@ Metadata::deserialize(const uint8_t* cursor) { (cursor = ReadBytes(cursor, &pod(), sizeof(pod()))) && (cursor = DeserializeVector(cursor, &funcImports)) && - (cursor = DeserializeVector(cursor, &funcExports)) && + (cursor = DeserializeVector(cursor, &funcDefExports)) && (cursor = DeserializeVector(cursor, &sigIds)) && (cursor = DeserializePodVector(cursor, &globals)) && (cursor = DeserializePodVector(cursor, &tables)) && @@ -482,7 +482,7 @@ size_t Metadata::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const { return SizeOfVectorExcludingThis(funcImports, mallocSizeOf) + - SizeOfVectorExcludingThis(funcExports, mallocSizeOf) + + SizeOfVectorExcludingThis(funcDefExports, mallocSizeOf) + SizeOfVectorExcludingThis(sigIds, mallocSizeOf) + globals.sizeOfExcludingThis(mallocSizeOf) + tables.sizeOfExcludingThis(mallocSizeOf) + @@ -496,33 +496,36 @@ Metadata::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const assumptions.sizeOfExcludingThis(mallocSizeOf); } -struct ProjectFuncIndex +struct ProjectIndex { - const FuncExportVector& funcExports; - explicit ProjectFuncIndex(const FuncExportVector& funcExports) : funcExports(funcExports) {} + const FuncDefExportVector& funcDefExports; + + explicit ProjectIndex(const FuncDefExportVector& funcDefExports) + : funcDefExports(funcDefExports) + {} uint32_t operator[](size_t index) const { - return funcExports[index].funcIndex(); + return funcDefExports[index].funcDefIndex(); } }; -const FuncExport& -Metadata::lookupFuncExport(uint32_t funcIndex) const +const FuncDefExport& +Metadata::lookupFuncDefExport(uint32_t funcDefIndex) const { size_t match; - if (!BinarySearch(ProjectFuncIndex(funcExports), 0, funcExports.length(), funcIndex, &match)) + if (!BinarySearch(ProjectIndex(funcDefExports), 0, funcDefExports.length(), funcDefIndex, &match)) MOZ_CRASH("missing function export"); - return funcExports[match]; + return funcDefExports[match]; } bool -Metadata::getFuncName(JSContext* cx, const Bytes* maybeBytecode, uint32_t funcIndex, - TwoByteName* name) const +Metadata::getFuncDefName(JSContext* cx, const Bytes* maybeBytecode, uint32_t funcDefIndex, + TwoByteName* name) const { - if (funcIndex < funcNames.length()) { + if (funcDefIndex < funcNames.length()) { MOZ_ASSERT(maybeBytecode, "NameInBytecode requires preserved bytecode"); - const NameInBytecode& n = funcNames[funcIndex]; + const NameInBytecode& n = funcNames[funcDefIndex]; MOZ_ASSERT(n.offset + n.length < maybeBytecode->length()); if (n.length == 0) @@ -548,7 +551,7 @@ Metadata::getFuncName(JSContext* cx, const Bytes* maybeBytecode, uint32_t funcIn // For names that are out of range or invalid, synthesize a name. - UniqueChars chars(JS_smprintf("wasm-function[%u]", funcIndex)); + UniqueChars chars(JS_smprintf("wasm-function[%u]", funcDefIndex)); if (!chars) { ReportOutOfMemory(cx); return false; @@ -635,17 +638,17 @@ Code::lookupMemoryAccess(void* pc) const #endif bool -Code::getFuncName(JSContext* cx, uint32_t funcIndex, TwoByteName* name) const +Code::getFuncDefName(JSContext* cx, uint32_t funcDefIndex, TwoByteName* name) const { const Bytes* maybeBytecode = maybeBytecode_ ? &maybeBytecode_.get()->bytes : nullptr; - return metadata_->getFuncName(cx, maybeBytecode, funcIndex, name); + return metadata_->getFuncDefName(cx, maybeBytecode, funcDefIndex, name); } JSAtom* -Code::getFuncAtom(JSContext* cx, uint32_t funcIndex) const +Code::getFuncDefAtom(JSContext* cx, uint32_t funcDefIndex) const { TwoByteName name(cx); - if (!getFuncName(cx, funcIndex, &name)) + if (!getFuncDefName(cx, funcDefIndex, &name)) return nullptr; return AtomizeChars(cx, name.begin(), name.length()); @@ -767,7 +770,7 @@ Code::ensureProfilingState(JSContext* cx, bool newProfilingEnabled) continue; TwoByteName name(cx); - if (!getFuncName(cx, codeRange.funcIndex(), &name)) + if (!getFuncDefName(cx, codeRange.funcDefIndex(), &name)) return false; if (!name.append('\0')) return false; @@ -781,11 +784,11 @@ Code::ensureProfilingState(JSContext* cx, bool newProfilingEnabled) return false; } - if (codeRange.funcIndex() >= funcLabels_.length()) { - if (!funcLabels_.resize(codeRange.funcIndex() + 1)) + if (codeRange.funcDefIndex() >= funcLabels_.length()) { + if (!funcLabels_.resize(codeRange.funcDefIndex() + 1)) return false; } - funcLabels_[codeRange.funcIndex()] = Move(label); + funcLabels_[codeRange.funcDefIndex()] = Move(label); } } else { funcLabels_.clear(); diff --git a/js/src/asmjs/WasmCode.h b/js/src/asmjs/WasmCode.h index 22071afd14561..bf7df52bc6b9a 100644 --- a/js/src/asmjs/WasmCode.h +++ b/js/src/asmjs/WasmCode.h @@ -112,35 +112,37 @@ struct ShareableBytes : ShareableBase size_t sizeOfExcludingThis(MallocSizeOf m) const { return bytes.sizeOfExcludingThis(m); } const uint8_t* begin() const { return bytes.begin(); } const uint8_t* end() const { return bytes.end(); } + size_t length() const { return bytes.length(); } bool append(const uint8_t *p, uint32_t ct) { return bytes.append(p, ct); } }; typedef RefPtr MutableBytes; typedef RefPtr SharedBytes; -// A FuncExport represents a single function inside a wasm Module that has been -// exported one or more times. A FuncExport represents an internal entry point -// that can be called via function-index by Instance::callExport(). To allow -// O(log(n)) lookup of a FuncExport by function-index, the FuncExportVector -// is stored sorted by function index. +// A FuncDefExport represents a single function definition inside a wasm Module +// that has been exported one or more times. A FuncDefExport represents an +// internal entry point that can be called via function definition index by +// Instance::callExport(). To allow O(log(n)) lookup of a FuncDefExport by +// function definition index, the FuncDefExportVector is stored sorted by +// function definition index. -class FuncExport +class FuncDefExport { Sig sig_; MOZ_INIT_OUTSIDE_CTOR struct CacheablePod { - uint32_t funcIndex_; + uint32_t funcDefIndex_; uint32_t codeRangeIndex_; uint32_t entryOffset_; } pod; public: - FuncExport() = default; - explicit FuncExport(Sig&& sig, - uint32_t funcIndex, - uint32_t codeRangeIndex) + FuncDefExport() = default; + explicit FuncDefExport(Sig&& sig, + uint32_t funcDefIndex, + uint32_t codeRangeIndex) : sig_(Move(sig)) { - pod.funcIndex_ = funcIndex; + pod.funcDefIndex_ = funcDefIndex; pod.codeRangeIndex_ = codeRangeIndex; pod.entryOffset_ = UINT32_MAX; } @@ -152,8 +154,8 @@ class FuncExport const Sig& sig() const { return sig_; } - uint32_t funcIndex() const { - return pod.funcIndex_; + uint32_t funcDefIndex() const { + return pod.funcDefIndex_; } uint32_t codeRangeIndex() const { return pod.codeRangeIndex_; @@ -163,10 +165,10 @@ class FuncExport return pod.entryOffset_; } - WASM_DECLARE_SERIALIZABLE(FuncExport) + WASM_DECLARE_SERIALIZABLE(FuncDefExport) }; -typedef Vector FuncExportVector; +typedef Vector FuncDefExportVector; // An FuncImport contains the runtime metadata needed to implement a call to an // imported function. Each function import has two call stubs: an optimized path @@ -237,7 +239,7 @@ class CodeRange uint32_t begin_; uint32_t profilingReturn_; uint32_t end_; - uint32_t funcIndex_; + uint32_t funcDefIndex_; uint32_t funcLineOrBytecode_; uint8_t funcBeginToTableEntry_; uint8_t funcBeginToTableProfilingJump_; @@ -250,7 +252,7 @@ class CodeRange CodeRange() = default; CodeRange(Kind kind, Offsets offsets); CodeRange(Kind kind, ProfilingOffsets offsets); - CodeRange(uint32_t funcIndex, uint32_t lineOrBytecode, FuncOffsets offsets); + CodeRange(uint32_t funcDefIndex, uint32_t lineOrBytecode, FuncOffsets offsets); // All CodeRanges have a begin and end. @@ -312,9 +314,9 @@ class CodeRange MOZ_ASSERT(isFunction()); return profilingReturn_ - funcProfilingEpilogueToProfilingReturn_; } - uint32_t funcIndex() const { + uint32_t funcDefIndex() const { MOZ_ASSERT(isFunction()); - return funcIndex_; + return funcDefIndex_; } uint32_t funcLineOrBytecode() const { MOZ_ASSERT(isFunction()); @@ -346,11 +348,11 @@ struct CallThunk { uint32_t offset; union { - uint32_t funcIndex; + uint32_t funcDefIndex; uint32_t codeRangeIndex; } u; - CallThunk(uint32_t offset, uint32_t funcIndex) : offset(offset) { u.funcIndex = funcIndex; } + CallThunk(uint32_t offset, uint32_t funcDefIndex) : offset(offset) { u.funcDefIndex = funcDefIndex; } CallThunk() = default; }; @@ -448,7 +450,7 @@ struct Metadata : ShareableBase, MetadataCacheablePod const MetadataCacheablePod& pod() const { return *this; } FuncImportVector funcImports; - FuncExportVector funcExports; + FuncDefExportVector funcDefExports; SigWithIdVector sigIds; GlobalDescVector globals; TableDescVector tables; @@ -464,7 +466,7 @@ struct Metadata : ShareableBase, MetadataCacheablePod bool usesMemory() const { return UsesMemory(memoryUsage); } bool hasSharedMemory() const { return memoryUsage == MemoryUsage::Shared; } - const FuncExport& lookupFuncExport(uint32_t funcIndex) const; + const FuncDefExport& lookupFuncDefExport(uint32_t funcDefIndex) const; // AsmJSMetadata derives Metadata iff isAsmJS(). Mostly this distinction is // encapsulated within AsmJS.cpp, but the additional virtual functions allow @@ -487,8 +489,8 @@ struct Metadata : ShareableBase, MetadataCacheablePod virtual ScriptSource* maybeScriptSource() const { return nullptr; } - virtual bool getFuncName(JSContext* cx, const Bytes* maybeBytecode, uint32_t funcIndex, - TwoByteName* name) const; + virtual bool getFuncDefName(JSContext* cx, const Bytes* maybeBytecode, uint32_t funcDefIndex, + TwoByteName* name) const; WASM_DECLARE_SERIALIZABLE_VIRTUAL(Metadata); }; @@ -529,8 +531,8 @@ class Code // Return the name associated with a given function index, or generate one // if none was given by the module. - bool getFuncName(JSContext* cx, uint32_t funcIndex, TwoByteName* name) const; - JSAtom* getFuncAtom(JSContext* cx, uint32_t funcIndex) const; + bool getFuncDefName(JSContext* cx, uint32_t funcDefIndex, TwoByteName* name) const; + JSAtom* getFuncDefAtom(JSContext* cx, uint32_t funcDefIndex) const; // If the source bytecode was saved when this Code was constructed, this // method will render the binary as text. Otherwise, a diagnostic string @@ -547,7 +549,7 @@ class Code MOZ_MUST_USE bool ensureProfilingState(JSContext* cx, bool enabled); bool profilingEnabled() const { return profilingEnabled_; } - const char* profilingLabel(uint32_t funcIndex) const { return funcLabels_[funcIndex].get(); } + const char* profilingLabel(uint32_t funcDefIndex) const { return funcLabels_[funcDefIndex].get(); } // about:memory reporting: diff --git a/js/src/asmjs/WasmCompile.cpp b/js/src/asmjs/WasmCompile.cpp index a625c6fc7e8e5..6b1f0344f09fc 100644 --- a/js/src/asmjs/WasmCompile.cpp +++ b/js/src/asmjs/WasmCompile.cpp @@ -56,20 +56,28 @@ class FunctionDecoder const ModuleGenerator& mg_; const ValTypeVector& locals_; ValidatingExprIter iter_; + bool newFormat_; public: - FunctionDecoder(const ModuleGenerator& mg, const ValTypeVector& locals, Decoder& d) - : mg_(mg), locals_(locals), iter_(d) + FunctionDecoder(const ModuleGenerator& mg, const ValTypeVector& locals, Decoder& d, bool newFormat) + : mg_(mg), locals_(locals), iter_(d), newFormat_(newFormat) {} const ModuleGenerator& mg() const { return mg_; } ValidatingExprIter& iter() { return iter_; } const ValTypeVector& locals() const { return locals_; } + bool newFormat() const { return newFormat_; } bool checkHasMemory() { if (!mg().usesMemory()) return iter().fail("can't touch memory without memory"); return true; } + + bool checkIsOldFormat() { + if (newFormat_) + return iter().fail("opcode no longer in new format"); + return true; + } }; } // end anonymous namespace @@ -123,12 +131,21 @@ DecodeCall(FunctionDecoder& f) if (!f.iter().readCall(&calleeIndex, &arity)) return false; - if (calleeIndex >= f.mg().numFuncSigs()) - return f.iter().fail("callee index out of range"); + const Sig* sig; + if (f.newFormat()) { + if (calleeIndex >= f.mg().numFuncs()) + return f.iter().fail("callee index out of range"); - const Sig& sig = f.mg().funcSig(calleeIndex); - return DecodeCallArgs(f, arity, sig) && - DecodeCallReturn(f, sig); + sig = &f.mg().funcSig(calleeIndex); + } else { + if (calleeIndex >= f.mg().numFuncDefs()) + return f.iter().fail("callee index out of range"); + + sig = &f.mg().funcDefSig(calleeIndex); + } + + return DecodeCallArgs(f, arity, *sig) && + DecodeCallReturn(f, *sig); } static bool @@ -204,7 +221,8 @@ DecodeExpr(FunctionDecoder& f) case Expr::CallIndirect: return DecodeCallIndirect(f); case Expr::CallImport: - return DecodeCallImport(f); + return f.checkIsOldFormat() && + DecodeCallImport(f); case Expr::I32Const: return f.iter().readI32Const(nullptr); case Expr::I64Const: @@ -573,18 +591,18 @@ DecodeFunctionSection(Decoder& d, ModuleGeneratorData* init) if (sectionStart == Decoder::NotStarted) return true; - uint32_t numDecls; - if (!d.readVarU32(&numDecls)) - return Fail(d, "expected number of declarations"); + uint32_t numDefs; + if (!d.readVarU32(&numDefs)) + return Fail(d, "expected number of function definitions"); - if (numDecls > MaxFuncs) + if (numDefs > MaxFuncs) return Fail(d, "too many functions"); - if (!init->funcSigs.resize(numDecls)) + if (!init->funcDefSigs.resize(numDefs)) return false; - for (uint32_t i = 0; i < numDecls; i++) { - if (!DecodeSignatureIndex(d, *init, &init->funcSigs[i])) + for (uint32_t i = 0; i < numDefs; i++) { + if (!DecodeSignatureIndex(d, *init, &init->funcDefSigs[i])) return false; } @@ -876,14 +894,14 @@ DecodeTableSection(Decoder& d, bool newFormat, ModuleGeneratorData* init, Uint32 return false; for (uint32_t i = 0; i < table.initial; i++) { - uint32_t funcIndex; - if (!d.readVarU32(&funcIndex)) + uint32_t funcDefIndex; + if (!d.readVarU32(&funcDefIndex)) return Fail(d, "expected table element"); - if (funcIndex >= init->funcSigs.length()) + if (funcDefIndex >= init->funcDefSigs.length()) return Fail(d, "table element out of range"); - (*oldElems)[i] = funcIndex; + (*oldElems)[i] = init->funcImports.length() + funcDefIndex; } MOZ_ASSERT(init->tables.empty()); @@ -1078,18 +1096,18 @@ static bool DecodeExport(Decoder& d, bool newFormat, ModuleGenerator& mg, CStringSet* dupSet) { if (!newFormat) { - uint32_t funcIndex; - if (!d.readVarU32(&funcIndex)) + uint32_t funcDefIndex; + if (!d.readVarU32(&funcDefIndex)) return Fail(d, "expected export internal index"); - if (funcIndex >= mg.numFuncSigs()) + if (funcDefIndex >= mg.numFuncDefs()) return Fail(d, "exported function index out of bounds"); UniqueChars fieldName = DecodeExportName(d, dupSet); if (!fieldName) return false; - return mg.addFuncExport(Move(fieldName), funcIndex); + return mg.addFuncDefExport(Move(fieldName), mg.numFuncImports() + funcDefIndex); } UniqueChars fieldName = DecodeExportName(d, dupSet); @@ -1106,10 +1124,10 @@ DecodeExport(Decoder& d, bool newFormat, ModuleGenerator& mg, CStringSet* dupSet if (!d.readVarU32(&funcIndex)) return Fail(d, "expected export internal index"); - if (funcIndex >= mg.numFuncSigs()) + if (funcIndex >= mg.numFuncs()) return Fail(d, "exported function index out of bounds"); - return mg.addFuncExport(Move(fieldName), funcIndex); + return mg.addFuncDefExport(Move(fieldName), funcIndex); } case DefinitionKind::Table: { uint32_t tableIndex; @@ -1190,7 +1208,7 @@ DecodeExportSection(Decoder& d, bool newFormat, bool memoryExported, ModuleGener } static bool -DecodeFunctionBody(Decoder& d, ModuleGenerator& mg, uint32_t funcIndex) +DecodeFunctionBody(Decoder& d, bool newFormat, ModuleGenerator& mg, uint32_t funcDefIndex) { uint32_t bodySize; if (!d.readVarU32(&bodySize)) @@ -1207,7 +1225,7 @@ DecodeFunctionBody(Decoder& d, ModuleGenerator& mg, uint32_t funcIndex) return false; ValTypeVector locals; - const Sig& sig = mg.funcSig(funcIndex); + const Sig& sig = mg.funcDefSig(funcDefIndex); if (!locals.appendAll(sig.args())) return false; @@ -1219,7 +1237,7 @@ DecodeFunctionBody(Decoder& d, ModuleGenerator& mg, uint32_t funcIndex) return false; } - FunctionDecoder f(mg, locals, d); + FunctionDecoder f(mg, locals, d, newFormat); if (!f.iter().readFunctionStart()) return false; @@ -1240,7 +1258,7 @@ DecodeFunctionBody(Decoder& d, ModuleGenerator& mg, uint32_t funcIndex) memcpy(fg.bytes().begin(), bodyBegin, bodySize); - return mg.finishFuncDef(funcIndex, &fg); + return mg.finishFuncDef(funcDefIndex, &fg); } static bool @@ -1252,21 +1270,21 @@ DecodeStartSection(Decoder& d, ModuleGenerator& mg) if (sectionStart == Decoder::NotStarted) return true; - uint32_t startFuncIndex; - if (!d.readVarU32(&startFuncIndex)) + uint32_t funcIndex; + if (!d.readVarU32(&funcIndex)) return Fail(d, "failed to read start func index"); - if (startFuncIndex >= mg.numFuncSigs()) + if (funcIndex >= mg.numFuncs()) return Fail(d, "unknown start function"); - const Sig& sig = mg.funcSig(startFuncIndex); + const Sig& sig = mg.funcSig(funcIndex); if (sig.ret() != ExprType::Void) return Fail(d, "start function must not return anything"); if (sig.args().length()) return Fail(d, "start function must be nullary"); - if (!mg.setStartFunction(startFuncIndex)) + if (!mg.setStartFunction(funcIndex)) return false; if (!d.finishSection(sectionStart, sectionSize)) @@ -1276,7 +1294,7 @@ DecodeStartSection(Decoder& d, ModuleGenerator& mg) } static bool -DecodeCodeSection(Decoder& d, ModuleGenerator& mg) +DecodeCodeSection(Decoder& d, bool newFormat, ModuleGenerator& mg) { if (!mg.startFuncDefs()) return false; @@ -1286,21 +1304,21 @@ DecodeCodeSection(Decoder& d, ModuleGenerator& mg) return Fail(d, "failed to start section"); if (sectionStart == Decoder::NotStarted) { - if (mg.numFuncSigs() != 0) + if (mg.numFuncDefs() != 0) return Fail(d, "expected function bodies"); return mg.finishFuncDefs(); } - uint32_t numFuncBodies; - if (!d.readVarU32(&numFuncBodies)) + uint32_t numFuncDefs; + if (!d.readVarU32(&numFuncDefs)) return Fail(d, "expected function body count"); - if (numFuncBodies != mg.numFuncSigs()) + if (numFuncDefs != mg.numFuncDefs()) return Fail(d, "function body count does not match function signature count"); - for (uint32_t funcIndex = 0; funcIndex < numFuncBodies; funcIndex++) { - if (!DecodeFunctionBody(d, mg, funcIndex)) + for (uint32_t i = 0; i < numFuncDefs; i++) { + if (!DecodeFunctionBody(d, newFormat, mg, i)) return false; } @@ -1335,7 +1353,7 @@ DecodeElemSection(Decoder& d, bool newFormat, Uint32Vector&& oldElems, ModuleGen if (numSegments > MaxElemSegments) return Fail(d, "too many elem segments"); - for (uint32_t i = 0, prevEnd = 0; i < numSegments; i++) { + for (uint32_t i = 0; i < numSegments; i++) { uint32_t tableIndex; if (!d.readVarU32(&tableIndex)) return Fail(d, "expected table index"); @@ -1348,9 +1366,6 @@ DecodeElemSection(Decoder& d, bool newFormat, Uint32Vector&& oldElems, ModuleGen if (!DecodeInitializerExpression(d, mg.globals(), ValType::I32, &offset)) return false; - if (offset.isVal() && offset.val().i32() < prevEnd) - return Fail(d, "elem segments must be disjoint and ordered"); - uint32_t numElems; if (!d.readVarU32(&numElems)) return Fail(d, "expected segment size"); @@ -1369,13 +1384,10 @@ DecodeElemSection(Decoder& d, bool newFormat, Uint32Vector&& oldElems, ModuleGen for (uint32_t i = 0; i < numElems; i++) { if (!d.readVarU32(&elemFuncIndices[i])) return Fail(d, "failed to read element function index"); - if (elemFuncIndices[i] >= mg.numFuncSigs()) + if (elemFuncIndices[i] >= mg.numFuncs()) return Fail(d, "table element out of range"); } - if (offset.isVal()) - prevEnd = offset.val().i32() + elemFuncIndices.length(); - if (!mg.addElemSegment(offset, Move(elemFuncIndices))) return false; } @@ -1406,7 +1418,8 @@ DecodeDataSection(Decoder& d, bool newFormat, ModuleGenerator& mg) return Fail(d, "too many data segments"); uint32_t max = mg.minMemoryLength(); - for (uint32_t i = 0, prevEnd = 0; i < numSegments; i++) { + for (uint32_t i = 0; i < numSegments; i++) { + DataSegment seg; if (newFormat) { uint32_t linearMemoryIndex; if (!d.readVarU32(&linearMemoryIndex)) @@ -1415,26 +1428,24 @@ DecodeDataSection(Decoder& d, bool newFormat, ModuleGenerator& mg) if (linearMemoryIndex != 0) return Fail(d, "linear memory index must currently be 0"); - Expr expr; - if (!d.readExpr(&expr)) - return Fail(d, "failed to read initializer expression"); + if (!DecodeInitializerExpression(d, mg.globals(), ValType::I32, &seg.offset)) + return false; + } else { + uint32_t offset; + if (!d.readVarU32(&offset)) + return Fail(d, "expected segment destination offset"); - if (expr != Expr::I32Const) - return Fail(d, "expected i32.const initializer expression"); + seg.offset = InitExpr(Val(offset)); } - DataSegment seg; - if (!d.readVarU32(&seg.memoryOffset)) - return Fail(d, "expected segment destination offset"); - - if (seg.memoryOffset < prevEnd) - return Fail(d, "data segments must be disjoint and ordered"); - if (!d.readVarU32(&seg.length)) return Fail(d, "expected segment size"); - if (seg.memoryOffset > max || max - seg.memoryOffset < seg.length) - return Fail(d, "data segment data segment does not fit"); + if (seg.offset.isVal()) { + uint32_t off = seg.offset.val().i32(); + if (off > max || max - off < seg.length) + return Fail(d, "data segment does not fit"); + } seg.bytecodeOffset = d.currentOffset(); @@ -1443,8 +1454,6 @@ DecodeDataSection(Decoder& d, bool newFormat, ModuleGenerator& mg) if (!mg.addDataSegment(seg)) return false; - - prevEnd = seg.memoryOffset + seg.length; } if (!d.finishSection(sectionStart, sectionSize)) @@ -1586,10 +1595,10 @@ wasm::Compile(const ShareableBytes& bytecode, const CompileArgs& args, UniqueCha if (!DecodeStartSection(d, mg)) return nullptr; - if (!DecodeCodeSection(d, mg)) + if (!DecodeElemSection(d, newFormat, Move(oldElems), mg)) return nullptr; - if (!DecodeElemSection(d, newFormat, Move(oldElems), mg)) + if (!DecodeCodeSection(d, newFormat, mg)) return nullptr; if (!DecodeDataSection(d, newFormat, mg)) diff --git a/js/src/asmjs/WasmFrameIterator.cpp b/js/src/asmjs/WasmFrameIterator.cpp index 745c1e729de25..43d8093ae45fc 100644 --- a/js/src/asmjs/WasmFrameIterator.cpp +++ b/js/src/asmjs/WasmFrameIterator.cpp @@ -190,7 +190,7 @@ FrameIterator::functionDisplayAtom() const MOZ_ASSERT(codeRange_); - JSAtom* atom = code_->getFuncAtom(cx, codeRange_->funcIndex()); + JSAtom* atom = code_->getFuncDefAtom(cx, codeRange_->funcDefIndex()); if (!atom) { cx->clearPendingException(); return cx->names().empty; @@ -779,7 +779,7 @@ ProfilingFrameIterator::label() const } switch (codeRange_->kind()) { - case CodeRange::Function: return code_->profilingLabel(codeRange_->funcIndex()); + case CodeRange::Function: return code_->profilingLabel(codeRange_->funcDefIndex()); case CodeRange::Entry: return "entry trampoline (in asm.js)"; case CodeRange::ImportJitExit: return importJitDescription; case CodeRange::ImportInterpExit: return importInterpDescription; diff --git a/js/src/asmjs/WasmGenerator.cpp b/js/src/asmjs/WasmGenerator.cpp index 3e589b1cab031..ab740f1573308 100644 --- a/js/src/asmjs/WasmGenerator.cpp +++ b/js/src/asmjs/WasmGenerator.cpp @@ -54,7 +54,7 @@ ModuleGenerator::ModuleGenerator(ImportVector&& imports) startOfUnpatchedBranches_(0), parallel_(false), outstanding_(0), - activeFunc_(nullptr), + activeFuncDef_(nullptr), startedFuncDefs_(false), finishedFuncDefs_(false) { @@ -103,7 +103,7 @@ ModuleGenerator::init(UniqueModuleGeneratorData shared, const CompileArgs& args, shared_ = Move(shared); alwaysBaseline_ = args.alwaysBaseline; - if (!exportedFuncs_.init()) + if (!exportedFuncDefs_.init()) return false; linkData_.globalDataLength = AlignBytes(InitialGlobalDataBytes, sizeof(void*));; @@ -137,6 +137,9 @@ ModuleGenerator::init(UniqueModuleGeneratorData shared, const CompileArgs& args, numSigs_ = shared_->sigs.length(); numTables_ = shared_->tables.length(); + if (args.assumptions.newFormat) + shared_->firstFuncDefIndex = shared_->funcImports.length(); + for (FuncImportGenDesc& funcImport : shared_->funcImports) { MOZ_ASSERT(!funcImport.globalDataOffset); funcImport.globalDataOffset = linkData_.globalDataLength; @@ -223,17 +226,31 @@ ModuleGenerator::finishOutstandingTask() static const uint32_t BadCodeRange = UINT32_MAX; bool -ModuleGenerator::funcIsDefined(uint32_t funcIndex) const +ModuleGenerator::funcIndexIsDef(uint32_t funcIndex) const +{ + MOZ_ASSERT(funcIndex < numFuncImports() + numFuncDefs()); + return funcIndex >= numFuncImports(); +} + +uint32_t +ModuleGenerator::funcIndexToDef(uint32_t funcIndex) const +{ + MOZ_ASSERT(funcIndexIsDef(funcIndex)); + return funcIndex - numFuncImports(); +} + +bool +ModuleGenerator::funcIsDefined(uint32_t funcDefIndex) const { - return funcIndex < funcIndexToCodeRange_.length() && - funcIndexToCodeRange_[funcIndex] != BadCodeRange; + return funcDefIndex < funcDefIndexToCodeRange_.length() && + funcDefIndexToCodeRange_[funcDefIndex] != BadCodeRange; } const CodeRange& -ModuleGenerator::funcCodeRange(uint32_t funcIndex) const +ModuleGenerator::funcDefCodeRange(uint32_t funcDefIndex) const { - MOZ_ASSERT(funcIsDefined(funcIndex)); - const CodeRange& cr = metadata_->codeRanges[funcIndexToCodeRange_[funcIndex]]; + MOZ_ASSERT(funcIsDefined(funcDefIndex)); + const CodeRange& cr = metadata_->codeRanges[funcDefIndexToCodeRange_[funcDefIndex]]; MOZ_ASSERT(cr.isFunction()); return cr; } @@ -260,14 +277,14 @@ ModuleGenerator::convertOutOfRangeBranchesToThunks() for (; lastPatchedCallsite_ < masm_.callSites().length(); lastPatchedCallsite_++) { const CallSiteAndTarget& cs = masm_.callSites()[lastPatchedCallsite_]; - if (!cs.isInternal()) + if (!cs.isDefinition()) continue; uint32_t callerOffset = cs.returnAddressOffset(); MOZ_RELEASE_ASSERT(callerOffset < INT32_MAX); - if (funcIsDefined(cs.targetIndex())) { - uint32_t calleeOffset = funcCodeRange(cs.targetIndex()).funcNonProfilingEntry(); + if (funcIsDefined(cs.funcDefIndex())) { + uint32_t calleeOffset = funcDefCodeRange(cs.funcDefIndex()).funcNonProfilingEntry(); MOZ_RELEASE_ASSERT(calleeOffset < INT32_MAX); if (uint32_t(abs(int32_t(calleeOffset) - int32_t(callerOffset))) < JumpRange()) { @@ -276,7 +293,7 @@ ModuleGenerator::convertOutOfRangeBranchesToThunks() } } - OffsetMap::AddPtr p = alreadyThunked.lookupForAdd(cs.targetIndex()); + OffsetMap::AddPtr p = alreadyThunked.lookupForAdd(cs.funcDefIndex()); if (!p) { Offsets offsets; offsets.begin = masm_.currentOffset(); @@ -287,9 +304,9 @@ ModuleGenerator::convertOutOfRangeBranchesToThunks() if (!metadata_->codeRanges.emplaceBack(CodeRange::CallThunk, offsets)) return false; - if (!metadata_->callThunks.emplaceBack(thunkOffset, cs.targetIndex())) + if (!metadata_->callThunks.emplaceBack(thunkOffset, cs.funcDefIndex())) return false; - if (!alreadyThunked.add(p, cs.targetIndex(), offsets.begin)) + if (!alreadyThunked.add(p, cs.funcDefIndex(), offsets.begin)) return false; } @@ -351,17 +368,17 @@ ModuleGenerator::finishTask(IonCompileTask* task) // Add the CodeRange for this function. uint32_t funcCodeRangeIndex = metadata_->codeRanges.length(); - if (!metadata_->codeRanges.emplaceBack(func.index(), func.lineOrBytecode(), results.offsets())) + if (!metadata_->codeRanges.emplaceBack(func.defIndex(), func.lineOrBytecode(), results.offsets())) return false; // Maintain a mapping from function index to CodeRange index. - if (func.index() >= funcIndexToCodeRange_.length()) { - uint32_t n = func.index() - funcIndexToCodeRange_.length() + 1; - if (!funcIndexToCodeRange_.appendN(BadCodeRange, n)) + if (func.defIndex() >= funcDefIndexToCodeRange_.length()) { + uint32_t n = func.defIndex() - funcDefIndexToCodeRange_.length() + 1; + if (!funcDefIndexToCodeRange_.appendN(BadCodeRange, n)) return false; } - MOZ_ASSERT(!funcIsDefined(func.index())); - funcIndexToCodeRange_[func.index()] = funcCodeRangeIndex; + MOZ_ASSERT(!funcIsDefined(func.defIndex())); + funcDefIndexToCodeRange_[func.defIndex()] = funcCodeRangeIndex; // Merge the compiled results into the whole-module masm. mozilla::DebugOnly sizeBefore = masm_.size(); @@ -374,33 +391,33 @@ ModuleGenerator::finishTask(IonCompileTask* task) } bool -ModuleGenerator::finishFuncExports() +ModuleGenerator::finishFuncDefExports() { - // ModuleGenerator::exportedFuncs_ is an unordered HashSet. The - // FuncExportVector stored in Metadata needs to be stored sorted by + // ModuleGenerator::exportedFuncDefs_ is an unordered HashSet. The + // FuncDefExportVector stored in Metadata needs to be stored sorted by // function index to allow O(log(n)) lookup at runtime. - Uint32Vector funcIndices; - if (!funcIndices.reserve(exportedFuncs_.count())) + Uint32Vector funcDefIndices; + if (!funcDefIndices.reserve(exportedFuncDefs_.count())) return false; - for (Uint32Set::Range r = exportedFuncs_.all(); !r.empty(); r.popFront()) - funcIndices.infallibleAppend(r.front()); + for (Uint32Set::Range r = exportedFuncDefs_.all(); !r.empty(); r.popFront()) + funcDefIndices.infallibleAppend(r.front()); - std::sort(funcIndices.begin(), funcIndices.end()); + std::sort(funcDefIndices.begin(), funcDefIndices.end()); - MOZ_ASSERT(metadata_->funcExports.empty()); - if (!metadata_->funcExports.reserve(exportedFuncs_.count())) + MOZ_ASSERT(metadata_->funcDefExports.empty()); + if (!metadata_->funcDefExports.reserve(exportedFuncDefs_.count())) return false; - for (uint32_t funcIndex : funcIndices) { + for (uint32_t funcDefIndex : funcDefIndices) { Sig sig; - if (!sig.clone(funcSig(funcIndex))) + if (!sig.clone(funcDefSig(funcDefIndex))) return false; - metadata_->funcExports.infallibleEmplaceBack(Move(sig), - funcIndex, - funcIndexToCodeRange_[funcIndex]); + metadata_->funcDefExports.infallibleEmplaceBack(Move(sig), + funcDefIndex, + funcDefIndexToCodeRange_[funcDefIndex]); } return true; @@ -414,8 +431,8 @@ ModuleGenerator::finishCodegen() { uint32_t offsetInWhole = masm_.size(); - uint32_t numFuncExports = metadata_->funcExports.length(); - MOZ_ASSERT(numFuncExports == exportedFuncs_.count()); + uint32_t numFuncDefExports = metadata_->funcDefExports.length(); + MOZ_ASSERT(numFuncDefExports == exportedFuncDefs_.count()); // Generate stubs in a separate MacroAssembler since, otherwise, for modules // larger than the JumpImmediateRange, even local uses of Label will fail @@ -431,10 +448,10 @@ ModuleGenerator::finishCodegen() TempAllocator alloc(&lifo_); MacroAssembler masm(MacroAssembler::AsmJSToken(), alloc); - if (!entries.resize(numFuncExports)) + if (!entries.resize(numFuncDefExports)) return false; - for (uint32_t i = 0; i < numFuncExports; i++) - entries[i] = GenerateEntry(masm, metadata_->funcExports[i]); + for (uint32_t i = 0; i < numFuncDefExports; i++) + entries[i] = GenerateEntry(masm, metadata_->funcDefExports[i]); if (!interpExits.resize(numFuncImports())) return false; @@ -457,9 +474,9 @@ ModuleGenerator::finishCodegen() // Adjust each of the resulting Offsets (to account for being merged into // masm_) and then create code ranges for all the stubs. - for (uint32_t i = 0; i < numFuncExports; i++) { + for (uint32_t i = 0; i < numFuncDefExports; i++) { entries[i].offsetBy(offsetInWhole); - metadata_->funcExports[i].initEntryOffset(entries[i].begin); + metadata_->funcDefExports[i].initEntryOffset(entries[i].begin); if (!metadata_->codeRanges.emplaceBack(CodeRange::Entry, entries[i])) return false; } @@ -502,9 +519,9 @@ ModuleGenerator::finishCodegen() // Now that all thunks have been generated, patch all the thunks. for (CallThunk& callThunk : metadata_->callThunks) { - uint32_t funcIndex = callThunk.u.funcIndex; - callThunk.u.codeRangeIndex = funcIndexToCodeRange_[funcIndex]; - masm_.patchThunk(callThunk.offset, funcCodeRange(funcIndex).funcNonProfilingEntry()); + uint32_t funcDefIndex = callThunk.u.funcDefIndex; + callThunk.u.codeRangeIndex = funcDefIndexToCodeRange_[funcDefIndex]; + masm_.patchThunk(callThunk.offset, funcDefCodeRange(funcDefIndex).funcNonProfilingEntry()); } for (JumpTarget target : MakeEnumeratedRange(JumpTarget::Limit)) { @@ -671,12 +688,12 @@ ModuleGenerator::sig(uint32_t index) const } void -ModuleGenerator::initFuncSig(uint32_t funcIndex, uint32_t sigIndex) +ModuleGenerator::initFuncDefSig(uint32_t funcDefIndex, uint32_t sigIndex) { MOZ_ASSERT(isAsmJS()); - MOZ_ASSERT(!shared_->funcSigs[funcIndex]); + MOZ_ASSERT(!shared_->funcDefSigs[funcDefIndex]); - shared_->funcSigs[funcIndex] = &shared_->sigs[sigIndex]; + shared_->funcDefSigs[funcDefIndex] = &shared_->sigs[sigIndex]; } void @@ -698,10 +715,10 @@ ModuleGenerator::bumpMinMemoryLength(uint32_t newMinMemoryLength) } const SigWithId& -ModuleGenerator::funcSig(uint32_t funcIndex) const +ModuleGenerator::funcDefSig(uint32_t funcDefIndex) const { - MOZ_ASSERT(shared_->funcSigs[funcIndex]); - return *shared_->funcSigs[funcIndex]; + MOZ_ASSERT(shared_->funcDefSigs[funcDefIndex]); + return *shared_->funcDefSigs[funcDefIndex]; } bool @@ -737,17 +754,38 @@ ModuleGenerator::funcImport(uint32_t funcImportIndex) const return shared_->funcImports[funcImportIndex]; } +uint32_t +ModuleGenerator::numFuncs() const +{ + return numFuncImports() + numFuncDefs(); +} + +const SigWithId& +ModuleGenerator::funcSig(uint32_t funcIndex) const +{ + MOZ_ASSERT(funcIndex < numFuncs()); + + if (funcIndex < numFuncImports()) + return *funcImport(funcIndex).sig; + + return funcDefSig(funcIndex - numFuncImports()); +} + bool -ModuleGenerator::addFuncExport(UniqueChars fieldName, uint32_t funcIndex) +ModuleGenerator::addFuncDefExport(UniqueChars fieldName, uint32_t funcIndex) { - return exports_.emplaceBack(Move(fieldName), funcIndex, DefinitionKind::Function) && - exportedFuncs_.put(funcIndex); + if (funcIndexIsDef(funcIndex)) { + if (!exportedFuncDefs_.put(funcIndexToDef(funcIndex))) + return false; + } + + return exports_.emplaceBack(Move(fieldName), funcIndex, DefinitionKind::Function); } bool ModuleGenerator::addTableExport(UniqueChars fieldName) { - MOZ_ASSERT(elemSegments_.empty()); + MOZ_ASSERT(!startedFuncDefs_); MOZ_ASSERT(shared_->tables.length() == 1); shared_->tables[0].external = true; return exports_.emplaceBack(Move(fieldName), DefinitionKind::Table); @@ -768,8 +806,30 @@ ModuleGenerator::addGlobalExport(UniqueChars fieldName, uint32_t globalIndex) bool ModuleGenerator::setStartFunction(uint32_t funcIndex) { + if (funcIndexIsDef(funcIndex)) { + if (!exportedFuncDefs_.put(funcIndexToDef(funcIndex))) + return false; + } + metadata_->initStartFuncIndex(funcIndex); - return exportedFuncs_.put(funcIndex); + return true; +} + +bool +ModuleGenerator::addElemSegment(InitExpr offset, Uint32Vector&& elemFuncIndices) +{ + MOZ_ASSERT(!isAsmJS()); + MOZ_ASSERT(!startedFuncDefs_); + MOZ_ASSERT(shared_->tables.length() == 1); + + for (uint32_t funcIndex : elemFuncIndices) { + if (!funcIndexIsDef(funcIndex)) { + shared_->tables[0].external = true; + break; + } + } + + return elemSegments_.emplaceBack(0, offset, Move(elemFuncIndices)); } bool @@ -778,6 +838,23 @@ ModuleGenerator::startFuncDefs() MOZ_ASSERT(!startedFuncDefs_); MOZ_ASSERT(!finishedFuncDefs_); + // Now that it is known whether tables are internal or external, mark the + // elements of any external table as exported since they may be called from + // outside the module. + + for (ElemSegment& elems : elemSegments_) { + if (!shared_->tables[elems.tableIndex].external) + continue; + + for (uint32_t funcIndex : elems.elemFuncIndices) { + if (!funcIndexIsDef(funcIndex)) + continue; + + if (!exportedFuncDefs_.put(funcIndexToDef(funcIndex))) + return false; + } + } + // The wasmCompilationInProgress atomic ensures that there is only one // parallel compilation in progress at a time. In the special case of // asm.js, where the ModuleGenerator itself can be on a helper thread, this @@ -827,7 +904,7 @@ bool ModuleGenerator::startFuncDef(uint32_t lineOrBytecode, FunctionGenerator* fg) { MOZ_ASSERT(startedFuncDefs_); - MOZ_ASSERT(!activeFunc_); + MOZ_ASSERT(!activeFuncDef_); MOZ_ASSERT(!finishedFuncDefs_); if (freeTasks_.empty() && !finishOutstandingTask()) @@ -840,18 +917,18 @@ ModuleGenerator::startFuncDef(uint32_t lineOrBytecode, FunctionGenerator* fg) fg->lineOrBytecode_ = lineOrBytecode; fg->m_ = this; fg->task_ = task; - activeFunc_ = fg; + activeFuncDef_ = fg; return true; } bool -ModuleGenerator::finishFuncDef(uint32_t funcIndex, FunctionGenerator* fg) +ModuleGenerator::finishFuncDef(uint32_t funcDefIndex, FunctionGenerator* fg) { - MOZ_ASSERT(activeFunc_ == fg); + MOZ_ASSERT(activeFuncDef_ == fg); auto func = js::MakeUnique(Move(fg->bytes_), - funcIndex, - funcSig(funcIndex), + funcDefIndex, + funcDefSig(funcDefIndex), fg->lineOrBytecode_, Move(fg->callSiteLineNums_)); if (!func) @@ -876,7 +953,7 @@ ModuleGenerator::finishFuncDef(uint32_t funcIndex, FunctionGenerator* fg) fg->m_ = nullptr; fg->task_ = nullptr; - activeFunc_ = nullptr; + activeFuncDef_ = nullptr; return true; } @@ -884,7 +961,7 @@ bool ModuleGenerator::finishFuncDefs() { MOZ_ASSERT(startedFuncDefs_); - MOZ_ASSERT(!activeFunc_); + MOZ_ASSERT(!activeFuncDef_); MOZ_ASSERT(!finishedFuncDefs_); while (outstanding_ > 0) { @@ -892,35 +969,34 @@ ModuleGenerator::finishFuncDefs() return false; } - for (uint32_t funcIndex = 0; funcIndex < funcIndexToCodeRange_.length(); funcIndex++) - MOZ_ASSERT(funcIsDefined(funcIndex)); +#ifdef DEBUG + for (uint32_t i = 0; i < funcDefIndexToCodeRange_.length(); i++) + MOZ_ASSERT(funcIsDefined(i)); +#endif - linkData_.functionCodeLength = masm_.size(); - finishedFuncDefs_ = true; - return true; -} + // Complete element segments with the code range index of every element, now + // that all functions have been compiled. -bool -ModuleGenerator::addElemSegment(InitExpr offset, Uint32Vector&& elemFuncIndices) -{ - MOZ_ASSERT(!isAsmJS()); - MOZ_ASSERT(finishedFuncDefs_); - MOZ_ASSERT(shared_->tables.length() == 1); + for (ElemSegment& elems : elemSegments_) { + Uint32Vector& codeRangeIndices = elems.elemCodeRangeIndices; - if (shared_->tables[0].external) { - for (uint32_t funcIndex : elemFuncIndices) { - if (!exportedFuncs_.put(funcIndex)) - return false; + MOZ_ASSERT(codeRangeIndices.empty()); + if (!codeRangeIndices.reserve(elems.elemFuncIndices.length())) + return false; + + for (uint32_t funcIndex : elems.elemFuncIndices) { + if (!funcIndexIsDef(funcIndex)) { + codeRangeIndices.infallibleAppend(UINT32_MAX); + continue; + } + + codeRangeIndices.infallibleAppend(funcDefIndexToCodeRange_[funcIndexToDef(funcIndex)]); } } - Uint32Vector codeRangeIndices; - if (!codeRangeIndices.resize(elemFuncIndices.length())) - return false; - for (size_t i = 0; i < elemFuncIndices.length(); i++) - codeRangeIndices[i] = funcIndexToCodeRange_[elemFuncIndices[i]]; - - return elemSegments_.emplaceBack(0, offset, Move(elemFuncIndices), Move(codeRangeIndices)); + linkData_.functionCodeLength = masm_.size(); + finishedFuncDefs_ = true; + return true; } void @@ -950,28 +1026,36 @@ ModuleGenerator::initSigTableLength(uint32_t sigIndex, uint32_t length) } bool -ModuleGenerator::initSigTableElems(uint32_t sigIndex, Uint32Vector&& elemFuncIndices) +ModuleGenerator::initSigTableElems(uint32_t sigIndex, Uint32Vector&& elemFuncDefIndices) { MOZ_ASSERT(isAsmJS()); MOZ_ASSERT(finishedFuncDefs_); uint32_t tableIndex = shared_->asmJSSigToTableIndex[sigIndex]; - MOZ_ASSERT(shared_->tables[tableIndex].initial == elemFuncIndices.length()); + MOZ_ASSERT(shared_->tables[tableIndex].initial == elemFuncDefIndices.length()); Uint32Vector codeRangeIndices; - if (!codeRangeIndices.resize(elemFuncIndices.length())) + if (!codeRangeIndices.resize(elemFuncDefIndices.length())) return false; - for (size_t i = 0; i < elemFuncIndices.length(); i++) - codeRangeIndices[i] = funcIndexToCodeRange_[elemFuncIndices[i]]; + for (size_t i = 0; i < elemFuncDefIndices.length(); i++) { + codeRangeIndices[i] = funcDefIndexToCodeRange_[elemFuncDefIndices[i]]; + elemFuncDefIndices[i] += numFuncImports(); + } + // By adding numFuncImports to each element, elemFuncDefIndices is now a + // Vector of func indices. InitExpr offset(Val(uint32_t(0))); - return elemSegments_.emplaceBack(tableIndex, offset, Move(elemFuncIndices), Move(codeRangeIndices)); + if (!elemSegments_.emplaceBack(tableIndex, offset, Move(elemFuncDefIndices))) + return false; + + elemSegments_.back().elemCodeRangeIndices = Move(codeRangeIndices); + return true; } SharedModule ModuleGenerator::finish(const ShareableBytes& bytecode) { - MOZ_ASSERT(!activeFunc_); + MOZ_ASSERT(!activeFuncDef_); MOZ_ASSERT(finishedFuncDefs_); // Now that all asm.js tables have been created and the compiler threads are @@ -979,7 +1063,7 @@ ModuleGenerator::finish(const ShareableBytes& bytecode) if (isAsmJS() && !shared_->tables.resize(numTables_)) return nullptr; - if (!finishFuncExports()) + if (!finishFuncDefExports()) return nullptr; if (!finishCodegen()) diff --git a/js/src/asmjs/WasmGenerator.h b/js/src/asmjs/WasmGenerator.h index 5c877a9191d78..aa3451f658359 100644 --- a/js/src/asmjs/WasmGenerator.h +++ b/js/src/asmjs/WasmGenerator.h @@ -53,9 +53,10 @@ struct ModuleGeneratorData MemoryUsage memoryUsage; mozilla::Atomic minMemoryLength; Maybe maxMemoryLength; + uint32_t firstFuncDefIndex; SigWithIdVector sigs; - SigWithIdPtrVector funcSigs; + SigWithIdPtrVector funcDefSigs; FuncImportGenDescVector funcImports; GlobalDescVector globals; TableDescVector tables; @@ -64,7 +65,8 @@ struct ModuleGeneratorData explicit ModuleGeneratorData(ModuleKind kind = ModuleKind::Wasm) : kind(kind), memoryUsage(MemoryUsage::None), - minMemoryLength(0) + minMemoryLength(0), + firstFuncDefIndex(0) {} bool isAsmJS() const { @@ -105,8 +107,8 @@ class MOZ_STACK_CLASS ModuleGenerator jit::JitContext jcx_; jit::TempAllocator masmAlloc_; jit::MacroAssembler masm_; - Uint32Vector funcIndexToCodeRange_; - Uint32Set exportedFuncs_; + Uint32Vector funcDefIndexToCodeRange_; + Uint32Set exportedFuncDefs_; uint32_t lastPatchedCallsite_; uint32_t startOfUnpatchedBranches_; JumpSiteArray jumpThunks_; @@ -118,16 +120,18 @@ class MOZ_STACK_CLASS ModuleGenerator IonCompileTaskPtrVector freeTasks_; // Assertions - DebugOnly activeFunc_; + DebugOnly activeFuncDef_; DebugOnly startedFuncDefs_; DebugOnly finishedFuncDefs_; MOZ_MUST_USE bool finishOutstandingTask(); - bool funcIsDefined(uint32_t funcIndex) const; - const CodeRange& funcCodeRange(uint32_t funcIndex) const; + bool funcIndexIsDef(uint32_t funcIndex) const; + uint32_t funcIndexToDef(uint32_t funcIndex) const; + bool funcIsDefined(uint32_t funcDefIndex) const; + const CodeRange& funcDefCodeRange(uint32_t funcDefIndex) const; MOZ_MUST_USE bool convertOutOfRangeBranchesToThunks(); MOZ_MUST_USE bool finishTask(IonCompileTask* task); - MOZ_MUST_USE bool finishFuncExports(); + MOZ_MUST_USE bool finishFuncDefExports(); MOZ_MUST_USE bool finishCodegen(); MOZ_MUST_USE bool finishLinkData(Bytes& code); MOZ_MUST_USE bool addFuncImport(const Sig& sig, uint32_t globalDataOffset); @@ -157,8 +161,8 @@ class MOZ_STACK_CLASS ModuleGenerator const SigWithId& sig(uint32_t sigIndex) const; // Function declarations: - uint32_t numFuncSigs() const { return shared_->funcSigs.length(); } - const SigWithId& funcSig(uint32_t funcIndex) const; + uint32_t numFuncDefs() const { return shared_->funcDefSigs.length(); } + const SigWithId& funcDefSig(uint32_t funcDefIndex) const; // Globals: const GlobalDescVector& globals() const { return shared_->globals; } @@ -167,8 +171,12 @@ class MOZ_STACK_CLASS ModuleGenerator uint32_t numFuncImports() const; const FuncImportGenDesc& funcImport(uint32_t funcImportIndex) const; + // Function index space: + uint32_t numFuncs() const; + const SigWithId& funcSig(uint32_t funcIndex) const; + // Exports: - MOZ_MUST_USE bool addFuncExport(UniqueChars fieldName, uint32_t funcIndex); + MOZ_MUST_USE bool addFuncDefExport(UniqueChars fieldName, uint32_t funcIndex); MOZ_MUST_USE bool addTableExport(UniqueChars fieldName); MOZ_MUST_USE bool addMemoryExport(UniqueChars fieldName); MOZ_MUST_USE bool addGlobalExport(UniqueChars fieldName, uint32_t globalIndex); @@ -176,7 +184,7 @@ class MOZ_STACK_CLASS ModuleGenerator // Function definitions: MOZ_MUST_USE bool startFuncDefs(); MOZ_MUST_USE bool startFuncDef(uint32_t lineOrBytecode, FunctionGenerator* fg); - MOZ_MUST_USE bool finishFuncDef(uint32_t funcIndex, FunctionGenerator* fg); + MOZ_MUST_USE bool finishFuncDef(uint32_t funcDefIndex, FunctionGenerator* fg); MOZ_MUST_USE bool finishFuncDefs(); // Start function: @@ -191,10 +199,10 @@ class MOZ_STACK_CLASS ModuleGenerator // asm.js lazy initialization: void initSig(uint32_t sigIndex, Sig&& sig); - void initFuncSig(uint32_t funcIndex, uint32_t sigIndex); + void initFuncDefSig(uint32_t funcIndex, uint32_t sigIndex); MOZ_MUST_USE bool initImport(uint32_t importIndex, uint32_t sigIndex); MOZ_MUST_USE bool initSigTableLength(uint32_t sigIndex, uint32_t length); - MOZ_MUST_USE bool initSigTableElems(uint32_t sigIndex, Uint32Vector&& elemFuncIndices); + MOZ_MUST_USE bool initSigTableElems(uint32_t sigIndex, Uint32Vector&& elemFuncDefIndices); void initMemoryUsage(MemoryUsage memoryUsage); void bumpMinMemoryLength(uint32_t newMinMemoryLength); MOZ_MUST_USE bool addGlobal(ValType type, bool isConst, uint32_t* index); diff --git a/js/src/asmjs/WasmInstance.cpp b/js/src/asmjs/WasmInstance.cpp index da9e1e9c51f9f..db60672d70675 100644 --- a/js/src/asmjs/WasmInstance.cpp +++ b/js/src/asmjs/WasmInstance.cpp @@ -354,16 +354,14 @@ Instance::Instance(JSContext* cx, HandleFunction f = funcImports[i]; const FuncImport& fi = metadata().funcImports[i]; FuncImportTls& import = funcImportTls(fi); - if (IsExportedFunction(f) && !isAsmJS() && !ExportedFunctionToInstance(f).isAsmJS()) { - Instance& calleeInstance = ExportedFunctionToInstance(f); - const Metadata& calleeMetadata = calleeInstance.metadata(); - uint32_t funcIndex = ExportedFunctionToIndex(f); - const FuncExport& funcExport = calleeMetadata.lookupFuncExport(funcIndex); - const CodeRange& codeRange = calleeMetadata.codeRanges[funcExport.codeRangeIndex()]; + if (!isAsmJS() && IsExportedWasmFunction(f)) { + WasmInstanceObject* calleeInstanceObj = ExportedFunctionToInstanceObject(f); + const CodeRange& codeRange = calleeInstanceObj->getExportedFunctionCodeRange(f); + Instance& calleeInstance = calleeInstanceObj->instance(); import.tls = &calleeInstance.tlsData_; import.code = calleeInstance.codeSegment().base() + codeRange.funcNonProfilingEntry(); import.baselineScript = nullptr; - import.obj = ExportedFunctionToInstanceObject(f); + import.obj = calleeInstanceObj; } else { import.tls = &tlsData_; import.code = codeBase() + fi.interpExitCodeOffset(); @@ -590,12 +588,12 @@ Instance::object() const } bool -Instance::callExport(JSContext* cx, uint32_t funcIndex, CallArgs args) +Instance::callExport(JSContext* cx, uint32_t funcDefIndex, CallArgs args) { if (!cx->compartment()->wasm.ensureProfilingState(cx)) return false; - const FuncExport& func = metadata().lookupFuncExport(funcIndex); + const FuncDefExport& func = metadata().lookupFuncDefExport(funcDefIndex); // The calling convention for an external call into wasm is to pass an // array of 16-byte values where each value contains either a coerced int32 diff --git a/js/src/asmjs/WasmInstance.h b/js/src/asmjs/WasmInstance.h index 7e734560b5618..c59591ef119a3 100644 --- a/js/src/asmjs/WasmInstance.h +++ b/js/src/asmjs/WasmInstance.h @@ -104,7 +104,7 @@ class Instance // Execute the given export given the JS call arguments, storing the return // value in args.rval. - MOZ_MUST_USE bool callExport(JSContext* cx, uint32_t funcIndex, CallArgs args); + MOZ_MUST_USE bool callExport(JSContext* cx, uint32_t funcDefIndex, CallArgs args); // Initially, calls to imports in wasm code call out through the generic // callImport method. If the imported callee gets JIT compiled and the types diff --git a/js/src/asmjs/WasmIonCompile.cpp b/js/src/asmjs/WasmIonCompile.cpp index ebd7c6d00a241..f2d04ef0efdf9 100644 --- a/js/src/asmjs/WasmIonCompile.cpp +++ b/js/src/asmjs/WasmIonCompile.cpp @@ -994,8 +994,8 @@ class FunctionCompiler return true; } - bool internalCall(const Sig& sig, uint32_t funcIndex, const CallCompileState& call, - MDefinition** def) + bool callDefinition(const Sig& sig, uint32_t funcDefIndex, const CallCompileState& call, + MDefinition** def) { if (inDeadCode()) { *def = nullptr; @@ -1004,7 +1004,7 @@ class FunctionCompiler CallSiteDesc desc(call.lineOrBytecode_, CallSiteDesc::Relative); MIRType ret = ToMIRType(sig.ret()); - auto callee = CalleeDesc::internal(funcIndex); + auto callee = CalleeDesc::definition(funcDefIndex); auto* ins = MWasmCall::New(alloc(), desc, callee, call.regArgs_, ret, call.spIncrement_, MWasmCall::DontSaveTls); if (!ins) @@ -1885,26 +1885,20 @@ EmitCallArgs(FunctionCompiler& f, const Sig& sig, InterModule interModule, CallC } static bool -EmitCall(FunctionCompiler& f, uint32_t callOffset) +EmitCallImportCommon(FunctionCompiler& f, uint32_t lineOrBytecode, uint32_t funcImportIndex) { - uint32_t lineOrBytecode = f.readCallSiteLineOrBytecode(callOffset); - - uint32_t calleeIndex; - uint32_t arity; - if (!f.iter().readCall(&calleeIndex, &arity)) - return false; - - const Sig& sig = *f.mg().funcSigs[calleeIndex]; + const FuncImportGenDesc& funcImport = f.mg().funcImports[funcImportIndex]; + const Sig& sig = *funcImport.sig; CallCompileState call(f, lineOrBytecode); - if (!EmitCallArgs(f, sig, InterModule::False, &call)) + if (!EmitCallArgs(f, sig, InterModule::True, &call)) return false; if (!f.iter().readCallReturn(sig.ret())) return false; MDefinition* def; - if (!f.internalCall(sig, calleeIndex, call, &def)) + if (!f.callImport(funcImport.globalDataOffset, call, sig.ret(), &def)) return false; if (IsVoid(sig.ret())) @@ -1915,32 +1909,33 @@ EmitCall(FunctionCompiler& f, uint32_t callOffset) } static bool -EmitCallIndirect(FunctionCompiler& f, uint32_t callOffset) +EmitCall(FunctionCompiler& f, uint32_t callOffset) { uint32_t lineOrBytecode = f.readCallSiteLineOrBytecode(callOffset); - uint32_t sigIndex; + uint32_t calleeIndex; uint32_t arity; - if (!f.iter().readCallIndirect(&sigIndex, &arity)) + if (!f.iter().readCall(&calleeIndex, &arity)) return false; - const Sig& sig = f.mg().sigs[sigIndex]; + // For asm.js and old-format wasm code, imports are not part of the function + // index space so in these cases firstFuncDefIndex is fixed to 0, even if + // there are function imports. + if (calleeIndex < f.mg().firstFuncDefIndex) + return EmitCallImportCommon(f, lineOrBytecode, calleeIndex); - InterModule interModule = InterModule(!f.mg().isAsmJS() && f.mg().tables[0].external); + uint32_t funcDefIndex = calleeIndex - f.mg().firstFuncDefIndex; + const Sig& sig = *f.mg().funcDefSigs[funcDefIndex]; CallCompileState call(f, lineOrBytecode); - if (!EmitCallArgs(f, sig, interModule, &call)) - return false; - - MDefinition* callee; - if (!f.iter().readCallIndirectCallee(&callee)) + if (!EmitCallArgs(f, sig, InterModule::False, &call)) return false; if (!f.iter().readCallReturn(sig.ret())) return false; MDefinition* def; - if (!f.callIndirect(sigIndex, callee, call, &def)) + if (!f.callDefinition(sig, funcDefIndex, call, &def)) return false; if (IsVoid(sig.ret())) @@ -1953,6 +1948,8 @@ EmitCallIndirect(FunctionCompiler& f, uint32_t callOffset) static bool EmitCallImport(FunctionCompiler& f, uint32_t callOffset) { + MOZ_ASSERT(!f.mg().firstFuncDefIndex); + uint32_t lineOrBytecode = f.readCallSiteLineOrBytecode(callOffset); uint32_t funcImportIndex; @@ -1960,18 +1957,36 @@ EmitCallImport(FunctionCompiler& f, uint32_t callOffset) if (!f.iter().readCallImport(&funcImportIndex, &arity)) return false; - const FuncImportGenDesc& funcImport = f.mg().funcImports[funcImportIndex]; - const Sig& sig = *funcImport.sig; + return EmitCallImportCommon(f, lineOrBytecode, funcImportIndex); +} + +static bool +EmitCallIndirect(FunctionCompiler& f, uint32_t callOffset) +{ + uint32_t lineOrBytecode = f.readCallSiteLineOrBytecode(callOffset); + + uint32_t sigIndex; + uint32_t arity; + if (!f.iter().readCallIndirect(&sigIndex, &arity)) + return false; + + const Sig& sig = f.mg().sigs[sigIndex]; + + InterModule interModule = InterModule(!f.mg().isAsmJS() && f.mg().tables[0].external); CallCompileState call(f, lineOrBytecode); - if (!EmitCallArgs(f, sig, InterModule::True, &call)) + if (!EmitCallArgs(f, sig, interModule, &call)) + return false; + + MDefinition* callee; + if (!f.iter().readCallIndirectCallee(&callee)) return false; if (!f.iter().readCallReturn(sig.ret())) return false; MDefinition* def; - if (!f.callImport(funcImport.globalDataOffset, call, sig.ret(), &def)) + if (!f.callIndirect(sigIndex, callee, call, &def)) return false; if (IsVoid(sig.ret())) @@ -3694,7 +3709,7 @@ wasm::IonCompileFunction(IonCompileTask* task) if (!lir) return false; - SigIdDesc sigId = task->mg().funcSigs[func.index()]->id; + SigIdDesc sigId = task->mg().funcDefSigs[func.defIndex()]->id; CodeGenerator codegen(&mir, lir, &results.masm()); if (!codegen.generateWasm(sigId, &results.offsets())) diff --git a/js/src/asmjs/WasmIonCompile.h b/js/src/asmjs/WasmIonCompile.h index 557125adbb0fc..353cd0f0611a6 100644 --- a/js/src/asmjs/WasmIonCompile.h +++ b/js/src/asmjs/WasmIonCompile.h @@ -38,19 +38,19 @@ typedef jit::ABIArgIter ABIArgValTypeIter; class FuncBytes { Bytes bytes_; - uint32_t index_; + uint32_t defIndex_; const SigWithId& sig_; uint32_t lineOrBytecode_; Uint32Vector callSiteLineNums_; public: FuncBytes(Bytes&& bytes, - uint32_t index, + uint32_t defIndex, const SigWithId& sig, uint32_t lineOrBytecode, Uint32Vector&& callSiteLineNums) : bytes_(Move(bytes)), - index_(index), + defIndex_(defIndex), sig_(sig), lineOrBytecode_(lineOrBytecode), callSiteLineNums_(Move(callSiteLineNums)) @@ -58,7 +58,7 @@ class FuncBytes Bytes& bytes() { return bytes_; } const Bytes& bytes() const { return bytes_; } - uint32_t index() const { return index_; } + uint32_t defIndex() const { return defIndex_; } const SigWithId& sig() const { return sig_; } uint32_t lineOrBytecode() const { return lineOrBytecode_; } const Uint32Vector& callSiteLineNums() const { return callSiteLineNums_; } diff --git a/js/src/asmjs/WasmJS.cpp b/js/src/asmjs/WasmJS.cpp index 5e5a30a47fd60..b3cfd88633e87 100644 --- a/js/src/asmjs/WasmJS.cpp +++ b/js/src/asmjs/WasmJS.cpp @@ -617,34 +617,34 @@ WasmCall(JSContext* cx, unsigned argc, Value* vp) RootedFunction callee(cx, &args.callee().as()); Instance& instance = ExportedFunctionToInstance(callee); - uint32_t funcIndex = ExportedFunctionToIndex(callee); - return instance.callExport(cx, funcIndex, args); + uint32_t funcDefIndex = ExportedFunctionToDefinitionIndex(callee); + return instance.callExport(cx, funcDefIndex, args); } /* static */ bool WasmInstanceObject::getExportedFunction(JSContext* cx, HandleWasmInstanceObject instanceObj, - uint32_t funcIndex, MutableHandleFunction fun) + uint32_t funcDefIndex, MutableHandleFunction fun) { - if (ExportMap::Ptr p = instanceObj->exports().lookup(funcIndex)) { + if (ExportMap::Ptr p = instanceObj->exports().lookup(funcDefIndex)) { fun.set(p->value()); return true; } const Instance& instance = instanceObj->instance(); - RootedAtom name(cx, instance.code().getFuncAtom(cx, funcIndex)); + RootedAtom name(cx, instance.code().getFuncDefAtom(cx, funcDefIndex)); if (!name) return false; - unsigned numArgs = instance.metadata().lookupFuncExport(funcIndex).sig().args().length(); + unsigned numArgs = instance.metadata().lookupFuncDefExport(funcDefIndex).sig().args().length(); fun.set(NewNativeConstructor(cx, WasmCall, numArgs, name, gc::AllocKind::FUNCTION_EXTENDED, GenericObject, JSFunction::ASMJS_CTOR)); if (!fun) return false; fun->setExtendedSlot(FunctionExtended::WASM_INSTANCE_SLOT, ObjectValue(*instanceObj)); - fun->setExtendedSlot(FunctionExtended::WASM_FUNC_INDEX_SLOT, Int32Value(funcIndex)); + fun->setExtendedSlot(FunctionExtended::WASM_FUNC_DEF_INDEX_SLOT, Int32Value(funcDefIndex)); - if (!instanceObj->exports().putNew(funcIndex, fun)) { + if (!instanceObj->exports().putNew(funcDefIndex, fun)) { ReportOutOfMemory(cx); return false; } @@ -652,12 +652,27 @@ WasmInstanceObject::getExportedFunction(JSContext* cx, HandleWasmInstanceObject return true; } +const CodeRange& +WasmInstanceObject::getExportedFunctionCodeRange(HandleFunction fun) +{ + uint32_t funcDefIndex = ExportedFunctionToDefinitionIndex(fun); + MOZ_ASSERT(exports().lookup(funcDefIndex)->value() == fun); + const Metadata& metadata = instance().metadata(); + return metadata.codeRanges[metadata.lookupFuncDefExport(funcDefIndex).codeRangeIndex()]; +} + bool wasm::IsExportedFunction(JSFunction* fun) { return fun->maybeNative() == WasmCall; } +bool +wasm::IsExportedWasmFunction(JSFunction* fun) +{ + return IsExportedFunction(fun) && !ExportedFunctionToInstance(fun).isAsmJS(); +} + bool wasm::IsExportedFunction(const Value& v, MutableHandleFunction f) { @@ -687,10 +702,10 @@ wasm::ExportedFunctionToInstanceObject(JSFunction* fun) } uint32_t -wasm::ExportedFunctionToIndex(JSFunction* fun) +wasm::ExportedFunctionToDefinitionIndex(JSFunction* fun) { MOZ_ASSERT(IsExportedFunction(fun)); - const Value& v = fun->getExtendedSlot(FunctionExtended::WASM_FUNC_INDEX_SLOT); + const Value& v = fun->getExtendedSlot(FunctionExtended::WASM_FUNC_DEF_INDEX_SLOT); return v.toInt32(); } @@ -1040,7 +1055,7 @@ WasmTableObject::getImpl(JSContext* cx, const CallArgs& args) RootedWasmInstanceObject instanceObj(cx, instance.object()); RootedFunction fun(cx); - if (!instanceObj->getExportedFunction(cx, instanceObj, codeRange->funcIndex(), &fun)) + if (!instanceObj->getExportedFunction(cx, instanceObj, codeRange->funcDefIndex(), &fun)) return false; args.rval().setObject(*fun); @@ -1077,7 +1092,7 @@ WasmTableObject::setImpl(JSContext* cx, const CallArgs& args) RootedFunction value(cx); if (!IsExportedFunction(args[1], &value) && !args[1].isNull()) { - JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_SET_VALUE); + JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_TABLE_VALUE); return false; } @@ -1092,17 +1107,17 @@ WasmTableObject::setImpl(JSContext* cx, const CallArgs& args) if (value) { RootedWasmInstanceObject instanceObj(cx, ExportedFunctionToInstanceObject(value)); - uint32_t funcIndex = ExportedFunctionToIndex(value); + uint32_t funcDefIndex = ExportedFunctionToDefinitionIndex(value); #ifdef DEBUG RootedFunction f(cx); - MOZ_ASSERT(instanceObj->getExportedFunction(cx, instanceObj, funcIndex, &f)); + MOZ_ASSERT(instanceObj->getExportedFunction(cx, instanceObj, funcDefIndex, &f)); MOZ_ASSERT(value == f); #endif Instance& instance = instanceObj->instance(); - const FuncExport& funcExport = instance.metadata().lookupFuncExport(funcIndex); - const CodeRange& codeRange = instance.metadata().codeRanges[funcExport.codeRangeIndex()]; + const FuncDefExport& funcDefExport = instance.metadata().lookupFuncDefExport(funcDefIndex); + const CodeRange& codeRange = instance.metadata().codeRanges[funcDefExport.codeRangeIndex()]; void* code = instance.codeSegment().base() + codeRange.funcTableEntry(); table.set(index, code, instance); } else { diff --git a/js/src/asmjs/WasmJS.h b/js/src/asmjs/WasmJS.h index e9619443f2de4..1e9c80941353f 100644 --- a/js/src/asmjs/WasmJS.h +++ b/js/src/asmjs/WasmJS.h @@ -53,6 +53,9 @@ extern const char InstanceExportField[]; extern bool IsExportedFunction(JSFunction* fun); +extern bool +IsExportedWasmFunction(JSFunction* fun); + extern bool IsExportedFunction(const Value& v, MutableHandleFunction f); @@ -63,7 +66,7 @@ extern WasmInstanceObject* ExportedFunctionToInstanceObject(JSFunction* fun); extern uint32_t -ExportedFunctionToIndex(JSFunction* fun); +ExportedFunctionToDefinitionIndex(JSFunction* fun); } // namespace wasm @@ -117,9 +120,9 @@ class WasmInstanceObject : public NativeObject static void finalize(FreeOp* fop, JSObject* obj); static void trace(JSTracer* trc, JSObject* obj); - // ExportMap maps from function index to exported function object. This map - // is weak to avoid holding objects alive; the point is just to ensure a - // unique object identity for any given function object. + // ExportMap maps from function definition index to exported function + // object. This map is weak to avoid holding objects alive; the point is + // just to ensure a unique object identity for any given function object. using ExportMap = GCHashMap, @@ -147,6 +150,8 @@ class WasmInstanceObject : public NativeObject HandleWasmInstanceObject instanceObj, uint32_t funcIndex, MutableHandleFunction fun); + + const wasm::CodeRange& getExportedFunctionCodeRange(HandleFunction fun); }; // The class of WebAssembly.Memory. A WasmMemoryObject references an ArrayBuffer diff --git a/js/src/asmjs/WasmModule.cpp b/js/src/asmjs/WasmModule.cpp index ef8a6576275dc..e1a44ff69b10e 100644 --- a/js/src/asmjs/WasmModule.cpp +++ b/js/src/asmjs/WasmModule.cpp @@ -412,69 +412,113 @@ Module::addSizeOfMisc(MallocSizeOf mallocSizeOf, bytecode_->sizeOfIncludingThisIfNotSeen(mallocSizeOf, seenBytes); } +static uint32_t +EvaluateInitExpr(const ValVector& globalImports, InitExpr initExpr) +{ + switch (initExpr.kind()) { + case InitExpr::Kind::Constant: + return initExpr.val().i32(); + case InitExpr::Kind::GetGlobal: + return globalImports[initExpr.globalIndex()].i32(); + } + + MOZ_CRASH("bad initializer expression"); +} + bool -Module::initElems(JSContext* cx, HandleWasmInstanceObject instanceObj, - const ValVector& globalImports, HandleWasmTableObject tableObj) const +Module::initSegments(JSContext* cx, + HandleWasmInstanceObject instanceObj, + Handle funcImports, + HandleWasmMemoryObject memoryObj, + const ValVector& globalImports) const { Instance& instance = instanceObj->instance(); const SharedTableVector& tables = instance.tables(); + // Perform all error checks up front so that this function does not perform + // partial initialization if an error is reported. + + for (const ElemSegment& seg : elemSegments_) { + uint32_t tableLength = tables[seg.tableIndex]->length(); + uint32_t offset = EvaluateInitExpr(globalImports, seg.offset); + + if (offset > tableLength || tableLength - offset < seg.elemCodeRangeIndices.length()) { + JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_FIT, "elem", "table"); + return false; + } + } + + if (memoryObj) { + for (const DataSegment& seg : dataSegments_) { + uint32_t memoryLength = memoryObj->buffer().byteLength(); + uint32_t offset = EvaluateInitExpr(globalImports, seg.offset); + + if (offset > memoryLength || memoryLength - offset < seg.length) { + JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_FIT, "data", "memory"); + return false; + } + } + } else { + MOZ_ASSERT(dataSegments_.empty()); + } + // Ensure all tables are initialized before storing into them. + for (const SharedTable& table : tables) { if (!table->initialized()) table->init(instance); } - // Now that all tables have been initialized, write elements. - Vector prevEnds(cx); - if (!prevEnds.appendN(0, tables.length())) - return false; + // Now that initialization can't fail partway through, write data/elem + // segments into memories/tables. for (const ElemSegment& seg : elemSegments_) { Table& table = *tables[seg.tableIndex]; + uint32_t offset = EvaluateInitExpr(globalImports, seg.offset); + bool profilingEnabled = instance.code().profilingEnabled(); + const CodeRangeVector& codeRanges = metadata().codeRanges; + uint8_t* codeBase = instance.codeBase(); - uint32_t offset; - switch (seg.offset.kind()) { - case InitExpr::Kind::Constant: { - offset = seg.offset.val().i32(); - break; - } - case InitExpr::Kind::GetGlobal: { - const GlobalDesc& global = metadata_->globals[seg.offset.globalIndex()]; - offset = globalImports[global.importIndex()].i32(); - break; - } - } - - uint32_t& prevEnd = prevEnds[seg.tableIndex]; + for (uint32_t i = 0; i < seg.elemCodeRangeIndices.length(); i++) { + uint32_t elemFuncIndex = seg.elemFuncIndices[i]; + if (elemFuncIndex < funcImports.length()) { + MOZ_ASSERT(!metadata().isAsmJS()); + MOZ_ASSERT(!table.isTypedFunction()); + MOZ_ASSERT(seg.elemCodeRangeIndices[i] == UINT32_MAX); + + HandleFunction f = funcImports[elemFuncIndex]; + if (!IsExportedWasmFunction(f)) { + JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_TABLE_VALUE); + return false; + } - if (offset < prevEnd) { - JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_FAIL, - "elem segments must be disjoint and ordered"); - return false; + WasmInstanceObject* exportInstanceObj = ExportedFunctionToInstanceObject(f); + const CodeRange& cr = exportInstanceObj->getExportedFunctionCodeRange(f); + Instance& exportInstance = exportInstanceObj->instance(); + table.set(offset + i, exportInstance.codeBase() + cr.funcTableEntry(), exportInstance); + } else { + MOZ_ASSERT(seg.elemCodeRangeIndices[i] != UINT32_MAX); + + const CodeRange& cr = codeRanges[seg.elemCodeRangeIndices[i]]; + uint32_t entryOffset = table.isTypedFunction() + ? profilingEnabled + ? cr.funcProfilingEntry() + : cr.funcNonProfilingEntry() + : cr.funcTableEntry(); + table.set(offset + i, codeBase + entryOffset, instance); + } } + } - uint32_t tableLength = instance.metadata().tables[seg.tableIndex].initial; - if (offset > tableLength || tableLength - offset < seg.elemCodeRangeIndices.length()) { - JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_FAIL, - "element segment does not fit"); - return false; - } + if (memoryObj) { + uint8_t* memoryBase = memoryObj->buffer().dataPointerEither().unwrap(/* memcpy */); - bool profilingEnabled = instance.code().profilingEnabled(); - const CodeRangeVector& codeRanges = instance.code().metadata().codeRanges; - uint8_t* codeBase = instance.codeBase(); - for (uint32_t i = 0; i < seg.elemCodeRangeIndices.length(); i++) { - const CodeRange& cr = codeRanges[seg.elemCodeRangeIndices[i]]; - uint32_t codeOffset = table.isTypedFunction() - ? profilingEnabled - ? cr.funcProfilingEntry() - : cr.funcNonProfilingEntry() - : cr.funcTableEntry(); - table.set(offset + i, codeBase + codeOffset, instance); + for (const DataSegment& seg : dataSegments_) { + MOZ_ASSERT(seg.bytecodeOffset <= bytecode_->length()); + MOZ_ASSERT(seg.length <= bytecode_->length() - seg.bytecodeOffset); + uint32_t offset = EvaluateInitExpr(globalImports, seg.offset); + memcpy(memoryBase + offset, bytecode_->begin() + seg.bytecodeOffset, seg.length); } - - prevEnd = offset + seg.elemFuncIndices.length(); } return true; @@ -493,11 +537,11 @@ Module::instantiateFunctions(JSContext* cx, Handle funcImports) if (!IsExportedFunction(f) || ExportedFunctionToInstance(f).isAsmJS()) continue; - uint32_t funcIndex = ExportedFunctionToIndex(f); + uint32_t funcDefIndex = ExportedFunctionToDefinitionIndex(f); Instance& instance = ExportedFunctionToInstance(f); - const FuncExport& funcExport = instance.metadata().lookupFuncExport(funcIndex); + const FuncDefExport& funcDefExport = instance.metadata().lookupFuncDefExport(funcDefIndex); - if (funcExport.sig() != metadata_->funcImports[i].sig()) { + if (funcDefExport.sig() != metadata_->funcImports[i].sig()) { JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_IMPORT_SIG); return false; } @@ -518,16 +562,16 @@ Module::instantiateMemory(JSContext* cx, MutableHandleWasmMemoryObject memory) c return true; } - RootedArrayBufferObjectMaybeShared buffer(cx); + uint32_t declaredMin = metadata_->minMemoryLength; + Maybe declaredMax = metadata_->maxMemoryLength; + if (memory) { - buffer = &memory->buffer(); - uint32_t length = buffer->wasmActualByteLength(); - uint32_t declaredMaxLength = metadata_->maxMemoryLength.valueOr(UINT32_MAX); - - // It's not an error to import a memory whose mapped size is less than - // the maxMemoryLength required for the module. This is the same as trying to - // map up to maxMemoryLength but actually getting less. - if (length < metadata_->minMemoryLength || length > declaredMaxLength) { + RootedArrayBufferObjectMaybeShared buffer(cx, &memory->buffer()); + MOZ_RELEASE_ASSERT(buffer->is() || + buffer->as().isWasm()); + + uint32_t actualLength = buffer->wasmActualByteLength(); + if (actualLength < declaredMin || actualLength > declaredMax.valueOr(UINT32_MAX)) { JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_IMP_SIZE, "Memory"); return false; } @@ -536,27 +580,18 @@ Module::instantiateMemory(JSContext* cx, MutableHandleWasmMemoryObject memory) c // For wasm we require that either both memory and module don't specify a max size // OR that the memory's max size is less than the modules. if (!metadata_->isAsmJS()) { - Maybe memMaxSize = - buffer->as().wasmMaxSize(); - - if (metadata_->maxMemoryLength.isSome() != memMaxSize.isSome() || - metadata_->maxMemoryLength < memMaxSize) { - JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_IMP_SIZE, - "Memory"); + Maybe actualMax = buffer->as().wasmMaxSize(); + if (declaredMax.isSome() != actualMax.isSome() || declaredMax < actualMax) { + JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_IMP_SIZE, "Memory"); return false; } } - - MOZ_RELEASE_ASSERT(buffer->is() || - buffer->as().isWasm()); - - // We currently assume SharedArrayBuffer => asm.js. Can remove this - // once wasmMaxSize/mappedSize/growForWasm have been implemented in SAB - MOZ_ASSERT_IF(buffer->is(), metadata_->isAsmJS()); } else { - buffer = ArrayBufferObject::createForWasm(cx, metadata_->minMemoryLength, - metadata_->maxMemoryLength); + MOZ_ASSERT(!metadata_->isAsmJS()); + MOZ_ASSERT(metadata_->memoryUsage == MemoryUsage::Unshared); + RootedArrayBufferObjectMaybeShared buffer(cx, + ArrayBufferObject::createForWasm(cx, declaredMin, declaredMax)); if (!buffer) return false; @@ -569,12 +604,6 @@ Module::instantiateMemory(JSContext* cx, MutableHandleWasmMemoryObject memory) c return false; } - MOZ_ASSERT(buffer->is() || buffer->as().isWasm()); - - uint8_t* memoryBase = memory->buffer().dataPointerEither().unwrap(/* memcpy */); - for (const DataSegment& seg : dataSegments_) - memcpy(memoryBase + seg.memoryOffset, bytecode_->begin() + seg.bytecodeOffset, seg.length); - return true; } @@ -628,8 +657,30 @@ Module::instantiateTable(JSContext* cx, MutableHandleWasmTableObject tableObj, } static bool -ExportGlobalValue(JSContext* cx, const GlobalDescVector& globals, uint32_t globalIndex, - const ValVector& globalImports, MutableHandleValue jsval) +GetFunctionExport(JSContext* cx, + HandleWasmInstanceObject instanceObj, + Handle funcImports, + const Export& exp, + MutableHandleValue val) +{ + if (exp.funcIndex() < funcImports.length()) { + val.setObject(*funcImports[exp.funcIndex()]); + return true; + } + + uint32_t funcDefIndex = exp.funcIndex() - funcImports.length(); + + RootedFunction fun(cx); + if (!instanceObj->getExportedFunction(cx, instanceObj, funcDefIndex, &fun)) + return false; + + val.setObject(*fun); + return true; +} + +static bool +GetGlobalExport(JSContext* cx, const GlobalDescVector& globals, uint32_t globalIndex, + const ValVector& globalImports, MutableHandleValue jsval) { const GlobalDesc& global = globals[globalIndex]; @@ -672,6 +723,7 @@ ExportGlobalValue(JSContext* cx, const GlobalDescVector& globals, uint32_t globa static bool CreateExportObject(JSContext* cx, HandleWasmInstanceObject instanceObj, + Handle funcImports, HandleWasmTableObject tableObj, HandleWasmMemoryObject memoryObj, const ValVector& globalImports, @@ -682,10 +734,10 @@ CreateExportObject(JSContext* cx, const Metadata& metadata = instance.metadata(); if (metadata.isAsmJS() && exports.length() == 1 && strlen(exports[0].fieldName()) == 0) { - RootedFunction fun(cx); - if (!instanceObj->getExportedFunction(cx, instanceObj, exports[0].funcIndex(), &fun)) + RootedValue val(cx); + if (!GetFunctionExport(cx, instanceObj, funcImports, exports[0], &val)) return false; - exportObj.set(fun); + exportObj.set(&val.toObject()); return true; } @@ -701,29 +753,23 @@ CreateExportObject(JSContext* cx, RootedId id(cx, AtomToId(atom)); RootedValue val(cx); switch (exp.kind()) { - case DefinitionKind::Function: { - RootedFunction fun(cx); - if (!instanceObj->getExportedFunction(cx, instanceObj, exp.funcIndex(), &fun)) + case DefinitionKind::Function: + if (!GetFunctionExport(cx, instanceObj, funcImports, exp, &val)) return false; - val = ObjectValue(*fun); break; - } - case DefinitionKind::Table: { + case DefinitionKind::Table: val = ObjectValue(*tableObj); break; - } - case DefinitionKind::Memory: { + case DefinitionKind::Memory: if (metadata.assumptions.newFormat) val = ObjectValue(*memoryObj); else val = ObjectValue(memoryObj->buffer()); break; - } - case DefinitionKind::Global: { - if (!ExportGlobalValue(cx, metadata.globals, exp.globalIndex(), globalImports, &val)) + case DefinitionKind::Global: + if (!GetGlobalExport(cx, metadata.globals, exp.globalIndex(), globalImports, &val)) return false; break; - } } if (!JS_DefinePropertyById(cx, exportObj, id, val, JSPROP_ENUMERATE)) @@ -740,7 +786,7 @@ Module::instantiate(JSContext* cx, HandleWasmMemoryObject memoryImport, const ValVector& globalImports, HandleObject instanceProto, - MutableHandleWasmInstanceObject instanceObj) const + MutableHandleWasmInstanceObject instance) const { if (!instantiateFunctions(cx, funcImports)) return false; @@ -773,18 +819,18 @@ Module::instantiate(JSContext* cx, if (!code) return false; - instanceObj.set(WasmInstanceObject::create(cx, - Move(code), - memory, - Move(tables), - funcImports, - globalImports, - instanceProto)); - if (!instanceObj) + instance.set(WasmInstanceObject::create(cx, + Move(code), + memory, + Move(tables), + funcImports, + globalImports, + instanceProto)); + if (!instance) return false; RootedObject exportObj(cx); - if (!CreateExportObject(cx, instanceObj, table, memory, globalImports, exports_, &exportObj)) + if (!CreateExportObject(cx, instance, funcImports, table, memory, globalImports, exports_, &exportObj)) return false; JSAtom* atom = Atomize(cx, InstanceExportField, strlen(InstanceExportField)); @@ -793,32 +839,42 @@ Module::instantiate(JSContext* cx, RootedId id(cx, AtomToId(atom)); RootedValue val(cx, ObjectValue(*exportObj)); - if (!JS_DefinePropertyById(cx, instanceObj, id, val, JSPROP_ENUMERATE)) + if (!JS_DefinePropertyById(cx, instance, id, val, JSPROP_ENUMERATE)) return false; // Register the instance with the JSCompartment so that it can find out // about global events like profiling being enabled in the compartment. + // Registration does not require a fully-initialized instance and must + // precede initSegments as the final pre-requisite for a live instance. - if (!cx->compartment()->wasm.registerInstance(cx, instanceObj)) + if (!cx->compartment()->wasm.registerInstance(cx, instance)) return false; - // Initialize table elements only after the instance is fully initialized - // since the Table object needs to point to a valid instance object. Perform - // initialization as the final step after the instance is fully live since - // it is observable (in the case of an imported Table object) and can't be - // easily rolled back in case of error. + // Perform initialization as the final step after the instance is fully + // constructed since this can make the instance live to content (even if the + // start function fails). - if (!initElems(cx, instanceObj, globalImports, table)) + if (!initSegments(cx, instance, funcImports, memory, globalImports)) return false; - // Call the start function, if there's one. This effectively makes the - // instance object live to content and thus must go after initialization is - // complete. + // Now that the instance is fully live and initialized, the start function. + // Note that failure may cause instantiation to throw, but the instance may + // still be live via edges created by initSegments or the start function. if (metadata_->hasStartFunction()) { + uint32_t startFuncIndex = metadata_->startFuncIndex(); FixedInvokeArgs<0> args(cx); - if (!instanceObj->instance().callExport(cx, metadata_->startFuncIndex(), args)) - return false; + if (startFuncIndex < funcImports.length()) { + RootedValue fval(cx, ObjectValue(*funcImports[startFuncIndex])); + RootedValue thisv(cx); + RootedValue rval(cx); + if (!Call(cx, fval, thisv, args, &rval)) + return false; + } else { + uint32_t funcDefIndex = startFuncIndex - funcImports.length(); + if (!instance->instance().callExport(cx, funcDefIndex, args)) + return false; + } } return true; diff --git a/js/src/asmjs/WasmModule.h b/js/src/asmjs/WasmModule.h index 253b7a41ed2d2..07881ab57abe5 100644 --- a/js/src/asmjs/WasmModule.h +++ b/js/src/asmjs/WasmModule.h @@ -113,7 +113,7 @@ typedef Vector ImportVector; // Export describes the export of a definition in a Module to a field in the // export object. For functions, Export stores an index into the -// FuncExportVector in Metadata. For memory and table exports, there is +// FuncDefExportVector in Metadata. For memory and table exports, there is // at most one (default) memory/table so no index is needed. Note: a single // definition can be exported by multiple Exports in the ExportVector. // @@ -149,7 +149,7 @@ typedef Vector ExportVector; struct DataSegment { - uint32_t memoryOffset; + InitExpr offset; uint32_t bytecodeOffset; uint32_t length; }; @@ -167,17 +167,9 @@ struct ElemSegment Uint32Vector elemCodeRangeIndices; ElemSegment() = default; - ElemSegment(uint32_t tableIndex, - InitExpr offset, - Uint32Vector&& elemFuncIndices, - Uint32Vector&& elemCodeRangeIndices) - : tableIndex(tableIndex), - offset(offset), - elemFuncIndices(Move(elemFuncIndices)), - elemCodeRangeIndices(Move(elemCodeRangeIndices)) - { - MOZ_ASSERT(elemFuncIndices.length() == elemCodeRangeIndices.length()); - } + ElemSegment(uint32_t tableIndex, InitExpr offset, Uint32Vector&& elemFuncIndices) + : tableIndex(tableIndex), offset(offset), elemFuncIndices(Move(elemFuncIndices)) + {} WASM_DECLARE_SERIALIZABLE(ElemSegment) }; @@ -209,10 +201,14 @@ class Module : public RefCounted bool instantiateFunctions(JSContext* cx, Handle funcImports) const; bool instantiateMemory(JSContext* cx, MutableHandleWasmMemoryObject memory) const; - bool instantiateTable(JSContext* cx, MutableHandleWasmTableObject table, + bool instantiateTable(JSContext* cx, + MutableHandleWasmTableObject table, SharedTableVector* tables) const; - bool initElems(JSContext* cx, HandleWasmInstanceObject instanceObj, - const ValVector& globalImports, HandleWasmTableObject tableObj) const; + bool initSegments(JSContext* cx, + HandleWasmInstanceObject instance, + Handle funcImports, + HandleWasmMemoryObject memory, + const ValVector& globalImports) const; public: Module(Bytes&& code, diff --git a/js/src/asmjs/WasmStubs.cpp b/js/src/asmjs/WasmStubs.cpp index 669368cfa1b01..52c8e93433d91 100644 --- a/js/src/asmjs/WasmStubs.cpp +++ b/js/src/asmjs/WasmStubs.cpp @@ -96,7 +96,7 @@ static const unsigned FramePushedForEntrySP = FramePushedAfterSave + sizeof(void // function has an ABI derived from its specific signature, so this function // must map from the ABI of ExportFuncPtr to the export's signature's ABI. Offsets -wasm::GenerateEntry(MacroAssembler& masm, const FuncExport& fe) +wasm::GenerateEntry(MacroAssembler& masm, const FuncDefExport& func) { masm.haltingAlign(CodeAlignment); @@ -160,11 +160,11 @@ wasm::GenerateEntry(MacroAssembler& masm, const FuncExport& fe) masm.andToStackPtr(Imm32(~(AsmJSStackAlignment - 1))); // Bump the stack for the call. - masm.reserveStack(AlignBytes(StackArgBytes(fe.sig().args()), AsmJSStackAlignment)); + masm.reserveStack(AlignBytes(StackArgBytes(func.sig().args()), AsmJSStackAlignment)); // Copy parameters out of argv and into the registers/stack-slots specified by // the system ABI. - for (ABIArgValTypeIter iter(fe.sig().args()); !iter.done(); iter++) { + for (ABIArgValTypeIter iter(func.sig().args()); !iter.done(); iter++) { unsigned argOffset = iter.index() * sizeof(ExportArg); Address src(argv, argOffset); MIRType type = iter.mirType(); @@ -264,7 +264,7 @@ wasm::GenerateEntry(MacroAssembler& masm, const FuncExport& fe) // Call into the real function. masm.assertStackAlignment(AsmJSStackAlignment); - masm.call(CallSiteDesc(CallSiteDesc::Relative), fe.funcIndex()); + masm.call(CallSiteDesc(CallSiteDesc::Relative), func.funcDefIndex()); // Recover the stack pointer value before dynamic alignment. masm.loadWasmActivationFromTls(scratch); @@ -275,7 +275,7 @@ wasm::GenerateEntry(MacroAssembler& masm, const FuncExport& fe) masm.Pop(argv); // Store the return value in argv[0] - switch (fe.sig().ret()) { + switch (func.sig().ret()) { case ExprType::Void: break; case ExprType::I32: diff --git a/js/src/asmjs/WasmStubs.h b/js/src/asmjs/WasmStubs.h index dbb6ac833e18b..19a85cd5c63f6 100644 --- a/js/src/asmjs/WasmStubs.h +++ b/js/src/asmjs/WasmStubs.h @@ -27,11 +27,11 @@ namespace jit { class MacroAssembler; } namespace wasm { -class FuncExport; +class FuncDefExport; class FuncImport; extern Offsets -GenerateEntry(jit::MacroAssembler& masm, const FuncExport& fe); +GenerateEntry(jit::MacroAssembler& masm, const FuncDefExport& func); extern ProfilingOffsets GenerateInterpExit(jit::MacroAssembler& masm, const FuncImport& fi, uint32_t funcImportIndex); diff --git a/js/src/asmjs/WasmTextToBinary.cpp b/js/src/asmjs/WasmTextToBinary.cpp index aee6587c49bef..ce14deb5abfb1 100644 --- a/js/src/asmjs/WasmTextToBinary.cpp +++ b/js/src/asmjs/WasmTextToBinary.cpp @@ -1373,12 +1373,14 @@ struct WasmParseContext LifoAlloc& lifo; UniqueChars* error; DtoaState* dtoaState; + bool newFormat; - WasmParseContext(const char16_t* text, LifoAlloc& lifo, UniqueChars* error) + WasmParseContext(const char16_t* text, LifoAlloc& lifo, UniqueChars* error, bool newFormat) : ts(text, error), lifo(lifo), error(error), - dtoaState(NewDtoaState()) + dtoaState(NewDtoaState()), + newFormat(newFormat) {} bool fail(const char* message) { @@ -2208,7 +2210,7 @@ ParseExprInsideParens(WasmParseContext& c) case WasmToken::Call: return ParseCall(c, Expr::Call); case WasmToken::CallImport: - return ParseCall(c, Expr::CallImport); + return ParseCall(c, c.newFormat ? Expr::Call : Expr::CallImport); case WasmToken::CallIndirect: return ParseCallIndirect(c); case WasmToken::ComparisonOpcode: @@ -2403,17 +2405,32 @@ ParseTypeDef(WasmParseContext& c) } static AstDataSegment* -ParseDataSegment(WasmParseContext& c) +ParseDataSegment(WasmParseContext& c, bool newFormat) { - WasmToken dstOffset; - if (!c.ts.match(WasmToken::Index, &dstOffset, c.error)) - return nullptr; + AstExpr* offset; + if (newFormat) { + WasmToken dstOffset; + if (c.ts.getIf(WasmToken::Index, &dstOffset)) + offset = new(c.lifo) AstConst(Val(dstOffset.index())); + else + offset = ParseExpr(c); + if (!offset) + return nullptr; + } else { + WasmToken dstOffset; + if (!c.ts.match(WasmToken::Index, &dstOffset, c.error)) + return nullptr; + + offset = new(c.lifo) AstConst(Val(dstOffset.index())); + if (!offset) + return nullptr; + } WasmToken text; if (!c.ts.match(WasmToken::Text, &text, c.error)) return nullptr; - return new(c.lifo) AstDataSegment(dstOffset.index(), text.text()); + return new(c.lifo) AstDataSegment(offset, text.text()); } static bool @@ -2442,7 +2459,7 @@ ParseMemory(WasmParseContext& c, WasmToken token, AstModule* module) while (c.ts.getIf(WasmToken::OpenParen)) { if (!c.ts.match(WasmToken::Segment, c.error)) return false; - AstDataSegment* segment = ParseDataSegment(c); + AstDataSegment* segment = ParseDataSegment(c, /* newFormat = */ false); if (!segment || !module->append(segment)) return false; if (!c.ts.match(WasmToken::CloseParen, c.error)) @@ -2487,7 +2504,7 @@ ParseGlobalType(WasmParseContext& c, WasmToken* typeToken, uint32_t* flags) } static AstImport* -ParseImport(WasmParseContext& c, bool newFormat, AstModule* module) +ParseImport(WasmParseContext& c, AstModule* module) { AstName name = c.ts.getIfName(); @@ -2502,7 +2519,7 @@ ParseImport(WasmParseContext& c, bool newFormat, AstModule* module) AstRef sigRef; WasmToken openParen; if (c.ts.getIf(WasmToken::OpenParen, &openParen)) { - if (newFormat) { + if (c.newFormat) { if (c.ts.getIf(WasmToken::Memory)) { AstResizable memory; if (!ParseResizable(c, &memory)) @@ -2668,7 +2685,7 @@ ParseGlobal(WasmParseContext& c) static AstModule* ParseModule(const char16_t* text, bool newFormat, LifoAlloc& lifo, UniqueChars* error) { - WasmParseContext c(text, lifo, error); + WasmParseContext c(text, lifo, error, newFormat); if (!c.ts.match(WasmToken::OpenParen, c.error)) return nullptr; @@ -2706,13 +2723,13 @@ ParseModule(const char16_t* text, bool newFormat, LifoAlloc& lifo, UniqueChars* break; } case WasmToken::Data: { - AstDataSegment* segment = ParseDataSegment(c); + AstDataSegment* segment = ParseDataSegment(c, newFormat); if (!segment || !module->append(segment)) return nullptr; break; } case WasmToken::Import: { - AstImport* imp = ParseImport(c, newFormat, module); + AstImport* imp = ParseImport(c, module); if (!imp || !module->append(imp)) return nullptr; break; @@ -3190,7 +3207,7 @@ ResolveFunc(Resolver& r, AstFunc& func) } static bool -ResolveModule(LifoAlloc& lifo, AstModule* module, UniqueChars* error) +ResolveModule(LifoAlloc& lifo, bool newFormat, AstModule* module, UniqueChars* error) { Resolver r(lifo, error); @@ -3204,31 +3221,19 @@ ResolveModule(LifoAlloc& lifo, AstModule* module, UniqueChars* error) return r.fail("duplicate signature"); } - size_t numFuncs = module->funcs().length(); - for (size_t i = 0; i < numFuncs; i++) { - AstFunc* func = module->funcs()[i]; - if (!r.resolveSignature(func->sig())) - return false; - if (!r.registerFuncName(func->name(), i)) - return r.fail("duplicate function"); - } - - for (AstElemSegment* seg : module->elemSegments()) { - for (AstRef& ref : seg->elems()) { - if (!r.resolveFunction(ref)) - return false; - } - } - - size_t numImports = module->imports().length(); + size_t lastFuncIndex = 0; size_t lastFuncImportIndex = 0; size_t lastGlobalIndex = 0; - for (size_t i = 0; i < numImports; i++) { - AstImport* imp = module->imports()[i]; + for (AstImport* imp : module->imports()) { switch (imp->kind()) { case DefinitionKind::Function: - if (!r.registerImportName(imp->name(), lastFuncImportIndex++)) - return r.fail("duplicate import"); + if (newFormat) { + if (!r.registerFuncName(imp->name(), lastFuncIndex++)) + return r.fail("duplicate import"); + } else { + if (!r.registerImportName(imp->name(), lastFuncImportIndex++)) + return r.fail("duplicate import"); + } if (!r.resolveSignature(imp->funcSig())) return false; break; @@ -3242,6 +3247,13 @@ ResolveModule(LifoAlloc& lifo, AstModule* module, UniqueChars* error) } } + for (AstFunc* func : module->funcs()) { + if (!r.resolveSignature(func->sig())) + return false; + if (!r.registerFuncName(func->name(), lastFuncIndex++)) + return r.fail("duplicate function"); + } + const AstGlobalVector& globals = module->globals(); for (const AstGlobal* global : globals) { if (!r.registerGlobalName(global->name(), lastGlobalIndex++)) @@ -3276,9 +3288,18 @@ ResolveModule(LifoAlloc& lifo, AstModule* module, UniqueChars* error) return false; } + for (AstDataSegment* segment : module->dataSegments()) { + if (!ResolveExpr(r, *segment->offset())) + return false; + } + for (AstElemSegment* segment : module->elemSegments()) { if (!ResolveExpr(r, *segment->offset())) return false; + for (AstRef& ref : segment->elems()) { + if (!r.resolveFunction(ref)) + return false; + } } return true; @@ -4056,13 +4077,15 @@ EncodeDataSegment(Encoder& e, bool newFormat, AstDataSegment& segment) if (!e.writeVarU32(0)) // linear memory index return false; - if (!e.writeExpr(Expr::I32Const)) + if (!EncodeExpr(e, *segment.offset())) + return false; + if (!e.writeExpr(Expr::End)) + return false; + } else { + if (!e.writeVarU32(segment.offset()->as().val().i32())) return false; } - if (!e.writeVarU32(segment.offset())) - return false; - AstName text = segment.text(); Vector bytes; @@ -4184,13 +4207,13 @@ EncodeModule(AstModule& module, bool newFormat, Bytes* bytes) if (!EncodeStartSection(e, module)) return false; - if (!EncodeCodeSection(e, module)) + if (!EncodeElemSection(e, newFormat, module)) return false; - if (!EncodeDataSection(e, newFormat, module)) + if (!EncodeCodeSection(e, module)) return false; - if (!EncodeElemSection(e, newFormat, module)) + if (!EncodeDataSection(e, newFormat, module)) return false; return true; @@ -4206,7 +4229,7 @@ wasm::TextToBinary(const char16_t* text, bool newFormat, Bytes* bytes, UniqueCha if (!module) return false; - if (!ResolveModule(lifo, module, error)) + if (!ResolveModule(lifo, newFormat, module, error)) return false; return EncodeModule(*module, newFormat, bytes); diff --git a/js/src/asmjs/WasmTypes.h b/js/src/asmjs/WasmTypes.h index 4a151e09d81da..d85de940f18c4 100644 --- a/js/src/asmjs/WasmTypes.h +++ b/js/src/asmjs/WasmTypes.h @@ -84,6 +84,7 @@ using mozilla::Unused; typedef Vector Uint32Vector; class Code; +class CodeRange; class Memory; class Module; class Instance; @@ -775,17 +776,17 @@ WASM_DECLARE_POD_VECTOR(CallSite, CallSiteVector) class CallSiteAndTarget : public CallSite { - uint32_t targetIndex_; + uint32_t funcDefIndex_; public: - CallSiteAndTarget(CallSite cs, uint32_t targetIndex) - : CallSite(cs), targetIndex_(targetIndex) + CallSiteAndTarget(CallSite cs, uint32_t funcDefIndex) + : CallSite(cs), funcDefIndex_(funcDefIndex) { } - static const uint32_t NOT_INTERNAL = UINT32_MAX; + static const uint32_t NOT_DEFINITION = UINT32_MAX; - bool isInternal() const { return targetIndex_ != NOT_INTERNAL; } - uint32_t targetIndex() const { MOZ_ASSERT(isInternal()); return targetIndex_; } + bool isDefinition() const { return funcDefIndex_ != NOT_DEFINITION; } + uint32_t funcDefIndex() const { MOZ_ASSERT(isDefinition()); return funcDefIndex_; } }; typedef Vector CallSiteAndTargetVector; @@ -1059,15 +1060,33 @@ WASM_DECLARE_POD_VECTOR(TableDesc, TableDescVector) class CalleeDesc { public: - // Unlike Builtin, BuilinInstanceMethod expects an implicit Instance* - // as its first argument. (e.g. see Instance::growMemory) - enum Which { Internal, Import, WasmTable, AsmJSTable, Builtin, BuiltinInstanceMethod }; + enum Which { + // Calls a function defined in the same module by its index. + Definition, + + // Calls the import identified by the offset of its FuncImportTls in + // thread-local data. + Import, + + // Calls a WebAssembly table (heterogeneous, index must be bounds + // checked, callee instance depends on TableDesc). + WasmTable, + + // Calls an asm.js table (homogeneous, masked index, same-instance). + AsmJSTable, + + // Call a C++ function identified by SymbolicAddress. + Builtin, + + // Like Builtin, but automatically passes Instance* as first argument. + BuiltinInstanceMethod + }; private: Which which_; union U { U() {} - uint32_t internalFuncIndex_; + uint32_t funcDefIndex_; struct { uint32_t globalDataOffset_; } import; @@ -1080,10 +1099,10 @@ class CalleeDesc public: CalleeDesc() {} - static CalleeDesc internal(uint32_t callee) { + static CalleeDesc definition(uint32_t funcDefIndex) { CalleeDesc c; - c.which_ = Internal; - c.u.internalFuncIndex_ = callee; + c.which_ = Definition; + c.u.funcDefIndex_ = funcDefIndex; return c; } static CalleeDesc import(uint32_t globalDataOffset) { @@ -1120,9 +1139,9 @@ class CalleeDesc Which which() const { return which_; } - uint32_t internalFuncIndex() const { - MOZ_ASSERT(which_ == Internal); - return u.internalFuncIndex_; + uint32_t funcDefIndex() const { + MOZ_ASSERT(which_ == Definition); + return u.funcDefIndex_; } uint32_t importGlobalDataOffset() const { MOZ_ASSERT(which_ == Import); diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 1631909412cf5..74ed0fd2d3bff 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -3425,6 +3425,8 @@ BytecodeEmitter::emitPropIncDec(ParseNode* pn) bool BytecodeEmitter::emitNameIncDec(ParseNode* pn) { + MOZ_ASSERT(pn->pn_kid->isKind(PNK_NAME)); + bool post; JSOp binop = GetIncDecInfo(pn->getKind(), &post); @@ -3648,6 +3650,27 @@ BytecodeEmitter::emitElemIncDec(ParseNode* pn) return true; } +bool +BytecodeEmitter::emitCallIncDec(ParseNode* incDec) +{ + MOZ_ASSERT(incDec->isKind(PNK_PREINCREMENT) || + incDec->isKind(PNK_POSTINCREMENT) || + incDec->isKind(PNK_PREDECREMENT) || + incDec->isKind(PNK_POSTDECREMENT)); + + MOZ_ASSERT(incDec->pn_kid->isKind(PNK_CALL)); + + ParseNode* call = incDec->pn_kid; + if (!emitTree(call)) // CALLRESULT + return false; + if (!emit1(JSOP_POS)) // N + return false; + + // The increment/decrement has no side effects, so proceed to throw for + // invalid assignment target. + return emitUint16Operand(JSOP_THROWMSG, JSMSG_BAD_LEFTSIDE_OF_ASS); +} + bool BytecodeEmitter::emitNumberOp(double dval) { @@ -4418,17 +4441,9 @@ BytecodeEmitter::emitDestructuringLHS(ParseNode* target, DestructuringFlavor fla } case PNK_CALL: - MOZ_ASSERT(target->pn_xflags & PNX_SETCALL); - if (!emitTree(target)) - return false; - - // Pop the call return value. Below, we pop the RHS too, balancing - // the stack --- presumably for the benefit of bytecode - // analysis. (The interpreter will never reach these instructions - // since we just emitted JSOP_SETCALL, which always throws. It's - // possible no analyses actually depend on this either.) - if (!emit1(JSOP_POP)) - return false; + MOZ_ASSERT_UNREACHABLE("Parser::reportIfNotValidSimpleAssignmentTarget " + "rejects function calls as assignment " + "targets in destructuring assignments"); break; default: @@ -4944,9 +4959,15 @@ BytecodeEmitter::emitAssignment(ParseNode* lhs, JSOp op, ParseNode* rhs) case PNK_OBJECT: break; case PNK_CALL: - MOZ_ASSERT(lhs->pn_xflags & PNX_SETCALL); if (!emitTree(lhs)) return false; + + // Assignment to function calls is forbidden, but we have to make the + // call first. Now we can throw. + if (!emitUint16Operand(JSOP_THROWMSG, JSMSG_BAD_LEFTSIDE_OF_ASS)) + return false; + + // Rebalance the stack to placate stack-depth assertions. if (!emit1(JSOP_POP)) return false; break; @@ -4993,12 +5014,9 @@ BytecodeEmitter::emitAssignment(ParseNode* lhs, JSOp op, ParseNode* rhs) break; } case PNK_CALL: - /* - * We just emitted a JSOP_SETCALL (which will always throw) and - * popped the call's return value. Push a random value to make sure - * the stack depth is correct. - */ - MOZ_ASSERT(lhs->pn_xflags & PNX_SETCALL); + // We just emitted a JSOP_THROWMSG and popped the call's return + // value. Push a random value to make sure the stack depth is + // correct. if (!emit1(JSOP_NULL)) return false; break; @@ -5028,8 +5046,7 @@ BytecodeEmitter::emitAssignment(ParseNode* lhs, JSOp op, ParseNode* rhs) break; } case PNK_CALL: - /* Do nothing. The JSOP_SETCALL we emitted will always throw. */ - MOZ_ASSERT(lhs->pn_xflags & PNX_SETCALL); + // We threw above, so nothing to do here. break; case PNK_ELEM: { JSOp setOp = lhs->as().isSuper() ? @@ -7527,7 +7544,6 @@ BytecodeEmitter::emitDeleteExpression(ParseNode* node) return false; if (useful) { - MOZ_ASSERT_IF(expression->isKind(PNK_CALL), !(expression->pn_xflags & PNX_SETCALL)); if (!emitTree(expression)) return false; if (!emit1(JSOP_POP)) @@ -7787,9 +7803,6 @@ BytecodeEmitter::emitCallOrNew(ParseNode* pn) switch (pn2->getKind()) { case PNK_NAME: if (emitterMode == BytecodeEmitter::SelfHosting && !spread) { - // We shouldn't see foo(bar) = x in self-hosted code. - MOZ_ASSERT(!(pn->pn_xflags & PNX_SETCALL)); - // Calls to "forceInterpreter", "callFunction", // "callContentFunction", or "resumeGenerator" in self-hosted // code generate inline bytecode. @@ -7953,10 +7966,6 @@ BytecodeEmitter::emitCallOrNew(ParseNode* pn) if (!emitUint32Operand(JSOP_LINENO, lineNum)) return false; } - if (pn->pn_xflags & PNX_SETCALL) { - if (!emitUint16Operand(JSOP_THROWMSG, JSMSG_BAD_LEFTSIDE_OF_ASS)) - return false; - } return true; } @@ -8065,18 +8074,14 @@ BytecodeEmitter::emitSequenceExpr(ParseNode* pn) MOZ_NEVER_INLINE bool BytecodeEmitter::emitIncOrDec(ParseNode* pn) { - /* Emit lvalue-specialized code for ++/-- operators. */ - ParseNode* pn2 = pn->pn_kid; - switch (pn2->getKind()) { + switch (pn->pn_kid->getKind()) { case PNK_DOT: return emitPropIncDec(pn); case PNK_ELEM: return emitElemIncDec(pn); case PNK_CALL: - MOZ_ASSERT(pn2->pn_xflags & PNX_SETCALL); - return emitTree(pn2); + return emitCallIncDec(pn); default: - MOZ_ASSERT(pn2->isKind(PNK_NAME)); return emitNameIncDec(pn); } diff --git a/js/src/frontend/BytecodeEmitter.h b/js/src/frontend/BytecodeEmitter.h index 1c5fa7d77f693..584bb6bc7b5a3 100644 --- a/js/src/frontend/BytecodeEmitter.h +++ b/js/src/frontend/BytecodeEmitter.h @@ -501,6 +501,7 @@ struct MOZ_STACK_CLASS BytecodeEmitter MOZ_MUST_USE bool emitJumpTargetAndPatch(JumpList jump); MOZ_MUST_USE bool emitCall(JSOp op, uint16_t argc, ParseNode* pn = nullptr); + MOZ_MUST_USE bool emitCallIncDec(ParseNode* incDec); MOZ_MUST_USE bool emitLoopHead(ParseNode* nextpn, JumpTarget* top); MOZ_MUST_USE bool emitLoopEntry(ParseNode* nextpn, JumpList entryJump); diff --git a/js/src/frontend/FullParseHandler.h b/js/src/frontend/FullParseHandler.h index 28ae341b1a484..b2a2f66c3b866 100644 --- a/js/src/frontend/FullParseHandler.h +++ b/js/src/frontend/FullParseHandler.h @@ -196,10 +196,6 @@ class FullParseHandler return new_(cond, thenExpr, elseExpr); } - void markAsSetCall(ParseNode* pn) { - pn->pn_xflags |= PNX_SETCALL; - } - ParseNode* newDelete(uint32_t begin, ParseNode* expr) { if (expr->isKind(PNK_NAME)) { expr->setOp(JSOP_DELNAME); diff --git a/js/src/frontend/ParseNode.h b/js/src/frontend/ParseNode.h index 371722708a5a9..f008a1a7c1650 100644 --- a/js/src/frontend/ParseNode.h +++ b/js/src/frontend/ParseNode.h @@ -621,11 +621,10 @@ class ParseNode /* PN_LIST pn_xflags bits. */ #define PNX_FUNCDEFS 0x01 /* contains top-level function statements */ -#define PNX_SETCALL 0x02 /* call expression in lvalue context */ -#define PNX_ARRAYHOLESPREAD 0x04 /* one or more of +#define PNX_ARRAYHOLESPREAD 0x02 /* one or more of 1. array initialiser has holes 2. array initializer has spread node */ -#define PNX_NONCONST 0x08 /* initialiser has non-constants */ +#define PNX_NONCONST 0x04 /* initialiser has non-constants */ bool functionIsHoisted() const { MOZ_ASSERT(pn_arity == PN_CODE && getKind() == PNK_FUNCTION); diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index fa9c62f6a3448..85ae7f03bd0f0 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -3741,7 +3741,7 @@ Parser::PossibleError::transferErrorTo(PossibleError* other) template bool -Parser::makeSetCall(Node target, unsigned msg) +Parser::checkAssignmentToCall(Node target, unsigned msg) { MOZ_ASSERT(handler.isFunctionCall(target)); @@ -3749,11 +3749,7 @@ Parser::makeSetCall(Node target, unsigned msg) // concerned about sites using this in dead code, so forbid it only in // strict mode code (or if the werror option has been set), and otherwise // warn. - if (!report(ParseStrictError, pc->sc()->strict(), target, msg)) - return false; - - handler.markAsSetCall(target); - return true; + return report(ParseStrictError, pc->sc()->strict(), target, msg); } template <> @@ -5046,7 +5042,7 @@ Parser::validateForInOrOfLHSExpression(Node target) } if (handler.isFunctionCall(target)) - return makeSetCall(target, JSMSG_BAD_FOR_LEFTSIDE); + return checkAssignmentToCall(target, JSMSG_BAD_FOR_LEFTSIDE); report(ParseError, false, target, JSMSG_BAD_FOR_LEFTSIDE); return false; @@ -7163,7 +7159,7 @@ Parser::checkAndMarkAsAssignmentLhs(Node target, AssignmentFlavor } MOZ_ASSERT(handler.isFunctionCall(target)); - return makeSetCall(target, JSMSG_BAD_LEFTSIDE_OF_ASS); + return checkAssignmentToCall(target, JSMSG_BAD_LEFTSIDE_OF_ASS); } class AutoClearInDestructuringDecl @@ -7483,7 +7479,7 @@ Parser::checkAndMarkAsIncOperand(Node target, AssignmentFlavor fla if (!reportIfArgumentsEvalTarget(target)) return false; } else if (handler.isFunctionCall(target)) { - if (!makeSetCall(target, JSMSG_BAD_INCOP_OPERAND)) + if (!checkAssignmentToCall(target, JSMSG_BAD_INCOP_OPERAND)) return false; } return true; diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index a08ae0f0c0494..73cc9b527716b 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -1319,7 +1319,7 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter bool checkDestructuringObject(Node objectPattern, mozilla::Maybe maybeDecl); bool checkDestructuringName(Node expr, mozilla::Maybe maybeDecl); - bool makeSetCall(Node node, unsigned errnum); + bool checkAssignmentToCall(Node node, unsigned errnum); Node newNumber(const Token& tok) { return handler.newNumber(tok.number(), tok.decimalPoint(), tok.pos); diff --git a/js/src/frontend/SyntaxParseHandler.h b/js/src/frontend/SyntaxParseHandler.h index 89c8d36391f60..cc633bbf4f862 100644 --- a/js/src/frontend/SyntaxParseHandler.h +++ b/js/src/frontend/SyntaxParseHandler.h @@ -219,10 +219,6 @@ class SyntaxParseHandler Node newElision() { return NodeGeneric; } - void markAsSetCall(Node node) { - MOZ_ASSERT(node == NodeFunctionCall); - } - Node newDelete(uint32_t begin, Node expr) { return NodeGeneric; } diff --git a/js/src/gc/GCRuntime.h b/js/src/gc/GCRuntime.h index 45efc02291722..767600cd23a73 100644 --- a/js/src/gc/GCRuntime.h +++ b/js/src/gc/GCRuntime.h @@ -946,6 +946,7 @@ class GCRuntime bool shouldPreserveJITCode(JSCompartment* comp, int64_t currentTime, JS::gcreason::Reason reason); void traceRuntimeForMajorGC(JSTracer* trc, AutoLockForExclusiveAccess& lock); + void traceRuntimeAtoms(JSTracer* trc, AutoLockForExclusiveAccess& lock); void traceRuntimeCommon(JSTracer* trc, TraceOrMarkRuntime traceOrMark, AutoLockForExclusiveAccess& lock); void bufferGrayRoots(); diff --git a/js/src/gc/RootMarking.cpp b/js/src/gc/RootMarking.cpp index 0b64e6dbc6454..bf0322570f7fc 100644 --- a/js/src/gc/RootMarking.cpp +++ b/js/src/gc/RootMarking.cpp @@ -274,12 +274,33 @@ PropertyDescriptor::trace(JSTracer* trc) void js::gc::GCRuntime::traceRuntimeForMajorGC(JSTracer* trc, AutoLockForExclusiveAccess& lock) { + // FinishRoots will have asserted that every root that we do not expect + // is gone, so we can simply skip traceRuntime here. + if (rt->isBeingDestroyed()) + return; + + gcstats::AutoPhase ap(stats, gcstats::PHASE_MARK_ROOTS); + if (rt->atomsCompartment(lock)->zone()->isCollecting()) + traceRuntimeAtoms(trc, lock); + JSCompartment::traceIncomingCrossCompartmentEdgesForZoneGC(trc); traceRuntimeCommon(trc, MarkRuntime, lock); } void js::gc::GCRuntime::traceRuntimeForMinorGC(JSTracer* trc, AutoLockForExclusiveAccess& lock) { + // Note that we *must* trace the runtime during the SHUTDOWN_GC's minor GC + // despite having called FinishRoots already. This is because FinishRoots + // does not clear the crossCompartmentWrapper map. It cannot do this + // because Proxy's trace for CrossCompartmentWrappers asserts presence in + // the map. And we can reach its trace function despite having finished the + // roots via the edges stored by the pre-barrier verifier when we finish + // the verifier for the last time. + gcstats::AutoPhase ap(stats, gcstats::PHASE_MARK_ROOTS); + + // FIXME: As per bug 1298816 comment 12, we should be able to remove this. + jit::JitRuntime::MarkJitcodeGlobalTableUnconditionally(trc); + traceRuntimeCommon(trc, TraceRuntime, lock); } @@ -298,57 +319,53 @@ js::TraceRuntime(JSTracer* trc) void js::gc::GCRuntime::traceRuntime(JSTracer* trc, AutoLockForExclusiveAccess& lock) { + MOZ_ASSERT(!rt->isBeingDestroyed()); + + gcstats::AutoPhase ap(stats, gcstats::PHASE_MARK_ROOTS); + traceRuntimeAtoms(trc, lock); traceRuntimeCommon(trc, TraceRuntime, lock); } +void +js::gc::GCRuntime::traceRuntimeAtoms(JSTracer* trc, AutoLockForExclusiveAccess& lock) +{ + gcstats::AutoPhase ap(stats, gcstats::PHASE_MARK_RUNTIME_DATA); + MarkPermanentAtoms(trc); + MarkAtoms(trc, lock); + MarkWellKnownSymbols(trc); + jit::JitRuntime::Mark(trc, lock); +} + void js::gc::GCRuntime::traceRuntimeCommon(JSTracer* trc, TraceOrMarkRuntime traceOrMark, AutoLockForExclusiveAccess& lock) { - gcstats::AutoPhase ap(stats, gcstats::PHASE_MARK_ROOTS); - MOZ_ASSERT(!rt->mainThread.suppressGC); - // Trace incoming CCW edges. - if (traceOrMark == MarkRuntime) { - gcstats::AutoPhase ap(stats, gcstats::PHASE_MARK_CCWS); - JSCompartment::traceIncomingCrossCompartmentEdgesForZoneGC(trc); - } - - // Trace C stack roots. { - gcstats::AutoPhase ap(stats, gcstats::PHASE_MARK_ROOTERS); + gcstats::AutoPhase ap(stats, gcstats::PHASE_MARK_STACK); - AutoGCRooter::traceAll(trc); + // Trace active interpreter and JIT stack roots. + MarkInterpreterActivations(rt, trc); + jit::MarkJitActivations(rt, trc); - if (!rt->isBeingDestroyed()) { - MarkExactStackRoots(rt, trc); - rt->markSelfHostingGlobal(trc); - } + // Trace legacy C stack roots. + AutoGCRooter::traceAll(trc); for (RootRange r = rootsHash.all(); !r.empty(); r.popFront()) { const RootEntry& entry = r.front(); TraceRoot(trc, entry.key(), entry.value()); } - MarkPersistentRooted(rt, trc); + // Trace C stack roots. + MarkExactStackRoots(rt, trc); } - // Trace the atoms Compartment. - if (!rt->isBeingDestroyed() && !rt->isHeapMinorCollecting()) { - gcstats::AutoPhase ap(stats, gcstats::PHASE_MARK_RUNTIME_DATA); + // Trace runtime global roots. + MarkPersistentRooted(rt, trc); - if (traceOrMark == TraceRuntime || rt->atomsCompartment(lock)->zone()->isCollecting()) { - MarkPermanentAtoms(trc); - MarkAtoms(trc, lock); - MarkWellKnownSymbols(trc); - jit::JitRuntime::Mark(trc, lock); - } - } - - // This table is weak in major GC's. - if (rt->isHeapMinorCollecting()) - jit::JitRuntime::MarkJitcodeGlobalTableUnconditionally(trc); + // Trace the self-hosting global compartment. + rt->markSelfHostingGlobal(trc); // Trace anything in the single context. Note that this is actually the // same struct as the JSRuntime, but is still split for historical reasons. @@ -359,14 +376,10 @@ js::gc::GCRuntime::traceRuntimeCommon(JSTracer* trc, TraceOrMarkRuntime traceOrM for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) c->traceRoots(trc, traceOrMark); - // Trace JS stack roots. - MarkInterpreterActivations(rt, trc); - jit::MarkJitActivations(rt, trc); - // Trace SPS. rt->spsProfiler.trace(trc); - // Trace the embeddings black and gray roots. + // Trace the embedding's black and gray roots. if (!rt->isHeapMinorCollecting()) { gcstats::AutoPhase ap(stats, gcstats::PHASE_MARK_EMBEDDING); diff --git a/js/src/gc/Statistics.cpp b/js/src/gc/Statistics.cpp index e7ca2cc4c8526..b83e050f42f3b 100644 --- a/js/src/gc/Statistics.cpp +++ b/js/src/gc/Statistics.cpp @@ -180,7 +180,7 @@ static const PhaseInfo phases[] = { { PHASE_MARK_ROOTS, "Mark Roots", PHASE_MULTI_PARENTS, 48 }, { PHASE_BUFFER_GRAY_ROOTS, "Buffer Gray Roots", PHASE_MARK_ROOTS, 49 }, { PHASE_MARK_CCWS, "Mark Cross Compartment Wrappers", PHASE_MARK_ROOTS, 50 }, - { PHASE_MARK_ROOTERS, "Mark Rooters", PHASE_MARK_ROOTS, 51 }, + { PHASE_MARK_STACK, "Mark C and JS stacks", PHASE_MARK_ROOTS, 51 }, { PHASE_MARK_RUNTIME_DATA, "Mark Runtime-wide Data", PHASE_MARK_ROOTS, 52 }, { PHASE_MARK_EMBEDDING, "Mark Embedding", PHASE_MARK_ROOTS, 53 }, { PHASE_MARK_COMPARTMENTS, "Mark Compartments", PHASE_MARK_ROOTS, 54 }, diff --git a/js/src/gc/Statistics.h b/js/src/gc/Statistics.h index 3e562a39a2e2c..bac94b7baf91b 100644 --- a/js/src/gc/Statistics.h +++ b/js/src/gc/Statistics.h @@ -81,7 +81,7 @@ enum Phase : uint8_t { PHASE_MARK_ROOTS, PHASE_BUFFER_GRAY_ROOTS, PHASE_MARK_CCWS, - PHASE_MARK_ROOTERS, + PHASE_MARK_STACK, PHASE_MARK_RUNTIME_DATA, PHASE_MARK_EMBEDDING, PHASE_MARK_COMPARTMENTS, diff --git a/js/src/gc/Verifier.cpp b/js/src/gc/Verifier.cpp index 50260fcd42fee..c681860d2cbd1 100644 --- a/js/src/gc/Verifier.cpp +++ b/js/src/gc/Verifier.cpp @@ -509,7 +509,8 @@ CheckHeapTracer::check(AutoLockForExclusiveAccess& lock) { // The analysis thinks that traceRuntime might GC by calling a GC callback. JS::AutoSuppressGCAnalysis nogc; - rt->gc.traceRuntime(this, lock); + if (!rt->isBeingDestroyed()) + rt->gc.traceRuntime(this, lock); while (!stack.empty()) { WorkItem item = stack.back(); diff --git a/js/src/jit-test/tests/arrays/reverse-frozen.js b/js/src/jit-test/tests/arrays/reverse-frozen.js new file mode 100644 index 0000000000000..d2f32b78d2f4c --- /dev/null +++ b/js/src/jit-test/tests/arrays/reverse-frozen.js @@ -0,0 +1,6 @@ +// |jit-test| error: TypeError + +x = [0]; +x.length = 9; +Object.freeze(x); +x.reverse(); diff --git a/js/src/jit-test/tests/wasm/basic.js b/js/src/jit-test/tests/wasm/basic.js index 6c349518347d0..42e3314fd6080 100644 --- a/js/src/jit-test/tests/wasm/basic.js +++ b/js/src/jit-test/tests/wasm/basic.js @@ -445,9 +445,9 @@ assertErrorMessage(() => i2v(5), Error, badIndirectCall); `(module (type $v2v (func)) (import $foo "f" "") - (func (call_import $foo)) - (func (result i32) (i32.const 0)) - (table 0 1) + (func $a (call_import $foo)) + (func $b (result i32) (i32.const 0)) + (table $a $b) (func $bar (call_indirect $v2v (i32.const 0))) (export "" $bar) )`, diff --git a/js/src/jit-test/tests/wasm/import-export.js b/js/src/jit-test/tests/wasm/import-export.js index 2c912205f6417..96e1c8b9693e0 100644 --- a/js/src/jit-test/tests/wasm/import-export.js +++ b/js/src/jit-test/tests/wasm/import-export.js @@ -303,6 +303,21 @@ assertEq(e1.foo, tbl.get(1)); assertEq(tbl.get(0) === e1.foo, false); assertEq(e1.foo === e2.foo, false); +var code = textToBinary('(module (table (resizable 2 2)) (import $foo "a" "b" (result i32)) (func $bar (result i32) (i32.const 13)) (elem (i32.const 0) $foo $bar) (export "foo" $foo) (export "bar" $bar) (export "tbl" table))'); +var foo = new Instance(new Module(textToBinary('(module (func (result i32) (i32.const 42)) (export "foo" 0))'))).exports.foo; +var e1 = new Instance(new Module(code), {a:{b:foo}}).exports; +assertEq(foo, e1.foo); +assertEq(foo, e1.tbl.get(0)); +assertEq(e1.bar, e1.tbl.get(1)); +assertEq(e1.tbl.get(0)(), 42); +assertEq(e1.tbl.get(1)(), 13); +var e2 = new Instance(new Module(code), {a:{b:foo}}).exports; +assertEq(e1.foo, e2.foo); +assertEq(e1.bar === e2.bar, false); +assertEq(e1.tbl === e2.tbl, false); +assertEq(e1.tbl.get(0), e2.tbl.get(0)); +assertEq(e1.tbl.get(1) === e2.tbl.get(1), false); + // i64 is fully allowed for imported wasm functions var code1 = textToBinary('(module (func $exp (param i64) (result i64) (i64.add (get_local 0) (i64.const 10))) (export "exp" $exp))'); @@ -352,6 +367,60 @@ assertEq(i8[100], 0xc); assertEq(i8[101], 0xd); assertEq(i8[102], 0x0); +// Data segments with imported offsets + +var m = new Module(textToBinary(` + (module + (import "glob" "a" (global i32 immutable)) + (memory 1) + (data (get_global 0) "\\0a\\0b")) +`)); +assertEq(new Instance(m, {glob:{a:0}}) instanceof Instance, true); +assertEq(new Instance(m, {glob:{a:(64*1024 - 2)}}) instanceof Instance, true); +assertErrorMessage(() => new Instance(m, {glob:{a:(64*1024 - 1)}}), RangeError, /data segment does not fit/); +assertErrorMessage(() => new Instance(m, {glob:{a:64*1024}}), RangeError, /data segment does not fit/); + +// Errors during segment initialization do not have observable effects +// and are checked against the actual memory/table length, not the declared +// initial length. + +var m = new Module(textToBinary(` + (module + (import "a" "mem" (memory 1)) + (import "a" "tbl" (table 1)) + (import $memOff "a" "memOff" (global i32 immutable)) + (import $tblOff "a" "tblOff" (global i32 immutable)) + (func $f) + (func $g) + (data (i32.const 0) "\\01") + (elem (i32.const 0) $f) + (data (get_global $memOff) "\\02") + (elem (get_global $tblOff) $g) + (export "f" $f) + (export "g" $g)) +`)); + +var npages = 2; +var mem = new Memory({initial:npages}); +var mem8 = new Uint8Array(mem.buffer); +var tbl = new Table({initial:2, element:"anyfunc"}); + +assertErrorMessage(() => new Instance(m, {a:{mem, tbl, memOff:1, tblOff:2}}), RangeError, /elem segment does not fit/); +assertEq(mem8[0], 0); +assertEq(mem8[1], 0); +assertEq(tbl.get(0), null); + +assertErrorMessage(() => new Instance(m, {a:{mem, tbl, memOff:npages*64*1024, tblOff:1}}), RangeError, /data segment does not fit/); +assertEq(mem8[0], 0); +assertEq(tbl.get(0), null); +assertEq(tbl.get(1), null); + +var i = new Instance(m, {a:{mem, tbl, memOff:npages*64*1024-1, tblOff:1}}); +assertEq(mem8[0], 1); +assertEq(mem8[npages*64*1024-1], 2); +assertEq(tbl.get(0), i.exports.f); +assertEq(tbl.get(1), i.exports.g); + // Elem segments on imports var m = new Module(textToBinary(` @@ -377,9 +446,29 @@ for (var i = 5; i < 10; i++) // Cross-instance calls var i1 = new Instance(new Module(textToBinary(`(module (func) (func (param i32) (result i32) (i32.add (get_local 0) (i32.const 1))) (func) (export "f" 1))`))); -var i2 = new Instance(new Module(textToBinary(`(module (import "a" "b" (param i32) (result i32)) (func $g (result i32) (call_import 0 (i32.const 13))) (export "g" $g))`)), {a:{b:i1.exports.f}}); +var i2 = new Instance(new Module(textToBinary(`(module (import $imp "a" "b" (param i32) (result i32)) (func $g (result i32) (call $imp (i32.const 13))) (export "g" $g))`)), {a:{b:i1.exports.f}}); assertEq(i2.exports.g(), 14); +var i1 = new Instance(new Module(textToBinary(`(module + (memory 1 1) + (data (i32.const 0) "\\42") + (func $f (result i32) (i32.load (i32.const 0))) + (export "f" $f) +)`))); +var i2 = new Instance(new Module(textToBinary(`(module + (import $imp "a" "b" (result i32)) + (memory 1 1) + (data (i32.const 0) "\\13") + (table (resizable 2 2)) + (elem (i32.const 0) $imp $def) + (func $def (result i32) (i32.load (i32.const 0))) + (type $v2i (func (result i32))) + (func $call (param i32) (result i32) (call_indirect $v2i (get_local 0))) + (export "call" $call) +)`)), {a:{b:i1.exports.f}}); +assertEq(i2.exports.call(0), 0x42); +assertEq(i2.exports.call(1), 0x13); + var m = new Module(textToBinary(`(module (import $val "a" "val" (global i32 immutable)) (import $next "a" "next" (result i32)) @@ -391,7 +480,7 @@ var m = new Module(textToBinary(`(module (get_global $val) (i32.add (i32.load (i32.const 0)) - (call_import $next)))) + (call $next)))) (export "call" $call) )`)); var e = {call:() => 1000}; diff --git a/js/src/jit-test/tests/wasm/import-gc.js b/js/src/jit-test/tests/wasm/import-gc.js index cf0ab501bccb0..61bd07d24b78d 100644 --- a/js/src/jit-test/tests/wasm/import-gc.js +++ b/js/src/jit-test/tests/wasm/import-gc.js @@ -12,8 +12,8 @@ const Instance = WebAssembly.Instance; // is used by default everywhere. const textToBinary = str => wasmTextToBinary(str, 'new-format'); -const m1 = new Module(textToBinary(`(module (func) (export "f" 0))`)); -const m2 = new Module(textToBinary(`(module (import "a" "f") (func) (export "g" 0))`)); +const m1 = new Module(textToBinary(`(module (func $f) (export "f" $f))`)); +const m2 = new Module(textToBinary(`(module (import "a" "f") (func $f) (export "g" $f))`)); // Imported instance objects should stay alive as long as any importer is alive. resetFinalizeCount(); diff --git a/js/src/jit-test/tests/wasm/jsapi.js b/js/src/jit-test/tests/wasm/jsapi.js index f329311ee47ec..ee0c0ffb67606 100644 --- a/js/src/jit-test/tests/wasm/jsapi.js +++ b/js/src/jit-test/tests/wasm/jsapi.js @@ -254,10 +254,10 @@ assertErrorMessage(() => set.call(tbl1, 0), TypeError, /requires more than 1 arg assertErrorMessage(() => set.call(tbl1, 2, null), RangeError, /out-of-range index/); assertErrorMessage(() => set.call(tbl1, -1, null), RangeError, /out-of-range index/); assertErrorMessage(() => set.call(tbl1, Math.pow(2,33), null), RangeError, /out-of-range index/); -assertErrorMessage(() => set.call(tbl1, 0, undefined), TypeError, /second argument must be null or an exported WebAssembly Function object/); -assertErrorMessage(() => set.call(tbl1, 0, {}), TypeError, /second argument must be null or an exported WebAssembly Function object/); -assertErrorMessage(() => set.call(tbl1, 0, function() {}), TypeError, /second argument must be null or an exported WebAssembly Function object/); -assertErrorMessage(() => set.call(tbl1, 0, Math.sin), TypeError, /second argument must be null or an exported WebAssembly Function object/); +assertErrorMessage(() => set.call(tbl1, 0, undefined), TypeError, /can only assign WebAssembly exported functions to Table/); +assertErrorMessage(() => set.call(tbl1, 0, {}), TypeError, /can only assign WebAssembly exported functions to Table/); +assertErrorMessage(() => set.call(tbl1, 0, function() {}), TypeError, /can only assign WebAssembly exported functions to Table/); +assertErrorMessage(() => set.call(tbl1, 0, Math.sin), TypeError, /can only assign WebAssembly exported functions to Table/); assertErrorMessage(() => set.call(tbl1, {valueOf() { throw Error("hai") }}, null), Error, "hai"); assertEq(set.call(tbl1, 0, null), undefined); assertEq(set.call(tbl1, 1, null), undefined); diff --git a/js/src/jit-test/tests/wasm/profiling.js b/js/src/jit-test/tests/wasm/profiling.js index c9d10bd573ee0..b4625758361df 100644 --- a/js/src/jit-test/tests/wasm/profiling.js +++ b/js/src/jit-test/tests/wasm/profiling.js @@ -189,7 +189,7 @@ Error); )`)); var m2 = new Module(textToBinary(`(module (import $foo "a" "foo" (result i32)) - (func $bar (result i32) (call_import $foo)) + (func $bar (result i32) (call $foo)) (export "bar" $bar) )`)); diff --git a/js/src/jit-test/tests/wasm/spec/func_ptrs.wast b/js/src/jit-test/tests/wasm/spec/func_ptrs.wast index c63d78e24b65d..e39214c2ff5c6 100644 --- a/js/src/jit-test/tests/wasm/spec/func_ptrs.wast +++ b/js/src/jit-test/tests/wasm/spec/func_ptrs.wast @@ -78,7 +78,7 @@ (module (type $T (func (result i32))) - (table 0 1) + (table $t1 $t2) (import $print_i32 "spectest" "print" (param i32)) diff --git a/js/src/jit-test/tests/wasm/spec/memory.wast b/js/src/jit-test/tests/wasm/spec/memory.wast index 9b0c5fae3366a..9c8a2ac160eb6 100644 --- a/js/src/jit-test/tests/wasm/spec/memory.wast +++ b/js/src/jit-test/tests/wasm/spec/memory.wast @@ -19,18 +19,6 @@ (module (memory 1 2 (segment 0 "a") (segment 98304 "b"))) "data segment does not fit memory" ) -(assert_invalid - (module (memory 1 2 (segment 0 "abc") (segment 0 "def"))) - "data segment not disjoint and ordered" -) -(assert_invalid - (module (memory 1 2 (segment 3 "ab") (segment 0 "de"))) - "data segment not disjoint and ordered" -) -(assert_invalid - (module (memory 1 2 (segment 0 "a") (segment 2 "b") (segment 1 "c"))) - "data segment not disjoint and ordered" -) ;; Test alignment annotation rules ;; TODO Tests being debated on the spec repo. diff --git a/js/src/jit-test/tests/wasm/spec/start.wast b/js/src/jit-test/tests/wasm/spec/start.wast index 042f98f0dacb5..dd51b256bb8fd 100644 --- a/js/src/jit-test/tests/wasm/spec/start.wast +++ b/js/src/jit-test/tests/wasm/spec/start.wast @@ -64,7 +64,7 @@ (call $inc) (call $inc) ) - (start 2) + (start $main) (export "inc" $inc) (export "get" $get) ) @@ -78,7 +78,7 @@ (import $print_i32 "spectest" "print" (param i32)) (func $main (call_import $print_i32 (i32.const 1))) - (start 0) + (start $main) ) (module diff --git a/js/src/jit-test/tests/wasm/start.js b/js/src/jit-test/tests/wasm/start.js index 8217e201529bc..e0741877be188 100644 --- a/js/src/jit-test/tests/wasm/start.js +++ b/js/src/jit-test/tests/wasm/start.js @@ -14,7 +14,7 @@ assertErrorMessage(() => wasmEvalText('(module (func (result f32)) (start 0))'), // Basic use case. var count = 0; function inc() { count++; } -var exports = wasmEvalText(`(module (import "inc" "") (func (param i32)) (func (call_import 0)) (start 1))`, { inc }); +var exports = wasmEvalText(`(module (import $imp "inc" "") (func $f (param i32)) (func (call_import $imp)) (start $f))`, { inc }); assertEq(count, 1); assertEq(Object.keys(exports).length, 0); @@ -31,7 +31,7 @@ const Instance = WebAssembly.Instance; const textToBinary = str => wasmTextToBinary(str, 'new-format'); count = 0; -const m = new Module(textToBinary('(module (import "inc" "") (func) (func (call_import 0)) (start 1) (export "" 1))')); +const m = new Module(textToBinary('(module (import $imp "inc" "") (func) (func $start (call $imp)) (start $start) (export "" $start))')); assertEq(count, 0); assertErrorMessage(() => new Instance(m), TypeError, /no import object given/); @@ -44,3 +44,11 @@ assertEq(count, 2); const i2 = new Instance(m, { inc }); assertEq(count, 3); + +function fail() { assertEq(true, false); } + +count = 0; +const m2 = new Module(textToBinary('(module (import "fail" "") (import $imp "inc" "") (func) (start $imp))')); +assertEq(count, 0); +new Instance(m2, { inc, fail }); +assertEq(count, 1); diff --git a/js/src/jit-test/tests/wasm/table-gc.js b/js/src/jit-test/tests/wasm/table-gc.js index 8f9f6ca7bd0f0..22048cb523f37 100644 --- a/js/src/jit-test/tests/wasm/table-gc.js +++ b/js/src/jit-test/tests/wasm/table-gc.js @@ -202,8 +202,8 @@ function runTest() { } var i = evalText( `(module - (import "a" "b" (result i32)) - (func $f (param i32) (result i32) (call_import 0)) + (import $imp "a" "b" (result i32)) + (func $f (param i32) (result i32) (call $imp)) (export "f" $f) )`, {a:{b:runTest}} diff --git a/js/src/jit-test/tests/wasm/tables.js b/js/src/jit-test/tests/wasm/tables.js index 441c953e3878e..fc9d5d6f235cb 100644 --- a/js/src/jit-test/tests/wasm/tables.js +++ b/js/src/jit-test/tests/wasm/tables.js @@ -22,21 +22,25 @@ assertErrorMessage(() => new Module(textToBinary(`(module (table (resizable 10)) assertErrorMessage(() => new Module(textToBinary(`(module (table (resizable 10)) (elem (i32.const 10) $f0) ${callee(0)})`)), TypeError, /element segment does not fit/); assertErrorMessage(() => new Module(textToBinary(`(module (table (resizable 10)) (elem (i32.const 8) $f0 $f0 $f0) ${callee(0)})`)), TypeError, /element segment does not fit/); -assertErrorMessage(() => new Module(textToBinary(`(module (table (resizable 10)) (elem (i32.const 1) $f0 $f0) (elem (i32.const 0) $f0) ${callee(0)})`)), TypeError, /must be.*ordered/); -assertErrorMessage(() => new Module(textToBinary(`(module (table (resizable 10)) (elem (i32.const 1) $f0 $f0) (elem (i32.const 2) $f0) ${callee(0)})`)), TypeError, /must be.*disjoint/); - -assertErrorMessage(() => evalText(`(module (table (resizable 10)) (import "globals" "a" (global i32 immutable)) (elem (get_global 0) $f0) ${callee(0)})`, {globals:{a:10}}), TypeError, /element segment does not fit/); -assertErrorMessage(() => evalText(`(module (table (resizable 10)) (import "globals" "a" (global i32 immutable)) (elem (get_global 0) $f0 $f0 $f0) ${callee(0)})`, {globals:{a:8}}), TypeError, /element segment does not fit/); -assertErrorMessage(() => evalText(`(module (table (resizable 10)) (import "globals" "a" (global i32 immutable)) (elem (i32.const 1) $f0 $f0) (elem (get_global 0) $f0) ${callee(0)})`, {globals:{a:0}}), TypeError, /must be.*ordered/); -assertErrorMessage(() => evalText(`(module (table (resizable 10)) (import "globals" "a" (global i32 immutable)) (elem (get_global 0) $f0 $f0) (elem (i32.const 2) $f0) ${callee(0)})`, {globals:{a:1}}), TypeError, /must be.*disjoint/); +assertErrorMessage(() => evalText(`(module (table (resizable 10)) (import "globals" "a" (global i32 immutable)) (elem (get_global 0) $f0) ${callee(0)})`, {globals:{a:10}}), RangeError, /elem segment does not fit/); +assertErrorMessage(() => evalText(`(module (table (resizable 10)) (import "globals" "a" (global i32 immutable)) (elem (get_global 0) $f0 $f0 $f0) ${callee(0)})`, {globals:{a:8}}), RangeError, /elem segment does not fit/); + +assertEq(new Module(textToBinary(`(module (table (resizable 10)) (elem (i32.const 1) $f0 $f0) (elem (i32.const 0) $f0) ${callee(0)})`)) instanceof Module, true); +assertEq(new Module(textToBinary(`(module (table (resizable 10)) (elem (i32.const 1) $f0 $f0) (elem (i32.const 2) $f0) ${callee(0)})`)) instanceof Module, true); +evalText(`(module (table (resizable 10)) (import "globals" "a" (global i32 immutable)) (elem (i32.const 1) $f0 $f0) (elem (get_global 0) $f0) ${callee(0)})`, {globals:{a:0}}); +evalText(`(module (table (resizable 10)) (import "globals" "a" (global i32 immutable)) (elem (get_global 0) $f0 $f0) (elem (i32.const 2) $f0) ${callee(0)})`, {globals:{a:1}}); + +var m = new Module(textToBinary(` + (module + (import "globals" "table" (table 10)) + (import "globals" "a" (global i32 immutable)) + (elem (get_global 0) $f0 $f0) + ${callee(0)}) +`)); var tbl = new Table({initial:50, element:"anyfunc"}); -assertErrorMessage(() => evalText(`(module - (import "globals" "table" (table 10 100)) - (import "globals" "a" (global i32 immutable)) - (elem (get_global 0) $f0 $f0) - ${callee(0)}) -`, {globals:{a:20, table:tbl}}), Error, /element segment does not fit/); +assertEq(new Instance(m, {globals:{a:20, table:tbl}}) instanceof Instance, true); +assertErrorMessage(() => new Instance(m, {globals:{a:50, table:tbl}}), RangeError, /elem segment does not fit/); var caller = `(type $v2i (func (result i32))) (func $call (param $i i32) (result i32) (call_indirect $v2i (get_local $i))) (export "call" $call)` var callee = i => `(func $f${i} (type $v2i) (result i32) (i32.const ${i}))`; @@ -124,7 +128,7 @@ var m = new Module(textToBinary(`(module (import $imp "a" "imp" (result i32)) (func $call (param $i i32) (result i32) (i32.add - (call_import $imp) + (call $imp) (i32.add (i32.load (i32.const 0)) (if (i32.eqz (get_local $i)) diff --git a/js/src/jit/MacroAssembler-inl.h b/js/src/jit/MacroAssembler-inl.h index 9626b57f3ab79..720e05d0ac3b7 100644 --- a/js/src/jit/MacroAssembler-inl.h +++ b/js/src/jit/MacroAssembler-inl.h @@ -86,10 +86,10 @@ MacroAssembler::call(const wasm::CallSiteDesc& desc, const Register reg) } void -MacroAssembler::call(const wasm::CallSiteDesc& desc, uint32_t callee) +MacroAssembler::call(const wasm::CallSiteDesc& desc, uint32_t funcDefIndex) { CodeOffset l = callWithPatch(); - append(desc, l, framePushed(), callee); + append(desc, l, framePushed(), funcDefIndex); } // =============================================================== diff --git a/js/src/jit/MacroAssembler.h b/js/src/jit/MacroAssembler.h index 28e838aa29f8f..0d529f6aa824f 100644 --- a/js/src/jit/MacroAssembler.h +++ b/js/src/jit/MacroAssembler.h @@ -487,7 +487,7 @@ class MacroAssembler : public MacroAssemblerSpecific void call(JitCode* c) PER_SHARED_ARCH; inline void call(const wasm::CallSiteDesc& desc, const Register reg); - inline void call(const wasm::CallSiteDesc& desc, uint32_t callee); + inline void call(const wasm::CallSiteDesc& desc, uint32_t funcDefIndex); CodeOffset callWithPatch() PER_SHARED_ARCH; void patchCall(uint32_t callerOffset, uint32_t calleeOffset) PER_SHARED_ARCH; diff --git a/js/src/jit/shared/Assembler-shared.h b/js/src/jit/shared/Assembler-shared.h index 0eb7d26a4210f..b31338b443fae 100644 --- a/js/src/jit/shared/Assembler-shared.h +++ b/js/src/jit/shared/Assembler-shared.h @@ -754,12 +754,12 @@ class AssemblerShared } void append(const wasm::CallSiteDesc& desc, CodeOffset retAddr, size_t framePushed, - uint32_t targetIndex = wasm::CallSiteAndTarget::NOT_INTERNAL) + uint32_t funcDefIndex = wasm::CallSiteAndTarget::NOT_DEFINITION) { // framePushed does not include sizeof(AsmJSFrame), so add it in here (see // CallSite::stackDepth). wasm::CallSite callsite(desc, retAddr.offset(), framePushed + sizeof(AsmJSFrame)); - enoughMemory_ &= callsites_.append(wasm::CallSiteAndTarget(callsite, targetIndex)); + enoughMemory_ &= callsites_.append(wasm::CallSiteAndTarget(callsite, funcDefIndex)); } wasm::CallSiteAndTargetVector& callSites() { return callsites_; } diff --git a/js/src/jit/shared/CodeGenerator-shared.cpp b/js/src/jit/shared/CodeGenerator-shared.cpp index 623f758e041d8..30c638edc3756 100644 --- a/js/src/jit/shared/CodeGenerator-shared.cpp +++ b/js/src/jit/shared/CodeGenerator-shared.cpp @@ -1506,8 +1506,8 @@ CodeGeneratorShared::emitWasmCallBase(LWasmCallBase* ins) const wasm::CallSiteDesc& desc = mir->desc(); const wasm::CalleeDesc& callee = mir->callee(); switch (callee.which()) { - case wasm::CalleeDesc::Internal: - masm.call(desc, callee.internalFuncIndex()); + case wasm::CalleeDesc::Definition: + masm.call(desc, callee.funcDefIndex()); break; case wasm::CalleeDesc::Import: masm.wasmCallImport(desc, callee); diff --git a/js/src/jit/x86/CodeGenerator-x86.cpp b/js/src/jit/x86/CodeGenerator-x86.cpp index fd4bfd9dd73c0..92bb496bee104 100644 --- a/js/src/jit/x86/CodeGenerator-x86.cpp +++ b/js/src/jit/x86/CodeGenerator-x86.cpp @@ -401,9 +401,7 @@ CodeGeneratorX86::emitWasmCall(LWasmCallBase* ins) emitWasmCallBase(ins); - if (IsFloatingPointType(mir->type()) && - mir->callee().which() == wasm::CalleeDesc::Builtin) - { + if (IsFloatingPointType(mir->type()) && mir->callee().which() == wasm::CalleeDesc::Builtin) { if (mir->type() == MIRType::Float32) { masm.reserveStack(sizeof(float)); Operand op(esp, 0); diff --git a/js/src/js.msg b/js/src/js.msg index f086de8d51348..424b5e0697953 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -358,8 +358,9 @@ MSG_DEF(JSMSG_WASM_BAD_ELEMENT, 0, JSEXN_TYPEERR, "\"element\" proper MSG_DEF(JSMSG_WASM_BAD_IMPORT_ARG, 0, JSEXN_TYPEERR, "second argument, if present, must be an object") MSG_DEF(JSMSG_WASM_BAD_IMPORT_FIELD, 1, JSEXN_TYPEERR, "import object field is not {0}") MSG_DEF(JSMSG_WASM_BAD_IMPORT_SIG, 0, JSEXN_TYPEERR, "imported function signature mismatch") -MSG_DEF(JSMSG_WASM_BAD_SET_VALUE, 0, JSEXN_TYPEERR, "second argument must be null or an exported WebAssembly Function object") +MSG_DEF(JSMSG_WASM_BAD_TABLE_VALUE, 0, JSEXN_TYPEERR, "can only assign WebAssembly exported functions to Table") MSG_DEF(JSMSG_WASM_BAD_I64, 0, JSEXN_TYPEERR, "cannot pass i64 to or from JS") +MSG_DEF(JSMSG_WASM_BAD_FIT, 2, JSEXN_RANGEERR, "{0} segment does not fit in {1}") MSG_DEF(JSMSG_WASM_UNREACHABLE, 0, JSEXN_ERR, "unreachable executed") MSG_DEF(JSMSG_WASM_INTEGER_OVERFLOW, 0, JSEXN_ERR, "integer overflow") MSG_DEF(JSMSG_WASM_INVALID_CONVERSION, 0, JSEXN_ERR, "invalid conversion to integer") diff --git a/js/src/jscompartment.cpp b/js/src/jscompartment.cpp index 6194c864b176c..78dea4e24c85d 100644 --- a/js/src/jscompartment.cpp +++ b/js/src/jscompartment.cpp @@ -586,6 +586,7 @@ JSCompartment::traceOutgoingCrossCompartmentWrappers(JSTracer* trc) /* static */ void JSCompartment::traceIncomingCrossCompartmentEdgesForZoneGC(JSTracer* trc) { + gcstats::AutoPhase ap(trc->runtime()->gc.stats, gcstats::PHASE_MARK_CCWS); MOZ_ASSERT(trc->runtime()->isHeapMajorCollecting()); for (CompartmentsIter c(trc->runtime(), SkipAtoms); !c.done(); c.next()) { if (!c->zone()->isCollecting()) diff --git a/js/src/jsfun.h b/js/src/jsfun.h index b9838403032ad..776893f75cc18 100644 --- a/js/src/jsfun.h +++ b/js/src/jsfun.h @@ -685,7 +685,7 @@ class FunctionExtended : public JSFunction * wasm/asm.js exported functions store the function index of the exported * function in the original module. */ - static const unsigned WASM_FUNC_INDEX_SLOT = 1; + static const unsigned WASM_FUNC_DEF_INDEX_SLOT = 1; /* * asm.js module functions store their WasmModuleObject in the first slot. diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index fd6db7e556d27..cdb8ced62230b 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -2526,6 +2526,7 @@ GCRuntime::updateAllCellPointers(MovingTracer* trc, Zone* zone) void GCRuntime::updatePointersToRelocatedCells(Zone* zone, AutoLockForExclusiveAccess& lock) { + MOZ_ASSERT(!rt->isBeingDestroyed()); MOZ_ASSERT(zone->isGCCompacting()); gcstats::AutoPhase ap(stats, gcstats::PHASE_COMPACT_UPDATE); diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index 0ef98547276d0..c15db4f0d34f8 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -942,7 +942,7 @@ js::XDRLazyScript(XDRState* xdr, HandleScope enclosingScope, HandleScript } } - // Code free variables. + // Code closed-over bindings. if (!XDRLazyClosedOverBindings(xdr, lazy)) return false; @@ -955,7 +955,7 @@ js::XDRLazyScript(XDRState* xdr, HandleScope enclosingScope, HandleScript if (mode == XDR_ENCODE) func = innerFunctions[i]; - if (!XDRInterpretedFunction(xdr, enclosingScope, enclosingScript, &func)) + if (!XDRInterpretedFunction(xdr, nullptr, nullptr, &func)) return false; if (mode == XDR_DECODE) @@ -3965,7 +3965,7 @@ LazyScript::Create(ExclusiveContext* cx, HandleFunction fun, /* static */ LazyScript* LazyScript::Create(ExclusiveContext* cx, HandleFunction fun, HandleScript script, HandleScope enclosingScope, - HandleScript sourceObjectScript, + HandleScript enclosingScript, uint64_t packedFields, uint32_t begin, uint32_t end, uint32_t lineno, uint32_t column) { @@ -3991,10 +3991,15 @@ LazyScript::Create(ExclusiveContext* cx, HandleFunction fun, for (i = 0, num = res->numInnerFunctions(); i < num; i++) functions[i].init(dummyFun); - // Set the enclosing scope of the lazy function, this would later be - // used to define the environment when the function would be used. + // Set the enclosing scope and source object of the lazy function. These + // values should only be non-null if we have a non-lazy enclosing script. + // AddLazyFunctionsForCompartment relies on the source object being null + // if we're nested inside another lazy function. + MOZ_ASSERT(!!enclosingScript == !!enclosingScope); MOZ_ASSERT(!res->sourceObject()); - res->setEnclosingScopeAndSource(enclosingScope, &sourceObjectScript->scriptSourceUnwrap()); + MOZ_ASSERT(!res->enclosingScope()); + if (enclosingScript) + res->setEnclosingScopeAndSource(enclosingScope, &enclosingScript->scriptSourceUnwrap()); MOZ_ASSERT(!res->hasScript()); if (script) diff --git a/js/src/jsscript.h b/js/src/jsscript.h index 9f5bdb59d4abb..bc7063f3f5856 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -1905,11 +1905,11 @@ class LazyScript : public gc::TenuredCell // The "script" argument to this function can be null. If it's non-null, // then this LazyScript should be associated with the given JSScript. // - // The sourceObjectScript argument must be non-null and is the script that - // should be used to get the sourceObject_ of this lazyScript. + // The enclosingScript and enclosingScope arguments may be null if the + // enclosing function is also lazy. static LazyScript* Create(ExclusiveContext* cx, HandleFunction fun, HandleScript script, HandleScope enclosingScope, - HandleScript sourceObjectScript, + HandleScript enclosingScript, uint64_t packedData, uint32_t begin, uint32_t end, uint32_t lineno, uint32_t column); diff --git a/js/src/tests/ecma_5/extensions/inc-dec-functioncall.js b/js/src/tests/ecma_5/extensions/inc-dec-functioncall.js new file mode 100644 index 0000000000000..b4de03c6c05d2 --- /dev/null +++ b/js/src/tests/ecma_5/extensions/inc-dec-functioncall.js @@ -0,0 +1,90 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +//----------------------------------------------------------------------------- +var BUGNUMBER = 609756; +var summary = + "Perform ToNumber on the result of the |fun()| in |fun()++| before " + + "throwing"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +var hadSideEffect; + +function f() +{ + return { valueOf: function() { hadSideEffect = true; return 0; } }; +} + +hadSideEffect = false; +assertThrowsInstanceOf(function() { f()++; }, ReferenceError); +assertEq(hadSideEffect, true); + +hadSideEffect = false; +assertThrowsInstanceOf(function() { + for (var i = 0; i < 20; i++) + { + if (i > 18) + f()++; + } +}, ReferenceError); +assertEq(hadSideEffect, true); + + +hadSideEffect = false; +assertThrowsInstanceOf(function() { f()--; }, ReferenceError); +assertEq(hadSideEffect, true); + +hadSideEffect = false; +assertThrowsInstanceOf(function() { + for (var i = 0; i < 20; i++) + { + if (i > 18) + f()--; + } +}, ReferenceError); +assertEq(hadSideEffect, true); + + +hadSideEffect = false; +assertThrowsInstanceOf(function() { ++f(); }, ReferenceError); +assertEq(hadSideEffect, true); + +hadSideEffect = false; +assertThrowsInstanceOf(function() { + for (var i = 0; i < 20; i++) + { + if (i > 18) + ++f(); + } +}, ReferenceError); +assertEq(hadSideEffect, true); + + +hadSideEffect = false; +assertThrowsInstanceOf(function() { --f(); }, ReferenceError); +assertEq(hadSideEffect, true); + +hadSideEffect = false; +assertThrowsInstanceOf(function() { + for (var i = 0; i < 20; i++) + { + if (i > 18) + --f(); + } +}, ReferenceError); +assertEq(hadSideEffect, true); + + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_5/misc/future-reserved-words.js b/js/src/tests/ecma_5/misc/future-reserved-words.js index b4a41a2b93870..0fa2e32214de0 100644 --- a/js/src/tests/ecma_5/misc/future-reserved-words.js +++ b/js/src/tests/ecma_5/misc/future-reserved-words.js @@ -55,7 +55,7 @@ function testWord(word, expectNormal, expectStrict) actual = e.name; status += ", " + e.name + ": " + e.message + " "; } - reportCompare(expectNormal, actual, status); + assertEq(actual, expectNormal, status); actual = ""; status = summary + ": " + word + ": strict assignment"; @@ -69,7 +69,7 @@ function testWord(word, expectNormal, expectStrict) actual = e.name; status += ", " + e.name + ": " + e.message + " "; } - reportCompare(expectStrict, actual, status); + assertEq(actual, expectStrict, status); // USE IN VARIABLE DECLARATION @@ -85,7 +85,7 @@ function testWord(word, expectNormal, expectStrict) actual = e.name; status += ", " + e.name + ": " + e.message + " "; } - reportCompare(expectNormal, actual, status); + assertEq(actual, expectNormal, status); actual = ""; status = summary + ": " + word + ": strict var"; @@ -99,7 +99,7 @@ function testWord(word, expectNormal, expectStrict) actual = e.name; status += ", " + e.name + ": " + e.message + " "; } - reportCompare(expectStrict, actual, status); + assertEq(actual, expectStrict, status); // USE IN FOR-IN VARIABLE DECLARATION @@ -115,7 +115,7 @@ function testWord(word, expectNormal, expectStrict) actual = e.name; status += ", " + e.name + ": " + e.message + " "; } - reportCompare(expectNormal, actual, status); + assertEq(actual, expectNormal, status); actual = ""; status = summary + ": " + word + ": strict for-in var"; @@ -129,7 +129,7 @@ function testWord(word, expectNormal, expectStrict) actual = e.name; status += ", " + e.name + ": " + e.message + " "; } - reportCompare(expectStrict, actual, status); + assertEq(actual, expectStrict, status); // USE AS CATCH IDENTIFIER @@ -145,7 +145,7 @@ function testWord(word, expectNormal, expectStrict) actual = e.name; status += ", " + e.name + ": " + e.message + " "; } - reportCompare(expectNormal, actual, status); + assertEq(actual, expectNormal, status); actual = ""; status = summary + ": " + word + ": strict var"; @@ -159,7 +159,7 @@ function testWord(word, expectNormal, expectStrict) actual = e.name; status += ", " + e.name + ": " + e.message + " "; } - reportCompare(expectStrict, actual, status); + assertEq(actual, expectStrict, status); // USE AS LABEL @@ -175,7 +175,7 @@ function testWord(word, expectNormal, expectStrict) actual = e.name; status += ", " + e.name + ": " + e.message + " "; } - reportCompare(expectNormal, actual, status); + assertEq(actual, expectNormal, status); actual = ""; status = summary + ": " + word + ": strict label"; @@ -189,7 +189,7 @@ function testWord(word, expectNormal, expectStrict) actual = e.name; status += ", " + e.name + ": " + e.message + " "; } - reportCompare(expectStrict, actual, status); + assertEq(actual, expectStrict, status); // USE AS ARGUMENT NAME IN FUNCTION DECLARATION @@ -205,7 +205,7 @@ function testWord(word, expectNormal, expectStrict) actual = e.name; status += ", " + e.name + ": " + e.message + " "; } - reportCompare(expectNormal, actual, status); + assertEq(actual, expectNormal, status); actual = ""; status = summary + ": " + word + ": strict function argument"; @@ -219,7 +219,7 @@ function testWord(word, expectNormal, expectStrict) actual = e.name; status += ", " + e.name + ": " + e.message + " "; } - reportCompare(expectStrict, actual, status); + assertEq(actual, expectStrict, status); actual = ""; status = summary + ": " + word + ": function argument retroactively strict"; @@ -233,7 +233,7 @@ function testWord(word, expectNormal, expectStrict) actual = e.name; status += ", " + e.name + ": " + e.message + " "; } - reportCompare(expectStrict, actual, status); + assertEq(actual, expectStrict, status); // USE AS ARGUMENT NAME IN FUNCTION EXPRESSION @@ -249,7 +249,7 @@ function testWord(word, expectNormal, expectStrict) actual = e.name; status += ", " + e.name + ": " + e.message + " "; } - reportCompare(expectNormal, actual, status); + assertEq(actual, expectNormal, status); actual = ""; status = summary + ": " + word + ": strict function expression argument"; @@ -263,7 +263,7 @@ function testWord(word, expectNormal, expectStrict) actual = e.name; status += ", " + e.name + ": " + e.message + " "; } - reportCompare(expectStrict, actual, status); + assertEq(actual, expectStrict, status); actual = ""; status = summary + ": " + word + ": function expression argument retroactively strict"; @@ -277,7 +277,7 @@ function testWord(word, expectNormal, expectStrict) actual = e.name; status += ", " + e.name + ": " + e.message + " "; } - reportCompare(expectStrict, actual, status); + assertEq(actual, expectStrict, status); // USE AS ARGUMENT NAME WITH FUNCTION CONSTRUCTOR @@ -293,7 +293,7 @@ function testWord(word, expectNormal, expectStrict) actual = e.name; status += ", " + e.name + ": " + e.message + " "; } - reportCompare(expectNormal, actual, status); + assertEq(actual, expectNormal, status); actual = ""; status = summary + ": " + word + ": argument with strict Function"; @@ -307,7 +307,7 @@ function testWord(word, expectNormal, expectStrict) actual = e.name; status += ", " + e.name + ": " + e.message + " "; } - reportCompare(expectStrict, actual, status); + assertEq(actual, expectStrict, status); // USE AS ARGUMENT NAME IN PROPERTY SETTER @@ -323,7 +323,7 @@ function testWord(word, expectNormal, expectStrict) actual = e.name; status += ", " + e.name + ": " + e.message + " "; } - reportCompare(expectNormal, actual, status); + assertEq(actual, expectNormal, status); actual = ""; status = summary + ": " + word + ": strict property setter argument"; @@ -337,7 +337,7 @@ function testWord(word, expectNormal, expectStrict) actual = e.name; status += ", " + e.name + ": " + e.message + " "; } - reportCompare(expectStrict, actual, status); + assertEq(actual, expectStrict, status); actual = ""; status = summary + ": " + word + ": property setter argument retroactively strict"; @@ -351,7 +351,7 @@ function testWord(word, expectNormal, expectStrict) actual = e.name; status += ", " + e.name + ": " + e.message + " "; } - reportCompare(expectStrict, actual, status); + assertEq(actual, expectStrict, status); // USE AS FUNCTION NAME IN FUNCTION DECLARATION @@ -367,7 +367,7 @@ function testWord(word, expectNormal, expectStrict) actual = e.name; status += ", " + e.name + ": " + e.message + " "; } - reportCompare(expectNormal, actual, status); + assertEq(actual, expectNormal, status); actual = ""; status = summary + ": " + word + ": strict function name"; @@ -381,7 +381,7 @@ function testWord(word, expectNormal, expectStrict) actual = e.name; status += ", " + e.name + ": " + e.message + " "; } - reportCompare(expectStrict, actual, status); + assertEq(actual, expectStrict, status); actual = ""; status = summary + ": " + word + ": function name retroactively strict"; @@ -395,7 +395,7 @@ function testWord(word, expectNormal, expectStrict) actual = e.name; status += ", " + e.name + ": " + e.message + " "; } - reportCompare(expectStrict, actual, status); + assertEq(actual, expectStrict, status); // USE AS FUNCTION NAME IN FUNCTION EXPRESSION @@ -411,7 +411,7 @@ function testWord(word, expectNormal, expectStrict) actual = e.name; status += ", " + e.name + ": " + e.message + " "; } - reportCompare(expectNormal, actual, status); + assertEq(actual, expectNormal, status); actual = ""; status = summary + ": " + word + ": strict function expression name"; @@ -425,7 +425,7 @@ function testWord(word, expectNormal, expectStrict) actual = e.name; status += ", " + e.name + ": " + e.message + " "; } - reportCompare(expectStrict, actual, status); + assertEq(actual, expectStrict, status); actual = ""; status = summary + ": " + word + ": function expression name retroactively strict"; @@ -439,7 +439,7 @@ function testWord(word, expectNormal, expectStrict) actual = e.name; status += ", " + e.name + ": " + e.message + " "; } - reportCompare(expectStrict, actual, status); + assertEq(actual, expectStrict, status); } function testFutureReservedWord(word) diff --git a/js/src/vm/CommonPropertyNames.h b/js/src/vm/CommonPropertyNames.h index 636fa6336e42f..68a91f5797f0e 100644 --- a/js/src/vm/CommonPropertyNames.h +++ b/js/src/vm/CommonPropertyNames.h @@ -18,7 +18,6 @@ macro(Any, Any, "Any") \ macro(apply, apply, "apply") \ macro(arguments, arguments, "arguments") \ - macro(as, as, "as") \ macro(ArrayBufferSpecies, ArrayBufferSpecies, "ArrayBufferSpecies") \ macro(ArrayIterator, ArrayIterator, "Array Iterator") \ macro(ArrayIteratorNext, ArrayIteratorNext, "ArrayIteratorNext") \ @@ -27,6 +26,7 @@ macro(ArrayType, ArrayType, "ArrayType") \ macro(ArrayValues, ArrayValues, "ArrayValues") \ macro(ArrayValuesAt, ArrayValuesAt, "ArrayValuesAt") \ + macro(as, as, "as") \ macro(Async, Async, "Async") \ macro(Bool8x16, Bool8x16, "Bool8x16") \ macro(Bool16x8, Bool16x8, "Bool16x8") \ @@ -36,14 +36,13 @@ macro(buffer, buffer, "buffer") \ macro(builder, builder, "builder") \ macro(by, by, "by") \ - macro(byteLength, byteLength, "byteLength") \ macro(byteAlignment, byteAlignment, "byteAlignment") \ + macro(byteLength, byteLength, "byteLength") \ macro(byteOffset, byteOffset, "byteOffset") \ macro(bytes, bytes, "bytes") \ macro(BYTES_PER_ELEMENT, BYTES_PER_ELEMENT, "BYTES_PER_ELEMENT") \ macro(call, call, "call") \ macro(callContentFunction, callContentFunction, "callContentFunction") \ - macro(std_Function_apply, std_Function_apply, "std_Function_apply") \ macro(callee, callee, "callee") \ macro(caller, caller, "caller") \ macro(callFunction, callFunction, "callFunction") \ @@ -73,11 +72,11 @@ macro(dayPeriod, dayPeriod, "dayPeriod") \ macro(decodeURI, decodeURI, "decodeURI") \ macro(decodeURIComponent, decodeURIComponent, "decodeURIComponent") \ - macro(default_, default_, "default") \ macro(DefaultBaseClassConstructor, DefaultBaseClassConstructor, "DefaultBaseClassConstructor") \ macro(DefaultDerivedClassConstructor, DefaultDerivedClassConstructor, "DefaultDerivedClassConstructor") \ - macro(defineProperty, defineProperty, "defineProperty") \ + macro(default_, default_, "default") \ macro(defineGetter, defineGetter, "__defineGetter__") \ + macro(defineProperty, defineProperty, "defineProperty") \ macro(defineSetter, defineSetter, "__defineSetter__") \ macro(delete, delete_, "delete") \ macro(deleteProperty, deleteProperty, "deleteProperty") \ @@ -119,17 +118,19 @@ macro(formatToParts, formatToParts, "formatToParts") \ macro(frame, frame, "frame") \ macro(from, from, "from") \ - macro(futexOK, futexOK, "ok") \ + macro(fulfilled, fulfilled, "fulfilled") \ + macro(fulfillHandler, fulfillHandler, "fulfillHandler") \ macro(futexNotEqual, futexNotEqual, "not-equal") \ + macro(futexOK, futexOK, "ok") \ macro(futexTimedOut, futexTimedOut, "timed-out") \ macro(gcCycleNumber, gcCycleNumber, "gcCycleNumber") \ macro(Generator, Generator, "Generator") \ macro(GeneratorFunction, GeneratorFunction, "GeneratorFunction") \ macro(get, get, "get") \ - macro(getPrefix, getPrefix, "get ") \ macro(getInternals, getInternals, "getInternals") \ macro(getOwnPropertyDescriptor, getOwnPropertyDescriptor, "getOwnPropertyDescriptor") \ macro(getOwnPropertyNames, getOwnPropertyNames, "getOwnPropertyNames") \ + macro(getPrefix, getPrefix, "get ") \ macro(getPropertyDescriptor, getPropertyDescriptor, "getPropertyDescriptor") \ macro(getPrototypeOf, getPrototypeOf, "getPrototypeOf") \ macro(global, global, "global") \ @@ -141,27 +142,28 @@ macro(ignoreCase, ignoreCase, "ignoreCase") \ macro(ignorePunctuation, ignorePunctuation, "ignorePunctuation") \ macro(includes, includes, "includes") \ + macro(incumbentGlobal, incumbentGlobal, "incumbentGlobal") \ macro(index, index, "index") \ + macro(Infinity, Infinity, "Infinity") \ macro(InitializeCollator, InitializeCollator, "InitializeCollator") \ macro(InitializeDateTimeFormat, InitializeDateTimeFormat, "InitializeDateTimeFormat") \ macro(InitializeNumberFormat, InitializeNumberFormat, "InitializeNumberFormat") \ - macro(inNursery, inNursery, "inNursery") \ macro(innermost, innermost, "innermost") \ + macro(inNursery, inNursery, "inNursery") \ macro(input, input, "input") \ + macro(int8, int8, "int8") \ + macro(int16, int16, "int16") \ + macro(int32, int32, "int32") \ macro(Int8x16, Int8x16, "Int8x16") \ macro(Int16x8, Int16x8, "Int16x8") \ macro(Int32x4, Int32x4, "Int32x4") \ + macro(InterpretGeneratorResume, InterpretGeneratorResume, "InterpretGeneratorResume") \ + macro(isEntryPoint, isEntryPoint, "isEntryPoint") \ + macro(isExtensible, isExtensible, "isExtensible") \ macro(isFinite, isFinite, "isFinite") \ macro(isNaN, isNaN, "isNaN") \ macro(isPrototypeOf, isPrototypeOf, "isPrototypeOf") \ macro(iterate, iterate, "iterate") \ - macro(Infinity, Infinity, "Infinity") \ - macro(InterpretGeneratorResume, InterpretGeneratorResume, "InterpretGeneratorResume") \ - macro(int8, int8, "int8") \ - macro(int16, int16, "int16") \ - macro(int32, int32, "int32") \ - macro(isEntryPoint, isEntryPoint, "isEntryPoint") \ - macro(isExtensible, isExtensible, "isExtensible") \ macro(iteratorIntrinsic, iteratorIntrinsic, "__iterator__") \ macro(join, join, "join") \ macro(js, js, "js") \ @@ -202,24 +204,24 @@ macro(NFD, NFD, "NFD") \ macro(NFKC, NFKC, "NFKC") \ macro(NFKD, NFKD, "NFKD") \ - macro(nonincrementalReason, nonincrementalReason, "nonincrementalReason") \ macro(noFilename, noFilename, "noFilename") \ + macro(nonincrementalReason, nonincrementalReason, "nonincrementalReason") \ macro(noStack, noStack, "noStack") \ macro(NumberFormat, NumberFormat, "NumberFormat") \ macro(NumberFormatFormatGet, NumberFormatFormatGet, "Intl_NumberFormat_format_get") \ macro(numeric, numeric, "numeric") \ - macro(objectUndefined, objectUndefined, "[object Undefined]") \ - macro(objectNull, objectNull, "[object Null]") \ - macro(objectArray, objectArray, "[object Array]") \ - macro(objectString, objectString, "[object String]") \ macro(objectArguments, objectArguments, "[object Arguments]") \ - macro(objectFunction, objectFunction, "[object Function]") \ - macro(objectError, objectError, "[object Error]") \ + macro(objectArray, objectArray, "[object Array]") \ macro(objectBoolean, objectBoolean, "[object Boolean]") \ - macro(objectNumber, objectNumber, "[object Number]") \ macro(objectDate, objectDate, "[object Date]") \ + macro(objectError, objectError, "[object Error]") \ + macro(objectFunction, objectFunction, "[object Function]") \ + macro(objectNull, objectNull, "[object Null]") \ + macro(objectNumber, objectNumber, "[object Number]") \ macro(objectRegExp, objectRegExp, "[object RegExp]") \ macro(objects, objects, "objects") \ + macro(objectString, objectString, "[object String]") \ + macro(objectUndefined, objectUndefined, "[object Undefined]") \ macro(of, of, "of") \ macro(offset, offset, "offset") \ macro(optimizedOut, optimizedOut, "optimizedOut") \ @@ -229,33 +231,36 @@ macro(parseFloat, parseFloat, "parseFloat") \ macro(parseInt, parseInt, "parseInt") \ macro(pattern, pattern, "pattern") \ + macro(pending, pending, "pending") \ macro(preventExtensions, preventExtensions, "preventExtensions") \ macro(promise, promise, "promise") \ - macro(SetIterator, SetIterator, "Set Iterator") \ - macro(state, state, "state") \ - macro(pending, pending, "pending") \ - macro(fulfillHandler, fulfillHandler, "fulfillHandler") \ - macro(fulfilled, fulfilled, "fulfilled") \ - macro(reject, reject, "reject") \ - macro(rejected, rejected, "rejected") \ - macro(rejectHandler, rejectHandler, "rejectHandler") \ - macro(resolve, resolve, "resolve") \ - macro(incumbentGlobal, incumbentGlobal, "incumbentGlobal") \ macro(propertyIsEnumerable, propertyIsEnumerable, "propertyIsEnumerable") \ macro(proto, proto, "__proto__") \ macro(prototype, prototype, "prototype") \ macro(proxy, proxy, "proxy") \ + macro(raw, raw, "raw") \ macro(reason, reason, "reason") \ + macro(RegExpBuiltinExec, RegExpBuiltinExec, "RegExpBuiltinExec") \ + macro(RegExpMatcher, RegExpMatcher, "RegExpMatcher") \ + macro(RegExpSearcher, RegExpSearcher, "RegExpSearcher") \ + macro(RegExpTester, RegExpTester, "RegExpTester") \ + macro(RegExp_prototype_Exec, RegExp_prototype_Exec, "RegExp_prototype_Exec") \ macro(Reify, Reify, "Reify") \ + macro(reject, reject, "reject") \ + macro(rejected, rejected, "rejected") \ + macro(rejectHandler, rejectHandler, "rejectHandler") \ macro(RequireObjectCoercible, RequireObjectCoercible, "RequireObjectCoercible") \ + macro(resolve, resolve, "resolve") \ macro(resumeGenerator, resumeGenerator, "resumeGenerator") \ macro(return, return_, "return") \ macro(revoke, revoke, "revoke") \ macro(script, script, "script") \ macro(scripts, scripts, "scripts") \ macro(second, second, "second") \ + macro(selfHosted, selfHosted, "self-hosted") \ macro(sensitivity, sensitivity, "sensitivity") \ macro(set, set, "set") \ + macro(SetIterator, SetIterator, "Set Iterator") \ macro(setPrefix, setPrefix, "set ") \ macro(setPrototypeOf, setPrototypeOf, "setPrototypeOf") \ macro(shape, shape, "shape") \ @@ -266,13 +271,16 @@ macro(star, star, "*") \ macro(starDefaultStar, starDefaultStar, "*default*") \ macro(startTimestamp, startTimestamp, "startTimestamp") \ + macro(state, state, "state") \ macro(static, static_, "static") \ + macro(std_Function_apply, std_Function_apply, "std_Function_apply") \ macro(sticky, sticky, "sticky") \ - macro(strings, strings, "strings") \ macro(StringIterator, StringIterator, "String Iterator") \ + macro(strings, strings, "strings") \ macro(StructType, StructType, "StructType") \ macro(style, style, "style") \ macro(super, super, "super") \ + macro(Symbol_iterator_fun, Symbol_iterator_fun, "[Symbol.iterator]") \ macro(target, target, "target") \ macro(test, test, "test") \ macro(then, then, "then") \ @@ -289,10 +297,6 @@ macro(toUTCString, toUTCString, "toUTCString") \ macro(true, true_, "true") \ macro(type, type, "type") \ - macro(unescape, unescape, "unescape") \ - macro(uneval, uneval, "uneval") \ - macro(unicode, unicode, "unicode") \ - macro(uninitialized, uninitialized, "uninitialized") \ macro(uint8, uint8, "uint8") \ macro(uint8Clamped, uint8Clamped, "uint8Clamped") \ macro(uint16, uint16, "uint16") \ @@ -300,35 +304,33 @@ macro(Uint8x16, Uint8x16, "Uint8x16") \ macro(Uint16x8, Uint16x8, "Uint16x8") \ macro(Uint32x4, Uint32x4, "Uint32x4") \ + macro(unescape, unescape, "unescape") \ + macro(uneval, uneval, "uneval") \ + macro(unicode, unicode, "unicode") \ + macro(uninitialized, uninitialized, "uninitialized") \ macro(unsized, unsized, "unsized") \ macro(unwatch, unwatch, "unwatch") \ + macro(UnwrapAndCallRegExpBuiltinExec, UnwrapAndCallRegExpBuiltinExec, "UnwrapAndCallRegExpBuiltinExec") \ macro(url, url, "url") \ macro(usage, usage, "usage") \ - macro(useGrouping, useGrouping, "useGrouping") \ macro(useAsm, useAsm, "use asm") \ + macro(useGrouping, useGrouping, "useGrouping") \ macro(useStrict, useStrict, "use strict") \ macro(value, value, "value") \ - macro(values, values, "values") \ macro(valueOf, valueOf, "valueOf") \ + macro(values, values, "values") \ macro(var, var, "var") \ macro(variable, variable, "variable") \ macro(void0, void0, "(void 0)") \ macro(wasm, wasm, "wasm") \ macro(watch, watch, "watch") \ macro(WeakSet_add, WeakSet_add, "WeakSet_add") \ - macro(RegExp_prototype_Exec, RegExp_prototype_Exec, "RegExp_prototype_Exec") \ - macro(UnwrapAndCallRegExpBuiltinExec, UnwrapAndCallRegExpBuiltinExec, "UnwrapAndCallRegExpBuiltinExec") \ - macro(RegExpBuiltinExec, RegExpBuiltinExec, "RegExpBuiltinExec") \ - macro(RegExpMatcher, RegExpMatcher, "RegExpMatcher") \ - macro(RegExpSearcher, RegExpSearcher, "RegExpSearcher") \ - macro(RegExpTester, RegExpTester, "RegExpTester") \ macro(weekday, weekday, "weekday") \ macro(weekendEnd, weekendEnd, "weekendEnd") \ macro(weekendStart, weekendStart, "weekendStart") \ macro(writable, writable, "writable") \ macro(year, year, "year") \ macro(yield, yield, "yield") \ - macro(raw, raw, "raw") \ /* Type names must be contiguous and ordered; see js::TypeName. */ \ macro(undefined, undefined, "undefined") \ macro(object, object, "object") \ @@ -338,10 +340,5 @@ macro(boolean, boolean, "boolean") \ macro(null, null, "null") \ macro(symbol, symbol, "symbol") \ - /* Function names for properties named by symbols. */ \ - macro(Symbol_iterator_fun, Symbol_iterator_fun, "[Symbol.iterator]") \ - /* Not really a property name, but we use this to compare to atomized - script source strings */ \ - macro(selfHosted, selfHosted, "self-hosted") \ #endif /* vm_CommonPropertyNames_h */ diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index 52c582967a1be..7a9360959903e 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -4886,28 +4886,29 @@ bool Debugger::drainTraceLogger(JSContext* cx, unsigned argc, Value* vp) { THIS_DEBUGGER(cx, argc, vp, "drainTraceLogger", args, dbg); - if (!args.requireAtLeast(cx, "Debugger.drainTraceLogger", 0)) - return false; - size_t num; TraceLoggerThread* logger = TraceLoggerForMainThread(cx->runtime()); bool lostEvents = logger->lostEvents(dbg->traceLoggerLastDrainedIteration, dbg->traceLoggerLastDrainedSize); + + size_t numEvents; EventEntry* events = logger->getEventsStartingAt(&dbg->traceLoggerLastDrainedIteration, &dbg->traceLoggerLastDrainedSize, - &num); + &numEvents); RootedObject array(cx, NewDenseEmptyArray(cx)); - JSAtom* dataAtom = Atomize(cx, "data", strlen("data")); if (!array) return false; + + JSAtom* dataAtom = Atomize(cx, "data", strlen("data")); if (!dataAtom) return false; + RootedId dataId(cx, AtomToId(dataAtom)); /* Add all events to the array. */ uint32_t index = 0; - for (EventEntry* eventItem = events; eventItem < events + num; eventItem++, index++) { + for (EventEntry* eventItem = events; eventItem < events + numEvents; eventItem++, index++) { RootedObject item(cx, NewObjectWithGivenProto(cx, &PlainObject::class_, nullptr)); if (!item) return false; @@ -5037,32 +5038,33 @@ bool Debugger::drainTraceLoggerScriptCalls(JSContext* cx, unsigned argc, Value* vp) { THIS_DEBUGGER(cx, argc, vp, "drainTraceLoggerScriptCalls", args, dbg); - if (!args.requireAtLeast(cx, "Debugger.drainTraceLoggerScriptCalls", 0)) - return false; - size_t num; TraceLoggerThread* logger = TraceLoggerForMainThread(cx->runtime()); bool lostEvents = logger->lostEvents(dbg->traceLoggerScriptedCallsLastDrainedIteration, dbg->traceLoggerScriptedCallsLastDrainedSize); + + size_t numEvents; EventEntry* events = logger->getEventsStartingAt( &dbg->traceLoggerScriptedCallsLastDrainedIteration, &dbg->traceLoggerScriptedCallsLastDrainedSize, - &num); + &numEvents); RootedObject array(cx, NewDenseEmptyArray(cx)); if (!array) return false; - RootedId fileNameId(cx, AtomToId(cx->names().fileName)); - RootedId lineNumberId(cx, AtomToId(cx->names().lineNumber)); - RootedId columnNumberId(cx, AtomToId(cx->names().columnNumber)); + JSAtom* logTypeAtom = Atomize(cx, "logType", strlen("logType")); if (!logTypeAtom) return false; + + RootedId fileNameId(cx, AtomToId(cx->names().fileName)); + RootedId lineNumberId(cx, AtomToId(cx->names().lineNumber)); + RootedId columnNumberId(cx, AtomToId(cx->names().columnNumber)); RootedId logTypeId(cx, AtomToId(logTypeAtom)); /* Add all events to the array. */ uint32_t index = 0; - for (EventEntry* eventItem = events; eventItem < events + num; eventItem++) { + for (EventEntry* eventItem = events; eventItem < events + numEvents; eventItem++) { RootedObject item(cx, NewObjectWithGivenProto(cx, &PlainObject::class_, nullptr)); if (!item) return false; diff --git a/js/src/vm/NativeObject-inl.h b/js/src/vm/NativeObject-inl.h index 05d82b8b92e9c..99929c7537ad3 100644 --- a/js/src/vm/NativeObject-inl.h +++ b/js/src/vm/NativeObject-inl.h @@ -161,7 +161,7 @@ NativeObject::extendDenseElements(ExclusiveContext* cx, * long as there is capacity for them. */ if (!nonProxyIsExtensible() || watched()) { - MOZ_ASSERT(getDenseCapacity() == 0); + MOZ_ASSERT(getDenseCapacity() == 0 || (!watched() && getElementsHeader()->isFrozen())); return DenseElementResult::Incomplete; } diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index 8be7941aa42b0..f6cafee193001 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -6647,10 +6647,10 @@ nsCharClipDisplayItem::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, nsDisplaySVGEffects::nsDisplaySVGEffects(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayList* aList, - bool aOpacityItemCreated) + bool aHandleOpacity) : nsDisplayWrapList(aBuilder, aFrame, aList) , mEffectsBounds(aFrame->GetVisualOverflowRectRelativeToSelf()) - , mOpacityItemCreated(aOpacityItemCreated) + , mHandleOpacity(aHandleOpacity) { MOZ_COUNT_CTOR(nsDisplaySVGEffects); } @@ -6738,9 +6738,9 @@ bool nsDisplaySVGEffects::ValidateSVGFrame() } nsDisplayMask::nsDisplayMask(nsDisplayListBuilder* aBuilder, - nsIFrame* aFrame, nsDisplayList* aList, - bool aOpacityItemCreated) - : nsDisplaySVGEffects(aBuilder, aFrame, aList, aOpacityItemCreated) + nsIFrame* aFrame, nsDisplayList* aList, + bool aHandleOpacity) + : nsDisplaySVGEffects(aBuilder, aFrame, aList, aHandleOpacity) { MOZ_COUNT_CTOR(nsDisplayMask); } @@ -6782,7 +6782,7 @@ nsDisplayMask::BuildLayer(nsDisplayListBuilder* aBuilder, return nullptr; } - if (mFrame->StyleEffects()->mOpacity == 0.0f && !mOpacityItemCreated) { + if (mFrame->StyleEffects()->mOpacity == 0.0f && mHandleOpacity) { return nullptr; } @@ -6814,7 +6814,8 @@ nsDisplayMask::GetLayerState(nsDisplayListBuilder* aBuilder, } bool nsDisplayMask::ComputeVisibility(nsDisplayListBuilder* aBuilder, - nsRegion* aVisibleRegion) { + nsRegion* aVisibleRegion) +{ // Our children may be made translucent or arbitrarily deformed so we should // not allow them to subtract area from aVisibleRegion. nsRegion childrenVisible(mVisibleRect); @@ -6832,7 +6833,8 @@ nsDisplayMask::PaintAsLayer(nsDisplayListBuilder* aBuilder, nsSVGIntegrationUtils::PaintFramesParams params(*aCtx->ThebesContext(), mFrame, mVisibleRect, borderArea, aBuilder, - aManager, mOpacityItemCreated); + aManager, + mHandleOpacity); image::DrawResult result = nsSVGIntegrationUtils::PaintMaskAndClipPath(params); @@ -6883,9 +6885,9 @@ nsDisplayMask::PrintEffects(nsACString& aTo) #endif nsDisplayFilter::nsDisplayFilter(nsDisplayListBuilder* aBuilder, - nsIFrame* aFrame, nsDisplayList* aList, - bool aOpacityItemCreated) - : nsDisplaySVGEffects(aBuilder, aFrame, aList, aOpacityItemCreated) + nsIFrame* aFrame, nsDisplayList* aList, + bool aHandleOpacity) + : nsDisplaySVGEffects(aBuilder, aFrame, aList, aHandleOpacity) { MOZ_COUNT_CTOR(nsDisplayFilter); } @@ -6906,7 +6908,7 @@ nsDisplayFilter::BuildLayer(nsDisplayListBuilder* aBuilder, return nullptr; } - if (mFrame->StyleEffects()->mOpacity == 0.0f && !mOpacityItemCreated) { + if (mFrame->StyleEffects()->mOpacity == 0.0f && mHandleOpacity) { return nullptr; } @@ -6963,7 +6965,8 @@ nsDisplayFilter::GetLayerState(nsDisplayListBuilder* aBuilder, } bool nsDisplayFilter::ComputeVisibility(nsDisplayListBuilder* aBuilder, - nsRegion* aVisibleRegion) { + nsRegion* aVisibleRegion) +{ nsPoint offset = ToReferenceFrame(); nsRect dirtyRect = nsSVGIntegrationUtils::GetRequiredSourceForInvalidArea(mFrame, @@ -6987,7 +6990,8 @@ nsDisplayFilter::PaintAsLayer(nsDisplayListBuilder* aBuilder, nsSVGIntegrationUtils::PaintFramesParams params(*aCtx->ThebesContext(), mFrame, mVisibleRect, borderArea, aBuilder, - aManager, mOpacityItemCreated); + aManager, + mHandleOpacity); image::DrawResult result = nsSVGIntegrationUtils::PaintFilter(params); diff --git a/layout/base/nsDisplayList.h b/layout/base/nsDisplayList.h index 1b704800711d2..a35f34370b44e 100644 --- a/layout/base/nsDisplayList.h +++ b/layout/base/nsDisplayList.h @@ -3785,7 +3785,7 @@ class nsDisplayZoom : public nsDisplaySubDocument { class nsDisplaySVGEffects: public nsDisplayWrapList { public: nsDisplaySVGEffects(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, - nsDisplayList* aList, bool aOpacityItemCreated); + nsDisplayList* aList, bool aHandleOpacity); #ifdef NS_BUILD_REFCNT_LOGGING virtual ~nsDisplaySVGEffects(); #endif @@ -3820,9 +3820,8 @@ class nsDisplaySVGEffects: public nsDisplayWrapList { // relative to mFrame nsRect mEffectsBounds; - // True if the caller also created an nsDisplayOpacity item, and we should tell - // PaintFramesWithEffects that it doesn't need to handle opacity itself. - bool mOpacityItemCreated; + // True if we need to handle css opacity in this display item. + bool mHandleOpacity; }; /** @@ -3832,7 +3831,7 @@ class nsDisplaySVGEffects: public nsDisplayWrapList { class nsDisplayMask : public nsDisplaySVGEffects { public: nsDisplayMask(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, - nsDisplayList* aList, bool aOpacityItemCreated); + nsDisplayList* aList, bool aHandleOpacity); #ifdef NS_BUILD_REFCNT_LOGGING virtual ~nsDisplayMask(); #endif @@ -3858,10 +3857,14 @@ class nsDisplayMask : public nsDisplaySVGEffects { LayerManager* aManager); }; +/** + * A display item to paint a stacking context with filter effects set by the + * stacking context root frame's style. + */ class nsDisplayFilter : public nsDisplaySVGEffects { public: nsDisplayFilter(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, - nsDisplayList* aList, bool aOpacityItemCreated); + nsDisplayList* aList, bool aHandleOpacity); #ifdef NS_BUILD_REFCNT_LOGGING virtual ~nsDisplayFilter(); #endif diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index 686c6ff7a5fcc..2bc766e61c407 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -2442,7 +2442,8 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder, */ if (usingSVGEffects) { MOZ_ASSERT(StyleEffects()->HasFilters() || - nsSVGIntegrationUtils::UsingMaskOrClipPathForFrame(this)); + nsSVGIntegrationUtils::UsingMaskOrClipPathForFrame(this), + "Beside filter & mask/clip-path, what else effect do we have?"); if (clipCapturedBy == ContainerItemType::eSVGEffects) { clipState.ExitStackingContextContents(&containerItemScrollClip); @@ -2451,16 +2452,27 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder, buildingDisplayList.SetDirtyRect(dirtyRectOutsideSVGEffects); // Skip all filter effects while generating glyph mask. - if (StyleEffects()->HasFilters() && !aBuilder->IsForGenerateGlyphMask()) { + bool createFilter = + StyleEffects()->HasFilters() && !aBuilder->IsForGenerateGlyphMask(); + bool createMask = nsSVGIntegrationUtils::UsingMaskOrClipPathForFrame(this); + + if (createFilter) { + // If we are going to create a mask display item, handle opacity effect + // in that mask display item; Otherwise, take care of opacity in this + // filter display item. + bool handleOpacity = !createMask && !useOpacity; + /* List now emptied, so add the new list to the top. */ resultList.AppendNewToTop( - new (aBuilder) nsDisplayFilter(aBuilder, this, &resultList, useOpacity)); + new (aBuilder) nsDisplayFilter(aBuilder, this, &resultList, + handleOpacity)); } - if (nsSVGIntegrationUtils::UsingMaskOrClipPathForFrame(this)) { + if (createMask) { /* List now emptied, so add the new list to the top. */ resultList.AppendNewToTop( - new (aBuilder) nsDisplayMask(aBuilder, this, &resultList, useOpacity)); + new (aBuilder) nsDisplayMask(aBuilder, this, &resultList, + !useOpacity)); } // Also add the hoisted scroll info items. We need those for APZ scrolling diff --git a/layout/generic/nsGridContainerFrame.cpp b/layout/generic/nsGridContainerFrame.cpp index 6bc1f01932ebd..9409a1c736567 100644 --- a/layout/generic/nsGridContainerFrame.cpp +++ b/layout/generic/nsGridContainerFrame.cpp @@ -1628,7 +1628,7 @@ struct nsGridContainerFrame::Tracks return size; } - nsTArray GetLineNamesAtIndex( + nsTArray GetExplicitLineNamesAtIndex( const nsStyleGridTemplate& aGridTemplate, const TrackSizingFunctions& aFunctions, uint32_t aIndex) @@ -2315,7 +2315,6 @@ struct MOZ_STACK_CLASS nsGridContainerFrame::Grid */ uint32_t mExplicitGridOffsetCol; uint32_t mExplicitGridOffsetRow; - }; void @@ -2678,15 +2677,30 @@ nsGridContainerFrame::AddImplicitNamedAreas( ImplicitNamedAreas* areas = GetImplicitNamedAreas(); for (uint32_t i = 0; i < len; ++i) { for (const nsString& name : aLineNameLists[i]) { - uint32_t index; - if (Grid::IsNameWithStartSuffix(name, &index) || - Grid::IsNameWithEndSuffix(name, &index)) { - nsDependentSubstring area(name, 0, index); + uint32_t indexOfSuffix; + if (Grid::IsNameWithStartSuffix(name, &indexOfSuffix) || + Grid::IsNameWithEndSuffix(name, &indexOfSuffix)) { + // Extract the name that was found earlier. + nsDependentSubstring areaName(name, 0, indexOfSuffix); + + // Lazily create the ImplicitNamedAreas. if (!areas) { areas = new ImplicitNamedAreas; Properties().Set(ImplicitNamedAreasProperty(), areas); } - areas->PutEntry(area); + + mozilla::css::GridNamedArea area; + if (!areas->Get(areaName, &area)) { + // Not found, so prep the newly-seen area with a name and empty + // boundary information, which will get filled in later. + area.mName = areaName; + area.mRowStart = 0; + area.mRowEnd = 0; + area.mColumnStart = 0; + area.mColumnEnd = 0; + + areas->Put(areaName, area); + } } } } @@ -3457,6 +3471,38 @@ nsGridContainerFrame::Grid::PlaceGridItems(GridReflowInput& aState, auto finalRowRepeatCount = aState.mRowFunctions.NumRepeatTracks() - numEmptyRows; aState.mRowFunctions.SetNumRepeatTracks(finalRowRepeatCount); } + + // Update the line boundaries of the implicit grid areas, if needed. + if (mAreas && + aState.mFrame->HasAnyStateBits(NS_STATE_GRID_GENERATE_COMPUTED_VALUES)) { + for (auto iter = mAreas->Iter(); !iter.Done(); iter.Next()) { + auto& areaInfo = iter.Data(); + + // Resolve the lines for the area. We use the name of the area as the + // name of the lines, knowing that the line placement algorithm will + // add the -start and -end suffixes as appropriate for layout. + nsStyleGridLine lineStartAndEnd; + lineStartAndEnd.mLineName = areaInfo.mName; + + LineRange columnLines = ResolveLineRange( + lineStartAndEnd, lineStartAndEnd, + colLineNameMap, + &GridNamedArea::mColumnStart, &GridNamedArea::mColumnEnd, + mExplicitGridColEnd, gridStyle); + + LineRange rowLines = ResolveLineRange( + lineStartAndEnd, lineStartAndEnd, + rowLineNameMap, + &GridNamedArea::mRowStart, &GridNamedArea::mRowEnd, + mExplicitGridRowEnd, gridStyle); + + // Put the resolved line indices back into the area structure. + areaInfo.mColumnStart = columnLines.mStart + mExplicitGridOffsetCol; + areaInfo.mColumnEnd = columnLines.mEnd + mExplicitGridOffsetCol; + areaInfo.mRowStart = rowLines.mStart + mExplicitGridOffsetRow; + areaInfo.mRowEnd = rowLines.mEnd + mExplicitGridOffsetRow; + } + } } void @@ -5809,18 +5855,23 @@ nsGridContainerFrame::Reflow(nsPresContext* aPresContext, } // Generate the line info properties. We need to provide the number of - // repeat tracks produced in the reflow. + // repeat tracks produced in the reflow. Only explicit names are assigned + // to lines here; the mozilla::dom::GridLines class will later extract + // implicit names from grid areas and assign them to the appropriate lines. // Generate column lines first. uint32_t capacity = gridReflowInput.mColFunctions.NumRepeatTracks() + gridReflowInput.mCols.mSizes.Length(); nsTArray> columnLineNames(capacity); for (col = 0; col <= gridReflowInput.mCols.mSizes.Length(); col++) { - columnLineNames.AppendElement( - gridReflowInput.mCols.GetLineNamesAtIndex( + // Offset col by the explicit grid offset, to get the original names. + nsTArray explicitNames = + gridReflowInput.mCols.GetExplicitLineNamesAtIndex( gridReflowInput.mGridStyle->mGridTemplateColumns, gridReflowInput.mColFunctions, - col)); + col - gridReflowInput.mColFunctions.mExplicitGridOffset); + + columnLineNames.AppendElement(explicitNames); } ComputedGridLineInfo* columnLineInfo = new ComputedGridLineInfo( Move(columnLineNames)); @@ -5831,11 +5882,14 @@ nsGridContainerFrame::Reflow(nsPresContext* aPresContext, gridReflowInput.mRows.mSizes.Length(); nsTArray> rowLineNames(capacity); for (row = 0; row <= gridReflowInput.mRows.mSizes.Length(); row++) { - rowLineNames.AppendElement( - gridReflowInput.mRows.GetLineNamesAtIndex( + // Offset row by the explicit grid offset, to get the original names. + nsTArray explicitNames = + gridReflowInput.mRows.GetExplicitLineNamesAtIndex( gridReflowInput.mGridStyle->mGridTemplateRows, gridReflowInput.mRowFunctions, - row)); + row - gridReflowInput.mRowFunctions.mExplicitGridOffset); + + rowLineNames.AppendElement(explicitNames); } ComputedGridLineInfo* rowLineInfo = new ComputedGridLineInfo( Move(rowLineNames)); diff --git a/layout/generic/nsGridContainerFrame.h b/layout/generic/nsGridContainerFrame.h index f3d16bbc374ca..2ad96dc53f7e2 100644 --- a/layout/generic/nsGridContainerFrame.h +++ b/layout/generic/nsGridContainerFrame.h @@ -151,7 +151,9 @@ class nsGridContainerFrame final : public nsContainerFrame return info; } - typedef nsTHashtable ImplicitNamedAreas; + typedef nsBaseHashtable ImplicitNamedAreas; NS_DECLARE_FRAME_PROPERTY_DELETABLE(ImplicitNamedAreasProperty, ImplicitNamedAreas) ImplicitNamedAreas* GetImplicitNamedAreas() const { diff --git a/layout/generic/nsTextFrame.cpp b/layout/generic/nsTextFrame.cpp index 1ad5990327b3b..78e2c33e9401c 100644 --- a/layout/generic/nsTextFrame.cpp +++ b/layout/generic/nsTextFrame.cpp @@ -9093,6 +9093,9 @@ nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth, } bool canTrimTrailingWhitespace = !textStyle->WhiteSpaceIsSignificant() || (GetStateBits() & TEXT_IS_IN_TOKEN_MATHML); + // allow whitespace to overflow the container + bool whitespaceCanHang = textStyle->WhiteSpaceCanWrapStyle() && + textStyle->WhiteSpaceIsSignificant(); gfxBreakPriority breakPriority = aLineLayout.LastOptionalBreakPriority(); gfxTextRun::SuppressBreak suppressBreak = gfxTextRun::eNoSuppressBreak; bool shouldSuppressLineBreak = ShouldSuppressLineBreak(); @@ -9107,6 +9110,7 @@ nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth, availWidth, &provider, suppressBreak, canTrimTrailingWhitespace ? &trimmedWidth : nullptr, + whitespaceCanHang, &textMetrics, boundingBoxType, aDrawTarget, &usedHyphenation, &transformedLastBreak, diff --git a/layout/printing/ipc/RemotePrintJobParent.cpp b/layout/printing/ipc/RemotePrintJobParent.cpp index 0e30cf2644483..e544d224e5582 100644 --- a/layout/printing/ipc/RemotePrintJobParent.cpp +++ b/layout/printing/ipc/RemotePrintJobParent.cpp @@ -130,10 +130,10 @@ RemotePrintJobParent::RecvFinalizePrint() // EndDocument is sometimes called in the child even when BeginDocument has // not been called. See bug 1223332. if (mPrintDeviceContext) { - nsresult rv = mPrintDeviceContext->EndDocument(); + DebugOnly rv = mPrintDeviceContext->EndDocument(); // Too late to abort the child just log. - NS_WARN_IF(NS_FAILED(rv)); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "EndDocument failed"); } diff --git a/layout/reftests/text/justification-1-ref.html b/layout/reftests/text/justification-1-ref.html index 34841a4b8e006..68a15e87d9b94 100644 --- a/layout/reftests/text/justification-1-ref.html +++ b/layout/reftests/text/justification-1-ref.html @@ -1,10 +1,10 @@ - +

I am the very model of a modern major-general.

-

I am the very model of a modern major-general.

-

I  am the
very model of a modern major-general.

+

I am the very model of a modern major-general.

+

I  am the
very model of a modern major-general.

I  ​am ​the
very ​model ​of ​a ​modern ​major-general.

I am the
very model of a modern major-general.

diff --git a/layout/reftests/text/justification-1.html b/layout/reftests/text/justification-1.html index 06e2c6d00991f..a12544fc1913e 100644 --- a/layout/reftests/text/justification-1.html +++ b/layout/reftests/text/justification-1.html @@ -1,6 +1,6 @@ - + diff --git a/layout/reftests/text/pre-wrap-1-ref.html b/layout/reftests/text/pre-wrap-1-ref.html new file mode 100644 index 0000000000000..7cda9fba13a29 --- /dev/null +++ b/layout/reftests/text/pre-wrap-1-ref.html @@ -0,0 +1,27 @@ + + + + +test for bug 1008019 + + + +
ab c d e f +g h i +j k +l m +n o +p +q +r +s
+ + diff --git a/layout/reftests/text/pre-wrap-1.html b/layout/reftests/text/pre-wrap-1.html new file mode 100644 index 0000000000000..782acc146c81d --- /dev/null +++ b/layout/reftests/text/pre-wrap-1.html @@ -0,0 +1,21 @@ + + + + +test for bug 1008019 + + + +
ab c d e f g h i j k l m n o p q r s
+ + diff --git a/layout/reftests/text/reftest.list b/layout/reftests/text/reftest.list index b6b4b4ba0a519..6ea7b97e58099 100644 --- a/layout/reftests/text/reftest.list +++ b/layout/reftests/text/reftest.list @@ -34,6 +34,7 @@ fuzzy-if(Android,255,147) == pre-line-1.html pre-line-1-ref.html == pre-line-3.html pre-line-3-ref.html == pre-line-4.html pre-line-4-ref.html == pre-space-1.html pre-space-1-ref.html +== pre-wrap-1.html pre-wrap-1-ref.html == soft-hyphens-1a.html soft-hyphens-1-ref.html == soft-hyphens-1b.html soft-hyphens-1-ref.html == soft-hyphens-1c.html soft-hyphens-1-ref.html diff --git a/layout/reftests/text/white-space-1-ref.html b/layout/reftests/text/white-space-1-ref.html index fa5b7ed2ca5f1..88351db062118 100644 --- a/layout/reftests/text/white-space-1-ref.html +++ b/layout/reftests/text/white-space-1-ref.html @@ -16,18 +16,18 @@ Kitty

Hello Kitty

Hello Kitty -

Hello +

Hello Kitty

Hello Kitty -

Hello +

Hello  Kitty

Hello Kitty -

Hello +

Hello Kitty

@@ -36,7 +36,7 @@ Kitty

Hello Kitty

Hello Kitty -

Hello +

Hello Kitty @@ -45,18 +45,18 @@ Kitty

Hello Kitty

Hello Kitty -

Hello +

Hello Kitty

-

Hello +

Hello  Kitty -

Hello +

Hello  Kitty -

Hello +

Hello  Kitty -

Hello +

Hello Kitty

diff --git a/layout/reftests/text/white-space-1a.html b/layout/reftests/text/white-space-1a.html index 90cec9ddd405f..4ae2034595d25 100644 --- a/layout/reftests/text/white-space-1a.html +++ b/layout/reftests/text/white-space-1a.html @@ -46,7 +46,7 @@

Hello Kitty

Hello Kitty

Hello Kitty -

Hello Kitty +

Hello Kitty diff --git a/layout/reftests/text/wordwrap-01-ref.html b/layout/reftests/text/wordwrap-01-ref.html index 8e1982b203af5..8f88fae973fab 100644 --- a/layout/reftests/text/wordwrap-01-ref.html +++ b/layout/reftests/text/wordwrap-01-ref.html @@ -14,6 +14,6 @@ ingoodbuzzincooltalk inhighwalkinfastlivi nevergivincoolfizzin - Firefox! +Firefox! diff --git a/layout/reftests/text/wordwrap-09-ref.html b/layout/reftests/text/wordwrap-09-ref.html index dc709b7effba6..a6dcbe642fd96 100644 --- a/layout/reftests/text/wordwrap-09-ref.html +++ b/layout/reftests/text/wordwrap-09-ref.html @@ -9,7 +9,7 @@ diff --git a/layout/reftests/w3c-css/submitted/masking/mask-opacity-1-ref.html b/layout/reftests/w3c-css/submitted/masking/mask-opacity-1-ref.html new file mode 100644 index 0000000000000..5def84f067a4e --- /dev/null +++ b/layout/reftests/w3c-css/submitted/masking/mask-opacity-1-ref.html @@ -0,0 +1,22 @@ + + + + + CSS Masking: mask-image: mask with opacity + + + + + +

+ + diff --git a/layout/reftests/w3c-css/submitted/masking/mask-opacity-1a.html b/layout/reftests/w3c-css/submitted/masking/mask-opacity-1a.html new file mode 100644 index 0000000000000..1bd42abfb1480 --- /dev/null +++ b/layout/reftests/w3c-css/submitted/masking/mask-opacity-1a.html @@ -0,0 +1,28 @@ + + + + + CSS Masking: mask-image: mask with filter and opacity + + + + + + + + +
+ + diff --git a/layout/reftests/w3c-css/submitted/masking/mask-opacity-1b.html b/layout/reftests/w3c-css/submitted/masking/mask-opacity-1b.html new file mode 100644 index 0000000000000..0de78f7612396 --- /dev/null +++ b/layout/reftests/w3c-css/submitted/masking/mask-opacity-1b.html @@ -0,0 +1,32 @@ + + + + + CSS Masking: mask-image: mask with opacity + + + + + + + + + + + + + +
+ + diff --git a/layout/reftests/w3c-css/submitted/masking/mask-opacity-1c.html b/layout/reftests/w3c-css/submitted/masking/mask-opacity-1c.html new file mode 100644 index 0000000000000..1673d7c4e89ab --- /dev/null +++ b/layout/reftests/w3c-css/submitted/masking/mask-opacity-1c.html @@ -0,0 +1,27 @@ + + + + + CSS Masking: mask-image: filter with opacity + + + + + + + + +
+ + diff --git a/layout/reftests/w3c-css/submitted/masking/reftest.list b/layout/reftests/w3c-css/submitted/masking/reftest.list index 7ee89d8f7fe78..6c6507f332f89 100644 --- a/layout/reftests/w3c-css/submitted/masking/reftest.list +++ b/layout/reftests/w3c-css/submitted/masking/reftest.list @@ -99,3 +99,8 @@ fuzzy(64,311) == clip-path-viewBox-1c.html clip-path-geometryBox-1-ref.html fuzzy-if(winWidget,1,98) == clip-path-geometryBox-2.html clip-path-geometryBox-2-ref.html default-preferences + +# mask with opacity test cases +fuzzy(1,5000) == mask-opacity-1a.html mask-opacity-1-ref.html +fuzzy(1,5000) == mask-opacity-1b.html mask-opacity-1-ref.html +fuzzy(1,5000) == mask-opacity-1c.html mask-opacity-1-ref.html diff --git a/layout/style/nsStyleContext.h b/layout/style/nsStyleContext.h index c8ac09e92c1fd..9e5bf5895e8bf 100644 --- a/layout/style/nsStyleContext.h +++ b/layout/style/nsStyleContext.h @@ -695,8 +695,9 @@ class nsStyleContext final if (mPseudoTag == nsCSSAnonBoxes::mozText) { \ MOZ_ASSERT(mParent); \ newData = mParent->DoGetStyle##name_(); \ - NS_WARN_IF(newData != \ - Servo_GetStyle##name_(mSource.AsServoComputedValues())); \ + NS_WARNING_ASSERTION( \ + newData == Servo_GetStyle##name_(mSource.AsServoComputedValues()), \ + "bad newData"); \ } else { \ newData = \ Servo_GetStyle##name_(mSource.AsServoComputedValues()); \ diff --git a/layout/svg/nsSVGIntegrationUtils.cpp b/layout/svg/nsSVGIntegrationUtils.cpp index 8bfb4cd6fc562..2b306e10c1e07 100644 --- a/layout/svg/nsSVGIntegrationUtils.cpp +++ b/layout/svg/nsSVGIntegrationUtils.cpp @@ -165,8 +165,7 @@ nsSVGIntegrationUtils::UsingMaskOrClipPathForFrame(const nsIFrame* aFrame) { const nsStyleSVGReset *style = aFrame->StyleSVGReset(); return style->HasClipPath() || - style->mMask.HasLayerWithImage() || - (aFrame->StyleEffects()->mOpacity != 1.0f); + style->mMask.HasLayerWithImage(); } // For non-SVG frames, this gives the offset to the frame's "user space". @@ -617,15 +616,10 @@ static float ComputeOpacity(const nsSVGIntegrationUtils::PaintFramesParams& aParams) { nsIFrame* frame = aParams.frame; - - MOZ_ASSERT(!nsSVGUtils::CanOptimizeOpacity(frame) || - !aParams.callerPaintsOpacity, - "How can we be optimizing the opacity into the svg as well as having the caller paint it?"); - float opacity = frame->StyleEffects()->mOpacity; if (opacity != 1.0f && - (nsSVGUtils::CanOptimizeOpacity(frame) || aParams.callerPaintsOpacity)) { + (nsSVGUtils::CanOptimizeOpacity(frame) || !aParams.handleOpacity)) { return 1.0f; } @@ -758,6 +752,10 @@ BlendToTarget(const nsSVGIntegrationUtils::PaintFramesParams& aParams, DrawResult nsSVGIntegrationUtils::PaintMaskAndClipPath(const PaintFramesParams& aParams) { + MOZ_ASSERT(UsingMaskOrClipPathForFrame(aParams.frame), + "Should not use this method when no mask or clipPath effect" + "on this frame"); + /* SVG defines the following rendering model: * * 1. Render geometry @@ -926,7 +924,10 @@ nsSVGIntegrationUtils::PaintMaskAndClipPath(const PaintFramesParams& aParams) DrawResult nsSVGIntegrationUtils::PaintFilter(const PaintFramesParams& aParams) { - MOZ_ASSERT(!aParams.builder->IsForGenerateGlyphMask()); + MOZ_ASSERT(!aParams.builder->IsForGenerateGlyphMask(), + "Filter effect is discarded while generating glyph mask."); + MOZ_ASSERT(aParams.frame->StyleEffects()->HasFilters(), + "Should not use this method when no filter effect on this frame"); nsIFrame* frame = aParams.frame; DrawResult result = DrawResult::SUCCESS; @@ -969,6 +970,18 @@ nsSVGIntegrationUtils::PaintFilter(const PaintFramesParams& aParams) return DrawResult::TEMPORARY_ERROR; } + if (opacity != 1.0f) { + context.Save(); + nsRect clipRect = + frame->GetVisualOverflowRectRelativeToSelf() + toUserSpace; + context.Clip(NSRectToSnappedRect(clipRect, + frame->PresContext()->AppUnitsPerDevPixel(), + *context.GetDrawTarget())); + + target->PushGroupForBlendBack(gfxContentType::COLOR_ALPHA, opacity, + nullptr, Matrix()); + } + /* Paint the child and apply filters */ RegularFramePaintCallback callback(aParams.builder, aParams.layerManager, offsetToUserSpace); @@ -977,6 +990,11 @@ nsSVGIntegrationUtils::PaintFilter(const PaintFramesParams& aParams) nsFilterInstance::PaintFilteredFrame(frame, target->GetDrawTarget(), tm, &callback, &dirtyRegion); + if (opacity != 1.0f) { + target->PopGroupAndBlend(); + context.Restore(); + } + if (aParams.frame->StyleEffects()->mMixBlendMode != NS_STYLE_BLEND_NORMAL) { MOZ_ASSERT(target != &aParams.ctx); BlendToTarget(aParams, target, targetOffset); diff --git a/layout/svg/nsSVGIntegrationUtils.h b/layout/svg/nsSVGIntegrationUtils.h index 24c0828faccb8..cb90ebfc2f493 100644 --- a/layout/svg/nsSVGIntegrationUtils.h +++ b/layout/svg/nsSVGIntegrationUtils.h @@ -136,16 +136,17 @@ class nsSVGIntegrationUtils final const nsRect& borderArea; nsDisplayListBuilder* builder; mozilla::layers::LayerManager* layerManager; - bool callerPaintsOpacity; + bool handleOpacity; // If true, PaintMaskAndClipPath/ PaintFilter should + // apply css opacity. explicit PaintFramesParams(gfxContext& aCtx, nsIFrame* aFrame, const nsRect& aDirtyRect, const nsRect& aBorderArea, nsDisplayListBuilder* aBuilder, mozilla::layers::LayerManager* aLayerManager, - bool aCallerPaintsOpacity) + bool aHandleOpacity) : ctx(aCtx), frame(aFrame), dirtyRect(aDirtyRect), borderArea(aBorderArea), builder(aBuilder), - layerManager(aLayerManager), callerPaintsOpacity(aCallerPaintsOpacity) + layerManager(aLayerManager), handleOpacity(aHandleOpacity) { } }; diff --git a/media/webrtc/signaling/src/media-conduit/WebrtcOMXH264VideoCodec.cpp b/media/webrtc/signaling/src/media-conduit/WebrtcOMXH264VideoCodec.cpp index 6ac547316000b..dc052f4e032a4 100644 --- a/media/webrtc/signaling/src/media-conduit/WebrtcOMXH264VideoCodec.cpp +++ b/media/webrtc/signaling/src/media-conduit/WebrtcOMXH264VideoCodec.cpp @@ -1141,7 +1141,7 @@ WebrtcOMXH264VideoEncoder::SetRates(uint32_t aBitRateKbps, uint32_t aFrameRate) } mBitRateKbps = aBitRateKbps; nsresult rv = mOMX->SetBitrate(mBitRateKbps); - NS_WARN_IF(NS_FAILED(rv)); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "SetBitrate failed"); return NS_FAILED(rv) ? WEBRTC_VIDEO_CODEC_OK : WEBRTC_VIDEO_CODEC_ERROR; } diff --git a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp index b45834732e9ad..1cd0d7d883629 100644 --- a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp +++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp @@ -42,7 +42,6 @@ #include "nsIURI.h" #include "nsIScriptSecurityManager.h" #include "nsICancelable.h" -#include "nsIDocument.h" #include "nsILoadInfo.h" #include "nsIContentPolicy.h" #include "nsIProxyInfo.h" diff --git a/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java b/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java index 13f349dd96489..d68090c58a310 100644 --- a/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java +++ b/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java @@ -1154,8 +1154,6 @@ public void onCreate(Bundle savedInstanceState) { // sending notifications immediately after startup, which we don't want to lose/crash on. GeckoAppShell.setNotificationClient(makeNotificationClient()); - Tabs.getInstance().attachToContext(this); - // Tell Stumbler to register a local broadcast listener to listen for preference intents. // We do this via intents since we can't easily access Stumbler directly, // as it might be compiled outside of Fennec. @@ -1267,6 +1265,8 @@ public void run() { mMainLayout = (RelativeLayout) findViewById(R.id.main_layout); mLayerView = (GeckoView) findViewById(R.id.layer_view); + Tabs.getInstance().attachToContext(this, mLayerView); + // Use global layout state change to kick off additional initialization mMainLayout.getViewTreeObserver().addOnGlobalLayoutListener(this); @@ -2879,4 +2879,8 @@ public String getDefaultChromeURI() { // Use the chrome URI specified by Gecko's defaultChromeURI pref. return null; } + + public GeckoView getGeckoView() { + return mLayerView; + } } diff --git a/mobile/android/base/java/org/mozilla/gecko/PrivateTab.java b/mobile/android/base/java/org/mozilla/gecko/PrivateTab.java index 2d5c4c1968a98..39b6899d3fbae 100644 --- a/mobile/android/base/java/org/mozilla/gecko/PrivateTab.java +++ b/mobile/android/base/java/org/mozilla/gecko/PrivateTab.java @@ -7,8 +7,6 @@ import android.content.Context; -import android.support.v4.content.ContextCompat; - import org.json.JSONObject; import org.mozilla.gecko.db.BrowserDB; diff --git a/mobile/android/base/java/org/mozilla/gecko/Tabs.java b/mobile/android/base/java/org/mozilla/gecko/Tabs.java index 7fa3cb47e5131..46f432e1e027a 100644 --- a/mobile/android/base/java/org/mozilla/gecko/Tabs.java +++ b/mobile/android/base/java/org/mozilla/gecko/Tabs.java @@ -19,6 +19,7 @@ import org.mozilla.gecko.annotation.RobocopTarget; import org.mozilla.gecko.AppConstants.Versions; import org.mozilla.gecko.db.BrowserDB; +import org.mozilla.gecko.gfx.LayerView; import org.mozilla.gecko.mozglue.SafeIntent; import org.mozilla.gecko.notifications.WhatsNewReceiver; import org.mozilla.gecko.reader.ReaderModeUtils; @@ -36,6 +37,7 @@ import android.net.Uri; import android.os.Handler; import android.provider.Browser; +import android.support.v4.content.ContextCompat; import android.util.Log; public class Tabs implements GeckoEventListener { @@ -75,8 +77,10 @@ public class Tabs implements GeckoEventListener { private volatile boolean mInitialTabsAdded; private Context mAppContext; + private LayerView mLayerView; private ContentObserver mBookmarksContentObserver; private PersistTabsRunnable mPersistTabsRunnable; + private int mPrivateClearColor; private static class PersistTabsRunnable implements Runnable { private final BrowserDB db; @@ -121,9 +125,11 @@ private Tabs() { "Tab:StreamStop", "Tab:AudioPlayingChange"); + mPrivateClearColor = Color.RED; + } - public synchronized void attachToContext(Context context) { + public synchronized void attachToContext(Context context, LayerView layerView) { final Context appContext = context.getApplicationContext(); if (mAppContext == appContext) { return; @@ -135,6 +141,8 @@ public synchronized void attachToContext(Context context) { } mAppContext = appContext; + mLayerView = layerView; + mPrivateClearColor = ContextCompat.getColor(context, R.color.tabs_tray_grey_pressed); mAccountManager = AccountManager.get(appContext); mAccountListener = new OnAccountsUpdateListener() { @@ -250,6 +258,10 @@ public synchronized Tab selectTab(int id) { mSelectedTab = tab; notifyListeners(tab, TabEvents.SELECTED); + if (mLayerView != null) { + mLayerView.setClearColor(getTabColor(tab)); + } + if (oldTab != null) { notifyListeners(oldTab, TabEvents.UNSELECTED); } @@ -660,6 +672,10 @@ private void onTabChanged(Tab tab, Tabs.TabEvents msg, Object data) { // are also selected/unselected, so it would be redundant to also listen // for ADDED/CLOSED events. case SELECTED: + if (mLayerView != null) { + mLayerView.setSurfaceBackgroundColor(getTabColor(tab)); + mLayerView.setPaintState(LayerView.PAINT_START); + } queuePersistAllTabs(); case UNSELECTED: tab.onChange(); @@ -971,4 +987,12 @@ public void loadUrlInTab(String url) { public static int getNextTabId() { return sTabId.getAndIncrement(); } + + private int getTabColor(Tab tab) { + if (tab != null) { + return tab.isPrivate() ? mPrivateClearColor : Color.WHITE; + } + + return Color.WHITE; + } } diff --git a/mobile/android/base/java/org/mozilla/gecko/dlc/catalog/DownloadContentCatalog.java b/mobile/android/base/java/org/mozilla/gecko/dlc/catalog/DownloadContentCatalog.java index 0a4d4bb6ee1fd..43ba4e82e0280 100644 --- a/mobile/android/base/java/org/mozilla/gecko/dlc/catalog/DownloadContentCatalog.java +++ b/mobile/android/base/java/org/mozilla/gecko/dlc/catalog/DownloadContentCatalog.java @@ -234,6 +234,12 @@ protected synchronized void loadFromDisk() { // Catalog seems to be broken. Re-create catalog: loadedContent = DownloadContentBootstrap.createInitialDownloadContentList(); hasCatalogChanged = true; // Indicate that we want to persist the new catalog + } catch (NullPointerException e) { + // Bad content can produce an NPE in JSON code -- bug 1300139 + Log.w(LOGTAG, "Unable to parse catalog JSON. Re-creating catalog.", e); + // Catalog seems to be broken. Re-create catalog: + loadedContent = DownloadContentBootstrap.createInitialDownloadContentList(); + hasCatalogChanged = true; // Indicate that we want to persist the new catalog } catch (UnsupportedEncodingException e) { AssertionError error = new AssertionError("Should not happen: This device does not speak UTF-8"); error.initCause(e); diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/GeckoLayerClient.java b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/GeckoLayerClient.java index 5206ff89d9857..e34e63207076f 100644 --- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/GeckoLayerClient.java +++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/GeckoLayerClient.java @@ -17,6 +17,7 @@ import org.mozilla.gecko.AppConstants; import android.content.Context; +import android.graphics.Color; import android.graphics.Matrix; import android.graphics.PointF; import android.graphics.RectF; @@ -106,6 +107,9 @@ class GeckoLayerClient implements LayerView.Listener, PanZoomTarget private SynthesizedEventState mPointerState; + @WrapForJNI(stubName = "ClearColor") + private volatile int mClearColor = Color.WHITE; + public GeckoLayerClient(Context context, LayerView view, EventDispatcher eventDispatcher) { // we can fill these in with dummy values because they are always written // to before being read @@ -901,4 +905,8 @@ public void addDrawListener(DrawListener listener) { public void removeDrawListener(DrawListener listener) { mDrawListeners.remove(listener); } + + public void setClearColor(int color) { + mClearColor = color; + } } diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/LayerView.java b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/LayerView.java index 8e3faf4e811ea..57fc7138061e7 100644 --- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/LayerView.java +++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/LayerView.java @@ -394,7 +394,7 @@ public Matrix getMatrixForLayerRectToViewRect() { return mLayerClient.getMatrixForLayerRectToViewRect(); } - void setSurfaceBackgroundColor(int newColor) { + public void setSurfaceBackgroundColor(int newColor) { if (mSurfaceView != null) { mSurfaceView.setBackgroundColor(newColor); } @@ -794,4 +794,9 @@ public void removeZoomedViewListener(ZoomedViewListener listener) { mRenderer.removeZoomedViewListener(listener); } + public void setClearColor(int color) { + if (mLayerClient != null) { + mLayerClient.setClearColor(color); + } + } } diff --git a/moz.build b/moz.build index 2c02ec3a01373..fa20fa0fb5888 100644 --- a/moz.build +++ b/moz.build @@ -57,6 +57,7 @@ DIRS += [ 'memory', 'mfbt', 'mozglue', + 'tools/fuzzing', ] if not CONFIG['JS_STANDALONE']: diff --git a/netwerk/base/NetworkInfoServiceCocoa.cpp b/netwerk/base/NetworkInfoServiceCocoa.cpp index ae8983bd366fa..937c726583902 100644 --- a/netwerk/base/NetworkInfoServiceCocoa.cpp +++ b/netwerk/base/NetworkInfoServiceCocoa.cpp @@ -12,6 +12,7 @@ #include #include +#include "mozilla/DebugOnly.h" #include "mozilla/ScopeExit.h" #include "NetworkInfoServiceImpl.h" @@ -52,8 +53,9 @@ DoListAddresses(AddrMapType& aAddrMap) while (i < ifconf.ifc_len) { size_t len = IFNAMSIZ + ifreq->ifr_addr.sa_len; - nsresult rv = ListInterfaceAddresses(fd, ifreq->ifr_name, aAddrMap); - NS_WARN_IF(NS_FAILED(rv)); + DebugOnly rv = + ListInterfaceAddresses(fd, ifreq->ifr_name, aAddrMap); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "ListInterfaceAddresses failed"); ifreq = (struct ifreq*) ((char*)ifreq + len); i += len; diff --git a/netwerk/base/NetworkInfoServiceLinux.cpp b/netwerk/base/NetworkInfoServiceLinux.cpp index 287c583f41e97..96627cfecd319 100644 --- a/netwerk/base/NetworkInfoServiceLinux.cpp +++ b/netwerk/base/NetworkInfoServiceLinux.cpp @@ -12,6 +12,7 @@ #include #include +#include "mozilla/DebugOnly.h" #include "mozilla/ScopeExit.h" #include "NetworkInfoServiceImpl.h" @@ -52,8 +53,9 @@ DoListAddresses(AddrMapType& aAddrMap) while (i < ifconf.ifc_len) { size_t len = sizeof(struct ifreq); - nsresult rv = ListInterfaceAddresses(fd, ifreq->ifr_name, aAddrMap); - NS_WARN_IF(NS_FAILED(rv)); + DebugOnly rv = + ListInterfaceAddresses(fd, ifreq->ifr_name, aAddrMap); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "ListInterfaceAddresses failed"); ifreq = (struct ifreq*) ((char*)ifreq + len); i += len; diff --git a/netwerk/dns/mdns/libmdns/MDNSResponderOperator.cpp b/netwerk/dns/mdns/libmdns/MDNSResponderOperator.cpp index 9d9bd3f6c368e..04e5b3ec7ebd6 100644 --- a/netwerk/dns/mdns/libmdns/MDNSResponderOperator.cpp +++ b/netwerk/dns/mdns/libmdns/MDNSResponderOperator.cpp @@ -8,6 +8,7 @@ #include "mozilla/EndianUtils.h" #include "mozilla/Logging.h" #include "mozilla/ScopeExit.h" +#include "mozilla/Unused.h" #include "nsComponentManagerUtils.h" #include "nsCOMPtr.h" #include "nsDebug.h" @@ -335,7 +336,7 @@ BrowseOperator::Start() nullptr, &BrowseReplyRunnable::Reply, this); - NS_WARN_IF(kDNSServiceErr_NoError != err); + NS_WARNING_ASSERTION(kDNSServiceErr_NoError == err, "DNSServiceBrowse fail"); if (mListener) { if (kDNSServiceErr_NoError == err) { @@ -491,7 +492,8 @@ RegisterOperator::Start() TXTRecordGetBytesPtr(&txtRecord), &RegisterReplyRunnable::Reply, this); - NS_WARN_IF(kDNSServiceErr_NoError != err); + NS_WARNING_ASSERTION(kDNSServiceErr_NoError == err, + "DNSServiceRegister fail"); TXTRecordDeallocate(&txtRecord); @@ -620,7 +622,7 @@ ResolveOperator::Reply(DNSServiceRef aSdRef, MOZ_ASSERT(GetThread() == NS_GetCurrentThread()); auto guard = MakeScopeExit([this] { - NS_WARN_IF(NS_FAILED(Stop())); + Unused << NS_WARN_IF(NS_FAILED(Stop())); }); if (NS_WARN_IF(kDNSServiceErr_NoError != aErrorCode)) { @@ -674,7 +676,7 @@ ResolveOperator::Reply(DNSServiceRef aSdRef, } else { mListener->OnResolveFailed(info, aErrorCode); - NS_WARN_IF(NS_FAILED(Stop())); + Unused << NS_WARN_IF(NS_FAILED(Stop())); } } @@ -683,7 +685,7 @@ ResolveOperator::GetAddrInfor(nsIDNSServiceInfo* aServiceInfo) { RefPtr getAddreOp = new GetAddrInfoOperator(aServiceInfo, mListener); - NS_WARN_IF(NS_FAILED(getAddreOp->Start())); + Unused << NS_WARN_IF(NS_FAILED(getAddreOp->Start())); } GetAddrInfoOperator::GetAddrInfoOperator(nsIDNSServiceInfo* aServiceInfo, @@ -739,7 +741,7 @@ GetAddrInfoOperator::Reply(DNSServiceRef aSdRef, MOZ_ASSERT(GetThread() == NS_GetCurrentThread()); auto guard = MakeScopeExit([this] { - NS_WARN_IF(NS_FAILED(Stop())); + Unused << NS_WARN_IF(NS_FAILED(Stop())); }); if (NS_WARN_IF(kDNSServiceErr_NoError != aErrorCode)) { diff --git a/netwerk/dns/mdns/libmdns/nsDNSServiceInfo.cpp b/netwerk/dns/mdns/libmdns/nsDNSServiceInfo.cpp index da82d0f87b27e..7c67b49ac797b 100644 --- a/netwerk/dns/mdns/libmdns/nsDNSServiceInfo.cpp +++ b/netwerk/dns/mdns/libmdns/nsDNSServiceInfo.cpp @@ -8,6 +8,7 @@ #include "nsIProperty.h" #include "nsISimpleEnumerator.h" #include "nsISupportsImpl.h" +#include "mozilla/Unused.h" namespace mozilla { namespace net { @@ -24,22 +25,22 @@ nsDNSServiceInfo::nsDNSServiceInfo(nsIDNSServiceInfo* aServiceInfo) uint16_t value; if (NS_SUCCEEDED(aServiceInfo->GetHost(str))) { - NS_WARN_IF(NS_FAILED(SetHost(str))); + Unused << NS_WARN_IF(NS_FAILED(SetHost(str))); } if (NS_SUCCEEDED(aServiceInfo->GetAddress(str))) { - NS_WARN_IF(NS_FAILED(SetAddress(str))); + Unused << NS_WARN_IF(NS_FAILED(SetAddress(str))); } if (NS_SUCCEEDED(aServiceInfo->GetPort(&value))) { - NS_WARN_IF(NS_FAILED(SetPort(value))); + Unused << NS_WARN_IF(NS_FAILED(SetPort(value))); } if (NS_SUCCEEDED(aServiceInfo->GetServiceName(str))) { - NS_WARN_IF(NS_FAILED(SetServiceName(str))); + Unused << NS_WARN_IF(NS_FAILED(SetServiceName(str))); } if (NS_SUCCEEDED(aServiceInfo->GetServiceType(str))) { - NS_WARN_IF(NS_FAILED(SetServiceType(str))); + Unused << NS_WARN_IF(NS_FAILED(SetServiceType(str))); } if (NS_SUCCEEDED(aServiceInfo->GetDomainName(str))) { - NS_WARN_IF(NS_FAILED(SetDomainName(str))); + Unused << NS_WARN_IF(NS_FAILED(SetDomainName(str))); } nsCOMPtr attributes; // deep copy @@ -55,21 +56,22 @@ nsDNSServiceInfo::nsDNSServiceInfo(nsIDNSServiceInfo* aServiceInfo) while (NS_SUCCEEDED(enumerator->HasMoreElements(&hasMoreElements)) && hasMoreElements) { nsCOMPtr element; - NS_WARN_IF(NS_FAILED(enumerator->GetNext(getter_AddRefs(element)))); + Unused << + NS_WARN_IF(NS_FAILED(enumerator->GetNext(getter_AddRefs(element)))); nsCOMPtr property = do_QueryInterface(element); MOZ_ASSERT(property); nsAutoString name; nsCOMPtr value; - NS_WARN_IF(NS_FAILED(property->GetName(name))); - NS_WARN_IF(NS_FAILED(property->GetValue(getter_AddRefs(value)))); + Unused << NS_WARN_IF(NS_FAILED(property->GetName(name))); + Unused << NS_WARN_IF(NS_FAILED(property->GetValue(getter_AddRefs(value)))); nsAutoCString valueStr; - NS_WARN_IF(NS_FAILED(value->GetAsACString(valueStr))); + Unused << NS_WARN_IF(NS_FAILED(value->GetAsACString(valueStr))); - NS_WARN_IF(NS_FAILED(newAttributes->SetPropertyAsACString(name, valueStr))); + Unused << NS_WARN_IF(NS_FAILED(newAttributes->SetPropertyAsACString(name, valueStr))); } - NS_WARN_IF(NS_FAILED(SetAttributes(newAttributes))); + Unused << NS_WARN_IF(NS_FAILED(SetAttributes(newAttributes))); } } diff --git a/netwerk/ipc/ChannelEventQueue.cpp b/netwerk/ipc/ChannelEventQueue.cpp index ae55ebd032bfa..b9bd2b34417ad 100644 --- a/netwerk/ipc/ChannelEventQueue.cpp +++ b/netwerk/ipc/ChannelEventQueue.cpp @@ -7,6 +7,7 @@ #include "nsISupports.h" #include "mozilla/net/ChannelEventQueue.h" +#include "mozilla/Unused.h" #include "nsThreadUtils.h" namespace mozilla { @@ -73,7 +74,7 @@ ChannelEventQueue::Resume() mTargetThread->Dispatch(event.forget(), NS_DISPATCH_NORMAL); } else { MOZ_RELEASE_ASSERT(NS_IsMainThread()); - NS_WARN_IF(NS_FAILED(NS_DispatchToCurrentThread(event.forget()))); + Unused << NS_WARN_IF(NS_FAILED(NS_DispatchToCurrentThread(event.forget()))); } } } diff --git a/netwerk/protocol/http/HttpChannelChild.cpp b/netwerk/protocol/http/HttpChannelChild.cpp index 0ce2563d8cdcb..4c8a77069a7ba 100644 --- a/netwerk/protocol/http/HttpChannelChild.cpp +++ b/netwerk/protocol/http/HttpChannelChild.cpp @@ -1990,12 +1990,16 @@ HttpChannelChild::ContinueAsyncOpen() return NS_ERROR_FAILURE; } + ContentChild* cc = static_cast(gNeckoChild->Manager()); + if (cc->IsShuttingDown()) { + return NS_ERROR_FAILURE; + } + // The socket transport in the chrome process now holds a logical ref to us // until OnStopRequest, or we do a redirect, or we hit an IPDL error. AddIPDLReference(); - PBrowserOrId browser = static_cast(gNeckoChild->Manager()) - ->GetBrowserOrId(tabChild); + PBrowserOrId browser = cc->GetBrowserOrId(tabChild); if (!gNeckoChild->SendPHttpChannelConstructor(this, browser, IPC::SerializedLoadContext(this), openArgs)) { diff --git a/netwerk/protocol/http/HttpChannelParentListener.cpp b/netwerk/protocol/http/HttpChannelParentListener.cpp index bcc356e92eaef..59030cf99c63c 100644 --- a/netwerk/protocol/http/HttpChannelParentListener.cpp +++ b/netwerk/protocol/http/HttpChannelParentListener.cpp @@ -10,9 +10,12 @@ #include "HttpChannelParentListener.h" #include "mozilla/net/HttpChannelParent.h" #include "mozilla/Unused.h" -#include "nsIRedirectChannelRegistrar.h" +#include "nsIAuthPrompt.h" +#include "nsIAuthPrompt2.h" #include "nsIHttpEventSink.h" #include "nsIHttpHeaderVisitor.h" +#include "nsIRedirectChannelRegistrar.h" +#include "nsIPromptFactory.h" #include "nsQueryObject.h" using mozilla::Unused; @@ -132,6 +135,17 @@ HttpChannelParentListener::GetInterface(const nsIID& aIID, void **result) return ir->GetInterface(aIID, result); } + if (aIID.Equals(NS_GET_IID(nsIAuthPrompt)) || + aIID.Equals(NS_GET_IID(nsIAuthPrompt2))) { + nsresult rv; + nsCOMPtr wwatch = + do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + return wwatch->GetPrompt(nullptr, aIID, + reinterpret_cast(result)); + } + return NS_NOINTERFACE; } diff --git a/netwerk/protocol/http/PackagedAppService.cpp b/netwerk/protocol/http/PackagedAppService.cpp index 24a509905ef0d..5797a4f91ed81 100644 --- a/netwerk/protocol/http/PackagedAppService.cpp +++ b/netwerk/protocol/http/PackagedAppService.cpp @@ -465,7 +465,7 @@ PackagedAppService::PackagedAppDownloader::OnStartRequest(nsIRequest *aRequest, MOZ_ASSERT(mWriter); rv = mWriter->OnStartRequest(aRequest, aContext); - NS_WARN_IF(NS_FAILED(rv)); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "OnStartRequest failed"); EnsureVerifier(aRequest); diff --git a/netwerk/protocol/http/nsHttpRequestHead.cpp b/netwerk/protocol/http/nsHttpRequestHead.cpp index 0d6fdd1878975..094a794570945 100644 --- a/netwerk/protocol/http/nsHttpRequestHead.cpp +++ b/netwerk/protocol/http/nsHttpRequestHead.cpp @@ -6,9 +6,6 @@ // HttpLog.h should generally be included first #include "HttpLog.h" -#ifdef MOZ_CRASHREPORTER -#include "nsExceptionHandler.h" -#endif #include "nsHttpRequestHead.h" #include "nsIHttpHeaderVisitor.h" @@ -19,34 +16,6 @@ namespace mozilla { namespace net { -#ifdef MOZ_CRASHREPORTER - -void nsHttpRequestHead::DbgReentrantMonitorAutoEnter::DbgCheck(bool aIn) -{ - nsHttpAtom header; - if (!mInstance.mAnnotated && mInstance.mHeaders.Count() && - !mInstance.mHeaders.PeekHeaderAt(0, header)) { - nsAutoCString str; - str.Append(nsPrintfCString("%s %s", aIn ? "in" : "out", mFunc)); - // Output the content of the array header and the first nsEntry. - const uint8_t* p = reinterpret_cast - (mInstance.mHeaders.mHeaders.Elements()) - sizeof(nsTArrayHeader); - for (int i = 0; i < 28; ++i, ++p) { - str.Append(nsPrintfCString(" %02x", *p)); - } - CrashReporter::AnnotateCrashReport( - NS_LITERAL_CSTRING("InvalidHttpHeaderArray"), str); - // Make sure we annotate only when we found it is invalid at the first - // time. - mInstance.mAnnotated = true; - } -} - -#define ReentrantMonitorAutoEnter DbgReentrantMonitorAutoEnter -#define mon(x) mon(*this, __func__) - -#endif - nsHttpRequestHead::nsHttpRequestHead() : mMethod(NS_LITERAL_CSTRING("GET")) , mVersion(NS_HTTP_VERSION_1_1) @@ -54,9 +23,6 @@ nsHttpRequestHead::nsHttpRequestHead() , mHTTPS(false) , mReentrantMonitor("nsHttpRequestHead.mReentrantMonitor") , mInVisitHeaders(false) -#ifdef MOZ_CRASHREPORTER - , mAnnotated(false) -#endif { MOZ_COUNT_CTOR(nsHttpRequestHead); } @@ -399,10 +365,5 @@ nsHttpRequestHead::Flatten(nsACString &buf, bool pruneProxyHeaders) mHeaders.Flatten(buf, pruneProxyHeaders, false); } -#ifdef MOZ_CRASHREPORTER -#undef ReentrantMonitorAutoEnter -#undef mon -#endif - } // namespace net } // namespace mozilla diff --git a/netwerk/protocol/http/nsHttpRequestHead.h b/netwerk/protocol/http/nsHttpRequestHead.h index 0d5e4eda22fef..4159680834777 100644 --- a/netwerk/protocol/http/nsHttpRequestHead.h +++ b/netwerk/protocol/http/nsHttpRequestHead.h @@ -120,33 +120,6 @@ class nsHttpRequestHead // During VisitHeader we sould not allow cal to SetHeader. bool mInVisitHeaders; - -#ifdef MOZ_CRASHREPORTER - class DbgReentrantMonitorAutoEnter : ReentrantMonitorAutoEnter - { - public: - explicit DbgReentrantMonitorAutoEnter(nsHttpRequestHead& aInstance, - const char* aFunc) - : ReentrantMonitorAutoEnter(aInstance.mReentrantMonitor), - mInstance(aInstance), - mFunc(aFunc) - { - DbgCheck(true); - } - ~DbgReentrantMonitorAutoEnter(void) - { - DbgCheck(false); - } - - private: - void DbgCheck(bool aIn); - - nsHttpRequestHead& mInstance; - const char* mFunc; - }; - - bool mAnnotated; -#endif }; } // namespace net diff --git a/netwerk/protocol/websocket/WebSocketEventService.cpp b/netwerk/protocol/websocket/WebSocketEventService.cpp index a7c9723809dcf..2f9486a706ae4 100644 --- a/netwerk/protocol/websocket/WebSocketEventService.cpp +++ b/netwerk/protocol/websocket/WebSocketEventService.cpp @@ -83,15 +83,14 @@ class WebSocketFrameRunnable final : public WebSocketBaseRunnable private: virtual void DoWork(nsIWebSocketEventListener* aListener) override { - nsresult rv; - + DebugOnly rv; if (mFrameSent) { rv = aListener->FrameSent(mWebSocketSerialID, mFrame); } else { rv = aListener->FrameReceived(mWebSocketSerialID, mFrame); } - NS_WARN_IF(NS_FAILED(rv)); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Frame op failed"); } RefPtr mFrame; @@ -113,9 +112,9 @@ class WebSocketCreatedRunnable final : public WebSocketBaseRunnable private: virtual void DoWork(nsIWebSocketEventListener* aListener) override { - nsresult rv = aListener->WebSocketCreated(mWebSocketSerialID, - mURI, mProtocols); - NS_WARN_IF(NS_FAILED(rv)); + DebugOnly rv = + aListener->WebSocketCreated(mWebSocketSerialID, mURI, mProtocols); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WebSocketCreated failed"); } const nsString mURI; @@ -139,11 +138,11 @@ class WebSocketOpenedRunnable final : public WebSocketBaseRunnable private: virtual void DoWork(nsIWebSocketEventListener* aListener) override { - nsresult rv = aListener->WebSocketOpened(mWebSocketSerialID, - mEffectiveURI, - mProtocols, - mExtensions); - NS_WARN_IF(NS_FAILED(rv)); + DebugOnly rv = aListener->WebSocketOpened(mWebSocketSerialID, + mEffectiveURI, + mProtocols, + mExtensions); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WebSocketOpened failed"); } const nsString mEffectiveURI; @@ -166,9 +165,10 @@ class WebSocketMessageAvailableRunnable final : public WebSocketBaseRunnable private: virtual void DoWork(nsIWebSocketEventListener* aListener) override { - nsresult rv = aListener->WebSocketMessageAvailable(mWebSocketSerialID, - mData, mMessageType); - NS_WARN_IF(NS_FAILED(rv)); + DebugOnly rv = + aListener->WebSocketMessageAvailable(mWebSocketSerialID, mData, + mMessageType); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WebSocketMessageAvailable failed"); } const nsCString mData; @@ -192,9 +192,9 @@ class WebSocketClosedRunnable final : public WebSocketBaseRunnable private: virtual void DoWork(nsIWebSocketEventListener* aListener) override { - nsresult rv = aListener->WebSocketClosed(mWebSocketSerialID, - mWasClean, mCode, mReason); - NS_WARN_IF(NS_FAILED(rv)); + DebugOnly rv = + aListener->WebSocketClosed(mWebSocketSerialID, mWasClean, mCode, mReason); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WebSocketClosed failed"); } bool mWasClean; @@ -255,8 +255,8 @@ WebSocketEventService::WebSocketCreated(uint32_t aWebSocketSerialID, RefPtr runnable = new WebSocketCreatedRunnable(aWebSocketSerialID, aInnerWindowID, aURI, aProtocols); - nsresult rv = NS_DispatchToMainThread(runnable); - NS_WARN_IF(NS_FAILED(rv)); + DebugOnly rv = NS_DispatchToMainThread(runnable); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToMainThread failed"); } void @@ -274,8 +274,8 @@ WebSocketEventService::WebSocketOpened(uint32_t aWebSocketSerialID, RefPtr runnable = new WebSocketOpenedRunnable(aWebSocketSerialID, aInnerWindowID, aEffectiveURI, aProtocols, aExtensions); - nsresult rv = NS_DispatchToMainThread(runnable); - NS_WARN_IF(NS_FAILED(rv)); + DebugOnly rv = NS_DispatchToMainThread(runnable); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToMainThread failed"); } void @@ -292,8 +292,8 @@ WebSocketEventService::WebSocketMessageAvailable(uint32_t aWebSocketSerialID, RefPtr runnable = new WebSocketMessageAvailableRunnable(aWebSocketSerialID, aInnerWindowID, aData, aMessageType); - nsresult rv = NS_DispatchToMainThread(runnable); - NS_WARN_IF(NS_FAILED(rv)); + DebugOnly rv = NS_DispatchToMainThread(runnable); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToMainThread failed"); } void @@ -311,8 +311,8 @@ WebSocketEventService::WebSocketClosed(uint32_t aWebSocketSerialID, RefPtr runnable = new WebSocketClosedRunnable(aWebSocketSerialID, aInnerWindowID, aWasClean, aCode, aReason); - nsresult rv = NS_DispatchToMainThread(runnable); - NS_WARN_IF(NS_FAILED(rv)); + DebugOnly rv = NS_DispatchToMainThread(runnable); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToMainThread failed"); } void @@ -331,8 +331,8 @@ WebSocketEventService::FrameReceived(uint32_t aWebSocketSerialID, RefPtr runnable = new WebSocketFrameRunnable(aWebSocketSerialID, aInnerWindowID, frame.forget(), false /* frameSent */); - nsresult rv = NS_DispatchToMainThread(runnable); - NS_WARN_IF(NS_FAILED(rv)); + DebugOnly rv = NS_DispatchToMainThread(runnable); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToMainThread failed"); } void @@ -352,8 +352,8 @@ WebSocketEventService::FrameSent(uint32_t aWebSocketSerialID, new WebSocketFrameRunnable(aWebSocketSerialID, aInnerWindowID, frame.forget(), true /* frameSent */); - nsresult rv = NS_DispatchToMainThread(runnable); - NS_WARN_IF(NS_FAILED(rv)); + DebugOnly rv = NS_DispatchToMainThread(runnable); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToMainThread failed"); } NS_IMETHODIMP diff --git a/netwerk/streamconv/converters/nsFTPDirListingConv.cpp b/netwerk/streamconv/converters/nsFTPDirListingConv.cpp index 87496dcca9f67..dbdc4870b959c 100644 --- a/netwerk/streamconv/converters/nsFTPDirListingConv.cpp +++ b/netwerk/streamconv/converters/nsFTPDirListingConv.cpp @@ -19,6 +19,7 @@ #include #include "mozilla/UniquePtrExtensions.h" +#include "mozilla/Unused.h" // // Log module for FTP dir listing stream converter logging... @@ -295,7 +296,7 @@ nsFTPDirListingConv::DigestBufferLines(char *aBuffer, nsCString &aString) { "%a, %d %b %Y %H:%M:%S", &result.fe_time ); nsAutoCString escaped; - NS_WARN_IF(!NS_Escape(nsDependentCString(buffer), escaped, url_Path)); + Unused << NS_WARN_IF(!NS_Escape(nsDependentCString(buffer), escaped, url_Path)); aString.Append(escaped); aString.Append(' '); diff --git a/python/mozbuild/mozbuild/artifacts.py b/python/mozbuild/mozbuild/artifacts.py index a7178ca214620..c2a7f5775fb3d 100644 --- a/python/mozbuild/mozbuild/artifacts.py +++ b/python/mozbuild/mozbuild/artifacts.py @@ -638,7 +638,8 @@ def artifact_urls(self, tree, job, rev): # extract the build ID; we use the .ini files embedded in the # downloaded artifact for this. We could also use the uploaded # public/build/buildprops.json for this purpose. - url = self._queue.buildUrl('getLatestArtifact', taskId, artifact_name) + replDict = {'taskId': taskId, 'name': artifact_name} + url = self._queue.buildUrl('getLatestArtifact', replDict=replDict) urls.append(url) if not urls: raise ValueError('Task for {key} existed, but no artifacts found!'.format(key=key)) diff --git a/testing/docker/rust-build/tcbuild.py b/testing/docker/rust-build/tcbuild.py index d55c6f3a75e13..fb1cabfb19817 100644 --- a/testing/docker/rust-build/tcbuild.py +++ b/testing/docker/rust-build/tcbuild.py @@ -101,7 +101,8 @@ def fetch_artifact(queue, task_id, run_id, name, dest_dir): write it to a file in dest_dir, and return the path to the written file. ''' - url = queue.buildUrl('getArtifact', task_id, run_id, name) + replDict = {'taskId': task_id, 'runId': run_id, 'name': name} + url = queue.buildUrl('getArtifact', replDict=replDict) fn = os.path.join(dest_dir, os.path.basename(name)) print('Fetching %s...' % name) try: diff --git a/toolkit/components/passwordmgr/nsLoginManagerPrompter.js b/toolkit/components/passwordmgr/nsLoginManagerPrompter.js index a13eb8be70a33..a0e09131489f3 100644 --- a/toolkit/components/passwordmgr/nsLoginManagerPrompter.js +++ b/toolkit/components/passwordmgr/nsLoginManagerPrompter.js @@ -205,7 +205,7 @@ LoginManagerPrompter.prototype = { Ci.nsILoginManagerPrompter]), _factory : null, - _window : null, + _chromeWindow : null, _browser : null, _opener : null, diff --git a/toolkit/components/terminator/nsTerminator.cpp b/toolkit/components/terminator/nsTerminator.cpp index 6f0d3972a364a..f9459cc5d615d 100644 --- a/toolkit/components/terminator/nsTerminator.cpp +++ b/toolkit/components/terminator/nsTerminator.cpp @@ -344,9 +344,7 @@ nsTerminator::SelfInit() for (size_t i = 0; i < ArrayLength(sShutdownSteps); ++i) { DebugOnly rv = os->AddObserver(this, sShutdownSteps[i].mTopic, false); -#if defined(DEBUG) - NS_WARN_IF(NS_FAILED(rv)); -#endif // defined(DEBUG) + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "AddObserver failed"); } return NS_OK; diff --git a/toolkit/components/url-classifier/ProtocolParser.cpp b/toolkit/components/url-classifier/ProtocolParser.cpp index d6773d359125d..38dfea96da3d9 100644 --- a/toolkit/components/url-classifier/ProtocolParser.cpp +++ b/toolkit/components/url-classifier/ProtocolParser.cpp @@ -865,8 +865,8 @@ ProtocolParserProtobuf::ProcessOneResponse(const ListUpdateResponse& aResponse) nsCString state(aResponse.new_client_state().c_str(), aResponse.new_client_state().size()); NS_DispatchToMainThread(NS_NewRunnableFunction([listName, state] () { - nsresult rv = SaveStateToPref(listName, state); - NS_WARN_IF(NS_FAILED(rv)); + DebugOnly rv = SaveStateToPref(listName, state); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "SaveStateToPref failed"); })); PARSER_LOG(("==== Update for threat type '%d' ====", aResponse.threat_type())); diff --git a/toolkit/content/widgets/notification.xml b/toolkit/content/widgets/notification.xml index b6e81cdef9c4a..c3e20f9474eac 100644 --- a/toolkit/content/widgets/notification.xml +++ b/toolkit/content/widgets/notification.xml @@ -493,6 +493,9 @@ &learnMore; + + @@ -500,7 +503,7 @@ + xbl:inherits="oncommand=buttoncommand,onpopupshown=buttonpopupshown,label=buttonlabel,accesskey=buttonaccesskey,disabled=mainactiondisabled"> @@ -516,6 +519,9 @@ + + document.getAnonymousElementByAttribute(this, "anonid", "checkbox"); + document.getAnonymousElementByAttribute(this, "anonid", "closebutton"); diff --git a/toolkit/modules/PopupNotifications.jsm b/toolkit/modules/PopupNotifications.jsm index c65d6bc350251..af4fb654cdea8 100644 --- a/toolkit/modules/PopupNotifications.jsm +++ b/toolkit/modules/PopupNotifications.jsm @@ -55,6 +55,18 @@ function getAnchorFromBrowser(aBrowser, aAnchorID) { return null; } +function getNotificationFromElement(aElement) { + // Need to find the associated notification object, which is a bit tricky + // since it isn't associated with the element directly - this is kind of + // gross and very dependent on the structure of the popupnotification + // binding's content. + let notificationEl; + let parent = aElement; + while (parent && (parent = aElement.ownerDocument.getBindingParent(parent))) + notificationEl = parent; + return notificationEl; +} + /** * Notification object describes a single popup notification. * @@ -72,6 +84,8 @@ function Notification(id, message, anchorID, mainAction, secondaryActions, this.options = options || {}; this._dismissed = false; + // Will become a boolean when manually toggled by the user. + this._checkboxChecked = null; this.wasDismissed = false; this.recordedTelemetryStats = new Set(); this.isPrivate = PrivateBrowsingUtils.isWindowPrivate( @@ -274,7 +288,8 @@ PopupNotifications.prototype = { * - label (string): the button's label. * - accessKey (string): the button's accessKey. * - callback (function): a callback to be invoked when the button is - * pressed. + * pressed, is passed an object that contains the following fields: + * - checkboxChecked: (boolean) If the optional checkbox is checked. * - [optional] dismiss (boolean): If this is true, the notification * will be dismissed instead of removed after running the callback. * If null, the notification will not have a button, and @@ -332,6 +347,26 @@ PopupNotifications.prototype = { * removed when they would have otherwise been dismissed * (i.e. any time the popup is closed due to user * interaction). + * checkbox: An object that allows you to add a checkbox and + * control its behavior with these fields: + * label: + * (required) Label to be shown next to the checkbox. + * checked: + * (optional) Whether the checkbox should be checked + * by default. Defaults to false. + * checkedState: + * (optional) An object that allows you to customize + * the notification state when the checkbox is checked. + * disableMainAction: + * (optional) Whether the mainAction is disabled. + * Defaults to false. + * warningLabel: + * (optional) A (warning) text that is shown below the + * checkbox. Pass null to hide. + * uncheckedState: + * (optional) An object that allows you to customize + * the notification state when the checkbox is not checked. + * Has the same attributes as checkedState. * hideNotNow: If true, indicates that the 'Not Now' menuitem should * not be shown. If 'Not Now' is hidden, it needs to be * replaced by another 'do nothing' item, so providing at @@ -705,6 +740,25 @@ PopupNotifications.prototype = { } } + let checkbox = n.options.checkbox; + if (checkbox && checkbox.label) { + let checked = n._checkboxChecked != null ? n._checkboxChecked : !!checkbox.checked; + + popupnotification.setAttribute("checkboxhidden", "false"); + popupnotification.setAttribute("checkboxchecked", checked); + popupnotification.setAttribute("checkboxlabel", checkbox.label); + + popupnotification.setAttribute("checkboxcommand", "PopupNotifications._onCheckboxCommand(event);"); + + if (checked) { + this._setNotificationUIState(popupnotification, checkbox.checkedState); + } else { + this._setNotificationUIState(popupnotification, checkbox.uncheckedState); + } + } else { + popupnotification.setAttribute("checkboxhidden", "true"); + } + this.panel.appendChild(popupnotification); // The popupnotification may be hidden if we got it from the chrome @@ -713,6 +767,32 @@ PopupNotifications.prototype = { }, this); }, + _setNotificationUIState(notification, state={}) { + notification.setAttribute("mainactiondisabled", state.disableMainAction || "false"); + + if (state.warningLabel) { + notification.setAttribute("warninglabel", state.warningLabel); + notification.setAttribute("warninghidden", "false"); + } else { + notification.setAttribute("warninghidden", "true"); + } + }, + + _onCheckboxCommand(event) { + let notificationEl = getNotificationFromElement(event.originalTarget); + let checked = notificationEl.checkbox.checked; + let notification = notificationEl.notification; + + // Save checkbox state to be able to persist it when re-opening the doorhanger. + notification._checkboxChecked = checked; + + if (checked) { + this._setNotificationUIState(notificationEl, notification.options.checkbox.checkedState); + } else { + this._setNotificationUIState(notificationEl, notification.options.checkbox.uncheckedState); + } + }, + _showPanel: function PopupNotifications_showPanel(notificationsToShow, anchorElement) { this.panel.hidden = false; @@ -1102,15 +1182,7 @@ PopupNotifications.prototype = { }, _onButtonEvent(event, type) { - // Need to find the associated notification object, which is a bit tricky - // since it isn't associated with the button directly - this is kind of - // gross and very dependent on the structure of the popupnotification - // binding's content. - let target = event.originalTarget; - let notificationEl; - let parent = target; - while (parent && (parent = target.ownerDocument.getBindingParent(parent))) - notificationEl = parent; + let notificationEl = getNotificationFromElement(event.originalTarget); if (!notificationEl) throw "PopupNotifications._onButtonEvent: couldn't find notification element"; @@ -1150,7 +1222,9 @@ PopupNotifications.prototype = { notification._recordTelemetryStat(TELEMETRY_STAT_ACTION_1); try { - notification.mainAction.callback.call(); + notification.mainAction.callback.call(undefined, { + checkboxChecked: notificationEl.checkbox.checked + }); } catch (error) { Cu.reportError(error); } @@ -1169,12 +1243,15 @@ PopupNotifications.prototype = { if (!target.action || !target.notification) throw "menucommand target has no associated action/notification"; + let notificationEl = target.parentElement; event.stopPropagation(); target.notification._recordTelemetryStat(target.action.telemetryStatId); try { - target.action.callback.call(); + target.action.callback.call(undefined, { + checkboxChecked: notificationEl.checkbox.checked + }); } catch (error) { Cu.reportError(error); } diff --git a/toolkit/modules/RemotePageManager.jsm b/toolkit/modules/RemotePageManager.jsm index f1cd80a3b476f..a3fea49e67543 100644 --- a/toolkit/modules/RemotePageManager.jsm +++ b/toolkit/modules/RemotePageManager.jsm @@ -344,7 +344,15 @@ ChromeMessagePort.prototype.message = function({ data: messagedata }) { }; ChromeMessagePort.prototype.destroy = function() { - this._browser.removeEventListener("SwapDocShells", this.swapBrowsers, false); + try { + this._browser.removeEventListener( + "SwapDocShells", this.swapBrowsers, false); + } + catch (e) { + // It's possible the browser instance is already dead so we can just ignore + // this error. + } + this._browser = null; Services.obs.removeObserver(this, "message-manager-disconnect"); MessagePort.prototype.destroy.call(this); diff --git a/toolkit/moz.configure b/toolkit/moz.configure index facd2a9dd9d5f..0c98c7ad4a0cf 100644 --- a/toolkit/moz.configure +++ b/toolkit/moz.configure @@ -764,3 +764,15 @@ def skia_includes(skia, skia_gpu): return includes set_config('SKIA_INCLUDES', skia_includes) + +# Support various fuzzing options +# ============================================================== +option('--enable-libfuzzer', help='Enable libfuzzer support') + +@depends('--enable-libfuzzer') +def enable_libfuzzer(value): + if value: + return True + +set_config('LIBFUZZER', enable_libfuzzer) +set_define('LIBFUZZER', enable_libfuzzer) diff --git a/toolkit/mozapps/update/tests/data/xpcshellUtilsAUS.js b/toolkit/mozapps/update/tests/data/xpcshellUtilsAUS.js index ed4ff96bd5101..70fab8ff470dd 100644 --- a/toolkit/mozapps/update/tests/data/xpcshellUtilsAUS.js +++ b/toolkit/mozapps/update/tests/data/xpcshellUtilsAUS.js @@ -122,6 +122,9 @@ const HELPER_SLEEP_TIMEOUT = 180; // the test will try to kill it. const APP_TIMER_TIMEOUT = 120000; +// How many of do_timeout calls using FILE_IN_USE_TIMEOUT_MS to wait before the +// test is aborted. +const FILE_IN_USE_MAX_TIMEOUT_RUNS = 60; const FILE_IN_USE_TIMEOUT_MS = 1000; const PIPE_TO_NULL = IS_WIN ? ">nul" : "> /dev/null 2>&1"; @@ -174,6 +177,7 @@ var gUseTestAppDir = true; var gStagingRemovedUpdate = false; var gTimeoutRuns = 0; +var gFileInUseTimeoutRuns = 0; // Environment related globals var gShouldResetEnv = undefined; @@ -3335,6 +3339,10 @@ function checkFilesAfterUpdateCommon(aGetFileFunc, aStageDirExists, */ function checkCallbackLog() { if (IS_SERVICE_TEST) { + // Prevent this check from being repeatedly logged in the xpcshell log by + // checking it here instead of in checkCallbackServiceLog. + Assert.ok(!!gServiceLaunchedCallbackLog, + "gServiceLaunchedCallbackLog should be defined"); checkCallbackServiceLog(); } else { checkCallbackAppLog(); @@ -3452,9 +3460,6 @@ function checkPostUpdateAppLog() { * the callback application. */ function checkCallbackServiceLog() { - Assert.ok(!!gServiceLaunchedCallbackLog, - "gServiceLaunchedCallbackLog should be defined"); - let expectedLogContents = gServiceLaunchedCallbackArgs.join("\n") + "\n"; let logFile = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile); logFile.initWithPath(gServiceLaunchedCallbackLog); @@ -3465,29 +3470,27 @@ function checkCallbackServiceLog() { // fail by timing out after gTimeoutRuns is greater than MAX_TIMEOUT_RUNS or // the test harness times out the test. if (logContents != expectedLogContents) { - gTimeoutRuns++; - if (gTimeoutRuns > MAX_TIMEOUT_RUNS) { - logTestInfo("callback service log contents are not correct"); - let aryLog = logContents.split("\n"); - let aryCompare = expectedLogContents.split("\n"); - // Pushing an empty string to both arrays makes it so either array's length - // can be used in the for loop below without going out of bounds. - aryLog.push(""); - aryCompare.push(""); - // xpcshell tests won't display the entire contents so log the incorrect - // line. - for (let i = 0; i < aryLog.length; ++i) { - if (aryLog[i] != aryCompare[i]) { - logTestInfo("the first incorrect line in the service callback log " + - "is: " + aryLog[i]); - Assert.equal(aryLog[i], aryCompare[i], - "the service callback log contents" + MSG_SHOULD_EQUAL); + gFileInUseTimeoutRuns++; + if (gFileInUseTimeoutRuns > FILE_IN_USE_MAX_TIMEOUT_RUNS) { + if (logContents == null) { + if (logFile.exists()) { + logTestInfo("callback service log exists but readFile returned null"); + } else { + logTestInfo("callback service log does not exist"); + } + } else { + logTestInfo("callback service log contents are not correct"); + let aryLog = logContents.split("\n"); + // xpcshell tests won't display the entire contents so log each line. + logTestInfo("contents of " + logFile.path + ":"); + for (let i = 0; i < aryLog.length; ++i) { + logTestInfo(aryLog[i]); } } // This should never happen! do_throw("Unable to find incorrect service callback log contents!"); } - do_execute_soon(checkCallbackServiceLog); + do_timeout(FILE_IN_USE_TIMEOUT_MS, checkCallbackServiceLog); return; } Assert.ok(true, "the callback service log contents" + MSG_SHOULD_EQUAL); diff --git a/toolkit/themes/osx/global/notification.css b/toolkit/themes/osx/global/notification.css index 1a78959907a52..24b3d3920b4e6 100644 --- a/toolkit/themes/osx/global/notification.css +++ b/toolkit/themes/osx/global/notification.css @@ -200,3 +200,7 @@ notification[type="info"]:not([value="translation"]) .close-icon:not(:hover) { .popup-notification-menubutton > .button-menubutton-button[disabled] { opacity: 0.5; } + +.popup-notification-warning { + color: #aa1b08; +} diff --git a/toolkit/themes/windows/global/notification.css b/toolkit/themes/windows/global/notification.css index 0b74b1030ddf9..d5d6a647342db 100644 --- a/toolkit/themes/windows/global/notification.css +++ b/toolkit/themes/windows/global/notification.css @@ -207,3 +207,7 @@ XXX: apply styles to all themes until bug 509642 is fixed .popup-notification-menubutton > .button-menubutton-button[disabled] { opacity: 0.5; } + +@media (-moz-windows-default-theme) { + color: #aa1b08; +} diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp index f2185a10f9b4e..66ccd7380a553 100644 --- a/toolkit/xre/nsAppRunner.cpp +++ b/toolkit/xre/nsAppRunner.cpp @@ -258,6 +258,18 @@ nsString gAbsoluteArgv0Path; extern "C" MFBT_API bool IsSignalHandlingBroken(); #endif +#ifdef LIBFUZZER +#include "LibFuzzerRunner.h" + +namespace mozilla { +LibFuzzerRunner* libFuzzerRunner = 0; +} // namespace mozilla + +extern "C" MOZ_EXPORT void XRE_LibFuzzerSetMain(int argc, char** argv, LibFuzzerMain main) { + mozilla::libFuzzerRunner->setParams(argc, argv, main); +} +#endif + namespace mozilla { int (*RunGTest)() = 0; } // namespace mozilla @@ -3642,6 +3654,13 @@ XREMain::XRE_mainStartup(bool* aExitFlag) return 1; #endif /* MOZ_WIDGET_GTK */ +#ifdef LIBFUZZER + if (PR_GetEnv("LIBFUZZER")) { + *aExitFlag = true; + return mozilla::libFuzzerRunner->Run(); + } +#endif + if (PR_GetEnv("MOZ_RUN_GTEST")) { int result; #ifdef XP_WIN diff --git a/tools/fuzzing/libfuzzer/FuzzerCustomMain.cpp b/tools/fuzzing/libfuzzer/FuzzerCustomMain.cpp new file mode 100644 index 0000000000000..2293efd95d8ee --- /dev/null +++ b/tools/fuzzing/libfuzzer/FuzzerCustomMain.cpp @@ -0,0 +1,37 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * * This Source Code Form is subject to the terms of the Mozilla Public + * * License, v. 2.0. If a copy of the MPL was not distributed with this + * * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include + +#include "FuzzerInterface.h" +#include "FuzzerInternal.h" +#include "harness/LibFuzzerRegistry.h" + +/* This is a wrapper defined in browser/app/nsBrowserApp.cpp, + * encapsulating the XRE_ equivalent defined in libxul */ +extern void libFuzzerGetFuncs(const char*, LibFuzzerInitFunc*, + LibFuzzerTestingFunc*); + +int libfuzzer_main(int argc, char **argv) { + LibFuzzerInitFunc initFunc = nullptr; + LibFuzzerTestingFunc testingFunc = nullptr; + + libFuzzerGetFuncs(getenv("LIBFUZZER"), &initFunc, &testingFunc); + + if (initFunc) { + int ret = initFunc(&argc, &argv); + if (ret) { + fprintf(stderr, "LibFuzzer: Error: Initialize callback failed\n"); + return ret; + } + } + + if (!testingFunc) { + fprintf(stderr, "LibFuzzer: Error: No testing callback found\n"); + return 1; + } + + return fuzzer::FuzzerDriver(&argc, &argv, testingFunc); +} diff --git a/tools/fuzzing/libfuzzer/Makefile.in b/tools/fuzzing/libfuzzer/Makefile.in new file mode 100644 index 0000000000000..7ffe876852a4d --- /dev/null +++ b/tools/fuzzing/libfuzzer/Makefile.in @@ -0,0 +1,12 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +include $(topsrcdir)/config/rules.mk + +# According to the LLVM docs, LibFuzzer isn't supposed to be built with any +# sanitizer flags and in fact, building it with ASan coverage currently causes +# Clang 3.9+ to crash, so we filter out all sanitizer-related flags here. +CXXFLAGS := $(filter-out -fsanitize%,$(CXXFLAGS)) +CFLAGS := $(filter-out -fsanitize%,$(CFLAGS)) +LDFLAGS := $(filter-out -fsanitize%,$(LDFLAGS)) diff --git a/tools/fuzzing/libfuzzer/clone_libfuzzer.sh b/tools/fuzzing/libfuzzer/clone_libfuzzer.sh new file mode 100755 index 0000000000000..6170362ac9fbf --- /dev/null +++ b/tools/fuzzing/libfuzzer/clone_libfuzzer.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +mkdir tmp/ +git clone --no-checkout --depth 1 https://chromium.googlesource.com/chromium/llvm-project/llvm/lib/Fuzzer tmp/ +mv tmp/.git . +rm -Rf tmp +git reset --hard HEAD diff --git a/tools/fuzzing/libfuzzer/harness/LibFuzzerRegistry.cpp b/tools/fuzzing/libfuzzer/harness/LibFuzzerRegistry.cpp new file mode 100644 index 0000000000000..5390c91c2a4b7 --- /dev/null +++ b/tools/fuzzing/libfuzzer/harness/LibFuzzerRegistry.cpp @@ -0,0 +1,32 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * * This Source Code Form is subject to the terms of the Mozilla Public + * * License, v. 2.0. If a copy of the MPL was not distributed with this + * * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "LibFuzzerRegistry.h" + +extern "C" { + void MOZ_EXPORT XRE_LibFuzzerGetFuncs(const char* moduleName, LibFuzzerInitFunc* initFunc, LibFuzzerTestingFunc* testingFunc) { + std::string moduleNameStr(moduleName); + mozilla::LibFuzzerFunctions funcs = mozilla::LibFuzzerRegistry::getInstance().getModuleFunctions(moduleNameStr); + *initFunc = funcs.first; + *testingFunc = funcs.second; + } +} + +namespace mozilla { + +LibFuzzerRegistry& LibFuzzerRegistry::getInstance() { + static LibFuzzerRegistry instance; + return instance; +} + +void LibFuzzerRegistry::registerModule(std::string moduleName, LibFuzzerInitFunc initFunc, LibFuzzerTestingFunc testingFunc) { + moduleMap.insert(std::pair(moduleName,LibFuzzerFunctions(initFunc, testingFunc))); +} + +LibFuzzerFunctions LibFuzzerRegistry::getModuleFunctions(std::string& moduleName) { + return moduleMap[moduleName]; +} + +} // namespace mozilla diff --git a/tools/fuzzing/libfuzzer/harness/LibFuzzerRegistry.h b/tools/fuzzing/libfuzzer/harness/LibFuzzerRegistry.h new file mode 100644 index 0000000000000..e459ade33e714 --- /dev/null +++ b/tools/fuzzing/libfuzzer/harness/LibFuzzerRegistry.h @@ -0,0 +1,41 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * * This Source Code Form is subject to the terms of the Mozilla Public + * * License, v. 2.0. If a copy of the MPL was not distributed with this + * * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef _LibFuzzerRegistry_h__ +#define _LibFuzzerRegistry_h__ + +#include +#include +#include +#include + +#include "mozilla/Attributes.h" + +typedef int(*LibFuzzerMain)(int, char**); +typedef int(*LibFuzzerInitFunc)(int*, char***); +typedef int(*LibFuzzerTestingFunc)(const uint8_t*, size_t); + +namespace mozilla { + +typedef std::pair LibFuzzerFunctions; + +class LibFuzzerRegistry { + public: + MOZ_EXPORT static LibFuzzerRegistry& getInstance(); + MOZ_EXPORT void registerModule(std::string moduleName, LibFuzzerInitFunc initFunc, LibFuzzerTestingFunc testingFunc); + MOZ_EXPORT LibFuzzerFunctions getModuleFunctions(std::string& moduleName); + + LibFuzzerRegistry(LibFuzzerRegistry const&) = delete; + void operator=(LibFuzzerRegistry const&) = delete; + + private: + LibFuzzerRegistry() {}; + std::map moduleMap; +}; + +} // namespace mozilla + + +#endif // _LibFuzzerRegistry_h__ diff --git a/tools/fuzzing/libfuzzer/harness/LibFuzzerRunner.cpp b/tools/fuzzing/libfuzzer/harness/LibFuzzerRunner.cpp new file mode 100644 index 0000000000000..2a57ddac80acb --- /dev/null +++ b/tools/fuzzing/libfuzzer/harness/LibFuzzerRunner.cpp @@ -0,0 +1,38 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * * This Source Code Form is subject to the terms of the Mozilla Public + * * License, v. 2.0. If a copy of the MPL was not distributed with this + * * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "LibFuzzerRunner.h" +#include "mozilla/Attributes.h" +#include "prenv.h" + +#include "LibFuzzerTestHarness.h" + +namespace mozilla { + +// We use a static var 'libFuzzerRunner' defined in nsAppRunner.cpp. +// libFuzzerRunner is initialized to nullptr but if LibFuzzer (this file) +// is linked in then libFuzzerRunner will be set here indicating that +// we want to call into LibFuzzer's main. +class _InitLibFuzzer { +public: + _InitLibFuzzer() { + libFuzzerRunner = new LibFuzzerRunner(); + } +} InitLibFuzzer; + +int LibFuzzerRunner::Run() { + ScopedXPCOM xpcom("LibFuzzer"); + return mFuzzerMain(mArgc, mArgv); +} + +typedef int(*LibFuzzerMain)(int, char**); + +void LibFuzzerRunner::setParams(int argc, char** argv, LibFuzzerMain main) { + mArgc = argc; + mArgv = argv; + mFuzzerMain = main; +} + +} // namespace mozilla diff --git a/tools/fuzzing/libfuzzer/harness/LibFuzzerRunner.h b/tools/fuzzing/libfuzzer/harness/LibFuzzerRunner.h new file mode 100644 index 0000000000000..c2362f4e99eca --- /dev/null +++ b/tools/fuzzing/libfuzzer/harness/LibFuzzerRunner.h @@ -0,0 +1,23 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * * This Source Code Form is subject to the terms of the Mozilla Public + * * License, v. 2.0. If a copy of the MPL was not distributed with this + * * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +namespace mozilla { + +typedef int(*LibFuzzerMain)(int, char**); + +class LibFuzzerRunner { +public: + int Run(); + void setParams(int argc, char** argv, LibFuzzerMain main); + +private: + int mArgc; + char** mArgv; + LibFuzzerMain mFuzzerMain; +}; + +extern LibFuzzerRunner* libFuzzerRunner; + +} // namespace mozilla diff --git a/tools/fuzzing/libfuzzer/harness/LibFuzzerTestHarness.h b/tools/fuzzing/libfuzzer/harness/LibFuzzerTestHarness.h new file mode 100644 index 0000000000000..c402c9c53bdfa --- /dev/null +++ b/tools/fuzzing/libfuzzer/harness/LibFuzzerTestHarness.h @@ -0,0 +1,312 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + * Test harness for XPCOM objects, providing a scoped XPCOM initializer, + * nsCOMPtr, nsRefPtr, do_CreateInstance, do_GetService, ns(Auto|C|)String, + * and stdio.h/stdlib.h. + */ + +#ifndef LibFuzzerTestHarness_h__ +#define LibFuzzerTestHarness_h__ + +#include "mozilla/ArrayUtils.h" + +#include "prenv.h" +#include "nsComponentManagerUtils.h" +#include "nsServiceManagerUtils.h" +#include "nsCOMPtr.h" +#include "nsAutoPtr.h" +#include "nsStringGlue.h" +#include "nsAppDirectoryServiceDefs.h" +#include "nsDirectoryServiceDefs.h" +#include "nsDirectoryServiceUtils.h" +#include "nsIDirectoryService.h" +#include "nsIFile.h" +#include "nsIProperties.h" +#include "nsIObserverService.h" +#include "nsXULAppAPI.h" +#include +#include +#include + +namespace { + +static uint32_t gFailCount = 0; + +/** + * Prints the given failure message and arguments using printf, prepending + * "TEST-UNEXPECTED-FAIL " for the benefit of the test harness and + * appending "\n" to eliminate having to type it at each call site. + */ +void fail(const char* msg, ...) +{ + va_list ap; + + printf("TEST-UNEXPECTED-FAIL | "); + + va_start(ap, msg); + vprintf(msg, ap); + va_end(ap); + + putchar('\n'); + ++gFailCount; +} + +/** + * Prints the given success message and arguments using printf, prepending + * "TEST-PASS " for the benefit of the test harness and + * appending "\n" to eliminate having to type it at each call site. + */ +void passed(const char* msg, ...) +{ + va_list ap; + + printf("TEST-PASS | "); + + va_start(ap, msg); + vprintf(msg, ap); + va_end(ap); + + putchar('\n'); +} + +//----------------------------------------------------------------------------- + +class ScopedLogging +{ +public: + ScopedLogging() + { + NS_LogInit(); + } + + ~ScopedLogging() + { + NS_LogTerm(); + } +}; + +static class ScopedXPCOM : public nsIDirectoryServiceProvider2 +{ + public: + NS_DECL_ISUPPORTS + + explicit ScopedXPCOM(const char* testName, + nsIDirectoryServiceProvider *dirSvcProvider = nullptr) + : mDirSvcProvider(dirSvcProvider) + { + mTestName = testName; + printf("Running %s tests...\n", mTestName); + + nsresult rv = NS_InitXPCOM2(&mServMgr, nullptr, this); + if (NS_FAILED(rv)) + { + fail("NS_InitXPCOM2 returned failure code 0x%x", rv); + mServMgr = nullptr; + return; + } + } + + ~ScopedXPCOM() + { + // If we created a profile directory, we need to remove it. + if (mProfD) { + nsCOMPtr os = + do_GetService(NS_OBSERVERSERVICE_CONTRACTID); + MOZ_ASSERT(os); + if (os) { + MOZ_ALWAYS_SUCCEEDS(os->NotifyObservers(nullptr, "profile-change-net-teardown", nullptr)); + MOZ_ALWAYS_SUCCEEDS(os->NotifyObservers(nullptr, "profile-change-teardown", nullptr)); + MOZ_ALWAYS_SUCCEEDS(os->NotifyObservers(nullptr, "profile-before-change", nullptr)); + MOZ_ALWAYS_SUCCEEDS(os->NotifyObservers(nullptr, "profile-before-change-qm", nullptr)); + MOZ_ALWAYS_SUCCEEDS(os->NotifyObservers(nullptr, "profile-before-change-telemetry", nullptr)); + } + + if (NS_FAILED(mProfD->Remove(true))) { + NS_WARNING("Problem removing profile directory"); + } + + mProfD = nullptr; + } + + if (mServMgr) + { + NS_RELEASE(mServMgr); + nsresult rv = NS_ShutdownXPCOM(nullptr); + if (NS_FAILED(rv)) + { + fail("XPCOM shutdown failed with code 0x%x", rv); + exit(1); + } + } + + printf("Finished running %s tests.\n", mTestName); + } + + bool failed() + { + return mServMgr == nullptr; + } + + already_AddRefed GetProfileDirectory() + { + if (mProfD) { + nsCOMPtr copy = mProfD; + return copy.forget(); + } + + // Create a unique temporary folder to use for this test. + // Note that runcppunittests.py will run tests with a temp + // directory as the cwd, so just put something under that. + nsCOMPtr profD; + nsresult rv = NS_GetSpecialDirectory(NS_OS_CURRENT_PROCESS_DIR, + getter_AddRefs(profD)); + NS_ENSURE_SUCCESS(rv, nullptr); + + rv = profD->Append(NS_LITERAL_STRING("cpp-unit-profd")); + NS_ENSURE_SUCCESS(rv, nullptr); + + rv = profD->CreateUnique(nsIFile::DIRECTORY_TYPE, 0755); + NS_ENSURE_SUCCESS(rv, nullptr); + + mProfD = profD; + return profD.forget(); + } + + already_AddRefed GetGREDirectory() + { + if (mGRED) { + nsCOMPtr copy = mGRED; + return copy.forget(); + } + + char* env = PR_GetEnv("MOZ_XRE_DIR"); + nsCOMPtr greD; + if (env) { + NS_NewLocalFile(NS_ConvertUTF8toUTF16(env), false, + getter_AddRefs(greD)); + } + + mGRED = greD; + return greD.forget(); + } + + already_AddRefed GetGREBinDirectory() + { + if (mGREBinD) { + nsCOMPtr copy = mGREBinD; + return copy.forget(); + } + + nsCOMPtr greD = GetGREDirectory(); + if (!greD) { + return greD.forget(); + } + greD->Clone(getter_AddRefs(mGREBinD)); + +#ifdef XP_MACOSX + nsAutoCString leafName; + mGREBinD->GetNativeLeafName(leafName); + if (leafName.Equals("Resources")) { + mGREBinD->SetNativeLeafName(NS_LITERAL_CSTRING("MacOS")); + } +#endif + + nsCOMPtr copy = mGREBinD; + return copy.forget(); + } + + //////////////////////////////////////////////////////////////////////////// + //// nsIDirectoryServiceProvider + + NS_IMETHODIMP GetFile(const char *aProperty, bool *_persistent, + nsIFile **_result) override + { + // If we were supplied a directory service provider, ask it first. + if (mDirSvcProvider && + NS_SUCCEEDED(mDirSvcProvider->GetFile(aProperty, _persistent, + _result))) { + return NS_OK; + } + + // Otherwise, the test harness provides some directories automatically. + if (0 == strcmp(aProperty, NS_APP_USER_PROFILE_50_DIR) || + 0 == strcmp(aProperty, NS_APP_USER_PROFILE_LOCAL_50_DIR) || + 0 == strcmp(aProperty, NS_APP_PROFILE_LOCAL_DIR_STARTUP)) { + nsCOMPtr profD = GetProfileDirectory(); + NS_ENSURE_TRUE(profD, NS_ERROR_FAILURE); + + nsCOMPtr clone; + nsresult rv = profD->Clone(getter_AddRefs(clone)); + NS_ENSURE_SUCCESS(rv, rv); + + *_persistent = true; + clone.forget(_result); + return NS_OK; + } else if (0 == strcmp(aProperty, NS_GRE_DIR)) { + nsCOMPtr greD = GetGREDirectory(); + NS_ENSURE_TRUE(greD, NS_ERROR_FAILURE); + + *_persistent = true; + greD.forget(_result); + return NS_OK; + } else if (0 == strcmp(aProperty, NS_GRE_BIN_DIR)) { + nsCOMPtr greBinD = GetGREBinDirectory(); + NS_ENSURE_TRUE(greBinD, NS_ERROR_FAILURE); + + *_persistent = true; + greBinD.forget(_result); + return NS_OK; + } + + return NS_ERROR_FAILURE; + } + + //////////////////////////////////////////////////////////////////////////// + //// nsIDirectoryServiceProvider2 + + NS_IMETHODIMP GetFiles(const char *aProperty, nsISimpleEnumerator **_enum) override + { + // If we were supplied a directory service provider, ask it first. + nsCOMPtr provider = + do_QueryInterface(mDirSvcProvider); + if (provider && NS_SUCCEEDED(provider->GetFiles(aProperty, _enum))) { + return NS_OK; + } + + return NS_ERROR_FAILURE; + } + + private: + const char* mTestName; + nsIServiceManager* mServMgr; + nsCOMPtr mDirSvcProvider; + nsCOMPtr mProfD; + nsCOMPtr mGRED; + nsCOMPtr mGREBinD; +}; + +NS_IMPL_QUERY_INTERFACE( + ScopedXPCOM, + nsIDirectoryServiceProvider, + nsIDirectoryServiceProvider2 +) + +NS_IMETHODIMP_(MozExternalRefCountType) +ScopedXPCOM::AddRef() +{ + return 2; +} + +NS_IMETHODIMP_(MozExternalRefCountType) +ScopedXPCOM::Release() +{ + return 1; +} + +} // namespace + +#endif // LibFuzzerTestHarness_h__ diff --git a/tools/fuzzing/libfuzzer/harness/moz.build b/tools/fuzzing/libfuzzer/harness/moz.build new file mode 100644 index 0000000000000..596018cb3c74f --- /dev/null +++ b/tools/fuzzing/libfuzzer/harness/moz.build @@ -0,0 +1,19 @@ +# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +Library('fuzzer-runner') + +SOURCES += [ + 'LibFuzzerRegistry.cpp', + 'LibFuzzerRunner.cpp', +] + +EXPORTS += [ + 'LibFuzzerRegistry.h', + 'LibFuzzerRunner.h', +] + +FINAL_LIBRARY = "xul" diff --git a/tools/fuzzing/libfuzzer/moz.build b/tools/fuzzing/libfuzzer/moz.build new file mode 100644 index 0000000000000..b37afdf9ce1fa --- /dev/null +++ b/tools/fuzzing/libfuzzer/moz.build @@ -0,0 +1,26 @@ +# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +Library('fuzzer') + +DIRS += [ + 'harness', +] + +SOURCES += [ + 'FuzzerCrossOver.cpp', + 'FuzzerCustomMain.cpp', + 'FuzzerDriver.cpp', + 'FuzzerExtFunctionsDlsym.cpp', + 'FuzzerExtFunctionsWeak.cpp', + 'FuzzerIO.cpp', + 'FuzzerLoop.cpp', + 'FuzzerMutate.cpp', + 'FuzzerSHA1.cpp', + 'FuzzerTracePC.cpp', + 'FuzzerTraceState.cpp', + 'FuzzerUtil.cpp', +] diff --git a/tools/fuzzing/moz.build b/tools/fuzzing/moz.build new file mode 100644 index 0000000000000..527b7c1d50b02 --- /dev/null +++ b/tools/fuzzing/moz.build @@ -0,0 +1,10 @@ +# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +if CONFIG['LIBFUZZER']: + DIRS += [ + 'libfuzzer', + ] diff --git a/tools/profiler/gecko/ProfileGatherer.cpp b/tools/profiler/gecko/ProfileGatherer.cpp index 0b46879527da5..5cd45bee3fe0f 100644 --- a/tools/profiler/gecko/ProfileGatherer.cpp +++ b/tools/profiler/gecko/ProfileGatherer.cpp @@ -84,10 +84,11 @@ ProfileGatherer::Start(double aSinceTime, nsCOMPtr os = mozilla::services::GetObserverService(); if (os) { - nsresult rv = os->AddObserver(this, "profiler-subprocess", false); - NS_WARN_IF(NS_FAILED(rv)); + DebugOnly rv = + os->AddObserver(this, "profiler-subprocess", false); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "AddObserver failed"); rv = os->NotifyObservers(this, "profiler-subprocess-gather", nullptr); - NS_WARN_IF(NS_FAILED(rv)); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NotifyObservers failed"); } if (!mPendingProfiles) { @@ -110,8 +111,8 @@ ProfileGatherer::Finish() nsCOMPtr os = mozilla::services::GetObserverService(); if (os) { - nsresult rv = os->RemoveObserver(this, "profiler-subprocess"); - NS_WARN_IF(NS_FAILED(rv)); + DebugOnly rv = os->RemoveObserver(this, "profiler-subprocess"); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "RemoveObserver failed"); } AutoJSAPI jsapi; diff --git a/uriloader/base/nsDocLoader.cpp b/uriloader/base/nsDocLoader.cpp index b9ac770233e9f..edd9305d6620e 100644 --- a/uriloader/base/nsDocLoader.cpp +++ b/uriloader/base/nsDocLoader.cpp @@ -35,6 +35,7 @@ #include "nsPresContext.h" #include "nsIAsyncVerifyRedirectCallback.h" +using mozilla::DebugOnly; using mozilla::LogLevel; static NS_DEFINE_CID(kThisImplCID, NS_THIS_DOCLOADER_IMPL_CID); @@ -345,8 +346,8 @@ nsDocLoader::Destroy() // Remove the document loader from the parent list of loaders... if (mParent) { - nsresult rv = mParent->RemoveChildLoader(this); - NS_WARN_IF(NS_FAILED(rv)); + DebugOnly rv = mParent->RemoveChildLoader(this); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "RemoveChildLoader failed"); } // Release all the information about network requests... @@ -377,8 +378,9 @@ nsDocLoader::DestroyChildren() if (loader) { // This is a safe cast, as we only put nsDocLoader objects into the // array - nsresult rv = static_cast(loader)->SetDocLoaderParent(nullptr); - NS_WARN_IF(NS_FAILED(rv)); + DebugOnly rv = + static_cast(loader)->SetDocLoaderParent(nullptr); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "SetDocLoaderParent failed"); } } mChildList.Clear(); diff --git a/uriloader/exthandler/mac/nsOSHelperAppService.mm b/uriloader/exthandler/mac/nsOSHelperAppService.mm index 5f0788bed7a33..00f12f5448bac 100644 --- a/uriloader/exthandler/mac/nsOSHelperAppService.mm +++ b/uriloader/exthandler/mac/nsOSHelperAppService.mm @@ -561,7 +561,7 @@ static CFArrayRef GetMIMETypesHandledByApp(FSRef *aAppRef) nsAutoString desc; rv = GetApplicationDescription(aScheme, desc); - NS_WARN_IF(NS_FAILED(rv)); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "GetApplicationDescription failed"); handlerInfo->SetDefaultDescription(desc); return NS_OK; diff --git a/widget/ContentCache.cpp b/widget/ContentCache.cpp index fe4023c4b1a14..9b2d0da27d335 100644 --- a/widget/ContentCache.cpp +++ b/widget/ContentCache.cpp @@ -499,7 +499,7 @@ ContentCacheInChild::SetSelection(nsIWidget* aWidget, if (NS_WARN_IF(!CacheCaret(aWidget))) { return; } - NS_WARN_IF(!CacheTextRects(aWidget)); + Unused << NS_WARN_IF(!CacheTextRects(aWidget)); } /***************************************************************************** @@ -528,10 +528,10 @@ ContentCacheInParent::AssignContent(const ContentCache& aOther, mEditorRect = aOther.mEditorRect; if (mIsComposing) { - NS_WARN_IF(mCompositionStart == UINT32_MAX); + NS_WARNING_ASSERTION(mCompositionStart != UINT32_MAX, "mCompositionStart"); IMEStateManager::MaybeStartOffsetUpdatedInChild(aWidget, mCompositionStart); } else { - NS_WARN_IF(mCompositionStart != UINT32_MAX); + NS_WARNING_ASSERTION(mCompositionStart == UINT32_MAX, "mCompositionStart"); } MOZ_LOG(sContentCacheLog, LogLevel::Info, @@ -836,27 +836,31 @@ ContentCacheInParent::GetTextRect(uint32_t aOffset, mSelection.mAnchor, mSelection.mFocus)); if (!aOffset) { - NS_WARN_IF(mFirstCharRect.IsEmpty()); + NS_WARNING_ASSERTION(!mFirstCharRect.IsEmpty(), "empty rect"); aTextRect = mFirstCharRect; return !aTextRect.IsEmpty(); } if (aOffset == mSelection.mAnchor) { - NS_WARN_IF(mSelection.mAnchorCharRects[eNextCharRect].IsEmpty()); + NS_WARNING_ASSERTION(!mSelection.mAnchorCharRects[eNextCharRect].IsEmpty(), + "empty rect"); aTextRect = mSelection.mAnchorCharRects[eNextCharRect]; return !aTextRect.IsEmpty(); } if (mSelection.mAnchor && aOffset == mSelection.mAnchor - 1) { - NS_WARN_IF(mSelection.mAnchorCharRects[ePrevCharRect].IsEmpty()); + NS_WARNING_ASSERTION(!mSelection.mAnchorCharRects[ePrevCharRect].IsEmpty(), + "empty rect"); aTextRect = mSelection.mAnchorCharRects[ePrevCharRect]; return !aTextRect.IsEmpty(); } if (aOffset == mSelection.mFocus) { - NS_WARN_IF(mSelection.mFocusCharRects[eNextCharRect].IsEmpty()); + NS_WARNING_ASSERTION(!mSelection.mFocusCharRects[eNextCharRect].IsEmpty(), + "empty rect"); aTextRect = mSelection.mFocusCharRects[eNextCharRect]; return !aTextRect.IsEmpty(); } if (mSelection.mFocus && aOffset == mSelection.mFocus - 1) { - NS_WARN_IF(mSelection.mFocusCharRects[ePrevCharRect].IsEmpty()); + NS_WARNING_ASSERTION(!mSelection.mFocusCharRects[ePrevCharRect].IsEmpty(), + "empty rect"); aTextRect = mSelection.mFocusCharRects[ePrevCharRect]; return !aTextRect.IsEmpty(); } @@ -908,34 +912,38 @@ ContentCacheInParent::GetUnionTextRects( if (!mSelection.Collapsed() && aOffset == mSelection.StartOffset() && aLength == mSelection.Length()) { - NS_WARN_IF(mSelection.mRect.IsEmpty()); + NS_WARNING_ASSERTION(!mSelection.mRect.IsEmpty(), "empty rect"); aUnionTextRect = mSelection.mRect; return !aUnionTextRect.IsEmpty(); } if (aLength == 1) { if (!aOffset) { - NS_WARN_IF(mFirstCharRect.IsEmpty()); + NS_WARNING_ASSERTION(!mFirstCharRect.IsEmpty(), "empty rect"); aUnionTextRect = mFirstCharRect; return !aUnionTextRect.IsEmpty(); } if (aOffset == mSelection.mAnchor) { - NS_WARN_IF(mSelection.mAnchorCharRects[eNextCharRect].IsEmpty()); + NS_WARNING_ASSERTION( + !mSelection.mAnchorCharRects[eNextCharRect].IsEmpty(), "empty rect"); aUnionTextRect = mSelection.mAnchorCharRects[eNextCharRect]; return !aUnionTextRect.IsEmpty(); } if (mSelection.mAnchor && aOffset == mSelection.mAnchor - 1) { - NS_WARN_IF(mSelection.mAnchorCharRects[ePrevCharRect].IsEmpty()); + NS_WARNING_ASSERTION( + !mSelection.mAnchorCharRects[ePrevCharRect].IsEmpty(), "empty rect"); aUnionTextRect = mSelection.mAnchorCharRects[ePrevCharRect]; return !aUnionTextRect.IsEmpty(); } if (aOffset == mSelection.mFocus) { - NS_WARN_IF(mSelection.mFocusCharRects[eNextCharRect].IsEmpty()); + NS_WARNING_ASSERTION( + !mSelection.mFocusCharRects[eNextCharRect].IsEmpty(), "empty rect"); aUnionTextRect = mSelection.mFocusCharRects[eNextCharRect]; return !aUnionTextRect.IsEmpty(); } if (mSelection.mFocus && aOffset == mSelection.mFocus - 1) { - NS_WARN_IF(mSelection.mFocusCharRects[ePrevCharRect].IsEmpty()); + NS_WARNING_ASSERTION( + !mSelection.mFocusCharRects[ePrevCharRect].IsEmpty(), "empty rect"); aUnionTextRect = mSelection.mFocusCharRects[ePrevCharRect]; return !aUnionTextRect.IsEmpty(); } diff --git a/widget/android/GeneratedJNIWrappers.cpp b/widget/android/GeneratedJNIWrappers.cpp index 69d26ce93d797..fef3505f9db1c 100644 --- a/widget/android/GeneratedJNIWrappers.cpp +++ b/widget/android/GeneratedJNIWrappers.cpp @@ -1362,6 +1362,19 @@ auto GeckoLayerClient::SynthesizeNativeTouchPoint(int32_t a0, int32_t a1, int32_ return mozilla::jni::Method::Call(GeckoLayerClient::mCtx, nullptr, a0, a1, a2, a3, a4, a5); } +constexpr char GeckoLayerClient::ClearColor_t::name[]; +constexpr char GeckoLayerClient::ClearColor_t::signature[]; + +auto GeckoLayerClient::ClearColor() const -> int32_t +{ + return mozilla::jni::Field::Get(GeckoLayerClient::mCtx, nullptr); +} + +auto GeckoLayerClient::ClearColor(int32_t a0) const -> void +{ + return mozilla::jni::Field::Set(GeckoLayerClient::mCtx, nullptr, a0); +} + const char ImmutableViewportMetrics::name[] = "org/mozilla/gecko/gfx/ImmutableViewportMetrics"; diff --git a/widget/android/GeneratedJNIWrappers.h b/widget/android/GeneratedJNIWrappers.h index 32909d1c49379..2b829a286eb55 100644 --- a/widget/android/GeneratedJNIWrappers.h +++ b/widget/android/GeneratedJNIWrappers.h @@ -4448,6 +4448,27 @@ class GeckoLayerClient : public mozilla::jni::ObjectBase auto SynthesizeNativeTouchPoint(int32_t, int32_t, int32_t, int32_t, double, int32_t) const -> void; + struct ClearColor_t { + typedef GeckoLayerClient Owner; + typedef int32_t ReturnType; + typedef int32_t SetterType; + typedef mozilla::jni::Args<> Args; + static constexpr char name[] = "mClearColor"; + static constexpr char signature[] = + "I"; + static const bool isStatic = false; + static const mozilla::jni::ExceptionMode exceptionMode = + mozilla::jni::ExceptionMode::ABORT; + static const mozilla::jni::CallingThread callingThread = + mozilla::jni::CallingThread::ANY; + static const mozilla::jni::DispatchTarget dispatchTarget = + mozilla::jni::DispatchTarget::CURRENT; + }; + + auto ClearColor() const -> int32_t; + + auto ClearColor(int32_t) const -> void; + static const mozilla::jni::CallingThread callingThread = mozilla::jni::CallingThread::ANY; diff --git a/widget/android/nsWindow.cpp b/widget/android/nsWindow.cpp index 573f2e3f41cf4..d0f83bab7360a 100644 --- a/widget/android/nsWindow.cpp +++ b/widget/android/nsWindow.cpp @@ -3489,6 +3489,28 @@ nsWindow::SynthesizeNativeMouseMove(LayoutDeviceIntPoint aPoint, return NS_OK; } +bool +nsWindow::PreRender(LayerManagerComposite* aManager) +{ + if (Destroyed()) { + return true; + } + + layers::Compositor* compositor = aManager->GetCompositor(); + + GeckoLayerClient::LocalRef client; + + if (NativePtr::Locked lvs{mLayerViewSupport}) { + client = lvs->GetLayerClient(); + } + + if (compositor && client) { + // Android Color is ARGB which is apparently unusual. + compositor->SetDefaultClearColor(gfx::Color::UnusualFromARGB((uint32_t)client->ClearColor())); + } + + return true; +} void nsWindow::DrawWindowUnderlay(LayerManagerComposite* aManager, LayoutDeviceIntRect aRect) @@ -3503,6 +3525,10 @@ nsWindow::DrawWindowUnderlay(LayerManagerComposite* aManager, client = lvs->GetLayerClient(); } + if (!client) { + return; + } + LayerRenderer::Frame::LocalRef frame = client->CreateFrame(); mLayerRendererFrame = frame; if (NS_WARN_IF(!mLayerRendererFrame)) { diff --git a/widget/android/nsWindow.h b/widget/android/nsWindow.h index 424bb983ac712..05356dfec9b26 100644 --- a/widget/android/nsWindow.h +++ b/widget/android/nsWindow.h @@ -199,6 +199,7 @@ class nsWindow : public nsBaseWidget LayerManagerPersistence aPersistence = LAYER_MANAGER_CURRENT) override; virtual bool NeedsPaint() override; + virtual bool PreRender(LayerManagerComposite* aManager) override; virtual void DrawWindowUnderlay(LayerManagerComposite* aManager, LayoutDeviceIntRect aRect) override; virtual void DrawWindowOverlay(LayerManagerComposite* aManager, LayoutDeviceIntRect aRect) override; diff --git a/widget/cocoa/VibrancyManager.h b/widget/cocoa/VibrancyManager.h index 56ae35140e5fa..3ed7db49ee023 100644 --- a/widget/cocoa/VibrancyManager.h +++ b/widget/cocoa/VibrancyManager.h @@ -73,6 +73,8 @@ class VibrancyManager { void UpdateVibrantRegion(VibrancyType aType, const LayoutDeviceIntRegion& aRegion); + bool HasVibrantRegions() { return !mVibrantRegions.IsEmpty(); } + /** * Clear the vibrant areas that we know about. * The clearing happens in the current NSGraphicsContext. If you call this diff --git a/widget/cocoa/VibrancyManager.mm b/widget/cocoa/VibrancyManager.mm index 1e5f431f40c51..76bbdfed2f990 100644 --- a/widget/cocoa/VibrancyManager.mm +++ b/widget/cocoa/VibrancyManager.mm @@ -14,6 +14,10 @@ VibrancyManager::UpdateVibrantRegion(VibrancyType aType, const LayoutDeviceIntRegion& aRegion) { + if (aRegion.IsEmpty()) { + mVibrantRegions.Remove(uint32_t(aType)); + return; + } auto& vr = *mVibrantRegions.LookupOrAdd(uint32_t(aType)); vr.UpdateRegion(aRegion, mCoordinateConverter, mContainerView, ^() { return this->CreateEffectView(aType); diff --git a/widget/cocoa/nsChildView.h b/widget/cocoa/nsChildView.h index f609cfef8cdf1..d7d5b590c75f0 100644 --- a/widget/cocoa/nsChildView.h +++ b/widget/cocoa/nsChildView.h @@ -598,6 +598,7 @@ class nsChildView : public nsBaseWidget int mDevPixelCornerRadius; bool mIsCoveringTitlebar; bool mIsFullscreen; + bool mIsOpaque; LayoutDeviceIntRect mTitlebarRect; // The area of mTitlebarCGContext that needs to be redrawn during the next diff --git a/widget/cocoa/nsChildView.mm b/widget/cocoa/nsChildView.mm index 3defd1e5ffea4..edc4b7dffc3ef 100644 --- a/widget/cocoa/nsChildView.mm +++ b/widget/cocoa/nsChildView.mm @@ -178,7 +178,7 @@ - (BOOL)hasRoundedBottomCorners; - (CGFloat)cornerRadius; - (void)clearCorners; --(void)setFullscreen:(BOOL)aFullscreen; +-(void)setGLOpaque:(BOOL)aOpaque; // Overlay drawing functions for traditional CGContext drawing - (void)drawTitleString; @@ -351,6 +351,7 @@ virtual void BindAndDrawQuad(ShaderProgramOGL *aProg, , mHasRoundedBottomCorners(false) , mIsCoveringTitlebar(false) , mIsFullscreen(false) +, mIsOpaque(false) , mTitlebarCGContext(nullptr) , mBackingScaleFactor(0.0) , mVisible(false) @@ -1982,7 +1983,7 @@ inline uint16_t COLOR8TOCOLOR16(uint8_t color8) { NS_OBJC_BEGIN_TRY_ABORT_BLOCK; - bool isFullscreen; + bool canBeOpaque; { MutexAutoLock lock(mEffectsLock); mShowsResizeIndicator = ShowsResizeIndicator(&mResizeIndicatorRect); @@ -1991,7 +1992,13 @@ inline uint16_t COLOR8TOCOLOR16(uint8_t color8) mDevPixelCornerRadius = cornerRadius * BackingScaleFactor(); mIsCoveringTitlebar = [(ChildView*)mView isCoveringTitlebar]; NSInteger styleMask = [[mView window] styleMask]; - isFullscreen = (styleMask & NSFullScreenWindowMask) || !(styleMask & NSTitledWindowMask); + bool wasFullscreen = mIsFullscreen; + mIsFullscreen = (styleMask & NSFullScreenWindowMask) || !(styleMask & NSTitledWindowMask); + + canBeOpaque = mIsFullscreen && wasFullscreen; + if (canBeOpaque && VibrancyManager::SystemSupportsVibrancy()) { + canBeOpaque = !EnsureVibrancyManager().HasVibrantRegions(); + } if (mIsCoveringTitlebar) { mTitlebarRect = RectContainingTitlebarControls(); UpdateTitlebarCGContext(); @@ -1999,9 +2006,9 @@ inline uint16_t COLOR8TOCOLOR16(uint8_t color8) } // If we've just transitioned into or out of full screen then update the opacity on our GLContext. - if (isFullscreen != mIsFullscreen) { - mIsFullscreen = isFullscreen; - [(ChildView*)mView setFullscreen:isFullscreen]; + if (canBeOpaque != mIsOpaque) { + mIsOpaque = canBeOpaque; + [(ChildView*)mView setGLOpaque:canBeOpaque]; } NS_OBJC_END_TRY_ABORT_BLOCK; @@ -3827,12 +3834,12 @@ - (CGFloat)cornerRadius return [frameView roundedCornerRadius]; } --(void)setFullscreen:(BOOL)aFullscreen +-(void)setGLOpaque:(BOOL)aOpaque { CGLLockContext((CGLContextObj)[mGLContext CGLContextObj]); // Make the context opaque for fullscreen (since it performs better), and transparent // for windowed (since we need it for rounded corners). - GLint opaque = aFullscreen ? 1 : 0; + GLint opaque = aOpaque ? 1 : 0; [mGLContext setValues:&opaque forParameter:NSOpenGLCPSurfaceOpacity]; CGLUnlockContext((CGLContextObj)[mGLContext CGLContextObj]); } diff --git a/widget/windows/GfxInfo.cpp b/widget/windows/GfxInfo.cpp index 5922acfe68abd..eab4be821f578 100644 --- a/widget/windows/GfxInfo.cpp +++ b/widget/windows/GfxInfo.cpp @@ -991,21 +991,21 @@ GfxInfo::GetGfxDriverInfo() APPEND_TO_DRIVER_BLOCKLIST2( winVer, \ (nsAString&) GfxDriverInfo::GetDeviceVendor(VendorIntel), (GfxDeviceFamily*) GfxDriverInfo::GetDeviceFamily(devFamily), \ nsIGfxInfo::FEATURE_DIRECT2D, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, \ - DRIVER_LESS_THAN, driverVer, ruleId ) + DRIVER_BUILD_ID_LESS_THAN, driverVer, ruleId ) - IMPLEMENT_INTEL_DRIVER_BLOCKLIST_D2D(OperatingSystem::WindowsVista, IntelGMA500, V(7,14,10,1006), "FEATURE_FAILURE_594877_1"); + IMPLEMENT_INTEL_DRIVER_BLOCKLIST_D2D(OperatingSystem::WindowsVista, IntelGMA500, 1006, "FEATURE_FAILURE_594877_1"); IMPLEMENT_INTEL_DRIVER_BLOCKLIST_D2D(OperatingSystem::WindowsVista, IntelGMA900, GfxDriverInfo::allDriverVersions, "FEATURE_FAILURE_594877_2"); - IMPLEMENT_INTEL_DRIVER_BLOCKLIST_D2D(OperatingSystem::WindowsVista, IntelGMA950, V(7,14,10,1504), "FEATURE_FAILURE_594877_3"); - IMPLEMENT_INTEL_DRIVER_BLOCKLIST_D2D(OperatingSystem::WindowsVista, IntelGMA3150, V(7,14,10,2124), "FEATURE_FAILURE_594877_4"); - IMPLEMENT_INTEL_DRIVER_BLOCKLIST_D2D(OperatingSystem::WindowsVista, IntelGMAX3000, V(7,15,10,1666), "FEATURE_FAILURE_594877_5"); - IMPLEMENT_INTEL_DRIVER_BLOCKLIST_D2D(OperatingSystem::WindowsVista, IntelHDGraphicsToSandyBridge, V(8,15,10,2202), "FEATURE_FAILURE_594877_6"); + IMPLEMENT_INTEL_DRIVER_BLOCKLIST_D2D(OperatingSystem::WindowsVista, IntelGMA950, 1504, "FEATURE_FAILURE_594877_3"); + IMPLEMENT_INTEL_DRIVER_BLOCKLIST_D2D(OperatingSystem::WindowsVista, IntelGMA3150, 2124, "FEATURE_FAILURE_594877_4"); + IMPLEMENT_INTEL_DRIVER_BLOCKLIST_D2D(OperatingSystem::WindowsVista, IntelGMAX3000, 1666, "FEATURE_FAILURE_594877_5"); + IMPLEMENT_INTEL_DRIVER_BLOCKLIST_D2D(OperatingSystem::WindowsVista, IntelHDGraphicsToSandyBridge, 2202, "FEATURE_FAILURE_594877_6"); - IMPLEMENT_INTEL_DRIVER_BLOCKLIST_D2D(OperatingSystem::Windows7, IntelGMA500, V(5,0,0,2026), "FEATURE_FAILURE_594877_7"); + IMPLEMENT_INTEL_DRIVER_BLOCKLIST_D2D(OperatingSystem::Windows7, IntelGMA500, 2026, "FEATURE_FAILURE_594877_7"); IMPLEMENT_INTEL_DRIVER_BLOCKLIST_D2D(OperatingSystem::Windows7, IntelGMA900, GfxDriverInfo::allDriverVersions, "FEATURE_FAILURE_594877_8"); - IMPLEMENT_INTEL_DRIVER_BLOCKLIST_D2D(OperatingSystem::Windows7, IntelGMA950, V(8,15,10,1930), "FEATURE_FAILURE_594877_9"); - IMPLEMENT_INTEL_DRIVER_BLOCKLIST_D2D(OperatingSystem::Windows7, IntelGMA3150, V(8,14,10,2117), "FEATURE_FAILURE_594877_10"); - IMPLEMENT_INTEL_DRIVER_BLOCKLIST_D2D(OperatingSystem::Windows7, IntelGMAX3000, V(8,15,10,1930), "FEATURE_FAILURE_594877_11"); - IMPLEMENT_INTEL_DRIVER_BLOCKLIST_D2D(OperatingSystem::Windows7, IntelHDGraphicsToSandyBridge, V(8,15,10,2202), "FEATURE_FAILURE_594877_12"); + IMPLEMENT_INTEL_DRIVER_BLOCKLIST_D2D(OperatingSystem::Windows7, IntelGMA950, 1930, "FEATURE_FAILURE_594877_9"); + IMPLEMENT_INTEL_DRIVER_BLOCKLIST_D2D(OperatingSystem::Windows7, IntelGMA3150, 2117, "FEATURE_FAILURE_594877_10"); + IMPLEMENT_INTEL_DRIVER_BLOCKLIST_D2D(OperatingSystem::Windows7, IntelGMAX3000, 1930, "FEATURE_FAILURE_594877_11"); + IMPLEMENT_INTEL_DRIVER_BLOCKLIST_D2D(OperatingSystem::Windows7, IntelHDGraphicsToSandyBridge, 2202, "FEATURE_FAILURE_594877_12"); /* Disable Direct2D on Intel GMAX4500 devices because of rendering corruption discovered * in bug 1180379. These seems to affect even the most recent drivers. We're black listing @@ -1167,10 +1167,10 @@ GfxInfo::GetGfxDriverInfo() DRIVER_LESS_THAN, V(8,15,10,2869), "FEATURE_FAILURE_INTEL_W7_HW_DECODING"); /* Bug 1203199/1092166: DXVA startup crashes on some intel drivers. */ - APPEND_TO_DRIVER_BLOCKLIST_RANGE(OperatingSystem::Windows, + APPEND_TO_DRIVER_BLOCKLIST(OperatingSystem::Windows, (nsAString&)GfxDriverInfo::GetDeviceVendor(VendorIntel), GfxDriverInfo::allDevices, nsIGfxInfo::FEATURE_HARDWARE_VIDEO_DECODING, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, - DRIVER_BETWEEN_INCLUSIVE, V(9,17,10,0), V(9,17,10,2849), "FEATURE_FAILURE_BUG_1203199_1", "Intel driver > 9.17.10.2849"); + DRIVER_BUILD_ID_LESS_THAN_OR_EQUAL, 2849, "FEATURE_FAILURE_BUG_1203199_1", "Intel driver > X.X.X.2849"); APPEND_TO_DRIVER_BLOCKLIST2(OperatingSystem::Windows, (nsAString&)GfxDriverInfo::GetDeviceVendor(VendorNVIDIA), (GfxDeviceFamily*)GfxDriverInfo::GetDeviceFamily(Nvidia8800GTS), diff --git a/xpcom/base/CycleCollectedJSRuntime.cpp b/xpcom/base/CycleCollectedJSRuntime.cpp index 1cfa16603f5e8..bfde991ce85d0 100644 --- a/xpcom/base/CycleCollectedJSRuntime.cpp +++ b/xpcom/base/CycleCollectedJSRuntime.cpp @@ -64,6 +64,7 @@ #include "mozilla/Telemetry.h" #include "mozilla/TimelineConsumers.h" #include "mozilla/TimelineMarker.h" +#include "mozilla/Unused.h" #include "mozilla/DebuggerOnGCRunnable.h" #include "mozilla/dom/DOMJSClass.h" #include "mozilla/dom/ProfileTimelineMarkerBinding.h" @@ -817,10 +818,11 @@ CycleCollectedJSRuntime::GCSliceCallback(JSContext* aContext, if (aProgress == JS::GC_CYCLE_END) { JS::gcreason::Reason reason = aDesc.reason_; - NS_WARN_IF(NS_FAILED(DebuggerOnGCRunnable::Enqueue(aContext, aDesc)) && - reason != JS::gcreason::SHUTDOWN_CC && - reason != JS::gcreason::DESTROY_RUNTIME && - reason != JS::gcreason::XPCONNECT_SHUTDOWN); + Unused << + NS_WARN_IF(NS_FAILED(DebuggerOnGCRunnable::Enqueue(aContext, aDesc)) && + reason != JS::gcreason::SHUTDOWN_CC && + reason != JS::gcreason::DESTROY_RUNTIME && + reason != JS::gcreason::XPCONNECT_SHUTDOWN); } if (self->mPrevGCSliceCallback) { diff --git a/xpcom/base/nsCycleCollector.cpp b/xpcom/base/nsCycleCollector.cpp index 6401e94bcbfdc..61a339ee2f3da 100644 --- a/xpcom/base/nsCycleCollector.cpp +++ b/xpcom/base/nsCycleCollector.cpp @@ -1948,7 +1948,7 @@ class nsCycleCollectorLogger final : public nsICycleCollectorListener { if (!mDisableLog) { mCCLog = nullptr; - NS_WARN_IF(NS_FAILED(mLogSink->CloseCCLog())); + Unused << NS_WARN_IF(NS_FAILED(mLogSink->CloseCCLog())); } } NS_IMETHOD ProcessNext(nsICycleCollectorHandler* aHandler, diff --git a/xpcom/base/nsMemoryInfoDumper.cpp b/xpcom/base/nsMemoryInfoDumper.cpp index ce2ad2ba7dd56..06453b126ffdf 100644 --- a/xpcom/base/nsMemoryInfoDumper.cpp +++ b/xpcom/base/nsMemoryInfoDumper.cpp @@ -797,7 +797,7 @@ nsMemoryInfoDumper::OpenDMDFile(const nsAString& aIdentifier, int aPid, return rv; } rv = dmdFile->OpenANSIFileDesc("wb", aOutFile); - NS_WARN_IF(NS_FAILED(rv)); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "OpenANSIFileDesc failed"); // Print the path, because on some platforms (e.g. Mac) it's not obvious. nsCString path; @@ -823,7 +823,7 @@ nsMemoryInfoDumper::DumpDMDToFile(FILE* aFile) dmd::Analyze(MakeUnique(gzWriter)); rv = gzWriter->Finish(); - NS_WARN_IF(NS_FAILED(rv)); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Finish failed"); return rv; } #endif // MOZ_DMD diff --git a/xpcom/build/nsXULAppAPI.h b/xpcom/build/nsXULAppAPI.h index a87e85ab1445c..7551cb20a1916 100644 --- a/xpcom/build/nsXULAppAPI.h +++ b/xpcom/build/nsXULAppAPI.h @@ -520,4 +520,16 @@ XRE_API(void, XRE_GlibInit, ()) #endif + +#ifdef LIBFUZZER +#include "LibFuzzerRegistry.h" + +XRE_API(void, + XRE_LibFuzzerSetMain, (int, char**, LibFuzzerMain)) + +XRE_API(void, + XRE_LibFuzzerGetFuncs, (const char*, LibFuzzerInitFunc*, + LibFuzzerTestingFunc*)) +#endif // LIBFUZZER + #endif // _nsXULAppAPI_h__ diff --git a/xpcom/glue/nsDebug.h b/xpcom/glue/nsDebug.h index 9540c95cca156..86495e47f0aa5 100644 --- a/xpcom/glue/nsDebug.h +++ b/xpcom/glue/nsDebug.h @@ -24,18 +24,32 @@ * release and debug builds, and the result is an expression which can be * used in subsequent expressions, such as: * - * if (NS_WARN_IF(NS_FAILED(rv)) + * if (NS_WARN_IF(NS_FAILED(rv)) { * return rv; + * } * * This explicit warning and return is preferred to the NS_ENSURE_* macros * which hide the warning and the return control flow. * + * This macro can also be used outside of conditions just to issue a warning, + * like so: + * + * Unused << NS_WARN_IF(NS_FAILED(FnWithSideEffects()); + * + * (The |Unused <<| is necessary because of the MOZ_MUST_USE annotation.) + * + * However, note that the argument to this macro is evaluated in all builds. If + * you just want a warning assertion, it is better to use NS_WARNING_ASSERTION + * (which evaluates the condition only in debug builds) like so: + * + * NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "operation failed"); + * * @note This is C++-only */ #ifdef __cplusplus #ifdef DEBUG -inline bool NS_warn_if_impl(bool aCondition, const char* aExpr, - const char* aFile, int32_t aLine) +inline MOZ_MUST_USE bool NS_warn_if_impl(bool aCondition, const char* aExpr, + const char* aFile, int32_t aLine) { if (MOZ_UNLIKELY(aCondition)) { NS_DebugBreak(NS_DEBUG_WARNING, nullptr, aExpr, aFile, aLine);