Backout bug 1071646, bug 1231758 on CLOSED TREE for breaking the web. (r=woe, a=backout)
authorShu-yu Guo <shu@rfrn.org>
Mon, 14 Dec 2015 13:28:14 -0800
changeset 310438 7fdc4b055faa0e39d40eaec269e750a4ef310dae
parent 310437 e2031358e2a6d6d686b7a6b592d07cfb874bacae
child 310439 0489aa6d8fb64e9ddaa097c32278f1fbb03a7272
push id5513
push userraliiev@mozilla.com
push dateMon, 25 Jan 2016 13:55:34 +0000
treeherdermozilla-beta@5ee97dd05b5c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerswoe, backout
bugs1071646, 1231758
milestone45.0a2
Backout bug 1071646, bug 1231758 on CLOSED TREE for breaking the web. (r=woe, a=backout)
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)