Igor's patch for bug 433382, r=me.
authorBrendan Eich <brendan@mozilla.org>
Fri, 23 May 2008 23:44:08 -0700
changeset 17170 5783ce0bad4f085912b1697ccfed22b61e150798
parent 17169 9f158c90185bcae0c60c7376b9039095c3202bca
child 17171 251c171475d361646abfddf5df87e29505b6c95a
push idunknown
push userunknown
push dateunknown
reviewersme
bugs433382
milestone1.9.1a1pre
Igor's patch for bug 433382, r=me.
js/src/Makefile.in
js/src/Makefile.ref
js/src/jsdbgapi.cpp
js/src/jsemit.cpp
js/src/jsinterp.cpp
js/src/jsinterp.h
js/src/jsobj.cpp
js/src/jsopcode.cpp
js/src/jsopcode.h
js/src/jsopcode.tbl
js/src/jsxdrapi.h
js/src/liveconnect/nsCLiveconnect.cpp
js/src/rules.mk
--- a/js/src/Makefile.in
+++ b/js/src/Makefile.in
@@ -233,16 +233,19 @@ JSJAVA_CFLAGS	= \
 		$(JSJAVA_STUBHEADERS)
 
 # Define keyword generator before rules.mk, see bug 323979 comment 50
 
 HOST_SIMPLE_PROGRAMS += host_jskwgen$(HOST_BIN_SUFFIX)
 GARBAGE += jsautokw.h host_jskwgen$(HOST_BIN_SUFFIX)
 USE_HOST_CXX = 1
 
+HOST_SIMPLE_PROGRAMS += host_jsoplengen$(HOST_BIN_SUFFIX)
+GARBAGE += jsautooplen.h host_jsoplengen$(HOST_BIN_SUFFIX)
+
 ifdef HAVE_DTRACE
 ifneq ($(OS_ARCH),Darwin)
 DTRACE_PROBE_OBJ = $(LIBRARY_NAME)-dtrace.$(OBJ_SUFFIX)
 endif
 MOZILLA_DTRACE_SRC = $(srcdir)/javascript-trace.d
 endif
 
 include $(topsrcdir)/config/rules.mk
@@ -434,23 +437,29 @@ ifeq ($(OS_ARCH),WINCE)
 jscpucfg$(HOST_BIN_SUFFIX):
 	echo no need to build jscpucfg $<
 else
 jscpucfg$(HOST_BIN_SUFFIX): jscpucfg.cpp Makefile.in
 	$(HOST_CXX) $(HOST_CXXFLAGS) $(JSCPUCFG_DEFINES) $(DEFINES) $(NSPR_CFLAGS) $(OUTOPTION)$@ $<
 endif
 endif
 
-# Extra dependancies and rules for keyword switch code
-jsscan.$(OBJ_SUFFIX): jsautokw.h jskeyword.tbl
-
+# Extra dependancies and rules for auto-generated headers
 host_jskwgen.$(OBJ_SUFFIX): jsconfig.h jskeyword.tbl
 
 jsautokw.h: host_jskwgen$(HOST_BIN_SUFFIX)
 	./host_jskwgen$(HOST_BIN_SUFFIX) $@
 
+host_jsoplengen.$(OBJ_SUFFIX): jsopcode.tbl
+
+jsautooplen.h: host_jsoplengen$(HOST_BIN_SUFFIX)
+	./host_jsoplengen$(HOST_BIN_SUFFIX) $@
+
+# Force auto-header generation before compiling any source that may use them
+$(CPPSRCS:%.cpp=%.$(OBJ_SUFFIX)): jsautokw.h jsautooplen.h
+
 ifdef HAVE_DTRACE
 javascript-trace.h: $(srcdir)/javascript-trace.d
 	dtrace -h -s $(srcdir)/javascript-trace.d -o javascript-trace.h.in
 	sed 's/if _DTRACE_VERSION/ifdef INCLUDE_MOZILLA_DTRACE/' \
 	    javascript-trace.h.in > javascript-trace.h
 endif
 
--- a/js/src/Makefile.ref
+++ b/js/src/Makefile.ref
@@ -271,48 +271,48 @@ include rules.mk
 
 MOZ_DEPTH = ../..
 include jsconfig.mk
 
 nsinstall-target:
 	cd ../../config; $(MAKE) OBJDIR=$(OBJDIR) OBJDIR_NAME=$(OBJDIR)
 
 #
-# Rules for keyword switch generation
+# Automatic header generation
 #
 
-GARBAGE += $(OBJDIR)/jsautokw.h $(OBJDIR)/jskwgen$(HOST_BIN_SUFFIX)
-GARBAGE += $(OBJDIR)/jskwgen.$(OBJ_SUFFIX)
+AUTO_HEADERS = $(OBJDIR)/jsautokw.h $(OBJDIR)/jsautooplen.h
 
-$(OBJDIR)/jsscan.$(OBJ_SUFFIX): $(OBJDIR)/jsautokw.h jskeyword.tbl
+$(OBJDIR)/jsautokw.h: jskeyword.tbl
 
-$(OBJDIR)/jskwgen.$(OBJ_SUFFIX): jskwgen.cpp jskeyword.tbl
+$(OBJDIR)/jsautooplen.h: jsopcode.tbl
 
-$(OBJDIR)/jsautokw.h: $(OBJDIR)/jskwgen$(HOST_BIN_SUFFIX) jskeyword.tbl
-	$(OBJDIR)/jskwgen$(HOST_BIN_SUFFIX) $@
+GARBAGE += $(AUTO_HEADERS)
+GARBAGE	+= $(AUTO_HEADERS:$(OBJDIR)/jsauto%.h=$(OBJDIR)/js%gen$(HOST_BIN_SUFFIX))
 
 ifdef USE_MSVC
 
