Merge inbound to mozilla-central. a=merge
authorGurzau Raul <rgurzau@mozilla.com>
Tue, 02 Oct 2018 19:03:40 +0300
changeset 487520 17c314f6930d2b8d6e456aa9e9d41407a45c3008
parent 487519 cdedc6a6b40a397181b549fb3898a25cf1bb1ba3 (current diff)
parent 487478 231b53d76122680bb682eb74cc73615a9a554f31 (diff)
child 487521 04cf22628ca53643fdb9620fe547ae59f45e4b14
child 487564 cefdf4d102faabf8a000caa821d311ca3d289701
push id246
push userfmarier@mozilla.com
push dateSat, 13 Oct 2018 00:15:40 +0000
reviewersmerge
milestone64.0a1
Merge inbound to mozilla-central. a=merge
docshell/test/mochitest/bug123696-subframe.html
docshell/test/mochitest/bug404548-subframe.html
docshell/test/mochitest/bug404548-subframe_window.html
docshell/test/mochitest/bug413310-post.sjs
docshell/test/mochitest/bug413310-subframe.html
docshell/test/mochitest/bug529119-window.html
docshell/test/mochitest/bug530396-noref.sjs
docshell/test/mochitest/bug530396-subframe.html
docshell/test/mochitest/bug570341_recordevents.html
docshell/test/mochitest/bug668513_redirect.html
docshell/test/mochitest/bug668513_redirect.html^headers^
docshell/test/mochitest/bug691547_frame.html
docshell/test/mochitest/dummy_page.html
docshell/test/mochitest/file_anchor_scroll_after_document_open.html
docshell/test/mochitest/file_bfcache_plus_hash_1.html
docshell/test/mochitest/file_bfcache_plus_hash_2.html
docshell/test/mochitest/file_bug1121701_1.html
docshell/test/mochitest/file_bug1121701_2.html
docshell/test/mochitest/file_bug1151421.html
docshell/test/mochitest/file_bug1186774.html
docshell/test/mochitest/file_bug1450164.html
docshell/test/mochitest/file_bug385434_1.html
docshell/test/mochitest/file_bug385434_2.html
docshell/test/mochitest/file_bug385434_3.html
docshell/test/mochitest/file_bug475636.sjs
docshell/test/mochitest/file_bug509055.html
docshell/test/mochitest/file_bug511449.html
docshell/test/mochitest/file_bug540462.html
docshell/test/mochitest/file_bug580069_1.html
docshell/test/mochitest/file_bug580069_2.sjs
docshell/test/mochitest/file_bug590573_1.html
docshell/test/mochitest/file_bug590573_2.html
docshell/test/mochitest/file_bug598895_1.html
docshell/test/mochitest/file_bug598895_2.html
docshell/test/mochitest/file_bug634834.html
docshell/test/mochitest/file_bug637644_1.html
docshell/test/mochitest/file_bug637644_2.html
docshell/test/mochitest/file_bug640387.html
docshell/test/mochitest/file_bug653741.html
docshell/test/mochitest/file_bug660404
docshell/test/mochitest/file_bug660404-1.html
docshell/test/mochitest/file_bug660404^headers^
docshell/test/mochitest/file_bug662170.html
docshell/test/mochitest/file_bug668513.html
docshell/test/mochitest/file_bug669671.sjs
docshell/test/mochitest/file_bug675587.html
docshell/test/mochitest/file_bug680257.html
docshell/test/mochitest/file_bug703855.html
docshell/test/mochitest/file_bug728939.html
docshell/test/mochitest/file_close_onpagehide1.html
docshell/test/mochitest/file_close_onpagehide2.html
docshell/test/mochitest/file_framedhistoryframes.html
docshell/test/mochitest/file_pushState_after_document_open.html
docshell/test/mochitest/historyframes.html
docshell/test/mochitest/mochitest.ini
docshell/test/mochitest/start_historyframe.html
docshell/test/mochitest/test_anchor_scroll_after_document_open.html
docshell/test/mochitest/test_bfcache_plus_hash.html
docshell/test/mochitest/test_bug1045096.html
docshell/test/mochitest/test_bug1121701.html
docshell/test/mochitest/test_bug1151421.html
docshell/test/mochitest/test_bug1186774.html
docshell/test/mochitest/test_bug123696.html
docshell/test/mochitest/test_bug1450164.html
docshell/test/mochitest/test_bug384014.html
docshell/test/mochitest/test_bug385434.html
docshell/test/mochitest/test_bug387979.html
docshell/test/mochitest/test_bug402210.html
docshell/test/mochitest/test_bug404548.html
docshell/test/mochitest/test_bug413310.html
docshell/test/mochitest/test_bug475636.html
docshell/test/mochitest/test_bug509055.html
docshell/test/mochitest/test_bug511449.html
docshell/test/mochitest/test_bug529119-1.html
docshell/test/mochitest/test_bug529119-2.html
docshell/test/mochitest/test_bug530396.html
docshell/test/mochitest/test_bug540462.html
docshell/test/mochitest/test_bug551225.html
docshell/test/mochitest/test_bug570341.html
docshell/test/mochitest/test_bug580069.html
docshell/test/mochitest/test_bug590573.html
docshell/test/mochitest/test_bug598895.html
docshell/test/mochitest/test_bug634834.html
docshell/test/mochitest/test_bug637644.html
docshell/test/mochitest/test_bug640387_1.html
docshell/test/mochitest/test_bug640387_2.html
docshell/test/mochitest/test_bug653741.html
docshell/test/mochitest/test_bug660404.html
docshell/test/mochitest/test_bug662170.html
docshell/test/mochitest/test_bug668513.html
docshell/test/mochitest/test_bug669671.html
docshell/test/mochitest/test_bug675587.html
docshell/test/mochitest/test_bug680257.html
docshell/test/mochitest/test_bug691547.html
docshell/test/mochitest/test_bug694612.html
docshell/test/mochitest/test_bug703855.html
docshell/test/mochitest/test_bug728939.html
docshell/test/mochitest/test_bug797909.html
docshell/test/mochitest/test_close_onpagehide_by_history_back.html
docshell/test/mochitest/test_close_onpagehide_by_window_close.html
docshell/test/mochitest/test_forceinheritprincipal_overrule_owner.html
docshell/test/mochitest/test_framedhistoryframes.html
docshell/test/mochitest/test_pushState_after_document_open.html
docshell/test/mochitest/test_triggeringprincipal_location_seturi.html
docshell/test/mochitest/test_windowedhistoryframes.html
docshell/test/mochitest/url1_historyframe.html
docshell/test/mochitest/url2_historyframe.html
docshell/test/moz.build
testing/web-platform/meta/encrypted-media/clearkey-mp4-unique-origin.https.html.ini
third_party/rust/syn-0.14.6/src/parsers.rs
third_party/rust/syn-0.14.6/src/verbatim.rs
third_party/rust/uuid-0.5.1/.travis.yml
third_party/rust/uuid-0.5.1/src/rustc_serialize.rs
third_party/rust/uuid-0.5.1/src/serde.rs
toolkit/moz.configure
--- 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;
 
   /**