Remove unsound global optimizations (bug 618007, r=brendan).
authorDavid Anderson <danderson@mozilla.com>
Sat, 08 Jan 2011 16:27:48 -0800
changeset 60526 f497fca35415432c6c6277456cfc809f1de14145
parent 60525 96203bfc94f2090fe2b51cce9d25f4fa7f389bdb
child 60527 558d826c33bfb472d96704e09ff12978f3199d29
push idunknown
push userunknown
push dateunknown
reviewersbrendan
bugs618007
milestone2.0b9pre
Remove unsound global optimizations (bug 618007, r=brendan).
js/src/jit-test/tests/jaeger/bug563000/simple-trap-1.js
js/src/jit-test/tests/jaeger/bug563000/simple-trap-2.js
js/src/jit-test/tests/jaeger/bug618007.js
js/src/jit-test/tests/jaeger/testForOps.js
js/src/jsemit.cpp
js/src/jsinterp.cpp
js/src/jsopcode.cpp
js/src/jsopcode.tbl
js/src/jsparse.cpp
js/src/jsparse.h
js/src/jstracer.cpp
js/src/jsxdrapi.h
js/src/methodjit/Compiler.cpp
js/src/methodjit/Compiler.h
js/src/methodjit/FastOps.cpp
js/src/methodjit/StubCalls.cpp
js/src/methodjit/StubCalls.h
js/src/methodjit/StubCompiler.cpp
js/src/methodjit/StubCompiler.h
--- a/js/src/jit-test/tests/jaeger/bug563000/simple-trap-1.js
+++ b/js/src/jit-test/tests/jaeger/bug563000/simple-trap-1.js
@@ -1,9 +1,9 @@
 setDebug(true);
 var x = "failure";
 function main() { x = "success"; }
 
 /* The JSOP_STOP in a. */
-trap(main, 8, "");
+trap(main, 11, "");
 main();
 
 assertEq(x, "success");
--- a/js/src/jit-test/tests/jaeger/bug563000/simple-trap-2.js
+++ b/js/src/jit-test/tests/jaeger/bug563000/simple-trap-2.js
@@ -1,10 +1,10 @@
 setDebug(true);
 var x = "notset";
 function main() { x = "failure"; }
 function success() { x = "success"; }
 
 /* The JSOP_STOP in a. */
-trap(main, 7, "success()");
+trap(main, 10, "success()");
 main();
 
 assertEq(x, "success");
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/jaeger/bug618007.js
@@ -0,0 +1,31 @@
+var appendToActual = function(s) {
+    actual += s + ',';
+}
+
+for(var z=0; z < 3; z++) {
+    function ff() {
+    }
+    ff();
+
+    // jit-test/tests/closures/setname-closure.js
+    actual = '';
+    expected = '2,4,8,16,32,undefined,64,128,256,512,1024,undefined,2048,4096,8192,16384,32768,undefined,65536,131072,262144,524288,1048576,undefined,2097152,4194304,8388608,16777216,33554432,undefined,';
+
+    var f = function() {
+	var p = 1;
+	function g() {
+	    for (var i = 0; i < 5; ++i) {
+		p = p * 2;
+		appendToActual(p);
+	    }
+	}
+	return g;
+    }
+    var g = f();
+    for (var i = 0; i < 5; ++i) {
+	g();
+	appendToActual();
+    }
+    assertEq(actual, expected);
+}
+
--- a/js/src/jit-test/tests/jaeger/testForOps.js
+++ b/js/src/jit-test/tests/jaeger/testForOps.js
@@ -15,16 +15,24 @@ function forName(obj) {
     assertJit();
     eval('');
     var r = { };
     for (x in obj)
         r[x] = obj[x];
     return r;
 }
 
+function forGlobalName(obj) {
+    assertJit();
+    var r = { };
+    for (x in obj)
+        r[x] = obj[x];
+    return r;
+}
+
 function forProp(obj) {
     assertJit();
     var r = { };
     var c = { };
     for (c.x in obj)
         r[c.x] = obj[c.x];
     return r;
 }
@@ -51,13 +59,14 @@ function forArg(obj, x) {
     var r = { };
     for (x in obj)
         r[x] = obj[x];
     return r;
 }
 
 var obj = { a: 1, b: "bee", c: "crab", d: 12 };
 assertObjectsEqual(obj, forName(obj));
+assertObjectsEqual(obj, forGlobalName(obj));
 assertObjectsEqual(obj, forProp(obj));
 assertObjectsEqual(obj, forElem(obj, "v"));
 assertObjectsEqual(obj, forLocal(obj));
 assertObjectsEqual(obj, forArg(obj));
 
--- a/js/src/jsemit.cpp
+++ b/js/src/jsemit.cpp
@@ -1995,37 +1995,105 @@ EmitLeaveBlock(JSContext *cx, JSCodeGene
  *   }
  *   foo();
  */
 static bool
 TryConvertToGname(JSCodeGenerator *cg, JSParseNode *pn, JSOp *op)
 {
     if (cg->compileAndGo() && 
         cg->compiler()->globalScope->globalObj &&
+        !cg->mightAliasLocals() &&
         !pn->isDeoptimized() &&
         !(cg->flags & TCF_STRICT_MODE_CODE)) { 
         switch (*op) {
           case JSOP_NAME:     *op = JSOP_GETGNAME; break;
           case JSOP_SETNAME:  *op = JSOP_SETGNAME; break;
           case JSOP_INCNAME:  *op = JSOP_INCGNAME; break;
           case JSOP_NAMEINC:  *op = JSOP_GNAMEINC; break;
           case JSOP_DECNAME:  *op = JSOP_DECGNAME; break;
           case JSOP_NAMEDEC:  *op = JSOP_GNAMEDEC; break;
+          case JSOP_FORNAME:  *op = JSOP_FORGNAME; break;
           case JSOP_SETCONST:
           case JSOP_DELNAME:
-          case JSOP_FORNAME:
             /* Not supported. */
             return false;
           default: JS_NOT_REACHED("gname");
         }
         return true;
     }
     return false;
 }
 
