Backed out changeset f13e2a2a5d66 - I was not careful when merging the unary op changes
authorIgor Bukanov <igor@mir2.org>
Sun, 21 Dec 2008 12:23:08 +0100
changeset 23108 01b6e96c3208250f75d1f519da178461c36ea1e5
parent 23107 f13e2a2a5d66682ec1a6f695d1aeca92ea066ea2
child 23109 605fd1985d05780c6429c1ce63e7e4bbfe38b88e
push id4346
push userrsayre@mozilla.com
push dateFri, 26 Dec 2008 01:26:36 +0000
treeherdermozilla-central@8eb5a5b83a93 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone1.9.2a1pre
backs outf13e2a2a5d66682ec1a6f695d1aeca92ea066ea2
Backed out changeset f13e2a2a5d66 - I was not careful when merging the unary op changes
js/src/jsinterp.cpp
js/src/jsopcode.tbl
js/src/jstracer.cpp
js/src/jstracer.h
js/src/jsxdrapi.h
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -237,18 +237,18 @@ js_FillPropertyCache(JSContext *cx, JSOb
                     vword = JSVAL_OBJECT_TO_PCVAL(v);
                     break;
                 }
             }
         }
 
         /* If getting a value via a stub getter, we can cache the slot. */
         if (!(cs->format & JOF_SET) &&
-            !((cs->format & (JOF_INCDEC | JOF_FOR)) &&
-              (sprop->attrs & JSPROP_READONLY)) &&
+            !((cs->format & (JOF_INCDEC | JOF_FOR)) && 
+              (sprop->attrs & JSPROP_READONLY)) && 
             SPROP_HAS_STUB_GETTER(sprop) &&
             SPROP_HAS_VALID_SLOT(sprop, scope)) {
             /* Great, let's cache sprop's slot and use it on cache hit. */
             vword = SLOT_TO_PCVAL(sprop->slot);
         } else {
             /* Best we can do is to cache sprop (still a nice speedup). */
             vword = SPROP_TO_PCVAL(sprop);
         }
