Merge inbound to mozilla-central. a=merge
authorCsoregi Natalia <ncsoregi@mozilla.com>
Wed, 17 Oct 2018 13:03:35 +0300
changeset 489962 9c943fa07f723ebf4fa3a885b69fe2cb3c5da2d7
parent 489961 99c45aca2d8a868eb9e6c3c5543af78954839934 (current diff)
parent 489935 09dd66ffc95aff0d95312717a450fd85e803eb35 (diff)
child 489963 1a9ecfe4c2d4aae717bdb8cdbef9391a1e1c1ba6
child 490024 5cc98bf772f726daa10abb0f5e3305c6466c6c53
push id247
push userfmarier@mozilla.com
push dateSat, 27 Oct 2018 01:06:44 +0000
reviewersmerge
milestone64.0a1
Merge inbound to mozilla-central. a=merge
security/nss/automation/taskcluster/windows/setup32.sh
security/nss/automation/taskcluster/windows/setup64.sh
testing/web-platform/meta/wasm/idlharness.any.js.ini
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1500,16 +1500,21 @@ pref("toolkit.telemetry.hybridContent.en
 pref("browser.ping-centre.telemetry", true);
 pref("browser.ping-centre.log", false);
 pref("browser.ping-centre.staging.endpoint", "https://onyx_tiles.stage.mozaws.net/v3/links/ping-centre");
 pref("browser.ping-centre.production.endpoint", "https://tiles.services.mozilla.com/v3/links/ping-centre");
 
 // Enable GMP support in the addon manager.
 pref("media.gmp-provider.enabled", true);
 
+// Enable blocking access to storage from tracking resources by default on Nightly
+#ifdef NIGHTLY_BUILD
+pref("network.cookie.cookieBehavior", 4 /* BEHAVIOR_REJECT_TRACKER */);
+#endif
+
 pref("browser.contentblocking.allowlist.storage.enabled", true);
 
 #ifdef NIGHTLY_BUILD
 pref("browser.contentblocking.global-toggle.enabled", true);
 #else
 pref("browser.contentblocking.global-toggle.enabled", false);
 #endif
 
--- a/caps/SystemPrincipal.cpp
+++ b/caps/SystemPrincipal.cpp
@@ -97,17 +97,17 @@ SystemPrincipal::GetPreloadCsp(nsIConten
   return NS_OK;
 }
 
 NS_IMETHODIMP
 SystemPrincipal::EnsurePreloadCSP(nsIDocument* aDocument,
                                   nsIContentSecurityPolicy** aPreloadCSP)
 {
   // CSP on a system principal makes no sense
-  return NS_OK;
+  return NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 SystemPrincipal::GetDomain(nsIURI** aDomain)
 {
     *aDomain = nullptr;
     return NS_OK;
 }
--- a/dom/payments/PaymentRequest.cpp
+++ b/dom/payments/PaymentRequest.cpp
@@ -5,25 +5,29 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "BasicCardPayment.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/FeaturePolicyUtils.h"
 #include "mozilla/dom/PaymentRequest.h"
 #include "mozilla/dom/PaymentRequestChild.h"
 #include "mozilla/dom/PaymentResponse.h"
+#include "mozilla/intl/LocaleService.h"
+#include "mozilla/intl/MozLocale.h"
 #include "mozilla/EventStateManager.h"
 #include "mozilla/StaticPrefs.h"
 #include "nsContentUtils.h"
 #include "nsIScriptError.h"
 #include "nsIURLParser.h"
 #include "nsNetCID.h"
 #include "PaymentRequestManager.h"
 #include "mozilla/dom/MerchantValidationEvent.h"
 
+using mozilla::intl::LocaleService;
+
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(PaymentRequest)
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(PaymentRequest,
                                                DOMEventTargetHelper)
   // Don't need NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER because
@@ -55,21 +59,45 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
 
 NS_IMPL_ADDREF_INHERITED(PaymentRequest, DOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(PaymentRequest, DOMEventTargetHelper)
 
 bool
 PaymentRequest::PrefEnabled(JSContext* aCx, JSObject* aObj)
 {
-#ifdef NIGHTLY_BUILD
+#if defined(NIGHTLY_BUILD)
+  const char* supportedRegions[] = { "US", "CA" };
+
   if (!XRE_IsContentProcess()) {
     return false;
   }
-  return StaticPrefs::dom_payments_request_enabled();
+  if (!StaticPrefs::dom_payments_request_enabled()) {
+    return false;
+  }
+  nsAutoString region;
+  Preferences::GetString("browser.search.region", region);
+  bool regionIsSupported = false;
+  for (const char* each : supportedRegions) {
+    if (region.EqualsASCII(each)) {
+      regionIsSupported = true;
+      break;
+    }
+  }
+  if (!regionIsSupported) {
+    return false;
+  }
+  nsAutoCString locale;
+  LocaleService::GetInstance()->GetAppLocaleAsLangTag(locale);
+  mozilla::intl::Locale loc = mozilla::intl::Locale(locale);
+  if (!(loc.GetLanguage() == "en" && loc.GetRegion() == "US")) {
+    return false;
+  }
+
+  return true;
 #else
   return false;
 #endif
 }
 
 nsresult
 PaymentRequest::IsValidStandardizedPMI(const nsAString& aIdentifier,
                                        nsAString& aErrorMsg)
--- a/dom/serviceworkers/test/mochitest.ini
+++ b/dom/serviceworkers/test/mochitest.ini
@@ -1,10 +1,16 @@
 [DEFAULT]
-
+# Mochitests are executed in iframes. Several ServiceWorker tests use iframes
+# too. The result is that we have nested iframes. CookieBehavior 4
+# (BEHAVIOR_REJECT_TRACKER) doesn't grant storage access permission to nested
+# iframes because trackers could use them to follow users across sites. Let's
+# use cookieBehavior 0 (BEHAVIOR_ACCEPT) here.
+prefs =
+  network.cookie.cookieBehavior=0
 skip-if = serviceworker_e10s
 support-files =
   worker.js
   worker2.js
   worker3.js
   fetch_event_worker.js
   parse_error_worker.js
   activate_event_error_worker.js
--- a/dom/tests/mochitest/general/test_interfaces.js
+++ b/dom/tests/mochitest/general/test_interfaces.js
@@ -654,16 +654,18 @@ var interfaceNamesInGlobalScope =
     {name: "MediaStreamAudioSourceNode", insecureContext: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "MediaStreamEvent", insecureContext: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "MediaStreamTrackEvent", insecureContext: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "MediaStreamTrack", insecureContext: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
+    {name: "MerchantValidationEvent", insecureContext: false, desktop: true, nightly: true, linux: false},
+// IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "MessageChannel", insecureContext: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "MessageEvent", insecureContext: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "MessagePort", insecureContext: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "MIDIAccess", disabled: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
@@ -734,16 +736,26 @@ var interfaceNamesInGlobalScope =
     {name: "PaintRequest", insecureContext: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "PaintRequestList", insecureContext: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "PannerNode", insecureContext: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "Path2D", insecureContext: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
+    {name: "PaymentAddress", insecureContext: false, desktop: true, nightly: true, linux: false},
+// IMPORTANT: Do not change this list without review from a DOM peer!
+    {name: "PaymentMethodChangeEvent", insecureContext: false, desktop: true, nightly: true, linux: false},
+// IMPORTANT: Do not change this list without review from a DOM peer!
+    {name: "PaymentRequest", insecureContext: false, desktop: true, nightly: true, linux: false},
+// IMPORTANT: Do not change this list without review from a DOM peer!
+    {name: "PaymentRequestUpdateEvent", insecureContext: false, desktop: true, nightly: true, linux: false},
+// IMPORTANT: Do not change this list without review from a DOM peer!
+    {name: "PaymentResponse", insecureContext: false, desktop: true, nightly: true, linux: false},
+// IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "Performance", insecureContext: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "PerformanceEntry", insecureContext: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "PerformanceMark", insecureContext: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "PerformanceMeasure", insecureContext: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
--- a/extensions/cookie/nsPermissionManager.cpp
+++ b/extensions/cookie/nsPermissionManager.cpp
@@ -1,15 +1,16 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/Attributes.h"
+#include "mozilla/AntiTrackingCommon.h"
 #include "mozilla/DebugOnly.h"
 
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/BasePrincipal.h"
 #include "mozilla/ContentPrincipal.h"
 #include "mozilla/Pair.h"
 #include "mozilla/Services.h"
@@ -132,17 +133,19 @@ static const char* kPreloadPermissions[]
   "speculative",
 
   // This permission is preloaded to support properly blocking service worker
   // interception when a user has disabled storage for a specific site.  Once
   // service worker interception moves to the parent process this should be
   // removed.  See bug 1428130.
   "cookie",
   "trackingprotection",
-  "trackingprotection-pb"
+  "trackingprotection-pb",
+
+  USER_INTERACTION_PERM
 };
 
 // A list of permissions that can have a fallback default permission
 // set under the permissions.default.* pref.
 static const char* kPermissionsWithDefaults[] = {
   "camera",
   "microphone",
   "geo",
--- a/gfx/layers/wr/WebRenderBridgeParent.cpp
+++ b/gfx/layers/wr/WebRenderBridgeParent.cpp
@@ -1182,17 +1182,17 @@ WebRenderBridgeParent::RecvGetSnapshot(P
   MOZ_ASSERT(bufferTexture->GetFormat() == SurfaceFormat::B8G8R8A8);
   uint32_t buffer_size = size.width * size.height * 4;
 
   // Assert the stride of the buffer is what webrender expects
   MOZ_ASSERT((uint32_t)(size.width * 4) == stride);
 
   FlushSceneBuilds();
   FlushFrameGeneration();
-  mApi->Readback(start, size, buffer, buffer_size);
+  mApi->Readback(start, size, Range<uint8_t>(buffer, buffer_size));
 
   return IPC_OK();
 }
 
 void
 WebRenderBridgeParent::AddPipelineIdForCompositable(const wr::PipelineId& aPipelineId,
                                                     const CompositableHandle& aHandle,
                                                     const bool& aAsync,
--- a/gfx/webrender_bindings/RenderThread.cpp
+++ b/gfx/webrender_bindings/RenderThread.cpp
@@ -273,17 +273,17 @@ RenderThread::HandleFrame(wr::WindowId a
     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, aRender, /* aReadback */ false);
+  UpdateAndRender(aWindowId, startTime, aRender, /* aReadbackSize */ Nothing(), /* aReadbackBuffer */ Nothing());
   FrameRenderingComplete(aWindowId);
 }
 
 void
 RenderThread::WakeUp(wr::WindowId aWindowId)
 {
   if (mHasShutdown) {
     return;
@@ -351,32 +351,33 @@ NotifyDidRender(layers::CompositorBridge
 
   wr_pipeline_info_delete(aInfo);
 }
 
 void
 RenderThread::UpdateAndRender(wr::WindowId aWindowId,
                               const TimeStamp& aStartTime,
                               bool aRender,
-                              bool aReadback)
+                              const Maybe<gfx::IntSize>& aReadbackSize,
+                              const Maybe<Range<uint8_t>>& aReadbackBuffer)
 {
   AUTO_PROFILER_TRACING("Paint", "Composite");
   MOZ_ASSERT(IsInRenderThread());
-  MOZ_ASSERT(aRender || !aReadback);
+  MOZ_ASSERT(aRender || aReadbackBuffer.isNothing());
 
   auto it = mRenderers.find(aWindowId);
   MOZ_ASSERT(it != mRenderers.end());
   if (it == mRenderers.end()) {
     return;
   }
 
   auto& renderer = it->second;
 
   if (aRender) {
-    renderer->UpdateAndRender(aReadback);
+    renderer->UpdateAndRender(aReadbackSize, aReadbackBuffer);
   } else {
     renderer->Update();
   }
 
   TimeStamp end = TimeStamp::Now();
 
   auto info = renderer->FlushPipelineInfo();
   RefPtr<layers::AsyncImagePipelineManager> pipelineMgr =
--- a/gfx/webrender_bindings/RenderThread.h
+++ b/gfx/webrender_bindings/RenderThread.h
@@ -8,16 +8,17 @@
 #define MOZILLA_LAYERS_RENDERTHREAD_H
 
 #include "base/basictypes.h"            // for DISALLOW_EVIL_CONSTRUCTORS
 #include "base/platform_thread.h"       // for PlatformThreadId
 #include "base/thread.h"                // for Thread
 #include "base/message_loop.h"
 #include "nsISupportsImpl.h"
 #include "ThreadSafeRefcountingWithMainThreadDestruction.h"
+#include "mozilla/gfx/Point.h"
 #include "mozilla/MozPromise.h"
 #include "mozilla/Mutex.h"
 #include "mozilla/webrender/webrender_ffi.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/webrender/WebRenderTypes.h"
 #include "mozilla/layers/SynchronousTask.h"
 #include "GLContext.h"
 
@@ -146,17 +147,17 @@ public:
 
   /// 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 aRender, bool aReadback);
+  void UpdateAndRender(wr::WindowId aWindowId, const TimeStamp& aStartTime, bool aRender, const Maybe<gfx::IntSize>& aReadbackSize, const Maybe<Range<uint8_t>>& aReadbackBuffer);
 
   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/RendererOGL.cpp
+++ b/gfx/webrender_bindings/RendererOGL.cpp
@@ -101,21 +101,21 @@ RendererOGL::Update()
 
 static void
 DoNotifyWebRenderContextPurge(layers::CompositorBridgeParent* aBridge)
 {
   aBridge->NotifyWebRenderContextPurge();
 }
 
 bool
-RendererOGL::UpdateAndRender(bool aReadback)
+RendererOGL::UpdateAndRender(const Maybe<gfx::IntSize>& aReadbackSize, const Maybe<Range<uint8_t>>& aReadbackBuffer)
 {
   uint32_t flags = gfx::gfxVars::WebRenderDebugFlags();
   // Disable debug flags during readback
-  if (aReadback) {
+  if (aReadbackBuffer.isSome()) {
     flags = 0;
   }
 
   if (mDebugFlags.mBits != flags) {
     mDebugFlags.mBits = flags;
     wr_renderer_set_debug_flags(mRenderer, mDebugFlags);
   }
 
@@ -142,16 +142,24 @@ RendererOGL::UpdateAndRender(bool aReadb
   wr_renderer_update(mRenderer);
 
   auto size = mCompositor->GetBufferSize();
 
   if (!wr_renderer_render(mRenderer, size.width, size.height)) {
     NotifyWebRenderError(WebRenderError::RENDER);
   }
 
+  if (aReadbackBuffer.isSome()) {
+    MOZ_ASSERT(aReadbackSize.isSome());
+    wr_renderer_readback(mRenderer,
+                         aReadbackSize.ref().width, aReadbackSize.ref().height,
+                         &aReadbackBuffer.ref()[0],
+                         aReadbackBuffer.ref().length());
+  }
+
   mCompositor->EndFrame();
 
   mCompositor->GetWidget()->PostRender(&widgetContext);
 
 #if defined(ENABLE_FRAME_LATENCY_LOG)
   if (mFrameStartTime) {
     uint32_t latencyMs = round((TimeStamp::Now() - mFrameStartTime).ToMilliseconds());
     printf_stderr("generate frame latencyMs latencyMs %d\n", latencyMs);
--- a/gfx/webrender_bindings/RendererOGL.h
+++ b/gfx/webrender_bindings/RendererOGL.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 MOZILLA_LAYERS_RENDEREROGL_H
 #define MOZILLA_LAYERS_RENDEREROGL_H
 
 #include "mozilla/layers/CompositorTypes.h"
+#include "mozilla/gfx/Point.h"
 #include "mozilla/webrender/RenderThread.h"
 #include "mozilla/webrender/WebRenderTypes.h"
 #include "mozilla/webrender/webrender_ffi.h"
 
 namespace mozilla {
 
 namespace gfx {
 class DrawTarget;
@@ -51,17 +52,17 @@ class RendererOGL
 
 public:
   wr::WrExternalImageHandler GetExternalImageHandler();
 
   /// This can be called on the render thread only.
   void Update();
 
   /// This can be called on the render thread only.
-  bool UpdateAndRender(bool aReadback);
+  bool UpdateAndRender(const Maybe<gfx::IntSize>& aReadbackSize, const Maybe<Range<uint8_t>>& aReadbackBuffer);
 
   /// This can be called on the render thread only.
   bool RenderToTarget(gfx::DrawTarget& aTarget);
 
   /// This can be called on the render thread only.
   void SetProfilerEnabled(bool aEnabled);
 
   /// This can be called on the render thread only.
--- a/gfx/webrender_bindings/WebRenderAPI.cpp
+++ b/gfx/webrender_bindings/WebRenderAPI.cpp
@@ -391,56 +391,51 @@ WebRenderAPI::HitTest(const wr::WorldPoi
     aOutHitInfo.deserialize(serialized);
   }
   return result;
 }
 
 void
 WebRenderAPI::Readback(const TimeStamp& aStartTime,
                        gfx::IntSize size,
-                       uint8_t *buffer,
-                       uint32_t buffer_size)
+                       const Range<uint8_t>& buffer)
 {
     class Readback : public RendererEvent
     {
         public:
             explicit Readback(layers::SynchronousTask* aTask,
                               TimeStamp aStartTime,
-                              gfx::IntSize aSize, uint8_t *aBuffer, uint32_t aBufferSize)
+                              gfx::IntSize aSize, const Range<uint8_t>& aBuffer)
                 : mTask(aTask)
                 , mStartTime(aStartTime)
                 , mSize(aSize)
                 , mBuffer(aBuffer)
-                , mBufferSize(aBufferSize)
             {
                 MOZ_COUNT_CTOR(Readback);
             }
 
             ~Readback()
             {
                 MOZ_COUNT_DTOR(Readback);
             }
 
             virtual void Run(RenderThread& aRenderThread, WindowId aWindowId) override
             {
-                aRenderThread.UpdateAndRender(aWindowId, mStartTime, /* aRender */ true, /* aReadback */ true);
-                wr_renderer_readback(aRenderThread.GetRenderer(aWindowId)->GetRenderer(),
-                                     mSize.width, mSize.height, mBuffer, mBufferSize);
+                aRenderThread.UpdateAndRender(aWindowId, mStartTime, /* aRender */ true, Some(mSize), Some(mBuffer));
                 layers::AutoCompleteTask complete(mTask);
             }
 
             layers::SynchronousTask* mTask;
             TimeStamp mStartTime;
             gfx::IntSize mSize;
-            uint8_t *mBuffer;
-            uint32_t mBufferSize;
+            const Range<uint8_t>& mBuffer;
     };
 
     layers::SynchronousTask task("Readback");
-    auto event = MakeUnique<Readback>(&task, aStartTime, size, buffer, buffer_size);
+    auto event = MakeUnique<Readback>(&task, aStartTime, size, buffer);
     // This event will be passed from wr_backend thread to renderer thread. That
     // implies that all frame data have been processed when the renderer runs this
     // read-back event. Then, we could make sure this read-back event gets the
     // latest result.
     RunOnRenderThread(std::move(event));
 
     task.Wait();
 }
--- a/gfx/webrender_bindings/WebRenderAPI.h
+++ b/gfx/webrender_bindings/WebRenderAPI.h
@@ -209,17 +209,17 @@ public:
                gfx::CompositorHitTestInfo& aOutHitInfo);
 
   void SendTransaction(TransactionBuilder& aTxn);
 
   void SetFrameStartTime(const TimeStamp& aTime);
 
   void RunOnRenderThread(UniquePtr<RendererEvent> aEvent);
 
-  void Readback(const TimeStamp& aStartTime, gfx::IntSize aSize, uint8_t *aBuffer, uint32_t aBufferSize);
+  void Readback(const TimeStamp& aStartTime, gfx::IntSize aSize, const Range<uint8_t>& aBuffer);
 
   void ClearAllCaches();
 
   void Pause();
   bool Resume();
 
   void WakeSceneBuilder();
   void FlushSceneBuilder();
--- a/js/src/frontend/BytecodeEmitter.h
+++ b/js/src/frontend/BytecodeEmitter.h
@@ -261,18 +261,18 @@ struct MOZ_STACK_CLASS BytecodeEmitter
     BytecodeEmitter(BytecodeEmitter* parent, BCEParserHandle* parser, SharedContext* sc,
                     HandleScript script, Handle<LazyScript*> lazyScript, uint32_t lineNum,
                     EmitterMode emitterMode = Normal);
 
     BytecodeEmitter(BytecodeEmitter* parent, const EitherParser& parser, SharedContext* sc,
                     HandleScript script, Handle<LazyScript*> lazyScript, uint32_t lineNum,
                     EmitterMode emitterMode = Normal);
 
-    template<typename CharT>
-    BytecodeEmitter(BytecodeEmitter* parent, Parser<FullParseHandler, CharT>* parser,
+    template<typename Unit>
+    BytecodeEmitter(BytecodeEmitter* parent, Parser<FullParseHandler, Unit>* parser,
                     SharedContext* sc, HandleScript script, Handle<LazyScript*> lazyScript,
                     uint32_t lineNum, EmitterMode emitterMode = Normal)
       : BytecodeEmitter(parent, EitherParser(parser), sc, script, lazyScript,
                         lineNum, emitterMode)
     {}
 
     // An alternate constructor that uses a TokenPos for the starting
     // line and that sets functionBodyEndPos as well.
@@ -291,18 +291,18 @@ struct MOZ_STACK_CLASS BytecodeEmitter
                     EmitterMode emitterMode = Normal)
         : BytecodeEmitter(parent, parser, sc, script, lazyScript,
                           parser.errorReporter().lineAt(bodyPosition.begin),
                           emitterMode)
     {
         initFromBodyPosition(bodyPosition);
     }
 
-    template<typename CharT>
-    BytecodeEmitter(BytecodeEmitter* parent, Parser<FullParseHandler, CharT>* parser,
+    template<typename Unit>
+    BytecodeEmitter(BytecodeEmitter* parent, Parser<FullParseHandler, Unit>* parser,
                     SharedContext* sc, HandleScript script, Handle<LazyScript*> lazyScript,
                     TokenPos bodyPosition, EmitterMode emitterMode = Normal)
       : BytecodeEmitter(parent, EitherParser(parser), sc, script, lazyScript,
                         bodyPosition, emitterMode)
     {}
 
     MOZ_MUST_USE bool init();
 
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -694,180 +694,180 @@ FunctionBox::finish()
 {
     if (!isLazyFunctionWithoutEnclosingScope()) {
         return;
     }
     MOZ_ASSERT(enclosingScope_);
     function()->lazyScript()->setEnclosingScope(enclosingScope_);
 }
 
-template <class ParseHandler, typename CharT>
-inline typename GeneralParser<ParseHandler, CharT>::FinalParser*
-GeneralParser<ParseHandler, CharT>::asFinalParser()
-{
-    static_assert(mozilla::IsBaseOf<GeneralParser<ParseHandler, CharT>, FinalParser>::value,
+template <class ParseHandler, typename Unit>
+inline typename GeneralParser<ParseHandler, Unit>::FinalParser*
+GeneralParser<ParseHandler, Unit>::asFinalParser()
+{
+    static_assert(mozilla::IsBaseOf<GeneralParser<ParseHandler, Unit>, FinalParser>::value,
                   "inheritance relationship required by the static_cast<> below");
 
     return static_cast<FinalParser*>(this);
 }
 
-template <class ParseHandler, typename CharT>
-inline const typename GeneralParser<ParseHandler, CharT>::FinalParser*
-GeneralParser<ParseHandler, CharT>::asFinalParser() const
-{
-    static_assert(mozilla::IsBaseOf<GeneralParser<ParseHandler, CharT>, FinalParser>::value,
+template <class ParseHandler, typename Unit>
+inline const typename GeneralParser<ParseHandler, Unit>::FinalParser*
+GeneralParser<ParseHandler, Unit>::asFinalParser() const
+{
+    static_assert(mozilla::IsBaseOf<GeneralParser<ParseHandler, Unit>, FinalParser>::value,
                   "inheritance relationship required by the static_cast<> below");
 
     return static_cast<const FinalParser*>(this);
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 void
-GeneralParser<ParseHandler, CharT>::error(unsigned errorNumber, ...)
+GeneralParser<ParseHandler, Unit>::error(unsigned errorNumber, ...)
 {
     va_list args;
     va_start(args, errorNumber);
 
     ErrorMetadata metadata;
     if (tokenStream.computeErrorMetadata(&metadata, pos().begin)) {
         ReportCompileError(context, std::move(metadata), nullptr, JSREPORT_ERROR, errorNumber, args);
     }
 
     va_end(args);
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 void
-GeneralParser<ParseHandler, CharT>::errorWithNotes(UniquePtr<JSErrorNotes> notes,
-                                                   unsigned errorNumber, ...)
+GeneralParser<ParseHandler, Unit>::errorWithNotes(UniquePtr<JSErrorNotes> notes,
+                                                  unsigned errorNumber, ...)
 {
     va_list args;
     va_start(args, errorNumber);
 
     ErrorMetadata metadata;
     if (tokenStream.computeErrorMetadata(&metadata, pos().begin)) {
         ReportCompileError(context, std::move(metadata), std::move(notes), JSREPORT_ERROR, errorNumber,
                            args);
     }
 
     va_end(args);
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 void
-GeneralParser<ParseHandler, CharT>::errorAt(uint32_t offset, unsigned errorNumber, ...)
+GeneralParser<ParseHandler, Unit>::errorAt(uint32_t offset, unsigned errorNumber, ...)
 {
     va_list args;
     va_start(args, errorNumber);
 
     ErrorMetadata metadata;
     if (tokenStream.computeErrorMetadata(&metadata, offset)) {
         ReportCompileError(context, std::move(metadata), nullptr, JSREPORT_ERROR, errorNumber, args);
     }
 
     va_end(args);
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 void
-GeneralParser<ParseHandler, CharT>::errorWithNotesAt(UniquePtr<JSErrorNotes> notes,
-                                                     uint32_t offset, unsigned errorNumber, ...)
+GeneralParser<ParseHandler, Unit>::errorWithNotesAt(UniquePtr<JSErrorNotes> notes,
+                                                    uint32_t offset, unsigned errorNumber, ...)
 {
     va_list args;
     va_start(args, errorNumber);
 
     ErrorMetadata metadata;
     if (tokenStream.computeErrorMetadata(&metadata, offset)) {
         ReportCompileError(context, std::move(metadata), std::move(notes), JSREPORT_ERROR, errorNumber,
                            args);
     }
 
     va_end(args);
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 bool
-GeneralParser<ParseHandler, CharT>::warning(unsigned errorNumber, ...)
+GeneralParser<ParseHandler, Unit>::warning(unsigned errorNumber, ...)
 {
     va_list args;
     va_start(args, errorNumber);
 
     ErrorMetadata metadata;
     bool result =
         tokenStream.computeErrorMetadata(&metadata, pos().begin) &&
         anyChars.compileWarning(std::move(metadata), nullptr, JSREPORT_WARNING, errorNumber, args);
 
     va_end(args);
     return result;
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 bool
-GeneralParser<ParseHandler, CharT>::warningAt(uint32_t offset, unsigned errorNumber, ...)
+GeneralParser<ParseHandler, Unit>::warningAt(uint32_t offset, unsigned errorNumber, ...)
 {
     va_list args;
     va_start(args, errorNumber);
 
     ErrorMetadata metadata;
     bool result = tokenStream.computeErrorMetadata(&metadata, offset);
     if (result) {
         result =
             anyChars.compileWarning(std::move(metadata), nullptr, JSREPORT_WARNING, errorNumber, args);
     }
 
     va_end(args);
     return result;
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 bool
-GeneralParser<ParseHandler, CharT>::extraWarning(unsigned errorNumber, ...)
+GeneralParser<ParseHandler, Unit>::extraWarning(unsigned errorNumber, ...)
 {
     va_list args;
     va_start(args, errorNumber);
 
     bool result =
         tokenStream.reportExtraWarningErrorNumberVA(nullptr, pos().begin, errorNumber, &args);
 
     va_end(args);
     return result;
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 bool
-GeneralParser<ParseHandler, CharT>::extraWarningAt(uint32_t offset, unsigned errorNumber, ...)
+GeneralParser<ParseHandler, Unit>::extraWarningAt(uint32_t offset, unsigned errorNumber, ...)
 {
     va_list args;
     va_start(args, errorNumber);
 
     bool result =
         tokenStream.reportExtraWarningErrorNumberVA(nullptr, offset, errorNumber, &args);
 
     va_end(args);
     return result;
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 bool
-GeneralParser<ParseHandler, CharT>::strictModeError(unsigned errorNumber, ...)
+GeneralParser<ParseHandler, Unit>::strictModeError(unsigned errorNumber, ...)
 {
     va_list args;
     va_start(args, errorNumber);
 
     bool res =
         tokenStream.reportStrictModeErrorNumberVA(nullptr, pos().begin, pc->sc()->strict(),
                                                   errorNumber, &args);
 
     va_end(args);
     return res;
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 bool
-GeneralParser<ParseHandler, CharT>::strictModeErrorAt(uint32_t offset, unsigned errorNumber, ...)
+GeneralParser<ParseHandler, Unit>::strictModeErrorAt(uint32_t offset, unsigned errorNumber, ...)
 {
     va_list args;
     va_start(args, errorNumber);
 
     bool res =
         tokenStream.reportStrictModeErrorNumberVA(nullptr, offset, pc->sc()->strict(),
                                                   errorNumber, &args);
 
@@ -969,75 +969,75 @@ PerHandlerParser<ParseHandler>::PerHandl
                                                  ParseGoal parseGoal, void* internalSyntaxParser)
   : ParserBase(cx, alloc, options, foldConstants, usedNames, sourceObject, parseGoal),
     handler(cx, alloc, lazyOuterFunction),
     internalSyntaxParser_(internalSyntaxParser)
 {
 
 }
 
-template <class ParseHandler, typename CharT>
-GeneralParser<ParseHandler, CharT>::GeneralParser(JSContext* cx, LifoAlloc& alloc,
-                                                  const ReadOnlyCompileOptions& options,
-                                                  const CharT* chars, size_t length,
-                                                  bool foldConstants,
-                                                  UsedNameTracker& usedNames,
-                                                  SyntaxParser* syntaxParser,
-                                                  LazyScript* lazyOuterFunction,
-                                                  ScriptSourceObject* sourceObject,
-                                                  ParseGoal parseGoal)
+template <class ParseHandler, typename Unit>
+GeneralParser<ParseHandler, Unit>::GeneralParser(JSContext* cx, LifoAlloc& alloc,
+                                                 const ReadOnlyCompileOptions& options,
+                                                 const Unit* units, size_t length,
+                                                 bool foldConstants,
+                                                 UsedNameTracker& usedNames,
+                                                 SyntaxParser* syntaxParser,
+                                                 LazyScript* lazyOuterFunction,
+                                                 ScriptSourceObject* sourceObject,
+                                                 ParseGoal parseGoal)
   : Base(cx, alloc, options, foldConstants, usedNames, syntaxParser, lazyOuterFunction,
          sourceObject, parseGoal),
-    tokenStream(cx, options, chars, length)
+    tokenStream(cx, options, units, length)
 {}
 
-template <typename CharT>
+template <typename Unit>
 void
-Parser<SyntaxParseHandler, CharT>::setAwaitHandling(AwaitHandling awaitHandling)
+Parser<SyntaxParseHandler, Unit>::setAwaitHandling(AwaitHandling awaitHandling)
 {
     this->awaitHandling_ = awaitHandling;
 }
 
-template <typename CharT>
+template <typename Unit>
 void
-Parser<FullParseHandler, CharT>::setAwaitHandling(AwaitHandling awaitHandling)
+Parser<FullParseHandler, Unit>::setAwaitHandling(AwaitHandling awaitHandling)
 {
     this->awaitHandling_ = awaitHandling;
     if (SyntaxParser* syntaxParser = getSyntaxParser()) {
         syntaxParser->setAwaitHandling(awaitHandling);
     }
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 inline void
-GeneralParser<ParseHandler, CharT>::setAwaitHandling(AwaitHandling awaitHandling)
+GeneralParser<ParseHandler, Unit>::setAwaitHandling(AwaitHandling awaitHandling)
 {
     asFinalParser()->setAwaitHandling(awaitHandling);
 }
 
-template <typename CharT>
+template <typename Unit>
 void
-Parser<SyntaxParseHandler, CharT>::setInParametersOfAsyncFunction(bool inParameters)
+Parser<SyntaxParseHandler, Unit>::setInParametersOfAsyncFunction(bool inParameters)
 {
     this->inParametersOfAsyncFunction_ = inParameters;
 }
 
-template <typename CharT>
+template <typename Unit>
 void
-Parser<FullParseHandler, CharT>::setInParametersOfAsyncFunction(bool inParameters)
+Parser<FullParseHandler, Unit>::setInParametersOfAsyncFunction(bool inParameters)
 {
     this->inParametersOfAsyncFunction_ = inParameters;
     if (SyntaxParser* syntaxParser = getSyntaxParser()) {
         syntaxParser->setInParametersOfAsyncFunction(inParameters);
     }
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 inline void
-GeneralParser<ParseHandler, CharT>::setInParametersOfAsyncFunction(bool inParameters)
+GeneralParser<ParseHandler, Unit>::setInParametersOfAsyncFunction(bool inParameters)
 {
     asFinalParser()->setInParametersOfAsyncFunction(inParameters);
 }
 
 ObjectBox*
 ParserBase::newObjectBox(JSObject* obj)
 {
     MOZ_ASSERT(obj);
@@ -1159,19 +1159,19 @@ ParserBase::setSourceMapInfo()
 
     return true;
 }
 
 
 /*
  * Parse a top-level JS script.
  */
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::ListNodeType
-GeneralParser<ParseHandler, CharT>::parse()
+GeneralParser<ParseHandler, Unit>::parse()
 {
     MOZ_ASSERT(checkOptionsCalled);
 
     Directives directives(options().strictOption);
     GlobalSharedContext globalsc(context, ScopeKind::Global,
                                  directives, options().extraWarningsOption);
     SourceParseContext globalpc(this, &globalsc, /* newDirectives = */ nullptr);
     if (!globalpc.init()) {
@@ -1242,20 +1242,20 @@ ParserBase::hasValidSimpleStrictParamete
         MOZ_ASSERT(name);
         if (!isValidStrictBinding(name->asPropertyName())) {
             return false;
         }
     }
     return true;
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 void
-GeneralParser<ParseHandler, CharT>::reportMissingClosing(unsigned errorNumber, unsigned noteNumber,
-                                                         uint32_t openedPos)
+GeneralParser<ParseHandler, Unit>::reportMissingClosing(unsigned errorNumber, unsigned noteNumber,
+                                                        uint32_t openedPos)
 {
     auto notes = MakeUnique<JSErrorNotes>();
     if (!notes) {
         ReportOutOfMemory(pc->sc()->context);
         return;
     }
 
     uint32_t line, column;
@@ -1273,21 +1273,21 @@ GeneralParser<ParseHandler, CharT>::repo
                              noteNumber, lineNumber, columnNumber))
     {
         return;
     }
 
     errorWithNotes(std::move(notes), errorNumber);
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 void
-GeneralParser<ParseHandler, CharT>::reportRedeclaration(HandlePropertyName name,
-                                                        DeclarationKind prevKind,
-                                                        TokenPos pos, uint32_t prevPos)
+GeneralParser<ParseHandler, Unit>::reportRedeclaration(HandlePropertyName name,
+                                                       DeclarationKind prevKind,
+                                                       TokenPos pos, uint32_t prevPos)
 {
     UniqueChars bytes = AtomToPrintableString(context, name);
     if (!bytes) {
         return;
     }
 
     if (prevPos == DeclaredNameInfo::npos) {
         errorAt(pos.begin, JSMSG_REDECLARED_VAR, DeclarationKindString(prevKind), bytes.get());
@@ -1326,23 +1326,23 @@ GeneralParser<ParseHandler, CharT>::repo
 // function definition and the arguments specified by the Function
 // constructor.
 //
 // The 'disallowDuplicateParams' bool indicates whether the use of another
 // feature (destructuring or default arguments) disables duplicate arguments.
 // (ECMA-262 requires us to support duplicate parameter names, but, for newer
 // features, we consider the code to have "opted in" to higher standards and
 // forbid duplicates.)
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 bool
-GeneralParser<ParseHandler, CharT>::notePositionalFormalParameter(CodeNodeType funNode,
-                                                                  HandlePropertyName name,
-                                                                  uint32_t beginPos,
-                                                                  bool disallowDuplicateParams,
-                                                                  bool* duplicatedParam)
+GeneralParser<ParseHandler, Unit>::notePositionalFormalParameter(CodeNodeType funNode,
+                                                                 HandlePropertyName name,
+                                                                 uint32_t beginPos,
+                                                                 bool disallowDuplicateParams,
+                                                                 bool* duplicatedParam)
 {
     if (AddDeclaredNamePtr p = pc->functionScope().lookupDeclaredNameForAdd(name)) {
         if (disallowDuplicateParams) {
             error(JSMSG_BAD_DUP_ARGS);
             return false;
         }
 
         // Strict-mode disallows duplicate args. We may not know whether we are
@@ -1628,21 +1628,21 @@ ParseContext::annexBAppliesToLexicalFunc
         }
     }
 
     // If an early error would have occurred already, this function should not
     // exhibit Annex B.3.3 semantics.
     return !redeclaredKind;
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 bool
-GeneralParser<ParseHandler, CharT>::checkLexicalDeclarationDirectlyWithinBlock(ParseContext::Statement& stmt,
-                                                                               DeclarationKind kind,
-                                                                               TokenPos pos)
+GeneralParser<ParseHandler, Unit>::checkLexicalDeclarationDirectlyWithinBlock(ParseContext::Statement& stmt,
+                                                                              DeclarationKind kind,
+                                                                              TokenPos pos)
 {
     MOZ_ASSERT(DeclarationKindIsLexical(kind));
 
     // It is an early error to declare a lexical binding not directly
     // within a block.
     if (!StatementKindIsBraced(stmt.kind()) &&
         stmt.kind() != StatementKind::ForLoopLexicalHead)
     {
@@ -1652,20 +1652,20 @@ GeneralParser<ParseHandler, CharT>::chec
                 : JSMSG_LEXICAL_DECL_NOT_IN_BLOCK,
                 DeclarationKindString(kind));
         return false;
     }
 
     return true;
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 bool
-GeneralParser<ParseHandler, CharT>::noteDeclaredName(HandlePropertyName name, DeclarationKind kind,
-                                                     TokenPos pos)
+GeneralParser<ParseHandler, Unit>::noteDeclaredName(HandlePropertyName name, DeclarationKind kind,
+                                                    TokenPos pos)
 {
     // The asm.js validator does all its own symbol-table management so, as an
     // optimization, avoid doing any work here.
     if (pc->useAsmOrInsideUseAsm()) {
         return true;
     }
 
     switch (kind) {
@@ -1907,19 +1907,19 @@ PerHandlerParser<ParseHandler>::propagat
     if (isSyntaxParser && !pc->closedOverBindingsForLazy().append(nullptr)) {
         ReportOutOfMemory(context);
         return false;
     }
 
     return true;
 }
 
-template <typename CharT>
+template <typename Unit>
 bool
-Parser<FullParseHandler, CharT>::checkStatementsEOF()
+Parser<FullParseHandler, Unit>::checkStatementsEOF()
 {
     // This is designed to be paired with parsing a statement list at the top
     // level.
     //
     // The statementList() call breaks on TokenKind::RightCurly, so make sure
     // we've reached EOF here.
     TokenKind tt;
     if (!tokenStream.peekToken(&tt, TokenStream::Operand)) {
@@ -2372,19 +2372,19 @@ PerHandlerParser<FullParseHandler>::fini
     Maybe<LexicalScope::Data*> bindings = newLexicalScopeData(scope);
     if (!bindings) {
         return nullptr;
     }
 
     return handler.newLexicalScope(*bindings, body);
 }
 
-template <typename CharT>
+template <typename Unit>
 LexicalScopeNode*
-Parser<FullParseHandler, CharT>::evalBody(EvalSharedContext* evalsc)
+Parser<FullParseHandler, Unit>::evalBody(EvalSharedContext* evalsc)
 {
     SourceParseContext evalpc(this, evalsc, /* newDirectives = */ nullptr);
     if (!evalpc.init()) {
         return nullptr;
     }
 
     ParseContext::VarScope varScope(this);
     if (!varScope.init(pc)) {
@@ -2458,19 +2458,19 @@ Parser<FullParseHandler, CharT>::evalBod
     if (!bindings) {
         return nullptr;
     }
     evalsc->bindings = *bindings;
 
     return body;
 }
 
-template <typename CharT>
+template <typename Unit>
 ListNode*
-Parser<FullParseHandler, CharT>::globalBody(GlobalSharedContext* globalsc)
+Parser<FullParseHandler, Unit>::globalBody(GlobalSharedContext* globalsc)
 {
     SourceParseContext globalpc(this, globalsc, /* newDirectives = */ nullptr);
     if (!globalpc.init()) {
         return nullptr;
     }
 
     ParseContext::VarScope varScope(this);
     if (!varScope.init(pc)) {
@@ -2507,19 +2507,19 @@ Parser<FullParseHandler, CharT>::globalB
     if (!bindings) {
         return nullptr;
     }
     globalsc->bindings = *bindings;
 
     return body;
 }
 
-template <typename CharT>
+template <typename Unit>
 CodeNode*
-Parser<FullParseHandler, CharT>::moduleBody(ModuleSharedContext* modulesc)
+Parser<FullParseHandler, Unit>::moduleBody(ModuleSharedContext* modulesc)
 {
     MOZ_ASSERT(checkOptionsCalled);
 
     SourceParseContext modulepc(this, modulesc, nullptr);
     if (!modulepc.init()) {
         return null();
     }
 
@@ -2528,17 +2528,17 @@ Parser<FullParseHandler, CharT>::moduleB
         return nullptr;
     }
 
     CodeNodeType moduleNode = handler.newModule(pos());
     if (!moduleNode) {
         return null();
     }
 
-    AutoAwaitIsKeyword<FullParseHandler, CharT> awaitIsKeyword(this, AwaitIsModuleKeyword);
+    AutoAwaitIsKeyword<FullParseHandler, Unit> awaitIsKeyword(this, AwaitIsModuleKeyword);
     ListNode* stmtList = statementList(YieldIsName);
     if (!stmtList) {
         return null();
     }
 
     MOZ_ASSERT(stmtList->isKind(ParseNodeKind::StatementList));
     moduleNode->setBody(&stmtList->as<ListNode>());
 
@@ -2592,19 +2592,19 @@ Parser<FullParseHandler, CharT>::moduleB
     if (!bindings) {
         return nullptr;
     }
 
     modulesc->bindings = *bindings;
     return moduleNode;
 }
 
-template <typename CharT>
+template <typename Unit>
 SyntaxParseHandler::CodeNodeType
-Parser<SyntaxParseHandler, CharT>::moduleBody(ModuleSharedContext* modulesc)
+Parser<SyntaxParseHandler, Unit>::moduleBody(ModuleSharedContext* modulesc)
 {
     MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
     return SyntaxParseHandler::NodeFailure;
 }
 
 bool
 ParserBase::hasUsedFunctionSpecialName(HandlePropertyName name)
 {
@@ -2835,25 +2835,24 @@ static AwaitHandling
 GetAwaitHandling(FunctionAsyncKind asyncKind)
 {
     if (asyncKind == FunctionAsyncKind::SyncFunction) {
         return AwaitIsName;
     }
     return AwaitIsKeyword;
 }
 
-template <typename CharT>
+template <typename Unit>
 CodeNode*
-Parser<FullParseHandler, CharT>::standaloneFunction(HandleFunction fun,
-                                                    HandleScope enclosingScope,
-                                                    const Maybe<uint32_t>& parameterListEnd,
-                                                    GeneratorKind generatorKind,
-                                                    FunctionAsyncKind asyncKind,
-                                                    Directives inheritedDirectives,
-                                                    Directives* newDirectives)
+Parser<FullParseHandler, Unit>::standaloneFunction(HandleFunction fun, HandleScope enclosingScope,
+                                                   const Maybe<uint32_t>& parameterListEnd,
+                                                   GeneratorKind generatorKind,
+                                                   FunctionAsyncKind asyncKind,
+                                                   Directives inheritedDirectives,
+                                                   Directives* newDirectives)
 {
     MOZ_ASSERT(checkOptionsCalled);
 
     // Skip prelude.
     TokenKind tt;
     if (!tokenStream.getToken(&tt, TokenStream::Operand)) {
         return null();
     }
@@ -2904,17 +2903,17 @@ Parser<FullParseHandler, CharT>::standal
     SourceParseContext funpc(this, funbox, newDirectives);
     if (!funpc.init()) {
         return null();
     }
     funpc.setIsStandaloneFunctionBody();
 
     YieldHandling yieldHandling = GetYieldHandling(generatorKind);
     AwaitHandling awaitHandling = GetAwaitHandling(asyncKind);
-    AutoAwaitIsKeyword<FullParseHandler, CharT> awaitIsKeyword(this, awaitHandling);
+    AutoAwaitIsKeyword<FullParseHandler, Unit> awaitIsKeyword(this, awaitHandling);
     if (!functionFormalParametersAndBody(InAllowed, yieldHandling, &funNode,
                                          FunctionSyntaxKind::Statement,
                                          parameterListEnd, /* isStandaloneFunction = */ true))
     {
         return null();
     }
 
     if (!tokenStream.getToken(&tt, TokenStream::Operand)) {
@@ -3014,21 +3013,20 @@ PerHandlerParser<ParseHandler>::declareF
         if (pc->sc()->hasDebuggerStatement()) {
             funbox->setDefinitelyNeedsArgsObj();
         }
     }
 
     return true;
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::LexicalScopeNodeType
-GeneralParser<ParseHandler, CharT>::functionBody(InHandling inHandling,
-                                                 YieldHandling yieldHandling,
-                                                 FunctionSyntaxKind kind, FunctionBodyType type)
+GeneralParser<ParseHandler, Unit>::functionBody(InHandling inHandling, YieldHandling yieldHandling,
+                                                FunctionSyntaxKind kind, FunctionBodyType type)
 {
     MOZ_ASSERT(pc->isFunctionBox());
 
 #ifdef DEBUG
     uint32_t startYieldOffset = pc->lastYieldOffset;
 #endif
 
     Node body;
@@ -3197,19 +3195,19 @@ JSFunction*
 ParserBase::newFunction(HandleAtom atom, FunctionSyntaxKind kind,
                         GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
                         HandleObject proto)
 {
     return AllocNewFunction(context, atom, kind, generatorKind, asyncKind, proto,
                             options().selfHostingMode, pc->isFunctionBox());
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 bool
-GeneralParser<ParseHandler, CharT>::matchOrInsertSemicolon()
+GeneralParser<ParseHandler, Unit>::matchOrInsertSemicolon()
 {
     TokenKind tt = TokenKind::Eof;
     if (!tokenStream.peekTokenSameLine(&tt, TokenStream::Operand)) {
         return false;
     }
     if (tt != TokenKind::Eof &&
         tt != TokenKind::Eol &&
         tt != TokenKind::Semi &&
@@ -3291,21 +3289,20 @@ ParserBase::prefixAccessorName(PropertyT
     RootedString str(context, ConcatStrings<CanGC>(context, prefix, propAtom));
     if (!str) {
         return nullptr;
     }
 
     return AtomizeString(context, str);
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 bool
-GeneralParser<ParseHandler, CharT>::functionArguments(YieldHandling yieldHandling,
-                                                      FunctionSyntaxKind kind,
-                                                      CodeNodeType funNode)
+GeneralParser<ParseHandler, Unit>::functionArguments(YieldHandling yieldHandling,
+                                                     FunctionSyntaxKind kind, CodeNodeType funNode)
 {
     FunctionBox* funbox = pc->functionBox();
 
     bool parenFreeArrow = false;
     // Modifier for the following tokens.
     // TokenStream::None for the following cases:
     //   async a => 1
     //         ^
@@ -3603,20 +3600,20 @@ GeneralParser<ParseHandler, CharT>::func
     } else if (kind == FunctionSyntaxKind::Setter) {
         error(JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", "");
         return false;
     }
 
     return true;
 }
 
-template <typename CharT>
+template <typename Unit>
 bool
-Parser<FullParseHandler, CharT>::skipLazyInnerFunction(CodeNode* funNode, uint32_t toStringStart,
-                                                       FunctionSyntaxKind kind, bool tryAnnexB)
+Parser<FullParseHandler, Unit>::skipLazyInnerFunction(CodeNode* funNode, uint32_t toStringStart,
+                                                      FunctionSyntaxKind kind, bool tryAnnexB)
 {
     // When a lazily-parsed function is called, we only fully parse (and emit)
     // that function, not any of its nested children. The initial syntax-only
     // parse recorded the free variables of nested functions and their extents,
     // so we can skip over them after accounting for their free variables.
 
     RootedFunction fun(context, handler.nextLazyInnerFunction());
     FunctionBox* funbox =
@@ -3640,41 +3637,39 @@ Parser<FullParseHandler, CharT>::skipLaz
     // Append possible Annex B function box only upon successfully parsing.
     if (tryAnnexB && !pc->innermostScope()->addPossibleAnnexBFunctionBox(pc, funbox)) {
         return false;
     }
 
     return true;
 }
 
-template <typename CharT>
+template <typename Unit>
 bool
-Parser<SyntaxParseHandler, CharT>::skipLazyInnerFunction(CodeNodeType funNode,
-                                                         uint32_t toStringStart,
-                                                         FunctionSyntaxKind kind,
-                                                         bool tryAnnexB)
+Parser<SyntaxParseHandler, Unit>::skipLazyInnerFunction(CodeNodeType funNode,
+                                                        uint32_t toStringStart,
+                                                        FunctionSyntaxKind kind, bool tryAnnexB)
 {
     MOZ_CRASH("Cannot skip lazy inner functions when syntax parsing");
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 bool
-GeneralParser<ParseHandler, CharT>::skipLazyInnerFunction(CodeNodeType funNode,
-                                                          uint32_t toStringStart,
-                                                          FunctionSyntaxKind kind,
-                                                          bool tryAnnexB)
+GeneralParser<ParseHandler, Unit>::skipLazyInnerFunction(CodeNodeType funNode,
+                                                         uint32_t toStringStart,
+                                                         FunctionSyntaxKind kind, bool tryAnnexB)
 {
     return asFinalParser()->skipLazyInnerFunction(funNode, toStringStart, kind, tryAnnexB);
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 bool
-GeneralParser<ParseHandler, CharT>::addExprAndGetNextTemplStrToken(YieldHandling yieldHandling,
-                                                                   ListNodeType nodeList,
-                                                                   TokenKind* ttp)
+GeneralParser<ParseHandler, Unit>::addExprAndGetNextTemplStrToken(YieldHandling yieldHandling,
+                                                                  ListNodeType nodeList,
+                                                                  TokenKind* ttp)
 {
     Node pn = expr(InAllowed, yieldHandling, TripledotProhibited);
     if (!pn) {
         return false;
     }
     handler.addList(nodeList, pn);
 
     TokenKind tt;
@@ -3684,21 +3679,20 @@ GeneralParser<ParseHandler, CharT>::addE
     if (tt != TokenKind::RightCurly) {
         error(JSMSG_TEMPLSTR_UNTERM_EXPR);
         return false;
     }
 
     return tokenStream.getToken(ttp, TokenStream::TemplateTail);
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 bool
-GeneralParser<ParseHandler, CharT>::taggedTemplate(YieldHandling yieldHandling,
-                                                   ListNodeType tagArgsList,
-                                                   TokenKind tt)
+GeneralParser<ParseHandler, Unit>::taggedTemplate(YieldHandling yieldHandling,
+                                                  ListNodeType tagArgsList, TokenKind tt)
 {
     CallSiteNodeType callSiteObjNode = handler.newCallSiteObject(pos().begin);
     if (!callSiteObjNode) {
         return false;
     }
     handler.addList(tagArgsList, callSiteObjNode);
 
     while (true) {
@@ -3712,19 +3706,19 @@ GeneralParser<ParseHandler, CharT>::tagg
         if (!addExprAndGetNextTemplStrToken(yieldHandling, tagArgsList, &tt)) {
             return false;
         }
     }
     handler.setEndPosition(tagArgsList, callSiteObjNode);
     return true;
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::ListNodeType
-GeneralParser<ParseHandler, CharT>::templateLiteral(YieldHandling yieldHandling)
+GeneralParser<ParseHandler, Unit>::templateLiteral(YieldHandling yieldHandling)
 {
     NameNodeType literal = noSubstitutionUntaggedTemplate();
     if (!literal) {
         return null();
     }
 
     ListNodeType nodeList = handler.newList(ParseNodeKind::TemplateStringList, literal);
     if (!nodeList) {
@@ -3742,25 +3736,25 @@ GeneralParser<ParseHandler, CharT>::temp
             return null();
         }
 
         handler.addList(nodeList, literal);
     } while (tt == TokenKind::TemplateHead);
     return nodeList;
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::CodeNodeType
-GeneralParser<ParseHandler, CharT>::functionDefinition(CodeNodeType funNode, uint32_t toStringStart,
-                                                       InHandling inHandling,
-                                                       YieldHandling yieldHandling,
-                                                       HandleAtom funName, FunctionSyntaxKind kind,
-                                                       GeneratorKind generatorKind,
-                                                       FunctionAsyncKind asyncKind,
-                                                       bool tryAnnexB /* = false */)
+GeneralParser<ParseHandler, Unit>::functionDefinition(CodeNodeType funNode, uint32_t toStringStart,
+                                                      InHandling inHandling,
+                                                      YieldHandling yieldHandling,
+                                                      HandleAtom funName, FunctionSyntaxKind kind,
+                                                      GeneratorKind generatorKind,
+                                                      FunctionAsyncKind asyncKind,
+                                                      bool tryAnnexB /* = false */)
 {
     MOZ_ASSERT_IF(kind == FunctionSyntaxKind::Statement, funName);
 
     // When fully parsing a LazyScript, we do not fully reparse its inner
     // functions, which are also lazy. Instead, their free variables and
     // source extents are recorded and may be skipped.
     if (handler.canSkipLazyInnerFunctions()) {
         if (!skipLazyInnerFunction(funNode, toStringStart, kind, tryAnnexB)) {
@@ -3820,29 +3814,28 @@ GeneralParser<ParseHandler, CharT>::func
         // functionFormalParametersAndBody may have already set body before
         // failing.
         handler.setFunctionFormalParametersAndBody(funNode, null());
     }
 
     return funNode;
 }
 
-template <typename CharT>
+template <typename Unit>
 bool
-Parser<FullParseHandler, CharT>::trySyntaxParseInnerFunction(CodeNode** funNode,
-                                                             HandleFunction fun,
-                                                             uint32_t toStringStart,
-                                                             InHandling inHandling,
-                                                             YieldHandling yieldHandling,
-                                                             FunctionSyntaxKind kind,
-                                                             GeneratorKind generatorKind,
-                                                             FunctionAsyncKind asyncKind,
-                                                             bool tryAnnexB,
-                                                             Directives inheritedDirectives,
-                                                             Directives* newDirectives)
+Parser<FullParseHandler, Unit>::trySyntaxParseInnerFunction(CodeNode** funNode, HandleFunction fun,
+                                                            uint32_t toStringStart,
+                                                            InHandling inHandling,
+                                                            YieldHandling yieldHandling,
+                                                            FunctionSyntaxKind kind,
+                                                            GeneratorKind generatorKind,
+                                                            FunctionAsyncKind asyncKind,
+                                                            bool tryAnnexB,
+                                                            Directives inheritedDirectives,
+                                                            Directives* newDirectives)
 {
     // Try a syntax parse for this inner function.
     do {
         // If we're assuming this function is an IIFE, always perform a full
         // parse to avoid the overhead of a lazy syntax-only parse. Although
         // the prediction may be incorrect, IIFEs are common enough that it
         // pays off for lots of code.
         if ((*funNode)->isLikelyIIFE() &&
@@ -3919,70 +3912,72 @@ Parser<FullParseHandler, CharT>::trySynt
     if (!innerFunc) {
         return false;
     }
 
     *funNode = innerFunc;
     return true;
 }
 
-template <typename CharT>
+template <typename Unit>
 bool
-Parser<SyntaxParseHandler, CharT>::trySyntaxParseInnerFunction(CodeNodeType* funNode, HandleFunction fun,
-                                                               uint32_t toStringStart,
-                                                               InHandling inHandling,
-                                                               YieldHandling yieldHandling,
-                                                               FunctionSyntaxKind kind,
-                                                               GeneratorKind generatorKind,
-                                                               FunctionAsyncKind asyncKind,
-                                                               bool tryAnnexB,
-                                                               Directives inheritedDirectives,
-                                                               Directives* newDirectives)
+Parser<SyntaxParseHandler, Unit>::trySyntaxParseInnerFunction(CodeNodeType* funNode,
+                                                              HandleFunction fun,
+                                                              uint32_t toStringStart,
+                                                              InHandling inHandling,
+                                                              YieldHandling yieldHandling,
+                                                              FunctionSyntaxKind kind,
+                                                              GeneratorKind generatorKind,
+                                                              FunctionAsyncKind asyncKind,
+                                                              bool tryAnnexB,
+                                                              Directives inheritedDirectives,
+                                                              Directives* newDirectives)
 {
     // This is already a syntax parser, so just parse the inner function.
     CodeNodeType innerFunc =
         innerFunction(*funNode, pc, fun, toStringStart, inHandling, yieldHandling, kind,
                       generatorKind, asyncKind, tryAnnexB, inheritedDirectives, newDirectives);
 
     if (!innerFunc) {
         return false;
     }
 
     *funNode = innerFunc;
     return true;
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 inline bool
-GeneralParser<ParseHandler, CharT>::trySyntaxParseInnerFunction(CodeNodeType* funNode, HandleFunction fun,
-                                                                uint32_t toStringStart,
-                                                                InHandling inHandling,
-                                                                YieldHandling yieldHandling,
-                                                                FunctionSyntaxKind kind,
-                                                                GeneratorKind generatorKind,
-                                                                FunctionAsyncKind asyncKind,
-                                                                bool tryAnnexB,
-                                                                Directives inheritedDirectives,
-                                                                Directives* newDirectives)
+GeneralParser<ParseHandler, Unit>::trySyntaxParseInnerFunction(CodeNodeType* funNode,
+                                                               HandleFunction fun,
+                                                               uint32_t toStringStart,
+                                                               InHandling inHandling,
+                                                               YieldHandling yieldHandling,
+                                                               FunctionSyntaxKind kind,
+                                                               GeneratorKind generatorKind,
+                                                               FunctionAsyncKind asyncKind,
+                                                               bool tryAnnexB,
+                                                               Directives inheritedDirectives,
+                                                               Directives* newDirectives)
 {
     return asFinalParser()->trySyntaxParseInnerFunction(funNode, fun, toStringStart, inHandling,
                                                         yieldHandling, kind, generatorKind,
                                                         asyncKind, tryAnnexB, inheritedDirectives,
                                                         newDirectives);
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::CodeNodeType
-GeneralParser<ParseHandler, CharT>::innerFunctionForFunctionBox(CodeNodeType funNode,
-                                                                ParseContext* outerpc,
-                                                                FunctionBox* funbox,
-                                                                InHandling inHandling,
-                                                                YieldHandling yieldHandling,
-                                                                FunctionSyntaxKind kind,
-                                                                Directives* newDirectives)
+GeneralParser<ParseHandler, Unit>::innerFunctionForFunctionBox(CodeNodeType funNode,
+                                                               ParseContext* outerpc,
+                                                               FunctionBox* funbox,
+                                                               InHandling inHandling,
+                                                               YieldHandling yieldHandling,
+                                                               FunctionSyntaxKind kind,
+                                                               Directives* newDirectives)
 {
     // Note that it is possible for outerpc != this->pc, as we may be
     // attempting to syntax parse an inner function from an outer full
     // parser. In that case, outerpc is a SourceParseContext from the full parser
     // instead of the current top of the stack of the syntax parser.
 
     // Push a new ParseContext.
     SourceParseContext funpc(this, funbox, newDirectives);
@@ -3996,27 +3991,27 @@ GeneralParser<ParseHandler, CharT>::inne
 
     if (!leaveInnerFunction(outerpc)) {
         return null();
     }
 
     return funNode;
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::CodeNodeType
-GeneralParser<ParseHandler, CharT>::innerFunction(CodeNodeType funNode, ParseContext* outerpc,
-                                                  HandleFunction fun, uint32_t toStringStart,
-                                                  InHandling inHandling,
-                                                  YieldHandling yieldHandling,
-                                                  FunctionSyntaxKind kind,
-                                                  GeneratorKind generatorKind,
-                                                  FunctionAsyncKind asyncKind, bool tryAnnexB,
-                                                  Directives inheritedDirectives,
-                                                  Directives* newDirectives)
+GeneralParser<ParseHandler, Unit>::innerFunction(CodeNodeType funNode, ParseContext* outerpc,
+                                                 HandleFunction fun, uint32_t toStringStart,
+                                                 InHandling inHandling,
+                                                 YieldHandling yieldHandling,
+                                                 FunctionSyntaxKind kind,
+                                                 GeneratorKind generatorKind,
+                                                 FunctionAsyncKind asyncKind, bool tryAnnexB,
+                                                 Directives inheritedDirectives,
+                                                 Directives* newDirectives)
 {
     // Note that it is possible for outerpc != this->pc, as we may be
     // attempting to syntax parse an inner function from an outer full
     // parser. In that case, outerpc is a SourceParseContext from the full parser
     // instead of the current top of the stack of the syntax parser.
 
     FunctionBox* funbox = newFunctionBox(funNode, fun, toStringStart, inheritedDirectives,
                                          generatorKind, asyncKind);
@@ -4037,19 +4032,19 @@ GeneralParser<ParseHandler, CharT>::inne
         if (!pc->innermostScope()->addPossibleAnnexBFunctionBox(pc, funbox)) {
             return null();
         }
     }
 
     return innerFunc;
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 bool
-GeneralParser<ParseHandler, CharT>::appendToCallSiteObj(CallSiteNodeType callSiteObj)
+GeneralParser<ParseHandler, Unit>::appendToCallSiteObj(CallSiteNodeType callSiteObj)
 {
     Node cookedNode = noSubstitutionTaggedTemplate();
     if (!cookedNode) {
         return false;
     }
 
     JSAtom* atom = tokenStream.getRawTemplateStringAtom();
     if (!atom) {
@@ -4059,21 +4054,21 @@ GeneralParser<ParseHandler, CharT>::appe
     if (!rawNode) {
         return false;
     }
 
     handler.addToCallSiteObject(callSiteObj, rawNode, cookedNode);
     return true;
 }
 
-template <typename CharT>
+template <typename Unit>
 CodeNode*
-Parser<FullParseHandler, CharT>::standaloneLazyFunction(HandleFunction fun, uint32_t toStringStart,
-                                                        bool strict, GeneratorKind generatorKind,
-                                                        FunctionAsyncKind asyncKind)
+Parser<FullParseHandler, Unit>::standaloneLazyFunction(HandleFunction fun, uint32_t toStringStart,
+                                                       bool strict, GeneratorKind generatorKind,
+                                                       FunctionAsyncKind asyncKind)
 {
     MOZ_ASSERT(checkOptionsCalled);
 
     CodeNodeType funNode = handler.newFunctionStatement(pos());
     if (!funNode) {
         return null();
     }
 
@@ -4126,41 +4121,41 @@ Parser<FullParseHandler, CharT>::standal
     if (!FoldConstants(context, &node, this)) {
         return null();
     }
     funNode = &node->as<CodeNode>();
 
     return funNode;
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 bool
-GeneralParser<ParseHandler, CharT>::functionFormalParametersAndBody(InHandling inHandling,
-                                                                    YieldHandling yieldHandling,
-                                                                    CodeNodeType* funNode,
-                                                                    FunctionSyntaxKind kind,
-                                                                    const Maybe<uint32_t>& parameterListEnd /* = Nothing() */,
-                                                                    bool isStandaloneFunction /* = false */)
+GeneralParser<ParseHandler, Unit>::functionFormalParametersAndBody(InHandling inHandling,
+                                                                   YieldHandling yieldHandling,
+                                                                   CodeNodeType* funNode,
+                                                                   FunctionSyntaxKind kind,
+                                                                   const Maybe<uint32_t>& parameterListEnd /* = Nothing() */,
+                                                                   bool isStandaloneFunction /* = false */)
 {
     // Given a properly initialized parse context, try to parse an actual
     // function without concern for conversion to strict mode, use of lazy
     // parsing and such.
 
     FunctionBox* funbox = pc->functionBox();
     RootedFunction fun(context, funbox->function());
 
     // See below for an explanation why arrow function parameters and arrow
     // function bodies are parsed with different yield/await settings.
     {
         AwaitHandling awaitHandling =
             (funbox->isAsync() || (kind == FunctionSyntaxKind::Arrow && awaitIsKeyword()))
             ? AwaitIsKeyword
             : AwaitIsName;
-        AutoAwaitIsKeyword<ParseHandler, CharT> awaitIsKeyword(this, awaitHandling);
-        AutoInParametersOfAsyncFunction<ParseHandler, CharT> inParameters(this, funbox->isAsync());
+        AutoAwaitIsKeyword<ParseHandler, Unit> awaitIsKeyword(this, awaitHandling);
+        AutoInParametersOfAsyncFunction<ParseHandler, Unit> inParameters(this, funbox->isAsync());
         if (!functionArguments(yieldHandling, kind, *funNode)) {
             return false;
         }
     }
 
     Maybe<ParseContext::VarScope> varScope;
     if (funbox->hasParameterExprs) {
         varScope.emplace(this);
@@ -4215,18 +4210,18 @@ GeneralParser<ParseHandler, CharT>::func
     // whether the arrow function is enclosed in a generator function or not.
     // Whereas the |yield| in the function body is always parsed as a name.
     // The same goes when parsing |await| in arrow functions.
     YieldHandling bodyYieldHandling = GetYieldHandling(pc->generatorKind());
     AwaitHandling bodyAwaitHandling = GetAwaitHandling(pc->asyncKind());
     bool inheritedStrict = pc->sc()->strict();
     LexicalScopeNodeType body;
     {
-        AutoAwaitIsKeyword<ParseHandler, CharT> awaitIsKeyword(this, bodyAwaitHandling);
-        AutoInParametersOfAsyncFunction<ParseHandler, CharT> inParameters(this, false);
+        AutoAwaitIsKeyword<ParseHandler, Unit> awaitIsKeyword(this, bodyAwaitHandling);
+        AutoInParametersOfAsyncFunction<ParseHandler, Unit> inParameters(this, false);
         body = functionBody(inHandling, bodyYieldHandling, kind, bodyType);
         if (!body) {
             return false;
         }
     }
 
     // Revalidate the function name when we transitioned to strict mode.
     if ((kind == FunctionSyntaxKind::Statement || kind == FunctionSyntaxKind::Expression) &&
@@ -4286,22 +4281,22 @@ GeneralParser<ParseHandler, CharT>::func
 
     handler.setEndPosition(body, pos().begin);
     handler.setEndPosition(*funNode, pos().end);
     handler.setFunctionBody(*funNode, body);
 
     return true;
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::CodeNodeType
-GeneralParser<ParseHandler, CharT>::functionStmt(uint32_t toStringStart,
-                                                 YieldHandling yieldHandling,
-                                                 DefaultHandling defaultHandling,
-                                                 FunctionAsyncKind asyncKind)
+GeneralParser<ParseHandler, Unit>::functionStmt(uint32_t toStringStart,
+                                                YieldHandling yieldHandling,
+                                                DefaultHandling defaultHandling,
+                                                FunctionAsyncKind asyncKind)
 {
     MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Function));
 
     // In sloppy mode, Annex B.3.2 allows labelled function declarations.
     // Otherwise it's a parse error.
     ParseContext::Statement* declaredInStmt = pc->innermostStatement();
     if (declaredInStmt && declaredInStmt->kind() == StatementKind::Label) {
         MOZ_ASSERT(!pc->sc()->strict(),
@@ -4383,25 +4378,24 @@ GeneralParser<ParseHandler, CharT>::func
     // Scope::propagateAndMarkAnnexBFunctionBoxes.
     bool tryAnnexB = kind == DeclarationKind::SloppyLexicalFunction;
 
     YieldHandling newYieldHandling = GetYieldHandling(generatorKind);
     return functionDefinition(funNode, toStringStart, InAllowed, newYieldHandling, name,
                               FunctionSyntaxKind::Statement, generatorKind, asyncKind, tryAnnexB);
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::CodeNodeType
-GeneralParser<ParseHandler, CharT>::functionExpr(uint32_t toStringStart,
-                                                 InvokedPrediction invoked,
-                                                 FunctionAsyncKind asyncKind)
+GeneralParser<ParseHandler, Unit>::functionExpr(uint32_t toStringStart, InvokedPrediction invoked,
+                                                FunctionAsyncKind asyncKind)
 {
     MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Function));
 
-    AutoAwaitIsKeyword<ParseHandler, CharT> awaitIsKeyword(this, GetAwaitHandling(asyncKind));
+    AutoAwaitIsKeyword<ParseHandler, Unit> awaitIsKeyword(this, GetAwaitHandling(asyncKind));
     GeneratorKind generatorKind = GeneratorKind::NotGenerator;
     TokenKind tt;
     if (!tokenStream.getToken(&tt)) {
         return null();
     }
 
     if (tt == TokenKind::Mul) {
         generatorKind = GeneratorKind::Generator;
@@ -4448,19 +4442,19 @@ IsEscapeFreeStringLiteral(const TokenPos
     /*
      * If the string's length in the source code is its length as a value,
      * accounting for the quotes, then it must not contain any escape
      * sequences or line continuations.
      */
     return pos.begin + str->length() + 2 == pos.end;
 }
 
-template <typename CharT>
+template <typename Unit>
 bool
-Parser<SyntaxParseHandler, CharT>::asmJS(ListNodeType list)
+Parser<SyntaxParseHandler, Unit>::asmJS(ListNodeType list)
 {
     // While asm.js could technically be validated and compiled during syntax
     // parsing, we have no guarantee that some later JS wouldn't abort the
     // syntax parse and cause us to re-parse (and re-compile) the asm.js module.
     // For simplicity, unconditionally abort the syntax parse when "use asm" is
     // encountered so that asm.js is always validated/compiled exactly once
     // during a full parse.
     MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
@@ -4520,19 +4514,19 @@ bool
 Parser<FullParseHandler, Utf8Unit>::asmJS(ListNodeType list)
 {
     // Just succeed without setting the asm.js directive flag.  Given Web
     // Assembly's rapid advance, it's probably not worth the trouble to really
     // support UTF-8 asm.js.
     return true;
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 inline bool
-GeneralParser<ParseHandler, CharT>::asmJS(ListNodeType list)
+GeneralParser<ParseHandler, Unit>::asmJS(ListNodeType list)
 {
     return asFinalParser()->asmJS(list);
 }
 
 /*
  * Recognize Directive Prologue members and directives. Assuming |pn| is a
  * candidate for membership in a directive prologue, recognize directives and
  * set |pc|'s flags accordingly. If |pn| is indeed part of a prologue, set its
@@ -4546,20 +4540,20 @@ GeneralParser<ParseHandler, CharT>::asmJ
  *   "use\x20loose"
  *   "use strict"
  * }
  *
  * That is, even though "use\x20loose" can never be a directive, now or in the
  * future (because of the hex escape), the Directive Prologue extends through it
  * to the "use strict" statement, which is indeed a directive.
  */
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 bool
-GeneralParser<ParseHandler, CharT>::maybeParseDirective(ListNodeType list, Node possibleDirective,
-                                                        bool* cont)
+GeneralParser<ParseHandler, Unit>::maybeParseDirective(ListNodeType list, Node possibleDirective,
+                                                       bool* cont)
 {
     TokenPos directivePos;
     JSAtom* directive = handler.isStringExprStatement(possibleDirective, &directivePos);
 
     *cont = !!directive;
     if (!*cont) {
         return true;
     }
@@ -4612,19 +4606,19 @@ GeneralParser<ParseHandler, CharT>::mayb
                 return asmJS(list);
             }
             return warningAt(directivePos.begin, JSMSG_USE_ASM_DIRECTIVE_FAIL);
         }
     }
     return true;
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::ListNodeType
-GeneralParser<ParseHandler, CharT>::statementList(YieldHandling yieldHandling)
+GeneralParser<ParseHandler, Unit>::statementList(YieldHandling yieldHandling)
 {
     if (!CheckRecursionLimit(context)) {
         return null();
     }
 
     ListNodeType stmtList = handler.newStatementList(pos());
     if (!stmtList) {
         return null();
@@ -4686,19 +4680,19 @@ GeneralParser<ParseHandler, CharT>::stat
         }
 
         handler.addStatementToList(stmtList, next);
     }
 
     return stmtList;
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::Node
-GeneralParser<ParseHandler, CharT>::condition(InHandling inHandling, YieldHandling yieldHandling)
+GeneralParser<ParseHandler, Unit>::condition(InHandling inHandling, YieldHandling yieldHandling)
 {
     MUST_MATCH_TOKEN(TokenKind::LeftParen, JSMSG_PAREN_BEFORE_COND);
 
     Node pn = exprInParens(inHandling, yieldHandling, TripledotProhibited);
     if (!pn) {
         return null();
     }
 
@@ -4708,20 +4702,20 @@ GeneralParser<ParseHandler, CharT>::cond
     if (handler.isUnparenthesizedAssignment(pn)) {
         if (!extraWarning(JSMSG_EQUAL_AS_ASSIGN)) {
             return null();
         }
     }
     return pn;
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 bool
-GeneralParser<ParseHandler, CharT>::matchLabel(YieldHandling yieldHandling,
-                                               MutableHandle<PropertyName*> label)
+GeneralParser<ParseHandler, Unit>::matchLabel(YieldHandling yieldHandling,
+                                              MutableHandle<PropertyName*> label)
 {
     TokenKind tt = TokenKind::Eof;
     if (!tokenStream.peekTokenSameLine(&tt, TokenStream::Operand)) {
         return false;
     }
 
     if (TokenKindIsPossibleIdentifier(tt)) {
         tokenStream.consumeKnownToken(tt, TokenStream::Operand);
@@ -4731,180 +4725,180 @@ GeneralParser<ParseHandler, CharT>::matc
             return false;
         }
     } else {
         label.set(nullptr);
     }
     return true;
 }
 
-template <class ParseHandler, typename CharT>
-GeneralParser<ParseHandler, CharT>::PossibleError::PossibleError(GeneralParser<ParseHandler, CharT>& parser)
+template <class ParseHandler, typename Unit>
+GeneralParser<ParseHandler, Unit>::PossibleError::PossibleError(GeneralParser<ParseHandler, Unit>& parser)
   : parser_(parser)
 {}
 
-template <class ParseHandler, typename CharT>
-typename GeneralParser<ParseHandler, CharT>::PossibleError::Error&
-GeneralParser<ParseHandler, CharT>::PossibleError::error(ErrorKind kind)
+template <class ParseHandler, typename Unit>
+typename GeneralParser<ParseHandler, Unit>::PossibleError::Error&
+GeneralParser<ParseHandler, Unit>::PossibleError::error(ErrorKind kind)
 {
     if (kind == ErrorKind::Expression) {
         return exprError_;
     }
     if (kind == ErrorKind::Destructuring) {
         return destructuringError_;
     }
     MOZ_ASSERT(kind == ErrorKind::DestructuringWarning);
     return destructuringWarning_;
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 void
-GeneralParser<ParseHandler, CharT>::PossibleError::setResolved(ErrorKind kind)
+GeneralParser<ParseHandler, Unit>::PossibleError::setResolved(ErrorKind kind)
 {
     error(kind).state_ = ErrorState::None;
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 bool
-GeneralParser<ParseHandler, CharT>::PossibleError::hasError(ErrorKind kind)
+GeneralParser<ParseHandler, Unit>::PossibleError::hasError(ErrorKind kind)
 {
     return error(kind).state_ == ErrorState::Pending;
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 bool
-GeneralParser<ParseHandler, CharT>::PossibleError::hasPendingDestructuringError()
+GeneralParser<ParseHandler, Unit>::PossibleError::hasPendingDestructuringError()
 {
     return hasError(ErrorKind::Destructuring);
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 void
-GeneralParser<ParseHandler, CharT>::PossibleError::setPending(ErrorKind kind, const TokenPos& pos,
-                                                              unsigned errorNumber)
+GeneralParser<ParseHandler, Unit>::PossibleError::setPending(ErrorKind kind, const TokenPos& pos,
+                                                             unsigned errorNumber)
 {
     // Don't overwrite a previously recorded error.
     if (hasError(kind)) {
         return;
     }
 
     // If we report an error later, we'll do it from the position where we set
     // the state to pending.
     Error& err = error(kind);
     err.offset_ = pos.begin;
     err.errorNumber_ = errorNumber;
     err.state_ = ErrorState::Pending;
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 void
-GeneralParser<ParseHandler, CharT>::PossibleError::setPendingDestructuringErrorAt(const TokenPos& pos,
-                                                                                  unsigned errorNumber)
+GeneralParser<ParseHandler, Unit>::PossibleError::setPendingDestructuringErrorAt(const TokenPos& pos,
+                                                                                 unsigned errorNumber)
 {
     setPending(ErrorKind::Destructuring, pos, errorNumber);
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 void
-GeneralParser<ParseHandler, CharT>::PossibleError::setPendingDestructuringWarningAt(const TokenPos& pos,
-                                                                                    unsigned errorNumber)
+GeneralParser<ParseHandler, Unit>::PossibleError::setPendingDestructuringWarningAt(const TokenPos& pos,
+                                                                                   unsigned errorNumber)
 {
     setPending(ErrorKind::DestructuringWarning, pos, errorNumber);
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 void
-GeneralParser<ParseHandler, CharT>::PossibleError::setPendingExpressionErrorAt(const TokenPos& pos,
-                                                                               unsigned errorNumber)
+GeneralParser<ParseHandler, Unit>::PossibleError::setPendingExpressionErrorAt(const TokenPos& pos,
+                                                                              unsigned errorNumber)
 {
     setPending(ErrorKind::Expression, pos, errorNumber);
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 bool
-GeneralParser<ParseHandler, CharT>::PossibleError::checkForError(ErrorKind kind)
+GeneralParser<ParseHandler, Unit>::PossibleError::checkForError(ErrorKind kind)
 {
     if (!hasError(kind)) {
         return true;
     }
 
     Error& err = error(kind);
     parser_.errorAt(err.offset_, err.errorNumber_);
     return false;
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 bool
-GeneralParser<ParseHandler, CharT>::PossibleError::checkForWarning(ErrorKind kind)
+GeneralParser<ParseHandler, Unit>::PossibleError::checkForWarning(ErrorKind kind)
 {
     if (!hasError(kind)) {
         return true;
     }
 
     Error& err = error(kind);
     return parser_.extraWarningAt(err.offset_, err.errorNumber_);
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 bool
-GeneralParser<ParseHandler, CharT>::PossibleError::checkForDestructuringErrorOrWarning()
+GeneralParser<ParseHandler, Unit>::PossibleError::checkForDestructuringErrorOrWarning()
 {
     // Clear pending expression error, because we're definitely not in an
     // expression context.
     setResolved(ErrorKind::Expression);
 
     // Report any pending destructuring error or warning.
     return checkForError(ErrorKind::Destructuring) &&
            checkForWarning(ErrorKind::DestructuringWarning);
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 bool
-GeneralParser<ParseHandler, CharT>::PossibleError::checkForExpressionError()
+GeneralParser<ParseHandler, Unit>::PossibleError::checkForExpressionError()
 {
     // Clear pending destructuring error or warning, because we're definitely
     // not in a destructuring context.
     setResolved(ErrorKind::Destructuring);
     setResolved(ErrorKind::DestructuringWarning);
 
     // Report any pending expression error.
     return checkForError(ErrorKind::Expression);
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 void
-GeneralParser<ParseHandler, CharT>::PossibleError::transferErrorTo(ErrorKind kind,
-                                                                   PossibleError* other)
+GeneralParser<ParseHandler, Unit>::PossibleError::transferErrorTo(ErrorKind kind,
+                                                                  PossibleError* other)
 {
     if (hasError(kind) && !other->hasError(kind)) {
         Error& err = error(kind);
         Error& otherErr = other->error(kind);
         otherErr.offset_ = err.offset_;
         otherErr.errorNumber_ = err.errorNumber_;
         otherErr.state_ = err.state_;
     }
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 void
-GeneralParser<ParseHandler, CharT>::PossibleError::transferErrorsTo(PossibleError* other)
+GeneralParser<ParseHandler, Unit>::PossibleError::transferErrorsTo(PossibleError* other)
 {
     MOZ_ASSERT(other);
     MOZ_ASSERT(this != other);
     MOZ_ASSERT(&parser_ == &other->parser_,
                "Can't transfer fields to an instance which belongs to a different parser");
 
     transferErrorTo(ErrorKind::Destructuring, other);
     transferErrorTo(ErrorKind::Expression, other);
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::BinaryNodeType
-GeneralParser<ParseHandler, CharT>::bindingInitializer(Node lhs, DeclarationKind kind,
-                                                       YieldHandling yieldHandling)
+GeneralParser<ParseHandler, Unit>::bindingInitializer(Node lhs, DeclarationKind kind,
+                                                      YieldHandling yieldHandling)
 {
     MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Assign));
 
     if (kind == DeclarationKind::FormalParameter) {
         pc->functionBox()->hasParameterExprs = true;
     }
 
     Node rhs = assignExpr(InAllowed, yieldHandling, TripledotProhibited);
@@ -4923,39 +4917,39 @@ GeneralParser<ParseHandler, CharT>::bind
             return null();
         }
         assign = handler.asBinary(node);
     }
 
     return assign;
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::NameNodeType
-GeneralParser<ParseHandler, CharT>::bindingIdentifier(DeclarationKind kind,
-                                                      YieldHandling yieldHandling)
+GeneralParser<ParseHandler, Unit>::bindingIdentifier(DeclarationKind kind,
+                                                     YieldHandling yieldHandling)
 {
     RootedPropertyName name(context, bindingIdentifier(yieldHandling));
     if (!name) {
         return null();
     }
 
     NameNodeType binding = newName(name);
     if (!binding || !noteDeclaredName(name, kind, pos())) {
         return null();
     }
 
     return binding;
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::Node
-GeneralParser<ParseHandler, CharT>::bindingIdentifierOrPattern(DeclarationKind kind,
-                                                               YieldHandling yieldHandling,
-                                                               TokenKind tt)
+GeneralParser<ParseHandler, Unit>::bindingIdentifierOrPattern(DeclarationKind kind,
+                                                              YieldHandling yieldHandling,
+                                                              TokenKind tt)
 {
     if (tt == TokenKind::LeftBracket) {
         return arrayBindingPattern(kind, yieldHandling);
     }
 
     if (tt == TokenKind::LeftCurly) {
         return objectBindingPattern(kind, yieldHandling);
     }
@@ -4963,20 +4957,20 @@ GeneralParser<ParseHandler, CharT>::bind
     if (!TokenKindIsPossibleIdentifierName(tt)) {
         error(JSMSG_NO_VARIABLE_NAME);
         return null();
     }
 
     return bindingIdentifier(kind, yieldHandling);
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::ListNodeType
-GeneralParser<ParseHandler, CharT>::objectBindingPattern(DeclarationKind kind,
-                                                         YieldHandling yieldHandling)
+GeneralParser<ParseHandler, Unit>::objectBindingPattern(DeclarationKind kind,
+                                                        YieldHandling yieldHandling)
 {
     MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::LeftCurly));
 
     if (!CheckRecursionLimit(context)) {
         return null();
     }
 
     uint32_t begin = pos().begin;
@@ -5110,20 +5104,20 @@ GeneralParser<ParseHandler, CharT>::obje
     MUST_MATCH_TOKEN_MOD_WITH_REPORT(TokenKind::RightCurly, TokenStream::Operand,
                                      reportMissingClosing(JSMSG_CURLY_AFTER_LIST,
                                                           JSMSG_CURLY_OPENED, begin));
 
     handler.setEndPosition(literal, pos().end);
     return literal;
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::ListNodeType
-GeneralParser<ParseHandler, CharT>::arrayBindingPattern(DeclarationKind kind,
-                                                        YieldHandling yieldHandling)
+GeneralParser<ParseHandler, Unit>::arrayBindingPattern(DeclarationKind kind,
+                                                       YieldHandling yieldHandling)
 {
     MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::LeftBracket));
 
     if (!CheckRecursionLimit(context)) {
         return null();
     }
 
     uint32_t begin = pos().begin;
@@ -5211,35 +5205,35 @@ GeneralParser<ParseHandler, CharT>::arra
      MUST_MATCH_TOKEN_MOD_WITH_REPORT(TokenKind::RightBracket, TokenStream::Operand,
                                       reportMissingClosing(JSMSG_BRACKET_AFTER_LIST,
                                                            JSMSG_BRACKET_OPENED, begin));
 
     handler.setEndPosition(literal, pos().end);
     return literal;
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::Node
-GeneralParser<ParseHandler, CharT>::destructuringDeclaration(DeclarationKind kind,
-                                                             YieldHandling yieldHandling,
-                                                             TokenKind tt)
+GeneralParser<ParseHandler, Unit>::destructuringDeclaration(DeclarationKind kind,
+                                                            YieldHandling yieldHandling,
+                                                            TokenKind tt)
 {
     MOZ_ASSERT(anyChars.isCurrentTokenType(tt));
     MOZ_ASSERT(tt == TokenKind::LeftBracket || tt == TokenKind::LeftCurly);
 
     return tt == TokenKind::LeftBracket
            ? arrayBindingPattern(kind, yieldHandling)
            : objectBindingPattern(kind, yieldHandling);
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::Node
-GeneralParser<ParseHandler, CharT>::destructuringDeclarationWithoutYieldOrAwait(DeclarationKind kind,
-                                                                                YieldHandling yieldHandling,
-                                                                                TokenKind tt)
+GeneralParser<ParseHandler, Unit>::destructuringDeclarationWithoutYieldOrAwait(DeclarationKind kind,
+                                                                               YieldHandling yieldHandling,
+                                                                               TokenKind tt)
 {
     uint32_t startYieldOffset = pc->lastYieldOffset;
     uint32_t startAwaitOffset = pc->lastAwaitOffset;
     Node res = destructuringDeclaration(kind, yieldHandling, tt);
     if (res) {
         if (pc->lastYieldOffset != startYieldOffset) {
             errorAt(pc->lastYieldOffset, JSMSG_YIELD_IN_PARAMETER);
             return null();
@@ -5247,20 +5241,20 @@ GeneralParser<ParseHandler, CharT>::dest
         if (pc->lastAwaitOffset != startAwaitOffset) {
             errorAt(pc->lastAwaitOffset, JSMSG_AWAIT_IN_PARAMETER);
             return null();
         }
     }
     return res;
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::LexicalScopeNodeType
-GeneralParser<ParseHandler, CharT>::blockStatement(YieldHandling yieldHandling,
-                                                   unsigned errorNumber)
+GeneralParser<ParseHandler, Unit>::blockStatement(YieldHandling yieldHandling,
+                                                  unsigned errorNumber)
 {
     MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::LeftCurly));
     uint32_t openedPos = pos().begin;
 
     ParseContext::Statement stmt(pc, StatementKind::Block);
     ParseContext::Scope scope(this);
     if (!scope.init(pc)) {
         return null();
@@ -5273,35 +5267,35 @@ GeneralParser<ParseHandler, CharT>::bloc
 
     MUST_MATCH_TOKEN_MOD_WITH_REPORT(TokenKind::RightCurly, TokenStream::Operand,
                                      reportMissingClosing(errorNumber, JSMSG_CURLY_OPENED,
                                                           openedPos));
 
     return finishLexicalScope(scope, list);
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::Node
-GeneralParser<ParseHandler, CharT>::expressionAfterForInOrOf(ParseNodeKind forHeadKind,
-                                                             YieldHandling yieldHandling)
+GeneralParser<ParseHandler, Unit>::expressionAfterForInOrOf(ParseNodeKind forHeadKind,
+                                                            YieldHandling yieldHandling)
 {
     MOZ_ASSERT(forHeadKind == ParseNodeKind::ForIn || forHeadKind == ParseNodeKind::ForOf);
     Node pn = forHeadKind == ParseNodeKind::ForOf
            ? assignExpr(InAllowed, yieldHandling, TripledotProhibited)
            : expr(InAllowed, yieldHandling, TripledotProhibited);
     return pn;
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::Node
-GeneralParser<ParseHandler, CharT>::declarationPattern(DeclarationKind declKind, TokenKind tt,
-                                                       bool initialDeclaration,
-                                                       YieldHandling yieldHandling,
-                                                       ParseNodeKind* forHeadKind,
-                                                       Node* forInOrOfExpression)
+GeneralParser<ParseHandler, Unit>::declarationPattern(DeclarationKind declKind, TokenKind tt,
+                                                      bool initialDeclaration,
+                                                      YieldHandling yieldHandling,
+                                                      ParseNodeKind* forHeadKind,
+                                                      Node* forInOrOfExpression)
 {
     MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::LeftBracket) ||
                anyChars.isCurrentTokenType(TokenKind::LeftCurly));
 
     Node pattern = destructuringDeclaration(declKind, yieldHandling, tt);
     if (!pattern) {
         return null();
     }
@@ -5341,24 +5335,24 @@ GeneralParser<ParseHandler, CharT>::decl
                            yieldHandling, TripledotProhibited);
     if (!init) {
         return null();
     }
 
     return handler.newAssignment(ParseNodeKind::Assign, pattern, init);
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 bool
-GeneralParser<ParseHandler, CharT>::initializerInNameDeclaration(NameNodeType binding,
-                                                                 DeclarationKind declKind,
-                                                                 bool initialDeclaration,
-                                                                 YieldHandling yieldHandling,
-                                                                 ParseNodeKind* forHeadKind,
-                                                                 Node* forInOrOfExpression)
+GeneralParser<ParseHandler, Unit>::initializerInNameDeclaration(NameNodeType binding,
+                                                                DeclarationKind declKind,
+                                                                bool initialDeclaration,
+                                                                YieldHandling yieldHandling,
+                                                                ParseNodeKind* forHeadKind,
+                                                                Node* forInOrOfExpression)
 {
     MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Assign));
 
     uint32_t initializerOffset;
     if (!tokenStream.peekOffset(&initializerOffset, TokenStream::Operand)) {
         return false;
     }
 
@@ -5405,23 +5399,23 @@ GeneralParser<ParseHandler, CharT>::init
         } else {
             *forHeadKind = ParseNodeKind::ForHead;
         }
     }
 
     return handler.finishInitializerAssignment(binding, initializer);
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::NameNodeType
-GeneralParser<ParseHandler, CharT>::declarationName(DeclarationKind declKind, TokenKind tt,
-                                                    bool initialDeclaration,
-                                                    YieldHandling yieldHandling,
-                                                    ParseNodeKind* forHeadKind,
-                                                    Node* forInOrOfExpression)
+GeneralParser<ParseHandler, Unit>::declarationName(DeclarationKind declKind, TokenKind tt,
+                                                   bool initialDeclaration,
+                                                   YieldHandling yieldHandling,
+                                                   ParseNodeKind* forHeadKind,
+                                                   Node* forInOrOfExpression)
 {
     // Anything other than possible identifier is an error.
     if (!TokenKindIsPossibleIdentifier(tt)) {
         error(JSMSG_NO_VARIABLE_NAME);
         return null();
     }
 
     RootedPropertyName name(context, bindingIdentifier(yieldHandling));
@@ -5494,22 +5488,22 @@ GeneralParser<ParseHandler, CharT>::decl
     // loop, due to special early error semantics in Annex B.3.5.
     if (!noteDeclaredName(name, declKind, namePos)) {
         return null();
     }
 
     return binding;
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::ListNodeType
-GeneralParser<ParseHandler, CharT>::declarationList(YieldHandling yieldHandling,
-                                                    ParseNodeKind kind,
-                                                    ParseNodeKind* forHeadKind /* = nullptr */,
-                                                    Node* forInOrOfExpression /* = nullptr */)
+GeneralParser<ParseHandler, Unit>::declarationList(YieldHandling yieldHandling,
+                                                   ParseNodeKind kind,
+                                                   ParseNodeKind* forHeadKind /* = nullptr */,
+                                                   Node* forInOrOfExpression /* = nullptr */)
 {
     MOZ_ASSERT(kind == ParseNodeKind::Var ||
                kind == ParseNodeKind::Let ||
                kind == ParseNodeKind::Const);
 
     DeclarationKind declKind;
     switch (kind) {
       case ParseNodeKind::Var:
@@ -5563,20 +5557,20 @@ GeneralParser<ParseHandler, CharT>::decl
         if (!tokenStream.matchToken(&moreDeclarations, TokenKind::Comma, TokenStream::Operand)) {
             return null();
         }
     } while (moreDeclarations);
 
     return decl;
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::ListNodeType
-GeneralParser<ParseHandler, CharT>::lexicalDeclaration(YieldHandling yieldHandling,
-                                                       DeclarationKind kind)
+GeneralParser<ParseHandler, Unit>::lexicalDeclaration(YieldHandling yieldHandling,
+                                                      DeclarationKind kind)
 {
     MOZ_ASSERT(kind == DeclarationKind::Const || kind == DeclarationKind::Let);
 
     /*
      * Parse body-level lets without a new block object. ES6 specs
      * that an execution environment's initial lexical environment
      * is the VariableEnvironment, i.e., body-level lets are in
      * the same environment record as vars.
@@ -5592,20 +5586,20 @@ GeneralParser<ParseHandler, CharT>::lexi
                                         : ParseNodeKind::Let);
     if (!decl || !matchOrInsertSemicolon()) {
         return null();
     }
 
     return decl;
 }
 
-template <typename CharT>
+template <typename Unit>
 bool
-Parser<FullParseHandler, CharT>::namedImportsOrNamespaceImport(TokenKind tt,
-                                                               ListNodeType importSpecSet)
+Parser<FullParseHandler, Unit>::namedImportsOrNamespaceImport(TokenKind tt,
+                                                              ListNodeType importSpecSet)
 {
     if (tt == TokenKind::LeftCurly) {
         while (true) {
             // Handle the forms |import {} from 'a'| and
             // |import { ..., } from 'a'| (where ... is non empty), by
             // escaping the loop early if the next token is }.
             if (!tokenStream.getToken(&tt)) {
                 return false;
@@ -5726,19 +5720,19 @@ Parser<FullParseHandler, CharT>::namedIm
         }
 
         handler.addList(importSpecSet, importSpec);
     }
 
     return true;
 }
 
-template<typename CharT>
+template<typename Unit>
 BinaryNode*
-Parser<FullParseHandler, CharT>::importDeclaration()
+Parser<FullParseHandler, Unit>::importDeclaration()
 {
     MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Import));
 
     if (!pc->atModuleLevel()) {
         error(JSMSG_IMPORT_DECL_AT_TOP_LEVEL);
         return null();
     }
 
@@ -5835,84 +5829,84 @@ Parser<FullParseHandler, CharT>::importD
         handler.newImportDeclaration(importSpecSet, moduleSpec, TokenPos(begin, pos().end));
     if (!node || !pc->sc()->asModuleContext()->builder.processImport(node)) {
         return null();
     }
 
     return node;
 }
 
-template<typename CharT>
+template<typename Unit>
 inline SyntaxParseHandler::BinaryNodeType
-Parser<SyntaxParseHandler, CharT>::importDeclaration()
+Parser<SyntaxParseHandler, Unit>::importDeclaration()
 {
     MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
     return SyntaxParseHandler::NodeFailure;
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 inline typename ParseHandler::BinaryNodeType
-GeneralParser<ParseHandler, CharT>::importDeclaration()
+GeneralParser<ParseHandler, Unit>::importDeclaration()
 {
     return asFinalParser()->importDeclaration();
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 inline typename ParseHandler::Node
-GeneralParser<ParseHandler, CharT>::importDeclarationOrImportExpr(YieldHandling yieldHandling)
+GeneralParser<ParseHandler, Unit>::importDeclarationOrImportExpr(YieldHandling yieldHandling)
 {
     MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Import));
 
     TokenKind tt;
     if (!tokenStream.peekToken(&tt)) {
         return null();
     }
 
     if (tt == TokenKind::Dot || tt == TokenKind::LeftParen) {
         return expressionStatement(yieldHandling);
     }
 
     return importDeclaration();
 }
 
-template<typename CharT>
+template<typename Unit>
 bool
-Parser<FullParseHandler, CharT>::checkExportedName(JSAtom* exportName)
+Parser<FullParseHandler, Unit>::checkExportedName(JSAtom* exportName)
 {
     if (!pc->sc()->asModuleContext()->builder.hasExportedName(exportName)) {
         return true;
     }
 
     UniqueChars str = AtomToPrintableString(context, exportName);
     if (!str) {
         return false;
     }
 
     error(JSMSG_DUPLICATE_EXPORT_NAME, str.get());
     return false;
 }
 
-template<typename CharT>
+template<typename Unit>
 inline bool
-Parser<SyntaxParseHandler, CharT>::checkExportedName(JSAtom* exportName)
+Parser<SyntaxParseHandler, Unit>::checkExportedName(JSAtom* exportName)
 {
     MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
     return false;
 }
 
-template<class ParseHandler, typename CharT>
+template<class ParseHandler, typename Unit>
 inline bool
-GeneralParser<ParseHandler, CharT>::checkExportedName(JSAtom* exportName)
+GeneralParser<ParseHandler, Unit>::checkExportedName(JSAtom* exportName)
 {
     return asFinalParser()->checkExportedName(exportName);
 }
 
-template<typename CharT>
+template<typename Unit>
 bool
-Parser<FullParseHandler, CharT>::checkExportedNamesForArrayBinding(ListNode* array)
+Parser<FullParseHandler, Unit>::checkExportedNamesForArrayBinding(ListNode* array)
 {
     MOZ_ASSERT(array->isKind(ParseNodeKind::Array));
 
     for (ParseNode* node : array->contents()) {
         if (node->isKind(ParseNodeKind::Elision)) {
             continue;
         }
 
@@ -5928,34 +5922,34 @@ Parser<FullParseHandler, CharT>::checkEx
         if (!checkExportedNamesForDeclaration(binding)) {
             return false;
         }
     }
 
     return true;
 }
 
-template<typename CharT>
+template<typename Unit>
 inline bool
-Parser<SyntaxParseHandler, CharT>::checkExportedNamesForArrayBinding(ListNodeType array)
+Parser<SyntaxParseHandler, Unit>::checkExportedNamesForArrayBinding(ListNodeType array)
 {
     MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
     return false;
 }
 
-template<class ParseHandler, typename CharT>
+template<class ParseHandler, typename Unit>
 inline bool
-GeneralParser<ParseHandler, CharT>::checkExportedNamesForArrayBinding(ListNodeType array)
+GeneralParser<ParseHandler, Unit>::checkExportedNamesForArrayBinding(ListNodeType array)
 {
     return asFinalParser()->checkExportedNamesForArrayBinding(array);
 }
 
-template<typename CharT>
+template<typename Unit>
 bool
-Parser<FullParseHandler, CharT>::checkExportedNamesForObjectBinding(ListNode* obj)
+Parser<FullParseHandler, Unit>::checkExportedNamesForObjectBinding(ListNode* obj)
 {
     MOZ_ASSERT(obj->isKind(ParseNodeKind::Object));
 
     for (ParseNode* node : obj->contents()) {
         MOZ_ASSERT(node->isKind(ParseNodeKind::MutateProto) ||
                    node->isKind(ParseNodeKind::Colon) ||
                    node->isKind(ParseNodeKind::Shorthand) ||
                    node->isKind(ParseNodeKind::Spread));
@@ -5978,34 +5972,34 @@ Parser<FullParseHandler, CharT>::checkEx
         if (!checkExportedNamesForDeclaration(target)) {
             return false;
         }
     }
 
     return true;
 }
 
-template<typename CharT>
+template<typename Unit>
 inline bool
-Parser<SyntaxParseHandler, CharT>::checkExportedNamesForObjectBinding(ListNodeType obj)
+Parser<SyntaxParseHandler, Unit>::checkExportedNamesForObjectBinding(ListNodeType obj)
 {
     MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
     return false;
 }
 
-template<class ParseHandler, typename CharT>
+template<class ParseHandler, typename Unit>
 inline bool
-GeneralParser<ParseHandler, CharT>::checkExportedNamesForObjectBinding(ListNodeType obj)
+GeneralParser<ParseHandler, Unit>::checkExportedNamesForObjectBinding(ListNodeType obj)
 {
     return asFinalParser()->checkExportedNamesForObjectBinding(obj);
 }
 
-template<typename CharT>
+template<typename Unit>
 bool
-Parser<FullParseHandler, CharT>::checkExportedNamesForDeclaration(ParseNode* node)
+Parser<FullParseHandler, Unit>::checkExportedNamesForDeclaration(ParseNode* node)
 {
     if (node->isKind(ParseNodeKind::Name)) {
         if (!checkExportedName(node->as<NameNode>().atom())) {
             return false;
         }
     } else if (node->isKind(ParseNodeKind::Array)) {
         if (!checkExportedNamesForArrayBinding(&node->as<ListNode>())) {
             return false;
@@ -6015,128 +6009,128 @@ Parser<FullParseHandler, CharT>::checkEx
         if (!checkExportedNamesForObjectBinding(&node->as<ListNode>())) {
             return false;
         }
     }
 
     return true;
 }
 
-template<typename CharT>
+template<typename Unit>
 inline bool
-Parser<SyntaxParseHandler, CharT>::checkExportedNamesForDeclaration(Node node)
+Parser<SyntaxParseHandler, Unit>::checkExportedNamesForDeclaration(Node node)
 {
     MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
     return false;
 }
 
-template<class ParseHandler, typename CharT>
+template<class ParseHandler, typename Unit>
 inline bool
-GeneralParser<ParseHandler, CharT>::checkExportedNamesForDeclaration(Node node)
+GeneralParser<ParseHandler, Unit>::checkExportedNamesForDeclaration(Node node)
 {
     return asFinalParser()->checkExportedNamesForDeclaration(node);
 }
 
-template<typename CharT>
+template<typename Unit>
 bool
-Parser<FullParseHandler, CharT>::checkExportedNamesForDeclarationList(ListNode* node)
+Parser<FullParseHandler, Unit>::checkExportedNamesForDeclarationList(ListNode* node)
 {
     for (ParseNode* binding : node->contents()) {
         if (binding->isKind(ParseNodeKind::Assign)) {
             binding = binding->as<AssignmentNode>().left();
         } else {
             MOZ_ASSERT(binding->isKind(ParseNodeKind::Name));
         }
 
         if (!checkExportedNamesForDeclaration(binding)) {
             return false;
         }
     }
 
     return true;
 }
 
-template<typename CharT>
+template<typename Unit>
 inline bool
-Parser<SyntaxParseHandler, CharT>::checkExportedNamesForDeclarationList(ListNodeType node)
+Parser<SyntaxParseHandler, Unit>::checkExportedNamesForDeclarationList(ListNodeType node)
 {
     MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
     return false;
 }
 
-template<class ParseHandler, typename CharT>
+template<class ParseHandler, typename Unit>
 inline bool
-GeneralParser<ParseHandler, CharT>::checkExportedNamesForDeclarationList(ListNodeType node)
+GeneralParser<ParseHandler, Unit>::checkExportedNamesForDeclarationList(ListNodeType node)
 {
     return asFinalParser()->checkExportedNamesForDeclarationList(node);
 }
 
-template<typename CharT>
+template<typename Unit>
 inline bool
-Parser<FullParseHandler, CharT>::checkExportedNameForClause(NameNode* nameNode)
+Parser<FullParseHandler, Unit>::checkExportedNameForClause(NameNode* nameNode)
 {
     return checkExportedName(nameNode->atom());
 }
 
-template<typename CharT>
+template<typename Unit>
 inline bool
-Parser<SyntaxParseHandler, CharT>::checkExportedNameForClause(NameNodeType nameNode)
+Parser<SyntaxParseHandler, Unit>::checkExportedNameForClause(NameNodeType nameNode)
 {
     MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
     return false;
 }
 
-template<class ParseHandler, typename CharT>
+template<class ParseHandler, typename Unit>
 inline bool
-GeneralParser<ParseHandler, CharT>::checkExportedNameForClause(NameNodeType nameNode)
+GeneralParser<ParseHandler, Unit>::checkExportedNameForClause(NameNodeType nameNode)
 {
     return asFinalParser()->checkExportedNameForClause(nameNode);
 }
 
-template<typename CharT>
+template<typename Unit>
 bool
-Parser<FullParseHandler, CharT>::checkExportedNameForFunction(CodeNode* funNode)
+Parser<FullParseHandler, Unit>::checkExportedNameForFunction(CodeNode* funNode)
 {
     return checkExportedName(funNode->funbox()->function()->explicitName());
 }
 
-template<typename CharT>
+template<typename Unit>
 inline bool
-Parser<SyntaxParseHandler, CharT>::checkExportedNameForFunction(CodeNodeType funNode)
+Parser<SyntaxParseHandler, Unit>::checkExportedNameForFunction(CodeNodeType funNode)
 {
     MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
     return false;
 }
 
-template<class ParseHandler, typename CharT>
+template<class ParseHandler, typename Unit>
 inline bool
-GeneralParser<ParseHandler, CharT>::checkExportedNameForFunction(CodeNodeType funNode)
+GeneralParser<ParseHandler, Unit>::checkExportedNameForFunction(CodeNodeType funNode)
 {
     return asFinalParser()->checkExportedNameForFunction(funNode);
 }
 
-template<typename CharT>
+template<typename Unit>
 bool
-Parser<FullParseHandler, CharT>::checkExportedNameForClass(ClassNode* classNode)
+Parser<FullParseHandler, Unit>::checkExportedNameForClass(ClassNode* classNode)
 {
     MOZ_ASSERT(classNode->names());
     return checkExportedName(classNode->names()->innerBinding()->atom());
 }
 
-template<typename CharT>
+template<typename Unit>
 inline bool
-Parser<SyntaxParseHandler, CharT>::checkExportedNameForClass(ClassNodeType classNode)
+Parser<SyntaxParseHandler, Unit>::checkExportedNameForClass(ClassNodeType classNode)
 {
     MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
     return false;
 }
 
-template<class ParseHandler, typename CharT>
+template<class ParseHandler, typename Unit>
 inline bool
-GeneralParser<ParseHandler, CharT>::checkExportedNameForClass(ClassNodeType classNode)
+GeneralParser<ParseHandler, Unit>::checkExportedNameForClass(ClassNodeType classNode)
 {
     return asFinalParser()->checkExportedNameForClass(classNode);
 }
 
 template<>
 inline bool
 PerHandlerParser<FullParseHandler>::processExport(ParseNode* node)
 {
@@ -6161,19 +6155,19 @@ PerHandlerParser<FullParseHandler>::proc
 template<>
 inline bool
 PerHandlerParser<SyntaxParseHandler>::processExportFrom(BinaryNodeType node)
 {
     MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
     return false;
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::BinaryNodeType
-GeneralParser<ParseHandler, CharT>::exportFrom(uint32_t begin, Node specList)
+GeneralParser<ParseHandler, Unit>::exportFrom(uint32_t begin, Node specList)
 {
     if (!abortIfSyntaxParser()) {
         return null();
     }
 
     MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::From));
 
     if (!abortIfSyntaxParser()) {
@@ -6198,19 +6192,19 @@ GeneralParser<ParseHandler, CharT>::expo
 
     if (!processExportFrom(node)) {
         return null();
     }
 
     return node;
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::BinaryNodeType
-GeneralParser<ParseHandler, CharT>::exportBatch(uint32_t begin)
+GeneralParser<ParseHandler, Unit>::exportBatch(uint32_t begin)
 {
     if (!abortIfSyntaxParser()) {
         return null();
     }
 
     MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Mul));
 
     ListNodeType kid = handler.newList(ParseNodeKind::ExportSpecList, pos());
@@ -6227,52 +6221,52 @@ GeneralParser<ParseHandler, CharT>::expo
 
     handler.addList(kid, exportSpec);
 
     MUST_MATCH_TOKEN(TokenKind::From, JSMSG_FROM_AFTER_EXPORT_STAR);
 
     return exportFrom(begin, kid);
 }
 
-template<typename CharT>
+template<typename Unit>
 bool
-Parser<FullParseHandler, CharT>::checkLocalExportNames(ListNode* node)
+Parser<FullParseHandler, Unit>::checkLocalExportNames(ListNode* node)
 {
     // ES 2017 draft 15.2.3.1.
     for (ParseNode* next : node->contents()) {
         ParseNode* name = next->as<BinaryNode>().left();
         MOZ_ASSERT(name->isKind(ParseNodeKind::Name));
 
         RootedPropertyName ident(context, name->as<NameNode>().atom()->asPropertyName());
         if (!checkLocalExportName(ident, name->pn_pos.begin)) {
             return false;
         }
     }
 
     return true;
 }
 
-template<typename CharT>
+template<typename Unit>
 bool
-Parser<SyntaxParseHandler, CharT>::checkLocalExportNames(ListNodeType node)
+Parser<SyntaxParseHandler, Unit>::checkLocalExportNames(ListNodeType node)
 {
     MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
     return false;
 }
 
-template<class ParseHandler, typename CharT>
+template<class ParseHandler, typename Unit>
 inline bool
-GeneralParser<ParseHandler, CharT>::checkLocalExportNames(ListNodeType node)
+GeneralParser<ParseHandler, Unit>::checkLocalExportNames(ListNodeType node)
 {
     return asFinalParser()->checkLocalExportNames(node);
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::Node
-GeneralParser<ParseHandler, CharT>::exportClause(uint32_t begin)
+GeneralParser<ParseHandler, Unit>::exportClause(uint32_t begin)
 {
     if (!abortIfSyntaxParser()) {
         return null();
     }
 
     MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::LeftCurly));
 
     ListNodeType kid = handler.newList(ParseNodeKind::ExportSpecList, pos());
@@ -6378,19 +6372,19 @@ GeneralParser<ParseHandler, CharT>::expo
 
     if (!processExport(node)) {
         return null();
     }
 
     return node;
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::UnaryNodeType
-GeneralParser<ParseHandler, CharT>::exportVariableStatement(uint32_t begin)
+GeneralParser<ParseHandler, Unit>::exportVariableStatement(uint32_t begin)
 {
     if (!abortIfSyntaxParser()) {
         return null();
     }
 
     MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Var));
 
     ListNodeType kid = declarationList(YieldIsName, ParseNodeKind::Var);
@@ -6411,21 +6405,21 @@ GeneralParser<ParseHandler, CharT>::expo
 
     if (!processExport(node)) {
         return null();
     }
 
     return node;
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::UnaryNodeType
-GeneralParser<ParseHandler, CharT>::exportFunctionDeclaration(uint32_t begin,
-                                                              uint32_t toStringStart,
-                                                              FunctionAsyncKind asyncKind /* = SyncFunction */)
+GeneralParser<ParseHandler, Unit>::exportFunctionDeclaration(uint32_t begin,
+                                                             uint32_t toStringStart,
+                                                             FunctionAsyncKind asyncKind /* = SyncFunction */)
 {
     if (!abortIfSyntaxParser()) {
         return null();
     }
 
     MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Function));
 
     Node kid = functionStmt(toStringStart, YieldIsName, NameRequired, asyncKind);
@@ -6444,19 +6438,19 @@ GeneralParser<ParseHandler, CharT>::expo
 
     if (!processExport(node)) {
         return null();
     }
 
     return node;
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::UnaryNodeType
-GeneralParser<ParseHandler, CharT>::exportClassDeclaration(uint32_t begin)
+GeneralParser<ParseHandler, Unit>::exportClassDeclaration(uint32_t begin)
 {
     if (!abortIfSyntaxParser()) {
         return null();
     }
 
     MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Class));
 
     ClassNodeType kid = classDefinition(YieldIsName, ClassStatement, NameRequired);
@@ -6475,19 +6469,19 @@ GeneralParser<ParseHandler, CharT>::expo
 
     if (!processExport(node)) {
         return null();
     }
 
     return node;
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::UnaryNodeType
-GeneralParser<ParseHandler, CharT>::exportLexicalDeclaration(uint32_t begin, DeclarationKind kind)
+GeneralParser<ParseHandler, Unit>::exportLexicalDeclaration(uint32_t begin, DeclarationKind kind)
 {
     if (!abortIfSyntaxParser()) {
         return null();
     }
 
     MOZ_ASSERT(kind == DeclarationKind::Const || kind == DeclarationKind::Let);
     MOZ_ASSERT_IF(kind == DeclarationKind::Const, anyChars.isCurrentTokenType(TokenKind::Const));
     MOZ_ASSERT_IF(kind == DeclarationKind::Let, anyChars.isCurrentTokenType(TokenKind::Let));
@@ -6507,21 +6501,21 @@ GeneralParser<ParseHandler, CharT>::expo
 
     if (!processExport(node)) {
         return null();
     }
 
     return node;
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::BinaryNodeType
-GeneralParser<ParseHandler, CharT>::exportDefaultFunctionDeclaration(uint32_t begin,
-                                                                     uint32_t toStringStart,
-                                                                     FunctionAsyncKind asyncKind /* = SyncFunction */)
+GeneralParser<ParseHandler, Unit>::exportDefaultFunctionDeclaration(uint32_t begin,
+                                                                    uint32_t toStringStart,
+                                                                    FunctionAsyncKind asyncKind /* = SyncFunction */)
 {
     if (!abortIfSyntaxParser()) {
         return null();
     }
 
     MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Function));
 
     Node kid = functionStmt(toStringStart, YieldIsName, AllowDefaultName, asyncKind);
@@ -6537,19 +6531,19 @@ GeneralParser<ParseHandler, CharT>::expo
 
     if (!processExport(node)) {
         return null();
     }
 
     return node;
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::BinaryNodeType
-GeneralParser<ParseHandler, CharT>::exportDefaultClassDeclaration(uint32_t begin)
+GeneralParser<ParseHandler, Unit>::exportDefaultClassDeclaration(uint32_t begin)
 {
     if (!abortIfSyntaxParser()) {
         return null();
     }
 
     MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Class));
 
     ClassNodeType kid = classDefinition(YieldIsName, ClassStatement, AllowDefaultName);
@@ -6565,19 +6559,19 @@ GeneralParser<ParseHandler, CharT>::expo
 
     if (!processExport(node)) {
         return null();
     }
 
     return node;
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::BinaryNodeType
-GeneralParser<ParseHandler, CharT>::exportDefaultAssignExpr(uint32_t begin)
+GeneralParser<ParseHandler, Unit>::exportDefaultAssignExpr(uint32_t begin)
 {
     if (!abortIfSyntaxParser()) {
         return null();
     }
 
     HandlePropertyName name = context->names().default_;
     NameNodeType nameNode = newName(name);
     if (!nameNode) {
@@ -6604,19 +6598,19 @@ GeneralParser<ParseHandler, CharT>::expo
 
     if (!processExport(node)) {
         return null();
     }
 
     return node;
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::BinaryNodeType
-GeneralParser<ParseHandler, CharT>::exportDefault(uint32_t begin)
+GeneralParser<ParseHandler, Unit>::exportDefault(uint32_t begin)
 {
     if (!abortIfSyntaxParser()) {
         return null();
     }
 
     MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Default));
 
     TokenKind tt;
@@ -6653,19 +6647,19 @@ GeneralParser<ParseHandler, CharT>::expo
         return exportDefaultClassDeclaration(begin);
 
       default:
         anyChars.ungetToken();
         return exportDefaultAssignExpr(begin);
     }
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::Node
-GeneralParser<ParseHandler, CharT>::exportDeclaration()
+GeneralParser<ParseHandler, Unit>::exportDeclaration()
 {
     if (!abortIfSyntaxParser()) {
         return null();
     }
 
     MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Export));
 
     if (!pc->atModuleLevel()) {
@@ -6722,36 +6716,36 @@ GeneralParser<ParseHandler, CharT>::expo
         return exportDefault(begin);
 
       default:
         error(JSMSG_DECLARATION_AFTER_EXPORT);
         return null();
     }
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::UnaryNodeType
-GeneralParser<ParseHandler, CharT>::expressionStatement(YieldHandling yieldHandling,
-                                                        InvokedPrediction invoked)
+GeneralParser<ParseHandler, Unit>::expressionStatement(YieldHandling yieldHandling,
+                                                       InvokedPrediction invoked)
 {
     anyChars.ungetToken();
     Node pnexpr = expr(InAllowed, yieldHandling, TripledotProhibited,
                        /* possibleError = */ nullptr, invoked);
     if (!pnexpr) {
         return null();
     }
     if (!matchOrInsertSemicolon()) {
         return null();
     }
     return handler.newExprStatement(pnexpr, pos().end);
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::Node
-GeneralParser<ParseHandler, CharT>::consequentOrAlternative(YieldHandling yieldHandling)
+GeneralParser<ParseHandler, Unit>::consequentOrAlternative(YieldHandling yieldHandling)
 {
     TokenKind next;
     if (!tokenStream.peekToken(&next, TokenStream::Operand)) {
         return null();
     }
 
     // Annex B.3.4 says that unbraced FunctionDeclarations under if/else in
     // non-strict code act as if they were braced: |if (x) function f() {}|
@@ -6798,19 +6792,19 @@ GeneralParser<ParseHandler, CharT>::cons
 
         handler.addStatementToList(block, fun);
         return finishLexicalScope(scope, block);
     }
 
     return statement(yieldHandling);
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::TernaryNodeType
-GeneralParser<ParseHandler, CharT>::ifStatement(YieldHandling yieldHandling)
+GeneralParser<ParseHandler, Unit>::ifStatement(YieldHandling yieldHandling)
 {
     Vector<Node, 4> condList(context), thenList(context);
     Vector<uint32_t, 4> posList(context);
     Node elseBranch;
 
     ParseContext::Statement stmt(pc, StatementKind::If);
 
     while (true) {
@@ -6869,19 +6863,19 @@ GeneralParser<ParseHandler, CharT>::ifSt
             return null();
         }
         elseBranch = ifNode;
     }
 
     return ifNode;
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::BinaryNodeType
-GeneralParser<ParseHandler, CharT>::doWhileStatement(YieldHandling yieldHandling)
+GeneralParser<ParseHandler, Unit>::doWhileStatement(YieldHandling yieldHandling)
 {
     uint32_t begin = pos().begin;
     ParseContext::Statement stmt(pc, StatementKind::DoLoop);
     Node body = statement(yieldHandling);
     if (!body) {
         return null();
     }
     MUST_MATCH_TOKEN_MOD(TokenKind::While, TokenStream::Operand, JSMSG_WHILE_AFTER_DO);
@@ -6898,58 +6892,58 @@ GeneralParser<ParseHandler, CharT>::doWh
     // To parse |do {} while (true) false| correctly, use Operand.
     bool ignored;
     if (!tokenStream.matchToken(&ignored, TokenKind::Semi, TokenStream::Operand)) {
         return null();
     }
     return handler.newDoWhileStatement(body, cond, TokenPos(begin, pos().end));
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::BinaryNodeType
-GeneralParser<ParseHandler, CharT>::whileStatement(YieldHandling yieldHandling)
+GeneralParser<ParseHandler, Unit>::whileStatement(YieldHandling yieldHandling)
 {
     uint32_t begin = pos().begin;
     ParseContext::Statement stmt(pc, StatementKind::WhileLoop);
     Node cond = condition(InAllowed, yieldHandling);
     if (!cond) {
         return null();
     }
     Node body = statement(yieldHandling);
     if (!body) {
         return null();
     }
     return handler.newWhileStatement(begin, cond, body);
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 bool
-GeneralParser<ParseHandler, CharT>::matchInOrOf(bool* isForInp, bool* isForOfp)
+GeneralParser<ParseHandler, Unit>::matchInOrOf(bool* isForInp, bool* isForOfp)
 {
     TokenKind tt;
     if (!tokenStream.getToken(&tt, TokenStream::Operand)) {
         return false;
     }
 
     *isForInp = tt == TokenKind::In;
     *isForOfp = tt == TokenKind::Of;
     if (!*isForInp && !*isForOfp) {
         anyChars.ungetToken();
     }
 
     MOZ_ASSERT_IF(*isForInp || *isForOfp, *isForInp != *isForOfp);
     return true;
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 bool
-GeneralParser<ParseHandler, CharT>::forHeadStart(YieldHandling yieldHandling,
-                                                 ParseNodeKind* forHeadKind, Node* forInitialPart,
-                                                 Maybe<ParseContext::Scope>& forLoopLexicalScope,
-                                                 Node* forInOrOfExpression)
+GeneralParser<ParseHandler, Unit>::forHeadStart(YieldHandling yieldHandling,
+                                                ParseNodeKind* forHeadKind, Node* forInitialPart,
+                                                Maybe<ParseContext::Scope>& forLoopLexicalScope,
+                                                Node* forInOrOfExpression)
 {
     MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::LeftParen));
 
     TokenKind tt;
     if (!tokenStream.peekToken(&tt, TokenStream::Operand)) {
         return false;
     }
 
@@ -7100,19 +7094,19 @@ GeneralParser<ParseHandler, CharT>::forH
     }
 
     // Finally, parse the iterated expression, making the for-loop's closing
     // ')' the next token.
     *forInOrOfExpression = expressionAfterForInOrOf(*forHeadKind, yieldHandling);
     return *forInOrOfExpression != null();
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::Node
-GeneralParser<ParseHandler, CharT>::forStatement(YieldHandling yieldHandling)
+GeneralParser<ParseHandler, Unit>::forStatement(YieldHandling yieldHandling)
 {
     MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::For));
 
     uint32_t begin = pos().begin;
 
     ParseContext::Statement stmt(pc, StatementKind::ForLoop);
 
     IteratorKind iterKind = IteratorKind::Sync;
@@ -7269,19 +7263,19 @@ GeneralParser<ParseHandler, CharT>::forS
 
     if (forLoopLexicalScope) {
         return finishLexicalScope(*forLoopLexicalScope, forLoop);
     }
 
     return forLoop;
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::SwitchStatementType
-GeneralParser<ParseHandler, CharT>::switchStatement(YieldHandling yieldHandling)
+GeneralParser<ParseHandler, Unit>::switchStatement(YieldHandling yieldHandling)
 {
     MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Switch));
     uint32_t begin = pos().begin;
 
     MUST_MATCH_TOKEN(TokenKind::LeftParen, JSMSG_PAREN_BEFORE_SWITCH);
 
     Node discriminant = exprInParens(InAllowed, yieldHandling, TripledotProhibited);
     if (!discriminant) {
@@ -7390,19 +7384,19 @@ GeneralParser<ParseHandler, CharT>::swit
         return null();
     }
 
     handler.setEndPosition(lexicalForCaseList, pos().end);
 
     return handler.newSwitchStatement(begin, discriminant, lexicalForCaseList, seenDefault);
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::ContinueStatementType
-GeneralParser<ParseHandler, CharT>::continueStatement(YieldHandling yieldHandling)
+GeneralParser<ParseHandler, Unit>::continueStatement(YieldHandling yieldHandling)
 {
     MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Continue));
     uint32_t begin = pos().begin;
 
     RootedPropertyName label(context);
     if (!matchLabel(yieldHandling, &label)) {
         return null();
     }
@@ -7422,19 +7416,19 @@ GeneralParser<ParseHandler, CharT>::cont
 
     if (!matchOrInsertSemicolon()) {
         return null();
     }
 
     return handler.newContinueStatement(label, TokenPos(begin, pos().end));
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::BreakStatementType
-GeneralParser<ParseHandler, CharT>::breakStatement(YieldHandling yieldHandling)
+GeneralParser<ParseHandler, Unit>::breakStatement(YieldHandling yieldHandling)
 {
     MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Break));
     uint32_t begin = pos().begin;
 
     RootedPropertyName label(context);
     if (!matchLabel(yieldHandling, &label)) {
         return null();
     }
@@ -7464,19 +7458,19 @@ GeneralParser<ParseHandler, CharT>::brea
 
     if (!matchOrInsertSemicolon()) {
         return null();
     }
 
     return handler.newBreakStatement(label, TokenPos(begin, pos().end));
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::UnaryNodeType
-GeneralParser<ParseHandler, CharT>::returnStatement(YieldHandling yieldHandling)
+GeneralParser<ParseHandler, Unit>::returnStatement(YieldHandling yieldHandling)
 {
     MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Return));
     uint32_t begin = pos().begin;
 
     MOZ_ASSERT(pc->isFunctionBox());
     pc->functionBox()->usesReturn = true;
 
     // Parse an optional operand.
@@ -7504,19 +7498,19 @@ GeneralParser<ParseHandler, CharT>::retu
 
     if (!matchOrInsertSemicolon()) {
         return null();
     }
 
     return handler.newReturnStatement(exprNode, TokenPos(begin, pos().end));
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::UnaryNodeType
-GeneralParser<ParseHandler, CharT>::yieldExpression(InHandling inHandling)
+GeneralParser<ParseHandler, Unit>::yieldExpression(InHandling inHandling)
 {
     MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Yield));
     uint32_t begin = pos().begin;
 
     MOZ_ASSERT(pc->isGenerator());
     MOZ_ASSERT(pc->isFunctionBox());
 
     pc->lastYieldOffset = begin;
@@ -7558,19 +7552,19 @@ GeneralParser<ParseHandler, CharT>::yiel
         }
     }
     if (kind == ParseNodeKind::YieldStar) {
         return handler.newYieldStarExpression(begin, exprNode);
     }
     return handler.newYieldExpression(begin, exprNode);
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::BinaryNodeType
-GeneralParser<ParseHandler, CharT>::withStatement(YieldHandling yieldHandling)
+GeneralParser<ParseHandler, Unit>::withStatement(YieldHandling yieldHandling)
 {
     MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::With));
     uint32_t begin = pos().begin;
 
     // Usually we want the constructs forbidden in strict mode code to be a
     // subset of those that ContextOptions::extraWarnings() warns about, and we
     // use strictModeError directly.  But while 'with' is forbidden in strict
     // mode code, it doesn't even merit a warning in non-strict code.  See
@@ -7599,19 +7593,19 @@ GeneralParser<ParseHandler, CharT>::with
         }
     }
 
     pc->sc()->setBindingsAccessedDynamically();
 
     return handler.newWithStatement(begin, objectExpr, innerBlock);
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::Node
-GeneralParser<ParseHandler, CharT>::labeledItem(YieldHandling yieldHandling)
+GeneralParser<ParseHandler, Unit>::labeledItem(YieldHandling yieldHandling)
 {
     TokenKind tt;
     if (!tokenStream.getToken(&tt, TokenStream::Operand)) {
         return null();
     }
 
     if (tt == TokenKind::Function) {
         TokenKind next;
@@ -7636,19 +7630,19 @@ GeneralParser<ParseHandler, CharT>::labe
 
         return functionStmt(pos().begin, yieldHandling, NameRequired);
     }
 
     anyChars.ungetToken();
     return statement(yieldHandling);
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::LabeledStatementType
-GeneralParser<ParseHandler, CharT>::labeledStatement(YieldHandling yieldHandling)
+GeneralParser<ParseHandler, Unit>::labeledStatement(YieldHandling yieldHandling)
 {
     RootedPropertyName label(context, labelIdentifier(yieldHandling));
     if (!label) {
         return null();
     }
 
     auto hasSameLabel = [&label](ParseContext::LabelStatement* stmt) {
         return stmt->label() == label;
@@ -7668,19 +7662,19 @@ GeneralParser<ParseHandler, CharT>::labe
     Node pn = labeledItem(yieldHandling);
     if (!pn) {
         return null();
     }
 
     return handler.newLabeledStatement(label, pn, begin);
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::UnaryNodeType
-GeneralParser<ParseHandler, CharT>::throwStatement(YieldHandling yieldHandling)
+GeneralParser<ParseHandler, Unit>::throwStatement(YieldHandling yieldHandling)
 {
     MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Throw));
     uint32_t begin = pos().begin;
 
     /* ECMA-262 Edition 3 says 'throw [no LineTerminator here] Expr'. */
     TokenKind tt = TokenKind::Eof;
     if (!tokenStream.peekTokenSameLine(&tt, TokenStream::Operand)) {
         return null();
@@ -7701,19 +7695,19 @@ GeneralParser<ParseHandler, CharT>::thro
 
     if (!matchOrInsertSemicolon()) {
         return null();
     }
 
     return handler.newThrowStatement(throwExpr, TokenPos(begin, pos().end));
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::TernaryNodeType
-GeneralParser<ParseHandler, CharT>::tryStatement(YieldHandling yieldHandling)
+GeneralParser<ParseHandler, Unit>::tryStatement(YieldHandling yieldHandling)
 {
     MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Try));
     uint32_t begin = pos().begin;
 
     /*
      * try nodes are ternary.
      * kid1 is the try statement
      * kid2 is the catch node list or null
@@ -7875,20 +7869,20 @@ GeneralParser<ParseHandler, CharT>::tryS
     if (!catchScope && !finallyBlock) {
         error(JSMSG_CATCH_OR_FINALLY);
         return null();
     }
 
     return handler.newTryStatement(begin, innerBlock, catchScope, finallyBlock);
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::LexicalScopeNodeType
-GeneralParser<ParseHandler, CharT>::catchBlockStatement(YieldHandling yieldHandling,
-                                                        ParseContext::Scope& catchParamScope)
+GeneralParser<ParseHandler, Unit>::catchBlockStatement(YieldHandling yieldHandling,
+                                                       ParseContext::Scope& catchParamScope)
 {
     uint32_t openedPos = pos().begin;
 
     ParseContext::Statement stmt(pc, StatementKind::Block);
 
     // ES 13.15.7 CatchClauseEvaluation
     //
     // Step 8 means that the body of a catch block always has an additional
@@ -7914,19 +7908,19 @@ GeneralParser<ParseHandler, CharT>::catc
                                                           JSMSG_CURLY_OPENED, openedPos));
 
     // The catch parameter names are not bound in the body scope, so remove
     // them before generating bindings.
     scope.removeCatchParameters(pc, catchParamScope);
     return finishLexicalScope(scope, list);
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::DebuggerStatementType
-GeneralParser<ParseHandler, CharT>::debuggerStatement()
+GeneralParser<ParseHandler, Unit>::debuggerStatement()
 {
     TokenPos p;
     p.begin = pos().begin;
     if (!matchOrInsertSemicolon()) {
         return null();
     }
     p.end = pos().end;
 
@@ -7952,21 +7946,21 @@ ToAccessorType(PropertyType propType)
       case PropertyType::Constructor:
       case PropertyType::DerivedConstructor:
         return AccessorType::None;
       default:
         MOZ_CRASH("unexpected property type");
     }
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::ClassNodeType
-GeneralParser<ParseHandler, CharT>::classDefinition(YieldHandling yieldHandling,
-                                                    ClassContext classContext,
-                                                    DefaultHandling defaultHandling)
+GeneralParser<ParseHandler, Unit>::classDefinition(YieldHandling yieldHandling,
+                                                   ClassContext classContext,
+                                                   DefaultHandling defaultHandling)
 {
     MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Class));
 
     uint32_t classStartOffset = pos().begin;
     bool savedStrictness = setLocalStrictMode(true);
 
     TokenKind tt;
     if (!tokenStream.getToken(&tt)) {
@@ -8226,33 +8220,33 @@ ParserBase::nextTokenContinuesLetDeclara
     // that we should parse this as two ExpressionStatements?   No.  ASI
     // resolves during parsing.  Static semantics only apply to the full
     // parse tree with ASI applied.  No backsies!
 
     // Otherwise a let declaration must have a name.
     return TokenKindIsPossibleIdentifier(next);
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::Node
-GeneralParser<ParseHandler, CharT>::variableStatement(YieldHandling yieldHandling)
+GeneralParser<ParseHandler, Unit>::variableStatement(YieldHandling yieldHandling)
 {
     ListNodeType vars = declarationList(yieldHandling, ParseNodeKind::Var);
     if (!vars) {
         return null();
     }
     if (!matchOrInsertSemicolon()) {
         return null();
     }
     return vars;
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::Node
-GeneralParser<ParseHandler, CharT>::statement(YieldHandling yieldHandling)
+GeneralParser<ParseHandler, Unit>::statement(YieldHandling yieldHandling)
 {
     MOZ_ASSERT(checkOptionsCalled);
 
     if (!CheckRecursionLimit(context)) {
         return null();
     }
 
     TokenKind tt;
@@ -8468,20 +8462,20 @@ GeneralParser<ParseHandler, CharT>::stat
       case TokenKind::Finally:
         error(JSMSG_FINALLY_WITHOUT_TRY);
         return null();
 
       // NOTE: default case handled in the ExpressionStatement section.
     }
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::Node
-GeneralParser<ParseHandler, CharT>::statementListItem(YieldHandling yieldHandling,
-                                                      bool canHaveDirectives /* = false */)
+GeneralParser<ParseHandler, Unit>::statementListItem(YieldHandling yieldHandling,
+                                                     bool canHaveDirectives /* = false */)
 {
     MOZ_ASSERT(checkOptionsCalled);
 
     if (!CheckRecursionLimit(context)) {
         return null();
     }
 
     TokenKind tt;
@@ -8674,22 +8668,22 @@ GeneralParser<ParseHandler, CharT>::stat
       case TokenKind::Finally:
         error(JSMSG_FINALLY_WITHOUT_TRY);
         return null();
 
       // NOTE: default case handled in the ExpressionStatement section.
     }
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::Node
-GeneralParser<ParseHandler, CharT>::expr(InHandling inHandling, YieldHandling yieldHandling,
-                                         TripledotHandling tripledotHandling,
-                                         PossibleError* possibleError /* = nullptr */,
-                                         InvokedPrediction invoked /* = PredictUninvoked */)
+GeneralParser<ParseHandler, Unit>::expr(InHandling inHandling, YieldHandling yieldHandling,
+                                        TripledotHandling tripledotHandling,
+                                        PossibleError* possibleError /* = nullptr */,
+                                        InvokedPrediction invoked /* = PredictUninvoked */)
 {
     Node pn = assignExpr(inHandling, yieldHandling, tripledotHandling,
                          possibleError, invoked);
     if (!pn) {
         return null();
     }
 
     bool matched;
@@ -8811,22 +8805,22 @@ Precedence(ParseNodeKind pnk)
         return 0;
     }
 
     MOZ_ASSERT(pnk >= ParseNodeKind::BinOpFirst);
     MOZ_ASSERT(pnk <= ParseNodeKind::BinOpLast);
     return PrecedenceTable[size_t(pnk) - size_t(ParseNodeKind::BinOpFirst)];
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 MOZ_ALWAYS_INLINE typename ParseHandler::Node
-GeneralParser<ParseHandler, CharT>::orExpr(InHandling inHandling, YieldHandling yieldHandling,
-                                           TripledotHandling tripledotHandling,
-                                           PossibleError* possibleError,
-                                           InvokedPrediction invoked /* = PredictUninvoked */)
+GeneralParser<ParseHandler, Unit>::orExpr(InHandling inHandling, YieldHandling yieldHandling,
+                                          TripledotHandling tripledotHandling,
+                                          PossibleError* possibleError,
+                                          InvokedPrediction invoked /* = PredictUninvoked */)
 {
     // Shift-reduce parser for the binary operator part of the JS expression
     // syntax.
 
     // Conceptually there's just one stack, a stack of pairs (lhs, op).
     // It's implemented using two separate arrays, though.
     Node nodeStack[PRECEDENCE_CLASSES];
     ParseNodeKind kindStack[PRECEDENCE_CLASSES];
@@ -8897,22 +8891,22 @@ GeneralParser<ParseHandler, CharT>::orEx
     // modifier can be Operand.
     anyChars.ungetToken();
     anyChars.addModifierException(TokenStream::OperandIsNone);
 
     MOZ_ASSERT(depth == 0);
     return pn;
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 MOZ_ALWAYS_INLINE typename ParseHandler::Node
-GeneralParser<ParseHandler, CharT>::condExpr(InHandling inHandling, YieldHandling yieldHandling,
-                                             TripledotHandling tripledotHandling,
-                                             PossibleError* possibleError,
-                                             InvokedPrediction invoked /* = PredictUninvoked */)
+GeneralParser<ParseHandler, Unit>::condExpr(InHandling inHandling, YieldHandling yieldHandling,
+                                            TripledotHandling tripledotHandling,
+                                            PossibleError* possibleError,
+                                            InvokedPrediction invoked /* = PredictUninvoked */)
 {
     Node condition = orExpr(inHandling, yieldHandling, tripledotHandling, possibleError, invoked);
     if (!condition) {
         return null();
     }
 
     bool matched;
     if (!tokenStream.matchToken(&matched, TokenKind::Hook)) {
@@ -8932,22 +8926,22 @@ GeneralParser<ParseHandler, CharT>::cond
     Node elseExpr = assignExpr(inHandling, yieldHandling, TripledotProhibited);
     if (!elseExpr) {
         return null();
     }
 
     return handler.newConditional(condition, thenExpr, elseExpr);
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::Node
-GeneralParser<ParseHandler, CharT>::assignExpr(InHandling inHandling, YieldHandling yieldHandling,
-                                               TripledotHandling tripledotHandling,
-                                               PossibleError* possibleError /* = nullptr */,
-                                               InvokedPrediction invoked /* = PredictUninvoked */)
+GeneralParser<ParseHandler, Unit>::assignExpr(InHandling inHandling, YieldHandling yieldHandling,
+                                              TripledotHandling tripledotHandling,
+                                              PossibleError* possibleError /* = nullptr */,
+                                              InvokedPrediction invoked /* = PredictUninvoked */)
 {
     if (!CheckRecursionLimit(context)) {
         return null();
     }
 
     // It's very common at this point to have a "detectably simple" expression,
     // i.e. a name/number/string token followed by one of the following tokens
     // that obviously isn't part of an expression: , ; : ) ] }
@@ -9228,19 +9222,19 @@ PerHandlerParser<ParseHandler>::nameIsAr
         return js_eval_str;
     }
     if (handler.isArgumentsName(node, context)) {
         return js_arguments_str;
     }
     return nullptr;
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 bool
-GeneralParser<ParseHandler, CharT>::checkIncDecOperand(Node operand, uint32_t operandOffset)
+GeneralParser<ParseHandler, Unit>::checkIncDecOperand(Node operand, uint32_t operandOffset)
 {
     if (handler.isName(operand)) {
         if (const char* chars = nameIsArgumentsOrEval(operand)) {
             if (!strictModeErrorAt(operandOffset, JSMSG_BAD_STRICT_ASSIGN, chars)) {
                 return false;
             }
         }
     } else if (handler.isPropertyAccess(operand)) {
@@ -9258,34 +9252,34 @@ GeneralParser<ParseHandler, CharT>::chec
         return false;
     }
 
     MOZ_ASSERT(isValidSimpleAssignmentTarget(operand, PermitAssignmentToFunctionCalls),
                "inconsistent increment/decrement operand validation");
     return true;
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::UnaryNodeType
-GeneralParser<ParseHandler, CharT>::unaryOpExpr(YieldHandling yieldHandling, ParseNodeKind kind,
+GeneralParser<ParseHandler, Unit>::unaryOpExpr(YieldHandling yieldHandling, ParseNodeKind kind,
                                                 uint32_t begin)
 {
     Node kid = unaryExpr(yieldHandling, TripledotProhibited);
     if (!kid) {
         return null();
     }
     return handler.newUnary(kind, begin, kid);
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::Node
-GeneralParser<ParseHandler, CharT>::unaryExpr(YieldHandling yieldHandling,
-                                              TripledotHandling tripledotHandling,
-                                              PossibleError* possibleError /* = nullptr */,
-                                              InvokedPrediction invoked /* = PredictUninvoked */)
+GeneralParser<ParseHandler, Unit>::unaryExpr(YieldHandling yieldHandling,
+                                             TripledotHandling tripledotHandling,
+                                             PossibleError* possibleError /* = nullptr */,
+                                             InvokedPrediction invoked /* = PredictUninvoked */)
 {
     if (!CheckRecursionLimit(context)) {
         return null();
     }
 
     TokenKind tt;
     if (!tokenStream.getToken(&tt, TokenStream::Operand)) {
         return null();
@@ -9409,19 +9403,19 @@ GeneralParser<ParseHandler, CharT>::unar
                             ? ParseNodeKind::PostIncrement
                             : ParseNodeKind::PostDecrement;
         return handler.newUpdate(pnk, begin, expr);
       }
     }
 }
 
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::Node
-GeneralParser<ParseHandler, CharT>::assignExprWithoutYieldOrAwait(YieldHandling yieldHandling)
+GeneralParser<ParseHandler, Unit>::assignExprWithoutYieldOrAwait(YieldHandling yieldHandling)
 {
     uint32_t startYieldOffset = pc->lastYieldOffset;
     uint32_t startAwaitOffset = pc->lastAwaitOffset;
     Node res = assignExpr(InAllowed, yieldHandling, TripledotProhibited);
     if (res) {
         if (pc->lastYieldOffset != startYieldOffset) {
             errorAt(pc->lastYieldOffset, JSMSG_YIELD_IN_PARAMETER);
             return null();
@@ -9429,20 +9423,20 @@ GeneralParser<ParseHandler, CharT>::assi
         if (pc->lastAwaitOffset != startAwaitOffset) {
             errorAt(pc->lastAwaitOffset, JSMSG_AWAIT_IN_PARAMETER);
             return null();
         }
     }
     return res;
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::ListNodeType
-GeneralParser<ParseHandler, CharT>::argumentList(YieldHandling yieldHandling, bool* isSpread,
-                                                 PossibleError* possibleError /* = nullptr */)
+GeneralParser<ParseHandler, Unit>::argumentList(YieldHandling yieldHandling, bool* isSpread,
+                                                PossibleError* possibleError /* = nullptr */)
 {
     ListNodeType argsList = handler.newArguments(pos());
     if (!argsList) {
         return null();
     }
 
     bool matched;
     if (!tokenStream.matchToken(&matched, TokenKind::RightParen, TokenStream::Operand)) {
@@ -9507,23 +9501,23 @@ ParserBase::checkAndMarkSuperScope()
     if (!pc->sc()->allowSuperProperty()) {
         return false;
     }
 
     pc->setSuperScopeNeedsHomeObject();
     return true;
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::Node
-GeneralParser<ParseHandler, CharT>::memberExpr(YieldHandling yieldHandling,
-                                               TripledotHandling tripledotHandling,
-                                               TokenKind tt, bool allowCallSyntax /* = true */,
-                                               PossibleError* possibleError /* = nullptr */,
-                                               InvokedPrediction invoked /* = PredictUninvoked */)
+GeneralParser<ParseHandler, Unit>::memberExpr(YieldHandling yieldHandling,
+                                              TripledotHandling tripledotHandling,
+                                              TokenKind tt, bool allowCallSyntax /* = true */,
+                                              PossibleError* possibleError /* = nullptr */,
+                                              InvokedPrediction invoked /* = PredictUninvoked */)
 {
     MOZ_ASSERT(anyChars.isCurrentTokenType(tt));
 
     Node lhs;
 
     if (!CheckRecursionLimit(context)) {
         return null();
     }
@@ -9803,22 +9797,22 @@ PerHandlerParser<ParseHandler>::newName(
 
 template <class ParseHandler>
 inline typename ParseHandler::NameNodeType
 PerHandlerParser<ParseHandler>::newName(PropertyName* name, TokenPos pos)
 {
     return handler.newName(name, pos, context);
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 bool
-GeneralParser<ParseHandler, CharT>::checkLabelOrIdentifierReference(PropertyName* ident,
-                                                                    uint32_t offset,
-                                                                    YieldHandling yieldHandling,
-                                                                    TokenKind hint /* = TokenKind::Limit */)
+GeneralParser<ParseHandler, Unit>::checkLabelOrIdentifierReference(PropertyName* ident,
+                                                                   uint32_t offset,
+                                                                   YieldHandling yieldHandling,
+                                                                   TokenKind hint /* = TokenKind::Limit */)
 {
     TokenKind tt;
     if (hint == TokenKind::Limit) {
         tt = ReservedWordTokenKind(ident);
     } else {
         MOZ_ASSERT(hint == ReservedWordTokenKind(ident), "hint doesn't match actual token kind");
         tt = hint;
     }
@@ -9877,21 +9871,21 @@ GeneralParser<ParseHandler, CharT>::chec
     if (TokenKindIsFutureReservedWord(tt)) {
         errorAt(offset, JSMSG_RESERVED_ID, ReservedWordToCharZ(tt));
         return false;
     }
     MOZ_ASSERT_UNREACHABLE("Unexpected reserved word kind.");
     return false;
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 bool
-GeneralParser<ParseHandler, CharT>::checkBindingIdentifier(PropertyName* ident, uint32_t offset,
-                                                           YieldHandling yieldHandling,
-                                                           TokenKind hint /* = TokenKind::Limit */)
+GeneralParser<ParseHandler, Unit>::checkBindingIdentifier(PropertyName* ident, uint32_t offset,
+                                                          YieldHandling yieldHandling,
+                                                          TokenKind hint /* = TokenKind::Limit */)
 {
     if (pc->sc()->needStrictChecks()) {
         if (ident == context->names().arguments) {
             if (!strictModeErrorAt(offset, JSMSG_BAD_STRICT_ASSIGN, "arguments")) {
                 return false;
             }
             return true;
         }
@@ -9902,19 +9896,19 @@ GeneralParser<ParseHandler, CharT>::chec
             }
             return true;
         }
     }
 
     return checkLabelOrIdentifierReference(ident, offset, yieldHandling, hint);
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 PropertyName*
-GeneralParser<ParseHandler, CharT>::labelOrIdentifierReference(YieldHandling yieldHandling)
+GeneralParser<ParseHandler, Unit>::labelOrIdentifierReference(YieldHandling yieldHandling)
 {
     // ES 2017 draft 12.1.1.
     //   StringValue of IdentifierName normalizes any Unicode escape sequences
     //   in IdentifierName hence such escapes cannot be used to write an
     //   Identifier whose code point sequence is the same as a ReservedWord.
     //
     // Use PropertyName* instead of TokenKind to reflect the normalization.
 
@@ -9925,19 +9919,19 @@ GeneralParser<ParseHandler, CharT>::labe
                      : TokenKind::Limit;
     RootedPropertyName ident(context, anyChars.currentName());
     if (!checkLabelOrIdentifierReference(ident, pos().begin, yieldHandling, hint)) {
         return nullptr;
     }
     return ident;
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 PropertyName*
-GeneralParser<ParseHandler, CharT>::bindingIdentifier(YieldHandling yieldHandling)
+GeneralParser<ParseHandler, Unit>::bindingIdentifier(YieldHandling yieldHandling)
 {
     TokenKind hint = !anyChars.currentNameHasEscapes()
                      ? anyChars.currentToken().type
                      : TokenKind::Limit;
     RootedPropertyName ident(context, anyChars.currentName());
     if (!checkBindingIdentifier(ident, pos().begin, yieldHandling, hint)) {
         return nullptr;
     }
@@ -9974,30 +9968,30 @@ PerHandlerParser<ParseHandler>::noSubsti
     if (anyChars.hasInvalidTemplateEscape()) {
         anyChars.clearInvalidTemplateEscape();
         return handler.newRawUndefinedLiteral(pos());
     }
 
     return handler.newTemplateStringLiteral(anyChars.currentToken().atom(), pos());
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::NameNodeType
-GeneralParser<ParseHandler, CharT>::noSubstitutionUntaggedTemplate()
+GeneralParser<ParseHandler, Unit>::noSubstitutionUntaggedTemplate()
 {
     if (!tokenStream.checkForInvalidTemplateEscapeError()) {
         return null();
     }
 
     return handler.newTemplateStringLiteral(anyChars.currentToken().atom(), pos());
 }
 
-template <typename CharT>
+template <typename Unit>
 RegExpLiteral*
-Parser<FullParseHandler, CharT>::newRegExp()
+Parser<FullParseHandler, Unit>::newRegExp()
 {
     MOZ_ASSERT(!options().selfHostingMode);
 
     // Create the regexp and check its syntax.
     const auto& chars = tokenStream.getCharBuffer();
     RegExpFlag flags = anyChars.currentToken().regExpFlags();
 
     Rooted<RegExpObject*> reobj(context);
@@ -10005,49 +9999,49 @@ Parser<FullParseHandler, CharT>::newRegE
                                  TenuredObject);
     if (!reobj) {
         return null();
     }
 
     return handler.newRegExp(reobj, pos(), *this);
 }
 
-template <typename CharT>
+template <typename Unit>
 SyntaxParseHandler::RegExpLiteralType
-Parser<SyntaxParseHandler, CharT>::newRegExp()
+Parser<SyntaxParseHandler, Unit>::newRegExp()
 {
     MOZ_ASSERT(!options().selfHostingMode);
 
     // Only check the regexp's syntax, but don't create a regexp object.
     const auto& chars = tokenStream.getCharBuffer();
     RegExpFlag flags = anyChars.currentToken().regExpFlags();
 
     mozilla::Range<const char16_t> source(chars.begin(), chars.length());
     if (!js::irregexp::ParsePatternSyntax(anyChars, alloc, source, flags & UnicodeFlag)) {
         return null();
     }
 
     return handler.newRegExp(SyntaxParseHandler::NodeGeneric, pos(), *this);
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::RegExpLiteralType
-GeneralParser<ParseHandler, CharT>::newRegExp()
+GeneralParser<ParseHandler, Unit>::newRegExp()
 {
     return asFinalParser()->newRegExp();
 }
 
 // |exprPossibleError| is the PossibleError state within |expr|,
 // |possibleError| is the surrounding PossibleError state.
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 bool
-GeneralParser<ParseHandler, CharT>::checkDestructuringAssignmentTarget(Node expr, TokenPos exprPos,
-                                                                       PossibleError* exprPossibleError,
-                                                                       PossibleError* possibleError,
-                                                                       TargetBehavior behavior)
+GeneralParser<ParseHandler, Unit>::checkDestructuringAssignmentTarget(Node expr, TokenPos exprPos,
+                                                                      PossibleError* exprPossibleError,
+                                                                      PossibleError* possibleError,
+                                                                      TargetBehavior behavior)
 {
     // Report any pending expression error if we're definitely not in a
     // destructuring context or the possible destructuring target is a
     // property accessor.
     if (!possibleError || handler.isPropertyAccess(expr)) {
         return exprPossibleError->checkForExpressionError();
     }
 
@@ -10084,21 +10078,21 @@ GeneralParser<ParseHandler, CharT>::chec
         possibleError->setPendingDestructuringErrorAt(exprPos, JSMSG_BAD_DESTRUCT_PARENS);
     } else {
         possibleError->setPendingDestructuringErrorAt(exprPos, JSMSG_BAD_DESTRUCT_TARGET);
     }
 
     return true;
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 void
-GeneralParser<ParseHandler, CharT>::checkDestructuringAssignmentName(NameNodeType name,
-                                                                     TokenPos namePos,
-                                                                     PossibleError* possibleError)
+GeneralParser<ParseHandler, Unit>::checkDestructuringAssignmentName(NameNodeType name,
+                                                                    TokenPos namePos,
+                                                                    PossibleError* possibleError)
 {
 #ifdef DEBUG
     // GCC 8.0.1 crashes if this is a one-liner.
     bool isName = handler.isName(name);
     MOZ_ASSERT(isName);
 #endif
 
     // Return early if a pending destructuring error is already present.
@@ -10126,21 +10120,21 @@ GeneralParser<ParseHandler, CharT>::chec
                 possibleError->setPendingDestructuringWarningAt(namePos,
                                                                 JSMSG_BAD_STRICT_ASSIGN_EVAL);
             }
             return;
         }
     }
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 bool
-GeneralParser<ParseHandler, CharT>::checkDestructuringAssignmentElement(Node expr, TokenPos exprPos,
-                                                                        PossibleError* exprPossibleError,
-                                                                        PossibleError* possibleError)
+GeneralParser<ParseHandler, Unit>::checkDestructuringAssignmentElement(Node expr, TokenPos exprPos,
+                                                                       PossibleError* exprPossibleError,
+                                                                       PossibleError* possibleError)
 {
     // ES2018 draft rev 0719f44aab93215ed9a626b2f45bd34f36916834
     // 12.15.5 Destructuring Assignment
     //
     // AssignmentElement[Yield, Await]:
     //   DestructuringAssignmentTarget[?Yield, ?Await]
     //   DestructuringAssignmentTarget[?Yield, ?Await] Initializer[+In, ?Yield, ?Await]
 
@@ -10155,20 +10149,20 @@ GeneralParser<ParseHandler, CharT>::chec
         }
 
         exprPossibleError->transferErrorsTo(possibleError);
         return true;
     }
     return checkDestructuringAssignmentTarget(expr, exprPos, exprPossibleError, possibleError);
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::ListNodeType
-GeneralParser<ParseHandler, CharT>::arrayInitializer(YieldHandling yieldHandling,
-                                                     PossibleError* possibleError)
+GeneralParser<ParseHandler, Unit>::arrayInitializer(YieldHandling yieldHandling,
+                                                    PossibleError* possibleError)
 {
     MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::LeftBracket));
 
     uint32_t begin = pos().begin;
     ListNodeType literal = handler.newArrayLiteral(begin);
     if (!literal) {
         return null();
     }
@@ -10273,23 +10267,23 @@ GeneralParser<ParseHandler, CharT>::arra
                                          reportMissingClosing(JSMSG_BRACKET_AFTER_LIST,
                                                               JSMSG_BRACKET_OPENED, begin));
     }
 
     handler.setEndPosition(literal, pos().end);
     return literal;
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::Node
-GeneralParser<ParseHandler, CharT>::propertyName(YieldHandling yieldHandling,
-                                                 const Maybe<DeclarationKind>& maybeDecl,
-                                                 ListNodeType propList,
-                                                 PropertyType* propType,
-                                                 MutableHandleAtom propAtom)
+GeneralParser<ParseHandler, Unit>::propertyName(YieldHandling yieldHandling,
+                                                const Maybe<DeclarationKind>& maybeDecl,
+                                                ListNodeType propList,
+                                                PropertyType* propType,
+                                                MutableHandleAtom propAtom)
 {
     TokenKind ltok;
     if (!tokenStream.getToken(&ltok)) {
         return null();
     }
 
     MOZ_ASSERT(ltok != TokenKind::RightCurly, "caller should have handled TokenKind::RightCurly");
 
@@ -10485,21 +10479,21 @@ GeneralParser<ParseHandler, CharT>::prop
         }
         return propName;
     }
 
     error(JSMSG_COLON_AFTER_ID);
     return null();
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::UnaryNodeType
-GeneralParser<ParseHandler, CharT>::computedPropertyName(YieldHandling yieldHandling,
-                                                         const Maybe<DeclarationKind>& maybeDecl,
-                                                         ListNodeType literal)
+GeneralParser<ParseHandler, Unit>::computedPropertyName(YieldHandling yieldHandling,
+                                                        const Maybe<DeclarationKind>& maybeDecl,
+                                                        ListNodeType literal)
 {
     MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::LeftBracket));
 
     uint32_t begin = pos().begin;
 
     if (maybeDecl) {
         if (*maybeDecl == DeclarationKind::FormalParameter) {
             pc->functionBox()->hasParameterExprs = true;
@@ -10512,20 +10506,20 @@ GeneralParser<ParseHandler, CharT>::comp
     if (!assignNode) {
         return null();
     }
 
     MUST_MATCH_TOKEN_MOD(TokenKind::RightBracket, TokenStream::Operand, JSMSG_COMP_PROP_UNTERM_EXPR);
     return handler.newComputedName(assignNode, begin, pos().end);
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::ListNodeType
-GeneralParser<ParseHandler, CharT>::objectLiteral(YieldHandling yieldHandling,
-                                                  PossibleError* possibleError)
+GeneralParser<ParseHandler, Unit>::objectLiteral(YieldHandling yieldHandling,
+                                                 PossibleError* possibleError)
 {
     MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::LeftCurly));
 
     uint32_t openedPos = pos().begin;
 
     ListNodeType literal = handler.newObjectLiteral(pos().begin);
     if (!literal) {
         return null();
@@ -10766,20 +10760,20 @@ GeneralParser<ParseHandler, CharT>::obje
     MUST_MATCH_TOKEN_MOD_WITH_REPORT(TokenKind::RightCurly, TokenStream::Operand,
                                      reportMissingClosing(JSMSG_CURLY_AFTER_LIST,
                                                           JSMSG_CURLY_OPENED, openedPos));
 
     handler.setEndPosition(literal, pos().end);
     return literal;
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::CodeNodeType
-GeneralParser<ParseHandler, CharT>::methodDefinition(uint32_t toStringStart, PropertyType propType,
-                                                     HandleAtom funName)
+GeneralParser<ParseHandler, Unit>::methodDefinition(uint32_t toStringStart, PropertyType propType,
+                                                    HandleAtom funName)
 {
     FunctionSyntaxKind kind;
     switch (propType) {
       case PropertyType::Getter:
         kind = FunctionSyntaxKind::Getter;
         break;
 
       case PropertyType::Setter:
@@ -10821,19 +10815,19 @@ GeneralParser<ParseHandler, CharT>::meth
     if (!funNode) {
         return null();
     }
 
     return functionDefinition(funNode, toStringStart, InAllowed, yieldHandling, funName, kind,
                               generatorKind, asyncKind);
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 bool
-GeneralParser<ParseHandler, CharT>::tryNewTarget(BinaryNodeType* newTarget)
+GeneralParser<ParseHandler, Unit>::tryNewTarget(BinaryNodeType* newTarget)
 {
     MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::New));
 
     *newTarget = null();
 
     NullaryNodeType newHolder = handler.newPosHolder(pos());
     if (!newHolder) {
         return false;
@@ -10870,19 +10864,19 @@ GeneralParser<ParseHandler, CharT>::tryN
     if (!targetHolder) {
         return false;
     }
 
     *newTarget = handler.newNewTarget(newHolder, targetHolder);
     return !!*newTarget;
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::BinaryNodeType
-GeneralParser<ParseHandler, CharT>::importExpr(YieldHandling yieldHandling)
+GeneralParser<ParseHandler, Unit>::importExpr(YieldHandling yieldHandling)
 {
     MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Import));
 
     NullaryNodeType importHolder = handler.newPosHolder(pos());
     if (!importHolder) {
         return null();
     }
 
@@ -10925,22 +10919,22 @@ GeneralParser<ParseHandler, CharT>::impo
 
         return handler.newCallImport(importHolder, arg);
     } else {
         error(JSMSG_UNEXPECTED_TOKEN_NO_EXPECT, TokenKindToDesc(next));
         return null();
     }
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::Node
-GeneralParser<ParseHandler, CharT>::primaryExpr(YieldHandling yieldHandling,
-                                                TripledotHandling tripledotHandling,
-                                                TokenKind tt, PossibleError* possibleError,
-                                                InvokedPrediction invoked /* = PredictUninvoked */)
+GeneralParser<ParseHandler, Unit>::primaryExpr(YieldHandling yieldHandling,
+                                               TripledotHandling tripledotHandling,
+                                               TokenKind tt, PossibleError* possibleError,
+                                               InvokedPrediction invoked /* = PredictUninvoked */)
 {
     MOZ_ASSERT(anyChars.isCurrentTokenType(tt));
     if (!CheckRecursionLimit(context)) {
         return null();
     }
 
     switch (tt) {
       case TokenKind::Function:
@@ -11108,22 +11102,22 @@ GeneralParser<ParseHandler, CharT>::prim
         anyChars.ungetToken();  // put back right paren
 
         // Return an arbitrary expression node. See case TokenKind::RightParen above.
         return handler.newNullLiteral(pos());
       }
     }
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 typename ParseHandler::Node
-GeneralParser<ParseHandler, CharT>::exprInParens(InHandling inHandling,
-                                                 YieldHandling yieldHandling,
-                                                 TripledotHandling tripledotHandling,
-                                                 PossibleError* possibleError /* = nullptr */)
+GeneralParser<ParseHandler, Unit>::exprInParens(InHandling inHandling,
+                                                YieldHandling yieldHandling,
+                                                TripledotHandling tripledotHandling,
+                                                PossibleError* possibleError /* = nullptr */)
 {
     MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::LeftParen));
     return expr(inHandling, yieldHandling, tripledotHandling, possibleError, PredictInvoked);
 }
 
 template class PerHandlerParser<FullParseHandler>;
 template class PerHandlerParser<SyntaxParseHandler>;
 template class GeneralParser<FullParseHandler, Utf8Unit>;
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -54,17 +54,17 @@
  * syntax and full parsing but (because no source characters are examined) does
  * not vary by source text character type.  Such functionality is implemented
  * through functions in PerHandlerParser.
  *
  * Functionality only used by syntax parsing or full parsing doesn't live here:
  * it should be implemented in the appropriate Parser<ParseHandler> (described
  * further below).
  *
- * == GeneralParser<ParseHandler, CharT> → PerHandlerParser<ParseHandler> ==
+ * == GeneralParser<ParseHandler, Unit> → PerHandlerParser<ParseHandler> ==
  *
  * Most parsing behavior varies across the character-type axis (and possibly
  * along the full/syntax axis).  For example:
  *
  *   * Parsing ECMAScript's Expression production, implemented by
  *     GeneralParser::expr, varies in this manner: different types are used to
  *     represent nodes in full and syntax parsing (ParseNode* versus an enum),
  *     and reading the tokens comprising the expression requires inspecting
@@ -83,90 +83,90 @@
  * |TokenStreamSpecific| component, for all aspects of tokenizing that (contra
  * |TokenStreamAnyChars| in ParserBase above) are character-type-sensitive.  As
  * noted above, this field's existence separate from that in ParserBase
  * motivates the |AnyCharsAccess| template parameters on various token stream
  * classes.
  *
  * Everything in PerHandlerParser *could* be folded into GeneralParser (below)
  * if desired.  We don't fold in this manner because all such functions would
- * be instantiated once per CharT -- but if exactly equivalent code would be
- * generated (because PerHandlerParser functions have no awareness of CharT),
+ * be instantiated once per Unit -- but if exactly equivalent code would be
+ * generated (because PerHandlerParser functions have no awareness of Unit),
  * it's risky to *depend* upon the compiler coalescing the instantiations into
  * one in the final binary.  PerHandlerParser guarantees no duplication.
  *
- * == Parser<ParseHandler, CharT> final → GeneralParser<ParseHandler, CharT> ==
+ * == Parser<ParseHandler, Unit> final → GeneralParser<ParseHandler, Unit> ==
  *
  * The final (pun intended) axis of complexity lies in Parser.
  *
  * Some functionality depends on character type, yet also is defined in
  * significantly different form in full and syntax parsing.  For example,
  * attempting to parse the source text of a module will do so in full parsing
  * but immediately fail in syntax parsing -- so the former is a mess'o'code
  * while the latter is effectively |return null();|.  Such functionality is
- * defined in Parser<SyntaxParseHandler or FullParseHandler, CharT> as
+ * defined in Parser<SyntaxParseHandler or FullParseHandler, Unit> as
  * appropriate.
  *
  * There's a crucial distinction between GeneralParser and Parser, that
  * explains why both must exist (despite taking exactly the same template
  * parameters, and despite GeneralParser and Parser existing in a one-to-one
  * relationship).  GeneralParser is one unspecialized template class:
  *
- *   template<class ParseHandler, typename CharT>
+ *   template<class ParseHandler, typename Unit>
  *   class GeneralParser : ...
  *   {
  *     ...parsing functions...
  *   };
  *
  * but Parser is one undefined template class with two separate
  * specializations:
  *
  *   // Declare, but do not define.
- *   template<class ParseHandler, typename CharT> class Parser;
+ *   template<class ParseHandler, typename Unit> class Parser;
  *
  *   // Define a syntax-parsing specialization.
- *   template<typename CharT>
- *   class Parser<SyntaxParseHandler, CharT> final
- *     : public GeneralParser<SyntaxParseHandler, CharT>
+ *   template<typename Unit>
+ *   class Parser<SyntaxParseHandler, Unit> final
+ *     : public GeneralParser<SyntaxParseHandler, Unit>
  *   {
  *     ...parsing functions...
  *   };
  *
  *   // Define a full-parsing specialization.
- *   template<typename CharT>
- *   class Parser<SyntaxParseHandler, CharT> final
- *     : public GeneralParser<SyntaxParseHandler, CharT>
+ *   template<typename Unit>
+ *   class Parser<SyntaxParseHandler, Unit> final
+ *     : public GeneralParser<SyntaxParseHandler, Unit>
  *   {
  *     ...parsing functions...
  *   };
  *
  * This odd distinction is necessary because C++ unfortunately doesn't allow
  * partial function specialization:
  *
  *   // BAD: You can only specialize a template function if you specify *every*
- *   //      template parameter, i.e. ParseHandler *and* CharT.
- *   template<typename CharT>
+ *   //      template parameter, i.e. ParseHandler *and* Unit.
+ *   template<typename Unit>
  *   void
- *   GeneralParser<SyntaxParseHandler, CharT>::foo() {}
+ *   GeneralParser<SyntaxParseHandler, Unit>::foo() {}
  *
  * But if you specialize Parser *as a class*, then this is allowed:
  *
- *   template<typename CharT>
+ *   template<typename Unit>
  *   void
- *   Parser<SyntaxParseHandler, CharT>::foo() {}
+ *   Parser<SyntaxParseHandler, Unit>::foo() {}
  *
- *   template<typename CharT>
+ *   template<typename Unit>
  *   void
- *   Parser<FullParseHandler, CharT>::foo() {}
+ *   Parser<FullParseHandler, Unit>::foo() {}
  *
- * because the only template parameter on the function is CharT -- and so all
+ * because the only template parameter on the function is Unit -- and so all
  * template parameters *are* varying, not a strict subset of them.
  *
  * So -- any parsing functionality that is differently defined for different
- * ParseHandlers, *but* is defined textually identically for different CharT
+ * ParseHandlers, *but* is defined textually identically for different Unit
  * (even if different code ends up generated for them by the compiler), should
  * reside in Parser.
  */
 
 #include "mozilla/Array.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/TypeTraits.h"
 
@@ -185,24 +185,24 @@
 namespace js {
 
 class ModuleObject;
 
 namespace frontend {
 
 class ParserBase;
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 class GeneralParser;
 
 class SourceParseContext: public ParseContext
 {
 public:
-    template<typename ParseHandler, typename CharT>
-    SourceParseContext(GeneralParser<ParseHandler, CharT>* prs, SharedContext* sc,
+    template<typename ParseHandler, typename Unit>
+    SourceParseContext(GeneralParser<ParseHandler, Unit>* prs, SharedContext* sc,
                        Directives* newDirectives)
       : ParseContext(prs->context, prs->pc, sc, prs->tokenStream, prs->usedNames, newDirectives,
                      mozilla::IsSame<ParseHandler, FullParseHandler>::value)
     { }
 };
 
 template <typename T>
 inline T&
@@ -240,20 +240,20 @@ enum class PropertyType {
     AsyncMethod,
     AsyncGeneratorMethod,
     Constructor,
     DerivedConstructor
 };
 
 enum AwaitHandling : uint8_t { AwaitIsName, AwaitIsKeyword, AwaitIsModuleKeyword };
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 class AutoAwaitIsKeyword;
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 class AutoInParametersOfAsyncFunction;
 
 class MOZ_STACK_CLASS ParserBase
   : public StrictModeGetter,
     private JS::AutoGCRooter
 {
   private:
     ParserBase* thisForCtor() { return this; }
@@ -474,36 +474,36 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_TYPE
     //   parsing of inner functions. If null, then lazy parsing is disabled.
     //
     // When ParseHandler is SyntaxParseHandler:
     //
     //   If non-null, this field must be a sentinel value signaling that the
     //   syntax parse was aborted. If null, then lazy parsing was aborted due
     //   to encountering unsupported language constructs.
     //
-    // |internalSyntaxParser_| is really a |Parser<SyntaxParseHandler, CharT>*|
-    // where |CharT| varies per |Parser<ParseHandler, CharT>|.  But this
-    // template class doesn't know |CharT|, so we store a |void*| here and make
-    // |GeneralParser<ParseHandler, CharT>::getSyntaxParser| impose the real type.
+    // |internalSyntaxParser_| is really a |Parser<SyntaxParseHandler, Unit>*|
+    // where |Unit| varies per |Parser<ParseHandler, Unit>|.  But this
+    // template class doesn't know |Unit|, so we store a |void*| here and make
+    // |GeneralParser<ParseHandler, Unit>::getSyntaxParser| impose the real type.
     void* internalSyntaxParser_;
 
   private:
     // NOTE: The argument ordering here is deliberately different from the
     //       public constructor so that typos calling the public constructor
     //       are less likely to select this overload.
     PerHandlerParser(JSContext* cx, LifoAlloc& alloc, const JS::ReadOnlyCompileOptions& options,
                      bool foldConstants, UsedNameTracker& usedNames, LazyScript* lazyOuterFunction,
                      ScriptSourceObject* sourceObject, ParseGoal parseGoal,
                      void* internalSyntaxParser);
 
   protected:
-    template<typename CharT>
+    template<typename Unit>
     PerHandlerParser(JSContext* cx, LifoAlloc& alloc, const JS::ReadOnlyCompileOptions& options,
                      bool foldConstants, UsedNameTracker& usedNames,
-                     GeneralParser<SyntaxParseHandler, CharT>* syntaxParser,
+                     GeneralParser<SyntaxParseHandler, Unit>* syntaxParser,
                      LazyScript* lazyOuterFunction, ScriptSourceObject* sourceObject,
                      ParseGoal parseGoal)
       : PerHandlerParser(cx, alloc, options, foldConstants, usedNames, lazyOuterFunction,
                          sourceObject, parseGoal,
                          // JSOPTION_EXTRA_WARNINGS adds extra warnings not
                          // generated when functions are parsed lazily.
                          // ("use strict" doesn't inhibit lazy parsing.)
                          static_cast<void*>(options.extraWarningsOption ? nullptr : syntaxParser))
@@ -674,38 +674,38 @@ class ParserAnyCharsAccess
 // [Return] because its behavior is exactly equivalent to checking whether
 // we're in a function box -- easier and simpler than passing an extra
 // parameter everywhere.
 enum YieldHandling { YieldIsName, YieldIsKeyword };
 enum InHandling { InAllowed, InProhibited };
 enum DefaultHandling { NameRequired, AllowDefaultName };
 enum TripledotHandling { TripledotAllowed, TripledotProhibited };
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 class Parser;
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 class MOZ_STACK_CLASS GeneralParser
   : public PerHandlerParser<ParseHandler>
 {
   public:
-    using TokenStream = TokenStreamSpecific<CharT, ParserAnyCharsAccess<GeneralParser>>;
+    using TokenStream = TokenStreamSpecific<Unit, ParserAnyCharsAccess<GeneralParser>>;
 
   private:
     using Base = PerHandlerParser<ParseHandler>;
-    using FinalParser = Parser<ParseHandler, CharT>;
+    using FinalParser = Parser<ParseHandler, Unit>;
     using Node = typename ParseHandler::Node;
 
 #define DECLARE_TYPE(typeName, longTypeName, asMethodName) \
     using longTypeName = typename ParseHandler::longTypeName;
 FOR_EACH_PARSENODE_SUBCLASS(DECLARE_TYPE)
 #undef DECLARE_TYPE
 
     using typename Base::InvokedPrediction;
-    using SyntaxParser = Parser<SyntaxParseHandler, CharT>;
+    using SyntaxParser = Parser<SyntaxParseHandler, Unit>;
 
   protected:
     using Modifier = TokenStreamShared::Modifier;
     using Position = typename TokenStream::Position;
 
     using Base::PredictUninvoked;
     using Base::PredictInvoked;
 
@@ -832,17 +832,17 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_TYPE
         struct Error {
             ErrorState state_ = ErrorState::None;
 
             // Error reporting fields.
             uint32_t offset_;
             unsigned errorNumber_;
         };
 
-        GeneralParser<ParseHandler, CharT>& parser_;
+        GeneralParser<ParseHandler, Unit>& parser_;
         Error exprError_;
         Error destructuringError_;
         Error destructuringWarning_;
 
         // Returns the error report.
         Error& error(ErrorKind kind);
 
         // Return true if an error is pending without reporting.
@@ -862,17 +862,17 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_TYPE
         // If there is a pending warning, report it and return either false or
         // true depending on the werror option, otherwise return true.
         MOZ_MUST_USE bool checkForWarning(ErrorKind kind);
 
         // Transfer an existing error to another instance.
         void transferErrorTo(ErrorKind kind, PossibleError* other);
 
       public:
-        explicit PossibleError(GeneralParser<ParseHandler, CharT>& parser);
+        explicit PossibleError(GeneralParser<ParseHandler, Unit>& parser);
 
         // Return true if a pending destructuring error is present.
         bool hasPendingDestructuringError();
 
         // Set a pending destructuring error. Only a single error may be set
         // per instance, i.e. subsequent calls to this method are ignored and
         // won't overwrite the existing pending error.
         void setPendingDestructuringErrorAt(const TokenPos& pos, unsigned errorNumber);
@@ -909,17 +909,17 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_TYPE
         return reinterpret_cast<SyntaxParser*>(Base::internalSyntaxParser_);
     }
 
   public:
     TokenStream tokenStream;
 
   public:
     GeneralParser(JSContext* cx, LifoAlloc& alloc, const JS::ReadOnlyCompileOptions& options,
-                  const CharT* chars, size_t length, bool foldConstants,
+                  const Unit* units, size_t length, bool foldConstants,
                   UsedNameTracker& usedNames, SyntaxParser* syntaxParser,
                   LazyScript* lazyOuterFunction,
                   ScriptSourceObject* sourceObject,
                   ParseGoal parseGoal);
 
     inline void setAwaitHandling(AwaitHandling awaitHandling);
     inline void setInParametersOfAsyncFunction(bool inParameters);
 
@@ -1302,37 +1302,37 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_TYPE
     bool matchOrInsertSemicolon();
 
     bool noteDeclaredName(HandlePropertyName name, DeclarationKind kind, TokenPos pos);
 
   private:
     inline bool asmJS(ListNodeType list);
 };
 
-template <typename CharT>
-class MOZ_STACK_CLASS Parser<SyntaxParseHandler, CharT> final
-  : public GeneralParser<SyntaxParseHandler, CharT>
+template <typename Unit>
+class MOZ_STACK_CLASS Parser<SyntaxParseHandler, Unit> final
+  : public GeneralParser<SyntaxParseHandler, Unit>
 {
-    using Base = GeneralParser<SyntaxParseHandler, CharT>;
+    using Base = GeneralParser<SyntaxParseHandler, Unit>;
     using Node = SyntaxParseHandler::Node;
 
 #define DECLARE_TYPE(typeName, longTypeName, asMethodName) \
     using longTypeName = SyntaxParseHandler::longTypeName;
 FOR_EACH_PARSENODE_SUBCLASS(DECLARE_TYPE)
 #undef DECLARE_TYPE
 
-    using SyntaxParser = Parser<SyntaxParseHandler, CharT>;
+    using SyntaxParser = Parser<SyntaxParseHandler, Unit>;
 
     // Numerous Base::* functions have bodies like
     //
     //   return asFinalParser()->func(...);
     //
     // and must be able to call functions here.  Add a friendship relationship
     // so functions here can be hidden when appropriate.
-    friend class GeneralParser<SyntaxParseHandler, CharT>;
+    friend class GeneralParser<SyntaxParseHandler, Unit>;
 
   public:
     using Base::Base;
 
     // Inherited types, listed here to have non-dependent names.
     using typename Base::Modifier;
     using typename Base::Position;
     using typename Base::TokenStream;
@@ -1383,17 +1383,17 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_TYPE
     // Functions with multiple overloads of different visibility.  We can't
     // |using| the whole thing into existence because of the visibility
     // distinction, so we instead must manually delegate the required overload.
 
     PropertyName* bindingIdentifier(YieldHandling yieldHandling) {
         return Base::bindingIdentifier(yieldHandling);
     }
 
-    // Functions present in both Parser<ParseHandler, CharT> specializations.
+    // Functions present in both Parser<ParseHandler, Unit> specializations.
 
     inline void setAwaitHandling(AwaitHandling awaitHandling);
     inline void setInParametersOfAsyncFunction(bool inParameters);
 
     RegExpLiteralType newRegExp();
 
     // Parse a module.
     CodeNodeType moduleBody(ModuleSharedContext* modulesc);
@@ -1416,40 +1416,40 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_TYPE
                                      FunctionAsyncKind asyncKind, bool tryAnnexB,
                                      Directives inheritedDirectives, Directives* newDirectives);
 
     bool skipLazyInnerFunction(CodeNodeType funNode, uint32_t toStringStart,
                                FunctionSyntaxKind kind, bool tryAnnexB);
 
     bool asmJS(ListNodeType list);
 
-    // Functions present only in Parser<SyntaxParseHandler, CharT>.
+    // Functions present only in Parser<SyntaxParseHandler, Unit>.
 };
 
-template <typename CharT>
-class MOZ_STACK_CLASS Parser<FullParseHandler, CharT> final
-  : public GeneralParser<FullParseHandler, CharT>
+template <typename Unit>
+class MOZ_STACK_CLASS Parser<FullParseHandler, Unit> final
+  : public GeneralParser<FullParseHandler, Unit>
 {
-    using Base = GeneralParser<FullParseHandler, CharT>;
+    using Base = GeneralParser<FullParseHandler, Unit>;
     using Node = FullParseHandler::Node;
 
 #define DECLARE_TYPE(typeName, longTypeName, asMethodName) \
     using longTypeName = FullParseHandler::longTypeName;
 FOR_EACH_PARSENODE_SUBCLASS(DECLARE_TYPE)
 #undef DECLARE_TYPE
 
-    using SyntaxParser = Parser<SyntaxParseHandler, CharT>;
+    using SyntaxParser = Parser<SyntaxParseHandler, Unit>;
 
     // Numerous Base::* functions have bodies like
     //
     //   return asFinalParser()->func(...);
     //
     // and must be able to call functions here.  Add a friendship relationship
     // so functions here can be hidden when appropriate.
-    friend class GeneralParser<FullParseHandler, CharT>;
+    friend class GeneralParser<FullParseHandler, Unit>;
 
   public:
     using Base::Base;
 
     // Inherited types, listed here to have non-dependent names.
     using typename Base::Modifier;
     using typename Base::Position;
     using typename Base::TokenStream;
@@ -1506,22 +1506,22 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_TYPE
     // Functions with multiple overloads of different visibility.  We can't
     // |using| the whole thing into existence because of the visibility
     // distinction, so we instead must manually delegate the required overload.
 
     PropertyName* bindingIdentifier(YieldHandling yieldHandling) {
         return Base::bindingIdentifier(yieldHandling);
     }
 
-    // Functions present in both Parser<ParseHandler, CharT> specializations.
+    // Functions present in both Parser<ParseHandler, Unit> specializations.
 
-    friend class AutoAwaitIsKeyword<SyntaxParseHandler, CharT>;
+    friend class AutoAwaitIsKeyword<SyntaxParseHandler, Unit>;
     inline void setAwaitHandling(AwaitHandling awaitHandling);
 
-    friend class AutoInParametersOfAsyncFunction<SyntaxParseHandler, CharT>;
+    friend class AutoInParametersOfAsyncFunction<SyntaxParseHandler, Unit>;
     inline void setInParametersOfAsyncFunction(bool inParameters);
 
     RegExpLiteralType newRegExp();
 
     // Parse a module.
     CodeNodeType moduleBody(ModuleSharedContext* modulesc);
 
     BinaryNodeType importDeclaration();
@@ -1540,17 +1540,17 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_TYPE
                                      InHandling inHandling, YieldHandling yieldHandling,
                                      FunctionSyntaxKind kind, GeneratorKind generatorKind,
                                      FunctionAsyncKind asyncKind, bool tryAnnexB,
                                      Directives inheritedDirectives, Directives* newDirectives);
 
     bool skipLazyInnerFunction(CodeNodeType funNode, uint32_t toStringStart,
                                FunctionSyntaxKind kind, bool tryAnnexB);
 
-    // Functions present only in Parser<FullParseHandler, CharT>.
+    // Functions present only in Parser<FullParseHandler, Unit>.
 
     // Parse the body of an eval.
     //
     // Eval scripts are distinguished from global scripts in that in ES6, per
     // 18.2.1.1 steps 9 and 10, all eval scripts are executed under a fresh
     // lexical scope.
     LexicalScopeNodeType evalBody(EvalSharedContext* evalsc);
 
@@ -1629,20 +1629,20 @@ template<class Parser>
 ParserAnyCharsAccess<Parser>::anyChars(GeneralTokenStreamChars* ts)
 {
     const TokenStreamAnyChars& anyCharsConst =
         anyChars(const_cast<const GeneralTokenStreamChars*>(ts));
 
     return const_cast<TokenStreamAnyChars&>(anyCharsConst);
 }
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 class MOZ_STACK_CLASS AutoAwaitIsKeyword
 {
-    using GeneralParser = frontend::GeneralParser<ParseHandler, CharT>;
+    using GeneralParser = frontend::GeneralParser<ParseHandler, Unit>;
 
   private:
     GeneralParser* parser_;
     AwaitHandling oldAwaitHandling_;
 
   public:
     AutoAwaitIsKeyword(GeneralParser* parser, AwaitHandling awaitHandling) {
         parser_ = parser;
@@ -1655,20 +1655,20 @@ class MOZ_STACK_CLASS AutoAwaitIsKeyword
         }
     }
 
     ~AutoAwaitIsKeyword() {
         parser_->setAwaitHandling(oldAwaitHandling_);
     }
 };
 
-template <class ParseHandler, typename CharT>
+template <class ParseHandler, typename Unit>
 class MOZ_STACK_CLASS AutoInParametersOfAsyncFunction
 {
-    using GeneralParser = frontend::GeneralParser<ParseHandler, CharT>;
+    using GeneralParser = frontend::GeneralParser<ParseHandler, Unit>;
 
   private:
     GeneralParser* parser_;
     bool oldInParametersOfAsyncFunction_;
 
   public:
     AutoInParametersOfAsyncFunction(GeneralParser* parser, bool inParameters) {
         parser_ = parser;
--- a/js/src/frontend/TokenStream.cpp
+++ b/js/src/frontend/TokenStream.cpp
@@ -462,21 +462,21 @@ TokenStreamAnyChars::TokenStreamAnyChars
     isExprEnding[size_t(TokenKind::Comma)] = true;
     isExprEnding[size_t(TokenKind::Semi)] = true;
     isExprEnding[size_t(TokenKind::Colon)] = true;
     isExprEnding[size_t(TokenKind::RightParen)] = true;
     isExprEnding[size_t(TokenKind::RightBracket)] = true;
     isExprEnding[size_t(TokenKind::RightCurly)] = true;
 }
 
-template<typename CharT>
-TokenStreamCharsBase<CharT>::TokenStreamCharsBase(JSContext* cx, const CharT* chars, size_t length,
-                                                  size_t startOffset)
+template<typename Unit>
+TokenStreamCharsBase<Unit>::TokenStreamCharsBase(JSContext* cx, const Unit* units, size_t length,
+                                                 size_t startOffset)
   : TokenStreamCharsShared(cx),
-    sourceUnits(chars, length, startOffset)
+    sourceUnits(units, length, startOffset)
 {}
 
 template<>
 MOZ_MUST_USE bool
 TokenStreamCharsBase<char16_t>::fillCharBufferFromSourceNormalizingAsciiLineBreaks(const char16_t* cur,
                                                                                    const char16_t* end)
 {
     MOZ_ASSERT(this->charBuffer.length() == 0);
@@ -532,21 +532,21 @@ TokenStreamCharsBase<Utf8Unit>::fillChar
             return false;
         }
     }
 
     MOZ_ASSERT(cur == end);
     return true;
 }
 
-template<typename CharT, class AnyCharsAccess>
-TokenStreamSpecific<CharT, AnyCharsAccess>::TokenStreamSpecific(JSContext* cx,
-                                                                const ReadOnlyCompileOptions& options,
-                                                                const CharT* base, size_t length)
-  : TokenStreamChars<CharT, AnyCharsAccess>(cx, base, length, options.scriptSourceOffset)
+template<typename Unit, class AnyCharsAccess>
+TokenStreamSpecific<Unit, AnyCharsAccess>::TokenStreamSpecific(JSContext* cx,
+                                                               const ReadOnlyCompileOptions& options,
+                                                               const Unit* units, size_t length)
+  : TokenStreamChars<Unit, AnyCharsAccess>(cx, units, length, options.scriptSourceOffset)
 {}
 
 bool
 TokenStreamAnyChars::checkOptions()
 {
     // Constrain starting columns to half of the range of a signed 32-bit value,
     // to avoid overflow.
     if (options().column >= mozilla::MaxValue<int32_t>::value / 2 + 1) {
@@ -875,19 +875,19 @@ TokenStreamChars<char16_t, AnyCharsAcces
     }
 
     // Otherwise we have a multi-unit code point.
     *codePoint = unicode::UTF16Decode(lead, this->sourceUnits.getCodeUnit());
     MOZ_ASSERT(!IsLineTerminator(AssertedCast<char32_t>(*codePoint)));
     return true;
 }
 
-template<typename CharT, class AnyCharsAccess>
+template<typename Unit, class AnyCharsAccess>
 bool
-TokenStreamSpecific<CharT, AnyCharsAccess>::getCodePoint(int32_t* cp)
+TokenStreamSpecific<Unit, AnyCharsAccess>::getCodePoint(int32_t* cp)
 {
     int32_t unit = getCodeUnit();
     if (unit == EOF) {
         MOZ_ASSERT(anyCharsAccess().flags.isEOF,
                    "flags.isEOF should have been set by getCodeUnit()");
         *cp = EOF;
         return true;
     }
@@ -1196,75 +1196,75 @@ SourceUnits<Utf8Unit>::findWindowEnd(siz
 
         p += len;
     }
 
     MOZ_ASSERT(HalfWindowSize() <= WindowRadius);
     return offset + HalfWindowSize();
 }
 
-template<typename CharT, class AnyCharsAccess>
+template<typename Unit, class AnyCharsAccess>
 bool
-TokenStreamSpecific<CharT, AnyCharsAccess>::advance(size_t position)
+TokenStreamSpecific<Unit, AnyCharsAccess>::advance(size_t position)
 {
-    const CharT* end = this->sourceUnits.codeUnitPtrAt(position);
+    const Unit* end = this->sourceUnits.codeUnitPtrAt(position);
     while (this->sourceUnits.addressOfNextCodeUnit() < end) {
         int32_t c;
         if (!getCodePoint(&c)) {
             return false;
         }
     }
 
     TokenStreamAnyChars& anyChars = anyCharsAccess();
     Token* cur = const_cast<Token*>(&anyChars.currentToken());
     cur->pos.begin = this->sourceUnits.offset();
     MOZ_MAKE_MEM_UNDEFINED(&cur->type, sizeof(cur->type));
     anyChars.lookahead = 0;
     return true;
 }
 
-template<typename CharT, class AnyCharsAccess>
+template<typename Unit, class AnyCharsAccess>
 void
-TokenStreamSpecific<CharT, AnyCharsAccess>::seek(const Position& pos)
+TokenStreamSpecific<Unit, AnyCharsAccess>::seek(const Position& pos)
 {
     TokenStreamAnyChars& anyChars = anyCharsAccess();
 
     this->sourceUnits.setAddressOfNextCodeUnit(pos.buf, /* allowPoisoned = */ true);
     anyChars.flags = pos.flags;
     anyChars.lineno = pos.lineno;
     anyChars.linebase = pos.linebase;
     anyChars.prevLinebase = pos.prevLinebase;
     anyChars.lookahead = pos.lookahead;
 
     anyChars.tokens[anyChars.cursor()] = pos.currentToken;
     for (unsigned i = 0; i < anyChars.lookahead; i++) {
         anyChars.tokens[anyChars.aheadCursor(1 + i)] = pos.lookaheadTokens[i];
     }
 }
 
-template<typename CharT, class AnyCharsAccess>
+template<typename Unit, class AnyCharsAccess>
 bool
-TokenStreamSpecific<CharT, AnyCharsAccess>::seek(const Position& pos,
+TokenStreamSpecific<Unit, AnyCharsAccess>::seek(const Position& pos,
                                                  const TokenStreamAnyChars& other)
 {
     if (!anyCharsAccess().srcCoords.fill(other.srcCoords)) {
         return false;
     }
 
     seek(pos);
     return true;
 }
 
-template<typename CharT, class AnyCharsAccess>
+template<typename Unit, class AnyCharsAccess>
 bool
-TokenStreamSpecific<CharT, AnyCharsAccess>::reportStrictModeErrorNumberVA(UniquePtr<JSErrorNotes> notes,
-                                                                          uint32_t offset,
-                                                                          bool strictMode,
-                                                                          unsigned errorNumber,
-                                                                          va_list* args)
+TokenStreamSpecific<Unit, AnyCharsAccess>::reportStrictModeErrorNumberVA(UniquePtr<JSErrorNotes> notes,
+                                                                         uint32_t offset,
+                                                                         bool strictMode,
+                                                                         unsigned errorNumber,
+                                                                         va_list* args)
 {
     TokenStreamAnyChars& anyChars = anyCharsAccess();
     if (!strictMode && !anyChars.options().extraWarningsOption) {
         return true;
     }
 
     ErrorMetadata metadata;
     if (!computeErrorMetadata(&metadata, offset)) {
@@ -1324,42 +1324,42 @@ TokenStreamAnyChars::fillExcludingContex
     }
 
     // Otherwise use this TokenStreamAnyChars's location information.
     err->filename = filename_;
     srcCoords.lineNumAndColumnIndex(offset, &err->lineNumber, &err->columnNumber);
     return true;
 }
 
-template<typename CharT, class AnyCharsAccess>
+template<typename Unit, class AnyCharsAccess>
 bool
-TokenStreamSpecific<CharT, AnyCharsAccess>::hasTokenizationStarted() const
+TokenStreamSpecific<Unit, AnyCharsAccess>::hasTokenizationStarted() const
 {
     const TokenStreamAnyChars& anyChars = anyCharsAccess();
     return anyChars.isCurrentTokenType(TokenKind::Eof) && !anyChars.isEOF();
 }
 
 void
 TokenStreamAnyChars::lineAndColumnAt(size_t offset, uint32_t* line, uint32_t* column) const
 {
     srcCoords.lineNumAndColumnIndex(offset, line, column);
 }
 
-template<typename CharT, class AnyCharsAccess>
+template<typename Unit, class AnyCharsAccess>
 void
-TokenStreamSpecific<CharT, AnyCharsAccess>::currentLineAndColumn(uint32_t* line, uint32_t* column) const
+TokenStreamSpecific<Unit, AnyCharsAccess>::currentLineAndColumn(uint32_t* line, uint32_t* column) const
 {
     const TokenStreamAnyChars& anyChars = anyCharsAccess();
     uint32_t offset = anyChars.currentToken().pos.begin;
     anyChars.srcCoords.lineNumAndColumnIndex(offset, line, column);
 }
 
-template<typename CharT>
+template<typename Unit>
 bool
-TokenStreamCharsBase<CharT>::addLineOfContext(ErrorMetadata* err, uint32_t offset)
+TokenStreamCharsBase<Unit>::addLineOfContext(ErrorMetadata* err, uint32_t offset)
 {
     size_t windowStart = sourceUnits.findWindowStart(offset);
     size_t windowEnd = sourceUnits.findWindowEnd(offset);
 
     size_t windowLength = windowEnd - windowStart;
     MOZ_ASSERT(windowLength <= SourceUnits::WindowRadius * 2);
 
     // Don't add a useless "line" of context when the window ends up empty
@@ -1372,17 +1372,17 @@ TokenStreamCharsBase<CharT>::addLineOfCo
     }
 
     // We might have hit an error while processing some source code feature
     // that's accumulating text into |this->charBuffer| -- e.g. we could be
     // halfway into a regular expression literal, then encounter invalid UTF-8.
     // Thus we must clear |this->charBuffer| of prior work.
     this->charBuffer.clear();
 
-    const CharT* start = sourceUnits.codeUnitPtrAt(windowStart);
+    const Unit* start = sourceUnits.codeUnitPtrAt(windowStart);
     if (!fillCharBufferFromSourceNormalizingAsciiLineBreaks(start, start + windowLength)) {
         return false;
     }
 
     // The windowed string is null-terminated.
     if (!this->charBuffer.append('\0')) {
         return false;
     }
@@ -1392,20 +1392,20 @@ TokenStreamCharsBase<CharT>::addLineOfCo
         return false;
     }
 
     err->lineLength = windowLength;
     err->tokenOffset = offset - windowStart;
     return true;
 }
 
-template<typename CharT, class AnyCharsAccess>
+template<typename Unit, class AnyCharsAccess>
 bool
-TokenStreamSpecific<CharT, AnyCharsAccess>::computeErrorMetadata(ErrorMetadata* err,
-                                                                 uint32_t offset)
+TokenStreamSpecific<Unit, AnyCharsAccess>::computeErrorMetadata(ErrorMetadata* err,
+                                                                uint32_t offset)
 {
     if (offset == NoOffset) {
         anyCharsAccess().computeErrorMetadataNoOffset(err);
         return true;
     }
 
     // This function's return value isn't a success/failure indication: it
     // returns true if this TokenStream's location information could be used,
@@ -1414,34 +1414,34 @@ TokenStreamSpecific<CharT, AnyCharsAcces
     if (!anyCharsAccess().fillExcludingContext(err, offset)) {
         return true;
     }
 
     // Add a line of context from this TokenStream to help with debugging.
     return internalComputeLineOfContext(err, offset);
 }
 
-template<typename CharT, class AnyCharsAccess>
+template<typename Unit, class AnyCharsAccess>
 bool
-TokenStreamSpecific<CharT, AnyCharsAccess>::reportStrictModeError(unsigned errorNumber, ...)
+TokenStreamSpecific<Unit, AnyCharsAccess>::reportStrictModeError(unsigned errorNumber, ...)
 {
     va_list args;
     va_start(args, errorNumber);
 
     TokenStreamAnyChars& anyChars = anyCharsAccess();
     bool result = reportStrictModeErrorNumberVA(nullptr, anyChars.currentToken().pos.begin,
                                                 anyChars.strictMode(), errorNumber, &args);
 
     va_end(args);
     return result;
 }
 
-template<typename CharT, class AnyCharsAccess>
+template<typename Unit, class AnyCharsAccess>
 void
-TokenStreamSpecific<CharT, AnyCharsAccess>::reportError(unsigned errorNumber, ...)
+TokenStreamSpecific<Unit, AnyCharsAccess>::reportError(unsigned errorNumber, ...)
 {
     va_list args;
     va_start(args, errorNumber);
 
     TokenStreamAnyChars& anyChars = anyCharsAccess();
     ErrorMetadata metadata;
     if (computeErrorMetadata(&metadata, anyChars.currentToken().pos.begin)) {
         ReportCompileError(anyChars.cx, std::move(metadata), nullptr, JSREPORT_ERROR, errorNumber,
@@ -1466,111 +1466,111 @@ void
 TokenStreamAnyChars::reportErrorNoOffsetVA(unsigned errorNumber, va_list args)
 {
     ErrorMetadata metadata;
     computeErrorMetadataNoOffset(&metadata);
 
     ReportCompileError(cx, std::move(metadata), nullptr, JSREPORT_ERROR, errorNumber, args);
 }
 
-template<typename CharT, class AnyCharsAccess>
+template<typename Unit, class AnyCharsAccess>
 bool
-TokenStreamSpecific<CharT, AnyCharsAccess>::warning(unsigned errorNumber, ...)
+TokenStreamSpecific<Unit, AnyCharsAccess>::warning(unsigned errorNumber, ...)
 {
     va_list args;
     va_start(args, errorNumber);
 
     ErrorMetadata metadata;
     bool result =
         computeErrorMetadata(&metadata, anyCharsAccess().currentToken().pos.begin) &&
         anyCharsAccess().compileWarning(std::move(metadata), nullptr, JSREPORT_WARNING, errorNumber,
                                         args);
 
     va_end(args);
     return result;
 }
 
-template<typename CharT, class AnyCharsAccess>
+template<typename Unit, class AnyCharsAccess>
 bool
-TokenStreamSpecific<CharT, AnyCharsAccess>::reportExtraWarningErrorNumberVA(UniquePtr<JSErrorNotes> notes,
-                                                                            uint32_t offset,
-                                                                            unsigned errorNumber,
-                                                                            va_list* args)
+TokenStreamSpecific<Unit, AnyCharsAccess>::reportExtraWarningErrorNumberVA(UniquePtr<JSErrorNotes> notes,
+                                                                           uint32_t offset,
+                                                                           unsigned errorNumber,
+                                                                           va_list* args)
 {
     TokenStreamAnyChars& anyChars = anyCharsAccess();
     if (!anyChars.options().extraWarningsOption) {
         return true;
     }
 
     ErrorMetadata metadata;
     if (!computeErrorMetadata(&metadata, offset)) {
         return false;
     }
 
     return anyChars.compileWarning(std::move(metadata), std::move(notes), JSREPORT_STRICT | JSREPORT_WARNING,
                                    errorNumber, *args);
 }
 
-template<typename CharT, class AnyCharsAccess>
+template<typename Unit, class AnyCharsAccess>
 void
-TokenStreamSpecific<CharT, AnyCharsAccess>::error(unsigned errorNumber, ...)
+TokenStreamSpecific<Unit, AnyCharsAccess>::error(unsigned errorNumber, ...)
 {
     va_list args;
     va_start(args, errorNumber);
 
     ErrorMetadata metadata;
     if (computeErrorMetadata(&metadata, this->sourceUnits.offset())) {
         TokenStreamAnyChars& anyChars = anyCharsAccess();
         ReportCompileError(anyChars.cx, std::move(metadata), nullptr, JSREPORT_ERROR, errorNumber,
                            args);
     }
 
     va_end(args);
 }
 
-template<typename CharT, class AnyCharsAccess>
+template<typename Unit, class AnyCharsAccess>
 void
-TokenStreamSpecific<CharT, AnyCharsAccess>::errorAtVA(uint32_t offset, unsigned errorNumber, va_list *args)
+TokenStreamSpecific<Unit, AnyCharsAccess>::errorAtVA(uint32_t offset, unsigned errorNumber, va_list *args)
 {
     ErrorMetadata metadata;
     if (computeErrorMetadata(&metadata, offset)) {
         TokenStreamAnyChars& anyChars = anyCharsAccess();
         ReportCompileError(anyChars.cx, std::move(metadata), nullptr, JSREPORT_ERROR, errorNumber,
                            *args);
     }
 }
 
 
-template<typename CharT, class AnyCharsAccess>
+template<typename Unit, class AnyCharsAccess>
 void
-TokenStreamSpecific<CharT, AnyCharsAccess>::errorAt(uint32_t offset, unsigned errorNumber, ...)
+TokenStreamSpecific<Unit, AnyCharsAccess>::errorAt(uint32_t offset, unsigned errorNumber, ...)
 {
     va_list args;
     va_start(args, errorNumber);
 
     errorAtVA(offset, errorNumber, &args);
 
     va_end(args);
 }
 
 // We have encountered a '\': check for a Unicode escape sequence after it.
 // Return the length of the escape sequence and the encoded code point (by
 // value) if we found a Unicode escape sequence, and skip all code units
 // involed.  Otherwise, return 0 and don't advance along the buffer.
-template<typename CharT, class AnyCharsAccess>
+template<typename Unit, class AnyCharsAccess>
 uint32_t
-GeneralTokenStreamChars<CharT, AnyCharsAccess>::matchUnicodeEscape(uint32_t* codePoint)
+GeneralTokenStreamChars<Unit, AnyCharsAccess>::matchUnicodeEscape(uint32_t* codePoint)
 {
-    MOZ_ASSERT(this->sourceUnits.previousCodeUnit() == CharT('\\'));
+    MOZ_ASSERT(this->sourceUnits.previousCodeUnit() == Unit('\\'));
 
     int32_t unit = getCodeUnit();
     if (unit != 'u') {
         // NOTE: |unit| may be EOF here.
         ungetCodeUnit(unit);
-        MOZ_ASSERT(this->sourceUnits.previousCodeUnit() == CharT('\\'));
+        MOZ_ASSERT(this->sourceUnits.previousCodeUnit() == Unit('\\'));
         return 0;
     }
 
     char16_t v;
     unit = getCodeUnit();
     if (JS7_ISHEX(unit) && this->sourceUnits.matchHexDigits(3, &v)) {
         *codePoint = (JS7_UNHEX(unit) << 12) | v;
         return 5;
@@ -1578,25 +1578,25 @@ GeneralTokenStreamChars<CharT, AnyCharsA
 
     if (unit == '{') {
         return matchExtendedUnicodeEscape(codePoint);
     }
 
     // NOTE: |unit| may be EOF here, so this ungets either one or two units.
     ungetCodeUnit(unit);
     ungetCodeUnit('u');
-    MOZ_ASSERT(this->sourceUnits.previousCodeUnit() == CharT('\\'));
+    MOZ_ASSERT(this->sourceUnits.previousCodeUnit() == Unit('\\'));
     return 0;
 }
 
-template<typename CharT, class AnyCharsAccess>
+template<typename Unit, class AnyCharsAccess>
 uint32_t
-GeneralTokenStreamChars<CharT, AnyCharsAccess>::matchExtendedUnicodeEscape(uint32_t* codePoint)
+GeneralTokenStreamChars<Unit, AnyCharsAccess>::matchExtendedUnicodeEscape(uint32_t* codePoint)
 {
-    MOZ_ASSERT(this->sourceUnits.previousCodeUnit() == CharT('{'));
+    MOZ_ASSERT(this->sourceUnits.previousCodeUnit() == Unit('{'));
 
     int32_t unit = getCodeUnit();
 
     // Skip leading zeroes.
     uint32_t leadingZeroes = 0;
     while (unit == '0') {
         leadingZeroes++;
         unit = getCodeUnit();
@@ -1617,58 +1617,58 @@ GeneralTokenStreamChars<CharT, AnyCharsA
         (unit != EOF); // subtract a get if it didn't contribute to length
 
     if (unit == '}' && (leadingZeroes > 0 || i > 0) && code <= unicode::NonBMPMax) {
         *codePoint = code;
         return gotten;
     }
 
     this->sourceUnits.unskipCodeUnits(gotten);
-    MOZ_ASSERT(this->sourceUnits.previousCodeUnit() == CharT('\\'));
+    MOZ_ASSERT(this->sourceUnits.previousCodeUnit() == Unit('\\'));
     return 0;
 }
 
-template<typename CharT, class AnyCharsAccess>
+template<typename Unit, class AnyCharsAccess>
 uint32_t
-GeneralTokenStreamChars<CharT, AnyCharsAccess>::matchUnicodeEscapeIdStart(uint32_t* codePoint)
+GeneralTokenStreamChars<Unit, AnyCharsAccess>::matchUnicodeEscapeIdStart(uint32_t* codePoint)
 {
     uint32_t length = matchUnicodeEscape(codePoint);
     if (MOZ_LIKELY(length > 0)) {
         if (MOZ_LIKELY(unicode::IsIdentifierStart(*codePoint))) {
             return length;
         }
 
         this->sourceUnits.unskipCodeUnits(length);
     }
 
-    MOZ_ASSERT(this->sourceUnits.previousCodeUnit() == CharT('\\'));
+    MOZ_ASSERT(this->sourceUnits.previousCodeUnit() == Unit('\\'));
     return 0;
 }
 
-template<typename CharT, class AnyCharsAccess>
+template<typename Unit, class AnyCharsAccess>
 bool
-GeneralTokenStreamChars<CharT, AnyCharsAccess>::matchUnicodeEscapeIdent(uint32_t* codePoint)
+GeneralTokenStreamChars<Unit, AnyCharsAccess>::matchUnicodeEscapeIdent(uint32_t* codePoint)
 {
     uint32_t length = matchUnicodeEscape(codePoint);
     if (MOZ_LIKELY(length > 0)) {
         if (MOZ_LIKELY(unicode::IsIdentifierPart(*codePoint))) {
             return true;
         }
 
         this->sourceUnits.unskipCodeUnits(length);
     }
 
-    MOZ_ASSERT(this->sourceUnits.previousCodeUnit() == CharT('\\'));
+    MOZ_ASSERT(this->sourceUnits.previousCodeUnit() == Unit('\\'));
     return false;
 }
 
-template<typename CharT, class AnyCharsAccess>
+template<typename Unit, class AnyCharsAccess>
 bool
-TokenStreamSpecific<CharT, AnyCharsAccess>::getDirectives(bool isMultiline,
-                                                          bool shouldWarnDeprecated)
+TokenStreamSpecific<Unit, AnyCharsAccess>::getDirectives(bool isMultiline,
+                                                         bool shouldWarnDeprecated)
 {
     // Match directive comments used in debugging, such as "//# sourceURL" and
     // "//# sourceMappingURL". Use of "//@" instead of "//#" is deprecated.
     //
     // To avoid a crashing bug in IE, several JavaScript transpilers wrap single
     // line comments containing a source mapping URL inside a multiline
     // comment. To avoid potentially expensive lookahead and backtracking, we
     // only check for this case if we encounter a '#' code unit.
@@ -1693,24 +1693,24 @@ TokenStreamCharsShared::copyCharBufferTo
         return false;
     }
 
     std::copy(charBuffer.begin(), charBuffer.end(), destination->get());
     (*destination)[length] = '\0';
     return true;
 }
 
-template<typename CharT, class AnyCharsAccess>
+template<typename Unit, class AnyCharsAccess>
 MOZ_MUST_USE bool
-TokenStreamSpecific<CharT, AnyCharsAccess>::getDirective(bool isMultiline,
-                                                         bool shouldWarnDeprecated,
-                                                         const char* directive,
-                                                         uint8_t directiveLength,
-                                                         const char* errorMsgPragma,
-                                                         UniquePtr<char16_t[], JS::FreePolicy>* destination)
+TokenStreamSpecific<Unit, AnyCharsAccess>::getDirective(bool isMultiline,
+                                                        bool shouldWarnDeprecated,
+                                                        const char* directive,
+                                                        uint8_t directiveLength,
+                                                        const char* errorMsgPragma,
+                                                        UniquePtr<char16_t[], JS::FreePolicy>* destination)
 {
     // Stop if we don't find |directive|.  (Note that |directive| must be
     // ASCII, so there are no tricky encoding issues to consider in matching
     // UTF-8/16-agnostically.)
     if (!this->sourceUnits.matchCodeUnits(directive, directiveLength)) {
         return true;
     }
 
@@ -1747,17 +1747,17 @@ TokenStreamSpecific<CharT, AnyCharsAcces
                 return false;
             }
 
             continue;
         }
 
         // This ignores encoding errors: subsequent caller-side code to
         // handle the remaining source text in the comment will do so.
-        PeekedCodePoint<CharT> peeked = this->sourceUnits.peekCodePoint();
+        PeekedCodePoint<Unit> peeked = this->sourceUnits.peekCodePoint();
         if (peeked.isNone() || unicode::IsSpaceOrBOM2(peeked.codePoint())) {
             break;
         }
 
         MOZ_ASSERT(!IsLineTerminator(peeked.codePoint()),
                    "!IsSpaceOrBOM2 must imply !IsLineTerminator or else we'll "
                    "fail to maintain line-info/flags for EOL");
         this->sourceUnits.consumeKnownCodePoint(peeked);
@@ -1771,55 +1771,55 @@ TokenStreamSpecific<CharT, AnyCharsAcces
         // The directive's URL was missing, but comments can contain anything,
         // so it isn't an error.
         return true;
     }
 
     return copyCharBufferTo(anyCharsAccess().cx, destination);
 }
 
-template<typename CharT, class AnyCharsAccess>
+template<typename Unit, class AnyCharsAccess>
 bool
-TokenStreamSpecific<CharT, AnyCharsAccess>::getDisplayURL(bool isMultiline,
-                                                          bool shouldWarnDeprecated)
+TokenStreamSpecific<Unit, AnyCharsAccess>::getDisplayURL(bool isMultiline,
+                                                         bool shouldWarnDeprecated)
 {
     // Match comments of the form "//# sourceURL=<url>" or
     // "/\* //# sourceURL=<url> *\/"
     //
     // Note that while these are labeled "sourceURL" in the source text,
     // internally we refer to it as a "displayURL" to distinguish what the
     // developer would like to refer to the source as from the source's actual
     // URL.
 
     static const char sourceURLDirective[] = " sourceURL=";
     constexpr uint8_t sourceURLDirectiveLength = ArrayLength(sourceURLDirective) - 1;
     return getDirective(isMultiline, shouldWarnDeprecated,
                         sourceURLDirective, sourceURLDirectiveLength,
                         "sourceURL", &anyCharsAccess().displayURL_);
 }
 
-template<typename CharT, class AnyCharsAccess>
+template<typename Unit, class AnyCharsAccess>
 bool
-TokenStreamSpecific<CharT, AnyCharsAccess>::getSourceMappingURL(bool isMultiline,
-                                                                bool shouldWarnDeprecated)
+TokenStreamSpecific<Unit, AnyCharsAccess>::getSourceMappingURL(bool isMultiline,
+                                                               bool shouldWarnDeprecated)
 {
     // Match comments of the form "//# sourceMappingURL=<url>" or
     // "/\* //# sourceMappingURL=<url> *\/"
 
     static const char sourceMappingURLDirective[] = " sourceMappingURL=";
     constexpr uint8_t sourceMappingURLDirectiveLength = ArrayLength(sourceMappingURLDirective) - 1;
     return getDirective(isMultiline, shouldWarnDeprecated,
                         sourceMappingURLDirective, sourceMappingURLDirectiveLength,
                         "sourceMappingURL", &anyCharsAccess().sourceMapURL_);
 }
 
-template<typename CharT, class AnyCharsAccess>
+template<typename Unit, class AnyCharsAccess>
 MOZ_ALWAYS_INLINE Token*
-GeneralTokenStreamChars<CharT, AnyCharsAccess>::newTokenInternal(TokenKind kind, TokenStart start,
-                                                                 TokenKind* out)
+GeneralTokenStreamChars<Unit, AnyCharsAccess>::newTokenInternal(TokenKind kind, TokenStart start,
+                                                                TokenKind* out)
 {
     MOZ_ASSERT(kind < TokenKind::Limit);
     MOZ_ASSERT(kind != TokenKind::Eol,
                "TokenKind::Eol should never be used in an actual Token, only "
                "returned by peekTokenSameLine()");
 
     TokenStreamAnyChars& anyChars = anyCharsAccess();
     anyChars.flags.isDirtyLine = true;
@@ -1832,19 +1832,19 @@ GeneralTokenStreamChars<CharT, AnyCharsA
 
     // NOTE: |token->modifier| and |token->modifierException| are set in
     //       |newToken()| so that optimized, non-debug code won't do any work
     //       to pass a modifier-argument that will never be used.
 
     return token;
 }
 
-template<typename CharT, class AnyCharsAccess>
+template<typename Unit, class AnyCharsAccess>
 MOZ_COLD bool
-GeneralTokenStreamChars<CharT, AnyCharsAccess>::badToken()
+GeneralTokenStreamChars<Unit, AnyCharsAccess>::badToken()
 {
     // We didn't get a token, so don't set |flags.isDirtyLine|.
     anyCharsAccess().flags.hadError = true;
 
     // Poisoning sourceUnits on error establishes an invariant: once an
     // erroneous token has been seen, sourceUnits will not be consulted again.
     // This is true because the parser will deal with the illegal token by
     // aborting parsing immediately.
@@ -1869,21 +1869,21 @@ TokenStreamCharsShared::appendCodePointT
 
     if (numUnits == 1) {
         return true;
     }
 
     return charBuffer.append(units[1]);
 }
 
-template<typename CharT, class AnyCharsAccess>
+template<typename Unit, class AnyCharsAccess>
 bool
-TokenStreamSpecific<CharT, AnyCharsAccess>::putIdentInCharBuffer(const CharT* identStart)
+TokenStreamSpecific<Unit, AnyCharsAccess>::putIdentInCharBuffer(const Unit* identStart)
 {
-    const CharT* const originalAddress = this->sourceUnits.addressOfNextCodeUnit();
+    const Unit* const originalAddress = this->sourceUnits.addressOfNextCodeUnit();
     this->sourceUnits.setAddressOfNextCodeUnit(identStart);
 
     auto restoreNextRawCharAddress =
         MakeScopeExit([this, originalAddress]() {
             this->sourceUnits.setAddressOfNextCodeUnit(originalAddress);
         });
 
     this->charBuffer.clear();
@@ -1905,17 +1905,17 @@ TokenStreamSpecific<CharT, AnyCharsAcces
 
             if (unit != '\\' || !matchUnicodeEscapeIdent(&codePoint)) {
                 break;
             }
         } else {
             // |restoreNextRawCharAddress| undoes all gets, and this function
             // doesn't update line/column info.
             char32_t cp;
-            if (!getNonAsciiCodePointDontNormalize(toCharT(unit), &cp)) {
+            if (!getNonAsciiCodePointDontNormalize(toUnit(unit), &cp)) {
                 return false;
             }
 
             codePoint = cp;
             if (!unicode::IsIdentifierPart(codePoint)) {
                 break;
             }
         }
@@ -1923,22 +1923,22 @@ TokenStreamSpecific<CharT, AnyCharsAcces
         if (!appendCodePointToCharBuffer(codePoint)) {
             return false;
         }
     } while (true);
 
     return true;
 }
 
-template<typename CharT, class AnyCharsAccess>
+template<typename Unit, class AnyCharsAccess>
 MOZ_MUST_USE bool
-TokenStreamSpecific<CharT, AnyCharsAccess>::identifierName(TokenStart start,
-                                                           const CharT* identStart,
-                                                           IdentifierEscapes escaping,
-                                                           Modifier modifier, TokenKind* out)
+TokenStreamSpecific<Unit, AnyCharsAccess>::identifierName(TokenStart start,
+                                                          const Unit* identStart,
+                                                          IdentifierEscapes escaping,
+                                                          Modifier modifier, TokenKind* out)
 {
     // Run the bad-token code for every path out of this function except the
     // two success-cases.
     auto noteBadToken = MakeScopeExit([this]() {
         this->badToken();
     });
 
     // We've already consumed an initial code point in the identifer, to *know*
@@ -1963,17 +1963,17 @@ TokenStreamSpecific<CharT, AnyCharsAcces
                     break;
                 }
 
                 escaping = IdentifierEscapes::SawUnicodeEscape;
             }
         } else {
             // This ignores encoding errors: subsequent caller-side code to
             // handle source text after the IdentifierName will do so.
-            PeekedCodePoint<CharT> peeked = this->sourceUnits.peekCodePoint();
+            PeekedCodePoint<Unit> peeked = this->sourceUnits.peekCodePoint();
             if (peeked.isNone() || !unicode::IsIdentifierPart(peeked.codePoint())) {
                 break;
             }
 
             MOZ_ASSERT(!IsLineTerminator(peeked.codePoint()),
                        "IdentifierPart must guarantee !IsLineTerminator or "
                        "else we'll fail to maintain line-info/flags for EOL");
 
@@ -1987,17 +1987,17 @@ TokenStreamSpecific<CharT, AnyCharsAcces
         // tokenbuf before atomizing.
         if (!putIdentInCharBuffer(identStart)) {
             return false;
         }
 
         atom = drainCharBufferIntoAtom(anyCharsAccess().cx);
     } else {
         // Escape-free identifiers can be created directly from sourceUnits.
-        const CharT* chars = identStart;
+        const Unit* chars = identStart;
         size_t length = this->sourceUnits.addressOfNextCodeUnit() - identStart;
 
         // Represent reserved words lacking escapes as reserved word tokens.
         if (const ReservedWordInfo* rw = FindReservedWord(chars, length)) {
             noteBadToken.release();
             newSimpleToken(rw->tokentype, start, modifier, out);
             return true;
         }
@@ -2136,21 +2136,21 @@ SourceUnits<Utf8Unit>::consumeRestOfSing
         if (MOZ_UNLIKELY(c == unicode::LINE_SEPARATOR || c == unicode::PARA_SEPARATOR)) {
             return;
         }
 
         consumeKnownCodePoint(peeked);
     }
 }
 
-template<typename CharT, class AnyCharsAccess>
+template<typename Unit, class AnyCharsAccess>
 MOZ_MUST_USE bool
-TokenStreamSpecific<CharT, AnyCharsAccess>::decimalNumber(int32_t unit, TokenStart start,
-                                                          const CharT* numStart,
-                                                          Modifier modifier, TokenKind* out)
+TokenStreamSpecific<Unit, AnyCharsAccess>::decimalNumber(int32_t unit, TokenStart start,
+                                                         const Unit* numStart,
+                                                         Modifier modifier, TokenKind* out)
 {
     // Run the bad-token code for every path out of this function except the
     // one success-case.
     auto noteBadToken = MakeScopeExit([this]() {
         this->badToken();
     });
 
     // Consume integral component digits.
@@ -2220,42 +2220,42 @@ TokenStreamSpecific<CharT, AnyCharsAcces
         if (MOZ_LIKELY(isAsciiCodePoint(unit))) {
             if (unicode::IsIdentifierStart(char16_t(unit))) {
                 error(JSMSG_IDSTART_AFTER_NUMBER);
                 return false;
             }
         } else {
             // This ignores encoding errors: subsequent caller-side code to
             // handle source text after the number will do so.
-            PeekedCodePoint<CharT> peeked = this->sourceUnits.peekCodePoint();
+            PeekedCodePoint<Unit> peeked = this->sourceUnits.peekCodePoint();
             if (!peeked.isNone() && unicode::IsIdentifierStart(peeked.codePoint())) {
                 error(JSMSG_IDSTART_AFTER_NUMBER);
                 return false;
             }
         }
     }
 
     noteBadToken.release();
     newNumberToken(dval, decimalPoint, start, modifier, out);
     return true;
 }
 
-template<typename CharT, class AnyCharsAccess>
+template<typename Unit, class AnyCharsAccess>
 MOZ_MUST_USE bool
-TokenStreamSpecific<CharT, AnyCharsAccess>::regexpLiteral(TokenStart start, TokenKind* out)
+TokenStreamSpecific<Unit, AnyCharsAccess>::regexpLiteral(TokenStart start, TokenKind* out)
 {
-    MOZ_ASSERT(this->sourceUnits.previousCodeUnit() == CharT('/'));
+    MOZ_ASSERT(this->sourceUnits.previousCodeUnit() == Unit('/'));
     this->charBuffer.clear();
 
     auto ProcessNonAsciiCodePoint = [this](int32_t lead) {
         MOZ_ASSERT(lead != EOF);
         MOZ_ASSERT(!this->isAsciiCodePoint(lead));
 
         char32_t codePoint;
-        if (!this->getNonAsciiCodePointDontNormalize(this->toCharT(lead), &codePoint)) {
+        if (!this->getNonAsciiCodePointDontNormalize(this->toUnit(lead), &codePoint)) {
             return false;
         }
 
         if (MOZ_UNLIKELY(codePoint == unicode::LINE_SEPARATOR ||
                          codePoint == unicode::PARA_SEPARATOR))
         {
             this->sourceUnits.ungetLineOrParagraphSeparator();
             this->reportError(JSMSG_UNTERMINATED_REGEXP);
@@ -2359,20 +2359,20 @@ TokenStreamSpecific<CharT, AnyCharsAcces
         reflags = RegExpFlag(reflags | flag);
     }
     ungetCodeUnit(unit);
 
     newRegExpToken(reflags, start, out);
     return true;
 }
 
-template<typename CharT, class AnyCharsAccess>
+template<typename Unit, class AnyCharsAccess>
 MOZ_MUST_USE bool
-TokenStreamSpecific<CharT, AnyCharsAccess>::getTokenInternal(TokenKind* const ttp,
-                                                             const Modifier modifier)
+TokenStreamSpecific<Unit, AnyCharsAccess>::getTokenInternal(TokenKind* const ttp,
+                                                            const Modifier modifier)
 {
     // Assume we'll fail: success cases will overwrite this.
 #ifdef DEBUG
     *ttp = TokenKind::Limit;
 #endif
     MOZ_MAKE_MEM_UNDEFINED(ttp, sizeof(*ttp));
 
     // Check if in the middle of a template string. Have to get this out of
@@ -2396,19 +2396,19 @@ TokenStreamSpecific<CharT, AnyCharsAcces
         if (MOZ_UNLIKELY(!isAsciiCodePoint(unit))) {
             // Non-ASCII code points can only be identifiers or whitespace.
             // It would be nice to compute these *after* discarding whitespace,
             // but IN A WORLD where |unicode::IsSpaceOrBOM2| requires consuming
             // a variable number of code points, it's easier to assume it's an
             // identifier and maybe do a little wasted work, than to unget and
             // compute and reget if whitespace.
             TokenStart start(this->sourceUnits, 0);
-            const CharT* identStart = this->sourceUnits.addressOfNextCodeUnit();
-
-            PeekedCodePoint<CharT> peeked = this->sourceUnits.peekCodePoint();
+            const Unit* identStart = this->sourceUnits.addressOfNextCodeUnit();
+
+            PeekedCodePoint<Unit> peeked = this->sourceUnits.peekCodePoint();
             if (peeked.isNone()) {
                 int32_t bad;
                 MOZ_ALWAYS_FALSE(getCodePoint(&bad));
                 return badToken();
             }
 
             char32_t cp = peeked.codePoint();
             if (unicode::IsSpaceOrBOM2(cp)) {
@@ -2491,17 +2491,17 @@ TokenStreamSpecific<CharT, AnyCharsAcces
             return identifierName(start, this->sourceUnits.addressOfNextCodeUnit() - 1,
                                   IdentifierEscapes::None, modifier, ttp);
         }
 
         // Look for a decimal number.
         //
         if (c1kind == Dec) {
             TokenStart start(this->sourceUnits, -1);
-            const CharT* numStart = this->sourceUnits.addressOfNextCodeUnit() - 1;
+            const Unit* numStart = this->sourceUnits.addressOfNextCodeUnit() - 1;
             return decimalNumber(unit, start, numStart, modifier, ttp);
         }
 
         // Look for a string or a template string.
         //
         if (c1kind == String) {
             return getStringOrTemplateToken(static_cast<char>(unit), modifier, ttp);
         }
@@ -2524,17 +2524,17 @@ TokenStreamSpecific<CharT, AnyCharsAcces
         // From a '0', look for a hexadecimal, binary, octal, or "noctal" (a
         // number starting with '0' that contains '8' or '9' and is treated as
         // decimal) number.
         //
         if (c1kind == ZeroDigit) {
             TokenStart start(this->sourceUnits, -1);
 
             int radix;
-            const CharT* numStart;
+            const Unit* numStart;
             unit = getCodeUnit();
             if (unit == 'x' || unit == 'X') {
                 radix = 16;
                 unit = getCodeUnit();
                 if (!JS7_ISHEX(unit)) {
                     // NOTE: |unit| may be EOF here.
                     ungetCodeUnit(unit);
                     error(JSMSG_MISSING_HEXDIGITS);
@@ -2623,17 +2623,17 @@ TokenStreamSpecific<CharT, AnyCharsAcces
             if (MOZ_LIKELY(isAsciiCodePoint(unit))) {
                 if (unicode::IsIdentifierStart(char16_t(unit))) {
                     error(JSMSG_IDSTART_AFTER_NUMBER);
                     return badToken();
                 }
             } else if (MOZ_LIKELY(unit != EOF)) {
                 // This ignores encoding errors: subsequent caller-side code to
                 // handle source text after the number will do so.
-                PeekedCodePoint<CharT> peeked = this->sourceUnits.peekCodePoint();
+                PeekedCodePoint<Unit> peeked = this->sourceUnits.peekCodePoint();
                 if (!peeked.isNone() && unicode::IsIdentifierStart(peeked.codePoint())) {
                     error(JSMSG_IDSTART_AFTER_NUMBER);
                     return badToken();
                 }
             }
 
             double dval;
             if (!GetFullInteger(anyCharsAccess().cx, numStart,
@@ -2655,17 +2655,17 @@ TokenStreamSpecific<CharT, AnyCharsAcces
         TokenStart start(this->sourceUnits, -1);
         TokenKind simpleKind;
 #ifdef DEBUG
         simpleKind = TokenKind::Limit; // sentinel value for code after switch
 #endif
 
         // The block a ways above eliminated all non-ASCII, so cast to the
         // smallest type possible to assist the C++ compiler.
-        switch (AssertedCast<uint8_t>(CodeUnitValue(toCharT(unit)))) {
+        switch (AssertedCast<uint8_t>(CodeUnitValue(toUnit(unit)))) {
           case '.':
             unit = getCodeUnit();
             if (IsAsciiDigit(unit)) {
                 return decimalNumber('.', start, this->sourceUnits.addressOfNextCodeUnit() - 2,
                                      modifier, ttp);
             }
 
             if (unit == '.') {
@@ -2879,32 +2879,32 @@ TokenStreamSpecific<CharT, AnyCharsAcces
             break;
 
           default:
             // We consumed a bad ASCII code point/unit.  Put it back so the
             // error location is the bad code point.
             ungetCodeUnit(unit);
             error(JSMSG_ILLEGAL_CHARACTER);
             return badToken();
-        } // switch (AssertedCast<uint8_t>(CodeUnitValue(toCharT(unit))))
+        } // switch (AssertedCast<uint8_t>(CodeUnitValue(toUnit(unit))))
 
         MOZ_ASSERT(simpleKind != TokenKind::Limit,
                    "switch-statement should have set |simpleKind| before "
                    "breaking");
 
         newSimpleToken(simpleKind, start, modifier, ttp);
         return true;
     } while (true);
 }
 
-template<typename CharT, class AnyCharsAccess>
+template<typename Unit, class AnyCharsAccess>
 bool
-TokenStreamSpecific<CharT, AnyCharsAccess>::getStringOrTemplateToken(char untilChar,
-                                                                     Modifier modifier,
-                                                                     TokenKind* out)
+TokenStreamSpecific<Unit, AnyCharsAccess>::getStringOrTemplateToken(char untilChar,
+                                                                    Modifier modifier,
+                                                                    TokenKind* out)
 {
     MOZ_ASSERT(untilChar == '\'' || untilChar == '"' || untilChar == '`',
                "unexpected string/template literal delimiter");
 
     bool parsingTemplate = (untilChar == '`');
     bool templateHead = false;
 
     TokenStart start(this->sourceUnits, -1);
@@ -2915,18 +2915,18 @@ TokenStreamSpecific<CharT, AnyCharsAcces
     auto noteBadToken = MakeScopeExit([this]() {
         this->badToken();
     });
 
     auto ReportPrematureEndOfLiteral = [this, untilChar](unsigned errnum) {
         // Unicode separators aren't end-of-line in template or (as of
         // recently) string literals, so this assertion doesn't allow them.
         MOZ_ASSERT(this->sourceUnits.atEnd() ||
-                   this->sourceUnits.peekCodeUnit() == CharT('\r') ||
-                   this->sourceUnits.peekCodeUnit() == CharT('\n'),
+                   this->sourceUnits.peekCodeUnit() == Unit('\r') ||
+                   this->sourceUnits.peekCodeUnit() == Unit('\n'),
                    "must be parked at EOF or EOL to call this function");
 
         // The various errors reported here include language like "in a ''
         // literal" or similar, with '' being '', "", or `` as appropriate.
         const char delimiters[] = { untilChar, untilChar, '\0' };
 
         this->error(errnum, delimiters);
         return;
@@ -2945,17 +2945,17 @@ TokenStreamSpecific<CharT, AnyCharsAcces
         // Non-ASCII code points are always directly appended -- even
         // U+2028 LINE SEPARATOR and U+2029 PARAGRAPH SEPARATOR that are
         // ordinarily LineTerminatorSequences.  (They contribute their literal
         // values to template and [as of recently] string literals, but they're
         // line terminators when computing line/column coordinates.)  Handle
         // the non-ASCII case early for readability.
         if (MOZ_UNLIKELY(!isAsciiCodePoint(unit))) {
             char32_t cp;
-            if (!getNonAsciiCodePointDontNormalize(toCharT(unit), &cp)) {
+            if (!getNonAsciiCodePointDontNormalize(toUnit(unit), &cp)) {
                 return false;
             }
 
             if (MOZ_UNLIKELY(cp == unicode::LINE_SEPARATOR || cp == unicode::PARA_SEPARATOR)) {
                 if (!updateLineInfoForEOL()) {
                     return false;
                 }
 
@@ -2999,17 +2999,17 @@ TokenStreamSpecific<CharT, AnyCharsAcces
                     }
                 }
 
                 continue;
             }
 
             // The block above eliminated all non-ASCII, so cast to the
             // smallest type possible to assist the C++ compiler.
-            switch (AssertedCast<uint8_t>(CodeUnitValue(toCharT(unit)))) {
+            switch (AssertedCast<uint8_t>(CodeUnitValue(toUnit(unit)))) {
               case 'b': unit = '\b'; break;
               case 'f': unit = '\f'; break;
               case 'n': unit = '\n'; break;
               case 'r': unit = '\r'; break;
               case 't': unit = '\t'; break;
               case 'v': unit = '\v'; break;
 
               case '\r':
@@ -3202,17 +3202,17 @@ TokenStreamSpecific<CharT, AnyCharsAcces
                             val = save;
                         }
                     }
                 }
 
                 unit = char16_t(val);
                 break;
               } // default
-            } // switch (AssertedCast<uint8_t>(CodeUnitValue(toCharT(unit))))
+            } // switch (AssertedCast<uint8_t>(CodeUnitValue(toUnit(unit))))
 
             if (!this->charBuffer.append(unit)) {
                 return false;
             }
 
             continue;
         } // (unit == '\\')
 
--- a/js/src/frontend/TokenStream.h
+++ b/js/src/frontend/TokenStream.h
@@ -17,18 +17,18 @@
 
 /*
  * [SMDOC] Parser Token Stream
  *
  * A token stream exposes the raw tokens -- operators, names, numbers,
  * keywords, and so on -- of JavaScript source code.
  *
  * These are the components of the overall token stream concept:
- * TokenStreamShared, TokenStreamAnyChars, TokenStreamCharsBase<CharT>,
- * TokenStreamChars<CharT>, and TokenStreamSpecific<CharT, AnyCharsAccess>.
+ * TokenStreamShared, TokenStreamAnyChars, TokenStreamCharsBase<Unit>,
+ * TokenStreamChars<Unit>, and TokenStreamSpecific<Unit, AnyCharsAccess>.
  *
  * == TokenStreamShared → ∅ ==
  *
  * Certain aspects of tokenizing are used everywhere:
  *
  *   * modifiers (used to select which context-sensitive interpretation of a
  *     character should be used to decide what token it is), modifier
  *     exceptions, and modifier assertion handling;
@@ -48,17 +48,17 @@
  * current and next tokens (is the token of the given type?  what name or
  * number is contained in the token?  and other queries), and others.
  *
  * All this data/functionality *could* be duplicated for both single-byte and
  * double-byte tokenizing, but there are two problems.  First, it's potentially
  * wasteful if the compiler doesnt recognize it can unify the concepts.  (And
  * if any-character concepts are intermixed with character-specific concepts,
  * potentially the compiler *can't* unify them because offsets into the
- * hypothetical TokenStream<CharT>s would differ.)  Second, some of this stuff
+ * hypothetical TokenStream<Unit>s would differ.)  Second, some of this stuff
  * needs to be accessible in ParserBase, the aspects of JS language parsing
  * that have meaning independent of the character type of the source text being
  * parsed.  So we need a separate data structure that ParserBase can hold on to
  * for it.  (ParserBase isn't the only instance of this, but it's certainly the
  * biggest case of it.)  Ergo, TokenStreamAnyChars.
  *
  * == TokenStreamCharsShared → ∅ ==
  *
@@ -67,61 +67,61 @@
  * TokenStreamAnyChars, but it makes more sense to live in a separate class
  * that character-aware token information can simply inherit.
  *
  * This class currently exists only to contain a char16_t buffer, transiently
  * used to accumulate strings in tricky cases that can't just be read directly
  * from source text.  It's not used outside character-aware tokenizing, so it
  * doesn't make sense in TokenStreamAnyChars.
  *
- * == TokenStreamCharsBase<CharT> → TokenStreamCharsShared ==
+ * == TokenStreamCharsBase<Unit> → TokenStreamCharsShared ==
  *
  * Certain data structures in tokenizing are character-type-specific: namely,
  * the various pointers identifying the source text (including current offset
  * and end).
  *
  * Additionally, some functions operating on this data are defined the same way
  * no matter what character type you have (e.g. current offset in code units
  * into the source text) or share a common interface regardless of character
  * type (e.g. consume the next code unit if it has a given value).
  *
- * All such functionality lives in TokenStreamCharsBase<CharT>.
+ * All such functionality lives in TokenStreamCharsBase<Unit>.
  *
- * == SpecializedTokenStreamCharsBase<CharT> → TokenStreamCharsBase<CharT> ==
+ * == SpecializedTokenStreamCharsBase<Unit> → TokenStreamCharsBase<Unit> ==
  *
  * Certain tokenizing functionality is specific to a single character type.
  * For example, JS's UTF-16 encoding recognizes no coding errors, because lone
  * surrogates are not an error; but a UTF-8 encoding must recognize a variety
  * of validation errors.  Such functionality is defined only in the appropriate
  * SpecializedTokenStreamCharsBase specialization.
  *
- * == GeneralTokenStreamChars<CharT, AnyCharsAccess> →
- *    SpecializedTokenStreamCharsBase<CharT> ==
+ * == GeneralTokenStreamChars<Unit, AnyCharsAccess> →
+ *    SpecializedTokenStreamCharsBase<Unit> ==
  *
  * Some functionality operates differently on different character types, just
  * as for TokenStreamCharsBase, but additionally requires access to character-
  * type-agnostic information in TokenStreamAnyChars.  For example, getting the
  * next character performs different steps for different character types and
  * must access TokenStreamAnyChars to update line break information.
  *
  * Such functionality, if it can be defined using the same algorithm for all
- * character types, lives in GeneralTokenStreamChars<CharT, AnyCharsAccess>.
+ * character types, lives in GeneralTokenStreamChars<Unit, AnyCharsAccess>.
  * The AnyCharsAccess parameter provides a way for a GeneralTokenStreamChars
  * instance to access its corresponding TokenStreamAnyChars, without inheriting
  * from it.
  *
- * GeneralTokenStreamChars<CharT, AnyCharsAccess> is just functionality, no
+ * GeneralTokenStreamChars<Unit, AnyCharsAccess> is just functionality, no
  * actual member data.
  *
- * Such functionality all lives in TokenStreamChars<CharT, AnyCharsAccess>, a
+ * Such functionality all lives in TokenStreamChars<Unit, AnyCharsAccess>, a
  * declared-but-not-defined template class whose specializations have a common
  * public interface (plus whatever private helper functions are desirable).
  *
- * == TokenStreamChars<CharT, AnyCharsAccess> →
- *    GeneralTokenStreamChars<CharT, AnyCharsAccess> ==
+ * == TokenStreamChars<Unit, AnyCharsAccess> →
+ *    GeneralTokenStreamChars<Unit, AnyCharsAccess> ==
  *
  * Some functionality is like that in GeneralTokenStreamChars, *but* it's
  * defined entirely differently for different character types.
  *
  * For example, consider "match a multi-code unit code point" (hypothetically:
  * we've only implemented two-byte tokenizing right now):
  *
  *   * For two-byte text, there must be two code units to get, the leading code
@@ -132,47 +132,47 @@
  *   * For single-byte UTF-8 text, the first code unit must have N > 1 of its
  *     highest bits set (and the next unset), and |N - 1| successive code units
  *     must have their high bit set and next-highest bit unset, *and*
  *     concatenating all unconstrained bits together must not produce a code
  *     point value that could have been encoded in fewer code units.
  *
  * This functionality can't be implemented as member functions in
  * GeneralTokenStreamChars because we'd need to *partially specialize* those
- * functions -- hold CharT constant while letting AnyCharsAccess vary.  But
+ * functions -- hold Unit constant while letting AnyCharsAccess vary.  But
  * C++ forbids function template partial specialization like this: either you
  * fix *all* parameters or you fix none of them.
  *
  * Fortunately, C++ *does* allow *class* template partial specialization.  So
- * TokenStreamChars is a template class with one specialization per CharT.
+ * TokenStreamChars is a template class with one specialization per Unit.
  * Functions can be defined differently in the different specializations,
  * because AnyCharsAccess as the only template parameter on member functions
  * *can* vary.
  *
- * All TokenStreamChars<CharT, AnyCharsAccess> specializations, one per CharT,
+ * All TokenStreamChars<Unit, AnyCharsAccess> specializations, one per Unit,
  * are just functionality, no actual member data.
  *
- * == TokenStreamSpecific<CharT, AnyCharsAccess> →
- *    TokenStreamChars<CharT, AnyCharsAccess>, TokenStreamShared ==
+ * == TokenStreamSpecific<Unit, AnyCharsAccess> →
+ *    TokenStreamChars<Unit, AnyCharsAccess>, TokenStreamShared ==
  *
  * TokenStreamSpecific is operations that are parametrized on character type
  * but implement the *general* idea of tokenizing, without being intrinsically
  * tied to character type.  Notably, this includes all operations that can
  * report warnings or errors at particular offsets, because we include a line
  * of context with such errors -- and that necessarily accesses the raw
  * characters of their specific type.
  *
  * Much TokenStreamSpecific operation depends on functionality in
  * TokenStreamAnyChars.  The obvious solution is to inherit it -- but this
  * doesn't work in Parser: its ParserBase base class needs some
  * TokenStreamAnyChars functionality without knowing character type.
  *
  * The AnyCharsAccess type parameter is a class that statically converts from a
  * TokenStreamSpecific* to its corresponding TokenStreamAnyChars.  The
- * TokenStreamSpecific in Parser<ParseHandler, CharT> can then specify a class
+ * TokenStreamSpecific in Parser<ParseHandler, Unit> can then specify a class
  * that properly converts from TokenStreamSpecific Parser::tokenStream to
  * TokenStreamAnyChars ParserBase::anyChars.
  *
  * Could we hardcode one set of offset calculations for this and eliminate
  * AnyCharsAccess?  No.  Offset calculations possibly could be hardcoded if
  * TokenStreamSpecific were present in Parser before Parser::handler, assuring
  * the same offsets in all Parser-related cases.  But there's still a separate
  * TokenStream class, that requires different offset calculations.  So even if
@@ -489,33 +489,33 @@ struct TokenStreamFlags
     bool hadError:1;        // Hit a syntax error, at start or during a
                             // token.
 
     TokenStreamFlags()
       : isEOF(), isDirtyLine(), sawOctalEscape(), hadError()
     {}
 };
 
-template<typename CharT>
+template<typename Unit>
 class TokenStreamPosition;
 
 /**
  * TokenStream types and constants that are used in both TokenStreamAnyChars
  * and TokenStreamSpecific.  Do not add any non-static data members to this
  * class!
  */
 class TokenStreamShared
 {
   protected:
     static constexpr size_t ntokens = 4; // 1 current + 2 lookahead, rounded
                                          // to power of 2 to avoid divmod by 3
 
     static constexpr unsigned ntokensMask = ntokens - 1;
 
-    template<typename CharT> friend class TokenStreamPosition;
+    template<typename Unit> friend class TokenStreamPosition;
 
   public:
     static constexpr unsigned maxLookahead = 2;
 
     static constexpr uint32_t NoOffset = UINT32_MAX;
 
     using Modifier = Token::Modifier;
     static constexpr Modifier None = Token::None;
@@ -555,65 +555,65 @@ class TokenStreamShared
                                "tokenization non-deterministic");
 #endif
     }
 };
 
 static_assert(mozilla::IsEmpty<TokenStreamShared>::value,
               "TokenStreamShared shouldn't bloat classes that inherit from it");
 
-template<typename CharT, class AnyCharsAccess>
+template<typename Unit, class AnyCharsAccess>
 class TokenStreamSpecific;
 
-template<typename CharT>
+template<typename Unit>
 class MOZ_STACK_CLASS TokenStreamPosition final
 {
   public:
     // The JS_HAZ_ROOTED is permissible below because: 1) the only field in
     // TokenStreamPosition that can keep GC things alive is Token, 2) the only
     // GC things Token can keep alive are atoms, and 3) the AutoKeepAtoms&
     // passed to the constructor here represents that collection of atoms
     // is disabled while atoms in Tokens in this Position are alive.  DON'T
     // ADD NON-ATOM GC THING POINTERS HERE!  They would create a rooting
     // hazard that JS_HAZ_ROOTED will cause to be ignored.
     template<class AnyCharsAccess>
     inline TokenStreamPosition(AutoKeepAtoms& keepAtoms,
-                               TokenStreamSpecific<CharT, AnyCharsAccess>& tokenStream);
+                               TokenStreamSpecific<Unit, AnyCharsAccess>& tokenStream);
 
   private:
     TokenStreamPosition(const TokenStreamPosition&) = delete;
 
-    // Technically only TokenStreamSpecific<CharT, AnyCharsAccess>::seek with
-    // CharT constant and AnyCharsAccess varying must be friended, but 1) it's
+    // Technically only TokenStreamSpecific<Unit, AnyCharsAccess>::seek with
+    // Unit constant and AnyCharsAccess varying must be friended, but 1) it's
     // hard to friend one function in template classes, and 2) C++ doesn't
     // allow partial friend specialization to target just that single class.
     template<typename Char, class AnyCharsAccess> friend class TokenStreamSpecific;
 
-    const CharT* buf;
+    const Unit* buf;
     TokenStreamFlags flags;
     unsigned lineno;
     size_t linebase;
     size_t prevLinebase;
     Token currentToken;
     unsigned lookahead;
     Token lookaheadTokens[TokenStreamShared::maxLookahead];
 } JS_HAZ_ROOTED;
 
 class TokenStreamAnyChars
   : public TokenStreamShared
 {
   public:
     TokenStreamAnyChars(JSContext* cx, const JS::ReadOnlyCompileOptions& options,
                         StrictModeGetter* smg);
 
-    template<typename CharT, class AnyCharsAccess> friend class GeneralTokenStreamChars;
-    template<typename CharT, class AnyCharsAccess> friend class TokenStreamChars;
-    template<typename CharT, class AnyCharsAccess> friend class TokenStreamSpecific;
-
-    template<typename CharT> friend class TokenStreamPosition;
+    template<typename Unit, class AnyCharsAccess> friend class GeneralTokenStreamChars;
+    template<typename Unit, class AnyCharsAccess> friend class TokenStreamChars;
+    template<typename Unit, class AnyCharsAccess> friend class TokenStreamSpecific;
+
+    template<typename Unit> friend class TokenStreamPosition;
 
     // Accessors.
     unsigned cursor() const { return cursor_; }
     unsigned nextCursor() const { return (cursor_ + 1) & ntokensMask; }
     unsigned aheadCursor(unsigned steps) const { return (cursor_ + steps) & ntokensMask; }
 
     const Token& currentToken() const { return tokens[cursor()]; }
     bool isCurrentTokenType(TokenKind type) const {
@@ -957,17 +957,17 @@ CodeUnitValue(char16_t unit)
 }
 
 constexpr uint8_t
 CodeUnitValue(mozilla::Utf8Unit unit)
 {
     return unit.toUint8();
 }
 
-template<typename CharT>
+template<typename Unit>
 class TokenStreamCharsBase;
 
 template<typename T>
 inline bool
 IsLineTerminator(T) = delete;
 
 inline bool
 IsLineTerminator(char32_t codePoint)
@@ -980,17 +980,17 @@ IsLineTerminator(char32_t codePoint)
 
 inline bool
 IsLineTerminator(char16_t unit)
 {
     // Every LineTerminator fits in char16_t, so this is exact.
     return IsLineTerminator(static_cast<char32_t>(unit));
 }
 
-template<typename CharT>
+template<typename Unit>
 struct SourceUnitTraits;
 
 template<>
 struct SourceUnitTraits<char16_t>
 {
   public:
     static constexpr uint8_t maxUnitsLength = 2;
 
@@ -1022,24 +1022,24 @@ struct SourceUnitTraits<mozilla::Utf8Uni
  *
  * If there isn't a valid code point, then |isNone()|.
  *
  * But if there *is* a valid code point, then |!isNone()|, the code point has
  * value |codePoint()| and its length in code units is |lengthInUnits()|.
  *
  * Conceptually, this class is |Maybe<struct { char32_t v; uint8_t len; }>|.
  */
-template<typename CharT>
+template<typename Unit>
 class PeekedCodePoint final
 {
     char32_t codePoint_ = 0;
     uint8_t lengthInUnits_ = 0;
 
   private:
-    using SourceUnitTraits = frontend::SourceUnitTraits<CharT>;
+    using SourceUnitTraits = frontend::SourceUnitTraits<Unit>;
 
     PeekedCodePoint() = default;
 
   public:
     /**
      * Create a peeked code point with the given value and length in code
      * units.
      *
@@ -1146,25 +1146,25 @@ IsSingleUnitLineTerminator(mozilla::Utf8
 // converting all EOL sequences to '\n', tracking the line number, and setting
 // |flags.isEOF|.  (The "raw" in "raw Unicode code units" refers to the lack of
 // EOL sequence normalization.)
 //
 // buf[0..length-1] often represents a substring of some larger source,
 // where we have only the substring in memory. The |startOffset| argument
 // indicates the offset within this larger string at which our string
 // begins, the offset of |buf[0]|.
-template<typename CharT>
+template<typename Unit>
 class SourceUnits
 {
   public:
-    SourceUnits(const CharT* buf, size_t length, size_t startOffset)
-      : base_(buf),
+    SourceUnits(const Unit* units, size_t length, size_t startOffset)
+      : base_(units),
         startOffset_(startOffset),
-        limit_(buf + length),
-        ptr(buf)
+        limit_(units + length),
+        ptr(units)
     { }
 
     bool atStart() const {
         MOZ_ASSERT(ptr, "shouldn't be using if poisoned");
         return ptr == base_;
     }
 
     bool atEnd() const {
@@ -1180,75 +1180,75 @@ class SourceUnits
     size_t startOffset() const {
         return startOffset_;
     }
 
     size_t offset() const {
         return startOffset_ + mozilla::PointerRangeSize(base_, ptr);
     }
 
-    const CharT* codeUnitPtrAt(size_t offset) const {
+    const Unit* codeUnitPtrAt(size_t offset) const {
         MOZ_ASSERT(startOffset_ <= offset);
         MOZ_ASSERT(offset - startOffset_ <= mozilla::PointerRangeSize(base_, limit_));
         return base_ + (offset - startOffset_);
     }
 
-    const CharT* current() const {
+    const Unit* current() const {
         return ptr;
     }
 
-    const CharT* limit() const {
+    const Unit* limit() const {
         return limit_;
     }
 
-    CharT previousCodeUnit() {
+    Unit previousCodeUnit() {
         MOZ_ASSERT(ptr, "can't get previous code unit if poisoned");
         MOZ_ASSERT(!atStart(), "must have a previous code unit to get");
         return *(ptr - 1);
     }
 
-    CharT getCodeUnit() {
+    Unit getCodeUnit() {
         return *ptr++;      // this will nullptr-crash if poisoned
     }
 
-    CharT peekCodeUnit() const {
+    Unit peekCodeUnit() const {
         return *ptr;        // this will nullptr-crash if poisoned
     }
 
     /**
      * Determine the next code point in source text.  The code point is not
      * normalized: '\r', '\n', '\u2028', and '\u2029' are returned literally.
      * If there is no next code point because |atEnd()|, or if an encoding
      * error is encountered, return a |PeekedCodePoint| that |isNone()|.
      *
      * This function does not report errors: code that attempts to get the next
      * code point must report any error.
      *
      * If a next code point is found, it may be consumed by passing it to
      * |consumeKnownCodePoint|.
      */
-    PeekedCodePoint<CharT> peekCodePoint() const {
+    PeekedCodePoint<Unit> peekCodePoint() const {
         return PeekCodePoint(ptr, limit_);
     }
 
   private:
 #ifdef DEBUG
-    void assertNextCodePoint(const PeekedCodePoint<CharT>& peeked);
+    void assertNextCodePoint(const PeekedCodePoint<Unit>& peeked);
 #endif
 
   public:
     /**
      * Consume a peeked code point that |!isNone()|.
      *
      * This call DOES NOT UPDATE LINE-STATUS.  You may need to call
      * |updateLineInfoForEOL()| and |updateFlagsForEOL()| if this consumes a
      * LineTerminator.  Note that if this consumes '\r', you also must consume
      * an optional '\n' (i.e. a full LineTerminatorSequence) before doing so.
      */
-    void consumeKnownCodePoint(const PeekedCodePoint<CharT>& peeked) {
+    void consumeKnownCodePoint(const PeekedCodePoint<Unit>& peeked) {
         MOZ_ASSERT(!peeked.isNone());
         MOZ_ASSERT(peeked.lengthInUnits() <= remaining());
 
 #ifdef DEBUG
         assertNextCodePoint(peeked);
 #endif
 
         ptr += peeked.lengthInUnits();
@@ -1278,20 +1278,20 @@ class SourceUnits
     }
 
     bool matchCodeUnits(const char* chars, uint8_t length) {
         MOZ_ASSERT(ptr, "shouldn't match into poisoned SourceUnits");
         if (length > remaining()) {
             return false;
         }
 
-        const CharT* start = ptr;
-        const CharT* end = ptr + length;
+        const Unit* start = ptr;
+        const Unit* end = ptr + length;
         while (ptr < end) {
-            if (*ptr++ != CharT(*chars++)) {
+            if (*ptr++ != Unit(*chars++)) {
                 ptr = start;
                 return false;
             }
         }
 
         return true;
     }
 
@@ -1305,66 +1305,66 @@ class SourceUnits
     void unskipCodeUnits(uint32_t n) {
         MOZ_ASSERT(ptr, "shouldn't use poisoned SourceUnits");
         MOZ_ASSERT(n <= mozilla::PointerRangeSize(base_, ptr),
                    "shouldn't unskip beyond start of SourceUnits");
         ptr -= n;
     }
 
   private:
-    friend class TokenStreamCharsBase<CharT>;
-
-    bool internalMatchCodeUnit(CharT c) {
+    friend class TokenStreamCharsBase<Unit>;
+
+    bool internalMatchCodeUnit(Unit c) {
         MOZ_ASSERT(ptr, "shouldn't use poisoned SourceUnits");
         if (MOZ_LIKELY(!atEnd()) && *ptr == c) {
             ptr++;
             return true;
         }
         return false;
     }
 
   public:
-    void consumeKnownCodeUnit(CharT c) {
+    void consumeKnownCodeUnit(Unit c) {
         MOZ_ASSERT(ptr, "shouldn't use poisoned SourceUnits");
         MOZ_ASSERT(*ptr == c, "consuming the wrong code unit");
         ptr++;
     }
 
     /**
      * Unget the '\n' (CR) that precedes a '\n' (LF), when ungetting a line
      * terminator that's a full "\r\n" sequence.  If the prior code unit isn't
      * '\r', do nothing.
      */
     void ungetOptionalCRBeforeLF() {
         MOZ_ASSERT(ptr, "shouldn't unget a '\\r' from poisoned SourceUnits");
-        MOZ_ASSERT(*ptr == CharT('\n'),
+        MOZ_ASSERT(*ptr == Unit('\n'),
                    "function should only be called when a '\\n' was just "
                    "ungotten, and any '\\r' preceding it must also be "
                    "ungotten");
-        if (*(ptr - 1) == CharT('\r')) {
+        if (*(ptr - 1) == Unit('\r')) {
             ptr--;
         }
     }
 
     /** Unget U+2028 LINE SEPARATOR or U+2029 PARAGRAPH SEPARATOR. */
     inline void ungetLineOrParagraphSeparator();
 
     void ungetCodeUnit() {
         MOZ_ASSERT(!atStart(), "can't unget if currently at start");
         MOZ_ASSERT(ptr);     // make sure it hasn't been poisoned
         ptr--;
     }
 
-    const CharT* addressOfNextCodeUnit(bool allowPoisoned = false) const {
+    const Unit* addressOfNextCodeUnit(bool allowPoisoned = false) const {
         MOZ_ASSERT_IF(!allowPoisoned, ptr);     // make sure it hasn't been poisoned
         return ptr;
     }
 
     // Use this with caution!
-    void setAddressOfNextCodeUnit(const CharT* a, bool allowPoisoned = false) {
+    void setAddressOfNextCodeUnit(const Unit* a, bool allowPoisoned = false) {
         MOZ_ASSERT_IF(!allowPoisoned, a);
         ptr = a;
     }
 
     // Poison the SourceUnits so they can't be accessed again.
     void poisonInDebug() {
 #ifdef DEBUG
         ptr = nullptr;
@@ -1418,26 +1418,26 @@ class SourceUnits
      * text, no further than |WindowRadius| code units away from |offset|, such
      * that all code units from |offset| to that offset are valid,
      * non-LineTerminator code points.
      */
     size_t findWindowEnd(size_t offset) const;
 
   private:
     /** Base of buffer. */
-    const CharT* base_;
+    const Unit* base_;
 
     /** Offset of base_[0]. */
     uint32_t startOffset_;
 
     /** Limit for quick bounds check. */
-    const CharT* limit_;
+    const Unit* limit_;
 
     /** Next char to get. */
-    const CharT* ptr;
+    const Unit* ptr;
 };
 
 template<>
 inline void
 SourceUnits<char16_t>::ungetLineOrParagraphSeparator()
 {
 #ifdef DEBUG
     char16_t prev = previousCodeUnit();
@@ -1459,17 +1459,17 @@ SourceUnits<mozilla::Utf8Unit>::ungetLin
 #ifdef DEBUG
     uint8_t last = ptr[2].toUint8();
 #endif
     MOZ_ASSERT(last == 0xA8 || last == 0xA9);
 }
 
 class TokenStreamCharsShared
 {
-    // Using char16_t (not CharT) is a simplifying decision that hopefully
+    // Using char16_t (not Unit) is a simplifying decision that hopefully
     // eliminates the need for a UTF-8 regular expression parser and makes
     // |copyCharBufferTo| markedly simpler.
     using CharBuffer = Vector<char16_t, 32>;
 
   protected:
     /**
      * Buffer transiently used to store sequences of identifier or string code
      * points when such can't be directly processed from the original source
@@ -1521,85 +1521,85 @@ ToCharSpan(mozilla::Span<const mozilla::
     //
     // Second, Utf8Unit *contains* a |char|.  Examining that memory as |char|
     // is simply, per C++11 [basic.lval]p10, to access the memory according to
     // the dynamic type of the object: essentially trivially safe.
     return mozilla::MakeSpan(reinterpret_cast<const char*>(codeUnits.data()),
                              codeUnits.size());
 }
 
-template<typename CharT>
+template<typename Unit>
 class TokenStreamCharsBase
   : public TokenStreamCharsShared
 {
   protected:
-    TokenStreamCharsBase(JSContext* cx, const CharT* chars, size_t length, size_t startOffset);
+    TokenStreamCharsBase(JSContext* cx, const Unit* units, size_t length, size_t startOffset);
 
     /**
      * Convert a non-EOF code unit returned by |getCodeUnit()| or
-     * |peekCodeUnit()| to a CharT code unit.
+     * |peekCodeUnit()| to a Unit code unit.
      */
-    inline CharT toCharT(int32_t codeUnitValue);
+    inline Unit toUnit(int32_t codeUnitValue);
 
     void ungetCodeUnit(int32_t c) {
         if (c == EOF) {
             return;
         }
 
         sourceUnits.ungetCodeUnit();
     }
 
     static MOZ_ALWAYS_INLINE JSAtom*
-    atomizeSourceChars(JSContext* cx, mozilla::Span<const CharT> units);
-
-    using SourceUnits = frontend::SourceUnits<CharT>;
+    atomizeSourceChars(JSContext* cx, mozilla::Span<const Unit> units);
+
+    using SourceUnits = frontend::SourceUnits<Unit>;
 
     /**
      * Try to match a non-LineTerminator ASCII code point.  Return true iff it
      * was matched.
      */
     bool matchCodeUnit(char expect) {
         MOZ_ASSERT(mozilla::IsAscii(expect));
         MOZ_ASSERT(expect != '\r');
         MOZ_ASSERT(expect != '\n');
-        return this->sourceUnits.internalMatchCodeUnit(CharT(expect));
+        return this->sourceUnits.internalMatchCodeUnit(Unit(expect));
     }
 
     /**
      * Try to match an ASCII LineTerminator code point.  Return true iff it was
      * matched.
      */
     bool matchLineTerminator(char expect) {
         MOZ_ASSERT(expect == '\r' || expect == '\n');
-        return this->sourceUnits.internalMatchCodeUnit(CharT(expect));
+        return this->sourceUnits.internalMatchCodeUnit(Unit(expect));
     }
 
     template<typename T> bool matchCodeUnit(T) = delete;
     template<typename T> bool matchLineTerminator(T) = delete;
 
     int32_t peekCodeUnit() {
         return MOZ_LIKELY(!sourceUnits.atEnd()) ? CodeUnitValue(sourceUnits.peekCodeUnit()) : EOF;
     }
 
     /** Consume a known, non-EOF code unit. */
     inline void consumeKnownCodeUnit(int32_t unit);
 
     // Forbid accidental calls to consumeKnownCodeUnit *not* with the single
-    // unit-or-EOF type.  CharT should use SourceUnits::consumeKnownCodeUnit;
-    // CodeUnitValue() results should go through toCharT(), or better yet just
-    // use the original CharT.
+    // unit-or-EOF type.  Unit should use SourceUnits::consumeKnownCodeUnit;
+    // CodeUnitValue() results should go through toUnit(), or better yet just
+    // use the original Unit.
     template<typename T> inline void consumeKnownCodeUnit(T) = delete;
 
     /**
      * Accumulate the provided range of already-validated text (valid UTF-8, or
-     * anything if CharT is char16_t because JS allows lone surrogates) into
+     * anything if Unit is char16_t because JS allows lone surrogates) into
      * |charBuffer|.  Normalize '\r', '\n', and "\r\n" into '\n'.
      */
     MOZ_MUST_USE bool
-    fillCharBufferFromSourceNormalizingAsciiLineBreaks(const CharT* cur, const CharT* end);
+    fillCharBufferFromSourceNormalizingAsciiLineBreaks(const Unit* cur, const Unit* end);
 
     /**
      * Add a null-terminated line of context to error information, for the line
      * in |sourceUnits| that contains |offset|.  Also record the window's
      * length and the offset of the error in the window.  (Don't bother adding
      * a line of context if it would be empty.)
      *
      * The window will contain no LineTerminators of any kind, and it will not
@@ -1613,35 +1613,35 @@ class TokenStreamCharsBase
 
   protected:
     /** Code units in the source code being tokenized. */
     SourceUnits sourceUnits;
 };
 
 template<>
 inline char16_t
-TokenStreamCharsBase<char16_t>::toCharT(int32_t codeUnitValue)
+TokenStreamCharsBase<char16_t>::toUnit(int32_t codeUnitValue)
 {
-    MOZ_ASSERT(codeUnitValue != EOF, "EOF is not a CharT");
+    MOZ_ASSERT(codeUnitValue != EOF, "EOF is not a Unit");
     return mozilla::AssertedCast<char16_t>(codeUnitValue);
 }
 
 template<>
 inline mozilla::Utf8Unit
-TokenStreamCharsBase<mozilla::Utf8Unit>::toCharT(int32_t value)
+TokenStreamCharsBase<mozilla::Utf8Unit>::toUnit(int32_t value)
 {
-    MOZ_ASSERT(value != EOF, "EOF is not a CharT");
-    return mozilla::Utf8Unit(static_cast<unsigned char>(value));
+    MOZ_ASSERT(value != EOF, "EOF is not a Unit");
+    return mozilla::Utf8Unit(mozilla::AssertedCast<unsigned char>(value));
 }
 
-template<typename CharT>
+template<typename Unit>
 inline void
-TokenStreamCharsBase<CharT>::consumeKnownCodeUnit(int32_t unit)
+TokenStreamCharsBase<Unit>::consumeKnownCodeUnit(int32_t unit)
 {
-    sourceUnits.consumeKnownCodeUnit(toCharT(unit));
+    sourceUnits.consumeKnownCodeUnit(toUnit(unit));
 }
 
 template<>
 /* static */ MOZ_ALWAYS_INLINE JSAtom*
 TokenStreamCharsBase<char16_t>::atomizeSourceChars(JSContext* cx,
                                                    mozilla::Span<const char16_t> units)
 {
     return AtomizeChars(cx, units.data(), units.size());
@@ -1651,17 +1651,17 @@ template<>
 /* static */ MOZ_ALWAYS_INLINE JSAtom*
 TokenStreamCharsBase<mozilla::Utf8Unit>::atomizeSourceChars(JSContext* cx,
                                                             mozilla::Span<const mozilla::Utf8Unit> units)
 {
     auto chars = ToCharSpan(units);
     return AtomizeUTF8Chars(cx, chars.data(), chars.size());
 }
 
-template<typename CharT>
+template<typename Unit>
 class SpecializedTokenStreamCharsBase;
 
 template<>
 class SpecializedTokenStreamCharsBase<char16_t>
   : public TokenStreamCharsBase<char16_t>
 {
     using CharsBase = TokenStreamCharsBase<char16_t>;
 
@@ -1693,17 +1693,17 @@ class SpecializedTokenStreamCharsBase<ch
         }
 
         // Otherwise it's a multi-unit code point.
         return unicode::UTF16Decode(lead, this->sourceUnits.getCodeUnit());
     }
 
   protected:
     // These APIs are in both SpecializedTokenStreamCharsBase specializations
-    // and so are usable in subclasses no matter what CharT is.
+    // and so are usable in subclasses no matter what Unit is.
 
     using CharsBase::CharsBase;
 };
 
 template<>
 class SpecializedTokenStreamCharsBase<mozilla::Utf8Unit>
   : public TokenStreamCharsBase<mozilla::Utf8Unit>
 {
@@ -1794,17 +1794,17 @@ class SpecializedTokenStreamCharsBase<mo
 
     /** A sentinel representing the end of |SourceUnits| data. */
     class SourceUnitsEnd {};
 
     friend inline size_t operator-(const SourceUnitsEnd& aEnd, const SourceUnitsIterator& aIter);
 
   protected:
     // These APIs are in both SpecializedTokenStreamCharsBase specializations
-    // and so are usable in subclasses no matter what CharT is.
+    // and so are usable in subclasses no matter what Unit is.
 
     using CharsBase::CharsBase;
 };
 
 inline size_t
 operator-(const SpecializedTokenStreamCharsBase<mozilla::Utf8Unit>::SourceUnitsEnd& aEnd,
           const SpecializedTokenStreamCharsBase<mozilla::Utf8Unit>::SourceUnitsIterator& aIter)
 {
@@ -1827,22 +1827,22 @@ class TokenStart
       : startOffset_(sourceUnits.offset() + adjust)
     {}
 
     TokenStart(const TokenStart&) = default;
 
     uint32_t offset() const { return startOffset_; }
 };
 
-template<typename CharT, class AnyCharsAccess>
+template<typename Unit, class AnyCharsAccess>
 class GeneralTokenStreamChars
-  : public SpecializedTokenStreamCharsBase<CharT>
+  : public SpecializedTokenStreamCharsBase<Unit>
 {
-    using CharsBase = TokenStreamCharsBase<CharT>;
-    using SpecializedCharsBase = SpecializedTokenStreamCharsBase<CharT>;
+    using CharsBase = TokenStreamCharsBase<Unit>;
+    using SpecializedCharsBase = SpecializedTokenStreamCharsBase<Unit>;
 
   private:
     Token* newTokenInternal(TokenKind kind, TokenStart start, TokenKind* out);
 
     /**
      * Allocates a new Token from the given offset to the current offset,
      * ascribes it the given kind, and sets |*out| to that kind.
      */
@@ -1867,32 +1867,32 @@ class GeneralTokenStreamChars
 
   protected:
     using CharsBase::addLineOfContext;
     using TokenStreamCharsShared::drainCharBufferIntoAtom;
     using CharsBase::fillCharBufferFromSourceNormalizingAsciiLineBreaks;
     using TokenStreamCharsShared::isAsciiCodePoint;
     using CharsBase::matchLineTerminator;
     // Deliberately don't |using CharsBase::sourceUnits| because of bug 1472569.  :-(
-    using CharsBase::toCharT;
+    using CharsBase::toUnit;
 
     using typename CharsBase::SourceUnits;
 
   protected:
     using SpecializedCharsBase::SpecializedCharsBase;
 
     TokenStreamAnyChars& anyCharsAccess() {
         return AnyCharsAccess::anyChars(this);
     }
 
     const TokenStreamAnyChars& anyCharsAccess() const {
         return AnyCharsAccess::anyChars(this);
     }
 
-    using TokenStreamSpecific = frontend::TokenStreamSpecific<CharT, AnyCharsAccess>;
+    using TokenStreamSpecific = frontend::TokenStreamSpecific<Unit, AnyCharsAccess>;
 
     TokenStreamSpecific* asSpecific() {
         static_assert(mozilla::IsBaseOf<GeneralTokenStreamChars, TokenStreamSpecific>::value,
                       "static_cast below presumes an inheritance relationship");
 
         return static_cast<TokenStreamSpecific*>(this);
     }
 
@@ -1968,17 +1968,17 @@ class GeneralTokenStreamChars
      *
      * If a LineTerminatorSequence was consumed, also update line/column info.
      *
      * This may change the current |sourceUnits| offset.
      */
     MOZ_MUST_USE bool getFullAsciiCodePoint(int32_t lead, int32_t* codePoint) {
         MOZ_ASSERT(isAsciiCodePoint(lead),
                    "non-ASCII code units must be handled separately");
-        MOZ_ASSERT(toCharT(lead) == this->sourceUnits.previousCodeUnit(),
+        MOZ_ASSERT(toUnit(lead) == this->sourceUnits.previousCodeUnit(),
                    "getFullAsciiCodePoint called incorrectly");
 
         if (MOZ_UNLIKELY(lead == '\r')) {
             matchLineTerminator('\n');
         } else if (MOZ_LIKELY(lead != '\n')) {
             *codePoint = lead;
             return true;
         }
@@ -2022,18 +2022,18 @@ class GeneralTokenStreamChars
     }
 
   public:
     JSAtom* getRawTemplateStringAtom() {
         TokenStreamAnyChars& anyChars = anyCharsAccess();
 
         MOZ_ASSERT(anyChars.currentToken().type == TokenKind::TemplateHead ||
                    anyChars.currentToken().type == TokenKind::NoSubsTemplate);
-        const CharT* cur = this->sourceUnits.codeUnitPtrAt(anyChars.currentToken().pos.begin + 1);
-        const CharT* end;
+        const Unit* cur = this->sourceUnits.codeUnitPtrAt(anyChars.currentToken().pos.begin + 1);
+        const Unit* end;
         if (anyChars.currentToken().type == TokenKind::TemplateHead) {
             // Of the form    |`...${|   or   |}...${|
             end = this->sourceUnits.codeUnitPtrAt(anyChars.currentToken().pos.end - 2);
         } else {
             // NO_SUBS_TEMPLATE is of the form   |`...`|   or   |}...`|
             end = this->sourceUnits.codeUnitPtrAt(anyChars.currentToken().pos.end - 1);
         }
 
@@ -2043,17 +2043,17 @@ class GeneralTokenStreamChars
         if (!fillCharBufferFromSourceNormalizingAsciiLineBreaks(cur, end)) {
             return nullptr;
         }
 
         return drainCharBufferIntoAtom(anyChars.cx);
     }
 };
 
-template<typename CharT, class AnyCharsAccess> class TokenStreamChars;
+template<typename Unit, class AnyCharsAccess> class TokenStreamChars;
 
 template<class AnyCharsAccess>
 class TokenStreamChars<char16_t, AnyCharsAccess>
   : public GeneralTokenStreamChars<char16_t, AnyCharsAccess>
 {
     using CharsBase = TokenStreamCharsBase<char16_t>;
     using SpecializedCharsBase = SpecializedTokenStreamCharsBase<char16_t>;
     using GeneralCharsBase = GeneralTokenStreamChars<char16_t, AnyCharsAccess>;
@@ -2239,17 +2239,17 @@ class TokenStreamChars<mozilla::Utf8Unit
      *
      * This function will change the current |sourceUnits| offset.
      */
     MOZ_MUST_USE bool getNonAsciiCodePoint(int32_t lead, int32_t* codePoint);
 };
 
 // TokenStream is the lexical scanner for JavaScript source text.
 //
-// It takes a buffer of CharT code units (currently only char16_t encoding
+// It takes a buffer of Unit code units (currently only char16_t encoding
 // UTF-16, but we're adding either UTF-8 or Latin-1 single-byte text soon) and
 // linearly scans it into |Token|s.
 //
 // Internally the class uses a four element circular buffer |tokens| of
 // |Token|s. As an index for |tokens|, the member |cursor_| points to the
 // current token. Calls to getToken() increase |cursor_| by one and return the
 // new current token. If a TokenStream was just created, the current token is
 // uninitialized. It's therefore important that one of the first four member
@@ -2278,29 +2278,29 @@ class TokenStreamChars<mozilla::Utf8Unit
 // this turns out not to be a problem in practice. See the
 // mozilla.dev.tech.js-engine.internals thread entitled 'Bug in the scanner?'
 // for more details:
 // https://groups.google.com/forum/?fromgroups=#!topic/mozilla.dev.tech.js-engine.internals/2JLH5jRcr7E).
 //
 // The method seek() allows rescanning from a previously visited location of
 // the buffer, initially computed by constructing a Position local variable.
 //
-template<typename CharT, class AnyCharsAccess>
+template<typename Unit, class AnyCharsAccess>
 class MOZ_STACK_CLASS TokenStreamSpecific
-  : public TokenStreamChars<CharT, AnyCharsAccess>,
+  : public TokenStreamChars<Unit, AnyCharsAccess>,
     public TokenStreamShared,
     public ErrorReporter
 {
   public:
-    using CharsBase = TokenStreamCharsBase<CharT>;
-    using SpecializedCharsBase = SpecializedTokenStreamCharsBase<CharT>;
-    using GeneralCharsBase = GeneralTokenStreamChars<CharT, AnyCharsAccess>;
-    using SpecializedChars = TokenStreamChars<CharT, AnyCharsAccess>;
-
-    using Position = TokenStreamPosition<CharT>;
+    using CharsBase = TokenStreamCharsBase<Unit>;
+    using SpecializedCharsBase = SpecializedTokenStreamCharsBase<Unit>;
+    using GeneralCharsBase = GeneralTokenStreamChars<Unit, AnyCharsAccess>;
+    using SpecializedChars = TokenStreamChars<Unit, AnyCharsAccess>;
+
+    using Position = TokenStreamPosition<Unit>;
 
     // Anything inherited through a base class whose type depends upon this
     // class's template parameters can only be accessed through a dependent
     // name: prefixed with |this|, by explicit qualification, and so on.  (This
     // is so that references to inherited fields are statically distinguishable
     // from references to names outside of the class.)  This is tedious and
     // onerous.
     //
@@ -2335,25 +2335,25 @@ class MOZ_STACK_CLASS TokenStreamSpecifi
     using GeneralCharsBase::matchUnicodeEscapeIdStart;
     using GeneralCharsBase::newAtomToken;
     using GeneralCharsBase::newNameToken;
     using GeneralCharsBase::newNumberToken;
     using GeneralCharsBase::newRegExpToken;
     using GeneralCharsBase::newSimpleToken;
     using CharsBase::peekCodeUnit;
     // Deliberately don't |using| |sourceUnits| because of bug 1472569.  :-(
-    using CharsBase::toCharT;
+    using CharsBase::toUnit;
     using GeneralCharsBase::ungetCodeUnit;
     using GeneralCharsBase::updateLineInfoForEOL;
 
     template<typename CharU> friend class TokenStreamPosition;
 
   public:
     TokenStreamSpecific(JSContext* cx, const JS::ReadOnlyCompileOptions& options,
-                        const CharT* base, size_t length);
+                        const Unit* units, size_t length);
 
     /**
      * Get the next code point, converting LineTerminatorSequences to '\n' and
      * updating internal line-counter state if needed.  Return true on success
      * and store the code point in |*cp|.  Return false and leave |*cp|
      * undefined on failure.
      */
     MOZ_MUST_USE bool getCodePoint(int32_t* cp);
@@ -2452,17 +2452,17 @@ class MOZ_STACK_CLASS TokenStreamSpecifi
                 errorAt(offset, JSMSG_UNICODE_OVERFLOW, "escape sequence");
                 return;
             case InvalidEscapeType::Octal:
                 errorAt(offset, JSMSG_DEPRECATED_OCTAL);
                 return;
         }
     }
 
-    MOZ_MUST_USE bool putIdentInCharBuffer(const CharT* identStart);
+    MOZ_MUST_USE bool putIdentInCharBuffer(const Unit* identStart);
 
     /**
      * Tokenize a decimal number that begins at |numStart| into the provided
      * token.
      *
      * |unit| must be one of these values:
      *
      *   1. The first decimal digit in the integral part of a decimal number
@@ -2492,17 +2492,17 @@ class MOZ_STACK_CLASS TokenStreamSpecifi
      *
      *   In this case, the next |getCodeUnit()| returns the code unit after
      *   |unit|: '.', '6', or '+' in the examples above.
      *
      * This interface is super-hairy and horribly stateful.  Unfortunately, its
      * hair merely reflects the intricacy of ECMAScript numeric literal syntax.
      * And incredibly, it *improves* on the goto-based horror that predated it.
      */
-    MOZ_MUST_USE bool decimalNumber(int32_t unit, TokenStart start, const CharT* numStart,
+    MOZ_MUST_USE bool decimalNumber(int32_t unit, TokenStart start, const Unit* numStart,
                                     Modifier modifier, TokenKind* out);
 
     /** Tokenize a regular expression literal beginning at |start|. */
     MOZ_MUST_USE bool regexpLiteral(TokenStart start, TokenKind* out);
 
   public:
     // Advance to the next token.  If the token stream encountered an error,
     // return false.  Otherwise return true and store the token kind in |*ttp|.
@@ -2655,25 +2655,25 @@ class MOZ_STACK_CLASS TokenStreamSpecifi
         return true;
     }
 
     MOZ_MUST_USE bool advance(size_t position);
 
     void seek(const Position& pos);
     MOZ_MUST_USE bool seek(const Position& pos, const TokenStreamAnyChars& other);
 
-    const CharT* codeUnitPtrAt(size_t offset) const {
+    const Unit* codeUnitPtrAt(size_t offset) const {
         return this->sourceUnits.codeUnitPtrAt(offset);
     }
 
-    const CharT* rawLimit() const {
+    const Unit* rawLimit() const {
         return this->sourceUnits.limit();
     }
 
-    MOZ_MUST_USE bool identifierName(TokenStart start, const CharT* identStart,
+    MOZ_MUST_USE bool identifierName(TokenStart start, const Unit* identStart,
                                      IdentifierEscapes escaping, Modifier modifier,
                                      TokenKind* out);
 
     MOZ_MUST_USE bool getTokenInternal(TokenKind* const ttp, const Modifier modifier);
 
     MOZ_MUST_USE bool getStringOrTemplateToken(char untilChar, Modifier modifier, TokenKind* out);
 
     MOZ_MUST_USE bool getDirectives(bool isMultiline, bool shouldWarnDeprecated);
@@ -2682,25 +2682,25 @@ class MOZ_STACK_CLASS TokenStreamSpecifi
                                    const char* errorMsgPragma,
                                    UniquePtr<char16_t[], JS::FreePolicy>* destination);
     MOZ_MUST_USE bool getDisplayURL(bool isMultiline, bool shouldWarnDeprecated);
     MOZ_MUST_USE bool getSourceMappingURL(bool isMultiline, bool shouldWarnDeprecated);
 };
 
 // It's preferable to define this in TokenStream.cpp, but its template-ness
 // means we'd then have to *instantiate* this constructor for all possible
-// (CharT, AnyCharsAccess) pairs -- and that gets super-messy as AnyCharsAccess
+// (Unit, AnyCharsAccess) pairs -- and that gets super-messy as AnyCharsAccess
 // *itself* is templated.  This symbol really isn't that huge compared to some
 // defined inline in TokenStreamSpecific, so just rely on the linker commoning
 // stuff up.
-template<typename CharT>
+template<typename Unit>
 template<class AnyCharsAccess>
 inline
-TokenStreamPosition<CharT>::TokenStreamPosition(AutoKeepAtoms& keepAtoms,
-                                                TokenStreamSpecific<CharT, AnyCharsAccess>& tokenStream)
+TokenStreamPosition<Unit>::TokenStreamPosition(AutoKeepAtoms& keepAtoms,
+                                               TokenStreamSpecific<Unit, AnyCharsAccess>& tokenStream)
 {
     TokenStreamAnyChars& anyChars = tokenStream.anyCharsAccess();
 
     buf = tokenStream.sourceUnits.addressOfNextCodeUnit(/* allowPoisoned = */ true);
     flags = anyChars.flags;
     lineno = anyChars.lineno;
     linebase = anyChars.linebase;
     prevLinebase = anyChars.prevLinebase;
@@ -2720,23 +2720,23 @@ class TokenStreamAnyCharsAccess
     template<class TokenStreamSpecific>
     static inline const TokenStreamAnyChars& anyChars(const TokenStreamSpecific* tss);
 };
 
 class MOZ_STACK_CLASS TokenStream final
   : public TokenStreamAnyChars,
     public TokenStreamSpecific<char16_t, TokenStreamAnyCharsAccess>
 {
-    using CharT = char16_t;
+    using Unit = char16_t;
 
   public:
     TokenStream(JSContext* cx, const JS::ReadOnlyCompileOptions& options,
-                const CharT* base, size_t length, StrictModeGetter* smg)
+                const Unit* units, size_t length, StrictModeGetter* smg)
     : TokenStreamAnyChars(cx, options, smg),
-      TokenStreamSpecific<CharT, TokenStreamAnyCharsAccess>(cx, options, base, length)
+      TokenStreamSpecific<Unit, TokenStreamAnyCharsAccess>(cx, options, units, length)
     {}
 };
 
 template<class TokenStreamSpecific>
 /* static */ inline TokenStreamAnyChars&
 TokenStreamAnyCharsAccess::anyChars(TokenStreamSpecific* tss)
 {
     auto* ts = static_cast<TokenStream*>(tss);
--- a/js/src/vm/JSFunction.cpp
+++ b/js/src/vm/JSFunction.cpp
@@ -1782,36 +1782,36 @@ JSFunction::createScriptForLazilyInterpr
         } else {
             MOZ_ASSERT(lazy->scriptSource()->hasSourceText());
 
             // Parse and compile the script from source.
             UncompressedSourceCache::AutoHoldEntry holder;
 
             if (lazy->scriptSource()->hasSourceType<Utf8Unit>()) {
                 // UTF-8 source text.
-                ScriptSource::PinnedChars<Utf8Unit> chars(cx, lazy->scriptSource(), holder,
+                ScriptSource::PinnedUnits<Utf8Unit> units(cx, lazy->scriptSource(), holder,
                                                           lazy->sourceStart(), lazyLength);
-                if (!chars.get()) {
+                if (!units.get()) {
                     return false;
                 }
 
                 // XXX There are no UTF-8 ScriptSources now, so just crash so this
                 //     gets filled in later.
                 MOZ_CRASH("UTF-8 lazy function compilation not implemented yet");
             } else {
                 MOZ_ASSERT(lazy->scriptSource()->hasSourceType<char16_t>());
 
                 // UTF-16 source text.
-                ScriptSource::PinnedChars<char16_t> chars(cx, lazy->scriptSource(), holder,
+                ScriptSource::PinnedUnits<char16_t> units(cx, lazy->scriptSource(), holder,
                                                           lazy->sourceStart(), lazyLength);
-                if (!chars.get()) {
+                if (!units.get()) {
                     return false;
                 }
 
-                if (!frontend::CompileLazyFunction(cx, lazy, chars.get(), lazyLength)) {
+                if (!frontend::CompileLazyFunction(cx, lazy, units.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;
                 }
             }
--- a/js/src/vm/JSScript.cpp
+++ b/js/src/vm/JSScript.cpp
@@ -1568,17 +1568,17 @@ JSScript::loadSource(JSContext* cx, Scri
         return false;
     }
     if (!src) {
         return true;
     }
 
     // XXX On-demand source is currently only UTF-16.  Perhaps it should be
     //     changed to UTF-8, or UTF-8 be allowed in addition to UTF-16?
-    if (!ss->setSource(cx, EntryChars<char16_t>(src), length)) {
+    if (!ss->setSource(cx, EntryUnits<char16_t>(src), length)) {
         return false;
     }
 
     *worked = true;
     return true;
 }
 
 /* static */ JSFlatString*
@@ -1605,30 +1605,30 @@ UncompressedSourceCache::holdEntry(AutoH
 
 void
 UncompressedSourceCache::releaseEntry(AutoHoldEntry& holder)
 {
     MOZ_ASSERT(holder_ == &holder);
     holder_ = nullptr;
 }
 
-template<typename CharT>
-const CharT*
+template<typename Unit>
+const Unit*
 UncompressedSourceCache::lookup(const ScriptSourceChunk& ssc, AutoHoldEntry& holder)
 {
     MOZ_ASSERT(!holder_);
-    MOZ_ASSERT(ssc.ss->compressedSourceIs<CharT>());
+    MOZ_ASSERT(ssc.ss->compressedSourceIs<Unit>());
 
     if (!map_) {
         return nullptr;
     }
 
     if (Map::Ptr p = map_->lookup(ssc)) {
         holdEntry(holder, ssc);
-        return static_cast<const CharT*>(p->value().get());
+        return static_cast<const Unit*>(p->value().get());
     }
 
     return nullptr;
 }
 
 bool
 UncompressedSourceCache::put(const ScriptSourceChunk& ssc, SourceData data, AutoHoldEntry& holder)
 {
@@ -1674,318 +1674,318 @@ UncompressedSourceCache::sizeOfExcluding
         n += map_->shallowSizeOfIncludingThis(mallocSizeOf);
         for (Map::Range r = map_->all(); !r.empty(); r.popFront()) {
             n += mallocSizeOf(r.front().value().get());
         }
     }
     return n;
 }
 
-template<typename CharT>
-const CharT*
-ScriptSource::chunkChars(JSContext* cx, UncompressedSourceCache::AutoHoldEntry& holder,
+template<typename Unit>
+const Unit*
+ScriptSource::chunkUnits(JSContext* cx, UncompressedSourceCache::AutoHoldEntry& holder,
                          size_t chunk)
 {
-    const Compressed<CharT>& c = data.as<Compressed<CharT>>();
+    const Compressed<Unit>& c = data.as<Compressed<Unit>>();
 
     ScriptSourceChunk ssc(this, chunk);
-    if (const CharT* decompressed = cx->caches().uncompressedSourceCache.lookup<CharT>(ssc, holder)) {
+    if (const Unit* decompressed = cx->caches().uncompressedSourceCache.lookup<Unit>(ssc, holder)) {
         return decompressed;
     }
 
-    size_t totalLengthInBytes = length() * sizeof(CharT);
+    size_t totalLengthInBytes = length() * sizeof(Unit);
     size_t chunkBytes = Compressor::chunkSize(totalLengthInBytes, chunk);
 
-    MOZ_ASSERT((chunkBytes % sizeof(CharT)) == 0);
-    const size_t lengthWithNull = (chunkBytes / sizeof(CharT)) + 1;
-    EntryChars<CharT> decompressed(js_pod_malloc<CharT>(lengthWithNull));
+    MOZ_ASSERT((chunkBytes % sizeof(Unit)) == 0);
+    const size_t lengthWithNull = (chunkBytes / sizeof(Unit)) + 1;
+    EntryUnits<Unit> decompressed(js_pod_malloc<Unit>(lengthWithNull));
     if (!decompressed) {
         JS_ReportOutOfMemory(cx);
         return nullptr;
     }
 
     // Compression treats input and output memory as plain ol' bytes. These
     // reinterpret_cast<>s accord exactly with that.
     if (!DecompressStringChunk(reinterpret_cast<const unsigned char*>(c.raw.chars()),
                                chunk,
                                reinterpret_cast<unsigned char*>(decompressed.get()),
                                chunkBytes))
     {
         JS_ReportOutOfMemory(cx);
         return nullptr;
     }
 
-    decompressed[lengthWithNull - 1] = CharT('\0');
-
-    const CharT* ret = decompressed.get();
+    decompressed[lengthWithNull - 1] = Unit('\0');
+
+    const Unit* ret = decompressed.get();
     if (!cx->caches().uncompressedSourceCache.put(ssc, ToSourceData(std::move(decompressed)),
                                                   holder))
     {
         JS_ReportOutOfMemory(cx);
         return nullptr;
     }
     return ret;
 }
 
-template<typename CharT>
+template<typename Unit>
 void
 ScriptSource::movePendingCompressedSource()
 {
     if (pendingCompressed_.empty()) {
         return;
     }
 
-    Compressed<CharT>& pending = pendingCompressed_.ref<Compressed<CharT>>();
+    Compressed<Unit>& pending = pendingCompressed_.ref<Compressed<Unit>>();
 
     MOZ_ASSERT(!hasCompressedSource());
     MOZ_ASSERT_IF(hasUncompressedSource(),
                   pending.uncompressedLength == length());
 
     data = SourceType(std::move(pending));
     pendingCompressed_.destroy();
 }
 
-template<typename CharT>
-ScriptSource::PinnedChars<CharT>::~PinnedChars()
+template<typename Unit>
+ScriptSource::PinnedUnits<Unit>::~PinnedUnits()
 {
-    if (chars_) {
+    if (units_) {
         MOZ_ASSERT(*stack_ == this);
         *stack_ = prev_;
         if (!prev_) {
-            source_->movePendingCompressedSource<CharT>();
+            source_->movePendingCompressedSource<Unit>();
         }
     }
 }
 
-template<typename CharT>
-const CharT*
-ScriptSource::chars(JSContext* cx, UncompressedSourceCache::AutoHoldEntry& holder,
+template<typename Unit>
+const Unit*
+ScriptSource::units(JSContext* cx, UncompressedSourceCache::AutoHoldEntry& holder,
                     size_t begin, size_t len)
 {
     MOZ_ASSERT(begin <= length());
     MOZ_ASSERT(begin + len <= length());
 
-    if (data.is<Uncompressed<CharT>>()) {
-        const CharT* chars = data.as<Uncompressed<CharT>>().chars();
-        if (!chars) {
+    if (data.is<Uncompressed<Unit>>()) {
+        const Unit* units = data.as<Uncompressed<Unit>>().units();
+        if (!units) {
             return nullptr;
         }
-        return chars + begin;
+        return units + begin;
     }
 
     if (data.is<Missing>()) {
-        MOZ_CRASH("ScriptSource::chars() on ScriptSource with SourceType = Missing");
-    }
-
-    MOZ_ASSERT(data.is<Compressed<CharT>>());
+        MOZ_CRASH("ScriptSource::units() on ScriptSource with SourceType = Missing");
+    }
+
+    MOZ_ASSERT(data.is<Compressed<Unit>>());
 
     // Determine which chunk(s) we are interested in, and the offsets within
     // these chunks.
     size_t firstChunk, lastChunk;
     size_t firstChunkOffset, lastChunkOffset;
     MOZ_ASSERT(len > 0);
-    Compressor::toChunkOffset(begin * sizeof(CharT), &firstChunk, &firstChunkOffset);
-    Compressor::toChunkOffset((begin + len - 1) * sizeof(CharT), &lastChunk, &lastChunkOffset);
-
-    MOZ_ASSERT(firstChunkOffset % sizeof(CharT) == 0);
-    size_t firstChar = firstChunkOffset / sizeof(CharT);
+    Compressor::toChunkOffset(begin * sizeof(Unit), &firstChunk, &firstChunkOffset);
+    Compressor::toChunkOffset((begin + len - 1) * sizeof(Unit), &lastChunk, &lastChunkOffset);
+
+    MOZ_ASSERT(firstChunkOffset % sizeof(Unit) == 0);
+    size_t firstUnit = firstChunkOffset / sizeof(Unit);
 
     if (firstChunk == lastChunk) {
-        const CharT* chars = chunkChars<CharT>(cx, holder, firstChunk);
-        if (!chars) {
+        const Unit* units = chunkUnits<Unit>(cx, holder, firstChunk);
+        if (!units) {
             return nullptr;
         }
 
-        return chars + firstChar;
+        return units + firstUnit;
     }
 
     // We need multiple chunks. Allocate a (null-terminated) buffer to hold
-    // |len| chars and copy uncompressed chars from the chunks into it. We use
-    // chunkChars() so we benefit from chunk caching by UncompressedSourceCache.
+    // |len| units and copy uncompressed units from the chunks into it. We use
+    // chunkUnits() so we benefit from chunk caching by UncompressedSourceCache.
 
     MOZ_ASSERT(firstChunk < lastChunk);
 
     size_t lengthWithNull = len + 1;
-    EntryChars<CharT> decompressed(js_pod_malloc<CharT>(lengthWithNull));
+    EntryUnits<Unit> decompressed(js_pod_malloc<Unit>(lengthWithNull));
     if (!decompressed) {
         JS_ReportOutOfMemory(cx);
         return nullptr;
     }
 
-    size_t totalLengthInBytes = length() * sizeof(CharT);
-    CharT* cursor = decompressed.get();
+    size_t totalLengthInBytes = length() * sizeof(Unit);
+    Unit* cursor = decompressed.get();
 
     for (size_t i = firstChunk; i <= lastChunk; i++) {
         UncompressedSourceCache::AutoHoldEntry chunkHolder;
-        const CharT* chars = chunkChars<CharT>(cx, chunkHolder, i);
-        if (!chars) {
+        const Unit* units = chunkUnits<Unit>(cx, chunkHolder, i);
+        if (!units) {
             return nullptr;
         }
 
-        size_t numChars = Compressor::chunkSize(totalLengthInBytes, i) / sizeof(CharT);
+        size_t numUnits = Compressor::chunkSize(totalLengthInBytes, i) / sizeof(Unit);
         if (i == firstChunk) {
-            MOZ_ASSERT(firstChar < numChars);
-            chars += firstChar;
-            numChars -= firstChar;
+            MOZ_ASSERT(firstUnit < numUnits);
+            units += firstUnit;
+            numUnits -= firstUnit;
         } else if (i == lastChunk) {
-            size_t numCharsNew = lastChunkOffset / sizeof(CharT) + 1;
-            MOZ_ASSERT(numCharsNew <= numChars);
-            numChars = numCharsNew;
+            size_t numUnitsNew = lastChunkOffset / sizeof(Unit) + 1;
+            MOZ_ASSERT(numUnitsNew <= numUnits);
+            numUnits = numUnitsNew;
         }
-        mozilla::PodCopy(cursor, chars, numChars);
-        cursor += numChars;
+        mozilla::PodCopy(cursor, units, numUnits);
+        cursor += numUnits;
     }
 
     // XXX Bug 1499192: can we remove the null-termination?  It's unclear if
     //     anyone uses chunk implicit null-termination, chunks can contain
     //     nulls anyway, and the extra character risks size-class goofs.
-    *cursor++ = CharT('\0');
+    *cursor++ = Unit('\0');
     MOZ_ASSERT(PointerRangeSize(decompressed.get(), cursor) == lengthWithNull);
 
     // Transfer ownership to |holder|.
-    const CharT* ret = decompressed.get();
-    holder.holdChars(std::move(decompressed));
+    const Unit* ret = decompressed.get();
+    holder.holdUnits(std::move(decompressed));
     return ret;
 }
 
-template<typename CharT>
-ScriptSource::PinnedChars<CharT>::PinnedChars(JSContext* cx, ScriptSource* source,
-                                              UncompressedSourceCache::AutoHoldEntry& holder,
-                                              size_t begin, size_t len)
-  : PinnedCharsBase(source)
+template<typename Unit>
+ScriptSource::PinnedUnits<Unit>::PinnedUnits(JSContext* cx, ScriptSource* source,
+                                             UncompressedSourceCache::AutoHoldEntry& holder,
+                                             size_t begin, size_t len)
+  : PinnedUnitsBase(source)
 {
-    MOZ_ASSERT(source->hasSourceType<CharT>(),
-               "must pin chars of source's type");
-
-    chars_ = source->chars<CharT>(cx, holder, begin, len);
-    if (chars_) {
-        stack_ = &source->pinnedCharsStack_;
+    MOZ_ASSERT(source->hasSourceType<Unit>(),
+               "must pin units of source's type");
+
+    units_ = source->units<Unit>(cx, holder, begin, len);
+    if (units_) {
+        stack_ = &source->pinnedUnitsStack_;
         prev_ = *stack_;
         *stack_ = this;
     }
 }
 
-template class ScriptSource::PinnedChars<Utf8Unit>;
-template class ScriptSource::PinnedChars<char16_t>;
+template class ScriptSource::PinnedUnits<Utf8Unit>;
+template class ScriptSource::PinnedUnits<char16_t>;
 
 JSFlatString*
 ScriptSource::substring(JSContext* cx, size_t start, size_t stop)
 {
     MOZ_ASSERT(start <= stop);
 
     size_t len = stop - start;
     UncompressedSourceCache::AutoHoldEntry holder;
 
     // UTF-8 source text.
     if (hasSourceType<Utf8Unit>()) {
-        PinnedChars<Utf8Unit> chars(cx, this, holder, start, len);
-        if (!chars.get()) {
+        PinnedUnits<Utf8Unit> units(cx, this, holder, start, len);
+        if (!units.asChars()) {
             return nullptr;
         }
 
-        char* str = SourceTypeTraits<Utf8Unit>::toString(chars.get());
+        const char* str = units.asChars();
         return NewStringCopyUTF8N<CanGC>(cx, JS::UTF8Chars(str, len));
     }
 
     // UTF-16 source text.
-    PinnedChars<char16_t> chars(cx, this, holder, start, len);
-    if (!chars.get()) {
+    PinnedUnits<char16_t> units(cx, this, holder, start, len);
+    if (!units.asChars()) {
         return nullptr;
     }
 
-    return NewStringCopyN<CanGC>(cx, chars.get(), len);
+    return NewStringCopyN<CanGC>(cx, units.asChars(), len);
 }
 
 JSFlatString*
 ScriptSource::substringDontDeflate(JSContext* cx, size_t start, size_t stop)
 {
     MOZ_ASSERT(start <= stop);
 
     size_t len = stop - start;
     UncompressedSourceCache::AutoHoldEntry holder;
 
     // UTF-8 source text.
     if (hasSourceType<Utf8Unit>()) {
-        PinnedChars<Utf8Unit> chars(cx, this, holder, start, len);
-        if (!chars.get()) {
+        PinnedUnits<Utf8Unit> units(cx, this, holder, start, len);
+        if (!units.asChars()) {
             return nullptr;
         }
 
-        char* str = SourceTypeTraits<Utf8Unit>::toString(chars.get());
+        const char* str = units.asChars();
 
         // There doesn't appear to be a non-deflating UTF-8 string creation
         // function -- but then again, it's not entirely clear how current
         // callers benefit from non-deflation.
         return NewStringCopyUTF8N<CanGC>(cx, JS::UTF8Chars(str, len));
     }
 
     // UTF-16 source text.
-    PinnedChars<char16_t> chars(cx, this, holder, start, len);
-    if (!chars.get()) {
+    PinnedUnits<char16_t> units(cx, this, holder, start, len);
+    if (!units.asChars()) {
         return nullptr;
     }
 
-    return NewStringCopyNDontDeflate<CanGC>(cx, chars.get(), len);
+    return NewStringCopyNDontDeflate<CanGC>(cx, units.asChars(), len);
 }
 
 bool
 ScriptSource::appendSubstring(JSContext* cx, StringBuffer& buf, size_t start, size_t stop)
 {
     MOZ_ASSERT(start <= stop);
 
     size_t len = stop - start;
     UncompressedSourceCache::AutoHoldEntry holder;
 
     if (hasSourceType<Utf8Unit>()) {
         MOZ_CRASH("for now");
         return false;
     } else {
-        PinnedChars<char16_t> chars(cx, this, holder, start, len);
-        if (!chars.get()) {
+        PinnedUnits<char16_t> units(cx, this, holder, start, len);
+        if (!units.asChars()) {
             return false;
         }
         if (len > SourceDeflateLimit && !buf.ensureTwoByteChars()) {
             return false;
         }
-        return buf.append(chars.get(), len);
+        return buf.append(units.asChars(), len);
     }
 }
 
 JSFlatString*
 ScriptSource::functionBodyString(JSContext* cx)
 {
     MOZ_ASSERT(isFunctionBody());
 
     size_t start = parameterListEnd_ + (sizeof(FunctionConstructorMedialSigils) - 1);
     size_t stop = length() - (sizeof(FunctionConstructorFinalBrace) - 1);
     return substring(cx, start, stop);
 }
 
-template<typename CharT>
+template<typename Unit>
 void
-ScriptSource::setSource(typename SourceTypeTraits<CharT>::SharedImmutableString uncompressed)
+ScriptSource::setSource(typename SourceTypeTraits<Unit>::SharedImmutableString uncompressed)
 {
     MOZ_ASSERT(data.is<Missing>());
-    data = SourceType(Uncompressed<CharT>(std::move(uncompressed)));
+    data = SourceType(Uncompressed<Unit>(std::move(uncompressed)));
 }
 
-template<typename CharT>
+template<typename Unit>
 MOZ_MUST_USE bool
-ScriptSource::setSource(JSContext* cx, EntryChars<CharT>&& source, size_t length)
+ScriptSource::setSource(JSContext* cx, EntryUnits<Unit>&& source, size_t length)
 {
     auto& cache = cx->zone()->runtimeFromAnyThread()->sharedImmutableStrings();
 
-    auto uniqueChars = SourceTypeTraits<CharT>::toCacheable(std::move(source));
+    auto uniqueChars = SourceTypeTraits<Unit>::toCacheable(std::move(source));
     auto deduped = cache.getOrCreate(std::move(uniqueChars), length);
     if (!deduped) {
         ReportOutOfMemory(cx);
         return false;
     }
 
-    setSource<CharT>(std::move(*deduped));
+    setSource<Unit>(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)
 {
@@ -2066,46 +2066,46 @@ ScriptSource::tryCompressOffThread(JSCon
     auto task = MakeUnique<SourceCompressionTask>(cx->runtime(), this);
     if (!task) {
         ReportOutOfMemory(cx);
         return false;
     }
     return EnqueueOffThreadCompression(cx, std::move(task));
 }
 
-template<typename CharT>
+template<typename Unit>
 void
 ScriptSource::setCompressedSource(SharedImmutableString raw, size_t uncompressedLength)
 {
     MOZ_ASSERT(data.is<Missing>() || hasUncompressedSource());
     MOZ_ASSERT_IF(hasUncompressedSource(), length() == uncompressedLength);
 
-    if (pinnedCharsStack_) {
+    if (pinnedUnitsStack_) {
         MOZ_ASSERT(pendingCompressed_.empty());
-        pendingCompressed_.construct<Compressed<CharT>>(std::move(raw), uncompressedLength);
+        pendingCompressed_.construct<Compressed<Unit>>(std::move(raw), uncompressedLength);
     } else {
-        data = SourceType(Compressed<CharT>(std::move(raw), uncompressedLength));
+        data = SourceType(Compressed<Unit>(std::move(raw), uncompressedLength));
     }
 }
 
-template<typename CharT>
+template<typename Unit>
 MOZ_MUST_USE bool
 ScriptSource::setCompressedSource(JSContext* cx, UniqueChars&& compressed, size_t rawLength,
                                   size_t sourceLength)
 {
     MOZ_ASSERT(compressed);
 
     auto& cache = cx->zone()->runtimeFromAnyThread()->sharedImmutableStrings();
     auto deduped = cache.getOrCreate(std::move(compressed), rawLength);
     if (!deduped) {
         ReportOutOfMemory(cx);
         return false;
     }
 
-    setCompressedSource<CharT>(std::move(*deduped), sourceLength);
+    setCompressedSource<Unit>(std::move(*deduped), sourceLength);
     return true;
 }
 
 bool
 ScriptSource::setSourceCopy(JSContext* cx, SourceBufferHolder& srcBuf)
 {
     MOZ_ASSERT(!hasSourceText());
 
@@ -2146,33 +2146,33 @@ reallocUniquePtr(UniqueChars& unique, si
     }
 
     // Since the realloc succeeded, unique is now holding a freed pointer.
     mozilla::Unused << unique.release();
     unique.reset(newPtr);
     return true;
 }
 
-template<typename CharT>
+template<typename Unit>
 void
 SourceCompressionTask::workEncodingSpecific()
 {
     ScriptSource* source = sourceHolder_.get();
-    MOZ_ASSERT(source->data.is<ScriptSource::Uncompressed<CharT>>());
+    MOZ_ASSERT(source->data.is<ScriptSource::Uncompressed<Unit>>());
 
     // Try to keep the maximum memory usage down by only allocating half the
     // size of the string, first.
-    size_t inputBytes = source->length() * sizeof(CharT);
+    size_t inputBytes = source->length() * sizeof(Unit);
     size_t firstSize = inputBytes / 2;
     UniqueChars compressed(js_pod_malloc<char>(firstSize));
     if (!compressed) {
         return;
     }
 
-    const CharT* chars = source->data.as<ScriptSource::Uncompressed<CharT>>().chars();
+    const Unit* chars = source->data.as<ScriptSource::Uncompressed<Unit>>().units();
     Compressor comp(reinterpret_cast<const unsigned char*>(chars), inputBytes);
     if (!comp.init()) {
         return;
     }
 
     comp.setOutput(reinterpret_cast<unsigned char*>(compressed.get()), firstSize);
     bool cont = true;
     bool reallocated = false;
@@ -2228,19 +2228,19 @@ SourceCompressionTask::workEncodingSpeci
 struct SourceCompressionTask::PerformTaskWork
 {
     SourceCompressionTask* const task_;
 
     explicit PerformTaskWork(SourceCompressionTask* task)
       : task_(task)
     {}
 
-    template<typename CharT>
-    void match(const ScriptSource::Uncompressed<CharT>&) {
-        task_->workEncodingSpecific<CharT>();
+    template<typename Unit>
+    void match(const ScriptSource::Uncompressed<Unit>&) {
+        task_->workEncodingSpecific<Unit>();
     }
 
     template<typename T>
     void match (const T&) {
         MOZ_CRASH("why are we compressing missing, already-compressed, or "
                   "BinAST source?");
     }
 };
@@ -2360,41 +2360,41 @@ ScriptSource::xdrFinalizeEncoder(JS::Tra
     auto cleanup = mozilla::MakeScopeExit([&] {
         xdrEncoder_.reset(nullptr);
     });
 
     XDRResult res = xdrEncoder_->linearize(buffer);
     return res.isOk();
 }
 
-template<typename CharT>
+template<typename Unit>
 struct SourceDecoder
 {
     XDRState<XDR_DECODE>* const xdr_;
     ScriptSource* const scriptSource_;
     const uint32_t uncompressedLength_;
 
   public:
     SourceDecoder(XDRState<XDR_DECODE>* xdr, ScriptSource* scriptSource,
                   uint32_t uncompressedLength)
       : xdr_(xdr),
         scriptSource_(scriptSource),
         uncompressedLength_(uncompressedLength)
     {}
 
     XDRResult decode() {
-        auto sourceChars =
-            xdr_->cx()->make_pod_array<CharT>(Max<size_t>(uncompressedLength_, 1));
-        if (!sourceChars) {
+        auto sourceUnits =
+            xdr_->cx()->make_pod_array<Unit>(Max<size_t>(uncompressedLength_, 1));
+        if (!sourceUnits) {
             return xdr_->fail(JS::TranscodeResult_Throw);
         }
 
-        MOZ_TRY(xdr_->codeChars(sourceChars.get(), uncompressedLength_));
-
-        if (!scriptSource_->setSource(xdr_->cx(), std::move(sourceChars),
+        MOZ_TRY(xdr_->codeChars(sourceUnits.get(), uncompressedLength_));
+
+        if (!scriptSource_->setSource(xdr_->cx(), std::move(sourceUnits),
                                       uncompressedLength_))
         {
             return xdr_->fail(JS::TranscodeResult_Throw);
         }
 
         return Ok();
     }
 };
@@ -2415,33 +2415,33 @@ ScriptSource::xdrUncompressedSource<XDR_
     }
 
     SourceDecoder<char16_t> decoder(xdr, this, uncompressedLength);
     return decoder.decode();
 }
 
 } // namespace js
 
-template<typename CharT>
+template<typename Unit>
 struct SourceEncoder
 {
     XDRState<XDR_ENCODE>* const xdr_;
     ScriptSource* const source_;
     const uint32_t uncompressedLength_;
 
     SourceEncoder(XDRState<XDR_ENCODE>* xdr, ScriptSource* source, uint32_t uncompressedLength)
       : xdr_(xdr),
         source_(source),
         uncompressedLength_(uncompressedLength)
     {}
 
     XDRResult encode() {
-        CharT* sourceChars = const_cast<CharT*>(source_->uncompressedData<CharT>());
-
-        return xdr_->codeChars(sourceChars, uncompressedLength_);
+        Unit* sourceUnits = const_cast<Unit*>(source_->uncompressedData<Unit>());
+
+        return xdr_->codeChars(sourceUnits, uncompressedLength_);
     }
 };
 
 namespace js {
 
 template<>
 XDRResult
 ScriptSource::xdrUncompressedSource<XDR_ENCODE>(XDRState<XDR_ENCODE>* xdr,
@@ -2687,30 +2687,30 @@ ScriptSource::performXDR(XDRState<mode>*
         if (mode == XDR_DECODE &&
             hasSourceText() &&
             mozilla::recordreplay::IsRecordingOrReplaying())
         {
             UncompressedSourceCache::AutoHoldEntry holder;
 
             if (hasSourceType<Utf8Unit>()) {
                 // UTF-8 source text.
-                ScriptSource::PinnedChars<Utf8Unit> chars(xdr->cx(), this, holder, 0, length());
-                if (!chars.get()) {
+                ScriptSource::PinnedUnits<Utf8Unit> units(xdr->cx(), this, holder, 0, length());
+                if (!units.get()) {
                     return xdr->fail(JS::TranscodeResult_Throw);
                 }
                 mozilla::recordreplay::NoteContentParse8(this, filename(), "application/javascript",
-                                                         chars.get(), length());
+                                                         units.get(), length());
             } else {
                 // UTF-16 source text.
-                ScriptSource::PinnedChars<char16_t> chars(xdr->cx(), this, holder, 0, length());
-                if (!chars.get()) {
+                ScriptSource::PinnedUnits<char16_t> units(xdr->cx(), this, holder, 0, length());
+                if (!units.get()) {
                     return xdr->fail(JS::TranscodeResult_Throw);
                 }
                 mozilla::recordreplay::NoteContentParse16(this, filename(), "application/javascript",
-                                                          chars.get(), length());
+                                                          units.get(), length());
             }
         }
     }
 
     return Ok();
 }
 
 // Format and return a cx->pod_malloc'ed URL for a generated script like:
--- a/js/src/vm/JSScript.h
+++ b/js/src/vm/JSScript.h
@@ -327,32 +327,32 @@ struct ScriptSourceChunkHasher
     static HashNumber hash(const ScriptSourceChunk& ssc) {
         return mozilla::AddToHash(DefaultHasher<ScriptSource*>::hash(ssc.ss), ssc.chunk);
     }
     static bool match(const ScriptSourceChunk& c1, const ScriptSourceChunk& c2) {
         return c1 == c2;
     }
 };
 
-template<typename CharT>
-using EntryChars = mozilla::UniquePtr<CharT[], JS::FreePolicy>;
+template<typename Unit>
+using EntryUnits = mozilla::UniquePtr<Unit[], JS::FreePolicy>;
 
 // The uncompressed source cache contains *either* UTF-8 source data *or*
 // UTF-16 source data.  ScriptSourceChunk implies a ScriptSource that
 // contains either UTF-8 data or UTF-16 data, so the nature of the key to
 // Map below indicates how each SourceData ought to be interpreted.
 using SourceData = mozilla::UniquePtr<void, JS::FreePolicy>;
 
-template<typename CharT>
+template<typename Unit>
 inline SourceData
-ToSourceData(EntryChars<CharT> chars)
+ToSourceData(EntryUnits<Unit> chars)
 {
     static_assert(std::is_same<SourceData::DeleterType,
-                               typename EntryChars<CharT>::DeleterType>::value,
-                  "EntryChars and SourceData must share the same deleter "
+                               typename EntryUnits<Unit>::DeleterType>::value,
+                  "EntryUnits and SourceData must share the same deleter "
                   "type, that need not know the type of the data being freed, "
                   "for the upcast below to be safe");
     return SourceData(chars.release());
 }
 
 class UncompressedSourceCache
 {
     using Map = HashMap<ScriptSourceChunk,
@@ -373,23 +373,23 @@ class UncompressedSourceCache
 
         ~AutoHoldEntry() {
             if (cache_) {
                 MOZ_ASSERT(sourceChunk_.valid());
                 cache_->releaseEntry(*this);
             }
         }
 
-        template<typename CharT>
-        void holdChars(EntryChars<CharT> chars) {
+        template<typename Unit>
+        void holdUnits(EntryUnits<Unit> units) {
             MOZ_ASSERT(!cache_);
             MOZ_ASSERT(!sourceChunk_.valid());
             MOZ_ASSERT(!data_);
 
-            data_ = ToSourceData(std::move(chars));
+            data_ = ToSourceData(std::move(units));
         }
 
       private:
         void holdEntry(UncompressedSourceCache* cache, const ScriptSourceChunk& sourceChunk) {
             // Initialise the holder for a specific cache and script source.
             // This will hold on to the cached source chars in the event that
             // the cache is purged.
             MOZ_ASSERT(!cache_);
@@ -420,148 +420,154 @@ class UncompressedSourceCache
 
   private:
     UniquePtr<Map> map_ = nullptr;
     AutoHoldEntry* holder_ = nullptr;
 
   public:
     UncompressedSourceCache() = default;
 
-    template<typename CharT>
-    const CharT* lookup(const ScriptSourceChunk& ssc, AutoHoldEntry& asp);
+    template<typename Unit>
+    const Unit* lookup(const ScriptSourceChunk& ssc, AutoHoldEntry& asp);
 
     bool put(const ScriptSourceChunk& ssc, SourceData data, AutoHoldEntry& asp);
 
     void purge();
 
     size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf);
 
   private:
     void holdEntry(AutoHoldEntry& holder, const ScriptSourceChunk& ssc);
     void releaseEntry(AutoHoldEntry& holder);
 };
 
-template<typename CharT>
+template<typename Unit>
 struct SourceTypeTraits;
 
 template<>
 struct SourceTypeTraits<mozilla::Utf8Unit>
 {
+    using CharT = char;
     using SharedImmutableString = js::SharedImmutableString;
 
-    static const mozilla::Utf8Unit* chars(const SharedImmutableString& string) {
+    static const mozilla::Utf8Unit* units(const SharedImmutableString& string) {
         // Casting |char| data to |Utf8Unit| is safe because |Utf8Unit|
         // contains a |char|.  See the long comment in |Utf8Unit|'s definition.
         return reinterpret_cast<const mozilla::Utf8Unit*>(string.chars());
     }
 
     static char* toString(const mozilla::Utf8Unit* units) {
         auto asUnsigned = const_cast<unsigned char*>(mozilla::Utf8AsUnsignedChars(units));
         return reinterpret_cast<char*>(asUnsigned);
     }
 
-    static UniqueChars toCacheable(EntryChars<mozilla::Utf8Unit> str) {
+    static UniqueChars toCacheable(EntryUnits<mozilla::Utf8Unit> str) {
         // The cache only stores strings of |char| or |char16_t|, and right now
         // it seems best not to gunk up the cache with |Utf8Unit| too.  So
         // cache |Utf8Unit| strings by interpreting them as |char| strings.
         char* chars = toString(str.release());
         return UniqueChars(chars);
     }
 };
 
 template<>
 struct SourceTypeTraits<char16_t>
 {
+    using CharT = char16_t;
     using SharedImmutableString = js::SharedImmutableTwoByteString;
 
-    static const char16_t* chars(const SharedImmutableString& string) {
+    static const char16_t* units(const SharedImmutableString& string) {
         return string.chars();
     }
 
-    static char16_t* toString(char16_t* units) {
-        return units;
+    static char16_t* toString(const char16_t* units) {
+        return const_cast<char16_t*>(units);
     }
 
-    static UniqueTwoByteChars toCacheable(EntryChars<char16_t> str) {
+    static UniqueTwoByteChars toCacheable(EntryUnits<char16_t> str) {
         return UniqueTwoByteChars(std::move(str));
     }
 };
 
 class ScriptSource
 {
     friend class SourceCompressionTask;
 
-    class PinnedCharsBase
+    class PinnedUnitsBase
     {
       protected:
-        PinnedCharsBase** stack_ = nullptr;
-        PinnedCharsBase* prev_ = nullptr;
+        PinnedUnitsBase** stack_ = nullptr;
+        PinnedUnitsBase* prev_ = nullptr;
 
         ScriptSource* source_;
 
-        explicit PinnedCharsBase(ScriptSource* source)
+        explicit PinnedUnitsBase(ScriptSource* source)
           : source_(source)
         {}
     };
 
   public:
     // Any users that wish to manipulate the char buffer of the ScriptSource
-    // needs to do so via PinnedChars for GC safety. A GC may compress
+    // needs to do so via PinnedUnits for GC safety. A GC may compress
     // ScriptSources. If the source were initially uncompressed, then any raw
     // pointers to the char buffer would now point to the freed, uncompressed
     // chars. This is analogous to Rooted.
-    template<typename CharT>
-    class PinnedChars : public PinnedCharsBase
+    template<typename Unit>
+    class PinnedUnits : public PinnedUnitsBase
     {
-        const CharT* chars_;
+        const Unit* units_;
 
       public:
-        PinnedChars(JSContext* cx, ScriptSource* source,
+        PinnedUnits(JSContext* cx, ScriptSource* source,
                     UncompressedSourceCache::AutoHoldEntry& holder,
                     size_t begin, size_t len);
 
-        ~PinnedChars();
-
-        const CharT* get() const {
-            return chars_;
+        ~PinnedUnits();
+
+        const Unit* get() const {
+            return units_;
+        }
+
+        const typename SourceTypeTraits<Unit>::CharT* asChars() const {
+            return SourceTypeTraits<Unit>::toString(get());
         }
     };
 
   private:
     mozilla::Atomic<uint32_t, mozilla::ReleaseAcquire,
                     mozilla::recordreplay::Behavior::DontPreserve> refs;
 
     // Note: while ScriptSources may be compressed off thread, they are only
     // modified by the main thread, and all members are always safe to access
     // on the main thread.
 
     // Indicate which field in the |data| union is active.
     struct Missing { };
 
-    template<typename CharT>
+    template<typename Unit>
     class Uncompressed
     {
-        typename SourceTypeTraits<CharT>::SharedImmutableString string_;
+        typename SourceTypeTraits<Unit>::SharedImmutableString string_;
 
 
       public:
-        explicit Uncompressed(typename SourceTypeTraits<CharT>::SharedImmutableString str)
+        explicit Uncompressed(typename SourceTypeTraits<Unit>::SharedImmutableString str)
           : string_(std::move(str))
         {}
 
-        const CharT* chars() const {
-            return SourceTypeTraits<CharT>::chars(string_);
+        const Unit* units() const {
+            return SourceTypeTraits<Unit>::units(string_);
         }
 
         size_t length() const {
             return string_.length();
         }
     };
 
-    template<typename CharT>
+    template<typename Unit>
     struct Compressed
     {
         // Single-byte compressed text, regardless whether the original text
         // was single-byte or two-byte.
         SharedImmutableString raw;
         size_t uncompressedLength;
 
         Compressed(SharedImmutableString raw, size_t uncompressedLength)
@@ -580,20 +586,20 @@ class ScriptSource
 
     using SourceType =
         mozilla::Variant<Compressed<mozilla::Utf8Unit>, Uncompressed<mozilla::Utf8Unit>,
                          Compressed<char16_t>, Uncompressed<char16_t>,
                          Missing,
                          BinAST>;
     SourceType data;
 
-    // If the GC attempts to call setCompressedSource with PinnedChars
-    // present, the first PinnedChars (that is, bottom of the stack) will set
+    // If the GC attempts to call setCompressedSource with PinnedUnits
+    // present, the first PinnedUnits (that is, bottom of the stack) will set
     // the compressed chars upon destruction.
-    PinnedCharsBase* pinnedCharsStack_;
+    PinnedUnitsBase* pinnedUnitsStack_;
     mozilla::MaybeOneOf<Compressed<mozilla::Utf8Unit>, Compressed<char16_t>> pendingCompressed_;
 
     // The filename of this script.
     UniqueChars filename_;
 
     UniqueTwoByteChars displayURL_;
     UniqueTwoByteChars sourceMapURL_;
     bool mutedErrors_;
@@ -650,41 +656,41 @@ class ScriptSource
     // 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_;
 
-    template<typename CharT>
-    const CharT* chunkChars(JSContext* cx, UncompressedSourceCache::AutoHoldEntry& holder,
-                            size_t chunk);
+    template<typename Unit>
+    const Unit* chunkUnits(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.
-    template<typename CharT>
-    const CharT* chars(JSContext* cx, UncompressedSourceCache::AutoHoldEntry& asp,
-                       size_t begin, size_t len);
-
-    template<typename CharT>
+    // PinnedUnits. See comment below.
+    template<typename Unit>
+    const Unit* units(JSContext* cx, UncompressedSourceCache::AutoHoldEntry& asp,
+                      size_t begin, size_t len);
+
+    template<typename Unit>
     void movePendingCompressedSource();
 
   public:
     // When creating a JSString* from TwoByte source characters, we don't try to
     // to deflate to Latin1 for longer strings, because this can be slow.
     static const size_t SourceDeflateLimit = 100;
 
     explicit ScriptSource()
       : refs(0),
         data(SourceType(Missing())),
-        pinnedCharsStack_(nullptr),
+        pinnedUnitsStack_(nullptr),
         filename_(nullptr),
         displayURL_(nullptr),
         sourceMapURL_(nullptr),
         mutedErrors_(false),
         introductionOffset_(0),
         parameterListEnd_(0),
         introducerFilename_(nullptr),
         introductionType_(nullptr),
@@ -722,53 +728,53 @@ class ScriptSource
     frontend::BinASTSourceMetadata* binASTSourceMetadata() const {
         MOZ_ASSERT(hasBinASTSource());
         return binASTMetadata_.get();
     }
 
   private:
     struct UncompressedDataMatcher
     {
-        template<typename CharT>
-        const void* match(const Uncompressed<CharT>& u) {
-            return u.chars();
+        template<typename Unit>
+        const void* match(const Uncompressed<Unit>& u) {
+            return u.units();
         }
 
         template<typename T>
         const void* match(const T&) {
             MOZ_CRASH("attempting to access uncompressed data in a "
                       "ScriptSource not containing it");
             return nullptr;
         }
     };
 
   public:
-    template<typename CharT>
-    const CharT* uncompressedData() {
-        return static_cast<const CharT*>(data.match(UncompressedDataMatcher()));
+    template<typename Unit>
+    const Unit* uncompressedData() {
+        return static_cast<const Unit*>(data.match(UncompressedDataMatcher()));
     }
 
   private:
     struct CompressedDataMatcher
     {
-        template<typename CharT>
-        char* match(const Compressed<CharT>& c) {
+        template<typename Unit>
+        char* match(const Compressed<Unit>& c) {
             return const_cast<char*>(c.raw.chars());
         }
 
         template<typename T>
         char* match(const T&) {
             MOZ_CRASH("attempting to access compressed data in a ScriptSource "
                       "not containing it");
             return nullptr;
         }
     };
 
   public:
-    template<typename CharT>
+    template<typename Unit>
     char* compressedData() {
         return data.match(CompressedDataMatcher());
     }
 
   private:
     struct BinASTDataMatcher
     {
         void* match(const BinAST& b) {
@@ -789,103 +795,103 @@ class ScriptSource
   public:
     void* binASTData() {
         return data.match(BinASTDataMatcher());
     }
 
   private:
     struct HasUncompressedSource
     {
-        template<typename CharT>
-        bool match(const Uncompressed<CharT>&) { return true; }
-
-        template<typename CharT>
-        bool match(const Compressed<CharT>&) { return false; }
+        template<typename Unit>
+        bool match(const Uncompressed<Unit>&) { return true; }
+
+        template<typename Unit>
+        bool match(const Compressed<Unit>&) { return false; }
 
         bool match(const BinAST&) { return false; }
 
         bool match(const Missing&) { return false; }
     };
 
   public:
     bool hasUncompressedSource() const {
         return data.match(HasUncompressedSource());
     }
 
-    template<typename CharT>
+    template<typename Unit>
     bool uncompressedSourceIs() const {
         MOZ_ASSERT(hasUncompressedSource());
-        return data.is<Uncompressed<CharT>>();
+        return data.is<Uncompressed<Unit>>();
     }
 
   private:
     struct HasCompressedSource
     {
-        template<typename CharT>
-        bool match(const Compressed<CharT>&) { return true; }
-
-        template<typename CharT>
-        bool match(const Uncompressed<CharT>&) { return false; }
+        template<typename Unit>
+        bool match(const Compressed<Unit>&) { return true; }
+
+        template<typename Unit>
+        bool match(const Uncompressed<Unit>&) { return false; }
 
         bool match(const BinAST&) { return false; }
 
         bool match(const Missing&) { return false; }
     };
 
   public:
     bool hasCompressedSource() const {
         return data.match(HasCompressedSource());
     }
 
-    template<typename CharT>
+    template<typename Unit>
     bool compressedSourceIs() const {
         MOZ_ASSERT(hasCompressedSource());
-        return data.is<Compressed<CharT>>();
+        return data.is<Compressed<Unit>>();
     }
 
   private:
-    template<typename CharT>
+    template<typename Unit>
     struct SourceTypeMatcher
     {
         template<template<typename C> class Data>
-        bool match(const Data<CharT>&) {
+        bool match(const Data<Unit>&) {
             return true;
         }
 
-        template<template<typename C> class Data, typename NotCharT>
-        bool match(const Data<NotCharT>&) {
+        template<template<typename C> class Data, typename NotUnit>
+        bool match(const Data<NotUnit>&) {
             return false;
         }
 
         bool match(const BinAST&) {
             MOZ_CRASH("doesn't make sense to ask source type of BinAST data");
             return false;
         }
 
         bool match(const Missing&) {
             MOZ_CRASH("doesn't make sense to ask source type when missing");
             return false;
         }
     };
 
   public:
-    template<typename CharT>
+    template<typename Unit>
     bool hasSourceType() const {
-        return data.match(SourceTypeMatcher<CharT>());
+        return data.match(SourceTypeMatcher<Unit>());
     }
 
   private:
     struct SourceCharSizeMatcher
     {
-        template<template<typename C> class Data, typename CharT>
-        uint8_t match(const Data<CharT>& data) {
-            static_assert(std::is_same<CharT, mozilla::Utf8Unit>::value ||
-                          std::is_same<CharT, char16_t>::value,
+        template<template<typename C> class Data, typename Unit>
+        uint8_t match(const Data<Unit>& data) {
+            static_assert(std::is_same<Unit, mozilla::Utf8Unit>::value ||
+                          std::is_same<Unit, char16_t>::value,
                           "should only have UTF-8 or UTF-16 source char");
-            return sizeof(CharT);
+            return sizeof(Unit);
         }
 
         uint8_t match(const BinAST&) {
             MOZ_CRASH("BinAST source has no source-char size");
             return 0;
         }
 
         uint8_t match(const Missing&) {
@@ -897,23 +903,23 @@ class ScriptSource
   public:
     uint8_t sourceCharSize() const {
         return data.match(SourceCharSizeMatcher());
     }
 
   private:
     struct UncompressedLengthMatcher
     {
-        template<typename CharT>
-        size_t match(const Uncompressed<CharT>& u) {
+        template<typename Unit>
+        size_t match(const Uncompressed<Unit>& u) {
             return u.length();
         }
 
-        template<typename CharT>
-        size_t match(const Compressed<CharT>& u) {
+        template<typename Unit>
+        size_t match(const Compressed<Unit>& u) {
             return u.uncompressedLength;
         }
 
         size_t match(const BinAST& b) {
             return b.string.length();
         }
 
         size_t match(const Missing& m) {
@@ -926,23 +932,23 @@ class ScriptSource
     size_t length() const {
         MOZ_ASSERT(hasSourceText() || hasBinASTSource());
         return data.match(UncompressedLengthMatcher());
     }
 
   private:
     struct CompressedLengthOrZeroMatcher
     {
-        template<typename CharT>
-        size_t match(const Uncompressed<CharT>&) {
+        template<typename Unit>
+        size_t match(const Uncompressed<Unit>&) {
             return 0;
         }
 
-        template<typename CharT>
-        size_t match(const Compressed<CharT>& c) {
+        template<typename Unit>
+        size_t match(const Compressed<Unit>& c) {
             return c.raw.length();
         }
 
         size_t match(const BinAST&) {
             MOZ_CRASH("trying to get compressed length for BinAST data");
             return 0;
         }
 
@@ -965,32 +971,32 @@ class ScriptSource
     bool isFunctionBody() {
         return parameterListEnd_ != 0;
     }
     JSFlatString* functionBodyString(JSContext* cx);
 
     void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
                                 JS::ScriptSourceInfo* info) const;
 
-    template<typename CharT>
+    template<typename Unit>
     MOZ_MUST_USE bool setSource(JSContext* cx,
-                                EntryChars<CharT>&& source,
+                                EntryUnits<Unit>&& source,
                                 size_t length);
 
-    template<typename CharT>
-    void setSource(typename SourceTypeTraits<CharT>::SharedImmutableString uncompressed);
+    template<typename Unit>
+    void setSource(typename SourceTypeTraits<Unit>::SharedImmutableString uncompressed);
 
     MOZ_MUST_USE bool tryCompressOffThread(JSContext* cx);
 
-    // The CharT parameter determines which type of compressed source is
+    // The Unit parameter determines which type of compressed source is
     // recorded, but raw compressed source is always single-byte.
-    template<typename CharT>
+    template<typename Unit>
     void setCompressedSource(SharedImmutableString compressed, size_t sourceLength);
 
-    template<typename CharT>
+    template<typename Unit>
     MOZ_MUST_USE bool setCompressedSource(JSContext* cx, UniqueChars&& raw, size_t rawLength,
                                           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
@@ -1016,23 +1022,23 @@ class ScriptSource
         ScriptSource* const source_;
         SharedImmutableString& compressed_;
 
         SetCompressedSourceFromTask(ScriptSource* source, SharedImmutableString& compressed)
           : source_(source),
             compressed_(compressed)
         {}
 
-        template<typename CharT>
-        void match(const Uncompressed<CharT>&) {
-            source_->setCompressedSource<CharT>(std::move(compressed_), source_->length());
+        template<typename Unit>
+        void match(const Uncompressed<Unit>&) {
+            source_->setCompressedSource<Unit>(std::move(compressed_), source_->length());
         }
 
-        template<typename CharT>
-        void match(const Compressed<CharT>&) {
+        template<typename Unit>
+        void match(const Compressed<Unit>&) {
             MOZ_CRASH("can't set compressed source when source is already "
                       "compressed -- ScriptSource::tryCompressOffThread "
                       "shouldn't have queued up this task?");
         }
 
         void match(const BinAST&) {
             MOZ_CRASH("doesn't make sense to set compressed source for BinAST "
                       "data");
@@ -1048,21 +1054,21 @@ class ScriptSource
     void setCompressedSourceFromTask(SharedImmutableString compressed);
 
   public:
     // XDR handling
     template <XDRMode mode>
     MOZ_MUST_USE XDRResult performXDR(XDRState<mode>* xdr);
 
   private:
-    // It'd be better to make this function take <XDRMode, CharT>, as both
-    // specializations of this function contain nested CharT-parametrized
+    // It'd be better to make this function take <XDRMode, Unit>, as both
+    // specializations of this function contain nested Unit-parametrized
     // helper classes that do everything the function needs to do.  But then
     // we'd need template function partial specialization to hold XDRMode
-    // constant while varying CharT, so that idea's no dice.
+    // constant while varying Unit, so that idea's no dice.
     template <XDRMode mode>
     MOZ_MUST_USE XDRResult xdrUncompressedSource(XDRState<mode>* xdr, uint8_t sourceCharSize,
                                                  uint32_t uncompressedLength);
 
   public:
     MOZ_MUST_USE bool setFilename(JSContext* cx, const char* filename);
     const char* introducerFilename() const {
         return introducerFilename_ ? introducerFilename_.get() : filename_.get();
--- a/modules/libpref/init/StaticPrefList.h
+++ b/modules/libpref/init/StaticPrefList.h
@@ -218,17 +218,17 @@ VARCACHE_PREF(
 )
 
 // If true. then the service worker interception and the ServiceWorkerManager
 // will live in the parent process.  This only takes effect on browser start.
 // Note, this is not currently safe to use for normal browsing yet.
 PREF("dom.serviceWorkers.parent_intercept", bool, false)
 
 // Enable PaymentRequest API
-#ifdef NIGHTLY_BUILD
+#if defined(NIGHTLY_BUILD) && (defined(XP_WIN) || defined(XP_MACOSX))
 # define PREF_VALUE  true
 #else
 # define PREF_VALUE  false
 #endif
 VARCACHE_PREF(
   "dom.payments.request.enabled",
    dom_payments_request_enabled,
   bool, PREF_VALUE
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -5842,18 +5842,17 @@ pref("dom.IntersectionObserver.enabled",
 
 // Whether module scripts (<script type="module">) are enabled for content.
 pref("dom.moduleScripts.enabled", true);
 
 // Maximum amount of time in milliseconds consecutive setTimeout()/setInterval()
 // callback are allowed to run before yielding the event loop.
 pref("dom.timeout.max_consecutive_callbacks_ms", 4);
 
-// Use this preference to house "Payment Request API" during development
-pref("dom.payments.request.enabled", false);
+// Payment Request API preferences
 pref("dom.payments.loglevel", "Warn");
 pref("dom.payments.defaults.saveCreditCard", false);
 pref("dom.payments.defaults.saveAddress", true);
 
 #ifdef MOZ_ASAN_REPORTER
 pref("asanreporter.apiurl", "https://anf1.fuzzing.mozilla.org/crashproxy/submit/");
 pref("asanreporter.clientid", "unknown");
 pref("toolkit.telemetry.overrideUpdateChannel", "nightly-asan");
--- a/security/nss/TAG-INFO
+++ b/security/nss/TAG-INFO
@@ -1,1 +1,1 @@
-dc4500650617
+704d253fa016
--- a/security/nss/automation/taskcluster/graph/src/extend.js
+++ b/security/nss/automation/taskcluster/graph/src/extend.js
@@ -147,23 +147,23 @@ queue.map(task => {
 });
 
 /*****************************************************************************/
 
 export default async function main() {
   await scheduleLinux("Linux 32 (opt)", {
     platform: "linux32",
     image: LINUX_IMAGE
-  }, "-m32 --opt");
+  }, "-t ia32 --opt");
 
   await scheduleLinux("Linux 32 (debug)", {
     platform: "linux32",
     collection: "debug",
     image: LINUX_IMAGE
-  }, "-m32");
+  }, "-t ia32");
 
   await scheduleLinux("Linux 64 (opt)", {
     platform: "linux64",
     image: LINUX_IMAGE
   }, "--opt");
 
   await scheduleLinux("Linux 64 (debug)", {
     platform: "linux64",
@@ -243,22 +243,22 @@ export default async function main() {
 
   await scheduleWindows("Windows 2012 64 (debug)", {
     platform: "windows2012-64",
     collection: "debug"
   }, "build_gyp.sh");
 
   await scheduleWindows("Windows 2012 32 (opt)", {
     platform: "windows2012-32",
-  }, "build_gyp.sh --opt -m32");
+  }, "build_gyp.sh --opt -t ia32");
 
   await scheduleWindows("Windows 2012 32 (debug)", {
     platform: "windows2012-32",
     collection: "debug"
-  }, "build_gyp.sh -m32");
+  }, "build_gyp.sh -t ia32");
 
   await scheduleFuzzing();
   await scheduleFuzzing32();
 
   await scheduleTools();
 
   let aarch64_base = {
     image: "franziskus/nss-aarch64-ci",
@@ -674,17 +674,17 @@ async function scheduleFuzzing32() {
   };
 
   // Build base definition.
   let build_base = merge(base, {
     command: [
       "/bin/bash",
       "-c",
       "bin/checkout.sh && " +
-      "nss/automation/taskcluster/scripts/build_gyp.sh -g -v --fuzz -m32"
+      "nss/automation/taskcluster/scripts/build_gyp.sh -g -v --fuzz -t ia32"
     ],
     artifacts: {
       public: {
         expires: 24 * 7,
         type: "directory",
         path: "/home/worker/artifacts"
       }
     },
@@ -701,17 +701,17 @@ async function scheduleFuzzing32() {
   let task_build_tls = queue.scheduleTask(merge(build_base, {
     name: "Linux 32 (debug, TLS fuzz)",
     symbol: "B",
     group: "TLS",
     command: [
       "/bin/bash",
       "-c",
       "bin/checkout.sh && " +
-      "nss/automation/taskcluster/scripts/build_gyp.sh -g -v --fuzz=tls -m32"
+      "nss/automation/taskcluster/scripts/build_gyp.sh -g -v --fuzz=tls -t ia32"
     ],
   }));
 
   // Schedule tests.
   queue.scheduleTask(merge(base, {
     parent: task_build_tls,
     name: "Gtests",
     command: [
@@ -1100,17 +1100,17 @@ async function scheduleTools() {
         expires: 24 * 7,
         type: "directory",
         path: "/home/worker/artifacts"
       }
     },
     command: [
       "/bin/bash",
       "-c",
-      "bin/checkout.sh && nss/automation/taskcluster/scripts/build_gyp.sh --disable-tests --emit-llvm -m32"
+      "bin/checkout.sh && nss/automation/taskcluster/scripts/build_gyp.sh --disable-tests --emit-llvm -t ia32"
     ]
   }));
 
   queue.scheduleTask(merge(base, {
     parent: task_saw,
     symbol: "bmul",
     group: "SAW",
     name: "bmul.saw",
--- a/security/nss/automation/taskcluster/windows/build.sh
+++ b/security/nss/automation/taskcluster/windows/build.sh
@@ -1,18 +1,18 @@
 #!/usr/bin/env bash
 
 set -v -e -x
 
-# Set up the toolchain.
-if [ "$USE_64" = 1 ]; then
-  source $(dirname $0)/setup64.sh
+if [[ "$USE_64" == 1 ]]; then
+    m=x64
 else
-  source $(dirname $0)/setup32.sh
+    m=x86
 fi
+source "$(dirname "$0")/setup.sh"
 
 # Clone NSPR.
 hg_clone https://hg.mozilla.org/projects/nspr nspr default
 
 # Build.
 make -C nss nss_build_all
 
 # Package.
--- a/security/nss/automation/taskcluster/windows/build_gyp.sh
+++ b/security/nss/automation/taskcluster/windows/build_gyp.sh
@@ -1,34 +1,38 @@
 #!/usr/bin/env bash
 
 set -v -e -x
 
-# Set up the toolchain.
-if [[ "$@" == *"-m32"* ]]; then
-  source $(dirname $0)/setup32.sh
-else
-  source $(dirname $0)/setup64.sh
-fi
+# Parse for the -t option.
+m=x64
+for i in "$@"; do
+    case "$i" in
+        -t|--target) m= ;;
+        --target=*) m="${i#*=}" ;;
+        *) [[ -z "$m" ]] && m="$i" ;;
+    esac
+done
+[[ "$m" == "ia32" ]] && m=x86
+source "$(dirname "$0")/setup.sh"
 
 # Install GYP.
-cd gyp
+pushd gyp
 python -m virtualenv test-env
 test-env/Scripts/python setup.py install
 test-env/Scripts/python -m pip install --upgrade pip
 test-env/Scripts/pip install --upgrade setuptools
-cd ..
-
-export GYP_MSVS_OVERRIDE_PATH="${VSPATH}"
-export GYP_MSVS_VERSION="2015"
-export GYP="${PWD}/gyp/test-env/Scripts/gyp"
-
 # Fool GYP.
 touch "${VSPATH}/VC/vcvarsall.bat"
+export GYP_MSVS_OVERRIDE_PATH="${VSPATH}"
+export GYP_MSVS_VERSION=2015
+popd
+
+export PATH="${PATH}:${PWD}/ninja/bin:${PWD}/gyp/test-env/Scripts"
 
 # Clone NSPR.
 hg_clone https://hg.mozilla.org/projects/nspr nspr default
 
 # Build with gyp.
-GYP=${GYP} ./nss/build.sh -g -v "$@"
+./nss/build.sh -g -v "$@"
 
 # Package.
 7z a public/build/dist.7z dist
--- a/security/nss/automation/taskcluster/windows/setup.sh
+++ b/security/nss/automation/taskcluster/windows/setup.sh
@@ -1,26 +1,56 @@
 #!/usr/bin/env bash
 
 set -v -e -x
 
-export VSPATH="$(pwd)/vs2017_15.4.2"
-export NINJA_PATH="$(pwd)/ninja/bin"
-
-export WINDOWSSDKDIR="${VSPATH}/SDK"
-export VS90COMNTOOLS="${VSPATH}/VC"
-export INCLUDE="${VSPATH}/VC/include:${VSPATH}/SDK/Include/10.0.15063.0/ucrt:${VSPATH}/SDK/Include/10.0.15063.0/shared:${VSPATH}/SDK/Include/10.0.15063.0/um"
-
 # Usage: hg_clone repo dir [revision=@]
 hg_clone() {
     repo=$1
     dir=$2
     rev=${3:-@}
     for i in 0 2 5; do
         sleep $i
         hg clone -r "$rev" "$repo" "$dir" && return
         rm -rf "$dir"
     done
     exit 1
 }
 
-hg_clone https://hg.mozilla.org/build/tools tools default
-tools/scripts/tooltool/tooltool_wrapper.sh $(dirname $0)/releng.manifest https://tooltool.mozilla-releng.net/ non-existant-file.sh /c/mozilla-build/python/python.exe /c/builds/tooltool.py --authentication-file /c/builds/relengapi.tok -c /c/builds/tooltool_cache
+hg_clone https://hg.mozilla.org/build/tools tools b8d7c263dfc3
+tools/scripts/tooltool/tooltool_wrapper.sh \
+    $(dirname $0)/releng.manifest https://tooltool.mozilla-releng.net/ \
+    non-existant-file.sh /c/mozilla-build/python/python.exe \
+    /c/builds/tooltool.py --authentication-file /c/builds/relengapi.tok \
+    -c /c/builds/tooltool_cache
+
+# This needs $m to be set.
+[[ -n "$m" ]]
+
+# Setup MSVC paths.
+export VSPATH="${PWD}/vs2017_15.4.2"
+UCRTVersion="10.0.15063.0"
+
+export WINDOWSSDKDIR="${VSPATH}/SDK"
+export VS90COMNTOOLS="${VSPATH}/VC"
+export WIN32_REDIST_DIR="${VSPATH}/VC/redist/${m}/Microsoft.VC141.CRT"
+export WIN_UCRT_REDIST_DIR="${VSPATH}/SDK/Redist/ucrt/DLLs/${m}"
+
+if [ "$m" == "x86" ]; then
+    PATH="${PATH}:${VSPATH}/VC/bin/Hostx64/x86"
+    PATH="${PATH}:${VSPATH}/VC/bin/Hostx64/x64"
+fi
+PATH="${PATH}:${VSPATH}/VC/bin/Host${m}/${m}"
+PATH="${PATH}:${WIN32_REDIST_DIR}"
+PATH="${PATH}:${WIN_UCRT_REDIST_DIR}"
+PATH="${PATH}:${VSPATH}/SDK/bin/${UCRTVersion}/x64"
+export PATH
+
+LIB="${LIB}:${VSPATH}/VC/lib/${m}"
+LIB="${LIB}:${VSPATH}/SDK/lib/${UCRTVersion}/ucrt/${m}"
+LIB="${LIB}:${VSPATH}/SDK/lib/${UCRTVersion}/um/${m}"
+export LIB
+
+INCLUDE="${INCLUDE}:${VSPATH}/VC/include"
+INCLUDE="${INCLUDE}:${VSPATH}/SDK/Include/${UCRTVersion}/ucrt"
+INCLUDE="${INCLUDE}:${VSPATH}/SDK/Include/${UCRTVersion}/shared"
+INCLUDE="${INCLUDE}:${VSPATH}/SDK/Include/${UCRTVersion}/um"
+export INCLUDE
deleted file mode 100644
--- a/security/nss/automation/taskcluster/windows/setup32.sh
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/usr/bin/env bash
-
-set -v -e -x
-
-source $(dirname $0)/setup.sh
-
-export WIN32_REDIST_DIR="${VSPATH}/VC/redist/x86/Microsoft.VC141.CRT"
-export WIN_UCRT_REDIST_DIR="${VSPATH}/SDK/Redist/ucrt/DLLs/x86"
-export PATH="${NINJA_PATH}:${VSPATH}/VC/bin/Hostx64/x86:${VSPATH}/VC/bin/Hostx64/x64:${VSPATH}/VC/Hostx86/x86:${VSPATH}/SDK/bin/10.0.15063.0/x64:${VSPATH}/VC/redist/x86/Microsoft.VC141.CRT:${VSPATH}/SDK/Redist/ucrt/DLLs/x86:${PATH}"
-export LIB="${VSPATH}/VC/lib/x86:${VSPATH}/SDK/lib/10.0.15063.0/ucrt/x86:${VSPATH}/SDK/lib/10.0.15063.0/um/x86"
deleted file mode 100644
--- a/security/nss/automation/taskcluster/windows/setup64.sh
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/usr/bin/env bash
-
-set -v -e -x
-
-source $(dirname $0)/setup.sh
-
-export WIN32_REDIST_DIR="${VSPATH}/VC/redist/x64/Microsoft.VC141.CRT"
-export WIN_UCRT_REDIST_DIR="${VSPATH}/SDK/Redist/ucrt/DLLs/x64"
-export PATH="${NINJA_PATH}:${VSPATH}/VC/bin/Hostx64/x64:${VSPATH}/VC/bin/Hostx86/x86:${VSPATH}/SDK/bin/10.0.15063.0/x64:${VSPATH}/VC/redist/x64/Microsoft.VC141.CRT:${VSPATH}/SDK/Redist/ucrt/DLLs/x64:${PATH}"
-export LIB="${VSPATH}/VC/lib/x64:${VSPATH}/SDK/lib/10.0.15063.0/ucrt/x64:${VSPATH}/SDK/lib/10.0.15063.0/um/x64"
--- a/security/nss/build.sh
+++ b/security/nss/build.sh
@@ -45,86 +45,96 @@ clean=0
 rebuild_gyp=0
 rebuild_nspr=0
 target=Debug
 verbose=0
 fuzz=0
 fuzz_tls=0
 fuzz_oss=0
 no_local_nspr=0
-armhf=0
 
 gyp_params=(--depth="$cwd" --generator-output=".")
-nspr_params=()
 ninja_params=()
 
-# try to guess sensible defaults
-arch=$(python "$cwd"/coreconf/detect_host_arch.py)
-if [ "$arch" = "x64" -o "$arch" = "aarch64" ]; then
-    build_64=1
-elif [ "$arch" = "arm" ]; then
-    armhf=1
+# Assume that the target architecture is the same as the host by default.
+host_arch=$(python "$cwd"/coreconf/detect_host_arch.py)
+target_arch=$host_arch
+
+# Assume that MSVC is wanted if this is running on windows.
+platform=$(uname -s)
+if [ "${platform%-*}" = "MINGW32_NT" -o "${platform%-*}" = "MINGW64_NT" ]; then
+    msvc=1
 fi
 
-# parse command line arguments
+# Parse command line arguments.
 while [ $# -gt 0 ]; do
-    case $1 in
+    case "$1" in
         -c) clean=1 ;;
         -cc) clean_only=1 ;;
-        --gyp|-g) rebuild_gyp=1 ;;
-        --nspr) nspr_clean; rebuild_nspr=1 ;;
+        -v) ninja_params+=(-v); verbose=1 ;;
         -j) ninja_params+=(-j "$2"); shift ;;
-        -v) ninja_params+=(-v); verbose=1 ;;
-        --test) gyp_params+=(-Dtest_build=1) ;;
-        --clang) export CC=clang; export CCC=clang++; export CXX=clang++ ;;
-        --gcc) export CC=gcc; export CCC=g++; export CXX=g++ ;;
-        --fuzz) fuzz=1 ;;
-        --fuzz=oss) fuzz=1; fuzz_oss=1 ;;
-        --fuzz=tls) fuzz=1; fuzz_tls=1 ;;
+        --gyp|-g) rebuild_gyp=1 ;;
+        --opt|-o) opt_build=1 ;;
+        -m32|--m32) target_arch=ia32; echo 'Warning: use -t instead of -m32' 1>&2 ;;
+        -t|--target) target_arch="$2"; shift ;;
+        --target=*) target_arch="${1#*=}" ;;
+        --clang) export CC=clang; export CCC=clang++; export CXX=clang++; msvc=0 ;;
+        --gcc) export CC=gcc; export CCC=g++; export CXX=g++; msvc=0 ;;
+        --msvc) msvc=1 ;;
         --scan-build) enable_scanbuild  ;;
         --scan-build=?*) enable_scanbuild "${1#*=}" ;;
-        --opt|-o) opt_build=1 ;;
-        -m32|--m32) build_64=0 ;;
+        --disable-tests) gyp_params+=(-Ddisable_tests=1) ;;
+        --pprof) gyp_params+=(-Duse_pprof=1) ;;
         --asan) enable_sanitizer asan ;;
         --msan) enable_sanitizer msan ;;
         --ubsan) enable_ubsan ;;
         --ubsan=?*) enable_ubsan "${1#*=}" ;;
+        --fuzz) fuzz=1 ;;
+        --fuzz=oss) fuzz=1; fuzz_oss=1 ;;
+        --fuzz=tls) fuzz=1; fuzz_tls=1 ;;
         --sancov) enable_sancov ;;
         --sancov=?*) enable_sancov "${1#*=}" ;;
-        --pprof) gyp_params+=(-Duse_pprof=1) ;;
+        --emit-llvm) gyp_params+=(-Demit_llvm=1 -Dsign_libs=0) ;;
+        --no-zdefs) gyp_params+=(-Dno_zdefs=1) ;;
+        --test) gyp_params+=(-Dtest_build=1) ;;
         --ct-verif) gyp_params+=(-Dct_verif=1) ;;
-        --emit-llvm) gyp_params+=(-Demit_llvm=1 -Dsign_libs=0) ;;
-        --disable-tests) gyp_params+=(-Ddisable_tests=1) ;;
-        --no-zdefs) gyp_params+=(-Dno_zdefs=1) ;;
-        --system-sqlite) gyp_params+=(-Duse_system_sqlite=1) ;;
+        --nspr) nspr_clean; rebuild_nspr=1 ;;
         --with-nspr=?*) set_nspr_path "${1#*=}"; no_local_nspr=1 ;;
         --system-nspr) set_nspr_path "/usr/include/nspr/:"; no_local_nspr=1 ;;
+        --system-sqlite) gyp_params+=(-Duse_system_sqlite=1) ;;
+        --enable-fips) gyp_params+=(-Ddisable_fips=0) ;;
         --enable-libpkix) gyp_params+=(-Ddisable_libpkix=0) ;;
-        --enable-fips) gyp_params+=(-Ddisable_fips=0) ;;
         --mozpkix-only) gyp_params+=(-Dmozpkix_only=1 -Ddisable_tests=1 -Dsign_libs=0) ;;
         *) show_help; exit 2 ;;
     esac
     shift
 done
 
+# Set the target architecture and build type.
+gyp_params+=(-Dtarget_arch="$target_arch")
 if [ "$opt_build" = 1 ]; then
     target=Release
 else
     target=Debug
 fi
-if [ "$build_64" = 1 ]; then
-    nspr_params+=(--enable-64bit)
-elif [ ! "$armhf" = 1 ]; then
-    gyp_params+=(-Dtarget_arch=ia32)
-fi
+
+# Do special setup.
 if [ "$fuzz" = 1 ]; then
     source "$cwd"/coreconf/fuzz.sh
 fi
+nspr_set_flags $sanitizer_flags
+if [ ! -z "$sanitizer_flags" ]; then
+    gyp_params+=(-Dsanitizer_flags="$sanitizer_flags")
+fi
 
-# set paths
+if [ "$msvc" = 1 ]; then
+    source "$cwd"/coreconf/msvc.sh
+fi
+
+# Setup build paths.
 target_dir="$cwd"/out/$target
 mkdir -p "$target_dir"
 dist_dir="$cwd"/../dist
 dist_dir=$(mkdir -p "$dist_dir"; cd "$dist_dir"; pwd -P)
 gyp_params+=(-Dnss_dist_dir="$dist_dir")
 
 # -c = clean first
 if [ "$clean" = 1 -o "$clean_only" = 1 ]; then
@@ -145,61 +155,58 @@ fi
 check_config()
 {
     local newconf="$1".new oldconf="$1"
     shift
     mkdir -p $(dirname "$newconf")
     echo CC="$CC" >"$newconf"
     echo CCC="$CCC" >>"$newconf"
     echo CXX="$CXX" >>"$newconf"
+    echo target_arch="$target_arch" >>"$newconf"
     for i in "$@"; do echo $i; done | sort >>"$newconf"
 
     # Note: The following diff fails if $oldconf isn't there as well, which
     # happens if we don't have a previous successful build.
     ! diff -q "$newconf" "$oldconf" >/dev/null 2>&1
 }
 
 gyp_config="$cwd"/out/gyp_config
 nspr_config="$cwd"/out/$target/nspr_config
 
+# Now check what needs to be rebuilt.
 # If we don't have a build directory make sure that we rebuild.
 if [ ! -d "$target_dir" ]; then
     rebuild_nspr=1
     rebuild_gyp=1
 elif [ ! -d "$dist_dir"/$target ]; then
     rebuild_nspr=1
 fi
 
-# Update NSPR ${C,CXX,LD}FLAGS.
-nspr_set_flags $sanitizer_flags
-
-if check_config "$nspr_config" "${nspr_params[@]}" \
+if check_config "$nspr_config" \
                  nspr_cflags="$nspr_cflags" \
                  nspr_cxxflags="$nspr_cxxflags" \
                  nspr_ldflags="$nspr_ldflags"; then
     rebuild_nspr=1
 fi
 
-# Forward sanitizer flags.
-if [ ! -z "$sanitizer_flags" ]; then
-    gyp_params+=(-Dsanitizer_flags="$sanitizer_flags")
-fi
-
 if check_config "$gyp_config" "${gyp_params[@]}"; then
     rebuild_gyp=1
 fi
 
-# save the chosen target
+# Save the chosen target.
 mkdir -p "$dist_dir"
 echo $target > "$dist_dir"/latest
 
+# Build.
+# NSPR.
 if [[ "$rebuild_nspr" = 1 && "$no_local_nspr" = 0 ]]; then
-    nspr_build "${nspr_params[@]}"
+    nspr_build
     mv -f "$nspr_config".new "$nspr_config"
 fi
+# gyp.
 if [ "$rebuild_gyp" = 1 ]; then
     if ! hash ${GYP} 2> /dev/null; then
         echo "Please install gyp" 1>&2
         exit 1
     fi
     # These extra arguments aren't used in determining whether to rebuild.
     obj_dir="$dist_dir"/$target
     gyp_params+=(-Dnss_dist_obj_dir=$obj_dir)
@@ -207,18 +214,18 @@ if [ "$rebuild_gyp" = 1 ]; then
         set_nspr_path "$obj_dir/include/nspr:$obj_dir/lib"
     fi
 
     run_verbose run_scanbuild ${GYP} -f ninja "${gyp_params[@]}" "$cwd"/nss.gyp
 
     mv -f "$gyp_config".new "$gyp_config"
 fi
 
-# Run ninja.
-if hash ninja 2>/dev/null; then
+# ninja.
+if hash ninja-build 2>/dev/null; then
+    ninja=ninja-build
+elif hash ninja 2>/dev/null; then
     ninja=ninja
-elif hash ninja-build 2>/dev/null; then
-    ninja=ninja-build
 else
     echo "Please install ninja" 1>&2
     exit 1
 fi
 run_scanbuild $ninja -C "$target_dir" "${ninja_params[@]}"
--- a/security/nss/coreconf/coreconf.dep
+++ b/security/nss/coreconf/coreconf.dep
@@ -5,8 +5,9 @@
 
 /*
  * A dummy header file that is a dependency for all the object files.
  * Used to force a full recompilation of NSS in Mozilla's Tinderbox
  * depend builds.  See comments in rules.mk.
  */
 
 #error "Do not include this header file."
+
--- a/security/nss/coreconf/fuzz.sh
+++ b/security/nss/coreconf/fuzz.sh
@@ -1,17 +1,16 @@
 #!/usr/bin/env bash
 # This file is used by build.sh to setup fuzzing.
 
 set +e
 
 # Default to clang if CC is not set.
 if [ -z "$CC" ]; then
-    command -v clang &> /dev/null 2>&1
-    if [ $? != 0 ]; then
+    if ! command -v clang &> /dev/null 2>&1; then
         echo "Fuzzing requires clang!"
         exit 1
     fi
     export CC=clang
     export CCC=clang++
     export CXX=clang++
 fi
 
@@ -19,18 +18,18 @@ gyp_params+=(-Dtest_build=1 -Dfuzz=1 -Ds
 
 # Add debug symbols even for opt builds.
 nspr_params+=(--enable-debug-symbols)
 
 if [ "$fuzz_oss" = 1 ]; then
   gyp_params+=(-Dno_zdefs=1 -Dfuzz_oss=1)
 else
   enable_sanitizer asan
-  # Ubsan doesn't build on 32-bit at the moment. Disable it.
-  if [ "$build_64" = 1 ]; then
+  # Ubsan only builds on x64 for the moment.
+  if [ "$target_arch" = "x64" ]; then
     enable_ubsan
   fi
   enable_sancov
 fi
 
 if [ "$fuzz_tls" = 1 ]; then
   gyp_params+=(-Dfuzz_tls=1)
 fi
new file mode 100644
--- /dev/null
+++ b/security/nss/coreconf/msvc.sh
@@ -0,0 +1,106 @@
+#!/bin/bash
+# This configures the environment for running MSVC.  It uses vswhere, the
+# registry, and a little knowledge of how MSVC is laid out.
+
+if ! hash vswhere 2>/dev/null; then
+    echo "Can't find vswhere on the path, aborting" 1>&2
+    exit 1
+fi
+
+if ! hash reg 2>/dev/null; then
+    echo "Can't find reg on the path, aborting" 1>&2
+    exit 1
+fi
+
+# Turn a unix-y path into a windows one.
+fixpath() {
+    if hash cygpath 2>/dev/null; then
+        cygpath --unix "$1"
+    else # haxx
+        echo "$1" | sed -e 's,\\,/,g;s,^\(.\):,/\L\1,;s,/$,,'
+    fi
+}
+
+# Query the registry.  This takes $1 and tags that on the end of several
+# different paths, looking for a value called $2 at that location.
+# e.g.,
+#   regquery Microsoft\Microsoft SDKs\Windows\v10.0 ProductVersion
+# looks for a REG_SZ value called ProductVersion at
+#   HKLM\SOFTWARE\Wow6432Node\Microsoft\Microsoft SDKs\Windows\v10.0
+#   HKLU\SOFTWARE\Wow6432Node\Microsoft\Microsoft SDKs\Windows\v10.0
+#   etc...
+regquery() {
+    search=("HKLM\\SOFTWARE\\Wow6432Node" \
+            "HKCU\\SOFTWARE\\Wow6432Node" \
+            "HKLM\\SOFTWARE" \
+            "HKCU\\SOFTWARE")
+    for i in "${search[@]}"; do
+        r=$(reg query "${i}\\${1}" -v "$2" | sed -e 's/ *'"$2"' *REG_SZ *//;t;d')
+        if [ -n "$r" ]; then
+            echo "$r"
+            return 0
+        fi
+    done
+    return 1
+}
+
+VSCOMPONENT=Microsoft.VisualStudio.Component.VC.Tools.x86.x64
+vsinstall=$(vswhere -latest -requires "$VSCOMPONENT" -property installationPath)
+
+# Attempt to setup paths if vswhere returns something and VSPATH isn't set.
+# Otherwise, assume that the env is setup.
+if [[ -n "$vsinstall" && -z "$VSPATH" ]]; then
+
+    case "$target_arch" in
+        ia32) m=x86 ;;
+        x64) m="$target_arch" ;;
+        *)
+            echo "No support for target '$target_arch' with MSVC." 1>&2
+            exit 1
+    esac
+
+    export VSPATH=$(fixpath "$vsinstall")
+    export WINDOWSSDKDIR="${VSPATH}/SDK"
+    export VCINSTALLDIR="${VSPATH}/VC"
+
+    CRTREG="Microsoft\\Microsoft SDKs\\Windows\\v10.0"
+    UniversalCRTSdkDir=$(regquery "$CRTREG" InstallationFolder)
+    UniversalCRTSdkDir=$(fixpath "$UniversalCRTSdkDir")
+    UCRTVersion=$(regquery "$CRTREG" ProductVersion)
+    UCRTVersion=$(cd "${UniversalCRTSdkDir}/include"; ls -d "${UCRTVersion}"* | tail -1)
+
+    VCVER=$(cat "${VCINSTALLDIR}/Auxiliary/Build/Microsoft.VCToolsVersion.default.txt")
+    REDISTVER=$(cat "${VCINSTALLDIR}/Auxiliary/Build/Microsoft.VCRedistVersion.default.txt")
+    export WIN32_REDIST_DIR="${VCINSTALLDIR}/Redist/MSVC/${REDISTVER}/${m}/Microsoft.VC141.CRT"
+    export WIN_UCRT_REDIST_DIR="${UniversalCRTSdkDir}/Redist/ucrt/DLLs/${m}"
+
+    if [ "$m" == "x86" ]; then
+        PATH="${PATH}:${VCINSTALLDIR}/Tools/MSVC/${VCVER}/bin/Hostx64/x64"
+        PATH="${PATH}:${VCINSTALLDIR}/Tools/MSVC/${VCVER}/bin/Hostx64/x86"
+    fi
+    PATH="${PATH}:${VCINSTALLDIR}/Tools/MSVC/${VCVER}/bin/Host${m}/${m}"
+    PATH="${PATH}:${UniversalCRTSdkDir}/bin/${UCRTVersion}/${m}"
+    PATH="${PATH}:${WIN32_REDIST_DIR}"
+    export PATH
+
+    INCLUDE="${VCINSTALLDIR}/Tools/MSVC/${VCVER}/ATLMFC/include"
+    INCLUDE="${INCLUDE}:${VCINSTALLDIR}/Tools/MSVC/${VCVER}/include"
+    INCLUDE="${INCLUDE}:${UniversalCRTSdkDir}/include/${UCRTVersion}/ucrt"
+    INCLUDE="${INCLUDE}:${UniversalCRTSdkDir}/include/${UCRTVersion}/shared"
+    INCLUDE="${INCLUDE}:${UniversalCRTSdkDir}/include/${UCRTVersion}/um"
+    INCLUDE="${INCLUDE}:${UniversalCRTSdkDir}/include/${UCRTVersion}/winrt"
+    INCLUDE="${INCLUDE}:${UniversalCRTSdkDir}/include/${UCRTVersion}/cppwinrt"
+    export INCLUDE
+
+    LIB="${VCINSTALLDIR}/lib/${m}"
+    LIB="${VCINSTALLDIR}/Tools/MSVC/${VCVER}/lib/${m}"
+    LIB="${LIB}:${UniversalCRTSdkDir}/lib/${UCRTVersion}/ucrt/${m}"
+    LIB="${LIB}:${UniversalCRTSdkDir}/lib/${UCRTVersion}/um/${m}"
+    export LIB
+
+    export GYP_MSVS_OVERRIDE_PATH="${VSPATH}"
+    export GYP_MSVS_VERSION=$(vswhere -latest -requires "$VSCOMPONENT" -property catalog_productLineVersion)
+else
+    echo Assuming env setup is already done.
+    echo VSPATH=$VSPATH
+fi
--- a/security/nss/coreconf/nspr.sh
+++ b/security/nss/coreconf/nspr.sh
@@ -27,16 +27,19 @@ nspr_build()
     mkdir -p "$nspr_dir"
 
     # These NSPR options are directory-specific, so they don't need to be
     # included in nspr_opt and changing them doesn't force a rebuild of NSPR.
     extra_params=(--prefix="$dist_dir"/$target)
     if [ "$opt_build" = 1 ]; then
         extra_params+=(--disable-debug --enable-optimize)
     fi
+    if [ "$target_arch" = "x64" ]; then
+        extra_params+=(--enable-64bit)
+    fi
 
     echo "NSPR [1/3] configure ..."
     pushd "$nspr_dir" >/dev/null
     CFLAGS="$nspr_cflags" CXXFLAGS="$nspr_cxxflags" \
           LDFLAGS="$nspr_ldflags" CC="$CC" CXX="$CCC" \
           run_verbose ../configure "${extra_params[@]}" "$@"
     popd >/dev/null
     echo "NSPR [2/3] make ..."
--- a/security/nss/gtests/ssl_gtest/ssl_resumption_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_resumption_unittest.cc
@@ -941,16 +941,46 @@ TEST_F(TlsConnectDatagram13, SendSession
   ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
   ConfigureVersion(SSL_LIBRARY_VERSION_TLS_1_3);
   Connect();
   EXPECT_EQ(SECFailure, SSL_SendSessionTicket(server_->ssl_fd(), NULL, 0))
       << "no extra tickets in DTLS until we have Ack support";
   EXPECT_EQ(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_VERSION, PORT_GetError());
 }
 
+TEST_F(TlsConnectStreamTls13, ExternalResumptionUseSecondTicket) {
+  ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
+  ConfigureVersion(SSL_LIBRARY_VERSION_TLS_1_3);
+
+  struct ResumptionTicketState {
+    std::vector<uint8_t> ticket;
+    size_t invoked = 0;
+  } ticket_state;
+  auto cb = [](PRFileDesc* fd, const PRUint8* ticket, unsigned int ticket_len,
+               void* arg) -> SECStatus {
+    auto state = reinterpret_cast<ResumptionTicketState*>(arg);
+    state->ticket.assign(ticket, ticket + ticket_len);
+    state->invoked++;
+    return SECSuccess;
+  };
+  SSL_SetResumptionTokenCallback(client_->ssl_fd(), cb, &ticket_state);
+
+  Connect();
+  EXPECT_EQ(SECSuccess, SSL_SendSessionTicket(server_->ssl_fd(), nullptr, 0));
+  SendReceive();
+  EXPECT_EQ(2U, ticket_state.invoked);
+
+  Reset();
+  ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
+  client_->SetResumptionToken(ticket_state.ticket);
+  ExpectResumption(RESUME_TICKET);
+  Connect();
+  SendReceive();
+}
+
 TEST_F(TlsConnectTest, TestTls13ResumptionDowngrade) {
   ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
   ConfigureVersion(SSL_LIBRARY_VERSION_TLS_1_3);
   Connect();
 
   SendReceive();  // Need to read so that we absorb the session tickets.
   CheckKeys();
 
--- a/security/nss/gtests/ssl_gtest/tls_esni_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/tls_esni_unittest.cc
@@ -445,9 +445,26 @@ TEST_P(TlsConnectTls13, ConnectBogusEsni
   const uint8_t bogusNonceBuf[16] = {0};
   DataBuffer bogusNonce(bogusNonceBuf, sizeof(bogusNonceBuf));
   auto filter = MakeTlsFilter<TlsExtensionReplacer>(
       server_, ssl_tls13_encrypted_sni_xtn, bogusNonce);
   filter->EnableDecryption();
   ConnectExpectAlert(client_, illegal_parameter);
   client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_ESNI_EXTENSION);
 }
+
+// ESNI is a commitment to doing TLS 1.3 or above.
+// The TLS 1.2 server ignores ESNI and processes the dummy SNI.
+// The client then aborts when it sees the server did TLS 1.2.
+TEST_P(TlsConnectTls13, EsniButTLS12Server) {
+  EnsureTlsSetup();
+  SetupEsni(client_, server_);
+  client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
+                           SSL_LIBRARY_VERSION_TLS_1_3);
+  server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
+                           SSL_LIBRARY_VERSION_TLS_1_2);
+  ConnectExpectAlert(client_, kTlsAlertProtocolVersion);
+  client_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_VERSION);
+  server_->CheckErrorCode(SSL_ERROR_PROTOCOL_VERSION_ALERT);
+  ASSERT_FALSE(SSLInt_ExtensionNegotiated(server_->ssl_fd(),
+                                          ssl_tls13_encrypted_sni_xtn));
 }
+}
--- a/security/nss/help.txt
+++ b/security/nss/help.txt
@@ -1,52 +1,53 @@
-Usage: build.sh [-hcv] [-cc] [-j <n>] [--nspr] [--gyp|-g] [--opt|-o] [-m32]
-                [--test] [--pprof] [--scan-build[=output]] [--ct-verif]
-                [--asan] [--ubsan] [--msan] [--sancov[=edge|bb|func|...]]
-                [--disable-tests] [--fuzz[=tls|oss]] [--system-sqlite]
-                [--no-zdefs] [--with-nspr] [--system-nspr] [--enable-libpkix]
-                [--enable-fips] [--mozpkix-only]
+Usage: build.sh [-h] [-c|-cc] [-v] [-j <n>] [--gyp|-g] [--opt|-o]
+                [-t <x64|x86|...>|--target=<x64|x86|...>]
+                [--clang|--gcc|--msvc] [--scan-build[=dir]] [--disable-tests]
+                [--pprof] [--asan] [--msan] [--ubsan[=bool,shift,...]
+                [--fuzz[=tls|oss]] [--sancov[=edge|bb|func|...]]
+                [--emit-llvm] [--no-zdefs] [--test] [--ct-verif]
+                [--nspr|--with-nspr=<include>:<lib>|--system-nspr]
+                [--system-sqlite] [--enable-fips] [--enable-libpkix]
+                [--mozpkix-only]
 
 This script builds NSS with gyp and ninja.
 
-This build system is still under development.  It does not yet support all
-the features or platforms that NSS supports.
-
 NSS build tool options:
 
     -h               display this help and exit
     -c               clean before build
     -cc              clean without building
     -v               verbose build
     -j <n>           run at most <n> concurrent jobs
-    --nspr           force a rebuild of NSPR
     --gyp|-g         force a rerun of gyp
     --opt|-o         do an opt build
-    -m32             do a 32-bit build on a 64-bit system
+    --target|-t      specify target architecture (e.g., x86, x64, aarch64)
     --clang          build with clang and clang++
     --gcc            build with gcc and g++
-    --test           ignore map files and export everything we have
+    --msvc           build with MSVC
+    --scan-build     run the build with scan-build
+                     --scan-build=<dir> sets the output path for scan-build
+    --disable-tests  don't build tests and corresponding cmdline utils
+    --pprof          build with gperftool support
+    --asan           enable address sanitizer
+    --msan           enable memory sanitizer
+    --ubsan          enable undefined behavior sanitizer
+                     --ubsan=bool,shift,... sets specific UB sanitizers
     --fuzz           build fuzzing targets (this always enables test builds)
                      --fuzz=tls to enable TLS fuzzing mode
                      --fuzz=oss to build for OSS-Fuzz
-    --pprof          build with gperftool support
-    --ct-verif       build with valgrind for ct-verif
-    --scan-build     run the build with scan-build (scan-build has to be in the path)
-                     --scan-build=/out/path sets the output path for scan-build
-    --asan           do an asan build
-    --ubsan          do an ubsan build
-                     --ubsan=bool,shift,... sets specific UB sanitizers
-    --msan           do an msan build
     --sancov         do sanitize coverage builds
                      --sancov=func sets coverage to function level for example
     --emit-llvm      emit LLVM bitcode while building
                      (requires the gold linker, use clang-3.8 for SAW)
-    --disable-tests  don't build tests and corresponding cmdline utils
+    --no-zdefs       don't set -Wl,-z,defs
+    --test           ignore map files and export everything we have
+    --ct-verif       build with valgrind for ct-verif
+    --nspr           force a rebuild of NSPR
+    --with-nspr      use the NSPR build at the given locations
+                     --with-nspr=<include>:<lib> sets include and lib paths
+    --system-nspr    attempt to use system nspr
+                     shorthand for --with-nspr=/usr/include/nspr:
     --system-sqlite  use system sqlite
-    --no-zdefs       don't set -Wl,-z,defs
-    --with-nspr      don't build NSPR but use the one at the given location, e.g.
-                     --with-nspr=/path/to/nspr/include:/path/to/nspr/lib
-    --system-nspr    use system nspr. This requires an installation of NSPR and
-                     might not work on all systems.
-    --enable-libpkix make libpkix part of the build.
-    --enable-fips    don't disable FIPS checks.
-    --mozpkix-only   build only static mozpkix and mozpkix-test libraries.
-                     Note that support for this build option is limited.
+    --enable-fips    enable FIPS checks
+    --enable-libpkix make libpkix part of the build
+    --mozpkix-only   build only static mozpkix and mozpkix-test libraries
+                     support for this build option is limited
--- a/security/nss/lib/nss/nss.h
+++ b/security/nss/lib/nss/nss.h
@@ -17,22 +17,22 @@
 
 /*
  * NSS's major version, minor version, patch level, build number, and whether
  * this is a beta release.
  *
  * The format of the version string should be
  *     "<major version>.<minor version>[.<patch level>[.<build number>]][ <ECC>][ <Beta>]"
  */
-#define NSS_VERSION "3.40" _NSS_CUSTOMIZED " Beta"
+#define NSS_VERSION "3.40" _NSS_CUSTOMIZED
 #define NSS_VMAJOR 3
 #define NSS_VMINOR 40
 #define NSS_VPATCH 0
 #define NSS_VBUILD 0
-#define NSS_BETA PR_TRUE
+#define NSS_BETA PR_FALSE
 
 #ifndef RC_INVOKED
 
 #include "seccomon.h"
 
 typedef struct NSSInitParametersStr NSSInitParameters;
 
 /*
--- a/security/nss/lib/softoken/softkver.h
+++ b/security/nss/lib/softoken/softkver.h
@@ -12,16 +12,16 @@
 
 /*
  * Softoken's major version, minor version, patch level, build number,
  * and whether this is a beta release.
  *
  * The format of the version string should be
  *     "<major version>.<minor version>[.<patch level>[.<build number>]][ <ECC>][ <Beta>]"
  */
-#define SOFTOKEN_VERSION "3.40" SOFTOKEN_ECC_STRING " Beta"
+#define SOFTOKEN_VERSION "3.40" SOFTOKEN_ECC_STRING
 #define SOFTOKEN_VMAJOR 3
 #define SOFTOKEN_VMINOR 40
 #define SOFTOKEN_VPATCH 0
 #define SOFTOKEN_VBUILD 0
-#define SOFTOKEN_BETA PR_TRUE
+#define SOFTOKEN_BETA PR_FALSE
 
 #endif /* _SOFTKVER_H_ */
--- a/security/nss/lib/ssl/ssl3con.c
+++ b/security/nss/lib/ssl/ssl3con.c
@@ -6558,19 +6558,30 @@ ssl3_HandleServerHello(sslSocket *ss, PR
     if (isHelloRetry && ss->ssl3.hs.helloRetry) {
         SSL_TRC(3, ("%d: SSL3[%d]: received a second hello_retry_request",
                     SSL_GETPID(), ss->fd));
         desc = unexpected_message;
         errCode = SSL_ERROR_RX_UNEXPECTED_HELLO_RETRY_REQUEST;
         goto alert_loser;
     }
 
-    /* The server didn't pick 1.3 although we either received a
-     * HelloRetryRequest, or we prepared to send early app data. */
+    /* There are three situations in which the server must pick
+     * TLS 1.3.
+     *
+     * 1. We offered ESNI.
+     * 2. We received HRR
+     * 3. We sent early app data.
+     *
+     */
     if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
+        if (ss->xtnData.esniPrivateKey) {
+            desc = protocol_version;
+            errCode = SSL_ERROR_UNSUPPORTED_VERSION;
+            goto alert_loser;
+        }
         if (isHelloRetry || ss->ssl3.hs.helloRetry) {
             /* SSL3_SendAlert() will uncache the SID. */
             desc = illegal_parameter;
             errCode = SSL_ERROR_RX_MALFORMED_SERVER_HELLO;
             goto alert_loser;
         }
         if (ss->ssl3.hs.zeroRttState == ssl_0rtt_sent) {
             /* SSL3_SendAlert() will uncache the SID. */
--- a/security/nss/lib/ssl/sslnonce.c
+++ b/security/nss/lib/ssl/sslnonce.c
@@ -1088,20 +1088,22 @@ ssl_CacheExternalToken(sslSocket *ss)
     if (ssl_EncodeResumptionToken(sid, &encodedToken) != SECSuccess) {
         SSL_TRC(3, ("SSL [%d]: encoding resumption token failed", ss->fd));
         return;
     }
     PORT_Assert(SSL_BUFFER_LEN(&encodedToken) > 0);
     PRINT_BUF(40, (ss, "SSL: encoded resumption token",
                    SSL_BUFFER_BASE(&encodedToken),
                    SSL_BUFFER_LEN(&encodedToken)));
-    ss->resumptionTokenCallback(ss->fd, SSL_BUFFER_BASE(&encodedToken),
-                                SSL_BUFFER_LEN(&encodedToken),
-                                ss->resumptionTokenContext);
-
+    SECStatus rv = ss->resumptionTokenCallback(
+        ss->fd, SSL_BUFFER_BASE(&encodedToken), SSL_BUFFER_LEN(&encodedToken),
+        ss->resumptionTokenContext);
+    if (rv == SECSuccess) {
+        sid->cached = in_external_cache;
+    }
     sslBuffer_Clear(&encodedToken);
 }
 
 void
 ssl_CacheSessionID(sslSocket *ss)
 {
     sslSecurityInfo *sec = &ss->sec;
     PORT_Assert(sec);
@@ -1195,27 +1197,33 @@ void
 ssl3_SetSIDSessionTicket(sslSessionID *sid,
                          /*in/out*/ NewSessionTicket *newSessionTicket)
 {
     PORT_Assert(sid);
     PORT_Assert(newSessionTicket);
     PORT_Assert(newSessionTicket->ticket.data);
     PORT_Assert(newSessionTicket->ticket.len != 0);
 
-    /* if sid->u.ssl3.lock, we are updating an existing entry that is already
-     * cached or was once cached, so we need to acquire and release the write
-     * lock. Otherwise, this is a new session that isn't shared with anything
-     * yet, so no locking is needed.
+    /* If this is in the client cache, we are updating an existing entry that is
+     * already cached or was once cached, so we need to acquire and release the
+     * write lock. Otherwise, this is a new session that isn't shared with
+     * anything yet, so no locking is needed.
      */
     if (sid->u.ssl3.lock) {
+        PORT_Assert(sid->cached == in_client_cache);
         PR_RWLock_Wlock(sid->u.ssl3.lock);
-        if (sid->u.ssl3.locked.sessionTicket.ticket.data) {
-            SECITEM_FreeItem(&sid->u.ssl3.locked.sessionTicket.ticket,
-                             PR_FALSE);
-        }
+    }
+    /* If this was in the client cache, then we might have to free the old
+     * ticket.  In TLS 1.3, we might get a replacement ticket if the server
+     * sends more than one ticket. */
+    if (sid->u.ssl3.locked.sessionTicket.ticket.data) {
+        PORT_Assert(sid->cached == in_client_cache ||
+                    sid->version >= SSL_LIBRARY_VERSION_TLS_1_3);
+        SECITEM_FreeItem(&sid->u.ssl3.locked.sessionTicket.ticket,
+                         PR_FALSE);
     }
 
     PORT_Assert(!sid->u.ssl3.locked.sessionTicket.ticket.data);
 
     /* Do a shallow copy, moving the ticket data. */
     sid->u.ssl3.locked.sessionTicket = *newSessionTicket;
     newSessionTicket->ticket.data = NULL;
     newSessionTicket->ticket.len = 0;
--- a/security/nss/lib/ssl/tls13con.c
+++ b/security/nss/lib/ssl/tls13con.c
@@ -4722,17 +4722,18 @@ tls13_HandleNewSessionTicket(sslSocket *
             return SECFailure;
         }
         PRINT_BUF(50, (ss, "Caching session ticket",
                        ticket.ticket.data,
                        ticket.ticket.len));
 
         /* Replace a previous session ticket when
          * we receive a second NewSessionTicket message. */
-        if (ss->sec.ci.sid->cached == in_client_cache) {
+        if (ss->sec.ci.sid->cached == in_client_cache ||
+            ss->sec.ci.sid->cached == in_external_cache) {
             /* Create a new session ID. */
             sslSessionID *sid = ssl3_NewSessionID(ss, PR_FALSE);
             if (!sid) {
                 return SECFailure;
             }
 
             /* Copy over the peerCert. */
             PORT_Assert(ss->sec.ci.sid->peerCert);
--- a/security/nss/lib/util/nssutil.h
+++ b/security/nss/lib/util/nssutil.h
@@ -14,22 +14,22 @@
 
 /*
  * NSS utilities's major version, minor version, patch level, build number,
  * and whether this is a beta release.
  *
  * The format of the version string should be
  *     "<major version>.<minor version>[.<patch level>[.<build number>]][ <Beta>]"
  */
-#define NSSUTIL_VERSION "3.40 Beta"
+#define NSSUTIL_VERSION "3.40"
 #define NSSUTIL_VMAJOR 3
 #define NSSUTIL_VMINOR 40
 #define NSSUTIL_VPATCH 0
 #define NSSUTIL_VBUILD 0
-#define NSSUTIL_BETA PR_TRUE
+#define NSSUTIL_BETA PR_FALSE
 
 SEC_BEGIN_PROTOS
 
 /*
  * Returns a const string of the UTIL library version.
  */
 extern const char *NSSUTIL_GetVersion(void);
 
--- a/taskcluster/taskgraph/actions/backfill.py
+++ b/taskcluster/taskgraph/actions/backfill.py
@@ -113,27 +113,24 @@ def backfill_action(parameters, graph_co
                 if task.label != label:
                     return task
                 if input.get('addGeckoProfile'):
                     cmd = task.task['payload']['command']
                     task.task['payload']['command'] = add_args_to_command(cmd, ['--geckoProfile'])
                     task.task['extra']['treeherder']['symbol'] += '-p'
 
                 if input.get('testPath', ''):
-                    tp = input.get('testPath', '')
                     is_wpttest = 'web-platform' in task.task['metadata']['name']
                     is_android = 'android' in task.task['metadata']['name']
                     gpu_required = False
-                    # TODO: this has a high chance of getting out of date
                     if (not is_wpttest) and \
                        ('gpu' in task.task['metadata']['name'] or
                         'webgl' in task.task['metadata']['name'] or
-                        'canvas' in tp or
-                        'gfx/tests' in tp or
-                        ('reftest' in tp and 'jsreftest' not in tp)):
+                        ('reftest' in task.task['metadata']['name'] and
+                         'jsreftest' not in task.task['metadata']['name'])):
                         gpu_required = True
 
                     # Create new cmd that runs a test-verify type job
                     preamble_length = 3
                     verify_args = ['--e10s',
                                    '--verify',
                                    '--total-chunk=1',
                                    '--this-chunk=1']
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/payment-handler/__dir__.ini
@@ -0,0 +1,3 @@
+prefs: [dom.payments.request.enabled:true]
+disabled:
+  if not nightly_build: https://bugzilla.mozilla.org/show_bug.cgi?id=1495301
--- a/testing/web-platform/meta/payment-handler/can-make-payment-event.https.html.ini
+++ b/testing/web-platform/meta/payment-handler/can-make-payment-event.https.html.ini
@@ -13,17 +13,18 @@
 
   [If CanMakePaymentEvent.respondWith(Promise.resolve(true)) is called, then the payment method is supported.]
     expected: FAIL
 
   [If CanMakePaymentEvent.respondWith(Promise.reject(error)) is called, then the payment method is not supported.]
     expected: FAIL
 
   [If an app supports "basic-card" in general and that's what merchant requests as well, then capability filtering should make the app available for use. CanMakePaymentEvent should not be fired for "basic-card".]
-    expected: FAIL
+    expected:
+      if not e10s: FAIL
 
   [If an app has less specific "basic-card" capabilites than merchant's request, capability filtering should not make the app available for use. CanMakePaymentEvent should not be fired for "basic-card". ]
     expected: FAIL
 
   [If an app has the exact "basic-card" capabilities that a merchant requested, capability filtering should make the app available for use. CanMakePaymentEvent should not be fired for "basic-card".]
     expected: FAIL
 
   [If an app has more specific "basic-card" capabilities than merchant's request, capability filtering should make the app available for use. CanMakePaymentEvent should not be fired for "basic-card".]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/payment-method-basic-card/__dir__.ini
@@ -0,0 +1,3 @@
+prefs: [dom.payments.request.enabled:true]
+disabled:
+  if not nightly_build: https://bugzilla.mozilla.org/show_bug.cgi?id=1495301
--- a/testing/web-platform/meta/payment-method-basic-card/payment-request-canmakepayment-method.https.html.ini
+++ b/testing/web-platform/meta/payment-method-basic-card/payment-request-canmakepayment-method.https.html.ini
@@ -1,10 +1,11 @@
 [payment-request-canmakepayment-method.https.html]
   [Must return false when the PMI is not supported at by the user agent.]
-    expected: FAIL
+    expected:
+      if not e10s: FAIL
 
   [Must return true when basic-card is amongst unsupported PMIs.]
     expected: FAIL
 
   [If basic-card is supported, then return a promise that resolves to true.]
-    expected: FAIL
-
+    expected:
+      if not e10s: FAIL
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/payment-method-id/__dir__.ini
@@ -0,0 +1,3 @@
+prefs: [dom.payments.request.enabled:true]
+disabled:
+  if not nightly_build: https://bugzilla.mozilla.org/show_bug.cgi?id=1495301
--- a/testing/web-platform/meta/payment-method-id/payment-request-ctor-pmi-handling.https.html.ini
+++ b/testing/web-platform/meta/payment-method-id/payment-request-ctor-pmi-handling.https.html.ini
@@ -1,13 +1,16 @@
 [payment-request-ctor-pmi-handling.https.html]
   [Must not throw on syntactically valid standardized payment method identifiers, even if they are not supported]
-    expected: FAIL
+    expected:
+      if not e10s: FAIL
 
   [Must support valid standard URL PMIs]
-    expected: FAIL
+    expected:
+      if not e10s: FAIL
 
   [Must throw on syntactically invalid standardized payment method identifiers]
-    expected: FAIL
+    expected:
+      if not e10s: FAIL
 
   [Constructor MUST throw if given an invalid URL-based payment method identifier]
-    expected: FAIL
-
+    expected:
+      if not e10s: FAIL
--- a/toolkit/components/antitracking/AntiTrackingCommon.cpp
+++ b/toolkit/components/antitracking/AntiTrackingCommon.cpp
@@ -31,17 +31,16 @@
 #include "nsNetUtil.h"
 #include "nsPIDOMWindow.h"
 #include "nsPrintfCString.h"
 #include "nsScriptSecurityManager.h"
 #include "nsSandboxFlags.h"
 #include "prtime.h"
 
 #define ANTITRACKING_PERM_KEY "3rdPartyStorage"
-#define USER_INTERACTION_PERM "storageAccessAPI"
 
 using namespace mozilla;
 using mozilla::dom::ContentChild;
 
 static LazyLogModule gAntiTrackingLog("AntiTracking");
 static const nsCString::size_type sMaxSpecLength = 128;
 
 #define LOG(format) MOZ_LOG(gAntiTrackingLog, mozilla::LogLevel::Debug, format)
--- a/toolkit/components/antitracking/AntiTrackingCommon.h
+++ b/toolkit/components/antitracking/AntiTrackingCommon.h
@@ -6,16 +6,18 @@
 
 #ifndef mozilla_antitrackingservice_h
 #define mozilla_antitrackingservice_h
 
 #include "nsString.h"
 #include "mozilla/MozPromise.h"
 #include "mozilla/RefPtr.h"
 
+#define USER_INTERACTION_PERM "storageAccessAPI"
+
 class nsIChannel;
 class nsIHttpChannel;
 class nsIPermission;
 class nsIPrincipal;
 class nsIURI;
 class nsPIDOMWindowInner;
 
 namespace mozilla {