-$(OBJDIR)/jskwgen.obj: jskwgen.cpp jskeyword.tbl
+GARBAGE	+= $(AUTO_HEADERS:$(OBJDIR)/jsauto%.h=$(OBJDIR)/js%gen.obj)
+
+$(AUTO_HEADERS): $(OBJDIR)/jsauto%.h: js%gen.cpp
 	@$(MAKE_OBJDIR)
 	$(CXX) -Fo$(OBJDIR)/ -c $(CFLAGS) $<
-
-$(OBJDIR)/jskwgen$(HOST_BIN_SUFFIX): $(OBJDIR)/jskwgen.$(OBJ_SUFFIX)
-	link.exe -out:"$@" $(EXE_LINK_FLAGS) $^
+	link.exe -out:"$(OBJDIR)/js$*gen$(HOST_BIN_SUFFIX)" $(EXE_LINK_FLAGS) $(OBJDIR)/js$*gen.obj
+	$(OBJDIR)/js$*gen$(HOST_BIN_SUFFIX) $@
 
 else
 
-$(OBJDIR)/jskwgen.o: jskwgen.cpp jskeyword.tbl
+$(AUTO_HEADERS): $(OBJDIR)/jsauto%.h: js%gen.cpp
 	@$(MAKE_OBJDIR)
-	$(CXX) -o $@ -c $(CFLAGS) $<
+	$(CXX) -o $(OBJDIR)/js$*gen$(HOST_BIN_SUFFIX) $(CFLAGS) $(LDFLAGS) $<
+	$(OBJDIR)/js$*gen$(HOST_BIN_SUFFIX) $@
+endif
 
-$(OBJDIR)/jskwgen$(HOST_BIN_SUFFIX): $(OBJDIR)/jskwgen.$(OBJ_SUFFIX)
-	$(CXX) -o $@ $(CFLAGS) $(LDFLAGS) $^
-
-endif
+# force creation of autoheaders before compiling any source that may use them
+$(LIB_OBJS) : $(AUTO_HEADERS)
 
 #
 # JS shell executable
 #
 
 ifdef USE_MSVC
 $(PROGRAM): $(PROG_OBJS) $(LIBRARY)
 	link.exe -out:"$@" $(EXE_LINK_FLAGS) $^
--- a/js/src/jsdbgapi.cpp
+++ b/js/src/jsdbgapi.cpp
@@ -57,16 +57,18 @@
 #include "jslock.h"
 #include "jsobj.h"
 #include "jsopcode.h"
 #include "jsparse.h"
 #include "jsscope.h"
 #include "jsscript.h"
 #include "jsstr.h"
 
+#include "jsautooplen.h"
+
 typedef struct JSTrap {
     JSCList         links;
     JSScript        *script;
     jsbytecode      *pc;
     JSOp            op;
     JSTrapHandler   handler;
     void            *closure;
 } JSTrap;
--- a/js/src/jsemit.cpp
+++ b/js/src/jsemit.cpp
@@ -61,16 +61,18 @@
 #include "jsnum.h"
 #include "jsopcode.h"
 #include "jsparse.h"
 #include "jsregexp.h"
 #include "jsscan.h"
 #include "jsscope.h"
 #include "jsscript.h"
 
+#include "jsautooplen.h"
+
 /* Allocation chunk counts, must be powers of two in general. */
 #define BYTECODE_CHUNK  256     /* code allocation increment */
 #define SRCNOTE_CHUNK   64      /* initial srcnote allocation increment */
 #define TRYNOTE_CHUNK   64      /* trynote allocation increment */
 
 /* Macros to compute byte sizes from typed element counts. */
 #define BYTECODE_SIZE(n)        ((n) * sizeof(jsbytecode))
 #define SRCNOTE_SIZE(n)         ((n) * sizeof(jssrcnote))
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -72,16 +72,18 @@
 #ifdef INCLUDE_MOZILLA_DTRACE
 #include "jsdtracef.h"
 #endif
 
 #if JS_HAS_XML_SUPPORT
 #include "jsxml.h"
 #endif
 