@@ -2411,16 +2411,22 @@ JS_STATIC_ASSERT(!CAN_DO_FAST_INC_DEC(IN
     __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_GETUPVAR_LENGTH == JSOP_CALLUPVAR_LENGTH);
 JS_STATIC_ASSERT(JSOP_GETARG_LENGTH == JSOP_CALLARG_LENGTH);
 JS_STATIC_ASSERT(JSOP_GETLOCAL_LENGTH == JSOP_CALLLOCAL_LENGTH);
@@ -2466,16 +2472,22 @@ 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
+    register void * const *jumpTable;
+#else
+    register uint32 switchMask;
+    uintN switchOp;
+#endif
     jsint low, high, off, npairs;
     JSBool match;
 #if JS_HAS_GETTER_SETTER
     JSPropertyOp getter, setter;
 #endif
     JSAutoResolveFlags rf(cx, JSRESOLVE_INFER);
 
 #ifdef __GNUC__
@@ -2489,77 +2501,73 @@ js_Interpret(JSContext *cx)
 #if JS_THREADED_INTERP
     static 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 *const interruptJumpTable[] = {
-# define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format)              \
-        JS_EXTENSION &&interrupt,
+#ifdef JS_TRACER
+    static void *const recordingJumpTable[] = {
+# define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format) \
+        JS_EXTENSION &&R_##op,
 # include "jsopcode.tbl"
 # undef OPDEF
     };
-
-    register void * const *jumpTable = normalJumpTable;
+#endif /* JS_TRACER */
+
+    static void *const interruptJumpTable[] = {
+# define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format)              \
+        JS_EXTENSION &&L_JSOP_INTERRUPT,
+# include "jsopcode.tbl"
+# undef OPDEF
+    };
 
     METER_OP_INIT(op);      /* to nullify first METER_OP_PAIR */
 
-# define ENABLE_INTERRUPTS() ((void) (jumpTable = interruptJumpTable))
-
 # ifdef JS_TRACER
-#  define CHECK_RECORDER()                                                    \
-    JS_ASSERT_IF(TRACE_RECORDER(cx), jumpTable == interruptJumpTable)
+#  define CHECK_RECORDER()  JS_BEGIN_MACRO                                    \
+                                JS_ASSERT(!TRACE_RECORDER(cx) ^               \
+                                          (jumpTable == recordingJumpTable)); \
+                            JS_END_MACRO
 # else
 #  define CHECK_RECORDER()  ((void)0)
 # endif
 
 # define DO_OP()            JS_BEGIN_MACRO                                    \
                                 CHECK_RECORDER();                             \
                                 JS_EXTENSION_(goto *jumpTable[op]);           \
                             JS_END_MACRO
 # 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: CHECK_RECORDER();
+# define BEGIN_CASE(OP)     L_##OP:                                           \
+                                CHECK_RECORDER();
 # define END_CASE(OP)       DO_NEXT_OP(OP##_LENGTH);
 # define END_VARLEN_CASE    DO_NEXT_OP(len);
 # 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 */
 
-    register intN switchMask = 0;
-    intN switchOp;
-
-# define ENABLE_INTERRUPTS() ((void) (switchMask = -1))
-
-# ifdef JS_TRACER
-#  define CHECK_RECORDER()                                                    \
-    JS_ASSERT_IF(TRACE_RECORDER(cx), switchMask == -1)
-# else
-#  define CHECK_RECORDER()  ((void)0)
-# endif
-
 # define DO_OP()            goto do_op
 # define DO_NEXT_OP(n)      JS_BEGIN_MACRO                                    \
                                 JS_ASSERT((n) == len);                        \
                                 goto advance_pc;                              \
                             JS_END_MACRO
 
-# define BEGIN_CASE(OP)     case OP: CHECK_RECORDER();
+# define BEGIN_CASE(OP)     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: .
  */
@@ -2636,20 +2644,17 @@ js_Interpret(JSContext *cx)
 #define LOAD_FUNCTION(PCOFF)                                                  \
     JS_GET_SCRIPT_FUNCTION(script, GET_FULL_INDEX(PCOFF), fun)
 
 #ifdef JS_TRACER
 
 #define MONITOR_BRANCH()                                                      \
     JS_BEGIN_MACRO                                                            \
         if (TRACING_ENABLED(cx)) {                                            \
-            if (js_MonitorLoopEdge(cx, inlineCallCount)) {                    \
-                JS_ASSERT(TRACE_RECORDER(cx));                                \
-                ENABLE_INTERRUPTS();                                          \
-            }                                                                 \
+            ENABLE_TRACER(js_MonitorLoopEdge(cx, inlineCallCount));           \
             fp = cx->fp;                                                      \
             script = fp->script;                                              \
             atoms = fp->imacpc                                                \
                     ? COMMON_ATOMS_START(&rt->atomState)                      \
                     : script->atomMap.vector;                                 \
             currentVersion = (JSVersion) script->version;                     \
             JS_ASSERT(fp->regs == &regs);                                     \
             if (cx->throwing)                                                 \
@@ -2708,29 +2713,63 @@ js_Interpret(JSContext *cx)
         JSStackFrame **disp = &cx->display[script->staticDepth];
         fp->displaySave = *disp;
         *disp = fp;
     }
 #ifdef DEBUG
     fp->pcDisabledSave = JS_PROPERTY_CACHE(cx).disabled;
 #endif
 
-# define CHECK_INTERRUPT_HANDLER()                                            \
-    JS_BEGIN_MACRO                                                            \
-        if (cx->debugHooks->interruptHandler)                                 \
-            ENABLE_INTERRUPTS();                                              \
-    JS_END_MACRO
-
     /*
      * 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.
      */
-    CHECK_INTERRUPT_HANDLER();
+#if JS_THREADED_INTERP
+#ifdef JS_TRACER
+# define LOAD_INTERRUPT_HANDLER(cx)                                           \
+    ((void) (jumpTable = (cx)->debugHooks->interruptHandler                   \
+                         ? interruptJumpTable                                 \
+                         : TRACE_RECORDER(cx)                                 \
+                         ? recordingJumpTable                                 \
+                         : normalJumpTable))
+# define ENABLE_TRACER(flag)                                                  \
+    JS_BEGIN_MACRO                                                            \
+        bool flag_ = (flag);                                                  \
+        JS_ASSERT(flag_ == !!TRACE_RECORDER(cx));                             \
+        jumpTable = flag_ ? recordingJumpTable : normalJumpTable;             \
+    JS_END_MACRO
+#else /* !JS_TRACER */
+# define LOAD_INTERRUPT_HANDLER(cx)                                           \
+    ((void) (jumpTable = (cx)->debugHooks->interruptHandler                   \
+                         ? interruptJumpTable                                 \
+                         : normalJumpTable))
+# define ENABLE_TRACER(flag) ((void)0)
+#endif /* !JS_TRACER */
+#else /* !JS_THREADED_INTERP */
+#ifdef JS_TRACER
+# define LOAD_INTERRUPT_HANDLER(cx)                                           \
+    ((void) (switchMask = ((cx)->debugHooks->interruptHandler ||              \
+                           TRACE_RECORDER(cx)) ? 0 : 255))
+# define ENABLE_TRACER(flag)                                                  \
+    JS_BEGIN_MACRO                                                            \
+        bool flag_ = (flag);                                                  \
+        JS_ASSERT(flag_ == !!TRACE_RECORDER(cx));                             \
+        switchMask = flag_ ? 0 : 255;                                         \
+    JS_END_MACRO
+#else /* !JS_TRACER */
+# define LOAD_INTERRUPT_HANDLER(cx)                                           \
+    ((void) (switchMask = ((cx)->debugHooks->interruptHandler                 \
+                           ? 0 : 255)))
+# define ENABLE_TRACER(flag) ((void)0)
+#endif /* !JS_TRACER */
+#endif /* !JS_THREADED_INTERP */
+
+    LOAD_INTERRUPT_HANDLER(cx);
 
 #if !JS_HAS_GENERATORS
     JS_ASSERT(!fp->regs);
 #else
     /* Initialize the pc and sp registers unless we're resuming a generator. */
     if (JS_LIKELY(!fp->regs)) {
 #endif
         ASSERT_NOT_THROWING(cx);
@@ -2776,91 +2815,75 @@ js_Interpret(JSContext *cx)
     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 interrupt label. The latter, after
+     * 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.
      */
-  interrupt:
-#else /* !JS_THREADED_INTERP */
+#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
+#ifdef DEBUG
         if (cx->tracefp)
             js_TraceOpcode(cx, len);
-# endif
+#endif
 
       do_op:
-        CHECK_RECORDER();
-        switchOp = intN(op) | switchMask;
+        switchOp = op & switchMask;
       do_switch:
         switch (switchOp) {
-          case -1:
-            JS_ASSERT(switchMask == -1);
 #endif /* !JS_THREADED_INTERP */
+
+          BEGIN_CASE(JSOP_INTERRUPT)
           {
-            bool moreInterrupts = false;
-            JSTrapHandler handler = cx->debugHooks->interruptHandler;
+            JSTrapHandler handler;
+
+            handler = cx->debugHooks->interruptHandler;
             if (handler) {
-#ifdef JS_TRACER
-                if (TRACE_RECORDER(cx))
-                    js_AbortRecording(cx, "interrupt handler");
-#endif
                 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:;
                 }
-                moreInterrupts = true;
+#if !JS_THREADED_INTERP
+            } else {
+                /* this was not a real interrupt, the tracer is trying to
+                   record a trace */
+                switchOp = op + 256;
+                goto do_switch;
+#endif
             }
-
-#ifdef JS_TRACER
-            TraceRecorder* tr = TRACE_RECORDER(cx);
-            if (tr) {
-                JSMonitorRecordingStatus status = tr->monitorRecording(op);
-                if (status == JSMRS_CONTINUE) {
-                    moreInterrupts = true;
-                } else if (status == JSMRS_IMACRO) {
-                    atoms = COMMON_ATOMS_START(&rt->atomState);
-                    op = JSOp(*regs.pc);
-                    DO_OP();    /* keep interrupting for op. */
-                } else {
-                    JS_ASSERT(status == JSMRS_STOP);
-                }
-            }
-#endif /* !JS_TRACER */
+            LOAD_INTERRUPT_HANDLER(cx);
 
 #if JS_THREADED_INTERP
-            jumpTable = moreInterrupts ? interruptJumpTable : normalJumpTable;
             JS_EXTENSION_(goto *normalJumpTable[op]);
 #else
-            switchMask = moreInterrupts ? -1 : 0;
-            switchOp = intN(op);
+            switchOp = op;
             goto do_switch;
 #endif
           }
 
           /* No-ops for ease of decompilation. */
           ADD_EMPTY_CASE(JSOP_NOP)
           ADD_EMPTY_CASE(JSOP_CONDSWITCH)
           ADD_EMPTY_CASE(JSOP_TRY)
@@ -2996,17 +3019,17 @@ js_Interpret(JSContext *cx)
                     if (hook) {
                         /*
                          * Do not pass &ok directly as exposing the address
                          * inhibits optimizations and uninitialised warnings.
                          */
                         status = ok;
                         hook(cx, fp, JS_FALSE, &status, hookData);
                         ok = status;
-                        CHECK_INTERRUPT_HANDLER();
+                        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.
@@ -3211,27 +3234,27 @@ js_Interpret(JSContext *cx)
             STORE_OPND(-1, BOOLEAN_TO_JSVAL(cond));
           END_CASE(JSOP_IN)
 
           BEGIN_CASE(JSOP_ITER)
             JS_ASSERT(regs.sp > StackBase(fp));
             flags = regs.pc[1];
             if (!js_ValueToIterator(cx, flags, &regs.sp[-1]))
                 goto error;
-            CHECK_INTERRUPT_HANDLER();
+            LOAD_INTERRUPT_HANDLER(cx);
             JS_ASSERT(!JSVAL_IS_PRIMITIVE(regs.sp[-1]));
             PUSH(JSVAL_VOID);
           END_CASE(JSOP_ITER)
 
           BEGIN_CASE(JSOP_NEXTITER)
             JS_ASSERT(regs.sp - 2 >= StackBase(fp));
             JS_ASSERT(!JSVAL_IS_PRIMITIVE(regs.sp[-2]));
             if (!js_CallIteratorNext(cx, JSVAL_TO_OBJECT(regs.sp[-2]), &regs.sp[-1]))
                 goto error;
-            CHECK_INTERRUPT_HANDLER();
+            LOAD_INTERRUPT_HANDLER(cx);
             rval = BOOLEAN_TO_JSVAL(regs.sp[-1] != JSVAL_HOLE);
             PUSH(rval);
             TRACE_0(IteratorNextComplete);
           END_CASE(JSOP_NEXTITER)
 
           BEGIN_CASE(JSOP_ENDITER)
             /*
              * Decrease the stack pointer even when !ok -- see comments in the
@@ -4627,18 +4650,20 @@ js_Interpret(JSContext *cx)
                     if (entry)
                         TRACE_1(SetPropMiss, entry);
 #endif
                 } else {
                     if (!OBJ_SET_PROPERTY(cx, obj, id, &rval))
                         goto error;
                 }
 #ifdef JS_TRACER
-                if (!entry && TRACE_RECORDER(cx))
+                if (!entry && TRACE_RECORDER(cx)) {
                     js_AbortRecording(cx, "SetPropUncached");
+                    ENABLE_TRACER(0);
+                }
 #endif
             } while (0);
           END_SET_CASE_STORE_RVAL(JSOP_SETPROP, 2);
 
           BEGIN_CASE(JSOP_GETELEM)
             /* Open-coded ELEMENT_OP optimized for strings and dense arrays. */
             lval = FETCH_OPND(-2);
             rval = FETCH_OPND(-1);
@@ -4778,17 +4803,17 @@ js_Interpret(JSContext *cx)
                     flags = JSFRAME_CONSTRUCTING;
                     goto inline_call;
                 }
             }
 
             if (!js_InvokeConstructor(cx, argc, JS_FALSE, vp))
                 goto error;
             regs.sp = vp + 1;
-            CHECK_INTERRUPT_HANDLER();
+            LOAD_INTERRUPT_HANDLER(cx);
           END_CASE(JSOP_NEW)
           
           BEGIN_CASE(JSOP_CALL)
           BEGIN_CASE(JSOP_EVAL)
           BEGIN_CASE(JSOP_APPLY)
             argc = GET_ARGC(regs.pc);
             vp = regs.sp - (argc + 2);
             
@@ -4918,17 +4943,17 @@ js_Interpret(JSContext *cx)
                     while (nvars--)
                         *newsp++ = JSVAL_VOID;
 
                     /* Call the debugger hook if present. */
                     hook = cx->debugHooks->callHook;
                     if (hook) {
                         newifp->hookData = hook(cx, &newifp->frame, JS_TRUE, 0,
                                                 cx->debugHooks->callHookData);
-                        CHECK_INTERRUPT_HANDLER();
+                        LOAD_INTERRUPT_HANDLER(cx);
                     } else {
                         newifp->hookData = NULL;
                     }
 
                     /* Scope with a call object parented by callee's parent. */
                     if (JSFUN_HEAVYWEIGHT_TEST(fun->flags) &&
                         !js_GetCallObject(cx, &newifp->frame, parent)) {
                         goto bad_inline_call;
@@ -5016,17 +5041,17 @@ js_Interpret(JSContext *cx)
             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
             regs.sp = vp + 1;
-            CHECK_INTERRUPT_HANDLER();
+            LOAD_INTERRUPT_HANDLER(cx);
             if (!ok)
                 goto error;
             JS_RUNTIME_METER(rt, nonInlineCalls);
 
           end_call:
 #if JS_HAS_LVALUE_RETURN
             if (cx->rval2set) {
                 /*
@@ -5054,17 +5079,17 @@ js_Interpret(JSContext *cx)
           END_CASE(JSOP_CALL)
 
 #if JS_HAS_LVALUE_RETURN
           BEGIN_CASE(JSOP_SETCALL)
             argc = GET_ARGC(regs.pc);
             vp = regs.sp - argc - 2;
             ok = js_Invoke(cx, argc, vp, 0);
             regs.sp = vp + 1;
-            CHECK_INTERRUPT_HANDLER();
+            LOAD_INTERRUPT_HANDLER(cx);
             if (!ok)
                 goto error;
             if (!cx->rval2set) {
                 op2 = (JSOp) regs.pc[JSOP_SETCALL_LENGTH];
                 if (op2 != JSOP_DELELEM) {
                     JS_ASSERT(!(js_CodeSpec[op2].format & JOF_DEL));
                     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                          JSMSG_BAD_LEFTSIDE_OF_ASS);
@@ -5492,17 +5517,17 @@ js_Interpret(JSContext *cx)
               case JSTRAP_THROW:
                 cx->throwing = JS_TRUE;
                 cx->exception = rval;
                 goto error;
               default:;
                 break;
             }
             JS_ASSERT(status == JSTRAP_CONTINUE);
-            CHECK_INTERRUPT_HANDLER();
+            LOAD_INTERRUPT_HANDLER(cx);
             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))
@@ -5824,17 +5849,17 @@ js_Interpret(JSContext *cx)
             obj = FUN_OBJECT(fun);
             if (OBJ_GET_PARENT(cx, obj) != parent) {
                 obj = js_CloneFunctionObject(cx, fun, parent);
                 if (!obj)
                     goto error;
             }
 
             TRACE_2(DefLocalFunSetSlot, slot, obj);
-
+            
             fp->slots[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. */
@@ -6049,17 +6074,17 @@ js_Interpret(JSContext *cx)
             JS_ASSERT(i == JSProto_Array || i == JSProto_Object);
             obj = (i == JSProto_Array)
                   ? js_NewArrayObject(cx, 0, NULL)
                   : js_NewObject(cx, &js_ObjectClass, NULL, NULL, 0);
             if (!obj)
                 goto error;
             PUSH_OPND(OBJECT_TO_JSVAL(obj));
             fp->sharpDepth++;
-            CHECK_INTERRUPT_HANDLER();
+            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(regs.sp - StackBase(fp) >= 1);
@@ -6415,17 +6440,17 @@ js_Interpret(JSContext *cx)
                     ok = JS_TRUE;
                     goto forced_return;
                   case JSTRAP_THROW:
                     cx->throwing = JS_TRUE;
                     cx->exception = rval;
                     goto error;
                   default:;
                 }
-                CHECK_INTERRUPT_HANDLER();
+                LOAD_INTERRUPT_HANDLER(cx);
             }
           }
           END_CASE(JSOP_DEBUGGER)
 #endif /* JS_HAS_DEBUGGER_KEYWORD */
 
 #if JS_HAS_XML_SUPPORT
           BEGIN_CASE(JSOP_DEFXMLNS)
             rval = POP();
@@ -6829,17 +6854,16 @@ js_Interpret(JSContext *cx)
           L_JSOP_TOATTRNAME:
           L_JSOP_QNAME:
           L_JSOP_QNAMECONST:
           L_JSOP_QNAMEPART:
           L_JSOP_ANYNAME:
           L_JSOP_DEFXMLNS:
 # endif
 
-          L_JSOP_UNUSED135:
           L_JSOP_UNUSED203:
           L_JSOP_UNUSED204:
           L_JSOP_UNUSED205:
           L_JSOP_UNUSED206:
           L_JSOP_UNUSED207:
           L_JSOP_UNUSED208:
           L_JSOP_UNUSED209:
           L_JSOP_UNUSED219:
@@ -6851,19 +6875,34 @@ js_Interpret(JSContext *cx)
           {
             char numBuf[12];
             JS_snprintf(numBuf, sizeof numBuf, "%d", op);
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                  JSMSG_BAD_BYTECODE, numBuf);
             goto error;
           }
 
