Bug 1179063 - Cleanup: make StmtType an enum class. (r=efaust)
☠☠ backed out by 189161dc1616 ☠ ☠
authorShu-yu Guo <shu@rfrn.org>
Thu, 30 Jul 2015 09:25:41 -0700
changeset 287169 47fe6e30240df7403726881b33f126b37b04c70c
parent 287132 c14a0de10f23d4b40a314d20fa471b7c27009f97
child 287170 f251b383631427a9d2dbc1c4bb2b5b3148c9c19a
push id5067
push userraliiev@mozilla.com
push dateMon, 21 Sep 2015 14:04:52 +0000
treeherdermozilla-beta@14221ffe5b2f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersefaust
bugs1179063
milestone42.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 1179063 - Cleanup: make StmtType an enum class. (r=efaust)
js/src/frontend/BytecodeEmitter.cpp
js/src/frontend/BytecodeEmitter.h
js/src/frontend/Parser.cpp
js/src/frontend/Parser.h
js/src/frontend/SharedContext.h
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -70,22 +70,22 @@ struct frontend::StmtInfoBCE : public St
      * try/catch/finally code generation and backpatching.
      *
      * Only a loop, switch, or label statement info record can have breaks and
      * continues, and only a for loop has an update backpatch chain, so it's
      * safe to overlay these for the "trying" StmtTypes.
      */
 
     ptrdiff_t& gosubs() {
-        MOZ_ASSERT(type == STMT_FINALLY);
+        MOZ_ASSERT(type == StmtType::FINALLY);
         return breaks;
     }
 
     ptrdiff_t& guardJump() {
-        MOZ_ASSERT(type == STMT_TRY || type == STMT_FINALLY);
+        MOZ_ASSERT(type == StmtType::TRY || type == StmtType::FINALLY);
         return continues;
     }
 };
 
 struct frontend::LoopStmtInfo : public StmtInfoBCE
 {
     int32_t         stackDepth;     // Stack depth when this loop was pushed.
     uint32_t        loopDepth;      // Loop depth.
@@ -371,25 +371,25 @@ static const char * const statementName[
     "do loop",               /* DO_LOOP */
     "for loop",              /* FOR_LOOP */
     "for/in loop",           /* FOR_IN_LOOP */
     "for/of loop",           /* FOR_OF_LOOP */
     "while loop",            /* WHILE_LOOP */
     "spread",                /* SPREAD */
 };
 
-static_assert(MOZ_ARRAY_LENGTH(statementName) == STMT_LIMIT,
+static_assert(MOZ_ARRAY_LENGTH(statementName) == uint16_t(StmtType::LIMIT),
               "statementName array and StmtType enum must be consistent");
 
 static const char*
 StatementName(StmtInfoBCE* topStmt)
 {
     if (!topStmt)
         return js_script_str;
-    return statementName[topStmt->type];
+    return statementName[uint16_t(topStmt->type)];
 }
 
 static void
 ReportStatementTooLarge(TokenStream& ts, StmtInfoBCE* topStmt)
 {
     ts.reportError(JSMSG_NEED_DIET, StatementName(topStmt));
 }
 
@@ -608,47 +608,47 @@ bool
 NonLocalExitScope::prepareForNonLocalJump(StmtInfoBCE* toStmt)
 {
     int npops = 0;
 
 #define FLUSH_POPS() if (npops && !bce->flushPops(&npops)) return false
 
     for (StmtInfoBCE* stmt = bce->topStmt; stmt != toStmt; stmt = stmt->down) {
         switch (stmt->type) {
-          case STMT_FINALLY:
+          case StmtType::FINALLY:
             FLUSH_POPS();
             if (!bce->emitBackPatchOp(&stmt->gosubs()))
                 return false;
             break;
 
-          case STMT_WITH:
+          case StmtType::WITH:
             if (!bce->emit1(JSOP_LEAVEWITH))
                 return false;
             MOZ_ASSERT(stmt->isNestedScope);
             if (!popScopeForNonLocalExit(stmt->blockScopeIndex))
                 return false;
             break;
 
-          case STMT_FOR_OF_LOOP:
+          case StmtType::FOR_OF_LOOP:
             npops += 2;
             break;
 
-          case STMT_FOR_IN_LOOP:
+          case StmtType::FOR_IN_LOOP:
             /* The iterator and the current value are on the stack. */
             npops += 1;
             FLUSH_POPS();
             if (!bce->emit1(JSOP_ENDITER))
                 return false;
             break;
 
-          case STMT_SPREAD:
+          case StmtType::SPREAD:
             MOZ_ASSERT_UNREACHABLE("can't break/continue/return from inside a spread");
             break;
 
-          case STMT_SUBROUTINE:
+          case StmtType::SUBROUTINE:
             /*
              * There's a [exception or hole, retsub pc-index] pair on the
              * stack that we need to pop.
              */
             npops += 2;
             break;
 
           default:;
@@ -737,19 +737,19 @@ BytecodeEmitter::pushLoopStatement(LoopS
             break;
         }
     }
 
     stmt->stackDepth = this->stackDepth;
     stmt->loopDepth = downLoop ? downLoop->loopDepth + 1 : 1;
 
     int loopSlots;
-    if (type == STMT_SPREAD)
+    if (type == StmtType::SPREAD)
         loopSlots = 3;
-    else if (type == STMT_FOR_IN_LOOP || type == STMT_FOR_OF_LOOP)
+    else if (type == StmtType::FOR_IN_LOOP || type == StmtType::FOR_OF_LOOP)
         loopSlots = 2;
     else
         loopSlots = 0;
 
     MOZ_ASSERT(loopSlots <= stmt->stackDepth);
 
     if (downLoop)
         stmt->canIonOsr = (downLoop->canIonOsr &&
@@ -890,41 +890,41 @@ BytecodeEmitter::computeLocalOffset(Hand
 // to an onStep hook.
 //
 // Enter a nested scope with enterNestedScope.  It will emit
 // PUSHBLOCKSCOPE/ENTERWITH if needed, and arrange to record the PC bounds of
 // the scope.  Leave a nested scope with leaveNestedScope, which, for blocks,
 // will emit DEBUGLEAVEBLOCK and may emit POPBLOCKSCOPE.  (For "with" scopes it
 // emits LEAVEWITH, of course.)  Pass enterNestedScope a fresh StmtInfoBCE
 // object, and pass that same object to the corresponding leaveNestedScope.  If
-// the statement is a block scope, pass STMT_BLOCK as stmtType; otherwise for
-// with scopes pass STMT_WITH.
+// the statement is a block scope, pass StmtType::BLOCK as stmtType; otherwise for
+// with scopes pass StmtType::WITH.
 //
 bool
 BytecodeEmitter::enterNestedScope(StmtInfoBCE* stmt, ObjectBox* objbox, StmtType stmtType)
 {
     Rooted<NestedScopeObject*> scopeObj(cx, &objbox->object->as<NestedScopeObject>());
     uint32_t scopeObjectIndex = objectList.add(objbox);
 
     switch (stmtType) {
-      case STMT_BLOCK: {
+      case StmtType::BLOCK: {
         Rooted<StaticBlockObject*> blockObj(cx, &scopeObj->as<StaticBlockObject>());
 
         computeLocalOffset(blockObj);
 
         if (!computeAliasedSlots(blockObj))
             return false;
 
         if (blockObj->needsClone()) {
             if (!emitInternedObjectOp(scopeObjectIndex, JSOP_PUSHBLOCKSCOPE))
                 return false;
         }
         break;
       }
-      case STMT_WITH:
+      case StmtType::WITH:
         MOZ_ASSERT(scopeObj->is<StaticWithObject>());
         if (!emitInternedObjectOp(scopeObjectIndex, JSOP_ENTERWITH))
             return false;
         break;
       default:
         MOZ_CRASH("Unexpected scope statement");
     }
 
@@ -937,17 +937,17 @@ BytecodeEmitter::enterNestedScope(StmtIn
     stmt->blockScopeIndex = blockScopeList.length();
     if (!blockScopeList.append(scopeObjectIndex, offset(), parent))
         return false;
 
     pushStatement(stmt, stmtType, offset());
     scopeObj->initEnclosingNestedScope(enclosingStaticScope());
     FinishPushNestedScope(this, stmt, *scopeObj);
     MOZ_ASSERT(stmt->isNestedScope);
-    stmt->isBlockScope = (stmtType == STMT_BLOCK);
+    stmt->isBlockScope = (stmtType == StmtType::BLOCK);
 
     return true;
 }
 
 // Patches |breaks| and |continues| unless the top statement info record
 // represents a try-catch-finally suite.
 void
 BytecodeEmitter::popStatement()
@@ -960,17 +960,17 @@ BytecodeEmitter::popStatement()
     FinishPopStatement(this);
 }
 
 bool
 BytecodeEmitter::leaveNestedScope(StmtInfoBCE* stmt)
 {
     MOZ_ASSERT(stmt == topStmt);
     MOZ_ASSERT(stmt->isNestedScope);
-    MOZ_ASSERT(stmt->isBlockScope == !(stmt->type == STMT_WITH));
+    MOZ_ASSERT(stmt->isBlockScope == !(stmt->type == StmtType::WITH));
     uint32_t blockScopeIndex = stmt->blockScopeIndex;
 
 #ifdef DEBUG
     MOZ_ASSERT(blockScopeList.list[blockScopeIndex].length == 0);
     uint32_t blockObjIndex = blockScopeList.list[blockScopeIndex].index;
     ObjectBox* blockObjBox = objectList.find(blockObjIndex);
     NestedScopeObject* staticScope = &blockObjBox->object->as<NestedScopeObject>();
     MOZ_ASSERT(stmt->staticScope == staticScope);
@@ -1519,17 +1519,17 @@ BytecodeEmitter::tryConvertFreeName(Pars
      * When parsing inner functions lazily, parse nodes for outer functions no
      * longer exist and only the function's scope chain is available for
      * resolving upvar accesses within the inner function.
      */
     if (emitterMode == BytecodeEmitter::LazyFunction) {
         // The only statements within a lazy function which can push lexical
         // scopes are try/catch blocks. Use generic ops in this case.
         for (StmtInfoBCE* stmt = topStmt; stmt; stmt = stmt->down) {
-            if (stmt->type == STMT_CATCH)
+            if (stmt->type == StmtType::CATCH)
                 return true;
         }
 
         size_t hops = 0;
         FunctionBox* funbox = sc->asFunctionBox();
         if (funbox->hasExtensibleScope())
             return false;
         if (funbox->function()->isNamedLambda() && funbox->function()->atom() == pn->pn_atom)
@@ -2346,17 +2346,17 @@ BytecodeEmitter::checkRunOnceContext()
 
 bool
 BytecodeEmitter::needsImplicitThis()
 {
     if (sc->inWith())
         return true;
 
     for (StmtInfoBCE* stmt = topStmt; stmt; stmt = stmt->down) {
-        if (stmt->type == STMT_WITH)
+        if (stmt->type == StmtType::WITH)
             return true;
     }
 
     return false;
 }
 
 void
 BytecodeEmitter::tellDebuggerAboutCompiledScript(ExclusiveContext* cx)
@@ -3030,17 +3030,17 @@ BytecodeEmitter::enterBlockScope(StmtInf
     // Initial values for block-scoped locals. Whether it is undefined or the
     // JS_UNINITIALIZED_LEXICAL magic value depends on the context. The
     // current way we emit for-in and for-of heads means its let bindings will
     // always be initialized, so we can initialize them to undefined.
     Rooted<StaticBlockObject*> blockObj(cx, &objbox->object->as<StaticBlockObject>());
     if (!pushInitialConstants(initialValueOp, blockObj->numVariables() - alreadyPushed))
         return false;
 
-    if (!enterNestedScope(stmtInfo, objbox, STMT_BLOCK))
+    if (!enterNestedScope(stmtInfo, objbox, StmtType::BLOCK))
         return false;
 
     if (!initializeBlockScopedLocalsFromStack(blockObj))
         return false;
 
     return true;
 }
 
@@ -3060,24 +3060,24 @@ BytecodeEmitter::emitSwitch(ParseNode* p
         return false;
 
     StmtInfoBCE stmtInfo(cx);
     ptrdiff_t top;
     if (cases->isKind(PNK_LEXICALSCOPE)) {
         if (!enterBlockScope(&stmtInfo, cases->pn_objbox, JSOP_UNINITIALIZED, 0))
             return false;
 
-        stmtInfo.type = STMT_SWITCH;
+        stmtInfo.type = StmtType::SWITCH;
         stmtInfo.update = top = offset();
         /* Advance |cases| to refer to the switch case list. */
         cases = cases->expr();
     } else {
         MOZ_ASSERT(cases->isKind(PNK_STATEMENTLIST));
         top = offset();
-        pushStatement(&stmtInfo, STMT_SWITCH, top);
+        pushStatement(&stmtInfo, StmtType::SWITCH, top);
     }
 
     /* Switch bytecodes run from here till end of final case. */
     uint32_t caseCount = cases->pn_count;
     if (caseCount > JS_BIT(16)) {
         parser->tokenStream.reportError(JSMSG_TOO_MANY_CASES);
         return false;
     }
@@ -4768,26 +4768,26 @@ class EmitLevelManager
 };
 
 } /* anonymous namespace */
 
 bool
 BytecodeEmitter::emitCatch(ParseNode* pn)
 {
     /*
-     * Morph STMT_BLOCK to STMT_CATCH, note the block entry code offset,
+     * Morph StmtType::BLOCK to StmtType::CATCH, note the block entry code offset,
      * and save the block object atom.
      */
     StmtInfoBCE* stmt = topStmt;
-    MOZ_ASSERT(stmt->type == STMT_BLOCK && stmt->isBlockScope);
-    stmt->type = STMT_CATCH;
+    MOZ_ASSERT(stmt->type == StmtType::BLOCK && stmt->isBlockScope);
+    stmt->type = StmtType::CATCH;
 
     /* Go up one statement info record to the TRY or FINALLY record. */
     stmt = stmt->down;
-    MOZ_ASSERT(stmt->type == STMT_TRY || stmt->type == STMT_FINALLY);
+    MOZ_ASSERT(stmt->type == StmtType::TRY || stmt->type == StmtType::FINALLY);
 
     /* Pick up the pending exception and bind it to the catch variable. */
     if (!emit1(JSOP_EXCEPTION))
         return false;
 
     /*
      * Dup the exception object if there is a guard for rethrowing to use
      * it later when rethrowing or in other catches.
@@ -4867,22 +4867,22 @@ BytecodeEmitter::emitCatch(ParseNode* pn
 MOZ_NEVER_INLINE bool
 BytecodeEmitter::emitTry(ParseNode* pn)
 {
     StmtInfoBCE stmtInfo(cx);
 
     // Push stmtInfo to track jumps-over-catches and gosubs-to-finally
     // for later fixup.
     //
-    // When a finally block is active (STMT_FINALLY in our parse context),
+    // When a finally block is active (StmtType::FINALLY in our parse context),
     // non-local jumps (including jumps-over-catches) result in a GOSUB
     // being written into the bytecode stream and fixed-up later (c.f.
     // emitBackPatchOp and backPatch).
     //
-    pushStatement(&stmtInfo, pn->pn_kid3 ? STMT_FINALLY : STMT_TRY, offset());
+    pushStatement(&stmtInfo, pn->pn_kid3 ? StmtType::FINALLY : StmtType::TRY, offset());
 
     // Since an exception can be thrown at any place inside the try block,
     // we need to restore the stack and the scope chain before we transfer
     // the control to the exception handler.
     //
     // For that we store in a try note associated with the catch or
     // finally block the stack depth upon the try entry. The interpreter
     // uses this depth to properly unwind the stack and the scope chain.
@@ -4993,17 +4993,17 @@ BytecodeEmitter::emitTry(ParseNode* pn)
     if (pn->pn_kid3) {
         // Fix up the gosubs that might have been emitted before non-local
         // jumps to the finally code.
         backPatch(stmtInfo.gosubs(), code().end(), JSOP_GOSUB);
 
         finallyStart = offset();
 
         // Indicate that we're emitting a subroutine body.
-        stmtInfo.type = STMT_SUBROUTINE;
+        stmtInfo.type = StmtType::SUBROUTINE;
         if (!updateSourceCoordNotes(pn->pn_kid3->pn_pos.begin))
             return false;
         if (!emit1(JSOP_FINALLY) ||
             !emitTree(pn->pn_kid3) ||
             !emit1(JSOP_RETSUB))
         {
             return false;
         }
@@ -5034,36 +5034,36 @@ BytecodeEmitter::emitTry(ParseNode* pn)
 }
 
 bool
 BytecodeEmitter::emitIf(ParseNode* pn)
 {
     StmtInfoBCE stmtInfo(cx);
 
     /* Initialize so we can detect else-if chains and avoid recursion. */
-    stmtInfo.type = STMT_IF;
+    stmtInfo.type = StmtType::IF;
     ptrdiff_t beq = -1;
     ptrdiff_t jmp = -1;
     unsigned noteIndex = -1;
 
   if_again:
     /* Emit code for the condition before pushing stmtInfo. */
     if (!emitTree(pn->pn_kid1))
         return false;
     ptrdiff_t top = offset();
-    if (stmtInfo.type == STMT_IF) {
-        pushStatement(&stmtInfo, STMT_IF, top);
+    if (stmtInfo.type == StmtType::IF) {
+        pushStatement(&stmtInfo, StmtType::IF, top);
     } else {
         /*
          * We came here from the goto further below that detects else-if
-         * chains, so we must mutate stmtInfo back into a STMT_IF record.
+         * chains, so we must mutate stmtInfo back into a StmtType::IF record.
          * Also we need a note offset for SRC_IF_ELSE to help IonMonkey.
          */
-        MOZ_ASSERT(stmtInfo.type == STMT_ELSE);
-        stmtInfo.type = STMT_IF;
+        MOZ_ASSERT(stmtInfo.type == StmtType::ELSE);
+        stmtInfo.type = StmtType::IF;
         stmtInfo.update = top;
         if (!setSrcNoteOffset(noteIndex, 0, jmp - beq))
             return false;
     }
 
     /* Emit an annotated branch-if-false around the then part. */
     ParseNode* pn3 = pn->pn_kid3;
     if (!newSrcNote(pn3 ? SRC_IF_ELSE : SRC_IF, &noteIndex))
@@ -5071,17 +5071,17 @@ BytecodeEmitter::emitIf(ParseNode* pn)
     if (!emitJump(JSOP_IFEQ, 0, &beq))
         return false;
 
     /* Emit code for the then and optional else parts. */
     if (!emitTree(pn->pn_kid2))
         return false;
     if (pn3) {
         /* Modify stmtInfo so we know we're in the else part. */
-        stmtInfo.type = STMT_ELSE;
+        stmtInfo.type = StmtType::ELSE;
 
         /*
          * Emit a JSOP_BACKPATCH op to jump from the end of our then part
          * around the else part.  The popStatement call at the bottom of
          * this function will fix up the backpatch chain linked from
          * stmtInfo.breaks.
          */
         if (!emitGoto(&stmtInfo, &stmtInfo.breaks))
@@ -5174,17 +5174,17 @@ BytecodeEmitter::emitLexicalScope(ParseN
 }
 
 bool
 BytecodeEmitter::emitWith(ParseNode* pn)
 {
     StmtInfoBCE stmtInfo(cx);
     if (!emitTree(pn->pn_left))
         return false;
-    if (!enterNestedScope(&stmtInfo, pn->pn_binary_obj, STMT_WITH))
+    if (!enterNestedScope(&stmtInfo, pn->pn_binary_obj, StmtType::WITH))
         return false;
     if (!emitTree(pn->pn_right))
         return false;
     if (!leaveNestedScope(&stmtInfo))
         return false;
     return true;
 }
 
@@ -5273,30 +5273,30 @@ BytecodeEmitter::emitForInOrOfVariables(
 
     return true;
 }
 
 
 bool
 BytecodeEmitter::emitForOf(StmtType type, ParseNode* pn, ptrdiff_t top)
 {
-    MOZ_ASSERT(type == STMT_FOR_OF_LOOP || type == STMT_SPREAD);
-    MOZ_ASSERT_IF(type == STMT_FOR_OF_LOOP, pn && pn->pn_left->isKind(PNK_FOROF));
-    MOZ_ASSERT_IF(type == STMT_SPREAD, !pn);
+    MOZ_ASSERT(type == StmtType::FOR_OF_LOOP || type == StmtType::SPREAD);
+    MOZ_ASSERT_IF(type == StmtType::FOR_OF_LOOP, pn && pn->pn_left->isKind(PNK_FOROF));
+    MOZ_ASSERT_IF(type == StmtType::SPREAD, !pn);
 
     ParseNode* forHead = pn ? pn->pn_left : nullptr;
     ParseNode* forHeadExpr = forHead ? forHead->pn_kid3 : nullptr;
     ParseNode* forBody = pn ? pn->pn_right : nullptr;
 
     ParseNode* pn1 = forHead ? forHead->pn_kid1 : nullptr;
     bool letDecl = false;
     if (pn1 && !emitForInOrOfVariables(pn1, &letDecl))
         return false;
 
-    if (type == STMT_FOR_OF_LOOP) {
+    if (type == StmtType::FOR_OF_LOOP) {
         // For-of loops run with two values on the stack: the iterator and the
         // current result object.
 
         // Compile the object expression to the right of 'of'.
         if (!emitTree(forHeadExpr))
             return false;
         if (!emitIterator())
             return false;
@@ -5328,63 +5328,63 @@ BytecodeEmitter::emitForOf(StmtType type
     if (!emitJump(JSOP_GOTO, 0, &jmp))
         return false;
 
     top = offset();
     SET_STATEMENT_TOP(&stmtInfo, top);
     if (!emitLoopHead(nullptr))
         return false;
 
-    if (type == STMT_SPREAD)
+    if (type == StmtType::SPREAD)
         this->stackDepth++;
 
 #ifdef DEBUG
     int loopDepth = this->stackDepth;
 #endif
 
     // Emit code to assign result.value to the iteration variable.
-    if (type == STMT_FOR_OF_LOOP) {
+    if (type == StmtType::FOR_OF_LOOP) {
         if (!emit1(JSOP_DUP))                             // ITER RESULT RESULT
             return false;
     }
     if (!emitAtomOp(cx->names().value, JSOP_GETPROP))     // ... RESULT VALUE
         return false;
-    if (type == STMT_FOR_OF_LOOP) {
+    if (type == StmtType::FOR_OF_LOOP) {
         if (!emitAssignment(forHead->pn_kid2, JSOP_NOP, nullptr)) // ITER RESULT VALUE
             return false;
         if (!emit1(JSOP_POP))                             // ITER RESULT
             return false;
 
         // The stack should be balanced around the assignment opcode sequence.
         MOZ_ASSERT(this->stackDepth == loopDepth);
 
         // Emit code for the loop body.
         if (!emitTree(forBody))
             return false;
 
         // Set loop and enclosing "update" offsets, for continue.
         StmtInfoBCE* stmt = &stmtInfo;
         do {
             stmt->update = offset();
-        } while ((stmt = stmt->down) != nullptr && stmt->type == STMT_LABEL);
+        } while ((stmt = stmt->down) != nullptr && stmt->type == StmtType::LABEL);
     } else {
         if (!emit1(JSOP_INITELEM_INC))                    // ITER ARR (I+1)
             return false;
 
         MOZ_ASSERT(this->stackDepth == loopDepth - 1);
 
-        // STMT_SPREAD never contain continue, so do not set "update" offset.
+        // StmtType::SPREAD never contain continue, so do not set "update" offset.
     }
 
     // COME FROM the beginning of the loop to here.
     setJumpOffsetAt(jmp);
     if (!emitLoopEntry(forHeadExpr))
         return false;
 
-    if (type == STMT_FOR_OF_LOOP) {
+    if (type == StmtType::FOR_OF_LOOP) {
         if (!emit1(JSOP_POP))                             // ITER
             return false;
         if (!emit1(JSOP_DUP))                             // ITER ITER
             return false;
     } else {
         if (!emitDupAt(this->stackDepth - 1 - 2))         // ITER ARR I ITER
             return false;
     }
@@ -5401,28 +5401,28 @@ BytecodeEmitter::emitForOf(StmtType type
 
     MOZ_ASSERT(this->stackDepth == loopDepth);
 
     // Let Ion know where the closing jump of this loop is.
     if (!setSrcNoteOffset(noteIndex, 0, beq - jmp))
         return false;
 
     // Fixup breaks and continues.
-    // For STMT_SPREAD, just pop pc->topStmt.
+    // For StmtType::SPREAD, just pop pc->topStmt.
     popStatement();
 
     if (!tryNoteList.append(JSTRY_FOR_OF, stackDepth, top, offset()))
         return false;
 
     if (letDecl) {
         if (!leaveNestedScope(&letStmt))
             return false;
     }
 
-    if (type == STMT_SPREAD) {
+    if (type == StmtType::SPREAD) {
         if (!emit2(JSOP_PICK, (jsbytecode)3))      // ARR I RESULT ITER
             return false;
     }
 
     // Pop the result and the iter.
     return emitUint16Operand(JSOP_POPN, 2);
 }
 
@@ -5460,17 +5460,17 @@ BytecodeEmitter::emitForIn(ParseNode* pn
     // assigned to is a plain assignment.
     StmtInfoBCE letStmt(cx);
     if (letDecl) {
         if (!enterBlockScope(&letStmt, pn1->pn_objbox, JSOP_UNDEFINED, 0))
             return false;
     }
 
     LoopStmtInfo stmtInfo(cx);
-    pushLoopStatement(&stmtInfo, STMT_FOR_IN_LOOP, top);
+    pushLoopStatement(&stmtInfo, StmtType::FOR_IN_LOOP, top);
 
     /* Annotate so IonMonkey can find the loop-closing jump. */
     unsigned noteIndex;
     if (!newSrcNote(SRC_FOR_IN, &noteIndex))
         return false;
 
     /*
      * Jump down to the loop condition to minimize overhead assuming at
@@ -5500,17 +5500,17 @@ BytecodeEmitter::emitForIn(ParseNode* pn
     /* Emit code for the loop body. */
     if (!emitTree(forBody))
         return false;
 
     /* Set loop and enclosing "update" offsets, for continue. */
     StmtInfoBCE* stmt = &stmtInfo;
     do {
         stmt->update = offset();
-    } while ((stmt = stmt->down) != nullptr && stmt->type == STMT_LABEL);
+    } while ((stmt = stmt->down) != nullptr && stmt->type == StmtType::LABEL);
 
     /*
      * Fixup the goto that starts the loop to jump down to JSOP_MOREITER.
      */
     setJumpOffsetAt(jmp);
     if (!emitLoopEntry(nullptr))
         return false;
     if (!emit1(JSOP_POP))
@@ -5546,17 +5546,17 @@ BytecodeEmitter::emitForIn(ParseNode* pn
 
     return true;
 }
 
 bool
 BytecodeEmitter::emitNormalFor(ParseNode* pn, ptrdiff_t top)
 {
     LoopStmtInfo stmtInfo(cx);
-    pushLoopStatement(&stmtInfo, STMT_FOR_LOOP, top);
+    pushLoopStatement(&stmtInfo, StmtType::FOR_LOOP, top);
 
     ParseNode* forHead = pn->pn_left;
     ParseNode* forBody = pn->pn_right;
 
     /* C-style for (init; cond; update) ... loop. */
     bool forLoopRequiresFreshening = false;
     JSOp op;
     ParseNode* init = forHead->pn_kid1;
@@ -5621,28 +5621,28 @@ BytecodeEmitter::emitNormalFor(ParseNode
     ptrdiff_t tmp2 = offset();
 
     // Set loop and enclosing "update" offsets, for continue.  Note that we
     // continue to immediately *before* the block-freshening: continuing must
     // refresh the block.
     StmtInfoBCE* stmt = &stmtInfo;
     do {
         stmt->update = offset();
-    } while ((stmt = stmt->down) != nullptr && stmt->type == STMT_LABEL);
+    } while ((stmt = stmt->down) != nullptr && stmt->type == StmtType::LABEL);
 
     // Freshen the block on the scope chain to expose distinct bindings for each loop
     // iteration.
     if (forLoopRequiresFreshening) {
         // The scope chain only includes an actual block *if* the scope object
         // is captured and therefore requires cloning.  Get the static block
         // object from the parent let-block statement (which *must* be the
         // let-statement for the guarding condition to have held) and freshen
         // if the block object needs cloning.
         StmtInfoBCE* parent = stmtInfo.down;
-        MOZ_ASSERT(parent->type == STMT_BLOCK);
+        MOZ_ASSERT(parent->type == StmtType::BLOCK);
         MOZ_ASSERT(parent->isBlockScope);
 
         if (parent->staticScope->as<StaticBlockObject>().needsClone()) {
             if (!emit1(JSOP_FRESHENBLOCKSCOPE))
                 return false;
         }
     }
 
@@ -5705,17 +5705,17 @@ BytecodeEmitter::emitNormalFor(ParseNode
 
 bool
 BytecodeEmitter::emitFor(ParseNode* pn, ptrdiff_t top)
 {
     if (pn->pn_left->isKind(PNK_FORIN))
         return emitForIn(pn, top);
 
     if (pn->pn_left->isKind(PNK_FOROF))
-        return emitForOf(STMT_FOR_OF_LOOP, pn, top);
+        return emitForOf(StmtType::FOR_OF_LOOP, pn, top);
 
     MOZ_ASSERT(pn->pn_left->isKind(PNK_FORHEAD));
     return emitNormalFor(pn, top);
 }
 
 bool
 BytecodeEmitter::arrowNeedsNewTarget()
 {
@@ -5899,30 +5899,30 @@ BytecodeEmitter::emitDo(ParseNode* pn)
         return false;
 
     /* Compile the loop body. */
     ptrdiff_t top = offset();
     if (!emitLoopHead(pn->pn_left))
         return false;
 
     LoopStmtInfo stmtInfo(cx);
-    pushLoopStatement(&stmtInfo, STMT_DO_LOOP, top);
+    pushLoopStatement(&stmtInfo, StmtType::DO_LOOP, top);
 
     if (!emitLoopEntry(nullptr))
         return false;
 
     if (!emitTree(pn->pn_left))
         return false;
 
     /* Set loop and enclosing label update offsets, for continue. */
     ptrdiff_t off = offset();
     StmtInfoBCE* stmt = &stmtInfo;
     do {
         stmt->update = off;
-    } while ((stmt = stmt->down) != nullptr && stmt->type == STMT_LABEL);
+    } while ((stmt = stmt->down) != nullptr && stmt->type == StmtType::LABEL);
 
     /* Compile the loop condition, now that continues know where to go. */
     if (!emitTree(pn->pn_right))
         return false;
 
     ptrdiff_t beq;
     if (!emitJump(JSOP_IFNE, top - offset(), &beq))
         return false;
@@ -5958,17 +5958,17 @@ BytecodeEmitter::emitWhile(ParseNode* pn
      *  =    ===============                 ==================
      *  0    ifeq-pass                       goto; ifne-fail
      *  1    ifeq-fail; goto; ifne-pass      goto; ifne-pass; ifne-fail
      *  2    2*(ifeq-fail; goto); ifeq-pass  goto; 2*ifne-pass; ifne-fail
      *  . . .
      *  N    N*(ifeq-fail; goto); ifeq-pass  goto; N*ifne-pass; ifne-fail
      */
     LoopStmtInfo stmtInfo(cx);
-    pushLoopStatement(&stmtInfo, STMT_WHILE_LOOP, top);
+    pushLoopStatement(&stmtInfo, StmtType::WHILE_LOOP, top);
 
     unsigned noteIndex;
     if (!newSrcNote(SRC_WHILE, &noteIndex))
         return false;
 
     ptrdiff_t jmp;
     if (!emitJump(JSOP_GOTO, 0, &jmp))
         return false;
@@ -6001,36 +6001,36 @@ BytecodeEmitter::emitWhile(ParseNode* pn
 }
 
 bool
 BytecodeEmitter::emitBreak(PropertyName* label)
 {
     StmtInfoBCE* stmt = topStmt;
     SrcNoteType noteType;
     if (label) {
-        while (stmt->type != STMT_LABEL || stmt->label != label)
+        while (stmt->type != StmtType::LABEL || stmt->label != label)
             stmt = stmt->down;
         noteType = SRC_BREAK2LABEL;
     } else {
-        while (!stmt->isLoop() && stmt->type != STMT_SWITCH)
+        while (!stmt->isLoop() && stmt->type != StmtType::SWITCH)
             stmt = stmt->down;
-        noteType = (stmt->type == STMT_SWITCH) ? SRC_SWITCHBREAK : SRC_BREAK;
+        noteType = (stmt->type == StmtType::SWITCH) ? SRC_SWITCHBREAK : SRC_BREAK;
     }
 
     return emitGoto(stmt, &stmt->breaks, noteType);
 }
 
 bool
 BytecodeEmitter::emitContinue(PropertyName* label)
 {
     StmtInfoBCE* stmt = topStmt;
     if (label) {
         /* Find the loop statement enclosed by the matching label. */
         StmtInfoBCE* loop = nullptr;
-        while (stmt->type != STMT_LABEL || stmt->label != label) {
+        while (stmt->type != StmtType::LABEL || stmt->label != label) {
             if (stmt->isLoop())
                 loop = stmt;
             stmt = stmt->down;
         }
         stmt = loop;
     } else {
         while (!stmt->isLoop())
             stmt = stmt->down;
@@ -6038,17 +6038,17 @@ BytecodeEmitter::emitContinue(PropertyNa
 
     return emitGoto(stmt, &stmt->continues, SRC_CONTINUE);
 }
 
 bool
 BytecodeEmitter::inTryBlockWithFinally()
 {
     for (StmtInfoBCE* stmt = topStmt; stmt; stmt = stmt->down) {
-        if (stmt->type == STMT_FINALLY)
+        if (stmt->type == StmtType::FINALLY)
             return true;
     }
     return false;
 }
 
 bool
 BytecodeEmitter::emitReturn(ParseNode* pn)
 {
@@ -6197,17 +6197,17 @@ BytecodeEmitter::emitYieldStar(ParseNode
     MOZ_ASSERT(depth >= 2);
 
     ptrdiff_t initialSend = -1;
     if (!emitBackPatchOp(&initialSend))                          // goto initialSend
         return false;
 
     // Try prologue.                                             // ITER RESULT
     StmtInfoBCE stmtInfo(cx);
-    pushStatement(&stmtInfo, STMT_TRY, offset());
+    pushStatement(&stmtInfo, StmtType::TRY, offset());
     unsigned noteIndex;
     if (!newSrcNote(SRC_TRY, &noteIndex))
         return false;
     ptrdiff_t tryStart = offset();                               // tryStart:
     if (!emit1(JSOP_TRY))
         return false;
     MOZ_ASSERT(this->stackDepth == depth);
 
@@ -6331,17 +6331,17 @@ BytecodeEmitter::emitYieldStar(ParseNode
 }
 
 bool
 BytecodeEmitter::emitStatementList(ParseNode* pn, ptrdiff_t top)
 {
     MOZ_ASSERT(pn->isArity(PN_LIST));
 
     StmtInfoBCE stmtInfo(cx);
-    pushStatement(&stmtInfo, STMT_BLOCK, top);
+    pushStatement(&stmtInfo, StmtType::BLOCK, top);
 
     for (ParseNode* pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
         if (!emitTree(pn2))
             return false;
     }
 
     popStatement();
     return true;
@@ -6382,17 +6382,17 @@ BytecodeEmitter::emitStatement(ParseNode
 
         /*
          * Don't eliminate apparently useless expressions if they are
          * labeled expression statements.  The pc->topStmt->update test
          * catches the case where we are nesting in emitTree for a labeled
          * compound statement.
          */
         if (topStmt &&
-            topStmt->type == STMT_LABEL &&
+            topStmt->type == StmtType::LABEL &&
             topStmt->update >= offset())
         {
             useful = true;
         }
     }
 
     if (useful) {
         JSOp op = wantval ? JSOP_SETRVAL : JSOP_POP;
@@ -6943,17 +6943,17 @@ BytecodeEmitter::emitLabeledStatement(co
         return false;
 
     ptrdiff_t top;
     if (!emitJump(JSOP_LABEL, 0, &top))
         return false;
 
     /* Emit code for the labeled statement. */
     StmtInfoBCE stmtInfo(cx);
-    pushStatement(&stmtInfo, STMT_LABEL, offset());
+    pushStatement(&stmtInfo, StmtType::LABEL, offset());
     stmtInfo.label = pn->label();
 
     if (!emitTree(pn->statement()))
         return false;
 
     popStatement();
 
     /* Patch the JSOP_LABEL offset. */
@@ -7195,17 +7195,17 @@ BytecodeEmitter::emitArrayComp(ParseNode
     arrayCompDepth = saveDepth;
 
     return true;
 }
 
 bool
 BytecodeEmitter::emitSpread()
 {
-    return emitForOf(STMT_SPREAD, nullptr, -1);
+    return emitForOf(StmtType::SPREAD, nullptr, -1);
 }
 
 bool
 BytecodeEmitter::emitArray(ParseNode* pn, uint32_t count, JSOp op)
 {
     /*
      * Emit code for [a, b, c] that is equivalent to constructing a new
      * array and in source order evaluating each element value and adding
--- a/js/src/frontend/BytecodeEmitter.h
+++ b/js/src/frontend/BytecodeEmitter.h
@@ -587,20 +587,20 @@ struct BytecodeEmitter
     // emitSpread expects the current index (I) of the array, the array itself
     // and the iterator to be on the stack in that order (iterator on the bottom).
     // It will pop the iterator and I, then iterate over the iterator by calling
     // |.next()| and put the results into the I-th element of array with
     // incrementing I, then push the result I (it will be original I +
     // iteration count). The stack after iteration will look like |ARRAY INDEX|.
     bool emitSpread();
 
-    // If type is STMT_FOR_OF_LOOP, emit bytecode for a for-of loop.
+    // If type is StmtType::FOR_OF_LOOP, emit bytecode for a for-of loop.
     // pn should be PNK_FOR, and pn->pn_left should be PNK_FOROF.
     //
-    // If type is STMT_SPREAD, emit bytecode for spread operator.
+    // If type is StmtType::SPREAD, emit bytecode for spread operator.
     // pn should be nullptr.
     //
     // Please refer the comment above emitSpread for additional information about
     // stack convention.
     bool emitForOf(StmtType type, ParseNode* pn, ptrdiff_t top);
 
     bool emitClass(ParseNode* pn);
     bool emitSuperPropLHS(bool isCall = false);
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -1321,17 +1321,17 @@ ConvertDefinitionToNamedLambdaUse(TokenS
 }
 
 static bool
 IsNonDominatingInScopedSwitch(ParseContext<FullParseHandler>* pc, HandleAtom name,
                               Definition* dn)
 {
     MOZ_ASSERT(dn->isLexical());
     StmtInfoPC* stmt = LexicalLookup(pc, name);
-    if (stmt && stmt->type == STMT_SWITCH)
+    if (stmt && stmt->type == StmtType::SWITCH)
         return dn->pn_cookie.slot() < stmt->firstDominatingLexicalInCase;
     return false;
 }
 
 static void
 AssociateUsesWithOuterDefinition(ParseNode* pnu, Definition* dn, Definition* outer_dn,
                                  bool markUsesAsLexical)
 {
@@ -2949,17 +2949,17 @@ template <typename ParseHandler>
 bool
 Parser<ParseHandler>::reportRedeclaration(Node pn, Definition::Kind redeclKind, HandlePropertyName name)
 {
     JSAutoByteString printable;
     if (!AtomToPrintableString(context, name, &printable))
         return false;
 
     StmtInfoPC* stmt = LexicalLookup(pc, name);
-    if (stmt && stmt->type == STMT_CATCH) {
+    if (stmt && stmt->type == StmtType::CATCH) {
         report(ParseError, false, pn, JSMSG_REDECLARED_CATCH_IDENTIFIER, printable.ptr());
     } else {
         if (redeclKind == Definition::ARG) {
             report(ParseError, false, pn, JSMSG_REDECLARED_PARAM, printable.ptr());
         } else {
             report(ParseError, false, pn, JSMSG_REDECLARED_VAR, Definition::kindString(redeclKind),
                    printable.ptr());
         }
@@ -3162,17 +3162,17 @@ LexicalLookup(ContextT* ct, HandleAtom a
     if (!stmt)
         stmt = ct->topScopeStmt;
     for (; stmt; stmt = stmt->downScope) {
         /*
          * With-statements introduce dynamic bindings. Since dynamic bindings
          * can potentially override any static bindings introduced by statements
          * further up the stack, we have to abort the search.
          */
-        if (stmt->type == STMT_WITH && !ct->sc->isDotVariable(atom))
+        if (stmt->type == StmtType::WITH && !ct->sc->isDotVariable(atom))
             break;
 
         // Skip statements that do not introduce a new scope
         if (!stmt->isBlockScope)
             continue;
 
         StaticBlockObject& blockObj = stmt->staticBlock();
         Shape* shape = blockObj.lookup(ct->sc->context, id);
@@ -3186,17 +3186,17 @@ LexicalLookup(ContextT* ct, HandleAtom a
 template <typename ParseHandler>
 static inline bool
 OuterLet(ParseContext<ParseHandler>* pc, StmtInfoPC* stmt, HandleAtom atom)
 {
     while (stmt->downScope) {
         stmt = LexicalLookup(pc, atom, stmt->downScope);
         if (!stmt)
             return false;
-        if (stmt->type == STMT_BLOCK)
+        if (stmt->type == StmtType::BLOCK)
             return true;
     }
     return false;
 }
 
 template <typename ParseHandler>
 /* static */ bool
 Parser<ParseHandler>::bindVarOrGlobalConst(BindData<ParseHandler>* data,
@@ -3210,17 +3210,17 @@ Parser<ParseHandler>::bindVarOrGlobalCon
     /* Default best op for pn is JSOP_GETNAME; we'll try to improve below. */
     parser->handler.setOp(pn, JSOP_GETNAME);
 
     if (!parser->checkStrictBinding(name, pn))
         return false;
 
     StmtInfoPC* stmt = LexicalLookup(pc, name);
 
-    if (stmt && stmt->type == STMT_WITH) {
+    if (stmt && stmt->type == StmtType::WITH) {
         parser->handler.setFlag(pn, PND_DEOPTIMIZED);
         if (pc->sc->isFunctionBox()) {
             FunctionBox* funbox = pc->sc->asFunctionBox();
             funbox->setMightAliasLocals();
         }
 
         /*
          * This definition isn't being added to the parse context's
@@ -3259,17 +3259,17 @@ Parser<ParseHandler>::bindVarOrGlobalCon
 
         if (isConstDecl) {
             parser->report(ParseError, false, pn, JSMSG_REDECLARED_PARAM, bytes.ptr());
             return false;
         }
         if (!parser->report(ParseExtraWarning, false, pn, JSMSG_VAR_HIDES_ARG, bytes.ptr()))
             return false;
     } else {
-        bool inCatchBody = (stmt && stmt->type == STMT_CATCH);
+        bool inCatchBody = (stmt && stmt->type == StmtType::CATCH);
         bool error = (isConstDecl ||
                       dn_kind == Definition::CONST ||
                       dn_kind == Definition::GLOBALCONST ||
                       (dn_kind == Definition::LET &&
                        (!inCatchBody || OuterLet(pc, stmt, name))));
 
         if (parser->options().extraWarningsOption
             ? data->op != JSOP_DEFVAR || dn_kind != Definition::VAR
@@ -3344,19 +3344,19 @@ Parser<ParseHandler>::noteNameUse(Handle
         dn = getOrCreateLexicalDependency(pc, name);
         if (!dn)
             return false;
     }
 
     handler.linkUseToDef(pn, dn);
 
     if (stmt) {
-        if (stmt->type == STMT_WITH) {
+        if (stmt->type == StmtType::WITH) {
             handler.setFlag(pn, PND_DEOPTIMIZED);
-        } else if (stmt->type == STMT_SWITCH && stmt->isBlockScope) {
+        } else if (stmt->type == StmtType::SWITCH && stmt->isBlockScope) {
             // See comments above StmtInfoPC and switchStatement for how
             // firstDominatingLexicalInCase is computed.
             MOZ_ASSERT(stmt->firstDominatingLexicalInCase <= stmt->staticBlock().numVariables());
             handler.markMaybeUninitializedLexicalUseInSwitch(pn, dn,
                                                              stmt->firstDominatingLexicalInCase);
         }
     }
 
@@ -3628,17 +3628,17 @@ typename ParseHandler::Node
 Parser<ParseHandler>::pushLexicalScope(HandleStaticBlockObject blockObj, StmtInfoPC* stmt)
 {
     MOZ_ASSERT(blockObj);
 
     ObjectBox* blockbox = newObjectBox(blockObj);
     if (!blockbox)
         return null();
 
-    PushStatementPC(pc, stmt, STMT_BLOCK);
+    PushStatementPC(pc, stmt, StmtType::BLOCK);
     blockObj->initEnclosingNestedScopeFromParser(pc->staticScope);
     FinishPushNestedScope(pc, stmt, *blockObj.get());
     stmt->isBlockScope = true;
 
     Node pn = handler.newLexicalScope(blockbox);
     if (!pn)
         return null();
 
@@ -3761,17 +3761,17 @@ PushBlocklikeStatement(TokenStream& ts, 
 
 template <typename ParseHandler>
 typename ParseHandler::Node
 Parser<ParseHandler>::blockStatement(YieldHandling yieldHandling)
 {
     MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_LC));
 
     StmtInfoPC stmtInfo(context);
-    if (!PushBlocklikeStatement(tokenStream, &stmtInfo, STMT_BLOCK, pc))
+    if (!PushBlocklikeStatement(tokenStream, &stmtInfo, StmtType::BLOCK, pc))
         return null();
 
     Node list = statements(yieldHandling);
     if (!list)
         return null();
 
     MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_IN_COMPOUND);
     PopStatementPC(tokenStream, pc);
@@ -4074,20 +4074,20 @@ Parser<FullParseHandler>::checkAndPrepar
 
         /*
          * Some obvious assertions here, but they may help clarify the
          * situation. This stmt is not yet a scope, so it must not be a
          * catch block (catch is a lexical scope by definition).
          */
         MOZ_ASSERT(!stmt->isBlockScope);
         MOZ_ASSERT(stmt != pc->topScopeStmt);
-        MOZ_ASSERT(stmt->type == STMT_BLOCK ||
-                    stmt->type == STMT_SWITCH ||
-                    stmt->type == STMT_TRY ||
-                    stmt->type == STMT_FINALLY);
+        MOZ_ASSERT(stmt->type == StmtType::BLOCK ||
+                   stmt->type == StmtType::SWITCH ||
+                   stmt->type == StmtType::TRY ||
+                   stmt->type == StmtType::FINALLY);
         MOZ_ASSERT(!stmt->downScope);
 
         /* Convert the block statement into a scope statement. */
         StaticBlockObject* blockObj = StaticBlockObject::create(context);
         if (!blockObj)
             return false;
 
         ObjectBox* blockbox = newObjectBox(blockObj);
@@ -4690,17 +4690,17 @@ Parser<ParseHandler>::ifStatement(YieldH
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
 Parser<ParseHandler>::doWhileStatement(YieldHandling yieldHandling)
 {
     uint32_t begin = pos().begin;
     StmtInfoPC stmtInfo(context);
-    PushStatementPC(pc, &stmtInfo, STMT_DO_LOOP);
+    PushStatementPC(pc, &stmtInfo, StmtType::DO_LOOP);
     Node body = statement(yieldHandling);
     if (!body)
         return null();
     MUST_MATCH_TOKEN(TOK_WHILE, JSMSG_WHILE_AFTER_DO);
     Node cond = condition(InAllowed, yieldHandling);
     if (!cond)
         return null();
     PopStatementPC(tokenStream, pc);
@@ -4717,17 +4717,17 @@ Parser<ParseHandler>::doWhileStatement(Y
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
 Parser<ParseHandler>::whileStatement(YieldHandling yieldHandling)
 {
     uint32_t begin = pos().begin;
     StmtInfoPC stmtInfo(context);
-    PushStatementPC(pc, &stmtInfo, STMT_WHILE_LOOP);
+    PushStatementPC(pc, &stmtInfo, StmtType::WHILE_LOOP);
     Node cond = condition(InAllowed, yieldHandling);
     if (!cond)
         return null();
     Node body = statement(yieldHandling);
     if (!body)
         return null();
     PopStatementPC(tokenStream, pc);
     return handler.newWhileStatement(begin, cond, body);
@@ -4791,17 +4791,17 @@ Parser<FullParseHandler>::checkForHeadCo
 template <>
 ParseNode*
 Parser<FullParseHandler>::forStatement(YieldHandling yieldHandling)
 {
     MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FOR));
     uint32_t begin = pos().begin;
 
     StmtInfoPC forStmt(context);
-    PushStatementPC(pc, &forStmt, STMT_FOR_LOOP);
+    PushStatementPC(pc, &forStmt, StmtType::FOR_LOOP);
 
     bool isForEach = false;
     unsigned iflags = 0;
 
     if (allowsForEachIn()) {
         bool matched;
         if (!tokenStream.matchContextualKeyword(&matched, context->names().each))
             return null();
@@ -4943,23 +4943,23 @@ Parser<FullParseHandler>::forStatement(Y
          * Parse the rest of the for/in or for/of head.
          *
          * Here pn1 is everything to the left of 'in' or 'of'. At the end of
          * this block, pn1 is a decl or nullptr, pn2 is the assignment target
          * that receives the enumeration value each iteration, and pn3 is the
          * rhs of 'in'.
          */
         if (headKind == PNK_FOROF) {
-            forStmt.type = STMT_FOR_OF_LOOP;
+            forStmt.type = StmtType::FOR_OF_LOOP;
             if (isForEach) {
                 report(ParseError, false, null(), JSMSG_BAD_FOR_EACH_LOOP);
                 return null();
             }
         } else {
-            forStmt.type = STMT_FOR_IN_LOOP;
+            forStmt.type = StmtType::FOR_IN_LOOP;
             iflags |= JSITER_ENUMERATE;
         }
 
         /* Check that the left side of the 'in' or 'of' is valid. */
         if (!isValidForStatementLHS(pn1, versionNumber(), isForDecl, isForEach, headKind)) {
             report(ParseError, false, pn1, JSMSG_BAD_FOR_LEFTSIDE);
             return null();
         }
@@ -5146,17 +5146,17 @@ Parser<SyntaxParseHandler>::forStatement
      * 'for' statement parsing is fantastically complicated and requires being
      * able to inspect the parse tree for previous parts of the 'for'. Syntax
      * parsing of 'for' statements is thus done separately, and only handles
      * the types of 'for' statements likely to be seen in web content.
      */
     MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FOR));
 
     StmtInfoPC forStmt(context);
-    PushStatementPC(pc, &forStmt, STMT_FOR_LOOP);
+    PushStatementPC(pc, &forStmt, StmtType::FOR_LOOP);
 
     /* Don't parse 'for each' loops. */
     if (allowsForEachIn()) {
         TokenKind tt;
         if (!tokenStream.peekToken(&tt))
             return null();
         // Not all "yield" tokens are names, but the ones that aren't names are
         // invalid in this context anyway.
@@ -5204,17 +5204,17 @@ Parser<SyntaxParseHandler>::forStatement
     // parsing of |pn1|.
     bool isForIn = false, isForOf = false;
     if (lhsNode) {
         if (!matchInOrOf(&isForIn, &isForOf))
             return null();
     }
     if (isForIn || isForOf) {
         /* Parse the rest of the for/in or for/of head. */
-        forStmt.type = isForOf ? STMT_FOR_OF_LOOP : STMT_FOR_IN_LOOP;
+        forStmt.type = isForOf ? StmtType::FOR_OF_LOOP : StmtType::FOR_IN_LOOP;
 
         /* Check that the left side of the 'in' or 'of' is valid. */
         if (!isForDecl &&
             !handler.maybeNameAnyParentheses(lhsNode) &&
             !handler.isPropertyAccess(lhsNode))
         {
             JS_ALWAYS_FALSE(abortIfSyntaxParser());
             return null();
@@ -5273,17 +5273,17 @@ Parser<ParseHandler>::switchStatement(Yi
     Node discriminant = exprInParens(InAllowed, yieldHandling);
     if (!discriminant)
         return null();
 
     MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_SWITCH);
     MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_SWITCH);
 
     StmtInfoPC stmtInfo(context);
-    PushStatementPC(pc, &stmtInfo, STMT_SWITCH);
+    PushStatementPC(pc, &stmtInfo, StmtType::SWITCH);
 
     if (!GenerateBlockId(tokenStream, pc, pc->topStmt->blockid))
         return null();
 
     Node caseList = handler.newStatementList(pc->blockid(), pos());
     if (!caseList)
         return null();
 
@@ -5410,17 +5410,17 @@ Parser<ParseHandler>::continueStatement(
 
     StmtInfoPC* stmt = pc->topStmt;
     if (label) {
         for (StmtInfoPC* stmt2 = nullptr; ; stmt = stmt->down) {
             if (!stmt) {
                 report(ParseError, false, null(), JSMSG_LABEL_NOT_FOUND);
                 return null();
             }
-            if (stmt->type == STMT_LABEL) {
+            if (stmt->type == StmtType::LABEL) {
                 if (stmt->label == label) {
                     if (!stmt2 || !stmt2->isLoop()) {
                         report(ParseError, false, null(), JSMSG_BAD_CONTINUE);
                         return null();
                     }
                     break;
                 }
             } else {
@@ -5456,26 +5456,26 @@ Parser<ParseHandler>::breakStatement(Yie
         return null();
     StmtInfoPC* stmt = pc->topStmt;
     if (label) {
         for (; ; stmt = stmt->down) {
             if (!stmt) {
                 report(ParseError, false, null(), JSMSG_LABEL_NOT_FOUND);
                 return null();
             }
-            if (stmt->type == STMT_LABEL && stmt->label == label)
+            if (stmt->type == StmtType::LABEL && stmt->label == label)
                 break;
         }
     } else {
         for (; ; stmt = stmt->down) {
             if (!stmt) {
                 report(ParseError, false, null(), JSMSG_TOUGH_BREAK);
                 return null();
             }
-            if (stmt->isLoop() || stmt->type == STMT_SWITCH)
+            if (stmt->isLoop() || stmt->type == StmtType::SWITCH)
                 break;
         }
     }
 
     if (!MatchOrInsertSemicolon(tokenStream))
         return null();
 
     return handler.newBreakStatement(label, TokenPos(begin, pos().end));
@@ -5697,17 +5697,17 @@ Parser<FullParseHandler>::withStatement(
     if (!objectExpr)
         return null();
     MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_WITH);
 
     bool oldParsingWith = pc->parsingWith;
     pc->parsingWith = true;
 
     StmtInfoPC stmtInfo(context);
-    PushStatementPC(pc, &stmtInfo, STMT_WITH);
+    PushStatementPC(pc, &stmtInfo, StmtType::WITH);
     Rooted<StaticWithObject*> staticWith(context, StaticWithObject::create(context));
     if (!staticWith)
         return null();
     staticWith->initEnclosingNestedScopeFromParser(pc->staticScope);
     FinishPushNestedScope(pc, &stmtInfo, *staticWith);
 
     Node innerBlock = statement(yieldHandling);
     if (!innerBlock)
@@ -5745,27 +5745,27 @@ Parser<SyntaxParseHandler>::withStatemen
 
 template <typename ParseHandler>
 typename ParseHandler::Node
 Parser<ParseHandler>::labeledStatement(YieldHandling yieldHandling)
 {
     uint32_t begin = pos().begin;
     RootedPropertyName label(context, tokenStream.currentName());
     for (StmtInfoPC* stmt = pc->topStmt; stmt; stmt = stmt->down) {
-        if (stmt->type == STMT_LABEL && stmt->label == label) {
+        if (stmt->type == StmtType::LABEL && stmt->label == label) {
             report(ParseError, false, null(), JSMSG_DUPLICATE_LABEL);
             return null();
         }
     }
 
     tokenStream.consumeKnownToken(TOK_COLON);
 
     /* Push a label struct and parse the statement. */
     StmtInfoPC stmtInfo(context);
-    PushStatementPC(pc, &stmtInfo, STMT_LABEL);
+    PushStatementPC(pc, &stmtInfo, StmtType::LABEL);
     stmtInfo.label = label;
     Node pn = statement(yieldHandling);
     if (!pn)
         return null();
 
     /* Pop the label, set pn_expr, and return early. */
     PopStatementPC(tokenStream, pc);
 
@@ -5824,17 +5824,17 @@ Parser<ParseHandler>::tryStatement(Yield
      *   TOK_NAME for a single identifier
      *   TOK_RB or TOK_RC for a destructuring left-hand side
      *
      * finally nodes are TOK_LC statement lists.
      */
 
     MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_TRY);
     StmtInfoPC stmtInfo(context);
-    if (!PushBlocklikeStatement(tokenStream, &stmtInfo, STMT_TRY, pc))
+    if (!PushBlocklikeStatement(tokenStream, &stmtInfo, StmtType::TRY, pc))
         return null();
     Node innerBlock = statements(yieldHandling);
     if (!innerBlock)
         return null();
     MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_TRY);
     PopStatementPC(tokenStream, pc);
 
     bool hasUnconditionalCatch = false;
@@ -5859,17 +5859,17 @@ Parser<ParseHandler>::tryStatement(Yield
 
             /*
              * Create a lexical scope node around the whole catch clause,
              * including the head.
              */
             pnblock = pushLexicalScope(&stmtInfo);
             if (!pnblock)
                 return null();
-            stmtInfo.type = STMT_CATCH;
+            stmtInfo.type = StmtType::CATCH;
 
             /*
              * Legal catch forms are:
              *   catch (lhs)
              *   catch (lhs if <boolean_expression>)
              * where lhs is a name or a destructuring left-hand side.
              * (the latter is legal only #ifdef JS_HAS_CATCH_GUARD)
              */
@@ -5960,17 +5960,17 @@ Parser<ParseHandler>::tryStatement(Yield
                 return null();
         } while (tt == TOK_CATCH);
     }
 
     Node finallyBlock = null();
 
     if (tt == TOK_FINALLY) {
         MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_FINALLY);
-        if (!PushBlocklikeStatement(tokenStream, &stmtInfo, STMT_FINALLY, pc))
+        if (!PushBlocklikeStatement(tokenStream, &stmtInfo, StmtType::FINALLY, pc))
             return null();
         finallyBlock = statements(yieldHandling);
         if (!finallyBlock)
             return null();
         MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_FINALLY);
         PopStatementPC(tokenStream, pc);
     } else {
         tokenStream.ungetToken();
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -30,17 +30,17 @@ struct StmtInfoPC : public StmtInfoBase 
     uint32_t        blockid;        /* for simplified dominance computation */
     uint32_t        innerBlockScopeDepth; /* maximum depth of nested block scopes, in slots */
 
     // Lexical declarations inside switches are tricky because the block id
     // doesn't convey dominance information. Record what index the current
     // case's lexical declarations start at so we may generate dead zone
     // checks for other cases' declarations.
     //
-    // Only valid if type is STMT_SWITCH.
+    // Only valid if type is StmtType::SWITCH.
     uint16_t        firstDominatingLexicalInCase;
 
     explicit StmtInfoPC(ExclusiveContext* cx)
       : StmtInfoBase(cx),
         innerBlockScopeDepth(0),
         firstDominatingLexicalInCase(0)
     {}
 };
--- a/js/src/frontend/SharedContext.h
+++ b/js/src/frontend/SharedContext.h
@@ -444,35 +444,35 @@ SharedContext::allLocalsAliased()
  * NB: If you add a new type of statement that is a scope, add it between
  * STMT_WITH and STMT_CATCH, or you will break StmtInfoBase::linksScope. If you
  * add a non-looping statement type, add it before STMT_DO_LOOP or you will
  * break StmtInfoBase::isLoop().
  *
  * Also remember to keep the statementName array in BytecodeEmitter.cpp in
  * sync.
  */
-enum StmtType {
-    STMT_LABEL,                 /* labeled statement:  L: s */
-    STMT_IF,                    /* if (then) statement */
-    STMT_ELSE,                  /* else clause of if statement */
-    STMT_SEQ,                   /* synthetic sequence of statements */
-    STMT_BLOCK,                 /* compound statement: { s1[;... sN] } */
-    STMT_SWITCH,                /* switch statement */
-    STMT_WITH,                  /* with statement */
-    STMT_CATCH,                 /* catch block */
-    STMT_TRY,                   /* try block */
-    STMT_FINALLY,               /* finally block */
-    STMT_SUBROUTINE,            /* gosub-target subroutine body */
-    STMT_DO_LOOP,               /* do/while loop statement */
-    STMT_FOR_LOOP,              /* for loop statement */
-    STMT_FOR_IN_LOOP,           /* for/in loop statement */
-    STMT_FOR_OF_LOOP,           /* for/of loop statement */
-    STMT_WHILE_LOOP,            /* while loop statement */
-    STMT_SPREAD,                /* spread operator (pseudo for/of) */
-    STMT_LIMIT
+enum class StmtType : uint16_t {
+    LABEL,                 /* labeled statement:  L: s */
+    IF,                    /* if (then) statement */
+    ELSE,                  /* else clause of if statement */
+    SEQ,                   /* synthetic sequence of statements */
+    BLOCK,                 /* compound statement: { s1[;... sN] } */
+    SWITCH,                /* switch statement */
+    WITH,                  /* with statement */
+    CATCH,                 /* catch block */
+    TRY,                   /* try block */
+    FINALLY,               /* finally block */
+    SUBROUTINE,            /* gosub-target subroutine body */
+    DO_LOOP,               /* do/while loop statement */
+    FOR_LOOP,              /* for loop statement */
+    FOR_IN_LOOP,           /* for/in loop statement */
+    FOR_OF_LOOP,           /* for/of loop statement */
+    WHILE_LOOP,            /* while loop statement */
+    SPREAD,                /* spread operator (pseudo for/of) */
+    LIMIT
 };
 
 /*
  * A comment on the encoding of the js::StmtType enum and StmtInfoBase
  * type-testing methods:
  *
  * StmtInfoBase::maybeScope() tells whether a statement type is always, or may
  * become, a lexical scope. It therefore includes block and switch (the two
@@ -493,24 +493,24 @@ enum StmtType {
 
 // StmtInfoPC is used by the Parser.  StmtInfoBCE is used by the
 // BytecodeEmitter.  The two types have some overlap, encapsulated by
 // StmtInfoBase.  Several functions below (e.g. PushStatement) are templated to
 // work with both types.
 
 struct StmtInfoBase {
     // Statement type (StmtType).
-    uint16_t        type;
+    StmtType type;
 
-    // True if type is STMT_BLOCK, STMT_TRY, STMT_SWITCH, or STMT_FINALLY and
-    // the block contains at least one let-declaration, or if type is
-    // STMT_CATCH.
+    // True if type is StmtType::BLOCK, StmtType::TRY, StmtType::SWITCH, or
+    // StmtType::FINALLY and the block contains at least one let-declaration,
+    // or if type is StmtType::CATCH.
     bool isBlockScope:1;
 
-    // True if isBlockScope or type == STMT_WITH.
+    // True if isBlockScope or type == StmtType::WITH.
     bool isNestedScope:1;
 
     // for (let ...) induced block scope
     bool isForLetBlock:1;
 
     // Block label.
     RootedAtom      label;
 
@@ -519,38 +519,36 @@ struct StmtInfoBase {
     Rooted<NestedScopeObject*> staticScope;
 
     explicit StmtInfoBase(ExclusiveContext* cx)
         : isBlockScope(false), isNestedScope(false), isForLetBlock(false),
           label(cx), staticScope(cx)
     {}
 
     bool maybeScope() const {
-        return STMT_BLOCK <= type && type <= STMT_SUBROUTINE && type != STMT_WITH;
+        return StmtType::BLOCK <= type && type <= StmtType::SUBROUTINE &&
+               type != StmtType::WITH;
     }
 
     bool linksScope() const {
         return isNestedScope;
     }
 
-    void setStaticScope() {
-    }
-
     StaticBlockObject& staticBlock() const {
         MOZ_ASSERT(isNestedScope);
         MOZ_ASSERT(isBlockScope);
         return staticScope->as<StaticBlockObject>();
     }
 
     bool isLoop() const {
-        return type >= STMT_DO_LOOP;
+        return type >= StmtType::DO_LOOP;
     }
 
     bool isTrying() const {
-        return STMT_TRY <= type && type <= STMT_SUBROUTINE;
+        return StmtType::TRY <= type && type <= StmtType::SUBROUTINE;
     }
 };
 
 // Push the C-stack-allocated struct at stmt onto the StmtInfoPC stack.
 template <class ContextT>
 void
 PushStatement(ContextT* ct, typename ContextT::StmtInfo* stmt, StmtType type)
 {