+#include "jsautooplen.h"
+
 #ifdef js_invoke_c__
 
 uint32
 js_GenerateShape(JSContext *cx, JSBool gcLocked)
 {
     JSRuntime *rt;
     uint32 shape;
 
@@ -2068,16 +2070,87 @@ js_DoIncDec(JSContext *cx, const JSCodeS
     if (!js_NewNumberInRootedValue(cx, d, vp2))
         return JS_FALSE;
 
     if (!(cs->format & JOF_POST))
         *vp = *vp2;
     return JS_TRUE;
 }
 
+#ifdef DEBUG
+
+void
+js_TraceOpcode(JSContext *cx, jsint len)
+{
+    FILE *tracefp;
+    JSStackFrame *fp;
+    JSFrameRegs *regs;
+    JSOp prevop;
+    intN ndefs, n, nuses;
+    jsval *siter;
+    JSString *str;
+    JSOp op;
+
+    tracefp = (FILE *) cx->tracefp;
+    JS_ASSERT(tracefp);
+    fp = cx->fp;
+    regs = fp->regs;
+    if (len != 0) {
+        prevop = (JSOp) regs->pc[-len];
+        ndefs = js_CodeSpec[prevop].ndefs;
+        if (ndefs != 0) {
+            if (prevop == JSOP_FORELEM && regs->sp[-1] == JSVAL_FALSE)
+                --ndefs;
+            for (n = -ndefs; n < 0; 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", regs->sp - fp->spbase);
+        }
+        fprintf(tracefp, "  stack: ");
+        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);
+    }
+
+    fprintf(tracefp, "%4u: ", js_PCToLineNumber(cx, fp->script, regs->pc));
+    js_Disassemble1(cx, fp->script, regs->pc,
+                    PTRDIFF(regs->pc, fp->script->code, jsbytecode),
+                    JS_FALSE, tracefp);
+    op = (JSOp) *regs->pc;
+    nuses = js_CodeSpec[op].nuses;
+    if (nuses != 0) {
+        for (n = -nuses; n < 0; 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", regs->sp - fp->spbase);
+    }
+}
+
+#endif /* DEBUG */
+
 #ifdef JS_OPMETER
 
 # include <stdlib.h>
 
 # define HIST_NSLOTS            8
 
 /*
  * The second dimension is hardcoded at 256 because we know that many bits fit
@@ -2416,16 +2489,23 @@ JS_STATIC_ASSERT(!CAN_DO_FAST_INC_DEC(IN
     (__IBMC__ >= 700 && defined __IBM_COMPUTED_GOTO) ||                       \
     __SUNPRO_C >= 0x570)
 #  define JS_THREADED_INTERP 1
 # else
 #  define JS_THREADED_INTERP 0
 # endif
 #endif
 
+
+/*
+ * Interpreter assumes the following to implement condition-free interrupt
+ * implementation when !JS_THREADED_INTERP.
+ */
+JS_STATIC_ASSERT(JSOP_INTERRUPT == 0);
+
 /*
  * Ensure that the intrepreter switch can close call-bytecode cases in the
  * same way as non-call bytecodes.
  */
 JS_STATIC_ASSERT(JSOP_NAME_LENGTH == JSOP_CALLNAME_LENGTH);
 JS_STATIC_ASSERT(JSOP_GETGVAR_LENGTH == JSOP_CALLGVAR_LENGTH);
 JS_STATIC_ASSERT(JSOP_GETVAR_LENGTH == JSOP_CALLVAR_LENGTH);
 JS_STATIC_ASSERT(JSOP_GETARG_LENGTH == JSOP_CALLARG_LENGTH);
@@ -2449,17 +2529,16 @@ js_Interpret(JSContext *cx)
     JSScript *script;
     uintN inlineCallCount;
     JSAtom **atoms;
     JSVersion currentVersion, originalVersion;
     void *mark;
     JSFrameRegs regs;
     JSObject *obj, *obj2, *parent;
     JSBool ok, cond;
-    JSTrapHandler interruptHandler;
     jsint len;
     jsbytecode *endpc, *pc2;
     JSOp op, op2;
     jsatomid index;
     JSAtom *atom;
     uintN argc, attrs, flags;
     uint32 slot;
     jsval *vp, lval, rval, ltmp, rtmp;
@@ -2468,18 +2547,21 @@ js_Interpret(JSContext *cx)
     JSProperty *prop;
     JSScopeProperty *sprop;
     JSString *str, *str2;
     jsint i, j;
     jsdouble d, d2;
     JSClass *clasp;
     JSFunction *fun;
     JSType type;
-#if !JS_THREADED_INTERP && defined DEBUG
-    FILE *tracefp = NULL;
+#if JS_THREADED_INTERP
+    register const void * const *jumpTable;
+#else
+    register uint32 switchMask;
+    uintN switchOp;
 #endif
 #if JS_HAS_EXPORT_IMPORT
     JSIdArray *ida;
 #endif
     jsint low, high, off, npairs;
     JSBool match;
 #if JS_HAS_GETTER_SETTER
     JSPropertyOp getter, setter;
@@ -2489,52 +2571,78 @@ js_Interpret(JSContext *cx)
 # define JS_EXTENSION __extension__
 # define JS_EXTENSION_(s) __extension__ ({ s; })
 #else
 # define JS_EXTENSION
 # define JS_EXTENSION_(s) s
 #endif
 
 #if JS_THREADED_INTERP
-    static void *normalJumpTable[] = {
+    static const void *const normalJumpTable[] = {
 # define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format) \
         JS_EXTENSION &&L_##op,
 # include "jsopcode.tbl"
 # undef OPDEF
     };
 
-    static void *interruptJumpTable[] = {
+    static const void *const interruptJumpTable[] = {
 # define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format)              \
-        JS_EXTENSION &&interrupt,
+        JS_EXTENSION &&L_JSOP_INTERRUPT,
 # include "jsopcode.tbl"
 # 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, regs.pc[n]);               \
-                                 op = (JSOp) *(regs.pc += (n));               \
-                                 DO_OP(); } while (0)
+# define DO_NEXT_OP(n)      JS_BEGIN_MACRO                                    \
+                                METER_OP_PAIR(op, regs.pc[n]);                \
+                                op = (JSOp) *(regs.pc += (n));                \
+                                DO_OP();                                      \
+                            JS_END_MACRO
+
 # 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) *++regs.pc; DO_OP();
-#else
+# define ADD_EMPTY_CASE(OP) BEGIN_CASE(OP)                                    \
+                                JS_ASSERT(js_CodeSpec[OP].length == 1);       \
+                                op = (JSOp) *++regs.pc;                       \
+                                DO_OP();
+
+# define END_EMPTY_CASES
+
+#else /* !JS_THREADED_INTERP */
+
 # define DO_OP()            goto do_op
-# define DO_NEXT_OP(n)      goto advance_pc
+# define DO_NEXT_OP(n)      JS_BEGIN_MACRO                                    \
+                                JS_ASSERT((n) == len);                        \
+                                goto advance_pc;                              \
+                            JS_END_MACRO
+
 # 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)
+# define END_CASE(OP)       END_CASE_LEN(OP##_LENGTH)
+# define END_CASE_LEN(n)    END_CASE_LENX(n)
+# define END_CASE_LENX(n)   END_CASE_LEN##n
+
+/*
+ * To share the code for all len == 1 cases we use the specialized label with
+ * code that falls through to advance_pc: .
+ */
+# define END_CASE_LEN1      goto advance_pc_by_one;
+# define END_CASE_LEN2      len = 2; goto advance_pc;
+# define END_CASE_LEN3      len = 3; goto advance_pc;
+# define END_CASE_LEN4      len = 4; goto advance_pc;
+# define END_CASE_LEN5      len = 5; goto advance_pc;
+# define END_VARLEN_CASE    goto advance_pc;
+# define ADD_EMPTY_CASE(OP) BEGIN_CASE(OP)
+# define END_EMPTY_CASES    goto advance_pc_by_one;
+
 #endif
 
-    /* Check for too deep a C stack. */
+    /* Check for too deep of a native thread stack. */
     JS_CHECK_RECURSION(cx, return JS_FALSE);
 
     rt = cx->runtime;
 
     /* Set registerized frame pointer and derived script pointer. */
     fp = cx->fp;
     script = fp->script;
     JS_ASSERT(script->length != 0);
@@ -2603,28 +2711,25 @@ js_Interpret(JSContext *cx)
      * 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()                                                    \
-    (jumpTable = interruptHandler ? interruptJumpTable : normalJumpTable)
+# define LOAD_INTERRUPT_HANDLER(cx)                                           \
+    ((void) (jumpTable = (cx)->debugHooks->interruptHandler                   \
+                         ? interruptJumpTable                                 \
+                         : normalJumpTable))
 #else
-# define LOAD_JUMP_TABLE()      ((void) 0)
+# define LOAD_INTERRUPT_HANDLER(cx)                                           \
+    ((void) (switchMask = (cx)->debugHooks->interruptHandler ? 0 : 255))
 #endif
 
-#define LOAD_INTERRUPT_HANDLER(cx)                                            \
-    JS_BEGIN_MACRO                                                            \
-        interruptHandler = (cx)->debugHooks->interruptHandler;                \
-        LOAD_JUMP_TABLE();                                                    \
-    JS_END_MACRO
-
     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);
@@ -2662,117 +2767,99 @@ js_Interpret(JSContext *cx)
                 printf("JS INTERPRETER CALLED WITH PENDING EXCEPTION %lx\n",
                        (unsigned long) cx->exception);
             }
 #endif
             goto error;
         }
     }
 
