author | Carsten "Tomcat" Book <cbook@mozilla.com> |
Mon, 14 Nov 2016 10:22:06 +0100 | |
changeset 322374 | 1196bf3032e1bce1fb07a01fd9082a767426c5fb |
parent 322258 | add9dada238ed99b4f93c027b535423f067d3781 (current diff) |
parent 322373 | 71825cbd0e2549d813d8279dcdb19fb357f8ab3f (diff) |
child 322375 | 67a7f044f3f995defdd9721431fde57f9fd422a0 |
child 322388 | f9c01ced5685b4a1e8af1de4d3089b298afc0507 |
child 322455 | c29cedd0d3f883f1a798160fbc46ccc0a04b4925 |
push id | 30945 |
push user | cbook@mozilla.com |
push date | Mon, 14 Nov 2016 09:22:29 +0000 |
treeherder | mozilla-central@1196bf3032e1 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | merge |
milestone | 52.0a1 |
first release with | nightly linux32
1196bf3032e1
/
52.0a1
/
20161114030203
/
files
nightly linux64
1196bf3032e1
/
52.0a1
/
20161114030203
/
files
nightly mac
1196bf3032e1
/
52.0a1
/
20161114030203
/
files
nightly win32
1196bf3032e1
/
52.0a1
/
20161114030203
/
files
nightly win64
1196bf3032e1
/
52.0a1
/
20161114030203
/
files
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
releases | nightly linux32
52.0a1
/
20161114030203
/
pushlog to previous
nightly linux64
52.0a1
/
20161114030203
/
pushlog to previous
nightly mac
52.0a1
/
20161114030203
/
pushlog to previous
nightly win32
52.0a1
/
20161114030203
/
pushlog to previous
nightly win64
52.0a1
/
20161114030203
/
pushlog to previous
|
--- a/addon-sdk/source/lib/sdk/ui/frame/view.html +++ b/addon-sdk/source/lib/sdk/ui/frame/view.html @@ -1,18 +1,18 @@ -<script> -// HACK: This is not an ideal way to deliver chrome messages -// to a innef frame content but seems only way that would -// make `event.source` an this (outer frame) window. -window.onmessage = function(event) { - var frame = document.querySelector("iframe"); - var content = frame.contentWindow; - // If message is posted from chrome it has no `event.source`. - if (event.source === null) - content.postMessage(event.data, "*"); -}; -// Hack: Ideally we would have used srcdoc on iframe, but in -// that case origin of document is either content which is unable -// to load add-on resources or a chrome to which add-on resource -// can not send messages back. -document.documentElement.style.overflow = "hidden"; -document.documentElement.innerHTML = atob(location.hash.substr(1)); -</script> +<!DOCTYPE html> +<html> + <head> + <script> + // HACK: This is not an ideal way to deliver chrome messages + // to an inner frame content but seems only way that would + // make `event.source` this (outer frame) window. + window.onmessage = function(event) { + var frame = document.querySelector("iframe"); + var content = frame.contentWindow; + // If message is posted from chrome it has no `event.source`. + if (event.source === null) + content.postMessage(event.data, "*"); + }; + </script> + </head> + <body style="overflow: hidden"></body> +</html>
--- a/addon-sdk/source/lib/sdk/ui/frame/view.js +++ b/addon-sdk/source/lib/sdk/ui/frame/view.js @@ -58,39 +58,45 @@ const registerFrame = ({id, url}) => { id: id, type: "custom", removable: true, onBuild: document => { let view = document.createElementNS(XUL_NS, "toolbaritem"); view.setAttribute("id", id); view.setAttribute("flex", 2); - let innerFrame = document.createElementNS(HTML_NS, "iframe"); - innerFrame.setAttribute("id", id); - innerFrame.setAttribute("src", url); - innerFrame.setAttribute("seamless", "seamless"); - innerFrame.setAttribute("sandbox", "allow-scripts"); - innerFrame.setAttribute("scrolling", "no"); - innerFrame.setAttribute("data-is-sdk-inner-frame", true); - innerFrame.setAttribute("style", [ "border:none", - "position:absolute", "width:100%", "top: 0", - "left: 0", "overflow: hidden"].join(";")); - let outerFrame = document.createElementNS(XUL_NS, "iframe"); - outerFrame.setAttribute("src", OUTER_FRAME_URI + "#" + - encode(innerFrame.outerHTML)); + outerFrame.setAttribute("src", OUTER_FRAME_URI); outerFrame.setAttribute("id", "outer-" + id); outerFrame.setAttribute("data-is-sdk-outer-frame", true); outerFrame.setAttribute("type", "content"); outerFrame.setAttribute("transparent", true); outerFrame.setAttribute("flex", 2); outerFrame.setAttribute("style", "overflow: hidden;"); outerFrame.setAttribute("scrolling", "no"); outerFrame.setAttribute("disablehistory", true); outerFrame.setAttribute("seamless", "seamless"); + outerFrame.addEventListener("load", function onload() { + outerFrame.removeEventListener("load", onload, true); + + let doc = outerFrame.contentDocument; + + let innerFrame = doc.createElementNS(HTML_NS, "iframe"); + innerFrame.setAttribute("id", id); + innerFrame.setAttribute("src", url); + innerFrame.setAttribute("seamless", "seamless"); + innerFrame.setAttribute("sandbox", "allow-scripts"); + innerFrame.setAttribute("scrolling", "no"); + innerFrame.setAttribute("data-is-sdk-inner-frame", true); + innerFrame.setAttribute("style", [ "border:none", + "position:absolute", "width:100%", "top: 0", + "left: 0", "overflow: hidden"].join(";")); + + doc.body.appendChild(innerFrame); + }, true); view.appendChild(outerFrame); return view; } }); };
--- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -133,19 +133,16 @@ pref("app.update.badge", false); // when it finishes downloading them. pref("app.update.staging.enabled", true); // Update service URL: pref("app.update.url", "https://aus5.mozilla.org/update/6/%PRODUCT%/%VERSION%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%SYSTEM_CAPABILITIES%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/update.xml"); // app.update.url.manual is in branding section // app.update.url.details is in branding section -// User-settable override to app.update.url for testing purposes. -//pref("app.update.url.override", ""); - // app.update.interval is in branding section // app.update.promptWaitTime is in branding section // Show the Update Checking/Ready UI when the user was idle for x seconds pref("app.update.idletime", 60); // Whether or not to attempt using the service for updates. #ifdef MOZ_MAINTENANCE_SERVICE
--- a/browser/components/extensions/test/browser/browser_ext_browserAction_disabled.js +++ b/browser/components/extensions/test/browser/browser_ext_browserAction_disabled.js @@ -36,30 +36,33 @@ add_task(function* testDisabled() { browser.test.sendMessage("ready"); }, }); yield extension.startup(); yield extension.awaitMessage("ready"); yield clickBrowserAction(extension); + yield new Promise(resolve => setTimeout(resolve, 0)); extension.sendMessage("check-clicked", true); yield extension.awaitMessage("next-test"); extension.sendMessage("disable"); yield extension.awaitMessage("next-test"); yield clickBrowserAction(extension); + yield new Promise(resolve => setTimeout(resolve, 0)); extension.sendMessage("check-clicked", false); yield extension.awaitMessage("next-test"); extension.sendMessage("enable"); yield extension.awaitMessage("next-test"); yield clickBrowserAction(extension); + yield new Promise(resolve => setTimeout(resolve, 0)); extension.sendMessage("check-clicked", true); yield extension.awaitMessage("next-test"); yield extension.unload(); });
--- a/browser/components/extensions/test/browser/browser_ext_windows_create_tabId.js +++ b/browser/components/extensions/test/browser/browser_ext_windows_create_tabId.js @@ -91,24 +91,29 @@ add_task(function* testWindowCreate() { browser.test.log("Try to create a window with an invalid tabId"); await browser.test.assertRejects( browser.windows.create({tabId: 0}), /Invalid tab ID: 0/, "Create call failed as expected"); browser.test.log("Try to create a window with two URLs"); - [, , window] = await Promise.all([ + let readyPromise = Promise.all([ // tabs.onUpdated can be invoked between the call of windows.create and // the invocation of its callback/promise, so set up the listeners // before creating the window. promiseTabUpdated("http://example.com/"), promiseTabUpdated("http://example.org/"), - browser.windows.create({url: ["http://example.com/", "http://example.org/"]}), ]); + + await new Promise(resolve => setTimeout(resolve, 0)); + + window = await browser.windows.create({url: ["http://example.com/", "http://example.org/"]}); + await readyPromise; + browser.test.assertEq(2, window.tabs.length, "2 tabs were opened in new window"); browser.test.assertEq("about:blank", window.tabs[0].url, "about:blank, page not loaded yet"); browser.test.assertEq("about:blank", window.tabs[1].url, "about:blank, page not loaded yet"); window = await browser.windows.get(window.id, {populate: true}); browser.test.assertEq(2, window.tabs.length, "2 tabs were opened in new window"); browser.test.assertEq("http://example.com/", window.tabs[0].url, "Correct URL was loaded in tab 1");
--- a/browser/components/migration/MSMigrationUtils.jsm +++ b/browser/components/migration/MSMigrationUtils.jsm @@ -559,17 +559,17 @@ Cookies.prototype = { } catch (ex) { Components.utils.reportError("Unable to migrate cookie: " + ex); success = false; } finally { aCallback(success); } }; fileReader.addEventListener("loadend", onLoadEnd, false); - fileReader.readAsText(new File(aFile)); + fileReader.readAsText(File.createFromNsIFile(aFile)); }, /** * Parses a cookie file buffer and returns an array of the contained cookies. * * The cookie file format is a newline-separated-values with a "*" used as * delimeter between multiple records. * Each cookie has the following fields:
--- a/browser/extensions/e10srollout/bootstrap.js +++ b/browser/extensions/e10srollout/bootstrap.js @@ -165,20 +165,10 @@ function optedOut() { /* If this function returns a non-empty string, it * means that this particular user should be temporarily * disqualified due to some particular reason. * If a user shouldn't be disqualified, then an empty * string must be returned. */ function getTemporaryDisqualification() { - let applicationLanguage = - Cc["@mozilla.org/chrome/chrome-registry;1"] - .getService(Ci.nsIXULChromeRegistry) - .getSelectedLocale("global") - .split("-")[0]; - - if (applicationLanguage == "ru") { - return "ru"; - } - return ""; }
--- a/browser/extensions/pdfjs/README.mozilla +++ b/browser/extensions/pdfjs/README.mozilla @@ -1,3 +1,3 @@ This is the pdf.js project output, https://github.com/mozilla/pdf.js -Current extension version is: 1.6.304 +Current extension version is: 1.6.315
--- a/browser/extensions/pdfjs/content/build/pdf.js +++ b/browser/extensions/pdfjs/content/build/pdf.js @@ -19,18 +19,18 @@ } else if (typeof exports !== 'undefined') { factory(exports); } else { factory(root['pdfjsDistBuildPdf'] = {}); } }(this, function (exports) { // Use strict in our context only - users might not want it 'use strict'; - var pdfjsVersion = '1.6.304'; - var pdfjsBuild = 'b4100ba'; + var pdfjsVersion = '1.6.315'; + var pdfjsBuild = 'a139c75'; var pdfjsFilePath = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : null; var pdfjsLibs = {}; (function pdfjsWrapper() { (function (root, factory) { factory(root.pdfjsSharedUtil = {}); }(this, function (exports) { var globalScope = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : this; var FONT_IDENTITY_MATRIX = [
--- a/browser/extensions/pdfjs/content/build/pdf.worker.js +++ b/browser/extensions/pdfjs/content/build/pdf.worker.js @@ -19,18 +19,18 @@ } else if (typeof exports !== 'undefined') { factory(exports); } else { factory(root['pdfjsDistBuildPdfWorker'] = {}); } }(this, function (exports) { // Use strict in our context only - users might not want it 'use strict'; - var pdfjsVersion = '1.6.304'; - var pdfjsBuild = 'b4100ba'; + var pdfjsVersion = '1.6.315'; + var pdfjsBuild = 'a139c75'; var pdfjsFilePath = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : null; var pdfjsLibs = {}; (function pdfjsWrapper() { (function (root, factory) { factory(root.pdfjsCoreArithmeticDecoder = {}); }(this, function (exports) { /* This class implements the QM Coder decoding as defined in * JPEG 2000 Part I Final Committee Draft Version 1.0 @@ -45074,16 +45074,39 @@ } break; case 'Named': var namedAction = action.get('N'); if (isName(namedAction)) { resultObj.action = namedAction.name; } break; + case 'JavaScript': + var jsAction = action.get('JS'), js; + if (isStream(jsAction)) { + js = bytesToString(jsAction.getBytes()); + } else if (isString(jsAction)) { + js = jsAction; + } + if (js) { + // Attempt to recover valid URLs from 'JS' entries with certain + // white-listed formats, e.g. + // - window.open('http://example.com') + // - app.launchURL('http://example.com', true) + var URL_OPEN_METHODS = [ + 'app.launchURL', + 'window.open' + ]; + var regex = new RegExp('^(?:' + URL_OPEN_METHODS.join('|') + ')' + '\\((?:\'|\")(\\S+)(?:\'|\")(?:,|\\))'); + var jsUrl = regex.exec(stringToPDFString(js), 'i'); + if (jsUrl && jsUrl[1]) { + url = jsUrl[1]; + break; + } + } default: warn('Catalog_parseDestDictionary: Unrecognized link type "' + linkType + '".'); break; } } else if (destDict.has('Dest')) { // Simple destination link. dest = destDict.get('Dest'); }
--- a/browser/extensions/pdfjs/content/web/viewer.css +++ b/browser/extensions/pdfjs/content/web/viewer.css @@ -321,42 +321,16 @@ select { cursor: none; } .pdfPresentationMode.pdfPresentationModeControls > *, .pdfPresentationMode.pdfPresentationModeControls .textLayer > div { cursor: default; } -/* outer/inner center provides horizontal center */ -.outerCenter { - pointer-events: none; - position: relative; -} -html[dir='ltr'] .outerCenter { - float: right; - right: 50%; -} -html[dir='rtl'] .outerCenter { - float: left; - left: 50%; -} -.innerCenter { - pointer-events: auto; - position: relative; -} -html[dir='ltr'] .innerCenter { - float: right; - right: -50%; -} -html[dir='rtl'] .innerCenter { - float: left; - left: -50%; -} - #outerContainer { width: 100%; height: 100%; position: relative; } #sidebarContainer { position: absolute; @@ -660,34 +634,29 @@ html[dir='ltr'] .doorHangerRight:before font-style: italic; color: #A6B7D0; } #findInput.notFound { background-color: rgb(255, 102, 102); } -html[dir='ltr'] #toolbarViewerLeft { - margin-left: -1px; -} -html[dir='rtl'] #toolbarViewerRight { - margin-right: -1px; +#toolbarViewerMiddle { + position: absolute; + left: 50%; + transform: translateX(-50%); } html[dir='ltr'] #toolbarViewerLeft, html[dir='rtl'] #toolbarViewerRight { - position: absolute; - top: 0; - left: 0; + float: left; } html[dir='ltr'] #toolbarViewerRight, html[dir='rtl'] #toolbarViewerLeft { - position: absolute; - top: 0; - right: 0; + float: right; } html[dir='ltr'] #toolbarViewerLeft > *, html[dir='ltr'] #toolbarViewerMiddle > *, html[dir='ltr'] #toolbarViewerRight > *, html[dir='ltr'] .findbar > * { position: relative; float: left; } @@ -1953,48 +1922,57 @@ html[dir='rtl'] #documentPropertiesOverl } .visibleLargeView, .visibleMediumView, .visibleSmallView { display: none; } -@media all and (max-width: 960px) { - html[dir='ltr'] #outerContainer.sidebarMoving .outerCenter, - html[dir='ltr'] #outerContainer.sidebarOpen .outerCenter { - float: left; - left: 205px; - } - html[dir='rtl'] #outerContainer.sidebarMoving .outerCenter, - html[dir='rtl'] #outerContainer.sidebarOpen .outerCenter { - float: right; - right: 205px; +@media all and (max-width: 1040px) { + #outerContainer.sidebarMoving #toolbarViewerMiddle, + #outerContainer.sidebarOpen #toolbarViewerMiddle { + display: table; + margin: auto; + left: auto; + position: inherit; + transform: none; } } -@media all and (max-width: 900px) { +@media all and (max-width: 980px) { + .sidebarMoving .hiddenLargeView, .sidebarOpen .hiddenLargeView { display: none; } + .sidebarMoving .visibleLargeView, .sidebarOpen .visibleLargeView { display: inherit; } } -@media all and (max-width: 860px) { +@media all and (max-width: 900px) { + #toolbarViewerMiddle { + display: table; + margin: auto; + left: auto; + position: inherit; + transform: none; + } + .sidebarMoving .hiddenMediumView, .sidebarOpen .hiddenMediumView { display: none; } + .sidebarMoving .visibleMediumView, .sidebarOpen .visibleMediumView { display: inherit; } } -@media all and (max-width: 770px) { +@media all and (max-width: 840px) { #sidebarContainer { top: 32px; z-index: 100; } .loadingInProgress #sidebarContainer { top: 37px; } #sidebarContent { @@ -2004,72 +1982,53 @@ html[dir='rtl'] #documentPropertiesOverl html[dir='ltr'] #outerContainer.sidebarOpen > #mainContainer { left: 0px; } html[dir='rtl'] #outerContainer.sidebarOpen > #mainContainer { right: 0px; } - html[dir='ltr'] .outerCenter { - float: left; - left: 205px; - } - html[dir='rtl'] .outerCenter { - float: right; - right: 205px; - } - #outerContainer .hiddenLargeView, #outerContainer .hiddenMediumView { display: inherit; } #outerContainer .visibleLargeView, #outerContainer .visibleMediumView { display: none; } } -@media all and (max-width: 700px) { +@media all and (max-width: 770px) { #outerContainer .hiddenLargeView { display: none; } #outerContainer .visibleLargeView { display: inherit; } } -@media all and (max-width: 660px) { +@media all and (max-width: 700px) { #outerContainer .hiddenMediumView { display: none; } #outerContainer .visibleMediumView { display: inherit; } } -@media all and (max-width: 600px) { +@media all and (max-width: 640px) { .hiddenSmallView { display: none; } .visibleSmallView { display: inherit; } - html[dir='ltr'] #outerContainer.sidebarMoving .outerCenter, - html[dir='ltr'] #outerContainer.sidebarOpen .outerCenter, - html[dir='ltr'] .outerCenter { - left: 156px; - } - html[dir='rtl'] #outerContainer.sidebarMoving .outerCenter, - html[dir='rtl'] #outerContainer.sidebarOpen .outerCenter, - html[dir='rtl'] .outerCenter { - right: 156px; - } .toolbarButtonSpacer { width: 0; } } -@media all and (max-width: 510px) { +@media all and (max-width: 535px) { #scaleSelectContainer { display: none; } }
--- a/browser/extensions/pdfjs/content/web/viewer.html +++ b/browser/extensions/pdfjs/content/web/viewer.html @@ -189,45 +189,43 @@ See https://github.com/adobe-type-tools/ </a> <div class="verticalToolbarSeparator hiddenSmallView"></div> <button id="secondaryToolbarToggle" class="toolbarButton" title="Tools" tabindex="36" data-l10n-id="tools"> <span data-l10n-id="tools_label">Tools</span> </button> </div> - <div class="outerCenter"> - <div class="innerCenter" id="toolbarViewerMiddle"> - <div class="splitToolbarButton"> - <button id="zoomOut" class="toolbarButton zoomOut" title="Zoom Out" tabindex="21" data-l10n-id="zoom_out"> - <span data-l10n-id="zoom_out_label">Zoom Out</span> - </button> - <div class="splitToolbarButtonSeparator"></div> - <button id="zoomIn" class="toolbarButton zoomIn" title="Zoom In" tabindex="22" data-l10n-id="zoom_in"> - <span data-l10n-id="zoom_in_label">Zoom In</span> - </button> - </div> - <span id="scaleSelectContainer" class="dropdownToolbarButton"> - <select id="scaleSelect" title="Zoom" tabindex="23" data-l10n-id="zoom"> - <option id="pageAutoOption" title="" value="auto" selected="selected" data-l10n-id="page_scale_auto">Automatic Zoom</option> - <option id="pageActualOption" title="" value="page-actual" data-l10n-id="page_scale_actual">Actual Size</option> - <option id="pageFitOption" title="" value="page-fit" data-l10n-id="page_scale_fit">Fit Page</option> - <option id="pageWidthOption" title="" value="page-width" data-l10n-id="page_scale_width">Full Width</option> - <option id="customScaleOption" title="" value="custom" hidden="true"></option> - <option title="" value="0.5" data-l10n-id="page_scale_percent" data-l10n-args='{ "scale": 50 }'>50%</option> - <option title="" value="0.75" data-l10n-id="page_scale_percent" data-l10n-args='{ "scale": 75 }'>75%</option> - <option title="" value="1" data-l10n-id="page_scale_percent" data-l10n-args='{ "scale": 100 }'>100%</option> - <option title="" value="1.25" data-l10n-id="page_scale_percent" data-l10n-args='{ "scale": 125 }'>125%</option> - <option title="" value="1.5" data-l10n-id="page_scale_percent" data-l10n-args='{ "scale": 150 }'>150%</option> - <option title="" value="2" data-l10n-id="page_scale_percent" data-l10n-args='{ "scale": 200 }'>200%</option> - <option title="" value="3" data-l10n-id="page_scale_percent" data-l10n-args='{ "scale": 300 }'>300%</option> - <option title="" value="4" data-l10n-id="page_scale_percent" data-l10n-args='{ "scale": 400 }'>400%</option> - </select> - </span> + <div id="toolbarViewerMiddle"> + <div class="splitToolbarButton"> + <button id="zoomOut" class="toolbarButton zoomOut" title="Zoom Out" tabindex="21" data-l10n-id="zoom_out"> + <span data-l10n-id="zoom_out_label">Zoom Out</span> + </button> + <div class="splitToolbarButtonSeparator"></div> + <button id="zoomIn" class="toolbarButton zoomIn" title="Zoom In" tabindex="22" data-l10n-id="zoom_in"> + <span data-l10n-id="zoom_in_label">Zoom In</span> + </button> </div> + <span id="scaleSelectContainer" class="dropdownToolbarButton"> + <select id="scaleSelect" title="Zoom" tabindex="23" data-l10n-id="zoom"> + <option id="pageAutoOption" title="" value="auto" selected="selected" data-l10n-id="page_scale_auto">Automatic Zoom</option> + <option id="pageActualOption" title="" value="page-actual" data-l10n-id="page_scale_actual">Actual Size</option> + <option id="pageFitOption" title="" value="page-fit" data-l10n-id="page_scale_fit">Fit Page</option> + <option id="pageWidthOption" title="" value="page-width" data-l10n-id="page_scale_width">Full Width</option> + <option id="customScaleOption" title="" value="custom" disabled="disabled" hidden="true"></option> + <option title="" value="0.5" data-l10n-id="page_scale_percent" data-l10n-args='{ "scale": 50 }'>50%</option> + <option title="" value="0.75" data-l10n-id="page_scale_percent" data-l10n-args='{ "scale": 75 }'>75%</option> + <option title="" value="1" data-l10n-id="page_scale_percent" data-l10n-args='{ "scale": 100 }'>100%</option> + <option title="" value="1.25" data-l10n-id="page_scale_percent" data-l10n-args='{ "scale": 125 }'>125%</option> + <option title="" value="1.5" data-l10n-id="page_scale_percent" data-l10n-args='{ "scale": 150 }'>150%</option> + <option title="" value="2" data-l10n-id="page_scale_percent" data-l10n-args='{ "scale": 200 }'>200%</option> + <option title="" value="3" data-l10n-id="page_scale_percent" data-l10n-args='{ "scale": 300 }'>300%</option> + <option title="" value="4" data-l10n-id="page_scale_percent" data-l10n-args='{ "scale": 400 }'>400%</option> + </select> + </span> </div> </div> <div id="loadingBar"> <div class="progress"> <div class="glimmer"> </div> </div> </div>
--- a/devtools/client/inspector/inspector.js +++ b/devtools/client/inspector/inspector.js @@ -529,48 +529,42 @@ Inspector.prototype = { setupSidebar: function () { let tabbox = this.panelDoc.querySelector("#inspector-sidebar"); this.sidebar = new ToolSidebar(tabbox, this, "inspector", { showAllTabsMenu: true }); let defaultTab = Services.prefs.getCharPref("devtools.inspector.activeSidebar"); + this._setDefaultSidebar = (event, toolId) => { + Services.prefs.setCharPref("devtools.inspector.activeSidebar", toolId); + }; + + this.sidebar.on("select", this._setDefaultSidebar); + if (!Services.prefs.getBoolPref("devtools.fontinspector.enabled") && defaultTab == "fontinspector") { defaultTab = "ruleview"; } // Append all side panels this.sidebar.addExistingTab( "ruleview", INSPECTOR_L10N.getStr("inspector.sidebar.ruleViewTitle"), defaultTab == "ruleview"); this.sidebar.addExistingTab( "computedview", INSPECTOR_L10N.getStr("inspector.sidebar.computedViewTitle"), defaultTab == "computedview"); - this._setDefaultSidebar = (event, toolId) => { - Services.prefs.setCharPref("devtools.inspector.activeSidebar", toolId); - }; - - this.sidebar.on("select", this._setDefaultSidebar); - this.ruleview = new RuleViewTool(this, this.panelWin); this.computedview = new ComputedViewTool(this, this.panelWin); if (Services.prefs.getBoolPref("devtools.layoutview.enabled")) { - this.sidebar.addExistingTab( - "layoutview", - INSPECTOR_L10N.getStr("inspector.sidebar.layoutViewTitle"), - defaultTab == "layoutview" - ); - const {LayoutView} = require("devtools/client/inspector/layout/layout"); this.layoutview = new LayoutView(this, this.panelWin); } if (this.target.form.animationsActor) { this.sidebar.addFrameTab( "animationinspector", INSPECTOR_L10N.getStr("inspector.sidebar.animationInspectorTitle"),
--- a/devtools/client/inspector/inspector.xhtml +++ b/devtools/client/inspector/inspector.xhtml @@ -186,21 +186,16 @@ <div id="propertyContainer" class="theme-separator" tabindex="0"> </div> <div id="computedview-no-results" hidden="" data-localization="content=inspector.noProperties"></div> </div> </div> </div> - <div id="sidebar-panel-layoutview" class="devtools-monospace theme-sidebar inspector-tabpanel" - data-localization-bundle="devtools/client/locales/inspector.properties"> - <div id="layoutview-container"></div> - </div> - <div id="sidebar-panel-fontinspector" class="devtools-monospace theme-sidebar inspector-tabpanel" data-localization-bundle="devtools/client/locales/font-inspector.properties"> <div class="devtools-toolbar"> <div class="devtools-searchbox"> <input id="font-preview-text-input" class="devtools-textinput" type="search" data-localization="placeholder=fontinspector.previewText"/> </div> <label id="font-showall" class="theme-link"
--- a/devtools/client/inspector/layout/components/App.js +++ b/devtools/client/inspector/layout/components/App.js @@ -13,17 +13,17 @@ const Grid = createFactory(require("./Gr const App = createClass({ displayName: "App", render() { return dom.div( { - id: "layoutview-container-focusable", + id: "layoutview-container", }, Accordion({ items: [ { header: getStr("layout.header"), component: Grid, opened: true } ] })
--- a/devtools/client/inspector/layout/layout.js +++ b/devtools/client/inspector/layout/layout.js @@ -1,36 +1,52 @@ /* 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/. */ "use strict"; -const { createFactory, createElement } = - require("devtools/client/shared/vendor/react"); -const ReactDOM = require("devtools/client/shared/vendor/react-dom"); +const Services = require("Services"); +const { createFactory, createElement } = require("devtools/client/shared/vendor/react"); const { Provider } = require("devtools/client/shared/vendor/react-redux"); const App = createFactory(require("./components/app")); const Store = require("./store"); +const { LocalizationHelper } = require("devtools/shared/l10n"); +const INSPECTOR_L10N = + new LocalizationHelper("devtools/client/locales/inspector.properties"); + function LayoutView(inspector, window) { this.inspector = inspector; this.document = window.document; this.store = null; this.init(); } LayoutView.prototype = { init() { let store = this.store = Store(); - let provider = createElement(Provider, { store }, App()); - ReactDOM.render(provider, this.document.querySelector("#layoutview-container")); + let provider = createElement(Provider, { + store, + id: "layoutview", + title: INSPECTOR_L10N.getStr("inspector.sidebar.layoutViewTitle"), + key: "layoutview", + }, App()); + + let defaultTab = Services.prefs.getCharPref("devtools.inspector.activeSidebar"); + + this.inspector.addSidebarTab( + "layoutview", + INSPECTOR_L10N.getStr("inspector.sidebar.layoutViewTitle"), + provider, + defaultTab == "layoutview" + ); }, destroy() { this.inspector = null; this.document = null; this.store = null; }, };
--- a/devtools/client/preferences/devtools.js +++ b/devtools/client/preferences/devtools.js @@ -95,22 +95,17 @@ pref("devtools.debugger.remote-timeout", pref("devtools.debugger.pause-on-exceptions", false); pref("devtools.debugger.ignore-caught-exceptions", true); pref("devtools.debugger.source-maps-enabled", true); pref("devtools.debugger.client-source-maps-enabled", true); pref("devtools.debugger.pretty-print-enabled", true); pref("devtools.debugger.auto-pretty-print", false); pref("devtools.debugger.auto-black-box", true); pref("devtools.debugger.workers", false); - -#if defined(NIGHTLY_BUILD) pref("devtools.debugger.new-debugger-frontend", true); -#else -pref("devtools.debugger.new-debugger-frontend", false); -#endif // The default Debugger UI settings pref("devtools.debugger.ui.panes-workers-and-sources-width", 200); pref("devtools.debugger.ui.panes-instruments-width", 300); pref("devtools.debugger.ui.panes-visible-on-startup", false); pref("devtools.debugger.ui.variables-sorting-enabled", true); pref("devtools.debugger.ui.variables-only-enum-visible", false); pref("devtools.debugger.ui.variables-searchbox-visible", false);
--- a/devtools/client/themes/layout.css +++ b/devtools/client/themes/layout.css @@ -1,27 +1,14 @@ /* 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/. */ -#sidebar-panel-layoutview { - margin: 0; - display: flex; - flex-direction: column; - width: 100%; - height: 100%; -} - #layoutview-container { height: 100%; - overflow: auto; -} - -#layoutview-container-focusable { - height: 100%; - outline: none; + width: 100%; } .layoutview-no-grids { font-style: italic; text-align: center; padding: 0.5em; }
--- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -1723,17 +1723,19 @@ nsDocShell::MaybeInitTiming() mBlankTiming = false; } } if (!mTiming) { mTiming = new nsDOMNavigationTiming(); } - mTiming->NotifyNavigationStart(); + mTiming->NotifyNavigationStart( + mIsActive ? nsDOMNavigationTiming::DocShellState::eActive + : nsDOMNavigationTiming::DocShellState::eInactive); } // // Bug 13871: Prevent frameset spoofing // // This routine answers: 'Is origin's document from same domain as // target's document?' // @@ -6214,16 +6216,30 @@ nsDocShell::SetIsActive(bool aIsActive) ScreenOrientation::UpdateActiveOrientationLock(orientation); } } doc->PostVisibilityUpdateEvent(); } } + // Tell the nsDOMNavigationTiming about it + RefPtr<nsDOMNavigationTiming> timing = mTiming; + if (!timing && mContentViewer) { + nsIDocument* doc = mContentViewer->GetDocument(); + if (doc) { + timing = doc->GetNavigationTiming(); + } + } + if (timing) { + timing->NotifyDocShellStateChanged( + aIsActive ? nsDOMNavigationTiming::DocShellState::eActive + : nsDOMNavigationTiming::DocShellState::eInactive); + } + // Recursively tell all of our children, but don't tell <iframe mozbrowser> // children; they handle their state separately. nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList); while (iter.HasMore()) { nsCOMPtr<nsIDocShell> docshell = do_QueryObject(iter.GetNext()); if (!docshell) { continue; } @@ -9855,28 +9871,20 @@ nsDocShell::InternalLoad(nsIURI* aURI, nsCOMPtr<nsIDocShell> elementDocShell = requestingDoc->GetDocShell(); // requestingElement docshell type = current docshell type. MOZ_ASSERT(mItemType == elementDocShell->ItemType(), "subframes should have the same docshell type as their parent"); #endif } - // XXXbz would be nice to know the loading principal here... but we don't - nsCOMPtr<nsIPrincipal> requestingPrincipal = aTriggeringPrincipal; - if (!requestingPrincipal && aReferrer) { - rv = - CreatePrincipalFromReferrer(aReferrer, getter_AddRefs(requestingPrincipal)); - NS_ENSURE_SUCCESS(rv, rv); - } - int16_t shouldLoad = nsIContentPolicy::ACCEPT; rv = NS_CheckContentLoadPolicy(contentType, aURI, - requestingPrincipal, + aTriggeringPrincipal, requestingContext, EmptyCString(), // mime guess nullptr, // extra &shouldLoad); if (NS_FAILED(rv) || NS_CP_REJECTED(shouldLoad)) { if (NS_SUCCEEDED(rv) && shouldLoad == nsIContentPolicy::REJECT_TYPE) { return NS_ERROR_CONTENT_BLOCKED_SHOW_ALT;
--- a/dom/base/DOMIntersectionObserver.cpp +++ b/dom/base/DOMIntersectionObserver.cpp @@ -154,25 +154,33 @@ DOMIntersectionObserver::Observe(Element aTarget.RegisterIntersectionObserver(this); mObservationTargets.PutEntry(&aTarget); Connect(); } void DOMIntersectionObserver::Unobserve(Element& aTarget) { - if (!mObservationTargets.Contains(&aTarget)) { - return; + if (UnlinkTarget(aTarget)) { + aTarget.UnregisterIntersectionObserver(this); } - if (mObservationTargets.Count() == 1) { - Disconnect(); - return; - } - aTarget.UnregisterIntersectionObserver(this); - mObservationTargets.RemoveEntry(&aTarget); +} + +bool +DOMIntersectionObserver::UnlinkTarget(Element& aTarget) +{ + if (!mObservationTargets.Contains(&aTarget)) { + return false; + } + if (mObservationTargets.Count() == 1) { + Disconnect(); + return false; + } + mObservationTargets.RemoveEntry(&aTarget); + return true; } void DOMIntersectionObserver::Connect() { if (mConnected) { return; } @@ -187,18 +195,20 @@ DOMIntersectionObserver::Disconnect() if (!mConnected) { return; } for (auto iter = mObservationTargets.Iter(); !iter.Done(); iter.Next()) { Element* target = iter.Get()->GetKey(); target->UnregisterIntersectionObserver(this); } mObservationTargets.Clear(); - nsIDocument* document = mOwner->GetExtantDoc(); - document->RemoveIntersectionObserver(this); + if (mOwner) { + nsIDocument* document = mOwner->GetExtantDoc(); + document->RemoveIntersectionObserver(this); + } mConnected = false; } void DOMIntersectionObserver::TakeRecords(nsTArray<RefPtr<DOMIntersectionObserverEntry>>& aRetVal) { aRetVal.SwapElements(mQueuedEntries); mQueuedEntries.Clear();
--- a/dom/base/DOMIntersectionObserver.h +++ b/dom/base/DOMIntersectionObserver.h @@ -137,17 +137,19 @@ public: return mRoot; } void GetRootMargin(mozilla::dom::DOMString& aRetVal); void GetThresholds(nsTArray<double>& aRetVal); void Observe(Element& aTarget); void Unobserve(Element& aTarget); + bool UnlinkTarget(Element& aTarget); void Disconnect(); + void TakeRecords(nsTArray<RefPtr<DOMIntersectionObserverEntry>>& aRetVal); mozilla::dom::IntersectionCallback* IntersectionCallback() { return mCallback; } bool SetRootMargin(const nsAString& aString); void Update(nsIDocument* aDocument, DOMHighResTimeStamp time); void Notify();
--- a/dom/base/File.cpp +++ b/dom/base/File.cpp @@ -559,46 +559,20 @@ File::Constructor(const GlobalObject& aG impl->SetLastModified(aBag.mLastModified.Value()); } RefPtr<File> file = new File(aGlobal.GetAsSupports(), impl); return file.forget(); } /* static */ already_AddRefed<File> -File::Constructor(const GlobalObject& aGlobal, - Blob& aData, - const ChromeFilePropertyBag& aBag, - ErrorResult& aRv) -{ - if (!nsContentUtils::ThreadsafeIsCallerChrome()) { - aRv.ThrowTypeError<MSG_NOT_SEQUENCE>(NS_LITERAL_STRING("Argument 1 of File.constructor")); - return nullptr; - } - - RefPtr<MultipartBlobImpl> impl = new MultipartBlobImpl(EmptyString()); - impl->InitializeChromeFile(aData, aBag, aRv); - if (aRv.Failed()) { - return nullptr; - } - MOZ_ASSERT(impl->IsFile()); - - if (aBag.mLastModified.WasPassed()) { - impl->SetLastModified(aBag.mLastModified.Value()); - } - - RefPtr<File> domFile = new File(aGlobal.GetAsSupports(), impl); - return domFile.forget(); -} - -/* static */ already_AddRefed<File> -File::Constructor(const GlobalObject& aGlobal, - nsIFile* aData, - const ChromeFilePropertyBag& aBag, - ErrorResult& aRv) +File::CreateFromNsIFile(const GlobalObject& aGlobal, + nsIFile* aData, + const ChromeFilePropertyBag& aBag, + ErrorResult& aRv) { MOZ_ASSERT(NS_IsMainThread()); if (!nsContentUtils::IsCallerChrome()) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal.GetAsSupports()); @@ -614,20 +588,20 @@ File::Constructor(const GlobalObject& aG impl->SetLastModified(aBag.mLastModified.Value()); } RefPtr<File> domFile = new File(aGlobal.GetAsSupports(), impl); return domFile.forget(); } /* static */ already_AddRefed<File> -File::Constructor(const GlobalObject& aGlobal, - const nsAString& aData, - const ChromeFilePropertyBag& aBag, - ErrorResult& aRv) +File::CreateFromFileName(const GlobalObject& aGlobal, + const nsAString& aData, + const ChromeFilePropertyBag& aBag, + ErrorResult& aRv) { if (!nsContentUtils::ThreadsafeIsCallerChrome()) { aRv.ThrowTypeError<MSG_MISSING_ARGUMENTS>(NS_LITERAL_STRING("File")); return nullptr; } nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal.GetAsSupports());
--- a/dom/base/File.h +++ b/dom/base/File.h @@ -206,36 +206,29 @@ public: // File constructor static already_AddRefed<File> Constructor(const GlobalObject& aGlobal, const Sequence<BlobPart>& aData, const nsAString& aName, const FilePropertyBag& aBag, ErrorResult& aRv); - // File constructor - ChromeOnly - static already_AddRefed<File> - Constructor(const GlobalObject& aGlobal, - Blob& aData, - const ChromeFilePropertyBag& aBag, - ErrorResult& aRv); - - // File constructor - ChromeOnly + // ChromeOnly static already_AddRefed<File> - Constructor(const GlobalObject& aGlobal, - const nsAString& aData, - const ChromeFilePropertyBag& aBag, - ErrorResult& aRv); + CreateFromFileName(const GlobalObject& aGlobal, + const nsAString& aData, + const ChromeFilePropertyBag& aBag, + ErrorResult& aRv); - // File constructor - ChromeOnly + // ChromeOnly static already_AddRefed<File> - Constructor(const GlobalObject& aGlobal, - nsIFile* aData, - const ChromeFilePropertyBag& aBag, - ErrorResult& aRv); + CreateFromNsIFile(const GlobalObject& aGlobal, + nsIFile* aData, + const ChromeFilePropertyBag& aBag, + ErrorResult& aRv); void GetName(nsAString& aName) const; int64_t GetLastModified(ErrorResult& aRv); Date GetLastModifiedDate(ErrorResult& aRv); // GetPath and SetPath are currently used only for the webkitRelativePath
--- a/dom/base/nsDOMDataChannel.cpp +++ b/dom/base/nsDOMDataChannel.cpp @@ -352,27 +352,27 @@ nsDOMDataChannel::Send(nsIInputStream* a if (state == mozilla::DataChannel::CLOSING || state == mozilla::DataChannel::CLOSED) { return; } MOZ_ASSERT(state == mozilla::DataChannel::OPEN, "Unknown state in nsDOMDataChannel::Send"); - int32_t sent; + bool sent; if (aMsgStream) { sent = mDataChannel->SendBinaryStream(aMsgStream, aMsgLength); } else { if (aIsBinary) { sent = mDataChannel->SendBinaryMsg(aMsgString); } else { sent = mDataChannel->SendMsg(aMsgString); } } - if (sent < 0) { + if (!sent) { aRv.Throw(NS_ERROR_FAILURE); } } nsresult nsDOMDataChannel::DoOnMessageAvailable(const nsACString& aData, bool aBinary) {
--- a/dom/base/nsDOMNavigationTiming.cpp +++ b/dom/base/nsDOMNavigationTiming.cpp @@ -1,20 +1,23 @@ /* -*- 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 "nsDOMNavigationTiming.h" + +#include "GeckoProfiler.h" #include "nsCOMPtr.h" #include "nsContentUtils.h" #include "nsIScriptSecurityManager.h" #include "prtime.h" #include "nsIURI.h" +#include "nsPrintfCString.h" #include "mozilla/dom/PerformanceNavigation.h" #include "mozilla/TimeStamp.h" nsDOMNavigationTiming::nsDOMNavigationTiming() { Clear(); } @@ -40,16 +43,17 @@ nsDOMNavigationTiming::Clear() mLoadEventStartSet = false; mLoadEventEndSet = false; mDOMLoadingSet = false; mDOMInteractiveSet = false; mDOMContentLoadedEventStartSet = false; mDOMContentLoadedEventEndSet = false; mDOMCompleteSet = false; + mDocShellHasBeenActiveSinceNavigationStart = false; } DOMTimeMilliSec nsDOMNavigationTiming::TimeStampToDOM(mozilla::TimeStamp aStamp) const { if (aStamp.IsNull()) { return 0; } @@ -58,20 +62,21 @@ nsDOMNavigationTiming::TimeStampToDOM(mo } DOMTimeMilliSec nsDOMNavigationTiming::DurationFromStart() { return TimeStampToDOM(mozilla::TimeStamp::Now()); } void -nsDOMNavigationTiming::NotifyNavigationStart() +nsDOMNavigationTiming::NotifyNavigationStart(DocShellState aDocShellState) { mNavigationStartHighRes = (double)PR_Now() / PR_USEC_PER_MSEC; mNavigationStartTimeStamp = mozilla::TimeStamp::Now(); + mDocShellHasBeenActiveSinceNavigationStart = (aDocShellState == DocShellState::eActive); } void nsDOMNavigationTiming::NotifyFetchStart(nsIURI* aURI, Type aNavigationType) { mNavigationType = aNavigationType; // At the unload event time we don't really know the loading uri. // Need it for later check for unload timing access. @@ -176,16 +181,54 @@ nsDOMNavigationTiming::NotifyDOMContentL { if (!mDOMContentLoadedEventEndSet) { mLoadedURI = aURI; mDOMContentLoadedEventEnd = DurationFromStart(); mDOMContentLoadedEventEndSet = true; } } +void +nsDOMNavigationTiming::NotifyNonBlankPaintForRootContentDocument() +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(!mNavigationStartTimeStamp.IsNull()); + + if (!mNonBlankPaintTimeStamp.IsNull()) { + return; + } + + mNonBlankPaintTimeStamp = TimeStamp::Now(); + TimeDuration elapsed = mNonBlankPaintTimeStamp - mNavigationStartTimeStamp; + + if (profiler_is_active()) { + nsAutoCString spec; + if (mLoadedURI) { + mLoadedURI->GetSpec(spec); + } + nsPrintfCString marker("Non-blank paint after %dms for URL %s, %s", + int(elapsed.ToMilliseconds()), spec.get(), + mDocShellHasBeenActiveSinceNavigationStart ? "foreground tab" : "this tab was inactive some of the time between navigation start and first non-blank paint"); + PROFILER_MARKER(marker.get()); + } + + if (mDocShellHasBeenActiveSinceNavigationStart) { + Telemetry::AccumulateTimeDelta(Telemetry::TIME_TO_NON_BLANK_PAINT_MS, + mNavigationStartTimeStamp, + mNonBlankPaintTimeStamp); + } +} + +void +nsDOMNavigationTiming::NotifyDocShellStateChanged(DocShellState aDocShellState) +{ + mDocShellHasBeenActiveSinceNavigationStart &= + (aDocShellState == DocShellState::eActive); +} + DOMTimeMilliSec nsDOMNavigationTiming::GetUnloadEventStart() { nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager(); nsresult rv = ssm->CheckSameOriginURI(mLoadedURI, mUnloadedURI, false); if (NS_SUCCEEDED(rv)) { return mUnloadStart; }
--- a/dom/base/nsDOMNavigationTiming.h +++ b/dom/base/nsDOMNavigationTiming.h @@ -76,32 +76,41 @@ public: { return mLoadEventStart; } DOMTimeMilliSec GetLoadEventEnd() const { return mLoadEventEnd; } - void NotifyNavigationStart(); + enum class DocShellState : uint8_t { + eActive, + eInactive + }; + + void NotifyNavigationStart(DocShellState aDocShellState); void NotifyFetchStart(nsIURI* aURI, Type aNavigationType); void NotifyBeforeUnload(); void NotifyUnloadAccepted(nsIURI* aOldURI); void NotifyUnloadEventStart(); void NotifyUnloadEventEnd(); void NotifyLoadEventStart(); void NotifyLoadEventEnd(); // Document changes state to 'loading' before connecting to timing void SetDOMLoadingTimeStamp(nsIURI* aURI, mozilla::TimeStamp aValue); void NotifyDOMLoading(nsIURI* aURI); void NotifyDOMInteractive(nsIURI* aURI); void NotifyDOMComplete(nsIURI* aURI); void NotifyDOMContentLoadedStart(nsIURI* aURI); void NotifyDOMContentLoadedEnd(nsIURI* aURI); + + void NotifyNonBlankPaintForRootContentDocument(); + void NotifyDocShellStateChanged(DocShellState aDocShellState); + DOMTimeMilliSec TimeStampToDOM(mozilla::TimeStamp aStamp) const; inline DOMHighResTimeStamp TimeStampToDOMHighRes(mozilla::TimeStamp aStamp) { mozilla::TimeDuration duration = aStamp - mNavigationStartTimeStamp; return duration.ToMilliseconds(); } @@ -112,16 +121,17 @@ private: void Clear(); nsCOMPtr<nsIURI> mUnloadedURI; nsCOMPtr<nsIURI> mLoadedURI; Type mNavigationType; DOMHighResTimeStamp mNavigationStartHighRes; mozilla::TimeStamp mNavigationStartTimeStamp; + mozilla::TimeStamp mNonBlankPaintTimeStamp; DOMTimeMilliSec DurationFromStart(); DOMTimeMilliSec mBeforeUnloadStart; DOMTimeMilliSec mUnloadStart; DOMTimeMilliSec mUnloadEnd; DOMTimeMilliSec mLoadEventStart; DOMTimeMilliSec mLoadEventEnd; @@ -136,11 +146,12 @@ private: // once. bool mLoadEventStartSet : 1; bool mLoadEventEndSet : 1; bool mDOMLoadingSet : 1; bool mDOMInteractiveSet : 1; bool mDOMContentLoadedEventStartSet : 1; bool mDOMContentLoadedEventEndSet : 1; bool mDOMCompleteSet : 1; + bool mDocShellHasBeenActiveSinceNavigationStart : 1; }; #endif /* nsDOMNavigationTiming_h___ */
--- a/dom/base/nsNodeUtils.cpp +++ b/dom/base/nsNodeUtils.cpp @@ -292,16 +292,25 @@ nsNodeUtils::LastRelease(nsINode* aNode) nsINode::nsSlots* slots = aNode->GetExistingSlots(); if (slots) { if (!slots->mMutationObservers.IsEmpty()) { NS_OBSERVER_ARRAY_NOTIFY_OBSERVERS(slots->mMutationObservers, nsIMutationObserver, NodeWillBeDestroyed, (aNode)); } + if (aNode->IsElement()) { + Element* elem = aNode->AsElement(); + FragmentOrElement::nsDOMSlots* domSlots = + static_cast<FragmentOrElement::nsDOMSlots*>(slots); + for (auto& reg : domSlots->mRegisteredIntersectionObservers) { + reg.observer->UnlinkTarget(*elem); + } + } + delete slots; aNode->mSlots = nullptr; } // Kill properties first since that may run external code, so we want to // be in as complete state as possible at that time. if (aNode->IsNodeOfType(nsINode::eDOCUMENT)) { // Delete all properties before tearing down the document. Some of the
--- a/dom/base/test/bug403852_fileOpener.js +++ b/dom/base/test/bug403852_fileOpener.js @@ -4,14 +4,14 @@ Cu.importGlobalProperties(["File"]); var testFile = Cc["@mozilla.org/file/directory_service;1"] .getService(Ci.nsIDirectoryService) .QueryInterface(Ci.nsIProperties) .get("ProfD", Ci.nsIFile); testFile.append("prefs.js"); addMessageListener("file.open", function () { sendAsyncMessage("file.opened", { - file: new File(testFile), + file: File.createFromNsIFile(testFile), mtime: testFile.lastModifiedTime, - fileWithDate: new File(testFile, { lastModified: 123 }), + fileWithDate: File.createFromNsIFile(testFile, { lastModified: 123 }), fileDate: 123, }); });
--- a/dom/base/test/bug578096LoadChromeScript.js +++ b/dom/base/test/bug578096LoadChromeScript.js @@ -2,15 +2,15 @@ var file; Components.utils.importGlobalProperties(["File"]); addMessageListener("file.create", function (message) { file = Components.classes["@mozilla.org/file/directory_service;1"] .getService(Components.interfaces.nsIProperties) .get("TmpD", Components.interfaces.nsIFile); file.append("foo.txt"); file.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0o600); - sendAsyncMessage("file.created", new File(file)); + sendAsyncMessage("file.created", File.createFromNsIFile(file)); }); addMessageListener("file.remove", function (message) { file.remove(false); sendAsyncMessage("file.removed", {}); });
--- a/dom/base/test/chrome/test_bug914381.html +++ b/dom/base/test/chrome/test_bug914381.html @@ -30,19 +30,19 @@ function createFileWithData(fileData) { outStream.write(fileData, fileData.length); outStream.close(); return testFile; } /** Test for Bug 914381. File's created in JS using an nsIFile should allow mozGetFullPathInternal calls to succeed **/ var file = createFileWithData("Test bug 914381"); -var f = new File(file); +var f = File.createFromNsIFile(file); is(f.mozFullPathInternal, undefined, "mozFullPathInternal is undefined from js"); is(f.mozFullPath, file.path, "mozFullPath returns path if created with nsIFile"); -f = new File(file.path); +f = File.createFromFileName(file.path); is(f.mozFullPathInternal, undefined, "mozFullPathInternal is undefined from js"); is(f.mozFullPath, "", "mozFullPath returns blank if created with a string"); </script> </pre> </body> </html>
--- a/dom/base/test/chrome/test_fileconstructor.xul +++ b/dom/base/test/chrome/test_fileconstructor.xul @@ -37,43 +37,36 @@ var file = Components.classes["@mozilla. // man I wish this were simpler ... file.append("chrome"); file.append("dom"); file.append("base"); file.append("test"); file.append("chrome"); file.append("fileconstructor_file.png"); -doTest(new File(file.path)); -doTest(new File(file)); +doTest(File.createFromFileName(file.path)); +doTest(File.createFromNsIFile(file)); function doTest(domfile) { ok(domfile instanceof File, "File() should return a File"); is(domfile.type, "image/png", "File should be a PNG"); is(domfile.size, 95, "File has size 95 (and more importantly we can read it)"); } try { - var boomfile = new File(); - ok(false, "This should never be reached!"); -} catch (e) { - ok(true, "Botched file constructor attempts throw and do not crash."); -} - -try { - var nonexistentfile = new File("i/sure/hope/this/does/not/exist/anywhere.txt"); + var nonexistentfile = File.createFromFileName("i/sure/hope/this/does/not/exist/anywhere.txt"); ok(false, "This should never be reached!"); } catch (e) { ok(true, "Attempt to construct a non-existent file should fail."); } try { var dir = Components.classes["@mozilla.org/file/directory_service;1"] .getService(Components.interfaces.nsIProperties) .get("CurWorkD", Components.interfaces.nsIFile); - var dirfile = new File(dir); + var dirfile = File.createFromNsIFile(dir); ok(false, "This should never be reached!"); } catch (e) { ok(true, "Attempt to construct a file from a directory should fail."); } ]]> </script> </window>
--- a/dom/base/test/chrome/test_fileconstructor_tempfile.xul +++ b/dom/base/test/chrome/test_fileconstructor_tempfile.xul @@ -67,17 +67,17 @@ try { .createInstance(Ci.nsIFileOutputStream); outStream.init(tmp, 0x02 | 0x08 | 0x20, // write, create, truncate 0666, 0); outStream.write(fileData, fileData.length); outStream.close(); // Create a scoped DOMFile so the gc will happily get rid of it. { - let dirfile = new File(tmp, { temporary: true }); + let dirfile = File.createFromNsIFile(tmp, { temporary: true }); ok(true, "Temporary File() created"); let reader = new FileReader(); reader.readAsArrayBuffer(dirfile); reader.onload = function(event) { let buffer = event.target.result; ok(buffer.byteLength > 0, "Blob size should be > 0 : " + buffer.byteLength); cleanup(tmp);
--- a/dom/base/test/create_file_objects.js +++ b/dom/base/test/create_file_objects.js @@ -1,10 +1,10 @@ Components.utils.importGlobalProperties(['File']); addMessageListener("create-file-objects", function(message) { let files = [] for (fileName of message.fileNames) { - files.push(new File(fileName)); + files.push(File.createFromFileName(fileName)); } sendAsyncMessage("created-file-objects", files); });
--- a/dom/base/test/file_bug1198095.js +++ b/dom/base/test/file_bug1198095.js @@ -8,17 +8,17 @@ function createFileWithData(message) { var outStream = Cc["@mozilla.org/network/file-output-stream;1"].createInstance(Ci.nsIFileOutputStream); outStream.init(testFile, 0x02 | 0x08 | 0x20, // write, create, truncate 0o666, 0); outStream.write(message, message.length); outStream.close(); - var domFile = new File(testFile); + var domFile = File.createFromNsIFile(testFile); return domFile; } addMessageListener("file.open", function (message) { sendAsyncMessage("file.opened", createFileWithData(message)); }); addMessageListener("file.modify", function (message) {
--- a/dom/base/test/fileapi_chromeScript.js +++ b/dom/base/test/fileapi_chromeScript.js @@ -12,17 +12,17 @@ function createFileWithData(fileData) { var outStream = Cc["@mozilla.org/network/file-output-stream;1"].createInstance(Ci.nsIFileOutputStream); outStream.init(testFile, 0x02 | 0x08 | 0x20, // write, create, truncate 0o666, 0); if (willDelete) { fileData = "some irrelevant test data\n"; } outStream.write(fileData, fileData.length); outStream.close(); - var domFile = new File(testFile); + var domFile = File.createFromNsIFile(testFile); if (willDelete) { testFile.remove(/* recursive: */ false); } return domFile; } addMessageListener("files.open", function (message) { sendAsyncMessage("files.opened", message.map(createFileWithData));
--- a/dom/base/test/script_bug1238440.js +++ b/dom/base/test/script_bug1238440.js @@ -6,17 +6,17 @@ var tmpFile; function writeFile(text, answer) { var stream = Cc["@mozilla.org/network/file-output-stream;1"] .createInstance(Ci.nsIFileOutputStream); stream.init(tmpFile, 0x02 | 0x08 | 0x10, 0o600, 0); stream.write(text, text.length); stream.close(); sendAsyncMessage(answer, { - file: new File(tmpFile) + file: File.createFromNsIFile(tmpFile) }); } addMessageListener("file.open", function (e) { tmpFile = Cc["@mozilla.org/file/directory_service;1"] .getService(Ci.nsIDirectoryService) .QueryInterface(Ci.nsIProperties) .get('TmpD', Ci.nsIFile)
--- a/dom/base/test/script_postmessages_fileList.js +++ b/dom/base/test/script_postmessages_fileList.js @@ -4,17 +4,17 @@ Cu.importGlobalProperties(["File"]); addMessageListener("file.open", function () { var testFile = Cc["@mozilla.org/file/directory_service;1"] .getService(Ci.nsIDirectoryService) .QueryInterface(Ci.nsIProperties) .get("ProfD", Ci.nsIFile); testFile.append("prefs.js"); sendAsyncMessage("file.opened", { - file: new File(testFile) + file: File.createFromNsIFile(testFile) }); }); addMessageListener("dir.open", function () { var testFile = Cc["@mozilla.org/file/directory_service;1"] .getService(Ci.nsIDirectoryService) .QueryInterface(Ci.nsIProperties) .get("ProfD", Ci.nsIFile);
--- a/dom/bindings/BindingDeclarations.h +++ b/dom/bindings/BindingDeclarations.h @@ -518,12 +518,18 @@ public: // Allow converting to const sequences as needed operator const Sequence<T>&() const { return *reinterpret_cast<const Sequence<T>*>(this); } }; } // namespace binding_detail +// Enum to represent a system or non-system caller type. +enum class CallerType { + System, + NonSystem +}; + } // namespace dom } // namespace mozilla #endif // mozilla_dom_BindingDeclarations_h__
--- a/dom/bindings/Bindings.conf +++ b/dom/bindings/Bindings.conf @@ -1592,16 +1592,21 @@ DOMInterfaces = { # Keep this in sync with TestInterface 'headerFile': 'TestExampleInterface-example.h', 'register': False, 'binaryNames': { 'methodRenamedFrom': 'methodRenamedTo', 'attributeGetterRenamedFrom': 'attributeGetterRenamedTo', 'attributeRenamedFrom': 'attributeRenamedTo' } }, +'TestExampleWorkerInterface' : { + 'headerFile': 'TestExampleWorkerInterface-example.h', + 'register': False, + }, + 'TestExampleProxyInterface' : { 'headerFile': 'TestExampleProxyInterface-example.h', 'register': False }, 'TestDeprecatedInterface' : { # Keep this in sync with TestExampleInterface 'headerFile': 'TestBindingHeader.h', @@ -1629,16 +1634,21 @@ DOMInterfaces = { 'register': False, }, 'TestProtoObjectHackedNamespace' : { 'headerFile': 'TestBindingHeader.h', 'register': False, }, +'TestWorkerExposedInterface' : { + 'headerFile': 'TestBindingHeader.h', + 'register': False, + }, + } # These are temporary, until they've been converted to use new DOM bindings def addExternalIface(iface, nativeType=None, headerFile=None, notflattened=False): if iface in DOMInterfaces: raise Exception('Interface declared both as WebIDL and External interface') domInterface = {
--- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -6906,25 +6906,28 @@ def needScopeObject(returnType, argument class CGCallGenerator(CGThing): """ A class to generate an actual call to a C++ object. Assumes that the C++ object is stored in a variable whose name is given by the |object| argument. needsSubjectPrincipal is a boolean indicating whether the call should receive the subject nsIPrincipal as argument. + needsCallerType is a boolean indicating whether the call should receive + a PrincipalType for the caller. + isFallible is a boolean indicating whether the call should be fallible. resultVar: If the returnType is not void, then the result of the call is stored in a C++ variable named by resultVar. The caller is responsible for declaring the result variable. If the caller doesn't care about the result value, resultVar can be omitted. """ - def __init__(self, isFallible, needsSubjectPrincipal, arguments, argsPre, - returnType, extendedAttributes, descriptor, + def __init__(self, isFallible, needsSubjectPrincipal, needsCallerType, + arguments, argsPre, returnType, extendedAttributes, descriptor, nativeMethodName, static, object="self", argsPost=[], resultVar=None): CGThing.__init__(self) result, resultOutParam, resultRooter, resultArgs, resultConversion = \ getRetvalDeclarationForType(returnType, descriptor) args = CGList([CGGeneric(arg) for arg in argsPre], ", ") @@ -6976,16 +6979,19 @@ class CGCallGenerator(CGThing): args.append(CGGeneric(resultVar)) else: assert resultOutParam == "ptr" args.append(CGGeneric("&" + resultVar)) if needsSubjectPrincipal: args.append(CGGeneric("subjectPrincipal")) + if needsCallerType: + args.append(CGGeneric("callerType")) + if isFallible: args.append(CGGeneric("rv")) args.extend(CGGeneric(arg) for arg in argsPost) # Build up our actual call self.cgRoot = CGList([]) call = CGGeneric(nativeMethodName) @@ -7042,16 +7048,34 @@ class CGCallGenerator(CGThing): """ $*{getPrincipal} // Initializing a nonnull is pretty darn annoying... NonNull<nsIPrincipal> subjectPrincipal; subjectPrincipal = static_cast<nsIPrincipal*>(nsJSPrincipals::get(principals)); """, getPrincipal=getPrincipal))) + if needsCallerType: + # Note that we do not want to use + # IsCallerChrome/ThreadsafeIsCallerChrome directly because those + # will pull in the check for UniversalXPConnect, which we ideally + # don't want to have in the new thing we're doing here. If not + # NS_IsMainThread(), though, we'll go ahead and call + # ThreasafeIsCallerChrome(), since that won't mess with + # UnivesalXPConnect and we don't want to worry about the right + # worker includes here. + callerCheck = CGGeneric("callerType = nsContentUtils::IsSystemPrincipal(nsContentUtils::SubjectPrincipal()) ? CallerType::System : CallerType::NonSystem;\n") + if descriptor.interface.isExposedInAnyWorker(): + callerCheck = CGIfElseWrapper( + "NS_IsMainThread()", + callerCheck, + CGGeneric("callerType = nsContentUtils::ThreadsafeIsCallerChrome() ? CallerType::System : CallerType::NonSystem;\n")); + self.cgRoot.prepend(callerCheck) + self.cgRoot.prepend(CGGeneric("CallerType callerType;\n")) + if isFallible: self.cgRoot.prepend(CGGeneric("binding_detail::FastErrorResult rv;\n")) self.cgRoot.append(CGGeneric(dedent( """ if (MOZ_UNLIKELY(rv.MaybeSetPendingException(cx))) { return false; } """))) @@ -7214,16 +7238,18 @@ def wrapArgIntoCurrentCompartment(arg, v if wrap and isOptional: wrap = CGIfWrapper(wrap, "%s.WasPassed()" % origValue) return wrap def needsContainsHack(m): return m.getExtendedAttribute("ReturnValueNeedsContainsHack") +def needsCallerType(m): + return m.getExtendedAttribute("NeedsCallerType") class CGPerSignatureCall(CGThing): """ This class handles the guts of generating code for a particular call signature. A call signature consists of four things: 1) A return type, which can be None to indicate that there is no actual return value (e.g. this is an attribute setter) or an @@ -7513,16 +7539,17 @@ class CGPerSignatureCall(CGThing): else: cgThings.append(CGIterableMethodGenerator(descriptor, idlNode.maplikeOrSetlikeOrIterable, idlNode.identifier.name)) else: cgThings.append(CGCallGenerator( self.isFallible(), idlNode.getExtendedAttribute('NeedsSubjectPrincipal'), + needsCallerType(idlNode), self.getArguments(), argsPre, returnType, self.extendedAttributes, descriptor, nativeMethodName, static, argsPost=argsPost, resultVar=resultVar)) if useCounterName: # Generate a telemetry call for when [UseCounter] is used. code = "SetDocumentAndPageUseCounter(cx, obj, eUseCounter_%s);\n" % useCounterName @@ -13633,17 +13660,18 @@ class CGBindingRoot(CGThing): bindingHeaders["mozilla/Preferences.h"] = any( descriptorRequiresPreferences(d) for d in descriptors) bindingHeaders["mozilla/dom/DOMJSProxyHandler.h"] = any( d.concrete and d.proxy for d in descriptors) def descriptorHasChromeOnly(desc): ctor = desc.interface.ctor() - return (any(isChromeOnly(a) or needsContainsHack(a) + return (any(isChromeOnly(a) or needsContainsHack(a) or + needsCallerType(a) for a in desc.interface.members) or desc.interface.getExtendedAttribute("ChromeOnly") is not None or # JS-implemented interfaces with an interface object get a # chromeonly _create method. And interfaces with an # interface object might have a ChromeOnly constructor. (desc.interface.hasInterfaceObject() and (desc.interface.isJSImplemented() or (ctor and isChromeOnly(ctor)))) or @@ -14076,17 +14104,24 @@ class CGNativeMember(ClassMethod): "aRetVal")) elif returnType.isAny(): args.append(Argument("JS::MutableHandle<JS::Value>", "aRetVal")) elif returnType.isObject() or returnType.isSpiderMonkeyInterface(): args.append(Argument("JS::MutableHandle<JSObject*>", "aRetVal")) # And the nsIPrincipal if self.member.getExtendedAttribute('NeedsSubjectPrincipal'): - args.append(Argument("nsIPrincipal&", "aPrincipal")) + # Cheat and assume self.descriptorProvider is a descriptor + if self.descriptorProvider.interface.isExposedInAnyWorker(): + args.append(Argument("Maybe<nsIPrincipal*>", "aSubjectPrincipal")) + else: + args.append(Argument("nsIPrincipal&", "aPrincipal")) + # And the caller type, if desired. + if needsCallerType(self.member): + args.append(Argument("CallerType", "aCallerType")) # And the ErrorResult if 'infallible' not in self.extendedAttrs: # Use aRv so it won't conflict with local vars named "rv" args.append(Argument("ErrorResult&", "aRv")) # The legacycaller thisval if self.member.isMethod() and self.member.isLegacycaller(): # If it has an identifier, we can't deal with it yet assert self.member.isIdentifierLess()
--- a/dom/bindings/docs/index.rst +++ b/dom/bindings/docs/index.rst @@ -78,17 +78,18 @@ Parser unit tests The current mechanism for this is ``mach webidl-parser-test``. Mochitests There are various mochitests under ``dom/bindings/test``. They should be runnable through the standard mechanisms. Working with test interfaces ``TestExampleGenBinding.cpp`` calls into methods from the - ``TestExampleInterface`` and ``TestExampleProxyInterface`` interfaces. + ``TestExampleInterface``, ``TestExampleProxyInterface``, + and ``TestExampleWorkerInterface`` interfaces. These interfaces need to be generated as part of the build. These interfaces should not be exported or packaged. There is a ``compiletests`` make target in ``dom/bindings`` that isn't part of the build that facilitates turnkey code generation and test file compilation. Minimal rebuilds
--- a/dom/bindings/parser/WebIDL.py +++ b/dom/bindings/parser/WebIDL.py @@ -4221,16 +4221,17 @@ class IDLAttribute(IDLInterfaceMember): identifier == "GetterThrows" or identifier == "ChromeOnly" or identifier == "Func" or identifier == "SecureContext" or identifier == "Frozen" or identifier == "NewObject" or identifier == "UnsafeInPrerendering" or identifier == "NeedsSubjectPrincipal" or + identifier == "NeedsCallerType" or identifier == "ReturnValueNeedsContainsHack" or identifier == "BinaryName"): # Known attributes that we don't need to do anything with here pass else: raise WebIDLError("Unknown extended attribute %s on attribute" % identifier, [attr.location]) IDLInterfaceMember.handleExtendedAttribute(self, attr) @@ -4939,16 +4940,17 @@ class IDLMethod(IDLInterfaceMember, IDLS identifier == "ChromeOnly" or identifier == "UnsafeInPrerendering" or identifier == "Pref" or identifier == "Deprecated" or identifier == "Func" or identifier == "SecureContext" or identifier == "BinaryName" or identifier == "NeedsSubjectPrincipal" or + identifier == "NeedsCallerType" or identifier == "StaticClassOverride"): # Known attributes that we don't need to do anything with here pass else: raise WebIDLError("Unknown extended attribute %s on method" % identifier, [attr.location]) IDLInterfaceMember.handleExtendedAttribute(self, attr)
--- a/dom/bindings/test/TestBindingHeader.h +++ b/dom/bindings/test/TestBindingHeader.h @@ -931,16 +931,19 @@ public: void SetThrowingAttr(bool arg, ErrorResult& aRv); bool GetThrowingGetterAttr(ErrorResult& aRv) const; void SetThrowingGetterAttr(bool arg); bool ThrowingSetterAttr() const; void SetThrowingSetterAttr(bool arg, ErrorResult& aRv); void NeedsSubjectPrincipalMethod(nsIPrincipal&); bool NeedsSubjectPrincipalAttr(nsIPrincipal&); void SetNeedsSubjectPrincipalAttr(bool, nsIPrincipal&); + void NeedsCallerTypeMethod(CallerType); + bool NeedsCallerTypeAttr(CallerType); + void SetNeedsCallerTypeAttr(bool, CallerType); int16_t LegacyCall(const JS::Value&, uint32_t, TestInterface&); void PassArgsWithDefaults(JSContext*, const Optional<int32_t>&, TestInterface*, const Dict&, double, const Optional<float>&); void SetDashed_attribute(int8_t); int8_t Dashed_attribute(); void Dashed_method(); @@ -1400,12 +1403,29 @@ public: }; class TestRenamedNamespace { }; class TestProtoObjectHackedNamespace { }; +class TestWorkerExposedInterface : public nsISupports, + public nsWrapperCache +{ +public: + NS_DECL_ISUPPORTS + + // We need a GetParentObject to make binding codegen happy + nsISupports* GetParentObject(); + + void NeedsSubjectPrincipalMethod(Maybe<nsIPrincipal*>); + bool NeedsSubjectPrincipalAttr(Maybe<nsIPrincipal*>); + void SetNeedsSubjectPrincipalAttr(bool, Maybe<nsIPrincipal*>); + void NeedsCallerTypeMethod(CallerType); + bool NeedsCallerTypeAttr(CallerType); + void SetNeedsCallerTypeAttr(bool, CallerType); +}; + } // namespace dom } // namespace mozilla #endif /* TestBindingHeader_h */
--- a/dom/bindings/test/TestCodeGen.webidl +++ b/dom/bindings/test/TestCodeGen.webidl @@ -940,16 +940,18 @@ interface TestInterface { [PutForwards=writableByte, LenientThis] readonly attribute TestInterface putForwardsAttr2; [PutForwards=writableByte, ChromeOnly] readonly attribute TestInterface putForwardsAttr3; [Throws] void throwingMethod(); [Throws] attribute boolean throwingAttr; [GetterThrows] attribute boolean throwingGetterAttr; [SetterThrows] attribute boolean throwingSetterAttr; [NeedsSubjectPrincipal] void needsSubjectPrincipalMethod(); [NeedsSubjectPrincipal] attribute boolean needsSubjectPrincipalAttr; + [NeedsCallerType] void needsCallerTypeMethod(); + [NeedsCallerType] attribute boolean needsCallerTypeAttr; legacycaller short(unsigned long arg1, TestInterface arg2); void passArgsWithDefaults(optional long arg1, optional TestInterface? arg2 = null, optional Dict arg3, optional double arg4 = 5.0, optional float arg5); attribute any jsonifierShouldSkipThis; attribute TestParentInterface jsonifierShouldSkipThis2; @@ -1247,8 +1249,16 @@ namespace TestRenamedNamespace { [ProtoObjectHack] namespace TestProtoObjectHackedNamespace { }; [SecureContext] interface TestSecureContextInterface { static void alsoSecureContext(); }; + +[Exposed=(Window,Worker)] +interface TestWorkerExposedInterface { + [NeedsSubjectPrincipal] void needsSubjectPrincipalMethod(); + [NeedsSubjectPrincipal] attribute boolean needsSubjectPrincipalAttr; + [NeedsCallerType] void needsCallerTypeMethod(); + [NeedsCallerType] attribute boolean needsCallerTypeAttr; +};
--- a/dom/bindings/test/TestExampleGen.webidl +++ b/dom/bindings/test/TestExampleGen.webidl @@ -770,16 +770,18 @@ interface TestExampleInterface { [PutForwards=writableByte, LenientThis] readonly attribute TestExampleInterface putForwardsAttr2; [PutForwards=writableByte, ChromeOnly] readonly attribute TestExampleInterface putForwardsAttr3; [Throws] void throwingMethod(); [Throws] attribute boolean throwingAttr; [GetterThrows] attribute boolean throwingGetterAttr; [SetterThrows] attribute boolean throwingSetterAttr; [NeedsSubjectPrincipal] void needsSubjectPrincipalMethod(); [NeedsSubjectPrincipal] attribute boolean needsSubjectPrincipalAttr; + [NeedsCallerType] void needsCallerTypeMethod(); + [NeedsCallerType] attribute boolean needsCallerTypeAttr; legacycaller short(unsigned long arg1, TestInterface arg2); void passArgsWithDefaults(optional long arg1, optional TestInterface? arg2 = null, optional Dict arg3, optional double arg4 = 5.0, optional float arg5); attribute any jsonifierShouldSkipThis; attribute TestParentInterface jsonifierShouldSkipThis2; attribute TestCallbackInterface jsonifierShouldSkipThis3; @@ -794,8 +796,16 @@ interface TestExampleInterface { interface TestExampleProxyInterface { getter long longIndexedGetter(unsigned long ix); setter creator void longIndexedSetter(unsigned long y, long z); stringifier DOMString myStringifier(); getter short shortNameGetter(DOMString nom); deleter void (DOMString nomnom); setter creator void shortNamedSetter(DOMString me, short value); }; + +[Exposed=(Window,Worker)] +interface TestExampleWorkerInterface { + [NeedsSubjectPrincipal] void needsSubjectPrincipalMethod(); + [NeedsSubjectPrincipal] attribute boolean needsSubjectPrincipalAttr; + [NeedsCallerType] void needsCallerTypeMethod(); + [NeedsCallerType] attribute boolean needsCallerTypeAttr; +};
--- a/dom/bindings/test/moz.build +++ b/dom/bindings/test/moz.build @@ -34,16 +34,17 @@ PREPROCESSED_TEST_WEBIDL_FILES += [ 'TestCodeGen.webidl', 'TestExampleGen.webidl', 'TestJSImplGen.webidl', ] WEBIDL_EXAMPLE_INTERFACES += [ 'TestExampleInterface', 'TestExampleProxyInterface', + 'TestExampleWorkerInterface', ] # Bug 932082 tracks having bindings use namespaced includes. LOCAL_INCLUDES += [ '!/dist/include/mozilla/dom', ] LOCAL_INCLUDES += [
--- a/dom/canvas/WebGL2ContextBuffers.cpp +++ b/dom/canvas/WebGL2ContextBuffers.cpp @@ -59,20 +59,28 @@ WebGL2Context::CopyBufferSubData(GLenum }; if (!fnValidateOffsetSize("read", readOffset, readBuffer) || !fnValidateOffsetSize("write", writeOffset, writeBuffer)) { return; } - if (readBuffer == writeBuffer && - !ValidateDataRanges(readOffset, writeOffset, size, funcName)) - { - return; + if (readBuffer == writeBuffer) { + MOZ_ASSERT((CheckedInt<WebGLsizeiptr>(readOffset) + size).isValid()); + MOZ_ASSERT((CheckedInt<WebGLsizeiptr>(writeOffset) + size).isValid()); + + const bool separate = (readOffset + size <= writeOffset || + writeOffset + size <= readOffset); + if (!separate) { + ErrorInvalidValue("%s: ranges [readOffset, readOffset + size) and" + " [writeOffset, writeOffset + size) overlap", + funcName); + return; + } } const auto& readType = readBuffer->Content(); const auto& writeType = writeBuffer->Content(); MOZ_ASSERT(readType != WebGLBuffer::Kind::Undefined); MOZ_ASSERT(writeType != WebGLBuffer::Kind::Undefined); if (writeType != readType) { ErrorInvalidOperation("%s: Can't copy %s data to %s data.",
--- a/dom/canvas/WebGL2ContextFramebuffers.cpp +++ b/dom/canvas/WebGL2ContextFramebuffers.cpp @@ -84,17 +84,17 @@ WebGL2Context::FramebufferTextureLayer(G fb = mBoundReadFramebuffer; break; default: MOZ_CRASH("GFX: Bad target."); } if (!fb) - return ErrorInvalidOperation("%a: Xannot modify framebuffer 0."); + return ErrorInvalidOperation("%s: Cannot modify framebuffer 0.", funcName); fb->FramebufferTextureLayer(funcName, attachment, texture, level, layer); } JS::Value WebGL2Context::GetFramebufferAttachmentParameter(JSContext* cx, GLenum target, GLenum attachment,
--- a/dom/canvas/WebGLContext.h +++ b/dom/canvas/WebGLContext.h @@ -1494,18 +1494,16 @@ protected: // Validation functions (implemented in WebGLContextValidate.cpp) bool InitAndValidateGL(FailureReason* const out_failReason); bool ValidateBlendEquationEnum(GLenum cap, const char* info); bool ValidateBlendFuncDstEnum(GLenum mode, const char* info); bool ValidateBlendFuncSrcEnum(GLenum mode, const char* info); bool ValidateBlendFuncEnumsCompatibility(GLenum sfactor, GLenum dfactor, const char* info); - bool ValidateDataRanges(WebGLintptr readOffset, WebGLintptr writeOffset, WebGLsizeiptr size, const char* info); - bool ValidateTextureTargetEnum(GLenum target, const char* info); bool ValidateComparisonEnum(GLenum target, const char* info); bool ValidateStencilOpEnum(GLenum action, const char* info); bool ValidateFaceEnum(GLenum face, const char* info); bool ValidateTexInputData(GLenum type, js::Scalar::Type jsArrayType, WebGLTexImageFunc func, WebGLTexDimensions dims); bool ValidateDrawModeEnum(GLenum mode, const char* info); bool ValidateAttribIndex(GLuint index, const char* info); bool ValidateAttribPointer(bool integerMode, GLuint index, GLint size, GLenum type,
--- a/dom/canvas/WebGLContextValidate.cpp +++ b/dom/canvas/WebGLContextValidate.cpp @@ -117,59 +117,16 @@ WebGLContext::ValidateBlendFuncEnumsComp ErrorInvalidOperation("%s are mutually incompatible, see section 6.8 in" " the WebGL 1.0 spec", info); return false; } return true; } -/** - * Check data ranges [readOffset, readOffset + size] and [writeOffset, - * writeOffset + size] for overlap. - * - * It is assumed that offset and size have already been validated. - */ -bool -WebGLContext::ValidateDataRanges(WebGLintptr readOffset, WebGLintptr writeOffset, WebGLsizeiptr size, const char* info) -{ - MOZ_ASSERT((CheckedInt<WebGLsizeiptr>(readOffset) + size).isValid()); - MOZ_ASSERT((CheckedInt<WebGLsizeiptr>(writeOffset) + size).isValid()); - - bool separate = (readOffset + size < writeOffset || writeOffset + size < readOffset); - if (!separate) { - ErrorInvalidValue("%s: ranges [readOffset, readOffset + size) and [writeOffset, " - "writeOffset + size) overlap", info); - } - - return separate; -} - -bool -WebGLContext::ValidateTextureTargetEnum(GLenum target, const char* info) -{ - switch (target) { - case LOCAL_GL_TEXTURE_2D: - case LOCAL_GL_TEXTURE_CUBE_MAP: - return true; - - case LOCAL_GL_TEXTURE_3D: - if (IsWebGL2()) - return true; - - break; - - default: - break; - } - - ErrorInvalidEnumInfo(info, target); - return false; -} - bool WebGLContext::ValidateComparisonEnum(GLenum target, const char* info) { switch (target) { case LOCAL_GL_NEVER: case LOCAL_GL_LESS: case LOCAL_GL_LEQUAL: case LOCAL_GL_GREATER:
--- a/dom/canvas/WebGLProgram.cpp +++ b/dom/canvas/WebGLProgram.cpp @@ -515,17 +515,17 @@ WebGLProgram::BindAttribLocation(GLuint if (loc >= mContext->MaxVertexAttribs()) { mContext->ErrorInvalidValue("bindAttribLocation: `location` must be less than" " MAX_VERTEX_ATTRIBS."); return; } if (StringBeginsWith(name, NS_LITERAL_STRING("gl_"))) { - mContext->ErrorInvalidOperation("bindAttribLocation: Can't set the location of a" + mContext->ErrorInvalidOperation("bindAttribLocation: Can't set the location of a" " name that starts with 'gl_'."); return; } NS_LossyConvertUTF16toASCII asciiName(name); auto res = mNextLink_BoundAttribLocs.insert({asciiName, loc});
--- a/dom/filesystem/compat/tests/script_entries.js +++ b/dom/filesystem/compat/tests/script_entries.js @@ -31,17 +31,17 @@ addMessageListener("entries.open", funct file2.append('bar.txt'); file2.create(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0o600); var dir2 = dir1.clone(); dir2.append('subsubdir'); dir2.create(Components.interfaces.nsIFile.DIRECTORY_TYPE, 0o700); sendAsyncMessage("entries.opened", { - data: [ new Directory(tmpDir.path), new File(tmpFile) ] + data: [ new Directory(tmpDir.path), File.createFromNsIFile(tmpFile) ] }); }); addMessageListener("entries.delete", function(e) { tmpFile.remove(true); tmpDir.remove(true); sendAsyncMessage("entries.deleted"); });
--- a/dom/filesystem/tests/script_fileList.js +++ b/dom/filesystem/tests/script_fileList.js @@ -119,11 +119,11 @@ addMessageListener("dir.open", function addMessageListener("file.open", function (e) { var testFile = Cc["@mozilla.org/file/directory_service;1"] .getService(Ci.nsIDirectoryService) .QueryInterface(Ci.nsIProperties) .get("ProfD", Ci.nsIFile); testFile.append("prefs.js"); sendAsyncMessage("file.opened", { - file: new File(testFile) + file: File.createFromNsIFile(testFile) }); });
--- a/dom/html/test/formSubmission_chrome.js +++ b/dom/html/test/formSubmission_chrome.js @@ -1,6 +1,6 @@ var { classes: Cc, interfaces: Ci, utils: Cu } = Components; Cu.importGlobalProperties(["File"]); addMessageListener("files.open", function (message) { - sendAsyncMessage("files.opened", message.map(path => new File(path))); + sendAsyncMessage("files.opened", message.map(path => File.createFromFileName(path))); });
--- a/dom/html/test/simpleFileOpener.js +++ b/dom/html/test/simpleFileOpener.js @@ -9,17 +9,17 @@ addMessageListener("file.open", function file = Cc["@mozilla.org/file/directory_service;1"] .getService(Ci.nsIProperties).get("TmpD", Ci.nsIFile); file.append(stem); file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o600); } sendAsyncMessage("file.opened", { fullPath: file.path, leafName: file.leafName, - domFile: new File(file), + domFile: File.createFromNsIFile(file), }); } catch(e) { sendAsyncMessage("fail", e.toString()); } }); addMessageListener("file.remove", function () { try {
--- a/dom/indexedDB/test/unit/xpcshell-head-parent-process.js +++ b/dom/indexedDB/test/unit/xpcshell-head-parent-process.js @@ -632,17 +632,17 @@ var SpecialPowers = { } let outStream = Cc["@mozilla.org/network/file-output-stream;1"].createInstance(Ci.nsIFileOutputStream); outStream.init(testFile, 0x02 | 0x08 | 0x20, // PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE filePerms, 0); if (request.data) { outStream.write(request.data, request.data.length); outStream.close(); } - filePaths.push(new File(testFile.path, request.options)); + filePaths.push(File.createFromFileName(testFile.path, request.options)); createdFiles.push(testFile); }); setTimeout(function () { callback(filePaths); }, 0); },
--- a/dom/media/MediaFormatReader.cpp +++ b/dom/media/MediaFormatReader.cpp @@ -195,16 +195,17 @@ private: RefPtr<MediaDataDecoder> mDecoder; MozPromiseRequestHolder<TokenPromise> mTokenPromise; MozPromiseRequestHolder<InitPromise> mInitPromise; ~Data() { mTokenPromise.DisconnectIfExists(); mInitPromise.DisconnectIfExists(); if (mDecoder) { + mDecoder->Flush(); mDecoder->Shutdown(); } } } mAudio, mVideo; void RunStage(TrackType aTrack); MediaResult DoCreateDecoder(TrackType aTrack); void DoInitDecoder(TrackType aTrack);
--- a/dom/media/ipc/RemoteVideoDecoder.cpp +++ b/dom/media/ipc/RemoteVideoDecoder.cpp @@ -6,16 +6,17 @@ #include "RemoteVideoDecoder.h" #include "VideoDecoderChild.h" #include "VideoDecoderManagerChild.h" #include "mozilla/layers/TextureClient.h" #include "base/thread.h" #include "MediaInfo.h" #include "MediaPrefs.h" #include "ImageContainer.h" +#include "mozilla/layers/SynchronousTask.h" namespace mozilla { namespace dom { using base::Thread; using namespace ipc; using namespace layers; using namespace gfx; @@ -91,21 +92,24 @@ RemoteVideoDecoder::Drain() self->mActor->Drain(); }), NS_DISPATCH_NORMAL); } void RemoteVideoDecoder::Shutdown() { MOZ_ASSERT(mCallback->OnReaderTaskQueue()); + SynchronousTask task("Shutdown"); RefPtr<RemoteVideoDecoder> self = this; - VideoDecoderManagerChild::GetManagerThread()->Dispatch(NS_NewRunnableFunction([self]() { + VideoDecoderManagerChild::GetManagerThread()->Dispatch(NS_NewRunnableFunction([&]() { + AutoCompleteTask complete(&task); MOZ_ASSERT(self->mActor); self->mActor->Shutdown(); }), NS_DISPATCH_NORMAL); + task.Wait(); } bool RemoteVideoDecoder::IsHardwareAccelerated(nsACString& aFailureReason) const { MOZ_ASSERT(mCallback->OnReaderTaskQueue()); return mActor->IsHardwareAccelerated(aFailureReason); } @@ -155,18 +159,18 @@ RemoteDecoderModule::CreateVideoDecoder( } MediaDataDecoderCallback* callback = aParams.mCallback; MOZ_ASSERT(callback->OnReaderTaskQueue()); RefPtr<RemoteVideoDecoder> object = new RemoteVideoDecoder(callback); VideoInfo info = aParams.VideoConfig(); - RefPtr<layers::KnowsCompositor> knowsCompositor = aParams.mKnowsCompositor; + TextureFactoryIdentifier ident = aParams.mKnowsCompositor->GetTextureFactoryIdentifier(); VideoDecoderManagerChild::GetManagerThread()->Dispatch(NS_NewRunnableFunction([=]() { - object->mActor->InitIPDL(callback, info, knowsCompositor); + object->mActor->InitIPDL(callback, info, ident); }), NS_DISPATCH_NORMAL); return object.forget(); } } // namespace dom } // namespace mozilla
--- a/dom/media/ipc/VideoDecoderChild.cpp +++ b/dom/media/ipc/VideoDecoderChild.cpp @@ -47,41 +47,49 @@ VideoDecoderChild::RecvOutput(const Vide RefPtr<VideoData> video = VideoData::CreateFromImage(info, aData.base().offset(), aData.base().time(), aData.base().duration(), image, aData.base().keyframe(), aData.base().timecode(), IntRect()); - mCallback->Output(video); + if (mCallback) { + mCallback->Output(video); + } return true; } bool VideoDecoderChild::RecvInputExhausted() { AssertOnManagerThread(); - mCallback->InputExhausted(); + if (mCallback) { + mCallback->InputExhausted(); + } return true; } bool VideoDecoderChild::RecvDrainComplete() { AssertOnManagerThread(); - mCallback->DrainComplete(); + if (mCallback) { + mCallback->DrainComplete(); + } return true; } bool VideoDecoderChild::RecvError(const nsresult& aError) { AssertOnManagerThread(); - mCallback->Error(aError); + if (mCallback) { + mCallback->Error(aError); + } return true; } bool VideoDecoderChild::RecvInitComplete(const bool& aHardware, const nsCString& aHardwareReason) { AssertOnManagerThread(); mInitPromise.Resolve(TrackInfo::kVideoTrack, __func__); @@ -102,45 +110,45 @@ VideoDecoderChild::RecvInitFailed(const void VideoDecoderChild::ActorDestroy(ActorDestroyReason aWhy) { if (aWhy == AbnormalShutdown) { // Defer reporting an error until we've recreated the manager so that // it'll be safe for MediaFormatReader to recreate decoders RefPtr<VideoDecoderChild> ref = this; GetManager()->RunWhenRecreated(NS_NewRunnableFunction([=]() { - if (ref->mInitialized) { + if (ref->mInitialized && ref->mCallback) { ref->mCallback->Error(NS_ERROR_DOM_MEDIA_NEED_NEW_DECODER); } else { ref->mInitPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_NEED_NEW_DECODER, __func__); } })); } mCanSend = false; } void VideoDecoderChild::InitIPDL(MediaDataDecoderCallback* aCallback, const VideoInfo& aVideoInfo, - layers::KnowsCompositor* aKnowsCompositor) + const layers::TextureFactoryIdentifier& aIdentifier) { RefPtr<VideoDecoderManagerChild> manager = VideoDecoderManagerChild::GetSingleton(); // If the manager isn't available, then don't initialize mIPDLSelfRef and leave // us in an error state. We'll then immediately reject the promise when Init() // is called and the caller can try again. Hopefully by then the new manager is // ready, or we've notified the caller of it being no longer available. // If not, then the cycle repeats until we're ready. if (!manager || !manager->CanSend()) { return; } mIPDLSelfRef = this; mCallback = aCallback; mVideoInfo = aVideoInfo; - mKnowsCompositor = aKnowsCompositor; + mIdentifier = aIdentifier; if (manager->SendPVideoDecoderConstructor(this)) { mCanSend = true; } } void VideoDecoderChild::DestroyIPDL() { @@ -164,17 +172,17 @@ VideoDecoderChild::Init() if (!mIPDLSelfRef) { return MediaDataDecoder::InitPromise::CreateAndReject( NS_ERROR_DOM_MEDIA_DECODE_ERR, __func__); } // If we failed to send this, then we'll still resolve the Init promise // as ActorDestroy handles it. if (mCanSend) { - SendInit(mVideoInfo, mKnowsCompositor->GetTextureFactoryIdentifier()); + SendInit(mVideoInfo, mIdentifier); } return mInitPromise.Ensure(__func__); } void VideoDecoderChild::Input(MediaRawData* aSample) { AssertOnManagerThread(); @@ -220,16 +228,17 @@ VideoDecoderChild::Drain() SendDrain(); } } void VideoDecoderChild::Shutdown() { AssertOnManagerThread(); + mInitPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__); if (mCanSend) { SendShutdown(); } mInitialized = false; } bool VideoDecoderChild::IsHardwareAccelerated(nsACString& aFailureReason) const
--- a/dom/media/ipc/VideoDecoderChild.h +++ b/dom/media/ipc/VideoDecoderChild.h @@ -41,17 +41,17 @@ public: void Drain(); void Shutdown(); bool IsHardwareAccelerated(nsACString& aFailureReason) const; void SetSeekThreshold(const media::TimeUnit& aTime); MOZ_IS_CLASS_INIT void InitIPDL(MediaDataDecoderCallback* aCallback, const VideoInfo& aVideoInfo, - layers::KnowsCompositor* aKnowsCompositor); + const layers::TextureFactoryIdentifier& aIdentifier); void DestroyIPDL(); // Called from IPDL when our actor has been destroyed void IPDLActorDestroyed(); VideoDecoderManagerChild* GetManager(); private: @@ -62,17 +62,17 @@ private: RefPtr<VideoDecoderChild> mIPDLSelfRef; RefPtr<nsIThread> mThread; MediaDataDecoderCallback* mCallback; MozPromiseHolder<MediaDataDecoder::InitPromise> mInitPromise; VideoInfo mVideoInfo; - RefPtr<layers::KnowsCompositor> mKnowsCompositor; + layers::TextureFactoryIdentifier mIdentifier; nsCString mHardwareAcceleratedReason; bool mCanSend; bool mInitialized; bool mIsHardwareAccelerated; }; } // namespace dom } // namespace mozilla
--- a/dom/media/ipc/VideoDecoderManagerParent.cpp +++ b/dom/media/ipc/VideoDecoderManagerParent.cpp @@ -12,16 +12,17 @@ #include "nsIObserverService.h" #include "nsIObserver.h" #include "nsIEventTarget.h" #include "nsThreadUtils.h" #include "ImageContainer.h" #include "mozilla/layers/VideoBridgeChild.h" #include "mozilla/SharedThreadPool.h" #include "mozilla/layers/ImageDataSerializer.h" +#include "mozilla/SyncRunnable.h" #if XP_WIN #include <objbase.h> #endif namespace mozilla { namespace dom { @@ -96,24 +97,33 @@ VideoDecoderManagerParent::StartupThread observerService->AddObserver(obs, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false); } void VideoDecoderManagerParent::ShutdownThreads() { sManagerTaskQueue->BeginShutdown(); sManagerTaskQueue->AwaitShutdownAndIdle(); + sManagerTaskQueue = nullptr; - sVideoDecoderManagerThread->Dispatch(NS_NewRunnableFunction([]() { - layers::VideoBridgeChild::Shutdown(); - }), NS_DISPATCH_SYNC); sVideoDecoderManagerThread->Shutdown(); sVideoDecoderManagerThread = nullptr; } +void +VideoDecoderManagerParent::ShutdownVideoBridge() +{ + if (sVideoDecoderManagerThread) { + RefPtr<Runnable> task = NS_NewRunnableFunction([]() { + VideoBridgeChild::Shutdown(); + }); + SyncRunnable::DispatchToThread(sVideoDecoderManagerThread, task); + } +} + bool VideoDecoderManagerParent::OnManagerThread() { return NS_GetCurrentThread() == sVideoDecoderManagerThread; } bool VideoDecoderManagerParent::CreateForContent(Endpoint<PVideoDecoderManagerParent>&& aEndpoint)
--- a/dom/media/ipc/VideoDecoderManagerParent.h +++ b/dom/media/ipc/VideoDecoderManagerParent.h @@ -19,16 +19,18 @@ public: static bool CreateForContent(Endpoint<PVideoDecoderManagerParent>&& aEndpoint); // Can be called from any thread SurfaceDescriptorGPUVideo StoreImage(layers::Image* aImage, layers::TextureClient* aTexture); static void StartupThreads(); static void ShutdownThreads(); + static void ShutdownVideoBridge(); + bool OnManagerThread(); protected: PVideoDecoderParent* AllocPVideoDecoderParent() override; bool DeallocPVideoDecoderParent(PVideoDecoderParent* actor) override; bool RecvReadback(const SurfaceDescriptorGPUVideo& aSD, SurfaceDescriptor* aResult) override; bool RecvDeallocateSurfaceDescriptorGPUVideo(const SurfaceDescriptorGPUVideo& aSD) override;
--- a/dom/media/ipc/VideoDecoderParent.cpp +++ b/dom/media/ipc/VideoDecoderParent.cpp @@ -132,33 +132,37 @@ VideoDecoderParent::RecvInput(const Medi mDecoder->Input(data); return true; } bool VideoDecoderParent::RecvFlush() { MOZ_ASSERT(!mDestroyed); - mDecoder->Flush(); + if (mDecoder) { + mDecoder->Flush(); + } return true; } bool VideoDecoderParent::RecvDrain() { MOZ_ASSERT(!mDestroyed); mDecoder->Drain(); return true; } bool VideoDecoderParent::RecvShutdown() { MOZ_ASSERT(!mDestroyed); - mDecoder->Shutdown(); + if (mDecoder) { + mDecoder->Shutdown(); + } mDecoder = nullptr; return true; } bool VideoDecoderParent::RecvSetSeekThreshold(const int64_t& aTime) { MOZ_ASSERT(!mDestroyed);
--- a/dom/media/platforms/wmf/WMFVideoMFTManager.cpp +++ b/dom/media/platforms/wmf/WMFVideoMFTManager.cpp @@ -25,16 +25,17 @@ #include "IMFYCbCrImage.h" #include "mozilla/WindowsVersion.h" #include "mozilla/Telemetry.h" #include "nsPrintfCString.h" #include "MediaTelemetryConstants.h" #include "GMPUtils.h" // For SplitAt. TODO: Move SplitAt to a central place. #include "MP4Decoder.h" #include "VPXDecoder.h" +#include "mozilla/SyncRunnable.h" #define LOG(...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, (__VA_ARGS__)) using mozilla::layers::Image; using mozilla::layers::IMFYCbCrImage; using mozilla::layers::LayerManager; using mozilla::layers::LayersBackend; @@ -366,17 +367,19 @@ WMFVideoMFTManager::InitializeDXVA(bool new CreateDXVAManagerEvent(aForceD3D9 ? LayersBackend::LAYERS_D3D9 : backend, mKnowsCompositor, mDXVAFailureReason); if (NS_IsMainThread()) { event->Run(); } else { - NS_DispatchToMainThread(event, NS_DISPATCH_SYNC); + // This logic needs to run on the main thread + nsCOMPtr<nsIThread> mainThread = do_GetMainThread(); + mozilla::SyncRunnable::DispatchToThread(mainThread, event); } mDXVA2Manager = event->mDXVA2Manager; return mDXVA2Manager != nullptr; } bool WMFVideoMFTManager::ValidateVideoInfo() @@ -602,17 +605,19 @@ WMFVideoMFTManager::CanUseDXVA(IMFMediaT // The supports config check must be done on the main thread since we have // a crash guard protecting it. RefPtr<SupportsConfigEvent> event = new SupportsConfigEvent(mDXVA2Manager, aType, framerate); if (NS_IsMainThread()) { event->Run(); } else { - NS_DispatchToMainThread(event, NS_DISPATCH_SYNC); + // This logic needs to run on the main thread + nsCOMPtr<nsIThread> mainThread = do_GetMainThread(); + mozilla::SyncRunnable::DispatchToThread(mainThread, event); } return event->mSupportsConfig; } HRESULT WMFVideoMFTManager::ConfigureVideoFrameGeometry() {
--- a/dom/webidl/File.webidl +++ b/dom/webidl/File.webidl @@ -6,22 +6,16 @@ * The origin of this IDL file is * https://w3c.github.io/FileAPI/#file */ interface nsIFile; [Constructor(sequence<BlobPart> fileBits, USVString fileName, optional FilePropertyBag options), - - // These constructors are just for chrome callers: - Constructor(Blob fileBits, optional ChromeFilePropertyBag options), - Constructor(nsIFile fileBits, optional ChromeFilePropertyBag options), - Constructor(USVString fileBits, optional ChromeFilePropertyBag options), - Exposed=(Window,Worker)] interface File : Blob { readonly attribute DOMString name; [GetterThrows] readonly attribute long long lastModified; }; @@ -40,9 +34,17 @@ partial interface File { [GetterThrows, Deprecated="FileLastModifiedDate"] readonly attribute Date lastModifiedDate; [BinaryName="path", Func="mozilla::dom::Directory::WebkitBlinkDirectoryPickerEnabled"] readonly attribute USVString webkitRelativePath; [GetterThrows, ChromeOnly] readonly attribute DOMString mozFullPath; + + [ChromeOnly, Throws] + static File createFromNsIFile(nsIFile file, + optional ChromeFilePropertyBag options); + + [ChromeOnly, Throws] + static File createFromFileName(USVString fileName, + optional ChromeFilePropertyBag options); };
--- a/dom/webidl/Window.webidl +++ b/dom/webidl/Window.webidl @@ -250,22 +250,16 @@ interface WindowModal { [Throws, Func="nsGlobalWindow::IsModalContentWindow", NeedsSubjectPrincipal] readonly attribute any dialogArguments; [Throws, Func="nsGlobalWindow::IsModalContentWindow", NeedsSubjectPrincipal] attribute any returnValue; }; Window implements WindowModal; -// https://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html#self-caches -partial interface Window { -[Throws, Func="mozilla::dom::cache::CacheStorage::PrefEnabled", SameObject] -readonly attribute CacheStorage caches; -}; - // Mozilla-specific stuff partial interface Window { //[NewObject, Throws] CSSStyleDeclaration getDefaultComputedStyle(Element elt, optional DOMString pseudoElt = ""); [NewObject, Throws] CSSStyleDeclaration? getDefaultComputedStyle(Element elt, optional DOMString pseudoElt = ""); // Mozilla extensions /** * Method for scrolling this window by a number of lines.
--- a/dom/webidl/WindowOrWorkerGlobalScope.webidl +++ b/dom/webidl/WindowOrWorkerGlobalScope.webidl @@ -2,16 +2,17 @@ /* 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://html.spec.whatwg.org/multipage/webappapis.html#windoworworkerglobalscope-mixin * https://fetch.spec.whatwg.org/#fetch-method * https://w3c.github.io/webappsec-secure-contexts/#monkey-patching-global-object + * https://w3c.github.io/ServiceWorker/#self-caches */ // https://html.spec.whatwg.org/multipage/webappapis.html#windoworworkerglobalscope-mixin [NoInterfaceObject, Exposed=(Window,Worker)] interface WindowOrWorkerGlobalScope { // XXXbz We don't implement 'origin' yet on either window or worker globals. // See bug 1306170. // [Replaceable] readonly attribute USVString origin; @@ -55,16 +56,22 @@ partial interface WindowOrWorkerGlobalSc // http://w3c.github.io/IndexedDB/#factory-interface partial interface WindowOrWorkerGlobalScope { // readonly attribute IDBFactory indexedDB; [Throws] readonly attribute IDBFactory? indexedDB; }; +// https://w3c.github.io/ServiceWorker/#self-caches +partial interface WindowOrWorkerGlobalScope { + [Throws, Func="mozilla::dom::cache::CacheStorage::PrefEnabled", SameObject] + readonly attribute CacheStorage caches; +}; + // Mozilla extensions partial interface WindowOrWorkerGlobalScope { // Extensions to ImageBitmap bits. // Bug 1141979 - [FoxEye] Extend ImageBitmap with interfaces to access its // underlying image data // // Note: // Overloaded functions cannot have different "extended attributes",
--- a/dom/webidl/WorkerGlobalScope.webidl +++ b/dom/webidl/WorkerGlobalScope.webidl @@ -30,22 +30,16 @@ interface WorkerGlobalScope : EventTarge partial interface WorkerGlobalScope { [Throws] void importScripts(DOMString... urls); readonly attribute WorkerNavigator navigator; }; -// https://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html#self-caches -partial interface WorkerGlobalScope { -[Throws, Func="mozilla::dom::cache::CacheStorage::PrefEnabled", SameObject] -readonly attribute CacheStorage caches; -}; - WorkerGlobalScope implements GlobalCrypto; WorkerGlobalScope implements WindowOrWorkerGlobalScope; // Not implemented yet: bug 1072107. // WorkerGlobalScope implements FontFaceSource; // Mozilla extensions partial interface WorkerGlobalScope {
--- a/dom/workers/test/fileapi_chromeScript.js +++ b/dom/workers/test/fileapi_chromeScript.js @@ -12,17 +12,17 @@ function createFileWithData(fileData) { var outStream = Cc["@mozilla.org/network/file-output-stream;1"].createInstance(Ci.nsIFileOutputStream); outStream.init(testFile, 0x02 | 0x08 | 0x20, // write, create, truncate 0o666, 0); if (willDelete) { fileData = "some irrelevant test data\n"; } outStream.write(fileData, fileData.length); outStream.close(); - var domFile = new File(testFile); + var domFile = File.createFromNsIFile(testFile); if (willDelete) { testFile.remove(/* recursive: */ false); } return domFile; } addMessageListener("files.open", function (message) { sendAsyncMessage("files.opened", message.map(createFileWithData));
--- a/dom/workers/test/script_bug1301094.js +++ b/dom/workers/test/script_bug1301094.js @@ -5,11 +5,11 @@ addMessageListener("file.open", function var tmpFile = Cc["@mozilla.org/file/directory_service;1"] .getService(Ci.nsIDirectoryService) .QueryInterface(Ci.nsIProperties) .get('TmpD', Ci.nsIFile) tmpFile.append('file.txt'); tmpFile.createUnique(Components.interfaces.nsIFile.FILE_TYPE, 0o600); sendAsyncMessage("file.opened", { - data: new File(tmpFile) + data: File.createFromNsIFile(tmpFile) }); });
--- a/editor/libeditor/CompositionTransaction.cpp +++ b/editor/libeditor/CompositionTransaction.cpp @@ -1,16 +1,17 @@ /* -*- 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 "CompositionTransaction.h" #include "mozilla/EditorBase.h" // mEditorBase +#include "mozilla/SelectionState.h" // RangeUpdater #include "mozilla/dom/Selection.h" // local var #include "mozilla/dom/Text.h" // mTextNode #include "nsAString.h" // params #include "nsDebug.h" // for NS_ASSERTION, etc #include "nsError.h" // for NS_SUCCEEDED, NS_FAILED, etc #include "nsIPresShell.h" // nsISelectionController constants #include "nsRange.h" // local var #include "nsQueryObject.h" // for do_QueryObject @@ -20,25 +21,28 @@ namespace mozilla { using namespace dom; CompositionTransaction::CompositionTransaction( Text& aTextNode, uint32_t aOffset, uint32_t aReplaceLength, TextRangeArray* aTextRangeArray, const nsAString& aStringToInsert, - EditorBase& aEditorBase) + EditorBase& aEditorBase, + RangeUpdater* aRangeUpdater) : mTextNode(&aTextNode) , mOffset(aOffset) , mReplaceLength(aReplaceLength) , mRanges(aTextRangeArray) , mStringToInsert(aStringToInsert) , mEditorBase(aEditorBase) + , mRangeUpdater(aRangeUpdater) , mFixed(false) { + MOZ_ASSERT(mTextNode->TextLength() >= mOffset); } CompositionTransaction::~CompositionTransaction() { } NS_IMPL_CYCLE_COLLECTION_INHERITED(CompositionTransaction, EditTransactionBase, mTextNode) @@ -62,22 +66,42 @@ CompositionTransaction::DoTransaction() NS_ENSURE_TRUE(selCon, NS_ERROR_NOT_INITIALIZED); // Advance caret: This requires the presentation shell to get the selection. if (mReplaceLength == 0) { nsresult rv = mTextNode->InsertData(mOffset, mStringToInsert); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } + mRangeUpdater->SelAdjInsertText(*mTextNode, mOffset, mStringToInsert); } else { + uint32_t replaceableLength = mTextNode->TextLength() - mOffset; nsresult rv = mTextNode->ReplaceData(mOffset, mReplaceLength, mStringToInsert); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } + mRangeUpdater->SelAdjDeleteText(mTextNode, mOffset, mReplaceLength); + mRangeUpdater->SelAdjInsertText(*mTextNode, mOffset, mStringToInsert); + + // If IME text node is multiple node, ReplaceData doesn't remove all IME + // text. So we need remove remained text into other text node. + if (replaceableLength < mReplaceLength) { + int32_t remainLength = mReplaceLength - replaceableLength; + nsCOMPtr<nsINode> node = mTextNode->GetNextSibling(); + while (node && node->IsNodeOfType(nsINode::eTEXT) && + remainLength > 0) { + Text* text = static_cast<Text*>(node.get()); + uint32_t textLength = text->TextLength(); + text->DeleteData(0, remainLength); + mRangeUpdater->SelAdjDeleteText(text, 0, remainLength); + remainLength -= textLength; + node = node->GetNextSibling(); + } + } } nsresult rv = SetSelectionForRanges(); NS_ENSURE_SUCCESS(rv, rv); return NS_OK; }
--- a/editor/libeditor/CompositionTransaction.h +++ b/editor/libeditor/CompositionTransaction.h @@ -12,16 +12,17 @@ #define NS_IMETEXTTXN_IID \ { 0xb391355d, 0x346c, 0x43d1, \ { 0x85, 0xed, 0x9e, 0x65, 0xbe, 0xe7, 0x7e, 0x48 } } namespace mozilla { class EditorBase; +class RangeUpdater; class TextRangeArray; namespace dom { class Text; } // namespace dom /** * CompositionTransaction stores all edit for a composition, i.e., @@ -30,30 +31,32 @@ class Text; * ranges and commit or cancel the composition. */ class CompositionTransaction final : public EditTransactionBase { public: NS_DECLARE_STATIC_IID_ACCESSOR(NS_IMETEXTTXN_IID) /** - * @param aTextNode The text content node. + * @param aTextNode The start node of text content. * @param aOffset The location in aTextNode to do the insertion. * @param aReplaceLength The length of text to replace. 0 means not * replacing existing text. * @param aTextRangeArray Clauses and/or caret information. This may be * null. * @param aString The new text to insert. * @param aEditorBase Used to get and set the selection. + * @param aRangeUpdater The range updater */ CompositionTransaction(dom::Text& aTextNode, uint32_t aOffset, uint32_t aReplaceLength, TextRangeArray* aTextRangeArray, const nsAString& aString, - EditorBase& aEditorBase); + EditorBase& aEditorBase, + RangeUpdater* aRangeUpdater); NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(CompositionTransaction, EditTransactionBase) NS_DECL_ISUPPORTS_INHERITED NS_DECL_EDITTRANSACTIONBASE @@ -84,16 +87,18 @@ private: RefPtr<TextRangeArray> mRanges; // The text to insert into mTextNode at mOffset. nsString mStringToInsert; // The editor, which is used to get the selection controller. EditorBase& mEditorBase; + RangeUpdater* mRangeUpdater; + bool mFixed; }; NS_DEFINE_STATIC_IID_ACCESSOR(CompositionTransaction, NS_IMETEXTTXN_IID) } // namespace mozilla #endif // #ifndef CompositionTransaction_h
--- a/editor/libeditor/EditorBase.cpp +++ b/editor/libeditor/EditorBase.cpp @@ -922,16 +922,17 @@ EditorBase::BeginPlaceHolderTransaction( // time to turn on the batch BeginUpdateViewBatch(); mPlaceHolderTxn = nullptr; mPlaceHolderName = aName; RefPtr<Selection> selection = GetSelection(); if (selection) { mSelState = new SelectionState(); mSelState->SaveSelection(selection); + mRangeUpdater.RegisterSelectionState(*mSelState); } } mPlaceHolderBatch++; return NS_OK; } NS_IMETHODIMP @@ -973,16 +974,17 @@ EditorBase::EndPlaceHolderTransaction() // cached for frame offset are Not available now if (selection) { selection->SetCanCacheFrameOffset(false); } if (mSelState) { // we saved the selection state, but never got to hand it to placeholder // (else we ould have nulled out this pointer), so destroy it to prevent leaks. + mRangeUpdater.DropSelectionState(*mSelState); delete mSelState; mSelState = nullptr; } // We might have never made a placeholder if no action took place. if (mPlaceHolderTxn) { nsCOMPtr<nsIAbsorbingTransaction> plcTxn = do_QueryReferent(mPlaceHolderTxn); if (plcTxn) { plcTxn->EndPlaceHolderBatch(); @@ -2431,18 +2433,18 @@ EditorBase::InsertTextImpl(const nsAStri nsresult EditorBase::InsertTextIntoTextNodeImpl(const nsAString& aStringToInsert, Text& aTextNode, int32_t aOffset, bool aSuppressIME) { RefPtr<EditTransactionBase> transaction; bool isIMETransaction = false; - int32_t replacedOffset = 0; - int32_t replacedLength = 0; + RefPtr<Text> insertedTextNode = &aTextNode; + int32_t insertedOffset = aOffset; // aSuppressIME is used when editor must insert text, yet this text is not // part of the current IME operation. Example: adjusting whitespace around an // IME insertion. if (ShouldHandleIMEComposition() && !aSuppressIME) { if (!mIMETextNode) { mIMETextNode = &aTextNode; mIMETextOffset = aOffset; } @@ -2462,48 +2464,41 @@ EditorBase::InsertTextIntoTextNodeImpl(c textRange.mStartOffset, textRange.Length()); } transaction = CreateTxnForComposition(aStringToInsert); isIMETransaction = true; // All characters of the composition string will be replaced with // aStringToInsert. So, we need to emulate to remove the composition // string. - replacedOffset = mIMETextOffset; - replacedLength = mIMETextLength; + insertedTextNode = mIMETextNode; + insertedOffset = mIMETextOffset; mIMETextLength = aStringToInsert.Length(); } else { transaction = CreateTxnForInsertText(aStringToInsert, aTextNode, aOffset); } // Let listeners know what's up for (auto& listener : mActionListeners) { listener->WillInsertText( - static_cast<nsIDOMCharacterData*>(aTextNode.AsDOMNode()), aOffset, - aStringToInsert); + static_cast<nsIDOMCharacterData*>(insertedTextNode->AsDOMNode()), + insertedOffset, aStringToInsert); } // XXX We may not need these view batches anymore. This is handled at a // higher level now I believe. BeginUpdateViewBatch(); nsresult rv = DoTransaction(transaction); EndUpdateViewBatch(); - if (replacedLength) { - mRangeUpdater.SelAdjDeleteText( - static_cast<nsIDOMCharacterData*>(aTextNode.AsDOMNode()), - replacedOffset, replacedLength); - } - mRangeUpdater.SelAdjInsertText(aTextNode, aOffset, aStringToInsert); - // let listeners know what happened for (auto& listener : mActionListeners) { listener->DidInsertText( - static_cast<nsIDOMCharacterData*>(aTextNode.AsDOMNode()), - aOffset, aStringToInsert, rv); + static_cast<nsIDOMCharacterData*>(insertedTextNode->AsDOMNode()), + insertedOffset, aStringToInsert, rv); } // Added some cruft here for bug 43366. Layout was crashing because we left // an empty text node lying around in the document. So I delete empty text // nodes caused by IME. I have to mark the IME transaction as "fixed", which // means that furure IME txns won't merge with it. This is because we don't // want future IME txns trying to put their text into a node that is no // longer in the document. This does not break undo/redo, because all these @@ -2610,17 +2605,18 @@ EditorBase::NotifyDocumentListeners( } already_AddRefed<InsertTextTransaction> EditorBase::CreateTxnForInsertText(const nsAString& aStringToInsert, Text& aTextNode, int32_t aOffset) { RefPtr<InsertTextTransaction> transaction = - new InsertTextTransaction(aTextNode, aOffset, aStringToInsert, *this); + new InsertTextTransaction(aTextNode, aOffset, aStringToInsert, *this, + &mRangeUpdater); return transaction.forget(); } nsresult EditorBase::DeleteText(nsGenericDOMDataNode& aCharData, uint32_t aOffset, uint32_t aLength) { @@ -4240,17 +4236,17 @@ EditorBase::CreateTxnForComposition(cons { MOZ_ASSERT(mIMETextNode); // During handling IME composition, mComposition must have been initialized. // TODO: We can simplify CompositionTransaction::Init() with TextComposition // class. RefPtr<CompositionTransaction> transaction = new CompositionTransaction(*mIMETextNode, mIMETextOffset, mIMETextLength, mComposition->GetRanges(), aStringToInsert, - *this); + *this, &mRangeUpdater); return transaction.forget(); } NS_IMETHODIMP EditorBase::CreateTxnForAddStyleSheet(StyleSheet* aSheet, AddStyleSheetTransaction** aTransaction) { RefPtr<AddStyleSheetTransaction> transaction = new AddStyleSheetTransaction();
--- a/editor/libeditor/InsertTextTransaction.cpp +++ b/editor/libeditor/InsertTextTransaction.cpp @@ -1,35 +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 "InsertTextTransaction.h" #include "mozilla/EditorBase.h" // mEditorBase +#include "mozilla/SelectionState.h" // RangeUpdater #include "mozilla/dom/Selection.h" // Selection local var #include "mozilla/dom/Text.h" // mTextNode #include "nsAString.h" // nsAString parameter #include "nsDebug.h" // for NS_ASSERTION, etc. #include "nsError.h" // for NS_OK, etc. #include "nsQueryObject.h" // for do_QueryObject namespace mozilla { using namespace dom; InsertTextTransaction::InsertTextTransaction(Text& aTextNode, uint32_t aOffset, const nsAString& aStringToInsert, - EditorBase& aEditorBase) + EditorBase& aEditorBase, + RangeUpdater* aRangeUpdater) : mTextNode(&aTextNode) , mOffset(aOffset) , mStringToInsert(aStringToInsert) , mEditorBase(aEditorBase) + , mRangeUpdater(aRangeUpdater) { } InsertTextTransaction::~InsertTextTransaction() { } NS_IMPL_CYCLE_COLLECTION_INHERITED(InsertTextTransaction, EditTransactionBase, @@ -56,16 +59,17 @@ InsertTextTransaction::DoTransaction() NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER); DebugOnly<nsresult> rv = selection->Collapse(mTextNode, mOffset + mStringToInsert.Length()); NS_ASSERTION(NS_SUCCEEDED(rv), "Selection could not be collapsed after insert"); } else { // Do nothing - DOM Range gravity will adjust selection } + mRangeUpdater->SelAdjInsertText(*mTextNode, mOffset, mStringToInsert); return NS_OK; } NS_IMETHODIMP InsertTextTransaction::UndoTransaction() { return mTextNode->DeleteData(mOffset, mStringToInsert.Length());
--- a/editor/libeditor/InsertTextTransaction.h +++ b/editor/libeditor/InsertTextTransaction.h @@ -17,16 +17,18 @@ class nsITransaction; #define NS_INSERTTEXTTXN_IID \ { 0x8c9ad77f, 0x22a7, 0x4d01, \ { 0xb1, 0x59, 0x8a, 0x0f, 0xdb, 0x1d, 0x08, 0xe9 } } namespace mozilla { class EditorBase; +class RangeUpdater; + namespace dom { class Text; } // namespace dom /** * A transaction that inserts text into a content node. */ class InsertTextTransaction final : public EditTransactionBase @@ -34,19 +36,21 @@ class InsertTextTransaction final : publ public: NS_DECLARE_STATIC_IID_ACCESSOR(NS_INSERTTEXTTXN_IID) /** * @param aElement The text content node. * @param aOffset The location in aElement to do the insertion. * @param aString The new text to insert. * @param aPresShell Used to get and set the selection. + * @param aRangeUpdater The range updater */ InsertTextTransaction(dom::Text& aTextNode, uint32_t aOffset, - const nsAString& aString, EditorBase& aEditorBase); + const nsAString& aString, EditorBase& aEditorBase, + RangeUpdater* aRangeUpdater); NS_DECL_ISUPPORTS_INHERITED NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(InsertTextTransaction, EditTransactionBase) NS_DECL_EDITTRANSACTIONBASE NS_IMETHOD Merge(nsITransaction* aTransaction, bool* aDidMerge) override; @@ -68,15 +72,17 @@ private: // The offset into mTextNode where the insertion is to take place. uint32_t mOffset; // The text to insert into mTextNode at mOffset. nsString mStringToInsert; // The editor, which we'll need to get the selection. EditorBase& mEditorBase; + + RangeUpdater* mRangeUpdater; }; NS_DEFINE_STATIC_IID_ACCESSOR(InsertTextTransaction, NS_INSERTTEXTTXN_IID) } // namespace mozilla #endif // #ifndef InsertTextTransaction_h
--- a/editor/libeditor/tests/mochitest.ini +++ b/editor/libeditor/tests/mochitest.ini @@ -205,16 +205,18 @@ skip-if = os == 'android' subsuite = clipboard skip-if = toolkit == 'android' [test_bug1248128.html] [test_bug1250010.html] [test_bug1257363.html] [test_bug1248185.html] [test_bug1258085.html] [test_bug1268736.html] +[test_bug1310912.html] +skip-if = toolkit == 'android' # bug 1315898 [test_bug1315065.html] [test_CF_HTML_clipboard.html] subsuite = clipboard [test_composition_event_created_in_chrome.html] [test_contenteditable_focus.html] [test_dom_input_event_on_htmleditor.html] skip-if = toolkit == 'android' # bug 1054087
new file mode 100644 --- /dev/null +++ b/editor/libeditor/tests/test_bug1310912.html @@ -0,0 +1,93 @@ +<!DOCTYPE html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1310912 +--> +<html> +<head> + <title>Test for Bug 1310912</title> + <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1310912">Mozilla Bug 1310912</a> +<p id="display"></p> +<div id="content" style="display: none;"> + +</div> + +<div id="editable1" contenteditable="true">ABC</div> +<pre id="test"> + +<script class="testbody" type="application/javascript"> +SimpleTest.waitForExplicitFinish(); +SimpleTest.waitForFocus(function() { + let elm = document.getElementById("editable1"); + + elm.focus(); + let sel = window.getSelection(); + sel.collapse(elm.childNodes[0], elm.textContent.length); + + synthesizeCompositionChange({ + composition: { + string: "DEF", + clauses: [ + { length: 3, attr: COMPOSITION_ATTR_RAW_CLAUSE } + ] + }, + caret: { start: 3, length: 0 } + }); + ok(elm.textContent == "ABCDEF", "composing text should be set"); + + window.getSelection().getRangeAt(0).insertNode(document.createTextNode("")); + synthesizeCompositionChange({ + composition: { + string: "GHI", + clauses: [ + { length: 3, attr: COMPOSITION_ATTR_CONVERTED_CLAUSE } + ] + }, + caret: { start: 0, length: 0 } + }); + ok(elm.textContent == "ABCGHI", "composing text should be replaced"); + + window.getSelection().getRangeAt(0).insertNode(document.createTextNode("")); + synthesizeCompositionChange({ + composition: { + string: "JKL", + clauses: [ + { length: 3, attr: COMPOSITION_ATTR_CONVERTED_CLAUSE } + ] + }, + caret: { start: 0, length: 0 } + }); + ok(elm.textContent == "ABCJKL", "composing text should be replaced"); + + window.getSelection().getRangeAt(0).insertNode(document.createTextNode("")); + synthesizeCompositionChange({ + composition: { + string: "MNO", + clauses: [ + { length: 3, attr: COMPOSITION_ATTR_CONVERTED_CLAUSE } + ] + }, + caret: { start: 1, length: 0 } + }); + ok(elm.textContent == "ABCMNO", "composing text should be replaced"); + + window.getSelection().getRangeAt(0).insertNode(document.createTextNode("")); + synthesizeComposition({ type: "compositioncommitasis" }); + ok(elm.textContent == "ABCMNO", "composing text should be committed"); + + synthesizeKey("Z", { accelKey: true }); + ok(elm.textContent == "ABC", "text should be undoed"); + + synthesizeKey("Z", { accelKey: true, shiftKey: true }); + ok(elm.textContent == "ABCMNO", "text should be redoed"); + + SimpleTest.finish(); +}); +</script> +</pre> +</body> +</html>
--- a/gfx/ipc/GPUParent.cpp +++ b/gfx/ipc/GPUParent.cpp @@ -17,16 +17,17 @@ #include "mozilla/ipc/CrashReporterClient.h" #include "mozilla/ipc/ProcessChild.h" #include "mozilla/layers/APZThreadUtils.h" #include "mozilla/layers/APZCTreeManager.h" #include "mozilla/layers/CompositorBridgeParent.h" #include "mozilla/dom/VideoDecoderManagerParent.h" #include "mozilla/layers/CompositorThread.h" #include "mozilla/layers/ImageBridgeParent.h" +#include "mozilla/dom/VideoDecoderManagerChild.h" #include "mozilla/layers/LayerTreeOwnerTracker.h" #include "nsDebugImpl.h" #include "nsExceptionHandler.h" #include "nsThreadManager.h" #include "prenv.h" #include "ProcessUtils.h" #include "VRManager.h" #include "VRManagerParent.h" @@ -363,16 +364,17 @@ GPUParent::ActorDestroy(ActorDestroyReas // state. ProcessChild::QuickExit(); #endif if (mVsyncBridge) { mVsyncBridge->Shutdown(); mVsyncBridge = nullptr; } + dom::VideoDecoderManagerParent::ShutdownVideoBridge(); CompositorThreadHolder::Shutdown(); Factory::ShutDown(); #if defined(XP_WIN) DeviceManagerDx::Shutdown(); DeviceManagerD3D9::Shutdown(); #endif LayerTreeOwnerTracker::Shutdown(); gfxVars::Shutdown();
--- a/gfx/layers/d3d11/TextureD3D11.cpp +++ b/gfx/layers/d3d11/TextureD3D11.cpp @@ -789,17 +789,17 @@ DXGITextureHostD3D11::LockInternal() { if (!GetDevice()) { NS_WARNING("trying to lock a TextureHost without a D3D device"); return false; } if (!mTextureSource) { if (!mTexture && !OpenSharedHandle()) { - gfxWindowsPlatform::GetPlatform()->ForceDeviceReset(ForcedDeviceResetReason::OPENSHAREDHANDLE); + DeviceManagerDx::Get()->ForceDeviceReset(ForcedDeviceResetReason::OPENSHAREDHANDLE); return false; } mTextureSource = new DataTextureSourceD3D11(mFormat, mCompositor, mTexture); } mIsLocked = LockD3DTexture(mTextureSource->GetD3D11Texture()); @@ -1207,17 +1207,17 @@ SyncObjectD3D11::FinalizeFrame() if (!mD3D11Texture && mD3D11SyncedTextures.size()) { RefPtr<ID3D11Device> device = DeviceManagerDx::Get()->GetContentDevice(); hr = device->OpenSharedResource(mHandle, __uuidof(ID3D11Texture2D), (void**)(ID3D11Texture2D**)getter_AddRefs(mD3D11Texture)); if (FAILED(hr) || !mD3D11Texture) { gfxCriticalError() << "Failed to D3D11 OpenSharedResource for frame finalization: " << hexa(hr); - if (gfxWindowsPlatform::GetPlatform()->DidRenderingDeviceReset()) { + if (DeviceManagerDx::Get()->HasDeviceReset()) { return; } gfxDevCrash(LogReason::D3D11FinalizeFrame) << "Without device reset: " << hexa(hr); } // test QI RefPtr<IDXGIKeyedMutex> mutex; @@ -1233,30 +1233,30 @@ SyncObjectD3D11::FinalizeFrame() if (mD3D11SyncedTextures.size()) { RefPtr<IDXGIKeyedMutex> mutex; hr = mD3D11Texture->QueryInterface((IDXGIKeyedMutex**)getter_AddRefs(mutex)); { AutoTextureLock(mutex, hr, 20000); if (hr == WAIT_TIMEOUT) { - if (gfxWindowsPlatform::GetPlatform()->DidRenderingDeviceReset()) { + if (DeviceManagerDx::Get()->HasDeviceReset()) { gfxWarning() << "AcquireSync timed out because of device reset."; return; } gfxDevCrash(LogReason::D3D11SyncLock) << "Timeout on the D3D11 sync lock"; } D3D11_BOX box; box.front = box.top = box.left = 0; box.back = box.bottom = box.right = 1; RefPtr<ID3D11Device> dev = DeviceManagerDx::Get()->GetContentDevice(); if (!dev) { - if (gfxWindowsPlatform::GetPlatform()->DidRenderingDeviceReset()) { + if (DeviceManagerDx::Get()->HasDeviceReset()) { return; } MOZ_CRASH("GFX: Invalid D3D11 content device"); } RefPtr<ID3D11DeviceContext> ctx; dev->GetImmediateContext(getter_AddRefs(ctx));
--- a/gfx/layers/d3d9/CompositorD3D9.cpp +++ b/gfx/layers/d3d9/CompositorD3D9.cpp @@ -12,16 +12,17 @@ #include "mozilla/layers/Effects.h" #include "nsWindowsHelpers.h" #include "Nv3DVUtils.h" #include "gfxFailure.h" #include "mozilla/layers/LayerManagerComposite.h" #include "gfxPrefs.h" #include "gfxCrashReporterUtils.h" #include "gfxUtils.h" +#include "mozilla/gfx/DeviceManagerDx.h" #include "mozilla/layers/CompositorBridgeParent.h" #include "mozilla/widget/WinCompositorWidget.h" #include "D3D9SurfaceImage.h" namespace mozilla { namespace layers { using namespace mozilla::gfx; @@ -674,17 +675,17 @@ CompositorD3D9::Ready() void CompositorD3D9::FailedToResetDevice() { mFailedResetAttempts += 1; // 10 is a totally arbitrary number that we may want to increase or decrease // depending on how things behave in the wild. if (mFailedResetAttempts > 10) { mFailedResetAttempts = 0; - gfxWindowsPlatform::GetPlatform()->D3D9DeviceReset(); + DeviceManagerDx::Get()->NotifyD3D9DeviceReset(); gfxCriticalNote << "[D3D9] Unable to get a working D3D9 Compositor"; } } void CompositorD3D9::BeginFrame(const nsIntRegion& aInvalidRegion, const IntRect *aClipRectIn, const IntRect& aRenderBounds,
--- a/gfx/layers/ipc/VideoBridgeChild.cpp +++ b/gfx/layers/ipc/VideoBridgeChild.cpp @@ -18,30 +18,33 @@ VideoBridgeChild::Startup() sVideoBridgeChildSingleton = new VideoBridgeChild(); RefPtr<VideoBridgeParent> parent = new VideoBridgeParent(); MessageLoop* loop = CompositorThreadHolder::Loop(); sVideoBridgeChildSingleton->Open(parent->GetIPCChannel(), loop, ipc::ChildSide); + sVideoBridgeChildSingleton->mIPDLSelfRef = sVideoBridgeChildSingleton; parent->SetOtherProcessId(base::GetCurrentProcId()); } /* static */ void VideoBridgeChild::Shutdown() { - sVideoBridgeChildSingleton = nullptr; - + if (sVideoBridgeChildSingleton) { + sVideoBridgeChildSingleton->Close(); + sVideoBridgeChildSingleton = nullptr; + } } VideoBridgeChild::VideoBridgeChild() : mMessageLoop(MessageLoop::current()) + , mCanSend(true) { - sVideoBridgeChildSingleton = this; } VideoBridgeChild::~VideoBridgeChild() { } VideoBridgeChild* VideoBridgeChild::GetSingleton() @@ -83,16 +86,28 @@ VideoBridgeChild::AllocPTextureChild(con } bool VideoBridgeChild::DeallocPTextureChild(PTextureChild* actor) { return TextureClient::DestroyIPDLActor(actor); } +void +VideoBridgeChild::ActorDestroy(ActorDestroyReason aWhy) +{ + mCanSend = false; +} + +void +VideoBridgeChild::DeallocPVideoBridgeChild() +{ + mIPDLSelfRef = nullptr; +} + PTextureChild* VideoBridgeChild::CreateTexture(const SurfaceDescriptor& aSharedData, LayersBackend aLayersBackend, TextureFlags aFlags, uint64_t aSerial) { MOZ_ASSERT(CanSend()); return SendPTextureConstructor(aSharedData, aLayersBackend, aFlags, aSerial);
--- a/gfx/layers/ipc/VideoBridgeChild.h +++ b/gfx/layers/ipc/VideoBridgeChild.h @@ -26,16 +26,20 @@ public: // PVideoBridgeChild PTextureChild* AllocPTextureChild(const SurfaceDescriptor& aSharedData, const LayersBackend& aLayersBackend, const TextureFlags& aFlags, const uint64_t& aSerial) override; bool DeallocPTextureChild(PTextureChild* actor) override; + void ActorDestroy(ActorDestroyReason aWhy) override; + void DeallocPVideoBridgeChild() override; + + // ISurfaceAllocator bool AllocUnsafeShmem(size_t aSize, mozilla::ipc::SharedMemory::SharedMemoryType aShmType, mozilla::ipc::Shmem* aShmem) override; bool AllocShmem(size_t aSize, mozilla::ipc::SharedMemory::SharedMemoryType aShmType, mozilla::ipc::Shmem* aShmem) override; bool DeallocShmem(mozilla::ipc::Shmem& aShmem) override; @@ -49,21 +53,23 @@ public: // ClientIPCAllocator base::ProcessId GetParentPid() const override { return OtherPid(); } MessageLoop * GetMessageLoop() const override { return mMessageLoop; } void CancelWaitForRecycle(uint64_t aTextureId) override { MOZ_ASSERT(false, "NO RECYCLING HERE"); } // ISurfaceAllocator bool IsSameProcess() const override; - bool CanSend() { return true; } + bool CanSend() { return mCanSend; } private: VideoBridgeChild(); ~VideoBridgeChild(); + RefPtr<VideoBridgeChild> mIPDLSelfRef; MessageLoop* mMessageLoop; + bool mCanSend; }; } // namespace layers } // namespace mozilla #endif
--- a/gfx/src/DriverCrashGuard.cpp +++ b/gfx/src/DriverCrashGuard.cpp @@ -61,16 +61,21 @@ DriverCrashGuard::InitializeIfNeeded() mInitialized = true; Initialize(); } static inline bool AreCrashGuardsEnabled() { + // Crash guard isn't supported in the GPU process since the entire + // process is basically a crash guard. + if (XRE_IsGPUProcess()) { + return false; + } #ifdef NIGHTLY_BUILD // We only use the crash guard on non-nightly channels, since the nightly // channel is for development and having graphics features perma-disabled // is rather annoying. Unless the user forces is with an environment // variable, which comes in handy for testing. return gfxEnv::ForceCrashGuardNightly(); #else // Check to see if all guards have been disabled through the environment.
--- a/gfx/thebes/DeviceManagerDx.cpp +++ b/gfx/thebes/DeviceManagerDx.cpp @@ -574,28 +574,31 @@ void DeviceManagerDx::ResetDevices() { MutexAutoLock lock(mDeviceLock); mAdapter = nullptr; mCompositorDevice = nullptr; mContentDevice = nullptr; mDeviceStatus = Nothing(); + mDeviceResetReason = Nothing(); Factory::SetDirect3D11Device(nullptr); } bool DeviceManagerDx::MaybeResetAndReacquireDevices() { DeviceResetReason resetReason; - if (!GetAnyDeviceRemovedReason(&resetReason)) { + if (!HasDeviceReset(&resetReason)) { return false; } - Telemetry::Accumulate(Telemetry::DEVICE_RESET_REASON, uint32_t(resetReason)); + if (resetReason != DeviceResetReason::FORCED_RESET) { + Telemetry::Accumulate(Telemetry::DEVICE_RESET_REASON, uint32_t(resetReason)); + } bool createCompositorDevice = !!mCompositorDevice; bool createContentDevice = !!mContentDevice; ResetDevices(); if (createCompositorDevice && !CreateCompositorDevices()) { // Just stop, don't try anything more @@ -651,45 +654,94 @@ static DeviceResetReason HResultToResetR case E_OUTOFMEMORY: return DeviceResetReason::OUT_OF_MEMORY; default: MOZ_ASSERT(false); } return DeviceResetReason::UNKNOWN; } +bool +DeviceManagerDx::HasDeviceReset(DeviceResetReason* aOutReason) +{ + MutexAutoLock lock(mDeviceLock); + + if (mDeviceResetReason) { + *aOutReason = mDeviceResetReason.value(); + return true; + } + + DeviceResetReason reason; + if (GetAnyDeviceRemovedReason(&reason)) { + mDeviceResetReason = Some(reason); + *aOutReason = reason; + return true; + } + + return false; +} + static inline bool -DidDeviceReset(RefPtr<ID3D11Device> aDevice, DeviceResetReason* aOutReason) +DidDeviceReset(const RefPtr<ID3D11Device>& aDevice, DeviceResetReason* aOutReason) { if (!aDevice) { return false; } HRESULT hr = aDevice->GetDeviceRemovedReason(); if (hr == S_OK) { return false; } *aOutReason = HResultToResetReason(hr); return true; } bool DeviceManagerDx::GetAnyDeviceRemovedReason(DeviceResetReason* aOutReason) { - // Note: this can be called off the main thread, so we need to use - // our threadsafe getters. - if (DidDeviceReset(GetCompositorDevice(), aOutReason) || - DidDeviceReset(GetContentDevice(), aOutReason)) + // Caller must own the lock, since we access devices directly, and can be + // called from any thread. + mDeviceLock.AssertCurrentThreadOwns(); + + if (DidDeviceReset(mCompositorDevice, aOutReason) || + DidDeviceReset(mContentDevice, aOutReason)) { return true; } + + if (XRE_IsParentProcess() && + NS_IsMainThread() && + gfxPrefs::DeviceResetForTesting()) + { + gfxPrefs::SetDeviceResetForTesting(0); + *aOutReason = DeviceResetReason::FORCED_RESET; + return true; + } + return false; } void +DeviceManagerDx::ForceDeviceReset(ForcedDeviceResetReason aReason) +{ + Telemetry::Accumulate(Telemetry::FORCED_DEVICE_RESET_REASON, uint32_t(aReason)); + { + MutexAutoLock lock(mDeviceLock); + mDeviceResetReason = Some(DeviceResetReason::FORCED_RESET); + } +} + +void +DeviceManagerDx::NotifyD3D9DeviceReset() +{ + MutexAutoLock lock(mDeviceLock); + mDeviceResetReason = Some(DeviceResetReason::D3D9_RESET); +} + +void DeviceManagerDx::DisableD3D11AfterCrash() { gfxConfig::Disable(Feature::D3D11_COMPOSITING, FeatureStatus::CrashedInHandler, "Crashed while acquiring a Direct3D11 device", NS_LITERAL_CSTRING("FEATURE_FAILURE_D3D11_CRASH")); ResetDevices(); }
--- a/gfx/thebes/DeviceManagerDx.h +++ b/gfx/thebes/DeviceManagerDx.h @@ -71,29 +71,33 @@ public: void CreateContentDevices(); void ImportDeviceInfo(const D3D11DeviceStatus& aDeviceStatus); void ExportDeviceInfo(D3D11DeviceStatus* aOut); void ResetDevices(); void InitializeDirectDraw(); - // Call GetDeviceRemovedReason on each device until one returns - // a failure. - bool GetAnyDeviceRemovedReason(DeviceResetReason* aOutReason); - // Reset and reacquire the devices if a reset has happened. // Returns whether a reset occurred not whether reacquiring // was successful. bool MaybeResetAndReacquireDevices(); // Test whether we can acquire a DXGI 1.2-compatible adapter. This should // only be called on startup before devices are initialized. bool CheckRemotePresentSupport(); + // Device reset helpers. + bool HasDeviceReset(DeviceResetReason* aOutReason = nullptr); + + // Note: these set the cached device reset reason, which will be picked up + // on the next frame. + void ForceDeviceReset(ForcedDeviceResetReason aReason); + void NotifyD3D9DeviceReset(); + private: IDXGIAdapter1 *GetDXGIAdapter(); void DisableD3D11AfterCrash(); void CreateCompositorDevice(mozilla::gfx::FeatureState& d3d11); bool CreateCompositorDeviceHelper( mozilla::gfx::FeatureState& aD3d11, @@ -111,16 +115,20 @@ private: HRESULT& aResOut, RefPtr<ID3D11Device>& aOutDevice); bool ContentAdapterIsParentAdapter(ID3D11Device* device); bool LoadD3D11(); void ReleaseD3D11(); + // Call GetDeviceRemovedReason on each device until one returns + // a failure. + bool GetAnyDeviceRemovedReason(DeviceResetReason* aOutReason); + private: static StaticAutoPtr<DeviceManagerDx> sInstance; // This is assigned during device creation. Afterwards, it is released if // devices failed, and "forgotten" if devices succeeded (meaning, we leak // the ref and unassign the module). nsModuleHandle mD3D11Module; @@ -131,14 +139,16 @@ private: RefPtr<ID3D11Device> mContentDevice; RefPtr<ID3D11Device> mDecoderDevice; bool mCompositorDeviceSupportsVideo; Maybe<D3D11DeviceStatus> mDeviceStatus; nsModuleHandle mDirectDrawDLL; RefPtr<IDirectDraw7> mDirectDraw; + + Maybe<DeviceResetReason> mDeviceResetReason; }; } // namespace gfx } // namespace mozilla #endif // mozilla_gfx_thebes_DeviceManagerDx_h
--- a/gfx/thebes/gfxPlatform.h +++ b/gfx/thebes/gfxPlatform.h @@ -125,17 +125,18 @@ enum class DeviceResetReason OK = 0, HUNG, REMOVED, RESET, DRIVER_ERROR, INVALID_CALL, OUT_OF_MEMORY, FORCED_RESET, - UNKNOWN + UNKNOWN, + D3D9_RESET }; enum class ForcedDeviceResetReason { OPENSHAREDHANDLE = 0, COMPOSITOR_UPDATED, };
--- a/gfx/thebes/gfxWindowsPlatform.cpp +++ b/gfx/thebes/gfxWindowsPlatform.cpp @@ -305,19 +305,16 @@ public: return NS_OK; } }; NS_IMPL_ISUPPORTS(D3DSharedTexturesReporter, nsIMemoryReporter) gfxWindowsPlatform::gfxWindowsPlatform() : mRenderMode(RENDER_GDI) - , mHasDeviceReset(false) - , mHasFakeDeviceReset(false) - , mHasD3D9DeviceReset(false) { mUseClearTypeForDownloadableFonts = UNINITIALIZED_VALUE; mUseClearTypeAlways = UNINITIALIZED_VALUE; /* * Initialize COM */ CoInitialize(nullptr); @@ -434,30 +431,23 @@ gfxWindowsPlatform::InitDWriteSupport() bool gfxWindowsPlatform::HandleDeviceReset() { DeviceResetReason resetReason = DeviceResetReason::OK; if (!DidRenderingDeviceReset(&resetReason)) { return false; } - if (!mHasFakeDeviceReset) { + if (resetReason != DeviceResetReason::FORCED_RESET) { Telemetry::Accumulate(Telemetry::DEVICE_RESET_REASON, uint32_t(resetReason)); } // Remove devices and adapters. DeviceManagerDx::Get()->ResetDevices(); - // Reset local state. Note: we leave feature status variables as-is. They - // will be recomputed by InitializeDevices(). - mHasDeviceReset = false; - mHasFakeDeviceReset = false; - mHasD3D9DeviceReset = false; - mDeviceResetReason = DeviceResetReason::OK; - imgLoader::NormalLoader()->ClearCache(true); imgLoader::NormalLoader()->ClearCache(false); imgLoader::PrivateBrowsingLoader()->ClearCache(true); imgLoader::PrivateBrowsingLoader()->ClearCache(false); gfxAlphaBoxBlur::ShutdownBlurCache(); if (XRE_IsContentProcess()) { // Fetch updated device parameters. @@ -512,25 +502,16 @@ gfxWindowsPlatform::UpdateRenderMode() << ", D2D1 status:" << FeatureStatusToString(gfxConfig::GetValue(Feature::DIRECT2D)) << ", content:" << int(GetDefaultContentBackend()) << ", compositor:" << int(GetCompositorBackend()); MOZ_CRASH("GFX: Failed to update reference draw target after device reset"); } } } -void -gfxWindowsPlatform::ForceDeviceReset(ForcedDeviceResetReason aReason) -{ - Telemetry::Accumulate(Telemetry::FORCED_DEVICE_RESET_REASON, uint32_t(aReason)); - - mDeviceResetReason = DeviceResetReason::FORCED_RESET; - mHasDeviceReset = true; -} - mozilla::gfx::BackendType gfxWindowsPlatform::GetContentBackendFor(mozilla::layers::LayersBackend aLayers) { mozilla::gfx::BackendType defaultBackend = gfxPlatform::GetDefaultContentBackend(); if (aLayers == LayersBackend::LAYERS_D3D11) { return defaultBackend; } @@ -911,67 +892,31 @@ gfxWindowsPlatform::IsFontFormatSupporte if (aFormatFlags != 0) { return false; } // no format hint set, need to look at data return true; } -void -gfxWindowsPlatform::CompositorUpdated() -{ - ForceDeviceReset(ForcedDeviceResetReason::COMPOSITOR_UPDATED); - UpdateRenderMode(); -} - -void -gfxWindowsPlatform::TestDeviceReset(DeviceResetReason aReason) -{ - if (mHasDeviceReset) { - return; - } - mHasDeviceReset = true; - mHasFakeDeviceReset = true; - mDeviceResetReason = aReason; -} - bool gfxWindowsPlatform::DidRenderingDeviceReset(DeviceResetReason* aResetReason) { - if (mHasDeviceReset) { - if (aResetReason) { - *aResetReason = mDeviceResetReason; - } - return true; + DeviceManagerDx* dm = DeviceManagerDx::Get(); + if (!dm) { + return false; } - if (aResetReason) { - *aResetReason = DeviceResetReason::OK; - } + return dm->HasDeviceReset(aResetReason); +} - if (DeviceManagerDx::Get()->GetAnyDeviceRemovedReason(&mDeviceResetReason)) { - mHasDeviceReset = true; - if (aResetReason) { - *aResetReason = mDeviceResetReason; - } - return true; - } - - if (mHasD3D9DeviceReset) { - return true; - } - if (XRE_IsParentProcess() && gfxPrefs::DeviceResetForTesting()) { - TestDeviceReset((DeviceResetReason)gfxPrefs::DeviceResetForTesting()); - if (aResetReason) { - *aResetReason = mDeviceResetReason; - } - gfxPrefs::SetDeviceResetForTesting(0); - return true; - } - return false; +void +gfxWindowsPlatform::CompositorUpdated() +{ + DeviceManagerDx::Get()->ForceDeviceReset(ForcedDeviceResetReason::COMPOSITOR_UPDATED); + UpdateRenderMode(); } BOOL CALLBACK InvalidateWindowForDeviceReset(HWND aWnd, LPARAM aMsg) { RedrawWindow(aWnd, nullptr, nullptr, RDW_INVALIDATE|RDW_INTERNALPAINT|RDW_FRAME); return TRUE; @@ -1327,21 +1272,16 @@ gfxWindowsPlatform::SetupClearTypeParams getter_AddRefs(mRenderingParams[TEXT_RENDERING_NORMAL])); GetDWriteFactory()->CreateCustomRenderingParams(gamma, contrast, level, dwriteGeometry, DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC, getter_AddRefs(mRenderingParams[TEXT_RENDERING_GDI_CLASSIC])); } } -void -gfxWindowsPlatform::D3D9DeviceReset() { - mHasD3D9DeviceReset = true; -} - ReadbackManagerD3D11* gfxWindowsPlatform::GetReadbackManager() { if (!mD3D11ReadbackManager) { mD3D11ReadbackManager = new ReadbackManagerD3D11(); } return mD3D11ReadbackManager;
--- a/gfx/thebes/gfxWindowsPlatform.h +++ b/gfx/thebes/gfxWindowsPlatform.h @@ -146,21 +146,16 @@ public: /** * Updates render mode with relation to the current preferences and * available devices. */ void UpdateRenderMode(); /** - * Forces all GPU resources to be recreated on the next frame. - */ - void ForceDeviceReset(ForcedDeviceResetReason aReason); - - /** * Verifies a D2D device is present and working, will attempt to create one * it is non-functional or non-existant. * * \param aAttemptForce Attempt to force D2D cairo device creation by using * cairo device creation routines. */ void VerifyD2DDevice(bool aAttemptForce); @@ -206,36 +201,32 @@ public: IDWriteFactory *GetDWriteFactory() { return mDWriteFactory; } inline bool DWriteEnabled() { return !!mDWriteFactory; } inline DWRITE_MEASURING_MODE DWriteMeasuringMode() { return mMeasuringMode; } IDWriteRenderingParams *GetRenderingParams(TextRenderingMode aRenderMode) { return mRenderingParams[aRenderMode]; } public: - void D3D9DeviceReset(); - bool DwmCompositionEnabled(); mozilla::layers::ReadbackManagerD3D11* GetReadbackManager(); static bool IsOptimus(); bool SupportsApzWheelInput() const override { return true; } bool SupportsApzTouchInput() const override; // Recreate devices as needed for a device reset. Returns true if a device // reset occurred. bool HandleDeviceReset(); void UpdateBackendPrefs(); - void TestDeviceReset(DeviceResetReason aReason); - virtual already_AddRefed<mozilla::gfx::VsyncSource> CreateHardwareVsyncSource() override; static mozilla::Atomic<size_t> sD3D11SharedTextures; static mozilla::Atomic<size_t> sD3D9SharedTextures; bool SupportsPluginDirectBitmapDrawing() override { return true; } bool SupportsPluginDirectDXGIDrawing(); @@ -277,19 +268,14 @@ private: void InitializeD3D11Config(); void InitializeD2DConfig(); void InitializeDirectDrawConfig(); RefPtr<IDWriteFactory> mDWriteFactory; RefPtr<IDWriteRenderingParams> mRenderingParams[TEXT_RENDERING_COUNT]; DWRITE_MEASURING_MODE mMeasuringMode; - bool mHasDeviceReset; - bool mHasFakeDeviceReset; - mozilla::Atomic<bool> mHasD3D9DeviceReset; - DeviceResetReason mDeviceResetReason; - RefPtr<mozilla::layers::ReadbackManagerD3D11> mD3D11ReadbackManager; nsTArray<D3D_FEATURE_LEVEL> mFeatureLevels; }; #endif /* GFX_WINDOWS_PLATFORM_H */
--- a/image/SVGDocumentWrapper.cpp +++ b/image/SVGDocumentWrapper.cpp @@ -357,17 +357,17 @@ SVGDocumentWrapper::SetupViewer(nsIReque // document needs this navigation timing object for time computation, such // as to calculate current time stamp based on the start time of navigation // time object. // // For a root document, DocShell would do these sort of things // automatically. Since there is no DocShell for this wrapped SVG document, // we must set it up manually. RefPtr<nsDOMNavigationTiming> timing = new nsDOMNavigationTiming(); - timing->NotifyNavigationStart(); + timing->NotifyNavigationStart(nsDOMNavigationTiming::DocShellState::eInactive); viewer->SetNavigationTiming(timing); nsCOMPtr<nsIParser> parser = do_QueryInterface(listener); NS_ENSURE_TRUE(parser, NS_ERROR_UNEXPECTED); // XML-only, because this is for SVG content nsCOMPtr<nsIContentSink> sink = parser->GetContentSink(); NS_ENSURE_TRUE(sink, NS_ERROR_UNEXPECTED);
--- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -512,17 +512,17 @@ IsProxy(JSContext* cx, unsigned argc, Va args.rval().setBoolean(args[0].toObject().is<ProxyObject>()); return true; } static bool WasmIsSupported(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); - args.rval().setBoolean(wasm::HasCompilerSupport(cx)); + args.rval().setBoolean(wasm::HasSupport(cx)); return true; } static bool WasmTextToBinary(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); RootedObject callee(cx, &args.callee());
--- a/js/src/builtin/TypedArray.js +++ b/js/src/builtin/TypedArray.js @@ -1651,22 +1651,16 @@ function ArrayBufferSlice(start, end) { // Step 22. return new_; } function IsDetachedBufferThis() { return IsDetachedBuffer(this); } -function ArrayBufferStaticSlice(buf, start, end) { - if (arguments.length < 1) - ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'ArrayBuffer.slice'); - return callFunction(ArrayBufferSlice, buf, start, end); -} - // ES 2016 draft Mar 25, 2016 24.1.3.3. function ArrayBufferSpecies() { // Step 1. return this; } _SetCanonicalName(ArrayBufferSpecies, "get [Symbol.species]"); // Shared memory and atomics proposal (30 Oct 2016)
--- a/js/src/builtin/Utilities.js +++ b/js/src/builtin/Utilities.js @@ -143,17 +143,17 @@ function GetIterator(obj, method) { if (arguments.length === 1) method = GetMethod(obj, std_iterator); // Steps 3-4. var iterator = callContentFunction(method, obj); // Step 5. if (!IsObject(iterator)) - ThrowTypeError(JSMSG_NOT_ITERABLE, ToString(iterator)); + ThrowTypeError(JSMSG_NOT_ITERATOR, ToString(iterator)); // Step 6. return iterator; } var _builtinCtorsCache = {__proto__: null}; function GetBuiltinConstructor(builtinName) {
--- a/js/src/ds/PageProtectingVector.h +++ b/js/src/ds/PageProtectingVector.h @@ -73,30 +73,28 @@ class PageProtectingVector final unprotectedBytes += offsetToPage; offsetToPage = (pageSize - (uintptr_t(vector.begin()) & pageMask)) & pageMask; unprotectedBytes -= offsetToPage; protectionEnabled = vector.capacity() >= protectionLowerBound && vector.capacity() >= pageSize + offsetToPage; } void protect() { - MOZ_ASSERT(!regionUnprotected); - if (protectionEnabled && unprotectedBytes >= intptr_t(pageSize)) { + if (!regionUnprotected && protectionEnabled && unprotectedBytes >= intptr_t(pageSize)) { size_t toProtect = size_t(unprotectedBytes) & ~pageMask; uintptr_t addr = uintptr_t(vector.begin()) + offsetToPage + protectedBytes; gc::MakePagesReadOnly(reinterpret_cast<void*>(addr), toProtect); unprotectedBytes -= toProtect; protectedBytes += toProtect; } } void unprotect() { - MOZ_ASSERT(!regionUnprotected); MOZ_ASSERT_IF(!protectionEnabled, !protectedBytes); - if (protectedBytes) { + if (!regionUnprotected && protectedBytes) { uintptr_t addr = uintptr_t(vector.begin()) + offsetToPage; gc::UnprotectPages(reinterpret_cast<void*>(addr), protectedBytes); unprotectedBytes += protectedBytes; protectedBytes = 0; } } void protectNewBuffer() {
--- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -5981,16 +5981,18 @@ BytecodeEmitter::emitIterator() return false; if (!emitElemOpBase(JSOP_CALLELEM)) // OBJ ITERFN return false; if (!emit1(JSOP_SWAP)) // ITERFN OBJ return false; if (!emitCall(JSOP_CALLITER, 0)) // ITER return false; checkTypeSet(JSOP_CALLITER); + if (!emitCheckIsObj(CheckIsObjectKind::GetIterator)) // ITER + return false; return true; } bool BytecodeEmitter::emitSpread(bool allowSelfHosted) { LoopControl loopInfo(this, StatementKind::Spread);
new file mode 100644 --- /dev/null +++ b/js/src/jit-test/tests/basic/arraybuffer-slice-warn.js @@ -0,0 +1,13 @@ +// ArrayBuffer.slice should be warned once and only once. + +enableLastWarning(); + +ArrayBuffer.slice(new ArrayBuffer(10), 1); +var warning = getLastWarning(); +assertEq(warning !== null, true, "warning should be generated"); +assertEq(warning.name, "Warning"); + +clearLastWarning(); +ArrayBuffer.slice(new ArrayBuffer(10), 1); +warning = getLastWarning(); +assertEq(warning, null, "warning should not generated for 2nd ocurrence");
new file mode 100644 --- /dev/null +++ b/js/src/jit-test/tests/xdr/async-lazy.js @@ -0,0 +1,24 @@ +async function f1(a, b) { + let x = await 10; + return x; +}; +var toStringResult = f1.toString(); + +async function f2(a, b) { + // arguments.callee gets wrapped function from unwrapped function. + return arguments.callee; +}; + +relazifyFunctions(); + +// toString gets unwrapped function from wrapped function. +assertEq(f1.toString(), toStringResult); + +var ans = 0; +f1().then(x => { ans = x; }); +drainJobQueue(); +assertEq(ans, 10); + +f2().then(x => { ans = x; }); +drainJobQueue(); +assertEq(ans, f2);
new file mode 100644 --- /dev/null +++ b/js/src/jit-test/tests/xdr/async.js @@ -0,0 +1,32 @@ +load(libdir + 'bytecode-cache.js'); + +async function f1(a, b) { + let x = await 10; + return x; +}; +var toStringResult = f1.toString(); + +var test = ` +async function f1(a, b) { + let x = await 10; + return x; +}; +// toString gets unwrapped function from wrapped function. +assertEq(f1.toString(), \`${toStringResult}\`); + +var ans = 0; +f1().then(x => { ans = x; }); +drainJobQueue(); +assertEq(ans, 10); + +async function f2(a, b) { + // arguments.callee gets wrapped function from unwrapped function. + return arguments.callee; +}; + +f2().then(x => { ans = x; }); +drainJobQueue(); +assertEq(ans, f2); +`; + +evalWithCache(test, { assertEqBytecode: true, checkFrozen: true});
--- a/js/src/jit/arm/MacroAssembler-arm.h +++ b/js/src/jit/arm/MacroAssembler-arm.h @@ -1531,16 +1531,20 @@ class MacroAssemblerARMCompat : public M ma_ldr(Address(WasmTlsReg, offsetof(wasm::TlsData, memoryBase)), HeapReg, scratch); ma_ldr(Address(WasmTlsReg, offsetof(wasm::TlsData, globalData)), GlobalReg, scratch); ma_add(Imm32(WasmGlobalRegBias), GlobalReg, scratch); } // Instrumentation for entering and leaving the profiler. void profilerEnterFrame(Register framePtr, Register scratch); void profilerExitFrame(); + + struct AutoPrepareForPatching { + explicit AutoPrepareForPatching(MacroAssemblerARMCompat&) {} + }; }; typedef MacroAssemblerARMCompat MacroAssemblerSpecific; } // namespace jit } // namespace js #endif /* jit_arm_MacroAssembler_arm_h */
--- a/js/src/jit/arm64/MacroAssembler-arm64.h +++ b/js/src/jit/arm64/MacroAssembler-arm64.h @@ -2311,16 +2311,20 @@ class MacroAssemblerCompat : public vixl } // FIXME: Should be in Assembler? // FIXME: Should be const? uint32_t currentOffset() const { return nextOffset().getOffset(); } + struct AutoPrepareForPatching { + explicit AutoPrepareForPatching(MacroAssemblerCompat&) {} + }; + protected: bool buildOOLFakeExitFrame(void* fakeReturnAddr) { uint32_t descriptor = MakeFrameDescriptor(framePushed(), JitFrame_IonJS, ExitFrameLayout::Size()); Push(Imm32(descriptor)); Push(ImmPtr(fakeReturnAddr)); return true; }
--- a/js/src/jit/mips-shared/MacroAssembler-mips-shared.h +++ b/js/src/jit/mips-shared/MacroAssembler-mips-shared.h @@ -244,14 +244,19 @@ class MacroAssemblerMIPSShared : public Register output); void atomicExchange(int nbytes, bool signExtend, const Address& address, Register value, Register valueTemp, Register offsetTemp, Register maskTemp, Register output); void atomicExchange(int nbytes, bool signExtend, const BaseIndex& address, Register value, Register valueTemp, Register offsetTemp, Register maskTemp, Register output); + + public: + struct AutoPrepareForPatching { + explicit AutoPrepareForPatching(MacroAssemblerMIPSShared&) {} + }; }; } // namespace jit } // namespace js #endif /* jit_mips_shared_MacroAssembler_mips_shared_h */
--- a/js/src/jit/x86-shared/Assembler-x86-shared.h +++ b/js/src/jit/x86-shared/Assembler-x86-shared.h @@ -1052,27 +1052,34 @@ class AssemblerX86Shared : public Assemb default: MOZ_CRASH("unexpected operand kind"); } } CodeOffset callWithPatch() { return CodeOffset(masm.call().offset()); } + + struct AutoPrepareForPatching : X86Encoding::AutoUnprotectAssemblerBufferRegion { + explicit AutoPrepareForPatching(AssemblerX86Shared& masm) + : X86Encoding::AutoUnprotectAssemblerBufferRegion(masm.masm, 0, masm.size()) + {} + }; + void patchCall(uint32_t callerOffset, uint32_t calleeOffset) { + // The caller uses AutoUnprotectBuffer. unsigned char* code = masm.data(); - X86Encoding::AutoUnprotectAssemblerBufferRegion unprotect(masm, callerOffset - 4, 4); X86Encoding::SetRel32(code + callerOffset, code + calleeOffset); } CodeOffset farJumpWithPatch() { return CodeOffset(masm.jmp().offset()); } void patchFarJump(CodeOffset farJump, uint32_t targetOffset) { + // The caller uses AutoUnprotectBuffer. unsigned char* code = masm.data(); - X86Encoding::AutoUnprotectAssemblerBufferRegion unprotect(masm, farJump.offset() - 4, 4); X86Encoding::SetRel32(code + farJump.offset(), code + targetOffset); } static void repatchFarJump(uint8_t* code, uint32_t farJumpOffset, uint32_t targetOffset) { X86Encoding::SetRel32(code + farJumpOffset, code + targetOffset); } CodeOffset twoByteNop() { return CodeOffset(masm.twoByteNop().offset());
--- a/js/src/js.msg +++ b/js/src/js.msg @@ -67,16 +67,17 @@ MSG_DEF(JSMSG_REDECLARED_VAR, 2 MSG_DEF(JSMSG_UNDECLARED_VAR, 1, JSEXN_REFERENCEERR, "assignment to undeclared variable {0}") MSG_DEF(JSMSG_GETTER_ONLY, 0, JSEXN_TYPEERR, "setting a property that has only a getter") MSG_DEF(JSMSG_OVERWRITING_ACCESSOR, 1, JSEXN_TYPEERR, "can't overwrite accessor property {0}") MSG_DEF(JSMSG_UNDEFINED_PROP, 1, JSEXN_REFERENCEERR, "reference to undefined property {0}") MSG_DEF(JSMSG_INVALID_MAP_ITERABLE, 1, JSEXN_TYPEERR, "iterable for {0} should have array-like objects") MSG_DEF(JSMSG_NESTING_GENERATOR, 0, JSEXN_TYPEERR, "already executing generator") MSG_DEF(JSMSG_INCOMPATIBLE_METHOD, 3, JSEXN_TYPEERR, "{0} {1} called on incompatible {2}") MSG_DEF(JSMSG_OBJECT_WATCH_DEPRECATED, 0, JSEXN_WARN, "Object.prototype.watch and unwatch are very slow, non-standard, and deprecated; use a getter/setter instead") +MSG_DEF(JSMSG_ARRAYBUFFER_SLICE_DEPRECATED, 0, JSEXN_WARN, "ArrayBuffer.slice is deprecated; use ArrayBuffer.prototype.slice instead") MSG_DEF(JSMSG_BAD_SURROGATE_CHAR, 1, JSEXN_TYPEERR, "bad surrogate character {0}") MSG_DEF(JSMSG_UTF8_CHAR_TOO_LARGE, 1, JSEXN_TYPEERR, "UTF-8 character {0} too large") MSG_DEF(JSMSG_MALFORMED_UTF8_CHAR, 1, JSEXN_TYPEERR, "malformed UTF-8 character sequence at offset {0}") MSG_DEF(JSMSG_BUILTIN_CTOR_NO_NEW, 1, JSEXN_TYPEERR, "calling a builtin {0} constructor without new is forbidden") MSG_DEF(JSMSG_BAD_GENERATOR_YIELD, 1, JSEXN_TYPEERR, "yield from closing generator {0}") MSG_DEF(JSMSG_EMPTY_ARRAY_REDUCE, 0, JSEXN_TYPEERR, "reduce of empty array with no initial value") MSG_DEF(JSMSG_UNEXPECTED_TYPE, 2, JSEXN_TYPEERR, "{0} is {1}") MSG_DEF(JSMSG_MISSING_FUN_ARG, 2, JSEXN_TYPEERR, "missing argument {0} when calling function {1}") @@ -87,17 +88,19 @@ MSG_DEF(JSMSG_OBJECT_NOT_EXTENSIBLE, 1 MSG_DEF(JSMSG_CANT_DEFINE_PROP_OBJECT_NOT_EXTENSIBLE, 2, JSEXN_TYPEERR, "can't define property {1}: {0} is not extensible") MSG_DEF(JSMSG_CANT_REDEFINE_PROP, 1, JSEXN_TYPEERR, "can't redefine non-configurable property {0}") MSG_DEF(JSMSG_CANT_REDEFINE_ARRAY_LENGTH, 0, JSEXN_TYPEERR, "can't redefine array length") MSG_DEF(JSMSG_CANT_DEFINE_PAST_ARRAY_LENGTH, 0, JSEXN_TYPEERR, "can't define array index property past the end of an array with non-writable length") MSG_DEF(JSMSG_BAD_GET_SET_FIELD, 1, JSEXN_TYPEERR, "property descriptor's {0} field is neither undefined nor a function") MSG_DEF(JSMSG_THROW_TYPE_ERROR, 0, JSEXN_TYPEERR, "'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them") MSG_DEF(JSMSG_NOT_EXPECTED_TYPE, 3, JSEXN_TYPEERR, "{0}: expected {1}, got {2}") MSG_DEF(JSMSG_NOT_ITERABLE, 1, JSEXN_TYPEERR, "{0} is not iterable") +MSG_DEF(JSMSG_NOT_ITERATOR, 1, JSEXN_TYPEERR, "{0} is not iterator") MSG_DEF(JSMSG_ALREADY_HAS_PRAGMA, 2, JSEXN_WARN, "{0} is being assigned a {1}, but already has one") +MSG_DEF(JSMSG_GET_ITER_RETURNED_PRIMITIVE, 0, JSEXN_TYPEERR, "[Symbol.iterator]() returned a non-object value") MSG_DEF(JSMSG_NEXT_RETURNED_PRIMITIVE, 0, JSEXN_TYPEERR, "iterator.next() returned a non-object value") MSG_DEF(JSMSG_CANT_SET_PROTO, 0, JSEXN_TYPEERR, "can't set prototype of this object") MSG_DEF(JSMSG_CANT_SET_PROTO_OF, 1, JSEXN_TYPEERR, "can't set prototype of {0}") MSG_DEF(JSMSG_CANT_SET_PROTO_CYCLE, 0, JSEXN_TYPEERR, "can't set prototype: it would cause a prototype chain cycle") MSG_DEF(JSMSG_INVALID_ARG_TYPE, 3, JSEXN_TYPEERR, "Invalid type: {0} can't be a{1} {2}") MSG_DEF(JSMSG_TERMINATED, 1, JSEXN_ERR, "Script terminated by timeout at:\n{0}") MSG_DEF(JSMSG_PROTO_NOT_OBJORNULL, 1, JSEXN_TYPEERR, "{0}.prototype is not an object or null") MSG_DEF(JSMSG_CANT_CALL_CLASS_CONSTRUCTOR, 0, JSEXN_TYPEERR, "class constructors must be invoked with |new|")
--- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -65,16 +65,17 @@ #include "js/Conversions.h" #include "js/Date.h" #include "js/Initialization.h" #include "js/Proxy.h" #include "js/SliceBudget.h" #include "js/StructuredClone.h" #include "js/UniquePtr.h" #include "js/Utility.h" +#include "vm/AsyncFunction.h" #include "vm/DateObject.h" #include "vm/Debugger.h" #include "vm/EnvironmentObject.h" #include "vm/ErrorObject.h" #include "vm/HelperThreads.h" #include "vm/Interpreter.h" #include "vm/RegExpStatics.h" #include "vm/Runtime.h" @@ -3522,16 +3523,21 @@ CloneFunctionObject(JSContext* cx, Handl return nullptr; } if (IsAsmJSModule(fun)) { JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CANT_CLONE_OBJECT); return nullptr; } + if (IsWrappedAsyncFunction(fun)) { + JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CANT_CLONE_OBJECT); + return nullptr; + } + if (CanReuseScriptForClone(cx->compartment(), fun, env)) { // If the script is to be reused, either the script can already handle // non-syntactic scopes, or there is only the standard global lexical // scope. #ifdef DEBUG // Fail here if we OOM during debug asserting. // CloneFunctionReuseScript will delazify the script anyways, so we // are not creating an extra failure condition for DEBUG builds.
--- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -311,16 +311,17 @@ js::XDRScript(XDRState<mode>* xdr, Handl ArgumentsHasVarBinding, NeedsArgsObj, HasMappedArgsObj, FunctionHasThisBinding, FunctionHasExtraBodyVarScope, IsGeneratorExp, IsLegacyGenerator, IsStarGenerator, + IsAsync, OwnSource, ExplicitUseStrict, SelfHosted, HasSingleton, TreatAsRunOnce, HasLazyScript, HasNonSyntacticScope, HasInnerFunctions, @@ -424,16 +425,18 @@ js::XDRScript(XDRState<mode>* xdr, Handl if (!enclosingScript || enclosingScript->scriptSource() != script->scriptSource()) scriptBits |= (1 << OwnSource); if (script->isGeneratorExp()) scriptBits |= (1 << IsGeneratorExp); if (script->isLegacyGenerator()) scriptBits |= (1 << IsLegacyGenerator); if (script->isStarGenerator()) scriptBits |= (1 << IsStarGenerator); + if (script->asyncKind() == AsyncFunction) + scriptBits |= (1 << IsAsync); if (script->hasSingletons()) scriptBits |= (1 << HasSingleton); if (script->treatAsRunOnce()) scriptBits |= (1 << TreatAsRunOnce); if (script->isRelazifiable()) scriptBits |= (1 << HasLazyScript); if (script->hasNonSyntacticScope()) scriptBits |= (1 << HasNonSyntacticScope); @@ -572,16 +575,19 @@ js::XDRScript(XDRState<mode>* xdr, Handl if (scriptBits & (1 << IsDefaultClassConstructor)) script->isDefaultClassConstructor_ = true; if (scriptBits & (1 << IsLegacyGenerator)) { MOZ_ASSERT(!(scriptBits & (1 << IsStarGenerator))); script->setGeneratorKind(LegacyGenerator); } else if (scriptBits & (1 << IsStarGenerator)) script->setGeneratorKind(StarGenerator); + + if (scriptBits & (1 << IsAsync)) + script->setAsyncKind(AsyncFunction); } JS_STATIC_ASSERT(sizeof(jsbytecode) == 1); JS_STATIC_ASSERT(sizeof(jssrcnote) == 1); if (scriptBits & (1 << OwnSource)) { if (!script->scriptSource()->performXDR<mode>(xdr)) return false;
new file mode 100644 --- /dev/null +++ b/js/src/tests/ecma_6/Destructuring/iterator-primitive.js @@ -0,0 +1,36 @@ +var BUGNUMBER = 1021835; +var summary = "Returning non-object from @@iterator should throw"; + +print(BUGNUMBER + ": " + summary); + +let primitives = [ + 1, + true, + undefined, + null, + "foo", + Symbol.iterator +]; + +function f([]) { +} + +for (let primitive of primitives) { + let obj = { + [Symbol.iterator]() { + return primitive; + } + }; + assertThrowsInstanceOf(() => { + let [] = obj; + }, TypeError); + assertThrowsInstanceOf(() => { + [] = obj; + }, TypeError); + assertThrowsInstanceOf(() => { + f(obj); + }, TypeError); +} + +if (typeof reportCompare === "function") + reportCompare(0, 0);
new file mode 100644 --- /dev/null +++ b/js/src/tests/ecma_6/Function/spread-iterator-primitive.js @@ -0,0 +1,28 @@ +var BUGNUMBER = 1021835; +var summary = "Returning non-object from @@iterator should throw"; + +print(BUGNUMBER + ": " + summary); + +let primitives = [ + 1, + true, + undefined, + null, + "foo", + Symbol.iterator +]; + +function f() { +} + +for (let primitive of primitives) { + let arg = { + [Symbol.iterator]() { + return primitive; + } + }; + assertThrowsInstanceOf(() => f(...arg), TypeError); +} + +if (typeof reportCompare === "function") + reportCompare(0, 0);
new file mode 100644 --- /dev/null +++ b/js/src/tests/ecma_6/Generators/yield-star-iterator-primitive.js @@ -0,0 +1,31 @@ +var BUGNUMBER = 1021835; +var summary = "Returning non-object from @@iterator should throw"; + +print(BUGNUMBER + ": " + summary); + +let primitives = [ + 1, + true, + undefined, + null, + "foo", + Symbol.iterator +]; + +for (let primitive of primitives) { + let obj = { + [Symbol.iterator]() { + return primitive; + } + }; + assertThrowsInstanceOf(() => { + function* g() { + yield* obj; + } + for (let x of g()) { + } + }, TypeError); +} + +if (typeof reportCompare === "function") + reportCompare(0, 0);
new file mode 100644 --- /dev/null +++ b/js/src/tests/ecma_6/Map/constructor-iterator-primitive.js @@ -0,0 +1,34 @@ +var BUGNUMBER = 1021835; +var summary = "Returning non-object from @@iterator should throw"; + +print(BUGNUMBER + ": " + summary); + +let ctors = [ + Map, + Set, + WeakMap, + WeakSet +]; + +let primitives = [ + 1, + true, + undefined, + null, + "foo", + Symbol.iterator +]; + +for (let ctor of ctors) { + for (let primitive of primitives) { + let arg = { + [Symbol.iterator]() { + return primitive; + } + }; + assertThrowsInstanceOf(() => new ctor(arg), TypeError); + } +} + +if (typeof reportCompare === "function") + reportCompare(0, 0);
new file mode 100644 --- /dev/null +++ b/js/src/tests/ecma_6/Promise/iterator-primitive.js @@ -0,0 +1,28 @@ +// |reftest| skip-if(!xulRuntime.shell) -- needs drainJobQueue + +var BUGNUMBER = 1021835; +var summary = "Returning non-object from @@iterator should throw"; + +print(BUGNUMBER + ": " + summary); + +let primitives = [ + 1, + true, + undefined, + null, + "foo", + Symbol.iterator +]; + +for (let primitive of primitives) { + let arg = { + [Symbol.iterator]() { + return primitive; + } + }; + assertEventuallyThrows(Promise.all(arg), TypeError); + assertEventuallyThrows(Promise.race(arg), TypeError); +} + +if (typeof reportCompare === "function") + reportCompare(0, 0);
new file mode 100644 --- /dev/null +++ b/js/src/tests/ecma_6/Statements/for-of-iterator-primitive.js @@ -0,0 +1,28 @@ +var BUGNUMBER = 1021835; +var summary = "Returning non-object from @@iterator should throw"; + +print(BUGNUMBER + ": " + summary); + +let primitives = [ + 1, + true, + undefined, + null, + "foo", + Symbol.iterator +]; + +for (let primitive of primitives) { + let obj = { + [Symbol.iterator]() { + return primitive; + } + }; + assertThrowsInstanceOf(() => { + for (let x of obj) { + } + }, TypeError); +} + +if (typeof reportCompare === "function") + reportCompare(0, 0);
new file mode 100644 --- /dev/null +++ b/js/src/tests/ecma_6/TypedArray/constructor-iterator-primitive.js @@ -0,0 +1,29 @@ +var BUGNUMBER = 1021835; +var summary = "Returning non-object from @@iterator should throw"; + +print(BUGNUMBER + ": " + summary); + +let primitives = [ + 1, + true, + undefined, + null, + "foo", + Symbol.iterator +]; + +for (let ctor of typedArrayConstructors) { + for (let primitive of primitives) { + let arg = { + [Symbol.iterator]() { + return primitive; + } + }; + assertThrowsInstanceOf(() => { + new ctor(arg); + }, TypeError); + } +} + +if (typeof reportCompare === "function") + reportCompare(0, 0);
new file mode 100644 --- /dev/null +++ b/js/src/tests/ecma_7/AsyncFunctions/clone.js @@ -0,0 +1,7 @@ +// |reftest| skip-if(!xulRuntime.shell) -- needs clone + +// Async function cannot be cloned. +assertThrowsInstanceOf(() => clone(async function f() {}), TypeError); + +if (typeof reportCompare === "function") + reportCompare(true, true);
--- a/js/src/tests/ecma_7/AsyncFunctions/shell.js +++ b/js/src/tests/ecma_7/AsyncFunctions/shell.js @@ -1,26 +0,0 @@ -(function(global) { - function getPromiseResult(promise) { - var result, error, caught = false; - promise.then(r => { result = r; }, - e => { caught = true; error = e; }); - drainJobQueue(); - if (caught) - throw error; - return result; - } - - function assertEventuallyEq(promise, expected) { - assertEq(getPromiseResult(promise), expected); - } - global.assertEventuallyEq = assertEventuallyEq; - - function assertEventuallyThrows(promise, expectedErrorType) { - assertThrowsInstanceOf(() => getPromiseResult(promise), expectedErrorType); - }; - global.assertEventuallyThrows = assertEventuallyThrows; - - function assertEventuallyDeepEq(promise, expected) { - assertDeepEq(getPromiseResult(promise), expected); - }; - global.assertEventuallyDeepEq = assertEventuallyDeepEq; -})(this);
--- a/js/src/tests/shell.js +++ b/js/src/tests/shell.js @@ -319,16 +319,42 @@ function OptLevel(i) { i = Number(i); var cx = GetContext(); cx.setOptimizationLevel(i); } global.OptLevel = OptLevel; })(this); +(function(global) { + function getPromiseResult(promise) { + var result, error, caught = false; + promise.then(r => { result = r; }, + e => { caught = true; error = e; }); + drainJobQueue(); + if (caught) + throw error; + return result; + } + + function assertEventuallyEq(promise, expected) { + assertEq(getPromiseResult(promise), expected); + } + global.assertEventuallyEq = assertEventuallyEq; + + function assertEventuallyThrows(promise, expectedErrorType) { + assertThrowsInstanceOf(() => getPromiseResult(promise), expectedErrorType); + }; + global.assertEventuallyThrows = assertEventuallyThrows; + + function assertEventuallyDeepEq(promise, expected) { + assertDeepEq(getPromiseResult(promise), expected); + }; + global.assertEventuallyDeepEq = assertEventuallyDeepEq; +})(this); var STATUS = "STATUS: "; var gDelayTestDriverEnd = false; var gTestcases = new Array(); var gTc = gTestcases.length; var summary = '';
--- a/js/src/vm/ArrayBufferObject.cpp +++ b/js/src/vm/ArrayBufferObject.cpp @@ -39,16 +39,17 @@ #include "gc/Barrier.h" #include "gc/Marking.h" #include "gc/Memory.h" #include "js/Conversions.h" #include "js/MemoryMetrics.h" #include "vm/GlobalObject.h" #include "vm/Interpreter.h" +#include "vm/SelfHosting.h" #include "vm/SharedArrayObject.h" #include "vm/WrapperObject.h" #include "wasm/WasmSignalHandlers.h" #include "wasm/WasmTypes.h" #include "jsatominlines.h" #include "vm/NativeObject-inl.h" @@ -82,16 +83,35 @@ js::ToClampedIndex(JSContext* cx, Handle result = 0; } else if (uint32_t(result) > length) { result = length; } *out = uint32_t(result); return true; } +static bool +arraybuffer_static_slice(JSContext* cx, unsigned argc, Value* vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + + if (args.length() < 1) { + ReportMissingArg(cx, args.calleev(), 1); + return false; + } + + if (!GlobalObject::warnOnceAboutArrayBufferSlice(cx, cx->global())) + return false; + + FixedInvokeArgs<2> args2(cx); + args2[0].set(args.get(1)); + args2[1].set(args.get(2)); + return CallSelfHostedFunction(cx, "ArrayBufferSlice", args[0], args2, args.rval()); +} + /* * ArrayBufferObject * * This class holds the underlying raw buffer that the TypedArrayObject classes * access. It can be created explicitly and passed to a TypedArrayObject, or * can be created implicitly by constructing a TypedArrayObject with a size. */ @@ -135,17 +155,17 @@ static const ClassOps ArrayBufferObjectC nullptr, /* call */ nullptr, /* hasInstance */ nullptr, /* construct */ ArrayBufferObject::trace, }; static const JSFunctionSpec static_functions[] = { JS_FN("isView", ArrayBufferObject::fun_isView, 1, 0), - JS_SELF_HOSTED_FN("slice", "ArrayBufferStaticSlice", 3, 0), + JS_FN("slice", arraybuffer_static_slice, 3, 0), JS_FS_END }; static const JSPropertySpec static_properties[] = { JS_SELF_HOSTED_SYM_GET(species, "ArrayBufferSpecies", 0), JS_PS_END };
--- a/js/src/vm/ForOfIterator.cpp +++ b/js/src/vm/ForOfIterator.cpp @@ -69,20 +69,20 @@ ForOfIterator::init(HandleValue iterable JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_NOT_ITERABLE, bytes.get()); return false; } RootedValue res(cx); if (!js::Call(cx, callee, iterable, &res)) return false; - iterator = ToObject(cx, res); - if (!iterator) - return false; + if (!res.isObject()) + return ThrowCheckIsObject(cx, CheckIsObjectKind::GetIterator); + iterator = &res.toObject(); return true; } inline bool ForOfIterator::nextFromOptimizedArray(MutableHandleValue vp, bool* done) { MOZ_ASSERT(index != NOT_ARRAY);
--- a/js/src/vm/GlobalObject.cpp +++ b/js/src/vm/GlobalObject.cpp @@ -94,17 +94,17 @@ js::GlobalObject::getTypedObjectModule() MOZ_ASSERT(v.isObject()); return v.toObject().as<TypedObjectModuleObject>(); } /* static */ bool GlobalObject::skipDeselectedConstructor(JSContext* cx, JSProtoKey key) { if (key == JSProto_WebAssembly) - return !wasm::HasCompilerSupport(cx); + return !wasm::HasSupport(cx); #ifdef ENABLE_SHARED_ARRAY_BUFFER // Return true if the given constructor has been disabled at run-time. switch (key) { case JSProto_Atomics: case JSProto_SharedArrayBuffer: return !cx->compartment()->creationOptions().getSharedMemoryAndAtomicsEnabled(); default:
--- a/js/src/vm/GlobalObject.h +++ b/js/src/vm/GlobalObject.h @@ -125,16 +125,17 @@ class GlobalObject : public NativeObject * we won't expose GlobalObject, so just assert that the two values are * synchronized. */ static_assert(JSCLASS_GLOBAL_SLOT_COUNT == RESERVED_SLOTS, "global object slot counts are inconsistent"); enum WarnOnceFlag : int32_t { WARN_WATCH_DEPRECATED = 1 << 0, + WARN_ARRAYBUFFER_SLICE_DEPRECATED = 1 << 1, }; // Emit the specified warning if the given slot in |obj|'s global isn't // true, then set the slot to true. Thus calling this method warns once // for each global object it's called on, and every other call does // nothing. static bool warnOnceAbout(JSContext* cx, HandleObject obj, WarnOnceFlag flag, unsigned errorNumber); @@ -720,16 +721,22 @@ class GlobalObject : public NativeObject // in which |obj| was created, if no prior warning was given. static bool warnOnceAboutWatch(JSContext* cx, HandleObject obj) { // Temporarily disabled until we've provided a watch/unwatch workaround for // debuggers like Firebug (bug 934669). //return warnOnceAbout(cx, obj, WARN_WATCH_DEPRECATED, JSMSG_OBJECT_WATCH_DEPRECATED); return true; } + // Warn about use of the deprecated (static) ArrayBuffer.slice method. + static bool warnOnceAboutArrayBufferSlice(JSContext* cx, HandleObject obj) { + return warnOnceAbout(cx, obj, WARN_ARRAYBUFFER_SLICE_DEPRECATED, + JSMSG_ARRAYBUFFER_SLICE_DEPRECATED); + } + static bool getOrCreateEval(JSContext* cx, Handle<GlobalObject*> global, MutableHandleObject eval); // Infallibly test whether the given value is the eval function for this global. bool valueIsEval(const Value& val); // Implemented in jsiter.cpp. static bool initIteratorProto(JSContext* cx, Handle<GlobalObject*> global);
--- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -5028,16 +5028,19 @@ js::ReportRuntimeRedeclaration(JSContext bool js::ThrowCheckIsObject(JSContext* cx, CheckIsObjectKind kind) { switch (kind) { case CheckIsObjectKind::IteratorNext: JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NEXT_RETURNED_PRIMITIVE); break; + case CheckIsObjectKind::GetIterator: + JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_GET_ITER_RETURNED_PRIMITIVE); + break; default: MOZ_CRASH("Unknown kind"); } return false; } bool js::ThrowUninitializedThis(JSContext* cx, AbstractFramePtr frame)
--- a/js/src/vm/Interpreter.h +++ b/js/src/vm/Interpreter.h @@ -556,17 +556,18 @@ ReportRuntimeLexicalError(JSContext* cx, // The parser only reports redeclarations that occurs within a single // script. Due to the extensibility of the global lexical scope, we also check // for redeclarations during runtime in JSOP_DEF{VAR,LET,CONST}. void ReportRuntimeRedeclaration(JSContext* cx, HandlePropertyName name, const char* redeclKind); enum class CheckIsObjectKind : uint8_t { - IteratorNext + IteratorNext, + GetIterator }; bool ThrowCheckIsObject(JSContext* cx, CheckIsObjectKind kind); bool ThrowUninitializedThis(JSContext* cx, AbstractFramePtr frame);
--- a/js/src/wasm/AsmJS.cpp +++ b/js/src/wasm/AsmJS.cpp @@ -2727,116 +2727,116 @@ IsLiteralInt(ModuleValidator& m, ParseNo return IsNumericLiteral(m, pn) && IsLiteralInt(ExtractNumericLiteral(m, pn), u32); } /*****************************************************************************/ namespace { -#define CASE(TYPE, OP) case SimdOperation::Fn_##OP: return Expr::TYPE##OP; +#define CASE(TYPE, OP) case SimdOperation::Fn_##OP: return Op::TYPE##OP; #define I8x16CASE(OP) CASE(I8x16, OP) #define I16x8CASE(OP) CASE(I16x8, OP) #define I32x4CASE(OP) CASE(I32x4, OP) #define F32x4CASE(OP) CASE(F32x4, OP) #define B8x16CASE(OP) CASE(B8x16, OP) #define B16x8CASE(OP) CASE(B16x8, OP) #define B32x4CASE(OP) CASE(B32x4, OP) #define ENUMERATE(TYPE, FOR_ALL, DO) \ switch(op) { \ - case SimdOperation::Constructor: return Expr::TYPE##Constructor; \ + case SimdOperation::Constructor: return Op::TYPE##Constructor; \ FOR_ALL(DO) \ default: break; \ } -static inline Expr -SimdToExpr(SimdType type, SimdOperation op) +static inline Op +SimdToOp(SimdType type, SimdOperation op) { switch (type) { case SimdType::Uint8x16: // Handle the special unsigned opcodes, then fall through to Int8x16. switch (op) { - case SimdOperation::Fn_addSaturate: return Expr::I8x16addSaturateU; - case SimdOperation::Fn_subSaturate: return Expr::I8x16subSaturateU; - case SimdOperation::Fn_extractLane: return Expr::I8x16extractLaneU; - case SimdOperation::Fn_shiftRightByScalar: return Expr::I8x16shiftRightByScalarU; - case SimdOperation::Fn_lessThan: return Expr::I8x16lessThanU; - case SimdOperation::Fn_lessThanOrEqual: return Expr::I8x16lessThanOrEqualU; - case SimdOperation::Fn_greaterThan: return Expr::I8x16greaterThanU; - case SimdOperation::Fn_greaterThanOrEqual: return Expr::I8x16greaterThanOrEqualU; - case SimdOperation::Fn_fromInt8x16Bits: return Expr::Limit; + case SimdOperation::Fn_addSaturate: return Op::I8x16addSaturateU; + case SimdOperation::Fn_subSaturate: return Op::I8x16subSaturateU; + case SimdOperation::Fn_extractLane: return Op::I8x16extractLaneU; + case SimdOperation::Fn_shiftRightByScalar: return Op::I8x16shiftRightByScalarU; + case SimdOperation::Fn_lessThan: return Op::I8x16lessThanU; + case SimdOperation::Fn_lessThanOrEqual: return Op::I8x16lessThanOrEqualU; + case SimdOperation::Fn_greaterThan: return Op::I8x16greaterThanU; + case SimdOperation::Fn_greaterThanOrEqual: return Op::I8x16greaterThanOrEqualU; + case SimdOperation::Fn_fromInt8x16Bits: return Op::Limit; default: break; } MOZ_FALLTHROUGH; case SimdType::Int8x16: // Bitcasts Uint8x16 <--> Int8x16 become noops. switch (op) { - case SimdOperation::Fn_fromUint8x16Bits: return Expr::Limit; - case SimdOperation::Fn_fromUint16x8Bits: return Expr::I8x16fromInt16x8Bits; - case SimdOperation::Fn_fromUint32x4Bits: return Expr::I8x16fromInt32x4Bits; + case SimdOperation::Fn_fromUint8x16Bits: return Op::Limit; + case SimdOperation::Fn_fromUint16x8Bits: return Op::I8x16fromInt16x8Bits; + case SimdOperation::Fn_fromUint32x4Bits: return Op::I8x16fromInt32x4Bits; default: break; } ENUMERATE(I8x16, FORALL_INT8X16_ASMJS_OP, I8x16CASE) break; case SimdType::Uint16x8: // Handle the special unsigned opcodes, then fall through to Int16x8. switch(op) { - case SimdOperation::Fn_addSaturate: return Expr::I16x8addSaturateU; - case SimdOperation::Fn_subSaturate: return Expr::I16x8subSaturateU; - case SimdOperation::Fn_extractLane: return Expr::I16x8extractLaneU; - case SimdOperation::Fn_shiftRightByScalar: return Expr::I16x8shiftRightByScalarU; - case SimdOperation::Fn_lessThan: return Expr::I16x8lessThanU; - case SimdOperation::Fn_lessThanOrEqual: return Expr::I16x8lessThanOrEqualU; - case SimdOperation::Fn_greaterThan: return Expr::I16x8greaterThanU; - case SimdOperation::Fn_greaterThanOrEqual: return Expr::I16x8greaterThanOrEqualU; - case SimdOperation::Fn_fromInt16x8Bits: return Expr::Limit; + case SimdOperation::Fn_addSaturate: return Op::I16x8addSaturateU; + case SimdOperation::Fn_subSaturate: return Op::I16x8subSaturateU; + case SimdOperation::Fn_extractLane: return Op::I16x8extractLaneU; + case SimdOperation::Fn_shiftRightByScalar: return Op::I16x8shiftRightByScalarU; + case SimdOperation::Fn_lessThan: return Op::I16x8lessThanU; + case SimdOperation::Fn_lessThanOrEqual: return Op::I16x8lessThanOrEqualU; + case SimdOperation::Fn_greaterThan: return Op::I16x8greaterThanU; + case SimdOperation::Fn_greaterThanOrEqual: return Op::I16x8greaterThanOrEqualU; + case SimdOperation::Fn_fromInt16x8Bits: return Op::Limit; default: break; } MOZ_FALLTHROUGH; case SimdType::Int16x8: // Bitcasts Uint16x8 <--> Int16x8 become noops. switch (op) { - case SimdOperation::Fn_fromUint8x16Bits: return Expr::I16x8fromInt8x16Bits; - case SimdOperation::Fn_fromUint16x8Bits: return Expr::Limit; - case SimdOperation::Fn_fromUint32x4Bits: return Expr::I16x8fromInt32x4Bits; + case SimdOperation::Fn_fromUint8x16Bits: return Op::I16x8fromInt8x16Bits; + case SimdOperation::Fn_fromUint16x8Bits: return Op::Limit; + case SimdOperation::Fn_fromUint32x4Bits: return Op::I16x8fromInt32x4Bits; default: break; } ENUMERATE(I16x8, FORALL_INT16X8_ASMJS_OP, I16x8CASE) break; case SimdType::Uint32x4: // Handle the special unsigned opcodes, then fall through to Int32x4. switch(op) { - case SimdOperation::Fn_shiftRightByScalar: return Expr::I32x4shiftRightByScalarU; - case SimdOperation::Fn_lessThan: return Expr::I32x4lessThanU; - case SimdOperation::Fn_lessThanOrEqual: return Expr::I32x4lessThanOrEqualU; - case SimdOperation::Fn_greaterThan: return Expr::I32x4greaterThanU; - case SimdOperation::Fn_greaterThanOrEqual: return Expr::I32x4greaterThanOrEqualU; - case SimdOperation::Fn_fromFloat32x4: return Expr::I32x4fromFloat32x4U; - case SimdOperation::Fn_fromInt32x4Bits: return Expr::Limit; + case SimdOperation::Fn_shiftRightByScalar: return Op::I32x4shiftRightByScalarU; + case SimdOperation::Fn_lessThan: return Op::I32x4lessThanU; + case SimdOperation::Fn_lessThanOrEqual: return Op::I32x4lessThanOrEqualU; + case SimdOperation::Fn_greaterThan: return Op::I32x4greaterThanU; + case SimdOperation::Fn_greaterThanOrEqual: return Op::I32x4greaterThanOrEqualU; + case SimdOperation::Fn_fromFloat32x4: return Op::I32x4fromFloat32x4U; + case SimdOperation::Fn_fromInt32x4Bits: return Op::Limit; default: break; } MOZ_FALLTHROUGH; case SimdType::Int32x4: // Bitcasts Uint32x4 <--> Int32x4 become noops. switch (op) { - case SimdOperation::Fn_fromUint8x16Bits: return Expr::I32x4fromInt8x16Bits; - case SimdOperation::Fn_fromUint16x8Bits: return Expr::I32x4fromInt16x8Bits; - case SimdOperation::Fn_fromUint32x4Bits: return Expr::Limit; + case SimdOperation::Fn_fromUint8x16Bits: return Op::I32x4fromInt8x16Bits; + case SimdOperation::Fn_fromUint16x8Bits: return Op::I32x4fromInt16x8Bits; + case SimdOperation::Fn_fromUint32x4Bits: return Op::Limit; default: break; } ENUMERATE(I32x4, FORALL_INT32X4_ASMJS_OP, I32x4CASE) break; case SimdType::Float32x4: switch (op) { - case SimdOperation::Fn_fromUint8x16Bits: return Expr::F32x4fromInt8x16Bits; - case SimdOperation::Fn_fromUint16x8Bits: return Expr::F32x4fromInt16x8Bits; - case SimdOperation::Fn_fromUint32x4Bits: return Expr::F32x4fromInt32x4Bits; + case SimdOperation::Fn_fromUint8x16Bits: return Op::F32x4fromInt8x16Bits; + case SimdOperation::Fn_fromUint16x8Bits: return Op::F32x4fromInt16x8Bits; + case SimdOperation::Fn_fromUint32x4Bits: return Op::F32x4fromInt32x4Bits; default: break; } ENUMERATE(F32x4, FORALL_FLOAT32X4_ASMJS_OP, F32x4CASE) break; case SimdType::Bool8x16: ENUMERATE(B8x16, FORALL_BOOL_SIMD_OP, B8x16CASE) break; @@ -2993,116 +2993,116 @@ class MOZ_STACK_CLASS FunctionValidator void setReturnedType(ExprType ret) { ret_ = ret; hasAlreadyReturned_ = true; } /**************************************************************** Labels */ private: - bool writeBr(uint32_t absolute, Expr expr = Expr::Br) { - MOZ_ASSERT(expr == Expr::Br || expr == Expr::BrIf); + bool writeBr(uint32_t absolute, Op op = Op::Br) { + MOZ_ASSERT(op == Op::Br || op == Op::BrIf); MOZ_ASSERT(absolute < blockDepth_); - return encoder().writeExpr(expr) && + return encoder().writeOp(op) && encoder().writeVarU32(blockDepth_ - 1 - absolute); } void removeLabel(PropertyName* label, LabelMap* map) { LabelMap::Ptr p = map->lookup(label); MOZ_ASSERT(p); map->remove(p); } public: bool pushBreakableBlock() { - return encoder().writeExpr(Expr::Block) && + return encoder().writeOp(Op::Block) && encoder().writeFixedU8(uint8_t(ExprType::Void)) && breakableStack_.append(blockDepth_++); } bool popBreakableBlock() { JS_ALWAYS_TRUE(breakableStack_.popCopy() == --blockDepth_); - return encoder().writeExpr(Expr::End); + return encoder().writeOp(Op::End); } bool pushUnbreakableBlock(const NameVector* labels = nullptr) { if (labels) { for (PropertyName* label : *labels) { if (!breakLabels_.putNew(label, blockDepth_)) return false; } } blockDepth_++; - return encoder().writeExpr(Expr::Block) && + return encoder().writeOp(Op::Block) && encoder().writeFixedU8(uint8_t(ExprType::Void)); } bool popUnbreakableBlock(const NameVector* labels = nullptr) { if (labels) { for (PropertyName* label : *labels) removeLabel(label, &breakLabels_); } --blockDepth_; - return encoder().writeExpr(Expr::End); + return encoder().writeOp(Op::End); } bool pushContinuableBlock() { - return encoder().writeExpr(Expr::Block) && + return encoder().writeOp(Op::Block) && encoder().writeFixedU8(uint8_t(ExprType::Void)) && continuableStack_.append(blockDepth_++); } bool popContinuableBlock() { JS_ALWAYS_TRUE(continuableStack_.popCopy() == --blockDepth_); - return encoder().writeExpr(Expr::End); + return encoder().writeOp(Op::End); } bool pushLoop() { - return encoder().writeExpr(Expr::Block) && + return encoder().writeOp(Op::Block) && encoder().writeFixedU8(uint8_t(ExprType::Void)) && - encoder().writeExpr(Expr::Loop) && + encoder().writeOp(Op::Loop) && encoder().writeFixedU8(uint8_t(ExprType::Void)) && breakableStack_.append(blockDepth_++) && continuableStack_.append(blockDepth_++); } bool popLoop() { JS_ALWAYS_TRUE(continuableStack_.popCopy() == --blockDepth_); JS_ALWAYS_TRUE(breakableStack_.popCopy() == --blockDepth_); - return encoder().writeExpr(Expr::End) && - encoder().writeExpr(Expr::End); + return encoder().writeOp(Op::End) && + encoder().writeOp(Op::End); } bool pushIf(size_t* typeAt) { ++blockDepth_; - return encoder().writeExpr(Expr::If) && + return encoder().writeOp(Op::If) && encoder().writePatchableFixedU7(typeAt); } bool switchToElse() { MOZ_ASSERT(blockDepth_ > 0); - return encoder().writeExpr(Expr::Else); + return encoder().writeOp(Op::Else); } void setIfType(size_t typeAt, ExprType type) { encoder().patchFixedU7(typeAt, uint8_t(type)); } bool popIf() { MOZ_ASSERT(blockDepth_ > 0); --blockDepth_; - return encoder().writeExpr(Expr::End); + return encoder().writeOp(Op::End); } bool popIf(size_t typeAt, ExprType type) { MOZ_ASSERT(blockDepth_ > 0); --blockDepth_; - if (!encoder().writeExpr(Expr::End)) + if (!encoder().writeOp(Op::End)) return false; setIfType(typeAt, type); return true; } bool writeBreakIf() { - return writeBr(breakableStack_.back(), Expr::BrIf); + return writeBr(breakableStack_.back(), Op::BrIf); } bool writeContinueIf() { - return writeBr(continuableStack_.back(), Expr::BrIf); + return writeBr(continuableStack_.back(), Op::BrIf); } bool writeUnlabeledBreakOrContinue(bool isBreak) { return writeBr(isBreak? breakableStack_.back() : continuableStack_.back()); } bool writeContinue() { return writeBr(continuableStack_.back()); } @@ -3146,75 +3146,75 @@ class MOZ_STACK_CLASS FunctionValidator size_t numLocals() const { return locals_.count(); } /**************************************************** Encoding interface */ Encoder& encoder() { return *encoder_; } MOZ_MUST_USE bool writeInt32Lit(int32_t i32) { - return encoder().writeExpr(Expr::I32Const) && + return encoder().writeOp(Op::I32Const) && encoder().writeVarS32(i32); } MOZ_MUST_USE bool writeConstExpr(const NumLit& lit) { switch (lit.which()) { case NumLit::Fixnum: case NumLit::NegativeInt: case NumLit::BigUnsigned: return writeInt32Lit(lit.toInt32()); case NumLit::Float: - return encoder().writeExpr(Expr::F32Const) && + return encoder().writeOp(Op::F32Const) && encoder().writeFixedF32(lit.toFloat()); case NumLit::Double: - return encoder().writeExpr(Expr::F64Const) && + return encoder().writeOp(Op::F64Const) && encoder().writeFixedF64(lit.toDouble()); case NumLit::Int8x16: case NumLit::Uint8x16: - return encoder().writeExpr(Expr::I8x16Const) && + return encoder().writeOp(Op::I8x16Const) && encoder().writeFixedI8x16(lit.simdValue().asInt8x16()); case NumLit::Int16x8: case NumLit::Uint16x8: - return encoder().writeExpr(Expr::I16x8Const) && + return encoder().writeOp(Op::I16x8Const) && encoder().writeFixedI16x8(lit.simdValue().asInt16x8()); case NumLit::Int32x4: case NumLit::Uint32x4: - return encoder().writeExpr(Expr::I32x4Const) && + return encoder().writeOp(Op::I32x4Const) && encoder().writeFixedI32x4(lit.simdValue().asInt32x4()); case NumLit::Float32x4: - return encoder().writeExpr(Expr::F32x4Const) && + return encoder().writeOp(Op::F32x4Const) && encoder().writeFixedF32x4(lit.simdValue().asFloat32x4()); case NumLit::Bool8x16: // Boolean vectors use the Int8x16 memory representation. - return encoder().writeExpr(Expr::B8x16Const) && + return encoder().writeOp(Op::B8x16Const) && encoder().writeFixedI8x16(lit.simdValue().asInt8x16()); case NumLit::Bool16x8: // Boolean vectors use the Int16x8 memory representation. - return encoder().writeExpr(Expr::B16x8Const) && + return encoder().writeOp(Op::B16x8Const) && encoder().writeFixedI16x8(lit.simdValue().asInt16x8()); case NumLit::Bool32x4: // Boolean vectors use the Int32x4 memory representation. - return encoder().writeExpr(Expr::B32x4Const) && + return encoder().writeOp(Op::B32x4Const) && encoder().writeFixedI32x4(lit.simdValue().asInt32x4()); case NumLit::OutOfRangeInt: break; } MOZ_CRASH("unexpected literal type"); } - MOZ_MUST_USE bool writeCall(ParseNode* pn, Expr op) { - return encoder().writeExpr(op) && + MOZ_MUST_USE bool writeCall(ParseNode* pn, Op op) { + return encoder().writeOp(op) && fg_.addCallSiteLineNum(m().tokenStream().srcCoords.lineNum(pn->pn_pos.begin)); } MOZ_MUST_USE bool prepareCall(ParseNode* pn) { return fg_.addCallSiteLineNum(m().tokenStream().srcCoords.lineNum(pn->pn_pos.begin)); } - MOZ_MUST_USE bool writeSimdOp(SimdType simdType, SimdOperation op) { - Expr expr = SimdToExpr(simdType, op); - if (expr == Expr::Limit) + MOZ_MUST_USE bool writeSimdOp(SimdType simdType, SimdOperation simdOp) { + Op op = SimdToOp(simdType, simdOp); + if (op == Op::Limit) return true; - return encoder().writeExpr(expr); + return encoder().writeOp(op); } }; } /* anonymous namespace */ /*****************************************************************************/ // asm.js type-checking and code-generation algorithm @@ -3873,17 +3873,17 @@ IsLiteralOrConst(FunctionValidator& f, P *lit = ExtractNumericLiteral(f.m(), pn); return true; } static bool CheckFinalReturn(FunctionValidator& f, ParseNode* lastNonEmptyStmt) { - if (!f.encoder().writeExpr(Expr::End)) + if (!f.encoder().writeOp(Op::End)) return false; if (!f.hasAlreadyReturned()) { f.setReturnedType(ExprType::Void); return true; } if (!lastNonEmptyStmt->isKind(PNK_RETURN) && !IsVoid(f.returnedType())) @@ -3944,28 +3944,28 @@ CheckVariables(FunctionValidator& f, Par return false; for (uint32_t i = 0; i < inits.length(); i++) { NumLit lit = inits[i]; if (lit.isZeroBits()) continue; if (!f.writeConstExpr(lit)) return false; - if (!f.encoder().writeExpr(Expr::SetLocal)) + if (!f.encoder().writeOp(Op::SetLocal)) return false; if (!f.encoder().writeVarU32(firstVar + i)) return false; } *stmtIter = stmt; return true; } static bool -CheckExpr(FunctionValidator& f, ParseNode* expr, Type* type); +CheckExpr(FunctionValidator& f, ParseNode* op, Type* type); static bool CheckNumericLiteral(FunctionValidator& f, ParseNode* num, Type* type) { NumLit lit = ExtractNumericLiteral(f.m(), num); if (!lit.valid()) return f.fail(num, "numeric literal out of representable integer range"); *type = Type::lit(lit); @@ -3973,33 +3973,33 @@ CheckNumericLiteral(FunctionValidator& f } static bool CheckVarRef(FunctionValidator& f, ParseNode* varRef, Type* type) { PropertyName* name = varRef->name(); if (const FunctionValidator::Local* local = f.lookupLocal(name)) { - if (!f.encoder().writeExpr(Expr::GetLocal)) + if (!f.encoder().writeOp(Op::GetLocal)) return false; if (!f.encoder().writeVarU32(local->slot)) return false; *type = local->type; return true; } if (const ModuleValidator::Global* global = f.lookupGlobal(name)) { switch (global->which()) { case ModuleValidator::Global::ConstantLiteral: *type = global->varOrConstType(); return f.writeConstExpr(global->constLiteralValue()); case ModuleValidator::Global::ConstantImport: case ModuleValidator::Global::Variable: { *type = global->varOrConstType(); - return f.encoder().writeExpr(Expr::GetGlobal) && + return f.encoder().writeOp(Op::GetGlobal) && f.encoder().writeVarU32(global->varOrConstIndex()); } case ModuleValidator::Global::Function: case ModuleValidator::Global::FFI: case ModuleValidator::Global::MathBuiltinFunction: case ModuleValidator::Global::AtomicsBuiltinFunction: case ModuleValidator::Global::FuncPtrTable: case ModuleValidator::Global::ArrayView: @@ -4097,17 +4097,17 @@ CheckArrayAccess(FunctionValidator& f, P return f.failf(pointerNode, "%s is not a subtype of int", pointerType.toChars()); } } // Don't generate the mask op if there is no need for it which could happen for // a shift of zero or a SIMD access. if (mask != NoMask) { return f.writeInt32Lit(mask) && - f.encoder().writeExpr(Expr::I32And); + f.encoder().writeOp(Op::I32And); } return true; } static bool CheckAndPrepareArrayAccess(FunctionValidator& f, ParseNode* viewName, ParseNode* indexExpr, bool isSimd, Scalar::Type* viewType) @@ -4135,24 +4135,24 @@ static bool CheckLoadArray(FunctionValidator& f, ParseNode* elem, Type* type) { Scalar::Type viewType; if (!CheckAndPrepareArrayAccess(f, ElemBase(elem), ElemIndex(elem), NoSimd, &viewType)) return false; switch (viewType) { - case Scalar::Int8: if (!f.encoder().writeExpr(Expr::I32Load8S)) return false; break; - case Scalar::Uint8: if (!f.encoder().writeExpr(Expr::I32Load8U)) return false; break; - case Scalar::Int16: if (!f.encoder().writeExpr(Expr::I32Load16S)) return false; break; - case Scalar::Uint16: if (!f.encoder().writeExpr(Expr::I32Load16U)) return false; break; + case Scalar::Int8: if (!f.encoder().writeOp(Op::I32Load8S)) return false; break; + case Scalar::Uint8: if (!f.encoder().writeOp(Op::I32Load8U)) return false; break; + case Scalar::Int16: if (!f.encoder().writeOp(Op::I32Load16S)) return false; break; + case Scalar::Uint16: if (!f.encoder().writeOp(Op::I32Load16U)) return false; break; case Scalar::Uint32: - case Scalar::Int32: if (!f.encoder().writeExpr(Expr::I32Load)) return false; break; - case Scalar::Float32: if (!f.encoder().writeExpr(Expr::F32Load)) return false; break; - case Scalar::Float64: if (!f.encoder().writeExpr(Expr::F64Load)) return false; break; + case Scalar::Int32: if (!f.encoder().writeOp(Op::I32Load)) return false; break; + case Scalar::Float32: if (!f.encoder().writeOp(Op::F32Load)) return false; break; + case Scalar::Float64: if (!f.encoder().writeOp(Op::F64Load)) return false; break; default: MOZ_CRASH("unexpected scalar type"); } switch (viewType) { case Scalar::Int8: case Scalar::Int16: case Scalar::Int32: case Scalar::Uint8: @@ -4206,44 +4206,44 @@ CheckStoreArray(FunctionValidator& f, Pa break; default: MOZ_CRASH("Unexpected view type"); } switch (viewType) { case Scalar::Int8: case Scalar::Uint8: - if (!f.encoder().writeExpr(Expr::I32TeeStore8)) + if (!f.encoder().writeOp(Op::I32TeeStore8)) return false; break; case Scalar::Int16: case Scalar::Uint16: - if (!f.encoder().writeExpr(Expr::I32TeeStore16)) + if (!f.encoder().writeOp(Op::I32TeeStore16)) return false; break; case Scalar::Int32: case Scalar::Uint32: - if (!f.encoder().writeExpr(Expr::I32TeeStore)) + if (!f.encoder().writeOp(Op::I32TeeStore)) return false; break; case Scalar::Float32: if (rhsType.isFloatish()) { - if (!f.encoder().writeExpr(Expr::F32TeeStore)) + if (!f.encoder().writeOp(Op::F32TeeStore)) return false; } else { - if (!f.encoder().writeExpr(Expr::F64TeeStoreF32)) + if (!f.encoder().writeOp(Op::F64TeeStoreF32)) return false; } break; case Scalar::Float64: if (rhsType.isFloatish()) { - if (!f.encoder().writeExpr(Expr::F32TeeStoreF64)) + if (!f.encoder().writeOp(Op::F32TeeStoreF64)) return false; } else { - if (!f.encoder().writeExpr(Expr::F64TeeStore)) + if (!f.encoder().writeOp(Op::F64TeeStore)) return false; } break; default: MOZ_CRASH("unexpected scalar type"); } if (!WriteArrayAccessFlags(f, viewType)) return false; @@ -4257,17 +4257,17 @@ CheckAssignName(FunctionValidator& f, Pa { RootedPropertyName name(f.cx(), lhs->name()); if (const FunctionValidator::Local* lhsVar = f.lookupLocal(name)) { Type rhsType; if (!CheckExpr(f, rhs, &rhsType)) return false; - if (!f.encoder().writeExpr(Expr::TeeLocal)) + if (!f.encoder().writeOp(Op::TeeLocal)) return false; if (!f.encoder().writeVarU32(lhsVar->slot)) return false; if (!(rhsType <= lhsVar->type)) { return f.failf(lhs, "%s is not a subtype of %s", rhsType.toChars(), lhsVar->type.toChars()); } @@ -4281,17 +4281,17 @@ CheckAssignName(FunctionValidator& f, Pa Type rhsType; if (!CheckExpr(f, rhs, &rhsType)) return false; Type globType = global->varOrConstType(); if (!(rhsType <= globType)) return f.failf(lhs, "%s is not a subtype of %s", rhsType.toChars(), globType.toChars()); - if (!f.encoder().writeExpr(Expr::TeeGlobal)) + if (!f.encoder().writeOp(Op::TeeGlobal)) return false; if (!f.encoder().writeVarU32(global->varOrConstIndex())) return false; *type = rhsType; return true; } @@ -4333,17 +4333,17 @@ CheckMathIMul(FunctionValidator& f, Pars return false; if (!lhsType.isIntish()) return f.failf(lhs, "%s is not a subtype of intish", lhsType.toChars()); if (!rhsType.isIntish()) return f.failf(rhs, "%s is not a subtype of intish", rhsType.toChars()); *type = Type::Signed; - return f.encoder().writeExpr(Expr::I32Mul); + return f.encoder().writeOp(Op::I32Mul); } static bool CheckMathClz32(FunctionValidator& f, ParseNode* call, Type* type) { if (CallArgListLength(call) != 1) return f.fail(call, "Math.clz32 must be passed 1 argument"); @@ -4352,44 +4352,44 @@ CheckMathClz32(FunctionValidator& f, Par Type argType; if (!CheckExpr(f, arg, &argType)) return false; if (!argType.isIntish()) return f.failf(arg, "%s is not a subtype of intish", argType.toChars()); *type = Type::Fixnum; - return f.encoder().writeExpr(Expr::I32Clz); + return f.encoder().writeOp(Op::I32Clz); } static bool CheckMathAbs(FunctionValidator& f, ParseNode* call, Type* type) { if (CallArgListLength(call) != 1) return f.fail(call, "Math.abs must be passed 1 argument"); ParseNode* arg = CallArgList(call); Type argType; if (!CheckExpr(f, arg, &argType)) return false; if (argType.isSigned()) { *type = Type::Unsigned; - return f.encoder().writeExpr(Expr::I32Abs); + return f.encoder().writeOp(Op::I32Abs); } if (argType.isMaybeDouble()) { *type = Type::Double; - return f.encoder().writeExpr(Expr::F64Abs); + return f.encoder().writeOp(Op::F64Abs); } if (argType.isMaybeFloat()) { *type = Type::Floatish; - return f.encoder().writeExpr(Expr::F32Abs); + return f.encoder().writeOp(Op::F32Abs); } return f.failf(call, "%s is not a subtype of signed, float? or double?", argType.toChars()); } static bool CheckMathSqrt(FunctionValidator& f, ParseNode* call, Type* type) { @@ -4399,66 +4399,66 @@ CheckMathSqrt(FunctionValidator& f, Pars ParseNode* arg = CallArgList(call); Type argType; if (!CheckExpr(f, arg, &argType)) return false; if (argType.isMaybeDouble()) { *type = Type::Double; - return f.encoder().writeExpr(Expr::F64Sqrt); + return f.encoder().writeOp(Op::F64Sqrt); } if (argType.isMaybeFloat()) { *type = Type::Floatish; - return f.encoder().writeExpr(Expr::F32Sqrt); + return f.encoder().writeOp(Op::F32Sqrt); } return f.failf(call, "%s is neither a subtype of double? nor float?", argType.toChars()); } static bool CheckMathMinMax(FunctionValidator& f, ParseNode* callNode, bool isMax, Type* type) { if (CallArgListLength(callNode) < 2) return f.fail(callNode, "Math.min/max must be passed at least 2 arguments"); ParseNode* firstArg = CallArgList(callNode); Type firstType; if (!CheckExpr(f, firstArg, &firstType)) return false; - Expr expr; + Op op; if (firstType.isMaybeDouble()) { *type = Type::Double; firstType = Type::MaybeDouble; - expr = isMax ? Expr::F64Max : Expr::F64Min; + op = isMax ? Op::F64Max : Op::F64Min; } else if (firstType.isMaybeFloat()) { *type = Type::Float; firstType = Type::MaybeFloat; - expr = isMax ? Expr::F32Max : Expr::F32Min; + op = isMax ? Op::F32Max : Op::F32Min; } else if (firstType.isSigned()) { *type = Type::Signed; firstType = Type::Signed; - expr = isMax ? Expr::I32Max : Expr::I32Min; + op = isMax ? Op::I32Max : Op::I32Min; } else { return f.failf(firstArg, "%s is not a subtype of double?, float? or signed", firstType.toChars()); } unsigned numArgs = CallArgListLength(callNode); ParseNode* nextArg = NextNode(firstArg); for (unsigned i = 1; i < numArgs; i++, nextArg = NextNode(nextArg)) { Type nextType; if (!CheckExpr(f, nextArg, &nextType)) return false; if (!(nextType <= firstType)) return f.failf(nextArg, "%s is not a subtype of %s", nextType.toChars(), firstType.toChars()); - if (!f.encoder().writeExpr(expr)) + if (!f.encoder().writeOp(op)) return false; } return true; } static bool CheckSharedArrayAtomicAccess(FunctionValidator& f, ParseNode* viewName, ParseNode* indexExpr, @@ -4485,36 +4485,36 @@ CheckSharedArrayAtomicAccess(FunctionVal default: return f.failf(viewName, "not an integer array"); } return true; } static bool -WriteAtomicOperator(FunctionValidator& f, Expr opcode, Scalar::Type viewType) -{ - return f.encoder().writeExpr(opcode) && +WriteAtomicOperator(FunctionValidator& f, Op opcode, Scalar::Type viewType) +{ + return f.encoder().writeOp(opcode) && f.encoder().writeFixedU8(viewType); } static bool CheckAtomicsLoad(FunctionValidator& f, ParseNode* call, Type* type) { if (CallArgListLength(call) != 2) return f.fail(call, "Atomics.load must be passed 2 arguments"); ParseNode* arrayArg = CallArgList(call); ParseNode* indexArg = NextNode(arrayArg); Scalar::Type viewType; if (!CheckSharedArrayAtomicAccess(f, arrayArg, indexArg, &viewType)) return false; - if (!WriteAtomicOperator(f, Expr::I32AtomicsLoad, viewType)) + if (!WriteAtomicOperator(f, Op::I32AtomicsLoad, viewType)) return false; if (!WriteArrayAccessFlags(f, viewType)) return false; *type = Type::Int; return true; } @@ -4535,17 +4535,17 @@ CheckAtomicsStore(FunctionValidator& f, if (!rhsType.isIntish()) return f.failf(arrayArg, "%s is not a subtype of intish", rhsType.toChars()); Scalar::Type viewType; if (!CheckSharedArrayAtomicAccess(f, arrayArg, indexArg, &viewType)) return false; - if (!WriteAtomicOperator(f, Expr::I32AtomicsStore, viewType)) + if (!WriteAtomicOperator(f, Op::I32AtomicsStore, viewType)) return false; if (!WriteArrayAccessFlags(f, viewType)) return false; *type = rhsType; return true; } @@ -4566,17 +4566,17 @@ CheckAtomicsBinop(FunctionValidator& f, if (!valueArgType.isIntish()) return f.failf(valueArg, "%s is not a subtype of intish", valueArgType.toChars()); Scalar::Type viewType; if (!CheckSharedArrayAtomicAccess(f, arrayArg, indexArg, &viewType)) return false; - if (!WriteAtomicOperator(f, Expr::I32AtomicsBinOp, viewType)) + if (!WriteAtomicOperator(f, Op::I32AtomicsBinOp, viewType)) return false; if (!f.encoder().writeFixedU8(uint8_t(op))) return false; if (!WriteArrayAccessFlags(f, viewType)) return false; *type = Type::Int; @@ -4623,17 +4623,17 @@ CheckAtomicsCompareExchange(FunctionVali if (!newValueArgType.isIntish()) return f.failf(newValueArg, "%s is not a subtype of intish", newValueArgType.toChars()); Scalar::Type viewType; if (!CheckSharedArrayAtomicAccess(f, arrayArg, indexArg, &viewType)) return false; - if (!WriteAtomicOperator(f, Expr::I32AtomicsCompareExchange, viewType)) + if (!WriteAtomicOperator(f, Op::I32AtomicsCompareExchange, viewType)) return false; if (!WriteArrayAccessFlags(f, viewType)) return false; *type = Type::Int; return true; } @@ -4654,17 +4654,17 @@ CheckAtomicsExchange(FunctionValidator& if (!valueArgType.isIntish()) return f.failf(arrayArg, "%s is not a subtype of intish", valueArgType.toChars()); Scalar::Type viewType; if (!CheckSharedArrayAtomicAccess(f, arrayArg, indexArg, &viewType)) return false; - if (!WriteAtomicOperator(f, Expr::I32AtomicsExchange, viewType)) + if (!WriteAtomicOperator(f, Op::I32AtomicsExchange, viewType)) return false; if (!WriteArrayAccessFlags(f, viewType)) return false; *type = Type::Int; return true; } @@ -4787,17 +4787,17 @@ CheckInternalCall(FunctionValidator& f, return false; Sig sig(Move(args), ret.canonicalToExprType()); ModuleValidator::Func* callee; if (!CheckFunctionSignature(f.m(), callNode, Move(sig), calleeName, &callee)) return false; - if (!f.writeCall(callNode, Expr::Call)) + if (!f.writeCall(callNode, Op::Call)) return false; if (!f.encoder().writeVarU32(callee->index())) return false; *type = Type::ret(ret); return true; } @@ -4870,17 +4870,17 @@ CheckFuncPtrCall(FunctionValidator& f, P return false; Sig sig(Move(args), ret.canonicalToExprType()); uint32_t tableIndex; if (!CheckFuncPtrTableAgainstExisting(f.m(), tableNode, name, Move(sig), mask, &tableIndex)) return false; - if (!f.writeCall(callNode, Expr::OldCallIndirect)) + if (!f.writeCall(callNode, Op::OldCallIndirect)) return false; // Call signature if (!f.encoder().writeVarU32(f.m().funcPtrTable(tableIndex).sigIndex())) return false; *type = Type::ret(ret); return true; @@ -4911,35 +4911,35 @@ CheckFFICall(FunctionValidator& f, Parse return false; Sig sig(Move(args), ret.canonicalToExprType()); uint32_t funcIndex; if (!f.m().declareImport(calleeName, Move(sig), ffiIndex, &funcIndex)) return false; - if (!f.writeCall(callNode, Expr::Call)) + if (!f.writeCall(callNode, Op::Call)) return false; if (!f.encoder().writeVarU32(funcIndex)) return false; *type = Type::ret(ret); return true; } static bool CheckFloatCoercionArg(FunctionValidator& f, ParseNode* inputNode, Type inputType) { if (inputType.isMaybeDouble()) - return f.encoder().writeExpr(Expr::F32DemoteF64); + return f.encoder().writeOp(Op::F32DemoteF64); if (inputType.isSigned()) - return f.encoder().writeExpr(Expr::F32ConvertSI32); + return f.encoder().writeOp(Op::F32ConvertSI32); if (inputType.isUnsigned()) - return f.encoder().writeExpr(Expr::F32ConvertUI32); + return f.encoder().writeOp(Op::F32ConvertUI32); if (inputType.isFloatish()) return true; return f.failf(inputNode, "%s is not a subtype of signed, unsigned, double? or floatish", inputType.toChars()); } static bool @@ -4987,38 +4987,38 @@ CheckMathFRound(FunctionValidator& f, Pa return true; } static bool CheckMathBuiltinCall(FunctionValidator& f, ParseNode* callNode, AsmJSMathBuiltinFunction func, Type* type) { unsigned arity = 0; - Expr f32; - Expr f64; + Op f32; + Op f64; switch (func) { case AsmJSMathBuiltin_imul: return CheckMathIMul(f, callNode, type); case AsmJSMathBuiltin_clz32: return CheckMathClz32(f, callNode, type); case AsmJSMathBuiltin_abs: return CheckMathAbs(f, callNode, type); case AsmJSMathBuiltin_sqrt: return CheckMathSqrt(f, callNode, type); case AsmJSMathBuiltin_fround: return CheckMathFRound(f, callNode, type); case AsmJSMathBuiltin_min: return CheckMathMinMax(f, callNode, /* isMax = */ false, type); case AsmJSMathBuiltin_max: return CheckMathMinMax(f, callNode, /* isMax = */ true, type); - case AsmJSMathBuiltin_ceil: arity = 1; f64 = Expr::F64Ceil; f32 = Expr::F32Ceil; break; - case AsmJSMathBuiltin_floor: arity = 1; f64 = Expr::F64Floor; f32 = Expr::F32Floor; break; - case AsmJSMathBuiltin_sin: arity = 1; f64 = Expr::F64Sin; f32 = Expr::Unreachable; break; - case AsmJSMathBuiltin_cos: arity = 1; f64 = Expr::F64Cos; f32 = Expr::Unreachable; break; - case AsmJSMathBuiltin_tan: arity = 1; f64 = Expr::F64Tan; f32 = Expr::Unreachable; break; - case AsmJSMathBuiltin_asin: arity = 1; f64 = Expr::F64Asin; f32 = Expr::Unreachable; break; - case AsmJSMathBuiltin_acos: arity = 1; f64 = Expr::F64Acos; f32 = Expr::Unreachable; break; - case AsmJSMathBuiltin_atan: arity = 1; f64 = Expr::F64Atan; f32 = Expr::Unreachable; break; - case AsmJSMathBuiltin_exp: arity = 1; f64 = Expr::F64Exp; f32 = Expr::Unreachable; break; - case AsmJSMathBuiltin_log: arity = 1; f64 = Expr::F64Log; f32 = Expr::Unreachable; break; - case AsmJSMathBuiltin_pow: arity = 2; f64 = Expr::F64Pow; f32 = Expr::Unreachable; break; - case AsmJSMathBuiltin_atan2: arity = 2; f64 = Expr::F64Atan2; f32 = Expr::Unreachable; break; + case AsmJSMathBuiltin_ceil: arity = 1; f64 = Op::F64Ceil; f32 = Op::F32Ceil; break; + case AsmJSMathBuiltin_floor: arity = 1; f64 = Op::F64Floor; f32 = Op::F32Floor; break; + case AsmJSMathBuiltin_sin: arity = 1; f64 = Op::F64Sin; f32 = Op::Unreachable; break; + case AsmJSMathBuiltin_cos: arity = 1; f64 = Op::F64Cos; f32 = Op::Unreachable; break; + case AsmJSMathBuiltin_tan: arity = 1; f64 = Op::F64Tan; f32 = Op::Unreachable; break; + case AsmJSMathBuiltin_asin: arity = 1; f64 = Op::F64Asin; f32 = Op::Unreachable; break; + case AsmJSMathBuiltin_acos: arity = 1; f64 = Op::F64Acos; f32 = Op::Unreachable; break; + case AsmJSMathBuiltin_atan: arity = 1; f64 = Op::F64Atan; f32 = Op::Unreachable; break; + case AsmJSMathBuiltin_exp: arity = 1; f64 = Op::F64Exp; f32 = Op::Unreachable; break; + case AsmJSMathBuiltin_log: arity = 1; f64 = Op::F64Log; f32 = Op::Unreachable; break; + case AsmJSMathBuiltin_pow: arity = 2; f64 = Op::F64Pow; f32 = Op::Unreachable; break; + case AsmJSMathBuiltin_atan2: arity = 2; f64 = Op::F64Atan2; f32 = Op::Unreachable; break; default: MOZ_CRASH("unexpected mathBuiltin function"); } unsigned actualArity = CallArgListLength(callNode); if (actualArity != arity) return f.failf(callNode, "call passed %u arguments, expected %u", actualArity, arity); if (!f.prepareCall(callNode)) @@ -5028,36 +5028,36 @@ CheckMathBuiltinCall(FunctionValidator& ParseNode* argNode = CallArgList(callNode); if (!CheckExpr(f, argNode, &firstType)) return false; if (!firstType.isMaybeFloat() && !firstType.isMaybeDouble()) return f.fail(argNode, "arguments to math call should be a subtype of double? or float?"); bool opIsDouble = firstType.isMaybeDouble(); - if (!opIsDouble && f32 == Expr::Unreachable) + if (!opIsDouble && f32 == Op::Unreachable) return f.fail(callNode, "math builtin cannot be used as float"); if (arity == 2) { Type secondType; argNode = NextNode(argNode); if (!CheckExpr(f, argNode, &secondType)) return false; if (firstType.isMaybeDouble() && !secondType.isMaybeDouble()) return f.fail(argNode, "both arguments to math builtin call should be the same type"); if (firstType.isMaybeFloat() && !secondType.isMaybeFloat()) return f.fail(argNode, "both arguments to math builtin call should be the same type"); } if (opIsDouble) { - if (!f.encoder().writeExpr(f64)) + if (!f.encoder().writeOp(f64)) return false; } else { - if (!f.encoder().writeExpr(f32)) + if (!f.encoder().writeOp(f32)) return false; } *type = opIsDouble ? Type::Double : Type::Floatish; return true; } namespace { @@ -5142,17 +5142,17 @@ class CheckSimdScalarArgs // re-emitting them as float32 constants. if (simdType_ != SimdType::Float32x4 || !actualType.isDoubleLit()) { return f.failf(arg, "%s is not a subtype of %s%s", actualType.toChars(), formalType_.toChars(), simdType_ == SimdType::Float32x4 ? " or doublelit" : ""); } // We emitted a double literal and actually want a float32. - return f.encoder().writeExpr(Expr::F32DemoteF64); + return f.encoder().writeOp(Op::F32DemoteF64); } return true; } }; class CheckSimdSelectArgs { @@ -5329,17 +5329,17 @@ CheckSimdReplaceLane(FunctionValidator& arg = NextNode(arg); // Third argument is the scalar Type scalarType; if (!CheckExpr(f, arg, &scalarType)) return false; if (!(scalarType <= SimdToCoercedScalarType(opType))) { if (opType == SimdType::Float32x4 && scalarType.isDoubleLit()) { - if (!f.encoder().writeExpr(Expr::F32DemoteF64)) + if (!f.encoder().writeOp(Op::F32DemoteF64)) return false; } else { return f.failf(arg, "%s is not the correct type to replace an element of %s", scalarType.toChars(), vecType.toChars()); } } if (!f.writeSimdOp(opType, SimdOperation::Fn_replaceLane)) @@ -5722,39 +5722,39 @@ CoerceResult(FunctionValidator& f, Parse { MOZ_ASSERT(expected.isCanonical()); // At this point, the bytecode resembles this: // | the thing we wanted to coerce | current position |> switch (expected.which()) { case Type::Void: if (!actual.isVoid()) { - if (!f.encoder().writeExpr(Expr::Drop)) + if (!f.encoder().writeOp(Op::Drop)) return false; } break; case Type::Int: if (!actual.isIntish()) return f.failf(expr, "%s is not a subtype of intish", actual.toChars()); break; case Type::Float: if (!CheckFloatCoercionArg(f, expr, actual)) return false; break; case Type::Double: if (actual.isMaybeDouble()) { // No conversion necessary. } else if (actual.isMaybeFloat()) { - if (!f.encoder().writeExpr(Expr::F64PromoteF32)) + if (!f.encoder().writeOp(Op::F64PromoteF32)) return false; } else if (actual.isSigned()) { - if (!f.encoder().writeExpr(Expr::F64ConvertSI32)) + if (!f.encoder().writeOp(Op::F64ConvertSI32)) return false; } else if (actual.isUnsigned()) { - if (!f.encoder().writeExpr(Expr::F64ConvertUI32)) + if (!f.encoder().writeOp(Op::F64ConvertUI32)) return false; } else { return f.failf(expr, "%s is not a subtype of double?, float?, signed or unsigned", actual.toChars()); } break; default: MOZ_ASSERT(expected.isSimd(), "Incomplete switch"); if (actual != expected) @@ -5886,42 +5886,42 @@ CheckNot(FunctionValidator& f, ParseNode Type operandType; if (!CheckExpr(f, operand, &operandType)) return false; if (!operandType.isInt()) return f.failf(operand, "%s is not a subtype of int", operandType.toChars()); *type = Type::Int; - return f.encoder().writeExpr(Expr::I32Eqz); + return f.encoder().writeOp(Op::I32Eqz); } static bool CheckNeg(FunctionValidator& f, ParseNode* expr, Type* type) { MOZ_ASSERT(expr->isKind(PNK_NEG)); ParseNode* operand = UnaryKid(expr); Type operandType; if (!CheckExpr(f, operand, &operandType)) return false; if (operandType.isInt()) { *type = Type::Intish; - return f.encoder().writeExpr(Expr::I32Neg); + return f.encoder().writeOp(Op::I32Neg); } if (operandType.isMaybeDouble()) { *type = Type::Double; - return f.encoder().writeExpr(Expr::F64Neg); + return f.encoder().writeOp(Op::F64Neg); } if (operandType.isMaybeFloat()) { *type = Type::Floatish; - return f.encoder().writeExpr(Expr::F32Neg); + return f.encoder().writeOp(Op::F32Neg); } return f.failf(operand, "%s is not a subtype of int, float? or double?", operandType.toChars()); } static bool CheckCoerceToInt(FunctionValidator& f, ParseNode* expr, Type* type) { @@ -5929,18 +5929,18 @@ CheckCoerceToInt(FunctionValidator& f, P ParseNode* operand = UnaryKid(expr); Type operandType; if (!CheckExpr(f, operand, &operandType)) return false; if (operandType.isMaybeDouble() || operandType.isMaybeFloat()) { *type = Type::Signed; - Expr opcode = operandType.isMaybeDouble() ? Expr::I32TruncSF64 : Expr::I32TruncSF32; - return f.encoder().writeExpr(opcode); + Op opcode = operandType.isMaybeDouble() ? Op::I32TruncSF64 : Op::I32TruncSF32; + return f.encoder().writeOp(opcode); } if (!operandType.isIntish()) return f.failf(operand, "%s is not a subtype of double?, float? or intish", operandType.toChars()); *type = Type::Signed; return true; } @@ -5956,17 +5956,17 @@ CheckBitNot(FunctionValidator& f, ParseN Type operandType; if (!CheckExpr(f, operand, &operandType)) return false; if (!operandType.isIntish()) return f.failf(operand, "%s is not a subtype of intish", operandType.toChars()); - if (!f.encoder().writeExpr(Expr::I32BitNot)) + if (!f.encoder().writeOp(Op::I32BitNot)) return false; *type = Type::Signed; return true; } static bool CheckAsExprStatement(FunctionValidator& f, ParseNode* exprStmt); @@ -5974,17 +5974,17 @@ CheckAsExprStatement(FunctionValidator& static bool CheckComma(FunctionValidator& f, ParseNode* comma, Type* type) { MOZ_ASSERT(comma->isKind(PNK_COMMA)); ParseNode* operands = ListHead(comma); // The block depth isn't taken into account here, because a comma list can't // contain breaks and continues and nested control flow structures. - if (!f.encoder().writeExpr(Expr::Block)) + if (!f.encoder().writeOp(Op::Block)) return false; size_t typeAt; if (!f.encoder().writePatchableFixedU7(&typeAt)) return false; ParseNode* pn = operands; for (; NextNode(pn); pn = NextNode(pn)) { @@ -5992,17 +5992,17 @@ CheckComma(FunctionValidator& f, ParseNo return false; } if (!CheckExpr(f, pn, type)) return false; f.encoder().patchFixedU7(typeAt, uint8_t(type->toWasmBlockSignatureType())); - return f.encoder().writeExpr(Expr::End); + return f.encoder().writeOp(Op::End); } static bool CheckConditional(FunctionValidator& f, ParseNode* ternary, Type* type) { MOZ_ASSERT(ternary->isKind(PNK_CONDITIONAL)); ParseNode* cond = TernaryKid1(ternary); @@ -6098,27 +6098,27 @@ CheckMultiply(FunctionValidator& f, Pars Type rhsType; if (!CheckExpr(f, rhs, &rhsType)) return false; if (lhsType.isInt() && rhsType.isInt()) { if (!IsValidIntMultiplyConstant(f.m(), lhs) && !IsValidIntMultiplyConstant(f.m(), rhs)) return f.fail(star, "one arg to int multiply must be a small (-2^20, 2^20) int literal"); *type = Type::Intish; - return f.encoder().writeExpr(Expr::I32Mul); + return f.encoder().writeOp(Op::I32Mul); } if (lhsType.isMaybeDouble() && rhsType.isMaybeDouble()) { *type = Type::Double; - return f.encoder().writeExpr(Expr::F64Mul); + return f.encoder().writeOp(Op::F64Mul); } if (lhsType.isMaybeFloat() && rhsType.isMaybeFloat()) { *type = Type::Floatish; - return f.encoder().writeExpr(Expr::F32Mul); + return f.encoder().writeOp(Op::F32Mul); } return f.fail(star, "multiply operands must be both int, both double? or both float?"); } static bool CheckAddOrSub(FunctionValidator& f, ParseNode* expr, Type* type, unsigned* numAddOrSubOut = nullptr) { @@ -6153,25 +6153,25 @@ CheckAddOrSub(FunctionValidator& f, Pars rhsNumAddOrSub = 0; } unsigned numAddOrSub = lhsNumAddOrSub + rhsNumAddOrSub + 1; if (numAddOrSub > (1<<20)) return f.fail(expr, "too many + or - without intervening coercion"); if (lhsType.isInt() && rhsType.isInt()) { - if (!f.encoder().writeExpr(expr->isKind(PNK_ADD) ? Expr::I32Add : Expr::I32Sub)) + if (!f.encoder().writeOp(expr->isKind(PNK_ADD) ? Op::I32Add : Op::I32Sub)) return false; *type = Type::Intish; } else if (lhsType.isMaybeDouble() && rhsType.isMaybeDouble()) { - if (!f.encoder().writeExpr(expr->isKind(PNK_ADD) ? Expr::F64Add : Expr::F64Sub)) + if (!f.encoder().writeOp(expr->isKind(PNK_ADD) ? Op::F64Add : Op::F64Sub)) return false; *type = Type::Double; } else if (lhsType.isMaybeFloat() && rhsType.isMaybeFloat()) { - if (!f.encoder().writeExpr(expr->isKind(PNK_ADD) ? Expr::F32Add : Expr::F32Sub)) + if (!f.encoder().writeOp(expr->isKind(PNK_ADD) ? Op::F32Add : Op::F32Sub)) return false; *type = Type::Floatish; } else { return f.failf(expr, "operands to + or - must both be int, float? or double?, got %s and %s", lhsType.toChars(), rhsType.toChars()); } if (numAddOrSubOut) @@ -6190,35 +6190,35 @@ CheckDivOrMod(FunctionValidator& f, Pars Type lhsType, rhsType; if (!CheckExpr(f, lhs, &lhsType)) return false; if (!CheckExpr(f, rhs, &rhsType)) return false; if (lhsType.isMaybeDouble() && rhsType.isMaybeDouble()) { *type = Type::Double; - return f.encoder().writeExpr(expr->isKind(PNK_DIV) ? Expr::F64Div : Expr::F64Mod); + return f.encoder().writeOp(expr->isKind(PNK_DIV) ? Op::F64Div : Op::F64Mod); } if (lhsType.isMaybeFloat() && rhsType.isMaybeFloat()) { *type = Type::Floatish; if (expr->isKind(PNK_DIV)) - return f.encoder().writeExpr(Expr::F32Div); + return f.encoder().writeOp(Op::F32Div); else return f.fail(expr, "modulo cannot receive float arguments"); } if (lhsType.isSigned() && rhsType.isSigned()) { *type = Type::Intish; - return f.encoder().writeExpr(expr->isKind(PNK_DIV) ? Expr::I32DivS : Expr::I32RemS); + return f.encoder().writeOp(expr->isKind(PNK_DIV) ? Op::I32DivS : Op::I32RemS); } if (lhsType.isUnsigned() && rhsType.isUnsigned()) { *type = Type::Intish; - return f.encoder().writeExpr(expr->isKind(PNK_DIV) ? Expr::I32DivU : Expr::I32RemU); + return f.encoder().writeOp(expr->isKind(PNK_DIV) ? Op::I32DivU : Op::I32RemU); } return f.failf(expr, "arguments to / or %% must both be double?, float?, signed, or unsigned; " "%s and %s are given", lhsType.toChars(), rhsType.toChars()); } static bool CheckComparison(FunctionValidator& f, ParseNode* comp, Type* type) @@ -6239,63 +6239,63 @@ CheckComparison(FunctionValidator& f, Pa !(lhsType.isUnsigned() && rhsType.isUnsigned()) && !(lhsType.isDouble() && rhsType.isDouble()) && !(lhsType.isFloat() && rhsType.isFloat())) { return f.failf(comp, "arguments to a comparison must both be signed, unsigned, floats or doubles; " "%s and %s are given", lhsType.toChars(), rhsType.toChars()); } - Expr stmt; + Op stmt; if (lhsType.isSigned() && rhsType.isSigned()) { switch (comp->getOp()) { - case JSOP_EQ: stmt = Expr::I32Eq; break; - case JSOP_NE: stmt = Expr::I32Ne; break; - case JSOP_LT: stmt = Expr::I32LtS; break; - case JSOP_LE: stmt = Expr::I32LeS; break; - case JSOP_GT: stmt = Expr::I32GtS; break; - case JSOP_GE: stmt = Expr::I32GeS; break; + case JSOP_EQ: stmt = Op::I32Eq; break; + case JSOP_NE: stmt = Op::I32Ne; break; + case JSOP_LT: stmt = Op::I32LtS; break; + case JSOP_LE: stmt = Op::I32LeS; break; + case JSOP_GT: stmt = Op::I32GtS; break; + case JSOP_GE: stmt = Op::I32GeS; break; default: MOZ_CRASH("unexpected comparison op"); } } else if (lhsType.isUnsigned() && rhsType.isUnsigned()) { switch (comp->getOp()) { - case JSOP_EQ: stmt = Expr::I32Eq; break; - case JSOP_NE: stmt = Expr::I32Ne; break; - case JSOP_LT: stmt = Expr::I32LtU; break; - case JSOP_LE: stmt = Expr::I32LeU; break; - case JSOP_GT: stmt = Expr::I32GtU; break; - case JSOP_GE: stmt = Expr::I32GeU; break; + case JSOP_EQ: stmt = Op::I32Eq; break; + case JSOP_NE: stmt = Op::I32Ne; break; + case JSOP_LT: stmt = Op::I32LtU; break; + case JSOP_LE: stmt = Op::I32LeU; break; + case JSOP_GT: stmt = Op::I32GtU; break; + case JSOP_GE: stmt = Op::I32GeU; break; default: MOZ_CRASH("unexpected comparison op"); } } else if (lhsType.isDouble()) { switch (comp->getOp()) { - case JSOP_EQ: stmt = Expr::F64Eq; break; - case JSOP_NE: stmt = Expr::F64Ne; break; - case JSOP_LT: stmt = Expr::F64Lt; break; - case JSOP_LE: stmt = Expr::F64Le; break; - case JSOP_GT: stmt = Expr::F64Gt; break; - case JSOP_GE: stmt = Expr::F64Ge; break; + case JSOP_EQ: stmt = Op::F64Eq; break; + case JSOP_NE: stmt = Op::F64Ne; break; + case JSOP_LT: stmt = Op::F64Lt; break; + case JSOP_LE: stmt = Op::F64Le; break; + case JSOP_GT: stmt = Op::F64Gt; break; + case JSOP_GE: stmt = Op::F64Ge; break; default: MOZ_CRASH("unexpected comparison op"); } } else if (lhsType.isFloat()) { switch (comp->getOp()) { - case JSOP_EQ: stmt = Expr::F32Eq; break; - case JSOP_NE: stmt = Expr::F32Ne; break; - case JSOP_LT: stmt = Expr::F32Lt; break; - case JSOP_LE: stmt = Expr::F32Le; break; - case JSOP_GT: stmt = Expr::F32Gt; break; - case JSOP_GE: stmt = Expr::F32Ge; break; + case JSOP_EQ: stmt = Op::F32Eq; break; + case JSOP_NE: stmt = Op::F32Ne; break; + case JSOP_LT: stmt = Op::F32Lt; break; + case JSOP_LE: stmt = Op::F32Le; break; + case JSOP_GT: stmt = Op::F32Gt; break; + case JSOP_GE: stmt = Op::F32Ge; break; default: MOZ_CRASH("unexpected comparison op"); } } else { MOZ_CRASH("unexpected type"); } *type = Type::Int; - return f.encoder().writeExpr(stmt); + return f.encoder().writeOp(stmt); } static bool CheckBitwise(FunctionValidator& f, ParseNode* bitwise, Type* type) { ParseNode* lhs = BitwiseLeft(bitwise); ParseNode* rhs = BitwiseRight(bitwise); @@ -6342,22 +6342,22 @@ CheckBitwise(FunctionValidator& f, Parse return false; if (!lhsType.isIntish()) return f.failf(lhs, "%s is not a subtype of intish", lhsType.toChars()); if (!rhsType.isIntish()) return f.failf(rhs, "%s is not a subtype of intish", rhsType.toChars()); switch (bitwise->getKind()) { - case PNK_BITOR: if (!f.encoder().writeExpr(Expr::I32Or)) return false; break; - case PNK_BITAND: if (!f.encoder().writeExpr(Expr::I32And)) return false; break; - case PNK_BITXOR: if (!f.encoder().writeExpr(Expr::I32Xor)) return false; break; - case PNK_LSH: if (!f.encoder().writeExpr(Expr::I32Shl)) return false; break; - case PNK_RSH: if (!f.encoder().writeExpr(Expr::I32ShrS)) return false; break; - case PNK_URSH: if (!f.encoder().writeExpr(Expr::I32ShrU)) return false; break; + case PNK_BITOR: if (!f.encoder().writeOp(Op::I32Or)) return false; break; + case PNK_BITAND: if (!f.encoder().writeOp(Op::I32And)) return false; break; + case PNK_BITXOR: if (!f.encoder().writeOp(Op::I32Xor)) return false; break; + case PNK_LSH: if (!f.encoder().writeOp(Op::I32Shl)) return false; break; + case PNK_RSH: if (!f.encoder().writeOp(Op::I32ShrS)) return false; break; + case PNK_URSH: if (!f.encoder().writeOp(Op::I32ShrU)) return false; break; default: MOZ_CRASH("not a bitwise op"); } return true; } static bool CheckExpr(FunctionValidator& f, ParseNode* expr, Type* type) @@ -6421,17 +6421,17 @@ CheckAsExprStatement(FunctionValidator& return CheckCoercedCall(f, expr, Type::Void, &ignored); } Type resultType; if (!CheckExpr(f, expr, &resultType)) return false; if (!resultType.isVoid()) { - if (!f.encoder().writeExpr(Expr::Drop)) + if (!f.encoder().writeOp(Op::Drop)) return false; } return true; } static bool CheckExprStatement(FunctionValidator& f, ParseNode* exprStmt) @@ -6455,17 +6455,17 @@ CheckLoopConditionOnEntry(FunctionValida return false; if (!condType.isInt()) return f.failf(cond, "%s is not a subtype of int", condType.toChars()); // TODO change this to i32.eqz // i32.eq 0 $f if (!f.writeInt32Lit(0)) return false; - if (!f.encoder().writeExpr(Expr::I32Eq)) + if (!f.encoder().writeOp(Op::I32Eq)) return false; // brIf (i32.eq 0 $f) $out if (!f.writeBreakIf()) return false; return true; } @@ -6828,17 +6828,17 @@ CheckSwitch(FunctionValidator& f, ParseN return f.fail(switchBody, "switch body may not contain lexical declarations"); switchBody = switchBody->scopeBody(); } ParseNode* stmt = ListHead(switchBody); if (!stmt) { if (!CheckSwitchExpr(f, switchExpr)) return false; - if (!f.encoder().writeExpr(Expr::Drop)) + if (!f.encoder().writeOp(Op::Drop)) return false; return true; } if (!CheckDefaultAtEnd(f, stmt)) return false; int32_t low = 0, high = 0; @@ -6883,25 +6883,25 @@ CheckSwitch(FunctionValidator& f, ParseN uint32_t defaultDepth = numCases; // Subtract lowest case value, so that all the cases start from 0. if (low) { if (!CheckSwitchExpr(f, switchExpr)) return false; if (!f.writeInt32Lit(low)) return false; - if (!f.encoder().writeExpr(Expr::I32Sub)) + if (!f.encoder().writeOp(Op::I32Sub)) return false; } else { if (!CheckSwitchExpr(f, switchExpr)) return false; } // Start the br_table block. - if (!f.encoder().writeExpr(Expr::BrTable)) + if (!f.encoder().writeOp(Op::BrTable)) return false; // Write the number of cases (tableLength - 1 + 1 (default)). // Write the number of cases (tableLength - 1 + 1 (default)). if (!f.encoder().writeVarU32(tableLength)) return false; // Each case value describes the relative depth to the actual block. When @@ -6970,17 +6970,17 @@ CheckReturn(FunctionValidator& f, ParseN if (!type.isReturnType()) return f.failf(expr, "%s is not a valid return type", type.toChars()); if (!CheckReturnType(f, expr, Type::canonicalize(type))) return false; } - if (!f.encoder().writeExpr(Expr::Return)) + if (!f.encoder().writeOp(Op::Return)) return false; return true; } static bool CheckStatementList(FunctionValidator& f, ParseNode* stmtList, const NameVector* labels /*= nullptr */) {
--- a/js/src/wasm/WasmAST.h +++ b/js/src/wasm/WasmAST.h @@ -369,71 +369,71 @@ class AstTeeLocal : public AstExpr } AstExpr& value() const { return value_; } }; class AstBlock : public AstExpr { - Expr expr_; + Op op_; AstName name_; AstExprVector exprs_; public: static const AstExprKind Kind = AstExprKind::Block; - explicit AstBlock(Expr expr, ExprType type, AstName name, AstExprVector&& exprs) + explicit AstBlock(Op op, ExprType type, AstName name, AstExprVector&& exprs) : AstExpr(Kind, type), - expr_(expr), + op_(op), name_(name), exprs_(Move(exprs)) {} - Expr expr() const { return expr_; } + Op op() const { return op_; } AstName name() const { return name_; } const AstExprVector& exprs() const { return exprs_; } }; class AstBranch : public AstExpr { - Expr expr_; + Op op_; AstExpr* cond_; AstRef target_; AstExpr* value_; public: static const AstExprKind Kind = AstExprKind::Branch; - explicit AstBranch(Expr expr, ExprType type, + explicit AstBranch(Op op, ExprType type, AstExpr* cond, AstRef target, AstExpr* value) : AstExpr(Kind, type), - expr_(expr), + op_(op), cond_(cond), target_(target), value_(value) {} - Expr expr() const { return expr_; } + Op op() const { return op_; } AstRef& target() { return target_; } AstExpr& cond() const { MOZ_ASSERT(cond_); return *cond_; } AstExpr* maybeValue() const { return value_; } }; class AstCall : public AstExpr { - Expr expr_; + Op op_; AstRef func_; AstExprVector args_; public: static const AstExprKind Kind = AstExprKind::Call; - AstCall(Expr expr, ExprType type, AstRef func, AstExprVector&& args) - : AstExpr(Kind, type), expr_(expr), func_(func), args_(Move(args)) + AstCall(Op op, ExprType type, AstRef func, AstExprVector&& args) + : AstExpr(Kind, type), op_(op), func_(func), args_(Move(args)) {} - Expr expr() const { return expr_; } + Op op() const { return op_; } AstRef& func() { return func_; } const AstExprVector& args() const { return args_; } }; class AstCallIndirect : public AstExpr { AstRef sig_; AstExprVector args_; @@ -502,72 +502,71 @@ class AstLoadStoreAddress AstExpr& base() const { return *base_; } int32_t flags() const { return flags_; } int32_t offset() const { return offset_; } }; class AstLoad : public AstExpr { - Expr expr_; + Op op_; AstLoadStoreAddress address_; public: static const AstExprKind Kind = AstExprKind::Load; - explicit AstLoad(Expr expr, const AstLoadStoreAddress &address) + explicit AstLoad(Op op, const AstLoadStoreAddress &address) : AstExpr(Kind, ExprType::Limit), - expr_(expr), + op_(op), address_(address) {} - Expr expr() const { return expr_; } + Op op() const { return op_; } const AstLoadStoreAddress& address() const { return address_; } }; class AstStore : public AstExpr { - Expr expr_; + Op op_; AstLoadStoreAddress address_; AstExpr* value_; public: static const AstExprKind Kind = AstExprKind::Store; - explicit AstStore(Expr expr, const AstLoadStoreAddress &address, - AstExpr* value) + explicit AstStore(Op op, const AstLoadStoreAddress &address, AstExpr* value) : AstExpr(Kind, ExprType::Void), - expr_(expr), + op_(op), address_(address), value_(value) {} - Expr expr() const { return expr_; } + Op op() const { return op_; } const AstLoadStoreAddress& address() const { return address_; } AstExpr& value() const { return *value_; } }; class AstCurrentMemory final : public AstExpr { public: static const AstExprKind Kind = AstExprKind::CurrentMemory; explicit AstCurrentMemory() : AstExpr(Kind, ExprType::I32) {} }; class AstGrowMemory final : public AstExpr { - AstExpr* op_; + AstExpr* operand_; public: static const AstExprKind Kind = AstExprKind::GrowMemory; - explicit AstGrowMemory(AstExpr* op) - : AstExpr(Kind, ExprType::I32), op_(op) + explicit AstGrowMemory(AstExpr* operand) + : AstExpr(Kind, ExprType::I32), operand_(operand) {} - AstExpr* op() const { return op_; } + AstExpr* operand() const { return operand_; } }; class AstBranchTable : public AstExpr { AstExpr& index_; AstRef default_; AstRefVector table_; AstExpr* value_; @@ -912,100 +911,100 @@ class AstModule : public AstNode } const AstGlobalVector& globals() const { return globals_; } }; class AstUnaryOperator final : public AstExpr { - Expr expr_; - AstExpr* op_; + Op op_; + AstExpr* operand_; public: static const AstExprKind Kind = AstExprKind::UnaryOperator; - explicit AstUnaryOperator(Expr expr, AstExpr* op) + explicit AstUnaryOperator(Op op, AstExpr* operand) : AstExpr(Kind, ExprType::Limit), - expr_(expr), op_(op) + op_(op), operand_(operand) {} - Expr expr() const { return expr_; } - AstExpr* op() const { return op_; } + Op op() const { return op_; } + AstExpr* operand() const { return operand_; } }; class AstBinaryOperator final : public AstExpr { - Expr expr_; + Op op_; AstExpr* lhs_; AstExpr* rhs_; public: static const AstExprKind Kind = AstExprKind::BinaryOperator; - explicit AstBinaryOperator(Expr expr, AstExpr* lhs, AstExpr* rhs) + explicit AstBinaryOperator(Op op, AstExpr* lhs, AstExpr* rhs) : AstExpr(Kind, ExprType::Limit), - expr_(expr), lhs_(lhs), rhs_(rhs) + op_(op), lhs_(lhs), rhs_(rhs) {} - Expr expr() const { return expr_; } + Op op() const { return op_; } AstExpr* lhs() const { return lhs_; } AstExpr* rhs() const { return rhs_; } }; class AstTernaryOperator : public AstExpr { - Expr expr_; + Op op_; AstExpr* op0_; AstExpr* op1_; AstExpr* op2_; public: static const AstExprKind Kind = AstExprKind::TernaryOperator; - AstTernaryOperator(Expr expr, AstExpr* op0, AstExpr* op1, AstExpr* op2) + AstTernaryOperator(Op op, AstExpr* op0, AstExpr* op1, AstExpr* op2) : AstExpr(Kind, ExprType::Limit), - expr_(expr), op0_(op0), op1_(op1), op2_(op2) + op_(op), op0_(op0), op1_(op1), op2_(op2) {} - Expr expr() const { return expr_; } + Op op() const { return op_; } AstExpr* op0() const { return op0_; } AstExpr* op1() const { return op1_; } AstExpr* op2() const { return op2_; } }; class AstComparisonOperator final : public AstExpr { - Expr expr_; + Op op_; AstExpr* lhs_; AstExpr* rhs_; public: static const AstExprKind Kind = AstExprKind::ComparisonOperator; - explicit AstComparisonOperator(Expr expr, AstExpr* lhs, AstExpr* rhs) + explicit AstComparisonOperator(Op op, AstExpr* lhs, AstExpr* rhs) : AstExpr(Kind, ExprType::Limit), - expr_(expr), lhs_(lhs), rhs_(rhs) + op_(op), lhs_(lhs), rhs_(rhs) {} - Expr expr() const { return expr_; } + Op op() const { return op_; } AstExpr* lhs() const { return lhs_; } AstExpr* rhs() const { return rhs_; } }; class AstConversionOperator final : public AstExpr { - Expr expr_; - AstExpr* op_; + Op op_; + AstExpr* operand_; public: static const AstExprKind Kind = AstExprKind::ConversionOperator; - explicit AstConversionOperator(Expr expr, AstExpr* op) + explicit AstConversionOperator(Op op, AstExpr* operand) : AstExpr(Kind, ExprType::Limit), - expr_(expr), op_(op) + op_(op), operand_(operand) {} - Expr expr() const { return expr_; } - AstExpr* op() const { return op_; } + Op op() const { return op_; } + AstExpr* operand() const { return operand_; } }; // This is an artificial AST node which can fill operand slots in an AST // constructed from parsing or decoding stack-machine code that doesn't have // an inherent AST structure. class AstPop final : public AstExpr { public:
--- a/js/src/wasm/WasmBaselineCompile.cpp +++ b/js/src/wasm/WasmBaselineCompile.cpp @@ -54,17 +54,17 @@ * this reduces register pressure and instruction count. * * - (Bug 1286816) Opportunities for cheaply folding in a constant rhs to * conditionals. * * - (Bug 1286816) Boolean evaluation for control can be optimized by pushing a * bool-generating operation onto the value stack in the same way that we now * push latent constants and local lookups, or (easier) by remembering the - * operation in a side location if the next Expr will consume it. + * operation in a side location if the next Op will consume it. * * - (Bug 1286816) brIf pessimizes by branching over code that performs stack * cleanup and a branch. If no cleanup is needed we can just branch * conditionally to the target. * * - (Bug 1316804) brTable pessimizes by always dispatching to code that pops * the stack and then jumps to the code for the target case. If no cleanup is * needed we could just branch conditionally to the target; if the same amount @@ -128,33 +128,33 @@ using mozilla::IsPowerOfTwo; using mozilla::SpecificNaN; namespace js { namespace wasm { using namespace js::jit; using JS::GenericNaN; -struct BaseCompilePolicy : ExprIterPolicy +struct BaseCompilePolicy : OpIterPolicy { static const bool Output = true; // The baseline compiler tracks values on a stack of its own -- it // needs to scan that stack for spilling -- and thus has no need // for the values maintained by the iterator. // // The baseline compiler tracks control items on a stack of its // own as well. // // TODO / REDUNDANT (Bug 1316814): It would be nice if we could // make use of the iterator's ControlItems and not require our own // stack for that. }; -typedef ExprIter<BaseCompilePolicy> BaseExprIter; +typedef OpIter<BaseCompilePolicy> BaseOpIter; typedef bool IsUnsigned; typedef bool IsSigned; typedef bool ZeroOnOverflow; typedef bool IsKnownNotZero; typedef bool HandleNaNSpecially; typedef unsigned ByteSize; typedef unsigned BitSize; @@ -501,17 +501,17 @@ class BaseCompiler // // All other registers must be explicitly saved and restored // by the OOL code before being used. virtual void generate(MacroAssembler& masm) = 0; }; const ModuleGeneratorData& mg_; - BaseExprIter iter_; + BaseOpIter iter_; const FuncBytes& func_; size_t lastReadCallSite_; TempAllocator& alloc_; const ValTypeVector& locals_; // Types of parameters and locals int32_t localSize_; // Size of local area in bytes (stable after beginFunction) int32_t varLow_; // Low byte offset of local area for true locals (not parameters) int32_t varHigh_; // High byte offset + 1 of local area for true locals int32_t maxFramePushed_; // Max value of masm.framePushed() observed @@ -6579,540 +6579,540 @@ BaseCompiler::emitBody() CHECK(stk_.reserve(stk_.length() + overhead * 2)); } overhead--; if (done()) return true; - Expr expr; - CHECK(iter_.readExpr(&expr)); - - switch (expr) { + uint16_t op; + CHECK(iter_.readOp(&op)); + + switch (op) { // Control opcodes - case Expr::Nop: + case uint16_t(Op::Nop): CHECK(iter_.readNop()); NEXT(); - case Expr::Drop: + case uint16_t(Op::Drop): CHECK_NEXT(emitDrop()); - case Expr::Block: + case uint16_t(Op::Block): CHECK_NEXT(emitBlock()); - case Expr::Loop: + case uint16_t(Op::Loop): CHECK_NEXT(emitLoop()); - case Expr::If: + case uint16_t(Op::If): CHECK_NEXT(emitIf()); - case Expr::Else: + case uint16_t(Op::Else): CHECK_NEXT(emitElse()); - case Expr::End: + case uint16_t(Op::End): CHECK_NEXT(emitEnd()); - case Expr::Br: + case uint16_t(Op::Br): CHECK_NEXT(emitBr()); - case Expr::BrIf: + case uint16_t(Op::BrIf): CHECK_NEXT(emitBrIf()); - case Expr::BrTable: + case uint16_t(Op::BrTable): CHECK_NEXT(emitBrTable()); - case Expr::Return: + case uint16_t(Op::Return): CHECK_NEXT(emitReturn()); - case Expr::Unreachable: + case uint16_t(Op::Unreachable): CHECK(iter_.readUnreachable()); if (!deadCode_) { unreachableTrap(); deadCode_ = true; popValueStackTo(ctl_.back().stackSize); } NEXT(); // Calls - case Expr::Call: + case uint16_t(Op::Call): CHECK_NEXT(emitCall()); - case Expr::CallIndirect: + case uint16_t(Op::CallIndirect): CHECK_NEXT(emitCallIndirect(/* oldStyle = */ false)); - case Expr::OldCallIndirect: + case uint16_t(Op::OldCallIndirect): CHECK_NEXT(emitCallIndirect(/* oldStyle = */ true)); // Locals and globals - case Expr::GetLocal: + case uint16_t(Op::GetLocal): CHECK_NEXT(emitGetLocal()); - case Expr::SetLocal: + case uint16_t(Op::SetLocal): CHECK_NEXT(emitSetLocal()); - case Expr::TeeLocal: + case uint16_t(Op::TeeLocal): CHECK_NEXT(emitTeeLocal()); - case Expr::GetGlobal: + case uint16_t(Op::GetGlobal): CHECK_NEXT(emitGetGlobal()); - case Expr::SetGlobal: + case uint16_t(Op::SetGlobal): CHECK_NEXT(emitSetGlobal()); - case Expr::TeeGlobal: + case uint16_t(Op::TeeGlobal): CHECK_NEXT(emitTeeGlobal()); // Select - case Expr::Select: + case uint16_t(Op::Select): CHECK_NEXT(emitSelect()); // I32 - case Expr::I32Const: { + case uint16_t(Op::I32Const): { int32_t i32; CHECK(iter_.readI32Const(&i32)); if (!deadCode_) pushI32(i32); NEXT(); } - case Expr::I32Add: + case uint16_t(Op::I32Add): CHECK_NEXT(emitBinary(emitAddI32, ValType::I32)); - case Expr::I32Sub: + case uint16_t(Op::I32Sub): CHECK_NEXT(emitBinary(emitSubtractI32, ValType::I32)); - case Expr::I32Mul: + case uint16_t(Op::I32Mul): CHECK_NEXT(emitBinary(emitMultiplyI32, ValType::I32)); - case Expr::I32DivS: + case uint16_t(Op::I32DivS): CHECK_NEXT(emitBinary(emitQuotientI32, ValType::I32)); - case Expr::I32DivU: + case uint16_t(Op::I32DivU): CHECK_NEXT(emitBinary(emitQuotientU32, ValType::I32)); - case Expr::I32RemS: + case uint16_t(Op::I32RemS): CHECK_NEXT(emitBinary(emitRemainderI32, ValType::I32)); - case Expr::I32RemU: + case uint16_t(Op::I32RemU): CHECK_NEXT(emitBinary(emitRemainderU32, ValType::I32)); - case Expr::I32Min: + case uint16_t(Op::I32Min): CHECK_NEXT(emitBinary(emitMinI32, ValType::I32)); - case Expr::I32Max: + case uint16_t(Op::I32Max): CHECK_NEXT(emitBinary(emitMaxI32, ValType::I32)); - case Expr::I32Eqz: + case uint16_t(Op::I32Eqz): CHECK_NEXT(emitConversion(emitEqzI32, ValType::I32, ValType::I32)); - case Expr::I32TruncSF32: + case uint16_t(Op::I32TruncSF32): CHECK_NEXT(emitConversionOOM(emitTruncateF32ToI32<false>, ValType::F32, ValType::I32)); - case Expr::I32TruncUF32: + case uint16_t(Op::I32TruncUF32): CHECK_NEXT(emitConversionOOM(emitTruncateF32ToI32<true>, ValType::F32, ValType::I32)); - case Expr::I32TruncSF64: + case uint16_t(Op::I32TruncSF64): CHECK_NEXT(emitConversionOOM(emitTruncateF64ToI32<false>, ValType::F64, ValType::I32)); - case Expr::I32TruncUF64: + case uint16_t(Op::I32TruncUF64): CHECK_NEXT(emitConversionOOM(emitTruncateF64ToI32<true>, ValType::F64, ValType::I32)); - case Expr::I32WrapI64: + case uint16_t(Op::I32WrapI64): CHECK_NEXT(emitConversion(emitWrapI64ToI32, ValType::I64, ValType::I32)); - case Expr::I32ReinterpretF32: + case uint16_t(Op::I32ReinterpretF32): CHECK_NEXT(emitConversion(emitReinterpretF32AsI32, ValType::F32, ValType::I32)); - case Expr::I32Clz: + case uint16_t(Op::I32Clz): CHECK_NEXT(emitUnary(emitClzI32, ValType::I32)); - case Expr::I32Ctz: + case uint16_t(Op::I32Ctz): CHECK_NEXT(emitUnary(emitCtzI32, ValType::I32)); - case Expr::I32Popcnt: + case uint16_t(Op::I32Popcnt): CHECK_NEXT(emitUnary(emitPopcntI32, ValType::I32)); - case Expr::I32Abs: + case uint16_t(Op::I32Abs): CHECK_NEXT(emitUnary(emitAbsI32, ValType::I32)); - case Expr::I32Neg: + case uint16_t(Op::I32Neg): CHECK_NEXT(emitUnary(emitNegateI32, ValType::I32)); - case Expr::I32Or: + case uint16_t(Op::I32Or): CHECK_NEXT(emitBinary(emitOrI32, ValType::I32)); - case Expr::I32And: + case uint16_t(Op::I32And): CHECK_NEXT(emitBinary(emitAndI32, ValType::I32)); - case Expr::I32Xor: + case uint16_t(Op::I32Xor): CHECK_NEXT(emitBinary(emitXorI32, ValType::I32)); - case Expr::I32Shl: + case uint16_t(Op::I32Shl): CHECK_NEXT(emitBinary(emitShlI32, ValType::I32)); - case Expr::I32ShrS: + case uint16_t(Op::I32ShrS): CHECK_NEXT(emitBinary(emitShrI32, ValType::I32)); - case Expr::I32ShrU: + case uint16_t(Op::I32ShrU): CHECK_NEXT(emitBinary(emitShrU32, ValType::I32)); - case Expr::I32BitNot: + case uint16_t(Op::I32BitNot): CHECK_NEXT(emitUnary(emitBitNotI32, ValType::I32)); - case Expr::I32Load8S: + case uint16_t(Op::I32Load8S): CHECK_NEXT(emitLoad(ValType::I32, Scalar::Int8)); - case Expr::I32Load8U: + case uint16_t(Op::I32Load8U): CHECK_NEXT(emitLoad(ValType::I32, Scalar::Uint8)); - case Expr::I32Load16S: + case uint16_t(Op::I32Load16S): CHECK_NEXT(emitLoad(ValType::I32, Scalar::Int16)); - case Expr::I32Load16U: + case uint16_t(Op::I32Load16U): CHECK_NEXT(emitLoad(ValType::I32, Scalar::Uint16)); - case Expr::I32Load: + case uint16_t(Op::I32Load): CHECK_NEXT(emitLoad(ValType::I32, Scalar::Int32)); - case Expr::I32Store8: + case uint16_t(Op::I32Store8): CHECK_NEXT(emitStore(ValType::I32, Scalar::Int8)); - case Expr::I32TeeStore8: + case uint16_t(Op::I32TeeStore8): CHECK_NEXT(emitTeeStore(ValType::I32, Scalar::Int8)); - case Expr::I32Store16: + case uint16_t(Op::I32Store16): CHECK_NEXT(emitStore(ValType::I32, Scalar::Int16)); - case Expr::I32TeeStore16: + case uint16_t(Op::I32TeeStore16): CHECK_NEXT(emitTeeStore(ValType::I32, Scalar::Int16)); - case Expr::I32Store: + case uint16_t(Op::I32Store): CHECK_NEXT(emitStore(ValType::I32, Scalar::Int32)); - case Expr::I32TeeStore: + case uint16_t(Op::I32TeeStore): CHECK_NEXT(emitTeeStore(ValType::I32, Scalar::Int32)); - case Expr::I32Rotr: + case uint16_t(Op::I32Rotr): CHECK_NEXT(emitBinary(emitRotrI32, ValType::I32)); - case Expr::I32Rotl: + case uint16_t(Op::I32Rotl): CHECK_NEXT(emitBinary(emitRotlI32, ValType::I32)); // I64 - case Expr::I64Const: { + case uint16_t(Op::I64Const): { int64_t i64; CHECK(iter_.readI64Const(&i64)); if (!deadCode_) pushI64(i64); NEXT(); } - case Expr::I64Add: + case uint16_t(Op::I64Add): CHECK_NEXT(emitBinary(emitAddI64, ValType::I64)); - case Expr::I64Sub: + case uint16_t(Op::I64Sub): CHECK_NEXT(emitBinary(emitSubtractI64, ValType::I64)); - case Expr::I64Mul: + case uint16_t(Op::I64Mul): CHECK_NEXT(emitBinary(emitMultiplyI64, ValType::I64)); - case Expr::I64DivS: + case uint16_t(Op::I64DivS): #ifdef INT_DIV_I64_CALLOUT CHECK_NEXT(emitDivOrModI64BuiltinCall(SymbolicAddress::DivI64, ValType::I64)); #else CHECK_NEXT(emitBinary(emitQuotientI64, ValType::I64)); #endif - case Expr::I64DivU: + case uint16_t(Op::I64DivU): #ifdef INT_DIV_I64_CALLOUT CHECK_NEXT(emitDivOrModI64BuiltinCall(SymbolicAddress::UDivI64, ValType::I64)); #else CHECK_NEXT(emitBinary(emitQuotientU64, ValType::I64)); #endif - case Expr::I64RemS: + case uint16_t(Op::I64RemS): #ifdef INT_DIV_I64_CALLOUT CHECK_NEXT(emitDivOrModI64BuiltinCall(SymbolicAddress::ModI64, ValType::I64)); #else CHECK_NEXT(emitBinary(emitRemainderI64, ValType::I64)); #endif - case Expr::I64RemU: + case uint16_t(Op::I64RemU): #ifdef INT_DIV_I64_CALLOUT CHECK_NEXT(emitDivOrModI64BuiltinCall(SymbolicAddress::UModI64, ValType::I64)); #else CHECK_NEXT(emitBinary(emitRemainderU64, ValType::I64)); #endif - case Expr::I64TruncSF32: + case uint16_t(Op::I64TruncSF32): #ifdef FLOAT_TO_I64_CALLOUT CHECK_NEXT(emitCalloutConversionOOM(emitConvertFloatingToInt64Callout, SymbolicAddress::TruncateDoubleToInt64, ValType::F32, ValType::I64)); #else CHECK_NEXT(emitConversionOOM(emitTruncateF32ToI64<false>, ValType::F32, ValType::I64)); #endif - case Expr::I64TruncUF32: + case uint16_t(Op::I64TruncUF32): #ifdef FLOAT_TO_I64_CALLOUT CHECK_NEXT(emitCalloutConversionOOM(emitConvertFloatingToInt64Callout, SymbolicAddress::TruncateDoubleToUint64, ValType::F32, ValType::I64)); #else CHECK_NEXT(emitConversionOOM(emitTruncateF32ToI64<true>, ValType::F32, ValType::I64)); #endif - case Expr::I64TruncSF64: + case uint16_t(Op::I64TruncSF64): #ifdef FLOAT_TO_I64_CALLOUT CHECK_NEXT(emitCalloutConversionOOM(emitConvertFloatingToInt64Callout, SymbolicAddress::TruncateDoubleToInt64, ValType::F64, ValType::I64)); #else CHECK_NEXT(emitConversionOOM(emitTruncateF64ToI64<false>, ValType::F64, ValType::I64)); #endif - case Expr::I64TruncUF64: + case uint16_t(Op::I64TruncUF64): #ifdef FLOAT_TO_I64_CALLOUT CHECK_NEXT(emitCalloutConversionOOM(emitConvertFloatingToInt64Callout, SymbolicAddress::TruncateDoubleToUint64, ValType::F64, ValType::I64)); #else CHECK_NEXT(emitConversionOOM(emitTruncateF64ToI64<true>, ValType::F64, ValType::I64)); #endif - case Expr::I64ExtendSI32: + case uint16_t(Op::I64ExtendSI32): CHECK_NEXT(emitConversion(emitExtendI32ToI64, ValType::I32, ValType::I64)); - case Expr::I64ExtendUI32: + case uint16_t(Op::I64ExtendUI32): CHECK_NEXT(emitConversion(emitExtendU32ToI64, ValType::I32, ValType::I64)); - case Expr::I64ReinterpretF64: + case uint16_t(Op::I64ReinterpretF64): CHECK_NEXT(emitConversion(emitReinterpretF64AsI64, ValType::F64, ValType::I64)); - case Expr::I64Or: + case uint16_t(Op::I64Or): CHECK_NEXT(emitBinary(emitOrI64, ValType::I64)); - case Expr::I64And: + case uint16_t(Op::I64And): CHECK_NEXT(emitBinary(emitAndI64, ValType::I64)); - case Expr::I64Xor: + case uint16_t(Op::I64Xor): CHECK_NEXT(emitBinary(emitXorI64, ValType::I64)); - case Expr::I64Shl: + case uint16_t(Op::I64Shl): CHECK_NEXT(emitBinary(emitShlI64, ValType::I64)); - case Expr::I64ShrS: + case uint16_t(Op::I64ShrS): CHECK_NEXT(emitBinary(emitShrI64, ValType::I64)); - case Expr::I64ShrU: + case uint16_t(Op::I64ShrU): CHECK_NEXT(emitBinary(emitShrU64, ValType::I64)); - case Expr::I64Rotr: + case uint16_t(Op::I64Rotr): CHECK_NEXT(emitBinary(emitRotrI64, ValType::I64)); - case Expr::I64Rotl: + case uint16_t(Op::I64Rotl): CHECK_NEXT(emitBinary(emitRotlI64, ValType::I64)); - case Expr::I64Clz: + case uint16_t(Op::I64Clz): CHECK_NEXT(emitUnary(emitClzI64, ValType::I64)); - case Expr::I64Ctz: + case uint16_t(Op::I64Ctz): CHECK_NEXT(emitUnary(emitCtzI64, ValType::I64)); - case Expr::I64Popcnt: + case uint16_t(Op::I64Popcnt): CHECK_NEXT(emitUnary(emitPopcntI64, ValType::I64)); - case Expr::I64Eqz: + case uint16_t(Op::I64Eqz): CHECK_NEXT(emitConversion(emitEqzI64, ValType::I64, ValType::I32)); - case Expr::I64Load8S: + case uint16_t(Op::I64Load8S): CHECK_NEXT(emitLoad(ValType::I64, Scalar::Int8)); - case Expr::I64Load16S: + case uint16_t(Op::I64Load16S): CHECK_NEXT(emitLoad(ValType::I64, Scalar::Int16)); - case Expr::I64Load32S: + case uint16_t(Op::I64Load32S): CHECK_NEXT(emitLoad(ValType::I64, Scalar::Int32)); - case Expr::I64Load8U: + case uint16_t(Op::I64Load8U): CHECK_NEXT(emitLoad(ValType::I64, Scalar::Uint8)); - case Expr::I64Load16U: + case uint16_t(Op::I64Load16U): CHECK_NEXT(emitLoad(ValType::I64, Scalar::Uint16)); - case Expr::I64Load32U: + case uint16_t(Op::I64Load32U): CHECK_NEXT(emitLoad(ValType::I64, Scalar::Uint32)); - case Expr::I64Load: + case uint16_t(Op::I64Load): CHECK_NEXT(emitLoad(ValType::I64, Scalar::Int64)); - case Expr::I64Store8: + case uint16_t(Op::I64Store8): CHECK_NEXT(emitStore(ValType::I64, Scalar::Int8)); - case Expr::I64TeeStore8: + case uint16_t(Op::I64TeeStore8): CHECK_NEXT(emitTeeStore(ValType::I64, Scalar::Int8)); - case Expr::I64Store16: + case uint16_t(Op::I64Store16): CHECK_NEXT(emitStore(ValType::I64, Scalar::Int16)); - case Expr::I64TeeStore16: + case uint16_t(Op::I64TeeStore16): CHECK_NEXT(emitTeeStore(ValType::I64, Scalar::Int16)); - case Expr::I64Store32: + case uint16_t(Op::I64Store32): CHECK_NEXT(emitStore(ValType::I64, Scalar::Int32)); - case Expr::I64TeeStore32: + case uint16_t(Op::I64TeeStore32): CHECK_NEXT(emitTeeStore(ValType::I64, Scalar::Int32)); - case Expr::I64Store: + case uint16_t(Op::I64Store): CHECK_NEXT(emitStore(ValType::I64, Scalar::Int64)); - case Expr::I64TeeStore: + case uint16_t(Op::I64TeeStore): CHECK_NEXT(emitTeeStore(ValType::I64, Scalar::Int64)); // F32 - case Expr::F32Const: { + case uint16_t(Op::F32Const): { RawF32 f32; CHECK(iter_.readF32Const(&f32)); if (!deadCode_) pushF32(f32); NEXT(); } - case Expr::F32Add: + case uint16_t(Op::F32Add): CHECK_NEXT(emitBinary(emitAddF32, ValType::F32)); - case Expr::F32Sub: + case uint16_t(Op::F32Sub): CHECK_NEXT(emitBinary(emitSubtractF32, ValType::F32)); - case Expr::F32Mul: + case uint16_t(Op::F32Mul): CHECK_NEXT(emitBinary(emitMultiplyF32, ValType::F32)); - case Expr::F32Div: + case uint16_t(Op::F32Div): CHECK_NEXT(emitBinary(emitDivideF32, ValType::F32)); - case Expr::F32Min: + case uint16_t(Op::F32Min): CHECK_NEXT(emitBinary(emitMinF32, ValType::F32)); - case Expr::F32Max: + case uint16_t(Op::F32Max): CHECK_NEXT(emitBinary(emitMaxF32, ValType::F32)); - case Expr::F32Neg: + case uint16_t(Op::F32Neg): CHECK_NEXT(emitUnary(emitNegateF32, ValType::F32)); - case Expr::F32Abs: + case uint16_t(Op::F32Abs): CHECK_NEXT(emitUnary(emitAbsF32, ValType::F32)); - case Expr::F32Sqrt: + case uint16_t(Op::F32Sqrt): CHECK_NEXT(emitUnary(emitSqrtF32, ValType::F32)); - case Expr::F32Ceil: + case uint16_t(Op::F32Ceil): CHECK_NEXT(emitUnaryMathBuiltinCall(SymbolicAddress::CeilF, ValType::F32)); - case Expr::F32Floor: + case uint16_t(Op::F32Floor): CHECK_NEXT(emitUnaryMathBuiltinCall(SymbolicAddress::FloorF, ValType::F32)); - case Expr::F32DemoteF64: + case uint16_t(Op::F32DemoteF64): CHECK_NEXT(emitConversion(emitConvertF64ToF32, ValType::F64, ValType::F32)); - case Expr::F32ConvertSI32: + case uint16_t(Op::F32ConvertSI32): CHECK_NEXT(emitConversion(emitConvertI32ToF32, ValType::I32, ValType::F32)); - case Expr::F32ConvertUI32: + case uint16_t(Op::F32ConvertUI32): CHECK_NEXT(emitConversion(emitConvertU32ToF32, ValType::I32, ValType::F32)); - case Expr::F32ConvertSI64: + case uint16_t(Op::F32ConvertSI64): #ifdef I64_TO_FLOAT_CALLOUT CHECK_NEXT(emitCalloutConversionOOM(emitConvertInt64ToFloatingCallout, SymbolicAddress::Int64ToFloatingPoint, ValType::I64, ValType::F32)); #else CHECK_NEXT(emitConversion(emitConvertI64ToF32, ValType::I64, ValType::F32)); #endif - case Expr::F32ConvertUI64: + case uint16_t(Op::F32ConvertUI64): #ifdef I64_TO_FLOAT_CALLOUT CHECK_NEXT(emitCalloutConversionOOM(emitConvertInt64ToFloatingCallout, SymbolicAddress::Uint64ToFloatingPoint, ValType::I64, ValType::F32)); #else CHECK_NEXT(emitConversion(emitConvertU64ToF32, ValType::I64, ValType::F32)); #endif - case Expr::F32ReinterpretI32: + case uint16_t(Op::F32ReinterpretI32): CHECK_NEXT(emitConversion(emitReinterpretI32AsF32, ValType::I32, ValType::F32)); - case Expr::F32Load: + case uint16_t(Op::F32Load): CHECK_NEXT(emitLoad(ValType::F32, Scalar::Float32)); - case Expr::F32Store: + case uint16_t(Op::F32Store): CHECK_NEXT(emitStore(ValType::F32, Scalar::Float32)); - case Expr::F32TeeStore: + case uint16_t(Op::F32TeeStore): CHECK_NEXT(emitTeeStore(ValType::F32, Scalar::Float32)); - case Expr::F32TeeStoreF64: + case uint16_t(Op::F32TeeStoreF64): CHECK_NEXT(emitTeeStoreWithCoercion(ValType::F32, Scalar::Float64)); - case Expr::F32CopySign: + case uint16_t(Op::F32CopySign): CHECK_NEXT(emitBinary(emitCopysignF32, ValType::F32)); - case Expr::F32Nearest: + case uint16_t(Op::F32Nearest): CHECK_NEXT(emitUnaryMathBuiltinCall(SymbolicAddress::NearbyIntF, ValType::F32)); - case Expr::F32Trunc: + case uint16_t(Op::F32Trunc): CHECK_NEXT(emitUnaryMathBuiltinCall(SymbolicAddress::TruncF, ValType::F32)); // F64 - case Expr::F64Const: { + case uint16_t(Op::F64Const): { RawF64 f64; CHECK(iter_.readF64Const(&f64)); if (!deadCode_) pushF64(f64); NEXT(); } - case Expr::F64Add: + case uint16_t(Op::F64Add): CHECK_NEXT(emitBinary(emitAddF64, ValType::F64)); - case Expr::F64Sub: + case uint16_t(Op::F64Sub): CHECK_NEXT(emitBinary(emitSubtractF64, ValType::F64)); - case Expr::F64Mul: + case uint16_t(Op::F64Mul): CHECK_NEXT(emitBinary(emitMultiplyF64, ValType::F64)); - case Expr::F64Div: + case uint16_t(Op::F64Div): CHECK_NEXT(emitBinary(emitDivideF64, ValType::F64)); - case Expr::F64Mod: + case uint16_t(Op::F64Mod): CHECK_NEXT(emitBinaryMathBuiltinCall(SymbolicAddress::ModD, ValType::F64)); - case Expr::F64Min: + case uint16_t(Op::F64Min): CHECK_NEXT(emitBinary(emitMinF64, ValType::F64)); - case Expr::F64Max: + case uint16_t(Op::F64Max): CHECK_NEXT(emitBinary(emitMaxF64, ValType::F64)); - case Expr::F64Neg: + case uint16_t(Op::F64Neg): CHECK_NEXT(emitUnary(emitNegateF64, ValType::F64)); - case Expr::F64Abs: + case uint16_t(Op::F64Abs): CHECK_NEXT(emitUnary(emitAbsF64, ValType::F64)); - case Expr::F64Sqrt: + case uint16_t(Op::F64Sqrt): CHECK_NEXT(emitUnary(emitSqrtF64, ValType::F64)); - case Expr::F64Ceil: + case uint16_t(Op::F64Ceil): CHECK_NEXT(emitUnaryMathBuiltinCall(SymbolicAddress::CeilD, ValType::F64)); - case Expr::F64Floor: + case uint16_t(Op::F64Floor): CHECK_NEXT(emitUnaryMathBuiltinCall(SymbolicAddress::FloorD, ValType::F64)); - case Expr::F64Sin: + case uint16_t(Op::F64Sin): CHECK_NEXT(emitUnaryMathBuiltinCall(SymbolicAddress::SinD, ValType::F64)); - case Expr::F64Cos: + case uint16_t(Op::F64Cos): CHECK_NEXT(emitUnaryMathBuiltinCall(SymbolicAddress::CosD, ValType::F64)); - case Expr::F64Tan: + case uint16_t(Op::F64Tan): CHECK_NEXT(emitUnaryMathBuiltinCall(SymbolicAddress::TanD, ValType::F64)); - case Expr::F64Asin: + case uint16_t(Op::F64Asin): CHECK_NEXT(emitUnaryMathBuiltinCall(SymbolicAddress::ASinD, ValType::F64)); - case Expr::F64Acos: + case uint16_t(Op::F64Acos): CHECK_NEXT(emitUnaryMathBuiltinCall(SymbolicAddress::ACosD, ValType::F64)); - case Expr::F64Atan: + case uint16_t(Op::F64Atan): CHECK_NEXT(emitUnaryMathBuiltinCall(SymbolicAddress::ATanD, ValType::F64)); - case Expr::F64Exp: + case uint16_t(Op::F64Exp): CHECK_NEXT(emitUnaryMathBuiltinCall(SymbolicAddress::ExpD, ValType::F64)); - case Expr::F64Log: + case uint16_t(Op::F64Log): CHECK_NEXT(emitUnaryMathBuiltinCall(SymbolicAddress::LogD, ValType::F64)); - case Expr::F64Pow: + case uint16_t(Op::F64Pow): CHECK_NEXT(emitBinaryMathBuiltinCall(SymbolicAddress::PowD, ValType::F64)); - case Expr::F64Atan2: + case uint16_t(Op::F64Atan2): CHECK_NEXT(emitBinaryMathBuiltinCall(SymbolicAddress::ATan2D, ValType::F64)); - case Expr::F64PromoteF32: + case uint16_t(Op::F64PromoteF32): CHECK_NEXT(emitConversion(emitConvertF32ToF64, ValType::F32, ValType::F64)); - case Expr::F64ConvertSI32: + case uint16_t(Op::F64ConvertSI32): CHECK_NEXT(emitConversion(emitConvertI32ToF64, ValType::I32, ValType::F64)); - case Expr::F64ConvertUI32: + case uint16_t(Op::F64ConvertUI32): CHECK_NEXT(emitConversion(emitConvertU32ToF64, ValType::I32, ValType::F64)); - case Expr::F64ConvertSI64: + case uint16_t(Op::F64ConvertSI64): #ifdef I64_TO_FLOAT_CALLOUT CHECK_NEXT(emitCalloutConversionOOM(emitConvertInt64ToFloatingCallout, SymbolicAddress::Int64ToFloatingPoint, ValType::I64, ValType::F64)); #else CHECK_NEXT(emitConversion(emitConvertI64ToF64, ValType::I64, ValType::F64)); #endif - case Expr::F64ConvertUI64: + case uint16_t(Op::F64ConvertUI64): #ifdef I64_TO_FLOAT_CALLOUT CHECK_NEXT(emitCalloutConversionOOM(emitConvertInt64ToFloatingCallout, SymbolicAddress::Uint64ToFloatingPoint, ValType::I64, ValType::F64)); #else CHECK_NEXT(emitConversion(emitConvertU64ToF64, ValType::I64, ValType::F64)); #endif - case Expr::F64Load: + case uint16_t(Op::F64Load): CHECK_NEXT(emitLoad(ValType::F64, Scalar::Float64)); - case Expr::F64Store: + case uint16_t(Op::F64Store): CHECK_NEXT(emitStore(ValType::F64, Scalar::Float64)); - case Expr::F64TeeStore: + case uint16_t(Op::F64TeeStore): CHECK_NEXT(emitTeeStore(ValType::F64, Scalar::Float64)); - case Expr::F64TeeStoreF32: + case uint16_t(Op::F64TeeStoreF32): CHECK_NEXT(emitTeeStoreWithCoercion(ValType::F64, Scalar::Float32)); - case Expr::F64ReinterpretI64: + case uint16_t(Op::F64ReinterpretI64): CHECK_NEXT(emitConversion(emitReinterpretI64AsF64, ValType::I64, ValType::F64)); - case Expr::F64CopySign: + case uint16_t(Op::F64CopySign): CHECK_NEXT(emitBinary(emitCopysignF64, ValType::F64)); - case Expr::F64Nearest: + case uint16_t(Op::F64Nearest): CHECK_NEXT(emitUnaryMathBuiltinCall(SymbolicAddress::NearbyIntD, ValType::F64)); - case Expr::F64Trunc: + case uint16_t(Op::F64Trunc): CHECK_NEXT(emitUnaryMathBuiltinCall(SymbolicAddress::TruncD, ValType::F64)); // Comparisons - case Expr::I32Eq: + case uint16_t(Op::I32Eq): CHECK_NEXT(emitComparison(emitCompareI32, ValType::I32, JSOP_EQ, MCompare::Compare_Int32)); - case Expr::I32Ne: + case uint16_t(Op::I32Ne): CHECK_NEXT(emitComparison(emitCompareI32, ValType::I32, JSOP_NE, MCompare::Compare_Int32)); - case Expr::I32LtS: + case uint16_t(Op::I32LtS): CHECK_NEXT(emitComparison(emitCompareI32, ValType::I32, JSOP_LT, MCompare::Compare_Int32)); - case Expr::I32LeS: + case uint16_t(Op::I32LeS): CHECK_NEXT(emitComparison(emitCompareI32, ValType::I32, JSOP_LE, MCompare::Compare_Int32)); - case Expr::I32GtS: + case uint16_t(Op::I32GtS): CHECK_NEXT(emitComparison(emitCompareI32, ValType::I32, JSOP_GT, MCompare::Compare_Int32)); - case Expr::I32GeS: + case uint16_t(Op::I32GeS): CHECK_NEXT(emitComparison(emitCompareI32, ValType::I32, JSOP_GE, MCompare::Compare_Int32)); - case Expr::I32LtU: + case uint16_t(Op::I32LtU): CHECK_NEXT(emitComparison(emitCompareI32, ValType::I32, JSOP_LT, MCompare::Compare_UInt32)); - case Expr::I32LeU: + case uint16_t(Op::I32LeU): CHECK_NEXT(emitComparison(emitCompareI32, ValType::I32, JSOP_LE, MCompare::Compare_UInt32)); - case Expr::I32GtU: + case uint16_t(Op::I32GtU): CHECK_NEXT(emitComparison(emitCompareI32, ValType::I32, JSOP_GT, MCompare::Compare_UInt32)); - case Expr::I32GeU: + case uint16_t(Op::I32GeU): CHECK_NEXT(emitComparison(emitCompareI32, ValType::I32, JSOP_GE, MCompare::Compare_UInt32)); - case Expr::I64Eq: + case uint16_t(Op::I64Eq): CHECK_NEXT(emitComparison(emitCompareI64, ValType::I64, JSOP_EQ, MCompare::Compare_Int64)); - case Expr::I64Ne: + case uint16_t(Op::I64Ne): CHECK_NEXT(emitComparison(emitCompareI64, ValType::I64, JSOP_NE, MCompare::Compare_Int64)); - case Expr::I64LtS: + case uint16_t(Op::I64LtS): CHECK_NEXT(emitComparison(emitCompareI64, ValType::I64, JSOP_LT, MCompare::Compare_Int64)); - case Expr::I64LeS: + case uint16_t(Op::I64LeS): CHECK_NEXT(emitComparison(emitCompareI64, ValType::I64, JSOP_LE, MCompare::Compare_Int64)); - case Expr::I64GtS: + case uint16_t(Op::I64GtS): CHECK_NEXT(emitComparison(emitCompareI64, ValType::I64, JSOP_GT, MCompare::Compare_Int64)); - case Expr::I64GeS: + case uint16_t(Op::I64GeS): CHECK_NEXT(emitComparison(emitCompareI64, ValType::I64, JSOP_GE, MCompare::Compare_Int64)); - case Expr::I64LtU: + case uint16_t(Op::I64LtU): CHECK_NEXT(emitComparison(emitCompareI64, ValType::I64, JSOP_LT, MCompare::Compare_UInt64)); - case Expr::I64LeU: + case uint16_t(Op::I64LeU): CHECK_NEXT(emitComparison(emitCompareI64, ValType::I64, JSOP_LE, MCompare::Compare_UInt64)); - case Expr::I64GtU: + case uint16_t(Op::I64GtU): CHECK_NEXT(emitComparison(emitCompareI64, ValType::I64, JSOP_GT, MCompare::Compare_UInt64)); - case Expr::I64GeU: + case uint16_t(Op::I64GeU): CHECK_NEXT(emitComparison(emitCompareI64, ValType::I64, JSOP_GE, MCompare::Compare_UInt64)); - case Expr::F32Eq: + case uint16_t(Op::F32Eq): CHECK_NEXT(emitComparison(emitCompareF32, ValType::F32, JSOP_EQ, MCompare::Compare_Float32)); - case Expr::F32Ne: + case uint16_t(Op::F32Ne): CHECK_NEXT(emitComparison(emitCompareF32, ValType::F32, JSOP_NE, MCompare::Compare_Float32)); - case Expr::F32Lt: + case uint16_t(Op::F32Lt): CHECK_NEXT(emitComparison(emitCompareF32, ValType::F32, JSOP_LT, MCompare::Compare_Float32)); - case Expr::F32Le: + case uint16_t(Op::F32Le): CHECK_NEXT(emitComparison(emitCompareF32, ValType::F32, JSOP_LE, MCompare::Compare_Float32)); - case Expr::F32Gt: + case uint16_t(Op::F32Gt): CHECK_NEXT(emitComparison(emitCompareF32, ValType::F32, JSOP_GT, MCompare::Compare_Float32)); - case Expr::F32Ge: + case uint16_t(Op::F32Ge): CHECK_NEXT(emitComparison(emitCompareF32, ValType::F32, JSOP_GE, MCompare::Compare_Float32)); - case Expr::F64Eq: + case uint16_t(Op::F64Eq): CHECK_NEXT(emitComparison(emitCompareF64, ValType::F64, JSOP_EQ, MCompare::Compare_Double)); - case Expr::F64Ne: + case uint16_t(Op::F64Ne): CHECK_NEXT(emitComparison(emitCompareF64, ValType::F64, JSOP_NE, MCompare::Compare_Double)); - case Expr::F64Lt: + case uint16_t(Op::F64Lt): CHECK_NEXT(emitComparison(emitCompareF64, ValType::F64, JSOP_LT, MCompare::Compare_Double)); - case Expr::F64Le: + case uint16_t(Op::F64Le): CHECK_NEXT(emitComparison(emitCompareF64, ValType::F64, JSOP_LE, MCompare::Compare_Double)); - case Expr::F64Gt: + case uint16_t(Op::F64Gt): CHECK_NEXT(emitComparison(emitCompareF64, ValType::F64, JSOP_GT, MCompare::Compare_Double)); - case Expr::F64Ge: + case uint16_t(Op::F64Ge): CHECK_NEXT(emitComparison(emitCompareF64, ValType::F64, JSOP_GE, MCompare::Compare_Double)); // SIMD #define CASE(TYPE, OP, SIGN) \ - case Expr::TYPE##OP: \ + case uint16_t(Op::TYPE##OP): \ MOZ_CRASH("Unimplemented SIMD"); #define I8x16CASE(OP) CASE(I8x16, OP, SimdSign::Signed) #define I16x8CASE(OP) CASE(I16x8, OP, SimdSign::Signed) #define I32x4CASE(OP) CASE(I32x4, OP, SimdSign::Signed) #define F32x4CASE(OP) CASE(F32x4, OP, SimdSign::NotApplicable) #define B8x16CASE(OP) CASE(B8x16, OP, SimdSign::NotApplicable) #define B16x8CASE(OP) CASE(B16x8, OP, SimdSign::NotApplicable) #define B32x4CASE(OP) CASE(B32x4, OP, SimdSign::NotApplicable) #define ENUMERATE(TYPE, FORALL, DO) \ - case Expr::TYPE##Constructor: \ + case uint16_t(Op::TYPE##Constructor): \ FORALL(DO) ENUMERATE(I8x16, FORALL_INT8X16_ASMJS_OP, I8x16CASE) ENUMERATE(I16x8, FORALL_INT16X8_ASMJS_OP, I16x8CASE) ENUMERATE(I32x4, FORALL_INT32X4_ASMJS_OP, I32x4CASE) ENUMERATE(F32x4, FORALL_FLOAT32X4_ASMJS_OP, F32x4CASE) ENUMERATE(B8x16, FORALL_BOOL_SIMD_OP, B8x16CASE) ENUMERATE(B16x8, FORALL_BOOL_SIMD_OP, B16x8CASE) @@ -7123,62 +7123,60 @@ BaseCompiler::emitBody() #undef I16x8CASE #undef I32x4CASE #undef F32x4CASE #undef B8x16CASE #undef B16x8CASE #undef B32x4CASE #undef ENUMERATE - case Expr::I8x16Const: - case Expr::I16x8Const: - case Expr::I32x4Const: - case Expr::F32x4Const: - case Expr::B8x16Const: - case Expr::B16x8Const: - case Expr::B32x4Const: - case Expr::I32x4shiftRightByScalarU: - case Expr::I8x16addSaturateU: - case Expr::I8x16subSaturateU: - case Expr::I8x16shiftRightByScalarU: - case Expr::I8x16lessThanU: - case Expr::I8x16lessThanOrEqualU: - case Expr::I8x16greaterThanU: - case Expr::I8x16greaterThanOrEqualU: - case Expr::I8x16extractLaneU: - case Expr::I16x8addSaturateU: - case Expr::I16x8subSaturateU: - case Expr::I16x8shiftRightByScalarU: - case Expr::I16x8lessThanU: - case Expr::I16x8lessThanOrEqualU: - case Expr::I16x8greaterThanU: - case Expr::I16x8greaterThanOrEqualU: - case Expr::I16x8extractLaneU: - case Expr::I32x4lessThanU: - case Expr::I32x4lessThanOrEqualU: - case Expr::I32x4greaterThanU: - case Expr::I32x4greaterThanOrEqualU: - case Expr::I32x4fromFloat32x4U: + case uint16_t(Op::I8x16Const): + case uint16_t(Op::I16x8Const): + case uint16_t(Op::I32x4Const): + case uint16_t(Op::F32x4Const): + case uint16_t(Op::B8x16Const): + case uint16_t(Op::B16x8Const): + case uint16_t(Op::B32x4Const): + case uint16_t(Op::I32x4shiftRightByScalarU): + case uint16_t(Op::I8x16addSaturateU): + case uint16_t(Op::I8x16subSaturateU): + case uint16_t(Op::I8x16shiftRightByScalarU): + case uint16_t(Op::I8x16lessThanU): + case uint16_t(Op::I8x16lessThanOrEqualU): + case uint16_t(Op::I8x16greaterThanU): + case uint16_t(Op::I8x16greaterThanOrEqualU): + case uint16_t(Op::I8x16extractLaneU): + case uint16_t(Op::I16x8addSaturateU): + case uint16_t(Op::I16x8subSaturateU): + case uint16_t(Op::I16x8shiftRightByScalarU): + case uint16_t(Op::I16x8lessThanU): + case uint16_t(Op::I16x8lessThanOrEqualU): + case uint16_t(Op::I16x8greaterThanU): + case uint16_t(Op::I16x8greaterThanOrEqualU): + case uint16_t(Op::I16x8extractLaneU): + case uint16_t(Op::I32x4lessThanU): + case uint16_t(Op::I32x4lessThanOrEqualU): + case uint16_t(Op::I32x4greaterThanU): + case uint16_t(Op::I32x4greaterThanOrEqualU): + case uint16_t(Op::I32x4fromFloat32x4U): MOZ_CRASH("Unimplemented SIMD"); // Atomics - case Expr::I32AtomicsLoad: - case Expr::I32AtomicsStore: - case Expr::I32AtomicsBinOp: - case Expr::I32AtomicsCompareExchange: - case Expr::I32AtomicsExchange: + case uint16_t(Op::I32AtomicsLoad): + case uint16_t(Op::I32AtomicsStore): + case uint16_t(Op::I32AtomicsBinOp): + case uint16_t(Op::I32AtomicsCompareExchange): + case uint16_t(Op::I32AtomicsExchange): MOZ_CRASH("Unimplemented Atomics"); // Memory Related - case Expr::GrowMemory: + case uint16_t(Op::GrowMemory): CHECK_NEXT(emitGrowMemory()); - case Expr::CurrentMemory: + case uint16_t(Op::CurrentMemory): CHECK_NEXT(emitCurrentMemory()); - - case Expr::Limit:; } MOZ_CRASH("unexpected wasm opcode"); #undef CHECK #undef NEXT #undef CHECK_NEXT #undef emitBinary @@ -7451,17 +7449,17 @@ js::wasm::BaselineCompileFunction(IonCom Decoder d(func.bytes()); // Build the local types vector. ValTypeVector locals; if (!locals.appendAll(func.sig().args())) return false; - if (!DecodeLocalEntries(d, &locals)) + if (!DecodeLocalEntries(d, task->mg().kind, &locals)) return false; // The MacroAssembler will sometimes access the jitContext. JitContext jitContext(&results.alloc()); // One-pass baseline compilation.
--- a/js/src/wasm/WasmBinaryConstants.h +++ b/js/src/wasm/WasmBinaryConstants.h @@ -64,22 +64,20 @@ enum class TypeCode AnyFunc = 0x70, // SLEB128(-0x10) // Type constructor for function types Func = 0x60, // SLEB128(-0x20) // Special code representing the block signature ()->() BlockVoid = 0x40, // SLEB128(-0x40) - // Type codes currently always fit in a single byte - Max = 0x7f, Limit = 0x80 }; -enum class ValType : uint32_t // fix type so we can cast from any u8 in decoder +enum class ValType { I32 = uint8_t(TypeCode::I32), I64 = uint8_t(TypeCode::I64), F32 = uint8_t(TypeCode::F32), F64 = uint8_t(TypeCode::F64), // ------------------------------------------------------------------------ // The rest of these types are currently only emitted internally when @@ -110,17 +108,17 @@ enum class GlobalFlags AllowedMask = 0x1 }; enum class MemoryTableFlags { Default = 0x0 }; -enum class Expr : uint32_t // fix type so we can cast from any u16 in decoder +enum class Op { // Control flow operators Unreachable = 0x00, Nop = 0x01, Block = 0x02, Loop = 0x03, If = 0x04, Else = 0x05,
--- a/js/src/wasm/WasmBinaryFormat.cpp +++ b/js/src/wasm/WasmBinaryFormat.cpp @@ -38,31 +38,44 @@ wasm::DecodePreamble(Decoder& d) if (!d.readFixedU32(&u32) || u32 != EncodingVersion) return d.fail("binary version 0x%" PRIx32 " does not match expected version 0x%" PRIx32, u32, EncodingVersion); return true; } -bool -wasm::CheckValType(Decoder& d, ValType type) +static bool +DecodeValType(Decoder& d, ModuleKind kind, ValType* type) { - switch (type) { - case ValType::I32: - case ValType::F32: - case ValType::F64: - case ValType::I64: + uint8_t unchecked; + if (!d.readValType(&unchecked)) + return false; + + switch (unchecked) { + case uint8_t(ValType::I32): + case uint8_t(ValType::F32): + case uint8_t(ValType::F64): + case uint8_t(ValType::I64): + *type = ValType(unchecked); + return true; + case uint8_t(ValType::I8x16): + case uint8_t(ValType::I16x8): + case uint8_t(ValType::I32x4): + case uint8_t(ValType::F32x4): + case uint8_t(ValType::B8x16): + case uint8_t(ValType::B16x8): + case uint8_t(ValType::B32x4): + if (kind != ModuleKind::AsmJS) + return d.fail("bad type"); + *type = ValType(unchecked); return true; default: - // Note: it's important not to remove this default since readValType() - // can return ValType values for which there is no enumerator. break; } - return d.fail("bad type"); } bool wasm::DecodeTypeSection(Decoder& d, SigWithIdVector* sigs) { uint32_t sectionStart, sectionSize; if (!d.startSection(SectionId::Type, §ionStart, §ionSize, "type")) @@ -92,38 +105,32 @@ wasm::DecodeTypeSection(Decoder& d, SigW if (numArgs > MaxArgsPerFunc) return d.fail("too many arguments in signature"); ValTypeVector args; if (!args.resize(numArgs)) return false; for (uint32_t i = 0; i < numArgs; i++) { - if (!d.readValType(&args[i])) - return d.fail("bad value type"); - - if (!CheckValType(d, args[i])) + if (!DecodeValType(d, ModuleKind::Wasm, &args[i])) return false; } uint32_t numRets; if (!d.readVarU32(&numRets)) return d.fail("bad number of function returns"); if (numRets > 1) return d.fail("too many returns in signature"); ExprType result = ExprType::Void; if (numRets == 1) { ValType type; - if (!d.readValType(&type)) - return d.fail("bad expression type"); - - if (!CheckValType(d, type)) + if (!DecodeValType(d, ModuleKind::Wasm, &type)) return false; result = ToExprType(type); } (*sigs)[sigIndex] = Sig(Move(args), result); } @@ -362,96 +369,96 @@ wasm::EncodeLocalEntries(Encoder& e, con if (!e.writeValType(prev)) return false; } return true; } bool -wasm::DecodeLocalEntries(Decoder& d, ValTypeVector* locals) +wasm::DecodeLocalEntries(Decoder& d, ModuleKind kind, ValTypeVector* locals) { uint32_t numLocalEntries; if (!d.readVarU32(&numLocalEntries)) - return false; + return d.fail("failed to read number of local entries"); for (uint32_t i = 0; i < numLocalEntries; i++) { uint32_t count; if (!d.readVarU32(&count)) - return false; + return d.fail("failed to read local entry count"); if (MaxLocals - locals->length() < count) - return false; + return d.fail("too many locals"); ValType type; - if (!d.readValType(&type)) + if (!DecodeValType(d, kind, &type)) return false; if (!locals->appendN(type, count)) return false; } return true; } bool wasm::DecodeGlobalType(Decoder& d, ValType* type, bool* isMutable) { - if (!d.readValType(type)) - return d.fail("bad global type"); + if (!DecodeValType(d, ModuleKind::Wasm, type)) + return false; uint32_t flags; if (!d.readVarU32(&flags)) return d.fail("expected global flags"); if (flags & ~uint32_t(GlobalFlags::AllowedMask)) return d.fail("unexpected bits set in global flags"); *isMutable = flags & uint32_t(GlobalFlags::IsMutable); return true; } bool wasm::DecodeInitializerExpression(Decoder& d, const GlobalDescVector& globals, ValType expected, InitExpr* init) { - Expr expr; - if (!d.readExpr(&expr)) + uint16_t op; + if (!d.readOp(&op)) return d.fail("failed to read initializer type"); - switch (expr) { - case Expr::I32Const: { + switch (op) { + case uint16_t(Op::I32Const): { int32_t i32; if (!d.readVarS32(&i32)) return d.fail("failed to read initializer i32 expression"); *init = InitExpr(Val(uint32_t(i32))); break; } - case Expr::I64Const: { + case uint16_t(Op::I64Const): { int64_t i64; if (!d.readVarS64(&i64)) return d.fail("failed to read initializer i64 expression"); *init = InitExpr(Val(uint64_t(i64))); break; } - case Expr::F32Const: { + case uint16_t(Op::F32Const): { RawF32 f32; if (!d.readFixedF32(&f32)) return d.fail("failed to read initializer f32 expression"); *init = InitExpr(Val(f32)); break; } - case Expr::F64Const: { + case uint16_t(Op::F64Const): { RawF64 f64; if (!d.readFixedF64(&f64)) return d.fail("failed to read initializer f64 expression"); *init = InitExpr(Val(f64)); break; } - case Expr::GetGlobal: { + case uint16_t(Op::GetGlobal): { uint32_t i; if (!d.readVarU32(&i)) return d.fail("failed to read get_global index in initializer expression"); if (i >= globals.length()) return d.fail("global index out of range in initializer expression"); if (!globals[i].isImport() || globals[i].isMutable()) return d.fail("initializer expression must reference a global immutable import"); *init = InitExpr(i, globals[i].type()); @@ -460,18 +467,18 @@ wasm::DecodeInitializerExpression(Decode default: { return d.fail("unexpected initializer expression"); } } if (expected != init->type()) return d.fail("type mismatch: initializer type and expected type don't match"); - Expr end; - if (!d.readExpr(&end) || end != Expr::End) + uint16_t end; + if (!d.readOp(&end) || end != uint16_t(Op::End)) return d.fail("failed to read end of initializer expression"); return true; } bool wasm::DecodeLimits(Decoder& d, Limits* limits) {
--- a/js/src/wasm/WasmBinaryFormat.h +++ b/js/src/wasm/WasmBinaryFormat.h @@ -93,18 +93,16 @@ class Encoder uint32_t varU32ByteLength(size_t offset) const { size_t start = offset; while (bytes_[offset] & 0x80) offset++; return offset - start + 1; } - static const size_t ExprLimit = 2 * UINT8_MAX - 1; - public: explicit Encoder(Bytes& bytes) : bytes_(bytes) { MOZ_ASSERT(empty()); } size_t currentOffset() const { return bytes_.length(); } @@ -152,31 +150,32 @@ class Encoder } MOZ_MUST_USE bool writeVarU64(uint64_t i) { return writeVarU<uint64_t>(i); } MOZ_MUST_USE bool writeVarS64(int64_t i) { return writeVarS<int64_t>(i); } MOZ_MUST_USE bool writeValType(ValType type) { - static_assert(size_t(TypeCode::Max) <= INT8_MAX, "fits"); - MOZ_ASSERT(size_t(type) <= size_t(TypeCode::Max)); + static_assert(size_t(TypeCode::Limit) <= UINT8_MAX, "fits"); + MOZ_ASSERT(size_t(type) < size_t(TypeCode::Limit)); return writeFixedU8(uint8_t(type)); } MOZ_MUST_USE bool writeBlockType(ExprType type) { - static_assert(size_t(TypeCode::Max) <= INT8_MAX, "fits"); - MOZ_ASSERT(size_t(type) <= size_t(TypeCode::Max)); + static_assert(size_t(TypeCode::Limit) <= UINT8_MAX, "fits"); + MOZ_ASSERT(size_t(type) < size_t(TypeCode::Limit)); return writeFixedU8(uint8_t(type)); } - MOZ_MUST_USE bool writeExpr(Expr expr) { - static_assert(size_t(Expr::Limit) <= ExprLimit, "fits"); - if (size_t(expr) < UINT8_MAX) - return writeFixedU8(uint8_t(expr)); + MOZ_MUST_USE bool writeOp(Op op) { + static_assert(size_t(Op::Limit) <= 2 * UINT8_MAX, "fits"); + MOZ_ASSERT(size_t(op) < size_t(Op::Limit)); + if (size_t(op) < UINT8_MAX) + return writeFixedU8(uint8_t(op)); return writeFixedU8(UINT8_MAX) && - writeFixedU8(size_t(expr) - UINT8_MAX); + writeFixedU8(size_t(op) - UINT8_MAX); } // Fixed-length encodings that allow back-patching. MOZ_MUST_USE bool writePatchableFixedU7(size_t* offset) { *offset = bytes_.length(); return writeFixedU8(UINT8_MAX); } @@ -303,18 +302,16 @@ class Decoder return false; uint8_t mask = 0x7f & (uint8_t(-1) << remainderBits); if ((byte & mask) != ((byte & (1 << (remainderBits - 1))) ? mask : 0)) return false; *out = s | SInt(byte) << shift; return true; } - static const size_t ExprLimit = 2 * UINT8_MAX - 1; - public: Decoder(const uint8_t* begin, const uint8_t* end, UniqueChars* error) : beg_(begin), end_(end), cur_(begin), error_(error) { MOZ_ASSERT(begin <= end); @@ -397,46 +394,36 @@ class Decoder return readVarS<int32_t>(out); } MOZ_MUST_USE bool readVarU64(uint64_t* out) { return readVarU<uint64_t>(out); } MOZ_MUST_USE bool readVarS64(int64_t* out) { return readVarS<int64_t>(out); } - MOZ_MUST_USE bool readValType(ValType* type) { - static_assert(uint8_t(TypeCode::Max) <= INT8_MAX, "fits"); + MOZ_MUST_USE bool readValType(uint8_t* type) { + static_assert(uint8_t(TypeCode::Limit) <= UINT8_MAX, "fits"); + return readFixedU8(type); + } + MOZ_MUST_USE bool readBlockType(uint8_t* type) { + static_assert(size_t(TypeCode::Limit) <= UINT8_MAX, "fits"); + return readFixedU8(type); + } + MOZ_MUST_USE bool readOp(uint16_t* op) { + static_assert(size_t(Op::Limit) <= 2 * UINT8_MAX, "fits"); uint8_t u8; if (!readFixedU8(&u8)) return false; - *type = (ValType)u8; - return true; - } - MOZ_MUST_USE bool readBlockType(ExprType* type) { - static_assert(size_t(TypeCode::Max) <= INT8_MAX, "fits"); - uint8_t u8; - if (!readFixedU8(&u8)) - return false; - *type = (ExprType)u8; - return true; - } - MOZ_MUST_USE bool readExpr(Expr* expr) { - static_assert(size_t(Expr::Limit) <= ExprLimit, "fits"); - uint8_t u8; - if (!readFixedU8(&u8)) - return false; - if (u8 != UINT8_MAX) { - *expr = Expr(u8); + if (MOZ_LIKELY(u8 != UINT8_MAX)) { + *op = u8; return true; } if (!readFixedU8(&u8)) return false; - if (u8 == UINT8_MAX) - return false; - *expr = Expr(uint16_t(u8) + UINT8_MAX); + *op = uint16_t(u8) + UINT8_MAX; return true; } // See writeBytes comment. MOZ_MUST_USE bool readBytes(uint32_t numBytes, const uint8_t** bytes = nullptr) { if (bytes) *bytes = cur_; @@ -597,22 +584,22 @@ class Decoder int64_t uncheckedReadVarS64() { int64_t i64 = 0; MOZ_ALWAYS_TRUE(readVarS64(&i64)); return i64; } ValType uncheckedReadValType() { return (ValType)uncheckedReadFixedU8(); } - Expr uncheckedReadExpr() { - static_assert(size_t(Expr::Limit) <= ExprLimit, "fits"); + Op uncheckedReadOp() { + static_assert(size_t(Op::Limit) <= 2 * UINT8_MAX, "fits"); uint8_t u8 = uncheckedReadFixedU8(); return u8 != UINT8_MAX - ? Expr(u8) - : Expr(uncheckedReadFixedU8() + UINT8_MAX); + ? Op(u8) + : Op(uncheckedReadFixedU8() + UINT8_MAX); } void uncheckedReadFixedI8x16(I8x16* i8x16) { struct T { I8x16 v; }; T t = uncheckedRead<T>(); memcpy(i8x16, &t, sizeof(t)); } void uncheckedReadFixedI16x8(I16x8* i16x8) { struct T { I16x8 v; }; @@ -632,33 +619,30 @@ class Decoder }; // Reusable macro encoding/decoding functions reused by both the two // encoders (AsmJS/WasmTextToBinary) and all the decoders // (WasmCompile/WasmIonCompile/WasmBaselineCompile/WasmBinaryToText). // Misc helpers. -MOZ_MUST_USE bool -CheckValType(Decoder& d, ValType type); - UniqueChars DecodeName(Decoder& d); MOZ_MUST_USE bool DecodeTableLimits(Decoder& d, TableDescVector* tables); MOZ_MUST_USE bool GlobalIsJSCompatible(Decoder& d, ValType type, bool isMutable); MOZ_MUST_USE bool EncodeLocalEntries(Encoder& d, const ValTypeVector& locals); MOZ_MUST_USE bool -DecodeLocalEntries(Decoder& d, ValTypeVector* locals); +DecodeLocalEntries(Decoder& d, ModuleKind kind, ValTypeVector* locals); MOZ_MUST_USE bool DecodeGlobalType(Decoder& d, ValType* type, bool* isMutable); MOZ_MUST_USE bool DecodeInitializerExpression(Decoder& d, const GlobalDescVector& globals, ValType expected, InitExpr* init);
--- a/js/src/wasm/WasmBinaryIterator.cpp +++ b/js/src/wasm/WasmBinaryIterator.cpp @@ -18,481 +18,481 @@ #include "wasm/WasmBinaryIterator.h" using namespace js; using namespace js::jit; using namespace js::wasm; #ifdef DEBUG -ExprKind -wasm::Classify(Expr expr) +OpKind +wasm::Classify(Op op) { - switch (expr) { - case Expr::Block: - return ExprKind::Block; - case Expr::Loop: - return ExprKind::Loop; - case Expr::Unreachable: - return ExprKind::Unreachable; - case Expr::Drop: - return ExprKind::Drop; - case Expr::I32Const: - return ExprKind::I32; - case Expr::I64Const: - return ExprKind::I64; - case Expr::F32Const: - return ExprKind::F32; - case Expr::F64Const: - return ExprKind::F64; - case Expr::I8x16Const: - return ExprKind::I8x16; - case Expr::I16x8Const: - return ExprKind::I16x8; - case Expr::I32x4Const: - return ExprKind::I32x4; - case Expr::B8x16Const: - return ExprKind::B8x16; - case Expr::B16x8Const: - return ExprKind::B16x8; - case Expr::B32x4Const: - return ExprKind::B32x4; - case Expr::F32x4Const: - return ExprKind::F32x4; - case Expr::Br: - return ExprKind::Br; - case Expr::BrIf: - return ExprKind::BrIf; - case Expr::BrTable: - return ExprKind::BrTable; - case Expr::Nop: - return ExprKind::Nop; - case Expr::I32Clz: - case Expr::I32Ctz: - case Expr::I32Popcnt: - case Expr::I64Clz: - case Expr::I64Ctz: - case Expr::I64Popcnt: - case Expr::F32Abs: - case Expr::F32Neg: - case Expr::F32Ceil: - case Expr::F32Floor: - case Expr::F32Trunc: - case Expr::F32Nearest: - case Expr::F32Sqrt: - case Expr::F64Abs: - case Expr::F64Neg: - case Expr::F64Ceil: - case Expr::F64Floor: - case Expr::F64Trunc: - case Expr::F64Nearest: - case Expr::F64Sqrt: - case Expr::I32BitNot: - case Expr::I32Abs: - case Expr::F64Sin: - case Expr::F64Cos: - case Expr::F64Tan: - case Expr::F64Asin: - case Expr::F64Acos: - case Expr::F64Atan: - case Expr::F64Exp: - case Expr::F64Log: - case Expr::I32Neg: - case Expr::I8x16neg: - case Expr::I8x16not: - case Expr::I16x8neg: - case Expr::I16x8not: - case Expr::I32x4neg: - case Expr::I32x4not: - case Expr::F32x4neg: - case Expr::F32x4sqrt: - case Expr::F32x4abs: - case Expr::F32x4reciprocalApproximation: - case Expr::F32x4reciprocalSqrtApproximation: - case Expr::B8x16not: - case Expr::B16x8not: - case Expr::B32x4not: - return ExprKind::Unary; - case Expr::I32Add: - case Expr::I32Sub: - case Expr::I32Mul: - case Expr::I32DivS: - case Expr::I32DivU: - case Expr::I32RemS: - case Expr::I32RemU: - case Expr::I32And: - case Expr::I32Or: - case Expr::I32Xor: - case Expr::I32Shl: - case Expr::I32ShrS: - case Expr::I32ShrU: - case Expr::I32Rotl: - case Expr::I32Rotr: - case Expr::I64Add: - case Expr::I64Sub: - case Expr::I64Mul: - case Expr::I64DivS: - case Expr::I64DivU: - case Expr::I64RemS: - case Expr::I64RemU: - case Expr::I64And: - case Expr::I64Or: - case Expr::I64Xor: - case Expr::I64Shl: - case Expr::I64ShrS: - case Expr::I64ShrU: - case Expr::I64Rotl: - case Expr::I64Rotr: - case Expr::F32Add: - case Expr::F32Sub: - case Expr::F32Mul: - case Expr::F32Div: - case Expr::F32Min: - case Expr::F32Max: - case Expr::F32CopySign: - case Expr::F64Add: - case Expr::F64Sub: - case Expr::F64Mul: - case Expr::F64Div: - case Expr::F64Min: - case Expr::F64Max: - case Expr::F64CopySign: - case Expr::I32Min: - case Expr::I32Max: - case Expr::F64Mod: - case Expr::F64Pow: - case Expr::F64Atan2: - case Expr::I8x16add: - case Expr::I8x16sub: - case Expr::I8x16mul: - case Expr::I8x16addSaturate: - case Expr::I8x16subSaturate: - case Expr::I8x16addSaturateU: - case Expr::I8x16subSaturateU: - case Expr::I8x16and: - case Expr::I8x16or: - case Expr::I8x16xor: - case Expr::I16x8add: - case Expr::I16x8sub: - case Expr::I16x8mul: - case Expr::I16x8addSaturate: - case Expr::I16x8subSaturate: - case Expr::I16x8addSaturateU: - case Expr::I16x8subSaturateU: - case Expr::I16x8and: - case Expr::I16x8or: - case Expr::I16x8xor: - case Expr::I32x4add: - case Expr::I32x4sub: - case Expr::I32x4mul: - case Expr::I32x4and: - case Expr::I32x4or: - case Expr::I32x4xor: - case Expr::F32x4add: - case Expr::F32x4sub: - case Expr::F32x4mul: - case Expr::F32x4div: - case Expr::F32x4min: - case Expr::F32x4max: - case Expr::F32x4minNum: - case Expr::F32x4maxNum: - case Expr::B8x16and: - case Expr::B8x16or: - case Expr::B8x16xor: - case Expr::B16x8and: - case Expr::B16x8or: - case Expr::B16x8xor: - case Expr::B32x4and: - case Expr::B32x4or: - case Expr::B32x4xor: - return ExprKind::Binary; - case Expr::I32Eq: - case Expr::I32Ne: - case Expr::I32LtS: - case Expr::I32LtU: - case Expr::I32LeS: - case Expr::I32LeU: - case Expr::I32GtS: - case Expr::I32GtU: - case Expr::I32GeS: - case Expr::I32GeU: - case Expr::I64Eq: - case Expr::I64Ne: - case Expr::I64LtS: - case Expr::I64LtU: - case Expr::I64LeS: - case Expr::I64LeU: - case Expr::I64GtS: - case Expr::I64GtU: - case Expr::I64GeS: - case Expr::I64GeU: - case Expr::F32Eq: - case Expr::F32Ne: - case Expr::F32Lt: - case Expr::F32Le: - case Expr::F32Gt: - case Expr::F32Ge: - case Expr::F64Eq: - case Expr::F64Ne: - case Expr::F64Lt: - case Expr::F64Le: - case Expr::F64Gt: - case Expr::F64Ge: - return ExprKind::Comparison; - case Expr::I32Eqz: - case Expr::I32WrapI64: - case Expr::I32TruncSF32: - case Expr::I32TruncUF32: - case Expr::I32ReinterpretF32: - case Expr::I32TruncSF64: - case Expr::I32TruncUF64: - case Expr::I64ExtendSI32: - case Expr::I64ExtendUI32: - case Expr::I64TruncSF32: - case Expr::I64TruncUF32: - case Expr::I64TruncSF64: - case Expr::I64TruncUF64: - case Expr::I64ReinterpretF64: - case Expr::I64Eqz: - case Expr::F32ConvertSI32: - case Expr::F32ConvertUI32: - case Expr::F32ReinterpretI32: - case Expr::F32ConvertSI64: - case Expr::F32ConvertUI64: - case Expr::F32DemoteF64: - case Expr::F64ConvertSI32: - case Expr::F64ConvertUI32: - case Expr::F64ConvertSI64: - case Expr::F64ConvertUI64: - case Expr::F64ReinterpretI64: - case Expr::F64PromoteF32: - case Expr::I32x4fromFloat32x4: - case Expr::I32x4fromFloat32x4U: - case Expr::F32x4fromInt32x4: - case Expr::F32x4fromUint32x4: - case Expr::I32x4fromFloat32x4Bits: - case Expr::I32x4fromInt8x16Bits: - case Expr::I32x4fromInt16x8Bits: - case Expr::I16x8fromInt8x16Bits: - case Expr::I16x8fromInt32x4Bits: - case Expr::I16x8fromFloat32x4Bits: - case Expr::I8x16fromInt16x8Bits: - case Expr::I8x16fromInt32x4Bits: - case Expr::I8x16fromFloat32x4Bits: - case Expr::F32x4fromInt8x16Bits: - case Expr::F32x4fromInt16x8Bits: - case Expr::F32x4fromInt32x4Bits: - return ExprKind::Conversion; - case Expr::I32Load8S: - case Expr::I32Load8U: - case Expr::I32Load16S: - case Expr::I32Load16U: - case Expr::I64Load8S: - case Expr::I64Load8U: - case Expr::I64Load16S: - case Expr::I64Load16U: - case Expr::I64Load32S: - case Expr::I64Load32U: - case Expr::I32Load: - case Expr::I64Load: - case Expr::F32Load: - case Expr::F64Load: - case Expr::I8x16load: - case Expr::I16x8load: - case Expr::I32x4load: - case Expr::I32x4load1: - case Expr::I32x4load2: - case Expr::I32x4load3: - case Expr::F32x4load: - case Expr::F32x4load1: - case Expr::F32x4load2: - case Expr::F32x4load3: - return ExprKind::Load; - case Expr::I32Store8: - case Expr::I32Store16: - case Expr::I64Store8: - case Expr::I64Store16: - case Expr::I64Store32: - case Expr::I32Store: - case Expr::I64Store: - case Expr::F32Store: - case Expr::F64Store: - return ExprKind::Store; - case Expr::I32TeeStore8: - case Expr::I32TeeStore16: - case Expr::I64TeeStore8: - case Expr::I64TeeStore16: - case Expr::I64TeeStore32: - case Expr::I32TeeStore: - case Expr::I64TeeStore: - case Expr::F32TeeStore: - case Expr::F64TeeStore: - case Expr::F32TeeStoreF64: - case Expr::F64TeeStoreF32: - case Expr::I8x16store: - case Expr::I16x8store: - case Expr::I32x4store: - case Expr::I32x4store1: - case Expr::I32x4store2: - case Expr::I32x4store3: - case Expr::F32x4store: - case Expr::F32x4store1: - case Expr::F32x4store2: - case Expr::F32x4store3: - return ExprKind::TeeStore; - case Expr::Select: - return ExprKind::Select; - case Expr::GetLocal: - return ExprKind::GetLocal; - case Expr::SetLocal: - return ExprKind::SetLocal; - case Expr::TeeLocal: - return ExprKind::TeeLocal; - case Expr::GetGlobal: - return ExprKind::GetGlobal; - case Expr::SetGlobal: - return ExprKind::SetGlobal; - case Expr::TeeGlobal: - return ExprKind::TeeGlobal; - case Expr::Call: - return ExprKind::Call; - case Expr::CallIndirect: - return ExprKind::CallIndirect; - case Expr::OldCallIndirect: - return ExprKind::OldCallIndirect; - case Expr::Return: - case Expr::Limit: + switch (op) { + case Op::Block: + return OpKind::Block; + case Op::Loop: + return OpKind::Loop; + case Op::Unreachable: + return OpKind::Unreachable; + case Op::Drop: + return OpKind::Drop; + case Op::I32Const: + return OpKind::I32; + case Op::I64Const: + return OpKind::I64; + case Op::F32Const: + return OpKind::F32; + case Op::F64Const: + return OpKind::F64; + case Op::I8x16Const: + return OpKind::I8x16; + case Op::I16x8Const: + return OpKind::I16x8; + case Op::I32x4Const: + return OpKind::I32x4; + case Op::B8x16Const: + return OpKind::B8x16; + case Op::B16x8Const: + return OpKind::B16x8; + case Op::B32x4Const: + return OpKind::B32x4; + case Op::F32x4Const: + return OpKind::F32x4; + case Op::Br: + return OpKind::Br; + case Op::BrIf: + return OpKind::BrIf; + case Op::BrTable: + return OpKind::BrTable; + case Op::Nop: + return OpKind::Nop; + case Op::I32Clz: + case Op::I32Ctz: + case Op::I32Popcnt: + case Op::I64Clz: + case Op::I64Ctz: + case Op::I64Popcnt: + case Op::F32Abs: + case Op::F32Neg: + case Op::F32Ceil: + case Op::F32Floor: + case Op::F32Trunc: + case Op::F32Nearest: + case Op::F32Sqrt: + case Op::F64Abs: + case Op::F64Neg: + case Op::F64Ceil: + case Op::F64Floor: + case Op::F64Trunc: + case Op::F64Nearest: + case Op::F64Sqrt: + case Op::I32BitNot: + case Op::I32Abs: + case Op::F64Sin: + case Op::F64Cos: + case Op::F64Tan: + case Op::F64Asin: + case Op::F64Acos: + case Op::F64Atan: + case Op::F64Exp: + case Op::F64Log: + case Op::I32Neg: + case Op::I8x16neg: + case Op::I8x16not: + case Op::I16x8neg: + case Op::I16x8not: + case Op::I32x4neg: + case Op::I32x4not: + case Op::F32x4neg: + case Op::F32x4sqrt: + case Op::F32x4abs: + case Op::F32x4reciprocalApproximation: + case Op::F32x4reciprocalSqrtApproximation: + case Op::B8x16not: + case Op::B16x8not: + case Op::B32x4not: + return OpKind::Unary; + case Op::I32Add: + case Op::I32Sub: + case Op::I32Mul: + case Op::I32DivS: + case Op::I32DivU: + case Op::I32RemS: + case Op::I32RemU: + case Op::I32And: + case Op::I32Or: + case Op::I32Xor: + case Op::I32Shl: + case Op::I32ShrS: + case Op::I32ShrU: + case Op::I32Rotl: + case Op::I32Rotr: + case Op::I64Add: + case Op::I64Sub: + case Op::I64Mul: + case Op::I64DivS: + case Op::I64DivU: + case Op::I64RemS: + case Op::I64RemU: + case Op::I64And: + case Op::I64Or: + case Op::I64Xor: + case Op::I64Shl: + case Op::I64ShrS: + case Op::I64ShrU: + case Op::I64Rotl: + case Op::I64Rotr: + case Op::F32Add: + case Op::F32Sub: + case Op::F32Mul: + case Op::F32Div: + case Op::F32Min: + case Op::F32Max: + case Op::F32CopySign: + case Op::F64Add: + case Op::F64Sub: + case Op::F64Mul: + case Op::F64Div: + case Op::F64Min: + case Op::F64Max: + case Op::F64CopySign: + case Op::I32Min: + case Op::I32Max: + case Op::F64Mod: + case Op::F64Pow: + case Op::F64Atan2: + case Op::I8x16add: + case Op::I8x16sub: + case Op::I8x16mul: + case Op::I8x16addSaturate: + case Op::I8x16subSaturate: + case Op::I8x16addSaturateU: + case Op::I8x16subSaturateU: + case Op::I8x16and: + case Op::I8x16or: + case Op::I8x16xor: + case Op::I16x8add: + case Op::I16x8sub: + case Op::I16x8mul: + case Op::I16x8addSaturate: + case Op::I16x8subSaturate: + case Op::I16x8addSaturateU: + case Op::I16x8subSaturateU: + case Op::I16x8and: + case Op::I16x8or: + case Op::I16x8xor: + case Op::I32x4add: + case Op::I32x4sub: + case Op::I32x4mul: + case Op::I32x4and: + case Op::I32x4or: + case Op::I32x4xor: + case Op::F32x4add: + case Op::F32x4sub: + case Op::F32x4mul: + case Op::F32x4div: + case Op::F32x4min: + case Op::F32x4max: + case Op::F32x4minNum: + case Op::F32x4maxNum: + case Op::B8x16and: + case Op::B8x16or: + case Op::B8x16xor: + case Op::B16x8and: + case Op::B16x8or: + case Op::B16x8xor: + case Op::B32x4and: + case Op::B32x4or: + case Op::B32x4xor: + return OpKind::Binary; + case Op::I32Eq: + case Op::I32Ne: + case Op::I32LtS: + case Op::I32LtU: + case Op::I32LeS: + case Op::I32LeU: + case Op::I32GtS: + case Op::I32GtU: + case Op::I32GeS: + case Op::I32GeU: + case Op::I64Eq: + case Op::I64Ne: + case Op::I64LtS: + case Op::I64LtU: + case Op::I64LeS: + case Op::I64LeU: + case Op::I64GtS: + case Op::I64GtU: + case Op::I64GeS: + case Op::I64GeU: + case Op::F32Eq: + case Op::F32Ne: + case Op::F32Lt: + case Op::F32Le: + case Op::F32Gt: + case Op::F32Ge: + case Op::F64Eq: + case Op::F64Ne: + case Op::F64Lt: + case Op::F64Le: + case Op::F64Gt: + case Op::F64Ge: + return OpKind::Comparison; + case Op::I32Eqz: + case Op::I32WrapI64: + case Op::I32TruncSF32: + case Op::I32TruncUF32: + case Op::I32ReinterpretF32: + case Op::I32TruncSF64: + case Op::I32TruncUF64: + case Op::I64ExtendSI32: + case Op::I64ExtendUI32: + case Op::I64TruncSF32: + case Op::I64TruncUF32: + case Op::I64TruncSF64: + case Op::I64TruncUF64: + case Op::I64ReinterpretF64: + case Op::I64Eqz: + case Op::F32ConvertSI32: + case Op::F32ConvertUI32: + case Op::F32ReinterpretI32: + case Op::F32ConvertSI64: + case Op::F32ConvertUI64: + case Op::F32DemoteF64: + case Op::F64ConvertSI32: + case Op::F64ConvertUI32: + case Op::F64ConvertSI64: + case Op::F64ConvertUI64: + case Op::F64ReinterpretI64: + case Op::F64PromoteF32: + case Op::I32x4fromFloat32x4: + case Op::I32x4fromFloat32x4U: + case Op::F32x4fromInt32x4: + case Op::F32x4fromUint32x4: + case Op::I32x4fromFloat32x4Bits: + case Op::I32x4fromInt8x16Bits: + case Op::I32x4fromInt16x8Bits: + case Op::I16x8fromInt8x16Bits: + case Op::I16x8fromInt32x4Bits: + case Op::I16x8fromFloat32x4Bits: + case Op::I8x16fromInt16x8Bits: + case Op::I8x16fromInt32x4Bits: + case Op::I8x16fromFloat32x4Bits: + case Op::F32x4fromInt8x16Bits: + case Op::F32x4fromInt16x8Bits: + case Op::F32x4fromInt32x4Bits: + return OpKind::Conversion; + case Op::I32Load8S: + case Op::I32Load8U: + case Op::I32Load16S: + case Op::I32Load16U: + case Op::I64Load8S: + case Op::I64Load8U: + case Op::I64Load16S: + case Op::I64Load16U: + case Op::I64Load32S: + case Op::I64Load32U: + case Op::I32Load: + case Op::I64Load: + case Op::F32Load: + case Op::F64Load: + case Op::I8x16load: + case Op::I16x8load: + case Op::I32x4load: + case Op::I32x4load1: + case Op::I32x4load2: + case Op::I32x4load3: + case Op::F32x4load: + case Op::F32x4load1: + case Op::F32x4load2: + case Op::F32x4load3: + return OpKind::Load; + case Op::I32Store8: + case Op::I32Store16: + case Op::I64Store8: + case Op::I64Store16: + case Op::I64Store32: + case Op::I32Store: + case Op::I64Store: + case Op::F32Store: + case Op::F64Store: + return OpKind::Store; + case Op::I32TeeStore8: + case Op::I32TeeStore16: + case Op::I64TeeStore8: + case Op::I64TeeStore16: + case Op::I64TeeStore32: + case Op::I32TeeStore: + case Op::I64TeeStore: + case Op::F32TeeStore: + case Op::F64TeeStore: + case Op::F32TeeStoreF64: + case Op::F64TeeStoreF32: + case Op::I8x16store: + case Op::I16x8store: + case Op::I32x4store: + case Op::I32x4store1: + case Op::I32x4store2: + case Op::I32x4store3: + case Op::F32x4store: + case Op::F32x4store1: + case Op::F32x4store2: + case Op::F32x4store3: + return OpKind::TeeStore; + case Op::Select: + return OpKind::Select; + case Op::GetLocal: + return OpKind::GetLocal; + case Op::SetLocal: + return OpKind::SetLocal; + case Op::TeeLocal: + return OpKind::TeeLocal; + case Op::GetGlobal: + return OpKind::GetGlobal; + case Op::SetGlobal: + return OpKind::SetGlobal; + case Op::TeeGlobal: + return OpKind::TeeGlobal; + case Op::Call: + return OpKind::Call; + case Op::CallIndirect: + return OpKind::CallIndirect; + case Op::OldCallIndirect: + return OpKind::OldCallIndirect; + case Op::Return: + case Op::Limit: // Accept Limit, for use in decoding the end of a function after the body. - return ExprKind::Return; - case Expr::If: - return ExprKind::If; - case Expr::Else: - return ExprKind::Else; - case Expr::End: - return ExprKind::End; - case Expr::I32AtomicsLoad: - return ExprKind::AtomicLoad; - case Expr::I32AtomicsStore: - return ExprKind::AtomicStore; - case Expr::I32AtomicsBinOp: - return ExprKind::AtomicBinOp; - case Expr::I32AtomicsCompareExchange: - return ExprKind::AtomicCompareExchange; - case Expr::I32AtomicsExchange: - return ExprKind::AtomicExchange; - case Expr::I8x16extractLane: - case Expr::I8x16extractLaneU: - case Expr::I16x8extractLane: - case Expr::I16x8extractLaneU: - case Expr::I32x4extractLane: - case Expr::F32x4extractLane: - case Expr::B8x16extractLane: - case Expr::B16x8extractLane: - case Expr::B32x4extractLane: - return ExprKind::ExtractLane; - case Expr::I8x16replaceLane: - case Expr::I16x8replaceLane: - case Expr::I32x4replaceLane: - case Expr::F32x4replaceLane: - case Expr::B8x16replaceLane: - case Expr::B16x8replaceLane: - case Expr::B32x4replaceLane: - return ExprKind::ReplaceLane; - case Expr::I8x16swizzle: - case Expr::I16x8swizzle: - case Expr::I32x4swizzle: - case Expr::F32x4swizzle: - return ExprKind::Swizzle; - case Expr::I8x16shuffle: - case Expr::I16x8shuffle: - case Expr::I32x4shuffle: - case Expr::F32x4shuffle: - return ExprKind::Shuffle; - case Expr::I16x8check: - case Expr::I16x8splat: - case Expr::I32x4check: - case Expr::I32x4splat: - case Expr::I8x16check: - case Expr::I8x16splat: - case Expr::F32x4check: - case Expr::F32x4splat: - case Expr::B16x8check: - case Expr::B16x8splat: - case Expr::B32x4check: - case Expr::B32x4splat: - case Expr::B8x16check: - case Expr::B8x16splat: - return ExprKind::Splat; - case Expr::I8x16select: - case Expr::I16x8select: - case Expr::I32x4select: - case Expr::F32x4select: - return ExprKind::SimdSelect; - case Expr::I8x16Constructor: - case Expr::I16x8Constructor: - case Expr::I32x4Constructor: - case Expr::F32x4Constructor: - case Expr::B8x16Constructor: - case Expr::B16x8Constructor: - case Expr::B32x4Constructor: - return ExprKind::SimdCtor; - case Expr::B8x16allTrue: - case Expr::B8x16anyTrue: - case Expr::B16x8allTrue: - case Expr::B16x8anyTrue: - case Expr::B32x4allTrue: - case Expr::B32x4anyTrue: - return ExprKind::SimdBooleanReduction; - case Expr::I8x16shiftLeftByScalar: - case Expr::I8x16shiftRightByScalar: - case Expr::I8x16shiftRightByScalarU: - case Expr::I16x8shiftLeftByScalar: - case Expr::I16x8shiftRightByScalar: - case Expr::I16x8shiftRightByScalarU: - case Expr::I32x4shiftLeftByScalar: - case Expr::I32x4shiftRightByScalar: - case Expr::I32x4shiftRightByScalarU: - return ExprKind::SimdShiftByScalar; - case Expr::I8x16equal: - case Expr::I8x16notEqual: - case Expr::I8x16greaterThan: - case Expr::I8x16greaterThanOrEqual: - case Expr::I8x16lessThan: - case Expr::I8x16lessThanOrEqual: - case Expr::I8x16greaterThanU: - case Expr::I8x16greaterThanOrEqualU: - case Expr::I8x16lessThanU: - case Expr::I8x16lessThanOrEqualU: - case Expr::I16x8equal: - case Expr::I16x8notEqual: - case Expr::I16x8greaterThan: - case Expr::I16x8greaterThanOrEqual: - case Expr::I16x8lessThan: - case Expr::I16x8lessThanOrEqual: - case Expr::I16x8greaterThanU: - case Expr::I16x8greaterThanOrEqualU: - case Expr::I16x8lessThanU: - case Expr::I16x8lessThanOrEqualU: - case Expr::I32x4equal: - case Expr::I32x4notEqual: - case Expr::I32x4greaterThan: - case Expr::I32x4greaterThanOrEqual: - case Expr::I32x4lessThan: - case Expr::I32x4lessThanOrEqual: - case Expr::I32x4greaterThanU: - case Expr::I32x4greaterThanOrEqualU: - case Expr::I32x4lessThanU: - case Expr::I32x4lessThanOrEqualU: - case Expr::F32x4equal: - case Expr::F32x4notEqual: - case Expr::F32x4greaterThan: - case Expr::F32x4greaterThanOrEqual: - case Expr::F32x4lessThan: - case Expr::F32x4lessThanOrEqual: - return ExprKind::SimdComparison; - case Expr::CurrentMemory: - return ExprKind::CurrentMemory; - case Expr::GrowMemory: - return ExprKind::GrowMemory; + return OpKind::Return; + case Op::If: + return OpKind::If; + case Op::Else: + return OpKind::Else; + case Op::End: + return OpKind::End; + case Op::I32AtomicsLoad: + return OpKind::AtomicLoad; + case Op::I32AtomicsStore: + return OpKind::AtomicStore; + case Op::I32AtomicsBinOp: + return OpKind::AtomicBinOp; + case Op::I32AtomicsCompareExchange: + return OpKind::AtomicCompareExchange; + case Op::I32AtomicsExchange: + return OpKind::AtomicExchange; + case Op::I8x16extractLane: + case Op::I8x16extractLaneU: + case Op::I16x8extractLane: + case Op::I16x8extractLaneU: + case Op::I32x4extractLane: + case Op::F32x4extractLane: + case Op::B8x16extractLane: + case Op::B16x8extractLane: + case Op::B32x4extractLane: + return OpKind::ExtractLane; + case Op::I8x16replaceLane: + case Op::I16x8replaceLane: + case Op::I32x4replaceLane: + case Op::F32x4replaceLane: + case Op::B8x16replaceLane: + case Op::B16x8replaceLane: + case Op::B32x4replaceLane: + return OpKind::ReplaceLane; + case Op::I8x16swizzle: + case Op::I16x8swizzle: + case Op::I32x4swizzle: + case Op::F32x4swizzle: + return OpKind::Swizzle; + case Op::I8x16shuffle: + case Op::I16x8shuffle: + case Op::I32x4shuffle: + case Op::F32x4shuffle: + return OpKind::Shuffle; + case Op::I16x8check: + case Op::I16x8splat: + case Op::I32x4check: + case Op::I32x4splat: + case Op::I8x16check: + case Op::I8x16splat: + case Op::F32x4check: + case Op::F32x4splat: + case Op::B16x8check: + case Op::B16x8splat: + case Op::B32x4check: + case Op::B32x4splat: + case Op::B8x16check: + case Op::B8x16splat: + return OpKind::Splat; + case Op::I8x16select: + case Op::I16x8select: + case Op::I32x4select: + case Op::F32x4select: + return OpKind::SimdSelect; + case Op::I8x16Constructor: + case Op::I16x8Constructor: + case Op::I32x4Constructor: + case Op::F32x4Constructor: + case Op::B8x16Constructor: + case Op::B16x8Constructor: + case Op::B32x4Constructor: + return OpKind::SimdCtor; + case Op::B8x16allTrue: + case Op::B8x16anyTrue: + case Op::B16x8allTrue: + case Op::B16x8anyTrue: + case Op::B32x4allTrue: + case Op::B32x4anyTrue: + return OpKind::SimdBooleanReduction; + case Op::I8x16shiftLeftByScalar: + case Op::I8x16shiftRightByScalar: + case Op::I8x16shiftRightByScalarU: + case Op::I16x8shiftLeftByScalar: + case Op::I16x8shiftRightByScalar: + case Op::I16x8shiftRightByScalarU: + case Op::I32x4shiftLeftByScalar: + case Op::I32x4shiftRightByScalar: + case Op::I32x4shiftRightByScalarU: + return OpKind::SimdShiftByScalar; + case Op::I8x16equal: + case Op::I8x16notEqual: + case Op::I8x16greaterThan: + case Op::I8x16greaterThanOrEqual: + case Op::I8x16lessThan: + case Op::I8x16lessThanOrEqual: + case Op::I8x16greaterThanU: + case Op::I8x16greaterThanOrEqualU: + case Op::I8x16lessThanU: + case Op::I8x16lessThanOrEqualU: + case Op::I16x8equal: + case Op::I16x8notEqual: + case Op::I16x8greaterThan: + case Op::I16x8greaterThanOrEqual: + case Op::I16x8lessThan: + case Op::I16x8lessThanOrEqual: + case Op::I16x8greaterThanU: + case Op::I16x8greaterThanOrEqualU: + case Op::I16x8lessThanU: + case Op::I16x8lessThanOrEqualU: + case Op::I32x4equal: + case Op::I32x4notEqual: + case Op::I32x4greaterThan: + case Op::I32x4greaterThanOrEqual: + case Op::I32x4lessThan: + case Op::I32x4lessThanOrEqual: + case Op::I32x4greaterThanU: + case Op::I32x4greaterThanOrEqualU: + case Op::I32x4lessThanU: + case Op::I32x4lessThanOrEqualU: + case Op::F32x4equal: + case Op::F32x4notEqual: + case Op::F32x4greaterThan: + case Op::F32x4greaterThanOrEqual: + case Op::F32x4lessThan: + case Op::F32x4lessThanOrEqual: + return OpKind::SimdComparison; + case Op::CurrentMemory: + return OpKind::CurrentMemory; + case Op::GrowMemory: + return OpKind::GrowMemory; } MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("unimplemented opcode"); } #endif
--- a/js/src/wasm/WasmBinaryIterator.h +++ b/js/src/wasm/WasmBinaryIterator.h @@ -35,17 +35,17 @@ enum class LabelKind : uint8_t { Loop, Then, UnreachableThen, // like Then, but not reachable Else }; #ifdef DEBUG // Families of opcodes that share a signature and validation logic. -enum class ExprKind { +enum class OpKind { Block, Loop, Unreachable, Drop, I32, I64, F32, F64, @@ -96,20 +96,20 @@ enum class ExprKind { Splat, SimdSelect, SimdCtor, SimdBooleanReduction, SimdShiftByScalar, SimdComparison, }; -// Return the ExprKind for a given Expr. This is used for sanity-checking that -// API users use the correct read function for a given Expr. -ExprKind -Classify(Expr expr); +// Return the OpKind for a given Op. This is used for sanity-checking that +// API users use the correct read function for a given Op. +OpKind +Classify(Op op); #endif // Common fields for linear memory access. template <typename Value> struct LinearMemoryAddress { Value base; uint32_t offset; @@ -225,19 +225,19 @@ class TypeAndValue<Nothing> : type_(type) {} ValType type() const { return type_; } Nothing value() const { return Nothing(); } void setValue(Nothing value) {} }; -// A policy class for configuring ExprIter. Clients can use this as a +// A policy class for configuring OpIter. Clients can use this as a // base class, and override the behavior as needed. -struct ExprIterPolicy +struct OpIterPolicy { // Should the iterator perform validation, such as type checking and // validity checking? static const bool Validate = false; // Should the iterator produce output values? static const bool Output = false; @@ -250,31 +250,31 @@ struct ExprIterPolicy // An iterator over the bytes of a function body. It performs validation // (if Policy::Validate is true) and unpacks the data into a usable form. // // The MOZ_STACK_CLASS attribute here is because of the use of DebugOnly. // There's otherwise nothing inherent in this class which would require // it to be used on the stack. template <typename Policy> -class MOZ_STACK_CLASS ExprIter : private Policy +class MOZ_STACK_CLASS OpIter : private Policy { static const bool Validate = Policy::Validate; static const bool Output = Policy::Output; typedef typename Policy::Value Value; typedef typename Policy::ControlItem ControlItem; Decoder& d_; const size_t offsetInModule_; - Vector<TypeAndValue<Value>, 0, SystemAllocPolicy> valueStack_; - Vector<ControlStackEntry<ControlItem>, 0, SystemAllocPolicy> controlStack_; + Vector<TypeAndValue<Value>, 8, SystemAllocPolicy> valueStack_; + Vector<ControlStackEntry<ControlItem>, 8, SystemAllocPolicy> controlStack_; bool reachable_; - DebugOnly<Expr> expr_; + DebugOnly<Op> op_; size_t offsetOfExpr_; MOZ_MUST_USE bool readFixedU8(uint8_t* out) { if (Validate) return d_.readFixedU8(out); *out = d_.uncheckedReadFixedU8(); return true; } @@ -498,48 +498,48 @@ class MOZ_STACK_CLASS ExprIter : private valueStack_.shrinkTo(controlStack_.back().valueStackStart()); reachable_ = false; } bool checkBrValue(uint32_t relativeDepth, ExprType* type, Value* value); bool checkBrIfValues(uint32_t relativeDepth, Value* condition, ExprType* type, Value* value); public: - explicit ExprIter(Decoder& decoder, uint32_t offsetInModule = 0) + explicit OpIter(Decoder& decoder, uint32_t offsetInModule = 0) : d_(decoder), offsetInModule_(offsetInModule), reachable_(true), - expr_(Expr::Limit), offsetOfExpr_(0) + op_(Op::Limit), offsetOfExpr_(0) {} // Return the decoding byte offset. uint32_t currentOffset() const { return d_.currentOffset(); } - // Returning the offset within the entire module of the last-read Expr. + // Returning the offset within the entire module of the last-read Op. TrapOffset trapOffset() const { return TrapOffset(offsetInModule_ + offsetOfExpr_); } // Test whether the iterator has reached the end of the buffer. bool done() const { return d_.done(); } // Report a general failure. MOZ_MUST_USE bool fail(const char* msg) MOZ_COLD; // Report an unimplemented feature. MOZ_MUST_USE bool notYetImplemented(const char* what) MOZ_COLD; // Report an unrecognized opcode. - MOZ_MUST_USE bool unrecognizedOpcode(Expr expr) MOZ_COLD; + MOZ_MUST_USE bool unrecognizedOpcode(uint32_t expr) MOZ_COLD; // Test whether the iterator is currently in "reachable" code. bool inReachableCode() const { return reachable_; } // ------------------------------------------------------------------------ // Decoding and validation interface. - MOZ_MUST_USE bool readExpr(Expr* expr); + MOZ_MUST_USE bool readOp(uint16_t* op); MOZ_MUST_USE bool readFunctionStart(ExprType ret); MOZ_MUST_USE bool readFunctionEnd(); MOZ_MUST_USE bool readReturn(Value* value); MOZ_MUST_USE bool readBlock(); MOZ_MUST_USE bool readLoop(); MOZ_MUST_USE bool readIf(Value* condition); MOZ_MUST_USE bool readElse(ExprType* thenType, Value* thenValue); MOZ_MUST_USE bool readEnd(LabelKind* kind, ExprType* type, Value* value); @@ -658,92 +658,92 @@ class MOZ_STACK_CLASS ExprIter : private // end of the function body. bool controlStackEmpty() const { return controlStack_.empty(); } }; template <typename Policy> bool -ExprIter<Policy>::typeMismatch(ExprType actual, ExprType expected) +OpIter<Policy>::typeMismatch(ExprType actual, ExprType expected) { MOZ_ASSERT(Validate); MOZ_ASSERT(reachable_); UniqueChars error(JS_smprintf("type mismatch: expression has type %s but expected %s", ToCString(actual), ToCString(expected))); if (!error) return false; return fail(error.get()); } template <typename Policy> inline bool -ExprIter<Policy>::checkType(ValType actual, ValType expected) +OpIter<Policy>::checkType(ValType actual, ValType expected) { return checkType(ToExprType(actual), ToExprType(expected)); } template <typename Policy> inline bool -ExprIter<Policy>::checkType(ExprType actual, ExprType expected) +OpIter<Policy>::checkType(ExprType actual, ExprType expected) { MOZ_ASSERT(reachable_); if (!Validate) { MOZ_ASSERT(actual == expected, "type mismatch"); return true; } if (MOZ_LIKELY(actual == expected)) return true; return typeMismatch(actual, expected); } template <typename Policy> bool -ExprIter<Policy>::notYetImplemented(const char* what) +OpIter<Policy>::notYetImplemented(const char* what) { UniqueChars error(JS_smprintf("not yet implemented: %s", what)); if (!error) return false; return fail(error.get()); } template <typename Policy> bool -ExprIter<Policy>::unrecognizedOpcode(Expr expr) +OpIter<Policy>::unrecognizedOpcode(uint32_t expr) { - UniqueChars error(JS_smprintf("unrecognized opcode: %x", uint32_t(expr))); + UniqueChars error(JS_smprintf("unrecognized opcode: %x", expr)); if (!error) return false; return fail(error.get()); } template <typename Policy> bool -ExprIter<Policy>::fail(const char* msg) +OpIter<Policy>::fail(const char* msg) { return d_.fail("%s", msg); } template <typename Policy> inline bool -ExprIter<Policy>::pushControl(LabelKind kind, ExprType type, bool reachable) +OpIter<Policy>::pushControl(LabelKind kind, ExprType type, bool reachable) { return controlStack_.emplaceBack(kind, type, reachable, valueStack_.length()); } template <typename Policy> inline bool -ExprIter<Policy>::mergeControl(LabelKind* kind, ExprType* type, Value* value) +OpIter<Policy>::mergeControl(LabelKind* kind, ExprType* type, Value* value) { MOZ_ASSERT(!controlStack_.empty()); ControlStackEntry<ControlItem>& controlItem = controlStack_.back(); *kind = controlItem.kind(); if (reachable_) { // Unlike branching, exiting a scope via fallthrough does not implicitly @@ -781,17 +781,17 @@ ExprIter<Policy>::mergeControl(LabelKind *value = Value(); } return true; } template <typename Policy> inline bool -ExprIter<Policy>::popControl(LabelKind* kind, ExprType* type, Value* value) +OpIter<Policy>::popControl(LabelKind* kind, ExprType* type, Value* value) { if (!mergeControl(kind, type, value)) return false; if (*kind == LabelKind::Then) { // A reachable If without an Else. Forbid a result value. if (reachable_) { if (Validate && !IsVoid(*type)) @@ -805,95 +805,97 @@ ExprIter<Policy>::popControl(LabelKind* if (!reachable_ && !controlStack_.empty()) valueStack_.shrinkTo(controlStack_.back().valueStackStart()); return true; } template <typename Policy> inline bool -ExprIter<Policy>::readBlockType(ExprType* type) +OpIter<Policy>::readBlockType(ExprType* type) { - if (!d_.readBlockType(type)) + uint8_t unchecked; + if (!d_.readBlockType(&unchecked)) return fail("unable to read block signature"); if (Validate) { - switch (*type) { - case ExprType::Void: - case ExprType::I32: - case ExprType::I64: - case ExprType::F32: - case ExprType::F64: - case ExprType::I8x16: - case ExprType::I16x8: - case ExprType::I32x4: - case ExprType::F32x4: - case ExprType::B8x16: - case ExprType::B16x8: - case ExprType::B32x4: + switch (unchecked) { + case uint8_t(ExprType::Void): + case uint8_t(ExprType::I32): + case uint8_t(ExprType::I64): + case uint8_t(ExprType::F32): + case uint8_t(ExprType::F64): + case uint8_t(ExprType::I8x16): + case uint8_t(ExprType::I16x8): + case uint8_t(ExprType::I32x4): + case uint8_t(ExprType::F32x4): + case uint8_t(ExprType::B8x16): + case uint8_t(ExprType::B16x8): + case uint8_t(ExprType::B32x4): break; default: return fail("invalid inline block type"); } } + *type = ExprType(unchecked); return true; } template <typename Policy> inline bool -ExprIter<Policy>::readExpr(Expr* expr) +OpIter<Policy>::readOp(uint16_t* op) { offsetOfExpr_ = d_.currentOffset(); if (Validate) { - if (MOZ_UNLIKELY(!d_.readExpr(expr))) + if (MOZ_UNLIKELY(!d_.readOp(op))) return fail("unable to read opcode"); } else { - *expr = d_.uncheckedReadExpr(); + *op = uint16_t(d_.uncheckedReadOp()); } - expr_ = *expr; + op_ = Op(*op); // debug-only return true; } template <typename Policy> inline bool -ExprIter<Policy>::readFunctionStart(ExprType ret) +OpIter<Policy>::readFunctionStart(ExprType ret) { MOZ_ASSERT(valueStack_.empty()); MOZ_ASSERT(controlStack_.empty()); - MOZ_ASSERT(Expr(expr_) == Expr::Limit); + MOZ_ASSERT(Op(op_) == Op::Limit); MOZ_ASSERT(reachable_); return pushControl(LabelKind::Block, ret, false); } template <typename Policy> inline bool -ExprIter<Policy>::readFunctionEnd() +OpIter<Policy>::readFunctionEnd() { if (Validate) { if (!controlStack_.empty()) return fail("unbalanced function body control flow"); } else { MOZ_ASSERT(controlStack_.empty()); } - expr_ = Expr::Limit; + op_ = Op::Limit; valueStack_.clear(); return true; } template <typename Policy> inline bool -ExprIter<Policy>::readReturn(Value* value) +OpIter<Policy>::readReturn(Value* value) { - MOZ_ASSERT(Classify(expr_) == ExprKind::Return); + MOZ_ASSERT(Classify(op_) == OpKind::Return); if (MOZ_LIKELY(reachable_)) { ControlStackEntry<ControlItem>& controlItem = controlStack_[0]; MOZ_ASSERT(controlItem.kind() == LabelKind::Block); controlItem.setReachable(); if (!IsVoid(controlItem.type())) { @@ -903,45 +905,45 @@ ExprIter<Policy>::readReturn(Value* valu } enterUnreachableCode(); return true; } template <typename Policy> inline bool -ExprIter<Policy>::readBlock() +OpIter<Policy>::readBlock() { - MOZ_ASSERT(Classify(expr_) == ExprKind::Block); + MOZ_ASSERT(Classify(op_) == OpKind::Block); ExprType type = ExprType::Limit; if (!readBlockType(&type)) return false; return pushControl(LabelKind::Block, type, false); } template <typename Policy> inline bool -ExprIter<Policy>::readLoop() +OpIter<Policy>::readLoop() { - MOZ_ASSERT(Classify(expr_) == ExprKind::Loop); + MOZ_ASSERT(Classify(op_) == OpKind::Loop); ExprType type = ExprType::Limit; if (!readBlockType(&type)) return false; return pushControl(LabelKind::Loop, type, reachable_); } template <typename Policy> inline bool -ExprIter<Policy>::readIf(Value* condition) +OpIter<Policy>::readIf(Value* condition) { - MOZ_ASSERT(Classify(expr_) == ExprKind::If); + MOZ_ASSERT(Classify(op_) == OpKind::If); ExprType type = ExprType::Limit; if (!readBlockType(&type)) return false; if (MOZ_LIKELY(reachable_)) { if (!popWithType(ValType::I32, condition)) return false; @@ -949,19 +951,19 @@ ExprIter<Policy>::readIf(Value* conditio return pushControl(LabelKind::Then, type, false); } return pushControl(LabelKind::UnreachableThen, type, false); } template <typename Policy> inline bool -ExprIter<Policy>::readElse(ExprType* thenType, Value* thenValue) +OpIter<Policy>::readElse(ExprType* thenType, Value* thenValue) { - MOZ_ASSERT(Classify(expr_) == ExprKind::Else); + MOZ_ASSERT(Classify(op_) == OpKind::Else); // Finish up the then arm. ExprType type = ExprType::Limit; LabelKind kind; if (!mergeControl(&kind, &type, thenValue)) return false; if (Output) @@ -981,36 +983,36 @@ ExprIter<Policy>::readElse(ExprType* the MOZ_ASSERT(valueStack_.length() == controlStack_.back().valueStackStart()); return true; } template <typename Policy> inline bool -ExprIter<Policy>::readEnd(LabelKind* kind, ExprType* type, Value* value) +OpIter<Policy>::readEnd(LabelKind* kind, ExprType* type, Value* value) { - MOZ_ASSERT(Classify(expr_) == ExprKind::End); + MOZ_ASSERT(Classify(op_) == OpKind::End); LabelKind validateKind = static_cast<LabelKind>(-1); ExprType validateType = ExprType::Limit; if (!popControl(&validateKind, &validateType, value)) return false; if (Output) { *kind = validateKind; *type = validateType; } return true; } template <typename Policy> inline bool -ExprIter<Policy>::checkBrValue(uint32_t relativeDepth, ExprType* type, Value* value) +OpIter<Policy>::checkBrValue(uint32_t relativeDepth, ExprType* type, Value* value) { if (MOZ_LIKELY(reachable_)) { ControlStackEntry<ControlItem>* controlItem = nullptr; if (!getControl(relativeDepth, &controlItem)) return false; if (controlItem->kind() != LabelKind::Loop) { controlItem->setReachable(); @@ -1029,19 +1031,19 @@ ExprIter<Policy>::checkBrValue(uint32_t *value = Value(); } return true; } template <typename Policy> inline bool -ExprIter<Policy>::readBr(uint32_t* relativeDepth, ExprType* type, Value* value) +OpIter<Policy>::readBr(uint32_t* relativeDepth, ExprType* type, Value* value) { - MOZ_ASSERT(Classify(expr_) == ExprKind::Br); + MOZ_ASSERT(Classify(op_) == OpKind::Br); uint32_t validateRelativeDepth; if (!readVarU32(&validateRelativeDepth)) return fail("unable to read br depth"); if (!checkBrValue(validateRelativeDepth, type, value)) return false; @@ -1049,17 +1051,17 @@ ExprIter<Policy>::readBr(uint32_t* relat *relativeDepth = validateRelativeDepth; enterUnreachableCode(); return true; } template <typename Policy> inline bool -ExprIter<Policy>::checkBrIfValues(uint32_t relativeDepth, Value* condition, +OpIter<Policy>::checkBrIfValues(uint32_t relativeDepth, Value* condition, ExprType* type, Value* value) { if (MOZ_LIKELY(reachable_)) { if (!popWithType(ValType::I32, condition)) return false; ControlStackEntry<ControlItem>* controlItem = nullptr; if (!getControl(relativeDepth, &controlItem)) @@ -1082,39 +1084,39 @@ ExprIter<Policy>::checkBrIfValues(uint32 *value = Value(); } return true; } template <typename Policy> inline bool -ExprIter<Policy>::readBrIf(uint32_t* relativeDepth, ExprType* type, Value* value, Value* condition) +OpIter<Policy>::readBrIf(uint32_t* relativeDepth, ExprType* type, Value* value, Value* condition) { - MOZ_ASSERT(Classify(expr_) == ExprKind::BrIf); + MOZ_ASSERT(Classify(op_) == OpKind::BrIf); uint32_t validateRelativeDepth; if (!readVarU32(&validateRelativeDepth)) return fail("unable to read br_if depth"); if (!checkBrIfValues(validateRelativeDepth, condition, type, value)) return false; if (Output) *relativeDepth = validateRelativeDepth; return true; } template <typename Policy> inline bool -ExprIter<Policy>::readBrTable(uint32_t* tableLength, ExprType* type, +OpIter<Policy>::readBrTable(uint32_t* tableLength, ExprType* type, Value* value, Value* index) { - MOZ_ASSERT(Classify(expr_) == ExprKind::BrTable); + MOZ_ASSERT(Classify(op_) == OpKind::BrTable); if (!readVarU32(tableLength)) return fail("unable to read br_table table length"); if (MOZ_LIKELY(reachable_)) { if (!popWithType(ValType::I32, index)) return false; } @@ -1124,19 +1126,19 @@ ExprIter<Policy>::readBrTable(uint32_t* if (Output) *value = Value(); return true; } template <typename Policy> inline bool -ExprIter<Policy>::readBrTableEntry(ExprType* type, Value* value, uint32_t* depth) +OpIter<Policy>::readBrTableEntry(ExprType* type, Value* value, uint32_t* depth) { - MOZ_ASSERT(Classify(expr_) == ExprKind::BrTable); + MOZ_ASSERT(Classify(op_) == OpKind::BrTable); if (!readVarU32(depth)) return false; ExprType knownType = *type; if (MOZ_LIKELY(reachable_)) { ControlStackEntry<ControlItem>* controlItem = nullptr; @@ -1166,114 +1168,114 @@ ExprIter<Policy>::readBrTableEntry(ExprT *type = ExprType::Void; if (Output) *value = Value(); return true; } template <typename Policy> inline bool -ExprIter<Policy>::readBrTableDefault(ExprType* type, Value* value, uint32_t* depth) +OpIter<Policy>::readBrTableDefault(ExprType* type, Value* value, uint32_t* depth) { if (!readBrTableEntry(type, value, depth)) return false; MOZ_ASSERT(!reachable_ || *type != ExprType::Limit); enterUnreachableCode(); return true; } template <typename Policy> inline bool -ExprIter<Policy>::readUnreachable() +OpIter<Policy>::readUnreachable() { - MOZ_ASSERT(Classify(expr_) == ExprKind::Unreachable); + MOZ_ASSERT(Classify(op_) == OpKind::Unreachable); enterUnreachableCode(); return true; } template <typename Policy> inline bool -ExprIter<Policy>::readDrop() +OpIter<Policy>::readDrop() { - MOZ_ASSERT(Classify(expr_) == ExprKind::Drop); + MOZ_ASSERT(Classify(op_) == OpKind::Drop); if (!pop()) return false; return true; } template <typename Policy> inline bool -ExprIter<Policy>::readUnary(ValType operandType, Value* input) +OpIter<Policy>::readUnary(ValType operandType, Value* input) { - MOZ_ASSERT(Classify(expr_) == ExprKind::Unary); + MOZ_ASSERT(Classify(op_) == OpKind::Unary); if (!popWithType(operandType, input)) return false; infalliblePush(operandType); return true; } template <typename Policy> inline bool -ExprIter<Policy>::readConversion(ValType operandType, ValType resultType, Value* input) +OpIter<Policy>::readConversion(ValType operandType, ValType resultType, Value* input) { - MOZ_ASSERT(Classify(expr_) == ExprKind::Conversion); + MOZ_ASSERT(Classify(op_) == OpKind::Conversion); if (!popWithType(operandType, input)) return false; infalliblePush(resultType); return true; } template <typename Policy> inline bool -ExprIter<Policy>::readBinary(ValType operandType, Value* lhs, Value* rhs) +OpIter<Policy>::readBinary(ValType operandType, Value* lhs, Value* rhs) { - MOZ_ASSERT(Classify(expr_) == ExprKind::Binary); + MOZ_ASSERT(Classify(op_) == OpKind::Binary); if (!popWithType(operandType, rhs)) return false; if (!popWithType(operandType, lhs)) return false; infalliblePush(operandType); return true; } template <typename Policy> inline bool -ExprIter<Policy>::readComparison(ValType operandType, Value* lhs, Value* rhs) +OpIter<Policy>::readComparison(ValType operandType, Value* lhs, Value* rhs) { - MOZ_ASSERT(Classify(expr_) == ExprKind::Comparison); + MOZ_ASSERT(Classify(op_) == OpKind::Comparison); if (!popWithType(operandType, rhs)) return false; if (!popWithType(operandType, lhs)) return false; infalliblePush(ValType::I32); return true; } template <typename Policy> inline bool -ExprIter<Policy>::readLinearMemoryAddress(uint32_t byteSize, LinearMemoryAddress<Value>* addr) +OpIter<Policy>::readLinearMemoryAddress(uint32_t byteSize, LinearMemoryAddress<Value>* addr) { uint8_t alignLog2; if (!readFixedU8(&alignLog2)) return fail("unable to read load alignment"); uint32_t unusedOffset; if (!readVarU32(Output ? &addr->offset : &unusedOffset)) return fail("unable to read load offset"); @@ -1288,96 +1290,95 @@ ExprIter<Policy>::readLinearMemoryAddres if (Output) addr->align = uint32_t(1) << alignLog2; return true; } template <typename Policy> inline bool -ExprIter<Policy>::readLoad(ValType resultType, uint32_t byteSize, - LinearMemoryAddress<Value>* addr) +OpIter<Policy>::readLoad(ValType resultType, uint32_t byteSize, LinearMemoryAddress<Value>* addr) { - MOZ_ASSERT(Classify(expr_) == ExprKind::Load); + MOZ_ASSERT(Classify(op_) == OpKind::Load); if (!readLinearMemoryAddress(byteSize, addr)) return false; infalliblePush(resultType); return true; } template <typename Policy> inline bool -ExprIter<Policy>::readStore(ValType resultType, uint32_t byteSize, - LinearMemoryAddress<Value>* addr, Value* value) +OpIter<Policy>::readStore(ValType resultType, uint32_t byteSize, LinearMemoryAddress<Value>* addr, + Value* value) { - MOZ_ASSERT(Classify(expr_) == ExprKind::Store); + MOZ_ASSERT(Classify(op_) == OpKind::Store); if (!popWithType(resultType, value)) return false; if (!readLinearMemoryAddress(byteSize, addr)) return false; return true; } template <typename Policy> inline bool -ExprIter<Policy>::readTeeStore(ValType resultType, uint32_t byteSize, - LinearMemoryAddress<Value>* addr, Value* value) +OpIter<Policy>::readTeeStore(ValType resultType, uint32_t byteSize, LinearMemoryAddress<Value>* addr, + Value* value) { - MOZ_ASSERT(Classify(expr_) == ExprKind::TeeStore); + MOZ_ASSERT(Classify(op_) == OpKind::TeeStore); if (!popWithType(resultType, value)) return false; if (!readLinearMemoryAddress(byteSize, addr)) return false; infalliblePush(TypeAndValue<Value>(resultType, Output ? *value : Value())); return true; } template <typename Policy> inline bool -ExprIter<Policy>::readNop() +OpIter<Policy>::readNop() { - MOZ_ASSERT(Classify(expr_) == ExprKind::Nop); + MOZ_ASSERT(Classify(op_) == OpKind::Nop); return true; } template <typename Policy> inline bool -ExprIter<Policy>::readCurrentMemory() +OpIter<Policy>::readCurrentMemory() { - MOZ_ASSERT(Classify(expr_) == ExprKind::CurrentMemory); + MOZ_ASSERT(Classify(op_) == OpKind::CurrentMemory); uint32_t flags; if (!readVarU32(&flags)) return false; if (Validate && flags != uint32_t(MemoryTableFlags::Default)) return fail("unexpected flags"); if (!push(ValType::I32)) return false; return true; } template <typename Policy> inline bool -ExprIter<Policy>::readGrowMemory(Value* input) +OpIter<Policy>::readGrowMemory(Value* input) { - MOZ_ASSERT(Classify(expr_) == ExprKind::GrowMemory); + MOZ_ASSERT(Classify(op_) == OpKind::GrowMemory); uint32_t flags; if (!readVarU32(&flags)) return false; if (Validate && flags != uint32_t(MemoryTableFlags::Default)) return fail("unexpected flags"); @@ -1386,19 +1387,19 @@ ExprIter<Policy>::readGrowMemory(Value* infalliblePush(ValType::I32); return true; } template <typename Policy> inline bool -ExprIter<Policy>::readSelect(ValType* type, Value* trueValue, Value* falseValue, Value* condition) +OpIter<Policy>::readSelect(ValType* type, Value* trueValue, Value* falseValue, Value* condition) { - MOZ_ASSERT(Classify(expr_) == ExprKind::Select); + MOZ_ASSERT(Classify(op_) == OpKind::Select); if (!popWithType(ValType::I32, condition)) return false; TypeAndValue<Value> false_; if (!pop(&false_)) return false; @@ -1418,19 +1419,19 @@ ExprIter<Policy>::readSelect(ValType* ty *falseValue = false_.value(); } return true; } template <typename Policy> inline bool -ExprIter<Policy>::readGetLocal(const ValTypeVector& locals, uint32_t* id) +OpIter<Policy>::readGetLocal(const ValTypeVector& locals, uint32_t* id) { - MOZ_ASSERT(Classify(expr_) == ExprKind::GetLocal); + MOZ_ASSERT(Classify(op_) == OpKind::GetLocal); uint32_t validateId; if (!readVarU32(&validateId)) return false; if (Validate && validateId >= locals.length()) return fail("get_local index out of range"); @@ -1440,19 +1441,19 @@ ExprIter<Policy>::readGetLocal(const Val if (Output) *id = validateId; return true; } template <typename Policy> inline bool -ExprIter<Policy>::readSetLocal(const ValTypeVector& locals, uint32_t* id, Value* value) +OpIter<Policy>::readSetLocal(const ValTypeVector& locals, uint32_t* id, Value* value) { - MOZ_ASSERT(Classify(expr_) == ExprKind::SetLocal); + MOZ_ASSERT(Classify(op_) == OpKind::SetLocal); uint32_t validateId; if (!readVarU32(&validateId)) return false; if (Validate && validateId >= locals.length()) return fail("set_local index out of range"); @@ -1462,19 +1463,19 @@ ExprIter<Policy>::readSetLocal(const Val if (Output) *id = validateId; return true; } template <typename Policy> inline bool -ExprIter<Policy>::readTeeLocal(const ValTypeVector& locals, uint32_t* id, Value* value) +OpIter<Policy>::readTeeLocal(const ValTypeVector& locals, uint32_t* id, Value* value) { - MOZ_ASSERT(Classify(expr_) == ExprKind::TeeLocal); + MOZ_ASSERT(Classify(op_) == OpKind::TeeLocal); uint32_t validateId; if (!readVarU32(&validateId)) return false; if (Validate && validateId >= locals.length()) return fail("set_local index out of range"); @@ -1484,19 +1485,19 @@ ExprIter<Policy>::readTeeLocal(const Val if (Output) *id = validateId; return true; } template <typename Policy> inline bool -ExprIter<Policy>::readGetGlobal(const GlobalDescVector& globals, uint32_t* id) +OpIter<Policy>::readGetGlobal(const GlobalDescVector& globals, uint32_t* id) { - MOZ_ASSERT(Classify(expr_) == ExprKind::GetGlobal); + MOZ_ASSERT(Classify(op_) == OpKind::GetGlobal); uint32_t validateId; if (!readVarU32(&validateId)) return false; if (Validate && validateId >= globals.length()) return fail("get_global index out of range"); @@ -1506,19 +1507,19 @@ ExprIter<Policy>::readGetGlobal(const Gl if (Output) *id = validateId; return true; } template <typename Policy> inline bool -ExprIter<Policy>::readSetGlobal(const GlobalDescVector& globals, uint32_t* id, Value* value) +OpIter<Policy>::readSetGlobal(const GlobalDescVector& globals, uint32_t* id, Value* value) { - MOZ_ASSERT(Classify(expr_) == ExprKind::SetGlobal); + MOZ_ASSERT(Classify(op_) == OpKind::SetGlobal); uint32_t validateId; if (!readVarU32(&validateId)) return false; if (Validate && validateId >= globals.length()) return fail("set_global index out of range"); @@ -1531,19 +1532,19 @@ ExprIter<Policy>::readSetGlobal(const Gl if (Output) *id = validateId; return true; } template <typename Policy> inline bool -ExprIter<Policy>::readTeeGlobal(const GlobalDescVector& globals, uint32_t* id, Value* value) +OpIter<Policy>::readTeeGlobal(const GlobalDescVector& globals, uint32_t* id, Value* value) { - MOZ_ASSERT(Classify(expr_) == ExprKind::TeeGlobal); + MOZ_ASSERT(Classify(op_) == OpKind::TeeGlobal); uint32_t validateId; if (!readVarU32(&validateId)) return false; if (Validate && validateId >= globals.length()) return fail("set_global index out of range"); @@ -1556,207 +1557,207 @@ ExprIter<Policy>::readTeeGlobal(const Gl if (Output) *id = validateId; return true; } template <typename Policy> inline bool -ExprIter<Policy>::readI32Const(int32_t* i32) +OpIter<Policy>::readI32Const(int32_t* i32) { - MOZ_ASSERT(Classify(expr_) == ExprKind::I32); + MOZ_ASSERT(Classify(op_) == OpKind::I32); int32_t unused; if (!readVarS32(Output ? i32 : &unused)) return false; if (!push(ValType::I32)) return false; return true; } template <typename Policy> inline bool -ExprIter<Policy>::readI64Const(int64_t* i64) +OpIter<Policy>::readI64Const(int64_t* i64) { - MOZ_ASSERT(Classify(expr_) == ExprKind::I64); + MOZ_ASSERT(Classify(op_) == OpKind::I64); int64_t unused; if (!readVarS64(Output ? i64 : &unused)) return false; if (!push(ValType::I64)) return false; return true; } template <typename Policy> inline bool -ExprIter<Policy>::readF32Const(RawF32* f32) +OpIter<Policy>::readF32Const(RawF32* f32) { - MOZ_ASSERT(Classify(expr_) == ExprKind::F32); + MOZ_ASSERT(Classify(op_) == OpKind::F32); RawF32 unused; if (!readFixedF32(Output ? f32 : &unused)) return false; if (!push(ValType::F32)) return false; return true; } template <typename Policy> inline bool -ExprIter<Policy>::readF64Const(RawF64* f64) +OpIter<Policy>::readF64Const(RawF64* f64) { - MOZ_ASSERT(Classify(expr_) == ExprKind::F64); + MOZ_ASSERT(Classify(op_) == OpKind::F64); RawF64 unused; if (!readFixedF64(Output ? f64 : &unused)) return false; if (!push(ValType::F64)) return false; return true; } template <typename Policy> inline bool -ExprIter<Policy>::readI8x16Const(I8x16* i8x16) +OpIter<Policy>::readI8x16Const(I8x16* i8x16) { - MOZ_ASSERT(Classify(expr_) == ExprKind::I8x16); + MOZ_ASSERT(Classify(op_) == OpKind::I8x16); I8x16 unused; if (!readFixedI8x16(Output ? i8x16 : &unused)) return false; if (!push(ValType::I8x16)) return false; return true; } template <typename Policy> inline bool -ExprIter<Policy>::readI16x8Const(I16x8* i16x8) +OpIter<Policy>::readI16x8Const(I16x8* i16x8) { - MOZ_ASSERT(Classify(expr_) == ExprKind::I16x8); + MOZ_ASSERT(Classify(op_) == OpKind::I16x8); I16x8 unused; if (!readFixedI16x8(Output ? i16x8 : &unused)) return false; if (!push(ValType::I16x8)) return false; return true; } template <typename Policy> inline bool -ExprIter<Policy>::readI32x4Const(I32x4* i32x4) +OpIter<Policy>::readI32x4Const(I32x4* i32x4) { - MOZ_ASSERT(Classify(expr_) == ExprKind::I32x4); + MOZ_ASSERT(Classify(op_) == OpKind::I32x4); I32x4 unused; if (!readFixedI32x4(Output ? i32x4 : &unused)) return false; if (!push(ValType::I32x4)) return false; return true; } template <typename Policy> inline bool -ExprIter<Policy>::readF32x4Const(F32x4* f32x4) +OpIter<Policy>::readF32x4Const(F32x4* f32x4) { - MOZ_ASSERT(Classify(expr_) == ExprKind::F32x4); + MOZ_ASSERT(Classify(op_) == OpKind::F32x4); F32x4 unused; if (!readFixedF32x4(Output ? f32x4 : &unused))