Backed out 10 changesets (bug 1494930, bug 1459067, bug 1459555) for build bustages on JSScript.cpp. CLOSED TREE
authorNarcis Beleuzu <nbeleuzu@mozilla.com>
Tue, 02 Oct 2018 06:59:06 +0300
changeset 494881 63ea63571271f031dc457f1b1b7519ec8bf3e3de
parent 494880 211ea8e33f7ec9046580e5f1caaefdb04bb535d6
child 494882 58adc643dcdc20eccb4d30bc454b50420e96c020
push id9984
push userffxbld-merge
push dateMon, 15 Oct 2018 21:07:35 +0000
treeherdermozilla-beta@183d27ea8570 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1494930, 1459067, 1459555
milestone64.0a1
backs out211ea8e33f7ec9046580e5f1caaefdb04bb535d6
b3dbe062fb3dcdbb33067352cc80ab85fd0249a6
edada9212b5b707c60cc3989588561f3df03f525
90505ae78229cc37f024fae810c34bf3cc6456be
ccdbc1449e13a2b6a75ff55286f905669499cd27
8f2f2bcd57d2d65a5f4412a9c8867a0296a5b271
275f7949148be2d20a45653e44a0bf4b4ae09a44
8544285b414588d834cd9147ed06ba02a2a60a03
5fb50ca3776ed1d45fe9ec5634dc267c869082f0
864b718cd7978d9daa418362220e12e2a9aac74d
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
Backed out 10 changesets (bug 1494930, bug 1459067, bug 1459555) for build bustages on JSScript.cpp. CLOSED TREE Backed out changeset 211ea8e33f7e (bug 1459067) Backed out changeset b3dbe062fb3d (bug 1459067) Backed out changeset edada9212b5b (bug 1459067) Backed out changeset 90505ae78229 (bug 1459555) Backed out changeset ccdbc1449e13 (bug 1459555) Backed out changeset 8f2f2bcd57d2 (bug 1459555) Backed out changeset 275f7949148b (bug 1494930) Backed out changeset 8544285b4145 (bug 1494930) Backed out changeset 5fb50ca3776e (bug 1494930) Backed out changeset 864b718cd797 (bug 1494930)
js/src/frontend/BinSource-auto.cpp
js/src/frontend/BinSource.cpp
js/src/frontend/BinSource.h
js/src/frontend/BinSource.yaml
js/src/frontend/BinSourceRuntimeSupport.cpp
js/src/frontend/BinSourceRuntimeSupport.h
js/src/frontend/BinToken.cpp
js/src/frontend/BinTokenReaderBase.cpp
js/src/frontend/BinTokenReaderBase.h
js/src/frontend/BinTokenReaderMultipart.cpp
js/src/frontend/BinTokenReaderMultipart.h
js/src/frontend/BinTokenReaderTester.cpp
js/src/frontend/BinTokenReaderTester.h
js/src/frontend/BytecodeCompiler.cpp
js/src/frontend/BytecodeCompiler.h
js/src/frontend/BytecodeEmitter.cpp
js/src/js.msg
js/src/jsapi-tests/testBinASTReader.cpp
js/src/jsapi-tests/testBinTokenReaderTester.cpp
js/src/jsapi.cpp
js/src/moz.build
js/src/shell/js.cpp
js/src/vm/Debugger.cpp
js/src/vm/HelperThreads.cpp
js/src/vm/JSFunction.cpp
js/src/vm/JSScript.cpp
js/src/vm/JSScript.h
js/src/vm/OffThreadScriptCompilation.cpp
js/src/wasm/AsmJS.cpp
--- a/js/src/frontend/BinSource-auto.cpp
+++ b/js/src/frontend/BinSource-auto.cpp
@@ -2593,19 +2593,16 @@ BinASTParser<Tok>::parseInterfaceArrayEx
 
 #if defined(DEBUG)
     const BinField expected_fields[1] = { BinField::Elements };
     MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif // defined(DEBUG)
 
     BINJS_MOZ_TRY_DECL(elements, parseListOfOptionalSpreadElementOrExpression());
 
-    if (elements->empty()) {
-        elements->setHasNonConstInitializer();
-    }
     auto result = elements;
     return result;
 }
 
 
 /*
  interface ArrowExpressionContentsWithExpression : Node {
     AssertedParameterScope parameterScope;
@@ -3855,28 +3852,16 @@ BinASTParser<Tok>::parseInterfaceCallExp
     MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif // defined(DEBUG)
 
     BINJS_MOZ_TRY_DECL(callee, parseExpressionOrSuper());
 
     BINJS_MOZ_TRY_DECL(arguments, parseArguments());
 
     auto op = JSOP_CALL;
-
-    // Try to optimize funcall and funapply at the bytecode level
-    if (PropertyName* prop = factory_.maybeDottedProperty(callee)) {
-        if (prop == cx_->names().apply) {
-            op = JSOP_FUNAPPLY;
-            if (parseContext_->isFunctionBox())
-                parseContext_->functionBox()->usesApply = true;
-        } else if (prop == cx_->names().call) {
-            op = JSOP_FUNCALL;
-        }
-    }
-
     // Check for direct calls to `eval`.
     if (factory_.isEvalName(callee, cx_)) {
         if (!parseContext_->varScope().lookupDeclaredNameForAdd(callee->name())
          && !parseContext_->innermostScope()->lookupDeclaredNameForAdd(callee->name())) {
             // This is a direct call to `eval`.
             if (!parseContext_->sc()->hasDirectEval()) {
                 return raiseMissingDirectEvalInAssertedScope();
             }
@@ -3931,17 +3916,16 @@ BinASTParser<Tok>::parseInterfaceCatchCl
     BINJS_TRY(currentScope.init(parseContext_));
 
     MOZ_TRY(parseAssertedBoundNamesScope());
 
     BINJS_MOZ_TRY_DECL(binding, parseBinding());
 
     BINJS_MOZ_TRY_DECL(body, parseBlock());
 
-    MOZ_TRY(checkClosedVars(currentScope));
     BINJS_TRY_DECL(bindings, NewLexicalScopeData(cx_, currentScope, alloc_, parseContext_));
     BINJS_TRY_DECL(result, factory_.newLexicalScope(*bindings, body));
     BINJS_TRY(factory_.setupCatchScope(result, binding, body));
     return result;
 }
 
 
 /*
@@ -4631,18 +4615,16 @@ BinASTParser<Tok>::parseInterfaceEagerFu
         isGenerator ? GeneratorKind::Generator
                     : GeneratorKind::NotGenerator,
         isAsync ? FunctionAsyncKind::AsyncFunction
                 : FunctionAsyncKind::SyncFunction,
         syntax,
         (syntax != FunctionSyntaxKind::Setter &&
          syntax != FunctionSyntaxKind::Getter) ? name : nullptr));
 
-    forceStrictIfNecessary(funbox, directives);
-
     // Push a new ParseContext. It will be used to parse `scope`, the arguments, the function.
     BinParseContext funpc(cx_, this, funbox, /* newDirectives = */ nullptr);
     BINJS_TRY(funpc.init());
     parseContext_->functionScope().useAsVarScope(parseContext_);
     MOZ_ASSERT(parseContext_->isFunctionBox());
 
     ParseContext::Scope lexicalScope(cx_, parseContext_, usedNames_);
     BINJS_TRY(lexicalScope.init(parseContext_));
@@ -4712,18 +4694,16 @@ BinASTParser<Tok>::parseInterfaceEagerFu
         isGenerator ? GeneratorKind::Generator
                     : GeneratorKind::NotGenerator,
         isAsync ? FunctionAsyncKind::AsyncFunction
                 : FunctionAsyncKind::SyncFunction,
         syntax,
         (syntax != FunctionSyntaxKind::Setter &&
          syntax != FunctionSyntaxKind::Getter) ? name : nullptr));
 
-    forceStrictIfNecessary(funbox, directives);
-
     // Push a new ParseContext. It will be used to parse `scope`, the arguments, the function.
     BinParseContext funpc(cx_, this, funbox, /* newDirectives = */ nullptr);
     BINJS_TRY(funpc.init());
     parseContext_->functionScope().useAsVarScope(parseContext_);
     MOZ_ASSERT(parseContext_->isFunctionBox());
 
     ParseContext::Scope lexicalScope(cx_, parseContext_, usedNames_);
     BINJS_TRY(lexicalScope.init(parseContext_));
@@ -4788,18 +4768,16 @@ BinASTParser<Tok>::parseInterfaceEagerGe
         isGenerator ? GeneratorKind::Generator
                     : GeneratorKind::NotGenerator,
         isAsync ? FunctionAsyncKind::AsyncFunction
                 : FunctionAsyncKind::SyncFunction,
         syntax,
         (syntax != FunctionSyntaxKind::Setter &&
          syntax != FunctionSyntaxKind::Getter) ? name : nullptr));
 
-    forceStrictIfNecessary(funbox, directives);
-
     // Push a new ParseContext. It will be used to parse `scope`, the arguments, the function.
     BinParseContext funpc(cx_, this, funbox, /* newDirectives = */ nullptr);
     BINJS_TRY(funpc.init());
     parseContext_->functionScope().useAsVarScope(parseContext_);
     MOZ_ASSERT(parseContext_->isFunctionBox());
 
     ParseContext::Scope lexicalScope(cx_, parseContext_, usedNames_);
     BINJS_TRY(lexicalScope.init(parseContext_));
@@ -4869,18 +4847,16 @@ BinASTParser<Tok>::parseInterfaceEagerMe
         isGenerator ? GeneratorKind::Generator
                     : GeneratorKind::NotGenerator,
         isAsync ? FunctionAsyncKind::AsyncFunction
                 : FunctionAsyncKind::SyncFunction,
         syntax,
         (syntax != FunctionSyntaxKind::Setter &&
          syntax != FunctionSyntaxKind::Getter) ? name : nullptr));
 
-    forceStrictIfNecessary(funbox, directives);
-
     // Push a new ParseContext. It will be used to parse `scope`, the arguments, the function.
     BinParseContext funpc(cx_, this, funbox, /* newDirectives = */ nullptr);
     BINJS_TRY(funpc.init());
     parseContext_->functionScope().useAsVarScope(parseContext_);
     MOZ_ASSERT(parseContext_->isFunctionBox());
 
     ParseContext::Scope lexicalScope(cx_, parseContext_, usedNames_);
     BINJS_TRY(lexicalScope.init(parseContext_));
@@ -4946,18 +4922,16 @@ BinASTParser<Tok>::parseInterfaceEagerSe
         isGenerator ? GeneratorKind::Generator
                     : GeneratorKind::NotGenerator,
         isAsync ? FunctionAsyncKind::AsyncFunction
                 : FunctionAsyncKind::SyncFunction,
         syntax,
         (syntax != FunctionSyntaxKind::Setter &&
          syntax != FunctionSyntaxKind::Getter) ? name : nullptr));
 
-    forceStrictIfNecessary(funbox, directives);
-
     // Push a new ParseContext. It will be used to parse `scope`, the arguments, the function.
     BinParseContext funpc(cx_, this, funbox, /* newDirectives = */ nullptr);
     BINJS_TRY(funpc.init());
     parseContext_->functionScope().useAsVarScope(parseContext_);
     MOZ_ASSERT(parseContext_->isFunctionBox());
 
     ParseContext::Scope lexicalScope(cx_, parseContext_, usedNames_);
     BINJS_TRY(lexicalScope.init(parseContext_));