+#ifdef JS_TRACER
+
+#if JS_THREADED_INTERP
+# define OPDEF(x,val,name,token,length,nuses,ndefs,prec,format)               \
+    R_##x: RECORD(x); goto L_##x;
+#else
+# define OPDEF(x,val,name,token,length,nuses,ndefs,prec,format)               \
+    case 256 + x: RECORD(x); op = x; switchOp = x; goto do_switch;
+#endif
+#include "jsopcode.tbl"
+#undef OPDEF
+
+#endif /* JS_TRACER */
+
 #if !JS_THREADED_INTERP
+
         } /* switch (op) */
-    } /* for (;;) */
+    }
 #endif /* !JS_THREADED_INTERP */
 
   error:
     if (fp->imacpc && cx->throwing) {
         // To keep things simple, we hard-code imacro exception handlers here.
         if (*fp->imacpc == JSOP_NEXTITER) {
             JS_ASSERT(*regs.pc == JSOP_CALL);
             if (js_ValueIsStopIteration(cx->exception)) {
@@ -6903,17 +6942,17 @@ js_Interpret(JSContext *cx)
                 fp->rval = rval;
                 ok = JS_TRUE;
                 goto forced_return;
               case JSTRAP_THROW:
                 cx->exception = rval;
               case JSTRAP_CONTINUE:
               default:;
             }
-            CHECK_INTERRUPT_HANDLER();
+            LOAD_INTERRUPT_HANDLER(cx);
         }
 
         /*
          * Look for a try block in script that can catch this exception.
          */
         if (script->trynotesOffset == 0)
             goto no_catch;
 
--- a/js/src/jsopcode.tbl
+++ b/js/src/jsopcode.tbl
@@ -100,22 +100,18 @@
  * argument lists, so they have the lowest precedence.
  *
  * This file is best viewed with 128 columns:
 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678
  */
 
 /* legend: op         val name          image       len use def prec  format */
 
-/*
- * Generic nop for the decompiler.
- */
-OPDEF(JSOP_NOP,       0,  "nop",        NULL,         1,  0,  0,  0,  JOF_BYTE)
-
 /* Longstanding JavaScript bytecodes. */
+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)
@@ -348,17 +344,20 @@ OPDEF(JSOP_SETCALL,     132, "setcall", 
 
 /*
  * Exception handling no-op, for more economical byte-coding than SRC_TRYFIN
  * srcnote-annotated JSOP_NOPs and to simply stack balance handling.
  */
 OPDEF(JSOP_TRY,         133,"try",        NULL,       1,  0,  0,  0,  JOF_BYTE)
 OPDEF(JSOP_FINALLY,     134,"finally",    NULL,       1,  0,  2,  0,  JOF_BYTE)
 
-OPDEF(JSOP_UNUSED135,   135,"unused135",  NULL,       1,  0,  0,  0,  JOF_BYTE)
+/*
+ * Generic nop for the decompiler.
+ */
+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/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -3829,107 +3829,70 @@ monitor_loop:
             return js_AttemptToExtendTree(cx, innermostNestedGuard, lr, NULL);
         return false;
       default:
         /* No, this was an unusual exit (i.e. out of memory/GC), so just resume interpretation. */
         return false;
     }
 }
 