+// Binds a global, given a |dn| that is known to have the PND_GVAR bit, and a pn
+// that is |dn| or whose definition is |dn|. |pn->pn_cookie| is an outparam
+// that will be free (meaning no binding), or a slot number.
+static bool
+BindKnownGlobal(JSContext *cx, JSCodeGenerator *cg, JSParseNode *dn, JSParseNode *pn, JSAtom *atom)
+{
+    // Cookie is an outparam; make sure caller knew to clear it.
+    JS_ASSERT(pn->pn_cookie.isFree());
+
+    if (cg->mightAliasLocals())
+        return true;
+
+    GlobalScope *globalScope = cg->compiler()->globalScope;
+
+    uint32 index;
+    if (dn->pn_cookie.isFree()) {
+        // The definition wasn't bound, so find its atom's index in the
+        // mapping of defined globals.
+        JSAtomListElement *ale = globalScope->names.lookup(atom);
+        index = ALE_INDEX(ale);
+    } else {
+        JSCodeGenerator *globalcg = globalScope->cg;
+
+        // If the definition is bound, and we're in the same cg, we can re-use
+        // its cookie.
+        if (globalcg == cg) {
+            pn->pn_cookie = dn->pn_cookie;
+            pn->pn_dflags |= PND_BOUND;
+            return true;
+        }
+
+        // Otherwise, find the atom's index by using the originating cg's
+        // global use table.
+        index = globalcg->globalUses[dn->pn_cookie.asInteger()].slot;
+    }
+
+    if (!cg->addGlobalUse(atom, index, &pn->pn_cookie))
+        return false;
+
+    if (!pn->pn_cookie.isFree())
+        pn->pn_dflags |= PND_BOUND;
+
+    return true;
+}
+
+// See BindKnownGlobal()'s comment.
+static bool
+BindGlobal(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn, JSAtom *atom)
+{
+    pn->pn_cookie.makeFree();
+
+    JSDefinition *dn;
+    if (pn->pn_used) {
+        dn = pn->pn_lexdef;
+    } else {
+        if (!pn->pn_defn)
+            return true;
+        dn = (JSDefinition *)pn;
+    }
+
+    // Only optimize for defined globals.
+    if (!dn->isGlobal())
+        return true;
+
+    return BindKnownGlobal(cx, cg, dn, pn, atom);
+}
+
 /*
  * BindNameToSlot attempts to optimize name gets and sets to stack slot loads
  * and stores, given the compile-time information in cg and a TOK_NAME node pn.
  * It returns false on error, true on success.
  *
  * The caller can inspect pn->pn_cookie for FREE_UPVAR_COOKIE to tell whether
  * optimization occurred, in which case BindNameToSlot also updated pn->pn_op.
  * If pn->pn_cookie is still FREE_UPVAR_COOKIE on return, pn->pn_op still may
@@ -2106,16 +2174,40 @@ BindNameToSlot(JSContext *cx, JSCodeGene
             return JS_TRUE;
         }
         break;
       default:
         if (pn->isConst())
             pn->pn_op = op = JSOP_NAME;
     }
 
+    if (dn->isGlobal()) {
+        if (op == JSOP_NAME) {
+            /*
+             * If the definition is a defined global, not potentially aliased
+             * by a local variable, and not mutating the variable, try and
+             * optimize to a fast, unguarded global access.
+             */
+            if (!BindKnownGlobal(cx, cg, dn, pn, atom))
+                return JS_FALSE;
+            if (!pn->pn_cookie.isFree()) {
+                pn->pn_op = JSOP_GETGLOBAL;
+                return JS_TRUE;
+            }
+        }
+
+        /*
+         * The locally stored cookie here should really come from |pn|, not
+         * |dn|. For example, we could have a SETGNAME op's lexdef be a
+         * GETGLOBAL op, and their cookies have very different meanings. As
+         * a workaround, just make the cookie free.
+         */
+        cookie.makeFree();
+    }
+
     if (cookie.isFree()) {
         JSStackFrame *caller = cg->parser->callerFrame;
         if (caller) {
             JS_ASSERT(cg->compileAndGo());
 
             /*
              * Don't generate upvars on the left side of a for loop. See
              * bug 470758.
@@ -2155,56 +2247,16 @@ BindNameToSlot(JSContext *cx, JSCodeGene
             return JS_FALSE;
 
         pn->pn_op = op;
         pn->pn_dflags |= PND_BOUND;
 
         return JS_TRUE;
     }
 
-    if (dn->pn_dflags & PND_GVAR) {
-        /*
-         * JSOP_DEFFUN could introduce a shadowing definition, so if it
-         * is present, we can't optimize to JSOP_GETGLOBAL.
-         */
-        if (cg->mightAliasLocals())
-            return JS_TRUE;
-
-        switch (op) {
-          case JSOP_NAME:     op = JSOP_GETGLOBAL; break;
-          case JSOP_SETNAME:  op = JSOP_SETGLOBAL; break;
-          case JSOP_INCNAME:  op = JSOP_INCGLOBAL; break;
-          case JSOP_NAMEINC:  op = JSOP_GLOBALINC; break;
-          case JSOP_DECNAME:  op = JSOP_DECGLOBAL; break;
-          case JSOP_NAMEDEC:  op = JSOP_GLOBALDEC; break;
-          case JSOP_FORNAME:  op = JSOP_FORGLOBAL; break;
-          case JSOP_SETCONST:
-          case JSOP_DELNAME:
-            /* Not supported. */
-            return JS_TRUE;
-          default: JS_NOT_REACHED("gvar");
-        }
-
-        JSCodeGenerator *globalCg = cg->compiler()->globalScope->cg;
-        if (globalCg != cg) {
-            uint32 slot = globalCg->globalUses[cookie.asInteger()].slot;
-
-            /* Fall back to NAME if we can't add a slot. */
-            if (!cg->addGlobalUse(atom, slot, &cookie))
-                return JS_FALSE;
-
-            if (cookie.isFree())
-                return JS_TRUE;
-        }
-        pn->pn_op = op;
-        pn->pn_cookie.set(cookie);
-        pn->pn_dflags |= PND_BOUND;
-        return JS_TRUE;
-    }
-
     uint16 level = cookie.level();
     JS_ASSERT(cg->staticLevel >= level);
 
     const uintN skip = cg->staticLevel - level;
     if (skip != 0) {
         JS_ASSERT(cg->inFunction());
         JS_ASSERT_IF(cookie.slot() != UpvarCookie::CALLEE_SLOT, cg->lexdeps.lookup(atom));
         JS_ASSERT(JOF_OPTYPE(op) == JOF_ATOM);
@@ -3670,17 +3722,17 @@ MaybeEmitVarDecl(JSContext *cx, JSCodeGe
         ale = cg->atomList.add(cg->parser, pn->pn_atom);
         if (!ale)
             return JS_FALSE;
         atomIndex = ALE_INDEX(ale);
     }
 
     if (JOF_OPTYPE(pn->pn_op) == JOF_ATOM &&
         (!cg->inFunction() || (cg->flags & TCF_FUN_HEAVYWEIGHT)) &&
-        js_CodeSpec[pn->pn_op].type() != JOF_GLOBAL)
+        !(pn->pn_dflags & PND_GVAR))
     {
         CG_SWITCH_TO_PROLOG(cg);
         if (!UpdateLineNumberNotes(cx, cg, pn->pn_pos.begin.lineno))
             return JS_FALSE;
         EMIT_INDEX_OP(prologOp, atomIndex);
         CG_SWITCH_TO_MAIN(cg);
     }
 
@@ -3792,17 +3844,16 @@ EmitDestructuringLHS(JSContext *cx, JSCo
           case JSOP_SETLOCAL:
           {
             jsuint slot = pn->pn_cookie.asInteger();
             EMIT_UINT16_IMM_OP(JSOP_SETLOCALPOP, slot);
             break;
           }
 
           case JSOP_SETARG:
-          case JSOP_SETGLOBAL:
           {
             jsuint slot = pn->pn_cookie.asInteger();
             EMIT_UINT16_IMM_OP(PN_OP(pn), slot);
             if (js_Emit1(cx, cg, JSOP_POP) < 0)
                 return JS_FALSE;
             break;
           }
 
@@ -4612,16 +4663,18 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
          * names in the variable object before the already-generated main code
          * is executed. This extra work for top-level scripts is not necessary
          * when we emit the code for a function. It is fully parsed prior to
          * invocation of the emitter and calls to js_EmitTree for function
          * definitions can be scheduled before generating the rest of code.
          */
         if (!cg->inFunction()) {
             JS_ASSERT(!cg->topStmt);
+            if (!BindGlobal(cx, cg, pn, fun->atom))
+                return false;
             if (pn->pn_cookie.isFree()) {
                 CG_SWITCH_TO_PROLOG(cg);
                 op = FUN_FLAT_CLOSURE(fun) ? JSOP_DEFFUN_FC : JSOP_DEFFUN;
                 EMIT_INDEX_OP(op, index);
 
                 /* Make blockChain determination quicker. */
                 if (EmitBlockChain(cx, cg) < 0)
                     return JS_FALSE;
@@ -4977,16 +5030,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
                     goto destructuring_for;
                 }
 #else
                 JS_ASSERT(pn3->pn_type == TOK_NAME);
 #endif
                 /* FALL THROUGH */
 
               case TOK_NAME:
+              {
                 /*
                  * Always annotate JSOP_FORLOCAL if given input of the form
                  * 'for (let x in * o)' -- the decompiler must not hoist the
                  * 'let x' out of the loop head, or x will be bound in the
                  * wrong scope.  Likewise, but in this case only for the sake
                  * of higher decompilation fidelity only, do not hoist 'var x'
                  * when given 'for (var x in o)'.
                  */
@@ -4996,46 +5050,56 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
 #endif
                      (type == TOK_VAR && !pn3->maybeExpr())) &&
                     js_NewSrcNote2(cx, cg, SRC_DECL,
                                    (type == TOK_VAR)
                                    ? SRC_DECL_VAR
                                    : SRC_DECL_LET) < 0) {
                     return JS_FALSE;
                 }
-                if (!pn3->pn_cookie.isFree()) {
+                UpvarCookie cookie = pn3->pn_cookie;
+                if (!cookie.isFree()) {
                     op = PN_OP(pn3);
                     switch (op) {
-                      case JSOP_GETARG:   /* FALL THROUGH */
-                      case JSOP_SETARG:   op = JSOP_FORARG; break;
-                      case JSOP_GETLOCAL: /* FALL THROUGH */
-                      case JSOP_SETLOCAL: op = JSOP_FORLOCAL; break;
-                      case JSOP_GETGLOBAL: /* FALL THROUGH */
-                      case JSOP_SETGLOBAL: op = JSOP_FORGLOBAL; break;
-                      default:            JS_ASSERT(0);
+                      case JSOP_GETARG:
+                      case JSOP_SETARG:
+                        op = JSOP_FORARG;
+                        break;
+                      case JSOP_GETLOCAL:
+                      case JSOP_SETLOCAL:
+                        op = JSOP_FORLOCAL;
+                        break;
+                      case JSOP_GETGLOBAL:
+                        op = JSOP_FORGNAME;
+                        cookie.makeFree();
+                        break;
+                      default:
+                        JS_NOT_REACHED("unexpected opcode");
                     }
                 } else {
                     pn3->pn_op = JSOP_FORNAME;
                     if (!BindNameToSlot(cx, cg, pn3))
                         return JS_FALSE;
                     op = PN_OP(pn3);
+                    cookie = pn3->pn_cookie;
                 }
                 if (pn3->isConst()) {
                     ReportCompileErrorNumber(cx, CG_TS(cg), pn3, JSREPORT_ERROR,
                                              JSMSG_BAD_FOR_LEFTSIDE);
                     return JS_FALSE;
                 }
-                if (!pn3->pn_cookie.isFree()) {
-                    atomIndex = (jsatomid) pn3->pn_cookie.asInteger();
+                if (!cookie.isFree()) {
+                    atomIndex = (jsatomid) cookie.asInteger();
                     EMIT_UINT16_IMM_OP(op, atomIndex);
                 } else {
                     if (!EmitAtomOp(cx, pn3, op, cg))
                         return JS_FALSE;
                 }
                 break;
+              }
 
               case TOK_DOT:
                 /*
                  * 'for (o.p in q)' can use JSOP_FORPROP only if evaluating 'o'
                  * has no side effects.
                  */
                 useful = JS_FALSE;
                 if (!CheckSideEffects(cx, cg, pn3->expr(), &useful))
@@ -6048,22 +6112,25 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
                             return JS_FALSE;
                     } else {
                         EMIT_INDEX_OP(PN_OP(pn2), atomIndex);
                     }
                 } else if (PN_OP(pn2) == JSOP_SETNAME) {
                     if (js_Emit1(cx, cg, JSOP_DUP) < 0)
                         return JS_FALSE;
                     EMIT_INDEX_OP(JSOP_GETXPROP, atomIndex);
+                } else if (PN_OP(pn2) == JSOP_SETGNAME) {
+                    if (!BindGlobal(cx, cg, pn2, pn2->pn_atom))
+                        return JS_FALSE;
+                    if (pn2->pn_cookie.isFree())
+                        EmitAtomOp(cx, pn2, JSOP_GETGNAME, cg);
+                    else
+                        EMIT_UINT16_IMM_OP(JSOP_GETGLOBAL, pn2->pn_cookie.asInteger());
                 } else {
-                    EMIT_UINT16_IMM_OP((PN_OP(pn2) == JSOP_SETGNAME)
-                                       ? JSOP_GETGNAME
-                                       : (PN_OP(pn2) == JSOP_SETGLOBAL)
-                                       ? JSOP_GETGLOBAL
-                                       : (PN_OP(pn2) == JSOP_SETARG)
+                    EMIT_UINT16_IMM_OP((PN_OP(pn2) == JSOP_SETARG)
                                        ? JSOP_GETARG
                                        : JSOP_GETLOCAL,
                                        atomIndex);
                 }
                 break;
               case TOK_DOT:
                 if (js_Emit1(cx, cg, JSOP_DUP) < 0)
                     return JS_FALSE;
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -3149,16 +3149,17 @@ BEGIN_CASE(JSOP_FORLOCAL)
     JS_ASSERT(slot < regs.fp->numSlots());
     JS_ASSERT(regs.sp[-1].isObject());
     if (!IteratorNext(cx, &regs.sp[-1].toObject(), &regs.fp->slots()[slot]))
         goto error;
 }
 END_CASE(JSOP_FORLOCAL)
 
 BEGIN_CASE(JSOP_FORNAME)
+BEGIN_CASE(JSOP_FORGNAME)
 {
     JS_ASSERT(regs.sp - 1 >= regs.fp->base());
     JSAtom *atom;
     LOAD_ATOM(0, atom);
     jsid id = ATOM_TO_JSID(atom);
     JSObject *obj, *obj2;
     JSProperty *prop;
     if (!js_FindProperty(cx, id, &obj, &obj2, &prop))
@@ -4038,49 +4039,30 @@ do_incop:
     }
     len = cs->length;
     DO_NEXT_OP(len);
 }
 }
 
 {
     int incr, incr2;
+    uint32 slot;
     Value *vp;
 
-BEGIN_CASE(JSOP_INCGLOBAL)
-    incr =  1; incr2 =  1; goto do_bound_global_incop;
-BEGIN_CASE(JSOP_DECGLOBAL)
-    incr = -1; incr2 = -1; goto do_bound_global_incop;
-BEGIN_CASE(JSOP_GLOBALINC)
-    incr =  1; incr2 =  0; goto do_bound_global_incop;
-BEGIN_CASE(JSOP_GLOBALDEC)
-    incr = -1; incr2 =  0; goto do_bound_global_incop;
-
-  do_bound_global_incop:
-    uint32 slot;
-    slot = GET_SLOTNO(regs.pc);
-    slot = script->getGlobalSlot(slot);
-    JSObject *obj;
-    obj = regs.fp->scopeChain().getGlobal();
-    vp = &obj->getSlotRef(slot);
-    goto do_int_fast_incop;
-END_CASE(JSOP_INCGLOBAL)
-
     /* Position cases so the most frequent i++ does not need a jump. */
 BEGIN_CASE(JSOP_DECARG)
     incr = -1; incr2 = -1; goto do_arg_incop;
 BEGIN_CASE(JSOP_ARGDEC)
     incr = -1; incr2 =  0; goto do_arg_incop;
 BEGIN_CASE(JSOP_INCARG)
     incr =  1; incr2 =  1; goto do_arg_incop;
 BEGIN_CASE(JSOP_ARGINC)
     incr =  1; incr2 =  0;
 
   do_arg_incop:
-    // If we initialize in the declaration, MSVC complains that the labels skip init.
     slot = GET_ARGNO(regs.pc);
     JS_ASSERT(slot < regs.fp->numFormalArgs());
     METER_SLOT_OP(op, slot);
     vp = argv + slot;
     goto do_int_fast_incop;
 
 BEGIN_CASE(JSOP_DECLOCAL)
     incr = -1; incr2 = -1; goto do_local_incop;
@@ -5351,41 +5333,16 @@ BEGIN_CASE(JSOP_CALLGLOBAL)
     JSObject *obj = regs.fp->scopeChain().getGlobal();
     JS_ASSERT(obj->containsSlot(slot));
     PUSH_COPY(obj->getSlot(slot));
     if (op == JSOP_CALLGLOBAL)
         PUSH_UNDEFINED();
 }
 END_CASE(JSOP_GETGLOBAL)
 
