Merge inbound to central, a=merge
authorWes Kocher <wkocher@mozilla.com>
Fri, 13 May 2016 16:43:37 -0700
changeset 336390 2afd8fa9bb5df5577e5566468bb423b76c63cc77
parent 336313 cecc6f0f056069ec9f765a0d513c2226001f144f (current diff)
parent 336389 dc0186974f99dd83f39c69b8ba1635fee83f8c55 (diff)
child 336424 6bab48d2528b459f7e0cb322ddccada8c72fd95d
child 336457 93d60e9db618bd817bdba3fec6151d701bd5627a
push id6249
push userjlund@mozilla.com
push dateMon, 01 Aug 2016 13:59:36 +0000
treeherdermozilla-beta@bad9d4f5bf7e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone49.0a1
first release with
nightly linux32
2afd8fa9bb5d / 49.0a1 / 20160514030209 / files
nightly linux64
2afd8fa9bb5d / 49.0a1 / 20160514030209 / files
nightly mac
2afd8fa9bb5d / 49.0a1 / 20160514030209 / files
nightly win32
2afd8fa9bb5d / 49.0a1 / 20160514030209 / files
nightly win64
2afd8fa9bb5d / 49.0a1 / 20160514030209 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to central, a=merge
netwerk/base/nsAutodialQt.cpp
netwerk/base/nsAutodialQt.h
netwerk/base/nsAutodialWin.cpp
netwerk/base/nsAutodialWin.h
netwerk/base/nsNativeConnectionHelper.cpp
netwerk/base/nsNativeConnectionHelper.h
tools/update-packaging/app.mozbuild
tools/update-packaging/confvars.sh
--- a/addon-sdk/source/python-lib/cuddlefish/prefs.py
+++ b/addon-sdk/source/python-lib/cuddlefish/prefs.py
@@ -32,19 +32,16 @@ DEFAULT_COMMON_PREFS = {
     # Disable intalling any distribution add-ons
     'extensions.installDistroAddons' : False,
     # Allow installing extensions dropped into the profile folder
     'extensions.autoDisableScopes' : 10,
 
     # shut up some warnings on `about:` page
     'app.releaseNotesURL': 'http://localhost/app-dummy/',
     'app.vendorURL': 'http://localhost/app-dummy/',
-
-    # Don't prompt about e10s
-    'browser.displayedE10SPrompt.1': 5
 }
 
 DEFAULT_NO_CONNECTIONS_PREFS = {
     'toolkit.telemetry.enabled': False,
     'toolkit.telemetry.server': 'https://localhost/telemetry-dummy/',
     'app.update.auto' : False,
     'app.update.url': 'http://localhost/app-dummy/update',
     # Make sure GMPInstallManager won't hit the network.
--- a/addon-sdk/source/test/preferences/e10s-off.json
+++ b/addon-sdk/source/test/preferences/e10s-off.json
@@ -1,6 +1,5 @@
 {
-  "browser.displayedE10SPrompt.1": 5,
   "browser.tabs.remote.autostart": false,
   "browser.tabs.remote.autostart.1": false,
   "browser.tabs.remote.autostart.2": false
 }
--- a/b2g/config/mozconfigs/linux32_gecko/debug
+++ b/b2g/config/mozconfigs/linux32_gecko/debug
@@ -1,16 +1,15 @@
 MOZ_AUTOMATION_L10N_CHECK=0
 MOZ_AUTOMATION_UPLOAD_SYMBOLS=0
 MOZ_AUTOMATION_UPDATE_PACKAGING=0
 . "$topsrcdir/b2g/config/mozconfigs/common"
 . "$topsrcdir/build/unix/mozconfig.linux32"
 
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
-ac_add_options --enable-update-packaging
 ac_add_options --enable-signmar
 ac_add_options --enable-debug
 
 # This will overwrite the default of stripping everything and keep the symbol table.
 # This is useful for profiling and debugging and only increases the package size
 # by 2 MBs.
 STRIP_FLAGS="--strip-debug"
 
--- a/b2g/config/mozconfigs/linux32_gecko/nightly
+++ b/b2g/config/mozconfigs/linux32_gecko/nightly
@@ -1,17 +1,16 @@
 MOZ_AUTOMATION_L10N_CHECK=0
 MOZ_AUTOMATION_UPLOAD_SYMBOLS=0
 MOZ_AUTOMATION_UPDATE_PACKAGING=0
 MOZ_AUTOMATION_SDK=0
 . "$topsrcdir/b2g/config/mozconfigs/common"
 . "$topsrcdir/build/unix/mozconfig.linux32"
 
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
-ac_add_options --enable-update-packaging
 ac_add_options --enable-signmar
 
 # This will overwrite the default of stripping everything and keep the symbol table.
 # This is useful for profiling and debugging and only increases the package size
 # by 2 MBs.
 STRIP_FLAGS="--strip-debug"
 
 # Needed to enable breakpad in application.ini
--- a/b2g/config/mozconfigs/linux64_gecko/nightly
+++ b/b2g/config/mozconfigs/linux64_gecko/nightly
@@ -1,17 +1,16 @@
 MOZ_AUTOMATION_L10N_CHECK=0
 MOZ_AUTOMATION_UPLOAD_SYMBOLS=0
 MOZ_AUTOMATION_UPDATE_PACKAGING=0
 MOZ_AUTOMATION_SDK=0
 . "$topsrcdir/b2g/config/mozconfigs/common"
 . "$topsrcdir/build/unix/mozconfig.linux"
 
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
-ac_add_options --enable-update-packaging
 ac_add_options --enable-signmar
 
 # This will overwrite the default of stripping everything and keep the symbol table.
 # This is useful for profiling and debugging and only increases the package size
 # by 2 MBs.
 STRIP_FLAGS="--strip-debug"
 
 # Needed to enable breakpad in application.ini
--- a/b2g/config/mozconfigs/macosx64_gecko/debug
+++ b/b2g/config/mozconfigs/macosx64_gecko/debug
@@ -3,17 +3,16 @@ MOZ_AUTOMATION_UPDATE_PACKAGING=0
 . "$topsrcdir/b2g/config/mozconfigs/common"
 
 # Use sccache
 no_sccache=
 
 . $topsrcdir/build/macosx/mozconfig.common
 
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
-ac_add_options --enable-update-packaging
 ac_add_options --enable-signmar
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
 export MOZ_TELEMETRY_REPORTING=1
 
 #ac_add_options --with-macbundlename-prefix=Firefox
--- a/b2g/config/mozconfigs/macosx64_gecko/nightly
+++ b/b2g/config/mozconfigs/macosx64_gecko/nightly
@@ -4,17 +4,16 @@ MOZ_AUTOMATION_SDK=0
 . "$topsrcdir/b2g/config/mozconfigs/common"
 
 # Use sccache
 no_sccache=
 
 . $topsrcdir/build/macosx/mozconfig.common
 
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
-ac_add_options --enable-update-packaging
 ac_add_options --enable-signmar
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
 export MOZ_TELEMETRY_REPORTING=1
 
 #ac_add_options --with-macbundlename-prefix=Firefox
--- a/b2g/config/mozconfigs/win32_gecko/debug
+++ b/b2g/config/mozconfigs/win32_gecko/debug
@@ -1,15 +1,14 @@
 MOZ_AUTOMATION_L10N_CHECK=0
 MOZ_AUTOMATION_UPLOAD_SYMBOLS=0
 MOZ_AUTOMATION_UPDATE_PACKAGING=0
 . "$topsrcdir/b2g/config/mozconfigs/common"
 
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
-ac_add_options --enable-update-packaging
 ac_add_options --enable-jemalloc
 ac_add_options --enable-signmar
 ac_add_options --enable-debug
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
 export MOZ_TELEMETRY_REPORTING=1
--- a/b2g/config/mozconfigs/win32_gecko/nightly
+++ b/b2g/config/mozconfigs/win32_gecko/nightly
@@ -1,16 +1,15 @@
 MOZ_AUTOMATION_L10N_CHECK=0
 MOZ_AUTOMATION_UPLOAD_SYMBOLS=0
 MOZ_AUTOMATION_UPDATE_PACKAGING=0
 MOZ_AUTOMATION_SDK=0
 . "$topsrcdir/b2g/config/mozconfigs/common"
 
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
-ac_add_options --enable-update-packaging
 ac_add_options --enable-jemalloc
 ac_add_options --enable-signmar
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
 export MOZ_TELEMETRY_REPORTING=1
 
--- a/b2g/graphene/config/horizon-mozconfigs/linux32/nightly
+++ b/b2g/graphene/config/horizon-mozconfigs/linux32/nightly
@@ -1,13 +1,12 @@
 . "$topsrcdir/b2g/graphene/config/horizon-mozconfigs/common"
 . "$topsrcdir/build/unix/mozconfig.linux32"
 
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
-ac_add_options --enable-update-packaging
 ac_add_options --enable-signmar
 
 # Nightlies only since this has a cost in performance
 #ac_add_options --enable-js-diagnostics
 
 # This will overwrite the default of stripping everything and keep the symbol table.
 # This is useful for profiling and debugging and only increases the package size
 # by 2 MBs.
--- a/b2g/graphene/config/horizon-mozconfigs/linux64/nightly
+++ b/b2g/graphene/config/horizon-mozconfigs/linux64/nightly
@@ -1,13 +1,12 @@
 . "$topsrcdir/b2g/graphene/config/horizon-mozconfigs/common"
 . "$topsrcdir/build/unix/mozconfig.linux"
 
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
-ac_add_options --enable-update-packaging
 ac_add_options --enable-signmar
 
 # Nightlies only since this has a cost in performance
 #ac_add_options --enable-js-diagnostics
 
 # This will overwrite the default of stripping everything and keep the symbol table.
 # This is useful for profiling and debugging and only increases the package size
 # by 2 MBs.
--- a/b2g/graphene/config/horizon-mozconfigs/macosx64/nightly
+++ b/b2g/graphene/config/horizon-mozconfigs/macosx64/nightly
@@ -1,17 +1,16 @@
 . "$topsrcdir/b2g/graphene/config/horizon-mozconfigs/common"
 
 # Use sccache
 no_sccache=
 
 . $topsrcdir/build/macosx/mozconfig.common
 
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
-ac_add_options --enable-update-packaging
 ac_add_options --enable-signmar
 
 # Nightlies only since this has a cost in performance
 ac_add_options --enable-js-diagnostics
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
--- a/b2g/graphene/config/horizon-mozconfigs/win32/nightly
+++ b/b2g/graphene/config/horizon-mozconfigs/win32/nightly
@@ -1,12 +1,11 @@
 . "$topsrcdir/b2g/graphene/config/horizon-mozconfigs/common"
 
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
-ac_add_options --enable-update-packaging
 ac_add_options --enable-jemalloc
 ac_add_options --enable-signmar
 
 # Nightlies only since this has a cost in performance
 ac_add_options --enable-js-diagnostics
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
--- a/b2g/graphene/config/horizon-mozconfigs/win64/nightly
+++ b/b2g/graphene/config/horizon-mozconfigs/win64/nightly
@@ -6,17 +6,16 @@ fi
 . "$topsrcdir/b2g/graphene/config/horizon-mozconfigs/common"
 
 ac_add_options --target=x86_64-pc-mingw32
 ac_add_options --host=x86_64-pc-mingw32
 
 . $topsrcdir/build/win64/mozconfig.vs-latest
 
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
-ac_add_options --enable-update-packaging
 ac_add_options --enable-jemalloc
 ac_add_options --enable-signmar
 
 # Nightlies only since this has a cost in performance
 ac_add_options --enable-js-diagnostics
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
--- a/b2g/graphene/config/mozconfigs/linux32/nightly
+++ b/b2g/graphene/config/mozconfigs/linux32/nightly
@@ -1,13 +1,12 @@
 . "$topsrcdir/b2g/graphene/config/mozconfigs/common"
 . "$topsrcdir/build/unix/mozconfig.linux32"
 
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
-ac_add_options --enable-update-packaging
 ac_add_options --enable-signmar
 
 # Nightlies only since this has a cost in performance
 #ac_add_options --enable-js-diagnostics
 
 # This will overwrite the default of stripping everything and keep the symbol table.
 # This is useful for profiling and debugging and only increases the package size
 # by 2 MBs.
--- a/b2g/graphene/config/mozconfigs/linux64/nightly
+++ b/b2g/graphene/config/mozconfigs/linux64/nightly
@@ -1,13 +1,12 @@
 . "$topsrcdir/b2g/graphene/config/mozconfigs/common"
 . "$topsrcdir/build/unix/mozconfig.linux"
 
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
-ac_add_options --enable-update-packaging
 ac_add_options --enable-signmar
 
 # Nightlies only since this has a cost in performance
 #ac_add_options --enable-js-diagnostics
 
 # This will overwrite the default of stripping everything and keep the symbol table.
 # This is useful for profiling and debugging and only increases the package size
 # by 2 MBs.
--- a/b2g/graphene/config/mozconfigs/macosx64/nightly
+++ b/b2g/graphene/config/mozconfigs/macosx64/nightly
@@ -1,17 +1,16 @@
 . "$topsrcdir/b2g/graphene/config/mozconfigs/common"
 
 # Use sccache
 no_sccache=
 
 . $topsrcdir/build/macosx/mozconfig.common
 
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
-ac_add_options --enable-update-packaging
 ac_add_options --enable-signmar
 
 # Nightlies only since this has a cost in performance
 ac_add_options --enable-js-diagnostics
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
--- a/b2g/graphene/config/mozconfigs/win32/nightly
+++ b/b2g/graphene/config/mozconfigs/win32/nightly
@@ -1,12 +1,11 @@
 . "$topsrcdir/b2g/graphene/config/mozconfigs/common"
 
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
-ac_add_options --enable-update-packaging
 ac_add_options --enable-jemalloc
 ac_add_options --enable-signmar
 
 # Nightlies only since this has a cost in performance
 ac_add_options --enable-js-diagnostics
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
--- a/b2g/graphene/config/mozconfigs/win64/nightly
+++ b/b2g/graphene/config/mozconfigs/win64/nightly
@@ -6,17 +6,16 @@ fi
 . "$topsrcdir/b2g/graphene/config/mozconfigs/common"
 
 ac_add_options --target=x86_64-pc-mingw32
 ac_add_options --host=x86_64-pc-mingw32
 
 . $topsrcdir/build/win64/mozconfig.vs-latest
 
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
-ac_add_options --enable-update-packaging
 ac_add_options --enable-jemalloc
 ac_add_options --enable-signmar
 
 # Nightlies only since this has a cost in performance
 ac_add_options --enable-js-diagnostics
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
--- a/browser/base/content/popup-notifications.inc
+++ b/browser/base/content/popup-notifications.inc
@@ -71,22 +71,16 @@
         <textbox id="login-fill-username" readonly="true"/>
         <textbox id="login-fill-password" type="password" disabled="true"/>
         <hbox>
           <button id="login-fill-use" label="Use in form"/>
         </hbox>
       </vbox>
     </stack>
 
-#ifdef E10S_TESTING_ONLY
-    <popupnotification id="enable-e10s-notification" hidden="true">
-      <popupnotificationcontent orient="vertical"/>
-    </popupnotification>
-#endif
-
     <popupnotification id="addon-progress-notification" hidden="true">
       <popupnotificationcontent orient="vertical">
         <progressmeter id="addon-progress-notification-progressmeter"/>
         <label id="addon-progress-notification-progresstext" crop="end"/>
       </popupnotificationcontent>
       <button id="addon-progress-cancel"
               oncommand="this.parentNode.cancel();"/>
       <button id="addon-progress-accept" disabled="true"/>
--- a/browser/base/content/test/general/browser_devices_get_user_media.js
+++ b/browser/base/content/test/general/browser_devices_get_user_media.js
@@ -5,27 +5,22 @@
 requestLongerTimeout(2);
 
 const CONTENT_SCRIPT_HELPER = getRootDirectory(gTestPath) + "get_user_media_content_script.js";
 Cc["@mozilla.org/moz/jssubscript-loader;1"]
   .getService(Ci.mozIJSSubScriptLoader)
   .loadSubScript(getRootDirectory(gTestPath) + "get_user_media_helpers.js",
                  this);
 
-function enableDevice(aType, aEnabled) {
-  let menulist = document.getElementById("webRTC-select" + aType + "-menulist");
-  let menupopup = document.getElementById("webRTC-select" + aType + "-menupopup");
-  menulist.value = aEnabled ? menupopup.firstChild.getAttribute("value") : "-1";
-}
-
 registerCleanupFunction(function() {
   gBrowser.removeCurrentTab();
 });
 
-const permissionError = "error: SecurityError: The operation is insecure.";
+const permissionError = "error: NotAllowedError: The request is not allowed " +
+    "by the user agent or the platform in the current context.";
 
 var gTests = [
 
 {
   desc: "getUserMedia audio+video",
   run: function checkAudioVideo() {
     let promise = promisePopupNotificationShown("webRTC-shareDevices");
     yield promiseRequestDevice(true, true);
@@ -62,18 +57,16 @@ var gTests = [
     yield expectObserverCalled("getUserMedia:request");
 
     is(PopupNotifications.getNotification("webRTC-shareDevices").anchorID,
        "webRTC-shareMicrophone-notification-icon", "anchored to mic icon");
     checkDeviceSelectors(true);
     is(PopupNotifications.panel.firstChild.getAttribute("popupid"),
        "webRTC-shareMicrophone", "panel using microphone icon");
 
-    enableDevice("Microphone", true);
-
     let indicator = promiseIndicatorWindow();
     yield promiseMessage("ok", () => {
       PopupNotifications.panel.firstChild.button.click();
     });
     yield expectObserverCalled("getUserMedia:response:allow");
     yield expectObserverCalled("recording-device-events");
     is((yield getMediaCaptureState()), "Microphone",
        "expected microphone to be shared");
@@ -108,107 +101,16 @@ var gTests = [
 
     yield indicator;
     yield checkSharingUI({video: true});
     yield closeStream();
   }
 },
 
 {
-  desc: "getUserMedia audio+video, user disables video",
-  run: function checkDisableVideo() {
-    let promise = promisePopupNotificationShown("webRTC-shareDevices");
-    yield promiseRequestDevice(true, true);
-    yield promise;
-    yield expectObserverCalled("getUserMedia:request");
-    checkDeviceSelectors(true, true);
-
-    // disable the camera
-    enableDevice("Microphone", true);
-    enableDevice("Camera", false);
-
-    let indicator = promiseIndicatorWindow();
-    yield promiseMessage("ok", () => {
-      PopupNotifications.panel.firstChild.button.click();
-    });
-
-    // reset the menuitem to have no impact on the following tests.
-    enableDevice("Camera", true);
-
-    yield expectObserverCalled("getUserMedia:response:allow");
-    yield expectObserverCalled("recording-device-events");
-    is((yield getMediaCaptureState()), "Microphone",
-       "expected microphone to be shared");
-
-    yield indicator;
-    yield checkSharingUI({audio: true});
-    yield closeStream();
-  }
-},
-
-{
-  desc: "getUserMedia audio+video, user disables audio",
-  run: function checkDisableAudio() {
-    let promise = promisePopupNotificationShown("webRTC-shareDevices");
-    yield promiseRequestDevice(true, true);
-    yield promise;
-    yield expectObserverCalled("getUserMedia:request");
-    checkDeviceSelectors(true, true);
-
-    // disable the microphone
-    enableDevice("Microphone", false);
-    enableDevice("Camera", true);
-
-    let indicator = promiseIndicatorWindow();
-    yield promiseMessage("ok", () => {
-      PopupNotifications.panel.firstChild.button.click();
-    });
-
-    // reset the menuitem to have no impact on the following tests.
-    enableDevice("Microphone", true);
-
-    yield expectObserverCalled("getUserMedia:response:allow");
-    yield expectObserverCalled("recording-device-events");
-    is((yield getMediaCaptureState()), "Camera",
-       "expected microphone to be shared");
-
-    yield indicator;
-    yield checkSharingUI({video: true});
-    yield closeStream();
-  }
-},
-
-{
-  desc: "getUserMedia audio+video, user disables both audio and video",
-  run: function checkDisableAudioVideo() {
-    let promise = promisePopupNotificationShown("webRTC-shareDevices");
-    yield promiseRequestDevice(true, true);
-    yield promise;
-    yield expectObserverCalled("getUserMedia:request");
-    checkDeviceSelectors(true, true);
-
-    // disable the camera and microphone
-    enableDevice("Camera", false);
-    enableDevice("Microphone", false);
-
-    yield promiseMessage(permissionError, () => {
-      PopupNotifications.panel.firstChild.button.click();
-    });
-
-    // reset the menuitems to have no impact on the following tests.
-    enableDevice("Camera", true);
-    enableDevice("Microphone", true);
-
-    yield expectObserverCalled("getUserMedia:response:deny");
-    yield expectObserverCalled("recording-window-ended");
-    yield checkNotSharing();
-  }
-},
-
-{
   desc: "getUserMedia audio+video, user clicks \"Don't Share\"",
   run: function checkDontShare() {
     let promise = promisePopupNotificationShown("webRTC-shareDevices");
     yield promiseRequestDevice(true, true);
     yield promise;
     yield expectObserverCalled("getUserMedia:request");
     checkDeviceSelectors(true, true);
 
@@ -303,47 +205,40 @@ var gTests = [
   }
 },
 
 {
   desc: "getUserMedia prompt: Always/Never Share",
   run: function checkRememberCheckbox() {
     let elt = id => document.getElementById(id);
 
-    function checkPerm(aRequestAudio, aRequestVideo, aAllowAudio, aAllowVideo,
+    function checkPerm(aRequestAudio, aRequestVideo,
                        aExpectedAudioPerm, aExpectedVideoPerm, aNever) {
       let promise = promisePopupNotificationShown("webRTC-shareDevices");
       yield promiseRequestDevice(aRequestAudio, aRequestVideo);
       yield promise;
       yield expectObserverCalled("getUserMedia:request");
 
-      let noAudio = aAllowAudio === undefined;
-      is(elt("webRTC-selectMicrophone").hidden, noAudio,
-         "microphone selector expected to be " + (noAudio ? "hidden" : "visible"));
-      if (!noAudio)
-        enableDevice("Microphone", aAllowAudio || aNever);
+      is(elt("webRTC-selectMicrophone").hidden, !aRequestAudio,
+         "microphone selector expected to be " + (aRequestAudio ? "visible" : "hidden"));
 
-      let noVideo = aAllowVideo === undefined;
-      is(elt("webRTC-selectCamera").hidden, noVideo,
-         "camera selector expected to be " + (noVideo ? "hidden" : "visible"));
-      if (!noVideo)
-        enableDevice("Camera", aAllowVideo || aNever);
+      is(elt("webRTC-selectCamera").hidden, !aRequestVideo,
+         "camera selector expected to be " + (aRequestVideo ? "visible" : "hidden"));
 
-      let expectedMessage =
-        (aAllowVideo || aAllowAudio) ? "ok" : permissionError;
+      let expectedMessage = aNever ? permissionError : "ok";
       yield promiseMessage(expectedMessage, () => {
         activateSecondaryAction(aNever ? kActionNever : kActionAlways);
       });
       let expected = [];
       if (expectedMessage == "ok") {
         yield expectObserverCalled("getUserMedia:response:allow");
         yield expectObserverCalled("recording-device-events");
-        if (aAllowVideo)
+        if (aRequestVideo)
           expected.push("Camera");
-        if (aAllowAudio)
+        if (aRequestAudio)
           expected.push("Microphone");
         expected = expected.join("And");
       }
       else {
         yield expectObserverCalled("getUserMedia:response:deny");
         yield expectObserverCalled("recording-window-ended");
         expected = "none";
       }
@@ -366,49 +261,29 @@ var gTests = [
       checkDevicePermissions("camera", aExpectedVideoPerm);
 
       if (expectedMessage == "ok")
         yield closeStream();
     }
 
     // 3 cases where the user accepts the device prompt.
     info("audio+video, user grants, expect both perms set to allow");
-    yield checkPerm(true, true, true, true, true, true);
+    yield checkPerm(true, true, true, true);
     info("audio only, user grants, check audio perm set to allow, video perm not set");
-    yield checkPerm(true, false, true, undefined, true, undefined);
+    yield checkPerm(true, false, true, undefined);
     info("video only, user grants, check video perm set to allow, audio perm not set");
-    yield checkPerm(false, true, undefined, true, undefined, true);
+    yield checkPerm(false, true, undefined, true);
 
-    // 3 cases where the user rejects the device request.
-    // First test these cases by setting the device to 'No Audio'/'No Video'
-    info("audio+video, user denies, expect both perms set to deny");
-    yield checkPerm(true, true, false, false, false, false);
+    // 3 cases where the user rejects the device request by using 'Never Share'.
     info("audio only, user denies, expect audio perm set to deny, video not set");
-    yield checkPerm(true, false, false, undefined, false, undefined);
+    yield checkPerm(true, false, false, undefined, true);
     info("video only, user denies, expect video perm set to deny, audio perm not set");
-    yield checkPerm(false, true, undefined, false, undefined, false);
-    // Now test these 3 cases again by using the 'Never Share' action.
+    yield checkPerm(false, true, undefined, false, true);
     info("audio+video, user denies, expect both perms set to deny");
-    yield checkPerm(true, true, false, false, false, false, true);
-    info("audio only, user denies, expect audio perm set to deny, video not set");
-    yield checkPerm(true, false, false, undefined, false, undefined, true);
-    info("video only, user denies, expect video perm set to deny, audio perm not set");
-    yield checkPerm(false, true, undefined, false, undefined, false, true);
-
-    // 2 cases where the user allows half of what's requested.
-    info("audio+video, user denies video, grants audio, " +
-         "expect video perm set to deny, audio perm set to allow.");
-    yield checkPerm(true, true, true, false, true, false);
-    info("audio+video, user denies audio, grants video, " +
-         "expect video perm set to allow, audio perm set to deny.");
-    yield checkPerm(true, true, false, true, false, true);
-
-    // reset the menuitems to have no impact on the following tests.
-    enableDevice("Microphone", true);
-    enableDevice("Camera", true);
+    yield checkPerm(true, true, false, false, true);
   }
 },
 
 {
   desc: "getUserMedia without prompt: use persistent permissions",
   run: function checkUsePersistentPermissions() {
     function usePerm(aAllowAudio, aAllowVideo, aRequestAudio, aRequestVideo,
                      aExpectStream) {
@@ -473,58 +348,58 @@ var gTests = [
 
     // Set both permissions identically
     info("allow audio+video, request audio+video, expect ok (audio+video)");
     yield usePerm(true, true, true, true, true);
     info("deny audio+video, request audio+video, expect denied");
     yield usePerm(false, false, true, true, false);
 
     // Allow audio, deny video.
-    info("allow audio, deny video, request audio+video, expect ok (audio)");
-    yield usePerm(true, false, true, true, true);
+    info("allow audio, deny video, request audio+video, expect denied");
+    yield usePerm(true, false, true, true, false);
     info("allow audio, deny video, request audio, expect ok (audio)");
     yield usePerm(true, false, true, false, true);
     info("allow audio, deny video, request video, expect denied");
     yield usePerm(true, false, false, true, false);
 
     // Deny audio, allow video.
-    info("deny audio, allow video, request audio+video, expect ok (video)");
-    yield usePerm(false, true, true, true, true);
+    info("deny audio, allow video, request audio+video, expect denied");
+    yield usePerm(false, true, true, true, false);
     info("deny audio, allow video, request audio, expect denied");
     yield usePerm(false, true, true, false, false);
     info("deny audio, allow video, request video, expect ok (video)");
     yield usePerm(false, true, false, true, true);
 
     // Allow audio, video not set.
     info("allow audio, request audio+video, expect prompt");
     yield usePerm(true, undefined, true, true, undefined);
     info("allow audio, request audio, expect ok (audio)");
     yield usePerm(true, undefined, true, false, true);
     info("allow audio, request video, expect prompt");
     yield usePerm(true, undefined, false, true, undefined);
 
     // Deny audio, video not set.
-    info("deny audio, request audio+video, expect prompt");
-    yield usePerm(false, undefined, true, true, undefined);
+    info("deny audio, request audio+video, expect denied");
+    yield usePerm(false, undefined, true, true, false);
     info("deny audio, request audio, expect denied");
     yield usePerm(false, undefined, true, false, false);
     info("deny audio, request video, expect prompt");
     yield usePerm(false, undefined, false, true, undefined);
 
-    // Allow video, video not set.
+    // Allow video, audio not set.
     info("allow video, request audio+video, expect prompt");
     yield usePerm(undefined, true, true, true, undefined);
     info("allow video, request audio, expect prompt");
     yield usePerm(undefined, true, true, false, undefined);
     info("allow video, request video, expect ok (video)");
     yield usePerm(undefined, true, false, true, true);
 
-    // Deny video, video not set.
-    info("deny video, request audio+video, expect prompt");
-    yield usePerm(undefined, false, true, true, undefined);
+    // Deny video, audio not set.
+    info("deny video, request audio+video, expect denied");
+    yield usePerm(undefined, false, true, true, false);
     info("deny video, request audio, expect prompt");
     yield usePerm(undefined, false, true, false, undefined);
     info("deny video, request video, expect denied");
     yield usePerm(undefined, false, false, true, false);
   }
 },
 
 {
--- a/browser/base/content/test/general/browser_devices_get_user_media_about_urls.js
+++ b/browser/base/content/test/general/browser_devices_get_user_media_about_urls.js
@@ -57,17 +57,18 @@ function loadPage(aUrl) {
   content.location = aUrl;
   return deferred.promise;
 }
 
 registerCleanupFunction(function() {
   gBrowser.removeCurrentTab();
 });
 
-const permissionError = "error: SecurityError: The operation is insecure.";
+const permissionError = "error: NotAllowedError: The request is not allowed " +
+    "by the user agent or the platform in the current context.";
 
 var gTests = [
 
 {
   desc: "getUserMedia about:loopconversation shouldn't prompt",
   run: function checkAudioVideoLoop() {
     yield new Promise(resolve => SpecialPowers.pushPrefEnv({
       "set": [[PREF_LOOP_CSP, "default-src 'unsafe-inline'"]],
--- a/browser/components/migration/moz.build
+++ b/browser/components/migration/moz.build
@@ -1,16 +1,18 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini']
 
+MARIONETTE_UNIT_MANIFESTS += ['tests/marionette/manifest.ini']
+
 JAR_MANIFESTS += ['jar.mn']
 
 XPIDL_SOURCES += [
     'nsIBrowserProfileMigrator.idl',
 ]
 
 XPIDL_MODULE = 'migration'
 
new file mode 100644
--- /dev/null
+++ b/browser/components/migration/tests/marionette/manifest.ini
@@ -0,0 +1,8 @@
+[DEFAULT]
+qemu = false
+b2g = false
+browser = true
+skip = false
+
+[test_refresh_firefox.py]
+
new file mode 100644
--- /dev/null
+++ b/browser/components/migration/tests/marionette/test_refresh_firefox.py
@@ -0,0 +1,407 @@
+import os, shutil
+from marionette import MarionetteTestCase
+
+
+class TestFirefoxRefresh(MarionetteTestCase):
+    _username = "marionette-test-login"
+    _password = "marionette-test-password"
+    _bookmarkURL = "about:mozilla"
+    _bookmarkText = "Some bookmark from Marionette"
+
+    _cookieHost = "firefox-refresh.marionette-test.mozilla.org"
+    _cookiePath = "some/cookie/path"
+    _cookieName = "somecookie"
+    _cookieValue = "some cookie value"
+
+    _historyURL = "http://firefox-refresh.marionette-test.mozilla.org/"
+    _historyTitle = "Test visit for Firefox Reset"
+
+    _formHistoryFieldName = "some-very-unique-marionette-only-firefox-reset-field"
+    _formHistoryValue = "special-pumpkin-value"
+
+    _expectedURLs = ["about:robots", "about:mozilla"]
+
+    def savePassword(self):
+        self.runCode("""
+          let myLogin = new global.LoginInfo(
+            "test.marionette.mozilla.com",
+            "http://test.marionette.mozilla.com/some/form/",
+            null,
+            arguments[0],
+            arguments[1],
+            "username",
+            "password"
+          );
+          Services.logins.addLogin(myLogin)
+        """, script_args=[self._username, self._password])
+
+    def createBookmark(self):
+        self.marionette.execute_script("""
+          let url = arguments[0];
+          let title = arguments[1];
+          PlacesUtils.bookmarks.insertBookmark(PlacesUtils.bookmarks.bookmarksMenuFolder,
+            makeURI(url), 0, title);
+        """, script_args=[self._bookmarkURL, self._bookmarkText])
+
+    def createHistory(self):
+        error = self.runAsyncCode("""
+          // Copied from PlacesTestUtils, which isn't available in Marionette tests.
+          let didReturn;
+          PlacesUtils.asyncHistory.updatePlaces(
+            [{title: arguments[1], uri: makeURI(arguments[0]), visits: [{
+                transitionType: Ci.nsINavHistoryService.TRANSITION_LINK,
+                visitDate: (Date.now() - 5000) * 1000,
+                referrerURI: makeURI("about:mozilla"),
+              }]
+            }],
+            {
+              handleError(resultCode, place) {
+                didReturn = true;
+                marionetteScriptFinished("Unexpected error in adding visit: " + resultCode);
+              },
+              handleResult() {},
+              handleCompletion() {
+                if (!didReturn) {
+                  marionetteScriptFinished(false);
+                }
+              },
+            }
+          );
+        """, script_args=[self._historyURL, self._historyTitle])
+        if error:
+            print error
+
+    def createFormHistory(self):
+        error = self.runAsyncCode("""
+          let updateDefinition = {
+            op: "add",
+            fieldname: arguments[0],
+            value: arguments[1],
+            firstUsed: (Date.now() - 5000) * 1000,
+          };
+          let finished = false;
+          global.FormHistory.update(updateDefinition, {
+            handleError(error) {
+              finished = true;
+              marionetteScriptFinished(error);
+            },
+            handleCompletion() {
+              if (!finished) {
+                marionetteScriptFinished(false);
+              }
+            }
+          });
+        """, script_args=[self._formHistoryFieldName, self._formHistoryValue])
+        if error:
+          print error
+
+    def createCookie(self):
+        self.runCode("""
+          // Expire in 15 minutes:
+          let expireTime = Math.floor(Date.now() / 1000) + 15 * 60;
+          Services.cookies.add(arguments[0], arguments[1], arguments[2], arguments[3],
+                               true, false, false, expireTime);
+        """, script_args=[self._cookieHost, self._cookiePath, self._cookieName, self._cookieValue])
+
+    def createSession(self):
+        self.runAsyncCode("""
+          const COMPLETE_STATE = Ci.nsIWebProgressListener.STATE_STOP +
+                                 Ci.nsIWebProgressListener.STATE_IS_NETWORK;
+          let {TabStateFlusher} = Cu.import("resource:///modules/sessionstore/TabStateFlusher.jsm", {});
+          let expectedURLs = Array.from(arguments[0])
+          gBrowser.addTabsProgressListener({
+            onStateChange(browser, webprogress, request, flags, status) {
+              try {
+                request && request.QueryInterface(Ci.nsIChannel);
+              } catch (ex) {}
+              let uriLoaded = request.originalURI && request.originalURI.spec;
+              if ((flags & COMPLETE_STATE == COMPLETE_STATE) && uriLoaded &&
+                  expectedURLs.includes(uriLoaded)) {
+                TabStateFlusher.flush(browser).then(function() {
+                  expectedURLs.splice(expectedURLs.indexOf(uriLoaded), 1);
+                  if (!expectedURLs.length) {
+                    gBrowser.removeTabsProgressListener(this);
+                    marionetteScriptFinished();
+                  }
+                });
+              }
+            }
+          });
+          for (let url of expectedURLs) {
+            gBrowser.addTab(url);
+          }
+        """, script_args=[self._expectedURLs])
+
+    def checkPassword(self):
+        loginInfo = self.marionette.execute_script("""
+          let ary = Services.logins.findLogins({},
+            "test.marionette.mozilla.com",
+            "http://test.marionette.mozilla.com/some/form/",
+            null, {});
+          return ary.length ? ary : {username: "null", password: "null"};
+        """)
+        self.assertEqual(len(loginInfo), 1)
+        self.assertEqual(loginInfo[0]['username'], self._username)
+        self.assertEqual(loginInfo[0]['password'], self._password)
+
+        loginCount = self.marionette.execute_script("""
+          return Services.logins.getAllLogins().length;
+        """)
+        self.assertEqual(loginCount, 1, "No other logins are present")
+
+    def checkBookmark(self):
+        titleInBookmarks = self.marionette.execute_script("""
+          let url = arguments[0];
+          let bookmarkIds = PlacesUtils.bookmarks.getBookmarkIdsForURI(makeURI(url), {}, {});
+          return bookmarkIds.length == 1 ? PlacesUtils.bookmarks.getItemTitle(bookmarkIds[0]) : "";
+        """, script_args=[self._bookmarkURL])
+        self.assertEqual(titleInBookmarks, self._bookmarkText)
+
+    def checkHistory(self):
+        historyResults = self.runAsyncCode("""
+          let placeInfos = [];
+          PlacesUtils.asyncHistory.getPlacesInfo(makeURI(arguments[0]), {
+            handleError(resultCode, place) {
+              placeInfos = null;
+              marionetteScriptFinished("Unexpected error in fetching visit: " + resultCode);
+            },
+            handleResult(placeInfo) {
+              placeInfos.push(placeInfo);
+            },
+            handleCompletion() {
+              if (placeInfos) {
+                if (!placeInfos.length) {
+                  marionetteScriptFinished("No visits found");
+                } else {
+                  marionetteScriptFinished(placeInfos);
+                }
+              }
+            },
+          });
+        """, script_args=[self._historyURL])
+        if type(historyResults) == str:
+            self.fail(historyResults)
+            return
+
+        historyCount = len(historyResults)
+        self.assertEqual(historyCount, 1, "Should have exactly 1 entry for URI, got %d" % historyCount)
+        if historyCount == 1:
+            self.assertEqual(historyResults[0]['title'], self._historyTitle)
+
+    def checkFormHistory(self):
+        formFieldResults = self.runAsyncCode("""
+          let results = [];
+          global.FormHistory.search(["value"], {fieldname: arguments[0]}, {
+            handleError(error) {
+              results = error;
+            },
+            handleResult(result) {
+              results.push(result);
+            },
+            handleCompletion() {
+              marionetteScriptFinished(results);
+            },
+          });
+        """, script_args=[self._formHistoryFieldName])
+        if type(formFieldResults) == str:
+            self.fail(formFieldResults)
+            return
+
+        formFieldResultCount = len(formFieldResults)
+        self.assertEqual(formFieldResultCount, 1, "Should have exactly 1 entry for this field, got %d" % formFieldResultCount)
+        if formFieldResultCount == 1:
+            self.assertEqual(formFieldResults[0]['value'], self._formHistoryValue)
+
+        formHistoryCount = self.runAsyncCode("""
+          let count;
+          let callbacks = {
+            handleResult: rv => count = rv,
+            handleCompletion() {
+              marionetteScriptFinished(count);
+            },
+          };
+          global.FormHistory.count({}, callbacks);
+        """)
+        self.assertEqual(formHistoryCount, 1, "There should be only 1 entry in the form history")
+
+    def checkCookie(self):
+        cookieInfo = self.runCode("""
+          try {
+            let cookieEnum = Services.cookies.getCookiesFromHost(arguments[0]);
+            let cookie = null;
+            while (cookieEnum.hasMoreElements()) {
+              if (cookie != null) {
+                return "more than 1 cookie! That shouldn't happen!";
+              }
+              cookie = cookieEnum.getNext();
+              cookie.QueryInterface(Ci.nsICookie2);
+            }
+            return {path: cookie.path, name: cookie.name, value: cookie.value};
+          } catch (ex) {
+            return "got exception trying to fetch cookie: " + ex;
+          }
+        """, script_args=[self._cookieHost])
+        self.assertEqual(cookieInfo['path'], self._cookiePath)
+        self.assertEqual(cookieInfo['value'], self._cookieValue)
+        self.assertEqual(cookieInfo['name'], self._cookieName)
+
+    def checkSession(self):
+        tabURIs = self.runCode("""
+          return [... gBrowser.browsers].map(b => b.currentURI && b.currentURI.spec)
+        """)
+        self.assertSequenceEqual(tabURIs, ["about:welcomeback"])
+
+        tabURIs = self.runAsyncCode("""
+          let mm = gBrowser.selectedBrowser.messageManager;
+          let fs = function() {
+            content.document.getElementById("errorTryAgain").click();
+          };
+          let {TabStateFlusher} = Cu.import("resource:///modules/sessionstore/TabStateFlusher.jsm", {});
+          window.addEventListener("SSWindowStateReady", function testSSPostReset() {
+            window.removeEventListener("SSWindowStateReady", testSSPostReset, false);
+            Promise.all(gBrowser.browsers.map(b => TabStateFlusher.flush(b))).then(function() {
+              marionetteScriptFinished([... gBrowser.browsers].map(b => b.currentURI && b.currentURI.spec));
+            });
+          }, false);
+          mm.loadFrameScript("data:application/javascript,(" + fs.toString() + ")()", true);
+        """)
+        self.assertSequenceEqual(tabURIs, ["about:blank"] + self._expectedURLs)
+        pass
+
+    def checkProfile(self, hasMigrated=False):
+        self.checkPassword()
+        self.checkBookmark()
+        self.checkHistory()
+        self.checkFormHistory()
+        self.checkCookie()
+        if hasMigrated:
+            self.checkSession()
+
+    def createProfileData(self):
+        self.savePassword()
+        self.createBookmark()
+        self.createHistory()
+        self.createFormHistory()
+        self.createCookie()
+        self.createSession()
+
+    def setUpScriptData(self):
+        self.marionette.set_context(self.marionette.CONTEXT_CHROME)
+        self.marionette.execute_script("""
+          global.LoginInfo = Components.Constructor("@mozilla.org/login-manager/loginInfo;1", "nsILoginInfo", "init");
+          global.profSvc = Cc["@mozilla.org/toolkit/profile-service;1"].getService(Ci.nsIToolkitProfileService);
+          global.Preferences = Cu.import("resource://gre/modules/Preferences.jsm", {}).Preferences;
+          global.FormHistory = Cu.import("resource://gre/modules/FormHistory.jsm", {}).FormHistory;
+        """, new_sandbox=False, sandbox='system')
+
+    def runCode(self, script, *args, **kwargs):
+        return self.marionette.execute_script(script, new_sandbox=False, sandbox='system', *args, **kwargs)
+
+    def runAsyncCode(self, script, *args, **kwargs):
+        return self.marionette.execute_async_script(script, new_sandbox=False, sandbox='system', *args, **kwargs)
+
+    def setUp(self):
+        MarionetteTestCase.setUp(self)
+        self.setUpScriptData()
+
+        self.reset_profile_path = None
+        self.desktop_backup_path = None
+
+        self.createProfileData()
+
+    def tearDown(self):
+        # Force yet another restart with a clean profile to disconnect from the
+        # profile and environment changes we've made, to leave a more or less
+        # blank slate for the next person.
+        self.marionette.restart(clean=True, in_app=False)
+        self.setUpScriptData()
+
+        # Super
+        MarionetteTestCase.tearDown(self)
+
+        # Some helpers to deal with removing a load of files
+        import errno, stat
+        def handleRemoveReadonly(func, path, exc):
+            excvalue = exc[1]
+            if func in (os.rmdir, os.remove) and excvalue.errno == errno.EACCES:
+                os.chmod(path, stat.S_IRWXU| stat.S_IRWXG| stat.S_IRWXO) # 0777
+                func(path)
+            else:
+                raise
+
+        if self.desktop_backup_path:
+            shutil.rmtree(self.desktop_backup_path, ignore_errors=False, onerror=handleRemoveReadonly)
+
+        if self.reset_profile_path:
+            # Remove ourselves from profiles.ini
+            profileLeafName = os.path.basename(os.path.normpath(self.reset_profile_path))
+            self.runCode("""
+              let [salt, name] = arguments[0].split(".");
+              let profile = global.profSvc.getProfileByName(name);
+              profile.remove(false)
+              global.profSvc.flush();
+            """, script_args=[profileLeafName])
+            # And delete all the files.
+            shutil.rmtree(self.reset_profile_path, ignore_errors=False, onerror=handleRemoveReadonly)
+
+    def doReset(self):
+        self.runCode("""
+          // Ensure the current (temporary) profile is in profiles.ini:
+          let profD = Services.dirsvc.get("ProfD", Ci.nsIFile);
+          let profileName = "marionette-test-profile-" + Date.now();
+          let myProfile = global.profSvc.createProfile(profD, profileName);
+          global.profSvc.flush()
+
+          // Now add the reset parameters:
+          let env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment);
+          let allMarionettePrefs = Services.prefs.getChildList("marionette.");
+          let prefObj = {};
+          for (let pref of allMarionettePrefs) {
+            let prefSuffix = pref.substr("marionette.".length);
+            let prefVal = global.Preferences.get(pref);
+            prefObj[prefSuffix] = prefVal;
+          }
+          let marionetteInfo = JSON.stringify(prefObj);
+          env.set("MOZ_MARIONETTE_PREF_STATE_ACROSS_RESTARTS", marionetteInfo);
+          env.set("MOZ_RESET_PROFILE_RESTART", "1");
+          env.set("XRE_PROFILE_PATH", arguments[0]);
+          env.set("XRE_PROFILE_NAME", profileName);
+        """, script_args=[self.marionette.instance.profile.profile])
+
+        profileLeafName = os.path.basename(os.path.normpath(self.marionette.instance.profile.profile))
+
+        # Now restart the browser to get it reset:
+        self.marionette.restart(clean=False, in_app=True)
+        self.setUpScriptData()
+
+        # Determine the new profile path (we'll need to remove it when we're done)
+        self.reset_profile_path = self.runCode("""
+          let profD = Services.dirsvc.get("ProfD", Ci.nsIFile);
+          return profD.path;
+        """)
+
+        # Determine the backup path
+        self.desktop_backup_path = self.runCode("""
+          let container;
+          try {
+            container = Services.dirsvc.get("Desk", Ci.nsIFile);
+          } catch (ex) {
+            container = Services.dirsvc.get("Home", Ci.nsIFile);
+          }
+          let bundle = Services.strings.createBundle("chrome://mozapps/locale/profile/profileSelection.properties");
+          let dirName = bundle.formatStringFromName("resetBackupDirectory", [Services.appinfo.name], 1);
+          container.append(dirName);
+          container.append(arguments[0]);
+          return container.path;
+        """, script_args = [profileLeafName])
+
+        self.assertTrue(os.path.isdir(self.reset_profile_path), "Reset profile path should be present")
+        self.assertTrue(os.path.isdir(self.desktop_backup_path), "Backup profile path should be present")
+
+    def testReset(self):
+        self.checkProfile()
+
+        self.doReset()
+
+        # Now check that we're doing OK...
+        self.checkProfile(hasMigrated=True)
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -112,21 +112,16 @@ XPCOMUtils.defineLazyModuleGetter(this, 
                                   "resource://gre/modules/LoginHelper.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "SimpleServiceDiscovery",
                                   "resource://gre/modules/SimpleServiceDiscovery.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "ContentSearch",
                                   "resource:///modules/ContentSearch.jsm");
 
-if (AppConstants.E10S_TESTING_ONLY) {
-  XPCOMUtils.defineLazyModuleGetter(this, "UpdateUtils",
-                                    "resource://gre/modules/UpdateUtils.jsm");
-}
-
 XPCOMUtils.defineLazyModuleGetter(this, "TabCrashHandler",
                                   "resource:///modules/ContentCrashHandlers.jsm");
 if (AppConstants.MOZ_CRASHREPORTER) {
   XPCOMUtils.defineLazyModuleGetter(this, "PluginCrashReporter",
                                     "resource:///modules/ContentCrashHandlers.jsm");
 }
 
 XPCOMUtils.defineLazyGetter(this, "gBrandBundle", function() {
@@ -2991,164 +2986,16 @@ var DefaultBrowserCheck = {
       let popup = doc.getElementById(this.OPTIONPOPUP);
       popup.removeEventListener("command", this);
       popup.remove();
       delete this._notification;
     }
   },
 };
 
-var E10SUINotification = {
-  CURRENT_PROMPT_PREF: "browser.displayedE10SPrompt.1",
-  PREVIOUS_PROMPT_PREF: "browser.displayedE10SPrompt",
-
-  get forcedOn() {
-    try {
-      return Services.prefs.getBoolPref("browser.tabs.remote.force-enable");
-    } catch (e) {}
-    return false;
-  },
-
-  get a11yRecentlyRan() {
-    try {
-      if (Services.prefs.getBoolPref("accessibility.loadedInLastSession")) {
-        return true;
-      }
-    } catch (e) {}
-    try {
-      Services.prefs.getBoolPref("accessibility.lastLoadDate");
-      return true;
-    } catch (e) {}
-    return false;
-  },
-
-  checkStatus: function() {
-    let updateChannel = UpdateUtils.UpdateChannel;
-    let channelAuthorized = updateChannel == "nightly" || updateChannel == "aurora";
-    if (!channelAuthorized) {
-      return;
-    }
-
-    if (!Services.appinfo.browserTabsRemoteAutostart) {
-      let displayFeedbackRequest = false;
-      try {
-        displayFeedbackRequest = Services.prefs.getBoolPref("browser.requestE10sFeedback");
-      } catch (e) {}
-
-      if (displayFeedbackRequest) {
-        let win = RecentWindow.getMostRecentBrowserWindow();
-        if (!win) {
-          return;
-        }
-
-        Services.prefs.clearUserPref("browser.requestE10sFeedback");
-
-        let url = Services.urlFormatter.formatURLPref("app.feedback.baseURL");
-        url += "?utm_source=tab&utm_campaign=e10sfeedback";
-
-        win.openUILinkIn(url, "tab");
-        return;
-      }
-
-      // If accessibility recently ran, don't prompt about trying out e10s
-      if (this.a11yRecentlyRan) {
-        return;
-      }
-
-      let e10sPromptShownCount = 0;
-      try {
-        e10sPromptShownCount = Services.prefs.getIntPref(this.CURRENT_PROMPT_PREF);
-      } catch(e) {}
-
-      let isHardwareAccelerated = true;
-      // Linux and Windows are currently ok, mac not so much.
-      if (AppConstants.platform == "macosx") {
-        try {
-          let win = RecentWindow.getMostRecentBrowserWindow();
-          let winutils = win.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
-          isHardwareAccelerated = winutils.layerManagerType != "Basic";
-        } catch (e) {}
-      }
-
-      if (!Services.appinfo.inSafeMode &&
-          !Services.appinfo.accessibilityEnabled &&
-          isHardwareAccelerated &&
-          e10sPromptShownCount < 5) {
-        Services.tm.mainThread.dispatch(() => {
-          try {
-            this._showE10SPrompt();
-            Services.prefs.setIntPref(this.CURRENT_PROMPT_PREF, e10sPromptShownCount + 1);
-            Services.prefs.clearUserPref(this.PREVIOUS_PROMPT_PREF);
-          } catch (ex) {
-            Cu.reportError("Failed to show e10s prompt: " + ex);
-          }
-        }, Ci.nsIThread.DISPATCH_NORMAL);
-      }
-    }
-  },
-
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
-
-  _showE10SPrompt: function BG__showE10SPrompt() {
-    let win = RecentWindow.getMostRecentBrowserWindow();
-    if (!win)
-      return;
-
-    let browser = win.gBrowser.selectedBrowser;
-
-    let promptMessage = win.gNavigatorBundle.getFormattedString(
-                          "e10s.offerPopup.mainMessage",
-                          [gBrandBundle.GetStringFromName("brandShortName")]
-                        );
-    let mainAction = {
-      label: win.gNavigatorBundle.getString("e10s.offerPopup.enableAndRestart.label"),
-      accessKey: win.gNavigatorBundle.getString("e10s.offerPopup.enableAndRestart.accesskey"),
-      callback: function () {
-        Services.prefs.setBoolPref("browser.tabs.remote.autostart", true);
-        Services.prefs.setBoolPref("browser.enabledE10SFromPrompt", true);
-        // Restart the app
-        let cancelQuit = Cc["@mozilla.org/supports-PRBool;1"].createInstance(Ci.nsISupportsPRBool);
-        Services.obs.notifyObservers(cancelQuit, "quit-application-requested", "restart");
-        if (cancelQuit.data)
-          return; // somebody canceled our quit request
-        Services.startup.quit(Services.startup.eAttemptQuit | Services.startup.eRestart);
-      }
-    };
-    let secondaryActions = [
-      {
-        label: win.gNavigatorBundle.getString("e10s.offerPopup.noThanks.label"),
-        accessKey: win.gNavigatorBundle.getString("e10s.offerPopup.noThanks.accesskey"),
-        callback: function () {
-          Services.prefs.setIntPref(E10SUINotification.CURRENT_PROMPT_PREF, 5);
-        }
-      }
-    ];
-    let options = {
-      popupIconURL: "chrome://browser/skin/e10s-64@2x.png",
-      learnMoreURL: "https://wiki.mozilla.org/Electrolysis",
-      persistWhileVisible: true
-    };
-
-    win.PopupNotifications.show(browser, "enable-e10s", promptMessage, null, mainAction, secondaryActions, options);
-
-    let highlights = [
-      win.gNavigatorBundle.getString("e10s.offerPopup.highlight1"),
-      win.gNavigatorBundle.getString("e10s.offerPopup.highlight2")
-    ];
-
-    let doorhangerExtraContent = win.document.getElementById("enable-e10s-notification")
-                                             .querySelector("popupnotificationcontent");
-    for (let highlight of highlights) {
-      let highlightLabel = win.document.createElement("label");
-      highlightLabel.setAttribute("value", highlight);
-      doorhangerExtraContent.appendChild(highlightLabel);
-    }
-  }
-};
-
 var E10SAccessibilityCheck = {
   init: function() {
     Services.obs.addObserver(this, "a11y-init-or-shutdown", true);
     Services.obs.addObserver(this, "quit-application-granted", true);
   },
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
 
--- a/browser/components/preferences/in-content/main.js
+++ b/browser/components/preferences/in-content/main.js
@@ -156,22 +156,16 @@ var gMainPane = {
                                    "restart");
       shouldProceed = !cancelQuit.data;
 
       if (shouldProceed) {
         for (let prefToChange of prefsToChange) {
           prefToChange.value = e10sCheckbox.checked;
         }
 
-        let tmp = {};
-        Components.utils.import("resource://gre/modules/UpdateUtils.jsm", tmp);
-        if (!e10sCheckbox.checked && tmp.UpdateUtils.UpdateChannel != "default") {
-          Services.prefs.setBoolPref("browser.requestE10sFeedback", true);
-          Services.prompt.alert(window, brandName, bundle.getString("e10sFeedbackAfterRestart"));
-        }
         Services.startup.quit(Ci.nsIAppStartup.eAttemptQuit |  Ci.nsIAppStartup.eRestart);
       }
     }
 
     // Revert the checkbox in case we didn't quit
     e10sCheckbox.checked = e10sPref.value || e10sTempPref.value;
   },
 #endif
--- a/browser/config/mozconfigs/linux32/common-opt
+++ b/browser/config/mozconfigs/linux32/common-opt
@@ -1,12 +1,11 @@
 # This file is sourced by nightly, beta, and release mozconfigs.
 
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
-ac_add_options --enable-update-packaging
 ac_add_options --with-google-api-keyfile=/builds/gapi.data
 ac_add_options --with-google-oauth-api-keyfile=/builds/google-oauth-api.key
 ac_add_options --with-mozilla-api-keyfile=/builds/mozilla-desktop-geoloc-api.key
 
 . $topsrcdir/build/unix/mozconfig.linux32
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
--- a/browser/config/mozconfigs/linux32/l10n-mozconfig
+++ b/browser/config/mozconfigs/linux32/l10n-mozconfig
@@ -1,13 +1,12 @@
 no_sccache=1
 
 ac_add_options --with-l10n-base=../../l10n
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
-ac_add_options --enable-update-packaging
 ac_add_options --with-branding=browser/branding/nightly
 
 . $topsrcdir/build/unix/mozconfig.linux32
 
 export MOZILLA_OFFICIAL=1
 
 # Enable Telemetry
 export MOZ_TELEMETRY_REPORTING=1
--- a/browser/config/mozconfigs/linux64/common-opt
+++ b/browser/config/mozconfigs/linux64/common-opt
@@ -1,12 +1,11 @@
 # This file is sourced by the nightly, beta, and release mozconfigs.
 
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
-ac_add_options --enable-update-packaging
 ac_add_options --with-google-api-keyfile=/builds/gapi.data
 ac_add_options --with-google-oauth-api-keyfile=/builds/google-oauth-api.key
 ac_add_options --with-mozilla-api-keyfile=/builds/mozilla-desktop-geoloc-api.key
 
 . $topsrcdir/build/unix/mozconfig.linux
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
--- a/browser/config/mozconfigs/linux64/l10n-mozconfig
+++ b/browser/config/mozconfigs/linux64/l10n-mozconfig
@@ -1,13 +1,12 @@
 no_sccache=1
 
 ac_add_options --with-l10n-base=../../l10n
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
-ac_add_options --enable-update-packaging
 ac_add_options --with-branding=browser/branding/nightly
 
 . $topsrcdir/build/unix/mozconfig.linux
 
 export MOZILLA_OFFICIAL=1
 
 # Enable Telemetry
 export MOZ_TELEMETRY_REPORTING=1
--- a/browser/config/mozconfigs/macosx-universal/common-opt
+++ b/browser/config/mozconfigs/macosx-universal/common-opt
@@ -1,17 +1,16 @@
 # This file is sourced by the nightly, beta, and release mozconfigs.
 
 . $topsrcdir/build/macosx/universal/mozconfig
 
 # Universal builds override the default of browser (bug 575283 comment 29)
 ac_add_options --enable-application=browser
 
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
-ac_add_options --enable-update-packaging
 ac_add_options --with-google-api-keyfile=/builds/gapi.data
 ac_add_options --with-google-oauth-api-keyfile=/builds/google-oauth-api.key
 ac_add_options --with-mozilla-api-keyfile=/builds/mozilla-desktop-geoloc-api.key
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
 export MOZ_TELEMETRY_REPORTING=1
--- a/browser/config/mozconfigs/macosx-universal/l10n-mozconfig
+++ b/browser/config/mozconfigs/macosx-universal/l10n-mozconfig
@@ -1,14 +1,13 @@
 . "$topsrcdir/browser/config/mozconfigs/common"
 . "$topsrcdir/build/macosx/mozconfig.common"
 
 ac_add_options --with-l10n-base=../../l10n
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
-ac_add_options --enable-update-packaging
 ac_add_options --with-branding=browser/branding/nightly
 
 if test "${MOZ_UPDATE_CHANNEL}" = "nightly"; then
 ac_add_options --with-macbundlename-prefix=Firefox
 fi
 
 export MOZILLA_OFFICIAL=1
 
--- a/browser/config/mozconfigs/macosx64/l10n-mozconfig
+++ b/browser/config/mozconfigs/macosx64/l10n-mozconfig
@@ -1,9 +1,8 @@
 . "$topsrcdir/browser/config/mozconfigs/common"
 
 ac_add_options --with-l10n-base=../../l10n
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
-ac_add_options --enable-update-packaging
 ac_add_options --with-branding=browser/branding/nightly
 
 . "$topsrcdir/build/mozconfig.common.override"
 . "$topsrcdir/build/mozconfig.cache"
--- a/browser/config/mozconfigs/win32/common-opt
+++ b/browser/config/mozconfigs/win32/common-opt
@@ -1,14 +1,13 @@
 # This file is sourced by the nightly, beta, and release mozconfigs.
 
 . "$topsrcdir/browser/config/mozconfigs/common"
 
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
-ac_add_options --enable-update-packaging
 ac_add_options --enable-jemalloc
 ac_add_options --enable-require-all-d3dc-versions
 
 if [ -f /c/builds/gapi.data ]; then
   _gapi_keyfile=/c/builds/gapi.data
 else
   _gapi_keyfile=/e/builds/gapi.data
 fi
--- a/browser/config/mozconfigs/win32/l10n-mozconfig
+++ b/browser/config/mozconfigs/win32/l10n-mozconfig
@@ -1,12 +1,11 @@
 . "$topsrcdir/browser/config/mozconfigs/common"
 
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
-ac_add_options --enable-update-packaging
 ac_add_options --with-l10n-base=../../l10n
 ac_add_options --with-windows-version=603
 ac_add_options --with-branding=browser/branding/nightly
 
 export MOZILLA_OFFICIAL=1
 
 # Enable Telemetry
 export MOZ_TELEMETRY_REPORTING=1
--- a/browser/config/mozconfigs/win64/common-opt
+++ b/browser/config/mozconfigs/win64/common-opt
@@ -1,14 +1,13 @@
 # This file is sourced by the nightly, beta, and release mozconfigs.
 
 . "$topsrcdir/browser/config/mozconfigs/common"
 
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
-ac_add_options --enable-update-packaging
 ac_add_options --enable-jemalloc
 if [ -f /c/builds/gapi.data ]; then
   _gapi_keyfile=/c/builds/gapi.data
 else
   _gapi_keyfile=/e/builds/gapi.data
 fi
 ac_add_options --with-google-api-keyfile=${_gapi_keyfile}
 
--- a/browser/config/mozconfigs/win64/l10n-mozconfig
+++ b/browser/config/mozconfigs/win64/l10n-mozconfig
@@ -1,13 +1,12 @@
 . "$topsrcdir/browser/config/mozconfigs/common"
 . "$topsrcdir/browser/config/mozconfigs/win64/common-win64"
 
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
-ac_add_options --enable-update-packaging
 ac_add_options --with-l10n-base=../../l10n
 ac_add_options --with-windows-version=603
 ac_add_options --with-branding=browser/branding/nightly
 
 export MOZILLA_OFFICIAL=1
 
 # Enable Telemetry
 export MOZ_TELEMETRY_REPORTING=1
--- a/browser/locales/en-US/chrome/browser/browser.properties
+++ b/browser/locales/en-US/chrome/browser/browser.properties
@@ -511,21 +511,19 @@ getUserMedia.shareScreenAndMicrophone.me
 getUserMedia.shareScreenAndAudioCapture.message = Would you like to share this tab’s audio and your screen with %S?
 getUserMedia.shareAudioCapture.message = Would you like to share this tab’s audio with %S?
 getUserMedia.selectWindow.label=Window to share:
 getUserMedia.selectWindow.accesskey=W
 getUserMedia.selectScreen.label=Screen to share:
 getUserMedia.selectScreen.accesskey=S
 getUserMedia.selectApplication.label=Application to share:
 getUserMedia.selectApplication.accesskey=A
-getUserMedia.noVideo.label = No Video
 getUserMedia.noApplication.label = No Application
 getUserMedia.noScreen.label = No Screen
 getUserMedia.noWindow.label = No Window
-getUserMedia.noAudio.label = No Audio
 getUserMedia.shareEntireScreen.label = Entire screen
 # LOCALIZATION NOTE (getUserMedia.shareMonitor.label):
 # %S is screen number (digits 1, 2, etc)
 # Example: Screen 1, Screen 2,..
 getUserMedia.shareMonitor.label = Screen %S
 # LOCALIZATION NOTE (getUserMedia.shareApplicationWindowCount.label):
 # Semicolon-separated list of plural forms.
 # See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
@@ -688,37 +686,23 @@ readingList.promo.firstUse.readerView.bo
 # https://www.mozilla.org/firefox/android/.
 # %2$S will be replaced with a link, the text of which is
 # appMenuRemoteTabs.mobilePromo.ios
 # and the link will be to https://www.mozilla.org/firefox/ios/.
 appMenuRemoteTabs.mobilePromo.text2 = Download %1$S or %2$S and connect them to your Firefox Account.
 appMenuRemoteTabs.mobilePromo.android = Firefox for Android
 appMenuRemoteTabs.mobilePromo.ios = Firefox for iOS
 
-# LOCALIZATION NOTE (e10s.offerPopup.mainMessage
-#                    e10s.offerPopup.highlight1
-#                    e10s.offerPopup.highlight2
-#                    e10s.offerPopup.enableAndRestart.label
-#                    e10s.offerPopup.enableAndRestart.accesskey
-#                    e10s.offerPopup.noThanks.label
-#                    e10s.offerPopup.noThanks.accesskey
-#                    e10s.accessibilityNotice.mainMessage
-#                    e10s.accessibilityNotice.enableAndRestart.label
-#                    e10s.accessibilityNotice.enableAndRestart.accesskey
+# LOCALIZATION NOTE (e10s.accessibilityNotice.mainMessage,
+#                    e10s.accessibilityNotice.enableAndRestart.label,
+#                    e10s.accessibilityNotice.enableAndRestart.accesskey):
 # These strings are related to the messages we display to offer e10s (Multi-process) to users
 # on the pre-release channels. They won't be used in release but they will likely be used in
 # beta starting from version 41, so it's still useful to have these strings properly localized.
 # %S is brandShortName
-e10s.offerPopup.mainMessage = Multi-process is coming soon to %S. You can start using it now to get early access to some of the benefits:
-e10s.offerPopup.highlight1 = Improved responsiveness
-e10s.offerPopup.highlight2 = Fewer crashes
-e10s.offerPopup.enableAndRestart.label = Enable and Restart
-e10s.offerPopup.enableAndRestart.accesskey = E
-e10s.offerPopup.noThanks.label = No, thanks
-e10s.offerPopup.noThanks.accesskey = N
 e10s.accessibilityNotice.mainMessage2 = Accessibility support is partially disabled due to compatibility issues with new %S features.
 e10s.accessibilityNotice.acceptButton.label = OK
 e10s.accessibilityNotice.acceptButton.accesskey = O
 e10s.accessibilityNotice.enableAndRestart.label = Enable (Requires Restart)
 e10s.accessibilityNotice.enableAndRestart.accesskey = E
 
 # LOCALIZATION NOTE (usercontext.personal.label,
 #                    usercontext.work.label,
--- a/browser/locales/en-US/chrome/browser/preferences/preferences.properties
+++ b/browser/locales/en-US/chrome/browser/preferences/preferences.properties
@@ -170,13 +170,8 @@ syncUnlinkConfirm.label=Unlink
 featureEnableRequiresRestart=%S must restart to enable this feature.
 featureDisableRequiresRestart=%S must restart to disable this feature.
 shouldRestartTitle=Restart %S
 okToRestartButton=Restart %S now
 revertNoRestartButton=Revert
 
 restartNow=Restart Now
 restartLater=Restart Later
-
-#### e10S
-# LOCALIZATION NOTE (e10sFeedbackAfterRestart): This message appears when the user
-# unchecks "Enable multi-process" on the "General" preferences tab.
-e10sFeedbackAfterRestart=After restart, a tab will open to input.mozilla.org where you can provide us feedback about your e10s experience.
--- a/browser/modules/webrtcUI.jsm
+++ b/browser/modules/webrtcUI.jsm
@@ -521,24 +521,16 @@ function prompt(aBrowser, aRequest) {
       if (sharingScreen)
         listScreenShareDevices(windowMenupopup, videoDevices);
       else
         listDevices(camMenupopup, videoDevices);
 
       if (!sharingAudio)
         listDevices(micMenupopup, audioDevices);
 
-      if (requestTypes.length == 2) {
-        let stringBundle = chromeDoc.defaultView.gNavigatorBundle;
-        if (!sharingScreen)
-          addDeviceToList(camMenupopup, stringBundle.getString("getUserMedia.noVideo.label"), "-1");
-        if (!sharingAudio)
-          addDeviceToList(micMenupopup, stringBundle.getString("getUserMedia.noAudio.label"), "-1");
-      }
-
       this.mainAction.callback = function(aRemember) {
         let allowedDevices = [];
         let perms = Services.perms;
         if (videoDevices.length) {
           let listId = "webRTC-select" + (sharingScreen ? "Window" : "Camera") + "-menulist";
           let videoDeviceIndex = chromeDoc.getElementById(listId).value;
           let allowCamera = videoDeviceIndex != "-1";
           if (allowCamera) {
--- a/build/moz.configure/old.configure
+++ b/build/moz.configure/old.configure
@@ -254,17 +254,16 @@ def old_configure_options(*options):
     '--enable-tasktracer',
     '--enable-tests',
     '--enable-thread-sanitizer',
     '--enable-trace-logging',
     '--enable-tree-freetype',
     '--enable-ui-locale',
     '--enable-universalchardet',
     '--enable-update-channel',
-    '--enable-update-packaging',
     '--enable-updater',
     '--enable-url-classifier',
     '--enable-valgrind',
     '--enable-verify-mar',
     '--enable-warnings-as-errors',
     '--enable-webapp-runtime',
     '--enable-webrtc',
     '--enable-websms-backend',
--- a/dom/base/File.cpp
+++ b/dom/base/File.cpp
@@ -460,19 +460,25 @@ File::WrapObject(JSContext* aCx, JS::Han
 
 void
 File::GetName(nsAString& aFileName) const
 {
   mImpl->GetName(aFileName);
 }
 
 void
-File::GetPath(nsAString& aPath, ErrorResult& aRv)
+File::GetPath(nsAString& aPath) const
 {
-  mImpl->GetPath(aPath, aRv);
+  mImpl->GetPath(aPath);
+}
+
+void
+File::SetPath(const nsAString& aPath)
+{
+  mImpl->SetPath(aPath);
 }
 
 Date
 File::GetLastModifiedDate(ErrorResult& aRv)
 {
   int64_t value = GetLastModified(aRv);
   if (aRv.Failed()) {
     return Date();
@@ -680,23 +686,30 @@ NS_IMPL_ISUPPORTS_INHERITED0(BlobImplFil
 void
 BlobImplBase::GetName(nsAString& aName) const
 {
   NS_ASSERTION(mIsFile, "Should only be called on files");
   aName = mName;
 }
 
 void
-BlobImplBase::GetPath(nsAString& aPath, ErrorResult& aRv)
+BlobImplBase::GetPath(nsAString& aPath) const
 {
   NS_ASSERTION(mIsFile, "Should only be called on files");
   aPath = mPath;
 }
 
 void
+BlobImplBase::SetPath(const nsAString& aPath)
+{
+  NS_ASSERTION(mIsFile, "Should only be called on files");
+  mPath = aPath;
+}
+
+void
 BlobImplBase::GetMozFullPath(nsAString& aFileName, ErrorResult& aRv) const
 {
   NS_ASSERTION(mIsFile, "Should only be called on files");
 
   aFileName.Truncate();
 
   if (NS_IsMainThread()) {
     if (nsContentUtils::LegacyIsCallerChromeOrNativeCode()) {
@@ -980,25 +993,16 @@ BlobImplFile::GetInternalStream(nsIInput
     aRv = NS_NewLocalFileInputStream(aStream, mFile, -1, -1, sFileStreamFlags);
     return;
   }
 
   aRv = NS_NewPartialLocalFileInputStream(aStream, mFile, mStart, mLength,
                                           -1, -1, sFileStreamFlags);
 }
 
-void
-BlobImplFile::SetPath(const nsAString& aPath)
-{
-  MOZ_ASSERT(aPath.IsEmpty() ||
-             aPath[aPath.Length() - 1] == char16_t('/'),
-             "Path must end with a path separator");
-  mPath = aPath;
-}
-
 ////////////////////////////////////////////////////////////////////////////
 // EmptyBlobImpl implementation
 
 NS_IMPL_ISUPPORTS_INHERITED0(EmptyBlobImpl, BlobImpl)
 
 already_AddRefed<BlobImpl>
 EmptyBlobImpl::CreateSlice(uint64_t aStart, uint64_t aLength,
                            const nsAString& aContentType,
--- a/dom/base/File.h
+++ b/dom/base/File.h
@@ -231,17 +231,23 @@ public:
               ErrorResult& aRv);
 
   void GetName(nsAString& aName) const;
 
   int64_t GetLastModified(ErrorResult& aRv);
 
   Date GetLastModifiedDate(ErrorResult& aRv);
 
-  void GetPath(nsAString& aName, ErrorResult& aRv);
+  // GetPath and SetPath are currently used only for the webkitRelativePath
+  // attribute and they are only used when this File object is created from a
+  // Directory, generated by a Directory Picker.
+
+  void GetPath(nsAString& aName) const;
+
+  void SetPath(const nsAString& aName);
 
   void GetMozFullPath(nsAString& aFilename, ErrorResult& aRv) const;
 
   void GetMozFullPathInternal(nsAString& aName, ErrorResult& aRv) const;
 
 protected:
   virtual bool HasFileInterface() const override { return true; }
 
@@ -259,17 +265,19 @@ class BlobImpl : public nsISupports
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(BLOBIMPL_IID)
   NS_DECL_THREADSAFE_ISUPPORTS
 
   BlobImpl() {}
 
   virtual void GetName(nsAString& aName) const = 0;
 
-  virtual void GetPath(nsAString& aName, ErrorResult& aRv) = 0;
+  virtual void GetPath(nsAString& aName) const = 0;
+
+  virtual void SetPath(const nsAString& aName) = 0;
 
   virtual int64_t GetLastModified(ErrorResult& aRv) = 0;
 
   virtual void SetLastModified(int64_t aLastModified) = 0;
 
   virtual void GetMozFullPath(nsAString& aName, ErrorResult& aRv) const = 0;
 
   virtual void GetMozFullPathInternal(nsAString& aFileName, ErrorResult& aRv) const = 0;
@@ -395,17 +403,19 @@ public:
     NS_ASSERTION(aLength != UINT64_MAX,
                  "Must know length when creating slice");
     // Ensure non-null mContentType by default
     mContentType.SetIsVoid(false);
   }
 
   virtual void GetName(nsAString& aName) const override;
 
-  virtual void GetPath(nsAString& aName, ErrorResult& aRv) override;
+  virtual void GetPath(nsAString& aName) const override;
+
+  virtual void SetPath(const nsAString& aName) override;
 
   virtual int64_t GetLastModified(ErrorResult& aRv) override;
 
   virtual void SetLastModified(int64_t aLastModified) override;
 
   virtual void GetMozFullPath(nsAString& aName, ErrorResult& aRv) const override;
 
   virtual void GetMozFullPathInternal(nsAString& aFileName,
@@ -700,18 +710,16 @@ public:
   virtual void GetType(nsAString& aType) override;
   virtual int64_t GetLastModified(ErrorResult& aRv) override;
   virtual void SetLastModified(int64_t aLastModified) override;
   virtual void GetMozFullPathInternal(nsAString& aFullPath,
                                       ErrorResult& aRv) const override;
   virtual void GetInternalStream(nsIInputStream** aInputStream,
                                  ErrorResult& aRv) override;
 
-  void SetPath(const nsAString& aFullPath);
-
   // We always have size and date for this kind of blob.
   virtual bool IsSizeUnknown() const override { return false; }
   virtual bool IsDateUnknown() const override { return false; }
 
 protected:
   virtual ~BlobImplFile() {
     if (mFile && mIsTemporary) {
       NS_WARNING("In temporary ~BlobImplFile");
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -5795,16 +5795,36 @@ nsContentUtils::GetUTFOrigin(nsIURI* aUR
     if (principal) {
       nsCOMPtr<nsIURI> uri;
       nsresult rv = principal->GetURI(getter_AddRefs(uri));
       NS_ENSURE_SUCCESS(rv, rv);
 
       if (uri && uri != aURI) {
         return GetUTFOrigin(uri, aOrigin);
       }
+    } else {
+      // We are probably dealing with an unknown blob URL.
+      bool isBlobURL = false;
+      nsresult rv = aURI->SchemeIs(BLOBURI_SCHEME, &isBlobURL);
+      NS_ENSURE_SUCCESS(rv, rv);
+
+      if (isBlobURL) {
+        nsAutoCString path;
+        rv = aURI->GetPath(path);
+        NS_ENSURE_SUCCESS(rv, rv);
+
+        nsCOMPtr<nsIURI> uri;
+        nsresult rv = NS_NewURI(getter_AddRefs(uri), path);
+        if (NS_FAILED(rv)) {
+          aOrigin.AssignLiteral("null");
+          return NS_OK;
+        }
+
+        return GetUTFOrigin(uri, aOrigin);
+      }
     }
   }
 
   aOrigin.Truncate();
 
   nsCOMPtr<nsIURI> uri = NS_GetInnermostURI(aURI);
   NS_ENSURE_TRUE(uri, NS_ERROR_UNEXPECTED);
 
--- a/dom/base/test/mochitest.ini
+++ b/dom/base/test/mochitest.ini
@@ -900,8 +900,9 @@ skip-if = toolkit == 'android'
 skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) # b2g-debug(12 total, 2 failing - .mozSystem == true - got false, expected true + ) b2g-desktop(12 total, 2 failing - .mozSystem == true - got false, expected true + )
 [test_XHR_timeout.html]
 skip-if = buildapp == 'b2g' || (android_version == '18' && debug) # b2g(flaky on B2G, bug 960743) b2g-debug(flaky on B2G, bug 960743) b2g-desktop(flaky on B2G, bug 960743)
 support-files = test_XHR_timeout.js
 [test_xhr_withCredentials.html]
 [test_XHRDocURI.html]
 [test_XHRResponseURL.html]
 [test_XHRSendData.html]
+[test_unknown_url_origin.html]
new file mode 100644
--- /dev/null
+++ b/dom/base/test/test_unknown_url_origin.html
@@ -0,0 +1,17 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Test for unknwon URL.origin</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+  <script type="application/javascript">
+
+  is ((new URL("blob:http://foo.com/bar")).origin, "http://foo.com");
+  is ((new URL("blob:blob:http://foo.com/bar")).origin, "http://foo.com");
+
+  </script>
+</body>
+</html>
--- a/dom/filesystem/CreateFileTask.cpp
+++ b/dom/filesystem/CreateFileTask.cpp
@@ -235,17 +235,17 @@ CreateFileTaskParent::GetSuccessRequestR
   AssertIsOnBackgroundThread();
 
   nsAutoString path;
   aRv = mTargetPath->GetPath(path);
   if (NS_WARN_IF(aRv.Failed())) {
     return FileSystemDirectoryResponse();
   }
 
-  return FileSystemFileResponse(path);
+  return FileSystemFileResponse(path, EmptyString());
 }
 
 nsresult
 CreateFileTaskParent::IOWork()
 {
   class MOZ_RAII AutoClose final
   {
   public:
--- a/dom/filesystem/Directory.cpp
+++ b/dom/filesystem/Directory.cpp
@@ -8,16 +8,17 @@
 
 #include "CreateDirectoryTask.h"
 #include "CreateFileTask.h"
 #include "FileSystemPermissionRequest.h"
 #include "GetDirectoryListingTask.h"
 #include "GetFileOrDirectoryTask.h"
 #include "GetFilesTask.h"
 #include "RemoveTask.h"
+#include "WorkerPrivate.h"
 
 #include "nsCharSeparatedTokenizer.h"
 #include "nsString.h"
 #include "mozilla/dom/DirectoryBinding.h"
 #include "mozilla/dom/FileSystemBase.h"
 #include "mozilla/dom/FileSystemUtils.h"
 #include "mozilla/dom/OSFileSystem.h"
 
@@ -117,16 +118,34 @@ Directory::DeviceStorageEnabled(JSContex
 {
   if (!NS_IsMainThread()) {
     return false;
   }
 
   return Preferences::GetBool("device.storage.enabled", false);
 }
 
+/* static */ bool
+Directory::WebkitBlinkDirectoryPickerEnabled(JSContext* aCx, JSObject* aObj)
+{
+  if (NS_IsMainThread()) {
+    return Preferences::GetBool("dom.webkitBlink.dirPicker.enabled", false);
+  }
+
+  // aCx can be null when this function is called by something else than WebIDL
+  // binding code.
+  workers::WorkerPrivate* workerPrivate =
+    workers::GetCurrentThreadWorkerPrivate();
+  if (!workerPrivate) {
+    return false;
+  }
+
+  return workerPrivate->WebkitBlinkDirectoryPickerEnabled();
+}
+
 /* static */ already_AddRefed<Promise>
 Directory::GetRoot(FileSystemBase* aFileSystem, ErrorResult& aRv)
 {
   // Only exposed for DeviceStorage.
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aFileSystem);
 
   nsCOMPtr<nsIFile> path;
@@ -415,17 +434,17 @@ already_AddRefed<Promise>
 Directory::GetFilesAndDirectories(ErrorResult& aRv)
 {
   RefPtr<FileSystemBase> fs = GetFileSystem(aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
   RefPtr<GetDirectoryListingTaskChild> task =
-    GetDirectoryListingTaskChild::Create(fs, mFile, mFilters, aRv);
+    GetDirectoryListingTaskChild::Create(fs, this, mFile, mFilters, aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
   FileSystemPermissionRequest::RequestForTask(task);
   return task->GetPromise();
 }
 
@@ -435,17 +454,17 @@ Directory::GetFiles(bool aRecursiveFlag,
   ErrorResult rv;
   RefPtr<FileSystemBase> fs = GetFileSystem(rv);
   if (NS_WARN_IF(rv.Failed())) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return nullptr;
   }
 
   RefPtr<GetFilesTaskChild> task =
-    GetFilesTaskChild::Create(fs, mFile, aRecursiveFlag, rv);
+    GetFilesTaskChild::Create(fs, this, mFile, aRecursiveFlag, rv);
   if (NS_WARN_IF(rv.Failed())) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return nullptr;
   }
 
   FileSystemPermissionRequest::RequestForTask(task);
   return task->GetPromise();
 }
--- a/dom/filesystem/Directory.h
+++ b/dom/filesystem/Directory.h
@@ -51,16 +51,19 @@ public:
   };
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Directory)
 
   static bool
   DeviceStorageEnabled(JSContext* aCx, JSObject* aObj);
 
+  static bool
+  WebkitBlinkDirectoryPickerEnabled(JSContext* aCx, JSObject* aObj);
+
   static already_AddRefed<Promise>
   GetRoot(FileSystemBase* aFileSystem, ErrorResult& aRv);
 
   static already_AddRefed<Directory>
   Create(nsISupports* aParent, nsIFile* aDirectory,
          FileSystemBase* aFileSystem = 0);
 
   // ========= Begin WebIDL bindings. ===========
--- a/dom/filesystem/FileSystemBase.cpp
+++ b/dom/filesystem/FileSystemBase.cpp
@@ -148,17 +148,19 @@ FileSystemBase::GetDOMPath(nsIFile* aFil
 
   while (true) {
     nsAutoString leafName;
     aRv = path->GetLeafName(leafName);
     if (NS_WARN_IF(aRv.Failed())) {
       return;
     }
 
-    parts.AppendElement(leafName);
+    if (!leafName.IsEmpty()) {
+      parts.AppendElement(leafName);
+    }
 
     bool equal = false;
     aRv = fileSystemPath->Equals(path, &equal);
     if (NS_WARN_IF(aRv.Failed())) {
       return;
     }
 
     if (equal) {
@@ -174,17 +176,20 @@ FileSystemBase::GetDOMPath(nsIFile* aFil
     MOZ_ASSERT(parentPath);
 
     aRv = parentPath->Clone(getter_AddRefs(path));
     if (NS_WARN_IF(aRv.Failed())) {
       return;
     }
   }
 
-  MOZ_ASSERT(!parts.IsEmpty());
+  if (parts.IsEmpty()) {
+    aRetval.AppendLiteral(FILESYSTEM_DOM_PATH_SEPARATOR_LITERAL);
+    return;
+  }
 
   for (int32_t i = parts.Length() - 1; i >= 0; --i) {
     aRetval.AppendLiteral(FILESYSTEM_DOM_PATH_SEPARATOR_LITERAL);
     aRetval.Append(parts[i]);
   }
 }
 
 void
--- a/dom/filesystem/GetDirectoryListingTask.cpp
+++ b/dom/filesystem/GetDirectoryListingTask.cpp
@@ -22,25 +22,28 @@ namespace mozilla {
 namespace dom {
 
 /**
  * GetDirectoryListingTaskChild
  */
 
 /* static */ already_AddRefed<GetDirectoryListingTaskChild>
 GetDirectoryListingTaskChild::Create(FileSystemBase* aFileSystem,
+                                     Directory* aDirectory,
                                      nsIFile* aTargetPath,
                                      const nsAString& aFilters,
                                      ErrorResult& aRv)
 {
   MOZ_ASSERT(aFileSystem);
+  MOZ_ASSERT(aDirectory);
   aFileSystem->AssertIsOnOwningThread();
 
   RefPtr<GetDirectoryListingTaskChild> task =
-    new GetDirectoryListingTaskChild(aFileSystem, aTargetPath, aFilters);
+    new GetDirectoryListingTaskChild(aFileSystem, aDirectory, aTargetPath,
+                                     aFilters);
 
   // aTargetPath can be null. In this case SetError will be called.
 
   nsCOMPtr<nsIGlobalObject> globalObject =
     do_QueryInterface(aFileSystem->GetParentObject());
   if (NS_WARN_IF(!globalObject)) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
@@ -50,19 +53,21 @@ GetDirectoryListingTaskChild::Create(Fil
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
   return task.forget();
 }
 
 GetDirectoryListingTaskChild::GetDirectoryListingTaskChild(FileSystemBase* aFileSystem,
+                                                           Directory* aDirectory,
                                                            nsIFile* aTargetPath,
                                                            const nsAString& aFilters)
   : FileSystemTaskChildBase(aFileSystem)
+  , mDirectory(aDirectory)
   , mTargetPath(aTargetPath)
   , mFilters(aFilters)
 {
   MOZ_ASSERT(aFileSystem);
   aFileSystem->AssertIsOnOwningThread();
 }
 
 GetDirectoryListingTaskChild::~GetDirectoryListingTaskChild()
@@ -137,16 +142,25 @@ GetDirectoryListingTaskChild::HandlerCal
   if (HasError()) {
     mPromise->MaybeReject(mErrorValue);
     mPromise = nullptr;
     return;
   }
 
   size_t count = mTargetData.Length();
 
+  nsAutoString directoryPath;
+  ErrorResult error;
+  mDirectory->GetPath(directoryPath, error);
+  if (NS_WARN_IF(error.Failed())) {
+    mPromise->MaybeReject(error.StealNSResult());
+    mPromise = nullptr;
+    return;
+  }
+
   Sequence<OwningFileOrDirectory> listing;
 
   if (!listing.SetLength(count, mozilla::fallible_t())) {
     mPromise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
     mPromise = nullptr;
     return;
   }
 
@@ -183,16 +197,29 @@ GetDirectoryListingTaskChild::HandlerCal
       listing[i].SetAsDirectory() = directory;
     } else {
       MOZ_ASSERT(mTargetData[i].mType == Directory::FileOrDirectoryPath::eFilePath);
 
       RefPtr<File> file =
         File::CreateFromFile(mFileSystem->GetParentObject(), path);
       MOZ_ASSERT(file);
 
+      nsAutoString filePath;
+      filePath.Assign(directoryPath);
+
+      // This is specific for unix root filesystem.
+      if (!directoryPath.EqualsLiteral(FILESYSTEM_DOM_PATH_SEPARATOR_LITERAL)) {
+        filePath.AppendLiteral(FILESYSTEM_DOM_PATH_SEPARATOR_LITERAL);
+      }
+
+      nsAutoString name;
+      file->GetName(name);
+      filePath.Append(name);
+      file->SetPath(filePath);
+
       listing[i].SetAsFile() = file;
     }
   }
 
   mPromise->MaybeResolve(listing);
   mPromise = nullptr;
 }
 
--- a/dom/filesystem/GetDirectoryListingTask.h
+++ b/dom/filesystem/GetDirectoryListingTask.h
@@ -17,47 +17,50 @@ namespace dom {
 
 class BlobImpl;
 
 class GetDirectoryListingTaskChild final : public FileSystemTaskChildBase
 {
 public:
   static already_AddRefed<GetDirectoryListingTaskChild>
   Create(FileSystemBase* aFileSystem,
+         Directory* aDirectory,
          nsIFile* aTargetPath,
          const nsAString& aFilters,
          ErrorResult& aRv);
 
   virtual
   ~GetDirectoryListingTaskChild();
 
   already_AddRefed<Promise>
   GetPromise();
 
   virtual void
   GetPermissionAccessType(nsCString& aAccess) const override;
 
 private:
   // If aDirectoryOnly is set, we should ensure that the target is a directory.
   GetDirectoryListingTaskChild(FileSystemBase* aFileSystem,
+                               Directory* aDirectory,
                                nsIFile* aTargetPath,
                                const nsAString& aFilters);
 
   virtual FileSystemParams
   GetRequestParams(const nsString& aSerializedDOMPath,
                    ErrorResult& aRv) const override;
 
   virtual void
   SetSuccessRequestResult(const FileSystemResponseValue& aValue,
                           ErrorResult& aRv) override;
 
   virtual void
   HandlerCallback() override;
 
   RefPtr<Promise> mPromise;
+  RefPtr<Directory> mDirectory;
   nsCOMPtr<nsIFile> mTargetPath;
   nsString mFilters;
 
   // We cannot store File or Directory objects bacause this object is created
   // on a different thread and File and Directory are not thread-safe.
   FallibleTArray<Directory::FileOrDirectoryPath> mTargetData;
 };
 
--- a/dom/filesystem/GetFileOrDirectoryTask.cpp
+++ b/dom/filesystem/GetFileOrDirectoryTask.cpp
@@ -213,17 +213,17 @@ GetFileOrDirectoryTaskParent::GetSuccess
   if (NS_WARN_IF(aRv.Failed())) {
     return FileSystemDirectoryResponse();
   }
 
   if (mIsDirectory) {
     return FileSystemDirectoryResponse(path);
   }
 
-  return FileSystemFileResponse(path);
+  return FileSystemFileResponse(path, EmptyString());
 }
 
 nsresult
 GetFileOrDirectoryTaskParent::IOWork()
 {
   MOZ_ASSERT(XRE_IsParentProcess(),
              "Only call from parent process!");
   MOZ_ASSERT(!NS_IsMainThread(), "Only call on worker thread!");
--- a/dom/filesystem/GetFilesTask.cpp
+++ b/dom/filesystem/GetFilesTask.cpp
@@ -22,51 +22,57 @@ namespace mozilla {
 namespace dom {
 
 /**
  * GetFilesTaskChild
  */
 
 /* static */ already_AddRefed<GetFilesTaskChild>
 GetFilesTaskChild::Create(FileSystemBase* aFileSystem,
+                          Directory* aDirectory,
                           nsIFile* aTargetPath,
                           bool aRecursiveFlag,
                           ErrorResult& aRv)
 {
   MOZ_ASSERT(aFileSystem);
+  MOZ_ASSERT(aDirectory);
   aFileSystem->AssertIsOnOwningThread();
 
   nsCOMPtr<nsIGlobalObject> globalObject =
     do_QueryInterface(aFileSystem->GetParentObject());
   if (NS_WARN_IF(!globalObject)) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   RefPtr<GetFilesTaskChild> task =
-    new GetFilesTaskChild(aFileSystem, aTargetPath, aRecursiveFlag);
+    new GetFilesTaskChild(aFileSystem, aDirectory, aTargetPath,
+                          aRecursiveFlag);
 
   // aTargetPath can be null. In this case SetError will be called.
 
   task->mPromise = Promise::Create(globalObject, aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
   return task.forget();
 }
 
 GetFilesTaskChild::GetFilesTaskChild(FileSystemBase* aFileSystem,
+                                     Directory* aDirectory,
                                      nsIFile* aTargetPath,
                                      bool aRecursiveFlag)
   : FileSystemTaskChildBase(aFileSystem)
+  , mDirectory(aDirectory)
   , mTargetPath(aTargetPath)
   , mRecursiveFlag(aRecursiveFlag)
 {
   MOZ_ASSERT(aFileSystem);
+  MOZ_ASSERT(aDirectory);
   aFileSystem->AssertIsOnOwningThread();
 }
 
 GetFilesTaskChild::~GetFilesTaskChild()
 {
   mFileSystem->AssertIsOnOwningThread();
 }
 
@@ -84,17 +90,24 @@ GetFilesTaskChild::GetRequestParams(cons
   mFileSystem->AssertIsOnOwningThread();
 
   nsAutoString path;
   aRv = mTargetPath->GetPath(path);
   if (NS_WARN_IF(aRv.Failed())) {
     return FileSystemGetFilesParams();
   }
 
-  return FileSystemGetFilesParams(aSerializedDOMPath, path, mRecursiveFlag);
+  nsAutoString domPath;
+  mDirectory->GetPath(domPath, aRv);
+  if (NS_WARN_IF(aRv.Failed())) {
+    return FileSystemGetFilesParams();
+  }
+
+  return FileSystemGetFilesParams(aSerializedDOMPath, path, domPath,
+                                  mRecursiveFlag);
 }
 
 void
 GetFilesTaskChild::SetSuccessRequestResult(const FileSystemResponseValue& aValue,
                                            ErrorResult& aRv)
 {
   mFileSystem->AssertIsOnOwningThread();
   MOZ_ASSERT(aValue.type() ==
@@ -104,17 +117,18 @@ GetFilesTaskChild::SetSuccessRequestResu
 
   if (!mTargetData.SetLength(r.data().Length(), mozilla::fallible_t())) {
     aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
     return;
   }
 
   for (uint32_t i = 0; i < r.data().Length(); ++i) {
     const FileSystemFileResponse& data = r.data()[i];
-    mTargetData[i] = data.realPath();
+    mTargetData[i].mRealPath = data.realPath();
+    mTargetData[i].mDOMPath = data.domPath();
   }
 }
 
 void
 GetFilesTaskChild::HandlerCallback()
 {
   mFileSystem->AssertIsOnOwningThread();
   if (mFileSystem->IsShutdown()) {
@@ -135,17 +149,17 @@ GetFilesTaskChild::HandlerCallback()
   if (!listing.SetLength(count, mozilla::fallible_t())) {
     mPromise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
     mPromise = nullptr;
     return;
   }
 
   for (unsigned i = 0; i < count; i++) {
     nsCOMPtr<nsIFile> path;
-    NS_ConvertUTF16toUTF8 fullPath(mTargetData[i]);
+    NS_ConvertUTF16toUTF8 fullPath(mTargetData[i].mRealPath);
     nsresult rv = NS_NewNativeLocalFile(fullPath, true, getter_AddRefs(path));
     if (NS_WARN_IF(NS_FAILED(rv))) {
       mPromise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
       mPromise = nullptr;
       return;
     }
 
 #ifdef DEBUG
@@ -159,16 +173,17 @@ GetFilesTaskChild::HandlerCallback()
     }
 
     MOZ_ASSERT(FileSystemUtils::IsDescendantPath(rootPath, path));
 #endif
 
     RefPtr<File> file =
       File::CreateFromFile(mFileSystem->GetParentObject(), path);
     MOZ_ASSERT(file);
+    file->SetPath(mTargetData[i].mDOMPath);
 
     listing[i] = file;
   }
 
   mPromise->MaybeResolve(listing);
   mPromise = nullptr;
 }
 
@@ -203,16 +218,17 @@ GetFilesTaskParent::Create(FileSystemBas
 
   return task.forget();
 }
 
 GetFilesTaskParent::GetFilesTaskParent(FileSystemBase* aFileSystem,
                                        const FileSystemGetFilesParams& aParam,
                                        FileSystemRequestParent* aParent)
   : FileSystemTaskParentBase(aFileSystem, aParam, aParent)
+  , mDirectoryDOMPath(aParam.domPath())
   , mRecursiveFlag(aParam.recursiveFlag())
 {
   MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(aFileSystem);
 }
 
 FileSystemResponseValue
@@ -226,17 +242,18 @@ GetFilesTaskParent::GetSuccessRequestRes
   if (!inputs.SetLength(mTargetData.Length(), mozilla::fallible_t())) {
     aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
     FileSystemFilesResponse response;
     return response;
   }
 
   for (unsigned i = 0; i < mTargetData.Length(); i++) {
     FileSystemFileResponse fileData;
-    fileData.realPath() = mTargetData[i];
+    fileData.realPath() = mTargetData[i].mRealPath;
+    fileData.domPath() = mTargetData[i].mDOMPath;
     inputs[i] = fileData;
   }
 
   FileSystemFilesResponse response;
   response.data().SwapElements(inputs);
   return response;
 }
 
@@ -257,26 +274,26 @@ GetFilesTaskParent::IOWork()
     return rv;
   }
 
   if (!exists) {
     return NS_OK;
   }
 
   // Get isDirectory.
-  rv = ExploreDirectory(mTargetPath);
+  rv = ExploreDirectory(mDirectoryDOMPath, mTargetPath);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   return NS_OK;
 }
 
 nsresult
-GetFilesTaskParent::ExploreDirectory(nsIFile* aPath)
+GetFilesTaskParent::ExploreDirectory(const nsAString& aDOMPath, nsIFile* aPath)
 {
   MOZ_ASSERT(XRE_IsParentProcess(),
              "Only call from parent process!");
   MOZ_ASSERT(!NS_IsMainThread(), "Only call on worker thread!");
   MOZ_ASSERT(aPath);
 
   bool isDir;
   nsresult rv = aPath->IsDirectory(&isDir);
@@ -315,37 +332,53 @@ GetFilesTaskParent::ExploreDirectory(nsI
     }
 
     if (NS_WARN_IF(NS_FAILED(currFile->IsFile(&isFile)) ||
                    NS_FAILED(currFile->IsDirectory(&isDir))) ||
         !(isFile || isDir)) {
       continue;
     }
 
+    nsAutoString domPath;
+    domPath.Assign(aDOMPath);
+
+    // This is specific for unix root filesystem.
+    if (!aDOMPath.EqualsLiteral(FILESYSTEM_DOM_PATH_SEPARATOR_LITERAL)) {
+      domPath.AppendLiteral(FILESYSTEM_DOM_PATH_SEPARATOR_LITERAL);
+    }
+
+    nsAutoString leafName;
+    if (NS_WARN_IF(NS_FAILED(currFile->GetLeafName(leafName)))) {
+      continue;
+    }
+    domPath.Append(leafName);
+
     if (isFile) {
-      nsAutoString path;
-      if (NS_WARN_IF(NS_FAILED(currFile->GetPath(path)))) {
+      FileData data;
+      data.mDOMPath.Append(domPath);
+
+      if (NS_WARN_IF(NS_FAILED(currFile->GetPath(data.mRealPath)))) {
         continue;
       }
 
-      if (!mTargetData.AppendElement(path, fallible)) {
+      if (!mTargetData.AppendElement(data, fallible)) {
         return NS_ERROR_OUT_OF_MEMORY;
       }
 
       continue;
     }
 
     MOZ_ASSERT(isDir);
 
     if (!mRecursiveFlag) {
       continue;
     }
 
     // Recursive.
-    rv = ExploreDirectory(currFile);
+    rv = ExploreDirectory(domPath, currFile);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   }
 
   return NS_OK;
 }
 
--- a/dom/filesystem/GetFilesTask.h
+++ b/dom/filesystem/GetFilesTask.h
@@ -17,52 +17,60 @@ namespace dom {
 
 class BlobImpl;
 
 class GetFilesTaskChild final : public FileSystemTaskChildBase
 {
 public:
   static already_AddRefed<GetFilesTaskChild>
   Create(FileSystemBase* aFileSystem,
+         Directory* aDirectory,
          nsIFile* aTargetPath,
          bool aRecursiveFlag,
          ErrorResult& aRv);
 
   virtual
   ~GetFilesTaskChild();
 
   already_AddRefed<Promise>
   GetPromise();
 
   virtual void
   GetPermissionAccessType(nsCString& aAccess) const override;
 
 private:
   // If aDirectoryOnly is set, we should ensure that the target is a directory.
   GetFilesTaskChild(FileSystemBase* aFileSystem,
+                    Directory* aDirectory,
                     nsIFile* aTargetPath,
                     bool aRecursiveFlag);
 
   virtual FileSystemParams
   GetRequestParams(const nsString& aSerializedDOMPath,
                    ErrorResult& aRv) const override;
 
   virtual void
   SetSuccessRequestResult(const FileSystemResponseValue& aValue,
                           ErrorResult& aRv) override;
 
   virtual void
   HandlerCallback() override;
 
   RefPtr<Promise> mPromise;
+  RefPtr<Directory> mDirectory;
   nsCOMPtr<nsIFile> mTargetPath;
   bool mRecursiveFlag;
 
-  // We store the fullpath of Files.
-  FallibleTArray<nsString> mTargetData;
+  // We store the fullpath and the dom path of Files.
+  struct FileData {
+    nsString mRealPath;
+    nsString mDOMPath;
+  };
+
+  FallibleTArray<FileData> mTargetData;
 };
 
 class GetFilesTaskParent final : public FileSystemTaskParentBase
 {
 public:
   static already_AddRefed<GetFilesTaskParent>
   Create(FileSystemBase* aFileSystem,
          const FileSystemGetFilesParams& aParam,
@@ -79,21 +87,27 @@ private:
 
   virtual FileSystemResponseValue
   GetSuccessRequestResult(ErrorResult& aRv) const override;
 
   virtual nsresult
   IOWork() override;
 
   nsresult
-  ExploreDirectory(nsIFile* aPath);
+  ExploreDirectory(const nsAString& aDOMPath, nsIFile* aPath);
 
+  nsString mDirectoryDOMPath;
   nsCOMPtr<nsIFile> mTargetPath;
   bool mRecursiveFlag;
 
-  // We store the fullpath of Files.
-  FallibleTArray<nsString> mTargetData;
+  // We store the fullpath and the dom path of Files.
+  struct FileData {
+    nsString mRealPath;
+    nsString mDOMPath;
+  };
+
+  FallibleTArray<FileData> mTargetData;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_GetFilesTask_h
--- a/dom/filesystem/PFileSystemParams.ipdlh
+++ b/dom/filesystem/PFileSystemParams.ipdlh
@@ -43,16 +43,17 @@ struct FileSystemGetDirectoryListingPara
   // each nsString that it contains.
   nsString filters;
 };
 
 struct FileSystemGetFilesParams
 {
   nsString filesystem;
   nsString realPath;
+  nsString domPath;
   bool recursiveFlag;
 };
 
 struct FileSystemGetFileOrDirectoryParams
 {
   nsString filesystem;
   nsString realPath;
 };
--- a/dom/filesystem/PFileSystemRequest.ipdl
+++ b/dom/filesystem/PFileSystemRequest.ipdl
@@ -8,16 +8,17 @@ include protocol PBackground;
 include protocol PBlob;
 
 namespace mozilla {
 namespace dom {
 
 struct FileSystemFileResponse
 {
   nsString realPath;
+  nsString domPath;
 };
 
 struct FileSystemDirectoryResponse
 {
   nsString realPath;
 };
 
 struct FileSystemDirectoryListingResponseFile
--- a/dom/filesystem/moz.build
+++ b/dom/filesystem/moz.build
@@ -39,12 +39,13 @@ IPDL_SOURCES += [
     'PFileSystemParams.ipdlh',
     'PFileSystemRequest.ipdl',
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 LOCAL_INCLUDES += [
     '/dom/base',
+    '/dom/workers',
 ]
 
 if CONFIG['GNU_CXX']:
     CXXFLAGS += ['-Wshadow']
--- a/dom/filesystem/tests/filesystem_commons.js
+++ b/dom/filesystem/tests/filesystem_commons.js
@@ -1,10 +1,15 @@
+function createPath(parentDir, dirOrFile) {
+  return parentDir.path + (parentDir.path == '/' ? '' : '/') + dirOrFile.name;
+}
+
 function setup_tests(aNext) {
-  SpecialPowers.pushPrefEnv({"set": [["dom.input.dirpicker", true]]}, aNext);
+  SpecialPowers.pushPrefEnv({"set": [["dom.input.dirpicker", true],
+                                     ["dom.webkitBlink.dirPicker.enabled", true]]}, aNext);
 }
 
 function test_basic(aDirectory, aNext) {
   ok(aDirectory, "Directory exists.");
   ok(aDirectory instanceof Directory, "We have a directory.");
   is(aDirectory.path, '/' + aDirectory.name, "directory.path must be '/'+name");
   aNext();
 }
@@ -14,51 +19,62 @@ function test_getFilesAndDirectories(aDi
     return dir.getFilesAndDirectories().then(
       function(data) {
         for (var i = 0; i < data.length; ++i) {
           ok (data[i] instanceof File || data[i] instanceof Directory, "Just Files or Directories");
           if (data[i] instanceof Directory) {
             isnot(data[i].name, '/', "Subdirectory should be called with the leafname");
             isnot(data[i].path, '/', "Subdirectory path should be called with the leafname");
             isnot(data[i].path, dir.path, "Subdirectory path should contain the parent path.");
-            is(data[i].path, dir.path + '/' + data[i].name, "Subdirectory path should be called parentdir.path + '/' + leafname");
+            is(data[i].path, createPath(dir, data[i]), "Subdirectory path should be called parentdir.path + '/' + leafname: " + data[i].path);
+          }
+
+          if (data[i] instanceof File) {
+            is(data[i].webkitRelativePath, createPath(dir, data[i]), "File.webkitRelativePath should be called: parentdir.path + '/' + file.name: " + data[i].webkitRelativePath);
           }
         }
       }
     );
   }
 
   aDirectory.getFilesAndDirectories().then(
     function(data) {
       ok(data.length, "We should have some data.");
       var promises = [];
       for (var i = 0; i < data.length; ++i) {
         ok (data[i] instanceof File || data[i] instanceof Directory, "Just Files or Directories: " + data[i].name);
         if (data[i] instanceof Directory) {
           isnot(data[i].name, '/', "Subdirectory should be called with the leafname");
-          is(data[i].path, aDirectory.path + '/' + data[i].name, "Subdirectory path should be called parentdir.path + '/' + leafname");
+          is(data[i].path, createPath(aDirectory, data[i]), "Subdirectory path should be called parentdir.path + '/' + leafname: " + data[i].path);
           if (aRecursive) {
             promises.push(checkSubDir(data[i]));
           }
         }
+
+        if (data[i] instanceof File) {
+          is(data[i].webkitRelativePath, createPath(aDirectory, data[i]), "File.webkitRelativePath should be called '/' + file.name: " + data[i].webkitRelativePath);
+        }
       }
 
       return Promise.all(promises);
     },
     function() {
       ok(false, "Something when wrong");
     }
   ).then(aNext);
 }
 
 function test_getFiles(aDirectory, aRecursive, aNext) {
   aDirectory.getFiles(aRecursive).then(
     function(data) {
       for (var i = 0; i < data.length; ++i) {
-        ok (data[i] instanceof File, "File: " + data[i].name);
+        ok(data[i] instanceof File, "File: " + data[i].name);
+        ok(data[i].webkitRelativePath.indexOf(aDirectory.path) == 0 &&
+           data[i].webkitRelativePath.indexOf('/' + data[i].name) + ('/' + data[i].name).length == data[i].webkitRelativePath.length,
+           "File.webkitRelativePath should be called dir.path + '/' + file.name: " + data[i].webkitRelativePath);
       }
     },
     function() {
       ok(false, "Something when wrong");
     }
   ).then(aNext);
 }
 
--- a/dom/filesystem/tests/script_fileList.js
+++ b/dom/filesystem/tests/script_fileList.js
@@ -63,8 +63,20 @@ addMessageListener("dir.open", function 
       testFile = createTestFile();
       break;
   }
 
   sendAsyncMessage("dir.opened", {
     dir: testFile.path
   });
 });
+
+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)
+  });
+});
--- a/dom/filesystem/tests/test_basic.html
+++ b/dom/filesystem/tests/test_basic.html
@@ -30,32 +30,77 @@ function create_fileList(aPath) {
       next();
     });
   }
 
   script.addMessageListener("dir.opened", onOpened);
   script.sendAsyncMessage("dir.open", { path: aPath });
 }
 
+function test_simpleFilePicker(aPath) {
+  var url = SimpleTest.getTestFileURL("script_fileList.js");
+  var script = SpecialPowers.loadChromeScript(url);
+
+  function onOpened(message) {
+    var fileList = document.getElementById('fileList');
+    SpecialPowers.wrap(fileList).mozSetFileArray([message.file]);
+
+    is(fileList.files.length, 1, "we want 1 element");
+    ok(fileList.files[0] instanceof File, "we want 1 file");
+    ok("webkitRelativePath" in fileList.files[0], "we have webkitRelativePath attribute");
+    is(fileList.files[0].webkitRelativePath, "", "No webkit relative path for normal filePicker");
+
+    script.destroy();
+    next();
+  }
+
+  script.addMessageListener("file.opened", onOpened);
+  script.sendAsyncMessage("file.open");
+}
+
+function test_duplicateGetFilesAndDirectories() {
+  var url = SimpleTest.getTestFileURL("script_fileList.js");
+  var script = SpecialPowers.loadChromeScript(url);
+
+  function onOpened(message) {
+    var fileList = document.getElementById('fileList');
+    SpecialPowers.wrap(fileList).mozSetDirectory(message.dir);
+
+    var p1 = fileList.getFilesAndDirectories();
+    var p2 = fileList.getFilesAndDirectories();
+
+    isnot(p1, p2, "We create 2 different promises");
+
+    script.destroy();
+    next();
+  }
+
+  script.addMessageListener("dir.opened", onOpened);
+  script.sendAsyncMessage("dir.open", { path: 'test' });
+}
+
 var tests = [
   function() { setup_tests(next); },
 
   function() { create_fileList('ProfD') },
   function() { test_basic(directory, next); },
   function() { test_getFilesAndDirectories(directory, true, next); },
   function() { test_getFiles(directory, false, next); },
   function() { test_getFiles(directory, true, next); },
 
   function() { create_fileList('test') },
   function() { test_getFiles_recursiveComparison(directory, next); },
 
   function() { create_fileList('root'); },
   function() { test_basic(directory, next); },
   function() { test_getFilesAndDirectories(directory, false, next); },
   function() { test_getFiles(directory, false, next); },
+
+  test_duplicateGetFilesAndDirectories,
+  test_simpleFilePicker
 ];
 
 function next() {
   if (!tests.length) {
     SimpleTest.finish();
     return;
   }
 
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -6,16 +6,17 @@
 
 #include "mozilla/dom/HTMLInputElement.h"
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/AsyncEventDispatcher.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/dom/Date.h"
 #include "mozilla/dom/Directory.h"
+#include "mozilla/dom/FileSystemUtils.h"
 #include "nsAttrValueInlines.h"
 #include "nsCRTGlue.h"
 
 #include "nsIDOMHTMLInputElement.h"
 #include "nsITextControlElement.h"
 #include "nsIDOMNSEditableElement.h"
 #include "nsIRadioVisitor.h"
 #include "nsIPhonetic.h"
@@ -283,17 +284,28 @@ class HTMLInputElementState final : publ
 
     void SetFilesOrDirectories(const nsTArray<OwningFileOrDirectory>& aArray)
     {
       mBlobImplsOrDirectoryPaths.Clear();
       for (uint32_t i = 0; i < aArray.Length(); ++i) {
         if (aArray[i].IsFile()) {
           BlobImplOrDirectoryPath* data = mBlobImplsOrDirectoryPaths.AppendElement();
 
-          data->mBlobImpl = aArray[i].GetAsFile()->Impl();
+          RefPtr<File> file = aArray[i].GetAsFile();
+
+          nsAutoString name;
+          file->GetName(name);
+
+          nsAutoString path;
+          path.AssignLiteral(FILESYSTEM_DOM_PATH_SEPARATOR_LITERAL);
+          path.Append(name);
+
+          file->SetPath(path);
+
+          data->mBlobImpl = file->Impl();
           data->mType = BlobImplOrDirectoryPath::eBlobImpl;
         } else {
           MOZ_ASSERT(aArray[i].IsDirectory());
           nsAutoString fullPath;
           nsresult rv = aArray[i].GetAsDirectory()->GetFullRealPath(fullPath);
           if (NS_WARN_IF(NS_FAILED(rv))) {
             continue;
           }
@@ -1036,26 +1048,24 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
                                                   nsGenericHTMLFormElementWithState)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mValidity)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mControllers)
   if (tmp->IsSingleLineTextControl(false)) {
     tmp->mInputData.mState->Traverse(cb);
   }
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFilesOrDirectories)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFileList)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFilesAndDirectoriesPromise)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLInputElement,
                                                 nsGenericHTMLFormElementWithState)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mValidity)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mControllers)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mFilesOrDirectories)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mFileList)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mFilesAndDirectoriesPromise)
   if (tmp->IsSingleLineTextControl(false)) {
     tmp->mInputData.mState->Unlink();
   }
   //XXX should unlink more?
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_ADDREF_INHERITED(HTMLInputElement, Element)
 NS_IMPL_RELEASE_INHERITED(HTMLInputElement, Element)
@@ -2684,19 +2694,16 @@ HTMLInputElement::UpdateFileList()
       GetFilesOrDirectoriesInternal();
 
     for (uint32_t i = 0; i < array.Length(); ++i) {
       if (array[i].IsFile()) {
         mFileList->Append(array[i].GetAsFile());
       }
     }
   }
-
-  // Make sure we (lazily) create a new Promise for GetFilesAndDirectories:
-  mFilesAndDirectoriesPromise = nullptr;
 }
 
 nsresult
 HTMLInputElement::SetValueInternal(const nsAString& aValue, uint32_t aFlags)
 {
   NS_PRECONDITION(GetValueMode() != VALUE_MODE_FILENAME,
                   "Don't call SetValueInternal for file inputs");
 
@@ -5020,20 +5027,16 @@ HTMLInputElement::ChooseDirectory(ErrorR
 already_AddRefed<Promise>
 HTMLInputElement::GetFilesAndDirectories(ErrorResult& aRv)
 {
   if (mType != NS_FORM_INPUT_FILE) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return nullptr;
   }
 
-  if (mFilesAndDirectoriesPromise) {
-    return RefPtr<Promise>(mFilesAndDirectoriesPromise).forget();
-  }
-
   nsCOMPtr<nsIGlobalObject> global = OwnerDoc()->GetScopeObject();
   MOZ_ASSERT(global);
   if (!global) {
     return nullptr;
   }
 
   RefPtr<Promise> p = Promise::Create(global, aRv);
   if (aRv.Failed()) {
@@ -5064,22 +5067,16 @@ HTMLInputElement::GetFilesAndDirectories
       MOZ_ASSERT(filesAndDirs[i].IsFile());
 
       // This file was directly selected by the user, so don't filter it.
       filesAndDirsSeq[i].SetAsFile() = filesAndDirs[i].GetAsFile();
     }
   }
 
   p->MaybeResolve(filesAndDirsSeq);
-
-  // Cache the Promise so that repeat getFilesAndDirectories() calls return
-  // the same Promise and array of File and Directory objects until the user
-  // picks different files/directories:
-  mFilesAndDirectoriesPromise = p;
-
   return p.forget();
 }
 
 
 // Controllers Methods
 
 nsIControllers*
 HTMLInputElement::GetControllers(ErrorResult& aRv)
--- a/dom/html/HTMLInputElement.h
+++ b/dom/html/HTMLInputElement.h
@@ -1283,17 +1283,16 @@ protected:
 #ifndef MOZ_CHILD_PERMISSIONS
   /**
    * Hack for bug 1086684: Stash the .value when we're a file picker.
    */
   nsString mFirstFilePath;
 #endif
 
   RefPtr<FileList>  mFileList;
-  RefPtr<Promise> mFilesAndDirectoriesPromise;
 
   nsString mStaticDocFileList;
   
   /** 
    * The value of the input element when first initialized and it is updated
    * when the element is either changed through a script, focused or dispatches   
    * a change event. This is to ensure correct future change event firing.
    * NB: This is ONLY applicable where the element is a text control. ie,
--- a/dom/html/nsFormSubmission.cpp
+++ b/dom/html/nsFormSubmission.cpp
@@ -31,21 +31,23 @@
 #include "nsIMIMEService.h"
 #include "nsIConsoleService.h"
 #include "nsIScriptError.h"
 #include "nsIStringBundle.h"
 #include "nsCExternalHandlerService.h"
 #include "nsIFileStreams.h"
 #include "nsContentUtils.h"
 
+#include "mozilla/dom/Directory.h"
 #include "mozilla/dom/EncodingUtils.h"
 #include "mozilla/dom/File.h"
 
 using namespace mozilla;
 using mozilla::dom::Blob;
+using mozilla::dom::Directory;
 using mozilla::dom::EncodingUtils;
 using mozilla::dom::File;
 
 static void
 SendJSWarning(nsIDocument* aDocument,
               const char* aWarningName,
               const char16_t** aWarningArgs, uint32_t aWarningArgsLen)
 {
@@ -459,31 +461,29 @@ nsFSMultipartFormData::AddNameBlobOrNull
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsAutoCString filename;
   nsAutoCString contentType;
   nsCOMPtr<nsIInputStream> fileStream;
 
   if (aBlob) {
     nsAutoString filename16;
-    RetrieveFileName(aBlob, filename16);
 
-    ErrorResult error;
-    nsAutoString filepath16;
     RefPtr<File> file = aBlob->ToFile();
     if (file) {
-      file->GetPath(filepath16, error);
-      if (NS_WARN_IF(error.Failed())) {
-        return error.StealNSResult();
+      nsAutoString path;
+      file->GetPath(path);
+      if (Directory::WebkitBlinkDirectoryPickerEnabled(nullptr, nullptr) &&
+          !path.IsEmpty()) {
+        filename16 = path;
       }
-    }
 
-    if (!filepath16.IsEmpty()) {
-      // File.path includes trailing "/"
-      filename16 = filepath16 + filename16;
+      if (filename16.IsEmpty()) {
+        RetrieveFileName(aBlob, filename16);
+      }
     }
 
     rv = EncodeVal(filename16, filename, true);
     NS_ENSURE_SUCCESS(rv, rv);
 
     // Get content type
     nsAutoString contentType16;
     aBlob->GetType(contentType16);
@@ -492,16 +492,17 @@ nsFSMultipartFormData::AddNameBlobOrNull
     }
 
     contentType.Adopt(nsLinebreakConverter::
                       ConvertLineBreaks(NS_ConvertUTF16toUTF8(contentType16).get(),
                                         nsLinebreakConverter::eLinebreakAny,
                                         nsLinebreakConverter::eLinebreakSpace));
 
     // Get input stream
+    ErrorResult error;
     aBlob->GetInternalStream(getter_AddRefs(fileStream), error);
     if (NS_WARN_IF(error.Failed())) {
       return error.StealNSResult();
     }
 
     if (fileStream) {
       // Create buffered stream (for efficiency)
       nsCOMPtr<nsIInputStream> bufferedStream;
--- a/dom/indexedDB/FileSnapshot.h
+++ b/dom/indexedDB/FileSnapshot.h
@@ -56,19 +56,25 @@ private:
   // BlobImpl
   virtual void
   GetName(nsAString& aName) const override
   {
     mBlobImpl->GetName(aName);
   }
 
   virtual void
-  GetPath(nsAString& aPath, ErrorResult& aRv) override
+  GetPath(nsAString& aPath) const override
   {
-    mBlobImpl->GetPath(aPath, aRv);
+    mBlobImpl->GetPath(aPath);
+  }
+
+  virtual void
+  SetPath(const nsAString& aPath) override
+  {
+    mBlobImpl->SetPath(aPath);
   }
 
   virtual int64_t
   GetLastModified(ErrorResult& aRv) override
   {
     return mBlobImpl->GetLastModified(aRv);
   }
 
--- a/dom/ipc/Blob.cpp
+++ b/dom/ipc/Blob.cpp
@@ -1919,17 +1919,20 @@ public:
   NoteDyingActor();
 
   NS_DECL_ISUPPORTS_INHERITED
 
   virtual void
   GetName(nsAString& aName) const override;
 
   virtual void
-  GetPath(nsAString& aPath, ErrorResult& aRv) override;
+  GetPath(nsAString& aPath) const override;
+
+  virtual void
+  SetPath(const nsAString& aPath) override;
 
   virtual int64_t
   GetLastModified(ErrorResult& aRv) override;
 
   virtual void
   SetLastModified(int64_t aLastModified) override;
 
   virtual void
@@ -2585,19 +2588,26 @@ void
 BlobParent::
 RemoteBlobImpl::GetName(nsAString& aName) const
 {
   mBlobImpl->GetName(aName);
 }
 
 void
 BlobParent::
-RemoteBlobImpl::GetPath(nsAString& aPath, ErrorResult& aRv)
+RemoteBlobImpl::GetPath(nsAString& aPath) const
 {
-  mBlobImpl->GetPath(aPath, aRv);
+  mBlobImpl->GetPath(aPath);
+}
+
+void
+BlobParent::
+RemoteBlobImpl::SetPath(const nsAString& aPath)
+{
+  mBlobImpl->SetPath(aPath);
 }
 
 int64_t
 BlobParent::
 RemoteBlobImpl::GetLastModified(ErrorResult& aRv)
 {
   return mBlobImpl->GetLastModified(aRv);
 }
--- a/dom/media/ADTSDecoder.cpp
+++ b/dom/media/ADTSDecoder.cpp
@@ -27,17 +27,16 @@ ADTSDecoder::CreateStateMachine()
   RefPtr<MediaDecoderReader> reader =
       new MediaFormatReader(this, new ADTSDemuxer(GetResource()));
   return new MediaDecoderStateMachine(this, reader);
 }
 
 /* static */ bool
 ADTSDecoder::IsEnabled()
 {
-  PDMFactory::Init();
   RefPtr<PDMFactory> platform = new PDMFactory();
   return platform->SupportsMimeType(NS_LITERAL_CSTRING("audio/mp4a-latm"),
                                     /* DecoderDoctorDiagnostics* */ nullptr);
 }
 
 /* static */ bool
 ADTSDecoder::CanHandleMediaType(const nsACString& aType,
                                 const nsAString& aCodecs)
--- a/dom/media/Benchmark.cpp
+++ b/dom/media/Benchmark.cpp
@@ -2,16 +2,17 @@
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* 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 "Benchmark.h"
 #include "BufferMediaResource.h"
 #include "MediaData.h"
+#include "MediaPrefs.h"
 #include "PDMFactory.h"
 #include "WebMDemuxer.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/dom/ContentChild.h"
 
 #ifndef MOZ_WIDGET_ANDROID
 #include "WebMSample.h"
@@ -40,18 +41,16 @@ VP9Benchmark::IsVP9DecodeFast()
   uint32_t hadRecentUpdate = Preferences::GetUint(sBenchmarkFpsVersionCheck, 0U);
 
   if (!sHasRunTest && (!hasPref || hadRecentUpdate != sBenchmarkVersionID)) {
     sHasRunTest = true;
 
     RefPtr<WebMDemuxer> demuxer =
       new WebMDemuxer(new BufferMediaResource(sWebMSample, sizeof(sWebMSample), nullptr,
                                               NS_LITERAL_CSTRING("video/webm")));
-    PDMFactory::Init();
-
     RefPtr<Benchmark> estimiser =
       new Benchmark(demuxer,
                     {
                       Preferences::GetInt("media.benchmark.frames", 300), // frames to measure
                       1, // start benchmarking after decoding this frame.
                       8, // loop after decoding that many frames.
                       TimeDuration::FromMilliseconds(
                         Preferences::GetUint("media.benchmark.timeout", 1000))
@@ -130,17 +129,17 @@ Benchmark::Dispose()
   mPromise.RejectIfExists(false, __func__);
 }
 
 void
 Benchmark::Init()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
-  PDMFactory::Init();
+  MediaPrefs::GetSingleton();
 }
 
 BenchmarkPlayback::BenchmarkPlayback(Benchmark* aMainThreadState,
                                      MediaDataDemuxer* aDemuxer)
   : QueueObject(new TaskQueue(GetMediaThreadPool(MediaThreadType::PLAYBACK)))
   , mMainThreadState(aMainThreadState)
   , mDecoderTaskQueue(new FlushableTaskQueue(GetMediaThreadPool(
                         MediaThreadType::PLATFORM_DECODER)))
--- a/dom/media/MP3Decoder.cpp
+++ b/dom/media/MP3Decoder.cpp
@@ -26,17 +26,16 @@ MP3Decoder::CreateStateMachine() {
   RefPtr<MediaDecoderReader> reader =
       new MediaFormatReader(this, new mp3::MP3Demuxer(GetResource()));
   return new MediaDecoderStateMachine(this, reader);
 }
 
 /* static */
 bool
 MP3Decoder::IsEnabled() {
-  PDMFactory::Init();
   RefPtr<PDMFactory> platform = new PDMFactory();
   return platform->SupportsMimeType(NS_LITERAL_CSTRING("audio/mpeg"),
                                     /* DecoderDoctorDiagnostics* */ nullptr);
 }
 
 /* static */
 bool MP3Decoder::CanHandleMediaType(const nsACString& aType,
                                     const nsAString& aCodecs)
--- a/dom/media/MediaDecoderReaderWrapper.cpp
+++ b/dom/media/MediaDecoderReaderWrapper.cpp
@@ -274,17 +274,17 @@ MediaDecoderReaderWrapper::RequestVideoD
 bool
 MediaDecoderReaderWrapper::IsRequestingAudioData() const
 {
   MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
   return mAudioDataRequest.Exists();
 }
 
 bool
-MediaDecoderReaderWrapper::IsRequestingVidoeData() const
+MediaDecoderReaderWrapper::IsRequestingVideoData() const
 {
   MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
   return mVideoDataRequest.Exists();
 }
 
 RefPtr<MediaDecoderReader::SeekPromise>
 MediaDecoderReaderWrapper::Seek(SeekTarget aTarget, media::TimeUnit aEndTime)
 {
--- a/dom/media/MediaDecoderReaderWrapper.h
+++ b/dom/media/MediaDecoderReaderWrapper.h
@@ -242,17 +242,17 @@ public:
   void CancelAudioCallback(CallbackID aID);
   void CancelVideoCallback(CallbackID aID);
 
   // NOTE: please set callbacks before requesting audio/video data!
   void RequestAudioData();
   void RequestVideoData(bool aSkipToNextKeyframe, media::TimeUnit aTimeThreshold);
 
   bool IsRequestingAudioData() const;
-  bool IsRequestingVidoeData() const;
+  bool IsRequestingVideoData() const;
 
   RefPtr<SeekPromise> Seek(SeekTarget aTarget, media::TimeUnit aEndTime);
   RefPtr<WaitForDataPromise> WaitForData(MediaData::Type aType);
   RefPtr<BufferedUpdatePromise> UpdateBufferedWithPromise();
   RefPtr<ShutdownPromise> Shutdown();
 
   void ReleaseMediaResources();
   void SetIdle();
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -1759,17 +1759,17 @@ MediaDecoderStateMachine::EnsureVideoDec
 
   if (IsVideoDecodeSuspended() && !IsDecodingFirstFrame()) {
     // The element is invisible and background videos should be suspended.
     // If the first frame has already been decoded, don't request anymore video
     // frames.
     return NS_OK;
   }
 
-  if (!IsVideoDecoding() || mReader->IsRequestingVidoeData() ||
+  if (!IsVideoDecoding() || mReader->IsRequestingVideoData() ||
       mVideoWaitRequest.Exists()) {
     return NS_OK;
   }
 
   RequestVideoData();
   return NS_OK;
 }
 
@@ -2272,17 +2272,17 @@ nsresult MediaDecoderStateMachine::RunSt
           ScheduleStateMachineIn(USECS_PER_S);
           return NS_OK;
         }
       } else if (OutOfDecodedAudio() || OutOfDecodedVideo()) {
         MOZ_ASSERT(mReader->IsWaitForDataSupported(),
                    "Don't yet have a strategy for non-heuristic + non-WaitForData");
         DispatchDecodeTasksIfNeeded();
         MOZ_ASSERT_IF(!mMinimizePreroll && OutOfDecodedAudio(), mReader->IsRequestingAudioData() || mAudioWaitRequest.Exists());
-        MOZ_ASSERT_IF(!mMinimizePreroll && OutOfDecodedVideo(), mReader->IsRequestingVidoeData() || mVideoWaitRequest.Exists());
+        MOZ_ASSERT_IF(!mMinimizePreroll && OutOfDecodedVideo(), mReader->IsRequestingVideoData() || mVideoWaitRequest.Exists());
         DECODER_LOG("In buffering mode, waiting to be notified: outOfAudio: %d, "
                     "mAudioStatus: %s, outOfVideo: %d, mVideoStatus: %s",
                     OutOfDecodedAudio(), AudioRequestStatus(),
                     OutOfDecodedVideo(), VideoRequestStatus());
         return NS_OK;
       }
 
       DECODER_LOG("Changed state from BUFFERING to DECODING");
@@ -2855,17 +2855,17 @@ MediaDecoderStateMachine::AudioRequestSt
   }
   return "idle";
 }
 
 const char*
 MediaDecoderStateMachine::VideoRequestStatus() const
 {
   MOZ_ASSERT(OnTaskQueue());
-  if (mReader->IsRequestingVidoeData()) {
+  if (mReader->IsRequestingVideoData()) {
     MOZ_DIAGNOSTIC_ASSERT(!mVideoWaitRequest.Exists());
     return "pending";
   } else if (mVideoWaitRequest.Exists()) {
     return "waiting";
   }
   return "idle";
 }
 
--- a/dom/media/MediaFormatReader.cpp
+++ b/dom/media/MediaFormatReader.cpp
@@ -167,17 +167,16 @@ MediaFormatReader::InitLayersBackendType
 
   mLayersBackendType = layerManager->GetCompositorBackendType();
 }
 
 nsresult
 MediaFormatReader::Init()
 {
   MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
-  PDMFactory::Init();
 
   InitLayersBackendType();
 
   mAudio.mTaskQueue =
     new FlushableTaskQueue(GetMediaThreadPool(MediaThreadType::PLATFORM_DECODER));
   mVideo.mTaskQueue =
     new FlushableTaskQueue(GetMediaThreadPool(MediaThreadType::PLATFORM_DECODER));
 
@@ -1306,48 +1305,37 @@ MediaFormatReader::ResetDecode(TargetQue
 
   // Do the same for any data wait promises.
   mAudio.mWaitingPromise.RejectIfExists(WaitForDataRejectValue(MediaData::AUDIO_DATA, WaitForDataRejectValue::CANCELED), __func__);
   mVideo.mWaitingPromise.RejectIfExists(WaitForDataRejectValue(MediaData::VIDEO_DATA, WaitForDataRejectValue::CANCELED), __func__);
 
   // Reset miscellaneous seeking state.
   mPendingSeekTime.reset();
 
-  ResetDemuxers();
-
   if (HasVideo()) {
+    mVideo.ResetDemuxer();
+    mVideo.ResetState();
     Reset(TrackInfo::kVideoTrack);
     if (mVideo.HasPromise()) {
       mVideo.RejectPromise(CANCELED, __func__);
     }
   }
 
   if (HasAudio() && aQueues == AUDIO_VIDEO) {
+    mAudio.ResetDemuxer();
+    mAudio.ResetState();
     Reset(TrackInfo::kAudioTrack);
     if (mAudio.HasPromise()) {
       mAudio.RejectPromise(CANCELED, __func__);
     }
   }
   return MediaDecoderReader::ResetDecode(aQueues);
 }
 
 void
-MediaFormatReader::ResetDemuxers()
-{
-  if (HasVideo()) {
-    mVideo.ResetDemuxer();
-    mVideo.ResetState();
-  }
-  if (HasAudio()) {
-    mAudio.ResetDemuxer();
-    mAudio.ResetState();
-  }
-}
-
-void
 MediaFormatReader::Output(TrackType aTrack, MediaData* aSample)
 {
   LOGV("Decoded %s sample time=%lld timecode=%lld kf=%d dur=%lld",
        TrackTypeToStr(aTrack), aSample->mTime, aSample->mTimecode,
        aSample->mKeyframe, aSample->mDuration);
 
   if (!aSample) {
     NS_WARNING("MediaFormatReader::Output() passed a null sample");
@@ -1496,20 +1484,20 @@ RefPtr<MediaDecoderReader::SeekPromise>
 MediaFormatReader::Seek(SeekTarget aTarget, int64_t aUnused)
 {
   MOZ_ASSERT(OnTaskQueue());
 
   LOG("aTarget=(%lld)", aTarget.GetTime().ToMicroseconds());
 
   MOZ_DIAGNOSTIC_ASSERT(mSeekPromise.IsEmpty());
   MOZ_DIAGNOSTIC_ASSERT(!mVideo.HasPromise());
-  MOZ_DIAGNOSTIC_ASSERT(!mAudio.HasPromise());
+  MOZ_DIAGNOSTIC_ASSERT(aTarget.IsVideoOnly() || !mAudio.HasPromise());
   MOZ_DIAGNOSTIC_ASSERT(mPendingSeekTime.isNothing());
   MOZ_DIAGNOSTIC_ASSERT(mVideo.mTimeThreshold.isNothing());
-  MOZ_DIAGNOSTIC_ASSERT(mAudio.mTimeThreshold.isNothing());
+  MOZ_DIAGNOSTIC_ASSERT(aTarget.IsVideoOnly() || mAudio.mTimeThreshold.isNothing());
 
   if (!mInfo.mMediaSeekable && !mInfo.mMediaSeekableOnlyInBufferedRanges) {
     LOG("Seek() END (Unseekable)");
     return SeekPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
   }
 
   if (mShutdown) {
     return SeekPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
@@ -1540,17 +1528,30 @@ MediaFormatReader::AttemptSeek()
 {
   MOZ_ASSERT(OnTaskQueue());
 
   mSeekScheduled = false;
 
   if (mPendingSeekTime.isNothing()) {
     return;
   }
-  ResetDemuxers();
+
+  if (HasVideo()) {
+    mVideo.ResetDemuxer();
+    mVideo.ResetState();
+  }
+
+  // Don't reset the audio demuxer not state when seeking video only
+  // as it will cause the audio to seek back to the beginning
+  // resulting in out-of-sync audio from video.
+  if (HasAudio() && !mOriginalSeekTarget->IsVideoOnly()) {
+    mAudio.ResetDemuxer();
+    mAudio.ResetState();
+  }
+
   if (HasVideo()) {
     DoVideoSeek();
   } else if (HasAudio()) {
     DoAudioSeek();
   } else {
     MOZ_CRASH();
   }
 }
--- a/dom/media/MediaFormatReader.h
+++ b/dom/media/MediaFormatReader.h
@@ -169,17 +169,16 @@ private:
   // functions.
   void Output(TrackType aType, MediaData* aSample);
   void InputExhausted(TrackType aTrack);
   void Error(TrackType aTrack);
   void Reset(TrackType aTrack);
   void DrainComplete(TrackType aTrack);
 
   bool ShouldSkip(bool aSkipToNextKeyframe, media::TimeUnit aTimeThreshold);
-  void ResetDemuxers();
 
   size_t SizeOfQueue(TrackType aTrack);
 
   RefPtr<PDMFactory> mPlatform;
 
   class DecoderCallback : public MediaDataDecoderCallback {
   public:
     DecoderCallback(MediaFormatReader* aReader, TrackType aType)
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -1086,27 +1086,33 @@ MediaManager::SelectSettings(
         videos.AppendElement(video);
       } else {
         RefPtr<AudioDevice> audio = static_cast<AudioDevice*>(source.get());
         audios.AppendElement(audio);
       }
     }
     sources.Clear();
     const char* badConstraint = nullptr;
-
-    if (videos.Length() && IsOn(aConstraints.mVideo)) {
+    bool needVideo = IsOn(aConstraints.mVideo);
+    bool needAudio = IsOn(aConstraints.mAudio);
+
+    if (needVideo && videos.Length()) {
       badConstraint = MediaConstraintsHelper::SelectSettings(
           GetInvariant(aConstraints.mVideo), videos);
+    }
+    if (!badConstraint && needAudio && audios.Length()) {
+      badConstraint = MediaConstraintsHelper::SelectSettings(
+          GetInvariant(aConstraints.mAudio), audios);
+    }
+    if (!badConstraint &&
+        !needVideo == !videos.Length() &&
+        !needAudio == !audios.Length()) {
       for (auto& video : videos) {
         sources.AppendElement(video);
       }
-    }
-    if (audios.Length() && IsOn(aConstraints.mAudio)) {
-      badConstraint = MediaConstraintsHelper::SelectSettings(
-          GetInvariant(aConstraints.mAudio), audios);
       for (auto& audio : audios) {
         sources.AppendElement(audio);
       }
     }
     NS_DispatchToMainThread(NewRunnableFrom([id, badConstraint]() mutable {
       RefPtr<MediaManager> mgr = MediaManager_GetInstance();
       RefPtr<PledgeChar> p = mgr->mOutstandingCharPledges.Remove(id);
       if (p) {
@@ -1256,16 +1262,22 @@ public:
 
   nsresult
   SetContraints(const MediaStreamConstraints& aConstraints)
   {
     mConstraints = aConstraints;
     return NS_OK;
   }
 
+  const MediaStreamConstraints&
+  GetConstraints()
+  {
+    return mConstraints;
+  }
+
   nsresult
   SetAudioDevice(AudioDevice* aAudioDevice)
   {
     mAudioDevice = aAudioDevice;
     mDeviceChosen = true;
     return NS_OK;
   }
 
@@ -1885,17 +1897,17 @@ MediaManager::GetUserMedia(nsPIDOMWindow
               !IsVistaOrLater()
 #endif
               ) ||
 #endif
             (!privileged && !HostIsHttps(*docURI)) ||
             !(loop || HostHasPermission(*docURI))) {
           RefPtr<MediaStreamError> error =
               new MediaStreamError(aWindow,
-                                   NS_LITERAL_STRING("SecurityError"));
+                                   NS_LITERAL_STRING("NotAllowedError"));
           onFailure->OnError(error);
           return NS_OK;
         }
         break;
 
       case MediaSourceEnum::Microphone:
       case MediaSourceEnum::Other:
       default: {
@@ -1966,17 +1978,17 @@ MediaManager::GetUserMedia(nsPIDOMWindow
         break;
 
       case MediaSourceEnum::AudioCapture:
         // Only enable AudioCapture if the pref is enabled. If it's not, we can
         // deny right away.
         if (!Preferences::GetBool("media.getusermedia.audiocapture.enabled")) {
           RefPtr<MediaStreamError> error =
             new MediaStreamError(aWindow,
-                                 NS_LITERAL_STRING("SecurityError"));
+                                 NS_LITERAL_STRING("NotAllowedError"));
           onFailure->OnError(error);
           return NS_OK;
         }
         break;
 
       case MediaSourceEnum::Other:
       default: {
         RefPtr<MediaStreamError> error =
@@ -2028,20 +2040,21 @@ MediaManager::GetUserMedia(nsPIDOMWindow
 
     uint32_t videoPerm = nsIPermissionManager::UNKNOWN_ACTION;
     if (IsOn(c.mVideo)) {
       rv = permManager->TestExactPermissionFromPrincipal(
         principal, "camera", &videoPerm);
       NS_ENSURE_SUCCESS(rv, rv);
     }
 
-    if ((!IsOn(c.mAudio) || audioPerm == nsIPermissionManager::DENY_ACTION) &&
-        (!IsOn(c.mVideo) || videoPerm == nsIPermissionManager::DENY_ACTION)) {
+    if ((!IsOn(c.mAudio) && !IsOn(c.mVideo)) ||
+        (IsOn(c.mAudio) && audioPerm == nsIPermissionManager::DENY_ACTION) ||
+        (IsOn(c.mVideo) && videoPerm == nsIPermissionManager::DENY_ACTION)) {
       RefPtr<MediaStreamError> error =
-          new MediaStreamError(aWindow, NS_LITERAL_STRING("SecurityError"));
+          new MediaStreamError(aWindow, NS_LITERAL_STRING("NotAllowedError"));
       onFailure->OnError(error);
       RemoveFromWindowList(windowID, listener);
       return NS_OK;
     }
   }
 
 #if defined(MOZ_B2G_CAMERA) && defined(MOZ_WIDGET_GONK)
   if (mCameraManager == nullptr) {
@@ -2713,21 +2726,16 @@ MediaManager::Observe(nsISupports* aSubj
 
     if (aSubject) {
       // A particular device or devices were chosen by the user.
       // NOTE: does not allow setting a device to null; assumes nullptr
       nsCOMPtr<nsISupportsArray> array(do_QueryInterface(aSubject));
       MOZ_ASSERT(array);
       uint32_t len = 0;
       array->Count(&len);
-      if (!len) {
-        // neither audio nor video were selected
-        task->Denied(NS_LITERAL_STRING("SecurityError"));
-        return NS_OK;
-      }
       bool videoFound = false, audioFound = false;
       for (uint32_t i = 0; i < len; i++) {
         nsCOMPtr<nsISupports> supports;
         array->GetElementAt(i,getter_AddRefs(supports));
         nsCOMPtr<nsIMediaDevice> device(do_QueryInterface(supports));
         MOZ_ASSERT(device); // shouldn't be returning anything else...
         if (device) {
           nsString type;
@@ -2742,27 +2750,35 @@ MediaManager::Observe(nsISupports* aSubj
               task->SetAudioDevice(static_cast<AudioDevice*>(device.get()));
               audioFound = true;
             }
           } else {
             NS_WARNING("Unknown device type in getUserMedia");
           }
         }
       }
+      bool needVideo = IsOn(task->GetConstraints().mVideo);
+      bool needAudio = IsOn(task->GetConstraints().mAudio);
+      MOZ_ASSERT(needVideo || needAudio);
+
+      if ((needVideo && !videoFound) || (needAudio && !audioFound)) {
+        task->Denied(NS_LITERAL_STRING("NotAllowedError"));
+        return NS_OK;
+      }
     }
 
     if (sInShutdown) {
       return task->Denied(NS_LITERAL_STRING("In shutdown"));
     }
     // Reuse the same thread to save memory.
     MediaManager::PostTask(task.forget());
     return NS_OK;
 
   } else if (!strcmp(aTopic, "getUserMedia:response:deny")) {
-    nsString errorMessage(NS_LITERAL_STRING("SecurityError"));
+    nsString errorMessage(NS_LITERAL_STRING("NotAllowedError"));
 
     if (aSubject) {
       nsCOMPtr<nsISupportsString> msg(do_QueryInterface(aSubject));
       MOZ_ASSERT(msg);
       msg->GetData(errorMessage);
       if (errorMessage.IsEmpty())
         errorMessage.AssignLiteral(MOZ_UTF16("InternalError"));
     }
--- a/dom/media/MediaPrefs.h
+++ b/dom/media/MediaPrefs.h
@@ -90,16 +90,19 @@ private:
 #ifdef MOZ_FFVPX
   DECL_MEDIA_PREF("media.ffvpx.enabled",                      PDMFFVPXEnabled, bool, true);
 #endif
 #ifdef XP_WIN
   DECL_MEDIA_PREF("media.wmf.enabled",                        PDMWMFEnabled, bool, true);
   DECL_MEDIA_PREF("media.webm.intel_decoder.enabled",         PDMWMFIntelDecoderEnabled, bool, false);
   DECL_MEDIA_PREF("media.wmf.low-latency.enabled",            PDMWMFLowLatencyEnabled, bool, false);
   DECL_MEDIA_PREF("media.wmf.decoder.thread-count",           PDMWMFThreadCount, int32_t, -1);
+  DECL_MEDIA_PREF("media.wmf.skip-blacklist",                 PDMWMFSkipBlacklist, bool, false);
+  DECL_MEDIA_PREF("media.windows-media-foundation.max-dxva-videos", PDMWMFMaxDXVAVideos, uint32_t, 8);
+  DECL_MEDIA_PREF("media.windows-media-foundation.allow-d3d11-dxva", PDMWMFAllowD3D11, bool, true);
 #endif
   DECL_MEDIA_PREF("media.decoder.fuzzing.enabled",            PDMFuzzingEnabled, bool, false);
   DECL_MEDIA_PREF("media.decoder.fuzzing.video-output-minimum-interval-ms", PDMFuzzingInterval, uint32_t, 0);
   DECL_MEDIA_PREF("media.decoder.fuzzing.dont-delay-inputexhausted", PDMFuzzingDelayInputExhausted, bool, true);
   DECL_MEDIA_PREF("media.gmp.decoder.enabled",                PDMGMPEnabled, bool, true);
   DECL_MEDIA_PREF("media.gmp.decoder.aac",                    GMPAACPreferred, uint32_t, 0);
   DECL_MEDIA_PREF("media.gmp.decoder.h264",                   GMPH264Preferred, uint32_t, 0);
 
--- a/dom/media/MediaStreamError.cpp
+++ b/dom/media/MediaStreamError.cpp
@@ -15,16 +15,19 @@ BaseMediaMgrError::BaseMediaMgrError(con
                                      const nsAString& aConstraint)
   : mName(aName)
   , mMessage(aMessage)
   , mConstraint(aConstraint)
 {
   if (mMessage.IsEmpty()) {
     if (mName.EqualsLiteral("NotFoundError")) {
       mMessage.AssignLiteral("The object can not be found here.");
+    } else if (mName.EqualsLiteral("NotAllowedError")) {
+      mMessage.AssignLiteral("The request is not allowed by the user agent "
+                             "or the platform in the current context.");
     } else if (mName.EqualsLiteral("SecurityError")) {
       mMessage.AssignLiteral("The operation is insecure.");
     } else if (mName.EqualsLiteral("SourceUnavailableError")) {
       mMessage.AssignLiteral("The source of the MediaStream could not be "
           "accessed due to a hardware error (e.g. lock from another process).");
     } else if (mName.EqualsLiteral("InternalError")) {
       mMessage.AssignLiteral("Internal error.");
     } else if (mName.EqualsLiteral("NotSupportedError")) {
--- a/dom/media/PeerConnection.js
+++ b/dom/media/PeerConnection.js
@@ -210,18 +210,19 @@ GlobalPCList.prototype = {
       }
     } else if (topic == "PeerConnection:response:allow" ||
                topic == "PeerConnection:response:deny") {
       var pc = this.findPC(data);
       if (pc) {
         if (topic == "PeerConnection:response:allow") {
           pc._settlePermission.allow();
         } else {
-          let err = new pc._win.DOMException("The operation is insecure.",
-                                             "SecurityError");
+          let err = new pc._win.DOMException("The request is not allowed by " +
+              "the user agent or the platform in the current context.",
+              "NotAllowedError");
           pc._settlePermission.deny(err);
         }
       }
     }
   },
 
   _registerPeerConnectionLifecycleCallback: function(winID, cb) {
     this._lifecycleobservers[winID] = cb;
--- a/dom/media/SeekTask.cpp
+++ b/dom/media/SeekTask.cpp
@@ -232,17 +232,17 @@ nsresult
 SeekTask::EnsureVideoDecodeTaskQueued()
 {
   AssertOwnerThread();
 
   SAMPLE_LOG("EnsureVideoDecodeTaskQueued isDecoding=%d status=%s",
              IsVideoDecoding(), VideoRequestStatus());
 
   if (!IsVideoDecoding() ||
-      mReader->IsRequestingVidoeData() ||
+      mReader->IsRequestingVideoData() ||
       mVideoWaitRequest.Exists() ||
       mSeekRequest.Exists()) {
     return NS_OK;
   }
 
   RequestVideoData();
   return NS_OK;
 }
@@ -259,17 +259,17 @@ SeekTask::AudioRequestStatus()
   }
   return "idle";
 }
 
 const char*
 SeekTask::VideoRequestStatus()
 {
   AssertOwnerThread();
-  if (mReader->IsRequestingVidoeData()) {
+  if (mReader->IsRequestingVideoData()) {
     MOZ_DIAGNOSTIC_ASSERT(!mVideoWaitRequest.Exists());
     return "pending";
   } else if (mVideoWaitRequest.Exists()) {
     return "waiting";
   }
   return "idle";
 }
 
--- a/dom/media/VideoSegment.cpp
+++ b/dom/media/VideoSegment.cpp
@@ -41,17 +41,18 @@ VideoFrame::TakeFrom(VideoFrame* aFrame)
   mIntrinsicSize = aFrame->mIntrinsicSize;
   mForceBlack = aFrame->GetForceBlack();
   mPrincipalHandle = aFrame->mPrincipalHandle;
 }
 
 /* static */ already_AddRefed<Image>
 VideoFrame::CreateBlackImage(const gfx::IntSize& aSize)
 {
-  RefPtr<ImageContainer> container = LayerManager::CreateImageContainer();
+  RefPtr<ImageContainer> container =
+    LayerManager::CreateImageContainer(ImageContainer::ASYNCHRONOUS);
   RefPtr<PlanarYCbCrImage> image = container->CreatePlanarYCbCrImage();
   if (!image) {
     MOZ_ASSERT(false);
     return nullptr;
   }
 
   int len = ((aSize.width * aSize.height) * 3 / 2);
 
--- a/dom/media/fmp4/MP4Decoder.cpp
+++ b/dom/media/fmp4/MP4Decoder.cpp
@@ -146,17 +146,16 @@ MP4Decoder::CanHandleMediaType(const nsA
         continue;
       }
       // Some unsupported codec.
       return false;
     }
   }
 
   // Verify that we have a PDM that supports the whitelisted types.
-  PDMFactory::Init();
   RefPtr<PDMFactory> platform = new PDMFactory();
   for (const nsCString& codecMime : codecMimes) {
     if (!platform->SupportsMimeType(codecMime, aDiagnostics)) {
       return false;
     }
   }
 
   return true;
@@ -225,18 +224,16 @@ CreateTestH264Decoder(layers::LayersBack
   aConfig.mId = 1;
   aConfig.mDuration = 40000;
   aConfig.mMediaTime = 0;
   aConfig.mImage = aConfig.mDisplay = nsIntSize(640, 360);
   aConfig.mExtraData = new MediaByteBuffer();
   aConfig.mExtraData->AppendElements(sTestH264ExtraData,
                                      MOZ_ARRAY_LENGTH(sTestH264ExtraData));
 
-  PDMFactory::Init();
-
   RefPtr<PDMFactory> platform = new PDMFactory();
   RefPtr<MediaDataDecoder> decoder(
     platform->CreateDecoder(aConfig, aTaskQueue, nullptr,
                             /* DecoderDoctorDiagnostics* */ nullptr,
                             aBackend, nullptr));
 
   return decoder.forget();
 }
--- a/dom/media/platforms/PDMFactory.cpp
+++ b/dom/media/platforms/PDMFactory.cpp
@@ -21,84 +21,97 @@
 #ifdef MOZ_GONK_MEDIACODEC
 #include "GonkDecoderModule.h"
 #endif
 #ifdef MOZ_WIDGET_ANDROID
 #include "AndroidDecoderModule.h"
 #endif
 #include "GMPDecoderModule.h"
 
+#include "mozilla/ClearOnShutdown.h"
+#include "mozilla/SharedThreadPool.h"
+#include "mozilla/StaticPtr.h"
 #include "mozilla/TaskQueue.h"
 
-#include "mozilla/SharedThreadPool.h"
-
 #include "MediaInfo.h"
 #include "MediaPrefs.h"
 #include "FuzzingWrapper.h"
 #include "H264Converter.h"
 
 #include "AgnosticDecoderModule.h"
 
 #ifdef MOZ_EME
 #include "EMEDecoderModule.h"
 #include "mozilla/CDMProxy.h"
 #endif
 
 #include "DecoderDoctorDiagnostics.h"
 
+
 namespace mozilla {
 
 extern already_AddRefed<PlatformDecoderModule> CreateAgnosticDecoderModule();
 extern already_AddRefed<PlatformDecoderModule> CreateBlankDecoderModule();
 
-/* static */
-void
-PDMFactory::Init()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  static bool alreadyInitialized = false;
-  if (alreadyInitialized) {
-    return;
-  }
-  alreadyInitialized = true;
-
-  // Ensure MediaPrefs are initialized.
-  MediaPrefs::GetSingleton();
-
+class PDMFactoryImpl final {
+public:
+  PDMFactoryImpl()
+  {
 #ifdef XP_WIN
-  WMFDecoderModule::Init();
+    WMFDecoderModule::Init();
 #endif
 #ifdef MOZ_APPLEMEDIA
-  AppleDecoderModule::Init();
+    AppleDecoderModule::Init();
 #endif
 #ifdef MOZ_FFVPX
-  FFVPXRuntimeLinker::Init();
+    FFVPXRuntimeLinker::Init();
 #endif
 #ifdef MOZ_FFMPEG
-  FFmpegRuntimeLinker::Init();
+    FFmpegRuntimeLinker::Init();
 #endif
-  GMPDecoderModule::Init();
-}
+    GMPDecoderModule::Init();
+  }
+};
+
+StaticAutoPtr<PDMFactoryImpl> PDMFactory::sInstance;
+StaticMutex PDMFactory::sMonitor;
 
 PDMFactory::PDMFactory()
 {
+  EnsureInit();
   CreatePDMs();
 }
 
 PDMFactory::~PDMFactory()
 {
 }
 
+void
+PDMFactory::EnsureInit() const
+{
+  StaticMutexAutoLock mon(sMonitor);
+  if (!sInstance) {
+    sInstance = new PDMFactoryImpl();
+    if (NS_IsMainThread()) {
+      ClearOnShutdown(&sInstance);
+    } else {
+      nsCOMPtr<nsIRunnable> runnable =
+        NS_NewRunnableFunction([]() { ClearOnShutdown(&sInstance); });
+      NS_DispatchToMainThread(runnable);
+    }
+  }
+}
+
 already_AddRefed<MediaDataDecoder>
 PDMFactory::CreateDecoder(const TrackInfo& aConfig,
                           FlushableTaskQueue* aTaskQueue,
                           MediaDataDecoderCallback* aCallback,
                           DecoderDoctorDiagnostics* aDiagnostics,
                           layers::LayersBackend aLayersBackend,
-                          layers::ImageContainer* aImageContainer)
+                          layers::ImageContainer* aImageContainer) const
 {
   bool isEncrypted = mEMEPDM && aConfig.mCrypto.mValid;
 
   if (isEncrypted) {
     return CreateDecoderWithPDM(mEMEPDM,
                                 aConfig,
                                 aTaskQueue,
                                 aCallback,
@@ -143,17 +156,17 @@ PDMFactory::CreateDecoder(const TrackInf
 
 already_AddRefed<MediaDataDecoder>
 PDMFactory::CreateDecoderWithPDM(PlatformDecoderModule* aPDM,
                                  const TrackInfo& aConfig,
                                  FlushableTaskQueue* aTaskQueue,
                                  MediaDataDecoderCallback* aCallback,
                                  DecoderDoctorDiagnostics* aDiagnostics,
                                  layers::LayersBackend aLayersBackend,
-                                 layers::ImageContainer* aImageContainer)
+                                 layers::ImageContainer* aImageContainer) const
 {
   MOZ_ASSERT(aPDM);
   RefPtr<MediaDataDecoder> m;
 
   if (aConfig.GetAsAudioInfo()) {
     m = aPDM->CreateAudioDecoder(*aConfig.GetAsAudioInfo(),
                                  aTaskQueue,
                                  aCallback,
--- a/dom/media/platforms/PDMFactory.h
+++ b/dom/media/platforms/PDMFactory.h
@@ -3,45 +3,44 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #if !defined(PDMFactory_h_)
 #define PDMFactory_h_
 
 #include "PlatformDecoderModule.h"
+#include "mozilla/StaticMutex.h"
 
 class CDMProxy;
 
 namespace mozilla {
 
 class DecoderDoctorDiagnostics;
+class PDMFactoryImpl;
+template<class T> class StaticAutoPtr;
 
 class PDMFactory final {
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PDMFactory)
 
   PDMFactory();
 
-  // Call on the main thread to initialize the static state
-  // needed by Create().
-  static void Init();
-
   // Factory method that creates the appropriate PlatformDecoderModule for
   // the platform we're running on. Caller is responsible for deleting this
   // instance. It's expected that there will be multiple
   // PlatformDecoderModules alive at the same time.
   // This is called on the decode task queue.
   already_AddRefed<MediaDataDecoder>
   CreateDecoder(const TrackInfo& aConfig,
                 FlushableTaskQueue* aTaskQueue,
                 MediaDataDecoderCallback* aCallback,
                 DecoderDoctorDiagnostics* aDiagnostics,
                 layers::LayersBackend aLayersBackend = layers::LayersBackend::LAYERS_NONE,
-                layers::ImageContainer* aImageContainer = nullptr);
+                layers::ImageContainer* aImageContainer = nullptr) const;
 
   bool SupportsMimeType(const nsACString& aMimeType,
                         DecoderDoctorDiagnostics* aDiagnostics) const;
 
 #ifdef MOZ_EME
   // Creates a PlatformDecoderModule that uses a CDMProxy to decrypt or
   // decrypt-and-decode EME encrypted content. If the CDM only decrypts and
   // does not decode, we create a PDM and use that to create MediaDataDecoders
@@ -62,21 +61,26 @@ private:
 
   already_AddRefed<MediaDataDecoder>
   CreateDecoderWithPDM(PlatformDecoderModule* aPDM,
                        const TrackInfo& aConfig,
                        FlushableTaskQueue* aTaskQueue,
                        MediaDataDecoderCallback* aCallback,
                        DecoderDoctorDiagnostics* aDiagnostics,
                        layers::LayersBackend aLayersBackend,
-                       layers::ImageContainer* aImageContainer);
+                       layers::ImageContainer* aImageContainer) const;
 
   nsTArray<RefPtr<PlatformDecoderModule>> mCurrentPDMs;
   RefPtr<PlatformDecoderModule> mEMEPDM;
 
   bool mWMFFailedToLoad = false;
   bool mFFmpegFailedToLoad = false;
   bool mGMPPDMFailedToStartup = false;
+
+  void EnsureInit() const;
+  template<class T> friend class StaticAutoPtr;
+  static StaticAutoPtr<PDMFactoryImpl> sInstance;
+  static StaticMutex sMonitor;
 };
 
 } // namespace mozilla
 
 #endif /* PDMFactory_h_ */
--- a/dom/media/platforms/agnostic/gmp/GMPDecoderModule.cpp
+++ b/dom/media/platforms/agnostic/gmp/GMPDecoderModule.cpp
@@ -8,16 +8,17 @@
 #include "DecoderDoctorDiagnostics.h"
 #include "GMPAudioDecoder.h"
 #include "GMPVideoDecoder.h"
 #include "MediaDataDecoderProxy.h"
 #include "MediaPrefs.h"
 #include "mozIGeckoMediaPluginService.h"
 #include "nsServiceManagerUtils.h"
 #include "mozilla/StaticMutex.h"
+#include "mozilla/SyncRunnable.h"
 #include "gmp-audio-decode.h"
 #include "gmp-video-decode.h"
 #ifdef XP_WIN
 #include "WMFDecoderModule.h"
 #endif
 
 namespace mozilla {
 
@@ -107,17 +108,16 @@ GMPDecoderModule::DecoderNeedsConversion
   }
 }
 
 static bool
 HasGMPFor(const nsACString& aAPI,
           const nsACString& aCodec,
           const nsACString& aGMP)
 {
-  MOZ_ASSERT(NS_IsMainThread());
 #ifdef XP_WIN
   // gmp-clearkey uses WMF for decoding, so if we're using clearkey we must
   // verify that WMF works before continuing.
   if (aGMP.EqualsLiteral("org.w3.clearkey")) {
     RefPtr<WMFDecoderModule> pdm(new WMFDecoderModule());
     if (aCodec.EqualsLiteral("aac") &&
         !pdm->SupportsMimeType(NS_LITERAL_CSTRING("audio/mp4a-latm"),
                                /* DecoderDoctorDiagnostics* */ nullptr)) {
@@ -125,16 +125,18 @@ HasGMPFor(const nsACString& aAPI,
     }
     if (aCodec.EqualsLiteral("h264") &&
         !pdm->SupportsMimeType(NS_LITERAL_CSTRING("video/avc"),
                                /* DecoderDoctorDiagnostics* */ nullptr)) {
       return false;
     }
   }
 #endif
+  MOZ_ASSERT(NS_IsMainThread(),
+             "HasPluginForAPI must be called on the main thread");
   nsTArray<nsCString> tags;
   tags.AppendElement(aCodec);
   tags.AppendElement(aGMP);
   nsCOMPtr<mozIGeckoMediaPluginService> mps =
     do_GetService("@mozilla.org/gecko-media-plugin-service;1");
   if (NS_WARN_IF(!mps)) {
     return false;
   }
@@ -174,18 +176,23 @@ GMPDecoderModule::UpdateUsableCodecs()
                              nsDependentCString(gmp.mKeySystem));
   }
 }
 
 /* static */
 void
 GMPDecoderModule::Init()
 {
-  MOZ_ASSERT(NS_IsMainThread());
-
+  if (!NS_IsMainThread()) {
+    nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
+    nsCOMPtr<nsIRunnable> runnable =
+      NS_NewRunnableFunction([]() { Init(); });
+    SyncRunnable::DispatchToThread(mainThread, runnable);
+    return;
+  }
   // GMPService::HasPluginForAPI is main thread only, so to implement
   // SupportsMimeType() we build a table of the codecs which each whitelisted
   // GMP has and update it when any GMPs are removed or added at runtime.
   UpdateUsableCodecs();
 }
 
 /* static */
 const Maybe<nsCString>
--- a/dom/media/platforms/apple/AppleATDecoder.cpp
+++ b/dom/media/platforms/apple/AppleATDecoder.cpp
@@ -5,33 +5,35 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "AppleUtils.h"
 #include "MP4Decoder.h"
 #include "mp4_demuxer/Adts.h"
 #include "MediaInfo.h"
 #include "AppleATDecoder.h"
 #include "mozilla/Logging.h"
+#include "mozilla/SyncRunnable.h"
 #include "mozilla/UniquePtr.h"
 
 extern mozilla::LogModule* GetPDMLog();
 #define LOG(...) MOZ_LOG(GetPDMLog(), mozilla::LogLevel::Debug, (__VA_ARGS__))
 #define FourCC2Str(n) ((char[5]){(char)(n >> 24), (char)(n >> 16), (char)(n >> 8), (char)(n), 0})
 
 namespace mozilla {
 
 AppleATDecoder::AppleATDecoder(const AudioInfo& aConfig,
-                               FlushableTaskQueue* aAudioTaskQueue,
+                               TaskQueue* aTaskQueue,
                                MediaDataDecoderCallback* aCallback)
   : mConfig(aConfig)
   , mFileStreamError(false)
-  , mTaskQueue(aAudioTaskQueue)
+  , mTaskQueue(aTaskQueue)
   , mCallback(aCallback)
   , mConverter(nullptr)
   , mStream(nullptr)
+  , mIsFlushing(false)
 {
   MOZ_COUNT_CTOR(AppleATDecoder);
   LOG("Creating Apple AudioToolbox decoder");
   LOG("Audio Decoder configuration: %s %d Hz %d channels %d bits per channel",
       mConfig.mMimeType.get(),
       mConfig.mRate,
       mConfig.mChannels,
       mConfig.mBitDepth);
@@ -60,16 +62,17 @@ AppleATDecoder::Init()
   }
 
   return InitPromise::CreateAndResolve(TrackType::kAudioTrack, __func__);
 }
 
 nsresult
 AppleATDecoder::Input(MediaRawData* aSample)
 {
+  MOZ_ASSERT(mCallback->OnReaderTaskQueue());
   LOG("mp4 input sample %p %lld us %lld pts%s %llu bytes audio",
       aSample,
       aSample->mDuration,
       aSample->mTime,
       aSample->mKeyframe ? " keyframe" : "",
       (unsigned long long)aSample->Size());
 
   // Queue a task to perform the actual decoding on a separate thread.
@@ -78,42 +81,55 @@ AppleATDecoder::Input(MediaRawData* aSam
         this,
         &AppleATDecoder::SubmitSample,
         RefPtr<MediaRawData>(aSample));
   mTaskQueue->Dispatch(runnable.forget());
 
   return NS_OK;
 }
 
-nsresult
-AppleATDecoder::Flush()
+void
+AppleATDecoder::ProcessFlush()
 {
-  LOG("Flushing AudioToolbox AAC decoder");
-  mTaskQueue->Flush();
+  MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
   mQueuedSamples.Clear();
   OSStatus rv = AudioConverterReset(mConverter);
   if (rv) {
     LOG("Error %d resetting AudioConverter", rv);
-    return NS_ERROR_FAILURE;
   }
+}
+
+nsresult
+AppleATDecoder::Flush()
+{
+  MOZ_ASSERT(mCallback->OnReaderTaskQueue());
+  LOG("Flushing AudioToolbox AAC decoder");
+  mIsFlushing = true;
+  nsCOMPtr<nsIRunnable> runnable =
+    NewRunnableMethod(this, &AppleATDecoder::ProcessFlush);
+  SyncRunnable::DispatchToThread(mTaskQueue, runnable);
+  mIsFlushing = false;
   return NS_OK;
 }
 
 nsresult
 AppleATDecoder::Drain()
 {
+  MOZ_ASSERT(mCallback->OnReaderTaskQueue());
   LOG("Draining AudioToolbox AAC decoder");
   mTaskQueue->AwaitIdle();
   mCallback->DrainComplete();
   return Flush();
 }
 
 nsresult
 AppleATDecoder::Shutdown()
 {
+  MOZ_ASSERT(mCallback->OnReaderTaskQueue());
+
   LOG("Shutdown: Apple AudioToolbox AAC decoder");
   mQueuedSamples.Clear();
   OSStatus rv = AudioConverterDispose(mConverter);
   if (rv) {
     LOG("error %d disposing of AudioConverter", rv);
     return NS_ERROR_FAILURE;
   }
   mConverter = nullptr;
@@ -168,16 +184,22 @@ static OSStatus
   userData->mDataSize = 0;
 
   return noErr;
 }
 
 void
 AppleATDecoder::SubmitSample(MediaRawData* aSample)
 {
+  MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
+
+  if (mIsFlushing) {
+    return;
+  }
+
   nsresult rv = NS_OK;
   if (!mConverter) {
     rv = SetupDecoder(aSample);
     if (rv != NS_OK && rv != NS_ERROR_NOT_INITIALIZED) {
       mCallback->Error();
       return;
     }
   }
@@ -198,16 +220,18 @@ AppleATDecoder::SubmitSample(MediaRawDat
   if (mTaskQueue->IsEmpty()) {
     mCallback->InputExhausted();
   }
 }
 
 nsresult
 AppleATDecoder::DecodeSample(MediaRawData* aSample)
 {
+  MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
+
   // Array containing the queued decoded audio frames, about to be output.
   nsTArray<AudioDataValue> outputData;
   UInt32 channels = mOutputFormat.mChannelsPerFrame;
   // Pick a multiple of the frame size close to a power of two
   // for efficient allocation.
   const uint32_t MAX_AUDIO_FRAMES = 128;
   const uint32_t maxDecodedSamples = MAX_AUDIO_FRAMES * channels;
 
@@ -303,16 +327,18 @@ AppleATDecoder::DecodeSample(MediaRawDat
   mCallback->Output(audio);
   return NS_OK;
 }
 
 nsresult
 AppleATDecoder::GetInputAudioDescription(AudioStreamBasicDescription& aDesc,
                                          const nsTArray<uint8_t>& aExtraData)
 {
+  MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
+
   // Request the properties from CoreAudio using the codec magic cookie
   AudioFormatInfo formatInfo;
   PodZero(&formatInfo.mASBD);
   formatInfo.mASBD.mFormatID = mFormatID;
   if (mFormatID == kAudioFormatMPEG4AAC) {
     formatInfo.mASBD.mFormatFlags = mConfig.mExtendedProfile;
   }
   formatInfo.mMagicCookieSize = aExtraData.Length();
@@ -406,16 +432,18 @@ ConvertChannelLabel(AudioChannelLabel id
   }
 }
 
 // Will set mChannelLayout if a channel layout could properly be identified
 // and is supported.
 nsresult
 AppleATDecoder::SetupChannelLayout()
 {
+  MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
+
   // Determine the channel layout.
   UInt32 propertySize;
   UInt32 size;
   OSStatus status =
     AudioConverterGetPropertyInfo(mConverter,
                                   kAudioConverterOutputChannelLayout,
                                   &propertySize, NULL);
   if (status || !propertySize) {
@@ -505,16 +533,18 @@ AppleATDecoder::SetupChannelLayout()
     MakeUnique<AudioConfig::ChannelLayout>(mOutputFormat.mChannelsPerFrame,
                                            channels);
   return NS_OK;
 }
 
 nsresult
 AppleATDecoder::SetupDecoder(MediaRawData* aSample)
 {
+  MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
+
   if (mFormatID == kAudioFormatMPEG4AAC &&
       mConfig.mExtendedProfile == 2) {
     // Check for implicit SBR signalling if stream is AAC-LC
     // This will provide us with an updated magic cookie for use with
     // GetInputAudioDescription.
     if (NS_SUCCEEDED(GetImplicitAACMagicCookie(aSample)) &&
         !mMagicCookie.Length()) {
       // nothing found yet, will try again later
@@ -610,16 +640,18 @@ static void
                 const void* aData,
                 AudioStreamPacketDescription* aPackets)
 {
 }
 
 nsresult
 AppleATDecoder::GetImplicitAACMagicCookie(const MediaRawData* aSample)
 {
+  MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
+
   // Prepend ADTS header to AAC audio.
   RefPtr<MediaRawData> adtssample(aSample->Clone());
   if (!adtssample) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
   int8_t frequency_index =
     mp4_demuxer::Adts::GetFrequencyIndex(mConfig.mRate);
 
--- a/dom/media/platforms/apple/AppleATDecoder.h
+++ b/dom/media/platforms/apple/AppleATDecoder.h
@@ -11,23 +11,23 @@
 #include "PlatformDecoderModule.h"
 #include "mozilla/ReentrantMonitor.h"
 #include "mozilla/Vector.h"
 #include "nsIThread.h"
 #include "AudioConverter.h"
 
 namespace mozilla {
 
-class FlushableTaskQueue;
+class TaskQueue;
 class MediaDataDecoderCallback;
 
 class AppleATDecoder : public MediaDataDecoder {
 public:
   AppleATDecoder(const AudioInfo& aConfig,
-                 FlushableTaskQueue* aVideoTaskQueue,
+                 TaskQueue* aTaskQueue,
                  MediaDataDecoderCallback* aCallback);
   virtual ~AppleATDecoder();
 
   RefPtr<InitPromise> Init() override;
   nsresult Input(MediaRawData* aSample) override;
   nsresult Flush() override;
   nsresult Drain() override;
   nsresult Shutdown() override;
@@ -42,26 +42,28 @@ public:
 
   // Use to extract magic cookie for HE-AAC detection.
   nsTArray<uint8_t> mMagicCookie;
   // Will be set to true should an error occurred while attempting to retrieve
   // the magic cookie property.
   bool mFileStreamError;
 
 private:
-  RefPtr<FlushableTaskQueue> mTaskQueue;
+  const RefPtr<TaskQueue> mTaskQueue;
   MediaDataDecoderCallback* mCallback;
   AudioConverterRef mConverter;
   AudioStreamBasicDescription mOutputFormat;
   UInt32 mFormatID;
   AudioFileStreamID mStream;
   nsTArray<RefPtr<MediaRawData>> mQueuedSamples;
   UniquePtr<AudioConfig::ChannelLayout> mChannelLayout;
   UniquePtr<AudioConverter> mAudioConverter;
+  Atomic<bool> mIsFlushing;
 
+  void ProcessFlush();
   void SubmitSample(MediaRawData* aSample);
   nsresult DecodeSample(MediaRawData* aSample);
   nsresult GetInputAudioDescription(AudioStreamBasicDescription& aDesc,
                                     const nsTArray<uint8_t>& aExtraData);
   // Setup AudioConverter once all information required has been gathered.
   // Will return NS_ERROR_NOT_INITIALIZED if more data is required.
   nsresult SetupDecoder(MediaRawData* aSample);
   nsresult GetImplicitAACMagicCookie(const MediaRawData* aSample);
--- a/dom/media/platforms/apple/AppleCMLinker.cpp
+++ b/dom/media/platforms/apple/AppleCMLinker.cpp
@@ -2,50 +2,42 @@
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* 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 <dlfcn.h>
 
 #include "AppleCMLinker.h"
-#include "MainThreadUtils.h"
 #include "mozilla/ArrayUtils.h"
 #include "nsDebug.h"
 
 #ifndef MOZ_WIDGET_UIKIT
 #include "nsCocoaFeatures.h"
 #endif
 
 extern mozilla::LogModule* GetPDMLog();
 #define LOG(...) MOZ_LOG(GetPDMLog(), mozilla::LogLevel::Debug, (__VA_ARGS__))
 
 namespace mozilla {
 
 AppleCMLinker::LinkStatus
 AppleCMLinker::sLinkStatus = LinkStatus_INIT;
 
 void* AppleCMLinker::sLink = nullptr;
-nsrefcnt AppleCMLinker::sRefCount = 0;
 CFStringRef AppleCMLinker::skPropExtensionAtoms = nullptr;
 CFStringRef AppleCMLinker::skPropFullRangeVideo = nullptr;
 
 #define LINK_FUNC(func) typeof(CM ## func) CM ## func;
 #include "AppleCMFunctions.h"
 #undef LINK_FUNC
 
 /* static */ bool
 AppleCMLinker::Link()
 {
-  // Bump our reference count every time we're called.
-  // Add a lock or change the thread assertion if
-  // you need to call this off the main thread.
-  MOZ_ASSERT(NS_IsMainThread());
-  ++sRefCount;
-
   if (sLinkStatus) {
     return sLinkStatus == LinkStatus_SUCCEEDED;
   }
 
   const char* dlnames[] =
     { "/System/Library/Frameworks/CoreMedia.framework/CoreMedia",
       "/System/Library/PrivateFrameworks/CoreMedia.framework/CoreMedia" };
   bool dlfound = false;
@@ -111,20 +103,17 @@ fail:
 
   sLinkStatus = LinkStatus_FAILED;
   return false;
 }
 
 /* static */ void
 AppleCMLinker::Unlink()
 {
-  MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(sRefCount > 0, "Unbalanced Unlink()");
-  --sRefCount;
-  if (sLink && sRefCount < 1) {
+  if (sLink) {
     LOG("Unlinking CoreMedia framework.");
     dlclose(sLink);
     sLink = nullptr;
     sLinkStatus = LinkStatus_INIT;
   }
 }
 
 /* static */ CFStringRef
--- a/dom/media/platforms/apple/AppleCMLinker.h
+++ b/dom/media/platforms/apple/AppleCMLinker.h
@@ -22,17 +22,16 @@ class AppleCMLinker
 public:
   static bool Link();
   static void Unlink();
   static CFStringRef skPropExtensionAtoms;
   static CFStringRef skPropFullRangeVideo;
 
 private:
   static void* sLink;
-  static nsrefcnt sRefCount;
 
   static enum LinkStatus {
     LinkStatus_INIT = 0,
     LinkStatus_FAILED,
     LinkStatus_SUCCEEDED
   } sLinkStatus;
 
   static CFStringRef GetIOConst(const char* symbol);
--- a/dom/media/platforms/apple/AppleDecoderModule.cpp
+++ b/dom/media/platforms/apple/AppleDecoderModule.cpp
@@ -32,18 +32,16 @@ AppleDecoderModule::AppleDecoderModule()
 AppleDecoderModule::~AppleDecoderModule()
 {
 }
 
 /* static */
 void
 AppleDecoderModule::Init()
 {
-  MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
-
   if (sInitialized) {
     return;
   }
 
   // Ensure IOSurface framework is loaded.
   MacIOSurfaceLib::LoadLibrary();
   const bool loaded = MacIOSurfaceLib::isInit();
 
--- a/dom/media/platforms/apple/AppleVDALinker.cpp
+++ b/dom/media/platforms/apple/AppleVDALinker.cpp
@@ -2,47 +2,39 @@
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* 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 <dlfcn.h>
 
 #include "AppleVDALinker.h"
-#include "MainThreadUtils.h"
 #include "nsDebug.h"
 
 extern mozilla::LogModule* GetPDMLog();
 #define LOG(...) MOZ_LOG(GetPDMLog(), mozilla::LogLevel::Debug, (__VA_ARGS__))
 
 namespace mozilla {
 
 AppleVDALinker::LinkStatus
 AppleVDALinker::sLinkStatus = LinkStatus_INIT;
 
 void* AppleVDALinker::sLink = nullptr;
-nsrefcnt AppleVDALinker::sRefCount = 0;
 CFStringRef AppleVDALinker::skPropWidth = nullptr;
 CFStringRef AppleVDALinker::skPropHeight = nullptr;
 CFStringRef AppleVDALinker::skPropSourceFormat = nullptr;
 CFStringRef AppleVDALinker::skPropAVCCData = nullptr;
 
 #define LINK_FUNC(func) typeof(func) func;
 #include "AppleVDAFunctions.h"
 #undef LINK_FUNC
 
 /* static */ bool
 AppleVDALinker::Link()
 {
-  // Bump our reference count every time we're called.
-  // Add a lock or change the thread assertion if
-  // you need to call this off the main thread.
-  MOZ_ASSERT(NS_IsMainThread());
-  ++sRefCount;
-
   if (sLinkStatus) {
     return sLinkStatus == LinkStatus_SUCCEEDED;
   }
 
   const char* dlname =
     "/System/Library/Frameworks/VideoDecodeAcceleration.framework/VideoDecodeAcceleration";
 
   if (!(sLink = dlopen(dlname, RTLD_NOW | RTLD_LOCAL))) {
@@ -77,24 +69,17 @@ fail:
 
   sLinkStatus = LinkStatus_FAILED;
   return false;
 }
 
 /* static */ void
 AppleVDALinker::Unlink()
 {
-  // We'll be called by multiple Decoders, one intantiated for
-  // each media element. Therefore we receive must maintain a
-  // reference count to avoidunloading our symbols when other
-  // instances still need them.
-  MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(sRefCount > 0, "Unbalanced Unlink()");
-  --sRefCount;
-  if (sLink && sRefCount < 1) {
+  if (sLink) {
     LOG("Unlinking VideoDecodeAcceleration framework.");
 #define LINK_FUNC(func)                                                   \
     func = nullptr;
 #include "AppleVDAFunctions.h"
 #undef LINK_FUNC
     dlclose(sLink);
     sLink = nullptr;
     skPropWidth = nullptr;
--- a/dom/media/platforms/apple/AppleVTLinker.cpp
+++ b/dom/media/platforms/apple/AppleVTLinker.cpp
@@ -2,46 +2,38 @@
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* 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 <dlfcn.h>
 
 #include "AppleVTLinker.h"
-#include "MainThreadUtils.h"
 #include "mozilla/ArrayUtils.h"
 #include "nsDebug.h"
 
 extern mozilla::LogModule* GetPDMLog();
 #define LOG(...) MOZ_LOG(GetPDMLog(), mozilla::LogLevel::Debug, (__VA_ARGS__))
 
 namespace mozilla {
 
 AppleVTLinker::LinkStatus
 AppleVTLinker::sLinkStatus = LinkStatus_INIT;
 
 void* AppleVTLinker::sLink = nullptr;
-nsrefcnt AppleVTLinker::sRefCount = 0;
 CFStringRef AppleVTLinker::skPropEnableHWAccel = nullptr;
 CFStringRef AppleVTLinker::skPropUsingHWAccel = nullptr;
 
 #define LINK_FUNC(func) typeof(func) func;
 #include "AppleVTFunctions.h"
 #undef LINK_FUNC
 
 /* static */ bool
 AppleVTLinker::Link()
 {
-  // Bump our reference count every time we're called.
-  // Add a lock or change the thread assertion if
-  // you need to call this off the main thread.
-  MOZ_ASSERT(NS_IsMainThread());
-  ++sRefCount;
-
   if (sLinkStatus) {
     return sLinkStatus == LinkStatus_SUCCEEDED;
   }
 
   const char* dlnames[] =
     { "/System/Library/Frameworks/VideoToolbox.framework/VideoToolbox",
       "/System/Library/PrivateFrameworks/VideoToolbox.framework/VideoToolbox" };
   bool dlfound = false;
@@ -80,24 +72,17 @@ fail:
 
   sLinkStatus = LinkStatus_FAILED;
   return false;
 }
 
 /* static */ void
 AppleVTLinker::Unlink()
 {
-  // We'll be called by multiple Decoders, one intantiated for
-  // each media element. Therefore we receive must maintain a
-  // reference count to avoidunloading our symbols when other
-  // instances still need them.
-  MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(sRefCount > 0, "Unbalanced Unlink()");
-  --sRefCount;
-  if (sLink && sRefCount < 1) {
+  if (sLink) {
     LOG("Unlinking VideoToolbox framework.");
 #define LINK_FUNC(func)                                                   \
     func = nullptr;
 #include "AppleVTFunctions.h"
 #undef LINK_FUNC
     dlclose(sLink);
     sLink = nullptr;
     skPropEnableHWAccel = nullptr;
--- a/dom/media/platforms/apple/AppleVTLinker.h
+++ b/dom/media/platforms/apple/AppleVTLinker.h
@@ -22,17 +22,16 @@ class AppleVTLinker
 public:
   static bool Link();
   static void Unlink();
   static CFStringRef skPropEnableHWAccel;
   static CFStringRef skPropUsingHWAccel;
 
 private:
   static void* sLink;
-  static nsrefcnt sRefCount;
 
   static enum LinkStatus {
     LinkStatus_INIT = 0,
     LinkStatus_FAILED,
     LinkStatus_SUCCEEDED
   } sLinkStatus;
 
   static CFStringRef GetIOConst(const char* symbol);
--- a/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.cpp
+++ b/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.cpp
@@ -43,17 +43,16 @@ static const char* sLibs[] = {
 };
 
 /* static */ bool
 FFmpegRuntimeLinker::Init()
 {
   if (sLinkStatus) {
     return sLinkStatus == LinkStatus_SUCCEEDED;
   }
-  MOZ_ASSERT(NS_IsMainThread());
 
   for (size_t i = 0; i < ArrayLength(sLibs); i++) {
     const char* lib = sLibs[i];
     PRLibSpec lspec;
     lspec.type = PR_LibSpec_Pathname;
     lspec.value.pathname = lib;
     sLibAV.mAVCodecLib = PR_LoadLibraryWithFlags(lspec, PR_LD_NOW | PR_LD_LOCAL);
     if (sLibAV.mAVCodecLib) {
--- a/dom/media/platforms/ffmpeg/ffvpx/FFVPXRuntimeLinker.cpp
+++ b/dom/media/platforms/ffmpeg/ffvpx/FFVPXRuntimeLinker.cpp
@@ -44,17 +44,16 @@ MozAVLink(const char* aName)
 
 /* static */ bool
 FFVPXRuntimeLinker::Init()
 {
   if (sLinkStatus) {
     return sLinkStatus == LinkStatus_SUCCEEDED;
   }
 
-  MOZ_ASSERT(NS_IsMainThread());
   sLinkStatus = LinkStatus_FAILED;
 
   // We retrieve the path of the lgpllibs library as this is where mozavcodec
   // and mozavutil libs are located.
   char* lgpllibsname = PR_GetLibraryName(nullptr, "lgpllibs");
   if (!lgpllibsname) {
     return false;
   }
--- a/dom/media/platforms/gonk/GonkDecoderModule.cpp
+++ b/dom/media/platforms/gonk/GonkDecoderModule.cpp
@@ -13,23 +13,16 @@ namespace mozilla {
 GonkDecoderModule::GonkDecoderModule()
 {
 }
 
 GonkDecoderModule::~GonkDecoderModule()
 {
 }
 
-/* static */
-void
-GonkDecoderModule::Init()
-{
-  MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
-}
-
 already_AddRefed<MediaDataDecoder>
 GonkDecoderModule::CreateVideoDecoder(const VideoInfo& aConfig,
                                      mozilla::layers::LayersBackend aLayersBackend,
                                      mozilla::layers::ImageContainer* aImageContainer,
                                      FlushableTaskQueue* aVideoTaskQueue,
                                      MediaDataDecoderCallback* aCallback,
                                      DecoderDoctorDiagnostics* aDiagnostics)
 {
--- a/dom/media/platforms/gonk/GonkDecoderModule.h
+++ b/dom/media/platforms/gonk/GonkDecoderModule.h
@@ -27,18 +27,16 @@ public:
 
   // Decode thread.
   already_AddRefed<MediaDataDecoder>
   CreateAudioDecoder(const AudioInfo& aConfig,
                      FlushableTaskQueue* aAudioTaskQueue,
                      MediaDataDecoderCallback* aCallback,
                      DecoderDoctorDiagnostics* aDiagnostics) override;
 
-  static void Init();
-
   ConversionRequired
   DecoderNeedsConversion(const TrackInfo& aConfig) const override;
 
   bool SupportsMimeType(const nsACString& aMimeType,
                         DecoderDoctorDiagnostics* aDiagnostics) const override;
 
 };
 
--- a/dom/media/platforms/omx/OmxDecoderModule.cpp
+++ b/dom/media/platforms/omx/OmxDecoderModule.cpp
@@ -28,22 +28,16 @@ OmxDecoderModule::CreateAudioDecoder(con
                                      FlushableTaskQueue* aAudioTaskQueue,
                                      MediaDataDecoderCallback* aCallback,
                                      DecoderDoctorDiagnostics* aDiagnostics)
 {
   RefPtr<OmxDataDecoder> decoder = new OmxDataDecoder(aConfig, aCallback, nullptr);
   return decoder.forget();
 }
 
-void
-OmxDecoderModule::Init()
-{
-  MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
-}
-
 PlatformDecoderModule::ConversionRequired
 OmxDecoderModule::DecoderNeedsConversion(const TrackInfo& aConfig) const
 {
   return kNeedNone;
 }
 
 bool
 OmxDecoderModule::SupportsMimeType(const nsACString& aMimeType,
--- a/dom/media/platforms/omx/OmxDecoderModule.h
+++ b/dom/media/platforms/omx/OmxDecoderModule.h
@@ -22,18 +22,16 @@ public:
                      DecoderDoctorDiagnostics* aDiagnostics) override;
 
   already_AddRefed<MediaDataDecoder>
   CreateAudioDecoder(const AudioInfo& aConfig,
                      FlushableTaskQueue* aAudioTaskQueue,
                      MediaDataDecoderCallback* aCallback,
                      DecoderDoctorDiagnostics* aDiagnostics) override;
 
-  static void Init();
-
   bool SupportsMimeType(const nsACString& aMimeType,
                         DecoderDoctorDiagnostics* aDiagnostics) const override;
 
   ConversionRequired DecoderNeedsConversion(const TrackInfo& aConfig) const override;
 };
 
 } // namespace mozilla
 
--- a/dom/media/platforms/wmf/DXVA2Manager.cpp
+++ b/dom/media/platforms/wmf/DXVA2Manager.cpp
@@ -7,20 +7,20 @@
 #include "DXVA2Manager.h"
 #include <d3d11.h>
 #include "nsThreadUtils.h"
 #include "ImageContainer.h"
 #include "gfxWindowsPlatform.h"
 #include "D3D9SurfaceImage.h"
 #include "mozilla/layers/D3D11ShareHandleImage.h"
 #include "mozilla/layers/ImageBridgeChild.h"
-#include "mozilla/Preferences.h"
 #include "mozilla/Telemetry.h"
 #include "MediaTelemetryConstants.h"
 #include "mfapi.h"
+#include "MediaPrefs.h"
 #include "MFTDecoder.h"
 #include "DriverCrashGuard.h"
 #include "nsPrintfCString.h"
 
 const CLSID CLSID_VideoProcessorMFT =
 {
   0x88753b26,
   0x5b24,
@@ -385,18 +385,17 @@ D3D9DXVA2Manager::Init(nsACString& aFail
 
   D3DADAPTER_IDENTIFIER9 adapter;
   hr = d3d9Ex->GetAdapterIdentifier(D3DADAPTER_DEFAULT, 0, &adapter);
   if (!SUCCEEDED(hr)) {
     aFailureReason = nsPrintfCString("IDirect3D9Ex::GetAdapterIdentifier failed with error %X", hr);
     return hr;
   }
 
-  if (adapter.VendorId == 0x1022 &&
-      !Preferences::GetBool("media.wmf.skip-blacklist", false)) {
+  if (adapter.VendorId == 0x1022 && !MediaPrefs::PDMWMFSkipBlacklist()) {
     for (size_t i = 0; i < MOZ_ARRAY_LENGTH(sAMDPreUVD4); i++) {
       if (adapter.DeviceId == sAMDPreUVD4[i]) {
         mIsAMDPreUVD4 = true;
         break;
       }
     }
   }
 
@@ -471,18 +470,17 @@ static uint32_t sDXVAVideosCount = 0;
 DXVA2Manager*
 DXVA2Manager::CreateD3D9DXVA(nsACString& aFailureReason)
 {
   MOZ_ASSERT(NS_IsMainThread());
   HRESULT hr;
 
   // DXVA processing takes up a lot of GPU resources, so limit the number of
   // videos we use DXVA with at any one time.
-  const uint32_t dxvaLimit =
-    Preferences::GetInt("media.windows-media-foundation.max-dxva-videos", 8);
+  const uint32_t dxvaLimit = MediaPrefs::PDMWMFMaxDXVAVideos();
   if (sDXVAVideosCount == dxvaLimit) {
     aFailureReason.AssignLiteral("Too many DXVA videos playing");
     return nullptr;
   }
 
   nsAutoPtr<D3D9DXVA2Manager> d3d9Manager(new D3D9DXVA2Manager());
   hr = d3d9Manager->Init(aFailureReason);
   if (SUCCEEDED(hr)) {
@@ -699,18 +697,17 @@ D3D11DXVA2Manager::Init(nsACString& aFai
 
   DXGI_ADAPTER_DESC adapterDesc;
   hr = adapter->GetDesc(&adapterDesc);
   if (!SUCCEEDED(hr)) {
     aFailureReason = nsPrintfCString("IDXGIAdapter::GetDesc failed with code %X", hr);
     return hr;
   }
 
-  if (adapterDesc.VendorId == 0x1022 &&
-      !Preferences::GetBool("media.wmf.skip-blacklist", false)) {
+  if (adapterDesc.VendorId == 0x1022 && !MediaPrefs::PDMWMFSkipBlacklist()) {
     for (size_t i = 0; i < MOZ_ARRAY_LENGTH(sAMDPreUVD4); i++) {
       if (adapterDesc.DeviceId == sAMDPreUVD4[i]) {
         mIsAMDPreUVD4 = true;
         break;
       }
     }
   }
 
@@ -870,18 +867,17 @@ D3D11DXVA2Manager::ConfigureForSize(uint
 }
 
 /* static */
 DXVA2Manager*
 DXVA2Manager::CreateD3D11DXVA(nsACString& aFailureReason)
 {
   // DXVA processing takes up a lot of GPU resources, so limit the number of
   // videos we use DXVA with at any one time.
-  const uint32_t dxvaLimit =
-    Preferences::GetInt("media.windows-media-foundation.max-dxva-videos", 8);
+  const uint32_t dxvaLimit = MediaPrefs::PDMWMFMaxDXVAVideos();
   if (sDXVAVideosCount == dxvaLimit) {
     aFailureReason.AssignLiteral("Too many DXVA videos playing");
     return nullptr;
   }
 
   nsAutoPtr<D3D11DXVA2Manager> manager(new D3D11DXVA2Manager());
   HRESULT hr = manager->Init(aFailureReason);
   NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr);
--- a/dom/media/platforms/wmf/WMFDecoderModule.cpp
+++ b/dom/media/platforms/wmf/WMFDecoderModule.cpp
@@ -22,17 +22,17 @@
 #include "MediaInfo.h"
 #include "MediaPrefs.h"
 #include "prsystem.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/StaticMutex.h"
 
 namespace mozilla {
 
-static bool sDXVAEnabled = false;
+static Atomic<bool> sDXVAEnabled(false);
 
 WMFDecoderModule::WMFDecoderModule()
   : mWMFInitialized(false)
 {
 }
 
 WMFDecoderModule::~WMFDecoderModule()
 {
@@ -41,17 +41,16 @@ WMFDecoderModule::~WMFDecoderModule()
     NS_ASSERTION(SUCCEEDED(hr), "MFShutdown failed");
   }
 }
 
 /* static */
 void
 WMFDecoderModule::Init()
 {
-  MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
   sDXVAEnabled = gfxPlatform::GetPlatform()->CanUseHardwareVideoDecoding();
 }
 
 /* static */
 int
 WMFDecoderModule::GetNumDecoderThreads()
 {
   int32_t numCores = PR_GetNumberOfProcessors();
--- a/dom/media/platforms/wmf/WMFVideoMFTManager.cpp
+++ b/dom/media/platforms/wmf/WMFVideoMFTManager.cpp
@@ -11,22 +11,22 @@
 #include "WMFUtils.h"
 #include "ImageContainer.h"
 #include "VideoUtils.h"
 #include "DXVA2Manager.h"
 #include "nsThreadUtils.h"
 #include "Layers.h"
 #include "mozilla/layers/LayersTypes.h"
 #include "MediaInfo.h"
+#include "MediaPrefs.h"
 #include "mozilla/Logging.h"
 #include "gfx2DGlue.h"
 #include "gfxWindowsPlatform.h"
 #include "IMFYCbCrImage.h"
 #include "mozilla/WindowsVersion.h"
-#include "mozilla/Preferences.h"
 #include "mozilla/Telemetry.h"
 #include "nsPrintfCString.h"
 #include "MediaTelemetryConstants.h"
 
 extern mozilla::LogModule* GetPDMLog();
 #define LOG(...) MOZ_LOG(GetPDMLog(), mozilla::LogLevel::Debug, (__VA_ARGS__))
 
 using mozilla::layers::Image;
@@ -157,18 +157,17 @@ public:
     , mFailureReason(aFailureReason)
   {}
 
   NS_IMETHOD Run() {
     NS_ASSERTION(NS_IsMainThread(), "Must be on main thread.");
     nsACString* failureReason = &mFailureReason;
     nsCString secondFailureReason;
     if (mBackend == LayersBackend::LAYERS_D3D11 &&
-        Preferences::GetBool("media.windows-media-foundation.allow-d3d11-dxva", true) &&
-        IsWin8OrLater()) {
+        MediaPrefs::PDMWMFAllowD3D11() && IsWin8OrLater()) {
       mDXVA2Manager = DXVA2Manager::CreateD3D11DXVA(*failureReason);
       if (mDXVA2Manager) {
         return NS_OK;
       }
       // Try again with d3d9, but record the failure reason
       // into a new var to avoid overwriting the d3d11 failure.
       failureReason = &secondFailureReason;
       mFailureReason.Append(NS_LITERAL_CSTRING("; "));
--- a/dom/media/tests/mochitest/test_getUserMedia_basicScreenshare.html
+++ b/dom/media/tests/mochitest/test_getUserMedia_basicScreenshare.html
@@ -61,17 +61,17 @@
           max: '10'
         }
       }
     ];
     return Promise.resolve()
       .then(() => pushPrefs(["media.getusermedia.screensharing.allowed_domains",
                              "mozilla.github.io,*.bugzilla.mozilla.org"]))
       .then(() => mustFailWith("Screensharing if absent in allowed_domains",
-                               "SecurityError",
+                               "NotAllowedError",
                                () => navigator.mediaDevices.getUserMedia({
                                  video: videoConstraints[0], fake: false
                                })))
       .then(() => pushPrefs(["media.getusermedia.screensharing.allowed_domains",
                              "mozilla.github.io,mochi.test,*.bugzilla.mozilla.org"]))
       .then(() => getUserMedia(constraints).then(stream => {
         var playback = new LocalMediaStreamPlayback(testVideo, stream);
         return playback.playMediaWithDeprecatedStreamStop(false);
--- a/dom/media/tests/mochitest/test_getUserMedia_constraints.html
+++ b/dom/media/tests/mochitest/test_getUserMedia_constraints.html
@@ -21,26 +21,26 @@ var tests = [
   { message: "unknown required constraint on audio ignored",
     constraints: { audio: { somethingUnknown: { exact: 0 } } },
     error: null },
   { message: "audio overconstrained by facingMode ignored",
     constraints: { audio: { facingMode: { exact: 'left' } } },
     error: null },
   { message: "full screensharing requires permission",
     constraints: { video: { mediaSource: 'screen' } },
-    error: "SecurityError" },
+    error: "NotAllowedError" },
   { message: "application screensharing requires permission",
     constraints: { video: { mediaSource: 'application' } },
-    error: "SecurityError" },
+    error: "NotAllowedError" },
   { message: "window screensharing requires permission",
     constraints: { video: { mediaSource: 'window' } },
-    error: "SecurityError" },
+    error: "NotAllowedError" },
   { message: "browser screensharing requires permission",
     constraints: { video: { mediaSource: 'browser' } },
-    error: "SecurityError" },
+    error: "NotAllowedError" },
   { message: "unknown mediaSource in video fails",
     constraints: { video: { mediaSource: 'uncle' } },
     error: "OverconstrainedError",
     constraint: "mediaSource" },
   { message: "unknown mediaSource in audio fails",
     constraints: { audio: { mediaSource: 'uncle' } },
     error: "OverconstrainedError",
     constraint: "mediaSource" },
@@ -130,14 +130,21 @@ runTest(function() {
       .then(() => stream.getAudioTracks()[0].applyConstraints({ })))
     .then(() => ok(true, "applyConstraints code exercised"))
     // TODO: Test outcome once fake devices support constraints (Bug 1088621)
     .then(() => mustFailWith("applyConstraints fails on non-Gum tracks",
                              "OverconstrainedError", "",
                              () => (new AudioContext())
                                  .createMediaStreamDestination().stream
                                  .getAudioTracks()[0].applyConstraints()))
+    .then(() => mustFailWith(
+        "getUserMedia with unsatisfied required constraint",
+        "OverconstrainedError", "deviceId",
+        () => navigator.mediaDevices.getUserMedia({
+          audio: true,
+          video: { deviceId: { exact: "unheardof" } },
+        })));
 });
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/wave/WaveDecoder.cpp
+++ b/dom/media/wave/WaveDecoder.cpp
@@ -35,17 +35,16 @@ WaveDecoder::CreateStateMachine()
 /* static */
 bool
 WaveDecoder::IsEnabled()
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (!Preferences::GetBool("media.wave.decoder.enabled", false)) {
     return false;
   }
-  PDMFactory::Init();
   RefPtr<PDMFactory> platform = new PDMFactory();
   return platform->SupportsMimeType(NS_LITERAL_CSTRING("audio/x-wav"),
                                     /* DecoderDoctorDiagnostics* */ nullptr);
 }
 
 /* static */
 bool
 WaveDecoder::CanHandleMediaType(const nsACString& aType,
--- a/dom/media/webrtc/MediaEngineDefault.cpp
+++ b/dom/media/webrtc/MediaEngineDefault.cpp
@@ -44,17 +44,18 @@ NS_IMPL_ISUPPORTS(MediaEngineDefaultVide
  */
 
 MediaEngineDefaultVideoSource::MediaEngineDefaultVideoSource()
   : MediaEngineVideoSource(kReleased)
   , mTimer(nullptr)
   , mMonitor("Fake video")
   , mCb(16), mCr(16)
 {
-  mImageContainer = layers::LayerManager::CreateImageContainer();
+  mImageContainer =
+    layers::LayerManager::CreateImageContainer(layers::ImageContainer::ASYNCHRONOUS);
 }
 
 MediaEngineDefaultVideoSource::~MediaEngineDefaultVideoSource()
 {}
 
 void
 MediaEngineDefaultVideoSource::GetName(nsAString& aName)
 {
--- a/dom/media/webrtc/MediaEngineRemoteVideoSource.cpp
+++ b/dom/media/webrtc/MediaEngineRemoteVideoSource.cpp
@@ -185,17 +185,18 @@ MediaEngineRemoteVideoSource::Start(Sour
     MOZ_ASSERT(mSources.Length() == mPrincipalHandles.Length());
   }
 
   aStream->AddTrack(aID, 0, new VideoSegment(), SourceMediaStream::ADDTRACK_QUEUED);
 
   if (mState == kStarted) {
     return NS_OK;
   }
-  mImageContainer = layers::LayerManager::CreateImageContainer();
+  mImageContainer =
+    layers::LayerManager::CreateImageContainer(layers::ImageContainer::ASYNCHRONOUS);
 
   mState = kStarted;
   mTrackID = aID;
 
   if (mozilla::camera::GetChildAndCall(
     &mozilla::camera::CamerasChild::StartCapture,
     mCapEngine, mCaptureIndex, mCapability, this)) {
     LOG(("StartCapture failed"));
--- a/dom/media/webrtc/MediaEngineTabVideoSource.cpp
+++ b/dom/media/webrtc/MediaEngineTabVideoSource.cpp
@@ -283,17 +283,18 @@ MediaEngineTabVideoSource::Draw() {
       docshell->GetPresContext(getter_AddRefs(presContext));
     }
     if (!presContext) {
       return;
     }
     presShell = presContext->PresShell();
   }
 
-  RefPtr<layers::ImageContainer> container = layers::LayerManager::CreateImageContainer();
+  RefPtr<layers::ImageContainer> container =
+    layers::LayerManager::CreateImageContainer(layers::ImageContainer::ASYNCHRONOUS);
   RefPtr<DrawTarget> dt =
     Factory::CreateDrawTargetForData(BackendType::CAIRO,
                                      mData.get(),
                                      size,
                                      stride,
                                      SurfaceFormat::B8G8R8X8);
   if (!dt || !dt->IsValid()) {
     return;
--- a/dom/webidl/File.webidl
+++ b/dom/webidl/File.webidl
@@ -39,14 +39,14 @@ dictionary ChromeFilePropertyBag : FileP
 };
 
 // Mozilla extensions
 partial interface File {
 
   [GetterThrows]
   readonly attribute Date lastModifiedDate;
 
-  [GetterThrows, ChromeOnly]
-  readonly attribute DOMString path;
+  [BinaryName="path", Func="mozilla::dom::Directory::WebkitBlinkDirectoryPickerEnabled"]
+  readonly attribute DOMString webkitRelativePath;
 
   [GetterThrows, ChromeOnly]
   readonly attribute DOMString mozFullPath;
 };
--- a/dom/workers/WorkerPrefs.h
+++ b/dom/workers/WorkerPrefs.h
@@ -30,16 +30,17 @@ WORKER_SIMPLE_PREF("dom.performance.enab
 WORKER_SIMPLE_PREF("dom.webnotifications.enabled", DOMWorkerNotificationEnabled, DOM_WORKERNOTIFICATION)
 WORKER_SIMPLE_PREF("dom.webnotifications.serviceworker.enabled", DOMServiceWorkerNotificationEnabled, DOM_SERVICEWORKERNOTIFICATION)
 WORKER_SIMPLE_PREF("dom.serviceWorkers.enabled", ServiceWorkersEnabled, SERVICEWORKERS_ENABLED)
 WORKER_SIMPLE_PREF("dom.serviceWorkers.testing.enabled", ServiceWorkersTestingEnabled, SERVICEWORKERS_TESTING_ENABLED)
 WORKER_SIMPLE_PREF("dom.serviceWorkers.openWindow.enabled", OpenWindowEnabled, OPEN_WINDOW_ENABLED)
 WORKER_SIMPLE_PREF("dom.push.enabled", PushEnabled, PUSH_ENABLED)
 WORKER_SIMPLE_PREF("dom.requestcontext.enabled", RequestContextEnabled, REQUESTCONTEXT_ENABLED)
 WORKER_SIMPLE_PREF("gfx.offscreencanvas.enabled", OffscreenCanvasEnabled, OFFSCREENCANVAS_ENABLED)
+WORKER_SIMPLE_PREF("dom.webkitBlink.dirPicker.enabled", WebkitBlinkDirectoryPickerEnabled, DOM_WEBKITBLINK_DIRPICKER_WEBKITBLINK)
 WORKER_PREF("dom.workers.latestJSVersion", JSVersionChanged)
 WORKER_PREF("intl.accept_languages", PrefLanguagesChanged)
 WORKER_PREF("general.appname.override", AppNameOverrideChanged)
 WORKER_PREF("general.appversion.override", AppVersionOverrideChanged)
 WORKER_PREF("general.platform.override", PlatformOverrideChanged)
 #ifdef JS_GC_ZEAL
 WORKER_PREF("dom.workers.options.gcZeal", LoadGCZealOptions)
 #endif
--- a/gfx/layers/composite/TextureHost.cpp
+++ b/gfx/layers/composite/TextureHost.cpp
@@ -6,16 +6,17 @@
 #include "TextureHost.h"
 
 #include "CompositableHost.h"           // for CompositableHost
 #include "LayerScope.h"
 #include "LayersLogging.h"              // for AppendToString
 #include "mozilla/gfx/2D.h"             // for DataSourceSurface, Factory
 #include "mozilla/ipc/Shmem.h"          // for Shmem
 #include "mozilla/layers/CompositableTransactionParent.h" // for CompositableParentManager
+#include "mozilla/layers/CompositorBridgeParent.h"
 #include "mozilla/layers/Compositor.h"  // for Compositor
 #include "mozilla/layers/ISurfaceAllocator.h"  // for ISurfaceAllocator
 #include "mozilla/layers/LayersSurfaces.h"  // for SurfaceDescriptor, etc
 #include "mozilla/layers/TextureHostOGL.h"  // for TextureHostOGL
 #include "mozilla/layers/ImageDataSerializer.h"
 #include "nsAString.h"
 #include "mozilla/RefPtr.h"                   // for nsRefPtr
 #include "nsPrintfCString.h"            // for nsPrintfCString
@@ -59,17 +60,17 @@ namespace layers {
 
 /**
  * TextureParent is the host-side IPDL glue between TextureClient and TextureHost.
  * It is an IPDL actor just like LayerParent, CompositableParent, etc.
  */
 class TextureParent : public ParentActor<PTextureParent>
 {
 public:
-  explicit TextureParent(CompositableParentManager* aManager);
+  explicit TextureParent(ISurfaceAllocator* aAllocator);
 
   ~TextureParent();
 
   bool Init(const SurfaceDescriptor& aSharedData,
             const LayersBackend& aLayersBackend,
             const TextureFlags& aFlags);
 
   void CompositorRecycle();
@@ -77,36 +78,36 @@ public:
   virtual bool RecvClientRecycle() override;
 
   virtual bool RecvRecycleTexture(const TextureFlags& aTextureFlags) override;
 
   TextureHost* GetTextureHost() { return mTextureHost; }
 
   virtual void Destroy() override;
 
-  CompositableParentManager* mCompositableManager;
+  ISurfaceAllocator* mSurfaceAllocator;
   RefPtr<TextureHost> mWaitForClientRecycle;
   RefPtr<TextureHost> mTextureHost;
 };
 
 ////////////////////////////////////////////////////////////////////////////////
 PTextureParent*
-TextureHost::CreateIPDLActor(CompositableParentManager* aManager,
+TextureHost::CreateIPDLActor(ISurfaceAllocator* aAllocator,
                              const SurfaceDescriptor& aSharedData,
                              LayersBackend aLayersBackend,
                              TextureFlags aFlags)
 {
   if (aSharedData.type() == SurfaceDescriptor::TSurfaceDescriptorBuffer &&
       aSharedData.get_SurfaceDescriptorBuffer().data().type() == MemoryOrShmem::Tuintptr_t &&
-      !aManager->IsSameProcess())
+      !aAllocator->IsSameProcess())
   {
     NS_ERROR("A client process is trying to peek at our address space using a MemoryTexture!");
     return nullptr;
   }
-  TextureParent* actor = new TextureParent(aManager);
+  TextureParent* actor = new TextureParent(aAllocator);
   if (!actor->Init(aSharedData, aLayersBackend, aFlags)) {
     delete actor;
     return nullptr;
   }
   return actor;
 }
 
 // static
@@ -889,18 +890,18 @@ size_t MemoryTextureHost::GetBufferSize(
 {
   // MemoryTextureHost just trusts that the buffer size is large enough to read
   // anything we need to. That's because MemoryTextureHost has to trust the buffer
   // pointer anyway, so the security model here is just that MemoryTexture's
   // are restricted to same-process clients.
   return std::numeric_limits<size_t>::max();
 }
 
-TextureParent::TextureParent(CompositableParentManager* aCompositableManager)
-: mCompositableManager(aCompositableManager)
+TextureParent::TextureParent(ISurfaceAllocator* aSurfaceAllocator)
+: mSurfaceAllocator(aSurfaceAllocator)
 {
   MOZ_COUNT_CTOR(TextureParent);
 }
 
 TextureParent::~TextureParent()
 {
   MOZ_COUNT_DTOR(TextureParent);
   if (mTextureHost) {
@@ -940,17 +941,17 @@ TextureParent::RecvClientRecycle()
 }
 
 bool
 TextureParent::Init(const SurfaceDescriptor& aSharedData,
                     const LayersBackend& aBackend,
                     const TextureFlags& aFlags)
 {
   mTextureHost = TextureHost::Create(aSharedData,
-                                     mCompositableManager,
+                                     mSurfaceAllocator,
                                      aBackend,
                                      aFlags);
   if (mTextureHost) {
     mTextureHost->mActor = this;
     if (aFlags & TextureFlags::RECYCLE) {
       mWaitForClientRecycle = mTextureHost;
       RECYCLE_LOG("Setup recycling for tile %p\n", this);
     }
--- a/gfx/layers/composite/TextureHost.h
+++ b/gfx/layers/composite/TextureHost.h
@@ -36,16 +36,17 @@ namespace ipc {
 class Shmem;
 } // namespace ipc
 
 namespace layers {
 
 class BufferDescriptor;
 class Compositor;
 class CompositableParentManager;
+class CompositorBridgeParent;
 class SurfaceDescriptor;
 class ISurfaceAllocator;
 class TextureHostOGL;
 class TextureSourceOGL;
 class TextureSourceD3D9;
 class TextureSourceD3D11;
 class TextureSourceBasic;
 class DataTextureSource;
@@ -473,17 +474,17 @@ public:
   /**
    * Allocate and deallocate a TextureParent actor.
    *
    * TextureParent< is an implementation detail of TextureHost that is not
    * exposed to the rest of the code base. CreateIPDLActor and DestroyIPDLActor
    * are for use with the managing IPDL protocols only (so that they can
    * implement AllocPTextureParent and DeallocPTextureParent).
    */
-  static PTextureParent* CreateIPDLActor(CompositableParentManager* aManager,
+  static PTextureParent* CreateIPDLActor(ISurfaceAllocator* aAllocator,
                                          const SurfaceDescriptor& aSharedData,
                                          LayersBackend aLayersBackend,
                                          TextureFlags aFlags);
   static bool DestroyIPDLActor(PTextureParent* actor);
 
   /**
    * Destroy the TextureChild/Parent pair.
    */
--- a/gfx/layers/ipc/CompositorBridgeChild.cpp
+++ b/gfx/layers/ipc/CompositorBridgeChild.cpp
@@ -107,16 +107,26 @@ CompositorBridgeChild::Destroy()
   // CompositorBridgeChild before it gets destroyed. It suffices to ensure that
   // events already in the MessageLoop get processed before the
   // CompositorBridgeChild is destroyed, so we add a task to the MessageLoop to
   // handle compositor desctruction.
 
   // From now on we can't send any message message.
   MessageLoop::current()->PostTask(
              NewRunnableFunction(DeferredDestroyCompositor, mCompositorBridgeParent, selfRef));
+
+  const ManagedContainer<PTextureChild>& textures = ManagedPTextureChild();
+  for (auto iter = textures.ConstIter(); !iter.Done(); iter.Next()) {
+    RefPtr<TextureClient> texture = TextureClient::AsTextureClient(iter.Get()->GetKey());
+
+    if (texture) {
+      texture->Destroy();
+    }
+  }
+
 }
 
 // static
 void
 CompositorBridgeChild::ShutDown()
 {
   if (sCompositorBridge) {
     sCompositorBridge->Destroy();
@@ -745,11 +755,26 @@ CompositorBridgeChild::SendUpdateVisible
 {
   MOZ_ASSERT(mCanSend);
   if (!mCanSend) {
     return true;
   }
   return PCompositorBridgeChild::SendUpdateVisibleRegion(aCounter, aGuid, aRegion);
 }
 
+PTextureChild*
+CompositorBridgeChild::AllocPTextureChild(const SurfaceDescriptor&,
+                                          const LayersBackend&,
+                                          const TextureFlags&,
+                                          const uint64_t&)
+{
+  return TextureClient::CreateIPDLActor();
+}
+
+bool
+CompositorBridgeChild::DeallocPTextureChild(PTextureChild* actor)
+{
+  return TextureClient::DestroyIPDLActor(actor);
+}
+
 } // namespace layers
 } // namespace mozilla
 
--- a/gfx/layers/ipc/CompositorBridgeChild.h
+++ b/gfx/layers/ipc/CompositorBridgeChild.h
@@ -91,16 +91,23 @@ public:
   virtual bool
   RecvUpdatePluginConfigurations(const LayoutDeviceIntPoint& aContentOffset,
                                  const LayoutDeviceIntRegion& aVisibleRegion,
                                  nsTArray<PluginWindowData>&& aPlugins) override;
 
   virtual bool
   RecvHideAllPlugins(const uintptr_t& aParentWidget) override;
 
+  virtual PTextureChild* AllocPTextureChild(const SurfaceDescriptor& aSharedData,
+                                            const LayersBackend& aLayersBackend,
+                                            const TextureFlags& aFlags,
+                                            const uint64_t& aId) override;
+
+  virtual bool DeallocPTextureChild(PTextureChild* actor) override;
+
   /**
    * Request that the parent tell us when graphics are ready on GPU.
    * When we get that message, we bounce it to the TabParent via
    * the TabChild
    * @param tabChild The object to bounce the note to.  Non-NULL.
    */
   void RequestNotifyAfterRemotePaint(TabChild* aTabChild);
 
--- a/gfx/layers/ipc/CompositorBridgeParent.cpp
+++ b/gfx/layers/ipc/CompositorBridgeParent.cpp
@@ -708,16 +708,20 @@ CompositorBridgeParent::CompositorBridge
   , mDeferPluginWindows(false)
   , mPluginWindowsHidden(false)
 #endif
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(CompositorThread(),
              "The compositor thread must be Initialized before instanciating a CompositorBridgeParent.");
   MOZ_COUNT_CTOR(CompositorBridgeParent);
+
+  // Always run destructor on the main thread
+  SetMessageLoopToPostDestructionTo(MessageLoop::current());
+
   mCompositorID = 0;
   // FIXME: This holds on the the fact that right now the only thing that
   // can destroy this instance is initialized on the compositor thread after
   // this task has been processed.
   MOZ_ASSERT(CompositorLoop());
   CompositorLoop()->PostTask(NewRunnableFunction(&AddCompositor,
                                                  this, &mCompositorID));
 
@@ -751,16 +755,25 @@ CompositorBridgeParent::RootLayerTreeId(
 {
   return mRootLayerTreeID;
 }
 
 CompositorBridgeParent::~CompositorBridgeParent()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_COUNT_DTOR(CompositorBridgeParent);
+
+  InfallibleTArray<PTextureParent*> textures;
+  ManagedPTextureParent(textures);
+  // We expect all textures to be destroyed by now.
+  MOZ_DIAGNOSTIC_ASSERT(textures.Length() == 0);
+  for (unsigned int i = 0; i < textures.Length(); ++i) {
+    RefPtr<TextureHost> tex = TextureHost::AsTextureHost(textures[i]);
+    tex->DeallocateDeviceData();
+  }
 }
 
 void
 CompositorBridgeParent::ForceIsFirstPaint()
 {
   mCompositionManager->ForceIsFirstPaint();
 }
 
@@ -1894,29 +1907,32 @@ CompositorBridgeParent::RequestNotifyLay
 /**
  * This class handles layer updates pushed directly from child processes to
  * the compositor thread. It's associated with a CompositorBridgeParent on the
  * compositor thread. While it uses the PCompositorBridge protocol to manage
  * these updates, it doesn't actually drive compositing itself. For that it
  * hands off work to the CompositorBridgeParent it's associated with.
  */
 class CrossProcessCompositorBridgeParent final : public PCompositorBridgeParent,
-                                                 public ShadowLayersManager
+                                                 public ShadowLayersManager,
+                                                 public ISurfaceAllocator,
+                                                 public ShmemAllocator
 {
   friend class CompositorBridgeParent;
 
-  NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION(CrossProcessCompositorBridgeParent)
 public:
   explicit CrossProcessCompositorBridgeParent(Transport* aTransport)
     : mTransport(aTransport)
     , mSubprocess(nullptr)
     , mNotifyAfterRemotePaint(false)
     , mDestroyCalled(false)
   {
     MOZ_ASSERT(NS_IsMainThread());
+    // Always run destructor on the main thread
+    SetMessageLoopToPostDestructionTo(MessageLoop::current());
   }
 
   // IToplevelProtocol::CloneToplevel()
   virtual IToplevelProtocol*
   CloneToplevel(const InfallibleTArray<mozilla::ipc::ProtocolFdMapping>& aFds,
                 base::ProcessHandle aPeerProcess,
                 mozilla::ipc::ProtocolCloneContext* aCtx) override;
 
@@ -2029,16 +2045,37 @@ public:
   virtual AsyncCompositionManager* GetCompositionManager(LayerTransactionParent* aParent) override;
   virtual bool RecvRemotePluginsReady()  override { return false; }
   virtual bool RecvAcknowledgeCompositorUpdate(const uint64_t& aLayersId) override;
 
   void DidComposite(uint64_t aId,
                     TimeStamp& aCompositeStart,
                     TimeStamp& aCompositeEnd);
 
+  virtual PTextureParent* AllocPTextureParent(const SurfaceDescriptor& aSharedData,
+                                              const LayersBackend& aLayersBackend,
+                                              const TextureFlags& aFlags,
+                                              const uint64_t& aId) override;
+
+  virtual bool DeallocPTextureParent(PTextureParent* actor) override;
+
+  virtual bool IsSameProcess() const override;
+
+  virtual ShmemAllocator* AsShmemAllocator() override { return this; }
+
+  virtual bool AllocShmem(size_t aSize,
+                          mozilla::ipc::SharedMemory::SharedMemoryType aType,
+                          mozilla::ipc::Shmem* aShmem) override;
+
+  virtual bool AllocUnsafeShmem(size_t aSize,
+                                mozilla::ipc::SharedMemory::SharedMemoryType aType,
+                                mozilla::ipc::Shmem* aShmem) override;
+
+  virtual void DeallocShmem(mozilla::ipc::Shmem& aShmem) override;
+
 protected:
   void OnChannelConnected(int32_t pid) override { mCompositorThreadHolder = sCompositorThreadHolder; }
 private:
   // Private destructor, to discourage deletion outside of Release():
   virtual ~CrossProcessCompositorBridgeParent();
 
   void DeferredDestroy();
 
@@ -2242,16 +2279,59 @@ CompositorBridgeParent::GetIndirectShado
   MonitorAutoLock lock(*sIndirectLayerTreesLock);
   LayerTreeMap::iterator cit = sIndirectLayerTrees.find(aId);
   if (sIndirectLayerTrees.end() == cit) {
     return nullptr;
   }
   return &cit->second;
 }
 
+PTextureParent*
+CompositorBridgeParent::AllocPTextureParent(const SurfaceDescriptor& aSharedData,
+                                            const LayersBackend& aLayersBackend,
+                                            const TextureFlags& aFlags,
+                                            const uint64_t& aId)
+{
+  return TextureHost::CreateIPDLActor(this, aSharedData, aLayersBackend, aFlags);
+}
+
+bool
+CompositorBridgeParent::DeallocPTextureParent(PTextureParent* actor)
+{
+  return TextureHost::DestroyIPDLActor(actor);
+}
+
+bool
+CompositorBridgeParent::AllocShmem(size_t aSize,
+                                   ipc::SharedMemory::SharedMemoryType aType,
+                                   ipc::Shmem* aShmem)
+{
+  return PCompositorBridgeParent::AllocShmem(aSize, aType, aShmem);
+}
+
+bool
+CompositorBridgeParent::AllocUnsafeShmem(size_t aSize,
+                                         ipc::SharedMemory::SharedMemoryType aType,
+                                         ipc::Shmem* aShmem)
+{
+  return PCompositorBridgeParent::AllocUnsafeShmem(aSize, aType, aShmem);
+}
+
+void
+CompositorBridgeParent::DeallocShmem(ipc::Shmem& aShmem)
+{
+  PCompositorBridgeParent::DeallocShmem(aShmem);
+}
+
+bool
+CompositorBridgeParent::IsSameProcess() const
+{
+  return OtherPid() == base::GetCurrentProcId();
+}
+
 bool
 CrossProcessCompositorBridgeParent::RecvNotifyHidden(const uint64_t& id)
 {
   RefPtr<CompositorLRU> lru = CompositorLRU::GetSingleton();
   lru->Add(this, id);
   return true;
 }
 
@@ -2763,10 +2843,74 @@ CrossProcessCompositorBridgeParent::Clon
       // We need to do this for cloned actors, too.
       compositor->OnChannelConnected(base::GetProcId(aPeerProcess));
       return compositor;
     }
   }
   return nullptr;
 }
 
+PTextureParent*
+CrossProcessCompositorBridgeParent::AllocPTextureParent(const SurfaceDescriptor& aSharedData,
+                                                        const LayersBackend& aLayersBackend,
+                                                        const TextureFlags& aFlags,
+                                                        const uint64_t& aId)
+{
+  CompositorBridgeParent::LayerTreeState* state = nullptr;
+
+  LayerTreeMap::iterator itr = sIndirectLayerTrees.find(aId);
+  if (sIndirectLayerTrees.end() != itr) {
+    state = &itr->second;
+  }
+
+  TextureFlags flags = aFlags;
+
+  if (!state || state->mPendingCompositorUpdates) {
+    // The compositor was recreated, and we're receiving layers updates for a
+    // a layer manager that will soon be discarded or invalidated. We can't
+    // return null because this will mess up deserialization later and we'll
+    // kill the content process. Instead, we signal that the underlying
+    // TextureHost should not attempt to access the compositor.
+    flags |= TextureFlags::INVALID_COMPOSITOR;
+  } else if (state->mLayerManager && state->mLayerManager->GetCompositor() &&
+             aLayersBackend != state->mLayerManager->GetCompositor()->GetBackendType()) {
+    gfxDevCrash(gfx::LogReason::PAllocTextureBackendMismatch) << "Texture backend is wrong";
+  }
+
+  return TextureHost::CreateIPDLActor(this, aSharedData, aLayersBackend, aFlags);
+}
+
+bool
+CrossProcessCompositorBridgeParent::DeallocPTextureParent(PTextureParent* actor)
+{
+  return TextureHost::DestroyIPDLActor(actor);
+}
+
+bool
+CrossProcessCompositorBridgeParent::AllocShmem(size_t aSize,
+                                               ipc::SharedMemory::SharedMemoryType aType,
+                                               ipc::Shmem* aShmem)
+{
+  return PCompositorBridgeParent::AllocShmem(aSize, aType, aShmem);
+}
+
+bool
+CrossProcessCompositorBridgeParent::AllocUnsafeShmem(size_t aSize,
+                                                     ipc::SharedMemory::SharedMemoryType aType,
+                                                     ipc::Shmem* aShmem)
+{
+  return PCompositorBridgeParent::AllocUnsafeShmem(aSize, aType, aShmem);
+}
+
+void
+CrossProcessCompositorBridgeParent::DeallocShmem(ipc::Shmem& aShmem)
+{
+  PCompositorBridgeParent::DeallocShmem(aShmem);
+}
+
+bool
+CrossProcessCompositorBridgeParent::IsSameProcess() const
+{
+  return OtherPid() == base::GetCurrentProcId();
+}
+
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/ipc/CompositorBridgeParent.h
+++ b/gfx/layers/ipc/CompositorBridgeParent.h
@@ -24,17 +24,19 @@
 #include "mozilla/Attributes.h"         // for override
 #include "mozilla/Maybe.h"
 #include "mozilla/Monitor.h"            // for Monitor
 #include "mozilla/RefPtr.h"             // for RefPtr
 #include "mozilla/TimeStamp.h"          // for TimeStamp
 #include "mozilla/dom/ipc/IdType.h"
 #include "mozilla/gfx/Point.h"          // for IntSize
 #include "mozilla/ipc/ProtocolUtils.h"
+#include "mozilla/ipc/SharedMemory.h"
 #include "mozilla/layers/GeckoContentController.h"
+#include "mozilla/layers/ISurfaceAllocator.h" // for ShmemAllocator
 #include "mozilla/layers/LayersMessages.h"  // for TargetConfig
 #include "mozilla/layers/PCompositorBridgeParent.h"
 #include "mozilla/layers/ShadowLayersManager.h" // for ShadowLayersManager
 #include "mozilla/layers/APZTestData.h"
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsISupportsImpl.h"
 #include "ThreadSafeRefcountingWithMainThreadDestruction.h"
 #include "mozilla/VsyncDispatcher.h"
@@ -48,16 +50,17 @@ namespace mozilla {
 class CancelableRunnable;
 
 namespace gfx {
 class DrawTarget;
 } // namespace gfx
 
 namespace ipc {
 class GeckoChildProcessHost;
+class Shmem;
 } // namespace ipc
 
 namespace layers {
 
 class APZCTreeManager;
 class AsyncCompositionManager;
 class Compositor;
 class CompositorBridgeParent;
@@ -218,19 +221,20 @@ public:
 
   virtual void ObserveUpdate(uint64_t aLayersId, bool aActive) = 0;
 
 protected:
   virtual ~CompositorUpdateObserver() {}
 };
 
 class CompositorBridgeParent final : public PCompositorBridgeParent,
-                               public ShadowLayersManager
+                                     public ShadowLayersManager,
+                                     public ISurfaceAllocator,
+                                     public ShmemAllocator
 {
-  NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION(CompositorBridgeParent)
   friend class CompositorVsyncScheduler;
 
 public:
   explicit CompositorBridgeParent(widget::CompositorWidgetProxy* aWidget,
                                   CSSToLayoutDeviceScale aScale,
                                   bool aUseAPZ,
                                   bool aUseExternalSurfaceSize = false,
                                   int aSurfaceWidth = -1, int aSurfaceHeight = -1);
@@ -295,16 +299,36 @@ public:
   virtual void FlushApzRepaints(const LayerTransactionParent* aLayerTree) override;
   virtual void GetAPZTestData(const LayerTransactionParent* aLayerTree,
                               APZTestData* aOutData) override;
   virtual void SetConfirmedTargetAPZC(const LayerTransactionParent* aLayerTree,
                                       const uint64_t& aInputBlockId,
                                       const nsTArray<ScrollableLayerGuid>& aTargets) override;
   virtual AsyncCompositionManager* GetCompositionManager(LayerTransactionParent* aLayerTree) override { return mCompositionManager; }
 
+  virtual PTextureParent* AllocPTextureParent(const SurfaceDescriptor& aSharedData,
+                                              const LayersBackend& aLayersBackend,
+                                              const TextureFlags& aFlags,
+                                              const uint64_t& aId) override;
+  virtual bool DeallocPTextureParent(PTextureParent* actor) override;
+
+  virtual bool IsSameProcess() const override;
+
+  virtual ShmemAllocator* AsShmemAllocator() override { return this; }
+
+  virtual bool AllocShmem(size_t aSize,
+                          mozilla::ipc::SharedMemory::SharedMemoryType aType,
+                          mozilla::ipc::Shmem* aShmem) override;
+
+  virtual bool AllocUnsafeShmem(size_t aSize,
+                                mozilla::ipc::SharedMemory::SharedMemoryType aType,
+                                mozilla::ipc::Shmem* aShmem) override;
+
+  virtual void DeallocShmem(mozilla::ipc::Shmem& aShmem) override;
+
   /**
    * Request that the compositor be recreated due to a shared device reset.
    * This must be called on the main thread, and blocks until a task posted
    * to the compositor thread has completed.
    *
    * Note that this posts a task directly, rather than using synchronous
    * IPDL, and waits on a monitor notification from the compositor thread.
    * We do this as a best-effort attempt to jump any IPDL messages that
--- a/gfx/layers/ipc/LayerTransactionChild.cpp
+++ b/gfx/layers/ipc/LayerTransactionChild.cpp
@@ -32,25 +32,16 @@ LayerTransactionChild::Destroy()
   // under Send__delete__() call, this function is called from
   // ShadowLayerForwarder's destructor.
   // When it happens, IPCOpen() is still true.
   // See bug 1004191.
   mDestroyed = true;
   MOZ_ASSERT(0 == ManagedPLayerChild().Count(),
              "layers should have been cleaned up by now");
 
-  const ManagedContainer<PTextureChild>& textures = ManagedPTextureChild();
-  for (auto iter = textures.ConstIter(); !iter.Done(); iter.Next()) {
-    RefPtr<TextureClient> texture = TextureClient::AsTextureClient(iter.Get()->GetKey());
-
-    if (texture) {
-      texture->Destroy();
-    }
-  }
-
   SendShutdown();
 }
 
 
 PLayerChild*
 LayerTransactionChild::AllocPLayerChild()
 {
   // we always use the "power-user" ctor
@@ -122,25 +113,10 @@ LayerTransactionChild::ActorDestroy(Acto
   // shutdown. Its better just to crash here. On desktop though, we have a chance
   // of recovering.
   if (why == AbnormalShutdown) {
     NS_RUNTIMEABORT("ActorDestroy by IPC channel failure at LayerTransactionChild");
   }
 #endif
 }
 
-PTextureChild*
-LayerTransactionChild::AllocPTextureChild(const SurfaceDescriptor&,
-                                          const LayersBackend&,
-                                          const TextureFlags&)
-{
-  MOZ_ASSERT(!mDestroyed);
-  return TextureClient::CreateIPDLActor();
-}
-
-bool
-LayerTransactionChild::DeallocPTextureChild(PTextureChild* actor)
-{
-  return TextureClient::DestroyIPDLActor(actor);
-}
-
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/ipc/LayerTransactionChild.h
+++ b/gfx/layers/ipc/LayerTransactionChild.h
@@ -60,21 +60,16 @@ protected:
   ~LayerTransactionChild() { }
 
   virtual PLayerChild* AllocPLayerChild() override;
   virtual bool DeallocPLayerChild(PLayerChild* actor) override;
 
   virtual PCompositableChild* AllocPCompositableChild(const TextureInfo& aInfo) override;
   virtual bool DeallocPCompositableChild(PCompositableChild* actor) override;
 
-  virtual PTextureChild* AllocPTextureChild(const SurfaceDescriptor& aSharedData,
-                                            const LayersBackend& aLayersBackend,
-                                            const TextureFlags& aFlags) override;
-  virtual bool DeallocPTextureChild(PTextureChild* actor) override;
-
   virtual bool
   RecvParentAsyncMessages(InfallibleTArray<AsyncParentMessageData>&& aMessages) override;
 
   virtual void ActorDestroy(ActorDestroyReason why) override;
 
   void AddIPDLReference() {
     MOZ_ASSERT(mIPCOpen == false);
     mIPCOpen = true;
--- a/gfx/layers/ipc/LayerTransactionParent.cpp
+++ b/gfx/layers/ipc/LayerTransactionParent.cpp
@@ -173,24 +173,16 @@ void
 LayerTransactionParent::Destroy()
 {
   const ManagedContainer<PLayerParent>& layers = ManagedPLayerParent();
   for (auto iter = layers.ConstIter(); !iter.Done(); iter.Next()) {
     ShadowLayerParent* slp =
       static_cast<ShadowLayerParent*>(iter.Get()->GetKey());
     slp->Destroy();
   }
-  InfallibleTArray<PTextureParent*> textures;
-  ManagedPTextureParent(textures);
-  // We expect all textures to be destroyed by now.
-  MOZ_DIAGNOSTIC_ASSERT(textures.Length() == 0);
-  for (unsigned int i = 0; i < textures.Length(); ++i) {
-    RefPtr<TextureHost> tex = TextureHost::AsTextureHost(textures[i]);
-    tex->DeallocateDeviceData();
-  }
   mDestroyed = true;
 }
 
 bool
 LayerTransactionParent::RecvUpdateNoSwap(InfallibleTArray<Edit>&& cset,
                                          InfallibleTArray<OpDestroy>&& aToDestroy,
                                          const uint64_t& aTransactionId,
                                          const TargetConfig& targetConfig,
@@ -955,43 +947,16 @@ LayerTransactionParent::AllocPCompositab
 }
 
 bool
 LayerTransactionParent::DeallocPCompositableParent(PCompositableParent* aActor)
 {
   return CompositableHost::DestroyIPDLActor(aActor);
 }
 
-PTextureParent*
-LayerTransactionParent::AllocPTextureParent(const SurfaceDescriptor& aSharedData,
-                                            const LayersBackend& aLayersBackend,
-                                            const TextureFlags& aFlags)
-{
-  TextureFlags flags = aFlags;
-
-  if (mPendingCompositorUpdates) {
-    // The compositor was recreated, and we're receiving layers updates for a
-    // a layer manager that will soon be discarded or invalidated. We can't
-    // return null because this will mess up deserialization later and we'll
-    // kill the content process. Instead, we signal that the underlying
-    // TextureHost should not attempt to access the compositor.
-    flags |= TextureFlags::INVALID_COMPOSITOR;
-  } else if (aLayersBackend != mLayerManager->GetCompositor()->GetBackendType()) {
-    gfxDevCrash(gfx::LogReason::PAllocTextureBackendMismatch) << "Texture backend is wrong";
-  }
-
-  return TextureHost::CreateIPDLActor(this, aSharedData, aLayersBackend, flags);
-}
-
-bool
-LayerTransactionParent::DeallocPTextureParent(PTextureParent* actor)
-{
-  return TextureHost::DestroyIPDLActor(actor);
-}
-
 bool
 LayerTransactionParent::RecvChildAsyncMessages(InfallibleTArray<AsyncChildMessageData>&& aMessages)
 {
   AutoLayerTransactionParentAsyncMessageSender autoAsyncMessageSender(this);
 
   for (AsyncChildMessageArray::index_type i = 0; i < aMessages.Length(); ++i) {
     const AsyncChildMessageData& message = aMessages[i];
 
--- a/gfx/layers/ipc/LayerTransactionParent.h
+++ b/gfx/layers/ipc/LayerTransactionParent.h
@@ -154,21 +154,16 @@ protected:
                                           nsTArray<ScrollableLayerGuid>&& aTargets) override;
 
   virtual PLayerParent* AllocPLayerParent() override;
   virtual bool DeallocPLayerParent(PLayerParent* actor) override;
 
   virtual PCompositableParent* AllocPCompositableParent(const TextureInfo& aInfo) override;
   virtual bool DeallocPCompositableParent(PCompositableParent* actor) override;
 
-  virtual PTextureParent* AllocPTextureParent(const SurfaceDescriptor& aSharedData,
-                                              const LayersBackend& aLayersBackend,
-                                              const TextureFlags& aFlags) override;
-  virtual bool DeallocPTextureParent(PTextureParent* actor) override;
-
   virtual bool
   RecvChildAsyncMessages(InfallibleTArray<AsyncChildMessageData>&& aMessages) override;
 
   virtual void ActorDestroy(ActorDestroyReason why) override;
 
   bool Attach(ShadowLayerParent* aLayerParent,
               CompositableHost* aCompositable,
               bool aIsAsyncVideo);
--- a/gfx/layers/ipc/PCompositorBridge.ipdl
+++ b/gfx/layers/ipc/PCompositorBridge.ipdl
@@ -3,18 +3,21 @@
  */
 /* 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 LayersSurfaces;
 include LayersMessages;
 include protocol PBrowser;
+include protocol PCompositable;
+include protocol PImageContainer;
 include protocol PLayer;
 include protocol PLayerTransaction;
+include protocol PTexture;
 include "mozilla/GfxMessageUtils.h";
 
 using struct mozilla::null_t from "ipc/IPCMessageUtils.h";
 using struct mozilla::layers::TextureFactoryIdentifier from "mozilla/layers/CompositorTypes.h";
 using struct mozilla::layers::FrameMetrics from "FrameMetrics.h";
 using mozilla::layers::FrameMetrics::ViewID from "FrameMetrics.h";
 using mozilla::layers::MaybeZoomConstraints from "FrameMetrics.h";
 using struct mozilla::layers::ScrollableLayerGuid from "FrameMetrics.h";
@@ -23,30 +26,32 @@ using mozilla::layers::TouchBehaviorFlag
 using mozilla::CrossProcessMutexHandle from "mozilla/ipc/CrossProcessMutex.h";
 using mozilla::ipc::SharedMemoryBasic::Handle from "mozilla/ipc/SharedMemoryBasic.h";
 using mozilla::CSSIntRegion from "Units.h";
 using mozilla::LayoutDeviceIntPoint from "Units.h";
 using mozilla::LayoutDeviceIntRegion from "Units.h";
 using mozilla::VisibilityCounter from "VisibilityIPC.h";
 using class mozilla::TimeStamp from "mozilla/TimeStamp.h";
 using class mozilla::layers::FrameUniformityData from "mozilla/layers/FrameUniformityData.h";
+using mozilla::layers::TextureFlags from "mozilla/layers/CompositorTypes.h";
 
 namespace mozilla {
 namespace layers {
 
 
 /**
  * The PCompositorBridge protocol is used to manage communication between
  * the main thread and the compositor thread context. It's primary
  * purpose is to manage the PLayerTransaction sub protocol.
  */
 sync protocol PCompositorBridge
 {
   // A Compositor manages a single Layer Manager (PLayerTransaction)
   manages PLayerTransaction;
+  manages PTexture;
 
 child:
   // The child should invalidate retained layers. This is used for local
   // compositor device resets, such as in CompositorD3D9, and ensures that
   // TextureSources are recreated.
   async InvalidateLayers(uint64_t layersId);
 
   // The compositor type or device has changed, and a new texture factory
@@ -182,16 +187,18 @@ parent:
   // The child sends a region containing rects associated with the provided
   // scrollable layer GUID that the child considers visible in the sense
   // specified by |counter|.
   // We visualize this information in the APZ minimap.
   async UpdateVisibleRegion(VisibilityCounter counter,
                             ScrollableLayerGuid guid,
                             CSSIntRegion region);
 
+  async PTexture(SurfaceDescriptor aSharedData, LayersBackend aBackend, TextureFlags aTextureFlags, uint64_t id);
+
 child:
   // Send back Compositor Frame Metrics from APZCs so tiled layers can
   // update progressively.
   async SharedCompositorFrameMetrics(Handle metrics, CrossProcessMutexHandle mutex, uint64_t aLayersId, uint32_t aAPZCId);
   async ReleaseSharedCompositorFrameMetrics(ViewID aId, uint32_t aAPZCId);
 };
 
 } // layers
--- a/gfx/layers/ipc/PLayerTransaction.ipdl
+++ b/gfx/layers/ipc/PLayerTransaction.ipdl
@@ -12,17 +12,16 @@ include protocol PCompositorBridge;
 include protocol PLayer;
 include protocol PRenderFrame;
 include protocol PTexture;
 
 include "mozilla/GfxMessageUtils.h";
 
 using struct mozilla::layers::TextureInfo from "mozilla/layers/CompositorTypes.h";
 using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
-using mozilla::layers::TextureFlags from "mozilla/layers/CompositorTypes.h";
 using class mozilla::layers::APZTestData from "mozilla/layers/APZTestData.h";
 using mozilla::layers::FrameMetrics::ViewID from "FrameMetrics.h";
 using struct mozilla::layers::ScrollableLayerGuid from "FrameMetrics.h";
 using mozilla::layers::LayersBackend from "mozilla/layers/LayersTypes.h";
 
 /**
  * The layers protocol is spoken between thread contexts that manage
  * layer (sub)trees.  The protocol comprises atomically publishing
@@ -38,25 +37,23 @@ union MaybeTransform {
   Matrix4x4;
   void_t;
 };
 
 sync protocol PLayerTransaction {
   manager PCompositorBridge;
   manages PLayer;
   manages PCompositable;
-  manages PTexture;
 
 child:
   async ParentAsyncMessages(AsyncParentMessageData[] aMessages);
 
 parent:
   async PLayer();
   async PCompositable(TextureInfo aTextureInfo);
-  async PTexture(SurfaceDescriptor aSharedData, LayersBackend aBackend, TextureFlags aTextureFlags);
 
   // The isFirstPaint flag can be used to indicate that this is the first update
   // for a particular document.
   sync Update(Edit[] cset, OpDestroy[] toDestroy,
               uint64_t id, TargetConfig targetConfig,
               PluginWindowData[] plugins, bool isFirstPaint,
               bool scheduleComposite, uint32_t paintSequenceNumber,
               bool isRepeatTransaction, TimeStamp transactionStart,
--- a/gfx/layers/ipc/PTexture.ipdl
+++ b/gfx/layers/ipc/PTexture.ipdl
@@ -2,30 +2,31 @@
  * vim: sw=2 ts=8 et :
  */
 /* 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 LayersSurfaces;
 include protocol PLayerTransaction;
+include protocol PCompositorBridge;
 include protocol PImageBridge;
 include "mozilla/GfxMessageUtils.h";
 
 using struct mozilla::layers::FrameMetrics from "FrameMetrics.h";
 using mozilla::layers::TextureFlags from "mozilla/layers/CompositorTypes.h";
 
 namespace mozilla {
 namespace layers {
 
 /**
  * PTexture is the IPDL glue between a TextureClient and a TextureHost.
  */
 sync protocol PTexture {
-    manager PImageBridge or PLayerTransaction;
+    manager PImageBridge or PCompositorBridge;
 
 child:
     async __delete__();
 
     async CompositorRecycle();
 
 parent:
 
--- a/gfx/layers/ipc/ShadowLayers.cpp
+++ b/gfx/layers/ipc/ShadowLayers.cpp
@@ -16,16 +16,17 @@
 #include "gfx2DGlue.h"                  // for Moz2D transition helpers
 #include "gfxPlatform.h"                // for gfxImageFormat, gfxPlatform
 //#include "gfxSharedImageSurface.h"      // for gfxSharedImageSurface
 #include "ipc/IPCMessageUtils.h"        // for gfxContentType, null_t
 #include "IPDLActor.h"
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
 #include "mozilla/gfx/Point.h"          // for IntSize
 #include "mozilla/layers/CompositableClient.h"  // for CompositableClient, etc
+#include "mozilla/layers/CompositorBridgeChild.h"
 #include "mozilla/layers/ImageDataSerializer.h"
 #include "mozilla/layers/LayersMessages.h"  // for Edit, etc
 #include "mozilla/layers/LayersSurfaces.h"  // for SurfaceDescriptor, etc
 #include "mozilla/layers/LayersTypes.h"  // for MOZ_LAYERS_LOG
 #include "mozilla/layers/LayerTransactionChild.h"
 #include "mozilla/layers/SharedBufferManagerChild.h"
 #include "ShadowLayerUtils.h"
 #include "mozilla/layers/TextureClient.h"  // for TextureClient
@@ -1071,20 +1072,21 @@ void ShadowLayerForwarder::AttachAsyncCo
 }
 
 PTextureChild*
 ShadowLayerForwarder::CreateTexture(const SurfaceDescriptor& aSharedData,
                                     LayersBackend aLayersBackend,
                                     TextureFlags aFlags)
 {
   if (!HasShadowManager() ||
-      !mShadowManager->IPCOpen()) {
+      !mShadowManager->IPCOpen() ||
+      !mShadowManager->Manager()) {
     return nullptr;
   }
-  return mShadowManager->SendPTextureConstructor(aSharedData, aLayersBackend, aFlags);
+  return mShadowManager->Manager()->SendPTextureConstructor(aSharedData, aLayersBackend, aFlags, mShadowManager->GetId());
 }
 
 
 void ShadowLayerForwarder::SetShadowManager(PLayerTransactionChild* aShadowManager)
 {
   mShadowManager = static_cast<LayerTransactionChild*>(aShadowManager);
   mShadowManager->SetForwarder(this);
 }
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -123,16 +123,17 @@ static const uint32_t kDefaultGlyphCache
 
 #if !defined(USE_SKIA) || !defined(USE_SKIA_GPU)
 class mozilla::gl::SkiaGLGlue : public GenericAtomicRefCounted {
 };
 #endif
 
 #include "mozilla/Preferences.h"
 #include "mozilla/Assertions.h"
+#include "mozilla/Atomics.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/Mutex.h"
 
 #include "nsAlgorithm.h"
 #include "nsIGfxInfo.h"
 #include "nsIXULRuntime.h"
 #include "VsyncSource.h"
 #include "SoftwareVsyncSource.h"
@@ -2057,22 +2058,22 @@ gfxPlatform::OptimalFormatForContent(gfx
 /**
  * There are a number of layers acceleration (or layers in general) preferences
  * that should be consistent for the lifetime of the application (bug 840967).
  * As such, we will evaluate them all as soon as one of them is evaluated
  * and remember the values.  Changing these preferences during the run will
  * not have any effect until we restart.
  */
 bool gANGLESupportsD3D11 = false;
-static bool sLayersSupportsHardwareVideoDecoding = false;
+static mozilla::Atomic<bool> sLayersSupportsHardwareVideoDecoding(false);
 static bool sLayersHardwareVideoDecodingFailed = false;
 static bool sBufferRotationCheckPref = true;
 static bool sPrefBrowserTabsRemoteAutostart = false;
 
-static bool sLayersAccelerationPrefsInitialized = false;
+static mozilla::Atomic<bool> sLayersAccelerationPrefsInitialized(false);
 
 void
 gfxPlatform::InitAcceleration()
 {
   if (sLayersAccelerationPrefsInitialized) {
     return;
   }
 
--- a/gfx/thebes/gfxWindowsPlatform.h
+++ b/gfx/thebes/gfxWindowsPlatform.h
@@ -222,17 +222,17 @@ public:
       HRESULT& aResOut);
 
     bool DwmCompositionEnabled();
 
     mozilla::layers::ReadbackManagerD3D11* GetReadbackManager();
 
     static bool IsOptimus();
 
-    bool IsWARP() { return mIsWARP; }
+    bool IsWARP() const { return mIsWARP; }
 
     // Returns whether the compositor's D3D11 device supports texture sharing.
     bool CompositorD3D11TextureSharingWorks() const {
       return mCompositorD3D11TextureSharingWorks;
     }
 
     bool SupportsApzWheelInput() const override {
       return true;
@@ -325,20 +325,20 @@ private:
     DWRITE_MEASURING_MODE mMeasuringMode;
 
     mozilla::Mutex mDeviceLock;
     RefPtr<IDXGIAdapter1> mAdapter;
     RefPtr<ID3D11Device> mD3D11Device;
     RefPtr<ID3D11Device> mD3D11ContentDevice;
     RefPtr<ID3D11Device> mD3D11ImageBridgeDevice;
     RefPtr<mozilla::layers::DeviceManagerD3D9> mDeviceManager;
-    bool mIsWARP;
+    mozilla::Atomic<bool> mIsWARP;
     bool mHasDeviceReset;
     bool mHasFakeDeviceReset;
-    bool mCompositorD3D11TextureSharingWorks;
+    mozilla::Atomic<bool> mCompositorD3D11TextureSharingWorks;
     mozilla::Atomic<bool> mHasD3D9DeviceReset;
     DeviceResetReason mDeviceResetReason;
 
     RefPtr<mozilla::layers::ReadbackManagerD3D11> mD3D11ReadbackManager;
 
     nsTArray<D3D_FEATURE_LEVEL> mFeatureLevels;
 };
 
--- a/js/public/Utility.h
+++ b/js/public/Utility.h
@@ -175,16 +175,23 @@ static inline bool ShouldFailWithOOM() {
 # endif /* DEBUG || JS_OOM_BREAKPOINT */
 
 namespace js {
 
 /* Disable OOM testing in sections which are not OOM safe. */
 struct MOZ_RAII AutoEnterOOMUnsafeRegion
 {
     MOZ_NORETURN MOZ_COLD void crash(const char* reason);
+    MOZ_NORETURN MOZ_COLD void crash(size_t size, const char* reason);
+
+    using AnnotateOOMAllocationSizeCallback = void(*)(size_t);
+    static AnnotateOOMAllocationSizeCallback annotateOOMSizeCallback;
+    static void setAnnotateOOMAllocationSizeCallback(AnnotateOOMAllocationSizeCallback callback) {
+        annotateOOMSizeCallback = callback;
+    }
 
 #if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
     AutoEnterOOMUnsafeRegion()
       : oomEnabled_(oom::IsThreadSimulatingOOM() && oom::maxAllocations != UINT64_MAX),
         oomAfter_(0)
     {
         if (oomEnabled_) {
             MOZ_ALWAYS_TRUE(owner_.compareExchange(nullptr, this));
--- a/js/src/asmjs/Wasm.cpp
+++ b/js/src/asmjs/Wasm.cpp
@@ -280,17 +280,17 @@ DecodeExpr(FunctionDecoder& f)
         return f.iter().readEnd(nullptr, nullptr, nullptr);
       case Expr::I32Clz:
       case Expr::I32Ctz:
       case Expr::I32Popcnt:
         return f.iter().readUnary(ValType::I32, nullptr);
       case Expr::I64Clz:
       case Expr::I64Ctz:
       case Expr::I64Popcnt:
-        return f.iter().notYetImplemented("i64") &&
+        return f.checkI64Support() &&
                f.iter().readUnary(ValType::I64, nullptr);
       case Expr::F32Abs:
       case Expr::F32Neg:
       case Expr::F32Ceil:
       case Expr::F32Floor:
       case Expr::F32Sqrt:
         return f.iter().readUnary(ValType::F32, nullptr);
       case Expr::F32Trunc:
@@ -393,18 +393,16 @@ DecodeExpr(FunctionDecoder& f)
       case Expr::F64Lt:
       case Expr::F64Le:
       case Expr::F64Gt:
       case Expr::F64Ge:
         return f.iter().readComparison(ValType::F64, nullptr, nullptr);
       case Expr::I32Eqz:
         return f.iter().readConversion(ValType::I32, ValType::I32, nullptr);
       case Expr::I64Eqz:
-        return f.checkI64Support() &&
-               f.iter().readConversion(ValType::I64, ValType::I32, nullptr);
       case Expr::I32WrapI64:
         return f.checkI64Support() &&
                f.iter().readConversion(ValType::I64, ValType::I32, nullptr);
       case Expr::I32TruncSF32:
       case Expr::I32TruncUF32:
       case Expr::I32ReinterpretF32:
         return f.iter().readConversion(ValType::F32, ValType::I32, nullptr);
       case Expr::I32TruncSF64:
--- a/js/src/asmjs/WasmBinaryIterator.cpp
+++ b/js/src/asmjs/WasmBinaryIterator.cpp
@@ -56,17 +56,16 @@ wasm::Classify(Expr expr)
       case Expr::Nop:
         return ExprKind::Nullary;
       case Expr::I32Clz:
       case Expr::I32Ctz:
       case Expr::I32Popcnt:
       case Expr::I64Clz:
       case Expr::I64Ctz:
       case Expr::I64Popcnt:
-      case Expr::I64Eqz:
       case Expr::F32Abs:
       case Expr::F32Neg:
       case Expr::F32Ceil:
       case Expr::F32Floor:
       case Expr::F32Sqrt:
       case Expr::F64Abs:
       case Expr::F64Neg:
       case Expr::F64Ceil:
@@ -201,16 +200,17 @@ wasm::Classify(Expr expr)
       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:
--- a/js/src/asmjs/WasmIonCompile.cpp
+++ b/js/src/asmjs/WasmIonCompile.cpp
@@ -2906,16 +2906,24 @@ EmitExpr(FunctionCompiler& f)
         return EmitBitwise<MLsh>(f, ValType::I64, MIRType::Int64);
       case Expr::I64ShrS:
         return EmitBitwise<MRsh>(f, ValType::I64, MIRType::Int64);
       case Expr::I64ShrU:
         return EmitBitwise<MUrsh>(f, ValType::I64, MIRType::Int64);
       case Expr::I64Rotr:
       case Expr::I64Rotl:
         return EmitRotate(f, ValType::I64, expr == Expr::I64Rotl);
+      case Expr::I64Eqz:
+        return EmitConversion<MNot>(f, ValType::I64, ValType::I32);
+      case Expr::I64Clz:
+        return EmitUnary<MClz>(f, ValType::I64);
+      case Expr::I64Ctz:
+        return EmitUnary<MCtz>(f, ValType::I64);
+      case Expr::I64Popcnt:
+        return EmitUnary<MPopcnt>(f, ValType::I64);
 
       // F32
       case Expr::F32Const: {
         float f32;
         if (!f.iter().readF32Const(&f32))
             return false;
 
         f.iter().setResult(f.constant(Float32Value(f32), MIRType::Float32));
@@ -3187,20 +3195,16 @@ EmitExpr(FunctionCompiler& f)
       case Expr::I64Load8U:
       case Expr::I64Load16U:
       case Expr::I64Load32U:
       case Expr::I64Load:
       case Expr::I64Store8:
       case Expr::I64Store16:
       case Expr::I64Store32:
       case Expr::I64Store:
-      case Expr::I64Clz:
-      case Expr::I64Ctz:
-      case Expr::I64Popcnt:
-      case Expr::I64Eqz:
       case Expr::CurrentMemory:
       case Expr::GrowMemory:
         MOZ_CRASH("NYI");
       case Expr::Limit:;
     }
 
     MOZ_CRASH("unexpected wasm opcode");
 }
--- a/js/src/asmjs/WasmTextToBinary.cpp
+++ b/js/src/asmjs/WasmTextToBinary.cpp
@@ -387,32 +387,39 @@ class WasmAstReturn : public WasmAstExpr
         maybeExpr_(maybeExpr)
     {}
     WasmAstExpr* maybeExpr() const { return maybeExpr_; }
 };
 
 class WasmAstIf : public WasmAstExpr
 {
     WasmAstExpr* cond_;
-    WasmAstExpr* thenBranch_;
-    WasmAstExpr* elseBranch_;
+    WasmName thenName_;
+    WasmAstExprVector thenExprs_;
+    WasmName elseName_;
+    WasmAstExprVector elseExprs_;
 
   public:
     static const WasmAstExprKind Kind = WasmAstExprKind::If;
-    WasmAstIf(WasmAstExpr* cond, WasmAstExpr* thenBranch, WasmAstExpr* elseBranch)
+    WasmAstIf(WasmAstExpr* cond, WasmName thenName, WasmAstExprVector&& thenExprs,
+              WasmName elseName, WasmAstExprVector&& elseExprs)
       : WasmAstExpr(Kind),
         cond_(cond),
-        thenBranch_(thenBranch),
-        elseBranch_(elseBranch)
+        thenName_(thenName),
+        thenExprs_(Move(thenExprs)),
+        elseName_(elseName),
+        elseExprs_(Move(elseExprs))
     {}
 
     WasmAstExpr& cond() const { return *cond_; }
-    WasmAstExpr& thenBranch() const { return *thenBranch_; }
-    bool hasElse() const { return !!elseBranch_; }
-    WasmAstExpr& elseBranch() const { MOZ_ASSERT(hasElse()); return *elseBranch_; }
+    const WasmAstExprVector& thenExprs() const { return thenExprs_; }
+    bool hasElse() const { return elseExprs_.length(); }
+    const WasmAstExprVector& elseExprs() const { MOZ_ASSERT(hasElse()); return elseExprs_; }
+    WasmName thenName() const { return thenName_; }
+    WasmName elseName() const { return elseName_; }
 };
 
 class WasmAstLoadStoreAddress
 {
     WasmAstExpr* base_;
     int32_t flags_;
     int32_t offset_;
 
@@ -513,26 +520,26 @@ class WasmAstFunc : public WasmAstNode
     WasmName name() const { return name_; }
 };
 
 class WasmAstImport : public WasmAstNode
 {
     WasmName name_;
     WasmName module_;
     WasmName func_;
-    uint32_t sigIndex_;
+    WasmRef  sig_;
 
   public:
-    WasmAstImport(WasmName name, WasmName module, WasmName func, uint32_t sigIndex)
-      : name_(name), module_(module), func_(func), sigIndex_(sigIndex)
+    WasmAstImport(WasmName name, WasmName module, WasmName func, WasmRef sig)
+      : name_(name), module_(module), func_(func), sig_(sig)
     {}
     WasmName name() const { return name_; }
     WasmName module() const { return module_; }
     WasmName func() const { return func_; }
-    uint32_t sigIndex() const { return sigIndex_; }
+    WasmRef& sig() { return sig_; }
 };
 
 enum class WasmAstExportKind { Func, Memory };
 
 class WasmAstExport : public WasmAstNode
 {
     WasmName name_;
     WasmAstExportKind kind_;
@@ -801,16 +808,17 @@ class WasmToken
         BrTable,
         Call,
         CallImport,
         CallIndirect,
         CloseParen,
         ComparisonOpcode,
         Const,
         ConversionOpcode,
+        Else,
         EndOfFile,
         Equal,
         Error,
         Export,
         Float,
         Func,
         GetLocal,
         If,
@@ -832,16 +840,17 @@ class WasmToken
         Result,
         Return,
         Segment,
         SetLocal,
         Store,
         Table,
         TernaryOpcode,
         Text,
+        Then,
         Type,
         UnaryOpcode,
         Unreachable,
         ValueType
     };
   private:
     Kind kind_;
     const char16_t* begin_;
@@ -1470,16 +1479,18 @@ WasmTokenStream::next()
                 return WasmToken(WasmToken::CallIndirect, begin, cur_);
             if (consume(MOZ_UTF16("_import")))
                 return WasmToken(WasmToken::CallImport, begin, cur_);
             return WasmToken(WasmToken::Call, begin, cur_);
         }
         break;
 
       case 'e':
+        if (consume(MOZ_UTF16("else")))
+            return WasmToken(WasmToken::Else, begin, cur_);
         if (consume(MOZ_UTF16("export")))
             return WasmToken(WasmToken::Export, begin, cur_);
         break;
 
       case 'f':
         if (consume(MOZ_UTF16("func")))
             return WasmToken(WasmToken::Func, begin, cur_);
 
@@ -2029,16 +2040,18 @@ WasmTokenStream::next()
             return WasmToken(WasmToken::SetLocal, begin, cur_);
         if (consume(MOZ_UTF16("segment")))
             return WasmToken(WasmToken::Segment, begin, cur_);
         break;
 
       case 't':
         if (consume(MOZ_UTF16("table")))
             return WasmToken(WasmToken::Table, begin, cur_);
+        if (consume(MOZ_UTF16("then")))
+            return WasmToken(WasmToken::Then, begin, cur_);
         if (consume(MOZ_UTF16("type")))
             return WasmToken(WasmToken::Type, begin, cur_);
         break;
 
       case 'u':
         if (consume(MOZ_UTF16("unreachable")))
             return WasmToken(WasmToken::Unreachable, begin, cur_);
         break;
@@ -2094,34 +2107,42 @@ ParseExpr(WasmParseContext& c)
         return nullptr;
 
     if (!c.ts.match(WasmToken::CloseParen, c.error))
         return nullptr;
 
     return expr;
 }
 
+static bool
+ParseExprList(WasmParseContext& c, WasmAstExprVector* exprs)
+{
+    while (c.ts.getIf(WasmToken::OpenParen)) {
+        WasmAstExpr* expr = ParseExprInsideParens(c);
+        if (!expr || !exprs->append(expr))
+            return false;
+        if (!c.ts.match(WasmToken::CloseParen, c.error))
+            return false;
+    }
+    return true;
+}
+
 static WasmAstBlock*
 ParseBlock(WasmParseContext& c, Expr expr)
 {
     WasmAstExprVector exprs(c.lifo);
 
     WasmName breakName = c.ts.getIfName();
 
     WasmName continueName;
     if (expr == Expr::Loop)
         continueName = c.ts.getIfName();
 
-    while (c.ts.getIf(WasmToken::OpenParen)) {
-        WasmAstExpr* expr = ParseExprInsideParens(c);
-        if (!expr || !exprs.append(expr))
-            return nullptr;
-        if (!c.ts.match(WasmToken::CloseParen, c.error))
-            return nullptr;
-    }
+    if (!ParseExprList(c, &exprs))
+        return nullptr;
 
     return new(c.lifo) WasmAstBlock(expr, breakName, continueName, Move(exprs));
 }
 
 static WasmAstBranch*
 ParseBranch(WasmParseContext& c, Expr expr)
 {
     MOZ_ASSERT(expr == Expr::Br || expr == Expr::BrIf);
@@ -2632,30 +2653,50 @@ ParseConversionOperator(WasmParseContext
 
 static WasmAstIf*
 ParseIf(WasmParseContext& c)
 {
     WasmAstExpr* cond = ParseExpr(c);
     if (!cond)
         return nullptr;
 
-    WasmAstExpr* thenBranch = ParseExpr(c);
-    if (!thenBranch)
+    if (!c.ts.match(WasmToken::OpenParen, c.error))
         return nullptr;
 
-    WasmAstExpr* elseBranch = nullptr;
+    WasmName thenName;
+    WasmAstExprVector thenExprs(c.lifo);
+    if (c.ts.getIf(WasmToken::Then)) {
+        thenName = c.ts.getIfName();
+        if (!ParseExprList(c, &thenExprs))
+            return nullptr;
+    } else {
+        WasmAstExpr* thenBranch = ParseExprInsideParens(c);
+        if (!thenBranch || !thenExprs.append(thenBranch))
+            return nullptr;
+    }
+    if (!c.ts.match(WasmToken::CloseParen, c.error))
+        return nullptr;
+
+    WasmName elseName;
+    WasmAstExprVector elseExprs(c.lifo);
     if (c.ts.getIf(WasmToken::OpenParen)) {
-        elseBranch = ParseExprInsideParens(c);
-        if (!elseBranch)
-            return nullptr;
+        if (c.ts.getIf(WasmToken::Else)) {
+            elseName = c.ts.getIfName();
+            if (!ParseExprList(c, &elseExprs))
+                return nullptr;
+        } else {
+            WasmAstExpr* elseBranch = ParseExprInsideParens(c);
+            if (!elseBranch || !elseExprs.append(elseBranch))
+                return nullptr;
+        }
         if (!c.ts.match(WasmToken::CloseParen, c.error))
             return nullptr;
     }
 
-    return new(c.lifo) WasmAstIf(cond, thenBranch, elseBranch);
+    return new(c.lifo) WasmAstIf(cond, thenName, Move(thenExprs), elseName, Move(elseExprs));
 }
 
 static bool
 ParseLoadStoreAddress(WasmParseContext& c, int32_t* offset, uint32_t* alignLog2, WasmAstExpr** base)
 {
     *offset = 0;
     if (c.ts.getIf(WasmToken::Offset)) {
         if (!c.ts.match(WasmToken::Equal, c.error))
@@ -2869,24 +2910,16 @@ ParseExprInsideParens(WasmParseContext& 
         return ParseUnaryOperator(c, token.expr());
       default:
         c.ts.generateError(token, c.error);
         return nullptr;
     }
 }
 
 static bool
-ParseValueType(WasmParseContext& c, WasmAstValTypeVector* vec)
-{
-    WasmToken token;
-    return c.ts.match(WasmToken::ValueType, &token, c.error) &&
-           vec->append(token.valueType());
-}
-
-static bool
 ParseValueTypeList(WasmParseContext& c, WasmAstValTypeVector* vec)
 {
     WasmToken token;
     while (c.ts.getIf(WasmToken::ValueType, &token)) {
         if (!vec->append(token.valueType()))
             return false;
     }
 
@@ -2905,30 +2938,25 @@ ParseResult(WasmParseContext& c, ExprTyp
     if (!c.ts.match(WasmToken::ValueType, &token, c.error))
         return false;
 
     *result = ToExprType(token.valueType());
     return true;
 }
 
 static bool
-ParseLocal(WasmParseContext& c, WasmNameVector* locals, WasmAstValTypeVector* localTypes)
+ParseLocalOrParam(WasmParseContext& c, WasmNameVector* locals, WasmAstValTypeVector* localTypes)
 {
-    return locals->append(c.ts.getIfName()) &&
-           ParseValueType(c, localTypes);
-}
-
-static bool
-ParseParam(WasmParseContext& c, WasmNameVector* locals, WasmAstValTypeVector* args)
-{
-    if (c.ts.peek().kind() == WasmToken::Name)
-        return ParseLocal(c, locals, args);
-
-    return locals->append(WasmName()) &&
-           ParseValueTypeList(c, args);
+    if (c.ts.peek().kind() != WasmToken::Name)
+        return locals->append(WasmName()) && ParseValueTypeList(c, localTypes);
+
+    WasmToken token;
+    return locals->append(c.ts.get().name()) &&
+           c.ts.match(WasmToken::ValueType, &token, c.error) &&
+           localTypes->append(token.valueType());
 }
 
 static WasmAstFunc*
 ParseFunc(WasmParseContext& c, WasmAstModule* module)
 {
     WasmAstValTypeVector vars(c.lifo);
     WasmAstValTypeVector args(c.lifo);
     WasmNameVector locals(c.lifo);
@@ -2951,25 +2979,25 @@ ParseFunc(WasmParseContext& c, WasmAstMo
 
     WasmAstExprVector body(c.lifo);
     ExprType result = ExprType::Void;
 
     while (c.ts.getIf(WasmToken::OpenParen)) {
         WasmToken token = c.ts.get();
         switch (token.kind()) {
           case WasmToken::Local:
-            if (!ParseLocal(c, &locals, &vars))
+            if (!ParseLocalOrParam(c, &locals, &vars))
                 return nullptr;
             break;
           case WasmToken::Param:
             if (!vars.empty()) {
                 c.ts.generateError(token, c.error);
                 return nullptr;
             }
-            if (!ParseParam(c, &locals, &args))
+            if (!ParseLocalOrParam(c, &locals, &args))
                 return nullptr;
             break;
           case WasmToken::Result:
             if (!ParseResult(c, &result))
                 return nullptr;
             break;
           default:
             c.ts.unget(token);
@@ -3090,25 +3118,41 @@ ParseImport(WasmParseContext& c, WasmAst
     WasmToken moduleName;
     if (!c.ts.match(WasmToken::Text, &moduleName, c.error))
         return nullptr;
 
     WasmToken funcName;
     if (!c.ts.match(WasmToken::Text, &funcName, c.error))
         return nullptr;
 
-    WasmAstSig sig(c.lifo);
-    if (!ParseFuncType(c, &sig))
-        return nullptr;
-
-    uint32_t sigIndex;
-    if (!module->declare(Move(sig), &sigIndex))
-        return nullptr;
-
-    return new(c.lifo) WasmAstImport(name, moduleName.text(), funcName.text(), sigIndex);
+    WasmRef sigRef;
+    WasmToken openParen;
+    if (c.ts.getIf(WasmToken::OpenParen, &openParen)) {
+        if (c.ts.getIf(WasmToken::Type)) {
+            if (!c.ts.matchRef(&sigRef, c.error))
+                return nullptr;
+            if (!c.ts.match(WasmToken::CloseParen, c.error))
+                return nullptr;
+        } else {
+            c.ts.unget(openParen);
+        }
+    }
+
+    if (sigRef.isInvalid()) {
+        WasmAstSig sig(c.lifo);
+        if (!ParseFuncType(c, &sig))
+            return nullptr;
+
+        uint32_t sigIndex;
+        if (!module->declare(Move(sig), &sigIndex))
+            return nullptr;
+        sigRef.setIndex(sigIndex);
+    }
+
+    return new(c.lifo) WasmAstImport(name, moduleName.text(), funcName.text(), sigRef);
 }
 
 static WasmAstExport*
 ParseExport(WasmParseContext& c)
 {
     WasmToken name;
     if (!c.ts.match(WasmToken::Text, &name, c.error))
         return nullptr;
@@ -3352,31 +3396,38 @@ class Resolver
 };
 
 } // end anonymous namespace
 
 static bool
 ResolveExpr(Resolver& r, WasmAstExpr& expr);
 
 static bool
+ResolveExprList(Resolver& r, const WasmAstExprVector& v)
+{
+    for (size_t i = 0; i < v.length(); i++) {
+        if (!ResolveExpr(r, *v[i]))
+            return false;
+    }
+    return true;
+}
+
+static bool
 ResolveBlock(Resolver& r, WasmAstBlock& b)
 {
     if (!r.pushTarget(b.breakName()))
         return false;
 
     if (b.expr() == Expr::Loop) {
         if (!r.pushTarget(b.continueName()))
             return false;
     }
 
-    size_t numExprs = b.exprs().length();
-    for (size_t i = 0; i < numExprs; i++) {
-        if (!ResolveExpr(r, *b.exprs()[i]))
-            return false;
-    }
+    if (!ResolveExprList(r, b.exprs()))
+        return false;
 
     if (b.expr() == Expr::Loop)
         r.popTarget(b.continueName());
     r.popTarget(b.breakName());
     return true;
 }
 
 static bool
@@ -3492,25 +3543,28 @@ ResolveConversionOperator(Resolver& r, W
     return ResolveExpr(r, *b.op());
 }
 
 static bool
 ResolveIfElse(Resolver& r, WasmAstIf& i)
 {
     if (!ResolveExpr(r, i.cond()))
         return false;
-    if (!r.pushTarget(WasmName()))
+    if (!r.pushTarget(i.thenName()))
         return false;
-    if (!ResolveExpr(r, i.thenBranch()))
+    if (!ResolveExprList(r, i.thenExprs()))
         return false;
+    r.popTarget(i.thenName());
     if (i.hasElse()) {
-        if (!ResolveExpr(r, i.elseBranch()))
+        if (!r.pushTarget(i.elseName()))
             return false;
+        if (!ResolveExprList(r, i.elseExprs()))
+            return false;
+        r.popTarget(i.elseName());
     }
-    r.popTarget(WasmName());
     return true;
 }
 
 static bool
 ResolveLoadStoreAddress(Resolver& r, const WasmAstLoadStoreAddress &address)
 {
     return ResolveExpr(r, address.base());
 }
@@ -3540,16 +3594,19 @@ ResolveBranchTable(Resolver& r, WasmAstB
     if (!r.resolveBranchTarget(bt.def()))
         return false;
 
     for (WasmRef& elem : bt.table()) {
         if (!r.resolveBranchTarget(elem))
             return false;
     }
 
+    if (bt.maybeValue() && !ResolveExpr(r, *bt.maybeValue()))
+        return false;
+
     return ResolveExpr(r, bt.index());
 }
 
 static bool
 ResolveExpr(Resolver& r, WasmAstExpr& expr)
 {
     switch (expr.kind()) {
       case WasmAstExprKind::Nop:
@@ -3640,16 +3697,18 @@ ResolveModule(LifoAlloc& lifo, WasmAstMo
             if (!r.resolveFunction(ref))
                 return false;
         }
     }
 
     size_t numImports = module->imports().length();
     for (size_t i = 0; i < numImports; i++) {
         WasmAstImport* imp = module->imports()[i];
+        if (!r.resolveSignature(imp->sig()))
+            return false;
         if (!r.registerImportName(imp->name(), i))
             return r.fail("duplicate import");
     }
 
     for (WasmAstExport* export_ : module->exports()) {
         if (export_->kind() != WasmAstExportKind::Func)
             continue;
         if (!r.resolveFunction(export_->func()))
@@ -3666,27 +3725,33 @@ ResolveModule(LifoAlloc& lifo, WasmAstMo
 
 /*****************************************************************************/
 // wasm function body serialization
 
 static bool
 EncodeExpr(Encoder& e, WasmAstExpr& expr);
 
 static bool
+EncodeExprList(Encoder& e, const WasmAstExprVector& v)
+{
+    for (size_t i = 0; i < v.length(); i++) {
+        if (!EncodeExpr(e, *v[i]))
+            return false;
+    }
+    return true;
+}
+
+static bool
 EncodeBlock(Encoder& e, WasmAstBlock& b)
 {
     if (!e.writeExpr(b.expr()))
         return false;
 
-    size_t numExprs = b.exprs().length();
-
-    for (size_t i = 0; i < numExprs; i++) {
-        if (!EncodeExpr(e, *b.exprs()[i]))
-            return false;
-    }
+    if (!EncodeExprList(e, b.exprs()))
+        return false;
 
     if (!e.writeExpr(Expr::End))
         return false;
 
     return true;
 }
 
 static bool
@@ -3840,25 +3905,32 @@ EncodeComparisonOperator(Encoder& e, Was
 static bool
 EncodeConversionOperator(Encoder& e, WasmAstConversionOperator& b)
 {
     return EncodeExpr(e, *b.op()) &&
            e.writeExpr(b.expr());
 }
 
 static bool
-EmitIf(Encoder& e, WasmAstIf& i)
+EncodeIf(Encoder& e, WasmAstIf& i)
 {
-    return EncodeExpr(e, i.cond()) &&
-           e.writeExpr(Expr::If) &&
-           EncodeExpr(e, i.thenBranch()) &&
-           (!i.hasElse() ||
-            (e.writeExpr(Expr::Else) &&
-             EncodeExpr(e, i.elseBranch()))) &&
-           e.writeExpr(Expr::End);
+    if (!EncodeExpr(e, i.cond()) || !e.writeExpr(Expr::If))
+        return false;
+
+    if (!EncodeExprList(e, i.thenExprs()))
+        return false;
+
+    if (i.hasElse()) {
+        if (!e.writeExpr(Expr::Else))
+            return false;
+        if (!EncodeExprList(e, i.elseExprs()))
+            return false;
+    }
+
+    return e.writeExpr(Expr::End);
 }
 
 static bool
 EncodeLoadStoreAddress(Encoder &e, const WasmAstLoadStoreAddress &address)
 {
     return EncodeExpr(e, address.base());
 }
 
@@ -3960,17 +4032,17 @@ EncodeExpr(Encoder& e, WasmAstExpr& expr
         return EncodeComparisonOperator(e, expr.as<WasmAstComparisonOperator>());
       case WasmAstExprKind::Const:
         return EncodeConst(e, expr.as<WasmAstConst>());
       case WasmAstExprKind::ConversionOperator:
         return EncodeConversionOperator(e, expr.as<WasmAstConversionOperator>());
       case WasmAstExprKind::GetLocal:
         return EncodeGetLocal(e, expr.as<WasmAstGetLocal>());
       case WasmAstExprKind::If:
-        return EmitIf(e, expr.as<WasmAstIf>());
+        return EncodeIf(e, expr.as<WasmAstIf>());
       case WasmAstExprKind::Load:
         return EncodeLoad(e, expr.as<WasmAstLoad>());
       case WasmAstExprKind::Return:
         return EncodeReturn(e, expr.as<WasmAstReturn>());
       case WasmAstExprKind::SetLocal:
         return EncodeSetLocal(e, expr.as<WasmAstSetLocal>());
       case WasmAstExprKind::Store:
         return EncodeStore(e, expr.as<WasmAstStore>());
@@ -4053,17 +4125,17 @@ EncodeBytes(Encoder& e, WasmName wasmNam
     TwoByteChars range(wasmName.begin(), wasmName.length());
     UniqueChars utf8(JS::CharsToNewUTF8CharsZ(nullptr, range).c_str());
     return utf8 && e.writeBytes(utf8.get(), strlen(utf8.get()));
 }
 
 static bool
 EncodeImport(Encoder& e, WasmAstImport& imp)
 {
-    if (!e.writeVarU32(imp.sigIndex()))
+    if (!e.writeVarU32(imp.sig().index()))
         return false;
 
     if (!EncodeBytes(e, imp.module()))
         return false;
 
     if (!EncodeBytes(e, imp.func()))
         return false;
 
--- a/js/src/asmjs/WasmTypes.cpp
+++ b/js/src/asmjs/WasmTypes.cpp
@@ -44,17 +44,17 @@ extern MOZ_EXPORT int64_t
 __aeabi_uidivmod(int, int);
 
 }
 #endif
 
 static void
 WasmReportOverRecursed()
 {
-    ReportOverRecursed(JSRuntime::innermostWasmActivation()->cx());
+    ReportOverRecursed(JSRuntime::innermostWasmActivation()->cx(), JSMSG_WASM_OVERRECURSED);
 }
 
 static bool
 WasmHandleExecutionInterrupt()
 {
     return CheckForInterrupt(JSRuntime::innermostWasmActivation()->cx());
 }
 
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -2153,17 +2153,17 @@ js::TenuringTracer::moveToTenured(JSObje
 
     TenuredCell* t = zone->arenas.allocateFromFreeList(dstKind, Arena::thingSize(dstKind));
     if (!t) {
         zone->arenas.checkEmptyFreeList(dstKind);
         AutoMaybeStartBackgroundAllocation maybeStartBackgroundAllocation;
         AutoEnterOOMUnsafeRegion oomUnsafe;
         t = zone->arenas.allocateFromArena(zone, dstKind, maybeStartBackgroundAllocation);
         if (!t)
-            oomUnsafe.crash("Failed to allocate object while tenuring.");
+            oomUnsafe.crash(ChunkSize, "Failed to allocate object while tenuring.");
     }
     JSObject* dst = reinterpret_cast<JSObject*>(t);
     tenuredSize += moveObjectToTenured(dst, src, dstKind);
 
     RelocationOverlay* overlay = RelocationOverlay::fromCell(src);
     overlay->forwardTo(dst);
     insertIntoFixupList(overlay);
 
@@ -2310,17 +2310,17 @@ js::TenuringTracer::moveSlotsToTenured(N
 
     Zone* zone = src->zone();
     size_t count = src->numDynamicSlots();
 
     {
         AutoEnterOOMUnsafeRegion oomUnsafe;
         dst->slots_ = zone->pod_malloc<HeapSlot>(count);
         if (!dst->slots_)
-            oomUnsafe.crash("Failed to allocate slots while tenuring.");
+            oomUnsafe.crash(sizeof(HeapSlot) * count, "Failed to allocate slots while tenuring.");
     }
 
     PodCopy(dst->slots_, src->slots_, count);
     nursery().setSlotsForwardingPointer(src->slots_, dst->slots_, count);
     return count * sizeof(HeapSlot);
 }
 
 size_t
@@ -2351,18 +2351,20 @@ js::TenuringTracer::moveElementsToTenure
         return nslots * sizeof(HeapSlot);
     }
 
     MOZ_ASSERT(nslots >= 2);
 
     {
         AutoEnterOOMUnsafeRegion oomUnsafe;
         dstHeader = reinterpret_cast<ObjectElements*>(zone->pod_malloc<HeapSlot>(nslots));
-        if (!dstHeader)
-            oomUnsafe.crash("Failed to allocate elements while tenuring.");
+        if (!dstHeader) {
+            oomUnsafe.crash(sizeof(HeapSlot) * nslots,
+                            "Failed to allocate elements while tenuring.");
+        }
     }
 
     js_memcpy(dstHeader, srcHeader, nslots * sizeof(HeapSlot));
     nursery().setElementsForwardingPointer(srcHeader, dstHeader, nslots);
     dst->elements_ = dstHeader->elements();
     return nslots * sizeof(HeapSlot);
 }
 
--- a/js/src/jit-test/tests/wasm/basic-integer.js
+++ b/js/src/jit-test/tests/wasm/basic-integer.js
@@ -1,16 +1,30 @@
 load(libdir + "wasm.js");
 
 assertEq(wasmEvalText('(module (func (result i32) (i32.const -1)) (export "" 0))')(), -1);
 assertEq(wasmEvalText('(module (func (result i32) (i32.const -2147483648)) (export "" 0))')(), -2147483648);
 assertEq(wasmEvalText('(module (func (result i32) (i32.const 4294967295)) (export "" 0))')(), -1);
 
 function testUnary(type, opcode, op, expect) {
-  assertEq(wasmEvalText(`(module (func (param ${type}) (result ${type}) (${type}.${opcode} (get_local 0))) (export "" 0))`)(op), expect);
+    var assertFunc = assertEq;
+    if (type === 'i64') {
+        expect = createI64(expect);
+        assertFunc = assertEqI64;
+    }
+
+    // Test with constant
+    assertFunc(wasmEvalText(`(module (func (result ${type}) (${type}.${opcode} (${type}.const ${op}))) (export "" 0))`)(), expect);
+
+    if (type === 'i64') {
+        op = createI64(op);
+    }
+
+    // Test with param
+    assertFunc(wasmEvalText(`(module (func (param ${type}) (result ${type}) (${type}.${opcode} (get_local 0))) (export "" 0))`)(op), expect);
 }
 
 function testBinary64(opcode, lhs, rhs, expect) {
     let lobj = createI64(lhs);
     let robj = createI64(rhs);
     expect = createI64(expect);
 
     assertEqI64(wasmEvalText(`(module (func (param i64) (param i64) (result i64) (i64.${opcode} (get_local 0) (get_local 1))) (export "" 0))`)(lobj, robj), expect);
@@ -42,16 +56,29 @@ function testComparison64(opcode, lhs, r
     // Also test if, for the compare-and-branch path.
     assertEq(wasmEvalText(`(module
                             (func (param i64) (param i64) (result i32)
                              (if (i64.${opcode} (get_local 0) (get_local 1))
                               (i32.const 1)
                               (i32.const 0)))
                               (export "" 0))`)(lobj, robj), expect);
 }
+function testI64Eqz(input, expect) {
+    assertEq(wasmEvalText(`(module (func (result i32) (i64.eqz (i64.const ${input}))) (export "" 0))`)(input), expect);
+    input = createI64(input);
+    assertEq(wasmEvalText(`(module (func (param i64) (result i32) (i64.eqz (get_local 0))) (export "" 0))`)(input), expect);
+}
+
+function testTrap32(opcode, lhs, rhs, expect) {
+    assertErrorMessage(() => wasmEvalText(`(module (func (param i32) (param i32) (result i32) (i32.${opcode} (get_local 0) (get_local 1))) (export "" 0))`)(lhs, rhs), Error, expect);
+    // The same, but now the RHS is a constant.
+    assertErrorMessage(() => wasmEvalText(`(module (func (param i32) (result i32) (i32.${opcode} (get_local 0) (i32.const ${rhs}))) (export "" 0))`)(lhs), Error, expect);
+    // LHS and RHS are constants.
+    assertErrorMessage(wasmEvalText(`(module (func (result i32) (i32.${opcode} (i32.const ${lhs}) (i32.const ${rhs}))) (export "" 0))`), Error, expect);
+}
 
 function testTrap64(opcode, lhs, rhs, expect) {
     let lobj = createI64(lhs);
     let robj = createI64(rhs);
 
     assertErrorMessage(() => wasmEvalText(`(module (func (param i64) (param i64) (result i64) (i64.${opcode} (get_local 0) (get_local 1))) (export "" 0))`)(lobj, robj), Error, expect);
     // The same, but now the RHS is a constant.
     assertErrorMessage(() => wasmEvalText(`(module (func (param i64) (result i64) (i64.${opcode} (get_local 0) (i64.const ${rhs}))) (export "" 0))`)(lobj), Error, expect);
@@ -85,37 +112,38 @@ testBinary32('rem_s', 40, -3, 1);
 testBinary32('rem_u', 40, -3, 40);
 testBinary32('and', 42, 6, 2);
 testBinary32('or', 42, 6, 46);
 testBinary32('xor', 42, 2, 40);
 testBinary32('shl', 40, 2, 160);
 testBinary32('shr_s', -40, 2, -10);
 testBinary32('shr_u', -40, 2, 1073741814);
 
+testTrap32('div_s', 42, 0, /integer divide by zero/);
+testTrap32('div_s', 0x80000000 | 0, -1, /integer overflow/);
+testTrap32('div_u', 42, 0, /integer divide by zero/);
+testTrap32('rem_s', 42, 0, /integer divide by zero/);
+testTrap32('rem_u', 42, 0, /integer divide by zero/);
+
 testBinary32('rotl', 40, 2, 160);
 testBinary32('rotl', 40, 34, 160);
 testBinary32('rotr', 40, 2, 10);
 testBinary32('rotr', 40, 34, 10);
 
 testComparison32('eq', 40, 40, 1);
 testComparison32('ne', 40, 40, 0);
 testComparison32('lt_s', 40, 40, 0);
 testComparison32('lt_u', 40, 40, 0);
 testComparison32('le_s', 40, 40, 1);
 testComparison32('le_u', 40, 40, 1);
 testComparison32('gt_s', 40, 40, 0);
 testComparison32('gt_u', 40, 40, 0);
 testComparison32('ge_s', 40, 40, 1);
 testComparison32('ge_u', 40, 40, 1);
 
-//testUnary('i64', 'clz', 40, 58); // TODO: NYI
-//testUnary('i64', 'ctz', 40, 0); // TODO: NYI
-//testUnary('i64', 'popcnt', 40, 0); // TODO: NYI
-//testUnary('i64', 'eqz', 40, 0); // TODO: NYI
-
 if (hasI64()) {
 
     setJitCompilerOption('wasm.test-mode', 1);
 
     testBinary64('add', 40, 2, 42);
     testBinary64('add', "0x1234567887654321", -1, "0x1234567887654320");
     testBinary64('add', "0xffffffffffffffff", 1, 0);
     testBinary64('sub', 40, 2, 38);
@@ -180,16 +208,59 @@ if (hasI64()) {
     testComparison64('lt_u', "0x8000000012345678", "0x1", 0);
     testComparison64('le_s', -1, 0, 1);
     testComparison64('le_u', -1, -1, 1);
     testComparison64('gt_s', 1, "0x8000000000000000", 1);
     testComparison64('gt_u', 1, "0x8000000000000000", 0);
     testComparison64('ge_s', 1, "0x8000000000000000", 1);
     testComparison64('ge_u', 1, "0x8000000000000000", 0);
 
+    testUnary('i64', 'clz', 40, 58);
+    testUnary('i64', 'clz', "0x8000000000000000", 0);
+    testUnary('i64', 'clz', "0x7fffffffffffffff", 1);
+    testUnary('i64', 'clz', "0x4000000000000000", 1);
+    testUnary('i64', 'clz', "0x3000000000000000", 2);
+    testUnary('i64', 'clz', "0x2000000000000000", 2);
+    testUnary('i64', 'clz', "0x1000000000000000", 3);
+    testUnary('i64', 'clz', "0x0030000000000000", 10);
+    testUnary('i64', 'clz', "0x0000800000000000", 16);
+    testUnary('i64', 'clz', "0x00000000ffffffff", 32);
+    testUnary('i64', 'clz', -1, 0);
+    testUnary('i64', 'clz', 0, 64);
+
+    testUnary('i64', 'ctz', 40, 3);
+    testUnary('i64', 'ctz', "0x8000000000000000", 63);
+    testUnary('i64', 'ctz', "0x7fffffffffffffff", 0);
+    testUnary('i64', 'ctz', "0x4000000000000000", 62);
+    testUnary('i64', 'ctz', "0x3000000000000000", 60);
+    testUnary('i64', 'ctz', "0x2000000000000000", 61);
+    testUnary('i64', 'ctz', "0x1000000000000000", 60);
+    testUnary('i64', 'ctz', "0x0030000000000000", 52);
+    testUnary('i64', 'ctz', "0x0000800000000000", 47);
+    testUnary('i64', 'ctz', "0x00000000ffffffff", 0);
+    testUnary('i64', 'ctz', -1, 0);
+    testUnary('i64', 'ctz', 0, 64);
+
+    testUnary('i64', 'popcnt', 40, 2);
+    testUnary('i64', 'popcnt', 0, 0);
+    testUnary('i64', 'popcnt', "0x8000000000000000", 1);
+    testUnary('i64', 'popcnt', "0x7fffffffffffffff", 63);
+    testUnary('i64', 'popcnt', "0x4000000000000000", 1);
+    testUnary('i64', 'popcnt', "0x3000000000000000", 2);
+    testUnary('i64', 'popcnt', "0x2000000000000000", 1);
+    testUnary('i64', 'popcnt', "0x1000000000000000", 1);
+    testUnary('i64', 'popcnt', "0x0030000000000000", 2);
+    testUnary('i64', 'popcnt', "0x0000800000000000", 1);
+    testUnary('i64', 'popcnt', "0x00000000ffffffff", 32);
+    testUnary('i64', 'popcnt', -1, 64);
+    testUnary('i64', 'popcnt', 0, 0);
+
+    testI64Eqz(40, 0);
+    testI64Eqz(0, 1);
+
     setJitCompilerOption('wasm.test-mode', 0);
 } else {
     // Sleeper test: once i64 works on more platforms, remove this if-else.
     try {
         testComparison64('eq', 40, 40, 1);
         assertEq(0, 1);
     } catch(e) {
         assertEq(e.toString().indexOf("NYI on this platform") >= 0, true);
--- a/js/src/jit-test/tests/wasm/spec.js
+++ b/js/src/jit-test/tests/wasm/spec.js
@@ -1,92 +1,129 @@
 load(libdir + "wasm.js");
 load(scriptdir + "spec/list.js");
 
 if (typeof assert === 'undefined') {
-    var assert = function assert(c, msg) {
-        if (!c) {
-            throw new Error("Assertion failed: " + msg);
-        }
+    var assert = function(c, msg) {
+        assertEq(c, true, msg);
     };
 }
 
 // Element list or string.
 function Element(str, dollared, quoted) {
     this.list = [];
     this.str = str === undefined ? null : str;
     this.dollared = !!dollared;
     this.quoted = !!quoted;
 }
+
 Element.prototype.toString = function() {
     if (this.str !== null) {
         if (this.dollared) {
             return "$" + this.str;
-        } else if (this.quoted) {
+        }
+        if (this.quoted) {
             return `"${this.str}"`;
         }
         return this.str;
     }
     return `(${this.list.map(x => x.toString()).join(" ")})`;
 };
 
+var module;
+
+setJitCompilerOption('wasm.test-mode', 1);
+
 // Creates a tree of s-expressions. Ported from Binaryen's SExpressionParser.
 function parseSExpression(text) {
     var input = 0;
+
+    var commentDepth = 0;
+    function skipBlockComment() {
+        while (true) {
+            if (text[input] === '(' && text[input + 1] === ';') {
+                input += 2;
+                commentDepth++;
+            } else if (text[input] === ';' && text[input + 1] === ')') {
+                input += 2;
+                commentDepth--;
+                if (!commentDepth) {
+                    return;
+                }
+            } else {
+                input++;
+            }
+        }
+    }
+
     function parseInnerList() {
         if (text[input] === ';') {
             // Parse comment.
             input++;
             if (text[input] === ';') {
                 while (text[input] != '\n') input++;
                 return null;
             }
-            input = text.substring(";)", input);
-            assert(input >= 0);
+            assert(false, 'malformed comment');
+        }
+
+        if (text[input] === '(' && text[input + 1] === ';') {
+            skipBlockComment();
             return null;
         }
+
+        var start = input;
         var ret = new Element();
         while (true) {
             var curr = parse();
-            if (!curr) return ret;
+            if (!curr) {
+                ret.lineno = countLines(text, input);
+                return ret;
+            }
             ret.list.push(curr);
         }
     }
+
     function isSpace(c) {
         switch (c) {
+            case '\n':
             case ' ':
-            case '\n':
             case '\r':
             case '\t':
             case '\v':
             case '\f':
                 return true;
             default:
                 return false;
         }
     }
+
     function skipWhitespace() {
         while (true) {
-            while (isSpace(text[input])) input++;
+            while (isSpace(text[input]))
+                input++;
+
             if (text[input] === ';' && text[input + 1] === ';') {
                 while (text.length > input && text[input] != '\n') input++;
             } else if (text[input] === '(' && text[input + 1] === ';') {
-                input = text.substring(";)", input) + 2;
+                skipBlockComment();
             } else {
                 return;
             }
         }
     }
+
     function parseString() {
         var dollared = false;
         var quoted = false;
         if (text[input] === '$') {
             input++;
             dollared = true;
         }
+
         var start = input;
         if (text[input] === '"') {
             quoted = true;
             // Parse escaping \", but leave code escaped - we'll handle escaping in memory segments specifically.
             input++;
             var str = "";
             while (true) {
                 if (text[input] === '"') break;
@@ -97,86 +134,236 @@ function parseSExpression(text) {
                     continue;
                 }
                 str += text[input];
                 input++;
             }
             input++;
             return new Element(str, dollared, quoted);
         }
-        while (text.length > input && !isSpace(text[input]) && text[input] != ')' && text[input] != '(') input++;
+
+        while (text.length > input &&
+               !isSpace(text[input]) &&
+               text[input] != ')' &&
+               text[input] != '(') {
+            input++;
+        }
+
         return new Element(text.substring(start, input), dollared);
     }
+
     function parse() {
         skipWhitespace();
-        if (text.length === input || text[input] === ')') return null;
+
+        if (text.length === input || text[input] === ')')
+            return null;
+
         if (text[input] === '(') {
             input++;
             var ret = parseInnerList();
             skipWhitespace();
-            assert(text[input] === ')');
+            assert(text[input] === ')', 'inner list ends with a )');
             input++;
             return ret;
         }
+
         return parseString();
     }
+
     var root = null;
     while (!root) { // Keep parsing until we pass an initial comment.
         root = parseInnerList();
     }
     return root;
 }
 
 var imports = {
     spectest: {
         print: function (x) {
             print(x);
         }
     }
 };
-var module;
-var moduleText;
+
+function handleNonStandard(exprName, e)
+{
+    if (exprName === 'quit') {
+        quit();
+    }
+    if (exprName === 'print') {
+        print.apply(null, e.list.slice(1).map(exec))
+        return true;
+    }
+    return false;
+}
 
 // Recursively execute the expression.
 function exec(e) {
     var exprName = e.list[0].str;
+
     if (exprName === "module") {
-        moduleText = e.toString();
-        try {
-            module = wasmEvalText(moduleText, imports);
-        } catch (x) {
-            assert(false, x.toString());
-        }
-    } else if (exprName === "invoke") {
+        let moduleText = e.toString();
+        module = wasmEvalText(moduleText, imports);
+        return;
+    }
+
+    if (exprName === "invoke") {
         var name = e.list[1].str;
         var args = e.list.slice(2).map(exec);
         var fn = null;
-        assert(module !== null);
+
+        if (module === null) {
+            debug('We should have a module here before trying to invoke things!');
+            quit();
+        }
+
         if (typeof module[name] === "function") {
             fn = module[name];
         } else if (name === "") {
             fn = module;
             assert(typeof fn === "function", "Default exported function not found: " + e);
         } else {
             assert(false, "Exported function not found: " + e);
         }
         return fn.apply(null, args);
-    } else if (exprName.indexOf(".const") > 0) {
+    }
+
+    if (exprName.indexOf(".const") > 0) {
         // Eval the expression using a wasm module.
         var type = exprName.substring(0, exprName.indexOf(".const"));
         return wasmEvalText('(module (func (result ' + type + ') ' + e + ') (export "" 0))')()
-    } else if (exprName === "assert_return") {
-        assertEq(exec(e.list[1]), exec(e.list[2]));
-    } else if (exprName === "assert_return_nan") {
+    }
+
+    if (exprName === "assert_return") {
+        let lhs = exec(e.list[1]);
+        // There might be a value to test against.
+        if (e.list[2]) {
+            let rhs = exec(e.list[2]);
+            if (typeof lhs === 'number') {
+                assertEq(lhs, rhs);
+            } else {
+                // Int64 are emulated with objects with shape:
+                // {low: Number, high: Number}
+                assert(typeof lhs.low === 'number', 'assert_return expects int64 or number');
+                assert(typeof lhs.high === 'number', 'assert_return expects int64 or number');
+                assertEq(lhs.low, rhs.low);
+                assertEq(lhs.high, rhs.high);
+            }
+        }
+        return;
+    }
+
+    if (exprName === "assert_return_nan") {
         assertEq(exec(e.list[1]), NaN);
-    } else {
+        return;
+    }
+
+    if (exprName === "assert_invalid") {
+        let moduleText = e.list[1].toString();
+        let errMsg = e.list[2];
+        if (errMsg) {
+            assert(errMsg.quoted, "assert_invalid second argument must be a string");
+            errMsg.quoted = false;
+        }
+        let caught = false;
+        try {
+            wasmEvalText(moduleText, imports);
+        } catch(e) {
+            if (errMsg && e.toString().indexOf(errMsg) === -1)
+                warn(`expected error message "${errMsg}", got "${e}"`);
+            caught = true;
+        }
+        assert(caught, "assert_invalid error");
+        return;
+    }
+
+    if (exprName === 'assert_trap') {
+        let caught = false;
+        let errMsg = e.list[2];
+        assert(errMsg.quoted, "assert_trap second argument must be a string");
+        errMsg.quoted = false;
+        try {
+            exec(e.list[1]);
+        } catch(err) {
+            caught = true;
+            assert(err.toString().indexOf(errMsg) !== -1, `expected error message "${errMsg}", got "${err}"`);
+        }
+        assert(caught, "assert_trap exception not caught");
+        return;
+    }
+
+    if(!handleNonStandard(exprName, e)) {
         assert(false, "NYI: " + e);
     }
 }
 
+var args = scriptArgs;
+
+// Whether we should keep on executing tests if one of them failed or throw.
+var softFail = false;
+
+// Debug function
+var debug = function() {};
+var debugImpl = print;
+
+var warn = print;
+
+// Count number of lines from start to `input` in `text.
+var countLines = function() { return -1; }
+var countLinesImpl = function(text, input) {
+    return text.substring(0, input).split('\n').length;
+}
+
+// Specific tests to be run
+var targets = [];
+for (let arg of args) {
+    switch (arg) {
+      case '-c':
+        countLines = countLinesImpl;
+        break;
+      case '-d':
+        debug = debugImpl;
+        break;
+      case '-s':
+        softFail = true;
+        break;
+      default:
+        targets.push(arg);
+        break;
+    }
+}
+
+if (targets.length)
+    specTests = targets;
+
+top_loop:
 for (var test of specTests) {
     module = null;
-    moduleText = null;
-    var root = new parseSExpression(read(scriptdir + "spec/" + test));
-    for (var e of root.list) {
-        exec(e);
+
+    debug(`Running test ${test}...`);
+
+    let source = read(scriptdir + "spec/" + test);
+
+    let root = new parseSExpression(source);
+
+    let success = true;
+    for (let e of root.list) {
+        try {
+            exec(e);
+        } catch(err) {
+            if (err && err.message && err.message.indexOf("i64 NYI") !== -1) {
+                assert(!hasI64(), 'i64 NYI should happen only on platforms without i64');
+                warn(`Skipping test file ${test} as it contains int64, NYI.\n`)
+                continue top_loop;
+            }
+            success = false;
+            debug(`Error in ${test}:${e.lineno}: ${err.stack ? err.stack : ''}\n${err}`);
+            if (!softFail) {
+                throw err;
+            }
+        }
     }
-}
\ No newline at end of file
+
+    if (success)
+        debug(`\n${test} PASSED`);
+    else
+        debug(`\n${test} FAILED`);
+}
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/spec/address.wast
@@ -0,0 +1,34 @@
+(module
+    (memory 1 (segment 0 "abcdefghijklmnopqrstuvwxyz"))
+    (import $print "spectest" "print" (param i32))
+
+    (func $good (param $i i32)
+        (call_import $print (i32.load8_u offset=0 (get_local $i)))  ;; 97 'a'
+        (call_import $print (i32.load8_u offset=1 (get_local $i)))  ;; 98 'b'
+        (call_import $print (i32.load8_u offset=2 (get_local $i)))  ;; 99 'c'
+        (call_import $print (i32.load8_u offset=25 (get_local $i))) ;; 122 'z'
+
+        (call_import $print (i32.load16_u offset=0 (get_local $i)))          ;; 25185 'ab'
+        (call_import $print (i32.load16_u align=1 (get_local $i)))           ;; 25185 'ab'
+        (call_import $print (i32.load16_u offset=1 align=1 (get_local $i)))  ;; 25442 'bc'
+        (call_import $print (i32.load16_u offset=2 (get_local $i)))          ;; 25699 'cd'
+        (call_import $print (i32.load16_u offset=25 align=1 (get_local $i))) ;; 122 'z\0'
+
+        (call_import $print (i32.load offset=0 (get_local $i)))          ;; 1684234849 'abcd'
+        (call_import $print (i32.load offset=1 align=1 (get_local $i)))  ;; 1701077858 'bcde'
+        (call_import $print (i32.load offset=2 align=2 (get_local $i)))  ;; 1717920867 'cdef'
+        (call_import $print (i32.load offset=25 align=1 (get_local $i))) ;; 122 'z\0\0\0'
+    )
+    (export "good" $good)
+
+    (func $bad2 (param $i i32) (i32.load offset=4294967295 (get_local $i)))
+    (export "bad2" $bad2)
+)
+
+(invoke "good" (i32.const 0))
+(invoke "good" (i32.const 65507))
+(assert_trap (invoke "good" (i32.const 65508)) "out of bounds memory access")
+(assert_trap (invoke "bad2" (i32.const 0)) "out of bounds memory access")
+(assert_trap (invoke "bad2" (i32.const 1)) "out of bounds memory access")
+
+(assert_invalid (module (memory 1) (func $bad1 (param $i i32) (i32.load offset=4294967296 (get_local $i))) ) "offset too large")
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/spec/binary.wast
@@ -0,0 +1,14 @@
+(module "\00asm\0b\00\00\00")
+(module "\00asm" "\0b\00\00\00")
+
+(assert_invalid (module "") "unexpected end")
+(assert_invalid (module "\01") "unexpected end")
+(assert_invalid (module "\00as") "unexpected end")
+(assert_invalid (module "\01") "unexpected end")
+(assert_invalid (module "asm\00") "magic header not detected")
+
+(assert_invalid (module "\00asm") "unexpected end")
+(assert_invalid (module "\00asm\0b") "unexpected end")
+(assert_invalid (module "\00asm\0b\00\00") "unexpected end")
+(assert_invalid (module "\00asm\10\00\00\00") "unknown binary version")
+
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/spec/block.wast
@@ -0,0 +1,35 @@
+(module
+  (func $empty
+    (block)
+    (block $l)
+  )
+
+  (func $singular (result i32)
+    (block (i32.const 7))
+  )
+
+  (func $multi (result i32)
+    (block (i32.const 5) (i32.const 6) (i32.const 7) (i32.const 8))
+  )
+
+  (func $effects (result i32)
+    (local i32)
+    (block
+      (set_local 0 (i32.const 1))
+      (set_local 0 (i32.mul (get_local 0) (i32.const 3)))
+      (set_local 0 (i32.sub (get_local 0) (i32.const 5)))
+      (set_local 0 (i32.mul (get_local 0) (i32.const 7)))
+    )
+    (get_local 0)
+  )
+
+  (export "empty" $empty)
+  (export "singular" $singular)
+  (export "multi" $multi)
+  (export "effects" $effects)
+)
+
+(invoke "empty")
+(assert_return (invoke "singular") (i32.const 7))
+(assert_return (invoke "multi") (i32.const 8))
+(assert_return (invoke "effects") (i32.const -14))
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/spec/block_comments.wast
@@ -0,0 +1,15 @@
+(;;)
+(;(((((((((( ;)
+(;)))))))))));)
+(; (module $error) ;)
+  (; (module $error) ;)
+(; (module $error)
+;)
+(;
+(module $error);)
+(; a (; b ;) c ;)
+(; ;; bla ;)
+(; ;; bla
+;)
+
+(module)  ;; dummy
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/spec/break-drop.wast
@@ -0,0 +1,64 @@
+(module
+  (func $br (block (br 0)))
+  (export "br" $br)
+
+  (func $br-nop (block (br 0 (nop))))
+  (export "br-nop" $br-nop)
+
+  (func $br-drop (block (br 0 (i32.const 1))))
+  (export "br-drop" $br-drop)
+
+  (func $br-block-nop (block (br 0 (block (i32.const 1) (nop)))))
+  (export "br-block-nop" $br-block-nop)
+
+  (func $br-block-drop (block (br 0 (block (nop) (i32.const 1)))))
+  (export "br-block-drop" $br-block-drop)
+
+  (func $br_if (block (br_if 0 (i32.const 1))))
+  (export "br_if" $br_if)
+
+  (func $br_if-nop (block (br_if 0 (nop) (i32.const 1))))
+  (export "br_if-nop" $br_if-nop)
+
+  (func $br_if-drop (block (br_if 0 (i32.const 1) (i32.const 1))))
+  (export "br_if-drop" $br_if-drop)
+
+  (func $br_if-block-nop (block (br_if 0 (block (i32.const 1) (nop)) (i32.const 1))))
+  (export "br_if-block-nop" $br_if-block-nop)
+
+  (func $br_if-block-drop (block (br_if 0 (block (nop) (i32.const 1)) (i32.const 1))))
+  (export "br_if-block-drop" $br_if-block-drop)
+
+  (func $br_table (block (br_table 0 (i32.const 0))))
+  (export "br_table" $br_table)
+
+  (func $br_table-nop (block (br_table 0 (nop) (i32.const 0))))
+  (export "br_table-nop" $br_table-nop)
+
+  (func $br_table-drop (block (br_table 0 (i32.const 1) (i32.const 0))))
+  (export "br_table-drop" $br_table-drop)
+
+  (func $br_table-block-nop (block (br_table 0 (block (i32.const 1) (nop)) (i32.const 0))))
+  (export "br_table-block-nop" $br_table-block-nop)
+
+  (func $br_table-block-drop (block (br_table 0 (block (nop) (i32.const 1)) (i32.const 0))))
+  (export "br_table-block-drop" $br_table-block-drop)
+)
+
+(assert_return (invoke "br"))
+(assert_return (invoke "br-nop"))
+(assert_return (invoke "br-drop"))
+(assert_return (invoke "br-block-nop"))
+(assert_return (invoke "br-block-drop"))
+
+(assert_return (invoke "br_if"))
+(assert_return (invoke "br_if-nop"))
+(assert_return (invoke "br_if-drop"))
+(assert_return (invoke "br_if-block-nop"))
+(assert_return (invoke "br_if-block-drop"))
+
+(assert_return (invoke "br_table"))
+(assert_return (invoke "br_table-nop"))
+(assert_return (invoke "br_table-drop"))
+(assert_return (invoke "br_table-block-nop"))
+(assert_return (invoke "br_table-block-drop"))
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/spec/conversions.wast
@@ -0,0 +1,453 @@
+(module
+  (func $i64.extend_s_i32 (param $x i32) (result i64) (i64.extend_s/i32 (get_local $x)))
+  (export "i64.extend_s_i32" $i64.extend_s_i32)
+
+  (func $i64.extend_u_i32 (param $x i32) (result i64) (i64.extend_u/i32 (get_local $x)))
+  (export "i64.extend_u_i32" $i64.extend_u_i32)
+
+  (func $i32.wrap_i64 (param $x i64) (result i32) (i32.wrap/i64 (get_local $x)))
+  (export "i32.wrap_i64" $i32.wrap_i64)
+
+  (func $i32.trunc_s_f32 (param $x f32) (result i32) (i32.trunc_s/f32 (get_local $x)))
+  (export "i32.trunc_s_f32" $i32.trunc_s_f32)
+
+  (func $i32.trunc_u_f32 (param $x f32) (result i32) (i32.trunc_u/f32 (get_local $x)))
+  (export "i32.trunc_u_f32" $i32.trunc_u_f32)
+
+  (func $i32.trunc_s_f64 (param $x f64) (result i32) (i32.trunc_s/f64 (get_local $x)))
+  (export "i32.trunc_s_f64" $i32.trunc_s_f64)
+
+  (func $i32.trunc_u_f64 (param $x f64) (result i32) (i32.trunc_u/f64 (get_local $x)))
+  (export "i32.trunc_u_f64" $i32.trunc_u_f64)
+
+  (func $i64.trunc_s_f32 (param $x f32) (result i64) (i64.trunc_s/f32 (get_local $x)))
+  (export "i64.trunc_s_f32" $i64.trunc_s_f32)
+
+  (func $i64.trunc_u_f32 (param $x f32) (result i64) (i64.trunc_u/f32 (get_local $x)))
+  (export "i64.trunc_u_f32" $i64.trunc_u_f32)
+
+  (func $i64.trunc_s_f64 (param $x f64) (result i64) (i64.trunc_s/f64 (get_local $x)))
+  (export "i64.trunc_s_f64" $i64.trunc_s_f64)
+
+  (func $i64.trunc_u_f64 (param $x f64) (result i64) (i64.trunc_u/f64 (get_local $x)))
+  (export "i64.trunc_u_f64" $i64.trunc_u_f64)
+
+  (func $f32.convert_s_i32 (param $x i32) (result f32) (f32.convert_s/i32 (get_local $x)))
+  (export "f32.convert_s_i32" $f32.convert_s_i32)
+
+  (func $f32.convert_s_i64 (param $x i64) (result f32) (f32.convert_s/i64 (get_local $x)))
+  (export "f32.convert_s_i64" $f32.convert_s_i64)
+
+  (func $f64.convert_s_i32 (param $x i32) (result f64) (f64.convert_s/i32 (get_local $x)))
+  (export "f64.convert_s_i32" $f64.convert_s_i32)
+
+  (func $f64.convert_s_i64 (param $x i64) (result f64) (f64.convert_s/i64 (get_local $x)))
+  (export "f64.convert_s_i64" $f64.convert_s_i64)
+
+  (func $f32.convert_u_i32 (param $x i32) (result f32) (f32.convert_u/i32 (get_local $x)))
+  (export "f32.convert_u_i32" $f32.convert_u_i32)
+
+  (func $f32.convert_u_i64 (param $x i64) (result f32) (f32.convert_u/i64 (get_local $x)))
+  (export "f32.convert_u_i64" $f32.convert_u_i64)
+
+  (func $f64.convert_u_i32 (param $x i32) (result f64) (f64.convert_u/i32 (get_local $x)))
+  (export "f64.convert_u_i32" $f64.convert_u_i32)
+
+  (func $f64.convert_u_i64 (param $x i64) (result f64) (f64.convert_u/i64 (get_local $x)))
+  (export "f64.convert_u_i64" $f64.convert_u_i64)
+
+  (func $f64.promote_f32 (param $x f32) (result f64) (f64.promote/f32 (get_local $x)))
+  (export "f64.promote_f32" $f64.promote_f32)
+
+  (func $f32.demote_f64 (param $x f64) (result f32) (f32.demote/f64 (get_local $x)))
+  (export "f32.demote_f64" $f32.demote_f64)
+
+  (func $f32.reinterpret_i32 (param $x i32) (result f32) (f32.reinterpret/i32 (get_local $x)))
+  (export "f32.reinterpret_i32" $f32.reinterpret_i32)
+
+  (func $f64.reinterpret_i64 (param $x i64) (result f64) (f64.reinterpret/i64 (get_local $x)))
+  (export "f64.reinterpret_i64" $f64.reinterpret_i64)
+
+  (func $i32.reinterpret_f32 (param $x f32) (result i32) (i32.reinterpret/f32 (get_local $x)))
+  (export "i32.reinterpret_f32" $i32.reinterpret_f32)
+
+  (func $i64.reinterpret_f64 (param $x f64) (result i64) (i64.reinterpret/f64 (get_local $x)))
+  (export "i64.reinterpret_f64" $i64.reinterpret_f64)
+)
+
+(assert_return (invoke "i64.extend_s_i32" (i32.const 0)) (i64.const 0))
+(assert_return (invoke "i64.extend_s_i32" (i32.const 10000)) (i64.const 10000))
+(assert_return (invoke "i64.extend_s_i32" (i32.const -10000)) (i64.const -10000))
+(assert_return (invoke "i64.extend_s_i32" (i32.const -1)) (i64.const -1))
+(assert_return (invoke "i64.extend_s_i32" (i32.const 0x7fffffff)) (i64.const 0x000000007fffffff))
+(assert_return (invoke "i64.extend_s_i32" (i32.const 0x80000000)) (i64.const 0xffffffff80000000))
+
+(assert_return (invoke "i64.extend_u_i32" (i32.const 0)) (i64.const 0))
+(assert_return (invoke "i64.extend_u_i32" (i32.const 10000)) (i64.const 10000))
+(assert_return (invoke "i64.extend_u_i32" (i32.const -10000)) (i64.const 0x00000000ffffd8f0))
+(assert_return (invoke "i64.extend_u_i32" (i32.const -1)) (i64.const 0xffffffff))
+(assert_return (invoke "i64.extend_u_i32" (i32.const 0x7fffffff)) (i64.const 0x000000007fffffff))
+(assert_return (invoke "i64.extend_u_i32" (i32.const 0x80000000)) (i64.const 0x0000000080000000))
+
+(assert_return (invoke "i32.wrap_i64" (i64.const -1)) (i32.const -1))
+(assert_return (invoke "i32.wrap_i64" (i64.const -100000)) (i32.const -100000))
+(assert_return (invoke "i32.wrap_i64" (i64.const 0x80000000)) (i32.const 0x80000000))
+(assert_return (invoke "i32.wrap_i64" (i64.const 0xffffffff7fffffff)) (i32.const 0x7fffffff))
+(assert_return (invoke "i32.wrap_i64" (i64.const 0xffffffff00000000)) (i32.const 0x00000000))
+(assert_return (invoke "i32.wrap_i64" (i64.const 0xfffffffeffffffff)) (i32.const 0xffffffff))
+(assert_return (invoke "i32.wrap_i64" (i64.const 0xffffffff00000001)) (i32.const 0x00000001))
+(assert_return (invoke "i32.wrap_i64" (i64.const 0)) (i32.const 0))
+(assert_return (invoke "i32.wrap_i64" (i64.const 1311768467463790320)) (i32.const 0x9abcdef0))
+(assert_return (invoke "i32.wrap_i64" (i64.const 0x00000000ffffffff)) (i32.const 0xffffffff))
+(assert_return (invoke "i32.wrap_i64" (i64.const 0x0000000100000000)) (i32.const 0x00000000))
+(assert_return (invoke "i32.wrap_i64" (i64.const 0x0000000100000001)) (i32.const 0x00000001))
+
+(assert_return (invoke "i32.trunc_s_f32" (f32.const 0.0)) (i32.const 0))
+(assert_return (invoke "i32.trunc_s_f32" (f32.const -0.0)) (i32.const 0))
+(assert_return (invoke "i32.trunc_s_f32" (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "i32.trunc_s_f32" (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "i32.trunc_s_f32" (f32.const 1.0)) (i32.const 1))
+(assert_return (invoke "i32.trunc_s_f32" (f32.const 0x1.19999ap+0)) (i32.const 1))
+(assert_return (invoke "i32.trunc_s_f32" (f32.const 1.5)) (i32.const 1))
+(assert_return (invoke "i32.trunc_s_f32" (f32.const -1.0)) (i32.const -1))
+(assert_return (invoke "i32.trunc_s_f32" (f32.const -0x1.19999ap+0)) (i32.const -1))
+(assert_return (invoke "i32.trunc_s_f32" (f32.const -1.5)) (i32.const -1))
+(assert_return (invoke "i32.trunc_s_f32" (f32.const -1.9)) (i32.const -1))
+(assert_return (invoke "i32.trunc_s_f32" (f32.const -2.0)) (i32.const -2))
+(assert_return (invoke "i32.trunc_s_f32" (f32.const 2147483520.0)) (i32.const 2147483520))
+(assert_return (invoke "i32.trunc_s_f32" (f32.const -2147483648.0)) (i32.const -2147483648))
+(assert_trap (invoke "i32.trunc_s_f32" (f32.const 2147483648.0)) "integer overflow")
+(assert_trap (invoke "i32.trunc_s_f32" (f32.const -2147483904.0)) "integer overflow")
+(assert_trap (invoke "i32.trunc_s_f32" (f32.const infinity)) "integer overflow")
+(assert_trap (invoke "i32.trunc_s_f32" (f32.const -infinity)) "integer overflow")
+(assert_trap (invoke "i32.trunc_s_f32" (f32.const nan)) "invalid conversion to integer")
+
+(assert_return (invoke "i32.trunc_u_f32" (f32.const 0.0)) (i32.const 0))
+(assert_return (invoke "i32.trunc_u_f32" (f32.const -0.0)) (i32.const 0))
+(assert_return (invoke "i32.trunc_u_f32" (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "i32.trunc_u_f32" (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "i32.trunc_u_f32" (f32.const 1.0)) (i32.const 1))
+(assert_return (invoke "i32.trunc_u_f32" (f32.const 0x1.19999ap+0)) (i32.const 1))
+(assert_return (invoke "i32.trunc_u_f32" (f32.const 1.5)) (i32.const 1))
+(assert_return (invoke "i32.trunc_u_f32" (f32.const 1.9)) (i32.const 1))
+(assert_return (invoke "i32.trunc_u_f32" (f32.const 2.0)) (i32.const 2))
+(assert_return (invoke "i32.trunc_u_f32" (f32.const 2147483648)) (i32.const -2147483648)) ;; 0x1.00000p+31 -> 8000 0000
+(assert_return (invoke "i32.trunc_u_f32" (f32.const 4294967040.0)) (i32.const -256))
+(assert_return (invoke "i32.trunc_u_f32" (f32.const -0x1.ccccccp-1)) (i32.const 0))
+(assert_return (invoke "i32.trunc_u_f32" (f32.const -0x1.fffffep-1)) (i32.const 0))
+(assert_trap (invoke "i32.trunc_u_f32" (f32.const 4294967296.0)) "integer overflow")
+(assert_trap (invoke "i32.trunc_u_f32" (f32.const -1.0)) "integer overflow")
+(assert_trap (invoke "i32.trunc_u_f32" (f32.const infinity)) "integer overflow")
+(assert_trap (invoke "i32.trunc_u_f32" (f32.const -infinity)) "integer overflow")
+(assert_trap (invoke "i32.trunc_u_f32" (f32.const nan)) "invalid conversion to integer")
+
+(assert_return (invoke "i32.trunc_s_f64" (f64.const 0.0)) (i32.const 0))
+(assert_return (invoke "i32.trunc_s_f64" (f64.const -0.0)) (i32.const 0))
+(assert_return (invoke "i32.trunc_s_f64" (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "i32.trunc_s_f64" (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "i32.trunc_s_f64" (f64.const 1.0)) (i32.const 1))
+(assert_return (invoke "i32.trunc_s_f64" (f64.const 0x1.199999999999ap+0)) (i32.const 1))
+(assert_return (invoke "i32.trunc_s_f64" (f64.const 1.5)) (i32.const 1))
+(assert_return (invoke "i32.trunc_s_f64" (f64.const -1.0)) (i32.const -1))
+(assert_return (invoke "i32.trunc_s_f64" (f64.const -0x1.199999999999ap+0)) (i32.const -1))
+(assert_return (invoke "i32.trunc_s_f64" (f64.const -1.5)) (i32.const -1))
+(assert_return (invoke "i32.trunc_s_f64" (f64.const -1.9)) (i32.const -1))
+(assert_return (invoke "i32.trunc_s_f64" (f64.const -2.0)) (i32.const -2))
+(assert_return (invoke "i32.trunc_s_f64" (f64.const 2147483647.0)) (i32.const 2147483647))
+(assert_return (invoke "i32.trunc_s_f64" (f64.const -2147483648.0)) (i32.const -2147483648))
+(assert_trap (invoke "i32.trunc_s_f64" (f64.const 2147483648.0)) "integer overflow")
+(assert_trap (invoke "i32.trunc_s_f64" (f64.const -2147483649.0)) "integer overflow")
+(assert_trap (invoke "i32.trunc_s_f64" (f64.const infinity)) "integer overflow")
+(assert_trap (invoke "i32.trunc_s_f64" (f64.const -infinity)) "integer overflow")
+(assert_trap (invoke "i32.trunc_s_f64" (f64.const nan)) "invalid conversion to integer")
+
+(assert_return (invoke "i32.trunc_u_f64" (f64.const 0.0)) (i32.const 0))
+(assert_return (invoke "i32.trunc_u_f64" (f64.const -0.0)) (i32.const 0))
+(assert_return (invoke "i32.trunc_u_f64" (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "i32.trunc_u_f64" (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "i32.trunc_u_f64" (f64.const 1.0)) (i32.const 1))
+(assert_return (invoke "i32.trunc_u_f64" (f64.const 0x1.199999999999ap+0)) (i32.const 1))
+(assert_return (invoke "i32.trunc_u_f64" (f64.const 1.5)) (i32.const 1))
+(assert_return (invoke "i32.trunc_u_f64" (f64.const 1.9)) (i32.const 1))
+(assert_return (invoke "i32.trunc_u_f64" (f64.const 2.0)) (i32.const 2))
+(assert_return (invoke "i32.trunc_u_f64" (f64.const 2147483648)) (i32.const -2147483648)) ;; 0x1.00000p+31 -> 8000 0000
+(assert_return (invoke "i32.trunc_u_f64" (f64.const 4294967295.0)) (i32.const -1))
+(assert_return (invoke "i32.trunc_u_f64" (f64.const -0x1.ccccccccccccdp-1)) (i32.const 0))
+(assert_return (invoke "i32.trunc_u_f64" (f64.const -0x1.fffffffffffffp-1)) (i32.const 0))
+(assert_return (invoke "i32.trunc_u_f64" (f64.const 1e8)) (i32.const 100000000))
+(assert_trap (invoke "i32.trunc_u_f64" (f64.const 4294967296.0)) "integer overflow")
+(assert_trap (invoke "i32.trunc_u_f64" (f64.const -1.0)) "integer overflow")
+(assert_trap (invoke "i32.trunc_u_f64" (f64.const 1e16)) "integer overflow")
+(assert_trap (invoke "i32.trunc_u_f64" (f64.const 1e30)) "integer overflow")
+(assert_trap (invoke "i32.trunc_u_f64" (f64.const 9223372036854775808)) "integer overflow")
+(assert_trap (invoke "i32.trunc_u_f64" (f64.const infinity)) "integer overflow")
+(assert_trap (invoke "i32.trunc_u_f64" (f64.const -infinity)) "integer overflow")
+(assert_trap (invoke "i32.trunc_u_f64" (f64.const nan)) "invalid conversion to integer")
+
+(assert_return (invoke "i64.trunc_s_f32" (f32.const 0.0)) (i64.const 0))
+(assert_return (invoke "i64.trunc_s_f32" (f32.const -0.0)) (i64.const 0))
+(assert_return (invoke "i64.trunc_s_f32" (f32.const 0x1p-149)) (i64.const 0))
+(assert_return (invoke "i64.trunc_s_f32" (f32.const -0x1p-149)) (i64.const 0))
+(assert_return (invoke "i64.trunc_s_f32" (f32.const 1.0)) (i64.const 1))
+(assert_return (invoke "i64.trunc_s_f32" (f32.const 0x1.19999ap+0)) (i64.const 1))
+(assert_return (invoke "i64.trunc_s_f32" (f32.const 1.5)) (i64.const 1))
+(assert_return (invoke "i64.trunc_s_f32" (f32.const -1.0)) (i64.const -1))
+(assert_return (invoke "i64.trunc_s_f32" (f32.const -0x1.19999ap+0)) (i64.const -1))
+(assert_return (invoke "i64.trunc_s_f32" (f32.const -1.5)) (i64.const -1))
+(assert_return (invoke "i64.trunc_s_f32" (f32.const -1.9)) (i64.const -1))
+(assert_return (invoke "i64.trunc_s_f32" (f32.const -2.0)) (i64.const -2))
+(assert_return (invoke "i64.trunc_s_f32" (f32.const 4294967296)) (i64.const 4294967296)) ;; 0x1.00000p+32 -> 1 0000 0000
+(assert_return (invoke "i64.trunc_s_f32" (f32.const -4294967296)) (i64.const -4294967296)) ;; -0x1.00000p+32 -> ffff ffff 0000 0000
+(assert_return (invoke "i64.trunc_s_f32" (f32.const 9223371487098961920.0)) (i64.const 9223371487098961920))
+(assert_return (invoke "i64.trunc_s_f32" (f32.const -9223372036854775808.0)) (i64.const -9223372036854775808))
+(assert_trap (invoke "i64.trunc_s_f32" (f32.const 9223372036854775808.0)) "integer overflow")
+(assert_trap (invoke "i64.trunc_s_f32" (f32.const -9223373136366403584.0)) "integer overflow")
+(assert_trap (invoke "i64.trunc_s_f32" (f32.const infinity)) "integer overflow")
+(assert_trap (invoke "i64.trunc_s_f32" (f32.const -infinity)) "integer overflow")
+(assert_trap (invoke "i64.trunc_s_f32" (f32.const nan)) "invalid conversion to integer")
+
+(assert_return (invoke "i64.trunc_u_f32" (f32.const 0.0)) (i64.const 0))
+(assert_return (invoke "i64.trunc_u_f32" (f32.const -0.0)) (i64.const 0))
+(assert_return (invoke "i64.trunc_u_f32" (f32.const 0x1p-149)) (i64.const 0))
+(assert_return (invoke "i64.trunc_u_f32" (f32.const -0x1p-149)) (i64.const 0))
+(assert_return (invoke "i64.trunc_u_f32" (f32.const 1.0)) (i64.const 1))
+(assert_return (invoke "i64.trunc_u_f32" (f32.const 0x1.19999ap+0)) (i64.const 1))
+(assert_return (invoke "i64.trunc_u_f32" (f32.const 1.5)) (i64.const 1))
+(assert_return (invoke "i64.trunc_u_f32" (f32.const 4294967296)) (i64.const 4294967296))
+(assert_return (invoke "i64.trunc_u_f32" (f32.const 18446742974197923840.0)) (i64.const -1099511627776))
+(assert_return (invoke "i64.trunc_u_f32" (f32.const -0x1.ccccccp-1)) (i64.const 0))
+(assert_return (invoke "i64.trunc_u_f32" (f32.const -0x1.fffffep-1)) (i64.const 0))
+(assert_trap (invoke "i64.trunc_u_f32" (f32.const 18446744073709551616.0)) "integer overflow")
+(assert_trap (invoke "i64.trunc_u_f32" (f32.const -1.0)) "integer overflow")
+(assert_trap (invoke "i64.trunc_u_f32" (f32.const infinity)) "integer overflow")
+(assert_trap (invoke "i64.trunc_u_f32" (f32.const -infinity)) "integer overflow")
+(assert_trap (invoke "i64.trunc_u_f32" (f32.const nan)) "invalid conversion to integer")
+
+(assert_return (invoke "i64.trunc_s_f64" (f64.const 0.0)) (i64.const 0))
+(assert_return (invoke "i64.trunc_s_f64" (f64.const -0.0)) (i64.const 0))
+(assert_return (invoke "i64.trunc_s_f64" (f64.const 0x0.0000000000001p-1022)) (i64.const 0))
+(assert_return (invoke "i64.trunc_s_f64" (f64.const -0x0.0000000000001p-1022)) (i64.const 0))
+(assert_return (invoke "i64.trunc_s_f64" (f64.const 1.0)) (i64.const 1))
+(assert_return (invoke "i64.trunc_s_f64" (f64.const 0x1.199999999999ap+0)) (i64.const 1))
+(assert_return (invoke "i64.trunc_s_f64" (f64.const 1.5)) (i64.const 1))
+(assert_return (invoke "i64.trunc_s_f64" (f64.const -1.0)) (i64.const -1))
+(assert_return (invoke "i64.trunc_s_f64" (f64.const -0x1.199999999999ap+0)) (i64.const -1))
+(assert_return (invoke "i64.trunc_s_f64" (f64.const -1.5)) (i64.const -1))
+(assert_return (invoke "i64.trunc_s_f64" (f64.const -1.9)) (i64.const -1))
+(assert_return (invoke "i64.trunc_s_f64" (f64.const -2.0)) (i64.const -2))
+(assert_return (invoke "i64.trunc_s_f64" (f64.const 4294967296)) (i64.const 4294967296)) ;; 0x1.00000p+32 -> 1 0000 0000
+(assert_return (invoke "i64.trunc_s_f64" (f64.const -4294967296)) (i64.const -4294967296)) ;; -0x1.00000p+32 -> ffff ffff 0000 0000
+(assert_return (invoke "i64.trunc_s_f64" (f64.const 9223372036854774784.0)) (i64.const 9223372036854774784))
+(assert_return (invoke "i64.trunc_s_f64" (f64.const -9223372036854775808.0)) (i64.const -9223372036854775808))
+(assert_trap (invoke "i64.trunc_s_f64" (f64.const 9223372036854775808.0)) "integer overflow")
+(assert_trap (invoke "i64.trunc_s_f64" (f64.const -9223372036854777856.0)) "integer overflow")
+(assert_trap (invoke "i64.trunc_s_f64" (f64.const infinity)) "integer overflow")
+(assert_trap (invoke "i64.trunc_s_f64" (f64.const -infinity)) "integer overflow")
+(assert_trap (invoke "i64.trunc_s_f64" (f64.const nan)) "invalid conversion to integer")
+
+(assert_return (invoke "i64.trunc_u_f64" (f64.const 0.0)) (i64.const 0))
+(assert_return (invoke "i64.trunc_u_f64" (f64.const -0.0)) (i64.const 0))
+(assert_return (invoke "i64.trunc_u_f64" (f64.const 0x0.0000000000001p-1022)) (i64.const 0))
+(assert_return (invoke "i64.trunc_u_f64" (f64.const -0x0.0000000000001p-1022)) (i64.const 0))
+(assert_return (invoke "i64.trunc_u_f64" (f64.const 1.0)) (i64.const 1))
+(assert_return (invoke "i64.trunc_u_f64" (f64.const 0x1.199999999999ap+0)) (i64.const 1))
+(assert_return (invoke "i64.trunc_u_f64" (f64.const 1.5)) (i64.const 1))
+(assert_return (invoke "i64.trunc_u_f64" (f64.const 4294967295)) (i64.const 0xffffffff))
+(assert_return (invoke "i64.trunc_u_f64" (f64.const 4294967296)) (i64.const 0x100000000))
+(assert_return (invoke "i64.trunc_u_f64" (f64.const 18446744073709549568.0)) (i64.const -2048))
+(assert_return (invoke "i64.trunc_u_f64" (f64.const -0x1.ccccccccccccdp-1)) (i64.const 0))
+(assert_return (invoke "i64.trunc_u_f64" (f64.const -0x1.fffffffffffffp-1)) (i64.const 0))
+(assert_return (invoke "i64.trunc_u_f64" (f64.const 1e8)) (i64.const 100000000))
+(assert_return (invoke "i64.trunc_u_f64" (f64.const 1e16)) (i64.const 10000000000000000))
+(assert_return (invoke "i64.trunc_u_f64" (f64.const 9223372036854775808)) (i64.const -9223372036854775808))
+(assert_trap (invoke "i64.trunc_u_f64" (f64.const 18446744073709551616.0)) "integer overflow")
+(assert_trap (invoke "i64.trunc_u_f64" (f64.const -1.0)) "integer overflow")
+(assert_trap (invoke "i64.trunc_u_f64" (f64.const infinity)) "integer overflow")
+(assert_trap (invoke "i64.trunc_u_f64" (f64.const -infinity)) "integer overflow")
+(assert_trap (invoke "i64.trunc_u_f64" (f64.const nan)) "invalid conversion to integer")
+
+(assert_return (invoke "f32.convert_s_i32" (i32.const 1)) (f32.const 1.0))
+(assert_return (invoke "f32.convert_s_i32" (i32.const -1)) (f32.const -1.0))
+(assert_return (invoke "f32.convert_s_i32" (i32.const 0)) (f32.const 0.0))
+(assert_return (invoke "f32.convert_s_i32" (i32.const 2147483647)) (f32.const 2147483648))
+(assert_return (invoke "f32.convert_s_i32" (i32.const -2147483648)) (f32.const -2147483648))
+(assert_return (invoke "f32.convert_s_i32" (i32.const 1234567890)) (f32.const 0x1.26580cp+30))
+;; Test rounding directions.
+(assert_return (invoke "f32.convert_s_i32" (i32.const 16777217)) (f32.const 16777216.0))
+(assert_return (invoke "f32.convert_s_i32" (i32.const -16777217)) (f32.const -16777216.0))
+(assert_return (invoke "f32.convert_s_i32" (i32.const 16777219)) (f32.const 16777220.0))
+(assert_return (invoke "f32.convert_s_i32" (i32.const -16777219)) (f32.const -16777220.0))
+
+(assert_return (invoke "f32.convert_s_i64" (i64.const 1)) (f32.const 1.0))
+(assert_return (invoke "f32.convert_s_i64" (i64.const -1)) (f32.const -1.0))
+(assert_return (invoke "f32.convert_s_i64" (i64.const 0)) (f32.const 0.0))
+(assert_return (invoke "f32.convert_s_i64" (i64.const 9223372036854775807)) (f32.const 9223372036854775807))
+(assert_return (invoke "f32.convert_s_i64" (i64.const -9223372036854775808)) (f32.const -9223372036854775808))
+(assert_return (invoke "f32.convert_s_i64" (i64.const 314159265358979)) (f32.const 0x1.1db9e8p+48)) ;; PI
+;; Test rounding directions.
+(assert_return (invoke "f32.convert_s_i64" (i64.const 16777217)) (f32.const 16777216.0))
+(assert_return (invoke "f32.convert_s_i64" (i64.const -16777217)) (f32.const -16777216.0))
+(assert_return (invoke "f32.convert_s_i64" (i64.const 16777219)) (f32.const 16777220.0))
+(assert_return (invoke "f32.convert_s_i64" (i64.const -16777219)) (f32.const -16777220.0))
+
+(assert_return (invoke "f64.convert_s_i32" (i32.const 1)) (f64.const 1.0))
+(assert_return (invoke "f64.convert_s_i32" (i32.const -1)) (f64.const -1.0))
+(assert_return (invoke "f64.convert_s_i32" (i32.const 0)) (f64.const 0.0))
+(assert_return (invoke "f64.convert_s_i32" (i32.const 2147483647)) (f64.const 2147483647))
+(assert_return (invoke "f64.convert_s_i32" (i32.const -2147483648)) (f64.const -2147483648))
+(assert_return (invoke "f64.convert_s_i32" (i32.const 987654321)) (f64.const 987654321))
+
+(assert_return (invoke "f64.convert_s_i64" (i64.const 1)) (f64.const 1.0))
+(assert_return (invoke "f64.convert_s_i64" (i64.const -1)) (f64.const -1.0))
+(assert_return (invoke "f64.convert_s_i64" (i64.const 0)) (f64.const 0.0))
+(assert_return (invoke "f64.convert_s_i64" (i64.const 9223372036854775807)) (f64.const 9223372036854775807))
+(assert_return (invoke "f64.convert_s_i64" (i64.const -9223372036854775808)) (f64.const -9223372036854775808))
+(assert_return (invoke "f64.convert_s_i64" (i64.const 4669201609102990)) (f64.const 4669201609102990)) ;; Feigenbaum
+;; Test rounding directions.
+(assert_return (invoke "f64.convert_s_i64" (i64.const 9007199254740993)) (f64.const 9007199254740992))
+(assert_return (invoke "f64.convert_s_i64" (i64.const -9007199254740993)) (f64.const -9007199254740992))
+(assert_return (invoke "f64.convert_s_i64" (i64.const 9007199254740995)) (f64.const 9007199254740996))
+(assert_return (invoke "f64.convert_s_i64" (i64.const -9007199254740995)) (f64.const -9007199254740996))
+
+(assert_return (invoke "f32.convert_u_i32" (i32.const 1)) (f32.const 1.0))
+(assert_return (invoke "f32.convert_u_i32" (i32.const 0)) (f32.const 0.0))
+(assert_return (invoke "f32.convert_u_i32" (i32.const 2147483647)) (f32.const 2147483648))
+(assert_return (invoke "f32.convert_u_i32" (i32.const -2147483648)) (f32.const 2147483648))
+(assert_return (invoke "f32.convert_u_i32" (i32.const 0x12345678)) (f32.const 0x1.234568p+28))
+(assert_return (invoke "f32.convert_u_i32" (i32.const 0xffffffff)) (f32.const 4294967296.0))
+;; Test rounding directions.
+(assert_return (invoke "f32.convert_u_i32" (i32.const 16777217)) (f32.const 16777216.0))
+(assert_return (invoke "f32.convert_u_i32" (i32.const 16777219)) (f32.const 16777220.0))
+
+(assert_return (invoke "f32.convert_u_i64" (i64.const 1)) (f32.const 1.0))
+(assert_return (invoke "f32.convert_u_i64" (i64.const 0)) (f32.const 0.0))
+(assert_return (invoke "f32.convert_u_i64" (i64.const 9223372036854775807)) (f32.const 9223372036854775807))
+(assert_return (invoke "f32.convert_u_i64" (i64.const -9223372036854775808)) (f32.const 9223372036854775808))
+(assert_return (invoke "f32.convert_u_i64" (i64.const 0xffffffffffffffff)) (f32.const 18446744073709551616.0))
+;; Test rounding directions.
+(assert_return (invoke "f32.convert_u_i64" (i64.const 16777217)) (f32.const 16777216.0))
+(assert_return (invoke "f32.convert_u_i64" (i64.const 16777219)) (f32.const 16777220.0))
+
+(assert_return (invoke "f64.convert_u_i32" (i32.const 1)) (f64.const 1.0))
+(assert_return (invoke "f64.convert_u_i32" (i32.const 0)) (f64.const 0.0))
+(assert_return (invoke "f64.convert_u_i32" (i32.const 2147483647)) (f64.const 2147483647))
+(assert_return (invoke "f64.convert_u_i32" (i32.const -2147483648)) (f64.const 2147483648))
+(assert_return (invoke "f64.convert_u_i32" (i32.const 0xffffffff)) (f64.const 4294967295.0))
+
+(assert_return (invoke "f64.convert_u_i64" (i64.const 1)) (f64.const 1.0))
+(assert_return (invoke "f64.convert_u_i64" (i64.const 0)) (f64.const 0.0))
+(assert_return (invoke "f64.convert_u_i64" (i64.const 9223372036854775807)) (f64.const 9223372036854775807))
+(assert_return (invoke "f64.convert_u_i64" (i64.const -9223372036854775808)) (f64.const 9223372036854775808))
+(assert_return (invoke "f64.convert_u_i64" (i64.const 0xffffffffffffffff)) (f64.const 18446744073709551616.0))
+;; Test rounding directions.
+(assert_return (invoke "f64.convert_u_i64" (i64.const 9007199254740993)) (f64.const 9007199254740992))
+(assert_return (invoke "f64.convert_u_i64" (i64.const 9007199254740995)) (f64.const 9007199254740996))
+
+(assert_return (invoke "f64.promote_f32" (f32.const 0.0)) (f64.const 0.0))
+(assert_return (invoke "f64.promote_f32" (f32.const -0.0)) (f64.const -0.0))
+(assert_return (invoke "f64.promote_f32" (f32.const 0x1p-149)) (f64.const 0x1p-149))
+(assert_return (invoke "f64.promote_f32" (f32.const -0x1p-149)) (f64.const -0x1p-149))
+(assert_return (invoke "f64.promote_f32" (f32.const 1.0)) (f64.const 1.0))
+(assert_return (invoke "f64.promote_f32" (f32.const -1.0)) (f64.const -1.0))
+(assert_return (invoke "f64.promote_f32" (f32.const -0x1.fffffep+127)) (f64.const -0x1.fffffep+127))
+(assert_return (invoke "f64.promote_f32" (f32.const 0x1.fffffep+127)) (f64.const 0x1.fffffep+127))
+;; Generated randomly by picking a random int and reinterpret it to float.
+(assert_return (invoke "f64.promote_f32" (f32.const 0x1p-119)) (f64.const 0x1p-119))
+;; Generated randomly by picking a random float.
+(assert_return (invoke "f64.promote_f32" (f32.const 0x1.8f867ep+125)) (f64.const 6.6382536710104395e+37))
+(assert_return (invoke "f64.promote_f32" (f32.const infinity)) (f64.const infinity))
+(assert_return (invoke "f64.promote_f32" (f32.const -infinity)) (f64.const -infinity))
+(assert_return (invoke "f64.promote_f32" (f32.const nan)) (f64.const nan))
+
+(assert_return (invoke "f32.demote_f64" (f64.const 0.0)) (f32.const 0.0))
+(assert_return (invoke "f32.demote_f64" (f64.const -0.0)) (f32.const -0.0))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x0.0000000000001p-1022)) (f32.const 0.0))
+(assert_return (invoke "f32.demote_f64" (f64.const -0x0.0000000000001p-1022)) (f32.const -0.0))
+(assert_return (invoke "f32.demote_f64" (f64.const 1.0)) (f32.const 1.0))
+(assert_return (invoke "f32.demote_f64" (f64.const -1.0)) (f32.const -1.0))
+(assert_return (invoke "f32.demote_f64" (f64.const -0x1p-149)) (f32.const -0x1p-149))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1p-149)) (f32.const 0x1p-149))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "f32.demote_f64" (f64.const -0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1.ffffffp+127)) (f32.const infinity))
+(assert_return (invoke "f32.demote_f64" (f64.const -0x1.ffffffp+127)) (f32.const -infinity))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1p-119)) (f32.const 0x1p-119))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1.8f867ep+125)) (f32.const 0x1.8f867ep+125))
+(assert_return (invoke "f32.demote_f64" (f64.const infinity)) (f32.const infinity))
+(assert_return (invoke "f32.demote_f64" (f64.const -infinity)) (f32.const -infinity))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1.0000000000001p+0)) (f32.const 1.0))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1.fffffffffffffp-1)) (f32.const 1.0))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1.0000030000000p+0)) (f32.const 0x1.000004p+0))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1.0000050000000p+0)) (f32.const 0x1.000004p+0))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1.4eae4f7024c7p+108)) (f32.const 0x1.4eae5p+108))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1.a12e71e358685p-113)) (f32.const 0x1.a12e72p-113))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1.cb98354d521ffp-127)) (f32.const 0x1.cb9834p-127))
+(assert_return (invoke "f32.demote_f64" (f64.const -0x1.6972b30cfb562p+1)) (f32.const -0x1.6972b4p+1))
+(assert_return (invoke "f32.demote_f64" (f64.const -0x1.bedbe4819d4c4p+112)) (f32.const -0x1.bedbe4p+112))
+(assert_return (invoke "f32.demote_f64" (f64.const nan)) (f32.const nan))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1p-1022)) (f32.const 0.0))
+(assert_return (invoke "f32.demote_f64" (f64.const -0x1p-1022)) (f32.const -0.0))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x0.0000000000001p-1022)) (f32.const 0.0))
+(assert_return (invoke "f32.demote_f64" (f64.const -0x0.0000000000001p-1022)) (f32.const -0.0))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x0.8p-149)) (f32.const 0.0))
+(assert_return (invoke "f32.demote_f64" (f64.const -0x0.8p-149)) (f32.const -0.0))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1.0000000000001p-150)) (f32.const 0x1p-149))
+(assert_return (invoke "f32.demote_f64" (f64.const -0x1.0000000000001p-150)) (f32.const -0x1p-149))
+
+(assert_return (invoke "f32.reinterpret_i32" (i32.const 0)) (f32.const 0.0))
+(assert_return (invoke "f32.reinterpret_i32" (i32.const 0x80000000)) (f32.const -0.0))
+(assert_return (invoke "f32.reinterpret_i32" (i32.const 1)) (f32.const 0x1p-149))
+(assert_return (invoke "f32.reinterpret_i32" (i32.const -1)) (f32.const -nan:0x7fffff))
+(assert_return (invoke "f32.reinterpret_i32" (i32.const 123456789)) (f32.const 0x1.b79a2ap-113))
+(assert_return (invoke "f32.reinterpret_i32" (i32.const -2147483647)) (f32.const -0x1p-149))
+(assert_return (invoke "f32.reinterpret_i32" (i32.const 0x7f800000)) (f32.const infinity))
+(assert_return (invoke "f32.reinterpret_i32" (i32.const 0xff800000)) (f32.const -infinity))
+(assert_return (invoke "f32.reinterpret_i32" (i32.const 0x7fc00000)) (f32.const nan))
+(assert_return (invoke "f32.reinterpret_i32" (i32.const 0xffc00000)) (f32.const -nan))
+(assert_return (invoke "f32.reinterpret_i32" (i32.const 0x7fa00000)) (f32.const nan:0x200000))
+(assert_return (invoke "f32.reinterpret_i32" (i32.const 0xffa00000)) (f32.const -nan:0x200000))
+
+(assert_return (invoke "f64.reinterpret_i64" (i64.const 0)) (f64.const 0.0))
+(assert_return (invoke "f64.reinterpret_i64" (i64.const 1)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "f64.reinterpret_i64" (i64.const -1)) (f64.const -nan:0xfffffffffffff))
+(assert_return (invoke "f64.reinterpret_i64" (i64.const 0x8000000000000000)) (f64.const -0.0))
+(assert_return (invoke "f64.reinterpret_i64" (i64.const 1234567890)) (f64.const 0x0.00000499602d2p-1022))
+(assert_return (invoke "f64.reinterpret_i64" (i64.const -9223372036854775807)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "f64.reinterpret_i64" (i64.const 0x7ff0000000000000)) (f64.const infinity))
+(assert_return (invoke "f64.reinterpret_i64" (i64.const 0xfff0000000000000)) (f64.const -infinity))
+(assert_return (invoke "f64.reinterpret_i64" (i64.const 0x7ff8000000000000)) (f64.const nan))
+(assert_return (invoke "f64.reinterpret_i64" (i64.const 0xfff8000000000000)) (f64.const -nan))
+(assert_return (invoke "f64.reinterpret_i64" (i64.const 0x7ff4000000000000)) (f64.const nan:0x4000000000000))
+(assert_return (invoke "f64.reinterpret_i64" (i64.const 0xfff4000000000000)) (f64.const -nan:0x4000000000000))
+
+(assert_return (invoke "i32.reinterpret_f32" (f32.const 0.0)) (i32.const 0))
+(assert_return (invoke "i32.reinterpret_f32" (f32.const -0.0)) (i32.const 0x80000000))
+(assert_return (invoke "i32.reinterpret_f32" (f32.const 0x1p-149)) (i32.const 1))
+(assert_return (invoke "i32.reinterpret_f32" (f32.const -nan:0x7fffff)) (i32.const -1))
+(assert_return (invoke "i32.reinterpret_f32" (f32.const -0x1p-149)) (i32.const 0x80000001))
+(assert_return (invoke "i32.reinterpret_f32" (f32.const 1.0)) (i32.const 1065353216))
+(assert_return (invoke "i32.reinterpret_f32" (f32.const 3.1415926)) (i32.const 1078530010))
+(assert_return (invoke "i32.reinterpret_f32" (f32.const 0x1.fffffep+127)) (i32.const 2139095039))
+(assert_return (invoke "i32.reinterpret_f32" (f32.const -0x1.fffffep+127)) (i32.const -8388609))
+(assert_return (invoke "i32.reinterpret_f32" (f32.const infinity)) (i32.const 0x7f800000))
+(assert_return (invoke "i32.reinterpret_f32" (f32.const -infinity)) (i32.const 0xff800000))
+(assert_return (invoke "i32.reinterpret_f32" (f32.const nan)) (i32.const 0x7fc00000))
+(assert_return (invoke "i32.reinterpret_f32" (f32.const -nan)) (i32.const 0xffc00000))
+(assert_return (invoke "i32.reinterpret_f32" (f32.const nan:0x200000)) (i32.const 0x7fa00000))
+(assert_return (invoke "i32.reinterpret_f32" (f32.const -nan:0x200000)) (i32.const 0xffa00000))
+
+(assert_return (invoke "i64.reinterpret_f64" (f64.const 0.0)) (i64.const 0))
+(assert_return (invoke "i64.reinterpret_f64" (f64.const -0.0)) (i64.const 0x8000000000000000))
+(assert_return (invoke "i64.reinterpret_f64" (f64.const 0x0.0000000000001p-1022)) (i64.const 1))
+(assert_return (invoke "i64.reinterpret_f64" (f64.const -nan:0xfffffffffffff)) (i64.const -1))
+(assert_return (invoke "i64.reinterpret_f64" (f64.const -0x0.0000000000001p-1022)) (i64.const 0x8000000000000001))
+(assert_return (invoke "i64.reinterpret_f64" (f64.const 1.0)) (i64.const 4607182418800017408))
+(assert_return (invoke "i64.reinterpret_f64" (f64.const 3.14159265358979)) (i64.const 4614256656552045841))
+(assert_return (invoke "i64.reinterpret_f64" (f64.const 0x1.fffffffffffffp+1023)) (i64.const 9218868437227405311))
+(assert_return (invoke "i64.reinterpret_f64" (f64.const -0x1.fffffffffffffp+1023)) (i64.const -4503599627370497))
+(assert_return (invoke "i64.reinterpret_f64" (f64.const infinity)) (i64.const 0x7ff0000000000000))
+(assert_return (invoke "i64.reinterpret_f64" (f64.const -infinity)) (i64.const 0xfff0000000000000))
+(assert_return (invoke "i64.reinterpret_f64" (f64.const nan)) (i64.const 0x7ff8000000000000))
+(assert_return (invoke "i64.reinterpret_f64" (f64.const -nan)) (i64.const 0xfff8000000000000))
+(assert_return (invoke "i64.reinterpret_f64" (f64.const nan:0x4000000000000)) (i64.const 0x7ff4000000000000))
+(assert_return (invoke "i64.reinterpret_f64" (f64.const -nan:0x4000000000000)) (i64.const 0xfff4000000000000))
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/spec/endianness.wast
@@ -0,0 +1,241 @@
+(module
+  (memory 1)
+
+  ;; Stores an i16 value in little-endian-format
+  (func $i16_store_little (param $address i32) (param $value i32)
+    (i32.store8 (get_local $address) (get_local $value))
+    (i32.store8 (i32.add (get_local $address) (i32.const 1)) (i32.shr_u (get_local $value) (i32.const 8)))
+  )
+
+  ;; Stores an i32 value in little-endian format
+  (func $i32_store_little (param $address i32) (param $value i32)
+    (call $i16_store_little (get_local $address) (get_local $value))
+    (call $i16_store_little (i32.add (get_local $address) (i32.const 2)) (i32.shr_u (get_local $value) (i32.const 16)))
+  )
+
+  ;; Stores an i64 value in little-endian format
+  (func $i64_store_little (param $address i32) (param $value i64)
+    (call $i32_store_little (get_local $address) (i32.wrap/i64 (get_local $value)))
+    (call $i32_store_little (i32.add (get_local $address) (i32.const 4)) (i32.wrap/i64 (i64.shr_u (get_local $value) (i64.const 32))))
+  )
+
+  ;; Loads an i16 value in little-endian format
+  (func $i16_load_little (param $address i32) (result i32)
+    (i32.or
+      (i32.load8_u (get_local $address))
+      (i32.shl (i32.load8_u (i32.add (get_local $address) (i32.const 1))) (i32.const 8))
+    )
+  )
+
+  ;; Loads an i32 value in little-endian format
+  (func $i32_load_little (param $address i32) (result i32)
+    (i32.or
+      (call $i16_load_little (get_local $address))
+      (i32.shl (call $i16_load_little (i32.add (get_local $address) (i32.const 2))) (i32.const 16))
+    )
+  )
+
+  ;; Loads an i64 value in little-endian format
+  (func $i64_load_little (param $address i32) (result i64)
+    (i64.or
+      (i64.extend_u/i32 (call $i32_load_little (get_local $address)))
+      (i64.shl (i64.extend_u/i32 (call $i32_load_little (i32.add (get_local $address) (i32.const 4)))) (i64.const 32))
+    )
+  )
+
+  (func $i32_load16_s (param $value i32) (result i32)
+    (call $i16_store_little (i32.const 0) (get_local $value))
+    (i32.load16_s (i32.const 0))
+  )
+
+  (func $i32_load16_u (param $value i32) (result i32)
+    (call $i16_store_little (i32.const 0) (get_local $value))
+    (i32.load16_u (i32.const 0))
+  )
+
+  (func $i32_load (param $value i32) (result i32)
+    (call $i32_store_little (i32.const 0) (get_local $value))
+    (i32.load (i32.const 0))
+  )
+
+  (func $i64_load16_s (param $value i64) (result i64)
+    (call $i16_store_little (i32.const 0) (i32.wrap/i64 (get_local $value)))
+    (i64.load16_s (i32.const 0))
+  )
+
+  (func $i64_load16_u (param $value i64) (result i64)
+    (call $i16_store_little (i32.const 0) (i32.wrap/i64 (get_local $value)))
+    (i64.load16_u (i32.const 0))
+  )
+
+  (func $i64_load32_s (param $value i64) (result i64)
+    (call $i32_store_little (i32.const 0) (i32.wrap/i64 (get_local $value)))
+    (i64.load32_s (i32.const 0))
+  )
+
+  (func $i64_load32_u (param $value i64) (result i64)
+    (call $i32_store_little (i32.const 0) (i32.wrap/i64 (get_local $value)))
+    (i64.load32_u (i32.const 0))
+  )
+
+  (func $i64_load (param $value i64) (result i64)
+    (call $i64_store_little (i32.const 0) (get_local $value))
+    (i64.load (i32.const 0))
+  )
+
+  (func $f32_load (param $value f32) (result f32)
+    (call $i32_store_little (i32.const 0) (i32.reinterpret/f32 (get_local $value)))
+    (f32.load (i32.const 0))
+  )
+
+  (func $f64_load (param $value f64) (result f64)
+    (call $i64_store_little (i32.const 0) (i64.reinterpret/f64 (get_local $value)))
+    (f64.load (i32.const 0))
+  )
+
+
+  (func $i32_store16 (param $value i32) (result i32)
+    (i32.store16 (i32.const 0) (get_local $value))
+    (call $i16_load_little (i32.const 0))
+  )
+
+  (func $i32_store (param $value i32) (result i32)
+    (i32.store (i32.const 0) (get_local $value))
+    (call $i32_load_little (i32.const 0))
+  )
+
+  (func $i64_store16 (param $value i64) (result i64)
+    (i64.store16 (i32.const 0) (get_local $value))
+    (i64.extend_u/i32 (call $i16_load_little (i32.const 0)))
+  )
+
+  (func $i64_store32 (param $value i64) (result i64)
+    (i64.store32 (i32.const 0) (get_local $value))
+    (i64.extend_u/i32 (call $i32_load_little (i32.const 0)))
+  )
+
+  (func $i64_store (param $value i64) (result i64)
+    (i64.store (i32.const 0) (get_local $value))
+    (call $i64_load_little (i32.const 0))
+  )
+
+  (func $f32_store (param $value f32) (result f32)
+    (f32.store (i32.const 0) (get_local $value))
+    (f32.reinterpret/i32 (call $i32_load_little (i32.const 0)))
+  )
+
+  (func $f64_store (param $value f64) (result f64)
+    (f64.store (i32.const 0) (get_local $value))
+    (f64.reinterpret/i64 (call $i64_load_little (i32.const 0)))
+  )
+
+  (export "i32_load16_s" $i32_load16_s)
+  (export "i32_load16_u" $i32_load16_u)
+  (export "i32_load" $i32_load)
+
+  (export "i64_load16_s" $i64_load16_s)
+  (export "i64_load16_u" $i64_load16_u)
+  (export "i64_load32_s" $i64_load32_s)
+  (export "i64_load32_u" $i64_load32_u)
+  (export "i64_load" $i64_load)
+
+  (export "f32_load" $f32_load)
+  (export "f64_load" $f64_load)
+
+
+  (export "i32_store16" $i32_store16)
+  (export "i32_store" $i32_store)
+
+  (export "i64_store16" $i64_store16)
+  (export "i64_store32" $i64_store32)
+  (export "i64_store" $i64_store)
+
+  (export "f32_store" $f32_store)
+  (export "f64_store" $f64_store)
+)
+
+(assert_return (invoke "i32_load16_s" (i32.const -1)) (i32.const -1))
+(assert_return (invoke "i32_load16_s" (i32.const -4242)) (i32.const -4242))
+(assert_return (invoke "i32_load16_s" (i32.const 42)) (i32.const 42))
+(assert_return (invoke "i32_load16_s" (i32.const 0x3210)) (i32.const 0x3210))
+
+(assert_return (invoke "i32_load16_u" (i32.const -1)) (i32.const 0xFFFF))
+(assert_return (invoke "i32_load16_u" (i32.const -4242)) (i32.const 61294))
+(assert_return (invoke "i32_load16_u" (i32.const 42)) (i32.const 42))
+(assert_return (invoke "i32_load16_u" (i32.const 0xCAFE)) (i32.const 0xCAFE))
+
+(assert_return (invoke "i32_load" (i32.const -1)) (i32.const -1))
+(assert_return (invoke "i32_load" (i32.const -42424242)) (i32.const -42424242))
+(assert_return (invoke "i32_load" (i32.const 42424242)) (i32.const 42424242))
+(assert_return (invoke "i32_load" (i32.const 0xABAD1DEA)) (i32.const 0xABAD1DEA))
+
+(assert_return (invoke "i64_load16_s" (i64.const -1)) (i64.const -1))
+(assert_return (invoke "i64_load16_s" (i64.const -4242)) (i64.const -4242))
+(assert_return (invoke "i64_load16_s" (i64.const 42)) (i64.const 42))
+(assert_return (invoke "i64_load16_s" (i64.const 0x3210)) (i64.const 0x3210))
+
+(assert_return (invoke "i64_load16_u" (i64.const -1)) (i64.const 0xFFFF))
+(assert_return (invoke "i64_load16_u" (i64.const -4242)) (i64.const 61294))
+(assert_return (invoke "i64_load16_u" (i64.const 42)) (i64.const 42))
+(assert_return (invoke "i64_load16_u" (i64.const 0xCAFE)) (i64.const 0xCAFE))
+
+(assert_return (invoke "i64_load32_s" (i64.const -1)) (i64.const -1))
+(assert_return (invoke "i64_load32_s" (i64.const -42424242)) (i64.const -42424242))
+(assert_return (invoke "i64_load32_s" (i64.const 42424242)) (i64.const 42424242))
+(assert_return (invoke "i64_load32_s" (i64.const 0x12345678)) (i64.const 0x12345678))
+
+(assert_return (invoke "i64_load32_u" (i64.const -1)) (i64.const 0xFFFFFFFF))
+(assert_return (invoke "i64_load32_u" (i64.const -42424242)) (i64.const 4252543054))
+(assert_return (invoke "i64_load32_u" (i64.const 42424242)) (i64.const 42424242))
+(assert_return (invoke "i64_load32_u" (i64.const 0xABAD1DEA)) (i64.const 0xABAD1DEA))
+
+(assert_return (invoke "i64_load" (i64.const -1)) (i64.const -1))
+(assert_return (invoke "i64_load" (i64.const -42424242)) (i64.const -42424242))
+(assert_return (invoke "i64_load" (i64.const 0xABAD1DEA)) (i64.const 0xABAD1DEA))
+(assert_return (invoke "i64_load" (i64.const 0xABADCAFEDEAD1DEA)) (i64.const 0xABADCAFEDEAD1DEA))
+
+(assert_return (invoke "f32_load" (f32.const -1)) (f32.const -1))
+(assert_return (invoke "f32_load" (f32.const 1234e-5)) (f32.const 1234e-5))
+(assert_return (invoke "f32_load" (f32.const 4242.4242)) (f32.const 4242.4242))
+(assert_return (invoke "f32_load" (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+
+(assert_return (invoke "f64_load" (f64.const -1)) (f64.const -1))
+(assert_return (invoke "f64_load" (f64.const 123456789e-5)) (f64.const 123456789e-5))
+(assert_return (invoke "f64_load" (f64.const 424242.424242)) (f64.const 424242.424242))
+(assert_return (invoke "f64_load" (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1023))
+
+
+(assert_return (invoke "i32_store16" (i32.const -1)) (i32.const 0xFFFF))
+(assert_return (invoke "i32_store16" (i32.const -4242)) (i32.const 61294))
+(assert_return (invoke "i32_store16" (i32.const 42)) (i32.const 42))
+(assert_return (invoke "i32_store16" (i32.const 0xCAFE)) (i32.const 0xCAFE))
+
+(assert_return (invoke "i32_store" (i32.const -1)) (i32.const -1))
+(assert_return (invoke "i32_store" (i32.const -4242)) (i32.const -4242))
+(assert_return (invoke "i32_store" (i32.const 42424242)) (i32.const 42424242))
+(assert_return (invoke "i32_store" (i32.const 0xDEADCAFE)) (i32.const 0xDEADCAFE))
+
+(assert_return (invoke "i64_store16" (i64.const -1)) (i64.const 0xFFFF))
+(assert_return (invoke "i64_store16" (i64.const -4242)) (i64.const 61294))
+(assert_return (invoke "i64_store16" (i64.const 42)) (i64.const 42))
+(assert_return (invoke "i64_store16" (i64.const 0xCAFE)) (i64.const 0xCAFE))
+
+(assert_return (invoke "i64_store32" (i64.const -1)) (i64.const 0xFFFFFFFF))
+(assert_return (invoke "i64_store32" (i64.const -4242)) (i64.const 4294963054))
+(assert_return (invoke "i64_store32" (i64.const 42424242)) (i64.const 42424242))
+(assert_return (invoke "i64_store32" (i64.const 0xDEADCAFE)) (i64.const 0xDEADCAFE))
+
+(assert_return (invoke "i64_store" (i64.const -1)) (i64.const -1))
+(assert_return (invoke "i64_store" (i64.const -42424242)) (i64.const -42424242))
+(assert_return (invoke "i64_store" (i64.const 0xABAD1DEA)) (i64.const 0xABAD1DEA))
+(assert_return (invoke "i64_store" (i64.const 0xABADCAFEDEAD1DEA)) (i64.const 0xABADCAFEDEAD1DEA))
+
+(assert_return (invoke "f32_store" (f32.const -1)) (f32.const -1))
+(assert_return (invoke "f32_store" (f32.const 1234e-5)) (f32.const 1234e-5))
+(assert_return (invoke "f32_store" (f32.const 4242.4242)) (f32.const 4242.4242))
+(assert_return (invoke "f32_store" (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+
+(assert_return (invoke "f64_store" (f64.const -1)) (f64.const -1))
+(assert_return (invoke "f64_store" (f64.const 123456789e-5)) (f64.const 123456789e-5))
+(assert_return (invoke "f64_store" (f64.const 424242.424242)) (f64.const 424242.424242))
+(assert_return (invoke "f64_store" (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1023))
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/spec/exports.wast
@@ -0,0 +1,26 @@
+(module (func (i32.const 1)) (export "a" 0))
+(module (func (i32.const 1)) (export "a" 0) (export "b" 0))
+(module (func (i32.const 1)) (func (i32.const 2)) (export "a" 0) (export "b" 1))
+(assert_invalid
+  (module (func (i32.const 1)) (export "a" 1))
+  "unknown function 1")
+(assert_invalid
+  (module (func (i32.const 1)) (func (i32.const 2)) (export "a" 0) (export "a" 1))
+  "duplicate export name")
+(assert_invalid
+  (module (func (i32.const 1)) (export "a" 0) (export "a" 0))
+  "duplicate export name")
+
+(module
+  (func $f (param $n i32) (result i32)
+    (return (i32.add (get_local $n) (i32.const 1)))
+  )
+
+  (export "e" $f)
+)
+
+(assert_return (invoke "e" (i32.const 42)) (i32.const 43))
+
+(module (memory 0 0) (export "a" memory))
+(module (memory 0 0) (export "a" memory) (export "b" memory))
+(assert_invalid (module (export "a" memory)) "no memory to export")
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/spec/f32.wast
@@ -0,0 +1,2429 @@
+;; Test all the f32 operators on major boundary values and all special
+;; values (except comparison operators, which are tested in f32_cmp.wast).
+
+(module
+  (func $add (param $x f32) (param $y f32) (result f32) (f32.add (get_local $x) (get_local $y)))
+  (func $sub (param $x f32) (param $y f32) (result f32) (f32.sub (get_local $x) (get_local $y)))
+  (func $mul (param $x f32) (param $y f32) (result f32) (f32.mul (get_local $x) (get_local $y)))
+  (func $div (param $x f32) (param $y f32) (result f32) (f32.div (get_local $x) (get_local $y)))
+  (func $sqrt (param $x f32) (result f32) (f32.sqrt (get_local $x)))
+  (func $min (param $x f32) (param $y f32) (result f32) (f32.min (get_local $x) (get_local $y)))
+  (func $max (param $x f32) (param $y f32) (result f32) (f32.max (get_local $x) (get_local $y)))
+  (func $ceil (param $x f32) (result f32) (f32.ceil (get_local $x)))
+  (func $floor (param $x f32) (result f32) (f32.floor (get_local $x)))
+  (func $trunc (param $x f32) (result f32) (f32.trunc (get_local $x)))
+  (func $nearest (param $x f32) (result f32) (f32.nearest (get_local $x)))
+  (func $abs (param $x f32) (result f32) (f32.abs (get_local $x)))
+  (func $neg (param $x f32) (result f32) (f32.neg (get_local $x)))
+  (func $copysign (param $x f32) (param $y f32) (result f32) (f32.copysign (get_local $x) (get_local $y)))
+
+  (export "add" $add)
+  (export "sub" $sub)
+  (export "mul" $mul)
+  (export "div" $div)
+  (export "sqrt" $sqrt)
+  (export "min" $min)
+  (export "max" $max)
+  (export "ceil" $ceil)
+  (export "floor" $floor)
+  (export "trunc" $trunc)
+  (export "nearest" $nearest)
+  (export "abs" $abs)
+  (export "neg" $neg)
+  (export "copysign" $copysign)
+)
+
+(assert_return (invoke "add" (f32.const -0x0p+0) (f32.const -0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "add" (f32.const -0x0p+0) (f32.const 0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "add" (f32.const 0x0p+0) (f32.const -0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "add" (f32.const 0x0p+0) (f32.const 0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "add" (f32.const -0x0p+0) (f32.const -0x1p-149)) (f32.const -0x1p-149))
+(assert_return (invoke "add" (f32.const -0x0p+0) (f32.const 0x1p-149)) (f32.const 0x1p-149))
+(assert_return (invoke "add" (f32.const 0x0p+0) (f32.const -0x1p-149)) (f32.const -0x1p-149))
+(assert_return (invoke "add" (f32.const 0x0p+0) (f32.const 0x1p-149)) (f32.const 0x1p-149))
+(assert_return (invoke "add" (f32.const -0x0p+0) (f32.const -0x1p-126)) (f32.const -0x1p-126))
+(assert_return (invoke "add" (f32.const -0x0p+0) (f32.const 0x1p-126)) (f32.const 0x1p-126))
+(assert_return (invoke "add" (f32.const 0x0p+0) (f32.const -0x1p-126)) (f32.const -0x1p-126))
+(assert_return (invoke "add" (f32.const 0x0p+0) (f32.const 0x1p-126)) (f32.const 0x1p-126))
+(assert_return (invoke "add" (f32.const -0x0p+0) (f32.const -0x1p-1)) (f32.const -0x1p-1))
+(assert_return (invoke "add" (f32.const -0x0p+0) (f32.const 0x1p-1)) (f32.const 0x1p-1))
+(assert_return (invoke "add" (f32.const 0x0p+0) (f32.const -0x1p-1)) (f32.const -0x1p-1))
+(assert_return (invoke "add" (f32.const 0x0p+0) (f32.const 0x1p-1)) (f32.const 0x1p-1))
+(assert_return (invoke "add" (f32.const -0x0p+0) (f32.const -0x1p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "add" (f32.const -0x0p+0) (f32.const 0x1p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "add" (f32.const 0x0p+0) (f32.const -0x1p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "add" (f32.const 0x0p+0) (f32.const 0x1p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "add" (f32.const -0x0p+0) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "add" (f32.const -0x0p+0) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "add" (f32.const 0x0p+0) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "add" (f32.const 0x0p+0) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "add" (f32.const -0x0p+0) (f32.const -0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const -0x0p+0) (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const 0x0p+0) (f32.const -0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const 0x0p+0) (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const -0x0p+0) (f32.const -infinity)) (f32.const -infinity))
+(assert_return (invoke "add" (f32.const -0x0p+0) (f32.const infinity)) (f32.const infinity))
+(assert_return (invoke "add" (f32.const 0x0p+0) (f32.const -infinity)) (f32.const -infinity))
+(assert_return (invoke "add" (f32.const 0x0p+0) (f32.const infinity)) (f32.const infinity))
+(assert_return (invoke "add" (f32.const -0x0p+0) (f32.const -nan)) (f32.const -nan))
+(assert_return (invoke "add" (f32.const -0x0p+0) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "add" (f32.const 0x0p+0) (f32.const -nan)) (f32.const -nan))
+(assert_return (invoke "add" (f32.const 0x0p+0) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "add" (f32.const -0x1p-149) (f32.const -0x0p+0)) (f32.const -0x1p-149))
+(assert_return (invoke "add" (f32.const -0x1p-149) (f32.const 0x0p+0)) (f32.const -0x1p-149))
+(assert_return (invoke "add" (f32.const 0x1p-149) (f32.const -0x0p+0)) (f32.const 0x1p-149))
+(assert_return (invoke "add" (f32.const 0x1p-149) (f32.const 0x0p+0)) (f32.const 0x1p-149))
+(assert_return (invoke "add" (f32.const -0x1p-149) (f32.const -0x1p-149)) (f32.const -0x1p-148))
+(assert_return (invoke "add" (f32.const -0x1p-149) (f32.const 0x1p-149)) (f32.const 0x0p+0))
+(assert_return (invoke "add" (f32.const 0x1p-149) (f32.const -0x1p-149)) (f32.const 0x0p+0))
+(assert_return (invoke "add" (f32.const 0x1p-149) (f32.const 0x1p-149)) (f32.const 0x1p-148))
+(assert_return (invoke "add" (f32.const -0x1p-149) (f32.const -0x1p-126)) (f32.const -0x1.000002p-126))
+(assert_return (invoke "add" (f32.const -0x1p-149) (f32.const 0x1p-126)) (f32.const 0x1.fffffcp-127))
+(assert_return (invoke "add" (f32.const 0x1p-149) (f32.const -0x1p-126)) (f32.const -0x1.fffffcp-127))
+(assert_return (invoke "add" (f32.const 0x1p-149) (f32.const 0x1p-126)) (f32.const 0x1.000002p-126))
+(assert_return (invoke "add" (f32.const -0x1p-149) (f32.const -0x1p-1)) (f32.const -0x1p-1))
+(assert_return (invoke "add" (f32.const -0x1p-149) (f32.const 0x1p-1)) (f32.const 0x1p-1))
+(assert_return (invoke "add" (f32.const 0x1p-149) (f32.const -0x1p-1)) (f32.const -0x1p-1))
+(assert_return (invoke "add" (f32.const 0x1p-149) (f32.const 0x1p-1)) (f32.const 0x1p-1))
+(assert_return (invoke "add" (f32.const -0x1p-149) (f32.const -0x1p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "add" (f32.const -0x1p-149) (f32.const 0x1p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "add" (f32.const 0x1p-149) (f32.const -0x1p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "add" (f32.const 0x1p-149) (f32.const 0x1p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "add" (f32.const -0x1p-149) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "add" (f32.const -0x1p-149) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "add" (f32.const 0x1p-149) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "add" (f32.const 0x1p-149) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "add" (f32.const -0x1p-149) (f32.const -0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const -0x1p-149) (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const 0x1p-149) (f32.const -0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const 0x1p-149) (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const -0x1p-149) (f32.const -infinity)) (f32.const -infinity))
+(assert_return (invoke "add" (f32.const -0x1p-149) (f32.const infinity)) (f32.const infinity))
+(assert_return (invoke "add" (f32.const 0x1p-149) (f32.const -infinity)) (f32.const -infinity))
+(assert_return (invoke "add" (f32.const 0x1p-149) (f32.const infinity)) (f32.const infinity))
+(assert_return (invoke "add" (f32.const -0x1p-149) (f32.const -nan)) (f32.const -nan))
+(assert_return (invoke "add" (f32.const -0x1p-149) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "add" (f32.const 0x1p-149) (f32.const -nan)) (f32.const -nan))
+(assert_return (invoke "add" (f32.const 0x1p-149) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "add" (f32.const -0x1p-126) (f32.const -0x0p+0)) (f32.const -0x1p-126))
+(assert_return (invoke "add" (f32.const -0x1p-126) (f32.const 0x0p+0)) (f32.const -0x1p-126))
+(assert_return (invoke "add" (f32.const 0x1p-126) (f32.const -0x0p+0)) (f32.const 0x1p-126))
+(assert_return (invoke "add" (f32.const 0x1p-126) (f32.const 0x0p+0)) (f32.const 0x1p-126))
+(assert_return (invoke "add" (f32.const -0x1p-126) (f32.const -0x1p-149)) (f32.const -0x1.000002p-126))
+(assert_return (invoke "add" (f32.const -0x1p-126) (f32.const 0x1p-149)) (f32.const -0x1.fffffcp-127))
+(assert_return (invoke "add" (f32.const 0x1p-126) (f32.const -0x1p-149)) (f32.const 0x1.fffffcp-127))
+(assert_return (invoke "add" (f32.const 0x1p-126) (f32.const 0x1p-149)) (f32.const 0x1.000002p-126))
+(assert_return (invoke "add" (f32.const -0x1p-126) (f32.const -0x1p-126)) (f32.const -0x1p-125))
+(assert_return (invoke "add" (f32.const -0x1p-126) (f32.const 0x1p-126)) (f32.const 0x0p+0))
+(assert_return (invoke "add" (f32.const 0x1p-126) (f32.const -0x1p-126)) (f32.const 0x0p+0))
+(assert_return (invoke "add" (f32.const 0x1p-126) (f32.const 0x1p-126)) (f32.const 0x1p-125))
+(assert_return (invoke "add" (f32.const -0x1p-126) (f32.const -0x1p-1)) (f32.const -0x1p-1))
+(assert_return (invoke "add" (f32.const -0x1p-126) (f32.const 0x1p-1)) (f32.const 0x1p-1))
+(assert_return (invoke "add" (f32.const 0x1p-126) (f32.const -0x1p-1)) (f32.const -0x1p-1))
+(assert_return (invoke "add" (f32.const 0x1p-126) (f32.const 0x1p-1)) (f32.const 0x1p-1))
+(assert_return (invoke "add" (f32.const -0x1p-126) (f32.const -0x1p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "add" (f32.const -0x1p-126) (f32.const 0x1p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "add" (f32.const 0x1p-126) (f32.const -0x1p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "add" (f32.const 0x1p-126) (f32.const 0x1p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "add" (f32.const -0x1p-126) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "add" (f32.const -0x1p-126) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "add" (f32.const 0x1p-126) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "add" (f32.const 0x1p-126) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "add" (f32.const -0x1p-126) (f32.const -0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const -0x1p-126) (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const 0x1p-126) (f32.const -0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const 0x1p-126) (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const -0x1p-126) (f32.const -infinity)) (f32.const -infinity))
+(assert_return (invoke "add" (f32.const -0x1p-126) (f32.const infinity)) (f32.const infinity))
+(assert_return (invoke "add" (f32.const 0x1p-126) (f32.const -infinity)) (f32.const -infinity))
+(assert_return (invoke "add" (f32.const 0x1p-126) (f32.const infinity)) (f32.const infinity))
+(assert_return (invoke "add" (f32.const -0x1p-126) (f32.const -nan)) (f32.const -nan))
+(assert_return (invoke "add" (f32.const -0x1p-126) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "add" (f32.const 0x1p-126) (f32.const -nan)) (f32.const -nan))
+(assert_return (invoke "add" (f32.const 0x1p-126) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "add" (f32.const -0x1p-1) (f32.const -0x0p+0)) (f32.const -0x1p-1))
+(assert_return (invoke "add" (f32.const -0x1p-1) (f32.const 0x0p+0)) (f32.const -0x1p-1))
+(assert_return (invoke "add" (f32.const 0x1p-1) (f32.const -0x0p+0)) (f32.const 0x1p-1))
+(assert_return (invoke "add" (f32.const 0x1p-1) (f32.const 0x0p+0)) (f32.const 0x1p-1))
+(assert_return (invoke "add" (f32.const -0x1p-1) (f32.const -0x1p-149)) (f32.const -0x1p-1))
+(assert_return (invoke "add" (f32.const -0x1p-1) (f32.const 0x1p-149)) (f32.const -0x1p-1))
+(assert_return (invoke "add" (f32.const 0x1p-1) (f32.const -0x1p-149)) (f32.const 0x1p-1))
+(assert_return (invoke "add" (f32.const 0x1p-1) (f32.const 0x1p-149)) (f32.const 0x1p-1))
+(assert_return (invoke "add" (f32.const -0x1p-1) (f32.const -0x1p-126)) (f32.const -0x1p-1))
+(assert_return (invoke "add" (f32.const -0x1p-1) (f32.const 0x1p-126)) (f32.const -0x1p-1))
+(assert_return (invoke "add" (f32.const 0x1p-1) (f32.const -0x1p-126)) (f32.const 0x1p-1))
+(assert_return (invoke "add" (f32.const 0x1p-1) (f32.const 0x1p-126)) (f32.const 0x1p-1))
+(assert_return (invoke "add" (f32.const -0x1p-1) (f32.const -0x1p-1)) (f32.const -0x1p+0))
+(assert_return (invoke "add" (f32.const -0x1p-1) (f32.const 0x1p-1)) (f32.const 0x0p+0))
+(assert_return (invoke "add" (f32.const 0x1p-1) (f32.const -0x1p-1)) (f32.const 0x0p+0))
+(assert_return (invoke "add" (f32.const 0x1p-1) (f32.const 0x1p-1)) (f32.const 0x1p+0))
+(assert_return (invoke "add" (f32.const -0x1p-1) (f32.const -0x1p+0)) (f32.const -0x1.8p+0))
+(assert_return (invoke "add" (f32.const -0x1p-1) (f32.const 0x1p+0)) (f32.const 0x1p-1))
+(assert_return (invoke "add" (f32.const 0x1p-1) (f32.const -0x1p+0)) (f32.const -0x1p-1))
+(assert_return (invoke "add" (f32.const 0x1p-1) (f32.const 0x1p+0)) (f32.const 0x1.8p+0))
+(assert_return (invoke "add" (f32.const -0x1p-1) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.b21fb6p+2))
+(assert_return (invoke "add" (f32.const -0x1p-1) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.721fb6p+2))
+(assert_return (invoke "add" (f32.const 0x1p-1) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.721fb6p+2))
+(assert_return (invoke "add" (f32.const 0x1p-1) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.b21fb6p+2))
+(assert_return (invoke "add" (f32.const -0x1p-1) (f32.const -0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const -0x1p-1) (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const 0x1p-1) (f32.const -0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const 0x1p-1) (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const -0x1p-1) (f32.const -infinity)) (f32.const -infinity))
+(assert_return (invoke "add" (f32.const -0x1p-1) (f32.const infinity)) (f32.const infinity))
+(assert_return (invoke "add" (f32.const 0x1p-1) (f32.const -infinity)) (f32.const -infinity))
+(assert_return (invoke "add" (f32.const 0x1p-1) (f32.const infinity)) (f32.const infinity))
+(assert_return (invoke "add" (f32.const -0x1p-1) (f32.const -nan)) (f32.const -nan))
+(assert_return (invoke "add" (f32.const -0x1p-1) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "add" (f32.const 0x1p-1) (f32.const -nan)) (f32.const -nan))
+(assert_return (invoke "add" (f32.const 0x1p-1) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "add" (f32.const -0x1p+0) (f32.const -0x0p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "add" (f32.const -0x1p+0) (f32.const 0x0p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "add" (f32.const 0x1p+0) (f32.const -0x0p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "add" (f32.const 0x1p+0) (f32.const 0x0p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "add" (f32.const -0x1p+0) (f32.const -0x1p-149)) (f32.const -0x1p+0))
+(assert_return (invoke "add" (f32.const -0x1p+0) (f32.const 0x1p-149)) (f32.const -0x1p+0))
+(assert_return (invoke "add" (f32.const 0x1p+0) (f32.const -0x1p-149)) (f32.const 0x1p+0))
+(assert_return (invoke "add" (f32.const 0x1p+0) (f32.const 0x1p-149)) (f32.const 0x1p+0))
+(assert_return (invoke "add" (f32.const -0x1p+0) (f32.const -0x1p-126)) (f32.const -0x1p+0))
+(assert_return (invoke "add" (f32.const -0x1p+0) (f32.const 0x1p-126)) (f32.const -0x1p+0))
+(assert_return (invoke "add" (f32.const 0x1p+0) (f32.const -0x1p-126)) (f32.const 0x1p+0))
+(assert_return (invoke "add" (f32.const 0x1p+0) (f32.const 0x1p-126)) (f32.const 0x1p+0))
+(assert_return (invoke "add" (f32.const -0x1p+0) (f32.const -0x1p-1)) (f32.const -0x1.8p+0))
+(assert_return (invoke "add" (f32.const -0x1p+0) (f32.const 0x1p-1)) (f32.const -0x1p-1))
+(assert_return (invoke "add" (f32.const 0x1p+0) (f32.const -0x1p-1)) (f32.const 0x1p-1))
+(assert_return (invoke "add" (f32.const 0x1p+0) (f32.const 0x1p-1)) (f32.const 0x1.8p+0))
+(assert_return (invoke "add" (f32.const -0x1p+0) (f32.const -0x1p+0)) (f32.const -0x1p+1))
+(assert_return (invoke "add" (f32.const -0x1p+0) (f32.const 0x1p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "add" (f32.const 0x1p+0) (f32.const -0x1p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "add" (f32.const 0x1p+0) (f32.const 0x1p+0)) (f32.const 0x1p+1))
+(assert_return (invoke "add" (f32.const -0x1p+0) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.d21fb6p+2))
+(assert_return (invoke "add" (f32.const -0x1p+0) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.521fb6p+2))
+(assert_return (invoke "add" (f32.const 0x1p+0) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.521fb6p+2))
+(assert_return (invoke "add" (f32.const 0x1p+0) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.d21fb6p+2))
+(assert_return (invoke "add" (f32.const -0x1p+0) (f32.const -0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const -0x1p+0) (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const 0x1p+0) (f32.const -0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const 0x1p+0) (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const -0x1p+0) (f32.const -infinity)) (f32.const -infinity))
+(assert_return (invoke "add" (f32.const -0x1p+0) (f32.const infinity)) (f32.const infinity))
+(assert_return (invoke "add" (f32.const 0x1p+0) (f32.const -infinity)) (f32.const -infinity))
+(assert_return (invoke "add" (f32.const 0x1p+0) (f32.const infinity)) (f32.const infinity))
+(assert_return (invoke "add" (f32.const -0x1p+0) (f32.const -nan)) (f32.const -nan))
+(assert_return (invoke "add" (f32.const -0x1p+0) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "add" (f32.const 0x1p+0) (f32.const -nan)) (f32.const -nan))
+(assert_return (invoke "add" (f32.const 0x1p+0) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "add" (f32.const -0x1.921fb6p+2) (f32.const -0x0p+0)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "add" (f32.const -0x1.921fb6p+2) (f32.const 0x0p+0)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "add" (f32.const 0x1.921fb6p+2) (f32.const -0x0p+0)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "add" (f32.const 0x1.921fb6p+2) (f32.const 0x0p+0)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "add" (f32.const -0x1.921fb6p+2) (f32.const -0x1p-149)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "add" (f32.const -0x1.921fb6p+2) (f32.const 0x1p-149)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "add" (f32.const 0x1.921fb6p+2) (f32.const -0x1p-149)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "add" (f32.const 0x1.921fb6p+2) (f32.const 0x1p-149)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "add" (f32.const -0x1.921fb6p+2) (f32.const -0x1p-126)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "add" (f32.const -0x1.921fb6p+2) (f32.const 0x1p-126)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "add" (f32.const 0x1.921fb6p+2) (f32.const -0x1p-126)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "add" (f32.const 0x1.921fb6p+2) (f32.const 0x1p-126)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "add" (f32.const -0x1.921fb6p+2) (f32.const -0x1p-1)) (f32.const -0x1.b21fb6p+2))
+(assert_return (invoke "add" (f32.const -0x1.921fb6p+2) (f32.const 0x1p-1)) (f32.const -0x1.721fb6p+2))
+(assert_return (invoke "add" (f32.const 0x1.921fb6p+2) (f32.const -0x1p-1)) (f32.const 0x1.721fb6p+2))
+(assert_return (invoke "add" (f32.const 0x1.921fb6p+2) (f32.const 0x1p-1)) (f32.const 0x1.b21fb6p+2))
+(assert_return (invoke "add" (f32.const -0x1.921fb6p+2) (f32.const -0x1p+0)) (f32.const -0x1.d21fb6p+2))
+(assert_return (invoke "add" (f32.const -0x1.921fb6p+2) (f32.const 0x1p+0)) (f32.const -0x1.521fb6p+2))
+(assert_return (invoke "add" (f32.const 0x1.921fb6p+2) (f32.const -0x1p+0)) (f32.const 0x1.521fb6p+2))
+(assert_return (invoke "add" (f32.const 0x1.921fb6p+2) (f32.const 0x1p+0)) (f32.const 0x1.d21fb6p+2))
+(assert_return (invoke "add" (f32.const -0x1.921fb6p+2) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.921fb6p+3))
+(assert_return (invoke "add" (f32.const -0x1.921fb6p+2) (f32.const 0x1.921fb6p+2)) (f32.const 0x0p+0))
+(assert_return (invoke "add" (f32.const 0x1.921fb6p+2) (f32.const -0x1.921fb6p+2)) (f32.const 0x0p+0))
+(assert_return (invoke "add" (f32.const 0x1.921fb6p+2) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.921fb6p+3))
+(assert_return (invoke "add" (f32.const -0x1.921fb6p+2) (f32.const -0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const -0x1.921fb6p+2) (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const 0x1.921fb6p+2) (f32.const -0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const 0x1.921fb6p+2) (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const -0x1.921fb6p+2) (f32.const -infinity)) (f32.const -infinity))
+(assert_return (invoke "add" (f32.const -0x1.921fb6p+2) (f32.const infinity)) (f32.const infinity))
+(assert_return (invoke "add" (f32.const 0x1.921fb6p+2) (f32.const -infinity)) (f32.const -infinity))
+(assert_return (invoke "add" (f32.const 0x1.921fb6p+2) (f32.const infinity)) (f32.const infinity))
+(assert_return (invoke "add" (f32.const -0x1.921fb6p+2) (f32.const -nan)) (f32.const -nan))
+(assert_return (invoke "add" (f32.const -0x1.921fb6p+2) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "add" (f32.const 0x1.921fb6p+2) (f32.const -nan)) (f32.const -nan))
+(assert_return (invoke "add" (f32.const 0x1.921fb6p+2) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "add" (f32.const -0x1.fffffep+127) (f32.const -0x0p+0)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const -0x1.fffffep+127) (f32.const 0x0p+0)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const 0x1.fffffep+127) (f32.const -0x0p+0)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const 0x1.fffffep+127) (f32.const 0x0p+0)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const -0x1.fffffep+127) (f32.const -0x1p-149)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const -0x1.fffffep+127) (f32.const 0x1p-149)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const 0x1.fffffep+127) (f32.const -0x1p-149)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const 0x1.fffffep+127) (f32.const 0x1p-149)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const -0x1.fffffep+127) (f32.const -0x1p-126)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const -0x1.fffffep+127) (f32.const 0x1p-126)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const 0x1.fffffep+127) (f32.const -0x1p-126)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const 0x1.fffffep+127) (f32.const 0x1p-126)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const -0x1.fffffep+127) (f32.const -0x1p-1)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const -0x1.fffffep+127) (f32.const 0x1p-1)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const 0x1.fffffep+127) (f32.const -0x1p-1)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const 0x1.fffffep+127) (f32.const 0x1p-1)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const -0x1.fffffep+127) (f32.const -0x1p+0)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const -0x1.fffffep+127) (f32.const 0x1p+0)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const 0x1.fffffep+127) (f32.const -0x1p+0)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const 0x1.fffffep+127) (f32.const 0x1p+0)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const -0x1.fffffep+127) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const -0x1.fffffep+127) (f32.const 0x1.921fb6p+2)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const 0x1.fffffep+127) (f32.const -0x1.921fb6p+2)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const 0x1.fffffep+127) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const -0x1.fffffep+127) (f32.const -0x1.fffffep+127)) (f32.const -infinity))
+(assert_return (invoke "add" (f32.const -0x1.fffffep+127) (f32.const 0x1.fffffep+127)) (f32.const 0x0p+0))
+(assert_return (invoke "add" (f32.const 0x1.fffffep+127) (f32.const -0x1.fffffep+127)) (f32.const 0x0p+0))
+(assert_return (invoke "add" (f32.const 0x1.fffffep+127) (f32.const 0x1.fffffep+127)) (f32.const infinity))
+(assert_return (invoke "add" (f32.const -0x1.fffffep+127) (f32.const -infinity)) (f32.const -infinity))
+(assert_return (invoke "add" (f32.const -0x1.fffffep+127) (f32.const infinity)) (f32.const infinity))
+(assert_return (invoke "add" (f32.const 0x1.fffffep+127) (f32.const -infinity)) (f32.const -infinity))
+(assert_return (invoke "add" (f32.const 0x1.fffffep+127) (f32.const infinity)) (f32.const infinity))
+(assert_return (invoke "add" (f32.const -0x1.fffffep+127) (f32.const -nan)) (f32.const -nan))
+(assert_return (invoke "add" (f32.const -0x1.fffffep+127) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "add" (f32.const 0x1.fffffep+127) (f32.const -nan)) (f32.const -nan))
+(assert_return (invoke "add" (f32.const 0x1.fffffep+127) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "add" (f32.const -infinity) (f32.const -0x0p+0)) (f32.const -infinity))
+(assert_return (invoke "add" (f32.const -infinity) (f32.const 0x0p+0)) (f32.const -infinity))
+(assert_return (invoke "add" (f32.const infinity) (f32.const -0x0p+0)) (f32.const infinity))
+(assert_return (invoke "add" (f32.const infinity) (f32.const 0x0p+0)) (f32.const infinity))
+(assert_return (invoke "add" (f32.const -infinity) (f32.const -0x1p-149)) (f32.const -infinity))
+(assert_return (invoke "add" (f32.const -infinity) (f32.const 0x1p-149)) (f32.const -infinity))
+(assert_return (invoke "add" (f32.const infinity) (f32.const -0x1p-149)) (f32.const infinity))
+(assert_return (invoke "add" (f32.const infinity) (f32.const 0x1p-149)) (f32.const infinity))
+(assert_return (invoke "add" (f32.const -infinity) (f32.const -0x1p-126)) (f32.const -infinity))
+(assert_return (invoke "add" (f32.const -infinity) (f32.const 0x1p-126)) (f32.const -infinity))
+(assert_return (invoke "add" (f32.const infinity) (f32.const -0x1p-126)) (f32.const infinity))
+(assert_return (invoke "add" (f32.const infinity) (f32.const 0x1p-126)) (f32.const infinity))
+(assert_return (invoke "add" (f32.const -infinity) (f32.const -0x1p-1)) (f32.const -infinity))
+(assert_return (invoke "add" (f32.const -infinity) (f32.const 0x1p-1)) (f32.const -infinity))
+(assert_return (invoke "add" (f32.const infinity) (f32.const -0x1p-1)) (f32.const infinity))
+(assert_return (invoke "add" (f32.const infinity) (f32.const 0x1p-1)) (f32.const infinity))
+(assert_return (invoke "add" (f32.const -infinity) (f32.const -0x1p+0)) (f32.const -infinity))
+(assert_return (invoke "add" (f32.const -infinity) (f32.const 0x1p+0)) (f32.const -infinity))
+(assert_return (invoke "add" (f32.const infinity) (f32.const -0x1p+0)) (f32.const infinity))
+(assert_return (invoke "add" (f32.const infinity) (f32.const 0x1p+0)) (f32.const infinity))
+(assert_return (invoke "add" (f32.const -infinity) (f32.const -0x1.921fb6p+2)) (f32.const -infinity))
+(assert_return (invoke "add" (f32.const -infinity) (f32.const 0x1.921fb6p+2)) (f32.const -infinity))
+(assert_return (invoke "add" (f32.const infinity) (f32.const -0x1.921fb6p+2)) (f32.const infinity))
+(assert_return (invoke "add" (f32.const infinity) (f32.const 0x1.921fb6p+2)) (f32.const infinity))
+(assert_return (invoke "add" (f32.const -infinity) (f32.const -0x1.fffffep+127)) (f32.const -infinity))
+(assert_return (invoke "add" (f32.const -infinity) (f32.const 0x1.fffffep+127)) (f32.const -infinity))
+(assert_return (invoke "add" (f32.const infinity) (f32.const -0x1.fffffep+127)) (f32.const infinity))
+(assert_return (invoke "add" (f32.const infinity) (f32.const 0x1.fffffep+127)) (f32.const infinity))
+(assert_return (invoke "add" (f32.const -infinity) (f32.const -infinity)) (f32.const -infinity))
+(assert_return_nan (invoke "add" (f32.const -infinity) (f32.const infinity)))
+(assert_return_nan (invoke "add" (f32.const infinity) (f32.const -infinity)))
+(assert_return (invoke "add" (f32.const infinity) (f32.const infinity)) (f32.const infinity))
+(assert_return (invoke "add" (f32.const -infinity) (f32.const -nan)) (f32.const -nan))
+(assert_return (invoke "add" (f32.const -infinity) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "add" (f32.const infinity) (f32.const -nan)) (f32.const -nan))
+(assert_return (invoke "add" (f32.const infinity) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "add" (f32.const -nan) (f32.const -0x0p+0)) (f32.const -nan))
+(assert_return (invoke "add" (f32.const -nan) (f32.const 0x0p+0)) (f32.const -nan))
+(assert_return (invoke "add" (f32.const nan) (f32.const -0x0p+0)) (f32.const nan))
+(assert_return (invoke "add" (f32.const nan) (f32.const 0x0p+0)) (f32.const nan))
+(assert_return (invoke "add" (f32.const -nan) (f32.const -0x1p-149)) (f32.const -nan))
+(assert_return (invoke "add" (f32.const -nan) (f32.const 0x1p-149)) (f32.const -nan))
+(assert_return (invoke "add" (f32.const nan) (f32.const -0x1p-149)) (f32.const nan))
+(assert_return (invoke "add" (f32.const nan) (f32.const 0x1p-149)) (f32.const nan))
+(assert_return (invoke "add" (f32.const -nan) (f32.const -0x1p-126)) (f32.const -nan))
+(assert_return (invoke "add" (f32.const -nan) (f32.const 0x1p-126)) (f32.const -nan))
+(assert_return (invoke "add" (f32.const nan) (f32.const -0x1p-126)) (f32.const nan))
+(assert_return (invoke "add" (f32.const nan) (f32.const 0x1p-126)) (f32.const nan))
+(assert_return (invoke "add" (f32.const -nan) (f32.const -0x1p-1)) (f32.const -nan))
+(assert_return (invoke "add" (f32.const -nan) (f32.const 0x1p-1)) (f32.const -nan))
+(assert_return (invoke "add" (f32.const nan) (f32.const -0x1p-1)) (f32.const nan))
+(assert_return (invoke "add" (f32.const nan) (f32.const 0x1p-1)) (f32.const nan))
+(assert_return (invoke "add" (f32.const -nan) (f32.const -0x1p+0)) (f32.const -nan))
+(assert_return (invoke "add" (f32.const -nan) (f32.const 0x1p+0)) (f32.const -nan))
+(assert_return (invoke "add" (f32.const nan) (f32.const -0x1p+0)) (f32.const nan))
+(assert_return (invoke "add" (f32.const nan) (f32.const 0x1p+0)) (f32.const nan))
+(assert_return (invoke "add" (f32.const -nan) (f32.const -0x1.921fb6p+2)) (f32.const -nan))
+(assert_return (invoke "add" (f32.const -nan) (f32.const 0x1.921fb6p+2)) (f32.const -nan))
+(assert_return (invoke "add" (f32.const nan) (f32.const -0x1.921fb6p+2)) (f32.const nan))
+(assert_return (invoke "add" (f32.const nan) (f32.const 0x1.921fb6p+2)) (f32.const nan))
+(assert_return (invoke "add" (f32.const -nan) (f32.const -0x1.fffffep+127)) (f32.const -nan))
+(assert_return (invoke "add" (f32.const -nan) (f32.const 0x1.fffffep+127)) (f32.const -nan))
+(assert_return (invoke "add" (f32.const nan) (f32.const -0x1.fffffep+127)) (f32.const nan))
+(assert_return (invoke "add" (f32.const nan) (f32.const 0x1.fffffep+127)) (f32.const nan))
+(assert_return (invoke "add" (f32.const -nan) (f32.const -infinity)) (f32.const -nan))
+(assert_return (invoke "add" (f32.const -nan) (f32.const infinity)) (f32.const -nan))
+(assert_return (invoke "add" (f32.const nan) (f32.const -infinity)) (f32.const nan))
+(assert_return (invoke "add" (f32.const nan) (f32.const infinity)) (f32.const nan))
+(assert_return (invoke "add" (f32.const -nan) (f32.const -nan)) (f32.const -nan))
+(assert_return_nan (invoke "add" (f32.const -nan) (f32.const nan)))
+(assert_return_nan (invoke "add" (f32.const nan) (f32.const -nan)))
+(assert_return (invoke "add" (f32.const nan) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "sub" (f32.const -0x0p+0) (f32.const -0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "sub" (f32.const -0x0p+0) (f32.const 0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "sub" (f32.const 0x0p+0) (f32.const -0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "sub" (f32.const 0x0p+0) (f32.const 0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "sub" (f32.const -0x0p+0) (f32.const -0x1p-149)) (f32.const 0x1p-149))
+(assert_return (invoke "sub" (f32.const -0x0p+0) (f32.const 0x1p-149)) (f32.const -0x1p-149))
+(assert_return (invoke "sub" (f32.const 0x0p+0) (f32.const -0x1p-149)) (f32.const 0x1p-149))
+(assert_return (invoke "sub" (f32.const 0x0p+0) (f32.const 0x1p-149)) (f32.const -0x1p-149))
+(assert_return (invoke "sub" (f32.const -0x0p+0) (f32.const -0x1p-126)) (f32.const 0x1p-126))
+(assert_return (invoke "sub" (f32.const -0x0p+0) (f32.const 0x1p-126)) (f32.const -0x1p-126))
+(assert_return (invoke "sub" (f32.const 0x0p+0) (f32.const -0x1p-126)) (f32.const 0x1p-126))
+(assert_return (invoke "sub" (f32.const 0x0p+0) (f32.const 0x1p-126)) (f32.const -0x1p-126))
+(assert_return (invoke "sub" (f32.const -0x0p+0) (f32.const -0x1p-1)) (f32.const 0x1p-1))
+(assert_return (invoke "sub" (f32.const -0x0p+0) (f32.const 0x1p-1)) (f32.const -0x1p-1))
+(assert_return (invoke "sub" (f32.const 0x0p+0) (f32.const -0x1p-1)) (f32.const 0x1p-1))
+(assert_return (invoke "sub" (f32.const 0x0p+0) (f32.const 0x1p-1)) (f32.const -0x1p-1))
+(assert_return (invoke "sub" (f32.const -0x0p+0) (f32.const -0x1p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "sub" (f32.const -0x0p+0) (f32.const 0x1p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "sub" (f32.const 0x0p+0) (f32.const -0x1p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "sub" (f32.const 0x0p+0) (f32.const 0x1p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "sub" (f32.const -0x0p+0) (f32.const -0x1.921fb6p+2)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "sub" (f32.const -0x0p+0) (f32.const 0x1.921fb6p+2)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "sub" (f32.const 0x0p+0) (f32.const -0x1.921fb6p+2)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "sub" (f32.const 0x0p+0) (f32.const 0x1.921fb6p+2)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "sub" (f32.const -0x0p+0) (f32.const -0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const -0x0p+0) (f32.const 0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const 0x0p+0) (f32.const -0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const 0x0p+0) (f32.const 0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const -0x0p+0) (f32.const -infinity)) (f32.const infinity))
+(assert_return (invoke "sub" (f32.const -0x0p+0) (f32.const infinity)) (f32.const -infinity))
+(assert_return (invoke "sub" (f32.const 0x0p+0) (f32.const -infinity)) (f32.const infinity))
+(assert_return (invoke "sub" (f32.const 0x0p+0) (f32.const infinity)) (f32.const -infinity))
+(assert_return (invoke "sub" (f32.const -0x0p+0) (f32.const -nan)) (f32.const -nan))
+(assert_return (invoke "sub" (f32.const -0x0p+0) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "sub" (f32.const 0x0p+0) (f32.const -nan)) (f32.const -nan))
+(assert_return (invoke "sub" (f32.const 0x0p+0) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "sub" (f32.const -0x1p-149) (f32.const -0x0p+0)) (f32.const -0x1p-149))
+(assert_return (invoke "sub" (f32.const -0x1p-149) (f32.const 0x0p+0)) (f32.const -0x1p-149))
+(assert_return (invoke "sub" (f32.const 0x1p-149) (f32.const -0x0p+0)) (f32.const 0x1p-149))
+(assert_return (invoke "sub" (f32.const 0x1p-149) (f32.const 0x0p+0)) (f32.const 0x1p-149))
+(assert_return (invoke "sub" (f32.const -0x1p-149) (f32.const -0x1p-149)) (f32.const 0x0p+0))
+(assert_return (invoke "sub" (f32.const -0x1p-149) (f32.const 0x1p-149)) (f32.const -0x1p-148))
+(assert_return (invoke "sub" (f32.const 0x1p-149) (f32.const -0x1p-149)) (f32.const 0x1p-148))
+(assert_return (invoke "sub" (f32.const 0x1p-149) (f32.const 0x1p-149)) (f32.const 0x0p+0))
+(assert_return (invoke "sub" (f32.const -0x1p-149) (f32.const -0x1p-126)) (f32.const 0x1.fffffcp-127))
+(assert_return (invoke "sub" (f32.const -0x1p-149) (f32.const 0x1p-126)) (f32.const -0x1.000002p-126))
+(assert_return (invoke "sub" (f32.const 0x1p-149) (f32.const -0x1p-126)) (f32.const 0x1.000002p-126))
+(assert_return (invoke "sub" (f32.const 0x1p-149) (f32.const 0x1p-126)) (f32.const -0x1.fffffcp-127))
+(assert_return (invoke "sub" (f32.const -0x1p-149) (f32.const -0x1p-1)) (f32.const 0x1p-1))
+(assert_return (invoke "sub" (f32.const -0x1p-149) (f32.const 0x1p-1)) (f32.const -0x1p-1))
+(assert_return (invoke "sub" (f32.const 0x1p-149) (f32.const -0x1p-1)) (f32.const 0x1p-1))
+(assert_return (invoke "sub" (f32.const 0x1p-149) (f32.const 0x1p-1)) (f32.const -0x1p-1))
+(assert_return (invoke "sub" (f32.const -0x1p-149) (f32.const -0x1p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "sub" (f32.const -0x1p-149) (f32.const 0x1p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "sub" (f32.const 0x1p-149) (f32.const -0x1p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "sub" (f32.const 0x1p-149) (f32.const 0x1p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "sub" (f32.const -0x1p-149) (f32.const -0x1.921fb6p+2)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "sub" (f32.const -0x1p-149) (f32.const 0x1.921fb6p+2)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "sub" (f32.const 0x1p-149) (f32.const -0x1.921fb6p+2)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "sub" (f32.const 0x1p-149) (f32.const 0x1.921fb6p+2)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "sub" (f32.const -0x1p-149) (f32.const -0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const -0x1p-149) (f32.const 0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const 0x1p-149) (f32.const -0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const 0x1p-149) (f32.const 0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const -0x1p-149) (f32.const -infinity)) (f32.const infinity))
+(assert_return (invoke "sub" (f32.const -0x1p-149) (f32.const infinity)) (f32.const -infinity))
+(assert_return (invoke "sub" (f32.const 0x1p-149) (f32.const -infinity)) (f32.const infinity))
+(assert_return (invoke "sub" (f32.const 0x1p-149) (f32.const infinity)) (f32.const -infinity))
+(assert_return (invoke "sub" (f32.const -0x1p-149) (f32.const -nan)) (f32.const -nan))
+(assert_return (invoke "sub" (f32.const -0x1p-149) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "sub" (f32.const 0x1p-149) (f32.const -nan)) (f32.const -nan))
+(assert_return (invoke "sub" (f32.const 0x1p-149) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "sub" (f32.const -0x1p-126) (f32.const -0x0p+0)) (f32.const -0x1p-126))
+(assert_return (invoke "sub" (f32.const -0x1p-126) (f32.const 0x0p+0)) (f32.const -0x1p-126))
+(assert_return (invoke "sub" (f32.const 0x1p-126) (f32.const -0x0p+0)) (f32.const 0x1p-126))
+(assert_return (invoke "sub" (f32.const 0x1p-126) (f32.const 0x0p+0)) (f32.const 0x1p-126))
+(assert_return (invoke "sub" (f32.const -0x1p-126) (f32.const -0x1p-149)) (f32.const -0x1.fffffcp-127))
+(assert_return (invoke "sub" (f32.const -0x1p-126) (f32.const 0x1p-149)) (f32.const -0x1.000002p-126))
+(assert_return (invoke "sub" (f32.const 0x1p-126) (f32.const -0x1p-149)) (f32.const 0x1.000002p-126))
+(assert_return (invoke "sub" (f32.const 0x1p-126) (f32.const 0x1p-149)) (f32.const 0x1.fffffcp-127))
+(assert_return (invoke "sub" (f32.const -0x1p-126) (f32.const -0x1p-126)) (f32.const 0x0p+0))
+(assert_return (invoke "sub" (f32.const -0x1p-126) (f32.const 0x1p-126)) (f32.const -0x1p-125))
+(assert_return (invoke "sub" (f32.const 0x1p-126) (f32.const -0x1p-126)) (f32.const 0x1p-125))
+(assert_return (invoke "sub" (f32.const 0x1p-126) (f32.const 0x1p-126)) (f32.const 0x0p+0))
+(assert_return (invoke "sub" (f32.const -0x1p-126) (f32.const -0x1p-1)) (f32.const 0x1p-1))
+(assert_return (invoke "sub" (f32.const -0x1p-126) (f32.const 0x1p-1)) (f32.const -0x1p-1))
+(assert_return (invoke "sub" (f32.const 0x1p-126) (f32.const -0x1p-1)) (f32.const 0x1p-1))
+(assert_return (invoke "sub" (f32.const 0x1p-126) (f32.const 0x1p-1)) (f32.const -0x1p-1))
+(assert_return (invoke "sub" (f32.const -0x1p-126) (f32.const -0x1p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "sub" (f32.const -0x1p-126) (f32.const 0x1p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "sub" (f32.const 0x1p-126) (f32.const -0x1p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "sub" (f32.const 0x1p-126) (f32.const 0x1p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "sub" (f32.const -0x1p-126) (f32.const -0x1.921fb6p+2)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "sub" (f32.const -0x1p-126) (f32.const 0x1.921fb6p+2)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "sub" (f32.const 0x1p-126) (f32.const -0x1.921fb6p+2)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "sub" (f32.const 0x1p-126) (f32.const 0x1.921fb6p+2)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "sub" (f32.const -0x1p-126) (f32.const -0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const -0x1p-126) (f32.const 0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const 0x1p-126) (f32.const -0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const 0x1p-126) (f32.const 0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const -0x1p-126) (f32.const -infinity)) (f32.const infinity))
+(assert_return (invoke "sub" (f32.const -0x1p-126) (f32.const infinity)) (f32.const -infinity))
+(assert_return (invoke "sub" (f32.const 0x1p-126) (f32.const -infinity)) (f32.const infinity))
+(assert_return (invoke "sub" (f32.const 0x1p-126) (f32.const infinity)) (f32.const -infinity))
+(assert_return (invoke "sub" (f32.const -0x1p-126) (f32.const -nan)) (f32.const -nan))
+(assert_return (invoke "sub" (f32.const -0x1p-126) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "sub" (f32.const 0x1p-126) (f32.const -nan)) (f32.const -nan))
+(assert_return (invoke "sub" (f32.const 0x1p-126) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "sub" (f32.const -0x1p-1) (f32.const -0x0p+0)) (f32.const -0x1p-1))
+(assert_return (invoke "sub" (f32.const -0x1p-1) (f32.const 0x0p+0)) (f32.const -0x1p-1))
+(assert_return (invoke "sub" (f32.const 0x1p-1) (f32.const -0x0p+0)) (f32.const 0x1p-1))
+(assert_return (invoke "sub" (f32.const 0x1p-1) (f32.const 0x0p+0)) (f32.const 0x1p-1))
+(assert_return (invoke "sub" (f32.const -0x1p-1) (f32.const -0x1p-149)) (f32.const -0x1p-1))
+(assert_return (invoke "sub" (f32.const -0x1p-1) (f32.const 0x1p-149)) (f32.const -0x1p-1))
+(assert_return (invoke "sub" (f32.const 0x1p-1) (f32.const -0x1p-149)) (f32.const 0x1p-1))
+(assert_return (invoke "sub" (f32.const 0x1p-1) (f32.const 0x1p-149)) (f32.const 0x1p-1))
+(assert_return (invoke "sub" (f32.const -0x1p-1) (f32.const -0x1p-126)) (f32.const -0x1p-1))
+(assert_return (invoke "sub" (f32.const -0x1p-1) (f32.const 0x1p-126)) (f32.const -0x1p-1))
+(assert_return (invoke "sub" (f32.const 0x1p-1) (f32.const -0x1p-126)) (f32.const 0x1p-1))
+(assert_return (invoke "sub" (f32.const 0x1p-1) (f32.const 0x1p-126)) (f32.const 0x1p-1))
+(assert_return (invoke "sub" (f32.const -0x1p-1) (f32.const -0x1p-1)) (f32.const 0x0p+0))
+(assert_return (invoke "sub" (f32.const -0x1p-1) (f32.const 0x1p-1)) (f32.const -0x1p+0))
+(assert_return (invoke "sub" (f32.const 0x1p-1) (f32.const -0x1p-1)) (f32.const 0x1p+0))
+(assert_return (invoke "sub" (f32.const 0x1p-1) (f32.const 0x1p-1)) (f32.const 0x0p+0))
+(assert_return (invoke "sub" (f32.const -0x1p-1) (f32.const -0x1p+0)) (f32.const 0x1p-1))
+(assert_return (invoke "sub" (f32.const -0x1p-1) (f32.const 0x1p+0)) (f32.const -0x1.8p+0))
+(assert_return (invoke "sub" (f32.const 0x1p-1) (f32.const -0x1p+0)) (f32.const 0x1.8p+0))
+(assert_return (invoke "sub" (f32.const 0x1p-1) (f32.const 0x1p+0)) (f32.const -0x1p-1))
+(assert_return (invoke "sub" (f32.const -0x1p-1) (f32.const -0x1.921fb6p+2)) (f32.const 0x1.721fb6p+2))
+(assert_return (invoke "sub" (f32.const -0x1p-1) (f32.const 0x1.921fb6p+2)) (f32.const -0x1.b21fb6p+2))
+(assert_return (invoke "sub" (f32.const 0x1p-1) (f32.const -0x1.921fb6p+2)) (f32.const 0x1.b21fb6p+2))
+(assert_return (invoke "sub" (f32.const 0x1p-1) (f32.const 0x1.921fb6p+2)) (f32.const -0x1.721fb6p+2))
+(assert_return (invoke "sub" (f32.const -0x1p-1) (f32.const -0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const -0x1p-1) (f32.const 0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const 0x1p-1) (f32.const -0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const 0x1p-1) (f32.const 0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const -0x1p-1) (f32.const -infinity)) (f32.const infinity))
+(assert_return (invoke "sub" (f32.const -0x1p-1) (f32.const infinity)) (f32.const -infinity))
+(assert_return (invoke "sub" (f32.const 0x1p-1) (f32.const -infinity)) (f32.const infinity))
+(assert_return (invoke "sub" (f32.const 0x1p-1) (f32.const infinity)) (f32.const -infinity))
+(assert_return (invoke "sub" (f32.const -0x1p-1) (f32.const -nan)) (f32.const -nan))
+(assert_return (invoke "sub" (f32.const -0x1p-1) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "sub" (f32.const 0x1p-1) (f32.const -nan)) (f32.const -nan))
+(assert_return (invoke "sub" (f32.const 0x1p-1) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "sub" (f32.const -0x1p+0) (f32.const -0x0p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "sub" (f32.const -0x1p+0) (f32.const 0x0p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "sub" (f32.const 0x1p+0) (f32.const -0x0p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "sub" (f32.const 0x1p+0) (f32.const 0x0p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "sub" (f32.const -0x1p+0) (f32.const -0x1p-149)) (f32.const -0x1p+0))
+(assert_return (invoke "sub" (f32.const -0x1p+0) (f32.const 0x1p-149)) (f32.const -0x1p+0))
+(assert_return (invoke "sub" (f32.const 0x1p+0) (f32.const -0x1p-149)) (f32.const 0x1p+0))
+(assert_return (invoke "sub" (f32.const 0x1p+0) (f32.const 0x1p-149)) (f32.const 0x1p+0))
+(assert_return (invoke "sub" (f32.const -0x1p+0) (f32.const -0x1p-126)) (f32.const -0x1p+0))
+(assert_return (invoke "sub" (f32.const -0x1p+0) (f32.const 0x1p-126)) (f32.const -0x1p+0))
+(assert_return (invoke "sub" (f32.const 0x1p+0) (f32.const -0x1p-126)) (f32.const 0x1p+0))
+(assert_return (invoke "sub" (f32.const 0x1p+0) (f32.const 0x1p-126)) (f32.const 0x1p+0))
+(assert_return (invoke "sub" (f32.const -0x1p+0) (f32.const -0x1p-1)) (f32.const -0x1p-1))
+(assert_return (invoke "sub" (f32.const -0x1p+0) (f32.const 0x1p-1)) (f32.const -0x1.8p+0))
+(assert_return (invoke "sub" (f32.const 0x1p+0) (f32.const -0x1p-1)) (f32.const 0x1.8p+0))
+(assert_return (invoke "sub" (f32.const 0x1p+0) (f32.const 0x1p-1)) (f32.const 0x1p-1))
+(assert_return (invoke "sub" (f32.const -0x1p+0) (f32.const -0x1p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "sub" (f32.const -0x1p+0) (f32.const 0x1p+0)) (f32.const -0x1p+1))
+(assert_return (invoke "sub" (f32.const 0x1p+0) (f32.const -0x1p+0)) (f32.const 0x1p+1))
+(assert_return (invoke "sub" (f32.const 0x1p+0) (f32.const 0x1p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "sub" (f32.const -0x1p+0) (f32.const -0x1.921fb6p+2)) (f32.const 0x1.521fb6p+2))
+(assert_return (invoke "sub" (f32.const -0x1p+0) (f32.const 0x1.921fb6p+2)) (f32.const -0x1.d21fb6p+2))
+(assert_return (invoke "sub" (f32.const 0x1p+0) (f32.const -0x1.921fb6p+2)) (f32.const 0x1.d21fb6p+2))
+(assert_return (invoke "sub" (f32.const 0x1p+0) (f32.const 0x1.921fb6p+2)) (f32.const -0x1.521fb6p+2))
+(assert_return (invoke "sub" (f32.const -0x1p+0) (f32.const -0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const -0x1p+0) (f32.const 0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const 0x1p+0) (f32.const -0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const 0x1p+0) (f32.const 0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const -0x1p+0) (f32.const -infinity)) (f32.const infinity))
+(assert_return (invoke "sub" (f32.const -0x1p+0) (f32.const infinity)) (f32.const -infinity))
+(assert_return (invoke "sub" (f32.const 0x1p+0) (f32.const -infinity)) (f32.const infinity))
+(assert_return (invoke "sub" (f32.const 0x1p+0) (f32.const infinity)) (f32.const -infinity))
+(assert_return (invoke "sub" (f32.const -0x1p+0) (f32.const -nan)) (f32.const -nan))
+(assert_return (invoke "sub" (f32.const -0x1p+0) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "sub" (f32.const 0x1p+0) (f32.const -nan)) (f32.const -nan))
+(assert_return (invoke "sub" (f32.const 0x1p+0) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "sub" (f32.const -0x1.921fb6p+2) (f32.const -0x0p+0)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "sub" (f32.const -0x1.921fb6p+2) (f32.const 0x0p+0)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "sub" (f32.const 0x1.921fb6p+2) (f32.const -0x0p+0)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "sub" (f32.const 0x1.921fb6p+2) (f32.const 0x0p+0)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "sub" (f32.const -0x1.921fb6p+2) (f32.const -0x1p-149)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "sub" (f32.const -0x1.921fb6p+2) (f32.const 0x1p-149)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "sub" (f32.const 0x1.921fb6p+2) (f32.const -0x1p-149)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "sub" (f32.const 0x1.921fb6p+2) (f32.const 0x1p-149)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "sub" (f32.const -0x1.921fb6p+2) (f32.const -0x1p-126)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "sub" (f32.const -0x1.921fb6p+2) (f32.const 0x1p-126)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "sub" (f32.const 0x1.921fb6p+2) (f32.const -0x1p-126)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "sub" (f32.const 0x1.921fb6p+2) (f32.const 0x1p-126)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "sub" (f32.const -0x1.921fb6p+2) (f32.const -0x1p-1)) (f32.const -0x1.721fb6p+2))
+(assert_return (invoke "sub" (f32.const -0x1.921fb6p+2) (f32.const 0x1p-1)) (f32.const -0x1.b21fb6p+2))
+(assert_return (invoke "sub" (f32.const 0x1.921fb6p+2) (f32.const -0x1p-1)) (f32.const 0x1.b21fb6p+2))
+(assert_return (invoke "sub" (f32.const 0x1.921fb6p+2) (f32.const 0x1p-1)) (f32.const 0x1.721fb6p+2))
+(assert_return (invoke "sub" (f32.const -0x1.921fb6p+2) (f32.const -0x1p+0)) (f32.const -0x1.521fb6p+2))
+(assert_return (invoke "sub" (f32.const -0x1.921fb6p+2) (f32.const 0x1p+0)) (f32.const -0x1.d21fb6p+2))
+(assert_return (invoke "sub" (f32.const 0x1.921fb6p+2) (f32.const -0x1p+0)) (f32.const 0x1.d21fb6p+2))
+(assert_return (invoke "sub" (f32.const 0x1.921fb6p+2) (f32.const 0x1p+0)) (f32.const 0x1.521fb6p+2))
+(assert_return (invoke "sub" (f32.const -0x1.921fb6p+2) (f32.const -0x1.921fb6p+2)) (f32.const 0x0p+0))
+(assert_return (invoke "sub" (f32.const -0x1.921fb6p+2) (f32.const 0x1.921fb6p+2)) (f32.const -0x1.921fb6p+3))
+(assert_return (invoke "sub" (f32.const 0x1.921fb6p+2) (f32.const -0x1.921fb6p+2)) (f32.const 0x1.921fb6p+3))
+(assert_return (invoke "sub" (f32.const 0x1.921fb6p+2) (f32.const 0x1.921fb6p+2)) (f32.const 0x0p+0))
+(assert_return (invoke "sub" (f32.const -0x1.921fb6p+2) (f32.const -0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const -0x1.921fb6p+2) (f32.const 0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const 0x1.921fb6p+2) (f32.const -0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const 0x1.921fb6p+2) (f32.const 0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const -0x1.921fb6p+2) (f32.const -infinity)) (f32.const infinity))
+(assert_return (invoke "sub" (f32.const -0x1.921fb6p+2) (f32.const infinity)) (f32.const -infinity))
+(assert_return (invoke "sub" (f32.const 0x1.921fb6p+2) (f32.const -infinity)) (f32.const infinity))
+(assert_return (invoke "sub" (f32.const 0x1.921fb6p+2) (f32.const infinity)) (f32.const -infinity))
+(assert_return (invoke "sub" (f32.const -0x1.921fb6p+2) (f32.const -nan)) (f32.const -nan))
+(assert_return (invoke "sub" (f32.const -0x1.921fb6p+2) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "sub" (f32.const 0x1.921fb6p+2) (f32.const -nan)) (f32.const -nan))
+(assert_return (invoke "sub" (f32.const 0x1.921fb6p+2) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "sub" (f32.const -0x1.fffffep+127) (f32.const -0x0p+0)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const -0x1.fffffep+127) (f32.const 0x0p+0)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const 0x1.fffffep+127) (f32.const -0x0p+0)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const 0x1.fffffep+127) (f32.const 0x0p+0)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const -0x1.fffffep+127) (f32.const -0x1p-149)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const -0x1.fffffep+127) (f32.const 0x1p-149)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const 0x1.fffffep+127) (f32.const -0x1p-149)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const 0x1.fffffep+127) (f32.const 0x1p-149)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const -0x1.fffffep+127) (f32.const -0x1p-126)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const -0x1.fffffep+127) (f32.const 0x1p-126)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const 0x1.fffffep+127) (f32.const -0x1p-126)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const 0x1.fffffep+127) (f32.const 0x1p-126)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const -0x1.fffffep+127) (f32.const -0x1p-1)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const -0x1.fffffep+127) (f32.const 0x1p-1)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const 0x1.fffffep+127) (f32.const -0x1p-1)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const 0x1.fffffep+127) (f32.const 0x1p-1)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const -0x1.fffffep+127) (f32.const -0x1p+0)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const -0x1.fffffep+127) (f32.const 0x1p+0)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const 0x1.fffffep+127) (f32.const -0x1p+0)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const 0x1.fffffep+127) (f32.const 0x1p+0)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const -0x1.fffffep+127) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const -0x1.fffffep+127) (f32.const 0x1.921fb6p+2)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const 0x1.fffffep+127) (f32.const -0x1.921fb6p+2)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const 0x1.fffffep+127) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const -0x1.fffffep+127) (f32.const -0x1.fffffep+127)) (f32.const 0x0p+0))
+(assert_return (invoke "sub" (f32.const -0x1.fffffep+127) (f32.const 0x1.fffffep+127)) (f32.const -infinity))
+(assert_return (invoke "sub" (f32.const 0x1.fffffep+127) (f32.const -0x1.fffffep+127)) (f32.const infinity))
+(assert_return (invoke "sub" (f32.const 0x1.fffffep+127) (f32.const 0x1.fffffep+127)) (f32.const 0x0p+0))
+(assert_return (invoke "sub" (f32.const -0x1.fffffep+127) (f32.const -infinity)) (f32.const infinity))
+(assert_return (invoke "sub" (f32.const -0x1.fffffep+127) (f32.const infinity)) (f32.const -infinity))
+(assert_return (invoke "sub" (f32.const 0x1.fffffep+127) (f32.const -infinity)) (f32.const infinity))
+(assert_return (invoke "sub" (f32.const 0x1.fffffep+127) (f32.const infinity)) (f32.const -infinity))
+(assert_return (invoke "sub" (f32.const -0x1.fffffep+127) (f32.const -nan)) (f32.const -nan))
+(assert_return (invoke "sub" (f32.const -0x1.fffffep+127) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "sub" (f32.const 0x1.fffffep+127) (f32.const -nan)) (f32.const -nan))
+(assert_return (invoke "sub" (f32.const 0x1.fffffep+127) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "sub" (f32.const -infinity) (f32.const -0x0p+0)) (f32.const -infinity))
+(assert_return (invoke "sub" (f32.const -infinity) (f32.const 0x0p+0)) (f32.const -infinity))
+(assert_return (invoke "sub" (f32.const infinity) (f32.const -0x0p+0)) (f32.const infinity))
+(assert_return (invoke "sub" (f32.const infinity) (f32.const 0x0p+0)) (f32.const infinity))
+(assert_return (invoke "sub" (f32.const -infinity) (f32.const -0x1p-149)) (f32.const -infinity))
+(assert_return (invoke "sub" (f32.const -infinity) (f32.const 0x1p-149)) (f32.const -infinity))
+(assert_return (invoke "sub" (f32.const infinity) (f32.const -0x1p-149)) (f32.const infinity))
+(assert_return (invoke "sub" (f32.const infinity) (f32.const 0x1p-149)) (f32.const infinity))
+(assert_return (invoke "sub" (f32.const -infinity) (f32.const -0x1p-126)) (f32.const -infinity))
+(assert_return (invoke "sub" (f32.const -infinity) (f32.const 0x1p-126)) (f32.const -infinity))
+(assert_return (invoke "sub" (f32.const infinity) (f32.const -0x1p-126)) (f32.const infinity))
+(assert_return (invoke "sub" (f32.const infinity) (f32.const 0x1p-126)) (f32.const infinity))
+(assert_return (invoke "sub" (f32.const -infinity) (f32.const -0x1p-1)) (f32.const -infinity))
+(assert_return (invoke "sub" (f32.const -infinity) (f32.const 0x1p-1)) (f32.const -infinity))
+(assert_return (invoke "sub" (f32.const infinity) (f32.const -0x1p-1)) (f32.const infinity))
+(assert_return (invoke "sub" (f32.const infinity) (f32.const 0x1p-1)) (f32.const infinity))
+(assert_return (invoke "sub" (f32.const -infinity) (f32.const -0x1p+0)) (f32.const -infinity))
+(assert_return (invoke "sub" (f32.const -infinity) (f32.const 0x1p+0)) (f32.const -infinity))
+(assert_return (invoke "sub" (f32.const infinity) (f32.const -0x1p+0)) (f32.const infinity))
+(assert_return (invoke "sub" (f32.const infinity) (f32.const 0x1p+0)) (f32.const infinity))
+(assert_return (invoke "sub" (f32.const -infinity) (f32.const -0x1.921fb6p+2)) (f32.const -infinity))
+(assert_return (invoke "sub" (f32.const -infinity) (f32.const 0x1.921fb6p+2)) (f32.const -infinity))
+(assert_return (invoke "sub" (f32.const infinity) (f32.const -0x1.921fb6p+2)) (f32.const infinity))
+(assert_return (invoke "sub" (f32.const infinity) (f32.const 0x1.921fb6p+2)) (f32.const infinity))
+(assert_return (invoke "sub" (f32.const -infinity) (f32.const -0x1.fffffep+127)) (f32.const -infinity))
+(assert_return (invoke "sub" (f32.const -infinity) (f32.const 0x1.fffffep+127)) (f32.const -infinity))
+(assert_return (invoke "sub" (f32.const infinity) (f32.const -0x1.fffffep+127)) (f32.const infinity))
+(assert_return (invoke "sub" (f32.const infinity) (f32.const 0x1.fffffep+127)) (f32.const infinity))
+(assert_return_nan (invoke "sub" (f32.const -infinity) (f32.const -infinity)))
+(assert_return (invoke "sub" (f32.const -infinity) (f32.const infinity)) (f32.const -infinity))
+(assert_return (invoke "sub" (f32.const infinity) (f32.const -infinity)) (f32.const infinity))
+(assert_return_nan (invoke "sub" (f32.const infinity) (f32.const infinity)))
+(assert_return (invoke "sub" (f32.const -infinity) (f32.const -nan)) (f32.const -nan))
+(assert_return (invoke "sub" (f32.const -infinity) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "sub" (f32.const infinity) (f32.const -nan)) (f32.const -nan))
+(assert_return (invoke "sub" (f32.const infinity) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "sub" (f32.const -nan) (f32.const -0x0p+0)) (f32.const -nan))
+(assert_return (invoke "sub" (f32.const -nan) (f32.const 0x0p+0)) (f32.const -nan))
+(assert_return (invoke "sub" (f32.const nan) (f32.const -0x0p+0)) (f32.const nan))
+(assert_return (invoke "sub" (f32.const nan) (f32.const 0x0p+0)) (f32.const nan))
+(assert_return (invoke "sub" (f32.const -nan) (f32.const -0x1p-149)) (f32.const -nan))
+(assert_return (invoke "sub" (f32.const -nan) (f32.const 0x1p-149)) (f32.const -nan))
+(assert_return (invoke "sub" (f32.const nan) (f32.const -0x1p-149)) (f32.const nan))
+(assert_return (invoke "sub" (f32.const nan) (f32.const 0x1p-149)) (f32.const nan))
+(assert_return (invoke "sub" (f32.const -nan) (f32.const -0x1p-126)) (f32.const -nan))
+(assert_return (invoke "sub" (f32.const -nan) (f32.const 0x1p-126)) (f32.const -nan))
+(assert_return (invoke "sub" (f32.const nan) (f32.const -0x1p-126)) (f32.const nan))
+(assert_return (invoke "sub" (f32.const nan) (f32.const 0x1p-126)) (f32.const nan))
+(assert_return (invoke "sub" (f32.const -nan) (f32.const -0x1p-1)) (f32.const -nan))
+(assert_return (invoke "sub" (f32.const -nan) (f32.const 0x1p-1)) (f32.const -nan))
+(assert_return (invoke "sub" (f32.const nan) (f32.const -0x1p-1)) (f32.const nan))
+(assert_return (invoke "sub" (f32.const nan) (f32.const 0x1p-1)) (f32.const nan))
+(assert_return (invoke "sub" (f32.const -nan) (f32.const -0x1p+0)) (f32.const -nan))
+(assert_return (invoke "sub" (f32.const -nan) (f32.const 0x1p+0)) (f32.const -nan))
+(assert_return (invoke "sub" (f32.const nan) (f32.const -0x1p+0)) (f32.const nan))
+(assert_return (invoke "sub" (f32.const nan) (f32.const 0x1p+0)) (f32.const nan))
+(assert_return (invoke "sub" (f32.const -nan) (f32.const -0x1.921fb6p+2)) (f32.const -nan))
+(assert_return (invoke "sub" (f32.const -nan) (f32.const 0x1.921fb6p+2)) (f32.const -nan))
+(assert_return (invoke "sub" (f32.const nan) (f32.const -0x1.921fb6p+2)) (f32.const nan))
+(assert_return (invoke "sub" (f32.const nan) (f32.const 0x1.921fb6p+2)) (f32.const nan))
+(assert_return (invoke "sub" (f32.const -nan) (f32.const -0x1.fffffep+127)) (f32.const -nan))
+(assert_return (invoke "sub" (f32.const -nan) (f32.const 0x1.fffffep+127)) (f32.const -nan))
+(assert_return (invoke "sub" (f32.const nan) (f32.const -0x1.fffffep+127)) (f32.const nan))
+(assert_return (invoke "sub" (f32.const nan) (f32.const 0x1.fffffep+127)) (f32.const nan))
+(assert_return (invoke "sub" (f32.const -nan) (f32.const -infinity)) (f32.const -nan))
+(assert_return (invoke "sub" (f32.const -nan) (f32.const infinity)) (f32.const -nan))
+(assert_return (invoke "sub" (f32.const nan) (f32.const -infinity)) (f32.const nan))
+(assert_return (invoke "sub" (f32.const nan) (f32.const infinity)) (f32.const nan))
+(assert_return (invoke "sub" (f32.const -nan) (f32.const -nan)) (f32.const -nan))
+(assert_return_nan (invoke "sub" (f32.const -nan) (f32.const nan)))
+(assert_return_nan (invoke "sub" (f32.const nan) (f32.const -nan)))
+(assert_return (invoke "sub" (f32.const nan) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "mul" (f32.const -0x0p+0) (f32.const -0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x0p+0) (f32.const 0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x0p+0) (f32.const -0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x0p+0) (f32.const 0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x0p+0) (f32.const -0x1p-149)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x0p+0) (f32.const 0x1p-149)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x0p+0) (f32.const -0x1p-149)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x0p+0) (f32.const 0x1p-149)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x0p+0) (f32.const -0x1p-126)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x0p+0) (f32.const 0x1p-126)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x0p+0) (f32.const -0x1p-126)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x0p+0) (f32.const 0x1p-126)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x0p+0) (f32.const -0x1p-1)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x0p+0) (f32.const 0x1p-1)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x0p+0) (f32.const -0x1p-1)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x0p+0) (f32.const 0x1p-1)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x0p+0) (f32.const -0x1p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x0p+0) (f32.const 0x1p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x0p+0) (f32.const -0x1p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x0p+0) (f32.const 0x1p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x0p+0) (f32.const -0x1.921fb6p+2)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x0p+0) (f32.const 0x1.921fb6p+2)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x0p+0) (f32.const -0x1.921fb6p+2)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x0p+0) (f32.const 0x1.921fb6p+2)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x0p+0) (f32.const -0x1.fffffep+127)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x0p+0) (f32.const 0x1.fffffep+127)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x0p+0) (f32.const -0x1.fffffep+127)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x0p+0) (f32.const 0x1.fffffep+127)) (f32.const 0x0p+0))
+(assert_return_nan (invoke "mul" (f32.const -0x0p+0) (f32.const -infinity)))
+(assert_return_nan (invoke "mul" (f32.const -0x0p+0) (f32.const infinity)))
+(assert_return_nan (invoke "mul" (f32.const 0x0p+0) (f32.const -infinity)))
+(assert_return_nan (invoke "mul" (f32.const 0x0p+0) (f32.const infinity)))
+(assert_return (invoke "mul" (f32.const -0x0p+0) (f32.const -nan)) (f32.const -nan))
+(assert_return (invoke "mul" (f32.const -0x0p+0) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "mul" (f32.const 0x0p+0) (f32.const -nan)) (f32.const -nan))
+(assert_return (invoke "mul" (f32.const 0x0p+0) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "mul" (f32.const -0x1p-149) (f32.const -0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x1p-149) (f32.const 0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x1p-149) (f32.const -0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x1p-149) (f32.const 0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x1p-149) (f32.const -0x1p-149)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x1p-149) (f32.const 0x1p-149)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x1p-149) (f32.const -0x1p-149)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x1p-149) (f32.const 0x1p-149)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x1p-149) (f32.const -0x1p-126)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x1p-149) (f32.const 0x1p-126)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x1p-149) (f32.const -0x1p-126)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x1p-149) (f32.const 0x1p-126)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x1p-149) (f32.const -0x1p-1)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x1p-149) (f32.const 0x1p-1)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x1p-149) (f32.const -0x1p-1)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x1p-149) (f32.const 0x1p-1)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x1p-149) (f32.const -0x1p+0)) (f32.const 0x1p-149))
+(assert_return (invoke "mul" (f32.const -0x1p-149) (f32.const 0x1p+0)) (f32.const -0x1p-149))
+(assert_return (invoke "mul" (f32.const 0x1p-149) (f32.const -0x1p+0)) (f32.const -0x1p-149))
+(assert_return (invoke "mul" (f32.const 0x1p-149) (f32.const 0x1p+0)) (f32.const 0x1p-149))
+(assert_return (invoke "mul" (f32.const -0x1p-149) (f32.const -0x1.921fb6p+2)) (f32.const 0x1.8p-147))
+(assert_return (invoke "mul" (f32.const -0x1p-149) (f32.const 0x1.921fb6p+2)) (f32.const -0x1.8p-147))
+(assert_return (invoke "mul" (f32.const 0x1p-149) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.8p-147))
+(assert_return (invoke "mul" (f32.const 0x1p-149) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.8p-147))
+(assert_return (invoke "mul" (f32.const -0x1p-149) (f32.const -0x1.fffffep+127)) (f32.const 0x1.fffffep-22))
+(assert_return (invoke "mul" (f32.const -0x1p-149) (f32.const 0x1.fffffep+127)) (f32.const -0x1.fffffep-22))
+(assert_return (invoke "mul" (f32.const 0x1p-149) (f32.const -0x1.fffffep+127)) (f32.const -0x1.fffffep-22))
+(assert_return (invoke "mul" (f32.const 0x1p-149) (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep-22))
+(assert_return (invoke "mul" (f32.const -0x1p-149) (f32.const -infinity)) (f32.const infinity))
+(assert_return (invoke "mul" (f32.const -0x1p-149) (f32.const infinity)) (f32.const -infinity))
+(assert_return (invoke "mul" (f32.const 0x1p-149) (f32.const -infinity)) (f32.const -infinity))
+(assert_return (invoke "mul" (f32.const 0x1p-149) (f32.const infinity)) (f32.const infinity))
+(assert_return (invoke "mul" (f32.const -0x1p-149) (f32.const -nan)) (f32.const -nan))
+(assert_return (invoke "mul" (f32.const -0x1p-149) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "mul" (f32.const 0x1p-149) (f32.const -nan)) (f32.const -nan))
+(assert_return (invoke "mul" (f32.const 0x1p-149) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "mul" (f32.const -0x1p-126) (f32.const -0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x1p-126) (f32.const 0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x1p-126) (f32.const -0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x1p-126) (f32.const 0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x1p-126) (f32.const -0x1p-149)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x1p-126) (f32.const 0x1p-149)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x1p-126) (f32.const -0x1p-149)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x1p-126) (f32.const 0x1p-149)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x1p-126) (f32.const -0x1p-126)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x1p-126) (f32.const 0x1p-126)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x1p-126) (f32.const -0x1p-126)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x1p-126) (f32.const 0x1p-126)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x1p-126) (f32.const -0x1p-1)) (f32.const 0x1p-127))
+(assert_return (invoke "mul" (f32.const -0x1p-126) (f32.const 0x1p-1)) (f32.const -0x1p-127))
+(assert_return (invoke "mul" (f32.const 0x1p-126) (f32.const -0x1p-1)) (f32.const -0x1p-127))
+(assert_return (invoke "mul" (f32.const 0x1p-126) (f32.const 0x1p-1)) (f32.const 0x1p-127))
+(assert_return (invoke "mul" (f32.const -0x1p-126) (f32.const -0x1p+0)) (f32.const 0x1p-126))
+(assert_return (invoke "mul" (f32.const -0x1p-126) (f32.const 0x1p+0)) (f32.const -0x1p-126))
+(assert_return (invoke "mul" (f32.const 0x1p-126) (f32.const -0x1p+0)) (f32.const -0x1p-126))
+(assert_return (invoke "mul" (f32.const 0x1p-126) (f32.const 0x1p+0)) (f32.const 0x1p-126))
+(assert_return (invoke "mul" (f32.const -0x1p-126) (f32.const -0x1.921fb6p+2)) (f32.const 0x1.921fb6p-124))
+(assert_return (invoke "mul" (f32.const -0x1p-126) (f32.const 0x1.921fb6p+2)) (f32.const -0x1.921fb6p-124))
+(assert_return (invoke "mul" (f32.const 0x1p-126) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.921fb6p-124))
+(assert_return (invoke "mul" (f32.const 0x1p-126) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.921fb6p-124))
+(assert_return (invoke "mul" (f32.const -0x1p-126) (f32.const -0x1.fffffep+127)) (f32.const 0x1.fffffep+1))
+(assert_return (invoke "mul" (f32.const -0x1p-126) (f32.const 0x1.fffffep+127)) (f32.const -0x1.fffffep+1))
+(assert_return (invoke "mul" (f32.const 0x1p-126) (f32.const -0x1.fffffep+127)) (f32.const -0x1.fffffep+1))
+(assert_return (invoke "mul" (f32.const 0x1p-126) (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+1))
+(assert_return (invoke "mul" (f32.const -0x1p-126) (f32.const -infinity)) (f32.const infinity))
+(assert_return (invoke "mul" (f32.const -0x1p-126) (f32.const infinity)) (f32.const -infinity))
+(assert_return (invoke "mul" (f32.const 0x1p-126) (f32.const -infinity)) (f32.const -infinity))
+(assert_return (invoke "mul" (f32.const 0x1p-126) (f32.const infinity)) (f32.const infinity))
+(assert_return (invoke "mul" (f32.const -0x1p-126) (f32.const -nan)) (f32.const -nan))
+(assert_return (invoke "mul" (f32.const -0x1p-126) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "mul" (f32.const 0x1p-126) (f32.const -nan)) (f32.const -nan))
+(assert_return (invoke "mul" (f32.const 0x1p-126) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "mul" (f32.const -0x1p-1) (f32.const -0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x1p-1) (f32.const 0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x1p-1) (f32.const -0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x1p-1) (f32.const 0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x1p-1) (f32.const -0x1p-149)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x1p-1) (f32.const 0x1p-149)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x1p-1) (f32.const -0x1p-149)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x1p-1) (f32.const 0x1p-149)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x1p-1) (f32.const -0x1p-126)) (f32.const 0x1p-127))
+(assert_return (invoke "mul" (f32.const -0x1p-1) (f32.const 0x1p-126)) (f32.const -0x1p-127))
+(assert_return (invoke "mul" (f32.const 0x1p-1) (f32.const -0x1p-126)) (f32.const -0x1p-127))
+(assert_return (invoke "mul" (f32.const 0x1p-1) (f32.const 0x1p-126)) (f32.const 0x1p-127))
+(assert_return (invoke "mul" (f32.const -0x1p-1) (f32.const -0x1p-1)) (f32.const 0x1p-2))
+(assert_return (invoke "mul" (f32.const -0x1p-1) (f32.const 0x1p-1)) (f32.const -0x1p-2))
+(assert_return (invoke "mul" (f32.const 0x1p-1) (f32.const -0x1p-1)) (f32.const -0x1p-2))
+(assert_return (invoke "mul" (f32.const 0x1p-1) (f32.const 0x1p-1)) (f32.const 0x1p-2))
+(assert_return (invoke "mul" (f32.const -0x1p-1) (f32.const -0x1p+0)) (f32.const 0x1p-1))
+(assert_return (invoke "mul" (f32.const -0x1p-1) (f32.const 0x1p+0)) (f32.const -0x1p-1))
+(assert_return (invoke "mul" (f32.const 0x1p-1) (f32.const -0x1p+0)) (f32.const -0x1p-1))
+(assert_return (invoke "mul" (f32.const 0x1p-1) (f32.const 0x1p+0)) (f32.const 0x1p-1))
+(assert_return (invoke "mul" (f32.const -0x1p-1) (f32.const -0x1.921fb6p+2)) (f32.const 0x1.921fb6p+1))
+(assert_return (invoke "mul" (f32.const -0x1p-1) (f32.const 0x1.921fb6p+2)) (f32.const -0x1.921fb6p+1))
+(assert_return (invoke "mul" (f32.const 0x1p-1) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.921fb6p+1))
+(assert_return (invoke "mul" (f32.const 0x1p-1) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.921fb6p+1))
+(assert_return (invoke "mul" (f32.const -0x1p-1) (f32.const -0x1.fffffep+127)) (f32.const 0x1.fffffep+126))
+(assert_return (invoke "mul" (f32.const -0x1p-1) (f32.const 0x1.fffffep+127)) (f32.const -0x1.fffffep+126))
+(assert_return (invoke "mul" (f32.const 0x1p-1) (f32.const -0x1.fffffep+127)) (f32.const -0x1.fffffep+126))
+(assert_return (invoke "mul" (f32.const 0x1p-1) (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+126))
+(assert_return (invoke "mul" (f32.const -0x1p-1) (f32.const -infinity)) (f32.const infinity))
+(assert_return (invoke "mul" (f32.const -0x1p-1) (f32.const infinity)) (f32.const -infinity))
+(assert_return (invoke "mul" (f32.const 0x1p-1) (f32.const -infinity)) (f32.const -infinity))
+(assert_return (invoke "mul" (f32.const 0x1p-1) (f32.const infinity)) (f32.const infinity))
+(assert_return (invoke "mul" (f32.const -0x1p-1) (f32.const -nan)) (f32.const -nan))
+(assert_return (invoke "mul" (f32.const -0x1p-1) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "mul" (f32.const 0x1p-1) (f32.const -nan)) (f32.const -nan))
+(assert_return (invoke "mul" (f32.const 0x1p-1) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "mul" (f32.const -0x1p+0) (f32.const -0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x1p+0) (f32.const 0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x1p+0) (f32.const -0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x1p+0) (f32.const 0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x1p+0) (f32.const -0x1p-149)) (f32.const 0x1p-149))
+(assert_return (invoke "mul" (f32.const -0x1p+0) (f32.const 0x1p-149)) (f32.const -0x1p-149))
+(assert_return (invoke "mul" (f32.const 0x1p+0) (f32.const -0x1p-149)) (f32.const -0x1p-149))
+(assert_return (invoke "mul" (f32.const 0x1p+0) (f32.const 0x1p-149)) (f32.const 0x1p-149))
+(assert_return (invoke "mul" (f32.const -0x1p+0) (f32.const -0x1p-126)) (f32.const 0x1p-126))
+(assert_return (invoke "mul" (f32.const -0x1p+0) (f32.const 0x1p-126)) (f32.const -0x1p-126))
+(assert_return (invoke "mul" (f32.const 0x1p+0) (f32.const -0x1p-126)) (f32.const -0x1p-126))
+(assert_return (invoke "mul" (f32.const 0x1p+0) (f32.const 0x1p-126)) (f32.const 0x1p-126))
+(assert_return (invoke "mul" (f32.const -0x1p+0) (f32.const -0x1p-1)) (f32.const 0x1p-1))
+(assert_return (invoke "mul" (f32.const -0x1p+0) (f32.const 0x1p-1)) (f32.const -0x1p-1))
+(assert_return (invoke "mul" (f32.const 0x1p+0) (f32.const -0x1p-1)) (f32.const -0x1p-1))
+(assert_return (invoke "mul" (f32.const 0x1p+0) (f32.const 0x1p-1)) (f32.const 0x1p-1))
+(assert_return (invoke "mul" (f32.const -0x1p+0) (f32.const -0x1p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "mul" (f32.const -0x1p+0) (f32.const 0x1p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "mul" (f32.const 0x1p+0) (f32.const -0x1p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "mul" (f32.const 0x1p+0) (f32.const 0x1p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "mul" (f32.const -0x1p+0) (f32.const -0x1.921fb6p+2)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "mul" (f32.const -0x1p+0) (f32.const 0x1.921fb6p+2)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "mul" (f32.const 0x1p+0) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "mul" (f32.const 0x1p+0) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "mul" (f32.const -0x1p+0) (f32.const -0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "mul" (f32.const -0x1p+0) (f32.const 0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "mul" (f32.const 0x1p+0) (f32.const -0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "mul" (f32.const 0x1p+0) (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "mul" (f32.const -0x1p+0) (f32.const -infinity)) (f32.const infinity))
+(assert_return (invoke "mul" (f32.const -0x1p+0) (f32.const infinity)) (f32.const -infinity))
+(assert_return (invoke "mul" (f32.const 0x1p+0) (f32.const -infinity)) (f32.const -infinity))
+(assert_return (invoke "mul" (f32.const 0x1p+0) (f32.const infinity)) (f32.const infinity))
+(assert_return (invoke "mul" (f32.const -0x1p+0) (f32.const -nan)) (f32.const -nan))
+(assert_return (invoke "mul" (f32.const -0x1p+0) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "mul" (f32.const 0x1p+0) (f32.const -nan)) (f32.const -nan))
+(assert_return (invoke "mul" (f32.const 0x1p+0) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "mul" (f32.const -0x1.921fb6p+2) (f32.const -0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x1.921fb6p+2) (f32.const 0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x1.921fb6p+2) (f32.const -0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x1.921fb6p+2) (f32.const 0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x1.921fb6p+2) (f32.const -0x1p-149)) (f32.const 0x1.8p-147))
+(assert_return (invoke "mul" (f32.const -0x1.921fb6p+2) (f32.const 0x1p-149)) (f32.const -0x1.8p-147))
+(assert_return (invoke "mul" (f32.const 0x1.921fb6p+2) (f32.const -0x1p-149)) (f32.const -0x1.8p-147))
+(assert_return (invoke "mul" (f32.const 0x1.921fb6p+2) (f32.const 0x1p-149)) (f32.const 0x1.8p-147))
+(assert_return (invoke "mul" (f32.const -0x1.921fb6p+2) (f32.const -0x1p-126)) (f32.const 0x1.921fb6p-124))
+(assert_return (invoke "mul" (f32.const -0x1.921fb6p+2) (f32.const 0x1p-126)) (f32.const -0x1.921fb6p-124))
+(assert_return (invoke "mul" (f32.const 0x1.921fb6p+2) (f32.const -0x1p-126)) (f32.const -0x1.921fb6p-124))
+(assert_return (invoke "mul" (f32.const 0x1.921fb6p+2) (f32.const 0x1p-126)) (f32.const 0x1.921fb6p-124))
+(assert_return (invoke "mul" (f32.const -0x1.921fb6p+2) (f32.const -0x1p-1)) (f32.const 0x1.921fb6p+1))
+(assert_return (invoke "mul" (f32.const -0x1.921fb6p+2) (f32.const 0x1p-1)) (f32.const -0x1.921fb6p+1))
+(assert_return (invoke "mul" (f32.const 0x1.921fb6p+2) (f32.const -0x1p-1)) (f32.const -0x1.921fb6p+1))
+(assert_return (invoke "mul" (f32.const 0x1.921fb6p+2) (f32.const 0x1p-1)) (f32.const 0x1.921fb6p+1))
+(assert_return (invoke "mul" (f32.const -0x1.921fb6p+2) (f32.const -0x1p+0)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "mul" (f32.const -0x1.921fb6p+2) (f32.const 0x1p+0)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "mul" (f32.const 0x1.921fb6p+2) (f32.const -0x1p+0)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "mul" (f32.const 0x1.921fb6p+2) (f32.const 0x1p+0)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "mul" (f32.const -0x1.921fb6p+2) (f32.const -0x1.921fb6p+2)) (f32.const 0x1.3bd3cep+5))
+(assert_return (invoke "mul" (f32.const -0x1.921fb6p+2) (f32.const 0x1.921fb6p+2)) (f32.const -0x1.3bd3cep+5))
+(assert_return (invoke "mul" (f32.const 0x1.921fb6p+2) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.3bd3cep+5))
+(assert_return (invoke "mul" (f32.const 0x1.921fb6p+2) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.3bd3cep+5))
+(assert_return (invoke "mul" (f32.const -0x1.921fb6p+2) (f32.const -0x1.fffffep+127)) (f32.const infinity))
+(assert_return (invoke "mul" (f32.const -0x1.921fb6p+2) (f32.const 0x1.fffffep+127)) (f32.const -infinity))
+(assert_return (invoke "mul" (f32.const 0x1.921fb6p+2) (f32.const -0x1.fffffep+127)) (f32.const -infinity))
+(assert_return (invoke "mul" (f32.const 0x1.921fb6p+2) (f32.const 0x1.fffffep+127)) (f32.const infinity))
+(assert_return (invoke "mul" (f32.const -0x1.921fb6p+2) (f32.const -infinity)) (f32.const infinity))
+(assert_return (invoke "mul" (f32.const -0x1.921fb6p+2) (f32.const infinity)) (f32.const -infinity))
+(assert_return (invoke "mul" (f32.const 0x1.921fb6p+2) (f32.const -infinity)) (f32.const -infinity))
+(assert_return (invoke "mul" (f32.const 0x1.921fb6p+2) (f32.const infinity)) (f32.const infinity))
+(assert_return (invoke "mul" (f32.const -0x1.921fb6p+2) (f32.const -nan)) (f32.const -nan))
+(assert_return (invoke "mul" (f32.const -0x1.921fb6p+2) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "mul" (f32.const 0x1.921fb6p+2) (f32.const -nan)) (f32.const -nan))
+(assert_return (invoke "mul" (f32.const 0x1.921fb6p+2) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "mul" (f32.const -0x1.fffffep+127) (f32.const -0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x1.fffffep+127) (f32.const 0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x1.fffffep+127) (f32.const -0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x1.fffffep+127) (f32.const 0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x1.fffffep+127) (f32.const -0x1p-149)) (f32.const 0x1.fffffep-22))
+(assert_return (invoke "mul" (f32.const -0x1.fffffep+127) (f32.const 0x1p-149)) (f32.const -0x1.fffffep-22))
+(assert_return (invoke "mul" (f32.const 0x1.fffffep+127) (f32.const -0x1p-149)) (f32.const -0x1.fffffep-22))
+(assert_return (invoke "mul" (f32.const 0x1.fffffep+127) (f32.const 0x1p-149)) (f32.const 0x1.fffffep-22))
+(assert_return (invoke "mul" (f32.const -0x1.fffffep+127) (f32.const -0x1p-126)) (f32.const 0x1.fffffep+1))
+(assert_return (invoke "mul" (f32.const -0x1.fffffep+127) (f32.const 0x1p-126)) (f32.const -0x1.fffffep+1))
+(assert_return (invoke "mul" (f32.const 0x1.fffffep+127) (f32.const -0x1p-126)) (f32.const -0x1.fffffep+1))
+(assert_return (invoke "mul" (f32.const 0x1.fffffep+127) (f32.const 0x1p-126)) (f32.const 0x1.fffffep+1))
+(assert_return (invoke "mul" (f32.const -0x1.fffffep+127) (f32.const -0x1p-1)) (f32.const 0x1.fffffep+126))
+(assert_return (invoke "mul" (f32.const -0x1.fffffep+127) (f32.const 0x1p-1)) (f32.const -0x1.fffffep+126))
+(assert_return (invoke "mul" (f32.const 0x1.fffffep+127) (f32.const -0x1p-1)) (f32.const -0x1.fffffep+126))
+(assert_return (invoke "mul" (f32.const 0x1.fffffep+127) (f32.const 0x1p-1)) (f32.const 0x1.fffffep+126))
+(assert_return (invoke "mul" (f32.const -0x1.fffffep+127) (f32.const -0x1p+0)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "mul" (f32.const -0x1.fffffep+127) (f32.const 0x1p+0)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "mul" (f32.const 0x1.fffffep+127) (f32.const -0x1p+0)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "mul" (f32.const 0x1.fffffep+127) (f32.const 0x1p+0)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "mul" (f32.const -0x1.fffffep+127) (f32.const -0x1.921fb6p+2)) (f32.const infinity))
+(assert_return (invoke "mul" (f32.const -0x1.fffffep+127) (f32.const 0x1.921fb6p+2)) (f32.const -infinity))
+(assert_return (invoke "mul" (f32.const 0x1.fffffep+127) (f32.const -0x1.921fb6p+2)) (f32.const -infinity))
+(assert_return (invoke "mul" (f32.const 0x1.fffffep+127) (f32.const 0x1.921fb6p+2)) (f32.const infinity))
+(assert_return (invoke "mul" (f32.const -0x1.fffffep+127) (f32.const -0x1.fffffep+127)) (f32.const infinity))
+(assert_return (invoke "mul" (f32.const -0x1.fffffep+127) (f32.const 0x1.fffffep+127)) (f32.const -infinity))
+(assert_return (invoke "mul" (f32.const 0x1.fffffep+127) (f32.const -0x1.fffffep+127)) (f32.const -infinity))
+(assert_return (invoke "mul" (f32.const 0x1.fffffep+127) (f32.const 0x1.fffffep+127)) (f32.const infinity))
+(assert_return (invoke "mul" (f32.const -0x1.fffffep+127) (f32.const -infinity)) (f32.const infinity))
+(assert_return (invoke "mul" (f32.const -0x1.fffffep+127) (f32.const infinity)) (f32.const -infinity))
+(assert_return (invoke "mul" (f32.const 0x1.fffffep+127) (f32.const -infinity)) (f32.const -infinity))
+(assert_return (invoke "mul" (f32.const 0x1.fffffep+127) (f32.const infinity)) (f32.const infinity))
+(assert_return (invoke "mul" (f32.const -0x1.fffffep+127) (f32.const -nan)) (f32.const -nan))
+(assert_return (invoke "mul" (f32.const -0x1.fffffep+127) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "mul" (f32.const 0x1.fffffep+127) (f32.const -nan)) (f32.const -nan))
+(assert_return (invoke "mul" (f32.const 0x1.fffffep+127) (f32.const nan)) (f32.const nan))
+(assert_return_nan (invoke "mul" (f32.const -infinity) (f32.const -0x0p+0)))
+(assert_return_nan (invoke "mul" (f32.const -infinity) (f32.const 0x0p+0)))
+(assert_return_nan (invoke "mul" (f32.const infinity) (f32.const -0x0p+0)))
+(assert_return_nan (invoke "mul" (f32.const infinity) (f32.const 0x0p+0)))
+(assert_return (invoke "mul" (f32.const -infinity) (f32.const -0x1p-149)) (f32.const infinity))
+(assert_return (invoke "mul" (f32.const -infinity) (f32.const 0x1p-149)) (f32.const -infinity))
+(assert_return (invoke "mul" (f32.const infinity) (f32.const -0x1p-149)) (f32.const -infinity))
+(assert_return (invoke "mul" (f32.const infinity) (f32.const 0x1p-149)) (f32.const infinity))
+(assert_return (invoke "mul" (f32.const -infinity) (f32.const -0x1p-126)) (f32.const infinity))
+(assert_return (invoke "mul" (f32.const -infinity) (f32.const 0x1p-126)) (f32.const -infinity))
+(assert_return (invoke "mul" (f32.const infinity) (f32.const -0x1p-126)) (f32.const -infinity))
+(assert_return (invoke "mul" (f32.const infinity) (f32.const 0x1p-126)) (f32.const infinity))
+(assert_return (invoke "mul" (f32.const -infinity) (f32.const -0x1p-1)) (f32.const infinity))
+(assert_return (invoke "mul" (f32.const -infinity) (f32.const 0x1p-1)) (f32.const -infinity))
+(assert_return (invoke "mul" (f32.const infinity) (f32.const -0x1p-1)) (f32.const -infinity))
+(assert_return (invoke "mul" (f32.const infinity) (f32.const 0x1p-1)) (f32.const infinity))
+(assert_return (invoke "mul" (f32.const -infinity) (f32.const -0x1p+0)) (f32.const infinity))
+(assert_return (invoke "mul" (f32.const -infinity) (f32.const 0x1p+0)) (f32.const -infinity))
+(assert_return (invoke "mul" (f32.const infinity) (f32.const -0x1p+0)) (f32.const -infinity))
+(assert_return (invoke "mul" (f32.const infinity) (f32.const 0x1p+0)) (f32.const infinity))
+(assert_return (invoke "mul" (f32.const -infinity) (f32.const -0x1.921fb6p+2)) (f32.const infinity))
+(assert_return (invoke "mul" (f32.const -infinity) (f32.const 0x1.921fb6p+2)) (f32.const -infinity))
+(assert_return (invoke "mul" (f32.const infinity) (f32.const -0x1.921fb6p+2)) (f32.const -infinity))
+(assert_return (invoke "mul" (f32.const infinity) (f32.const 0x1.921fb6p+2)) (f32.const infinity))
+(assert_return (invoke "mul" (f32.const -infinity) (f32.const -0x1.fffffep+127)) (f32.const infinity))
+(assert_return (invoke "mul" (f32.const -infinity) (f32.const 0x1.fffffep+127