Rename the current CharT typename parameter, used for either char16_t or mozilla::Utf8Unit, to Unit -- so that CharT can be used for actual C++ character types, when such are needed to intermesh with character-demanding APIs. Also change a few "chars" in function/variable names to "units" for consistency. No bug, rs=jorendorff over IRC
authorJeff Walden <jwalden@mit.edu>
Tue, 16 Oct 2018 15:41:32 -0700
changeset 500051 0522e105ea10e64fcd421dd082e0ba1cd02dfae1
parent 500050 d327a2dc9cba31f1c446bc2b99627057040fbfc1
child 500052 89189817c169f830f2b880df11ac88569582a67e
push id1864
push userffxbld-merge
push dateMon, 03 Dec 2018 15:51:40 +0000
treeherdermozilla-release@f040763d99ad [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjorendorff
milestone64.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Rename the current CharT typename parameter, used for either char16_t or mozilla::Utf8Unit, to Unit -- so that CharT can be used for actual C++ character types, when such are needed to intermesh with character-demanding APIs. Also change a few "chars" in function/variable names to "units" for consistency. No bug, rs=jorendorff over IRC
js/src/frontend/BytecodeEmitter.h
js/src/frontend/Parser.cpp
js/src/frontend/Parser.h
js/src/frontend/TokenStream.cpp
js/src/frontend/TokenStream.h
js/src/vm/JSFunction.cpp
js/src/vm/JSScript.cpp
js/src/vm/JSScript.h
--- 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();