[JAEGER] Predict unbound names as being on the global object (bug 564949).
authorDavid Anderson <danderson@mozilla.com>
Sat, 12 Jun 2010 19:00:27 -0700
changeset 52825 986b895298227c56703a66a80c5e795317ad9a56
parent 52824 b9fcc815684c454cf3255acd5b013420a565fd64
child 52826 32aca0384575c09529131ad18d0ee875fb1a6bfb
push idunknown
push userunknown
push dateunknown
bugs564949
milestone1.9.3a5pre
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
[JAEGER] Predict unbound names as being on the global object (bug 564949).
js/src/jsemit.cpp
js/src/jsinterp.cpp
js/src/jsobj.cpp
js/src/jsopcode.cpp
js/src/jsopcode.h
js/src/jsopcode.tbl
js/src/jsops.cpp
js/src/jsparse.cpp
js/src/jsscript.cpp
js/src/jsscript.h
js/src/jstracer.cpp
js/src/methodjit/Compiler.cpp
js/src/methodjit/MethodJIT.h
js/src/methodjit/StubCalls.cpp
js/src/methodjit/StubCalls.h
--- a/js/src/jsemit.cpp
+++ b/js/src/jsemit.cpp
@@ -2097,87 +2097,69 @@ BindNameToSlot(JSContext *cx, JSCodeGene
             JSFunction *fun = cg->parser->callerFrame->fun;
             JS_ASSERT(cg->staticLevel >= fun->u.i.script->staticLevel);
             unsigned skip = cg->staticLevel - fun->u.i.script->staticLevel;
             if (cg->skipSpansGenerator(skip))
                 return JS_TRUE;
 
             return MakeUpvarForEval(pn, cg);
         }
+
+        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_SETCONST:
+          case JSOP_DELNAME:
+          case JSOP_FORNAME:
+            /* Not supported. */
+            return JS_TRUE;
+          default: JS_NOT_REACHED("gname");
+        }
+
+        ale = cg->atomList.add(cg->parser, atom);
+        if (!ale)
+            return JS_FALSE;
+
+        pn->pn_op = op;
+        pn->pn_dflags |= PND_BOUND;
+
         return JS_TRUE;
     }
 
     if (dn->pn_dflags & PND_GVAR) {
-        if (js_CodeSpec[dn->pn_op].type() == JOF_GLOBAL ||
-            dn_kind == JSDefinition::FUNCTION) {
-            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].slot;
-
-                /* Fall back to NAME if we can't add a slot. */
-                if (!cg->addGlobalUse(atom, slot, &cookie))
-                    return JS_FALSE;
-
-                if (cookie == FREE_UPVAR_COOKIE)
-                    return JS_TRUE;
-            }
-
-            pn->pn_op = op;
-            pn->pn_cookie = cookie;
-            pn->pn_dflags |= PND_BOUND;
+        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;
-        }
-
-        /*
-         * If this is a global reference from within a function, leave pn_op as
-         * JSOP_NAME, etc. We could emit JSOP_*GVAR ops within function code if
-         * only we could depend on the global frame's slots being valid for all
-         * calls to the function, and if we could equate the atom index in the
-         * function's atom map for every global name with its frame slot.
-         */
-        if (cg->inFunction())
-            return JS_TRUE;
-
-        /*
-         * We are optimizing global variables and there may be no pre-existing
-         * global property named atom when this global script runs. If atom was
-         * declared via const or var, optimize pn to access fp->vars using the
-         * appropriate JSOP_*GVAR op.
-         *
-         * FIXME: should be able to optimize global function access too.
-         */
-        JS_ASSERT(dn_kind == JSDefinition::VAR || dn_kind == JSDefinition::CONST);
-
-        switch (op) {
-          case JSOP_NAME:     op = JSOP_GETGVAR; break;
-          case JSOP_SETNAME:  op = JSOP_SETGVAR; break;
-          case JSOP_SETCONST: /* NB: no change */ break;
-          case JSOP_INCNAME:  op = JSOP_INCGVAR; break;
-          case JSOP_NAMEINC:  op = JSOP_GVARINC; break;
-          case JSOP_DECNAME:  op = JSOP_DECGVAR; break;
-          case JSOP_NAMEDEC:  op = JSOP_GVARDEC; break;
-          case JSOP_FORNAME:  /* NB: no change */ break;
-          case JSOP_DELNAME:  /* NB: no change */ break;
           default: JS_NOT_REACHED("gvar");
         }
+
+        JSCodeGenerator *globalCg = cg->compiler()->globalScope->cg;
+        if (globalCg != cg) {
+            uint32 slot = globalCg->globalUses[cookie].slot;
+
+            /* Fall back to NAME if we can't add a slot. */
+            if (!cg->addGlobalUse(atom, slot, &cookie))
+                return JS_FALSE;
+
+            if (cookie == FREE_UPVAR_COOKIE)
+                return JS_TRUE;
+        }
         pn->pn_op = op;
         pn->pn_cookie = cookie;
         pn->pn_dflags |= PND_BOUND;
         return JS_TRUE;
     }
 
     uintN level = UPVAR_FRAME_SKIP(cookie);
     JS_ASSERT(cg->staticLevel >= level);