-JS_REQUIRES_STACK JSMonitorRecordingStatus
-TraceRecorder::monitorRecording(JSOp op)
-{
-    if (lirbuf->outOMem()) {
+JS_REQUIRES_STACK bool
+js_MonitorRecording(TraceRecorder* tr)
+{
+    JSContext* cx = tr->cx;
+
+    if (tr->lirbuf->outOMem()) {
         js_AbortRecording(cx, "no more LIR memory");
         js_FlushJITCache(cx);
-        return JSMRS_STOP;
-    }
-
-    /* Process deepAbort() requests now. */
-    if (wasDeepAborted()) {
+        return false;
+    }
+
+    // Process deepAbort() requests now.
+    if (tr->wasDeepAborted()) {
         js_AbortRecording(cx, "deep abort requested");
-        return JSMRS_STOP;
-    }
-
-    if (walkedOutOfLoop()) {
-        if (!js_CloseLoop(cx))
-            return JSMRS_STOP;
-    } else {
-        // Clear one-shot state used to communicate between record_JSOP_CALL and post-
-        // opcode-case-guts record hook (record_FastNativeCallComplete).
-        pendingTraceableNative = NULL;
-
-        // In the future, handle dslots realloc by computing an offset from dslots instead.
-        if (global_dslots != globalObj->dslots) {
-            js_AbortRecording(cx, "globalObj->dslots reallocated");
-            return JSMRS_STOP;
+        return false;
+    }
+
+    if (tr->walkedOutOfLoop())
+        return js_CloseLoop(cx);
+
+    // Clear one-shot state used to communicate between record_JSOP_CALL and post-                                                                                            
+    // opcode-case-guts record hook (record_FastNativeCallComplete).
+    tr->pendingTraceableNative = NULL;
+
+    // In the future, handle dslots realloc by computing an offset from dslots instead.
+    if (tr->global_dslots != tr->globalObj->dslots) {
+        js_AbortRecording(cx, "globalObj->dslots reallocated");
+        return false;
+    }
+
+    jsbytecode* pc = cx->fp->regs->pc;
+
+    /* If we hit a break, end the loop and generate an always taken loop exit guard. For other
+       downward gotos (like if/else) continue recording. */
+    if (*pc == JSOP_GOTO || *pc == JSOP_GOTOX) {
+        jssrcnote* sn = js_GetSrcNote(cx->fp->script, pc);
+        if (sn && SN_TYPE(sn) == SRC_BREAK) {
+            AUDIT(breakLoopExits);
+            tr->endLoop(JS_TRACE_MONITOR(cx).fragmento);
+            js_DeleteRecorder(cx);
+            return false; /* done recording */
         }
-
-        jsbytecode* pc = cx->fp->regs->pc;
-
-        /* If we hit a break, end the loop and generate an always taken loop exit guard. For other
-           downward gotos (like if/else) continue recording. */
-        if (*pc == JSOP_GOTO || *pc == JSOP_GOTOX) {
-            jssrcnote* sn = js_GetSrcNote(cx->fp->script, pc);
-            if (sn && SN_TYPE(sn) == SRC_BREAK) {
-                AUDIT(breakLoopExits);
-                endLoop(JS_TRACE_MONITOR(cx).fragmento);
-                js_DeleteRecorder(cx);
-                return JSMRS_STOP; /* done recording */
-            }
-        }
-
-        /* An explicit return from callDepth 0 should end the loop, not abort it. */
-        if (*pc == JSOP_RETURN && callDepth == 0) {
-            AUDIT(returnLoopExits);
-            endLoop(JS_TRACE_MONITOR(cx).fragmento);
-            js_DeleteRecorder(cx);
-            return JSMRS_STOP; /* done recording */
-        }
+    }
+
+    /* An explicit return from callDepth 0 should end the loop, not abort it. */
+    if (*pc == JSOP_RETURN && tr->callDepth == 0) {
+        AUDIT(returnLoopExits);
+        tr->endLoop(JS_TRACE_MONITOR(cx).fragmento);
+        js_DeleteRecorder(cx);
+        return false; /* done recording */
     }
 
     /* If it's not a break or a return from a loop, continue recording and follow the trace. */
-
-    /* We check for imacro-calling bytecodes inside the switch cases to resolve
-       the "if" condition at the compile time. */
-    bool flag;
-    switch (op) {
-      default: goto abort_recording;
-# define OPDEF(x,val,name,token,length,nuses,ndefs,prec,format)               \
-        case x:                                                               \
-          flag = record_##x();                                                \
-          if (x == JSOP_ITER || x == JSOP_NEXTITER || x == JSOP_APPLY ||      \
-              JSOP_IS_BINARY(x) || x == JSOP_IS_UNARY(op)) {                  \
-              goto imacro;                                                    \
-          }                                                                   \
-        break;
-# include "jsopcode.tbl"
-# undef OPDEF
-    }
-
-    if (flag)
-        return JSMRS_CONTINUE;
-    goto abort_recording;
-
-  imacro:
-    /* We save macro-generated code size also via bool TraceRecorder::record_JSOP_*
-       return type, instead of a three-state: OK, ABORTED, IMACRO_STARTED. But the
-       price of this is the JSFRAME_IMACRO_START frame flag. We need one more bit
-       to detect that TraceRecorder::call_imacro was invoked by the record_JSOP_
-       method. */
-    if (flag)
-        return JSMRS_CONTINUE;
-    if (cx->fp->flags & JSFRAME_IMACRO_START) {
-        cx->fp->flags &= ~JSFRAME_IMACRO_START;
-        return JSMRS_IMACRO;
-    }
-
-  abort_recording:
-    js_AbortRecording(cx, js_CodeName[op]);
-    return JSMRS_STOP;
+    return true;
 }
 
 /* If used on a loop trace, blacklists the root peer instead of the given fragment. */
 void
 js_BlacklistPC(Fragmento* frago, Fragment* frag)
 {
     if (frag->kind == LoopTrace)
         frag = frago->getLoop(frag->ip);
@@ -5536,16 +5499,22 @@ TraceRecorder::record_LeaveFrame()
     // LeaveFrame gets called after the interpreter popped the frame and
     // stored rval, so cx->fp not cx->fp->down, and -1 not 0.
     atoms = cx->fp->script->atomMap.vector;
     set(&stackval(-1), rval_ins, true);
     return true;
 }
 
 JS_REQUIRES_STACK bool
+TraceRecorder::record_JSOP_INTERRUPT()
+{
+    return false;
+}
+
+JS_REQUIRES_STACK bool
 TraceRecorder::record_JSOP_PUSH()
 {
     stack(0, INS_CONST(JSVAL_TO_BOOLEAN(JSVAL_VOID)));
     return true;
 }
 
 JS_REQUIRES_STACK bool
 TraceRecorder::record_JSOP_POPV()
@@ -6861,17 +6830,17 @@ TraceRecorder::record_FastNativeCallComp
       default:
         /* Convert the result to double if the builtin returns int32. */
         if (JSVAL_IS_NUMBER(v) &&
             (pendingTraceableNative->builtin->_argtypes & 3) == nanojit::ARGSIZE_LO) {
             set(&v, lir->ins1(LIR_i2f, v_ins));
         }
     }
 
-    // We'll null pendingTraceableNative in monitorRecording, on the next op cycle.
+    // We'll null pendingTraceableNative in js_MonitorRecording, on the next op cycle.
     // There must be a next op since the stack is non-empty.
     return ok;
 }
 
 JS_REQUIRES_STACK bool
 TraceRecorder::name(jsval*& vp)
 {
     JSObject* obj = cx->fp->scopeChain;
@@ -8650,17 +8619,16 @@ InitIMacroCode()
 
 #define UNUSED(n)                                                             \
     JS_REQUIRES_STACK bool                                                    \
     TraceRecorder::record_JSOP_UNUSED##n() {                                  \
         JS_NOT_REACHED("JSOP_UNUSED" # n);                                    \
         return false;                                                         \
     }
 
-UNUSED(135)
 UNUSED(203)
 UNUSED(204)
 UNUSED(205)
 UNUSED(206)
 UNUSED(207)
 UNUSED(208)
 UNUSED(209)
 UNUSED(219)
--- a/js/src/jstracer.h
+++ b/js/src/jstracer.h
@@ -256,22 +256,16 @@ struct FrameInfo {
         struct {
             uint16  spdist;     // distance from fp->slots to fp->regs->sp at JSOP_CALL
             uint16  argc;       // actual argument count, may be < fun->nargs
         } s;
         uint32      word;       // for spdist/argc LIR store in record_JSOP_CALL
     };
 };
 
-enum JSMonitorRecordingStatus {
-    JSMRS_CONTINUE,
-    JSMRS_STOP,
-    JSMRS_IMACRO
-};
-
 class TraceRecorder : public avmplus::GCObject {
     JSContext*              cx;
     JSTraceMonitor*         traceMonitor;
     JSObject*               globalObj;
     Tracker                 tracker;
     Tracker                 nativeFrameTracker;
     char*                   entryTypeMap;
     unsigned                callDepth;
@@ -317,17 +311,16 @@ class TraceRecorder : public avmplus::GC
                                   unsigned callDepth, uint8* globalTypeMap, uint8* stackTypeMap);
     void trackNativeStackUse(unsigned slots);
 
     JS_REQUIRES_STACK bool lazilyImportGlobalSlot(unsigned slot);
 
     JS_REQUIRES_STACK nanojit::LIns* guard(bool expected, nanojit::LIns* cond,
                                            ExitType exitType);
     nanojit::LIns* guard(bool expected, nanojit::LIns* cond, nanojit::LIns* exit);
-
     nanojit::LIns* addName(nanojit::LIns* ins, const char* name);
 
     JS_REQUIRES_STACK nanojit::LIns* get(jsval* p) const;
     nanojit::LIns* writeBack(nanojit::LIns* i, nanojit::LIns* base, ptrdiff_t offset);
     JS_REQUIRES_STACK void set(jsval* p, nanojit::LIns* l, bool initializing = false);
 
     JS_REQUIRES_STACK bool checkType(jsval& v, uint8 t, jsval*& stage_val,
                                      nanojit::LIns*& stage_ins, unsigned& stage_count);
@@ -426,24 +419,24 @@ class TraceRecorder : public avmplus::GC
     JS_REQUIRES_STACK void trackCfgMerges(jsbytecode* pc);
     JS_REQUIRES_STACK void flipIf(jsbytecode* pc, bool& cond);
     JS_REQUIRES_STACK void fuseIf(jsbytecode* pc, bool cond, nanojit::LIns* x);
 
     bool hasMethod(JSObject* obj, jsid id);
     bool hasIteratorMethod(JSObject* obj);
 
 public:
+    friend JS_REQUIRES_STACK bool js_MonitorRecording(TraceRecorder* tr);
+
     JS_REQUIRES_STACK
     TraceRecorder(JSContext* cx, VMSideExit*, nanojit::Fragment*, TreeInfo*,
                   unsigned ngslots, uint8* globalTypeMap, uint8* stackTypeMap, 
                   VMSideExit* expectedInnerExit, nanojit::Fragment* outerToBlacklist);
     ~TraceRecorder();
 
-    JS_REQUIRES_STACK JSMonitorRecordingStatus monitorRecording(JSOp op);
-
     JS_REQUIRES_STACK uint8 determineSlotType(jsval* vp) const;
     JS_REQUIRES_STACK nanojit::LIns* snapshot(ExitType exitType);
     nanojit::Fragment* getFragment() const { return fragment; }
     JS_REQUIRES_STACK bool isLoopHeader(JSContext* cx) const;
     JS_REQUIRES_STACK void compile(nanojit::Fragmento* fragmento);
     JS_REQUIRES_STACK bool closeLoop(nanojit::Fragmento* fragmento, bool& demote,
                                      unsigned *demotes);
     JS_REQUIRES_STACK void endLoop(nanojit::Fragmento* fragmento);
@@ -483,36 +476,68 @@ public:
 };
 #define TRACING_ENABLED(cx)       JS_HAS_OPTION(cx, JSOPTION_JIT)
 #define TRACE_RECORDER(cx)        (JS_TRACE_MONITOR(cx).recorder)
 #define SET_TRACE_RECORDER(cx,tr) (JS_TRACE_MONITOR(cx).recorder = (tr))
 
 #define JSOP_IS_BINARY(op) ((uintN)((op) - JSOP_BITOR) <= (uintN)(JSOP_MOD - JSOP_BITOR))
 #define JSOP_IS_UNARY(op) ((uintN)((op) - JSOP_NEG) <= (uintN)(JSOP_POS - JSOP_NEG))
 
