Merge inbound to mozilla-central. a=merge
authorGurzau Raul <rgurzau@mozilla.com>
Wed, 14 Mar 2018 00:40:07 +0200
changeset 408033 c56ef1c14a555023949ad727c86e3c2df995edd2
parent 408032 1bd1d50b1f3f53be310d20cc64e4d4e994b43940 (current diff)
parent 407949 7fa58c6285226b0f1a0e4424dcef7bbc72cb16eb (diff)
child 408034 e0b884f8163445cec722cd51463b1731c7c2caab
child 408085 6f60e8f0463c4f3eee02328088408bb21bee17cc
push id100832
push userrgurzau@mozilla.com
push dateTue, 13 Mar 2018 22:44:35 +0000
treeherdermozilla-inbound@e0b884f81634 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone61.0a1
first release with
nightly linux32
c56ef1c14a55 / 61.0a1 / 20180313225158 / files
nightly linux64
c56ef1c14a55 / 61.0a1 / 20180313225158 / files
nightly mac
c56ef1c14a55 / 61.0a1 / 20180313225158 / files
nightly win32
c56ef1c14a55 / 61.0a1 / 20180313225158 / files
nightly win64
c56ef1c14a55 / 61.0a1 / 20180313225158 / 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 mozilla-central. a=merge
browser/base/content/browser.js
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -6724,17 +6724,17 @@ var CanvasPermissionPromptHelper = {
       name: uri.asciiHost,
     };
     PopupNotifications.show(browser, aTopic, message, this._notificationIcon,
                             mainAction, secondaryActions, options);
   }
 };
 
 var WebAuthnPromptHelper = {
-  _icon: "default-notification-icon",
+  _icon: "webauthn-notification-icon",
   _topic: "webauthn-prompt",
 
   // The current notification, if any. The U2F manager is a singleton, we will
   // never allow more than one active request. And thus we'll never have more
   // than one notification either.
   _current: null,
 
   // The current transaction ID. Will be checked when we're notified of the
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -861,16 +861,18 @@
                   <image id="translated-notification-icon" class="notification-anchor-icon translation-icon in-use" role="button"
                          tooltiptext="&urlbar.translatedNotificationAnchor.tooltip;"/>
                   <image id="eme-notification-icon" class="notification-anchor-icon drm-icon" role="button"
                          tooltiptext="&urlbar.emeNotificationAnchor.tooltip;"/>
                   <image id="persistent-storage-notification-icon" class="notification-anchor-icon persistent-storage-icon" role="button"
                          tooltiptext="&urlbar.persistentStorageNotificationAnchor.tooltip;"/>
                   <image id="midi-notification-icon" class="notification-anchor-icon midi-icon" role="button"
                          tooltiptext="&urlbar.midiNotificationAnchor.tooltip;"/>
+                  <image id="webauthn-notification-icon" class="notification-anchor-icon" role="button"
+                         tooltiptext="&urlbar.defaultNotificationAnchor.tooltip;"/>
                 </box>
                 <image id="connection-icon"/>
                 <image id="extension-icon"/>
                 <image id="remote-control-icon"
                        tooltiptext="&urlbar.remoteControlNotificationAnchor.tooltip;"/>
                 <hbox id="identity-icon-labels">
                   <label id="identity-icon-label" class="plain" flex="1"/>
                   <label id="identity-icon-country-label" class="plain"/>
--- a/browser/themes/shared/jar.inc.mn
+++ b/browser/themes/shared/jar.inc.mn
@@ -70,16 +70,17 @@
   skin/classic/browser/notification-icons/persistent-storage.svg            (../shared/notification-icons/persistent-storage.svg)
   skin/classic/browser/notification-icons/plugin-badge.svg                  (../shared/notification-icons/plugin-badge.svg)
   skin/classic/browser/notification-icons/popup.svg                         (../shared/notification-icons/popup.svg)
   skin/classic/browser/notification-icons/popup-subitem.svg                 (../shared/notification-icons/popup-subitem.svg)
   skin/classic/browser/notification-icons/screen-blocked.svg                (../shared/notification-icons/screen-blocked.svg)
   skin/classic/browser/notification-icons/screen.svg                        (../shared/notification-icons/screen.svg)
   skin/classic/browser/notification-icons/update.svg                        (../shared/notification-icons/update.svg)
   skin/classic/browser/notification-icons/midi.svg                          (../shared/notification-icons/midi.svg)
+  skin/classic/browser/notification-icons/webauthn.svg                      (../shared/notification-icons/webauthn.svg)
 
   skin/classic/browser/tracking-protection-16.svg              (../shared/identity-block/tracking-protection-16.svg)
   skin/classic/browser/panel-icon-arrow-left.svg               (../shared/panel-icon-arrow-left.svg)
   skin/classic/browser/panel-icon-arrow-right.svg              (../shared/panel-icon-arrow-right.svg)
   skin/classic/browser/panel-icon-cancel.svg                   (../shared/panel-icon-cancel.svg)
 #ifndef XP_MACOSX
   skin/classic/browser/panel-icon-folder.svg                   (../shared/panel-icon-folder.svg)
 #else
--- a/browser/themes/shared/notification-icons.inc.css
+++ b/browser/themes/shared/notification-icons.inc.css
@@ -126,16 +126,21 @@
 .canvas-icon {
   list-style-image: url(chrome://browser/skin/notification-icons/canvas.svg);
 }
 
 .canvas-icon.blocked-permission-icon {
   list-style-image: url(chrome://browser/skin/notification-icons/canvas-blocked.svg);
 }
 
+#webauthn-notification-icon,
+.popup-notification-icon[popupid^="webauthn-prompt-"] {
+  list-style-image: url(chrome://browser/skin/notification-icons/webauthn.svg);
+}
+
 #webRTC-preview:not([hidden]) {
   display: -moz-stack;
   border-radius: 4px;
   border: 1px solid GrayText;
   overflow: hidden;
   min-width: 300px;
   min-height: 10em;
 }
new file mode 100644
--- /dev/null
+++ b/browser/themes/shared/notification-icons/webauthn.svg
@@ -0,0 +1,8 @@
+<!-- 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/. -->
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" fill-opacity="context-fill-opacity" fill="context-fill" fill-rule="evenodd">
+  <path d="M11.0013,17.9999 C11.0013,15.2386153 13.2400153,12.9999 16.0013,12.9999 C18.7625847,12.9999 21.0013,15.2386153 21.0013,17.9999 C21.0013,23.5534188 17.4872463,28.4378884 12.3346491,30.2597035 C11.8139531,30.4438071 11.2426002,30.1709451 11.0584965,29.6502491 C10.8743929,29.1295531 11.1472549,28.5582002 11.6679509,28.3740965 C16.027576,26.8326543 19.0013,22.699233 19.0013,17.9999 C19.0013,16.3431847 17.6580153,14.9999 16.0013,14.9999 C14.3445847,14.9999 13.0013,16.3431847 13.0013,17.9999 C13.0013,20.7611847 10.7625847,22.9999 8.0013,22.9999 C5.24001525,22.9999 3.0013,20.7611847 3.0013,17.9999 C3.0013,10.8206153 8.82201525,4.9999 16.0013,4.9999 C23.1805847,4.9999 29.0013,10.8206153 29.0013,17.9999 C29.0013,19.4211716 28.8597186,20.8259325 28.581352,22.1986412 C28.4715903,22.739909 27.9438266,23.0897137 27.4025588,22.979952 C26.861291,22.8701903 26.5114863,22.3424266 26.621248,21.8011588 C26.8731384,20.559012 27.0013,19.2874016 27.0013,17.9999 C27.0013,11.9251847 22.0760153,6.9999 16.0013,6.9999 C9.92658475,6.9999 5.0013,11.9251847 5.0013,17.9999 C5.0013,19.6566153 6.34458475,20.9999 8.0013,20.9999 C9.65801525,20.9999 11.0013,19.6566153 11.0013,17.9999 Z"/>
+  <path d="M8.0013,26.9999 C7.44901525,26.9999 7.0013,26.5521847 7.0013,25.9999 C7.0013,25.4476153 7.44901525,24.9999 8.0013,24.9999 C11.8670153,24.9999 15.0013,21.8656153 15.0013,17.9999 C15.0013,17.4476153 15.4490153,16.9999 16.0013,16.9999 C16.5535847,16.9999 17.0013,17.4476153 17.0013,17.9999 C17.0013,22.9701847 12.9715847,26.9999 8.0013,26.9999 Z"/>
+  <path d="M9.0013 17.9999C9.0013 18.5521847 8.55358475 18.9999 8.0013 18.9999 7.44901525 18.9999 7.0013 18.5521847 7.0013 17.9999 7.0013 13.0296153 11.0310153 8.9999 16.0013 8.9999 20.9715847 8.9999 25.0013 13.0296153 25.0013 17.9999 25.0013 21.0536668 24.2197241 23.9472067 22.7567899 26.4983547 22.4820533 26.9774562 21.8709467 27.1431266 21.3918453 26.8683899 20.9127438 26.5936533 20.7470734 25.9825467 21.0218101 25.5034453 22.3122709 23.2530661 23.0013 20.7021516 23.0013 18.0499 23.0013 14.1341847 19.8670153 10.9999 16.0013 10.9999 12.1355847 10.9999 9.0013 14.1341847 9.0013 17.9999zM4.74954564 8.07962613C4.38408439 8.49369922 3.75214695 8.53310689 3.33807387 8.16764564 2.92400078 7.80218439 2.88459311 7.17024695 3.25005436 6.75617387 6.45721717 3.12241027 11.0590025.9999 16.0008.9999 20.9435975.9999 25.5453828 3.12241027 28.7525456 6.75617387 29.1180069 7.17024695 29.0785992 7.80218439 28.6645261 8.16764564 28.2504531 8.53310689 27.6185156 8.49369922 27.2530544 8.07962613 24.4216114 4.87155881 20.3636937 2.9999 16.0018 2.9999 11.6389063 2.9999 7.58098857 4.87155881 4.74954564 8.07962613z"/>
+</svg>
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -224,17 +224,16 @@ DOMInterfaces = {
 },
 
 'CSSValueList': {
     'nativeType': 'nsDOMCSSValueList'
 },
 
 'DedicatedWorkerGlobalScope': {
     'headerFile': 'mozilla/dom/WorkerScope.h',
-    'implicitJSContext': [ 'close' ],
 },
 
 'DeviceAcceleration': {
     'headerFile': 'mozilla/dom/DeviceMotionEvent.h',
 },
 
 'DeviceRotationRate': {
     'headerFile': 'mozilla/dom/DeviceMotionEvent.h',
@@ -753,17 +752,16 @@ DOMInterfaces = {
 },
 
 'ServiceWorkerRegistration': {
     'implicitJSContext': [ 'pushManager' ],
 },
 
 'SharedWorkerGlobalScope': {
     'headerFile': 'mozilla/dom/WorkerScope.h',
-    'implicitJSContext': [ 'close' ],
 },
 
 'StreamFilter': {
     'nativeType': 'mozilla::extensions::StreamFilter',
 },
 
 'StreamFilterDataEvent': {
     'nativeType': 'mozilla::extensions::StreamFilterDataEvent',
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -505,19 +505,17 @@ private:
           override
   {
     aWorkerPrivate->ModifyBusyCountFromWorker(false);
   }
 
   virtual bool
   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
   {
-    bool ok = aWorkerPrivate->NotifyInternal(aCx, mStatus);
-    MOZ_ASSERT(!JS_IsExceptionPending(aCx));
-    return ok;
+    return aWorkerPrivate->NotifyInternal(mStatus);
   }
 };
 
 class FreezeRunnable final : public WorkerControlRunnable
 {
 public:
   explicit FreezeRunnable(WorkerPrivate* aWorkerPrivate)
   : WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount)
@@ -3189,18 +3187,17 @@ WorkerPrivate::DoRunLoop(JSContext* aCx)
       currentStatus = mStatus;
     }
 
     // if all holders are done then we can kill this thread.
     if (currentStatus != Running && !HasActiveHolders()) {
 
       // If we just changed status, we must schedule the current runnables.
       if (previousStatus != Running && currentStatus != Killing) {
-        NotifyInternal(aCx, Killing);
-        MOZ_ASSERT(!JS_IsExceptionPending(aCx));
+        NotifyInternal(Killing);
 
 #ifdef DEBUG
         {
           MutexAutoLock lock(mMutex);
           currentStatus = mStatus;
         }
         MOZ_ASSERT(currentStatus == Killing);
 #else
@@ -3966,34 +3963,32 @@ WorkerPrivate::RemoveHolder(WorkerHolder
     mNumHoldersPreventingShutdownStart -= 1;
     if (!mNumHoldersPreventingShutdownStart && !ModifyBusyCountFromWorker(false)) {
       NS_WARNING("Failed to modify busy count!");
     }
   }
 }
 
 void
-WorkerPrivate::NotifyHolders(JSContext* aCx, WorkerStatus aStatus)
+WorkerPrivate::NotifyHolders(WorkerStatus aStatus)
 {
   AssertIsOnWorkerThread();
-  MOZ_ASSERT(!JS_IsExceptionPending(aCx));
 
   NS_ASSERTION(aStatus > Running, "Bad status!");
 
   if (aStatus >= Closing) {
     CancelAllTimeouts();
   }
 
   nsTObserverArray<WorkerHolder*>::ForwardIterator iter(mHolders);
   while (iter.HasMore()) {
     WorkerHolder* holder = iter.GetNext();
     if (!holder->Notify(aStatus)) {
       NS_WARNING("Failed to notify holder!");
     }
-    MOZ_ASSERT(!JS_IsExceptionPending(aCx));
   }
 
   AutoTArray<WorkerPrivate*, 10> children;
   children.AppendElements(mChildWorkers);
 
   for (uint32_t index = 0; index < children.Length(); index++) {
     if (!children[index]->Notify(aStatus)) {
       NS_WARNING("Failed to notify child worker!");
@@ -4431,17 +4426,17 @@ void
 WorkerPrivate::ReportErrorToDebugger(const nsAString& aFilename,
                                      uint32_t aLineno,
                                      const nsAString& aMessage)
 {
   mDebugger->ReportErrorToDebugger(aFilename, aLineno, aMessage);
 }
 
 bool
-WorkerPrivate::NotifyInternal(JSContext* aCx, WorkerStatus aStatus)
+WorkerPrivate::NotifyInternal(WorkerStatus aStatus)
 {
   AssertIsOnWorkerThread();
 
   NS_ASSERTION(aStatus > Running && aStatus < Dead, "Bad status!");
 
   RefPtr<EventTarget> eventTarget;
 
   // Save the old status and set the new status.
@@ -4481,18 +4476,17 @@ WorkerPrivate::NotifyInternal(JSContext*
     if (aStatus == Closing) {
       Close();
     }
   }
 
   MOZ_ASSERT(previousStatus != Pending);
 
   // Let all our holders know the new status.
-  NotifyHolders(aCx, aStatus);
-  MOZ_ASSERT(!JS_IsExceptionPending(aCx));
+  NotifyHolders(aStatus);
 
   // If this is the first time our status has changed then we need to clear the
   // main event queue.
   if (previousStatus == Running) {
     // NB: If we're in a sync loop, we can't clear the queue immediately,
     // because this is the wrong queue. So we have to defer it until later.
     if (!mSyncLoopStack.IsEmpty()) {
       mPendingEventQueueClearing = true;
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -256,20 +256,20 @@ public:
 
   bool
   InterruptCallback(JSContext* aCx);
 
   bool
   IsOnCurrentThread();
 
   bool
-  CloseInternal(JSContext* aCx)
+  CloseInternal()
   {
     AssertIsOnWorkerThread();
-    return NotifyInternal(aCx, Closing);
+    return NotifyInternal(Closing);
   }
 
   bool
   FreezeInternal();
 
   bool
   ThawInternal();
 
@@ -315,17 +315,17 @@ public:
   void
   SetDebuggerImmediate(Function& aHandler, ErrorResult& aRv);
 
   void
   ReportErrorToDebugger(const nsAString& aFilename, uint32_t aLineno,
                         const nsAString& aMessage);
 
   bool
-  NotifyInternal(JSContext* aCx, WorkerStatus aStatus);
+  NotifyInternal(WorkerStatus aStatus);
 
   void
   ReportError(JSContext* aCx, JS::ConstUTF8CharsZ aToStringResult,
               JSErrorReport* aReport);
 
   static void
   ReportErrorToConsole(const char* aMessage);
 
@@ -1312,17 +1312,17 @@ private:
 
   bool
   AddHolder(WorkerHolder* aHolder, WorkerStatus aFailStatus);
 
   void
   RemoveHolder(WorkerHolder* aHolder);
 
   void
-  NotifyHolders(JSContext* aCx, WorkerStatus aStatus);
+  NotifyHolders(WorkerStatus aStatus);
 
   bool
   HasActiveHolders()
   {
     return !(mChildWorkers.IsEmpty() && mTimeouts.IsEmpty() &&
              mHolders.IsEmpty());
   }
 
--- a/dom/workers/WorkerScope.cpp
+++ b/dom/workers/WorkerScope.cpp
@@ -630,20 +630,20 @@ DedicatedWorkerGlobalScope::PostMessage(
                                         const Sequence<JSObject*>& aTransferable,
                                         ErrorResult& aRv)
 {
   mWorkerPrivate->AssertIsOnWorkerThread();
   mWorkerPrivate->PostMessageToParent(aCx, aMessage, aTransferable, aRv);
 }
 
 void
-DedicatedWorkerGlobalScope::Close(JSContext* aCx)
+DedicatedWorkerGlobalScope::Close()
 {
   mWorkerPrivate->AssertIsOnWorkerThread();
-  mWorkerPrivate->CloseInternal(aCx);
+  mWorkerPrivate->CloseInternal();
 }
 
 SharedWorkerGlobalScope::SharedWorkerGlobalScope(WorkerPrivate* aWorkerPrivate,
                                                  const nsString& aName)
 : WorkerGlobalScope(aWorkerPrivate), mName(aName)
 {
 }
 
@@ -658,20 +658,20 @@ SharedWorkerGlobalScope::WrapGlobalObjec
   mWorkerPrivate->CopyJSCompartmentOptions(options);
 
   return SharedWorkerGlobalScopeBinding::Wrap(aCx, this, this, options,
                                               GetWorkerPrincipal(),
                                               true, aReflector);
 }
 
 void
-SharedWorkerGlobalScope::Close(JSContext* aCx)
+SharedWorkerGlobalScope::Close()
 {
   mWorkerPrivate->AssertIsOnWorkerThread();
-  mWorkerPrivate->CloseInternal(aCx);
+  mWorkerPrivate->CloseInternal();
 }
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(ServiceWorkerGlobalScope, WorkerGlobalScope,
                                    mClients, mRegistration)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ServiceWorkerGlobalScope)
 NS_INTERFACE_MAP_END_INHERITING(WorkerGlobalScope)
 
 NS_IMPL_ADDREF_INHERITED(ServiceWorkerGlobalScope, WorkerGlobalScope)
--- a/dom/workers/WorkerScope.h
+++ b/dom/workers/WorkerScope.h
@@ -259,17 +259,17 @@ public:
   }
 
   void
   PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
               const Sequence<JSObject*>& aTransferable,
               ErrorResult& aRv);
 
   void
-  Close(JSContext* aCx);
+  Close();
 
   IMPL_EVENT_HANDLER(message)
   IMPL_EVENT_HANDLER(messageerror)
 };
 
 class SharedWorkerGlobalScope final : public WorkerGlobalScope
 {
   const nsString mName;
@@ -285,17 +285,17 @@ public:
                    JS::MutableHandle<JSObject*> aReflector) override;
 
   void GetName(DOMString& aName) const
   {
     aName.AsAString() = mName;
   }
 
   void
-  Close(JSContext* aCx);
+  Close();
 
   IMPL_EVENT_HANDLER(connect)
 };
 
 class ServiceWorkerGlobalScope final : public WorkerGlobalScope
 {
   const nsString mScope;
   RefPtr<Clients> mClients;
--- a/js/src/jit/AliasAnalysis.cpp
+++ b/js/src/jit/AliasAnalysis.cpp
@@ -84,37 +84,41 @@ BlockMightReach(MBasicBlock* src, MBasic
         }
     }
     return false;
 }
 
 static void
 IonSpewDependency(MInstruction* load, MInstruction* store, const char* verb, const char* reason)
 {
+#ifdef JS_JITSPEW
     if (!JitSpewEnabled(JitSpew_Alias))
         return;
 
     Fprinter& out = JitSpewPrinter();
     out.printf("Load ");
     load->printName(out);
     out.printf(" %s on store ", verb);
     store->printName(out);
     out.printf(" (%s)\n", reason);
+#endif
 }
 
 static void
 IonSpewAliasInfo(const char* pre, MInstruction* ins, const char* post)
 {
+#ifdef JS_JITSPEW
     if (!JitSpewEnabled(JitSpew_Alias))
         return;
 
     Fprinter& out = JitSpewPrinter();
     out.printf("%s ", pre);
     ins->printName(out);
     out.printf(" %s\n", post);
+#endif
 }
 
 // This pass annotates every load instruction with the last store instruction
 // on which it depends. The algorithm is optimistic in that it ignores explicit
 // dependencies and only considers loads and stores.
 //
 // Loads inside loops only have an implicit dependency on a store before the
 // loop header if no instruction inside the loop body aliases it. To calculate
@@ -176,22 +180,24 @@ AliasAnalysis::analyze()
                 continue;
 
             if (set.isStore()) {
                 for (AliasSetIterator iter(set); iter; iter++) {
                     if (!stores[*iter].append(*def))
                         return false;
                 }
 
+#ifdef JS_JITSPEW
                 if (JitSpewEnabled(JitSpew_Alias)) {
                     Fprinter& out = JitSpewPrinter();
                     out.printf("Processing store ");
                     def->printName(out);
                     out.printf(" (flags %x)\n", set.flags());
                 }
+#endif
             } else {
                 // Find the most recent store on which this instruction depends.
                 MInstruction* lastStore = firstIns;
 
                 for (AliasSetIterator iter(set); iter; iter++) {
                     MInstructionVector& aliasedStores = stores[*iter];
                     for (int i = aliasedStores.length() - 1; i >= 0; i--) {
                         MInstruction* store = aliasedStores[i];
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -5417,22 +5417,24 @@ struct ScriptCountBlockState
         // Collect human readable assembly for the code generated in the block.
         masm.setPrinter(&printer);
 
         return true;
     }
 
     void visitInstruction(LInstruction* ins)
     {
+#ifdef JS_JITSPEW
         // Prefix stream of assembly instructions with their LIR instruction
         // name and any associated high level info.
         if (const char* extra = ins->getExtraName())
             printer.printf("[%s:%s]\n", ins->opName(), extra);
         else
             printer.printf("[%s]\n", ins->opName());
+#endif
     }
 
     ~ScriptCountBlockState()
     {
         masm.setPrinter(nullptr);
 
         if (!printer.hadOutOfMemory())
             block.setCode(printer.string());
@@ -5796,20 +5798,20 @@ CodeGenerator::generateBody()
 
             setElement(*iter); // needed to encode correct snapshot location.
 
 #ifdef DEBUG
             emitDebugForceBailing(*iter);
 #endif
 
             switch (iter->op()) {
-#define LIROP(op) case LNode::LOp_##op: visit##op(iter->to##op()); break;
+#define LIROP(op) case LNode::Opcode::op: visit##op(iter->to##op()); break;
     LIR_OPCODE_LIST(LIROP)
 #undef LIROP
-              case LNode::LOp_Invalid:
+              case LNode::Opcode::Invalid:
               default:
                 MOZ_CRASH("Invalid LIR op");
             }
 
             // Track the end native offset of optimizations.
             if (iter->mirRaw() && iter->mirRaw()->trackedOptimizations())
                 extendTrackedOptimizationsEntry(iter->mirRaw()->trackedOptimizations());
 
--- a/js/src/jit/IonAnalysis.cpp
+++ b/js/src/jit/IonAnalysis.cpp
@@ -4787,39 +4787,43 @@ jit::CreateMIRRootList(IonBuilder& build
                 return false;
         }
     }
 
     builder.setRootList(*roots);
     return true;
 }
 
+#ifdef JS_JITSPEW
 static void
 DumpDefinition(GenericPrinter& out, MDefinition* def, size_t depth)
 {
     MDefinition::PrintOpcodeName(out, def->op());
 
     if (depth == 0)
         return;
 
     for (size_t i = 0; i < def->numOperands(); i++) {
         out.printf(" (");
         DumpDefinition(out, def->getOperand(i), depth - 1);
         out.printf(")");
     }
 }
+#endif
 
 void
 jit::DumpMIRExpressions(MIRGraph& graph)
 {
+#ifdef JS_JITSPEW
     if (!JitSpewEnabled(JitSpew_MIRExpressions))
         return;
 
     size_t depth = 2;
 
     Fprinter& out = JitSpewPrinter();
     for (ReversePostorderIterator block(graph.rpoBegin()); block != graph.rpoEnd(); block++) {
         for (MInstructionIterator iter(block->begin()), end(block->end()); iter != end; iter++) {
             DumpDefinition(out, *iter, depth);
             out.printf("\n");
         }
     }
+#endif
 }
--- a/js/src/jit/LIR.cpp
+++ b/js/src/jit/LIR.cpp
@@ -53,32 +53,34 @@ LIRGraph::noteNeedsSafepoint(LInstructio
 {
     // Instructions with safepoints must be in linear order.
     MOZ_ASSERT_IF(!safepoints_.empty(), safepoints_.back()->id() < ins->id());
     if (!ins->isCall() && !nonCallSafepoints_.append(ins))
         return false;
     return safepoints_.append(ins);
 }
 
+#ifdef JS_JITSPEW
 void
 LIRGraph::dump(GenericPrinter& out)
 {
     for (size_t i = 0; i < numBlocks(); i++) {
         getBlock(i)->dump(out);
         out.printf("\n");
     }
 }
 
 void
 LIRGraph::dump()
 {
     Fprinter out(stderr);
     dump(out);
     out.finish();
 }
+#endif
 
 LBlock::LBlock(MBasicBlock* from)
   : block_(from),
     phis_(),
     entryMoveGroup_(nullptr),
     exitMoveGroup_(nullptr)
 {
     from->assignLir(this);
@@ -155,16 +157,17 @@ LBlock::getExitMoveGroup(TempAllocator& 
 {
     if (exitMoveGroup_)
         return exitMoveGroup_;
     exitMoveGroup_ = LMoveGroup::New(alloc);
     insertBefore(*rbegin(), exitMoveGroup_);
     return exitMoveGroup_;
 }
 
+#ifdef JS_JITSPEW
 void
 LBlock::dump(GenericPrinter& out)
 {
     out.printf("block%u:\n", mir()->id());
     for (size_t i = 0; i < numPhis(); ++i) {
         getPhi(i)->dump(out);
         out.printf("\n");
     }
@@ -176,16 +179,17 @@ LBlock::dump(GenericPrinter& out)
 
 void
 LBlock::dump()
 {
     Fprinter out(stderr);
     dump(out);
     out.finish();
 }
+#endif
 
 static size_t
 TotalOperandCount(LRecoverInfo* recoverInfo)
 {
     size_t accum = 0;
     for (LRecoverInfo::OperandIter it(recoverInfo); !it; ++it) {
         if (!it->isRecoveredOnBailout())
             accum++;
@@ -328,47 +332,50 @@ LSnapshot::rewriteRecoveredInput(LUse in
     // Mark any operands to this snapshot with the same value as input as being
     // equal to the instruction's result.
     for (size_t i = 0; i < numEntries(); i++) {
         if (getEntry(i)->isUse() && getEntry(i)->toUse()->virtualRegister() == input.virtualRegister())
             setEntry(i, LUse(input.virtualRegister(), LUse::RECOVERED_INPUT));
     }
 }
 
+#ifdef JS_JITSPEW
 void
 LNode::printName(GenericPrinter& out, Opcode op)
 {
     static const char * const names[] =
     {
-#define LIROP(x) #x,
+# define LIROP(x) #x,
         LIR_OPCODE_LIST(LIROP)
-#undef LIROP
+# undef LIROP
     };
-    const char* name = names[op];
+    const char* name = names[uint32_t(op)];
     size_t len = strlen(name);
     for (size_t i = 0; i < len; i++)
         out.printf("%c", tolower(name[i]));
 }
 
 void
 LNode::printName(GenericPrinter& out)
 {
     printName(out, op());
 }
+#endif
 
 bool
 LAllocation::aliases(const LAllocation& other) const
 {
     if (isFloatReg() && other.isFloatReg())
         return toFloatReg()->reg().aliases(other.toFloatReg()->reg());
     return *this == other;
 }
 
+#ifdef JS_JITSPEW
 static const char*
-typeName(LDefinition::Type type)
+DefTypeName(LDefinition::Type type)
 {
     switch (type) {
       case LDefinition::GENERAL: return "g";
       case LDefinition::INT32: return "i";
       case LDefinition::OBJECT: return "o";
       case LDefinition::SLOTS: return "s";
       case LDefinition::FLOAT32: return "f";
       case LDefinition::DOUBLE: return "d";
@@ -389,17 +396,17 @@ UniqueChars
 LDefinition::toString() const
 {
     AutoEnterOOMUnsafeRegion oomUnsafe;
 
     UniqueChars buf;
     if (isBogusTemp()) {
         buf = JS_smprintf("bogus");
     } else {
-        buf = JS_smprintf("v%u<%s>", virtualRegister(), typeName(type()));
+        buf = JS_smprintf("v%u<%s>", virtualRegister(), DefTypeName(type()));
         if (buf) {
             if (policy() == LDefinition::FIXED)
                 buf = JS_sprintf_append(Move(buf), ":%s", output()->toString().get());
             else if (policy() == LDefinition::MUST_REUSE_INPUT)
                 buf = JS_sprintf_append(Move(buf), ":tied(%u)", getReusedInput());
         }
     }
 
@@ -502,16 +509,17 @@ LNode::printOperands(GenericPrinter& out
         return;
     }
 
     if (isPhi())
         PrintOperands(out, toPhi());
     else
         PrintOperands(out, toInstruction());
 }
+#endif
 
 void
 LInstruction::assignSnapshot(LSnapshot* snapshot)
 {
     MOZ_ASSERT(!snapshot_);
     snapshot_ = snapshot;
 
 #ifdef JS_JITSPEW
@@ -540,17 +548,17 @@ NumSuccessorsHelper(const LControlInstru
     return Succs;
 }
 
 static size_t
 NumSuccessors(const LInstruction* ins)
 {
     switch (ins->op()) {
       default: MOZ_CRASH("Unexpected LIR op");
-# define LIROP(x) case LNode::LOp_##x: return NumSuccessorsHelper(ins->to##x());
+# define LIROP(x) case LNode::Opcode::x: return NumSuccessorsHelper(ins->to##x());
     LIR_OPCODE_LIST(LIROP)
 # undef LIROP
     }
 }
 
 static MBasicBlock*
 GetSuccessorHelper(const LNode* ins, size_t i)
 {
@@ -566,23 +574,24 @@ GetSuccessorHelper(const LControlInstruc
 
 static MBasicBlock*
 GetSuccessor(const LInstruction* ins, size_t i)
 {
     MOZ_ASSERT(i < NumSuccessors(ins));
 
     switch (ins->op()) {
       default: MOZ_CRASH("Unexpected LIR op");
-# define LIROP(x) case LNode::LOp_##x: return GetSuccessorHelper(ins->to##x(), i);
+# define LIROP(x) case LNode::Opcode::x: return GetSuccessorHelper(ins->to##x(), i);
     LIR_OPCODE_LIST(LIROP)
 # undef LIROP
     }
 }
 #endif
 
+#ifdef JS_JITSPEW
 void
 LNode::dump(GenericPrinter& out)
 {
     if (numDefs() != 0) {
         out.printf("{");
         for (size_t i = 0; i < numDefs(); i++) {
             const LDefinition* def = isPhi() ? toPhi()->getDef(i) : toInstruction()->getDef(i);
             out.printf("%s", def->toString().get());
@@ -633,21 +642,22 @@ LNode::dump()
     out.finish();
 }
 
 const char*
 LNode::getExtraName() const
 {
     switch (op()) {
       default: MOZ_CRASH("Unexpected LIR op");
-# define LIROP(x) case LNode::LOp_##x: return to##x()->extraName();
+# define LIROP(x) case LNode::Opcode::x: return to##x()->extraName();
     LIR_OPCODE_LIST(LIROP)
 # undef LIROP
     }
 }
+#endif
 
 void
 LInstruction::initSafepoint(TempAllocator& alloc)
 {
     MOZ_ASSERT(!safepoint_);
     safepoint_ = new(alloc) LSafepoint(alloc);
     MOZ_ASSERT(safepoint_);
 }
@@ -703,27 +713,27 @@ LMoveGroup::addAfter(LAllocation from, L
             moves_[i] = LMove(from, to, type);
             return true;
         }
     }
 
     return add(from, to, type);
 }
 
+#ifdef JS_JITSPEW
 void
 LMoveGroup::printOperands(GenericPrinter& out)
 {
     for (size_t i = 0; i < numMoves(); i++) {
         const LMove& move = getMove(i);
         out.printf(" [%s -> %s", move.from().toString().get(), move.to().toString().get());
-#ifdef DEBUG
-        out.printf(", %s", typeName(move.type()));
-#endif
+        out.printf(", %s", DefTypeName(move.type()));
         out.printf("]");
         if (i != numMoves() - 1)
             out.printf(",");
     }
 }
+#endif
 
 #define LIROP(x) static_assert(!std::is_polymorphic<L##x>::value, \
                                "LIR instructions should not have virtual methods");
     LIR_OPCODE_LIST(LIROP)
 #undef LIROP
--- a/js/src/jit/LIR.h
+++ b/js/src/jit/LIR.h
@@ -182,19 +182,22 @@ class LAllocation : public TempObject
     bool operator !=(const LAllocation& other) const {
         return bits_ != other.bits_;
     }
 
     HashNumber hash() const {
         return bits_;
     }
 
+    bool aliases(const LAllocation& other) const;
+
+#ifdef JS_JITSPEW
     UniqueChars toString() const;
-    bool aliases(const LAllocation& other) const;
     void dump() const;
+#endif
 };
 
 class LUse : public LAllocation
 {
     static const uint32_t POLICY_BITS = 3;
     static const uint32_t POLICY_SHIFT = 0;
     static const uint32_t POLICY_MASK = (1 << POLICY_BITS) - 1;
     static const uint32_t REG_BITS = 6;
@@ -633,17 +636,19 @@ class LDefinition
             return LDefinition::SIMD128FLOAT;
           default:
             MOZ_CRASH("unexpected type");
         }
     }
 
     UniqueChars toString() const;
 
+#ifdef JS_JITSPEW
     void dump() const;
+#endif
 };
 
 using LInt64Definition = LInt64Value<LDefinition>;
 
 // Forward declarations of LIR types.
 #define LIROP(op) class L##op;
     LIR_OPCODE_LIST(LIROP)
 #undef LIROP
@@ -672,69 +677,71 @@ class LNode
     uint32_t nonPhiNumOperands_ : 6;
     // For LInstruction, the first operand is stored at offset
     // sizeof(LInstruction) + nonPhiOperandsOffset_ * sizeof(uintptr_t).
     uint32_t nonPhiOperandsOffset_ : 5;
     uint32_t numDefs_ : 4;
     uint32_t numTemps_ : 4;
 
   public:
-    enum Opcode {
-#define LIROP(name) LOp_##name,
+    enum class Opcode {
+#define LIROP(name) name,
         LIR_OPCODE_LIST(LIROP)
 #undef LIROP
-        LOp_Invalid
+        Invalid
     };
 
     LNode(Opcode op, uint32_t nonPhiNumOperands, uint32_t numDefs, uint32_t numTemps)
       : mir_(nullptr),
         block_(nullptr),
         id_(0),
-        op_(op),
+        op_(uint32_t(op)),
         isCall_(false),
         nonPhiNumOperands_(nonPhiNumOperands),
         nonPhiOperandsOffset_(0),
         numDefs_(numDefs),
         numTemps_(numTemps)
     {
-        MOZ_ASSERT(op_ < LOp_Invalid);
-        MOZ_ASSERT(op_ == op, "opcode must fit in bitfield");
+        MOZ_ASSERT(op < Opcode::Invalid);
+        MOZ_ASSERT(op_ == uint32_t(op), "opcode must fit in bitfield");
         MOZ_ASSERT(nonPhiNumOperands_ == nonPhiNumOperands,
                    "nonPhiNumOperands must fit in bitfield");
         MOZ_ASSERT(numDefs_ == numDefs, "numDefs must fit in bitfield");
         MOZ_ASSERT(numTemps_ == numTemps, "numTemps must fit in bitfield");
     }
 
     const char* opName() {
         switch (op()) {
 #define LIR_NAME_INS(name)                   \
-            case LOp_##name: return #name;
-            LIR_OPCODE_LIST(LIR_NAME_INS)
+          case Opcode::name: return #name;
+          LIR_OPCODE_LIST(LIR_NAME_INS)
 #undef LIR_NAME_INS
           default:
-            return "Invalid";
+            MOZ_CRASH("Invalid op");
         }
     }
 
     // Hook for opcodes to add extra high level detail about what code will be
     // emitted for the op.
   private:
     const char* extraName() const {
         return nullptr;
     }
 
   public:
+#ifdef JS_JITSPEW
     const char* getExtraName() const;
+#endif
 
     Opcode op() const {
         return Opcode(op_);
     }
 
     bool isInstruction() const {
-        return op() != LOp_Phi;
+        return op() != Opcode::Phi;
     }
     inline LInstruction* toInstruction();
     inline const LInstruction* toInstruction() const;
 
     // Returns the number of outputs of this instruction. If an output is
     // unallocated, it is an LDefinition, defining a virtual register.
     size_t numDefs() const {
         return numDefs_;
@@ -769,35 +776,37 @@ class LNode
     void setBlock(LBlock* block) {
         block_ = block;
     }
 
     // For an instruction which has a MUST_REUSE_INPUT output, whether that
     // output register will be restored to its original value when bailing out.
     inline bool recoversInput() const;
 
+#ifdef JS_JITSPEW
     void dump(GenericPrinter& out);
     void dump();
     static void printName(GenericPrinter& out, Opcode op);
     void printName(GenericPrinter& out);
     void printOperands(GenericPrinter& out);
+#endif
 
   public:
     // Opcode testing and casts.
 #define LIROP(name)                                                         \
     bool is##name() const {                                                 \
-        return op() == LOp_##name;                                          \
+        return op() == Opcode::name;                                        \
     }                                                                       \
     inline L##name* to##name();                                             \
     inline const L##name* to##name() const;
     LIR_OPCODE_LIST(LIROP)
 #undef LIROP
 
 #define LIR_HEADER(opcode)                                                  \
-    static constexpr LNode::Opcode classOpcode = LNode::LOp_##opcode;
+    static constexpr LNode::Opcode classOpcode = LNode::Opcode::opcode;
 };
 
 class LInstruction
   : public LNode
   , public TempObject
   , public InlineListNode<LInstruction>
 {
     // This snapshot could be set after a ResumePoint.  It is used to restart
@@ -1080,18 +1089,20 @@ class LBlock
     LMoveGroup* getExitMoveGroup(TempAllocator& alloc);
 
     // Test whether this basic block is empty except for a simple goto, and
     // which is not forming a loop. No code will be emitted for such blocks.
     bool isTrivial() {
         return begin()->isGoto() && !mir()->isLoopHeader();
     }
 
+#ifdef JS_JITSPEW
     void dump(GenericPrinter& out);
     void dump();
+#endif
 };
 
 namespace details {
     template <size_t Defs, size_t Temps>
     class LInstructionFixedDefsTempsHelper : public LInstruction
     {
         mozilla::Array<LDefinition, Defs + Temps> defsAndTemps_;
 
@@ -1980,18 +1991,20 @@ class LIRGraph
     }
     size_t numSafepoints() const {
         return safepoints_.length();
     }
     LInstruction* getSafepoint(size_t i) const {
         return safepoints_[i];
     }
 
+#ifdef JS_JITSPEW
     void dump(GenericPrinter& out);
     void dump();
+#endif
 };
 
 LAllocation::LAllocation(AnyRegister reg)
 {
     if (reg.isFloat())
         *this = LFloatReg(reg.fpu());
     else
         *this = LGeneralReg(reg.gpr());
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -4,16 +4,18 @@
  * 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 "jit/Lowering.h"
 
 #include "mozilla/DebugOnly.h"
 #include "mozilla/EndianUtils.h"
 
+#include <type_traits>
+
 #include "jit/JitSpewer.h"
 #include "jit/LIR.h"
 #include "jit/MIR.h"
 #include "jit/MIRGraph.h"
 #include "wasm/WasmSignalHandlers.h"
 
 #include "jit/shared/Lowering-shared-inl.h"
 #include "vm/BytecodeUtil-inl.h"
@@ -5182,16 +5184,17 @@ LIRGenerator::visitGetPrototypeOf(MGetPr
     MOZ_ASSERT(ins->target()->type() == MIRType::Object);
     MOZ_ASSERT(ins->type() == MIRType::Value);
 
     auto lir = new(alloc()) LGetPrototypeOf(useRegister(ins->target()));
     defineBox(lir, ins);
     assignSafepoint(lir, ins);
 }
 
+#ifdef JS_JITSPEW
 static void
 SpewResumePoint(MBasicBlock* block, MInstruction* ins, MResumePoint* resumePoint)
 {
     Fprinter& out = JitSpewPrinter();
     out.printf("Current resume point %p details:\n", (void*)resumePoint);
     out.printf("    frame count: %u\n", resumePoint->frameCount());
 
     if (ins) {
@@ -5209,28 +5212,47 @@ SpewResumePoint(MBasicBlock* block, MIns
 
     for (size_t i = 0, e = resumePoint->numOperands(); i < e; i++) {
         MDefinition* in = resumePoint->getOperand(i);
         out.printf("    slot%u: ", (unsigned)i);
         in->printName(out);
         out.printf("\n");
     }
 }
+#endif
+
+void
+LIRGenerator::visitInstructionDispatch(MInstruction* ins)
+{
+    switch (ins->op()) {
+#define MIR_OP(op) case MDefinition::Opcode::op: visit##op(ins->to##op()); break;
+    MIR_OPCODE_LIST(MIR_OP)
+#undef MIR_OP
+      default:
+        MOZ_CRASH("Invalid instruction");
+    }
+}
+
+void
+LIRGeneratorShared::visitEmittedAtUses(MInstruction* ins)
+{
+    static_cast<LIRGenerator*>(this)->visitInstructionDispatch(ins);
+}
 
 bool
 LIRGenerator::visitInstruction(MInstruction* ins)
 {
     if (ins->isRecoveredOnBailout()) {
         MOZ_ASSERT(!JitOptions.disableRecoverIns);
         return true;
     }
 
     if (!gen->ensureBallast())
         return false;
-    ins->accept(this);
+    visitInstructionDispatch(ins);
 
     if (ins->possiblyCalls()) {
         gen->setNeedsStaticStackAlignment();
         gen->setNeedsOverrecursedCheck();
     }
 
     if (ins->resumePoint())
         updateResumeState(ins);
@@ -5264,18 +5286,20 @@ LIRGenerator::definePhis()
         }
     }
 }
 
 void
 LIRGenerator::updateResumeState(MInstruction* ins)
 {
     lastResumePoint_ = ins->resumePoint();
+#ifdef JS_JITSPEW
     if (JitSpewEnabled(JitSpew_IonSnapshots) && lastResumePoint_)
         SpewResumePoint(nullptr, ins, lastResumePoint_);
+#endif
 }
 
 void
 LIRGenerator::updateResumeState(MBasicBlock* block)
 {
     // As Value Numbering phase can remove edges from the entry basic block to a
     // code paths reachable from the OSR entry point, we have to add fixup
     // blocks to keep the dominator tree organized the same way. These fixup
@@ -5283,18 +5307,20 @@ LIRGenerator::updateResumeState(MBasicBl
     // an OSR block.
     //
     // Note: RangeAnalysis can flag blocks as unreachable, but they are only
     // removed iff GVN (including UCE) is enabled.
     MOZ_ASSERT_IF(!mir()->compilingWasm() && !block->unreachable(), block->entryResumePoint());
     MOZ_ASSERT_IF(block->unreachable(), block->graph().osrBlock() ||
                   !mir()->optimizationInfo().gvnEnabled());
     lastResumePoint_ = block->entryResumePoint();
+#ifdef JS_JITSPEW
     if (JitSpewEnabled(JitSpew_IonSnapshots) && lastResumePoint_)
         SpewResumePoint(block, nullptr, lastResumePoint_);
+#endif
 }
 
 bool
 LIRGenerator::visitBlock(MBasicBlock* block)
 {
     current = block->lir();
     updateResumeState(block);
 
@@ -5418,8 +5444,11 @@ LIRGenerator::visitArgumentState(MArgume
     // ArgumentState nodes are always inlined at their uses.
 }
 
 void
 LIRGenerator::visitUnknownValue(MUnknownValue* ins)
 {
     MOZ_CRASH("Can not lower unknown value.");
 }
+
+static_assert(!std::is_polymorphic<LIRGenerator>::value,
+              "LIRGenerator should not have any virtual methods");
--- a/js/src/jit/Lowering.h
+++ b/js/src/jit/Lowering.h
@@ -27,17 +27,17 @@
 # include "jit/none/Lowering-none.h"
 #else
 # error "Unknown architecture!"
 #endif
 
 namespace js {
 namespace jit {
 
-class LIRGenerator : public LIRGeneratorSpecific
+class LIRGenerator final : public LIRGeneratorSpecific
 {
     void updateResumeState(MInstruction* ins);
     void updateResumeState(MBasicBlock* block);
 
     // The maximum depth, for framesizeclass determination.
     uint32_t maxargslots_;
 
   public:
@@ -62,302 +62,303 @@ class LIRGenerator : public LIRGenerator
     void definePhis();
 
     MOZ_MUST_USE bool lowerCallArguments(MCall* call);
 
     template <typename LClass>
     LInstruction* lowerWasmCall(MWasmCall* ins, bool needsBoundsCheck);
 
   public:
+    void visitInstructionDispatch(MInstruction* ins);
     MOZ_MUST_USE bool visitInstruction(MInstruction* ins);
     MOZ_MUST_USE bool visitBlock(MBasicBlock* block);
 
     // Visitor hooks are explicit, to give CPU-specific versions a chance to
     // intercept without a bunch of explicit gunk in the .cpp.
-    void visitCloneLiteral(MCloneLiteral* ins) override;
-    void visitParameter(MParameter* param) override;
-    void visitCallee(MCallee* callee) override;
-    void visitIsConstructing(MIsConstructing* ins) override;
-    void visitGoto(MGoto* ins) override;
-    void visitTableSwitch(MTableSwitch* tableswitch) override;
-    void visitNewArray(MNewArray* ins) override;
-    void visitNewArrayCopyOnWrite(MNewArrayCopyOnWrite* ins) override;
-    void visitNewArrayDynamicLength(MNewArrayDynamicLength* ins) override;
-    void visitNewIterator(MNewIterator* ins) override;
-    void visitNewTypedArray(MNewTypedArray* ins) override;
-    void visitNewTypedArrayDynamicLength(MNewTypedArrayDynamicLength* ins) override;
-    void visitNewObject(MNewObject* ins) override;
-    void visitNewTypedObject(MNewTypedObject* ins) override;
-    void visitNewNamedLambdaObject(MNewNamedLambdaObject* ins) override;
-    void visitNewCallObject(MNewCallObject* ins) override;
-    void visitNewSingletonCallObject(MNewSingletonCallObject* ins) override;
-    void visitNewStringObject(MNewStringObject* ins) override;
-    void visitNewDerivedTypedObject(MNewDerivedTypedObject* ins) override;
-    void visitInitElem(MInitElem* ins) override;
-    void visitInitElemGetterSetter(MInitElemGetterSetter* ins) override;
-    void visitMutateProto(MMutateProto* ins) override;
-    void visitInitPropGetterSetter(MInitPropGetterSetter* ins) override;
-    void visitCheckOverRecursed(MCheckOverRecursed* ins) override;
-    void visitDefVar(MDefVar* ins) override;
-    void visitDefLexical(MDefLexical* ins) override;
-    void visitDefFun(MDefFun* ins) override;
-    void visitCreateThisWithTemplate(MCreateThisWithTemplate* ins) override;
-    void visitCreateThisWithProto(MCreateThisWithProto* ins) override;
-    void visitCreateThis(MCreateThis* ins) override;
-    void visitCreateArgumentsObject(MCreateArgumentsObject* ins) override;
-    void visitGetArgumentsObjectArg(MGetArgumentsObjectArg* ins) override;
-    void visitSetArgumentsObjectArg(MSetArgumentsObjectArg* ins) override;
-    void visitReturnFromCtor(MReturnFromCtor* ins) override;
-    void visitComputeThis(MComputeThis* ins) override;
-    void visitImplicitThis(MImplicitThis* ins) override;
-    void visitCall(MCall* call) override;
-    void visitApplyArgs(MApplyArgs* apply) override;
-    void visitApplyArray(MApplyArray* apply) override;
-    void visitBail(MBail* bail) override;
-    void visitUnreachable(MUnreachable* unreachable) override;
-    void visitEncodeSnapshot(MEncodeSnapshot* ins) override;
-    void visitAssertFloat32(MAssertFloat32* ins) override;
-    void visitAssertRecoveredOnBailout(MAssertRecoveredOnBailout* ins) override;
-    void visitGetDynamicName(MGetDynamicName* ins) override;
-    void visitCallDirectEval(MCallDirectEval* ins) override;
-    void visitTest(MTest* test) override;
-    void visitGotoWithFake(MGotoWithFake* ins) override;
-    void visitFunctionDispatch(MFunctionDispatch* ins) override;
-    void visitObjectGroupDispatch(MObjectGroupDispatch* ins) override;
-    void visitCompare(MCompare* comp) override;
-    void visitSameValue(MSameValue* comp) override;
-    void visitTypeOf(MTypeOf* ins) override;
-    void visitToAsync(MToAsync* ins) override;
-    void visitToAsyncGen(MToAsyncGen* ins) override;
-    void visitToAsyncIter(MToAsyncIter* ins) override;
-    void visitToId(MToId* ins) override;
-    void visitBitNot(MBitNot* ins) override;
-    void visitBitAnd(MBitAnd* ins) override;
-    void visitBitOr(MBitOr* ins) override;
-    void visitBitXor(MBitXor* ins) override;
-    void visitLsh(MLsh* ins) override;
-    void visitRsh(MRsh* ins) override;
-    void visitUrsh(MUrsh* ins) override;
-    void visitSignExtendInt32(MSignExtendInt32* ins) override;
-    void visitRotate(MRotate* ins) override;
-    void visitFloor(MFloor* ins) override;
-    void visitCeil(MCeil* ins) override;
-    void visitRound(MRound* ins) override;
-    void visitNearbyInt(MNearbyInt* ins) override;
-    void visitMinMax(MMinMax* ins) override;
-    void visitAbs(MAbs* ins) override;
-    void visitClz(MClz* ins) override;
-    void visitCtz(MCtz* ins) override;
-    void visitSqrt(MSqrt* ins) override;
-    void visitPopcnt(MPopcnt* ins) override;
-    void visitAtan2(MAtan2* ins) override;
-    void visitHypot(MHypot* ins) override;
-    void visitPow(MPow* ins) override;
-    void visitMathFunction(MMathFunction* ins) override;
-    void visitAdd(MAdd* ins) override;
-    void visitSub(MSub* ins) override;
-    void visitMul(MMul* ins) override;
-    void visitDiv(MDiv* ins) override;
-    void visitMod(MMod* ins) override;
-    void visitConcat(MConcat* ins) override;
-    void visitCharCodeAt(MCharCodeAt* ins) override;
-    void visitFromCharCode(MFromCharCode* ins) override;
-    void visitFromCodePoint(MFromCodePoint* ins) override;
-    void visitStringConvertCase(MStringConvertCase* ins) override;
-    void visitSinCos(MSinCos *ins) override;
-    void visitStringSplit(MStringSplit* ins) override;
-    void visitStart(MStart* start) override;
-    void visitOsrEntry(MOsrEntry* entry) override;
-    void visitNop(MNop* nop) override;
-    void visitLimitedTruncate(MLimitedTruncate* nop) override;
-    void visitOsrValue(MOsrValue* value) override;
-    void visitOsrEnvironmentChain(MOsrEnvironmentChain* object) override;
-    void visitOsrReturnValue(MOsrReturnValue* value) override;
-    void visitOsrArgumentsObject(MOsrArgumentsObject* object) override;
-    void visitToDouble(MToDouble* convert) override;
-    void visitToFloat32(MToFloat32* convert) override;
-    void visitToNumberInt32(MToNumberInt32* convert) override;
-    void visitTruncateToInt32(MTruncateToInt32* truncate) override;
-    void visitWasmTruncateToInt32(MWasmTruncateToInt32* truncate) override;
-    void visitWrapInt64ToInt32(MWrapInt64ToInt32* ins) override;
-    void visitToString(MToString* convert) override;
-    void visitToObject(MToObject* convert) override;
-    void visitToObjectOrNull(MToObjectOrNull* convert) override;
-    void visitRegExp(MRegExp* ins) override;
-    void visitRegExpMatcher(MRegExpMatcher* ins) override;
-    void visitRegExpSearcher(MRegExpSearcher* ins) override;
-    void visitRegExpTester(MRegExpTester* ins) override;
-    void visitRegExpPrototypeOptimizable(MRegExpPrototypeOptimizable* ins) override;
-    void visitRegExpInstanceOptimizable(MRegExpInstanceOptimizable* ins) override;
-    void visitGetFirstDollarIndex(MGetFirstDollarIndex* ins) override;
-    void visitStringReplace(MStringReplace* ins) override;
-    void visitBinarySharedStub(MBinarySharedStub* ins) override;
-    void visitUnarySharedStub(MUnarySharedStub* ins) override;
-    void visitNullarySharedStub(MNullarySharedStub* ins) override;
-    void visitClassConstructor(MClassConstructor* ins) override;
-    void visitLambda(MLambda* ins) override;
-    void visitLambdaArrow(MLambdaArrow* ins) override;
-    void visitSetFunName(MSetFunName* ins) override;
-    void visitNewLexicalEnvironmentObject(MNewLexicalEnvironmentObject* ins) override;
-    void visitCopyLexicalEnvironmentObject(MCopyLexicalEnvironmentObject* ins) override;
-    void visitKeepAliveObject(MKeepAliveObject* ins) override;
-    void visitSlots(MSlots* ins) override;
-    void visitElements(MElements* ins) override;
-    void visitConstantElements(MConstantElements* ins) override;
-    void visitConvertElementsToDoubles(MConvertElementsToDoubles* ins) override;
-    void visitMaybeToDoubleElement(MMaybeToDoubleElement* ins) override;
-    void visitMaybeCopyElementsForWrite(MMaybeCopyElementsForWrite* ins) override;
-    void visitLoadSlot(MLoadSlot* ins) override;
-    void visitLoadFixedSlotAndUnbox(MLoadFixedSlotAndUnbox* ins) override;
-    void visitFunctionEnvironment(MFunctionEnvironment* ins) override;
-    void visitHomeObject(MHomeObject* ins) override;
-    void visitHomeObjectSuperBase(MHomeObjectSuperBase* ins) override;
-    void visitInterruptCheck(MInterruptCheck* ins) override;
-    void visitWasmTrap(MWasmTrap* ins) override;
-    void visitWasmReinterpret(MWasmReinterpret* ins) override;
-    void visitStoreSlot(MStoreSlot* ins) override;
-    void visitFilterTypeSet(MFilterTypeSet* ins) override;
-    void visitTypeBarrier(MTypeBarrier* ins) override;
-    void visitPostWriteBarrier(MPostWriteBarrier* ins) override;
-    void visitPostWriteElementBarrier(MPostWriteElementBarrier* ins) override;
-    void visitArrayLength(MArrayLength* ins) override;
-    void visitSetArrayLength(MSetArrayLength* ins) override;
-    void visitGetNextEntryForIterator(MGetNextEntryForIterator* ins) override;
-    void visitTypedArrayLength(MTypedArrayLength* ins) override;
-    void visitTypedArrayElements(MTypedArrayElements* ins) override;
-    void visitSetDisjointTypedElements(MSetDisjointTypedElements* ins) override;
-    void visitTypedObjectElements(MTypedObjectElements* ins) override;
-    void visitSetTypedObjectOffset(MSetTypedObjectOffset* ins) override;
-    void visitTypedObjectDescr(MTypedObjectDescr* ins) override;
-    void visitInitializedLength(MInitializedLength* ins) override;
-    void visitSetInitializedLength(MSetInitializedLength* ins) override;
-    void visitNot(MNot* ins) override;
-    void visitBoundsCheck(MBoundsCheck* ins) override;
-    void visitBoundsCheckLower(MBoundsCheckLower* ins) override;
-    void visitSpectreMaskIndex(MSpectreMaskIndex* ins) override;
-    void visitLoadElement(MLoadElement* ins) override;
-    void visitLoadElementHole(MLoadElementHole* ins) override;
-    void visitLoadUnboxedObjectOrNull(MLoadUnboxedObjectOrNull* ins) override;
-    void visitLoadUnboxedString(MLoadUnboxedString* ins) override;
-    void visitLoadElementFromState(MLoadElementFromState* ins) override;
-    void visitStoreElement(MStoreElement* ins) override;
-    void visitStoreElementHole(MStoreElementHole* ins) override;
-    void visitFallibleStoreElement(MFallibleStoreElement* ins) override;
-    void visitStoreUnboxedObjectOrNull(MStoreUnboxedObjectOrNull* ins) override;
-    void visitStoreUnboxedString(MStoreUnboxedString* ins) override;
-    void visitConvertUnboxedObjectToNative(MConvertUnboxedObjectToNative* ins) override;
-    void visitEffectiveAddress(MEffectiveAddress* ins) override;
-    void visitArrayPopShift(MArrayPopShift* ins) override;
-    void visitArrayPush(MArrayPush* ins) override;
-    void visitArraySlice(MArraySlice* ins) override;
-    void visitArrayJoin(MArrayJoin* ins) override;
-    void visitLoadUnboxedScalar(MLoadUnboxedScalar* ins) override;
-    void visitLoadTypedArrayElementHole(MLoadTypedArrayElementHole* ins) override;
-    void visitLoadTypedArrayElementStatic(MLoadTypedArrayElementStatic* ins) override;
-    void visitStoreUnboxedScalar(MStoreUnboxedScalar* ins) override;
-    void visitStoreTypedArrayElementHole(MStoreTypedArrayElementHole* ins) override;
-    void visitClampToUint8(MClampToUint8* ins) override;
-    void visitLoadFixedSlot(MLoadFixedSlot* ins) override;
-    void visitStoreFixedSlot(MStoreFixedSlot* ins) override;
-    void visitGetPropSuperCache(MGetPropSuperCache* ins) override;
-    void visitGetPropertyCache(MGetPropertyCache* ins) override;
-    void visitGetPropertyPolymorphic(MGetPropertyPolymorphic* ins) override;
-    void visitSetPropertyPolymorphic(MSetPropertyPolymorphic* ins) override;
-    void visitBindNameCache(MBindNameCache* ins) override;
-    void visitCallBindVar(MCallBindVar* ins) override;
-    void visitGuardObjectIdentity(MGuardObjectIdentity* ins) override;
-    void visitGuardShape(MGuardShape* ins) override;
-    void visitGuardObjectGroup(MGuardObjectGroup* ins) override;
-    void visitGuardObject(MGuardObject* ins) override;
-    void visitGuardString(MGuardString* ins) override;
-    void visitGuardReceiverPolymorphic(MGuardReceiverPolymorphic* ins) override;
-    void visitGuardUnboxedExpando(MGuardUnboxedExpando* ins) override;
-    void visitLoadUnboxedExpando(MLoadUnboxedExpando* ins) override;
-    void visitPolyInlineGuard(MPolyInlineGuard* ins) override;
-    void visitAssertRange(MAssertRange* ins) override;
-    void visitCallGetProperty(MCallGetProperty* ins) override;
-    void visitDeleteProperty(MDeleteProperty* ins) override;
-    void visitDeleteElement(MDeleteElement* ins) override;
-    void visitGetNameCache(MGetNameCache* ins) override;
-    void visitCallGetIntrinsicValue(MCallGetIntrinsicValue* ins) override;
-    void visitCallGetElement(MCallGetElement* ins) override;
-    void visitCallSetElement(MCallSetElement* ins) override;
-    void visitCallInitElementArray(MCallInitElementArray* ins) override;
-    void visitSetPropertyCache(MSetPropertyCache* ins) override;
-    void visitCallSetProperty(MCallSetProperty* ins) override;
-    void visitGetIteratorCache(MGetIteratorCache* ins) override;
-    void visitIteratorMore(MIteratorMore* ins) override;
-    void visitIsNoIter(MIsNoIter* ins) override;
-    void visitIteratorEnd(MIteratorEnd* ins) override;
-    void visitStringLength(MStringLength* ins) override;
-    void visitArgumentsLength(MArgumentsLength* ins) override;
-    void visitGetFrameArgument(MGetFrameArgument* ins) override;
-    void visitSetFrameArgument(MSetFrameArgument* ins) override;
-    void visitRunOncePrologue(MRunOncePrologue* ins) override;
-    void visitRest(MRest* ins) override;
-    void visitThrow(MThrow* ins) override;
-    void visitInCache(MInCache* ins) override;
-    void visitInArray(MInArray* ins) override;
-    void visitHasOwnCache(MHasOwnCache* ins) override;
-    void visitInstanceOf(MInstanceOf* ins) override;
-    void visitInstanceOfCache(MInstanceOfCache* ins) override;
-    void visitIsCallable(MIsCallable* ins) override;
-    void visitIsConstructor(MIsConstructor* ins) override;
-    void visitIsArray(MIsArray* ins) override;
-    void visitIsTypedArray(MIsTypedArray* ins) override;
-    void visitIsObject(MIsObject* ins) override;
-    void visitHasClass(MHasClass* ins) override;
-    void visitObjectClassToString(MObjectClassToString* ins) override;
-    void visitWasmAddOffset(MWasmAddOffset* ins) override;
-    void visitWasmLoadTls(MWasmLoadTls* ins) override;
-    void visitWasmBoundsCheck(MWasmBoundsCheck* ins) override;
-    void visitWasmAlignmentCheck(MWasmAlignmentCheck* ins) override;
-    void visitWasmLoadGlobalVar(MWasmLoadGlobalVar* ins) override;
-    void visitWasmStoreGlobalVar(MWasmStoreGlobalVar* ins) override;
-    void visitWasmParameter(MWasmParameter* ins) override;
-    void visitWasmReturn(MWasmReturn* ins) override;
-    void visitWasmReturnVoid(MWasmReturnVoid* ins) override;
-    void visitWasmStackArg(MWasmStackArg* ins) override;
-    void visitWasmCall(MWasmCall* ins) override;
-    void visitSetDOMProperty(MSetDOMProperty* ins) override;
-    void visitGetDOMProperty(MGetDOMProperty* ins) override;
-    void visitGetDOMMember(MGetDOMMember* ins) override;
-    void visitRecompileCheck(MRecompileCheck* ins) override;
-    void visitSimdBox(MSimdBox* ins) override;
-    void visitSimdUnbox(MSimdUnbox* ins) override;
-    void visitSimdUnaryArith(MSimdUnaryArith* ins) override;
-    void visitSimdBinaryComp(MSimdBinaryComp* ins) override;
-    void visitSimdBinaryBitwise(MSimdBinaryBitwise* ins) override;
-    void visitSimdShift(MSimdShift* ins) override;
-    void visitSimdConstant(MSimdConstant* ins) override;
-    void visitSimdConvert(MSimdConvert* ins) override;
-    void visitSimdReinterpretCast(MSimdReinterpretCast* ins) override;
-    void visitSimdAllTrue(MSimdAllTrue* ins) override;
-    void visitSimdAnyTrue(MSimdAnyTrue* ins) override;
-    void visitPhi(MPhi* ins) override;
-    void visitBeta(MBeta* ins) override;
-    void visitObjectState(MObjectState* ins) override;
-    void visitArrayState(MArrayState* ins) override;
-    void visitArgumentState(MArgumentState* ins) override;
-    void visitUnknownValue(MUnknownValue* ins) override;
-    void visitLexicalCheck(MLexicalCheck* ins) override;
-    void visitThrowRuntimeLexicalError(MThrowRuntimeLexicalError* ins) override;
-    void visitGlobalNameConflictsCheck(MGlobalNameConflictsCheck* ins) override;
-    void visitDebugger(MDebugger* ins) override;
-    void visitNewTarget(MNewTarget* ins) override;
-    void visitArrowNewTarget(MArrowNewTarget* ins) override;
-    void visitNaNToZero(MNaNToZero *ins) override;
-    void visitAtomicIsLockFree(MAtomicIsLockFree* ins) override;
-    void visitGuardSharedTypedArray(MGuardSharedTypedArray* ins) override;
-    void visitCheckReturn(MCheckReturn* ins) override;
-    void visitCheckIsObj(MCheckIsObj* ins) override;
-    void visitCheckIsCallable(MCheckIsCallable* ins) override;
-    void visitCheckObjCoercible(MCheckObjCoercible* ins) override;
-    void visitDebugCheckSelfHosted(MDebugCheckSelfHosted* ins) override;
-    void visitFinishBoundFunctionInit(MFinishBoundFunctionInit* ins) override;
-    void visitIsPackedArray(MIsPackedArray* ins) override;
-    void visitGetPrototypeOf(MGetPrototypeOf* ins) override;
+    void visitCloneLiteral(MCloneLiteral* ins);
+    void visitParameter(MParameter* param);
+    void visitCallee(MCallee* callee);
+    void visitIsConstructing(MIsConstructing* ins);
+    void visitGoto(MGoto* ins);
+    void visitTableSwitch(MTableSwitch* tableswitch);
+    void visitNewArray(MNewArray* ins);
+    void visitNewArrayCopyOnWrite(MNewArrayCopyOnWrite* ins);
+    void visitNewArrayDynamicLength(MNewArrayDynamicLength* ins);
+    void visitNewIterator(MNewIterator* ins);
+    void visitNewTypedArray(MNewTypedArray* ins);
+    void visitNewTypedArrayDynamicLength(MNewTypedArrayDynamicLength* ins);
+    void visitNewObject(MNewObject* ins);
+    void visitNewTypedObject(MNewTypedObject* ins);
+    void visitNewNamedLambdaObject(MNewNamedLambdaObject* ins);
+    void visitNewCallObject(MNewCallObject* ins);
+    void visitNewSingletonCallObject(MNewSingletonCallObject* ins);
+    void visitNewStringObject(MNewStringObject* ins);
+    void visitNewDerivedTypedObject(MNewDerivedTypedObject* ins);
+    void visitInitElem(MInitElem* ins);
+    void visitInitElemGetterSetter(MInitElemGetterSetter* ins);
+    void visitMutateProto(MMutateProto* ins);
+    void visitInitPropGetterSetter(MInitPropGetterSetter* ins);
+    void visitCheckOverRecursed(MCheckOverRecursed* ins);
+    void visitDefVar(MDefVar* ins);
+    void visitDefLexical(MDefLexical* ins);
+    void visitDefFun(MDefFun* ins);
+    void visitCreateThisWithTemplate(MCreateThisWithTemplate* ins);
+    void visitCreateThisWithProto(MCreateThisWithProto* ins);
+    void visitCreateThis(MCreateThis* ins);
+    void visitCreateArgumentsObject(MCreateArgumentsObject* ins);
+    void visitGetArgumentsObjectArg(MGetArgumentsObjectArg* ins);
+    void visitSetArgumentsObjectArg(MSetArgumentsObjectArg* ins);
+    void visitReturnFromCtor(MReturnFromCtor* ins);
+    void visitComputeThis(MComputeThis* ins);
+    void visitImplicitThis(MImplicitThis* ins);
+    void visitCall(MCall* call);
+    void visitApplyArgs(MApplyArgs* apply);
+    void visitApplyArray(MApplyArray* apply);
+    void visitBail(MBail* bail);
+    void visitUnreachable(MUnreachable* unreachable);
+    void visitEncodeSnapshot(MEncodeSnapshot* ins);
+    void visitAssertFloat32(MAssertFloat32* ins);
+    void visitAssertRecoveredOnBailout(MAssertRecoveredOnBailout* ins);
+    void visitGetDynamicName(MGetDynamicName* ins);
+    void visitCallDirectEval(MCallDirectEval* ins);
+    void visitTest(MTest* test);
+    void visitGotoWithFake(MGotoWithFake* ins);
+    void visitFunctionDispatch(MFunctionDispatch* ins);
+    void visitObjectGroupDispatch(MObjectGroupDispatch* ins);
+    void visitCompare(MCompare* comp);
+    void visitSameValue(MSameValue* comp);
+    void visitTypeOf(MTypeOf* ins);
+    void visitToAsync(MToAsync* ins);
+    void visitToAsyncGen(MToAsyncGen* ins);
+    void visitToAsyncIter(MToAsyncIter* ins);
+    void visitToId(MToId* ins);
+    void visitBitNot(MBitNot* ins);
+    void visitBitAnd(MBitAnd* ins);
+    void visitBitOr(MBitOr* ins);
+    void visitBitXor(MBitXor* ins);
+    void visitLsh(MLsh* ins);
+    void visitRsh(MRsh* ins);
+    void visitUrsh(MUrsh* ins);
+    void visitSignExtendInt32(MSignExtendInt32* ins);
+    void visitRotate(MRotate* ins);
+    void visitFloor(MFloor* ins);
+    void visitCeil(MCeil* ins);
+    void visitRound(MRound* ins);
+    void visitNearbyInt(MNearbyInt* ins);
+    void visitMinMax(MMinMax* ins);
+    void visitAbs(MAbs* ins);
+    void visitClz(MClz* ins);
+    void visitCtz(MCtz* ins);
+    void visitSqrt(MSqrt* ins);
+    void visitPopcnt(MPopcnt* ins);
+    void visitAtan2(MAtan2* ins);
+    void visitHypot(MHypot* ins);
+    void visitPow(MPow* ins);
+    void visitMathFunction(MMathFunction* ins);
+    void visitAdd(MAdd* ins);
+    void visitSub(MSub* ins);
+    void visitMul(MMul* ins);
+    void visitDiv(MDiv* ins);
+    void visitMod(MMod* ins);
+    void visitConcat(MConcat* ins);
+    void visitCharCodeAt(MCharCodeAt* ins);
+    void visitFromCharCode(MFromCharCode* ins);
+    void visitFromCodePoint(MFromCodePoint* ins);
+    void visitStringConvertCase(MStringConvertCase* ins);
+    void visitSinCos(MSinCos *ins);
+    void visitStringSplit(MStringSplit* ins);
+    void visitStart(MStart* start);
+    void visitOsrEntry(MOsrEntry* entry);
+    void visitNop(MNop* nop);
+    void visitLimitedTruncate(MLimitedTruncate* nop);
+    void visitOsrValue(MOsrValue* value);
+    void visitOsrEnvironmentChain(MOsrEnvironmentChain* object);
+    void visitOsrReturnValue(MOsrReturnValue* value);
+    void visitOsrArgumentsObject(MOsrArgumentsObject* object);
+    void visitToDouble(MToDouble* convert);
+    void visitToFloat32(MToFloat32* convert);
+    void visitToNumberInt32(MToNumberInt32* convert);
+    void visitTruncateToInt32(MTruncateToInt32* truncate);
+    void visitWasmTruncateToInt32(MWasmTruncateToInt32* truncate);
+    void visitWrapInt64ToInt32(MWrapInt64ToInt32* ins);
+    void visitToString(MToString* convert);
+    void visitToObject(MToObject* convert);
+    void visitToObjectOrNull(MToObjectOrNull* convert);
+    void visitRegExp(MRegExp* ins);
+    void visitRegExpMatcher(MRegExpMatcher* ins);
+    void visitRegExpSearcher(MRegExpSearcher* ins);
+    void visitRegExpTester(MRegExpTester* ins);
+    void visitRegExpPrototypeOptimizable(MRegExpPrototypeOptimizable* ins);
+    void visitRegExpInstanceOptimizable(MRegExpInstanceOptimizable* ins);
+    void visitGetFirstDollarIndex(MGetFirstDollarIndex* ins);
+    void visitStringReplace(MStringReplace* ins);
+    void visitBinarySharedStub(MBinarySharedStub* ins);
+    void visitUnarySharedStub(MUnarySharedStub* ins);
+    void visitNullarySharedStub(MNullarySharedStub* ins);
+    void visitClassConstructor(MClassConstructor* ins);
+    void visitLambda(MLambda* ins);
+    void visitLambdaArrow(MLambdaArrow* ins);
+    void visitSetFunName(MSetFunName* ins);
+    void visitNewLexicalEnvironmentObject(MNewLexicalEnvironmentObject* ins);
+    void visitCopyLexicalEnvironmentObject(MCopyLexicalEnvironmentObject* ins);
+    void visitKeepAliveObject(MKeepAliveObject* ins);
+    void visitSlots(MSlots* ins);
+    void visitElements(MElements* ins);
+    void visitConstantElements(MConstantElements* ins);
+    void visitConvertElementsToDoubles(MConvertElementsToDoubles* ins);
+    void visitMaybeToDoubleElement(MMaybeToDoubleElement* ins);
+    void visitMaybeCopyElementsForWrite(MMaybeCopyElementsForWrite* ins);
+    void visitLoadSlot(MLoadSlot* ins);
+    void visitLoadFixedSlotAndUnbox(MLoadFixedSlotAndUnbox* ins);
+    void visitFunctionEnvironment(MFunctionEnvironment* ins);
+    void visitHomeObject(MHomeObject* ins);
+    void visitHomeObjectSuperBase(MHomeObjectSuperBase* ins);
+    void visitInterruptCheck(MInterruptCheck* ins);
+    void visitWasmTrap(MWasmTrap* ins);
+    void visitWasmReinterpret(MWasmReinterpret* ins);
+    void visitStoreSlot(MStoreSlot* ins);
+    void visitFilterTypeSet(MFilterTypeSet* ins);
+    void visitTypeBarrier(MTypeBarrier* ins);
+    void visitPostWriteBarrier(MPostWriteBarrier* ins);
+    void visitPostWriteElementBarrier(MPostWriteElementBarrier* ins);
+    void visitArrayLength(MArrayLength* ins);
+    void visitSetArrayLength(MSetArrayLength* ins);
+    void visitGetNextEntryForIterator(MGetNextEntryForIterator* ins);
+    void visitTypedArrayLength(MTypedArrayLength* ins);
+    void visitTypedArrayElements(MTypedArrayElements* ins);
+    void visitSetDisjointTypedElements(MSetDisjointTypedElements* ins);
+    void visitTypedObjectElements(MTypedObjectElements* ins);
+    void visitSetTypedObjectOffset(MSetTypedObjectOffset* ins);
+    void visitTypedObjectDescr(MTypedObjectDescr* ins);
+    void visitInitializedLength(MInitializedLength* ins);
+    void visitSetInitializedLength(MSetInitializedLength* ins);
+    void visitNot(MNot* ins);
+    void visitBoundsCheck(MBoundsCheck* ins);
+    void visitBoundsCheckLower(MBoundsCheckLower* ins);
+    void visitSpectreMaskIndex(MSpectreMaskIndex* ins);
+    void visitLoadElement(MLoadElement* ins);
+    void visitLoadElementHole(MLoadElementHole* ins);
+    void visitLoadUnboxedObjectOrNull(MLoadUnboxedObjectOrNull* ins);
+    void visitLoadUnboxedString(MLoadUnboxedString* ins);
+    void visitLoadElementFromState(MLoadElementFromState* ins);
+    void visitStoreElement(MStoreElement* ins);
+    void visitStoreElementHole(MStoreElementHole* ins);
+    void visitFallibleStoreElement(MFallibleStoreElement* ins);
+    void visitStoreUnboxedObjectOrNull(MStoreUnboxedObjectOrNull* ins);
+    void visitStoreUnboxedString(MStoreUnboxedString* ins);
+    void visitConvertUnboxedObjectToNative(MConvertUnboxedObjectToNative* ins);
+    void visitEffectiveAddress(MEffectiveAddress* ins);
+    void visitArrayPopShift(MArrayPopShift* ins);
+    void visitArrayPush(MArrayPush* ins);
+    void visitArraySlice(MArraySlice* ins);
+    void visitArrayJoin(MArrayJoin* ins);
+    void visitLoadUnboxedScalar(MLoadUnboxedScalar* ins);
+    void visitLoadTypedArrayElementHole(MLoadTypedArrayElementHole* ins);
+    void visitLoadTypedArrayElementStatic(MLoadTypedArrayElementStatic* ins);
+    void visitStoreUnboxedScalar(MStoreUnboxedScalar* ins);
+    void visitStoreTypedArrayElementHole(MStoreTypedArrayElementHole* ins);
+    void visitClampToUint8(MClampToUint8* ins);
+    void visitLoadFixedSlot(MLoadFixedSlot* ins);
+    void visitStoreFixedSlot(MStoreFixedSlot* ins);
+    void visitGetPropSuperCache(MGetPropSuperCache* ins);
+    void visitGetPropertyCache(MGetPropertyCache* ins);
+    void visitGetPropertyPolymorphic(MGetPropertyPolymorphic* ins);
+    void visitSetPropertyPolymorphic(MSetPropertyPolymorphic* ins);
+    void visitBindNameCache(MBindNameCache* ins);
+    void visitCallBindVar(MCallBindVar* ins);
+    void visitGuardObjectIdentity(MGuardObjectIdentity* ins);
+    void visitGuardShape(MGuardShape* ins);
+    void visitGuardObjectGroup(MGuardObjectGroup* ins);
+    void visitGuardObject(MGuardObject* ins);
+    void visitGuardString(MGuardString* ins);
+    void visitGuardReceiverPolymorphic(MGuardReceiverPolymorphic* ins);
+    void visitGuardUnboxedExpando(MGuardUnboxedExpando* ins);
+    void visitLoadUnboxedExpando(MLoadUnboxedExpando* ins);
+    void visitPolyInlineGuard(MPolyInlineGuard* ins);
+    void visitAssertRange(MAssertRange* ins);
+    void visitCallGetProperty(MCallGetProperty* ins);
+    void visitDeleteProperty(MDeleteProperty* ins);
+    void visitDeleteElement(MDeleteElement* ins);
+    void visitGetNameCache(MGetNameCache* ins);
+    void visitCallGetIntrinsicValue(MCallGetIntrinsicValue* ins);
+    void visitCallGetElement(MCallGetElement* ins);
+    void visitCallSetElement(MCallSetElement* ins);
+    void visitCallInitElementArray(MCallInitElementArray* ins);
+    void visitSetPropertyCache(MSetPropertyCache* ins);
+    void visitCallSetProperty(MCallSetProperty* ins);
+    void visitGetIteratorCache(MGetIteratorCache* ins);
+    void visitIteratorMore(MIteratorMore* ins);
+    void visitIsNoIter(MIsNoIter* ins);
+    void visitIteratorEnd(MIteratorEnd* ins);
+    void visitStringLength(MStringLength* ins);
+    void visitArgumentsLength(MArgumentsLength* ins);
+    void visitGetFrameArgument(MGetFrameArgument* ins);
+    void visitSetFrameArgument(MSetFrameArgument* ins);
+    void visitRunOncePrologue(MRunOncePrologue* ins);
+    void visitRest(MRest* ins);
+    void visitThrow(MThrow* ins);
+    void visitInCache(MInCache* ins);
+    void visitInArray(MInArray* ins);
+    void visitHasOwnCache(MHasOwnCache* ins);
+    void visitInstanceOf(MInstanceOf* ins);
+    void visitInstanceOfCache(MInstanceOfCache* ins);
+    void visitIsCallable(MIsCallable* ins);
+    void visitIsConstructor(MIsConstructor* ins);
+    void visitIsArray(MIsArray* ins);
+    void visitIsTypedArray(MIsTypedArray* ins);
+    void visitIsObject(MIsObject* ins);
+    void visitHasClass(MHasClass* ins);
+    void visitObjectClassToString(MObjectClassToString* ins);
+    void visitWasmAddOffset(MWasmAddOffset* ins);
+    void visitWasmLoadTls(MWasmLoadTls* ins);
+    void visitWasmBoundsCheck(MWasmBoundsCheck* ins);
+    void visitWasmAlignmentCheck(MWasmAlignmentCheck* ins);
+    void visitWasmLoadGlobalVar(MWasmLoadGlobalVar* ins);
+    void visitWasmStoreGlobalVar(MWasmStoreGlobalVar* ins);
+    void visitWasmParameter(MWasmParameter* ins);
+    void visitWasmReturn(MWasmReturn* ins);
+    void visitWasmReturnVoid(MWasmReturnVoid* ins);
+    void visitWasmStackArg(MWasmStackArg* ins);
+    void visitWasmCall(MWasmCall* ins);
+    void visitSetDOMProperty(MSetDOMProperty* ins);
+    void visitGetDOMProperty(MGetDOMProperty* ins);
+    void visitGetDOMMember(MGetDOMMember* ins);
+    void visitRecompileCheck(MRecompileCheck* ins);
+    void visitSimdBox(MSimdBox* ins);
+    void visitSimdUnbox(MSimdUnbox* ins);
+    void visitSimdUnaryArith(MSimdUnaryArith* ins);
+    void visitSimdBinaryComp(MSimdBinaryComp* ins);
+    void visitSimdBinaryBitwise(MSimdBinaryBitwise* ins);
+    void visitSimdShift(MSimdShift* ins);
+    void visitSimdConstant(MSimdConstant* ins);
+    void visitSimdConvert(MSimdConvert* ins);
+    void visitSimdReinterpretCast(MSimdReinterpretCast* ins);
+    void visitSimdAllTrue(MSimdAllTrue* ins);
+    void visitSimdAnyTrue(MSimdAnyTrue* ins);
+    void visitPhi(MPhi* ins);
+    void visitBeta(MBeta* ins);
+    void visitObjectState(MObjectState* ins);
+    void visitArrayState(MArrayState* ins);
+    void visitArgumentState(MArgumentState* ins);
+    void visitUnknownValue(MUnknownValue* ins);
+    void visitLexicalCheck(MLexicalCheck* ins);
+    void visitThrowRuntimeLexicalError(MThrowRuntimeLexicalError* ins);
+    void visitGlobalNameConflictsCheck(MGlobalNameConflictsCheck* ins);
+    void visitDebugger(MDebugger* ins);
+    void visitNewTarget(MNewTarget* ins);
+    void visitArrowNewTarget(MArrowNewTarget* ins);
+    void visitNaNToZero(MNaNToZero *ins);
+    void visitAtomicIsLockFree(MAtomicIsLockFree* ins);
+    void visitGuardSharedTypedArray(MGuardSharedTypedArray* ins);
+    void visitCheckReturn(MCheckReturn* ins);
+    void visitCheckIsObj(MCheckIsObj* ins);
+    void visitCheckIsCallable(MCheckIsCallable* ins);
+    void visitCheckObjCoercible(MCheckObjCoercible* ins);
+    void visitDebugCheckSelfHosted(MDebugCheckSelfHosted* ins);
+    void visitFinishBoundFunctionInit(MFinishBoundFunctionInit* ins);
+    void visitIsPackedArray(MIsPackedArray* ins);
+    void visitGetPrototypeOf(MGetPrototypeOf* ins);
 };
 
 } // namespace jit
 } // namespace js
 
 #endif /* jit_Lowering_h */
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -66,30 +66,38 @@ static bool
 CheckUsesAreFloat32Consumers(const MInstruction* ins)
 {
     bool allConsumerUses = true;
     for (MUseDefIterator use(ins); allConsumerUses && use; use++)
         allConsumerUses &= use.def()->canConsumeFloat32(use.use());
     return allConsumerUses;
 }
 
-void
-MDefinition::PrintOpcodeName(GenericPrinter& out, MDefinition::Opcode op)
-{
-    static const char * const names[] =
+#ifdef JS_JITSPEW
+static const char*
+OpcodeName(MDefinition::Opcode op)
+{
+    static const char* const names[] =
     {
 #define NAME(x) #x,
         MIR_OPCODE_LIST(NAME)
 #undef NAME
     };
-    const char* name = names[unsigned(op)];
+    return names[unsigned(op)];
+}
+
+void
+MDefinition::PrintOpcodeName(GenericPrinter& out, Opcode op)
+{
+    const char* name = OpcodeName(op);
     size_t len = strlen(name);
     for (size_t i = 0; i < len; i++)
         out.printf("%c", tolower(name[i]));
 }
+#endif
 
 static MConstant*
 EvaluateConstantOperands(TempAllocator& alloc, MBinaryInstruction* ins, bool* ptypeChange = nullptr)
 {
     MDefinition* left = ins->getOperand(0);
     MDefinition* right = ins->getOperand(1);
 
     MOZ_ASSERT(IsTypeRepresentableAsDouble(left->type()));
@@ -215,22 +223,30 @@ EvaluateExactReciprocal(TempAllocator& a
     ins->block()->insertBefore(ins, foldedRhs);
 
     MMul* mul = MMul::New(alloc, left, foldedRhs, ins->type());
     mul->setCommutative();
     mul->setMustPreserveNaN(ins->mustPreserveNaN());
     return mul;
 }
 
+#ifdef JS_JITSPEW
+const char*
+MDefinition::opName() const
+{
+    return OpcodeName(op());
+}
+
 void
 MDefinition::printName(GenericPrinter& out) const
 {
     PrintOpcodeName(out, op());
     out.printf("%u", id());
 }
+#endif
 
 HashNumber
 MDefinition::valueHash() const
 {
     HashNumber out = HashNumber(op());
     for (size_t i = 0, e = numOperands(); i < e; i++)
         out = addU32ToHash(out, getOperand(i)->id());
     if (MDefinition* dep = dependency())
@@ -611,16 +627,17 @@ MTest::filtersUndefinedOrNull(bool trueB
         *filtersUndefined = *filtersNull = true;
         return;
     }
 
     *filtersUndefined = *filtersNull = false;
     *subject = nullptr;
 }
 
+#ifdef JS_JITSPEW
 void
 MDefinition::printOpcode(GenericPrinter& out) const
 {
     PrintOpcodeName(out, op());
     for (size_t j = 0, e = numOperands(); j < e; j++) {
         out.printf(" ");
         if (getUseFor(j)->hasProducer())
             getOperand(j)->printName(out);
@@ -675,16 +692,17 @@ MDefinition::dumpLocation(GenericPrinter
 
 void
 MDefinition::dumpLocation() const
 {
     Fprinter out(stderr);
     dumpLocation(out);
     out.finish();
 }
+#endif
 
 #if defined(DEBUG) || defined(JS_JITSPEW)
 size_t
 MDefinition::useCount() const
 {
     size_t count = 0;
     for (MUseIterator i(uses_.begin()); i != uses_.end(); i++)
         count++;
@@ -1101,16 +1119,17 @@ MConstant::valueHash() const
 }
 
 bool
 MConstant::congruentTo(const MDefinition* ins) const
 {
     return ins->isConstant() && equals(ins->toConstant());
 }
 
+#ifdef JS_JITSPEW
 void
 MConstant::printOpcode(GenericPrinter& out) const
 {
     PrintOpcodeName(out, op());
     out.printf(" ");
     switch (type()) {
       case MIRType::Undefined:
         out.printf("undefined");
@@ -1175,16 +1194,17 @@ MConstant::printOpcode(GenericPrinter& o
         break;
       case MIRType::MagicUninitializedLexical:
         out.printf("magic uninitialized-lexical");
         break;
       default:
         MOZ_CRASH("unexpected type");
     }
 }
+#endif
 
 bool
 MConstant::canProduceFloat32() const
 {
     if (!isTypeRepresentableAsDouble())
         return false;
 
     if (type() == MIRType::Int32)
@@ -1754,16 +1774,17 @@ MSimdShift::AddLegalized(TempAllocator& 
 template <typename T>
 static void
 PrintOpcodeOperation(T* mir, GenericPrinter& out)
 {
     mir->MDefinition::printOpcode(out);
     out.printf(" (%s)", T::OperationName(mir->operation()));
 }
 
+#ifdef JS_JITSPEW
 void
 MSimdBinaryArith::printOpcode(GenericPrinter& out) const
 {
     PrintOpcodeOperation(this, out);
 }
 void
 MSimdBinarySaturating::printOpcode(GenericPrinter& out) const
 {
@@ -1860,16 +1881,17 @@ void MNearbyInt::printOpcode(GenericPrin
     switch (roundingMode_) {
       case RoundingMode::Up:                roundingModeStr = "(up)"; break;
       case RoundingMode::Down:              roundingModeStr = "(down)"; break;
       case RoundingMode::NearestTiesToEven: roundingModeStr = "(nearest ties even)"; break;
       case RoundingMode::TowardsZero:       roundingModeStr = "(towards zero)"; break;
     }
     out.printf(" %s", roundingModeStr);
 }
+#endif
 
 const char*
 MMathFunction::FunctionName(Function function)
 {
     switch (function) {
       case Log:    return "Log";
       case Sin:    return "Sin";
       case Cos:    return "Cos";
@@ -1894,22 +1916,24 @@ MMathFunction::FunctionName(Function fun
       case Floor:  return "Floor";
       case Ceil:   return "Ceil";
       case Round:  return "Round";
       default:
         MOZ_CRASH("Unknown math function");
     }
 }
 
+#ifdef JS_JITSPEW
 void
 MMathFunction::printOpcode(GenericPrinter& out) const
 {
     MDefinition::printOpcode(out);
     out.printf(" %s", FunctionName(function()));
 }
+#endif
 
 MDefinition*
 MMathFunction::foldsTo(TempAllocator& alloc)
 {
     MDefinition* input = getOperand(0);
     if (!input->isConstant() || !input->toConstant()->isTypeRepresentableAsDouble())
         return this;
 
@@ -2008,25 +2032,27 @@ MAtomicIsLockFree::foldsTo(TempAllocator
     return MConstant::New(alloc, BooleanValue(AtomicOperations::isLockfreeJS(i)));
 }
 
 // Define |THIS_SLOT| as part of this translation unit, as it is used to
 // specialized the parameterized |New| function calls introduced by
 // TRIVIAL_NEW_WRAPPERS.
 const int32_t MParameter::THIS_SLOT;
 
+#ifdef JS_JITSPEW
 void
 MParameter::printOpcode(GenericPrinter& out) const
 {
     PrintOpcodeName(out, op());
     if (index() == THIS_SLOT)
         out.printf(" THIS_SLOT");
     else
         out.printf(" %d", index());
 }
+#endif
 
 HashNumber
 MParameter::valueHash() const
 {
     HashNumber hash = MDefinition::valueHash();
     hash = addU32ToHash(hash, index_);
     return hash;
 }
@@ -2270,16 +2296,17 @@ MGoto::New(TempAllocator::Fallible alloc
 }
 
 MGoto*
 MGoto::New(TempAllocator& alloc)
 {
     return new(alloc) MGoto(nullptr);
 }
 
+#ifdef JS_JITSPEW
 void
 MUnbox::printOpcode(GenericPrinter& out) const
 {
     PrintOpcodeName(out, op());
     out.printf(" ");
     getOperand(0)->printName(out);
     out.printf(" ");
 
@@ -2295,16 +2322,17 @@ MUnbox::printOpcode(GenericPrinter& out)
 
     switch (mode()) {
       case Fallible: out.printf(" (fallible)"); break;
       case Infallible: out.printf(" (infallible)"); break;
       case TypeBarrier: out.printf(" (typebarrier)"); break;
       default: break;
     }
 }
+#endif
 
 MDefinition*
 MUnbox::foldsTo(TempAllocator &alloc)
 {
     if (!input()->isLoadFixedSlot())
         return this;
     MLoadFixedSlot* load = input()->toLoadFixedSlot();
     if (load->type() != MIRType::Value)
@@ -2320,23 +2348,25 @@ MUnbox::foldsTo(TempAllocator &alloc)
 
     MLoadFixedSlotAndUnbox* ins = MLoadFixedSlotAndUnbox::New(alloc, load->object(), load->slot(),
                                                               mode(), type(), bailoutKind());
     // As GVN runs after the Alias Analysis, we have to set the dependency by hand
     ins->setDependency(load->dependency());
     return ins;
 }
 
+#ifdef JS_JITSPEW
 void
 MTypeBarrier::printOpcode(GenericPrinter& out) const
 {
     PrintOpcodeName(out, op());
     out.printf(" ");
     getOperand(0)->printName(out);
 }
+#endif
 
 bool
 MTypeBarrier::congruentTo(const MDefinition* def) const
 {
     if (!def->isTypeBarrier())
         return false;
     const MTypeBarrier* other = def->toTypeBarrier();
     if (barrierKind() != other->barrierKind() || isGuard() != other->isGuard())
@@ -3154,16 +3184,17 @@ NeedNegativeZeroCheck(MDefinition* def)
             break;
           default:
             return true;
         }
     }
     return false;
 }
 
+#ifdef JS_JITSPEW
 void
 MBinaryArithInstruction::printOpcode(GenericPrinter& out) const
 {
     MDefinition::printOpcode(out);
 
     switch (type()) {
       case MIRType::Int32:
         if (isDiv())
@@ -3186,16 +3217,17 @@ MBinaryArithInstruction::printOpcode(Gen
         break;
       case MIRType::Double:
         out.printf(" [double]");
         break;
       default:
         break;
     }
 }
+#endif
 
 MBinaryArithInstruction*
 MBinaryArithInstruction::New(TempAllocator& alloc, Opcode op,
                              MDefinition* left, MDefinition* right)
 {
     switch (op) {
       case Opcode::Add:
         return MAdd::New(alloc, left, right);
@@ -4274,16 +4306,17 @@ MResumePoint::addStore(TempAllocator& al
 
     // Ensure that the store would not be deleted by DCE.
     MOZ_ASSERT(store->isEffectful());
 
     MStoreToRecover* top = new(alloc) MStoreToRecover(store);
     stores_.push(top);
 }
 
+#ifdef JS_JITSPEW
 void
 MResumePoint::dump(GenericPrinter& out) const
 {
     out.printf("resumepoint mode=");
 
     switch (mode()) {
       case MResumePoint::ResumeAt:
         if (instruction_)
@@ -4314,16 +4347,17 @@ MResumePoint::dump(GenericPrinter& out) 
 
 void
 MResumePoint::dump() const
 {
     Fprinter out(stderr);
     dump(out);
     out.finish();
 }
+#endif
 
 bool
 MResumePoint::isObservableOperand(MUse* u) const
 {
     return isObservableOperand(indexOf(u));
 }
 
 bool
@@ -5003,24 +5037,26 @@ MNot::foldsTo(TempAllocator& alloc)
 void
 MNot::trySpecializeFloat32(TempAllocator& alloc)
 {
     MDefinition* in = input();
     if (!in->canProduceFloat32() && in->type() == MIRType::Float32)
         ConvertDefinitionToDouble<0>(alloc, in, this);
 }
 
+#ifdef JS_JITSPEW
 void
 MBeta::printOpcode(GenericPrinter& out) const
 {
     MDefinition::printOpcode(out);
 
     out.printf(" ");
     comparison_->dump(out);
 }
+#endif
 
 bool
 MCreateThisWithTemplate::canRecoverOnBailout() const
 {
     MOZ_ASSERT(templateObject()->is<PlainObject>() || templateObject()->is<UnboxedPlainObject>());
     MOZ_ASSERT_IF(templateObject()->is<PlainObject>(),
                   !templateObject()->as<PlainObject>().denseElementsAreCopyOnWrite());
     return true;
@@ -5479,32 +5515,34 @@ MDefinition*
 MLoadSlot::foldsTo(TempAllocator& alloc)
 {
     if (MDefinition* def = foldsToStore(alloc))
         return def;
 
     return this;
 }
 
+#ifdef JS_JITSPEW
 void
 MLoadSlot::printOpcode(GenericPrinter& out) const
 {
     MDefinition::printOpcode(out);
     out.printf(" %d", slot());
 }
 
 void
 MStoreSlot::printOpcode(GenericPrinter& out) const
 {
     PrintOpcodeName(out, op());
     out.printf(" ");
     getOperand(0)->printName(out);
     out.printf(" %d ", slot());
     getOperand(1)->printName(out);
 }
+#endif
 
 MDefinition*
 MFunctionEnvironment::foldsTo(TempAllocator& alloc)
 {
     if (!input()->isLambda())
         return this;
 
     return input()->toLambda()->environmentChain();
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -372,18 +372,20 @@ class MNode : public TempObject
         return getUseFor(index)->hasProducer();
     }
 
     inline MDefinition* toDefinition();
     inline MResumePoint* toResumePoint();
 
     virtual MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const;
 
+#ifdef JS_JITSPEW
     virtual void dump(GenericPrinter& out) const = 0;
     virtual void dump() const = 0;
+#endif
 
   protected:
     // Need visibility on getUseFor to avoid O(n^2) complexity.
     friend void AssertBasicGraphCoherency(MIRGraph& graph, bool force);
 
     // Gets the MUse corresponding to given operand.
     virtual MUse* getUseFor(size_t index) = 0;
     virtual const MUse* getUseFor(size_t index) const = 0;
@@ -571,26 +573,26 @@ class MDefinition : public MNode
         resultType_(other.resultType_),
         resultTypeSet_(other.resultTypeSet_),
         loadDependency_(other.loadDependency_),
         trackedSite_(other.trackedSite_)
     { }
 
     Opcode op() const { return op_; }
 
-    virtual const char* opName() const = 0;
-    virtual void accept(MDefinitionVisitor* visitor) = 0;
-
+#ifdef JS_JITSPEW
+    const char* opName() const;
     void printName(GenericPrinter& out) const;
     static void PrintOpcodeName(GenericPrinter& out, Opcode op);
     virtual void printOpcode(GenericPrinter& out) const;
     void dump(GenericPrinter& out) const override;
     void dump() const override;
     void dumpLocation(GenericPrinter& out) const;
     void dumpLocation() const;
+#endif
 
     // For LICM.
     virtual bool neverHoist() const { return false; }
 
     // Also for LICM. Test whether this definition is likely to be a call, which
     // would clobber all or many of the floating-point registers, such that
     // hoisting floating-point constants out of containing loops isn't likely to
     // be worthwhile.
@@ -1203,23 +1205,17 @@ class MInstruction
     // Instructions needing to hook into type analysis should return a
     // TypePolicy.
     virtual TypePolicy* typePolicy() = 0;
     virtual MIRType typePolicySpecialization() = 0;
 };
 
 #define INSTRUCTION_HEADER_WITHOUT_TYPEPOLICY(opcode)                       \
     static const Opcode classOpcode = Opcode::opcode;                       \
-    using MThisOpcode = M##opcode;                                          \
-    const char* opName() const override {                                   \
-        return #opcode;                                                     \
-    }                                                                       \
-    void accept(MDefinitionVisitor* visitor) override {                     \
-        visitor->visit##opcode(this);                                       \
-    }
+    using MThisOpcode = M##opcode;
 
 #define INSTRUCTION_HEADER(opcode)                                          \
     INSTRUCTION_HEADER_WITHOUT_TYPEPOLICY(opcode)                           \
     virtual TypePolicy* typePolicy() override;                              \
     virtual MIRType typePolicySpecialization() override;
 
 #define ALLOW_CLONE(typename)                                               \
     bool canClone() const override {                                        \
@@ -1635,17 +1631,19 @@ class MConstant : public MNullaryInstruc
     // Like valueToBoolean, but returns the result directly instead of using
     // an outparam. Should not be used if this constant might be a magic value.
     bool valueToBooleanInfallible() const {
         bool res;
         MOZ_ALWAYS_TRUE(valueToBoolean(&res));
         return res;
     }
 
+#ifdef JS_JITSPEW
     void printOpcode(GenericPrinter& out) const override;
+#endif
 
     HashNumber valueHash() const override;
     bool congruentTo(const MDefinition* ins) const override;
 
     AliasSet getAliasSet() const override {
         return AliasSet::None();
     }
 
@@ -2090,17 +2088,19 @@ class MSimdInsertElement
     AliasSet getAliasSet() const override {
         return AliasSet::None();
     }
 
     bool congruentTo(const MDefinition* ins) const override {
         return binaryCongruentTo(ins) && lane_ == ins->toSimdInsertElement()->lane();
     }
 
+#ifdef JS_JITSPEW
     void printOpcode(GenericPrinter& out) const override;
+#endif
 
     ALLOW_CLONE(MSimdInsertElement)
 };
 
 // Returns true if all lanes are true.
 class MSimdAllTrue
   : public MUnaryInstruction,
     public SimdPolicy<0>::Data
@@ -2420,17 +2420,19 @@ class MSimdUnaryArith
     AliasSet getAliasSet() const override {
         return AliasSet::None();
     }
 
     bool congruentTo(const MDefinition* ins) const override {
         return congruentIfOperandsEqual(ins) && ins->toSimdUnaryArith()->operation() == operation();
     }
 
+#ifdef JS_JITSPEW
     void printOpcode(GenericPrinter& out) const override;
+#endif
 
     ALLOW_CLONE(MSimdUnaryArith);
 };
 
 // Compares each value of a SIMD vector to each corresponding lane's value of
 // another SIMD vector, and returns a boolean vector containing the results of
 // the comparison: all bits are set to 1 if the comparison is true, 0 otherwise.
 // When comparing integer vectors, a SimdSign must be provided to request signed
@@ -2517,17 +2519,19 @@ class MSimdBinaryComp
         if (!binaryCongruentTo(ins))
             return false;
         const MSimdBinaryComp* other = ins->toSimdBinaryComp();
         return specialization_ == other->specialization() &&
                operation_ == other->operation() &&
                sign_ == other->signedness();
     }
 
+#ifdef JS_JITSPEW
     void printOpcode(GenericPrinter& out) const override;
+#endif
 
     ALLOW_CLONE(MSimdBinaryComp)
 };
 
 class MSimdBinaryArith
   : public MBinaryInstruction,
     public MixPolicy<SimdSameAsReturnedTypePolicy<0>, SimdSameAsReturnedTypePolicy<1> >::Data
 {
@@ -2587,17 +2591,19 @@ class MSimdBinaryArith
     Operation operation() const { return operation_; }
 
     bool congruentTo(const MDefinition* ins) const override {
         if (!binaryCongruentTo(ins))
             return false;
         return operation_ == ins->toSimdBinaryArith()->operation();
     }
 
+#ifdef JS_JITSPEW
     void printOpcode(GenericPrinter& out) const override;
+#endif
 
     ALLOW_CLONE(MSimdBinaryArith)
 };
 
 class MSimdBinarySaturating
   : public MBinaryInstruction,
     public MixPolicy<SimdSameAsReturnedTypePolicy<0>, SimdSameAsReturnedTypePolicy<1>>::Data
 {
@@ -2649,17 +2655,19 @@ class MSimdBinarySaturating
     bool congruentTo(const MDefinition* ins) const override
     {
         if (!binaryCongruentTo(ins))
             return false;
         return operation_ == ins->toSimdBinarySaturating()->operation() &&
                sign_ == ins->toSimdBinarySaturating()->signedness();
     }
 
+#ifdef JS_JITSPEW
     void printOpcode(GenericPrinter& out) const override;
+#endif
 
     ALLOW_CLONE(MSimdBinarySaturating)
 };
 
 class MSimdBinaryBitwise
   : public MBinaryInstruction,
     public MixPolicy<SimdSameAsReturnedTypePolicy<0>, SimdSameAsReturnedTypePolicy<1> >::Data
 {
@@ -2704,17 +2712,19 @@ class MSimdBinaryBitwise
     Operation operation() const { return operation_; }
 
     bool congruentTo(const MDefinition* ins) const override {
         if (!binaryCongruentTo(ins))
             return false;
         return operation_ == ins->toSimdBinaryBitwise()->operation();
     }
 
+#ifdef JS_JITSPEW
     void printOpcode(GenericPrinter& out) const override;
+#endif
 
     ALLOW_CLONE(MSimdBinaryBitwise)
 };
 
 class MSimdShift
   : public MBinaryInstruction,
     public MixPolicy<SimdSameAsReturnedTypePolicy<0>, SimdScalarPolicy<1> >::Data
 {
@@ -2768,17 +2778,19 @@ class MSimdShift
         switch (op) {
           case lsh:  return "lsh";
           case rsh:  return "rsh-arithmetic";
           case ursh: return "rsh-logical";
         }
         MOZ_CRASH("unexpected operation");
     }
 
+#ifdef JS_JITSPEW
     void printOpcode(GenericPrinter& out) const override;
+#endif
 
     bool congruentTo(const MDefinition* ins) const override {
         if (!binaryCongruentTo(ins))
             return false;
         return operation_ == ins->toSimdShift()->operation();
     }
 
     ALLOW_CLONE(MSimdShift)
@@ -2848,18 +2860,19 @@ class MParameter : public MNullaryInstru
   public:
     INSTRUCTION_HEADER(Parameter)
     TRIVIAL_NEW_WRAPPERS
 
     static const int32_t THIS_SLOT = -1;
     int32_t index() const {
         return index_;
     }
+#ifdef JS_JITSPEW
     void printOpcode(GenericPrinter& out) const override;
-
+#endif
     HashNumber valueHash() const override;
     bool congruentTo(const MDefinition* ins) const override;
 };
 
 class MCallee : public MNullaryInstruction
 {
   public:
     MCallee()
@@ -2915,17 +2928,19 @@ class MControlInstruction : public MInst
     virtual size_t numSuccessors() const = 0;
     virtual MBasicBlock* getSuccessor(size_t i) const = 0;
     virtual void replaceSuccessor(size_t i, MBasicBlock* successor) = 0;
 
     bool isControlInstruction() const override {
         return true;
     }
 
+#ifdef JS_JITSPEW
     void printOpcode(GenericPrinter& out) const override;
+#endif
 };
 
 class MTableSwitch final
   : public MControlInstruction,
     public NoFloatPolicy<0>::Data
 {
     // The successors of the tableswitch
     // - First successor = the default case
@@ -3770,17 +3785,20 @@ class MSimdBox
             return false;
         return true;
     }
 
     AliasSet getAliasSet() const override {
         return AliasSet::None();
     }
 
+#ifdef JS_JITSPEW
     void printOpcode(GenericPrinter& out) const override;
+#endif
+
     MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
     bool canRecoverOnBailout() const override {
         return true;
     }
 
     bool appendRoots(MRootList& roots) const override {
         return roots.append(templateObject_);
     }
@@ -3817,17 +3835,19 @@ class MSimdUnbox
             return false;
         return ins->toSimdUnbox()->simdType() == simdType();
     }
 
     AliasSet getAliasSet() const override {
         return AliasSet::None();
     }
 
+#ifdef JS_JITSPEW
     void printOpcode(GenericPrinter& out) const override;
+#endif
 };
 
 // Creates a new derived type object. At runtime, this is just a call
 // to `BinaryBlock::createDerived()`. That is, the MIR itself does not
 // compile to particularly optimized code. However, using a distinct
 // MIR for creating derived type objects allows the compiler to
 // optimize ephemeral typed objects as would be created for a
 // reference like `a.b.c` -- here, the `a.b` will create an ephemeral
@@ -4786,17 +4806,19 @@ class MCompare
         if (jsop_ == JSOP_STRICTEQ || jsop_ == JSOP_STRICTNE)
             return AliasSet::None();
         if (compareType_ == Compare_Unknown)
             return AliasSet::Store(AliasSet::Any);
         MOZ_ASSERT(compareType_ <= Compare_Bitwise);
         return AliasSet::None();
     }
 
+#ifdef JS_JITSPEW
     void printOpcode(GenericPrinter& out) const override;
+#endif
     void collectRangeInfoPreTrunc() override;
 
     void trySpecializeFloat32(TempAllocator& alloc) override;
     bool isFloat32Commutative() const override { return true; }
     bool needTruncation(TruncateKind kind) override;
     void truncate() override;
     TruncateKind operandTruncateKind(size_t index) const override;
 
@@ -5000,17 +5022,19 @@ class MUnbox final : public MUnaryInstru
         return congruentIfOperandsEqual(ins);
     }
 
     MDefinition* foldsTo(TempAllocator& alloc) override;
 
     AliasSet getAliasSet() const override {
         return AliasSet::None();
     }
+#ifdef JS_JITSPEW
     void printOpcode(GenericPrinter& out) const override;
+#endif
     void makeInfallible() {
         // Should only be called if we're already Infallible or TypeBarrier
         MOZ_ASSERT(mode() != Fallible);
         mode_ = Infallible;
     }
 
     ALLOW_CLONE(MUnbox)
 };
@@ -5102,17 +5126,19 @@ class MAssertRange
     const Range* assertedRange() const {
         return assertedRange_;
     }
 
     AliasSet getAliasSet() const override {
         return AliasSet::None();
     }
 
+#ifdef JS_JITSPEW
     void printOpcode(GenericPrinter& out) const override;
+#endif
 };
 
 // Caller-side allocation of |this| for |new|:
 // Given a templateobject, construct |this| for JSOP_NEW
 class MCreateThisWithTemplate
   : public MUnaryInstruction,
     public NoTypePolicy::Data
 {
@@ -6462,17 +6488,19 @@ class MBinaryArithInstruction
                                         MDefinition* left, MDefinition* right);
 
     bool constantDoubleResult(TempAllocator& alloc);
 
     void setMustPreserveNaN(bool b) { mustPreserveNaN_ = b; }
     bool mustPreserveNaN() const { return mustPreserveNaN_; }
 
     MDefinition* foldsTo(TempAllocator& alloc) override;
+#ifdef JS_JITSPEW
     void printOpcode(GenericPrinter& out) const override;
+#endif
 
     virtual double getIdentity() = 0;
 
     void setSpecialization(MIRType type) {
         specialization_ = type;
         setResultType(type);
     }
     void setInt32Specialization() {
@@ -7062,17 +7090,19 @@ class MMathFunction
     }
 
     bool possiblyCalls() const override {
         return true;
     }
 
     MDefinition* foldsTo(TempAllocator& alloc) override;
 
+#ifdef JS_JITSPEW
     void printOpcode(GenericPrinter& out) const override;
+#endif
 
     static const char* FunctionName(Function function);
 
     bool isFloat32Commutative() const override {
         return function_ == Floor || function_ == Ceil || function_ == Round;
     }
     void trySpecializeFloat32(TempAllocator& alloc) override;
     void computeRange(TempAllocator& alloc) override;
@@ -8066,17 +8096,19 @@ class MBeta
         setResultType(val->type());
         setResultTypeSet(val->resultTypeSet());
     }
 
   public:
     INSTRUCTION_HEADER(Beta)
     TRIVIAL_NEW_WRAPPERS
 
+#ifdef JS_JITSPEW
     void printOpcode(GenericPrinter& out) const override;
+#endif
 
     AliasSet getAliasSet() const override {
         return AliasSet::None();
     }
 
     void computeRange(TempAllocator& alloc) override;
 };
 
@@ -9026,17 +9058,19 @@ class MConstantElements : public MNullar
   public:
     INSTRUCTION_HEADER(ConstantElements)
     TRIVIAL_NEW_WRAPPERS
 
     SharedMem<void*> value() const {
         return value_;
     }
 
+#ifdef JS_JITSPEW
     void printOpcode(GenericPrinter& out) const override;
+#endif
 
     HashNumber valueHash() const override {
         return (HashNumber)(size_t) value_.asValue();
     }
 
     bool congruentTo(const MDefinition* ins) const override {
         return ins->isConstantElements() && ins->toConstantElements()->value() == value();
     }
@@ -10442,17 +10476,19 @@ class MLoadUnboxedScalar
             return false;
         if (offsetAdjustment() != other->offsetAdjustment())
             return false;
         if (canonicalizeDoubles() != other->canonicalizeDoubles())
             return false;
         return congruentIfOperandsEqual(other);
     }
 
+#ifdef JS_JITSPEW
     void printOpcode(GenericPrinter& out) const override;
+#endif
 
     void computeRange(TempAllocator& alloc) override;
 
     bool canProduceFloat32() const override { return storageType_ == Scalar::Float32; }
 
     ALLOW_CLONE(MLoadUnboxedScalar)
 };
 
@@ -11866,17 +11902,19 @@ class MLoadSlot
     MDefinition* foldsTo(TempAllocator& alloc) override;
 
     AliasSet getAliasSet() const override {
         MOZ_ASSERT(slots()->type() == MIRType::Slots);
         return AliasSet::Load(AliasSet::DynamicSlot);
     }
     AliasType mightAlias(const MDefinition* store) const override;
 
+#ifdef JS_JITSPEW
     void printOpcode(GenericPrinter& out) const override;
+#endif
 
     ALLOW_CLONE(MLoadSlot)
 };
 
 // Inline call to access a function's environment (scope chain).
 class MFunctionEnvironment
   : public MUnaryInstruction,
     public SingleObjectPolicy::Data
@@ -12035,17 +12073,20 @@ class MStoreSlot
         return needsBarrier_;
     }
     void setNeedsBarrier() {
         needsBarrier_ = true;
     }
     AliasSet getAliasSet() const override {
         return AliasSet::Store(AliasSet::DynamicSlot);
     }
+
+#ifdef JS_JITSPEW
     void printOpcode(GenericPrinter& out) const override;
+#endif
 
     ALLOW_CLONE(MStoreSlot)
 };
 
 class MGetNameCache
   : public MUnaryInstruction,
     public SingleObjectPolicy::Data
 {
@@ -12761,17 +12802,19 @@ class MNearbyInt
     }
 #endif
 
     bool congruentTo(const MDefinition* ins) const override {
         return congruentIfOperandsEqual(ins) &&
                ins->toNearbyInt()->roundingMode() == roundingMode_;
     }
 
+#ifdef JS_JITSPEW
     void printOpcode(GenericPrinter& out) const override;
+#endif
 
     MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
 
     bool canRecoverOnBailout() const override {
         switch (roundingMode_) {
           case RoundingMode::Up:
           case RoundingMode::Down:
             return true;
@@ -13197,17 +13240,20 @@ class MTypeBarrier
         setGuard();
         setMovable();
     }
 
   public:
     INSTRUCTION_HEADER(TypeBarrier)
     TRIVIAL_NEW_WRAPPERS
 
+#ifdef JS_JITSPEW
     void printOpcode(GenericPrinter& out) const override;
+#endif
+
     bool congruentTo(const MDefinition* def) const override;
 
     AliasSet getAliasSet() const override {
         return AliasSet::None();
     }
     virtual bool neverHoist() const override {
         return resultTypeSet()->empty();
     }
@@ -13578,18 +13624,20 @@ class MResumePoint final :
 
     MStoresToRecoverList::iterator storesBegin() const {
         return stores_.begin();
     }
     MStoresToRecoverList::iterator storesEnd() const {
         return stores_.end();
     }
 
+#ifdef JS_JITSPEW
     virtual void dump(GenericPrinter& out) const override;
     virtual void dump() const override;
+#endif
 };
 
 class MIsCallable
   : public MUnaryInstruction,
     public BoxExceptPolicy<0, MIRType::Object>::Data
 {
     explicit MIsCallable(MDefinition* object)
       : MUnaryInstruction(classOpcode, object)
--- a/js/src/jit/MOpcodes.h
+++ b/js/src/jit/MOpcodes.h
@@ -333,39 +333,21 @@ namespace jit {
     _(WasmFloatConstant)                                                    \
     _(WasmTruncateToInt64)
 
 // Forward declarations of MIR types.
 #define FORWARD_DECLARE(op) class M##op;
  MIR_OPCODE_LIST(FORWARD_DECLARE)
 #undef FORWARD_DECLARE
 
-class MDefinitionVisitor // interface i.e. pure abstract class
+// MDefinition visitor which ignores non-overloaded visit functions.
+class MDefinitionVisitorDefaultNoop
 {
   public:
-#define VISIT_INS(op) virtual void visit##op(M##op*) = 0;
-    MIR_OPCODE_LIST(VISIT_INS)
-#undef VISIT_INS
-};
-
-// MDefinition visitor which raises a Not Yet Implemented error for
-// non-overloaded visit functions.
-class MDefinitionVisitorDefaultNYI : public MDefinitionVisitor
-{
-  public:
-#define VISIT_INS(op) virtual void visit##op(M##op*) override { MOZ_CRASH("NYI: " #op); }
-    MIR_OPCODE_LIST(VISIT_INS)
-#undef VISIT_INS
-};
-
-// MDefinition visitor which ignores non-overloaded visit functions.
-class MDefinitionVisitorDefaultNoop : public MDefinitionVisitor
-{
-  public:
-#define VISIT_INS(op) virtual void visit##op(M##op*) override { }
+#define VISIT_INS(op) void visit##op(M##op*) { }
     MIR_OPCODE_LIST(VISIT_INS)
 #undef VISIT_INS
 };
 
 } // namespace jit
 } // namespace js
 
 #endif /* jit_MOpcodes_h */
--- a/js/src/jit/MacroAssembler.h
+++ b/js/src/jit/MacroAssembler.h
@@ -548,23 +548,16 @@ class MacroAssembler : public MacroAssem
     // ===============================================================
     // Patchable near/far jumps.
 
     // "Far jumps" provide the ability to jump to any uint32_t offset from any
     // other uint32_t offset without using a constant pool (thus returning a
     // simple CodeOffset instead of a CodeOffsetJump).
     CodeOffset farJumpWithPatch() PER_SHARED_ARCH;
     void patchFarJump(CodeOffset farJump, uint32_t targetOffset) PER_SHARED_ARCH;
-    static void repatchFarJump(uint8_t* code, uint32_t farJumpOffset, uint32_t targetOffset) PER_SHARED_ARCH;
-
-    // Emit a nop that can be patched to and from a nop and a jump with an int8
-    // relative displacement.
-    CodeOffset nopPatchableToNearJump() PER_SHARED_ARCH;
-    static void patchNopToNearJump(uint8_t* jump, uint8_t* target) PER_SHARED_ARCH;
-    static void patchNearJumpToNop(uint8_t* jump) PER_SHARED_ARCH;
 
     // Emit a nop that can be patched to and from a nop and a call with int32
     // relative displacement.
     CodeOffset nopPatchableToCall(const wasm::CallSiteDesc& desc) PER_SHARED_ARCH;
     static void patchNopToCall(uint8_t* callsite, uint8_t* target) PER_SHARED_ARCH;
     static void patchCallToNop(uint8_t* callsite) PER_SHARED_ARCH;
 
   public:
--- a/js/src/jit/ScalarReplacement.cpp
+++ b/js/src/jit/ScalarReplacement.cpp
@@ -69,20 +69,26 @@ EmulateStateOf<MemoryView>::run(MemoryVi
             continue;
         view.setEntryBlockState(state);
 
         // Iterates over resume points, phi and instructions.
         for (MNodeIterator iter(*block); iter; ) {
             // Increment the iterator before visiting the instruction, as the
             // visit function might discard itself from the basic block.
             MNode* ins = *iter++;
-            if (ins->isDefinition())
-                ins->toDefinition()->accept(&view);
-            else
+            if (ins->isDefinition()) {
+                MDefinition* def = ins->toDefinition();
+                switch (def->op()) {
+#define MIR_OP(op) case MDefinition::Opcode::op: view.visit##op(def->to##op()); break;
+    MIR_OPCODE_LIST(MIR_OP)
+#undef MIR_OP
+                }
+            } else {
                 view.visitResumePoint(ins->toResumePoint());
+            }
             if (view.oom())
                 return false;
         }
 
         // For each successor, merge the current state into the state of the
         // successors.
         for (size_t s = 0; s < block->numSuccessors(); s++) {
             MBasicBlock* succ = block->getSuccessor(s);
@@ -334,34 +340,34 @@ class ObjectMemoryView : public MDefinit
 #else
     void assertSuccess() {}
 #endif
 
     bool oom() const { return oom_; }
 
   public:
     void visitResumePoint(MResumePoint* rp);
-    void visitObjectState(MObjectState* ins) override;
-    void visitStoreFixedSlot(MStoreFixedSlot* ins) override;
-    void visitLoadFixedSlot(MLoadFixedSlot* ins) override;
-    void visitPostWriteBarrier(MPostWriteBarrier* ins) override;
-    void visitStoreSlot(MStoreSlot* ins) override;
-    void visitLoadSlot(MLoadSlot* ins) override;
-    void visitGuardShape(MGuardShape* ins) override;
-    void visitGuardObjectGroup(MGuardObjectGroup* ins) override;
-    void visitGuardUnboxedExpando(MGuardUnboxedExpando* ins) override;
-    void visitFunctionEnvironment(MFunctionEnvironment* ins) override;
-    void visitLambda(MLambda* ins) override;
-    void visitLambdaArrow(MLambdaArrow* ins) override;
-    void visitStoreUnboxedScalar(MStoreUnboxedScalar* ins) override;
-    void visitLoadUnboxedScalar(MLoadUnboxedScalar* ins) override;
-    void visitStoreUnboxedObjectOrNull(MStoreUnboxedObjectOrNull* ins) override;
-    void visitLoadUnboxedObjectOrNull(MLoadUnboxedObjectOrNull* ins) override;
-    void visitStoreUnboxedString(MStoreUnboxedString* ins) override;
-    void visitLoadUnboxedString(MLoadUnboxedString* ins) override;
+    void visitObjectState(MObjectState* ins);
+    void visitStoreFixedSlot(MStoreFixedSlot* ins);
+    void visitLoadFixedSlot(MLoadFixedSlot* ins);
+    void visitPostWriteBarrier(MPostWriteBarrier* ins);
+    void visitStoreSlot(MStoreSlot* ins);
+    void visitLoadSlot(MLoadSlot* ins);
+    void visitGuardShape(MGuardShape* ins);
+    void visitGuardObjectGroup(MGuardObjectGroup* ins);
+    void visitGuardUnboxedExpando(MGuardUnboxedExpando* ins);
+    void visitFunctionEnvironment(MFunctionEnvironment* ins);
+    void visitLambda(MLambda* ins);
+    void visitLambdaArrow(MLambdaArrow* ins);
+    void visitStoreUnboxedScalar(MStoreUnboxedScalar* ins);
+    void visitLoadUnboxedScalar(MLoadUnboxedScalar* ins);
+    void visitStoreUnboxedObjectOrNull(MStoreUnboxedObjectOrNull* ins);
+    void visitLoadUnboxedObjectOrNull(MLoadUnboxedObjectOrNull* ins);
+    void visitStoreUnboxedString(MStoreUnboxedString* ins);
+    void visitLoadUnboxedString(MLoadUnboxedString* ins);
 
   private:
     void storeOffset(MInstruction* ins, size_t offset, MDefinition* value);
     void loadOffset(MInstruction* ins, size_t offset);
     void visitObjectGuard(MInstruction* ins, MDefinition* operand);
 };
 
 const char* ObjectMemoryView::phaseName = "Scalar Replacement of Object";
@@ -1117,24 +1123,24 @@ class ArrayMemoryView : public MDefiniti
     bool oom() const { return oom_; }
 
   private:
     bool isArrayStateElements(MDefinition* elements);
     void discardInstruction(MInstruction* ins, MDefinition* elements);
 
   public:
     void visitResumePoint(MResumePoint* rp);
-    void visitArrayState(MArrayState* ins) override;
-    void visitStoreElement(MStoreElement* ins) override;
-    void visitLoadElement(MLoadElement* ins) override;
-    void visitSetInitializedLength(MSetInitializedLength* ins) override;
-    void visitInitializedLength(MInitializedLength* ins) override;
-    void visitArrayLength(MArrayLength* ins) override;
-    void visitMaybeCopyElementsForWrite(MMaybeCopyElementsForWrite* ins) override;
-    void visitConvertElementsToDoubles(MConvertElementsToDoubles* ins) override;
+    void visitArrayState(MArrayState* ins);
+    void visitStoreElement(MStoreElement* ins);
+    void visitLoadElement(MLoadElement* ins);
+    void visitSetInitializedLength(MSetInitializedLength* ins);
+    void visitInitializedLength(MInitializedLength* ins);
+    void visitArrayLength(MArrayLength* ins);
+    void visitMaybeCopyElementsForWrite(MMaybeCopyElementsForWrite* ins);
+    void visitConvertElementsToDoubles(MConvertElementsToDoubles* ins);
 };
 
 const char* ArrayMemoryView::phaseName = "Scalar Replacement of Array";
 
 ArrayMemoryView::ArrayMemoryView(TempAllocator& alloc, MInstruction* arr)
   : alloc_(alloc),
     undefinedVal_(nullptr),
     length_(nullptr),
--- a/js/src/jit/arm/Assembler-arm.h
+++ b/js/src/jit/arm/Assembler-arm.h
@@ -173,30 +173,16 @@ struct ScratchFloat32Scope : public Auto
 };
 struct ScratchDoubleScope : public AutoFloatRegisterScope
 {
     explicit ScratchDoubleScope(MacroAssembler& masm)
       : AutoFloatRegisterScope(masm, ScratchDoubleReg)
     { }
 };
 
-// Registers used in the GenerateFFIIonExit Enable Activation block.
-static constexpr Register WasmIonExitRegCallee = r4;
-static constexpr Register WasmIonExitRegE0 = r0;
-static constexpr Register WasmIonExitRegE1 = r1;
-
-// Registers used in the GenerateFFIIonExit Disable Activation block.
-// None of these may be the second scratch register (lr).
-static constexpr Register WasmIonExitRegReturnData = r2;
-static constexpr Register WasmIonExitRegReturnType = r3;
-static constexpr Register WasmIonExitTlsReg = r9;
-static constexpr Register WasmIonExitRegD0 = r0;
-static constexpr Register WasmIonExitRegD1 = r1;
-static constexpr Register WasmIonExitRegD2 = r4;
-
 // Registerd used in RegExpMatcher instruction (do not use JSReturnOperand).
 static constexpr Register RegExpMatcherRegExpReg = CallTempReg0;
 static constexpr Register RegExpMatcherStringReg = CallTempReg1;
 static constexpr Register RegExpMatcherLastIndexReg = CallTempReg2;
 
 // Registerd used in RegExpTester instruction (do not use ReturnReg).
 static constexpr Register RegExpTesterRegExpReg = CallTempReg0;
 static constexpr Register RegExpTesterStringReg = CallTempReg1;
--- a/js/src/jit/arm/Lowering-arm.h
+++ b/js/src/jit/arm/Lowering-arm.h
@@ -83,49 +83,49 @@ class LIRGeneratorARM : public LIRGenera
     void lowerModI(MMod* mod);
     void lowerDivI64(MDiv* div);
     void lowerModI64(MMod* mod);
     void lowerUDivI64(MDiv* div);
     void lowerUModI64(MMod* mod);
     void lowerMulI(MMul* mul, MDefinition* lhs, MDefinition* rhs);
     void lowerUDiv(MDiv* div);
     void lowerUMod(MMod* mod);
-    void visitPowHalf(MPowHalf* ins) override;
-    void visitWasmNeg(MWasmNeg* ins) override;
+    void visitPowHalf(MPowHalf* ins);
+    void visitWasmNeg(MWasmNeg* ins);
 
     LTableSwitch* newLTableSwitch(const LAllocation& in, const LDefinition& inputCopy,
                                   MTableSwitch* ins);
     LTableSwitchV* newLTableSwitchV(MTableSwitch* ins);
 
   public:
-    void visitBox(MBox* box) override;
-    void visitUnbox(MUnbox* unbox) override;
-    void visitReturn(MReturn* ret) override;
+    void visitBox(MBox* box);
+    void visitUnbox(MUnbox* unbox);
+    void visitReturn(MReturn* ret);
     void lowerPhi(MPhi* phi);
-    void visitWasmSelect(MWasmSelect* ins) override;
-    void visitWasmUnsignedToDouble(MWasmUnsignedToDouble* ins) override;
-    void visitWasmUnsignedToFloat32(MWasmUnsignedToFloat32* ins) override;
-    void visitWasmLoad(MWasmLoad* ins) override;
-    void visitWasmStore(MWasmStore* ins) override;
-    void visitAsmJSLoadHeap(MAsmJSLoadHeap* ins) override;
-    void visitAsmJSStoreHeap(MAsmJSStoreHeap* ins) override;
-    void visitWasmCompareExchangeHeap(MWasmCompareExchangeHeap* ins) override;
-    void visitWasmAtomicExchangeHeap(MWasmAtomicExchangeHeap* ins) override;
-    void visitWasmAtomicBinopHeap(MWasmAtomicBinopHeap* ins) override;
-    void visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic* ins) override;
-    void visitCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement* ins) override;
-    void visitAtomicExchangeTypedArrayElement(MAtomicExchangeTypedArrayElement* ins) override;
-    void visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop* ins) override;
-    void visitSubstr(MSubstr* ins) override;
-    void visitRandom(MRandom* ins) override;
-    void visitWasmTruncateToInt64(MWasmTruncateToInt64* ins) override;
-    void visitInt64ToFloatingPoint(MInt64ToFloatingPoint* ins) override;
-    void visitCopySign(MCopySign* ins) override;
-    void visitExtendInt32ToInt64(MExtendInt32ToInt64* ins) override;
-    void visitSignExtendInt64(MSignExtendInt64* ins) override;
+    void visitWasmSelect(MWasmSelect* ins);
+    void visitWasmUnsignedToDouble(MWasmUnsignedToDouble* ins);
+    void visitWasmUnsignedToFloat32(MWasmUnsignedToFloat32* ins);
+    void visitWasmLoad(MWasmLoad* ins);
+    void visitWasmStore(MWasmStore* ins);
+    void visitAsmJSLoadHeap(MAsmJSLoadHeap* ins);
+    void visitAsmJSStoreHeap(MAsmJSStoreHeap* ins);
+    void visitWasmCompareExchangeHeap(MWasmCompareExchangeHeap* ins);
+    void visitWasmAtomicExchangeHeap(MWasmAtomicExchangeHeap* ins);
+    void visitWasmAtomicBinopHeap(MWasmAtomicBinopHeap* ins);
+    void visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic* ins);
+    void visitCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement* ins);
+    void visitAtomicExchangeTypedArrayElement(MAtomicExchangeTypedArrayElement* ins);
+    void visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop* ins);
+    void visitSubstr(MSubstr* ins);
+    void visitRandom(MRandom* ins);
+    void visitWasmTruncateToInt64(MWasmTruncateToInt64* ins);
+    void visitInt64ToFloatingPoint(MInt64ToFloatingPoint* ins);
+    void visitCopySign(MCopySign* ins);
+    void visitExtendInt32ToInt64(MExtendInt32ToInt64* ins);
+    void visitSignExtendInt64(MSignExtendInt64* ins);
 };
 
 typedef LIRGeneratorARM LIRGeneratorSpecific;
 
 } // namespace jit
 } // namespace js
 
 #endif /* jit_arm_Lowering_arm_h */
--- a/js/src/jit/arm/MacroAssembler-arm.cpp
+++ b/js/src/jit/arm/MacroAssembler-arm.cpp
@@ -4477,52 +4477,16 @@ MacroAssembler::patchFarJump(CodeOffset 
     uint32_t addOffset = farJump.offset() - 4;
     MOZ_ASSERT(editSrc(BufferOffset(addOffset))->is<InstALU>());
 
     // When pc is read as the operand of the add, its value is the address of
     // the add instruction + 8.
     *u32 = (targetOffset - addOffset) - 8;
 }
 
-void
-MacroAssembler::repatchFarJump(uint8_t* code, uint32_t farJumpOffset, uint32_t targetOffset)
-{
-    uint32_t* u32 = reinterpret_cast<uint32_t*>(code + farJumpOffset);
-
-    uint32_t addOffset = farJumpOffset - 4;
-    MOZ_ASSERT(reinterpret_cast<Instruction*>(code + addOffset)->is<InstALU>());
-
-    *u32 = (targetOffset - addOffset) - 8;
-}
-
-CodeOffset
-MacroAssembler::nopPatchableToNearJump()
-{
-    // Inhibit pools so that the offset points precisely to the nop.
-    AutoForbidPools afp(this, 1);
-
-    CodeOffset offset(currentOffset());
-    ma_nop();
-    return offset;
-}
-
-void
-MacroAssembler::patchNopToNearJump(uint8_t* jump, uint8_t* target)
-{
-    MOZ_ASSERT(reinterpret_cast<Instruction*>(jump)->is<InstNOP>());
-    new (jump) InstBImm(BOffImm(target - jump), Assembler::Always);
-}
-
-void
-MacroAssembler::patchNearJumpToNop(uint8_t* jump)
-{
-    MOZ_ASSERT(reinterpret_cast<Instruction*>(jump)->is<InstBImm>());
-    new (jump) InstNOP();
-}
-
 CodeOffset
 MacroAssembler::nopPatchableToCall(const wasm::CallSiteDesc& desc)
 {
     CodeOffset offset(currentOffset());
     ma_nop();
     append(desc, CodeOffset(currentOffset()));
     return offset;
 }
--- a/js/src/jit/arm64/Assembler-arm64.h
+++ b/js/src/jit/arm64/Assembler-arm64.h
@@ -114,30 +114,16 @@ static constexpr ARMRegister sp = vixl::
 #define IMPORT_VIXL_VREGISTERS(N)  \
 static constexpr ARMFPRegister s##N = vixl::s##N;  \
 static constexpr ARMFPRegister d##N = vixl::d##N;
 REGISTER_CODE_LIST(IMPORT_VIXL_VREGISTERS)
 #undef IMPORT_VIXL_VREGISTERS
 
 static constexpr ValueOperand JSReturnOperand = ValueOperand(JSReturnReg);
 
-// Registers used in the GenerateFFIIonExit Enable Activation block.
-static constexpr Register WasmIonExitRegCallee = r8;
-static constexpr Register WasmIonExitRegE0 = r0;
-static constexpr Register WasmIonExitRegE1 = r1;
-
-// Registers used in the GenerateFFIIonExit Disable Activation block.
-// None of these may be the second scratch register.
-static constexpr Register WasmIonExitRegReturnData = r2;
-static constexpr Register WasmIonExitRegReturnType = r3;
-static constexpr Register WasmIonExitTlsReg = r17;
-static constexpr Register WasmIonExitRegD0 = r0;
-static constexpr Register WasmIonExitRegD1 = r1;
-static constexpr Register WasmIonExitRegD2 = r4;
-
 // Registerd used in RegExpMatcher instruction (do not use JSReturnOperand).
 static constexpr Register RegExpMatcherRegExpReg = CallTempReg0;
 static constexpr Register RegExpMatcherStringReg = CallTempReg1;
 static constexpr Register RegExpMatcherLastIndexReg = CallTempReg2;
 
 // Registerd used in RegExpTester instruction (do not use ReturnReg).
 static constexpr Register RegExpTesterRegExpReg = CallTempReg0;
 static constexpr Register RegExpTesterStringReg = CallTempReg1;
--- a/js/src/jit/arm64/Lowering-arm64.h
+++ b/js/src/jit/arm64/Lowering-arm64.h
@@ -82,50 +82,50 @@ class LIRGeneratorARM64 : public LIRGene
     void lowerTruncateFToInt32(MTruncateToInt32* ins);
     void lowerDivI(MDiv* div);
     void lowerModI(MMod* mod);
     void lowerDivI64(MDiv* div);
     void lowerModI64(MMod* mod);
     void lowerMulI(MMul* mul, MDefinition* lhs, MDefinition* rhs);
     void lowerUDiv(MDiv* div);
     void lowerUMod(MMod* mod);
-    void visitPowHalf(MPowHalf* ins) override;
-    void visitWasmNeg(MWasmNeg* ins) override;
-    void visitWasmSelect(MWasmSelect* ins) override;
+    void visitPowHalf(MPowHalf* ins);
+    void visitWasmNeg(MWasmNeg* ins);
+    void visitWasmSelect(MWasmSelect* ins);
 
     LTableSwitchV* newLTableSwitchV(MTableSwitch* ins);
     LTableSwitch* newLTableSwitch(const LAllocation& in,
                                   const LDefinition& inputCopy,
                                   MTableSwitch* ins);
 
   public:
-    void visitBox(MBox* box) override;
-    void visitUnbox(MUnbox* unbox) override;
-    void visitReturn(MReturn* ret) override;
+    void visitBox(MBox* box);
+    void visitUnbox(MUnbox* unbox);
+    void visitReturn(MReturn* ret);
     void lowerPhi(MPhi* phi);
-    void visitWasmUnsignedToDouble(MWasmUnsignedToDouble* ins) override;
-    void visitWasmUnsignedToFloat32(MWasmUnsignedToFloat32* ins) override;
-    void visitAsmJSLoadHeap(MAsmJSLoadHeap* ins) override;
-    void visitAsmJSStoreHeap(MAsmJSStoreHeap* ins) override;
-    void visitWasmCompareExchangeHeap(MWasmCompareExchangeHeap* ins) override;
-    void visitWasmAtomicExchangeHeap(MWasmAtomicExchangeHeap* ins) override;
-    void visitWasmAtomicBinopHeap(MWasmAtomicBinopHeap* ins) override;
-    void visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic* ins) override;
-    void visitCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement* ins) override;
-    void visitAtomicExchangeTypedArrayElement(MAtomicExchangeTypedArrayElement* ins) override;
-    void visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop* ins) override;
-    void visitSubstr(MSubstr* ins) override;
-    void visitRandom(MRandom* ins) override;
-    void visitWasmTruncateToInt64(MWasmTruncateToInt64* ins) override;
-    void visitWasmLoad(MWasmLoad* ins) override;
-    void visitWasmStore(MWasmStore* ins) override;
-    void visitInt64ToFloatingPoint(MInt64ToFloatingPoint* ins) override;
-    void visitCopySign(MCopySign* ins) override;
-    void visitExtendInt32ToInt64(MExtendInt32ToInt64* ins) override;
-    void visitSignExtendInt64(MSignExtendInt64* ins) override;
+    void visitWasmUnsignedToDouble(MWasmUnsignedToDouble* ins);
+    void visitWasmUnsignedToFloat32(MWasmUnsignedToFloat32* ins);
+    void visitAsmJSLoadHeap(MAsmJSLoadHeap* ins);
+    void visitAsmJSStoreHeap(MAsmJSStoreHeap* ins);
+    void visitWasmCompareExchangeHeap(MWasmCompareExchangeHeap* ins);
+    void visitWasmAtomicExchangeHeap(MWasmAtomicExchangeHeap* ins);
+    void visitWasmAtomicBinopHeap(MWasmAtomicBinopHeap* ins);
+    void visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic* ins);
+    void visitCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement* ins);
+    void visitAtomicExchangeTypedArrayElement(MAtomicExchangeTypedArrayElement* ins);
+    void visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop* ins);
+    void visitSubstr(MSubstr* ins);
+    void visitRandom(MRandom* ins);
+    void visitWasmTruncateToInt64(MWasmTruncateToInt64* ins);
+    void visitWasmLoad(MWasmLoad* ins);
+    void visitWasmStore(MWasmStore* ins);
+    void visitInt64ToFloatingPoint(MInt64ToFloatingPoint* ins);
+    void visitCopySign(MCopySign* ins);
+    void visitExtendInt32ToInt64(MExtendInt32ToInt64* ins);
+    void visitSignExtendInt64(MSignExtendInt64* ins);
 };
 
 typedef LIRGeneratorARM64 LIRGeneratorSpecific;
 
 } // namespace jit
 } // namespace js
 
 #endif /* jit_arm64_Lowering_arm64_h */
--- a/js/src/jit/arm64/MacroAssembler-arm64.cpp
+++ b/js/src/jit/arm64/MacroAssembler-arm64.cpp
@@ -699,40 +699,16 @@ MacroAssembler::patchFarJump(CodeOffset 
 
     MOZ_ASSERT(inst1->InstructionBits() == UINT32_MAX);
     MOZ_ASSERT(inst2->InstructionBits() == UINT32_MAX);
 
     inst1->SetInstructionBits((uint32_t)distance);
     inst2->SetInstructionBits((uint32_t)(distance >> 32));
 }
 
-void
-MacroAssembler::repatchFarJump(uint8_t* code, uint32_t farJumpOffset, uint32_t targetOffset)
-{
-    MOZ_CRASH("Unimplemented - never used");
-}
-
-CodeOffset
-MacroAssembler::nopPatchableToNearJump()
-{
-    MOZ_CRASH("Unimplemented - never used");
-}
-
-void
-MacroAssembler::patchNopToNearJump(uint8_t* jump, uint8_t* target)
-{
-    MOZ_CRASH("Unimplemented - never used");
-}
-
-void
-MacroAssembler::patchNearJumpToNop(uint8_t* jump)
-{
-    MOZ_CRASH("Unimplemented - never used");
-}
-
 CodeOffset
 MacroAssembler::nopPatchableToCall(const wasm::CallSiteDesc& desc)
 {
     CodeOffset offset(currentOffset());
     Nop();
     append(desc, CodeOffset(currentOffset()));
     return offset;
 }
--- a/js/src/jit/mips-shared/Assembler-mips-shared.h
+++ b/js/src/jit/mips-shared/Assembler-mips-shared.h
@@ -107,27 +107,16 @@ static constexpr Register ReturnReg = v0
 static constexpr FloatRegister ReturnSimd128Reg = InvalidFloatReg;
 static constexpr FloatRegister ScratchSimd128Reg = InvalidFloatReg;
 
 // A bias applied to the GlobalReg to allow the use of instructions with small
 // negative immediate offsets which doubles the range of global data that can be
 // accessed with a single instruction.
 static const int32_t WasmGlobalRegBias = 32768;
 
-// Registers used in the GenerateFFIIonExit Enable Activation block.
-static constexpr Register WasmIonExitRegCallee = t0;
-static constexpr Register WasmIonExitRegE0 = a0;
-static constexpr Register WasmIonExitRegE1 = a1;
-
-// Registers used in the GenerateFFIIonExit Disable Activation block.
-// None of these may be the second scratch register (t8).
-static constexpr Register WasmIonExitRegD0 = a0;
-static constexpr Register WasmIonExitRegD1 = a1;
-static constexpr Register WasmIonExitRegD2 = t0;
-
 // Registerd used in RegExpMatcher instruction (do not use JSReturnOperand).
 static constexpr Register RegExpMatcherRegExpReg = CallTempReg0;
 static constexpr Register RegExpMatcherStringReg = CallTempReg1;
 static constexpr Register RegExpMatcherLastIndexReg = CallTempReg2;
 
 // Registerd used in RegExpTester instruction (do not use ReturnReg).
 static constexpr Register RegExpTesterRegExpReg = CallTempReg0;
 static constexpr Register RegExpTesterStringReg = CallTempReg1;
--- a/js/src/jit/mips-shared/MacroAssembler-mips-shared.cpp
+++ b/js/src/jit/mips-shared/MacroAssembler-mips-shared.cpp
@@ -1625,44 +1625,16 @@ void
 MacroAssembler::patchFarJump(CodeOffset farJump, uint32_t targetOffset)
 {
     uint32_t* u32 = reinterpret_cast<uint32_t*>(editSrc(BufferOffset(farJump.offset())));
     MOZ_ASSERT(*u32 == UINT32_MAX);
     *u32 = targetOffset - farJump.offset();
 }
 
 void
-MacroAssembler::repatchFarJump(uint8_t* code, uint32_t farJumpOffset, uint32_t targetOffset)
-{
-    uint32_t* u32 = reinterpret_cast<uint32_t*>(code + farJumpOffset);
-    *u32 = targetOffset - farJumpOffset;
-}
-
-CodeOffset
-MacroAssembler::nopPatchableToNearJump()
-{
-    CodeOffset offset(currentOffset());
-    as_nop();
-    as_nop();
-    return offset;
-}
-
-void
-MacroAssembler::patchNopToNearJump(uint8_t* jump, uint8_t* target)
-{
-    new (jump) InstImm(op_beq, zero, zero, BOffImm16(target - jump));
-}
-
-void
-MacroAssembler::patchNearJumpToNop(uint8_t* jump)
-{
-    new (jump) InstNOP();
-}
-
-void
 MacroAssembler::call(wasm::SymbolicAddress target)
 {
     movePtr(target, CallReg);
     call(CallReg);
 }
 
 void
 MacroAssembler::call(const Address& addr)
--- a/js/src/jit/mips32/Assembler-mips32.h
+++ b/js/src/jit/mips32/Assembler-mips32.h
@@ -93,22 +93,16 @@ struct ScratchFloat32Scope : public Auto
 
 struct ScratchDoubleScope : public AutoFloatRegisterScope
 {
     explicit ScratchDoubleScope(MacroAssembler& masm)
       : AutoFloatRegisterScope(masm, ScratchDoubleReg)
     { }
 };
 
-// Registers used in the GenerateFFIIonExit Disable Activation block.
-// None of these may be the second scratch register (t8).
-static constexpr Register WasmIonExitRegReturnData = JSReturnReg_Data;
-static constexpr Register WasmIonExitRegReturnType = JSReturnReg_Type;
-static constexpr Register WasmIonExitTlsReg = s5;
-
 static constexpr FloatRegister f0  = { FloatRegisters::f0, FloatRegister::Double };
 static constexpr FloatRegister f2  = { FloatRegisters::f2, FloatRegister::Double };
 static constexpr FloatRegister f4  = { FloatRegisters::f4, FloatRegister::Double };
 static constexpr FloatRegister f6  = { FloatRegisters::f6, FloatRegister::Double };
 static constexpr FloatRegister f8  = { FloatRegisters::f8, FloatRegister::Double };
 static constexpr FloatRegister f10 = { FloatRegisters::f10, FloatRegister::Double };
 static constexpr FloatRegister f12 = { FloatRegisters::f12, FloatRegister::Double };
 static constexpr FloatRegister f14 = { FloatRegisters::f14, FloatRegister::Double };
--- a/js/src/jit/mips64/Assembler-mips64.h
+++ b/js/src/jit/mips64/Assembler-mips64.h
@@ -87,22 +87,16 @@ struct ScratchFloat32Scope : public Auto
 
 struct ScratchDoubleScope : public AutoFloatRegisterScope
 {
     explicit ScratchDoubleScope(MacroAssembler& masm)
       : AutoFloatRegisterScope(masm, ScratchDoubleReg)
     { }
 };
 
-// Registers used in the GenerateFFIIonExit Disable Activation block.
-// None of these may be the second scratch register (t8).
-static constexpr Register WasmIonExitRegReturnData = JSReturnReg_Data;
-static constexpr Register WasmIonExitRegReturnType = JSReturnReg_Type;
-static constexpr Register WasmIonExitTlsReg = s5;
-
 static constexpr FloatRegister f0  = { FloatRegisters::f0, FloatRegisters::Double };
 static constexpr FloatRegister f1  = { FloatRegisters::f1, FloatRegisters::Double };
 static constexpr FloatRegister f2  = { FloatRegisters::f2, FloatRegisters::Double };
 static constexpr FloatRegister f3  = { FloatRegisters::f3, FloatRegisters::Double };
 static constexpr FloatRegister f4  = { FloatRegisters::f4, FloatRegisters::Double };
 static constexpr FloatRegister f5  = { FloatRegisters::f5, FloatRegisters::Double };
 static constexpr FloatRegister f6  = { FloatRegisters::f6, FloatRegisters::Double };
 static constexpr FloatRegister f7  = { FloatRegisters::f7, FloatRegisters::Double };
--- a/js/src/jit/none/LIR-none.h
+++ b/js/src/jit/none/LIR-none.h
@@ -42,17 +42,17 @@ class LTableSwitchV : public LInstructio
 
     static const size_t InputValue = 0;
 };
 
 class LWasmUint32ToFloat32 : public LInstructionHelper<1, 1, 0>
 {
   public:
     explicit LWasmUint32ToFloat32(const LAllocation&)
-      : LInstructionHelper(LOp_Invalid)
+      : LInstructionHelper(Opcode::Invalid)
     {
         MOZ_CRASH();
     }
 };
 
 class LUnbox : public LInstructionHelper<1, 2, 0>
 {
   public:
@@ -62,59 +62,59 @@ class LUnbox : public LInstructionHelper
     const LAllocation* type() { MOZ_CRASH(); }
     const char* extraName() const { MOZ_CRASH(); }
 };
 class LDivI : public LBinaryMath<1>
 {
   public:
     LDivI(const LAllocation& , const LAllocation& ,
           const LDefinition& )
-      : LBinaryMath(LOp_Invalid)
+      : LBinaryMath(Opcode::Invalid)
     {
         MOZ_CRASH();
     }
     MDiv* mir() const { MOZ_CRASH(); }
 };
 class LDivPowTwoI : public LInstructionHelper<1, 1, 0>
 {
   public:
-    LDivPowTwoI(const LAllocation&, int32_t) : LInstructionHelper(LOp_Invalid) { MOZ_CRASH(); }
+    LDivPowTwoI(const LAllocation&, int32_t) : LInstructionHelper(Opcode::Invalid) { MOZ_CRASH(); }
     const LAllocation* numerator() { MOZ_CRASH(); }
     int32_t shift() { MOZ_CRASH(); }
     MDiv* mir() const { MOZ_CRASH(); }
 };
 class LModI : public LBinaryMath<1>
 {
   public:
     LModI(const LAllocation&, const LAllocation&,
           const LDefinition&)
-      : LBinaryMath(LOp_Invalid)
+      : LBinaryMath(Opcode::Invalid)
     {
         MOZ_CRASH();
     }
 
     const LDefinition* callTemp() { MOZ_CRASH(); }
     MMod* mir() const { MOZ_CRASH(); }
 };
 class LWasmUint32ToDouble : public LInstructionHelper<1, 1, 0>
 {
   public:
     explicit LWasmUint32ToDouble(const LAllocation&)
-      : LInstructionHelper(LOp_Invalid)
+      : LInstructionHelper(Opcode::Invalid)
     {
         MOZ_CRASH();
     }
 };
 class LModPowTwoI : public LInstructionHelper<1, 1, 0>
 {
 
   public:
     int32_t shift() { MOZ_CRASH(); }
     LModPowTwoI(const LAllocation& lhs, int32_t shift)
-      : LInstructionHelper(LOp_Invalid)
+      : LInstructionHelper(Opcode::Invalid)
     {
         MOZ_CRASH();
     }
     MMod* mir() const { MOZ_CRASH(); }
 };
 
 class LMulI : public LInstruction {};
 
--- a/js/src/jit/none/Lowering-none.h
+++ b/js/src/jit/none/Lowering-none.h
@@ -65,53 +65,53 @@ class LIRGeneratorNone : public LIRGener
     void lowerTruncateFToInt32(MTruncateToInt32*) { MOZ_CRASH(); }
     void lowerDivI(MDiv*) { MOZ_CRASH(); }
     void lowerModI(MMod*) { MOZ_CRASH(); }
     void lowerDivI64(MDiv*) { MOZ_CRASH(); }
     void lowerModI64(MMod*) { MOZ_CRASH(); }
     void lowerMulI(MMul*, MDefinition*, MDefinition*) { MOZ_CRASH(); }
     void lowerUDiv(MDiv*) { MOZ_CRASH(); }
     void lowerUMod(MMod*) { MOZ_CRASH(); }
-    void visitBox(MBox* box) override { MOZ_CRASH(); }
-    void visitUnbox(MUnbox* unbox) override { MOZ_CRASH(); }
-    void visitReturn(MReturn* ret) override { MOZ_CRASH(); }
-    void visitPowHalf(MPowHalf*) override { MOZ_CRASH(); }
-    void visitWasmNeg(MWasmNeg*) override { MOZ_CRASH(); }
-    void visitWasmUnsignedToDouble(MWasmUnsignedToDouble* ins) override { MOZ_CRASH(); }
-    void visitWasmUnsignedToFloat32(MWasmUnsignedToFloat32* ins) override { MOZ_CRASH(); }
-    void visitAsmJSLoadHeap(MAsmJSLoadHeap* ins) override { MOZ_CRASH(); }
-    void visitAsmJSStoreHeap(MAsmJSStoreHeap* ins) override { MOZ_CRASH(); }
-    void visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic* ins) override { MOZ_CRASH(); }
-    void visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop* ins) override { MOZ_CRASH(); }
-    void visitCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement* ins) override { MOZ_CRASH(); }
-    void visitAtomicExchangeTypedArrayElement(MAtomicExchangeTypedArrayElement* ins) override { MOZ_CRASH(); }
-    void visitWasmCompareExchangeHeap(MWasmCompareExchangeHeap* ins) override { MOZ_CRASH(); }
-    void visitWasmAtomicExchangeHeap(MWasmAtomicExchangeHeap* ins) override { MOZ_CRASH(); }
-    void visitWasmAtomicBinopHeap(MWasmAtomicBinopHeap* ins) override { MOZ_CRASH(); }
-    void visitWasmSelect(MWasmSelect*) override { MOZ_CRASH(); }
-    void visitWasmBoundsCheck(MWasmBoundsCheck* ins) override { MOZ_CRASH(); }
-    void visitWasmLoad(MWasmLoad* ins) override { MOZ_CRASH(); }
-    void visitWasmStore(MWasmStore* ins) override { MOZ_CRASH(); }
+    void visitBox(MBox* box) { MOZ_CRASH(); }
+    void visitUnbox(MUnbox* unbox) { MOZ_CRASH(); }
+    void visitReturn(MReturn* ret) { MOZ_CRASH(); }
+    void visitPowHalf(MPowHalf*) { MOZ_CRASH(); }
+    void visitWasmNeg(MWasmNeg*) { MOZ_CRASH(); }
+    void visitWasmUnsignedToDouble(MWasmUnsignedToDouble* ins) { MOZ_CRASH(); }
+    void visitWasmUnsignedToFloat32(MWasmUnsignedToFloat32* ins) { MOZ_CRASH(); }
+    void visitAsmJSLoadHeap(MAsmJSLoadHeap* ins) { MOZ_CRASH(); }
+    void visitAsmJSStoreHeap(MAsmJSStoreHeap* ins) { MOZ_CRASH(); }
+    void visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic* ins) { MOZ_CRASH(); }
+    void visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop* ins) { MOZ_CRASH(); }
+    void visitCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement* ins) { MOZ_CRASH(); }
+    void visitAtomicExchangeTypedArrayElement(MAtomicExchangeTypedArrayElement* ins) { MOZ_CRASH(); }
+    void visitWasmCompareExchangeHeap(MWasmCompareExchangeHeap* ins) { MOZ_CRASH(); }
+    void visitWasmAtomicExchangeHeap(MWasmAtomicExchangeHeap* ins) { MOZ_CRASH(); }
+    void visitWasmAtomicBinopHeap(MWasmAtomicBinopHeap* ins) { MOZ_CRASH(); }
+    void visitWasmSelect(MWasmSelect*) { MOZ_CRASH(); }
+    void visitWasmBoundsCheck(MWasmBoundsCheck* ins) { MOZ_CRASH(); }
+    void visitWasmLoad(MWasmLoad* ins) { MOZ_CRASH(); }
+    void visitWasmStore(MWasmStore* ins) { MOZ_CRASH(); }
 
     LTableSwitch* newLTableSwitch(LAllocation, LDefinition, MTableSwitch*) { MOZ_CRASH(); }
     LTableSwitchV* newLTableSwitchV(MTableSwitch*) { MOZ_CRASH(); }
-    void visitSimdSelect(MSimdSelect* ins) override { MOZ_CRASH(); }
-    void visitSimdSplat(MSimdSplat* ins) override { MOZ_CRASH(); }
-    void visitSimdSwizzle(MSimdSwizzle* ins) override { MOZ_CRASH(); }
-    void visitSimdShuffle(MSimdShuffle* ins) override { MOZ_CRASH(); }
-    void visitSimdValueX4(MSimdValueX4* lir) override { MOZ_CRASH(); }
-    void visitSubstr(MSubstr*) override { MOZ_CRASH(); }
-    void visitSimdBinaryArith(js::jit::MSimdBinaryArith*) override { MOZ_CRASH(); }
-    void visitSimdBinarySaturating(MSimdBinarySaturating* ins) override { MOZ_CRASH(); }
-    void visitRandom(js::jit::MRandom*) override { MOZ_CRASH(); }
-    void visitCopySign(js::jit::MCopySign*) override { MOZ_CRASH(); }
-    void visitWasmTruncateToInt64(MWasmTruncateToInt64*) override { MOZ_CRASH(); }
-    void visitInt64ToFloatingPoint(MInt64ToFloatingPoint*) override { MOZ_CRASH(); }
-    void visitExtendInt32ToInt64(MExtendInt32ToInt64* ins) override { MOZ_CRASH(); }
-    void visitSignExtendInt64(MSignExtendInt64* ins) override { MOZ_CRASH(); }
+    void visitSimdSelect(MSimdSelect* ins) { MOZ_CRASH(); }
+    void visitSimdSplat(MSimdSplat* ins) { MOZ_CRASH(); }
+    void visitSimdSwizzle(MSimdSwizzle* ins) { MOZ_CRASH(); }
+    void visitSimdShuffle(MSimdShuffle* ins) { MOZ_CRASH(); }
+    void visitSimdValueX4(MSimdValueX4* lir) { MOZ_CRASH(); }
+    void visitSubstr(MSubstr*) { MOZ_CRASH(); }
+    void visitSimdBinaryArith(js::jit::MSimdBinaryArith*) { MOZ_CRASH(); }
+    void visitSimdBinarySaturating(MSimdBinarySaturating* ins) { MOZ_CRASH(); }
+    void visitRandom(js::jit::MRandom*) { MOZ_CRASH(); }
+    void visitCopySign(js::jit::MCopySign*) { MOZ_CRASH(); }
+    void visitWasmTruncateToInt64(MWasmTruncateToInt64*) { MOZ_CRASH(); }
+    void visitInt64ToFloatingPoint(MInt64ToFloatingPoint*) { MOZ_CRASH(); }
+    void visitExtendInt32ToInt64(MExtendInt32ToInt64* ins) { MOZ_CRASH(); }
+    void visitSignExtendInt64(MSignExtendInt64* ins) { MOZ_CRASH(); }
 };
 
 typedef LIRGeneratorNone LIRGeneratorSpecific;
 
 } // namespace jit
 } // namespace js
 
 #endif /* jit_none_Lowering_none_h */
--- a/js/src/jit/none/MacroAssembler-none.h
+++ b/js/src/jit/none/MacroAssembler-none.h
@@ -36,27 +36,16 @@ static constexpr Register CallTempReg5 {
 static constexpr Register InvalidReg { Registers::invalid_reg };
 
 static constexpr Register IntArgReg0 { Registers::invalid_reg };
 static constexpr Register IntArgReg1 { Registers::invalid_reg };
 static constexpr Register IntArgReg2 { Registers::invalid_reg };
 static constexpr Register IntArgReg3 { Registers::invalid_reg };
 static constexpr Register HeapReg { Registers::invalid_reg };
 
-static constexpr Register WasmIonExitRegCallee { Registers::invalid_reg };
-static constexpr Register WasmIonExitRegE0 { Registers::invalid_reg };
-static constexpr Register WasmIonExitRegE1 { Registers::invalid_reg };
-
-static constexpr Register WasmIonExitRegReturnData { Registers::invalid_reg };
-static constexpr Register WasmIonExitRegReturnType { Registers::invalid_reg };
-static constexpr Register WasmIonExitTlsReg { Registers::invalid_reg };
-static constexpr Register WasmIonExitRegD0 { Registers::invalid_reg };
-static constexpr Register WasmIonExitRegD1 { Registers::invalid_reg };
-static constexpr Register WasmIonExitRegD2 { Registers::invalid_reg };
-
 static constexpr Register RegExpTesterRegExpReg { Registers::invalid_reg };
 static constexpr Register RegExpTesterStringReg { Registers::invalid_reg };
 static constexpr Register RegExpTesterLastIndexReg { Registers::invalid_reg };
 static constexpr Register RegExpTesterStickyReg { Registers::invalid_reg };
 
 static constexpr Register RegExpMatcherRegExpReg { Registers::invalid_reg };
 static constexpr Register RegExpMatcherStringReg { Registers::invalid_reg };
 static constexpr Register RegExpMatcherLastIndexReg { Registers::invalid_reg };
--- a/js/src/jit/shared/CodeGenerator-shared.cpp
+++ b/js/src/jit/shared/CodeGenerator-shared.cpp
@@ -600,17 +600,17 @@ CodeGeneratorShared::encode(LSnapshot* s
 #ifdef TRACK_SNAPSHOTS
     uint32_t pcOpcode = 0;
     uint32_t lirOpcode = 0;
     uint32_t lirId = 0;
     uint32_t mirOpcode = 0;
     uint32_t mirId = 0;
 
     if (LNode* ins = instruction()) {
-        lirOpcode = ins->op();
+        lirOpcode = uint32_t(ins->op());
         lirId = ins->id();
         if (ins->mirRaw()) {
             mirOpcode = uint32_t(ins->mirRaw()->op());
             mirId = ins->mirRaw()->id();
             if (ins->mirRaw()->trackedPc())
                 pcOpcode = *ins->mirRaw()->trackedPc();
         }
     }
--- a/js/src/jit/shared/LIR-shared.h
+++ b/js/src/jit/shared/LIR-shared.h
@@ -4326,19 +4326,19 @@ class LSubI : public LBinaryMath<0>
         return mir_->toSub();
     }
 };
 
 inline bool
 LNode::recoversInput() const
 {
     switch (op()) {
-      case LOp_AddI:
+      case Opcode::AddI:
         return toAddI()->recoversInput();
-      case LOp_SubI:
+      case Opcode::SubI:
         return toSubI()->recoversInput();
       default:
         return false;
     }
 }
 
 class LSubI64 : public LInstructionHelper<INT64_PIECES, 2 * INT64_PIECES, 0>
 {
@@ -9872,19 +9872,19 @@ class LWasmStackArgI64 : public LInstruc
     const LInt64Allocation arg() {
         return getInt64Operand(0);
     }
 };
 
 inline bool
 IsWasmCall(LNode::Opcode op)
 {
-    return (op == LNode::LOp_WasmCall ||
-            op == LNode::LOp_WasmCallVoid ||
-            op == LNode::LOp_WasmCallI64);
+    return (op == LNode::Opcode::WasmCall ||
+            op == LNode::Opcode::WasmCallVoid ||
+            op == LNode::Opcode::WasmCallI64);
 }
 
 template <size_t Defs>
 class LWasmCallBase : public LVariadicInstruction<Defs, 0>
 {
     using Base = LVariadicInstruction<Defs, 0>;
 
     bool needsBoundsCheck_;
--- a/js/src/jit/shared/Lowering-shared-inl.h
+++ b/js/src/jit/shared/Lowering-shared-inl.h
@@ -460,17 +460,17 @@ LIRGeneratorShared::redefine(MDefinition
 #endif
     }
 }
 
 void
 LIRGeneratorShared::ensureDefined(MDefinition* mir)
 {
     if (mir->isEmittedAtUses()) {
-        mir->toInstruction()->accept(this);
+        visitEmittedAtUses(mir->toInstruction());
         MOZ_ASSERT(mir->isLowered());
     }
 }
 
 template <typename LClass, typename... Args>
 LClass*
 LIRGeneratorShared::allocateVariadic(uint32_t numOperands, Args&&... args)
 {
--- a/js/src/jit/shared/Lowering-shared.h
+++ b/js/src/jit/shared/Lowering-shared.h
@@ -17,17 +17,17 @@ namespace js {
 namespace jit {
 
 class MIRGenerator;
 class MIRGraph;
 class MDefinition;
 class MInstruction;
 class LOsiPoint;
 
-class LIRGeneratorShared : public MDefinitionVisitor
+class LIRGeneratorShared
 {
   protected:
     MIRGenerator* gen;
     MIRGraph& graph;
     LIRGraph& lirGraph_;
     LBlock* current;
     MResumePoint* lastResumePoint_;
     LRecoverInfo* cachedRecoverInfo_;
@@ -78,16 +78,18 @@ class LIRGeneratorShared : public MDefin
     // The backend can use the worklist bit to determine whether or not a
     // definition should be created.
     inline void emitAtUses(MInstruction* mir);
 
     // The lowest-level calls to use, those that do not wrap another call to
     // use(), must prefix grabbing virtual register IDs by these calls.
     inline void ensureDefined(MDefinition* mir);
 
+    void visitEmittedAtUses(MInstruction* ins);
+
     // These all create a use of a virtual register, with an optional
     // allocation policy.
     //
     // Some of these use functions have atStart variants.
     // - non-atStart variants will tell the register allocator that the input
     // allocation must be different from any Temp or Definition also needed for
     // this LInstruction.
     // - atStart variants relax that restriction and allow the input to be in
@@ -282,42 +284,42 @@ class LIRGeneratorShared : public MDefin
   public:
     void lowerConstantDouble(double d, MInstruction* mir) {
         define(new(alloc()) LDouble(d), mir);
     }
     void lowerConstantFloat32(float f, MInstruction* mir) {
         define(new(alloc()) LFloat32(f), mir);
     }
 
-    void visitConstant(MConstant* ins) override;
-    void visitWasmFloatConstant(MWasmFloatConstant* ins) override;
+    void visitConstant(MConstant* ins);
+    void visitWasmFloatConstant(MWasmFloatConstant* ins);
 
     // Whether to generate typed reads for element accesses with hole checks.
     static bool allowTypedElementHoleCheck() {
         return false;
     }
 
     // Whether to generate typed array accesses on statically known objects.
     static bool allowStaticTypedArrayAccesses() {
         return false;
     }
 
     // Provide NYI default implementations of the SIMD visitor functions.
     // Many targets don't implement SIMD at all, and we don't want to duplicate
     // these stubs in the specific sub-classes.
     // Some SIMD visitors are implemented in LIRGenerator in Lowering.cpp. These
     // shared implementations are not included here.
-    void visitSimdInsertElement(MSimdInsertElement*) override { MOZ_CRASH("NYI"); }
-    void visitSimdExtractElement(MSimdExtractElement*) override { MOZ_CRASH("NYI"); }
-    void visitSimdBinaryArith(MSimdBinaryArith*) override { MOZ_CRASH("NYI"); }
-    void visitSimdSelect(MSimdSelect*) override { MOZ_CRASH("NYI"); }
-    void visitSimdSplat(MSimdSplat*) override { MOZ_CRASH("NYI"); }
-    void visitSimdValueX4(MSimdValueX4*) override { MOZ_CRASH("NYI"); }
-    void visitSimdBinarySaturating(MSimdBinarySaturating*) override { MOZ_CRASH("NYI"); }
-    void visitSimdSwizzle(MSimdSwizzle*) override { MOZ_CRASH("NYI"); }
-    void visitSimdShuffle(MSimdShuffle*) override { MOZ_CRASH("NYI"); }
-    void visitSimdGeneralShuffle(MSimdGeneralShuffle*) override { MOZ_CRASH("NYI"); }
+    void visitSimdInsertElement(MSimdInsertElement*) { MOZ_CRASH("NYI"); }
+    void visitSimdExtractElement(MSimdExtractElement*) { MOZ_CRASH("NYI"); }
+    void visitSimdBinaryArith(MSimdBinaryArith*) { MOZ_CRASH("NYI"); }
+    void visitSimdSelect(MSimdSelect*) { MOZ_CRASH("NYI"); }
+    void visitSimdSplat(MSimdSplat*) { MOZ_CRASH("NYI"); }
+    void visitSimdValueX4(MSimdValueX4*) { MOZ_CRASH("NYI"); }
+    void visitSimdBinarySaturating(MSimdBinarySaturating*) { MOZ_CRASH("NYI"); }
+    void visitSimdSwizzle(MSimdSwizzle*) { MOZ_CRASH("NYI"); }
+    void visitSimdShuffle(MSimdShuffle*) { MOZ_CRASH("NYI"); }
+    void visitSimdGeneralShuffle(MSimdGeneralShuffle*) { MOZ_CRASH("NYI"); }
 };
 
 } // namespace jit
 } // namespace js
 
 #endif /* jit_shared_Lowering_shared_h */
--- a/js/src/jit/x64/Assembler-x64.h
+++ b/js/src/jit/x64/Assembler-x64.h
@@ -143,29 +143,16 @@ static constexpr FloatRegister FloatArgR
 static constexpr FloatRegister FloatArgReg4 = xmm4;
 static constexpr FloatRegister FloatArgReg5 = xmm5;
 static constexpr FloatRegister FloatArgReg6 = xmm6;
 static constexpr FloatRegister FloatArgReg7 = xmm7;
 static constexpr uint32_t NumFloatArgRegs = 8;
 static constexpr FloatRegister FloatArgRegs[NumFloatArgRegs] = { xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7 };
 #endif
 
-// Registers used in the GenerateFFIIonExit Enable Activation block.
-static constexpr Register WasmIonExitRegCallee = r10;
-static constexpr Register WasmIonExitRegE0 = rax;
-static constexpr Register WasmIonExitRegE1 = rdi;
-
-// Registers used in the GenerateFFIIonExit Disable Activation block.
-static constexpr Register WasmIonExitRegReturnData = ecx;
-static constexpr Register WasmIonExitRegReturnType = ecx;
-static constexpr Register WasmIonExitTlsReg = r14;
-static constexpr Register WasmIonExitRegD0 = rax;
-static constexpr Register WasmIonExitRegD1 = rdi;
-static constexpr Register WasmIonExitRegD2 = rbx;
-
 // Registerd used in RegExpMatcher instruction (do not use JSReturnOperand).
 static constexpr Register RegExpMatcherRegExpReg = CallTempReg0;
 static constexpr Register RegExpMatcherStringReg = CallTempReg1;
 static constexpr Register RegExpMatcherLastIndexReg = CallTempReg2;
 
 // Registerd used in RegExpTester instruction (do not use ReturnReg).
 static constexpr Register RegExpTesterRegExpReg = CallTempReg1;
 static constexpr Register RegExpTesterStringReg = CallTempReg2;
--- a/js/src/jit/x64/Lowering-x64.h
+++ b/js/src/jit/x64/Lowering-x64.h
@@ -44,38 +44,38 @@ class LIRGeneratorX64 : public LIRGenera
     bool needTempForPostBarrier() { return true; }
 
     void lowerDivI64(MDiv* div);
     void lowerModI64(MMod* mod);
     void lowerUDivI64(MDiv* div);
     void lowerUModI64(MMod* mod);
 
   public:
-    void visitBox(MBox* box) override;
-    void visitUnbox(MUnbox* unbox) override;
-    void visitReturn(MReturn* ret) override;
-    void visitCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement* ins) override;
-    void visitAtomicExchangeTypedArrayElement(MAtomicExchangeTypedArrayElement* ins) override;
-    void visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop* ins) override;
-    void visitWasmUnsignedToDouble(MWasmUnsignedToDouble* ins) override;
-    void visitWasmUnsignedToFloat32(MWasmUnsignedToFloat32* ins) override;
-    void visitAsmJSLoadHeap(MAsmJSLoadHeap* ins) override;
-    void visitAsmJSStoreHeap(MAsmJSStoreHeap* ins) override;
-    void visitWasmCompareExchangeHeap(MWasmCompareExchangeHeap* ins) override;
-    void visitWasmAtomicExchangeHeap(MWasmAtomicExchangeHeap* ins) override;
-    void visitWasmAtomicBinopHeap(MWasmAtomicBinopHeap* ins) override;
-    void visitWasmLoad(MWasmLoad* ins) override;
-    void visitWasmStore(MWasmStore* ins) override;
-    void visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic* ins) override;
-    void visitSubstr(MSubstr* ins) override;
-    void visitRandom(MRandom* ins) override;
-    void visitWasmTruncateToInt64(MWasmTruncateToInt64* ins) override;
-    void visitInt64ToFloatingPoint(MInt64ToFloatingPoint* ins) override;
-    void visitExtendInt32ToInt64(MExtendInt32ToInt64* ins) override;
-    void visitSignExtendInt64(MSignExtendInt64* ins) override;
+    void visitBox(MBox* box);
+    void visitUnbox(MUnbox* unbox);
+    void visitReturn(MReturn* ret);
+    void visitCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement* ins);
+    void visitAtomicExchangeTypedArrayElement(MAtomicExchangeTypedArrayElement* ins);
+    void visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop* ins);
+    void visitWasmUnsignedToDouble(MWasmUnsignedToDouble* ins);
+    void visitWasmUnsignedToFloat32(MWasmUnsignedToFloat32* ins);
+    void visitAsmJSLoadHeap(MAsmJSLoadHeap* ins);
+    void visitAsmJSStoreHeap(MAsmJSStoreHeap* ins);
+    void visitWasmCompareExchangeHeap(MWasmCompareExchangeHeap* ins);
+    void visitWasmAtomicExchangeHeap(MWasmAtomicExchangeHeap* ins);
+    void visitWasmAtomicBinopHeap(MWasmAtomicBinopHeap* ins);
+    void visitWasmLoad(MWasmLoad* ins);
+    void visitWasmStore(MWasmStore* ins);
+    void visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic* ins);
+    void visitSubstr(MSubstr* ins);
+    void visitRandom(MRandom* ins);
+    void visitWasmTruncateToInt64(MWasmTruncateToInt64* ins);
+    void visitInt64ToFloatingPoint(MInt64ToFloatingPoint* ins);
+    void visitExtendInt32ToInt64(MExtendInt32ToInt64* ins);
+    void visitSignExtendInt64(MSignExtendInt64* ins);
 };
 
 typedef LIRGeneratorX64 LIRGeneratorSpecific;
 
 } // namespace jit
 } // namespace js
 
 #endif /* jit_x64_Lowering_x64_h */
--- a/js/src/jit/x86-shared/Assembler-x86-shared.h
+++ b/js/src/jit/x86-shared/Assembler-x86-shared.h
@@ -1079,19 +1079,16 @@ class AssemblerX86Shared : public Assemb
     }
     CodeOffset farJumpWithPatch() {
         return CodeOffset(masm.jmp().offset());
     }
     void patchFarJump(CodeOffset farJump, uint32_t targetOffset) {
         unsigned char* code = masm.data();
         X86Encoding::SetRel32(code + farJump.offset(), code + targetOffset);
     }
-    static void repatchFarJump(uint8_t* code, uint32_t farJumpOffset, uint32_t targetOffset) {
-        X86Encoding::SetRel32(code + farJumpOffset, code + targetOffset);
-    }
 
     // This is for patching during code generation, not after.
     void patchAddl(CodeOffset offset, int32_t n) {
         unsigned char* code = masm.data();
         X86Encoding::SetInt32(code + offset.offset(), n);
     }
 
     CodeOffset twoByteNop() {
--- a/js/src/jit/x86-shared/Lowering-x86-shared.h
+++ b/js/src/jit/x86-shared/Lowering-x86-shared.h
@@ -18,17 +18,17 @@ class LIRGeneratorX86Shared : public LIR
     LIRGeneratorX86Shared(MIRGenerator* gen, MIRGraph& graph, LIRGraph& lirGraph)
       : LIRGeneratorShared(gen, graph, lirGraph)
     {}
 
     LTableSwitch* newLTableSwitch(const LAllocation& in, const LDefinition& inputCopy,
                                   MTableSwitch* ins);
     LTableSwitchV* newLTableSwitchV(MTableSwitch* ins);
 
-    void visitPowHalf(MPowHalf* ins) override;
+    void visitPowHalf(MPowHalf* ins);
     void lowerForShift(LInstructionHelper<1, 2, 0>* ins, MDefinition* mir, MDefinition* lhs,
                        MDefinition* rhs);
     void lowerForALU(LInstructionHelper<1, 1, 0>* ins, MDefinition* mir, MDefinition* input);
     void lowerForALU(LInstructionHelper<1, 2, 0>* ins, MDefinition* mir, MDefinition* lhs,
                      MDefinition* rhs);
 
     template<size_t Temps>
     void lowerForShiftInt64(LInstructionHelper<INT64_PIECES, INT64_PIECES + 1, Temps>* ins,
@@ -38,41 +38,41 @@ class LIRGeneratorX86Shared : public LIR
     void lowerForFPU(LInstructionHelper<1, 2, Temps>* ins, MDefinition* mir, MDefinition* lhs,
                      MDefinition* rhs);
     void lowerForCompIx4(LSimdBinaryCompIx4* ins, MSimdBinaryComp* mir,
                          MDefinition* lhs, MDefinition* rhs);
     void lowerForCompFx4(LSimdBinaryCompFx4* ins, MSimdBinaryComp* mir,
                          MDefinition* lhs, MDefinition* rhs);
     void lowerForBitAndAndBranch(LBitAndAndBranch* baab, MInstruction* mir,
                                  MDefinition* lhs, MDefinition* rhs);
-    void visitWasmNeg(MWasmNeg* ins) override;
-    void visitWasmSelect(MWasmSelect* ins) override;
+    void visitWasmNeg(MWasmNeg* ins);
+    void visitWasmSelect(MWasmSelect* ins);
     void lowerMulI(MMul* mul, MDefinition* lhs, MDefinition* rhs);
     void lowerDivI(MDiv* div);
     void lowerModI(MMod* mod);
     void lowerUDiv(MDiv* div);
     void lowerUMod(MMod* mod);
     void lowerUrshD(MUrsh* mir);
     void lowerTruncateDToInt32(MTruncateToInt32* ins);
     void lowerTruncateFToInt32(MTruncateToInt32* ins);
-    void visitSimdInsertElement(MSimdInsertElement* ins) override;
-    void visitSimdExtractElement(MSimdExtractElement* ins) override;
-    void visitSimdBinaryArith(MSimdBinaryArith* ins) override;
-    void visitSimdBinarySaturating(MSimdBinarySaturating* ins) override;
-    void visitSimdSelect(MSimdSelect* ins) override;
-    void visitSimdSplat(MSimdSplat* ins) override;
-    void visitSimdSwizzle(MSimdSwizzle* ins) override;
-    void visitSimdShuffle(MSimdShuffle* ins) override;
-    void visitSimdGeneralShuffle(MSimdGeneralShuffle* ins) override;
-    void visitSimdValueX4(MSimdValueX4* ins) override;
+    void visitSimdInsertElement(MSimdInsertElement* ins);
+    void visitSimdExtractElement(MSimdExtractElement* ins);
+    void visitSimdBinaryArith(MSimdBinaryArith* ins);
+    void visitSimdBinarySaturating(MSimdBinarySaturating* ins);
+    void visitSimdSelect(MSimdSelect* ins);
+    void visitSimdSplat(MSimdSplat* ins);
+    void visitSimdSwizzle(MSimdSwizzle* ins);
+    void visitSimdShuffle(MSimdShuffle* ins);
+    void visitSimdGeneralShuffle(MSimdGeneralShuffle* ins);
+    void visitSimdValueX4(MSimdValueX4* ins);
     void lowerCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement* ins,
                                                bool useI386ByteRegisters);
     void lowerAtomicExchangeTypedArrayElement(MAtomicExchangeTypedArrayElement* ins,
                                               bool useI386ByteRegisters);
     void lowerAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop* ins,
                                            bool useI386ByteRegisters);
-    void visitCopySign(MCopySign* ins) override;
+    void visitCopySign(MCopySign* ins);
 };
 
 } // namespace jit
 } // namespace js
 
 #endif /* jit_x86_shared_Lowering_x86_shared_h */
--- a/js/src/jit/x86-shared/MacroAssembler-x86-shared.cpp
+++ b/js/src/jit/x86-shared/MacroAssembler-x86-shared.cpp
@@ -588,40 +588,16 @@ MacroAssembler::farJumpWithPatch()
 }
 
 void
 MacroAssembler::patchFarJump(CodeOffset farJump, uint32_t targetOffset)
 {
     Assembler::patchFarJump(farJump, targetOffset);
 }
 
-void
-MacroAssembler::repatchFarJump(uint8_t* code, uint32_t farJumpOffset, uint32_t targetOffset)
-{
-    Assembler::repatchFarJump(code, farJumpOffset, targetOffset);
-}
-
-CodeOffset
-MacroAssembler::nopPatchableToNearJump()
-{
-    return Assembler::twoByteNop();
-}
-
-void
-MacroAssembler::patchNopToNearJump(uint8_t* jump, uint8_t* target)
-{
-    Assembler::patchTwoByteNopToJump(jump, target);
-}
-
-void
-MacroAssembler::patchNearJumpToNop(uint8_t* jump)
-{
-    Assembler::patchJumpToTwoByteNop(jump);
-}
-
 CodeOffset
 MacroAssembler::nopPatchableToCall(const wasm::CallSiteDesc& desc)
 {
     CodeOffset offset(currentOffset());
     masm.nop_five();
     append(desc, CodeOffset(currentOffset()));
     MOZ_ASSERT_IF(!oom(), size() - offset.offset() == ToggledCallSize(nullptr));
     return offset;
--- a/js/src/jit/x86/Assembler-x86.h
+++ b/js/src/jit/x86/Assembler-x86.h
@@ -108,29 +108,16 @@ static constexpr Register WasmTlsReg = e
 // from the ABI argument registers, WasmTlsReg and each other.
 static constexpr Register WasmTableCallScratchReg = ABINonArgReg0;
 static constexpr Register WasmTableCallSigReg = ABINonArgReg1;
 static constexpr Register WasmTableCallIndexReg = ABINonArgReg2;
 
 static constexpr Register OsrFrameReg = edx;
 static constexpr Register PreBarrierReg = edx;
 
-// Registers used in the GenerateFFIIonExit Enable Activation block.
-static constexpr Register WasmIonExitRegCallee = ecx;
-static constexpr Register WasmIonExitRegE0 = edi;
-static constexpr Register WasmIonExitRegE1 = eax;
-
-// Registers used in the GenerateFFIIonExit Disable Activation block.
-static constexpr Register WasmIonExitRegReturnData = edx;
-static constexpr Register WasmIonExitRegReturnType = ecx;
-static constexpr Register WasmIonExitTlsReg = esi;
-static constexpr Register WasmIonExitRegD0 = edi;
-static constexpr Register WasmIonExitRegD1 = eax;
-static constexpr Register WasmIonExitRegD2 = ebx;
-
 // Registerd used in RegExpMatcher instruction (do not use JSReturnOperand).
 static constexpr Register RegExpMatcherRegExpReg = CallTempReg0;
 static constexpr Register RegExpMatcherStringReg = CallTempReg1;
 static constexpr Register RegExpMatcherLastIndexReg = CallTempReg2;
 
 // Registerd used in RegExpTester instruction (do not use ReturnReg).
 static constexpr Register RegExpTesterRegExpReg = CallTempReg0;
 static constexpr Register RegExpTesterStringReg = CallTempReg2;
--- a/js/src/jit/x86/Lowering-x86.h
+++ b/js/src/jit/x86/Lowering-x86.h
@@ -51,38 +51,38 @@ class LIRGeneratorX86 : public LIRGenera
     void lowerForMulInt64(LMulI64* ins, MMul* mir, MDefinition* lhs, MDefinition* rhs);
 
     void lowerDivI64(MDiv* div);
     void lowerModI64(MMod* mod);
     void lowerUDivI64(MDiv* div);
     void lowerUModI64(MMod* mod);
 
   public:
-    void visitBox(MBox* box) override;
-    void visitUnbox(MUnbox* unbox) override;
-    void visitReturn(MReturn* ret) override;
-    void visitCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement* ins) override;
-    void visitAtomicExchangeTypedArrayElement(MAtomicExchangeTypedArrayElement* ins) override;
-    void visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop* ins) override;
-    void visitWasmUnsignedToDouble(MWasmUnsignedToDouble* ins) override;
-    void visitWasmUnsignedToFloat32(MWasmUnsignedToFloat32* ins) override;
-    void visitAsmJSLoadHeap(MAsmJSLoadHeap* ins) override;
-    void visitAsmJSStoreHeap(MAsmJSStoreHeap* ins) override;
-    void visitWasmCompareExchangeHeap(MWasmCompareExchangeHeap* ins) override;
-    void visitWasmAtomicExchangeHeap(MWasmAtomicExchangeHeap* ins) override;
-    void visitWasmAtomicBinopHeap(MWasmAtomicBinopHeap* ins) override;
-    void visitWasmLoad(MWasmLoad* ins) override;
-    void visitWasmStore(MWasmStore* ins) override;
-    void visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic* ins) override;
-    void visitSubstr(MSubstr* ins) override;
-    void visitRandom(MRandom* ins) override;
-    void visitWasmTruncateToInt64(MWasmTruncateToInt64* ins) override;
-    void visitInt64ToFloatingPoint(MInt64ToFloatingPoint* ins) override;
-    void visitExtendInt32ToInt64(MExtendInt32ToInt64* ins) override;
-    void visitSignExtendInt64(MSignExtendInt64* ins) override;
+    void visitBox(MBox* box);
+    void visitUnbox(MUnbox* unbox);
+    void visitReturn(MReturn* ret);
+    void visitCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement* ins);
+    void visitAtomicExchangeTypedArrayElement(MAtomicExchangeTypedArrayElement* ins);
+    void visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop* ins);
+    void visitWasmUnsignedToDouble(MWasmUnsignedToDouble* ins);
+    void visitWasmUnsignedToFloat32(MWasmUnsignedToFloat32* ins);
+    void visitAsmJSLoadHeap(MAsmJSLoadHeap* ins);
+    void visitAsmJSStoreHeap(MAsmJSStoreHeap* ins);
+    void visitWasmCompareExchangeHeap(MWasmCompareExchangeHeap* ins);
+    void visitWasmAtomicExchangeHeap(MWasmAtomicExchangeHeap* ins);
+    void visitWasmAtomicBinopHeap(MWasmAtomicBinopHeap* ins);
+    void visitWasmLoad(MWasmLoad* ins);
+    void visitWasmStore(MWasmStore* ins);
+    void visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic* ins);
+    void visitSubstr(MSubstr* ins);
+    void visitRandom(MRandom* ins);
+    void visitWasmTruncateToInt64(MWasmTruncateToInt64* ins);
+    void visitInt64ToFloatingPoint(MInt64ToFloatingPoint* ins);
+    void visitExtendInt32ToInt64(MExtendInt32ToInt64* ins);
+    void visitSignExtendInt64(MSignExtendInt64* ins);
     void lowerPhi(MPhi* phi);
 
     static bool allowTypedElementHoleCheck() {
         return true;
     }
 
     static bool allowStaticTypedArrayAccesses() {
         return true;
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -7612,61 +7612,73 @@ JS::detail::AssertArgumentsAreSane(JSCon
 }
 #endif /* JS_DEBUG */
 
 JS_PUBLIC_API(JS::TranscodeResult)
 JS::EncodeScript(JSContext* cx, TranscodeBuffer& buffer, HandleScript scriptArg)
 {
     XDREncoder encoder(cx, buffer, buffer.length());
     RootedScript script(cx, scriptArg);
-    if (!encoder.codeScript(&script))
+    XDRResult res = encoder.codeScript(&script);
+    if (res.isErr()) {
         buffer.clearAndFree();
-    MOZ_ASSERT(!buffer.empty() == (encoder.resultCode() == TranscodeResult_Ok));
-    return encoder.resultCode();
+        return res.unwrapErr();
+    }
+    MOZ_ASSERT(!buffer.empty());
+    return JS::TranscodeResult_Ok;
 }
 
 JS_PUBLIC_API(JS::TranscodeResult)
 JS::EncodeInterpretedFunction(JSContext* cx, TranscodeBuffer& buffer, HandleObject funobjArg)
 {
     XDREncoder encoder(cx, buffer, buffer.length());
     RootedFunction funobj(cx, &funobjArg->as<JSFunction>());
-    if (!encoder.codeFunction(&funobj))
+    XDRResult res = encoder.codeFunction(&funobj);
+    if (res.isErr()) {
         buffer.clearAndFree();
-    MOZ_ASSERT(!buffer.empty() == (encoder.resultCode() == TranscodeResult_Ok));
-    return encoder.resultCode();
+        return res.unwrapErr();
+    }
+    MOZ_ASSERT(!buffer.empty());
+    return JS::TranscodeResult_Ok;
 }
 
 JS_PUBLIC_API(JS::TranscodeResult)
 JS::DecodeScript(JSContext* cx, TranscodeBuffer& buffer, JS::MutableHandleScript scriptp,
                  size_t cursorIndex)
 {
     XDRDecoder decoder(cx, buffer, cursorIndex);
-    decoder.codeScript(scriptp);
-    MOZ_ASSERT(bool(scriptp) == (decoder.resultCode() == TranscodeResult_Ok));
-    return decoder.resultCode();
+    XDRResult res = decoder.codeScript(scriptp);
+    MOZ_ASSERT(bool(scriptp) == res.isOk());
+    if (res.isErr())
+        return res.unwrapErr();
+    return JS::TranscodeResult_Ok;
 }
 
 JS_PUBLIC_API(JS::TranscodeResult)
 JS::DecodeScript(JSContext* cx, const TranscodeRange& range, JS::MutableHandleScript scriptp)
 {
     XDRDecoder decoder(cx, range);
-    decoder.codeScript(scriptp);
-    MOZ_ASSERT(bool(scriptp) == (decoder.resultCode() == TranscodeResult_Ok));
-    return decoder.resultCode();
+    XDRResult res = decoder.codeScript(scriptp);
+    MOZ_ASSERT(bool(scriptp) == res.isOk());
+    if (res.isErr())
+        return res.unwrapErr();
+    return JS::TranscodeResult_Ok;
 }
 
 JS_PUBLIC_API(JS::TranscodeResult)
 JS::DecodeInterpretedFunction(JSContext* cx, TranscodeBuffer& buffer,
                               JS::MutableHandleFunction funp,
                               size_t cursorIndex)
 {
     XDRDecoder decoder(cx, buffer, cursorIndex);
-    decoder.codeFunction(funp);
-    MOZ_ASSERT(bool(funp) == (decoder.resultCode() == TranscodeResult_Ok));
-    return decoder.resultCode();
+    XDRResult res = decoder.codeFunction(funp);
+    MOZ_ASSERT(bool(funp) == res.isOk());
+    if (res.isErr())
+        return res.unwrapErr();
+    return JS::TranscodeResult_Ok;
 }
 
 JS_PUBLIC_API(bool)
 JS::StartIncrementalEncoding(JSContext* cx, JS::HandleScript script)
 {
     if (!script)
         return false;
     if (!script->scriptSource()->xdrEncodeTopLevel(cx, script))
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -6044,32 +6044,32 @@ struct TranscodeSource
 
     const TranscodeRange range;
     const char* filename;
     const uint32_t lineno;
 };
 
 typedef mozilla::Vector<JS::TranscodeSource> TranscodeSources;
 
-enum TranscodeResult
+enum TranscodeResult: uint8_t
 {
     // Successful encoding / decoding.
     TranscodeResult_Ok = 0,
 
     // A warning message, is set to the message out-param.
-    TranscodeResult_Failure = 0x100,
+    TranscodeResult_Failure = 0x10,
     TranscodeResult_Failure_BadBuildId =          TranscodeResult_Failure | 0x1,
     TranscodeResult_Failure_RunOnceNotSupported = TranscodeResult_Failure | 0x2,
     TranscodeResult_Failure_AsmJSNotSupported =   TranscodeResult_Failure | 0x3,
     TranscodeResult_Failure_BadDecode =           TranscodeResult_Failure | 0x4,
     TranscodeResult_Failure_WrongCompileOption =  TranscodeResult_Failure | 0x5,
     TranscodeResult_Failure_NotInterpretedFun =   TranscodeResult_Failure | 0x6,
 
     // There is a pending exception on the context.
-    TranscodeResult_Throw = 0x200
+    TranscodeResult_Throw = 0x20
 };
 
 extern JS_PUBLIC_API(TranscodeResult)
 EncodeScript(JSContext* cx, TranscodeBuffer& buffer, JS::HandleScript script);
 
 extern JS_PUBLIC_API(TranscodeResult)
 EncodeInterpretedFunction(JSContext* cx, TranscodeBuffer& buffer, JS::HandleObject funobj);
 
--- a/js/src/vm/HelperThreads.cpp
+++ b/js/src/vm/HelperThreads.cpp
@@ -510,19 +510,19 @@ ScriptDecodeTask::ScriptDecodeTask(JSCon
 void
 ScriptDecodeTask::parse(JSContext* cx)
 {
     RootedScript resultScript(cx);
     Rooted<ScriptSourceObject*> sourceObject(cx);
 
     XDROffThreadDecoder decoder(cx, alloc, &options, /* sourceObjectOut = */ &sourceObject.get(),
                                 range);
-    decoder.codeScript(&resultScript);
-    MOZ_ASSERT(bool(resultScript) == (decoder.resultCode() == JS::TranscodeResult_Ok));
-    if (decoder.resultCode() == JS::TranscodeResult_Ok) {
+    XDRResult res = decoder.codeScript(&resultScript);
+    MOZ_ASSERT(bool(resultScript) == res.isOk());
+    if (res.isOk()) {
         scripts.infallibleAppend(resultScript);
         if (sourceObject)
             sourceObjects.infallibleAppend(sourceObject);
     }
 }
 
 MultiScriptsDecodeTask::MultiScriptsDecodeTask(JSContext* cx, JS::TranscodeSources& sources,
                                                JS::OffThreadCompileCallback callback,
@@ -543,20 +543,20 @@ MultiScriptsDecodeTask::parse(JSContext*
     for (auto& source : *sources) {
         CompileOptions opts(cx, options);
         opts.setFileAndLine(source.filename, source.lineno);
 
         RootedScript resultScript(cx);
         Rooted<ScriptSourceObject*> sourceObject(cx);
 
         XDROffThreadDecoder decoder(cx, alloc, &opts, &sourceObject.get(), source.range);
-        decoder.codeScript(&resultScript);
-        MOZ_ASSERT(bool(resultScript) == (decoder.resultCode() == JS::TranscodeResult_Ok));
+        XDRResult res = decoder.codeScript(&resultScript);
+        MOZ_ASSERT(bool(resultScript) == res.isOk());
 
-        if (decoder.resultCode() != JS::TranscodeResult_Ok)
+        if (res.isErr())
             break;
         MOZ_ASSERT(resultScript);
         scripts.infallibleAppend(resultScript);
         sourceObjects.infallibleAppend(sourceObject);
     }
 }
 
 void
--- a/js/src/vm/JSAtom.cpp
+++ b/js/src/vm/JSAtom.cpp
@@ -704,61 +704,71 @@ js::ToAtom(JSContext* cx, typename Maybe
 
 template JSAtom*
 js::ToAtom<CanGC>(JSContext* cx, HandleValue v);
 
 template JSAtom*
 js::ToAtom<NoGC>(JSContext* cx, const Value& v);
 
 template<XDRMode mode>
-bool
+XDRResult
 js::XDRAtom(XDRState<mode>* xdr, MutableHandleAtom atomp)
 {
+    bool latin1 = false;
+    uint32_t length = 0;
+    uint32_t lengthAndEncoding = 0;
     if (mode == XDR_ENCODE) {
         static_assert(JSString::MAX_LENGTH <= INT32_MAX, "String length must fit in 31 bits");
-        uint32_t length = atomp->length();
-        uint32_t lengthAndEncoding = (length << 1) | uint32_t(atomp->hasLatin1Chars());
-        if (!xdr->codeUint32(&lengthAndEncoding))
-            return false;
+        latin1 = atomp->hasLatin1Chars();
+        length = atomp->length();
+        lengthAndEncoding = (length << 1) | uint32_t(latin1);
+    }
 
-        JS::AutoCheckCannotGC nogc;
-        return atomp->hasLatin1Chars()
-               ? xdr->codeChars(atomp->latin1Chars(nogc), length)
-               : xdr->codeChars(const_cast<char16_t*>(atomp->twoByteChars(nogc)), length);
+    MOZ_TRY(xdr->codeUint32(&lengthAndEncoding));
+
+    if (mode == XDR_DECODE) {
+        length = lengthAndEncoding >> 1;
+        latin1 = lengthAndEncoding & 0x1;
     }
 
+    // We need to align the string in the XDR buffer such that we can avoid
+    // non-align loads of 16bits characters.
+    if (!latin1)
+        MOZ_TRY(xdr->codeAlign(sizeof(char16_t)));
+
+    if (mode == XDR_ENCODE) {
+        JS::AutoCheckCannotGC nogc;
+        if (latin1)
+            return xdr->codeChars(atomp->latin1Chars(nogc), length);
+        return xdr->codeChars(const_cast<char16_t*>(atomp->twoByteChars(nogc)), length);
+    }
+
+    MOZ_ASSERT(mode == XDR_DECODE);
     /* Avoid JSString allocation for already existing atoms. See bug 321985. */
-    uint32_t lengthAndEncoding;
-    if (!xdr->codeUint32(&lengthAndEncoding))
-        return false;
-
-    uint32_t length = lengthAndEncoding >> 1;
-    bool latin1 = lengthAndEncoding & 0x1;
-
     JSContext* cx = xdr->cx();
     JSAtom* atom;
     if (latin1) {
         const Latin1Char* chars = nullptr;
         if (length) {
             const uint8_t *ptr;
             size_t nbyte = length * sizeof(Latin1Char);
-            if (!xdr->peekData(&ptr, nbyte))
-                return false;
+            MOZ_TRY(xdr->peekData(&ptr, nbyte));
             chars = reinterpret_cast<const Latin1Char*>(ptr);
         }
         atom = AtomizeChars(cx, chars, length);
     } else {
 #if MOZ_LITTLE_ENDIAN
         /* Directly access the little endian chars in the XDR buffer. */
         const char16_t* chars = nullptr;
         if (length) {
             const uint8_t *ptr;
             size_t nbyte = length * sizeof(char16_t);
-            if (!xdr->peekData(&ptr, nbyte))
-                return false;
+            MOZ_TRY(xdr->peekData(&ptr, nbyte));
+            MOZ_ASSERT(reinterpret_cast<uintptr_t>(ptr) % sizeof(char16_t) == 0,
+                       "non-aligned buffer during JSAtom decoding");
             chars = reinterpret_cast<const char16_t*>(ptr);
         }
         atom = AtomizeChars(cx, chars, length);
 #else
         /*
          * We must copy chars to a temporary buffer to convert between little and
          * big endian data.
          */
@@ -769,36 +779,36 @@ js::XDRAtom(XDRState<mode>* xdr, Mutable
         } else {
             /*
              * This is very uncommon. Don't use the tempLifoAlloc arena for this as
              * most allocations here will be bigger than tempLifoAlloc's default
              * chunk size.
              */
             chars = cx->pod_malloc<char16_t>(length);
             if (!chars)
-                return false;
+                return fail(JS::TranscodeResult_Throw);
         }
 
         JS_ALWAYS_TRUE(xdr->codeChars(chars, length));
         atom = AtomizeChars(cx, chars, length);
         if (chars != stackChars)
             js_free(chars);
 #endif /* !MOZ_LITTLE_ENDIAN */
     }
 
     if (!atom)
-        return false;
+        return xdr->fail(JS::TranscodeResult_Throw);
     atomp.set(atom);
-    return true;
+    return Ok();
 }
 
-template bool
+template XDRResult
 js::XDRAtom(XDRState<XDR_ENCODE>* xdr, MutableHandleAtom atomp);
 
-template bool
+template XDRResult
 js::XDRAtom(XDRState<XDR_DECODE>* xdr, MutableHandleAtom atomp);
 
 Handle<PropertyName*>
 js::ClassName(JSProtoKey key, JSContext* cx)
 {
     return ClassName(key, cx->names());
 }
 
--- a/js/src/vm/JSAtom.h
+++ b/js/src/vm/JSAtom.h
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef vm_JSAtom_h
 #define vm_JSAtom_h
 
 #include "mozilla/Maybe.h"
 
 #include "gc/Rooting.h"
+#include "js/Result.h"
 #include "js/TypeDecls.h"
 #include "vm/CommonPropertyNames.h"
 
 class JSAutoByteString;
 
 namespace js {
 
 /*
@@ -48,16 +49,20 @@ JS_FOR_EACH_PROTOTYPE(DECLARE_PROTO_STR)
 FOR_EACH_COMMON_PROPERTYNAME(DECLARE_CONST_CHAR_STR)
 #undef DECLARE_CONST_CHAR_STR
 
 /* Constant strings that are not atomized. */
 extern const char js_getter_str[];
 extern const char js_send_str[];
 extern const char js_setter_str[];
 
+namespace JS {
+enum TranscodeResult : uint8_t;
+}
+
 namespace js {
 
 class AutoLockForExclusiveAccess;
 
 /*
  * Atom tracing and garbage collection hooks.
  */
 void
@@ -99,18 +104,20 @@ ToAtom(JSContext* cx, typename MaybeRoot
 enum XDRMode {
     XDR_ENCODE,
     XDR_DECODE
 };
 
 template <XDRMode mode>
 class XDRState;
 
+using XDRResult = mozilla::Result<mozilla::Ok, JS::TranscodeResult>;
+
 template<XDRMode mode>
-bool
+XDRResult
 XDRAtom(XDRState<mode>* xdr, js::MutableHandleAtom atomp);
 
 extern JS::Handle<PropertyName*>
 ClassName(JSProtoKey key, JSContext* cx);
 
 namespace gc {
 void MergeAtomsAddedWhileSweeping(JSRuntime* rt);
 } // namespace gc
--- a/js/src/vm/JSFunction.cpp
+++ b/js/src/vm/JSFunction.cpp
@@ -559,17 +559,17 @@ fun_resolve(JSContext* cx, HandleObject 
         *resolvedp = true;
         return true;
     }
 
     return true;
 }
 
 template<XDRMode mode>
-bool
+XDRResult
 js::XDRInterpretedFunction(XDRState<mode>* xdr, HandleScope enclosingScope,
                            HandleScriptSource sourceObject, MutableHandleFunction objp)
 {
     enum FirstWordFlag {
         HasAtom             = 0x1,
         HasGeneratorProto   = 0x2,
         IsLazy              = 0x4,
         HasSingletonType    = 0x8
@@ -617,82 +617,81 @@ js::XDRInterpretedFunction(XDRState<mode
         // mirror the scope chain.
         MOZ_ASSERT_IF(fun->isSingleton() &&
                       !((lazy && lazy->hasBeenCloned()) || (script && script->hasBeenCloned())),
                       fun->environment() == nullptr);
     }
 
     // Everything added below can substituted by the non-lazy-script version of
     // this function later.
+    MOZ_TRY(xdr->codeAlign(sizeof(js::XDRAlignment)));
     js::AutoXDRTree funTree(xdr, xdr->getTreeKey(fun));
 
-    if (!xdr->codeUint32(&firstword))
-        return false;
+    MOZ_TRY(xdr->codeUint32(&firstword));
 
-    if ((firstword & HasAtom) && !XDRAtom(xdr, &atom))
-        return false;
-    if (!xdr->codeUint32(&flagsword))
-        return false;
+    if (firstword & HasAtom)
+        MOZ_TRY(XDRAtom(xdr, &atom));
+    MOZ_TRY(xdr->codeUint32(&flagsword));
 
     if (mode == XDR_DECODE) {
         RootedObject proto(cx);
         if (firstword & HasGeneratorProto) {
             proto = GlobalObject::getOrCreateGeneratorFunctionPrototype(cx, cx->global());
             if (!proto)
-                return false;
+                return xdr->fail(JS::TranscodeResult_Throw);
         }
 
         gc::AllocKind allocKind = gc::AllocKind::FUNCTION;
         if (uint16_t(flagsword) & JSFunction::EXTENDED)
             allocKind = gc::AllocKind::FUNCTION_EXTENDED;
         fun = NewFunctionWithProto(cx, nullptr, 0, JSFunction::INTERPRETED,
                                    /* enclosingDynamicScope = */ nullptr, nullptr, proto,
                                    allocKind, TenuredObject);
         if (!fun)
-            return false;
+            return xdr->fail(JS::TranscodeResult_Throw);
         script = nullptr;
     }
 
-    if (firstword & IsLazy) {
-        if (!XDRLazyScript(xdr, enclosingScope, sourceObject, fun, &lazy))
-            return false;
-    } else {
-        if (!XDRScript(xdr, enclosingScope, sourceObject, fun, &script))
-            return false;
-    }
+    if (firstword & IsLazy)
+        MOZ_TRY(XDRLazyScript(xdr, enclosingScope, sourceObject, fun, &lazy));
+    else
+        MOZ_TRY(XDRScript(xdr, enclosingScope, sourceObject, fun, &script));
 
     if (mode == XDR_DECODE) {
         fun->setArgCount(flagsword >> 16);
         fun->setFlags(uint16_t(flagsword));
         fun->initAtom(atom);
         if (firstword & IsLazy) {
             MOZ_ASSERT(fun->lazyScript() == lazy);
         } else {
             MOZ_ASSERT(fun->nonLazyScript() == script);
             MOZ_ASSERT(fun->nargs() == script->numArgs());
         }
 
         bool singleton = firstword & HasSingletonType;
         if (!JSFunction::setTypeForScriptedFunction(cx, fun, singleton))
-            return false;
+            return xdr->fail(JS::TranscodeResult_Throw);
         objp.set(fun);
     }
 
     // Verify marker at end of function to detect buffer trunction.
-    if (!xdr->codeMarker(0x9E35CA1F))
-        return false;
+    MOZ_TRY(xdr->codeMarker(0x9E35CA1F));
 
-    return true;
+    // Required by AutoXDRTree to copy & paste snipet of sub-trees while keeping
+    // the alignment.
+    MOZ_TRY(xdr->codeAlign(sizeof(js::XDRAlignment)));
+
+    return Ok();
 }
 
-template bool
+template XDRResult
 js::XDRInterpretedFunction(XDRState<XDR_ENCODE>*, HandleScope, HandleScriptSource,
                            MutableHandleFunction);
 
-template bool
+template XDRResult
 js::XDRInterpretedFunction(XDRState<XDR_DECODE>*, HandleScope, HandleScriptSource,
                            MutableHandleFunction);
 
 /* ES6 (04-25-16) 19.2.3.6 Function.prototype [ @@hasInstance ] */
 bool
 js::fun_symbolHasInstance(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
--- a/js/src/vm/JSFunction.h
+++ b/js/src/vm/JSFunction.h
@@ -945,17 +945,17 @@ JSFunction::getExtendedSlot(size_t which
     return toExtended()->extendedSlots[which];
 }
 
 namespace js {
 
 JSString* FunctionToString(JSContext* cx, HandleFunction fun, bool isToSource);
 
 template<XDRMode mode>
-bool
+XDRResult
 XDRInterpretedFunction(XDRState<mode>* xdr, HandleScope enclosingScope,
                        HandleScriptSource sourceObject, MutableHandleFunction objp);
 
 /*
  * Report an error that call.thisv is not compatible with the specified class,
  * assuming that the method (clasp->name).prototype.<name of callee function>
  * is what was called.
  */
--- a/js/src/vm/JSObject.cpp
+++ b/js/src/vm/JSObject.cpp
@@ -1392,17 +1392,17 @@ JS_InitializePropertiesFromCompatibleNat
                                                   HandleObject src)
 {
     return InitializePropertiesFromCompatibleNativeObject(cx,
                                                           dst.as<NativeObject>(),
                                                           src.as<NativeObject>());
 }
 
 template<XDRMode mode>
-bool
+XDRResult
 js::XDRObjectLiteral(XDRState<mode>* xdr, MutableHandleObject obj)
 {
     /* NB: Keep this in sync with DeepCloneObjectLiteral. */
 
     JSContext* cx = xdr->cx();
     assertSameCompartment(cx, obj);
 
     // Distinguish between objects and array classes.
@@ -1410,115 +1410,109 @@ js::XDRObjectLiteral(XDRState<mode>* xdr
     {
         if (mode == XDR_ENCODE) {
             MOZ_ASSERT(obj->is<PlainObject>() ||
                        obj->is<UnboxedPlainObject>() ||
                        obj->is<ArrayObject>());
             isArray = obj->is<ArrayObject>() ? 1 : 0;
         }
 
-        if (!xdr->codeUint32(&isArray))
-            return false;
+        MOZ_TRY(xdr->codeUint32(&isArray));
     }
 
     RootedValue tmpValue(cx), tmpIdValue(cx);
     RootedId tmpId(cx);
 
     if (isArray) {
         Rooted<GCVector<Value>> values(cx, GCVector<Value>(cx));
         if (mode == XDR_ENCODE) {
             RootedArrayObject arr(cx, &obj->as<ArrayObject>());
             if (!GetScriptArrayObjectElements(arr, &values))
-                return false;
+                return xdr->fail(JS::TranscodeResult_Throw);
         }
 
         uint32_t initialized;
         if (mode == XDR_ENCODE)
             initialized = values.length();
-        if (!xdr->codeUint32(&initialized))
-            return false;
+        MOZ_TRY(xdr->codeUint32(&initialized));
         if (mode == XDR_DECODE && !values.appendN(MagicValue(JS_ELEMENTS_HOLE), initialized))
-            return false;
+            return xdr->fail(JS::TranscodeResult_Throw);
 
         // Recursively copy dense elements.
-        for (unsigned i = 0; i < initialized; i++) {
-            if (!xdr->codeConstValue(values[i]))
-                return false;
-        }
+        for (unsigned i = 0; i < initialized; i++)
+            MOZ_TRY(xdr->codeConstValue(values[i]));
 
         uint32_t copyOnWrite;
-        if (mode == XDR_ENCODE)
+        if (mode == XDR_ENCODE) {
             copyOnWrite = obj->is<ArrayObject>() &&
                           obj->as<ArrayObject>().denseElementsAreCopyOnWrite();
-        if (!xdr->codeUint32(&copyOnWrite))
-            return false;
+        }
+        MOZ_TRY(xdr->codeUint32(&copyOnWrite));
 
         if (mode == XDR_DECODE) {
             ObjectGroup::NewArrayKind arrayKind = copyOnWrite
                                                   ? ObjectGroup::NewArrayKind::CopyOnWrite
                                                   : ObjectGroup::NewArrayKind::Normal;
             obj.set(ObjectGroup::newArrayObject(cx, values.begin(), values.length(),
                                                 TenuredObject, arrayKind));
             if (!obj)
-                return false;
+                return xdr->fail(JS::TranscodeResult_Throw);
         }
 
-        return true;
+        return Ok();
     }
 
     // Code the properties in the object.
     Rooted<IdValueVector> properties(cx, IdValueVector(cx));
     if (mode == XDR_ENCODE && !GetScriptPlainObjectProperties(obj, &properties))
-        return false;
+        return xdr->fail(JS::TranscodeResult_Throw);
 
     uint32_t nproperties = properties.length();
-    if (!xdr->codeUint32(&nproperties))
-        return false;
+    MOZ_TRY(xdr->codeUint32(&nproperties));
 
     if (mode == XDR_DECODE && !properties.appendN(IdValuePair(), nproperties))
-        return false;
+        return xdr->fail(JS::TranscodeResult_Throw);
 
     for (size_t i = 0; i < nproperties; i++) {
         if (mode == XDR_ENCODE) {
             tmpIdValue = IdToValue(properties[i].get().id);
             tmpValue = properties[i].get().value;
         }
 
-        if (!xdr->codeConstValue(&tmpIdValue) || !xdr->codeConstValue(&tmpValue))
-            return false;
+        MOZ_TRY(xdr->codeConstValue(&tmpIdValue));
+        MOZ_TRY(xdr->codeConstValue(&tmpValue));
 
         if (mode == XDR_DECODE) {
             if (!ValueToId<CanGC>(cx, tmpIdValue, &tmpId))
-                return false;
+                return xdr->fail(JS::TranscodeResult_Throw);
             properties[i].get().id = tmpId;
             properties[i].get().value = tmpValue;
         }
     }
 
     // Code whether the object is a singleton.
     uint32_t isSingleton;
     if (mode == XDR_ENCODE)
         isSingleton = obj->isSingleton() ? 1 : 0;
-    if (!xdr->codeUint32(&isSingleton))
-        return false;
+    MOZ_TRY(xdr->codeUint32(&isSingleton));
 
     if (mode == XDR_DECODE) {
         NewObjectKind newKind = isSingleton ? SingletonObject : TenuredObject;
         obj.set(ObjectGroup::newPlainObject(cx, properties.begin(), properties.length(), newKind));
         if (!obj)
-            return false;
+            return xdr->fail(JS::TranscodeResult_Throw);
     }
 
-    return true;
+    return Ok();
 }
 
-template bool
+template XDRResult
 js::XDRObjectLiteral(XDRState<XDR_ENCODE>* xdr, MutableHandleObject obj);
 
-template bool
+template XDRResult
 js::XDRObjectLiteral(XDRState<XDR_DECODE>* xdr, MutableHandleObject obj);
 
 /* static */ bool
 NativeObject::fillInAfterSwap(JSContext* cx, HandleNativeObject obj,
                               const Vector<Value>& values, void* priv)
 {
     // This object has just been swapped with some other object, and its shape
     // no longer reflects its allocated size. Correct this information and
--- a/js/src/vm/JSObject.h
+++ b/js/src/vm/JSObject.h
@@ -1248,17 +1248,17 @@ MOZ_ALWAYS_INLINE JSObject*
 ToObjectFromStack(JSContext* cx, HandleValue vp)
 {
     if (vp.isObject())
         return &vp.toObject();
     return js::ToObjectSlow(cx, vp, true);
 }
 
 template<XDRMode mode>
-bool
+XDRResult
 XDRObjectLiteral(XDRState<mode>* xdr, MutableHandleObject obj);
 
 /*
  * Report a TypeError: "so-and-so is not an object".
  * Using NotNullObject is usually less code.
  */
 extern void
 ReportNotObject(JSContext* cx, const Value& v);
--- a/js/src/vm/JSScript.cpp
+++ b/js/src/vm/JSScript.cpp
@@ -80,17 +80,17 @@ CheckScriptDataIntegrity(JSScript* scrip
     // Check that scope data - who's pointer is stored in data region - also
     // points within the data region.
     MOZ_RELEASE_ASSERT(ptr >= script->data &&
                        ptr + sa->length <= script->data + script->dataSize(),
                        "Corrupt JSScript::data");
 }
 
 template<XDRMode mode>
-bool
+XDRResult
 js::XDRScriptConst(XDRState<mode>* xdr, MutableHandleValue vp)
 {
     JSContext* cx = xdr->cx();
 
     enum ConstTag {
         SCRIPT_INT,
         SCRIPT_DOUBLE,
         SCRIPT_ATOM,
@@ -121,46 +121,42 @@ js::XDRScriptConst(XDRState<mode>* xdr, 
         } else if (vp.isMagic(JS_ELEMENTS_HOLE)) {
             tag = SCRIPT_HOLE;
         } else {
             MOZ_ASSERT(vp.isUndefined());
             tag = SCRIPT_VOID;
         }
     }
 
-    if (!xdr->codeEnum32(&tag))
-        return false;
+    MOZ_TRY(xdr->codeEnum32(&tag));
 
     switch (tag) {
       case SCRIPT_INT: {
         uint32_t i;
         if (mode == XDR_ENCODE)
             i = uint32_t(vp.toInt32());
-        if (!xdr->codeUint32(&i))
-            return false;
+        MOZ_TRY(xdr->codeUint32(&i));
         if (mode == XDR_DECODE)
             vp.set(Int32Value(int32_t(i)));
         break;
       }
       case SCRIPT_DOUBLE: {
         double d;
         if (mode == XDR_ENCODE)
             d = vp.toDouble();
-        if (!xdr->codeDouble(&d))
-            return false;
+        MOZ_TRY(xdr->codeDouble(&d));
         if (mode == XDR_DECODE)
             vp.set(DoubleValue(d));
         break;
       }
       case SCRIPT_ATOM: {
         RootedAtom atom(cx);
         if (mode == XDR_ENCODE)
             atom = &vp.toString()->asAtom();
-        if (!XDRAtom(xdr, &atom))
-            return false;
+        MOZ_TRY(XDRAtom(xdr, &atom));
         if (mode == XDR_DECODE)
             vp.set(StringValue(atom));
         break;
       }
       case SCRIPT_TRUE:
         if (mode == XDR_DECODE)
             vp.set(BooleanValue(true));
         break;
@@ -172,18 +168,17 @@ js::XDRScriptConst(XDRState<mode>* xdr, 
         if (mode == XDR_DECODE)
             vp.set(NullValue());
         break;
       case SCRIPT_OBJECT: {
         RootedObject obj(cx);
         if (mode == XDR_ENCODE)
             obj = &vp.toObject();
 
-        if (!XDRObjectLiteral(xdr, &obj))
-            return false;
+        MOZ_TRY(XDRObjectLiteral(xdr, &obj));
 
         if (mode == XDR_DECODE)
             vp.setObject(*obj);
         break;
       }
       case SCRIPT_VOID:
         if (mode == XDR_DECODE)
             vp.set(UndefinedValue());
@@ -192,57 +187,56 @@ js::XDRScriptConst(XDRState<mode>* xdr, 
         if (mode == XDR_DECODE)
             vp.setMagic(JS_ELEMENTS_HOLE);
         break;
       default:
         // Fail in debug, but only soft-fail in release
         MOZ_ASSERT(false, "Bad XDR value kind");
         return xdr->fail(JS::TranscodeResult_Failure_BadDecode);
     }
-    return true;
+    return Ok();
 }
 
-template bool
+template XDRResult
 js::XDRScriptConst(XDRState<XDR_ENCODE>*, MutableHandleValue);
 
-template bool
+template XDRResult
 js::XDRScriptConst(XDRState<XDR_DECODE>*, MutableHandleValue);
 
 // Code LazyScript's closed over bindings.
 template<XDRMode mode>
-static bool
+static XDRResult
 XDRLazyClosedOverBindings(XDRState<mode>* xdr, MutableHandle<LazyScript*> lazy)
 {
     JSContext* cx = xdr->cx();
     RootedAtom atom(cx);
     for (size_t i = 0; i < lazy->numClosedOverBindings(); i++) {
         uint8_t endOfScopeSentinel;
         if (mode == XDR_ENCODE) {
             atom = lazy->closedOverBindings()[i];
             endOfScopeSentinel = !atom;
         }
 
-        if (!xdr->codeUint8(&endOfScopeSentinel))
-            return false;
+        MOZ_TRY(xdr->codeUint8(&endOfScopeSentinel));
 
         if (endOfScopeSentinel)
             atom = nullptr;
-        else if (!XDRAtom(xdr, &atom))
-            return false;
+        else
+            MOZ_TRY(XDRAtom(xdr, &atom));
 
         if (mode == XDR_DECODE)
             lazy->closedOverBindings()[i] = atom;
     }
 
-    return true;
+    return Ok();
 }
 
 // Code the missing part needed to re-create a LazyScript from a JSScript.
 template<XDRMode mode>
-static bool
+static XDRResult
 XDRRelazificationInfo(XDRState<mode>* xdr, HandleFunction fun, HandleScript script,
                       HandleScope enclosingScope, MutableHandle<LazyScript*> lazy)
 {
     MOZ_ASSERT_IF(mode == XDR_ENCODE, script->isRelazifiable() && script->maybeLazyScript());
     MOZ_ASSERT_IF(mode == XDR_ENCODE, !lazy->numInnerFunctions());
 
     JSContext* cx = xdr->cx();
 
@@ -264,43 +258,41 @@ XDRRelazificationInfo(XDRState<mode>* xd
             MOZ_ASSERT(lineno == lazy->lineno());
             MOZ_ASSERT(column == lazy->column());
             // We can assert we have no inner functions because we don't
             // relazify scripts with inner functions.  See
             // JSFunction::createScriptForLazilyInterpretedFunction.
             MOZ_ASSERT(lazy->numInnerFunctions() == 0);
         }
 
-        if (!xdr->codeUint64(&packedFields))
-            return false;
+        MOZ_TRY(xdr->codeUint64(&packedFields));
 
         if (mode == XDR_DECODE) {
             RootedScriptSource sourceObject(cx, &script->scriptSourceUnwrap());
             lazy.set(LazyScript::Create(cx, fun, script, enclosingScope, sourceObject,
                                         packedFields, begin, end, toStringStart, lineno, column));
             if (!lazy)
-                return false;
+                return xdr->fail(JS::TranscodeResult_Throw);
 
             lazy->setToStringEnd(toStringEnd);
 
             // As opposed to XDRLazyScript, we need to restore the runtime bits
             // of the script, as we are trying to match the fact this function
             // has already been parsed and that it would need to be re-lazified.
             lazy->initRuntimeFields(packedFields);
         }
     }
 
     // Code binding names.
-    if (!XDRLazyClosedOverBindings(xdr, lazy))
-        return false;
+    MOZ_TRY(XDRLazyClosedOverBindings(xdr, lazy));
 
     // No need to do anything with inner functions, since we asserted we don't
     // have any.
 
-    return true;
+    return Ok();
 }
 
 static inline uint32_t
 FindScopeIndex(JSScript* script, Scope& scope)
 {
     ScopeArray* scopes = script->scopes();
     GCPtrScope* vector = scopes->vector;
     unsigned length = scopes->length;
@@ -314,17 +306,17 @@ FindScopeIndex(JSScript* script, Scope& 
 
 enum XDRClassKind {
     CK_RegexpObject,
     CK_JSFunction,
     CK_JSObject
 };
 
 template<XDRMode mode>
-bool
+XDRResult
 js::XDRScript(XDRState<mode>* xdr, HandleScope scriptEnclosingScope,
               HandleScriptSource sourceObjectArg, HandleFunction fun,
               MutableHandleScript scriptp)
 {
     /* NB: Keep this in sync with CopyScript. */
 
     enum ScriptBits {
         NoScriptRval,
@@ -386,18 +378,17 @@ js::XDRScript(XDRState<mode>* xdr, Handl
             {
                 return xdr->fail(JS::TranscodeResult_Failure_RunOnceNotSupported);
             }
         }
     }
 
     if (mode == XDR_ENCODE)
         length = script->length();
-    if (!xdr->codeUint32(&length))
-        return false;
+    MOZ_TRY(xdr->codeUint32(&length));
 
     if (mode == XDR_ENCODE) {
         prologueLength = script->mainOffset();
         lineno = script->lineno();
         column = script->column();
         nfixed = script->nfixed();
         nslots = script->nslots();
 
@@ -469,42 +460,30 @@ js::XDRScript(XDRState<mode>* xdr, Handl
         if (script->needsHomeObject())
             scriptBits |= (1 << NeedsHomeObject);
         if (script->isDerivedClassConstructor())
             scriptBits |= (1 << IsDerivedClassConstructor);
         if (script->isDefaultClassConstructor())
             scriptBits |= (1 << IsDefaultClassConstructor);
     }
 
-    if (!xdr->codeUint32(&prologueLength))
-        return false;
+    MOZ_TRY(xdr->codeUint32(&prologueLength));
 
     // To fuse allocations, we need lengths of all embedded arrays early.
-    if (!xdr->codeUint32(&natoms))
-        return false;
-    if (!xdr->codeUint32(&nsrcnotes))
-        return false;
-    if (!xdr->codeUint32(&nconsts))
-        return false;
-    if (!xdr->codeUint32(&nobjects))
-        return false;
-    if (!xdr->codeUint32(&nscopes))
-        return false;
-    if (!xdr->codeUint32(&ntrynotes))
-        return false;
-    if (!xdr->codeUint32(&nscopenotes))
-        return false;
-    if (!xdr->codeUint32(&nyieldoffsets))
-        return false;
-    if (!xdr->codeUint32(&nTypeSets))
-        return false;
-    if (!xdr->codeUint32(&funLength))
-        return false;
-    if (!xdr->codeUint32(&scriptBits))
-        return false;
+    MOZ_TRY(xdr->codeUint32(&natoms));
+    MOZ_TRY(xdr->codeUint32(&nsrcnotes));
+    MOZ_TRY(xdr->codeUint32(&nconsts));
+    MOZ_TRY(xdr->codeUint32(&nobjects));
+    MOZ_TRY(xdr->codeUint32(&nscopes));
+    MOZ_TRY(xdr->codeUint32(&ntrynotes));
+    MOZ_TRY(xdr->codeUint32(&nscopenotes));
+    MOZ_TRY(xdr->codeUint32(&nyieldoffsets));
+    MOZ_TRY(xdr->codeUint32(&nTypeSets));
+    MOZ_TRY(xdr->codeUint32(&funLength));
+    MOZ_TRY(xdr->codeUint32(&scriptBits));
 
     MOZ_ASSERT(!!(scriptBits & (1 << OwnSource)) == !sourceObjectArg);
     RootedScriptSource sourceObject(cx, sourceObjectArg);
 
     if (mode == XDR_DECODE) {
         // When loading from the bytecode cache, we get the CompileOptions from
         // the document. If the noScriptRval or selfHostingMode flag doesn't
         // match, we should fail. This only applies to the top-level and not
@@ -521,60 +500,60 @@ js::XDRScript(XDRState<mode>* xdr, Handl
             options.emplace(xdr->cx());
             (*options).setNoScriptRval(!!(scriptBits & (1 << NoScriptRval)))
                       .setSelfHostingMode(!!(scriptBits & (1 << SelfHosted)));
         }
 
         if (scriptBits & (1 << OwnSource)) {
             ScriptSource* ss = cx->new_<ScriptSource>();
             if (!ss)
-                return false;
+                return xdr->fail(JS::TranscodeResult_Throw);
             ScriptSourceHolder ssHolder(ss);
 
             /*
              * We use this CompileOptions only to initialize the
              * ScriptSourceObject. Most CompileOptions fields aren't used by
              * ScriptSourceObject, and those that are (element; elementAttributeName)
              * aren't preserved by XDR. So this can be simple.
              */
             if (!ss->initFromOptions(cx, *options))
-                return false;
+                return xdr->fail(JS::TranscodeResult_Throw);
 
             sourceObject = ScriptSourceObject::create(cx, ss);
             if (!sourceObject)
-                return false;
+                return xdr->fail(JS::TranscodeResult_Throw);
 
             if (xdr->hasScriptSourceObjectOut()) {
                 // When the ScriptSourceObjectOut is provided by ParseTask, it
                 // is stored in a location which is traced by the GC.
                 *xdr->scriptSourceObjectOut() = sourceObject;
             } else if (!ScriptSourceObject::initFromOptions(cx, sourceObject, *options)) {
-                return false;
+                return xdr->fail(JS::TranscodeResult_Throw);
             }
         }
 
         script = JSScript::Create(cx, *options, sourceObject, 0, 0, 0, 0);
         if (!script)
-            return false;
+            return xdr->fail(JS::TranscodeResult_Throw);
 
         // Set the script in its function now so that inner scripts to be
         // decoded may iterate the static scope chain.
         if (fun)
             fun->initScript(script);
     } else {
         // When encoding, we do not mutate any of the JSScript or LazyScript, so
         // we can safely unwrap it here.
         sourceObject = &script->scriptSourceUnwrap();
     }
 
     if (mode == XDR_DECODE) {
         if (!JSScript::partiallyInit(cx, script, nscopes, nconsts, nobjects, ntrynotes,
                                      nscopenotes, nyieldoffsets, nTypeSets))
         {
-            return false;
+            return xdr->fail(JS::TranscodeResult_Throw);
         }
 
         MOZ_ASSERT(!script->mainOffset());
         script->mainOffset_ = prologueLength;
         script->funLength_ = funLength;
 
         scriptp.set(script);
 
@@ -620,91 +599,74 @@ js::XDRScript(XDRState<mode>* xdr, Handl
             script->setHasRest();
         if (scriptBits & (1 << IsExprBody))
             script->setIsExprBody();
     }
 
     JS_STATIC_ASSERT(sizeof(jsbytecode) == 1);
     JS_STATIC_ASSERT(sizeof(jssrcnote) == 1);
 
-    if (scriptBits & (1 << OwnSource)) {
-        if (!sourceObject->source()->performXDR<mode>(xdr))
-            return false;
-    }
-    if (!xdr->codeUint32(&script->sourceStart_))
-        return false;
-    if (!xdr->codeUint32(&script->sourceEnd_))
-        return false;
-    if (!xdr->codeUint32(&script->toStringStart_))
-        return false;
-    if (!xdr->codeUint32(&script->toStringEnd_))
-        return false;
-
-    if (!xdr->codeUint32(&lineno) ||
-        !xdr->codeUint32(&column) ||
-        !xdr->codeUint32(&nfixed) ||
-        !xdr->codeUint32(&nslots))
-    {
-        return false;
-    }
-
-    if (!xdr->codeUint32(&bodyScopeIndex))
-        return false;
+    if (scriptBits & (1 << OwnSource))
+        MOZ_TRY(sourceObject->source()->performXDR<mode>(xdr));
+    MOZ_TRY(xdr->codeUint32(&script->sourceStart_));
+    MOZ_TRY(xdr->codeUint32(&script->sourceEnd_));
+    MOZ_TRY(xdr->codeUint32(&script->toStringStart_));
+    MOZ_TRY(xdr->codeUint32(&script->toStringEnd_));
+    MOZ_TRY(xdr->codeUint32(&lineno));
+    MOZ_TRY(xdr->codeUint32(&column));
+    MOZ_TRY(xdr->codeUint32(&nfixed));
+    MOZ_TRY(xdr->codeUint32(&nslots));
+    MOZ_TRY(xdr->codeUint32(&bodyScopeIndex));
 
     if (mode == XDR_DECODE) {
         script->lineno_ = lineno;
         script->column_ = column;
         script->nfixed_ = nfixed;
         script->nslots_ = nslots;
         script->bodyScopeIndex_ = bodyScopeIndex;
     }
 
     if (mode == XDR_DECODE) {
-        if (!script->createScriptData(cx, length, nsrcnotes, natoms)) {
-            return false;
-        }
+        if (!script->createScriptData(cx, length, nsrcnotes, natoms))
+            return xdr->fail(JS::TranscodeResult_Throw);
     }
 
     auto scriptDataGuard = mozilla::MakeScopeExit([&] {
         if (mode == XDR_DECODE)
             script->freeScriptData();
     });
 
     jsbytecode* code = script->code();
-    if (!xdr->codeBytes(code, length) || !xdr->codeBytes(code + length, nsrcnotes)) {
-        return false;
-    }
+    MOZ_TRY(xdr->codeBytes(code, length));
+    MOZ_TRY(xdr->codeBytes(code + length, nsrcnotes));
 
     for (i = 0; i != natoms; ++i) {
         if (mode == XDR_DECODE) {
             RootedAtom tmp(cx);
-            if (!XDRAtom(xdr, &tmp))
-                return false;
+            MOZ_TRY(XDRAtom(xdr, &tmp));
             script->atoms()[i].init(tmp);
         } else {
             RootedAtom tmp(cx, script->atoms()[i]);
-            if (!XDRAtom(xdr, &tmp))
-                return false;
+            MOZ_TRY(XDRAtom(xdr, &tmp));
         }
     }
 
     scriptDataGuard.release();
     if (mode == XDR_DECODE) {
         if (!script->shareScriptData(cx))
-            return false;
+            return xdr->fail(JS::TranscodeResult_Throw);
     }
 
     if (nconsts) {
         GCPtrValue* vector = script->consts()->vector;
         RootedValue val(cx);
         for (i = 0; i != nconsts; ++i) {
             if (mode == XDR_ENCODE)
                 val = vector[i];
-            if (!XDRScriptConst(xdr, &val))
-                return false;
+            MOZ_TRY(XDRScriptConst(xdr, &val));
             if (mode == XDR_DECODE)
                 vector[i].init(val);
         }
     }
 
     {
         MOZ_ASSERT(nscopes != 0);
         GCPtrScope* vector = script->scopes()->vector;
@@ -715,76 +677,69 @@ js::XDRScript(XDRState<mode>* xdr, Handl
         for (i = 0; i != nscopes; ++i) {
             if (mode == XDR_ENCODE) {
                 scope = vector[i];
                 scopeKind = scope->kind();
             } else {
                 scope = nullptr;
             }
 
-            if (!xdr->codeEnum32(&scopeKind))
-                return false;
+            MOZ_TRY(xdr->codeEnum32(&scopeKind));
 
             if (mode == XDR_ENCODE) {
                 if (i == 0) {
                     enclosingScopeIndex = UINT32_MAX;
                 } else {
                     MOZ_ASSERT(scope->enclosing());
                     enclosingScopeIndex = FindScopeIndex(script, *scope->enclosing());
                 }
             }
 
-            if (!xdr->codeUint32(&enclosingScopeIndex))
-                return false;
+            MOZ_TRY(xdr->codeUint32(&enclosingScopeIndex));
 
             if (mode == XDR_DECODE) {
                 if (i == 0) {
                     MOZ_ASSERT(enclosingScopeIndex == UINT32_MAX);
                     enclosing = scriptEnclosingScope;
                 } else {
                     MOZ_ASSERT(enclosingScopeIndex < i);
                     enclosing = vector[enclosingScopeIndex];
                 }
             }
 
             switch (scopeKind) {
               case ScopeKind::Function:
                 MOZ_ASSERT(i == script->bodyScopeIndex());
-                if (!FunctionScope::XDR(xdr, fun, enclosing, &scope))
-                    return false;
+                MOZ_TRY(FunctionScope::XDR(xdr, fun, enclosing, &scope));
                 break;
               case ScopeKind::FunctionBodyVar:
               case ScopeKind::ParameterExpressionVar:
-                if (!VarScope::XDR(xdr, scopeKind, enclosing, &scope))
-                    return false;
+                MOZ_TRY(VarScope::XDR(xdr, scopeKind, enclosing, &scope));
                 break;
               case ScopeKind::Lexical:
               case ScopeKind::SimpleCatch:
               case ScopeKind::Catch:
               case ScopeKind::NamedLambda:
               case ScopeKind::StrictNamedLambda:
-                if (!LexicalScope::XDR(xdr, scopeKind, enclosing, &scope))
-                    return false;
+                MOZ_TRY(LexicalScope::XDR(xdr, scopeKind, enclosing, &scope));
                 break;
               case ScopeKind::With:
                 if (mode == XDR_DECODE) {
                     scope = WithScope::create(cx, enclosing);
                     if (!scope)
-                        return false;
+                        return xdr->fail(JS::TranscodeResult_Throw);
                 }
                 break;
               case ScopeKind::Eval:
               case ScopeKind::StrictEval:
-                if (!EvalScope::XDR(xdr, scopeKind, enclosing, &scope))
-                    return false;
+                MOZ_TRY(EvalScope::XDR(xdr, scopeKind, enclosing, &scope));
                 break;
               case ScopeKind::Global:
               case ScopeKind::NonSyntactic:
-                if (!GlobalScope::XDR(xdr, scopeKind, &scope))
-                    return false;
+                MOZ_TRY(GlobalScope::XDR(xdr, scopeKind, &scope));
                 break;
               case ScopeKind::Module:
               case ScopeKind::WasmInstance:
                 MOZ_CRASH("NYI");
                 break;
               case ScopeKind::WasmFunction:
                 MOZ_CRASH("wasm functions cannot be nested in JSScripts");
                 break;
@@ -795,18 +750,17 @@ js::XDRScript(XDRState<mode>* xdr, Handl
             }
 
             if (mode == XDR_DECODE)
                 vector[i].init(scope);
         }
 
         // Verify marker to detect data corruption after decoding scope data. A
         // mismatch here indicates we will almost certainly crash in release.
-        if (!xdr->codeMarker(0x48922BAB))
-            return false;
+        MOZ_TRY(xdr->codeMarker(0x48922BAB));
     }
 
     /*
      * Here looping from 0-to-length to xdr objects is essential to ensure that
      * all references to enclosing blocks (via FindScopeIndex below) happen
      * after the enclosing block has been XDR'd.
      */
     for (i = 0; i != nobjects; ++i) {
@@ -820,26 +774,24 @@ js::XDRScript(XDRState<mode>* xdr, Handl
             else if (obj->is<JSFunction>())
                 classk = CK_JSFunction;
             else if (obj->is<PlainObject>() || obj->is<ArrayObject>())
                 classk = CK_JSObject;
             else
                 MOZ_CRASH("Cannot encode this class of object.");
         }
 
-        if (!xdr->codeEnum32(&classk))
-            return false;
+        MOZ_TRY(xdr->codeEnum32(&classk));
 
         switch (classk) {
           case CK_RegexpObject: {
             Rooted<RegExpObject*> regexp(cx);
             if (mode == XDR_ENCODE)
                 regexp = &(*objp)->as<RegExpObject>();
-            if (!XDRScriptRegExpObject(xdr, &regexp))
-                return false;
+            MOZ_TRY(XDRScriptRegExpObject(xdr, &regexp));
             if (mode == XDR_DECODE)
                 *objp = regexp;
             break;
           }
 
           case CK_JSFunction: {
             /* Code the nested function's enclosing scope. */
             uint32_t funEnclosingScopeIndex = 0;
@@ -854,123 +806,112 @@ js::XDRScript(XDRState<mode>* xdr, Handl
                 } else {
                     MOZ_ASSERT(function->isAsmJSNative());
                     return xdr->fail(JS::TranscodeResult_Failure_AsmJSNotSupported);
                 }
 
                 funEnclosingScopeIndex = FindScopeIndex(script, *funEnclosingScope);
             }
 
-            if (!xdr->codeUint32(&funEnclosingScopeIndex))
-                return false;
+            MOZ_TRY(xdr->codeUint32(&funEnclosingScopeIndex));
 
             if (mode == XDR_DECODE) {
                 MOZ_ASSERT(funEnclosingScopeIndex < script->scopes()->length);
                 funEnclosingScope = script->scopes()->vector[funEnclosingScopeIndex];
             }
 
             // Code nested function and script.
             RootedFunction tmp(cx);
             if (mode == XDR_ENCODE)
                 tmp = &(*objp)->as<JSFunction>();
-            if (!XDRInterpretedFunction(xdr, funEnclosingScope, sourceObject, &tmp))
-                return false;
+            MOZ_TRY(XDRInterpretedFunction(xdr, funEnclosingScope, sourceObject, &tmp));
             *objp = tmp;
             break;
           }
 
           case CK_JSObject: {
             /* Code object literal. */
             RootedObject tmp(cx, *objp);
-            if (!XDRObjectLiteral(xdr, &tmp))
-                return false;
+            MOZ_TRY(XDRObjectLiteral(xdr, &tmp));
             *objp = tmp;
             break;
           }
 
           default: {
             // Fail in debug, but only soft-fail in release
             MOZ_ASSERT(false, "Bad XDR class kind");
             return xdr->fail(JS::TranscodeResult_Failure_BadDecode);
           }
         }
     }
 
     // Verify marker to detect data corruption after decoding object data. A
     // mismatch here indicates we will almost certainly crash in release.
-    if (!xdr->codeMarker(0xF83B989A))
-        return false;
+    MOZ_TRY(xdr->codeMarker(0xF83B989A));
 
     if (ntrynotes != 0) {
         JSTryNote* tnfirst = script->trynotes()->vector;
         MOZ_ASSERT(script->trynotes()->length == ntrynotes);
         JSTryNote* tn = tnfirst + ntrynotes;
         do {
             --tn;
-            if (!xdr->codeUint8(&tn->kind) ||
-                !xdr->codeUint32(&tn->stackDepth) ||
-                !xdr->codeUint32(&tn->start) ||
-                !xdr->codeUint32(&tn->length)) {
-                return false;
-            }
+            MOZ_TRY(xdr->codeUint8(&tn->kind));
+            MOZ_TRY(xdr->codeUint32(&tn->stackDepth));
+            MOZ_TRY(xdr->codeUint32(&tn->start));
+            MOZ_TRY(xdr->codeUint32(&tn->length));
         } while (tn != tnfirst);
     }
 
     for (i = 0; i < nscopenotes; ++i) {
         ScopeNote* note = &script->scopeNotes()->vector[i];
-        if (!xdr->codeUint32(&note->index) ||
-            !xdr->codeUint32(&note->start) ||
-            !xdr->codeUint32(&note->length) ||
-            !xdr->codeUint32(&note->parent))
-        {
-            return false;
-        }
+        MOZ_TRY(xdr->codeUint32(&note->index));
+        MOZ_TRY(xdr->codeUint32(&note->start));
+        MOZ_TRY(xdr->codeUint32(&note->length));
+        MOZ_TRY(xdr->codeUint32(&note->parent));
     }
 
     for (i = 0; i < nyieldoffsets; ++i) {
         uint32_t* offset = &script->yieldAndAwaitOffsets()[i];
-        if (!xdr->codeUint32(offset))
-            return false;
+        MOZ_TRY(xdr->codeUint32(offset));
     }
 
     if (scriptBits & (1 << HasLazyScript)) {
         Rooted<LazyScript*> lazy(cx);
         if (mode == XDR_ENCODE)
             lazy = script->maybeLazyScript();
 
-        if (!XDRRelazificationInfo(xdr, fun, script, scriptEnclosingScope, &lazy))
-            return false;
+        MOZ_TRY(XDRRelazificationInfo(xdr, fun, script, scriptEnclosingScope, &lazy));
 
         if (mode == XDR_DECODE)
             script->setLazyScript(lazy);
     }
 
     if (mode == XDR_DECODE) {
         CheckScriptDataIntegrity(script);
 
         scriptp.set(script);
 
         /* see BytecodeEmitter::tellDebuggerAboutCompiledScript */
         if (!fun && !cx->helperThread())
             Debugger::onNewScript(cx, script);
     }
 
-    return true;
+    return Ok();
 }
 
-template bool
+template XDRResult
 js::XDRScript(XDRState<XDR_ENCODE>*, HandleScope, HandleScriptSource, HandleFunction,
               MutableHandleScript);
 
-template bool
+template XDRResult
 js::XDRScript(XDRState<XDR_DECODE>*, HandleScope, HandleScriptSource, HandleFunction,
               MutableHandleScript);
 
 template<XDRMode mode>
-bool
+XDRResult
 js::XDRLazyScript(XDRState<mode>* xdr, HandleScope enclosingScope,
                   HandleScriptSource sourceObject, HandleFunction fun,
                   MutableHandle<LazyScript*> lazy)
 {
     JSContext* cx = xdr->cx();
 
     {
         uint32_t begin;
@@ -992,64 +933,61 @@ js::XDRLazyScript(XDRState<mode>* xdr, H
             end = lazy->end();
             toStringStart = lazy->toStringStart();
             toStringEnd = lazy->toStringEnd();
             lineno = lazy->lineno();
             column = lazy->column();
             packedFields = lazy->packedFields();
         }
 
-        if (!xdr->codeUint32(&begin) || !xdr->codeUint32(&end) ||
-            !xdr->codeUint32(&toStringStart) ||
-            !xdr->codeUint32(&toStringEnd) ||
-            !xdr->codeUint32(&lineno) || !xdr->codeUint32(&column) ||
-            !xdr->codeUint64(&packedFields))
-        {
-            return false;
-        }
+        MOZ_TRY(xdr->codeUint32(&begin));
+        MOZ_TRY(xdr->codeUint32(&end));
+        MOZ_TRY(xdr->codeUint32(&toStringStart));
+        MOZ_TRY(xdr->codeUint32(&toStringEnd));
+        MOZ_TRY(xdr->codeUint32(&lineno));
+        MOZ_TRY(xdr->codeUint32(&column));
+        MOZ_TRY(xdr->codeUint64(&packedFields));
 
         if (mode == XDR_DECODE) {
             lazy.set(LazyScript::Create(cx, fun, nullptr, enclosingScope, sourceObject,
                                         packedFields, begin, end, toStringStart, lineno, column));
             if (!lazy)
-                return false;
+                return xdr->fail(JS::TranscodeResult_Throw);
             lazy->setToStringEnd(toStringEnd);
             fun->initLazyScript(lazy);
         }
     }
 
     // Code closed-over bindings.
-    if (!XDRLazyClosedOverBindings(xdr, lazy))
-        return false;
+    MOZ_TRY(XDRLazyClosedOverBindings(xdr, lazy));
 
     // Code inner functions.
     {
         RootedFunction func(cx);
         GCPtrFunction* innerFunctions = lazy->innerFunctions();
         size_t numInnerFunctions = lazy->numInnerFunctions();
         for (size_t i = 0; i < numInnerFunctions; i++) {
             if (mode == XDR_ENCODE)
                 func = innerFunctions[i];
 
-            if (!XDRInterpretedFunction(xdr, nullptr, nullptr, &func))
-                return false;
+            MOZ_TRY(XDRInterpretedFunction(xdr, nullptr, nullptr, &func));
 
             if (mode == XDR_DECODE)
                 innerFunctions[i] = func;
         }
     }
 
-    return true;
+    return Ok();
 }
 
-template bool
+template XDRResult
 js::XDRLazyScript(XDRState<XDR_ENCODE>*, HandleScope, HandleScriptSource,
                   HandleFunction, MutableHandle<LazyScript*>);
 
-template bool
+template XDRResult
 js::XDRLazyScript(XDRState<XDR_DECODE>*, HandleScope, HandleScriptSource,
                   HandleFunction, MutableHandle<LazyScript*>);
 
 void
 JSScript::setSourceObject(JSObject* object)
 {
     MOZ_ASSERT(compartment() == object->compartment());
     sourceObject_ = object;
@@ -2098,20 +2036,21 @@ ScriptSource::xdrEncodeTopLevel(JSContex
     });
 
     if (!xdrEncoder_->init()) {
         ReportOutOfMemory(cx);
         return false;
     }
 
     RootedScript s(cx, script);
-    if (!xdrEncoder_->codeScript(&s)) {
+    XDRResult res = xdrEncoder_->codeScript(&s);
+    if (res.isErr()) {
         // On encoding failure, let failureCase destroy encoder and return true
         // to avoid failing any currently executing script.
-        if (xdrEncoder_->resultCode() & JS::TranscodeResult_Failure)
+        if (res.unwrapErr() & JS::TranscodeResult_Failure)
             return true;
 
         return false;
     }
 
     failureCase.release();
     return true;
 }
@@ -2121,22 +2060,22 @@ ScriptSource::xdrEncodeFunction(JSContex
 {
     MOZ_ASSERT(sourceObject->source() == this);
     MOZ_ASSERT(hasEncoder());
     auto failureCase = mozilla::MakeScopeExit([&] {
         xdrEncoder_.reset(nullptr);
     });
 
     RootedFunction f(cx, fun);
-    if (!xdrEncoder_->codeFunction(&f, sourceObject)) {
+    XDRResult res = xdrEncoder_->codeFunction(&f, sourceObject);
+    if (res.isErr()) {
         // On encoding failure, let failureCase destroy encoder and return true
         // to avoid failing any currently executing script.
-        if (xdrEncoder_->resultCode() & JS::TranscodeResult_Failure)
+        if (res.unwrapErr() & JS::TranscodeResult_Failure)
             return true;
-
         return false;
     }
 
     failureCase.release();
     return true;
 }
 
 bool
@@ -2144,23 +2083,22 @@ ScriptSource::xdrFinalizeEncoder(JS::Tra
 {
     if (!hasEncoder())
         return false;
 
     auto cleanup = mozilla::MakeScopeExit([&] {
         xdrEncoder_.reset(nullptr);
     });
 
-    if (!xdrEncoder_->linearize(buffer))
-        return false;
-    return true;
+    XDRResult res = xdrEncoder_->linearize(buffer);
+    return res.isOk();
 }
 
 template<XDRMode mode>
-bool
+XDRResult
 ScriptSource::performXDR(XDRState<mode>* xdr)
 {
     struct CompressedLengthMatcher
     {
         size_t match(Uncompressed&) {
             return 0;
         }
 
@@ -2186,126 +2124,115 @@ ScriptSource::performXDR(XDRState<mode>*
 
         void* match(Missing&) {
             MOZ_CRASH("Missing source data in ScriptSource::performXDR");
             return nullptr;
         }
     };
 
     uint8_t hasSource = hasSourceData();
-    if (!xdr->codeUint8(&hasSource))
-        return false;
+    MOZ_TRY(xdr->codeUint8(&hasSource));
 
     uint8_t retrievable = sourceRetrievable_;
-    if (!xdr->codeUint8(&retrievable))
-        return false;
+    MOZ_TRY(xdr->codeUint8(&retrievable));
     sourceRetrievable_ = retrievable;
 
     if (hasSource && !sourceRetrievable_) {
         uint32_t len = 0;
         if (mode == XDR_ENCODE)
             len = length();
-        if (!xdr->codeUint32(&len))
-            return false;
+        MOZ_TRY(xdr->codeUint32(&len));
 
         uint32_t compressedLength;
         if (mode == XDR_ENCODE) {
             CompressedLengthMatcher m;
             compressedLength = data.match(m);
         }
-        if (!xdr->codeUint32(&compressedLength))
-            return false;
+        MOZ_TRY(xdr->codeUint32(&compressedLength));
 
         size_t byteLen = compressedLength ? compressedLength : (len * sizeof(char16_t));
         if (mode == XDR_DECODE) {
-            uint8_t* p = xdr->cx()->template pod_malloc<uint8_t>(Max<size_t>(byteLen, 1));
-            if (!p || !xdr->codeBytes(p, byteLen)) {
-                js_free(p);
-                return false;
-            }
+            mozilla::UniquePtr<char[], JS::FreePolicy> bytes(
+                xdr->cx()->template pod_malloc<char>(Max<size_t>(byteLen, 1)));
+            if (!bytes)
+                return xdr->fail(JS::TranscodeResult_Throw);
+            MOZ_TRY(xdr->codeBytes(bytes.get(), byteLen));
 
             if (compressedLength) {
-                mozilla::UniquePtr<char[], JS::FreePolicy> compressedSource(
-                    reinterpret_cast<char*>(p));
-                if (!setCompressedSource(xdr->cx(), mozilla::Move(compressedSource), byteLen, len))
-                    return false;
+                if (!setCompressedSource(xdr->cx(), mozilla::Move(bytes), byteLen, len))
+                    return xdr->fail(JS::TranscodeResult_Throw);
             } else {
                 mozilla::UniquePtr<char16_t[], JS::FreePolicy> source(
-                    reinterpret_cast<char16_t*>(p));
+                    reinterpret_cast<char16_t*>(bytes.release()));
                 if (!setSource(xdr->cx(), mozilla::Move(source), len))
-                    return false;
+                    return xdr->fail(JS::TranscodeResult_Throw);
             }
         } else {
             RawDataMatcher rdm;
             void* p = data.match(rdm);
-            if (!xdr->codeBytes(p, byteLen))
-                return false;
+            MOZ_TRY(xdr->codeBytes(p, byteLen));
         }
     }
 
     uint8_t haveSourceMap = hasSourceMapURL();
-    if (!xdr->codeUint8(&haveSourceMap))
-        return false;
+    MOZ_TRY(xdr->codeUint8(&haveSourceMap));
 
     if (haveSourceMap) {
         uint32_t sourceMapURLLen = (mode == XDR_DECODE) ? 0 : js_strlen(sourceMapURL_.get());
-        if (!xdr->codeUint32(&sourceMapURLLen))
-            return false;
+        MOZ_TRY(xdr->codeUint32(&sourceMapURLLen));
 
         if (mode == XDR_DECODE) {
             sourceMapURL_ = xdr->cx()->template make_pod_array<char16_t>(sourceMapURLLen + 1);
             if (!sourceMapURL_)
-                return false;
+                return xdr->fail(JS::TranscodeResult_Throw);
         }
-        if (!xdr->codeChars(sourceMapURL_.get(), sourceMapURLLen)) {
+        auto guard = mozilla::MakeScopeExit([&] {
             if (mode == XDR_DECODE)
                 sourceMapURL_ = nullptr;
-            return false;
-        }
+        });
+        MOZ_TRY(xdr->codeChars(sourceMapURL_.get(), sourceMapURLLen));
+        guard.release();
         sourceMapURL_[sourceMapURLLen] = '\0';
     }
 
     uint8_t haveDisplayURL = hasDisplayURL();
-    if (!xdr->codeUint8(&haveDisplayURL))
-        return false;
+    MOZ_TRY(xdr->codeUint8(&haveDisplayURL));
 
     if (haveDisplayURL) {
         uint32_t displayURLLen = (mode == XDR_DECODE) ? 0 : js_strlen(displayURL_.get());
-        if (!xdr->codeUint32(&displayURLLen))
-            return false;
+        MOZ_TRY(xdr->codeUint32(&displayURLLen));
 
         if (mode == XDR_DECODE) {
             displayURL_ = xdr->cx()->template make_pod_array<char16_t>(displayURLLen + 1);
             if (!displayURL_)
-                return false;
+                return xdr->fail(JS::TranscodeResult_Throw);
         }
-        if (!xdr->codeChars(displayURL_.get(), displayURLLen)) {
+        auto guard = mozilla::MakeScopeExit([&] {
             if (mode == XDR_DECODE)
                 displayURL_ = nullptr;
-            return false;
-        }
+        });
+        MOZ_TRY(xdr->codeChars(displayURL_.get(), displayURLLen));
+        guard.release();
         displayURL_[displayURLLen] = '\0';
     }
 
     uint8_t haveFilename = !!filename_;
-    if (!xdr->codeUint8(&haveFilename))
-        return false;
+    MOZ_TRY(xdr->codeUint8(&haveFilename));
 
     if (haveFilename) {
         const char* fn = filename();
-        if (!xdr->codeCString(&fn))
-            return false;
+        MOZ_TRY(xdr->codeCString(&fn));
         // Note: If the decoder has an option, then the filename is defined by
         // the CompileOption from the document.
         MOZ_ASSERT_IF(mode == XDR_DECODE && xdr->hasOptions(), filename());
         if (mode == XDR_DECODE && !xdr->hasOptions() && !setFilename(xdr->cx(), fn))
-            return false;
+            return xdr->fail(JS::TranscodeResult_Throw);
     }
 
-    return true;
+    return Ok();
 }
 
 // Format and return a cx->zone()->pod_malloc'ed URL for a generated script like:
 //   {filename} line {lineno} > {introducer}
 // For example:
 //   foo.js line 7 > eval
 // indicating code compiled by the call to 'eval' on line 7 of foo.js.
 static char*
--- a/js/src/vm/JSScript.h
+++ b/js/src/vm/JSScript.h
@@ -592,17 +592,17 @@ class ScriptSource
     MOZ_MUST_USE bool setCompressedSource(JSContext* cx,
                                           UniqueChars&& raw,
                                           size_t rawLength,
                                           size_t sourceLength);
     void setCompressedSource(SharedImmutableString&& raw, size_t sourceLength);
 
     // XDR handling
     template <XDRMode mode>
-    MOZ_MUST_USE bool performXDR(XDRState<mode>* xdr);
+    MOZ_MUST_USE XDRResult performXDR(XDRState<mode>* xdr);
 
     MOZ_MUST_USE bool setFilename(JSContext* cx, const char* filename);
     const char* introducerFilename() const {
         return introducerFilename_ ? introducerFilename_.get() : filename_.get();
     }
     bool hasIntroductionType() const {
         return introductionType_;
     }
@@ -760,30 +760,30 @@ enum class GeneratorKind : bool { NotGen
 enum class FunctionAsyncKind : bool { SyncFunction, AsyncFunction };
 
 /*
  * NB: after a successful XDR_DECODE, XDRScript callers must do any required
  * subsequent set-up of owning function or script object and then call
  * CallNewScriptHook.
  */
 template<XDRMode mode>
-bool
+XDRResult
 XDRScript(XDRState<mode>* xdr, HandleScope enclosingScope, HandleScriptSource sourceObject,
           HandleFunction fun, MutableHandleScript scriptp);
 
 template<XDRMode mode>
-bool
+XDRResult
 XDRLazyScript(XDRState<mode>* xdr, HandleScope enclosingScope, HandleScriptSource sourceObject,
               HandleFunction fun, MutableHandle<LazyScript*> lazy);
 
 /*
  * Code any constant value.
  */
 template<XDRMode mode>
-bool
+XDRResult
 XDRScriptConst(XDRState<mode>* xdr, MutableHandleValue vp);
 
 /*
  * Common data that can be shared between many scripts in a single runtime.
  */
 class SharedScriptData
 {
     // This class is reference counted as follows: each pointer from a JSScript
@@ -885,17 +885,17 @@ extern void
 FreeScriptData(JSRuntime* rt);
 
 } /* namespace js */
 
 class JSScript : public js::gc::TenuredCell
 {
     template <js::XDRMode mode>
     friend
-    bool
+    js::XDRResult
     js::XDRScript(js::XDRState<mode>* xdr, js::HandleScope enclosingScope,
                   js::HandleScriptSource sourceObject, js::HandleFunction fun,
                   js::MutableHandleScript scriptp);
 
     friend bool
     js::detail::CopyScript(JSContext* cx, js::HandleScript src, js::HandleScript dst,
                            js::MutableHandle<JS::GCVector<js::Scope*>> scopes);
 
--- a/js/src/vm/RegExpObject.cpp
+++ b/js/src/vm/RegExpObject.cpp
@@ -1427,47 +1427,47 @@ js::ParseRegExpFlags(JSContext* cx, JSSt
                                          JSMSG_BAD_REGEXP_FLAG, utf8.get());
         return false;
     }
 
     return true;
 }
 
 template<XDRMode mode>
-bool
+XDRResult
 js::XDRScriptRegExpObject(XDRState<mode>* xdr, MutableHandle<RegExpObject*> objp)
 {
     /* NB: Keep this in sync with CloneScriptRegExpObject. */
 
     RootedAtom source(xdr->cx());
     uint32_t flagsword = 0;
 
     if (mode == XDR_ENCODE) {
         MOZ_ASSERT(objp);
         RegExpObject& reobj = *objp;
         source = reobj.getSource();
         flagsword = reobj.getFlags();
     }
-    if (!XDRAtom(xdr, &source) || !xdr->codeUint32(&flagsword))
-        return false;
+    MOZ_TRY(XDRAtom(xdr, &source));
+    MOZ_TRY(xdr->codeUint32(&flagsword));
     if (mode == XDR_DECODE) {
         RegExpObject* reobj = RegExpObject::create(xdr->cx(), source, RegExpFlag(flagsword),
                                                    xdr->lifoAlloc(), TenuredObject);
         if (!reobj)
-            return false;
+            return xdr->fail(JS::TranscodeResult_Throw);
 
         objp.set(reobj);
     }
-    return true;
+    return Ok();
 }
 
-template bool
+template XDRResult
 js::XDRScriptRegExpObject(XDRState<XDR_ENCODE>* xdr, MutableHandle<RegExpObject*> objp);
 
-template bool
+template XDRResult
 js::XDRScriptRegExpObject(XDRState<XDR_DECODE>* xdr, MutableHandle<RegExpObject*> objp);
 
 JSObject*
 js::CloneScriptRegExpObject(JSContext* cx, RegExpObject& reobj)
 {
     /* NB: Keep this in sync with XDRScriptRegExpObject. */
 
     RootedAtom source(cx, reobj.getSource());
--- a/js/src/vm/RegExpObject.h
+++ b/js/src/vm/RegExpObject.h
@@ -206,17 +206,17 @@ RegExpToShared(JSContext* cx, HandleObje
 {
     if (obj->is<RegExpObject>())
         return RegExpObject::getShared(cx, obj.as<RegExpObject>());
 
     return Proxy::regexp_toShared(cx, obj);
 }
 
 template<XDRMode mode>
-bool
+XDRResult
 XDRScriptRegExpObject(XDRState<mode>* xdr, MutableHandle<RegExpObject*> objp);
 
 extern JSObject*
 CloneScriptRegExpObject(JSContext* cx, RegExpObject& re);
 
 /* Escape all slashes and newlines in the given string. */
 extern JSAtom*
 EscapeRegExpPattern(JSContext* cx, HandleAtom src);
--- a/js/src/vm/Scope.cpp
+++ b/js/src/vm/Scope.cpp
@@ -208,100 +208,97 @@ NewEmptyScopeData(JSContext* cx, uint32_
     if (!bytes)
         ReportOutOfMemory(cx);
     auto data = reinterpret_cast<typename ConcreteScope::Data*>(bytes);
     if (data)
         new (data) typename ConcreteScope::Data();
     return UniquePtr<typename ConcreteScope::Data>(data);
 }
 
-static bool
+static XDRResult
 XDRBindingName(XDRState<XDR_ENCODE>* xdr, BindingName* bindingName)
 {
     JSContext* cx = xdr->cx();
 
     RootedAtom atom(cx, bindingName->name());
     bool hasAtom = !!atom;
 
     uint8_t u8 = uint8_t(hasAtom << 1) | uint8_t(bindingName->closedOver());
-    if (!xdr->codeUint8(&u8))
-        return false;
+    MOZ_TRY(xdr->codeUint8(&u8));
 
-    if (atom && !XDRAtom(xdr, &atom))
-        return false;
+    if (atom)
+        MOZ_TRY(XDRAtom(xdr, &atom));
 
-    return true;
+    return Ok();
 }
 
-static bool
+static XDRResult
 XDRBindingName(XDRState<XDR_DECODE>* xdr, BindingName* bindingName)
 {
     JSContext* cx = xdr->cx();
 
     uint8_t u8;
-    if (!xdr->codeUint8(&u8))
-        return false;
+    MOZ_TRY(xdr->codeUint8(&u8));
 
     bool closedOver = u8 & 1;
     bool hasAtom = u8 >> 1;
 
     RootedAtom atom(cx);
-    if (hasAtom && !XDRAtom(xdr, &atom))
-        return false;
+    if (hasAtom)
+        MOZ_TRY(XDRAtom(xdr, &atom));
 
     *bindingName = BindingName(atom, closedOver);
 
-    return true;
+    return Ok();
 }
 
 template <typename ConcreteScopeData>
 static void
 DeleteScopeData(ConcreteScopeData* data)
 {
     // Some scope Data classes have GCManagedDeletePolicy because then contain
     // GCPtrs. Dispose of them in the appropriate way.
     JS::DeletePolicy<ConcreteScopeData>()(data);
 }
 
 template <typename ConcreteScope, XDRMode mode>
-/* static */ bool
+/* static */ XDRResult
 Scope::XDRSizedBindingNames(XDRState<mode>* xdr, Handle<ConcreteScope*> scope,
                             MutableHandle<typename ConcreteScope::Data*> data)
 {
     MOZ_ASSERT(!data);
 
     JSContext* cx = xdr->cx();
 
     uint32_t length;
     if (mode == XDR_ENCODE)
         length = scope->data().length;
-    if (!xdr->codeUint32(&length))
-        return false;
+    MOZ_TRY(xdr->codeUint32(&length));
 
     if (mode == XDR_ENCODE) {
         data.set(&scope->data());
     } else {
         data.set(NewEmptyScopeData<ConcreteScope>(cx, length).release());
         if (!data)
-            return false;
+            return xdr->fail(JS::TranscodeResult_Throw);
         data->length = length;
     }
 
     for (uint32_t i = 0; i < length; i++) {
-        if (!XDRBindingName(xdr, &data->names[i])) {
+        auto guard = mozilla::MakeScopeExit([&] {
             if (mode == XDR_DECODE) {
                 DeleteScopeData(data.get());
                 data.set(nullptr);
             }
-
-            return false;
-        }
+        });
+        MOZ_TRY(XDRBindingName(xdr, &data->names[i]));
+        guard.release();
     }
 
-    return true;
+    return Ok();
 }
 
 /* static */ Scope*
 Scope::create(JSContext* cx, ScopeKind kind, HandleScope enclosing, HandleShape envShape)
 {
     Scope* scope = Allocate<Scope>(cx);
     if (scope)
         new (scope) Scope(kind, enclosing, envShape);
@@ -567,65 +564,61 @@ LexicalScope::createWithData(JSContext* 
 /* static */ Shape*
 LexicalScope::getEmptyExtensibleEnvironmentShape(JSContext* cx)
 {
     const Class* cls = &LexicalEnvironmentObject::class_;
     return EmptyEnvironmentShape(cx, cls, JSSLOT_FREE(cls), BaseShape::DELEGATE);
 }
 
 template <XDRMode mode>
-/* static */ bool
+/* static */ XDRResult
 LexicalScope::XDR(XDRState<mode>* xdr, ScopeKind kind, HandleScope enclosing,
                   MutableHandleScope scope)
 {
     JSContext* cx = xdr->cx();
 
     Rooted<Data*> data(cx);
-    if (!XDRSizedBindingNames<LexicalScope>(xdr, scope.as<LexicalScope>(), &data))
-        return false;
+    MOZ_TRY(XDRSizedBindingNames<LexicalScope>(xdr, scope.as<LexicalScope>(), &data));
 
     {
         Maybe<Rooted<UniquePtr<Data>>> uniqueData;
         if (mode == XDR_DECODE)
             uniqueData.emplace(cx, data);
 
         uint32_t firstFrameSlot;
         uint32_t nextFrameSlot;
         if (mode == XDR_ENCODE) {
             firstFrameSlot = scope->as<LexicalScope>().firstFrameSlot();
             nextFrameSlot = data->nextFrameSlot;
         }
 
-        if (!xdr->codeUint32(&data->constStart))
-            return false;
-        if (!xdr->codeUint32(&firstFrameSlot))
-            return false;
-        if (!xdr->codeUint32(&nextFrameSlot))
-            return false;
+        MOZ_TRY(xdr->codeUint32(&data->constStart));
+        MOZ_TRY(xdr->codeUint32(&firstFrameSlot));
+        MOZ_TRY(xdr->codeUint32(&nextFrameSlot));
 
         if (mode == XDR_DECODE) {
             scope.set(createWithData(cx, kind, &uniqueData.ref(), firstFrameSlot, enclosing));
             if (!scope)
-                return false;
+                return xdr->fail(JS::TranscodeResult_Throw);
 
             // nextFrameSlot is used only for this correctness check.
             MOZ_ASSERT(nextFrameSlot == scope->as<LexicalScope>().data().nextFrameSlot);
         }
     }
 
-    return true;
+    return Ok();
 }
 
 template
-/* static */ bool
+/* static */ XDRResult
 LexicalScope::XDR(XDRState<XDR_ENCODE>* xdr, ScopeKind kind, HandleScope enclosing,
                   MutableHandleScope scope);
 
 template
-/* static */ bool
+/* static */ XDRResult
 LexicalScope::XDR(XDRState<XDR_DECODE>* xdr, ScopeKind kind, HandleScope enclosing,
                   MutableHandleScope scope);
 
 static inline uint32_t
 FunctionScopeEnvShapeFlags(bool hasParameterExprs)
 {
     if (hasParameterExprs)
         return BaseShape::DELEGATE;
@@ -756,76 +749,70 @@ FunctionScope::clone(JSContext* cx, Hand
         funScopeClone = &scopeClone->as<FunctionScope>();
         funScopeClone->initData(Move(dataClone.get()));
     }
 
     return funScopeClone;
 }
 
 template <XDRMode mode>
-/* static */ bool
+/* static */ XDRResult
 FunctionScope::XDR(XDRState<mode>* xdr, HandleFunction fun, HandleScope enclosing,
                    MutableHandleScope scope)
 {
     JSContext* cx = xdr->cx();
     Rooted<Data*> data(cx);
-    if (!XDRSizedBindingNames<FunctionScope>(xdr, scope.as<FunctionScope>(), &data))
-        return false;
+    MOZ_TRY(XDRSizedBindingNames<FunctionScope>(xdr, scope.as<FunctionScope>(), &data));
 
     {
         Maybe<Rooted<UniquePtr<Data>>> uniqueData;
         if (mode == XDR_DECODE)
             uniqueData.emplace(cx, data);
 
         uint8_t needsEnvironment;
         uint8_t hasParameterExprs;
         uint32_t nextFrameSlot;
         if (mode == XDR_ENCODE) {
             needsEnvironment = scope->hasEnvironment();
             hasParameterExprs = data->hasParameterExprs;
             nextFrameSlot = data->nextFrameSlot;
         }
-        if (!xdr->codeUint8(&needsEnvironment))
-            return false;
-        if (!xdr->codeUint8(&hasParameterExprs))
-            return false;
-        if (!xdr->codeUint16(&data->nonPositionalFormalStart))
-            return false;
-        if (!xdr->codeUint16(&data->varStart))
-            return false;
-        if (!xdr->codeUint32(&nextFrameSlot))
-            return false;
+        MOZ_TRY(xdr->codeUint8(&needsEnvironment));
+        MOZ_TRY(xdr->codeUint8(&hasParameterExprs));
+        MOZ_TRY(xdr->codeUint16(&data->nonPositionalFormalStart));
+        MOZ_TRY(xdr->codeUint16(&data->varStart));
+        MOZ_TRY(xdr->codeUint32(&nextFrameSlot));
 
         if (mode == XDR_DECODE) {
             if (!data->length) {
                 MOZ_ASSERT(!data->nonPositionalFormalStart);
                 MOZ_ASSERT(!data->varStart);
                 MOZ_ASSERT(!data->nextFrameSlot);
             }
 
             scope.set(createWithData(cx, &uniqueData.ref(), hasParameterExprs, needsEnvironment, fun,
                                      enclosing));
             if (!scope)
-                return false;
+                return xdr->fail(JS::TranscodeResult_Throw);
 
             // nextFrameSlot is used only for this correctness check.
             MOZ_ASSERT(nextFrameSlot == scope->as<FunctionScope>().data().nextFrameSlot);
         }
     }
 
-    return true;
+    return Ok();
 }
 
 template
-/* static */ bool
+/* static */ XDRResult
 FunctionScope::XDR(XDRState<XDR_ENCODE>* xdr, HandleFunction fun, HandleScope enclosing,
                    MutableHandleScope scope);
 
 template
-/* static */ bool
+/* static */ XDRResult
 FunctionScope::XDR(XDRState<XDR_DECODE>* xdr, HandleFunction fun, HandleScope enclosing,
                    MutableHandleScope scope);
 
 static const uint32_t VarScopeEnvShapeFlags =
     BaseShape::QUALIFIED_VAROBJ | BaseShape::DELEGATE;
 
 static UniquePtr<VarScope::Data>
 NewEmptyVarScopeData(JSContext* cx, uint32_t firstFrameSlot)
@@ -892,70 +879,66 @@ uint32_t
 VarScope::firstFrameSlot() const
 {
     if (enclosing()->is<FunctionScope>())
         return enclosing()->as<FunctionScope>().nextFrameSlot();
     return 0;
 }
 
 template <XDRMode mode>
-/* static */ bool
+/* static */ XDRResult
 VarScope::XDR(XDRState<mode>* xdr, ScopeKind kind, HandleScope enclosing,
               MutableHandleScope scope)
 {
     JSContext* cx = xdr->cx();
     Rooted<Data*> data(cx);
-    if (!XDRSizedBindingNames<VarScope>(xdr, scope.as<VarScope>(), &data))
-        return false;
+    MOZ_TRY(XDRSizedBindingNames<VarScope>(xdr, scope.as<VarScope>(), &data));
 
     {
         Maybe<Rooted<UniquePtr<Data>>> uniqueData;
         if (mode == XDR_DECODE)
             uniqueData.emplace(cx, data);
 
         uint8_t needsEnvironment;
         uint32_t firstFrameSlot;
         uint32_t nextFrameSlot;
         if (mode == XDR_ENCODE) {
             needsEnvironment = scope->hasEnvironment();
             firstFrameSlot = scope->as<VarScope>().firstFrameSlot();
             nextFrameSlot = data->nextFrameSlot;
         }
-        if (!xdr->codeUint8(&needsEnvironment))
-            return false;
-        if (!xdr->codeUint32(&firstFrameSlot))
-            return false;
-        if (!xdr->codeUint32(&nextFrameSlot))
-            return false;
+        MOZ_TRY(xdr->codeUint8(&needsEnvironment));
+        MOZ_TRY(xdr->codeUint32(&firstFrameSlot));
+        MOZ_TRY(xdr->codeUint32(&nextFrameSlot));
 
         if (mode == XDR_DECODE) {
             if (!data->length) {
                 MOZ_ASSERT(!data->nextFrameSlot);
             }
 
             scope.set(createWithData(cx, kind, &uniqueData.ref(), firstFrameSlot, needsEnvironment,
                                      enclosing));
             if (!scope)
-                return false;
+                return xdr->fail(JS::TranscodeResult_Throw);
 
             // nextFrameSlot is used only for this correctness check.
             MOZ_ASSERT(nextFrameSlot == scope->as<VarScope>().data().nextFrameSlot);
         }
     }
 
-    return true;
+    return Ok();
 }
 
 template
-/* static */ bool
+/* static */ XDRResult
 VarScope::XDR(XDRState<XDR_ENCODE>* xdr, ScopeKind kind, HandleScope enclosing,
               MutableHandleScope scope);
 
 template
-/* static */ bool
+/* static */ XDRResult
 VarScope::XDR(XDRState<XDR_DECODE>* xdr, ScopeKind kind, HandleScope enclosing,
               MutableHandleScope scope);
 
 /* static */ GlobalScope*
 GlobalScope::create(JSContext* cx, ScopeKind kind, Handle<Data*> dataArg)
 {
     // The data that's passed in is from the frontend and is LifoAlloc'd.
     // Copy it now that we're creating a permanent VM scope.
@@ -992,60 +975,56 @@ GlobalScope::clone(JSContext* cx, Handle
 
     Scope* scopeClone = Scope::create(cx, kind, nullptr, nullptr, Move(dataClone.get()));
     if (!scopeClone)
         return nullptr;
     return &scopeClone->as<GlobalScope>();
 }
 
 template <XDRMode mode>
-/* static */ bool
+/* static */ XDRResult
 GlobalScope::XDR(XDRState<mode>* xdr, ScopeKind kind, MutableHandleScope scope)
 {
     MOZ_ASSERT((mode == XDR_DECODE) == !scope);
 
     JSContext* cx = xdr->cx();
     Rooted<Data*> data(cx);
-    if (!XDRSizedBindingNames<GlobalScope>(xdr, scope.as<GlobalScope>(), &data))
-        return false;
+    MOZ_TRY(XDRSizedBindingNames<GlobalScope>(xdr, scope.as<GlobalScope>(), &data));
 
     {
         Maybe<Rooted<UniquePtr<Data>>> uniqueData;
         if (mode == XDR_DECODE)
             uniqueData.emplace(cx, data);
 
-        if (!xdr->codeUint32(&data->varStart))
-            return false;
-        if (!xdr->codeUint32(&data->letStart))
-            return false;
-        if (!xdr->codeUint32(&data->constStart))
-            return false;
+        MOZ_TRY(xdr->codeUint32(&data->varStart));
+        MOZ_TRY(xdr->codeUint32(&data->letStart));
+        MOZ_TRY(xdr->codeUint32(&data->constStart));
 
         if (mode == XDR_DECODE) {
             if (!data->length) {
                 MOZ_ASSERT(!data->varStart);
                 MOZ_ASSERT(!data->letStart);
                 MOZ_ASSERT(!data->constStart);
             }
 
             scope.set(createWithData(cx, kind, &uniqueData.ref()));
             if (!scope)
-                return false;
+                return xdr->fail(JS::TranscodeResult_Throw);
         }
     }
 
-    return true;
+    return Ok();
 }
 
 template
-/* static */ bool
+/* static */ XDRResult
 GlobalScope::XDR(XDRState<XDR_ENCODE>* xdr, ScopeKind kind, MutableHandleScope scope);
 
 template
-/* static */ bool
+/* static */ XDRResult
 GlobalScope::XDR(XDRState<XDR_DECODE>* xdr, ScopeKind kind, MutableHandleScope scope);
 
 /* static */ WithScope*
 WithScope::create(JSContext* cx, HandleScope enclosing)
 {
     Scope* scope = Scope::create(cx, ScopeKind::With, enclosing, nullptr);
     return static_cast<WithScope*>(scope);
 }
@@ -1118,51 +1097,50 @@ EvalScope::nearestVarScopeForDirectEval(
 /* static */ Shape*
 EvalScope::getEmptyEnvironmentShape(JSContext* cx)
 {
     const Class* cls = &VarEnvironmentObject::class_;
     return EmptyEnvironmentShape(cx, cls, JSSLOT_FREE(cls), EvalScopeEnvShapeFlags);
 }
 
 template <XDRMode mode>
-/* static */ bool
+/* static */ XDRResult
 EvalScope::XDR(XDRState<mode>* xdr, ScopeKind kind, HandleScope enclosing,
                MutableHandleScope scope)
 {
     JSContext* cx = xdr->cx();
     Rooted<Data*> data(cx);
 
     {
         Maybe<Rooted<UniquePtr<Data>>> uniqueData;
         if (mode == XDR_DECODE)
             uniqueData.emplace(cx, data);
 
-        if (!XDRSizedBindingNames<EvalScope>(xdr, scope.as<EvalScope>(), &data))
-            return false;
+        MOZ_TRY(XDRSizedBindingNames<EvalScope>(xdr, scope.as<EvalScope>(), &data));
 
         if (mode == XDR_DECODE) {
             if (!data->length)
                 MOZ_ASSERT(!data->nextFrameSlot);
 
             scope.set(createWithData(cx, kind, &uniqueData.ref(), enclosing));
             if (!scope)
-                return false;
+                return xdr->fail(JS::TranscodeResult_Throw);
         }
     }
 
-    return true;
+    return Ok();
 }
 
 template
-/* static */ bool
+/* static */ XDRResult
 EvalScope::XDR(XDRState<XDR_ENCODE>* xdr, ScopeKind kind, HandleScope enclosing,
                MutableHandleScope scope);
 
 template
-/* static */ bool
+/* static */ XDRResult
 EvalScope::XDR(XDRState<XDR_DECODE>* xdr, ScopeKind kind, HandleScope enclosing,
                MutableHandleScope scope);
 
 static const uint32_t ModuleScopeEnvShapeFlags =
     BaseShape::NOT_EXTENSIBLE | BaseShape::QUALIFIED_VAROBJ | BaseShape::DELEGATE;
 
 Zone*
 ModuleScope::Data::zone() const
--- a/js/src/vm/Scope.h
+++ b/js/src/vm/Scope.h
@@ -254,18 +254,18 @@ class Scope : public js::gc::TenuredCell
     static Scope* create(JSContext* cx, ScopeKind kind, HandleScope enclosing,
                          HandleShape envShape);
 
     template <typename T, typename D>
     static Scope* create(JSContext* cx, ScopeKind kind, HandleScope enclosing,
                          HandleShape envShape, mozilla::UniquePtr<T, D> data);
 
     template <typename ConcreteScope, XDRMode mode>
-    static bool XDRSizedBindingNames(XDRState<mode>* xdr, Handle<ConcreteScope*> scope,
-                                     MutableHandle<typename ConcreteScope::Data*> data);
+    static XDRResult XDRSizedBindingNames(XDRState<mode>* xdr, Handle<ConcreteScope*> scope,
+                                          MutableHandle<typename ConcreteScope::Data*> data);
 
     Shape* maybeCloneEnvironmentShape(JSContext* cx);
 
     template <typename T, typename D>
     void initData(mozilla::UniquePtr<T, D> data) {
         MOZ_ASSERT(!data_);
         data_ = reinterpret_cast<uintptr_t>(data.release());
     }
@@ -401,17 +401,17 @@ class LexicalScope : public Scope
         *names = data->names;
         *length = data->length;
     }
 
     static LexicalScope* create(JSContext* cx, ScopeKind kind, Handle<Data*> data,
                                 uint32_t firstFrameSlot, HandleScope enclosing);
 
     template <XDRMode mode>
-    static bool XDR(XDRState<mode>* xdr, ScopeKind kind, HandleScope enclosing,
+    static XDRResult XDR(XDRState<mode>* xdr, ScopeKind kind, HandleScope enclosing,
                     MutableHandleScope scope);
 
   private:
     static LexicalScope* createWithData(JSContext* cx, ScopeKind kind,
                                         MutableHandle<UniquePtr<Data>> data,
                                         uint32_t firstFrameSlot, HandleScope enclosing);
 
     Data& data() {
@@ -528,17 +528,17 @@ class FunctionScope : public Scope
     static FunctionScope* create(JSContext* cx, Handle<Data*> data,
                                  bool hasParameterExprs, bool needsEnvironment,
                                  HandleFunction fun, HandleScope enclosing);
 
     static FunctionScope* clone(JSContext* cx, Handle<FunctionScope*> scope, HandleFunction fun,
                                 HandleScope enclosing);
 
     template <XDRMode mode>
-    static bool XDR(XDRState<mode>* xdr, HandleFunction fun, HandleScope enclosing,
+    static XDRResult XDR(XDRState<mode>* xdr, HandleFunction fun, HandleScope enclosing,
                     MutableHandleScope scope);
 
   private:
     static FunctionScope* createWithData(JSContext* cx, MutableHandle<UniquePtr<Data>> data,
                                          bool hasParameterExprs, bool needsEnvironment,
                                          HandleFunction fun, HandleScope enclosing);
 
     Data& data() {
@@ -626,17 +626,17 @@ class VarScope : public Scope
         *length = data->length;
     }
 
     static VarScope* create(JSContext* cx, ScopeKind kind, Handle<Data*> data,
                             uint32_t firstFrameSlot, bool needsEnvironment,
                             HandleScope enclosing);
 
     template <XDRMode mode>
-    static bool XDR(XDRState<mode>* xdr, ScopeKind kind, HandleScope enclosing,
+    static XDRResult XDR(XDRState<mode>* xdr, ScopeKind kind, HandleScope enclosing,
                     MutableHandleScope scope);
 
   private:
     static VarScope* createWithData(JSContext* cx, ScopeKind kind, MutableHandle<UniquePtr<Data>> data,
                                     uint32_t firstFrameSlot, bool needsEnvironment,
                                     HandleScope enclosing);
 
     Data& data() {
@@ -724,17 +724,17 @@ class GlobalScope : public Scope
 
     static GlobalScope* createEmpty(JSContext* cx, ScopeKind kind) {
         return create(cx, kind, nullptr);
     }
 
     static GlobalScope* clone(JSContext* cx, Handle<GlobalScope*> scope, ScopeKind kind);
 
     template <XDRMode mode>
-    static bool XDR(XDRState<mode>* xdr, ScopeKind kind, MutableHandleScope scope);
+    static XDRResult XDR(XDRState<mode>* xdr, ScopeKind kind, MutableHandleScope scope);
 
   private:
     static GlobalScope* createWithData(JSContext* cx, ScopeKind kind,
                                        MutableHandle<UniquePtr<Data>> data);
 
     Data& data() {
         return *reinterpret_cast<Data*>(data_);
     }
@@ -824,17 +824,17 @@ class EvalScope : public Scope
         *names = data->names;
         *length = data->length;
     }
 
     static EvalScope* create(JSContext* cx, ScopeKind kind, Handle<Data*> data,
                              HandleScope enclosing);
 
     template <XDRMode mode>
-    static bool XDR(XDRState<mode>* xdr, ScopeKind kind, HandleScope enclosing,
+    static XDRResult XDR(XDRState<mode>* xdr, ScopeKind kind, HandleScope enclosing,
                     MutableHandleScope scope);
 
   private:
     static EvalScope* createWithData(JSContext* cx, ScopeKind kind, MutableHandle<UniquePtr<Data>> data,
                                      HandleScope enclosing);
 
     Data& data() {
         return *reinterpret_cast<Data*>(data_);
--- a/js/src/vm/Xdr.cpp
+++ b/js/src/vm/Xdr.cpp
@@ -2,221 +2,228 @@
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * 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 "vm/Xdr.h"
 
 #include "mozilla/PodOperations.h"
+#include "mozilla/ScopeExit.h"
 
 #include <string.h>
 
 #include "jsapi.h"
+#include "jsutil.h"
 
 #include "vm/Debugger.h"
 #include "vm/EnvironmentObject.h"
 #include "vm/JSContext.h"
 #include "vm/JSScript.h"
 #include "vm/TraceLogging.h"
 
 using namespace js;
 using mozilla::PodEqual;
 
 template<XDRMode mode>
 LifoAlloc&
 XDRState<mode>::lifoAlloc() const {
     return buf.cx()->tempLifoAlloc();
 }
 
-template<XDRMode mode>
-void
-XDRState<mode>::postProcessContextErrors(JSContext* cx)
+#ifdef DEBUG
+bool
+XDRCoderBase::validateResultCode(JSContext* cx, JS::TranscodeResult code) const
 {
-    // NOTE: This should only be called on transcode failure. Not all failure
-    // paths call XDRState::fail(...), so we should update resultCode_ if it
-    // doesn't hold a specific transcode error.
-
-    if (resultCode_ & JS::TranscodeResult_Failure)
-        MOZ_ASSERT_IF(!cx->helperThread(), !cx->isExceptionPending());
-    else
-        resultCode_ = JS::TranscodeResult_Throw;
+    // NOTE: This function is called to verify that we do not have a pending
+    // exception on the JSContext at the same time as a TranscodeResult failure.
+    if (cx->helperThread())
+        return true;
+    return cx->isExceptionPending() == bool(code == JS::TranscodeResult_Throw);
 }
+#endif
 
 template<XDRMode mode>
-bool
+XDRResult
 XDRState<mode>::codeChars(const Latin1Char* chars, size_t nchars)
 {
     static_assert(sizeof(Latin1Char) == sizeof(uint8_t), "Latin1Char must fit in 1 byte");
 
     MOZ_ASSERT(mode == XDR_ENCODE);
 
     if (nchars == 0)
-        return true;
+        return Ok();
     uint8_t* ptr = buf.write(nchars);
     if (!ptr)
         return fail(JS::TranscodeResult_Throw);
 
     mozilla::PodCopy(ptr, chars, nchars);
-    return true;
+    return Ok();
 }
 
 template<XDRMode mode>
-bool
+XDRResult
 XDRState<mode>::codeChars(char16_t* chars, size_t nchars)
 {
     if (nchars == 0)
-        return true;
+        return Ok();
     size_t nbytes = nchars * sizeof(char16_t);
     if (mode == XDR_ENCODE) {
         uint8_t* ptr = buf.write(nbytes);
         if (!ptr)
             return fail(JS::TranscodeResult_Throw);
         mozilla::NativeEndian::copyAndSwapToLittleEndian(ptr, chars, nchars);
     } else {
         const uint8_t* ptr = buf.read(nbytes);
         if (!ptr)
             return fail(JS::TranscodeResult_Failure_BadDecode);
         mozilla::NativeEndian::copyAndSwapFromLittleEndian(chars, ptr, nchars);
     }
-    return true;
+    return Ok();
 }
 
 template<XDRMode mode>
-static bool
+static XDRResult
 VersionCheck(XDRState<mode>* xdr)
 {
     JS::BuildIdCharVector buildId;
     MOZ_ASSERT(xdr->cx()->buildIdOp());
     if (!xdr->cx()->buildIdOp()(&buildId)) {
         ReportOutOfMemory(xdr->cx());
         return xdr->fail(JS::TranscodeResult_Throw);
     }
     MOZ_ASSERT(!buildId.empty());
 
     uint32_t buildIdLength;
     if (mode == XDR_ENCODE)
         buildIdLength = buildId.length();
 
-    if (!xdr->codeUint32(&buildIdLength))
-        return false;
+    MOZ_TRY(xdr->codeUint32(&buildIdLength));
 
     if (mode == XDR_DECODE && buildIdLength != buildId.length())
         return xdr->fail(JS::TranscodeResult_Failure_BadBuildId);
 
     if (mode == XDR_ENCODE) {
-        if (!xdr->codeBytes(buildId.begin(), buildIdLength))
-            return false;
+        MOZ_TRY(xdr->codeBytes(buildId.begin(), buildIdLength));
     } else {
         JS::BuildIdCharVector decodedBuildId;
 
         // buildIdLength is already checked against the length of current
         // buildId.
         if (!decodedBuildId.resize(buildIdLength)) {
             ReportOutOfMemory(xdr->cx());
             return xdr->fail(JS::TranscodeResult_Throw);
         }
 
-        if (!xdr->codeBytes(decodedBuildId.begin(), buildIdLength))
-            return false;
+        MOZ_TRY(xdr->codeBytes(decodedBuildId.begin(), buildIdLength));
 
         // We do not provide binary compatibility with older scripts.
         if (!PodEqual(decodedBuildId.begin(), buildId.begin(), buildIdLength))
             return xdr->fail(JS::TranscodeResult_Failure_BadBuildId);
     }
 
-    return true;
+    return Ok();
 }
 
 template<XDRMode mode>
-bool
+XDRResult
 XDRState<mode>::codeFunction(MutableHandleFunction funp, HandleScriptSource sourceObject)
 {
     TraceLoggerThread* logger = TraceLoggerForCurrentThread(cx());
     TraceLoggerTextId event =
         mode == XDR_DECODE ? TraceLogger_DecodeFunction : TraceLogger_EncodeFunction;
     AutoTraceLog tl(logger, event);
 
+#ifdef DEBUG
+    auto sanityCheck = mozilla::MakeScopeExit([&] {
+        MOZ_ASSERT(validateResultCode(cx(), resultCode()));
+    });
+#endif
+    auto guard = mozilla::MakeScopeExit([&] { funp.set(nullptr); });
     RootedScope scope(cx(), &cx()->global()->emptyGlobalScope());
     if (mode == XDR_DECODE) {
         MOZ_ASSERT(!sourceObject);
         funp.set(nullptr);
     } else if (getTreeKey(funp) != AutoXDRTree::noKey) {
         MOZ_ASSERT(sourceObject);
         scope = funp->nonLazyScript()->enclosingScope();
     } else {
         MOZ_ASSERT(!sourceObject);
         MOZ_ASSERT(funp->nonLazyScript()->enclosingScope()->is<GlobalScope>());
     }
 
-    if (!VersionCheck(this)) {
-        postProcessContextErrors(cx());
-        return false;
-    }
+    MOZ_TRY(VersionCheck(this));
+    MOZ_TRY(XDRInterpretedFunction(this, scope, sourceObject, funp));
 
-    if (!XDRInterpretedFunction(this, scope, sourceObject, funp)) {
-        postProcessContextErrors(cx());
-        funp.set(nullptr);
-        return false;
-    }
-
-    return true;
+    guard.release();
+    return Ok();
 }
 
 template<XDRMode mode>
-bool
+XDRResult
 XDRState<mode>::codeScript(MutableHandleScript scriptp)
 {
     TraceLoggerThread* logger = TraceLoggerForCurrentThread(cx());
     TraceLoggerTextId event =
         mode == XDR_DECODE ? TraceLogger_DecodeScript : TraceLogger_EncodeScript;
     AutoTraceLog tl(logger, event);
 
+#ifdef DEBUG
+    auto sanityCheck = mozilla::MakeScopeExit([&] {
+        MOZ_ASSERT(validateResultCode(cx(), resultCode()));
+    });
+#endif
+    auto guard = mozilla::MakeScopeExit([&] { scriptp.set(nullptr); });
+
+    // This should be a no-op when encoding, but when decoding it would eat any
+    // miss-aligned bytes if when encoding the XDR buffer is appended at the end
+    // of an existing buffer, such as in XDRIncrementalEncoder::linearize
+    // function.
+    MOZ_TRY(codeAlign(sizeof(js::XDRAlignment)));
     AutoXDRTree scriptTree(this, getTopLevelTreeKey());
 
     if (mode == XDR_DECODE)
         scriptp.set(nullptr);
     else
         MOZ_ASSERT(!scriptp->enclosingScope());
 
-    if (!VersionCheck(this)) {
-        postProcessContextErrors(cx());
-        return false;
-    }
+    MOZ_TRY(VersionCheck(this));
+    MOZ_TRY(XDRScript(this, nullptr, nullptr, nullptr, scriptp));
+    MOZ_TRY(codeAlign(sizeof(js::XDRAlignment)));
 
-    if (!XDRScript(this, nullptr, nullptr, nullptr, scriptp)) {
-        postProcessContextErrors(cx());
-        scriptp.set(nullptr);
-        return false;
-    }
-
-    return true;
+    guard.release();
+    return Ok();
 }
 
 template<XDRMode mode>
-bool
+XDRResult
 XDRState<mode>::codeConstValue(MutableHandleValue vp)
 {
     return XDRScriptConst(this, vp);
 }
 
 template class js::XDRState<XDR_ENCODE>;
 template class js::XDRState<XDR_DECODE>;
 
 AutoXDRTree::AutoXDRTree(XDRCoderBase* xdr, AutoXDRTree::Key key)
   : key_(key),
     parent_(this),
     xdr_(xdr)
 {
+    // Expect sub-tree to start with the maximum alignment required.
+    MOZ_ASSERT(xdr->isAligned(sizeof(js::XDRAlignment)));
     if (key_ != AutoXDRTree::noKey)
         xdr->createOrReplaceSubTree(this);
 }
 
 AutoXDRTree::~AutoXDRTree()
 {
+    // Expect sub-tree to end with the maximum alignment required.
+    MOZ_ASSERT_IF(xdr_->resultCode() == JS::TranscodeResult_Ok,
+                  xdr_->isAligned(sizeof(js::XDRAlignment)));
     if (key_ != AutoXDRTree::noKey)
         xdr_->endSubTree();
 }
 
 constexpr AutoXDRTree::Key AutoXDRTree::noKey;
 constexpr AutoXDRTree::Key AutoXDRTree::noSubTree;
 constexpr AutoXDRTree::Key AutoXDRTree::topLevel;
 
@@ -324,27 +331,39 @@ XDRIncrementalEncoder::endSubTree()
 
     // Append the new slice in the parent node.
     if (!node_->append(Slice { cursor, 0, AutoXDRTree::noSubTree })) {
         oom_ = true;
         return;
     }
 }
 
-bool
+XDRResult
 XDRIncrementalEncoder::linearize(JS::TranscodeBuffer& buffer)
 {
     if (oom_) {
         ReportOutOfMemory(cx());
         return fail(JS::TranscodeResult_Throw);
     }
 
     // Do not linearize while we are currently adding bytes.
     MOZ_ASSERT(scope_ == nullptr);
 
+    // Ensure the content of the buffer is properly aligned within the buffer.
+    // This alignment difference should be consumed by the codeAlign function
+    // call of codeScript when decoded.
+    size_t alignLen = sizeof(js::XDRAlignment);
+    if (buffer.length() % alignLen) {
+        alignLen = ComputeByteAlignment(buffer.length(), alignLen);
+        if (!buffer.appendN(0, alignLen)) {
+            ReportOutOfMemory(cx());
+            return fail(JS::TranscodeResult_Throw);
+        }
+    }
+
     // Visit the tree parts in a depth first order, to linearize the bits.
     Vector<SlicesNode::ConstRange> depthFirst(cx());
 
     SlicesTree::Ptr p = tree_.lookup(AutoXDRTree::topLevel);
     MOZ_ASSERT(p);
 
     if (!depthFirst.append(((const SlicesNode&) p->value()).all())) {
         ReportOutOfMemory(cx());
@@ -359,16 +378,18 @@ XDRIncrementalEncoder::linearize(JS::Tra
         MOZ_ASSERT_IF(slice.child == AutoXDRTree::noSubTree, iter.empty());
         if (iter.empty())
             depthFirst.popBack();
 
         // Copy the bytes associated with the current slice to the transcode
         // buffer which would be serialized.
         MOZ_ASSERT(slice.sliceBegin <= slices_.length());
         MOZ_ASSERT(slice.sliceBegin + slice.sliceLength <= slices_.length());
+        MOZ_ASSERT(buffer.length() % sizeof(XDRAlignment) == 0);
+        MOZ_ASSERT(slice.sliceLength % sizeof(XDRAlignment) == 0);
         if (!buffer.append(slices_.begin() + slice.sliceBegin, slice.sliceLength)) {
             ReportOutOfMemory(cx());
             return fail(JS::TranscodeResult_Throw);
         }
 
         // If we are at the end, go to back to the parent script.
         if (slice.child == AutoXDRTree::noSubTree)
             continue;
@@ -379,10 +400,10 @@ XDRIncrementalEncoder::linearize(JS::Tra
         if (!depthFirst.append(((const SlicesNode&) p->value()).all())) {
             ReportOutOfMemory(cx());
             return fail(JS::TranscodeResult_Throw);
         }
     }
 
     tree_.finish();
     slices_.clearAndFree();
-    return true;
+    return Ok();
 }
--- a/js/src/vm/Xdr.h
+++ b/js/src/vm/Xdr.h
@@ -19,58 +19,85 @@
 namespace js {
 
 class LifoAlloc;
 
 class XDRBufferBase
 {
   public:
     explicit XDRBufferBase(JSContext* cx, size_t cursor = 0)
-      : context_(cx), cursor_(cursor) { }
+      : context_(cx), cursor_(cursor)
+#ifdef DEBUG
+        // Note, when decoding the buffer can be set to a range, which does not
+        // have any alignment requirement as opposed to allocations.
+      , aligned_(false)
+#endif
+    { }
 
     JSContext* cx() const {
         return context_;
     }
 
     size_t cursor() const {
         return cursor_;
     }
 
+#ifdef DEBUG
+    // This function records if the cursor got changed by codeAlign or by any
+    // other read/write of data. This is used for AutoXDRTree assertions, as a
+    // way to ensure that the last thing done is properly setting the alignment
+    // with codeAlign function.
+    void setAligned(bool aligned) { aligned_ = aligned; }
+    bool isAligned() const { return aligned_; }
+#else
+    void setAligned(bool) const {}
+    bool isAligned() const { return true; }
+#endif
+
   protected:
     JSContext* const context_;
     size_t cursor_;
+#ifdef DEBUG
+    bool aligned_;
+#endif
 };
 
 template <XDRMode mode>
 class XDRBuffer;
 
 template <>
 class XDRBuffer<XDR_ENCODE> : public XDRBufferBase
 {
   public:
     XDRBuffer(JSContext* cx, JS::TranscodeBuffer& buffer, size_t cursor = 0)
       : XDRBufferBase(cx, cursor),
         buffer_(buffer) { }
 
     uint8_t* write(size_t n) {
         MOZ_ASSERT(n != 0);
+        setAligned(false);
         if (!buffer_.growByUninitialized(n)) {
             ReportOutOfMemory(cx());
             return nullptr;
         }
         uint8_t* ptr = &buffer_[cursor_];
         cursor_ += n;
         return ptr;
     }
 
     const uint8_t* read(size_t n) {
         MOZ_CRASH("Should never read in encode mode");
         return nullptr;
     }
 
+    uintptr_t uptr() const {
+        // Note: Avoid bounds check assertion if the buffer is not yet allocated.
+        return reinterpret_cast<uintptr_t>(buffer_.begin() + cursor_);
+    }
+
   private:
     JS::TranscodeBuffer& buffer_;
 };
 
 template <>
 class XDRBuffer<XDR_DECODE> : public XDRBufferBase
 {
   public:
@@ -79,37 +106,45 @@ class XDRBuffer<XDR_DECODE> : public XDR
         buffer_(range) { }
 
     XDRBuffer(JSContext* cx, JS::TranscodeBuffer& buffer, size_t cursor = 0)
       : XDRBufferBase(cx, cursor),
         buffer_(buffer.begin(), buffer.length()) { }
 
     const uint8_t* read(size_t n) {
         MOZ_ASSERT(cursor_ < buffer_.length());
+        setAligned(false);
         uint8_t* ptr = &buffer_[cursor_];
         cursor_ += n;
 
         // Don't let buggy code read past our buffer
         if (cursor_ > buffer_.length())
             return nullptr;
 
         return ptr;
     }
 
     uint8_t* write(size_t n) {
         MOZ_CRASH("Should never write in decode mode");
         return nullptr;
     }
 
+    uintptr_t uptr() const {
+        // Note: Avoid bounds check assertion at the end of the buffer.
+        return reinterpret_cast<uintptr_t>(buffer_.begin().get() + cursor_);
+    }
+
   private:
     const JS::TranscodeRange buffer_;
 };
 
 class XDRCoderBase;
 class XDRIncrementalEncoder;
+using XDRAlignment = char16_t;
+static const uint8_t AlignPadding[sizeof(XDRAlignment)] = { 0, 0 };
 
 // An AutoXDRTree is used to identify section encoded by an XDRIncrementalEncoder.
 //
 // Its primary goal is to identify functions, such that we can first encode them
 // as LazyScript, and later replaced by them by their corresponding bytecode
 // once delazified.
 //
 // As a convenience, this is also used to identify the top-level of the content
@@ -144,48 +179,66 @@ class MOZ_RAII AutoXDRTree
 
     Key key_;
     AutoXDRTree* parent_;
     XDRCoderBase* xdr_;
 };
 
 class XDRCoderBase
 {
+  private:
+#ifdef DEBUG
+    JS::TranscodeResult resultCode_;
+#endif
+
   protected:
-    XDRCoderBase() {}
+    XDRCoderBase()
+#ifdef DEBUG
+      : resultCode_(JS::TranscodeResult_Ok)
+#endif
+    {}
 
   public:
     virtual AutoXDRTree::Key getTopLevelTreeKey() const { return AutoXDRTree::noKey; }
     virtual AutoXDRTree::Key getTreeKey(JSFunction* fun) const { return AutoXDRTree::noKey; }
     virtual void createOrReplaceSubTree(AutoXDRTree* child) {};
     virtual void endSubTree() {};
+    virtual bool isAligned(size_t n) = 0;
+
+#ifdef DEBUG
+    // Record logical failures of XDR.
+    JS::TranscodeResult resultCode() const {
+        return resultCode_;
+    }
+    void setResultCode(JS::TranscodeResult code) {
+        MOZ_ASSERT(resultCode() == JS::TranscodeResult_Ok);
+        resultCode_ = code;
+    }
+    bool validateResultCode(JSContext* cx, JS::TranscodeResult code) const;
+#endif
 };
 
 /*
  * XDR serialization state.  All data is encoded in little endian.
  */
 template <XDRMode mode>
 class XDRState : public XDRCoderBase
 {
   protected:
     XDRBuffer<mode> buf;
-  private:
-    JS::TranscodeResult resultCode_;
 
   public:
     XDRState(JSContext* cx, JS::TranscodeBuffer& buffer, size_t cursor = 0)
-      : buf(cx, buffer, cursor),
-        resultCode_(JS::TranscodeResult_Ok)
+      : buf(cx, buffer, cursor)
     {
     }
 
     template <typename RangeType>
     XDRState(JSContext* cx, const RangeType& range)
-      : buf(cx, range),
-        resultCode_(JS::TranscodeResult_Ok)
+      : buf(cx, range)
     {
     }
 
     virtual ~XDRState() {};
 
     JSContext* cx() const {
         return buf.cx();
     }
@@ -195,194 +248,224 @@ class XDRState : public XDRCoderBase
     virtual const ReadOnlyCompileOptions& options() {
         MOZ_CRASH("does not have options");
     }
     virtual bool hasScriptSourceObjectOut() const { return false; }
     virtual ScriptSourceObject** scriptSourceObjectOut() {
         MOZ_CRASH("does not have scriptSourceObjectOut.");
     }
 
-    // Record logical failures of XDR.
-    void postProcessContextErrors(JSContext* cx);
-    JS::TranscodeResult resultCode() const {
-        return resultCode_;
-    }
-    bool fail(JS::TranscodeResult code) {
-        MOZ_ASSERT(resultCode_ == JS::TranscodeResult_Ok);
-        resultCode_ = code;
-        return false;
+    XDRResult fail(JS::TranscodeResult code) {
+#ifdef DEBUG
+        MOZ_ASSERT(code != JS::TranscodeResult_Ok);
+        MOZ_ASSERT(validateResultCode(cx(), code));
+        setResultCode(code);
+#endif
+        return mozilla::Err(code);
     }
 
-    bool peekData(const uint8_t** pptr, size_t length) {
+    XDRResult peekData(const uint8_t** pptr, size_t length) {
         const uint8_t* ptr = buf.read(length);
         if (!ptr)
             return fail(JS::TranscodeResult_Failure_BadDecode);
         *pptr = ptr;
-        return true;
+        return Ok();
     }
 
-    bool codeUint8(uint8_t* n) {
+    // Alignment is required when doing memcpy of data which contains element
+    // largers than 1 byte.
+    bool isAligned(size_t n) override {
+        MOZ_ASSERT(mozilla::IsPowerOfTwo(n));
+        size_t mask = n - 1;
+        size_t offset = buf.uptr() & mask;
+        // In debug build, we not only check if the cursor is aligned, but also
+        // if the last cursor manipulation was made by the codeAlign function.
+        return offset == 0 && buf.isAligned();
+    }
+    XDRResult codeAlign(size_t n) {
+        MOZ_ASSERT(mozilla::IsPowerOfTwo(n));
+        size_t mask = n - 1;
+        MOZ_ASSERT_IF(mode == XDR_ENCODE, (buf.uptr() & mask) == (buf.cursor() & mask));
+        size_t offset = buf.uptr() & mask;
+        if (offset) {
+            size_t padding = n - offset;
+            MOZ_ASSERT(padding < sizeof(AlignPadding));
+            if (mode == XDR_ENCODE) {
+                uint8_t* ptr = buf.write(padding);
+                if (!ptr)
+                    return fail(JS::TranscodeResult_Throw);
+                memcpy(ptr, AlignPadding, padding);
+            } else {
+                const uint8_t* ptr = buf.read(padding);
+                if (!ptr)
+                    return fail(JS::TranscodeResult_Failure_BadDecode);
+                if (memcmp(ptr, AlignPadding, padding) != 0)
+                    return fail(JS::TranscodeResult_Failure_BadDecode);
+            }
+        }
+        buf.setAligned(true);
+        MOZ_ASSERT(isAligned(n));
+        return Ok();
+    }
+
+    XDRResult codeUint8(uint8_t* n) {
         if (mode == XDR_ENCODE) {
             uint8_t* ptr = buf.write(sizeof(*n));
             if (!ptr)
                 return fail(JS::TranscodeResult_Throw);
             *ptr = *n;
         } else {
             const uint8_t* ptr = buf.read(sizeof(*n));
             if (!ptr)
                 return fail(JS::TranscodeResult_Failure_BadDecode);
             *n = *ptr;
         }
-        return true;
+        return Ok();
     }
 
-    bool codeUint16(uint16_t* n) {
+    XDRResult codeUint16(uint16_t* n) {
         if (mode == XDR_ENCODE) {
             uint8_t* ptr = buf.write(sizeof(*n));
             if (!ptr)
                 return fail(JS::TranscodeResult_Throw);
             mozilla::LittleEndian::writeUint16(ptr, *n);
         } else {
             const uint8_t* ptr = buf.read(sizeof(*n));
             if (!ptr)
                 return fail(JS::TranscodeResult_Failure_BadDecode);
             *n = mozilla::LittleEndian::readUint16(ptr);
         }
-        return true;
+        return Ok();
     }
 
-    bool codeUint32(uint32_t* n) {
+    XDRResult codeUint32(uint32_t* n) {
         if (mode == XDR_ENCODE) {
             uint8_t* ptr = buf.write(sizeof(*n));
             if (!ptr)
                 return fail(JS::TranscodeResult_Throw);
             mozilla::LittleEndian::writeUint32(ptr, *n);
         } else {
             const uint8_t* ptr = buf.read(sizeof(*n));
             if (!ptr)
                 return fail(JS::TranscodeResult_Failure_BadDecode);
             *n = mozilla::LittleEndian::readUint32(ptr);
         }
-        return true;
+        return Ok();
     }
 
-    bool codeUint64(uint64_t* n) {
+    XDRResult codeUint64(uint64_t* n) {
         if (mode == XDR_ENCODE) {
             uint8_t* ptr = buf.write(sizeof(*n));
             if (!ptr)
                 return fail(JS::TranscodeResult_Throw);
             mozilla::LittleEndian::writeUint64(ptr, *n);
         } else {
             const uint8_t* ptr = buf.read(sizeof(*n));
             if (!ptr)
                 return fail(JS::TranscodeResult_Failure_BadDecode);
             *n = mozilla::LittleEndian::readUint64(ptr);
         }
-        return true;
+        return Ok();
     }
 
     /*
      * Use SFINAE to refuse any specialization which is not an enum.  Uses of
      * this function do not have to specialize the type of the enumerated field
      * as C++ will extract the parameterized from the argument list.
      */
     template <typename T>
-    bool codeEnum32(T* val, typename mozilla::EnableIf<mozilla::IsEnum<T>::value, T>::Type * = NULL)
+    XDRResult codeEnum32(T* val, typename mozilla::EnableIf<mozilla::IsEnum<T>::value, T>::Type * = NULL)
     {
         // Mix the enumeration value with a random magic number, such that a
         // corruption with a low-ranged value (like 0) is less likely to cause a
         // miss-interpretation of the XDR content and instead cause a failure.
         const uint32_t MAGIC = 0x21AB218C;
         uint32_t tmp;
         if (mode == XDR_ENCODE)
             tmp = uint32_t(*val) ^ MAGIC;
-        if (!codeUint32(&tmp))
-            return false;
+        MOZ_TRY(codeUint32(&tmp));
         if (mode == XDR_DECODE)
             *val = T(tmp ^ MAGIC);
-        return true;
+        return Ok();
     }
 
-    bool codeDouble(double* dp) {
+    XDRResult codeDouble(double* dp) {
         union DoublePun {
             double d;
             uint64_t u;
         } pun;
         if (mode == XDR_ENCODE)
             pun.d = *dp;
-        if (!codeUint64(&pun.u))
-            return false;
+        MOZ_TRY(codeUint64(&pun.u));
         if (mode == XDR_DECODE)
             *dp = pun.d;
-        return true;
+        return Ok();
     }
 
-    bool codeMarker(uint32_t magic) {
+    XDRResult codeMarker(uint32_t magic) {
         uint32_t actual = magic;
-        if (!codeUint32(&actual))
-            return false;
+        MOZ_TRY(codeUint32(&actual));
         if (actual != magic) {
             // Fail in debug, but only soft-fail in release
             MOZ_ASSERT(false, "Bad XDR marker");
             return fail(JS::TranscodeResult_Failure_BadDecode);
         }
-        return true;
+        return Ok();
     }
 
-    bool codeBytes(void* bytes, size_t len) {
+    XDRResult codeBytes(void* bytes, size_t len) {
         if (len == 0)
-            return true;
+            return Ok();
         if (mode == XDR_ENCODE) {
             uint8_t* ptr = buf.write(len);
             if (!ptr)
                 return fail(JS::TranscodeResult_Throw);
             memcpy(ptr, bytes, len);
         } else {
             const uint8_t* ptr = buf.read(len);
             if (!ptr)
                 return fail(JS::TranscodeResult_Failure_BadDecode);
             memcpy(bytes, ptr, len);
         }
-        return true;
+        return Ok();
     }
 
     /*
      * During encoding the string is written into the buffer together with its
      * terminating '\0'. During decoding the method returns a pointer into the
      * decoding buffer and the caller must copy the string if it will outlive
      * the decoding buffer.
      */
-    bool codeCString(const char** sp) {
+    XDRResult codeCString(const char** sp) {
         uint64_t len64;
         if (mode == XDR_ENCODE)
             len64 = (uint64_t)(strlen(*sp) + 1);
-        if (!codeUint64(&len64))
-            return false;
+        MOZ_TRY(codeUint64(&len64));
         size_t len = (size_t) len64;
 
         if (mode == XDR_ENCODE) {
             uint8_t* ptr = buf.write(len);
             if (!ptr)
                 return fail(JS::TranscodeResult_Throw);
             memcpy(ptr, *sp, len);
         } else {
             const uint8_t* ptr = buf.read(len);
             if (!ptr || ptr[len] != '\0')
                 return fail(JS::TranscodeResult_Failure_BadDecode);
             *sp = reinterpret_cast<const char*>(ptr);
         }
-        return true;
+        return Ok();
     }
 
-    bool codeChars(const JS::Latin1Char* chars, size_t nchars);
-    bool codeChars(char16_t* chars, size_t nchars);
+    XDRResult codeChars(const JS::Latin1Char* chars, size_t nchars);
+    XDRResult codeChars(char16_t* chars, size_t nchars);
 
-    bool codeFunction(JS::MutableHandleFunction objp, HandleScriptSource sourceObject = nullptr);
-    bool codeScript(MutableHandleScript scriptp);
-    bool codeConstValue(MutableHandleValue vp);
+    XDRResult codeFunction(JS::MutableHandleFunction objp, HandleScriptSource sourceObject = nullptr);
+    XDRResult codeScript(MutableHandleScript scriptp);
+    XDRResult codeConstValue(MutableHandleValue vp);
 };
 
 using XDREncoder = XDRState<XDR_ENCODE>;
 using XDRDecoder = XDRState<XDR_DECODE>;
 
 class XDROffThreadDecoder : public XDRDecoder
 {
     const ReadOnlyCompileOptions* options_;
@@ -507,14 +590,14 @@ class XDRIncrementalEncoder : public XDR
 
     MOZ_MUST_USE bool init();
 
     void createOrReplaceSubTree(AutoXDRTree* child) override;
     void endSubTree() override;
 
     // Append the content collected during the incremental encoding into the
     // buffer given as argument.
-    MOZ_MUST_USE bool linearize(JS::TranscodeBuffer& buffer);
+    XDRResult linearize(JS::TranscodeBuffer& buffer);
 };
 
 } /* namespace js */
 
 #endif /* vm_Xdr_h */
--- a/js/src/wasm/WasmBaselineCompile.cpp
+++ b/js/src/wasm/WasmBaselineCompile.cpp
@@ -1231,17 +1231,17 @@ class BaseStackFrame
 
 #ifdef RABALDR_CHUNKY_STACK
         return localSize_ + InitialChunk;
 #else
         return localSize_;
 #endif
     }
 
-    void zeroLocals(BaseRegAlloc& ra);
+    void zeroLocals(BaseRegAlloc* ra);
 
     void loadLocalI32(const Local& src, RegI32 dest) {
         masm.load32(Address(sp_, localOffset(src)), dest);
     }
 
 #ifndef JS_PUNBOX64
     void loadLocalI64Low(const Local& src, RegI32 dest) {
         masm.load32(Address(sp_, localOffset(src) + INT64LOW_OFFSET), dest);
@@ -1610,17 +1610,17 @@ class BaseStackFrame
 #else
         if (argSize + dropSize)
             masm.freeStack(argSize + dropSize);
 #endif
     }
 };
 
 void
-BaseStackFrame::zeroLocals(BaseRegAlloc& ra)
+BaseStackFrame::zeroLocals(BaseRegAlloc* ra)
 {
     MOZ_ASSERT(varLow_ != UINT32_MAX);
 
     if (varLow_ == varHigh_)
         return;
 
     static const uint32_t wordSize = sizeof(void*);
 
@@ -1658,64 +1658,64 @@ BaseStackFrame::zeroLocals(BaseRegAlloc&
     }
 
     // For other cases, it's best to have a zero in a register.
     //
     // One can do more here with SIMD registers (store 16 bytes at a time) or
     // with instructions like STRD on ARM (store 8 bytes at a time), but that's
     // for another day.
 
-    RegI32 zero = ra.needI32();
+    RegI32 zero = ra->needI32();
     masm.mov(ImmWord(0), zero);
 
     // For the general case we want to have a loop body of UNROLL_LIMIT stores
     // and then a tail of less than UNROLL_LIMIT stores.  When initWords is less
     // than 2*UNROLL_LIMIT the loop trip count is at most 1 and there is no
     // benefit to having the pointer calculations and the compare-and-branch.
     // So we completely unroll when we have initWords < 2 * UNROLL_LIMIT.  (In
     // this case we'll end up using 32-bit offsets on x64 for up to half of the
     // stores, though.)
 
     // Fully-unrolled case.
 
     if (initWords < 2 * UNROLL_LIMIT)  {
         for (uint32_t i = low; i < high; i += wordSize)
             masm.storePtr(zero, Address(sp_, localOffset(i + wordSize)));
-        ra.freeI32(zero);
+        ra->freeI32(zero);
         return;
     }
 
     // Unrolled loop with a tail. Stores will use negative offsets. That's OK
     // for x86 and ARM, at least.
 
     // Compute pointer to the highest-addressed slot on the frame.
-    RegI32 p = ra.needI32();
+    RegI32 p = ra->needI32();
     masm.computeEffectiveAddress(Address(sp_, localOffset(low + wordSize)),
                                  p);
 
     // Compute pointer to the lowest-addressed slot on the frame that will be
     // initialized by the loop body.
-    RegI32 lim = ra.needI32();
+    RegI32 lim = ra->needI32();
     masm.computeEffectiveAddress(Address(sp_, localOffset(loopHigh + wordSize)), lim);
 
     // The loop body.  Eventually we'll have p == lim and exit the loop.
     Label again;
     masm.bind(&again);
     for (uint32_t i = 0; i < UNROLL_LIMIT; ++i)
         masm.storePtr(zero, Address(p, -(wordSize * i)));
     masm.subPtr(Imm32(UNROLL_LIMIT * wordSize), p);
     masm.branchPtr(Assembler::LessThan, lim, p, &again);
 
     // The tail.
     for (uint32_t i = 0; i < tailWords; ++i)
         masm.storePtr(zero, Address(p, -(wordSize * i)));
 
-    ra.freeI32(p);
-    ra.freeI32(lim);
-    ra.freeI32(zero);
+    ra->freeI32(p);
+    ra->freeI32(lim);
+    ra->freeI32(zero);
 }
 
 // The baseline compiler proper.
 
 class BaseCompiler final : public BaseCompilerInterface
 {
     typedef BaseStackFrame::Local Local;
     typedef Vector<NonAssertingLabel, 8, SystemAllocPolicy> LabelVector;
@@ -2227,85 +2227,85 @@ class BaseCompiler final : public BaseCo
 
     Vector<Stk, 8, SystemAllocPolicy> stk_;
 
     Stk& push() {
         stk_.infallibleEmplaceBack(Stk());
         return stk_.back();
     }
 
-    void loadConstI32(Stk& src, RegI32 dest) {
+    void loadConstI32(const Stk& src, RegI32 dest) {
         moveImm32(src.i32val(), dest);
     }
 
-    void loadMemI32(Stk& src, RegI32 dest) {
+    void loadMemI32(const Stk& src, RegI32 dest) {
         fr.loadStackI32(src.offs(), dest);
     }
 
-    void loadLocalI32(Stk& src, RegI32 dest) {
+    void loadLocalI32(const Stk& src, RegI32 dest) {
         fr.loadLocalI32(localFromSlot(src.slot(), MIRType::Int32), dest);
     }
 
-    void loadRegisterI32(Stk& src, RegI32 dest) {
+    void loadRegisterI32(const Stk& src, RegI32 dest) {
         moveI32(src.i32reg(), dest);
     }
 
-    void loadConstI64(Stk &src, RegI64 dest) {
+    void loadConstI64(const Stk& src, RegI64 dest) {
         moveImm64(src.i64val(), dest);
     }
 
-    void loadMemI64(Stk& src, RegI64 dest) {
+    void loadMemI64(const Stk& src, RegI64 dest) {
         fr.loadStackI64(src.offs(), dest);
     }
 
-    void loadLocalI64(Stk& src, RegI64 dest) {
+    void loadLocalI64(const Stk& src, RegI64 dest) {
         fr.loadLocalI64(localFromSlot(src.slot(), MIRType::Int64), dest);
     }
 
-    void loadRegisterI64(Stk& src, RegI64 dest) {
+    void loadRegisterI64(const Stk& src, RegI64 dest) {
         moveI64(src.i64reg(), dest);
     }
 
-    void loadConstF64(Stk &src, RegF64 dest) {
+    void loadConstF64(const Stk& src, RegF64 dest) {
         double d;
         src.f64val(&d);
         masm.loadConstantDouble(d, dest);
     }
 
-    void loadMemF64(Stk& src, RegF64 dest) {
+    void loadMemF64(const Stk& src, RegF64 dest) {
         fr.loadStackF64(src.offs(), dest);
     }
 
-    void loadLocalF64(Stk& src, RegF64 dest) {
+    void loadLocalF64(const Stk& src, RegF64 dest) {
         fr.loadLocalF64(localFromSlot(src.slot(), MIRType::Double), dest);
     }
 
-    void loadRegisterF64(Stk& src, RegF64 dest) {
+    void loadRegisterF64(const Stk& src, RegF64 dest) {
         moveF64(src.f64reg(), dest);
     }
 
-    void loadConstF32(Stk &src, RegF32 dest) {
+    void loadConstF32(const Stk& src, RegF32 dest) {
         float f;
         src.f32val(&f);
         masm.loadConstantFloat32(f, dest);
     }
 
-    void loadMemF32(Stk& src, RegF32 dest) {
+    void loadMemF32(const Stk& src, RegF32 dest) {
         fr.loadStackF32(src.offs(), dest);
     }
 
-    void loadLocalF32(Stk& src, RegF32 dest) {
+    void loadLocalF32(const Stk& src, RegF32 dest) {
         fr.loadLocalF32(localFromSlot(src.slot(), MIRType::Float32), dest);
     }
 
-    void loadRegisterF32(Stk& src, RegF32 dest) {
+    void loadRegisterF32(const Stk& src, RegF32 dest) {
         moveF32(src.f32reg(), dest);
     }
 
-    void loadI32(Stk& src, RegI32 dest) {
+    void loadI32(const Stk& src, RegI32 dest) {
         switch (src.kind()) {
           case Stk::ConstI32:
             loadConstI32(src, dest);
             break;
           case Stk::MemI32:
             loadMemI32(src, dest);
             break;
           case Stk::LocalI32:
@@ -2315,17 +2315,17 @@ class BaseCompiler final : public BaseCo
             loadRegisterI32(src, dest);
             break;
           case Stk::None:
           default:
             MOZ_CRASH("Compiler bug: Expected I32 on stack");
         }
     }
 
-    void loadI64(Stk& src, RegI64 dest) {
+    void loadI64(const Stk& src, RegI64 dest) {
         switch (src.kind()) {
           case Stk::ConstI64:
             loadConstI64(src, dest);
             break;
           case Stk::MemI64:
             loadMemI64(src, dest);
             break;
           case Stk::LocalI64:
@@ -2336,17 +2336,17 @@ class BaseCompiler final : public BaseCo
             break;
           case Stk::None:
           default:
             MOZ_CRASH("Compiler bug: Expected I64 on stack");
         }
     }
 
 #if !defined(JS_PUNBOX64)
-    void loadI64Low(Stk& src, RegI32 dest) {
+    void loadI64Low(const Stk& src, RegI32 dest) {
         switch (src.kind()) {
           case Stk::ConstI64:
             moveImm32(int32_t(src.i64val()), dest);
             break;
           case Stk::MemI64:
             fr.loadStackI64Low(src.offs(), dest);
             break;
           case Stk::LocalI64:
@@ -2356,17 +2356,17 @@ class BaseCompiler final : public BaseCo
             moveI32(RegI32(src.i64reg().low), dest);
             break;
           case Stk::None:
           default:
             MOZ_CRASH("Compiler bug: Expected I64 on stack");
         }
     }
 
-    void loadI64High(Stk& src, RegI32 dest) {
+    void loadI64High(const Stk& src, RegI32 dest) {
         switch (src.kind()) {
           case Stk::ConstI64:
             moveImm32(int32_t(src.i64val() >> 32), dest);
             break;
           case Stk::MemI64:
             fr.loadStackI64High(src.offs(), dest);
             break;
           case Stk::LocalI64:
@@ -2377,17 +2377,17 @@ class BaseCompiler final : public BaseCo
             break;
           case Stk::None:
           default:
             MOZ_CRASH("Compiler bug: Expected I64 on stack");
         }
     }
 #endif
 
-    void loadF64(Stk& src, RegF64 dest) {
+    void loadF64(const Stk& src, RegF64 dest) {
         switch (src.kind()) {
           case Stk::ConstF64:
             loadConstF64(src, dest);
             break;
           case Stk::MemF64:
             loadMemF64(src, dest);
             break;
           case Stk::LocalF64:
@@ -2397,17 +2397,17 @@ class BaseCompiler final : public BaseCo
             loadRegisterF64(src, dest);
             break;
           case Stk::None:
           default:
             MOZ_CRASH("Compiler bug: expected F64 on stack");
         }
     }
 
-    void loadF32(Stk& src, RegF32 dest) {
+    void loadF32(const Stk& src, RegF32 dest) {
         switch (src.kind()) {
           case Stk::ConstF32:
             loadConstF32(src, dest);
             break;
           case Stk::MemF32:
             loadMemF32(src, dest);
             break;
           case Stk::LocalF32:
@@ -2625,17 +2625,17 @@ class BaseCompiler final : public BaseCo
     void pushLocalF32(uint32_t slot) {
         Stk& x = push();
         x.setSlot(Stk::LocalF32, slot);
     }
 
     // Call only from other popI32() variants.
     // v must be the stack top.  May pop the CPU stack.
 
-    void popI32(Stk& v, RegI32 dest) {
+    void popI32(const Stk& v, RegI32 dest) {
         MOZ_ASSERT(&v == &stk_.back());
         switch (v.kind()) {
           case Stk::ConstI32:
             loadConstI32(v, dest);
             break;
           case Stk::LocalI32:
             loadLocalI32(v, dest);
             break;
@@ -2674,17 +2674,17 @@ class BaseCompiler final : public BaseCo
 
         stk_.popBack();
         return specific;
     }
 
     // Call only from other popI64() variants.
     // v must be the stack top.  May pop the CPU stack.
 
-    void popI64(Stk& v, RegI64 dest) {
+    void popI64(const Stk& v, RegI64 dest) {
         MOZ_ASSERT(&v == &stk_.back());
         switch (v.kind()) {
           case Stk::ConstI64:
             loadConstI64(v, dest);
             break;
           case Stk::LocalI64:
             loadLocalI64(v, dest);
             break;
@@ -2733,17 +2733,17 @@ class BaseCompiler final : public BaseCo
 
         stk_.popBack();
         return specific;
     }
 
     // Call only from other popF64() variants.
     // v must be the stack top.  May pop the CPU stack.
 
-    void popF64(Stk& v, RegF64 dest) {
+    void popF64(const Stk& v, RegF64 dest) {
         MOZ_ASSERT(&v == &stk_.back());
         switch (v.kind()) {
           case Stk::ConstF64:
             loadConstF64(v, dest);
             break;
           case Stk::LocalF64:
             loadLocalF64(v, dest);
             break;
@@ -2782,17 +2782,17 @@ class BaseCompiler final : public BaseCo
 
         stk_.popBack();
         return specific;
     }
 
     // Call only from other popF32() variants.
     // v must be the stack top.  May pop the CPU stack.
 
-    void popF32(Stk& v, RegF32 dest) {
+    void popF32(const Stk& v, RegF32 dest) {
         MOZ_ASSERT(&v == &stk_.back());
         switch (v.kind()) {
           case Stk::ConstF32:
             loadConstF32(v, dest);
             break;
           case Stk::LocalF32:
             loadLocalF32(v, dest);
             break;
@@ -3205,17 +3205,17 @@ class BaseCompiler final : public BaseCo
                 if (i->argInRegister())
                     fr.storeLocalF32(RegF32(i->fpu()), l);
                 break;
               default:
                 MOZ_CRASH("Function argument type");
             }
         }
 
-        fr.zeroLocals(ra);
+        fr.zeroLocals(&ra);
 
         if (debugEnabled_)
             insertBreakablePoint(CallSiteDesc::EnterFrame);
     }
 
     void saveResult() {
         MOZ_ASSERT(debugEnabled_);
         size_t debugFrameOffset = masm.framePushed() - DebugFrame::offsetOfFrame();
@@ -3392,26 +3392,26 @@ class BaseCompiler final : public BaseCo
     template<class T>
     size_t stackArgAreaSize(const T& args) {
         ABIArgIter<const T> i(args);
         while (!i.done())
             i++;
         return AlignBytes(i.stackBytesConsumedSoFar(), 16u);
     }
 
-    void startCallArgs(FunctionCall& call, size_t stackArgAreaSize)
+    void startCallArgs(size_t stackArgAreaSize, FunctionCall* call)
     {
-        call.stackArgAreaSize = stackArgAreaSize;
-
-        size_t adjustment = call.stackArgAreaSize + call.frameAlignAdjustment;
+        call->stackArgAreaSize = stackArgAreaSize;
+
+        size_t adjustment = call->stackArgAreaSize + call->frameAlignAdjustment;
         fr.allocArgArea(adjustment);
     }
 
-    const ABIArg reservePointerArgument(FunctionCall& call) {
-        return call.abi.next(MIRType::Pointer);
+    const ABIArg reservePointerArgument(FunctionCall* call) {
+        return call->abi.next(MIRType::Pointer);
     }
 
     // TODO / OPTIMIZE (Bug 1316821): Note passArg is used only in one place.
     // (Or it was, until Luke wandered through, but that can be fixed again.)
     // I'm not saying we should manually inline it, but we could hoist the
     // dispatch into the caller and have type-specific implementations of
     // passArg: passArgI32(), etc.  Then those might be inlined, at least in PGO
     // builds.
@@ -3425,31 +3425,31 @@ class BaseCompiler final : public BaseCo
     // argument types (read from the input stream) leads to a cached
     // entry for stackArgAreaSize() and for how to pass arguments...
     //
     // But at least we could reduce the cost of stackArgAreaSize() by
     // first reading the argument types into a (reusable) vector, then
     // we have the outgoing size at low cost, and then we can pass
     // args based on the info we read.
 
-    void passArg(FunctionCall& call, ValType type, Stk& arg) {
+    void passArg(ValType type, const Stk& arg, FunctionCall* call) {
         switch (type) {
           case ValType::I32: {
-            ABIArg argLoc = call.abi.next(MIRType::Int32);
+            ABIArg argLoc = call->abi.next(MIRType::Int32);
             if (argLoc.kind() == ABIArg::Stack) {
                 ScratchI32 scratch(*this);
                 loadI32(arg, scratch);
                 masm.store32(scratch, Address(masm.getStackPointer(), argLoc.offsetFromArgBase()));
             } else {
                 loadI32(arg, RegI32(argLoc.gpr()));
             }
             break;
           }
           case ValType::I64: {
-            ABIArg argLoc = call.abi.next(MIRType::Int64);
+            ABIArg argLoc = call->abi.next(MIRType::Int64);
             if (argLoc.kind() == ABIArg::Stack) {
                 ScratchI32 scratch(*this);
 #ifdef JS_PUNBOX64
                 loadI64(arg, fromI32(scratch));
                 masm.storePtr(scratch, Address(masm.getStackPointer(), argLoc.offsetFromArgBase()));
 #else
                 loadI64Low(arg, scratch);
                 masm.store32(scratch, LowWord(Address(masm.getStackPointer(), argLoc.offsetFromArgBase())));
@@ -3457,17 +3457,17 @@ class BaseCompiler final : public BaseCo
                 masm.store32(scratch, HighWord(Address(masm.getStackPointer(), argLoc.offsetFromArgBase())));
 #endif
             } else {
                 loadI64(arg, RegI64(argLoc.gpr64()));
             }
             break;
           }
           case ValType::F64: {
-            ABIArg argLoc = call.abi.next(MIRType::Double);
+            ABIArg argLoc = call->abi.next(MIRType::Double);
             switch (argLoc.kind()) {
               case ABIArg::Stack: {
                 ScratchF64 scratch(*this);
                 loadF64(arg, scratch);
                 masm.storeDouble(scratch, Address(masm.getStackPointer(), argLoc.offsetFromArgBase()));
                 break;
               }
 #if defined(JS_CODEGEN_REGISTER_PAIR)
@@ -3497,17 +3497,17 @@ class BaseCompiler final : public BaseCo
                 MOZ_CRASH("Unexpected parameter passing discipline");
               }
               case ABIArg::Uninitialized:
                 MOZ_CRASH("Uninitialized ABIArg kind");
             }
             break;
           }
           case ValType::F32: {
-            ABIArg argLoc = call.abi.next(MIRType::Float32);
+            ABIArg argLoc = call->abi.next(MIRType::Float32);
             switch (argLoc.kind()) {
               case ABIArg::Stack: {
                 ScratchF32 scratch(*this);
                 loadF32(arg, scratch);
                 masm.storeFloat32(scratch, Address(masm.getStackPointer(), argLoc.offsetFromArgBase()));
                 break;
               }
               case ABIArg::GPR: {
@@ -3543,17 +3543,17 @@ class BaseCompiler final : public BaseCo
 
     void callSymbolic(SymbolicAddress callee, const FunctionCall& call) {
         CallSiteDesc desc(call.lineOrBytecode, CallSiteDesc::Symbolic);
         masm.call(desc, callee);
     }
 
     // Precondition: sync()
 
-    void callIndirect(uint32_t sigIndex, Stk& indexVal, const FunctionCall& call)
+    void callIndirect(uint32_t sigIndex, const Stk& indexVal, const FunctionCall& call)
     {
         const SigWithId& sig = env_.sigs[sigIndex];
         MOZ_ASSERT(sig.id.kind() != SigIdDesc::Kind::None);
 
         MOZ_ASSERT(env_.tables.length() == 1);
         const TableDesc& table = env_.tables[0];
 
         loadI32(indexVal, RegI32(WasmTableCallIndexReg));
@@ -5561,17 +5561,17 @@ class BaseCompiler final : public BaseCo
     MOZ_MUST_USE bool emitIf();
     MOZ_MUST_USE bool emitElse();
     MOZ_MUST_USE bool emitEnd();
     MOZ_MUST_USE bool emitBr();
     MOZ_MUST_USE bool emitBrIf();
     MOZ_MUST_USE bool emitBrTable();
     MOZ_MUST_USE bool emitDrop();
     MOZ_MUST_USE bool emitReturn();
-    MOZ_MUST_USE bool emitCallArgs(const ValTypeVector& args, FunctionCall& baselineCall);
+    MOZ_MUST_USE bool emitCallArgs(const ValTypeVector& args, FunctionCall* baselineCall);
     MOZ_MUST_USE bool emitCall();
     MOZ_MUST_USE bool emitCallIndirect();
     MOZ_MUST_USE bool emitUnaryMathBuiltinCall(SymbolicAddress callee, ValType operandType);
     MOZ_MUST_USE bool emitGetLocal();
     MOZ_MUST_USE bool emitSetLocal();
     MOZ_MUST_USE bool emitTeeLocal();
     MOZ_MUST_USE bool emitGetGlobal();
     MOZ_MUST_USE bool emitSetGlobal();
@@ -7545,25 +7545,25 @@ BaseCompiler::emitReturn()
 
     doReturn(sig().ret(), PopStack(true));
     deadCode_ = true;
 
     return true;
 }
 
 bool
-BaseCompiler::emitCallArgs(const ValTypeVector& argTypes, FunctionCall& baselineCall)
+BaseCompiler::emitCallArgs(const ValTypeVector& argTypes, FunctionCall* baselineCall)
 {
     MOZ_ASSERT(!deadCode_);
 
-    startCallArgs(baselineCall, stackArgAreaSize(argTypes));
+    startCallArgs(stackArgAreaSize(argTypes), baselineCall);
 
     uint32_t numArgs = argTypes.length();
     for (size_t i = 0; i < numArgs; ++i)
-        passArg(baselineCall, argTypes[i], peek(numArgs - 1 - i));
+        passArg(argTypes[i], peek(numArgs - 1 - i), baselineCall);
 
     masm.loadWasmTlsRegFromFrame();
     return true;
 }
 
 void
 BaseCompiler::pushReturned(const FunctionCall& call, ExprType type)
 {
@@ -7628,17 +7628,17 @@ BaseCompiler::emitCall()
     bool import = env_.funcIsImport(funcIndex);
 
     uint32_t numArgs = sig.args().length();
     size_t stackSpace = stackConsumed(numArgs);
 
     FunctionCall baselineCall(lineOrBytecode);
     beginCall(baselineCall, UseABI::Wasm, import ? InterModule::True : InterModule::False);
 
-    if (!emitCallArgs(sig.args(), baselineCall))
+    if (!emitCallArgs(sig.args(), &baselineCall))
         return false;
 
     if (import)
         callImport(env_.funcImportGlobalDataOffsets[funcIndex], baselineCall);
     else
         callDefinition(funcIndex, baselineCall);
 
     endCall(baselineCall, stackSpace);
@@ -7678,17 +7678,17 @@ BaseCompiler::emitCallIndirect()
     // callee if it is on top.  Note this only pops the compiler's stack,
     // not the CPU stack.
 
     Stk callee = stk_.popCopy();
 
     FunctionCall baselineCall(lineOrBytecode);
     beginCall(baselineCall, UseABI::Wasm, InterModule::True);
 
-    if (!emitCallArgs(sig.args(), baselineCall))
+    if (!emitCallArgs(sig.args(), &baselineCall))
         return false;
 
     callIndirect(sigIndex, callee, baselineCall);
 
     endCall(baselineCall, stackSpace);
 
     popValueStackBy(numArgs);
 
@@ -7737,17 +7737,17 @@ BaseCompiler::emitUnaryMathBuiltinCall(S
     ValTypeVector& signature = operandType == ValType::F32 ? SigF_ : SigD_;
     ExprType retType = operandType == ValType::F32 ? ExprType::F32 : ExprType::F64;
     uint32_t numArgs = signature.length();
     size_t stackSpace = stackConsumed(numArgs);
 
     FunctionCall baselineCall(lineOrBytecode);
     beginCall(baselineCall, UseABI::System, InterModule::False);
 
-    if (!emitCallArgs(signature, baselineCall))
+    if (!emitCallArgs(signature, &baselineCall))
         return false;
 
     builtinCall(callee, baselineCall);
 
     endCall(baselineCall, stackSpace);
 
     popValueStackBy(numArgs);
 
@@ -8584,27 +8584,27 @@ BaseCompiler::emitInstanceCall(uint32_t 
     sync();
 
     uint32_t numArgs = sig.length() - 1 /* instance */;
     size_t stackSpace = stackConsumed(numArgs);
 
     FunctionCall baselineCall(lineOrBytecode);
     beginCall(baselineCall, UseABI::System, InterModule::True);
 
-    ABIArg instanceArg = reservePointerArgument(baselineCall);
-
-    startCallArgs(baselineCall, stackArgAreaSize(sig));
+    ABIArg instanceArg = reservePointerArgument(&baselineCall);
+
+    startCallArgs(stackArgAreaSize(sig), &baselineCall);
     for (uint32_t i = 1; i < sig.length(); i++) {
         ValType t;
         switch (sig[i]) {
           case MIRType::Int32: t = ValType::I32; break;
           case MIRType::Int64: t = ValType::I64; break;
           default:             MOZ_CRASH("Unexpected type");
         }
-        passArg(baselineCall, t, peek(numArgs - i));
+        passArg(t, peek(numArgs - i), &baselineCall);
     }
     builtinInstanceMethodCall(builtin, instanceArg, baselineCall);
     endCall(baselineCall, stackSpace);
 
     popValueStackBy(numArgs);
 
     pushReturned(baselineCall, retType);
 }
--- a/js/xpconnect/loader/ScriptPreloader.cpp
+++ b/js/xpconnect/loader/ScriptPreloader.cpp
@@ -47,16 +47,26 @@ static LazyLogModule gLog("ScriptPreload
 
 using mozilla::dom::AutoJSAPI;
 using mozilla::dom::ContentChild;
 using mozilla::dom::ContentParent;
 using namespace mozilla::loader;
 
 ProcessType ScriptPreloader::sProcessType;
 
+// This type correspond to js::vm::XDRAlignment type, which is used as a size
+// reference for alignment of XDR buffers.
+using XDRAlign = uint16_t;
+static const uint8_t sAlignPadding[sizeof(XDRAlign)] = { 0, 0 };
+
+static inline size_t
+ComputeByteAlignment(size_t bytes, size_t align)
+{
+    return (align - (bytes % align)) % align;
+}
 
 nsresult
 ScriptPreloader::CollectReports(nsIHandleReportCallback* aHandleReport,
                                 nsISupports* aData, bool aAnonymize)
 {
     MOZ_COLLECT_REPORT(
         "explicit/script-preloader/heap/saved-scripts", KIND_HEAP, UNITS_BYTES,
         SizeOfHashEntries<ScriptStatus::Saved>(mScripts, MallocSizeOf),
@@ -455,16 +465,18 @@ ScriptPreloader::InitCacheInternal(JS::H
     auto size = mCacheData.size();
 
     uint32_t headerSize;
     if (size < sizeof(MAGIC) + sizeof(headerSize)) {
         return Err(NS_ERROR_UNEXPECTED);
     }
 
     auto data = mCacheData.get<uint8_t>();
+    uint8_t* start = data.get();
+    MOZ_ASSERT(reinterpret_cast<uintptr_t>(start) % sizeof(XDRAlign) == 0);
     auto end = data + size;
 
     if (memcmp(MAGIC, data.get(), sizeof(MAGIC))) {
         return Err(NS_ERROR_UNEXPECTED);
     }
     data += sizeof(MAGIC);
 
     headerSize = LittleEndian::readUint32(data.get());
@@ -481,16 +493,20 @@ ScriptPreloader::InitCacheInternal(JS::H
 
         LinkedList<CachedScript> scripts;
 
         Range<uint8_t> header(data, data + headerSize);
         data += headerSize;
 
         InputBuffer buf(header);
 
+        size_t len = data.get() - start;
+        size_t alignLen = ComputeByteAlignment(len, sizeof(XDRAlign));
+        data += alignLen;
+
         size_t offset = 0;
         while (!buf.finished()) {
             auto script = MakeUnique<CachedScript>(*this, buf);
             MOZ_RELEASE_ASSERT(script);
 
             auto scriptData = data + script->mOffset;
             if (scriptData + script->mSize > end) {
                 return Err(NS_ERROR_UNEXPECTED);
@@ -498,16 +514,17 @@ ScriptPreloader::InitCacheInternal(JS::H
 
             // Make sure offsets match what we'd expect based on script ordering and
             // size, as a basic sanity check.
             if (script->mOffset != offset) {
                 return Err(NS_ERROR_UNEXPECTED);
             }
             offset += script->mSize;
 
+            MOZ_ASSERT(reinterpret_cast<uintptr_t>(scriptData.get()) % sizeof(XDRAlign) == 0);
             script->mXDRRange.emplace(scriptData, scriptData + script->mSize);
 
             // Don't pre-decode the script unless it was used in this process type during the
             // previous session.
             if (script->mOriginalProcessTypes.contains(CurrentProcessType())) {
                 scripts.insertBack(script.get());
             } else {
                 script->mReadyToExecute = true;
@@ -652,30 +669,42 @@ ScriptPreloader::WriteCache()
         // Sort scripts by load time, with async loaded scripts before sync scripts.
         // Since async scripts are always loaded immediately at startup, it helps to
         // have them stored contiguously.
         scripts.Sort(CachedScript::Comparator());
 
         OutputBuffer buf;
         size_t offset = 0;
         for (auto script : scripts) {
+            MOZ_ASSERT(offset % sizeof(XDRAlign) == 0);
             script->mOffset = offset;
             script->Code(buf);
 
             offset += script->mSize;
         }
 
         uint8_t headerSize[4];
         LittleEndian::writeUint32(headerSize, buf.cursor());
 
+        size_t len = 0;
         MOZ_TRY(Write(fd, MAGIC, sizeof(MAGIC)));
+        len += sizeof(MAGIC);
         MOZ_TRY(Write(fd, headerSize, sizeof(headerSize)));
+        len += sizeof(headerSize);
         MOZ_TRY(Write(fd, buf.Get(), buf.cursor()));
+        len += buf.cursor();
+        size_t alignLen = ComputeByteAlignment(len, sizeof(XDRAlign));
+        if (alignLen) {
+            MOZ_TRY(Write(fd, sAlignPadding, alignLen));
+            len += alignLen;
+        }
         for (auto script : scripts) {
+            MOZ_ASSERT(script->mSize % sizeof(XDRAlign) == 0);
             MOZ_TRY(Write(fd, script->Range().begin().get(), script->mSize));
+            len += script->mSize;
 
             if (script->mScript) {
                 script->FreeData();
             }
         }
     }
 
     MOZ_TRY(cacheFile->MoveTo(nullptr, mBaseName + NS_LITERAL_STRING(".bin")));
--- a/memory/build/mozmemory_wrap.cpp
+++ b/memory/build/mozmemory_wrap.cpp
@@ -26,23 +26,23 @@ operator new(size_t size)
 
 MFBT_API void*
 operator new[](size_t size)
 {
   return malloc_impl(size);
 }
 
 MFBT_API void
-operator delete(void* ptr)
+operator delete(void* ptr) noexcept(true)
 {
   free_impl(ptr);
 }
 
 MFBT_API void
-operator delete[](void* ptr)
+operator delete[](void* ptr) noexcept(true)
 {
   free_impl(ptr);
 }
 
 MFBT_API void*
 operator new(size_t size, std::nothrow_t const&)
 {
   return malloc_impl(size);
@@ -50,23 +50,23 @@ operator new(size_t size, std::nothrow_t
 
 MFBT_API void*
 operator new[](size_t size, std::nothrow_t const&)
 {
   return malloc_impl(size);
 }
 
 MFBT_API void
-operator delete(void* ptr, std::nothrow_t const&)
+operator delete(void* ptr, std::nothrow_t const&) noexcept(true)
 {
   free_impl(ptr);
 }
 
 MFBT_API void
-operator delete[](void* ptr, std::nothrow_t const&)
+operator delete[](void* ptr, std::nothrow_t const&) noexcept(true)
 {
   free_impl(ptr);
 }
 #endif
 
 // strndup and strdup may be defined as macros in string.h, which would
 // clash with the definitions below.
 #undef strndup
--- a/mfbt/HashFunctions.h
+++ b/mfbt/HashFunctions.h
@@ -347,30 +347,29 @@ private:
 
       // 3. Finalization.
       mV2 ^= 0xff;
       for (int i = 0; i < 3; i++)
         sipRound();
       return mV0 ^ mV1 ^ mV2 ^ mV3;
     }
 
-    MOZ_NO_SANITIZE_UNSIGNED_OVERFLOW
     void sipRound()
     {
-      mV0 += mV1;
+      mV0 = WrappingAdd(mV0, mV1);
       mV1 = RotateLeft(mV1, 13);
       mV1 ^= mV0;
       mV0 = RotateLeft(mV0, 32);
-      mV2 += mV3;
+      mV2 = WrappingAdd(mV2, mV3);
       mV3 = RotateLeft(mV3, 16);
       mV3 ^= mV2;
-      mV0 += mV3;
+      mV0 = WrappingAdd(mV0, mV3);
       mV3 = RotateLeft(mV3, 21);
       mV3 ^= mV0;
-      mV2 += mV1;
+      mV2 = WrappingAdd(mV2, mV1);
       mV1 = RotateLeft(mV1, 17);
       mV1 ^= mV2;
       mV2 = RotateLeft(mV2, 32);
     }
 
     uint64_t mV0, mV1, mV2, mV3;
   };
 };
--- a/mfbt/WrappingOperations.h
+++ b/mfbt/WrappingOperations.h
@@ -1,18 +1,29 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /*
- * Math operations that implement wraparound semantics on overflow or underflow
- * without performing C++ undefined behavior or tripping up compiler-based
- * integer-overflow sanitizers.
+ * Math operations that implement wraparound semantics on overflow or underflow.
+ *
+ * While in some cases (but not all of them!) plain old C++ operators and casts
+ * will behave just like these functions, there are three reasons you should use
+ * these functions:
+ *
+ *   1) These functions make *explicit* the desire for and dependence upon
+ *      wraparound semantics, just as Rust's i32::wrapping_add and similar
+ *      functions explicitly produce wraparound in Rust.
+ *   2) They implement this functionality *safely*, without invoking signed
+ *      integer overflow that has undefined behavior in C++.
+ *   3) They play nice with compiler-based integer-overflow sanitizers (see
+ *      build/autoconf/sanitize.m4), that in appropriately configured builds
+ *      verify at runtime that integral arithmetic doesn't overflow.
  */
 
 #ifndef mozilla_WrappingOperations_h
 #define mozilla_WrappingOperations_h
 
 #include "mozilla/Attributes.h"
 #include "mozilla/TypeTraits.h"
 
@@ -84,102 +95,191 @@ struct WrapToSignedHelper
  */
 template<typename UnsignedType>
 inline constexpr typename detail::WrapToSignedHelper<UnsignedType>::SignedType
 WrapToSigned(UnsignedType aValue)
 {
   return detail::WrapToSignedHelper<UnsignedType>::compute(aValue);
 }
 
+// The |mozilla::Wrapping*| functions aren't constexpr because MSVC warns about
+// well-defined unsigned integer overflows that may occur within the constexpr
+// math.  If/when MSVC fix this bug, we should make them all constexpr.
+//
+//   https://msdn.microsoft.com/en-us/library/4kze989h.aspx (C4307)
+//   https://developercommunity.visualstudio.com/content/problem/211134/unsigned-integer-overflows-in-constexpr-functionsa.html (bug report)
+//
+// For now there's no practical, readable way to avoid such overflows in pure
+// C++.  And we can't add narrow #pragmas where overflow can occur to disable
+// the warnings, because constexpr apparently causes the warning to be emitted
+// at the outermost call *sites* (so every user of |mozilla::Wrapping*| would
+// have to add them).
+
+namespace detail {
+
+template<typename T>
+inline constexpr T
+ToResult(typename MakeUnsigned<T>::Type aUnsigned)
+{
+  // We could *always* return WrapToSigned and rely on unsigned conversion to
+  // undo the wrapping when |T| is unsigned, but this seems clearer.
+  return IsSigned<T>::value ? WrapToSigned(aUnsigned) : aUnsigned;
+}
+
+template<typename T>
+struct WrappingAddHelper
+{
+private:
+  using UnsignedT = typename MakeUnsigned<T>::Type;
+
+public:
+  MOZ_NO_SANITIZE_UNSIGNED_OVERFLOW
+  static T compute(T aX, T aY)
+  {
+    return ToResult<T>(static_cast<UnsignedT>(aX) + static_cast<UnsignedT>(aY));
+  }
+};
+
+} // namespace detail
+
+/**
+ * Add two integers of the same type and return the result converted to that
+ * type using wraparound semantics, without triggering overflow sanitizers.
+ *
+ * For N-bit unsigned integer types, this is equivalent to adding the two
+ * numbers, then taking the result mod 2**N:
+ *
+ *   WrappingAdd(uint32_t(42), uint32_t(17)) is 59 (59 mod 2**32);
+ *   WrappingAdd(uint8_t(240), uint8_t(20)) is 4 (260 mod 2**8).
+ *
+ * Unsigned WrappingAdd acts exactly like C++ unsigned addition.
+ *
+ * For N-bit signed integer types, this is equivalent to adding the two numbers
+ * wrapped to unsigned, then wrapping the sum mod 2**N to the signed range:
+ *
+ *   WrappingAdd(int16_t(32767), int16_t(3)) is -32766 ((32770 mod 2**16) - 2**16);
+ *   WrappingAdd(int8_t(-128), int8_t(-128)) is 0 (256 mod 2**8);
+ *   WrappingAdd(int32_t(-42), int32_t(-17)) is -59 ((8589934533 mod 2**32) - 2**32).
+ *
+ * There's no equivalent to this operation in C++, as C++ signed addition that
+ * overflows has undefined behavior.  But it's how such addition *tends* to
+ * behave with most compilers, unless an optimization or similar -- quite
+ * permissibly -- triggers different behavior.
+ */
+template<typename T>
+inline T
+WrappingAdd(T aX, T aY)
+{
+  return detail::WrappingAddHelper<T>::compute(aX, aY);
+}
+
+namespace detail {
+
+template<typename T>
+struct WrappingSubtractHelper
+{
+private:
+  using UnsignedT = typename MakeUnsigned<T>::Type;
+
+public:
+  MOZ_NO_SANITIZE_UNSIGNED_OVERFLOW
+  static T compute(T aX, T aY)
+  {
+    return ToResult<T>(static_cast<UnsignedT>(aX) - static_cast<UnsignedT>(aY));
+  }
+};
+
+} // namespace detail
+
+/**
+ * Subtract two integers of the same type and return the result converted to
+ * that type using wraparound semantics, without triggering overflow sanitizers.
+ *
+ * For N-bit unsigned integer types, this is equivalent to subtracting the two
+ * numbers, then taking the result mod 2**N:
+ *
+ *   WrappingSubtract(uint32_t(42), uint32_t(17)) is 29 (29 mod 2**32);
+ *   WrappingSubtract(uint8_t(5), uint8_t(20)) is 241 (-15 mod 2**8).
+ *
+ * Unsigned WrappingSubtract acts exactly like C++ unsigned subtraction.
+ *
+ * For N-bit signed integer types, this is equivalent to subtracting the two
+ * numbers wrapped to unsigned, then wrapping the difference mod 2**N to the
+ * signed range:
+ *
+ *   WrappingSubtract(int16_t(32767), int16_t(-5)) is -32764 ((32772 mod 2**16) - 2**16);
+ *   WrappingSubtract(int8_t(-128), int8_t(127)) is 1 (-255 mod 2**8);
+ *   WrappingSubtract(int32_t(-17), int32_t(-42)) is 25 (25 mod 2**32).
+ *
+ * There's no equivalent to this operation in C++, as C++ signed subtraction
+ * that overflows has undefined behavior.  But it's how such subtraction *tends*
+ * to behave with most compilers, unless an optimization or similar -- quite
+ * permissibly -- triggers different behavior.
+ */
+template<typename T>
+inline T
+WrappingSubtract(T aX, T aY)
+{
+  return detail::WrappingSubtractHelper<T>::compute(aX, aY);
+}
+
 namespace detail {
 
 template<typename T>
 struct WrappingMultiplyHelper
 {
 private:
   using UnsignedT = typename MakeUnsigned<T>::Type;
 
-  MOZ_NO_SANITIZE_UNSIGNED_OVERFLOW
-  static UnsignedT
-  multiply(UnsignedT aX, UnsignedT aY)
-  {
-  // |mozilla::WrappingMultiply| isn't constexpr because MSVC warns about well-
-  // defined unsigned integer overflows that may happen here.
-  // https://msdn.microsoft.com/en-us/library/4kze989h.aspx  And constexpr
-  // seems to cause the warning to be emitted at |WrappingMultiply| call *sites*
-  // instead of here, so these #pragmas are ineffective.
-  //
-  // https://stackoverflow.com/questions/37658794/integer-constant-overflow-warning-in-constexpr
-  //
-  // If/when MSVC fix this bug, we should make these functions constexpr.
-
-    // Begin with |1U| to ensure the overall operation chain is never promoted
-    // to signed integer operations that might have *signed* integer overflow.
-    return static_cast<UnsignedT>(1U * aX * aY);
-  }
-
-  static T
-  toResult(UnsignedT aX, UnsignedT aY)
-  {
-    // We could always return WrapToSigned and rely on unsigned conversion
-    // undoing the wrapping when |T| is unsigned, but this seems clearer.
-    return IsSigned<T>::value
-           ? WrapToSigned(multiply(aX, aY))
-           : multiply(aX, aY);
-  }
-
 public:
   MOZ_NO_SANITIZE_UNSIGNED_OVERFLOW
   static T compute(T aX, T aY)
   {
-    return toResult(static_cast<UnsignedT>(aX), static_cast<UnsignedT>(aY));
+    // Begin with |1U| to ensure the overall operation chain is never promoted
+    // to signed integer operations that might have *signed* integer overflow.
+    return ToResult<T>(static_cast<UnsignedT>(1U *
+                                              static_cast<UnsignedT>(aX) *
+                                              static_cast<UnsignedT>(aY)));
   }
 };
 
 } // namespace detail
 
 /**
- * Multiply two integers of the same type, and return the result converted to
- * that type using wraparound semantics.  This function:
- *
- *   1) makes explicit the desire for and dependence upon wraparound semantics,
- *   2) provides wraparound semantics *safely* with no signed integer overflow
- *      that would have undefined behavior, and
- *   3) won't trip up {,un}signed-integer overflow sanitizers (see
- *      build/autoconf/sanitize.m4) at runtime.
+ * Multiply two integers of the same type and return the result converted to
+ * that type using wraparound semantics, without triggering overflow sanitizers.
  *
  * For N-bit unsigned integer types, this is equivalent to multiplying the two
  * numbers, then taking the result mod 2**N:
  *
  *   WrappingMultiply(uint32_t(42), uint32_t(17)) is 714 (714 mod 2**32);
  *   WrappingMultiply(uint8_t(16), uint8_t(24)) is 128 (384 mod 2**8);
  *   WrappingMultiply(uint16_t(3), uint16_t(32768)) is 32768 (98304 mod 2*16).
  *
- * Use this function for any unsigned multiplication that can wrap (instead of
- * normal C++ multiplication) to play nice with the sanitizers.  But it's
- * especially important to use it for uint16_t multiplication: in most compilers
- * for uint16_t*uint16_t some operand values will trigger signed integer
- * overflow with undefined behavior!  http://kqueue.org/blog/2013/09/17/cltq/
- * has the grody details.  Other than that one weird case, WrappingMultiply on
- * unsigned types is the same as C++ multiplication.
+ * Unsigned WrappingMultiply is *not* identical to C++ multiplication: with most
+ * compilers, in rare cases uint16_t*uint16_t can invoke *signed* integer
+ * overflow having undefined behavior!  http://kqueue.org/blog/2013/09/17/cltq/
+ * has the grody details.  (Some compilers do this for uint32_t, not uint16_t.)
+ * So it's especially important to use WrappingMultiply for wraparound math with
+ * uint16_t.  That quirk aside, this function acts like you *thought* C++
+ * unsigned multiplication always worked.
  *
  * For N-bit signed integer types, this is equivalent to multiplying the two
- * numbers wrapped to unsigned, taking the product mod 2**N, then wrapping that
- * number to the signed range:
+ * numbers wrapped to unsigned, then wrapping the product mod 2**N to the signed
+ * range:
  *
  *   WrappingMultiply(int16_t(-456), int16_t(123)) is 9448 ((-56088 mod 2**16) + 2**16);
  *   WrappingMultiply(int32_t(-7), int32_t(-9)) is 63 (63 mod 2**32);
  *   WrappingMultiply(int8_t(16), int8_t(24)) is -128 ((384 mod 2**8) - 2**8);
  *   WrappingMultiply(int8_t(16), int8_t(255)) is -16 ((4080 mod 2**8) - 2**8).
  *
- * There is no ready equivalent to this operation in C++, as applying C++
- * multiplication to signed integer types in ways that trigger overflow has
- * undefined behavior.  However, it's how multiplication *tends* to behave with
- * most compilers in most situations, even though it's emphatically not required
- * to do so.
+ * There's no equivalent to this operation in C++, as C++ signed
+ * multiplication that overflows has undefined behavior.  But it's how such
+ * multiplication *tends* to behave with most compilers, unless an optimization
+ * or similar -- quite permissibly -- triggers different behavior.
  */
 template<typename T>
 inline T
 WrappingMultiply(T aX, T aY)
 {
   return detail::WrappingMultiplyHelper<T>::compute(aX, aY);
 }
 
--- a/mfbt/tests/TestWrappingOperations.cpp
+++ b/mfbt/tests/TestWrappingOperations.cpp
@@ -4,18 +4,20 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/Assertions.h"
 #include "mozilla/WrappingOperations.h"
 
 #include <stdint.h>
 
+using mozilla::WrappingAdd;
 using mozilla::WrappingMultiply;
 using mozilla::WrapToSigned;
+using mozilla::WrappingSubtract;
 
 // NOTE: In places below |-FOO_MAX - 1| is used instead of |-FOO_MIN| because
 //       in C++ numeric literals are full expressions -- the |-| in a negative
 //       number is technically separate.  So with most compilers that limit
 //       |int| to the signed 32-bit range, something like |-2147483648| is
 //       operator-() applied to an *unsigned* expression.  And MSVC, at least,
 //       warns when you do that.  (The operation is well-defined, but it likely
 //       doesn't do what was intended.)  So we do the usual workaround for this
@@ -64,16 +66,324 @@ static_assert(WrapToSigned(uint64_t(9223
 template<typename T>
 inline constexpr bool
 TestEqual(T aX, T aY)
 {
   return aX == aY;
 }
 
 static void
+TestWrappingAdd8()
+{
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingAdd(uint8_t(0), uint8_t(128)),
+                               uint8_t(128)),
+                     "zero plus anything is anything");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingAdd(uint8_t(17), uint8_t(42)),
+                               uint8_t(59)),
+                     "17 + 42 == 59");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingAdd(uint8_t(255), uint8_t(1)),
+                               uint8_t(0)),
+                     "all bits plus one overflows to zero");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingAdd(uint8_t(128), uint8_t(127)),
+                               uint8_t(255)),
+                     "high bit plus all lower bits is all bits");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingAdd(uint8_t(128), uint8_t(193)),
+                               uint8_t(65)),
+                     "128 + 193 is 256 + 65");
+
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingAdd(int8_t(0), int8_t(-128)),
+                               int8_t(-128)),
+                     "zero plus anything is anything");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingAdd(int8_t(123), int8_t(8)),
+                               int8_t(-125)),
+                     "overflow to negative");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingAdd(int8_t(5), int8_t(-123)),
+                               int8_t(-118)),
+                     "5 - 123 is -118");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingAdd(int8_t(-85), int8_t(-73)),
+                               int8_t(98)),
+                     "underflow to positive");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingAdd(int8_t(-128), int8_t(127)),
+                               int8_t(-1)),
+                     "high bit plus all lower bits is -1");
+}
+
+static void
+TestWrappingAdd16()
+{
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingAdd(uint16_t(0), uint16_t(32768)),
+                               uint16_t(32768)),
+                     "zero plus anything is anything");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingAdd(uint16_t(24389), uint16_t(2682)),
+                               uint16_t(27071)),
+                     "24389 + 2682 == 27071");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingAdd(uint16_t(65535), uint16_t(1)),
+                               uint16_t(0)),
+                     "all bits plus one overflows to zero");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingAdd(uint16_t(32768), uint16_t(32767)),
+                               uint16_t(65535)),
+                     "high bit plus all lower bits is all bits");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingAdd(uint16_t(32768), uint16_t(47582)),
+                               uint16_t(14814)),
+                     "32768 + 47582 is 65536 + 14814");
+
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingAdd(int16_t(0), int16_t(-32768)),
+                               int16_t(-32768)),
+                     "zero plus anything is anything");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingAdd(int16_t(32765), int16_t(8)),
+                               int16_t(-32763)),
+                     "overflow to negative");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingAdd(int16_t(5), int16_t(-28933)),
+                               int16_t(-28928)),
+                     "5 - 28933 is -28928");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingAdd(int16_t(-23892), int16_t(-12893)),
+                               int16_t(28751)),
+                     "underflow to positive");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingAdd(int16_t(-32768), int16_t(32767)),
+                               int16_t(-1)),
+                     "high bit plus all lower bits is -1");
+}
+
+static void
+TestWrappingAdd32()
+{
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingAdd(uint32_t(0), uint32_t(2147483648)),
+                               uint32_t(2147483648)),
+                     "zero plus anything is anything");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingAdd(uint32_t(1398742328), uint32_t(714192829)),
+                               uint32_t(2112935157)),
+                     "1398742328 + 714192829 == 2112935157");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingAdd(uint32_t(4294967295), uint32_t(1)),
+                               uint32_t(0)),
+                     "all bits plus one overflows to zero");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingAdd(uint32_t(2147483648), uint32_t(2147483647)),
+                               uint32_t(4294967295)),
+                     "high bit plus all lower bits is all bits");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingAdd(uint32_t(2147483648), uint32_t(3146492712)),
+                               uint32_t(999009064)),
+                     "2147483648 + 3146492712 is 4294967296 + 999009064");
+
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingAdd(int32_t(0), int32_t(-2147483647 - 1)),
+                               int32_t(-2147483647 - 1)),
+                     "zero plus anything is anything");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingAdd(int32_t(2147483645), int32_t(8)),
+                               int32_t(-2147483643)),
+                     "overflow to negative");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingAdd(int32_t(257), int32_t(-23947248)),
+                               int32_t(-23946991)),
+                     "257 - 23947248 is -23946991");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingAdd(int32_t(-2147483220), int32_t(-12893)),
+                               int32_t(2147471183)),
+                     "underflow to positive");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingAdd(int32_t(-32768), int32_t(32767)),
+                               int32_t(-1)),
+                     "high bit plus all lower bits is -1");
+}
+
+static void
+TestWrappingAdd64()
+{
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingAdd(uint64_t(0), uint64_t(9223372036854775808ULL)),
+                               uint64_t(9223372036854775808ULL)),
+                     "zero plus anything is anything");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingAdd(uint64_t(70368744177664), uint64_t(3740873592)),
+                               uint64_t(70372485051256)),
+                     "70368744177664 + 3740873592 == 70372485051256");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingAdd(uint64_t(18446744073709551615ULL), uint64_t(1)),
+                               uint64_t(0)),
+                     "all bits plus one overflows to zero");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingAdd(uint64_t(9223372036854775808ULL),
+                                           uint64_t(9223372036854775807ULL)),
+                               uint64_t(18446744073709551615ULL)),
+                     "high bit plus all lower bits is all bits");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingAdd(uint64_t(14552598638644786479ULL), uint64_t(3894174382537247221ULL)),
+                               uint64_t(28947472482084)),
+                     "9223372036854775808 + 3146492712 is 18446744073709551616 + 28947472482084");
+
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingAdd(int64_t(0), int64_t(-9223372036854775807LL - 1)),
+                               int64_t(-9223372036854775807LL - 1)),
+                     "zero plus anything is anything");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingAdd(int64_t(9223372036854775802LL), int64_t(8)),
+                               int64_t(-9223372036854775806LL)),
+                     "overflow to negative");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingAdd(int64_t(37482739294298742LL), int64_t(-437843573929483498LL)),
+                               int64_t(-400360834635184756LL)),
+                     "37482739294298742 - 437843573929483498 is -400360834635184756");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingAdd(int64_t(-9127837934058953374LL), int64_t(-4173572032144775807LL)),
+                               int64_t(5145334107505822435L)),
+                     "underflow to positive");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingAdd(int64_t(-9223372036854775807LL - 1), int64_t(9223372036854775807LL)),
+                               int64_t(-1)),
+                     "high bit plus all lower bits is -1");
+}
+
+static void
+TestWrappingAdd()
+{
+  TestWrappingAdd8();
+  TestWrappingAdd16();
+  TestWrappingAdd32();
+  TestWrappingAdd64();
+}
+
+static void
+TestWrappingSubtract8()
+{
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingSubtract(uint8_t(0), uint8_t(128)),
+                               uint8_t(128)),
+                     "zero minus half is half");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingSubtract(uint8_t(17), uint8_t(42)),
+                               uint8_t(231)),
+                     "17 - 42 == -25 added to 256 is 231");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingSubtract(uint8_t(0), uint8_t(1)),
+                               uint8_t(255)),
+                     "zero underflows to all bits");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingSubtract(uint8_t(128), uint8_t(127)),
+                               uint8_t(1)),
+                     "128 - 127 == 1");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingSubtract(uint8_t(128), uint8_t(193)),
+                               uint8_t(191)),
+                     "128 - 193 is -65 so -65 + 256 == 191");
+
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingSubtract(int8_t(0), int8_t(-128)),
+                               int8_t(-128)),
+                     "zero minus high bit wraps to high bit");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingSubtract(int8_t(-126), int8_t(4)),
+                               int8_t(126)),
+                     "underflow to positive");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingSubtract(int8_t(5), int8_t(-123)),
+                               int8_t(-128)),
+                     "overflow to negative");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingSubtract(int8_t(-85), int8_t(-73)),
+                               int8_t(-12)),
+                     "negative minus smaller negative");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingSubtract(int8_t(-128), int8_t(127)),
+                               int8_t(1)),
+                     "underflow to 1");
+}
+
+static void
+TestWrappingSubtract16()
+{
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingSubtract(uint16_t(0), uint16_t(32768)),
+                               uint16_t(32768)),
+                     "zero minus half is half");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingSubtract(uint16_t(24389), uint16_t(2682)),
+                               uint16_t(21707)),
+                     "24389 - 2682 == 21707");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingSubtract(uint16_t(0), uint16_t(1)),
+                               uint16_t(65535)),
+                     "zero underflows to all bits");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingSubtract(uint16_t(32768), uint16_t(32767)),
+                               uint16_t(1)),
+                     "high bit minus all lower bits is one");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingSubtract(uint16_t(32768), uint16_t(47582)),
+                               uint16_t(50722)),
+                     "32768 - 47582 + 65536 is 50722");
+
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingSubtract(int16_t(0), int16_t(-32768)),
+                               int16_t(-32768)),
+                     "zero minus high bit wraps to high bit");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingSubtract(int16_t(-32766), int16_t(4)),
+                               int16_t(32766)),
+                     "underflow to positive");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingSubtract(int16_t(5), int16_t(-28933)),
+                               int16_t(28938)),
+                     "5 - -28933 is 28938");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingSubtract(int16_t(-23892), int16_t(-12893)),
+                               int16_t(-10999)),
+                     "negative minus smaller negative");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingSubtract(int16_t(-32768), int16_t(32767)),
+                               int16_t(1)),
+                     "underflow to 1");
+}
+
+static void
+TestWrappingSubtract32()
+{
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingSubtract(uint32_t(0), uint32_t(2147483648)),
+                               uint32_t(2147483648)),
+                     "zero minus half is half");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingSubtract(uint32_t(1398742328), uint32_t(714192829)),
+                               uint32_t(684549499)),
+                     "1398742328 - 714192829 == 684549499");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingSubtract(uint32_t(0), uint32_t(1)),
+                               uint32_t(4294967295)),
+                     "zero underflows to all bits");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingSubtract(uint32_t(2147483648), uint32_t(2147483647)),
+                               uint32_t(1)),
+                     "high bit minus all lower bits is one");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingSubtract(uint32_t(2147483648), uint32_t(3146492712)),
+                               uint32_t(3295958232)),
+                     "2147483648 - 3146492712 + 4294967296 is 3295958232");
+
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingSubtract(int32_t(0), int32_t(-2147483647 - 1)),
+                               int32_t(-2147483647 - 1)),
+                     "zero minus high bit wraps to high bit");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingSubtract(int32_t(-2147483646), int32_t(4)),
+                               int32_t(2147483646)),
+                     "underflow to positive");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingSubtract(int32_t(257), int32_t(-23947248)),
+                               int32_t(23947505)),
+                     "257 - -23947248 is 23947505");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingSubtract(int32_t(-2147483220), int32_t(-12893)),
+                               int32_t(-2147470327)),
+                     "negative minus smaller negative");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingSubtract(int32_t(-2147483647 - 1), int32_t(2147483647)),
+                               int32_t(1)),
+                     "underflow to 1");
+}
+
+static void
+TestWrappingSubtract64()
+{
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingSubtract(uint64_t(0), uint64_t(9223372036854775808ULL)),
+                               uint64_t(9223372036854775808ULL)),
+                     "zero minus half is half");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingSubtract(uint64_t(70368744177664), uint64_t(3740873592)),
+                               uint64_t(70365003304072)),
+                     "70368744177664 - 3740873592 == 70365003304072");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingSubtract(uint64_t(0), uint64_t(1)),
+                               uint64_t(18446744073709551615ULL)),
+                     "zero underflows to all bits");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingSubtract(uint64_t(9223372036854775808ULL),
+                                                uint64_t(9223372036854775807ULL)),
+                               uint64_t(1)),
+                     "high bit minus all lower bits is one");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingSubtract(uint64_t(14552598638644786479ULL), uint64_t(3894174382537247221ULL)),
+                               uint64_t(10658424256107539258ULL)),
+                     "14552598638644786479 - 39763621533397112216 is 10658424256107539258L");
+
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingSubtract(int64_t(0), int64_t(-9223372036854775807LL - 1)),
+                               int64_t(-9223372036854775807LL - 1)),
+                     "zero minus high bit wraps to high bit");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingSubtract(int64_t(-9223372036854775802LL), int64_t(8)),
+                               int64_t(9223372036854775806LL)),
+                     "overflow to negative");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingSubtract(int64_t(37482739294298742LL), int64_t(-437843573929483498LL)),
+                               int64_t(475326313223782240)),
+                     "37482739294298742 - -437843573929483498 is 475326313223782240");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingSubtract(int64_t(-9127837934058953374LL), int64_t(-4173572032144775807LL)),
+                               int64_t(-4954265901914177567LL)),
+                     "negative minus smaller negative");
+  MOZ_RELEASE_ASSERT(TestEqual(WrappingSubtract(int64_t(-9223372036854775807LL - 1), int64_t(9223372036854775807LL)),
+                               int64_t(1)),
+                     "underflow to 1");
+}
+
+static void
+TestWrappingSubtract()
+{
+  TestWrappingSubtract8();
+  TestWrappingSubtract16();
+  TestWrappingSubtract32();
+  TestWrappingSubtract64();
+}
+
+static void
 TestWrappingMultiply8()
 {
   MOZ_RELEASE_ASSERT(TestEqual(WrappingMultiply(uint8_t(0), uint8_t(128)),
                                uint8_t(0)),
                      "zero times anything is zero");
   MOZ_RELEASE_ASSERT(TestEqual(WrappingMultiply(uint8_t(128), uint8_t(1)),
                                uint8_t(128)),
                      "1 times anything is anything");
@@ -232,17 +542,25 @@ TestWrappingMultiply64()
                                int64_t(-9223372036854775807 - 1)),
                      "multiply that populates the sign bit produces minval");
   MOZ_RELEASE_ASSERT(TestEqual(WrappingMultiply(int64_t(9223372036854775807),
                                                 int64_t(9223372036854775807)),
                                int64_t(1)),
                      "multiplying maxvals overflows all the way to 1");
 }
 
-int
-main()
+static void
+TestWrappingMultiply()
 {
   TestWrappingMultiply8();
   TestWrappingMultiply16();
   TestWrappingMultiply32();
   TestWrappingMultiply64();
+}
+
+int
+main()
+{
+  TestWrappingAdd();
+  TestWrappingSubtract();
+  TestWrappingMultiply();
   return 0;
 }
--- a/testing/config/tooltool-manifests/macosx64/hostutils.manifest
+++ b/testing/config/tooltool-manifests/macosx64/hostutils.manifest
@@ -1,10 +1,10 @@
 [
   {
-    "size": 72112596,
+    "size": 52350220,
     "visibility": "public",
-    "digest": "4d3fe61dd8ad9ca09c72e677e8d2d5b7409988de32d6feb9fc55cb0a320a4835b6e2f384a68d2409e89e7a0d2f622bf3ceb9b707e01ad8afe1270ad0d1c9973c",
+    "digest": "f8f86d8f2b8f754a79404dc38bf1d12419923d3d496cbd896a979658083b676f2eeda3bf03af21c5ea6389e8ec63459bf8e51bb093e99ef4d67b2a92a3160994",
     "algorithm": "sha512",
-    "filename": "host-utils-58.0a1.en-US.mac.tar.gz",
+    "filename": "host-utils-61.0a1.en-US.mac.tar.xz",
     "unpack": true
   }
 ]
--- a/testing/geckodriver/doc/Releasing.md
+++ b/testing/geckodriver/doc/Releasing.md
@@ -118,24 +118,36 @@ Export to GitHub
 
 The canonical GitHub repository is
 
 	https://github.com/mozilla/geckodriver.git
 
 so make sure you have a local clone of that.  It has three branches:
 _master_ which only contains the [README.md]; _old_ which was the
 state of the project when it was exported to mozilla-central; and
-_release_, from where releases are made.  We will export the contents
-of [testing/geckodriver] to the latter branch:
+_release_, from where releases are made.
+
+Before we copy the code over to the GitHub repository we need to
+check out the [commit we made earlier](#bump-the-version-number)
+against central that bumped the version number:
+
+	% git checkout $BUMP_REVISION
+
+Or:
+
+	% hg update $BUMP_REVISION
+
+We will now export the contents of [testing/geckodriver] to the
+_release_ branch:
 
 	% cd $SRC/geckodriver
 	% git checkout release
 	% git rm -rf .
 	% git clean -fxd
-	% cp -r $SRC/gecko/testing/geckodriver/* .
+	% cp -r $SRC/gecko/testing/geckodriver .
 
 [README.md]: https://searchfox.org/mozilla-central/source/testing/geckodriver/README.md
 [testing/geckodriver]: https://searchfox.org/mozilla-central/source/testing/geckodriver
 
 
 Manually change in-tree path dependencies
 ------------------------------------------
 
--- a/testing/mozharness/mozharness/mozilla/testing/verify_tools.py
+++ b/testing/mozharness/mozharness/mozilla/testing/verify_tools.py
@@ -212,17 +212,17 @@ class VerifyToolsMixin(object):
 
         if self.config.get('verify') != True:
             # not in verify mode: run once, with no additional args
             args = [[]]
         else:
             # in verify mode, run nothing by default (unsupported suite or no files modified)
             args = []
             # otherwise, run once for each file in requested suite
-            references = re.compile(r"(-ref|-noref|-noref.)\.")
+            references = re.compile(r"(-ref|-notref|-noref|-noref.)\.")
             files = []
             jsreftest_extra_dir = os.path.join('js', 'src', 'tests')
             # For some suites, the test path needs to be updated before passing to
             # the test harness.
             for file in self.verify_suites.get(suite):
                 if (self.config.get('verify_category') != "web-platform" and
                     suite in ['reftest', 'crashtest']):
                     file = os.path.join(self.reftest_test_dir, file)