@@ -2658,19 +2640,18 @@ EmitNameOp(JSContext *cx, JSCodeGenerato
         return JS_FALSE;
     op = PN_OP(pn);
 
     if (callContext) {
         switch (op) {
           case JSOP_NAME:
             op = JSOP_CALLNAME;
             break;
-          case JSOP_GETGVAR:
-            JS_ASSERT(!cg->funbox);
-            op = JSOP_CALLGVAR;
+          case JSOP_GETGNAME:
+            op = JSOP_CALLGNAME;
             break;
           case JSOP_GETGLOBAL:
             op = JSOP_CALLGLOBAL;
             break;
           case JSOP_GETARG:
             op = JSOP_CALLARG;
             break;
           case JSOP_GETLOCAL:
@@ -3778,16 +3759,17 @@ EmitDestructuringLHS(JSContext *cx, JSCo
             if (!BindNameToSlot(cx, cg, pn))
                 return JS_FALSE;
             if (pn->isConst() && !pn->isInitialized())
                 return js_Emit1(cx, cg, JSOP_POP) >= 0;
         }
 
         switch (pn->pn_op) {
           case JSOP_SETNAME:
+          case JSOP_SETGNAME:
             /*
              * NB: pn is a PN_NAME node, not a PN_BINARY.  Nevertheless,
              * we want to emit JSOP_ENUMELEM, which has format JOF_ELEM.
              * So here and for JSOP_ENUMCONSTELEM, we use EmitElemOp.
              */
             if (!EmitElemOp(cx, pn, JSOP_ENUMELEM, cg))
                 return JS_FALSE;
             break;
@@ -3798,17 +3780,16 @@ EmitDestructuringLHS(JSContext *cx, JSCo
             break;
 
           case JSOP_SETLOCAL:
             slot = (jsuint) pn->pn_cookie;
             EMIT_UINT16_IMM_OP(JSOP_SETLOCALPOP, slot);
             break;
 
           case JSOP_SETARG:
-          case JSOP_SETGVAR:
           case JSOP_SETGLOBAL:
             slot = (jsuint) pn->pn_cookie;
             EMIT_UINT16_IMM_OP(PN_OP(pn), slot);
             if (js_Emit1(cx, cg, JSOP_POP) < 0)
                 return JS_FALSE;
             break;
 
           default:
@@ -4207,16 +4188,19 @@ EmitVariables(JSContext *cx, JSCodeGener
             if (!MaybeEmitVarDecl(cx, cg, PN_OP(pn), pn2, &atomIndex))
                 return JS_FALSE;
 
             if (pn3) {
                 JS_ASSERT(!forInVar);
                 if (op == JSOP_SETNAME) {
                     JS_ASSERT(!let);
                     EMIT_INDEX_OP(JSOP_BINDNAME, atomIndex);
+                } else if (op == JSOP_SETGNAME) {
+                    JS_ASSERT(!let);
+                    EMIT_INDEX_OP(JSOP_BINDGNAME, atomIndex);
                 }
                 if (pn->pn_op == JSOP_DEFCONST &&
                     !js_DefineCompileTimeConstant(cx, cg, pn2->pn_atom, pn3)) {
                     return JS_FALSE;
                 }
 
 #if JS_HAS_BLOCK_SCOPE
                 /* Evaluate expr in the outer lexical scope if requested. */
@@ -4837,18 +4821,16 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
                                    : SRC_DECL_LET) < 0) {
                     return JS_FALSE;
                 }
                 if (pn3->pn_cookie != FREE_UPVAR_COOKIE) {
                     op = PN_OP(pn3);
                     switch (op) {
                       case JSOP_GETARG:   /* FALL THROUGH */
                       case JSOP_SETARG:   op = JSOP_FORARG; break;
-                      case JSOP_GETGVAR:  /* FALL THROUGH */
-                      case JSOP_SETGVAR:  op = JSOP_FORNAME; 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);
                     }
                 } else {
                     pn3->pn_op = JSOP_FORNAME;
@@ -5787,18 +5769,20 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
                 return JS_FALSE;
             if (pn2->pn_cookie != FREE_UPVAR_COOKIE) {
                 atomIndex = (jsatomid) pn2->pn_cookie;
             } else {
                 ale = cg->atomList.add(cg->parser, pn2->pn_atom);
                 if (!ale)
                     return JS_FALSE;
                 atomIndex = ALE_INDEX(ale);
-                if (!pn2->isConst())
-                    EMIT_INDEX_OP(JSOP_BINDNAME, atomIndex);
+                if (!pn2->isConst()) {
+                    JSOp op = PN_OP(pn2) == JSOP_SETGNAME ? JSOP_BINDGNAME : JSOP_BINDNAME;
+                    EMIT_INDEX_OP(op, atomIndex);
+                }
             }
             break;
           case TOK_DOT:
             if (!js_EmitTree(cx, cg, pn2->expr()))
                 return JS_FALSE;
             ale = cg->atomList.add(cg->parser, pn2->pn_atom);
             if (!ale)
                 return JS_FALSE;
@@ -5845,18 +5829,18 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
                         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 {
                     JS_ASSERT(PN_OP(pn2) != JSOP_GETUPVAR);
-                    EMIT_UINT16_IMM_OP((PN_OP(pn2) == JSOP_SETGVAR)
-                                       ? JSOP_GETGVAR
+                    EMIT_UINT16_IMM_OP((PN_OP(pn2) == JSOP_SETGNAME)
+                                       ? JSOP_GETGNAME
                                        : (PN_OP(pn2) == JSOP_SETGLOBAL)
                                        ? JSOP_GETGLOBAL
                                        : (PN_OP(pn2) == JSOP_SETARG)
                                        ? JSOP_GETARG
                                        : JSOP_GETLOCAL,
                                        atomIndex);
                 }
                 break;
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -1961,17 +1961,16 @@ AssertValidPropertyCacheHit(JSContext *c
 # define ASSERT_VALID_PROPERTY_CACHE_HIT(pcoff,obj,pobj,entry) ((void) 0)
 #endif
 
 /*
  * Ensure that the intrepreter switch can close call-bytecode cases in the
  * same way as non-call bytecodes.
  */
 JS_STATIC_ASSERT(JSOP_NAME_LENGTH == JSOP_CALLNAME_LENGTH);
-JS_STATIC_ASSERT(JSOP_GETGVAR_LENGTH == JSOP_CALLGVAR_LENGTH);
 JS_STATIC_ASSERT(JSOP_GETUPVAR_LENGTH == JSOP_CALLUPVAR_LENGTH);
 JS_STATIC_ASSERT(JSOP_GETUPVAR_DBG_LENGTH == JSOP_CALLUPVAR_DBG_LENGTH);
 JS_STATIC_ASSERT(JSOP_GETUPVAR_DBG_LENGTH == JSOP_GETUPVAR_LENGTH);
 JS_STATIC_ASSERT(JSOP_GETDSLOT_LENGTH == JSOP_CALLDSLOT_LENGTH);
 JS_STATIC_ASSERT(JSOP_GETARG_LENGTH == JSOP_CALLARG_LENGTH);
 JS_STATIC_ASSERT(JSOP_GETLOCAL_LENGTH == JSOP_CALLLOCAL_LENGTH);
 JS_STATIC_ASSERT(JSOP_XMLNAME_LENGTH == JSOP_CALLXMLNAME_LENGTH);
 
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -2807,16 +2807,17 @@ Detecting(JSContext *cx, jsbytecode *pc)
              * about JS1.2's revision of the equality operators here.
              */
             if (++pc < endpc) {
                 op = js_GetOpcode(cx, script, pc);
                 return *pc == JSOP_EQ || *pc == JSOP_NE;
             }
             return JS_FALSE;
 
+          case JSOP_GETGNAME:
           case JSOP_NAME:
             /*
              * Special case #2: handle (document.all == undefined).  Don't
              * worry about someone redefining undefined, which was added by
              * Edition 3, so is read/write for backward compatibility.
              */
             GET_ATOM_FROM_BYTECODE(script, pc, 0, atom);
             if (atom == cx->runtime->atomState.typeAtoms[JSTYPE_VOID] &&
--- a/js/src/jsopcode.cpp
+++ b/js/src/jsopcode.cpp
@@ -1440,29 +1440,26 @@ DecompileDestructuringLHS(SprintStack *s
         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_SETGVAR:
       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_SETGVAR) {
-            LOAD_ATOM(0);
         } 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);
         }
@@ -2333,16 +2330,17 @@ Decompile(SprintStack *ss, jsbytecode *p
                     LOCAL_ASSERT(*pc == JSOP_POPN);
                     len = oplen = JSOP_POPN_LENGTH;
                     goto end_groupassignment;
                 }
 #endif
                 /* FALL THROUGH */
 
               case JSOP_BINDNAME:
+              case JSOP_BINDGNAME:
                 todo = Sprint(&ss->sprinter, "");
                 break;
 
               case JSOP_TRY:
                 js_printf(jp, "\ttry {\n");
                 jp->indent += 4;
                 todo = -2;
                 break;
@@ -3541,25 +3539,25 @@ Decompile(SprintStack *ss, jsbytecode *p
                 goto do_setname;
 
               case JSOP_SETGLOBAL:
                 atom = jp->script->getGlobalAtom(GET_SLOTNO(pc));
                 goto do_setname;
 
               case JSOP_SETCONST:
               case JSOP_SETNAME:
-              case JSOP_SETGVAR:
+              case JSOP_SETGNAME:
                 LOAD_ATOM(0);
 
               do_setname:
                 lval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0);
                 if (!lval)
                     return NULL;
                 rval = POP_STR();
-                if (op == JSOP_SETNAME)
+                if (op == JSOP_SETNAME || op == JSOP_SETGNAME)
                     (void) PopOff(ss, op);
 
               do_setlval:
                 sn = js_GetSrcNote(jp->script, pc - 1);
                 if (sn && SN_TYPE(sn) == SRC_ASSIGNOP) {
                     todo = Sprint(&ss->sprinter, "%s %s= %s",
                                   lval,
                                   (lastop == JSOP_GETTER)
@@ -3762,18 +3760,18 @@ Decompile(SprintStack *ss, jsbytecode *p
 
               case JSOP_INCGLOBAL:
               case JSOP_DECGLOBAL:
                 atom = jp->script->getGlobalAtom(GET_SLOTNO(pc));
                 goto do_incatom;
 
               case JSOP_INCNAME:
               case JSOP_DECNAME:
-              case JSOP_INCGVAR:
-              case JSOP_DECGVAR:
+              case JSOP_INCGNAME:
+              case JSOP_DECGNAME:
                 LOAD_ATOM(0);
               do_incatom:
                 lval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0);
                 if (!lval)
                     return NULL;
                 RETRACT(&ss->sprinter, lval);
               do_inclval:
                 todo = Sprint(&ss->sprinter, ss_format,
@@ -3823,18 +3821,18 @@ Decompile(SprintStack *ss, jsbytecode *p
 
               case JSOP_GLOBALINC:
               case JSOP_GLOBALDEC:
                 atom = jp->script->getGlobalAtom(GET_SLOTNO(pc));
                 goto do_atominc;
 
               case JSOP_NAMEINC:
               case JSOP_NAMEDEC:
-              case JSOP_GVARINC:
-              case JSOP_GVARDEC:
+              case JSOP_GNAMEINC:
+              case JSOP_GNAMEDEC:
                 LOAD_ATOM(0);
               do_atominc:
                 lval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0);
                 if (!lval)
                     return NULL;
                 RETRACT(&ss->sprinter, lval);
               do_lvalinc:
                 todo = Sprint(&ss->sprinter, ss_format,
@@ -4033,18 +4031,18 @@ Decompile(SprintStack *ss, jsbytecode *p
 
               case JSOP_CALLGLOBAL:
               case JSOP_GETGLOBAL:
                 atom = jp->script->getGlobalAtom(GET_SLOTNO(pc));
                 goto do_name;
 
               case JSOP_CALLNAME:
               case JSOP_NAME:
-              case JSOP_GETGVAR:
-              case JSOP_CALLGVAR:
+              case JSOP_GETGNAME:
+              case JSOP_CALLGNAME:
                 LOAD_ATOM(0);
               do_name:
                 lval = "";
 #if JS_HAS_XML_SUPPORT
               do_qname:
 #endif
                 sn = js_GetSrcNote(jp->script, pc);
                 rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom),
--- a/js/src/jsopcode.h
+++ b/js/src/jsopcode.h
@@ -119,16 +119,17 @@ typedef enum JSOp {
 #define JOF_TMPSLOT2     (2U<<22) /* interpreter uses extra 2 temporary slot
                                      besides the slots opcode uses */
 #define JOF_TMPSLOT_SHIFT 22
 #define JOF_TMPSLOT_MASK  (JS_BITMASK(2) << JOF_TMPSLOT_SHIFT)
 
 #define JOF_SHARPSLOT    (1U<<24) /* first immediate is uint16 stack slot no.
                                      that needs fixup when in global code (see
                                      Compiler::compileScript) */
+#define JOF_GNAME        (1U<<25) /* predicted global name */
 
 /* Shorthands for type from format and type from opcode. */
 #define JOF_TYPE(fmt)   ((fmt) & JOF_TYPEMASK)
 #define JOF_OPTYPE(op)  JOF_TYPE(js_CodeSpec[op].format)
 
 /* Shorthands for mode from format and mode from opcode. */
 #define JOF_MODE(fmt)   ((fmt) & JOF_MODEMASK)
 #define JOF_OPMODE(op)  JOF_MODE(js_CodeSpec[op].format)
--- a/js/src/jsopcode.tbl
+++ b/js/src/jsopcode.tbl
@@ -391,23 +391,23 @@ OPDEF(JSOP_BACKPATCH_POP, 150,"backpatch
 
 /* Set pending exception from the stack, to trigger rethrow. */
 OPDEF(JSOP_THROWING,      151,"throwing", NULL,       1,  1,  0,  0,  JOF_BYTE)
 
 /* Set and get return value pseudo-register in stack frame. */
 OPDEF(JSOP_SETRVAL,       152,"setrval",  NULL,       1,  1,  0,  2,  JOF_BYTE)
 OPDEF(JSOP_RETRVAL,       153,"retrval",  NULL,       1,  0,  0,  0,  JOF_BYTE)
 
-/* Optimized global variable ops (we don't bother doing a JSOP_FORGVAR op). */
-OPDEF(JSOP_GETGVAR,       154,"getgvar",  NULL,       3,  0,  1, 19,  JOF_ATOM|JOF_NAME)
-OPDEF(JSOP_SETGVAR,       155,"setgvar",  NULL,       3,  1,  1,  3,  JOF_ATOM|JOF_NAME|JOF_SET|JOF_DETECTING)
-OPDEF(JSOP_INCGVAR,       156,"incgvar",  NULL,       3,  0,  1, 15,  JOF_ATOM|JOF_NAME|JOF_INC|JOF_TMPSLOT2)
-OPDEF(JSOP_DECGVAR,       157,"decgvar",  NULL,       3,  0,  1, 15,  JOF_ATOM|JOF_NAME|JOF_DEC|JOF_TMPSLOT2)
-OPDEF(JSOP_GVARINC,       158,"gvarinc",  NULL,       3,  0,  1, 15,  JOF_ATOM|JOF_NAME|JOF_INC|JOF_POST|JOF_TMPSLOT2)
-OPDEF(JSOP_GVARDEC,       159,"gvardec",  NULL,       3,  0,  1, 15,  JOF_ATOM|JOF_NAME|JOF_DEC|JOF_POST|JOF_TMPSLOT2)
+/* Free variable references that must either be found on the global or a ReferenceError */
+OPDEF(JSOP_GETGNAME,      154,"getgname",  NULL,       3,  0,  1, 19,  JOF_ATOM|JOF_NAME|JOF_GNAME)
+OPDEF(JSOP_SETGNAME,      155,"setgname",  NULL,       3,  2,  1,  3,  JOF_ATOM|JOF_NAME|JOF_SET|JOF_DETECTING|JOF_GNAME)
+OPDEF(JSOP_INCGNAME,      156,"incgname",  NULL,       3,  0,  1, 15,  JOF_ATOM|JOF_NAME|JOF_INC|JOF_TMPSLOT2|JOF_GNAME)
+OPDEF(JSOP_DECGNAME,      157,"decgname",  NULL,       3,  0,  1, 15,  JOF_ATOM|JOF_NAME|JOF_DEC|JOF_TMPSLOT2|JOF_GNAME)
+OPDEF(JSOP_GNAMEINC,      158,"gnameinc",  NULL,       3,  0,  1, 15,  JOF_ATOM|JOF_NAME|JOF_INC|JOF_POST|JOF_TMPSLOT2|JOF_GNAME)
+OPDEF(JSOP_GNAMEDEC,      159,"gnamedec",  NULL,       3,  0,  1, 15,  JOF_ATOM|JOF_NAME|JOF_DEC|JOF_POST|JOF_TMPSLOT2|JOF_GNAME)
 
 /* Regular expression literal requiring special "fork on exec" handling. */
 OPDEF(JSOP_REGEXP,        160,"regexp",   NULL,       3,  0,  1, 19,  JOF_REGEXP)
 
 /* XML (ECMA-357, a.k.a. "E4X") support. */
 OPDEF(JSOP_DEFXMLNS,      161,"defxmlns",   NULL,     1,  1,  0,  0,  JOF_BYTE)
 OPDEF(JSOP_ANYNAME,       162,"anyname",    NULL,     1,  0,  1, 19,  JOF_BYTE|JOF_XMLNAME)
 OPDEF(JSOP_QNAMEPART,     163,"qnamepart",  NULL,     3,  0,  1, 19,  JOF_ATOM|JOF_XMLNAME)
@@ -528,20 +528,20 @@ OPDEF(JSOP_GETLOCALPROP,  211,"getlocalp
 /*
  * Optimize atom segments 1-3.  These must be followed by JSOP_RESETBASE0 after
  * the opcode that they prefix.
  */
 OPDEF(JSOP_INDEXBASE1,    212,"atombase1",     NULL,  1,  0,  0,  0,  JOF_BYTE |JOF_INDEXBASE)
 OPDEF(JSOP_INDEXBASE2,    213,"atombase2",     NULL,  1,  0,  0,  0,  JOF_BYTE |JOF_INDEXBASE)
 OPDEF(JSOP_INDEXBASE3,    214,"atombase3",     NULL,  1,  0,  0,  0,  JOF_BYTE |JOF_INDEXBASE)
 
-OPDEF(JSOP_CALLGVAR,      215, "callgvar",     NULL,  3,  0,  2, 19,  JOF_ATOM|JOF_NAME|JOF_CALLOP)
+OPDEF(JSOP_CALLGNAME,     215, "callgname",    NULL,  3,  0,  2, 19,  JOF_ATOM|JOF_NAME|JOF_CALLOP|JOF_GNAME)
 OPDEF(JSOP_CALLLOCAL,     216, "calllocal",    NULL,  3,  0,  2, 19,  JOF_LOCAL|JOF_NAME|JOF_CALLOP)
 OPDEF(JSOP_CALLARG,       217, "callarg",      NULL,  3,  0,  2, 19,  JOF_QARG |JOF_NAME|JOF_CALLOP)
-OPDEF(JSOP_UNUSED218,     218, "unused218",    NULL,  1,  0,  0,  0,  JOF_BYTE)
+OPDEF(JSOP_BINDGNAME,     218, "bindgname",    NULL,  3,  0,  1,  0,  JOF_ATOM|JOF_NAME|JOF_SET|JOF_GNAME)
 
 /*
  * Opcodes to hold 8-bit and 32-bit immediate integer operands.
  */
 OPDEF(JSOP_INT8,          219, "int8",         NULL,  2,  0,  1, 16,  JOF_INT8)
 OPDEF(JSOP_INT32,         220, "int32",        NULL,  5,  0,  1, 16,  JOF_INT32)
 
 /*
--- a/js/src/jsops.cpp
+++ b/js/src/jsops.cpp
@@ -730,16 +730,20 @@ BEGIN_CASE(JSOP_ENUMCONSTELEM)
                              JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY)) {
         goto error;
     }
     regs.sp -= 3;
 }
 END_CASE(JSOP_ENUMCONSTELEM)
 #endif
 
+BEGIN_CASE(JSOP_BINDGNAME)
+    PUSH_NONFUNOBJ(*fp->scopeChainObj()->getGlobal());
+END_CASE(JSOP_BINDGNAME)
+
 BEGIN_CASE(JSOP_BINDNAME)
 {
     JSObject *obj;
     do {
         /*
          * We can skip the property lookup for the global object. If the
          * property does not exist anywhere on the scope chain, JSOP_SETNAME
          * adds the property to the global.
@@ -1350,18 +1354,24 @@ BEGIN_CASE(JSOP_PROPDEC)
     if (id == 0)
         FETCH_ELEMENT_ID(obj, -1, id);
     goto do_incop;
 
 BEGIN_CASE(JSOP_INCNAME)
 BEGIN_CASE(JSOP_DECNAME)
 BEGIN_CASE(JSOP_NAMEINC)
 BEGIN_CASE(JSOP_NAMEDEC)
+BEGIN_CASE(JSOP_INCGNAME)
+BEGIN_CASE(JSOP_DECGNAME)
+BEGIN_CASE(JSOP_GNAMEINC)
+BEGIN_CASE(JSOP_GNAMEDEC)
 {
     obj = fp->scopeChainObj();
+    if (js_CodeSpec[op].format & JOF_GNAME)
+        obj = obj->getGlobal();
 
     JSObject *obj2;
     PropertyCacheEntry *entry;
     JS_PROPERTY_CACHE(cx).test(cx, regs.pc, obj, obj2, entry, atom);
     if (!atom) {
         ASSERT_VALID_PROPERTY_CACHE_HIT(0, obj, obj2, entry);
         if (obj == obj2 && entry->vword.isSlot()) {
             uint32 slot = entry->vword.toSlot();
@@ -1521,72 +1531,16 @@ BEGIN_CASE(JSOP_LOCALINC)
         if (!js_DoIncDec(cx, &js_CodeSpec[op], &regs.sp[-1], vp))
             goto error;
     }
     len = JSOP_INCARG_LENGTH;
     JS_ASSERT(len == js_CodeSpec[op].length);
     DO_NEXT_OP(len);
 }
 
-/* NB: This macro doesn't use JS_BEGIN_MACRO/JS_END_MACRO around its body. */
-#define FAST_GLOBAL_INCREMENT_OP(SLOWOP,INCR,INCR2)                           \
-    op2 = SLOWOP;                                                             \
-    incr = INCR;                                                              \
-    incr2 = INCR2;                                                            \
-    goto do_global_incop
-
-{
-    JSOp op2;
-    int incr, incr2;
-
-BEGIN_CASE(JSOP_DECGVAR)
-    FAST_GLOBAL_INCREMENT_OP(JSOP_DECNAME, -1, -1);
-BEGIN_CASE(JSOP_GVARDEC)
-    FAST_GLOBAL_INCREMENT_OP(JSOP_NAMEDEC, -1,  0);
-BEGIN_CASE(JSOP_INCGVAR)
-    FAST_GLOBAL_INCREMENT_OP(JSOP_INCNAME,  1,  1);
-BEGIN_CASE(JSOP_GVARINC)
-    FAST_GLOBAL_INCREMENT_OP(JSOP_NAMEINC,  1,  0);
-
-#undef FAST_GLOBAL_INCREMENT_OP
-
-  do_global_incop:
-    JS_ASSERT((js_CodeSpec[op].format & JOF_TMPSLOT_MASK) ==
-              JOF_TMPSLOT2);
-    uint32 slot = GET_SLOTNO(regs.pc);
-    JS_ASSERT(slot < GlobalVarCount(fp));
-    METER_SLOT_OP(op, slot);
-    const Value &lref = fp->slots()[slot];
-    if (lref.isNull()) {
-        op = op2;
-        DO_OP();
-    }
-    slot = (uint32)lref.asInt32();
-    JS_ASSERT(fp->varobj(cx) == cx->activeCallStack()->getInitialVarObj());
-    JSObject *varobj = cx->activeCallStack()->getInitialVarObj();
-
-    /* XXX all this code assumes that varobj is either a callobj or global and
-     * that it cannot be accessed in a MT way. This is either true now or
-     * coming soon. */
-
-    Value &rref = varobj->getSlotRef(slot);
-    int32_t tmp;
-    if (JS_LIKELY(rref.isInt32() && CanIncDecWithoutOverflow(tmp = rref.asInt32()))) {
-        PUSH_INT32(tmp + incr2);
-        rref.asInt32Ref() = tmp + incr;
-    } else {
-        PUSH_COPY(rref);
-        if (!js_DoIncDec(cx, &js_CodeSpec[op], &regs.sp[-1], &rref))
-            goto error;
-    }
-    len = JSOP_INCGVAR_LENGTH;  /* all gvar incops are same length */
-    JS_ASSERT(len == js_CodeSpec[op].length);
-    DO_NEXT_OP(len);
-}
-
 BEGIN_CASE(JSOP_THIS)
     if (!fp->getThisObject(cx))
         goto error;
     PUSH_COPY(fp->thisv);
 END_CASE(JSOP_THIS)
 
 BEGIN_CASE(JSOP_UNBRANDTHIS)
 {
@@ -1818,27 +1772,30 @@ BEGIN_CASE(JSOP_CALLPROP)
 END_CASE(JSOP_CALLPROP)
 
 BEGIN_CASE(JSOP_UNBRAND)
     JS_ASSERT(regs.sp - fp->slots() >= 1);
     if (!regs.sp[-1].asObject().unbrand(cx))
         goto error;
 END_CASE(JSOP_UNBRAND)
 
+BEGIN_CASE(JSOP_SETGNAME)
 BEGIN_CASE(JSOP_SETNAME)
 BEGIN_CASE(JSOP_SETPROP)
 BEGIN_CASE(JSOP_SETMETHOD)
 {
     Value &rref = regs.sp[-1];
     JS_ASSERT_IF(op == JSOP_SETMETHOD, rref.isFunObj());
     Value &lref = regs.sp[-2];
     JS_ASSERT_IF(op == JSOP_SETNAME, lref.isObject());
     JSObject *obj;
     VALUE_TO_OBJECT(cx, &lref, obj);
 
+    JS_ASSERT_IF(op == JSOP_SETGNAME, obj == fp->scopeChainObj()->getGlobal());
+
     do {
         PropertyCache *cache = &JS_PROPERTY_CACHE(cx);
 
         /*
          * Probe the property cache, specializing for two important
          * set-property cases. First:
          *
          *   function f(a, b, c) {
@@ -2418,20 +2375,24 @@ BEGIN_CASE(JSOP_SETCALL)
     Value *vp = regs.sp - argc - 2;
     JSBool ok = Invoke(cx, InvokeArgsGuard(vp, argc), 0);
     if (ok)
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_LEFTSIDE_OF_ASS);
     goto error;
 }
 END_CASE(JSOP_SETCALL)
 
+BEGIN_CASE(JSOP_GETGNAME)
+BEGIN_CASE(JSOP_CALLGNAME)
 BEGIN_CASE(JSOP_NAME)
 BEGIN_CASE(JSOP_CALLNAME)
 {
     JSObject *obj = fp->scopeChainObj();
+    if (op == JSOP_GETGNAME || op == JSOP_CALLGNAME)
+        obj = obj->getGlobal();
 
     JSScopeProperty *sprop;
     Value rval;
 
     PropertyCacheEntry *entry;
     JSObject *obj2;
     JSAtom *atom;
     JS_PROPERTY_CACHE(cx).test(cx, regs.pc, obj, obj2, entry, atom);
@@ -2482,17 +2443,17 @@ BEGIN_CASE(JSOP_CALLNAME)
         NATIVE_GET(cx, obj, obj2, sprop, JSGET_METHOD_BARRIER, &rval);
         JS_UNLOCK_OBJ(cx, obj2);
     }
 
     PUSH_COPY(rval);
 
   do_push_obj_if_call:
     /* obj must be on the scope chain, thus not a function. */
-    if (op == JSOP_CALLNAME)
+    if (op == JSOP_CALLNAME || op == JSOP_CALLGNAME)
         PUSH_NONFUNOBJ(*obj);
 }
 END_CASE(JSOP_NAME)
 
 BEGIN_CASE(JSOP_UINT16)
     PUSH_INT32((int32_t) GET_UINT16(regs.pc));
 END_CASE(JSOP_UINT16)
 
@@ -2978,81 +2939,16 @@ BEGIN_CASE(JSOP_SETGLOBAL)
             goto error;
         }
         obj->lockedSetSlot(slot, regs.sp[-1]);
         JS_UNLOCK_SCOPE(cx, scope);
     }
 }
 END_SET_CASE(JSOP_SETGLOBAL)
 
-BEGIN_CASE(JSOP_GETGVAR)
-BEGIN_CASE(JSOP_CALLGVAR)
-{
-    uint32 slot = GET_SLOTNO(regs.pc);
-    JS_ASSERT(slot < GlobalVarCount(fp));
-    METER_SLOT_OP(op, slot);
-    const Value &lval = fp->slots()[slot];
-    if (lval.isNull()) {
-        op = (op == JSOP_GETGVAR) ? JSOP_NAME : JSOP_CALLNAME;
-        DO_OP();
-    }
-    JS_ASSERT(fp->varobj(cx) == cx->activeCallStack()->getInitialVarObj());
-    JSObject *varobj = cx->activeCallStack()->getInitialVarObj();
-
-    /* XXX all this code assumes that varobj is either a callobj or global and
-     * that it cannot be accessed in a MT way. This is either true now or
-     * coming soon. */
-
-    slot = (uint32)lval.asInt32();
-    const Value &rref = varobj->lockedGetSlot(slot);
-    PUSH_COPY(rref);
-    if (op == JSOP_CALLGVAR)
-        PUSH_NULL();
-}
-END_CASE(JSOP_GETGVAR)
-
-BEGIN_CASE(JSOP_SETGVAR)
-{
-    uint32 slot = GET_SLOTNO(regs.pc);
-    JS_ASSERT(slot < GlobalVarCount(fp));
-    METER_SLOT_OP(op, slot);
-    const Value &rref = regs.sp[-1];
-    JS_ASSERT(fp->varobj(cx) == cx->activeCallStack()->getInitialVarObj());
-    JSObject *obj = cx->activeCallStack()->getInitialVarObj();
-    const Value &lref = fp->slots()[slot];
-    if (lref.isNull()) {
-        /*
-         * Inline-clone and deoptimize JSOP_SETNAME code here because
-         * JSOP_SETGVAR has arity 1: [rref], not arity 2: [obj, rref]
-         * as JSOP_SETNAME does, where [obj] is due to JSOP_BINDNAME.
-         */
-#ifdef JS_TRACER
-        if (TRACE_RECORDER(cx))
-            AbortRecording(cx, "SETGVAR with NULL slot");
-#endif
-        JSAtom *atom;
-        LOAD_ATOM(0, atom);
-        jsid id = ATOM_TO_JSID(atom);
-        Value rval = rref;
-        if (!obj->setProperty(cx, id, &rval))
-            goto error;
-    } else {
-        uint32 slot = (uint32)lref.asInt32();
-        JS_LOCK_OBJ(cx, obj);
-        JSScope *scope = obj->scope();
-        if (!scope->methodWriteBarrier(cx, slot, rref)) {
-            JS_UNLOCK_SCOPE(cx, scope);
-            goto error;
-        }
-        obj->lockedSetSlot(slot, rref);
-        JS_UNLOCK_SCOPE(cx, scope);
-    }
-}
-END_SET_CASE(JSOP_SETGVAR)
-
 BEGIN_CASE(JSOP_DEFCONST)
 BEGIN_CASE(JSOP_DEFVAR)
 {
     uint32 index = GET_INDEX(regs.pc);
     JSAtom *atom = atoms[index];
 
     /*
      * index is relative to atoms at this point but for global var
@@ -3088,41 +2984,16 @@ BEGIN_CASE(JSOP_DEFVAR)
         if (!js_DefineNativeProperty(cx, obj, id, Value(UndefinedTag()), PropertyStub, PropertyStub,
                                      attrs, 0, 0, &prop)) {
             goto error;
         }
         JS_ASSERT(prop);
         obj2 = obj;
     }
 
-    /*
-     * Try to optimize a property we either just created, or found
-     * directly in the global object, that is permanent, has a slot,
-     * and has stub getter and setter, into a "fast global" accessed
-     * by the JSOP_*GVAR opcodes.
-     */
-    if (!fp->fun &&
-        index < GlobalVarCount(fp) &&
-        obj2 == obj &&
-        obj->isNative()) {
-        JSScopeProperty *sprop = (JSScopeProperty *) prop;
-        if (!sprop->configurable() &&
-            SPROP_HAS_VALID_SLOT(sprop, obj->scope()) &&
-            sprop->hasDefaultGetterOrIsMethod() &&
-            sprop->hasDefaultSetter()) {
-            /*
-             * Fast globals use frame variables to map the global name's atom
-             * index to the permanent varobj slot number, tagged as a jsval.
-             * The atom index for the global's name literal is identical to its
-             * variable index.
-             */
-            fp->slots()[index].setInt32(sprop->slot);
-        }
-    }
-
     obj2->dropProperty(cx, prop);
 }
 END_CASE(JSOP_DEFVAR)
 
 BEGIN_CASE(JSOP_DEFFUN)
 {
     PropertyOp getter, setter;
     bool doSet;
@@ -4507,11 +4378,9 @@ END_CASE(JSOP_ARRAYPUSH)
   L_JSOP_TOATTRNAME:
   L_JSOP_QNAME:
   L_JSOP_QNAMECONST:
   L_JSOP_QNAMEPART:
   L_JSOP_ANYNAME:
   L_JSOP_DEFXMLNS:
 # endif
 
-  L_JSOP_UNUSED218:
-
 #endif /* !JS_THREADED_INTERP */
--- a/js/src/jsparse.cpp
+++ b/js/src/jsparse.cpp
@@ -3394,74 +3394,32 @@ DefineGlobal(JSParseNode *pn, JSCodeGene
 }
 
 /*
  * If compile-and-go, and a global object is present, try to bake in either
  * an already available slot or a predicted slot that will be defined after
  * compiling is completed.
  *
  * If not compile-and-go, or compiling for eval, this optimization is invalid.
- * The old path (explained below), which works for global references only, is
- * thus preserved at the bottom of BindGvar().
- *
- * If we are generating global or eval-called-from-global code, bind a "gvar"
- * here, as soon as possible. The JSOP_GETGVAR, etc., ops speed up interpreted
- * global variable access by memoizing name-to-slot mappings during execution
- * of the script prolog (via JSOP_DEFVAR/JSOP_DEFCONST). If the memoization
- * can't be done due to a pre-existing property of the same name as the var or
- * const but incompatible attributes/getter/setter/etc, these ops devolve to
- * JSOP_NAME, etc.
- *
- * For now, don't try to lookup eval frame variables at compile time. This is
- * sub-optimal: we could handle eval-called-from-global-code gvars since eval
- * gets its own script and frame. The eval-from-function-code case is harder,
- * since functions do not atomize gvars and then reserve their atom indexes as
- * stack frame slots.
  */
 static bool
-BindGvar(JSParseNode *pn, JSTreeContext *tc, bool inWith = false)
+BindGvar(JSParseNode *pn, JSTreeContext *tc)
 {
     JS_ASSERT(pn->pn_op == JSOP_NAME);
     JS_ASSERT(!tc->inFunction());
 
     if (!tc->compiling() || tc->parser->callerFrame)
         return true;
 
     JSCodeGenerator *cg = (JSCodeGenerator *) tc;
 
-    if (!(pn->pn_dflags & PND_CONST) && !inWith) {
-        if (!DefineGlobal(pn, cg, pn->pn_atom))
-            return false;
-        if (pn->pn_dflags & PND_BOUND)
-            return true;
-    }
-
-    /* If direct binding failed, try the old gvar optimization. */
-
-    /* Index pn->pn_atom so we can map fast global number to name. */
-    JSAtomListElement *ale = cg->atomList.add(tc->parser, pn->pn_atom);
-    if (!ale)
-        return false;
-
-    /* Defend against cg->ngvars 16-bit overflow. */
-    uintN slot = ALE_INDEX(ale);
-    if ((slot + 1) >> 16)
+    if (pn->pn_dflags & PND_CONST)
         return true;
 
-    if ((uint16)(slot + 1) > cg->ngvars)
-        cg->ngvars = (uint16)(slot + 1);
-
-    /* See bug 561011; don't optimize, but slot must be reserved above. */
-    if (!inWith) {
-        pn->pn_op = JSOP_GETGVAR;
-        pn->pn_cookie = MAKE_UPVAR_COOKIE(tc->staticLevel, slot);
-        pn->pn_dflags |= PND_BOUND | PND_GVAR;
-    }
-
-    return true;
+    return DefineGlobal(pn, cg, pn->pn_atom);
 }
 
 static JSBool
 BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc)
 {
     JSParseNode *pn = data->pn;
 
     /* Default best op for pn is JSOP_NAME; we'll try to improve below. */
@@ -3469,17 +3427,17 @@ BindVarOrConst(JSContext *cx, BindData *
 
     if (!CheckStrictBinding(cx, tc, atom, pn))
         return false;
 
     JSStmtInfo *stmt = js_LexicalLookup(tc, atom, NULL);
 
     if (stmt && stmt->type == STMT_WITH) {
         data->fresh = false;
-        return tc->inFunction() || BindGvar(pn, tc, true);
+        return true;
     }
 
     JSAtomListElement *ale = tc->decls.lookup(atom);
     JSOp op = data->op;
 
     if (stmt || ale) {
         JSDefinition *dn = ale ? ALE_DEFN(ale) : NULL;
         JSDefinition::Kind dn_kind = dn ? dn->kind() : JSDefinition::VAR;
@@ -3726,22 +3684,21 @@ 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_GETGVAR || PN_OP(pn) == JSOP_GETGLOBAL);
+        JS_ASSERT_IF((pn->pn_dflags & PND_GVAR), PN_OP(pn) == JSOP_GETGLOBAL);
         pn->pn_op = (pn->pn_op == JSOP_ARGUMENTS)
                     ? JSOP_SETNAME
                     : (pn->pn_dflags & PND_GVAR)
-                    ? (PN_OP(pn) == JSOP_GETGVAR ? JSOP_SETGVAR : JSOP_SETGLOBAL)
+                    ? JSOP_SETGLOBAL
                     : JSOP_SETLOCAL;
     } else {
         pn->pn_op = (data->op == JSOP_DEFCONST)
                     ? JSOP_SETCONST
                     : JSOP_SETNAME;
     }
 
     if (data->op == JSOP_DEFCONST)
@@ -5986,23 +5943,22 @@ 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_GETGVAR || PN_OP(pn2) == JSOP_GETGLOBAL);
+            JS_ASSERT_IF((pn2->pn_dflags & PND_GVAR), PN_OP(pn2) == JSOP_GETGLOBAL);
 
             pn2->pn_op = (PN_OP(pn2) == JSOP_ARGUMENTS)
                          ? JSOP_SETNAME
                          : (pn2->pn_dflags & PND_GVAR)
-                         ? (PN_OP(pn2) == JSOP_GETGVAR ? JSOP_SETGVAR : JSOP_SETGLOBAL)
+                         ? 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/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -72,17 +72,17 @@
 #include "jsscriptinlines.h"
 
 using namespace js;
 
 static const jsbytecode emptyScriptCode[] = {JSOP_STOP, SRC_NULL};
 
 /* static */ const JSScript JSScript::emptyScriptConst = {
     const_cast<jsbytecode*>(emptyScriptCode),
-    1, JSVERSION_DEFAULT, 0, 0, 0, 0, 0, 0, 0, true, false, false, false,
+    1, JSVERSION_DEFAULT, 0, 0, 0, 0, 0, 0, 0, true, false, false, false, false,
     const_cast<jsbytecode*>(emptyScriptCode),
     {0, NULL}, NULL, 0, 0, 0, NULL
 };
 
 #if JS_HAS_XDR
 
 JSBool
 js_XDRScript(JSXDRState *xdr, JSScript **scriptp, bool needMutableScript,
@@ -1088,16 +1088,18 @@ js_NewScriptFromCG(JSContext *cx, JSCode
     if (cg->constList.length() != 0)
         cg->constList.finish(script->consts());
     if (cg->flags & TCF_NO_SCRIPT_RVAL)
         script->noScriptRval = true;
     if (cg->hasSharps())
         script->hasSharps = true;
     if (cg->flags & TCF_STRICT_MODE_CODE)
         script->strictModeCode = true;
+    if (cg->flags & TCF_COMPILE_N_GO)
+        script->compileAndGo = true;
 
     if (cg->upvarList.count != 0) {
         JS_ASSERT(cg->upvarList.count <= cg->upvarMap.length);
         memcpy(script->upvars()->vector, cg->upvarMap.vector,
                cg->upvarList.count * sizeof(uint32));
         cg->upvarList.clear();
         cx->free(cg->upvarMap.vector);
         cg->upvarMap.vector = NULL;
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -148,16 +148,17 @@ struct JSScript {
                                        0 if none */
     uint8           constOffset;    /* offset to the array of constants or
                                        0 if none */
     bool            noScriptRval:1; /* no need for result value of last
                                        expression statement */
     bool            savedCallerFun:1; /* object 0 is caller function */
     bool            hasSharps:1;      /* script uses sharp variables */
     bool            strictModeCode:1; /* code is in strict mode */
+    bool            compileAndGo:1;   /* script was compiled with TCF_COMPILE_N_GO */
 
     jsbytecode      *main;      /* main entry point, after predef'ing prolog */
     JSAtomMap       atomMap;    /* maps immediate index to literal struct */
     const char      *filename;  /* source filename or null */
     uint32          lineno;     /* base line number of script */
     uint16          nslots;     /* vars plus maximum stack depth */
     uint16          staticLevel;/* static level for display maintenance */
     JSPrincipals    *principals;/* principals for this script */
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -11629,16 +11629,17 @@ TraceRecorder::record_SetPropHit(Propert
     jsbytecode* pc = cx->regs->pc;
 
     bool isDefinitelyAtom = (*pc == JSOP_SETPROP);
     CHECK_STATUS_A(setProp(l, entry, sprop, r, v_ins, isDefinitelyAtom));
 
     switch (*pc) {
       case JSOP_SETPROP:
       case JSOP_SETNAME:
+      case JSOP_SETGNAME:
       case JSOP_SETMETHOD:
         if (pc[JSOP_SETPROP_LENGTH] != JSOP_POP)
             set(&l, v_ins);
         break;
 
       default:;
     }
 
@@ -12933,16 +12934,19 @@ TraceRecorder::record_NativeCallComplete
     // cycle.  There must be a next op since the stack is non-empty.
     return ARECORD_CONTINUE;
 }
 
 JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::name(Value*& vp, LIns*& ins, NameResult& nr)
 {
     JSObject* obj = cx->fp->scopeChainObj();
+    JSOp op = JSOp(*cx->regs->pc);
+    if (js_CodeSpec[op].format & JOF_GNAME)
+        obj = obj->getGlobal();
     if (obj != globalObj)
         return scopeChainProp(obj, vp, ins, nr);
 
     /* Can't use prop here, because we don't want unboxing from global slots. */
     LIns* obj_ins = INS_CONSTOBJ(globalObj);
     uint32 slot;
 
     JSObject* obj2;
@@ -14627,112 +14631,16 @@ TraceRecorder::record_JSOP_SETRVAL()
 
 JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_RETRVAL()
 {
     return ARECORD_STOP;
 }
 
 JS_REQUIRES_STACK AbortableRecordingStatus
-TraceRecorder::record_JSOP_GETGVAR()
-{
-    Value slotval = cx->fp->slots()[GET_SLOTNO(cx->regs->pc)];
-    if (slotval.isNull())
-        return ARECORD_CONTINUE; // We will see JSOP_NAME from the interpreter's jump, so no-op here.
-
-    uint32 slot = slotval.asInt32();
-
-    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_SETGVAR()
-{
-    Value slotval = cx->fp->slots()[GET_SLOTNO(cx->regs->pc)];
-    if (slotval.isNull())
-        return ARECORD_CONTINUE; // We will see JSOP_NAME from the interpreter's jump, so no-op here.
-
-    uint32 slot = slotval.asInt32();
-
-    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_INCGVAR()
-{
-    Value slotval = cx->fp->slots()[GET_SLOTNO(cx->regs->pc)];
-    if (slotval.isNull())
-        // We will see JSOP_INCNAME from the interpreter's jump, so no-op here.
-        return ARECORD_CONTINUE;
-
-    uint32 slot = slotval.asInt32();
-
-    if (!lazilyImportGlobalSlot(slot))
-         RETURN_STOP_A("lazy import of global slot failed");
-
-    return InjectStatus(inc(globalObj->getSlotRef(slot), 1));
-}
-
-JS_REQUIRES_STACK AbortableRecordingStatus
-TraceRecorder::record_JSOP_DECGVAR()
-{
-    Value slotval = cx->fp->slots()[GET_SLOTNO(cx->regs->pc)];
-    if (slotval.isNull())
-        // We will see JSOP_INCNAME from the interpreter's jump, so no-op here.
-        return ARECORD_CONTINUE;
-
-    uint32 slot = slotval.asInt32();
-
-    if (!lazilyImportGlobalSlot(slot))
-         RETURN_STOP_A("lazy import of global slot failed");
-
-    return InjectStatus(inc(globalObj->getSlotRef(slot), -1));
-}
-
-JS_REQUIRES_STACK AbortableRecordingStatus
-TraceRecorder::record_JSOP_GVARINC()
-{
-    Value slotval = cx->fp->slots()[GET_SLOTNO(cx->regs->pc)];
-    if (slotval.isNull())
-        // We will see JSOP_INCNAME from the interpreter's jump, so no-op here.
-        return ARECORD_CONTINUE;
-
-    uint32 slot = slotval.asInt32();
-
-    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_GVARDEC()
-{
-    Value slotval = cx->fp->slots()[GET_SLOTNO(cx->regs->pc)];
-    if (slotval.isNull())
-        // We will see JSOP_INCNAME from the interpreter's jump, so no-op here.
-        return ARECORD_CONTINUE;
-
-    uint32 slot = slotval.asInt32();
-
-    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_REGEXP()
 {
     JSStackFrame* const fp = cx->fp;
     JSScript* script = fp->script;
     unsigned index = atoms - script->atomMap.vector + GET_INDEX(cx->regs->pc);
 
     LIns* proto_ins;
     CHECK_STATUS_A(getClassPrototype(JSProto_RegExp, proto_ins));
@@ -15188,35 +15096,16 @@ TraceRecorder::record_JSOP_INDEXBASE2()
 JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_INDEXBASE3()
 {
     atoms += 3 << 16;
     return ARECORD_CONTINUE;
 }
 
 JS_REQUIRES_STACK AbortableRecordingStatus
-TraceRecorder::record_JSOP_CALLGVAR()
-{
-    Value slotval = cx->fp->slots()[GET_SLOTNO(cx->regs->pc)];
-    if (slotval.isNull())
-        // We will see JSOP_CALLNAME from the interpreter's jump, so no-op here.
-        return ARECORD_CONTINUE;
-
-    uint32 slot = slotval.asInt32();
-
-    if (!lazilyImportGlobalSlot(slot))
-         RETURN_STOP_A("lazy import of global slot failed");
-
-    Value& v = globalObj->getSlotRef(slot);
-    stack(0, get(&v));
-    stack(1, INS_NULL());
-    return ARECORD_CONTINUE;
-}
-
-JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_CALLLOCAL()
 {
     uintN slot = GET_SLOTNO(cx->regs->pc);
     stack(0, var(slot));
     stack(1, INS_NULL());
     return ARECORD_CONTINUE;
 }
 
@@ -15225,19 +15114,20 @@ TraceRecorder::record_JSOP_CALLARG()
 {
     uintN slot = GET_ARGNO(cx->regs->pc);
     stack(0, arg(slot));
     stack(1, INS_NULL());
     return ARECORD_CONTINUE;
 }
 
 JS_REQUIRES_STACK AbortableRecordingStatus
-TraceRecorder::record_JSOP_UNUSED218()
-{
-    return ARECORD_ABORTED;
+TraceRecorder::record_JSOP_BINDGNAME()
+{
+    stack(0, INS_CONSTOBJ(globalObj));
+    return ARECORD_CONTINUE;
 }
 
 JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_INT8()
 {
     stack(0, lir->insImmD(GET_INT8(cx->regs->pc)));
     return ARECORD_CONTINUE;
 }
@@ -15513,16 +15403,58 @@ 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()
+{
+    return record_JSOP_SETNAME();
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
+TraceRecorder::record_JSOP_GNAMEDEC()
+{
+    return record_JSOP_NAMEDEC();
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
+TraceRecorder::record_JSOP_GNAMEINC()
+{
+    return record_JSOP_NAMEINC();
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
+TraceRecorder::record_JSOP_DECGNAME()
+{
+    return record_JSOP_DECNAME();
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
+TraceRecorder::record_JSOP_INCGNAME()
+{
+    return record_JSOP_INCNAME();
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
+TraceRecorder::record_JSOP_CALLGNAME()
+{
+    return record_JSOP_CALLNAME();
+}
+
 #define DBG_STUB(OP)                                                          \
     JS_REQUIRES_STACK AbortableRecordingStatus                                \
     TraceRecorder::record_##OP()                                              \
     {                                                                         \
         RETURN_STOP_A("can't trace " #OP);                                    \
     }
 
 DBG_STUB(JSOP_GETUPVAR_DBG)
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -562,52 +562,64 @@ mjit::Compiler::generateMethod()
             frame.pop();
             frame.push(UndefinedTag());
           END_CASE(JSOP_VOID)
 
           BEGIN_CASE(JSOP_INCNAME)
             jsop_nameinc(op, stubs::IncName, fullAtomIndex(PC));
           END_CASE(JSOP_INCNAME)
 
+          BEGIN_CASE(JSOP_INCGNAME)
+            jsop_nameinc(op, stubs::IncGlobalName, fullAtomIndex(PC));
+          END_CASE(JSOP_INCGNAME)
+
           BEGIN_CASE(JSOP_INCPROP)
             jsop_propinc(op, stubs::IncProp, fullAtomIndex(PC));
           END_CASE(JSOP_INCPROP)
 
           BEGIN_CASE(JSOP_INCELEM)
             jsop_eleminc(op, stubs::IncElem);
           END_CASE(JSOP_INCELEM)
 
           BEGIN_CASE(JSOP_DECNAME)
             jsop_nameinc(op, stubs::DecName, fullAtomIndex(PC));
           END_CASE(JSOP_DECNAME)
 
+          BEGIN_CASE(JSOP_DECGNAME)
+            jsop_nameinc(op, stubs::DecGlobalName, fullAtomIndex(PC));
+          END_CASE(JSOP_DECGNAME)
+
           BEGIN_CASE(JSOP_DECPROP)
             jsop_propinc(op, stubs::DecProp, fullAtomIndex(PC));
           END_CASE(JSOP_DECPROP)
 
           BEGIN_CASE(JSOP_DECELEM)
             jsop_eleminc(op, stubs::DecElem);
           END_CASE(JSOP_DECELEM)
 
-          BEGIN_CASE(JSOP_NAMEINC)
-            jsop_nameinc(op, stubs::NameInc, fullAtomIndex(PC));
-          END_CASE(JSOP_NAMEINC)
+          BEGIN_CASE(JSOP_GNAMEINC)
+            jsop_nameinc(op, stubs::GlobalNameInc, fullAtomIndex(PC));
+          END_CASE(JSOP_GNAMEINC)
 
           BEGIN_CASE(JSOP_PROPINC)
             jsop_propinc(op, stubs::PropInc, fullAtomIndex(PC));
           END_CASE(JSOP_PROPINC)
 
           BEGIN_CASE(JSOP_ELEMINC)
             jsop_eleminc(op, stubs::ElemInc);
           END_CASE(JSOP_ELEMINC)
 
           BEGIN_CASE(JSOP_NAMEDEC)
             jsop_nameinc(op, stubs::NameDec, fullAtomIndex(PC));
           END_CASE(JSOP_NAMEDEC)
 
+          BEGIN_CASE(JSOP_GNAMEDEC)
+            jsop_nameinc(op, stubs::GlobalNameDec, fullAtomIndex(PC));
+          END_CASE(JSOP_GNAMEDEC)
+
           BEGIN_CASE(JSOP_PROPDEC)
             jsop_propinc(op, stubs::PropDec, fullAtomIndex(PC));
           END_CASE(JSOP_PROPDEC)
 
           BEGIN_CASE(JSOP_ELEMDEC)
             jsop_eleminc(op, stubs::ElemDec);
           END_CASE(JSOP_ELEMDEC)
 
@@ -820,16 +832,25 @@ mjit::Compiler::generateMethod()
           BEGIN_CASE(JSOP_CALLARG)
           {
             jsop_getarg(GET_SLOTNO(PC));
             if (op == JSOP_CALLARG)
                 frame.push(NullTag());
           }
           END_CASE(JSOP_GETARG)
 
+          BEGIN_CASE(JSOP_BINDGNAME)
+          {
+            if (script->compileAndGo && globalObj)
+                frame.push(NonFunObjTag(*globalObj));
+            else
+                jsop_bindname(fullAtomIndex(PC));
+          }
+          END_CASE(JSOP_BINDGNAME)
+
           BEGIN_CASE(JSOP_SETARG)
           {
             uint32 slot = GET_SLOTNO(PC);
             FrameEntry *top = frame.peek(-1);
 
             bool popped = PC[JSOP_SETARG_LENGTH] == JSOP_POP;
 
             RegisterID reg = frame.allocReg();
@@ -1050,16 +1071,42 @@ mjit::Compiler::generateMethod()
             frame.pop();
           }
           END_CASE(JSOP_DEFLOCALFUN)
 
           BEGIN_CASE(JSOP_RETRVAL)
             emitReturn();
           END_CASE(JSOP_RETRVAL)
 
+          BEGIN_CASE(JSOP_GETGNAME)
+          BEGIN_CASE(JSOP_CALLGNAME)
+            prepareStubCall();
+            stubCall(stubs::GetGlobalName, Uses(0), Defs(1));
+            frame.pushSynced();
+            if (op == JSOP_CALLGNAME)
+                frame.push(NullTag());
+          END_CASE(JSOP_GETGNAME)
+
+          BEGIN_CASE(JSOP_SETGNAME)
+          {
+            JSAtom *atom = script->getAtom(fullAtomIndex(PC));
+            prepareStubCall();
+            masm.move(ImmPtr(atom), Registers::ArgReg1);
+            stubCall(stubs::SetGlobalName, Uses(2), Defs(1));
+            if (JSOp(PC[JSOP_SETGNAME_LENGTH]) == JSOP_POP &&
+                !analysis[&PC[JSOP_SETGNAME_LENGTH]].nincoming) {
+                frame.popn(2);
+                PC += JSOP_SETGNAME_LENGTH + JSOP_POP_LENGTH;
+                break;
+            }
+            frame.popn(2);
+            frame.pushSynced();
+          }
+          END_CASE(JSOP_SETGNAME)
+
           BEGIN_CASE(JSOP_REGEXP)
           {
             JSObject *regex = script->getRegExp(fullAtomIndex(PC));
             prepareStubCall();
             masm.move(ImmPtr(regex), Registers::ArgReg1);
             stubCall(stubs::RegExp, Uses(0), Defs(1));
             frame.takeReg(Registers::ReturnReg);
             frame.pushTypedPayload(JSVAL_MASK32_NONFUNOBJ, Registers::ReturnReg);
@@ -1236,17 +1283,18 @@ mjit::Compiler::generateMethod()
             /* Advances PC automatically. */
             jsop_globalinc(op, GET_SLOTNO(PC));
             break;
           END_CASE(JSOP_GLOBALINC)
 
           default:
            /* Sorry, this opcode isn't implemented yet. */
 #ifdef JS_METHODJIT_SPEW
-            JaegerSpew(JSpew_Abort, "opcode %s not handled yet\n", OpcodeNames[op]);
+            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;
         }
 
     /**********************
      *  END COMPILER OPS  *
      **********************/ 
 
--- a/js/src/methodjit/MethodJIT.h
+++ b/js/src/methodjit/MethodJIT.h
@@ -66,40 +66,20 @@ struct VMFrame
 
 #if defined(JS_CPU_X86)
     uintptr_t               padding[2];
 #elif defined(JS_CPU_ARM)
     uintptr_t               padding;
 #endif
 
     union Arguments {
-        struct DEFVAR {
-            jsatomid index;
-            uint32   op;
-        } defvar;
-        struct LAMBDA {
-            uint32 index;
-            JSOp   op;
-        } lambda;
-        struct INITPROP {
-            uint32   index;
-            unsigned defineHow;
-        } initprop;
-        struct DEFLOCALFUN {
-            uint32   slot;
-            uint32   index;
-        } deflocalfun;
-        struct TRACER {
-            uint32 traceId;
-            uint32 offs;
-        } tracer;
-        struct SETTER {
-            jsatomid index;
-            JSOp     op;
-        } setter;
+        struct {
+            void *ptr;
+            void *ptr2;
+        } x;
     } u;
 
     JSFrameRegs  *oldRegs;
     JSFrameRegs  regs;
     JSStackFrame *fp;
     JSContext    *cx;
     uintptr_t    inlineCallCount;
 
--- a/js/src/methodjit/StubCalls.cpp
+++ b/js/src/methodjit/StubCalls.cpp
@@ -535,30 +535,34 @@ mjit::stubs::SetName(VMFrame &f, JSAtom 
             if (!obj->setProperty(cx, id, &rref))
                 THROW();
         }
     } while (0);
 
     f.regs.sp[-2] = f.regs.sp[-1];
 }
 
+void JS_FASTCALL
+stubs::SetGlobalName(VMFrame &f, JSAtom *atom)
+{
+    SetName(f, atom);
+}
+
 static void
 ReportAtomNotDefined(JSContext *cx, JSAtom *atom)
 {
     const char *printable = js_AtomToPrintableString(cx, atom);
     if (printable)
         js_ReportIsNotDefined(cx, printable);
 }
 
 static JSObject *
-NameOp(VMFrame &f)
+NameOp(VMFrame &f, JSObject *obj)
 {
     JSContext *cx = f.cx;
-    JSStackFrame *fp = f.fp;
-    JSObject *obj = fp->scopeChainObj();
 
     JSScopeProperty *sprop;
     Value rval;
 
     PropertyCacheEntry *entry;
     JSObject *obj2;
     JSAtom *atom;
     JS_PROPERTY_CACHE(cx).test(cx, f.regs.pc, obj, obj2, entry, atom);
@@ -614,20 +618,28 @@ NameOp(VMFrame &f)
     f.regs.sp++;
     f.regs.sp[-1] = rval;
     return obj;
 }
 
 void JS_FASTCALL
 stubs::Name(VMFrame &f)
 {
-    if (!NameOp(f))
+    if (!NameOp(f, f.fp->scopeChainObj()))
         THROW();
 }
 
+void JS_FASTCALL
+stubs::GetGlobalName(VMFrame &f)
+{
+    JSObject *globalObj = f.fp->scopeChainObj()->getGlobal();
+    if (!NameOp(f, globalObj))
+         THROW();
+}
+
 static inline bool
 IteratorNext(JSContext *cx, JSObject *iterobj, Value *rval)
 {
     if (iterobj->getClass() == &js_IteratorClass.base) {
         NativeIterator *ni = (NativeIterator *) iterobj->getPrivate();
         JS_ASSERT(ni->props_cursor < ni->props_end);
         *rval = ID_TO_VALUE(*ni->props_cursor);
         if (rval->isString() || (ni->flags & JSITER_FOREACH)) {
@@ -833,17 +845,17 @@ stubs::SetElem(VMFrame &f)
      * of popAfterSet() that allows popping more than one value;
      * this logic can then be handled in Compiler.cpp. */
     regs.sp[-3] = retval;
 }
 
 void JS_FASTCALL
 stubs::CallName(VMFrame &f)
 {
-    JSObject *obj = NameOp(f);
+    JSObject *obj = NameOp(f, f.fp->scopeChainObj());
     if (!obj)
         THROW();
     f.regs.sp++;
     f.regs.sp[-1].setNonFunObj(*obj);
 }
 
 void JS_FASTCALL
 stubs::BitOr(VMFrame &f)
@@ -2020,26 +2032,24 @@ ObjIncOp(VMFrame &f, JSObject *obj, jsid
             return false;
     }
 
     return true;
 }
 
 template <int32 N, bool POST>
 static inline bool
-NameIncDec(VMFrame &f, JSAtom *origAtom)
+NameIncDec(VMFrame &f, JSObject *obj, JSAtom *origAtom)
 {
     JSContext *cx = f.cx;
-    JSStackFrame *fp = f.fp;
 
     JSAtom *atom;
     JSObject *obj2;
     JSProperty *prop;
     PropertyCacheEntry *entry;
-    JSObject *obj = fp->scopeChainObj();
     JS_PROPERTY_CACHE(cx).test(cx, f.regs.pc, obj, obj2, entry, atom);
     if (!atom) {
         if (obj == obj2 && entry->vword.isSlot()) {
             uint32 slot = entry->vword.toSlot();
             JS_ASSERT(slot < obj->scope()->freeslot);
             Value &rref = obj->getSlotRef(slot);
             int32_t tmp;
             if (JS_LIKELY(rref.isInt32() && CanIncDecWithoutOverflow(tmp = rref.asInt32()))) {
@@ -2163,38 +2173,74 @@ stubs::DecElem(VMFrame &f)
     if (!ObjIncOp<-1, false>(f, obj, id))
         THROW();
     f.regs.sp[-3] = f.regs.sp[-1];
 }
 
 void JS_FASTCALL
 stubs::NameInc(VMFrame &f, JSAtom *atom)
 {
-    if (!NameIncDec<1, true>(f, atom))
+    JSObject *obj = f.fp->scopeChainObj();
+    if (!NameIncDec<1, true>(f, obj, atom))
         THROW();
 }
 
 void JS_FASTCALL
 stubs::NameDec(VMFrame &f, JSAtom *atom)
 {
-    if (!NameIncDec<-1, true>(f, atom))
+    JSObject *obj = f.fp->scopeChainObj();
+    if (!NameIncDec<-1, true>(f, obj, atom))
         THROW();
 }
 
 void JS_FASTCALL
 stubs::IncName(VMFrame &f, JSAtom *atom)
 {
-    if (!NameIncDec<1, false>(f, atom))
+    JSObject *obj = f.fp->scopeChainObj();
+    if (!NameIncDec<1, false>(f, obj, atom))
         THROW();
 }
 
 void JS_FASTCALL
 stubs::DecName(VMFrame &f, JSAtom *atom)
 {
-    if (!NameIncDec<-1, false>(f, atom))
+    JSObject *obj = f.fp->scopeChainObj();
+    if (!NameIncDec<-1, false>(f, obj, atom))
+        THROW();
+}
+
+void JS_FASTCALL
+stubs::GlobalNameInc(VMFrame &f, JSAtom *atom)
+{
+    JSObject *obj = f.fp->scopeChainObj()->getGlobal();
+    if (!NameIncDec<1, true>(f, obj, atom))
+        THROW();
+}
+
+void JS_FASTCALL
+stubs::GlobalNameDec(VMFrame &f, JSAtom *atom)
+{
+    JSObject *obj = f.fp->scopeChainObj()->getGlobal();
+    if (!NameIncDec<-1, true>(f, obj, atom))
+        THROW();
+}
+
+void JS_FASTCALL
+stubs::IncGlobalName(VMFrame &f, JSAtom *atom)
+{
+    JSObject *obj = f.fp->scopeChainObj()->getGlobal();
+    if (!NameIncDec<1, false>(f, obj, atom))
+        THROW();
+}
+
+void JS_FASTCALL
+stubs::DecGlobalName(VMFrame &f, JSAtom *atom)
+{
+    JSObject *obj = f.fp->scopeChainObj()->getGlobal();
+    if (!NameIncDec<-1, false>(f, obj, atom))
         THROW();
 }
 
 static bool JS_FASTCALL
 InlineGetProp(VMFrame &f)
 {
     JSContext *cx = f.cx;
     JSFrameRegs &regs = f.regs;
--- a/js/src/methodjit/StubCalls.h
+++ b/js/src/methodjit/StubCalls.h
@@ -62,29 +62,35 @@ void * JS_FASTCALL Call(VMFrame &f, uint
 void * JS_FASTCALL New(VMFrame &f, uint32 argc);
 void * JS_FASTCALL Return(VMFrame &f);
 void JS_FASTCALL Throw(VMFrame &f);
 void * JS_FASTCALL LookupSwitch(VMFrame &f, jsbytecode *pc);
 void * JS_FASTCALL TableSwitch(VMFrame &f, jsbytecode *origPc);
 
 void JS_FASTCALL BindName(VMFrame &f);
 void JS_FASTCALL SetName(VMFrame &f, JSAtom *atom);
+void JS_FASTCALL SetGlobalName(VMFrame &f, JSAtom *atom);
 void JS_FASTCALL Name(VMFrame &f);
 void JS_FASTCALL GetProp(VMFrame &f);
 void JS_FASTCALL GetElem(VMFrame &f);
 void JS_FASTCALL CallElem(VMFrame &f);
 void JS_FASTCALL SetElem(VMFrame &f);
 void JS_FASTCALL Length(VMFrame &f);
 void JS_FASTCALL CallName(VMFrame &f);
 void JS_FASTCALL GetUpvar(VMFrame &f, uint32 index);
+void JS_FASTCALL GetGlobalName(VMFrame &f);
 
 void JS_FASTCALL NameInc(VMFrame &f, JSAtom *atom);
 void JS_FASTCALL NameDec(VMFrame &f, JSAtom *atom);
 void JS_FASTCALL IncName(VMFrame &f, JSAtom *atom);
 void JS_FASTCALL DecName(VMFrame &f, JSAtom *atom);
+void JS_FASTCALL GlobalNameInc(VMFrame &f, JSAtom *atom);
+void JS_FASTCALL GlobalNameDec(VMFrame &f, JSAtom *atom);
+void JS_FASTCALL IncGlobalName(VMFrame &f, JSAtom *atom);
+void JS_FASTCALL DecGlobalName(VMFrame &f, JSAtom *atom);
 void JS_FASTCALL PropInc(VMFrame &f, JSAtom *atom);
 void JS_FASTCALL PropDec(VMFrame &f, JSAtom *atom);
 void JS_FASTCALL IncProp(VMFrame &f, JSAtom *atom);
 void JS_FASTCALL DecProp(VMFrame &f, JSAtom *atom);
 void JS_FASTCALL ElemInc(VMFrame &f);
 void JS_FASTCALL ElemDec(VMFrame &f);
 void JS_FASTCALL IncElem(VMFrame &f);
 void JS_FASTCALL DecElem(VMFrame &f);