@@ -6045,65 +6019,17 @@ BinASTParser<Tok>::parseLazyFunctionDecl
     MOZ_TRY(guard.done());
 
     return result;
 }
 
 template<typename Tok> JS::Result<ParseNode*>
 BinASTParser<Tok>::parseInterfaceLazyFunctionDeclaration(const size_t start, const BinKind kind, const BinFields& fields)
 {
-    MOZ_ASSERT(kind == BinKind::LazyFunctionDeclaration);
-    BINJS_TRY(CheckRecursionLimit(cx_));
-
-#if defined(DEBUG)
-    const BinField expected_fields[7] = { BinField::IsAsync, BinField::IsGenerator, BinField::Name, BinField::Length, BinField::Directives, BinField::ContentsSkip, BinField::Contents };
-    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
-#endif // defined(DEBUG)
-    const auto syntax = FunctionSyntaxKind::Statement;
-
-    BINJS_MOZ_TRY_DECL(isAsync, tokenizer_->readBool());
-
-    BINJS_MOZ_TRY_DECL(isGenerator, tokenizer_->readBool());
-
-    BINJS_MOZ_TRY_DECL(name, parseBindingIdentifier());
-
-    BINJS_MOZ_TRY_DECL(length, tokenizer_->readUnsignedLong());
-
-    BINJS_MOZ_TRY_DECL(directives, parseListOfDirective());
-
-    BINJS_MOZ_TRY_DECL(contentsSkip, tokenizer_->readSkippableSubTree());
-    // Don't parse the contents until we delazify.
-
-    BINJS_MOZ_TRY_DECL(funbox, buildFunctionBox(
-        isGenerator ? GeneratorKind::Generator
-                    : GeneratorKind::NotGenerator,
-        isAsync ? FunctionAsyncKind::AsyncFunction
-                : FunctionAsyncKind::SyncFunction,
-        syntax, name));
-
-    forceStrictIfNecessary(funbox, directives);
-
-    RootedFunction fun(cx_, funbox->function());
-
-    // TODO: This will become incorrect in the face of ES6 features.
-    fun->setArgCount(length);
-
-    auto skipStart = contentsSkip.startOffset();
-    BINJS_TRY_DECL(lazy, LazyScript::Create(cx_, fun, sourceObject_, parseContext_->closedOverBindingsForLazy(), parseContext_->innerFunctionsForLazy,
-                                            skipStart, skipStart + contentsSkip.length(),
-                                            skipStart, 0, skipStart, ParseGoal::Script));
-
-    if (funbox->strict()) {
-        lazy->setStrict();
-    }
-    lazy->setIsBinAST();
-    funbox->function()->initLazyScript(lazy);
-
-    BINJS_MOZ_TRY_DECL(result, makeEmptyFunctionNode(skipStart, kind, funbox));
-    return result;
+    return raiseError("FIXME: Not implemented yet (LazyFunctionDeclaration)");
 }
 
 
 /*
  interface LazyFunctionExpression : Node {
     bool isAsync;
     bool isGenerator;
     BindingIdentifier? name;
@@ -6128,65 +6054,17 @@ BinASTParser<Tok>::parseLazyFunctionExpr
     MOZ_TRY(guard.done());
 
     return result;
 }
 
 template<typename Tok> JS::Result<ParseNode*>
 BinASTParser<Tok>::parseInterfaceLazyFunctionExpression(const size_t start, const BinKind kind, const BinFields& fields)
 {
-    MOZ_ASSERT(kind == BinKind::LazyFunctionExpression);
-    BINJS_TRY(CheckRecursionLimit(cx_));
-
-#if defined(DEBUG)
-    const BinField expected_fields[7] = { BinField::IsAsync, BinField::IsGenerator, BinField::Name, BinField::Length, BinField::Directives, BinField::ContentsSkip, BinField::Contents };
-    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
-#endif // defined(DEBUG)
-    const auto syntax = FunctionSyntaxKind::Expression;
-
-    BINJS_MOZ_TRY_DECL(isAsync, tokenizer_->readBool());
-
-    BINJS_MOZ_TRY_DECL(isGenerator, tokenizer_->readBool());
-
-    BINJS_MOZ_TRY_DECL(name, parseOptionalBindingIdentifier());
-
-    BINJS_MOZ_TRY_DECL(length, tokenizer_->readUnsignedLong());
-
-    BINJS_MOZ_TRY_DECL(directives, parseListOfDirective());
-
-    BINJS_MOZ_TRY_DECL(contentsSkip, tokenizer_->readSkippableSubTree());
-    // Don't parse the contents until we delazify.
-
-    BINJS_MOZ_TRY_DECL(funbox, buildFunctionBox(
-        isGenerator ? GeneratorKind::Generator
-                    : GeneratorKind::NotGenerator,
-        isAsync ? FunctionAsyncKind::AsyncFunction
-                : FunctionAsyncKind::SyncFunction,
-        syntax, name));
-
-    forceStrictIfNecessary(funbox, directives);
-
-    RootedFunction fun(cx_, funbox->function());
-
-    // TODO: This will become incorrect in the face of ES6 features.
-    fun->setArgCount(length);
-
-    auto skipStart = contentsSkip.startOffset();
-    BINJS_TRY_DECL(lazy, LazyScript::Create(cx_, fun, sourceObject_, parseContext_->closedOverBindingsForLazy(), parseContext_->innerFunctionsForLazy,
-                                            skipStart, skipStart + contentsSkip.length(),
-                                            skipStart, 0, skipStart, ParseGoal::Script));
-
-    if (funbox->strict()) {
-        lazy->setStrict();
-    }
-    lazy->setIsBinAST();
-    funbox->function()->initLazyScript(lazy);
-
-    BINJS_MOZ_TRY_DECL(result, makeEmptyFunctionNode(skipStart, kind, funbox));
-    return result;
+    return raiseError("FIXME: Not implemented yet (LazyFunctionExpression)");
 }
 
 
 /*
  interface LazyGetter : Node {
     PropertyName name;
     FrozenArray<Directive> directives;
     GetterContents contents;
@@ -8469,18 +8347,16 @@ BinASTParser<Tok>::parseListOfObjectProp
     AutoList guard(*tokenizer_);
 
     const auto start = tokenizer_->offset();
     MOZ_TRY(tokenizer_->enterList(length, guard));
     BINJS_TRY_DECL(result, factory_.newObjectLiteral(start));
 
     for (uint32_t i = 0; i < length; ++i) {
         BINJS_MOZ_TRY_DECL(item, parseObjectProperty());
-        if (!item->isConstant())
-            result->setHasNonConstInitializer();
         result->appendWithoutOrderAssumption(item);
     }
 
     MOZ_TRY(guard.done());
     return result;
 }
 
 template<typename Tok> JS::Result<ParseNode*>
--- a/js/src/frontend/BinSource.cpp
+++ b/js/src/frontend/BinSource.cpp
@@ -6,17 +6,16 @@
 
 #include "frontend/BinSource.h"
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Casting.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/Move.h"
 #include "mozilla/PodOperations.h"
-#include "mozilla/ScopeExit.h"
 #include "mozilla/Vector.h"
 
 #include "frontend/BinSource-macros.h"
 #include "frontend/BinTokenReaderTester.h"
 #include "frontend/FullParseHandler.h"
 #include "frontend/Parser.h"
 #include "frontend/SharedContext.h"
 
@@ -71,31 +70,27 @@
 //
 // They should be treated lazily (whenever we open a subscope), like bindings.
 
 namespace js {
 namespace frontend {
 
 using UsedNamePtr = UsedNameTracker::UsedNameMap::Ptr;
 
-BinASTParserBase::BinASTParserBase(JSContext* cx, LifoAlloc& alloc, UsedNameTracker& usedNames,
-                                   HandleScriptSourceObject sourceObject, Handle<LazyScript*> lazyScript)
+BinASTParserBase::BinASTParserBase(JSContext* cx, LifoAlloc& alloc, UsedNameTracker& usedNames)
   : AutoGCRooter(cx, AutoGCRooter::Tag::BinParser)
   , cx_(cx)
   , alloc_(alloc)
   , traceListHead_(nullptr)
   , usedNames_(usedNames)
   , nodeAlloc_(cx, alloc)
   , keepAtoms_(cx)
-  , sourceObject_(cx, sourceObject)
-  , lazyScript_(cx, lazyScript)
   , parseContext_(nullptr)
   , factory_(cx, alloc, nullptr, SourceKind::Binary)
 {
-    MOZ_ASSERT_IF(lazyScript, lazyScript->isBinAST());
     cx->frontendCollectionPool().addActiveCompilation();
     tempPoolMark_ = alloc.mark();
 }
 
 BinASTParserBase::~BinASTParserBase()
 {
     alloc_.release(tempPoolMark_);
 
@@ -107,40 +102,37 @@ BinASTParserBase::~BinASTParserBase()
     alloc_.freeAllIfHugeAndUnused();
 
     cx_->frontendCollectionPool().removeActiveCompilation();
 }
 
 // ------------- Toplevel constructions
 
 template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parse(GlobalSharedContext* globalsc, const Vector<uint8_t>& data,
-                         BinASTSourceMetadata** metadataPtr)
+BinASTParser<Tok>::parse(GlobalSharedContext* globalsc, const Vector<uint8_t>& data)
 {
-    return parse(globalsc, data.begin(), data.length(), metadataPtr);
+    return parse(globalsc, data.begin(), data.length());
 }
 
 template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parse(GlobalSharedContext* globalsc, const uint8_t* start, const size_t length,
-                         BinASTSourceMetadata** metadataPtr)
+BinASTParser<Tok>::parse(GlobalSharedContext* globalsc, const uint8_t* start, const size_t length)
 {
-    auto result = parseAux(globalsc, start, length, metadataPtr);
+    auto result = parseAux(globalsc, start, length);
     poison(); // Make sure that the parser is never used again accidentally.
     return result;
 }
 
 
 template<typename Tok> JS::Result<ParseNode*>
 BinASTParser<Tok>::parseAux(GlobalSharedContext* globalsc,
-                            const uint8_t* start, const size_t length,
-                            BinASTSourceMetadata** metadataPtr)
+                            const uint8_t* start, const size_t length)
 {
     MOZ_ASSERT(globalsc);
 
-    tokenizer_.emplace(cx_, this, start, length);
+    tokenizer_.emplace(cx_, start, length);
 
     BinParseContext globalpc(cx_, this, globalsc, /* newDirectives = */ nullptr);
     if (!globalpc.init()) {
         return cx_->alreadyReportedError();
     }
 
     ParseContext::VarScope varScope(cx_, &globalpc, usedNames_);
     if (!varScope.init(&globalpc)) {
@@ -154,164 +146,68 @@ BinASTParser<Tok>::parseAux(GlobalShared
 
     mozilla::Maybe<GlobalScope::Data*> bindings = NewGlobalScopeData(cx_, varScope, alloc_,
                                                                      parseContext_);
     if (!bindings) {
         return cx_->alreadyReportedError();
     }
     globalsc->bindings = *bindings;
 
-    if (metadataPtr) {
-        *metadataPtr = tokenizer_->takeMetadata();
-    }
-
     return result; // Magic conversion to Ok.
 }
 
-template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parseLazyFunction(ScriptSource* scriptSource, const size_t firstOffset)
-{
-    MOZ_ASSERT(lazyScript_);
-    MOZ_ASSERT(scriptSource->length() > firstOffset);
-
-    tokenizer_.emplace(cx_, this, scriptSource->binASTSource(), scriptSource->length());
-
-    MOZ_TRY(tokenizer_->initFromScriptSource(scriptSource));
-
-    tokenizer_->seek(firstOffset);
-
-    // For now, only function declarations and function expression are supported.
-    JSFunction* func = lazyScript_->functionNonDelazifying();
-    bool isExpr = func->isLambda();
-    MOZ_ASSERT(func->kind() == JSFunction::FunctionKind::NormalFunction);
-
-    // Poison the tokenizer when we leave to ensure that it's not used again by accident.
-    auto onExit = mozilla::MakeScopeExit([&]() { poison(); });
-
-    // TODO: This should be actually shared with the auto-generated version.
-
-    auto syntaxKind = isExpr ? FunctionSyntaxKind::Expression : FunctionSyntaxKind::Statement;
-    BINJS_MOZ_TRY_DECL(funbox, buildFunctionBox(lazyScript_->generatorKind(),
-                                                lazyScript_->asyncKind(), syntaxKind, nullptr));
-
-    // Push a new ParseContext. It will be used to parse `scope`, the arguments, the function.
-    BinParseContext funpc(cx_, this, funbox, /* newDirectives = */ nullptr);
-    BINJS_TRY(funpc.init());
-    parseContext_->functionScope().useAsVarScope(parseContext_);
-    MOZ_ASSERT(parseContext_->isFunctionBox());
-
-    ParseContext::Scope lexicalScope(cx_, parseContext_, usedNames_);
-    BINJS_TRY(lexicalScope.init(parseContext_));
-    ListNode* params;
-    ListNode* tmpBody;
-    auto parseFunc = isExpr ? &BinASTParser::parseFunctionExpressionContents
-                            : &BinASTParser::parseFunctionOrMethodContents;
-    MOZ_TRY((this->*parseFunc)(func->nargs(), &params, &tmpBody));
-
-    BINJS_TRY_DECL(lexicalScopeData, NewLexicalScopeData(cx_, lexicalScope, alloc_, parseContext_));
-    BINJS_TRY_DECL(body, factory_.newLexicalScope(*lexicalScopeData, tmpBody));
-
-    auto binKind = isExpr ? BinKind::LazyFunctionExpression : BinKind::LazyFunctionDeclaration;
-    return buildFunction(firstOffset, binKind, nullptr, params, body, funbox);
-}
-
-template<typename Tok> void
-BinASTParser<Tok>::forceStrictIfNecessary(FunctionBox* funbox, ListNode* directives)
-{
-    JSAtom* useStrict = cx_->names().useStrict;
-
-    for (const ParseNode* directive : directives->contents()) {
-        if (directive->as<NameNode>().atom() == useStrict) {
-            funbox->strictScript = true;
-            break;
-        }
-    }
-}
 
 template<typename Tok> JS::Result<FunctionBox*>
 BinASTParser<Tok>::buildFunctionBox(GeneratorKind generatorKind,
     FunctionAsyncKind functionAsyncKind,
     FunctionSyntaxKind syntax,
     ParseNode* name)
 {
-    MOZ_ASSERT_IF(!parseContext_, lazyScript_);
-
     RootedAtom atom(cx_);
     if (name) {
         atom = name->name();
     }
 
-    if (parseContext_ && syntax == FunctionSyntaxKind::Statement) {
-        auto ptr = parseContext_->varScope().lookupDeclaredName(atom);
-        MOZ_ASSERT(ptr);
-        ptr->value()->alterKind(DeclarationKind::BodyLevelFunction);
-    }
-
     // Allocate the function before walking down the tree.
     RootedFunction fun(cx_);
-    BINJS_TRY_VAR(fun, !parseContext_
-        ? lazyScript_->functionNonDelazifying()
-        : AllocNewFunction(cx_, atom, syntax, generatorKind, functionAsyncKind, nullptr));
-    MOZ_ASSERT_IF(parseContext_, fun->explicitName() == atom);
-
-    mozilla::Maybe<Directives> directives;
-    if (parseContext_) {
-        directives.emplace(parseContext_);
-    } else {
-        directives.emplace(lazyScript_->strict());
-    }
+    BINJS_TRY_VAR(fun, AllocNewFunction(cx_, atom, syntax, generatorKind, functionAsyncKind, nullptr));
 
     auto* funbox = alloc_.new_<FunctionBox>(cx_, traceListHead_, fun, /* toStringStart = */ 0,
-                                            *directives, /* extraWarning = */ false,
+                                            Directives(parseContext_), /* extraWarning = */ false,
                                             generatorKind, functionAsyncKind);
     if (!funbox) {
         return raiseOOM();
     }
 
     traceListHead_ = funbox;
-    if (parseContext_) {
-        funbox->initWithEnclosingParseContext(parseContext_, syntax);
-    } else {
-        funbox->initFromLazyFunction();
-    }
+    funbox->initWithEnclosingParseContext(parseContext_, syntax);
     return funbox;
 }
 
-template<typename Tok> JS::Result<CodeNode*>
-BinASTParser<Tok>::makeEmptyFunctionNode(const size_t start, const BinKind kind, FunctionBox* funbox)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::buildFunction(const size_t start, const BinKind kind, ParseNode* name,
+                                 ListNode* params, ParseNode* body, FunctionBox* funbox)
 {
-    // LazyScript compilation requires basically none of the fields filled out.
     TokenPos pos = tokenizer_->pos(start);
+
+    // Set the argument count for building argument packets. Function.length is handled
+    // by setting the appropriate funbox field during argument parsing.
+    funbox->function()->setArgCount(params ? uint16_t(params->count()) : 0);
+
+    // ParseNode represents the body as concatenated after the params.
+    params->appendWithoutOrderAssumption(body);
+
     bool isStatement = kind == BinKind::EagerFunctionDeclaration ||
                        kind == BinKind::LazyFunctionDeclaration;
 
     BINJS_TRY_DECL(result, isStatement
                      ? factory_.newFunctionStatement(pos)
                      : factory_.newFunctionExpression(pos));
 
     factory_.setFunctionBox(result, funbox);
-
-    return result;
-}
-
-template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::buildFunction(const size_t start, const BinKind kind, ParseNode* name,
-                                 ListNode* params, ParseNode* body, FunctionBox* funbox)
-{
-    // Set the argument count for building argument packets. Function.length is handled
-    // by setting the appropriate funbox field during argument parsing.
-    if (!lazyScript_ || lazyScript_->functionNonDelazifying() != funbox->function()) {
-        funbox->function()->setArgCount(params ? uint16_t(params->count()) : 0);
-    }
-
-    // ParseNode represents the body as concatenated after the params.
-    params->appendWithoutOrderAssumption(body);
-
-    BINJS_MOZ_TRY_DECL(result, makeEmptyFunctionNode(start, kind, funbox));
-
     factory_.setFunctionFormalParametersAndBody(result, params);
 
     HandlePropertyName dotThis = cx_->names().dotThis;
     const bool declareThis = hasUsedName(dotThis) ||
                              funbox->bindingsAccessedDynamically() ||
                              funbox->isDerivedClassConstructor();
 
     if (declareThis) {
@@ -320,33 +216,16 @@ BinASTParser<Tok>::buildFunction(const s
         MOZ_ASSERT(!p);
         BINJS_TRY(funScope.addDeclaredName(parseContext_, p, dotThis, DeclarationKind::Var,
                                      DeclaredNameInfo::npos));
         funbox->setHasThisBinding();
 
         // TODO (efaust): This capture will have to come from encoder side for arrow functions.
     }
 
-    // This models PerHandlerParser::declaeFunctionArgumentsObject, with some subtleties removed,
-    // as they don't yet apply to us.
-    HandlePropertyName arguments = cx_->names().arguments;
-    if (hasUsedName(arguments) || parseContext_->functionBox()->bindingsAccessedDynamically()) {
-        ParseContext::Scope& funScope = parseContext_->functionScope();
-        ParseContext::Scope::AddDeclaredNamePtr p = funScope.lookupDeclaredNameForAdd(arguments);
-        if (!p) {
-            BINJS_TRY(funScope.addDeclaredName(parseContext_, p, arguments, DeclarationKind::Var,
-                                               DeclaredNameInfo::npos));
-            funbox->declaredArguments = true;
-            funbox->usesArguments = true;
-
-            funbox->setArgumentsHasLocalBinding();
-            funbox->setDefinitelyNeedsArgsObj();
-        }
-    }
-
     // Check all our bindings after maybe adding function This.
     MOZ_TRY(checkFunctionClosedVars());
 
     BINJS_TRY_DECL(bindings,
              NewFunctionScopeData(cx_, parseContext_->functionScope(),
                                   /* hasParameterExprs = */ false, alloc_, parseContext_));
 
     funbox->functionScopeBindings().set(*bindings);
@@ -583,19 +462,16 @@ BinASTParser<Tok>::appendDirectivesToBod
         ParseNode* iter = body->head();
         while (iter) {
             ParseNode* next = iter->pn_next;
             prefix->appendWithoutOrderAssumption(iter);
             iter = next;
         }
         prefix->setKind(body->getKind());
         prefix->setOp(body->getOp());
-        if (body->hasTopLevelFunctionDeclarations()) {
-            prefix->setHasTopLevelFunctionDeclarations();
-        }
         result = prefix;
     }
 
     return result;
 }
 
 template<typename Tok> mozilla::GenericErrorResult<JS::Error&>
 BinASTParser<Tok>::raiseInvalidClosedVar(JSAtom* name)
@@ -737,23 +613,16 @@ BinASTParserBase::hasUsedName(HandleProp
 }
 
 void
 TraceBinParser(JSTracer* trc, JS::AutoGCRooter* parser)
 {
     static_cast<BinASTParserBase*>(parser)->trace(trc);
 }
 
-template<typename Tok>
-void
-BinASTParser<Tok>::doTrace(JSTracer* trc)
-{
-    if (tokenizer_)
-        tokenizer_->traceMetadata(trc);
-}
 
 // Force class instantiation.
 // This ensures that the symbols are built, without having to export all our
 // code (and its baggage of #include and macros) in the header.
 template class BinASTParser<BinTokenReaderMultipart>;
 template class BinASTParser<BinTokenReaderTester>;
 
 } // namespace frontend