-#if JS_THREADED_INTERP
-
     /*
-     * This is a loop, but it does not look like a loop.  The loop-closing
-     * jump is distributed throughout interruptJumpTable, and comes back to
-     * the interrupt label.  The dispatch on op is through normalJumpTable.
-     * 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.
+     * It is important that "op" be initialized before calling DO_OP because
+     * it is possible for "op" to be specially assigned during the normal
+     * processing of an opcode while looping. We rely on DO_NEXT_OP to manage
+     * "op" correctly in all other cases.
      */
-    op = (JSOp) *regs.pc;
-    if (interruptHandler) {
-interrupt:
-        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;
-            goto forced_return;
-          case JSTRAP_THROW:
-            cx->throwing = JS_TRUE;
-            cx->exception = rval;
-            goto error;
-          default:;
-        }
-        LOAD_INTERRUPT_HANDLER(cx);
-    }
-
-    JS_ASSERT((uintN)op < (uintN)JSOP_LIMIT);
-    JS_EXTENSION_(goto *normalJumpTable[op]);
-
-#else  /* !JS_THREADED_INTERP */
-
+    len = 0;
+    DO_NEXT_OP(len);
+
+#if JS_THREADED_INTERP
+    /*
+     * This is a loop, but it does not look like a loop. The loop-closing
+     * jump is distributed throughout goto *jumpTable[op] inside of DO_OP.
+     * When interrupts are enabled, jumpTable is set to interruptJumpTable
+     * where all jumps point to the JSOP_INTERRUPT case. The latter, after
+     * calling the interrupt handler, dispatches through normalJumpTable to
+     * continue the normal bytecode processing.
+     */
+#else
     for (;;) {
+      advance_pc_by_one:
+        JS_ASSERT(js_CodeSpec[op].length == 1);
+        len = 1;
+      advance_pc:
+        regs.pc += len;
         op = (JSOp) *regs.pc;
+#ifdef DEBUG
+        if (cx->tracefp)
+            js_TraceOpcode(cx, len);
+#endif
+
       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, regs.pc));
-            js_Disassemble1(cx, script, regs.pc,
-                            PTRDIFF(regs.pc, script->code, jsbytecode),
-                            JS_FALSE, tracefp);
-            nuses = js_CodeSpec[op].nuses;
-            if (nuses) {
-                for (n = -nuses; n < 0; 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);
-                    }
+        switchOp = op & switchMask;
+      do_switch:
+        switch (switchOp) {
+#endif /* !JS_THREADED_INTERP */
+
+          BEGIN_CASE(JSOP_INTERRUPT)
+          {
+            JSTrapHandler handler;
+
+            handler = cx->debugHooks->interruptHandler;
+            if (handler) {
+                switch (handler(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;
+                    goto forced_return;
+                  case JSTRAP_THROW:
+                    cx->throwing = JS_TRUE;
+                    cx->exception = rval;
+                    goto error;
+                  default:;
                 }
-                fprintf(tracefp, " @ %d\n", regs.sp - fp->spbase);
-            }
-        }
-#endif /* DEBUG */
-
-        if (interruptHandler) {
-            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;
-                goto forced_return;
-              case JSTRAP_THROW:
-                cx->throwing = JS_TRUE;
-                cx->exception = rval;
-                goto error;
-              default:;
             }
             LOAD_INTERRUPT_HANDLER(cx);
-        }
-
-        switch (op) {
-
-#endif /* !JS_THREADED_INTERP */
-
-          EMPTY_CASE(JSOP_NOP)
-
-          EMPTY_CASE(JSOP_GROUP)
-
-          /* EMPTY_CASE is not used here as JSOP_LINENO_LENGTH == 3. */
+
+#if JS_THREADED_INTERP
+            JS_EXTENSION_(goto *normalJumpTable[op]);
+#else
+            switchOp = op;
+            goto do_switch;
+#endif
+          }
+
+          /* No-ops for ease of decompilation. */
+          ADD_EMPTY_CASE(JSOP_NOP)
+          ADD_EMPTY_CASE(JSOP_GROUP)
+          ADD_EMPTY_CASE(JSOP_CONDSWITCH)
+          ADD_EMPTY_CASE(JSOP_TRY)
+          ADD_EMPTY_CASE(JSOP_FINALLY)
+#if JS_HAS_XML_SUPPORT
+          ADD_EMPTY_CASE(JSOP_STARTXML)
+          ADD_EMPTY_CASE(JSOP_STARTXMLEXPR)
+#endif
+          END_EMPTY_CASES
+
+          /* ADD_EMPTY_CASE is not used here as JSOP_LINENO_LENGTH == 3. */
           BEGIN_CASE(JSOP_LINENO)
           END_CASE(JSOP_LINENO)
 
           BEGIN_CASE(JSOP_PUSH)
             PUSH_STACK(JSVAL_VOID);
           END_CASE(JSOP_PUSH)
 
           BEGIN_CASE(JSOP_POP)
@@ -2797,22 +2884,16 @@ interrupt:
                                      + ((clasp == &js_BlockClass)
                                         ? OBJ_BLOCK_COUNT(cx, obj)
                                         : 1)
                           <= regs.sp);
             }
 #endif
           END_CASE(JSOP_POPN)
 
