Backout bug 1071646, bug 1231758 for breaking the web. (r=woe)
authorShu-yu Guo <shu@rfrn.org>
Mon, 14 Dec 2015 13:28:14 -0800
changeset 276353 d2bec6ed7b30
parent 276352 9c9c92d39b01
child 276354 fe18b8f63cd6
push id69135
push usershu@rfrn.org
push date2015-12-14 21:40 +0000
treeherdermozilla-inbound@d2bec6ed7b30 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerswoe
bugs1071646, 1231758
milestone45.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
Backout bug 1071646, bug 1231758 for breaking the web. (r=woe)
js/src/builtin/ReflectParse.cpp
js/src/frontend/BytecodeEmitter.cpp
js/src/frontend/BytecodeEmitter.h
js/src/frontend/FoldConstants.cpp
js/src/frontend/FullParseHandler.h
js/src/frontend/NameFunctions.cpp
js/src/frontend/ParseNode.cpp
js/src/frontend/ParseNode.h
js/src/frontend/Parser.cpp
js/src/frontend/Parser.h
js/src/frontend/SharedContext.h
js/src/frontend/SyntaxParseHandler.h
js/src/jit-test/tests/auto-regress/bug771027.js
js/src/jit-test/tests/baseline/bug1081850.js
js/src/jit-test/tests/basic/bug667504-syntax.js
js/src/jit-test/tests/ion/bug1148973-1.js
js/src/jit/BaselineCompiler.cpp
js/src/jit/BaselineCompiler.h
js/src/jit/BytecodeAnalysis.cpp
js/src/jit/CodeGenerator.cpp
js/src/jit/CodeGenerator.h
js/src/jit/IonBuilder.cpp
js/src/jit/IonBuilder.h
js/src/jit/Lowering.cpp
js/src/jit/Lowering.h
js/src/jit/MIR.h
js/src/jit/MOpcodes.h
js/src/jit/VMFunctions.cpp
js/src/jit/VMFunctions.h
js/src/jit/shared/LIR-shared.h
js/src/jit/shared/LOpcodes-shared.h
js/src/js.msg
js/src/tests/ecma_5/extensions/function-definition-with.js
js/src/tests/ecma_5/extensions/strict-function-statements.js
js/src/tests/ecma_6/LexicalEnvironment/block-scoped-functions-annex-b-eval.js
js/src/tests/ecma_6/LexicalEnvironment/block-scoped-functions-annex-b-if.js
js/src/tests/ecma_6/LexicalEnvironment/block-scoped-functions-annex-b-label.js
js/src/tests/ecma_6/LexicalEnvironment/block-scoped-functions-annex-b-property.js
js/src/tests/ecma_6/LexicalEnvironment/block-scoped-functions-annex-b-same-name.js
js/src/tests/ecma_6/LexicalEnvironment/block-scoped-functions-annex-b-with.js
js/src/tests/ecma_6/LexicalEnvironment/block-scoped-functions-annex-b.js
js/src/tests/ecma_6/LexicalEnvironment/block-scoped-functions-strict.js
js/src/tests/ecma_6/extensions/for-loop-with-lexical-declaration-and-nested-function-statement.js
js/src/tests/js1_5/Regress/regress-326453.js
js/src/tests/js1_5/extensions/regress-245795.js
js/src/tests/js1_5/extensions/regress-406572.js
js/src/tests/js1_8_5/reflect-parse/declarations.js
js/src/vm/Interpreter.cpp
js/src/vm/Opcodes.h
js/src/vm/Xdr.h
--- a/js/src/builtin/ReflectParse.cpp
+++ b/js/src/builtin/ReflectParse.cpp
@@ -2035,19 +2035,16 @@ ASTSerializer::declaration(ParseNode* pn
                pn->isKind(PNK_VAR) ||
                pn->isKind(PNK_LET) ||
                pn->isKind(PNK_CONST));
 
     switch (pn->getKind()) {
       case PNK_FUNCTION:
         return function(pn, AST_FUNC_DECL, dst);
 
-      case PNK_ANNEXB_FUNCTION:
-        return function(pn->pn_left, AST_FUNC_DECL, dst);
-
       case PNK_VAR:
         return variableDeclaration(pn, false, dst);
 
       default:
         MOZ_ASSERT(pn->isKind(PNK_LET) || pn->isKind(PNK_CONST));
         return variableDeclaration(pn, true, dst);
     }
 }