--- a/js/src/frontend/BinSource.h
+++ b/js/src/frontend/BinSource.h
@@ -31,33 +31,29 @@
 #include "js/Result.h"
 
 namespace js {
 namespace frontend {
 
 class BinASTParserBase: private JS::AutoGCRooter
 {
   public:
-    BinASTParserBase(JSContext* cx, LifoAlloc& alloc, UsedNameTracker& usedNames,
-                     HandleScriptSourceObject sourceObject, Handle<LazyScript*> lazyScript);
+    BinASTParserBase(JSContext* cx, LifoAlloc& alloc, UsedNameTracker& usedNames);
     ~BinASTParserBase();
 
   public:
     // Names
 
 
     bool hasUsedName(HandlePropertyName name);
 
     // --- GC.
 
-    virtual void doTrace(JSTracer* trc) {}
-
     void trace(JSTracer* trc) {
         ObjectBox::TraceList(trc, traceListHead_);
-        doTrace(trc);
     }
 
 
   public:
     ParseNode* allocParseNode(size_t size) {
         MOZ_ASSERT(size == sizeof(ParseNode));
         return static_cast<ParseNode*>(nodeAlloc_.allocNode());
     }
@@ -79,18 +75,16 @@ class BinASTParserBase: private JS::Auto
     LifoAlloc::Mark tempPoolMark_;
     ParseNodeAllocator nodeAlloc_;
 
     // ---- Parsing-related stuff
   protected:
     // Root atoms and objects allocated for the parse tree.
     AutoKeepAtoms keepAtoms_;
 
-    RootedScriptSourceObject sourceObject_;
-    Rooted<LazyScript*> lazyScript_;
     ParseContext* parseContext_;
     FullParseHandler factory_;
 
     friend class BinParseContext;
 };
 
 /**
  * The parser for a Binary AST.
@@ -106,19 +100,18 @@ class BinASTParser : public BinASTParser
 
     using AutoList = typename Tokenizer::AutoList;
     using AutoTaggedTuple = typename Tokenizer::AutoTaggedTuple;
     using AutoTuple = typename Tokenizer::AutoTuple;
     using BinFields = typename Tokenizer::BinFields;
     using Chars = typename Tokenizer::Chars;
 
   public:
-    BinASTParser(JSContext* cx, LifoAlloc& alloc, UsedNameTracker& usedNames, const JS::ReadOnlyCompileOptions& options,
-                 HandleScriptSourceObject sourceObject, Handle<LazyScript*> lazyScript = nullptr)
-        : BinASTParserBase(cx, alloc, usedNames, sourceObject, lazyScript)
+    BinASTParser(JSContext* cx, LifoAlloc& alloc, UsedNameTracker& usedNames, const JS::ReadOnlyCompileOptions& options)
+        : BinASTParserBase(cx, alloc, usedNames)
         , options_(options)
         , variableDeclarationKind_(VariableDeclarationKind::Var)
     {
     }
     ~BinASTParser()
     {
     }
 
@@ -127,27 +120,22 @@ class BinASTParser : public BinASTParser
      * or Nothing() in case of error.
      *
      * The instance of `ParseNode` MAY NOT survive the `BinASTParser`. Indeed,
      * destruction of the `BinASTParser` will also destroy the `ParseNode`.
      *
      * In case of error, the parser reports the JS error.
      */
     JS::Result<ParseNode*> parse(GlobalSharedContext* globalsc,
-                                 const uint8_t* start, const size_t length,
-                                 BinASTSourceMetadata** metadataPtr = nullptr);
-    JS::Result<ParseNode*> parse(GlobalSharedContext* globalsc, const Vector<uint8_t>& data,
-                                 BinASTSourceMetadata** metadataPtr = nullptr);
-
-    JS::Result<ParseNode*> parseLazyFunction(ScriptSource* src, const size_t firstOffset);
+                                 const uint8_t* start, const size_t length);
+    JS::Result<ParseNode*> parse(GlobalSharedContext* globalsc, const Vector<uint8_t>& data);
 
   private:
     MOZ_MUST_USE JS::Result<ParseNode*> parseAux(GlobalSharedContext* globalsc,
-                                                 const uint8_t* start, const size_t length,
-                                                 BinASTSourceMetadata** metadataPtr = nullptr);
+                                                 const uint8_t* start, const size_t length);
 
     // --- Raise errors.
     //
     // These methods return a (failed) JS::Result for convenience.
 
     MOZ_MUST_USE mozilla::GenericErrorResult<JS::Error&> raiseInvalidClosedVar(JSAtom* name);
     MOZ_MUST_USE mozilla::GenericErrorResult<JS::Error&> raiseMissingVariableInAssertedScope(JSAtom* name);
     MOZ_MUST_USE mozilla::GenericErrorResult<JS::Error&> raiseMissingDirectEvalInAssertedScope();
@@ -177,21 +165,19 @@ class BinASTParser : public BinASTParser
     };
 
     // Auto-generated methods
 #include "frontend/BinSource-auto.h"
 
     // --- Auxiliary parsing functions
 
     // Build a function object for a function-producing production. Called AFTER creating the scope.
-    JS::Result<CodeNode*>
-    makeEmptyFunctionNode(const size_t start, const BinKind kind, FunctionBox* funbox);
     JS::Result<ParseNode*>
     buildFunction(const size_t start, const BinKind kind, ParseNode* name, ListNode* params,
-                  ParseNode* body, FunctionBox* funbox);
+        ParseNode* body, FunctionBox* funbox);
     JS::Result<FunctionBox*>
     buildFunctionBox(GeneratorKind generatorKind, FunctionAsyncKind functionAsyncKind, FunctionSyntaxKind syntax, ParseNode* name);
 
     // Add name to a given scope.
     MOZ_MUST_USE JS::Result<Ok> addScopeName(AssertedScopeKind scopeKind, HandleAtom name,
                                              ParseContext::Scope* scope,
                                              DeclarationKind declKind,
                                              bool isCaptured);
@@ -222,29 +208,23 @@ class BinASTParser : public BinASTParser
     // As a convenience, a helper that checks the body, parameter, and recursive binding scopes.
     MOZ_MUST_USE JS::Result<Ok> checkFunctionClosedVars();
 
     // --- Utilities.
 
     MOZ_MUST_USE JS::Result<ParseNode*> appendDirectivesToBody(ListNode* body,
         ListNode* directives);
 
-    // Optionally force a strict context without restarting the parse when we see a strict
-    // directive.
-    void forceStrictIfNecessary(FunctionBox* funbox, ListNode* directives);
-
   private: // Implement ErrorReporter
     const JS::ReadOnlyCompileOptions& options_;
 
     const JS::ReadOnlyCompileOptions& options() const override {
         return this->options_;
     }
 
-    void doTrace(JSTracer* trc) final;
-
   public:
     virtual ObjectBox* newObjectBox(JSObject* obj) override {
         MOZ_ASSERT(obj);
 
         /*
          * We use JSContext.tempLifoAlloc to allocate parsed objects and place them
          * on a list in this Parser to ensure GC safety. Thus the tempLifoAlloc
          * arenas containing the entries must be alive until we are done with
--- a/js/src/frontend/BinSource.yaml
+++ b/js/src/frontend/BinSource.yaml
@@ -207,20 +207,17 @@ hpp:
 
 Arguments:
     init:
         BINJS_TRY_DECL(result, factory_.newList(ParseNodeKind::Arguments, tokenizer_->pos(start)));
     append:
         factory_.addList(/* list = */ result, /* kid = */ item);
 
 ArrayExpression:
-    build: |
-        if (elements->empty()) {
-            elements->setHasNonConstInitializer();
-        }
+    build:
         auto result = elements;
 
 AssertedBlockScope:
     type-ok:
         Ok
     init: |
         const auto scopeKind = AssertedScopeKind::Block;
     fields:
@@ -477,28 +474,16 @@ BreakStatement:
                 }
             }
         }
         BINJS_TRY_DECL(result, factory_.newBreakStatement(label ? label->asPropertyName() : nullptr, tokenizer_->pos(start)));
 
 CallExpression:
     build: |
         auto op = JSOP_CALL;
