Merge mozilla-central to autoland. a=merge CLOSED TREE
authorGurzau Raul <rgurzau@mozilla.com>
Tue, 02 Oct 2018 19:07:23 +0300
changeset 439194 cefdf4d102faabf8a000caa821d311ca3d289701
parent 439193 ac55a8f97f06897ee34d65d6bbfc773091e2341e (current diff)
parent 439172 17c314f6930d2b8d6e456aa9e9d41407a45c3008 (diff)
child 439195 fb7f5d71b31ad06c7207f0945cd8fdbee003e237
push id34758
push userdvarga@mozilla.com
push dateTue, 02 Oct 2018 21:45:21 +0000
treeherdermozilla-central@4392b5198fb7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone64.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-central to autoland. a=merge CLOSED TREE
testing/web-platform/meta/encrypted-media/clearkey-mp4-unique-origin.https.html.ini
--- a/accessible/interfaces/nsIAccessible.idl
+++ b/accessible/interfaces/nsIAccessible.idl
@@ -77,32 +77,32 @@ interface nsIAccessible : nsISupports
   /**
    * The DOM node this nsIAccessible is associated with.
    */
   readonly attribute Node DOMNode;
 
   /**
     * For remote accessibles the id of the related DOM node.
     */
-  readonly attribute DOMString id;
+  readonly attribute AString id;
 
   /**
    * The document accessible that this access node resides in.
    */
   readonly attribute nsIAccessibleDocument document;
 
   /**
    * The root document accessible that this access node resides in.
    */
   readonly attribute nsIAccessibleDocument rootDocument;
 
   /**
    * The language for the current DOM node, e.g. en, de, etc.
    */
-  readonly attribute DOMString language;
+  readonly attribute AString language;
 
   /**
    * Accessible name -- the main text equivalent for this node. The name is
    * specified by ARIA or by native markup. Example of ARIA markup is
    * aria-labelledby attribute placed on element of this accessible. Example
    * of native markup is HTML label linked with HTML element of this accessible.
    *
    * Value can be string or null. A null value indicates that AT may attempt to
--- a/accessible/interfaces/nsIAccessibleApplication.idl
+++ b/accessible/interfaces/nsIAccessibleApplication.idl
@@ -10,25 +10,25 @@
  * provides information about application.
  */
 [scriptable, builtinclass, uuid(79251626-387c-4531-89f3-680d31d6cf05)]
 interface nsIAccessibleApplication : nsISupports
 {
   /**
    * Returns the application name.
    */
-  readonly attribute DOMString appName;
+  readonly attribute AString appName;
 
   /**
    * Returns the application version.
    */
-  readonly attribute DOMString appVersion;
+  readonly attribute AString appVersion;
 
   /**
    * Returns the platform name.
    */
-  readonly attribute DOMString platformName;
+  readonly attribute AString platformName;
 
   /**
    * Returns the platform version.
    */
-  readonly attribute DOMString platformVersion;
+  readonly attribute AString platformVersion;
 };
--- a/accessible/interfaces/nsIAccessibleTextChangeEvent.idl
+++ b/accessible/interfaces/nsIAccessibleTextChangeEvent.idl
@@ -24,10 +24,10 @@ interface nsIAccessibleTextChangeEvent :
   /**
    * Returns true if text was inserted, otherwise false.
    */
   readonly attribute boolean isInserted;
 
   /**
    * The inserted or removed text
    */
-  readonly attribute DOMString modifiedText;
+  readonly attribute AString modifiedText;
 };
--- a/accessible/interfaces/nsIXBLAccessible.idl
+++ b/accessible/interfaces/nsIXBLAccessible.idl
@@ -11,10 +11,10 @@
  * accessible properties.
  */
 [scriptable, builtinclass, uuid(3716eb86-166b-445b-a94a-9b522fee96e6)]
 interface nsIXBLAccessible : nsISupports
 {
   /**
    * Return accessible name.
    */
-  readonly attribute DOMString accessibleName;
+  readonly attribute AString accessibleName;
 };
--- a/browser/config/mozconfigs/linux64/code-coverage-debug
+++ b/browser/config/mozconfigs/linux64/code-coverage-debug
@@ -1,3 +1,3 @@
 . "$topsrcdir/browser/config/mozconfigs/linux64/code-coverage"
 
-ac_add_options --enable-debug
\ No newline at end of file
+ac_add_options --enable-debug=-g1
--- a/browser/config/mozconfigs/linux64/code-coverage-opt
+++ b/browser/config/mozconfigs/linux64/code-coverage-opt
@@ -1,1 +1,3 @@
 . "$topsrcdir/browser/config/mozconfigs/linux64/code-coverage"
+
+ac_add_options --enable-debug-symbols=-g1
--- a/build/build-clang/build-clang.py
+++ b/build/build-clang/build-clang.py
@@ -611,17 +611,18 @@ if __name__ == "__main__":
         extra_ldflags = []
     elif is_linux():
         extra_cflags = []
         extra_cxxflags = []
         extra_cflags2 = ["-fPIC"]
         # Silence clang's warnings about arguments not being used in compilation.
         extra_cxxflags2 = ["-fPIC", '-Qunused-arguments']
         extra_asmflags = []
-        extra_ldflags = []
+        # Avoid libLLVM internal function calls going through the PLT.
+        extra_ldflags = ['-Wl,-Bsymbolic-functions']
 
         if 'LD_LIBRARY_PATH' in os.environ:
             os.environ['LD_LIBRARY_PATH'] = ('%s/lib64/:%s' %
                                              (gcc_dir, os.environ['LD_LIBRARY_PATH']))
         else:
             os.environ['LD_LIBRARY_PATH'] = '%s/lib64/' % gcc_dir
     elif is_windows():
         extra_cflags = []
--- a/docshell/base/nsIDocShell.idl
+++ b/docshell/base/nsIDocShell.idl
@@ -211,18 +211,18 @@ interface nsIDocShell : nsIDocShellTreeI
                               out nsIDocShell aDocShell,
                               out nsIRequest aRequest);
 
   /**
    * Do either a history.pushState() or history.replaceState() operation,
    * depending on the value of aReplace.
    */
   [implicit_jscontext]
-  void addState(in jsval aData, in DOMString aTitle,
-                in DOMString aURL, in boolean aReplace);
+  void addState(in jsval aData, in AString aTitle,
+                in AString aURL, in boolean aReplace);
 
   /**
    * Reset state to a new content model within the current document and the document
    * viewer.  Called by the document before initiating an out of band document.write().
    */
   void prepareForNewContentModel();
 
   /**
@@ -269,17 +269,17 @@ interface nsIDocShell : nsIDocShellTreeI
    * This attribute allows chrome to tie in to handle DOM events that may
    * be of interest to chrome.
    */
   attribute EventTarget chromeEventHandler;
 
   /**
    * This allows chrome to set a custom User agent on a specific docshell
    */
-  attribute DOMString customUserAgent;
+  attribute AString customUserAgent;
 
   /**
    * Whether CSS error reporting is enabled.
    */
   attribute boolean cssErrorReportingEnabled;
 
   /**
    * Whether to allow plugin execution
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -31,16 +31,17 @@
 #include "nsContentUtils.h"
 #include "nsUnicharUtils.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/StaticPrefs.h"
 #include "mozilla/Telemetry.h"
 #include "BatteryManager.h"
 #include "mozilla/dom/CredentialsContainer.h"
 #include "mozilla/dom/Clipboard.h"
+#include "mozilla/dom/FeaturePolicyUtils.h"
 #include "mozilla/dom/GamepadServiceTest.h"
 #include "mozilla/dom/MediaCapabilities.h"
 #include "mozilla/dom/WakeLock.h"
 #include "mozilla/dom/power/PowerManagerService.h"
 #include "mozilla/dom/MIDIAccessManager.h"
 #include "mozilla/dom/MIDIOptionsBinding.h"
 #include "mozilla/dom/Permissions.h"
 #include "mozilla/dom/Presentation.h"
@@ -1716,16 +1717,24 @@ Navigator::RequestMediaKeySystemAccess(c
                                     NS_LITERAL_CSTRING("Media"),
                                     doc,
                                     nsContentUtils::eDOM_PROPERTIES,
                                     "MediaEMEInsecureContextDeprecatedWarning",
                                     params,
                                     ArrayLength(params));
   }
 
+  nsIDocument* doc = mWindow->GetExtantDoc();
+  if (doc &&
+      !FeaturePolicyUtils::IsFeatureAllowed(doc,
+                                            NS_LITERAL_STRING("encrypted-media"))) {
+    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
+    return nullptr;
+  }
+
   RefPtr<DetailedPromise> promise =
     DetailedPromise::Create(mWindow->AsGlobal(), aRv,
       NS_LITERAL_CSTRING("navigator.requestMediaKeySystemAccess"),
       Telemetry::VIDEO_EME_REQUEST_SUCCESS_LATENCY_MS,
       Telemetry::VIDEO_EME_REQUEST_FAILURE_LATENCY_MS);
   if (aRv.Failed()) {
     return nullptr;
   }
--- a/dom/base/nsIDOMRequestService.idl
+++ b/dom/base/nsIDOMRequestService.idl
@@ -10,12 +10,12 @@ interface mozIDOMWindow;
 webidl DOMRequest;
 
 [scriptable, builtinclass, uuid(9a57e5de-ce93-45fa-8145-755722834f7c)]
 interface nsIDOMRequestService : nsISupports
 {
   DOMRequest createRequest(in mozIDOMWindow window);
 
   void fireSuccess(in DOMRequest request, in jsval result);
-  void fireError(in DOMRequest request, in DOMString error);
+  void fireError(in DOMRequest request, in AString error);
   void fireSuccessAsync(in DOMRequest request, in jsval result);
-  void fireErrorAsync(in DOMRequest request, in DOMString error);
+  void fireErrorAsync(in DOMRequest request, in AString error);
 };
--- a/dom/base/nsIDroppedLinkHandler.idl
+++ b/dom/base/nsIDroppedLinkHandler.idl
@@ -9,27 +9,27 @@ webidl DragEvent;
 webidl DataTransfer;
 
 [scriptable, uuid(69E14F91-2E09-4CA6-A511-A715C99A2804)]
 interface nsIDroppedLinkItem : nsISupports
 {
   /**
    * Returns the URL of the link.
    */
-  readonly attribute DOMString url;
+  readonly attribute AString url;
 
   /**
    * Returns the link name.
    */
-  readonly attribute DOMString name;
+  readonly attribute AString name;
 
   /**
    * Returns the MIME-Type.
    */
-  readonly attribute DOMString type;
+  readonly attribute AString type;
 };
 
 [scriptable, uuid(21B5C25A-28A9-47BD-8431-FA9116305DED)]
 interface nsIDroppedLinkHandler : nsISupports
 {
   /**
    * Determines if a link being dragged can be dropped and returns true if so.
    * aEvent should be a dragenter or dragover event.
--- a/dom/bindings/CallbackObject.h
+++ b/dom/bindings/CallbackObject.h
@@ -29,16 +29,19 @@
 #include "mozilla/dom/ScriptSettings.h"
 #include "nsWrapperCache.h"
 #include "nsJSEnvironment.h"
 #include "xpcpublic.h"
 #include "jsapi.h"
 #include "js/TracingAPI.h"
 
 namespace mozilla {
+
+class PromiseJobRunnable;
+
 namespace dom {
 
 #define DOM_CALLBACKOBJECT_IID \
 { 0xbe74c190, 0x6d76, 0x4991, \
  { 0x84, 0xb9, 0x65, 0x06, 0x99, 0xe6, 0x93, 0x2b } }
 
 class CallbackObject : public nsISupports
 {
@@ -78,18 +81,19 @@ public:
                           JSObject* aAsyncStack,
                           nsIGlobalObject* aIncumbentGlobal)
   {
     Init(aCallback, aCallbackGlobal, aAsyncStack, aIncumbentGlobal);
   }
 
   // This is guaranteed to be non-null from the time the CallbackObject is
   // created until JavaScript has had a chance to run. It will only return null
-  // after a JavaScript caller has called nukeSandbox on a Sandbox object, and
-  // the cycle collector has had a chance to run.
+  // after a JavaScript caller has called nukeSandbox on a Sandbox object and
+  // the cycle collector has had a chance to run, unless Reset() is explicitly
+  // called (see below).
   //
   // This means that any native callee which receives a CallbackObject as an
   // argument can safely rely on the callback being non-null so long as it
   // doesn't trigger any scripts before it accesses it.
   JS::Handle<JSObject*> CallbackOrNull() const
   {
     mCallback.exposeToActiveJS();
     return CallbackPreserveColor();
@@ -232,16 +236,26 @@ private:
                    nsIGlobalObject* aIncumbentGlobal)
   {
     // Set script objects before we hold, on the off chance that a GC could
     // somehow happen in there... (which would be pretty odd, granted).
     InitNoHold(aCallback, aCallbackGlobal, aCreationStack, aIncumbentGlobal);
     mozilla::HoldJSObjects(this);
   }
 
+  // Provide a way to clear this object's pointers to GC things after the
+  // callback has been run. Note that CallbackOrNull() will return null after
+  // this point. This should only be called if the object is known not to be
+  // used again.
+  void Reset()
+  {
+    ClearJSReferences();
+  }
+  friend class mozilla::PromiseJobRunnable;
+
   inline void ClearJSReferences()
   {
     mCallback = nullptr;
     mCallbackGlobal = nullptr;
     mCreationStack = nullptr;
     mIncumbentJSGlobal = nullptr;
   }
 
--- a/dom/browser-element/nsIBrowserElementAPI.idl
+++ b/dom/browser-element/nsIBrowserElementAPI.idl
@@ -31,54 +31,54 @@ interface nsIBrowserElementAPI : nsISupp
 
   /**
    * Notify frame scripts that support the API to destroy.
    */
   void destroyFrameScripts();
 
   void setFrameLoader(in FrameLoader frameLoader);
 
-  void sendMouseEvent(in DOMString type,
+  void sendMouseEvent(in AString type,
                       in uint32_t x,
                       in uint32_t y,
                       in uint32_t button,
                       in uint32_t clickCount,
                       in uint32_t mifiers);
-  void sendTouchEvent(in DOMString aType,
+  void sendTouchEvent(in AString aType,
                       [const, array, size_is(count)] in uint32_t aIdentifiers,
                       [const, array, size_is(count)] in int32_t aXs,
                       [const, array, size_is(count)] in int32_t aYs,
                       [const, array, size_is(count)] in uint32_t aRxs,
                       [const, array, size_is(count)] in uint32_t aRys,
                       [const, array, size_is(count)] in float aRotationAngles,
                       [const, array, size_is(count)] in float aForces,
                       in uint32_t count,
                       in long aModifiers);
   void goBack();
   void goForward();
   void reload(in boolean hardReload);
   void stop();
-  DOMRequest download(in DOMString url,
+  DOMRequest download(in AString url,
                             [optional] in jsval options);
   DOMRequest purgeHistory();
   DOMRequest getScreenshot(in uint32_t width,
                                  in uint32_t height,
-                                 [optional] in DOMString mimeType);
+                                 [optional] in AString mimeType);
   void zoom(in float zoom);
   DOMRequest getCanGoBack();
   DOMRequest getCanGoForward();
   DOMRequest getContentDimensions();
 
-  void findAll(in DOMString searchString, in long caseSensitivity);
+  void findAll(in AString searchString, in long caseSensitivity);
   void findNext(in long direction);
   void clearMatch();
 
   void addNextPaintListener(in jsval listener); // BrowserElementNextPaintEventCallback
   void removeNextPaintListener(in jsval listener); // BrowserElementNextPaintEventCallback
 
-  DOMRequest executeScript(in DOMString script, in jsval options);
+  DOMRequest executeScript(in AString script, in jsval options);
 
   /**
    * Returns an object that represents a Web Manifest:
    * http://w3c.github.io/manifest/
    */
   DOMRequest getWebManifest();
 };
--- a/dom/chrome-webidl/XULTextElement.webidl
+++ b/dom/chrome-webidl/XULTextElement.webidl
@@ -4,9 +4,10 @@
  * 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/.
  */
 
 [HTMLConstructor, Func="IsChromeOrXBL"]
 interface XULTextElement : XULElement {
   attribute boolean disabled;
   attribute DOMString value;
+  attribute DOMString accessKey;
 };
--- a/dom/console/nsIConsoleAPIStorage.idl
+++ b/dom/console/nsIConsoleAPIStorage.idl
@@ -14,34 +14,34 @@ interface nsIConsoleAPIStorage : nsISupp
    * @param string [aId]
    *        Optional, the inner window ID for which you want to get the array of
    *        cached events.
    * @returns array
    *          The array of cached events for the given window. If no |aId| is
    *          given this function returns all of the cached events, from any
    *          window.
    */
-  jsval getEvents([optional] in DOMString aId);
+  jsval getEvents([optional] in AString aId);
 
   /**
    * Record an event associated with the given window ID.
    *
    * @param string aId
    *        The ID of the inner window for which the event occurred or "jsm" for
    *        messages logged from JavaScript modules..
    * @param string aOuterId
    *        This ID is used as 3rd parameters for the console-api-log-event
    *        notification.
    * @param object aEvent
    *        A JavaScript object you want to store.
    */
-  void recordEvent(in DOMString aId, in DOMString aOuterId, in jsval aEvent);
+  void recordEvent(in AString aId, in AString aOuterId, in jsval aEvent);
 
   /**
    * Clear storage data for the given window.
    *
    * @param string [aId]
    *        Optional, the inner window ID for which you want to clear the
    *        messages. If this is not specified all of the cached messages are
    *        cleared, from all window objects.
    */
-  void clearEvents([optional] in DOMString aId);
+  void clearEvents([optional] in AString aId);
 };
--- a/dom/events/nsIEventListenerService.idl
+++ b/dom/events/nsIEventListenerService.idl
@@ -84,33 +84,33 @@ interface nsIEventListenerService : nsIS
                               [optional] out unsigned long aCount,
                               [retval, array, size_is(aCount)] out
                                 EventTarget aOutArray);
 
   /**
    * Returns true if a event target has any listener for the given type.
    */
   boolean hasListenersFor(in EventTarget aEventTarget,
-                          in DOMString aType);
+                          in AString aType);
 
   /**
    * Add a system-group eventlistener to a event target.
    */
   [implicit_jscontext]
   void addSystemEventListener(in EventTarget target,
-                              in DOMString type,
+                              in AString type,
                               in jsval listener,
                               in boolean useCapture);
 
   /**
    * Remove a system-group eventlistener from a event target.
    */
   [implicit_jscontext]
   void removeSystemEventListener(in EventTarget target,
-                                 in DOMString type,
+                                 in AString type,
                                  in jsval listener,
                                  in boolean useCapture);
 
   [implicit_jscontext]
   void addListenerForAllEvents(in EventTarget target,
                                in jsval listener,
                                [optional] in boolean aUseCapture,
                                [optional] in boolean aWantsUntrusted,
--- a/dom/html/nsIDateTimeInputArea.idl
+++ b/dom/html/nsIDateTimeInputArea.idl
@@ -44,16 +44,16 @@ interface nsIDateTimeInputArea : nsISupp
    * Set the current state of the picker, true if it's opened, false otherwise.
    */
   void setPickerState(in boolean isOpen);
 
   /**
    * Set the attribute of the inner text boxes. Only "tabindex", "readonly",
    * and "disabled" are allowed.
    */
-  void setEditAttribute(in DOMString name, in DOMString value);
+  void setEditAttribute(in AString name, in AString value);
 
   /**
    * Remove the attribute of the inner text boxes. Only "tabindex", "readonly",
    * and "disabled" are allowed.
    */
-  void removeEditAttribute(in DOMString name);
+  void removeEditAttribute(in AString name);
 };
--- a/dom/html/nsIMenuBuilder.idl
+++ b/dom/html/nsIMenuBuilder.idl
@@ -15,17 +15,17 @@ webidl Element;
 interface nsIMenuBuilder : nsISupports
 {
 
   /**
    * Create the top level menu or a submenu. The implementation should create
    * a new context for this menu, so all subsequent methods will add new items
    * to this newly created menu.
    */
-  void openContainer(in DOMString aLabel);
+  void openContainer(in AString aLabel);
 
   /**
    * Add a new menu item. All menu item details can be obtained from
    * the element. This method is not called for hidden elements or elements
    * with no or empty label. The icon should be loaded only if aCanLoadIcon
    * is true.
    */
   void addItemFor(in Element aElement,
@@ -67,10 +67,10 @@ interface nsIMenuBuilder : nsISupports
    */
   AString toJSONString();
 
   /**
    * Invoke the action of the menuitem with assigned id aGeneratedItemId.
    *
    * @param aGeneratedItemId the menuitem id
    */
-  void click(in DOMString aGeneratedItemId);
+  void click(in AString aGeneratedItemId);
 };
--- a/dom/interfaces/base/nsIBrowserDOMWindow.idl
+++ b/dom/interfaces/base/nsIBrowserDOMWindow.idl
@@ -9,17 +9,17 @@ interface mozIDOMWindowProxy;
 interface nsIDOMWindow;
 interface nsIURI;
 interface nsIFrameLoaderOwner;
 interface nsIPrincipal;
 
 [scriptable, uuid(e774db14-79ac-4156-a7a3-aa3fd0a22c10)]
 interface nsIOpenURIInFrameParams : nsISupports
 {
-  attribute DOMString referrer;
+  attribute AString referrer;
   attribute unsigned long referrerPolicy;
   readonly attribute boolean isPrivate;
   attribute nsIPrincipal triggeringPrincipal;
 
   // The browser or frame element in the parent process which holds the
   // opener window in the content process. May be null.
   readonly attribute nsIFrameLoaderOwner openerBrowser;
 
--- a/dom/interfaces/base/nsIServiceWorkerManager.idl
+++ b/dom/interfaces/base/nsIServiceWorkerManager.idl
@@ -45,18 +45,18 @@ interface nsIServiceWorkerInfo : nsISupp
   const unsigned short STATE_PARSED = 0;
   const unsigned short STATE_INSTALLING = 1;
   const unsigned short STATE_INSTALLED = 2;
   const unsigned short STATE_ACTIVATING = 3;
   const unsigned short STATE_ACTIVATED = 4;
   const unsigned short STATE_REDUNDANT = 5;
   const unsigned short STATE_UNKNOWN = 6;
 
-  readonly attribute DOMString scriptSpec;
-  readonly attribute DOMString cacheName;
+  readonly attribute AString scriptSpec;
+  readonly attribute AString cacheName;
 
   readonly attribute unsigned short state;
 
   readonly attribute nsIWorkerDebugger debugger;
 
   readonly attribute bool handlesFetchEvents;
 
   readonly attribute PRTime installedTime;
@@ -79,18 +79,18 @@ interface nsIServiceWorkerRegistrationIn
 {
   // State values below should match the ServiceWorkerUpdateViaCache enumeration.
   const unsigned short UPDATE_VIA_CACHE_IMPORTS = 0;
   const unsigned short UPDATE_VIA_CACHE_ALL = 1;
   const unsigned short UPDATE_VIA_CACHE_NONE = 2;
 
   readonly attribute nsIPrincipal principal;
 
-  readonly attribute DOMString scope;
-  readonly attribute DOMString scriptSpec;
+  readonly attribute AString scope;
+  readonly attribute AString scriptSpec;
   readonly attribute unsigned short updateViaCache;
 
   readonly attribute PRTime lastUpdateTime;
 
   readonly attribute nsIServiceWorkerInfo installingWorker;
   readonly attribute nsIServiceWorkerInfo waitingWorker;
   readonly attribute nsIServiceWorkerInfo activeWorker;
 
@@ -118,39 +118,39 @@ interface nsIServiceWorkerManagerListene
 interface nsIServiceWorkerManager : nsISupports
 {
   /**
    * Unregister an existing ServiceWorker registration for `aScope`.
    * It keeps aCallback alive until the operation is concluded.
    */
   void unregister(in nsIPrincipal aPrincipal,
                   in nsIServiceWorkerUnregisterCallback aCallback,
-                  in DOMString aScope);
+                  in AString aScope);
 
   nsIServiceWorkerRegistrationInfo getRegistrationByPrincipal(in nsIPrincipal aPrincipal,
-                                                              in DOMString aScope);
+                                                              in AString aScope);
 
   [notxpcom, nostdcall] bool StartControlling(in const_ClientInfoRef aClientInfo,
                                               in const_ServiceWorkerDescriptorRef aServiceWorker);
 
   // Testing
-  DOMString getScopeForUrl(in nsIPrincipal aPrincipal, in DOMString aPath);
+  AString getScopeForUrl(in nsIPrincipal aPrincipal, in AString aPath);
 
   // It returns an array of nsIServiceWorkerRegistrationInfos.
   nsIArray getAllRegistrations();
 
   // It calls softUpdate() for each child process.
   [implicit_jscontext] void propagateSoftUpdate(in jsval aOriginAttributes,
-                                                in DOMString aScope);
+                                                in AString aScope);
 
   // It calls unregister() in each child process. The callback is used to
   // inform when unregister() is completed on the current process.
   void propagateUnregister(in nsIPrincipal aPrincipal,
                            in nsIServiceWorkerUnregisterCallback aCallback,
-                           in DOMString aScope);
+                           in AString aScope);
 
   void sendNotificationClickEvent(in ACString aOriginSuffix,
                                   in ACString scope,
                                   in AString aID,
                                   in AString aTitle,
                                   in AString aDir,
                                   in AString aLang,
                                   in AString aBody,
--- a/dom/interfaces/base/nsITextInputProcessor.idl
+++ b/dom/interfaces/base/nsITextInputProcessor.idl
@@ -322,17 +322,17 @@ interface nsITextInputProcessor : nsISup
   /**
    * Set new composition string.  Pending composition will be flushed by
    * a call of flushPendingComposition().  However, if the new composition
    * string isn't empty, you need to call appendClauseToPendingComposition() to
    * fill all characters of aString with one or more clauses before flushing.
    * Note that if you need to commit or cancel composition, use
    * commitComposition(), commitCompositionWith() or cancelComposition().
    */
-  void setPendingCompositionString(in DOMString aString);
+  void setPendingCompositionString(in AString aString);
 
   // ATTR_RAW_CLAUSE means that the clause hasn't been selected nor converted
   // yet.
   const unsigned long ATTR_RAW_CLAUSE           = 0x02;
   // ATTR_SELECTED_RAW_CLAUSE means that the clause hasn't been converted yet
   // but is selected for converting to the other string.
   const unsigned long ATTR_SELECTED_RAW_CLAUSE  = 0x03;
   // ATTR_CONVERTED_CLAUSE means that the clause has already been converted but
@@ -449,17 +449,17 @@ interface nsITextInputProcessor : nsISup
    * @param aKeyFlags       See KEY_* constants.
    * @return                Returns true if there is a composition already or
    *                        starting composition automatically.
    *                        Otherwise, i.e., if it cannot start composition
    *                        automatically, e.g., canceled by web apps, returns
    *                        false.
    */
   [optional_argc]
-    boolean commitCompositionWith(in DOMString aCommitString,
+    boolean commitCompositionWith(in AString aCommitString,
                                   [optional] in Event aKeyboardEvent,
                                   [optional] in unsigned long aKeyFlags);
 
   /**
    * cancelComposition() will cancel composition.  This is for now the same as
    * calling commitComposition("").  However, in the future, this might work
    * better.  If your IME needs to cancel composition, use this instead of
    * commitComposition().
@@ -587,17 +587,17 @@ interface nsITextInputProcessor : nsISup
   /**
    * getModifierState() returns modifier state managed by this instance.
    *
    * @param aModifier       One of modifier key names.  This doesn't support
    *                        virtual modifiers like "Accel".
    * @return                true if the modifier key is active.  Otherwise,
    *                        false.
    */
-  boolean getModifierState(in DOMString aModifierKey);
+  boolean getModifierState(in AString aModifierKey);
 
   /**
    * shareModifierStateOf() makes the instance shares modifier state of
    * another instance.  When this is called, the instance refers the modifier
    * state of another instance.  After that, changes to either this and the
    * other instance's modifier state is synchronized.
    *
    * @param aOther          Another instance which will be referred by the
--- a/dom/interfaces/notification/nsINotificationStorage.idl
+++ b/dom/interfaces/notification/nsINotificationStorage.idl
@@ -14,26 +14,26 @@ interface nsINotificationStorageCallback
    * @param id: a uuid for this notification
    * @param title: the notification title
    * @param dir: the notification direction,
    *             possible values are "ltr", "rtl", "auto"
    * @param lang: the notification language
    * @param body: the notification body
    * @param tag: the notification tag
    */
-  void handle(in DOMString id,
-              in DOMString title,
-              in DOMString dir,
-              in DOMString lang,
-              in DOMString body,
-              in DOMString tag,
-              in DOMString icon,
-              in DOMString data,
-              in DOMString behavior,
-              in DOMString serviceWorkerRegistrationScope);
+  void handle(in AString id,
+              in AString title,
+              in AString dir,
+              in AString lang,
+              in AString body,
+              in AString tag,
+              in AString icon,
+              in AString data,
+              in AString behavior,
+              in AString serviceWorkerRegistrationScope);
 
   /**
    * Callback function used to notify C++ the we have returned
    * all notification objects for this Notification.get call.
    */
   void done();
 };
 
@@ -60,74 +60,74 @@ interface nsINotificationStorage : nsISu
    *                   Stored in the database to avoid re-computing
    *                   it. Built from origin and tag or id depending
    *                   whether there is a tag defined.
    * @param registrationID: Opaque string that identifies the service worker
    *                        registration this Notification is associated with.
    *                        May be empty. Only set for Notifications created by
    *                        showNotification().
    */
-  void put(in DOMString origin,
-           in DOMString id,
-           in DOMString title,
-           in DOMString dir,
-           in DOMString lang,
-           in DOMString body,
-           in DOMString tag,
-           in DOMString icon,
-           in DOMString alertName,
-           in DOMString data,
-           in DOMString behavior,
-           in DOMString serviceWorkerRegistrationScope);
+  void put(in AString origin,
+           in AString id,
+           in AString title,
+           in AString dir,
+           in AString lang,
+           in AString body,
+           in AString tag,
+           in AString icon,
+           in AString alertName,
+           in AString data,
+           in AString behavior,
+           in AString serviceWorkerRegistrationScope);
 
   /**
    * Retrieve a list of notifications.
    *
    * @param origin: the origin/app for which to fetch notifications from
    * @param tag: used to fetch only a specific tag
    * @param callback: nsINotificationStorageCallback, used for
    *                  returning notifications objects
    */
-  void get(in DOMString origin,
-           in DOMString tag,
+  void get(in AString origin,
+           in AString tag,
            in nsINotificationStorageCallback aCallback);
 
   /**
    * Retrieve a notification by ID.
    *
    * @param origin: the origin/app for which to fetch notifications.
    * @param id: the id of the notification.
    * @param callback: nsINotificationStorageCallback whose Handle method will
    * be called *at most once* if the notification with that ID is found. Not
    * called if that ID is not found. Done() will be called right after
    * Handle().
    */
-  void getByID(in DOMString origin,
-               in DOMString id,
+  void getByID(in AString origin,
+               in AString id,
                in nsINotificationStorageCallback aCallback);
 
   /**
    * Remove a notification from storage.
    *
    * @param origin: the origin/app to delete the notification from
    * @param id: the uuid for the notification to delete
    */
-  void delete(in DOMString origin,
-              in DOMString id);
+  void delete(in AString origin,
+              in AString id);
 
   /**
    * Notifications are not supposed to be persistent, according to spec, at
    * least for now. But we want to be able to have this behavior on B2G. Thus,
    * this method will check if the origin sending the notifications is a valid
    * registered app with a manifest or not. Hence, a webpage that has none
    * will have its notification sent and available (via Notification.get())
    * during the life time of the page.
    *
    * @param origin: Origin from which the notification is sent.
    *
    * @return boolean
    */
-  boolean canPut(in DOMString origin);
+  boolean canPut(in AString origin);
 };
 
 %{C++
 #define NS_NOTIFICATION_STORAGE_CONTRACTID "@mozilla.org/notificationStorage;1"
 %}
--- a/dom/interfaces/push/nsIPushErrorReporter.idl
+++ b/dom/interfaces/push/nsIPushErrorReporter.idl
@@ -35,11 +35,11 @@ interface nsIPushErrorReporter : nsISupp
   const uint16_t DELIVERY_UNHANDLED_REJECTION = 7;
   const uint16_t DELIVERY_INTERNAL_ERROR = 8;
 
   /**
    * Reports a `push` event handler error to the Push service. |messageId| is
    * an opaque string passed to `nsIPushNotifier.notifyPush{WithData}`.
    * |reason| is a delivery error reason.
    */
-  void reportDeliveryError(in DOMString messageId,
+  void reportDeliveryError(in AString messageId,
                            [optional] in uint16_t reason);
 };
--- a/dom/interfaces/push/nsIPushNotifier.idl
+++ b/dom/interfaces/push/nsIPushNotifier.idl
@@ -25,25 +25,25 @@ interface nsIPrincipal;
 interface nsIPushNotifier : nsISupports
 {
   /**
    * Fires a `push-message` observer notification, and sends a `push` event to
    * the service worker registered for the |scope|. |messageId| is an opaque ID
    * used to report errors if the worker fails to handle the message.
    */
   void notifyPush(in ACString scope, in nsIPrincipal principal,
-                  in DOMString messageId);
+                  in AString messageId);
 
   /**
    * Same as `notifyPush`, except the subject of the observer notification
    * receives an `nsIPushMessage` instance containing the |data|. Service
    * workers can access the |data| via the `PushMessageData` WebIDL interface.
    */
   void notifyPushWithData(in ACString scope, in nsIPrincipal principal,
-                          in DOMString messageId,
+                          in AString messageId,
                           [optional] in uint32_t dataLen,
                           [array, size_is(dataLen)] in uint8_t data);
 
   /**
    * Fires a `push-subscription-change` observer notification, and sends a
    * `pushsubscriptionchange` event to the service worker registered for the
    * |scope|.
    */
@@ -56,28 +56,28 @@ interface nsIPushNotifier : nsISupports
    *
    * This is useful for Dev Tools and debugging add-ons that passively observe
    * when subscriptions are created or dropped. Other callers should listen for
    * `push-subscription-change` and resubscribe instead.
    */
   void notifySubscriptionModified(in ACString scope, in nsIPrincipal principal);
 
   void notifyError(in ACString scope, in nsIPrincipal principal,
-                   in DOMString message, in uint32_t flags);
+                   in AString message, in uint32_t flags);
 };
 
 /**
  * Provides methods for retrieving push message data in different formats.
  * This interface resembles the `PushMessageData` WebIDL interface.
  */
 [scriptable, builtinclass, uuid(dfc4f151-cead-40df-8eb7-7a7a67c54b16)]
 interface nsIPushData : nsISupports
 {
   /** Extracts the data as a UTF-8 text string. */
-  DOMString text();
+  AString text();
 
   /** Extracts the data as a JSON value. */
   [implicit_jscontext] jsval json();
 
   /** Extracts the raw binary data. */
   void binary([optional] out uint32_t dataLen,
               [array, retval, size_is(dataLen)] out uint8_t data);
 };
--- a/dom/interfaces/push/nsIPushService.idl
+++ b/dom/interfaces/push/nsIPushService.idl
@@ -9,27 +9,27 @@ interface nsIPrincipal;
 
 /**
  * A push subscription, passed as an argument to a subscription callback.
  * Similar to the `PushSubscription` WebIDL interface.
  */
 [scriptable, uuid(1de32d5c-ea88-4c9e-9626-b032bd87f415)]
 interface nsIPushSubscription : nsISupports
 {
-  readonly attribute DOMString endpoint;
+  readonly attribute AString endpoint;
   readonly attribute long long pushCount;
   readonly attribute long long lastPush;
   readonly attribute long quota;
   readonly attribute bool isSystemSubscription;
   readonly attribute jsval p256dhPrivateKey;
 
   bool quotaApplies();
   bool isExpired();
 
-  void getKey(in DOMString name,
+  void getKey(in AString name,
               [optional] out uint32_t keyLen,
               [array, size_is(keyLen), retval] out uint8_t key);
 };
 
 /**
  * Called by methods that return a push subscription. A non-success
  * |status| indicates that there was a problem returning the
  * subscription, and the |subscription| argument should be ignored. Otherwise,
@@ -71,19 +71,19 @@ interface nsIPushClearResultCallback : n
  * which uses service workers. This interface exists to support the DOM API,
  * and allows privileged code to receive messages without migrating to service
  * workers.
  */
 [scriptable, uuid(678ef584-bf25-47aa-ac84-03efc0865b68)]
 interface nsIPushService : nsISupports
 {
   /** Observer topic names, exported for convenience. */
-  readonly attribute DOMString pushTopic;
-  readonly attribute DOMString subscriptionChangeTopic;
-  readonly attribute DOMString subscriptionModifiedTopic;
+  readonly attribute AString pushTopic;
+  readonly attribute AString subscriptionChangeTopic;
+  readonly attribute AString subscriptionModifiedTopic;
 
   /**
    * Creates a push subscription for the given |scope| URL and |principal|.
    * If a subscription already exists for this |(scope, principal)| pair,
    * the callback will receive the existing record as the second argument.
    *
    * The |endpoint| property of the subscription record is a URL string
    * that can be used to send push messages to subscribers.
@@ -91,48 +91,48 @@ interface nsIPushService : nsISupports
    * Each incoming message fires a `push-message` observer notification, with
    * an `nsIPushMessage` as the subject and the |scope| as the data.
    *
    * If the server drops a subscription, a `push-subscription-change` observer
    * will be fired, with the subject set to |principal| and the data set to
    * |scope|. Servers may drop subscriptions at any time, so callers should
    * recreate subscriptions if desired.
    */
-  void subscribe(in DOMString scope, in nsIPrincipal principal,
+  void subscribe(in AString scope, in nsIPrincipal principal,
                  in nsIPushSubscriptionCallback callback);
 
   /**
    * Creates a restricted push subscription with the given public |key|. The
    * application server must use the corresponding private key to authenticate
    * message delivery requests, as described in draft-thomson-webpush-vapid.
    */
-  void subscribeWithKey(in DOMString scope, in nsIPrincipal principal,
+  void subscribeWithKey(in AString scope, in nsIPrincipal principal,
                         in uint32_t keyLength,
                         [const, array, size_is(keyLength)] in uint8_t key,
                         in nsIPushSubscriptionCallback callback);
 
   /**
    * Removes a push subscription for the given |scope|.
    */
-  void unsubscribe(in DOMString scope, in nsIPrincipal principal,
+  void unsubscribe(in AString scope, in nsIPrincipal principal,
                    in nsIUnsubscribeResultCallback callback);
 
   /**
    * Retrieves the subscription record associated with the given
    * |(scope, principal)| pair. If the subscription does not exist, the
    * callback will receive |null| as the second argument.
    */
-  void getSubscription(in DOMString scope, in nsIPrincipal principal,
+  void getSubscription(in AString scope, in nsIPrincipal principal,
                        in nsIPushSubscriptionCallback callback);
 
   /**
    * Drops every subscription for the given |domain|, or all domains if
    * |domain| is "*".
    */
-  void clearForDomain(in DOMString domain,
+  void clearForDomain(in AString domain,
                       in nsIPushClearResultCallback callback);
 };
 
 [scriptable, uuid(a2555e70-46f8-4b52-bf02-d978b979d143)]
 interface nsIPushQuotaManager : nsISupports
 {
   /**
    * Informs the quota manager that a notification
--- a/dom/interfaces/sidebar/nsIWebContentHandlerRegistrar.idl
+++ b/dom/interfaces/sidebar/nsIWebContentHandlerRegistrar.idl
@@ -20,19 +20,19 @@
 [scriptable, uuid(65a3fafd-0e4a-4b06-8b4e-6a611da63d98)]
 interface nsIWebContentHandlerRegistrar : nsISupports
 {
   /**
    * See documentation in Navigator.webidl
    * The additional contentWindow param for this method represents the dom
    * content window from which the method has been called.
    */
-   void registerProtocolHandler(in DOMString protocol,
-                                in DOMString uri,
-                                in DOMString title,
+   void registerProtocolHandler(in AString protocol,
+                                in AString uri,
+                                in AString title,
                                 in nsISupports windowOrBrowser);
   /**
    * Removes a registered protocol handler
    *
    * While registerProtocolHandler is exposed on Navigator, unregistering
    * is exposed through the UI code.
    * @param   protocol
    *          The protocol scheme to remove a service handler for
--- a/dom/interfaces/storage/nsIDOMStorageManager.idl
+++ b/dom/interfaces/storage/nsIDOMStorageManager.idl
@@ -41,17 +41,17 @@ interface nsIDOMStorageManager : nsISupp
    *    Principal to bound storage to.
    * @param aDocumentURI
    *    URL of the demanding document, used for DOM storage event only.
    * @param aPrivate
    *    Whether the demanding document is running in Private Browsing mode or not.
    */
   Storage createStorage(in mozIDOMWindow aWindow,
                         in nsIPrincipal aPrincipal,
-                        in DOMString aDocumentURI,
+                        in AString aDocumentURI,
                         [optional] in bool aPrivate);
   /**
    * Returns instance of DOM storage object for given principal.
    * If there is no storage managed for the scope, then null is returned and
    * no object is created.  Otherwise, an object (new) for the existing storage
    * scope is returned.
    *
    * @param aWindow
--- a/dom/interfaces/xul/nsIDOMXULButtonElement.idl
+++ b/dom/interfaces/xul/nsIDOMXULButtonElement.idl
@@ -2,20 +2,20 @@
 /* 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 "nsIDOMXULControlElement.idl"
 
 [scriptable, uuid(6ed53cfb-9e59-424c-af8d-e74582381951)]
 interface nsIDOMXULButtonElement : nsIDOMXULControlElement {
-  attribute DOMString type;
-  attribute DOMString dlgType;
+  attribute AString type;
+  attribute AString dlgType;
 
   // For buttons of type="menu" only.
   attribute boolean open;
   
   // For buttons of type="checkbox" only.
   attribute boolean checked;
 
   // For buttons of type="radio" only.
-  attribute DOMString group;
+  attribute AString group;
 };
--- a/dom/interfaces/xul/nsIDOMXULCommandDispatcher.idl
+++ b/dom/interfaces/xul/nsIDOMXULCommandDispatcher.idl
@@ -13,21 +13,21 @@ webidl Element;
 
 [scriptable, uuid(a9fa9fd3-8d62-4f94-9ed8-3ea9c3cf0773)]
 interface nsIDOMXULCommandDispatcher : nsISupports
 {
             attribute Element focusedElement;
             attribute mozIDOMWindowProxy focusedWindow;
 
   void                      addCommandUpdater(in Element updater,
-                                              in DOMString events,
-                                              in DOMString targets);
+                                              in AString events,
+                                              in AString targets);
   void                      removeCommandUpdater(in Element updater);
 
-  void                      updateCommands(in DOMString eventName);
+  void                      updateCommands(in AString eventName);
 
   nsIController             getControllerForCommand(in string command);
   nsIControllers            getControllers();
 
   void advanceFocus();
   void rewindFocus();
   void advanceFocusIntoSubtree(in Element elt);
 
--- a/dom/interfaces/xul/nsIDOMXULMenuListElement.idl
+++ b/dom/interfaces/xul/nsIDOMXULMenuListElement.idl
@@ -8,17 +8,17 @@
 webidl Element;
 
 [scriptable, uuid(36c16a17-c0e9-4b35-951b-81a147314ef1)]
 interface nsIDOMXULMenuListElement : nsIDOMXULSelectControlElement {
   attribute boolean editable;
   attribute boolean open;
   
   // label of selected option or value of textfield for editable menu lists
-  readonly attribute DOMString label;
+  readonly attribute AString label;
 
-  attribute DOMString crop;
-  attribute DOMString image;
+  attribute AString crop;
+  attribute AString image;
   
   // For editable menu lists only.
   readonly attribute Element inputField;
 };
 
--- a/dom/interfaces/xul/nsIDOMXULMultSelectCntrlEl.idl
+++ b/dom/interfaces/xul/nsIDOMXULMultSelectCntrlEl.idl
@@ -5,17 +5,17 @@
 
 #include "nsIDOMXULSelectCntrlEl.idl"
 
 webidl NodeList;
 
 [scriptable, uuid(40654a10-8204-4f06-9f21-7baa31c7b1dd)]
 interface nsIDOMXULMultiSelectControlElement : nsIDOMXULSelectControlElement
 {
-  attribute DOMString selType;
+  attribute AString selType;
 
   attribute nsIDOMXULSelectControlItemElement currentItem;
   attribute long currentIndex;
 
   readonly attribute NodeList selectedItems;
   
   void addItemToSelection(in nsIDOMXULSelectControlItemElement item);
   void removeItemFromSelection(in nsIDOMXULSelectControlItemElement item);
--- a/dom/interfaces/xul/nsIDOMXULSelectCntrlEl.idl
+++ b/dom/interfaces/xul/nsIDOMXULSelectCntrlEl.idl
@@ -6,15 +6,15 @@
 #include "nsIDOMXULControlElement.idl"
 interface nsIDOMXULSelectControlItemElement;
 
 [scriptable, uuid(9bf188a7-d6f9-431b-b5c7-118013998e8b)]
 interface nsIDOMXULSelectControlElement : nsIDOMXULControlElement {
   attribute nsIDOMXULSelectControlItemElement selectedItem;
   attribute long selectedIndex;
 
-  attribute DOMString value;
+  attribute AString value;
 
   readonly attribute unsigned long itemCount;
   long getIndexOfItem(in nsIDOMXULSelectControlItemElement item);
   nsIDOMXULSelectControlItemElement getItemAtIndex(in long index);
 };
 
--- a/dom/interfaces/xul/nsIDOMXULSelectCntrlItemEl.idl
+++ b/dom/interfaces/xul/nsIDOMXULSelectCntrlItemEl.idl
@@ -4,23 +4,23 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 interface nsIDOMXULSelectControlElement;
 
 [scriptable, uuid(5c6be58f-17df-4750-88a5-4a59ac28adc9)]
 interface nsIDOMXULSelectControlItemElement : nsISupports {
   attribute boolean disabled;
-  attribute DOMString crop;
-  attribute DOMString image;
-  attribute DOMString label;
-  attribute DOMString accessKey;
-  attribute DOMString command;
+  attribute AString crop;
+  attribute AString image;
+  attribute AString label;
+  attribute AString accessKey;
+  attribute AString command;
   
-  attribute DOMString value;
+  attribute AString value;
   
   readonly attribute boolean selected;
   
   readonly attribute nsIDOMXULSelectControlElement control;
   
   // XXX defined in XULElement, but should be defined here
   // void doCommand();
 };
--- a/dom/media/gmp/mozIGeckoMediaPluginChromeService.idl
+++ b/dom/media/gmp/mozIGeckoMediaPluginChromeService.idl
@@ -29,17 +29,17 @@ interface mozIGeckoMediaPluginChromeServ
   void removeAndDeletePluginDirectory(in AString directory,
                                       [optional] in bool defer);
 
   /**
    * Clears storage data associated with the site and the originAttributes
    * pattern in JSON format.
    */
   void forgetThisSite(in AString site,
-                      in DOMString aPattern);
+                      in AString aPattern);
 
   /**
    * Returns true if the given node id is allowed to store things
    * persistently on disk. Private Browsing and local content are not
    * allowed to store persistent data.
    */
   bool isPersistentStorageAllowed(in ACString nodeId);
 
--- a/dom/media/hls/HLSDecoder.cpp
+++ b/dom/media/hls/HLSDecoder.cpp
@@ -178,23 +178,18 @@ HLSDecoder::AddSizeOfResources(ResourceS
   MOZ_ASSERT(NS_IsMainThread());
   // TODO: track JAVA wrappers.
 }
 
 already_AddRefed<nsIPrincipal>
 HLSDecoder::GetCurrentPrincipal()
 {
   MOZ_ASSERT(NS_IsMainThread());
-  nsCOMPtr<nsIPrincipal> principal;
-  nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
-  if (!secMan || !mChannel) {
-    return nullptr;
-  }
-  secMan->GetChannelResultPrincipal(mChannel, getter_AddRefs(principal));
-  return principal.forget();
+  // Bug 1478843
+  return nullptr;
 }
 
 void
 HLSDecoder::Play()
 {
   MOZ_ASSERT(NS_IsMainThread());
   HLS_DEBUG("HLSDecoder", "MediaElement called Play");
   mHLSResourceWrapper->Play();
--- a/dom/media/nsIAudioDeviceInfo.idl
+++ b/dom/media/nsIAudioDeviceInfo.idl
@@ -3,21 +3,21 @@
  * 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 "nsISupports.idl"
 
 [scriptable, uuid(feb979a8-f8cc-4522-9dff-6c055ca50762)]
 interface nsIAudioDeviceInfo : nsISupports
 {
-  readonly attribute DOMString name;
+  readonly attribute AString name;
 
-  readonly attribute DOMString groupId;
+  readonly attribute AString groupId;
 
-  readonly attribute DOMString vendor;
+  readonly attribute AString vendor;
 
   // type: Unknown/Input/Output
   const unsigned short TYPE_UNKNOWN = 0;
   const unsigned short TYPE_INPUT   = 1;
   const unsigned short TYPE_OUTPUT  = 2;
   readonly attribute unsigned short type;
 
   // state: Disabled/Unplugged/Enabled
--- a/dom/media/nsIDOMNavigatorUserMedia.idl
+++ b/dom/media/nsIDOMNavigatorUserMedia.idl
@@ -3,21 +3,21 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 #include "nsIVariant.idl"
 
 [scriptable, builtinclass, uuid(ba3b2e08-1c07-4cd3-8822-f4d7e35ff2ae)]
 interface nsIMediaDevice : nsISupports
 {
-  readonly attribute DOMString type;
-  readonly attribute DOMString name;
-  readonly attribute DOMString id;
-  readonly attribute DOMString mediaSource;
-  readonly attribute DOMString rawId;
+  readonly attribute AString type;
+  readonly attribute AString name;
+  readonly attribute AString id;
+  readonly attribute AString mediaSource;
+  readonly attribute AString rawId;
   readonly attribute boolean scary;
 };
 
 [scriptable, function, uuid(24544878-d35e-4962-8c5f-fb84e97bdfee)]
 interface nsIGetUserMediaDevicesSuccessCallback : nsISupports
 {
   void onSuccess(in nsIVariant devices);
 };
--- a/dom/media/webspeech/synth/nsISpeechService.idl
+++ b/dom/media/webspeech/synth/nsISpeechService.idl
@@ -87,28 +87,28 @@ interface nsISpeechTask : nsISupports
   /**
    * Dispatch boundary event.
    *
    * @param aName        name of boundary, 'word' or 'sentence'
    * @param aElapsedTime time in seconds since speech has started.
    * @param aCharIndex   offset of spoken characters.
    * @param aCharLength  length of text in boundary event to be spoken.
    */
-  [optional_argc] void dispatchBoundary(in DOMString aName, in float aElapsedTime,
+  [optional_argc] void dispatchBoundary(in AString aName, in float aElapsedTime,
                                         in unsigned long aCharIndex,
                                         [optional] in unsigned long aCharLength);
 
   /**
    * Dispatch mark event.
    *
    * @param aName        mark identifier.
    * @param aElapsedTime time in seconds since speech has started.
    * @param aCharIndex   offset of spoken characters.
    */
-  void dispatchMark(in DOMString aName, in float aElapsedTime, in unsigned long aCharIndex);
+  void dispatchMark(in AString aName, in float aElapsedTime, in unsigned long aCharIndex);
 };
 
 /**
  * The main interface of a speech synthesis service.
  *
  * A service is responsible for outputting audio.
  * The service dispatches events, starting with dispatchStart() and ending with
  * dispatchEnd or dispatchError().
@@ -126,17 +126,17 @@ interface nsISpeechService : nsISupports
    * @param aText   text to utter.
    * @param aUri    unique voice identifier.
    * @param aVolume volume to speak voice in. Only relevant for indirect audio.
    * @param aRate   rate to speak voice in.
    * @param aPitch  pitch to speak voice in.
    * @param aTask  task instance for utterance, used for sending events or audio
    *                 data back to browser.
    */
-  void speak(in DOMString aText, in DOMString aUri,
+  void speak(in AString aText, in AString aUri,
              in float aVolume, in float aRate, in float aPitch,
              in nsISpeechTask aTask);
 };
 
 %{C++
 // This is the service category speech services could use to start up as
 // a component.
 #define NS_SPEECH_SYNTH_STARTED "speech-synth-started"
--- a/dom/media/webspeech/synth/nsISynthVoiceRegistry.idl
+++ b/dom/media/webspeech/synth/nsISynthVoiceRegistry.idl
@@ -15,53 +15,53 @@ interface nsISynthVoiceRegistry : nsISup
    *
    * @param aService          the service that provides this voice.
    * @param aUri              a unique identifier for this voice.
    * @param aName             human-readable name for this voice.
    * @param aLang             a BCP 47 language tag.
    * @param aLocalService     true if service does not require network.
    * @param aQueuesUtterances true if voice only speaks one utterance at a time
    */
-  void addVoice(in nsISpeechService aService, in DOMString aUri,
-                in DOMString aName, in DOMString aLang,
+  void addVoice(in nsISpeechService aService, in AString aUri,
+                in AString aName, in AString aLang,
                 in boolean aLocalService, in boolean aQueuesUtterances);
 
   /**
    * Remove a speech synthesis voice.
    *
    * @param aService the service that was used to add the voice.
    * @param aUri     a unique identifier of an existing voice.
    */
-  void removeVoice(in nsISpeechService aService, in DOMString aUri);
+  void removeVoice(in nsISpeechService aService, in AString aUri);
 
   /**
    * Notify content of voice availability changes. This allows content
    * to be notified of voice catalog changes in real time.
    */
   void notifyVoicesChanged();
 
   /**
    * Set a voice as default.
    *
    * @param aUri       a unique identifier of an existing voice.
    * @param aIsDefault true if this voice should be toggled as default.
    */
-  void setDefaultVoice(in DOMString aUri, in boolean aIsDefault);
+  void setDefaultVoice(in AString aUri, in boolean aIsDefault);
 
   readonly attribute uint32_t voiceCount;
 
   AString getVoice(in uint32_t aIndex);
 
-  bool isDefaultVoice(in DOMString aUri);
+  bool isDefaultVoice(in AString aUri);
 
-  bool isLocalVoice(in DOMString aUri);
+  bool isLocalVoice(in AString aUri);
 
-  AString getVoiceLang(in DOMString aUri);
+  AString getVoiceLang(in AString aUri);
 
-  AString getVoiceName(in DOMString aUri);
+  AString getVoiceName(in AString aUri);
 };
 
 %{C++
 #define NS_SYNTHVOICEREGISTRY_CID                   \
   { /* {7090524d-5574-4492-a77f-d8d558ced59d} */       \
     0x7090524d,                                        \
     0x5574,                                            \
     0x4492,                                            \
--- a/dom/midi/MIDIAccessManager.cpp
+++ b/dom/midi/MIDIAccessManager.cpp
@@ -3,16 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/MIDIAccessManager.h"
 #include "mozilla/dom/MIDIAccess.h"
 #include "mozilla/dom/MIDIManagerChild.h"
 #include "mozilla/dom/MIDIPermissionRequest.h"
+#include "mozilla/dom/FeaturePolicyUtils.h"
 #include "mozilla/dom/Promise.h"
 #include "nsIGlobalObject.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/ipc/PBackgroundChild.h"
 #include "mozilla/ipc/BackgroundChild.h"
 #include "mozilla/Preferences.h"
 
 using namespace mozilla::ipc;
@@ -65,16 +66,22 @@ MIDIAccessManager::RequestMIDIAccess(nsP
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
   nsCOMPtr<nsIDocument> doc = aWindow->GetDoc();
   if (NS_WARN_IF(!doc)) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
+
+  if (!FeaturePolicyUtils::IsFeatureAllowed(doc, NS_LITERAL_STRING("midi"))) {
+    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
+    return nullptr;
+  }
+
   nsCOMPtr<nsIRunnable> permRunnable = new MIDIPermissionRequest(aWindow, p, aOptions);
   aRv = NS_DispatchToMainThread(permRunnable);
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
   return p.forget();
 }
 
--- a/dom/network/interfaces/nsITCPSocketCallback.idl
+++ b/dom/network/interfaces/nsITCPSocketCallback.idl
@@ -28,23 +28,23 @@
 interface nsITCPSocketCallback : nsISupports {
   // Limitation of TCPSocket's buffer size.
   const unsigned long BUFFER_SIZE = 65536;
 
   // Dispatch an "error" event at this object with the given name and type.
   void fireErrorEvent(in AString name, in AString type);
 
   // Dispatch a "data" event at this object with a string
-  void fireDataStringEvent(in DOMString type, in ACString data);
+  void fireDataStringEvent(in AString type, in ACString data);
 
   // Dispatch a "data" event at this object with an Array
-  void fireDataArrayEvent(in DOMString type, [const] in nsUint8TArrayRef data);
+  void fireDataArrayEvent(in AString type, [const] in nsUint8TArrayRef data);
 
   // Dispatch an event of the given type at this object.
-  void fireEvent(in DOMString type);
+  void fireEvent(in AString type);
 
   // Update the DOM object's readyState.
   // @param readyState
   //        new ready state
   void updateReadyState(in unsigned long readystate);
 
   // Update the DOM object's bufferedAmount value with a tracking number to
   // to allow tracking of which writes are "in-flight"
--- a/dom/power/nsIDOMWakeLockListener.idl
+++ b/dom/power/nsIDOMWakeLockListener.idl
@@ -20,10 +20,10 @@ interface nsIDOMMozWakeLockListener : ns
    *    and it is visible.
    *
    *  - "locked-background" - at least one window holds the wake lock,
    *    but all of them are hidden.
    *
    * @param aTopic The resource name related to the wake lock.
    * @param aState The wake lock state
    */
-  void callback(in DOMString aTopic, in DOMString aState);
+  void callback(in AString aTopic, in AString aState);
 };
--- a/dom/power/nsIPowerManagerService.idl
+++ b/dom/power/nsIPowerManagerService.idl
@@ -16,17 +16,17 @@ interface mozIDOMWindow;
 /**
  * For use with non-content code.
  */
 [scriptable, builtinclass, uuid(ba7ca4c1-9d92-4425-a83b-85dd7fa953f7)]
 interface nsIPowerManagerService : nsISupports
 {
   void              addWakeLockListener(in nsIDOMMozWakeLockListener aListener);
   void              removeWakeLockListener(in nsIDOMMozWakeLockListener aListener);
-  DOMString         getWakeLockState(in DOMString aTopic);
+  AString           getWakeLockState(in AString aTopic);
 
   /**
    * Return a wake lock (MozWakeLock) object of aTopic associated with aWindow.
    * A wake lock without associated window, e.g. used in chrome, is
    * always considered invisible.
    */
-  nsISupports newWakeLock(in DOMString aTopic, [optional] in mozIDOMWindow aWindow);
+  nsISupports newWakeLock(in AString aTopic, [optional] in mozIDOMWindow aWindow);
 };
--- a/dom/presentation/interfaces/nsIPresentationControlChannel.idl
+++ b/dom/presentation/interfaces/nsIPresentationControlChannel.idl
@@ -21,17 +21,17 @@ interface nsIPresentationChannelDescript
   readonly attribute nsIArray tcpAddress;
 
   // Port number for TCP channel.
   // Should only be used while type == TYPE_TCP.
   readonly attribute uint16_t tcpPort;
 
   // SDP for Data Channel.
   // Should only be used while type == TYPE_DATACHANNEL.
-  readonly attribute DOMString dataChannelSDP;
+  readonly attribute AString dataChannelSDP;
 };
 
 /*
  * The callbacks for events on control channel.
  */
 [scriptable, uuid(96dd548f-7d0f-43c1-b1ad-28e666cf1e82)]
 interface nsIPresentationControlChannelListener: nsISupports
 {
@@ -46,17 +46,17 @@ interface nsIPresentationControlChannelL
    * @param answer The received answer.
    */
   void onAnswer(in nsIPresentationChannelDescription answer);
 
   /*
    * Callback for receiving ICE candidate from remote endpoint.
    * @param answer The received answer.
    */
-  void onIceCandidate(in DOMString candidate);
+  void onIceCandidate(in AString candidate);
 
   /*
    * The callback for notifying channel connected. This should be async called
    * after nsIPresentationDevice::establishControlChannel.
    */
   void notifyConnected();
 
   /*
@@ -100,40 +100,40 @@ interface nsIPresentationControlChannel:
   void sendAnswer(in nsIPresentationChannelDescription answer);
 
   /*
    * Send ICE candidate to remote endpoint. |onIceCandidate| should be invoked
    * on remote endpoint.
    * @param candidate The candidate to send
    * @throws NS_ERROR_FAILURE on failure
    */
-  void sendIceCandidate(in DOMString candidate);
+  void sendIceCandidate(in AString candidate);
 
   /*
    * Launch a presentation on remote endpoint.
    * @param presentationId The Id for representing this session.
    * @param url The URL requested to open by remote device.
    * @throws NS_ERROR_FAILURE on failure
    */
-  void launch(in DOMString presentationId, in DOMString url);
+  void launch(in AString presentationId, in AString url);
 
   /*
    * Terminate a presentation on remote endpoint.
    * @param presentationId The Id for representing this session.
    * @throws NS_ERROR_FAILURE on failure
    */
-  void terminate(in DOMString presentationId);
+  void terminate(in AString presentationId);
 
   /*
    * Disconnect the control channel.
    * @param reason The reason of disconnecting channel; NS_OK represents normal.
    */
   void disconnect(in nsresult reason);
 
   /*
    * Reconnect a presentation on remote endpoint.
    * Note that only controller is allowed to reconnect a session.
    * @param presentationId The Id for representing this session.
    * @param url The URL requested to open by remote device.
    * @throws NS_ERROR_FAILURE on failure
    */
-  void reconnect(in DOMString presentationId, in DOMString url);
+  void reconnect(in AString presentationId, in AString url);
 };
--- a/dom/presentation/interfaces/nsIPresentationControlService.idl
+++ b/dom/presentation/interfaces/nsIPresentationControlService.idl
@@ -50,42 +50,42 @@ interface nsIPresentationControlServerLi
   /**
    * Callback while the remote host is requesting to start a presentation session.
    * @param aDeviceInfo The device information related to the remote host.
    * @param aUrl The URL requested to open by remote device.
    * @param aPresentationId The Id for representing this session.
    * @param aControlChannel The control channel for this session.
    */
   void onSessionRequest(in nsITCPDeviceInfo aDeviceInfo,
-                        in DOMString aUrl,
-                        in DOMString aPresentationId,
+                        in AString aUrl,
+                        in AString aPresentationId,
                         in nsIPresentationControlChannel aControlChannel);
 
   /**
    * Callback while the remote host is requesting to terminate a presentation session.
    * @param aDeviceInfo The device information related to the remote host.
    * @param aPresentationId The Id for representing this session.
    * @param aControlChannel The control channel for this session.
    * @param aIsFromReceiver true if termination is initiated by receiver.
    */
   void onTerminateRequest(in nsITCPDeviceInfo aDeviceInfo,
-                          in DOMString aPresentationId,
+                          in AString aPresentationId,
                           in nsIPresentationControlChannel aControlChannel,
                           in boolean aIsFromReceiver);
 
   /**
    * Callback while the remote host is requesting to reconnect a presentation session.
    * @param aDeviceInfo The device information related to the remote host.
    * @param aUrl The URL requested to open by remote device.
    * @param aPresentationId The Id for representing this session.
    * @param aControlChannel The control channel for this session.
    */
   void onReconnectRequest(in nsITCPDeviceInfo aDeviceInfo,
-                          in DOMString url,
-                          in DOMString aPresentationId,
+                          in AString url,
+                          in AString aPresentationId,
                           in nsIPresentationControlChannel aControlChannel);
 };
 
 /**
  * Presentation control service which can be used for both presentation
  * control client and server.
  */
 [scriptable, uuid(55d6b605-2389-4aae-a8fe-60d4440540ea)]
--- a/dom/presentation/interfaces/nsIPresentationDevice.idl
+++ b/dom/presentation/interfaces/nsIPresentationDevice.idl
@@ -32,12 +32,12 @@ interface nsIPresentationDevice : nsISup
   // Do something when presentation session is disconnected.
   void disconnect();
 
   /*
    * Query if requested presentation URL is supported.
    * @params requestedUrl the designated URL for a presentation request.
    * @returns true if designated URL is supported.
    */
-  boolean isRequestedUrlSupported(in DOMString requestedUrl);
+  boolean isRequestedUrlSupported(in AString requestedUrl);
 };
 
 
--- a/dom/presentation/interfaces/nsIPresentationDevicePrompt.idl
+++ b/dom/presentation/interfaces/nsIPresentationDevicePrompt.idl
@@ -16,17 +16,17 @@ webidl EventTarget;
 
 /*
  * The information and callbacks for device selection
  */
 [scriptable, uuid(b2aa7f6a-9448-446a-bba4-9c29638b0ed4)]
 interface nsIPresentationDeviceRequest : nsISupports
 {
   // The origin which initiate the request.
-  readonly attribute DOMString origin;
+  readonly attribute AString origin;
 
   // The array of candidate URLs.
   readonly attribute nsIArray requestURLs;
 
   // The XUL browser element that the request was originated in.
   readonly attribute EventTarget chromeEventHandler;
 
   // The principal of the request.
--- a/dom/presentation/interfaces/nsIPresentationDeviceProvider.idl
+++ b/dom/presentation/interfaces/nsIPresentationDeviceProvider.idl
@@ -24,42 +24,42 @@ interface nsIPresentationDeviceListener:
   /*
    * Callback while the remote device is requesting to start a presentation session.
    * @param device The remote device that sent session request.
    * @param url The URL requested to open by remote device.
    * @param presentationId The Id for representing this session.
    * @param controlChannel The control channel for this session.
    */
   void onSessionRequest(in nsIPresentationDevice device,
-                        in DOMString url,
-                        in DOMString presentationId,
+                        in AString url,
+                        in AString presentationId,
                         in nsIPresentationControlChannel controlChannel);
 
   /*
    * Callback while the remote device is requesting to terminate a presentation session.
    * @param device The remote device that sent session request.
    * @param presentationId The Id for representing this session.
    * @param controlChannel The control channel for this session.
    * @param aIsFromReceiver true if termination is initiated by receiver.
    */
   void onTerminateRequest(in nsIPresentationDevice device,
-                          in DOMString presentationId,
+                          in AString presentationId,
                           in nsIPresentationControlChannel controlChannel,
                           in boolean aIsFromReceiver);
 
   /*
    * Callback while the remote device is requesting to reconnect a presentation session.
    * @param device The remote device that sent session request.
    * @param aUrl The URL requested to open by remote device.
    * @param presentationId The Id for representing this session.
    * @param controlChannel The control channel for this session.
    */
   void onReconnectRequest(in nsIPresentationDevice device,
-                          in DOMString url,
-                          in DOMString presentationId,
+                          in AString url,
+                          in AString presentationId,
                           in nsIPresentationControlChannel controlChannel);
 };
 
 /*
  * Device provider for any device protocol, can be registered as default
  * providers by adding its contractID to category "presentation-device-provider".
  */
 [scriptable, uuid(3db2578a-0f50-44ad-b01b-28427b71b7bf)]
--- a/dom/presentation/interfaces/nsIPresentationListener.idl
+++ b/dom/presentation/interfaces/nsIPresentationListener.idl
@@ -22,29 +22,29 @@ interface nsIPresentationSessionListener
   const unsigned short STATE_CONNECTING = 0;
   const unsigned short STATE_CONNECTED = 1;
   const unsigned short STATE_CLOSED = 2;
   const unsigned short STATE_TERMINATED = 3;
 
   /*
    * Called when session state changes.
    */
-  void notifyStateChange(in DOMString sessionId,
+  void notifyStateChange(in AString sessionId,
                          in unsigned short state,
                          in nsresult reason);
 
   /*
    * Called when receive messages.
    */
-  void notifyMessage(in DOMString sessionId,
+  void notifyMessage(in AString sessionId,
                      in ACString data,
                      in boolean isBinary);
 };
 
 [scriptable, uuid(27f101d7-9ed1-429e-b4f8-43b00e8e111c)]
 interface nsIPresentationRespondingListener : nsISupports
 {
   /*
    * Called when an incoming session connects.
    */
   void notifySessionConnect(in unsigned long long windowId,
-                            in DOMString sessionId);
+                            in AString sessionId);
 };
--- a/dom/presentation/interfaces/nsIPresentationRequestUIGlue.idl
+++ b/dom/presentation/interfaces/nsIPresentationRequestUIGlue.idl
@@ -18,12 +18,12 @@ interface nsIPresentationRequestUIGlue :
    * This method is called to open the responding app/page when
    * a presentation request comes in at receiver side.
    *
    * @param url       The url of the request.
    * @param sessionId The session ID of the request.
    *
    * @return A promise that resolves to the opening frame.
    */
-  Promise sendRequest(in DOMString url,
-                      in DOMString sessionId,
+  Promise sendRequest(in AString url,
+                      in AString sessionId,
                       in nsIPresentationDevice device);
 };
--- a/dom/presentation/interfaces/nsIPresentationService.idl
+++ b/dom/presentation/interfaces/nsIPresentationService.idl
@@ -31,17 +31,17 @@ webidl EventTarget;
 [scriptable, uuid(12073206-0065-4b10-9488-a6eb9b23e65b)]
 interface nsIPresentationServiceCallback : nsISupports
 {
   /*
    * Called when the operation succeeds.
    *
    * @param url: the selected request url used to start or reconnect a session.
    */
-  void notifySuccess(in DOMString url);
+  void notifySuccess(in AString url);
 
   /*
    * Called when the operation fails.
    *
    * @param error: error message.
    */
   void notifyError(in nsresult error);
 };
@@ -75,89 +75,89 @@ interface nsIPresentationService : nsISu
    * @param principal: The principal that initiated the session.
    * @param callback: Invoke the callback when the operation is completed.
    *                  NotifySuccess() is called with |id| if a session is
    *                  established successfully with the selected device.
    *                  Otherwise, NotifyError() is called with a error message.
    * @param constructor: The constructor for creating a transport builder.
    */
   [noscript] void startSession(in URLArrayRef urls,
-                               in DOMString sessionId,
-                               in DOMString origin,
-                               in DOMString deviceId,
+                               in AString sessionId,
+                               in AString origin,
+                               in AString deviceId,
                                in unsigned long long windowId,
                                in EventTarget eventTarget,
                                in nsIPrincipal principal,
                                in nsIPresentationServiceCallback callback,
                                in nsIPresentationTransportBuilderConstructor constructor);
 
   /*
    * Send the message to the session.
    *
    * @param sessionId: An ID to identify presentation session.
    * @param role: Identify the function called by controller or receiver.
    * @param data: the message being sent out.
    */
-  void sendSessionMessage(in DOMString sessionId,
-							            in uint8_t role,
-                          in DOMString data);
+  void sendSessionMessage(in AString sessionId,
+                          in uint8_t role,
+                          in AString data);
 
   /*
    * Send the binary message to the session.
    *
    * @param sessionId: An ID to identify presentation session.
    * @param role: Identify the function called by controller or receiver.
    * @param data: the message being sent out.
    */
-  void sendSessionBinaryMsg(in DOMString sessionId,
+  void sendSessionBinaryMsg(in AString sessionId,
                             in uint8_t role,
                             in ACString data);
 
   /*
    * Send the blob to the session.
    *
    * @param sessionId: An ID to identify presentation session.
    * @param role: Identify the function called by controller or receiver.
    * @param blob: The input blob to be sent.
    */
-  void sendSessionBlob(in DOMString sessionId,
+  void sendSessionBlob(in AString sessionId,
                        in uint8_t role,
                        in Blob blob);
 
   /*
    * Close the session.
    *
    * @param sessionId: An ID to identify presentation session.
    * @param role: Identify the function called by controller or receiver.
    */
-  void closeSession(in DOMString sessionId,
+  void closeSession(in AString sessionId,
                     in uint8_t role,
                     in uint8_t closedReason);
 
   /*
    * Terminate the session.
    *
    * @param sessionId: An ID to identify presentation session.
    * @param role: Identify the function called by controller or receiver.
    */
-  void terminateSession(in DOMString sessionId,
+  void terminateSession(in AString sessionId,
                         in uint8_t role);
 
   /*
    * Reconnect the session.
    *
    * @param url: The request Urls.
    * @param sessionId: An ID to identify presentation session.
    * @param role: Identify the function called by controller or receiver.
    * @param callback: NotifySuccess() is called when a control channel
    *                  is opened successfully.
    *                  Otherwise, NotifyError() is called with a error message.
    */
   [noscript] void reconnectSession(in URLArrayRef urls,
-                                   in DOMString sessionId,
+                                   in AString sessionId,
                                    in uint8_t role,
                                    in nsIPresentationServiceCallback callback);
 
   /*
    * Register an availability listener. Must be called from the main thread.
    *
    * @param availabilityUrls: The Urls that this listener is interested in.
    * @param listener: The listener to register.
@@ -178,27 +178,27 @@ interface nsIPresentationService : nsISu
 
   /*
    * Register a session listener. Must be called from the main thread.
    *
    * @param sessionId: An ID to identify presentation session.
    * @param role: Identify the function called by controller or receiver.
    * @param listener: The listener to register.
    */
-  void registerSessionListener(in DOMString sessionId,
+  void registerSessionListener(in AString sessionId,
                                in uint8_t role,
                                in nsIPresentationSessionListener listener);
 
   /*
    * Unregister a session listener. Must be called from the main thread.
    *
    * @param sessionId: An ID to identify presentation session.
    * @param role: Identify the function called by controller or receiver.
    */
-  void unregisterSessionListener(in DOMString sessionId,
+  void unregisterSessionListener(in AString sessionId,
                                  in uint8_t role);
 
   /*
    * Register a responding listener. Must be called from the main thread.
    *
    * @param windowId: The window ID associated with the listener.
    * @param listener: The listener to register.
    */
@@ -215,62 +215,62 @@ interface nsIPresentationService : nsISu
    * Notify the receiver page is ready for presentation use.
    *
    * @param sessionId An ID to identify presentation session.
    * @param windowId  The inner window ID associated with the presentation
    *                  session.
    * @param isLoading true if receiver page is loading successfully.
    * @param constructor: The constructor for creating a transport builder.
    */
-  void notifyReceiverReady(in DOMString sessionId,
+  void notifyReceiverReady(in AString sessionId,
                            in unsigned long long windowId,
                            in boolean isLoading,
                            in nsIPresentationTransportBuilderConstructor constructor);
 
   /*
    * Notify the transport is closed
    *
    * @param sessionId: An ID to identify presentation session.
    * @param role: Identify the function called by controller or receiver.
    * @param reason: the error message. NS_OK indicates it is closed normally.
    */
-  void NotifyTransportClosed(in DOMString sessionId,
+  void NotifyTransportClosed(in AString sessionId,
                              in uint8_t role,
                              in nsresult reason);
 
   /*
    * Untrack the relevant info about the presentation session if there's any.
    *
    * @param sessionId: An ID to identify presentation session.
    * @param role: Identify the function called by controller or receiver.
    */
-  void untrackSessionInfo(in DOMString sessionId, in uint8_t role);
+  void untrackSessionInfo(in AString sessionId, in uint8_t role);
 
   /*
    * The windowId for building RTCDataChannel session transport
    *
    * @param sessionId: An ID to identify presentation session.
    * @param role: Identify the function called by controller or receiver.
    */
-  unsigned long long getWindowIdBySessionId(in DOMString sessionId,
+  unsigned long long getWindowIdBySessionId(in AString sessionId,
                                             in uint8_t role);
 
   /*
    * Update the mapping of the session ID and window ID.
    *
    * @param sessionId: An ID to identify presentation session.
    * @param role: Identify the function called by controller or receiver.
    * @param windowId: The inner window ID associated with the presentation
    *                  session.
    */
-  void updateWindowIdBySessionId(in DOMString sessionId,
+  void updateWindowIdBySessionId(in AString sessionId,
                                  in uint8_t role,
                                  in unsigned long long windowId);
 
   /*
    * To build the session transport.
    * NOTE: This function should be only called at controller side.
    *
    * @param sessionId: An ID to identify presentation session.
    * @param role: Identify the function called by controller or receiver.
    */
-  void buildTransport(in DOMString sessionId, in uint8_t role);
+  void buildTransport(in AString sessionId, in uint8_t role);
 };
--- a/dom/presentation/interfaces/nsIPresentationSessionRequest.idl
+++ b/dom/presentation/interfaces/nsIPresentationSessionRequest.idl
@@ -20,16 +20,16 @@ interface nsIPresentationControlChannel;
  */
 [scriptable, uuid(d808a084-d0f8-455a-a8df-5879e05a755b)]
 interface nsIPresentationSessionRequest: nsISupports
 {
   // The device which requesting the presentation session.
   readonly attribute nsIPresentationDevice device;
 
   // The URL requested to open by remote device.
-  readonly attribute DOMString url;
+  readonly attribute AString url;
 
   // The Id for representing this session.
-  readonly attribute DOMString presentationId;
+  readonly attribute AString presentationId;
 
   // The control channel for this session.
   readonly attribute nsIPresentationControlChannel controlChannel;
 };
--- a/dom/presentation/interfaces/nsIPresentationSessionTransport.idl
+++ b/dom/presentation/interfaces/nsIPresentationSessionTransport.idl
@@ -43,17 +43,17 @@ interface nsIPresentationSessionTranspor
    * Should set callback before |enableDataNotification| is called.
    */
   void enableDataNotification();
 
   /*
    * Send message to the remote endpoint.
    * @param data The message to send.
    */
-  void send(in DOMString data);
+  void send(in AString data);
 
   /*
    * Send the binary message to the remote endpoint.
    * @param data: the message being sent out.
    */
   void sendBinaryMsg(in ACString data);
 
   /*
--- a/dom/presentation/interfaces/nsIPresentationSessionTransportBuilder.idl
+++ b/dom/presentation/interfaces/nsIPresentationSessionTransportBuilder.idl
@@ -14,17 +14,17 @@ interface nsIPresentationSessionTranspor
 interface nsIPresentationSessionTransportBuilderListener : nsISupports
 {
   // Should set |transport.callback| in |onSessionTransport|.
   void onSessionTransport(in nsIPresentationSessionTransport transport);
   void onError(in nsresult reason);
 
   void sendOffer(in nsIPresentationChannelDescription offer);
   void sendAnswer(in nsIPresentationChannelDescription answer);
-  void sendIceCandidate(in DOMString candidate);
+  void sendIceCandidate(in AString candidate);
   void close(in nsresult reason);
 };
 
 [scriptable, uuid(2fdbe67d-80f9-48dc-8237-5bef8fa19801)]
 interface nsIPresentationSessionTransportBuilder : nsISupports
 {
 };
 
@@ -70,11 +70,11 @@ interface nsIPresentationDataChannelSess
    */
   void buildDataChannelTransport(in uint8_t aRole,
                                  in mozIDOMWindow aWindow,
                                  in nsIPresentationSessionTransportBuilderListener aListener);
 
   // Bug 1275150 - Merge TCP builder with the following APIs
   void onOffer(in nsIPresentationChannelDescription offer);
   void onAnswer(in nsIPresentationChannelDescription answer);
-  void onIceCandidate(in DOMString candidate);
+  void onIceCandidate(in AString candidate);
   void notifyDisconnected(in nsresult reason);
 };
--- a/dom/presentation/interfaces/nsIPresentationTerminateRequest.idl
+++ b/dom/presentation/interfaces/nsIPresentationTerminateRequest.idl
@@ -17,17 +17,17 @@ interface nsIPresentationControlChannel;
  */
 [scriptable, uuid(3ddbf3a4-53ee-4b70-9bbc-58ac90dce6b5)]
 interface nsIPresentationTerminateRequest: nsISupports
 {
   // The device which requesting to terminate presentation session.
   readonly attribute nsIPresentationDevice device;
 
   // The Id for representing this session.
-  readonly attribute DOMString presentationId;
+  readonly attribute AString presentationId;
 
   // The control channel for this session.
   // Should only use this channel to complete session termination.
   readonly attribute nsIPresentationControlChannel controlChannel;
 
   // True if termination is initiated by receiver.
   readonly attribute boolean isFromReceiver;
 };
--- a/dom/security/featurepolicy/FeaturePolicyUtils.cpp
+++ b/dom/security/featurepolicy/FeaturePolicyUtils.cpp
@@ -21,45 +21,31 @@ struct FeatureMap {
 };
 
 /*
  * IMPORTANT: Do not change this list without review from a DOM peer _AND_ a
  * DOM Security peer!
  */
 static FeatureMap sSupportedFeatures[] = {
   // TODO: not supported yet!!!
-  { "accelerometer", FeatureMap::eSelf },
-  // TODO: not supported yet!!!
-  { "ambient-light-sensor", FeatureMap::eSelf },
-  // TODO: not supported yet!!!
   { "autoplay", FeatureMap::eSelf },
   // TODO: not supported yet!!!
   { "camera", FeatureMap::eSelf  },
-  // TODO: not supported yet!!!
   { "encrypted-media", FeatureMap::eSelf  },
   // TODO: not supported yet!!!
   { "fullscreen", FeatureMap::eSelf  },
   // TODO: not supported yet!!!
   { "geolocation", FeatureMap::eSelf  },
   // TODO: not supported yet!!!
-  { "gyroscope", FeatureMap::eSelf  },
-  // TODO: not supported yet!!!
-  { "magnetometer", FeatureMap::eSelf  },
-  // TODO: not supported yet!!!
   { "microphone", FeatureMap::eSelf  },
-  // TODO: not supported yet!!!
   { "midi", FeatureMap::eSelf  },
   { "payment", FeatureMap::eSelf  },
   // TODO: not supported yet!!!
-  { "picture-in-picture", FeatureMap::eAll  },
-  // TODO: not supported yet!!!
   { "speaker", FeatureMap::eSelf  },
   // TODO: not supported yet!!!
-  { "usb", FeatureMap::eSelf  },
-  // TODO: not supported yet!!!
   { "vr", FeatureMap::eSelf  },
 };
 
 /* static */ bool
 FeaturePolicyUtils::IsSupportedFeature(const nsAString& aFeatureName)
 {
   uint32_t numFeatures = (sizeof(sSupportedFeatures) / sizeof(sSupportedFeatures[0]));
   for (uint32_t i = 0; i < numFeatures; ++i) {
--- a/dom/workers/nsIWorkerDebugger.idl
+++ b/dom/workers/nsIWorkerDebugger.idl
@@ -3,20 +3,20 @@
 interface mozIDOMWindow;
 interface nsIPrincipal;
 
 [scriptable, uuid(9cf3b48e-361d-486a-8917-55cf8d00bb41)]
 interface nsIWorkerDebuggerListener : nsISupports
 {
   void onClose();
 
-  void onError(in DOMString filename, in unsigned long lineno,
-               in DOMString message);
+  void onError(in AString filename, in unsigned long lineno,
+               in AString message);
 
-  void onMessage(in DOMString message);
+  void onMessage(in AString message);
 };
 
 [scriptable, builtinclass, uuid(22f93aa3-8a05-46be-87e0-fa93bf8a8eff)]
 interface nsIWorkerDebugger : nsISupports
 {
   const unsigned long TYPE_DEDICATED = 0;
   const unsigned long TYPE_SHARED = 1;
   const unsigned long TYPE_SERVICE = 2;
@@ -26,25 +26,25 @@ interface nsIWorkerDebugger : nsISupport
   readonly attribute bool isChrome;
 
   readonly attribute bool isInitialized;
 
   readonly attribute nsIWorkerDebugger parent;
 
   readonly attribute unsigned long type;
 
-  readonly attribute DOMString url;
+  readonly attribute AString url;
 
   readonly attribute mozIDOMWindow window;
 
   readonly attribute nsIPrincipal principal;
 
   readonly attribute unsigned long serviceWorkerID;
 
-  void initialize(in DOMString url);
+  void initialize(in AString url);
 
   [binaryname(PostMessageMoz)]
-  void postMessage(in DOMString message);
+  void postMessage(in AString message);
 
   void addListener(in nsIWorkerDebuggerListener listener);
 
   void removeListener(in nsIWorkerDebuggerListener listener);
 };
--- a/dom/xslt/txIEXSLTRegExFunctions.idl
+++ b/dom/xslt/txIEXSLTRegExFunctions.idl
@@ -6,16 +6,16 @@
 #include "nsISupports.idl"
 
 webidl Document;
 webidl DocumentFragment;
 
 [scriptable, uuid(c180e993-aced-4839-95a0-ecd5ff138be9)]
 interface txIEXSLTRegExFunctions : nsISupports
 {
-    DocumentFragment match(in DOMString aString, in DOMString aRegEx,
-                           in DOMString aFlags,
+    DocumentFragment match(in AString aString, in AString aRegEx,
+                           in AString aFlags,
                            in Document aResultDocument);
-    DOMString replace(in DOMString aString, in DOMString aRegEx,
-                      in DOMString aFlags, in DOMString aReplace);
-    boolean test(in DOMString aString, in DOMString aRegEx,
-                 in DOMString aFlags);
+    AString replace(in AString aString, in AString aRegEx,
+                    in AString aFlags, in AString aReplace);
+    boolean test(in AString aString, in AString aRegEx,
+                 in AString aFlags);
 };
--- a/dom/xslt/xslt/txMozillaXSLTProcessor.cpp
+++ b/dom/xslt/xslt/txMozillaXSLTProcessor.cpp
@@ -773,17 +773,16 @@ txMozillaXSLTProcessor::SetParameter(con
         case nsIDataType::VTYPE_DOUBLE:
 
         // Boolean
         case nsIDataType::VTYPE_BOOL:
 
         // String
         case nsIDataType::VTYPE_CHAR:
         case nsIDataType::VTYPE_WCHAR:
-        case nsIDataType::VTYPE_DOMSTRING:
         case nsIDataType::VTYPE_CHAR_STR:
         case nsIDataType::VTYPE_WCHAR_STR:
         case nsIDataType::VTYPE_STRING_SIZE_IS:
         case nsIDataType::VTYPE_WSTRING_SIZE_IS:
         case nsIDataType::VTYPE_UTF8STRING:
         case nsIDataType::VTYPE_CSTRING:
         case nsIDataType::VTYPE_ASTRING:
         {
@@ -1352,17 +1351,16 @@ txVariable::Convert(nsIVariant *aValue, 
             NS_ADDREF(*aResult);
 
             return NS_OK;
         }
 
         // String
         case nsIDataType::VTYPE_CHAR:
         case nsIDataType::VTYPE_WCHAR:
-        case nsIDataType::VTYPE_DOMSTRING:
         case nsIDataType::VTYPE_CHAR_STR:
         case nsIDataType::VTYPE_WCHAR_STR:
         case nsIDataType::VTYPE_STRING_SIZE_IS:
         case nsIDataType::VTYPE_WSTRING_SIZE_IS:
         case nsIDataType::VTYPE_UTF8STRING:
         case nsIDataType::VTYPE_CSTRING:
         case nsIDataType::VTYPE_ASTRING:
         {
--- a/dom/xul/XULTextElement.h
+++ b/dom/xul/XULTextElement.h
@@ -32,16 +32,24 @@ public:
   void GetValue(DOMString& aValue) const
   {
     GetXULAttr(nsGkAtoms::value, aValue);
   }
   MOZ_CAN_RUN_SCRIPT void SetValue(const nsAString& aValue)
   {
     SetAttr(kNameSpaceID_None, nsGkAtoms::value, aValue, true);
   }
+  void GetAccessKey(DOMString& aValue) const
+  {
+    GetXULAttr(nsGkAtoms::accesskey, aValue);
+  }
+  MOZ_CAN_RUN_SCRIPT void SetAccessKey(const nsAString& aValue)
+  {
+    SetAttr(kNameSpaceID_None, nsGkAtoms::accesskey, aValue, true);
+  }
 
 protected:
   virtual ~XULTextElement() {}
   JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) final;
 };
 
 } // namespace dom
 } // namespace mozilla
--- a/editor/nsIEditActionListener.idl
+++ b/editor/nsIEditActionListener.idl
@@ -30,17 +30,17 @@ Editor Action Listener interface to outs
 interface nsIEditActionListener : nsISupports
 {
   /**
    * Called after the editor creates a node.
    * @param aTag      The tag name of the DOM Node to create.
    * @param aNewNode  The DOM Node that was created.
    * @param aResult   The result of the create node operation.
    */
-  void DidCreateNode(in DOMString aTag,
+  void DidCreateNode(in AString aTag,
                      in Node aNewNode,
                      in nsresult aResult);
 
   /**
    * Called after the editor inserts a node.
    * @param aNode     The DOM Node to insert.
    * @param aResult   The result of the insert node operation.
    */
@@ -82,17 +82,17 @@ interface nsIEditActionListener : nsISup
    * Called after the editor inserts text.
    * @param aTextNode   This node getting inserted text.
    * @param aOffset     The offset in aTextNode to insert at.
    * @param aString     The string that gets inserted.
    * @param aResult     The result of the insert text operation.
    */
   void DidInsertText(in CharacterData       aTextNode,
                      in long                aOffset,
-                     in DOMString           aString,
+                     in AString             aString,
                      in nsresult            aResult);
 
   /**
    * Called before the editor deletes text.
    * @param aTextNode   This node getting text deleted.
    * @param aOffset     The offset in aTextNode to delete at.
    * @param aLength     The amount of text to delete.
    */
--- a/editor/nsIEditor.idl
+++ b/editor/nsIEditor.idl
@@ -52,17 +52,17 @@ interface nsIEditor  : nsISupports
 
   readonly attribute Selection selection;
 
   void setAttributeOrEquivalent(in Element element,
                                 in AString sourceAttrName,
                                 in AString sourceAttrValue,
                                 in boolean aSuppressTransaction);
   void removeAttributeOrEquivalent(in Element element,
-                                   in DOMString sourceAttrName,
+                                   in AString sourceAttrName,
                                    in boolean aSuppressTransaction);
 
   /** edit flags for this editor.  May be set at any time. */
   attribute unsigned long flags;
 
   /**
    * the MimeType of the document
    */
--- a/editor/nsIPlaintextEditor.idl
+++ b/editor/nsIPlaintextEditor.idl
@@ -89,17 +89,17 @@ interface nsIPlaintextEditor : nsISuppor
   /**
    * Inserts a string at the current location,
    * given by the selection.
    * If the selection is not collapsed, the selection is deleted
    * and the insertion takes place at the resulting collapsed selection.
    *
    * @param aString   the string to be inserted
    */
-   void insertText(in DOMString aStringToInsert);
+   void insertText(in AString aStringToInsert);
 
   /**
    * Insert a line break into the content model.
    * The interpretation of a break is up to the implementation:
    * it may enter a character, split a node in the tree, etc.
    * This may be more efficient than calling InsertText with a newline.
    */
   void insertLineBreak();
--- a/editor/nsIURIRefObject.idl
+++ b/editor/nsIURIRefObject.idl
@@ -24,20 +24,20 @@ interface nsIURIRefObject  : nsISupports
   /**
    * Go back to the beginning of the attribute list.
    */
   void Reset();
 
   /**
    * Return the next rewritable URI.
    */
-  DOMString GetNextURI();
+  AString GetNextURI();
 
   /**
    * Go back to the beginning of the attribute list
    *
    * @param aOldPat  Old pattern to be replaced, e.g. file:///a/b/
    * @param aNewPat  New pattern to be replaced, e.g. http://mypage.aol.com/
    * @param aMakeRel Rewrite links as relative vs. absolute
    */
-  void RewriteAllURIs(in DOMString aOldPat, in DOMString aNewPat,
+  void RewriteAllURIs(in AString aOldPat, in AString aNewPat,
                       in boolean aMakeRel);
 };
--- a/gfx/webrender_bindings/RenderThread.cpp
+++ b/gfx/webrender_bindings/RenderThread.cpp
@@ -237,28 +237,29 @@ RenderThread::GetRenderer(wr::WindowId a
 size_t
 RenderThread::RendererCount()
 {
   MOZ_ASSERT(IsInRenderThread());
   return mRenderers.size();
 }
 
 void
-RenderThread::NewFrameReady(wr::WindowId aWindowId)
+RenderThread::HandleFrame(wr::WindowId aWindowId, bool aRender)
 {
   if (mHasShutdown) {
     return;
   }
 
   if (!IsInRenderThread()) {
     Loop()->PostTask(
-      NewRunnableMethod<wr::WindowId>("wr::RenderThread::NewFrameReady",
-                                      this,
-                                      &RenderThread::NewFrameReady,
-                                      aWindowId));
+      NewRunnableMethod<wr::WindowId, bool>("wr::RenderThread::NewFrameReady",
+                                            this,
+                                            &RenderThread::HandleFrame,
+                                            aWindowId,
+                                            aRender));
     return;
   }
 
   if (IsDestroyed(aWindowId)) {
     return;
   }
 
   if (mHandlingDeviceReset) {
@@ -271,17 +272,17 @@ RenderThread::NewFrameReady(wr::WindowId
     MutexAutoLock lock(mFrameCountMapLock);
     auto it = mWindowInfos.find(AsUint64(aWindowId));
     MOZ_ASSERT(it != mWindowInfos.end());
     WindowInfo* info = it->second;
     MOZ_ASSERT(info->mPendingCount > 0);
     startTime = info->mStartTimes.front();
   }
 
-  UpdateAndRender(aWindowId, startTime);
+  UpdateAndRender(aWindowId, startTime, aRender, /* aReadback */ false);
   FrameRenderingComplete(aWindowId);
 }
 
 void
 RenderThread::WakeUp(wr::WindowId aWindowId)
 {
   if (mHasShutdown) {
     return;
@@ -348,33 +349,35 @@ NotifyDidRender(layers::CompositorBridge
   }
 
   wr_pipeline_info_delete(aInfo);
 }
 
 void
 RenderThread::UpdateAndRender(wr::WindowId aWindowId,
                               const TimeStamp& aStartTime,
+                              bool aRender,
                               bool aReadback)
 {
   AUTO_PROFILER_TRACING("Paint", "Composite");
   MOZ_ASSERT(IsInRenderThread());
+  MOZ_ASSERT(aRender || !aReadback);
 
   auto it = mRenderers.find(aWindowId);
   MOZ_ASSERT(it != mRenderers.end());
   if (it == mRenderers.end()) {
     return;
   }
 
   auto& renderer = it->second;
 
-  bool ret = renderer->UpdateAndRender(aReadback);
-  if (!ret) {
-    // Render did not happen, do not call NotifyDidRender.
-    return;
+  if (aRender) {
+    renderer->UpdateAndRender(aReadback);
+  } else {
+    renderer->Update();
   }
 
   TimeStamp end = TimeStamp::Now();
 
   auto info = renderer->FlushPipelineInfo();
   RefPtr<layers::AsyncImagePipelineManager> pipelineMgr =
       renderer->GetCompositorBridge()->GetAsyncImagePipelineManager();
   // pipelineMgr should always be non-null here because it is only nulled out
@@ -745,35 +748,35 @@ WebRenderProgramCache::~WebRenderProgram
   wr_program_cache_delete(mProgramCache);
 }
 
 } // namespace wr
 } // namespace mozilla
 
 extern "C" {
 
-static void NewFrameReady(mozilla::wr::WrWindowId aWindowId)
+static void HandleFrame(mozilla::wr::WrWindowId aWindowId, bool aRender)
 {
   mozilla::wr::RenderThread::Get()->IncRenderingFrameCount(aWindowId);
-  mozilla::wr::RenderThread::Get()->NewFrameReady(aWindowId);
+  mozilla::wr::RenderThread::Get()->HandleFrame(aWindowId, aRender);
 }
 
 void wr_notifier_wake_up(mozilla::wr::WrWindowId aWindowId)
 {
   mozilla::wr::RenderThread::Get()->WakeUp(aWindowId);
 }
 
 void wr_notifier_new_frame_ready(mozilla::wr::WrWindowId aWindowId)
 {
-  NewFrameReady(aWindowId);
+  HandleFrame(aWindowId, /* aRender */ true);
 }
 
 void wr_notifier_nop_frame_done(mozilla::wr::WrWindowId aWindowId)
 {
-  mozilla::wr::RenderThread::Get()->DecPendingFrameCount(aWindowId);
+  HandleFrame(aWindowId, /* aRender */ false);
 }
 
 void wr_notifier_external_event(mozilla::wr::WrWindowId aWindowId, size_t aRawEvent)
 {
   mozilla::UniquePtr<mozilla::wr::RendererEvent> evt(
     reinterpret_cast<mozilla::wr::RendererEvent*>(aRawEvent));
   mozilla::wr::RenderThread::Get()->RunEvent(mozilla::wr::WindowId(aWindowId),
                                              std::move(evt));
--- a/gfx/webrender_bindings/RenderThread.h
+++ b/gfx/webrender_bindings/RenderThread.h
@@ -121,29 +121,29 @@ public:
   void RemoveRenderer(wr::WindowId aWindowId);
 
   /// Can only be called from the render thread.
   RendererOGL* GetRenderer(wr::WindowId aWindowId);
 
   // RenderNotifier implementation
 
   /// Automatically forwarded to the render thread.
-  void NewFrameReady(wr::WindowId aWindowId);
+  void HandleFrame(wr::WindowId aWindowId, bool aRender);
 
   /// Automatically forwarded to the render thread.
   void WakeUp(wr::WindowId aWindowId);
 
   /// Automatically forwarded to the render thread.
   void PipelineSizeChanged(wr::WindowId aWindowId, uint64_t aPipelineId, float aWidth, float aHeight);
 
   /// Automatically forwarded to the render thread.
   void RunEvent(wr::WindowId aWindowId, UniquePtr<RendererEvent> aCallBack);
 
   /// Can only be called from the render thread.
-  void UpdateAndRender(wr::WindowId aWindowId, const TimeStamp& aStartTime, bool aReadback = false);
+  void UpdateAndRender(wr::WindowId aWindowId, const TimeStamp& aStartTime, bool aRender, bool aReadback);
 
   void Pause(wr::WindowId aWindowId);
   bool Resume(wr::WindowId aWindowId);
 
   /// Can be called from any thread.
   void RegisterExternalImage(uint64_t aExternalImageId, already_AddRefed<RenderTextureHost> aTexture);
 
   /// Can be called from any thread.
--- a/gfx/webrender_bindings/WebRenderAPI.cpp
+++ b/gfx/webrender_bindings/WebRenderAPI.cpp
@@ -411,17 +411,17 @@ WebRenderAPI::Readback(const TimeStamp& 
 
             ~Readback()
             {
                 MOZ_COUNT_DTOR(Readback);
             }
 
             virtual void Run(RenderThread& aRenderThread, WindowId aWindowId) override
             {
-                aRenderThread.UpdateAndRender(aWindowId, mStartTime, /* aReadback */ true);
+                aRenderThread.UpdateAndRender(aWindowId, mStartTime, /* aRender */ true, /* aReadback */ true);
                 wr_renderer_readback(aRenderThread.GetRenderer(aWindowId)->GetRenderer(),
                                      mSize.width, mSize.height, mBuffer, mBufferSize);
                 layers::AutoCompleteTask complete(mTask);
             }
 
             layers::SynchronousTask* mTask;
             TimeStamp mStartTime;
             gfx::IntSize mSize;
--- a/gfx/webrender_bindings/src/bindings.rs
+++ b/gfx/webrender_bindings/src/bindings.rs
@@ -1,13 +1,14 @@
 use std::ffi::{CStr, CString};
 use std::{mem, slice, ptr, env};
 use std::path::PathBuf;
 use std::rc::Rc;
 use std::sync::Arc;
+use std::sync::atomic::{AtomicUsize, Ordering};
 use std::os::raw::{c_void, c_char, c_float};
 use gleam::gl;
 
 use webrender::api::*;
 use webrender::{ReadPixelsFormat, Renderer, RendererOptions, ThreadListener};
 use webrender::{ExternalImage, ExternalImageHandler, ExternalImageSource};
 use webrender::DebugFlags;
 use webrender::{ApiRecordingReceiver, BinaryRecorder};
@@ -24,16 +25,23 @@ use nsstring::nsAString;
 #[cfg(target_os = "windows")]
 use dwrote::{FontDescriptor, FontWeight, FontStretch, FontStyle};
 
 #[cfg(target_os = "macos")]
 use core_foundation::string::CFString;
 #[cfg(target_os = "macos")]
 use core_graphics::font::CGFont;
 
+/// The unique id for WR resource identification.
+static NEXT_NAMESPACE_ID: AtomicUsize = AtomicUsize::new(1);
+
+fn next_namespace_id() -> IdNamespace {
+    IdNamespace(NEXT_NAMESPACE_ID.fetch_add(1, Ordering::Relaxed) as u32)
+}
+
 /// Whether a border should be antialiased.
 #[repr(C)]
 #[derive(Eq, PartialEq, Copy, Clone)]
 pub enum AntialiasBorder {
     No = 0,
     Yes,
 }
 
@@ -981,16 +989,17 @@ pub extern "C" fn wr_window_new(window_i
         },
         renderer_id: Some(window_id.0),
         upload_method,
         scene_builder_hooks: Some(Box::new(APZCallbacks::new(window_id))),
         sampler: Some(Box::new(SamplerCallback::new(window_id))),
         max_texture_size: Some(8192), // Moz2D doesn't like textures bigger than this
         clear_color: Some(ColorF::new(0.0, 0.0, 0.0, 0.0)),
         precache_shaders: env_var_to_bool("MOZ_WR_PRECACHE_SHADERS"),
+        namespace_alloc_by_client: true,
         ..Default::default()
     };
 
     let notifier = Box::new(CppNotifier {
         window_id: window_id,
     });
     let (renderer, sender) = match Renderer::new(gl, notifier, opts) {
         Ok((renderer, sender)) => (renderer, sender),
@@ -1005,33 +1014,33 @@ pub extern "C" fn wr_window_new(window_i
     };
 
     unsafe {
         *out_max_texture_size = renderer.get_max_texture_size();
     }
     let window_size = DeviceUintSize::new(window_width, window_height);
     let layer = 0;
     *out_handle = Box::into_raw(Box::new(
-            DocumentHandle::new(sender.create_api(), window_size, layer)));
+            DocumentHandle::new(sender.create_api_by_client(next_namespace_id()), window_size, layer)));
     *out_renderer = Box::into_raw(Box::new(renderer));
 
     return true;
 }
 
 #[no_mangle]
 pub extern "C" fn wr_api_create_document(
     root_dh: &mut DocumentHandle,
     out_handle: &mut *mut DocumentHandle,
     doc_size: DeviceUintSize,
     layer: i8,
 ) {
     assert!(unsafe { is_in_compositor_thread() });
 
     *out_handle = Box::into_raw(Box::new(DocumentHandle::new(
-        root_dh.api.clone_sender().create_api(),
+        root_dh.api.clone_sender().create_api_by_client(next_namespace_id()),
         doc_size,
         layer
     )));
 }
 
 /// cbindgen:postfix=WR_DESTRUCTOR_SAFE_FUNC
 #[no_mangle]
 pub unsafe extern "C" fn wr_api_delete_document(dh: &mut DocumentHandle) {
@@ -1041,17 +1050,17 @@ pub unsafe extern "C" fn wr_api_delete_d
 #[no_mangle]
 pub extern "C" fn wr_api_clone(
     dh: &mut DocumentHandle,
     out_handle: &mut *mut DocumentHandle
 ) {
     assert!(unsafe { is_in_compositor_thread() });
 
     let handle = DocumentHandle {
-        api: dh.api.clone_sender().create_api(),
+        api: dh.api.clone_sender().create_api_by_client(next_namespace_id()),
         document_id: dh.document_id,
     };
     *out_handle = Box::into_raw(Box::new(handle));
 }
 
 /// cbindgen:postfix=WR_DESTRUCTOR_SAFE_FUNC
 #[no_mangle]
 pub unsafe extern "C" fn wr_api_delete(dh: *mut DocumentHandle) {
--- a/image/MultipartImage.cpp
+++ b/image/MultipartImage.cpp
@@ -77,17 +77,18 @@ public:
     // Retrieve the image's intrinsic size.
     int32_t width = 0;
     int32_t height = 0;
     mImage->GetWidth(&width);
     mImage->GetHeight(&height);
 
     // Request decoding at the intrinsic size.
     mImage->RequestDecodeForSize(IntSize(width, height),
-                                 imgIContainer::DECODE_FLAGS_DEFAULT);
+                                 imgIContainer::DECODE_FLAGS_DEFAULT |
+                                 imgIContainer::FLAG_HIGH_QUALITY_SCALING);
 
     // If there's already an error, we may never get a FRAME_COMPLETE
     // notification, so go ahead and notify our owner right away.
     RefPtr<ProgressTracker> tracker = mImage->GetProgressTracker();
     if (tracker->GetProgress() & FLAG_HAS_ERROR) {
       FinishObserving();
     }
   }
--- a/image/RasterImage.cpp
+++ b/image/RasterImage.cpp
@@ -1131,33 +1131,35 @@ RasterImage::StartDecoding(uint32_t aFla
     return NS_ERROR_FAILURE;
   }
 
   if (!mHasSize) {
     mWantFullDecode = true;
     return NS_OK;
   }
 
-  uint32_t flags = (aFlags & FLAG_ASYNC_NOTIFY) | FLAG_SYNC_DECODE_IF_FAST;
+  uint32_t flags =
+    (aFlags & FLAG_ASYNC_NOTIFY) | FLAG_SYNC_DECODE_IF_FAST | FLAG_HIGH_QUALITY_SCALING;
   return RequestDecodeForSize(mSize, flags);
 }
 
 bool
 RasterImage::StartDecodingWithResult(uint32_t aFlags)
 {
   if (mError) {
     return false;
   }
 
   if (!mHasSize) {
     mWantFullDecode = true;
     return false;
   }
 
-  uint32_t flags = (aFlags & FLAG_ASYNC_NOTIFY) | FLAG_SYNC_DECODE_IF_FAST;
+  uint32_t flags =
+    (aFlags & FLAG_ASYNC_NOTIFY) | FLAG_SYNC_DECODE_IF_FAST | FLAG_HIGH_QUALITY_SCALING;
   DrawableSurface surface = RequestDecodeForSizeInternal(mSize, flags);
   return surface && surface->IsFinished();
 }
 
 NS_IMETHODIMP
 RasterImage::RequestDecodeForSize(const IntSize& aSize, uint32_t aFlags)
 {
   MOZ_ASSERT(NS_IsMainThread());
@@ -1809,17 +1811,17 @@ RasterImage::NotifyDecodeComplete(const 
     if (mLoadProgress) {
       NotifyForLoadEvent(*mLoadProgress);
       mLoadProgress = Nothing();
     }
 
     // If we were a metadata decode and a full decode was requested, do it.
     if (mWantFullDecode) {
       mWantFullDecode = false;
-      RequestDecodeForSize(mSize, DECODE_FLAGS_DEFAULT);
+      RequestDecodeForSize(mSize, DECODE_FLAGS_DEFAULT | FLAG_HIGH_QUALITY_SCALING);
     }
   }
 }
 
 void
 RasterImage::ReportDecoderError()
 {
   nsCOMPtr<nsIConsoleService> consoleService =
--- a/intl/l10n/mozIDOMLocalization.idl
+++ b/intl/l10n/mozIDOMLocalization.idl
@@ -13,17 +13,17 @@ webidl Node;
 interface mozIDOMLocalization : nsISupports
 {
   unsigned long addResourceIds(in Array<AString> resourceIds, in bool aEager);
   unsigned long removeResourceIds(in Array<AString> resourceIds);
   void registerObservers();
 
   Promise formatMessages(in Array<jsval> aKeys);
   Promise formatValues(in Array<jsval> aKeys);
-  Promise formatValue(in DOMString aId, [optional] in jsval aArgs);
+  Promise formatValue(in AString aId, [optional] in jsval aArgs);
 
   Promise translateFragment(in Node aNode);
   Promise translateElements(in Array<Element> aElements);
 
   void connectRoot(in Element aElement);
   Promise translateRoots();
   readonly attribute Promise ready;
 };
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -2007,21 +2007,16 @@ ParseIterativeFailureTestParams(JSContex
     }
 
     if (!args[0].isObject() || !args[0].toObject().is<JSFunction>()) {
         JS_ReportErrorASCII(cx, "The first argument must be the function to test.");
         return false;
     }
     params->testFunction = &args[0].toObject().as<JSFunction>();
 
-    // There are some places where we do fail without raising an exception, so
-    // we can't expose this to the fuzzers by default.
-    if (fuzzingSafe)
-        params->expectExceptionOnFailure = false;
-
     if (args.length() == 2) {
         if (args[1].isBoolean()) {
             params->expectExceptionOnFailure = args[1].toBoolean();
         } else if (args[1].isObject()) {
             RootedObject options(cx, &args[1].toObject());
             RootedValue value(cx);
 
             if (!JS_GetProperty(cx, options, "expectExceptionOnFailure", &value)) {
@@ -2038,16 +2033,22 @@ ParseIterativeFailureTestParams(JSContex
                 params->keepFailing = ToBoolean(value);
             }
         } else {
             JS_ReportErrorASCII(cx, "The optional second argument must be an object or a boolean.");
             return false;
         }
     }
 
+    // There are some places where we do fail without raising an exception, so
+    // we can't expose this to the fuzzers by default.
+    if (fuzzingSafe) {
+        params->expectExceptionOnFailure = false;
+    }
+
     // Test all threads by default.
     params->threadStart = oom::FirstThreadTypeToTest;
     params->threadEnd = oom::LastThreadTypeToTest;
 
     // Test a single thread type if specified by the OOM_THREAD environment variable.
     int threadOption = 0;
     if (EnvVarAsInt("OOM_THREAD", &threadOption)) {
         if (threadOption < oom::FirstThreadTypeToTest || threadOption > oom::LastThreadTypeToTest) {
--- a/js/src/frontend/BinSource-auto.cpp
+++ b/js/src/frontend/BinSource-auto.cpp
@@ -2593,16 +2593,19 @@ BinASTParser<Tok>::parseInterfaceArrayEx
 
 #if defined(DEBUG)
     const BinField expected_fields[1] = { BinField::Elements };
     MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif // defined(DEBUG)
 
     BINJS_MOZ_TRY_DECL(elements, parseListOfOptionalSpreadElementOrExpression());
 
+    if (elements->empty()) {
+        elements->setHasNonConstInitializer();
+    }
     auto result = elements;
     return result;
 }
 
 
 /*
  interface ArrowExpressionContentsWithExpression : Node {
     AssertedParameterScope parameterScope;
@@ -3852,16 +3855,28 @@ BinASTParser<Tok>::parseInterfaceCallExp
     MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif // defined(DEBUG)
 
     BINJS_MOZ_TRY_DECL(callee, parseExpressionOrSuper());
 
     BINJS_MOZ_TRY_DECL(arguments, parseArguments());
 
     auto op = JSOP_CALL;
+
+    // Try to optimize funcall and funapply at the bytecode level
+    if (PropertyName* prop = factory_.maybeDottedProperty(callee)) {
+        if (prop == cx_->names().apply) {
+            op = JSOP_FUNAPPLY;
+            if (parseContext_->isFunctionBox())
+                parseContext_->functionBox()->usesApply = true;
+        } else if (prop == cx_->names().call) {
+            op = JSOP_FUNCALL;
+        }
+    }
+
     // Check for direct calls to `eval`.
     if (factory_.isEvalName(callee, cx_)) {
         if (!parseContext_->varScope().lookupDeclaredNameForAdd(callee->name())
          && !parseContext_->innermostScope()->lookupDeclaredNameForAdd(callee->name())) {
             // This is a direct call to `eval`.
             if (!parseContext_->sc()->hasDirectEval()) {
                 return raiseMissingDirectEvalInAssertedScope();
             }
@@ -3916,16 +3931,17 @@ BinASTParser<Tok>::parseInterfaceCatchCl
     BINJS_TRY(currentScope.init(parseContext_));
 
     MOZ_TRY(parseAssertedBoundNamesScope());
 
     BINJS_MOZ_TRY_DECL(binding, parseBinding());
 
     BINJS_MOZ_TRY_DECL(body, parseBlock());
 
+    MOZ_TRY(checkClosedVars(currentScope));
     BINJS_TRY_DECL(bindings, NewLexicalScopeData(cx_, currentScope, alloc_, parseContext_));
     BINJS_TRY_DECL(result, factory_.newLexicalScope(*bindings, body));
     BINJS_TRY(factory_.setupCatchScope(result, binding, body));
     return result;
 }
 
 
 /*
@@ -4615,16 +4631,18 @@ BinASTParser<Tok>::parseInterfaceEagerFu
         isGenerator ? GeneratorKind::Generator
                     : GeneratorKind::NotGenerator,
         isAsync ? FunctionAsyncKind::AsyncFunction
                 : FunctionAsyncKind::SyncFunction,
         syntax,
         (syntax != FunctionSyntaxKind::Setter &&
          syntax != FunctionSyntaxKind::Getter) ? name : nullptr));
 
+    forceStrictIfNecessary(funbox, directives);
+
     // Push a new ParseContext. It will be used to parse `scope`, the arguments, the function.
     BinParseContext funpc(cx_, this, funbox, /* newDirectives = */ nullptr);
     BINJS_TRY(funpc.init());
     parseContext_->functionScope().useAsVarScope(parseContext_);
     MOZ_ASSERT(parseContext_->isFunctionBox());
 
     ParseContext::Scope lexicalScope(cx_, parseContext_, usedNames_);
     BINJS_TRY(lexicalScope.init(parseContext_));
@@ -4694,16 +4712,18 @@ BinASTParser<Tok>::parseInterfaceEagerFu
         isGenerator ? GeneratorKind::Generator
                     : GeneratorKind::NotGenerator,
         isAsync ? FunctionAsyncKind::AsyncFunction
                 : FunctionAsyncKind::SyncFunction,
         syntax,
         (syntax != FunctionSyntaxKind::Setter &&
          syntax != FunctionSyntaxKind::Getter) ? name : nullptr));
 
+    forceStrictIfNecessary(funbox, directives);
+
     // Push a new ParseContext. It will be used to parse `scope`, the arguments, the function.
     BinParseContext funpc(cx_, this, funbox, /* newDirectives = */ nullptr);
     BINJS_TRY(funpc.init());
     parseContext_->functionScope().useAsVarScope(parseContext_);
     MOZ_ASSERT(parseContext_->isFunctionBox());
 
     ParseContext::Scope lexicalScope(cx_, parseContext_, usedNames_);
     BINJS_TRY(lexicalScope.init(parseContext_));
@@ -4768,16 +4788,18 @@ BinASTParser<Tok>::parseInterfaceEagerGe
         isGenerator ? GeneratorKind::Generator
                     : GeneratorKind::NotGenerator,
         isAsync ? FunctionAsyncKind::AsyncFunction
                 : FunctionAsyncKind::SyncFunction,
         syntax,
         (syntax != FunctionSyntaxKind::Setter &&
          syntax != FunctionSyntaxKind::Getter) ? name : nullptr));
 
+    forceStrictIfNecessary(funbox, directives);
+
     // Push a new ParseContext. It will be used to parse `scope`, the arguments, the function.
     BinParseContext funpc(cx_, this, funbox, /* newDirectives = */ nullptr);
     BINJS_TRY(funpc.init());
     parseContext_->functionScope().useAsVarScope(parseContext_);
     MOZ_ASSERT(parseContext_->isFunctionBox());
 
     ParseContext::Scope lexicalScope(cx_, parseContext_, usedNames_);
     BINJS_TRY(lexicalScope.init(parseContext_));
@@ -4847,16 +4869,18 @@ BinASTParser<Tok>::parseInterfaceEagerMe
         isGenerator ? GeneratorKind::Generator
                     : GeneratorKind::NotGenerator,
         isAsync ? FunctionAsyncKind::AsyncFunction
                 : FunctionAsyncKind::SyncFunction,
         syntax,
         (syntax != FunctionSyntaxKind::Setter &&
          syntax != FunctionSyntaxKind::Getter) ? name : nullptr));
 
+    forceStrictIfNecessary(funbox, directives);
+
     // Push a new ParseContext. It will be used to parse `scope`, the arguments, the function.
     BinParseContext funpc(cx_, this, funbox, /* newDirectives = */ nullptr);
     BINJS_TRY(funpc.init());
     parseContext_->functionScope().useAsVarScope(parseContext_);
     MOZ_ASSERT(parseContext_->isFunctionBox());
 
     ParseContext::Scope lexicalScope(cx_, parseContext_, usedNames_);
     BINJS_TRY(lexicalScope.init(parseContext_));
@@ -4922,16 +4946,18 @@ BinASTParser<Tok>::parseInterfaceEagerSe
         isGenerator ? GeneratorKind::Generator
                     : GeneratorKind::NotGenerator,
         isAsync ? FunctionAsyncKind::AsyncFunction
                 : FunctionAsyncKind::SyncFunction,
         syntax,
         (syntax != FunctionSyntaxKind::Setter &&
          syntax != FunctionSyntaxKind::Getter) ? name : nullptr));
 
+    forceStrictIfNecessary(funbox, directives);
+
     // Push a new ParseContext. It will be used to parse `scope`, the arguments, the function.
     BinParseContext funpc(cx_, this, funbox, /* newDirectives = */ nullptr);
     BINJS_TRY(funpc.init());
     parseContext_->functionScope().useAsVarScope(parseContext_);
     MOZ_ASSERT(parseContext_->isFunctionBox());
 
     ParseContext::Scope lexicalScope(cx_, parseContext_, usedNames_);
     BINJS_TRY(lexicalScope.init(parseContext_));
@@ -6019,17 +6045,65 @@ BinASTParser<Tok>::parseLazyFunctionDecl
     MOZ_TRY(guard.done());
 
     return result;
 }
 
 template<typename Tok> JS::Result<ParseNode*>
 BinASTParser<Tok>::parseInterfaceLazyFunctionDeclaration(const size_t start, const BinKind kind, const BinFields& fields)
 {
-    return raiseError("FIXME: Not implemented yet (LazyFunctionDeclaration)");
+    MOZ_ASSERT(kind == BinKind::LazyFunctionDeclaration);
+    BINJS_TRY(CheckRecursionLimit(cx_));
+
+#if defined(DEBUG)
+    const BinField expected_fields[7] = { BinField::IsAsync, BinField::IsGenerator, BinField::Name, BinField::Length, BinField::Directives, BinField::ContentsSkip, BinField::Contents };
+    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
+#endif // defined(DEBUG)
+    const auto syntax = FunctionSyntaxKind::Statement;
+
+    BINJS_MOZ_TRY_DECL(isAsync, tokenizer_->readBool());
+
+    BINJS_MOZ_TRY_DECL(isGenerator, tokenizer_->readBool());
+
+    BINJS_MOZ_TRY_DECL(name, parseBindingIdentifier());
+
+    BINJS_MOZ_TRY_DECL(length, tokenizer_->readUnsignedLong());
+
+    BINJS_MOZ_TRY_DECL(directives, parseListOfDirective());
+
+    BINJS_MOZ_TRY_DECL(contentsSkip, tokenizer_->readSkippableSubTree());
+    // Don't parse the contents until we delazify.
+
+    BINJS_MOZ_TRY_DECL(funbox, buildFunctionBox(
+        isGenerator ? GeneratorKind::Generator
+                    : GeneratorKind::NotGenerator,
+        isAsync ? FunctionAsyncKind::AsyncFunction
+                : FunctionAsyncKind::SyncFunction,
+        syntax, name));
+
+    forceStrictIfNecessary(funbox, directives);
+
+    RootedFunction fun(cx_, funbox->function());
+
+    // TODO: This will become incorrect in the face of ES6 features.
+    fun->setArgCount(length);
+
+    auto skipStart = contentsSkip.startOffset();
+    BINJS_TRY_DECL(lazy, LazyScript::Create(cx_, fun, sourceObject_, parseContext_->closedOverBindingsForLazy(), parseContext_->innerFunctionsForLazy,
+                                            skipStart, skipStart + contentsSkip.length(),
+                                            skipStart, 0, skipStart, ParseGoal::Script));
+
+    if (funbox->strict()) {
+        lazy->setStrict();
+    }
+    lazy->setIsBinAST();
+    funbox->function()->initLazyScript(lazy);
+
+    BINJS_MOZ_TRY_DECL(result, makeEmptyFunctionNode(skipStart, kind, funbox));
+    return result;
 }
 
 
 /*
  interface LazyFunctionExpression : Node {
     bool isAsync;
     bool isGenerator;
     BindingIdentifier? name;
@@ -6054,17 +6128,65 @@ BinASTParser<Tok>::parseLazyFunctionExpr
     MOZ_TRY(guard.done());
 
     return result;
 }
 
 template<typename Tok> JS::Result<ParseNode*>
 BinASTParser<Tok>::parseInterfaceLazyFunctionExpression(const size_t start, const BinKind kind, const BinFields& fields)
 {
-    return raiseError("FIXME: Not implemented yet (LazyFunctionExpression)");
+    MOZ_ASSERT(kind == BinKind::LazyFunctionExpression);
+    BINJS_TRY(CheckRecursionLimit(cx_));
+
+#if defined(DEBUG)
+    const BinField expected_fields[7] = { BinField::IsAsync, BinField::IsGenerator, BinField::Name, BinField::Length, BinField::Directives, BinField::ContentsSkip, BinField::Contents };
+    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
+#endif // defined(DEBUG)
+    const auto syntax = FunctionSyntaxKind::Expression;
+
+    BINJS_MOZ_TRY_DECL(isAsync, tokenizer_->readBool());
+
+    BINJS_MOZ_TRY_DECL(isGenerator, tokenizer_->readBool());
+
+    BINJS_MOZ_TRY_DECL(name, parseOptionalBindingIdentifier());
+
+    BINJS_MOZ_TRY_DECL(length, tokenizer_->readUnsignedLong());
+
+    BINJS_MOZ_TRY_DECL(directives, parseListOfDirective());
+
+    BINJS_MOZ_TRY_DECL(contentsSkip, tokenizer_->readSkippableSubTree());
+    // Don't parse the contents until we delazify.
+
+    BINJS_MOZ_TRY_DECL(funbox, buildFunctionBox(
+        isGenerator ? GeneratorKind::Generator
+                    : GeneratorKind::NotGenerator,
+        isAsync ? FunctionAsyncKind::AsyncFunction
+                : FunctionAsyncKind::SyncFunction,
+        syntax, name));
+
+    forceStrictIfNecessary(funbox, directives);
+
+    RootedFunction fun(cx_, funbox->function());
+
+    // TODO: This will become incorrect in the face of ES6 features.
+    fun->setArgCount(length);
+
+    auto skipStart = contentsSkip.startOffset();
+    BINJS_TRY_DECL(lazy, LazyScript::Create(cx_, fun, sourceObject_, parseContext_->closedOverBindingsForLazy(), parseContext_->innerFunctionsForLazy,
+                                            skipStart, skipStart + contentsSkip.length(),
+                                            skipStart, 0, skipStart, ParseGoal::Script));
+
+    if (funbox->strict()) {
+        lazy->setStrict();
+    }
+    lazy->setIsBinAST();
+    funbox->function()->initLazyScript(lazy);
+
+    BINJS_MOZ_TRY_DECL(result, makeEmptyFunctionNode(skipStart, kind, funbox));
+    return result;
 }
 
 
 /*
  interface LazyGetter : Node {
     PropertyName name;
     FrozenArray<Directive> directives;
     GetterContents contents;
@@ -8347,16 +8469,18 @@ BinASTParser<Tok>::parseListOfObjectProp
     AutoList guard(*tokenizer_);
 
     const auto start = tokenizer_->offset();
     MOZ_TRY(tokenizer_->enterList(length, guard));
     BINJS_TRY_DECL(result, factory_.newObjectLiteral(start));
 
     for (uint32_t i = 0; i < length; ++i) {
         BINJS_MOZ_TRY_DECL(item, parseObjectProperty());
+        if (!item->isConstant())
+            result->setHasNonConstInitializer();
         result->appendWithoutOrderAssumption(item);
     }
 
     MOZ_TRY(guard.done());
     return result;
 }
 
 template<typename Tok> JS::Result<ParseNode*>
--- a/js/src/frontend/BinSource.cpp
+++ b/js/src/frontend/BinSource.cpp
@@ -6,16 +6,17 @@
 
 #include "frontend/BinSource.h"
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Casting.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/Move.h"
 #include "mozilla/PodOperations.h"
+#include "mozilla/ScopeExit.h"
 #include "mozilla/Vector.h"
 
 #include "frontend/BinSource-macros.h"
 #include "frontend/BinTokenReaderTester.h"
 #include "frontend/FullParseHandler.h"
 #include "frontend/Parser.h"
 #include "frontend/SharedContext.h"
 
@@ -70,27 +71,31 @@
 //
 // They should be treated lazily (whenever we open a subscope), like bindings.
 
 namespace js {
 namespace frontend {
 
 using UsedNamePtr = UsedNameTracker::UsedNameMap::Ptr;
 
-BinASTParserBase::BinASTParserBase(JSContext* cx, LifoAlloc& alloc, UsedNameTracker& usedNames)
+BinASTParserBase::BinASTParserBase(JSContext* cx, LifoAlloc& alloc, UsedNameTracker& usedNames,
+                                   HandleScriptSourceObject sourceObject, Handle<LazyScript*> lazyScript)
   : AutoGCRooter(cx, AutoGCRooter::Tag::BinParser)
   , cx_(cx)
   , alloc_(alloc)
   , traceListHead_(nullptr)
   , usedNames_(usedNames)
   , nodeAlloc_(cx, alloc)
   , keepAtoms_(cx)
+  , sourceObject_(cx, sourceObject)
+  , lazyScript_(cx, lazyScript)
   , parseContext_(nullptr)
   , factory_(cx, alloc, nullptr, SourceKind::Binary)
 {
+    MOZ_ASSERT_IF(lazyScript, lazyScript->isBinAST());
     cx->frontendCollectionPool().addActiveCompilation();
     tempPoolMark_ = alloc.mark();
 }
 
 BinASTParserBase::~BinASTParserBase()
 {
     alloc_.release(tempPoolMark_);
 
@@ -102,37 +107,40 @@ BinASTParserBase::~BinASTParserBase()
     alloc_.freeAllIfHugeAndUnused();
 
     cx_->frontendCollectionPool().removeActiveCompilation();
 }
 
 // ------------- Toplevel constructions
 
 template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parse(GlobalSharedContext* globalsc, const Vector<uint8_t>& data)
+BinASTParser<Tok>::parse(GlobalSharedContext* globalsc, const Vector<uint8_t>& data,
+                         BinASTSourceMetadata** metadataPtr)
 {
-    return parse(globalsc, data.begin(), data.length());
+    return parse(globalsc, data.begin(), data.length(), metadataPtr);
 }
 
 template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parse(GlobalSharedContext* globalsc, const uint8_t* start, const size_t length)
+BinASTParser<Tok>::parse(GlobalSharedContext* globalsc, const uint8_t* start, const size_t length,
+                         BinASTSourceMetadata** metadataPtr)
 {
-    auto result = parseAux(globalsc, start, length);
+    auto result = parseAux(globalsc, start, length, metadataPtr);
     poison(); // Make sure that the parser is never used again accidentally.
     return result;
 }
 
 
 template<typename Tok> JS::Result<ParseNode*>
 BinASTParser<Tok>::parseAux(GlobalSharedContext* globalsc,
-                            const uint8_t* start, const size_t length)
+                            const uint8_t* start, const size_t length,
+                            BinASTSourceMetadata** metadataPtr)
 {
     MOZ_ASSERT(globalsc);
 
-    tokenizer_.emplace(cx_, start, length);
+    tokenizer_.emplace(cx_, this, start, length);
 
     BinParseContext globalpc(cx_, this, globalsc, /* newDirectives = */ nullptr);
     if (!globalpc.init()) {
         return cx_->alreadyReportedError();
     }
 
     ParseContext::VarScope varScope(cx_, &globalpc, usedNames_);
     if (!varScope.init(&globalpc)) {
@@ -146,68 +154,164 @@ BinASTParser<Tok>::parseAux(GlobalShared
 
     mozilla::Maybe<GlobalScope::Data*> bindings = NewGlobalScopeData(cx_, varScope, alloc_,
                                                                      parseContext_);
     if (!bindings) {
         return cx_->alreadyReportedError();
     }
     globalsc->bindings = *bindings;
 
+    if (metadataPtr) {
+        *metadataPtr = tokenizer_->takeMetadata();
+    }
+
     return result; // Magic conversion to Ok.
 }
 
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseLazyFunction(ScriptSource* scriptSource, const size_t firstOffset)
+{
+    MOZ_ASSERT(lazyScript_);
+    MOZ_ASSERT(scriptSource->length() > firstOffset);
+
+    tokenizer_.emplace(cx_, this, scriptSource->binASTSource(), scriptSource->length());
+
+    MOZ_TRY(tokenizer_->initFromScriptSource(scriptSource));
+
+    tokenizer_->seek(firstOffset);
+
+    // For now, only function declarations and function expression are supported.
+    RootedFunction func(cx_, lazyScript_->functionNonDelazifying());
+    bool isExpr = func->isLambda();
+    MOZ_ASSERT(func->kind() == JSFunction::FunctionKind::NormalFunction);
+
+    // Poison the tokenizer when we leave to ensure that it's not used again by accident.
+    auto onExit = mozilla::MakeScopeExit([&]() { poison(); });
+
+    // TODO: This should be actually shared with the auto-generated version.
+
+    auto syntaxKind = isExpr ? FunctionSyntaxKind::Expression : FunctionSyntaxKind::Statement;
+    BINJS_MOZ_TRY_DECL(funbox, buildFunctionBox(lazyScript_->generatorKind(),
+                                                lazyScript_->asyncKind(), syntaxKind, nullptr));
+
+    // Push a new ParseContext. It will be used to parse `scope`, the arguments, the function.
+    BinParseContext funpc(cx_, this, funbox, /* newDirectives = */ nullptr);
+    BINJS_TRY(funpc.init());
+    parseContext_->functionScope().useAsVarScope(parseContext_);
+    MOZ_ASSERT(parseContext_->isFunctionBox());
+
+    ParseContext::Scope lexicalScope(cx_, parseContext_, usedNames_);
+    BINJS_TRY(lexicalScope.init(parseContext_));
+    ListNode* params;
+    ListNode* tmpBody;
+    auto parseFunc = isExpr ? &BinASTParser::parseFunctionExpressionContents
+                            : &BinASTParser::parseFunctionOrMethodContents;
+    MOZ_TRY((this->*parseFunc)(func->nargs(), &params, &tmpBody));
+
+    BINJS_TRY_DECL(lexicalScopeData, NewLexicalScopeData(cx_, lexicalScope, alloc_, parseContext_));
+    BINJS_TRY_DECL(body, factory_.newLexicalScope(*lexicalScopeData, tmpBody));
+
+    auto binKind = isExpr ? BinKind::LazyFunctionExpression : BinKind::LazyFunctionDeclaration;
+    return buildFunction(firstOffset, binKind, nullptr, params, body, funbox);
+}
+
+template<typename Tok> void
+BinASTParser<Tok>::forceStrictIfNecessary(FunctionBox* funbox, ListNode* directives)
+{
+    JSAtom* useStrict = cx_->names().useStrict;
+
+    for (const ParseNode* directive : directives->contents()) {
+        if (directive->as<NameNode>().atom() == useStrict) {
+            funbox->strictScript = true;
+            break;
+        }
+    }
+}
 
 template<typename Tok> JS::Result<FunctionBox*>
 BinASTParser<Tok>::buildFunctionBox(GeneratorKind generatorKind,
     FunctionAsyncKind functionAsyncKind,
     FunctionSyntaxKind syntax,
     ParseNode* name)
 {
+    MOZ_ASSERT_IF(!parseContext_, lazyScript_);
+
     RootedAtom atom(cx_);
     if (name) {
         atom = name->name();
     }
 
+    if (parseContext_ && syntax == FunctionSyntaxKind::Statement) {
+        auto ptr = parseContext_->varScope().lookupDeclaredName(atom);
+        MOZ_ASSERT(ptr);
+        ptr->value()->alterKind(DeclarationKind::BodyLevelFunction);
+    }
+
     // Allocate the function before walking down the tree.
     RootedFunction fun(cx_);
-    BINJS_TRY_VAR(fun, AllocNewFunction(cx_, atom, syntax, generatorKind, functionAsyncKind, nullptr));
+    BINJS_TRY_VAR(fun, !parseContext_
+        ? lazyScript_->functionNonDelazifying()
+        : AllocNewFunction(cx_, atom, syntax, generatorKind, functionAsyncKind, nullptr));
+    MOZ_ASSERT_IF(parseContext_, fun->explicitName() == atom);
+
+    mozilla::Maybe<Directives> directives;
+    if (parseContext_) {
+        directives.emplace(parseContext_);
+    } else {
+        directives.emplace(lazyScript_->strict());
+    }
 
     auto* funbox = alloc_.new_<FunctionBox>(cx_, traceListHead_, fun, /* toStringStart = */ 0,
-                                            Directives(parseContext_), /* extraWarning = */ false,
+                                            *directives, /* extraWarning = */ false,
                                             generatorKind, functionAsyncKind);
     if (!funbox) {
         return raiseOOM();
     }
 
     traceListHead_ = funbox;
-    funbox->initWithEnclosingParseContext(parseContext_, syntax);
+    if (parseContext_) {
+        funbox->initWithEnclosingParseContext(parseContext_, syntax);
+    } else {
+        funbox->initFromLazyFunction();
+    }
     return funbox;
 }
 
-template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::buildFunction(const size_t start, const BinKind kind, ParseNode* name,
-                                 ListNode* params, ParseNode* body, FunctionBox* funbox)
+template<typename Tok> JS::Result<CodeNode*>
+BinASTParser<Tok>::makeEmptyFunctionNode(const size_t start, const BinKind kind, FunctionBox* funbox)
 {
+    // LazyScript compilation requires basically none of the fields filled out.
     TokenPos pos = tokenizer_->pos(start);
-
-    // Set the argument count for building argument packets. Function.length is handled
-    // by setting the appropriate funbox field during argument parsing.
-    funbox->function()->setArgCount(params ? uint16_t(params->count()) : 0);
-
-    // ParseNode represents the body as concatenated after the params.
-    params->appendWithoutOrderAssumption(body);
-
     bool isStatement = kind == BinKind::EagerFunctionDeclaration ||
                        kind == BinKind::LazyFunctionDeclaration;
 
     BINJS_TRY_DECL(result, isStatement
                      ? factory_.newFunctionStatement(pos)
                      : factory_.newFunctionExpression(pos));
 
     factory_.setFunctionBox(result, funbox);
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::buildFunction(const size_t start, const BinKind kind, ParseNode* name,
+                                 ListNode* params, ParseNode* body, FunctionBox* funbox)
+{
+    // Set the argument count for building argument packets. Function.length is handled
+    // by setting the appropriate funbox field during argument parsing.
+    if (!lazyScript_ || lazyScript_->functionNonDelazifying() != funbox->function()) {
+        funbox->function()->setArgCount(params ? uint16_t(params->count()) : 0);
+    }
+
+    // ParseNode represents the body as concatenated after the params.
+    params->appendWithoutOrderAssumption(body);
+
+    BINJS_MOZ_TRY_DECL(result, makeEmptyFunctionNode(start, kind, funbox));
+
     factory_.setFunctionFormalParametersAndBody(result, params);
 
     HandlePropertyName dotThis = cx_->names().dotThis;
     const bool declareThis = hasUsedName(dotThis) ||
                              funbox->bindingsAccessedDynamically() ||
                              funbox->isDerivedClassConstructor();
 
     if (declareThis) {
@@ -216,16 +320,33 @@ BinASTParser<Tok>::buildFunction(const s
         MOZ_ASSERT(!p);
         BINJS_TRY(funScope.addDeclaredName(parseContext_, p, dotThis, DeclarationKind::Var,
                                      DeclaredNameInfo::npos));
         funbox->setHasThisBinding();
 
         // TODO (efaust): This capture will have to come from encoder side for arrow functions.
     }
 
+    // This models PerHandlerParser::declaeFunctionArgumentsObject, with some subtleties removed,
+    // as they don't yet apply to us.
+    HandlePropertyName arguments = cx_->names().arguments;
+    if (hasUsedName(arguments) || parseContext_->functionBox()->bindingsAccessedDynamically()) {
+        ParseContext::Scope& funScope = parseContext_->functionScope();
+        ParseContext::Scope::AddDeclaredNamePtr p = funScope.lookupDeclaredNameForAdd(arguments);
+        if (!p) {
+            BINJS_TRY(funScope.addDeclaredName(parseContext_, p, arguments, DeclarationKind::Var,
+                                               DeclaredNameInfo::npos));
+            funbox->declaredArguments = true;
+            funbox->usesArguments = true;
+
+            funbox->setArgumentsHasLocalBinding();
+            funbox->setDefinitelyNeedsArgsObj();
+        }
+    }
+
     // Check all our bindings after maybe adding function This.
     MOZ_TRY(checkFunctionClosedVars());
 
     BINJS_TRY_DECL(bindings,
              NewFunctionScopeData(cx_, parseContext_->functionScope(),
                                   /* hasParameterExprs = */ false, alloc_, parseContext_));
 
     funbox->functionScopeBindings().set(*bindings);
@@ -462,16 +583,19 @@ BinASTParser<Tok>::appendDirectivesToBod
         ParseNode* iter = body->head();
         while (iter) {
             ParseNode* next = iter->pn_next;
             prefix->appendWithoutOrderAssumption(iter);
             iter = next;
         }
         prefix->setKind(body->getKind());
         prefix->setOp(body->getOp());
+        if (body->hasTopLevelFunctionDeclarations()) {
+            prefix->setHasTopLevelFunctionDeclarations();
+        }
         result = prefix;
     }
 
     return result;
 }
 
 template<typename Tok> mozilla::GenericErrorResult<JS::Error&>
 BinASTParser<Tok>::raiseInvalidClosedVar(JSAtom* name)
@@ -613,16 +737,23 @@ BinASTParserBase::hasUsedName(HandleProp
 }
 
 void
 TraceBinParser(JSTracer* trc, JS::AutoGCRooter* parser)
 {
     static_cast<BinASTParserBase*>(parser)->trace(trc);
 }
 
+template<typename Tok>
+void
+BinASTParser<Tok>::doTrace(JSTracer* trc)
+{
+    if (tokenizer_)
+        tokenizer_->traceMetadata(trc);
+}
 
 // Force class instantiation.
 // This ensures that the symbols are built, without having to export all our
 // code (and its baggage of #include and macros) in the header.
 template class BinASTParser<BinTokenReaderMultipart>;
 template class BinASTParser<BinTokenReaderTester>;
 
 } // namespace frontend
--- a/js/src/frontend/BinSource.h
+++ b/js/src/frontend/BinSource.h
@@ -31,29 +31,33 @@
 #include "js/Result.h"
 
 namespace js {
 namespace frontend {
 
 class BinASTParserBase: private JS::AutoGCRooter
 {
   public:
-    BinASTParserBase(JSContext* cx, LifoAlloc& alloc, UsedNameTracker& usedNames);
+    BinASTParserBase(JSContext* cx, LifoAlloc& alloc, UsedNameTracker& usedNames,
+                     HandleScriptSourceObject sourceObject, Handle<LazyScript*> lazyScript);
     ~BinASTParserBase();
 
   public:
     // Names
 
 
     bool hasUsedName(HandlePropertyName name);
 
     // --- GC.
 
+    virtual void doTrace(JSTracer* trc) {}
+
     void trace(JSTracer* trc) {
         ObjectBox::TraceList(trc, traceListHead_);
+        doTrace(trc);
     }
 
 
   public:
     ParseNode* allocParseNode(size_t size) {
         MOZ_ASSERT(size == sizeof(ParseNode));
         return static_cast<ParseNode*>(nodeAlloc_.allocNode());
     }
@@ -75,16 +79,18 @@ class BinASTParserBase: private JS::Auto
     LifoAlloc::Mark tempPoolMark_;
     ParseNodeAllocator nodeAlloc_;
 
     // ---- Parsing-related stuff
   protected:
     // Root atoms and objects allocated for the parse tree.
     AutoKeepAtoms keepAtoms_;
 
+    RootedScriptSourceObject sourceObject_;
+    Rooted<LazyScript*> lazyScript_;
     ParseContext* parseContext_;
     FullParseHandler factory_;
 
     friend class BinParseContext;
 };
 
 /**
  * The parser for a Binary AST.
@@ -100,18 +106,19 @@ class BinASTParser : public BinASTParser
 
     using AutoList = typename Tokenizer::AutoList;
     using AutoTaggedTuple = typename Tokenizer::AutoTaggedTuple;
     using AutoTuple = typename Tokenizer::AutoTuple;
     using BinFields = typename Tokenizer::BinFields;
     using Chars = typename Tokenizer::Chars;
 
   public:
-    BinASTParser(JSContext* cx, LifoAlloc& alloc, UsedNameTracker& usedNames, const JS::ReadOnlyCompileOptions& options)
-        : BinASTParserBase(cx, alloc, usedNames)
+    BinASTParser(JSContext* cx, LifoAlloc& alloc, UsedNameTracker& usedNames, const JS::ReadOnlyCompileOptions& options,
+                 HandleScriptSourceObject sourceObject, Handle<LazyScript*> lazyScript = nullptr)
+        : BinASTParserBase(cx, alloc, usedNames, sourceObject, lazyScript)
         , options_(options)
         , variableDeclarationKind_(VariableDeclarationKind::Var)
     {
     }
     ~BinASTParser()
     {
     }
 
@@ -120,22 +127,27 @@ class BinASTParser : public BinASTParser
      * or Nothing() in case of error.
      *
      * The instance of `ParseNode` MAY NOT survive the `BinASTParser`. Indeed,
      * destruction of the `BinASTParser` will also destroy the `ParseNode`.
      *
      * In case of error, the parser reports the JS error.
      */
     JS::Result<ParseNode*> parse(GlobalSharedContext* globalsc,
-                                 const uint8_t* start, const size_t length);
-    JS::Result<ParseNode*> parse(GlobalSharedContext* globalsc, const Vector<uint8_t>& data);
+                                 const uint8_t* start, const size_t length,
+                                 BinASTSourceMetadata** metadataPtr = nullptr);
+    JS::Result<ParseNode*> parse(GlobalSharedContext* globalsc, const Vector<uint8_t>& data,
+                                 BinASTSourceMetadata** metadataPtr = nullptr);
+
+    JS::Result<ParseNode*> parseLazyFunction(ScriptSource* src, const size_t firstOffset);
 
   private:
     MOZ_MUST_USE JS::Result<ParseNode*> parseAux(GlobalSharedContext* globalsc,
-                                                 const uint8_t* start, const size_t length);
+                                                 const uint8_t* start, const size_t length,
+                                                 BinASTSourceMetadata** metadataPtr = nullptr);
 
     // --- Raise errors.
     //
     // These methods return a (failed) JS::Result for convenience.
 
     MOZ_MUST_USE mozilla::GenericErrorResult<JS::Error&> raiseInvalidClosedVar(JSAtom* name);
     MOZ_MUST_USE mozilla::GenericErrorResult<JS::Error&> raiseMissingVariableInAssertedScope(JSAtom* name);
     MOZ_MUST_USE mozilla::GenericErrorResult<JS::Error&> raiseMissingDirectEvalInAssertedScope();
@@ -165,19 +177,21 @@ class BinASTParser : public BinASTParser
     };
 
     // Auto-generated methods
 #include "frontend/BinSource-auto.h"
 
     // --- Auxiliary parsing functions
 
     // Build a function object for a function-producing production. Called AFTER creating the scope.
+    JS::Result<CodeNode*>
+    makeEmptyFunctionNode(const size_t start, const BinKind kind, FunctionBox* funbox);
     JS::Result<ParseNode*>
     buildFunction(const size_t start, const BinKind kind, ParseNode* name, ListNode* params,
-        ParseNode* body, FunctionBox* funbox);
+                  ParseNode* body, FunctionBox* funbox);
     JS::Result<FunctionBox*>
     buildFunctionBox(GeneratorKind generatorKind, FunctionAsyncKind functionAsyncKind, FunctionSyntaxKind syntax, ParseNode* name);
 
     // Add name to a given scope.
     MOZ_MUST_USE JS::Result<Ok> addScopeName(AssertedScopeKind scopeKind, HandleAtom name,
                                              ParseContext::Scope* scope,
                                              DeclarationKind declKind,
                                              bool isCaptured);
@@ -208,23 +222,29 @@ class BinASTParser : public BinASTParser
     // As a convenience, a helper that checks the body, parameter, and recursive binding scopes.
     MOZ_MUST_USE JS::Result<Ok> checkFunctionClosedVars();
 
     // --- Utilities.
 
     MOZ_MUST_USE JS::Result<ParseNode*> appendDirectivesToBody(ListNode* body,
         ListNode* directives);
 
+    // Optionally force a strict context without restarting the parse when we see a strict
+    // directive.
+    void forceStrictIfNecessary(FunctionBox* funbox, ListNode* directives);
+
   private: // Implement ErrorReporter
     const JS::ReadOnlyCompileOptions& options_;
 
     const JS::ReadOnlyCompileOptions& options() const override {
         return this->options_;
     }
 
+    void doTrace(JSTracer* trc) final;
+
   public:
     virtual ObjectBox* newObjectBox(JSObject* obj) override {
         MOZ_ASSERT(obj);
 
         /*
          * We use JSContext.tempLifoAlloc to allocate parsed objects and place them
          * on a list in this Parser to ensure GC safety. Thus the tempLifoAlloc
          * arenas containing the entries must be alive until we are done with
--- a/js/src/frontend/BinSource.yaml
+++ b/js/src/frontend/BinSource.yaml
@@ -207,17 +207,20 @@ hpp:
 
 Arguments:
     init:
         BINJS_TRY_DECL(result, factory_.newList(ParseNodeKind::Arguments, tokenizer_->pos(start)));
     append:
         factory_.addList(/* list = */ result, /* kid = */ item);
 
 ArrayExpression:
-    build:
+    build: |
+        if (elements->empty()) {
+            elements->setHasNonConstInitializer();
+        }
         auto result = elements;
 
 AssertedBlockScope:
     type-ok:
         Ok
     init: |
         const auto scopeKind = AssertedScopeKind::Block;
     fields:
@@ -474,16 +477,28 @@ BreakStatement:
                 }
             }
         }
         BINJS_TRY_DECL(result, factory_.newBreakStatement(label ? label->asPropertyName() : nullptr, tokenizer_->pos(start)));
 
 CallExpression:
     build: |
         auto op = JSOP_CALL;
+
+        // Try to optimize funcall and funapply at the bytecode level
+        if (PropertyName* prop = factory_.maybeDottedProperty(callee)) {
+            if (prop == cx_->names().apply) {
+                op = JSOP_FUNAPPLY;
+                if (parseContext_->isFunctionBox())
+                    parseContext_->functionBox()->usesApply = true;
+            } else if (prop == cx_->names().call) {
+                op = JSOP_FUNCALL;
+            }
+        }
+
         // Check for direct calls to `eval`.
         if (factory_.isEvalName(callee, cx_)) {
             if (!parseContext_->varScope().lookupDeclaredNameForAdd(callee->name())
              && !parseContext_->innermostScope()->lookupDeclaredNameForAdd(callee->name())) {
                 // This is a direct call to `eval`.
                 if (!parseContext_->sc()->hasDirectEval()) {
                     return raiseMissingDirectEvalInAssertedScope();
                 }
@@ -499,16 +514,17 @@ CallExpression:
 CatchClause:
     type-ok:
         LexicalScopeNode*
     init: |
         ParseContext::Statement stmt(parseContext_, StatementKind::Catch);
         ParseContext::Scope currentScope(cx_, parseContext_, usedNames_);
         BINJS_TRY(currentScope.init(parseContext_));
     build: |
+        MOZ_TRY(checkClosedVars(currentScope));
         BINJS_TRY_DECL(bindings, NewLexicalScopeData(cx_, currentScope, alloc_, parseContext_));
         BINJS_TRY_DECL(result, factory_.newLexicalScope(*bindings, body));
         BINJS_TRY(factory_.setupCatchScope(result, binding, body));
 
 CompoundAssignmentExpression:
     build: |
         ParseNodeKind pnk;
         switch (operator_){
@@ -609,16 +625,21 @@ DoWhileStatement:
     build:
         BINJS_TRY_DECL(result, factory_.newDoWhileStatement(body, test, tokenizer_->pos(start)));
 
 EagerFunctionDeclaration:
     init: |
         const auto syntax = FunctionSyntaxKind::Statement;
     inherits: EagerFunctionExpression
 
+LazyFunctionDeclaration:
+    init: |
+        const auto syntax = FunctionSyntaxKind::Statement;
+    inherits: LazyFunctionExpression
+
 FunctionExpressionContents:
     type-ok:
         Ok
     extra-params: |
         uint32_t funLength,
         ListNode** paramsOut,
         ListNode** bodyOut
     extra-args: |
@@ -681,16 +702,18 @@ EagerFunctionExpression:
                     isGenerator ? GeneratorKind::Generator
                                 : GeneratorKind::NotGenerator,
                     isAsync ? FunctionAsyncKind::AsyncFunction
                             : FunctionAsyncKind::SyncFunction,
                     syntax,
                     (syntax != FunctionSyntaxKind::Setter &&
                      syntax != FunctionSyntaxKind::Getter) ? name : nullptr));
 
+                forceStrictIfNecessary(funbox, directives);
+
                 // Push a new ParseContext. It will be used to parse `scope`, the arguments, the function.
                 BinParseContext funpc(cx_, this, funbox, /* newDirectives = */ nullptr);
                 BINJS_TRY(funpc.init());
                 parseContext_->functionScope().useAsVarScope(parseContext_);
                 MOZ_ASSERT(parseContext_->isFunctionBox());
 
                 ParseContext::Scope lexicalScope(cx_, parseContext_, usedNames_);
                 BINJS_TRY(lexicalScope.init(parseContext_));
@@ -700,16 +723,52 @@ EagerFunctionExpression:
                 length, &params, &tmpBody
             after: |
                 BINJS_MOZ_TRY_DECL(body, appendDirectivesToBody(tmpBody, directives));
     build: |
         BINJS_TRY_DECL(lexicalScopeData, NewLexicalScopeData(cx_, lexicalScope, alloc_, parseContext_));
         BINJS_TRY_VAR(body, factory_.newLexicalScope(*lexicalScopeData, body));
         BINJS_MOZ_TRY_DECL(result, buildFunction(start, kind, name, params, body, funbox));
 
+LazyFunctionExpression:
+    init: |
+        const auto syntax = FunctionSyntaxKind::Expression;
+    fields:
+        contents:
+            block:
+                replace:
+                    // Don't parse the contents until we delazify.
+    build: |
+        BINJS_MOZ_TRY_DECL(funbox, buildFunctionBox(
+            isGenerator ? GeneratorKind::Generator
+                        : GeneratorKind::NotGenerator,
+            isAsync ? FunctionAsyncKind::AsyncFunction
+                    : FunctionAsyncKind::SyncFunction,
+            syntax, name));
+
+        forceStrictIfNecessary(funbox, directives);
+
+        RootedFunction fun(cx_, funbox->function());
+
+        // TODO: This will become incorrect in the face of ES6 features.
+        fun->setArgCount(length);
+
+        auto skipStart = contentsSkip.startOffset();
+        BINJS_TRY_DECL(lazy, LazyScript::Create(cx_, fun, sourceObject_, parseContext_->closedOverBindingsForLazy(), parseContext_->innerFunctionsForLazy,
+                                                skipStart, skipStart + contentsSkip.length(),
+                                                skipStart, 0, skipStart, ParseGoal::Script));
+
+        if (funbox->strict()) {
+            lazy->setStrict();
+        }
+        lazy->setIsBinAST();
+        funbox->function()->initLazyScript(lazy);
+
+        BINJS_MOZ_TRY_DECL(result, makeEmptyFunctionNode(skipStart, kind, funbox));
+
 EagerGetter:
     init: |
         const auto syntax = FunctionSyntaxKind::Setter;
         const bool isGenerator = false;
         const bool isAsync = false;
         const auto accessorType = AccessorType::Getter;
         const uint32_t length = 0;
     inherits: EagerMethod
@@ -866,16 +925,20 @@ ListOfDirective:
     append:
         factory_.addStatementToList(result, item);
 
 ListOfObjectProperty:
     type-ok:
         ListNode*
     init:
         BINJS_TRY_DECL(result, factory_.newObjectLiteral(start));
+    append: |
+        if (!item->isConstant())
+            result->setHasNonConstInitializer();
+        result->appendWithoutOrderAssumption(item);
 
 ListOfOptionalSpreadElementOrExpression:
     type-ok:
         ListNode*
     init:
         BINJS_TRY_DECL(result, factory_.newArrayLiteral(start));
     append: |
         if (item) {
new file mode 100644
--- /dev/null
+++ b/js/src/frontend/BinSourceRuntimeSupport.cpp
@@ -0,0 +1,44 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * 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 "frontend/BinSourceRuntimeSupport.h"
+
+#include "gc/Tracer.h"
+#include "js/Vector.h"
+#include "vm/StringType.h"
+
+namespace js {
+namespace frontend {
+
+/* static */ BinASTSourceMetadata*
+BinASTSourceMetadata::Create(const Vector<BinKind>& binKinds, uint32_t numStrings)
+{
+    uint32_t numBinKinds = binKinds.length();
+
+    BinASTSourceMetadata* data = static_cast<BinASTSourceMetadata*>(js_malloc(BinASTSourceMetadata::totalSize(numBinKinds, numStrings)));
+    if (!data) {
+        return nullptr;
+    }
+
+    new (data) BinASTSourceMetadata(numBinKinds, numStrings);
+    memcpy(data->binKindBase(), binKinds.begin(), binKinds.length() * sizeof(BinKind));
+
+    return data;
+}
+
+void
+BinASTSourceMetadata::trace(JSTracer* tracer)
+{
+    JSAtom** base = atomsBase();
+    for (uint32_t i = 0; i < numStrings_; i++) {
+        if (base[i]) {
+            TraceManuallyBarrieredEdge(tracer, &base[i], "BinAST Strings");
+        }
+    }
+}
+
+} // namespace frontend
+} // namespace js
--- a/js/src/frontend/BinSourceRuntimeSupport.h
+++ b/js/src/frontend/BinSourceRuntimeSupport.h
@@ -5,23 +5,28 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef frontend_BinSourceSupport_h
 #define frontend_BinSourceSupport_h
 
 #include "mozilla/HashFunctions.h"
 
 #include "frontend/BinToken.h"
+#include "gc/DeletePolicy.h"
 
 #include "js/AllocPolicy.h"
 #include "js/HashTable.h"
 #include "js/Result.h"
+#include "js/UniquePtr.h"
+#include "js/Vector.h"
 
 namespace js {
 
+class ScriptSource;
+
 // Support for parsing JS Binary ASTs.
 struct BinaryASTSupport {
     using BinVariant = js::frontend::BinVariant;
     using BinField = js::frontend::BinField;
     using BinKind = js::frontend::BinKind;
 
     // A structure designed to perform fast char* + length lookup
     // without copies.
@@ -31,16 +36,19 @@ struct BinaryASTSupport {
         CharSlice(const CharSlice& other)
             : start_(other.start_)
             , byteLen_(other.byteLen_)
         {  }
         CharSlice(const char* start, const uint32_t byteLen)
             : start_(start)
             , byteLen_(byteLen)
         { }
+        explicit CharSlice(JSContext*)
+          : CharSlice(nullptr, 0)
+        { }
         const char* begin() const {
             return start_;
         }
         const char* end() const {
             return start_ + byteLen_;
         }
 #ifdef DEBUG
         void dump() const {
@@ -62,28 +70,100 @@ struct BinaryASTSupport {
             }
             return strncmp(key.start_, lookup.start_, key.byteLen_) == 0;
         }
     };
 
     BinaryASTSupport();
 
     JS::Result<const BinVariant*>  binVariant(JSContext*, const CharSlice);
-    JS::Result<const BinField*> binField(JSContext*, const CharSlice);
     JS::Result<const BinKind*> binKind(JSContext*,  const CharSlice);
 
+    bool ensureBinTablesInitialized(JSContext*);
+
+  private:
+    bool ensureBinKindsInitialized(JSContext*);
+    bool ensureBinVariantsInitialized(JSContext*);
+
   private:
     // A HashMap that can be queried without copies from a CharSlice key.
     // Initialized on first call. Keys are CharSlices into static strings.
     using BinKindMap = js::HashMap<const CharSlice, BinKind, CharSlice, js::SystemAllocPolicy>;
     BinKindMap binKindMap_;
 
     using BinFieldMap = js::HashMap<const CharSlice, BinField, CharSlice, js::SystemAllocPolicy>;
     BinFieldMap binFieldMap_;
 
     using BinVariantMap = js::HashMap<const CharSlice, BinVariant, CharSlice, js::SystemAllocPolicy>;
     BinVariantMap binVariantMap_;
 
 };
 
+namespace frontend {
+
+class BinASTSourceMetadata
+{
+    using CharSlice = BinaryASTSupport::CharSlice;
+
+    const uint32_t numStrings_;
+    const uint32_t numBinKinds_;
+
+    // The data lives inline in the allocation, after this class.
+    inline JSAtom** atomsBase() {
+        return reinterpret_cast<JSAtom**>(reinterpret_cast<uintptr_t>(this + 1));
+    }
+    inline CharSlice* sliceBase() {
+        return reinterpret_cast<CharSlice*>(reinterpret_cast<uintptr_t>(atomsBase()) + numStrings_ * sizeof(JSAtom*));
+    }
+    inline BinKind* binKindBase() {
+        return reinterpret_cast<BinKind*>(reinterpret_cast<uintptr_t>(sliceBase()) + numStrings_ * sizeof(CharSlice));
+    }
+
+    static inline size_t totalSize(uint32_t numBinKinds, uint32_t numStrings) {
+        return sizeof(BinASTSourceMetadata) +
+               numStrings * sizeof(JSAtom*) +
+               numStrings * sizeof(CharSlice) +
+               numBinKinds * sizeof(BinKind);
+    }
+
+    BinASTSourceMetadata(uint32_t numBinKinds, uint32_t numStrings)
+      : numStrings_(numStrings),
+        numBinKinds_(numBinKinds)
+    { }
+
+    friend class js::ScriptSource;
+
+  public:
+    static BinASTSourceMetadata* Create(const Vector<BinKind>& binKinds, uint32_t numStrings);
+
+    inline uint32_t numBinKinds() {
+        return numBinKinds_;
+    }
+
+    inline uint32_t numStrings() {
+        return numStrings_;
+    }
+
+    inline BinKind& getBinKind(uint32_t index) {
+        MOZ_ASSERT(index < numBinKinds_);
+        return binKindBase()[index];
+    }
+
+    inline CharSlice& getSlice(uint32_t index) {
+        MOZ_ASSERT(index < numStrings_);
+        return sliceBase()[index];
+    }
+
+    inline JSAtom*& getAtom(uint32_t index) {
+        MOZ_ASSERT(index < numStrings_);
+        return atomsBase()[index];
+    }
+
+    void trace(JSTracer* tracer);
+};
+
+}
+
+typedef UniquePtr<frontend::BinASTSourceMetadata, GCManagedDeletePolicy<frontend::BinASTSourceMetadata>> UniqueBinASTSourceMetadataPtr;
+
 } // namespace js
 
 #endif // frontend_BinSourceSupport_h
--- a/js/src/frontend/BinToken.cpp
+++ b/js/src/frontend/BinToken.cpp
@@ -8,17 +8,17 @@
 
 #include "mozilla/Maybe.h"
 
 #include <sys/types.h>
 
 #include "frontend/BinSourceRuntimeSupport.h"
 #include "frontend/TokenStream.h"
 #include "js/Result.h"
-#include "vm/Runtime.h"
+#include "vm/JSContext.h"
 
 namespace js {
 namespace frontend {
 
 const BinaryASTSupport::CharSlice BINKIND_DESCRIPTIONS[] = {
 #define WITH_VARIANT(_, SPEC_NAME) BinaryASTSupport::CharSlice(SPEC_NAME, sizeof(SPEC_NAME) - 1),
     FOR_EACH_BIN_KIND(WITH_VARIANT)
 #undef WITH_VARIANT
@@ -73,56 +73,98 @@ const char* describeBinVariant(const Bin
 
 BinaryASTSupport::BinaryASTSupport()
   : binKindMap_(frontend::BINKIND_LIMIT)
   , binFieldMap_(frontend::BINFIELD_LIMIT)
   , binVariantMap_(frontend::BINVARIANT_LIMIT)
 {
 }
 
-JS::Result<const js::frontend::BinKind*>
-BinaryASTSupport::binKind(JSContext* cx, const CharSlice key)
+/**
+ * It is expected that all bin tables are initialized on the main thread, and that
+ * any helper threads will find the read-only tables properly initialized, so that
+ * they can do their accesses safely without taking any locks.
+ */
+bool
+BinaryASTSupport::ensureBinTablesInitialized(JSContext* cx)
 {
+    return ensureBinKindsInitialized(cx) && ensureBinVariantsInitialized(cx);
+}
+
+bool
+BinaryASTSupport::ensureBinKindsInitialized(JSContext* cx)
+{
+    MOZ_ASSERT(!cx->helperThread());
     if (binKindMap_.empty()) {
         for (size_t i = 0; i < frontend::BINKIND_LIMIT; ++i) {
             const BinKind variant = static_cast<BinKind>(i);
             const CharSlice& key = getBinKind(variant);
             auto ptr = binKindMap_.lookupForAdd(key);
             MOZ_ASSERT(!ptr);
             if (!binKindMap_.add(ptr, key, variant)) {
-                return ReportOutOfMemoryResult(cx);
+                ReportOutOfMemory(cx);
+                return false;
             }
         }
     }
 
-    auto ptr = binKindMap_.lookup(key);
+    return true;
+}
+
+bool
+BinaryASTSupport::ensureBinVariantsInitialized(JSContext* cx)
+{
+    MOZ_ASSERT(!cx->helperThread());
+    if (binVariantMap_.empty()) {
+        for (size_t i = 0; i < frontend::BINVARIANT_LIMIT; ++i) {
+            const BinVariant variant = static_cast<BinVariant>(i);
+            const CharSlice& key = getBinVariant(variant);
+            auto ptr = binVariantMap_.lookupForAdd(key);
+            MOZ_ASSERT(!ptr);
+            if (!binVariantMap_.add(ptr, key, variant)) {
+                ReportOutOfMemory(cx);
+                return false;
+            }
+        }
+    }
+    return true;
+}
+
+
+JS::Result<const js::frontend::BinKind*>
+BinaryASTSupport::binKind(JSContext* cx, const CharSlice key)
+{
+    MOZ_ASSERT_IF(cx->helperThread(), !binKindMap_.empty());
+    if (!cx->helperThread()) {
+        // Initialize Lazily if on main thread.
+        if (!ensureBinKindsInitialized(cx)) {
+            return cx->alreadyReportedError();
+        }
+    }
+
+    auto ptr = binKindMap_.readonlyThreadsafeLookup(key);
     if (!ptr) {
         return nullptr;
     }
 
     return &ptr->value();
 }
 
 JS::Result<const js::frontend::BinVariant*>
 BinaryASTSupport::binVariant(JSContext* cx, const CharSlice key)
 {
-    if (binVariantMap_.empty()) {
-        for (size_t i = 0; i < frontend::BINVARIANT_LIMIT; ++i) {
-            const BinVariant variant = static_cast<BinVariant>(i);
-            const CharSlice& key = getBinVariant(variant);
-            auto ptr = binVariantMap_.lookupForAdd(key);
-            MOZ_ASSERT(!ptr);
-            if (!binVariantMap_.add(ptr, key, variant)) {
-                return ReportOutOfMemoryResult(cx);
-            }
+    MOZ_ASSERT_IF(cx->helperThread(), !binVariantMap_.empty());
+    if (!cx->helperThread()) {
+        // Initialize lazily if on main thread.
+        if (!ensureBinVariantsInitialized(cx)) {
+            return cx->alreadyReportedError();
         }
     }
 
-
-    auto ptr = binVariantMap_.lookup(key);
+    auto ptr = binVariantMap_.readonlyThreadsafeLookup(key);
     if (!ptr) {
         return nullptr;
     }
 
     return &ptr->value();
 }
 
 } // namespace js
--- a/js/src/frontend/BinTokenReaderBase.cpp
+++ b/js/src/frontend/BinTokenReaderBase.cpp
@@ -26,19 +26,24 @@ BinTokenReaderBase::updateLatestKnownGoo
     MOZ_ASSERT(update >= latestKnownGoodPos_);
     latestKnownGoodPos_ = update;
 }
 
 ErrorResult<JS::Error&>
 BinTokenReaderBase::raiseError(const char* description)
 {
     MOZ_ASSERT(!cx_->isExceptionPending());
-    TokenPos pos = this->pos();
-    JS_ReportErrorASCII(cx_, "BinAST parsing error: %s at offsets %u => %u",
-                        description, pos.begin, pos.end);
+    if (MOZ_LIKELY(errorReporter_)) {
+        errorReporter_->reportErrorNoOffset(JSMSG_BINAST, description);
+    } else {
+        // Only true in testing code.
+        TokenPos pos = this->pos();
+        JS_ReportErrorASCII(cx_, "BinAST parsing error: %s at offsets %u => %u",
+                            description, pos.begin, pos.end);
+    }
     return cx_->alreadyReportedError();
 }
 
 ErrorResult<JS::Error&>
 BinTokenReaderBase::raiseOOM()
 {
     ReportOutOfMemory(cx_);
     return cx_->alreadyReportedError();
@@ -88,16 +93,24 @@ BinTokenReaderBase::pos(size_t start)
 {
     TokenPos pos;
     pos.begin = start;
     pos.end = current_ - start_;
     MOZ_ASSERT(pos.end >= pos.begin);
     return pos;
 }
 
+void
+BinTokenReaderBase::seek(size_t offset)
+{
+    MOZ_ASSERT(start_ + offset >= start_ &&
+               start_ + offset < stop_);
+    current_ = start_ + offset;
+}
+
 JS::Result<Ok>
 BinTokenReaderBase::readBuf(uint8_t* bytes, uint32_t len)
 {
     MOZ_ASSERT(!cx_->isExceptionPending());
     MOZ_ASSERT(len > 0);
 
     if (stop_ < current_ + len) {
         return raiseError("Buffer exceeds length");
--- a/js/src/frontend/BinTokenReaderBase.h
+++ b/js/src/frontend/BinTokenReaderBase.h
@@ -3,16 +3,17 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef frontend_BinTokenReaderBase_h
 #define frontend_BinTokenReaderBase_h
 
 #include "frontend/BinToken.h"
+#include "frontend/ErrorReporter.h"
 #include "frontend/TokenStream.h"
 
 #include "js/Result.h"
 #include "js/TypeDecls.h"
 
 namespace js {
 namespace frontend {
 
@@ -22,44 +23,47 @@ extern const uint64_t NULL_FLOAT_REPRESE
 class MOZ_STACK_CLASS BinTokenReaderBase
 {
   public:
     template<typename T> using ErrorResult = mozilla::GenericErrorResult<T>;
 
     // The information needed to skip a subtree.
     class SkippableSubTree {
       public:
-        SkippableSubTree(const uint8_t* start, const size_t length)
-          : start_(start)
+        SkippableSubTree(const size_t startOffset, const size_t length)
+          : startOffset_(startOffset)
           , length_(length)
         { }
 
         // The position in the source buffer at which the subtree starts.
         //
         // `SkippableSubTree` does *not* attempt to keep anything alive.
-        const uint8_t* start() const {
-            return start_;
+        size_t startOffset() const {
+            return startOffset_;
         }
 
         // The length of the subtree.
         size_t length() const {
             return length_;
         }
       private:
-        const uint8_t* start_;
+        const size_t startOffset_;
         const size_t length_;
     };
 
     /**
      * Return the position of the latest token.
      */
     TokenPos pos();
     TokenPos pos(size_t startOffset);
     size_t offset() const;
 
+    // Set the tokenizer's cursor in the file. Use with caution.
+    void seek(size_t offset);
+
      /**
       * Poison this tokenizer.
       */
     void poison();
 
     /**
      * Raise an error.
      *
@@ -68,18 +72,19 @@ class MOZ_STACK_CLASS BinTokenReaderBase
     MOZ_MUST_USE ErrorResult<JS::Error&> raiseError(const char* description);
     MOZ_MUST_USE ErrorResult<JS::Error&> raiseOOM();
     MOZ_MUST_USE ErrorResult<JS::Error&> raiseInvalidNumberOfFields(
         const BinKind kind, const uint32_t expected, const uint32_t got);
     MOZ_MUST_USE ErrorResult<JS::Error&> raiseInvalidField(const char* kind,
         const BinField field);
 
   protected:
-    BinTokenReaderBase(JSContext* cx, const uint8_t* start, const size_t length)
+    BinTokenReaderBase(JSContext* cx, ErrorReporter* er, const uint8_t* start, const size_t length)
         : cx_(cx)
+        , errorReporter_(er)
         , poisoned_(false)
         , start_(start)
         , current_(start)
         , stop_(start + length)
         , latestKnownGoodPos_(0)
     { }
 
     /**
@@ -147,16 +152,18 @@ class MOZ_STACK_CLASS BinTokenReaderBase
     void updateLatestKnownGood();
 
 #ifdef DEBUG
     bool hasRaisedError() const;
 #endif
 
     JSContext* cx_;
 
+    ErrorReporter* errorReporter_;
+
     // `true` if we have encountered an error. Errors are non recoverable.
     // Attempting to read from a poisoned tokenizer will cause assertion errors.
     bool poisoned_;
 
     // The first byte of the buffer. Not owned.
     const uint8_t* start_;
 
     // The current position.
--- a/js/src/frontend/BinTokenReaderMultipart.cpp
+++ b/js/src/frontend/BinTokenReaderMultipart.cpp
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "frontend/BinTokenReaderMultipart.h"
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Casting.h"
 #include "mozilla/EndianUtils.h"
 #include "mozilla/Maybe.h"
+#include "mozilla/ScopeExit.h"
 
 #include <utility>
 
 #include "frontend/BinSource-macros.h"
 #include "frontend/BinSourceRuntimeSupport.h"
 
 #include "js/Result.h"
 
@@ -40,23 +41,47 @@ const char COMPRESSION_IDENTITY[] = "ide
 const uint32_t MAX_NUMBER_OF_STRINGS = 32768;
 
 using AutoList = BinTokenReaderMultipart::AutoList;
 using AutoTaggedTuple = BinTokenReaderMultipart::AutoTaggedTuple;
 using AutoTuple = BinTokenReaderMultipart::AutoTuple;
 using CharSlice = BinaryASTSupport::CharSlice;
 using Chars = BinTokenReaderMultipart::Chars;
 
-BinTokenReaderMultipart::BinTokenReaderMultipart(JSContext* cx, const uint8_t* start, const size_t length)
-  : BinTokenReaderBase(cx, start, length)
-  , grammarTable_(cx)
-  , atomsTable_(cx, AtomVector(cx))
-  , slicesTable_(cx)
+BinTokenReaderMultipart::BinTokenReaderMultipart(JSContext* cx, ErrorReporter* er, const uint8_t* start, const size_t length)
+  : BinTokenReaderBase(cx, er, start, length)
+  , metadata_(nullptr)
   , posBeforeTree_(nullptr)
-{ }
+{
+    MOZ_ASSERT(er);
+}
+
+BinTokenReaderMultipart::~BinTokenReaderMultipart()
+{
+    if (metadata_ && metadataOwned_ == MetadataOwnership::Owned) {
+        UniqueBinASTSourceMetadataPtr ptr(metadata_);
+    }
+}
+
+BinASTSourceMetadata*
+BinTokenReaderMultipart::takeMetadata()
+{
+    MOZ_ASSERT(metadataOwned_ == MetadataOwnership::Owned);
+    metadataOwned_ = MetadataOwnership::Unowned;
+    return metadata_;
+}
+
+JS::Result<Ok>
+BinTokenReaderMultipart::initFromScriptSource(ScriptSource* scriptSource)
+{
+    metadata_ = scriptSource->binASTSourceMetadata();
+    metadataOwned_ = MetadataOwnership::Unowned;
+
+    return Ok();
+}
 
 JS::Result<Ok>
 BinTokenReaderMultipart::readHeader()
 {
     // Check that we don't call this function twice.
     MOZ_ASSERT(!posBeforeTree_);
 
     // Read global headers.
@@ -82,16 +107,17 @@ BinTokenReaderMultipart::readHeader()
 
     BINJS_MOZ_TRY_DECL(grammarNumberOfEntries, readInternalUint32());
     if (grammarNumberOfEntries > BINKIND_LIMIT) { // Sanity check.
         return raiseError("Invalid number of entries in grammar table");
     }
 
     // This table maps BinKind index -> BinKind.
     // Initialize and populate.
+    Vector<BinKind> grammarTable_(cx_);
     if (!grammarTable_.reserve(grammarNumberOfEntries)) {
         return raiseOOM();
     }
 
     for (uint32_t i = 0; i < grammarNumberOfEntries; ++i) {
         BINJS_MOZ_TRY_DECL(byteLen, readInternalUint32());
         if (current_ + byteLen > stop_) {
             return raiseError("Invalid byte length in grammar table");
@@ -123,68 +149,79 @@ BinTokenReaderMultipart::readHeader()
         return raiseError("Invalid byte length in strings table");
     }
 
     BINJS_MOZ_TRY_DECL(stringsNumberOfEntries, readInternalUint32());
     if (stringsNumberOfEntries > MAX_NUMBER_OF_STRINGS) { // Sanity check.
         return raiseError("Too many entries in strings table");
     }
 
-    // This table maps String index -> String.
-    // Initialize and populate.
-    if (!atomsTable_.reserve(stringsNumberOfEntries)) {
+    BinASTSourceMetadata* metadata = BinASTSourceMetadata::Create(grammarTable_, stringsNumberOfEntries);
+    if (!metadata) {
         return raiseOOM();
     }
-    if (!slicesTable_.reserve(stringsNumberOfEntries)) {
-        return raiseOOM();
-    }
+
+    // Free it if we don't make it out of here alive. Since we don't want to calloc(), we
+    // need to avoid marking atoms that might not be there.
+    auto se = mozilla::MakeScopeExit([metadata](){ js_free(metadata); });
 
     RootedAtom atom(cx_);
     for (uint32_t i = 0; i < stringsNumberOfEntries; ++i) {
         BINJS_MOZ_TRY_DECL(byteLen, readInternalUint32());
         if (current_ + byteLen > stop_ || current_ + byteLen < current_) {
             return raiseError("Invalid byte length in individual string");
         }
 
         // Check null string.
         if (byteLen == 2 && *current_ == 255 && *(current_ + 1) == 0) {
             atom = nullptr;
         } else {
-            BINJS_TRY_VAR(atom, Atomize(cx_, (const char*)current_, byteLen));
+            BINJS_TRY_VAR(atom, AtomizeUTF8Chars(cx_, (const char*)current_, byteLen));
         }
 
-        // Populate `atomsTable_`: i => atom.
-        atomsTable_.infallibleAppend(atom); // We have reserved before entering the loop.
+        metadata->getAtom(i) = atom;
 
         // Populate `slicesTable_`: i => slice
-        Chars slice((const char*)current_, byteLen);
-        slicesTable_.infallibleAppend(std::move(slice)); // We have reserved before entering the loop.
+        new (&metadata->getSlice(i)) Chars((const char*)current_, byteLen);
 
         current_ += byteLen;
     }
 
     if (posBeforeStrings + stringsByteLen != current_) {
         return raiseError("The length of the strings table didn't match its contents.");
     }
 
+    MOZ_ASSERT(!metadata_);
+    se.release();
+    metadata_ = metadata;
+    metadataOwned_ = MetadataOwnership::Owned;
+
     // Start reading AST.
     MOZ_TRY(readConst(SECTION_HEADER_TREE));
     MOZ_TRY(readConst(COMPRESSION_IDENTITY)); // For the moment, we only support identity compression.
     posBeforeTree_ = current_;
 
     BINJS_MOZ_TRY_DECL(treeByteLen, readInternalUint32());
 
     if (posBeforeTree_ + treeByteLen > stop_ || posBeforeTree_ + treeByteLen < posBeforeTree_) { // Sanity check.
         return raiseError("Invalid byte length in tree table");
     }
 
     // At this stage, we're ready to start reading the tree.
     return Ok();
 }
 
+void
+BinTokenReaderMultipart::traceMetadata(JSTracer* trc)
+{
+    if (metadata_) {
+        metadata_->trace(trc);
+    }
+}
+
 JS::Result<bool>
 BinTokenReaderMultipart::readBool()
 {
     updateLatestKnownGood();
     BINJS_MOZ_TRY_DECL(byte, readByte());
 
     switch (byte) {
       case 0:
@@ -226,20 +263,20 @@ BinTokenReaderMultipart::readDouble()
 
 // A single atom is represented as an index into the table of strings.
 JS::Result<JSAtom*>
 BinTokenReaderMultipart::readMaybeAtom()
 {
     updateLatestKnownGood();
     BINJS_MOZ_TRY_DECL(index, readInternalUint32());
 
-    if (index >= atomsTable_.length()) {
+    if (index >= metadata_->numStrings()) {
         return raiseError("Invalid index to strings table");
     }
-    return atomsTable_[index].get();
+    return metadata_->getAtom(index);
 }
 
 JS::Result<JSAtom*>
 BinTokenReaderMultipart::readAtom()
 {
     BINJS_MOZ_TRY_DECL(maybe, readMaybeAtom());
 
     if (!maybe) {
@@ -250,46 +287,46 @@ BinTokenReaderMultipart::readAtom()
 }
 
 JS::Result<Ok>
 BinTokenReaderMultipart::readChars(Chars& out)
 {
     updateLatestKnownGood();
     BINJS_MOZ_TRY_DECL(index, readInternalUint32());
 
-    if (index >= slicesTable_.length()) {
+    if (index >= metadata_->numStrings()) {
         return raiseError("Invalid index to strings table for string enum");
     }
 
-    out = slicesTable_[index];
+    out = metadata_->getSlice(index);
     return Ok();
 }
 
 JS::Result<BinVariant>
 BinTokenReaderMultipart::readVariant()
 {
     updateLatestKnownGood();
     BINJS_MOZ_TRY_DECL(index, readInternalUint32());
 
-    if (index >= slicesTable_.length()) {
+    if (index >= metadata_->numStrings()) {
         return raiseError("Invalid index to strings table for string enum");
     }
 
     auto variantsPtr = variantsTable_.lookupForAdd(index);
     if (variantsPtr) {
         return variantsPtr->value();
     }
 
     // Either we haven't cached the result yet or this is not a variant.
     // Check in the slices table and, in case of success, cache the result.
 
     // Note that we stop parsing if we attempt to readVariant() with an
     // ill-formed variant, so we don't run the risk of feching an ill-variant
     // more than once.
-    Chars slice = slicesTable_[index]; // We have checked `index` above.
+    Chars slice = metadata_->getSlice(index); // We have checked `index` above.
     BINJS_MOZ_TRY_DECL(variant, cx_->runtime()->binast().binVariant(cx_, slice));
 
     if (!variant) {
         return raiseError("Invalid string enum variant");
     }
 
     if (!variantsTable_.add(variantsPtr, index, *variant)) {
         return raiseOOM();
@@ -303,17 +340,17 @@ BinTokenReaderMultipart::readSkippableSu
 {
     updateLatestKnownGood();
     BINJS_MOZ_TRY_DECL(byteLen, readInternalUint32());
 
     if (current_ + byteLen > stop_ || current_ + byteLen < current_) {
         return raiseError("Invalid byte length in readSkippableSubTree");
     }
 
-    const auto start = current_;
+    const auto start = offset();
 
     current_ += byteLen;
 
     return BinTokenReaderBase::SkippableSubTree(start, byteLen);
 }
 
 // Untagged tuple:
 // - contents (specified by the higher-level grammar);
@@ -327,21 +364,21 @@ BinTokenReaderMultipart::enterUntaggedTu
 
 // Tagged tuples:
 // - uint32_t index in table [grammar];
 // - content (specified by the higher-level grammar);
 JS::Result<Ok>
 BinTokenReaderMultipart::enterTaggedTuple(BinKind& tag, BinTokenReaderMultipart::BinFields&, AutoTaggedTuple& guard)
 {
     BINJS_MOZ_TRY_DECL(index, readInternalUint32());
-    if (index >= grammarTable_.length()) {
+    if (index >= metadata_->numBinKinds()) {
         return raiseError("Invalid index to grammar table");
     }
 
-    tag = grammarTable_[index];
+    tag = metadata_->getBinKind(index);
 
     // Enter the body.
     guard.init();
     return Ok();
 }
 
 // List:
 //
--- a/js/src/frontend/BinTokenReaderMultipart.h
+++ b/js/src/frontend/BinTokenReaderMultipart.h
@@ -40,40 +40,34 @@ class MOZ_STACK_CLASS BinTokenReaderMult
     using CharSlice = BinaryASTSupport::CharSlice;
 
     // This implementation of `BinFields` is effectively `void`, as the format
     // does not embed field information.
     class BinFields {
       public:
         explicit BinFields(JSContext*) {}
     };
-    struct Chars: public CharSlice {
-        explicit Chars(JSContext*)
-          : CharSlice(nullptr, 0)
-        { }
-        Chars(const char* start, const uint32_t byteLen)
-          : CharSlice(start, byteLen)
-        { }
-        Chars(const Chars& other) = default;
-    };
+    using Chars = CharSlice;
 
   public:
     /**
      * Construct a token reader.
      *
      * Does NOT copy the buffer.
      */
-    BinTokenReaderMultipart(JSContext* cx, const uint8_t* start, const size_t length);
+    BinTokenReaderMultipart(JSContext* cx, ErrorReporter* er, const uint8_t* start, const size_t length);
 
     /**
      * Construct a token reader.
      *
      * Does NOT copy the buffer.
      */
-    BinTokenReaderMultipart(JSContext* cx, const Vector<uint8_t>& chars);
+    BinTokenReaderMultipart(JSContext* cx, ErrorReporter* er, const Vector<uint8_t>& chars);
+
+    ~BinTokenReaderMultipart();
 
     /**
      * Read the header of the file.
      */
     MOZ_MUST_USE JS::Result<Ok> readHeader();
 
     // --- Primitive values.
     //
@@ -187,40 +181,39 @@ class MOZ_STACK_CLASS BinTokenReaderMult
 
   private:
     /**
      * Read a single uint32_t.
      */
     MOZ_MUST_USE JS::Result<uint32_t> readInternalUint32();
 
   private:
-    // A mapping grammar index => BinKind, as defined by the [GRAMMAR]
-    // section of the file. Populated during readHeader().
-    Vector<BinKind> grammarTable_;
-
     // A mapping string index => BinVariant as extracted from the [STRINGS]
     // section of the file. Populated lazily.
     js::HashMap<uint32_t, BinVariant, DefaultHasher<uint32_t>, SystemAllocPolicy> variantsTable_;
 
-    // A mapping index => JSAtom, as defined by the [STRINGS]
-    // section of the file. Populated during readHeader().
-    using AtomVector = GCVector<JSAtom*>;
-    JS::Rooted<AtomVector> atomsTable_;
-
-    // The same mapping, but as CharSlice. Populated during readHeader().
-    // The slices are into the source buffer.
-    Vector<Chars> slicesTable_;
+    enum class MetadataOwnership {
+        Owned,
+        Unowned
+    };
+    MetadataOwnership metadataOwned_;
+    BinASTSourceMetadata* metadata_;
 
     const uint8_t* posBeforeTree_;
 
     BinTokenReaderMultipart(const BinTokenReaderMultipart&) = delete;
     BinTokenReaderMultipart(BinTokenReaderMultipart&&) = delete;
     BinTokenReaderMultipart& operator=(BinTokenReaderMultipart&) = delete;
 
   public:
+    void traceMetadata(JSTracer* trc);
+    BinASTSourceMetadata* takeMetadata();
+    MOZ_MUST_USE JS::Result<Ok> initFromScriptSource(ScriptSource* scriptSource);
+
+  public:
     // The following classes are used whenever we encounter a tuple/tagged tuple/list
     // to make sure that:
     //
     // - if the construct "knows" its byte length, we have exactly consumed all
     //   the bytes (otherwise, this means that the file is corrupted, perhaps on
     //   purpose, so we need to reject the stream);
     // - if the construct has a footer, once we are done reading it, we have
     //   reached the footer (this is to aid with debugging).
--- a/js/src/frontend/BinTokenReaderTester.cpp
+++ b/js/src/frontend/BinTokenReaderTester.cpp
@@ -18,22 +18,22 @@
 namespace js {
 namespace frontend {
 
 using BinFields = BinTokenReaderTester::BinFields;
 using AutoList = BinTokenReaderTester::AutoList;
 using AutoTaggedTuple = BinTokenReaderTester::AutoTaggedTuple;
 using AutoTuple = BinTokenReaderTester::AutoTuple;
 
-BinTokenReaderTester::BinTokenReaderTester(JSContext* cx, const uint8_t* start, const size_t length)
-    : BinTokenReaderBase(cx, start, length)
+BinTokenReaderTester::BinTokenReaderTester(JSContext* cx, ErrorReporter* er, const uint8_t* start, const size_t length)
+    : BinTokenReaderBase(cx, er, start, length)
 { }
 
-BinTokenReaderTester::BinTokenReaderTester(JSContext* cx, const Vector<uint8_t>& buf)
-    : BinTokenReaderBase(cx, buf.begin(), buf.length())
+BinTokenReaderTester::BinTokenReaderTester(JSContext* cx, ErrorReporter* er, const Vector<uint8_t>& buf)
+    : BinTokenReaderBase(cx, er, buf.begin(), buf.length())
 { }
 
 JS::Result<Ok>
 BinTokenReaderTester::readHeader()
 {
     // This format does not have a header.
     return Ok();
 }
@@ -235,17 +235,17 @@ BinTokenReaderTester::readSkippableSubTr
 {
     updateLatestKnownGood();
     BINJS_MOZ_TRY_DECL(byteLen, readInternalUint32());
 
     if (current_ + byteLen > stop_ || current_ + byteLen < current_) {
         return raiseError("Invalid byte length in readSkippableSubTree");
     }
 
-    const auto start = current_;
+    const auto start = offset();
 
     current_ += byteLen;
 
     return BinTokenReaderBase::SkippableSubTree(start, byteLen);
 }
 
 // Untagged tuple:
 // - "<tuple>";
--- a/js/src/frontend/BinTokenReaderTester.h
+++ b/js/src/frontend/BinTokenReaderTester.h
@@ -17,16 +17,18 @@
 
 #if !defined(NIGHTLY_BUILD)
 #error "BinTokenReaderTester.* is designed to help test implementations of successive versions of JS BinaryAST. It is available only on Nightly."
 #endif // !defined(NIGHTLY_BUILD)
 
 namespace js {
 namespace frontend {
 
+class BinASTSourceMetadata;
+
 /**
  * A token reader for a simple, alternative serialization format for BinAST.
  *
  * This serialization format, which is also supported by the reference
  * implementation of the BinAST compression suite, is designed to be
  * mostly human-readable and easy to check for all sorts of deserialization
  * errors. While this format is NOT designed to be shipped to end-users, it
  * is nevertheless a very useful tool for implementing and testing parsers.
@@ -63,24 +65,24 @@ class MOZ_STACK_CLASS BinTokenReaderTest
     class AutoTaggedTuple;
 
   public:
     /**
      * Construct a token reader.
      *
      * Does NOT copy the buffer.
      */
-    BinTokenReaderTester(JSContext* cx, const uint8_t* start, const size_t length);
+    BinTokenReaderTester(JSContext* cx, ErrorReporter* er, const uint8_t* start, const size_t length);
 
     /**
      * Construct a token reader.
      *
      * Does NOT copy the buffer.
      */
-    BinTokenReaderTester(JSContext* cx, const Vector<uint8_t>& chars);
+    BinTokenReaderTester(JSContext* cx, ErrorReporter* er, const Vector<uint8_t>& chars);
 
     /**
      * Read the header of the file.
      */
     MOZ_MUST_USE JS::Result<Ok> readHeader();
 
     // --- Primitive values.
     //
@@ -209,16 +211,21 @@ class MOZ_STACK_CLASS BinTokenReaderTest
     }
 
     /**
      * Read a single uint32_t.
      */
     MOZ_MUST_USE JS::Result<uint32_t> readInternalUint32();
 
   public:
+    void traceMetadata(JSTracer*) {}
+    BinASTSourceMetadata* takeMetadata() { MOZ_CRASH("Tester format has no metadata to take!"); }
+    MOZ_MUST_USE JS::Result<Ok> initFromScriptSource(ScriptSource*) { MOZ_CRASH("Tester format not for dynamic use"); }
+
+  public:
     // The following classes are used whenever we encounter a tuple/tagged tuple/list
     // to make sure that:
     //
     // - if the construct "knows" its byte length, we have exactly consumed all
     //   the bytes (otherwise, this means that the file is corrupted, perhaps on
     //   purpose, so we need to reject the stream);
     // - if the construct has a footer, once we are done reading it, we have
     //   reached the footer (this is to aid with debugging).
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -671,33 +671,41 @@ frontend::CompileGlobalBinASTScript(JSCo
     frontend::UsedNameTracker usedNames(cx);
 
     RootedScriptSourceObject sourceObj(cx, CreateScriptSourceObject(cx, options));
 
     if (!sourceObj) {
         return nullptr;
     }
 
+    if (!sourceObj->source()->setBinASTSourceCopy(cx, src, len))
+        return nullptr;
+
     RootedScript script(cx, JSScript::Create(cx, options, sourceObj, 0, len, 0, len));
 
     if (!script) {
         return nullptr;
     }
 
     Directives directives(options.strictOption);
     GlobalSharedContext globalsc(cx, ScopeKind::Global, directives, options.extraWarningsOption);
 
-    frontend::BinASTParser<BinTokenReaderMultipart> parser(cx, alloc, usedNames, options);
+    frontend::BinASTParser<BinTokenReaderMultipart> parser(cx, alloc, usedNames, options, sourceObj);
 
-    auto parsed = parser.parse(&globalsc, src, len);
+    // Metadata stores internal pointers, so we must use the same buffer every time, including for lazy parses
+    ScriptSource* ss = sourceObj->source();
+    BinASTSourceMetadata* metadata = nullptr;
+    auto parsed = parser.parse(&globalsc, ss->binASTSource(), ss->length(), &metadata);
 
     if (parsed.isErr()) {
         return nullptr;
     }
 
+    sourceObj->source()->setBinASTSourceMetadata(metadata);
+
     BytecodeEmitter bce(nullptr, &parser, &globalsc, script, nullptr, 0);
 
     if (!bce.init()) {
         return nullptr;
     }
 
     ParseNode *pn = parsed.unwrap();
     if (!bce.emitScript(pn)) {
@@ -829,21 +837,24 @@ class MOZ_STACK_CLASS AutoAssertFunction
 #endif
     }
 };
 
 bool
 frontend::CompileLazyFunction(JSContext* cx, Handle<LazyScript*> lazy, const char16_t* chars, size_t length)
 {
     MOZ_ASSERT(cx->compartment() == lazy->functionNonDelazifying()->compartment());
+
     // We can only compile functions whose parents have previously been
     // compiled, because compilation requires full information about the
     // function's immediately enclosing scope.
     MOZ_ASSERT(lazy->enclosingScriptHasEverBeenCompiled());
 
+    MOZ_ASSERT(!lazy->isBinAST());
+
     AutoAssertReportedException assertException(cx);
     Rooted<JSFunction*> fun(cx, lazy->functionNonDelazifying());
     AutoAssertFunctionDelazificationCompletion delazificationCompletion(cx, fun);
 
     JS::CompileOptions options(cx);
     options.setMutedErrors(lazy->mutedErrors())
            .setFileAndLine(lazy->filename(), lazy->lineno())
            .setColumn(lazy->column())
@@ -910,16 +921,79 @@ frontend::CompileLazyFunction(JSContext*
         return false;
     }
 
     delazificationCompletion.complete();
     assertException.reset();
     return true;
 }
 
+#ifdef JS_BUILD_BINAST
+
+bool
+frontend::CompileLazyBinASTFunction(JSContext* cx, Handle<LazyScript*> lazy, const uint8_t* buf, size_t length)
+{
+    MOZ_ASSERT(cx->compartment() == lazy->functionNonDelazifying()->compartment());
+
+    // We can only compile functions whose parents have previously been
+    // compiled, because compilation requires full information about the
+    // function's immediately enclosing scope.
+    MOZ_ASSERT(lazy->enclosingScriptHasEverBeenCompiled());
+    MOZ_ASSERT(lazy->isBinAST());
+
+    CompileOptions options(cx);
+    options.setMutedErrors(lazy->mutedErrors())
+           .setFileAndLine(lazy->filename(), lazy->lineno())
+           .setColumn(lazy->column())
+           .setScriptSourceOffset(lazy->sourceStart())
+           .setNoScriptRval(false)
+           .setSelfHostingMode(false);
+
+    UsedNameTracker usedNames(cx);
+
+    RootedScriptSourceObject sourceObj(cx, &lazy->sourceObject());
+    MOZ_ASSERT(sourceObj);
+
+    RootedScript script(cx, JSScript::Create(cx, options, sourceObj, lazy->sourceStart(), lazy->sourceEnd(),
+                                             lazy->sourceStart(), lazy->sourceEnd()));
+
+    if (!script)
+        return false;
+
+    if (lazy->hasBeenCloned())
+        script->setHasBeenCloned();
+
+    frontend::BinASTParser<BinTokenReaderMultipart> parser(cx, cx->tempLifoAlloc(),
+                                                           usedNames, options, sourceObj,
+                                                           lazy);
+
+    auto parsed = parser.parseLazyFunction(lazy->scriptSource(), lazy->sourceStart());
+
+    if (parsed.isErr())
+        return false;
+
+    ParseNode *pn = parsed.unwrap();
+
+    BytecodeEmitter bce(nullptr, &parser, pn->as<CodeNode>().funbox(), script,
+                        lazy, pn->pn_pos, BytecodeEmitter::LazyFunction);
+
+    if (!bce.init())
+        return false;
+
+    if (!bce.emitFunctionScript(&pn->as<CodeNode>(), BytecodeEmitter::TopLevelFunction::Yes))
+        return false;
+
+    if (!NameFunctions(cx, pn))
+        return false;
+
+    return script;
+}
+
+#endif // JS_BUILD_BINAST
+
 bool
 frontend::CompileStandaloneFunction(JSContext* cx, MutableHandleFunction fun,
                                     const JS::ReadOnlyCompileOptions& options,
                                     JS::SourceBufferHolder& srcBuf,
                                     const Maybe<uint32_t>& parameterListEnd,
                                     HandleScope enclosingScope /* = nullptr */)
 {
     AutoAssertReportedException assertException(cx);
--- a/js/src/frontend/BytecodeCompiler.h
+++ b/js/src/frontend/BytecodeCompiler.h
@@ -38,16 +38,19 @@ CompileGlobalScript(JSContext* cx, LifoA
 #if defined(JS_BUILD_BINAST)
 
 JSScript*
 CompileGlobalBinASTScript(JSContext *cx, LifoAlloc& alloc,
                           const JS::ReadOnlyCompileOptions& options,
                           const uint8_t* src, size_t len,
                           ScriptSourceObject** sourceObjectOut = nullptr);
 
+MOZ_MUST_USE bool
+CompileLazyBinASTFunction(JSContext* cx, Handle<LazyScript*> lazy, const uint8_t* buf, size_t length);
+
 #endif // JS_BUILD_BINAST
 
 JSScript*
 CompileEvalScript(JSContext* cx, LifoAlloc& alloc,
                   HandleObject scopeChain, HandleScope enclosingScope,
                   const JS::ReadOnlyCompileOptions& options,
                   JS::SourceBufferHolder& srcBuf,
                   ScriptSourceObject** sourceObjectOut = nullptr);
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -5748,18 +5748,24 @@ BytecodeEmitter::emitFunction(CodeNode* 
             Rooted<JSScript*> script(cx, JSScript::Create(cx, options, sourceObject,
                                                           funbox->bufStart, funbox->bufEnd,
                                                           funbox->toStringStart,
                                                           funbox->toStringEnd));
             if (!script) {
                 return false;
             }
 
+            EmitterMode nestedMode = emitterMode;
+            if (nestedMode == BytecodeEmitter::LazyFunction) {
+                MOZ_ASSERT(lazyScript->isBinAST());
+                nestedMode = BytecodeEmitter::Normal;
+            }
+
             BytecodeEmitter bce2(this, parser, funbox, script, /* lazyScript = */ nullptr,
-                                 funNode->pn_pos, emitterMode);
+                                 funNode->pn_pos, nestedMode);
             if (!bce2.init()) {
                 return false;
             }
 
             /* We measured the max scope depth when we parsed the function. */
             if (!bce2.emitFunctionScript(funNode, TopLevelFunction::No)) {
                 return false;
             }
--- a/js/src/fuzz-tests/testBinASTReader.cpp
+++ b/js/src/fuzz-tests/testBinASTReader.cpp
@@ -55,18 +55,24 @@ testBinASTReaderFuzz(const uint8_t* buf,
         return 0;
     }
 
     UsedNameTracker binUsedNames(gCx);
 
     Directives directives(false);
     GlobalSharedContext globalsc(gCx, ScopeKind::Global, directives, false);
 
+    RootedScriptSourceObject sourceObj(gCx, frontend::CreateScriptSourceObject(gCx, options,
+                                               mozilla::Nothing()));
+    if (!sourceObj) {
+        ReportOutOfMemory(gCx);
+        return 0;
+    }
     BinASTParser<js::frontend::BinTokenReaderMultipart> reader(gCx, gCx->tempLifoAlloc(),
-                                                               binUsedNames, options);
+                                                               binUsedNames, options, sourceObj);
 
     // Will be deallocated once `reader` goes out of scope.
     auto binParsed = reader.parse(&globalsc, binSource);
     RootedValue binExn(gCx);
     if (binParsed.isErr()) {
         js::GetAndClearException(gCx, &binExn);
         return 0;
     }
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/gc/bug-1491326.js
@@ -0,0 +1,9 @@
+// |jit-test| --fuzzing-safe
+
+if (!('oomTest' in this))
+    quit();
+
+var g = newGlobal();
+g.parent = this;
+g.eval("new Debugger(parent).onExceptionUnwind = function() {}");
+oomTest(() => l, (true));
--- a/js/src/jit-test/tests/wasm/gc/ref-global.js
+++ b/js/src/jit-test/tests/wasm/gc/ref-global.js
@@ -33,16 +33,79 @@ if (!wasmGcEnabled())
     let mod = new WebAssembly.Module(bin);
     let ins = new WebAssembly.Instance(mod).exports;
 
     assertEq(ins.get(), null);
     ins.copy();                 // Should not crash
     ins.clear();                // Should not crash
 }
 
+// Global with struct type
+
+{
+    let bin = wasmTextToBinary(
+        `(module
+          (gc_feature_opt_in 1)
+
+          (type $point (struct
+                        (field $x f64)
+                        (field $y f64)))
+
+          (global $glob (mut (ref $point)) (ref.null (ref $point)))
+
+          (func (export "init")
+           (set_global $glob (struct.new $point (f64.const 0.5) (f64.const 2.75))))
+
+          (func (export "change")
+           (set_global $glob (struct.new $point (f64.const 3.5) (f64.const 37.25))))
+
+          (func (export "clear")
+           (set_global $glob (ref.null (ref $point))))
+
+          (func (export "x") (result f64)
+           (struct.get $point 0 (get_global $glob)))
+
+          (func (export "y") (result f64)
+           (struct.get $point 1 (get_global $glob))))`);
+
+    let mod = new WebAssembly.Module(bin);
+    let ins = new WebAssembly.Instance(mod).exports;
+
+    assertErrorMessage(() => ins.x(), WebAssembly.RuntimeError, /dereferencing null pointer/);
+
+    ins.init();
+    assertEq(ins.x(), 0.5);
+    assertEq(ins.y(), 2.75);
+
+    ins.change();
+    assertEq(ins.x(), 3.5);
+    assertEq(ins.y(), 37.25);
+
+    ins.clear();
+    assertErrorMessage(() => ins.x(), WebAssembly.RuntimeError, /dereferencing null pointer/);
+}
+
+// Global value of type anyref for initializer from a WebAssembly.Global,
+// just check that it works.
+{
+    let bin = wasmTextToBinary(
+        `(module
+          (gc_feature_opt_in 1)
+          (import $g "" "g" (global anyref))
+          (global $glob anyref (get_global $g))
+          (func (export "get") (result anyref)
+           (get_global $glob)))`);
+
+    let mod = new WebAssembly.Module(bin);
+    let obj = {zappa:37};
+    let g = new WebAssembly.Global({value: "anyref"}, obj);
+    let ins = new WebAssembly.Instance(mod, {"":{g}}).exports;
+    assertEq(ins.get(), obj);
+}
+
 // We can't import a global of a reference type because we don't have a good
 // notion of structural type compatibility yet.
 {
     let bin = wasmTextToBinary(
         `(module
           (gc_feature_opt_in 1)
           (type $box (struct (field $val i32)))
           (import "m" "g" (global (mut (ref $box)))))`);
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -672,8 +672,11 @@ MSG_DEF(JSMSG_RESPONSE_ALREADY_CONSUMED,
 MSG_DEF(JSMSG_BIGINT_TO_NUMBER, 0, JSEXN_TYPEERR, "can't convert BigInt to number")
 MSG_DEF(JSMSG_NUMBER_TO_BIGINT, 0, JSEXN_RANGEERR, "can't convert non-finite number to BigInt")
 MSG_DEF(JSMSG_BIGINT_TOO_LARGE, 0, JSEXN_RANGEERR, "BigInt is too large to allocate")
 MSG_DEF(JSMSG_BIGINT_DIVISION_BY_ZERO, 0, JSEXN_RANGEERR, "BigInt division by zero")
 MSG_DEF(JSMSG_BIGINT_NEGATIVE_EXPONENT, 0, JSEXN_RANGEERR, "BigInt negative exponent")
 MSG_DEF(JSMSG_BIGINT_INVALID_SYNTAX, 0, JSEXN_SYNTAXERR, "invalid BigInt syntax")
 MSG_DEF(JSMSG_NOT_BIGINT, 0, JSEXN_TYPEERR, "not a BigInt")
 MSG_DEF(JSMSG_BIGINT_NOT_SERIALIZABLE, 0, JSEXN_TYPEERR, "BigInt value can't be serialized in JSON")
+
+// BinAST
+MSG_DEF(JSMSG_BINAST,                                    1, JSEXN_SYNTAXERR, "BinAST Parsing Error: {0}")
--- a/js/src/jsapi-tests/testBinASTReader.cpp
+++ b/js/src/jsapi-tests/testBinASTReader.cpp
@@ -223,17 +223,23 @@ runTestFromPath(JSContext* cx, const cha
         CompileOptions binOptions(cx);
         binOptions.setFileAndLine(binPath.begin(), 0);
 
         frontend::UsedNameTracker binUsedNames(cx);
 
         frontend::Directives directives(false);
         frontend::GlobalSharedContext globalsc(cx, ScopeKind::Global, directives, false);
 
-        frontend::BinASTParser<Tok> binParser(cx, allocScope.alloc(), binUsedNames, binOptions);
+        RootedScriptSourceObject sourceObj(cx, frontend::CreateScriptSourceObject(cx, binOptions,
+                                                   mozilla::Nothing()));
+        if (!sourceObj) {
+            MOZ_CRASH();
+        }
+
+        frontend::BinASTParser<Tok> binParser(cx, allocScope.alloc(), binUsedNames, binOptions, sourceObj);
 
         auto binParsed = binParser.parse(&globalsc, binSource); // Will be deallocated once `reader` goes out of scope.
         RootedValue binExn(cx);
         if (binParsed.isErr()) {
             // Save exception for more detailed error message, if necessary.
             if (!js::GetAndClearException(cx, &binExn)) {
                 MOZ_CRASH("Couldn't clear binExn");
             }
--- a/js/src/jsapi-tests/testBinTokenReaderTester.cpp
+++ b/js/src/jsapi-tests/testBinTokenReaderTester.cpp
@@ -135,66 +135,66 @@ void readFull(const char* path, js::Vect
 }
 
 
 // Reading a simple string.
 BEGIN_TEST(testBinTokenReaderTesterSimpleString)
 {
     js::Vector<uint8_t> contents(cx);
     readFull("jsapi-tests/binast/tokenizer/tester/test-simple-string.binjs", contents);
-    Tokenizer tokenizer(cx, contents);
+    Tokenizer tokenizer(cx, nullptr, contents);
 
     Chars found(cx);
     CHECK(tokenizer.readChars(found).isOk());
 
     CHECK(Tokenizer::equals(found, "simple string")); // FIXME: Find a way to make CHECK_EQUAL use `Tokenizer::equals`.
 
     return true;
 }
 END_TEST(testBinTokenReaderTesterSimpleString)
 
 // Reading a string with embedded 0.
 BEGIN_TEST(testBinTokenReaderTesterStringWithEscapes)
 {
     js::Vector<uint8_t> contents(cx);
     readFull("jsapi-tests/binast/tokenizer/tester/test-string-with-escapes.binjs", contents);
-    Tokenizer tokenizer(cx, contents);
+    Tokenizer tokenizer(cx, nullptr, contents);
 
     Chars found(cx);
     CHECK(tokenizer.readChars(found).isOk());
 
     CHECK(Tokenizer::equals(found, "string with escapes \0\1\0")); // FIXME: Find a way to make CHECK_EQUAL use `Tokenizer::equals`.
 
     return true;
 }
 END_TEST(testBinTokenReaderTesterStringWithEscapes)
 
 // Reading an empty untagged tuple
 BEGIN_TEST(testBinTokenReaderTesterEmptyUntaggedTuple)
 {
     js::Vector<uint8_t> contents(cx);
     readFull("jsapi-tests/binast/tokenizer/tester/test-empty-untagged-tuple.binjs", contents);
-    Tokenizer tokenizer(cx, contents);
+    Tokenizer tokenizer(cx, nullptr, contents);
 
     {
         Tokenizer::AutoTuple guard(tokenizer);
         CHECK(tokenizer.enterUntaggedTuple(guard).isOk());
         CHECK(guard.done().isOk());
     }
 
     return true;
 }
 END_TEST(testBinTokenReaderTesterEmptyUntaggedTuple)
 
 // Reading a untagged tuple with two strings
 BEGIN_TEST(testBinTokenReaderTesterTwoStringsInTuple)
 {
     js::Vector<uint8_t> contents(cx);
     readFull("jsapi-tests/binast/tokenizer/tester/test-trivial-untagged-tuple.binjs", contents);
-    Tokenizer tokenizer(cx, contents);
+    Tokenizer tokenizer(cx, nullptr, contents);
 
     {
         Tokenizer::AutoTuple guard(tokenizer);
         CHECK(tokenizer.enterUntaggedTuple(guard).isOk());
 
         Chars found_0(cx);
         CHECK(tokenizer.readChars(found_0).isOk());
         CHECK(Tokenizer::equals(found_0, "foo")); // FIXME: Find a way to make CHECK_EQUAL use `Tokenizer::equals`.
@@ -210,17 +210,17 @@ BEGIN_TEST(testBinTokenReaderTesterTwoSt
 }
 END_TEST(testBinTokenReaderTesterTwoStringsInTuple)
 
 // Reading a tagged tuple `Pattern { id: "foo", value: 3.1415}`
 BEGIN_TEST(testBinTokenReaderTesterSimpleTaggedTuple)
 {
     js::Vector<uint8_t> contents(cx);
     readFull("jsapi-tests/binast/tokenizer/tester/test-simple-tagged-tuple.binjs", contents);
-    Tokenizer tokenizer(cx, contents);
+    Tokenizer tokenizer(cx, nullptr, contents);
 
     {
         js::frontend::BinKind tag;
         Tokenizer::BinFields fields(cx);
         Tokenizer::AutoTaggedTuple guard(tokenizer);
         CHECK(tokenizer.enterTaggedTuple(tag, fields, guard).isOk());
 
         CHECK(tag == js::frontend::BinKind::BindingIdentifier);
@@ -244,17 +244,17 @@ BEGIN_TEST(testBinTokenReaderTesterSimpl
 END_TEST(testBinTokenReaderTesterSimpleTaggedTuple)
 
 
 // Reading an empty list
 BEGIN_TEST(testBinTokenReaderTesterEmptyList)
 {
     js::Vector<uint8_t> contents(cx);
     readFull("jsapi-tests/binast/tokenizer/tester/test-empty-list.binjs", contents);
-    Tokenizer tokenizer(cx, contents);
+    Tokenizer tokenizer(cx, nullptr, contents);
 
     {
         uint32_t length;
         Tokenizer::AutoList guard(tokenizer);
         CHECK(tokenizer.enterList(length, guard).isOk());
 
         CHECK(length == 0);
         CHECK(guard.done().isOk());
@@ -264,17 +264,17 @@ BEGIN_TEST(testBinTokenReaderTesterEmpty
 }
 END_TEST(testBinTokenReaderTesterEmptyList)
 
 // Reading `["foo", "bar"]`
 BEGIN_TEST(testBinTokenReaderTesterSimpleList)
 {
     js::Vector<uint8_t> contents(cx);
     readFull("jsapi-tests/binast/tokenizer/tester/test-trivial-list.binjs", contents);
-    Tokenizer tokenizer(cx, contents);
+    Tokenizer tokenizer(cx, nullptr, contents);
 
     {
         uint32_t length;
         Tokenizer::AutoList guard(tokenizer);
         CHECK(tokenizer.enterList(length, guard).isOk());
 
         CHECK(length == 2);
 
@@ -294,17 +294,17 @@ BEGIN_TEST(testBinTokenReaderTesterSimpl
 END_TEST(testBinTokenReaderTesterSimpleList)
 
 
 // Reading `[["foo", "bar"]]`
 BEGIN_TEST(testBinTokenReaderTesterNestedList)
 {
     js::Vector<uint8_t> contents(cx);
     readFull("jsapi-tests/binast/tokenizer/tester/test-nested-lists.binjs", contents);
-    Tokenizer tokenizer(cx, contents);
+    Tokenizer tokenizer(cx, nullptr, contents);
 
     {
         uint32_t outerLength;
         Tokenizer::AutoList outerGuard(tokenizer);
         CHECK(tokenizer.enterList(outerLength, outerGuard).isOk());
         CHECK_EQUAL(outerLength, (uint32_t)1);
 
         {
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -4097,17 +4097,17 @@ JS_DecompileScript(JSContext* cx, Handle
 
     AssertHeapIsIdle();
     CHECK_THREAD(cx);
     script->ensureNonLazyCanonicalFunction();
     RootedFunction fun(cx, script->functionNonDelazifying());
     if (fun) {
         return JS_DecompileFunction(cx, fun);
     }
-    bool haveSource = script->scriptSource()->hasSourceData();
+    bool haveSource = script->scriptSource()->hasSourceText();
     if (!haveSource && !JSScript::loadSource(cx, script->scriptSource(), &haveSource)) {
         return nullptr;
     }
     return haveSource ? JSScript::sourceData(cx, script)
                       : NewStringCopyZ<CanGC>(cx, "[no source]");
 }
 
 JS_PUBLIC_API(JSString*)
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -704,16 +704,17 @@ if CONFIG['JS_BUILD_BINAST']:
     # Using SOURCES, as UNIFIED_SOURCES causes mysterious bugs on 32-bit platforms.
     # These parts of BinAST are designed only to test evolutions of the
     # specification.
     SOURCES += ['frontend/BinTokenReaderTester.cpp']
     # These parts of BinAST should eventually move to release.
     SOURCES += [
         'frontend/BinSource-auto.cpp',
         'frontend/BinSource.cpp',
+        'frontend/BinSourceRuntimeSupport.cpp',
         'frontend/BinToken.cpp',
         'frontend/BinTokenReaderBase.cpp',
         'frontend/BinTokenReaderMultipart.cpp',
     ]
 
     # Instrument BinAST files for fuzzing as we have a fuzzing target for BinAST.
     if CONFIG['FUZZING_INTERFACES'] and CONFIG['LIBFUZZER']:
         SOURCES['frontend/BinSource-auto.cpp'].flags += libfuzzer_flags
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -5072,22 +5072,23 @@ using js::frontend::Directives;
 using js::frontend::GlobalSharedContext;
 using js::frontend::ParseNode;
 using js::frontend::UsedNameTracker;
 
 template <typename Tok>
 static bool
 ParseBinASTData(JSContext* cx, uint8_t* buf_data, uint32_t buf_length,
                 GlobalSharedContext* globalsc, UsedNameTracker& usedNames,
-                const JS::ReadOnlyCompileOptions& options)
+                const JS::ReadOnlyCompileOptions& options,
+                HandleScriptSourceObject sourceObj)
 {
     MOZ_ASSERT(globalsc);
 
     // Note: We need to keep `reader` alive as long as we can use `parsed`.
-    BinASTParser<Tok> reader(cx, cx->tempLifoAlloc(), usedNames, options);
+    BinASTParser<Tok> reader(cx, cx->tempLifoAlloc(), usedNames, options, sourceObj);
 
     JS::Result<ParseNode*> parsed = reader.parse(globalsc, buf_data, buf_length);
 
     if (parsed.isErr())
         return false;
 
 #ifdef DEBUG
     Fprinter out(stderr);
@@ -5178,22 +5179,27 @@ BinParse(JSContext* cx, unsigned argc, V
 
 
     CompileOptions options(cx);
     options.setIntroductionType("js shell bin parse")
            .setFileAndLine("<ArrayBuffer>", 1);
 
     UsedNameTracker usedNames(cx);
 
+    RootedScriptSourceObject sourceObj(cx, frontend::CreateScriptSourceObject(cx, options, Nothing()));
+    if (!sourceObj) {
+        return false;
+    }
+
     Directives directives(false);
     GlobalSharedContext globalsc(cx, ScopeKind::Global, directives, false);
 
     auto parseFunc = useMultipart ? ParseBinASTData<frontend::BinTokenReaderMultipart>
                                   : ParseBinASTData<frontend::BinTokenReaderTester>;
-    if (!parseFunc(cx, buf_data, buf_length, &globalsc, usedNames, options)) {
+    if (!parseFunc(cx, buf_data, buf_length, &globalsc, usedNames, options, sourceObj)) {
         return false;
     }
 
     args.rval().setUndefined();
     return true;
 }
 
 #endif // defined(JS_BUILD_BINAST)
@@ -10051,24 +10057,30 @@ SetContextOptions(JSContext* cx, const O
     enableNativeRegExp = !op.getBoolOption("no-native-regexp");
     enableWasmBaseline = !op.getBoolOption("no-wasm-baseline");
     enableWasmIon = !op.getBoolOption("no-wasm-ion");
 #ifdef ENABLE_WASM_CRANELIFT
     wasmForceCranelift = op.getBoolOption("wasm-force-cranelift");
 #endif
 #ifdef ENABLE_WASM_GC
     enableWasmGc = op.getBoolOption("wasm-gc");
-# ifdef ENABLE_WASM_CRANELIFT
-    enableWasmGc = false;
-# endif
 #endif
     enableTestWasmAwaitTier2 = op.getBoolOption("test-wasm-await-tier2");
     enableAsyncStacks = !op.getBoolOption("no-async-stacks");
     enableStreams = op.getBoolOption("enable-streams");
 
+#if defined ENABLE_WASM_GC && defined ENABLE_WASM_CRANELIFT
+    // Note, once we remove --wasm-gc this test will no longer make any sense
+    // and we'll need a better solution.
+    if (enableWasmGc && wasmForceCranelift) {
+        fprintf(stderr, "Do not combine --wasm-gc and --wasm-force-cranelift, they are incompatible.\n");
+        return false;
+    }
+#endif
+
     JS::ContextOptionsRef(cx).setBaseline(enableBaseline)
                              .setIon(enableIon)
                              .setAsmJS(enableAsmJS)
                              .setWasm(enableWasm)
                              .setWasmBaseline(enableWasmBaseline)
                              .setWasmIon(enableWasmIon)
 #ifdef ENABLE_WASM_CRANELIFT
                              .setWasmForceCranelift(wasmForceCranelift)
--- a/js/src/tests/jstests.py
+++ b/js/src/tests/jstests.py
@@ -349,18 +349,20 @@ def load_wpt_tests(requested_paths, excl
         for test in it:
             if test[1].get("jsshell"):
                 yield test
 
     test_manifests = testloader.ManifestLoader(test_paths, types=["testharness"],
                                                meta_filters=[filter_jsshell_tests]).load()
 
     run_info_extras = products.load_product(kwargs["config"], "firefox")[-1](**kwargs)
+    is_automation = os.environ.get('AUTOMATION', False)
     run_info = wpttest.get_run_info(kwargs["metadata_root"], "firefox",
-                                    debug=debug, extras=run_info_extras)
+                                    debug=debug, extras=run_info_extras,
+                                    raise_exception=is_automation)
 
     path_filter = testloader.TestFilter(test_manifests,
                                         include=requested_paths,
                                         exclude=excluded_paths)
     loader = testloader.TestLoader(test_manifests,
                                    ["testharness"],
                                    run_info,
                                    manifest_filters=[path_filter])
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -7795,21 +7795,21 @@ class DebuggerSourceGetTextMatcher
 
   public:
     explicit DebuggerSourceGetTextMatcher(JSContext* cx) : cx_(cx) { }
 
     using ReturnType = JSString*;
 
     ReturnType match(HandleScriptSourceObject sourceObject) {
         ScriptSource* ss = sourceObject->source();
-        bool hasSourceData = ss->hasSourceData();
-        if (!ss->hasSourceData() && !JSScript::loadSource(cx_, ss, &hasSourceData)) {
+        bool hasSourceText = ss->hasSourceText();
+        if (!ss->hasSourceText() && !JSScript::loadSource(cx_, ss, &hasSourceText)) {
             return nullptr;
         }
-        if (!hasSourceData) {
+        if (!hasSourceText) {
             return NewStringCopyZ<CanGC>(cx_, "[no source]");
         }
 
         if (ss->isFunctionBody()) {
             return ss->functionBodyString(cx_);
         }
 
         return ss->substring(cx_, 0, ss->length());
--- a/js/src/vm/HelperThreads.cpp
+++ b/js/src/vm/HelperThreads.cpp
@@ -925,16 +925,19 @@ js::StartOffThreadDecodeMultiScripts(JSC
 
 #if defined(JS_BUILD_BINAST)
 
 bool
 js::StartOffThreadDecodeBinAST(JSContext* cx, const ReadOnlyCompileOptions& options,
                                const uint8_t* buf, size_t length,
                                JS::OffThreadCompileCallback callback, void *callbackData)
 {
+    if (!cx->runtime()->binast().ensureBinTablesInitialized(cx))
+        return false;
+
     auto task = cx->make_unique<BinASTDecodeTask>(cx, buf, length, callback, callbackData);
     if (!task || !StartOffThreadParseTask(cx, task.get(), options)) {
         return false;
     }
 
     Unused << task.release();
     return true;
 }
--- a/js/src/vm/JSFunction.cpp
+++ b/js/src/vm/JSFunction.cpp
@@ -1046,17 +1046,17 @@ js::FunctionToString(JSContext* cx, Hand
     // all class constructors always have source.
     bool haveSource = fun->isInterpreted() && (fun->isClassConstructor() ||
                                                !fun->isSelfHostedBuiltin());
 
     // If we're in toSource mode, put parentheses around lambda functions so
     // that eval returns lambda, not function statement.
     bool addParentheses = haveSource && isToSource && (fun->isLambda() && !fun->isArrow());
 
-    if (haveSource && !script->scriptSource()->hasSourceData() &&
+    if (haveSource && !script->scriptSource()->hasSourceText() &&
         !JSScript::loadSource(cx, script->scriptSource(), &haveSource))
     {
         return nullptr;
     }
 
     // Fast path for the common case, to avoid StringBuffer overhead.
     if (!addParentheses && haveSource) {
         FunctionToStringCache& cache = cx->zone()->functionToStringCache();
@@ -1745,16 +1745,17 @@ JSFunction::createScriptForLazilyInterpr
 
         // Only functions without inner functions or direct eval are
         // re-lazified. Functions with either of those are on the static scope
         // chain of their inner functions, or in the case of eval, possibly
         // eval'd inner functions. This prohibits re-lazification as
         // StaticScopeIter queries needsCallObject of those functions, which
         // requires a non-lazy script.  Note that if this ever changes,
         // XDRRelazificationInfo will have to be fixed.
+        bool isBinAST = lazy->scriptSource()->hasBinASTSource();
         bool canRelazify = !lazy->numInnerFunctions() && !lazy->hasDirectEval();
 
         if (script) {
             // This function is non-canonical function, and the canonical
             // function is already delazified.
             fun->setUnlazifiedScript(script);
             // Remember the lazy script on the compiled script, so it can be
             // stored on the function again in case of re-lazification.
@@ -1778,34 +1779,48 @@ JSFunction::createScriptForLazilyInterpr
             }
 
             fun->setUnlazifiedScript(script);
             return true;
         }
 
         // This is lazy canonical-function.
 
-        MOZ_ASSERT(lazy->scriptSource()->hasSourceData());
-
-        // Parse and compile the script from source.
         size_t lazyLength = lazy->sourceEnd() - lazy->sourceStart();
-        UncompressedSourceCache::AutoHoldEntry holder;
-        ScriptSource::PinnedChars chars(cx, lazy->scriptSource(), holder,
-                                        lazy->sourceStart(), lazyLength);
-        if (!chars.get()) {
-            return false;
-        }
-
-        if (!frontend::CompileLazyFunction(cx, lazy, chars.get(), lazyLength)) {
-            // The frontend shouldn't fail after linking the function and the
-            // non-lazy script together.
-            MOZ_ASSERT(fun->isInterpretedLazy());
-            MOZ_ASSERT(fun->lazyScript() == lazy);
-            MOZ_ASSERT(!lazy->hasScript());
-            return false;
+        if (isBinAST) {
+#if defined(JS_BUILD_BINAST)
+            if (!frontend::CompileLazyBinASTFunction(cx, lazy,
+                    lazy->scriptSource()->binASTSource() + lazy->sourceStart(), lazyLength))
+            {
+                MOZ_ASSERT(fun->isInterpretedLazy());
+                MOZ_ASSERT(fun->lazyScript() == lazy);
+                MOZ_ASSERT(!lazy->hasScript());
+                return false;
+            }
+#else
+            MOZ_CRASH("Trying to delazify BinAST function in non-BinAST build");
+#endif /*JS_BUILD_BINAST */
+        } else {
+            MOZ_ASSERT(lazy->scriptSource()->hasSourceText());
+
+            // Parse and compile the script from source.
+            UncompressedSourceCache::AutoHoldEntry holder;
+            ScriptSource::PinnedChars chars(cx, lazy->scriptSource(), holder,
+                                            lazy->sourceStart(), lazyLength);
+            if (!chars.get())
+                return false;
+
+            if (!frontend::CompileLazyFunction(cx, lazy, chars.get(), lazyLength)) {
+		// The frontend shouldn't fail after linking the function and the
+		// non-lazy script together.
+                MOZ_ASSERT(fun->isInterpretedLazy());
+                MOZ_ASSERT(fun->lazyScript() == lazy);
+                MOZ_ASSERT(!lazy->hasScript());
+                return false;
+            }
         }
 
         script = fun->nonLazyScript();
 
         // Remember the compiled script on the lazy script itself, in case
         // there are clones of the function still pointing to the lazy script.
         if (!lazy->maybeScript()) {
             lazy->initScript(script);
--- a/js/src/vm/JSScript.cpp
+++ b/js/src/vm/JSScript.cpp
@@ -1439,28 +1439,38 @@ JSScript::hasScriptName()
 void
 ScriptSourceObject::finalize(FreeOp* fop, JSObject* obj)
 {
     MOZ_ASSERT(fop->onMainThread());
     ScriptSourceObject* sso = &obj->as<ScriptSourceObject>();
     sso->source()->decref();
 }
 
+void
+ScriptSourceObject::trace(JSTracer* trc, JSObject* obj)
+{
+    // This can be invoked during allocation of the SSO itself, before we've had a chance
+    // to initialize things properly. In that case, there's nothing to trace.
+    if (obj->as<ScriptSourceObject>().hasSource()) {
+        obj->as<ScriptSourceObject>().source()->trace(trc);
+    }
+}
+
 static const ClassOps ScriptSourceObjectClassOps = {
     nullptr, /* addProperty */
     nullptr, /* delProperty */
     nullptr, /* enumerate */
     nullptr, /* newEnumerate */
     nullptr, /* resolve */
     nullptr, /* mayResolve */
     ScriptSourceObject::finalize,
     nullptr, /* call */
     nullptr, /* hasInstance */
     nullptr, /* construct */
-    nullptr  /* trace */
+    ScriptSourceObject::trace
 };
 
 const Class ScriptSourceObject::class_ = {
     "ScriptSource",
     JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS) |
     JSCLASS_IS_ANONYMOUS |
     JSCLASS_FOREGROUND_FINALIZE,
     &ScriptSourceObjectClassOps
@@ -1538,17 +1548,17 @@ ScriptSourceObject::initElementPropertie
     source->setReservedSlot(ELEMENT_PROPERTY_SLOT, nameValue);
 
     return true;
 }
 
 /* static */ bool
 JSScript::loadSource(JSContext* cx, ScriptSource* ss, bool* worked)
 {
-    MOZ_ASSERT(!ss->hasSourceData());
+    MOZ_ASSERT(!ss->hasSourceText());
     *worked = false;
     if (!cx->runtime()->sourceHook.ref() || !ss->sourceRetrievable()) {
         return true;
     }
     char16_t* src = nullptr;
     size_t length;
     if (!cx->runtime()->sourceHook->load(cx, ss->filename(), &src, &length)) {
         return false;
@@ -1562,24 +1572,24 @@ JSScript::loadSource(JSContext* cx, Scri
 
     *worked = true;
     return true;
 }
 
 /* static */ JSFlatString*
 JSScript::sourceData(JSContext* cx, HandleScript script)
 {
-    MOZ_ASSERT(script->scriptSource()->hasSourceData());
+    MOZ_ASSERT(script->scriptSource()->hasSourceText());
     return script->scriptSource()->substring(cx, script->sourceStart(), script->sourceEnd());
 }
 
 bool
 JSScript::appendSourceDataForToString(JSContext* cx, StringBuffer& buf)
 {
-    MOZ_ASSERT(scriptSource()->hasSourceData());
+    MOZ_ASSERT(scriptSource()->hasSourceText());
     return scriptSource()->appendSubstring(cx, buf, toStringStart(), toStringEnd());
 }
 
 UncompressedSourceCache::AutoHoldEntry::AutoHoldEntry()
   : cache_(nullptr), sourceChunk_()
 {
 }
 
@@ -1931,16 +1941,55 @@ ScriptSource::setSource(JSContext* cx, U
     if (!deduped) {
         ReportOutOfMemory(cx);
         return false;
     }
     setSource(std::move(*deduped));
     return true;
 }
 
+#if defined(JS_BUILD_BINAST)
+
+MOZ_MUST_USE bool
+ScriptSource::setBinASTSourceCopy(JSContext* cx, const uint8_t* buf, size_t len)
+{
+    auto &cache = cx->zone()->runtimeFromAnyThread()->sharedImmutableStrings();
+    auto deduped = cache.getOrCreate(reinterpret_cast<const char *>(buf), len);
+    if (!deduped) {
+        ReportOutOfMemory(cx);
+        return false;
+    }
+    MOZ_ASSERT(data.is<Missing>());
+    data = SourceType(BinAST(std::move(*deduped)));
+    return true;
+}
+
+MOZ_MUST_USE bool
+ScriptSource::setBinASTSource(JSContext* cx, UniqueChars&& buf, size_t len)
+{
+    auto& cache = cx->zone()->runtimeFromAnyThread()->sharedImmutableStrings();
+    auto deduped = cache.getOrCreate(std::move(buf), len);
+    if (!deduped) {
+        ReportOutOfMemory(cx);
+        return false;
+    }
+    MOZ_ASSERT(data.is<Missing>());
+    data = SourceType(BinAST(std::move(*deduped)));
+    return true;
+}
+
+const uint8_t*
+ScriptSource::binASTSource()
+{
+    MOZ_ASSERT(hasBinASTSource());
+    return reinterpret_cast<const uint8_t*>(data.as<BinAST>().string.chars());
+}
+
+#endif /* JS_BUILD_BINAST */
+
 void
 ScriptSource::setSource(SharedImmutableTwoByteString&& string)
 {
     MOZ_ASSERT(data.is<Missing>());
     data = SourceType(Uncompressed(std::move(string)));
 }
 
 bool
@@ -2016,17 +2065,17 @@ ScriptSource::setCompressedSource(Shared
     } else {
         data = SourceType(Compressed(std::move(raw), uncompressedLength));
     }
 }
 
 bool
 ScriptSource::setSourceCopy(JSContext* cx, SourceBufferHolder& srcBuf)
 {
-    MOZ_ASSERT(!hasSourceData());
+    MOZ_ASSERT(!hasSourceText());
 
     JSRuntime* runtime = cx->zone()->runtimeFromAnyThread();
     auto& cache = runtime->sharedImmutableStrings();
     auto deduped = cache.getOrCreate(srcBuf.get(), srcBuf.length(), [&]() {
         return srcBuf.ownsChars()
                ? UniqueTwoByteChars(srcBuf.take())
                : DuplicateString(srcBuf.get(), srcBuf.length());
     });
@@ -2034,16 +2083,28 @@ ScriptSource::setSourceCopy(JSContext* c
         ReportOutOfMemory(cx);
         return false;
     }
     setSource(std::move(*deduped));
 
     return true;
 }
 
+void
+ScriptSource::trace(JSTracer* trc)
+{
+#ifdef JS_BUILD_BINAST
+    if (binASTMetadata_) {
+        binASTMetadata_->trace(trc);
+    }
+#else
+    MOZ_ASSERT(!binASTMetadata_);
+#endif // JS_BUILD_BINAST
+}
+
 static MOZ_MUST_USE bool
 reallocUniquePtr(UniqueChars& unique, size_t size)
 {
     auto newPtr = static_cast<char*>(js_realloc(unique.get(), size));
     if (!newPtr) {
         return false;
     }
 
@@ -2234,82 +2295,174 @@ ScriptSource::performXDR(XDRState<mode>*
         size_t match(Uncompressed&) {
             return 0;
         }
 
         size_t match(Compressed& c) {
             return c.raw.length();
         }
 
+        size_t match(BinAST&) {
+            return 0;
+        }
+
         size_t match(Missing&) {
             MOZ_CRASH("Missing source data in ScriptSource::performXDR");
             return 0;
         }
     };
 
     struct RawDataMatcher
     {
         void* match(Uncompressed& u) {
             return (void*) u.string.chars();
         }
 
         void* match(Compressed& c) {
             return (void*) c.raw.chars();
         }
 
+        void* match(BinAST& b) {
+            return (void*) b.string.chars();
+        }
+
         void* match(Missing&) {
             MOZ_CRASH("Missing source data in ScriptSource::performXDR");
             return nullptr;
         }
     };
 
-    uint8_t hasSource = hasSourceData();
+    uint8_t hasSource = hasSourceText();
     MOZ_TRY(xdr->codeUint8(&hasSource));
 
+    uint8_t hasBinSource = hasBinASTSource();
+    MOZ_TRY(xdr->codeUint8(&hasBinSource));
+
     uint8_t retrievable = sourceRetrievable_;
     MOZ_TRY(xdr->codeUint8(&retrievable));
     sourceRetrievable_ = retrievable;
 
-    if (hasSource && !sourceRetrievable_) {
+    if ((hasSource || hasBinSource) && !sourceRetrievable_) {
         uint32_t len = 0;
         if (mode == XDR_ENCODE) {
             len = length();
         }
         MOZ_TRY(xdr->codeUint32(&len));
 
         uint32_t compressedLength;
         if (mode == XDR_ENCODE) {
             CompressedLengthMatcher m;
             compressedLength = data.match(m);
         }
         MOZ_TRY(xdr->codeUint32(&compressedLength));
 
-        size_t byteLen = compressedLength ? compressedLength : (len * sizeof(char16_t));
+        size_t byteLen = hasBinSource ? len : compressedLength ? compressedLength : (len * sizeof(char16_t));
         if (mode == XDR_DECODE) {
             auto bytes = xdr->cx()->template make_pod_array<char>(Max<size_t>(byteLen, 1));
             if (!bytes) {
                 return xdr->fail(JS::TranscodeResult_Throw);
             }
             MOZ_TRY(xdr->codeBytes(bytes.get(), byteLen));
 
-            if (compressedLength) {
+            if (hasBinSource) {
+#if defined(JS_BUILD_BINAST)
+                if (!setBinASTSource(xdr->cx(), std::move(bytes), len)) {
+                    return xdr->fail(JS::TranscodeResult_Throw);
+                }
+#else
+                MOZ_ASSERT(mode != XDR_ENCODE);
+                return xdr->fail(JS::TranscodeResult_Throw);
+#endif /* JS_BUILD_BINAST */
+            } else if (compressedLength) {
                 if (!setCompressedSource(xdr->cx(), std::move(bytes), byteLen, len)) {
                     return xdr->fail(JS::TranscodeResult_Throw);
                 }
             } else {
                 UniqueTwoByteChars source(reinterpret_cast<char16_t*>(bytes.release()));
                 if (!setSource(xdr->cx(), std::move(source), len)) {
                     return xdr->fail(JS::TranscodeResult_Throw);
                 }
             }
         } else {
             RawDataMatcher rdm;
             void* p = data.match(rdm);
             MOZ_TRY(xdr->codeBytes(p, byteLen));
         }
+
+        uint8_t hasMetadata = !!binASTMetadata_;
+        MOZ_TRY(xdr->codeUint8(&hasMetadata));
+        if (hasMetadata) {
+#if defined(JS_BUILD_BINAST)
+            uint32_t numBinKinds;
+            uint32_t numStrings;
+            if (mode == XDR_ENCODE) {
+                numBinKinds = binASTMetadata_->numBinKinds();
+                numStrings = binASTMetadata_->numStrings();
+            }
+            MOZ_TRY(xdr->codeUint32(&numBinKinds));
+            MOZ_TRY(xdr->codeUint32(&numStrings));
+
+            if (mode == XDR_DECODE) {
+                // Use calloc, since we're storing this immediately, and filling it might GC, to
+                // avoid marking bogus atoms.
+                setBinASTSourceMetadata(
+                    static_cast<frontend::BinASTSourceMetadata*>(
+                        js_calloc(frontend::BinASTSourceMetadata::totalSize(numBinKinds, numStrings))));
+                if (!binASTMetadata_) {
+                    return xdr->fail(JS::TranscodeResult_Throw);
+                }
+            }
+
+            for (uint32_t i = 0; i < numBinKinds; i++) {
+                frontend::BinKind* binKindBase = binASTMetadata_->binKindBase();
+                MOZ_TRY(xdr->codeEnum32(&binKindBase[i]));
+            }
+
+            RootedAtom atom(xdr->cx());
+            JSAtom** atomsBase = binASTMetadata_->atomsBase();
+            auto slices = binASTMetadata_->sliceBase();
+            auto sourceBase = reinterpret_cast<const char*>(binASTSource());
+
+            for (uint32_t i = 0; i < numStrings; i++) {
+                uint8_t isNull;
+                if (mode == XDR_ENCODE) {
+                    atom = binASTMetadata_->getAtom(i);
+                    isNull = !atom;
+                }
+                MOZ_TRY(xdr->codeUint8(&isNull));
+                if (isNull) {
+                    atom = nullptr;
+                } else {
+                    MOZ_TRY(XDRAtom(xdr, &atom));
+                }
+                if (mode == XDR_DECODE) {
+                    atomsBase[i] = atom;
+                }
+
+                uint64_t sliceOffset;
+                uint32_t sliceLen;
+                if (mode == XDR_ENCODE) {
+                    auto &slice = binASTMetadata_->getSlice(i);
+                    sliceOffset = slice.begin()-sourceBase;
+                    sliceLen = slice.byteLen_;
+                }
+
+                MOZ_TRY(xdr->codeUint64(&sliceOffset));
+                MOZ_TRY(xdr->codeUint32(&sliceLen));
+
+                if (mode == XDR_DECODE) {
+                    new (&slices[i]) frontend::BinASTSourceMetadata::CharSlice(sourceBase + sliceOffset, sliceLen);
+                }
+            }
+#else
+            // No BinAST, no BinASTMetadata
+            MOZ_ASSERT(mode != XDR_ENCODE);
+            return xdr->fail(JS::TranscodeResult_Throw);
+#endif // JS_BUILD_BINAST
+        }
     }
 
     uint8_t haveSourceMap = hasSourceMapURL();
     MOZ_TRY(xdr->codeUint8(&haveSourceMap));
 
     if (haveSourceMap) {
         uint32_t sourceMapURLLen = (mode == XDR_DECODE) ? 0 : js_strlen(sourceMapURL_.get());
         MOZ_TRY(xdr->codeUint32(&sourceMapURLLen));
@@ -2362,17 +2515,17 @@ ScriptSource::performXDR(XDRState<mode>*
         // 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 xdr->fail(JS::TranscodeResult_Throw);
         }
 
         // Note the content of sources decoded when recording or replaying.
-        if (mode == XDR_DECODE && hasSourceData() && mozilla::recordreplay::IsRecordingOrReplaying()) {
+        if (mode == XDR_DECODE && hasSourceText() && mozilla::recordreplay::IsRecordingOrReplaying()) {
             UncompressedSourceCache::AutoHoldEntry holder;
             ScriptSource::PinnedChars chars(xdr->cx(), this, holder, 0, length());
             if (!chars.get()) {
                 return xdr->fail(JS::TranscodeResult_Throw);
             }
             mozilla::recordreplay::NoteContentParse(this, filename(), "application/javascript",
                                                     chars.get(), length());
         }
@@ -4601,16 +4754,17 @@ LazyScript::Create(JSContext* cx, Handle
     p.isGenerator = false;
     p.strict = false;
     p.bindingsAccessedDynamically = false;
     p.hasDebuggerStatement = false;
     p.hasDirectEval = false;
     p.isLikelyConstructorWrapper = false;
     p.isDerivedClassConstructor = false;
     p.needsHomeObject = false;
+    p.isBinAST = false;
     p.parseGoal = uint32_t(parseGoal);
 
     LazyScript* res = LazyScript::CreateRaw(cx, fun, sourceObject, packedFields,
                                             sourceStart, sourceEnd,
                                             toStringStart, lineno, column);
     if (!res) {
         return nullptr;
     }
--- a/js/src/vm/JSScript.h
+++ b/js/src/vm/JSScript.h
@@ -13,16 +13,17 @@
 #include "mozilla/Atomics.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/Span.h"
 #include "mozilla/Variant.h"
 
 #include "jstypes.h"
 
+#include "frontend/BinSourceRuntimeSupport.h"
 #include "frontend/NameAnalysisTypes.h"
 #include "gc/Barrier.h"
 #include "gc/Rooting.h"
 #include "jit/IonCode.h"
 #include "js/CompileOptions.h"
 #include "js/UbiNode.h"
 #include "js/UniquePtr.h"
 #include "vm/BytecodeUtil.h"
@@ -425,17 +426,25 @@ class ScriptSource
         size_t uncompressedLength;
 
         Compressed(SharedImmutableString&& raw, size_t uncompressedLength)
           : raw(std::move(raw))
           , uncompressedLength(uncompressedLength)
         { }
     };
 
-    using SourceType = mozilla::Variant<Missing, Uncompressed, Compressed>;
+    struct BinAST
+    {
+        SharedImmutableString string;
+        explicit BinAST(SharedImmutableString&& str)
+          : string(std::move(str))
+        { }
+    };
+
+    using SourceType = mozilla::Variant<Missing, Uncompressed, Compressed, BinAST>;
     SourceType data;
 
     // If the GC attempts to call setCompressedSource with PinnedChars
     // present, the first PinnedChars (that is, bottom of the stack) will set
     // the compressed chars upon destruction.
     PinnedChars* pinnedCharsStack_;
     mozilla::Maybe<Compressed> pendingCompressed_;
 
@@ -490,22 +499,24 @@ class ScriptSource
     // if the source hasn't been parsed yet.
     //
     // Used for statistics purposes, to determine how much time code spends
     // syntax parsed before being full parsed, to help determine whether
     // our syntax parse vs. full parse heuristics are correct.
     mozilla::TimeStamp parseEnded_;
 
     // True if we can call JSRuntime::sourceHook to load the source on
-    // demand. If sourceRetrievable_ and hasSourceData() are false, it is not
+    // demand. If sourceRetrievable_ and hasSourceText() are false, it is not
     // possible to get source at all.
     bool sourceRetrievable_:1;
     bool hasIntroductionOffset_:1;
     bool containsAsmJS_:1;
 
+    UniquePtr<frontend::BinASTSourceMetadata> binASTMetadata_;
+
     const char16_t* chunkChars(JSContext* cx, UncompressedSourceCache::AutoHoldEntry& holder,
                                size_t chunk);
 
     // Return a string containing the chars starting at |begin| and ending at
     // |begin + len|.
     //
     // Warning: this is *not* GC-safe! Any chars to be handed out should use
     // PinnedChars. See comment below.
@@ -550,38 +561,52 @@ class ScriptSource
         }
     }
     MOZ_MUST_USE bool initFromOptions(JSContext* cx,
                                       const JS::ReadOnlyCompileOptions& options,
                                       const mozilla::Maybe<uint32_t>& parameterListEnd = mozilla::Nothing());
     MOZ_MUST_USE bool setSourceCopy(JSContext* cx, JS::SourceBufferHolder& srcBuf);
     void setSourceRetrievable() { sourceRetrievable_ = true; }
     bool sourceRetrievable() const { return sourceRetrievable_; }
-    bool hasSourceData() const { return !data.is<Missing>(); }
+    bool hasSourceText() const { return hasUncompressedSource() || hasCompressedSource(); }
+    bool hasBinASTSource() const { return data.is<BinAST>(); }
     bool hasUncompressedSource() const { return data.is<Uncompressed>(); }
     bool hasCompressedSource() const { return data.is<Compressed>(); }
 
+    void setBinASTSourceMetadata(frontend::BinASTSourceMetadata* metadata) {
+        MOZ_ASSERT(hasBinASTSource());
+        binASTMetadata_.reset(metadata);
+    }
+    frontend::BinASTSourceMetadata* binASTSourceMetadata() const {
+        MOZ_ASSERT(hasBinASTSource());
+        return binASTMetadata_.get();
+    }
+
     size_t length() const {
         struct LengthMatcher
         {
             size_t match(const Uncompressed& u) {
                 return u.string.length();
             }
 
             size_t match(const Compressed& c) {
                 return c.uncompressedLength;
             }
 
+            size_t match(const BinAST& b) {
+                return b.string.length();
+            }
+
             size_t match(const Missing& m) {
                 MOZ_CRASH("ScriptSource::length on a missing source");
                 return 0;
             }
         };
 
-        MOZ_ASSERT(hasSourceData());
+        MOZ_ASSERT(hasSourceText() || hasBinASTSource());
         return data.match(LengthMatcher());
     }
 
     JSFlatString* substring(JSContext* cx, size_t start, size_t stop);
     JSFlatString* substringDontDeflate(JSContext* cx, size_t start, size_t stop);
 
     MOZ_MUST_USE bool appendSubstring(JSContext* cx, js::StringBuffer& buf, size_t start, size_t stop);
 
@@ -601,16 +626,35 @@ class ScriptSource
     MOZ_MUST_USE bool tryCompressOffThread(JSContext* cx);
 
     MOZ_MUST_USE bool setCompressedSource(JSContext* cx,
                                           UniqueChars&& raw,
                                           size_t rawLength,
                                           size_t sourceLength);
     void setCompressedSource(SharedImmutableString&& raw, size_t sourceLength);
 
+#if defined(JS_BUILD_BINAST)
+
+    /*
+     * Do not take ownership of the given `buf`. Store the canonical, shared
+     * and de-duplicated version. If there is no extant shared version of
+     * `buf`, make a copy.
+     */
+    MOZ_MUST_USE bool setBinASTSourceCopy(JSContext* cx, const uint8_t* buf, size_t len);
+
+    /*
+     * Take ownership of the given `buf` and return the canonical, shared and
+     * de-duplicated version.
+     */
+    MOZ_MUST_USE bool setBinASTSource(JSContext* cx, UniqueChars&& buf, size_t len);
+
+    const uint8_t* binASTSource();
+
+#endif /* JS_BUILD_BINAST */
+
     // XDR handling
     template <XDRMode mode>
     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();
     }
@@ -686,16 +730,18 @@ class ScriptSource
     const mozilla::TimeStamp parseEnded() const {
         return parseEnded_;
     }
     // Inform `this` source that it has been fully parsed.
     void recordParseEnded() {
         MOZ_ASSERT(parseEnded_.IsNull());
         parseEnded_ = ReallyNow();
     }
+
+    void trace(JSTracer* trc);
 };
 
 class ScriptSourceHolder
 {
     ScriptSource* ss;
   public:
     ScriptSourceHolder()
       : ss(nullptr)
@@ -740,16 +786,19 @@ class ScriptSourceObject : public Native
     // Initialize those properties of this ScriptSourceObject whose values
     // are provided by |options|, re-wrapping as necessary.
     static bool initFromOptions(JSContext* cx, HandleScriptSourceObject source,
                                 const JS::ReadOnlyCompileOptions& options);
 
     static bool initElementProperties(JSContext* cx, HandleScriptSourceObject source,
                                       HandleObject element, HandleString elementAttrName);
 
+    bool hasSource() const {
+        return !getReservedSlot(SOURCE_SLOT).isUndefined();
+    }
     ScriptSource* source() const {
         return static_cast<ScriptSource*>(getReservedSlot(SOURCE_SLOT).toPrivate());
     }
     JSObject* element() const {
         return getReservedSlot(ELEMENT_SLOT).toObjectOrNull();
     }
     const Value& elementAttributeName() const {
         MOZ_ASSERT(!getReservedSlot(ELEMENT_PROPERTY_SLOT).isMagic());
@@ -2305,16 +2354,17 @@ class LazyScript : public gc::TenuredCel
   private:
     static const uint32_t NumClosedOverBindingsBits = 20;
     static const uint32_t NumInnerFunctionsBits = 20;
 
     struct PackedView {
         uint32_t shouldDeclareArguments : 1;
         uint32_t hasThisBinding : 1;
         uint32_t isAsync : 1;
+        uint32_t isBinAST : 1;
 
         uint32_t numClosedOverBindings : NumClosedOverBindingsBits;
 
         // -- 32bit boundary --
 
         uint32_t numInnerFunctions : NumInnerFunctionsBits;
 
         // N.B. These are booleans but need to be uint32_t to pack correctly on MSVC.
@@ -2493,16 +2543,23 @@ class LazyScript : public gc::TenuredCel
     void setHasRest() {
         p_.hasRest = true;
     }
 
     frontend::ParseGoal parseGoal() const {
         return frontend::ParseGoal(p_.parseGoal);
     }
 
+    bool isBinAST() const {
+        return p_.isBinAST;
+    }
+    void setIsBinAST() {
+        p_.isBinAST = true;
+    }
+
     bool strict() const {
         return p_.strict;
     }
     void setStrict() {
         p_.strict = true;
     }
 
     bool bindingsAccessedDynamically() const {
--- a/js/src/vm/OffThreadScriptCompilation.cpp
+++ b/js/src/vm/OffThreadScriptCompilation.cpp
@@ -32,21 +32,16 @@ enum class OffThread
 static bool
 CanDoOffThread(JSContext* cx, const ReadOnlyCompileOptions& options, size_t length, OffThread what)
 {
     static const size_t TINY_LENGTH = 5 * 1000;
     static const size_t HUGE_SRC_LENGTH = 100 * 1000;
     static const size_t HUGE_BC_LENGTH = 367 * 1000;
     static const size_t HUGE_BINAST_LENGTH = 70 * 1000;
 
-    // TODO: We can't decode BinAST off main thread until bug 1459555 is fixed.
-    if (what == OffThread::DecodeBinAST) {
-        return false;
-    }
-
     // These are heuristics which the caller may choose to ignore (e.g., for
     // testing purposes).
     if (!options.forceAsync) {
         // Compiling off the main thread inolves creating a new Zone and other
         // significant overheads.  Don't bother if the script is tiny.
         if (length < TINY_LENGTH) {
             return false;
         }
--- a/js/src/wasm/AsmJS.cpp
+++ b/js/src/wasm/AsmJS.cpp
@@ -6677,17 +6677,17 @@ HandleInstantiationFailure(JSContext* cx
     if (cx->isExceptionPending()) {
         return false;
     }
 
     ScriptSource* source = metadata.scriptSource.get();
 
     // Source discarding is allowed to affect JS semantics because it is never
     // enabled for normal JS content.
-    bool haveSource = source->hasSourceData();
+    bool haveSource = source->hasSourceText();
     if (!haveSource && !JSScript::loadSource(cx, source, &haveSource)) {
         return false;
     }
     if (!haveSource) {
         JS_ReportErrorASCII(cx, "asm.js link failure with source discarding enabled");
         return false;
     }
 
@@ -7613,17 +7613,17 @@ js::AsmJSModuleToString(JSContext* cx, H
     ScriptSource* source = metadata.scriptSource.get();
 
     StringBuffer out(cx);
 
     if (isToSource && fun->isLambda() && !out.append("(")) {
         return nullptr;
     }
 
-    bool haveSource = source->hasSourceData();
+    bool haveSource = source->hasSourceText();
     if (!haveSource && !JSScript::loadSource(cx, source, &haveSource)) {
         return nullptr;
     }
 
     if (!haveSource) {
         if (!out.append("function ")) {
             return nullptr;
         }
@@ -7664,17 +7664,17 @@ js::AsmJSFunctionToString(JSContext* cx,
 
     ScriptSource* source = metadata.scriptSource.get();
     StringBuffer out(cx);
 
     if (!out.append("function ")) {
         return nullptr;
     }
 
-    bool haveSource = source->hasSourceData();
+    bool haveSource = source->hasSourceText();
     if (!haveSource && !JSScript::loadSource(cx, source, &haveSource)) {
         return nullptr;
     }
 
     if (!haveSource) {
         // asm.js functions can't be anonymous
         MOZ_ASSERT(fun->explicitName());
         if (!out.append(fun->explicitName())) {
--- a/js/src/wasm/cranelift/build.rs
+++ b/js/src/wasm/cranelift/build.rs
@@ -70,20 +70,26 @@ fn main() {
                 Arch::Aarch64 => { bindings.clang_arg("--target=aarch64-linux-android") }
                 Arch::Arm => { bindings.clang_arg("--target=armv7-linux-androideabi") }
                 Arch::X86 => { bindings.clang_arg("--target=i686-linux-android") }
                 Arch::X64 => { bindings.clang_arg("--target=x86_64-linux-android") }
             };
         }
 
         Ok("linux") | Ok("freebsd") | Ok("dragonfly") | Ok("openbsd") | Ok("bitrig") | Ok("netbsd")
-            | Ok("macos") | Ok("ios") => {
+            | Ok("ios") => {
             // Nothing to do in particular for these OSes, until proven the contrary.
         }
 
+        Ok("macos") => {
+            bindings = bindings.clang_arg("-DOS_MACOSX=1");
+            bindings = bindings.clang_arg("-stdlib=libc++");
+            bindings = bindings.clang_arg("--target=x86_64-apple-darwin");
+        }
+
         Ok("windows") => {
             let arch = arch.expect("unknown Windows architecture");
             bindings = bindings.clang_arg("-DOS_WIN=1")
                 .clang_arg("-DWIN32=1");
             bindings = match env::var("CARGO_CFG_TARGET_ENV").as_ref().map(|x| x.as_str()) {
                 Ok("msvc") => {
                     bindings = bindings.clang_arg("-fms-compatibility-version=19");
                     bindings = bindings.clang_arg("-D_CRT_USE_BUILTIN_OFFSETOF");
--- a/js/xpconnect/src/XPCConvert.cpp
+++ b/js/xpconnect/src/XPCConvert.cpp
@@ -200,19 +200,16 @@ XPCConvert::NativeData2JS(MutableHandleV
             return false;
         }
 
         d.setObject(*obj);
         return true;
     }
 
     case nsXPTType::T_ASTRING:
-        // Fall through to T_DOMSTRING case
-
-    case nsXPTType::T_DOMSTRING:
     {
         const nsAString* p = static_cast<const nsAString*>(s);
         if (!p || p->IsVoid()) {
             d.setNull();
             return true;
         }
 
         nsStringBuffer* buf;
@@ -603,47 +600,34 @@ XPCConvert::JSData2Native(JSContext* cx,
             return false;
         }
         *((const nsID**)d) = pid->Clone();
         return true;
     }
 
     case nsXPTType::T_ASTRING:
     {
-        if (s.isUndefined()) {
-            ((nsAString*)d)->SetIsVoid(true);
-            return true;
-        }
-        MOZ_FALLTHROUGH;
-    }
-    case nsXPTType::T_DOMSTRING:
-    {
         nsAString* ws = (nsAString*)d;
-        if (s.isNull()) {
+        if (s.isUndefined() || s.isNull()) {
             ws->SetIsVoid(true);
             return true;
         }
         size_t length = 0;
-        JSString* str = nullptr;
-        if (!s.isUndefined()) {
-            str = ToString(cx, s);
-            if (!str) {
-                return false;
-            }
-
-            length = JS_GetStringLength(str);
-            if (!length) {
-                ws->Truncate();
-                return true;
-            }
+        JSString* str = ToString(cx, s);
+        if (!str) {
+            return false;
         }
 
-        if (!str) {
-            ws->AssignLiteral(u"undefined");
-        } else if (XPCStringConvert::IsDOMString(str)) {
+        length = JS_GetStringLength(str);
+        if (!length) {
+            ws->Truncate();
+            return true;
+        }
+
+        if (XPCStringConvert::IsDOMString(str)) {
             // The characters represent an existing nsStringBuffer that
             // was shared by XPCStringConvert::ReadableToJSVal.
             const char16_t* chars = JS_GetTwoByteExternalStringChars(str);
             if (chars[length] == '\0') {
                 // Safe to share the buffer.
                 nsStringBuffer::FromData((void*)chars)->ToString(length, *ws);
             } else {
                 // We have to copy to ensure null-termination.
@@ -1680,17 +1664,16 @@ xpc::InnerCleanupValue(const nsXPTType& 
             break;
 
         case nsXPTType::T_INTERFACE:
         case nsXPTType::T_INTERFACE_IS:
             (*(nsISupports**)aValue)->Release();
             break;
 
         // String types
-        case nsXPTType::T_DOMSTRING:
         case nsXPTType::T_ASTRING:
             ((nsAString*)aValue)->Truncate();
             break;
         case nsXPTType::T_UTF8STRING:
         case nsXPTType::T_CSTRING:
             ((nsACString*)aValue)->Truncate();
             break;
 
--- a/js/xpconnect/src/XPCVariant.cpp
+++ b/js/xpconnect/src/XPCVariant.cpp
@@ -493,24 +493,16 @@ XPCVariant::VariantDataToJS(nsIVariant* 
         case nsIDataType::VTYPE_ASTRING:
         {
             nsAutoString astring;
             if (NS_FAILED(variant->GetAsAString(astring))) {
                 return false;
             }
             return XPCConvert::NativeData2JS(pJSVal, &astring, { TD_ASTRING }, &iid, 0, pErr);
         }
-        case nsIDataType::VTYPE_DOMSTRING:
-        {
-            nsAutoString astring;
-            if (NS_FAILED(variant->GetAsAString(astring))) {
-                return false;
-            }
-            return XPCConvert::NativeData2JS(pJSVal, &astring, { TD_DOMSTRING }, &iid, 0, pErr);
-        }
         case nsIDataType::VTYPE_CSTRING:
         {
             nsAutoCString cString;
             if (NS_FAILED(variant->GetAsACString(cString))) {
                 return false;
             }
             return XPCConvert::NativeData2JS(pJSVal, &cString, { TD_CSTRING }, &iid, 0, pErr);
         }
@@ -666,17 +658,16 @@ XPCVariant::VariantDataToJS(nsIVariant* 
                 case nsIDataType::VTYPE_INTERFACE_IS:
                     pid = &du.u.array.mArrayInterfaceID;
                     xptIndex = nsXPTType::Idx::INTERFACE_IS_TYPE;
                     break;
 
                 // The rest are illegal.
                 case nsIDataType::VTYPE_VOID:
                 case nsIDataType::VTYPE_ASTRING:
-                case nsIDataType::VTYPE_DOMSTRING:
                 case nsIDataType::VTYPE_CSTRING:
                 case nsIDataType::VTYPE_UTF8STRING:
                 case nsIDataType::VTYPE_WSTRING_SIZE_IS:
                 case nsIDataType::VTYPE_STRING_SIZE_IS:
                 case nsIDataType::VTYPE_ARRAY:
                 case nsIDataType::VTYPE_EMPTY_ARRAY:
                 case nsIDataType::VTYPE_EMPTY:
                 default:
@@ -794,23 +785,16 @@ NS_IMETHODIMP_(nsresult) XPCVariant::Get
     return mData.ConvertToID(retval);
 }
 
 NS_IMETHODIMP XPCVariant::GetAsAString(nsAString & _retval)
 {
     return mData.ConvertToAString(_retval);
 }
 
-NS_IMETHODIMP XPCVariant::GetAsDOMString(nsAString & _retval)
-{
-    // A DOMString maps to an AString internally, so we can re-use
-    // ConvertToAString here.
-    return mData.ConvertToAString(_retval);
-}
-
 NS_IMETHODIMP XPCVariant::GetAsACString(nsACString & _retval)
 {
     return mData.ConvertToACString(_retval);
 }
 
 NS_IMETHODIMP XPCVariant::GetAsAUTF8String(nsAUTF8String & _retval)
 {
     return mData.ConvertToAUTF8String(_retval);
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -3207,17 +3207,17 @@ nsresult HasInstance(JSContext* cx, JS::
 nsIPrincipal* GetObjectPrincipal(JSObject* obj);
 
 // Attempt to clean up the passed in value pointer. The pointer `value` must be
 // a pointer to a value described by the type `nsXPTType`.
 //
 // This method expects a value of the following types:
 //   TD_PNSIID
 //     value : nsID* (free)
-//   TD_DOMSTRING, TD_ASTRING, TD_CSTRING, TD_UTF8STRING
+//   TD_ASTRING, TD_CSTRING, TD_UTF8STRING
 //     value : ns[C]String* (truncate)
 //   TD_PSTRING, TD_PWSTRING, TD_PSTRING_SIZE_IS, TD_PWSTRING_SIZE_IS
 //     value : char[16_t]** (free)
 //   TD_INTERFACE_TYPE, TD_INTERFACE_IS_TYPE
 //     value : nsISupports** (release)
 //   TD_LEGACY_ARRAY (NOTE: aArrayLen should be passed)
 //     value : void** (destroy elements & free)
 //   TD_ARRAY
--- a/js/xpconnect/src/xpcpublic.h
+++ b/js/xpconnect/src/xpcpublic.h
@@ -348,17 +348,17 @@ bool Base64Decode(JSContext* cx, JS::Han
 /**
  * Convert an nsString to jsval, returning true on success.
  * Note, the ownership of the string buffer may be moved from str to rval.
  * If that happens, str will point to an empty string after this call.
  */
 bool NonVoidStringToJsval(JSContext* cx, nsAString& str, JS::MutableHandleValue rval);
 inline bool StringToJsval(JSContext* cx, nsAString& str, JS::MutableHandleValue rval)
 {
-    // From the T_DOMSTRING case in XPCConvert::NativeData2JS.
+    // From the T_ASTRING case in XPCConvert::NativeData2JS.
     if (str.IsVoid()) {
         rval.setNull();
         return true;
     }
     return NonVoidStringToJsval(cx, str, rval);
 }
 
 inline bool
--- a/js/xpconnect/tests/components/js/xpctest_params.js
+++ b/js/xpconnect/tests/components/js/xpctest_params.js
@@ -54,17 +54,16 @@ TestParams.prototype = {
   testUnsignedLong: f,
   testUnsignedLongLong: f,
   testFloat: f,
   testDouble: f,
   testChar: f,
   testString: f,
   testWchar: f,
   testWstring: f,
-  testDOMString: f,
   testAString: f,
   testAUTF8String: f,
   testACString: f,
   testJsval: f,
   testShortSequence: f,
   testDoubleSequence: f,
   testAStringSequence: f,
   testACStringSequence: f,
--- a/js/xpconnect/tests/components/native/xpctest_params.cpp
+++ b/js/xpconnect/tests/components/native/xpctest_params.cpp
@@ -157,22 +157,16 @@ NS_IMETHODIMP nsXPCTestParams::TestWstri
 
     // XPCOM ownership rules dictate that overwritten inout params must be callee-freed.
     // See https://developer.mozilla.org/en/XPIDL
     free((void*)bprime.get());
 
     return NS_OK;
 }
 
-NS_IMETHODIMP nsXPCTestParams::TestDOMString(const nsAString & a, nsAString & b, nsAString & _retval)
-{
-    STRING_METHOD_IMPL;
-}
-
-
 NS_IMETHODIMP nsXPCTestParams::TestAString(const nsAString & a, nsAString & b, nsAString & _retval)
 {
     STRING_METHOD_IMPL;
 }
 
 NS_IMETHODIMP nsXPCTestParams::TestAUTF8String(const nsACString & a, nsACString & b, nsACString & _retval)
 {
     STRING_METHOD_IMPL;
--- a/js/xpconnect/tests/idl/xpctest_params.idl
+++ b/js/xpconnect/tests/idl/xpctest_params.idl
@@ -28,17 +28,16 @@ interface nsIXPCTestParams : nsISupports
   unsigned long         testUnsignedLong(in unsigned long a, inout unsigned long b);
   unsigned long long    testUnsignedLongLong(in unsigned long long a, inout unsigned long long b);
   float                 testFloat(in float a, inout float b);
   double                testDouble(in double a, inout float b);
   char                  testChar(in char a, inout char b);
   string                testString(in string a, inout string b);
   wchar                 testWchar(in wchar a, inout wchar b);
   wstring               testWstring(in wstring a, inout wstring b);
-  DOMString             testDOMString(in DOMString a, inout DOMString b);
   AString               testAString(in AString a, inout AString b);
   AUTF8String           testAUTF8String(in AUTF8String a, inout AUTF8String b);
   ACString              testACString(in ACString a, inout ACString b);
   jsval                 testJsval(in jsval a, inout jsval b);
 
   // Test various forms of the Array<T> type.
   Array<short>          testShortSequence(in Array<short> a, inout Array<short> b);
   Array<double>         testDoubleSequence(in Array<double> a, inout Array<double> b);
--- a/js/xpconnect/tests/unit/test_params.js
+++ b/js/xpconnect/tests/unit/test_params.js
@@ -119,17 +119,16 @@ function test_component(contractid) {
   doTest("testUnsignedLong", 0, 4000000000);
   doTest("testUnsignedLongLong", 215435, 3453492580348535809);
   doTest("testFloat", 4.9, -11.2, fuzzComparator);
   doTest("testDouble", -80.5, 15000.2, fuzzComparator);
   doTest("testChar", "a", "2");
   doTest("testString", "someString", "another string");
   doTest("testWstring", "Why wasnt this", "turned on before? ಠ_ಠ");
   doTest("testWchar", "z", "ア");
-  doTestWorkaround("testDOMString", "Beware: ☠ s");
   doTestWorkaround("testAString", "Frosty the ☃ ;-)");
   doTestWorkaround("testAUTF8String", "We deliver 〠!");
   doTestWorkaround("testACString", "Just a regular C string.");
   doTest("testJsval", {aprop: 12, bprop: "str"}, 4.22);
 
   // Test out dipper parameters, since they're special and we can't really test
   // inouts.
   let outAString = {};
--- a/layout/generic/nsBulletFrame.cpp
+++ b/layout/generic/nsBulletFrame.cpp
@@ -1181,17 +1181,18 @@ nsBulletFrame::Notify(imgIRequest *aRequ
       // Retrieve the intrinsic size of the image.
       int32_t width = 0;
       int32_t height = 0;
       container->GetWidth(&width);
       container->GetHeight(&height);
 
       // Request a decode at that size.
       container->RequestDecodeForSize(IntSize(width, height),
-                                      imgIContainer::DECODE_FLAGS_DEFAULT);
+                                      imgIContainer::DECODE_FLAGS_DEFAULT |
+                                      imgIContainer::FLAG_HIGH_QUALITY_SCALING);
     }
 
     InvalidateFrame();
   }
 
   if (aType == imgINotificationObserver::DECODE_COMPLETE) {
     if (nsIDocument* parent = GetOurCurrentDoc()) {
       nsCOMPtr<imgIContainer> container;
--- a/layout/generic/nsImageFrame.cpp
+++ b/layout/generic/nsImageFrame.cpp
@@ -2553,17 +2553,18 @@ nsImageFrame::IconLoad::Notify(imgIReque
     // Retrieve the image's intrinsic size.
     int32_t width = 0;
     int32_t height = 0;
     image->GetWidth(&width);
     image->GetHeight(&height);
 
     // Request a decode at that size.
     image->RequestDecodeForSize(IntSize(width, height),
-                                imgIContainer::DECODE_FLAGS_DEFAULT);
+                                imgIContainer::DECODE_FLAGS_DEFAULT |
+                                imgIContainer::FLAG_HIGH_QUALITY_SCALING);
   }
 
   nsTObserverArray<nsImageFrame*>::ForwardIterator iter(mIconObservers);
   nsImageFrame *frame;
   while (iter.HasMore()) {
     frame = iter.GetNext();
     frame->InvalidateFrame();
   }
--- a/netwerk/base/nsIPermissionManager.idl
+++ b/netwerk/base/nsIPermissionManager.idl
@@ -287,17 +287,17 @@ interface nsIPermissionManager : nsISupp
    * @return an nsISimpleEnumerator interface that allows access to
    *         nsIPermission objects
    */
   readonly attribute nsISimpleEnumerator enumerator;
 
   /**
    * Remove all permissions that will match the origin pattern.
    */
-  void removePermissionsWithAttributes(in DOMString patternAsJSON);
+  void removePermissionsWithAttributes(in AString patternAsJSON);
 
   /**
    * If the current permission is set to expire, reset the expiration time. If
    * there is no permission or the current permission does not expire, this
    * method will silently return.
    *
    * @param sessionExpiretime  an integer representation of when this permission
    *                           should be forgotten (milliseconds since
--- a/netwerk/cookie/nsICookieManager.idl
+++ b/netwerk/cookie/nsICookieManager.idl
@@ -223,19 +223,19 @@ interface nsICookieManager : nsISupports
    * @param aPattern origin attribute pattern in JSON format
    *
    * @param aHost
    *        the host string to search for, e.g. "google.com". this should consist
    *        of only the host portion of a URI. see @add for a description of
    *        acceptable host strings. This attribute is optional. It will search
    *        all hosts if this attribute is not given.
    */
-  nsISimpleEnumerator getCookiesWithOriginAttributes(in DOMString aPattern,
+  nsISimpleEnumerator getCookiesWithOriginAttributes(in AString aPattern,
                                                      [optional] in AUTF8String aHost);
 
   /**
    * Remove all the cookies whose origin attributes matches aPattern
    *
    * @param aPattern origin attribute pattern in JSON format
    */
-  void removeCookiesWithOriginAttributes(in DOMString aPattern,
+  void removeCookiesWithOriginAttributes(in AString aPattern,
                                          [optional] in AUTF8String aHost);
 };
--- a/old-configure.in
+++ b/old-configure.in
@@ -1768,17 +1768,17 @@ dnl = If NSS was not detected in the sys
 dnl = use the one in the source tree (mozilla/security/nss)
 dnl ========================================================
 
 MOZ_ARG_WITH_BOOL(system-nss,
 [  --with-system-nss       Use system installed NSS],
     _USE_SYSTEM_NSS=1 )
 
 if test -n "$_USE_SYSTEM_NSS"; then
-    AM_PATH_NSS(3.39, [MOZ_SYSTEM_NSS=1], [AC_MSG_ERROR([you don't have NSS installed or your version is too old])])
+    AM_PATH_NSS(3.40, [MOZ_SYSTEM_NSS=1], [AC_MSG_ERROR([you don't have NSS installed or your version is too old])])
 fi
 
 if test -z "$MOZ_SYSTEM_NSS"; then
    NSS_CFLAGS="-I${DIST}/include/nss"
    case "${OS_ARCH}" in
         # Only few platforms have been tested with GYP
         WINNT|Darwin|Linux|DragonFly|FreeBSD|NetBSD|OpenBSD|SunOS)
             ;;
--- a/services/fxaccounts/interfaces/nsIFxAccountsUIGlue.idl
+++ b/services/fxaccounts/interfaces/nsIFxAccountsUIGlue.idl
@@ -6,10 +6,10 @@
 
 [scriptable, uuid(ab8d0700-9577-11e3-a5e2-0800200c9a66)]
 interface nsIFxAccountsUIGlue : nsISupports
 {
   // Returns a Promise.
   jsval signInFlow();
 
   // Returns a Promise.
-  jsval refreshAuthentication(in DOMString email);
+  jsval refreshAuthentication(in AString email);
 };
--- a/storage/Variant_inl.h
+++ b/storage/Variant_inl.h
@@ -156,23 +156,16 @@ inline
 NS_IMETHODIMP
 Variant_base::GetAsID(nsID *)
 {
   return NS_ERROR_CANNOT_CONVERT_DATA;
 }
 
 inline
 NS_IMETHODIMP
-Variant_base::GetAsDOMString(nsAString &)
-{
-  return NS_ERROR_CANNOT_CONVERT_DATA;
-}
-
-inline
-NS_IMETHODIMP
 Variant_base::GetAsString(char **)
 {
   return NS_ERROR_CANNOT_CONVERT_DATA;
 }
 
 inline
 NS_IMETHODIMP
 Variant_base::GetAsWString(char16_t **)
--- a/storage/mozStoragePrivateHelpers.cpp
+++ b/storage/mozStoragePrivateHelpers.cpp
@@ -203,17 +203,16 @@ convertVariantToStorageVariant(nsIVarian
     case nsIDataType::VTYPE_UTF8STRING:
     case nsIDataType::VTYPE_CSTRING: {
       nsCString v;
       rv = aVariant->GetAsAUTF8String(v);
       NS_ENSURE_SUCCESS(rv, nullptr);
       return new UTF8TextVariant(v);
     }
     case nsIDataType::VTYPE_WCHAR:
-    case nsIDataType::VTYPE_DOMSTRING:
     case nsIDataType::VTYPE_WCHAR_STR:
     case nsIDataType::VTYPE_WSTRING_SIZE_IS:
     case nsIDataType::VTYPE_ASTRING: {
       nsString v;
       rv = aVariant->GetAsAString(v);
       NS_ENSURE_SUCCESS(rv, nullptr);
       return new TextVariant(v);
     }
--- a/storage/variantToSQLiteT_impl.h
+++ b/storage/variantToSQLiteT_impl.h
@@ -70,17 +70,16 @@ variantToSQLiteT(T aObj,
       // GetAsAUTF8String should never perform conversion when coming from
       // 8-bit string types, and thus can accept strings with arbitrary encoding
       // (including UTF8 and ASCII).
       nsresult rv = aValue->GetAsAUTF8String(value);
       NS_ENSURE_SUCCESS(rv, SQLITE_MISMATCH);
       return sqlite3_T_text(aObj, value);
     }
     case nsIDataType::VTYPE_WCHAR:
-    case nsIDataType::VTYPE_DOMSTRING:
     case nsIDataType::VTYPE_WCHAR_STR:
     case nsIDataType::VTYPE_WSTRING_SIZE_IS:
     case nsIDataType::VTYPE_ASTRING:
     {
       nsAutoString value;
       // GetAsAString does proper conversion to UCS2 from all string-like types.
       // It can be used universally without problems (unless someone implements
       // their own variant, but that's their problem).
--- a/testing/web-platform/meta/encrypted-media/__dir__.ini
+++ b/testing/web-platform/meta/encrypted-media/__dir__.ini
@@ -1,1 +1,2 @@
+prefs: [dom.security.featurePolicy.enabled:true]
 lsan-allowed: [Alloc, MakeUnique, Malloc, NewPage, Realloc, mozilla::EMEDecryptor::EMEDecryptor, mozilla::SchedulerGroup::CreateEventTargetFor, CreateCDMProxy, mozilla::dom::MediaKeys::CreateCDMProxy, mozilla::dom::nsIContentChild::GetConstructedEventTarget]
deleted file mode 100644
--- a/testing/web-platform/meta/encrypted-media/clearkey-mp4-unique-origin.https.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[clearkey-mp4-unique-origin.https.html]
-  [Unique origin is unable to create MediaKeys]
-    expected: FAIL
-
--- a/testing/web-platform/meta/encrypted-media/encrypted-media-default-feature-policy.https.sub.html.ini
+++ b/testing/web-platform/meta/encrypted-media/encrypted-media-default-feature-policy.https.sub.html.ini
@@ -1,11 +1,8 @@
 [encrypted-media-default-feature-policy.https.sub.html]
   expected: TIMEOUT
   [Default "encrypted-media" feature policy ["self"\] allows same-origin iframes.]
     expected: TIMEOUT
 
-  [Default "encrypted-media" feature policy ["self"\] disallows cross-origin iframes.]
-    expected: FAIL
-
   [Feature policy "encrypted-media" can be enabled in cross-origin iframes using "allow" attribute.]
     expected: FAIL
 
--- a/testing/web-platform/tests/tools/wptrunner/wptrunner/wpttest.py
+++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/wpttest.py
@@ -66,19 +66,20 @@ def get_run_info(metadata_root, product,
     return RunInfo(metadata_root, product, **kwargs)
 
 
 class RunInfo(dict):
     def __init__(self, metadata_root, product, debug,
                  browser_version=None,
                  browser_channel=None,
                  verify=None,
-                 extras=None):
+                 extras=None,
+                 raise_exception=True):
         import mozinfo
-        self._update_mozinfo(metadata_root)
+        self._update_mozinfo(metadata_root, raise_exception=raise_exception)
         self.update(mozinfo.info)
 
         from update.tree import GitTree
         try:
             # GitTree.__init__ throws if we are not in a git tree.
             rev = GitTree(log_error=False).rev
         except (OSError, subprocess.CalledProcessError):
             rev = None
@@ -97,30 +98,30 @@ class RunInfo(dict):
             self["browser_channel"] = browser_channel
 
         self["verify"] = verify
         if "wasm" not in self:
             self["wasm"] = False
         if extras is not None:
             self.update(extras)
 
-    def _update_mozinfo(self, metadata_root):
+    def _update_mozinfo(self, metadata_root, **kwargs):
         """Add extra build information from a mozinfo.json file in a parent
         directory"""
         import mozinfo
 
         path = metadata_root
         dirs = set()
         while path != os.path.expanduser('~'):
             if path in dirs:
                 break
             dirs.add(str(path))
             path = os.path.split(path)[0]
 
-        mozinfo.find_and_update_from_json(*dirs)
+        mozinfo.find_and_update_from_json(*dirs, **kwargs)
 
 
 class Test(object):
 
     result_cls = None
     subtest_result_cls = None
     test_type = None
 
--- a/toolkit/components/alerts/AlertNotification.cpp
+++ b/toolkit/components/alerts/AlertNotification.cpp
@@ -246,17 +246,18 @@ AlertImageRequest::Notify(imgIRequest* a
       if (NS_WARN_IF(NS_FAILED(rv) || !image)) {
         return NotifyMissing();
       }
 
       // Ask the image to decode at its intrinsic size.
       int32_t width = 0, height = 0;
       image->GetWidth(&width);
       image->GetHeight(&height);
-      image->RequestDecodeForSize(gfx::IntSize(width, height), imgIContainer::FLAG_NONE);
+      image->RequestDecodeForSize(gfx::IntSize(width, height),
+                                  imgIContainer::FLAG_HIGH_QUALITY_SCALING);
     }
     return NS_OK;
   }
 
   if (aType == imgINotificationObserver::FRAME_COMPLETE) {
     return NotifyComplete();
   }
 
--- a/toolkit/components/places/nsAnnotationService.cpp
+++ b/toolkit/components/places/nsAnnotationService.cpp
@@ -187,17 +187,16 @@ nsAnnotationService::SetItemAnnotation(i
       NS_ENSURE_SUCCESS(rv, rv);
       rv = SetAnnotationDoubleInternal(aItemId, &bookmark,
                                        aName, valueDouble, aFlags, aExpiration);
       NS_ENSURE_SUCCESS(rv, rv);
       break;
     }
     case nsIDataType::VTYPE_CHAR:
     case nsIDataType::VTYPE_WCHAR:
-    case nsIDataType::VTYPE_DOMSTRING:
     case nsIDataType::VTYPE_CHAR_STR:
     case nsIDataType::VTYPE_WCHAR_STR:
     case nsIDataType::VTYPE_STRING_SIZE_IS:
     case nsIDataType::VTYPE_WSTRING_SIZE_IS:
     case nsIDataType::VTYPE_UTF8STRING:
     case nsIDataType::VTYPE_CSTRING:
     case nsIDataType::VTYPE_ASTRING: {
       nsAutoString stringValue;
--- a/toolkit/components/telemetry/core/TelemetryScalar.cpp
+++ b/toolkit/components/telemetry/core/TelemetryScalar.cpp
@@ -527,17 +527,16 @@ private:
 ScalarResult
 ScalarString::SetValue(nsIVariant* aValue)
 {
   // Check that we got the correct data type.
   uint16_t type;
   aValue->GetDataType(&type);
   if (type != nsIDataType::VTYPE_CHAR &&
       type != nsIDataType::VTYPE_WCHAR &&
-      type != nsIDataType::VTYPE_DOMSTRING &&
       type != nsIDataType::VTYPE_CHAR_STR &&
       type != nsIDataType::VTYPE_WCHAR_STR &&
       type != nsIDataType::VTYPE_STRING_SIZE_IS &&
       type != nsIDataType::VTYPE_WSTRING_SIZE_IS &&
       type != nsIDataType::VTYPE_UTF8STRING &&
       type != nsIDataType::VTYPE_CSTRING &&
       type != nsIDataType::VTYPE_ASTRING) {
     return ScalarResult::InvalidType;
--- a/toolkit/content/widgets/text.xml
+++ b/toolkit/content/widgets/text.xml
@@ -4,46 +4,17 @@
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 
 <bindings id="textBindings"
    xmlns="http://www.mozilla.org/xbl"
    xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
    xmlns:html="http://www.w3.org/1999/xhtml">
 
-  <binding id="text-label">
-    <implementation>
-      <property name="accessKey">
-        <getter>
-          <![CDATA[
-            var accessKey = this.getAttribute("accesskey");
-            return accessKey ? accessKey[0] : null;
-          ]]>
-        </getter>
-        <setter>
-          <![CDATA[
-            this.setAttribute("accesskey", val);
-            return val;
-          ]]>
-        </setter>
-      </property>
-
-      <property name="control" onget="return getAttribute('control');">
-        <setter>
-          <![CDATA[
-            // After this gets set, the label will use the binding #label-control
-            this.setAttribute("control", val);
-            return val;
-          ]]>
-        </setter>
-      </property>
-    </implementation>
-  </binding>
-
-  <binding id="label-control" extends="chrome://global/content/bindings/text.xml#text-label">
+  <binding id="label-control">
     <content>
       <children/><html:span anonid="accessKeyParens"></html:span>
     </content>
     <implementation>
       <constructor>
         <![CDATA[
           this.formatAccessKey(true);
         ]]>
@@ -281,17 +252,17 @@
           controlElement.checked = !controlElement.checked;
         } else if (controlElement.localName == "radio") {
           controlElement.control.selectedItem = controlElement;
         }
       ]]></handler>
     </handlers>
   </binding>
 
-  <binding id="text-link" extends="chrome://global/content/bindings/text.xml#text-label">
+  <binding id="text-link">
     <implementation>
       <property name="href" onget="return this.getAttribute('href');"
                             onset="this.setAttribute('href', val); return val;" />
       <method name="open">
         <parameter name="aEvent"/>
         <body>
         <![CDATA[
           var href = this.href;
--- a/toolkit/content/xul.css
+++ b/toolkit/content/xul.css
@@ -95,20 +95,16 @@ page {
 /******** box *******/
 
 vbox {
   -moz-box-orient: vertical;
 }
 
 /********** label **********/
 
-label {
-  -moz-binding: url("chrome://global/content/bindings/text.xml#text-label");
-}
-
 label.text-link, label[onclick] {
   -moz-binding: url("chrome://global/content/bindings/text.xml#text-link");
   -moz-user-focus: normal;
 }
 
 label[control], label.radio-label, label.checkbox-label, label.toolbarbutton-multiline-text {
   -moz-binding: url("chrome://global/content/bindings/text.xml#label-control");
 }
--- a/widget/cocoa/nsMenuItemIconX.mm
+++ b/widget/cocoa/nsMenuItemIconX.mm
@@ -284,17 +284,18 @@ nsMenuItemIconX::Notify(imgIRequest* aRe
     nsCOMPtr<imgIContainer> image;
     aRequest->GetImage(getter_AddRefs(image));
     MOZ_ASSERT(image);
 
     // Ask the image to decode at its intrinsic size.
     int32_t width = 0, height = 0;
     image->GetWidth(&width);
     image->GetHeight(&height);
-    image->RequestDecodeForSize(nsIntSize(width, height), imgIContainer::FLAG_NONE);
+    image->RequestDecodeForSize(nsIntSize(width, height),
+                                imgIContainer::FLAG_HIGH_QUALITY_SCALING);
   }
 
   if (aType == imgINotificationObserver::FRAME_COMPLETE) {
     return OnFrameComplete(aRequest);
   }
 
   if (aType == imgINotificationObserver::DECODE_COMPLETE) {
     if (mIconRequest && mIconRequest == aRequest) {
--- a/widget/nsIBaseWindow.idl
+++ b/widget/nsIBaseWindow.idl
@@ -161,24 +161,24 @@ interface nsIBaseWindow : nsISupports
 
 	On controls that don't support setting nativeWindow parents, setting this
 	will return a NS_ERROR_NOT_IMPLEMENTED error.
 	*/
 	attribute nativeWindow parentNativeWindow;
 
 	/*
 	This is the handle (HWND, GdkWindow*, ...) to the native window of the
-	control, exposed as a DOMString.
+	control, exposed as an AString.
 
-	@return DOMString in hex format with "0x" prepended, or empty string if
+	@return AString in hex format with "0x" prepended, or empty string if
 	mainWidget undefined
 
 	@throws NS_ERROR_NOT_IMPLEMENTED for non-XULWindows
 	*/
-	readonly attribute DOMString nativeHandle;
+	readonly attribute AString nativeHandle;
 
 	/*
 	Attribute controls the visibility of the object behind this interface.
 	Setting this attribute to false will hide the control.  Setting it to 
 	true will show it.
 	*/
 	attribute boolean visibility;
 
--- a/widget/nsIGfxInfo.idl
+++ b/widget/nsIGfxInfo.idl
@@ -11,62 +11,62 @@
 interface nsIGfxInfo : nsISupports
 {
   /*
    * These are win32-specific
    */
   readonly attribute boolean D2DEnabled;
   readonly attribute boolean DWriteEnabled;
   readonly attribute boolean usingGPUProcess;
-  readonly attribute DOMString DWriteVersion;
-  readonly attribute DOMString cleartypeParameters;
+  readonly attribute AString DWriteVersion;
+  readonly attribute AString cleartypeParameters;
 
   /*
    * These are valid across all platforms.
    */
-  readonly attribute DOMString ContentBackend;
+  readonly attribute AString ContentBackend;
   readonly attribute boolean WebRenderEnabled;
   readonly attribute boolean isHeadless;
   readonly attribute boolean UsesTiling;
   readonly attribute boolean ContentUsesTiling;
   readonly attribute boolean OffMainThreadPaintEnabled;
   readonly attribute long OffMainThreadPaintWorkerCount;
 
   // XXX: Switch to a list of devices, rather than explicitly numbering them.
 
   /**
    * The name of the display adapter.
    */
-  readonly attribute DOMString adapterDescription;
-  readonly attribute DOMString adapterDescription2;
+  readonly attribute AString adapterDescription;
+  readonly attribute AString adapterDescription2;
 
-  readonly attribute DOMString adapterDriver;
-  readonly attribute DOMString adapterDriver2;
+  readonly attribute AString adapterDriver;
+  readonly attribute AString adapterDriver2;
 
   /* These types are inspired by DXGI_ADAPTER_DESC */
-  readonly attribute DOMString adapterVendorID;
-  readonly attribute DOMString adapterVendorID2;
+  readonly attribute AString adapterVendorID;
+  readonly attribute AString adapterVendorID2;
 
-  readonly attribute DOMString adapterDeviceID;
-  readonly attribute DOMString adapterDeviceID2;
+  readonly attribute AString adapterDeviceID;
+  readonly attribute AString adapterDeviceID2;
 
-  readonly attribute DOMString adapterSubsysID;
-  readonly attribute DOMString adapterSubsysID2;
+  readonly attribute AString adapterSubsysID;
+  readonly attribute AString adapterSubsysID2;
 
   /**
    * The amount of RAM in MB in the display adapter.
    */
-  readonly attribute DOMString adapterRAM;
-  readonly attribute DOMString adapterRAM2;
+  readonly attribute AString adapterRAM;
+  readonly attribute AString adapterRAM2;
 
-  readonly attribute DOMString adapterDriverVersion;
-  readonly attribute DOMString adapterDriverVersion2;
+  readonly attribute AString adapterDriverVersion;
+  readonly attribute AString adapterDriverVersion2;
 
-  readonly attribute DOMString adapterDriverDate;
-  readonly attribute DOMString adapterDriverDate2;
+  readonly attribute AString adapterDriverDate;
+  readonly attribute AString adapterDriverDate2;
 
   readonly attribute boolean isGPU2Active;
 
   /**
    * Returns an array of objects describing each monitor. Guaranteed properties
    * are "screenWidth" and "screenHeight". This is only implemented on Desktop.
    *
    * Windows additionally supplies "refreshRate" and "pseudoDisplay".
@@ -167,17 +167,17 @@ interface nsIGfxInfo : nsISupports
    * otherwise it will be empty.
    */
   long getFeatureStatus(in long aFeature, [optional] out ACString aFailureId);
 
   /*
    * Ask about a feature, return the minimum driver version required for it if its status is
    * FEATURE_BLOCKED_DRIVER_VERSION, otherwise return an empty string.
    */
-  DOMString getFeatureSuggestedDriverVersion(in long aFeature);
+  AString getFeatureSuggestedDriverVersion(in long aFeature);
 
   // only useful on X11
   [noscript, notxpcom] void GetData();
 
   [implicit_jscontext]
   jsval getInfo();
 
   // Return an object describing all features that have been configured:
--- a/widget/nsIGfxInfoDebug.idl
+++ b/widget/nsIGfxInfoDebug.idl
@@ -5,15 +5,15 @@
 
 #include "nsISupports.idl"
 
 /* NOTE: this interface is only implemented in debug builds */
 
 [scriptable, uuid(ca7b0bc7-c67c-4b79-8270-ed7ba002af08)]
 interface nsIGfxInfoDebug : nsISupports
 {
-  void spoofVendorID(in DOMString aVendorID);
-  void spoofDeviceID(in DOMString aDeviceID);
+  void spoofVendorID(in AString aVendorID);
+  void spoofDeviceID(in AString aDeviceID);
   
-  void spoofDriverVersion(in DOMString aDriverVersion);
+  void spoofDriverVersion(in AString aDriverVersion);
 
   void spoofOSVersion(in unsigned long aVersion);
 };
--- a/widget/nsITaskbarPreview.idl
+++ b/widget/nsITaskbarPreview.idl
@@ -36,17 +36,17 @@ interface nsITaskbarPreview : nsISupport
    */
   attribute nsITaskbarPreviewController controller;
 
   /**
    * The tooltip displayed above the preview when the user hovers over it
    *
    * Default: an empty string
    */
-  attribute DOMString tooltip;
+  attribute AString tooltip;
 
   /**
    * Whether or not the preview is visible.
    *
    * Changing this option is expensive for tab previews since toggling this
    * option will destroy/create the proxy window and its registration with the
    * taskbar. If any step of that fails, an exception will be thrown.
    *
--- a/widget/nsITaskbarPreviewButton.idl
+++ b/widget/nsITaskbarPreviewButton.idl
@@ -17,17 +17,17 @@ interface imgIContainer;
 [scriptable, uuid(CED8842D-FE37-4767-9A8E-FDFA56510C75)]
 interface nsITaskbarPreviewButton : nsISupports
 {
   /**
    * The button's tooltip.
    *
    * Default: an empty string
    */
-  attribute DOMString tooltip;
+  attribute AString tooltip;
 
   /**
    * True if the array of previews should be dismissed when this button is clicked.
    *
    * Default: false
    */
   attribute boolean dismissOnClick;
 
--- a/widget/nsITaskbarTabPreview.idl
+++ b/widget/nsITaskbarTabPreview.idl
@@ -23,17 +23,17 @@ interface imgIContainer;
 [scriptable, uuid(11E4C8BD-5C2D-4E1A-A9A1-79DD5B0FE544)]
 interface nsITaskbarTabPreview : nsITaskbarPreview
 {
   /**
    * The title displayed above the thumbnail
    *
    * Default: an empty string
    */
-  attribute DOMString title;
+  attribute AString title;
 
   /**
    * The icon displayed next to the title in the preview
    *
    * Default: null
    */
   attribute imgIContainer icon;
 
--- a/xpcom/base/CycleCollectedJSContext.cpp
+++ b/xpcom/base/CycleCollectedJSContext.cpp
@@ -222,16 +222,22 @@ protected:
   virtual void Run(AutoSlowOperation& aAso) override
   {
     JSObject* callback = mCallback->CallbackPreserveColor();
     nsIGlobalObject* global = callback ? xpc::NativeGlobal(callback) : nullptr;
     if (global && !global->IsDying()) {
       mCallback->Call("promise callback");
       aAso.CheckForInterrupt();
     }
+    // Now that mCallback is no longer needed, clear any pointers it contains to
+    // JS GC things. This removes any storebuffer entries associated with those
+    // pointers, which can cause problems by taking up memory and by triggering
+    // minor GCs. This otherwise would not happen until the next minor GC or
+    // cycle collection.
+    mCallback->Reset();
   }
 
   virtual bool Suppressed() override
   {
     nsIGlobalObject* global =
       xpc::NativeGlobal(mCallback->CallbackPreserveColor());
     return global && global->IsInSyncOperation();
   }
--- a/xpcom/base/nsrootidl.idl
+++ b/xpcom/base/nsrootidl.idl
@@ -73,20 +73,16 @@ typedef unsigned long       size_t;
 // See: http://bugzilla.mozilla.org/show_bug.cgi?id=93792
 
 [nsid]        native nsIID(nsIID);
 [nsid]        native nsID(nsID);
 [nsid]        native nsCID(nsCID);
 
 [ptr]         native nsQIResult(void);
 
-[ref, domstring] native DOMString(ignored);
-[ref, domstring] native DOMStringRef(ignored);
-[ptr, domstring] native DOMStringPtr(ignored);
-
 [ref, utf8string] native AUTF8String(ignored);
 [ref, utf8string] native AUTF8StringRef(ignored);
 [ptr, utf8string] native AUTF8StringPtr(ignored);
 
 [ref, cstring] native ACString(ignored);
 [ref, cstring] native ACStringRef(ignored);
 [ptr, cstring] native ACStringPtr(ignored);
 
--- a/xpcom/ds/nsIVariant.idl
+++ b/xpcom/ds/nsIVariant.idl
@@ -29,17 +29,16 @@ struct nsIDataType
         VTYPE_UINT64            = TD_UINT64           ,
         VTYPE_FLOAT             = TD_FLOAT            ,
         VTYPE_DOUBLE            = TD_DOUBLE           ,
         VTYPE_BOOL              = TD_BOOL             ,
         VTYPE_CHAR              = TD_CHAR             ,
         VTYPE_WCHAR             = TD_WCHAR            ,
         VTYPE_VOID              = TD_VOID             ,
         VTYPE_ID                = TD_PNSIID           ,
-        VTYPE_DOMSTRING         = TD_DOMSTRING        ,
         VTYPE_CHAR_STR          = TD_PSTRING          ,
         VTYPE_WCHAR_STR         = TD_PWSTRING         ,
         VTYPE_INTERFACE         = TD_INTERFACE_TYPE   ,
         VTYPE_INTERFACE_IS      = TD_INTERFACE_IS_TYPE,
         VTYPE_ARRAY             = TD_LEGACY_ARRAY     ,
         VTYPE_STRING_SIZE_IS    = TD_PSTRING_SIZE_IS  ,
         VTYPE_WSTRING_SIZE_IS   = TD_PWSTRING_SIZE_IS ,
         VTYPE_UTF8STRING        = TD_UTF8STRING       ,
@@ -77,17 +76,16 @@ interface nsIVariant : nsISupports
     [noscript] uint64_t     getAsUint64();
     [noscript] float        getAsFloat();
     [noscript] double       getAsDouble();
     [noscript] boolean      getAsBool();
     [noscript] char         getAsChar();
     [noscript] wchar        getAsWChar();
     [notxpcom] nsresult     getAsID(out nsID retval);
     [noscript] AString      getAsAString();
-    [noscript] DOMString    getAsDOMString();
     [noscript] ACString     getAsACString();
     [noscript] AUTF8String  getAsAUTF8String();
     [noscript] string       getAsString();
     [noscript] wstring      getAsWString();
     [noscript] nsISupports  getAsISupports();
     [noscript] jsval        getAsJSVal();
 
     [noscript] void getAsInterface(out nsIIDPtr iid, 
@@ -128,17 +126,16 @@ interface nsIWritableVariant : nsIVarian
     void setAsUint64(in uint64_t aValue);
     void setAsFloat(in float aValue);
     void setAsDouble(in double aValue);
     void setAsBool(in boolean aValue);
     void setAsChar(in char aValue);
     void setAsWChar(in wchar aValue);
     void setAsID(in nsIDRef aValue);
     void setAsAString(in AString aValue);
-    void setAsDOMString(in DOMString aValue);
     void setAsACString(in ACString aValue);
     void setAsAUTF8String(in AUTF8String aValue);
     void setAsString(in string aValue);
     void setAsWString(in wstring aValue);
     void setAsISupports(in nsISupports aValue);
 
     void setAsInterface(in nsIIDRef iid, 
                         [iid_is(iid)] in nsQIResult iface);
--- a/xpcom/ds/nsVariant.cpp
+++ b/xpcom/ds/nsVariant.cpp
@@ -110,17 +110,16 @@ nsDiscriminatedUnion::ToManageableNumber
     case nsIDataType::VTYPE_CHAR_STR:
     case nsIDataType::VTYPE_STRING_SIZE_IS:
       rv = String2Double(u.str.mStringValue, &aOutData->u.mDoubleValue);
       if (NS_FAILED(rv)) {
         return rv;
       }
       aOutData->mType = nsIDataType::VTYPE_DOUBLE;
       return NS_OK;
-    case nsIDataType::VTYPE_DOMSTRING:
     case nsIDataType::VTYPE_ASTRING:
       rv = AString2Double(*u.mAStringValue, &aOutData->u.mDoubleValue);
       if (NS_FAILED(rv)) {
         return rv;
       }
       aOutData->mType = nsIDataType::VTYPE_DOUBLE;
       return NS_OK;
     case nsIDataType::VTYPE_UTF8STRING:
@@ -214,17 +213,16 @@ nsDiscriminatedUnion::FreeArray()
     CASE__FREE_ARRAY_PTR(VTYPE_CHAR_STR, char)
     CASE__FREE_ARRAY_PTR(VTYPE_WCHAR_STR, char16_t)
     CASE__FREE_ARRAY_IFACE(VTYPE_INTERFACE, nsISupports)
     CASE__FREE_ARRAY_IFACE(VTYPE_INTERFACE_IS, nsISupports)
 
     // The rest are illegal.
     case nsIDataType::VTYPE_VOID:
     case nsIDataType::VTYPE_ASTRING:
-    case nsIDataType::VTYPE_DOMSTRING:
     case nsIDataType::VTYPE_UTF8STRING:
     case nsIDataType::VTYPE_CSTRING:
     case nsIDataType::VTYPE_WSTRING_SIZE_IS:
     case nsIDataType::VTYPE_STRING_SIZE_IS:
     case nsIDataType::VTYPE_ARRAY:
     case nsIDataType::VTYPE_EMPTY_ARRAY:
     case nsIDataType::VTYPE_EMPTY:
     default:
@@ -305,17 +303,16 @@ CloneArray(uint16_t aInType, const nsIID
     case nsIDataType::VTYPE_WCHAR_STR:
     case nsIDataType::VTYPE_INTERFACE:
     case nsIDataType::VTYPE_INTERFACE_IS:
       elementSize = sizeof(void*);
       break;
 
     // The rest are illegal.
     case nsIDataType::VTYPE_ASTRING:
-    case nsIDataType::VTYPE_DOMSTRING:
     case nsIDataType::VTYPE_UTF8STRING:
     case nsIDataType::VTYPE_CSTRING:
     case nsIDataType::VTYPE_STRING_SIZE_IS:
     case nsIDataType::VTYPE_WSTRING_SIZE_IS:
     case nsIDataType::VTYPE_VOID:
     case nsIDataType::VTYPE_ARRAY:
     case nsIDataType::VTYPE_EMPTY_ARRAY:
     case nsIDataType::VTYPE_EMPTY:
@@ -410,17 +407,16 @@ CloneArray(uint16_t aInType, const nsIID
     }
 
     // The rest are illegal.
     case nsIDataType::VTYPE_VOID:
     case nsIDataType::VTYPE_ARRAY:
     case nsIDataType::VTYPE_EMPTY_ARRAY:
     case nsIDataType::VTYPE_EMPTY:
     case nsIDataType::VTYPE_ASTRING:
-    case nsIDataType::VTYPE_DOMSTRING:
     case nsIDataType::VTYPE_UTF8STRING:
     case nsIDataType::VTYPE_CSTRING:
     case nsIDataType::VTYPE_STRING_SIZE_IS:
     case nsIDataType::VTYPE_WSTRING_SIZE_IS:
     default:
       NS_ERROR("bad type in array!");
       return NS_ERROR_CANNOT_CONVERT_DATA;
   }
@@ -655,17 +651,16 @@ nsDiscriminatedUnion::String2ID(nsID* aP
     case nsIDataType::VTYPE_CHAR_STR:
     case nsIDataType::VTYPE_STRING_SIZE_IS:
       return aPid->Parse(u.str.mStringValue);
     case nsIDataType::VTYPE_CSTRING:
       return aPid->Parse(PromiseFlatCString(*u.mCStringValue).get());
     case nsIDataType::VTYPE_UTF8STRING:
       return aPid->Parse(PromiseFlatUTF8String(*u.mUTF8StringValue).get());
     case nsIDataType::VTYPE_ASTRING:
-    case nsIDataType::VTYPE_DOMSTRING:
       pString = u.mAStringValue;
       break;
     case nsIDataType::VTYPE_WCHAR_STR:
     case nsIDataType::VTYPE_WSTRING_SIZE_IS:
       tempString.Assign(u.wstr.mWStringValue);
       pString = &tempString;
       break;
     default:
@@ -693,17 +688,16 @@ nsDiscriminatedUnion::ConvertToID(nsID* 
       return NS_OK;
     case nsIDataType::VTYPE_INTERFACE:
       *aResult = NS_GET_IID(nsISupports);
       return NS_OK;
     case nsIDataType::VTYPE_INTERFACE_IS:
       *aResult = u.iface.mInterfaceID;
       return NS_OK;
     case nsIDataType::VTYPE_ASTRING:
-    case nsIDataType::VTYPE_DOMSTRING:
     case nsIDataType::VTYPE_UTF8STRING:
     case nsIDataType::VTYPE_CSTRING:
     case nsIDataType::VTYPE_CHAR_STR:
     case nsIDataType::VTYPE_WCHAR_STR:
     case nsIDataType::VTYPE_STRING_SIZE_IS:
     case nsIDataType::VTYPE_WSTRING_SIZE_IS:
       if (!String2ID(&id)) {
         return NS_ERROR_CANNOT_CONVERT_DATA;
@@ -720,17 +714,16 @@ nsDiscriminatedUnion::ConvertToID(nsID* 
 nsresult
 nsDiscriminatedUnion::ToString(nsACString& aOutString) const
 {
   mozilla::SmprintfPointer pptr;
 
   switch (mType) {
     // all the stuff we don't handle...
     case nsIDataType::VTYPE_ASTRING:
-    case nsIDataType::VTYPE_DOMSTRING:
     case nsIDataType::VTYPE_UTF8STRING:
     case nsIDataType::VTYPE_CSTRING:
     case nsIDataType::VTYPE_CHAR_STR:
     case nsIDataType::VTYPE_WCHAR_STR:
     case nsIDataType::VTYPE_STRING_SIZE_IS:
     case nsIDataType::VTYPE_WSTRING_SIZE_IS:
     case nsIDataType::VTYPE_WCHAR:
       NS_ERROR("ToString being called for a string type - screwy logic!");
@@ -811,17 +804,16 @@ nsDiscriminatedUnion::ToString(nsACStrin
   return NS_OK;
 }
 
 nsresult
 nsDiscriminatedUnion::ConvertToAString(nsAString& aResult) const
 {
   switch (mType) {
     case nsIDataType::VTYPE_ASTRING:
-    case nsIDataType::VTYPE_DOMSTRING:
       aResult.Assign(*u.mAStringValue);
       return NS_OK;
     case nsIDataType::VTYPE_CSTRING:
       CopyASCIItoUTF16(*u.mCStringValue, aResult);
       return NS_OK;
     case nsIDataType::VTYPE_UTF8STRING:
       CopyUTF8toUTF16(*u.mUTF8StringValue, aResult);
       return NS_OK;
@@ -854,17 +846,16 @@ nsDiscriminatedUnion::ConvertToAString(n
   }
 }
 
 nsresult
 nsDiscriminatedUnion::ConvertToACString(nsACString& aResult) const
 {
   switch (mType) {
     case nsIDataType::VTYPE_ASTRING:
-    case nsIDataType::VTYPE_DOMSTRING:
       LossyCopyUTF16toASCII(*u.mAStringValue, aResult);
       return NS_OK;
     case nsIDataType::VTYPE_CSTRING:
       aResult.Assign(*u.mCStringValue);
       return NS_OK;
     case nsIDataType::VTYPE_UTF8STRING:
       // XXX This is an extra copy that should be avoided
       // once Jag lands support for UTF8String and associated
@@ -897,17 +888,16 @@ nsDiscriminatedUnion::ConvertToACString(
   }
 }
 
 nsresult
 nsDiscriminatedUnion::ConvertToAUTF8String(nsAUTF8String& aResult) const
 {
   switch (mType) {
     case nsIDataType::VTYPE_ASTRING:
-    case nsIDataType::VTYPE_DOMSTRING:
       CopyUTF16toUTF8(*u.mAStringValue, aResult);
       return NS_OK;
     case nsIDataType::VTYPE_CSTRING:
       // XXX Extra copy, can be removed if we're sure CSTRING can
       //     only contain ASCII.
       CopyUTF16toUTF8(NS_ConvertASCIItoUTF16(*u.mCStringValue),
                       aResult);
       return NS_OK;
@@ -972,17 +962,16 @@ nsresult
 nsDiscriminatedUnion::ConvertToStringWithSize(uint32_t* aSize, char** aStr) const
 {
   nsAutoString  tempString;
   nsAutoCString tempCString;
   nsresult rv;
 
   switch (mType) {
     case nsIDataType::VTYPE_ASTRING:
-    case nsIDataType::VTYPE_DOMSTRING:
       *aSize = u.mAStringValue->Length();
       *aStr = ToNewCString(*u.mAStringValue);
       break;
     case nsIDataType::VTYPE_CSTRING:
       *aSize = u.mCStringValue->Length();
       *aStr = ToNewCString(*u.mCStringValue);
       break;
     case nsIDataType::VTYPE_UTF8STRING: {
@@ -1044,17 +1033,16 @@ nsresult
 nsDiscriminatedUnion::ConvertToWStringWithSize(uint32_t* aSize, char16_t** aStr) const
 {
   nsAutoString  tempString;
   nsAutoCString tempCString;
   nsresult rv;
 
   switch (mType) {
     case nsIDataType::VTYPE_ASTRING:
-    case nsIDataType::VTYPE_DOMSTRING:
       *aSize = u.mAStringValue->Length();
       *aStr = ToNewUnicode(*u.mAStringValue);
       break;
     case nsIDataType::VTYPE_CSTRING:
       *aSize = u.mCStringValue->Length();
       *aStr = ToNewUnicode(*u.mCStringValue);
       break;
     case nsIDataType::VTYPE_UTF8STRING: {
@@ -1241,17 +1229,16 @@ nsDiscriminatedUnion::SetFromVariant(nsI
     CASE__SET_FROM_VARIANT_TYPE(VTYPE_FLOAT,  mFloatValue,  Float)
     CASE__SET_FROM_VARIANT_TYPE(VTYPE_DOUBLE, mDoubleValue, Double)
     CASE__SET_FROM_VARIANT_TYPE(VTYPE_BOOL ,  mBoolValue,   Bool)
     CASE__SET_FROM_VARIANT_TYPE(VTYPE_CHAR,   mCharValue,   Char)
     CASE__SET_FROM_VARIANT_TYPE(VTYPE_WCHAR,  mWCharValue,  WChar)
     CASE__SET_FROM_VARIANT_TYPE(VTYPE_ID,     mIDValue,     ID)
 
     case nsIDataType::VTYPE_ASTRING:
-    case nsIDataType::VTYPE_DOMSTRING:
     case nsIDataType::VTYPE_WCHAR_STR:
     case nsIDataType::VTYPE_WSTRING_SIZE_IS:
       CASE__SET_FROM_VARIANT_VTYPE_PROLOGUE(VTYPE_ASTRING);
       u.mAStringValue = new nsString();
       if (!u.mAStringValue) {
         return NS_ERROR_OUT_OF_MEMORY;
       }
       rv = aValue->GetAsAString(*u.mAStringValue);
@@ -1405,24 +1392,16 @@ void
 nsDiscriminatedUnion::SetFromAString(const nsAString& aValue)
 {
   DATA_SETTER_PROLOGUE;
   u.mAStringValue = new nsString(aValue);
   DATA_SETTER_EPILOGUE(VTYPE_ASTRING);
 }
 
 void
-nsDiscriminatedUnion::SetFromDOMString(const nsAString& aValue)
-{
-  DATA_SETTER_PROLOGUE;
-  u.mAStringValue = new nsString(aValue);
-  DATA_SETTER_EPILOGUE(VTYPE_DOMSTRING);
-}
-
-void
 nsDiscriminatedUnion::SetFromACString(const nsACString& aValue)
 {
   DATA_SETTER_PROLOGUE;
   u.mCStringValue = new nsCString(aValue);
   DATA_SETTER_EPILOGUE(VTYPE_CSTRING);
 }
 
 void
@@ -1558,17 +1537,16 @@ nsDiscriminatedUnion::Cleanup()
     case nsIDataType::VTYPE_DOUBLE:
     case nsIDataType::VTYPE_BOOL:
     case nsIDataType::VTYPE_CHAR:
     case nsIDataType::VTYPE_WCHAR:
     case nsIDataType::VTYPE_VOID:
     case nsIDataType::VTYPE_ID:
       break;
     case nsIDataType::VTYPE_ASTRING:
-    case nsIDataType::VTYPE_DOMSTRING:
       delete u.mAStringValue;
       break;
     case nsIDataType::VTYPE_CSTRING:
       delete u.mCStringValue;
       break;
     case nsIDataType::VTYPE_UTF8STRING:
       delete u.mUTF8StringValue;
       break;
@@ -1732,24 +1710,16 @@ nsVariantBase::GetAsID(nsID* aResult)
 
 NS_IMETHODIMP
 nsVariantBase::GetAsAString(nsAString& aResult)
 {
   return mData.ConvertToAString(aResult);
 }
 
 NS_IMETHODIMP
-nsVariantBase::GetAsDOMString(nsAString& aResult)
-{
-  // A DOMString maps to an AString internally, so we can re-use
-  // ConvertToAString here.
-  return mData.ConvertToAString(aResult);
-}
-
-NS_IMETHODIMP
 nsVariantBase::GetAsACString(nsACString& aResult)
 {
   return mData.ConvertToACString(aResult);
 }
 
 NS_IMETHODIMP
 nsVariantBase::GetAsAUTF8String(nsAUTF8String& aResult)
 {
@@ -1975,27 +1945,16 @@ nsVariantBase::SetAsAString(const nsAStr
   if (!mWritable) {
     return NS_ERROR_OBJECT_IS_IMMUTABLE;
   }
   mData.SetFromAString(aValue);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsVariantBase::SetAsDOMString(const nsAString& aValue)
-{
-  if (!mWritable) {
-    return NS_ERROR_OBJECT_IS_IMMUTABLE;
-  }
-
-  mData.SetFromDOMString(aValue);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
 nsVariantBase::SetAsACString(const nsACString& aValue)
 {
   if (!mWritable) {
     return NS_ERROR_OBJECT_IS_IMMUTABLE;
   }
   mData.SetFromACString(aValue);
   return NS_OK;
 }
--- a/xpcom/ds/nsVariant.h
+++ b/xpcom/ds/nsVariant.h
@@ -87,17 +87,16 @@ public:
   void SetFromUint64(uint64_t aValue);
   void SetFromFloat(float aValue);
   void SetFromDouble(double aValue);
   void SetFromBool(bool aValue);
   void SetFromChar(char aValue);
   void SetFromWChar(char16_t aValue);
   void SetFromID(const nsID& aValue);
   void SetFromAString(const nsAString& aValue);
-  void SetFromDOMString(const nsAString& aValue);
   void SetFromAUTF8String(const nsAUTF8String& aValue);
   void SetFromACString(const nsACString& aValue);
   MOZ_MUST_USE nsresult SetFromString(const char* aValue);
   MOZ_MUST_USE nsresult SetFromWString(const char16_t* aValue);
   void SetFromISupports(nsISupports* aValue);
   void SetFromInterface(const nsIID& aIID, nsISupports* aValue);
   MOZ_MUST_USE nsresult SetFromArray(uint16_t aType, const nsIID* aIID,
                                      uint32_t aCount, void* aValue);
--- a/xpcom/idl-parser/xpidl/header.py
+++ b/xpcom/idl-parser/xpidl/header.py
@@ -118,17 +118,17 @@ def paramlistAsNative(m, empty='void'):
     # Set any optional out params to default to nullptr. Skip if we just added
     # extra non-optional args to l.
     if len(l) == len(m.params):
         paramIter = len(m.params) - 1
         while (paramIter >= 0 and m.params[paramIter].optional and
                 m.params[paramIter].paramtype == "out"):
             t = m.params[paramIter].type
             # Strings can't be optional, so this shouldn't happen, but let's make sure:
-            if t == "AString" or t == "ACString" or t == "DOMString" or t == "AUTF8String":
+            if t == "AString" or t == "ACString" or t == "AUTF8String":
                 break
             l[paramIter] += " = nullptr"
             paramIter -= 1
 
     if len(l) == 0:
         return empty
 
     return ", ".join(l)
--- a/xpcom/idl-parser/xpidl/jsonxpt.py
+++ b/xpcom/idl-parser/xpidl/jsonxpt.py
@@ -33,17 +33,16 @@ TypeMap = {
     'float':              'TD_FLOAT',
     'double':             'TD_DOUBLE',
     'char':               'TD_CHAR',
     'string':             'TD_PSTRING',
     'wchar':              'TD_WCHAR',
     'wstring':            'TD_PWSTRING',
     # special types
     'nsid':               'TD_PNSIID',
-    'domstring':          'TD_DOMSTRING',
     'astring':            'TD_ASTRING',
     'utf8string':         'TD_UTF8STRING',
     'cstring':            'TD_CSTRING',
     'jsval':              'TD_JSVAL',
     'promise':            'TD_PROMISE',
 }
 
 
--- a/xpcom/idl-parser/xpidl/xpidl.py
+++ b/xpcom/idl-parser/xpidl/xpidl.py
@@ -478,17 +478,16 @@ class Native(object):
     modifier = None
     specialtype = None
 
     # A tuple type here means that a custom value is used for each calltype:
     #   (in, out/inout, array element) respectively.
     # A `None` here means that the written type should be used as-is.
     specialtypes = {
         'nsid': None,
-        'domstring': ('const nsAString&', 'nsAString&', 'nsString'),
         'utf8string': ('const nsACString&', 'nsACString&', 'nsCString'),
         'cstring': ('const nsACString&', 'nsACString&', 'nsCString'),
         'astring': ('const nsAString&', 'nsAString&', 'nsString'),
         'jsval': ('JS::HandleValue', 'JS::MutableHandleValue', 'JS::Value'),
         'promise': '::mozilla::dom::Promise',
     }
 
     def __init__(self, name, nativename, attlist, location):
@@ -596,17 +595,17 @@ class Native(object):
             prefix += '*mut '
 
         if self.specialtype == 'nsid':
             return prefix + self.nativename
         if self.specialtype in ['cstring', 'utf8string']:
             if 'element' in calltype:
                 return '::nsstring::nsCString'
             return prefix + '::nsstring::nsACString'
-        if self.specialtype in ['astring', 'domstring']:
+        if self.specialtype == 'astring':
             if 'element' in calltype:
                 return '::nsstring::nsString'
             return prefix + '::nsstring::nsAString'
         if self.nativename == 'void':
             return prefix + 'libc::c_void'
 
         if self.specialtype:
             raise RustNoncompat("specialtype %s unsupported" % self.specialtype)
--- a/xpcom/reflect/xptinfo/xptinfo.h
+++ b/xpcom/reflect/xptinfo/xptinfo.h
@@ -200,22 +200,21 @@ enum nsXPTTypeTag : uint8_t
   TD_PROMISE           = 23,
   _TD_LAST_POINTER     = TD_PROMISE,
 
   // Complex Types
   //  - Require cleanup,
   //  - Always passed indirectly,
   //  - Outparams must be initialized by caller,
   //  - Supported in xptcall due to indirection.
-  TD_DOMSTRING         = 24,
-  TD_UTF8STRING        = 25,
-  TD_CSTRING           = 26,
-  TD_ASTRING           = 27,
-  TD_JSVAL             = 28,
-  TD_ARRAY             = 29,
+  TD_UTF8STRING        = 24,
+  TD_CSTRING           = 25,
+  TD_ASTRING           = 26,
+  TD_JSVAL             = 27,
+  TD_ARRAY             = 28,
   _TD_LAST_COMPLEX     = TD_ARRAY
 };
 
 static_assert(_TD_LAST_COMPLEX < 32, "nsXPTTypeTag must fit in 5 bits");
 
 
 /*
  * A nsXPTType is a union used to identify the type of a method argument or
@@ -355,17 +354,16 @@ public:
   TD_ALIAS_(T_U64               , TD_UINT64           );
   TD_ALIAS_(T_FLOAT             , TD_FLOAT            );
   TD_ALIAS_(T_DOUBLE            , TD_DOUBLE           );
   TD_ALIAS_(T_BOOL              , TD_BOOL             );
   TD_ALIAS_(T_CHAR              , TD_CHAR             );
   TD_ALIAS_(T_WCHAR             , TD_WCHAR            );
   TD_ALIAS_(T_VOID              , TD_VOID             );
   TD_ALIAS_(T_IID               , TD_PNSIID           );
-  TD_ALIAS_(T_DOMSTRING         , TD_DOMSTRING        );
   TD_ALIAS_(T_CHAR_STR          , TD_PSTRING          );
   TD_ALIAS_(T_WCHAR_STR         , TD_PWSTRING         );
   TD_ALIAS_(T_INTERFACE         , TD_INTERFACE_TYPE   );
   TD_ALIAS_(T_INTERFACE_IS      , TD_INTERFACE_IS_TYPE);
   TD_ALIAS_(T_LEGACY_ARRAY      , TD_LEGACY_ARRAY     );
   TD_ALIAS_(T_PSTRING_SIZE_IS   , TD_PSTRING_SIZE_IS  );
   TD_ALIAS_(T_PWSTRING_SIZE_IS  , TD_PWSTRING_SIZE_IS );
   TD_ALIAS_(T_UTF8STRING        , TD_UTF8STRING       );
@@ -703,17 +701,16 @@ GetString(uint32_t aIndex)
   macro(TD_INTERFACE_IS_TYPE, nsISupports*) \
   macro(TD_LEGACY_ARRAY,      void*) \
   macro(TD_PSTRING_SIZE_IS,   char*) \
   macro(TD_PWSTRING_SIZE_IS,  wchar_t*) \
   macro(TD_DOMOBJECT,         void*) \
   macro(TD_PROMISE,           mozilla::dom::Promise*)
 
 #define XPT_FOR_EACH_COMPLEX_TYPE(macro) \
-  macro(TD_DOMSTRING,  nsString) \
   macro(TD_UTF8STRING, nsCString) \
   macro(TD_CSTRING,    nsCString) \
   macro(TD_ASTRING,    nsString) \
   macro(TD_JSVAL,      JS::Value) \
   macro(TD_ARRAY,      xpt::detail::UntypedTArray)
 
 #define XPT_FOR_EACH_TYPE(macro) \
   XPT_FOR_EACH_ARITHMETIC_TYPE(macro) \
--- a/xpcom/system/nsIXULRuntime.idl
+++ b/xpcom/system/nsIXULRuntime.idl
@@ -93,17 +93,17 @@ interface nsIXULRuntime : nsISupports
    * A globally unique and non-recycled ID of the caller's process.
    */
   readonly attribute uint64_t uniqueProcessID;
 
   /**
    * The type of remote content process we're running in.
    * null if we're in the parent/chrome process.
    */
-  readonly attribute DOMString remoteType;
+  readonly attribute AString remoteType;
 
   /**
    * If true, browser tabs may be opened by default in a different process
    * from the main browser UI.
    */
   readonly attribute boolean browserTabsRemoteAutostart;
 
   /**
@@ -129,17 +129,17 @@ interface nsIXULRuntime : nsISupports
   /**
    * If true, the AccessibleHandler dll is used.
    */
   readonly attribute boolean accessibleHandlerUsed;
 
   /**
    * Executable of Windows service that activated accessibility.
    */
-  readonly attribute DOMString accessibilityInstantiator;
+  readonly attribute AString accessibilityInstantiator;
 
   /**
    * Temporary, do not use. Indicates if an incompat version of JAWS
    * screen reader software is loaded in our process space.
    */
   readonly attribute boolean shouldBlockIncompatJaws;
 
   /**