@@ -2409,19 +2406,16 @@ bool
 ASTSerializer::statement(ParseNode* pn, MutableHandleValue dst)
 {
     JS_CHECK_RECURSION(cx, return false);
     switch (pn->getKind()) {
       case PNK_FUNCTION:
       case PNK_VAR:
         return declaration(pn, dst);
 
-      case PNK_ANNEXB_FUNCTION:
-        return declaration(pn->pn_left, dst);
-
       case PNK_LETBLOCK:
         return letBlock(pn, dst);
 
       case PNK_LET:
       case PNK_CONST:
         return declaration(pn, dst);
 
       case PNK_IMPORT:
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -1367,30 +1367,30 @@ BytecodeEmitter::emitVarIncDec(ParseNode
         return false;
     if (post && !emit1(JSOP_POP))                            // RESULT
         return false;
 
     return true;
 }
 
 bool
-BytecodeEmitter::atBodyLevel(StmtInfoBCE* stmt) const
+BytecodeEmitter::atBodyLevel() const
 {
     // 'eval' and non-syntactic scripts are always under an invisible lexical
     // scope, but since it is not syntactic, it should still be considered at
     // body level.
     if (sc->staticScope()->is<StaticEvalObject>()) {
-        bool bl = !stmt->enclosing;
-        MOZ_ASSERT_IF(bl, stmt->type == StmtType::BLOCK);
-        MOZ_ASSERT_IF(bl, stmt->staticScope
-                              ->as<StaticBlockObject>()
-                              .enclosingStaticScope() == sc->staticScope());
+        bool bl = !innermostStmt()->enclosing;
+        MOZ_ASSERT_IF(bl, innermostStmt()->type == StmtType::BLOCK);
+        MOZ_ASSERT_IF(bl, innermostStmt()->staticScope
+                                         ->as<StaticBlockObject>()
+                                         .enclosingStaticScope() == sc->staticScope());
         return bl;
     }
-    return !stmt || sc->isModuleBox();
+    return !innermostStmt() || sc->isModuleBox();
 }
 
 uint32_t
 BytecodeEmitter::computeHops(ParseNode* pn, BytecodeEmitter** bceOfDefOut)
 {
     Definition* dn = pn->resolve();
     MOZ_ASSERT(dn->isDefn());
     MOZ_ASSERT(!dn->isPlaceholder());
@@ -1733,17 +1733,17 @@ BytecodeEmitter::bindNameToSlotHelper(Pa
      */
     Definition* dn;
     if (pn->isUsed()) {
         MOZ_ASSERT(pn->pn_scopecoord.isFree());
         dn = pn->pn_lexdef;
         MOZ_ASSERT(dn->isDefn());
         pn->pn_dflags |= (dn->pn_dflags & PND_CONST);
     } else if (pn->isDefn()) {
-        dn = &pn->as<Definition>();
+        dn = (Definition*) pn;
     } else {
         return true;
     }
 
     if (dn->pn_scopecoord.isFree()) {
         if (evalCaller) {
             MOZ_ASSERT(script->treatAsRunOnce() || sc->isFunctionBox());
 
@@ -2339,20 +2339,16 @@ BytecodeEmitter::checkSideEffects(ParseN
         *answer = pn->pn_count > 1;
         return true;
 
       case PNK_ARRAYCOMP:
         MOZ_ASSERT(pn->isArity(PN_LIST));
         MOZ_ASSERT(pn->pn_count == 1);
         return checkSideEffects(pn->pn_head, answer);
 
-      case PNK_ANNEXB_FUNCTION:
-        MOZ_ASSERT(pn->isArity(PN_BINARY));
-        return checkSideEffects(pn->pn_left, answer);
-
       case PNK_ARGSBODY:
         *answer = true;
         return true;
 
       case PNK_FORIN:           // by PNK_FOR/PNK_COMPREHENSIONFOR
       case PNK_FOROF:           // by PNK_FOR/PNK_COMPREHENSIONFOR
       case PNK_FORHEAD:         // by PNK_FOR/PNK_COMPREHENSIONFOR
       case PNK_CLASSMETHOD:     // by PNK_CLASS
@@ -3093,33 +3089,21 @@ 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 = StmtType::SWITCH;
+        stmtInfo.update = top = offset();
+
         // Advance |cases| to refer to the switch case list.
         cases = cases->expr();
-
-        // A switch statement may contain hoisted functions inside its
-        // cases. The PNX_FUNCDEFS flag is propagated from the STATEMENTLIST
-        // bodies of the cases to the case list.
-        if (cases->pn_xflags & PNX_FUNCDEFS) {
-            for (ParseNode* caseNode = cases->pn_head; caseNode; caseNode = caseNode->pn_next) {
-                if (caseNode->pn_right->pn_xflags & PNX_FUNCDEFS) {
-                    if (!emitHoistedFunctionsInList(caseNode->pn_right))
-                        return false;
-                }
-            }
-        }
-
-        stmtInfo.type = StmtType::SWITCH;
-        stmtInfo.update = top = offset();
     } else {
         MOZ_ASSERT(cases->isKind(PNK_STATEMENTLIST));
         top = offset();
         pushStatement(&stmtInfo, StmtType::SWITCH, top);
     }
 
     // Switch bytecodes run from here till end of final case.
     uint32_t caseCount = cases->pn_count;
@@ -4409,34 +4393,22 @@ BytecodeEmitter::emitVariables(ParseNode
             /*
              * A destructuring initialiser assignment preceded by var will
              * never occur to the left of 'in' in a for-in loop.  As with 'for
              * (var x = i in o)...', this will cause the entire 'var [a, b] =
              * i' to be hoisted out of the loop.
              */
             MOZ_ASSERT(binding->isOp(JSOP_NOP));
             MOZ_ASSERT(emitOption != DefineVars);
-            MOZ_ASSERT_IF(emitOption == AnnexB, binding->pn_left->isKind(PNK_NAME));
-
-            // To allow the front end to rewrite |var f = x;| as |f = x;| when a
-            // |function f(){}| precedes the var, detect simple name assignment
-            // here and initialize the name.
-            //
-            // There is a corner case where a function declaration synthesizes
-            // an Annex B declaration, which in turn gets rewritten later as a
-            // simple assignment due to hoisted function declaration of the
-            // same name. For example,
-            //
-            // {
-            //   // Synthesizes an Annex B declaration because no 'f' binding
-            //   // yet exists. This later gets rewritten as an assignment when
-            //   // the outer function 'f' gets hoisted.
-            //   function f() {}
-            // }
-            // function f() {}
+
+            /*
+             * To allow the front end to rewrite var f = x; as f = x; when a
+             * function f(){} precedes the var, detect simple name assignment
+             * here and initialize the name.
+             */
             if (binding->pn_left->isKind(PNK_NAME)) {
                 if (!emitSingleVariable(pn, binding->pn_left, binding->pn_right, emitOption))
                     return false;
             } else {
                 ParseNode* initializer = binding->pn_left;
                 if (!emitDestructuringDecls(pn->getOp(), initializer))
                     return false;
 
@@ -4481,28 +4453,23 @@ BytecodeEmitter::emitSingleVariable(Pars
     if (initializer) {
         MOZ_ASSERT(emitOption != DefineVars);
         if (op == JSOP_SETNAME ||
             op == JSOP_STRICTSETNAME ||
             op == JSOP_SETGNAME ||
             op == JSOP_STRICTSETGNAME)
         {
             MOZ_ASSERT(emitOption != PushInitialValues);
-            if (op == JSOP_SETGNAME || op == JSOP_STRICTSETGNAME) {
-                if (!emitIndex32(JSOP_BINDGNAME, atomIndex))
-                    return false;
-            } else if (emitOption == AnnexB) {
-                // Annex B vars always go on the nearest variable environment,
-                // even if scopes on the chain contain same-named bindings.
-                if (!emit1(JSOP_BINDVAR))
-                    return false;
-            } else {
-                if (!emitIndex32(JSOP_BINDNAME, atomIndex))
-                    return false;
-            }
+            JSOp bindOp;
+            if (op == JSOP_SETNAME || op == JSOP_STRICTSETNAME)
+                bindOp = JSOP_BINDNAME;
+            else
+                bindOp = JSOP_BINDGNAME;
+            if (!emitIndex32(bindOp, atomIndex))
+                return false;
         }
 
         bool oldEmittingForInit = emittingForInit;
         emittingForInit = false;
         if (!emitTree(initializer))
             return false;
         emittingForInit = oldEmittingForInit;
     } else if (op == JSOP_INITLEXICAL ||
@@ -4516,17 +4483,17 @@ BytecodeEmitter::emitSingleVariable(Pars
             return false;
     } else {
         // The declaration is like `var x;`. Nothing to do.
         return true;
     }
 
     // If we are not initializing, nothing to pop. If we are initializing
     // lets, we must emit the pops.
-    if (emitOption == InitializeVars || emitOption == AnnexB) {
+    if (emitOption == InitializeVars) {
         MOZ_ASSERT_IF(binding->isDefn(), initializer == binding->pn_expr);
         if (!binding->pn_scopecoord.isFree()) {
             if (!emitVarOp(binding, op))
                 return false;
         } else {
             if (!emitIndexOp(op, atomIndex))
                 return false;
         }
@@ -5354,60 +5321,28 @@ BytecodeEmitter::emitLetBlock(ParseNode*
         return false;
 
     if (!leaveNestedScope(&stmtInfo))
         return false;
 
     return true;
 }
 
-bool
-BytecodeEmitter::emitHoistedFunctionsInList(ParseNode* list)
-{
-    MOZ_ASSERT(list->pn_xflags & PNX_FUNCDEFS);
-
-    for (ParseNode* pn = list->pn_head; pn; pn = pn->pn_next) {
-        if (!sc->strict()) {
-            while (pn->isKind(PNK_LABEL))
-                pn = pn->as<LabeledStatement>().statement();
-        }
-
-        if (pn->isKind(PNK_ANNEXB_FUNCTION) ||
-            (pn->isKind(PNK_FUNCTION) && pn->functionIsHoisted()))
-        {
-            if (!emitTree(pn))
-                return false;
-        }
-    }
-
-    return true;
-}
-
 // Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047. See
 // the comment on emitSwitch.
 MOZ_NEVER_INLINE bool
 BytecodeEmitter::emitLexicalScope(ParseNode* pn)
 {
     MOZ_ASSERT(pn->isKind(PNK_LEXICALSCOPE));
 
     StmtInfoBCE stmtInfo(cx);
     if (!enterBlockScope(&stmtInfo, pn->pn_objbox, JSOP_UNINITIALIZED, 0))
         return false;
 
-    ParseNode* body = pn->pn_expr;
-
-    if (body->isKind(PNK_STATEMENTLIST) && body->pn_xflags & PNX_FUNCDEFS) {
-        // This block contains function statements whose definitions are
-        // hoisted to the top of the block. Emit these as a separate pass
-        // before the rest of the block.
-        if (!emitHoistedFunctionsInList(body))
-            return false;
-    }
-
-    if (!emitTree(body))
+    if (!emitTree(pn->pn_expr))
         return false;
 
     if (!leaveNestedScope(&stmtInfo))
         return false;
 
     return true;
 }
 
@@ -6258,51 +6193,29 @@ BytecodeEmitter::emitComprehensionFor(Pa
     return compFor->pn_left->isKind(PNK_FORIN)
            ? emitComprehensionForIn(compFor)
            : emitComprehensionForOf(compFor);
 }
 
 MOZ_NEVER_INLINE bool
 BytecodeEmitter::emitFunction(ParseNode* pn, bool needsProto)
 {
-    ParseNode* assignmentForAnnexB = nullptr;
-    if (pn->isKind(PNK_ANNEXB_FUNCTION)) {
-        assignmentForAnnexB = pn->pn_right;
-        pn = pn->pn_left;
-    }
-
     FunctionBox* funbox = pn->pn_funbox;
     RootedFunction fun(cx, funbox->function());
     MOZ_ASSERT_IF(fun->isInterpretedLazy(), fun->lazyScript());
 
     /*
      * Set the |wasEmitted| flag in the funbox once the function has been
      * emitted. Function definitions that need hoisting to the top of the
      * function will be seen by emitFunction in two places.
      */
     if (funbox->wasEmitted) {
-        // Annex B block-scoped functions are hoisted like any other
-        // block-scoped function to the top of their scope. When their
-        // definitions are seen for the second time, we need to emit the
-        // assignment that assigns the function to the outer 'var' binding.
-        if (assignmentForAnnexB) {
-            if (assignmentForAnnexB->isKind(PNK_VAR)) {
-                if (!emitVariables(assignmentForAnnexB, AnnexB))
-                    return false;
-            } else {
-                MOZ_ASSERT(assignmentForAnnexB->isKind(PNK_ASSIGN));
-                if (!emitTree(assignmentForAnnexB))
-                    return false;
-                if (!emit1(JSOP_POP))
-                    return false;
-            }
-        }
-
         MOZ_ASSERT_IF(fun->hasScript(), fun->nonLazyScript());
         MOZ_ASSERT(pn->functionIsHoisted());
+        MOZ_ASSERT(sc->isFunctionBox());
         return true;
     }
 
     funbox->wasEmitted = true;
 
     /*
      * Mark as singletons any function which will only be executed once, or
      * which is inner to a lambda we only expect to run once. In the latter
@@ -6400,38 +6313,20 @@ BytecodeEmitter::emitFunction(ParseNode*
      *
      * Functions are fully parsed prior to invocation of the emitter and calls
      * to emitTree for function definitions are scheduled before generating
      * the rest of code.
      *
      * For modules, we record the function and instantiate the binding during
      * ModuleDeclarationInstantiation(), before the script is run.
      */
-
-    // Check for functions that were parsed under labeled statements per ES6
-    // Annex B.3.2.
-    bool blockScopedFunction = !atBodyLevel();
-    if (!sc->strict() && blockScopedFunction) {
-        StmtInfoBCE* stmt = innermostStmt();
-        while (stmt && stmt->type == StmtType::LABEL)
-            stmt = stmt->enclosing;
-        blockScopedFunction = !atBodyLevel(stmt);
-    }
-
-    if (blockScopedFunction) {
-        if (!emitIndexOp(JSOP_LAMBDA, index))
-            return false;
-        MOZ_ASSERT(pn->getOp() == JSOP_INITLEXICAL);
-        if (!emitVarOp(pn, pn->getOp()))
-            return false;
-        if (!emit1(JSOP_POP))
-            return false;
-    } else if (sc->isGlobalContext()) {
+    if (sc->isGlobalContext()) {
         MOZ_ASSERT(pn->pn_scopecoord.isFree());
         MOZ_ASSERT(pn->getOp() == JSOP_NOP);
+        MOZ_ASSERT(atBodyLevel());
         switchToPrologue();
         if (!emitIndex32(JSOP_DEFFUN, index))
             return false;
         if (!updateSourceCoordNotes(pn->pn_pos.begin))
             return false;
         switchToMain();
     } else if (sc->isFunctionBox()) {
 #ifdef DEBUG
@@ -8058,16 +7953,17 @@ bool
 BytecodeEmitter::emitArgsBody(ParseNode *pn)
 {
     RootedFunction fun(cx, sc->asFunctionBox()->function());
     ParseNode* pnlast = pn->last();
 
     // Carefully emit everything in the right order:
     // 1. Defaults and Destructuring for each argument
     // 2. Functions
+    ParseNode* pnchild = pnlast->pn_head;
     bool hasDefaults = sc->asFunctionBox()->hasDefaults();
     ParseNode* rest = nullptr;
     bool restIsDefn = false;
     if (fun->hasRest() && hasDefaults) {
         // Defaults with a rest parameter need special handling. The
         // rest parameter needs to be undefined while defaults are being
         // processed. To do this, we create the rest argument and let it
         // sit on the stack while processing defaults. The rest
@@ -8118,21 +8014,31 @@ BytecodeEmitter::emitArgsBody(ParseNode 
             if (!emitVarOp(pn2, JSOP_SETARG))
                 return false;
             if (!emit1(JSOP_POP))
                 return false;
             switchToMain();
         }
     }
     if (pnlast->pn_xflags & PNX_FUNCDEFS) {
-        // This function contains top-level inner function definitions. To
-        // ensure that we emit the bytecode defining them before the rest
-        // of code in the block we use a separate pass over functions.
-        if (!emitHoistedFunctionsInList(pnlast))
-            return false;
+        // This block contains top-level function definitions. To ensure
+        // that we emit the bytecode defining them before the rest of code
+        // in the block we use a separate pass over functions. During the
+        // main pass later the emitter will add JSOP_NOP with source notes
+        // for the function to preserve the original functions position
+        // when decompiling.
+        //
+        // Currently this is used only for functions, as compile-as-we go
+        // mode for scripts does not allow separate emitter passes.
+        for (ParseNode* pn2 = pnchild; pn2; pn2 = pn2->pn_next) {
+            if (pn2->isKind(PNK_FUNCTION) && pn2->functionIsHoisted()) {
+                if (!emitTree(pn2))
+                    return false;
+            }
+        }
     }
     return emitTree(pnlast);
 }
 
 bool
 BytecodeEmitter::emitDefaultsAndDestructuring(ParseNode* pn)
 {
     MOZ_ASSERT(pn->isKind(PNK_ARGSBODY));
@@ -8341,17 +8247,16 @@ BytecodeEmitter::emitTree(ParseNode* pn,
        However, a couple trees require special treatment; see the
        relevant emitter functions for details. */
     if (emitLineNote == EMIT_LINENOTE && pn->getKind() != PNK_WHILE && pn->getKind() != PNK_FOR &&
         !updateLineNumberNotes(pn->pn_pos.begin))
         return false;
 
     switch (pn->getKind()) {
       case PNK_FUNCTION:
-      case PNK_ANNEXB_FUNCTION:
         if (!emitFunction(pn))
             return false;
         break;
 
       case PNK_ARGSBODY:
         if (!emitArgsBody(pn))
             return false;
         break;
--- a/js/src/frontend/BytecodeEmitter.h
+++ b/js/src/frontend/BytecodeEmitter.h
@@ -116,22 +116,17 @@ enum VarEmitOption {
     // used in one case: `for (var $BindingPattern in/of obj)`. If we're at
     // toplevel, the variable(s) must be defined with JSOP_DEFVAR, but they're
     // populated inside the loop, via emitAssignment.
     DefineVars,
 
     // Emit code to evaluate initializer expressions and leave those values on
     // the stack. This is used to implement `for (let/const ...;;)` and
     // deprecated `let` blocks.
-    PushInitialValues,
-
-    // Like InitializeVars, but bind using BINDVAR instead of
-    // BINDNAME/BINDGNAME. Only used for emitting declarations synthesized for
-    // Annex B block-scoped function semantics.
-    AnnexB,
+    PushInitialValues
 };
 
 struct BytecodeEmitter
 {
     SharedContext* const sc;      /* context shared between parsing and bytecode generation */
 
     ExclusiveContext* const cx;
 
@@ -249,20 +244,17 @@ struct BytecodeEmitter
 
     StmtInfoBCE* innermostStmt() const { return stmtStack.innermost(); }
     StmtInfoBCE* innermostScopeStmt() const { return stmtStack.innermostScopeStmt(); }
     JSObject* innermostStaticScope() const;
     JSObject* blockScopeOfDef(Definition* dn) const {
         return parser->blockScopes[dn->pn_blockid];
     }
 
-    bool atBodyLevel(StmtInfoBCE* stmt) const;
-    bool atBodyLevel() const {
-        return atBodyLevel(innermostStmt());
-    }
+    bool atBodyLevel() const;
     uint32_t computeHops(ParseNode* pn, BytecodeEmitter** bceOfDefOut);
     bool isAliasedName(BytecodeEmitter* bceOfDef, ParseNode* pn);
     bool computeDefinitionIsAliased(BytecodeEmitter* bceOfDef, Definition* dn, JSOp* op);
 
     MOZ_ALWAYS_INLINE
     bool makeAtomIndex(JSAtom* atom, jsatomid* indexp) {
         AtomIndexAddPtr p = atomIndices->lookupForAdd(atom);
         if (p) {
@@ -467,18 +459,16 @@ struct BytecodeEmitter
     bool emitInternedObjectOp(uint32_t index, JSOp op);
     bool emitObjectOp(ObjectBox* objbox, JSOp op);
     bool emitObjectPairOp(ObjectBox* objbox1, ObjectBox* objbox2, JSOp op);
     bool emitRegExp(uint32_t index);
 
     MOZ_NEVER_INLINE bool emitFunction(ParseNode* pn, bool needsProto = false);
     MOZ_NEVER_INLINE bool emitObject(ParseNode* pn);
 
-    bool emitHoistedFunctionsInList(ParseNode* pn);
-
     bool emitPropertyList(ParseNode* pn, MutableHandlePlainObject objp, PropListType type);
 
     // To catch accidental misuse, emitUint16Operand/emit3 assert that they are
     // not used to unconditionally emit JSOP_GETLOCAL. Variable access should
     // instead be emitted using EmitVarOp. In special cases, when the caller
     // definitely knows that a given local slot is unaliased, this function may be
     // used as a non-asserting version of emitUint16Operand.
     bool emitLocalOp(JSOp op, uint32_t slot);
--- a/js/src/frontend/FoldConstants.cpp
+++ b/js/src/frontend/FoldConstants.cpp
@@ -95,21 +95,16 @@ ContainsHoistedDeclaration(ExclusiveCont
       // the function statement is evaluated.  Thus any declaration introduced
       // by a function statement, as observed by this function, isn't a hoisted
       // declaration.
       case PNK_FUNCTION:
         MOZ_ASSERT(node->isArity(PN_CODE));
         *result = false;
         return true;
 
-      case PNK_ANNEXB_FUNCTION:
-        MOZ_ASSERT(node->isArity(PN_BINARY));
-        *result = false;
-        return true;
-
       case PNK_MODULE:
         *result = false;
         return true;
 
       // Statements with no sub-components at all.
       case PNK_NOP: // induced by function f() {} function f() {}
       case PNK_DEBUGGER:
         MOZ_ASSERT(node->isArity(PN_NULLARY));
@@ -1783,19 +1778,16 @@ Fold(ExclusiveContext* cx, ParseNode** p
 
       case PNK_AND:
       case PNK_OR:
         return FoldAndOr(cx, pnp, parser, inGenexpLambda);
 
       case PNK_FUNCTION:
         return FoldFunction(cx, pn, parser, inGenexpLambda);
 
-      case PNK_ANNEXB_FUNCTION:
-        return FoldFunction(cx, pn->pn_left, parser, inGenexpLambda);
-
       case PNK_MODULE:
         return FoldModule(cx, pn, parser);
 
       case PNK_SUB:
       case PNK_STAR:
       case PNK_LSH:
       case PNK_RSH:
       case PNK_URSH:
--- a/js/src/frontend/FullParseHandler.h
+++ b/js/src/frontend/FullParseHandler.h
@@ -440,49 +440,33 @@ class FullParseHandler
     ParseNode* newStatementList(unsigned blockid, const TokenPos& pos) {
         ParseNode* pn = new_<ListNode>(PNK_STATEMENTLIST, pos);
         if (pn)
             pn->pn_blockid = blockid;
         return pn;
     }
 
     template <typename PC>
-    bool isFunctionStmt(ParseNode* stmt, PC* pc) {
-        if (!pc->sc->strict()) {
-            while (stmt->isKind(PNK_LABEL))
-                stmt = stmt->as<LabeledStatement>().statement();
-        }
-
-        return stmt->isKind(PNK_FUNCTION) || stmt->isKind(PNK_ANNEXB_FUNCTION);
-    }
-
-    template <typename PC>
     void addStatementToList(ParseNode* list, ParseNode* stmt, PC* pc) {
         MOZ_ASSERT(list->isKind(PNK_STATEMENTLIST));
 
-        list->append(stmt);
-
-        if (isFunctionStmt(stmt, pc)) {
-            // PNX_FUNCDEFS notifies the emitter that the block contains
-            // body-level function definitions that should be processed
-            // before the rest of nodes.
-            list->pn_xflags |= PNX_FUNCDEFS;
+        if (stmt->isKind(PNK_FUNCTION)) {
+            if (pc->atBodyLevel()) {
+                // PNX_FUNCDEFS notifies the emitter that the block contains
+                // body-level function definitions that should be processed
+                // before the rest of nodes.
+                list->pn_xflags |= PNX_FUNCDEFS;
+            } else {
+                // General deoptimization was done in Parser::functionDef.
+                MOZ_ASSERT_IF(pc->sc->isFunctionBox(),
+                              pc->sc->asFunctionBox()->hasExtensibleScope());
+            }
         }
-    }
 
-    template <typename PC>
-    void addCaseStatementToList(ParseNode* list, ParseNode* casepn, PC* pc) {
-        MOZ_ASSERT(list->isKind(PNK_STATEMENTLIST));
-        MOZ_ASSERT(casepn->isKind(PNK_CASE));
-        MOZ_ASSERT(casepn->pn_right->isKind(PNK_STATEMENTLIST));
-
-        list->append(casepn);
-
-        if (casepn->pn_right->pn_xflags & PNX_FUNCDEFS)
-            list->pn_xflags |= PNX_FUNCDEFS;
+        list->append(stmt);
     }
 
     bool prependInitialYield(ParseNode* stmtList, ParseNode* genName) {
         MOZ_ASSERT(stmtList->isKind(PNK_STATEMENTLIST));
 
         TokenPos yieldPos(stmtList->pn_pos.begin, stmtList->pn_pos.begin + 1);
         ParseNode* makeGen = new_<NullaryNode>(PNK_GENERATOR, yieldPos);
         if (!makeGen)
@@ -667,21 +651,16 @@ class FullParseHandler
     }
     void setFunctionBody(ParseNode* pn, ParseNode* kid) {
         pn->pn_body = kid;
     }
     void setFunctionBox(ParseNode* pn, FunctionBox* funbox) {
         MOZ_ASSERT(pn->isKind(PNK_FUNCTION));
         pn->pn_funbox = funbox;
     }
-    ParseNode* newFunctionDefinitionForAnnexB(ParseNode* pn, ParseNode* assignment) {
-        MOZ_ASSERT(pn->isKind(PNK_FUNCTION));
-        MOZ_ASSERT(assignment->isKind(PNK_ASSIGN) || assignment->isKind(PNK_VAR));
-        return new_<BinaryNode>(PNK_ANNEXB_FUNCTION, JSOP_NOP, pos(), pn, assignment);
-    }
     void addFunctionArgument(ParseNode* pn, ParseNode* argpn) {
         pn->pn_body->append(argpn);
     }
     void setDerivedClassConstructor(ParseNode* pn) {
         MOZ_ASSERT(pn->isKind(PNK_FUNCTION));
         pn->pn_funbox->setDerivedClassConstructor();
     }
 
@@ -743,17 +722,17 @@ class FullParseHandler
         return kind == PNK_FUNCTION || kind == PNK_VAR || kind == PNK_BREAK || kind == PNK_THROW ||
                (kind == PNK_SEMI && !node->pn_kid);
     }
 
     bool isSuperBase(ParseNode* node) {
         return node->isKind(PNK_SUPERBASE);
     }
 
-    inline bool finishInitializerAssignment(ParseNode* pn, ParseNode* init);
+    inline bool finishInitializerAssignment(ParseNode* pn, ParseNode* init, JSOp op);
     inline void setLexicalDeclarationOp(ParseNode* pn, JSOp op);
 
     void setBeginPosition(ParseNode* pn, ParseNode* oth) {
         setBeginPosition(pn, oth->pn_pos.begin);
     }
     void setBeginPosition(ParseNode* pn, uint32_t begin) {
         pn->pn_pos.begin = begin;
         MOZ_ASSERT(pn->pn_pos.begin <= pn->pn_pos.end);
@@ -1006,17 +985,17 @@ FullParseHandler::setLastFunctionArgumen
     ParseNode* arg = funcpn->pn_body->last();
     MOZ_ASSERT(arg->isKind(PNK_NAME));
     MOZ_ASSERT(!arg->isUsed());
     MOZ_ASSERT(arg->isDefn());
     arg->pn_expr = destruct;
 }
 
 inline bool
-FullParseHandler::finishInitializerAssignment(ParseNode* pn, ParseNode* init)
+FullParseHandler::finishInitializerAssignment(ParseNode* pn, ParseNode* init, JSOp op)
 {
     if (pn->isUsed()) {
         pn = makeAssignment(pn, init);
         if (!pn)
             return false;
     } else {
         pn->pn_expr = init;
     }
--- a/js/src/frontend/NameFunctions.cpp
+++ b/js/src/frontend/NameFunctions.cpp
@@ -786,22 +786,16 @@ class NameResolver
 
           case PNK_FUNCTION:
           case PNK_MODULE:
             MOZ_ASSERT(cur->isArity(PN_CODE));
             if (!resolve(cur->pn_body, prefix))
                 return false;
             break;
 
-          case PNK_ANNEXB_FUNCTION:
-            MOZ_ASSERT(cur->isArity(PN_BINARY));
-            if (!resolve(cur->pn_left, prefix))
-                return false;
-            break;
-
           // Kinds that should be handled by parent node resolution.
 
           case PNK_IMPORT_SPEC: // by PNK_IMPORT_SPEC_LIST
           case PNK_EXPORT_SPEC: // by PNK_EXPORT_SPEC_LIST
           case PNK_CALLSITEOBJ: // by PNK_TAGGED_TEMPLATE
           case PNK_CLASSNAMES:  // by PNK_CLASS
             MOZ_CRASH("should have been handled by a parent node");
 
--- a/js/src/frontend/ParseNode.cpp
+++ b/js/src/frontend/ParseNode.cpp
@@ -278,18 +278,17 @@ PushNodeChildren(ParseNode* pn, NodeStac
       case PNK_DOWHILE:
       case PNK_WHILE:
       case PNK_SWITCH:
       case PNK_LETBLOCK:
       case PNK_CLASSMETHOD:
       case PNK_NEWTARGET:
       case PNK_SETTHIS:
       case PNK_FOR:
-      case PNK_COMPREHENSIONFOR:
-      case PNK_ANNEXB_FUNCTION: {
+      case PNK_COMPREHENSIONFOR: {
         MOZ_ASSERT(pn->isArity(PN_BINARY));
         stack->push(pn->pn_left);
         stack->push(pn->pn_right);
         return PushResult::Recyclable;
       }
 
       // Default clauses are PNK_CASE but do not have case expressions.
       // Named class expressions do not have outer binding nodes.
--- a/js/src/frontend/ParseNode.h
+++ b/js/src/frontend/ParseNode.h
@@ -160,17 +160,16 @@ class PackedScopeCoordinate
     F(EXPORT_FROM) \
     F(EXPORT_DEFAULT) \
     F(EXPORT_SPEC_LIST) \
     F(EXPORT_SPEC) \
     F(EXPORT_BATCH_SPEC) \
     F(FORIN) \
     F(FOROF) \
     F(FORHEAD) \
-    F(ANNEXB_FUNCTION) \
     F(ARGSBODY) \
     F(SPREAD) \
     F(MUTATEPROTO) \
     F(CLASS) \
     F(CLASSMETHOD) \
     F(CLASSMETHODLIST) \
     F(CLASSNAMES) \
     F(NEWTARGET) \
@@ -267,19 +266,16 @@ IsDeleteKind(ParseNodeKind kind)
  *                            object containing arg and var properties.  We
  *                            create the function object at parse (not emit)
  *                            time to specialize arg and var bytecodes early.
  *                          pn_body: PNK_ARGSBODY, ordinarily;
  *                            PNK_LEXICALSCOPE for implicit function in genexpr
  *                          pn_scopecoord: hops and var index for function
  *                          pn_dflags: PND_* definition/use flags (see below)
  *                          pn_blockid: block id number
- * PNK_ANNEXB_FUNCTION binary pn_left: PNK_FUNCTION
- *                            pn_right: assignment for annex B semantics for
- *                              block-scoped function
  * PNK_ARGSBODY list        list of formal parameters with
  *                              PNK_NAME node with non-empty name for
  *                                SingleNameBinding without Initializer
  *                              PNK_ASSIGN node for SingleNameBinding with
  *                                Initializer
  *                              PNK_NAME node with empty name for destructuring
  *                                pn_expr: PNK_ARRAY, PNK_OBJECT, or PNK_ASSIGN
  *                                  PNK_ARRAY or PNK_OBJECT for BindingPattern
@@ -779,18 +775,17 @@ class ParseNode
 
     bool functionIsHoisted() const {
         MOZ_ASSERT(pn_arity == PN_CODE && getKind() == PNK_FUNCTION);
         MOZ_ASSERT(isOp(JSOP_LAMBDA) ||        // lambda, genexpr
                    isOp(JSOP_LAMBDA_ARROW) ||  // arrow function
                    isOp(JSOP_DEFFUN) ||        // non-body-level function statement
                    isOp(JSOP_NOP) ||           // body-level function stmt in global code
                    isOp(JSOP_GETLOCAL) ||      // body-level function stmt in function code
-                   isOp(JSOP_GETARG) ||        // body-level function redeclaring formal
-                   isOp(JSOP_INITLEXICAL));    // block-level function stmt
+                   isOp(JSOP_GETARG));         // body-level function redeclaring formal
         return !isOp(JSOP_LAMBDA) && !isOp(JSOP_LAMBDA_ARROW) && !isOp(JSOP_DEFFUN);
     }
 
     /*
      * True if this statement node could be a member of a Directive Prologue: an
      * expression statement consisting of a single string literal.
      *
      * This considers only the node and its children, not its context. After
@@ -1607,28 +1602,24 @@ struct Definition : public ParseNode
         CONSTANT,
         LET,
         ARG,
         NAMED_LAMBDA,
         PLACEHOLDER,
         IMPORT
     };
 
-    static bool test(const ParseNode& pn) { return pn.isDefn(); }
-
     bool canHaveInitializer() { return int(kind()) <= int(ARG); }
 
     static const char* kindString(Kind kind);
 
     Kind kind() {
         if (getKind() == PNK_FUNCTION) {
             if (isOp(JSOP_GETARG))
                 return ARG;
-            if (isOp(JSOP_INITLEXICAL))
-                return LET;
             return VAR;
         }
         MOZ_ASSERT(getKind() == PNK_NAME);
         if (isOp(JSOP_CALLEE))
             return NAMED_LAMBDA;
         if (isPlaceholder())
             return PLACEHOLDER;
         if (isOp(JSOP_GETARG))
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -98,17 +98,19 @@ ParseContext<FullParseHandler>::checkLoc
         return false;
     }
     return true;
 }
 
 static void
 MarkUsesAsHoistedLexical(ParseNode* pn)
 {
-    Definition* dn = &pn->as<Definition>();
+    MOZ_ASSERT(pn->isDefn());
+
+    Definition* dn = (Definition*)pn;
     ParseNode** pnup = &dn->dn_uses;
     ParseNode* pnu;
     unsigned start = pn->pn_blockid;
 
     // In ES6, lexical bindings cannot be accessed until initialized.
     // Distinguish hoisted uses as a different JSOp for easier compilation.
     while ((pnu = *pnup) != nullptr && pnu->pn_blockid >= start) {
         MOZ_ASSERT(pnu->isUsed());
@@ -215,18 +217,16 @@ SharedContext::markSuperScopeNeedsHomeOb
 template <>
 bool
 ParseContext<FullParseHandler>::define(TokenStream& ts,
                                        HandlePropertyName name, ParseNode* pn, Definition::Kind kind)
 {
     MOZ_ASSERT(!pn->isUsed());
     MOZ_ASSERT_IF(pn->isDefn(), pn->isPlaceholder());
 
-    pn->setDefn(true);
-
     Definition* prevDef = nullptr;
     if (kind == Definition::LET || kind == Definition::CONSTANT)
         prevDef = decls_.lookupFirst(name);
     else
         MOZ_ASSERT(!decls_.lookupFirst(name));
 
     if (!prevDef)
         prevDef = lexdeps.lookupDefn<FullParseHandler>(name);
@@ -235,17 +235,17 @@ ParseContext<FullParseHandler>::define(T
         ParseNode** pnup = &prevDef->dn_uses;
         ParseNode* pnu;
         unsigned start = (kind == Definition::LET || kind == Definition::CONSTANT)
                          ? pn->pn_blockid : bodyid;
 
         while ((pnu = *pnup) != nullptr && pnu->pn_blockid >= start) {
             MOZ_ASSERT(pnu->pn_blockid >= bodyid);
             MOZ_ASSERT(pnu->isUsed());
-            pnu->pn_lexdef = &pn->as<Definition>();
+            pnu->pn_lexdef = (Definition*) pn;
             pn->pn_dflags |= pnu->pn_dflags & PND_USE2DEF_FLAGS;
             pnup = &pnu->pn_link;
         }
 
         if (!pnu || pnu != prevDef->dn_uses) {
             *pnup = pn->dn_uses;
             pn->dn_uses = prevDef->dn_uses;
             prevDef->dn_uses = pnu;
@@ -253,21 +253,22 @@ ParseContext<FullParseHandler>::define(T
             if (!pnu && prevDef->isPlaceholder())
                 lexdeps->remove(name);
         }
 
         pn->pn_dflags |= prevDef->pn_dflags & PND_CLOSED;
     }
 
     MOZ_ASSERT_IF(kind != Definition::LET && kind != Definition::CONSTANT, !lexdeps->lookup(name));
+    pn->setDefn(true);
     pn->pn_dflags &= ~PND_PLACEHOLDER;
     if (kind == Definition::CONSTANT)
         pn->pn_dflags |= PND_CONST;
 
-    Definition* dn = &pn->as<Definition>();
+    Definition* dn = (Definition*)pn;
     switch (kind) {
       case Definition::ARG:
         MOZ_ASSERT(sc->isFunctionBox());
         dn->setOp((CodeSpec[dn->getOp()].format & JOF_SET) ? JSOP_SETARG : JSOP_GETARG);
         dn->pn_blockid = bodyid;
         dn->pn_dflags |= PND_BOUND;
         if (!dn->pn_scopecoord.setSlot(ts, args_.length()))
             return false;
@@ -387,17 +388,17 @@ ParseContext<ParseHandler>::prepareToAdd
 
 template <typename ParseHandler>
 void
 ParseContext<ParseHandler>::updateDecl(TokenStream& ts, JSAtom* atom, Node pn)
 {
     Definition* oldDecl = decls_.lookupFirst(atom);
 
     pn->setDefn(true);
-    Definition* newDecl = &pn->template as<Definition>();
+    Definition* newDecl = (Definition*)pn;
     decls_.updateFirst(atom, newDecl);
 
     if (sc->isGlobalContext() || oldDecl->isDeoptimized()) {
         MOZ_ASSERT(newDecl->isFreeVar());
         // Global 'var' bindings have no slots, but are still tracked for
         // redeclaration checks.
         for (uint32_t i = 0; i < vars_.length(); i++) {
             if (vars_[i] == oldDecl) {
@@ -1193,16 +1194,28 @@ Parser<FullParseHandler>::standaloneFunc
 
     return fn;
 }
 
 template <>
 bool
 Parser<FullParseHandler>::checkFunctionArguments()
 {
+    /*
+     * Non-top-level functions use JSOP_DEFFUN which is a dynamic scope
+     * operation which means it aliases any bindings with the same name.
+     */
+    if (FuncStmtSet* set = pc->funcStmts) {
+        for (FuncStmtSet::Range r = set->all(); !r.empty(); r.popFront()) {
+            PropertyName* name = r.front()->asPropertyName();
+            if (Definition* dn = pc->decls().lookupFirst(name))
+                dn->pn_dflags |= PND_CLOSED;
+        }
+    }
+
     /* Time to implement the odd semantics of 'arguments'. */
     HandlePropertyName arguments = context->names().arguments;
 
     /*
      * As explained by the ContextFlags::funArgumentsHasLocalBinding comment,
      * create a declaration for 'arguments' if there are any unbound uses in
      * the function body.
      */
@@ -1387,17 +1400,17 @@ Parser<FullParseHandler>::makeDefIntoUse
 {
     /* Turn pn into a definition. */
     pc->updateDecl(tokenStream, atom, pn);
 
     /* Change all uses of dn to be uses of pn. */
     for (ParseNode* pnu = dn->dn_uses; pnu; pnu = pnu->pn_link) {
         MOZ_ASSERT(pnu->isUsed());
         MOZ_ASSERT(!pnu->isDefn());
-        pnu->pn_lexdef = &pn->as<Definition>();
+        pnu->pn_lexdef = (Definition*) pn;
         pn->pn_dflags |= pnu->pn_dflags & PND_USE2DEF_FLAGS;
     }
     pn->pn_dflags |= dn->pn_dflags & PND_USE2DEF_FLAGS;
     pn->dn_uses = dn;
 
     /*
      * A PNK_FUNCTION node must be a definition, so convert shadowed function
      * statements into nops. This is valid since all body-level function
@@ -1430,28 +1443,28 @@ Parser<FullParseHandler>::makeDefIntoUse
      */
     if (dn->canHaveInitializer()) {
         if (ParseNode* rhs = dn->expr()) {
             ParseNode* lhs = handler.makeAssignment(dn, rhs);
             if (!lhs)
                 return false;
             pn->dn_uses = lhs;
             dn->pn_link = nullptr;
-            dn = &lhs->as<Definition>();
+            dn = (Definition*) lhs;
         }
     }
 
     /* Turn dn into a use of pn. */
     MOZ_ASSERT(dn->isKind(PNK_NAME));
     MOZ_ASSERT(dn->isArity(PN_NAME));
     MOZ_ASSERT(dn->pn_atom == atom);
     dn->setOp((CodeSpec[dn->getOp()].format & JOF_SET) ? JSOP_SETNAME : JSOP_GETNAME);
     dn->setDefn(false);
     dn->setUsed(true);
-    dn->pn_lexdef = &pn->as<Definition>();
+    dn->pn_lexdef = (Definition*) pn;
     dn->pn_scopecoord.makeFree();
     dn->pn_dflags &= ~PND_BOUND;
     return true;
 }
 
 /*
  * Helper class for creating bindings.
  *
@@ -1473,32 +1486,28 @@ struct BindData
 
     explicit BindData(ExclusiveContext* cx)
       : kind_(Uninitialized), nameNode_(ParseHandler::null()), letData_(cx)
     {}
 
     void initLexical(VarContext varContext, JSOp op, StaticBlockObject* blockObj,
                      unsigned overflow)
     {
-        init(LexicalBinding, op, op == JSOP_DEFCONST, false);
+        init(LexicalBinding, op, op == JSOP_DEFCONST);
         letData_.varContext = varContext;
         letData_.blockObj = blockObj;
         letData_.overflow = overflow;
     }
 
     void initVar(JSOp op) {
-        init(VarBinding, op, false, false);
-    }
-
-    void initAnnexBVar() {
-        init(VarBinding, JSOP_DEFVAR, false, true);
+        init(VarBinding, op, false);
     }
 
     void initDestructuring(JSOp op) {
-        init(DestructuringBinding, op, false, false);
+        init(DestructuringBinding, op, false);
     }
 
     void setNameNode(typename ParseHandler::Node pn) {
         MOZ_ASSERT(isInitialized());
         nameNode_ = pn;
     }
 
     typename ParseHandler::Node nameNode() {
@@ -1511,21 +1520,16 @@ struct BindData
         return op_;
     }
 
     bool isConst() {
         MOZ_ASSERT(isInitialized());
         return isConst_;
     }
 
-    bool isAnnexB() {
-        MOZ_ASSERT(isInitialized());
-        return isAnnexB_;
-    }
-
     const LetData& letData() {
         MOZ_ASSERT(kind_ == LexicalBinding);
         return letData_;
     }
 
     bool bind(HandlePropertyName name, Parser<ParseHandler>* parser) {
         MOZ_ASSERT(isInitialized());
         MOZ_ASSERT(nameNode_ != ParseHandler::null());
@@ -1552,29 +1556,27 @@ struct BindData
 
     BindingKind kind_;
 
     // Name node for definition processing and error source coordinates.
     typename ParseHandler::Node nameNode_;
 
     JSOp op_;         // Prologue bytecode or nop.
     bool isConst_;    // Whether this is a const binding.
-    bool isAnnexB_;   // Whether this is a synthesized 'var' binding for Annex B.3.
     LetData letData_;
 
     bool isInitialized() {
         return kind_ != Uninitialized;
     }
 
-    void init(BindingKind kind, JSOp op, bool isConst, bool isAnnexB) {
+    void init(BindingKind kind, JSOp op, bool isConst) {
         MOZ_ASSERT(!isInitialized());
         kind_ = kind;
         op_ = op;
         isConst_ = isConst;
-        isAnnexB_ = isAnnexB;
     }
 };
 
 template <typename ParseHandler>
 JSFunction*
 Parser<ParseHandler>::newFunction(HandleAtom atom, FunctionSyntaxKind kind,
                                   GeneratorKind generatorKind, HandleObject proto)
 {
@@ -2230,223 +2232,146 @@ Parser<ParseHandler>::functionArguments(
         return false;
     }
 
     return true;
 }
 
 template <>
 bool
-Parser<FullParseHandler>::bindBodyLevelFunctionName(HandlePropertyName funName,
-                                                    ParseNode** pn_)
-{
-    MOZ_ASSERT(pc->atBodyLevel() || !pc->sc->strict());
-
-    ParseNode*& pn = *pn_;
-
-    /*
-     * Handle redeclaration and optimize cases where we can statically bind the
-     * function (thereby avoiding JSOP_DEFFUN and dynamic name lookup).
-     */
-    if (Definition* dn = pc->decls().lookupFirst(funName)) {
-        MOZ_ASSERT(!dn->isUsed());
-        MOZ_ASSERT(dn->isDefn());
-
-        if (dn->kind() == Definition::CONSTANT || dn->kind() == Definition::LET)
-            return reportRedeclaration(nullptr, Definition::VAR, funName);
-
-        /*
-         * Body-level function statements are effectively variable
-         * declarations where the initialization is hoisted to the
-         * beginning of the block. This means that any other variable
-         * declaration with the same name is really just an assignment to
-         * the function's binding (which is mutable), so turn any existing
-         * declaration into a use.
-         */
-        if (dn->kind() == Definition::ARG) {
-            // The exception to the above comment is when the function
-            // has the same name as an argument. Then the argument node
-            // remains a definition. But change the function node pn so
-            // that it knows where the argument is located.
-            pn->setOp(JSOP_GETARG);
-            pn->setDefn(true);
-            pn->pn_scopecoord = dn->pn_scopecoord;
-            pn->pn_blockid = dn->pn_blockid;
-            pn->pn_dflags |= PND_BOUND;
-            dn->markAsAssigned();
-        } else {
-            if (!makeDefIntoUse(dn, pn, funName))
-                return false;
-        }
-    } else {
-        /*
-         * If this function was used before it was defined, claim the
-         * pre-created definition node for this function that primaryExpr
-         * put in pc->lexdeps on first forward reference, and recycle pn.
-         */
-        if (Definition* fn = pc->lexdeps.lookupDefn<FullParseHandler>(funName)) {
-            MOZ_ASSERT(fn->isDefn());
-            fn->setKind(PNK_FUNCTION);
-            fn->setArity(PN_CODE);
-            fn->pn_pos.begin = pn->pn_pos.begin;
-            fn->pn_pos.end = pn->pn_pos.end;
-
-            fn->pn_body = nullptr;
-            fn->pn_scopecoord.makeFree();
-
-            pc->lexdeps->remove(funName);
-            handler.freeTree(pn);
-            pn = fn;
-        }
-
-        if (!pc->define(tokenStream, funName, pn, Definition::VAR))
-            return false;
-    }
-
-    /* No further binding (in BindNameToSlot) is needed for functions. */
-    pn->pn_dflags |= PND_BOUND;
-
-    MOZ_ASSERT(pn->functionIsHoisted());
-    MOZ_ASSERT(pc->sc->isGlobalContext() == pn->pn_scopecoord.isFree());
-
-    return true;
-}
-
-template <>
-bool
-Parser<FullParseHandler>::bindLexicalFunctionName(HandlePropertyName funName,
-                                                  ParseNode* pn);
-
-template <>
-bool
 Parser<FullParseHandler>::checkFunctionDefinition(HandlePropertyName funName,
                                                   ParseNode** pn_, FunctionSyntaxKind kind,
-                                                  bool* pbodyProcessed,
-                                                  ParseNode** assignmentForAnnexBOut)
+                                                  bool* pbodyProcessed)
 {
     ParseNode*& pn = *pn_;
     *pbodyProcessed = false;
 
+    /* Function statements add a binding to the enclosing scope. */
+    bool bodyLevel = pc->atBodyLevel();
+
     if (kind == Statement) {
-        MOZ_ASSERT(assignmentForAnnexBOut);
-        *assignmentForAnnexBOut = nullptr;
-
-        // In sloppy mode, ES6 Annex B.3.2 allows labelled function
-        // declarations. Otherwise it is a parse error.
-        bool bodyLevelFunction = pc->atBodyLevel();
-        if (!bodyLevelFunction) {
-            StmtInfoPC* stmt = pc->innermostStmt();
-            if (stmt->type == StmtType::LABEL) {
-                if (pc->sc->strict()) {
-                    report(ParseError, false, null(), JSMSG_FUNCTION_LABEL);
-                    return false;
-                }
-
-                stmt = pc->innermostNonLabelStmt();
-                // A switch statement is always braced, so it's okay to label
-                // functions in sloppy mode under switch.
-                if (stmt && stmt->type != StmtType::BLOCK && stmt->type != StmtType::SWITCH) {
-                    report(ParseError, false, null(), JSMSG_SLOPPY_FUNCTION_LABEL);
+        /*
+         * Handle redeclaration and optimize cases where we can statically bind the
+         * function (thereby avoiding JSOP_DEFFUN and dynamic name lookup).
+         */
+        if (Definition* dn = pc->decls().lookupFirst(funName)) {
+            MOZ_ASSERT(!dn->isUsed());
+            MOZ_ASSERT(dn->isDefn());
+
+            bool throwRedeclarationError = dn->kind() == Definition::CONSTANT ||
+                                           dn->kind() == Definition::LET;
+            if (options().extraWarningsOption || throwRedeclarationError) {
+                JSAutoByteString name;
+                ParseReportKind reporter = throwRedeclarationError
+                                           ? ParseError
+                                           : ParseExtraWarning;
+                if (!AtomToPrintableString(context, funName, &name) ||
+                    !report(reporter, false, nullptr, JSMSG_REDECLARED_VAR,
+                            Definition::kindString(dn->kind()), name.ptr()))
+                {
                     return false;
                 }
-
-                bodyLevelFunction = pc->atBodyLevel(stmt);
             }
-        }
-
-        if (bodyLevelFunction) {
-            if (!bindBodyLevelFunctionName(funName, pn_))
-                return false;
-        } else {
-            Definition* annexDef = nullptr;
-            Node synthesizedDeclarationList = null();
-
-            if (!pc->sc->strict()) {
-                // Under non-strict mode, try ES6 Annex B.3.3 semantics. If
-                // making an additional 'var' binding of the same name does
-                // not throw an early error, do so. This 'var' binding would
-                // be assigned the function object when its declaration is
-                // reached, not at the start of the block.
-
-                annexDef = pc->decls().lookupFirst(funName);
-                if (annexDef) {
-                    if (annexDef->kind() == Definition::CONSTANT ||
-                        annexDef->kind() == Definition::LET)
-                    {
-                        // Do not emit Annex B assignment if we would've
-                        // thrown a redeclaration error.
-                        annexDef = nullptr;
-                    }
+
+            /*
+             * Body-level function statements are effectively variable
+             * declarations where the initialization is hoisted to the
+             * beginning of the block. This means that any other variable
+             * declaration with the same name is really just an assignment to
+             * the function's binding (which is mutable), so turn any existing
+             * declaration into a use.
+             */
+            if (bodyLevel) {
+                if (dn->kind() == Definition::ARG) {
+                    // The exception to the above comment is when the function
+                    // has the same name as an argument. Then the argument node
+                    // remains a definition. But change the function node pn so
+                    // that it knows where the argument is located.
+                    pn->setOp(JSOP_GETARG);
+                    pn->setDefn(true);
+                    pn->pn_scopecoord = dn->pn_scopecoord;
+                    pn->pn_blockid = dn->pn_blockid;
+                    pn->pn_dflags |= PND_BOUND;
+                    dn->markAsAssigned();
                 } else {
-                    // Synthesize a new 'var' binding if one does not exist.
-                    ParseNode* varNode = newBindingNode(funName, /* functionScope = */ true);
-                    if (!varNode)
+                    if (!makeDefIntoUse(dn, pn, funName))
                         return false;
-
-                    // Treat the 'var' binding as body level. Otherwise the
-                    // lexical binding of the function name below would result
-                    // in a redeclaration. That is,
-                    // { var x; let x; } is an early error.
-                    // var x; { let x; } is not.
-                    varNode->pn_blockid = pc->bodyid;
-
-                    BindData<FullParseHandler> data(context);
-                    data.initAnnexBVar();
-                    data.setNameNode(varNode);
-                    if (!data.bind(funName, this))
-                        return false;
-
-                    annexDef = &varNode->as<Definition>();
-
-                    synthesizedDeclarationList = handler.newDeclarationList(PNK_VAR, JSOP_DEFVAR);
-                    if (!synthesizedDeclarationList)
-                        return false;
-                    handler.addList(synthesizedDeclarationList, annexDef);
                 }
             }
-
-            if (!bindLexicalFunctionName(funName, pn))
+        } else if (bodyLevel) {
+            /*
+             * If this function was used before it was defined, claim the
+             * pre-created definition node for this function that primaryExpr
+             * put in pc->lexdeps on first forward reference, and recycle pn.
+             */
+            if (Definition* fn = pc->lexdeps.lookupDefn<FullParseHandler>(funName)) {
+                MOZ_ASSERT(fn->isDefn());
+                fn->setKind(PNK_FUNCTION);
+                fn->setArity(PN_CODE);
+                fn->pn_pos.begin = pn->pn_pos.begin;
+                fn->pn_pos.end = pn->pn_pos.end;
+
+                fn->pn_body = nullptr;
+                fn->pn_scopecoord.makeFree();
+
+                pc->lexdeps->remove(funName);
+                handler.freeTree(pn);
+                pn = fn;
+            }
+
+            if (!pc->define(tokenStream, funName, pn, Definition::VAR))
                 return false;
-
-            if (annexDef) {
-                MOZ_ASSERT(!pc->sc->strict());
-
-                // Synthesize an assignment assigning the lexical name to the
-                // 'var' name for Annex B.
-
-                ParseNode* rhs = newName(funName);
-                if (!rhs)
-                    return false;
-                if (!noteNameUse(funName, rhs))
+        }
+
+        if (bodyLevel) {
+            MOZ_ASSERT(pn->functionIsHoisted());
+            MOZ_ASSERT(pc->sc->isGlobalContext() == pn->pn_scopecoord.isFree());
+        } else {
+            /*
+             * As a SpiderMonkey-specific extension, non-body-level function
+             * statements (e.g., functions in an "if" or "while" block) are
+             * dynamically bound when control flow reaches the statement.
+             */
+            MOZ_ASSERT(!pc->sc->strict());
+            MOZ_ASSERT(pn->pn_scopecoord.isFree());
+            if (pc->sc->isFunctionBox()) {
+                FunctionBox* funbox = pc->sc->asFunctionBox();
+                funbox->setMightAliasLocals();
+                funbox->setHasExtensibleScope();
+            }
+            pn->setOp(JSOP_DEFFUN);
+
+            /*
+             * Instead of setting bindingsAccessedDynamically, which would be
+             * overly conservative, remember the names of all function
+             * statements and mark any bindings with the same as aliased at the
+             * end of functionBody.
+             */
+            if (!pc->funcStmts) {
+                pc->funcStmts = alloc.new_<FuncStmtSet>(alloc);
+                if (!pc->funcStmts || !pc->funcStmts->init()) {
+                    ReportOutOfMemory(context);
                     return false;
-
-                // If we synthesized a new definition, emit the declaration to
-                // ensure DEFVAR is correctly emitted in global scripts.
-                // Otherwise, synthesize a simple assignment and emit that.
-                if (synthesizedDeclarationList) {
-                    if (!handler.finishInitializerAssignment(annexDef, rhs))
-                        return false;
-                    *assignmentForAnnexBOut = synthesizedDeclarationList;
-                } else {
-                    ParseNode* lhs = newName(funName);
-                    if (!lhs)
-                        return false;
-                    lhs->setOp(JSOP_SETNAME);
-
-                    // Manually link up the LHS with the non-lexical definition.
-                    handler.linkUseToDef(lhs, annexDef);
-
-                    ParseNode* assign = handler.newAssignment(PNK_ASSIGN, lhs, rhs, pc, JSOP_NOP);
-                    if (!assign)
-                        return false;
-
-                    *assignmentForAnnexBOut = assign;
                 }
             }
-        }
+            if (!pc->funcStmts->put(funName))
+                return false;
+
+            /*
+             * Due to the implicit declaration mechanism, 'arguments' will not
+             * have decls and, even if it did, they will not be noted as closed
+             * in the emitter. Thus, in the corner case of function statements
+             * overridding arguments, flag the whole scope as dynamic.
+             */
+            if (funName == context->names().arguments)
+                pc->sc->setBindingsAccessedDynamically();
+        }
+
+        /* No further binding (in BindNameToSlot) is needed for functions. */
+        pn->pn_dflags |= PND_BOUND;
     } else {
         /* A function expression does not introduce any binding. */
         pn->setOp(kind == Arrow ? JSOP_LAMBDA_ARROW : JSOP_LAMBDA);
     }
 
     // When a lazily-parsed function is called, we only fully parse (and emit)
     // that function, not any of its nested children. The initial syntax-only
     // parse recorded the free variables of nested functions and their extents,
@@ -2545,54 +2470,48 @@ Parser<ParseHandler>::addFreeVariablesFr
     PropagateTransitiveParseFlags(lazy, pc->sc);
     return true;
 }
 
 template <>
 bool
 Parser<SyntaxParseHandler>::checkFunctionDefinition(HandlePropertyName funName,
                                                     Node* pn, FunctionSyntaxKind kind,
-                                                    bool* pbodyProcessed,
-                                                    Node* assignmentForAnnexBOut)
+                                                    bool* pbodyProcessed)
 {
     *pbodyProcessed = false;
 
     /* Function statements add a binding to the enclosing scope. */
     bool bodyLevel = pc->atBodyLevel();
 
     if (kind == Statement) {
-        *assignmentForAnnexBOut = null();
-
-        if (!bodyLevel) {
-            // Block-scoped functions cannot yet be parsed lazily.
-            return abortIfSyntaxParser();
-        }
-
         /*
          * Handle redeclaration and optimize cases where we can statically bind the
          * function (thereby avoiding JSOP_DEFFUN and dynamic name lookup).
          */
-
         if (DefinitionNode dn = pc->decls().lookupFirst(funName)) {
             if (dn == Definition::CONSTANT || dn == Definition::LET) {
                 JSAutoByteString name;
                 if (!AtomToPrintableString(context, funName, &name) ||
                     !report(ParseError, false, null(), JSMSG_REDECLARED_VAR,
                             Definition::kindString(dn), name.ptr()))
                 {
                     return false;
                 }
             }
-        } else {
+        } else if (bodyLevel) {
             if (pc->lexdeps.lookupDefn<SyntaxParseHandler>(funName))
                 pc->lexdeps->remove(funName);
 
             if (!pc->define(tokenStream, funName, *pn, Definition::VAR))
                 return false;
         }
+
+        if (!bodyLevel && funName == context->names().arguments)
+            pc->sc->setBindingsAccessedDynamically();
     }
 
     if (kind == Arrow) {
         /* Arrow functions cannot yet be parsed lazily. */
         return abortIfSyntaxParser();
     }
 
     return true;
@@ -2663,32 +2582,30 @@ Parser<ParseHandler>::templateLiteral(Yi
     } while (tt == TOK_TEMPLATE_HEAD);
     return nodeList;
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
 Parser<ParseHandler>::functionDef(InHandling inHandling, YieldHandling yieldHandling,
                                   HandlePropertyName funName, FunctionSyntaxKind kind,
-                                  GeneratorKind generatorKind, InvokedPrediction invoked,
-                                  Node* assignmentForAnnexBOut)
+                                  GeneratorKind generatorKind, InvokedPrediction invoked)
 {
     MOZ_ASSERT_IF(kind == Statement, funName);
 
     /* Make a TOK_FUNCTION node. */
     Node pn = handler.newFunctionDefinition();
     if (!pn)
         return null();
-    handler.setBlockId(pn, pc->blockid());
 
     if (invoked)
         pn = handler.setLikelyIIFE(pn);
 
     bool bodyProcessed;
-    if (!checkFunctionDefinition(funName, &pn, kind, &bodyProcessed, assignmentForAnnexBOut))
+    if (!checkFunctionDefinition(funName, &pn, kind, &bodyProcessed))
         return null();
 
     if (bodyProcessed)
         return pn;
 
     RootedObject proto(context);
     if (generatorKind == StarGenerator) {
         // If we are off the main thread, the generator meta-objects have
@@ -2865,16 +2782,17 @@ Parser<FullParseHandler>::functionArgsAn
 
             // Update the end position of the parse node.
             pn->pn_pos.end = tokenStream.currentToken().pos.end;
         }
 
         if (!addFreeVariablesFromLazyFunction(fun, pc))
             return false;
 
+        pn->pn_blockid = outerpc->blockid();
         PropagateTransitiveParseFlags(funbox, outerpc->sc);
         return true;
     } while (false);
 
     blockScopes.resize(oldBlockScopesLength);
 
     // Continue doing a full parse for this inner function.
     ParseContext<FullParseHandler> funpc(this, pc, pn, funbox, newDirectives);
@@ -2882,16 +2800,18 @@ Parser<FullParseHandler>::functionArgsAn
         return false;
 
     if (!functionArgsAndBodyGeneric(inHandling, yieldHandling, pn, fun, kind))
         return false;
 
     if (!leaveFunction(pn, outerpc, kind))
         return false;
 
+    pn->pn_blockid = outerpc->blockid();
+
     /*
      * Fruit of the poisonous tree: if a closure contains a dynamic name access
      * (eval, with, etc), we consider the parent to do the same. The reason is
      * that the deoptimizing effects of dynamic name access apply equally to
      * parents: any local can be read at runtime.
      */
     PropagateTransitiveParseFlags(funbox, outerpc->sc);
     return true;
@@ -3123,34 +3043,16 @@ Parser<ParseHandler>::checkYieldNameVali
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
 Parser<ParseHandler>::functionStmt(YieldHandling yieldHandling, DefaultHandling defaultHandling)
 {
     MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FUNCTION));
 
-    // ES6 Annex B.3.4 says we can parse function declarations unbraced under if or
-    // else as if it were braced. That is, |if (x) function f() {}| is parsed as
-    // |if (x) { function f() {} }|.
-    Maybe<AutoPushStmtInfoPC> synthesizedStmtInfoForAnnexB;
-    Node synthesizedBlockForAnnexB = null();
-    StmtInfoPC *stmt = pc->innermostStmt();
-    if (!pc->sc->strict() && stmt) {
-        if (stmt->type == StmtType::IF || stmt->type == StmtType::ELSE) {
-            if (!abortIfSyntaxParser())
-                return null();
-
-            synthesizedStmtInfoForAnnexB.emplace(*this, StmtType::BLOCK);
-            synthesizedBlockForAnnexB = pushLexicalScope(*synthesizedStmtInfoForAnnexB);
-            if (!synthesizedBlockForAnnexB)
-                return null();
-        }
-    }
-
     RootedPropertyName name(context);
     GeneratorKind generatorKind = NotGenerator;
     TokenKind tt;
     if (!tokenStream.getToken(&tt))
         return null();
 
     if (tt == TOK_MUL) {
         generatorKind = StarGenerator;
@@ -3168,45 +3070,22 @@ Parser<ParseHandler>::functionStmt(Yield
         name = context->names().starDefaultStar;
         tokenStream.ungetToken();
     } else {
         /* Unnamed function expressions are forbidden in statement context. */
         report(ParseError, false, null(), JSMSG_UNNAMED_FUNCTION_STMT);
         return null();
     }
 
-    Node assignmentForAnnexB;
-    Node fun = functionDef(InAllowed, yieldHandling, name, Statement, generatorKind,
-                           PredictUninvoked, &assignmentForAnnexB);
-    if (!fun)
-        return null();
-
-    if (assignmentForAnnexB) {
-        fun = handler.newFunctionDefinitionForAnnexB(fun, assignmentForAnnexB);
-        if (!fun)
-            return null();
-    }
-
-    // Note that we may have synthesized a block for Annex B.3.4 without
-    // having synthesized an assignment for Annex B.3.3, e.g.,
-    //
-    //   let f = 1;
-    //   {
-    //     if (1) function f() {}
-    //   }
-    if (synthesizedBlockForAnnexB) {
-        Node body = handler.newStatementList(pc->blockid(), handler.getPosition(fun));
-        if (!body)
-            return null();
-        handler.addStatementToList(body, fun, pc);
-        handler.setLexicalScopeBody(synthesizedBlockForAnnexB, body);
-        return synthesizedBlockForAnnexB;
-    }
-
-    return fun;
+    /* We forbid function statements in strict mode code. */
+    if (!pc->atBodyLevel() && pc->sc->needStrictChecks() &&
+        !report(ParseStrictError, pc->sc->strict(), null(), JSMSG_STRICT_FUNCTION_STATEMENT))
+        return null();
+
+    return functionDef(InAllowed, yieldHandling, name, Statement, generatorKind);
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
 Parser<ParseHandler>::functionExpr(InvokedPrediction invoked)
 {
     MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FUNCTION));
 
@@ -3800,34 +3679,29 @@ Parser<ParseHandler>::bindVar(BindData<P
     parser->handler.setOp(pn, JSOP_GETNAME);
 
     if (!parser->checkStrictBinding(name, pn))
         return false;
 
     StmtInfoPC* stmt = LexicalLookup(pc, name);
 
     if (stmt && stmt->type == StmtType::WITH) {
-        // Do not deoptimize if we are binding a synthesized 'var' binding for
-        // Annex B.3.3, which states that the synthesized binding is to go on
-        // the nearest VariableEnvironment. Deoptimizing here would
-        // erroneously emit NAME ops when assigning to the Annex B 'var'.
-        if (!data->isAnnexB()) {
-            parser->handler.setFlag(pn, PND_DEOPTIMIZED);
-            if (pc->sc->isFunctionBox()) {
-                FunctionBox* funbox = pc->sc->asFunctionBox();
-                funbox->setMightAliasLocals();
-            }
-
-            // Make sure to indicate the need to deoptimize the script's
-            // arguments object. Mark the function as if it contained a
-            // debugger statement, which will deoptimize arguments as much as
-            // possible.
-            if (name == cx->names().arguments)
-                pc->sc->setHasDebuggerStatement();
-        }
+        parser->handler.setFlag(pn, PND_DEOPTIMIZED);
+        if (pc->sc->isFunctionBox()) {
+            FunctionBox* funbox = pc->sc->asFunctionBox();
+            funbox->setMightAliasLocals();
+        }
+
+        /*
+         * Make sure to indicate the need to deoptimize the script's arguments
+         * object. Mark the function as if it contained a debugger statement,
+         * which will deoptimize arguments as much as possible.
+         */
+        if (name == cx->names().arguments)
+            pc->sc->setHasDebuggerStatement();
 
         // Find the nearest enclosing non-with scope that defined name, if
         // any, for redeclaration checks below.
         while (stmt && stmt->type == StmtType::WITH) {
             if (stmt->enclosingScope)
                 stmt = LexicalLookup(pc, name, stmt->enclosingScope);
             else
                 stmt = nullptr;
@@ -3952,37 +3826,33 @@ Parser<ParseHandler>::noteNameUse(Handle
         }
     }
 
     return true;
 }
 
 template <>
 bool
-Parser<FullParseHandler>::bindUninitialized(BindData<FullParseHandler>* data, HandlePropertyName name,
-                                            ParseNode* pn)
-{
+Parser<FullParseHandler>::bindUninitialized(BindData<FullParseHandler>* data, ParseNode* pn)
+{
+    MOZ_ASSERT(pn->isKind(PNK_NAME));
+
+    RootedPropertyName name(context, pn->pn_atom->asPropertyName());
+
     data->setNameNode(pn);
-    return data->bind(name, this);
+    if (!data->bind(name, this))
+        return false;
+    return true;
 }
 
 template <>
 bool
-Parser<FullParseHandler>::bindUninitialized(BindData<FullParseHandler>* data, ParseNode* pn)
-{
-    RootedPropertyName name(context, pn->name());
-    return bindUninitialized(data, name, pn);
-}
-
-template <>
-bool
-Parser<FullParseHandler>::bindInitialized(BindData<FullParseHandler>* data, HandlePropertyName name,
-                                          ParseNode* pn)
-{
-    if (!bindUninitialized(data, name, pn))
+Parser<FullParseHandler>::bindInitialized(BindData<FullParseHandler>* data, ParseNode* pn)
+{
+    if (!bindUninitialized(data, pn))
         return false;
 
     /*
      * Select the appropriate name-setting opcode, respecting eager selection
      * done by the data->bind function.
      */
     if (data->op() == JSOP_DEFLET || data->op() == JSOP_DEFCONST)
         pn->setOp(pn->pn_scopecoord.isFree() ? JSOP_INITGLEXICAL : JSOP_INITLEXICAL);
@@ -3995,24 +3865,16 @@ Parser<FullParseHandler>::bindInitialize
         pn->pn_dflags |= PND_CONST;
 
     pn->markAsAssigned();
     return true;
 }
 
 template <>
 bool
-Parser<FullParseHandler>::bindInitialized(BindData<FullParseHandler>* data, ParseNode* pn)
-{
-    RootedPropertyName name(context, pn->name());
-    return bindInitialized(data, name, pn);
-}
-
-template <>
-bool
 Parser<FullParseHandler>::checkDestructuringName(BindData<FullParseHandler>* data, ParseNode* expr)
 {
     MOZ_ASSERT(!handler.isUnparenthesizedDestructuringPattern(expr));
 
     // Parentheses are forbidden around destructuring *patterns* (but allowed
     // around names).  Use our nicer error message for parenthesized, nested
     // patterns.
     if (handler.isParenthesizedDestructuringPattern(expr)) {
@@ -4549,17 +4411,17 @@ Parser<ParseHandler>::variables(YieldHan
                         }
                     }
                 }
 
                 if (performAssignment) {
                     if (!bindBeforeInitializer && !data.bind(name, this))
                         return null();
 
-                    if (!handler.finishInitializerAssignment(pn2, init))
+                    if (!handler.finishInitializerAssignment(pn2, init, data.op()))
                         return null();
                 }
             }
 
             handler.setLexicalDeclarationOp(pn2, data.op());
             handler.setEndPosition(pn, pn2);
         } while (false);
 
@@ -4570,66 +4432,49 @@ Parser<ParseHandler>::variables(YieldHan
             break;
     }
 
     return pn;
 }
 
 template <>
 bool
-Parser<FullParseHandler>::checkAndPrepareLexical(PrepareLexicalKind prepareWhat,
-                                                 const TokenPos& errorPos)
+Parser<FullParseHandler>::checkAndPrepareLexical(bool isConst, const TokenPos& errorPos)
 {
     /*
-     * This is a lexical declaration. We must be directly under a block for
-     * 'let' and 'const' declarations. If we pass this error test, make the
-     * enclosing StmtInfoPC be our scope. Further let declarations in this
-     * block will find this scope statement and use the same block object.
-     *
-     * Function declarations behave like 'let', except that they are allowed
-     * per ES6 Annex B.3.2 to be labeled, unlike plain 'let' and 'const'
-     * declarations.
+     * This is a lexical declaration. We must be directly under a block per the
+     * proposed ES4 specs, but not an implicit block created due to
+     * 'for (let ...)'. If we pass this error test, make the enclosing
+     * StmtInfoPC be our scope. Further let declarations in this block will
+     * find this scope statement and use the same block object.
      *
      * If we are the first let declaration in this block (i.e., when the
      * enclosing maybe-scope StmtInfoPC isn't yet a scope statement) then
      * we also need to set pc->blockNode to be our PNK_LEXICALSCOPE.
      */
-
-    // ES6 Annex B.3.2 does not apply in strict mode, and labeled functions in
-    // strict mode should have been rejected by checkFunctionDefinition.
-    MOZ_ASSERT_IF(pc->innermostStmt() &&
-                  pc->innermostStmt()->type == StmtType::LABEL &&
-                  prepareWhat == PrepareFunction,
-                  !pc->sc->strict());
-
-    StmtInfoPC* stmt = prepareWhat == PrepareFunction
-                       ? pc->innermostNonLabelStmt()
-                       : pc->innermostStmt();
+    StmtInfoPC* stmt = pc->innermostStmt();
     if (stmt && (!stmt->maybeScope() || stmt->isForLetBlock)) {
-        reportWithOffset(ParseError, false, errorPos.begin,
-                         stmt->type == StmtType::LABEL
-                         ? JSMSG_LEXICAL_DECL_LABEL
-                         : JSMSG_LEXICAL_DECL_NOT_IN_BLOCK,
-                         prepareWhat == PrepareConst ? "const" : "lexical");
+        reportWithOffset(ParseError, false, errorPos.begin, JSMSG_LEXICAL_DECL_NOT_IN_BLOCK,
+                         isConst ? "const" : "lexical");
         return false;
     }
 
     if (!stmt) {
-        MOZ_ASSERT_IF(prepareWhat != PrepareFunction, pc->atBodyLevel());
+        MOZ_ASSERT(pc->atBodyLevel());
 
         /*
          * Self-hosted code must be usable against *any* global object,
          * including ones with other let variables -- variables possibly
          * placed in conflicting slots.  Forbid top-level let declarations to
          * prevent such conflicts from ever occurring.
          */
         bool isGlobal = !pc->sc->isFunctionBox() && stmt == pc->innermostScopeStmt();
         if (options().selfHostingMode && isGlobal) {
             report(ParseError, false, null(), JSMSG_SELFHOSTED_TOP_LEVEL_LEXICAL,
-                   prepareWhat == PrepareConst ? "'const'" : "'let'");
+                   isConst ? "'const'" : "'let'");
             return false;
         }
         return true;
     }
 
     if (stmt->isBlockScope) {
         // Nothing to do, the top statement already has a block scope.
         MOZ_ASSERT(pc->innermostScopeStmt() == stmt);
@@ -4645,22 +4490,18 @@ Parser<FullParseHandler>::checkAndPrepar
             return false;
 
         /*
          * 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->canBeBlockScope() && stmt->type != StmtType::CATCH);
-        if (prepareWhat == PrepareFunction) {
-            stmt->isBlockScope = true;
-            pc->stmtStack.linkAsInnermostScopeStmt(stmt, *blockObj);
-        } else {
-            pc->stmtStack.makeInnermostLexicalScope(*blockObj);
-        }
+
+        pc->stmtStack.makeInnermostLexicalScope(*blockObj);
         MOZ_ASSERT(!blockScopes[stmt->blockid]);
         blockScopes[stmt->blockid].set(blockObj);
 
 #ifdef DEBUG
         ParseNode* tmp = pc->blockNode;
         MOZ_ASSERT(!tmp || !tmp->isKind(PNK_LEXICALSCOPE));
 #endif
 
@@ -4680,64 +4521,43 @@ CurrentLexicalStaticBlock(ParseContext<F
         return &pc->innermostStaticScope()->as<StaticBlockObject>();
     MOZ_ASSERT(pc->atBodyLevel() &&
                (!pc->sc->isGlobalContext() ||
                 HasNonSyntacticStaticScopeChain(pc->innermostStaticScope())));
     return nullptr;
 }
 
 template <>
-bool
-Parser<FullParseHandler>::prepareAndBindInitializedLexicalWithNode(HandlePropertyName name,
-                                                                   PrepareLexicalKind prepareWhat,
-                                                                   ParseNode* pn,
-                                                                   const TokenPos& pos)
+ParseNode*
+Parser<FullParseHandler>::makeInitializedLexicalBinding(HandlePropertyName name, bool isConst,
+                                                        const TokenPos& pos)
 {
     BindData<FullParseHandler> data(context);
-    if (!checkAndPrepareLexical(prepareWhat, pos))
-        return false;
-    data.initLexical(HoistVars, prepareWhat == PrepareConst ? JSOP_DEFCONST : JSOP_DEFLET,
+    if (!checkAndPrepareLexical(isConst, pos))
+        return null();
+    data.initLexical(HoistVars, isConst ? JSOP_DEFCONST : JSOP_DEFLET,
                      CurrentLexicalStaticBlock(pc), JSMSG_TOO_MANY_LOCALS);
-    return bindInitialized(&data, name, pn);
-}
-
-template <>
-ParseNode*
-Parser<FullParseHandler>::makeInitializedLexicalBinding(HandlePropertyName name,
-                                                        PrepareLexicalKind prepareWhat,
-                                                        const TokenPos& pos)
-{
     ParseNode* dn = newBindingNode(name, false);
     if (!dn)
         return null();
     handler.setPosition(dn, pos);
 
-    if (!prepareAndBindInitializedLexicalWithNode(name, prepareWhat, dn, pos))
+    if (!bindInitialized(&data, dn))
         return null();
 
     return dn;
 }
 
 template <>
-bool
-Parser<FullParseHandler>::bindLexicalFunctionName(HandlePropertyName funName,
-                                                  ParseNode* pn)
-{
-    MOZ_ASSERT(!pc->atBodyLevel());
-    pn->pn_blockid = pc->blockid();
-    return prepareAndBindInitializedLexicalWithNode(funName, PrepareFunction, pn, pos());
-}
-
-template <>
 ParseNode*
 Parser<FullParseHandler>::lexicalDeclaration(YieldHandling yieldHandling, bool isConst)
 {
     handler.disableSyntaxParser();
 
-    if (!checkAndPrepareLexical(isConst ? PrepareConst : PrepareLet, pos()))
+    if (!checkAndPrepareLexical(isConst, pos()))
         return null();
 
     /*
      * Parse body-level lets without a new block object. ES6 specs
      * that an execution environment's initial lexical environment
      * is the VariableEnvironment, i.e., body-level lets are in
      * the same environment record as vars.
      *
@@ -5239,17 +5059,17 @@ Parser<FullParseHandler>::exportDeclarat
           case TOK_CLASS:
             kid = classDefinition(YieldIsKeyword, ClassStatement, AllowDefaultName);
             if (!kid)
                 return null();
             break;
           default:
             tokenStream.ungetToken();
             RootedPropertyName name(context, context->names().starDefaultStar);
-            binding = makeInitializedLexicalBinding(name, PrepareConst, pos());
+            binding = makeInitializedLexicalBinding(name, true, pos());
             if (!binding)
                 return null();
             kid = assignExpr(InAllowed, YieldIsKeyword, TripledotProhibited);
             if (!kid)
                 return null();
             if (!MatchOrInsertSemicolonAfterExpression(tokenStream))
                 return null();
             break;
@@ -5986,17 +5806,17 @@ Parser<ParseHandler>::switchStatement(Yi
                             return null();
                         }
                         warnedAboutStatementsAfterReturn = true;
                     }
                 } else if (handler.isReturnStatement(stmt)) {
                     afterReturn = true;
                 }
             }
-            handler.addStatementToList(body, stmt, pc);
+            handler.addList(body, stmt);
         }
 
         // In ES6, lexical bindings cannot be accessed until initialized. If
         // there was a 'let' declaration in the case we just parsed, remember
         // the slot starting at which new lexical bindings will be
         // assigned. Since lexical bindings from previous cases will not
         // dominate uses in the current case, any such uses will require a
         // dead zone check.
@@ -6005,17 +5825,17 @@ Parser<ParseHandler>::switchStatement(Yi
         // declaring lexical bindings within switch cases without introducing
         // a new block is poor form and should be avoided.
         if (stmtInfo->isBlockScope)
             stmtInfo->firstDominatingLexicalInCase = stmtInfo->staticBlock().numVariables();
 
         Node casepn = handler.newCaseOrDefault(caseBegin, caseExpr, body);
         if (!casepn)
             return null();
-        handler.addCaseStatementToList(caseList, casepn, pc);
+        handler.addList(caseList, casepn);
     }
 
     /*
      * Handle the case where there was a let declaration in any case in
      * the switch body, but not within an inner block.  If it replaced
      * pc->blockNode with a new block node then we must refresh caseList and
      * then restore pc->blockNode.
      */
@@ -6832,28 +6652,28 @@ Parser<FullParseHandler>::classDefinitio
         JSOp op = JSOpFromPropertyType(propType);
         if (!handler.addClassMethodDefinition(classMethods, propName, fn, op, isStatic))
             return null();
     }
 
     ParseNode* nameNode = null();
     ParseNode* methodsOrBlock = classMethods;
     if (name) {
-        ParseNode* innerBinding = makeInitializedLexicalBinding(name, PrepareConst, namePos);
+        ParseNode* innerBinding = makeInitializedLexicalBinding(name, true, namePos);
         if (!innerBinding)
             return null();
 
         MOZ_ASSERT(classBlock);
         handler.setLexicalScopeBody(classBlock, classMethods);
         methodsOrBlock = classBlock;
         classStmt.reset();
 
         ParseNode* outerBinding = null();
         if (classContext == ClassStatement) {
-            outerBinding = makeInitializedLexicalBinding(name, PrepareLet, namePos);
+            outerBinding = makeInitializedLexicalBinding(name, false, namePos);
             if (!outerBinding)
                 return null();
         }
 
         nameNode = handler.newClassNames(outerBinding, innerBinding, namePos);
         if (!nameNode)
             return null();
     }
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -48,16 +48,17 @@ struct StmtInfoPC : public StmtInfoBase
     explicit StmtInfoPC(ExclusiveContext* cx)
       : StmtInfoBase(cx),
         blockid(BlockIdLimit),
         innerBlockScopeDepth(0),
         firstDominatingLexicalInCase(0)
     {}
 };
 
+typedef HashSet<JSAtom*, DefaultHasher<JSAtom*>, LifoAllocPolicy<Fallible>> FuncStmtSet;
 class SharedContext;
 
 typedef Vector<Definition*, 16> DeclVector;
 
 struct GenericParseContext
 {
     // Enclosing function or global context.
     GenericParseContext* parent;
@@ -230,16 +231,20 @@ struct MOZ_STACK_CLASS ParseContext : pu
     // Value for parserPC to restore at the end. Use 'parent' instead for
     // information about the parse chain, this may be nullptr if
     // parent != nullptr.
     ParseContext<ParseHandler>* oldpc;
 
   public:
     OwnedAtomDefnMapPtr lexdeps;    /* unresolved lexical name dependencies */
 
+    FuncStmtSet*    funcStmts;     /* Set of (non-top-level) function statements
+                                       that will alias any top-level bindings with
+                                       the same name. */
+
     // All inner functions in this context. Only filled in when parsing syntax.
     Rooted<TraceableVector<JSFunction*>> innerFunctions;
 
     // In a function context, points to a Directive struct that can be updated
     // to reflect new directives encountered in the Directive Prologue that
     // require reparsing the function. In global/module/generator-tail contexts,
     // we don't need to reparse when encountering a DirectivePrologue so this
     // pointer may be nullptr.
@@ -267,16 +272,17 @@ struct MOZ_STACK_CLASS ParseContext : pu
         blockNode(ParseHandler::null()),
         decls_(prs->context, prs->alloc),
         args_(prs->context),
         vars_(prs->context),
         bodyLevelLexicals_(prs->context),
         parserPC(&prs->pc),
         oldpc(prs->pc),
         lexdeps(prs->context),
+        funcStmts(nullptr),
         innerFunctions(prs->context, TraceableVector<JSFunction*>(prs->context)),
         newDirectives(newDirectives),
         inDeclDestructuring(false)
     {
         prs->pc = this;
         if (sc->isFunctionBox())
             parseUsingFunctionBox.emplace(prs->context, sc->asFunctionBox());
     }
@@ -284,47 +290,42 @@ struct MOZ_STACK_CLASS ParseContext : pu
     ~ParseContext();
 
     bool init(Parser<ParseHandler>& parser);
 
     unsigned blockid() { return stmtStack.innermost() ? stmtStack.innermost()->blockid : bodyid; }
 
     StmtInfoPC* innermostStmt() const { return stmtStack.innermost(); }
     StmtInfoPC* innermostScopeStmt() const { return stmtStack.innermostScopeStmt(); }
-    StmtInfoPC* innermostNonLabelStmt() const { return stmtStack.innermostNonLabel(); }
     JSObject* innermostStaticScope() const {
         if (StmtInfoPC* stmt = innermostScopeStmt())
             return stmt->staticScope;
         return sc->staticScope();
     }
 
     // True if we are at the topmost level of a entire script or function body.
     // For example, while parsing this code we would encounter f1 and f2 at
     // body level, but we would not encounter f3 or f4 at body level:
     //
     //   function f1() { function f2() { } }
     //   if (cond) { function f3() { if (cond) { function f4() { } } } }
     //
-    bool atBodyLevel(StmtInfoPC* stmt) {
+    bool atBodyLevel() {
         // 'eval' and non-syntactic scripts are always under an invisible
         // lexical scope, but since it is not syntactic, it should still be
         // considered at body level.
         if (sc->staticScope()->is<StaticEvalObject>()) {
-            bool bl = !stmt->enclosing;
-            MOZ_ASSERT_IF(bl, stmt->type == StmtType::BLOCK);
-            MOZ_ASSERT_IF(bl, stmt->staticScope
-                                  ->template as<StaticBlockObject>()
-                                  .enclosingStaticScope() == sc->staticScope());
+            bool bl = !innermostStmt()->enclosing;
+            MOZ_ASSERT_IF(bl, innermostStmt()->type == StmtType::BLOCK);
+            MOZ_ASSERT_IF(bl, innermostStmt()->staticScope
+                                             ->template as<StaticBlockObject>()
+                                             .enclosingStaticScope() == sc->staticScope());
             return bl;
         }
-        return !stmt;
-    }
-
-    bool atBodyLevel() {
-        return atBodyLevel(innermostStmt());
+        return !innermostStmt();
     }
 
     bool atGlobalLevel() {
         return atBodyLevel() && sc->isGlobalContext() && !innermostScopeStmt();
     }
 
     // True if we are at the topmost level of a module only.
     bool atModuleLevel() {
@@ -722,18 +723,17 @@ class Parser : private JS::AutoGCRooter,
     /*
      * Additional JS parsers.
      */
     bool functionArguments(YieldHandling yieldHandling, FunctionSyntaxKind kind,
                            Node funcpn, bool* hasRest);
 
     Node functionDef(InHandling inHandling, YieldHandling uieldHandling, HandlePropertyName name,
                      FunctionSyntaxKind kind, GeneratorKind generatorKind,
-                     InvokedPrediction invoked = PredictUninvoked,
-                     Node* assignmentForAnnexBOut = nullptr);
+                     InvokedPrediction invoked = PredictUninvoked);
     bool functionArgsAndBody(InHandling inHandling, Node pn, HandleFunction fun,
                              FunctionSyntaxKind kind, GeneratorKind generatorKind,
                              Directives inheritedDirectives, Directives* newDirectives);
 
     Node unaryOpExpr(YieldHandling yieldHandling, ParseNodeKind kind, JSOp op, uint32_t begin);
 
     Node condition(InHandling inHandling, YieldHandling yieldHandling);
 
@@ -789,20 +789,18 @@ class Parser : private JS::AutoGCRooter,
     bool matchInOrOf(bool* isForInp, bool* isForOfp);
 
     bool checkFunctionArguments();
 
     bool defineFunctionThis();
     Node newThisName();
 
     bool makeDefIntoUse(Definition* dn, Node pn, HandleAtom atom);
-    bool bindLexicalFunctionName(HandlePropertyName funName, ParseNode* pn);
-    bool bindBodyLevelFunctionName(HandlePropertyName funName, ParseNode** pn);
     bool checkFunctionDefinition(HandlePropertyName funName, Node* pn, FunctionSyntaxKind kind,
-                                 bool* pbodyProcessed, Node* assignmentForAnnexBOut);
+                                 bool* pbodyProcessed);
     bool finishFunctionDefinition(Node pn, FunctionBox* funbox, Node body);
     bool addFreeVariablesFromLazyFunction(JSFunction* fun, ParseContext<ParseHandler>* pc);
 
     bool isValidForStatementLHS(Node pn1, JSVersion version, bool forDecl, bool forEach,
                                 ParseNodeKind headKind);
     bool checkForHeadConstInitializers(Node pn1);
 
     // Use when the current token is TOK_NAME and is known to be 'let'.
@@ -841,44 +839,33 @@ class Parser : private JS::AutoGCRooter,
     Node propertyName(YieldHandling yieldHandling, Node propList,
                       PropertyType* propType, MutableHandleAtom propAtom);
     Node computedPropertyName(YieldHandling yieldHandling, Node literal);
     Node arrayInitializer(YieldHandling yieldHandling);
     Node newRegExp();
 
     Node objectLiteral(YieldHandling yieldHandling);
 
-    enum PrepareLexicalKind {
-        PrepareLet,
-        PrepareConst,
-        PrepareFunction
-    };
-    bool checkAndPrepareLexical(PrepareLexicalKind prepareWhat, const TokenPos& errorPos);
-    bool prepareAndBindInitializedLexicalWithNode(HandlePropertyName name,
-                                                  PrepareLexicalKind prepareWhat,
-                                                  ParseNode* pn, const TokenPos& pos);
-    Node makeInitializedLexicalBinding(HandlePropertyName name, PrepareLexicalKind prepareWhat,
-                                       const TokenPos& pos);
+    bool checkAndPrepareLexical(bool isConst, const TokenPos& errorPos);
+    Node makeInitializedLexicalBinding(HandlePropertyName name, bool isConst, const TokenPos& pos);
 
     Node newBindingNode(PropertyName* name, bool functionScope, VarContext varContext = HoistVars);
 
     // Top-level entrypoint into destructuring pattern checking/name-analyzing.
     bool checkDestructuringPattern(BindData<ParseHandler>* data, Node pattern);
 
     // Recursive methods for checking/name-analyzing subcomponents of a
     // destructuring pattern.  The array/object methods *must* be passed arrays
     // or objects.  The name method may be passed anything but will report an
     // error if not passed a name.
     bool checkDestructuringArray(BindData<ParseHandler>* data, Node arrayPattern);
     bool checkDestructuringObject(BindData<ParseHandler>* data, Node objectPattern);
     bool checkDestructuringName(BindData<ParseHandler>* data, Node expr);
 
-    bool bindInitialized(BindData<ParseHandler>* data, HandlePropertyName name, Node pn);
     bool bindInitialized(BindData<ParseHandler>* data, Node pn);
-    bool bindUninitialized(BindData<ParseHandler>* data, HandlePropertyName name, Node pn);
     bool bindUninitialized(BindData<ParseHandler>* data, Node pn);
     bool makeSetCall(Node node, unsigned errnum);
     Node cloneDestructuringDefault(Node opn);
     Node cloneLeftHandSide(Node opn);
     Node cloneParseTree(Node opn);
 
     Node newNumber(const Token& tok) {
         return handler.newNumber(tok.number(), tok.decimalPoint(), tok.pos);
--- a/js/src/frontend/SharedContext.h
+++ b/js/src/frontend/SharedContext.h
@@ -578,22 +578,16 @@ class MOZ_STACK_CLASS StmtInfoStack
   public:
     explicit StmtInfoStack(ExclusiveContext* cx)
       : innermostStmt_(nullptr),
         innermostScopeStmt_(nullptr)
     { }
 
     StmtInfo* innermost() const { return innermostStmt_; }
     StmtInfo* innermostScopeStmt() const { return innermostScopeStmt_; }
-    StmtInfo* innermostNonLabel() const {
-        StmtInfo* stmt = innermost();
-        while (stmt && stmt->type == StmtType::LABEL)
-            stmt = stmt->enclosing;
-        return stmt;
-    }
 
     void push(StmtInfo* stmt, StmtType type) {
         stmt->type = type;
         stmt->isBlockScope = false;
         stmt->isForLetBlock = false;
         stmt->label = nullptr;
         stmt->staticScope = nullptr;
         stmt->enclosing = innermostStmt_;
--- a/js/src/frontend/SyntaxParseHandler.h
+++ b/js/src/frontend/SyntaxParseHandler.h
@@ -285,17 +285,16 @@ class SyntaxParseHandler
     bool addClassMethodDefinition(Node literal, Node name, Node fn, JSOp op, bool isStatic) { return true; }
     Node newYieldExpression(uint32_t begin, Node value, Node gen) { return NodeUnparenthesizedYieldExpr; }
     Node newYieldStarExpression(uint32_t begin, Node value, Node gen) { return NodeGeneric; }
 
     // Statements
 
     Node newStatementList(unsigned blockid, const TokenPos& pos) { return NodeGeneric; }
     void addStatementToList(Node list, Node stmt, ParseContext<SyntaxParseHandler>* pc) {}
-    void addCaseStatementToList(Node list, Node stmt, ParseContext<SyntaxParseHandler>* pc) {}
     bool prependInitialYield(Node stmtList, Node gen) { return true; }
     Node newEmptyStatement(const TokenPos& pos) { return NodeEmptyStatement; }
 
     Node newSetThis(Node thisName, Node value) { return value; }
 
     Node newExprStatement(Node expr, uint32_t end) {
         return expr == NodeUnparenthesizedString ? NodeStringExprStatement : NodeGeneric;
     }
@@ -329,17 +328,16 @@ class SyntaxParseHandler
     bool addCatchBlock(Node catchList, Node letBlock,
                        Node catchName, Node catchGuard, Node catchBody) { return true; }
 
     bool setLastFunctionArgumentDefault(Node funcpn, Node pn) { return true; }
     void setLastFunctionArgumentDestructuring(Node funcpn, Node pn) {}
     Node newFunctionDefinition() { return NodeHoistableDeclaration; }
     void setFunctionBody(Node pn, Node kid) {}
     void setFunctionBox(Node pn, FunctionBox* funbox) {}
-    Node newFunctionDefinitionForAnnexB(Node pn, Node assignment) { return NodeHoistableDeclaration; }
     void addFunctionArgument(Node pn, Node argpn) {}
 
     Node newForStatement(uint32_t begin, Node forHead, Node body, unsigned iflags) {
         return NodeGeneric;
     }
 
     Node newComprehensionFor(uint32_t begin, Node forHead, Node body) {
         return NodeGeneric;
@@ -351,17 +349,17 @@ class SyntaxParseHandler
 
     Node newLexicalScope(ObjectBox* blockbox) { return NodeGeneric; }
     void setLexicalScopeBody(Node block, Node body) {}
 
     Node newLetBlock(Node vars, Node block, const TokenPos& pos) {
         return NodeGeneric;
     }
 
-    bool finishInitializerAssignment(Node pn, Node init) { return true; }
+    bool finishInitializerAssignment(Node pn, Node init, JSOp op) { return true; }
     void setLexicalDeclarationOp(Node pn, JSOp op) {}
 
     void setBeginPosition(Node pn, Node oth) {}
     void setBeginPosition(Node pn, uint32_t begin) {}
 
     void setEndPosition(Node pn, Node oth) {}
     void setEndPosition(Node pn, uint32_t end) {}
 
--- a/js/src/jit-test/tests/auto-regress/bug771027.js
+++ b/js/src/jit-test/tests/auto-regress/bug771027.js
@@ -1,9 +1,9 @@
 // |jit-test| error:TypeError
 
 // Binary: cache/js-dbg-32-b6aa44d8f11f-linux
 // Flags:
 //
 
-Array.prototype.iterator = (function() { { while(0) { function Uint8ClampedArray() {  } } } });
+Array.prototype.iterator = (function() { { while(0) function Uint8ClampedArray() {  } } });
 var s = new Set(["testing", "testing", 123]);
 assertEq(s.size(), 2);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/baseline/bug1081850.js
@@ -0,0 +1,18 @@
+// |jit-test| ion-eager
+
+var ARR = [];
+try {
+    function f() {
+        ARR.push(eval.prototype)
+    }
+    f()
+    function eval()(0)
+    f()
+} catch (e) {}
+
+if (ARR.length !== 2)
+    throw new Error("ERROR 1");
+if (typeof(ARR[0]) !== 'undefined')
+    throw new Error("ERROR 2");
+if (typeof(ARR[1]) !== 'object')
+    throw new Error("ERROR 3");
--- a/js/src/jit-test/tests/basic/bug667504-syntax.js
+++ b/js/src/jit-test/tests/basic/bug667504-syntax.js
@@ -1,3 +1,2 @@
-for (var x in x) {
+for (var x in x)
 function x() {}
-}
--- a/js/src/jit-test/tests/ion/bug1148973-1.js
+++ b/js/src/jit-test/tests/ion/bug1148973-1.js
@@ -3,16 +3,12 @@ try {
     String(b = Proxy.createFunction(function() {
         return {
             get: function(r, z) {
                 return x[z]
             }
         }
     }(), function() {}))
 } catch (e) {};
-var log = "";
-evaluate(`
 try {
     function x() {}
     assertEq(String(b), "function () {}");
-} catch (e) { log += "e"; }
-`);
-assertEq(log, "e");
+} catch (e) { throw (e); }
--- a/js/src/jit/BaselineCompiler.cpp
+++ b/js/src/jit/BaselineCompiler.cpp
@@ -2254,36 +2254,16 @@ BaselineCompiler::emit_JSOP_BINDGNAME()
         }
 
         // Otherwise we have to use the dynamic scope chain.
     }
 
     return emit_JSOP_BINDNAME();
 }
 
-typedef JSObject* (*BindVarFn)(JSContext*, HandleObject);
-static const VMFunction BindVarInfo = FunctionInfo<BindVarFn>(jit::BindVar);
-
-bool
-BaselineCompiler::emit_JSOP_BINDVAR()
-{
-    frame.syncStack(0);
-    masm.loadPtr(frame.addressOfScopeChain(), R0.scratchReg());
-
-    prepareVMCall();
-    pushArg(R0.scratchReg());
-
-    if (!callVM(BindVarInfo))
-        return false;
-
-    masm.tagValue(JSVAL_TYPE_OBJECT, ReturnReg, R0);
-    frame.push(R0);
-    return true;
-}
-
 bool
 BaselineCompiler::emit_JSOP_SETPROP()
 {
     // Keep lhs in R0, rhs in R1.
     frame.popRegsAndSync(2);
 
     // Call IC.
     ICSetProp_Fallback::Compiler compiler(cx);
--- a/js/src/jit/BaselineCompiler.h
+++ b/js/src/jit/BaselineCompiler.h
@@ -136,17 +136,16 @@ namespace jit {
     _(JSOP_GETXPROP)           \
     _(JSOP_GETALIASEDVAR)      \
     _(JSOP_SETALIASEDVAR)      \
     _(JSOP_GETNAME)            \
     _(JSOP_BINDNAME)           \
     _(JSOP_DELNAME)            \
     _(JSOP_GETIMPORT)          \
     _(JSOP_GETINTRINSIC)       \
-    _(JSOP_BINDVAR)            \
     _(JSOP_DEFVAR)             \
     _(JSOP_DEFCONST)           \
     _(JSOP_DEFLET)             \
     _(JSOP_DEFFUN)             \
     _(JSOP_GETLOCAL)           \
     _(JSOP_SETLOCAL)           \
     _(JSOP_GETARG)             \
     _(JSOP_SETARG)             \
--- a/js/src/jit/BytecodeAnalysis.cpp
+++ b/js/src/jit/BytecodeAnalysis.cpp
@@ -153,17 +153,16 @@ BytecodeAnalysis::init(TempAllocator& al
             for (size_t i = 0; i < catchFinallyRanges.length(); i++) {
                 if (catchFinallyRanges[i].contains(offset))
                     infos_[offset].loopEntryInCatchOrFinally = true;
             }
             break;
 
           case JSOP_GETNAME:
           case JSOP_BINDNAME:
-          case JSOP_BINDVAR:
           case JSOP_SETNAME:
           case JSOP_STRICTSETNAME:
           case JSOP_DELNAME:
           case JSOP_GETALIASEDVAR:
           case JSOP_SETALIASEDVAR:
           case JSOP_LAMBDA:
           case JSOP_LAMBDA_ARROW:
           case JSOP_DEFFUN:
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -8423,26 +8423,16 @@ CodeGenerator::visitOutOfLineUnboxFloati
         Label bail;
         masm.branchTestInt32(Assembler::NotEqual, value, &bail);
         bailoutFrom(&bail, ins->snapshot());
     }
     masm.int32ValueToFloatingPoint(value, ToFloatRegister(ins->output()), ins->type());
     masm.jump(ool->rejoin());
 }
 
-typedef JSObject* (*BindVarFn)(JSContext*, HandleObject);
-static const VMFunction BindVarInfo = FunctionInfo<BindVarFn>(jit::BindVar);
-
-void
-CodeGenerator::visitCallBindVar(LCallBindVar* lir)
-{
-    pushArg(ToRegister(lir->scopeChain()));
-    callVM(BindVarInfo, lir);
-}
-
 typedef bool (*GetPropertyFn)(JSContext*, HandleValue, HandlePropertyName, MutableHandleValue);
 static const VMFunction GetPropertyInfo = FunctionInfo<GetPropertyFn>(GetProperty);
 
 void
 CodeGenerator::visitCallGetProperty(LCallGetProperty* lir)
 {
     pushArg(ImmGCPtr(lir->mir()->name()));
     pushArg(ToValue(lir, LCallGetProperty::Value));
--- a/js/src/jit/CodeGenerator.h
+++ b/js/src/jit/CodeGenerator.h
@@ -324,17 +324,16 @@ class CodeGenerator : public CodeGenerat
     void visitInstanceOfV(LInstanceOfV* ins);
     void visitCallInstanceOf(LCallInstanceOf* ins);
     void visitGetDOMProperty(LGetDOMProperty* lir);
     void visitGetDOMMemberV(LGetDOMMemberV* lir);
     void visitGetDOMMemberT(LGetDOMMemberT* lir);
     void visitSetDOMProperty(LSetDOMProperty* lir);
     void visitCallDOMNative(LCallDOMNative* lir);
     void visitCallGetIntrinsicValue(LCallGetIntrinsicValue* lir);
-    void visitCallBindVar(LCallBindVar* lir);
     void visitIsCallable(LIsCallable* lir);
     void visitOutOfLineIsCallable(OutOfLineIsCallable* ool);
     void visitIsObject(LIsObject* lir);
     void visitIsObjectAndBranch(LIsObjectAndBranch* lir);
     void visitHasClass(LHasClass* lir);
     void visitAsmJSParameter(LAsmJSParameter* lir);
     void visitAsmJSReturn(LAsmJSReturn* ret);
     void visitAsmJSVoidReturn(LAsmJSVoidReturn* ret);
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -1938,19 +1938,16 @@ IonBuilder::inspectOpcode(JSOp op)
         if (!script()->hasNonSyntacticScope()) {
             if (JSObject* scope = testGlobalLexicalBinding(info().getName(pc)))
                 return pushConstant(ObjectValue(*scope));
         }
         // Fall through to JSOP_BINDNAME
       case JSOP_BINDNAME:
         return jsop_bindname(info().getName(pc));
 
-      case JSOP_BINDVAR:
-        return jsop_bindvar();
-
       case JSOP_DUP:
         current->pushSlot(current->stackDepth() - 1);
         return true;
 
       case JSOP_DUP2:
         return jsop_dup2();
 
       case JSOP_SWAP:
@@ -8416,26 +8413,16 @@ IonBuilder::jsop_bindname(PropertyName* 
     MBindNameCache* ins = MBindNameCache::New(alloc(), scopeChain, name, script(), pc);
 
     current->add(ins);
     current->push(ins);
 
     return resumeAfter(ins);
 }
 
-bool
-IonBuilder::jsop_bindvar()
-{
-    MOZ_ASSERT(analysis().usesScopeChain());
-    MCallBindVar* ins = MCallBindVar::New(alloc(), current->scopeChain());
-    current->add(ins);
-    current->push(ins);
-    return true;
-}
-
 static MIRType
 GetElemKnownType(bool needsHoleCheck, TemporaryTypeSet* types)
 {
     MIRType knownType = types->getKnownMIRType();
 
     // Null and undefined have no payload so they can't be specialized.
     // Since folding null/undefined while building SSA is not safe (see the
     // comment in IsPhiObservable), we just add an untyped load instruction
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -684,17 +684,16 @@ class IonBuilder
     bool getStaticName(JSObject* staticObject, PropertyName* name, bool* psucceeded,
                        MDefinition* lexicalCheck = nullptr);
     bool setStaticName(JSObject* staticObject, PropertyName* name);
     bool jsop_getgname(PropertyName* name);
     bool jsop_getname(PropertyName* name);
     bool jsop_intrinsic(PropertyName* name);
     bool jsop_getimport(PropertyName* name);
     bool jsop_bindname(PropertyName* name);
-    bool jsop_bindvar();
     bool jsop_getelem();
     bool jsop_getelem_dense(MDefinition* obj, MDefinition* index, JSValueType unboxedType);
     bool jsop_getelem_typed(MDefinition* obj, MDefinition* index, ScalarTypeDescr::Type arrayType);
     bool jsop_setelem();
     bool jsop_setelem_dense(TemporaryTypeSet::DoubleConversion conversion,
                             MDefinition* object, MDefinition* index, MDefinition* value,
                             JSValueType unboxedType, bool writeHole);
     bool jsop_setelem_typed(ScalarTypeDescr::Type arrayType,
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -3357,26 +3357,16 @@ LIRGenerator::visitBindNameCache(MBindNa
     MOZ_ASSERT(ins->type() == MIRType_Object);
 
     LBindNameCache* lir = new(alloc()) LBindNameCache(useRegister(ins->scopeChain()));
     define(lir, ins);
     assignSafepoint(lir, ins);
 }
 
 void
-LIRGenerator::visitCallBindVar(MCallBindVar* ins)
-{
-    MOZ_ASSERT(ins->scopeChain()->type() == MIRType_Object);
-    MOZ_ASSERT(ins->type() == MIRType_Object);
-
-    LCallBindVar* lir = new(alloc()) LCallBindVar(useRegister(ins->scopeChain()));
-    define(lir, ins);
-}
-
-void
 LIRGenerator::visitGuardObjectIdentity(MGuardObjectIdentity* ins)
 {
     LGuardObjectIdentity* guard = new(alloc()) LGuardObjectIdentity(useRegister(ins->obj()),
                                                                     useRegister(ins->expected()));
     assignSnapshot(guard, Bailout_ObjectIdentityOrTypeGuard);
     add(guard, ins);
     redefine(ins, ins->obj());
 }
--- a/js/src/jit/Lowering.h
+++ b/js/src/jit/Lowering.h
@@ -225,17 +225,16 @@ class LIRGenerator : public LIRGenerator
     void visitStoreTypedArrayElementHole(MStoreTypedArrayElementHole* ins);
     void visitClampToUint8(MClampToUint8* ins);
     void visitLoadFixedSlot(MLoadFixedSlot* ins);
     void visitStoreFixedSlot(MStoreFixedSlot* ins);
     void visitGetPropertyCache(MGetPropertyCache* ins);
     void visitGetPropertyPolymorphic(MGetPropertyPolymorphic* ins);
     void visitSetPropertyPolymorphic(MSetPropertyPolymorphic* ins);
     void visitBindNameCache(MBindNameCache* ins);
-    void visitCallBindVar(MCallBindVar* ins);
     void visitGuardObjectIdentity(MGuardObjectIdentity* ins);
     void visitGuardClass(MGuardClass* ins);
     void visitGuardObject(MGuardObject* ins);
     void visitGuardString(MGuardString* ins);
     void visitGuardReceiverPolymorphic(MGuardReceiverPolymorphic* ins);
     void visitGuardUnboxedExpando(MGuardUnboxedExpando* ins);
     void visitLoadUnboxedExpando(MLoadUnboxedExpando* ins);
     void visitPolyInlineGuard(MPolyInlineGuard* ins);
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -10753,49 +10753,16 @@ class MBindNameCache
     JSScript* script() const {
         return script_;
     }
     jsbytecode* pc() const {
         return pc_;
     }
 };
 
-class MCallBindVar
-  : public MUnaryInstruction,
-    public SingleObjectPolicy::Data
-{
-    explicit MCallBindVar(MDefinition* scopeChain)
-      : MUnaryInstruction(scopeChain)
-    {
-        setResultType(MIRType_Object);
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(CallBindVar)
-
-    static MCallBindVar* New(TempAllocator& alloc, MDefinition* scopeChain) {
-        return new(alloc) MCallBindVar(scopeChain);
-    }
-
-    MDefinition* scopeChain() const {
-        return getOperand(0);
-    }
-
-    bool congruentTo(const MDefinition* ins) const override {
-        if (!ins->isCallBindVar())
-            return false;
-        return congruentIfOperandsEqual(ins);
-    }
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-};
-
 // Guard on an object's shape.
 class MGuardShape
   : public MUnaryInstruction,
     public SingleObjectPolicy::Data
 {
     CompilerShape shape_;
     BailoutKind bailoutKind_;
 
--- a/js/src/jit/MOpcodes.h
+++ b/js/src/jit/MOpcodes.h
@@ -157,17 +157,16 @@ namespace jit {
     _(FilterTypeSet)                                                        \
     _(TypeBarrier)                                                          \
     _(MonitorTypes)                                                         \
     _(PostWriteBarrier)                                                     \
     _(GetPropertyCache)                                                     \
     _(GetPropertyPolymorphic)                                               \
     _(SetPropertyPolymorphic)                                               \
     _(BindNameCache)                                                        \
-    _(CallBindVar)                                                          \
     _(GuardShape)                                                           \
     _(GuardReceiverPolymorphic)                                             \
     _(GuardObjectGroup)                                                     \
     _(GuardObjectIdentity)                                                  \
     _(GuardClass)                                                           \
     _(GuardUnboxedExpando)                                                  \
     _(LoadUnboxedExpando)                                                   \
     _(ArrayLength)                                                          \
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -162,42 +162,38 @@ CheckOverRecursedWithExtra(JSContext* cx
 #else
     JS_CHECK_RECURSION_WITH_SP(cx, checkSp, return false);
 #endif
 
     gc::MaybeVerifyBarriers(cx);
     return cx->runtime()->handleInterrupt(cx);
 }
 
-JSObject*
-BindVar(JSContext* cx, HandleObject scopeChain)
-{
-    JSObject* obj = scopeChain;
-    while (!obj->isQualifiedVarObj())
-        obj = obj->enclosingScope();
-    MOZ_ASSERT(obj);
-    return obj;
-}
-
 bool
 DefVar(JSContext* cx, HandlePropertyName dn, unsigned attrs, HandleObject scopeChain)
 {
     // Given the ScopeChain, extract the VarObj.
-    RootedObject obj(cx, BindVar(cx, scopeChain));
+    RootedObject obj(cx, scopeChain);
+    while (!obj->isQualifiedVarObj())
+        obj = obj->enclosingScope();
+
     return DefVarOperation(cx, obj, dn, attrs);
 }
 
 bool
 DefLexical(JSContext* cx, HandlePropertyName dn, unsigned attrs, HandleObject scopeChain)
 {
     // Find the extensible lexical scope.
     Rooted<ClonedBlockObject*> lexical(cx, &NearestEnclosingExtensibleLexicalScope(scopeChain));
 
     // Find the variables object.
-    RootedObject varObj(cx, BindVar(cx, scopeChain));
+    RootedObject varObj(cx, scopeChain);
+    while (!varObj->isQualifiedVarObj())
+        varObj = varObj->enclosingScope();
+
     return DefLexicalOperation(cx, lexical, varObj, dn, attrs);
 }
 
 bool
 DefGlobalLexical(JSContext* cx, HandlePropertyName dn, unsigned attrs)
 {
     Rooted<ClonedBlockObject*> globalLexical(cx, &cx->global()->lexicalScope());
     return DefLexicalOperation(cx, globalLexical, cx->global(), dn, attrs);
@@ -852,34 +848,36 @@ GeneratorThrowOrClose(JSContext* cx, Bas
     MOZ_ALWAYS_FALSE(js::GeneratorThrowOrClose(cx, frame, genObj, arg, resumeKind));
     return false;
 }
 
 bool
 InitGlobalOrEvalScopeObjects(JSContext* cx, BaselineFrame* frame)
 {
     RootedScript script(cx, frame->script());
-    RootedObject scopeChain(cx, frame->scopeChain());
-    RootedObject varObj(cx, BindVar(cx, scopeChain));
+    RootedObject varObj(cx, frame->scopeChain());
+    while (!varObj->isQualifiedVarObj())
+        varObj = varObj->enclosingScope();
 
     if (script->isForEval()) {
         // Strict eval needs its own call object.
         //
         // Non-strict eval may introduce 'var' bindings that conflict with
         // lexical bindings in an enclosing lexical scope.
         if (script->strict()) {
             if (!frame->initStrictEvalScopeObjects(cx))
                 return false;
         } else {
+            RootedObject scopeChain(cx, frame->scopeChain());
             if (!CheckEvalDeclarationConflicts(cx, script, scopeChain, varObj))
                 return false;
         }
     } else {
         Rooted<ClonedBlockObject*> lexicalScope(cx,
-            &NearestEnclosingExtensibleLexicalScope(scopeChain));
+            &NearestEnclosingExtensibleLexicalScope(frame->scopeChain()));
         if (!CheckGlobalDeclarationConflicts(cx, script, lexicalScope, varObj))
             return false;
     }
 
     return true;
 }
 
 bool
--- a/js/src/jit/VMFunctions.h
+++ b/js/src/jit/VMFunctions.h
@@ -583,17 +583,16 @@ bool InvokeFunction(JSContext* cx, Handl
                     Value* argv, MutableHandleValue rval);
 bool InvokeFunctionShuffleNewTarget(JSContext* cx, HandleObject obj, uint32_t numActualArgs,
                                     uint32_t numFormalArgs, Value* argv, MutableHandleValue rval);
 
 bool CheckOverRecursed(JSContext* cx);
 bool CheckOverRecursedWithExtra(JSContext* cx, BaselineFrame* frame,
                                 uint32_t extra, uint32_t earlyCheck);
 
-JSObject* BindVar(JSContext* cx, HandleObject scopeChain);
 bool DefVar(JSContext* cx, HandlePropertyName dn, unsigned attrs, HandleObject scopeChain);
 bool DefLexical(JSContext* cx, HandlePropertyName dn, unsigned attrs, HandleObject scopeChain);
 bool DefGlobalLexical(JSContext* cx, HandlePropertyName dn, unsigned attrs);
 bool MutatePrototype(JSContext* cx, HandlePlainObject obj, HandleValue value);
 bool InitProp(JSContext* cx, HandleObject obj, HandlePropertyName name, HandleValue value,
               jsbytecode* pc);
 
 template<bool Equal>
--- a/js/src/jit/shared/LIR-shared.h
+++ b/js/src/jit/shared/LIR-shared.h
@@ -5769,32 +5769,16 @@ class LBindNameCache : public LInstructi
     const LAllocation* scopeChain() {
         return getOperand(0);
     }
     const MBindNameCache* mir() const {
         return mir_->toBindNameCache();
     }
 };
 
-class LCallBindVar : public LInstructionHelper<1, 1, 0>
-{
-  public:
-    LIR_HEADER(CallBindVar)
-
-    explicit LCallBindVar(const LAllocation& scopeChain) {
-        setOperand(0, scopeChain);
-    }
-    const LAllocation* scopeChain() {
-        return getOperand(0);
-    }
-    const MCallBindVar* mir() const {
-        return mir_->toCallBindVar();
-    }
-};
-
 // Load a value from an object's dslots or a slots vector.
 class LLoadSlotV : public LInstructionHelper<BOX_PIECES, 1, 0>
 {
   public:
     LIR_HEADER(LoadSlotV)
 
     explicit LLoadSlotV(const LAllocation& in) {
         setOperand(0, in);
--- a/js/src/jit/shared/LOpcodes-shared.h
+++ b/js/src/jit/shared/LOpcodes-shared.h
@@ -272,17 +272,16 @@
     _(StoreFixedSlotV)              \
     _(StoreFixedSlotT)              \
     _(FunctionEnvironment)          \
     _(GetPropertyCacheV)            \
     _(GetPropertyCacheT)            \
     _(GetPropertyPolymorphicV)      \
     _(GetPropertyPolymorphicT)      \
     _(BindNameCache)                \
-    _(CallBindVar)                  \
     _(CallGetProperty)              \
     _(GetNameCache)                 \
     _(CallGetIntrinsicValue)        \
     _(CallGetElement)               \
     _(CallSetElement)               \
     _(CallInitElementArray)         \
     _(CallSetProperty)              \
     _(CallDeleteProperty)           \
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -264,19 +264,16 @@ MSG_DEF(JSMSG_IDSTART_AFTER_NUMBER,    0
 MSG_DEF(JSMSG_ILLEGAL_CHARACTER,       0, JSEXN_SYNTAXERR, "illegal character")
 MSG_DEF(JSMSG_IMPORT_DECL_AT_TOP_LEVEL, 0, JSEXN_SYNTAXERR, "import declarations may only appear at top level of a module")
 MSG_DEF(JSMSG_INVALID_FOR_INOF_DECL_WITH_INIT,1,JSEXN_SYNTAXERR,"for-{0} loop head declarations may not have initializers")
 MSG_DEF(JSMSG_IN_AFTER_FOR_NAME,       0, JSEXN_SYNTAXERR, "missing 'in' or 'of' after for")
 MSG_DEF(JSMSG_LABEL_NOT_FOUND,         0, JSEXN_SYNTAXERR, "label not found")
 MSG_DEF(JSMSG_LET_CLASS_BINDING,       0, JSEXN_SYNTAXERR, "'let' is not a valid name for a class")
 MSG_DEF(JSMSG_LET_COMP_BINDING,        0, JSEXN_SYNTAXERR, "'let' is not a valid name for a comprehension variable")
 MSG_DEF(JSMSG_LEXICAL_DECL_NOT_IN_BLOCK,   1, JSEXN_SYNTAXERR, "{0} declaration not directly within block")
-MSG_DEF(JSMSG_LEXICAL_DECL_LABEL,      1, JSEXN_SYNTAXERR, "{0} declarations cannot be labelled")
-MSG_DEF(JSMSG_FUNCTION_LABEL,          0, JSEXN_SYNTAXERR, "functions cannot be labelled")
-MSG_DEF(JSMSG_SLOPPY_FUNCTION_LABEL,   0, JSEXN_SYNTAXERR, "functions can only be labelled inside blocks")
 MSG_DEF(JSMSG_LINE_BREAK_AFTER_THROW,  0, JSEXN_SYNTAXERR, "no line break is allowed between 'throw' and its expression")
 MSG_DEF(JSMSG_MALFORMED_ESCAPE,        1, JSEXN_SYNTAXERR, "malformed {0} character escape sequence")
 MSG_DEF(JSMSG_MISSING_BINARY_DIGITS,   0, JSEXN_SYNTAXERR, "missing binary digits after '0b'")
 MSG_DEF(JSMSG_MISSING_EXPONENT,        0, JSEXN_SYNTAXERR, "missing exponent")
 MSG_DEF(JSMSG_MISSING_EXPR_AFTER_THROW,0, JSEXN_SYNTAXERR, "throw statement is missing an expression")
 MSG_DEF(JSMSG_MISSING_FORMAL,          0, JSEXN_SYNTAXERR, "missing formal parameter")
 MSG_DEF(JSMSG_MISSING_HEXDIGITS,       0, JSEXN_SYNTAXERR, "missing hexadecimal digits after '0x'")
 MSG_DEF(JSMSG_MISSING_OCTAL_DIGITS,    0, JSEXN_SYNTAXERR, "missing octal digits after '0o'")
--- a/js/src/tests/ecma_5/extensions/function-definition-with.js
+++ b/js/src/tests/ecma_5/extensions/function-definition-with.js
@@ -14,41 +14,38 @@ print(BUGNUMBER + ": " + summary);
  * BEGIN TEST *
  **************/
 
 var called, obj;
 
 function inFile1() { return "in file"; }
 called = false;
 obj = { set inFile1(v) { called = true; } };
-with (obj) {
+with (obj)
   function inFile1() { return "in file in with"; };
-}
 assertEq(inFile1(), "in file in with");
 assertEq("set" in Object.getOwnPropertyDescriptor(obj, "inFile1"), true);
 assertEq(called, false);
 
 evaluate("function notInFile1() { return 'not in file'; }");
 called = false;
 obj = { set notInFile1(v) { called = true; return "not in file 2"; } };
-with (obj) {
+with (obj)
   function notInFile1() { return "not in file in with"; };
-}
 assertEq(notInFile1(), "not in file in with");
 assertEq("set" in Object.getOwnPropertyDescriptor(obj, "notInFile1"), true);
 assertEq(called, false);
 
 function inFile2() { return "in file 1"; }
 called = false;
 obj =
   Object.defineProperty({}, "inFile2",
                         { value: 42, configurable: false, enumerable: false });
-with (obj) {
+with (obj)
   function inFile2() { return "in file 2"; };
-}
 assertEq(inFile2(), "in file 2");
 assertEq(obj.inFile2, 42);
 
 
 /******************************************************************************/
 
 if (typeof reportCompare === "function")
   reportCompare(true, true);
--- a/js/src/tests/ecma_5/extensions/strict-function-statements.js
+++ b/js/src/tests/ecma_5/extensions/strict-function-statements.js
@@ -4,91 +4,97 @@
  */
 
 // Ordinary function definitions should be unaffected.
 assertEq(testLenientAndStrict("function f() { }",
                               parsesSuccessfully,
                               parsesSuccessfully),
          true);
 
+// Function statements within blocks are forbidden in strict mode code.
+assertEq(testLenientAndStrict("{ function f() { } }",
+                              parsesSuccessfully,
+                              parseRaisesException(SyntaxError)),
+         true);
+
 // Lambdas are always permitted within blocks.
 assertEq(testLenientAndStrict("{ (function f() { }) }",
                               parsesSuccessfully,
                               parsesSuccessfully),
          true);
 
-// Function statements within unbraced blocks are forbidden in strict mode code.
-// They are allowed only under if statements in sloppy mode.
+// Function statements within any sort of statement are forbidden in strict mode code.
 assertEq(testLenientAndStrict("if (true) function f() { }",
                               parsesSuccessfully,
                               parseRaisesException(SyntaxError)),
          true);
 assertEq(testLenientAndStrict("while (true) function f() { }",
-                              parseRaisesException(SyntaxError),
+                              parsesSuccessfully,
                               parseRaisesException(SyntaxError)),
          true);
 assertEq(testLenientAndStrict("do function f() { } while (true);",
-                              parseRaisesException(SyntaxError),
+                              parsesSuccessfully,
                               parseRaisesException(SyntaxError)),
          true);
 assertEq(testLenientAndStrict("for(;;) function f() { }",
-                              parseRaisesException(SyntaxError),
+                              parsesSuccessfully,
                               parseRaisesException(SyntaxError)),
          true);
 assertEq(testLenientAndStrict("for(x in []) function f() { }",
-                              parseRaisesException(SyntaxError),
+                              parsesSuccessfully,
                               parseRaisesException(SyntaxError)),
          true);
 assertEq(testLenientAndStrict("with(o) function f() { }",
-                              parseRaisesException(SyntaxError),
+                              parsesSuccessfully,
                               parseRaisesException(SyntaxError)),
          true);
 assertEq(testLenientAndStrict("switch(1) { case 1: function f() { } }",
                               parsesSuccessfully,
-                              parsesSuccessfully),
+                              parseRaisesException(SyntaxError)),
          true);
 assertEq(testLenientAndStrict("x: function f() { }",
                               parsesSuccessfully,
                               parseRaisesException(SyntaxError)),
          true);
 assertEq(testLenientAndStrict("try { function f() { } } catch (x) { }",
                               parsesSuccessfully,
-                              parsesSuccessfully),
+                              parseRaisesException(SyntaxError)),
          true);
 
 // Lambdas are always permitted within any sort of statement.
 assertEq(testLenientAndStrict("if (true) (function f() { })",
                               parsesSuccessfully,
                               parsesSuccessfully),
          true);
 
 // Function statements are permitted in blocks within lenient functions.
 assertEq(parsesSuccessfully("function f() { function g() { } }"),
          true);
 
-// Function statements are permitted in if statement within lenient functions.
+// Function statements are permitted in any statement within lenient functions.
 assertEq(parsesSuccessfully("function f() { if (true) function g() { } }"),
          true);
 
 assertEq(parseRaisesException(SyntaxError)
          ("function f() { 'use strict'; if (true) function g() { } }"),
          true);
 
-assertEq(parsesSuccessfully("function f() { 'use strict'; { function g() { } } }"),
+assertEq(parseRaisesException(SyntaxError)
+         ("function f() { 'use strict'; { function g() { } } }"),
          true);
 
 assertEq(parsesSuccessfully("function f() { 'use strict'; if (true) (function g() { }) }"),
          true);
 
 assertEq(parsesSuccessfully("function f() { 'use strict'; { (function g() { }) } }"),
          true);
 
 // Eval should behave the same way. (The parse-only tests use the Function constructor.)
 assertEq(testLenientAndStrict("function f() { }",
                               completesNormally,
                               completesNormally),
          true);
 assertEq(testLenientAndStrict("{ function f() { } }",
                               completesNormally,
-                              completesNormally),
+                              raisesException(SyntaxError)),
          true);
 
 reportCompare(true, true);
deleted file mode 100644
--- a/js/src/tests/ecma_6/LexicalEnvironment/block-scoped-functions-annex-b-eval.js
+++ /dev/null
@@ -1,38 +0,0 @@
-var log = "";
-
-function f() {
-  log += g();
-  function g() { return "outer-g"; }
-
-  var o = { g: function () { return "with-g"; } };
-  with (o) {
-    // Annex B.3.3.3 says g should be set on the nearest VariableEnvironment,
-    // and so should not change o.g.
-    eval(`{
-      function g() { return "eval-g"; }
-    }`);
-  }
-
-  log += g();
-  log += o.g();
-}
-
-f();
-
-function h() {
-  eval(`
-    // Should return true, as var bindings introduced by eval are configurable.
-    log += (delete q);
-    {
-      function q() { log += "q"; }
-      // Should return false, as lexical bindings introduced by eval are not
-      // configurable.
-      log += (delete q);
-    }
-  `);
-  return q;
-}
-
-h()();
-
-reportCompare(log, "outer-geval-gwith-gtruefalseq");
deleted file mode 100644
--- a/js/src/tests/ecma_6/LexicalEnvironment/block-scoped-functions-annex-b-if.js
+++ /dev/null
@@ -1,42 +0,0 @@
-var log = "";
-
-function f(x) {
-  if (x)
-    function g() { return "g0"; }
-  else
-    function g() { return "g1"; }
-
-  log += g();
-
-  if (x)
-    function g() { return "g2"; }
-  else {
-  }
-
-  log += g();
-
-  if (x) {
-  } else
-    function g() { return "g3"; }
-
-  log += g();
-
-  if (x)
-    function g() { return "g4"; }
-
-  log += g();
-}
-
-f(true);
-f(false);
-
-try {
-  eval(`
-    if (1)
-      l: function foo() {}
-  `);
-} catch (e) {
-  log += "e";
-}
-
-reportCompare(log, "g0g2g2g4g1g1g3g3e");
deleted file mode 100644
--- a/js/src/tests/ecma_6/LexicalEnvironment/block-scoped-functions-annex-b-label.js
+++ /dev/null
@@ -1,43 +0,0 @@
-function expectSyntaxError(str) {
-  var threwSyntaxError;
-  try {
-    eval(str);
-  } catch (e) {
-    threwSyntaxError = e instanceof SyntaxError;
-  }
-  assertEq(threwSyntaxError, true);
-
-  try {
-    eval('"use strict";' + str);
-  } catch (e) {
-    threwSyntaxError = e instanceof SyntaxError;
-  }
-  assertEq(threwSyntaxError, true);
-}
-
-function expectSloppyPass(str) {
-  eval(str);
-
-  try {
-    eval('"use strict";' + str);
-  } catch (e) {
-    threwSyntaxError = e instanceof SyntaxError;
-  }
-  assertEq(threwSyntaxError, true);
-}
-
-expectSloppyPass(`l: function f1() {}`);
-expectSloppyPass(`l0: l: function f1() {}`);
-expectSloppyPass(`{ f1(); l: function f1() {} }`);
-expectSloppyPass(`{ f1(); l0: l: function f1() {} }`);
-expectSloppyPass(`{ f1(); l: function f1() { return 42; } } assertEq(f1(), 42);`);
-expectSloppyPass(`eval("fe(); l: function fe() {}")`);
-expectSyntaxError(`if (1) l: function f2() {}`);
-expectSyntaxError(`if (1) {} else l: function f3() {}`);
-expectSyntaxError(`do l: function f4() {} while (0)`);
-expectSyntaxError(`while (0) l: function f5() {}`);
-expectSyntaxError(`for (;;) l: function f6() {}`);
-expectSloppyPass(`switch (1) { case 1: l: function f7() {} }`);
-expectSloppyPass(`switch (1) { case 1: assertEq(f8(), 'f8'); case 2: l: function f8() { return 'f8'; } } assertEq(f8(), 'f8');`);
-
-reportCompare(0, 0);
deleted file mode 100644
--- a/js/src/tests/ecma_6/LexicalEnvironment/block-scoped-functions-annex-b-property.js
+++ /dev/null
@@ -1,18 +0,0 @@
-// |reftest| skip-if(!xulRuntime.shell)
-
-// Define a global getter without a setter.
-Object.defineProperty(this, "x", {
-  get: function () { return "get-x"; },
-  configurable: true
-});
-
-// Simulate loading a 2nd script with evaluate, else we would DEFVAR the x and
-// the above defineProperty would fail in trying to redefine a non-configurable
-// property on the global.
-evaluate(`{
-  function x() { return "fun-x"; }
-}`);
-
-// Annex B is supposed to be like an assignment. Should not blow away the
-// existing setter-less getter.
-reportCompare(x, "get-x");
deleted file mode 100644
--- a/js/src/tests/ecma_6/LexicalEnvironment/block-scoped-functions-annex-b-same-name.js
+++ /dev/null
@@ -1,7 +0,0 @@
-{
-  function f() { return "inner"; }
-}
-
-function f() { return "outer"; }
-
-reportCompare(f(), "inner");
deleted file mode 100644
--- a/js/src/tests/ecma_6/LexicalEnvironment/block-scoped-functions-annex-b-with.js
+++ /dev/null
@@ -1,18 +0,0 @@
-var o = { f: "string-f" };
-with (o) {
-  var desc = Object.getOwnPropertyDescriptor(this, "f");
-  assertEq(desc.value, undefined);
-  assertEq(desc.writable, true);
-  assertEq(desc.enumerable, true);
-  assertEq(desc.configurable, false);
-  function f() {
-    return "fun-f";
-  }
-}
-
-// Annex B explicitly assigns to the nearest VariableEnvironment, so the
-// with-object "o" should have its property unchanged.
-assertEq(o.f, "string-f");
-assertEq(f(), "fun-f");
-
-reportCompare(true, true)
deleted file mode 100644
--- a/js/src/tests/ecma_6/LexicalEnvironment/block-scoped-functions-annex-b.js
+++ /dev/null
@@ -1,31 +0,0 @@
-var log = "";
-
-log += typeof f;
-
-{
-  log += f();
-
-  function f() {
-    return "f1";
-  }
-}
-
-log += f();
-
-function g() {
-  log += typeof h;
-
-  {
-    log += h();
-
-    function h() {
-      return "h1";
-    }
-  }
-
-  log += h();
-}
-
-g();
-
-reportCompare(log, "undefinedf1f1undefinedh1h1");
deleted file mode 100644
--- a/js/src/tests/ecma_6/LexicalEnvironment/block-scoped-functions-strict.js
+++ /dev/null
@@ -1,45 +0,0 @@
-"use strict"
-
-var log = "";
-
-function f() {
-  return "f0";
-}
-
-log += f();
-
-{
-  log += f();
-
-  function f() {
-    return "f1";
-  }
-
-  log += f();
-}
-
-log += f();
-
-function g() {
-  function h() {
-    return "h0";
-  }
-
-  log += h();
-
-  {
-    log += h();
-
-    function h() {
-      return "h1";
-    }
-
-    log += h();
-  }
-
-  log += h();
-}
-
-g();
-
-reportCompare(log, "f0f1f1f0h0h1h1h0");
--- a/js/src/tests/ecma_6/extensions/for-loop-with-lexical-declaration-and-nested-function-statement.js
+++ b/js/src/tests/ecma_6/extensions/for-loop-with-lexical-declaration-and-nested-function-statement.js
@@ -13,40 +13,36 @@ var summary =
   "bindings at runtime";
 
 print(BUGNUMBER + ": " + summary);
 
 /**************
  * BEGIN TEST *
  **************/
 
-for (let x = 0; x < 9; ++x) {
+for (let x = 0; x < 9; ++x)
   function q1() {}
-}
 
 {
-  for (let x = 0; x < 9; ++x) {
+  for (let x = 0; x < 9; ++x)
     function q2() {}
-  }
 }
 
 function f1()
 {
-  for (let x = 0; x < 9; ++x) {
+  for (let x = 0; x < 9; ++x)
     function q3() {}
-  }
 }
 f1();
 
 function f2()
 {
   {
-    for (let x = 0; x < 9; ++x) {
+    for (let x = 0; x < 9; ++x)
       function q4() {}
-    }
   }
 }
 f2();
 
 for (let x = 0; x < 9; ++x)
 {
   // deliberately inside a block statement
   function q5() {}
new file mode 100644
--- /dev/null
+++ b/js/src/tests/js1_5/Regress/regress-326453.js
@@ -0,0 +1,21 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/
+ * Contributor: Blake Kaplan
+ */
+
+//-----------------------------------------------------------------------------
+var BUGNUMBER = 326453;
+var summary = 'Do not assert: while decompiling';
+var actual = 'No Crash';
+var expect = 'No Crash';
+
+printBugNumber(BUGNUMBER);
+printStatus (summary);
+
+function f() { with({})function g() { }; printStatus(); }
+
+printStatus(f.toString());
+
+reportCompare(expect, actual, summary);
--- a/js/src/tests/js1_5/extensions/regress-245795.js
+++ b/js/src/tests/js1_5/extensions/regress-245795.js
@@ -7,25 +7,28 @@
 var BUGNUMBER = 245795;
 var summary = 'eval(uneval(function)) should be round-trippable';
 var actual = '';
 var expect = '';
 
 printBugNumber(BUGNUMBER);
 printStatus (summary);
 
-function a()
+if (typeof uneval != 'undefined')
 {
-  b = function() {};
-}
+  function a()
+  {
+    b = function() {};
+  }
 
-var r = "function a() { b = function() {}; }";
-eval(uneval(a));
+  var r = "function a() { b = function() {}; }";
+  eval(uneval(a));
 
-var v = a.toString().replace(/[ \n]+/g, ' ');
-print(v)
-
-printStatus("[" + v + "]");
+  var v = a.toString().replace(/[ \n]+/g, ' ');
+  print(v)
+ 
+  printStatus("[" + v + "]");
 
-expect = r;
-actual = v;
+  expect = r;
+  actual = v;
 
-reportCompare(expect, actual, summary);
+  reportCompare(expect, actual, summary);
+}
--- a/js/src/tests/js1_5/extensions/regress-406572.js
+++ b/js/src/tests/js1_5/extensions/regress-406572.js
@@ -17,24 +17,22 @@ if (typeof window != 'undefined')
   try {
     actual = "FAIL: Unexpected exception thrown";
 
     var win = window;
     var windowString = String(window);
     window = 1;
     reportCompare(windowString, String(window), "window should be readonly");
 
+    actual = ""; // We should reach this line, and throw an exception after it
+
     if (1)
       function window() { return 1; }
 
-    // We should reach this line without throwing. Annex B means the
-    // block-scoped function above gets an assignment to 'window' in the
-    // nearest 'var' environment, but since 'window' is read-only, the
-    // assignment silently fails.
-    actual = "";
+    actual = "FAIL: this line should never be reached";
 
     // The test harness might rely on window having its original value:
     // restore it.
     window = win;
   } catch (e) {
   }
 }
 else
--- a/js/src/tests/js1_8_5/reflect-parse/declarations.js
+++ b/js/src/tests/js1_8_5/reflect-parse/declarations.js
@@ -1,15 +1,15 @@
 // |reftest| skip-if(!xulRuntime.shell)
 function test() {
 
 // Bug 632056: constant-folding
 program([exprStmt(ident("f")),
          ifStmt(lit(1),
-                blockStmt([funDecl(ident("f"), [], blockStmt([]))]),
+                funDecl(ident("f"), [], blockStmt([])),
                 null)]).assert(Reflect.parse("f; if (1) function f(){}"));
 // declarations
 
 assertDecl("var x = 1, y = 2, z = 3",
            varDecl([{ id: ident("x"), init: lit(1) },
                     { id: ident("y"), init: lit(2) },
                     { id: ident("z"), init: lit(3) }]));
 assertDecl("var x, y, z",
@@ -81,17 +81,9 @@ assertStmt("function g(x) { var x }",
            funDecl(ident("g"), [ident("x")], blockStmt([varDecl[{ id: ident("x"), init: null }]])));
 assertProg("f.p = 1; var f; f.p; function f(){}",
            [exprStmt(aExpr("=", dotExpr(ident("f"), ident("p")), lit(1))),
             varDecl([{ id: ident("f"), init: null }]),
             exprStmt(dotExpr(ident("f"), ident("p"))),
             funDecl(ident("f"), [], blockStmt([]))]);
 }
 
-assertBlockStmt("{ function f(x) {} }",
-                blockStmt([funDecl(ident("f"), [ident("x")], blockStmt([]))]));
-
-// Annex B semantics should not change parse tree.
-assertBlockStmt("{ let f; { function f(x) {} } }",
-                blockStmt([letDecl([{ id: ident("f"), init: null }]),
-                           blockStmt([funDecl(ident("f"), [ident("x")], blockStmt([]))])]));
-
 runtest(test);
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -1748,16 +1748,17 @@ CASE(JSOP_UNUSED181)
 CASE(JSOP_UNUSED182)
 CASE(JSOP_UNUSED183)
 CASE(JSOP_UNUSED187)
 CASE(JSOP_UNUSED192)
 CASE(JSOP_UNUSED209)
 CASE(JSOP_UNUSED210)
 CASE(JSOP_UNUSED211)
 CASE(JSOP_UNUSED212)
+CASE(JSOP_UNUSED213)
 CASE(JSOP_UNUSED219)
 CASE(JSOP_UNUSED220)
 CASE(JSOP_UNUSED221)
 CASE(JSOP_UNUSED222)
 CASE(JSOP_UNUSED223)
 CASE(JSOP_CONDSWITCH)
 CASE(JSOP_TRY)
 {
@@ -2083,22 +2084,16 @@ CASE(JSOP_BINDNAME)
 
     PUSH_OBJECT(*scope);
 
     static_assert(JSOP_BINDNAME_LENGTH == JSOP_BINDGNAME_LENGTH,
                   "We're sharing the END_CASE so the lengths better match");
 }
 END_CASE(JSOP_BINDNAME)
 
-CASE(JSOP_BINDVAR)
-{
-    PUSH_OBJECT(REGS.fp()->varObj());
-}
-END_CASE(JSOP_BINDVAR)
-
 #define BITWISE_OP(OP)                                                        \
     JS_BEGIN_MACRO                                                            \
         int32_t i, j;                                                         \
         if (!ToInt32(cx, REGS.stackHandleAt(-2), &i))                         \
             goto error;                                                       \
         if (!ToInt32(cx, REGS.stackHandleAt(-1), &j))                         \
             goto error;                                                       \
         i = i OP j;                                                           \
--- a/js/src/vm/Opcodes.h
+++ b/js/src/vm/Opcodes.h
@@ -2047,25 +2047,17 @@ 1234567890123456789012345678901234567890
      *   Operands:
      *   Stack: =>
      */ \
     macro(JSOP_DEBUGAFTERYIELD,  208, "debugafteryield",  NULL,  1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED209,     209, "unused209",    NULL,  1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED210,     210, "unused210",    NULL,  1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED211,     211, "unused211",    NULL,  1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED212,     212, "unused212",    NULL,  1,  0,  0,  JOF_BYTE) \
-    /*
-     * Pushes the nearest 'var' environment.
-     *
-     *   Category: Variables and Scopes
-     *   Type: Free Variables
-     *   Operands:
-     *   Stack: => scope
-     */ \
-    macro(JSOP_BINDVAR,       213, "bindvar",      NULL,  1,  0,  1,  JOF_BYTE) \
+    macro(JSOP_UNUSED213,     213, "unused213",    NULL,  1,  0,  0,  JOF_BYTE) \
     /*
      * Pushes the global scope onto the stack if the script doesn't have a
      * non-syntactic global scope.  Otherwise will act like JSOP_BINDNAME.
      *
      * 'nameIndex' is only used when acting like JSOP_BINDNAME.
      *   Category: Variables and Scopes
      *   Type: Free Variables
      *   Operands: uint32_t nameIndex
--- a/js/src/vm/Xdr.h
+++ b/js/src/vm/Xdr.h
@@ -28,17 +28,17 @@ namespace js {
  * this wiki page:
  *
  *  https://developer.mozilla.org/en-US/docs/SpiderMonkey/Internals/Bytecode
  */
 static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 329;
 static const uint32_t XDR_BYTECODE_VERSION =
     uint32_t(0xb973c0de - XDR_BYTECODE_VERSION_SUBTRAHEND);
 
-static_assert(JSErr_Limit == 424,
+static_assert(JSErr_Limit == 421,
               "GREETINGS, POTENTIAL SUBTRAHEND INCREMENTER! If you added or "
               "removed MSG_DEFs from js.msg, you should increment "
               "XDR_BYTECODE_VERSION_SUBTRAHEND and update this assertion's "
               "expected JSErr_Limit value.");
 
 class XDRBuffer {
   public:
     explicit XDRBuffer(JSContext* cx)