-
-        // Try to optimize funcall and funapply at the bytecode level
-        if (PropertyName* prop = factory_.maybeDottedProperty(callee)) {
-            if (prop == cx_->names().apply) {
-                op = JSOP_FUNAPPLY;
-                if (parseContext_->isFunctionBox())
-                    parseContext_->functionBox()->usesApply = true;
-            } else if (prop == cx_->names().call) {
-                op = JSOP_FUNCALL;
-            }
-        }
-
         // Check for direct calls to `eval`.
         if (factory_.isEvalName(callee, cx_)) {
             if (!parseContext_->varScope().lookupDeclaredNameForAdd(callee->name())
              && !parseContext_->innermostScope()->lookupDeclaredNameForAdd(callee->name())) {
                 // This is a direct call to `eval`.
                 if (!parseContext_->sc()->hasDirectEval()) {
                     return raiseMissingDirectEvalInAssertedScope();
                 }
@@ -514,17 +499,16 @@ CallExpression:
 CatchClause:
     type-ok:
         LexicalScopeNode*
     init: |
         ParseContext::Statement stmt(parseContext_, StatementKind::Catch);
         ParseContext::Scope currentScope(cx_, parseContext_, usedNames_);
         BINJS_TRY(currentScope.init(parseContext_));
     build: |
-        MOZ_TRY(checkClosedVars(currentScope));
         BINJS_TRY_DECL(bindings, NewLexicalScopeData(cx_, currentScope, alloc_, parseContext_));
         BINJS_TRY_DECL(result, factory_.newLexicalScope(*bindings, body));
         BINJS_TRY(factory_.setupCatchScope(result, binding, body));
 
 CompoundAssignmentExpression:
     build: |
         ParseNodeKind pnk;
         switch (operator_){
@@ -625,21 +609,16 @@ DoWhileStatement:
     build:
         BINJS_TRY_DECL(result, factory_.newDoWhileStatement(body, test, tokenizer_->pos(start)));
 
 EagerFunctionDeclaration:
     init: |
         const auto syntax = FunctionSyntaxKind::Statement;
     inherits: EagerFunctionExpression
 
-LazyFunctionDeclaration:
-    init: |
-        const auto syntax = FunctionSyntaxKind::Statement;
-    inherits: LazyFunctionExpression
-
 FunctionExpressionContents:
     type-ok:
         Ok
     extra-params: |
         uint32_t funLength,
         ListNode** paramsOut,
         ListNode** bodyOut
     extra-args: |
@@ -702,18 +681,16 @@ EagerFunctionExpression:
                     isGenerator ? GeneratorKind::Generator
                                 : GeneratorKind::NotGenerator,
                     isAsync ? FunctionAsyncKind::AsyncFunction
                             : FunctionAsyncKind::SyncFunction,
                     syntax,
                     (syntax != FunctionSyntaxKind::Setter &&
                      syntax != FunctionSyntaxKind::Getter) ? name : nullptr));
 
-                forceStrictIfNecessary(funbox, directives);
-
                 // Push a new ParseContext. It will be used to parse `scope`, the arguments, the function.
                 BinParseContext funpc(cx_, this, funbox, /* newDirectives = */ nullptr);
                 BINJS_TRY(funpc.init());
                 parseContext_->functionScope().useAsVarScope(parseContext_);
                 MOZ_ASSERT(parseContext_->isFunctionBox());
 
                 ParseContext::Scope lexicalScope(cx_, parseContext_, usedNames_);
                 BINJS_TRY(lexicalScope.init(parseContext_));
@@ -723,52 +700,16 @@ EagerFunctionExpression:
                 length, &params, &tmpBody
             after: |
                 BINJS_MOZ_TRY_DECL(body, appendDirectivesToBody(tmpBody, directives));
     build: |
         BINJS_TRY_DECL(lexicalScopeData, NewLexicalScopeData(cx_, lexicalScope, alloc_, parseContext_));
         BINJS_TRY_VAR(body, factory_.newLexicalScope(*lexicalScopeData, body));
         BINJS_MOZ_TRY_DECL(result, buildFunction(start, kind, name, params, body, funbox));
 
-LazyFunctionExpression:
-    init: |
-        const auto syntax = FunctionSyntaxKind::Expression;
-    fields:
-        contents:
-            block:
-                replace:
-                    // Don't parse the contents until we delazify.
-    build: |
-        BINJS_MOZ_TRY_DECL(funbox, buildFunctionBox(
-            isGenerator ? GeneratorKind::Generator
-                        : GeneratorKind::NotGenerator,
-            isAsync ? FunctionAsyncKind::AsyncFunction
-                    : FunctionAsyncKind::SyncFunction,
-            syntax, name));
-
-        forceStrictIfNecessary(funbox, directives);
-
-        RootedFunction fun(cx_, funbox->function());
-
-        // TODO: This will become incorrect in the face of ES6 features.
-        fun->setArgCount(length);
-
-        auto skipStart = contentsSkip.startOffset();
-        BINJS_TRY_DECL(lazy, LazyScript::Create(cx_, fun, sourceObject_, parseContext_->closedOverBindingsForLazy(), parseContext_->innerFunctionsForLazy,
-                                                skipStart, skipStart + contentsSkip.length(),
-                                                skipStart, 0, skipStart, ParseGoal::Script));
-
-        if (funbox->strict()) {
-            lazy->setStrict();
-        }
-        lazy->setIsBinAST();
-        funbox->function()->initLazyScript(lazy);
-
-        BINJS_MOZ_TRY_DECL(result, makeEmptyFunctionNode(skipStart, kind, funbox));
-
 EagerGetter:
     init: |
         const auto syntax = FunctionSyntaxKind::Setter;
         const bool isGenerator = false;
         const bool isAsync = false;
         const auto accessorType = AccessorType::Getter;
         const uint32_t length = 0;
     inherits: EagerMethod
@@ -925,20 +866,16 @@ ListOfDirective:
     append:
         factory_.addStatementToList(result, item);
 
 ListOfObjectProperty:
     type-ok:
         ListNode*
     init:
         BINJS_TRY_DECL(result, factory_.newObjectLiteral(start));
-    append: |
-        if (!item->isConstant())
-            result->setHasNonConstInitializer();
-        result->appendWithoutOrderAssumption(item);
 
 ListOfOptionalSpreadElementOrExpression:
     type-ok:
         ListNode*
     init:
         BINJS_TRY_DECL(result, factory_.newArrayLiteral(start));
     append: |
         if (item) {
deleted file mode 100644
--- a/js/src/frontend/BinSourceRuntimeSupport.cpp
+++ /dev/null
@@ -1,44 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * vim: set ts=8 sts=4 et sw=4 tw=99:
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "frontend/BinSourceRuntimeSupport.h"
-
-#include "gc/Tracer.h"
-#include "js/Vector.h"
-#include "vm/StringType.h"
-
-namespace js {
-namespace frontend {
-
-/* static */ BinASTSourceMetadata*
-BinASTSourceMetadata::Create(const Vector<BinKind>& binKinds, uint32_t numStrings)
-{
-    uint32_t numBinKinds = binKinds.length();
-
-    BinASTSourceMetadata* data = static_cast<BinASTSourceMetadata*>(js_malloc(BinASTSourceMetadata::totalSize(numBinKinds, numStrings)));
-    if (!data) {
-        return nullptr;
-    }
-
-    new (data) BinASTSourceMetadata(numBinKinds, numStrings);
-    memcpy(data->binKindBase(), binKinds.begin(), binKinds.length() * sizeof(BinKind));
-
-    return data;
-}
-
-void
-BinASTSourceMetadata::trace(JSTracer* tracer)
-{
-    JSAtom** base = atomsBase();
-    for (uint32_t i = 0; i < numStrings_; i++) {
-        if (base[i]) {
-            TraceManuallyBarrieredEdge(tracer, &base[i], "BinAST Strings");
-        }
-    }
-}
-
-} // namespace frontend
-} // namespace js
--- a/js/src/frontend/BinSourceRuntimeSupport.h
+++ b/js/src/frontend/BinSourceRuntimeSupport.h
@@ -5,28 +5,23 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef frontend_BinSourceSupport_h
 #define frontend_BinSourceSupport_h
 
 #include "mozilla/HashFunctions.h"
 
 #include "frontend/BinToken.h"
-#include "gc/DeletePolicy.h"
 
 #include "js/AllocPolicy.h"
 #include "js/HashTable.h"
 #include "js/Result.h"
-#include "js/UniquePtr.h"
-#include "js/Vector.h"
 
 namespace js {
 
-class ScriptSource;
-
 // Support for parsing JS Binary ASTs.
 struct BinaryASTSupport {
     using BinVariant = js::frontend::BinVariant;
     using BinField = js::frontend::BinField;
     using BinKind = js::frontend::BinKind;
 
     // A structure designed to perform fast char* + length lookup
     // without copies.
@@ -36,19 +31,16 @@ struct BinaryASTSupport {
         CharSlice(const CharSlice& other)
             : start_(other.start_)
             , byteLen_(other.byteLen_)
         {  }
         CharSlice(const char* start, const uint32_t byteLen)
             : start_(start)
             , byteLen_(byteLen)
         { }
-        explicit CharSlice(JSContext*)
-          : CharSlice(nullptr, 0)
-        { }
         const char* begin() const {
             return start_;
         }
         const char* end() const {
             return start_ + byteLen_;
         }
 #ifdef DEBUG
         void dump() const {
@@ -70,100 +62,28 @@ struct BinaryASTSupport {
             }
             return strncmp(key.start_, lookup.start_, key.byteLen_) == 0;
         }
     };
 
     BinaryASTSupport();
 
     JS::Result<const BinVariant*>  binVariant(JSContext*, const CharSlice);
+    JS::Result<const BinField*> binField(JSContext*, const CharSlice);
     JS::Result<const BinKind*> binKind(JSContext*,  const CharSlice);
 
-    bool ensureBinTablesInitialized(JSContext*);
-
-  private:
-    bool ensureBinKindsInitialized(JSContext*);
-    bool ensureBinVariantsInitialized(JSContext*);
-
   private:
     // A HashMap that can be queried without copies from a CharSlice key.
     // Initialized on first call. Keys are CharSlices into static strings.
     using BinKindMap = js::HashMap<const CharSlice, BinKind, CharSlice, js::SystemAllocPolicy>;
     BinKindMap binKindMap_;
 
     using BinFieldMap = js::HashMap<const CharSlice, BinField, CharSlice, js::SystemAllocPolicy>;
     BinFieldMap binFieldMap_;
 
     using BinVariantMap = js::HashMap<const CharSlice, BinVariant, CharSlice, js::SystemAllocPolicy>;
     BinVariantMap binVariantMap_;
 
 };
 
-namespace frontend {
-
-class BinASTSourceMetadata
-{
-    using CharSlice = BinaryASTSupport::CharSlice;
-
-    const uint32_t numStrings_;
-    const uint32_t numBinKinds_;
-
-    // The data lives inline in the allocation, after this class.
-    inline JSAtom** atomsBase() {
-        return reinterpret_cast<JSAtom**>(reinterpret_cast<uintptr_t>(this + 1));
-    }
-    inline CharSlice* sliceBase() {
-        return reinterpret_cast<CharSlice*>(reinterpret_cast<uintptr_t>(atomsBase()) + numStrings_ * sizeof(JSAtom*));
-    }
-    inline BinKind* binKindBase() {
-        return reinterpret_cast<BinKind*>(reinterpret_cast<uintptr_t>(sliceBase()) + numStrings_ * sizeof(CharSlice));
-    }
-
-    static inline size_t totalSize(uint32_t numBinKinds, uint32_t numStrings) {
-        return sizeof(BinASTSourceMetadata) +
-               numStrings * sizeof(JSAtom*) +
-               numStrings * sizeof(CharSlice) +
-               numBinKinds * sizeof(BinKind);
-    }
-
-    BinASTSourceMetadata(uint32_t numBinKinds, uint32_t numStrings)
-      : numStrings_(numStrings),
-        numBinKinds_(numBinKinds)
-    { }
-
-    friend class js::ScriptSource;
-
-  public:
-    static BinASTSourceMetadata* Create(const Vector<BinKind>& binKinds, uint32_t numStrings);
-
-    inline uint32_t numBinKinds() {
-        return numBinKinds_;
-    }
-
-    inline uint32_t numStrings() {
-        return numStrings_;
-    }
-
-    inline BinKind& getBinKind(uint32_t index) {
-        MOZ_ASSERT(index < numBinKinds_);
-        return binKindBase()[index];
-    }
-
-    inline CharSlice& getSlice(uint32_t index) {
-        MOZ_ASSERT(index < numStrings_);
-        return sliceBase()[index];
-    }
-
-    inline JSAtom*& getAtom(uint32_t index) {
-        MOZ_ASSERT(index < numStrings_);
-        return atomsBase()[index];
-    }
-
-    void trace(JSTracer* tracer);
-};
-
-}
-
-typedef UniquePtr<frontend::BinASTSourceMetadata, GCManagedDeletePolicy<frontend::BinASTSourceMetadata>> UniqueBinASTSourceMetadataPtr;
-
 } // namespace js
 
 #endif // frontend_BinSourceSupport_h
--- a/js/src/frontend/BinToken.cpp
+++ b/js/src/frontend/BinToken.cpp
@@ -8,17 +8,17 @@
 
 #include "mozilla/Maybe.h"
 
 #include <sys/types.h>
 
 #include "frontend/BinSourceRuntimeSupport.h"
 #include "frontend/TokenStream.h"
 #include "js/Result.h"
-#include "vm/JSContext.h"
+#include "vm/Runtime.h"
 
 namespace js {
 namespace frontend {
 
 const BinaryASTSupport::CharSlice BINKIND_DESCRIPTIONS[] = {
 #define WITH_VARIANT(_, SPEC_NAME) BinaryASTSupport::CharSlice(SPEC_NAME, sizeof(SPEC_NAME) - 1),
     FOR_EACH_BIN_KIND(WITH_VARIANT)
 #undef WITH_VARIANT
@@ -73,98 +73,56 @@ const char* describeBinVariant(const Bin
 
 BinaryASTSupport::BinaryASTSupport()
   : binKindMap_(frontend::BINKIND_LIMIT)
   , binFieldMap_(frontend::BINFIELD_LIMIT)
   , binVariantMap_(frontend::BINVARIANT_LIMIT)
 {
 }
 
-/**
- * It is expected that all bin tables are initialized on the main thread, and that
- * any helper threads will find the read-only tables properly initialized, so that
- * they can do their accesses safely without taking any locks.
- */
-bool
-BinaryASTSupport::ensureBinTablesInitialized(JSContext* cx)
+JS::Result<const js::frontend::BinKind*>
+BinaryASTSupport::binKind(JSContext* cx, const CharSlice key)
 {
-    return ensureBinKindsInitialized(cx) && ensureBinVariantsInitialized(cx);
-}
-
-bool
-BinaryASTSupport::ensureBinKindsInitialized(JSContext* cx)
-{
-    MOZ_ASSERT(!cx->helperThread());
     if (binKindMap_.empty()) {
         for (size_t i = 0; i < frontend::BINKIND_LIMIT; ++i) {
             const BinKind variant = static_cast<BinKind>(i);
             const CharSlice& key = getBinKind(variant);
             auto ptr = binKindMap_.lookupForAdd(key);
             MOZ_ASSERT(!ptr);
             if (!binKindMap_.add(ptr, key, variant)) {
-                ReportOutOfMemory(cx);
-                return false;
+                return ReportOutOfMemoryResult(cx);
             }
         }
     }
 
-    return true;
-}
-
-bool
-BinaryASTSupport::ensureBinVariantsInitialized(JSContext* cx)
-{
-    MOZ_ASSERT(!cx->helperThread());
-    if (binVariantMap_.empty()) {
-        for (size_t i = 0; i < frontend::BINVARIANT_LIMIT; ++i) {
-            const BinVariant variant = static_cast<BinVariant>(i);
-            const CharSlice& key = getBinVariant(variant);
-            auto ptr = binVariantMap_.lookupForAdd(key);
-            MOZ_ASSERT(!ptr);
-            if (!binVariantMap_.add(ptr, key, variant)) {
-                ReportOutOfMemory(cx);
-                return false;
-            }
-        }
-    }
-    return true;
-}
-
-
-JS::Result<const js::frontend::BinKind*>
-BinaryASTSupport::binKind(JSContext* cx, const CharSlice key)
-{
-    MOZ_ASSERT_IF(cx->helperThread(), !binKindMap_.empty());
-    if (!cx->helperThread()) {
-        // Initialize Lazily if on main thread.
-        if (!ensureBinKindsInitialized(cx)) {
-            return cx->alreadyReportedError();
-        }
-    }
-
-    auto ptr = binKindMap_.readonlyThreadsafeLookup(key);
+    auto ptr = binKindMap_.lookup(key);
     if (!ptr) {
         return nullptr;
     }
 
     return &ptr->value();
 }
 
 JS::Result<const js::frontend::BinVariant*>
 BinaryASTSupport::binVariant(JSContext* cx, const CharSlice key)
 {
-    MOZ_ASSERT_IF(cx->helperThread(), !binVariantMap_.empty());
-    if (!cx->helperThread()) {
-        // Initialize lazily if on main thread.
-        if (!ensureBinVariantsInitialized(cx)) {
-            return cx->alreadyReportedError();
+    if (binVariantMap_.empty()) {
+        for (size_t i = 0; i < frontend::BINVARIANT_LIMIT; ++i) {
+            const BinVariant variant = static_cast<BinVariant>(i);
+            const CharSlice& key = getBinVariant(variant);
+            auto ptr = binVariantMap_.lookupForAdd(key);
+            MOZ_ASSERT(!ptr);
+            if (!binVariantMap_.add(ptr, key, variant)) {
+                return ReportOutOfMemoryResult(cx);
+            }
         }
     }
 
-    auto ptr = binVariantMap_.readonlyThreadsafeLookup(key);
+
+    auto ptr = binVariantMap_.lookup(key);
     if (!ptr) {
         return nullptr;
     }
 
     return &ptr->value();
 }
 
 } // namespace js
--- a/js/src/frontend/BinTokenReaderBase.cpp
+++ b/js/src/frontend/BinTokenReaderBase.cpp
@@ -26,24 +26,19 @@ BinTokenReaderBase::updateLatestKnownGoo
     MOZ_ASSERT(update >= latestKnownGoodPos_);
     latestKnownGoodPos_ = update;
 }
 
 ErrorResult<JS::Error&>
 BinTokenReaderBase::raiseError(const char* description)
 {
     MOZ_ASSERT(!cx_->isExceptionPending());
-    if (MOZ_LIKELY(errorReporter_)) {
-        errorReporter_->reportErrorNoOffset(JSMSG_BINAST, description);
-    } else {
-        // Only true in testing code.
-        TokenPos pos = this->pos();
-        JS_ReportErrorASCII(cx_, "BinAST parsing error: %s at offsets %u => %u",
-                            description, pos.begin, pos.end);
-    }
+    TokenPos pos = this->pos();
+    JS_ReportErrorASCII(cx_, "BinAST parsing error: %s at offsets %u => %u",
+                        description, pos.begin, pos.end);
     return cx_->alreadyReportedError();
 }
 
 ErrorResult<JS::Error&>
 BinTokenReaderBase::raiseOOM()
 {
     ReportOutOfMemory(cx_);
     return cx_->alreadyReportedError();
@@ -93,24 +88,16 @@ BinTokenReaderBase::pos(size_t start)
 {
     TokenPos pos;
     pos.begin = start;
     pos.end = current_ - start_;
     MOZ_ASSERT(pos.end >= pos.begin);
     return pos;
 }
 
-void
-BinTokenReaderBase::seek(size_t offset)
-{
-    MOZ_ASSERT(start_ + offset >= start_ &&
-               start_ + offset < stop_);
-    current_ = start_ + offset;
-}
-
 JS::Result<Ok>
 BinTokenReaderBase::readBuf(uint8_t* bytes, uint32_t len)
 {
     MOZ_ASSERT(!cx_->isExceptionPending());
     MOZ_ASSERT(len > 0);
 
     if (stop_ < current_ + len) {
         return raiseError("Buffer exceeds length");
--- a/js/src/frontend/BinTokenReaderBase.h
+++ b/js/src/frontend/BinTokenReaderBase.h
@@ -3,17 +3,16 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef frontend_BinTokenReaderBase_h
 #define frontend_BinTokenReaderBase_h
 
 #include "frontend/BinToken.h"
-#include "frontend/ErrorReporter.h"
 #include "frontend/TokenStream.h"
 
 #include "js/Result.h"
 #include "js/TypeDecls.h"
 
 namespace js {
 namespace frontend {
 
@@ -23,47 +22,44 @@ extern const uint64_t NULL_FLOAT_REPRESE
 class MOZ_STACK_CLASS BinTokenReaderBase
 {
   public:
     template<typename T> using ErrorResult = mozilla::GenericErrorResult<T>;
 
     // The information needed to skip a subtree.
     class SkippableSubTree {
       public:
-        SkippableSubTree(const size_t startOffset, const size_t length)
-          : startOffset_(startOffset)
+        SkippableSubTree(const uint8_t* start, const size_t length)
+          : start_(start)
           , length_(length)
         { }
 
         // The position in the source buffer at which the subtree starts.
         //
         // `SkippableSubTree` does *not* attempt to keep anything alive.
-        size_t startOffset() const {
-            return startOffset_;
+        const uint8_t* start() const {
+            return start_;
         }
 
         // The length of the subtree.
         size_t length() const {
             return length_;
         }
       private:
-        const size_t startOffset_;
+        const uint8_t* start_;
         const size_t length_;
     };
 
     /**
      * Return the position of the latest token.
      */
     TokenPos pos();
     TokenPos pos(size_t startOffset);
     size_t offset() const;
 
-    // Set the tokenizer's cursor in the file. Use with caution.
-    void seek(size_t offset);
-
      /**
       * Poison this tokenizer.
       */
     void poison();
 
     /**
      * Raise an error.
      *
@@ -72,19 +68,18 @@ class MOZ_STACK_CLASS BinTokenReaderBase
     MOZ_MUST_USE ErrorResult<JS::Error&> raiseError(const char* description);
     MOZ_MUST_USE ErrorResult<JS::Error&> raiseOOM();
     MOZ_MUST_USE ErrorResult<JS::Error&> raiseInvalidNumberOfFields(
         const BinKind kind, const uint32_t expected, const uint32_t got);
     MOZ_MUST_USE ErrorResult<JS::Error&> raiseInvalidField(const char* kind,
         const BinField field);
 
   protected:
-    BinTokenReaderBase(JSContext* cx, ErrorReporter* er, const uint8_t* start, const size_t length)
+    BinTokenReaderBase(JSContext* cx, const uint8_t* start, const size_t length)
         : cx_(cx)
-        , errorReporter_(er)
         , poisoned_(false)
         , start_(start)
         , current_(start)
         , stop_(start + length)
         , latestKnownGoodPos_(0)
     { }
 
     /**
@@ -152,18 +147,16 @@ class MOZ_STACK_CLASS BinTokenReaderBase
     void updateLatestKnownGood();
 
 #ifdef DEBUG
     bool hasRaisedError() const;
 #endif
 
     JSContext* cx_;
 
-    ErrorReporter* errorReporter_;
-
     // `true` if we have encountered an error. Errors are non recoverable.
     // Attempting to read from a poisoned tokenizer will cause assertion errors.
     bool poisoned_;
 
     // The first byte of the buffer. Not owned.
     const uint8_t* start_;
 
     // The current position.
--- a/js/src/frontend/BinTokenReaderMultipart.cpp
+++ b/js/src/frontend/BinTokenReaderMultipart.cpp
@@ -5,17 +5,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "frontend/BinTokenReaderMultipart.h"
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Casting.h"
 #include "mozilla/EndianUtils.h"
 #include "mozilla/Maybe.h"
-#include "mozilla/ScopeExit.h"
 
 #include <utility>
 
 #include "frontend/BinSource-macros.h"
 #include "frontend/BinSourceRuntimeSupport.h"
 
 #include "js/Result.h"
 
@@ -41,47 +40,23 @@ const char COMPRESSION_IDENTITY[] = "ide
 const uint32_t MAX_NUMBER_OF_STRINGS = 32768;
 
 using AutoList = BinTokenReaderMultipart::AutoList;
 using AutoTaggedTuple = BinTokenReaderMultipart::AutoTaggedTuple;
 using AutoTuple = BinTokenReaderMultipart::AutoTuple;
 using CharSlice = BinaryASTSupport::CharSlice;
 using Chars = BinTokenReaderMultipart::Chars;
 
-BinTokenReaderMultipart::BinTokenReaderMultipart(JSContext* cx, ErrorReporter* er, const uint8_t* start, const size_t length)
-  : BinTokenReaderBase(cx, er, start, length)
-  , metadata_(nullptr)
+BinTokenReaderMultipart::BinTokenReaderMultipart(JSContext* cx, const uint8_t* start, const size_t length)
+  : BinTokenReaderBase(cx, start, length)
+  , grammarTable_(cx)
+  , atomsTable_(cx, AtomVector(cx))
+  , slicesTable_(cx)
   , posBeforeTree_(nullptr)
-{
-    MOZ_ASSERT(er);
-}
-
-BinTokenReaderMultipart::~BinTokenReaderMultipart()
-{
-    if (metadata_ && metadataOwned_ == MetadataOwnership::Owned) {
-        UniqueBinASTSourceMetadataPtr ptr(metadata_);
-    }
-}
-
-BinASTSourceMetadata*
-BinTokenReaderMultipart::takeMetadata()
-{
-    MOZ_ASSERT(metadataOwned_ == MetadataOwnership::Owned);
-    metadataOwned_ = MetadataOwnership::Unowned;
-    return metadata_;
-}
-
-JS::Result<Ok>
-BinTokenReaderMultipart::initFromScriptSource(ScriptSource* scriptSource)
-{
-    metadata_ = scriptSource->binASTSourceMetadata();
-    metadataOwned_ = MetadataOwnership::Unowned;
-
-    return Ok();
-}
+{ }
 
 JS::Result<Ok>
 BinTokenReaderMultipart::readHeader()
 {
     // Check that we don't call this function twice.
     MOZ_ASSERT(!posBeforeTree_);
 
     // Read global headers.
@@ -107,17 +82,16 @@ BinTokenReaderMultipart::readHeader()
 
     BINJS_MOZ_TRY_DECL(grammarNumberOfEntries, readInternalUint32());
     if (grammarNumberOfEntries > BINKIND_LIMIT) { // Sanity check.
         return raiseError("Invalid number of entries in grammar table");
     }
 
     // This table maps BinKind index -> BinKind.
     // Initialize and populate.
-    Vector<BinKind> grammarTable_(cx_);
     if (!grammarTable_.reserve(grammarNumberOfEntries)) {
         return raiseOOM();
     }
 
     for (uint32_t i = 0; i < grammarNumberOfEntries; ++i) {
         BINJS_MOZ_TRY_DECL(byteLen, readInternalUint32());
         if (current_ + byteLen > stop_) {
             return raiseError("Invalid byte length in grammar table");
@@ -149,79 +123,68 @@ BinTokenReaderMultipart::readHeader()
         return raiseError("Invalid byte length in strings table");
     }
 
     BINJS_MOZ_TRY_DECL(stringsNumberOfEntries, readInternalUint32());
     if (stringsNumberOfEntries > MAX_NUMBER_OF_STRINGS) { // Sanity check.
         return raiseError("Too many entries in strings table");
     }
 
-    BinASTSourceMetadata* metadata = BinASTSourceMetadata::Create(grammarTable_, stringsNumberOfEntries);
-    if (!metadata) {
+    // This table maps String index -> String.
+    // Initialize and populate.
+    if (!atomsTable_.reserve(stringsNumberOfEntries)) {
         return raiseOOM();
     }
-
-    // Free it if we don't make it out of here alive. Since we don't want to calloc(), we
-    // need to avoid marking atoms that might not be there.
-    auto se = mozilla::MakeScopeExit([metadata](){ js_free(metadata); });
+    if (!slicesTable_.reserve(stringsNumberOfEntries)) {
+        return raiseOOM();
+    }
 
     RootedAtom atom(cx_);
     for (uint32_t i = 0; i < stringsNumberOfEntries; ++i) {
         BINJS_MOZ_TRY_DECL(byteLen, readInternalUint32());
         if (current_ + byteLen > stop_ || current_ + byteLen < current_) {
             return raiseError("Invalid byte length in individual string");
         }
 
         // Check null string.
         if (byteLen == 2 && *current_ == 255 && *(current_ + 1) == 0) {
             atom = nullptr;
         } else {
-            BINJS_TRY_VAR(atom, AtomizeUTF8Chars(cx_, (const char*)current_, byteLen));
+            BINJS_TRY_VAR(atom, Atomize(cx_, (const char*)current_, byteLen));
         }
 
-        metadata->getAtom(i) = atom;
+        // Populate `atomsTable_`: i => atom.
+        atomsTable_.infallibleAppend(atom); // We have reserved before entering the loop.
 
         // Populate `slicesTable_`: i => slice
-        new (&metadata->getSlice(i)) Chars((const char*)current_, byteLen);
+        Chars slice((const char*)current_, byteLen);
+        slicesTable_.infallibleAppend(std::move(slice)); // We have reserved before entering the loop.
 
         current_ += byteLen;
     }
 
     if (posBeforeStrings + stringsByteLen != current_) {
         return raiseError("The length of the strings table didn't match its contents.");
     }
 
-    MOZ_ASSERT(!metadata_);
-    se.release();
-    metadata_ = metadata;
-    metadataOwned_ = MetadataOwnership::Owned;
-
     // Start reading AST.
     MOZ_TRY(readConst(SECTION_HEADER_TREE));
     MOZ_TRY(readConst(COMPRESSION_IDENTITY)); // For the moment, we only support identity compression.
     posBeforeTree_ = current_;
 
     BINJS_MOZ_TRY_DECL(treeByteLen, readInternalUint32());
 
     if (posBeforeTree_ + treeByteLen > stop_ || posBeforeTree_ + treeByteLen < posBeforeTree_) { // Sanity check.
         return raiseError("Invalid byte length in tree table");
     }
 
     // At this stage, we're ready to start reading the tree.
     return Ok();
 }
 
-void
-BinTokenReaderMultipart::traceMetadata(JSTracer* trc)
-{
-    if (metadata_) {
-        metadata_->trace(trc);
-    }
-}
-
 JS::Result<bool>
 BinTokenReaderMultipart::readBool()
 {
     updateLatestKnownGood();
     BINJS_MOZ_TRY_DECL(byte, readByte());
 
     switch (byte) {
       case 0:
@@ -263,20 +226,20 @@ BinTokenReaderMultipart::readDouble()
 
 // A single atom is represented as an index into the table of strings.
 JS::Result<JSAtom*>
 BinTokenReaderMultipart::readMaybeAtom()
 {
     updateLatestKnownGood();
     BINJS_MOZ_TRY_DECL(index, readInternalUint32());
 
-    if (index >= metadata_->numStrings()) {
+    if (index >= atomsTable_.length()) {
         return raiseError("Invalid index to strings table");
     }
-    return metadata_->getAtom(index);
+    return atomsTable_[index].get();
 }
 
 JS::Result<JSAtom*>
 BinTokenReaderMultipart::readAtom()
 {
     BINJS_MOZ_TRY_DECL(maybe, readMaybeAtom());
 
     if (!maybe) {
@@ -287,46 +250,46 @@ BinTokenReaderMultipart::readAtom()
 }
 
 JS::Result<Ok>
 BinTokenReaderMultipart::readChars(Chars& out)
 {
     updateLatestKnownGood();
     BINJS_MOZ_TRY_DECL(index, readInternalUint32());
 
-    if (index >= metadata_->numStrings()) {
+    if (index >= slicesTable_.length()) {
         return raiseError("Invalid index to strings table for string enum");
     }
 
-    out = metadata_->getSlice(index);
+    out = slicesTable_[index];
     return Ok();
 }
 
 JS::Result<BinVariant>
 BinTokenReaderMultipart::readVariant()
 {
     updateLatestKnownGood();
     BINJS_MOZ_TRY_DECL(index, readInternalUint32());
 
-    if (index >= metadata_->numStrings()) {
+    if (index >= slicesTable_.length()) {
         return raiseError("Invalid index to strings table for string enum");
     }
 
     auto variantsPtr = variantsTable_.lookupForAdd(index);
     if (variantsPtr) {
         return variantsPtr->value();
     }
 
     // Either we haven't cached the result yet or this is not a variant.
     // Check in the slices table and, in case of success, cache the result.
 
     // Note that we stop parsing if we attempt to readVariant() with an
     // ill-formed variant, so we don't run the risk of feching an ill-variant
     // more than once.
-    Chars slice = metadata_->getSlice(index); // We have checked `index` above.
+    Chars slice = slicesTable_[index]; // We have checked `index` above.
     BINJS_MOZ_TRY_DECL(variant, cx_->runtime()->binast().binVariant(cx_, slice));
 
     if (!variant) {
         return raiseError("Invalid string enum variant");
     }
 
     if (!variantsTable_.add(variantsPtr, index, *variant)) {
         return raiseOOM();
@@ -340,17 +303,17 @@ BinTokenReaderMultipart::readSkippableSu
 {
     updateLatestKnownGood();
     BINJS_MOZ_TRY_DECL(byteLen, readInternalUint32());
 
     if (current_ + byteLen > stop_ || current_ + byteLen < current_) {
         return raiseError("Invalid byte length in readSkippableSubTree");
     }
 
-    const auto start = offset();
+    const auto start = current_;
 
     current_ += byteLen;
 
     return BinTokenReaderBase::SkippableSubTree(start, byteLen);
 }
 
 // Untagged tuple:
 // - contents (specified by the higher-level grammar);
@@ -364,21 +327,21 @@ BinTokenReaderMultipart::enterUntaggedTu
 
 // Tagged tuples:
 // - uint32_t index in table [grammar];
 // - content (specified by the higher-level grammar);
 JS::Result<Ok>
 BinTokenReaderMultipart::enterTaggedTuple(BinKind& tag, BinTokenReaderMultipart::BinFields&, AutoTaggedTuple& guard)
 {
     BINJS_MOZ_TRY_DECL(index, readInternalUint32());
-    if (index >= metadata_->numBinKinds()) {
+    if (index >= grammarTable_.length()) {
         return raiseError("Invalid index to grammar table");
     }
 
-    tag = metadata_->getBinKind(index);
+    tag = grammarTable_[index];
 
     // Enter the body.
     guard.init();
     return Ok();
 }
 
 // List:
 //
--- a/js/src/frontend/BinTokenReaderMultipart.h
+++ b/js/src/frontend/BinTokenReaderMultipart.h
@@ -40,34 +40,40 @@ class MOZ_STACK_CLASS BinTokenReaderMult
     using CharSlice = BinaryASTSupport::CharSlice;
 
     // This implementation of `BinFields` is effectively `void`, as the format
     // does not embed field information.
     class BinFields {
       public:
         explicit BinFields(JSContext*) {}
     };
-    using Chars = CharSlice;
+    struct Chars: public CharSlice {
+        explicit Chars(JSContext*)
+          : CharSlice(nullptr, 0)
+        { }
+        Chars(const char* start, const uint32_t byteLen)
+          : CharSlice(start, byteLen)
+        { }
+        Chars(const Chars& other) = default;
+    };
 
   public:
     /**
      * Construct a token reader.
      *
      * Does NOT copy the buffer.
      */
-    BinTokenReaderMultipart(JSContext* cx, ErrorReporter* er, const uint8_t* start, const size_t length);
+    BinTokenReaderMultipart(JSContext* cx, const uint8_t* start, const size_t length);
 
     /**
      * Construct a token reader.
      *
      * Does NOT copy the buffer.
      */
-    BinTokenReaderMultipart(JSContext* cx, ErrorReporter* er, const Vector<uint8_t>& chars);
-
-    ~BinTokenReaderMultipart();
+    BinTokenReaderMultipart(JSContext* cx, const Vector<uint8_t>& chars);
 
     /**
      * Read the header of the file.
      */
     MOZ_MUST_USE JS::Result<Ok> readHeader();
 
     // --- Primitive values.
     //
@@ -181,39 +187,40 @@ class MOZ_STACK_CLASS BinTokenReaderMult
 
   private:
     /**
      * Read a single uint32_t.
      */
     MOZ_MUST_USE JS::Result<uint32_t> readInternalUint32();
 
   private:
+    // A mapping grammar index => BinKind, as defined by the [GRAMMAR]
+    // section of the file. Populated during readHeader().
+    Vector<BinKind> grammarTable_;
+
     // A mapping string index => BinVariant as extracted from the [STRINGS]
     // section of the file. Populated lazily.
     js::HashMap<uint32_t, BinVariant, DefaultHasher<uint32_t>, SystemAllocPolicy> variantsTable_;
 
-    enum class MetadataOwnership {
-        Owned,
-        Unowned
-    };
-    MetadataOwnership metadataOwned_;
-    BinASTSourceMetadata* metadata_;
+    // A mapping index => JSAtom, as defined by the [STRINGS]
+    // section of the file. Populated during readHeader().
+    using AtomVector = GCVector<JSAtom*>;
+    JS::Rooted<AtomVector> atomsTable_;
+
+    // The same mapping, but as CharSlice. Populated during readHeader().
+    // The slices are into the source buffer.
+    Vector<Chars> slicesTable_;
 
     const uint8_t* posBeforeTree_;
 
     BinTokenReaderMultipart(const BinTokenReaderMultipart&) = delete;
     BinTokenReaderMultipart(BinTokenReaderMultipart&&) = delete;
     BinTokenReaderMultipart& operator=(BinTokenReaderMultipart&) = delete;
 
   public:
-    void traceMetadata(JSTracer* trc);
-    BinASTSourceMetadata* takeMetadata();
-    MOZ_MUST_USE JS::Result<Ok> initFromScriptSource(ScriptSource* scriptSource);
-
-  public:
     // The following classes are used whenever we encounter a tuple/tagged tuple/list
     // to make sure that:
     //
     // - if the construct "knows" its byte length, we have exactly consumed all
     //   the bytes (otherwise, this means that the file is corrupted, perhaps on
     //   purpose, so we need to reject the stream);
     // - if the construct has a footer, once we are done reading it, we have
     //   reached the footer (this is to aid with debugging).
--- a/js/src/frontend/BinTokenReaderTester.cpp
+++ b/js/src/frontend/BinTokenReaderTester.cpp
@@ -18,22 +18,22 @@
 namespace js {
 namespace frontend {
 
 using BinFields = BinTokenReaderTester::BinFields;
 using AutoList = BinTokenReaderTester::AutoList;
 using AutoTaggedTuple = BinTokenReaderTester::AutoTaggedTuple;
 using AutoTuple = BinTokenReaderTester::AutoTuple;
 
-BinTokenReaderTester::BinTokenReaderTester(JSContext* cx, ErrorReporter* er, const uint8_t* start, const size_t length)
-    : BinTokenReaderBase(cx, er, start, length)
+BinTokenReaderTester::BinTokenReaderTester(JSContext* cx, const uint8_t* start, const size_t length)
+    : BinTokenReaderBase(cx, start, length)
 { }
 
-BinTokenReaderTester::BinTokenReaderTester(JSContext* cx, ErrorReporter* er, const Vector<uint8_t>& buf)
-    : BinTokenReaderBase(cx, er, buf.begin(), buf.length())
+BinTokenReaderTester::BinTokenReaderTester(JSContext* cx, const Vector<uint8_t>& buf)
+    : BinTokenReaderBase(cx, buf.begin(), buf.length())
 { }
 
 JS::Result<Ok>
 BinTokenReaderTester::readHeader()
 {
     // This format does not have a header.
     return Ok();
 }
@@ -235,17 +235,17 @@ BinTokenReaderTester::readSkippableSubTr
 {
     updateLatestKnownGood();
     BINJS_MOZ_TRY_DECL(byteLen, readInternalUint32());
 
     if (current_ + byteLen > stop_ || current_ + byteLen < current_) {
         return raiseError("Invalid byte length in readSkippableSubTree");
     }
 
-    const auto start = offset();
+    const auto start = current_;
 
     current_ += byteLen;
 
     return BinTokenReaderBase::SkippableSubTree(start, byteLen);
 }
 
 // Untagged tuple:
 // - "<tuple>";
--- a/js/src/frontend/BinTokenReaderTester.h
+++ b/js/src/frontend/BinTokenReaderTester.h
@@ -17,18 +17,16 @@
 
 #if !defined(NIGHTLY_BUILD)
 #error "BinTokenReaderTester.* is designed to help test implementations of successive versions of JS BinaryAST. It is available only on Nightly."
 #endif // !defined(NIGHTLY_BUILD)
 
 namespace js {
 namespace frontend {
 
-class BinASTSourceMetadata;
-
 /**
  * A token reader for a simple, alternative serialization format for BinAST.
  *
  * This serialization format, which is also supported by the reference
  * implementation of the BinAST compression suite, is designed to be
  * mostly human-readable and easy to check for all sorts of deserialization
  * errors. While this format is NOT designed to be shipped to end-users, it
  * is nevertheless a very useful tool for implementing and testing parsers.
@@ -65,24 +63,24 @@ class MOZ_STACK_CLASS BinTokenReaderTest
     class AutoTaggedTuple;
 
   public:
     /**
      * Construct a token reader.
      *
      * Does NOT copy the buffer.
      */
-    BinTokenReaderTester(JSContext* cx, ErrorReporter* er, const uint8_t* start, const size_t length);
+    BinTokenReaderTester(JSContext* cx, const uint8_t* start, const size_t length);
 
     /**
      * Construct a token reader.
      *
      * Does NOT copy the buffer.
      */
-    BinTokenReaderTester(JSContext* cx, ErrorReporter* er, const Vector<uint8_t>& chars);
+    BinTokenReaderTester(JSContext* cx, const Vector<uint8_t>& chars);
 
     /**
      * Read the header of the file.
      */
     MOZ_MUST_USE JS::Result<Ok> readHeader();
 
     // --- Primitive values.
     //
@@ -211,21 +209,16 @@ class MOZ_STACK_CLASS BinTokenReaderTest
     }
 
     /**
      * Read a single uint32_t.
      */
     MOZ_MUST_USE JS::Result<uint32_t> readInternalUint32();
 
   public:
-    void traceMetadata(JSTracer*) {}
-    BinASTSourceMetadata* takeMetadata() { MOZ_CRASH("Tester format has no metadata to take!"); }
-    MOZ_MUST_USE JS::Result<Ok> initFromScriptSource(ScriptSource*) { MOZ_CRASH("Tester format not for dynamic use"); }
-
-  public:
     // The following classes are used whenever we encounter a tuple/tagged tuple/list
     // to make sure that:
     //
     // - if the construct "knows" its byte length, we have exactly consumed all
     //   the bytes (otherwise, this means that the file is corrupted, perhaps on
     //   purpose, so we need to reject the stream);
     // - if the construct has a footer, once we are done reading it, we have
     //   reached the footer (this is to aid with debugging).
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -671,41 +671,33 @@ frontend::CompileGlobalBinASTScript(JSCo
     frontend::UsedNameTracker usedNames(cx);
 
     RootedScriptSourceObject sourceObj(cx, CreateScriptSourceObject(cx, options));
 
     if (!sourceObj) {
         return nullptr;
     }
 
-    if (!sourceObj->source()->setBinASTSourceCopy(cx, src, len))
-        return nullptr;
-
     RootedScript script(cx, JSScript::Create(cx, options, sourceObj, 0, len, 0, len));
 
     if (!script) {
         return nullptr;
     }
 
     Directives directives(options.strictOption);
     GlobalSharedContext globalsc(cx, ScopeKind::Global, directives, options.extraWarningsOption);
 
-    frontend::BinASTParser<BinTokenReaderMultipart> parser(cx, alloc, usedNames, options, sourceObj);
+    frontend::BinASTParser<BinTokenReaderMultipart> parser(cx, alloc, usedNames, options);
 
-    // Metadata stores internal pointers, so we must use the same buffer every time, including for lazy parses
-    ScriptSource* ss = sourceObj->source();
-    BinASTSourceMetadata* metadata = nullptr;
-    auto parsed = parser.parse(&globalsc, ss->binASTSource(), ss->length(), &metadata);
+    auto parsed = parser.parse(&globalsc, src, len);
 
     if (parsed.isErr()) {
         return nullptr;
     }
 
-    sourceObj->source()->setBinASTSourceMetadata(metadata);
-
     BytecodeEmitter bce(nullptr, &parser, &globalsc, script, nullptr, 0);
 
     if (!bce.init()) {
         return nullptr;
     }
 
     ParseNode *pn = parsed.unwrap();
     if (!bce.emitScript(pn)) {
@@ -837,24 +829,21 @@ class MOZ_STACK_CLASS AutoAssertFunction
 #endif
     }
 };
 
 bool
 frontend::CompileLazyFunction(JSContext* cx, Handle<LazyScript*> lazy, const char16_t* chars, size_t length)
 {
     MOZ_ASSERT(cx->compartment() == lazy->functionNonDelazifying()->compartment());
-
     // We can only compile functions whose parents have previously been
     // compiled, because compilation requires full information about the
     // function's immediately enclosing scope.
     MOZ_ASSERT(lazy->enclosingScriptHasEverBeenCompiled());
 
-    MOZ_ASSERT(!lazy->isBinAST());
-
     AutoAssertReportedException assertException(cx);
     Rooted<JSFunction*> fun(cx, lazy->functionNonDelazifying());
     AutoAssertFunctionDelazificationCompletion delazificationCompletion(cx, fun);
 
     JS::CompileOptions options(cx);
     options.setMutedErrors(lazy->mutedErrors())
            .setFileAndLine(lazy->filename(), lazy->lineno())
            .setColumn(lazy->column())
@@ -922,75 +911,16 @@ frontend::CompileLazyFunction(JSContext*
     }
 
     delazificationCompletion.complete();
     assertException.reset();
     return true;
 }
 
 bool
-frontend::CompileLazyBinASTFunction(JSContext* cx, Handle<LazyScript*> lazy, const uint8_t* buf, size_t length)
-{
-    MOZ_ASSERT(cx->compartment() == lazy->functionNonDelazifying()->compartment());
-
-    // We can only compile functions whose parents have previously been
-    // compiled, because compilation requires full information about the
-    // function's immediately enclosing scope.
-    MOZ_ASSERT(lazy->enclosingScriptHasEverBeenCompiled());
-    MOZ_ASSERT(lazy->isBinAST());
-
-    CompileOptions options(cx);
-    options.setMutedErrors(lazy->mutedErrors())
-           .setFileAndLine(lazy->filename(), lazy->lineno())
-           .setColumn(lazy->column())
-           .setScriptSourceOffset(lazy->sourceStart())
-           .setNoScriptRval(false)
-           .setSelfHostingMode(false);
-
-    UsedNameTracker usedNames(cx);
-
-    RootedScriptSourceObject sourceObj(cx, &lazy->sourceObject());
-    MOZ_ASSERT(sourceObj);
-
-    RootedScript script(cx, JSScript::Create(cx, options, sourceObj, lazy->sourceStart(), lazy->sourceEnd(),
-                                             lazy->sourceStart(), lazy->sourceEnd()));
-
-    if (!script)
-        return false;
-
-    if (lazy->hasBeenCloned())
-        script->setHasBeenCloned();
-
-    frontend::BinASTParser<BinTokenReaderMultipart> parser(cx, cx->tempLifoAlloc(),
-                                                           usedNames, options, sourceObj,
-                                                           lazy);
-
-    auto parsed = parser.parseLazyFunction(lazy->scriptSource(), lazy->sourceStart());
-
-    if (parsed.isErr())
-        return false;
-
-    ParseNode *pn = parsed.unwrap();
-
-    BytecodeEmitter bce(nullptr, &parser, pn->as<CodeNode>().funbox(), script,
-                        lazy, pn->pn_pos, BytecodeEmitter::LazyFunction);
-
-    if (!bce.init())
-        return false;
-
-    if (!bce.emitFunctionScript(&pn->as<CodeNode>(), BytecodeEmitter::TopLevelFunction::Yes))
-        return false;
-
-    if (!NameFunctions(cx, pn))
-        return false;
-
-    return script;
-}
-
-bool
 frontend::CompileStandaloneFunction(JSContext* cx, MutableHandleFunction fun,
                                     const JS::ReadOnlyCompileOptions& options,
                                     JS::SourceBufferHolder& srcBuf,
                                     const Maybe<uint32_t>& parameterListEnd,
                                     HandleScope enclosingScope /* = nullptr */)
 {
     AutoAssertReportedException assertException(cx);
 
--- a/js/src/frontend/BytecodeCompiler.h
+++ b/js/src/frontend/BytecodeCompiler.h
@@ -59,19 +59,16 @@ CompileModule(JSContext* cx, const JS::R
 JSScript*
 CompileModule(JSContext* cx, const JS::ReadOnlyCompileOptions& options,
               JS::SourceBufferHolder& srcBuf, LifoAlloc& alloc,
               ScriptSourceObject** sourceObjectOut = nullptr);
 
 MOZ_MUST_USE bool
 CompileLazyFunction(JSContext* cx, Handle<LazyScript*> lazy, const char16_t* chars, size_t length);
 
-MOZ_MUST_USE bool
-CompileLazyBinASTFunction(JSContext* cx, Handle<LazyScript*> lazy, const uint8_t* buf, size_t length);
-
 //
 // Compile a single function. The source in srcBuf must match the ECMA-262
 // FunctionExpression production.
 //
 // If nonzero, parameterListEnd is the offset within srcBuf where the parameter
 // list is expected to end. During parsing, if we find that it ends anywhere
 // else, it's a SyntaxError. This is used to implement the Function constructor;
 // it's how we detect that these weird cases are SyntaxErrors:
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -5748,24 +5748,18 @@ BytecodeEmitter::emitFunction(CodeNode* 
             Rooted<JSScript*> script(cx, JSScript::Create(cx, options, sourceObject,
                                                           funbox->bufStart, funbox->bufEnd,
                                                           funbox->toStringStart,
                                                           funbox->toStringEnd));
             if (!script) {
                 return false;
             }
 
-            EmitterMode nestedMode = emitterMode;
-            if (nestedMode == BytecodeEmitter::LazyFunction) {
-                MOZ_ASSERT(lazyScript->isBinAST());
-                nestedMode = BytecodeEmitter::Normal;
-            }
-
             BytecodeEmitter bce2(this, parser, funbox, script, /* lazyScript = */ nullptr,
-                                 funNode->pn_pos, nestedMode);
+                                 funNode->pn_pos, emitterMode);
             if (!bce2.init()) {
                 return false;
             }
 
             /* We measured the max scope depth when we parsed the function. */
             if (!bce2.emitFunctionScript(funNode, TopLevelFunction::No)) {
                 return false;
             }
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -672,11 +672,8 @@ MSG_DEF(JSMSG_RESPONSE_ALREADY_CONSUMED,
 MSG_DEF(JSMSG_BIGINT_TO_NUMBER, 0, JSEXN_TYPEERR, "can't convert BigInt to number")
 MSG_DEF(JSMSG_NUMBER_TO_BIGINT, 0, JSEXN_RANGEERR, "can't convert non-finite number to BigInt")
 MSG_DEF(JSMSG_BIGINT_TOO_LARGE, 0, JSEXN_RANGEERR, "BigInt is too large to allocate")
 MSG_DEF(JSMSG_BIGINT_DIVISION_BY_ZERO, 0, JSEXN_RANGEERR, "BigInt division by zero")
 MSG_DEF(JSMSG_BIGINT_NEGATIVE_EXPONENT, 0, JSEXN_RANGEERR, "BigInt negative exponent")
 MSG_DEF(JSMSG_BIGINT_INVALID_SYNTAX, 0, JSEXN_SYNTAXERR, "invalid BigInt syntax")
 MSG_DEF(JSMSG_NOT_BIGINT, 0, JSEXN_TYPEERR, "not a BigInt")
 MSG_DEF(JSMSG_BIGINT_NOT_SERIALIZABLE, 0, JSEXN_TYPEERR, "BigInt value can't be serialized in JSON")
-
-// BinAST
-MSG_DEF(JSMSG_BINAST,                                    1, JSEXN_SYNTAXERR, "BinAST Parsing Error: {0}")
--- a/js/src/jsapi-tests/testBinASTReader.cpp
+++ b/js/src/jsapi-tests/testBinASTReader.cpp
@@ -223,23 +223,17 @@ runTestFromPath(JSContext* cx, const cha
         CompileOptions binOptions(cx);
         binOptions.setFileAndLine(binPath.begin(), 0);
 
         frontend::UsedNameTracker binUsedNames(cx);
 
         frontend::Directives directives(false);
         frontend::GlobalSharedContext globalsc(cx, ScopeKind::Global, directives, false);
 
-        RootedScriptSourceObject sourceObj(cx, frontend::CreateScriptSourceObject(cx, binOptions,
-                                                   mozilla::Nothing()));
-        if (!sourceObj) {
-            MOZ_CRASH();
-        }
-
-        frontend::BinASTParser<Tok> binParser(cx, allocScope.alloc(), binUsedNames, binOptions, sourceObj);
+        frontend::BinASTParser<Tok> binParser(cx, allocScope.alloc(), binUsedNames, binOptions);
 
         auto binParsed = binParser.parse(&globalsc, binSource); // Will be deallocated once `reader` goes out of scope.
         RootedValue binExn(cx);
         if (binParsed.isErr()) {
             // Save exception for more detailed error message, if necessary.
             if (!js::GetAndClearException(cx, &binExn)) {
                 MOZ_CRASH("Couldn't clear binExn");
             }
--- a/js/src/jsapi-tests/testBinTokenReaderTester.cpp
+++ b/js/src/jsapi-tests/testBinTokenReaderTester.cpp
@@ -135,66 +135,66 @@ void readFull(const char* path, js::Vect
 }
 
 
 // Reading a simple string.
 BEGIN_TEST(testBinTokenReaderTesterSimpleString)
 {
     js::Vector<uint8_t> contents(cx);
     readFull("jsapi-tests/binast/tokenizer/tester/test-simple-string.binjs", contents);
-    Tokenizer tokenizer(cx, nullptr, contents);
+    Tokenizer tokenizer(cx, contents);
 
     Chars found(cx);
     CHECK(tokenizer.readChars(found).isOk());
 
     CHECK(Tokenizer::equals(found, "simple string")); // FIXME: Find a way to make CHECK_EQUAL use `Tokenizer::equals`.
 
     return true;
 }
 END_TEST(testBinTokenReaderTesterSimpleString)
 
 // Reading a string with embedded 0.
 BEGIN_TEST(testBinTokenReaderTesterStringWithEscapes)
 {
     js::Vector<uint8_t> contents(cx);
     readFull("jsapi-tests/binast/tokenizer/tester/test-string-with-escapes.binjs", contents);
-    Tokenizer tokenizer(cx, nullptr, contents);
+    Tokenizer tokenizer(cx, contents);
 
     Chars found(cx);
     CHECK(tokenizer.readChars(found).isOk());
 
     CHECK(Tokenizer::equals(found, "string with escapes \0\1\0")); // FIXME: Find a way to make CHECK_EQUAL use `Tokenizer::equals`.
 
     return true;
 }
 END_TEST(testBinTokenReaderTesterStringWithEscapes)
 
 // Reading an empty untagged tuple
 BEGIN_TEST(testBinTokenReaderTesterEmptyUntaggedTuple)
 {
     js::Vector<uint8_t> contents(cx);
     readFull("jsapi-tests/binast/tokenizer/tester/test-empty-untagged-tuple.binjs", contents);
-    Tokenizer tokenizer(cx, nullptr, contents);
+    Tokenizer tokenizer(cx, contents);
 
     {
         Tokenizer::AutoTuple guard(tokenizer);
         CHECK(tokenizer.enterUntaggedTuple(guard).isOk());
         CHECK(guard.done().isOk());
     }
 
     return true;
 }
 END_TEST(testBinTokenReaderTesterEmptyUntaggedTuple)
 
 // Reading a untagged tuple with two strings
 BEGIN_TEST(testBinTokenReaderTesterTwoStringsInTuple)
 {
     js::Vector<uint8_t> contents(cx);
     readFull("jsapi-tests/binast/tokenizer/tester/test-trivial-untagged-tuple.binjs", contents);
-    Tokenizer tokenizer(cx, nullptr, contents);
+    Tokenizer tokenizer(cx, contents);
 
     {
         Tokenizer::AutoTuple guard(tokenizer);
         CHECK(tokenizer.enterUntaggedTuple(guard).isOk());
 
         Chars found_0(cx);
         CHECK(tokenizer.readChars(found_0).isOk());
         CHECK(Tokenizer::equals(found_0, "foo")); // FIXME: Find a way to make CHECK_EQUAL use `Tokenizer::equals`.
@@ -210,17 +210,17 @@ BEGIN_TEST(testBinTokenReaderTesterTwoSt
 }
 END_TEST(testBinTokenReaderTesterTwoStringsInTuple)
 
 // Reading a tagged tuple `Pattern { id: "foo", value: 3.1415}`
 BEGIN_TEST(testBinTokenReaderTesterSimpleTaggedTuple)
 {
     js::Vector<uint8_t> contents(cx);
     readFull("jsapi-tests/binast/tokenizer/tester/test-simple-tagged-tuple.binjs", contents);
-    Tokenizer tokenizer(cx, nullptr, contents);
+    Tokenizer tokenizer(cx, contents);
 
     {
         js::frontend::BinKind tag;
         Tokenizer::BinFields fields(cx);
         Tokenizer::AutoTaggedTuple guard(tokenizer);
         CHECK(tokenizer.enterTaggedTuple(tag, fields, guard).isOk());
 
         CHECK(tag == js::frontend::BinKind::BindingIdentifier);
@@ -244,17 +244,17 @@ BEGIN_TEST(testBinTokenReaderTesterSimpl
 END_TEST(testBinTokenReaderTesterSimpleTaggedTuple)
 
 
 // Reading an empty list
 BEGIN_TEST(testBinTokenReaderTesterEmptyList)
 {
     js::Vector<uint8_t> contents(cx);
     readFull("jsapi-tests/binast/tokenizer/tester/test-empty-list.binjs", contents);
-    Tokenizer tokenizer(cx, nullptr, contents);
+    Tokenizer tokenizer(cx, contents);
 
     {
         uint32_t length;
         Tokenizer::AutoList guard(tokenizer);
         CHECK(tokenizer.enterList(length, guard).isOk());
 
         CHECK(length == 0);
         CHECK(guard.done().isOk());
@@ -264,17 +264,17 @@ BEGIN_TEST(testBinTokenReaderTesterEmpty
 }
 END_TEST(testBinTokenReaderTesterEmptyList)
 
 // Reading `["foo", "bar"]`
 BEGIN_TEST(testBinTokenReaderTesterSimpleList)
 {
     js::Vector<uint8_t> contents(cx);
     readFull("jsapi-tests/binast/tokenizer/tester/test-trivial-list.binjs", contents);
-    Tokenizer tokenizer(cx, nullptr, contents);
+    Tokenizer tokenizer(cx, contents);
 
     {
         uint32_t length;
         Tokenizer::AutoList guard(tokenizer);
         CHECK(tokenizer.enterList(length, guard).isOk());
 
         CHECK(length == 2);
 
@@ -294,17 +294,17 @@ BEGIN_TEST(testBinTokenReaderTesterSimpl
 END_TEST(testBinTokenReaderTesterSimpleList)
 
 
 // Reading `[["foo", "bar"]]`
 BEGIN_TEST(testBinTokenReaderTesterNestedList)
 {
     js::Vector<uint8_t> contents(cx);
     readFull("jsapi-tests/binast/tokenizer/tester/test-nested-lists.binjs", contents);
-    Tokenizer tokenizer(cx, nullptr, contents);
+    Tokenizer tokenizer(cx, contents);
 
     {
         uint32_t outerLength;
         Tokenizer::AutoList outerGuard(tokenizer);
         CHECK(tokenizer.enterList(outerLength, outerGuard).isOk());
         CHECK_EQUAL(outerLength, (uint32_t)1);
 
         {
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -4097,17 +4097,17 @@ JS_DecompileScript(JSContext* cx, Handle
 
     AssertHeapIsIdle();
     CHECK_THREAD(cx);
     script->ensureNonLazyCanonicalFunction();
     RootedFunction fun(cx, script->functionNonDelazifying());
     if (fun) {
         return JS_DecompileFunction(cx, fun);
     }
-    bool haveSource = script->scriptSource()->hasSourceText();
+    bool haveSource = script->scriptSource()->hasSourceData();
     if (!haveSource && !JSScript::loadSource(cx, script->scriptSource(), &haveSource)) {
         return nullptr;
     }
     return haveSource ? JSScript::sourceData(cx, script)
                       : NewStringCopyZ<CanGC>(cx, "[no source]");
 }
 
 JS_PUBLIC_API(JSString*)
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -703,17 +703,16 @@ if CONFIG['JS_BUILD_BINAST']:
     # Using SOURCES, as UNIFIED_SOURCES causes mysterious bugs on 32-bit platforms.
     # These parts of BinAST are designed only to test evolutions of the
     # specification.
     SOURCES += ['frontend/BinTokenReaderTester.cpp']
     # These parts of BinAST should eventually move to release.
     SOURCES += [
         'frontend/BinSource-auto.cpp',
         'frontend/BinSource.cpp',
-        'frontend/BinSourceRuntimeSupport.cpp',
         'frontend/BinToken.cpp',
         'frontend/BinTokenReaderBase.cpp',
         'frontend/BinTokenReaderMultipart.cpp',
     ]
 
     # Instrument BinAST files for fuzzing as we have a fuzzing target for BinAST.
     if CONFIG['FUZZING_INTERFACES'] and CONFIG['LIBFUZZER']:
         SOURCES['frontend/BinSource-auto.cpp'].flags += libfuzzer_flags
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -5072,23 +5072,22 @@ using js::frontend::Directives;
 using js::frontend::GlobalSharedContext;
 using js::frontend::ParseNode;
 using js::frontend::UsedNameTracker;
 
 template <typename Tok>
 static bool
 ParseBinASTData(JSContext* cx, uint8_t* buf_data, uint32_t buf_length,
                 GlobalSharedContext* globalsc, UsedNameTracker& usedNames,
-                const JS::ReadOnlyCompileOptions& options,
-                HandleScriptSourceObject sourceObj)
+                const JS::ReadOnlyCompileOptions& options)
 {
     MOZ_ASSERT(globalsc);
 
     // Note: We need to keep `reader` alive as long as we can use `parsed`.
-    BinASTParser<Tok> reader(cx, cx->tempLifoAlloc(), usedNames, options, sourceObj);
+    BinASTParser<Tok> reader(cx, cx->tempLifoAlloc(), usedNames, options);
 
     JS::Result<ParseNode*> parsed = reader.parse(globalsc, buf_data, buf_length);
 
     if (parsed.isErr())
         return false;
 
 #ifdef DEBUG
     Fprinter out(stderr);
@@ -5179,27 +5178,22 @@ BinParse(JSContext* cx, unsigned argc, V
 
 
     CompileOptions options(cx);
     options.setIntroductionType("js shell bin parse")
            .setFileAndLine("<ArrayBuffer>", 1);
 
     UsedNameTracker usedNames(cx);
 
-    RootedScriptSourceObject sourceObj(cx, frontend::CreateScriptSourceObject(cx, options, Nothing()));
-    if (!sourceObj) {
-        return false;
-    }
-
     Directives directives(false);
     GlobalSharedContext globalsc(cx, ScopeKind::Global, directives, false);
 
     auto parseFunc = useMultipart ? ParseBinASTData<frontend::BinTokenReaderMultipart>
                                   : ParseBinASTData<frontend::BinTokenReaderTester>;
-    if (!parseFunc(cx, buf_data, buf_length, &globalsc, usedNames, options, sourceObj)) {
+    if (!parseFunc(cx, buf_data, buf_length, &globalsc, usedNames, options)) {
         return false;
     }
 
     args.rval().setUndefined();
     return true;
 }
 
 #endif // defined(JS_BUILD_BINAST)
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -7795,21 +7795,21 @@ class DebuggerSourceGetTextMatcher
 
   public:
     explicit DebuggerSourceGetTextMatcher(JSContext* cx) : cx_(cx) { }
 
     using ReturnType = JSString*;
 
     ReturnType match(HandleScriptSourceObject sourceObject) {
         ScriptSource* ss = sourceObject->source();
-        bool hasSourceText = ss->hasSourceText();
-        if (!ss->hasSourceText() && !JSScript::loadSource(cx_, ss, &hasSourceText)) {
+        bool hasSourceData = ss->hasSourceData();
+        if (!ss->hasSourceData() && !JSScript::loadSource(cx_, ss, &hasSourceData)) {
             return nullptr;
         }
-        if (!hasSourceText) {
+        if (!hasSourceData) {
             return NewStringCopyZ<CanGC>(cx_, "[no source]");
         }
 
         if (ss->isFunctionBody()) {
             return ss->functionBodyString(cx_);
         }
 
         return ss->substring(cx_, 0, ss->length());
--- a/js/src/vm/HelperThreads.cpp
+++ b/js/src/vm/HelperThreads.cpp
@@ -925,19 +925,16 @@ js::StartOffThreadDecodeMultiScripts(JSC
 
 #if defined(JS_BUILD_BINAST)
 
 bool
 js::StartOffThreadDecodeBinAST(JSContext* cx, const ReadOnlyCompileOptions& options,
                                const uint8_t* buf, size_t length,
                                JS::OffThreadCompileCallback callback, void *callbackData)
 {
-    if (!cx->runtime()->binast().ensureBinTablesInitialized(cx))
-        return false;
-
     auto task = cx->make_unique<BinASTDecodeTask>(cx, buf, length, callback, callbackData);
     if (!task || !StartOffThreadParseTask(cx, task.get(), options)) {
         return false;
     }
 
     Unused << task.release();
     return true;
 }
--- a/js/src/vm/JSFunction.cpp
+++ b/js/src/vm/JSFunction.cpp
@@ -1046,17 +1046,17 @@ js::FunctionToString(JSContext* cx, Hand
     // all class constructors always have source.
     bool haveSource = fun->isInterpreted() && (fun->isClassConstructor() ||
                                                !fun->isSelfHostedBuiltin());
 
     // If we're in toSource mode, put parentheses around lambda functions so
     // that eval returns lambda, not function statement.
     bool addParentheses = haveSource && isToSource && (fun->isLambda() && !fun->isArrow());
 
-    if (haveSource && !script->scriptSource()->hasSourceText() &&
+    if (haveSource && !script->scriptSource()->hasSourceData() &&
         !JSScript::loadSource(cx, script->scriptSource(), &haveSource))
     {
         return nullptr;
     }
 
     // Fast path for the common case, to avoid StringBuffer overhead.
     if (!addParentheses && haveSource) {
         FunctionToStringCache& cache = cx->zone()->functionToStringCache();
@@ -1745,17 +1745,16 @@ JSFunction::createScriptForLazilyInterpr
 
         // Only functions without inner functions or direct eval are
         // re-lazified. Functions with either of those are on the static scope
         // chain of their inner functions, or in the case of eval, possibly
         // eval'd inner functions. This prohibits re-lazification as
         // StaticScopeIter queries needsCallObject of those functions, which
         // requires a non-lazy script.  Note that if this ever changes,
         // XDRRelazificationInfo will have to be fixed.
-        bool isBinAST = lazy->scriptSource()->hasBinASTSource();
         bool canRelazify = !lazy->numInnerFunctions() && !lazy->hasDirectEval();
 
         if (script) {
             // This function is non-canonical function, and the canonical
             // function is already delazified.
             fun->setUnlazifiedScript(script);
             // Remember the lazy script on the compiled script, so it can be
             // stored on the function again in case of re-lazification.
@@ -1779,48 +1778,34 @@ JSFunction::createScriptForLazilyInterpr
             }
 
             fun->setUnlazifiedScript(script);
             return true;
         }
 
         // This is lazy canonical-function.
 
+        MOZ_ASSERT(lazy->scriptSource()->hasSourceData());
+
+        // Parse and compile the script from source.
         size_t lazyLength = lazy->sourceEnd() - lazy->sourceStart();
-        if (isBinAST) {
-#if defined(JS_BUILD_BINAST)
-            if (!frontend::CompileLazyBinASTFunction(cx, lazy,
-                    lazy->scriptSource()->binASTSource() + lazy->sourceStart(), lazyLength))
-            {
-                MOZ_ASSERT(fun->isInterpretedLazy());
-                MOZ_ASSERT(fun->lazyScript() == lazy);
-                MOZ_ASSERT(!lazy->hasScript());
-                return false;
-            }
-#else
-            MOZ_CRASH("Trying to delazify BinAST function in non-BinAST build");
-#endif /*JS_BUILD_BINAST */
-        } else {
-            MOZ_ASSERT(lazy->scriptSource()->hasSourceText());
-
-            // Parse and compile the script from source.
-            UncompressedSourceCache::AutoHoldEntry holder;
-            ScriptSource::PinnedChars chars(cx, lazy->scriptSource(), holder,
-                                            lazy->sourceStart(), lazyLength);
-            if (!chars.get())
-                return false;
-
-            if (!frontend::CompileLazyFunction(cx, lazy, chars.get(), lazyLength)) {
-		// The frontend shouldn't fail after linking the function and the
-		// non-lazy script together.
-                MOZ_ASSERT(fun->isInterpretedLazy());
-                MOZ_ASSERT(fun->lazyScript() == lazy);
-                MOZ_ASSERT(!lazy->hasScript());
-                return false;
-            }
+        UncompressedSourceCache::AutoHoldEntry holder;
+        ScriptSource::PinnedChars chars(cx, lazy->scriptSource(), holder,
+                                        lazy->sourceStart(), lazyLength);
+        if (!chars.get()) {
+            return false;
+        }
+
+        if (!frontend::CompileLazyFunction(cx, lazy, chars.get(), lazyLength)) {
+            // The frontend shouldn't fail after linking the function and the
+            // non-lazy script together.
+            MOZ_ASSERT(fun->isInterpretedLazy());
+            MOZ_ASSERT(fun->lazyScript() == lazy);
+            MOZ_ASSERT(!lazy->hasScript());
+            return false;
         }
 
         script = fun->nonLazyScript();
 
         // Remember the compiled script on the lazy script itself, in case
         // there are clones of the function still pointing to the lazy script.
         if (!lazy->maybeScript()) {
             lazy->initScript(script);
--- a/js/src/vm/JSScript.cpp
+++ b/js/src/vm/JSScript.cpp
@@ -1439,38 +1439,28 @@ JSScript::hasScriptName()
 void
 ScriptSourceObject::finalize(FreeOp* fop, JSObject* obj)
 {
     MOZ_ASSERT(fop->onMainThread());
     ScriptSourceObject* sso = &obj->as<ScriptSourceObject>();
     sso->source()->decref();
 }
 
-void
-ScriptSourceObject::trace(JSTracer* trc, JSObject* obj)
-{
-    // This can be invoked during allocation of the SSO itself, before we've had a chance
-    // to initialize things properly. In that case, there's nothing to trace.
-    if (obj->as<ScriptSourceObject>().hasSource()) {
-        obj->as<ScriptSourceObject>().source()->trace(trc);
-    }
-}
-
 static const ClassOps ScriptSourceObjectClassOps = {
     nullptr, /* addProperty */
     nullptr, /* delProperty */
     nullptr, /* enumerate */
     nullptr, /* newEnumerate */
     nullptr, /* resolve */
     nullptr, /* mayResolve */
     ScriptSourceObject::finalize,
     nullptr, /* call */
     nullptr, /* hasInstance */
     nullptr, /* construct */
-    ScriptSourceObject::trace
+    nullptr  /* trace */
 };
 
 const Class ScriptSourceObject::class_ = {
     "ScriptSource",
     JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS) |
     JSCLASS_IS_ANONYMOUS |
     JSCLASS_FOREGROUND_FINALIZE,
     &ScriptSourceObjectClassOps
@@ -1548,17 +1538,17 @@ ScriptSourceObject::initElementPropertie
     source->setReservedSlot(ELEMENT_PROPERTY_SLOT, nameValue);
 
     return true;
 }
 
 /* static */ bool
 JSScript::loadSource(JSContext* cx, ScriptSource* ss, bool* worked)
 {
-    MOZ_ASSERT(!ss->hasSourceText());
+    MOZ_ASSERT(!ss->hasSourceData());
     *worked = false;
     if (!cx->runtime()->sourceHook.ref() || !ss->sourceRetrievable()) {
         return true;
     }
     char16_t* src = nullptr;
     size_t length;
     if (!cx->runtime()->sourceHook->load(cx, ss->filename(), &src, &length)) {
         return false;
@@ -1572,24 +1562,24 @@ JSScript::loadSource(JSContext* cx, Scri
 
     *worked = true;
     return true;
 }
 
 /* static */ JSFlatString*
 JSScript::sourceData(JSContext* cx, HandleScript script)
 {
-    MOZ_ASSERT(script->scriptSource()->hasSourceText());
+    MOZ_ASSERT(script->scriptSource()->hasSourceData());
     return script->scriptSource()->substring(cx, script->sourceStart(), script->sourceEnd());
 }
 
 bool
 JSScript::appendSourceDataForToString(JSContext* cx, StringBuffer& buf)
 {
-    MOZ_ASSERT(scriptSource()->hasSourceText());
+    MOZ_ASSERT(scriptSource()->hasSourceData());
     return scriptSource()->appendSubstring(cx, buf, toStringStart(), toStringEnd());
 }
 
 UncompressedSourceCache::AutoHoldEntry::AutoHoldEntry()
   : cache_(nullptr), sourceChunk_()
 {
 }
 
@@ -1941,55 +1931,16 @@ ScriptSource::setSource(JSContext* cx, U
     if (!deduped) {
         ReportOutOfMemory(cx);
         return false;
     }
     setSource(std::move(*deduped));
     return true;
 }
 
-#if defined(JS_BUILD_BINAST)
-
-MOZ_MUST_USE bool
-ScriptSource::setBinASTSourceCopy(JSContext* cx, const uint8_t* buf, size_t len)
-{
-    auto &cache = cx->zone()->runtimeFromAnyThread()->sharedImmutableStrings();
-    auto deduped = cache.getOrCreate(reinterpret_cast<const char *>(buf), len);
-    if (!deduped) {
-        ReportOutOfMemory(cx);
-        return false;
-    }
-    MOZ_ASSERT(data.is<Missing>());
-    data = SourceType(BinAST(std::move(*deduped)));
-    return true;
-}
-
-MOZ_MUST_USE bool
-ScriptSource::setBinASTSource(JSContext* cx, UniqueChars&& buf, size_t len)
-{
-    auto& cache = cx->zone()->runtimeFromAnyThread()->sharedImmutableStrings();
-    auto deduped = cache.getOrCreate(std::move(buf), len);
-    if (!deduped) {
-        ReportOutOfMemory(cx);
-        return false;
-    }
-    MOZ_ASSERT(data.is<Missing>());
-    data = SourceType(BinAST(std::move(*deduped)));
-    return true;
-}
-
-const uint8_t*
-ScriptSource::binASTSource()
-{
-    MOZ_ASSERT(hasBinASTSource());
-    return reinterpret_cast<const uint8_t*>(data.as<BinAST>().string.chars());
-}
-
-#endif /* JS_BUILD_BINAST */
-
 void
 ScriptSource::setSource(SharedImmutableTwoByteString&& string)
 {
     MOZ_ASSERT(data.is<Missing>());
     data = SourceType(Uncompressed(std::move(string)));
 }
 
 bool
@@ -2065,17 +2016,17 @@ ScriptSource::setCompressedSource(Shared
     } else {
         data = SourceType(Compressed(std::move(raw), uncompressedLength));
     }
 }
 
 bool
 ScriptSource::setSourceCopy(JSContext* cx, SourceBufferHolder& srcBuf)
 {
-    MOZ_ASSERT(!hasSourceText());
+    MOZ_ASSERT(!hasSourceData());
 
     JSRuntime* runtime = cx->zone()->runtimeFromAnyThread();
     auto& cache = runtime->sharedImmutableStrings();
     auto deduped = cache.getOrCreate(srcBuf.get(), srcBuf.length(), [&]() {
         return srcBuf.ownsChars()
                ? UniqueTwoByteChars(srcBuf.take())
                : DuplicateString(srcBuf.get(), srcBuf.length());
     });
@@ -2083,24 +2034,16 @@ ScriptSource::setSourceCopy(JSContext* c
         ReportOutOfMemory(cx);
         return false;
     }
     setSource(std::move(*deduped));
 
     return true;
 }
 
-void
-ScriptSource::trace(JSTracer* trc)
-{
-    if (binASTMetadata_) {
-        binASTMetadata_->trace(trc);
-    }
-}
-
 static MOZ_MUST_USE bool
 reallocUniquePtr(UniqueChars& unique, size_t size)
 {
     auto newPtr = static_cast<char*>(js_realloc(unique.get(), size));
     if (!newPtr) {
         return false;
     }
 
@@ -2291,167 +2234,82 @@ ScriptSource::performXDR(XDRState<mode>*
         size_t match(Uncompressed&) {
             return 0;
         }
 
         size_t match(Compressed& c) {
             return c.raw.length();
         }
 
-        size_t match(BinAST&) {
-            return 0;
-        }
-
         size_t match(Missing&) {
             MOZ_CRASH("Missing source data in ScriptSource::performXDR");
             return 0;
         }
     };
 
     struct RawDataMatcher
     {
         void* match(Uncompressed& u) {
             return (void*) u.string.chars();
         }
 
         void* match(Compressed& c) {
             return (void*) c.raw.chars();
         }
 
-        void* match(BinAST& b) {
-            return (void*) b.string.chars();
-        }
-
         void* match(Missing&) {
             MOZ_CRASH("Missing source data in ScriptSource::performXDR");
             return nullptr;
         }
     };
 
-    uint8_t hasSource = hasSourceText();
+    uint8_t hasSource = hasSourceData();
     MOZ_TRY(xdr->codeUint8(&hasSource));
 
-    uint8_t hasBinSource = hasBinASTSource();
-    MOZ_TRY(xdr->codeUint8(&hasBinSource));
-
     uint8_t retrievable = sourceRetrievable_;
     MOZ_TRY(xdr->codeUint8(&retrievable));
     sourceRetrievable_ = retrievable;
 
-    if ((hasSource || hasBinSource) && !sourceRetrievable_) {
+    if (hasSource && !sourceRetrievable_) {
         uint32_t len = 0;
         if (mode == XDR_ENCODE) {
             len = length();
         }
         MOZ_TRY(xdr->codeUint32(&len));
 
         uint32_t compressedLength;
         if (mode == XDR_ENCODE) {
             CompressedLengthMatcher m;
             compressedLength = data.match(m);
         }
         MOZ_TRY(xdr->codeUint32(&compressedLength));
 
-        size_t byteLen = hasBinSource ? len : compressedLength ? compressedLength : (len * sizeof(char16_t));
+        size_t byteLen = compressedLength ? compressedLength : (len * sizeof(char16_t));
         if (mode == XDR_DECODE) {
             auto bytes = xdr->cx()->template make_pod_array<char>(Max<size_t>(byteLen, 1));
             if (!bytes) {
                 return xdr->fail(JS::TranscodeResult_Throw);
             }
             MOZ_TRY(xdr->codeBytes(bytes.get(), byteLen));
 
-            if (hasBinSource) {
-#if defined(JS_BUILD_BINAST)
-                if (!setBinASTSource(xdr->cx(), std::move(bytes), len)) {
-                    return xdr->fail(JS::TranscodeResult_Throw);
-                }
-#else
-                return xdr->fail(JS::TranscodeResult_Error);
-#endif /* JS_BUILD_BINAST */
-            } else if (compressedLength) {
+            if (compressedLength) {
                 if (!setCompressedSource(xdr->cx(), std::move(bytes), byteLen, len)) {
                     return xdr->fail(JS::TranscodeResult_Throw);
                 }
             } else {
                 UniqueTwoByteChars source(reinterpret_cast<char16_t*>(bytes.release()));
                 if (!setSource(xdr->cx(), std::move(source), len)) {
                     return xdr->fail(JS::TranscodeResult_Throw);
                 }
             }
         } else {
             RawDataMatcher rdm;
             void* p = data.match(rdm);
             MOZ_TRY(xdr->codeBytes(p, byteLen));
         }
-
-        uint8_t hasMetadata = !!binASTMetadata_;
-        MOZ_TRY(xdr->codeUint8(&hasMetadata));
-        if (hasMetadata) {
-            uint32_t numBinKinds;
-            uint32_t numStrings;
-            if (mode == XDR_ENCODE) {
-                numBinKinds = binASTMetadata_->numBinKinds();
-                numStrings = binASTMetadata_->numStrings();
-            }
-            MOZ_TRY(xdr->codeUint32(&numBinKinds));
-            MOZ_TRY(xdr->codeUint32(&numStrings));
-
-            if (mode == XDR_DECODE) {
-                // Use calloc, since we're storing this immediately, and filling it might GC, to
-                // avoid marking bogus atoms.
-                setBinASTSourceMetadata(
-                    static_cast<frontend::BinASTSourceMetadata*>(
-                        js_calloc(frontend::BinASTSourceMetadata::totalSize(numBinKinds, numStrings))));
-                if (!binASTMetadata_) {
-                    return xdr->fail(JS::TranscodeResult_Throw);
-                }
-            }
-
-            for (uint32_t i = 0; i < numBinKinds; i++) {
-                frontend::BinKind* binKindBase = binASTMetadata_->binKindBase();
-                MOZ_TRY(xdr->codeEnum32(&binKindBase[i]));
-            }
-
-            RootedAtom atom(xdr->cx());
-            JSAtom** atomsBase = binASTMetadata_->atomsBase();
-            auto slices = binASTMetadata_->sliceBase();
-            auto sourceBase = reinterpret_cast<const char*>(binASTSource());
-
-            for (uint32_t i = 0; i < numStrings; i++) {
-                uint8_t isNull;
-                if (mode == XDR_ENCODE) {
-                    atom = binASTMetadata_->getAtom(i);
-                    isNull = !atom;
-                }
-                MOZ_TRY(xdr->codeUint8(&isNull));
-                if (isNull) {
-                    atom = nullptr;
-                } else {
-                    MOZ_TRY(XDRAtom(xdr, &atom));
-                }
-                if (mode == XDR_DECODE) {
-                    atomsBase[i] = atom;
-                }
-
-                uint64_t sliceOffset;
-                uint32_t sliceLen;
-                if (mode == XDR_ENCODE) {
-                    auto &slice = binASTMetadata_->getSlice(i);
-                    sliceOffset = slice.begin()-sourceBase;
-                    sliceLen = slice.byteLen_;
-                }
-
-                MOZ_TRY(xdr->codeUint64(&sliceOffset));
-                MOZ_TRY(xdr->codeUint32(&sliceLen));
-
-                if (mode == XDR_DECODE) {
-                    new (&slices[i]) frontend::BinASTSourceMetadata::CharSlice(sourceBase + sliceOffset, sliceLen);
-                }
-            }
-        }
     }
 
     uint8_t haveSourceMap = hasSourceMapURL();
     MOZ_TRY(xdr->codeUint8(&haveSourceMap));
 
     if (haveSourceMap) {
         uint32_t sourceMapURLLen = (mode == XDR_DECODE) ? 0 : js_strlen(sourceMapURL_.get());
         MOZ_TRY(xdr->codeUint32(&sourceMapURLLen));
@@ -2504,17 +2362,17 @@ ScriptSource::performXDR(XDRState<mode>*
         // Note: If the decoder has an option, then the filename is defined by
         // the CompileOption from the document.
         MOZ_ASSERT_IF(mode == XDR_DECODE && xdr->hasOptions(), filename());
         if (mode == XDR_DECODE && !xdr->hasOptions() && !setFilename(xdr->cx(), fn)) {
             return xdr->fail(JS::TranscodeResult_Throw);
         }
 
         // Note the content of sources decoded when recording or replaying.
-        if (mode == XDR_DECODE && hasSourceText() && mozilla::recordreplay::IsRecordingOrReplaying()) {
+        if (mode == XDR_DECODE && hasSourceData() && mozilla::recordreplay::IsRecordingOrReplaying()) {
             UncompressedSourceCache::AutoHoldEntry holder;
             ScriptSource::PinnedChars chars(xdr->cx(), this, holder, 0, length());
             if (!chars.get()) {
                 return xdr->fail(JS::TranscodeResult_Throw);
             }
             mozilla::recordreplay::NoteContentParse(this, filename(), "application/javascript",
                                                     chars.get(), length());
         }
@@ -4743,17 +4601,16 @@ LazyScript::Create(JSContext* cx, Handle
     p.isGenerator = false;
     p.strict = false;
     p.bindingsAccessedDynamically = false;
     p.hasDebuggerStatement = false;
     p.hasDirectEval = false;
     p.isLikelyConstructorWrapper = false;
     p.isDerivedClassConstructor = false;
     p.needsHomeObject = false;
-    p.isBinAST = false;
     p.parseGoal = uint32_t(parseGoal);
 
     LazyScript* res = LazyScript::CreateRaw(cx, fun, sourceObject, packedFields,
                                             sourceStart, sourceEnd,
                                             toStringStart, lineno, column);
     if (!res) {
         return nullptr;
     }
--- a/js/src/vm/JSScript.h
+++ b/js/src/vm/JSScript.h
@@ -13,17 +13,16 @@
 #include "mozilla/Atomics.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/Span.h"
 #include "mozilla/Variant.h"
 
 #include "jstypes.h"
 
-#include "frontend/BinSourceRuntimeSupport.h"
 #include "frontend/NameAnalysisTypes.h"
 #include "gc/Barrier.h"
 #include "gc/Rooting.h"
 #include "jit/IonCode.h"
 #include "js/CompileOptions.h"
 #include "js/UbiNode.h"
 #include "js/UniquePtr.h"
 #include "vm/BytecodeUtil.h"
@@ -426,25 +425,17 @@ class ScriptSource
         size_t uncompressedLength;
 
         Compressed(SharedImmutableString&& raw, size_t uncompressedLength)
           : raw(std::move(raw))
           , uncompressedLength(uncompressedLength)
         { }
     };
 
-    struct BinAST
-    {
-        SharedImmutableString string;
-        explicit BinAST(SharedImmutableString&& str)
-          : string(std::move(str))
-        { }
-    };
-
-    using SourceType = mozilla::Variant<Missing, Uncompressed, Compressed, BinAST>;
+    using SourceType = mozilla::Variant<Missing, Uncompressed, Compressed>;
     SourceType data;
 
     // If the GC attempts to call setCompressedSource with PinnedChars
     // present, the first PinnedChars (that is, bottom of the stack) will set
     // the compressed chars upon destruction.
     PinnedChars* pinnedCharsStack_;
     mozilla::Maybe<Compressed> pendingCompressed_;
 
@@ -499,24 +490,22 @@ class ScriptSource
     // if the source hasn't been parsed yet.
     //
     // Used for statistics purposes, to determine how much time code spends
     // syntax parsed before being full parsed, to help determine whether
     // our syntax parse vs. full parse heuristics are correct.
     mozilla::TimeStamp parseEnded_;
 
     // True if we can call JSRuntime::sourceHook to load the source on
-    // demand. If sourceRetrievable_ and hasSourceText() are false, it is not
+    // demand. If sourceRetrievable_ and hasSourceData() are false, it is not
     // possible to get source at all.
     bool sourceRetrievable_:1;
     bool hasIntroductionOffset_:1;
     bool containsAsmJS_:1;
 
-    UniquePtr<frontend::BinASTSourceMetadata> binASTMetadata_;
-
     const char16_t* chunkChars(JSContext* cx, UncompressedSourceCache::AutoHoldEntry& holder,
                                size_t chunk);
 
     // Return a string containing the chars starting at |begin| and ending at
     // |begin + len|.
     //
     // Warning: this is *not* GC-safe! Any chars to be handed out should use
     // PinnedChars. See comment below.
@@ -561,52 +550,38 @@ class ScriptSource
         }
     }
     MOZ_MUST_USE bool initFromOptions(JSContext* cx,
                                       const JS::ReadOnlyCompileOptions& options,
                                       const mozilla::Maybe<uint32_t>& parameterListEnd = mozilla::Nothing());
     MOZ_MUST_USE bool setSourceCopy(JSContext* cx, JS::SourceBufferHolder& srcBuf);
     void setSourceRetrievable() { sourceRetrievable_ = true; }
     bool sourceRetrievable() const { return sourceRetrievable_; }
-    bool hasSourceText() const { return hasUncompressedSource() || hasCompressedSource(); }
-    bool hasBinASTSource() const { return data.is<BinAST>(); }
+    bool hasSourceData() const { return !data.is<Missing>(); }
     bool hasUncompressedSource() const { return data.is<Uncompressed>(); }
     bool hasCompressedSource() const { return data.is<Compressed>(); }
 
-    void setBinASTSourceMetadata(frontend::BinASTSourceMetadata* metadata) {
-        MOZ_ASSERT(hasBinASTSource());
-        binASTMetadata_.reset(metadata);
-    }
-    frontend::BinASTSourceMetadata* binASTSourceMetadata() const {
-        MOZ_ASSERT(hasBinASTSource());
-        return binASTMetadata_.get();
-    }
-
     size_t length() const {
         struct LengthMatcher
         {
             size_t match(const Uncompressed& u) {
                 return u.string.length();
             }
 
             size_t match(const Compressed& c) {
                 return c.uncompressedLength;
             }
 
-            size_t match(const BinAST& b) {
-                return b.string.length();
-            }
-
             size_t match(const Missing& m) {
                 MOZ_CRASH("ScriptSource::length on a missing source");
                 return 0;
             }
         };
 
-        MOZ_ASSERT(hasSourceText() || hasBinASTSource());
+        MOZ_ASSERT(hasSourceData());
         return data.match(LengthMatcher());
     }
 
     JSFlatString* substring(JSContext* cx, size_t start, size_t stop);
     JSFlatString* substringDontDeflate(JSContext* cx, size_t start, size_t stop);
 
     MOZ_MUST_USE bool appendSubstring(JSContext* cx, js::StringBuffer& buf, size_t start, size_t stop);
 
@@ -626,35 +601,16 @@ class ScriptSource
     MOZ_MUST_USE bool tryCompressOffThread(JSContext* cx);
 
     MOZ_MUST_USE bool setCompressedSource(JSContext* cx,
                                           UniqueChars&& raw,
                                           size_t rawLength,
                                           size_t sourceLength);
     void setCompressedSource(SharedImmutableString&& raw, size_t sourceLength);
 
-#if defined(JS_BUILD_BINAST)
-
-    /*
-     * Do not take ownership of the given `buf`. Store the canonical, shared
-     * and de-duplicated version. If there is no extant shared version of
-     * `buf`, make a copy.
-     */
-    MOZ_MUST_USE bool setBinASTSourceCopy(JSContext* cx, const uint8_t* buf, size_t len);
-
-    /*
-     * Take ownership of the given `buf` and return the canonical, shared and
-     * de-duplicated version.
-     */
-    MOZ_MUST_USE bool setBinASTSource(JSContext* cx, UniqueChars&& buf, size_t len);
-
-    const uint8_t* binASTSource();
-
-#endif /* JS_BUILD_BINAST */
-
     // XDR handling
     template <XDRMode mode>
     MOZ_MUST_USE XDRResult performXDR(XDRState<mode>* xdr);
 
     MOZ_MUST_USE bool setFilename(JSContext* cx, const char* filename);
     const char* introducerFilename() const {
         return introducerFilename_ ? introducerFilename_.get() : filename_.get();
     }
@@ -730,18 +686,16 @@ class ScriptSource
     const mozilla::TimeStamp parseEnded() const {
         return parseEnded_;
     }
     // Inform `this` source that it has been fully parsed.
     void recordParseEnded() {
         MOZ_ASSERT(parseEnded_.IsNull());
         parseEnded_ = ReallyNow();
     }
-
-    void trace(JSTracer* trc);
 };
 
 class ScriptSourceHolder
 {
     ScriptSource* ss;
   public:
     ScriptSourceHolder()
       : ss(nullptr)
@@ -786,19 +740,16 @@ class ScriptSourceObject : public Native
     // Initialize those properties of this ScriptSourceObject whose values
     // are provided by |options|, re-wrapping as necessary.
     static bool initFromOptions(JSContext* cx, HandleScriptSourceObject source,
                                 const JS::ReadOnlyCompileOptions& options);
 
     static bool initElementProperties(JSContext* cx, HandleScriptSourceObject source,
                                       HandleObject element, HandleString elementAttrName);
 
-    bool hasSource() const {
-        return !getReservedSlot(SOURCE_SLOT).isUndefined();
-    }
     ScriptSource* source() const {
         return static_cast<ScriptSource*>(getReservedSlot(SOURCE_SLOT).toPrivate());
     }
     JSObject* element() const {
         return getReservedSlot(ELEMENT_SLOT).toObjectOrNull();
     }
     const Value& elementAttributeName() const {
         MOZ_ASSERT(!getReservedSlot(ELEMENT_PROPERTY_SLOT).isMagic());
@@ -2354,17 +2305,16 @@ class LazyScript : public gc::TenuredCel
   private:
     static const uint32_t NumClosedOverBindingsBits = 20;
     static const uint32_t NumInnerFunctionsBits = 20;
 
     struct PackedView {
         uint32_t shouldDeclareArguments : 1;
         uint32_t hasThisBinding : 1;
         uint32_t isAsync : 1;
-        uint32_t isBinAST : 1;
 
         uint32_t numClosedOverBindings : NumClosedOverBindingsBits;
 
         // -- 32bit boundary --
 
         uint32_t numInnerFunctions : NumInnerFunctionsBits;
 
         // N.B. These are booleans but need to be uint32_t to pack correctly on MSVC.
@@ -2543,23 +2493,16 @@ class LazyScript : public gc::TenuredCel
     void setHasRest() {
         p_.hasRest = true;
     }
 
     frontend::ParseGoal parseGoal() const {
         return frontend::ParseGoal(p_.parseGoal);
     }
 
-    bool isBinAST() const {
-        return p_.isBinAST;
-    }
-    void setIsBinAST() {
-        p_.isBinAST = true;
-    }
-
     bool strict() const {
         return p_.strict;
     }
     void setStrict() {
         p_.strict = true;
     }
 
     bool bindingsAccessedDynamically() const {
--- a/js/src/vm/OffThreadScriptCompilation.cpp
+++ b/js/src/vm/OffThreadScriptCompilation.cpp
@@ -32,16 +32,21 @@ enum class OffThread
 static bool
 CanDoOffThread(JSContext* cx, const ReadOnlyCompileOptions& options, size_t length, OffThread what)
 {
     static const size_t TINY_LENGTH = 5 * 1000;
     static const size_t HUGE_SRC_LENGTH = 100 * 1000;
     static const size_t HUGE_BC_LENGTH = 367 * 1000;
     static const size_t HUGE_BINAST_LENGTH = 70 * 1000;
 
+    // TODO: We can't decode BinAST off main thread until bug 1459555 is fixed.
+    if (what == OffThread::DecodeBinAST) {
+        return false;
+    }
+
     // These are heuristics which the caller may choose to ignore (e.g., for
     // testing purposes).
     if (!options.forceAsync) {
         // Compiling off the main thread inolves creating a new Zone and other
         // significant overheads.  Don't bother if the script is tiny.
         if (length < TINY_LENGTH) {
             return false;
         }
--- a/js/src/wasm/AsmJS.cpp
+++ b/js/src/wasm/AsmJS.cpp
@@ -6677,17 +6677,17 @@ HandleInstantiationFailure(JSContext* cx
     if (cx->isExceptionPending()) {
         return false;
     }
 
     ScriptSource* source = metadata.scriptSource.get();
 
     // Source discarding is allowed to affect JS semantics because it is never
     // enabled for normal JS content.
-    bool haveSource = source->hasSourceText();
+    bool haveSource = source->hasSourceData();
     if (!haveSource && !JSScript::loadSource(cx, source, &haveSource)) {
         return false;
     }
     if (!haveSource) {
         JS_ReportErrorASCII(cx, "asm.js link failure with source discarding enabled");
         return false;
     }
 
@@ -7613,17 +7613,17 @@ js::AsmJSModuleToString(JSContext* cx, H
     ScriptSource* source = metadata.scriptSource.get();
 
     StringBuffer out(cx);
 
     if (isToSource && fun->isLambda() && !out.append("(")) {
         return nullptr;
     }
 
-    bool haveSource = source->hasSourceText();
+    bool haveSource = source->hasSourceData();
     if (!haveSource && !JSScript::loadSource(cx, source, &haveSource)) {
         return nullptr;
     }
 
     if (!haveSource) {
         if (!out.append("function ")) {
             return nullptr;
         }
@@ -7664,17 +7664,17 @@ js::AsmJSFunctionToString(JSContext* cx,
 
     ScriptSource* source = metadata.scriptSource.get();
     StringBuffer out(cx);
 
     if (!out.append("function ")) {
         return nullptr;
     }
 
-    bool haveSource = source->hasSourceText();
+    bool haveSource = source->hasSourceData();
     if (!haveSource && !JSScript::loadSource(cx, source, &haveSource)) {
         return nullptr;
     }
 
     if (!haveSource) {
         // asm.js functions can't be anonymous
         MOZ_ASSERT(fun->explicitName());
         if (!out.append(fun->explicitName())) {