Bug 1781008 - Part 3: Use ErrorContext instead of JSContext for error reporting in AutoCheckRecursionLimit in frontend. r=bthrall
authorTooru Fujisawa <arai_a@mac.com>
Sat, 30 Jul 2022 04:45:21 +0000
changeset 625571 241f5f4edede78ce53d48d0357521787261659fa
parent 625570 dd0966996f42dcd4d548eeb40a7ec7673ff5de57
child 625572 65f1ba1ea8b0ca23208f764f39de8494faeefda1
push id167065
push userarai_a@mac.com
push dateSat, 30 Jul 2022 04:50:14 +0000
treeherderautoland@1d0a625cf1be [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbthrall
bugs1781008
milestone105.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1781008 - Part 3: Use ErrorContext instead of JSContext for error reporting in AutoCheckRecursionLimit in frontend. r=bthrall Depends on D152780 Differential Revision: https://phabricator.services.mozilla.com/D152781
js/public/friend/StackLimits.h
js/src/frontend/BytecodeEmitter.cpp
js/src/frontend/FoldConstants.cpp
js/src/frontend/FoldConstants.h
js/src/frontend/NameFunctions.cpp
js/src/frontend/NameFunctions.h
js/src/frontend/ParseNodeVerify.cpp
js/src/frontend/ParseNodeVerify.h
js/src/frontend/ParseNodeVisitor.h
js/src/frontend/Parser.cpp
--- a/js/public/friend/StackLimits.h
+++ b/js/public/friend/StackLimits.h
@@ -83,17 +83,17 @@ class MOZ_RAII AutoCheckRecursionLimit {
     --JS::RootingContext::get(cx_)->wasiRecursionDepth;
 #endif  // __wasi__
   }
 
   AutoCheckRecursionLimit(const AutoCheckRecursionLimit&) = delete;
   void operator=(const AutoCheckRecursionLimit&) = delete;
 
   [[nodiscard]] MOZ_ALWAYS_INLINE bool check(JSContext* cx) const;
-  [[nodiscard]] MOZ_ALWAYS_INLINE bool check(JSContext* cx,
+  [[nodiscard]] MOZ_ALWAYS_INLINE bool check(ErrorContext* ec,
                                              uintptr_t limit) const;
   [[nodiscard]] MOZ_ALWAYS_INLINE bool checkDontReport(JSContext* cx) const;
   [[nodiscard]] MOZ_ALWAYS_INLINE bool checkDontReport(uintptr_t limit) const;
   [[nodiscard]] MOZ_ALWAYS_INLINE bool checkWithExtra(JSContext* cx,
                                                       size_t extra) const;
   [[nodiscard]] MOZ_ALWAYS_INLINE bool checkWithStackPointerDontReport(
       JSContext* cx, void* sp) const;
   [[nodiscard]] MOZ_ALWAYS_INLINE bool checkWithStackPointerDontReport(
@@ -153,20 +153,20 @@ MOZ_ALWAYS_INLINE uintptr_t AutoCheckRec
 MOZ_ALWAYS_INLINE bool AutoCheckRecursionLimit::check(JSContext* cx) const {
   if (MOZ_UNLIKELY(!checkDontReport(cx))) {
     ReportOverRecursed(cx);
     return false;
   }
   return true;
 }
 
-MOZ_ALWAYS_INLINE bool AutoCheckRecursionLimit::check(JSContext* cx,
+MOZ_ALWAYS_INLINE bool AutoCheckRecursionLimit::check(ErrorContext* ec,
                                                       uintptr_t limit) const {
   if (MOZ_UNLIKELY(!checkDontReport(limit))) {
-    ReportOverRecursed(cx);
+    ReportOverRecursed(ec);
     return false;
   }
   return true;
 }
 
 MOZ_ALWAYS_INLINE bool AutoCheckRecursionLimit::checkDontReport(
     JSContext* cx) const {
   int stackDummy;
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -823,17 +823,17 @@ JSOp BytecodeEmitter::strictifySetNameOp
       break;
     default:;
   }
   return op;
 }
 
 bool BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer) {
   AutoCheckRecursionLimit recursion(cx);
-  if (!recursion.check(cx, stackLimit)) {
+  if (!recursion.check(ec, stackLimit)) {
     return false;
   }
 
 restart:
 
   switch (pn->getKind()) {
     // Trivial cases with no side effects.
     case ParseNodeKind::EmptyStmt:
@@ -2484,17 +2484,17 @@ bool BytecodeEmitter::emitScript(ParseNo
   if (!emitReturnRval()) {
     return false;
   }
 
   if (!emitterScope.leave(this)) {
     return false;
   }
 
-  if (!NameFunctions(cx, stackLimit, parserAtoms(), body)) {
+  if (!NameFunctions(cx, ec, stackLimit, parserAtoms(), body)) {
     return false;
   }
 
   // Create a Stencil and convert it into a JSScript.
   return intoScriptStencil(CompilationStencil::TopLevelIndex);
 }
 
 js::UniquePtr<ImmutableScriptData> BytecodeEmitter::createImmutableScriptData(
@@ -2560,17 +2560,17 @@ bool BytecodeEmitter::emitFunctionScript
   }
 
   if (!fse.emitEndBody()) {
     //              [stack]
     return false;
   }
 
   if (funbox->index() == CompilationStencil::TopLevelIndex) {
-    if (!NameFunctions(cx, stackLimit, parserAtoms(), funNode)) {
+    if (!NameFunctions(cx, ec, stackLimit, parserAtoms(), funNode)) {
       return false;
     }
   }
 
   return fse.intoStencil();
 }
 
 bool BytecodeEmitter::emitDestructuringLHSRef(ParseNode* target,
@@ -7542,17 +7542,17 @@ bool BytecodeEmitter::checkSelfHostedUns
  *
  * See emitCallOrNew and emitOptionalCall for more context.
  */
 bool BytecodeEmitter::emitOptionalCalleeAndThis(ParseNode* callee,
                                                 CallNode* call,
                                                 CallOrNewEmitter& cone,
                                                 OptionalEmitter& oe) {
   AutoCheckRecursionLimit recursion(cx);
-  if (!recursion.check(cx, stackLimit)) {
+  if (!recursion.check(ec, stackLimit)) {
     return false;
   }
 
   switch (ParseNodeKind kind = callee->getKind()) {
     case ParseNodeKind::Name: {
       auto name = callee->as<NameNode>().name();
       if (!cone.emitNameCallee(name)) {
         //          [stack] CALLEE THIS
@@ -8202,17 +8202,17 @@ bool BytecodeEmitter::emitPrivateInExpr(
  * Special `emitTree` for Optional Chaining case.
  * Examples of this are `emitOptionalChain`, `emitDeleteOptionalChain` and
  * `emitCalleeAndThisForOptionalChain`.
  */
 bool BytecodeEmitter::emitOptionalTree(
     ParseNode* pn, OptionalEmitter& oe,
     ValueUsage valueUsage /* = ValueUsage::WantValue */) {
   AutoCheckRecursionLimit recursion(cx);
-  if (!recursion.check(cx, stackLimit)) {
+  if (!recursion.check(ec, stackLimit)) {
     return false;
   }
   ParseNodeKind kind = pn->getKind();
   switch (kind) {
     case ParseNodeKind::OptionalDotExpr: {
       OptionalPropertyAccess* prop = &pn->as<OptionalPropertyAccess>();
       bool isSuper = false;
       PropOpEmitter poe(this, PropOpEmitter::Kind::Get,
@@ -10947,17 +10947,17 @@ bool BytecodeEmitter::emitExportDefault(
 
   return true;
 }
 
 bool BytecodeEmitter::emitTree(
     ParseNode* pn, ValueUsage valueUsage /* = ValueUsage::WantValue */,
     EmitLineNumberNote emitLineNote /* = EMIT_LINENOTE */) {
   AutoCheckRecursionLimit recursion(cx);
-  if (!recursion.check(cx, stackLimit)) {
+  if (!recursion.check(ec, stackLimit)) {
     return false;
   }
 
   /* Emit notes to tell the current bytecode's source line number.
      However, a couple trees require special treatment; see the
      relevant emitter functions for details. */
   if (emitLineNote == EMIT_LINENOTE &&
       !ParseNodeRequiresSpecialLineNumberNotes(pn)) {
--- a/js/src/frontend/FoldConstants.cpp
+++ b/js/src/frontend/FoldConstants.cpp
@@ -29,16 +29,17 @@ using JS::ToInt32;
 using JS::ToUint32;
 using mozilla::IsNaN;
 using mozilla::IsNegative;
 using mozilla::NegativeInfinity;
 using mozilla::PositiveInfinity;
 
 struct FoldInfo {
   JSContext* cx;
+  ErrorContext* ec;
   uintptr_t stackLimit;
   ParserAtomsTable& parserAtoms;
   FullParseHandler* handler;
 };
 
 // Don't use ReplaceNode directly, because we want the constant folder to keep
 // the attributes isInParens and isDirectRHSAnonFunction of the old node being
 // replaced.
@@ -78,17 +79,17 @@ static bool ListContainsHoistedDeclarati
 //
 // THIS IS NOT A GENERAL-PURPOSE FUNCTION.  It is only written to work in the
 // specific context of deciding that |node|, as one arm of a ParseNodeKind::If
 // controlled by a constant condition, contains a declaration that forbids
 // |node| being completely eliminated as dead.
 static bool ContainsHoistedDeclaration(FoldInfo& info, ParseNode* node,
                                        bool* result) {
   AutoCheckRecursionLimit recursion(info.cx);
-  if (!recursion.check(info.cx, info.stackLimit)) {
+  if (!recursion.check(info.ec, info.stackLimit)) {
     return false;
   }
 
 restart:
 
   // With a better-typed AST, we would have distinct parse node classes for
   // expressions and for statements and would characterize expressions with
   // ExpressionKind and statements with StatementKind.  Perhaps someday.  In
@@ -1311,23 +1312,23 @@ static bool FoldAdd(FoldInfo info, Parse
 
 class FoldVisitor : public RewritingParseNodeVisitor<FoldVisitor> {
   using Base = RewritingParseNodeVisitor;
 
   ParserAtomsTable& parserAtoms;
   FullParseHandler* handler;
 
   FoldInfo info() const {
-    return FoldInfo{cx_, stackLimit_, parserAtoms, handler};
+    return FoldInfo{cx_, ec_, stackLimit_, parserAtoms, handler};
   }
 
  public:
-  FoldVisitor(JSContext* cx, uintptr_t stackLimit,
+  FoldVisitor(JSContext* cx, ErrorContext* ec, uintptr_t stackLimit,
               ParserAtomsTable& parserAtoms, FullParseHandler* handler)
-      : RewritingParseNodeVisitor(cx, stackLimit),
+      : RewritingParseNodeVisitor(cx, ec, stackLimit),
         parserAtoms(parserAtoms),
         handler(handler) {}
 
   bool visitElemExpr(ParseNode*& pn) {
     return Base::visitElemExpr(pn) && FoldElement(info(), &pn);
   }
 
   bool visitTypeOfExpr(ParseNode*& pn) {
@@ -1564,23 +1565,25 @@ class FoldVisitor : public RewritingPars
         }
       }
       list->unsetHasNonConstInitializer();
     }
     return true;
   }
 };
 
-static bool Fold(JSContext* cx, uintptr_t stackLimit,
+static bool Fold(JSContext* cx, ErrorContext* ec, uintptr_t stackLimit,
                  ParserAtomsTable& parserAtoms, FullParseHandler* handler,
                  ParseNode** pnp) {
-  FoldVisitor visitor(cx, stackLimit, parserAtoms, handler);
+  FoldVisitor visitor(cx, ec, stackLimit, parserAtoms, handler);
   return visitor.visit(*pnp);
 }
 static bool Fold(FoldInfo info, ParseNode** pnp) {
-  return Fold(info.cx, info.stackLimit, info.parserAtoms, info.handler, pnp);
+  return Fold(info.cx, info.ec, info.stackLimit, info.parserAtoms, info.handler,
+              pnp);
 }
 
-bool frontend::FoldConstants(JSContext* cx, uintptr_t stackLimit,
+bool frontend::FoldConstants(JSContext* cx, ErrorContext* ec,
+                             uintptr_t stackLimit,
                              ParserAtomsTable& parserAtoms, ParseNode** pnp,
                              FullParseHandler* handler) {
-  return Fold(cx, stackLimit, parserAtoms, handler, pnp);
+  return Fold(cx, ec, stackLimit, parserAtoms, handler, pnp);
 }
--- a/js/src/frontend/FoldConstants.h
+++ b/js/src/frontend/FoldConstants.h
@@ -5,16 +5,19 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef frontend_FoldConstants_h
 #define frontend_FoldConstants_h
 
 #include "frontend/SyntaxParseHandler.h"
 
 namespace js {
+
+class ErrorContext;
+
 namespace frontend {
 
 class FullParseHandler;
 template <class ParseHandler>
 class PerHandlerParser;
 class ParserAtomsTable;
 
 // Perform constant folding on the given AST. For example, the program
@@ -27,22 +30,24 @@ class ParserAtomsTable;
 // Usage:
 //    pn = parser->statement();
 //    if (!pn) {
 //        return false;
 //    }
 //    if (!FoldConstants(cx, parserAtoms, &pn, parser)) {
 //        return false;
 //    }
-[[nodiscard]] extern bool FoldConstants(JSContext* cx, uintptr_t stackLimit,
+[[nodiscard]] extern bool FoldConstants(JSContext* cx, ErrorContext* ec,
+                                        uintptr_t stackLimit,
                                         ParserAtomsTable& parserAtoms,
                                         ParseNode** pnp,
                                         FullParseHandler* handler);
 
-[[nodiscard]] inline bool FoldConstants(JSContext* cx, uintptr_t stackLimit,
+[[nodiscard]] inline bool FoldConstants(JSContext* cx, ErrorContext* ec,
+                                        uintptr_t stackLimit,
                                         ParserAtomsTable& parserAtoms,
                                         typename SyntaxParseHandler::Node* pnp,
                                         SyntaxParseHandler* handler) {
   return true;
 }
 
 } /* namespace frontend */
 } /* namespace js */
--- a/js/src/frontend/NameFunctions.cpp
+++ b/js/src/frontend/NameFunctions.cpp
@@ -444,19 +444,19 @@ class NameResolver : public ParseNodeVis
   [[nodiscard]] bool visitImportSpecList(ListNode* pn) {
     return internalVisitSpecList(pn);
   }
 
   [[nodiscard]] bool visitExportSpecList(ListNode* pn) {
     return internalVisitSpecList(pn);
   }
 
-  NameResolver(JSContext* cx, uintptr_t stackLimit,
+  NameResolver(JSContext* cx, ErrorContext* ec, uintptr_t stackLimit,
                ParserAtomsTable& parserAtoms)
-      : ParseNodeVisitor(cx, stackLimit),
+      : ParseNodeVisitor(cx, ec, stackLimit),
         parserAtoms_(parserAtoms),
         nparents_(0),
         buf_(cx) {}
 
   /*
    * Resolve names for all anonymous functions in the given ParseNode tree.
    */
   [[nodiscard]] bool visit(ParseNode* pn) {
@@ -480,13 +480,14 @@ class NameResolver : public ParseNodeVis
                  sizeof(parents_[initialParents]), MemCheckKind::MakeUndefined);
 
     return ok;
   }
 };
 
 } /* anonymous namespace */
 
-bool frontend::NameFunctions(JSContext* cx, uintptr_t stackLimit,
+bool frontend::NameFunctions(JSContext* cx, ErrorContext* ec,
+                             uintptr_t stackLimit,
                              ParserAtomsTable& parserAtoms, ParseNode* pn) {
-  NameResolver nr(cx, stackLimit, parserAtoms);
+  NameResolver nr(cx, ec, stackLimit, parserAtoms);
   return nr.visit(pn);
 }
--- a/js/src/frontend/NameFunctions.h
+++ b/js/src/frontend/NameFunctions.h
@@ -5,20 +5,24 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef frontend_NameFunctions_h
 #define frontend_NameFunctions_h
 
 #include "js/TypeDecls.h"
 
 namespace js {
+
+class ErrorContext;
+
 namespace frontend {
 
 class ParseNode;
 class ParserAtomsTable;
 
-[[nodiscard]] bool NameFunctions(JSContext* cx, uintptr_t stackLimit,
+[[nodiscard]] bool NameFunctions(JSContext* cx, ErrorContext* ec,
+                                 uintptr_t stackLimit,
                                  ParserAtomsTable& parserAtoms, ParseNode* pn);
 
 } /* namespace frontend */
 } /* namespace js */
 
 #endif /* frontend_NameFunctions_h */
--- a/js/src/frontend/ParseNodeVerify.cpp
+++ b/js/src/frontend/ParseNodeVerify.cpp
@@ -16,18 +16,19 @@ namespace js {
 namespace frontend {
 
 class ParseNodeVerifier : public ParseNodeVisitor<ParseNodeVerifier> {
   using Base = ParseNodeVisitor<ParseNodeVerifier>;
 
   const LifoAlloc& alloc_;
 
  public:
-  ParseNodeVerifier(JSContext* cx, uintptr_t stackLimit, const LifoAlloc& alloc)
-      : Base(cx, stackLimit), alloc_(alloc) {}
+  ParseNodeVerifier(JSContext* cx, ErrorContext* ec, uintptr_t stackLimit,
+                    const LifoAlloc& alloc)
+      : Base(cx, ec, stackLimit), alloc_(alloc) {}
 
   [[nodiscard]] bool visit(ParseNode* pn) {
     // pn->size() asserts that pn->pn_kind is valid, so we don't redundantly
     // assert that here.
     JS_PARSE_NODE_ASSERT(alloc_.contains(pn),
                          "start of parse node is in alloc");
     JS_PARSE_NODE_ASSERT(alloc_.contains((unsigned char*)pn + pn->size()),
                          "end of parse node is in alloc");
@@ -36,15 +37,16 @@ class ParseNodeVerifier : public ParseNo
     }
     return Base::visit(pn);
   }
 };
 
 }  // namespace frontend
 }  // namespace js
 
-bool frontend::CheckParseTree(JSContext* cx, uintptr_t stackLimit,
-                              const LifoAlloc& alloc, ParseNode* pn) {
-  ParseNodeVerifier verifier(cx, stackLimit, alloc);
+bool frontend::CheckParseTree(JSContext* cx, ErrorContext* ec,
+                              uintptr_t stackLimit, const LifoAlloc& alloc,
+                              ParseNode* pn) {
+  ParseNodeVerifier verifier(cx, ec, stackLimit, alloc);
   return verifier.visit(pn);
 }
 
 #endif  // DEBUG
--- a/js/src/frontend/ParseNodeVerify.h
+++ b/js/src/frontend/ParseNodeVerify.h
@@ -6,41 +6,45 @@
 
 #ifndef frontend_ParseNodeVerify_h
 #define frontend_ParseNodeVerify_h
 
 #include "frontend/SyntaxParseHandler.h"  // SyntaxParseHandler::Node
 
 namespace js {
 
+class ErrorContext;
 class LifoAlloc;
 
 namespace frontend {
 
 class ParseNode;
 
 // In most builds, examine the given ParseNode and crash if it's not
 // well-formed. (In late beta and shipping builds of Firefox, this does
 // nothing.)
 //
 // This returns true on success, and false only if we hit the recursion limit.
 // If the ParseNode is actually bad, we crash.
 
 #ifdef DEBUG
-[[nodiscard]] extern bool CheckParseTree(JSContext* cx, uintptr_t stackLimit,
+[[nodiscard]] extern bool CheckParseTree(JSContext* cx, ErrorContext* ec,
+                                         uintptr_t stackLimit,
                                          const LifoAlloc& alloc, ParseNode* pn);
 #else
-[[nodiscard]] inline bool CheckParseTree(JSContext* cx, uintptr_t stackLimit,
+[[nodiscard]] inline bool CheckParseTree(JSContext* cx, ErrorContext* ec,
+                                         uintptr_t stackLimit,
                                          const LifoAlloc& alloc,
                                          ParseNode* pn) {
   return true;
 }
 #endif
 
-[[nodiscard]] inline bool CheckParseTree(JSContext* cx, uintptr_t stackLimit,
+[[nodiscard]] inline bool CheckParseTree(JSContext* cx, ErrorContext* ec,
+                                         uintptr_t stackLimit,
                                          const LifoAlloc& alloc,
                                          SyntaxParseHandler::Node pn) {
   return true;
 }
 
 } /* namespace frontend */
 } /* namespace js */
 
--- a/js/src/frontend/ParseNodeVisitor.h
+++ b/js/src/frontend/ParseNodeVisitor.h
@@ -8,16 +8,19 @@
 #define frontend_ParseNodeVisitor_h
 
 #include "mozilla/Assertions.h"
 
 #include "frontend/ParseNode.h"
 #include "js/friend/StackLimits.h"  // js::AutoCheckRecursionLimit
 
 namespace js {
+
+class ErrorContext;
+
 namespace frontend {
 
 /**
  * Utility class for walking a JS AST.
  *
  * Simple usage:
  *
  *     class HowTrueVisitor : public ParseNodeVisitor<HowTrueVisitor> {
@@ -46,24 +49,25 @@ namespace frontend {
  * as it eliminates the need for virtual method calls. Some rough testing shows
  * about a 12% speedup in the FoldConstants.cpp pass.
  * https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
  */
 template <typename Derived>
 class ParseNodeVisitor {
  public:
   JSContext* cx_;
+  ErrorContext* ec_;
   uintptr_t stackLimit_;
 
-  ParseNodeVisitor(JSContext* cx, uintptr_t stackLimit)
-      : cx_(cx), stackLimit_(stackLimit) {}
+  ParseNodeVisitor(JSContext* cx, ErrorContext* ec, uintptr_t stackLimit)
+      : cx_(cx), ec_(ec), stackLimit_(stackLimit) {}
 
   [[nodiscard]] bool visit(ParseNode* pn) {
     AutoCheckRecursionLimit recursion(cx_);
-    if (!recursion.check(cx_, stackLimit_)) {
+    if (!recursion.check(ec_, stackLimit_)) {
       return false;
     }
 
     switch (pn->getKind()) {
 #define VISIT_CASE(KIND, TYPE) \
   case ParseNodeKind::KIND:    \
     return static_cast<Derived*>(this)->visit##KIND(&pn->as<TYPE>());
       FOR_EACH_PARSE_NODE_KIND(VISIT_CASE)
@@ -93,24 +97,26 @@ class ParseNodeVisitor {
  * All visit methods take a `ParseNode*&` rather than more specific types like
  * `BinaryNode*&`, to allow replacing the current node with one of a different
  * type. Constant folding makes use of this.
  */
 template <typename Derived>
 class RewritingParseNodeVisitor {
  public:
   JSContext* cx_;
+  ErrorContext* ec_;
   uintptr_t stackLimit_;
 
-  RewritingParseNodeVisitor(JSContext* cx, uintptr_t stackLimit)
-      : cx_(cx), stackLimit_(stackLimit) {}
+  RewritingParseNodeVisitor(JSContext* cx, ErrorContext* ec,
+                            uintptr_t stackLimit)
+      : cx_(cx), ec_(ec), stackLimit_(stackLimit) {}
 
   [[nodiscard]] bool visit(ParseNode*& pn) {
     AutoCheckRecursionLimit recursion(cx_);
-    if (!recursion.check(cx_, stackLimit_)) {
+    if (!recursion.check(ec_, stackLimit_)) {
       return false;
     }
 
     switch (pn->getKind()) {
 #define VISIT_CASE(KIND, _type) \
   case ParseNodeKind::KIND:     \
     return static_cast<Derived*>(this)->visit##KIND(pn);
       FOR_EACH_PARSE_NODE_KIND(VISIT_CASE)
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -407,27 +407,27 @@ typename ParseHandler::ListNodeType Gene
   if (!tokenStream.getToken(&tt, TokenStream::SlashIsRegExp)) {
     return null();
   }
   if (tt != TokenKind::Eof) {
     error(JSMSG_GARBAGE_AFTER_INPUT, "script", TokenKindToDesc(tt));
     return null();
   }
 
-  if (!CheckParseTree(cx_, this->stackLimit_, alloc_, stmtList)) {
+  if (!CheckParseTree(cx_, this->ec_, this->stackLimit_, alloc_, stmtList)) {
     return null();
   }
 
   if (foldConstants_) {
     Node node = stmtList;
     // Don't constant-fold inside "use asm" code, as this could create a parse
     // tree that doesn't type-check as asm.js.
     if (!pc_->useAsmOrInsideUseAsm()) {
-      if (!FoldConstants(cx_, this->stackLimit_, this->parserAtoms(), &node,
-                         &handler_)) {
+      if (!FoldConstants(cx_, this->ec_, this->stackLimit_, this->parserAtoms(),
+                         &node, &handler_)) {
         return null();
       }
     }
     stmtList = handler_.asList(node);
   }
 
   return stmtList;
 }
@@ -1761,26 +1761,26 @@ LexicalScopeNode* Parser<FullParseHandle
     // since it contains an eval.
     MOZ_ASSERT(
         this->compilationState_.scopeContext.hasFunctionNeedsHomeObjectOnChain,
         "Eval must have found an enclosing function box scope that "
         "allows super.property");
   }
 #endif
 
-  if (!CheckParseTree(cx_, this->stackLimit_, alloc_, body)) {
+  if (!CheckParseTree(cx_, this->ec_, this->stackLimit_, alloc_, body)) {
     return null();
   }
 
   ParseNode* node = body;
   // Don't constant-fold inside "use asm" code, as this could create a parse
   // tree that doesn't type-check as asm.js.
   if (!pc_->useAsmOrInsideUseAsm()) {
-    if (!FoldConstants(cx_, this->stackLimit_, this->parserAtoms(), &node,
-                       &handler_)) {
+    if (!FoldConstants(cx_, this->ec_, this->stackLimit_, this->parserAtoms(),
+                       &node, &handler_)) {
       return null();
     }
   }
   body = handler_.asLexicalScope(node);
 
   if (!this->setSourceMapInfo()) {
     return nullptr;
   }
@@ -1825,30 +1825,30 @@ ListNode* Parser<FullParseHandler, Unit>
   if (!body) {
     return nullptr;
   }
 
   if (!checkStatementsEOF()) {
     return nullptr;
   }
 
-  if (!CheckParseTree(cx_, this->stackLimit_, alloc_, body)) {
+  if (!CheckParseTree(cx_, this->ec_, this->stackLimit_, alloc_, body)) {
     return null();
   }
 
   if (!checkForUndefinedPrivateFields()) {
     return null();
   }
 
   ParseNode* node = body;
   // Don't constant-fold inside "use asm" code, as this could create a parse
   // tree that doesn't type-check as asm.js.
   if (!pc_->useAsmOrInsideUseAsm()) {
-    if (!FoldConstants(cx_, this->stackLimit_, this->parserAtoms(), &node,
-                       &handler_)) {
+    if (!FoldConstants(cx_, this->ec_, this->stackLimit_, this->parserAtoms(),
+                       &node, &handler_)) {
       return null();
     }
   }
   body = &node->as<ListNode>();
 
   if (!this->setSourceMapInfo()) {
     return nullptr;
   }
@@ -1967,26 +1967,26 @@ ModuleNode* Parser<FullParseHandler, Uni
       ->setClosedOver();
 
   if (options().deoptimizeModuleGlobalVars) {
     for (BindingIter bi = modulepc.varScope().bindings(pc_); bi; bi++) {
       bi.setClosedOver();
     }
   }
 
-  if (!CheckParseTree(cx_, this->stackLimit_, alloc_, stmtList)) {
+  if (!CheckParseTree(cx_, this->ec_, this->stackLimit_, alloc_, stmtList)) {
     return null();
   }
 
   ParseNode* node = stmtList;
   // Don't constant-fold inside "use asm" code, as this could create a parse
   // tree that doesn't type-check as asm.js.
   if (!pc_->useAsmOrInsideUseAsm()) {
-    if (!FoldConstants(cx_, this->stackLimit_, this->parserAtoms(), &node,
-                       &handler_)) {
+    if (!FoldConstants(cx_, this->ec_, this->stackLimit_, this->parserAtoms(),
+                       &node, &handler_)) {
       return null();
     }
   }
   stmtList = &node->as<ListNode>();
 
   if (!this->setSourceMapInfo()) {
     return null();
   }
@@ -2366,26 +2366,26 @@ FunctionNode* Parser<FullParseHandler, U
   if (!tokenStream.getToken(&tt, TokenStream::SlashIsRegExp)) {
     return null();
   }
   if (tt != TokenKind::Eof) {
     error(JSMSG_GARBAGE_AFTER_INPUT, "function body", TokenKindToDesc(tt));
     return null();
   }
 
-  if (!CheckParseTree(cx_, this->stackLimit_, alloc_, funNode)) {
+  if (!CheckParseTree(cx_, this->ec_, this->stackLimit_, alloc_, funNode)) {
     return null();
   }
 
   ParseNode* node = funNode;
   // Don't constant-fold inside "use asm" code, as this could create a parse
   // tree that doesn't type-check as asm.js.
   if (!pc_->useAsmOrInsideUseAsm()) {
-    if (!FoldConstants(cx_, this->stackLimit_, this->parserAtoms(), &node,
-                       &handler_)) {
+    if (!FoldConstants(cx_, this->ec_, this->stackLimit_, this->parserAtoms(),
+                       &node, &handler_)) {
       return null();
     }
   }
   funNode = &node->as<FunctionNode>();
 
   if (!checkForUndefinedPrivateFields(nullptr)) {
     return null();
   }
@@ -3454,26 +3454,26 @@ FunctionNode* Parser<FullParseHandler, U
   } else {
     if (!functionFormalParametersAndBody(InAllowed, yieldHandling, &funNode,
                                          syntaxKind)) {
       MOZ_ASSERT(directives == newDirectives);
       return null();
     }
   }
 
-  if (!CheckParseTree(cx_, this->stackLimit_, alloc_, funNode)) {
+  if (!CheckParseTree(cx_, this->ec_, this->stackLimit_, alloc_, funNode)) {
     return null();
   }
 
   ParseNode* node = funNode;
   // Don't constant-fold inside "use asm" code, as this could create a parse
   // tree that doesn't type-check as asm.js.
   if (!pc_->useAsmOrInsideUseAsm()) {
-    if (!FoldConstants(cx_, this->stackLimit_, this->parserAtoms(), &node,
-                       &handler_)) {
+    if (!FoldConstants(cx_, this->ec_, this->stackLimit_, this->parserAtoms(),
+                       &node, &handler_)) {
       return null();
     }
   }
   funNode = &node->as<FunctionNode>();
 
   return funNode;
 }
 
@@ -4034,17 +4034,17 @@ bool GeneralParser<ParseHandler, Unit>::
   }
   return true;
 }
 
 template <class ParseHandler, typename Unit>
 typename ParseHandler::ListNodeType
 GeneralParser<ParseHandler, Unit>::statementList(YieldHandling yieldHandling) {
   AutoCheckRecursionLimit recursion(cx_);
-  if (!recursion.check(cx_, this->stackLimit_)) {
+  if (!recursion.check(this->ec_, this->stackLimit_)) {
     return null();
   }
 
   ListNodeType stmtList = handler_.newStatementList(pos());
   if (!stmtList) {
     return null();
   }
 
@@ -4353,17 +4353,17 @@ GeneralParser<ParseHandler, Unit>::bindi
 
 template <class ParseHandler, typename Unit>
 typename ParseHandler::ListNodeType
 GeneralParser<ParseHandler, Unit>::objectBindingPattern(
     DeclarationKind kind, YieldHandling yieldHandling) {
   MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::LeftCurly));
 
   AutoCheckRecursionLimit recursion(cx_);
-  if (!recursion.check(cx_, this->stackLimit_)) {
+  if (!recursion.check(this->ec_, this->stackLimit_)) {
     return null();
   }
 
   uint32_t begin = pos().begin;
   ListNodeType literal = handler_.newObjectLiteral(begin);
   if (!literal) {
     return null();
   }
@@ -4508,17 +4508,17 @@ GeneralParser<ParseHandler, Unit>::objec
 
 template <class ParseHandler, typename Unit>
 typename ParseHandler::ListNodeType
 GeneralParser<ParseHandler, Unit>::arrayBindingPattern(
     DeclarationKind kind, YieldHandling yieldHandling) {
   MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::LeftBracket));
 
   AutoCheckRecursionLimit recursion(cx_);
-  if (!recursion.check(cx_, this->stackLimit_)) {
+  if (!recursion.check(this->ec_, this->stackLimit_)) {
     return null();
   }
 
   uint32_t begin = pos().begin;
   ListNodeType literal = handler_.newArrayLiteral(begin);
   if (!literal) {
     return null();
   }
@@ -8904,17 +8904,17 @@ GeneralParser<ParseHandler, Unit>::varia
 }
 
 template <class ParseHandler, typename Unit>
 typename ParseHandler::Node GeneralParser<ParseHandler, Unit>::statement(
     YieldHandling yieldHandling) {
   MOZ_ASSERT(checkOptionsCalled_);
 
   AutoCheckRecursionLimit recursion(cx_);
-  if (!recursion.check(cx_, this->stackLimit_)) {
+  if (!recursion.check(this->ec_, this->stackLimit_)) {
     return null();
   }
 
   TokenKind tt;
   if (!tokenStream.getToken(&tt, TokenStream::SlashIsRegExp)) {
     return null();
   }
 
@@ -9151,17 +9151,17 @@ typename ParseHandler::Node GeneralParse
 
 template <class ParseHandler, typename Unit>
 typename ParseHandler::Node
 GeneralParser<ParseHandler, Unit>::statementListItem(
     YieldHandling yieldHandling, bool canHaveDirectives /* = false */) {
   MOZ_ASSERT(checkOptionsCalled_);
 
   AutoCheckRecursionLimit recursion(cx_);
-  if (!recursion.check(cx_, this->stackLimit_)) {
+  if (!recursion.check(this->ec_, this->stackLimit_)) {
     return null();
   }
 
   TokenKind tt;
   if (!tokenStream.getToken(&tt, TokenStream::SlashIsRegExp)) {
     return null();
   }
 
@@ -9708,17 +9708,17 @@ GeneralParser<ParseHandler, Unit>::condE
 
 template <class ParseHandler, typename Unit>
 typename ParseHandler::Node GeneralParser<ParseHandler, Unit>::assignExpr(
     InHandling inHandling, YieldHandling yieldHandling,
     TripledotHandling tripledotHandling,
     PossibleError* possibleError /* = nullptr */,
     InvokedPrediction invoked /* = PredictUninvoked */) {
   AutoCheckRecursionLimit recursion(cx_);
-  if (!recursion.check(cx_, this->stackLimit_)) {
+  if (!recursion.check(this->ec_, this->stackLimit_)) {
     return null();
   }
 
   // It's very common at this point to have a "detectably simple" expression,
   // i.e. a name/number/string token followed by one of the following tokens
   // that obviously isn't part of an expression: , ; : ) ] }
   //
   // (In Parsemark this happens 81.4% of the time;  in code with large
@@ -10086,17 +10086,17 @@ GeneralParser<ParseHandler, Unit>::unary
 }
 
 template <class ParseHandler, typename Unit>
 typename ParseHandler::Node GeneralParser<ParseHandler, Unit>::optionalExpr(
     YieldHandling yieldHandling, TripledotHandling tripledotHandling,
     TokenKind tt, PossibleError* possibleError /* = nullptr */,
     InvokedPrediction invoked /* = PredictUninvoked */) {
   AutoCheckRecursionLimit recursion(cx_);
-  if (!recursion.check(cx_, this->stackLimit_)) {
+  if (!recursion.check(this->ec_, this->stackLimit_)) {
     return null();
   }
 
   uint32_t begin = pos().begin;
 
   Node lhs = memberExpr(yieldHandling, tripledotHandling, tt,
                         /* allowCallSyntax = */ true, possibleError, invoked);
   if (!lhs) {
@@ -10198,17 +10198,17 @@ typename ParseHandler::Node GeneralParse
 
 template <class ParseHandler, typename Unit>
 typename ParseHandler::Node GeneralParser<ParseHandler, Unit>::unaryExpr(
     YieldHandling yieldHandling, TripledotHandling tripledotHandling,
     PossibleError* possibleError /* = nullptr */,
     InvokedPrediction invoked /* = PredictUninvoked */,
     PrivateNameHandling privateNameHandling /* = PrivateNameProhibited */) {
   AutoCheckRecursionLimit recursion(cx_);
-  if (!recursion.check(cx_, this->stackLimit_)) {
+  if (!recursion.check(this->ec_, this->stackLimit_)) {
     return null();
   }
 
   TokenKind tt;
   if (!tokenStream.getToken(&tt, TokenStream::SlashIsRegExp)) {
     return null();
   }
   uint32_t begin = pos().begin;
@@ -10473,17 +10473,17 @@ typename ParseHandler::Node GeneralParse
     YieldHandling yieldHandling, TripledotHandling tripledotHandling,
     TokenKind tt, bool allowCallSyntax, PossibleError* possibleError,
     InvokedPrediction invoked) {
   MOZ_ASSERT(anyChars.isCurrentTokenType(tt));
 
   Node lhs;
 
   AutoCheckRecursionLimit recursion(cx_);
-  if (!recursion.check(cx_, this->stackLimit_)) {
+  if (!recursion.check(this->ec_, this->stackLimit_)) {
     return null();
   }
 
   /* Check for new expression first. */
   if (tt == TokenKind::New) {
     uint32_t newBegin = pos().begin;
     // Make sure this wasn't a |new.target| in disguise.
     NewTargetNodeType newTarget;
@@ -12381,17 +12381,17 @@ GeneralParser<ParseHandler, Unit>::impor
 }
 
 template <class ParseHandler, typename Unit>
 typename ParseHandler::Node GeneralParser<ParseHandler, Unit>::primaryExpr(
     YieldHandling yieldHandling, TripledotHandling tripledotHandling,
     TokenKind tt, PossibleError* possibleError, InvokedPrediction invoked) {
   MOZ_ASSERT(anyChars.isCurrentTokenType(tt));
   AutoCheckRecursionLimit recursion(cx_);
-  if (!recursion.check(cx_, this->stackLimit_)) {
+  if (!recursion.check(this->ec_, this->stackLimit_)) {
     return null();
   }
 
   switch (tt) {
     case TokenKind::Function:
       return functionExpr(pos().begin, invoked,
                           FunctionAsyncKind::SyncFunction);