Bug 916612 - Increase maximum number of local variables to 2^28 (r=wingo)
authorLuke Wagner <luke@mozilla.com>
Thu, 16 Jan 2014 12:41:46 -0600
changeset 179857 d2eca1d564021965d05da0a4dd674175b98ccb61
parent 179856 556ddac71fd823521e8daa0b495ab7f2b292bf0a
child 179858 f9374ef0fbedf9b17e10575b23aa9ba57ec46f35
push id3343
push userffxbld
push dateMon, 17 Mar 2014 21:55:32 +0000
treeherdermozilla-beta@2f7d3415f79f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerswingo
bugs916612
milestone29.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 916612 - Increase maximum number of local variables to 2^28 (r=wingo)
js/src/frontend/BytecodeEmitter.cpp
js/src/frontend/BytecodeEmitter.h
js/src/frontend/Parser.cpp
js/src/frontend/Parser.h
js/src/jit-test/tests/basic/bug849777.js
js/src/jit-test/tests/basic/testManyVars.js
js/src/jit/BaselineCompiler.cpp
js/src/jit/BaselineFrame.h
js/src/jit/IonBuilder.cpp
js/src/jsanalyze.cpp
js/src/jsanalyze.h
js/src/jsopcode.cpp
js/src/jsopcode.h
js/src/jsopcode.tbl
js/src/jsscript.cpp
js/src/jsscript.h
js/src/jsstr.cpp
js/src/vm/Interpreter.cpp
js/src/vm/ScopeObject.cpp
js/src/vm/ScopeObject.h
js/src/vm/Stack-inl.h
js/src/vm/Stack.cpp
js/src/vm/Stack.h
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -148,29 +148,29 @@ UpdateDepth(ExclusiveContext *cx, Byteco
     JSOp op = (JSOp) *pc;
     const JSCodeSpec *cs = &js_CodeSpec[op];
 
     if (cs->format & JOF_TMPSLOT_MASK) {
         /*
          * An opcode may temporarily consume stack space during execution.
          * Account for this in maxStackDepth separately from uses/defs here.
          */
-        unsigned depth = (unsigned) bce->stackDepth +
-                      ((cs->format & JOF_TMPSLOT_MASK) >> JOF_TMPSLOT_SHIFT);
+        uint32_t depth = (uint32_t) bce->stackDepth +
+                         ((cs->format & JOF_TMPSLOT_MASK) >> JOF_TMPSLOT_SHIFT);
         if (depth > bce->maxStackDepth)
             bce->maxStackDepth = depth;
     }
 
     int nuses = StackUses(nullptr, pc);
     int ndefs = StackDefs(nullptr, pc);
 
     bce->stackDepth -= nuses;
     JS_ASSERT(bce->stackDepth >= 0);
     bce->stackDepth += ndefs;
-    if ((unsigned)bce->stackDepth > bce->maxStackDepth)
+    if ((uint32_t)bce->stackDepth > bce->maxStackDepth)
         bce->maxStackDepth = bce->stackDepth;
 }
 
 ptrdiff_t
 frontend::Emit1(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp op)
 {
     ptrdiff_t offset = EmitCheck(cx, bce, 1);
     if (offset < 0)
@@ -945,23 +945,35 @@ EmitRegExp(ExclusiveContext *cx, uint32_
 /*
  * To catch accidental misuse, EMIT_UINT16_IMM_OP/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 EMIT_UINT16_IMM_OP.
  */
 static bool
-EmitUnaliasedVarOp(ExclusiveContext *cx, JSOp op, uint16_t slot, BytecodeEmitter *bce)
+EmitUnaliasedVarOp(ExclusiveContext *cx, JSOp op, uint32_t slot, BytecodeEmitter *bce)
 {
     JS_ASSERT(JOF_OPTYPE(op) != JOF_SCOPECOORD);
-    ptrdiff_t off = EmitN(cx, bce, op, sizeof(uint16_t));
+
+    if (IsLocalOp(op)) {
+        ptrdiff_t off = EmitN(cx, bce, op, LOCALNO_LEN);
+        if (off < 0)
+            return false;
+
+        SET_LOCALNO(bce->code(off), slot);
+        return true;
+    }
+
+    JS_ASSERT(IsArgOp(op));
+    ptrdiff_t off = EmitN(cx, bce, op, ARGNO_LEN);
     if (off < 0)
         return false;
-    SET_UINT16(bce->code(off), slot);
+
+    SET_ARGNO(bce->code(off), slot);
     return true;
 }
 
 static bool
 EmitAliasedVarOp(ExclusiveContext *cx, JSOp op, ScopeCoordinate sc, BytecodeEmitter *bce)
 {
     JS_ASSERT(JOF_OPTYPE(op) == JOF_SCOPECOORD);
 
@@ -2736,17 +2748,17 @@ frontend::EmitFunctionScript(ExclusiveCo
 
     FunctionBox *funbox = bce->sc->asFunctionBox();
     if (funbox->argumentsHasLocalBinding()) {
         JS_ASSERT(bce->offset() == 0);  /* See JSScript::argumentsBytecode. */
         bce->switchToProlog();
         if (Emit1(cx, bce, JSOP_ARGUMENTS) < 0)
             return false;
         InternalBindingsHandle bindings(bce->script, &bce->script->bindings);
-        unsigned varIndex = Bindings::argumentsVarIndex(cx, bindings);
+        uint32_t varIndex = Bindings::argumentsVarIndex(cx, bindings);
         if (bce->script->varIsAliased(varIndex)) {
             ScopeCoordinate sc;
             sc.setHops(0);
             JS_ALWAYS_TRUE(LookupAliasedNameSlot(bce->script, cx->names().arguments, &sc));
             if (!EmitAliasedVarOp(cx, JSOP_SETALIASEDVAR, sc, bce))
                 return false;
         } else {
             if (!EmitUnaliasedVarOp(cx, JSOP_SETLOCAL, varIndex, bce))
@@ -3145,33 +3157,33 @@ EmitDestructuringOpsHelper(ExclusiveCont
 
         /* Elision node makes a hole in the array destructurer. */
         if (pn3->isKind(PNK_ELISION)) {
             JS_ASSERT(pn->isKind(PNK_ARRAY));
             JS_ASSERT(pn2 == pn3);
             if (Emit1(cx, bce, JSOP_POP) < 0)
                 return false;
         } else {
-            int depthBefore = bce->stackDepth;
+            int32_t depthBefore = bce->stackDepth;
             if (!EmitDestructuringLHS(cx, bce, pn3, emitOption))
                 return false;
 
             if (emitOption == PushInitialValues) {
                 /*
                  * After '[x,y]' in 'let ([[x,y], z] = o)', the stack is
                  *   | to-be-destructured-value | x | y |
                  * The goal is:
                  *   | x | y | z |
                  * so emit a pick to produce the intermediate state
                  *   | x | y | to-be-destructured-value |
                  * before destructuring z. This gives the loop invariant that
                  * the to-be-destructured-value is always on top of the stack.
                  */
                 JS_ASSERT((bce->stackDepth - bce->stackDepth) >= -1);
-                unsigned pickDistance = (unsigned)((bce->stackDepth + 1) - depthBefore);
+                uint32_t pickDistance = (uint32_t)((bce->stackDepth + 1) - depthBefore);
                 if (pickDistance > 0) {
                     if (pickDistance > UINT8_MAX) {
                         bce->reportError(pn3, JSMSG_TOO_MANY_LOCALS);
                         return false;
                     }
                     if (Emit2(cx, bce, JSOP_PICK, (jsbytecode)pickDistance) < 0)
                         return false;
                 }
@@ -3203,20 +3215,20 @@ EmitDestructuringOps(ExclusiveContext *c
     VarEmitOption emitOption = isLet ? PushInitialValues : InitializeVars;
     return EmitDestructuringOpsHelper(cx, bce, pn, emitOption);
 }
 
 static bool
 EmitGroupAssignment(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp prologOp,
                     ParseNode *lhs, ParseNode *rhs)
 {
-    unsigned depth, limit, i, nslots;
+    uint32_t depth, limit, i, nslots;
     ParseNode *pn;
 
-    depth = limit = (unsigned) bce->stackDepth;
+    depth = limit = (uint32_t) bce->stackDepth;
     for (pn = rhs->pn_head; pn; pn = pn->pn_next) {
         if (limit == JS_BIT(16)) {
             bce->reportError(rhs, JSMSG_ARRAY_INIT_TOO_BIG);
             return false;
         }
 
         /* MaybeEmitGroupAssignment won't call us if rhs is holey. */
         JS_ASSERT(!pn->isKind(PNK_ELISION));
@@ -3242,17 +3254,17 @@ EmitGroupAssignment(ExclusiveContext *cx
         } else {
             if (!EmitDestructuringLHS(cx, bce, pn, InitializeVars))
                 return false;
         }
     }
 
     nslots = limit - depth;
     EMIT_UINT16_IMM_OP(JSOP_POPN, nslots);
-    bce->stackDepth = (unsigned) depth;
+    bce->stackDepth = (uint32_t) depth;
     return true;
 }
 
 enum GroupOption { GroupIsDecl, GroupIsNotDecl };
 
 /*
  * Helper called with pop out param initialized to a JSOP_POP* opcode.  If we
  * can emit a group assignment sequence, which results in 0 stack depth delta,
@@ -4246,17 +4258,17 @@ EmitLet(ExclusiveContext *cx, BytecodeEm
     Rooted<StaticBlockObject*> blockObj(cx, &letBody->pn_objbox->object->as<StaticBlockObject>());
 
     int letHeadDepth = bce->stackDepth;
 
     if (!EmitVariables(cx, bce, varList, PushInitialValues, true))
         return false;
 
     /* Push storage for hoisted let decls (e.g. 'let (x) { let y }'). */
-    uint32_t alreadyPushed = unsigned(bce->stackDepth - letHeadDepth);
+    uint32_t alreadyPushed = bce->stackDepth - letHeadDepth;
     uint32_t blockObjCount = blockObj->slotCount();
     for (uint32_t i = alreadyPushed; i < blockObjCount; ++i) {
         if (Emit1(cx, bce, JSOP_UNDEFINED) < 0)
             return false;
     }
 
     StmtInfoBCE stmtInfo(cx);
     if (!EnterBlockScope(cx, bce, &stmtInfo, letBody->pn_objbox, 0))
@@ -5203,17 +5215,17 @@ EmitYieldStar(ExclusiveContext *cx, Byte
         return false;
     ptrdiff_t subsequentSend = -1;
     if (EmitBackPatchOp(cx, bce, &subsequentSend) < 0)           // goto subsequentSend
         return false;
     ptrdiff_t tryEnd = bce->offset();                            // tryEnd:
 
     // Catch location.
     // THROW? = 'throw' in ITER                                  // ITER
-    bce->stackDepth = (unsigned) depth;
+    bce->stackDepth = (uint32_t) depth;
     if (Emit1(cx, bce, JSOP_EXCEPTION) < 0)                      // ITER EXCEPTION
         return false;
     if (Emit1(cx, bce, JSOP_SWAP) < 0)                           // EXCEPTION ITER
         return false;
     if (Emit1(cx, bce, JSOP_DUP) < 0)                            // EXCEPTION ITER ITER
         return false;
     if (!EmitAtomOp(cx, cx->names().throw_, JSOP_STRING, bce))   // EXCEPTION ITER ITER "throw"
         return false;
@@ -5227,17 +5239,17 @@ EmitYieldStar(ExclusiveContext *cx, Byte
         return false;
     if (Emit1(cx, bce, JSOP_POP) < 0)                            // EXCEPTION
         return false;
     if (Emit1(cx, bce, JSOP_THROW) < 0)                          // throw EXCEPTION
         return false;
 
     SetJumpOffsetAt(bce, checkThrow);                            // delegate:
     // RESULT = ITER.throw(EXCEPTION)                            // EXCEPTION ITER
-    bce->stackDepth = (unsigned) depth + 1;
+    bce->stackDepth = (uint32_t) depth + 1;
     if (Emit1(cx, bce, JSOP_DUP) < 0)                            // EXCEPTION ITER ITER
         return false;
     if (Emit1(cx, bce, JSOP_DUP) < 0)                            // EXCEPTION ITER ITER ITER
         return false;
     if (!EmitAtomOp(cx, cx->names().throw_, JSOP_CALLPROP, bce)) // EXCEPTION ITER ITER THROW
         return false;
     if (Emit1(cx, bce, JSOP_SWAP) < 0)                           // EXCEPTION ITER THROW ITER
         return false;
@@ -6007,17 +6019,17 @@ EmitArrayComp(ExclusiveContext *cx, Byte
         return false;
 
     /*
      * Pass the new array's stack index to the PNK_ARRAYPUSH case via
      * bce->arrayCompDepth, then simply traverse the PNK_FOR node and
      * its kids under pn2 to generate this comprehension.
      */
     JS_ASSERT(bce->stackDepth > 0);
-    unsigned saveDepth = bce->arrayCompDepth;
+    uint32_t saveDepth = bce->arrayCompDepth;
     bce->arrayCompDepth = (uint32_t) (bce->stackDepth - 1);
     if (!EmitTree(cx, bce, pn->pn_head))
         return false;
     bce->arrayCompDepth = saveDepth;
 
     /* Emit the usual op needed for decompilation. */
     return Emit1(cx, bce, JSOP_ENDINIT) >= 0;
 }
--- a/js/src/frontend/BytecodeEmitter.h
+++ b/js/src/frontend/BytecodeEmitter.h
@@ -108,20 +108,20 @@ struct BytecodeEmitter
     StmtInfoBCE     *topStmt;       /* top of statement info stack */
     StmtInfoBCE     *topScopeStmt;  /* top lexical scope statement */
     Rooted<StaticBlockObject *> blockChain;
                                     /* compile time block scope chain */
 
     OwnedAtomIndexMapPtr atomIndices; /* literals indexed for mapping */
     unsigned        firstLine;      /* first line, for JSScript::initFromEmitter */
 
-    int             stackDepth;     /* current stack depth in script frame */
-    unsigned        maxStackDepth;  /* maximum stack depth so far */
+    int32_t         stackDepth;     /* current stack depth in script frame */
+    uint32_t        maxStackDepth;  /* maximum stack depth so far */
 
-    unsigned        arrayCompDepth; /* stack depth of array in comprehension */
+    uint32_t        arrayCompDepth; /* stack depth of array in comprehension */
 
     unsigned        emitLevel;      /* js::frontend::EmitTree recursion level */
 
     CGConstList     constList;      /* constants to be included with the script */
 
     CGObjectList    objectList;     /* list of emitted objects */
     CGObjectList    regexpList;     /* list of emitted regexp that will be
                                        cloned during execution */
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -163,17 +163,17 @@ ParseContext<FullParseHandler>::define(T
       case Definition::VAR:
         if (sc->isFunctionBox()) {
             dn->setOp(JSOP_GETLOCAL);
             dn->pn_dflags |= PND_BOUND;
             if (!dn->pn_cookie.set(ts, staticLevel, vars_.length()))
                 return false;
             if (!vars_.append(dn))
                 return false;
-            if (vars_.length() >= SLOTNO_LIMIT) {
+            if (vars_.length() >= LOCALNO_LIMIT) {
                 ts.reportError(JSMSG_TOO_MANY_LOCALS);
                 return false;
             }
         }
         if (!decls_.addUnique(name, dn))
             return false;
         break;
 
@@ -237,22 +237,22 @@ ParseContext<ParseHandler>::updateDecl(J
         JS_ASSERT(newDecl->isFreeVar());
         return;
     }
 
     JS_ASSERT(oldDecl->isBound());
     JS_ASSERT(!oldDecl->pn_cookie.isFree());
     newDecl->pn_cookie = oldDecl->pn_cookie;
     newDecl->pn_dflags |= PND_BOUND;
-    if (JOF_OPTYPE(oldDecl->getOp()) == JOF_QARG) {
+    if (IsArgOp(oldDecl->getOp())) {
         newDecl->setOp(JSOP_GETARG);
         JS_ASSERT(args_[oldDecl->pn_cookie.slot()] == oldDecl);
         args_[oldDecl->pn_cookie.slot()] = newDecl;
     } else {
-        JS_ASSERT(JOF_OPTYPE(oldDecl->getOp()) == JOF_LOCAL);
+        JS_ASSERT(IsLocalOp(oldDecl->getOp()));
         newDecl->setOp(JSOP_GETLOCAL);
         JS_ASSERT(vars_[oldDecl->pn_cookie.slot()] == oldDecl);
         vars_[oldDecl->pn_cookie.slot()] = newDecl;
     }
 }
 
 template <typename ParseHandler>
 void
@@ -261,17 +261,17 @@ ParseContext<ParseHandler>::popLetDecl(J
     JS_ASSERT(ParseHandler::getDefinitionKind(decls_.lookupFirst(atom)) == Definition::LET);
     decls_.remove(atom);
 }
 
 template <typename ParseHandler>
 static void
 AppendPackedBindings(const ParseContext<ParseHandler> *pc, const DeclVector &vec, Binding *dst)
 {
-    for (unsigned i = 0; i < vec.length(); ++i, ++dst) {
+    for (size_t i = 0; i < vec.length(); ++i, ++dst) {
         Definition *dn = vec[i];
         PropertyName *name = dn->name();
 
         BindingKind kind;
         switch (dn->kind()) {
           case Definition::VAR:
             kind = VARIABLE;
             break;
@@ -296,41 +296,49 @@ AppendPackedBindings(const ParseContext<
                         pc->decls().lookupFirst(name) == dn);
 
         *dst = Binding(name, kind, aliased);
     }
 }
 
 template <typename ParseHandler>
 bool
-ParseContext<ParseHandler>::generateFunctionBindings(ExclusiveContext *cx, LifoAlloc &alloc,
+ParseContext<ParseHandler>::generateFunctionBindings(ExclusiveContext *cx, TokenStream &ts,
+                                                     LifoAlloc &alloc,
                                                      InternalHandle<Bindings*> bindings) const
 {
     JS_ASSERT(sc->isFunctionBox());
     JS_ASSERT(args_.length() < ARGNO_LIMIT);
-    JS_ASSERT(vars_.length() < SLOTNO_LIMIT);
-
-    unsigned count = args_.length() + vars_.length();
+    JS_ASSERT(vars_.length() < LOCALNO_LIMIT);
+
+    /*
+     * Avoid pathological edge cases by explicitly limiting the total number of
+     * bindings to what will fit in a uint32_t.
+     */
+    if (UINT32_MAX - args_.length() <= vars_.length())
+        return ts.reportError(JSMSG_TOO_MANY_LOCALS);
+
+    uint32_t count = args_.length() + vars_.length();
     Binding *packedBindings = alloc.newArrayUninitialized<Binding>(count);
     if (!packedBindings) {
         js_ReportOutOfMemory(cx);
         return false;
     }
 
     AppendPackedBindings(this, args_, packedBindings);
     AppendPackedBindings(this, vars_, packedBindings + args_.length());
 
     return Bindings::initWithTemporaryStorage(cx, bindings, args_.length(), vars_.length(),
                                               packedBindings);
 }
 
 template <typename ParseHandler>
 bool
 Parser<ParseHandler>::reportHelper(ParseReportKind kind, bool strict, uint32_t offset,
-                             unsigned errorNumber, va_list args)
+                                   unsigned errorNumber, va_list args)
 {
     bool result = false;
     switch (kind) {
       case ParseError:
         result = tokenStream.reportCompileErrorNumberVA(offset, JSREPORT_ERROR, errorNumber, args);
         break;
       case ParseWarning:
         result =
@@ -885,17 +893,17 @@ Parser<FullParseHandler>::standaloneFunc
         return null();
     }
 
     if (!FoldConstants(context, &pn, this))
         return null();
 
     InternalHandle<Bindings*> funboxBindings =
         InternalHandle<Bindings*>::fromMarkedLocation(&funbox->bindings);
-    if (!funpc.generateFunctionBindings(context, alloc, funboxBindings))
+    if (!funpc.generateFunctionBindings(context, tokenStream, alloc, funboxBindings))
         return null();
 
     JS_ASSERT(fn->pn_body->isKind(PNK_ARGSBODY));
     fn->pn_body->append(pn);
     fn->pn_body->pn_pos = pn->pn_pos;
     return fn;
 }
 
@@ -1412,17 +1420,17 @@ Parser<FullParseHandler>::leaveFunction(
 
             /* Mark the outer dn as escaping. */
             outer_dn->pn_dflags |= PND_CLOSED;
         }
     }
 
     InternalHandle<Bindings*> bindings =
         InternalHandle<Bindings*>::fromMarkedLocation(&funbox->bindings);
-    return pc->generateFunctionBindings(context, alloc, bindings);
+    return pc->generateFunctionBindings(context, tokenStream, alloc, bindings);
 }
 
 template <>
 bool
 Parser<SyntaxParseHandler>::leaveFunction(Node fn, ParseContext<SyntaxParseHandler> *outerpc,
                                           FunctionSyntaxKind kind)
 {
     outerpc->blockidGen = pc->blockidGen;
@@ -2246,17 +2254,17 @@ Parser<FullParseHandler>::standaloneLazy
             Definition *dn = p.value().get<FullParseHandler>();
             if (!ConvertDefinitionToNamedLambdaUse(tokenStream, pc, funbox, dn))
                 return nullptr;
         }
     }
 
     InternalHandle<Bindings*> bindings =
         InternalHandle<Bindings*>::fromMarkedLocation(&funbox->bindings);
-    if (!pc->generateFunctionBindings(context, alloc, bindings))
+    if (!pc->generateFunctionBindings(context, tokenStream, alloc, bindings))
         return null();
 
     if (!FoldConstants(context, &pn, this))
         return null();
 
     return pn;
 }
 
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -194,17 +194,18 @@ struct ParseContext : public GenericPars
      *    the use/def nodes, but the emitter occasionally needs 'bindings' for
      *    various scope-related queries.
      *  - Bindings provide the initial js::Shape to use when creating a dynamic
      *    scope object (js::CallObject) for the function. This shape is used
      *    during dynamic name lookup.
      *  - Sometimes a script's bindings are accessed at runtime to retrieve the
      *    contents of the lexical scope (e.g., from the debugger).
      */
-    bool generateFunctionBindings(ExclusiveContext *cx, LifoAlloc &alloc,
+    bool generateFunctionBindings(ExclusiveContext *cx, TokenStream &ts,
+                                  LifoAlloc &alloc,
                                   InternalHandle<Bindings*> bindings) const;
 
   private:
     ParseContext    **parserPC;     /* this points to the Parser's active pc
                                        and holds either |this| or one of
                                        |this|'s descendents */
 
     // Value for parserPC to restore at the end. Use 'parent' instead for
deleted file mode 100644
--- a/js/src/jit-test/tests/basic/bug849777.js
+++ /dev/null
@@ -1,7 +0,0 @@
-//|jit-test| error: InternalError
-
-var LIMIT = 65535;
-for ( var i = 0, args = "" ; i < LIMIT; i++ ) {
-  args += String(i) + ( i+1 < LIMIT ? "," : "" );
-}
-var LENGTH = eval( "GetLength("+ args +")" );
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/testManyVars.js
@@ -0,0 +1,13 @@
+const MANY_VARS = Math.pow(2,17);
+
+var code = "function f1() {\n";
+code += "  var x0 = 0";
+for (var i = 1; i < MANY_VARS; i++)
+    code += ", x" + i + " = " + i;
+code += ";\n";
+for (var i = 0; i < MANY_VARS; i += 100)
+    code += "  assertEq(x" + i + ", " + i + ");\n";
+code += "  return x80000;\n";
+code += "}\n";
+eval(code);
+assertEq(f1(), 80000);
--- a/js/src/jit/BaselineCompiler.cpp
+++ b/js/src/jit/BaselineCompiler.cpp
@@ -2237,17 +2237,17 @@ bool
 BaselineCompiler::emit_JSOP_INITELEM_SETTER()
 {
     return emitInitElemGetterSetter();
 }
 
 bool
 BaselineCompiler::emit_JSOP_GETLOCAL()
 {
-    uint32_t local = GET_SLOTNO(pc);
+    uint32_t local = GET_LOCALNO(pc);
 
     if (local >= frame.nlocals()) {
         // Destructuring assignments may use GETLOCAL to access stack values.
         frame.syncStack(0);
         masm.loadValue(Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfLocal(local)), R0);
         frame.push(R0);
         return true;
     }
@@ -2264,17 +2264,17 @@ BaselineCompiler::emit_JSOP_CALLLOCAL()
 
 bool
 BaselineCompiler::emit_JSOP_SETLOCAL()
 {
     // Ensure no other StackValue refers to the old value, for instance i + (i = 3).
     // This also allows us to use R0 as scratch below.
     frame.syncStack(1);
 
-    uint32_t local = GET_SLOTNO(pc);
+    uint32_t local = GET_LOCALNO(pc);
     storeValue(frame.peek(-1), frame.addressOfLocal(local), R0);
     return true;
 }
 
 bool
 BaselineCompiler::emitFormalArgAccess(uint32_t arg, bool get)
 {
     // Fast path: the script does not use |arguments|, or is strict. In strict
@@ -2347,17 +2347,17 @@ BaselineCompiler::emitFormalArgAccess(ui
 
     masm.bind(&done);
     return true;
 }
 
 bool
 BaselineCompiler::emit_JSOP_GETARG()
 {
-    uint32_t arg = GET_SLOTNO(pc);
+    uint32_t arg = GET_ARGNO(pc);
     return emitFormalArgAccess(arg, /* get = */ true);
 }
 
 bool
 BaselineCompiler::emit_JSOP_CALLARG()
 {
     return emit_JSOP_GETARG();
 }
@@ -2366,17 +2366,17 @@ bool
 BaselineCompiler::emit_JSOP_SETARG()
 {
     // Ionmonkey can't inline functions with SETARG with magic arguments.
     if (!script->argsObjAliasesFormals() && script->argumentsAliasesFormals())
         script->setUninlineable();
 
     modifiesArguments_ = true;
 
-    uint32_t arg = GET_SLOTNO(pc);
+    uint32_t arg = GET_ARGNO(pc);
     return emitFormalArgAccess(arg, /* get = */ false);
 }
 
 bool
 BaselineCompiler::emitCall()
 {
     JS_ASSERT(IsCallPC(pc));
 
--- a/js/src/jit/BaselineFrame.h
+++ b/js/src/jit/BaselineFrame.h
@@ -144,17 +144,17 @@ class BaselineFrame
         JS_ASSERT((size % sizeof(Value)) == 0);
         return size / sizeof(Value);
     }
     Value *valueSlot(size_t slot) const {
         JS_ASSERT(slot < numValueSlots());
         return (Value *)this - (slot + 1);
     }
 
-    Value &unaliasedVar(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING) const {
+    Value &unaliasedVar(uint32_t i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING) const {
         JS_ASSERT_IF(checkAliasing, !script()->varIsAliased(i));
         JS_ASSERT(i < script()->nfixed());
         return *valueSlot(i);
     }
 
     Value &unaliasedFormal(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING) const {
         JS_ASSERT(i < numFormalArgs());
         JS_ASSERT_IF(checkAliasing, !script()->argsObjAliasesFormals() &&
@@ -164,17 +164,17 @@ class BaselineFrame
 
     Value &unaliasedActual(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING) const {
         JS_ASSERT(i < numActualArgs());
         JS_ASSERT_IF(checkAliasing, !script()->argsObjAliasesFormals());
         JS_ASSERT_IF(checkAliasing && i < numFormalArgs(), !script()->formalIsAliased(i));
         return argv()[i];
     }
 
-    Value &unaliasedLocal(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING) const {
+    Value &unaliasedLocal(uint32_t i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING) const {
 #ifdef DEBUG
         CheckLocalUnaliased(checkAliasing, script(), i);
 #endif
         return *valueSlot(i);
     }
 
     unsigned numActualArgs() const {
         return *(size_t *)(reinterpret_cast<const uint8_t *>(this) +
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -459,19 +459,19 @@ IonBuilder::analyzeNewLoopTypes(MBasicBl
         }
     }
     loopHeaders_.append(LoopHeader(start, entry));
 
     jsbytecode *last = nullptr, *earlier = nullptr;
     for (jsbytecode *pc = start; pc != end; earlier = last, last = pc, pc += GetBytecodeLength(pc)) {
         uint32_t slot;
         if (*pc == JSOP_SETLOCAL)
-            slot = info().localSlot(GET_SLOTNO(pc));
+            slot = info().localSlot(GET_LOCALNO(pc));
         else if (*pc == JSOP_SETARG)
-            slot = info().argSlotUnchecked(GET_SLOTNO(pc));
+            slot = info().argSlotUnchecked(GET_ARGNO(pc));
         else
             continue;
         if (slot >= info().firstStackSlot())
             continue;
         if (!analysis().maybeInfo(pc))
             continue;
 
         MPhi *phi = entry->getSlot(slot)->toPhi();
@@ -482,18 +482,18 @@ IonBuilder::analyzeNewLoopTypes(MBasicBl
         if (js_CodeSpec[*last].format & JOF_TYPESET) {
             types::TemporaryTypeSet *typeSet = bytecodeTypes(last);
             if (!typeSet->empty()) {
                 MIRType type = MIRTypeFromValueType(typeSet->getKnownTypeTag());
                 phi->addBackedgeType(type, typeSet);
             }
         } else if (*last == JSOP_GETLOCAL || *last == JSOP_GETARG) {
             uint32_t slot = (*last == JSOP_GETLOCAL)
-                            ? info().localSlot(GET_SLOTNO(last))
-                            : info().argSlotUnchecked(GET_SLOTNO(last));
+                            ? info().localSlot(GET_LOCALNO(last))
+                            : info().argSlotUnchecked(GET_ARGNO(last));
             if (slot < info().firstStackSlot()) {
                 MPhi *otherPhi = entry->getSlot(slot)->toPhi();
                 if (otherPhi->hasBackedgeType())
                     phi->addBackedgeType(otherPhi->type(), otherPhi->resultTypeSet());
             }
         } else {
             MIRType type = MIRType_None;
             switch (*last) {
@@ -1512,34 +1512,34 @@ IonBuilder::inspectOpcode(JSOp op)
       case JSOP_REST:
         return jsop_rest();
 
       case JSOP_GETARG:
       case JSOP_CALLARG:
         if (info().argsObjAliasesFormals()) {
             MGetArgumentsObjectArg *getArg = MGetArgumentsObjectArg::New(alloc(),
                                                                          current->argumentsObject(),
-                                                                         GET_SLOTNO(pc));
+                                                                         GET_ARGNO(pc));
             current->add(getArg);
             current->push(getArg);
         } else {
-            current->pushArg(GET_SLOTNO(pc));
+            current->pushArg(GET_ARGNO(pc));
         }
         return true;
 
       case JSOP_SETARG:
-        return jsop_setarg(GET_SLOTNO(pc));
+        return jsop_setarg(GET_ARGNO(pc));
 
       case JSOP_GETLOCAL:
       case JSOP_CALLLOCAL:
-        current->pushLocal(GET_SLOTNO(pc));
+        current->pushLocal(GET_LOCALNO(pc));
         return true;
 
       case JSOP_SETLOCAL:
-        current->setLocal(GET_SLOTNO(pc));
+        current->setLocal(GET_LOCALNO(pc));
         return true;
 
       case JSOP_POP:
         current->pop();
 
         // POP opcodes frequently appear where values are killed, e.g. after
         // SET* opcodes. Place a resume point afterwards to avoid capturing
         // the dead value in later snapshots, except in places where that
@@ -9134,17 +9134,17 @@ IonBuilder::jsop_setarg(uint32_t arg)
     MDefinition *val = current->peek(-1);
 
     // If an arguments object is in use, and it aliases formals, then all SETARGs
     // must go through the arguments object.
     if (info().argsObjAliasesFormals()) {
         if (NeedsPostBarrier(info(), val))
             current->add(MPostWriteBarrier::New(alloc(), current->argumentsObject(), val));
         current->add(MSetArgumentsObjectArg::New(alloc(), current->argumentsObject(),
-                                                 GET_SLOTNO(pc), val));
+                                                 GET_ARGNO(pc), val));
         return true;
     }
 
     // :TODO: if hasArguments() is true, and the script has a JSOP_SETARG, then
     // convert all arg accesses to go through the arguments object. (see Bug 957475)
     if (info().hasArguments())
 	return abort("NYI: arguments & setarg.");
 
--- a/js/src/jsanalyze.cpp
+++ b/js/src/jsanalyze.cpp
@@ -310,28 +310,28 @@ ScriptAnalysis::analyzeBytecode(JSContex
           case JSOP_GETLOCAL: {
             /*
              * Watch for uses of variables not known to be defined, and mark
              * them as having possible uses before definitions.  Ignore GETLOCAL
              * followed by a POP, these are generated for, e.g. 'var x;'
              */
             jsbytecode *next = pc + JSOP_GETLOCAL_LENGTH;
             if (JSOp(*next) != JSOP_POP || jumpTarget(next)) {
-                uint32_t local = GET_SLOTNO(pc);
+                uint32_t local = GET_LOCALNO(pc);
                 if (local >= script_->nfixed()) {
                     localsAliasStack_ = true;
                     break;
                 }
             }
             break;
           }
 
           case JSOP_CALLLOCAL:
           case JSOP_SETLOCAL: {
-            uint32_t local = GET_SLOTNO(pc);
+            uint32_t local = GET_LOCALNO(pc);
             if (local >= script_->nfixed()) {
                 localsAliasStack_ = true;
                 break;
             }
             break;
           }
 
           case JSOP_GETPROP:
--- a/js/src/jsanalyze.h
+++ b/js/src/jsanalyze.h
@@ -238,22 +238,22 @@ static inline uint32_t StackSlot(JSScrip
 
 static inline uint32_t GetBytecodeSlot(JSScript *script, jsbytecode *pc)
 {
     switch (JSOp(*pc)) {
 
       case JSOP_GETARG:
       case JSOP_CALLARG:
       case JSOP_SETARG:
-        return ArgSlot(GET_SLOTNO(pc));
+        return ArgSlot(GET_ARGNO(pc));
 
       case JSOP_GETLOCAL:
       case JSOP_CALLLOCAL:
       case JSOP_SETLOCAL:
-        return LocalSlot(script, GET_SLOTNO(pc));
+        return LocalSlot(script, GET_LOCALNO(pc));
 
       case JSOP_THIS:
         return ThisSlot();
 
       default:
         MOZ_ASSUME_UNREACHABLE("Bad slot opcode");
     }
 }
--- a/js/src/jsopcode.cpp
+++ b/js/src/jsopcode.cpp
@@ -1017,17 +1017,17 @@ js_Disassemble1(JSContext *cx, HandleScr
         break;
       }
 
       case JOF_QARG:
         Sprint(sp, " %u", GET_ARGNO(pc));
         break;
 
       case JOF_LOCAL:
-        Sprint(sp, " %u", GET_SLOTNO(pc));
+        Sprint(sp, " %u", GET_LOCALNO(pc));
         break;
 
       {
         int i;
 
       case JOF_UINT16:
         i = (int)GET_UINT16(pc);
         goto print_int;
@@ -1439,17 +1439,17 @@ struct ExpressionDecompiler
           localNames(nullptr),
           parser(cx, script),
           sprinter(cx)
     {}
     ~ExpressionDecompiler();
     bool init();
     bool decompilePCForStackOperand(jsbytecode *pc, int i);
     bool decompilePC(jsbytecode *pc);
-    JSAtom *getVar(unsigned slot);
+    JSAtom *getVar(uint32_t slot);
     JSAtom *getArg(unsigned slot);
     JSAtom *findLetVar(jsbytecode *pc, unsigned depth);
     JSAtom *loadAtom(jsbytecode *pc);
     bool quote(JSString *s, uint32_t quote);
     bool write(const char *s);
     bool write(JSString *str);
     bool getOutput(char **out);
 };
@@ -1506,17 +1506,17 @@ ExpressionDecompiler::decompilePC(jsbyte
       case JSOP_GETARG:
       case JSOP_CALLARG: {
         unsigned slot = GET_ARGNO(pc);
         JSAtom *atom = getArg(slot);
         return write(atom);
       }
       case JSOP_GETLOCAL:
       case JSOP_CALLLOCAL: {
-        unsigned i = GET_SLOTNO(pc);
+        uint32_t i = GET_LOCALNO(pc);
         JSAtom *atom;
         if (i >= script->nfixed()) {
             i -= script->nfixed();
             JS_ASSERT(i < unsigned(parser.stackDepthAtPC(pc)));
             atom = findLetVar(pc, i);
             if (!atom)
                 return decompilePCForStackOperand(pc, i); // Destructing temporary
         } else {
@@ -1644,17 +1644,17 @@ ExpressionDecompiler::quote(JSString *s,
 
 JSAtom *
 ExpressionDecompiler::loadAtom(jsbytecode *pc)
 {
     return script->getAtom(GET_UINT32_INDEX(pc));
 }
 
 JSAtom *
-ExpressionDecompiler::findLetVar(jsbytecode *pc, unsigned depth)
+ExpressionDecompiler::findLetVar(jsbytecode *pc, uint32_t depth)
 {
     for (JSObject *chain = script->getBlockScope(pc); chain; chain = chain->getParent()) {
         StaticBlockObject &block = chain->as<StaticBlockObject>();
         uint32_t blockDepth = block.stackDepth();
         uint32_t blockCount = block.slotCount();
         if (uint32_t(depth - blockDepth) < uint32_t(blockCount)) {
             for (Shape::Range<NoGC> r(block.lastProperty()); !r.empty(); r.popFront()) {
                 const Shape &shape = r.front();
@@ -1670,17 +1670,17 @@ JSAtom *
 ExpressionDecompiler::getArg(unsigned slot)
 {
     JS_ASSERT(fun);
     JS_ASSERT(slot < script->bindings.count());
     return (*localNames)[slot].name();
 }
 
 JSAtom *
-ExpressionDecompiler::getVar(unsigned slot)
+ExpressionDecompiler::getVar(uint32_t slot)
 {
     JS_ASSERT(fun);
     slot += fun->nargs();
     JS_ASSERT(slot < script->bindings.count());
     return (*localNames)[slot].name();
 }
 
 bool
--- a/js/src/jsopcode.h
+++ b/js/src/jsopcode.h
@@ -196,20 +196,21 @@ SET_UINT32_INDEX(jsbytecode *pc, uint32_
 #define GET_ARGC(pc)            GET_UINT16(pc)
 #define ARGC_LIMIT              UINT16_LIMIT
 
 #define GET_ARGNO(pc)           GET_UINT16(pc)
 #define SET_ARGNO(pc,argno)     SET_UINT16(pc,argno)
 #define ARGNO_LEN               2
 #define ARGNO_LIMIT             UINT16_LIMIT
 
-#define GET_SLOTNO(pc)          GET_UINT16(pc)
-#define SET_SLOTNO(pc,varno)    SET_UINT16(pc,varno)
-#define SLOTNO_LEN              2
-#define SLOTNO_LIMIT            UINT16_LIMIT
+#define GET_LOCALNO(pc)         GET_UINT24(pc)
+#define SET_LOCALNO(pc,varno)   SET_UINT24(pc,varno)
+#define LOCALNO_LEN             3
+#define LOCALNO_BITS            24
+#define LOCALNO_LIMIT           (1 << LOCALNO_BITS)
 
 /*
  * Describes the 'hops' component of a JOF_SCOPECOORD opcode.
  *
  * Note: this component is only 8 bits wide, limiting the maximum number of
  * scopes between a use and def to roughly 255. This is a pretty small limit but
  * note that SpiderMonkey's recursive descent parser can only parse about this
  * many functions before hitting the C-stack recursion limit so this shouldn't
--- a/js/src/jsopcode.tbl
+++ b/js/src/jsopcode.tbl
@@ -175,18 +175,18 @@ OPDEF(JSOP_POP,       81, "pop",        
 /* Call a function as a constructor; operand is argc. */
 OPDEF(JSOP_NEW,       82, js_new_str,   NULL,         3, -1,  1,  JOF_UINT16|JOF_INVOKE|JOF_TYPESET)
 
 OPDEF(JSOP_SPREAD,    83, "spread",     NULL,         1,  3,  2,  JOF_BYTE|JOF_ELEM|JOF_SET)
 
 /* Fast get/set ops for function arguments and local variables. */
 OPDEF(JSOP_GETARG,    84, "getarg",     NULL,         3,  0,  1,  JOF_QARG |JOF_NAME)
 OPDEF(JSOP_SETARG,    85, "setarg",     NULL,         3,  1,  1,  JOF_QARG |JOF_NAME|JOF_SET)
-OPDEF(JSOP_GETLOCAL,  86,"getlocal",    NULL,         3,  0,  1,  JOF_LOCAL|JOF_NAME)
-OPDEF(JSOP_SETLOCAL,  87,"setlocal",    NULL,         3,  1,  1,  JOF_LOCAL|JOF_NAME|JOF_SET|JOF_DETECTING)
+OPDEF(JSOP_GETLOCAL,  86,"getlocal",    NULL,         4,  0,  1,  JOF_LOCAL|JOF_NAME)
+OPDEF(JSOP_SETLOCAL,  87,"setlocal",    NULL,         4,  1,  1,  JOF_LOCAL|JOF_NAME|JOF_SET|JOF_DETECTING)
 
 /* Push unsigned 16-bit int constant. */
 OPDEF(JSOP_UINT16,    88, "uint16",     NULL,         3,  0,  1,  JOF_UINT16)
 
 /*
  * Object and array literal support.  NEWINIT takes the kind of initializer
  * (JSProto_Array or JSProto_Object).  NEWARRAY is an array initializer
  * taking the final length, which can be filled in at the start and initialized
@@ -434,28 +434,28 @@ OPDEF(JSOP_DEBUGLEAVEBLOCK, 200,"debugle
 
 OPDEF(JSOP_UNUSED201,     201,"unused201",  NULL,     1,  0,  0,  JOF_BYTE)
 
 /*
  * Generator and array comprehension support.
  */
 OPDEF(JSOP_GENERATOR,     202,"generator",   NULL,    1,  0,  0,  JOF_BYTE)
 OPDEF(JSOP_YIELD,         203,"yield",       NULL,    1,  1,  1,  JOF_BYTE)
-OPDEF(JSOP_ARRAYPUSH,     204,"arraypush",   NULL,    3,  1,  0,  JOF_LOCAL)
+OPDEF(JSOP_ARRAYPUSH,     204,"arraypush",   NULL,    4,  1,  0,  JOF_LOCAL)
 
 OPDEF(JSOP_UNUSED205,     205, "unused205",    NULL,  1,  0,  0,  JOF_BYTE)
 OPDEF(JSOP_UNUSED206,     206, "unused206",    NULL,  1,  0,  0,  JOF_BYTE)
 
 OPDEF(JSOP_UNUSED207,     207, "unused207",    NULL,  1,  0,  0,  JOF_BYTE)
 OPDEF(JSOP_UNUSED208,     208, "unused208",    NULL,  1,  0,  0,  JOF_BYTE)
 OPDEF(JSOP_UNUSED209,     209, "unused209",    NULL,  1,  0,  0,  JOF_BYTE)
 OPDEF(JSOP_UNUSED210,     210, "unused210",    NULL,  1,  0,  0,  JOF_BYTE)
 
 OPDEF(JSOP_CALLGNAME,     211, "callgname",    NULL,  5,  0,  1,  JOF_ATOM|JOF_NAME|JOF_TYPESET|JOF_GNAME)
-OPDEF(JSOP_CALLLOCAL,     212, "calllocal",    NULL,  3,  0,  1,  JOF_LOCAL|JOF_NAME)
+OPDEF(JSOP_CALLLOCAL,     212, "calllocal",    NULL,  4,  0,  1,  JOF_LOCAL|JOF_NAME)
 OPDEF(JSOP_CALLARG,       213, "callarg",      NULL,  3,  0,  1,  JOF_QARG |JOF_NAME)
 OPDEF(JSOP_BINDGNAME,     214, "bindgname",    NULL,  5,  0,  1,  JOF_ATOM|JOF_NAME|JOF_SET|JOF_GNAME)
 
 /*
  * Opcodes to hold 8-bit and 32-bit immediate integer operands.
  */
 OPDEF(JSOP_INT8,          215, "int8",         NULL,  2,  0,  1, JOF_INT8)
 OPDEF(JSOP_INT32,         216, "int32",        NULL,  5,  0,  1, JOF_INT32)
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -48,36 +48,36 @@ using namespace js;
 using namespace js::gc;
 using namespace js::frontend;
 
 using mozilla::PodCopy;
 using mozilla::PodZero;
 
 typedef Rooted<GlobalObject *> RootedGlobalObject;
 
-/* static */ unsigned
+/* static */ uint32_t
 Bindings::argumentsVarIndex(ExclusiveContext *cx, InternalBindingsHandle bindings)
 {
     HandlePropertyName arguments = cx->names().arguments;
     BindingIter bi(bindings);
     while (bi->name() != arguments)
         bi++;
     return bi.frameIndex();
 }
 
 bool
 Bindings::initWithTemporaryStorage(ExclusiveContext *cx, InternalBindingsHandle self,
-                                   unsigned numArgs, unsigned numVars,
+                                   unsigned numArgs, uint32_t numVars,
                                    Binding *bindingArray)
 {
     JS_ASSERT(!self->callObjShape_);
     JS_ASSERT(self->bindingArrayAndFlag_ == TEMPORARY_STORAGE_BIT);
     JS_ASSERT(!(uintptr_t(bindingArray) & TEMPORARY_STORAGE_BIT));
     JS_ASSERT(numArgs <= ARGC_LIMIT);
-    JS_ASSERT(numVars <= SLOTNO_LIMIT);
+    JS_ASSERT(numVars <= LOCALNO_LIMIT);
     JS_ASSERT(UINT32_MAX - numArgs >= numVars);
 
     self->bindingArrayAndFlag_ = uintptr_t(bindingArray) | TEMPORARY_STORAGE_BIT;
     self->numArgs_ = numArgs;
     self->numVars_ = numVars;
 
     /*
      * Get the initial shape to use when creating CallObjects for this script.
@@ -100,18 +100,18 @@ Bindings::initWithTemporaryStorage(Exclu
 
 #ifdef DEBUG
     HashSet<PropertyName *> added(cx);
     if (!added.init())
         return false;
 #endif
 
     BindingIter bi(self);
-    unsigned slot = CallObject::RESERVED_SLOTS;
-    for (unsigned i = 0, n = self->count(); i < n; i++, bi++) {
+    uint32_t slot = CallObject::RESERVED_SLOTS;
+    for (uint32_t i = 0, n = self->count(); i < n; i++, bi++) {
         if (!bi->aliased())
             continue;
 
 #ifdef DEBUG
         /* The caller ensures no duplicate aliased names. */
         JS_ASSERT(!added.has(bi->name()));
         if (!added.put(bi->name()))
             return false;
@@ -175,17 +175,17 @@ Bindings::clone(JSContext *cx, InternalB
 /* static */ Bindings
 GCMethods<Bindings>::initial()
 {
     return Bindings();
 }
 
 template<XDRMode mode>
 static bool
-XDRScriptBindings(XDRState<mode> *xdr, LifoAllocScope &las, unsigned numArgs, unsigned numVars,
+XDRScriptBindings(XDRState<mode> *xdr, LifoAllocScope &las, unsigned numArgs, uint32_t numVars,
                   HandleScript script)
 {
     JSContext *cx = xdr->cx();
 
     if (mode == XDR_ENCODE) {
         for (BindingIter bi(script); bi; bi++) {
             RootedAtom atom(cx, bi->name());
             if (!XDRAtom(xdr, &atom))
@@ -193,32 +193,32 @@ XDRScriptBindings(XDRState<mode> *xdr, L
         }
 
         for (BindingIter bi(script); bi; bi++) {
             uint8_t u8 = (uint8_t(bi->kind()) << 1) | uint8_t(bi->aliased());
             if (!xdr->codeUint8(&u8))
                 return false;
         }
     } else {
-        unsigned nameCount = numArgs + numVars;
+        uint32_t nameCount = numArgs + numVars;
 
         AutoValueVector atoms(cx);
         if (!atoms.resize(nameCount))
             return false;
-        for (unsigned i = 0; i < nameCount; i++) {
+        for (uint32_t i = 0; i < nameCount; i++) {
             RootedAtom atom(cx);
             if (!XDRAtom(xdr, &atom))
                 return false;
             atoms[i] = StringValue(atom);
         }
 
         Binding *bindingArray = las.alloc().newArrayUninitialized<Binding>(nameCount);
         if (!bindingArray)
             return false;
-        for (unsigned i = 0; i < nameCount; i++) {
+        for (uint32_t i = 0; i < nameCount; i++) {
             uint8_t u8;
             if (!xdr->codeUint8(&u8))
                 return false;
 
             PropertyName *name = atoms[i].toString()->asAtom().asPropertyName();
             BindingKind kind = BindingKind(u8 >> 1);
             bool aliased = bool(u8 & 1);
 
@@ -229,17 +229,17 @@ XDRScriptBindings(XDRState<mode> *xdr, L
         if (!Bindings::initWithTemporaryStorage(cx, bindings, numArgs, numVars, bindingArray))
             return false;
     }
 
     return true;
 }
 
 bool
-Bindings::bindingIsAliased(unsigned bindingIndex)
+Bindings::bindingIsAliased(uint32_t bindingIndex)
 {
     JS_ASSERT(bindingIndex < count());
     return bindingArray()[bindingIndex].aliased();
 }
 
 void
 Bindings::trace(JSTracer *trc)
 {
@@ -2028,17 +2028,17 @@ JSScript::fullyInitFromEmitter(Exclusive
     if (funbox) {
         JS_ASSERT(!bce->script->noScriptRval());
         script->isGeneratorExp_ = funbox->inGenexpLambda;
         script->setGeneratorKind(funbox->generatorKind());
         script->setFunction(funbox->function());
     }
 
     // The call to nfixed() depends on the above setFunction() call.
-    if (script->nfixed() + bce->maxStackDepth >= JS_BIT(16)) {
+    if (UINT32_MAX - script->nfixed() < bce->maxStackDepth) {
         bce->reportError(nullptr, JSMSG_NEED_DIET, "script");
         return false;
     }
     script->nslots_ = script->nfixed() + bce->maxStackDepth;
 
     for (unsigned i = 0, n = script->bindings.numArgs(); i < n; ++i) {
         if (script->formalIsAliased(i)) {
             script->funHasAnyAliasedFormal_ = true;
@@ -2969,17 +2969,17 @@ js::SetFrameArgumentsObject(JSContext *c
                             HandleScript script, JSObject *argsobj)
 {
     /*
      * Replace any optimized arguments in the frame with an explicit arguments
      * object. Note that 'arguments' may have already been overwritten.
      */
 
     InternalBindingsHandle bindings(script, &script->bindings);
-    const unsigned var = Bindings::argumentsVarIndex(cx, bindings);
+    const uint32_t var = Bindings::argumentsVarIndex(cx, bindings);
 
     if (script->varIsAliased(var)) {
         /*
          * Scan the script to find the slot in the call object that 'arguments'
          * is assigned to.
          */
         jsbytecode *pc = script->code();
         while (*pc != JSOP_ARGUMENTS)
@@ -3070,17 +3070,17 @@ JSScript::argumentsOptimizationFailed(JS
             SetFrameArgumentsObject(cx, frame, script, argsobj);
         }
     }
 
     return true;
 }
 
 bool
-JSScript::varIsAliased(unsigned varSlot)
+JSScript::varIsAliased(uint32_t varSlot)
 {
     AutoThreadSafeAccess ts(this);
     return bindings.bindingIsAliased(bindings.numArgs() + varSlot);
 }
 
 bool
 JSScript::formalIsAliased(unsigned argSlot)
 {
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -183,17 +183,17 @@ typedef InternalHandle<Bindings *> Inter
 class Bindings
 {
     friend class BindingIter;
     friend class AliasedFormalIter;
 
     HeapPtr<Shape> callObjShape_;
     uintptr_t bindingArrayAndFlag_;
     uint16_t numArgs_;
-    uint16_t numVars_;
+    uint32_t numVars_;
 
     /*
      * During parsing, bindings are allocated out of a temporary LifoAlloc.
      * After parsing, a JSScript object is created and the bindings are
      * permanently transferred to it. On error paths, the JSScript object may
      * end up with bindings that still point to the (new released) LifoAlloc
      * memory. To avoid tracing these bindings during GC, we keep track of
      * whether the bindings are temporary or permanent in the low bit of
@@ -214,40 +214,40 @@ class Bindings
 
     /*
      * Initialize a Bindings with a pointer into temporary storage.
      * bindingArray must have length numArgs+numVars. Before the temporary
      * storage is release, switchToScriptStorage must be called, providing a
      * pointer into the Binding array stored in script->data.
      */
     static bool initWithTemporaryStorage(ExclusiveContext *cx, InternalBindingsHandle self,
-                                         unsigned numArgs, unsigned numVars,
+                                         unsigned numArgs, uint32_t numVars,
                                          Binding *bindingArray);
 
     uint8_t *switchToScriptStorage(Binding *newStorage);
 
     /*
      * Clone srcScript's bindings (as part of js::CloneScript). dstScriptData
      * is the pointer to what will eventually be dstScript->data.
      */
     static bool clone(JSContext *cx, InternalBindingsHandle self, uint8_t *dstScriptData,
                       HandleScript srcScript);
 
     unsigned numArgs() const { return numArgs_; }
-    unsigned numVars() const { return numVars_; }
-    unsigned count() const { return numArgs() + numVars(); }
+    uint32_t numVars() const { return numVars_; }
+    uint32_t count() const { return numArgs() + numVars(); }
 
     /* Return the initial shape of call objects created for this scope. */
     Shape *callObjShape() const { return callObjShape_; }
 
     /* Convenience method to get the var index of 'arguments'. */
-    static unsigned argumentsVarIndex(ExclusiveContext *cx, InternalBindingsHandle);
+    static uint32_t argumentsVarIndex(ExclusiveContext *cx, InternalBindingsHandle);
 
     /* Return whether the binding at bindingIndex is aliased. */
-    bool bindingIsAliased(unsigned bindingIndex);
+    bool bindingIsAliased(uint32_t bindingIndex);
 
     /* Return whether this scope has any aliased bindings. */
     bool hasAnyAliasedBindings() const {
         if (!callObjShape_)
             return false;
 
         // Binding shapes are immutable once constructed.
         AutoThreadSafeAccess ts(callObjShape_);
@@ -622,20 +622,16 @@ class JSScript : public js::gc::Barriere
     js::jit::BaselineScript *baseline;
 
     /* Information attached by Ion for parallel mode execution */
     js::jit::IonScript *parallelIon;
 
     /* Information used to re-lazify a lazily-parsed interpreted function. */
     js::LazyScript *lazyScript;
 
-#if JS_BITS_PER_WORD == 32
-    uint32_t padding0;
-#endif
-
     /*
      * Pointer to either baseline->method()->raw() or ion->method()->raw(), or
      * nullptr if there's no Baseline or Ion script.
      */
     uint8_t *baselineOrIonRaw;
     uint8_t *baselineOrIonSkipArgCheck;
 
     // 32-bit fields.
@@ -645,16 +641,17 @@ class JSScript : public js::gc::Barriere
 
     uint32_t        lineno_;    /* base line number of script */
     uint32_t        column_;    /* base column of script, optionally set */
 
     uint32_t        mainOffset_;/* offset of main entry point from code, after
                                    predef'ing prolog */
 
     uint32_t        natoms_;    /* length of atoms array */
+    uint32_t        nslots_;    /* vars plus maximum stack depth */
 
     /* Range of characters in scriptSource which contains this script's source. */
     uint32_t        sourceStart_;
     uint32_t        sourceEnd_;
 
     uint32_t        useCount;   /* Number of times the script has been called
                                  * or has had backedges taken. When running in
                                  * ion, also increased for any inlined scripts.
@@ -672,17 +669,16 @@ class JSScript : public js::gc::Barriere
 
     uint16_t        version;    /* JS version under which script was compiled */
 
     uint16_t        funLength_; /* ES6 function length */
 
     uint16_t        nTypeSets_; /* number of type sets used in this script for
                                    dynamic type monitoring */
 
-    uint16_t        nslots_;    /* vars plus maximum stack depth */
     uint16_t        staticLevel_;/* static level for display maintenance */
 
     // Bit fields.
 
   public:
     // The kinds of the optional arrays.
     enum ArrayKind {
         CONSTS,
@@ -1435,17 +1431,17 @@ class JSScript : public js::gc::Barriere
             return false;
 
         jsbytecode *pc = code();
         if (noScriptRval() && JSOp(*pc) == JSOP_FALSE)
             ++pc;
         return JSOp(*pc) == JSOP_RETRVAL;
     }
 
-    bool varIsAliased(unsigned varSlot);
+    bool varIsAliased(uint32_t varSlot);
     bool formalIsAliased(unsigned argSlot);
     bool formalLivesInArgumentsObject(unsigned argSlot);
 
   private:
     /*
      * Recompile with or without single-stepping support, as directed
      * by stepModeEnabled().
      */
@@ -1516,30 +1512,30 @@ namespace js {
  * Iterator over a script's bindings (formals and variables).
  * The order of iteration is:
  *  - first, formal arguments, from index 0 to numArgs
  *  - next, variables, from index 0 to numVars
  */
 class BindingIter
 {
     const InternalBindingsHandle bindings_;
-    unsigned i_;
+    uint32_t i_;
 
     friend class Bindings;
 
   public:
     explicit BindingIter(const InternalBindingsHandle &bindings) : bindings_(bindings), i_(0) {}
     explicit BindingIter(const HandleScript &script) : bindings_(script, &script->bindings), i_(0) {}
 
     bool done() const { return i_ == bindings_->count(); }
     operator bool() const { return !done(); }
     void operator++(int) { JS_ASSERT(!done()); i_++; }
     BindingIter &operator++() { (*this)++; return *this; }
 
-    unsigned frameIndex() const {
+    uint32_t frameIndex() const {
         JS_ASSERT(!done());
         return i_ < bindings_->numArgs() ? i_ : i_ - bindings_->numArgs();
     }
 
     const Binding &operator*() const { JS_ASSERT(!done()); return bindings_->bindingArray()[i_]; }
     const Binding *operator->() const { JS_ASSERT(!done()); return &bindings_->bindingArray()[i_]; }
 };
 
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -2946,17 +2946,17 @@ LambdaIsGetElem(JSContext *cx, JSObject 
     ScopeCoordinate sc(pc);
     ScopeObject *scope = &fun->environment()->as<ScopeObject>();
     for (unsigned i = 0; i < sc.hops(); ++i)
         scope = &scope->enclosingScope().as<ScopeObject>();
     Value b = scope->aliasedVar(sc);
     pc += JSOP_GETALIASEDVAR_LENGTH;
 
     /* Look for 'a' to be the lambda's first argument. */
-    if (JSOp(*pc) != JSOP_GETARG || GET_SLOTNO(pc) != 0)
+    if (JSOp(*pc) != JSOP_GETARG || GET_ARGNO(pc) != 0)
         return true;
     pc += JSOP_GETARG_LENGTH;
 
     /* 'b[a]' */
     if (JSOp(*pc) != JSOP_GETELEM)
         return true;
     pc += JSOP_GETELEM_LENGTH;
 
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -2917,33 +2917,33 @@ CASE(JSOP_SETARG)
     else
         REGS.fp()->unaliasedFormal(i) = REGS.sp[-1];
 }
 END_CASE(JSOP_SETARG)
 
 CASE(JSOP_GETLOCAL)
 CASE(JSOP_CALLLOCAL)
 {
-    unsigned i = GET_SLOTNO(REGS.pc);
+    uint32_t i = GET_LOCALNO(REGS.pc);
     PUSH_COPY_SKIP_CHECK(REGS.fp()->unaliasedLocal(i));
 
     /*
      * Skip the same-compartment assertion if the local will be immediately
      * popped. We do not guarantee sync for dead locals when coming in from the
      * method JIT, and a GETLOCAL followed by POP is not considered to be
      * a use of the variable.
      */
     if (REGS.pc[JSOP_GETLOCAL_LENGTH] != JSOP_POP)
         assertSameCompartmentDebugOnly(cx, REGS.sp[-1]);
 }
 END_CASE(JSOP_GETLOCAL)
 
 CASE(JSOP_SETLOCAL)
 {
-    unsigned i = GET_SLOTNO(REGS.pc);
+    uint32_t i = GET_LOCALNO(REGS.pc);
     REGS.fp()->unaliasedLocal(i) = REGS.sp[-1];
 }
 END_CASE(JSOP_SETLOCAL)
 
 CASE(JSOP_DEFCONST)
 CASE(JSOP_DEFVAR)
 {
     /* ES5 10.5 step 8 (with subsequent errata). */
@@ -3390,17 +3390,17 @@ CASE(JSOP_YIELD)
     REGS.fp()->setReturnValue(REGS.sp[-1]);
     REGS.fp()->setYielding();
     REGS.pc += JSOP_YIELD_LENGTH;
     interpReturnOK = true;
     goto exit;
 
 CASE(JSOP_ARRAYPUSH)
 {
-    uint32_t slot = GET_UINT16(REGS.pc);
+    uint32_t slot = GET_LOCALNO(REGS.pc);
     JS_ASSERT(script->nfixed() <= slot);
     JS_ASSERT(slot < script->nslots());
     RootedObject &obj = rootObject0;
     obj = &REGS.fp()->unaliasedLocal(slot).toObject();
     if (!js_NewbornArrayPush(cx, obj, REGS.sp[-1]))
         goto error;
     REGS.sp--;
 }
--- a/js/src/vm/ScopeObject.cpp
+++ b/js/src/vm/ScopeObject.cpp
@@ -1144,17 +1144,17 @@ class DebugScopeProxy : public BaseProxy
             Bindings &bindings = script->bindings;
             BindingIter bi(script);
             while (bi && NameToId(bi->name()) != id)
                 bi++;
             if (!bi)
                 return false;
 
             if (bi->kind() == VARIABLE || bi->kind() == CONSTANT) {
-                unsigned i = bi.frameIndex();
+                uint32_t i = bi.frameIndex();
                 if (script->varIsAliased(i))
                     return false;
 
                 if (maybeLiveScope) {
                     AbstractFramePtr frame = maybeLiveScope->frame();
                     if (action == GET)
                         vp.set(frame.unaliasedVar(i));
                     else
@@ -1215,17 +1215,17 @@ class DebugScopeProxy : public BaseProxy
 
             unsigned i = shape->shortid();
             if (block->staticBlock().isAliased(i))
                 return false;
 
             if (maybeLiveScope) {
                 AbstractFramePtr frame = maybeLiveScope->frame();
                 JSScript *script = frame.script();
-                unsigned local = block->slotToLocalIndex(script->bindings, shape->slot());
+                uint32_t local = block->slotToLocalIndex(script->bindings, shape->slot());
                 if (action == GET)
                     vp.set(frame.unaliasedLocal(local));
                 else
                     frame.unaliasedLocal(local) = vp;
                 JS_ASSERT(analyze::LocalSlot(script, local) >= analyze::TotalSlots(script));
             } else {
                 if (action == GET)
                     vp.set(block->var(i, DONT_CHECK_ALIASING));
--- a/js/src/vm/ScopeObject.h
+++ b/js/src/vm/ScopeObject.h
@@ -351,22 +351,22 @@ class BlockObject : public NestedScopeOb
         return propertyCountForCompilation();
     }
 
     /*
      * Return the local corresponding to the ith binding where i is in the
      * range [0, slotCount()) and the return local index is in the range
      * [script->nfixed, script->nfixed + script->nslots).
      */
-    unsigned slotToLocalIndex(const Bindings &bindings, unsigned slot) {
+    uint32_t slotToLocalIndex(const Bindings &bindings, uint32_t slot) {
         JS_ASSERT(slot < RESERVED_SLOTS + slotCount());
         return bindings.numVars() + stackDepth() + (slot - RESERVED_SLOTS);
     }
 
-    unsigned localIndexToSlot(const Bindings &bindings, uint32_t i) {
+    uint32_t localIndexToSlot(const Bindings &bindings, uint32_t i) {
         return RESERVED_SLOTS + (i - (bindings.numVars() + stackDepth()));
     }
 
   protected:
     /* Blocks contain an object slot for each slot i: 0 <= i < slotCount. */
     const Value &slotValue(unsigned i) {
         return getSlotRef(RESERVED_SLOTS + i);
     }
--- a/js/src/vm/Stack-inl.h
+++ b/js/src/vm/Stack-inl.h
@@ -92,25 +92,25 @@ StackFrame::initCallFrame(JSContext *cx,
 
 inline void
 StackFrame::initVarsToUndefined()
 {
     SetValueRangeToUndefined(slots(), script()->nfixed());
 }
 
 inline Value &
-StackFrame::unaliasedVar(unsigned i, MaybeCheckAliasing checkAliasing)
+StackFrame::unaliasedVar(uint32_t i, MaybeCheckAliasing checkAliasing)
 {
     JS_ASSERT_IF(checkAliasing, !script()->varIsAliased(i));
     JS_ASSERT(i < script()->nfixed());
     return slots()[i];
 }
 
 inline Value &
-StackFrame::unaliasedLocal(unsigned i, MaybeCheckAliasing checkAliasing)
+StackFrame::unaliasedLocal(uint32_t i, MaybeCheckAliasing checkAliasing)
 {
 #ifdef DEBUG
     CheckLocalUnaliased(checkAliasing, script(), i);
 #endif
     return slots()[i];
 }
 
 inline Value &
@@ -464,29 +464,29 @@ AbstractFramePtr::numFormalArgs() const
 #ifdef JS_ION
     return asBaselineFrame()->numFormalArgs();
 #else
     MOZ_ASSUME_UNREACHABLE("Invalid frame");
 #endif
 }
 
 inline Value &
-AbstractFramePtr::unaliasedVar(unsigned i, MaybeCheckAliasing checkAliasing)
+AbstractFramePtr::unaliasedVar(uint32_t i, MaybeCheckAliasing checkAliasing)
 {
     if (isStackFrame())
         return asStackFrame()->unaliasedVar(i, checkAliasing);
 #ifdef JS_ION
     return asBaselineFrame()->unaliasedVar(i, checkAliasing);
 #else
     MOZ_ASSUME_UNREACHABLE("Invalid frame");
 #endif
 }
 
 inline Value &
-AbstractFramePtr::unaliasedLocal(unsigned i, MaybeCheckAliasing checkAliasing)
+AbstractFramePtr::unaliasedLocal(uint32_t i, MaybeCheckAliasing checkAliasing)
 {
     if (isStackFrame())
         return asStackFrame()->unaliasedLocal(i, checkAliasing);
 #ifdef JS_ION
     return asBaselineFrame()->unaliasedLocal(i, checkAliasing);
 #else
     MOZ_ASSUME_UNREACHABLE("Invalid frame");
 #endif
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -1252,17 +1252,17 @@ AbstractFramePtr::hasPushedSPSFrame() co
     return asBaselineFrame()->hasPushedSPSFrame();
 #else
     MOZ_ASSUME_UNREACHABLE("Invalid frame");
 #endif
 }
 
 #ifdef DEBUG
 void
-js::CheckLocalUnaliased(MaybeCheckAliasing checkAliasing, JSScript *script, unsigned i)
+js::CheckLocalUnaliased(MaybeCheckAliasing checkAliasing, JSScript *script, uint32_t i)
 {
     if (!checkAliasing)
         return;
 
     JS_ASSERT(i < script->nslots());
     if (i < script->nfixed()) {
         JS_ASSERT(!script->varIsAliased(i));
     } else {
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -70,17 +70,17 @@ struct ScopeCoordinate;
 // is a local var of js::Interpret.
 
 enum MaybeCheckAliasing { CHECK_ALIASING = true, DONT_CHECK_ALIASING = false };
 
 /*****************************************************************************/
 
 #ifdef DEBUG
 extern void
-CheckLocalUnaliased(MaybeCheckAliasing checkAliasing, JSScript *script, unsigned i);
+CheckLocalUnaliased(MaybeCheckAliasing checkAliasing, JSScript *script, uint32_t i);
 #endif
 
 namespace jit {
     class BaselineFrame;
 }
 
 /*
  * Pointer to either a ScriptFrameIter::Data, a StackFrame, or a baseline JIT
@@ -206,18 +206,18 @@ class AbstractFramePtr
     inline bool hasArgs() const;
     inline bool hasArgsObj() const;
     inline ArgumentsObject &argsObj() const;
     inline void initArgsObj(ArgumentsObject &argsobj) const;
     inline bool useNewType() const;
 
     inline bool copyRawFrameSlots(AutoValueVector *vec) const;
 
-    inline Value &unaliasedVar(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING);
-    inline Value &unaliasedLocal(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING);
+    inline Value &unaliasedVar(uint32_t i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING);
+    inline Value &unaliasedLocal(uint32_t i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING);
     inline Value &unaliasedFormal(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING);
     inline Value &unaliasedActual(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING);
 
     inline bool prevUpToDate() const;
     inline void setPrevUpToDate() const;
 
     JSObject *evalPrevScopeChain(JSContext *cx) const;
 
@@ -519,18 +519,18 @@ class StackFrame
      * that value is the slot of an activation object (scope or arguments).
      * Currently, all variables are given slots in *both* the stack frame and
      * heap objects, even though, as just described, only one should ever be
      * accessed. Thus, it is up to the code performing an access to access the
      * correct value. These functions assert that accesses to stack values are
      * unaliased. For more about canonical values locations.
      */
 
-    inline Value &unaliasedVar(unsigned i, MaybeCheckAliasing = CHECK_ALIASING);
-    inline Value &unaliasedLocal(unsigned i, MaybeCheckAliasing = CHECK_ALIASING);
+    inline Value &unaliasedVar(uint32_t i, MaybeCheckAliasing = CHECK_ALIASING);
+    inline Value &unaliasedLocal(uint32_t i, MaybeCheckAliasing = CHECK_ALIASING);
 
     bool hasArgs() const { return isNonEvalFunctionFrame(); }
     inline Value &unaliasedFormal(unsigned i, MaybeCheckAliasing = CHECK_ALIASING);
     inline Value &unaliasedActual(unsigned i, MaybeCheckAliasing = CHECK_ALIASING);
     template <class Op> inline void forEachUnaliasedActual(Op op);
 
     bool copyRawFrameSlots(AutoValueVector *v);