bug=421274 r=brendan a=beltzner Eliminating SAVE_SP_AND_PC() macro
authorigor@mir2.org
Mon, 17 Mar 2008 01:58:28 -0700
changeset 13168 ca9fd7937bac1c08255a47b6f915cca6e054a8e0
parent 13167 3fd1d9fa068bb0f916d3a63c5be2e34dfd8e3600
child 13169 373de5f8625ec1623be04107034564089b7695a7
push idunknown
push userunknown
push dateunknown
reviewersbrendan, beltzner
bugs421274
milestone1.9b5pre
bug=421274 r=brendan a=beltzner Eliminating SAVE_SP_AND_PC() macro
dom/src/base/nsDOMClassInfo.cpp
js/src/js.c
js/src/jsapi.c
js/src/jscntxt.c
js/src/jsdbgapi.c
js/src/jsdtracef.c
js/src/jsexn.c
js/src/jsfun.c
js/src/jsgc.c
js/src/jsinterp.c
js/src/jsinterp.h
js/src/jsiter.c
js/src/jsiter.h
js/src/jsobj.c
js/src/jsopcode.c
js/src/jsstr.c
js/src/jsxml.c
js/src/liveconnect/nsCLiveconnect.cpp
--- a/dom/src/base/nsDOMClassInfo.cpp
+++ b/dom/src/base/nsDOMClassInfo.cpp
@@ -6186,18 +6186,18 @@ nsWindowSH::NewResolve(nsIXPConnectWrapp
     // Something went wrong, or the property got resolved. Return.
     return rv;
   }
 
   // Make a fast expando if we're assigning to (not declaring or
   // binding a name) a new undefined property that's not already
   // defined on our prototype chain. This way we can access this
   // expando w/o ever getting back into XPConnect.