-#define TRACE_ARGS_(x,args)                                                   \
+/*
+ * See jsinterp.cpp for the ENABLE_TRACER definition. Also note how comparing x
+ * to JSOP_* constants specializes trace-recording code at compile time either
+ * to include imacro support, or exclude it altogether for this particular x.
+ *
+ * We save macro-generated code size also via bool TraceRecorder::record_JSOP_*
+ * return type, instead of a three-state: OK, ABORTED, IMACRO_STARTED. But the
+ * price of this is the JSFRAME_IMACRO_START frame flag. We need one more bit
+ * to detect that TraceRecorder::call_imacro was invoked by the record_JSOP_*
+ * method invoked by TRACE_ARGS_.
+ */
+#define RECORD_ARGS(x,args)                                                   \
+    JS_BEGIN_MACRO                                                            \
+        if (!js_MonitorRecording(TRACE_RECORDER(cx))) {                       \
+            ENABLE_TRACER(0);                                                 \
+        } else {                                                              \
+            TRACE_ARGS_(x, args,                                              \
+                if ((fp->flags & JSFRAME_IMACRO_START) &&                     \
+                    (x == JSOP_ITER || x == JSOP_NEXTITER ||                  \
+                     x == JSOP_APPLY || JSOP_IS_BINARY(x) ||                  \
+                     JSOP_IS_UNARY(op))) {                                    \
+                    fp->flags &= ~JSFRAME_IMACRO_START;                       \
+                    atoms = COMMON_ATOMS_START(&rt->atomState);               \
+                    op = JSOp(*regs.pc);                                      \
+                    DO_OP();                                                  \
+                }                                                             \
+            );                                                                \
+         }                                                                    \
+    JS_END_MACRO
+
+#define TRACE_ARGS_(x,args,onfalse)                                           \
     JS_BEGIN_MACRO                                                            \
         TraceRecorder* tr_ = TRACE_RECORDER(cx);                              \