-          BEGIN_CASE(JSOP_SWAP)
-            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);
             POP_STACK(fp->rval);
           END_CASE(JSOP_POPV)
 
           BEGIN_CASE(JSOP_ENTERWITH)
             if (!js_EnterWith(cx, -1))
@@ -4071,49 +4152,44 @@ interrupt:
             COMPUTE_THIS(cx, fp, obj);
             PUSH_STACK(OBJECT_TO_JSVAL(obj));
           END_CASE(JSOP_THIS)
 
           BEGIN_CASE(JSOP_GETTHISPROP)
             i = 0;
             COMPUTE_THIS(cx, fp, obj);
             PUSH_STACK(JSVAL_NULL);
-            len = JSOP_GETTHISPROP_LENGTH;
             goto do_getprop_with_obj;
 
 #undef COMPUTE_THIS
 
           BEGIN_CASE(JSOP_GETARGPROP)
             i = ARGNO_LEN;
             slot = GET_ARGNO(regs.pc);
             JS_ASSERT(slot < fp->fun->nargs);
             PUSH_STACK(fp->argv[slot]);
-            len = JSOP_GETARGPROP_LENGTH;
             goto do_getprop_body;
 
           BEGIN_CASE(JSOP_GETVARPROP)
             i = VARNO_LEN;
             slot = GET_VARNO(regs.pc);
             JS_ASSERT(slot < fp->fun->u.i.nvars);
             PUSH_STACK(fp->vars[slot]);
-            len = JSOP_GETVARPROP_LENGTH;
             goto do_getprop_body;
 
           BEGIN_CASE(JSOP_GETLOCALPROP)
             i = UINT16_LEN;
             slot = GET_UINT16(regs.pc);
             JS_ASSERT(slot < script->depth);
             PUSH_STACK(fp->spbase[slot]);
-            len = JSOP_GETLOCALPROP_LENGTH;
             goto do_getprop_body;
 
           BEGIN_CASE(JSOP_GETPROP)
           BEGIN_CASE(JSOP_GETXPROP)
             i = 0;
-            len = JSOP_GETPROP_LENGTH;
 
           do_getprop_body:
             FETCH_STACK(-1, lval);
 
           do_getprop_with_lval:
             VALUE_TO_OBJECT(cx, -1, lval, obj);
 
           do_getprop_with_obj:
@@ -4173,18 +4249,19 @@ interrupt:
                 length = obj->fslots[JSSLOT_ARRAY_LENGTH];
                 if (length <= JSVAL_INT_MAX) {
                     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;
+            JS_ASSERT(JSOP_GETPROP_LENGTH + i == js_CodeSpec[op].length);
+            len = JSOP_GETPROP_LENGTH + i;
+                i = -2;
                 goto do_getprop_with_lval;
             }
           END_CASE(JSOP_LENGTH)
 
           BEGIN_CASE(JSOP_CALLPROP)
           {
             JSObject *aobj;
             JSPropCacheEntry *entry;
@@ -4576,17 +4653,17 @@ interrupt:
                         obj->fslots[JSSLOT_ARRAY_COUNT]++;
                     }
                     obj->dslots[i] = rval;
                     goto end_setelem;
                 }
             }
             if (!OBJ_SET_PROPERTY(cx, obj, id, &rval))
                 goto error;
-        end_setelem:
+          end_setelem:
             ADJUST_STACK(-2);
             STORE_STACK(-1, rval);
           END_CASE(JSOP_SETELEM)
 
           BEGIN_CASE(JSOP_ENUMELEM)
             /* Funky: the value to set is under the [obj, id] pair. */
             FETCH_STACK(-3, rval);
             FETCH_OBJECT(cx, -2, lval, obj);
@@ -4933,22 +5010,22 @@ interrupt:
                 LOAD_ATOM(0);
             }
 
             id = ATOM_TO_JSID(atom);
             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 = regs.pc + len; pc2 < endpc; pc2++) {
+                for (pc2 = regs.pc + JSOP_NAME_LENGTH; pc2 < endpc; pc2++) {
                     op2 = (JSOp)*pc2;
                     if (op2 == JSOP_TYPEOF) {
                         PUSH_STACK(JSVAL_VOID);
+                        len = JSOP_NAME_LENGTH;
                         DO_NEXT_OP(len);
                     }
                     if (op2 != JSOP_GROUP)
                         break;
                 }
                 goto atom_not_defined;
             }
 