-  if ((flags & (JSRESOLVE_ASSIGNING)) && (JSOp)*cx->fp->pc != JSOP_BINDNAME &&
-      win->IsInnerWindow()) {
+  if ((flags & (JSRESOLVE_ASSIGNING)) && cx->fp->regs &&
+      (JSOp)*cx->fp->regs->pc != JSOP_BINDNAME && win->IsInnerWindow()) {
     JSObject *realObj;
     wrapper->GetJSObject(&realObj);
 
     if (obj == realObj) {
       JSObject *proto = STOBJ_GET_PROTO(obj);
       if (proto) {
         jsid interned_id;
         JSProperty *prop = nsnull;
--- a/js/src/js.c
+++ b/js/src/js.c
@@ -2475,17 +2475,18 @@ EvalInContext(JSContext *cx, JSObject *o
         *rval = OBJECT_TO_JSVAL(sobj);
         ok = JS_TRUE;
     } else {
         fp = JS_GetScriptedCaller(cx, NULL);
         JS_SetGlobalObject(scx, sobj);
         JS_ToggleOptions(scx, JSOPTION_DONT_REPORT_UNCAUGHT);
         ok = JS_EvaluateUCScript(scx, sobj, src, srclen,
                                  fp->script->filename,
-                                 JS_PCToLineNumber(cx, fp->script, fp->pc),
+                                 JS_PCToLineNumber(cx, fp->script,
+                                                   fp->regs->pc),
                                  rval);
         if (!ok) {
             if (JS_GetPendingException(scx, &v))
                 JS_SetPendingException(cx, v);
             else
                 JS_ReportOutOfMemory(cx);
         }
     }
--- a/js/src/jsapi.c
+++ b/js/src/jsapi.c
@@ -5113,23 +5113,22 @@ JS_IsConstructing(JSContext *cx)
 {
     return cx->fp && (cx->fp->flags & JSFRAME_CONSTRUCTING);
 }
 
 JS_FRIEND_API(JSBool)
 JS_IsAssigning(JSContext *cx)
 {
     JSStackFrame *fp;
-    jsbytecode *pc;
 
     for (fp = cx->fp; fp && !fp->script; fp = fp->down)
         continue;
-    if (!fp || !(pc = fp->pc))
+    if (!fp || !fp->regs)
         return JS_FALSE;
-    return (js_CodeSpec[*pc].format & JOF_ASSIGNING) != 0;
+    return (js_CodeSpec[*fp->regs->pc].format & JOF_ASSIGNING) != 0;
 }
 
 JS_PUBLIC_API(void)
 JS_SetCallReturnValue2(JSContext *cx, jsval v)
 {
 #if JS_HAS_LVALUE_RETURN
     cx->rval2 = v;
     cx->rval2set = JS_TRUE;
--- a/js/src/jscntxt.c
+++ b/js/src/jscntxt.c
@@ -885,19 +885,19 @@ js_ReportOutOfMemory(JSContext *cx)
     report.flags = JSREPORT_ERROR;
     report.errorNumber = JSMSG_OUT_OF_MEMORY;
 
     /*
      * Walk stack until we find a frame that is associated with some script
      * rather than a native frame.
      */
     for (fp = cx->fp; fp; fp = fp->down) {
-        if (fp->script && fp->pc) {
+        if (fp->regs) {
             report.filename = fp->script->filename;
-            report.lineno = js_PCToLineNumber(cx, fp->script, fp->pc);
+            report.lineno = js_PCToLineNumber(cx, fp->script, fp->regs->pc);
             break;
         }
     }
 
     /*
      * If debugErrorHook is present then we give it a chance to veto sending
      * the error on to the regular ErrorReporter. We also clear a pending
      * exception if any now so the hooks can replace the out-of-memory error
@@ -955,19 +955,19 @@ js_ReportErrorVA(JSContext *cx, uintN fl
 
     memset(&report, 0, sizeof (struct JSErrorReport));
     report.flags = flags;
     report.errorNumber = JSMSG_USER_DEFINED_ERROR;
     report.ucmessage = ucmessage = js_InflateString(cx, message, &messagelen);
 
     /* Find the top-most active script frame, for best line number blame. */
     for (fp = cx->fp; fp; fp = fp->down) {
-        if (fp->script && fp->pc) {
+        if (fp->regs) {
             report.filename = fp->script->filename;
-            report.lineno = js_PCToLineNumber(cx, fp->script, fp->pc);
+            report.lineno = js_PCToLineNumber(cx, fp->script, fp->regs->pc);
             break;
         }
     }
 
     warning = JSREPORT_IS_WARNING(report.flags);
     if (warning && JS_HAS_WERROR_OPTION(cx)) {
         report.flags &= ~JSREPORT_WARNING;
         warning = JS_FALSE;
@@ -1167,19 +1167,19 @@ js_ReportErrorNumberVA(JSContext *cx, ui
     report.flags = flags;
     report.errorNumber = errorNumber;
 
     /*
      * If we can't find out where the error was based on the current frame,
      * see if the next frame has a script/pc combo we can use.
      */
     for (fp = cx->fp; fp; fp = fp->down) {
-        if (fp->script && fp->pc) {
+        if (fp->regs) {
             report.filename = fp->script->filename;
-            report.lineno = js_PCToLineNumber(cx, fp->script, fp->pc);
+            report.lineno = js_PCToLineNumber(cx, fp->script, fp->regs->pc);
             break;
         }
     }
 
     if (!js_ExpandErrorArguments(cx, callback, userRef, errorNumber,
                                  &message, &report, &warning, charArgs, ap)) {
         return JS_FALSE;
     }
--- a/js/src/jsdbgapi.c
+++ b/js/src/jsdbgapi.c
@@ -553,16 +553,17 @@ js_watch_set(JSContext *cx, JSObject *ob
                 JSClass *clasp;
                 JSFunction *fun;
                 JSScript *script;
                 JSBool injectFrame;
                 uintN nslots;
                 jsval smallv[5];
                 jsval *argv;
                 JSStackFrame frame;
+                JSFrameRegs regs;
 
                 closure = (JSObject *) wp->closure;
                 clasp = OBJ_GET_CLASS(cx, closure);
                 if (clasp == &js_FunctionClass) {
                     fun = GET_FUNCTION_PRIVATE(cx, closure);
                     script = FUN_SCRIPT(fun);
                 } else if (clasp == &js_ScriptClass) {
                     fun = NULL;
@@ -595,20 +596,23 @@ js_watch_set(JSContext *cx, JSObject *ob
                     }
 
                     argv[0] = OBJECT_TO_JSVAL(closure);
                     argv[1] = JSVAL_NULL;
                     memset(argv + 2, 0, (nslots - 2) * sizeof(jsval));
 
                     memset(&frame, 0, sizeof(frame));
                     frame.script = script;
+                    frame.regs = NULL;
                     if (script) {
                         JS_ASSERT(script->length >= JSOP_STOP_LENGTH);
-                        frame.pc = script->code + script->length
-                                   - JSOP_STOP_LENGTH;
+                        regs.pc = script->code + script->length
+                                  - JSOP_STOP_LENGTH;
+                        regs.sp = NULL;
+                        frame.regs = &regs;
                     }
                     frame.callee = closure;
                     frame.fun = fun;
                     frame.argv = argv + 2;
                     frame.down = cx->fp;
                     frame.scopeChain = OBJ_GET_PARENT(cx, closure);
 
                     cx->fp = &frame;
@@ -951,17 +955,17 @@ JS_PUBLIC_API(JSScript *)
 JS_GetFrameScript(JSContext *cx, JSStackFrame *fp)
 {
     return fp->script;
 }
 
 JS_PUBLIC_API(jsbytecode *)
 JS_GetFramePC(JSContext *cx, JSStackFrame *fp)
 {
-    return fp->pc;
+    return fp->regs ? fp->regs->pc : NULL;
 }
 
 JS_PUBLIC_API(JSStackFrame *)
 JS_GetScriptedCaller(JSContext *cx, JSStackFrame *fp)
 {
     if (!fp)
         fp = cx->fp;
     while (fp) {
--- a/js/src/jsdtracef.c
+++ b/js/src/jsdtracef.c
@@ -69,18 +69,18 @@ jsdtrace_filename(JSStackFrame *fp)
            : dempty;
 }
 
 int
 jsdtrace_linenumber(JSContext *cx, JSStackFrame *fp)
 {
     while (fp && fp->script == NULL)
         fp = fp->down;
-    return (fp && fp->script && fp->pc)
-           ? js_PCToLineNumber(cx, fp->script, fp->pc)
+    return (fp && fp->regs)
+           ? js_PCToLineNumber(cx, fp->script, fp->regs->pc)
            : -1;
 }
 
 /*
  * This function is used to convert function arguments and return value (jsval)
  * into the following based on each value's type tag:
  *
  *      jsval      returned
@@ -125,49 +125,46 @@ jsdtrace_jsvaltovoid(JSContext *cx, jsva
     }
     /* NOTREACHED */
 }
 
 char *
 jsdtrace_function_name(JSContext *cx, JSStackFrame *fp, JSFunction *fun)
 {
     JSAtom *atom;
+    JSFrameRegs *regs;
     JSScript *script;
     jsbytecode *pc;
     char *name;
 
     atom = fun->atom;
     if (!atom) {
         if (fp->fun != fun || !fp->down)
             return dempty;
 
-        script = fp->down->script;
-        pc = fp->down->pc;
-        if (!script || !pc)
+        regs = fp->down->regs;
+        if (!regs)
             return dempty;
 
         /*
          * An anonymous function called from an active script or interpreted
          * function: try to fetch the variable or property name by which the
-         * anonymous function was invoked. First handle call ops by recovering
-         * the generating pc for the callee expression at argv[-2].
+         * anonymous function was invoked.
          */
+        pc = regs->pc;
+        script = fp->down->script;
         switch ((JSOp) *pc) {
           case JSOP_CALL:
           case JSOP_EVAL:
-            JS_ASSERT(fp->argv == fp->down->sp - (int)GET_ARGC(pc));
-
-            pc = (jsbytecode *) fp->argv[-2 - (int)script->depth];
+            JS_ASSERT(fp->argv == regs->sp - (int)GET_ARGC(pc));
 
             /*
-             * Be paranoid about bugs to-do with generating pc storage when
-             * attempting to descend into the operand stack basement.
+             * FIXME bug 422864: update this code to use the pc stack from the
+             * decompiler.
              */
-            if ((uintptr_t)(pc - script->code) >= script->length)
-                return dempty;
             break;
         }
 
         switch ((JSOp) *pc) {
           case JSOP_CALLNAME:
           case JSOP_CALLPROP:
           case JSOP_NAME:
           case JSOP_SETNAME:
--- a/js/src/jsexn.c
+++ b/js/src/jsexn.c
@@ -327,18 +327,18 @@ InitExnPrivate(JSContext *cx, JSObject *
             elem->argc = fp->argc;
             memcpy(values, fp->argv, fp->argc * sizeof(jsval));
             values += fp->argc;
         }
         elem->ulineno = 0;
         elem->filename = NULL;
         if (fp->script) {
             elem->filename = fp->script->filename;
-            if (fp->pc)
-                elem->ulineno = js_PCToLineNumber(cx, fp->script, fp->pc);
+            if (fp->regs)
+                elem->ulineno = js_PCToLineNumber(cx, fp->script, fp->regs->pc);
         }
         ++elem;
     }
     JS_ASSERT(priv->stackElems + stackDepth == elem);
     JS_ASSERT(GetStackTraceValueBuffer(priv) + valueCount == values);
 
     STOBJ_SET_SLOT(exnObject, JSSLOT_PRIVATE, PRIVATE_TO_JSVAL(priv));
 
@@ -794,17 +794,19 @@ Exception(JSContext *cx, JSObject *obj, 
     /* Set the 'lineNumber' property. */
     if (argc > 2) {
         lineno = js_ValueToECMAUint32(cx, &argv[2]);
         if (JSVAL_IS_NULL(argv[2]))
             return JS_FALSE;
     } else {
         if (!fp)
             fp = JS_GetScriptedCaller(cx, NULL);
-        lineno = (fp && fp->pc) ? js_PCToLineNumber(cx, fp->script, fp->pc) : 0;
+        lineno = (fp && fp->regs)
+                 ? js_PCToLineNumber(cx, fp->script, fp->regs->pc)
+                 : 0;
     }
 
     return (OBJ_GET_CLASS(cx, obj) != &js_ErrorClass) ||
             InitExnPrivate(cx, obj, message, filename, lineno, NULL);
 }
 
 /*
  * Convert to string.
--- a/js/src/jsfun.c
+++ b/js/src/jsfun.c
@@ -2196,35 +2196,36 @@ js_ValueToCallableObject(JSContext *cx, 
 
 void
 js_ReportIsNotFunction(JSContext *cx, jsval *vp, uintN flags)
 {
     JSStackFrame *fp;
     uintN error;
     const char *name, *source;
 
-    for (fp = cx->fp; fp && !fp->spbase; fp = fp->down)
+    for (fp = cx->fp; fp && !fp->regs; fp = fp->down)
         continue;
     name = NULL;
     source = NULL;
     if (flags & JSV2F_ITERATOR) {
         error = JSMSG_BAD_ITERATOR;
         name = js_iterator_str;
         source = js_ValueToPrintableSource(cx, *vp);
         if (!source)
             return;
     } else if (flags & JSV2F_CONSTRUCT) {
         error = JSMSG_NOT_CONSTRUCTOR;
     } else {
         error = JSMSG_NOT_FUNCTION;
     }
 
     js_ReportValueError3(cx, error,
-                         (fp && fp->spbase <= vp && vp < fp->sp)
-                         ? vp - fp->sp
+                         (fp && fp->regs &&
+                          fp->spbase <= vp && vp < fp->regs->sp)
+                         ? vp - fp->regs->sp
                          : (flags & JSV2F_SEARCH_STACK)
                          ? JSDVG_SEARCH_STACK
                          : JSDVG_IGNORE_STACK,
                          *vp, NULL,
                          name, source);
 }
 
 /*
--- a/js/src/jsgc.c
+++ b/js/src/jsgc.c
@@ -2669,19 +2669,21 @@ js_TraceStackFrame(JSTracer *trc, JSStac
     if (fp->varobj)
         JS_CALL_OBJECT_TRACER(trc, fp->varobj, "variables");
     if (fp->script) {
         js_TraceScript(trc, fp->script);
         /*
          * Don't mark what has not been pushed yet, or what has been
          * popped already.
          */
-        nslots = (uintN) (fp->sp - fp->spbase);
-        JS_ASSERT(nslots <= fp->script->depth);
-        TRACE_JSVALS(trc, nslots, fp->spbase, "operand");
+        if (fp->regs) {
+            nslots = (uintN) (fp->regs->sp - fp->spbase);
+            JS_ASSERT(nslots <= fp->script->depth);
+            TRACE_JSVALS(trc, nslots, fp->spbase, "operand");
+        }
     }
 
     /* Allow for primitive this parameter due to JSFUN_THISP_* flags. */
     JS_ASSERT(JSVAL_IS_OBJECT((jsval)fp->thisp) ||
               (fp->fun && JSFUN_THISP_FLAGS(fp->fun->flags)));
     JS_CALL_VALUE_TRACER(trc, (jsval)fp->thisp, "this");
 
     if (fp->callee)
--- a/js/src/jsinterp.c
+++ b/js/src/jsinterp.c
@@ -112,17 +112,17 @@ js_FillPropertyCache(JSContext *cx, JSOb
     const JSCodeSpec *cs;
     jsuword vword;
     ptrdiff_t pcoff;
     jsuword khash;
     JSAtom *atom;
     JSPropCacheEntry *entry;
 
     cache = &JS_PROPERTY_CACHE(cx);
-    pc = cx->fp->pc;
+    pc = cx->fp->regs->pc;
     if (cache->disabled) {
         PCMETER(cache->disfills++);
         *entryp = NULL;
         return;
     }
 
     /*
      * Check for fill from js_SetPropertyHelper where the setter removed sprop
@@ -1201,17 +1201,17 @@ have_fun:
         /* Push void to initialize local variables. */
         i = nvars;
         do {
             *sp++ = JSVAL_VOID;
         } while (--i != 0);
     }
 
     /*
-     * Initialize the frame, except for sp (set by SAVE_SP later).
+     * Initialize the frame.
      *
      * To set thisp we use an explicit cast and not JSVAL_TO_OBJECT, as vp[1]
      * can be a primitive value here for those native functions specified with
      * JSFUN_THISP_(NUMBER|STRING|BOOLEAN) flags.
      */
     frame.thisp = (JSObject *)vp[1];
     frame.varobj = NULL;
     frame.callobj = frame.argsobj = NULL;
@@ -1223,18 +1223,17 @@ have_fun:
 
     /* Default return value for a constructor is the new object. */
     frame.rval = (flags & JSINVOKE_CONSTRUCT) ? vp[1] : JSVAL_VOID;
     frame.nvars = nvars;
     frame.vars = sp - nvars;
     frame.down = cx->fp;
     frame.annotation = NULL;
     frame.scopeChain = NULL;    /* set below for real, after cx->fp is set */
-    frame.pc = NULL;
-    frame.sp = NULL;
+    frame.regs = NULL;
     frame.spbase = NULL;
     frame.sharpDepth = 0;
     frame.sharpArray = NULL;
     frame.flags = flags | rootedArgsFlag;
     frame.dormantNext = NULL;
     frame.xmlNamespace = NULL;
     frame.blockChain = NULL;
 
@@ -1473,18 +1472,17 @@ js_Execute(JSContext *cx, JSObject *chai
             frame.vars = NULL;
         }
         frame.annotation = NULL;
         frame.sharpArray = NULL;
     }
     frame.rval = JSVAL_VOID;
     frame.down = down;
     frame.scopeChain = chain;
-    frame.pc = NULL;
-    frame.sp = NULL;
+    frame.regs = NULL;
     frame.spbase = NULL;
     frame.sharpDepth = 0;
     frame.flags = flags;
     frame.dormantNext = NULL;
     frame.xmlNamespace = NULL;
     frame.blockChain = NULL;
 
     /*
@@ -1891,17 +1889,17 @@ js_InternNonIntElementId(JSContext *cx, 
 JSBool
 js_EnterWith(JSContext *cx, jsint stackIndex)
 {
     JSStackFrame *fp;
     jsval *sp;
     JSObject *obj, *parent, *withobj;
 
     fp = cx->fp;
-    sp = fp->sp;
+    sp = fp->regs->sp;
     JS_ASSERT(stackIndex < 0);
     JS_ASSERT(fp->spbase <= sp + stackIndex);
 
     if (!JSVAL_IS_PRIMITIVE(sp[-1])) {
         obj = JSVAL_TO_OBJECT(sp[-1]);
     } else {
         obj = js_ValueToNonNullObject(cx, sp[-1]);
         if (!obj)
@@ -1979,17 +1977,17 @@ js_CountWithBlocks(JSContext *cx, JSStac
 JSBool
 js_UnwindScope(JSContext *cx, JSStackFrame *fp, jsint stackDepth,
                JSBool normalUnwind)
 {
     JSObject *obj;
     JSClass *clasp;
 
     JS_ASSERT(stackDepth >= 0);
-    JS_ASSERT(fp->spbase + stackDepth <= fp->sp);
+    JS_ASSERT(fp->spbase + stackDepth <= fp->regs->sp);
 
     for (obj = fp->blockChain; obj; obj = OBJ_GET_PARENT(cx, obj)) {
         JS_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_BlockClass);
         if (OBJ_BLOCK_DEPTH(cx, obj) < stackDepth)
             break;
     }
     fp->blockChain = obj;
 
@@ -2001,17 +1999,17 @@ js_UnwindScope(JSContext *cx, JSStackFra
         if (clasp == &js_BlockClass) {
             /* Don't fail until after we've updated all stacks. */
             normalUnwind &= js_PutBlockObject(cx, normalUnwind);
         } else {
             js_LeaveWith(cx);
         }
     }
 
-    fp->sp = fp->spbase + stackDepth;
+    fp->regs->sp = fp->spbase + stackDepth;
     return normalUnwind;
 }
 
 JSBool
 js_DoIncDec(JSContext *cx, const JSCodeSpec *cs, jsval *vp, jsval *vp2)
 {
     jsval v;
     jsdouble d;
@@ -2181,83 +2179,52 @@ js_DumpOpMeters()
     }
     fclose(fp);
 }
 
 #endif /* JS_OPSMETER */
 
 #else /* !defined js_invoke_c__ */
 
-/*
- * Stack macros and functions.  These all use a local variable, jsval *sp, to
- * point to the next free stack slot.  SAVE_SP must be called before any call
- * to a function that may invoke the interpreter.  RESTORE_SP must be called
- * only after return from js_Invoke, because only js_Invoke changes fp->sp.
- */
-#define SAVE_SP(fp)                                                           \
-    (JS_ASSERT((fp)->script || !(fp)->spbase || (sp) == (fp)->spbase),        \
-     (fp)->sp = sp)
-#define RESTORE_SP(fp)  (sp = (fp)->sp)
-
-/*
- * SAVE_SP_AND_PC commits deferred stores of interpreter registers to their
- * homes in fp, when calling out of the interpreter loop or threaded code.
- * RESTORE_SP_AND_PC copies the other way, to update registers after a call
- * to a subroutine that interprets a piece of the current script.
- * ASSERT_SAVED_SP_AND_PC checks that SAVE_SP_AND_PC was called.
- */
-#define SAVE_SP_AND_PC(fp)      (SAVE_SP(fp), (fp)->pc = pc)
-#define RESTORE_SP_AND_PC(fp)   (RESTORE_SP(fp), pc = (fp)->pc)
-#define ASSERT_SAVED_SP_AND_PC(fp) JS_ASSERT((fp)->sp == sp && (fp)->pc == pc);
-
-#define PUSH(v)         (*sp++ = (v))
+#define PUSH(v)         (*regs.sp++ = (v))
 #define PUSH_OPND(v)    PUSH(v)
-#define STORE_OPND(n,v) (sp[n] = (v))
-#define POP()           (*--sp)
+#define STORE_OPND(n,v) (regs.sp[n] = (v))
+#define POP()           (*--regs.sp)
 #define POP_OPND()      POP()
-#define FETCH_OPND(n)   (sp[n])
+#define FETCH_OPND(n)   (regs.sp[n])
 
 /*
  * Push the jsdouble d using sp from the lexical environment. Try to convert d
  * to a jsint that fits in a jsval, otherwise GC-alloc space for it and push a
  * reference.
  */
 #define STORE_NUMBER(cx, n, d)                                                \
     JS_BEGIN_MACRO                                                            \
         jsint i_;                                                             \
                                                                               \
-        if (JSDOUBLE_IS_INT(d, i_) && INT_FITS_IN_JSVAL(i_)) {                \
-            sp[n] = INT_TO_JSVAL(i_);                                         \
-        } else {                                                              \
-            SAVE_SP_AND_PC(fp);                                               \
-            if (!js_NewDoubleInRootedValue(cx, d, &sp[n]))                    \
-                goto error;                                                   \
-        }                                                                     \
+        if (JSDOUBLE_IS_INT(d, i_) && INT_FITS_IN_JSVAL(i_))                  \
+            regs.sp[n] = INT_TO_JSVAL(i_);                                    \
+        else if (!js_NewDoubleInRootedValue(cx, d, &regs.sp[n]))              \
+            goto error;                                                       \
     JS_END_MACRO
 
 #define STORE_INT(cx, n, i)                                                   \
     JS_BEGIN_MACRO                                                            \
-        if (INT_FITS_IN_JSVAL(i)) {                                           \
-            sp[n] = INT_TO_JSVAL(i);                                          \
-        } else {                                                              \
-            SAVE_SP_AND_PC(fp);                                               \
-            if (!js_NewDoubleInRootedValue(cx, (jsdouble)(i), &sp[n]))        \
-                goto error;                                                   \
-        }                                                                     \
+        if (INT_FITS_IN_JSVAL(i))                                             \
+            regs.sp[n] = INT_TO_JSVAL(i);                                     \
+        else if (!js_NewDoubleInRootedValue(cx, (jsdouble) (i), &regs.sp[n])) \
+            goto error;                                                       \
     JS_END_MACRO
 
 #define STORE_UINT(cx, n, u)                                                  \
     JS_BEGIN_MACRO                                                            \
-        if ((u) <= JSVAL_INT_MAX) {                                           \
-            sp[n] = INT_TO_JSVAL(u);                                          \
-        } else {                                                              \
-            SAVE_SP_AND_PC(fp);                                               \
-            if (!js_NewDoubleInRootedValue(cx, (jsdouble)(u), &sp[n]))        \
-                goto error;                                                   \
-        }                                                                     \
+        if ((u) <= JSVAL_INT_MAX)                                             \
+            regs.sp[n] = INT_TO_JSVAL(u);                                     \
+        else if (!js_NewDoubleInRootedValue(cx, (jsdouble) (u), &regs.sp[n])) \
+            goto error;                                                       \
     JS_END_MACRO
 
 #define FETCH_NUMBER(cx, n, d)                                                \
     JS_BEGIN_MACRO                                                            \
         jsval v_;                                                             \
                                                                               \
         v_ = FETCH_OPND(n);                                                   \
         VALUE_TO_NUMBER(cx, n, v_, d);                                        \
@@ -2266,100 +2233,94 @@ js_DumpOpMeters()
 #define FETCH_INT(cx, n, i)                                                   \
     JS_BEGIN_MACRO                                                            \
         jsval v_;                                                             \
                                                                               \
         v_= FETCH_OPND(n);                                                    \
         if (JSVAL_IS_INT(v_)) {                                               \
             i = JSVAL_TO_INT(v_);                                             \
         } else {                                                              \
-            SAVE_SP_AND_PC(fp);                                               \
-            i = js_ValueToECMAInt32(cx, &sp[n]);                              \
-            if (JSVAL_IS_NULL(sp[n]))                                         \
+            i = js_ValueToECMAInt32(cx, &regs.sp[n]);                         \
+            if (JSVAL_IS_NULL(regs.sp[n]))                                    \
                 goto error;                                                   \
         }                                                                     \
     JS_END_MACRO
 
 #define FETCH_UINT(cx, n, ui)                                                 \
     JS_BEGIN_MACRO                                                            \
         jsval v_;                                                             \
                                                                               \
         v_= FETCH_OPND(n);                                                    \
         if (JSVAL_IS_INT(v_)) {                                               \
             ui = (uint32) JSVAL_TO_INT(v_);                                   \
         } else {                                                              \
-            SAVE_SP_AND_PC(fp);                                               \
-            ui = js_ValueToECMAUint32(cx, &sp[n]);                            \
-            if (JSVAL_IS_NULL(sp[n]))                                         \
+            ui = js_ValueToECMAUint32(cx, &regs.sp[n]);                       \
+            if (JSVAL_IS_NULL(regs.sp[n]))                                    \
                 goto error;                                                   \
         }                                                                     \
     JS_END_MACRO
 
 /*
  * Optimized conversion macros that test for the desired type in v before
  * homing sp and calling a conversion function.
  */
 #define VALUE_TO_NUMBER(cx, n, v, d)                                          \
     JS_BEGIN_MACRO                                                            \
-        JS_ASSERT(v == sp[n]);                                                \
+        JS_ASSERT(v == regs.sp[n]);                                           \
         if (JSVAL_IS_INT(v)) {                                                \
             d = (jsdouble)JSVAL_TO_INT(v);                                    \
         } else if (JSVAL_IS_DOUBLE(v)) {                                      \
             d = *JSVAL_TO_DOUBLE(v);                                          \
         } else {                                                              \
-            SAVE_SP_AND_PC(fp);                                               \
-            d = js_ValueToNumber(cx, &sp[n]);                                 \
-            if (JSVAL_IS_NULL(sp[n]))                                         \
+            d = js_ValueToNumber(cx, &regs.sp[n]);                            \
+            if (JSVAL_IS_NULL(regs.sp[n]))                                    \
                 goto error;                                                   \
-            JS_ASSERT(JSVAL_IS_NUMBER(sp[n]) || sp[n] == JSVAL_TRUE);         \
+            JS_ASSERT(JSVAL_IS_NUMBER(regs.sp[n]) ||                          \
+                      regs.sp[n] == JSVAL_TRUE);                              \
         }                                                                     \
     JS_END_MACRO
 
 #define POP_BOOLEAN(cx, v, b)                                                 \
     JS_BEGIN_MACRO                                                            \
         v = FETCH_OPND(-1);                                                   \
         if (v == JSVAL_NULL) {                                                \
             b = JS_FALSE;                                                     \
         } else if (JSVAL_IS_BOOLEAN(v)) {                                     \
             b = JSVAL_TO_BOOLEAN(v);                                          \
         } else {                                                              \
             b = js_ValueToBoolean(v);                                         \
         }                                                                     \
-        sp--;                                                                 \
+        regs.sp--;                                                            \
     JS_END_MACRO
 
 #define VALUE_TO_OBJECT(cx, n, v, obj)                                        \
     JS_BEGIN_MACRO                                                            \
         if (!JSVAL_IS_PRIMITIVE(v)) {                                         \
             obj = JSVAL_TO_OBJECT(v);                                         \
         } else {                                                              \
-            SAVE_SP_AND_PC(fp);                                               \
             obj = js_ValueToNonNullObject(cx, v);                             \
             if (!obj)                                                         \
                 goto error;                                                   \
             STORE_OPND(n, OBJECT_TO_JSVAL(obj));                              \
         }                                                                     \
     JS_END_MACRO
 
-/* SAVE_SP_AND_PC must be already called. */
 #define FETCH_OBJECT(cx, n, v, obj)                                           \
     JS_BEGIN_MACRO                                                            \
-        ASSERT_SAVED_SP_AND_PC(fp);                                           \
         v = FETCH_OPND(n);                                                    \
         VALUE_TO_OBJECT(cx, n, v, obj);                                       \
     JS_END_MACRO
 
 #define DEFAULT_VALUE(cx, n, hint, v)                                         \
     JS_BEGIN_MACRO                                                            \
         JS_ASSERT(!JSVAL_IS_PRIMITIVE(v));                                    \
-        JS_ASSERT(v == sp[n]);                                                \
-        SAVE_SP_AND_PC(fp);                                                   \
-        if (!OBJ_DEFAULT_VALUE(cx, JSVAL_TO_OBJECT(v), hint, &sp[n]))         \
+        JS_ASSERT(v == regs.sp[n]);                                           \
+        if (!OBJ_DEFAULT_VALUE(cx, JSVAL_TO_OBJECT(v), hint, &regs.sp[n]))    \
             goto error;                                                       \
-        v = sp[n];                                                            \
+        v = regs.sp[n];                                                       \
     JS_END_MACRO
 
 /*
  * Quickly test if v is an int from the [-2**29, 2**29) range, that is, when
  * the lowest bit of v is 1 and the bits 30 and 31 are both either 0 or 1. For
  * such v we can do increment or decrement via adding or subtracting two
  * without checking that the result overflows JSVAL_INT_MIN or JSVAL_INT_MAX.
  */
@@ -2459,18 +2420,17 @@ js_Interpret(JSContext *cx)
 {
     JSRuntime *rt;
     JSStackFrame *fp;
     JSScript *script;
     uintN inlineCallCount;
     JSAtom **atoms;
     JSVersion currentVersion, originalVersion;
     void *mark;
-    jsval *sp;
-    jsbytecode *pc;
+    JSFrameRegs regs;
     JSObject *obj, *obj2, *parent;
     JSBool ok, cond;
     JSTrapHandler interruptHandler;
     jsint len;
     jsbytecode *endpc, *pc2;
     JSOp op, op2;
     jsatomid index;
     JSAtom *atom;
@@ -2522,23 +2482,23 @@ js_Interpret(JSContext *cx)
 # undef OPDEF
     };
 
     register void **jumpTable = normalJumpTable;
 
     METER_OP_INIT(op);      /* to nullify first METER_OP_PAIR */
 
 # define DO_OP()            JS_EXTENSION_(goto *jumpTable[op])
-# define DO_NEXT_OP(n)      do { METER_OP_PAIR(op, pc[n]);                    \
-                                 op = (JSOp) *(pc += (n));                    \
+# define DO_NEXT_OP(n)      do { METER_OP_PAIR(op, regs.pc[n]);               \
+                                 op = (JSOp) *(regs.pc += (n));               \
                                  DO_OP(); } while (0)
 # define BEGIN_CASE(OP)     L_##OP:
 # define END_CASE(OP)       DO_NEXT_OP(OP##_LENGTH);
 # define END_VARLEN_CASE    DO_NEXT_OP(len);
-# define EMPTY_CASE(OP)     BEGIN_CASE(OP) op = (JSOp) *++pc; DO_OP();
+# define EMPTY_CASE(OP)     BEGIN_CASE(OP) op = (JSOp) *++regs.pc; DO_OP();
 #else
 # define DO_OP()            goto do_op
 # define DO_NEXT_OP(n)      goto advance_pc
 # define BEGIN_CASE(OP)     case OP:
 # define END_CASE(OP)       break;
 # define END_VARLEN_CASE    break;
 # define EMPTY_CASE(OP)     BEGIN_CASE(OP) END_CASE(OP)
 #endif
@@ -2563,22 +2523,23 @@ js_Interpret(JSContext *cx)
      * access. For less frequent object and regexp loads we have to recover
      * the segment from atoms pointer first.
      */
     atoms = script->atomMap.vector;
 
 #define LOAD_ATOM(PCOFF)                                                      \
     JS_BEGIN_MACRO                                                            \
         JS_ASSERT((size_t)(atoms - script->atomMap.vector) <                  \
-                  (size_t)(script->atomMap.length - GET_INDEX(pc + PCOFF)));  \
-        atom = atoms[GET_INDEX(pc + PCOFF)];                                  \
+                  (size_t)(script->atomMap.length -                           \
+                           GET_INDEX(regs.pc + PCOFF)));                      \
+        atom = atoms[GET_INDEX(regs.pc + PCOFF)];                             \
     JS_END_MACRO
 
 #define GET_FULL_INDEX(PCOFF)                                                 \
-    (atoms - script->atomMap.vector + GET_INDEX(pc + PCOFF))
+    (atoms - script->atomMap.vector + GET_INDEX(regs.pc + PCOFF))
 
 #define LOAD_OBJECT(PCOFF)                                                    \
     JS_GET_SCRIPT_OBJECT(script, GET_FULL_INDEX(PCOFF), obj)
 
 #define LOAD_FUNCTION(PCOFF)                                                  \
     JS_BEGIN_MACRO                                                            \
         LOAD_OBJECT(PCOFF);                                                   \
         JS_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_FunctionClass);               \
@@ -2586,17 +2547,16 @@ js_Interpret(JSContext *cx)
 
     /*
      * Prepare to call a user-supplied branch handler, and abort the script
      * if it returns false.
      */
 #define CHECK_BRANCH(len)                                                     \
     JS_BEGIN_MACRO                                                            \
         if (len <= 0 && (cx->operationCount -= JSOW_SCRIPT_JUMP) <= 0) {      \
-            SAVE_SP_AND_PC(fp);                                               \
             if (!js_ResetOperationCount(cx))                                  \
                 goto error;                                                   \
         }                                                                     \
     JS_END_MACRO
 
     /*
      * Optimized Get and SetVersion for proper script language versioning.
      *
@@ -2612,17 +2572,17 @@ js_Interpret(JSContext *cx)
         js_SetVersion(cx, currentVersion);
 
     ++cx->interpLevel;
 #ifdef DEBUG
     fp->pcDisabledSave = JS_PROPERTY_CACHE(cx).disabled;
 #endif
 
     /*
-     * From this point the control must flow through the label exit.
+     * From this point control must flow through the label exit2.
      *
      * Load the debugger's interrupt hook here and after calling out to native
      * functions (but not to getters, setters, or other native hooks), so we do
      * not have to reload it each time through the interpreter loop -- we hope
      * the compiler can keep it in a register when it is non-null.
      */
 #if JS_THREADED_INTERP
 # define LOAD_JUMP_TABLE()                                                    \
@@ -2640,35 +2600,37 @@ js_Interpret(JSContext *cx)
     LOAD_INTERRUPT_HANDLER(cx);
 
      /*
      * Initialize the pc register and allocate operand stack slots for the
      * script's worst-case depth, unless we're resuming a generator.
      */
     if (JS_LIKELY(!fp->spbase)) {
         ASSERT_NOT_THROWING(cx);
-        JS_ASSERT(!fp->pc);
-        JS_ASSERT(!fp->sp);
-        JS_ASSERT(!fp->spbase);
+        JS_ASSERT(!fp->regs);
         fp->spbase = js_AllocRawStack(cx, script->depth, &mark);
         if (!fp->spbase) {
-            mark = NULL;
             ok = JS_FALSE;
-            goto exit;
+            goto exit2;
         }
         JS_ASSERT(mark);
-        fp->pc = script->code;
-        fp->sp = fp->spbase;
-        RESTORE_SP_AND_PC(fp);
+        regs.pc = script->code;
+        regs.sp = fp->spbase;
+        fp->regs = &regs;
     } else {
+        JSGenerator *gen;
+
         JS_ASSERT(fp->flags & JSFRAME_GENERATOR);
         mark = NULL;
-        RESTORE_SP_AND_PC(fp);
-        JS_ASSERT((size_t) (pc - script->code) <= script->length);
-        JS_ASSERT((size_t) (sp - fp->spbase) <= script->depth);
+        gen = FRAME_TO_GENERATOR(fp);
+        JS_ASSERT(fp->regs == &gen->savedRegs);
+        regs = gen->savedRegs;
+        fp->regs = &regs;
+        JS_ASSERT((size_t) (regs.pc - script->code) <= script->length);
+        JS_ASSERT((size_t) (regs.sp - fp->spbase) <= script->depth);
         JS_ASSERT(JS_PROPERTY_CACHE(cx).disabled >= 0);
         JS_PROPERTY_CACHE(cx).disabled += js_CountWithBlocks(cx, fp);
 
         /*
          * To support generator_throw and to catch ignored exceptions,
          * fail if cx->throwing is set.
          */
         if (cx->throwing) {
@@ -2691,21 +2653,20 @@ js_Interpret(JSContext *cx)
      * The trick is LOAD_INTERRUPT_HANDLER setting jumpTable appropriately.
      *
      * It is important that "op" be initialized before the interrupt label
      * because it is possible for "op" to be specially assigned during the
      * normally processing of an opcode while looping (in particular, this
      * happens in JSOP_TRAP while debugging).  We rely on DO_NEXT_OP to
      * correctly manage "op" in all other cases.
      */
-    op = (JSOp) *pc;
+    op = (JSOp) *regs.pc;
     if (interruptHandler) {
 interrupt:
-        SAVE_SP_AND_PC(fp);
-        switch (interruptHandler(cx, script, pc, &rval,
+        switch (interruptHandler(cx, script, regs.pc, &rval,
                                  cx->debugHooks->interruptHandlerData)) {
           case JSTRAP_ERROR:
             goto error;
           case JSTRAP_CONTINUE:
             break;
           case JSTRAP_RETURN:
             fp->rval = rval;
             ok = JS_TRUE;
@@ -2720,50 +2681,48 @@ interrupt:
     }
 
     JS_ASSERT((uintN)op < (uintN)JSOP_LIMIT);
     JS_EXTENSION_(goto *normalJumpTable[op]);
 
 #else  /* !JS_THREADED_INTERP */
 
     for (;;) {
-        op = (JSOp) *pc;
+        op = (JSOp) *regs.pc;
       do_op:
         len = js_CodeSpec[op].length;
 
 #ifdef DEBUG
         tracefp = (FILE *) cx->tracefp;
         if (tracefp) {
             intN nuses, n;
 
-            fprintf(tracefp, "%4u: ", js_PCToLineNumber(cx, script, pc));
-            js_Disassemble1(cx, script, pc,
-                            PTRDIFF(pc, script->code, jsbytecode), JS_FALSE,
-                            tracefp);
+            fprintf(tracefp, "%4u: ", js_PCToLineNumber(cx, script, regs.pc));
+            js_Disassemble1(cx, script, regs.pc,
+                            PTRDIFF(regs.pc, script->code, jsbytecode),
+                            JS_FALSE, tracefp);
             nuses = js_CodeSpec[op].nuses;
             if (nuses) {
-                SAVE_SP_AND_PC(fp);
                 for (n = -nuses; n < 0; n++) {
-                    char *bytes = js_DecompileValueGenerator(cx, n, sp[n],
+                    char *bytes = js_DecompileValueGenerator(cx, n, regs.sp[n],
                                                              NULL);
                     if (bytes) {
                         fprintf(tracefp, "%s %s",
                                 (n == -nuses) ? "  inputs:" : ",",
                                 bytes);
                         JS_free(cx, bytes);
                     }
                 }
-                fprintf(tracefp, " @ %d\n", sp - fp->spbase);
+                fprintf(tracefp, " @ %d\n", regs.sp - fp->spbase);
             }
         }
 #endif /* DEBUG */
 
         if (interruptHandler) {
-            SAVE_SP_AND_PC(fp);
-            switch (interruptHandler(cx, script, pc, &rval,
+            switch (interruptHandler(cx, script, regs.pc, &rval,
                                      cx->debugHooks->interruptHandlerData)) {
               case JSTRAP_ERROR:
                 goto error;
               case JSTRAP_CONTINUE:
                 break;
               case JSTRAP_RETURN:
                 fp->rval = rval;
                 ok = JS_TRUE;
@@ -2785,92 +2744,89 @@ interrupt:
 
           EMPTY_CASE(JSOP_GROUP)
 
           BEGIN_CASE(JSOP_PUSH)
             PUSH_OPND(JSVAL_VOID);
           END_CASE(JSOP_PUSH)
 
           BEGIN_CASE(JSOP_POP)
-            sp--;
+            regs.sp--;
           END_CASE(JSOP_POP)
 
           BEGIN_CASE(JSOP_POPN)
-            sp -= GET_UINT16(pc);
+            regs.sp -= GET_UINT16(regs.pc);
 #ifdef DEBUG
-            JS_ASSERT(fp->spbase <= sp);
+            JS_ASSERT(fp->spbase <= regs.sp);
             obj = fp->blockChain;
-            JS_ASSERT(!obj ||
-                      fp->spbase + OBJ_BLOCK_DEPTH(cx, obj)
-                                 + OBJ_BLOCK_COUNT(cx, obj)
-                      <= sp);
+            JS_ASSERT_IF(obj,
+                         OBJ_BLOCK_DEPTH(cx, obj) + OBJ_BLOCK_COUNT(cx, obj)
+                         <= (size_t) (regs.sp - fp->spbase));
             for (obj = fp->scopeChain; obj; obj = OBJ_GET_PARENT(cx, obj)) {
                 clasp = OBJ_GET_CLASS(cx, obj);
                 if (clasp != &js_BlockClass && clasp != &js_WithClass)
                     continue;
                 if (OBJ_GET_PRIVATE(cx, obj) != fp)
                     break;
                 JS_ASSERT(fp->spbase + OBJ_BLOCK_DEPTH(cx, obj)
                                      + ((clasp == &js_BlockClass)
-                                         ? OBJ_BLOCK_COUNT(cx, obj)
-                                         : 1)
-                          <= sp);
+                                        ? OBJ_BLOCK_COUNT(cx, obj)
+                                        : 1)
+                          <= regs.sp);
             }
 #endif
           END_CASE(JSOP_POPN)
 
           BEGIN_CASE(JSOP_SWAP)
-            rtmp = sp[-1];
-            sp[-1] = sp[-2];
-            sp[-2] = rtmp;
+            rtmp = regs.sp[-1];
+            regs.sp[-1] = regs.sp[-2];
+            regs.sp[-2] = rtmp;
           END_CASE(JSOP_SWAP)
 
           BEGIN_CASE(JSOP_SETRVAL)
           BEGIN_CASE(JSOP_POPV)
             ASSERT_NOT_THROWING(cx);
             fp->rval = POP_OPND();
           END_CASE(JSOP_POPV)
 
           BEGIN_CASE(JSOP_ENTERWITH)
-            SAVE_SP_AND_PC(fp);
             if (!js_EnterWith(cx, -1))
                 goto error;
 
             /*
              * We must ensure that different "with" blocks have different
              * stack depth associated with them. This allows the try handler
              * search to properly recover the scope chain. Thus we must keep
              * the stack at least at the current level.
              *
              * We set sp[-1] to the current "with" object to help asserting
              * the enter/leave balance in [leavewith].
              */
-            sp[-1] = OBJECT_TO_JSVAL(fp->scopeChain);
+            regs.sp[-1] = OBJECT_TO_JSVAL(fp->scopeChain);
           END_CASE(JSOP_ENTERWITH)
 
           BEGIN_CASE(JSOP_LEAVEWITH)
-            JS_ASSERT(sp[-1] == OBJECT_TO_JSVAL(fp->scopeChain));
-            sp--;
-            SAVE_SP_AND_PC(fp);
+            JS_ASSERT(regs.sp[-1] == OBJECT_TO_JSVAL(fp->scopeChain));
+            regs.sp--;
             js_LeaveWith(cx);
           END_CASE(JSOP_LEAVEWITH)
 
           BEGIN_CASE(JSOP_RETURN)
             CHECK_BRANCH(-1);
             fp->rval = POP_OPND();
             /* FALL THROUGH */
 
           BEGIN_CASE(JSOP_RETRVAL)    /* fp->rval already set */
           BEGIN_CASE(JSOP_STOP)
             /*
              * When the inlined frame exits with an exception or an error, ok
              * will be false after the inline_return label.
              */
             ASSERT_NOT_THROWING(cx);
-            JS_ASSERT(sp == fp->spbase);
+            JS_ASSERT(regs.sp == fp->spbase);
             ok = JS_TRUE;
             if (inlineCallCount)
           inline_return:
             {
                 JSInlineFrame *ifp = (JSInlineFrame *) fp;
                 void *hookData = ifp->hookData;
 
                 JS_ASSERT(JS_PROPERTY_CACHE(cx).disabled == fp->pcDisabledSave);
@@ -2882,203 +2838,195 @@ interrupt:
                     JSBool status;
 
                     hook = cx->debugHooks->callHook;
                     if (hook) {
                         /*
                          * Do not pass &ok directly as exposing the address
                          * inhibits optimizations and uninitialised warnings.
                          */
-                        SAVE_SP_AND_PC(fp);
                         status = ok;
                         hook(cx, fp, JS_FALSE, &status, hookData);
                         ok = status;
                         LOAD_INTERRUPT_HANDLER(cx);
                     }
                 }
 
                 /*
                  * If fp has a call object, sync values and clear the back-
                  * pointer. This can happen for a lightweight function if it
                  * calls eval unexpectedly (in a way that is hidden from the
                  * compiler). See bug 325540.
                  */
-                if (fp->callobj) {
-                    SAVE_SP_AND_PC(fp);
+                if (fp->callobj)
                     ok &= js_PutCallObject(cx, fp);
-                }
-
-                if (fp->argsobj) {
-                    SAVE_SP_AND_PC(fp);
+
+                if (fp->argsobj)
                     ok &= js_PutArgsObject(cx, fp);
-                }
 
 #ifdef INCLUDE_MOZILLA_DTRACE
                 /* DTrace function return, inlines */
                 if (JAVASCRIPT_FUNCTION_RVAL_ENABLED())
                     jsdtrace_function_rval(cx, fp, fp->fun);
                 if (JAVASCRIPT_FUNCTION_RETURN_ENABLED())
                     jsdtrace_function_return(cx, fp, fp->fun);
 #endif
 
                 /* Restore context version only if callee hasn't set version. */
                 if (JS_LIKELY(cx->version == currentVersion)) {
                     currentVersion = ifp->callerVersion;
                     if (currentVersion != cx->version)
                         js_SetVersion(cx, currentVersion);
                 }
 
+                /* Restore caller's registers. */
+                regs = ifp->callerRegs;
+
                 /* Store the return value in the caller's operand frame. */
-                vp = ifp->rvp;
-                *vp = fp->rval;
+                regs.sp -= 1 + (size_t) ifp->frame.argc;
+                regs.sp[-1] = fp->rval;
 
                 /* Restore cx->fp and release the inline frame's space. */
                 cx->fp = fp = fp->down;
+                JS_ASSERT(fp->regs == &ifp->callerRegs);
+                fp->regs = &regs;
                 JS_ARENA_RELEASE(&cx->stackPool, ifp->mark);
 
-                /* Restore sp to point just above the return value. */
-                fp->sp = vp + 1;
-                RESTORE_SP(fp);
-
                 /* Restore the calling script's interpreter registers. */
                 script = fp->script;
                 atoms = script->atomMap.vector;
-                pc = fp->pc;
 
                 /* Resume execution in the calling frame. */
                 inlineCallCount--;
                 if (JS_LIKELY(ok)) {
-                    JS_ASSERT(js_CodeSpec[*pc].length == JSOP_CALL_LENGTH);
+                    JS_ASSERT(js_CodeSpec[*regs.pc].length == JSOP_CALL_LENGTH);
                     len = JSOP_CALL_LENGTH;
                     DO_NEXT_OP(len);
                 }
                 goto error;
             }
             goto exit;
 
           BEGIN_CASE(JSOP_DEFAULT)
             (void) POP();
             /* FALL THROUGH */
           BEGIN_CASE(JSOP_GOTO)
-            len = GET_JUMP_OFFSET(pc);
+            len = GET_JUMP_OFFSET(regs.pc);
             CHECK_BRANCH(len);
           END_VARLEN_CASE
 
           BEGIN_CASE(JSOP_IFEQ)
             POP_BOOLEAN(cx, rval, cond);
             if (cond == JS_FALSE) {
-                len = GET_JUMP_OFFSET(pc);
+                len = GET_JUMP_OFFSET(regs.pc);
                 CHECK_BRANCH(len);
                 DO_NEXT_OP(len);
             }
           END_CASE(JSOP_IFEQ)
 
           BEGIN_CASE(JSOP_IFNE)
             POP_BOOLEAN(cx, rval, cond);
             if (cond != JS_FALSE) {
-                len = GET_JUMP_OFFSET(pc);
+                len = GET_JUMP_OFFSET(regs.pc);
                 CHECK_BRANCH(len);
                 DO_NEXT_OP(len);
             }
           END_CASE(JSOP_IFNE)
 
           BEGIN_CASE(JSOP_OR)
             POP_BOOLEAN(cx, rval, cond);
             if (cond == JS_TRUE) {
-                len = GET_JUMP_OFFSET(pc);
+                len = GET_JUMP_OFFSET(regs.pc);
                 PUSH_OPND(rval);
                 DO_NEXT_OP(len);
             }
           END_CASE(JSOP_OR)
 
           BEGIN_CASE(JSOP_AND)
             POP_BOOLEAN(cx, rval, cond);
             if (cond == JS_FALSE) {
-                len = GET_JUMP_OFFSET(pc);
+                len = GET_JUMP_OFFSET(regs.pc);
                 PUSH_OPND(rval);
                 DO_NEXT_OP(len);
             }
           END_CASE(JSOP_AND)
 
           BEGIN_CASE(JSOP_DEFAULTX)
             (void) POP();
             /* FALL THROUGH */
           BEGIN_CASE(JSOP_GOTOX)
-            len = GET_JUMPX_OFFSET(pc);
+            len = GET_JUMPX_OFFSET(regs.pc);
             CHECK_BRANCH(len);
           END_VARLEN_CASE
 
           BEGIN_CASE(JSOP_IFEQX)
             POP_BOOLEAN(cx, rval, cond);
             if (cond == JS_FALSE) {
-                len = GET_JUMPX_OFFSET(pc);
+                len = GET_JUMPX_OFFSET(regs.pc);
                 CHECK_BRANCH(len);
                 DO_NEXT_OP(len);
             }
           END_CASE(JSOP_IFEQX)
 
           BEGIN_CASE(JSOP_IFNEX)
             POP_BOOLEAN(cx, rval, cond);
             if (cond != JS_FALSE) {
-                len = GET_JUMPX_OFFSET(pc);
+                len = GET_JUMPX_OFFSET(regs.pc);
                 CHECK_BRANCH(len);
                 DO_NEXT_OP(len);
             }
           END_CASE(JSOP_IFNEX)
 
           BEGIN_CASE(JSOP_ORX)
             POP_BOOLEAN(cx, rval, cond);
             if (cond == JS_TRUE) {
-                len = GET_JUMPX_OFFSET(pc);
+                len = GET_JUMPX_OFFSET(regs.pc);
                 PUSH_OPND(rval);
                 DO_NEXT_OP(len);
             }
           END_CASE(JSOP_ORX)
 
           BEGIN_CASE(JSOP_ANDX)
             POP_BOOLEAN(cx, rval, cond);
             if (cond == JS_FALSE) {
-                len = GET_JUMPX_OFFSET(pc);
+                len = GET_JUMPX_OFFSET(regs.pc);
                 PUSH_OPND(rval);
                 DO_NEXT_OP(len);
             }
           END_CASE(JSOP_ANDX)
 
 /*
  * If the index value at sp[n] is not an int that fits in a jsval, it could
  * be an object (an XML QName, AttributeName, or AnyName), but only if we are
  * compiling with JS_HAS_XML_SUPPORT.  Otherwise convert the index value to a
  * string atom id.
- *
- * SAVE_SP_AND_PC must be already called.
  */
 #define FETCH_ELEMENT_ID(obj, n, id)                                          \
     JS_BEGIN_MACRO                                                            \
         jsval idval_ = FETCH_OPND(n);                                         \
         if (JSVAL_IS_INT(idval_)) {                                           \
             id = INT_JSVAL_TO_JSID(idval_);                                   \
         } else {                                                              \
             if (!js_InternNonIntElementId(cx, obj, idval_, &id))              \
                 goto error;                                                   \
-            sp[n] = ID_TO_VALUE(id);                                          \
+            regs.sp[n] = ID_TO_VALUE(id);                                     \
         }                                                                     \
     JS_END_MACRO
 
           BEGIN_CASE(JSOP_IN)
             rval = FETCH_OPND(-1);
-            SAVE_SP_AND_PC(fp);
             if (JSVAL_IS_PRIMITIVE(rval)) {
                 js_ReportValueError(cx, JSMSG_IN_NOT_OBJECT, -1, rval, NULL);
                 goto error;
             }
             obj = JSVAL_TO_OBJECT(rval);
             FETCH_ELEMENT_ID(obj, -2, id);
             if (!OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop))
                 goto error;
-            sp--;
+            regs.sp--;
             STORE_OPND(-1, BOOLEAN_TO_JSVAL(prop != NULL));
             if (prop)
                 OBJ_DROP_PROPERTY(cx, obj2, prop);
           END_CASE(JSOP_IN)
 
           BEGIN_CASE(JSOP_FOREACH)
             flags = JSITER_ENUMERATE | JSITER_FOREACH;
             goto value_to_iter;
@@ -3094,21 +3042,20 @@ interrupt:
              * Set JSITER_ENUMERATE to indicate that for-in loop should use
              * the enumeration protocol's iterator for compatibility if an
              * explicit iterator is not given via the optional __iterator__
              * method.
              */
             flags = JSITER_ENUMERATE;
 
           value_to_iter:
-            JS_ASSERT(sp > fp->spbase);
-            SAVE_SP_AND_PC(fp);
-            if (!js_ValueToIterator(cx, flags, &sp[-1]))
+            JS_ASSERT(regs.sp > fp->spbase);
+            if (!js_ValueToIterator(cx, flags, &regs.sp[-1]))
                 goto error;
-            JS_ASSERT(!JSVAL_IS_PRIMITIVE(sp[-1]));
+            JS_ASSERT(!JSVAL_IS_PRIMITIVE(regs.sp[-1]));
             JS_ASSERT(JSOP_FORIN_LENGTH == js_CodeSpec[op].length);
           END_CASE(JSOP_FORIN)
 
           BEGIN_CASE(JSOP_FORPROP)
             /*
              * Handle JSOP_FORPROP first, so the cost of the goto do_forinloop
              * is not paid for the more common cases.
              */
@@ -3143,46 +3090,45 @@ interrupt:
              */
             i = -1;
 
           do_forinloop:
             /*
              * Reach under the top of stack to find our property iterator, a
              * JSObject that contains the iteration state.
              */
-            JS_ASSERT(!JSVAL_IS_PRIMITIVE(sp[i]));
-            iterobj = JSVAL_TO_OBJECT(sp[i]);
-
-            SAVE_SP_AND_PC(fp);
+            JS_ASSERT(!JSVAL_IS_PRIMITIVE(regs.sp[i]));
+            iterobj = JSVAL_TO_OBJECT(regs.sp[i]);
+
             if (!js_CallIteratorNext(cx, iterobj, &rval))
                 goto error;
             if (rval == JSVAL_HOLE) {
                 rval = JSVAL_FALSE;
                 goto end_forinloop;
             }
 
             switch (op) {
               case JSOP_FORARG:
-                slot = GET_ARGNO(pc);
+                slot = GET_ARGNO(regs.pc);
                 JS_ASSERT(slot < fp->fun->nargs);
                 fp->argv[slot] = rval;
                 break;
 
               case JSOP_FORVAR:
-                slot = GET_VARNO(pc);
+                slot = GET_VARNO(regs.pc);
                 JS_ASSERT(slot < fp->fun->u.i.nvars);
                 fp->vars[slot] = rval;
                 break;
 
               case JSOP_FORCONST:
                 /* Don't update the const slot. */
                 break;
 
               case JSOP_FORLOCAL:
-                slot = GET_UINT16(pc);
+                slot = GET_UINT16(regs.pc);
                 JS_ASSERT(slot < script->depth);
                 vp = &fp->spbase[slot];
                 GC_POKE(cx, *vp);
                 *vp = rval;
                 break;
 
               case JSOP_FORELEM:
                 /* FORELEM is not a SET operation, it's more like BINDNAME. */
@@ -3190,17 +3136,16 @@ interrupt:
                 break;
 
               case JSOP_FORPROP:
                 /*
                  * We fetch object here to ensure that the iterator is called
                  * even if lval is null or undefined that throws in
                  * FETCH_OBJECT. See bug 372331.
                  */
-                SAVE_SP_AND_PC(fp);
                 FETCH_OBJECT(cx, -1, lval, obj);
                 goto set_for_property;
 
               default:
                 JS_ASSERT(op == JSOP_FORNAME);
 
                 /*
                  * We find property here after the iterator call to ensure
@@ -3222,50 +3167,48 @@ interrupt:
                     goto error;
                 break;
             }
 
             /* Push true to keep looping through properties. */
             rval = JSVAL_TRUE;
 
           end_forinloop:
-            sp += i + 1;
+            regs.sp += i + 1;
             PUSH_OPND(rval);
             len = js_CodeSpec[op].length;
             DO_NEXT_OP(len);
 
           BEGIN_CASE(JSOP_DUP)
-            JS_ASSERT(sp > fp->spbase);
+            JS_ASSERT(regs.sp > fp->spbase);
             rval = FETCH_OPND(-1);
             PUSH(rval);
           END_CASE(JSOP_DUP)
 
           BEGIN_CASE(JSOP_DUP2)
-            JS_ASSERT(sp - 2 >= fp->spbase);
+            JS_ASSERT(regs.sp - 2 >= fp->spbase);
             lval = FETCH_OPND(-2);
             rval = FETCH_OPND(-1);
             PUSH(lval);
             PUSH(rval);
           END_CASE(JSOP_DUP2)
 
 #define PROPERTY_OP(n, call)                                                  \
     JS_BEGIN_MACRO                                                            \
         /* Fetch the left part and resolve it to a non-null object. */        \
-        SAVE_SP_AND_PC(fp);                                                   \
         FETCH_OBJECT(cx, n, lval, obj);                                       \
                                                                               \
         /* Get or set the property. */                                        \
         if (!call)                                                            \
             goto error;                                                       \
     JS_END_MACRO
 
 #define ELEMENT_OP(n, call)                                                   \
     JS_BEGIN_MACRO                                                            \
         /* Fetch the left part and resolve it to a non-null object. */        \
-        SAVE_SP_AND_PC(fp);                                                   \
         FETCH_OBJECT(cx, n - 1, lval, obj);                                   \
                                                                               \
         /* Fetch index and convert it to id suitable for use with obj. */     \
         FETCH_ELEMENT_ID(obj, n, id);                                         \
                                                                               \
         /* Get or set the element. */                                         \
         if (!call)                                                            \
             goto error;                                                       \
@@ -3276,30 +3219,28 @@ interrupt:
         if (SPROP_HAS_STUB_GETTER(sprop)) {                                   \
             /* Fast path for Object instance properties. */                   \
             JS_ASSERT((sprop)->slot != SPROP_INVALID_SLOT ||                  \
                       !SPROP_HAS_STUB_SETTER(sprop));                         \
             *vp = ((sprop)->slot != SPROP_INVALID_SLOT)                       \
                   ? LOCKED_OBJ_GET_SLOT(pobj, (sprop)->slot)                  \
                   : JSVAL_VOID;                                               \
         } else {                                                              \
-            SAVE_SP_AND_PC(fp);                                               \
             if (!js_NativeGet(cx, obj, pobj, sprop, vp))                      \
                 goto error;                                                   \
         }                                                                     \
     JS_END_MACRO
 
 #define NATIVE_SET(cx,obj,sprop,vp)                                           \
     JS_BEGIN_MACRO                                                            \
         if (SPROP_HAS_STUB_SETTER(sprop) &&                                   \
             (sprop)->slot != SPROP_INVALID_SLOT) {                            \
             /* Fast path for, e.g., Object instance properties. */            \
             LOCKED_OBJ_WRITE_BARRIER(cx, obj, (sprop)->slot, *vp);            \
         } else {                                                              \
-            SAVE_SP_AND_PC(fp);                                               \
             if (!js_NativeSet(cx, obj, sprop, vp))                            \
                 goto error;                                                   \
         }                                                                     \
     JS_END_MACRO
 
 /*
  * Deadlocks or else bad races are likely if JS_THREADSAFE, so we must rely on
  * single-thread DEBUG js shell testing to verify property cache hits.
@@ -3307,22 +3248,21 @@ interrupt:
 #if defined DEBUG && !defined JS_THREADSAFE
 # define ASSERT_VALID_PROPERTY_CACHE_HIT(pcoff,obj,pobj,entry)                \
     do {                                                                      \
         JSAtom *atom_;                                                        \
         JSObject *obj_, *pobj_;                                               \
         JSProperty *prop_;                                                    \
         JSScopeProperty *sprop_;                                              \
         uint32 sample_ = rt->gcNumber;                                        \
-        SAVE_SP_AND_PC(fp);                                                   \
         if (pcoff >= 0)                                                       \
-            GET_ATOM_FROM_BYTECODE(script, pc, pcoff, atom_);                 \
+            GET_ATOM_FROM_BYTECODE(script, regs.pc, pcoff, atom_);            \
         else                                                                  \
             atom_ = rt->atomState.lengthAtom;                                 \
-        if (JOF_OPMODE(*pc) == JOF_NAME) {                                    \
+        if (JOF_OPMODE(*regs.pc) == JOF_NAME) {                               \
             ok = js_FindProperty(cx, ATOM_TO_JSID(atom_), &obj_, &pobj_,      \
                                  &prop_);                                     \
         } else {                                                              \
             obj_ = obj;                                                       \
             ok = js_LookupProperty(cx, obj, ATOM_TO_JSID(atom_), &pobj_,      \
                                    &prop_);                                   \
         }                                                                     \
         if (!ok)                                                              \
@@ -3352,75 +3292,72 @@ interrupt:
 #else
 # define ASSERT_VALID_PROPERTY_CACHE_HIT(pcoff,obj,pobj,entry) ((void) 0)
 #endif
 
           BEGIN_CASE(JSOP_SETCONST)
             LOAD_ATOM(0);
             obj = fp->varobj;
             rval = FETCH_OPND(-1);
-            SAVE_SP_AND_PC(fp);
             if (!OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), rval,
                                      JS_PropertyStub, JS_PropertyStub,
                                      JSPROP_ENUMERATE | JSPROP_PERMANENT |
                                      JSPROP_READONLY,
                                      NULL)) {
                 goto error;
             }
             STORE_OPND(-1, rval);
           END_CASE(JSOP_SETCONST)
 
 #if JS_HAS_DESTRUCTURING
           BEGIN_CASE(JSOP_ENUMCONSTELEM)
             rval = FETCH_OPND(-3);
-            SAVE_SP_AND_PC(fp);
             FETCH_OBJECT(cx, -2, lval, obj);
             FETCH_ELEMENT_ID(obj, -1, id);
             if (!OBJ_DEFINE_PROPERTY(cx, obj, id, rval,
                                      JS_PropertyStub, JS_PropertyStub,
                                      JSPROP_ENUMERATE | JSPROP_PERMANENT |
                                      JSPROP_READONLY,
                                      NULL)) {
                 goto error;
             }
-            sp -= 3;
+            regs.sp -= 3;
           END_CASE(JSOP_ENUMCONSTELEM)
 #endif
 
           BEGIN_CASE(JSOP_BINDNAME)
             do {
                 JSPropCacheEntry *entry;
 
                 obj = fp->scopeChain;
                 if (JS_LIKELY(OBJ_IS_NATIVE(obj))) {
-                    PROPERTY_CACHE_TEST(cx, pc, obj, obj2, entry, atom);
+                    PROPERTY_CACHE_TEST(cx, regs.pc, obj, obj2, entry, atom);
                     if (!atom) {
                         ASSERT_VALID_PROPERTY_CACHE_HIT(0, obj, obj2, entry);
                         JS_UNLOCK_OBJ(cx, obj2);
                         break;
                     }
                 } else {
                     entry = NULL;
                     LOAD_ATOM(0);
                 }
                 id = ATOM_TO_JSID(atom);
-                SAVE_SP_AND_PC(fp);
                 obj = js_FindIdentifierBase(cx, id, entry);
                 if (!obj)
                     goto error;
             } while (0);
             PUSH_OPND(OBJECT_TO_JSVAL(obj));
           END_CASE(JSOP_BINDNAME)
 
 #define BITWISE_OP(OP)                                                        \
     JS_BEGIN_MACRO                                                            \
         FETCH_INT(cx, -2, i);                                                 \
         FETCH_INT(cx, -1, j);                                                 \
         i = i OP j;                                                           \
-        sp--;                                                                 \
+        regs.sp--;                                                            \
         STORE_INT(cx, -1, i);                                                 \
     JS_END_MACRO
 
           BEGIN_CASE(JSOP_BITOR)
             BITWISE_OP(|);
           END_CASE(JSOP_BITOR)
 
           BEGIN_CASE(JSOP_BITXOR)
@@ -3456,17 +3393,17 @@ interrupt:
                 str2 = JSVAL_TO_STRING(rval);                                 \
                 cond = js_CompareStrings(str, str2) OP 0;                     \
             } else {                                                          \
                 VALUE_TO_NUMBER(cx, -2, lval, d);                             \
                 VALUE_TO_NUMBER(cx, -1, rval, d2);                            \
                 cond = JSDOUBLE_COMPARE(d, OP, d2, JS_FALSE);                 \
             }                                                                 \
         }                                                                     \
-        sp--;                                                                 \
+        regs.sp--;                                                            \
         STORE_OPND(-1, BOOLEAN_TO_JSVAL(cond));                               \
     JS_END_MACRO
 
 /*
  * NB: These macros can't use JS_BEGIN_MACRO/JS_END_MACRO around their bodies
  * because they begin if/else chains, so callers must not put semicolons after
  * the call expressions!
  */
@@ -3478,30 +3415,28 @@ interrupt:
         (rtmp == JSVAL_OBJECT &&                                              \
          (obj2 = JSVAL_TO_OBJECT(rval)) &&                                    \
          OBJECT_IS_XML(cx, obj2))) {                                          \
         JSXMLObjectOps *ops;                                                  \
                                                                               \
         ops = (JSXMLObjectOps *) obj2->map->ops;                              \
         if (obj2 == JSVAL_TO_OBJECT(rval))                                    \
             rval = lval;                                                      \
-        SAVE_SP_AND_PC(fp);                                                   \
         if (!ops->equality(cx, obj2, rval, &cond))                            \
             goto error;                                                       \
         cond = cond OP JS_TRUE;                                               \
     } else
 
 #define EXTENDED_EQUALITY_OP(OP)                                              \
     if (ltmp == JSVAL_OBJECT &&                                               \
         (obj2 = JSVAL_TO_OBJECT(lval)) &&                                     \
         ((clasp = OBJ_GET_CLASS(cx, obj2))->flags & JSCLASS_IS_EXTENDED)) {   \
         JSExtendedClass *xclasp;                                              \
                                                                               \
         xclasp = (JSExtendedClass *) clasp;                                   \
-        SAVE_SP_AND_PC(fp);                                                   \
         if (!xclasp->equality(cx, obj2, rval, &cond))                         \
             goto error;                                                       \
         cond = cond OP JS_TRUE;                                               \
     } else
 #else
 #define XML_EQUALITY_OP(OP)             /* nothing */
 #define EXTENDED_EQUALITY_OP(OP)        /* nothing */
 #endif
@@ -3546,61 +3481,61 @@ interrupt:
                     cond = js_EqualStrings(str, str2) OP JS_TRUE;             \
                 } else {                                                      \
                     VALUE_TO_NUMBER(cx, -2, lval, d);                         \
                     VALUE_TO_NUMBER(cx, -1, rval, d2);                        \
                     cond = JSDOUBLE_COMPARE(d, OP, d2, IFNAN);                \
                 }                                                             \
             }                                                                 \
         }                                                                     \
-        sp--;                                                                 \
+        regs.sp--;                                                            \
         STORE_OPND(-1, BOOLEAN_TO_JSVAL(cond));                               \
     JS_END_MACRO
 
           BEGIN_CASE(JSOP_EQ)
             EQUALITY_OP(==, JS_FALSE);
           END_CASE(JSOP_EQ)
 
           BEGIN_CASE(JSOP_NE)
             EQUALITY_OP(!=, JS_TRUE);
           END_CASE(JSOP_NE)
 
 #define STRICT_EQUALITY_OP(OP)                                                \
     JS_BEGIN_MACRO                                                            \
         rval = FETCH_OPND(-1);                                                \
         lval = FETCH_OPND(-2);                                                \
         cond = js_StrictlyEqual(cx, lval, rval) OP JS_TRUE;                   \
-        sp--;                                                                 \
+        regs.sp--;                                                            \
         STORE_OPND(-1, BOOLEAN_TO_JSVAL(cond));                               \
     JS_END_MACRO
 
           BEGIN_CASE(JSOP_STRICTEQ)
             STRICT_EQUALITY_OP(==);
           END_CASE(JSOP_STRICTEQ)
 
           BEGIN_CASE(JSOP_STRICTNE)
             STRICT_EQUALITY_OP(!=);
           END_CASE(JSOP_STRICTNE)
 
           BEGIN_CASE(JSOP_CASE)
             STRICT_EQUALITY_OP(==);
             (void) POP();
             if (cond) {
-                len = GET_JUMP_OFFSET(pc);
+                len = GET_JUMP_OFFSET(regs.pc);
                 CHECK_BRANCH(len);
                 DO_NEXT_OP(len);
             }
             PUSH(lval);
           END_CASE(JSOP_CASE)
 
           BEGIN_CASE(JSOP_CASEX)
             STRICT_EQUALITY_OP(==);
             (void) POP();
             if (cond) {
-                len = GET_JUMPX_OFFSET(pc);
+                len = GET_JUMPX_OFFSET(regs.pc);
                 CHECK_BRANCH(len);
                 DO_NEXT_OP(len);
             }
             PUSH(lval);
           END_CASE(JSOP_CASEX)
 
           BEGIN_CASE(JSOP_LT)
             RELATIONAL_OP(<);
@@ -3629,30 +3564,29 @@ interrupt:
 #define FETCH_SHIFT(shift)                                                    \
     JS_BEGIN_MACRO                                                            \
         jsval v_;                                                             \
                                                                               \
         v_ = FETCH_OPND(-1);                                                  \
         if (v_ & JSVAL_INT) {                                                 \
             shift = JSVAL_TO_INT(v_);                                         \
         } else {                                                              \
-            SAVE_SP_AND_PC(fp);                                               \
-            shift = js_ValueToECMAInt32(cx, &sp[-1]);                         \
-            if (JSVAL_IS_NULL(sp[-1]))                                        \
+            shift = js_ValueToECMAInt32(cx, &regs.sp[-1]);                    \
+            if (JSVAL_IS_NULL(regs.sp[-1]))                                   \
                 goto error;                                                   \
         }                                                                     \
         shift &= 31;                                                          \
     JS_END_MACRO
 
 #define SIGNED_SHIFT_OP(OP)                                                   \
     JS_BEGIN_MACRO                                                            \
         FETCH_INT(cx, -2, i);                                                 \
         FETCH_SHIFT(j);                                                       \
         i = i OP j;                                                           \
-        sp--;                                                                 \
+        regs.sp--;                                                            \
         STORE_INT(cx, -1, i);                                                 \
     JS_END_MACRO
 
           BEGIN_CASE(JSOP_LSH)
             SIGNED_SHIFT_OP(<<);
           END_CASE(JSOP_LSH)
 
           BEGIN_CASE(JSOP_RSH)
@@ -3661,17 +3595,17 @@ interrupt:
 
           BEGIN_CASE(JSOP_URSH)
           {
             uint32 u;
 
             FETCH_UINT(cx, -2, u);
             FETCH_SHIFT(j);
             u >>= j;
-            sp--;
+            regs.sp--;
             STORE_UINT(cx, -1, u);
           }
           END_CASE(JSOP_URSH)
 
 #undef BITWISE_OP
 #undef SIGNED_SHIFT_OP
 
           BEGIN_CASE(JSOP_ADD)
@@ -3679,79 +3613,77 @@ interrupt:
             lval = FETCH_OPND(-2);
 #if JS_HAS_XML_SUPPORT
             if (!JSVAL_IS_PRIMITIVE(lval) &&
                 (obj2 = JSVAL_TO_OBJECT(lval), OBJECT_IS_XML(cx, obj2)) &&
                 VALUE_IS_XML(cx, rval)) {
                 JSXMLObjectOps *ops;
 
                 ops = (JSXMLObjectOps *) obj2->map->ops;
-                SAVE_SP_AND_PC(fp);
                 if (!ops->concatenate(cx, obj2, rval, &rval))
                     goto error;
-                sp--;
+                regs.sp--;
                 STORE_OPND(-1, rval);
             } else
 #endif
             {
                 if (!JSVAL_IS_PRIMITIVE(lval))
                     DEFAULT_VALUE(cx, -2, JSTYPE_VOID, lval);
                 if (!JSVAL_IS_PRIMITIVE(rval))
                     DEFAULT_VALUE(cx, -1, JSTYPE_VOID, rval);
                 if ((cond = JSVAL_IS_STRING(lval)) || JSVAL_IS_STRING(rval)) {
-                    SAVE_SP_AND_PC(fp);
                     if (cond) {
                         str = JSVAL_TO_STRING(lval);
                         str2 = js_ValueToString(cx, rval);
                         if (!str2)
                             goto error;
-                        sp[-1] = STRING_TO_JSVAL(str2);
+                        regs.sp[-1] = STRING_TO_JSVAL(str2);
                     } else {
                         str2 = JSVAL_TO_STRING(rval);
                         str = js_ValueToString(cx, lval);
                         if (!str)
                             goto error;
-                        sp[-2] = STRING_TO_JSVAL(str);
+                        regs.sp[-2] = STRING_TO_JSVAL(str);
                     }
                     str = js_ConcatStrings(cx, str, str2);
                     if (!str)
                         goto error;
-                    sp--;
+                    regs.sp--;
                     STORE_OPND(-1, STRING_TO_JSVAL(str));
                 } else {
                     VALUE_TO_NUMBER(cx, -2, lval, d);
                     VALUE_TO_NUMBER(cx, -1, rval, d2);
                     d += d2;
-                    sp--;
+                    regs.sp--;
                     STORE_NUMBER(cx, -1, d);
                 }
             }
           END_CASE(JSOP_ADD)
 
 #define BINARY_OP(OP)                                                         \
     JS_BEGIN_MACRO                                                            \
         FETCH_NUMBER(cx, -1, d2);                                             \
         FETCH_NUMBER(cx, -2, d);                                              \
         d = d OP d2;                                                          \
-        sp--;                                                                 \
+        regs.sp--;                                                                 \
         STORE_NUMBER(cx, -1, d);                                              \
     JS_END_MACRO
 
           BEGIN_CASE(JSOP_SUB)
             BINARY_OP(-);
           END_CASE(JSOP_SUB)
 
           BEGIN_CASE(JSOP_MUL)
             BINARY_OP(*);
           END_CASE(JSOP_MUL)
 
           BEGIN_CASE(JSOP_DIV)
             FETCH_NUMBER(cx, -1, d2);
             FETCH_NUMBER(cx, -2, d);
-            sp--;
+            regs.sp--;
             if (d2 == 0) {
 #ifdef XP_WIN
                 /* XXX MSVC miscompiles such that (NaN == 0) */
                 if (JSDOUBLE_IS_NaN(d2))
                     rval = DOUBLE_TO_JSVAL(rt->jsNaN);
                 else
 #endif
                 if (d == 0 || JSDOUBLE_IS_NaN(d))
@@ -3765,17 +3697,17 @@ interrupt:
                 d /= d2;
                 STORE_NUMBER(cx, -1, d);
             }
           END_CASE(JSOP_DIV)
 
           BEGIN_CASE(JSOP_MOD)
             FETCH_NUMBER(cx, -1, d2);
             FETCH_NUMBER(cx, -2, d);
-            sp--;
+            regs.sp--;
             if (d2 == 0) {
                 STORE_OPND(-1, DOUBLE_TO_JSVAL(rt->jsNaN));
             } else {
 #ifdef XP_WIN
               /* Workaround MS fmod bug where 42 % (1/0) => NaN, not 42. */
               if (!(JSDOUBLE_IS_FINITE(d) && JSDOUBLE_IS_INFINITE(d2)))
 #endif
                 d = fmod(d, d2);
@@ -3799,107 +3731,101 @@ interrupt:
              * Optimize the case of an int-tagged operand by noting that
              * INT_FITS_IN_JSVAL(i) => INT_FITS_IN_JSVAL(-i) unless i is 0
              * when -i is the negative zero which is jsdouble.
              */
             rval = FETCH_OPND(-1);
             if (JSVAL_IS_INT(rval) && (i = JSVAL_TO_INT(rval)) != 0) {
                 i = -i;
                 JS_ASSERT(INT_FITS_IN_JSVAL(i));
-                sp[-1] = INT_TO_JSVAL(i);
+                regs.sp[-1] = INT_TO_JSVAL(i);
             } else {
-                SAVE_SP_AND_PC(fp);
                 if (JSVAL_IS_DOUBLE(rval)) {
                     d = *JSVAL_TO_DOUBLE(rval);
                 } else {
-                    d = js_ValueToNumber(cx, &sp[-1]);
-                    if (JSVAL_IS_NULL(sp[-1]))
+                    d = js_ValueToNumber(cx, &regs.sp[-1]);
+                    if (JSVAL_IS_NULL(regs.sp[-1]))
                         goto error;
-                    JS_ASSERT(JSVAL_IS_NUMBER(sp[-1]) || sp[-1] == JSVAL_TRUE);
+                    JS_ASSERT(JSVAL_IS_NUMBER(regs.sp[-1]) ||
+                              regs.sp[-1] == JSVAL_TRUE);
                 }
 #ifdef HPUX
                 /*
                  * Negation of a zero doesn't produce a negative
                  * zero on HPUX. Perform the operation by bit
                  * twiddling.
                  */
                 JSDOUBLE_HI32(d) ^= JSDOUBLE_HI32_SIGNBIT;
 #else
                 d = -d;
 #endif
-                if (!js_NewNumberInRootedValue(cx, d, &sp[-1]))
+                if (!js_NewNumberInRootedValue(cx, d, &regs.sp[-1]))
                     goto error;
             }
           END_CASE(JSOP_NEG)
 
           BEGIN_CASE(JSOP_POS)
             rval = FETCH_OPND(-1);
             if (!JSVAL_IS_NUMBER(rval)) {
-                SAVE_SP_AND_PC(fp);
-                d = js_ValueToNumber(cx, &sp[-1]);
-                rval = sp[-1];
+                d = js_ValueToNumber(cx, &regs.sp[-1]);
+                rval = regs.sp[-1];
                 if (JSVAL_IS_NULL(rval))
                     goto error;
                 if (rval == JSVAL_TRUE) {
-                    if (!js_NewNumberInRootedValue(cx, d, &sp[-1]))
+                    if (!js_NewNumberInRootedValue(cx, d, &regs.sp[-1]))
                         goto error;
                 } else {
                     JS_ASSERT(JSVAL_IS_NUMBER(rval));
                 }
             }
           END_CASE(JSOP_POS)
 
           BEGIN_CASE(JSOP_NEW)
             /* Get immediate argc and find the constructor function. */
-            argc = GET_ARGC(pc);
-            SAVE_SP_AND_PC(fp);
-            vp = sp - (2 + argc);
+            argc = GET_ARGC(regs.pc);
+            vp = regs.sp - (2 + argc);
             JS_ASSERT(vp >= fp->spbase);
 
             if (!js_InvokeConstructor(cx, vp, argc))
                 goto error;
-            sp = vp + 1;
+            regs.sp = vp + 1;
             LOAD_INTERRUPT_HANDLER(cx);
           END_CASE(JSOP_NEW)
 
           BEGIN_CASE(JSOP_DELNAME)
             LOAD_ATOM(0);
             id = ATOM_TO_JSID(atom);
-
-            SAVE_SP_AND_PC(fp);
             if (!js_FindProperty(cx, id, &obj, &obj2, &prop))
                 goto error;
 
             /* ECMA says to return true if name is undefined or inherited. */
-            rval = JSVAL_TRUE;
+            PUSH_OPND(JSVAL_TRUE);
             if (prop) {
                 OBJ_DROP_PROPERTY(cx, obj2, prop);
-                if (!OBJ_DELETE_PROPERTY(cx, obj, id, &rval))
+                if (!OBJ_DELETE_PROPERTY(cx, obj, id, &regs.sp[-1]))
                     goto error;
             }
-            PUSH_OPND(rval);
           END_CASE(JSOP_DELNAME)
 
           BEGIN_CASE(JSOP_DELPROP)
             LOAD_ATOM(0);
             id = ATOM_TO_JSID(atom);
             PROPERTY_OP(-1, OBJ_DELETE_PROPERTY(cx, obj, id, &rval));
             STORE_OPND(-1, rval);
           END_CASE(JSOP_DELPROP)
 
           BEGIN_CASE(JSOP_DELELEM)
             ELEMENT_OP(-1, OBJ_DELETE_PROPERTY(cx, obj, id, &rval));
-            sp--;
+            regs.sp--;
             STORE_OPND(-1, rval);
           END_CASE(JSOP_DELELEM)
 
           BEGIN_CASE(JSOP_TYPEOFEXPR)
           BEGIN_CASE(JSOP_TYPEOF)
             rval = FETCH_OPND(-1);
-            SAVE_SP_AND_PC(fp);
             type = JS_TypeOfValue(cx, rval);
             atom = rt->atomState.typeAtoms[type];
             STORE_OPND(-1, ATOM_KEY(atom));
           END_CASE(JSOP_TYPEOF)
 
           BEGIN_CASE(JSOP_VOID)
             STORE_OPND(-1, JSVAL_VOID);
           END_CASE(JSOP_VOID)
@@ -3920,95 +3846,90 @@ interrupt:
           BEGIN_CASE(JSOP_DECPROP)
           BEGIN_CASE(JSOP_PROPINC)
           BEGIN_CASE(JSOP_PROPDEC)
             LOAD_ATOM(0);
             id = ATOM_TO_JSID(atom);
             i = -1;
 
           fetch_incop_obj:
-            SAVE_SP_AND_PC(fp);
             FETCH_OBJECT(cx, i, lval, obj);
             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)
             LOAD_ATOM(0);
             id = ATOM_TO_JSID(atom);
-
-            SAVE_SP_AND_PC(fp);
             if (!js_FindProperty(cx, id, &obj, &obj2, &prop))
                 goto error;
             if (!prop)
                 goto atom_not_defined;
             OBJ_DROP_PROPERTY(cx, obj2, prop);
 
           do_incop:
           {
             const JSCodeSpec *cs;
             jsval v;
 
             /*
              * We need a root to store the value to leave on the stack until
              * we have done with OBJ_SET_PROPERTY.
              */
             PUSH_OPND(JSVAL_NULL);
-            SAVE_SP(fp);
-            if (!OBJ_GET_PROPERTY(cx, obj, id, &sp[-1]))
+            if (!OBJ_GET_PROPERTY(cx, obj, id, &regs.sp[-1]))
                 goto error;
 
             cs = &js_CodeSpec[op];
             JS_ASSERT(cs->ndefs == 1);
             JS_ASSERT((cs->format & JOF_TMPSLOT_MASK) == JOF_TMPSLOT2);
-            v = sp[-1];
+            v = regs.sp[-1];
             if (JS_LIKELY(CAN_DO_FAST_INC_DEC(v))) {
                 jsval incr;
 
                 incr = (cs->format & JOF_INC) ? 2 : -2;
                 if (cs->format & JOF_POST) {
-                    sp[-1] = v + incr;
+                    regs.sp[-1] = v + incr;
                 } else {
                     v += incr;
-                    sp[-1] = v;
+                    regs.sp[-1] = v;
                 }
                 fp->flags |= JSFRAME_ASSIGNING;
-                ok = OBJ_SET_PROPERTY(cx, obj, id, &sp[-1]);
+                ok = OBJ_SET_PROPERTY(cx, obj, id, &regs.sp[-1]);
                 fp->flags &= ~JSFRAME_ASSIGNING;
                 if (!ok)
                     goto error;
 
                 /*
-                 * We must set sp[-1] to v for both post and pre increments
-                 * as the setter overwrites sp[-1].
+                 * We must set regs.sp[-1] to v for both post and pre increments
+                 * as the setter overwrites regs.sp[-1].
                  */
-                sp[-1] = v;
+                regs.sp[-1] = v;
             } else {
                 /* We need an extra root for the result. */
                 PUSH_OPND(JSVAL_NULL);
-                SAVE_SP(fp);
-                if (!js_DoIncDec(cx, cs, &sp[-2], &sp[-1]))
+                if (!js_DoIncDec(cx, cs, &regs.sp[-2], &regs.sp[-1]))
                     goto error;
                 fp->flags |= JSFRAME_ASSIGNING;
-                ok = OBJ_SET_PROPERTY(cx, obj, id, &sp[-1]);
+                ok = OBJ_SET_PROPERTY(cx, obj, id, &regs.sp[-1]);
                 fp->flags &= ~JSFRAME_ASSIGNING;
                 if (!ok)
                     goto error;
-                sp--;
+                regs.sp--;
             }
 
             if (cs->nuses == 0) {
-                /* sp[-1] already contains the result of name increment. */
+                /* regs.sp[-1] already contains the result of name increment. */
             } else {
-                rtmp = sp[-1];
-                sp -= cs->nuses;
-                sp[-1] = rtmp;
+                rtmp = regs.sp[-1];
+                regs.sp -= cs->nuses;
+                regs.sp[-1] = rtmp;
             }
             len = cs->length;
             DO_NEXT_OP(len);
           }
 
           {
             jsval incr, incr2;
 
@@ -4018,33 +3939,33 @@ interrupt:
           BEGIN_CASE(JSOP_ARGDEC)
             incr = -2; incr2 =  0; goto do_arg_incop;
           BEGIN_CASE(JSOP_INCARG)
             incr =  2; incr2 =  2; goto do_arg_incop;
           BEGIN_CASE(JSOP_ARGINC)
             incr =  2; incr2 =  0;
 
           do_arg_incop:
-            slot = GET_ARGNO(pc);
+            slot = GET_ARGNO(regs.pc);
             JS_ASSERT(slot < fp->fun->nargs);
             METER_SLOT_OP(op, slot);
             vp = fp->argv + slot;
             goto do_int_fast_incop;
 
           BEGIN_CASE(JSOP_DECLOCAL)
             incr = -2; incr2 = -2; goto do_local_incop;
           BEGIN_CASE(JSOP_LOCALDEC)
             incr = -2; incr2 =  0; goto do_local_incop;
           BEGIN_CASE(JSOP_INCLOCAL)
             incr =  2; incr2 =  2; goto do_local_incop;
           BEGIN_CASE(JSOP_LOCALINC)
             incr =  2; incr2 =  0;
 
           do_local_incop:
-            slot = GET_UINT16(pc);
+            slot = GET_UINT16(regs.pc);
             JS_ASSERT(slot < script->depth);
             vp = fp->spbase + slot;
             goto do_int_fast_incop;
 
           BEGIN_CASE(JSOP_DECVAR)
             incr = -2; incr2 = -2; goto do_var_incop;
           BEGIN_CASE(JSOP_VARDEC)
             incr = -2; incr2 =  0; goto do_var_incop;
@@ -4054,30 +3975,29 @@ interrupt:
             incr =  2; incr2 =  0;
 
           /*
            * do_var_incop comes right before do_int_fast_incop as we want to
            * avoid an extra jump for variable cases as var++ is more frequent
            * than arg++ or local++;
            */
           do_var_incop:
-            slot = GET_VARNO(pc);
+            slot = GET_VARNO(regs.pc);
             JS_ASSERT(slot < fp->fun->u.i.nvars);
             METER_SLOT_OP(op, slot);
             vp = fp->vars + slot;
 
           do_int_fast_incop:
             rval = *vp;
             if (JS_LIKELY(CAN_DO_FAST_INC_DEC(rval))) {
                 *vp = rval + incr;
                 PUSH_OPND(rval + incr2);
             } else {
                 PUSH_OPND(rval);
-                SAVE_SP_AND_PC(fp);
-                if (!js_DoIncDec(cx, &js_CodeSpec[op], &sp[-1], vp))
+                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. */
@@ -4099,37 +4019,36 @@ interrupt:
           BEGIN_CASE(JSOP_GVARINC)
             FAST_GLOBAL_INCREMENT_OP(JSOP_NAMEINC,  2,  0);
 
 #undef FAST_GLOBAL_INCREMENT_OP
 
           do_global_incop:
             JS_ASSERT((js_CodeSpec[op].format & JOF_TMPSLOT_MASK) ==
                       JOF_TMPSLOT2);
-            slot = GET_VARNO(pc);
+            slot = GET_VARNO(regs.pc);
             JS_ASSERT(slot < fp->nvars);
             METER_SLOT_OP(op, slot);
             lval = fp->vars[slot];
             if (JSVAL_IS_NULL(lval)) {
                 op = op2;
                 DO_OP();
             }
             slot = JSVAL_TO_INT(lval);
             rval = OBJ_GET_SLOT(cx, fp->varobj, slot);
             if (JS_LIKELY(CAN_DO_FAST_INC_DEC(rval))) {
                 PUSH_OPND(rval + incr2);
                 rval += incr;
             } else {
                 PUSH_OPND(rval);
                 PUSH_OPND(JSVAL_NULL);  /* Extra root */
-                SAVE_SP_AND_PC(fp);
-                if (!js_DoIncDec(cx, &js_CodeSpec[op], &sp[-2], &sp[-1]))
+                if (!js_DoIncDec(cx, &js_CodeSpec[op], &regs.sp[-2], &regs.sp[-1]))
                     goto error;
-                rval = sp[-1];
-                --sp;
+                rval = regs.sp[-1];
+                --regs.sp;
             }
             OBJ_SET_SLOT(cx, fp->varobj, slot, rval);
             len = JSOP_INCGVAR_LENGTH;  /* all gvar incops are same length */
             JS_ASSERT(len == js_CodeSpec[op].length);
             DO_NEXT_OP(len);
           }
 
 #define COMPUTE_THIS(cx, fp, obj)                                             \
@@ -4156,33 +4075,33 @@ interrupt:
             PUSH(JSVAL_NULL);
             len = JSOP_GETTHISPROP_LENGTH;
             goto do_getprop_with_obj;
 
 #undef COMPUTE_THIS
 
           BEGIN_CASE(JSOP_GETARGPROP)
             i = ARGNO_LEN;
-            slot = GET_ARGNO(pc);
+            slot = GET_ARGNO(regs.pc);
             JS_ASSERT(slot < fp->fun->nargs);
             PUSH_OPND(fp->argv[slot]);
             len = JSOP_GETARGPROP_LENGTH;
             goto do_getprop_body;
 
           BEGIN_CASE(JSOP_GETVARPROP)
             i = VARNO_LEN;
-            slot = GET_VARNO(pc);
+            slot = GET_VARNO(regs.pc);
             JS_ASSERT(slot < fp->fun->u.i.nvars);
             PUSH_OPND(fp->vars[slot]);
             len = JSOP_GETVARPROP_LENGTH;
             goto do_getprop_body;
 
           BEGIN_CASE(JSOP_GETLOCALPROP)
             i = UINT16_LEN;
-            slot = GET_UINT16(pc);
+            slot = GET_UINT16(regs.pc);
             JS_ASSERT(slot < script->depth);
             PUSH_OPND(fp->spbase[slot]);
             len = JSOP_GETLOCALPROP_LENGTH;
             goto do_getprop_body;
 
           BEGIN_CASE(JSOP_GETPROP)
           BEGIN_CASE(JSOP_GETXPROP)
             i = 0;
@@ -4194,75 +4113,71 @@ interrupt:
           do_getprop_with_lval:
             VALUE_TO_OBJECT(cx, -1, lval, obj);
 
           do_getprop_with_obj:
             do {
                 JSPropCacheEntry *entry;
 
                 if (JS_LIKELY(obj->map->ops->getProperty == js_GetProperty)) {
-                    PROPERTY_CACHE_TEST(cx, pc, obj, obj2, entry, atom);
+                    PROPERTY_CACHE_TEST(cx, regs.pc, obj, obj2, entry, atom);
                     if (!atom) {
                         ASSERT_VALID_PROPERTY_CACHE_HIT(i, obj, obj2, entry);
                         if (PCVAL_IS_OBJECT(entry->vword)) {
                             rval = PCVAL_OBJECT_TO_JSVAL(entry->vword);
                         } else if (PCVAL_IS_SLOT(entry->vword)) {
                             slot = PCVAL_TO_SLOT(entry->vword);
                             JS_ASSERT(slot < obj2->map->freeslot);
                             rval = LOCKED_OBJ_GET_SLOT(obj2, slot);
                         } else {
                             JS_ASSERT(PCVAL_IS_SPROP(entry->vword));
                             sprop = PCVAL_TO_SPROP(entry->vword);
-                            SAVE_SP_AND_PC(fp);
                             NATIVE_GET(cx, obj, obj2, sprop, &rval);
                         }
                         JS_UNLOCK_OBJ(cx, obj2);
                         break;
                     }
                 } else {
                     entry = NULL;
                     if (i < 0)
                         atom = rt->atomState.lengthAtom;
                     else
                         LOAD_ATOM(i);
                 }
                 id = ATOM_TO_JSID(atom);
-                SAVE_SP_AND_PC(fp);
                 if (entry
                     ? !js_GetPropertyHelper(cx, obj, id, &rval, &entry)
                     : !OBJ_GET_PROPERTY(cx, obj, id, &rval)) {
                     goto error;
                 }
             } while (0);
 
             STORE_OPND(-1, rval);
           END_VARLEN_CASE
 
           BEGIN_CASE(JSOP_LENGTH)
             lval = FETCH_OPND(-1);
             if (JSVAL_IS_STRING(lval)) {
                 str = JSVAL_TO_STRING(lval);
-                sp[-1] = INT_TO_JSVAL(JSSTRING_LENGTH(str));
+                regs.sp[-1] = INT_TO_JSVAL(JSSTRING_LENGTH(str));
             } else if (!JSVAL_IS_PRIMITIVE(lval) &&
                        (obj = JSVAL_TO_OBJECT(lval), OBJ_IS_ARRAY(cx, obj))) {
                 jsuint length;
 
                 /*
                  * We know that the array is created with only its 'length'
                  * private data in a fixed slot at JSSLOT_ARRAY_LENGTH. See
                  * also JSOP_ARRAYPUSH, far below.
                  */
                 length = obj->fslots[JSSLOT_ARRAY_LENGTH];
                 if (length <= JSVAL_INT_MAX) {
-                    sp[-1] = INT_TO_JSVAL(length);
-                } else {
-                    SAVE_SP_AND_PC(fp);
-                    if (!js_NewDoubleInRootedValue(cx, (jsdouble) length,
-                                                   &sp[-1]))
-                        goto error;
+                    regs.sp[-1] = INT_TO_JSVAL(length);
+                } else if (!js_NewDoubleInRootedValue(cx, (jsdouble) length,
+                                                      &regs.sp[-1])) {
+                    goto error;
                 }
             } else {
                 i = -1;
                 len = JSOP_LENGTH_LENGTH;
                 goto do_getprop_with_lval;
             }
           END_CASE(JSOP_LENGTH)
 
@@ -4270,18 +4185,16 @@ interrupt:
           {
             JSObject *aobj;
             JSPropCacheEntry *entry;
 
             lval = FETCH_OPND(-1);
             if (!JSVAL_IS_PRIMITIVE(lval)) {
                 obj = JSVAL_TO_OBJECT(lval);
             } else {
-                SAVE_SP_AND_PC(fp);
-
                 if (JSVAL_IS_STRING(lval)) {
                     i = JSProto_String;
                 } else if (JSVAL_IS_NUMBER(lval)) {
                     i = JSProto_Number;
                 } else if (JSVAL_IS_BOOLEAN(lval)) {
                     i = JSProto_Boolean;
                 } else {
                     JS_ASSERT(JSVAL_IS_NULL(lval) || JSVAL_IS_VOID(lval));
@@ -4290,17 +4203,17 @@ interrupt:
                 }
 
                 if (!js_GetClassPrototype(cx, NULL, INT_TO_JSID(i), &obj))
                     goto error;
             }
 
             aobj = OBJ_IS_DENSE_ARRAY(cx, obj) ? OBJ_GET_PROTO(cx, obj) : obj;
             if (JS_LIKELY(aobj->map->ops->getProperty == js_GetProperty)) {
-                PROPERTY_CACHE_TEST(cx, pc, aobj, obj2, entry, atom);
+                PROPERTY_CACHE_TEST(cx, regs.pc, aobj, obj2, entry, atom);
                 if (!atom) {
                     ASSERT_VALID_PROPERTY_CACHE_HIT(0, aobj, obj2, entry);
                     if (PCVAL_IS_OBJECT(entry->vword)) {
                         rval = PCVAL_OBJECT_TO_JSVAL(entry->vword);
                     } else if (PCVAL_IS_SLOT(entry->vword)) {
                         slot = PCVAL_TO_SLOT(entry->vword);
                         JS_ASSERT(slot < obj2->map->freeslot);
                         rval = LOCKED_OBJ_GET_SLOT(obj2, slot);
@@ -4320,17 +4233,16 @@ interrupt:
             }
 
             /*
              * Cache miss: use the immediate atom that was loaded for us under
              * PROPERTY_CACHE_TEST.
              */
             id = ATOM_TO_JSID(atom);
             PUSH(JSVAL_NULL);
-            SAVE_SP_AND_PC(fp);
             if (!JSVAL_IS_PRIMITIVE(lval)) {
 #if JS_HAS_XML_SUPPORT
                 /* Special-case XML object method lookup, per ECMA-357. */
                 if (OBJECT_IS_XML(cx, obj)) {
                     JSXMLObjectOps *ops;
 
                     ops = (JSXMLObjectOps *) obj->map->ops;
                     obj = ops->getMethod(cx, obj, id, &rval);
@@ -4356,26 +4268,25 @@ interrupt:
           end_callprop:
             /* Wrap primitive lval in object clothing if necessary. */
             if (JSVAL_IS_PRIMITIVE(lval)) {
                 /* FIXME: https://bugzilla.mozilla.org/show_bug.cgi?id=412571 */
                 if (!VALUE_IS_FUNCTION(cx, rval) ||
                     (obj = JSVAL_TO_OBJECT(rval),
                      fun = GET_FUNCTION_PRIVATE(cx, obj),
                      !PRIMITIVE_THIS_TEST(fun, lval))) {
-                    if (!js_PrimitiveToObject(cx, &sp[-1]))
+                    if (!js_PrimitiveToObject(cx, &regs.sp[-1]))
                         goto error;
                 }
             }
 #if JS_HAS_NO_SUCH_METHOD
             if (JS_UNLIKELY(rval == JSVAL_VOID)) {
                 LOAD_ATOM(0);
-                sp[-2] = ATOM_KEY(atom);
-                SAVE_SP_AND_PC(fp);
-                if (!js_OnUnknownMethod(cx, sp - 2))
+                regs.sp[-2] = ATOM_KEY(atom);
+                if (!js_OnUnknownMethod(cx, regs.sp - 2))
                     goto error;
             }
 #endif
           }
           END_CASE(JSOP_CALLPROP)
 
           BEGIN_CASE(JSOP_SETNAME)
           BEGIN_CASE(JSOP_SETPROP)
@@ -4407,20 +4318,21 @@ interrupt:
                      * of property additions. And second:
                      *
                      *   o.p = x;
                      *
                      * in a frequently executed method or loop body, where p
                      * will (possibly after the first iteration) always exist
                      * in native object o.
                      */
-                    entry = &cache->table[PROPERTY_CACHE_HASH_PC(pc, kshape)];
+                    entry = &cache->table[PROPERTY_CACHE_HASH_PC(regs.pc,
+                                                                 kshape)];
                     PCMETER(cache->tests++);
                     PCMETER(cache->settests++);
-                    if (entry->kpc == pc && entry->kshape == kshape) {
+                    if (entry->kpc == regs.pc && entry->kshape == kshape) {
                         JSScope *scope;
 
                         JS_LOCK_OBJ(cx, obj);
                         scope = OBJ_SCOPE(obj);
                         if (scope->shape == kshape) {
                             JS_ASSERT(PCVAL_IS_SPROP(entry->vword));
                             sprop = PCVAL_TO_SPROP(entry->vword);
                             JS_ASSERT(!(sprop->attrs & JSPROP_READONLY));
@@ -4534,17 +4446,17 @@ interrupt:
 
                             PCMETER(cache->setpcmisses++);
                             atom = NULL;
                         }
 
                         JS_UNLOCK_OBJ(cx, obj);
                     }
 
-                    atom = js_FullTestPropertyCache(cx, pc, &obj, &obj2,
+                    atom = js_FullTestPropertyCache(cx, regs.pc, &obj, &obj2,
                                                     &entry);
                     if (atom) {
                         PCMETER(cache->misses++);
                         PCMETER(cache->setmisses++);
                     } else {
                         ASSERT_VALID_PROPERTY_CACHE_HIT(0, obj, obj2, entry);
                         if (obj == obj2) {
                             if (PCVAL_IS_SLOT(entry->vword)) {
@@ -4562,31 +4474,29 @@ interrupt:
                         if (obj == obj2 && !PCVAL_IS_OBJECT(entry->vword))
                             break;
                     }
                 }
 
                 if (!atom)
                     LOAD_ATOM(0);
                 id = ATOM_TO_JSID(atom);
-                SAVE_SP_AND_PC(fp);
                 if (entry
                     ? !js_SetPropertyHelper(cx, obj, id, &rval, &entry)
                     : !OBJ_SET_PROPERTY(cx, obj, id, &rval)) {
                     goto error;
                 }
             } while (0);
 
-            sp--;
+            regs.sp--;
             STORE_OPND(-1, rval);
           END_CASE(JSOP_SETPROP)
 
           BEGIN_CASE(JSOP_GETELEM)
             /* Open-coded ELEMENT_OP optimized for strings and dense arrays. */
-            SAVE_SP_AND_PC(fp);
             lval = FETCH_OPND(-2);
             rval = FETCH_OPND(-1);
             if (JSVAL_IS_STRING(lval) && JSVAL_IS_INT(rval)) {
                 str = JSVAL_TO_STRING(lval);
                 i = JSVAL_TO_INT(rval);
                 if ((size_t)i < JSSTRING_LENGTH(str)) {
                     str = js_GetUnitString(cx, str, (size_t)i);
                     if (!str)
@@ -4614,44 +4524,42 @@ interrupt:
             } else {
                 if (!js_InternNonIntElementId(cx, obj, rval, &id))
                     goto error;
             }
 
             if (!OBJ_GET_PROPERTY(cx, obj, id, &rval))
                 goto error;
           end_getelem:
-            sp--;
+            regs.sp--;
             STORE_OPND(-1, rval);
           END_CASE(JSOP_GETELEM)
 
           BEGIN_CASE(JSOP_CALLELEM)
             /*
              * FIXME: JSOP_CALLELEM should call getMethod on XML objects as
              * CALLPROP does. See bug 362910.
              */
             ELEMENT_OP(-1, OBJ_GET_PROPERTY(cx, obj, id, &rval));
 #if JS_HAS_NO_SUCH_METHOD
             if (JS_UNLIKELY(rval == JSVAL_VOID)) {
-                sp[-2] = sp[-1];
-                sp[-1] = OBJECT_TO_JSVAL(obj);
-                SAVE_SP_AND_PC(fp);
-                if (!js_OnUnknownMethod(cx, sp - 2))
+                regs.sp[-2] = regs.sp[-1];
+                regs.sp[-1] = OBJECT_TO_JSVAL(obj);
+                if (!js_OnUnknownMethod(cx, regs.sp - 2))
                     goto error;
             } else
 #endif
             {
                 STORE_OPND(-2, rval);
                 STORE_OPND(-1, OBJECT_TO_JSVAL(obj));
             }
           END_CASE(JSOP_CALLELEM)
 
           BEGIN_CASE(JSOP_SETELEM)
             rval = FETCH_OPND(-1);
-            SAVE_SP_AND_PC(fp);
             FETCH_OBJECT(cx, -3, lval, obj);
             FETCH_ELEMENT_ID(obj, -2, id);
             if (OBJ_IS_DENSE_ARRAY(cx, obj) && JSID_IS_INT(id)) {
                 jsuint length;
 
                 length = ARRAY_DENSE_LENGTH(obj);
                 i = JSID_TO_INT(id);
                 if ((jsuint)i < length) {
@@ -4662,106 +4570,103 @@ interrupt:
                     }
                     obj->dslots[i] = rval;
                     goto end_setelem;
                 }
             }
             if (!OBJ_SET_PROPERTY(cx, obj, id, &rval))
                 goto error;
         end_setelem:
-            sp -= 2;
+            regs.sp -= 2;
             STORE_OPND(-1, rval);
           END_CASE(JSOP_SETELEM)
 
           BEGIN_CASE(JSOP_ENUMELEM)
             /* Funky: the value to set is under the [obj, id] pair. */
             rval = FETCH_OPND(-3);
-            SAVE_SP_AND_PC(fp);
             FETCH_OBJECT(cx, -2, lval, obj);
             FETCH_ELEMENT_ID(obj, -1, id);
             if (!OBJ_SET_PROPERTY(cx, obj, id, &rval))
                 goto error;
-            sp -= 3;
+            regs.sp -= 3;
           END_CASE(JSOP_ENUMELEM)
 
           BEGIN_CASE(JSOP_CALL)
           BEGIN_CASE(JSOP_EVAL)
-            argc = GET_ARGC(pc);
-            vp = sp - (argc + 2);
+            argc = GET_ARGC(regs.pc);
+            vp = regs.sp - (argc + 2);
             lval = *vp;
-            SAVE_SP_AND_PC(fp);
             if (VALUE_IS_FUNCTION(cx, lval)) {
                 obj = JSVAL_TO_OBJECT(lval);
                 fun = GET_FUNCTION_PRIVATE(cx, obj);
 
                 if (FUN_INTERPRETED(fun)) {
-                    uintN nframeslots, nvars, nslots, missing;
+                    uintN nframeslots, nvars, missing;
                     JSArena *a;
-                    jsuword avail, nbytes;
+                    jsuword nbytes;
                     void *newmark;
-                    jsval *newsp, *rvp;
-                    JSBool overflow;
+                    jsval *newsp;
                     JSInlineFrame *newifp;
                     JSInterpreterHook hook;
 
                     /* Compute the total number of stack slots needed by fun. */
                     nframeslots = JS_HOWMANY(sizeof(JSInlineFrame),
                                              sizeof(jsval));
                     nvars = fun->u.i.nvars;
                     script = fun->u.i.script;
                     atoms = script->atomMap.vector;
-                    nslots = nframeslots + nvars + script->depth;
+                    nbytes = (nframeslots + nvars + script->depth) *
+                             sizeof(jsval);
 
                     /* Allocate missing expected args adjacent to actuals. */
-                    missing = (fun->nargs > argc) ? fun->nargs - argc : 0;
                     a = cx->stackPool.current;
-                    avail = a->avail;
-                    newmark = (void *) avail;
-                    if (missing) {
-                        newsp = sp + missing;
-                        overflow = (jsuword) newsp > a->limit;
-                        if (overflow)
-                            nslots += 2 + argc + missing;
-                        else if ((jsuword) newsp > avail)
-                            avail = a->avail = (jsuword) newsp;
+                    newmark = (void *) a->avail;
+                    if (fun->nargs <= argc) {
+                        missing = 0;
+                    } else {
+                        newsp = vp + 2 + fun->nargs;
+                        JS_ASSERT(newsp > regs.sp);
+                        if ((jsuword) newsp <= a->limit) {
+                            if ((jsuword) newsp > a->avail)
+                                a->avail = (jsuword) newsp;
+                            do {
+                                *--newsp = JSVAL_VOID;
+                            } while (newsp != regs.sp);
+                            missing = 0;
+                        } else {
+                            missing = fun->nargs - argc;
+                            nbytes += (2 + fun->nargs) * sizeof(jsval);
+                        }
                     }
-#ifdef __GNUC__
-                    else overflow = JS_FALSE; /* suppress bogus gcc warnings */
-#endif
 
                     /* Allocate the inline frame with its vars and operands. */
-                    newsp = (jsval *) avail;
-                    nbytes = nslots * sizeof(jsval);
-                    avail += nbytes;
-                    if (avail <= a->limit) {
-                        a->avail = avail;
+                    if (a->avail + nbytes <= a->limit) {
+                        newsp = (jsval *) a->avail;
+                        a->avail += nbytes;
+                        JS_ASSERT(missing == 0);
                     } else {
                         JS_ARENA_ALLOCATE_CAST(newsp, jsval *, &cx->stackPool,
                                                nbytes);
                         if (!newsp) {
                             js_ReportOutOfScriptQuota(cx);
                             goto bad_inline_call;
                         }
-                    }
-
-                    /*
-                     * Move args if missing overflow arena a, then push any
-                     * missing args.
-                     */
-                    rvp = vp;
-                    if (missing) {
-                        if (overflow) {
+
+                        /*
+                         * Move args if missing overflow arena a, then push
+                         * any missing args.
+                         */
+                        if (missing) {
                             memcpy(newsp, vp, (2 + argc) * sizeof(jsval));
                             vp = newsp;
-                            sp = vp + 2 + argc;
-                            newsp = sp + missing;
+                            newsp = vp + 2 + argc;
+                            do {
+                                *newsp++ = JSVAL_VOID;
+                            } while (--missing != 0);
                         }
-                        do {
-                            PUSH(JSVAL_VOID);
-                        } while (--missing != 0);
                     }
 
                     /* Claim space for the stack frame and initialize it. */
                     newifp = (JSInlineFrame *) newsp;
                     newsp += nframeslots;
                     newifp->frame.callobj = NULL;
                     newifp->frame.argsobj = NULL;
                     newifp->frame.varobj = NULL;
@@ -4781,35 +4686,33 @@ interrupt:
                     newifp->frame.flags = 0;
                     newifp->frame.dormantNext = NULL;
                     newifp->frame.xmlNamespace = NULL;
                     newifp->frame.blockChain = NULL;
 #ifdef DEBUG
                     newifp->frame.pcDisabledSave =
                         JS_PROPERTY_CACHE(cx).disabled;
 #endif
-                    newifp->rvp = rvp;
                     newifp->mark = newmark;
 
                     /* Compute the 'this' parameter now that argv is set. */
                     JS_ASSERT(!JSFUN_BOUND_METHOD_TEST(fun->flags));
                     JS_ASSERT(JSVAL_IS_OBJECT(vp[1]));
                     newifp->frame.thisp = (JSObject *)vp[1];
 
                     /* Push void to initialize local variables. */
-                    sp = newsp;
                     while (nvars--)
-                        PUSH(JSVAL_VOID);
-                    newifp->frame.spbase = sp;
-                    SAVE_SP(&newifp->frame);
+                        *newsp++ = JSVAL_VOID;
+
+                    newifp->frame.regs = NULL;
+                    newifp->frame.spbase = NULL;
 
                     /* Call the debugger hook if present. */
                     hook = cx->debugHooks->callHook;
                     if (hook) {
-                        newifp->frame.pc = NULL;
                         newifp->hookData = hook(cx, &newifp->frame, JS_TRUE, 0,
                                                 cx->debugHooks->callHookData);
                         LOAD_INTERRUPT_HANDLER(cx);
                     } else {
                         newifp->hookData = NULL;
                     }
 
                     /* Scope with a call object parented by callee's parent. */
@@ -4822,38 +4725,42 @@ interrupt:
                     newifp->callerVersion = (JSVersion) cx->version;
                     if (JS_LIKELY(cx->version == currentVersion)) {
                         currentVersion = (JSVersion) script->version;
                         if (currentVersion != cx->version)
                             js_SetVersion(cx, currentVersion);
                     }
 
                     /* Push the frame and set interpreter registers. */
+                    newifp->callerRegs = regs;
+                    fp->regs = &newifp->callerRegs;
+                    regs.sp = newifp->frame.spbase = newsp;
+                    regs.pc = script->code;
+                    newifp->frame.regs = &regs;
                     cx->fp = fp = &newifp->frame;
-                    pc = script->code;
+
                     inlineCallCount++;
                     JS_RUNTIME_METER(rt, inlineCalls);
 
 #ifdef INCLUDE_MOZILLA_DTRACE
                     /* DTrace function entry, inlines */
                     if (JAVASCRIPT_FUNCTION_ENTRY_ENABLED())
                         jsdtrace_function_entry(cx, fp, fun);
                     if (JAVASCRIPT_FUNCTION_INFO_ENABLED())
                         jsdtrace_function_info(cx, fp, fp->down, fun);
                     if (JAVASCRIPT_FUNCTION_ARGS_ENABLED())
                         jsdtrace_function_args(cx, fp, fun);
 #endif
 
                     /* Load first op and dispatch it (safe since JSOP_STOP). */
-                    op = (JSOp) *pc;
+                    op = (JSOp) *regs.pc;
                     DO_OP();
 
                   bad_inline_call:
-                    RESTORE_SP(fp);
-                    JS_ASSERT(fp->pc == pc);
+                    JS_ASSERT(fp->regs == &regs);
                     script = fp->script;
                     atoms = script->atomMap.vector;
                     js_FreeRawStack(cx, newmark);
                     goto error;
                 }
 
 #ifdef INCLUDE_MOZILLA_DTRACE
                 /* DTrace function entry, non-inlines */
@@ -4872,55 +4779,54 @@ interrupt:
                     if (argc < fun->u.n.minargs) {
                         uintN nargs;
 
                         /*
                          * If we can't fit missing args and local roots in
                          * this frame's operand stack, take the slow path.
                          */
                         nargs = fun->u.n.minargs - argc;
-                        if (sp + nargs > fp->spbase + script->depth)
+                        if (regs.sp + nargs > fp->spbase + script->depth)
                             goto do_invoke;
                         do {
                             PUSH(JSVAL_VOID);
                         } while (--nargs != 0);
-                        SAVE_SP(fp);
                     }
 
                     JS_ASSERT(JSVAL_IS_OBJECT(vp[1]) ||
                               PRIMITIVE_THIS_TEST(fun, vp[1]));
 
                     ok = ((JSFastNative) fun->u.n.native)(cx, argc, vp);
 #ifdef INCLUDE_MOZILLA_DTRACE
                     if (VALUE_IS_FUNCTION(cx, lval)) {
                         if (JAVASCRIPT_FUNCTION_RVAL_ENABLED())
                             jsdtrace_function_rval(cx, fp, fun);
                         if (JAVASCRIPT_FUNCTION_RETURN_ENABLED())
                             jsdtrace_function_return(cx, fp, fun);
                     }
 #endif
                     if (!ok)
                         goto error;
-                    sp = vp + 1;
+                    regs.sp = vp + 1;
                     goto end_call;
                 }
             }
 
           do_invoke:
             ok = js_Invoke(cx, argc, vp, 0);
 #ifdef INCLUDE_MOZILLA_DTRACE
             /* DTrace function return, non-inlines */
             if (VALUE_IS_FUNCTION(cx, lval)) {
                 if (JAVASCRIPT_FUNCTION_RVAL_ENABLED())
                     jsdtrace_function_rval(cx, fp, fun);
                 if (JAVASCRIPT_FUNCTION_RETURN_ENABLED())
                     jsdtrace_function_return(cx, fp, fun);
             }
 #endif
-            sp = vp + 1;
+            regs.sp = vp + 1;
             LOAD_INTERRUPT_HANDLER(cx);
             if (!ok)
                 goto error;
             JS_RUNTIME_METER(rt, nonInlineCalls);
 
           end_call:
 #if JS_HAS_LVALUE_RETURN
             if (cx->rval2set) {
@@ -4936,30 +4842,29 @@ interrupt:
                  * ECMA "reference type", which can be used on the right- or
                  * left-hand side of assignment ops.  Note well: only native
                  * methods can return reference types.  See JSOP_SETCALL just
                  * below for the left-hand-side case.
                  */
                 PUSH_OPND(cx->rval2);
                 ELEMENT_OP(-1, OBJ_GET_PROPERTY(cx, obj, id, &rval));
 
-                sp--;
+                regs.sp--;
                 STORE_OPND(-1, rval);
                 cx->rval2set = JS_FALSE;
             }
 #endif /* JS_HAS_LVALUE_RETURN */
           END_CASE(JSOP_CALL)
 
 #if JS_HAS_LVALUE_RETURN
           BEGIN_CASE(JSOP_SETCALL)
-            argc = GET_ARGC(pc);
-            SAVE_SP_AND_PC(fp);
-            vp = sp - argc - 2;
+            argc = GET_ARGC(regs.pc);
+            vp = regs.sp - argc - 2;
             ok = js_Invoke(cx, argc, vp, 0);
-            sp = vp + 1;
+            regs.sp = vp + 1;
             LOAD_INTERRUPT_HANDLER(cx);
             if (!ok)
                 goto error;
             if (!cx->rval2set) {
                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                      JSMSG_BAD_LEFTSIDE_OF_ASS);
                 goto error;
             }
@@ -4970,17 +4875,17 @@ interrupt:
 
           BEGIN_CASE(JSOP_NAME)
           BEGIN_CASE(JSOP_CALLNAME)
           {
             JSPropCacheEntry *entry;
 
             obj = fp->scopeChain;
             if (JS_LIKELY(OBJ_IS_NATIVE(obj))) {
-                PROPERTY_CACHE_TEST(cx, pc, obj, obj2, entry, atom);
+                PROPERTY_CACHE_TEST(cx, regs.pc, obj, obj2, entry, atom);
                 if (!atom) {
                     ASSERT_VALID_PROPERTY_CACHE_HIT(0, obj, obj2, entry);
                     if (PCVAL_IS_OBJECT(entry->vword)) {
                         rval = PCVAL_OBJECT_TO_JSVAL(entry->vword);
                         JS_UNLOCK_OBJ(cx, obj2);
                         goto do_push_rval;
                     }
 
@@ -4997,24 +4902,23 @@ interrupt:
                     goto do_native_get;
                 }
             } else {
                 entry = NULL;
                 LOAD_ATOM(0);
             }
 
             id = ATOM_TO_JSID(atom);
-            SAVE_SP_AND_PC(fp);
             if (js_FindPropertyHelper(cx, id, &obj, &obj2, &prop, &entry) < 0)
                 goto error;
             if (!prop) {
                 /* Kludge to allow (typeof foo == "undefined") tests. */
                 len = JSOP_NAME_LENGTH;
                 endpc = script->code + script->length;
-                for (pc2 = pc + len; pc2 < endpc; pc2++) {
+                for (pc2 = regs.pc + len; pc2 < endpc; pc2++) {
                     op2 = (JSOp)*pc2;
                     if (op2 == JSOP_TYPEOF) {
                         PUSH_OPND(JSVAL_VOID);
                         DO_NEXT_OP(len);
                     }
                     if (op2 != JSOP_GROUP)
                         break;
                 }
@@ -5037,45 +4941,45 @@ interrupt:
           do_push_rval:
             PUSH_OPND(rval);
             if (op == JSOP_CALLNAME)
                 PUSH_OPND(OBJECT_TO_JSVAL(obj));
           }
           END_CASE(JSOP_NAME)
 
           BEGIN_CASE(JSOP_UINT16)
-            i = (jsint) GET_UINT16(pc);
+            i = (jsint) GET_UINT16(regs.pc);
             rval = INT_TO_JSVAL(i);
             PUSH_OPND(rval);
           END_CASE(JSOP_UINT16)
 
           BEGIN_CASE(JSOP_UINT24)
-            i = (jsint) GET_UINT24(pc);
+            i = (jsint) GET_UINT24(regs.pc);
             rval = INT_TO_JSVAL(i);
             PUSH_OPND(rval);
           END_CASE(JSOP_UINT24)
 
           BEGIN_CASE(JSOP_INT8)
-            i = GET_INT8(pc);
+            i = GET_INT8(regs.pc);
             rval = INT_TO_JSVAL(i);
             PUSH_OPND(rval);
           END_CASE(JSOP_INT8)
 
           BEGIN_CASE(JSOP_INT32)
-            i = GET_INT32(pc);
+            i = GET_INT32(regs.pc);
             rval = INT_TO_JSVAL(i);
             PUSH_OPND(rval);
           END_CASE(JSOP_INT32)
 
           BEGIN_CASE(JSOP_INDEXBASE)
             /*
              * Here atoms can exceed script->atomMap.length as we use atoms
              * as a segment register for object literals as well.
              */
-            atoms += GET_INDEXBASE(pc);
+            atoms += GET_INDEXBASE(regs.pc);
           END_CASE(JSOP_INDEXBASE)
 
           BEGIN_CASE(JSOP_INDEXBASE1)
           BEGIN_CASE(JSOP_INDEXBASE2)
           BEGIN_CASE(JSOP_INDEXBASE3)
             atoms += (op - JSOP_INDEXBASE1 + 1) << 16;
           END_CASE(JSOP_INDEXBASE3)
 
@@ -5156,25 +5060,16 @@ interrupt:
 
             if (JSVAL_IS_NULL(rval)) {
                 /* Compute the current global object in obj2. */
                 obj2 = fp->scopeChain;
                 while ((parent = OBJ_GET_PARENT(cx, obj2)) != NULL)
                     obj2 = parent;
 
                 /*
-                 * We must home sp here, because either js_CloneRegExpObject
-                 * or JS_SetReservedSlot could nest a last-ditch GC.  We home
-                 * pc as well, in case js_CloneRegExpObject has to lookup the
-                 * "RegExp" class in the global object, which could entail a
-                 * JSNewResolveOp call.
-                 */
-                SAVE_SP_AND_PC(fp);
-
-                /*
                  * If obj's parent is not obj2, we must clone obj so that it
                  * has the right parent, and therefore, the right prototype.
                  *
                  * Yes, this means we assume that the correct RegExp.prototype
                  * to which regexp instances (including literals) delegate can
                  * be distinguished solely by the instance's parent, which was
                  * set to the parent of the RegExp constructor function object
                  * when the instance was created.  In other words,
@@ -5230,17 +5125,17 @@ interrupt:
             PUSH_OPND(JSVAL_FALSE);
           END_CASE(JSOP_FALSE)
 
           BEGIN_CASE(JSOP_TRUE)
             PUSH_OPND(JSVAL_TRUE);
           END_CASE(JSOP_TRUE)
 
           BEGIN_CASE(JSOP_TABLESWITCH)
-            pc2 = pc;
+            pc2 = regs.pc;
             len = GET_JUMP_OFFSET(pc2);
 
             /*
              * ECMAv2+ forbids conversion of discriminant, so we will skip to
              * the default case if the discriminant isn't already an int jsval.
              * (This opcode is emitted only for dense jsint-domain switches.)
              */
             rval = POP_OPND();
@@ -5258,17 +5153,17 @@ interrupt:
                 pc2 += JUMP_OFFSET_LEN + JUMP_OFFSET_LEN * i;
                 off = (jsint) GET_JUMP_OFFSET(pc2);
                 if (off)
                     len = off;
             }
           END_VARLEN_CASE
 
           BEGIN_CASE(JSOP_TABLESWITCHX)
-            pc2 = pc;
+            pc2 = regs.pc;
             len = GET_JUMPX_OFFSET(pc2);
 
             /*
              * ECMAv2+ forbids conversion of discriminant, so we will skip to
              * the default case if the discriminant isn't already an int jsval.
              * (This opcode is emitted only for dense jsint-domain switches.)
              */
             rval = POP_OPND();
@@ -5298,17 +5193,17 @@ interrupt:
             off = JUMP_OFFSET_LEN;
 
           do_lookup_switch:
             /*
              * JSOP_LOOKUPSWITCH and JSOP_LOOKUPSWITCHX are never used if
              * any atom index in it would exceed 64K limit.
              */
             JS_ASSERT(atoms == script->atomMap.vector);
-            pc2 = pc;
+            pc2 = regs.pc;
             lval = POP_OPND();
 
             if (!JSVAL_IS_NUMBER(lval) &&
                 !JSVAL_IS_STRING(lval) &&
                 !JSVAL_IS_BOOLEAN(lval)) {
                 goto end_lookup_switch;
             }
 
@@ -5323,17 +5218,17 @@ interrupt:
         atom = atoms[GET_INDEX(pc2)];                                         \
         rval = ATOM_KEY(atom);                                                \
         MATCH_CODE                                                            \
         pc2 += INDEX_LEN;                                                     \
         if (match)                                                            \
             break;                                                            \
         pc2 += off;                                                           \
         if (--npairs == 0) {                                                  \
-            pc2 = pc;                                                         \
+            pc2 = regs.pc;                                                    \
             break;                                                            \
         }                                                                     \
     }
             if (JSVAL_IS_STRING(lval)) {
                 str = JSVAL_TO_STRING(lval);
                 SEARCH_PAIRS(
                     match = (JSVAL_IS_STRING(rval) &&
                              ((str2 = JSVAL_TO_STRING(rval)) == str ||
@@ -5358,17 +5253,16 @@ interrupt:
                   : GET_JUMPX_OFFSET(pc2);
           END_VARLEN_CASE
 
           EMPTY_CASE(JSOP_CONDSWITCH)
 
 #if JS_HAS_EXPORT_IMPORT
           BEGIN_CASE(JSOP_EXPORTALL)
             obj = fp->varobj;
-            SAVE_SP_AND_PC(fp);
             ida = JS_Enumerate(cx, obj);
             if (!ida)
                 goto error;
             ok = JS_TRUE;
             for (i = 0; i != ida->length; i++) {
                 id = ida->vector[i];
                 ok = OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop);
                 if (!ok)
@@ -5389,17 +5283,16 @@ interrupt:
             if (!ok)
                 goto error;
           END_CASE(JSOP_EXPORTALL)
 
           BEGIN_CASE(JSOP_EXPORTNAME)
             LOAD_ATOM(0);
             id = ATOM_TO_JSID(atom);
             obj = fp->varobj;
-            SAVE_SP_AND_PC(fp);
             if (!OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop))
                 goto error;
             if (!prop) {
                 if (!OBJ_DEFINE_PROPERTY(cx, obj, id, JSVAL_VOID,
                                          JS_PropertyStub, JS_PropertyStub,
                                          JSPROP_EXPORTED, NULL)) {
                     goto error;
                 }
@@ -5413,36 +5306,35 @@ interrupt:
                 if (!ok)
                     goto error;
             }
           END_CASE(JSOP_EXPORTNAME)
 
           BEGIN_CASE(JSOP_IMPORTALL)
             id = (jsid) JSVAL_VOID;
             PROPERTY_OP(-1, js_ImportProperty(cx, obj, id));
-            sp--;
+            regs.sp--;
           END_CASE(JSOP_IMPORTALL)
 
           BEGIN_CASE(JSOP_IMPORTPROP)
             /* Get an immediate atom naming the property. */
             LOAD_ATOM(0);
             id = ATOM_TO_JSID(atom);
             PROPERTY_OP(-1, js_ImportProperty(cx, obj, id));
-            sp--;
+            regs.sp--;
           END_CASE(JSOP_IMPORTPROP)
 
           BEGIN_CASE(JSOP_IMPORTELEM)
             ELEMENT_OP(-1, js_ImportProperty(cx, obj, id));
-            sp -= 2;
+            regs.sp -= 2;
           END_CASE(JSOP_IMPORTELEM)
 #endif /* JS_HAS_EXPORT_IMPORT */
 
           BEGIN_CASE(JSOP_TRAP)
-            SAVE_SP_AND_PC(fp);
-            switch (JS_HandleTrap(cx, script, pc, &rval)) {
+            switch (JS_HandleTrap(cx, script, regs.pc, &rval)) {
               case JSTRAP_ERROR:
                 goto error;
               case JSTRAP_CONTINUE:
                 JS_ASSERT(JSVAL_IS_INT(rval));
                 op = (JSOp) JSVAL_TO_INT(rval);
                 JS_ASSERT((uintN)op < (uintN)JSOP_LIMIT);
                 LOAD_INTERRUPT_HANDLER(cx);
                 DO_OP();
@@ -5455,141 +5347,136 @@ interrupt:
                 cx->exception = rval;
                 goto error;
               default:;
             }
             LOAD_INTERRUPT_HANDLER(cx);
           END_CASE(JSOP_TRAP)
 
           BEGIN_CASE(JSOP_ARGUMENTS)
-            SAVE_SP_AND_PC(fp);
             if (!js_GetArgsValue(cx, fp, &rval))
                 goto error;
             PUSH_OPND(rval);
           END_CASE(JSOP_ARGUMENTS)
 
           BEGIN_CASE(JSOP_ARGSUB)
-            id = INT_TO_JSID(GET_ARGNO(pc));
-            SAVE_SP_AND_PC(fp);
+            id = INT_TO_JSID(GET_ARGNO(regs.pc));
             if (!js_GetArgsProperty(cx, fp, id, &rval))
                 goto error;
             PUSH_OPND(rval);
           END_CASE(JSOP_ARGSUB)
 
           BEGIN_CASE(JSOP_ARGCNT)
             id = ATOM_TO_JSID(rt->atomState.lengthAtom);
-            SAVE_SP_AND_PC(fp);
             if (!js_GetArgsProperty(cx, fp, id, &rval))
                 goto error;
             PUSH_OPND(rval);
           END_CASE(JSOP_ARGCNT)
 
           BEGIN_CASE(JSOP_GETARG)
           BEGIN_CASE(JSOP_CALLARG)
-            slot = GET_ARGNO(pc);
+            slot = GET_ARGNO(regs.pc);
             JS_ASSERT(slot < fp->fun->nargs);
             METER_SLOT_OP(op, slot);
             PUSH_OPND(fp->argv[slot]);
             if (op == JSOP_CALLARG)
                 PUSH_OPND(JSVAL_NULL);
           END_CASE(JSOP_GETARG)
 
           BEGIN_CASE(JSOP_SETARG)
-            slot = GET_ARGNO(pc);
+            slot = GET_ARGNO(regs.pc);
             JS_ASSERT(slot < fp->fun->nargs);
             METER_SLOT_OP(op, slot);
             vp = &fp->argv[slot];
             GC_POKE(cx, *vp);
             *vp = FETCH_OPND(-1);
           END_CASE(JSOP_SETARG)
 
           BEGIN_CASE(JSOP_GETVAR)
           BEGIN_CASE(JSOP_CALLVAR)
-            slot = GET_VARNO(pc);
+            slot = GET_VARNO(regs.pc);
             JS_ASSERT(slot < fp->fun->u.i.nvars);
             METER_SLOT_OP(op, slot);
             PUSH_OPND(fp->vars[slot]);
             if (op == JSOP_CALLVAR)
                 PUSH_OPND(JSVAL_NULL);
           END_CASE(JSOP_GETVAR)
 
           BEGIN_CASE(JSOP_SETVAR)
-            slot = GET_VARNO(pc);
+            slot = GET_VARNO(regs.pc);
             JS_ASSERT(slot < fp->fun->u.i.nvars);
             METER_SLOT_OP(op, slot);
             vp = &fp->vars[slot];
             GC_POKE(cx, *vp);
             *vp = FETCH_OPND(-1);
           END_CASE(JSOP_SETVAR)
 
           BEGIN_CASE(JSOP_GETGVAR)
           BEGIN_CASE(JSOP_CALLGVAR)
-            slot = GET_VARNO(pc);
+            slot = GET_VARNO(regs.pc);
             JS_ASSERT(slot < fp->nvars);
             METER_SLOT_OP(op, slot);
             lval = fp->vars[slot];
             if (JSVAL_IS_NULL(lval)) {
                 op = (op == JSOP_GETGVAR) ? JSOP_NAME : JSOP_CALLNAME;
                 DO_OP();
             }
             slot = JSVAL_TO_INT(lval);
             obj = fp->varobj;
             rval = OBJ_GET_SLOT(cx, obj, slot);
             PUSH_OPND(rval);
             if (op == JSOP_CALLGVAR)
                 PUSH_OPND(OBJECT_TO_JSVAL(obj));
           END_CASE(JSOP_GETGVAR)
 
           BEGIN_CASE(JSOP_SETGVAR)
-            slot = GET_VARNO(pc);
+            slot = GET_VARNO(regs.pc);
             JS_ASSERT(slot < fp->nvars);
             METER_SLOT_OP(op, slot);
             rval = FETCH_OPND(-1);
             lval = fp->vars[slot];
             obj = fp->varobj;
             if (JSVAL_IS_NULL(lval)) {
                 /*
                  * Inline-clone and deoptimize JSOP_SETNAME code here because
                  * JSOP_SETGVAR has arity 1: [rval], not arity 2: [obj, rval]
                  * as JSOP_SETNAME does, where [obj] is due to JSOP_BINDNAME.
                  */
                 LOAD_ATOM(0);
                 id = ATOM_TO_JSID(atom);
-                SAVE_SP_AND_PC(fp);
                 if (!OBJ_SET_PROPERTY(cx, obj, id, &rval))
                     goto error;
                 STORE_OPND(-1, rval);
             } else {
                 slot = JSVAL_TO_INT(lval);
                 JS_LOCK_OBJ(cx, obj);
                 LOCKED_OBJ_WRITE_BARRIER(cx, obj, slot, rval);
                 JS_UNLOCK_OBJ(cx, obj);
             }
           END_CASE(JSOP_SETGVAR)
 
           BEGIN_CASE(JSOP_DEFCONST)
           BEGIN_CASE(JSOP_DEFVAR)
-            index = GET_INDEX(pc);
+            index = GET_INDEX(regs.pc);
             atom = atoms[index];
 
             /*
              * index is relative to atoms at this point but for global var
              * code below we need the absolute value.
              */
             index += atoms - script->atomMap.vector;
             obj = fp->varobj;
             attrs = JSPROP_ENUMERATE;
             if (!(fp->flags & JSFRAME_EVAL))
                 attrs |= JSPROP_PERMANENT;
             if (op == JSOP_DEFCONST)
                 attrs |= JSPROP_READONLY;
 
             /* Lookup id in order to check for redeclaration problems. */
             id = ATOM_TO_JSID(atom);
-            SAVE_SP_AND_PC(fp);
             if (!js_CheckRedeclaration(cx, obj, id, attrs, &obj2, &prop))
                 goto error;
 
             /* Bind a variable only if it's not yet defined. */
             if (!prop) {
                 if (!OBJ_DEFINE_PROPERTY(cx, obj, id, JSVAL_VOID,
                                          JS_PropertyStub, JS_PropertyStub,
                                          attrs, &prop)) {
@@ -5659,23 +5546,21 @@ interrupt:
             JS_ASSERT(fp->scopeChain == fp->varobj);
             obj2 = fp->scopeChain;
 
             /*
              * ECMA requires functions defined when entering Global code to be
              * permanent.
              */
             attrs = JSPROP_ENUMERATE | JSPROP_PERMANENT;
-            SAVE_SP_AND_PC(fp);
 
           do_deffun:
-            /* The common code for JSOP_DEFFUN and JSOP_CLOSURE. */
-            ASSERT_SAVED_SP_AND_PC(fp);
-
             /*
+             * The common code for JSOP_DEFFUN and JSOP_CLOSURE.
+             *
              * Clone the function object with the current scope chain as the
              * clone's parent.  The original function object is the prototype
              * of the clone.  Do this only if re-parenting; the compiler may
              * have seen the right parent already and created a sufficiently
              * well-scoped function object.
              */
             if (OBJ_GET_PARENT(cx, obj) != obj2) {
                 obj = js_CloneFunctionObject(cx, obj, obj2);
@@ -5750,36 +5635,34 @@ interrupt:
 
             /*
              * Define a local function (i.e., one nested at the top level of
              * another function), parented by the current scope chain, and
              * stored in a local variable slot that the compiler allocated.
              * This is an optimization over JSOP_DEFFUN that avoids requiring
              * a call object for the outer function's activation.
              */
-            slot = GET_VARNO(pc);
+            slot = GET_VARNO(regs.pc);
 
             parent = js_GetScopeChain(cx, fp);
             if (!parent)
                 goto error;
 
-            SAVE_SP_AND_PC(fp);
             obj = js_CloneFunctionObject(cx, obj, parent);
             if (!obj)
                 goto error;
 
             fp->vars[slot] = OBJECT_TO_JSVAL(obj);
           END_CASE(JSOP_DEFLOCALFUN)
 
           BEGIN_CASE(JSOP_ANONFUNOBJ)
             /* Load the specified function object literal. */
             LOAD_FUNCTION(0);
 
             /* If re-parenting, push a clone of the function object. */
-            SAVE_SP_AND_PC(fp);
             parent = js_GetScopeChain(cx, fp);
             if (!parent)
                 goto error;
             if (OBJ_GET_PARENT(cx, obj) != parent) {
                 obj = js_CloneFunctionObject(cx, obj, parent);
                 if (!obj)
                     goto error;
             }
@@ -5794,17 +5677,16 @@ interrupt:
             /*
              * 1. Create a new object as if by the expression new Object().
              * 2. Add Result(1) to the front of the scope chain.
              *
              * Step 2 is achieved by making the new object's parent be the
              * current scope chain, and then making the new object the parent
              * of the Function object clone.
              */
-            SAVE_SP_AND_PC(fp);
             obj2 = js_GetScopeChain(cx, fp);
             if (!obj2)
                 goto error;
             parent = js_NewObject(cx, &js_ObjectClass, NULL, obj2);
             if (!parent)
                 goto error;
 
             /*
@@ -5881,17 +5763,16 @@ interrupt:
             LOAD_FUNCTION(0);
 
             /*
              * Clone the function object with the current scope chain as the
              * clone's parent. Do this only if re-parenting; the compiler may
              * have seen the right parent already and created a sufficiently
              * well-scoped function object.
              */
-            SAVE_SP_AND_PC(fp);
             obj2 = js_GetScopeChain(cx, fp);
             if (!obj2)
                 goto error;
 
             /*
              * ECMA requires that functions defined when entering Eval code to
              * be impermanent.
              */
@@ -5900,21 +5781,21 @@ interrupt:
                 attrs |= JSPROP_PERMANENT;
 
             goto do_deffun;
 
 #if JS_HAS_GETTER_SETTER
           BEGIN_CASE(JSOP_GETTER)
           BEGIN_CASE(JSOP_SETTER)
           do_getter_setter:
-            op2 = (JSOp) *++pc;
+            op2 = (JSOp) *++regs.pc;
             switch (op2) {
               case JSOP_INDEXBASE:
-                atoms += GET_INDEXBASE(pc);
-                pc += JSOP_INDEXBASE_LENGTH - 1;
+                atoms += GET_INDEXBASE(regs.pc);
+                regs.pc += JSOP_INDEXBASE_LENGTH - 1;
                 goto do_getter_setter;
               case JSOP_INDEXBASE1:
               case JSOP_INDEXBASE2:
               case JSOP_INDEXBASE3:
                 atoms += (op2 - JSOP_INDEXBASE1 + 1) << 16;
                 goto do_getter_setter;
 
               case JSOP_SETNAME:
@@ -5925,40 +5806,38 @@ interrupt:
                 i = -1;
                 goto gs_pop_lval;
 
               case JSOP_SETELEM:
                 rval = FETCH_OPND(-1);
                 id = 0;
                 i = -2;
               gs_pop_lval:
-                SAVE_SP_AND_PC(fp);
                 FETCH_OBJECT(cx, i - 1, lval, obj);
                 break;
 
               case JSOP_INITPROP:
-                JS_ASSERT(sp - fp->spbase >= 2);
+                JS_ASSERT(regs.sp - fp->spbase >= 2);
                 rval = FETCH_OPND(-1);
                 i = -1;
                 LOAD_ATOM(0);
                 id = ATOM_TO_JSID(atom);
                 goto gs_get_lval;
 
               default:
                 JS_ASSERT(op2 == JSOP_INITELEM);
 
-                JS_ASSERT(sp - fp->spbase >= 3);
+                JS_ASSERT(regs.sp - fp->spbase >= 3);
                 rval = FETCH_OPND(-1);
                 id = 0;
                 i = -2;
               gs_get_lval:
                 lval = FETCH_OPND(i-1);
                 JS_ASSERT(JSVAL_IS_OBJECT(lval));
                 obj = JSVAL_TO_OBJECT(lval);
-                SAVE_SP_AND_PC(fp);
                 break;
             }
 
             /* Ensure that id has a type suitable for use with obj. */
             if (id == 0)
                 FETCH_ELEMENT_ID(obj, i, id);
 
             if (JS_TypeOfValue(cx, rval) != JSTYPE_FUNCTION) {
@@ -5992,51 +5871,50 @@ interrupt:
             if (!js_CheckRedeclaration(cx, obj, id, attrs, NULL, NULL))
                 goto error;
 
             if (!OBJ_DEFINE_PROPERTY(cx, obj, id, JSVAL_VOID, getter, setter,
                                      attrs, NULL)) {
                 goto error;
             }
 
-            sp += i;
+            regs.sp += i;
             if (js_CodeSpec[op2].ndefs)
                 STORE_OPND(-1, rval);
             len = js_CodeSpec[op2].length;
             DO_NEXT_OP(len);
 #endif /* JS_HAS_GETTER_SETTER */
 
           BEGIN_CASE(JSOP_NEWINIT)
-            i = GET_INT8(pc);
+            i = GET_INT8(regs.pc);
             JS_ASSERT(i == JSProto_Array || i == JSProto_Object);
-            SAVE_SP_AND_PC(fp);
             obj = (i == JSProto_Array)
                   ? js_NewArrayObject(cx, 0, NULL)
                   : js_NewObject(cx, &js_ObjectClass, NULL, NULL);
             if (!obj)
                 goto error;
             PUSH_OPND(OBJECT_TO_JSVAL(obj));
             fp->sharpDepth++;
             LOAD_INTERRUPT_HANDLER(cx);
           END_CASE(JSOP_NEWINIT)
 
           BEGIN_CASE(JSOP_ENDINIT)
             if (--fp->sharpDepth == 0)
                 fp->sharpArray = NULL;
 
             /* Re-set the newborn root to the top of this object tree. */
-            JS_ASSERT(sp - fp->spbase >= 1);
+            JS_ASSERT(regs.sp - fp->spbase >= 1);
             lval = FETCH_OPND(-1);
             JS_ASSERT(JSVAL_IS_OBJECT(lval));
             cx->weakRoots.newborn[GCX_OBJECT] = JSVAL_TO_GCTHING(lval);
           END_CASE(JSOP_ENDINIT)
 
           BEGIN_CASE(JSOP_INITPROP)
             /* Load the property's initial value into rval. */
-            JS_ASSERT(sp - fp->spbase >= 2);
+            JS_ASSERT(regs.sp - fp->spbase >= 2);
             rval = FETCH_OPND(-1);
 
             /* Load the object being initialized into lval/obj. */
             lval = FETCH_OPND(-2);
             obj = JSVAL_TO_OBJECT(lval);
             JS_ASSERT(OBJ_IS_NATIVE(obj));
             JS_ASSERT(!OBJ_GET_CLASS(cx, obj)->reserveSlots);
             JS_ASSERT(!(LOCKED_OBJ_GET_CLASS(obj)->flags &
@@ -6048,21 +5926,21 @@ interrupt:
                 JSPropertyCache *cache;
                 JSPropCacheEntry *entry;
 
                 JS_LOCK_OBJ(cx, obj);
                 scope = OBJ_SCOPE(obj);
                 JS_ASSERT(!SCOPE_IS_SEALED(scope));
                 kshape = scope->shape;
                 cache = &JS_PROPERTY_CACHE(cx);
-                entry = &cache->table[PROPERTY_CACHE_HASH_PC(pc, kshape)];
+                entry = &cache->table[PROPERTY_CACHE_HASH_PC(regs.pc, kshape)];
                 PCMETER(cache->tests++);
                 PCMETER(cache->initests++);
 
-                if (entry->kpc == pc && entry->kshape == kshape) {
+                if (entry->kpc == regs.pc && entry->kshape == kshape) {
                     PCMETER(cache->pchits++);
                     PCMETER(cache->inipchits++);
 
                     JS_ASSERT(PCVAL_IS_SPROP(entry->vword));
                     sprop = PCVAL_TO_SPROP(entry->vword);
                     JS_ASSERT(!(sprop->attrs & JSPROP_READONLY));
 
                     /*
@@ -6142,116 +6020,111 @@ interrupt:
 
               do_initprop_miss:
                 PCMETER(cache->inipcmisses++);
                 JS_UNLOCK_SCOPE(cx, scope);
 
                 /* Get the immediate property name into id. */
                 LOAD_ATOM(0);
                 id = ATOM_TO_JSID(atom);
-                SAVE_SP_AND_PC(fp);
 
                 /* Set the property named by obj[id] to rval. */
                 if (!js_CheckRedeclaration(cx, obj, id, JSPROP_INITIALIZER,
                                            NULL, NULL)) {
                     goto error;
                 }
                 if (!js_SetPropertyHelper(cx, obj, id, &rval, &entry))
                     goto error;
             } while (0);
 
             /* Common tail for property cache hit and miss cases. */
-            sp--;
+            regs.sp--;
           END_CASE(JSOP_INITPROP);
 
           BEGIN_CASE(JSOP_INITELEM)
             /* Pop the element's value into rval. */
-            JS_ASSERT(sp - fp->spbase >= 3);
+            JS_ASSERT(regs.sp - fp->spbase >= 3);
             rval = FETCH_OPND(-1);
-            SAVE_SP_AND_PC(fp);
             FETCH_ELEMENT_ID(obj, -2, id);
 
             /* Find the object being initialized at top of stack. */
             lval = FETCH_OPND(-3);
             JS_ASSERT(!JSVAL_IS_PRIMITIVE(lval));
             obj = JSVAL_TO_OBJECT(lval);
 
             /* Set the property named by obj[id] to rval. */
             if (!js_CheckRedeclaration(cx, obj, id, JSPROP_INITIALIZER, NULL,
                                        NULL)) {
                 goto error;
             }
             if (!OBJ_SET_PROPERTY(cx, obj, id, &rval))
                 goto error;
-            sp -= 2;
+            regs.sp -= 2;
           END_CASE(JSOP_INITELEM);
 
 #if JS_HAS_SHARP_VARS
           BEGIN_CASE(JSOP_DEFSHARP)
-            SAVE_SP_AND_PC(fp);
             obj = fp->sharpArray;
             if (!obj) {
                 obj = js_NewArrayObject(cx, 0, NULL);
                 if (!obj)
                     goto error;
                 fp->sharpArray = obj;
             }
-            i = (jsint) GET_UINT16(pc);
+            i = (jsint) GET_UINT16(regs.pc);
             id = INT_TO_JSID(i);
             rval = FETCH_OPND(-1);
             if (JSVAL_IS_PRIMITIVE(rval)) {
                 char numBuf[12];
                 JS_snprintf(numBuf, sizeof numBuf, "%u", (unsigned) i);
                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                      JSMSG_BAD_SHARP_DEF, numBuf);
                 goto error;
             }
             if (!OBJ_SET_PROPERTY(cx, obj, id, &rval))
                 goto error;
           END_CASE(JSOP_DEFSHARP)
 
           BEGIN_CASE(JSOP_USESHARP)
-            i = (jsint) GET_UINT16(pc);
+            i = (jsint) GET_UINT16(regs.pc);
             id = INT_TO_JSID(i);
             obj = fp->sharpArray;
             if (!obj) {
                 rval = JSVAL_VOID;
             } else {
-                SAVE_SP_AND_PC(fp);
                 if (!OBJ_GET_PROPERTY(cx, obj, id, &rval))
                     goto error;
             }
             if (!JSVAL_IS_OBJECT(rval)) {
                 char numBuf[12];
+
                 JS_snprintf(numBuf, sizeof numBuf, "%u", (unsigned) i);
-
-                SAVE_SP_AND_PC(fp);
                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                      JSMSG_BAD_SHARP_USE, numBuf);
                 goto error;
             }
             PUSH_OPND(rval);
           END_CASE(JSOP_USESHARP)
 #endif /* JS_HAS_SHARP_VARS */
 
           /* No-ops for ease of decompilation and jit'ing. */
           EMPTY_CASE(JSOP_TRY)
           EMPTY_CASE(JSOP_FINALLY)
 
           BEGIN_CASE(JSOP_GOSUB)
             PUSH(JSVAL_FALSE);
-            i = PTRDIFF(pc, script->main, jsbytecode) + JSOP_GOSUB_LENGTH;
-            len = GET_JUMP_OFFSET(pc);
+            i = PTRDIFF(regs.pc, script->main, jsbytecode) + JSOP_GOSUB_LENGTH;
+            len = GET_JUMP_OFFSET(regs.pc);
             PUSH(INT_TO_JSVAL(i));
           END_VARLEN_CASE
 
           BEGIN_CASE(JSOP_GOSUBX)
             PUSH(JSVAL_FALSE);
-            i = PTRDIFF(pc, script->main, jsbytecode) + JSOP_GOSUBX_LENGTH;
-            len = GET_JUMPX_OFFSET(pc);
+            i = PTRDIFF(regs.pc, script->main, jsbytecode) + JSOP_GOSUBX_LENGTH;
+            len = GET_JUMPX_OFFSET(regs.pc);
             PUSH(INT_TO_JSVAL(i));
           END_VARLEN_CASE
 
           BEGIN_CASE(JSOP_RETSUB)
             rval = POP();
             lval = POP();
             JS_ASSERT(JSVAL_IS_BOOLEAN(lval));
             if (JSVAL_TO_BOOLEAN(lval)) {
@@ -6262,17 +6135,17 @@ interrupt:
                  * it points out a FIXME: 350509, due to Igor Bukanov.
                  */
                 cx->throwing = JS_TRUE;
                 cx->exception = rval;
                 goto error;
             }
             JS_ASSERT(JSVAL_IS_INT(rval));
             len = JSVAL_TO_INT(rval);
-            pc = script->main;
+            regs.pc = script->main;
           END_VARLEN_CASE
 
           BEGIN_CASE(JSOP_EXCEPTION)
             JS_ASSERT(cx->throwing);
             PUSH(cx->exception);
             cx->throwing = JS_FALSE;
           END_CASE(JSOP_EXCEPTION)
 
@@ -6289,46 +6162,44 @@ interrupt:
             /* let the code at error try to catch the exception. */
             goto error;
 
           BEGIN_CASE(JSOP_SETLOCALPOP)
             /*
              * The stack must have a block with at least one local slot below
              * the exception object.
              */
-            JS_ASSERT(sp - fp->spbase >= 2);
-            slot = GET_UINT16(pc);
+            JS_ASSERT(regs.sp - fp->spbase >= 2);
+            slot = GET_UINT16(regs.pc);
             JS_ASSERT(slot + 1 < script->depth);
             fp->spbase[slot] = POP_OPND();
           END_CASE(JSOP_SETLOCALPOP)
 
           BEGIN_CASE(JSOP_INSTANCEOF)
-            SAVE_SP_AND_PC(fp);
             rval = FETCH_OPND(-1);
             if (JSVAL_IS_PRIMITIVE(rval) ||
                 !(obj = JSVAL_TO_OBJECT(rval))->map->ops->hasInstance) {
                 js_ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS,
                                     -1, rval, NULL);
                 goto error;
             }
             lval = FETCH_OPND(-2);
             cond = JS_FALSE;
             if (!obj->map->ops->hasInstance(cx, obj, lval, &cond))
                 goto error;
-            sp--;
+            regs.sp--;
             STORE_OPND(-1, BOOLEAN_TO_JSVAL(cond));
           END_CASE(JSOP_INSTANCEOF)
 
 #if JS_HAS_DEBUGGER_KEYWORD
           BEGIN_CASE(JSOP_DEBUGGER)
           {
             JSTrapHandler handler = cx->debugHooks->debuggerHandler;
             if (handler) {
-                SAVE_SP_AND_PC(fp);
-                switch (handler(cx, script, pc, &rval,
+                switch (handler(cx, script, regs.pc, &rval,
                                 cx->debugHooks->debuggerHandlerData)) {
                   case JSTRAP_ERROR:
                     goto error;
                   case JSTRAP_CONTINUE:
                     break;
                   case JSTRAP_RETURN:
                     fp->rval = rval;
                     ok = JS_TRUE;
@@ -6343,224 +6214,207 @@ interrupt:
             }
           }
           END_CASE(JSOP_DEBUGGER)
 #endif /* JS_HAS_DEBUGGER_KEYWORD */
 
 #if JS_HAS_XML_SUPPORT
           BEGIN_CASE(JSOP_DEFXMLNS)
             rval = POP();
-            SAVE_SP_AND_PC(fp);
             if (!js_SetDefaultXMLNamespace(cx, rval))
                 goto error;
           END_CASE(JSOP_DEFXMLNS)
 
           BEGIN_CASE(JSOP_ANYNAME)
-            SAVE_SP_AND_PC(fp);
             if (!js_GetAnyName(cx, &rval))
                 goto error;
             PUSH_OPND(rval);
           END_CASE(JSOP_ANYNAME)
 
           BEGIN_CASE(JSOP_QNAMEPART)
             LOAD_ATOM(0);
             PUSH_OPND(ATOM_KEY(atom));
           END_CASE(JSOP_QNAMEPART)
 
           BEGIN_CASE(JSOP_QNAMECONST)
             LOAD_ATOM(0);
             rval = ATOM_KEY(atom);
             lval = FETCH_OPND(-1);
-            SAVE_SP_AND_PC(fp);
             obj = js_ConstructXMLQNameObject(cx, lval, rval);
             if (!obj)
                 goto error;
             STORE_OPND(-1, OBJECT_TO_JSVAL(obj));
           END_CASE(JSOP_QNAMECONST)
 
           BEGIN_CASE(JSOP_QNAME)
             rval = FETCH_OPND(-1);
             lval = FETCH_OPND(-2);
-            SAVE_SP_AND_PC(fp);
             obj = js_ConstructXMLQNameObject(cx, lval, rval);
             if (!obj)
                 goto error;
-            sp--;
+            regs.sp--;
             STORE_OPND(-1, OBJECT_TO_JSVAL(obj));
           END_CASE(JSOP_QNAME)
 
           BEGIN_CASE(JSOP_TOATTRNAME)
             rval = FETCH_OPND(-1);
-            SAVE_SP_AND_PC(fp);
             if (!js_ToAttributeName(cx, &rval))
                 goto error;
             STORE_OPND(-1, rval);
           END_CASE(JSOP_TOATTRNAME)
 
           BEGIN_CASE(JSOP_TOATTRVAL)
             rval = FETCH_OPND(-1);
             JS_ASSERT(JSVAL_IS_STRING(rval));
-            SAVE_SP_AND_PC(fp);
             str = js_EscapeAttributeValue(cx, JSVAL_TO_STRING(rval), JS_FALSE);
             if (!str)
                 goto error;
             STORE_OPND(-1, STRING_TO_JSVAL(str));
           END_CASE(JSOP_TOATTRVAL)
 
           BEGIN_CASE(JSOP_ADDATTRNAME)
           BEGIN_CASE(JSOP_ADDATTRVAL)
             rval = FETCH_OPND(-1);
             lval = FETCH_OPND(-2);
             str = JSVAL_TO_STRING(lval);
             str2 = JSVAL_TO_STRING(rval);
-            SAVE_SP_AND_PC(fp);
             str = js_AddAttributePart(cx, op == JSOP_ADDATTRNAME, str, str2);
             if (!str)
                 goto error;
-            sp--;
+            regs.sp--;
             STORE_OPND(-1, STRING_TO_JSVAL(str));
           END_CASE(JSOP_ADDATTRNAME)
 
           BEGIN_CASE(JSOP_BINDXMLNAME)
             lval = FETCH_OPND(-1);
-            SAVE_SP_AND_PC(fp);
             if (!js_FindXMLProperty(cx, lval, &obj, &id))
                 goto error;
             STORE_OPND(-1, OBJECT_TO_JSVAL(obj));
             PUSH_OPND(ID_TO_VALUE(id));
           END_CASE(JSOP_BINDXMLNAME)
 
           BEGIN_CASE(JSOP_SETXMLNAME)
             obj = JSVAL_TO_OBJECT(FETCH_OPND(-3));
             rval = FETCH_OPND(-1);
-            SAVE_SP_AND_PC(fp);
             FETCH_ELEMENT_ID(obj, -2, id);
             if (!OBJ_SET_PROPERTY(cx, obj, id, &rval))
                 goto error;
-            sp -= 2;
+            regs.sp -= 2;
             STORE_OPND(-1, rval);
           END_CASE(JSOP_SETXMLNAME)
 
           BEGIN_CASE(JSOP_CALLXMLNAME)
           BEGIN_CASE(JSOP_XMLNAME)
             lval = FETCH_OPND(-1);
-            SAVE_SP_AND_PC(fp);
             if (!js_FindXMLProperty(cx, lval, &obj, &id))
                 goto error;
             if (!OBJ_GET_PROPERTY(cx, obj, id, &rval))
                 goto error;
             STORE_OPND(-1, rval);
             if (op == JSOP_CALLXMLNAME)
                 PUSH_OPND(OBJECT_TO_JSVAL(obj));
           END_CASE(JSOP_XMLNAME)
 
           BEGIN_CASE(JSOP_DESCENDANTS)
           BEGIN_CASE(JSOP_DELDESC)
-            SAVE_SP_AND_PC(fp);
             FETCH_OBJECT(cx, -2, lval, obj);
             rval = FETCH_OPND(-1);
             if (!js_GetXMLDescendants(cx, obj, rval, &rval))
                 goto error;
 
             if (op == JSOP_DELDESC) {
-                sp[-1] = rval;          /* set local root */
+                regs.sp[-1] = rval;          /* set local root */
                 if (!js_DeleteXMLListElements(cx, JSVAL_TO_OBJECT(rval)))
                     goto error;
                 rval = JSVAL_TRUE;      /* always succeed */
             }
 
-            sp--;
+            regs.sp--;
             STORE_OPND(-1, rval);
           END_CASE(JSOP_DESCENDANTS)
 
           BEGIN_CASE(JSOP_FILTER)
             /*
              * We push the hole value before jumping to [enditer] so we can
              * detect the first iteration and direct js_StepXMLListFilter to
              * initialize filter's state.
              */
             PUSH_OPND(JSVAL_HOLE);
-            len = GET_JUMP_OFFSET(pc);
+            len = GET_JUMP_OFFSET(regs.pc);
             JS_ASSERT(len > 0);
           END_VARLEN_CASE
 
           BEGIN_CASE(JSOP_ENDFILTER)
-            SAVE_SP_AND_PC(fp);
-            cond = (sp[-1] != JSVAL_HOLE);
+            cond = (regs.sp[-1] != JSVAL_HOLE);
             if (cond) {
                 /* Exit the "with" block left from the previous iteration. */
                 js_LeaveWith(cx);
             }
             if (!js_StepXMLListFilter(cx, cond))
                 goto error;
-            if (sp[-1] != JSVAL_NULL) {
+            if (regs.sp[-1] != JSVAL_NULL) {
                 /*
                  * Decrease sp after EnterWith returns as we use sp[-1] there
                  * to root temporaries.
                  */
-                JS_ASSERT(VALUE_IS_XML(cx, sp[-1]));
+                JS_ASSERT(VALUE_IS_XML(cx, regs.sp[-1]));
                 if (!js_EnterWith(cx, -2))
                     goto error;
-                sp--;
-                len = GET_JUMP_OFFSET(pc);
+                regs.sp--;
+                len = GET_JUMP_OFFSET(regs.pc);
                 JS_ASSERT(len < 0);
                 CHECK_BRANCH(len);
                 DO_NEXT_OP(len);
             }
-            sp--;
+            regs.sp--;
           END_CASE(JSOP_ENDFILTER);
 
           EMPTY_CASE(JSOP_STARTXML)
           EMPTY_CASE(JSOP_STARTXMLEXPR)
 
           BEGIN_CASE(JSOP_TOXML)
             rval = FETCH_OPND(-1);
-            SAVE_SP_AND_PC(fp);
             obj = js_ValueToXMLObject(cx, rval);
             if (!obj)
                 goto error;
             STORE_OPND(-1, OBJECT_TO_JSVAL(obj));
           END_CASE(JSOP_TOXML)
 
           BEGIN_CASE(JSOP_TOXMLLIST)
             rval = FETCH_OPND(-1);
-            SAVE_SP_AND_PC(fp);
             obj = js_ValueToXMLListObject(cx, rval);
             if (!obj)
                 goto error;
             STORE_OPND(-1, OBJECT_TO_JSVAL(obj));
           END_CASE(JSOP_TOXMLLIST)
 
           BEGIN_CASE(JSOP_XMLTAGEXPR)
             rval = FETCH_OPND(-1);
-            SAVE_SP_AND_PC(fp);
             str = js_ValueToString(cx, rval);
             if (!str)
                 goto error;
             STORE_OPND(-1, STRING_TO_JSVAL(str));
           END_CASE(JSOP_XMLTAGEXPR)
 
           BEGIN_CASE(JSOP_XMLELTEXPR)
             rval = FETCH_OPND(-1);
-            SAVE_SP_AND_PC(fp);
             if (VALUE_IS_XML(cx, rval)) {
                 str = js_ValueToXMLString(cx, rval);
             } else {
                 str = js_ValueToString(cx, rval);
                 if (str)
                     str = js_EscapeElementValue(cx, str);
             }
             if (!str)
                 goto error;
             STORE_OPND(-1, STRING_TO_JSVAL(str));
           END_CASE(JSOP_XMLELTEXPR)
 
           BEGIN_CASE(JSOP_XMLOBJECT)
             LOAD_OBJECT(0);
-            SAVE_SP_AND_PC(fp);
             obj = js_CloneXMLObject(cx, obj);
             if (!obj)
                 goto error;
             PUSH_OPND(OBJECT_TO_JSVAL(obj));
           END_CASE(JSOP_XMLOBJECT)
 
           BEGIN_CASE(JSOP_XMLCDATA)
             LOAD_ATOM(0);
@@ -6580,41 +6434,39 @@ interrupt:
             PUSH_OPND(OBJECT_TO_JSVAL(obj));
           END_CASE(JSOP_XMLCOMMENT)
 
           BEGIN_CASE(JSOP_XMLPI)
             LOAD_ATOM(0);
             str = ATOM_TO_STRING(atom);
             rval = FETCH_OPND(-1);
             str2 = JSVAL_TO_STRING(rval);
-            SAVE_SP_AND_PC(fp);
             obj = js_NewXMLSpecialObject(cx,
                                          JSXML_CLASS_PROCESSING_INSTRUCTION,
                                          str, str2);
             if (!obj)
                 goto error;
             STORE_OPND(-1, OBJECT_TO_JSVAL(obj));
           END_CASE(JSOP_XMLPI)
 
           BEGIN_CASE(JSOP_GETFUNNS)
-            SAVE_SP_AND_PC(fp);
             if (!js_GetFunctionNamespace(cx, &rval))
                 goto error;
             PUSH_OPND(rval);
           END_CASE(JSOP_GETFUNNS)
 #endif /* JS_HAS_XML_SUPPORT */
 
           BEGIN_CASE(JSOP_ENTERBLOCK)
             LOAD_OBJECT(0);
-            JS_ASSERT(fp->spbase + OBJ_BLOCK_DEPTH(cx, obj) == sp);
-            vp = sp + OBJ_BLOCK_COUNT(cx, obj);
+            JS_ASSERT(fp->spbase + OBJ_BLOCK_DEPTH(cx, obj) == regs.sp);
+            vp = regs.sp + OBJ_BLOCK_COUNT(cx, obj);
             JS_ASSERT(vp <= fp->spbase + script->depth);
-            while (sp < vp) {
+            while (regs.sp < vp) {
                 STORE_OPND(0, JSVAL_VOID);
-                sp++;
+                regs.sp++;
             }
 
             /*
              * If this frame had to reflect the compile-time block chain into
              * the runtime scope chain, we can't optimize block scopes out of
              * runtime any longer, because an outer block that parents obj has
              * been cloned onto the scope chain.  To avoid re-cloning such a
              * parent and accumulating redundant clones via js_GetScopeChain,
@@ -6648,100 +6500,93 @@ interrupt:
             if (fp->blockChain) {
                 JS_ASSERT(OBJ_GET_CLASS(cx, fp->blockChain) == &js_BlockClass);
                 fp->blockChain = OBJ_GET_PARENT(cx, fp->blockChain);
             } else {
                 /*
                  * This block was cloned into fp->scopeChain, so clear its
                  * private data and sync its locals to their property slots.
                  */
-                SAVE_SP_AND_PC(fp);
                 if (!js_PutBlockObject(cx, JS_TRUE))
                     goto error;
             }
 
             /*
              * We will move the result of the expression to the new topmost
              * stack slot.
              */
             if (op == JSOP_LEAVEBLOCKEXPR)
                 rval = FETCH_OPND(-1);
-            sp -= GET_UINT16(pc);
+            regs.sp -= GET_UINT16(regs.pc);
             if (op == JSOP_LEAVEBLOCKEXPR) {
-                JS_ASSERT(blocksp == sp - 1);
+                JS_ASSERT(blocksp == regs.sp - 1);
                 STORE_OPND(-1, rval);
             } else {
-                JS_ASSERT(blocksp == sp);
+                JS_ASSERT(blocksp == regs.sp);
             }
           }
           END_CASE(JSOP_LEAVEBLOCK)
 
           BEGIN_CASE(JSOP_GETLOCAL)
           BEGIN_CASE(JSOP_CALLLOCAL)
-            slot = GET_UINT16(pc);
+            slot = GET_UINT16(regs.pc);
             JS_ASSERT(slot < script->depth);
             PUSH_OPND(fp->spbase[slot]);
             if (op == JSOP_CALLLOCAL)
                 PUSH_OPND(JSVAL_NULL);
           END_CASE(JSOP_GETLOCAL)
 
           BEGIN_CASE(JSOP_SETLOCAL)
-            slot = GET_UINT16(pc);
+            slot = GET_UINT16(regs.pc);
             JS_ASSERT(slot < script->depth);
             vp = &fp->spbase[slot];
             GC_POKE(cx, *vp);
             *vp = FETCH_OPND(-1);
           END_CASE(JSOP_SETLOCAL)
 
           BEGIN_CASE(JSOP_ENDITER)
             /*
              * Decrease the stack pointer even when !ok, see comments in the
              * exception capturing code for details.
              */
-            SAVE_SP_AND_PC(fp);
-            ok = js_CloseIterator(cx, sp[-1]);
-            sp--;
+            ok = js_CloseIterator(cx, regs.sp[-1]);
+            regs.sp--;
             if (!ok)
                 goto error;
           END_CASE(JSOP_ENDITER)
 
 #if JS_HAS_GENERATORS
           BEGIN_CASE(JSOP_GENERATOR)
             ASSERT_NOT_THROWING(cx);
-            pc += JSOP_GENERATOR_LENGTH;
-            SAVE_SP_AND_PC(fp);
+            regs.pc += JSOP_GENERATOR_LENGTH;
             obj = js_NewGenerator(cx, fp);
             if (!obj)
                 goto error;
             JS_ASSERT(!fp->callobj && !fp->argsobj);
             fp->rval = OBJECT_TO_JSVAL(obj);
             ok = JS_TRUE;
             if (inlineCallCount != 0)
                 goto inline_return;
             goto exit;
 
           BEGIN_CASE(JSOP_YIELD)
             ASSERT_NOT_THROWING(cx);
             if (FRAME_TO_GENERATOR(fp)->state == JSGEN_CLOSING) {
-                SAVE_SP_AND_PC(fp);
                 js_ReportValueError(cx, JSMSG_BAD_GENERATOR_YIELD,
                                     JSDVG_SEARCH_STACK, fp->argv[-2], NULL);
                 goto error;
             }
             fp->rval = FETCH_OPND(-1);
             fp->flags |= JSFRAME_YIELDING;
-            pc += JSOP_YIELD_LENGTH;
-            SAVE_SP_AND_PC(fp);
-            JS_PROPERTY_CACHE(cx).disabled -= js_CountWithBlocks(cx, fp);
-            JS_ASSERT(JS_PROPERTY_CACHE(cx).disabled >= 0);
+            regs.pc += JSOP_YIELD_LENGTH;
             ok = JS_TRUE;
             goto exit;
 
           BEGIN_CASE(JSOP_ARRAYPUSH)
-            slot = GET_UINT16(pc);
+            slot = GET_UINT16(regs.pc);
             JS_ASSERT(slot < script->depth);
             lval = fp->spbase[slot];
             obj  = JSVAL_TO_OBJECT(lval);
             JS_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_ArrayClass);
             rval = FETCH_OPND(-1);
 
             /*
              * We know that the array is created with only a 'length' private
@@ -6753,17 +6598,17 @@ interrupt:
             if (i == ARRAY_INIT_LIMIT) {
                 JS_ReportErrorNumberUC(cx, js_GetErrorMessage, NULL,
                                        JSMSG_ARRAY_INIT_TOO_BIG);
                 goto error;
             }
             id = INT_TO_JSID(i);
             if (!OBJ_SET_PROPERTY(cx, obj, id, &rval))
                 goto error;
-            sp--;
+            regs.sp--;
           END_CASE(JSOP_ARRAYPUSH)
 #endif /* JS_HAS_GENERATORS */
 
 #if JS_THREADED_INTERP
           L_JSOP_BACKPATCH:
           L_JSOP_BACKPATCH_POP:
 
 # if !JS_HAS_GENERATORS
@@ -6821,75 +6666,73 @@ interrupt:
             goto error;
           }
 
 #if !JS_THREADED_INTERP
 
         } /* switch (op) */
 
     advance_pc:
-        pc += len;
+        regs.pc += len;
 
 #ifdef DEBUG
         if (tracefp) {
             intN ndefs, n;
             jsval *siter;
 
             /*
              * op may be invalid here when a catch or finally handler jumps to
              * advance_pc.
              */
-            op = (JSOp) pc[-len];
+            op = (JSOp) regs.pc[-len];
             ndefs = js_CodeSpec[op].ndefs;
             if (ndefs) {
-                SAVE_SP_AND_PC(fp);
-                if (op == JSOP_FORELEM && sp[-1] == JSVAL_FALSE)
+                if (op == JSOP_FORELEM && regs.sp[-1] == JSVAL_FALSE)
                     --ndefs;
                 for (n = -ndefs; n < 0; n++) {
-                    char *bytes = js_DecompileValueGenerator(cx, n, sp[n],
+                    char *bytes = js_DecompileValueGenerator(cx, n, regs.sp[n],
                                                              NULL);
                     if (bytes) {
                         fprintf(tracefp, "%s %s",
                                 (n == -ndefs) ? "  output:" : ",",
                                 bytes);
                         JS_free(cx, bytes);
                     }
                 }
-                fprintf(tracefp, " @ %d\n", sp - fp->spbase);
+                fprintf(tracefp, " @ %d\n", regs.sp - fp->spbase);
             }
             fprintf(tracefp, "  stack: ");
-            for (siter = fp->spbase; siter < sp; siter++) {
+            for (siter = fp->spbase; siter < regs.sp; siter++) {
                 str = js_ValueToString(cx, *siter);
                 if (!str)
                     fputs("<null>", tracefp);
                 else
                     js_FileEscapedString(tracefp, str, 0);
                 fputc(' ', tracefp);
             }
             fputc('\n', tracefp);
         }
 #endif /* DEBUG */
     }
 #endif /* !JS_THREADED_INTERP */
 
   error:
-    JS_ASSERT((size_t)(pc - script->code) < script->length);
+    JS_ASSERT((size_t)(regs.pc - script->code) < script->length);
     if (!cx->throwing) {
         /* This is an error, not a catchable exception, quit the frame ASAP. */
         ok = JS_FALSE;
     } else {
         JSTrapHandler handler;
         JSTryNote *tn, *tnlimit;
         uint32 offset;
 
         /* Call debugger throw hook if set. */
         handler = cx->debugHooks->throwHook;
         if (handler) {
-            SAVE_SP_AND_PC(fp);
-            switch (handler(cx, script, pc, &rval,
+            switch (handler(cx, script, regs.pc, &rval,
                             cx->debugHooks->throwHookData)) {
               case JSTRAP_ERROR:
                 cx->throwing = JS_FALSE;
                 goto error;
               case JSTRAP_RETURN:
                 cx->throwing = JS_FALSE;
                 fp->rval = rval;
                 ok = JS_TRUE;
@@ -6903,17 +6746,17 @@ interrupt:
         }
 
         /*
          * Look for a try block in script that can catch this exception.
          */
         if (script->trynotesOffset == 0)
             goto no_catch;
 
-        offset = (uint32)(pc - script->main);
+        offset = (uint32)(regs.pc - script->main);
         tn = JS_SCRIPT_TRYNOTES(script)->vector;
         tnlimit = tn + JS_SCRIPT_TRYNOTES(script)->length;
         do {
             if (offset - tn->start >= tn->length)
                 continue;
 
             /*
              * We have a note that covers the exception pc but we must check
@@ -6929,41 +6772,39 @@ interrupt:
              * corresponding iterators and invoked the finally blocks.
              *
              * To address this, we make [enditer] always decrease the stack
              * even when its implementation throws an exception. Thus already
              * executed [enditer] and [gosub] opcodes will have try notes
              * with the stack depth exceeding the current one and this
              * condition is what we use to filter them out.
              */
-            if (tn->stackDepth > sp - fp->spbase)
+            if (tn->stackDepth > regs.sp - fp->spbase)
                 continue;
 
             /*
              * Set pc to the first bytecode after the the try note to point
              * to the beginning of catch or finally or to [enditer] closing
              * the for-in loop.
              */
-            pc = (script)->main + tn->start + tn->length;
-
-            SAVE_SP_AND_PC(fp);
+            regs.pc = (script)->main + tn->start + tn->length;
+
             ok = js_UnwindScope(cx, fp, tn->stackDepth, JS_TRUE);
-            JS_ASSERT(fp->sp == fp->spbase + tn->stackDepth);
-            RESTORE_SP(fp);
+            JS_ASSERT(fp->regs->sp == fp->spbase + tn->stackDepth);
             if (!ok) {
                 /*
                  * Restart the handler search with updated pc and stack depth
                  * to properly notify the debugger.
                  */
                 goto error;
             }
 
             switch (tn->kind) {
               case JSTN_CATCH:
-                JS_ASSERT(*pc == JSOP_ENTERBLOCK);
+                JS_ASSERT(*regs.pc == JSOP_ENTERBLOCK);
 
 #if JS_HAS_GENERATORS
                 /* Catch cannot intercept the closing of a generator. */
                 if (JS_UNLIKELY(cx->exception == JSVAL_ARETURN))
                     break;
 #endif
 
                 /*
@@ -6986,26 +6827,25 @@ interrupt:
                 DO_NEXT_OP(len);
 
               case JSTN_ITER:
                 /*
                  * This is similar to JSOP_ENDITER in the interpreter loop
                  * except the code now uses a reserved stack slot to save and
                  * restore the exception.
                  */
-                JS_ASSERT(*pc == JSOP_ENDITER);
+                JS_ASSERT(*regs.pc == JSOP_ENDITER);
                 PUSH(cx->exception);
                 cx->throwing = JS_FALSE;
-                SAVE_SP_AND_PC(fp);
-                ok = js_CloseIterator(cx, sp[-2]);
-                sp -= 2;
+                ok = js_CloseIterator(cx, regs.sp[-2]);
+                regs.sp -= 2;
                 if (!ok)
                     goto error;
                 cx->throwing = JS_TRUE;
-                cx->exception = sp[1];
+                cx->exception = regs.sp[1];
             }
         } while (++tn != tnlimit);
 
       no_catch:
         /*
          * Propagate the exception or error to the caller unless the exception
          * is an asynchronous return from a generator.
          */
@@ -7022,20 +6862,18 @@ interrupt:
   forced_return:
     /*
      * Unwind the scope making sure that ok stays false even when UnwindScope
      * returns true.
      *
      * When a trap handler returns JSTRAP_RETURN, we jump here with ok set to
      * true bypassing any finally blocks.
      */
-    SAVE_SP_AND_PC(fp);
     ok &= js_UnwindScope(cx, fp, 0, ok || cx->throwing);
-    JS_ASSERT(fp->sp == fp->spbase);
-    RESTORE_SP(fp);
+    JS_ASSERT(regs.sp == fp->spbase);
 
     if (inlineCallCount)
         goto inline_return;
 
   exit:
     /*
      * At this point we are inevitably leaving an interpreted function or a
      * top-level script, and returning to one of:
@@ -7043,38 +6881,53 @@ interrupt:
      * (b) a js_Execute activation;
      * (c) a generator (SendToGenerator, jsiter.c).
      *
      * We must not be in an inline frame. The check above ensures that for the
      * error case and for a normal return, the code jumps directly to parent's
      * frame pc.
      */
     JS_ASSERT(inlineCallCount == 0);
-    JS_ASSERT(JS_PROPERTY_CACHE(cx).disabled == fp->pcDisabledSave);
-
+
+    JS_ASSERT(fp->spbase);
+    JS_ASSERT(fp->regs == &regs);
     if (JS_LIKELY(mark != NULL)) {
         JS_ASSERT(!fp->blockChain);
         JS_ASSERT(!js_IsActiveWithOrBlock(cx, fp->scopeChain, 0));
         JS_ASSERT(!(fp->flags & JSFRAME_GENERATOR));
-        JS_ASSERT(fp->spbase);
-        JS_ASSERT(fp->spbase <= fp->sp);
-        fp->sp = fp->spbase = NULL;
+        fp->spbase = NULL;
+        fp->regs = NULL;
         js_FreeRawStack(cx, mark);
+    } else {
+        JS_ASSERT(fp->flags & JSFRAME_GENERATOR);
+        if (fp->flags & JSFRAME_YIELDING) {
+            JSGenerator *gen;
+
+            gen = FRAME_TO_GENERATOR(fp);
+            gen->savedRegs = regs;
+            gen->frame.regs = &gen->savedRegs;
+            JS_PROPERTY_CACHE(cx).disabled -= js_CountWithBlocks(cx, fp);
+            JS_ASSERT(JS_PROPERTY_CACHE(cx).disabled >= 0);
+        } else {
+            fp->regs = NULL;
+            fp->spbase = NULL;
+        }
     }
 
+  exit2:
+    JS_ASSERT(JS_PROPERTY_CACHE(cx).disabled == fp->pcDisabledSave);
     if (cx->version == currentVersion && currentVersion != originalVersion)
         js_SetVersion(cx, originalVersion);
     cx->interpLevel--;
     return ok;
 
   atom_not_defined:
     {
         const char *printable;
 
-        ASSERT_SAVED_SP_AND_PC(fp);
         printable = js_AtomToPrintableString(cx, atom);
         if (printable)
             js_ReportIsNotDefined(cx, printable);
         goto error;
     }
 }
 
 #endif /* !defined js_invoke_c__ */
--- a/js/src/jsinterp.h
+++ b/js/src/jsinterp.h
@@ -44,29 +44,33 @@
  * JS interpreter interface.
  */
 #include "jsprvtd.h"
 #include "jspubtd.h"
 #include "jsopcode.h"
 
 JS_BEGIN_EXTERN_C
 
+typedef struct JSFrameRegs {
+    jsbytecode      *pc;            /* program counter */
+    jsval           *sp;            /* stack pointer */
+} JSFrameRegs;
+
 /*
  * JS stack frame, may be allocated on the C stack by native callers.  Always
  * allocated on cx->stackPool for calls from the interpreter to an interpreted
  * function.
  *
  * NB: This struct is manually initialized in jsinterp.c and jsiter.c.  If you
  * add new members, update both files.  But first, try to remove members.  The
  * sharp* and xml* members should be moved onto the stack as local variables
  * with well-known slots, if possible.
  */
 struct JSStackFrame {
-    jsval           *sp;            /* stack pointer */
-    jsbytecode      *pc;            /* program counter */
+    JSFrameRegs     *regs;
     jsval           *spbase;        /* operand stack base */
     JSObject        *callobj;       /* lazily created Call object */
     JSObject        *argsobj;       /* lazily created arguments object */
     JSObject        *varobj;        /* variables object, where vars go */
     JSObject        *callee;        /* function or script object */
     JSScript        *script;        /* script being interpreted */
     JSFunction      *fun;           /* function being called or null */
     JSObject        *thisp;         /* "this" pointer if in method */
@@ -86,17 +90,17 @@ struct JSStackFrame {
     JSObject        *blockChain;    /* active compile-time block scopes */
 #ifdef DEBUG
     jsrefcount      pcDisabledSave; /* for balanced property cache control */
 #endif
 };
 
 typedef struct JSInlineFrame {
     JSStackFrame    frame;          /* base struct */
-    jsval           *rvp;           /* ptr to caller's return value slot */
+    JSFrameRegs     callerRegs;     /* parent's frame registers */
     void            *mark;          /* mark before inline frame */
     void            *hookData;      /* debugger call hook data */
     JSVersion       callerVersion;  /* dynamic version of calling script */
 } JSInlineFrame;
 
 /* JS stack frame flags. */
 #define JSFRAME_CONSTRUCTING   0x01 /* frame is for a constructor invocation */
 #define JSFRAME_INTERNAL       0x02 /* internal call, not invoked by a script */
--- a/js/src/jsiter.c
+++ b/js/src/jsiter.c
@@ -786,20 +786,22 @@ js_NewGenerator(JSContext *cx, JSStackFr
     COPY_STACK_ARRAY(vars, nvars, nvars);
 
 #undef COPY_STACK_ARRAY
 
     /* Initialize or copy virtual machine state. */
     gen->frame.down = NULL;
     gen->frame.annotation = NULL;
     gen->frame.scopeChain = fp->scopeChain;
-    gen->frame.pc = fp->pc;
 
-    /* Allocate generating pc and operand stack space. */
-    gen->frame.spbase = gen->frame.sp = newsp;
+    gen->frame.spbase = newsp;
+    JS_ASSERT(fp->spbase == fp->regs->sp);
+    gen->savedRegs.sp = newsp;
+    gen->savedRegs.pc = fp->regs->pc;
+    gen->frame.regs = &gen->savedRegs;
 
     /* Copy remaining state (XXX sharp* and xml* should be local vars). */
     gen->frame.sharpDepth = 0;
     gen->frame.sharpArray = NULL;
     gen->frame.flags = (fp->flags & ~JSFRAME_ROOTED_ARGV) | JSFRAME_GENERATOR;
     gen->frame.dormantNext = NULL;
     gen->frame.xmlNamespace = NULL;
     gen->frame.blockChain = NULL;
@@ -848,17 +850,17 @@ SendToGenerator(JSContext *cx, JSGenerat
     switch (op) {
       case JSGENOP_NEXT:
       case JSGENOP_SEND:
         if (gen->state == JSGEN_OPEN) {
             /*
              * Store the argument to send as the result of the yield
              * expression.
              */
-            gen->frame.sp[-1] = arg;
+            gen->savedRegs.sp[-1] = arg;
         }
         gen->state = JSGEN_RUNNING;
         break;
 
       case JSGENOP_THROW:
         JS_SetPendingException(cx, arg);
         gen->state = JSGEN_RUNNING;
         break;
--- a/js/src/jsiter.h
+++ b/js/src/jsiter.h
@@ -92,16 +92,17 @@ typedef enum JSGeneratorState {
     JSGEN_CLOSING,  /* close method is doing asynchronous return */
     JSGEN_CLOSED    /* closed, cannot be started or closed again */
 } JSGeneratorState;
 
 struct JSGenerator {
     JSObject            *obj;
     JSGeneratorState    state;
     JSStackFrame        frame;
+    JSFrameRegs         savedRegs;
     JSArena             arena;
     jsval               stack[1];
 };
 
 #define FRAME_TO_GENERATOR(fp) \
     ((JSGenerator *) ((uint8 *)(fp) - offsetof(JSGenerator, frame)))
 
 extern JSObject *
--- a/js/src/jsobj.c
+++ b/js/src/jsobj.c
@@ -1141,17 +1141,18 @@ js_ComputeFilename(JSContext *cx, JSStac
 
     flags = JS_GetScriptFilenameFlags(caller->script);
     if ((flags & JSFILENAME_PROTECTED) &&
         strcmp(principals->codebase, "[System Principal]")) {
         *linenop = 0;
         return principals->codebase;
     }
 
-    *linenop = js_PCToLineNumber(cx, caller->script, caller->pc);
+    *linenop = js_PCToLineNumber(cx, caller->script,
+                                 caller->regs ? caller->regs->pc : NULL);
     return caller->script->filename;
 }
 
 static JSBool
 obj_eval(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 {
     JSStackFrame *fp, *caller;
     JSBool indirectCall;
@@ -1165,18 +1166,18 @@ obj_eval(JSContext *cx, JSObject *obj, u
 #if JS_HAS_EVAL_THIS_SCOPE
     JSObject *callerScopeChain = NULL, *callerVarObj = NULL;
     JSObject *setCallerScopeChain = NULL;
     JSBool setCallerVarObj = JS_FALSE;
 #endif
 
     fp = cx->fp;
     caller = JS_GetScriptedCaller(cx, fp);
-    JS_ASSERT(!caller || caller->pc);
-    indirectCall = (caller && *caller->pc != JSOP_EVAL);
+    JS_ASSERT(!caller || caller->regs);
+    indirectCall = (caller && *caller->regs->pc != JSOP_EVAL);
 
     /*
      * Ban all indirect uses of eval (global.foo = eval; global.foo(...)) and
      * calls that attempt to use a non-global object as the "with" object in
      * the former indirect case.
      */
     scopeobj = OBJ_GET_PARENT(cx, obj);
     if (scopeobj) {
@@ -1954,27 +1955,27 @@ js_PutBlockObject(JSContext *cx, JSBool 
 
     fp = cx->fp;
     obj = fp->scopeChain;
     JS_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_BlockClass);
     JS_ASSERT(OBJ_GET_PRIVATE(cx, obj) == cx->fp);
 
     /* Block and its locals must be on the current stack for GC safety. */
     JS_ASSERT((size_t) OBJ_BLOCK_DEPTH(cx, obj) <=
-              (size_t) (fp->sp - fp->spbase));
+              (size_t) (fp->regs->sp - fp->spbase));
 
     if (normalUnwind) {
         depth = OBJ_BLOCK_DEPTH(cx, obj);
         for (sprop = OBJ_SCOPE(obj)->lastProp; sprop; sprop = sprop->parent) {
             if (sprop->getter != js_BlockClass.getProperty)
                 continue;
             if (!(sprop->flags & SPROP_HAS_SHORTID))
                 continue;
             slot = depth + (uintN) sprop->shortid;
-            JS_ASSERT(slot < (size_t) (fp->sp - fp->spbase));
+            JS_ASSERT(slot < (size_t) (fp->regs->sp - fp->spbase));
             if (!js_DefineNativeProperty(cx, obj, sprop->id,
                                          fp->spbase[slot], NULL, NULL,
                                          JSPROP_ENUMERATE | JSPROP_PERMANENT,
                                          SPROP_HAS_SHORTID, sprop->shortid,
                                          NULL)) {
                 /*
                  * Stop adding properties if we failed due to out-of-memory or
                  * other quit-asap errors.
@@ -3264,18 +3265,18 @@ js_LookupPropertyWithFlags(JSContext *cx
                 generation = cx->resolvingTable->generation;
 
                 /* Null *propp here so we can test it at cleanup: safely. */
                 *propp = NULL;
 
                 if (clasp->flags & JSCLASS_NEW_RESOLVE) {
                     newresolve = (JSNewResolveOp)resolve;
                     if (!(flags & JSRESOLVE_CLASSNAME) &&
-                        cx->fp &&
-                        (pc = cx->fp->pc)) {
+                        cx->fp && cx->fp->regs) {
+                        pc = cx->fp->regs->pc;
                         cs = &js_CodeSpec[*pc];
                         format = cs->format;
                         if (JOF_MODE(format) != JOF_NAME)
                             flags |= JSRESOLVE_QUALIFIED;
                         if ((format & JOF_ASSIGNING) ||
                             (cx->fp->flags & JSFRAME_ASSIGNING)) {
                             flags |= JSRESOLVE_ASSIGNING;
                         } else {
@@ -3462,20 +3463,20 @@ js_FindIdentifierBase(JSContext *cx, jsi
      * Look for id's property along the "with" statement chain and the
      * statically-linked scope chain.
      */
     if (js_FindPropertyHelper(cx, id, &obj, &pobj, &prop, &entry) < 0)
         return NULL;
     if (prop) {
         OBJ_DROP_PROPERTY(cx, pobj, prop);
 
-        JS_ASSERT(!entry ||
-                  entry->kpc == ((PCVCAP_TAG(entry->vcap) > 1)
-                                 ? (jsbytecode *) JSID_TO_ATOM(id)
-                                 : cx->fp->pc));
+        JS_ASSERT_IF(entry,
+                     entry->kpc == ((PCVCAP_TAG(entry->vcap) > 1)
+                                    ? (jsbytecode *) JSID_TO_ATOM(id)
+                                    : cx->fp->regs->pc));
         return obj;
     }
 
     /*
      * Use the top-level scope from the scope chain, which won't end in the
      * same scope as cx->globalObject for cross-context function calls.
      */
     JS_ASSERT(obj);
@@ -3624,20 +3625,21 @@ js_GetPropertyHelper(JSContext *cx, JSOb
             PCMETER(JS_PROPERTY_CACHE(cx).nofills++);
             *entryp = NULL;
         }
 
         /*
          * Give a strict warning if foo.bar is evaluated by a script for an
          * object foo with no property named 'bar'.
          */
-        if (JSVAL_IS_VOID(*vp) && cx->fp && (pc = cx->fp->pc)) {
+        if (JSVAL_IS_VOID(*vp) && cx->fp && cx->fp->regs) {
             JSOp op;
             uintN flags;
 
+            pc = cx->fp->regs->pc;
             op = (JSOp) *pc;
             if (op == JSOP_GETXPROP) {
                 flags = JSREPORT_ERROR;
             } else {
                 if (!JS_HAS_STRICT_OPTION(cx) ||
                     (op != JSOP_GETPROP && op != JSOP_GETELEM)) {
                     return JS_TRUE;
                 }
--- a/js/src/jsopcode.c
+++ b/js/src/jsopcode.c
@@ -1782,17 +1782,17 @@ Decompile(SprintStack *ss, jsbytecode *p
             /*
              * Rewrite non-get ops to their "get" format if the error is in
              * the bytecode at pc, so we don't decompile more than the error
              * expression.
              */
             for (fp = cx->fp; fp && !fp->script; fp = fp->down)
                 continue;
             format = cs->format;
-            if (((fp && pc == fp->pc) ||
+            if (((fp && fp->regs && pc == fp->regs->pc) ||
                  (pc == startpc && cs->nuses != 0)) &&
                 format & (JOF_SET|JOF_DEL|JOF_INCDEC|JOF_IMPORT|JOF_FOR|
                           JOF_VARPROP)) {
                 mode = JOF_MODE(format);
                 if (mode == JOF_NAME) {
                     /*
                      * JOF_NAME does not imply JOF_ATOM, so we must check for
                      * the QARG and QVAR format types, and translate those to
@@ -4780,81 +4780,81 @@ js_DecompileFunction(JSPrinter *jp)
 
 char *
 js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v,
                            JSString *fallback)
 {
     JSStackFrame *fp;
     jsbytecode *pc;
     JSScript *script;
+    JSFrameRegs *regs;
     intN pcdepth;
     jsval *sp;
     char *name;
 
     JS_ASSERT(spindex < 0 ||
               spindex == JSDVG_IGNORE_STACK ||
               spindex == JSDVG_SEARCH_STACK);
 
     for (fp = cx->fp; fp && !fp->script; fp = fp->down)
         continue;
-    if (!fp)
+    if (!fp || !fp->regs)
         goto do_fallback;
 
-    pc = fp->pc;
-    if (!pc)
-        goto do_fallback;
     script = fp->script;
+    regs = fp->regs;
+    pc = regs->pc;
     if (pc < script->main || script->code + script->length <= pc) {
         JS_NOT_REACHED("bug");
         goto do_fallback;
     }
 
     if (spindex != JSDVG_IGNORE_STACK) {
         jsbytecode **pcstack;
 
         /*
          * Prepare computing pcstack containing pointers to opcodes that
          * populated interpreter's stack with its current content.
          */
         pcstack = (jsbytecode **)
                   JS_malloc(cx, script->depth * sizeof *pcstack);
         if (!pcstack)
             return NULL;
-        pcdepth = ReconstructPCStack(cx, script, fp->pc, pcstack);
+        pcdepth = ReconstructPCStack(cx, script, regs->pc, pcstack);
         if (pcdepth < 0)
             goto release_pcstack;
 
         if (spindex != JSDVG_SEARCH_STACK) {
             JS_ASSERT(spindex < 0);
             pcdepth += spindex;
             if (pcdepth < 0)
                 goto release_pcstack;
             pc = pcstack[pcdepth];
         } else {
             /*
              * We search from fp->sp to base to find the most recently
              * calculated value matching v under assumption that it is
              * it that caused exception, see bug 328664.
              */
-            JS_ASSERT((size_t) (fp->sp - fp->spbase) <= fp->script->depth);
-            sp = fp->sp;
+            JS_ASSERT((size_t) (regs->sp - fp->spbase) <= script->depth);
+            sp = regs->sp;
             do {
                 if (sp == fp->spbase) {
                     pcdepth = -1;
                     goto release_pcstack;
                 }
             } while (*--sp != v);
 
             if (sp >= fp->spbase + pcdepth) {
                 /*
                  * This happens when the value comes from a temporary slot
                  * that the interpreter uses for GC roots. Assume that it is
                  * fp->pc that caused the exception.
                  */
-                pc = fp->pc;
+                pc = regs->pc;
             } else {
                 pc = pcstack[sp - fp->spbase];
             }
         }
 
       release_pcstack:
         JS_free(cx, pcstack);
         if (pcdepth < 0)
--- a/js/src/jsstr.c
+++ b/js/src/jsstr.c
@@ -1206,25 +1206,26 @@ match_or_replace(JSContext *cx,
              * MODE_MATCH implies str_match is being called from a script or a
              * scripted function.  If the caller cares only about testing null
              * vs. non-null return value, optimize away the array object that
              * would normally be returned in *vp.
              */
             JSStackFrame *fp;
 
             /* Skip Function.prototype.call and .apply frames. */
-            for (fp = cx->fp; fp && !fp->pc; fp = fp->down)
+            for (fp = cx->fp; fp && !fp->regs; fp = fp->down)
                 JS_ASSERT(!fp->script);
 
             /* Assume a full array result is required, then prove otherwise. */
             test = JS_FALSE;
             if (fp) {
-                JS_ASSERT(*fp->pc == JSOP_CALL || *fp->pc == JSOP_NEW);
-                JS_ASSERT(js_CodeSpec[*fp->pc].length == 3);
-                switch (fp->pc[3]) {
+                JS_ASSERT(*fp->regs->pc == JSOP_CALL ||
+                          *fp->regs->pc == JSOP_NEW);
+                JS_ASSERT(js_CodeSpec[*fp->regs->pc].length == 3);
+                switch (fp->regs->pc[3]) {
                   case JSOP_POP:
                   case JSOP_IFEQ:
                   case JSOP_IFNE:
                   case JSOP_IFEQX:
                   case JSOP_IFNEX:
                     test = JS_TRUE;
                     break;
                   default:;
--- a/js/src/jsxml.c
+++ b/js/src/jsxml.c
@@ -1997,25 +1997,25 @@ ParseXMLSource(JSContext *cx, JSString *
     js_strncpy(chars + offset, srcp, srclen);
     offset += srclen;
     dstlen = length - offset + 1;
     js_InflateStringToBuffer(cx, suffix, constrlen(suffix), chars + offset,
                              &dstlen);
     chars [offset + dstlen] = 0;
 
     xml = NULL;
-    for (fp = cx->fp; fp && !fp->pc; fp = fp->down)
+    for (fp = cx->fp; fp && !fp->regs; fp = fp->down)
         JS_ASSERT(!fp->script);
     filename = NULL;
     lineno = 1;
     if (fp) {
-        op = (JSOp) *fp->pc;
+        op = (JSOp) *fp->regs->pc;
         if (op == JSOP_TOXML || op == JSOP_TOXMLLIST) {
             filename = fp->script->filename;
-            lineno = js_PCToLineNumber(cx, fp->script, fp->pc);
+            lineno = js_PCToLineNumber(cx, fp->script, fp->regs->pc);
             for (endp = srcp + srclen; srcp < endp; srcp++) {
                 if (*srcp == '\n')
                     --lineno;
             }
         }
     }
 
     if (!js_InitParseContext(cx, &pc, NULL, chars, length, NULL,
@@ -8276,17 +8276,17 @@ js_InitXMLFilterClass(JSContext *cx, JSO
 JSBool
 js_StepXMLListFilter(JSContext *cx, JSBool initialized)
 {
     jsval *sp;
     JSObject *obj, *filterobj, *resobj, *kidobj;
     JSXML *xml, *list;
     JSXMLFilter *filter;
 
-    sp = cx->fp->sp;
+    sp = cx->fp->regs->sp;
     if (!initialized) {
         /*
          * We haven't iterated yet, so initialize the filter based on the
          * value stored in sp[-2].
          */
         if (!VALUE_IS_XML(cx, sp[-2])) {
             js_ReportValueError(cx, JSMSG_NON_XML_FILTER, -2, sp[-2], NULL);
             return JS_FALSE;
--- a/js/src/liveconnect/nsCLiveconnect.cpp
+++ b/js/src/liveconnect/nsCLiveconnect.cpp
@@ -182,17 +182,16 @@ AutoPushJSContext::AutoPushJSContext(nsI
                                                               jsprinc, "anonymous", 0, nsnull,
                                                               "", 0, "", 1);
             JSPRINCIPALS_DROP(cx, jsprinc);
 
             if (fun)
             {
                 mFrame.fun = fun;
                 mFrame.script = JS_GetFunctionScript(cx, fun);
-                mFrame.pc = mFrame.script->code;
                 mFrame.callee = JS_GetFunctionObject(fun);
                 mFrame.scopeChain = JS_GetParent(cx, mFrame.callee);
                 mFrame.down = cx->fp;
                 cx->fp = &mFrame;
             }
             else
                 mPushResult = NS_ERROR_OUT_OF_MEMORY;
         }