-        if (tr_ && !tr_->record_##x args)                                     \
+        if (tr_ && !tr_->record_##x args) {                                   \
+            onfalse                                                           \
             js_AbortRecording(cx, #x);                                        \
+            ENABLE_TRACER(0);                                                 \
+        }                                                                     \
     JS_END_MACRO
 
-#define TRACE_ARGS(x,args)      TRACE_ARGS_(x, args)
+#define TRACE_ARGS(x,args)      TRACE_ARGS_(x, args, )
+
+#define RECORD(x)               RECORD_ARGS(x, ())
 #define TRACE_0(x)              TRACE_ARGS(x, ())
 #define TRACE_1(x,a)            TRACE_ARGS(x, (a))
 #define TRACE_2(x,a,b)          TRACE_ARGS(x, (a, b))
 
 extern JS_REQUIRES_STACK bool
 js_MonitorLoopEdge(JSContext* cx, uintN& inlineCallCount);
 
-#ifdef DEBUG
-# define js_AbortRecording(cx, reason) js_AbortRecordingImpl(cx, reason)
-#else
-# define js_AbortRecording(cx, reason) js_AbortRecordingImpl(cx)
-#endif
+extern JS_REQUIRES_STACK bool
+js_MonitorRecording(TraceRecorder *tr);
 
 extern JS_REQUIRES_STACK void
 js_AbortRecording(JSContext* cx, const char* reason);
 
 extern void
 js_InitJIT(JSTraceMonitor *tm);
 
 extern void
@@ -521,15 +546,16 @@ js_FinishJIT(JSTraceMonitor *tm);
 extern void
 js_FlushJITCache(JSContext* cx);
 
 extern void
 js_FlushJITOracle(JSContext* cx);
 
 #else  /* !JS_TRACER */
 
+#define RECORD(x)               ((void)0)
 #define TRACE_0(x)              ((void)0)
 #define TRACE_1(x,a)            ((void)0)
 #define TRACE_2(x,a,b)          ((void)0)
 
 #endif /* !JS_TRACER */
 
 #endif /* jstracer_h___ */
--- a/js/src/jsxdrapi.h
+++ b/js/src/jsxdrapi.h
@@ -199,17 +199,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 - 39)
+#define JSXDR_BYTECODE_VERSION      (0xb973c0de - 38)
 
 /*
  * Library-private functions.
  */
 extern JSBool
 js_XDRAtom(JSXDRState *xdr, JSAtom **atomp);
 
 extern JSBool