@@ -5275,18 +5352,16 @@ interrupt:
 #undef SEARCH_PAIRS
 
           end_lookup_switch:
             len = (op == JSOP_LOOKUPSWITCH)
                   ? GET_JUMP_OFFSET(pc2)
                   : GET_JUMPX_OFFSET(pc2);
           END_VARLEN_CASE
 
-          EMPTY_CASE(JSOP_CONDSWITCH)
-
 #if JS_HAS_EXPORT_IMPORT
           BEGIN_CASE(JSOP_EXPORTALL)
             obj = fp->varobj;
             ida = JS_Enumerate(cx, obj);
             if (!ida)
                 goto error;
             ok = JS_TRUE;
             for (i = 0; i != ida->length; i++) {
@@ -5351,37 +5426,41 @@ interrupt:
 
           BEGIN_CASE(JSOP_IMPORTELEM)
             ELEMENT_OP(-1, js_ImportProperty(cx, obj, id));
             ADJUST_STACK(-2);
           END_CASE(JSOP_IMPORTELEM)
 #endif /* JS_HAS_EXPORT_IMPORT */
 
           BEGIN_CASE(JSOP_TRAP)
-            switch (JS_HandleTrap(cx, script, regs.pc, &rval)) {
+          {
+            JSTrapStatus status;
+
+            status = JS_HandleTrap(cx, script, regs.pc, &rval);
+            switch (status) {
               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();
               case JSTRAP_RETURN:
                 fp->rval = rval;
                 ok = JS_TRUE;
                 goto forced_return;
               case JSTRAP_THROW:
                 cx->throwing = JS_TRUE;
                 cx->exception = rval;
                 goto error;
               default:;
+                break;
             }
+            JS_ASSERT(status == JSTRAP_CONTINUE);
             LOAD_INTERRUPT_HANDLER(cx);
-          END_CASE(JSOP_TRAP)
+            JS_ASSERT(JSVAL_IS_INT(rval));
+            op = (JSOp) JSVAL_TO_INT(rval);
+            JS_ASSERT((uintN)op < (uintN)JSOP_LIMIT);
+            DO_OP();
+          }
 
           BEGIN_CASE(JSOP_ARGUMENTS)
             if (!js_GetArgsValue(cx, fp, &rval))
                 goto error;
             PUSH_STACK(rval);
           END_CASE(JSOP_ARGUMENTS)
 
           BEGIN_CASE(JSOP_ARGSUB)
@@ -6074,17 +6153,17 @@ interrupt:
             /* 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;
             ADJUST_STACK(-2);
-          END_CASE(JSOP_INITELEM);
+          END_CASE(JSOP_INITELEM)
 
 #if JS_HAS_SHARP_VARS
           BEGIN_CASE(JSOP_DEFSHARP)
             obj = fp->sharpArray;
             if (!obj) {
                 obj = js_NewArrayObject(cx, 0, NULL);
                 if (!obj)
                     goto error;
@@ -6121,25 +6200,21 @@ interrupt:
                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                      JSMSG_BAD_SHARP_USE, numBuf);
                 goto error;
             }
             PUSH_STACK(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_STACK(JSVAL_FALSE);
             i = PTRDIFF(regs.pc, script->main, jsbytecode) + JSOP_GOSUB_LENGTH;
+            PUSH_STACK(INT_TO_JSVAL(i));
             len = GET_JUMP_OFFSET(regs.pc);
-            PUSH_STACK(INT_TO_JSVAL(i));
           END_VARLEN_CASE
 
           BEGIN_CASE(JSOP_GOSUBX)
             PUSH_STACK(JSVAL_FALSE);
             i = PTRDIFF(regs.pc, script->main, jsbytecode) + JSOP_GOSUBX_LENGTH;
             len = GET_JUMPX_OFFSET(regs.pc);
             PUSH_STACK(INT_TO_JSVAL(i));
           END_VARLEN_CASE
@@ -6384,19 +6459,16 @@ interrupt:
                 len = GET_JUMP_OFFSET(regs.pc);
                 JS_ASSERT(len < 0);
                 CHECK_BRANCH(len);
                 DO_NEXT_OP(len);
             }
             ADJUST_STACK(-1);
           END_CASE(JSOP_ENDFILTER);
 
-          EMPTY_CASE(JSOP_STARTXML)
-          EMPTY_CASE(JSOP_STARTXMLEXPR)
-
           BEGIN_CASE(JSOP_TOXML)
             FETCH_STACK(-1, rval);
             obj = js_ValueToXMLObject(cx, rval);
             if (!obj)
                 goto error;
             STORE_STACK(-1, OBJECT_TO_JSVAL(obj));
           END_CASE(JSOP_TOXML)
 
@@ -6686,58 +6758,16 @@ interrupt:
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                  JSMSG_BAD_BYTECODE, numBuf);
             goto error;
           }
 
 #if !JS_THREADED_INTERP
 
         } /* switch (op) */
-
-    advance_pc:
-        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) regs.pc[-len];
-            ndefs = js_CodeSpec[op].ndefs;
-            if (ndefs) {
-                if (op == JSOP_FORELEM && regs.sp[-1] == JSVAL_FALSE)
-                    --ndefs;
-                for (n = -ndefs; n < 0; 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", regs.sp - fp->spbase);
-            }
-            fprintf(tracefp, "  stack: ");
-            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)(regs.pc - script->code) < script->length);
     if (!cx->throwing) {
         /* This is an error, not a catchable exception, quit the frame ASAP. */
         ok = JS_FALSE;
--- a/js/src/jsinterp.h
+++ b/js/src/jsinterp.h
@@ -503,16 +503,23 @@ js_OnUnknownMethod(JSContext *cx, jsval 
  * both *vp and *vp2 will contain the result on return. For post-increments,
  * vp will contain the original value converted to a number and vp2 will get
  * the result. Both vp and vp2 must be roots.
  */
 extern JSBool
 js_DoIncDec(JSContext *cx, const JSCodeSpec *cs, jsval *vp, jsval *vp2);
 
 /*
+ * Opcode tracing helper. When len is not 0, cx->fp->regs->pc[-len] gives the
+ * previous opcode.
+ */
+extern void
+js_TraceOpcode(JSContext *cx, jsint len);
+
+/*
  * JS_OPMETER helper functions.
  */
 extern void
 js_MeterOpcodePair(JSOp op1, JSOp op2);
 
 extern void
 js_MeterSlotOpcode(JSOp op, uint32 slot);
 
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -83,16 +83,18 @@
 #if JS_HAS_XDR
 #include "jsxdrapi.h"
 #endif
 
 #ifdef INCLUDE_MOZILLA_DTRACE
 #include "jsdtracef.h"
 #endif
 
+#include "jsautooplen.h"
+
 #ifdef JS_THREADSAFE
 #define NATIVE_DROP_PROPERTY js_DropProperty
 
 extern void
 js_DropProperty(JSContext *cx, JSObject *obj, JSProperty *prop);
 #else
 #define NATIVE_DROP_PROPERTY NULL
 #endif
--- a/js/src/jsopcode.cpp
+++ b/js/src/jsopcode.cpp
@@ -70,16 +70,24 @@
 #include "jsscope.h"
 #include "jsscript.h"
 #include "jsstr.h"
 
 #if JS_HAS_DESTRUCTURING
 # include "jsnum.h"
 #endif
 
+#include "jsautooplen.h"
+
+/* Verify JSOP_XXX_LENGTH constant definitions. */
+#define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format)               \
+    JS_STATIC_ASSERT(op##_LENGTH == length);
+#include "jsopcode.tbl"
+#undef OPDEF
+
 static const char js_incop_strs[][3] = {"++", "--"};
 
 const JSCodeSpec js_CodeSpec[] = {
 #define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format) \
     {length,nuses,ndefs,prec,format},
 #include "jsopcode.tbl"
 #undef OPDEF
 };
@@ -2143,24 +2151,16 @@ Decompile(SprintStack *ss, jsbytecode *p
               case JSOP_RETSUB:
                 rval = POP_STR();
                 LOCAL_ASSERT(strcmp(rval, retsub_pc_cookie) == 0);
                 lval = POP_STR();
                 LOCAL_ASSERT(strcmp(lval, exception_cookie) == 0);
                 todo = -2;
                 break;
 
-              case JSOP_SWAP:
-                /*
-                 * We don't generate this opcode currently, and previously we
-                 * did not need to decompile it.  If old, serialized bytecode
-                 * uses it still, we should fall through and set todo = -2.
-                 */
-                /* FALL THROUGH */
-
               case JSOP_GOSUB:
               case JSOP_GOSUBX:
                 /*
                  * JSOP_GOSUB and GOSUBX have no effect on the decompiler's
                  * string stack because the next op in bytecode order finds
                  * the stack balanced by a JSOP_RETSUB executed elsewhere.
                  */
                 todo = -2;
@@ -4931,18 +4931,17 @@ DecompileExpression(JSContext *cx, JSScr
         script->main = code + (oldmain - oldcode);
         pc = code + (pc - oldcode);
     }
 
     op = (JSOp) *pc;
 
     /* None of these stack-writing ops generates novel values. */
     JS_ASSERT(op != JSOP_CASE && op != JSOP_CASEX &&
-              op != JSOP_DUP && op != JSOP_DUP2 &&
-              op != JSOP_SWAP);
+              op != JSOP_DUP && op != JSOP_DUP2);
 
     /*
      * |this| could convert to a very long object initialiser, so cite it by
      * its keyword name instead.
      */
     if (op == JSOP_THIS) {
         name = JS_strdup(cx, js_this_str);
         goto out;
@@ -5204,23 +5203,16 @@ ReconstructPCStack(JSContext *cx, JSScri
             break;
 
           case JSOP_DUP2:
             JS_ASSERT(ndefs == 4);
             pcstack[pcdepth + 2] = pcstack[pcdepth];
             pcstack[pcdepth + 3] = pcstack[pcdepth + 1];
             break;
 
-          case JSOP_SWAP:
-            JS_ASSERT(ndefs == 2);
-            pc2 = pcstack[pcdepth];
-            pcstack[pcdepth] = pcstack[pcdepth + 1];
-            pcstack[pcdepth + 1] = pc2;
-            break;
-
           case JSOP_LEAVEBLOCKEXPR:
             /*
              * The decompiler wants to see [leaveblockexpr] on pcstack, not
              * [enterblock] or the pc that ended a simulated let expression
              * when [enterblock] defines zero locals as in:
              *
              *   let ([] = []) expr
              */
--- a/js/src/jsopcode.h
+++ b/js/src/jsopcode.h
@@ -55,24 +55,16 @@ JS_BEGIN_EXTERN_C
 typedef enum JSOp {
 #define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format) \
     op = val,
 #include "jsopcode.tbl"
 #undef OPDEF
     JSOP_LIMIT
 } JSOp;
 
-typedef enum JSOpLength {
-#define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format) \
-    op##_LENGTH = length,
-#include "jsopcode.tbl"
-#undef OPDEF
-    JSOP_LIMIT_LENGTH
-} JSOpLength;
-
 /*
  * JS bytecode formats.
  */
 #define JOF_BYTE          0       /* single bytecode, no immediates */
 #define JOF_JUMP          1       /* signed 16-bit jump offset immediate */
 #define JOF_ATOM          2       /* unsigned 16-bit constant pool index */
 #define JOF_UINT16        3       /* unsigned 16-bit immediate operand */
 #define JOF_TABLESWITCH   4       /* table switch */
--- a/js/src/jsopcode.tbl
+++ b/js/src/jsopcode.tbl
@@ -92,17 +92,17 @@
  *
  * This file is best viewed with 128 columns:
 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678
  */
 
 /* legend: op         val name          image       len use def prec  format */
 
 /* Longstanding JavaScript bytecodes. */
-OPDEF(JSOP_NOP,       0,  "nop",        NULL,         1,  0,  0,  0,  JOF_BYTE)
+OPDEF(JSOP_INTERRUPT, 0,  "interrupt",  NULL,         1,  0,  0,  0,  JOF_BYTE)
 OPDEF(JSOP_PUSH,      1,  "push",       NULL,         1,  0,  1,  0,  JOF_BYTE)
 OPDEF(JSOP_POPV,      2,  "popv",       NULL,         1,  1,  0,  2,  JOF_BYTE)
 OPDEF(JSOP_ENTERWITH, 3,  "enterwith",  NULL,         1,  1,  1,  0,  JOF_BYTE|JOF_PARENHEAD)
 OPDEF(JSOP_LEAVEWITH, 4,  "leavewith",  NULL,         1,  1,  0,  0,  JOF_BYTE)
 OPDEF(JSOP_RETURN,    5,  "return",     NULL,         1,  1,  0,  2,  JOF_BYTE)
 OPDEF(JSOP_GOTO,      6,  "goto",       NULL,         3,  0,  0,  0,  JOF_JUMP)
 OPDEF(JSOP_IFEQ,      7,  "ifeq",       NULL,         3,  1,  0,  4,  JOF_JUMP|JOF_DETECTING)
 OPDEF(JSOP_IFNE,      8,  "ifne",       NULL,         3,  1,  0,  0,  JOF_JUMP|JOF_PARENHEAD)
@@ -326,19 +326,19 @@ OPDEF(JSOP_SETCALL,     132, "setcall", 
 /*
  * Exception handling no-ops, for more economical byte-coding than SRC_TRYFIN
  * srcnote-annotated JSOP_NOPs.
  */
 OPDEF(JSOP_TRY,         133,"try",        NULL,       1,  0,  0,  0,  JOF_BYTE)
 OPDEF(JSOP_FINALLY,     134,"finally",    NULL,       1,  0,  0,  0,  JOF_BYTE)
 
 /*
- * Swap the top two stack elements.
+ * Generic nop for the decompiler.
  */
-OPDEF(JSOP_SWAP,        135,"swap",       NULL,       1,  2,  2,  0,  JOF_BYTE)
+OPDEF(JSOP_NOP,         135,"nop",        NULL,       1,  0,  0,  0,  JOF_BYTE)
 
 /*
  * Bytecodes that avoid making an arguments object in most cases:
  * JSOP_ARGSUB gets arguments[i] from fp->argv, iff i is in [0, fp->argc-1].
  * JSOP_ARGCNT returns fp->argc.
  */
 OPDEF(JSOP_ARGSUB,      136,"argsub",     NULL,       3,  0,  1, 18,  JOF_QARG |JOF_NAME)
 OPDEF(JSOP_ARGCNT,      137,"argcnt",     NULL,       1,  0,  1, 18,  JOF_BYTE)
--- a/js/src/jsxdrapi.h
+++ b/js/src/jsxdrapi.h
@@ -197,17 +197,17 @@ JS_XDRFindClassById(JSXDRState *xdr, uin
  * Bytecode version number. Increment the subtrahend whenever JS bytecode
  * changes incompatibly.
  *
  * This version number should be XDR'ed once near the front of any file or
  * larger storage unit containing XDR'ed bytecode and other data, and checked
  * before deserialization of bytecode.  If the saved version does not match
  * the current version, abort deserialization and invalidate the file.
  */
-#define JSXDR_BYTECODE_VERSION      (0xb973c0de - 24)
+#define JSXDR_BYTECODE_VERSION      (0xb973c0de - 25)
 
 /*
  * Library-private functions.
  */
 extern JSBool
 js_XDRAtom(JSXDRState *xdr, JSAtom **atomp);
 
 extern JSBool
--- a/js/src/liveconnect/nsCLiveconnect.cpp
+++ b/js/src/liveconnect/nsCLiveconnect.cpp
@@ -187,18 +187,18 @@ AutoPushJSContext::AutoPushJSContext(nsI
             if (fun)
             {
                 JSScript *script = JS_GetFunctionScript(cx, fun);
                 mFrame.fun = fun;
                 mFrame.script = script;
                 mFrame.callee = JS_GetFunctionObject(fun);
                 mFrame.scopeChain = JS_GetParent(cx, mFrame.callee);
                 mFrame.down = cx->fp;
-                mRegs.pc = script->code + script->length
-                           - JSOP_STOP_LENGTH;
+                mRegs.pc = script->code + script->length - 1;
+                JS_ASSERT(static_cast<JSOp>(*mRegs.pc) == JSOP_STOP);
                 mRegs.sp = NULL;
                 mFrame.regs = &mRegs;
                 cx->fp = &mFrame;
             }
             else
                 mPushResult = NS_ERROR_OUT_OF_MEMORY;
         }
     }
--- a/js/src/rules.mk
+++ b/js/src/rules.mk
@@ -180,18 +180,16 @@ ifneq "$(strip $(SHARED_LIBRARY))" ""
 endif
 ifneq "$(strip $(PROGRAM))" ""
 	$(CP) $(PROGRAM) $(DIST)/bin
 endif
 	+$(LOOP_OVER_DIRS)
 
 clean:
 	rm -rf $(OBJS) $(GARBAGE)
-	@cd fdlibm; $(MAKE) -f Makefile.ref clean
 
 clobber:
 	rm -rf $(OBJS) $(TARGETS) $(DEPENDENCIES)
-	@cd fdlibm; $(MAKE) -f Makefile.ref clobber
 
 tar:
 	tar cvf $(TARNAME) $(TARFILES)
 	gzip $(TARNAME)