-BEGIN_CASE(JSOP_FORGLOBAL)
-{
-    Value rval;
-    if (!IteratorNext(cx, &regs.sp[-1].toObject(), &rval))
-        goto error;
-    PUSH_COPY(rval);
-    uint32 slot = script->getGlobalSlot(GET_SLOTNO(regs.pc));
-    JSObject *obj = regs.fp->scopeChain().getGlobal();
-    if (!obj->methodWriteBarrier(cx, slot, rval))
-        goto error;
-    obj->nativeSetSlot(slot, rval);
-    regs.sp--;
-}
-END_CASE(JSOP_FORGLOBAL)
-
-BEGIN_CASE(JSOP_SETGLOBAL)
-{
-    uint32 slot = script->getGlobalSlot(GET_SLOTNO(regs.pc));
-    JSObject *obj = regs.fp->scopeChain().getGlobal();
-    if (!obj->methodWriteBarrier(cx, slot, regs.sp[-1]))
-        goto error;
-    obj->nativeSetSlot(slot, regs.sp[-1]);
-}
-END_SET_CASE(JSOP_SETGLOBAL)
-
 BEGIN_CASE(JSOP_DEFCONST)
 BEGIN_CASE(JSOP_DEFVAR)
 {
     uint32 index = GET_INDEX(regs.pc);
     JSAtom *atom = atoms[index];
 
     JSObject *obj = &regs.fp->varobj(cx);
     JS_ASSERT(!obj->getOps()->defineProperty);
--- a/js/src/jsopcode.cpp
+++ b/js/src/jsopcode.cpp
@@ -1470,30 +1470,27 @@ DecompileDestructuringLHS(SprintStack *s
         LOAD_OP_DATA(pc);
         lval = PopStr(ss, JSOP_NOP);
         todo = SprintCString(&ss->sprinter, lval);
         if (op == JSOP_POPN)
             return pc;
         LOCAL_ASSERT(*pc == JSOP_POP);
         break;
 
-      case JSOP_SETGLOBAL:
       case JSOP_SETARG:
       case JSOP_SETLOCAL:
         LOCAL_ASSERT(pc[oplen] == JSOP_POP || pc[oplen] == JSOP_POPN);
         /* FALL THROUGH */
 
       case JSOP_SETLOCALPOP:
         atom = NULL;
         lval = NULL;
         if (op == JSOP_SETARG) {
             atom = GetArgOrVarAtom(jp, GET_SLOTNO(pc));
             LOCAL_ASSERT(atom);
-        } else if (op == JSOP_SETGLOBAL) {
-            atom = jp->script->getGlobalAtom(GET_SLOTNO(pc));
         } else if (IsVarSlot(jp, pc, &i)) {
             atom = GetArgOrVarAtom(jp, i);
             LOCAL_ASSERT(atom);
         } else {
             lval = GetLocal(ss, i);
         }
         {
             JSAutoByteString bytes;
@@ -3424,20 +3421,16 @@ Decompile(SprintStack *ss, jsbytecode *p
                 cx->free((char *)lval);
                 break;
 
               case JSOP_AND:
               case JSOP_ANDX:
                 xval = "&&";
                 goto do_logical_connective;
 
-              case JSOP_FORGLOBAL:
-                atom = jp->script->getGlobalAtom(GET_SLOTNO(pc));
-                goto do_forname;
-
               case JSOP_FORARG:
                 sn = NULL;
                 i = GET_ARGNO(pc);
                 goto do_forvarslot;
 
               case JSOP_FORLOCAL:
                 sn = js_GetSrcNote(jp->script, pc);
                 if (!IsVarSlot(jp, pc, &i)) {
@@ -3450,19 +3443,19 @@ Decompile(SprintStack *ss, jsbytecode *p
                 atom = GetArgOrVarAtom(jp, i);
                 LOCAL_ASSERT(atom);
                 todo = SprintCString(&ss->sprinter, VarPrefix(sn));
                 if (todo < 0 || !QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0))
                     return NULL;
                 break;
 
               case JSOP_FORNAME:
+              case JSOP_FORGNAME:
                 LOAD_ATOM(0);
 
-              do_forname:
                 sn = js_GetSrcNote(jp->script, pc);
                 todo = SprintCString(&ss->sprinter, VarPrefix(sn));
                 if (todo < 0 || !QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0))
                     return NULL;
                 break;
 
               case JSOP_FORPROP:
                 xval = NULL;
@@ -3565,20 +3558,16 @@ Decompile(SprintStack *ss, jsbytecode *p
                 todo = SprintCString(&ss->sprinter, rval);
                 break;
 
               case JSOP_SETARG:
                 atom = GetArgOrVarAtom(jp, GET_ARGNO(pc));
                 LOCAL_ASSERT(atom);
                 goto do_setname;
 
-              case JSOP_SETGLOBAL:
-                atom = jp->script->getGlobalAtom(GET_SLOTNO(pc));
-                goto do_setname;
-
               case JSOP_SETCONST:
               case JSOP_SETNAME:
               case JSOP_SETGNAME:
                 LOAD_ATOM(0);
 
               do_setname:
                 lval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0);
                 if (!lval)
@@ -3740,21 +3729,16 @@ Decompile(SprintStack *ss, jsbytecode *p
                 break;
 
               case JSOP_INCARG:
               case JSOP_DECARG:
                 atom = GetArgOrVarAtom(jp, GET_ARGNO(pc));
                 LOCAL_ASSERT(atom);
                 goto do_incatom;
 
-              case JSOP_INCGLOBAL:
-              case JSOP_DECGLOBAL:
-                atom = jp->script->getGlobalAtom(GET_SLOTNO(pc));
-                goto do_incatom;
-
               case JSOP_INCNAME:
               case JSOP_DECNAME:
               case JSOP_INCGNAME:
               case JSOP_DECGNAME:
                 LOAD_ATOM(0);
               do_incatom:
                 lval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0);
                 if (!lval)
@@ -3801,21 +3785,16 @@ Decompile(SprintStack *ss, jsbytecode *p
                 break;
 
               case JSOP_ARGINC:
               case JSOP_ARGDEC:
                 atom = GetArgOrVarAtom(jp, GET_ARGNO(pc));
                 LOCAL_ASSERT(atom);
                 goto do_atominc;
 
-              case JSOP_GLOBALINC:
-              case JSOP_GLOBALDEC:
-                atom = jp->script->getGlobalAtom(GET_SLOTNO(pc));
-                goto do_atominc;
-
               case JSOP_NAMEINC:
               case JSOP_NAMEDEC:
               case JSOP_GNAMEINC:
               case JSOP_GNAMEDEC:
                 LOAD_ATOM(0);
               do_atominc:
                 lval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0);
                 if (!lval)
--- a/js/src/jsopcode.tbl
+++ b/js/src/jsopcode.tbl
@@ -605,18 +605,14 @@ OPDEF(JSOP_SETMETHOD,     235,"setmethod
 OPDEF(JSOP_INITMETHOD,    236,"initmethod",    NULL,  3,  2,  1,  3,  JOF_ATOM|JOF_PROP|JOF_SET|JOF_DETECTING)
 OPDEF(JSOP_UNBRAND,       237,"unbrand",       NULL,  1,  1,  1,  0,  JOF_BYTE)
 OPDEF(JSOP_UNBRANDTHIS,   238,"unbrandthis",   NULL,  1,  0,  0,  0,  JOF_BYTE)
 
 OPDEF(JSOP_SHARPINIT,     239,"sharpinit",     NULL,  3,  0,  0,  0,  JOF_UINT16|JOF_SHARPSLOT)
 
 /* Static binding for globals. */
 OPDEF(JSOP_GETGLOBAL,     240,"getglobal",     NULL,  3,  0,  1, 19,  JOF_GLOBAL|JOF_NAME)
-OPDEF(JSOP_SETGLOBAL,     241,"setglobal",     NULL,  3,  1,  1,  3,  JOF_GLOBAL|JOF_NAME|JOF_SET|JOF_DETECTING)
-OPDEF(JSOP_INCGLOBAL,     242,"incglobal",     NULL,  3,  0,  1, 15,  JOF_GLOBAL|JOF_NAME|JOF_INC|JOF_TMPSLOT2)
-OPDEF(JSOP_DECGLOBAL,     243,"decglobal",     NULL,  3,  0,  1, 15,  JOF_GLOBAL|JOF_NAME|JOF_DEC|JOF_TMPSLOT2)
-OPDEF(JSOP_GLOBALINC,     244,"globalinc",     NULL,  3,  0,  1, 15,  JOF_GLOBAL|JOF_NAME|JOF_INC|JOF_POST|JOF_TMPSLOT2)
-OPDEF(JSOP_GLOBALDEC,     245,"globaldec",     NULL,  3,  0,  1, 15,  JOF_GLOBAL|JOF_NAME|JOF_DEC|JOF_POST|JOF_TMPSLOT2)
-OPDEF(JSOP_CALLGLOBAL,    246,"callglobal",    NULL,  3,  0,  2, 19,  JOF_GLOBAL|JOF_NAME|JOF_CALLOP)
-OPDEF(JSOP_FORGLOBAL,     247,"forglobal",     NULL,  3,  1,  1, 19,  JOF_GLOBAL|JOF_NAME|JOF_FOR|JOF_TMPSLOT)
+OPDEF(JSOP_CALLGLOBAL,    241,"callglobal",    NULL,  3,  0,  2, 19,  JOF_GLOBAL|JOF_NAME|JOF_CALLOP)
 
 /* Like JSOP_FUNAPPLY but for f.call instead of f.apply. */
-OPDEF(JSOP_FUNCALL,       248,"funcall",       NULL,  3, -1,  1, 18,  JOF_UINT16|JOF_INVOKE)
+OPDEF(JSOP_FUNCALL,       242,"funcall",       NULL,  3, -1,  1, 18,  JOF_UINT16|JOF_INVOKE)
+
+OPDEF(JSOP_FORGNAME,      243,"forgname",      NULL,  3,  1,  1, 19,  JOF_ATOM|JOF_GNAME|JOF_FOR|JOF_TMPSLOT3)
--- a/js/src/jsparse.cpp
+++ b/js/src/jsparse.cpp
@@ -3590,28 +3590,17 @@ DefineGlobal(JSParseNode *pn, JSCodeGene
          */
         if (pn->pn_type == TOK_FUNCTION) {
             JS_ASSERT(pn->pn_arity = PN_FUNC);
             uint32 index = ALE_INDEX(ale);
             globalScope->defs[index].funbox = pn->pn_funbox;
         }
     }
 
-    UpvarCookie cookie;
-    if (!cg->addGlobalUse(atom, ALE_INDEX(ale), &cookie))
-        return false;
-
-    if (!cookie.isFree()) {
-        pn->pn_cookie.set(cookie);
-        pn->pn_dflags |= PND_GVAR;
-        if (pn->pn_type != TOK_FUNCTION) {
-            pn->pn_op = JSOP_GETGLOBAL;
-            pn->pn_dflags |= PND_BOUND;
-        }
-    }
+    pn->pn_dflags |= PND_GVAR;
 
     return true;
 }
 
 static bool
 BindTopLevelVar(JSContext *cx, BindData *data, JSAtomListElement *ale, JSParseNode *pn,
                 JSAtom *varname, JSTreeContext *tc)
 {
@@ -3947,21 +3936,19 @@ BindDestructuringVar(JSContext *cx, Bind
     if (!data->binder(cx, data, atom, tc))
         return JS_FALSE;
 
     /*
      * Select the appropriate name-setting opcode, respecting eager selection
      * done by the data->binder function.
      */
     if (pn->pn_dflags & PND_BOUND) {
-        JS_ASSERT_IF((pn->pn_dflags & PND_GVAR), PN_OP(pn) == JSOP_GETGLOBAL);
+        JS_ASSERT(!(pn->pn_dflags & PND_GVAR));
         pn->pn_op = (pn->pn_op == JSOP_ARGUMENTS)
                     ? JSOP_SETNAME
-                    : (pn->pn_dflags & PND_GVAR)
-                    ? JSOP_SETGLOBAL
                     : JSOP_SETLOCAL;
     } else {
         pn->pn_op = (data->op == JSOP_DEFCONST)
                     ? JSOP_SETCONST
                     : JSOP_SETNAME;
     }
 
     if (data->op == JSOP_DEFCONST)
@@ -6271,22 +6258,20 @@ Parser::variables(bool inLetHead)
             if (pn2->pn_used) {
                 pn2 = MakeAssignment(pn2, init, tc);
                 if (!pn2)
                     return NULL;
             } else {
                 pn2->pn_expr = init;
             }
 
-            JS_ASSERT_IF((pn2->pn_dflags & PND_GVAR), PN_OP(pn2) == JSOP_GETGLOBAL);
+            JS_ASSERT_IF(pn2->pn_dflags & PND_GVAR, !(pn2->pn_dflags & PND_BOUND));
 
             pn2->pn_op = (PN_OP(pn2) == JSOP_ARGUMENTS)
                          ? JSOP_SETNAME
-                         : (pn2->pn_dflags & PND_GVAR)
-                         ? JSOP_SETGLOBAL
                          : (pn2->pn_dflags & PND_BOUND)
                          ? JSOP_SETLOCAL
                          : (data.op == JSOP_DEFCONST)
                          ? JSOP_SETCONST
                          : JSOP_SETNAME;
 
             NoteLValue(context, pn2, tc, data.fresh ? PND_INITIALIZED : PND_ASSIGNED);
 
--- a/js/src/jsparse.h
+++ b/js/src/jsparse.h
@@ -859,16 +859,21 @@ struct JSDefinition : public JSParseNode
         return (JSDefinition *) pn;
     }
 
     bool isFreeVar() const {
         JS_ASSERT(pn_defn);
         return pn_cookie.isFree() || test(PND_GVAR);
     }
 
+    bool isGlobal() const {
+        JS_ASSERT(pn_defn);
+        return test(PND_GVAR);
+    }
+
     // Grr, windows.h or something under it #defines CONST...
 #ifdef CONST
 # undef CONST
 #endif
     enum Kind { VAR, CONST, LET, FUNCTION, ARG, UNKNOWN };
 
     bool isBindingForm() { return int(kind()) <= int(LET); }
 
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -14646,16 +14646,22 @@ TraceRecorder::record_JSOP_FORNAME()
         RETURN_STOP_A("forname on non-tracked value not supported");
     LIns* v_ins;
     CHECK_STATUS_A(unboxNextValue(v_ins));
     set(vp, v_ins);
     return ARECORD_CONTINUE;
 }
 
 JS_REQUIRES_STACK AbortableRecordingStatus
+TraceRecorder::record_JSOP_FORGNAME()
+{
+    return record_JSOP_FORNAME();
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_FORPROP()
 {
     return ARECORD_STOP;
 }
 
 JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_FORELEM()
 {
@@ -14679,31 +14685,16 @@ TraceRecorder::record_JSOP_FORLOCAL()
 {
     LIns* v_ins;
     CHECK_STATUS_A(unboxNextValue(v_ins));
     var(GET_SLOTNO(cx->regs->pc), v_ins);
     return ARECORD_CONTINUE;
 }
 
 JS_REQUIRES_STACK AbortableRecordingStatus
-TraceRecorder::record_JSOP_FORGLOBAL()
-{
-    LIns* v_ins;
-    CHECK_STATUS_A(unboxNextValue(v_ins));
-
-    uint32 slot = cx->fp()->script()->getGlobalSlot(GET_SLOTNO(cx->regs->pc));
-    if (!lazilyImportGlobalSlot(slot))
-         RETURN_STOP_A("lazy import of global slot failed");
-
-    set(&globalObj->getSlotRef(slot), v_ins);
-    return ARECORD_CONTINUE;
-}
-
-
-JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_POPN()
 {
     return ARECORD_CONTINUE;
 }
 
 /*
  * Generate LIR to reach |obj2| from |obj| by traversing the scope chain. The
  * generated code also ensures that any call objects found have not changed shape.
@@ -16163,80 +16154,29 @@ TraceRecorder::record_JSOP_GETGLOBAL()
     if (!lazilyImportGlobalSlot(slot))
          RETURN_STOP_A("lazy import of global slot failed");
 
     stack(0, get(&globalObj->getSlotRef(slot)));
     return ARECORD_CONTINUE;
 }
 
 JS_REQUIRES_STACK AbortableRecordingStatus
-TraceRecorder::record_JSOP_SETGLOBAL()
-{
-    uint32 slot = cx->fp()->script()->getGlobalSlot(GET_SLOTNO(cx->regs->pc));
-    if (!lazilyImportGlobalSlot(slot))
-         RETURN_STOP_A("lazy import of global slot failed");
-
-    set(&globalObj->getSlotRef(slot), stack(-1));
-    return ARECORD_CONTINUE;
-}
-
-JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_CALLGLOBAL()
 {
     uint32 slot = cx->fp()->script()->getGlobalSlot(GET_SLOTNO(cx->regs->pc));
     if (!lazilyImportGlobalSlot(slot))
          RETURN_STOP_A("lazy import of global slot failed");
 
     Value &v = globalObj->getSlotRef(slot);
     stack(0, get(&v));
     stack(1, w.immiUndefined());
     return ARECORD_CONTINUE;
 }
 
 JS_REQUIRES_STACK AbortableRecordingStatus
-TraceRecorder::record_JSOP_GLOBALDEC()
-{
-    uint32 slot = cx->fp()->script()->getGlobalSlot(GET_SLOTNO(cx->regs->pc));
-    if (!lazilyImportGlobalSlot(slot))
-         RETURN_STOP_A("lazy import of global slot failed");
-
-    return InjectStatus(inc(globalObj->getSlotRef(slot), -1, false));
-}
-
-JS_REQUIRES_STACK AbortableRecordingStatus
-TraceRecorder::record_JSOP_DECGLOBAL()
-{
-    uint32 slot = cx->fp()->script()->getGlobalSlot(GET_SLOTNO(cx->regs->pc));
-    if (!lazilyImportGlobalSlot(slot))
-         RETURN_STOP_A("lazy import of global slot failed");
-
-    return InjectStatus(inc(globalObj->getSlotRef(slot), -1, true));
-}
-
-JS_REQUIRES_STACK AbortableRecordingStatus
-TraceRecorder::record_JSOP_INCGLOBAL()
-{
-    uint32 slot = cx->fp()->script()->getGlobalSlot(GET_SLOTNO(cx->regs->pc));
-    if (!lazilyImportGlobalSlot(slot))
-         RETURN_STOP_A("lazy import of global slot failed");
-
-    return InjectStatus(inc(globalObj->getSlotRef(slot), 1, true));
-}
-
-JS_REQUIRES_STACK AbortableRecordingStatus
-TraceRecorder::record_JSOP_GLOBALINC()
-{
-    uint32 slot = cx->fp()->script()->getGlobalSlot(GET_SLOTNO(cx->regs->pc));
-    if (!lazilyImportGlobalSlot(slot))
-         RETURN_STOP_A("lazy import of global slot failed");
-
-    return InjectStatus(inc(globalObj->getSlotRef(slot), 1, false));
-}
-
-JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_GETGNAME()
 {
     return record_JSOP_NAME();
 }
 
 JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_SETGNAME()
 {
--- a/js/src/jsxdrapi.h
+++ b/js/src/jsxdrapi.h
@@ -201,17 +201,17 @@ JS_XDRFindClassById(JSXDRState *xdr, uin
  * Bytecode version number. Increment the subtrahend whenever JS bytecode
  * changes incompatibly.
  *
  * This version number should be XDR'ed once near the front of any file or
  * larger storage unit containing XDR'ed bytecode and other data, and checked
  * before deserialization of bytecode.  If the saved version does not match
  * the current version, abort deserialization and invalidate the file.
  */
-#define JSXDR_BYTECODE_VERSION      (0xb973c0de - 81)
+#define JSXDR_BYTECODE_VERSION      (0xb973c0de - 82)
 
 /*
  * Library-private functions.
  */
 extern JSBool
 js_XDRAtom(JSXDRState *xdr, JSAtom **atomp);
 
 JS_END_EXTERN_C
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -1650,52 +1650,35 @@ mjit::Compiler::generateMethod()
             PC += JSOP_LOCALINC_LENGTH;
             if (popped)
                 PC += JSOP_POP_LENGTH;
             break;
           }
           END_CASE(JSOP_LOCALDEC)
 
           BEGIN_CASE(JSOP_FORNAME)
-            // Before: ITER
-            // After:  ITER SCOPEOBJ
-            jsop_bindname(fullAtomIndex(PC), false);
-
-            // Fall through to FORPROP.
+            jsop_forname(script->getAtom(fullAtomIndex(PC)));
+          END_CASE(JSOP_FORNAME)
+
+          BEGIN_CASE(JSOP_FORGNAME)
+            jsop_forgname(script->getAtom(fullAtomIndex(PC)));
+          END_CASE(JSOP_FORGNAME)
 
           BEGIN_CASE(JSOP_FORPROP)
-            // Before: ITER OBJ
-            // After:  ITER OBJ ITER
-            frame.dupAt(-2);
-
-            // Before: ITER OBJ ITER 
-            // After:  ITER OBJ ITER VALUE
-            iterNext();
-
-            // Before: ITER OBJ ITER VALUE
-            // After:  ITER OBJ VALUE
-            frame.shimmy(1);
-
-            // Before: ITER OBJ VALUE
-            // After:  ITER VALUE
-            jsop_setprop(script->getAtom(fullAtomIndex(PC)), false);
-
-            // Before: ITER VALUE
-            // After:  ITER
-            frame.pop();
+            jsop_forprop(script->getAtom(fullAtomIndex(PC)));
           END_CASE(JSOP_FORPROP)
 
           BEGIN_CASE(JSOP_FORELEM)
             // This opcode is for the decompiler; it is succeeded by an
             // ENUMELEM, which performs the actual array store.
             iterNext();
           END_CASE(JSOP_FORELEM)
 
           BEGIN_CASE(JSOP_BINDNAME)
-            jsop_bindname(fullAtomIndex(PC), true);
+            jsop_bindname(script->getAtom(fullAtomIndex(PC)), true);
           END_CASE(JSOP_BINDNAME)
 
           BEGIN_CASE(JSOP_SETPROP)
             if (!jsop_setprop(script->getAtom(fullAtomIndex(PC)), true))
                 return Compile_Error;
           END_CASE(JSOP_SETPROP)
 
           BEGIN_CASE(JSOP_SETNAME)
@@ -1921,17 +1904,17 @@ mjit::Compiler::generateMethod()
           BEGIN_CASE(JSOP_GETGNAME)
           BEGIN_CASE(JSOP_CALLGNAME)
             jsop_getgname(fullAtomIndex(PC));
             if (op == JSOP_CALLGNAME)
                 frame.push(UndefinedValue());
           END_CASE(JSOP_GETGNAME)
 
           BEGIN_CASE(JSOP_SETGNAME)
-            jsop_setgname(fullAtomIndex(PC), true);
+            jsop_setgname(script->getAtom(fullAtomIndex(PC)), true);
           END_CASE(JSOP_SETGNAME)
 
           BEGIN_CASE(JSOP_REGEXP)
           {
             JSObject *regex = script->getRegExp(fullAtomIndex(PC));
             prepareStubCall(Uses(0));
             masm.move(ImmPtr(regex), Registers::ArgReg1);
             INLINE_STUBCALL(stubs::RegExp);
@@ -2035,35 +2018,16 @@ mjit::Compiler::generateMethod()
 
           BEGIN_CASE(JSOP_GETGLOBAL)
           BEGIN_CASE(JSOP_CALLGLOBAL)
             jsop_getglobal(GET_SLOTNO(PC));
             if (op == JSOP_CALLGLOBAL)
                 frame.push(UndefinedValue());
           END_CASE(JSOP_GETGLOBAL)
 
-          BEGIN_CASE(JSOP_SETGLOBAL)
-            jsop_setglobal(GET_SLOTNO(PC));
-          END_CASE(JSOP_SETGLOBAL)
-
-          BEGIN_CASE(JSOP_INCGLOBAL)
-          BEGIN_CASE(JSOP_DECGLOBAL)
-          BEGIN_CASE(JSOP_GLOBALINC)
-          BEGIN_CASE(JSOP_GLOBALDEC)
-            /* Advances PC automatically. */
-            jsop_globalinc(op, GET_SLOTNO(PC));
-            break;
-          END_CASE(JSOP_GLOBALINC)
-
-          BEGIN_CASE(JSOP_FORGLOBAL)
-            iterNext();
-            jsop_setglobal(GET_SLOTNO(PC));
-            frame.pop();
-          END_CASE(JSOP_FORGLOBAL)
-
           default:
            /* Sorry, this opcode isn't implemented yet. */
 #ifdef JS_METHODJIT_SPEW
             JaegerSpew(JSpew_Abort, "opcode %s not handled yet (%s line %d)\n", OpcodeNames[op],
                        script->filename, js_PCToLineNumber(cx, script, PC));
 #endif
             return Compile_Abort;
         }
@@ -2140,31 +2104,16 @@ mjit::Compiler::jumpInScript(Jump j, jsb
     if (pc < PC) {
         j.linkTo(jumpMap[uint32(pc - script->code)], &masm);
         return true;
     }
     return branchPatches.append(BranchPatch(j, pc));
 }
 
 void
-mjit::Compiler::jsop_setglobal(uint32 index)
-{
-    JS_ASSERT(globalObj);
-    uint32 slot = script->getGlobalSlot(index);
-
-    FrameEntry *fe = frame.peek(-1);
-    bool popped = PC[JSOP_SETGLOBAL_LENGTH] == JSOP_POP;
-
-    RegisterID reg = frame.allocReg();
-    Address address = masm.objSlotRef(globalObj, reg, slot);
-    frame.storeTo(fe, address, popped);
-    frame.freeReg(reg);
-}
-
-void
 mjit::Compiler::jsop_getglobal(uint32 index)
 {
     JS_ASSERT(globalObj);
     uint32 slot = script->getGlobalSlot(index);
 
     RegisterID reg = frame.allocReg();
     Address address = masm.objSlotRef(globalObj, reg, slot);
     frame.freeReg(reg);
@@ -3667,30 +3616,30 @@ mjit::Compiler::jsop_xname(JSAtom *atom)
 
     stubcc.rejoin(Changes(1));
 
     pics.append(pic);
     return true;
 }
 
 void
-mjit::Compiler::jsop_bindname(uint32 index, bool usePropCache)
+mjit::Compiler::jsop_bindname(JSAtom *atom, bool usePropCache)
 {
     PICGenInfo pic(ic::PICInfo::BIND, JSOp(*PC), usePropCache);
 
     // This code does not check the frame flags to see if scopeChain has been
     // set. Rather, it relies on the up-front analysis statically determining
     // whether BINDNAME can be used, which reifies the scope chain at the
     // prologue.
     JS_ASSERT(analysis->usesScopeChain());
 
     pic.shapeReg = frame.allocReg();
     pic.objReg = frame.allocReg();
     pic.typeReg = Registers::ReturnReg;
-    pic.atom = script->getAtom(index);
+    pic.atom = atom;
     pic.hasTypeCheck = false;
     pic.fastPathStart = masm.label();
 
     Address parent(pic.objReg, offsetof(JSObject, parent));
     masm.loadPtr(Address(JSFrameReg, JSStackFrame::offsetOfScopeChain()), pic.objReg);
 
     pic.shapeGuard = masm.label();
 #if defined JS_NUNBOX32
@@ -3756,32 +3705,32 @@ mjit::Compiler::jsop_callprop(JSAtom *at
 bool
 mjit::Compiler::jsop_setprop(JSAtom *atom, bool usePropCache)
 {
     jsop_setprop_slow(atom, usePropCache);
     return true;
 }
 
 void
-mjit::Compiler::jsop_bindname(uint32 index, bool usePropCache)
+mjit::Compiler::jsop_bindname(JSAtom *atom, bool usePropCache)
 {
     RegisterID reg = frame.allocReg();
     Address scopeChain(JSFrameReg, JSStackFrame::offsetOfScopeChain());
     masm.loadPtr(scopeChain, reg);
 
     Address address(reg, offsetof(JSObject, parent));
 
     Jump j = masm.branchPtr(Assembler::NotEqual, masm.payloadOf(address), ImmPtr(0));
 
     stubcc.linkExit(j, Uses(0));
     stubcc.leave();
     if (usePropCache) {
         OOL_STUBCALL(stubs::BindName);
     } else {
-        stubcc.masm.move(ImmPtr(script->getAtom(index)), Registers::ArgReg1);
+        stubcc.masm.move(ImmPtr(atom), Registers::ArgReg1);
         OOL_STUBCALL(stubs::BindNameNoCache);
     }
 
     frame.pushTypedPayload(JSVAL_TYPE_OBJECT, reg);
 
     stubcc.rejoin(Changes(1));
 }
 #endif
@@ -3813,16 +3762,18 @@ mjit::Compiler::jsop_this()
 
         JS_ASSERT(thisFe->isType(JSVAL_TYPE_OBJECT));
     }
 }
 
 void
 mjit::Compiler::jsop_gnameinc(JSOp op, VoidStubAtom stub, uint32 index)
 {
+    JSAtom *atom = script->getAtom(index);
+
 #if defined JS_MONOIC
     jsbytecode *next = &PC[JSOP_GNAMEINC_LENGTH];
     bool pop = (JSOp(*next) == JSOP_POP) && !analysis->jumpTarget(next);
     int amt = (op == JSOP_GNAMEINC || op == JSOP_INCGNAME) ? -1 : 1;
 
     if (pop || (op == JSOP_INCGNAME || op == JSOP_DECGNAME)) {
         /* These cases are easy, the original value is not observed. */
 
@@ -3843,17 +3794,17 @@ mjit::Compiler::jsop_gnameinc(JSOp op, V
         // V+1 OBJ V+1 OBJ
 
         frame.shift(-3);
         // OBJ OBJ V+1
 
         frame.shift(-1);
         // OBJ V+1
 
-        jsop_setgname(index, false);
+        jsop_setgname(atom, false);
         // V+1
 
         if (pop)
             frame.pop();
     } else {
         /* The pre-value is observed, making this more tricky. */
 
         jsop_getgname(index);
@@ -3878,27 +3829,26 @@ mjit::Compiler::jsop_gnameinc(JSOp op, V
         // N N+1 OBJ N+1 OBJ
 
         frame.shift(-3);
         // N OBJ OBJ N+1
 
         frame.shift(-1);
         // N OBJ N+1
 
-        jsop_setgname(index, false);
+        jsop_setgname(atom, false);
         // N N+1
 
         frame.pop();
         // N
     }
 
     if (pop)
         PC += JSOP_POP_LENGTH;
 #else
-    JSAtom *atom = script->getAtom(index);
     prepareStubCall(Uses(0));
     masm.move(ImmPtr(atom), Registers::ArgReg1);
     INLINE_STUBCALL(stub);
     frame.pushSynced();
 #endif
 
     PC += JSOP_GNAMEINC_LENGTH;
 }
@@ -3920,17 +3870,17 @@ mjit::Compiler::jsop_nameinc(JSOp op, Vo
 
         frame.push(Int32Value(amt));
         // V 1
 
         /* Use sub since it calls ValueToNumber instead of string concat. */
         jsop_binary(JSOP_SUB, stubs::Sub);
         // N+1
 
-        jsop_bindname(index, false);
+        jsop_bindname(atom, false);
         // V+1 OBJ
 
         frame.dup2();
         // V+1 OBJ V+1 OBJ
 
         frame.shift(-3);
         // OBJ OBJ V+1
 
@@ -3956,17 +3906,17 @@ mjit::Compiler::jsop_nameinc(JSOp op, Vo
         // N N
 
         frame.push(Int32Value(-amt));
         // N N 1
 
         jsop_binary(JSOP_ADD, stubs::Add);
         // N N+1
 
-        jsop_bindname(index, false);
+        jsop_bindname(atom, false);
         // N N+1 OBJ
 
         frame.dup2();
         // N N+1 OBJ N+1 OBJ
 
         frame.shift(-3);
         // N OBJ OBJ N+1
 
@@ -4473,31 +4423,30 @@ mjit::Compiler::jsop_getgname(uint32 ind
     mics.append(mic);
 
 #else
     jsop_getgname_slow(index);
 #endif
 }
 
 void
-mjit::Compiler::jsop_setgname_slow(uint32 index, bool usePropertyCache)
+mjit::Compiler::jsop_setgname_slow(JSAtom *atom, bool usePropertyCache)
 {
-    JSAtom *atom = script->getAtom(index);
     prepareStubCall(Uses(2));
     masm.move(ImmPtr(atom), Registers::ArgReg1);
     if (usePropertyCache)
         INLINE_STUBCALL(STRICT_VARIANT(stubs::SetGlobalName));
     else
         INLINE_STUBCALL(STRICT_VARIANT(stubs::SetGlobalNameNoCache));
     frame.popn(2);
     frame.pushSynced();
 }
 
 void
-mjit::Compiler::jsop_setgname(uint32 index, bool usePropertyCache)
+mjit::Compiler::jsop_setgname(JSAtom *atom, bool usePropertyCache)
 {
 #if defined JS_MONOIC
     FrameEntry *objFe = frame.peek(-2);
     JS_ASSERT_IF(objFe->isTypeKnown(), objFe->getKnownType() == JSVAL_TYPE_OBJECT);
 
     MICGenInfo mic(ic::MICInfo::SET);
     RESERVE_IC_SPACE(masm);
     RegisterID objReg;
@@ -4607,17 +4556,17 @@ mjit::Compiler::jsop_setgname(uint32 ind
         else
             frame.pushRegs(typeReg, dataReg);
     }
 
     stubcc.rejoin(Changes(1));
 
     mics.append(mic);
 #else
-    jsop_setgname_slow(index, usePropertyCache);
+    jsop_setgname_slow(atom, usePropertyCache);
 #endif
 }
 
 void
 mjit::Compiler::jsop_setelem_slow()
 {
     prepareStubCall(Uses(3));
     INLINE_STUBCALL(STRICT_VARIANT(stubs::SetElem));
@@ -5058,8 +5007,69 @@ mjit::Compiler::jsop_callelem_slow()
 {
     prepareStubCall(Uses(2));
     INLINE_STUBCALL(stubs::CallElem);
     frame.popn(2);
     frame.pushSynced();
     frame.pushSynced();
 }
 
+void
+mjit::Compiler::jsop_forprop(JSAtom *atom)
+{
+    // Before: ITER OBJ
+    // After:  ITER OBJ ITER
+    frame.dupAt(-2);
+
+    // Before: ITER OBJ ITER 
+    // After:  ITER OBJ ITER VALUE
+    iterNext();
+
+    // Before: ITER OBJ ITER VALUE
+    // After:  ITER OBJ VALUE
+    frame.shimmy(1);
+
+    // Before: ITER OBJ VALUE
+    // After:  ITER VALUE
+    jsop_setprop(atom, false);
+
+    // Before: ITER VALUE
+    // After:  ITER
+    frame.pop();
+}
+
+void
+mjit::Compiler::jsop_forname(JSAtom *atom)
+{
+    // Before: ITER
+    // After:  ITER SCOPEOBJ
+    jsop_bindname(atom, false);
+    jsop_forprop(atom);
+}
+
+void
+mjit::Compiler::jsop_forgname(JSAtom *atom)
+{
+    // Before: ITER
+    // After:  ITER GLOBAL
+    jsop_bindgname();
+
+    // Before: ITER GLOBAL
+    // After:  ITER GLOBAL ITER
+    frame.dupAt(-2);
+
+    // Before: ITER GLOBAL ITER 
+    // After:  ITER GLOBAL ITER VALUE
+    iterNext();
+
+    // Before: ITER GLOBAL ITER VALUE
+    // After:  ITER GLOBAL VALUE
+    frame.shimmy(1);
+
+    // Before: ITER GLOBAL VALUE
+    // After:  ITER VALUE
+    jsop_setgname(atom, false);
+
+    // Before: ITER VALUE
+    // After:  ITER
+    frame.pop();
+}
+
--- a/js/src/methodjit/Compiler.h
+++ b/js/src/methodjit/Compiler.h
@@ -359,17 +359,17 @@ class Compiler : public BaseCompiler
 #endif
 #ifdef JS_MONOIC
     void passMICAddress(MICGenInfo &mic);
 #endif
     bool constructThis();
 
     /* Opcode handlers. */
     bool jumpAndTrace(Jump j, jsbytecode *target, Jump *slow = NULL);
-    void jsop_bindname(uint32 index, bool usePropCache);
+    void jsop_bindname(JSAtom *atom, bool usePropCache);
     void jsop_setglobal(uint32 index);
     void jsop_getglobal(uint32 index);
     void jsop_getprop_slow(JSAtom *atom, bool usePropCache = true);
     void jsop_getarg(uint32 slot);
     void jsop_setarg(uint32 slot, bool popped);
     void jsop_this();
     void emitReturn(FrameEntry *fe);
     void emitFinalReturn(Assembler &masm);
@@ -386,18 +386,18 @@ class Compiler : public BaseCompiler
     void inlineCallHelper(uint32 argc, bool callingNew);
     void fixPrimitiveReturn(Assembler *masm, FrameEntry *fe);
     void jsop_gnameinc(JSOp op, VoidStubAtom stub, uint32 index);
     bool jsop_nameinc(JSOp op, VoidStubAtom stub, uint32 index);
     bool jsop_propinc(JSOp op, VoidStubAtom stub, uint32 index);
     void jsop_eleminc(JSOp op, VoidStub);
     void jsop_getgname(uint32 index);
     void jsop_getgname_slow(uint32 index);
-    void jsop_setgname(uint32 index, bool usePropertyCache);
-    void jsop_setgname_slow(uint32 index, bool usePropertyCache);
+    void jsop_setgname(JSAtom *atom, bool usePropertyCache);
+    void jsop_setgname_slow(JSAtom *atom, bool usePropertyCache);
     void jsop_bindgname();
     void jsop_setelem_slow();
     void jsop_getelem_slow();
     void jsop_callelem_slow();
     void jsop_unbrand();
     bool jsop_getprop(JSAtom *atom, bool typeCheck = true, bool usePropCache = true);
     bool jsop_length();
     bool jsop_setprop(JSAtom *atom, bool usePropCache = true);
@@ -410,16 +410,19 @@ class Compiler : public BaseCompiler
     bool jsop_instanceof();
     void jsop_name(JSAtom *atom);
     bool jsop_xname(JSAtom *atom);
     void enterBlock(JSObject *obj);
     void leaveBlock();
     void emitEval(uint32 argc);
     void jsop_arguments();
     void jsop_tableswitch(jsbytecode *pc);
+    void jsop_forprop(JSAtom *atom);
+    void jsop_forname(JSAtom *atom);
+    void jsop_forgname(JSAtom *atom);
 
     /* Fast arithmetic. */
     void jsop_binary(JSOp op, VoidStub stub);
     void jsop_binary_full(FrameEntry *lhs, FrameEntry *rhs, JSOp op, VoidStub stub);
     void jsop_binary_full_simple(FrameEntry *fe, JSOp op, VoidStub stub);
     void jsop_binary_double(FrameEntry *lhs, FrameEntry *rhs, JSOp op, VoidStub stub);
     void slowLoadConstantDouble(Assembler &masm, FrameEntry *fe,
                                 FPRegisterID fpreg);
@@ -447,17 +450,16 @@ class Compiler : public BaseCompiler
     void jsop_rsh_int_int(FrameEntry *lhs, FrameEntry *rhs);
     void jsop_rsh_const_int(FrameEntry *lhs, FrameEntry *rhs);
     void jsop_rsh_int_const(FrameEntry *lhs, FrameEntry *rhs);
     void jsop_rsh_int_unknown(FrameEntry *lhs, FrameEntry *rhs);
     void jsop_rsh_const_const(FrameEntry *lhs, FrameEntry *rhs);
     void jsop_rsh_const_unknown(FrameEntry *lhs, FrameEntry *rhs);
     void jsop_rsh_unknown_const(FrameEntry *lhs, FrameEntry *rhs);
     void jsop_rsh_unknown_any(FrameEntry *lhs, FrameEntry *rhs);
-    void jsop_globalinc(JSOp op, uint32 index);
     void jsop_mod();
     void jsop_neg();
     void jsop_bitnot();
     void jsop_not();
     void jsop_typeof();
     bool booleanJumpScript(JSOp op, jsbytecode *target);
     bool jsop_ifneq(JSOp op, jsbytecode *target);
     bool jsop_andor(JSOp op, jsbytecode *target);
--- a/js/src/methodjit/FastOps.cpp
+++ b/js/src/methodjit/FastOps.cpp
@@ -574,76 +574,16 @@ mjit::Compiler::jsop_bitop(JSOp op)
         frame.pushNumber(reg, true);
     else
         frame.pushTypedPayload(JSVAL_TYPE_INT32, reg);
 
     if (stubNeeded)
         stubcc.rejoin(Changes(1));
 }
 
-void
-mjit::Compiler::jsop_globalinc(JSOp op, uint32 index)
-{
-    uint32 slot = script->getGlobalSlot(index);
-
-    bool popped = false;
-    PC += JSOP_GLOBALINC_LENGTH;
-    if (JSOp(*PC) == JSOP_POP && !analysis->jumpTarget(PC)) {
-        popped = true;
-        PC += JSOP_POP_LENGTH;
-    }
-
-    int amt = (js_CodeSpec[op].format & JOF_INC) ? 1 : -1;
-    bool post = !!(js_CodeSpec[op].format & JOF_POST);
-
-    RegisterID data;
-    RegisterID reg = frame.allocReg();
-    Address addr = masm.objSlotRef(globalObj, reg, slot);
-    uint32 depth = frame.stackDepth();
-
-    if (post && !popped) {
-        frame.push(addr);
-        FrameEntry *fe = frame.peek(-1);
-        Jump notInt = frame.testInt32(Assembler::NotEqual, fe);
-        stubcc.linkExit(notInt, Uses(0));
-        data = frame.copyDataIntoReg(fe);
-    } else {
-        Jump notInt = masm.testInt32(Assembler::NotEqual, addr);
-        stubcc.linkExit(notInt, Uses(0));
-        data = frame.allocReg();
-        masm.loadPayload(addr, data);
-    }
-
-    Jump ovf;
-    if (amt > 0)
-        ovf = masm.branchAdd32(Assembler::Overflow, Imm32(1), data);
-    else
-        ovf = masm.branchSub32(Assembler::Overflow, Imm32(1), data);
-    stubcc.linkExit(ovf, Uses(0));
-
-    stubcc.leave();
-    stubcc.masm.lea(addr, Registers::ArgReg1);
-    stubcc.vpInc(op, depth);
-
-#if defined JS_NUNBOX32
-    masm.storePayload(data, addr);
-#elif defined JS_PUNBOX64
-    masm.storeValueFromComponents(ImmType(JSVAL_TYPE_INT32), data, addr);
-#endif
-
-    if (!post && !popped)
-        frame.pushInt32(data);
-    else
-        frame.freeReg(data);
-
-    frame.freeReg(reg);
-
-    stubcc.rejoin(Changes((!post && !popped) ? 1 : 0));
-}
-
 static inline bool
 CheckNullOrUndefined(FrameEntry *fe)
 {
     if (!fe->isTypeKnown())
         return false;
     JSValueType type = fe->getKnownType();
     return type == JSVAL_TYPE_NULL || type == JSVAL_TYPE_UNDEFINED;
 }
--- a/js/src/methodjit/StubCalls.cpp
+++ b/js/src/methodjit/StubCalls.cpp
@@ -692,114 +692,16 @@ stubs::Ursh(VMFrame &f)
     if (!ValueToECMAInt32(f.cx, f.regs.sp[-1], &j))
         THROW();
 
     u >>= (j & 31);
 
 	f.regs.sp[-2].setNumber(uint32(u));
 }
 
-template <int32 N>
-static inline bool
-PostInc(VMFrame &f, Value *vp)
-{
-    double d;
-    if (!ValueToNumber(f.cx, *vp, &d))
-        return false;
-    f.regs.sp++;
-    f.regs.sp[-1].setDouble(d);
-    d += N;
-    vp->setDouble(d);
-    return true;
-}
-
-template <int32 N>
-static inline bool
-PreInc(VMFrame &f, Value *vp)
-{
-    double d;
-    if (!ValueToNumber(f.cx, *vp, &d))
-        return false;
-    d += N;
-    vp->setDouble(d);
-    f.regs.sp++;
-    f.regs.sp[-1].setDouble(d);
-    return true;
-}
-
-void JS_FASTCALL
-stubs::VpInc(VMFrame &f, Value *vp)
-{
-    if (!PostInc<1>(f, vp))
-        THROW();
-}
-
-void JS_FASTCALL
-stubs::VpDec(VMFrame &f, Value *vp)
-{
-    if (!PostInc<-1>(f, vp))
-        THROW();
-}
-
-void JS_FASTCALL
-stubs::DecVp(VMFrame &f, Value *vp)
-{
-    if (!PreInc<-1>(f, vp))
-        THROW();
-}
-
-void JS_FASTCALL
-stubs::IncVp(VMFrame &f, Value *vp)
-{
-    if (!PreInc<1>(f, vp))
-        THROW();
-}
-
-void JS_FASTCALL
-stubs::LocalInc(VMFrame &f, uint32 slot)
-{
-    double d;
-    if (!ValueToNumber(f.cx, f.regs.sp[-2], &d))
-        THROW();
-    f.regs.sp[-2].setNumber(d);
-    f.regs.sp[-1].setNumber(d + 1);
-    f.fp()->slots()[slot] = f.regs.sp[-1];
-}
-
-void JS_FASTCALL
-stubs::LocalDec(VMFrame &f, uint32 slot)
-{
-    double d;
-    if (!ValueToNumber(f.cx, f.regs.sp[-2], &d))
-        THROW();
-    f.regs.sp[-2].setNumber(d);
-    f.regs.sp[-1].setNumber(d - 1);
-    f.fp()->slots()[slot] = f.regs.sp[-1];
-}
-
-void JS_FASTCALL
-stubs::IncLocal(VMFrame &f, uint32 slot)
-{
-    double d;
-    if (!ValueToNumber(f.cx, f.regs.sp[-1], &d))
-        THROW();
-    f.regs.sp[-1].setNumber(d + 1);
-    f.fp()->slots()[slot] = f.regs.sp[-1];
-}
-
-void JS_FASTCALL
-stubs::DecLocal(VMFrame &f, uint32 slot)
-{
-    double d;
-    if (!ValueToNumber(f.cx, f.regs.sp[-1], &d))
-        THROW();
-    f.regs.sp[-1].setNumber(d - 1);
-    f.fp()->slots()[slot] = f.regs.sp[-1];
-}
-
 template<JSBool strict>
 void JS_FASTCALL
 stubs::DefFun(VMFrame &f, JSFunction *fun)
 {
     JSObject *obj2;
 
     JSContext *cx = f.cx;
     JSStackFrame *fp = f.fp();
--- a/js/src/methodjit/StubCalls.h
+++ b/js/src/methodjit/StubCalls.h
@@ -171,25 +171,16 @@ JSObject * JS_FASTCALL LambdaForSet(VMFr
 JSObject * JS_FASTCALL LambdaJoinableForCall(VMFrame &f, JSFunction *fun);
 JSObject * JS_FASTCALL LambdaJoinableForNull(VMFrame &f, JSFunction *fun);
 JSObject * JS_FASTCALL FlatLambda(VMFrame &f, JSFunction *fun);
 void JS_FASTCALL Arguments(VMFrame &f);
 void JS_FASTCALL ArgSub(VMFrame &f, uint32 n);
 void JS_FASTCALL EnterBlock(VMFrame &f, JSObject *obj);
 void JS_FASTCALL LeaveBlock(VMFrame &f, JSObject *blockChain);
 
-void JS_FASTCALL VpInc(VMFrame &f, Value *vp);
-void JS_FASTCALL VpDec(VMFrame &f, Value *vp);
-void JS_FASTCALL DecVp(VMFrame &f, Value *vp);
-void JS_FASTCALL IncVp(VMFrame &f, Value *vp);
-void JS_FASTCALL LocalInc(VMFrame &f, uint32 slot);
-void JS_FASTCALL LocalDec(VMFrame &f, uint32 slot);
-void JS_FASTCALL IncLocal(VMFrame &f, uint32 slot);
-void JS_FASTCALL DecLocal(VMFrame &f, uint32 slot);
-
 JSBool JS_FASTCALL LessThan(VMFrame &f);
 JSBool JS_FASTCALL LessEqual(VMFrame &f);
 JSBool JS_FASTCALL GreaterThan(VMFrame &f);
 JSBool JS_FASTCALL GreaterEqual(VMFrame &f);
 JSBool JS_FASTCALL Equal(VMFrame &f);
 JSBool JS_FASTCALL NotEqual(VMFrame &f);
 
 void JS_FASTCALL BitOr(VMFrame &f);
--- a/js/src/methodjit/StubCompiler.cpp
+++ b/js/src/methodjit/StubCompiler.cpp
@@ -200,51 +200,16 @@ StubCompiler::fixCrossJumps(uint8 *ncode
         const CrossJumpInScript &cj = scriptJoins[i];
         slow.link(cj.from, fast.locationOf(cc.labelOf(cj.pc)));
     }
 
     for (size_t i = 0; i < joins.length(); i++)
         slow.link(joins[i].from, fast.locationOf(joins[i].to));
 }
 
-JSC::MacroAssembler::Call
-StubCompiler::vpInc(JSOp op, uint32 depth)
-{
-    uint32 slots = depth + script->nfixed;
-
-    VoidVpStub stub = NULL;
-    switch (op) {
-      case JSOP_GLOBALINC:
-      case JSOP_ARGINC:
-        stub = stubs::VpInc;
-        break;
-
-      case JSOP_GLOBALDEC:
-      case JSOP_ARGDEC:
-        stub = stubs::VpDec;
-        break;
-
-      case JSOP_INCGLOBAL:
-      case JSOP_INCARG:
-        stub = stubs::IncVp;
-        break;
-
-      case JSOP_DECGLOBAL:
-      case JSOP_DECARG:
-        stub = stubs::DecVp;
-        break;
-
-      default:
-        JS_NOT_REACHED("unknown incdec op");
-        break;
-    }
-
-    return emitStubCall(JS_FUNC_TO_DATA_PTR(void *, stub), slots, __LINE__);
-}
-
 void
 StubCompiler::crossJump(Jump j, Label L)
 {
     joins.append(CrossPatch(j, L));
 }
 
 bool
 StubCompiler::jumpInScript(Jump j, jsbytecode *target)
--- a/js/src/methodjit/StubCompiler.h
+++ b/js/src/methodjit/StubCompiler.h
@@ -99,18 +99,16 @@ class StubCompiler
     size_t size() {
         return masm.size();
     }
 
     uint8 *buffer() {
         return masm.buffer();
     }
 
-    Call vpInc(JSOp op, uint32 depth);
-
     /*
      * Force a frame sync and return a label before the syncing code.
      * A Jump may bind to the label with leaveExitDirect().
      */
     JSC::MacroAssembler::Label syncExit(Uses uses);
 
     /*
      * Sync the exit, and state that code will be immediately outputted