Bug 519004 - make deep abort danger more clear and present (r=dvander)
authorLuke Wagner <lw@mozilla.com>
Mon, 28 Sep 2009 09:03:21 -0700
changeset 33542 b7efeb401993939401c76e5448184948b02a3ea2
parent 33541 fb92e8e990cedcf31eb83c7393c0c7ad120b04fc
child 33544 33c00f847d8987d99bfde614defd82ec55bced46
push idunknown
push userunknown
push dateunknown
reviewersdvander
bugs519004
milestone1.9.3a1pre
Bug 519004 - make deep abort danger more clear and present (r=dvander)
js/src/jsops.cpp
js/src/jstracer.cpp
js/src/jstracer.h
--- a/js/src/jsops.cpp
+++ b/js/src/jsops.cpp
@@ -71,32 +71,34 @@
                   default:;
                 }
                 moreInterrupts = true;
             }
 
 #ifdef JS_TRACER
             TraceRecorder* tr = TRACE_RECORDER(cx);
             if (tr) {
-                JSRecordingStatus status = TraceRecorder::monitorRecording(cx, tr, op);
+                AbortableRecordingStatus status = TraceRecorder::monitorRecording(cx, tr, op);
                 switch (status) {
-                case JSRS_CONTINUE:
+                  case ARECORD_CONTINUE:
                     moreInterrupts = true;
                     break;
-                case JSRS_IMACRO:
+                  case ARECORD_IMACRO:
                     atoms = COMMON_ATOMS_START(&rt->atomState);
                     op = JSOp(*regs.pc);
                     DO_OP();    /* keep interrupting for op. */
                     break;
-                case JSRS_ERROR:
+                  case ARECORD_ERROR:
                     // The code at 'error:' aborts the recording.
                     goto error;
-                case JSRS_STOP:
+                  case ARECORD_ABORTED:
                     break;
-                default:
+                  case ARECORD_STOP:
+                    /* A 'stop' error should have already aborted recording. */
+                  default:
                     JS_NOT_REACHED("Bad recording status");
                 }
             }
 #endif /* !JS_TRACER */
 
 #if JS_THREADED_INTERP
 #ifdef MOZ_TRACEVIS
             if (!moreInterrupts)
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -80,24 +80,29 @@
 #include "jsscriptinlines.h"
 
 #include "jsautooplen.h"        // generated headers last
 #include "imacros.c.out"
 
 using namespace nanojit;
 
 #if JS_HAS_XML_SUPPORT
-#define ABORT_IF_XML(v)                                                       \
+#define RETURN_VALUE_IF_XML(val, ret)                                         \
     JS_BEGIN_MACRO                                                            \
-    if (!JSVAL_IS_PRIMITIVE(v) && OBJECT_IS_XML(BOGUS_CX, JSVAL_TO_OBJECT(v)))\
-        ABORT_TRACE("xml detected");                                          \
+        if (!JSVAL_IS_PRIMITIVE(val) &&                                       \
+            OBJECT_IS_XML(BOGUS_CX, JSVAL_TO_OBJECT(val))) {                  \
+            RETURN_VALUE("xml detected", ret);                                \
+        }                                                                     \
     JS_END_MACRO
 #else
-#define ABORT_IF_XML(v) ((void) 0)
-#endif
+#define RETURN_IF_XML(val, ret) ((void) 0)
+#endif
+
+#define RETURN_IF_XML_A(val) RETURN_VALUE_IF_XML(val, ARECORD_STOP)
+#define RETURN_IF_XML(val)   RETURN_VALUE_IF_XML(val, RECORD_STOP)
 
 /*
  * Never use JSVAL_IS_BOOLEAN because it restricts the value (true, false) and
  * the type. What you want to use is JSVAL_IS_SPECIAL(x) and then handle the
  * undefined case properly (bug 457363).
  */
 #undef JSVAL_IS_BOOLEAN
 #define JSVAL_IS_BOOLEAN(x) JS_STATIC_ASSERT(0)
@@ -149,33 +154,42 @@ static const char tagChar[]  = "OIDISIBI
      MAX_CALL_STACK_ENTRIES * sizeof(JSInlineFrame) +                         \
      sizeof(JSInlineFrame)) /* possibly slow native frame at top of stack */
 
 /* Max number of branches per tree. */
 #define MAX_BRANCHES 32
 
 #define CHECK_STATUS(expr)                                                    \
     JS_BEGIN_MACRO                                                            \
-        JSRecordingStatus _status = (expr);                                   \
-        if (_status != JSRS_CONTINUE)                                         \
+        RecordingStatus _status = (expr);                                     \
+        if (_status != RECORD_CONTINUE)                                       \
+          return _status;                                                     \
+    JS_END_MACRO
+
+#define CHECK_STATUS_A(expr)                                                  \
+    JS_BEGIN_MACRO                                                            \
+        AbortableRecordingStatus _status = InjectStatus((expr));              \
+        if (_status != ARECORD_CONTINUE)                                      \
           return _status;                                                     \
     JS_END_MACRO
 
 #ifdef JS_JIT_SPEW
-#define ABORT_TRACE_RV(msg, value)                                            \
+#define RETURN_VALUE(msg, value)                                              \
     JS_BEGIN_MACRO                                                            \
-        debug_only_printf(LC_TMAbort, "abort: %d: %s\n", __LINE__, (msg));    \
+        debug_only_printf(LC_TMAbort, "trace stopped: %d: %s\n", __LINE__, (msg)); \
         return (value);                                                       \
     JS_END_MACRO
 #else
-#define ABORT_TRACE_RV(msg, value)   return (value)
-#endif
-
-#define ABORT_TRACE(msg)         ABORT_TRACE_RV(msg, JSRS_STOP)
-#define ABORT_TRACE_ERROR(msg)   ABORT_TRACE_RV(msg, JSRS_ERROR)
+#define RETURN_VALUE(msg, value)   return (value)
+#endif
+
+#define RETURN_STOP(msg)     RETURN_VALUE(msg, RECORD_STOP)
+#define RETURN_STOP_A(msg)   RETURN_VALUE(msg, ARECORD_STOP)
+#define RETURN_ERROR(msg)    RETURN_VALUE(msg, RECORD_ERROR)
+#define RETURN_ERROR_A(msg)  RETURN_VALUE(msg, ARECORD_ERROR)
 
 #ifdef JS_JIT_SPEW
 struct __jitstats {
 #define JITSTAT(x) uint64 x;
 #include "jitstats.tbl"
 #undef JITSTAT
 } jitstats = { 0LL, };
 
@@ -1169,16 +1183,17 @@ Blacklist(jsbytecode* pc)
     AUDIT(blacklisted);
     JS_ASSERT(*pc == JSOP_TRACE || *pc == JSOP_NOP);
     *pc = JSOP_NOP;
 }
 
 static void
 Backoff(JSContext *cx, jsbytecode* pc, Fragment* tree = NULL)
 {
+    /* N.B. This code path cannot assume the recorder is/is not alive. */
     JSDHashTable *table = &JS_TRACE_MONITOR(cx).recordAttempts;
 
     if (table->ops) {
         PCHashEntry *entry = (PCHashEntry *)
             JS_DHashTableOperate(table, pc, JS_DHASH_ADD);
 
         if (entry) {
             if (!entry->key) {
@@ -3419,29 +3434,29 @@ TraceRecorder::import(TreeInfo* treeInfo
 
 JS_REQUIRES_STACK bool
 TraceRecorder::isValidSlot(JSScope* scope, JSScopeProperty* sprop)
 {
     uint32 setflags = (js_CodeSpec[*cx->fp->regs->pc].format & (JOF_SET | JOF_INCDEC | JOF_FOR));
 
     if (setflags) {
         if (!SPROP_HAS_STUB_SETTER(sprop))
-            ABORT_TRACE_RV("non-stub setter", false);
+            RETURN_VALUE("non-stub setter", false);
         if (sprop->attrs & JSPROP_READONLY)
-            ABORT_TRACE_RV("writing to a read-only property", false);
+            RETURN_VALUE("writing to a read-only property", false);
     }
 
     /* This check applies even when setflags == 0. */
     if (setflags != JOF_SET && !SPROP_HAS_STUB_GETTER(sprop)) {
         JS_ASSERT(!sprop->isMethod());
-        ABORT_TRACE_RV("non-stub getter", false);
+        RETURN_VALUE("non-stub getter", false);
     }
 
     if (!SPROP_HAS_VALID_SLOT(sprop, scope))
-        ABORT_TRACE_RV("slotless obj property", false);
+        RETURN_VALUE("slotless obj property", false);
 
     return true;
 }
 
 /* Lazily import a global slot if we don't already have it in the tracker. */
 JS_REQUIRES_STACK bool
 TraceRecorder::lazilyImportGlobalSlot(unsigned slot)
 {
@@ -4079,46 +4094,46 @@ ResetJIT(JSContext* cx, TraceVisFlushRea
 
 JS_REQUIRES_STACK void
 js_ResetJIT(JSContext* cx)
 {
     ResetJIT(cx, FR_OOM);
 }
 
 /* Compile the current fragment. */
-JS_REQUIRES_STACK bool
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::compile(JSTraceMonitor* tm)
 {
 #ifdef MOZ_TRACEVIS
     TraceVisStateObj tvso(cx, S_COMPILE);
 #endif
 
     if (tm->needFlush) {
         ResetJIT(cx, FR_DEEP_BAIL);
-        return false;
+        return ARECORD_ABORTED;
     }
     if (treeInfo->maxNativeStackSlots >= MAX_NATIVE_STACK_SLOTS) {
         debug_only_print0(LC_TMTracer, "Blacklist: excessive stack use.\n");
         Blacklist((jsbytecode*) fragment->root->ip);
-        return false;
+        return ARECORD_STOP;
     }
     if (anchor && anchor->exitType != CASE_EXIT)
         ++treeInfo->branchCount;
     if (outOfMemory())
-        return false;
+        return ARECORD_STOP;
 
     Assembler *assm = tm->assembler;
     nanojit::compile(assm, fragment verbose_only(, tempAlloc, tm->labels));
     if (outOfMemory())
-        return false;
+        return ARECORD_STOP;
 
     if (assm->error() != nanojit::None) {
         debug_only_print0(LC_TMTracer, "Blacklisted: error during compilation\n");
         Blacklist((jsbytecode*) fragment->root->ip);
-        return false;
+        return ARECORD_STOP;
     }
     ResetRecordingAttempts(cx, (jsbytecode*) fragment->ip);
     ResetRecordingAttempts(cx, (jsbytecode*) fragment->root->ip);
     if (anchor) {
 #ifdef NANOJIT_IA32
         if (anchor->exitType == CASE_EXIT)
             assm->patch(anchor, anchor->switchInfo);
         else
@@ -4135,17 +4150,17 @@ TraceRecorder::compile(JSTraceMonitor* t
     const char* filename = cx->fp->script->filename;
     char* label = (char*)js_malloc((filename ? strlen(filename) : 7) + 16);
     sprintf(label, "%s:%u", filename ? filename : "<stdin>",
             js_FramePCToLineNumber(cx, cx->fp));
     tm->labels->add(fragment, sizeof(Fragment), 0, label);
     js_free(label);
 #endif
     AUDIT(traceCompleted);
-    return true;
+    return ARECORD_CONTINUE;
 }
 
 static void
 JoinPeers(Assembler* assm, VMSideExit* exit, VMFragment* target)
 {
     exit->target = target;
     assm->patch(exit);
 
@@ -4386,45 +4401,47 @@ TraceRecorder::peerTypeStability(SlotMap
         }
         if (consensus == TypeConsensus_Undemotes)
             onlyUndemotes = true;
     }
 
     return onlyUndemotes ? TypeConsensus_Undemotes : TypeConsensus_Bad;
 }
 
-JS_REQUIRES_STACK bool
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::closeLoop(TypeConsensus &consensus)
 {
     DefaultSlotMap slotMap(*this);
     VisitSlots(slotMap, cx, 0, *treeInfo->globalSlots);
     return closeLoop(slotMap, snapshot(UNSTABLE_LOOP_EXIT), consensus);
 }
 
-/* Complete and compile a trace and link it to the existing tree if appropriate.
- * Returns true if something was compiled. Outparam is always set.
+/*
+ * Complete and compile a trace and link it to the existing tree if
+ * appropriate.  Returns ARECORD_ABORTED or ARECORD_STOP, depending on whether
+ * the recorder was deleted. Outparam is always set.
  */
-JS_REQUIRES_STACK bool
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::closeLoop(SlotMap& slotMap, VMSideExit* exit, TypeConsensus& consensus)
 {
     /*
      * We should have arrived back at the loop header, and hence we don't want
      * to be in an imacro here and the opcode should be either JSOP_TRACE or, in
      * case this loop was blacklisted in the meantime, JSOP_NOP.
      */
     JS_ASSERT((*cx->fp->regs->pc == JSOP_TRACE || *cx->fp->regs->pc == JSOP_NOP) &&
               !cx->fp->imacpc);
 
     if (callDepth != 0) {
         debug_only_print0(LC_TMTracer,
                           "Blacklisted: stack depth mismatch, possible recursion.\n");
         Blacklist((jsbytecode*) fragment->root->ip);
         trashSelf = true;
         consensus = TypeConsensus_Bad;
-        return false;
+        return ARECORD_STOP;
     }
 
     JS_ASSERT(exit->exitType == UNSTABLE_LOOP_EXIT);
     JS_ASSERT(exit->numStackSlots == treeInfo->nStackTypes);
 
     VMFragment* peer = NULL;
     VMFragment* root = (VMFragment*)fragment->root;
 
@@ -4488,18 +4505,18 @@ TraceRecorder::closeLoop(SlotMap& slotMa
         if (loopLabel) {
             lir->insBranch(LIR_j, NULL, loopLabel);
             lir->ins1(LIR_live, lirbuf->state);
         }
 
         exit->target = fragment->root;
         fragment->lastIns = lir->insGuard(LIR_x, NULL, createGuardRecord(exit));
     }
-    if (!compile(traceMonitor))
-        return false;
+
+    CHECK_STATUS_A(compile(traceMonitor));
 
     debug_only_printf(LC_TMTreeVis, "TREEVIS CLOSELOOP EXIT=%p PEER=%p\n", (void*)exit, (void*)peer);
 
     peer = getLoop(traceMonitor, root->ip, root->globalObj, root->globalShape, root->argc);
     JS_ASSERT(peer);
     joinEdgesToEntry(peer);
 
     debug_only_stmt(DumpPeerStability(traceMonitor, peer->ip, peer->globalObj,
@@ -4521,17 +4538,18 @@ TraceRecorder::closeLoop(SlotMap& slotMa
                       "Recording completed at  %s:%u@%u via closeLoop (FragID=%06u)\n",
                       cx->fp->script->filename,
                       js_FramePCToLineNumber(cx, cx->fp),
                       FramePCOffset(cx->fp),
                       fragment->profFragID);
     debug_only_print0(LC_TMMinimal, "\n");
 #endif
 
-    return true;
+    /* recording complete. */
+    return ARECORD_STOP;
 }
 
 static void
 FullMapFromExit(TypeMap& typeMap, VMSideExit* exit)
 {
     typeMap.setLength(0);
     typeMap.fromRaw(exit->stackTypeMap(), exit->numStackSlots);
     typeMap.fromRaw(exit->globalTypeMap(), exit->numGlobalSlots);
@@ -4617,37 +4635,37 @@ TraceRecorder::joinEdgesToEntry(VMFragme
                     return;
                 }
                 uexit = uexit->next;
             }
         }
     }
 }
 
-JS_REQUIRES_STACK void
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::endLoop()
 {
-    endLoop(snapshot(LOOP_EXIT));
+    return endLoop(snapshot(LOOP_EXIT));
 }
 
 /* Emit an always-exit guard and compile the tree (used for break statements. */
-JS_REQUIRES_STACK void
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::endLoop(VMSideExit* exit)
 {
     if (callDepth != 0) {
         debug_only_print0(LC_TMTracer, "Blacklisted: stack depth mismatch, possible recursion.\n");
         Blacklist((jsbytecode*) fragment->root->ip);
         trashSelf = true;
-        return;
+        return ARECORD_STOP;
     }
 
     fragment->lastIns =
         lir->insGuard(LIR_x, NULL, createGuardRecord(exit));
-    if (!compile(traceMonitor))
-        return;
+
+    CHECK_STATUS_A(compile(traceMonitor));
 
     debug_only_printf(LC_TMTreeVis, "TREEVIS ENDLOOP EXIT=%p\n", (void*)exit);
 
     VMFragment* root = (VMFragment*)fragment->root;
     joinEdgesToEntry(getLoop(traceMonitor,
                              root->ip,
                              root->globalObj,
                              root->globalShape,
@@ -4674,16 +4692,19 @@ TraceRecorder::endLoop(VMSideExit* exit)
     debug_only_printf(LC_TMMinimal,
                       "Recording completed at  %s:%u@%u via endLoop (FragID=%06u)\n",
                       cx->fp->script->filename,
                       js_FramePCToLineNumber(cx, cx->fp),
                       FramePCOffset(cx->fp),
                       fragment->profFragID);
     debug_only_print0(LC_TMTracer, "\n");
 #endif
+
+    /* recording complete */
+    return ARECORD_STOP;
 }
 
 /* Emit code to adjust the stack to match the inner tree's stack expectations. */
 JS_REQUIRES_STACK void
 TraceRecorder::prepareTreeCall(VMFragment* inner)
 {
     TreeInfo* ti = (TreeInfo*)inner->vmprivate;
     inner_sp_ins = lirbuf->sp;
@@ -4883,17 +4904,17 @@ TraceRecorder::fuseIf(jsbytecode* pc, bo
     if (*pc == JSOP_IFEQ || *pc == JSOP_IFNE) {
         emitIf(pc, cond, x);
         if (*pc == JSOP_IFEQ)
             trackCfgMerges(pc);
     }
 }
 
 /* Check whether we have reached the end of the trace. */
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::checkTraceEnd(jsbytecode *pc)
 {
     if (IsLoopEdge(pc, (jsbytecode*)fragment->root->ip)) {
         /*
          * If we compile a loop, the trace should have a zero stack balance at
          * the loop edge. Currently we are parked on a comparison op or
          * IFNE/IFEQ, so advance pc to the loop header and adjust the stack
          * pointer and pretend we have reached the loop header.
@@ -4902,25 +4923,25 @@ TraceRecorder::checkTraceEnd(jsbytecode 
             JS_ASSERT(!cx->fp->imacpc && (pc == cx->fp->regs->pc || pc == cx->fp->regs->pc + 1));
             bool fused = pc != cx->fp->regs->pc;
             JSFrameRegs orig = *cx->fp->regs;
 
             cx->fp->regs->pc = (jsbytecode*)fragment->root->ip;
             cx->fp->regs->sp -= fused ? 2 : 1;
 
             TypeConsensus consensus;
-            closeLoop(consensus);
+            AbortableRecordingStatus ars = closeLoop(consensus);
 
             *cx->fp->regs = orig;
+            return ars;
         } else {
-            endLoop();
-        }
-        return JSRS_STOP;
-    }
-    return JSRS_CONTINUE;
+            return endLoop();
+        }
+    }
+    return ARECORD_CONTINUE;
 }
 
 bool
 TraceRecorder::hasMethod(JSObject* obj, jsid id)
 {
     if (!obj)
         return false;
 
@@ -5395,24 +5416,20 @@ RecordTree(JSContext* cx, JSTraceMonitor
     JS_ASSERT(entryNativeStackSlots == NativeStackSlots(cx, 0 /* callDepth */));
     ti->nativeStackBase = (entryNativeStackSlots -
             (cx->fp->regs->sp - StackBase(cx->fp))) * sizeof(double);
     ti->maxNativeStackSlots = entryNativeStackSlots;
     ti->maxCallDepth = 0;
     ti->script = cx->fp->script;
 
     /* Recording primary trace. */
-    if (!StartRecorder(cx, NULL, f, ti,
-                       ti->nStackTypes,
-                       ti->globalSlots->length(),
-                       ti->typeMap.data(), NULL, outer, outerArgc)) {
-        return false;
-    }
-
-    return true;
+    return StartRecorder(cx, NULL, f, ti,
+                         ti->nStackTypes,
+                         ti->globalSlots->length(),
+                         ti->typeMap.data(), NULL, outer, outerArgc);
 }
 
 static JS_REQUIRES_STACK TypeConsensus
 FindLoopEdgeTarget(JSContext* cx, VMSideExit* exit, VMFragment** peerp)
 {
     VMFragment* from = exit->root();
     TreeInfo* from_ti = from->getTreeInfo();
 
@@ -6668,26 +6685,26 @@ js_MonitorLoopEdge(JSContext* cx, uintN&
          */
 #ifdef MOZ_TRACEVIS
         tvso.r = R_OTHER_EXIT;
 #endif
         return false;
     }
 }
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::monitorRecording(JSContext* cx, TraceRecorder* tr, JSOp op)
 {
     Assembler *assm = JS_TRACE_MONITOR(cx).assembler;
     JSTraceMonitor &localtm = JS_TRACE_MONITOR(cx);
 
     /* Process needFlush requests now. */
     if (localtm.needFlush) {
         ResetJIT(cx, FR_DEEP_BAIL);
-        return JSRS_STOP;
+        return ARECORD_ABORTED;
     }
     JS_ASSERT(!tr->fragment->lastIns);
 
     /*
      * Clear one-shot state used to communicate between record_JSOP_CALL and post-
      * opcode-case-guts record hook (record_NativeCallComplete).
      */
     tr->pendingSpecializedNative = NULL;
@@ -6718,70 +6735,71 @@ TraceRecorder::monitorRecording(JSContex
 
     /*
      * If op is not a break or a return from a loop, continue recording and
      * follow the trace. We check for imacro-calling bytecodes inside each
      * switch case to resolve the if (JSOP_IS_IMACOP(x)) conditions at compile
      * time.
      */
 
-    JSRecordingStatus status;
+    AbortableRecordingStatus status;
 #ifdef DEBUG
     bool wasInImacro = (cx->fp->imacpc != NULL);
 #endif
     switch (op) {
       default:
-          status = JSRS_ERROR;
+          status = ARECORD_ERROR;
           goto stop_recording;
 # define OPDEF(x,val,name,token,length,nuses,ndefs,prec,format)               \
       case x:                                                                 \
         status = tr->record_##x();                                            \
         if (JSOP_IS_IMACOP(x))                                                \
             goto imacro;                                                      \
         break;
 # include "jsopcode.tbl"
 # undef OPDEF
     }
 
-    /* record_JSOP_X can reenter the interpreter and kill |tr|. */
+    /* record_JSOP_* can reenter the interpreter and kill |tr|. */
     if (!localtm.recorder)
-        return JSRS_STOP;
-
-    JS_ASSERT(status != JSRS_IMACRO);
+        return ARECORD_ABORTED;
+
+    JS_ASSERT(status != ARECORD_IMACRO);
     JS_ASSERT_IF(!wasInImacro, cx->fp->imacpc == NULL);
 
     if (assm->error()) {
         js_AbortRecording(cx, "error during recording");
-        return JSRS_STOP;
+        return ARECORD_ABORTED;
     }
 
     if (tr->outOfMemory() || js_OverfullJITCache(&localtm)) {
         js_AbortRecording(cx, "no more memory");
         ResetJIT(cx, FR_OOM);
-        return JSRS_STOP;
+        return ARECORD_ABORTED;
     }
 
   imacro:
-    /* record_JSOP_X can reenter the interpreter and kill |tr|. */
+    /* record_JSOP_* can reenter the interpreter and kill |tr|. */
     if (!localtm.recorder)
-        return JSRS_STOP;
-
-    if (!STATUS_ABORTS_RECORDING(status))
+        return ARECORD_ABORTED;
+
+    if (!StatusAbortsRecording(status))
         return status;
 
   stop_recording:
     /* If we recorded the end of the trace, destroy the recorder now. */
     if (tr->fragment->lastIns) {
+        JS_ASSERT(status == ARECORD_STOP);
         DeleteRecorder(cx);
-        return status;
-    }
-
-    /* Looks like we encountered an error condition. Abort recording. */
+        return ARECORD_ABORTED;
+    }
+
+    /* We encountered an error, abort recording. */
     js_AbortRecording(cx, js_CodeName[op]);
-    return status;
+    return ARECORD_ABORTED;
 }
 
 JS_REQUIRES_STACK void
 js_AbortRecording(JSContext* cx, const char* reason)
 {
     JSTraceMonitor* tm = &JS_TRACE_MONITOR(cx);
     JS_ASSERT(tm->recorder != NULL);
 
@@ -7476,97 +7494,97 @@ TraceRecorder::frameIfInRange(JSObject* 
     return NULL;
 }
 
 JS_DEFINE_CALLINFO_4(extern, UINT32, GetClosureVar, CONTEXT, OBJECT, CVIPTR, DOUBLEPTR, 0, 0)
 JS_DEFINE_CALLINFO_4(extern, UINT32, GetClosureArg, CONTEXT, OBJECT, CVIPTR, DOUBLEPTR, 0, 0)
 
 /*
  * Search the scope chain for a property lookup operation at the current PC and
- * generate LIR to access the given property. Return JSRS_CONTINUE on success,
- * otherwise abort and return JSRS_STOP. There are 3 outparams:
+ * generate LIR to access the given property. Return RECORD_CONTINUE on success,
+ * otherwise abort and return RECORD_STOP. There are 3 outparams:
  *
  *     vp           the address of the current property value
  *     ins          LIR instruction representing the property value on trace
  *     NameResult   describes how to look up name; see comment for NameResult in jstracer.h
  */
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::scopeChainProp(JSObject* obj, jsval*& vp, LIns*& ins, NameResult& nr)
 {
     JS_ASSERT(obj != globalObj);
 
     JSTraceMonitor &localtm = *traceMonitor;
 
     JSAtom* atom = atoms[GET_INDEX(cx->fp->regs->pc)];
     JSObject* obj2;
     JSProperty* prop;
     bool ok = js_FindProperty(cx, ATOM_TO_JSID(atom), &obj, &obj2, &prop);
 
     /* js_FindProperty can reenter the interpreter and kill |this|. */
     if (!localtm.recorder)
-        return JSRS_STOP;
+        return ARECORD_ABORTED;
 
     if (!ok)
-        ABORT_TRACE_ERROR("error in js_FindProperty");
+        RETURN_ERROR_A("error in js_FindProperty");
 
     if (!prop)
-        ABORT_TRACE("failed to find name in non-global scope chain");
+        RETURN_STOP_A("failed to find name in non-global scope chain");
 
     if (obj == globalObj) {
         // Even if the property is on the global object, we must guard against
         // the creation of properties that shadow the property in the middle
         // of the scope chain if we are in a function.
         if (cx->fp->argv) {
             LIns* obj_ins;
             JSObject* parent = STOBJ_GET_PARENT(JSVAL_TO_OBJECT(cx->fp->argv[-2]));
             LIns* parent_ins = stobj_get_parent(get(&cx->fp->argv[-2]));
-            CHECK_STATUS(traverseScopeChain(parent, parent_ins, obj, obj_ins));
+            CHECK_STATUS_A(traverseScopeChain(parent, parent_ins, obj, obj_ins));
         }
 
         JSScopeProperty* sprop = (JSScopeProperty*) prop;
 
         if (obj2 != obj) {
             obj2->dropProperty(cx, prop);
-            ABORT_TRACE("prototype property");
+            RETURN_STOP_A("prototype property");
         }
         if (!isValidSlot(OBJ_SCOPE(obj), sprop)) {
             obj2->dropProperty(cx, prop);
-            return JSRS_STOP;
+            return ARECORD_STOP;
         }
         if (!lazilyImportGlobalSlot(sprop->slot)) {
             obj2->dropProperty(cx, prop);
-            ABORT_TRACE("lazy import of global slot failed");
+            RETURN_STOP_A("lazy import of global slot failed");
         }
         vp = &STOBJ_GET_SLOT(obj, sprop->slot);
         ins = get(vp);
         obj2->dropProperty(cx, prop);
         nr.tracked = true;
-        return JSRS_CONTINUE;
+        return ARECORD_CONTINUE;
     }
 
     if (obj == obj2 && OBJ_GET_CLASS(cx, obj) == &js_CallClass)
-        return callProp(obj, prop, ATOM_TO_JSID(atom), vp, ins, nr);
+        return InjectStatus(callProp(obj, prop, ATOM_TO_JSID(atom), vp, ins, nr));
 
     obj2->dropProperty(cx, prop);
-    ABORT_TRACE("fp->scopeChain is not global or active call object");
+    RETURN_STOP_A("fp->scopeChain is not global or active call object");
 }
 
 /*
  * Generate LIR to access a property of a Call object.
  */
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK RecordingStatus
 TraceRecorder::callProp(JSObject* obj, JSProperty* prop, jsid id, jsval*& vp,
                         LIns*& ins, NameResult& nr)
 {
     JSScopeProperty *sprop = (JSScopeProperty*) prop;
 
     JSOp op = JSOp(*cx->fp->regs->pc);
     uint32 setflags = (js_CodeSpec[op].format & (JOF_SET | JOF_INCDEC | JOF_FOR));
     if (setflags && (sprop->attrs & JSPROP_READONLY))
-        ABORT_TRACE("writing to a read-only property");
+        RETURN_STOP("writing to a read-only property");
 
     uintN slot = sprop->shortid;
 
     vp = NULL;
     uintN upvar_slot = SPROP_INVALID_SLOT;
     JSStackFrame* cfp = (JSStackFrame*) obj->getPrivate();
     if (cfp) {
         if (sprop->getter == js_GetCallArg) {
@@ -7575,26 +7593,26 @@ TraceRecorder::callProp(JSObject* obj, J
             upvar_slot = slot;
             nr.v = *vp;
         } else if (sprop->getter == js_GetCallVar) {
             JS_ASSERT(slot < cfp->script->nslots);
             vp = &cfp->slots[slot];
             upvar_slot = cx->fp->fun->nargs + slot;
             nr.v = *vp;
         } else {
-            ABORT_TRACE("dynamic property of Call object");
+            RETURN_STOP("dynamic property of Call object");
         }
         obj->dropProperty(cx, prop);
 
         if (frameIfInRange(obj)) {
             // At this point we are guaranteed to be looking at an active call oject
             // whose properties are stored in the corresponding JSStackFrame.
             ins = get(vp);
             nr.tracked = true;
-            return JSRS_CONTINUE;
+            return RECORD_CONTINUE;
         }
     } else {
         // Call objects do not yet have sprop->isMethod() properties, but they
         // should. See bug 514046, for which this code is future-proof. Remove
         // this comment when that bug is fixed (so, FIXME: 514046).
 #ifdef DEBUG
         JSBool rv =
 #endif
@@ -7639,17 +7657,17 @@ TraceRecorder::callProp(JSObject* obj, J
           addName(lir->ins2(LIR_eq, call_ins, lir->insImm(type)),
                   "guard(type-stable name access)"),
           BRANCH_EXIT);
     ins = stackLoad(outp, type);
     nr.tracked = false;
     nr.obj = obj;
     nr.obj_ins = obj_ins;
     nr.sprop = sprop;
-    return JSRS_CONTINUE;
+    return RECORD_CONTINUE;
 }
 
 JS_REQUIRES_STACK LIns*
 TraceRecorder::arg(unsigned n)
 {
     return get(&argval(n));
 }
 
@@ -7871,38 +7889,38 @@ TraceRecorder::stringify(jsval& v)
         return INS_ATOM(cx->runtime->atomState.nullAtom);
     }
 
     v_ins = lir->insCall(ci, args);
     guard(false, lir->ins_peq0(v_ins), OOM_EXIT);
     return v_ins;
 }
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK RecordingStatus
 TraceRecorder::call_imacro(jsbytecode* imacro)
 {
     JSStackFrame* fp = cx->fp;
     JSFrameRegs* regs = fp->regs;
 
     /* We cannot nest imacros, only tail-call. */
     if (fp->imacpc) {
         /* Dereference is safe since imacros are JSOP_STOP-terminated. */
         if (regs->pc[js_CodeSpec[*regs->pc].length] != JSOP_STOP)
-            return JSRS_STOP;
+            return RECORD_STOP;
         regs->pc = imacro;
-        return JSRS_IMACRO;
+        return RECORD_IMACRO;
     }
 
     fp->imacpc = regs->pc;
     regs->pc = imacro;
     atoms = COMMON_ATOMS_START(&cx->runtime->atomState);
-    return JSRS_IMACRO;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return RECORD_IMACRO;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::ifop()
 {
     jsval& v = stackval(-1);
     LIns* v_ins = get(&v);
     bool cond;
     LIns* x;
 
     if (JSVAL_IS_NULL(v)) {
@@ -7925,50 +7943,50 @@ TraceRecorder::ifop()
         cond = JSVAL_TO_STRING(v)->length() != 0;
         x = lir->ins2(LIR_piand,
                       lir->insLoad(LIR_ldp,
                                    v_ins,
                                    (int)offsetof(JSString, mLength)),
                       INS_CONSTWORD(JSString::LENGTH_MASK));
     } else {
         JS_NOT_REACHED("ifop");
-        return JSRS_STOP;
+        return ARECORD_STOP;
     }
 
     jsbytecode* pc = cx->fp->regs->pc;
     emitIf(pc, cond, x);
     return checkTraceEnd(pc);
 }
 
 #ifdef NANOJIT_IA32
 /*
  * Record LIR for a tableswitch or tableswitchx op. We record LIR only the
  * "first" time we hit the op. Later, when we start traces after exiting that
  * trace, we just patch.
  */
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::tableswitch()
 {
     jsval& v = stackval(-1);
 
     /* No need to guard if the condition can't match any of the cases. */
     if (!isNumber(v))
-        return JSRS_CONTINUE;
+        return ARECORD_CONTINUE;
 
     /* No need to guard if the condition is constant. */
     LIns* v_ins = f2i(get(&v));
     if (v_ins->isconst() || v_ins->isconstq())
-        return JSRS_CONTINUE;
+        return ARECORD_CONTINUE;
 
     jsbytecode* pc = cx->fp->regs->pc;
     /* Starting a new trace after exiting a trace via switch. */
     if (anchor &&
         (anchor->exitType == CASE_EXIT || anchor->exitType == DEFAULT_EXIT) &&
         fragment->ip == pc) {
-        return JSRS_CONTINUE;
+        return ARECORD_CONTINUE;
     }
 
     /* Decode jsop. */
     jsint low, high;
     if (*pc == JSOP_TABLESWITCH) {
         pc += JUMP_OFFSET_LEN;
         low = GET_JUMP_OFFSET(pc);
         pc += JUMP_OFFSET_LEN;
@@ -7980,53 +7998,53 @@ TraceRecorder::tableswitch()
         high = GET_JUMPX_OFFSET(pc);
     }
 
     /*
      * Really large tables won't fit in a page. This is a conservative check.
      * If it matters in practice we need to go off-page.
      */
     if ((high + 1 - low) * sizeof(intptr_t*) + 128 > (unsigned) LARGEST_UNDERRUN_PROT)
-        return switchop();
+        return InjectStatus(switchop());
 
     /* Generate switch LIR. */
     SwitchInfo* si = new (*traceMonitor->dataAlloc) SwitchInfo();
     si->count = high + 1 - low;
     si->table = 0;
     si->index = (uint32) -1;
     LIns* diff = lir->ins2(LIR_sub, v_ins, lir->insImm(low));
     LIns* cmp = lir->ins2(LIR_ult, diff, lir->insImm(si->count));
     lir->insGuard(LIR_xf, cmp, createGuardRecord(snapshot(DEFAULT_EXIT)));
     lir->insStorei(diff, lir->insImmPtr(&si->index), 0);
     VMSideExit* exit = snapshot(CASE_EXIT);
     exit->switchInfo = si;
     LIns* guardIns = lir->insGuard(LIR_xtbl, diff, createGuardRecord(exit));
     fragment->lastIns = guardIns;
     compile(&JS_TRACE_MONITOR(cx));
-    return JSRS_STOP;
+    return ARECORD_STOP;
 }
 #endif
 
 static JS_ALWAYS_INLINE int32_t
 UnboxBooleanOrUndefined(jsval v)
 {
     /* Although this says 'special', we really only expect 3 special values: */
     JS_ASSERT(v == JSVAL_TRUE || v == JSVAL_FALSE || v == JSVAL_VOID);
     return JSVAL_TO_SPECIAL(v);
 }
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK RecordingStatus
 TraceRecorder::switchop()
 {
     jsval& v = stackval(-1);
     LIns* v_ins = get(&v);
 
     /* No need to guard if the condition is constant. */
     if (v_ins->isconst() || v_ins->isconstq())
-        return JSRS_CONTINUE;
+        return RECORD_CONTINUE;
     if (isNumber(v)) {
         jsdouble d = asNumber(v);
         guard(true,
               addName(lir->ins2(LIR_feq, v_ins, lir->insImmf(d)),
                       "guard(switch on numeric)"),
               BRANCH_EXIT);
     } else if (JSVAL_IS_STRING(v)) {
         LIns* args[] = { v_ins, INS_CONSTSTR(JSVAL_TO_STRING(v)) };
@@ -8035,104 +8053,104 @@ TraceRecorder::switchop()
                       "guard(switch on string)"),
               BRANCH_EXIT);
     } else if (JSVAL_IS_SPECIAL(v)) {
         guard(true,
               addName(lir->ins2(LIR_eq, v_ins, lir->insImm(UnboxBooleanOrUndefined(v))),
                       "guard(switch on boolean)"),
               BRANCH_EXIT);
     } else {
-        ABORT_TRACE("switch on object or null");
-    }
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+        RETURN_STOP("switch on object or null");
+    }
+    return RECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK RecordingStatus
 TraceRecorder::inc(jsval& v, jsint incr, bool pre)
 {
     LIns* v_ins = get(&v);
     CHECK_STATUS(inc(v, v_ins, incr, pre));
     set(&v, v_ins);
-    return JSRS_CONTINUE;
+    return RECORD_CONTINUE;
 }
 
 /*
  * On exit, v_ins is the incremented unboxed value, and the appropriate value
  * (pre- or post-increment as described by pre) is stacked.
  */
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK RecordingStatus
 TraceRecorder::inc(jsval v, LIns*& v_ins, jsint incr, bool pre)
 {
     LIns* v_after;
     CHECK_STATUS(incHelper(v, v_ins, v_after, incr));
 
     const JSCodeSpec& cs = js_CodeSpec[*cx->fp->regs->pc];
     JS_ASSERT(cs.ndefs == 1);
     stack(-cs.nuses, pre ? v_after : v_ins);
     v_ins = v_after;
-    return JSRS_CONTINUE;
+    return RECORD_CONTINUE;
 }
 
 /*
  * Do an increment operation without storing anything to the stack.
  */
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK RecordingStatus
 TraceRecorder::incHelper(jsval v, LIns* v_ins, LIns*& v_after, jsint incr)
 {
     if (!isNumber(v))
-        ABORT_TRACE("can only inc numbers");
+        RETURN_STOP("can only inc numbers");
     v_after = alu(LIR_fadd, asNumber(v), incr, v_ins, lir->insImmf(incr));
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return RECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::incProp(jsint incr, bool pre)
 {
     jsval& l = stackval(-1);
     if (JSVAL_IS_PRIMITIVE(l))
-        ABORT_TRACE("incProp on primitive");
+        RETURN_STOP_A("incProp on primitive");
 
     JSObject* obj = JSVAL_TO_OBJECT(l);
     LIns* obj_ins = get(&l);
 
     uint32 slot;
     LIns* v_ins;
-    CHECK_STATUS(prop(obj, obj_ins, &slot, &v_ins, NULL));
+    CHECK_STATUS_A(prop(obj, obj_ins, &slot, &v_ins, NULL));
 
     if (slot == SPROP_INVALID_SLOT)
-        ABORT_TRACE("incProp on invalid slot");
+        RETURN_STOP_A("incProp on invalid slot");
 
     jsval& v = STOBJ_GET_SLOT(obj, slot);
-    CHECK_STATUS(inc(v, v_ins, incr, pre));
+    CHECK_STATUS_A(inc(v, v_ins, incr, pre));
 
     LIns* dslots_ins = NULL;
     stobj_set_slot(obj_ins, slot, dslots_ins, box_jsval(v, v_ins));
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK RecordingStatus
 TraceRecorder::incElem(jsint incr, bool pre)
 {
     jsval& r = stackval(-1);
     jsval& l = stackval(-2);
     jsval* vp;
     LIns* v_ins;
     LIns* addr_ins;
 
     if (JSVAL_IS_PRIMITIVE(l) || !JSVAL_IS_INT(r) ||
         !guardDenseArray(JSVAL_TO_OBJECT(l), get(&l))) {
-        return JSRS_STOP;
+        return RECORD_STOP;
     }
 
     CHECK_STATUS(denseArrayElement(l, r, vp, v_ins, addr_ins));
     if (!addr_ins) // if we read a hole, abort
-        return JSRS_STOP;
+        return RECORD_STOP;
     CHECK_STATUS(inc(*vp, v_ins, incr, pre));
     lir->insStorei(box_jsval(*vp, v_ins), addr_ins, 0);
-    return JSRS_CONTINUE;
+    return RECORD_CONTINUE;
 }
 
 static bool
 EvalCmp(LOpcode op, double l, double r)
 {
     bool cond;
     switch (op) {
       case LIR_feq:
@@ -8205,28 +8223,28 @@ TraceRecorder::strictEquality(bool equal
         if (!x->isconst())
             guard(cond, x, BRANCH_EXIT);
         return;
     }
 
     set(&l, x);
 }
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::equality(bool negate, bool tryBranchAfterCond)
 {
     jsval& rval = stackval(-1);
     jsval& lval = stackval(-2);
     LIns* l_ins = get(&lval);
     LIns* r_ins = get(&rval);
 
     return equalityHelper(lval, rval, l_ins, r_ins, negate, tryBranchAfterCond, lval);
 }
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::equalityHelper(jsval l, jsval r, LIns* l_ins, LIns* r_ins,
                               bool negate, bool tryBranchAfterCond,
                               jsval& rval)
 {
     LOpcode op = LIR_eq;
     bool cond;
     LIns* args[] = { NULL, NULL };
 
@@ -8298,22 +8316,22 @@ TraceRecorder::equalityHelper(jsval l, j
                 r = (r == JSVAL_VOID)
                     ? DOUBLE_TO_JSVAL(cx->runtime->jsNaN)
                     : INT_TO_JSVAL(r == JSVAL_TRUE);
                 return equalityHelper(l, r, l_ins, r_ins, negate,
                                       tryBranchAfterCond, rval);
             }
         } else {
             if ((JSVAL_IS_STRING(l) || isNumber(l)) && !JSVAL_IS_PRIMITIVE(r)) {
-                ABORT_IF_XML(r);
-                return call_imacro(equality_imacros.any_obj);
+                RETURN_IF_XML_A(r);
+                return InjectStatus(call_imacro(equality_imacros.any_obj));
             }
             if (!JSVAL_IS_PRIMITIVE(l) && (JSVAL_IS_STRING(r) || isNumber(r))) {
-                ABORT_IF_XML(l);
-                return call_imacro(equality_imacros.obj_any);
+                RETURN_IF_XML_A(l);
+                return InjectStatus(call_imacro(equality_imacros.obj_any));
             }
         }
 
         l_ins = lir->insImm(0);
         r_ins = lir->insImm(1);
         cond = false;
     }
 
@@ -8334,30 +8352,30 @@ TraceRecorder::equalityHelper(jsval l, j
     if (tryBranchAfterCond)
         fuseIf(pc + 1, cond, x);
 
     /*
      * There is no need to write out the result of this comparison if the trace
      * ends on this operation.
      */
     if (pc[1] == JSOP_IFNE || pc[1] == JSOP_IFEQ)
-        CHECK_STATUS(checkTraceEnd(pc + 1));
+        CHECK_STATUS_A(checkTraceEnd(pc + 1));
 
     /*
      * We update the stack after the guard. This is safe since the guard bails
      * out at the comparison and the interpreter will therefore re-execute the
      * comparison. This way the value of the condition doesn't have to be
      * calculated and saved on the stack in most cases.
      */
     set(&rval, x);
 
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::relational(LOpcode op, bool tryBranchAfterCond)
 {
     jsval& r = stackval(-1);
     jsval& l = stackval(-2);
     LIns* x = NULL;
     bool cond;
     LIns* l_ins = get(&l);
     LIns* r_ins = get(&r);
@@ -8365,26 +8383,26 @@ TraceRecorder::relational(LOpcode op, bo
     jsdouble lnum, rnum;
 
     /*
      * 11.8.5 if either argument is an object with a function-valued valueOf
      * property; if both arguments are objects with non-function-valued valueOf
      * properties, abort.
      */
     if (!JSVAL_IS_PRIMITIVE(l)) {
-        ABORT_IF_XML(l);
+        RETURN_IF_XML_A(l);
         if (!JSVAL_IS_PRIMITIVE(r)) {
-            ABORT_IF_XML(r);
-            return call_imacro(binary_imacros.obj_obj);
-        }
-        return call_imacro(binary_imacros.obj_any);
+            RETURN_IF_XML_A(r);
+            return InjectStatus(call_imacro(binary_imacros.obj_obj));
+        }
+        return InjectStatus(call_imacro(binary_imacros.obj_any));
     }
     if (!JSVAL_IS_PRIMITIVE(r)) {
-        ABORT_IF_XML(r);
-        return call_imacro(binary_imacros.any_obj);
+        RETURN_IF_XML_A(r);
+        return InjectStatus(call_imacro(binary_imacros.any_obj));
     }
 
     /* 11.8.5 steps 3, 16-21. */
     if (JSVAL_IS_STRING(l) && JSVAL_IS_STRING(r)) {
         LIns* args[] = { r_ins, l_ins };
         l_ins = lir->insCall(&js_CompareStrings_ci, args);
         r_ins = lir->insImm(0);
         cond = EvalCmp(op, JSVAL_TO_STRING(l), JSVAL_TO_STRING(r));
@@ -8407,17 +8425,17 @@ TraceRecorder::relational(LOpcode op, bo
                 break;
             }
             // FALL THROUGH
           case JSVAL_INT:
           case JSVAL_DOUBLE:
           default:
             JS_NOT_REACHED("JSVAL_IS_NUMBER if int/double, objects should "
                            "have been handled at start of method");
-            ABORT_TRACE("safety belt");
+            RETURN_STOP_A("safety belt");
         }
     }
     if (!JSVAL_IS_NUMBER(r)) {
         LIns* args[] = { r_ins, cx_ins };
         switch (JSVAL_TAG(r)) {
           case JSVAL_SPECIAL:
             r_ins = lir->insCall(&js_BooleanOrUndefinedToNumber_ci, args);
             break;
@@ -8430,17 +8448,17 @@ TraceRecorder::relational(LOpcode op, bo
                 break;
             }
             // FALL THROUGH
           case JSVAL_INT:
           case JSVAL_DOUBLE:
           default:
             JS_NOT_REACHED("JSVAL_IS_NUMBER if int/double, objects should "
                            "have been handled at start of method");
-            ABORT_TRACE("safety belt");
+            RETURN_STOP_A("safety belt");
         }
     }
     {
         jsval tmp = JSVAL_NULL;
         JSAutoTempValueRooter tvr(cx, 1, &tmp);
 
         tmp = l;
         lnum = js_ValueToNumber(cx, &tmp);
@@ -8472,63 +8490,63 @@ TraceRecorder::relational(LOpcode op, bo
     if (tryBranchAfterCond)
         fuseIf(pc + 1, cond, x);
 
     /*
      * There is no need to write out the result of this comparison if the trace
      * ends on this operation.
      */
     if (pc[1] == JSOP_IFNE || pc[1] == JSOP_IFEQ)
-        CHECK_STATUS(checkTraceEnd(pc + 1));
+        CHECK_STATUS_A(checkTraceEnd(pc + 1));
 
     /*
      * We update the stack after the guard. This is safe since the guard bails
      * out at the comparison and the interpreter will therefore re-execute the
      * comparison. This way the value of the condition doesn't have to be
      * calculated and saved on the stack in most cases.
      */
     set(&l, x);
 
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK RecordingStatus
 TraceRecorder::unary(LOpcode op)
 {
     jsval& v = stackval(-1);
     bool intop = !(op & LIR64);
     if (isNumber(v)) {
         LIns* a = get(&v);
         if (intop)
             a = f2i(a);
         a = lir->ins1(op, a);
         if (intop)
             a = lir->ins1(LIR_i2f, a);
         set(&v, a);
-        return JSRS_CONTINUE;
-    }
-    return JSRS_STOP;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+        return RECORD_CONTINUE;
+    }
+    return RECORD_STOP;
+}
+
+JS_REQUIRES_STACK RecordingStatus
 TraceRecorder::binary(LOpcode op)
 {
     jsval& r = stackval(-1);
     jsval& l = stackval(-2);
 
     if (!JSVAL_IS_PRIMITIVE(l)) {
-        ABORT_IF_XML(l);
+        RETURN_IF_XML(l);
         if (!JSVAL_IS_PRIMITIVE(r)) {
-            ABORT_IF_XML(r);
+            RETURN_IF_XML(r);
             return call_imacro(binary_imacros.obj_obj);
         }
         return call_imacro(binary_imacros.obj_any);
     }
     if (!JSVAL_IS_PRIMITIVE(r)) {
-        ABORT_IF_XML(r);
+        RETURN_IF_XML(r);
         return call_imacro(binary_imacros.any_obj);
     }
 
     bool intop = !(op & LIR64);
     LIns* a = get(&l);
     LIns* b = get(&r);
 
     bool leftIsNumber = isNumber(l);
@@ -8572,19 +8590,19 @@ TraceRecorder::binary(LOpcode op)
             LIns *args[] = { a };
             a = lir->insCall(op == LIR_ush ? &js_DoubleToUint32_ci : &js_DoubleToInt32_ci, args);
             b = f2i(b);
         }
         a = alu(op, lnum, rnum, a, b);
         if (intop)
             a = lir->ins1(op == LIR_ush ? LIR_u2f : LIR_i2f, a);
         set(&l, a);
-        return JSRS_CONTINUE;
-    }
-    return JSRS_STOP;
+        return RECORD_CONTINUE;
+    }
+    return RECORD_STOP;
 }
 
 void
 TraceRecorder::guardShape(LIns* obj_ins, JSObject* obj, uint32 shape, const char* guardName,
                           LIns* map_ins, VMSideExit* exit)
 {
     LIns* shape_ins = addName(lir->insLoad(LIR_ld, map_ins, offsetof(JSScope, shape)), "shape");
     guard(true,
@@ -8616,17 +8634,17 @@ TraceRecorder::map_is_native(JSObjectMap
     LIns* n = lir->insLoad(LIR_ldcp, ops_ins, op_offset);
     guard(true,
           addName(lir->ins2(LIR_peq, n, INS_CONSTPTR(ptr)), "guard(native-map)"),
           BRANCH_EXIT);
 
     return true;
 }
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK RecordingStatus
 TraceRecorder::guardNativePropertyOp(JSObject* aobj, LIns* map_ins)
 {
     /*
      * Interpreter calls to PROPERTY_CACHE_TEST guard on native object ops
      * which is required to use native objects (those whose maps are scopes),
      * or even more narrow conditions required because the cache miss case
      * will call a particular object-op (js_GetProperty, js_SetProperty).
      *
@@ -8646,22 +8664,22 @@ TraceRecorder::guardNativePropertyOp(JSO
                         ? offsetof(JSObjectOps, setProperty)
                         : offsetof(JSObjectOps, getProperty);
         } else {
             JS_ASSERT(mode == JOF_NAME);
         }
 
         LIns* ops_ins;
         if (!map_is_native(aobj->map, map_ins, ops_ins, op_offset))
-            ABORT_TRACE("non-native map");
-    }
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+            RETURN_STOP("non-native map");
+    }
+    return RECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::test_property_cache(JSObject* obj, LIns* obj_ins, JSObject*& obj2, jsuword& pcval)
 {
     jsbytecode* pc = cx->fp->regs->pc;
     JS_ASSERT(*pc != JSOP_INITPROP && *pc != JSOP_INITMETHOD &&
               *pc != JSOP_SETNAME && *pc != JSOP_SETPROP && *pc != JSOP_SETMETHOD);
 
     // Mimic the interpreter's special case for dense arrays by skipping up one
     // hop along the proto chain when accessing a named (not indexed) property,
@@ -8670,17 +8688,17 @@ TraceRecorder::test_property_cache(JSObj
     if (OBJ_IS_DENSE_ARRAY(cx, obj)) {
         guardDenseArray(obj, obj_ins, BRANCH_EXIT);
         aobj = OBJ_GET_PROTO(cx, obj);
         obj_ins = stobj_get_proto(obj_ins);
     }
 
     LIns* map_ins = map(obj_ins);
 
-    CHECK_STATUS(guardNativePropertyOp(aobj, map_ins));
+    CHECK_STATUS_A(guardNativePropertyOp(aobj, map_ins));
 
     JSAtom* atom;
     JSPropCacheEntry* entry;
     PROPERTY_CACHE_TEST(cx, pc, aobj, obj2, entry, atom);
     if (!atom) {
         // Null atom means that obj2 is locked and must now be unlocked.
         JS_UNLOCK_OBJ(cx, obj2);
     } else {
@@ -8690,43 +8708,43 @@ TraceRecorder::test_property_cache(JSObj
         if (JOF_OPMODE(*pc) == JOF_NAME) {
             JS_ASSERT(aobj == obj);
 
             JSTraceMonitor &localtm = *traceMonitor;
             entry = js_FindPropertyHelper(cx, id, true, &obj, &obj2, &prop);
 
             /* js_FindPropertyHelper can reenter the interpreter and kill |this|. */
             if (!localtm.recorder)
-                return JSRS_STOP;
+                return ARECORD_ABORTED;
 
             if (!entry)
-                ABORT_TRACE_ERROR("error in js_FindPropertyHelper");
+                RETURN_ERROR_A("error in js_FindPropertyHelper");
             if (entry == JS_NO_PROP_CACHE_FILL)
-                ABORT_TRACE("cannot cache name");
+                RETURN_STOP_A("cannot cache name");
         } else {
             JSTraceMonitor &localtm = *traceMonitor;
             JSContext *localcx = cx;
             int protoIndex = js_LookupPropertyWithFlags(cx, aobj, id,
                                                         cx->resolveFlags,
                                                         &obj2, &prop);
 
             /* js_LookupPropertyWithFlags can reenter the interpreter and kill |this|. */
             if (!localtm.recorder) {
                 if (prop)
                     obj2->dropProperty(localcx, prop);
-                return JSRS_STOP;
+                return ARECORD_ABORTED;
             }
 
             if (protoIndex < 0)
-                ABORT_TRACE_ERROR("error in js_LookupPropertyWithFlags");
+                RETURN_ERROR_A("error in js_LookupPropertyWithFlags");
 
             if (prop) {
                 if (!OBJ_IS_NATIVE(obj2)) {
                     obj2->dropProperty(cx, prop);
-                    ABORT_TRACE("property found on non-native object");
+                    RETURN_STOP_A("property found on non-native object");
                 }
                 entry = js_FillPropertyCache(cx, aobj, 0, protoIndex, obj2,
                                              (JSScopeProperty*) prop, false);
                 JS_ASSERT(entry);
                 if (entry == JS_NO_PROP_CACHE_FILL)
                     entry = NULL;
             }
 
@@ -8735,36 +8753,36 @@ TraceRecorder::test_property_cache(JSObj
         if (!prop) {
             // Propagate obj from js_FindPropertyHelper to record_JSOP_BINDNAME
             // via our obj2 out-parameter. If we are recording JSOP_SETNAME and
             // the global it's assigning does not yet exist, create it.
             obj2 = obj;
 
             // Use PCVAL_NULL to return "no such property" to our caller.
             pcval = PCVAL_NULL;
-            return JSRS_CONTINUE;
+            return ARECORD_CONTINUE;
         }
 
         obj2->dropProperty(cx, prop);
         if (!entry)
-            ABORT_TRACE("failed to fill property cache");
+            RETURN_STOP_A("failed to fill property cache");
     }
 
 #ifdef JS_THREADSAFE
     // There's a potential race in any JS_THREADSAFE embedding that's nuts
     // enough to share mutable objects on the scope or proto chain, but we
     // don't care about such insane embeddings. Anyway, the (scope, proto)
     // entry->vcap coordinates must reach obj2 from aobj at this point.
     JS_ASSERT(cx->requestDepth);
 #endif
 
-    return guardPropertyCacheHit(obj_ins, map_ins, aobj, obj2, entry, pcval);
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return InjectStatus(guardPropertyCacheHit(obj_ins, map_ins, aobj, obj2, entry, pcval));
+}
+
+JS_REQUIRES_STACK RecordingStatus
 TraceRecorder::guardPropertyCacheHit(LIns* obj_ins,
                                      LIns* map_ins,
                                      JSObject* aobj,
                                      JSObject* obj2,
                                      JSPropCacheEntry* entry,
                                      jsuword& pcval)
 {
     VMSideExit* exit = snapshot(BRANCH_EXIT);
@@ -8774,17 +8792,17 @@ TraceRecorder::guardPropertyCacheHit(LIn
     // Check for first-level cache hit and guard on kshape if possible.
     // Otherwise guard on key object exact match.
     if (PCVCAP_TAG(entry->vcap) <= 1) {
         if (aobj != globalObj)
             guardShape(obj_ins, aobj, entry->kshape, "guard_kshape", map_ins, exit);
 
         if (entry->adding()) {
             if (aobj == globalObj)
-                ABORT_TRACE("adding a property to the global object");
+                RETURN_STOP("adding a property to the global object");
 
             LIns *vshape_ins = addName(
                 lir->insLoad(LIR_ld,
                              addName(lir->insLoad(LIR_ldcp, cx_ins, offsetof(JSContext, runtime)),
                                      "runtime"),
                              offsetof(JSRuntime, protoHazardShape)),
                 "protoHazardShape");
             guard(true,
@@ -8823,17 +8841,17 @@ TraceRecorder::guardPropertyCacheHit(LIn
             guard(false, lir->ins_peq0(obj2_ins), exit);
         } else {
             obj2_ins = INS_CONSTOBJ(obj2);
         }
         guardShape(obj2_ins, obj2, vshape, "guard_vshape", map(obj2_ins), exit);
     }
 
     pcval = entry->vword;
-    return JSRS_CONTINUE;
+    return RECORD_CONTINUE;
 }
 
 void
 TraceRecorder::stobj_set_fslot(LIns *obj_ins, unsigned slot, LIns* v_ins)
 {
     lir->insStorei(v_ins, obj_ins, offsetof(JSObject, fslots) + slot * sizeof(jsval));
 }
 
@@ -8959,45 +8977,45 @@ TraceRecorder::unbox_jsval(jsval v, LIns
                         lir->ins2(LIR_piand, v_ins, INS_CONSTWORD(JSVAL_TAGMASK)),
                         INS_CONSTWORD(JSVAL_STRING)),
               exit);
         return lir->ins2(LIR_piand, v_ins, addName(lir->insImmWord(~JSVAL_TAGMASK),
     					           "~JSVAL_TAGMASK"));
     }
 }
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK RecordingStatus
 TraceRecorder::getThis(LIns*& this_ins)
 {
     /*
      * js_ComputeThisForFrame updates cx->fp->argv[-1], so sample it into 'original' first.
      */
     jsval original = JSVAL_NULL;
     if (cx->fp->argv) {
         original = cx->fp->argv[-1];
         if (!JSVAL_IS_PRIMITIVE(original) &&
             guardClass(JSVAL_TO_OBJECT(original), get(&cx->fp->argv[-1]), &js_WithClass, snapshot(MISMATCH_EXIT))) {
-            ABORT_TRACE("can't trace getThis on With object");
+            RETURN_STOP("can't trace getThis on With object");
         }
     }
 
     JSObject* thisObj = js_ComputeThisForFrame(cx, cx->fp);
     if (!thisObj)
-        ABORT_TRACE_ERROR("js_ComputeThisForName failed");
+        RETURN_ERROR("js_ComputeThisForName failed");
 
     /* In global code, bake in the global object as 'this' object. */
     if (!cx->fp->callee()) {
         JS_ASSERT(callDepth == 0);
         this_ins = INS_CONSTOBJ(thisObj);
 
         /*
          * We don't have argv[-1] in global code, so we don't update the
          * tracker here.
          */
-        return JSRS_CONTINUE;
+        return RECORD_CONTINUE;
     }
 
     jsval& thisv = cx->fp->argv[-1];
     JS_ASSERT(JSVAL_IS_OBJECT(thisv));
 
     /*
      * Traces type-specialize between null and objects, so if we currently see
      * a null value in argv[-1], this trace will only match if we see null at
@@ -9009,36 +9027,36 @@ TraceRecorder::getThis(LIns*& this_ins)
     JSClass* clasp = NULL;;
     if (JSVAL_IS_NULL(original) ||
         (((clasp = STOBJ_GET_CLASS(JSVAL_TO_OBJECT(original))) == &js_CallClass) ||
          (clasp == &js_BlockClass))) {
         if (clasp)
             guardClass(JSVAL_TO_OBJECT(original), get(&thisv), clasp, snapshot(BRANCH_EXIT));
         JS_ASSERT(!JSVAL_IS_PRIMITIVE(thisv));
         if (thisObj != globalObj)
-            ABORT_TRACE("global object was wrapped while recording");
+            RETURN_STOP("global object was wrapped while recording");
         this_ins = INS_CONSTOBJ(thisObj);
         set(&thisv, this_ins);
-        return JSRS_CONTINUE;
+        return RECORD_CONTINUE;
     }
 
     this_ins = get(&thisv);
 
     JSObject* wrappedGlobal = globalObj->thisObject(cx);
     if (!wrappedGlobal)
-        ABORT_TRACE_ERROR("globalObj->thisObject hook threw in getThis");
+        RETURN_ERROR("globalObj->thisObject hook threw in getThis");
 
     /*
      * The only unwrapped object that needs to be wrapped that we can get here
      * is the global object obtained throught the scope chain.
      */
     this_ins = lir->ins_choose(lir->ins_peq0(stobj_get_parent(this_ins)),
                                INS_CONSTOBJ(wrappedGlobal),
                                this_ins);
-    return JSRS_CONTINUE;
+    return RECORD_CONTINUE;
 }
 
 
 LIns*
 TraceRecorder::getStringLength(LIns* str_ins)
 {
     LIns* len_ins = lir->insLoad(LIR_ldp, str_ins, (int)offsetof(JSString, mLength));
 
@@ -9095,40 +9113,40 @@ TraceRecorder::guardHasPrototype(JSObjec
     *pobj = obj->getProto();
     *pobj_ins = stobj_get_proto(obj_ins);
 
     bool cond = *pobj == NULL;
     guard(cond, addName(lir->ins_peq0(*pobj_ins), "guard(proto-not-null)"), exit);
     return !cond;
 }
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK RecordingStatus
 TraceRecorder::guardPrototypeHasNoIndexedProperties(JSObject* obj, LIns* obj_ins, ExitType exitType)
 {
     /*
      * Guard that no object along the prototype chain has any indexed
      * properties which might become visible through holes in the array.
      */
     VMSideExit* exit = snapshot(exitType);
 
     if (js_PrototypeHasIndexedProperties(cx, obj))
-        return JSRS_STOP;
+        return RECORD_STOP;
 
     while (guardHasPrototype(obj, obj_ins, &obj, &obj_ins, exit))
         guardShape(obj_ins, obj, OBJ_SHAPE(obj), "guard(shape)", map(obj_ins), exit);
-    return JSRS_CONTINUE;
-}
-
-JSRecordingStatus
+    return RECORD_CONTINUE;
+}
+
+RecordingStatus
 TraceRecorder::guardNotGlobalObject(JSObject* obj, LIns* obj_ins)
 {
     if (obj == globalObj)
-        ABORT_TRACE("reference aliases global object");
+        RETURN_STOP("reference aliases global object");
     guard(false, lir->ins2(LIR_peq, obj_ins, INS_CONSTOBJ(globalObj)), MISMATCH_EXIT);
-    return JSRS_CONTINUE;
+    return RECORD_CONTINUE;
 }
 
 JS_REQUIRES_STACK void
 TraceRecorder::clearFrameSlotsFromCache()
 {
     /*
      * Clear out all slots of this frame in the nativeFrameTracker. Different
      * locations on the VM stack might map to different locations on the native
@@ -9173,28 +9191,28 @@ TraceRecorder::putArguments()
             LIns* arg_ins = box_jsval(cx->fp->argv[i], get(&cx->fp->argv[i]));
             lir->insStorei(arg_ins, args_ins, i * sizeof(jsval));
         }
         LIns* args[] = { args_ins, argsobj_ins, cx_ins };
         lir->insCall(&js_PutArguments_ci, args);
     }
 }
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_EnterFrame()
 {
     JSStackFrame* fp = cx->fp;
 
     if (++callDepth >= MAX_CALLDEPTH)
-        ABORT_TRACE("exceeded maximum call depth");
+        RETURN_STOP_A("exceeded maximum call depth");
 
     // FIXME: Allow and attempt to inline a single level of recursion until we compile
     //        recursive calls as independent trees (459301).
     if (fp->script == fp->down->script && fp->down->down && fp->down->down->script == fp->script)
-        ABORT_TRACE("recursive call");
+        RETURN_STOP_A("recursive call");
 
     debug_only_printf(LC_TMTracer, "EnterFrame %s, callDepth=%d\n",
                       js_AtomToPrintableString(cx, cx->fp->fun->atom),
                       callDepth);
     debug_only_stmt(
         if (js_LogController.lcbits & LC_TMRecorder) {
             js_Disassemble(cx, cx->fp->script, JS_TRUE, stdout);
             debug_only_print0(LC_TMTracer, "----\n");
@@ -9213,80 +9231,79 @@ TraceRecorder::record_EnterFrame()
         set(vp++, void_ins, true);
     }
 
     vp = &fp->slots[0];
     vpstop = vp + fp->script->nfixed;
     while (vp < vpstop)
         set(vp++, void_ins, true);
     set(&fp->argsobj, INS_NULL(), true);
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_LeaveFrame()
 {
     debug_only_stmt(
         if (cx->fp->fun)
             debug_only_printf(LC_TMTracer,
                               "LeaveFrame (back to %s), callDepth=%d\n",
                               js_AtomToPrintableString(cx, cx->fp->fun->atom),
                               callDepth);
         );
     if (callDepth-- <= 0)
-        ABORT_TRACE("returned out of a loop we started tracing");
+        RETURN_STOP_A("returned out of a loop we started tracing");
 
     // LeaveFrame gets called after the interpreter popped the frame and
     // stored rval, so cx->fp not cx->fp->down, and -1 not 0.
     atoms = FrameAtomBase(cx, cx->fp);
     set(&stackval(-1), rval_ins, true);
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_PUSH()
 {
     stack(0, INS_CONST(JSVAL_TO_SPECIAL(JSVAL_VOID)));
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_POPV()
 {
     jsval& rval = stackval(-1);
     LIns *rval_ins = box_jsval(rval, get(&rval));
 
     // Store it in cx->fp->rval. NB: Tricky dependencies. cx->fp is the right
     // frame because POPV appears only in global and eval code and we don't
     // trace JSOP_EVAL or leaving the frame where tracing started.
     LIns *fp_ins = lir->insLoad(LIR_ldp, cx_ins, offsetof(JSContext, fp));
     lir->insStorei(rval_ins, fp_ins, offsetof(JSStackFrame, rval));
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_ENTERWITH()
 {
-    return JSRS_STOP;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_STOP;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_LEAVEWITH()
 {
-    return JSRS_STOP;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_STOP;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_RETURN()
 {
     /* A return from callDepth 0 terminates the current loop. */
     if (callDepth == 0) {
         AUDIT(returnLoopExits);
-        endLoop();
-        return JSRS_STOP;
+        return endLoop();
     }
 
     putArguments();
 
     /* If we inlined this function call, make the return value available to the caller code. */
     jsval& rval = stackval(-1);
     JSStackFrame *fp = cx->fp;
     if ((cx->fp->flags & JSFRAME_CONSTRUCTING) && JSVAL_IS_PRIMITIVE(rval)) {
@@ -9295,45 +9312,44 @@ TraceRecorder::record_JSOP_RETURN()
     } else {
         rval_ins = get(&rval);
     }
     debug_only_printf(LC_TMTracer,
                       "returning from %s\n",
                       js_AtomToPrintableString(cx, cx->fp->fun->atom));
     clearFrameSlotsFromCache();
 
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_GOTO()
 {
     /*
      * If we hit a break or a continue to an outer loop, end the loop and
      * generate an always-taken loop exit guard.  For other downward gotos
      * (like if/else) continue recording.
      */
     jssrcnote* sn = js_GetSrcNote(cx->fp->script, cx->fp->regs->pc);
 
     if (sn && (SN_TYPE(sn) == SRC_BREAK || SN_TYPE(sn) == SRC_CONT2LABEL)) {
         AUDIT(breakLoopExits);
-        endLoop();
-        return JSRS_STOP;
-    }
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+        return endLoop();
+    }
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_IFEQ()
 {
     trackCfgMerges(cx->fp->regs->pc);
     return ifop();
 }
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_IFNE()
 {
     return ifop();
 }
 
 LIns*
 TraceRecorder::newArguments()
 {
@@ -9350,21 +9366,21 @@ TraceRecorder::newArguments()
     }
 
     LIns* args[] = { INS_CONSTPTR(apn), argv_ins, callee_ins, argc_ins, global_ins, cx_ins };
     LIns* call_ins = lir->insCall(&js_Arguments_ci, args);
     guard(false, lir->ins_peq0(call_ins), OOM_EXIT);
     return call_ins;
 }
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_ARGUMENTS()
 {
     if (cx->fp->flags & JSFRAME_OVERRIDE_ARGS)
-        ABORT_TRACE("Can't trace |arguments| if |arguments| is assigned to");
+        RETURN_STOP_A("Can't trace |arguments| if |arguments| is assigned to");
 
     LIns* a_ins = get(&cx->fp->argsobj);
     LIns* args_ins;
     if (a_ins->opcode() == LIR_int) {
         // |arguments| is set to 0 by EnterFrame on this trace, so call to create it.
         args_ins = newArguments();
     } else {
         // Generate LIR to create arguments only if it has not already been created.
@@ -9384,230 +9400,230 @@ TraceRecorder::record_JSOP_ARGUMENTS()
         LIns* label2 = lir->ins0(LIR_label);
         br2->setTarget(label2);
 
         args_ins = lir->insLoad(LIR_ldp, mem_ins, 0);
     }
 
     stack(0, args_ins);
     set(&cx->fp->argsobj, args_ins);
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_DUP()
 {
     stack(0, get(&stackval(-1)));
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_DUP2()
 {
     stack(0, get(&stackval(-2)));
     stack(1, get(&stackval(-1)));
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_SWAP()
 {
     jsval& l = stackval(-2);
     jsval& r = stackval(-1);
     LIns* l_ins = get(&l);
     LIns* r_ins = get(&r);
     set(&r, l_ins);
     set(&l, r_ins);
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_PICK()
 {
     jsval* sp = cx->fp->regs->sp;
     jsint n = cx->fp->regs->pc[1];
     JS_ASSERT(sp - (n+1) >= StackBase(cx->fp));
     LIns* top = get(sp - (n+1));
     for (jsint i = 0; i < n; ++i)
         set(sp - (n+1) + i, get(sp - n + i));
     set(&sp[-1], top);
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_SETCONST()
 {
-    return JSRS_STOP;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_STOP;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_BITOR()
 {
-    return binary(LIR_or);
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return InjectStatus(binary(LIR_or));
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_BITXOR()
 {
-    return binary(LIR_xor);
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return InjectStatus(binary(LIR_xor));
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_BITAND()
 {
-    return binary(LIR_and);
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return InjectStatus(binary(LIR_and));
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_EQ()
 {
     return equality(false, true);
 }
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_NE()
 {
     return equality(true, true);
 }
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_LT()
 {
     return relational(LIR_flt, true);
 }
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_LE()
 {
     return relational(LIR_fle, true);
 }
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_GT()
 {
     return relational(LIR_fgt, true);
 }
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_GE()
 {
     return relational(LIR_fge, true);
 }
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_LSH()
 {
-    return binary(LIR_lsh);
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return InjectStatus(binary(LIR_lsh));
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_RSH()
 {
-    return binary(LIR_rsh);
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return InjectStatus(binary(LIR_rsh));
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_URSH()
 {
-    return binary(LIR_ush);
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return InjectStatus(binary(LIR_ush));
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_ADD()
 {
     jsval& r = stackval(-1);
     jsval& l = stackval(-2);
 
     if (!JSVAL_IS_PRIMITIVE(l)) {
-        ABORT_IF_XML(l);
+        RETURN_IF_XML_A(l);
         if (!JSVAL_IS_PRIMITIVE(r)) {
-            ABORT_IF_XML(r);
-            return call_imacro(add_imacros.obj_obj);
-        }
-        return call_imacro(add_imacros.obj_any);
+            RETURN_IF_XML_A(r);
+            return InjectStatus(call_imacro(add_imacros.obj_obj));
+        }
+        return InjectStatus(call_imacro(add_imacros.obj_any));
     }
     if (!JSVAL_IS_PRIMITIVE(r)) {
-        ABORT_IF_XML(r);
-        return call_imacro(add_imacros.any_obj);
+        RETURN_IF_XML_A(r);
+        return InjectStatus(call_imacro(add_imacros.any_obj));
     }
 
     if (JSVAL_IS_STRING(l) || JSVAL_IS_STRING(r)) {
         LIns* args[] = { stringify(r), stringify(l), cx_ins };
         LIns* concat = lir->insCall(&js_ConcatStrings_ci, args);
         guard(false, lir->ins_peq0(concat), OOM_EXIT);
         set(&l, concat);
-        return JSRS_CONTINUE;
-    }
-
-    return binary(LIR_fadd);
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+        return ARECORD_CONTINUE;
+    }
+
+    return InjectStatus(binary(LIR_fadd));
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_SUB()
 {
-    return binary(LIR_fsub);
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return InjectStatus(binary(LIR_fsub));
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_MUL()
 {
-    return binary(LIR_fmul);
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return InjectStatus(binary(LIR_fmul));
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_DIV()
 {
-    return binary(LIR_fdiv);
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return InjectStatus(binary(LIR_fdiv));
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_MOD()
 {
-    return binary(LIR_fmod);
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return InjectStatus(binary(LIR_fmod));
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_NOT()
 {
     jsval& v = stackval(-1);
     if (JSVAL_IS_SPECIAL(v)) {
         set(&v, lir->ins_eq0(lir->ins2i(LIR_eq, get(&v), 1)));
-        return JSRS_CONTINUE;
+        return ARECORD_CONTINUE;
     }
     if (isNumber(v)) {
         LIns* v_ins = get(&v);
         set(&v, lir->ins2(LIR_or, lir->ins2(LIR_feq, v_ins, lir->insImmf(0)),
                                   lir->ins_eq0(lir->ins2(LIR_feq, v_ins, v_ins))));
-        return JSRS_CONTINUE;
+        return ARECORD_CONTINUE;
     }
     if (JSVAL_TAG(v) == JSVAL_OBJECT) {
         set(&v, lir->ins_peq0(get(&v)));
-        return JSRS_CONTINUE;
+        return ARECORD_CONTINUE;
     }
     JS_ASSERT(JSVAL_IS_STRING(v));
     set(&v, lir->ins_peq0(lir->ins2(LIR_piand,
                                     lir->insLoad(LIR_ldp, get(&v), (int)offsetof(JSString, mLength)),
                                     INS_CONSTWORD(JSString::LENGTH_MASK))));
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_BITNOT()
 {
-    return unary(LIR_not);
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return InjectStatus(unary(LIR_not));
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_NEG()
 {
     jsval& v = stackval(-1);
 
     if (!JSVAL_IS_PRIMITIVE(v)) {
-        ABORT_IF_XML(v);
-        return call_imacro(unary_imacros.sign);
+        RETURN_IF_XML_A(v);
+        return InjectStatus(call_imacro(unary_imacros.sign));
     }
 
     if (isNumber(v)) {
         LIns* a = get(&v);
 
         /*
          * If we're a promoted integer, we have to watch out for 0s since -0 is
          * a double. Only follow this path if we're not an integer that's 0 and
@@ -9625,135 +9641,150 @@ TraceRecorder::record_JSOP_NEG()
                 guard(false, lir->ins2i(LIR_eq, a, 0), exit);
             }
             a = lir->ins1(LIR_i2f, a);
         } else {
             a = lir->ins1(LIR_fneg, a);
         }
 
         set(&v, a);
-        return JSRS_CONTINUE;
+        return ARECORD_CONTINUE;
     }
 
     if (JSVAL_IS_NULL(v)) {
         set(&v, lir->insImmf(-0.0));
-        return JSRS_CONTINUE;
+        return ARECORD_CONTINUE;
     }
 
     JS_ASSERT(JSVAL_TAG(v) == JSVAL_STRING || JSVAL_IS_SPECIAL(v));
 
     LIns* args[] = { get(&v), cx_ins };
     set(&v, lir->ins1(LIR_fneg,
                       lir->insCall(JSVAL_IS_STRING(v)
                                    ? &js_StringToNumber_ci
                                    : &js_BooleanOrUndefinedToNumber_ci,
                                    args)));
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_POS()
 {
     jsval& v = stackval(-1);
 
     if (!JSVAL_IS_PRIMITIVE(v)) {
-        ABORT_IF_XML(v);
-        return call_imacro(unary_imacros.sign);
+        RETURN_IF_XML_A(v);
+        return InjectStatus(call_imacro(unary_imacros.sign));
     }
 
     if (isNumber(v))
-        return JSRS_CONTINUE;
+        return ARECORD_CONTINUE;
 
     if (JSVAL_IS_NULL(v)) {
         set(&v, lir->insImmf(0));
-        return JSRS_CONTINUE;
+        return ARECORD_CONTINUE;
     }
 
     JS_ASSERT(JSVAL_TAG(v) == JSVAL_STRING || JSVAL_IS_SPECIAL(v));
 
     LIns* args[] = { get(&v), cx_ins };
     set(&v, lir->insCall(JSVAL_IS_STRING(v)
                          ? &js_StringToNumber_ci
                          : &js_BooleanOrUndefinedToNumber_ci,
                          args));
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_PRIMTOP()
 {
     // Either this opcode does nothing or we couldn't have traced here, because
     // we'd have thrown an exception -- so do nothing if we actually hit this.
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_OBJTOP()
 {
     jsval& v = stackval(-1);
-    ABORT_IF_XML(v);
-    return JSRS_CONTINUE;
-}
-
-JSRecordingStatus
+    RETURN_IF_XML_A(v);
+    return ARECORD_CONTINUE;
+}
+
+RecordingStatus
 TraceRecorder::getClassPrototype(JSObject* ctor, LIns*& proto_ins)
 {
+#ifdef DEBUG
+    JSTraceMonitor &localtm = JS_TRACE_MONITOR(cx);
+#endif
+
     jsval pval;
-
     if (!ctor->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom), &pval))
-        ABORT_TRACE_ERROR("error getting prototype from constructor");
+        RETURN_ERROR("error getting prototype from constructor");
+
+    /* For functions, this shold not reenter */
+    JS_ASSERT(localtm.recorder);
+
     if (JSVAL_TAG(pval) != JSVAL_OBJECT)
-        ABORT_TRACE("got primitive prototype from constructor");
+        RETURN_STOP("got primitive prototype from constructor");
 #ifdef DEBUG
     JSBool ok, found;
     uintN attrs;
     ok = JS_GetPropertyAttributes(cx, ctor, js_class_prototype_str, &attrs, &found);
     JS_ASSERT(ok);
     JS_ASSERT(found);
     JS_ASSERT((~attrs & (JSPROP_READONLY | JSPROP_PERMANENT)) == 0);
 #endif
     proto_ins = INS_CONSTOBJ(JSVAL_TO_OBJECT(pval));
-    return JSRS_CONTINUE;
-}
-
-JSRecordingStatus
+    return RECORD_CONTINUE;
+}
+
+RecordingStatus
 TraceRecorder::getClassPrototype(JSProtoKey key, LIns*& proto_ins)
 {
+#ifdef DEBUG
+    JSTraceMonitor &localtm = JS_TRACE_MONITOR(cx);
+#endif
+
     JSObject* proto;
     if (!js_GetClassPrototype(cx, globalObj, INT_TO_JSID(key), &proto))
-        ABORT_TRACE_ERROR("error in js_GetClassPrototype");
+        RETURN_ERROR("error in js_GetClassPrototype");
+
+    /* For functions, this shold not reenter */
+    JS_ASSERT(localtm.recorder);
+
     proto_ins = INS_CONSTOBJ(proto);
-    return JSRS_CONTINUE;
+    return RECORD_CONTINUE;
 }
 
 #define IGNORE_NATIVE_CALL_COMPLETE_CALLBACK ((JSSpecializedNative*)1)
 
-JSRecordingStatus
+RecordingStatus
 TraceRecorder::newString(JSObject* ctor, uint32 argc, jsval* argv, jsval* rval)
 {
     JS_ASSERT(argc == 1);
 
     if (!JSVAL_IS_PRIMITIVE(argv[0])) {
-        ABORT_IF_XML(argv[0]);
+        RETURN_IF_XML(argv[0]);
         return call_imacro(new_imacros.String);
     }
 
     LIns* proto_ins;
     CHECK_STATUS(getClassPrototype(ctor, proto_ins));
 
     LIns* args[] = { stringify(argv[0]), proto_ins, cx_ins };
     LIns* obj_ins = lir->insCall(&js_String_tn_ci, args);
     guard(false, lir->ins_peq0(obj_ins), OOM_EXIT);
 
     set(rval, obj_ins);
     pendingSpecializedNative = IGNORE_NATIVE_CALL_COMPLETE_CALLBACK;
-    return JSRS_CONTINUE;
-}
-
-JSRecordingStatus
+    return RECORD_CONTINUE;
+}
+
+RecordingStatus
 TraceRecorder::newArray(JSObject* ctor, uint32 argc, jsval* argv, jsval* rval)
 {
     LIns *proto_ins;
     CHECK_STATUS(getClassPrototype(ctor, proto_ins));
 
     LIns *arr_ins;
     if (argc == 0 || (argc == 1 && JSVAL_IS_NUMBER(argv[0]))) {
         // arr_ins = js_NewEmptyArray(cx, Array.prototype)
@@ -9780,17 +9811,17 @@ TraceRecorder::newArray(JSObject* ctor, 
         }
 
         if (argc > 0)
             stobj_set_fslot(arr_ins, JSSLOT_ARRAY_COUNT, INS_CONST(argc));
     }
 
     set(rval, arr_ins);
     pendingSpecializedNative = IGNORE_NATIVE_CALL_COMPLETE_CALLBACK;
-    return JSRS_CONTINUE;
+    return RECORD_CONTINUE;
 }
 
 JS_REQUIRES_STACK void
 TraceRecorder::propagateFailureToBuiltinStatus(LIns* ok_ins, LIns*& status_ins)
 {
     /*
      * Check the boolean return value (ok_ins) of a native JSNative,
      * JSFastNative, or JSPropertyOp hook for failure. On failure, set the
@@ -9859,17 +9890,17 @@ TraceRecorder::emitNativePropertyOp(JSSc
                                     (int) offsetof(InterpState, builtinStatus));
     propagateFailureToBuiltinStatus(ok_ins, status_ins);
     guard(true, lir->ins_eq0(status_ins), STATUS_EXIT);
 
     // Re-load the value--but this is currently unused, so commented out.
     //boxed_ins = lir->insLoad(LIR_ldp, vp_ins, 0);
 }
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK RecordingStatus
 TraceRecorder::emitNativeCall(JSSpecializedNative* sn, uintN argc, LIns* args[], bool rooted)
 {
     bool constructing = !!(sn->flags & JSTN_CONSTRUCTOR);
 
     if (JSTN_ERRTYPE(sn) == FAIL_STATUS) {
         // This needs to capture the pre-call state of the stack. So do not set
         // pendingSpecializedNative before taking this snapshot.
         JS_ASSERT(!pendingSpecializedNative);
@@ -9913,24 +9944,24 @@ TraceRecorder::emitNativeCall(JSSpeciali
 
     /*
      * The return value will be processed by NativeCallComplete since
      * we have to know the actual return value type for calls that return
      * jsval (like Array_p_pop).
      */
     pendingSpecializedNative = sn;
 
-    return JSRS_CONTINUE;
+    return RECORD_CONTINUE;
 }
 
 /*
  * Check whether we have a specialized implementation for this native
  * invocation.
  */
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK RecordingStatus
 TraceRecorder::callSpecializedNative(JSNativeTraceInfo *trcinfo, uintN argc,
                                      bool constructing)
 {
     JSStackFrame* fp = cx->fp;
     jsbytecode *pc = fp->regs->pc;
 
     jsval& fval = stackval(0 - (2 + argc));
     jsval& tval = stackval(0 - (1 + argc));
@@ -10025,20 +10056,20 @@ TraceRecorder::callSpecializedNative(JSN
 #if defined DEBUG
         JS_ASSERT(args[0] != (LIns *)0xcdcdcdcd);
 #endif
         return emitNativeCall(sn, argc, args, false);
 
 next_specialization:;
     } while ((sn++)->flags & JSTN_MORE);
 
-    return JSRS_STOP;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return RECORD_STOP;
+}
+
+JS_REQUIRES_STACK RecordingStatus
 TraceRecorder::callNative(uintN argc, JSOp mode)
 {
     LIns* args[5];
 
     JS_ASSERT(mode == JSOP_CALL || mode == JSOP_NEW || mode == JSOP_APPLY);
 
     jsval* vp = &stackval(0 - (2 + argc));
     JSObject* funobj = JSVAL_TO_OBJECT(vp[0]);
@@ -10048,17 +10079,17 @@ TraceRecorder::callNative(uintN argc, JS
     switch (argc) {
       case 1:
         if (isNumber(vp[2]) &&
             (native == js_math_ceil || native == js_math_floor || native == js_math_round)) {
             LIns* a = get(&vp[2]);
             if (isPromote(a)) {
                 set(&vp[0], a);
                 pendingSpecializedNative = IGNORE_NATIVE_CALL_COMPLETE_CALLBACK;
-                return JSRS_CONTINUE;
+                return RECORD_CONTINUE;
             }
         }
         break;
 
       case 2:
         if (isNumber(vp[2]) && isNumber(vp[3]) &&
             (native == js_math_min || native == js_math_max)) {
             LIns* a = get(&vp[2]);
@@ -10068,36 +10099,36 @@ TraceRecorder::callNative(uintN argc, JS
                 b = ::demote(lir, b);
                 set(&vp[0],
                     lir->ins1(LIR_i2f,
                               lir->ins_choose(lir->ins2((native == js_math_min)
                                                         ? LIR_lt
                                                         : LIR_gt, a, b),
                                               a, b)));
                 pendingSpecializedNative = IGNORE_NATIVE_CALL_COMPLETE_CALLBACK;
-                return JSRS_CONTINUE;
+                return RECORD_CONTINUE;
             }
         }
         break;
     }
 
     if (fun->flags & JSFUN_TRCINFO) {
         JSNativeTraceInfo *trcinfo = FUN_TRCINFO(fun);
         JS_ASSERT(trcinfo && (JSFastNative)fun->u.n.native == trcinfo->native);
 
         /* Try to call a type specialized version of the native. */
         if (trcinfo->specializations) {
-            JSRecordingStatus status = callSpecializedNative(trcinfo, argc, mode == JSOP_NEW);
-            if (status != JSRS_STOP)
+            RecordingStatus status = callSpecializedNative(trcinfo, argc, mode == JSOP_NEW);
+            if (status != RECORD_STOP)
                 return status;
         }
     }
 
     if (native == js_fun_apply || native == js_fun_call)
-        ABORT_TRACE("trying to call native apply or call");
+        RETURN_STOP("trying to call native apply or call");
 
     // Allocate the vp vector and emit code to root it.
     uintN vplen = 2 + JS_MAX(argc, unsigned(FUN_MINARGS(fun))) + fun->u.n.extra;
     if (!(fun->flags & JSFUN_FAST_NATIVE))
         vplen++; // slow native return value slot
     LIns* invokevp_ins = lir->insAlloc(vplen * sizeof(jsval));
 
     // vp[0] is the callee.
@@ -10111,20 +10142,20 @@ TraceRecorder::callNative(uintN argc, JS
         if (!clasp)
             clasp = &js_ObjectClass;
         JS_ASSERT(((jsuword) clasp & 3) == 0);
 
         // Abort on |new Function|. js_NewInstance would allocate a regular-
         // sized JSObject, not a Function-sized one. (The Function ctor would
         // deep-bail anyway but let's not go there.)
         if (clasp == &js_FunctionClass)
-            ABORT_TRACE("new Function");
+            RETURN_STOP("new Function");
 
         if (clasp->getObjectOps)
-            ABORT_TRACE("new with non-native ops");
+            RETURN_STOP("new with non-native ops");
 
         args[0] = INS_CONSTOBJ(funobj);
         args[1] = INS_CONSTPTR(clasp);
         args[2] = cx_ins;
         newobj_ins = lir->insCall(&js_NewInstance_ci, args);
         guard(false, lir->ins_peq0(newobj_ins), OOM_EXIT);
         this_ins = newobj_ins; /* boxing an object is a no-op */
     } else if (JSFUN_BOUND_METHOD_TEST(fun->flags)) {
@@ -10137,23 +10168,23 @@ TraceRecorder::callNative(uintN argc, JS
          * For slow natives we have to ensure the object is substituted for the
          * appropriate global object or boxed object value. JSOP_NEW allocates its
          * own object so it's guaranteed to have a valid 'this' value.
          */
         if (!(fun->flags & JSFUN_FAST_NATIVE)) {
             if (JSVAL_IS_NULL(vp[1])) {
                 JSObject* thisObj = js_ComputeThis(cx, JS_FALSE, vp + 2);
                 if (!thisObj)
-                    ABORT_TRACE_ERROR("error in js_ComputeGlobalThis");
+                    RETURN_ERROR("error in js_ComputeGlobalThis");
                 this_ins = INS_CONSTOBJ(thisObj);
             } else if (!JSVAL_IS_OBJECT(vp[1])) {
-                ABORT_TRACE("slow native(primitive, args)");
+                RETURN_STOP("slow native(primitive, args)");
             } else {
                 if (guardClass(JSVAL_TO_OBJECT(vp[1]), this_ins, &js_WithClass, snapshot(MISMATCH_EXIT)))
-                    ABORT_TRACE("can't trace slow native invocation on With object");
+                    RETURN_STOP("can't trace slow native invocation on With object");
 
                 this_ins = lir->ins_choose(lir->ins_peq0(stobj_get_parent(this_ins)),
                                            INS_CONSTOBJ(globalObj),
                                            this_ins);
             }
         }
         this_ins = box_jsval(vp[1], this_ins);
     }
@@ -10162,35 +10193,35 @@ TraceRecorder::callNative(uintN argc, JS
     // Populate argv.
     for (uintN n = 2; n < 2 + argc; n++) {
         LIns* i = box_jsval(vp[n], get(&vp[n]));
         lir->insStorei(i, invokevp_ins, n * sizeof(jsval));
 
         // For a very long argument list we might run out of LIR space, so
         // check inside the loop.
         if (outOfMemory())
-            ABORT_TRACE("out of memory in argument list");
+            RETURN_STOP("out of memory in argument list");
     }
 
     // Populate extra slots, including the return value slot for a slow native.
     if (2 + argc < vplen) {
         LIns* undef_ins = INS_CONSTWORD(JSVAL_VOID);
         for (uintN n = 2 + argc; n < vplen; n++) {
             lir->insStorei(undef_ins, invokevp_ins, n * sizeof(jsval));
 
             if (outOfMemory())
-                ABORT_TRACE("out of memory in extra slots");
+                RETURN_STOP("out of memory in extra slots");
         }
     }
 
     // Set up arguments for the JSNative or JSFastNative.
     uint32 types;
     if (fun->flags & JSFUN_FAST_NATIVE) {
         if (mode == JSOP_NEW)
-            ABORT_TRACE("untraceable fast native constructor");
+            RETURN_STOP("untraceable fast native constructor");
         native_rval_ins = invokevp_ins;
         args[0] = invokevp_ins;
         args[1] = lir->insImm(argc);
         args[2] = cx_ins;
         types = ARGSIZE_I << (0*ARGSIZE_SHIFT) |
                 ARGSIZE_P << (1*ARGSIZE_SHIFT) |
                 ARGSIZE_I << (2*ARGSIZE_SHIFT) |
                 ARGSIZE_P << (3*ARGSIZE_SHIFT);
@@ -10239,24 +10270,24 @@ TraceRecorder::callNative(uintN argc, JS
     lir->insStorei(INS_CONST(vplen), lirbuf->state, offsetof(InterpState, nativeVpLen));
     lir->insStorei(invokevp_ins, lirbuf->state, offsetof(InterpState, nativeVp));
 
     // argc is the original argc here. It is used to calculate where to place
     // the return value.
     return emitNativeCall(&generatedSpecializedNative, argc, args, true);
 }
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK RecordingStatus
 TraceRecorder::functionCall(uintN argc, JSOp mode)
 {
     jsval& fval = stackval(0 - (2 + argc));
     JS_ASSERT(&fval >= StackBase(cx->fp));
 
     if (!VALUE_IS_FUNCTION(cx, fval))
-        ABORT_TRACE("callee is not a function");
+        RETURN_STOP("callee is not a function");
 
     jsval& tval = stackval(0 - (1 + argc));
 
     /*
      * If callee is not constant, it's a shapeless call and we have to guard
      * explicitly that we will get this callee again at runtime.
      */
     if (!get(&fval)->isconstp())
@@ -10289,55 +10320,55 @@ TraceRecorder::functionCall(uintN argc, 
         JSNative native = fun->u.n.native;
         jsval* argv = &tval + 1;
         if (native == js_Array)
             return newArray(JSVAL_TO_OBJECT(fval), argc, argv, &fval);
         if (native == js_String && argc == 1) {
             if (mode == JSOP_NEW)
                 return newString(JSVAL_TO_OBJECT(fval), 1, argv, &fval);
             if (!JSVAL_IS_PRIMITIVE(argv[0])) {
-                ABORT_IF_XML(argv[0]);
+                RETURN_IF_XML(argv[0]);
                 return call_imacro(call_imacros.String);
             }
             set(&fval, stringify(argv[0]));
             pendingSpecializedNative = IGNORE_NATIVE_CALL_COMPLETE_CALLBACK;
-            return JSRS_CONTINUE;
+            return RECORD_CONTINUE;
         }
     }
 
     return callNative(argc, mode);
 }
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_NEW()
 {
     uintN argc = GET_ARGC(cx->fp->regs->pc);
     cx->fp->assertValidStackDepth(argc + 2);
-    return functionCall(argc, JSOP_NEW);
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return InjectStatus(functionCall(argc, JSOP_NEW));
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_DELNAME()
 {
-    return JSRS_STOP;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_STOP;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_DELPROP()
 {
-    return JSRS_STOP;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_STOP;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_DELELEM()
 {
-    return JSRS_STOP;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_STOP;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_TYPEOF()
 {
     jsval& r = stackval(-1);
     LIns* type;
     if (JSVAL_IS_STRING(r)) {
         type = INS_ATOM(cx->runtime->atomState.typeAtoms[JSTYPE_STRING]);
     } else if (isNumber(r)) {
         type = INS_ATOM(cx->runtime->atomState.typeAtoms[JSTYPE_NUMBER]);
@@ -10351,146 +10382,146 @@ TraceRecorder::record_JSOP_TYPEOF()
             JS_ASSERT(r == JSVAL_TRUE || r == JSVAL_FALSE || r == JSVAL_VOID);
             type = lir->insCall(&js_TypeOfBoolean_ci, args);
         } else {
             JS_ASSERT(JSVAL_TAG(r) == JSVAL_OBJECT);
             type = lir->insCall(&js_TypeOfObject_ci, args);
         }
     }
     set(&r, type);
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_VOID()
 {
     stack(-1, INS_CONST(JSVAL_TO_SPECIAL(JSVAL_VOID)));
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_INCNAME()
 {
     return incName(1);
 }
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_INCPROP()
 {
     return incProp(1);
 }
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_INCELEM()
 {
-    return incElem(1);
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return InjectStatus(incElem(1));
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_DECNAME()
 {
     return incName(-1);
 }
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_DECPROP()
 {
     return incProp(-1);
 }
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_DECELEM()
 {
-    return incElem(-1);
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return InjectStatus(incElem(-1));
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::incName(jsint incr, bool pre)
 {
     jsval* vp;
     LIns* v_ins;
     LIns* v_after;
     NameResult nr;
 
-    CHECK_STATUS(name(vp, v_ins, nr));
+    CHECK_STATUS_A(name(vp, v_ins, nr));
     jsval v = nr.tracked ? *vp : nr.v;
-    CHECK_STATUS(incHelper(v, v_ins, v_after, incr));
+    CHECK_STATUS_A(incHelper(v, v_ins, v_after, incr));
     LIns* v_result = pre ? v_after : v_ins;
     if (nr.tracked) {
         set(vp, v_after);
         stack(0, v_result);
-        return JSRS_CONTINUE;
+        return ARECORD_CONTINUE;
     }
 
     if (OBJ_GET_CLASS(cx, nr.obj) != &js_CallClass)
-        ABORT_TRACE("incName on unsupported object class");
-
-    CHECK_STATUS(setCallProp(nr.obj, nr.obj_ins, nr.sprop, v_after, v));
+        RETURN_STOP_A("incName on unsupported object class");
+
+    CHECK_STATUS_A(setCallProp(nr.obj, nr.obj_ins, nr.sprop, v_after, v));
     stack(0, v_result);
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_NAMEINC()
 {
     return incName(1, false);
 }
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_PROPINC()
 {
     return incProp(1, false);
 }
 
 // XXX consolidate with record_JSOP_GETELEM code...
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_ELEMINC()
 {
-    return incElem(1, false);
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return InjectStatus(incElem(1, false));
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_NAMEDEC()
 {
     return incName(-1, false);
 }
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_PROPDEC()
 {
     return incProp(-1, false);
 }
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_ELEMDEC()
 {
-    return incElem(-1, false);
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return InjectStatus(incElem(-1, false));
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_GETPROP()
 {
     return getProp(stackval(-1));
 }
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_SETPROP()
 {
     jsval& l = stackval(-2);
     if (JSVAL_IS_PRIMITIVE(l))
-        ABORT_TRACE("primitive this for SETPROP");
+        RETURN_STOP_A("primitive this for SETPROP");
 
     JSObject* obj = JSVAL_TO_OBJECT(l);
     if (obj->map->ops->setProperty != js_SetProperty)
-        ABORT_TRACE("non-native JSObjectOps::setProperty");
-    return JSRS_CONTINUE;
+        RETURN_STOP_A("non-native JSObjectOps::setProperty");
+    return ARECORD_CONTINUE;
 }
 
 /* Emit a specialized, inlined copy of js_NativeSet. */
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK RecordingStatus
 TraceRecorder::nativeSet(JSObject* obj, LIns* obj_ins, JSScopeProperty* sprop,
                          jsval v, LIns* v_ins)
 {
     JSScope* scope = OBJ_SCOPE(obj);
     uint32 slot = sprop->slot;
 
     /*
      * We do not trace assignment to properties that have both a nonstub setter
@@ -10522,54 +10553,54 @@ TraceRecorder::nativeSet(JSObject* obj, 
         emitNativePropertyOp(scope, sprop, obj_ins, true, boxed_ins);
 
     // Store the value, if this property has a slot.
     if (slot != SPROP_INVALID_SLOT) {
         JS_ASSERT(SPROP_HAS_VALID_SLOT(sprop, scope));
         JS_ASSERT(!(sprop->attrs & JSPROP_SHARED));
         if (obj == globalObj) {
             if (!lazilyImportGlobalSlot(slot))
-                ABORT_TRACE("lazy import of global slot failed");
+                RETURN_STOP("lazy import of global slot failed");
             set(&STOBJ_GET_SLOT(obj, slot), v_ins);
         } else {
             LIns* dslots_ins = NULL;
             stobj_set_slot(obj_ins, slot, dslots_ins, boxed_ins);
         }
     }
 
-    return JSRS_CONTINUE;
+    return RECORD_CONTINUE;
 }
 
 static JSBool FASTCALL
 MethodWriteBarrier(JSContext* cx, JSObject* obj, JSScopeProperty* sprop, JSObject* funobj)
 {
     JSAutoTempValueRooter tvr(cx, funobj);
 
     return OBJ_SCOPE(obj)->methodWriteBarrier(cx, sprop, tvr.value());
 }
 JS_DEFINE_CALLINFO_4(static, BOOL_FAIL, MethodWriteBarrier, CONTEXT, OBJECT, SCOPEPROP, OBJECT,
                      0, 0)
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK RecordingStatus
 TraceRecorder::setProp(jsval &l, JSPropCacheEntry* entry, JSScopeProperty* sprop,
                        jsval &v, LIns*& v_ins)
 {
     if (entry == JS_NO_PROP_CACHE_FILL)
-        ABORT_TRACE("can't trace uncacheable property set");
+        RETURN_STOP("can't trace uncacheable property set");
     JS_ASSERT_IF(PCVCAP_TAG(entry->vcap) >= 1, sprop->attrs & JSPROP_SHARED);
     if (!SPROP_HAS_STUB_SETTER(sprop) && sprop->slot != SPROP_INVALID_SLOT)
-        ABORT_TRACE("can't trace set of property with setter and slot");
+        RETURN_STOP("can't trace set of property with setter and slot");
     if (sprop->attrs & JSPROP_SETTER)
-        ABORT_TRACE("can't trace JavaScript function setter");
+        RETURN_STOP("can't trace JavaScript function setter");
 
     // These two cases are errors and can't be traced.
     if (sprop->attrs & JSPROP_GETTER)
-        ABORT_TRACE("can't assign to property with script getter but no setter");
+        RETURN_STOP("can't assign to property with script getter but no setter");
     if (sprop->attrs & JSPROP_READONLY)
-        ABORT_TRACE("can't assign to readonly property");
+        RETURN_STOP("can't assign to readonly property");
 
     JS_ASSERT(!JSVAL_IS_PRIMITIVE(l));
     JSObject* obj = JSVAL_TO_OBJECT(l);
     LIns* obj_ins = get(&l);
     JSScope* scope = OBJ_SCOPE(obj);
 
     JS_ASSERT_IF(entry->vcap == PCVCAP_MAKE(entry->kshape, 0, 0), scope->has(sprop));
 
@@ -10581,17 +10612,17 @@ TraceRecorder::setProp(jsval &l, JSPropC
     /*
      * Setting a function-valued property might need to rebrand the object, so
      * we emit a call to the method write barrier. There's no need to guard on
      * this, because functions have distinct trace-type from other values and
      * branded-ness is implied by the shape, which we've already guarded on.
      */
     if (scope->branded() && VALUE_IS_FUNCTION(cx, v) && entry->directHit()) {
         if (obj == globalObj)
-            ABORT_TRACE("can't trace function-valued property set in branded global scope");
+            RETURN_STOP("can't trace function-valued property set in branded global scope");
 
         LIns* args[] = { v_ins, INS_CONSTSPROP(sprop), obj_ins, cx_ins };
         LIns* ok_ins = lir->insCall(&MethodWriteBarrier_ci, args);
         guard(false, lir->ins_eq0(ok_ins), OOM_EXIT);
     }
 
     // Find obj2. If entry->adding(), the TAG bits are all 0.
     JSObject* obj2 = obj;
@@ -10610,88 +10641,88 @@ TraceRecorder::setProp(jsval &l, JSPropC
     JS_ASSERT(scope->object == obj2);
     JS_ASSERT(scope->has(sprop));
     JS_ASSERT_IF(obj2 != obj, sprop->attrs & JSPROP_SHARED);
 
     // Add a property to the object if necessary.
     if (entry->adding()) {
         JS_ASSERT(!(sprop->attrs & JSPROP_SHARED));
         if (obj == globalObj)
-            ABORT_TRACE("adding a property to the global object");
+            RETURN_STOP("adding a property to the global object");
 
         LIns* args[] = { INS_CONSTSPROP(sprop), obj_ins, cx_ins };
         LIns* ok_ins = lir->insCall(&js_AddProperty_ci, args);
         guard(false, lir->ins_eq0(ok_ins), OOM_EXIT);
     }
 
     return nativeSet(obj, obj_ins, sprop, v, v_ins);
 }
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK RecordingStatus
 TraceRecorder::setCallProp(JSObject *callobj, LIns *callobj_ins, JSScopeProperty *sprop,
                            LIns *v_ins, jsval v)
 {
     // Set variables in on-trace-stack call objects by updating the tracker.
     JSStackFrame *fp = frameIfInRange(callobj);
     if (fp) {
         jsint slot = JSVAL_TO_INT(SPROP_USERID(sprop));
         if (sprop->setter == SetCallArg) {
             jsval *vp2 = &fp->argv[slot];
             set(vp2, v_ins);
-            return JSRS_CONTINUE;
+            return RECORD_CONTINUE;
         }
         if (sprop->setter == SetCallVar) {
             jsval *vp2 = &fp->slots[slot];
             set(vp2, v_ins);
-            return JSRS_CONTINUE;
-        }
-        ABORT_TRACE("can't trace special CallClass setter");
+            return RECORD_CONTINUE;
+        }
+        RETURN_STOP("can't trace special CallClass setter");
     }
 
     // Set variables in off-trace-stack call objects by calling standard builtins.
     const CallInfo* ci = NULL;
     if (sprop->setter == SetCallArg)
         ci = &js_SetCallArg_ci;
     else if (sprop->setter == SetCallVar)
         ci = &js_SetCallVar_ci;
     else
-        ABORT_TRACE("can't trace special CallClass setter");
+        RETURN_STOP("can't trace special CallClass setter");
 
     LIns* args[] = {
         box_jsval(v, v_ins),
         INS_CONST(SPROP_USERID(sprop)),
         callobj_ins,
         cx_ins
     };
     LIns* call_ins = lir->insCall(ci, args);
     guard(false, addName(lir->ins_eq0(call_ins), "guard(set upvar)"), STATUS_EXIT);
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return RECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_SetPropHit(JSPropCacheEntry* entry, JSScopeProperty* sprop)
 {
     jsval& r = stackval(-1);
     jsval& l = stackval(-2);
     LIns* v_ins;
-    CHECK_STATUS(setProp(l, entry, sprop, r, v_ins));
+    CHECK_STATUS_A(setProp(l, entry, sprop, r, v_ins));
 
     jsbytecode* pc = cx->fp->regs->pc;
     switch (*pc) {
       case JSOP_SETPROP:
       case JSOP_SETNAME:
       case JSOP_SETMETHOD:
         if (pc[JSOP_SETPROP_LENGTH] != JSOP_POP)
             set(&l, v_ins);
         break;
 
       default:;
     }
 
-    return JSRS_CONTINUE;
+    return ARECORD_CONTINUE;
 }
 
 JS_REQUIRES_STACK VMSideExit*
 TraceRecorder::enterDeepBailCall()
 {
     // Take snapshot for js_DeepBail and store it in cx->bailExit.
     VMSideExit* exit = snapshot(DEEP_BAIL_EXIT);
     lir->insStorei(INS_CONSTPTR(exit), cx_ins, offsetof(JSContext, bailExit));
@@ -10759,39 +10790,39 @@ GetPropertyByName(JSContext* cx, JSObjec
     }
     return cx->interpState->builtinStatus == 0;
 }
 JS_DEFINE_CALLINFO_4(static, BOOL_FAIL, GetPropertyByName, CONTEXT, OBJECT, STRINGPTR, JSVALPTR,
                      0, 0)
 
 // Convert the value in a slot to a string and store the resulting string back
 // in the slot (typically in order to root it).
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK RecordingStatus
 TraceRecorder::primitiveToStringInPlace(jsval* vp)
 {
     jsval v = *vp;
     JS_ASSERT(JSVAL_IS_PRIMITIVE(v));
 
     if (!JSVAL_IS_STRING(v)) {
         // v is not a string. Turn it into one. js_ValueToString is safe
         // because v is not an object.
         JSString *str = js_ValueToString(cx, v);
         if (!str)
-            ABORT_TRACE_ERROR("failed to stringify element id");
+            RETURN_ERROR("failed to stringify element id");
         v = STRING_TO_JSVAL(str);
         set(vp, stringify(*vp));
 
         // Write the string back to the stack to save the interpreter some work
         // and to ensure snapshots get the correct type for this slot.
         *vp = v;
     }
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return RECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK RecordingStatus
 TraceRecorder::getPropertyByName(LIns* obj_ins, jsval* idvalp, jsval* outp)
 {
     CHECK_STATUS(primitiveToStringInPlace(idvalp));
     enterDeepBailCall();
 
     // Call GetPropertyByName. The vp parameter points to stack because this is
     // what the interpreter currently does. obj and id are rooted on the
     // interpreter stack, but the slot at vp is not a root.
@@ -10802,62 +10833,62 @@ TraceRecorder::getPropertyByName(LIns* o
 
     // GetPropertyByName can assign to *idvalp, so the tracker has an incorrect
     // entry for that address. Correct it. (If the value in the address is
     // never used again, the usual case, Nanojit will kill this load.)
     tracker.set(idvalp, lir->insLoad(LIR_ldp, idvalp_ins, 0));
 
     finishGetProp(obj_ins, vp_ins, ok_ins, outp);
     leaveDeepBailCall();
-    return JSRS_CONTINUE;
+    return RECORD_CONTINUE;
 }
 
 static JSBool FASTCALL
 GetPropertyByIndex(JSContext* cx, JSObject* obj, int32 index, jsval* vp)
 {
     js_LeaveTraceIfGlobalObject(cx, obj);
 
     JSAutoTempIdRooter idr(cx);
     if (!js_Int32ToId(cx, index, idr.addr()) || !obj->getProperty(cx, idr.id(), vp)) {
         js_SetBuiltinError(cx);
         return JS_FALSE;
     }
     return cx->interpState->builtinStatus == 0;
 }
 JS_DEFINE_CALLINFO_4(static, BOOL_FAIL, GetPropertyByIndex, CONTEXT, OBJECT, INT32, JSVALPTR, 0, 0)
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK RecordingStatus
 TraceRecorder::getPropertyByIndex(LIns* obj_ins, LIns* index_ins, jsval* outp)
 {
     index_ins = makeNumberInt32(index_ins);
 
     // See note in getPropertyByName about vp.
     enterDeepBailCall();
     LIns* vp_ins = addName(lir->insAlloc(sizeof(jsval)), "vp");
     LIns* args[] = {vp_ins, index_ins, obj_ins, cx_ins};
     LIns* ok_ins = lir->insCall(&GetPropertyByIndex_ci, args);
     finishGetProp(obj_ins, vp_ins, ok_ins, outp);
     leaveDeepBailCall();
-    return JSRS_CONTINUE;
+    return RECORD_CONTINUE;
 }
 
 static JSBool FASTCALL
 GetPropertyById(JSContext* cx, JSObject* obj, jsid id, jsval* vp)
 {
     js_LeaveTraceIfGlobalObject(cx, obj);
     if (!obj->getProperty(cx, id, vp)) {
         js_SetBuiltinError(cx);
         return JS_FALSE;
     }
     return cx->interpState->builtinStatus == 0;
 }
 JS_DEFINE_CALLINFO_4(static, BOOL_FAIL, GetPropertyById,
                      CONTEXT, OBJECT, JSVAL, JSVALPTR,                  0, 0)
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK RecordingStatus
 TraceRecorder::getPropertyById(LIns* obj_ins, jsval* outp)
 {
     // Find the atom.
     JSAtom* atom;
     jsbytecode* pc = cx->fp->regs->pc;
     const JSCodeSpec& cs = js_CodeSpec[*pc];
     if (*pc == JSOP_LENGTH) {
         atom = cx->runtime->atomState.lengthAtom;
@@ -10871,17 +10902,17 @@ TraceRecorder::getPropertyById(LIns* obj
     // Call GetPropertyById. See note in getPropertyByName about vp.
     enterDeepBailCall();
     jsid id = ATOM_TO_JSID(atom);
     LIns* vp_ins = addName(lir->insAlloc(sizeof(jsval)), "vp");
     LIns* args[] = {vp_ins, INS_CONSTWORD(id), obj_ins, cx_ins};
     LIns* ok_ins = lir->insCall(&GetPropertyById_ci, args);
     finishGetProp(obj_ins, vp_ins, ok_ins, outp);
     leaveDeepBailCall();
-    return JSRS_CONTINUE;
+    return RECORD_CONTINUE;
 }
 
 /* Manually inlined, specialized copy of js_NativeGet. */
 static JSBool FASTCALL
 GetPropertyWithNativeGetter(JSContext* cx, JSObject* obj, JSScopeProperty* sprop, jsval* vp)
 {
     js_LeaveTraceIfGlobalObject(cx, obj);
 
@@ -10903,76 +10934,76 @@ GetPropertyWithNativeGetter(JSContext* c
         js_SetBuiltinError(cx);
         return JS_FALSE;
     }
     return cx->interpState->builtinStatus == 0;
 }
 JS_DEFINE_CALLINFO_4(static, BOOL_FAIL, GetPropertyWithNativeGetter,
                      CONTEXT, OBJECT, SCOPEPROP, JSVALPTR,              0, 0)
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK RecordingStatus
 TraceRecorder::getPropertyWithNativeGetter(LIns* obj_ins, JSScopeProperty* sprop, jsval* outp)
 {
     JS_ASSERT(!(sprop->attrs & JSPROP_GETTER));
     JS_ASSERT(sprop->slot == SPROP_INVALID_SLOT);
     JS_ASSERT(!SPROP_HAS_STUB_GETTER_OR_IS_METHOD(sprop));
 
     // Call GetPropertyWithNativeGetter. See note in getPropertyByName about vp.
     // FIXME - We should call the getter directly. Using a builtin function for
     // now because it buys some extra asserts. See bug 508310.
     enterDeepBailCall();
     LIns* vp_ins = addName(lir->insAlloc(sizeof(jsval)), "vp");
     LIns* args[] = {vp_ins, INS_CONSTPTR(sprop), obj_ins, cx_ins};
     LIns* ok_ins = lir->insCall(&GetPropertyWithNativeGetter_ci, args);
     finishGetProp(obj_ins, vp_ins, ok_ins, outp);
     leaveDeepBailCall();
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return RECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_GETELEM()
 {
     bool call = *cx->fp->regs->pc == JSOP_CALLELEM;
 
     jsval& idx = stackval(-1);
     jsval& lval = stackval(-2);
 
     LIns* obj_ins = get(&lval);
     LIns* idx_ins = get(&idx);
 
     // Special case for array-like access of strings.
     if (JSVAL_IS_STRING(lval) && isInt32(idx)) {
         if (call)
-            ABORT_TRACE("JSOP_CALLELEM on a string");
+            RETURN_STOP_A("JSOP_CALLELEM on a string");
         int i = asInt32(idx);
         if (size_t(i) >= JSVAL_TO_STRING(lval)->length())
-            ABORT_TRACE("Invalid string index in JSOP_GETELEM");
+            RETURN_STOP_A("Invalid string index in JSOP_GETELEM");
         idx_ins = makeNumberInt32(idx_ins);
         LIns* args[] = { idx_ins, obj_ins, cx_ins };
         LIns* unitstr_ins = lir->insCall(&js_String_getelem_ci, args);
         guard(false, lir->ins_peq0(unitstr_ins), MISMATCH_EXIT);
         set(&lval, unitstr_ins);
-        return JSRS_CONTINUE;
+        return ARECORD_CONTINUE;
     }
 
     if (JSVAL_IS_PRIMITIVE(lval))
-        ABORT_TRACE("JSOP_GETLEM on a primitive");
-    ABORT_IF_XML(lval);
+        RETURN_STOP_A("JSOP_GETLEM on a primitive");
+    RETURN_IF_XML_A(lval);
 
     JSObject* obj = JSVAL_TO_OBJECT(lval);
     if (obj == globalObj)
-        ABORT_TRACE("JSOP_GETELEM on global");
+        RETURN_STOP_A("JSOP_GETELEM on global");
     LIns* v_ins;
 
     /* Property access using a string name or something we have to stringify. */
     if (!JSVAL_IS_INT(idx)) {
         if (!JSVAL_IS_PRIMITIVE(idx))
-            ABORT_TRACE("object used as index");
-
-        return getPropertyByName(obj_ins, &idx, &lval);
+            RETURN_STOP_A("object used as index");
+
+        return InjectStatus(getPropertyByName(obj_ins, &idx, &lval));
     }
 
     if (STOBJ_GET_CLASS(obj) == &js_ArgumentsClass) {
         unsigned depth;
         JSStackFrame *afp = guardArguments(obj, obj_ins, &depth);
         if (afp) {
             uintN int_idx = JSVAL_TO_INT(idx);
             jsval* vp = &afp->argv[int_idx];
@@ -10992,17 +11023,17 @@ TraceRecorder::record_JSOP_GETELEM()
                     // Guard that the argument has the same type on trace as during recording.
                     LIns* typemap_ins;
                     if (callDepth == depth) {
                         // In this case, we are in the same frame where the arguments object was created.
                         // The entry type map is not necessarily up-to-date, so we capture a new type map
                         // for this point in the code.
                         unsigned stackSlots = NativeStackSlots(cx, 0 /* callDepth */);
                         if (stackSlots * sizeof(JSTraceType) > LirBuffer::MAX_SKIP_PAYLOAD_SZB)
-                            ABORT_TRACE("|arguments| requires saving too much stack");
+                            RETURN_STOP_A("|arguments| requires saving too much stack");
                         JSTraceType* typemap = new (*traceMonitor->dataAlloc) JSTraceType[stackSlots];
                         DetermineTypesVisitor detVisitor(*this, typemap);
                         VisitStackSlots(detVisitor, cx, 0);
                         typemap_ins = INS_CONSTPTR(typemap + 2 /* callee, this */);
                     } else {
                         // In this case, we are in a deeper frame from where the arguments object was
                         // created. The type map at the point of the call out from the creation frame
                         // is accurate.
@@ -11036,34 +11067,34 @@ TraceRecorder::record_JSOP_GETELEM()
                 } else {
                     guard(false, lir->ins2(LIR_ult, idx_ins, INS_CONST(afp->argc)),
                           snapshot(BRANCH_EXIT));
                     v_ins = INS_VOID();
                 }
             }
             JS_ASSERT(v_ins);
             set(&lval, v_ins);
-            return JSRS_CONTINUE;
-        }
-        ABORT_TRACE("can't reach arguments object's frame");
+            return ARECORD_CONTINUE;
+        }
+        RETURN_STOP_A("can't reach arguments object's frame");
     }
     if (js_IsDenseArray(obj)) {
         // Fast path for dense arrays accessed with a integer index.
         jsval* vp;
         LIns* addr_ins;
 
         guardDenseArray(obj, obj_ins, BRANCH_EXIT);
-        CHECK_STATUS(denseArrayElement(lval, idx, vp, v_ins, addr_ins));
+        CHECK_STATUS_A(denseArrayElement(lval, idx, vp, v_ins, addr_ins));
         set(&lval, v_ins);
         if (call)
             set(&idx, obj_ins);
-        return JSRS_CONTINUE;
-    }
-
-    return getPropertyByIndex(obj_ins, idx_ins, &lval);
+        return ARECORD_CONTINUE;
+    }
+
+    return InjectStatus(getPropertyByIndex(obj_ins, idx_ins, &lval));
 }
 
 /* Functions used by JSOP_SETELEM */
 
 static JSBool FASTCALL
 SetPropertyByName(JSContext* cx, JSObject* obj, JSString** namep, jsval* vp)
 {
     js_LeaveTraceIfGlobalObject(cx, obj);
@@ -11089,17 +11120,17 @@ InitPropertyByName(JSContext* cx, JSObje
         js_SetBuiltinError(cx);
         return JS_FALSE;
     }
     return cx->interpState->builtinStatus == 0;
 }
 JS_DEFINE_CALLINFO_4(static, BOOL_FAIL, InitPropertyByName, CONTEXT, OBJECT, STRINGPTR, JSVAL,
                      0, 0)
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK RecordingStatus
 TraceRecorder::initOrSetPropertyByName(LIns* obj_ins, jsval* idvalp, jsval* rvalp, bool init)
 {
     CHECK_STATUS(primitiveToStringInPlace(idvalp));
 
     LIns* rval_ins = box_jsval(*rvalp, get(rvalp));
 
     enterDeepBailCall();
 
@@ -11113,17 +11144,17 @@ TraceRecorder::initOrSetPropertyByName(L
         LIns* vp_ins = addName(lir->insAlloc(sizeof(jsval)), "vp");
         lir->insStorei(rval_ins, vp_ins, 0);
         LIns* args[] = {vp_ins, idvalp_ins, obj_ins, cx_ins};
         ok_ins = lir->insCall(&SetPropertyByName_ci, args);
     }
     pendingGuardCondition = ok_ins;
 
     leaveDeepBailCall();
-    return JSRS_CONTINUE;
+    return RECORD_CONTINUE;
 }
 
 static JSBool FASTCALL
 SetPropertyByIndex(JSContext* cx, JSObject* obj, int32 index, jsval* vp)
 {
     js_LeaveTraceIfGlobalObject(cx, obj);
 
     JSAutoTempIdRooter idr(cx);
@@ -11145,17 +11176,17 @@ InitPropertyByIndex(JSContext* cx, JSObj
         !obj->defineProperty(cx, idr.id(), val, NULL, NULL, JSPROP_ENUMERATE)) {
         js_SetBuiltinError(cx);
         return JS_FALSE;
     }
     return cx->interpState->builtinStatus == 0;
 }
 JS_DEFINE_CALLINFO_4(static, BOOL_FAIL, InitPropertyByIndex, CONTEXT, OBJECT, INT32, JSVAL, 0, 0)
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK RecordingStatus
 TraceRecorder::initOrSetPropertyByIndex(LIns* obj_ins, LIns* index_ins, jsval* rvalp, bool init)
 {
     index_ins = makeNumberInt32(index_ins);
 
     LIns* rval_ins = box_jsval(*rvalp, get(rvalp));
 
     enterDeepBailCall();
 
@@ -11168,49 +11199,49 @@ TraceRecorder::initOrSetPropertyByIndex(
         LIns* vp_ins = addName(lir->insAlloc(sizeof(jsval)), "vp");
         lir->insStorei(rval_ins, vp_ins, 0);
         LIns* args[] = {vp_ins, index_ins, obj_ins, cx_ins};
         ok_ins = lir->insCall(&SetPropertyByIndex_ci, args);
     }
     pendingGuardCondition = ok_ins;
 
     leaveDeepBailCall();
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return RECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_SETELEM()
 {
     jsval& v = stackval(-1);
     jsval& idx = stackval(-2);
     jsval& lval = stackval(-3);
 
     if (JSVAL_IS_PRIMITIVE(lval))
-        ABORT_TRACE("left JSOP_SETELEM operand is not an object");
-    ABORT_IF_XML(lval);
+        RETURN_STOP_A("left JSOP_SETELEM operand is not an object");
+    RETURN_IF_XML_A(lval);
 
     JSObject* obj = JSVAL_TO_OBJECT(lval);
     LIns* obj_ins = get(&lval);
     LIns* idx_ins = get(&idx);
     LIns* v_ins = get(&v);
 
     if (!JSVAL_IS_INT(idx)) {
         if (!JSVAL_IS_PRIMITIVE(idx))
-            ABORT_TRACE("non-primitive index");
-        CHECK_STATUS(initOrSetPropertyByName(obj_ins, &idx, &v,
+            RETURN_STOP_A("non-primitive index");
+        CHECK_STATUS_A(initOrSetPropertyByName(obj_ins, &idx, &v,
                                              *cx->fp->regs->pc == JSOP_INITELEM));
     } else if (JSVAL_TO_INT(idx) < 0 || !OBJ_IS_DENSE_ARRAY(cx, obj)) {
-        CHECK_STATUS(initOrSetPropertyByIndex(obj_ins, idx_ins, &v,
+        CHECK_STATUS_A(initOrSetPropertyByIndex(obj_ins, idx_ins, &v,
                                               *cx->fp->regs->pc == JSOP_INITELEM));
     } else {
         // Fast path: assigning to element of dense array.
 
         // Make sure the array is actually dense.
         if (!guardDenseArray(obj, obj_ins, BRANCH_EXIT))
-            return JSRS_STOP;
+            return ARECORD_STOP;
 
         // The index was on the stack and is therefore a LIR float. Force it to
         // be an integer.
         idx_ins = makeNumberInt32(idx_ins);
 
         // Box the value so we can use one builtin instead of having to add one
         // builtin for every storage type. Special case for integers though,
         // since they are so common.
@@ -11230,47 +11261,47 @@ TraceRecorder::record_JSOP_SETELEM()
         }
         guard(false, lir->ins_eq0(res_ins), MISMATCH_EXIT);
     }
 
     jsbytecode* pc = cx->fp->regs->pc;
     if (*pc == JSOP_SETELEM && pc[JSOP_SETELEM_LENGTH] != JSOP_POP)
         set(&lval, v_ins);
 
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_CALLNAME()
 {
     JSObject* obj = cx->fp->scopeChain;
     if (obj != globalObj) {
         jsval* vp;
         LIns* ins;
         NameResult nr;
-        CHECK_STATUS(scopeChainProp(obj, vp, ins, nr));
+        CHECK_STATUS_A(scopeChainProp(obj, vp, ins, nr));
         stack(0, ins);
         stack(1, INS_CONSTOBJ(globalObj));
-        return JSRS_CONTINUE;
+        return ARECORD_CONTINUE;
     }
 
     LIns* obj_ins = scopeChain();
     JSObject* obj2;
     jsuword pcval;
 
-    CHECK_STATUS(test_property_cache(obj, obj_ins, obj2, pcval));
+    CHECK_STATUS_A(test_property_cache(obj, obj_ins, obj2, pcval));
 
     if (PCVAL_IS_NULL(pcval) || !PCVAL_IS_OBJECT(pcval))
-        ABORT_TRACE("callee is not an object");
+        RETURN_STOP_A("callee is not an object");
 
     JS_ASSERT(HAS_FUNCTION_CLASS(PCVAL_TO_OBJECT(pcval)));
 
     stack(0, INS_CONSTOBJ(PCVAL_TO_OBJECT(pcval)));
     stack(1, obj_ins);
-    return JSRS_CONTINUE;
+    return ARECORD_CONTINUE;
 }
 
 JS_DEFINE_CALLINFO_5(extern, UINT32, GetUpvarArgOnTrace, CONTEXT, UINT32, INT32, UINT32,
                      DOUBLEPTR, 0, 0)
 JS_DEFINE_CALLINFO_5(extern, UINT32, GetUpvarVarOnTrace, CONTEXT, UINT32, INT32, UINT32,
                      DOUBLEPTR, 0, 0)
 JS_DEFINE_CALLINFO_5(extern, UINT32, GetUpvarStackOnTrace, CONTEXT, UINT32, INT32, UINT32,
                      DOUBLEPTR, 0, 0)
@@ -11365,63 +11396,63 @@ LIns* TraceRecorder::stackLoad(LIns* bas
     }
 
     LIns* result = lir->insLoad(loadOp, base, 0);
     if (type == TT_INT32)
         result = lir->ins1(LIR_i2f, result);
     return result;
 }
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_GETUPVAR()
 {
     uintN index = GET_UINT16(cx->fp->regs->pc);
     JSScript *script = cx->fp->script;
     JSUpvarArray* uva = script->upvars();
     JS_ASSERT(index < uva->length);
 
     jsval v;
     LIns* upvar_ins = upvar(script, uva, index, v);
     if (!upvar_ins)
-        return JSRS_STOP;
+        return ARECORD_STOP;
     stack(0, upvar_ins);
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_CALLUPVAR()
 {
-    CHECK_STATUS(record_JSOP_GETUPVAR());
+    CHECK_STATUS_A(record_JSOP_GETUPVAR());
     stack(1, INS_NULL());
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_GETDSLOT()
 {
     JSObject* callee = JSVAL_TO_OBJECT(cx->fp->argv[-2]);
     LIns* callee_ins = get(&cx->fp->argv[-2]);
 
     unsigned index = GET_UINT16(cx->fp->regs->pc);
     LIns* dslots_ins = NULL;
     LIns* v_ins = stobj_get_dslot(callee_ins, index, dslots_ins);
 
     stack(0, unbox_jsval(callee->dslots[index], v_ins, snapshot(BRANCH_EXIT)));
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_CALLDSLOT()
 {
-    CHECK_STATUS(record_JSOP_GETDSLOT());
+    CHECK_STATUS_A(record_JSOP_GETDSLOT());
     stack(1, INS_NULL());
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK RecordingStatus
 TraceRecorder::guardCallee(jsval& callee)
 {
     JS_ASSERT(VALUE_IS_FUNCTION(cx, callee));
 
     VMSideExit* branchExit = snapshot(BRANCH_EXIT);
     JSObject* callee_obj = JSVAL_TO_OBJECT(callee);
     LIns* callee_ins = get(&callee);
 
@@ -11431,17 +11462,17 @@ TraceRecorder::guardCallee(jsval& callee
                     stobj_get_private(callee_ins),
                     INS_CONSTPTR(callee_obj->getPrivate())),
           branchExit);
     guard(true,
           lir->ins2(LIR_peq,
                     stobj_get_parent(callee_ins),
                     INS_CONSTOBJ(OBJ_GET_PARENT(cx, callee_obj))),
           branchExit);
-    return JSRS_CONTINUE;
+    return RECORD_CONTINUE;
 }
 
 /*
  * Prepare the given |arguments| object to be accessed on trace. If the return
  * value is non-NULL, then the given |arguments| object refers to a frame on
  * the current trace and is guaranteed to refer to the same frame on trace for
  * all later executions.
  */
@@ -11458,34 +11489,34 @@ TraceRecorder::guardArguments(JSObject *
     guardClass(obj, obj_ins, &js_ArgumentsClass, exit);
 
     LIns* args_ins = get(&afp->argsobj);
     LIns* cmp = lir->ins2(LIR_peq, args_ins, obj_ins);
     lir->insGuard(LIR_xf, cmp, createGuardRecord(exit));
     return afp;
 }
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK RecordingStatus
 TraceRecorder::interpretedFunctionCall(jsval& fval, JSFunction* fun, uintN argc, bool constructing)
 {
     if (JS_GetGlobalForObject(cx, JSVAL_TO_OBJECT(fval)) != globalObj)
-        ABORT_TRACE("JSOP_CALL or JSOP_NEW crosses global scopes");
+        RETURN_STOP("JSOP_CALL or JSOP_NEW crosses global scopes");
 
     JSStackFrame* fp = cx->fp;
 
     // TODO: track the copying via the tracker...
     if (argc < fun->nargs &&
         jsuword(fp->regs->sp + (fun->nargs - argc)) > cx->stackPool.current->limit) {
-        ABORT_TRACE("can't trace calls with too few args requiring argv move");
+        RETURN_STOP("can't trace calls with too few args requiring argv move");
     }
 
     // Generate a type map for the outgoing frame and stash it in the LIR
     unsigned stackSlots = NativeStackSlots(cx, 0 /* callDepth */);
     if (sizeof(FrameInfo) + stackSlots * sizeof(JSTraceType) > LirBuffer::MAX_SKIP_PAYLOAD_SZB)
-        ABORT_TRACE("interpreted function call requires saving too much stack");
+        RETURN_STOP("interpreted function call requires saving too much stack");
     FrameInfo* fi = (FrameInfo*)
         traceMonitor->dataAlloc->alloc(sizeof(FrameInfo) +
                                        stackSlots * sizeof(JSTraceType));
     JSTraceType* typemap = reinterpret_cast<JSTraceType *>(fi + 1);
 
     DetermineTypesVisitor detVisitor(*this, typemap);
     VisitStackSlots(detVisitor, cx, 0);
 
@@ -11504,28 +11535,28 @@ TraceRecorder::interpretedFunctionCall(j
 
     unsigned callDepth = getCallDepth();
     if (callDepth >= treeInfo->maxCallDepth)
         treeInfo->maxCallDepth = callDepth + 1;
 
     lir->insStorei(INS_CONSTPTR(fi), lirbuf->rp, callDepth * sizeof(FrameInfo*));
 
     atoms = fun->u.i.script->atomMap.vector;
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return RECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_CALL()
 {
     uintN argc = GET_ARGC(cx->fp->regs->pc);
     cx->fp->assertValidStackDepth(argc + 2);
-    return functionCall(argc,
-                        (cx->fp->imacpc && *cx->fp->imacpc == JSOP_APPLY)
-                        ? JSOP_APPLY
-                        : JSOP_CALL);
+    return InjectStatus(functionCall(argc,
+                                     (cx->fp->imacpc && *cx->fp->imacpc == JSOP_APPLY)
+                                        ? JSOP_APPLY
+                                        : JSOP_CALL));
 }
 
 static jsbytecode* apply_imacro_table[] = {
     apply_imacros.apply0,
     apply_imacros.apply1,
     apply_imacros.apply2,
     apply_imacros.apply3,
     apply_imacros.apply4,
@@ -11542,34 +11573,34 @@ static jsbytecode* call_imacro_table[] =
     apply_imacros.call3,
     apply_imacros.call4,
     apply_imacros.call5,
     apply_imacros.call6,
     apply_imacros.call7,
     apply_imacros.call8
 };
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_APPLY()
 {
     JSStackFrame* fp = cx->fp;
     jsbytecode *pc = fp->regs->pc;
     uintN argc = GET_ARGC(pc);
     cx->fp->assertValidStackDepth(argc + 2);
 
     jsval* vp = fp->regs->sp - (argc + 2);
     jsuint length = 0;
     JSObject* aobj = NULL;
     LIns* aobj_ins = NULL;
 
     JS_ASSERT(!fp->imacpc);
 
     if (!VALUE_IS_FUNCTION(cx, vp[0]))
         return record_JSOP_CALL();
-    ABORT_IF_XML(vp[0]);
+    RETURN_IF_XML_A(vp[0]);
 
     JSObject* obj = JSVAL_TO_OBJECT(vp[0]);
     JSFunction* fun = GET_FUNCTION_PRIVATE(cx, obj);
     if (FUN_INTERPRETED(fun))
         return record_JSOP_CALL();
 
     bool apply = (JSFastNative)fun->u.n.native == js_fun_apply;
     if (!apply && (JSFastNative)fun->u.n.native != js_fun_call)
@@ -11581,24 +11612,24 @@ TraceRecorder::record_JSOP_APPLY()
      */
     if (argc > 0 && !JSVAL_IS_OBJECT(vp[2]))
         return record_JSOP_CALL();
 
     /*
      * Guard on the identity of this, which is the function we are applying.
      */
     if (!VALUE_IS_FUNCTION(cx, vp[1]))
-        ABORT_TRACE("callee is not a function");
-    CHECK_STATUS(guardCallee(vp[1]));
+        RETURN_STOP_A("callee is not a function");
+    CHECK_STATUS_A(guardCallee(vp[1]));
 
     if (apply && argc >= 2) {
         if (argc != 2)
-            ABORT_TRACE("apply with excess arguments");
+            RETURN_STOP_A("apply with excess arguments");
         if (JSVAL_IS_PRIMITIVE(vp[3]))
-            ABORT_TRACE("arguments parameter of apply is primitive");
+            RETURN_STOP_A("arguments parameter of apply is primitive");
         aobj = JSVAL_TO_OBJECT(vp[3]);
         aobj_ins = get(&vp[3]);
 
         /*
          * We trace dense arrays and arguments objects. The code we generate
          * for apply uses imacros to handle a specific number of arguments.
          */
         if (OBJ_IS_DENSE_ARRAY(cx, aobj)) {
@@ -11608,32 +11639,32 @@ TraceRecorder::record_JSOP_APPLY()
                   lir->ins2i(LIR_eq,
                              p2i(stobj_get_fslot(aobj_ins, JSSLOT_ARRAY_LENGTH)),
                              length),
                   BRANCH_EXIT);
         } else if (OBJ_GET_CLASS(cx, aobj) == &js_ArgumentsClass) {
             unsigned depth;
             JSStackFrame *afp = guardArguments(aobj, aobj_ins, &depth);
             if (!afp)
-                ABORT_TRACE("can't reach arguments object's frame");
+                RETURN_STOP_A("can't reach arguments object's frame");
             length = afp->argc;
         } else {
-            ABORT_TRACE("arguments parameter of apply is not a dense array or argments object");
+            RETURN_STOP_A("arguments parameter of apply is not a dense array or argments object");
         }
 
         if (length >= JS_ARRAY_LENGTH(apply_imacro_table))
-            ABORT_TRACE("too many arguments to apply");
-
-        return call_imacro(apply_imacro_table[length]);
+            RETURN_STOP_A("too many arguments to apply");
+
+        return InjectStatus(call_imacro(apply_imacro_table[length]));
     }
 
     if (argc >= JS_ARRAY_LENGTH(call_imacro_table))
-        ABORT_TRACE("too many arguments to call");
-
-    return call_imacro(call_imacro_table[argc]);
+        RETURN_STOP_A("too many arguments to call");
+
+    return InjectStatus(call_imacro(call_imacro_table[argc]));
 }
 
 static JSBool FASTCALL
 CatchStopIteration_tn(JSContext* cx, JSBool ok, jsval* vp)
 {
     if (!ok && cx->throwing && js_ValueIsStopIteration(cx->exception)) {
         cx->throwing = JS_FALSE;
         cx->exception = JSVAL_VOID;
@@ -11641,21 +11672,21 @@ CatchStopIteration_tn(JSContext* cx, JSB
         return JS_TRUE;
     }
     return ok;
 }
 
 JS_DEFINE_TRCINFO_1(CatchStopIteration_tn,
     (3, (static, BOOL, CatchStopIteration_tn, CONTEXT, BOOL, JSVALPTR, 0, 0)))
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_NativeCallComplete()
 {
     if (pendingSpecializedNative == IGNORE_NATIVE_CALL_COMPLETE_CALLBACK)
-        return JSRS_CONTINUE;
+        return ARECORD_CONTINUE;
 
     jsbytecode* pc = cx->fp->regs->pc;
 
     JS_ASSERT(pendingSpecializedNative);
     JS_ASSERT(*pc == JSOP_CALL || *pc == JSOP_APPLY || *pc == JSOP_NEW || *pc == JSOP_SETPROP);
 
     jsval& v = stackval(-1);
     LIns* v_ins = get(&v);
@@ -11705,17 +11736,16 @@ TraceRecorder::record_NativeCallComplete
             }
             set(&v, v_ins);
 
             propagateFailureToBuiltinStatus(ok_ins, status);
         }
         guard(true, lir->ins_eq0(status), STATUS_EXIT);
     }
 
-    JSRecordingStatus ok = JSRS_CONTINUE;
     if (pendingSpecializedNative->flags & JSTN_UNBOX_AFTER) {
         /*
          * If we side exit on the unboxing code due to a type change, make sure that the boxed
          * value is actually currently associated with that location, and that we are talking
          * about the top of the stack here, which is where we expected boxed values.
          */
         JS_ASSERT(&v == &cx->fp->regs->sp[-1] && get(&v) == v_ins);
         set(&v, unbox_jsval(v, v_ins, snapshot(BRANCH_EXIT)));
@@ -11727,20 +11757,20 @@ TraceRecorder::record_NativeCallComplete
         if (JSVAL_IS_NUMBER(v) &&
             (pendingSpecializedNative->builtin->_argtypes & ARGSIZE_MASK_ANY) == ARGSIZE_I) {
             set(&v, lir->ins1(LIR_i2f, v_ins));
         }
     }
 
     // We'll null pendingSpecializedNative in monitorRecording, on the next op
     // cycle.  There must be a next op since the stack is non-empty.
-    return ok;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::name(jsval*& vp, LIns*& ins, NameResult& nr)
 {
     JSObject* obj = cx->fp->scopeChain;
     if (obj != globalObj)
         return scopeChainProp(obj, vp, ins, nr);
 
     /* Can't use prop here, because we don't want unboxing from global slots. */
     LIns* obj_ins = scopeChain();
@@ -11748,45 +11778,45 @@ TraceRecorder::name(jsval*& vp, LIns*& i
 
     JSObject* obj2;
     jsuword pcval;
 
     /*
      * Property cache ensures that we are dealing with an existing property,
      * and guards the shape for us.
      */
-    CHECK_STATUS(test_property_cache(obj, obj_ins, obj2, pcval));
+    CHECK_STATUS_A(test_property_cache(obj, obj_ins, obj2, pcval));
 
     /* Abort if property doesn't exist (interpreter will report an error.) */
     if (PCVAL_IS_NULL(pcval))
-        ABORT_TRACE("named property not found");
+        RETURN_STOP_A("named property not found");
 
     /* Insist on obj being the directly addressed object. */
     if (obj2 != obj)
-        ABORT_TRACE("name() hit prototype chain");
+        RETURN_STOP_A("name() hit prototype chain");
 
     /* Don't trace getter or setter calls, our caller wants a direct slot. */
     if (PCVAL_IS_SPROP(pcval)) {
         JSScopeProperty* sprop = PCVAL_TO_SPROP(pcval);
         if (!isValidSlot(OBJ_SCOPE(obj), sprop))
-            ABORT_TRACE("name() not accessing a valid slot");
+            RETURN_STOP_A("name() not accessing a valid slot");
         slot = sprop->slot;
     } else {
         if (!PCVAL_IS_SLOT(pcval))
-            ABORT_TRACE("PCE is not a slot");
+            RETURN_STOP_A("PCE is not a slot");
         slot = PCVAL_TO_SLOT(pcval);
     }
 
     if (!lazilyImportGlobalSlot(slot))
-        ABORT_TRACE("lazy import of global slot failed");
+        RETURN_STOP_A("lazy import of global slot failed");
 
     vp = &STOBJ_GET_SLOT(obj, slot);
     ins = get(vp);
     nr.tracked = true;
-    return JSRS_CONTINUE;
+    return ARECORD_CONTINUE;
 }
 
 static JSObject* FASTCALL
 MethodReadBarrier(JSContext* cx, JSObject* obj, JSScopeProperty* sprop, JSObject* funobj)
 {
     JSAutoTempValueRooter tvr(cx, funobj);
 
     if (!OBJ_SCOPE(obj)->methodReadBarrier(cx, sprop, tvr.addr()))
@@ -11800,48 +11830,48 @@ JS_DEFINE_CALLINFO_4(static, OBJECT_FAIL
 /*
  * Get a property. The current opcode has JOF_ATOM.
  *
  * There are two modes. The caller must pass nonnull pointers for either outp
  * or both slotp and v_insp. In the latter case, we require a plain old
  * property with a slot; if the property turns out to be anything else, abort
  * tracing (rather than emit a call to a native getter or GetAnyProperty).
  */
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::prop(JSObject* obj, LIns* obj_ins, uint32 *slotp, LIns** v_insp, jsval *outp)
 {
     JS_ASSERT((slotp && v_insp && !outp) || (!slotp && !v_insp && outp));
 
     /*
      * Can't specialize to assert obj != global, must guard to avoid aliasing
      * stale homes of stacked global variables.
      */
-    CHECK_STATUS(guardNotGlobalObject(obj, obj_ins));
+    CHECK_STATUS_A(guardNotGlobalObject(obj, obj_ins));
 
     /*
      * Property cache ensures that we are dealing with an existing property,
      * and guards the shape for us.
      */
     JSObject* obj2;
     jsuword pcval;
-    CHECK_STATUS(test_property_cache(obj, obj_ins, obj2, pcval));
+    CHECK_STATUS_A(test_property_cache(obj, obj_ins, obj2, pcval));
 
     /* Check for non-existent property reference, which results in undefined. */
     const JSCodeSpec& cs = js_CodeSpec[*cx->fp->regs->pc];
     if (PCVAL_IS_NULL(pcval)) {
         if (slotp)
-            ABORT_TRACE("property not found");
+            RETURN_STOP_A("property not found");
 
         /*
          * We could specialize to guard on just JSClass.getProperty, but a mere
          * class guard is simpler and slightly faster.
          */
         if (OBJ_GET_CLASS(cx, obj)->getProperty != JS_PropertyStub) {
-            ABORT_TRACE("can't trace through access to undefined property if "
-                        "JSClass.getProperty hook isn't stubbed");
+            RETURN_STOP_A("can't trace through access to undefined property if "
+                                 "JSClass.getProperty hook isn't stubbed");
         }
         guardClass(obj, obj_ins, OBJ_GET_CLASS(cx, obj), snapshot(MISMATCH_EXIT));
 
         /*
          * This trace will be valid as long as neither the object nor any object
          * on its prototype chain changes shape.
          *
          * FIXME: This loop can become a single shape guard once bug 497789 has
@@ -11849,65 +11879,65 @@ TraceRecorder::prop(JSObject* obj, LIns*
          */
         VMSideExit* exit = snapshot(BRANCH_EXIT);
         do {
             LIns* map_ins = map(obj_ins);
             LIns* ops_ins;
             if (map_is_native(obj->map, map_ins, ops_ins)) {
                 guardShape(obj_ins, obj, OBJ_SHAPE(obj), "guard(shape)", map_ins, exit);
             } else if (!guardDenseArray(obj, obj_ins, exit)) {
-                ABORT_TRACE("non-native object involved in undefined property access");
+                RETURN_STOP_A("non-native object involved in undefined property access");
             }
         } while (guardHasPrototype(obj, obj_ins, &obj, &obj_ins, exit));
 
         set(outp, INS_CONST(JSVAL_TO_SPECIAL(JSVAL_VOID)), true);
-        return JSRS_CONTINUE;
+        return ARECORD_CONTINUE;
     }
 
     uint32 setflags = (cs.format & (JOF_INCDEC | JOF_FOR));
     JS_ASSERT(!(cs.format & JOF_SET));
 
     JSScopeProperty* sprop;
     uint32 slot;
     bool isMethod;
 
     if (PCVAL_IS_SPROP(pcval)) {
         sprop = PCVAL_TO_SPROP(pcval);
         JS_ASSERT(OBJ_SCOPE(obj2)->has(sprop));
 
         if (setflags && !SPROP_HAS_STUB_SETTER(sprop))
-            ABORT_TRACE("non-stub setter");
+            RETURN_STOP_A("non-stub setter");
         if (setflags && (sprop->attrs & JSPROP_READONLY))
-            ABORT_TRACE("writing to a readonly property");
+            RETURN_STOP_A("writing to a readonly property");
         if (!SPROP_HAS_STUB_GETTER_OR_IS_METHOD(sprop)) {
             if (slotp)
-                ABORT_TRACE("can't trace non-stub getter for this opcode");
+                RETURN_STOP_A("can't trace non-stub getter for this opcode");
             if (sprop->attrs & JSPROP_GETTER)
-                ABORT_TRACE("script getter");
+                RETURN_STOP_A("script getter");
             if (sprop->slot == SPROP_INVALID_SLOT)
-                return getPropertyWithNativeGetter(obj_ins, sprop, outp);
-            return getPropertyById(obj_ins, outp);
+                return InjectStatus(getPropertyWithNativeGetter(obj_ins, sprop, outp));
+            return InjectStatus(getPropertyById(obj_ins, outp));
         }
         if (!SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(obj2)))
-            ABORT_TRACE("no valid slot");
+            RETURN_STOP_A("no valid slot");
         slot = sprop->slot;
         isMethod = sprop->isMethod();
         JS_ASSERT_IF(isMethod, OBJ_SCOPE(obj2)->hasMethodBarrier());
     } else {
         if (!PCVAL_IS_SLOT(pcval))
-            ABORT_TRACE("PCE is not a slot");
+            RETURN_STOP_A("PCE is not a slot");
         slot = PCVAL_TO_SLOT(pcval);
         sprop = NULL;
         isMethod = false;
     }
 
     /* We have a slot. Check whether it is direct or in a prototype. */
     if (obj2 != obj) {
         if (setflags)
-            ABORT_TRACE("JOF_INCDEC|JOF_FOR opcode hit prototype chain");
+            RETURN_STOP_A("JOF_INCDEC|JOF_FOR opcode hit prototype chain");
 
         /*
          * We're getting a proto-property. Walk up the prototype chain emitting
          * proto slot loads, updating obj as we go, leaving obj set to obj2 with
          * obj_ins the last proto-load.
          */
         do {
             obj_ins = stobj_get_proto(obj_ins);
@@ -11936,20 +11966,20 @@ TraceRecorder::prop(JSObject* obj, LIns*
     }
 
     if (slotp) {
         *slotp = slot;
         *v_insp = v_ins;
     }
     if (outp)
         set(outp, v_ins, true);
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK RecordingStatus
 TraceRecorder::denseArrayElement(jsval& oval, jsval& ival, jsval*& vp, LIns*& v_ins,
                                  LIns*& addr_ins)
 {
     JS_ASSERT(JSVAL_IS_OBJECT(oval) && JSVAL_IS_INT(ival));
 
     JSObject* obj = JSVAL_TO_OBJECT(oval);
     LIns* obj_ins = get(&oval);
     jsint idx = JSVAL_TO_INT(ival);
@@ -11999,17 +12029,17 @@ TraceRecorder::denseArrayElement(jsval& 
         br3->setTarget(label);
         br4->setTarget(label);
 
         CHECK_STATUS(guardPrototypeHasNoIndexedProperties(obj, obj_ins, MISMATCH_EXIT));
 
         // Return undefined and indicate that we didn't actually read this (addr_ins).
         v_ins = lir->insImm(JSVAL_TO_SPECIAL(JSVAL_VOID));
         addr_ins = NULL;
-        return JSRS_CONTINUE;
+        return RECORD_CONTINUE;
     }
 
     /* Guard against negative index */
     if (MAX_DSLOTS_LENGTH > MAX_DSLOTS_LENGTH32 && !idx_ins->isconst()) {
         /* Only 64-bit machines support large enough arrays for this. */
         JS_ASSERT(sizeof(jsval) == 8);
         guard(false,
               lir->ins2i(LIR_lt, idx_ins, 0),
@@ -12048,426 +12078,426 @@ TraceRecorder::denseArrayElement(jsval& 
                                   lir->ins2i(LIR_eq, v_ins, JSVAL_TO_SPECIAL(JSVAL_HOLE)),
                                   NULL);
         CHECK_STATUS(guardPrototypeHasNoIndexedProperties(obj, obj_ins, MISMATCH_EXIT));
         br->setTarget(lir->ins0(LIR_label));
 
         /* Don't let the hole value escape. Turn it into an undefined. */
         v_ins = lir->ins2i(LIR_and, v_ins, ~(JSVAL_HOLE_FLAG >> JSVAL_TAGBITS));
     }
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return RECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::getProp(JSObject* obj, LIns* obj_ins)
 {
     const JSCodeSpec& cs = js_CodeSpec[*cx->fp->regs->pc];
     JS_ASSERT(cs.ndefs == 1);
     return prop(obj, obj_ins, NULL, NULL, &stackval(-cs.nuses));
 }
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::getProp(jsval& v)
 {
     if (JSVAL_IS_PRIMITIVE(v))
-        ABORT_TRACE("primitive lhs");
+        RETURN_STOP_A("primitive lhs");
 
     return getProp(JSVAL_TO_OBJECT(v), get(&v));
 }
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_NAME()
 {
     jsval* vp;
     LIns* v_ins;
     NameResult nr;
-    CHECK_STATUS(name(vp, v_ins, nr));
+    CHECK_STATUS_A(name(vp, v_ins, nr));
     stack(0, v_ins);
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_DOUBLE()
 {
     jsval v = jsval(atoms[GET_INDEX(cx->fp->regs->pc)]);
     stack(0, lir->insImmf(*JSVAL_TO_DOUBLE(v)));
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_STRING()
 {
     JSAtom* atom = atoms[GET_INDEX(cx->fp->regs->pc)];
     JS_ASSERT(ATOM_IS_STRING(atom));
     stack(0, INS_ATOM(atom));
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_ZERO()
 {
     stack(0, lir->insImmf(0));
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_ONE()
 {
     stack(0, lir->insImmf(1));
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_NULL()
 {
     stack(0, INS_NULL());
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_THIS()
 {
     LIns* this_ins;
-    CHECK_STATUS(getThis(this_ins));
+    CHECK_STATUS_A(getThis(this_ins));
     stack(0, this_ins);
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_FALSE()
 {
     stack(0, lir->insImm(0));
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_TRUE()
 {
     stack(0, lir->insImm(1));
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_OR()
 {
     return ifop();
 }
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_AND()
 {
     return ifop();
 }
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_TABLESWITCH()
 {
 #ifdef NANOJIT_IA32
     /* Handle tableswitches specially -- prepare a jump table if needed. */
     return tableswitch();
 #else
-    return switchop();
-#endif
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return InjectStatus(switchop());
+#endif
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_LOOKUPSWITCH()
 {
-    return switchop();
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return InjectStatus(switchop());
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_STRICTEQ()
 {
     strictEquality(true, false);
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_STRICTNE()
 {
     strictEquality(false, false);
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_OBJECT()
 {
     JSStackFrame* fp = cx->fp;
     JSScript* script = fp->script;
     unsigned index = atoms - script->atomMap.vector + GET_INDEX(fp->regs->pc);
 
     JSObject* obj;
     obj = script->getObject(index);
     stack(0, INS_CONSTOBJ(obj));
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_POP()
 {
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_TRAP()
 {
-    return JSRS_STOP;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_STOP;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_GETARG()
 {
     stack(0, arg(GET_ARGNO(cx->fp->regs->pc)));
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_SETARG()
 {
     arg(GET_ARGNO(cx->fp->regs->pc), stack(-1));
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_GETLOCAL()
 {
     stack(0, var(GET_SLOTNO(cx->fp->regs->pc)));
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_SETLOCAL()
 {
     var(GET_SLOTNO(cx->fp->regs->pc), stack(-1));
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_UINT16()
 {
     stack(0, lir->insImmf(GET_UINT16(cx->fp->regs->pc)));
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_NEWINIT()
 {
     JSProtoKey key = JSProtoKey(GET_INT8(cx->fp->regs->pc));
     LIns* proto_ins;
-    CHECK_STATUS(getClassPrototype(key, proto_ins));
+    CHECK_STATUS_A(getClassPrototype(key, proto_ins));
 
     LIns* args[] = { proto_ins, cx_ins };
     const CallInfo *ci = (key == JSProto_Array) ? &js_NewEmptyArray_ci : &js_Object_tn_ci;
     LIns* v_ins = lir->insCall(ci, args);
     guard(false, lir->ins_peq0(v_ins), OOM_EXIT);
     stack(0, v_ins);
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_ENDINIT()
 {
 #ifdef DEBUG
     jsval& v = stackval(-1);
     JS_ASSERT(!JSVAL_IS_PRIMITIVE(v));
 #endif
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_INITPROP()
 {
     // All the action is in record_SetPropHit.
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_INITELEM()
 {
     return record_JSOP_SETELEM();
 }
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_DEFSHARP()
 {
-    return JSRS_STOP;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_STOP;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_USESHARP()
 {
-    return JSRS_STOP;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_STOP;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_INCARG()
 {
-    return inc(argval(GET_ARGNO(cx->fp->regs->pc)), 1);
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return InjectStatus(inc(argval(GET_ARGNO(cx->fp->regs->pc)), 1));
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_INCLOCAL()
 {
-    return inc(varval(GET_SLOTNO(cx->fp->regs->pc)), 1);
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return InjectStatus(inc(varval(GET_SLOTNO(cx->fp->regs->pc)), 1));
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_DECARG()
 {
-    return inc(argval(GET_ARGNO(cx->fp->regs->pc)), -1);
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return InjectStatus(inc(argval(GET_ARGNO(cx->fp->regs->pc)), -1));
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_DECLOCAL()
 {
-    return inc(varval(GET_SLOTNO(cx->fp->regs->pc)), -1);
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return InjectStatus(inc(varval(GET_SLOTNO(cx->fp->regs->pc)), -1));
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_ARGINC()
 {
-    return inc(argval(GET_ARGNO(cx->fp->regs->pc)), 1, false);
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return InjectStatus(inc(argval(GET_ARGNO(cx->fp->regs->pc)), 1, false));
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_LOCALINC()
 {
-    return inc(varval(GET_SLOTNO(cx->fp->regs->pc)), 1, false);
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return InjectStatus(inc(varval(GET_SLOTNO(cx->fp->regs->pc)), 1, false));
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_ARGDEC()
 {
-    return inc(argval(GET_ARGNO(cx->fp->regs->pc)), -1, false);
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return InjectStatus(inc(argval(GET_ARGNO(cx->fp->regs->pc)), -1, false));
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_LOCALDEC()
 {
-    return inc(varval(GET_SLOTNO(cx->fp->regs->pc)), -1, false);
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return InjectStatus(inc(varval(GET_SLOTNO(cx->fp->regs->pc)), -1, false));
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_IMACOP()
 {
     JS_ASSERT(cx->fp->imacpc);
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_ITER()
 {
     jsval& v = stackval(-1);
     if (JSVAL_IS_PRIMITIVE(v))
-        ABORT_TRACE("for-in on a primitive value");
-    ABORT_IF_XML(v);
+        RETURN_STOP_A("for-in on a primitive value");
+    RETURN_IF_XML_A(v);
 
     jsuint flags = cx->fp->regs->pc[1];
 
     if (hasIteratorMethod(JSVAL_TO_OBJECT(v))) {
         if (flags == JSITER_ENUMERATE)
-            return call_imacro(iter_imacros.for_in);
+            return InjectStatus(call_imacro(iter_imacros.for_in));
         if (flags == (JSITER_ENUMERATE | JSITER_FOREACH))
-            return call_imacro(iter_imacros.for_each);
+            return InjectStatus(call_imacro(iter_imacros.for_each));
     } else {
         if (flags == JSITER_ENUMERATE)
-            return call_imacro(iter_imacros.for_in_native);
+            return InjectStatus(call_imacro(iter_imacros.for_in_native));
         if (flags == (JSITER_ENUMERATE | JSITER_FOREACH))
-            return call_imacro(iter_imacros.for_each_native);
-    }
-    ABORT_TRACE("unimplemented JSITER_* flags");
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+            return InjectStatus(call_imacro(iter_imacros.for_each_native));
+    }
+    RETURN_STOP_A("unimplemented JSITER_* flags");
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_NEXTITER()
 {
     jsval& iterobj_val = stackval(-2);
     if (JSVAL_IS_PRIMITIVE(iterobj_val))
-        ABORT_TRACE("for-in on a primitive value");
-    ABORT_IF_XML(iterobj_val);
+        RETURN_STOP_A("for-in on a primitive value");
+    RETURN_IF_XML_A(iterobj_val);
     JSObject* iterobj = JSVAL_TO_OBJECT(iterobj_val);
     JSClass* clasp = STOBJ_GET_CLASS(iterobj);
     LIns* iterobj_ins = get(&iterobj_val);
     if (clasp == &js_IteratorClass || clasp == &js_GeneratorClass) {
         guardClass(iterobj, iterobj_ins, clasp, snapshot(BRANCH_EXIT));
-        return call_imacro(nextiter_imacros.native_iter_next);
-    }
-    return call_imacro(nextiter_imacros.custom_iter_next);
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+        return InjectStatus(call_imacro(nextiter_imacros.native_iter_next));
+    }
+    return InjectStatus(call_imacro(nextiter_imacros.custom_iter_next));
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_ENDITER()
 {
     LIns* args[] = { stack(-2), cx_ins };
     LIns* ok_ins = lir->insCall(&js_CloseIterator_ci, args);
     guard(false, lir->ins_eq0(ok_ins), MISMATCH_EXIT);
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_FORNAME()
 {
     jsval* vp;
     LIns* x_ins;
     NameResult nr;
-    CHECK_STATUS(name(vp, x_ins, nr));
+    CHECK_STATUS_A(name(vp, x_ins, nr));
     if (!nr.tracked)
-        ABORT_TRACE("forname on non-tracked value not supported");
+        RETURN_STOP_A("forname on non-tracked value not supported");
     set(vp, stack(-1));
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_FORPROP()
 {
-    return JSRS_STOP;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_STOP;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_FORELEM()
 {
     return record_JSOP_DUP();
 }
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_FORARG()
 {
     return record_JSOP_SETARG();
 }
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_FORLOCAL()
 {
     return record_JSOP_SETLOCAL();
 }
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_POPN()
 {
-    return JSRS_CONTINUE;
+    return ARECORD_CONTINUE;
 }
 
 /*
  * Generate LIR to reach |obj2| from |obj| by traversing the scope chain. The generated code
  * also ensures that any call objects found have not changed shape.
  *
  *      obj               starting object
  *      obj_ins           LIR instruction representing obj
  *      obj2              end object for traversal
  *      obj2_ins   [out]  LIR instruction representing obj2
  */
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK RecordingStatus
 TraceRecorder::traverseScopeChain(JSObject *obj, LIns *obj_ins, JSObject *obj2, LIns *&obj2_ins)
 {
     VMSideExit* exit = NULL;
     for (;;) {
         if (obj != globalObj) {
             if (!js_IsCacheableNonGlobalScope(obj))
-                ABORT_TRACE("scope chain lookup crosses non-cacheable object");
+                RETURN_STOP("scope chain lookup crosses non-cacheable object");
 
             // We must guard on the shape of all call objects for heavyweight functions
             // that we traverse on the scope chain: if the shape changes, a variable with
             // the same name may have been inserted in the scope chain.
             if (STOBJ_GET_CLASS(obj) == &js_CallClass &&
                 JSFUN_HEAVYWEIGHT_TEST(js_GetCallObjectFunction(obj)->flags)) {
                 LIns* map_ins = map(obj_ins);
                 LIns* shape_ins = addName(lir->insLoad(LIR_ld, map_ins, offsetof(JSScope, shape)),
@@ -12480,25 +12510,25 @@ TraceRecorder::traverseScopeChain(JSObje
             }
         }
 
         if (obj == obj2)
             break;
 
         obj = STOBJ_GET_PARENT(obj);
         if (!obj)
-            ABORT_TRACE("target object not reached on scope chain");
+            RETURN_STOP("target object not reached on scope chain");
         obj_ins = stobj_get_parent(obj_ins);
     }
 
     obj2_ins = obj_ins;
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return RECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_BINDNAME()
 {
     JSStackFrame *fp = cx->fp;
     JSObject *obj;
 
     if (!fp->fun) {
         obj = fp->scopeChain;
 
@@ -12508,134 +12538,134 @@ TraceRecorder::record_JSOP_BINDNAME()
             // The block's values are still on the stack.
             JS_ASSERT(obj->getPrivate() == fp);
             obj = OBJ_GET_PARENT(cx, obj);
             // Blocks always have parents.
             JS_ASSERT(obj);
         }
 
         if (obj != globalObj)
-            ABORT_TRACE("BINDNAME in global code resolved to non-global object");
+            RETURN_STOP_A("BINDNAME in global code resolved to non-global object");
 
         /*
          * The trace is specialized to this global object. Furthermore, we know it
          * is the sole 'global' object on the scope chain: we set globalObj to the
          * scope chain element with no parent, and we reached it starting from the
          * function closure or the current scopeChain, so there is nothing inner to
          * it. Therefore this must be the right base object.
          */
         stack(0, INS_CONSTOBJ(obj));
-        return JSRS_CONTINUE;
+        return ARECORD_CONTINUE;
     }
 
     // We can't trace BINDNAME in functions that contain direct calls to eval,
     // as they might add bindings which previously-traced references would have
     // to see.
     if (JSFUN_HEAVYWEIGHT_TEST(fp->fun->flags))
-        ABORT_TRACE("BINDNAME in heavyweight function.");
+        RETURN_STOP_A("BINDNAME in heavyweight function.");
 
     // We don't have the scope chain on trace, so instead we get a start object
     // that is on the scope chain and doesn't skip the target object (the one
     // that contains the property).
     jsval *callee = &cx->fp->argv[-2];
     obj = STOBJ_GET_PARENT(JSVAL_TO_OBJECT(*callee));
     if (obj == globalObj) {
         stack(0, INS_CONSTOBJ(obj));
-        return JSRS_CONTINUE;
+        return ARECORD_CONTINUE;
     }
     LIns *obj_ins = stobj_get_parent(get(callee));
 
     // Find the target object.
     JSAtom *atom = atoms[GET_INDEX(cx->fp->regs->pc)];
     jsid id = ATOM_TO_JSID(atom);
     JSObject *obj2 = js_FindIdentifierBase(cx, fp->scopeChain, id);
     if (obj2 != globalObj && STOBJ_GET_CLASS(obj2) != &js_CallClass)
-        ABORT_TRACE("BINDNAME on non-global, non-call object");
+        RETURN_STOP_A("BINDNAME on non-global, non-call object");
 
     // Generate LIR to get to the target object from the start object.
     LIns *obj2_ins;
-    CHECK_STATUS(traverseScopeChain(obj, obj_ins, obj2, obj2_ins));
+    CHECK_STATUS_A(traverseScopeChain(obj, obj_ins, obj2, obj2_ins));
 
     // If |obj2| is the global object, we can refer to it directly instead of walking up
     // the scope chain. There may still be guards on intervening call objects.
     stack(0, obj2 == globalObj ? INS_CONSTOBJ(obj2) : obj2_ins);
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_SETNAME()
 {
     jsval& l = stackval(-2);
     JS_ASSERT(!JSVAL_IS_PRIMITIVE(l));
 
     /*
      * Trace only cases that are global code, in lightweight functions
      * scoped by the global object only, or in call objects.
      */
     JSObject* obj = JSVAL_TO_OBJECT(l);
     if (OBJ_GET_CLASS(cx, obj) == &js_CallClass)
-        return JSRS_CONTINUE;
+        return ARECORD_CONTINUE;
     if (obj != cx->fp->scopeChain || obj != globalObj)
-        ABORT_TRACE("JSOP_SETNAME left operand is not the global object");
+        RETURN_STOP_A("JSOP_SETNAME left operand is not the global object");
 
     // The rest of the work is in record_SetPropHit.
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_THROW()
 {
-    return JSRS_STOP;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_STOP;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_IN()
 {
     jsval& rval = stackval(-1);
     jsval& lval = stackval(-2);
 
     if (JSVAL_IS_PRIMITIVE(rval))
-        ABORT_TRACE("JSOP_IN on non-object right operand");
+        RETURN_STOP_A("JSOP_IN on non-object right operand");
     JSObject* obj = JSVAL_TO_OBJECT(rval);
     LIns* obj_ins = get(&rval);
 
     jsid id;
     LIns* x;
     if (JSVAL_IS_INT(lval)) {
         id = INT_JSVAL_TO_JSID(lval);
         LIns* args[] = { makeNumberInt32(get(&lval)), obj_ins, cx_ins };
         x = lir->insCall(&js_HasNamedPropertyInt32_ci, args);
     } else if (JSVAL_IS_STRING(lval)) {
         if (!js_ValueToStringId(cx, lval, &id))
-            ABORT_TRACE_ERROR("left operand of JSOP_IN didn't convert to a string-id");
+            RETURN_ERROR_A("left operand of JSOP_IN didn't convert to a string-id");
         LIns* args[] = { get(&lval), obj_ins, cx_ins };
         x = lir->insCall(&js_HasNamedProperty_ci, args);
     } else {
-        ABORT_TRACE("string or integer expected");
+        RETURN_STOP_A("string or integer expected");
     }
 
     guard(false, lir->ins2i(LIR_eq, x, JSVAL_TO_SPECIAL(JSVAL_VOID)), OOM_EXIT);
     x = lir->ins2i(LIR_eq, x, 1);
 
     JSTraceMonitor &localtm = *traceMonitor;
     JSContext *localcx = cx;
 
     JSObject* obj2;
     JSProperty* prop;
     bool ok = obj->lookupProperty(cx, id, &obj2, &prop);
 
     /* lookupProperty can reenter the interpreter and kill |this|. */
     if (!localtm.recorder) {
         if (prop)
             obj2->dropProperty(localcx, prop);
-        return JSRS_STOP;
+        return ARECORD_STOP;
     }
 
     if (!ok)
-        ABORT_TRACE_ERROR("obj->lookupProperty failed in JSOP_IN");
+        RETURN_ERROR_A("obj->lookupProperty failed in JSOP_IN");
     bool cond = prop != NULL;
     if (prop)
         obj2->dropProperty(cx, prop);
 
     /*
      * The interpreter fuses comparisons and the following branch, so we have
      * to do that here as well.
      */
@@ -12643,158 +12673,158 @@ TraceRecorder::record_JSOP_IN()
 
     /*
      * We update the stack after the guard. This is safe since the guard bails
      * out at the comparison and the interpreter will therefore re-execute the
      * comparison. This way the value of the condition doesn't have to be
      * calculated and saved on the stack in most cases.
      */
     set(&lval, x);
-    return JSRS_CONTINUE;
+    return ARECORD_CONTINUE;
 }
 
 static JSBool FASTCALL
 HasInstance(JSContext* cx, JSObject* ctor, jsval val)
 {
     JSBool result = JS_FALSE;
     if (!ctor->map->ops->hasInstance(cx, ctor, val, &result))
         js_SetBuiltinError(cx);
     return result;
 }
 JS_DEFINE_CALLINFO_3(static, BOOL_FAIL, HasInstance, CONTEXT, OBJECT, JSVAL, 0, 0)
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_INSTANCEOF()
 {
     // If the rhs isn't an object, we are headed for a TypeError.
     jsval& ctor = stackval(-1);
     if (JSVAL_IS_PRIMITIVE(ctor))
-        ABORT_TRACE("non-object on rhs of instanceof");
+        RETURN_STOP_A("non-object on rhs of instanceof");
 
     jsval& val = stackval(-2);
     LIns* val_ins = box_jsval(val, get(&val));
 
     enterDeepBailCall();
     LIns* args[] = {val_ins, get(&ctor), cx_ins};
     stack(-2, lir->insCall(&HasInstance_ci, args));
     LIns* status_ins = lir->insLoad(LIR_ld,
                                     lirbuf->state,
                                     (int) offsetof(InterpState, builtinStatus));
     pendingGuardCondition = lir->ins_eq0(status_ins);
     leaveDeepBailCall();
 
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_DEBUGGER()
 {
-    return JSRS_STOP;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_STOP;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_GOSUB()
 {
-    return JSRS_STOP;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_STOP;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_RETSUB()
 {
-    return JSRS_STOP;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_STOP;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_EXCEPTION()
 {
-    return JSRS_STOP;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_STOP;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_LINENO()
 {
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_CONDSWITCH()
 {
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_CASE()
 {
     strictEquality(true, true);
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_DEFAULT()
 {
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_EVAL()
 {
-    return JSRS_STOP;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_STOP;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_ENUMELEM()
 {
-    return JSRS_STOP;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_STOP;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_GETTER()
 {
-    return JSRS_STOP;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_STOP;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_SETTER()
 {
-    return JSRS_STOP;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_STOP;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_DEFFUN()
 {
-    return JSRS_STOP;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_STOP;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_DEFFUN_FC()
 {
-    return JSRS_STOP;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_STOP;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_DEFCONST()
 {
-    return JSRS_STOP;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_STOP;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_DEFVAR()
 {
-    return JSRS_STOP;
+    return ARECORD_STOP;
 }
 
 jsatomid
 TraceRecorder::getFullIndex(ptrdiff_t pcoff)
 {
     jsatomid index = GET_INDEX(cx->fp->regs->pc + pcoff);
     index += atoms - cx->fp->script->atomMap.vector;
     return index;
 }
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_LAMBDA()
 {
     JSFunction* fun;
     fun = cx->fp->script->getFunction(getFullIndex());
 
     /*
      * Emit code to clone a null closure parented by this recorder's global
      * object, in order to preserve function object evaluation rules observable
@@ -12802,31 +12832,31 @@ TraceRecorder::record_JSOP_LAMBDA()
      * JSOP_SETMETHOD or JSOP_INITMETHOD, since we optimize away the clone for
      * these combinations and clone only if the "method value" escapes.
      */
     if (FUN_NULL_CLOSURE(fun) && OBJ_GET_PARENT(cx, FUN_OBJECT(fun)) == globalObj) {
         JSOp op2 = JSOp(cx->fp->regs->pc[JSOP_LAMBDA_LENGTH]);
 
         if (op2 == JSOP_SETMETHOD || op2 == JSOP_INITMETHOD) {
             stack(0, INS_CONSTOBJ(FUN_OBJECT(fun)));
-            return JSRS_CONTINUE;
+            return ARECORD_CONTINUE;
         }
 
         LIns *proto_ins;
-        CHECK_STATUS(getClassPrototype(JSProto_Function, proto_ins));
+        CHECK_STATUS_A(getClassPrototype(JSProto_Function, proto_ins));
 
         LIns* args[] = { INS_CONSTOBJ(globalObj), proto_ins, INS_CONSTFUN(fun), cx_ins };
         LIns* x = lir->insCall(&js_NewNullClosure_ci, args);
         stack(0, x);
-        return JSRS_CONTINUE;
-    }
-    return JSRS_STOP;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+        return ARECORD_CONTINUE;
+    }
+    return ARECORD_STOP;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_LAMBDA_FC()
 {
     JSFunction* fun;
     fun = cx->fp->script->getFunction(getFullIndex());
 
     LIns* scopeChain_ins = get(&cx->fp->argv[-2]);
     JS_ASSERT(scopeChain_ins);
 
@@ -12842,505 +12872,505 @@ TraceRecorder::record_JSOP_LAMBDA_FC()
           OOM_EXIT);
 
     if (fun->u.i.nupvars) {
         JSUpvarArray *uva = fun->u.i.script->upvars();
         for (uint32 i = 0, n = uva->length; i < n; i++) {
             jsval v;
             LIns* upvar_ins = upvar(fun->u.i.script, uva, i, v);
             if (!upvar_ins)
-                return JSRS_STOP;
+                return ARECORD_STOP;
             LIns* dslots_ins = NULL;
             stobj_set_dslot(call_ins, i, dslots_ins, box_jsval(v, upvar_ins));
         }
     }
 
     stack(0, call_ins);
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_CALLEE()
 {
     stack(0, get(&cx->fp->argv[-2]));
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_SETLOCALPOP()
 {
     var(GET_SLOTNO(cx->fp->regs->pc), stack(-1));
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_IFPRIMTOP()
 {
     // Traces are type-specialized, including null vs. object, so we need do
     // nothing here. The upstream unbox_jsval called after valueOf or toString
     // from an imacro (e.g.) will fork the trace for us, allowing us to just
     // follow along mindlessly :-).
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_SETCALL()
 {
-    return JSRS_STOP;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_STOP;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_TRY()
 {
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_FINALLY()
 {
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_NOP()
 {
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_ARGSUB()
 {
     JSStackFrame* fp = cx->fp;
     if (!(fp->fun->flags & JSFUN_HEAVYWEIGHT)) {
         uintN slot = GET_ARGNO(fp->regs->pc);
         if (slot < fp->argc)
             stack(0, get(&cx->fp->argv[slot]));
         else
             stack(0, INS_VOID());
-        return JSRS_CONTINUE;
-    }
-    ABORT_TRACE("can't trace JSOP_ARGSUB hard case");
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+        return ARECORD_CONTINUE;
+    }
+    RETURN_STOP_A("can't trace JSOP_ARGSUB hard case");
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_ARGCNT()
 {
     if (cx->fp->fun->flags & JSFUN_HEAVYWEIGHT)
-        ABORT_TRACE("can't trace heavyweight JSOP_ARGCNT");
+        RETURN_STOP_A("can't trace heavyweight JSOP_ARGCNT");
 
     // argc is fixed on trace, so ideally we would simply generate LIR for
     // constant argc. But the user can mutate arguments.length in the
     // interpreter, so we have to check for that in the trace entry frame.
     // We also have to check that arguments.length has not been mutated
     // at record time, because if so we will generate incorrect constant
     // LIR, which will assert in alu().
     if (cx->fp->argsobj && js_IsOverriddenArgsLength(JSVAL_TO_OBJECT(cx->fp->argsobj)))
-        ABORT_TRACE("can't trace JSOP_ARGCNT if arguments.length has been modified");
+        RETURN_STOP_A("can't trace JSOP_ARGCNT if arguments.length has been modified");
     LIns *a_ins = get(&cx->fp->argsobj);
     if (callDepth == 0) {
         LIns *br = lir->insBranch(LIR_jt, lir->ins_peq0(a_ins), NULL);
 
         // The following implements js_IsOverriddenArgsLength on trace.
         // The '2' bit is set if length was overridden.
         LIns *len_ins = stobj_get_fslot(a_ins, JSSLOT_ARGS_LENGTH);
         LIns *ovr_ins = lir->ins2(LIR_piand, len_ins, INS_CONSTWORD(2));
 
         guard(true, lir->ins_peq0(ovr_ins), snapshot(BRANCH_EXIT));
         LIns *label = lir->ins0(LIR_label);
         br->setTarget(label);
     }
     stack(0, lir->insImmf(cx->fp->argc));
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_DefLocalFunSetSlot(uint32 slot, JSObject* obj)
 {
     JSFunction* fun = GET_FUNCTION_PRIVATE(cx, obj);
 
     if (FUN_NULL_CLOSURE(fun) && OBJ_GET_PARENT(cx, FUN_OBJECT(fun)) == globalObj) {
         LIns *proto_ins;
-        CHECK_STATUS(getClassPrototype(JSProto_Function, proto_ins));
+        CHECK_STATUS_A(getClassPrototype(JSProto_Function, proto_ins));
 
         LIns* args[] = { INS_CONSTOBJ(globalObj), proto_ins, INS_CONSTFUN(fun), cx_ins };
         LIns* x = lir->insCall(&js_NewNullClosure_ci, args);
         var(slot, x);
-        return JSRS_CONTINUE;
-    }
-
-    return JSRS_STOP;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+        return ARECORD_CONTINUE;
+    }
+
+    return ARECORD_STOP;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_DEFLOCALFUN()
 {
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_DEFLOCALFUN_FC()
 {
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_GOTOX()
 {
     return record_JSOP_GOTO();
 }
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_IFEQX()
 {
     return record_JSOP_IFEQ();
 }
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_IFNEX()
 {
     return record_JSOP_IFNE();
 }
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_ORX()
 {
     return record_JSOP_OR();
 }
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_ANDX()
 {
     return record_JSOP_AND();
 }
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_GOSUBX()
 {
     return record_JSOP_GOSUB();
 }
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_CASEX()
 {
     strictEquality(true, true);
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_DEFAULTX()
 {
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_TABLESWITCHX()
 {
     return record_JSOP_TABLESWITCH();
 }
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_LOOKUPSWITCHX()
 {
-    return switchop();
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return InjectStatus(switchop());
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_BACKPATCH()
 {
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_BACKPATCH_POP()
 {
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_THROWING()
 {
-    return JSRS_STOP;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_STOP;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_SETRVAL()
 {
     // If we implement this, we need to update JSOP_STOP.
-    return JSRS_STOP;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_STOP;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_RETRVAL()
 {
-    return JSRS_STOP;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_STOP;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_GETGVAR()
 {
     jsval slotval = cx->fp->slots[GET_SLOTNO(cx->fp->regs->pc)];
     if (JSVAL_IS_NULL(slotval))
-        return JSRS_CONTINUE; // We will see JSOP_NAME from the interpreter's jump, so no-op here.
+        return ARECORD_CONTINUE; // We will see JSOP_NAME from the interpreter's jump, so no-op here.
 
     uint32 slot = JSVAL_TO_INT(slotval);
 
     if (!lazilyImportGlobalSlot(slot))
-         ABORT_TRACE("lazy import of global slot failed");
+         RETURN_STOP_A("lazy import of global slot failed");
 
     stack(0, get(&STOBJ_GET_SLOT(globalObj, slot)));
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_SETGVAR()
 {
     jsval slotval = cx->fp->slots[GET_SLOTNO(cx->fp->regs->pc)];
     if (JSVAL_IS_NULL(slotval))
-        return JSRS_CONTINUE; // We will see JSOP_NAME from the interpreter's jump, so no-op here.
+        return ARECORD_CONTINUE; // We will see JSOP_NAME from the interpreter's jump, so no-op here.
 
     uint32 slot = JSVAL_TO_INT(slotval);
 
     if (!lazilyImportGlobalSlot(slot))
-         ABORT_TRACE("lazy import of global slot failed");
+         RETURN_STOP_A("lazy import of global slot failed");
 
     set(&STOBJ_GET_SLOT(globalObj, slot), stack(-1));
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_INCGVAR()
 {
     jsval slotval = cx->fp->slots[GET_SLOTNO(cx->fp->regs->pc)];
     if (JSVAL_IS_NULL(slotval))
         // We will see JSOP_INCNAME from the interpreter's jump, so no-op here.
-        return JSRS_CONTINUE;
+        return ARECORD_CONTINUE;
 
     uint32 slot = JSVAL_TO_INT(slotval);
 
     if (!lazilyImportGlobalSlot(slot))
-         ABORT_TRACE("lazy import of global slot failed");
-
-    return inc(STOBJ_GET_SLOT(globalObj, slot), 1);
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+         RETURN_STOP_A("lazy import of global slot failed");
+
+    return InjectStatus(inc(STOBJ_GET_SLOT(globalObj, slot), 1));
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_DECGVAR()
 {
     jsval slotval = cx->fp->slots[GET_SLOTNO(cx->fp->regs->pc)];
     if (JSVAL_IS_NULL(slotval))
         // We will see JSOP_INCNAME from the interpreter's jump, so no-op here.
-        return JSRS_CONTINUE;
+        return ARECORD_CONTINUE;
 
     uint32 slot = JSVAL_TO_INT(slotval);
 
     if (!lazilyImportGlobalSlot(slot))
-         ABORT_TRACE("lazy import of global slot failed");
-
-    return inc(STOBJ_GET_SLOT(globalObj, slot), -1);
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+         RETURN_STOP_A("lazy import of global slot failed");
+
+    return InjectStatus(inc(STOBJ_GET_SLOT(globalObj, slot), -1));
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_GVARINC()
 {
     jsval slotval = cx->fp->slots[GET_SLOTNO(cx->fp->regs->pc)];
     if (JSVAL_IS_NULL(slotval))
         // We will see JSOP_INCNAME from the interpreter's jump, so no-op here.
-        return JSRS_CONTINUE;
+        return ARECORD_CONTINUE;
 
     uint32 slot = JSVAL_TO_INT(slotval);
 
     if (!lazilyImportGlobalSlot(slot))
-         ABORT_TRACE("lazy import of global slot failed");
-
-    return inc(STOBJ_GET_SLOT(globalObj, slot), 1, false);
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+         RETURN_STOP_A("lazy import of global slot failed");
+
+    return InjectStatus(inc(STOBJ_GET_SLOT(globalObj, slot), 1, false));
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_GVARDEC()
 {
     jsval slotval = cx->fp->slots[GET_SLOTNO(cx->fp->regs->pc)];
     if (JSVAL_IS_NULL(slotval))
         // We will see JSOP_INCNAME from the interpreter's jump, so no-op here.
-        return JSRS_CONTINUE;
+        return ARECORD_CONTINUE;
 
     uint32 slot = JSVAL_TO_INT(slotval);
 
     if (!lazilyImportGlobalSlot(slot))
-         ABORT_TRACE("lazy import of global slot failed");
-
-    return inc(STOBJ_GET_SLOT(globalObj, slot), -1, false);
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+         RETURN_STOP_A("lazy import of global slot failed");
+
+    return InjectStatus(inc(STOBJ_GET_SLOT(globalObj, slot), -1, false));
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_REGEXP()
 {
-    return JSRS_STOP;
+    return ARECORD_STOP;
 }
 
 // begin JS_HAS_XML_SUPPORT
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_DEFXMLNS()
 {
-    return JSRS_STOP;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_STOP;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_ANYNAME()
 {
-    return JSRS_STOP;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_STOP;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_QNAMEPART()
 {
     return record_JSOP_STRING();
 }
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_QNAMECONST()
 {
-    return JSRS_STOP;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_STOP;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_QNAME()
 {
-    return JSRS_STOP;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_STOP;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_TOATTRNAME()
 {
-    return JSRS_STOP;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_STOP;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_TOATTRVAL()
 {
-    return JSRS_STOP;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_STOP;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_ADDATTRNAME()
 {
-    return JSRS_STOP;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_STOP;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_ADDATTRVAL()
 {
-    return JSRS_STOP;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_STOP;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_BINDXMLNAME()
 {
-    return JSRS_STOP;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_STOP;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_SETXMLNAME()
 {
-    return JSRS_STOP;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_STOP;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_XMLNAME()
 {
-    return JSRS_STOP;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_STOP;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_DESCENDANTS()
 {
-    return JSRS_STOP;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_STOP;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_FILTER()
 {
-    return JSRS_STOP;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_STOP;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_ENDFILTER()
 {
-    return JSRS_STOP;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_STOP;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_TOXML()
 {
-    return JSRS_STOP;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_STOP;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_TOXMLLIST()
 {
-    return JSRS_STOP;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_STOP;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_XMLTAGEXPR()
 {
-    return JSRS_STOP;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_STOP;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_XMLELTEXPR()
 {
-    return JSRS_STOP;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_STOP;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_XMLOBJECT()
 {
-    return JSRS_STOP;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_STOP;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_XMLCDATA()
 {
-    return JSRS_STOP;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_STOP;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_XMLCOMMENT()
 {
-    return JSRS_STOP;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_STOP;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_XMLPI()
 {
-    return JSRS_STOP;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_STOP;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_GETFUNNS()
 {
-    return JSRS_STOP;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_STOP;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_STARTXML()
 {
-    return JSRS_STOP;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_STOP;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_STARTXMLEXPR()
 {
-    return JSRS_STOP;
+    return ARECORD_STOP;
 }
 
 // end JS_HAS_XML_SUPPORT
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_CALLPROP()
 {
     jsval& l = stackval(-1);
     JSObject* obj;
     LIns* obj_ins;
     LIns* this_ins;
     if (!JSVAL_IS_PRIMITIVE(l)) {
         obj = JSVAL_TO_OBJECT(l);
@@ -13352,105 +13382,105 @@ TraceRecorder::record_JSOP_CALLPROP()
         if (JSVAL_IS_STRING(l)) {
             i = JSProto_String;
             debug_only_stmt(protoname = "String.prototype";)
         } else if (JSVAL_IS_NUMBER(l)) {
             i = JSProto_Number;
             debug_only_stmt(protoname = "Number.prototype";)
         } else if (JSVAL_IS_SPECIAL(l)) {
             if (l == JSVAL_VOID)
-                ABORT_TRACE("callprop on void");
+                RETURN_STOP_A("callprop on void");
             guard(false, lir->ins2i(LIR_eq, get(&l), JSVAL_TO_SPECIAL(JSVAL_VOID)), MISMATCH_EXIT);
             i = JSProto_Boolean;
             debug_only_stmt(protoname = "Boolean.prototype";)
         } else {
             JS_ASSERT(JSVAL_IS_NULL(l) || JSVAL_IS_VOID(l));
-            ABORT_TRACE("callprop on null or void");
+            RETURN_STOP_A("callprop on null or void");
         }
 
         if (!js_GetClassPrototype(cx, NULL, INT_TO_JSID(i), &obj))
-            ABORT_TRACE_ERROR("GetClassPrototype failed!");
+            RETURN_ERROR_A("GetClassPrototype failed!");
 
         obj_ins = INS_CONSTOBJ(obj);
         debug_only_stmt(obj_ins = addName(obj_ins, protoname);)
         this_ins = get(&l); // use primitive as |this|
     }
 
     JSObject* obj2;
     jsuword pcval;
-    CHECK_STATUS(test_property_cache(obj, obj_ins, obj2, pcval));
+    CHECK_STATUS_A(test_property_cache(obj, obj_ins, obj2, pcval));
 
     if (PCVAL_IS_NULL(pcval) || !PCVAL_IS_OBJECT(pcval))
-        ABORT_TRACE("callee is not an object");
+        RETURN_STOP_A("callee is not an object");
     JS_ASSERT(HAS_FUNCTION_CLASS(PCVAL_TO_OBJECT(pcval)));
 
     if (JSVAL_IS_PRIMITIVE(l)) {
         JSFunction* fun = GET_FUNCTION_PRIVATE(cx, PCVAL_TO_OBJECT(pcval));
         if (!PRIMITIVE_THIS_TEST(fun, l))
-            ABORT_TRACE("callee does not accept primitive |this|");
+            RETURN_STOP_A("callee does not accept primitive |this|");
     }
 
     stack(0, this_ins);
     stack(-1, INS_CONSTOBJ(PCVAL_TO_OBJECT(pcval)));
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_DELDESC()
 {
-    return JSRS_STOP;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_STOP;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_UINT24()
 {
     stack(0, lir->insImmf(GET_UINT24(cx->fp->regs->pc)));
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_INDEXBASE()
 {
     atoms += GET_INDEXBASE(cx->fp->regs->pc);
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_RESETBASE()
 {
     atoms = cx->fp->script->atomMap.vector;
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_RESETBASE0()
 {
     atoms = cx->fp->script->atomMap.vector;
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_CALLELEM()
 {
     return record_JSOP_GETELEM();
 }
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_STOP()
 {
     JSStackFrame *fp = cx->fp;
 
     if (fp->imacpc) {
         /*
          * End of imacro, so return true to the interpreter immediately. The
          * interpreter's JSOP_STOP case will return from the imacro, back to
          * the pc after the calling op, still in the same JSStackFrame.
          */
         atoms = fp->script->atomMap.vector;
-        return JSRS_CONTINUE;
+        return ARECORD_CONTINUE;
     }
 
     putArguments();
 
     /*
      * We know falling off the end of a constructor returns the new object that
      * was passed in via fp->argv[-1], while falling off the end of a function
      * returns undefined.
@@ -13460,198 +13490,198 @@ TraceRecorder::record_JSOP_STOP()
      */
     if (fp->flags & JSFRAME_CONSTRUCTING) {
         JS_ASSERT(fp->thisv == fp->argv[-1]);
         rval_ins = get(&fp->argv[-1]);
     } else {
         rval_ins = INS_CONST(JSVAL_TO_SPECIAL(JSVAL_VOID));
     }
     clearFrameSlotsFromCache();
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_GETXPROP()
 {
     jsval& l = stackval(-1);
     if (JSVAL_IS_PRIMITIVE(l))
-        ABORT_TRACE("primitive-this for GETXPROP?");
+        RETURN_STOP_A("primitive-this for GETXPROP?");
 
     jsval* vp;
     LIns* v_ins;
     NameResult nr;
-    CHECK_STATUS(name(vp, v_ins, nr));
+    CHECK_STATUS_A(name(vp, v_ins, nr));
     stack(-1, v_ins);
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_CALLXMLNAME()
 {
-    return JSRS_STOP;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_STOP;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_TYPEOFEXPR()
 {
     return record_JSOP_TYPEOF();
 }
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_ENTERBLOCK()
 {
     JSObject* obj;
     obj = cx->fp->script->getObject(getFullIndex(0));
 
     LIns* void_ins = INS_CONST(JSVAL_TO_SPECIAL(JSVAL_VOID));
     for (int i = 0, n = OBJ_BLOCK_COUNT(cx, obj); i < n; i++)
         stack(i, void_ins);
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_LEAVEBLOCK()
 {
     /* We mustn't exit the lexical block we began recording in. */
     if (cx->fp->blockChain != lexicalBlock)
-        return JSRS_CONTINUE;
+        return ARECORD_CONTINUE;
     else
-        return JSRS_STOP;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+        return ARECORD_STOP;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_GENERATOR()
 {
-    return JSRS_STOP;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_STOP;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_YIELD()
 {
-    return JSRS_STOP;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_STOP;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_ARRAYPUSH()
 {
     uint32_t slot = GET_UINT16(cx->fp->regs->pc);
     JS_ASSERT(cx->fp->script->nfixed <= slot);
     JS_ASSERT(cx->fp->slots + slot < cx->fp->regs->sp - 1);
     jsval &arrayval = cx->fp->slots[slot];
     JS_ASSERT(JSVAL_IS_OBJECT(arrayval));
     JS_ASSERT(OBJ_IS_DENSE_ARRAY(cx, JSVAL_TO_OBJECT(arrayval)));
     LIns *array_ins = get(&arrayval);
     jsval &elt = stackval(-1);
     LIns *elt_ins = box_jsval(elt, get(&elt));
 
     LIns *args[] = { elt_ins, array_ins, cx_ins };
     LIns *ok_ins = lir->insCall(&js_ArrayCompPush_ci, args);
     guard(false, lir->ins_eq0(ok_ins), OOM_EXIT);
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_ENUMCONSTELEM()
 {
-    return JSRS_STOP;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_STOP;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_LEAVEBLOCKEXPR()
 {
     LIns* v_ins = stack(-1);
     int n = -1 - GET_UINT16(cx->fp->regs->pc);
     stack(n, v_ins);
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_GETTHISPROP()
 {
     LIns* this_ins;
 
-    CHECK_STATUS(getThis(this_ins));
+    CHECK_STATUS_A(getThis(this_ins));
 
     /*
      * It's safe to just use cx->fp->thisv here because getThis() returns
-     * JSRS_STOP if thisv is not available.
+     * ARECORD_STOP if thisv is not available.
      */
     JS_ASSERT(cx->fp->flags & JSFRAME_COMPUTED_THIS);
-    CHECK_STATUS(getProp(JSVAL_TO_OBJECT(cx->fp->thisv), this_ins));
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    CHECK_STATUS_A(getProp(JSVAL_TO_OBJECT(cx->fp->thisv), this_ins));
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_GETARGPROP()
 {
     return getProp(argval(GET_ARGNO(cx->fp->regs->pc)));
 }
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_GETLOCALPROP()
 {
     return getProp(varval(GET_SLOTNO(cx->fp->regs->pc)));
 }
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_INDEXBASE1()
 {
     atoms += 1 << 16;
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_INDEXBASE2()
 {
     atoms += 2 << 16;
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_INDEXBASE3()
 {
     atoms += 3 << 16;
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_CALLGVAR()
 {
     jsval slotval = cx->fp->slots[GET_SLOTNO(cx->fp->regs->pc)];
     if (JSVAL_IS_NULL(slotval))
         // We will see JSOP_CALLNAME from the interpreter's jump, so no-op here.
-        return JSRS_CONTINUE;
+        return ARECORD_CONTINUE;
 
     uint32 slot = JSVAL_TO_INT(slotval);
 
     if (!lazilyImportGlobalSlot(slot))
-         ABORT_TRACE("lazy import of global slot failed");
+         RETURN_STOP_A("lazy import of global slot failed");
 
     jsval& v = STOBJ_GET_SLOT(globalObj, slot);
     stack(0, get(&v));
     stack(1, INS_NULL());
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_CALLLOCAL()
 {
     uintN slot = GET_SLOTNO(cx->fp->regs->pc);
     stack(0, var(slot));
     stack(1, INS_NULL());
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_CALLARG()
 {
     uintN slot = GET_ARGNO(cx->fp->regs->pc);
     stack(0, arg(slot));
     stack(1, INS_NULL());
-    return JSRS_CONTINUE;
+    return ARECORD_CONTINUE;
 }
 
 /* Functions for use with JSOP_CALLBUILTIN. */
 
 static JSBool
 ObjectToIterator(JSContext *cx, uintN argc, jsval *vp)
 {
     jsval *argv = JS_ARGV(cx, vp);
@@ -13733,93 +13763,93 @@ js_GetBuiltinFunction(JSContext *cx, uin
             else
                 funobj = rt->builtinFunctions[index];
             JS_UNLOCK_GC(rt);
         }
     }
     return funobj;
 }
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_CALLBUILTIN()
 {
     JSObject *obj = js_GetBuiltinFunction(cx, GET_INDEX(cx->fp->regs->pc));
     if (!obj)
-        ABORT_TRACE_ERROR("error in js_GetBuiltinFunction");
+        RETURN_ERROR_A("error in js_GetBuiltinFunction");
 
     stack(0, get(&stackval(-1)));
     stack(-1, INS_CONSTOBJ(obj));
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_INT8()
 {
     stack(0, lir->insImmf(GET_INT8(cx->fp->regs->pc)));
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_INT32()
 {
     stack(0, lir->insImmf(GET_INT32(cx->fp->regs->pc)));
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_LENGTH()
 {
     jsval& l = stackval(-1);
     if (JSVAL_IS_PRIMITIVE(l)) {
         if (!JSVAL_IS_STRING(l))
-            ABORT_TRACE("non-string primitive JSOP_LENGTH unsupported");
+            RETURN_STOP_A("non-string primitive JSOP_LENGTH unsupported");
         set(&l, lir->ins1(LIR_i2f, getStringLength(get(&l))));
-        return JSRS_CONTINUE;
+        return ARECORD_CONTINUE;
     }
 
     JSObject* obj = JSVAL_TO_OBJECT(l);
     LIns* obj_ins = get(&l);
 
     if (STOBJ_GET_CLASS(obj) == &js_ArgumentsClass) {
         unsigned depth;
         JSStackFrame *afp = guardArguments(obj, obj_ins, &depth);
         if (!afp)
-            ABORT_TRACE("can't reach arguments object's frame");
+            RETURN_STOP_A("can't reach arguments object's frame");
 
         LIns* v_ins = lir->ins1(LIR_i2f, INS_CONST(afp->argc));
         set(&l, v_ins);
-        return JSRS_CONTINUE;
+        return ARECORD_CONTINUE;
     }
 
     LIns* v_ins;
     if (OBJ_IS_ARRAY(cx, obj)) {
         if (OBJ_IS_DENSE_ARRAY(cx, obj)) {
             if (!guardDenseArray(obj, obj_ins, BRANCH_EXIT)) {
                 JS_NOT_REACHED("OBJ_IS_DENSE_ARRAY but not?!?");
-                return JSRS_STOP;
+                return ARECORD_STOP;
             }
         } else {
             if (!guardClass(obj, obj_ins, &js_SlowArrayClass, snapshot(BRANCH_EXIT)))
-                ABORT_TRACE("can't trace length property access on non-array");
+                RETURN_STOP_A("can't trace length property access on non-array");
         }
         v_ins = lir->ins1(LIR_i2f, p2i(stobj_get_fslot(obj_ins, JSSLOT_ARRAY_LENGTH)));
     } else {
         if (!OBJ_IS_NATIVE(obj))
-            ABORT_TRACE("can't trace length property access on non-array, non-native object");
+            RETURN_STOP_A("can't trace length property access on non-array, non-native object");
         return getProp(obj, obj_ins);
     }
     set(&l, v_ins);
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_NEWARRAY()
 {
     LIns *proto_ins;
-    CHECK_STATUS(getClassPrototype(JSProto_Array, proto_ins));
+    CHECK_STATUS_A(getClassPrototype(JSProto_Array, proto_ins));
 
     uint32 len = GET_UINT16(cx->fp->regs->pc);
     cx->fp->assertValidStackDepth(len);
 
     LIns* args[] = { lir->insImm(len), proto_ins, cx_ins };
     LIns* v_ins = lir->insCall(&js_NewArrayWithSlots_ci, args);
     guard(false, lir->ins_peq0(v_ins), OOM_EXIT);
 
@@ -13832,30 +13862,30 @@ TraceRecorder::record_JSOP_NEWARRAY()
         LIns* elt_ins = box_jsval(v, get(&v));
         stobj_set_dslot(v_ins, i, dslots_ins, elt_ins);
     }
 
     if (count > 0)
         stobj_set_fslot(v_ins, JSSLOT_ARRAY_COUNT, INS_CONST(count));
 
     stack(-int(len), v_ins);
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_HOLE()
 {
     stack(0, INS_CONST(JSVAL_TO_SPECIAL(JSVAL_HOLE)));
-    return JSRS_CONTINUE;
-}
-
-JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+AbortableRecordingStatus
 TraceRecorder::record_JSOP_TRACE()
 {
-    return JSRS_CONTINUE;
+    return ARECORD_CONTINUE;
 }
 
 static const uint32 sMaxConcatNSize = 32;
 
 /*
  * Copy the result of defvalue.string back into concatn's arguments, clean the
  * stack, and return a pointer to the argument that was just overwritten.
  */
@@ -13898,17 +13928,17 @@ js_ConcatPostImacroStackCleanup(uint32 a
  *   primarg[i]     nonprim[i] converted to primitive
  *   i
  *
  * Hence, the stack setup on entry to this function (and JSOP_CONCATN in the
  * interpreter, on trace abort) is dependent on whether an imacro is in
  * progress.  When all of concatn's arguments are primitive, it emits a builtin
  * call and allows the actual JSOP_CONCATN to be executed by the interpreter.
  */
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_CONCATN()
 {
     JSStackFrame *fp = cx->fp;
     JSFrameRegs &regs = *fp->regs;
 
     /*
      * If we are in an imacro, we must have just finished a call to
      * defvalue.string.  Continue where we left off last time.
@@ -13921,17 +13951,17 @@ TraceRecorder::record_JSOP_CONCATN()
         loopStart = js_ConcatPostImacroStackCleanup(argc, regs, this) + 1;
     } else {
         argc = GET_ARGC(regs.pc);
         JS_ASSERT(argc > 0);
         loopStart = regs.sp - argc;
 
         /* Prevent code/alloca explosion. */
         if (argc > sMaxConcatNSize)
-            return JSRS_STOP;
+            return ARECORD_STOP;
     }
 
     /* Convert non-primitives to primitives using defvalue.string. */
     for (jsval *vp = loopStart; vp != regs.sp; ++vp) {
         if (!JSVAL_IS_PRIMITIVE(*vp)) {
             /*
              * In addition to the jsval we want the imacro to convert to
              * primitive, pass through the offset of the argument on the stack.
@@ -13942,17 +13972,17 @@ TraceRecorder::record_JSOP_CONCATN()
             set(regs.sp, get(vp), true);
             *regs.sp++ = *vp;
 
             /* Push the argument index. */
             set(regs.sp, lir->insImm(offset), true);
             *regs.sp++ = INT_TO_JSVAL(offset);
 
             /* Nested imacro call OK because this is a tail call. */
-            return call_imacro(defvalue_imacros.string);
+            return InjectStatus(call_imacro(defvalue_imacros.string));
         }
     }
 
     /* Build an array of the stringified primitives. */
     int32_t bufSize = argc * sizeof(JSString *);
     LIns *buf_ins = lir->insAlloc(bufSize);
     int32_t d = 0;
     for (jsval *vp = regs.sp - argc; vp != regs.sp; ++vp, d += sizeof(void *))
@@ -13962,42 +13992,42 @@ TraceRecorder::record_JSOP_CONCATN()
     LIns *args[] = { lir->insImm(argc), buf_ins, cx_ins };
     LIns *concat = lir->insCall(&js_ConcatN_ci, args);
     guard(false, lir->ins_peq0(concat), OOM_EXIT);
 
     /* Update tracker with result. */
     jsval *afterPop = regs.sp - (argc - 1);
     set(afterPop - 1, concat);
 
-    return JSRS_CONTINUE;
-}
-
-JS_REQUIRES_STACK JSRecordingStatus
+    return ARECORD_CONTINUE;
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_SETMETHOD()
 {
     return record_JSOP_SETPROP();
 }
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_INITMETHOD()
 {
     return record_JSOP_INITPROP();
 }
 
-JS_REQUIRES_STACK JSRecordingStatus
+JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_SHARPINIT()
 {
-    return JSRS_STOP;
+    return ARECORD_STOP;
 }
 
 #define DBG_STUB(OP)                                                          \
-    JS_REQUIRES_STACK JSRecordingStatus                                       \
+    JS_REQUIRES_STACK AbortableRecordingStatus                                \
     TraceRecorder::record_##OP()                                              \
     {                                                                         \
-        ABORT_TRACE("can't trace " #OP);                                      \
+        RETURN_STOP_A("can't trace " #OP);                                    \
     }
 
 DBG_STUB(JSOP_GETUPVAR_DBG)
 DBG_STUB(JSOP_CALLUPVAR_DBG)
 DBG_STUB(JSOP_DEFFUN_DBGFC)
 DBG_STUB(JSOP_DEFLOCALFUN_DBGFC)
 DBG_STUB(JSOP_LAMBDA_DBGFC)
 
@@ -14118,15 +14148,8 @@ js_StopTraceVis(JSContext *cx, JSObject 
         fprintf(stderr, "stopped TraceVis recording\n");
     else
         JS_ReportError(cx, "TraceVis isn't running");
 
     return ok;
 }
 
 #endif /* MOZ_TRACEVIS */
-
-#define UNUSED(n)                                                             \
-    JS_REQUIRES_STACK JSRecordingStatus                                       \
-    TraceRecorder::record_JSOP_UNUSED##n() {                                  \
-        JS_NOT_REACHED("JSOP_UNUSED" #n);                                     \
-        return JSRS_STOP;                                                     \
-    }
--- a/js/src/jstracer.h
+++ b/js/src/jstracer.h
@@ -648,42 +648,126 @@ struct js_ArgsPrivateNative {
 };
 
 static JS_INLINE void
 js_SetBuiltinError(JSContext *cx)
 {
     cx->interpState->builtinStatus |= JSBUILTIN_ERROR;
 }
 
-#ifdef DEBUG_JSRS_NOT_BOOL
-struct JSRecordingStatus {
+#ifdef DEBUG_RECORDING_STATUS_NOT_BOOL
+/* #define DEBUG_RECORDING_STATUS_NOT_BOOL to detect misuses of RecordingStatus */
+struct RecordingStatus {
     int code;
-    bool operator==(JSRecordingStatus &s) { return this->code == s.code; };
-    bool operator!=(JSRecordingStatus &s) { return this->code != s.code; };
+    bool operator==(RecordingStatus &s) { return this->code == s.code; };
+    bool operator!=(RecordingStatus &s) { return this->code != s.code; };
+};
+enum RecordingStatusCodes {
+    RECORD_ERROR_code     = 0,
+    RECORD_STOP_code      = 1,
+
+    RECORD_CONTINUE_code  = 3,
+    RECORD_IMACRO_code    = 4
 };
-enum JSRScodes {
-    JSRS_ERROR_code,
-    JSRS_STOP_code,
-    JSRS_CONTINUE_code,
-    JSRS_IMACRO_code
+RecordingStatus RECORD_CONTINUE = { RECORD_CONTINUE_code };
+RecordingStatus RECORD_STOP     = { RECORD_STOP_code };
+RecordingStatus RECORD_IMACRO   = { RECORD_IMACRO_code };
+RecordingStatus RECORD_ERROR    = { RECORD_ERROR_code };
+
+struct AbortableRecordingStatus {
+    int code;
+    bool operator==(AbortableRecordingStatus &s) { return this->code == s.code; };
+    bool operator!=(AbortableRecordingStatus &s) { return this->code != s.code; };
+};
+enum AbortableRecordingStatusCodes {
+    ARECORD_ERROR_code    = 0,
+    ARECORD_STOP_code     = 1,
+    ARECORD_ABORTED_code  = 2,
+    ARECORD_CONTINUE_code = 3,
+    ARECORD_IMACRO_code   = 4
 };
-struct JSRecordingStatus JSRS_CONTINUE = { JSRS_CONTINUE_code };
-struct JSRecordingStatus JSRS_STOP     = { JSRS_STOP_code };
-struct JSRecordingStatus JSRS_IMACRO   = { JSRS_IMACRO_code };
-struct JSRecordingStatus JSRS_ERROR    = { JSRS_ERROR_code };
-#define STATUS_ABORTS_RECORDING(s) ((s) == JSRS_STOP || (s) == JSRS_ERROR)
+AbortableRecordingStatus ARECORD_ERROR    = { ARECORD_ERROR_code };
+AbortableRecordingStatus ARECORD_STOP     = { ARECORD_STOP_code };
+AbortableRecordingStatus ARECORD_CONTINUE = { ARECORD_CONTINUE_code };
+AbortableRecordingStatus ARECORD_IMACRO   = { ARECORD_IMACRO_code };
+AbortableRecordingStatus ARECORD_ABORTED =  { ARECORD_ABORTED_code };
+
+static inline AbortableRecordingStatus
+InjectStatus(RecordingStatus rs)
+{
+    AbortableRecordingStatus ars = { rs.code };
+    return ars;
+}
+static inline AbortableRecordingStatus
+InjectStatus(AbortableRecordingStatus ars)
+{
+    return ars;
+}
+
+static inline bool
+StatusAbortsRecording(AbortableRecordingStatus ars)
+{
+    return ars == ARECORD_ERROR || ars == ARECORD_STOP || ars == ARECORD_ABORTED;
+}
 #else
-enum JSRecordingStatus {
-    JSRS_ERROR,        // Error; propagate to interpreter.
-    JSRS_STOP,         // Abort recording.
-    JSRS_CONTINUE,     // Continue recording.
-    JSRS_IMACRO        // Entered imacro; continue recording.
-                       // Only JSOP_IS_IMACOP opcodes may return this.
+
+/*
+ * Normally, during recording, when the recorder cannot continue, it returns
+ * ARECORD_STOP to indicate that recording should be aborted by the top-level
+ * recording function. However, if the recorder reenters the interpreter (e.g.,
+ * when executing an inner loop), there will be an immediate abort. This
+ * condition must be carefully detected and propagated out of all nested
+ * recorder calls lest the now-invalid TraceRecorder object be accessed
+ * accidentally. This condition is indicated by the ARECORD_ABORTED value.
+ *
+ * The AbortableRecordingStatus enumeration represents the general set of
+ * possible results of calling a recorder function. Functions that cannot
+ * possibly return ARECORD_ABORTED may statically guarantee this to the caller
+ * using the RecordingStatus enumeration. Ideally, C++ would allow subtyping
+ * of enumerations, but it doesn't. To simulate subtype conversion manually,
+ * code should call InjectStatus to inject a value of the restricted set into a
+ * value of the general set.
+ */
+
+enum RecordingStatus {
+    RECORD_ERROR      = 0,  // Error; propagate to interpreter.
+    RECORD_STOP       = 1,  // Recording should be aborted at the top-level
+                            // call to the recorder.
+                            // (value reserved for ARECORD_ABORTED)
+    RECORD_CONTINUE   = 3,  // Continue recording.
+    RECORD_IMACRO     = 4   // Entered imacro; continue recording.
+                            // Only JSOP_IS_IMACOP opcodes may return this.
 };
-#define STATUS_ABORTS_RECORDING(s) ((s) <= JSRS_STOP)
+
+enum AbortableRecordingStatus {
+    ARECORD_ERROR    = 0,
+    ARECORD_STOP     = 1,
+    ARECORD_ABORTED  = 2,  // Recording has already been aborted; the recorder
+                         // has been deleted.
+    ARECORD_CONTINUE = 3,
+    ARECORD_IMACRO   = 4
+};
+
+static JS_ALWAYS_INLINE AbortableRecordingStatus
+InjectStatus(RecordingStatus rs)
+{
+    return static_cast<AbortableRecordingStatus>(rs);
+}
+
+static JS_ALWAYS_INLINE AbortableRecordingStatus
+InjectStatus(AbortableRecordingStatus ars)
+{
+    return ars;
+}
+
+static JS_ALWAYS_INLINE bool
+StatusAbortsRecording(AbortableRecordingStatus ars)
+{
+    return ars <= ARECORD_ABORTED;
+}
 #endif
 
 class SlotMap;
 
 /* Results of trying to compare two typemaps together */
 enum TypeConsensus
 {
     TypeConsensus_Okay,         /* Two typemaps are compatible */
@@ -784,19 +868,19 @@ class TraceRecorder {
         jsval            v;              // current property value
         JSObject         *obj;           // Call object where name was found
         nanojit::LIns    *obj_ins;       // LIR value for obj
         JSScopeProperty  *sprop;         // sprop name was resolved to
     };
 
     JS_REQUIRES_STACK nanojit::LIns* scopeChain() const;
     JS_REQUIRES_STACK JSStackFrame* frameIfInRange(JSObject* obj, unsigned* depthp = NULL) const;
-    JS_REQUIRES_STACK JSRecordingStatus traverseScopeChain(JSObject *obj, nanojit::LIns *obj_ins, JSObject *obj2, nanojit::LIns *&obj2_ins);
-    JS_REQUIRES_STACK JSRecordingStatus scopeChainProp(JSObject* obj, jsval*& vp, nanojit::LIns*& ins, NameResult& nr);
-    JS_REQUIRES_STACK JSRecordingStatus callProp(JSObject* obj, JSProperty* sprop, jsid id, jsval*& vp, nanojit::LIns*& ins, NameResult& nr);
+    JS_REQUIRES_STACK RecordingStatus traverseScopeChain(JSObject *obj, nanojit::LIns *obj_ins, JSObject *obj2, nanojit::LIns *&obj2_ins);
+    JS_REQUIRES_STACK AbortableRecordingStatus scopeChainProp(JSObject* obj, jsval*& vp, nanojit::LIns*& ins, NameResult& nr);
+    JS_REQUIRES_STACK RecordingStatus callProp(JSObject* obj, JSProperty* sprop, jsid id, jsval*& vp, nanojit::LIns*& ins, NameResult& nr);
 
     JS_REQUIRES_STACK nanojit::LIns* arg(unsigned n);
     JS_REQUIRES_STACK void arg(unsigned n, nanojit::LIns* i);
     JS_REQUIRES_STACK nanojit::LIns* var(unsigned n);
     JS_REQUIRES_STACK void var(unsigned n, nanojit::LIns* i);
     JS_REQUIRES_STACK nanojit::LIns* upvar(JSScript* script, JSUpvarArray* uva, uintN index, jsval& v);
     nanojit::LIns* stackLoad(nanojit::LIns* addr, uint8 type);
     JS_REQUIRES_STACK nanojit::LIns* stack(int n);
@@ -805,55 +889,55 @@ class TraceRecorder {
     JS_REQUIRES_STACK nanojit::LIns* alu(nanojit::LOpcode op, jsdouble v0, jsdouble v1,
                                          nanojit::LIns* s0, nanojit::LIns* s1);
     nanojit::LIns* f2i(nanojit::LIns* f);
     JS_REQUIRES_STACK nanojit::LIns* makeNumberInt32(nanojit::LIns* f);
     JS_REQUIRES_STACK nanojit::LIns* stringify(jsval& v);
 
     JS_REQUIRES_STACK nanojit::LIns* newArguments();
 
-    JS_REQUIRES_STACK JSRecordingStatus call_imacro(jsbytecode* imacro);
+    JS_REQUIRES_STACK RecordingStatus call_imacro(jsbytecode* imacro);
 
-    JS_REQUIRES_STACK JSRecordingStatus ifop();
-    JS_REQUIRES_STACK JSRecordingStatus switchop();
+    JS_REQUIRES_STACK AbortableRecordingStatus ifop();
+    JS_REQUIRES_STACK RecordingStatus switchop();
 #ifdef NANOJIT_IA32
-    JS_REQUIRES_STACK JSRecordingStatus tableswitch();
+    JS_REQUIRES_STACK AbortableRecordingStatus tableswitch();
 #endif
-    JS_REQUIRES_STACK JSRecordingStatus inc(jsval& v, jsint incr, bool pre = true);
-    JS_REQUIRES_STACK JSRecordingStatus inc(jsval v, nanojit::LIns*& v_ins, jsint incr,
+    JS_REQUIRES_STACK RecordingStatus inc(jsval& v, jsint incr, bool pre = true);
+    JS_REQUIRES_STACK RecordingStatus inc(jsval v, nanojit::LIns*& v_ins, jsint incr,
                                             bool pre = true);
-    JS_REQUIRES_STACK JSRecordingStatus incHelper(jsval v, nanojit::LIns* v_ins,
+    JS_REQUIRES_STACK RecordingStatus incHelper(jsval v, nanojit::LIns* v_ins,
                                                   nanojit::LIns*& v_after, jsint incr);
-    JS_REQUIRES_STACK JSRecordingStatus incProp(jsint incr, bool pre = true);
-    JS_REQUIRES_STACK JSRecordingStatus incElem(jsint incr, bool pre = true);
-    JS_REQUIRES_STACK JSRecordingStatus incName(jsint incr, bool pre = true);
+    JS_REQUIRES_STACK AbortableRecordingStatus incProp(jsint incr, bool pre = true);
+    JS_REQUIRES_STACK RecordingStatus incElem(jsint incr, bool pre = true);
+    JS_REQUIRES_STACK AbortableRecordingStatus incName(jsint incr, bool pre = true);
 
     JS_REQUIRES_STACK void strictEquality(bool equal, bool cmpCase);
-    JS_REQUIRES_STACK JSRecordingStatus equality(bool negate, bool tryBranchAfterCond);
-    JS_REQUIRES_STACK JSRecordingStatus equalityHelper(jsval l, jsval r,
-                                                       nanojit::LIns* l_ins, nanojit::LIns* r_ins,
-                                                       bool negate, bool tryBranchAfterCond,
-                                                       jsval& rval);
-    JS_REQUIRES_STACK JSRecordingStatus relational(nanojit::LOpcode op, bool tryBranchAfterCond);
+    JS_REQUIRES_STACK AbortableRecordingStatus equality(bool negate, bool tryBranchAfterCond);
+    JS_REQUIRES_STACK AbortableRecordingStatus equalityHelper(jsval l, jsval r,
+                                                                nanojit::LIns* l_ins, nanojit::LIns* r_ins,
+                                                                bool negate, bool tryBranchAfterCond,
+                                                                jsval& rval);
+    JS_REQUIRES_STACK AbortableRecordingStatus relational(nanojit::LOpcode op, bool tryBranchAfterCond);
 
-    JS_REQUIRES_STACK JSRecordingStatus unary(nanojit::LOpcode op);
-    JS_REQUIRES_STACK JSRecordingStatus binary(nanojit::LOpcode op);
+    JS_REQUIRES_STACK RecordingStatus unary(nanojit::LOpcode op);
+    JS_REQUIRES_STACK RecordingStatus binary(nanojit::LOpcode op);
 
     JS_REQUIRES_STACK void guardShape(nanojit::LIns* obj_ins, JSObject* obj,
                                       uint32 shape, const char* guardName,
                                       nanojit::LIns* map_ins, VMSideExit* exit);
 
     inline nanojit::LIns* map(nanojit::LIns *obj_ins);
     JS_REQUIRES_STACK bool map_is_native(JSObjectMap* map, nanojit::LIns* map_ins,
                                          nanojit::LIns*& ops_ins, size_t op_offset = 0);
-    JS_REQUIRES_STACK JSRecordingStatus test_property_cache(JSObject* obj, nanojit::LIns* obj_ins,
-                                                            JSObject*& obj2, jsuword& pcval);
-    JS_REQUIRES_STACK JSRecordingStatus guardNativePropertyOp(JSObject* aobj,
+    JS_REQUIRES_STACK AbortableRecordingStatus test_property_cache(JSObject* obj, nanojit::LIns* obj_ins,
+                                                                     JSObject*& obj2, jsuword& pcval);
+    JS_REQUIRES_STACK RecordingStatus guardNativePropertyOp(JSObject* aobj,
                                                               nanojit::LIns* map_ins);
-    JS_REQUIRES_STACK JSRecordingStatus guardPropertyCacheHit(nanojit::LIns* obj_ins,
+    JS_REQUIRES_STACK RecordingStatus guardPropertyCacheHit(nanojit::LIns* obj_ins,
                                                               nanojit::LIns* map_ins,
                                                               JSObject* aobj,
                                                               JSObject* obj2,
                                                               JSPropCacheEntry* entry,
                                                               jsuword& pcval);
 
     void stobj_set_fslot(nanojit::LIns *obj_ins, unsigned slot,
                          nanojit::LIns* v_ins);
@@ -877,106 +961,106 @@ class TraceRecorder {
     }
 
     nanojit::LIns* stobj_get_parent(nanojit::LIns* obj_ins) {
         return stobj_get_fslot(obj_ins, JSSLOT_PARENT);
     }
 
     nanojit::LIns* getStringLength(nanojit::LIns* str_ins);
 
-    JS_REQUIRES_STACK JSRecordingStatus name(jsval*& vp, nanojit::LIns*& ins, NameResult& nr);
-    JS_REQUIRES_STACK JSRecordingStatus prop(JSObject* obj, nanojit::LIns* obj_ins, uint32 *slotp,
-                                             nanojit::LIns** v_insp, jsval* outp);
-    JS_REQUIRES_STACK JSRecordingStatus denseArrayElement(jsval& oval, jsval& idx, jsval*& vp,
+    JS_REQUIRES_STACK AbortableRecordingStatus name(jsval*& vp, nanojit::LIns*& ins, NameResult& nr);
+    JS_REQUIRES_STACK AbortableRecordingStatus prop(JSObject* obj, nanojit::LIns* obj_ins, uint32 *slotp,
+                                                      nanojit::LIns** v_insp, jsval* outp);
+    JS_REQUIRES_STACK RecordingStatus denseArrayElement(jsval& oval, jsval& idx, jsval*& vp,
                                                           nanojit::LIns*& v_ins,
                                                           nanojit::LIns*& addr_ins);
-    JS_REQUIRES_STACK JSRecordingStatus getProp(JSObject* obj, nanojit::LIns* obj_ins);
-    JS_REQUIRES_STACK JSRecordingStatus getProp(jsval& v);
-    JS_REQUIRES_STACK JSRecordingStatus getThis(nanojit::LIns*& this_ins);
+    JS_REQUIRES_STACK AbortableRecordingStatus getProp(JSObject* obj, nanojit::LIns* obj_ins);
+    JS_REQUIRES_STACK AbortableRecordingStatus getProp(jsval& v);
+    JS_REQUIRES_STACK RecordingStatus getThis(nanojit::LIns*& this_ins);
 
     JS_REQUIRES_STACK VMSideExit* enterDeepBailCall();
     JS_REQUIRES_STACK void leaveDeepBailCall();
 
-    JS_REQUIRES_STACK JSRecordingStatus primitiveToStringInPlace(jsval* vp);
+    JS_REQUIRES_STACK RecordingStatus primitiveToStringInPlace(jsval* vp);
     JS_REQUIRES_STACK void finishGetProp(nanojit::LIns* obj_ins, nanojit::LIns* vp_ins,
                                          nanojit::LIns* ok_ins, jsval* outp);
-    JS_REQUIRES_STACK JSRecordingStatus getPropertyByName(nanojit::LIns* obj_ins, jsval* idvalp,
+    JS_REQUIRES_STACK RecordingStatus getPropertyByName(nanojit::LIns* obj_ins, jsval* idvalp,
                                                           jsval* outp);
-    JS_REQUIRES_STACK JSRecordingStatus getPropertyByIndex(nanojit::LIns* obj_ins,
+    JS_REQUIRES_STACK RecordingStatus getPropertyByIndex(nanojit::LIns* obj_ins,
                                                            nanojit::LIns* index_ins, jsval* outp);
-    JS_REQUIRES_STACK JSRecordingStatus getPropertyById(nanojit::LIns* obj_ins, jsval* outp);
-    JS_REQUIRES_STACK JSRecordingStatus getPropertyWithNativeGetter(nanojit::LIns* obj_ins,
+    JS_REQUIRES_STACK RecordingStatus getPropertyById(nanojit::LIns* obj_ins, jsval* outp);
+    JS_REQUIRES_STACK RecordingStatus getPropertyWithNativeGetter(nanojit::LIns* obj_ins,
                                                                     JSScopeProperty* sprop,
                                                                     jsval* outp);
 
-    JS_REQUIRES_STACK JSRecordingStatus nativeSet(JSObject* obj, nanojit::LIns* obj_ins,
+    JS_REQUIRES_STACK RecordingStatus nativeSet(JSObject* obj, nanojit::LIns* obj_ins,
                                                   JSScopeProperty* sprop,
                                                   jsval v, nanojit::LIns* v_ins);
-    JS_REQUIRES_STACK JSRecordingStatus setProp(jsval &l, JSPropCacheEntry* entry,
+    JS_REQUIRES_STACK RecordingStatus setProp(jsval &l, JSPropCacheEntry* entry,
                                                 JSScopeProperty* sprop,
                                                 jsval &v, nanojit::LIns*& v_ins);
-    JS_REQUIRES_STACK JSRecordingStatus setCallProp(JSObject *callobj, nanojit::LIns *callobj_ins,
+    JS_REQUIRES_STACK RecordingStatus setCallProp(JSObject *callobj, nanojit::LIns *callobj_ins,
                                                     JSScopeProperty *sprop, nanojit::LIns *v_ins,
                                                     jsval v);
-    JS_REQUIRES_STACK JSRecordingStatus initOrSetPropertyByName(nanojit::LIns* obj_ins,
+    JS_REQUIRES_STACK RecordingStatus initOrSetPropertyByName(nanojit::LIns* obj_ins,
                                                                 jsval* idvalp, jsval* rvalp,
                                                                 bool init);
-    JS_REQUIRES_STACK JSRecordingStatus initOrSetPropertyByIndex(nanojit::LIns* obj_ins,
+    JS_REQUIRES_STACK RecordingStatus initOrSetPropertyByIndex(nanojit::LIns* obj_ins,
                                                                  nanojit::LIns* index_ins,
                                                                  jsval* rvalp, bool init);
 
     JS_REQUIRES_STACK nanojit::LIns* box_jsval(jsval v, nanojit::LIns* v_ins);
     JS_REQUIRES_STACK nanojit::LIns* unbox_jsval(jsval v, nanojit::LIns* v_ins, VMSideExit* exit);
     JS_REQUIRES_STACK bool guardClass(JSObject* obj, nanojit::LIns* obj_ins, JSClass* clasp,
                                       VMSideExit* exit);
     JS_REQUIRES_STACK bool guardDenseArray(JSObject* obj, nanojit::LIns* obj_ins,
                                            ExitType exitType = MISMATCH_EXIT);
     JS_REQUIRES_STACK bool guardDenseArray(JSObject* obj, nanojit::LIns* obj_ins,
                                            VMSideExit* exit);
     JS_REQUIRES_STACK bool guardHasPrototype(JSObject* obj, nanojit::LIns* obj_ins,
                                              JSObject** pobj, nanojit::LIns** pobj_ins,
                                              VMSideExit* exit);
-    JS_REQUIRES_STACK JSRecordingStatus guardPrototypeHasNoIndexedProperties(JSObject* obj,
+    JS_REQUIRES_STACK RecordingStatus guardPrototypeHasNoIndexedProperties(JSObject* obj,
                                                                              nanojit::LIns* obj_ins,
                                                                              ExitType exitType);
-    JS_REQUIRES_STACK JSRecordingStatus guardNotGlobalObject(JSObject* obj,
+    JS_REQUIRES_STACK RecordingStatus guardNotGlobalObject(JSObject* obj,
                                                              nanojit::LIns* obj_ins);
     void clearFrameSlotsFromCache();
     JS_REQUIRES_STACK void putArguments();
-    JS_REQUIRES_STACK JSRecordingStatus guardCallee(jsval& callee);
+    JS_REQUIRES_STACK RecordingStatus guardCallee(jsval& callee);
     JS_REQUIRES_STACK JSStackFrame      *guardArguments(JSObject *obj, nanojit::LIns* obj_ins,
                                                         unsigned *depthp);
-    JS_REQUIRES_STACK JSRecordingStatus getClassPrototype(JSObject* ctor,
+    JS_REQUIRES_STACK RecordingStatus getClassPrototype(JSObject* ctor,
                                                           nanojit::LIns*& proto_ins);
-    JS_REQUIRES_STACK JSRecordingStatus getClassPrototype(JSProtoKey key,
+    JS_REQUIRES_STACK RecordingStatus getClassPrototype(JSProtoKey key,
                                                           nanojit::LIns*& proto_ins);
-    JS_REQUIRES_STACK JSRecordingStatus newArray(JSObject* ctor, uint32 argc, jsval* argv,
+    JS_REQUIRES_STACK RecordingStatus newArray(JSObject* ctor, uint32 argc, jsval* argv,
                                                  jsval* rval);
-    JS_REQUIRES_STACK JSRecordingStatus newString(JSObject* ctor, uint32 argc, jsval* argv,
+    JS_REQUIRES_STACK RecordingStatus newString(JSObject* ctor, uint32 argc, jsval* argv,
                                                   jsval* rval);
-    JS_REQUIRES_STACK JSRecordingStatus interpretedFunctionCall(jsval& fval, JSFunction* fun,
+    JS_REQUIRES_STACK RecordingStatus interpretedFunctionCall(jsval& fval, JSFunction* fun,
                                                                 uintN argc, bool constructing);
     JS_REQUIRES_STACK void propagateFailureToBuiltinStatus(nanojit::LIns *ok_ins,
                                                            nanojit::LIns *&status_ins);
-    JS_REQUIRES_STACK JSRecordingStatus emitNativeCall(JSSpecializedNative* sn, uintN argc,
+    JS_REQUIRES_STACK RecordingStatus emitNativeCall(JSSpecializedNative* sn, uintN argc,
                                                        nanojit::LIns* args[], bool rooted);
     JS_REQUIRES_STACK void emitNativePropertyOp(JSScope* scope,
                                                 JSScopeProperty* sprop,
                                                 nanojit::LIns* obj_ins,
                                                 bool setflag,
                                                 nanojit::LIns* boxed_ins);
-    JS_REQUIRES_STACK JSRecordingStatus callSpecializedNative(JSNativeTraceInfo* trcinfo, uintN argc,
+    JS_REQUIRES_STACK RecordingStatus callSpecializedNative(JSNativeTraceInfo* trcinfo, uintN argc,
                                                               bool constructing);
-    JS_REQUIRES_STACK JSRecordingStatus callNative(uintN argc, JSOp mode);
-    JS_REQUIRES_STACK JSRecordingStatus functionCall(uintN argc, JSOp mode);
+    JS_REQUIRES_STACK RecordingStatus callNative(uintN argc, JSOp mode);
+    JS_REQUIRES_STACK RecordingStatus functionCall(uintN argc, JSOp mode);
 
     JS_REQUIRES_STACK void trackCfgMerges(jsbytecode* pc);
     JS_REQUIRES_STACK void emitIf(jsbytecode* pc, bool cond, nanojit::LIns* x);
     JS_REQUIRES_STACK void fuseIf(jsbytecode* pc, bool cond, nanojit::LIns* x);
-    JS_REQUIRES_STACK JSRecordingStatus checkTraceEnd(jsbytecode* pc);
+    JS_REQUIRES_STACK AbortableRecordingStatus checkTraceEnd(jsbytecode* pc);
 
     bool hasMethod(JSObject* obj, jsid id);
     JS_REQUIRES_STACK bool hasIteratorMethod(JSObject* obj);
 
     JS_REQUIRES_STACK jsatomid getFullIndex(ptrdiff_t pcoff = 0);
 
 public:
 
@@ -996,18 +1080,18 @@ public:
     TraceRecorder(JSContext* cx, VMSideExit*, nanojit::Fragment*, TreeInfo*,
                   unsigned stackSlots, unsigned ngslots, JSTraceType* typeMap,
                   VMSideExit* expectedInnerExit, jsbytecode* outerTree,
                   uint32 outerArgc);
     ~TraceRecorder();
 
     bool outOfMemory();
 
-    static JS_REQUIRES_STACK JSRecordingStatus monitorRecording(JSContext* cx, TraceRecorder* tr,
-                                                                JSOp op);
+    static JS_REQUIRES_STACK AbortableRecordingStatus monitorRecording(JSContext* cx, TraceRecorder* tr,
+                                                                         JSOp op);
 
     JS_REQUIRES_STACK JSTraceType determineSlotType(jsval* vp);
 
     /*
      * Examines current interpreter state to record information suitable for
      * returning to the interpreter through a side exit of the given type.
      */
     JS_REQUIRES_STACK VMSideExit* snapshot(ExitType exitType);
@@ -1023,34 +1107,34 @@ public:
      * Creates an instruction whose payload is a GuardRecord for the given exit.
      * The instruction is suitable for use as the final argument of a single
      * call to LirBuffer::insGuard; do not reuse the returned value.
      */
     JS_REQUIRES_STACK nanojit::GuardRecord* createGuardRecord(VMSideExit* exit);
 
     nanojit::Fragment* getFragment() const { return fragment; }
     TreeInfo* getTreeInfo() const { return treeInfo; }
-    JS_REQUIRES_STACK bool compile(JSTraceMonitor* tm);
-    JS_REQUIRES_STACK bool closeLoop(TypeConsensus &consensus);
-    JS_REQUIRES_STACK bool closeLoop(SlotMap& slotMap, VMSideExit* exit, TypeConsensus &consensus);
-    JS_REQUIRES_STACK void endLoop();
-    JS_REQUIRES_STACK void endLoop(VMSideExit* exit);
+    JS_REQUIRES_STACK AbortableRecordingStatus compile(JSTraceMonitor* tm);
+    JS_REQUIRES_STACK AbortableRecordingStatus closeLoop(TypeConsensus &consensus);
+    JS_REQUIRES_STACK AbortableRecordingStatus closeLoop(SlotMap& slotMap, VMSideExit* exit, TypeConsensus &consensus);
+    JS_REQUIRES_STACK AbortableRecordingStatus endLoop();
+    JS_REQUIRES_STACK AbortableRecordingStatus endLoop(VMSideExit* exit);
     JS_REQUIRES_STACK void joinEdgesToEntry(VMFragment* peer_root);
     JS_REQUIRES_STACK void adjustCallerTypes(nanojit::Fragment* f);
     JS_REQUIRES_STACK VMFragment* findNestedCompatiblePeer(VMFragment* f);
     JS_REQUIRES_STACK void prepareTreeCall(VMFragment* inner);
     JS_REQUIRES_STACK void emitTreeCall(VMFragment* inner, VMSideExit* exit);
     unsigned getCallDepth() const;
 
-    JS_REQUIRES_STACK JSRecordingStatus record_EnterFrame();
-    JS_REQUIRES_STACK JSRecordingStatus record_LeaveFrame();
-    JS_REQUIRES_STACK JSRecordingStatus record_SetPropHit(JSPropCacheEntry* entry,
-                                                          JSScopeProperty* sprop);
-    JS_REQUIRES_STACK JSRecordingStatus record_DefLocalFunSetSlot(uint32 slot, JSObject* obj);
-    JS_REQUIRES_STACK JSRecordingStatus record_NativeCallComplete();
+    JS_REQUIRES_STACK AbortableRecordingStatus record_EnterFrame();
+    JS_REQUIRES_STACK AbortableRecordingStatus record_LeaveFrame();
+    JS_REQUIRES_STACK AbortableRecordingStatus record_SetPropHit(JSPropCacheEntry* entry,
+                                                                  JSScopeProperty* sprop);
+    JS_REQUIRES_STACK AbortableRecordingStatus record_DefLocalFunSetSlot(uint32 slot, JSObject* obj);
+    JS_REQUIRES_STACK AbortableRecordingStatus record_NativeCallComplete();
 
     TreeInfo* getTreeInfo() { return treeInfo; }
 
 #ifdef DEBUG
     void tprint(const char *format, int count, nanojit::LIns *insa[]);
     void tprint(const char *format);
     void tprint(const char *format, nanojit::LIns *ins);
     void tprint(const char *format, nanojit::LIns *ins1, nanojit::LIns *ins2);
@@ -1059,17 +1143,17 @@ public:
                 nanojit::LIns *ins4);
     void tprint(const char *format, nanojit::LIns *ins1, nanojit::LIns *ins2, nanojit::LIns *ins3,
                 nanojit::LIns *ins4, nanojit::LIns *ins5);
     void tprint(const char *format, nanojit::LIns *ins1, nanojit::LIns *ins2, nanojit::LIns *ins3,
                 nanojit::LIns *ins4, nanojit::LIns *ins5, nanojit::LIns *ins6);
 #endif
 
 #define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format)               \
-    JS_REQUIRES_STACK JSRecordingStatus record_##op();
+    JS_REQUIRES_STACK AbortableRecordingStatus record_##op();
 # include "jsopcode.tbl"
 #undef OPDEF
 
     friend class ImportBoxedStackSlotVisitor;
     friend class ImportUnboxedStackSlotVisitor;
     friend class ImportGlobalSlotVisitor;
     friend class AdjustCallerGlobalTypesVisitor;
     friend class AdjustCallerStackTypesVisitor;
@@ -1086,24 +1170,24 @@ public:
 #define JSOP_IN_RANGE(op,lo,hi)   (uintN((op) - (lo)) <= uintN((hi) - (lo)))
 #define JSOP_IS_BINARY(op)        JSOP_IN_RANGE(op, JSOP_BITOR, JSOP_MOD)
 #define JSOP_IS_UNARY(op)         JSOP_IN_RANGE(op, JSOP_NEG, JSOP_POS)
 #define JSOP_IS_EQUALITY(op)      JSOP_IN_RANGE(op, JSOP_EQ, JSOP_NE)
 
 #define TRACE_ARGS_(x,args)                                                   \
     JS_BEGIN_MACRO                                                            \
         if (TraceRecorder* tr_ = TRACE_RECORDER(cx)) {                        \
-            JSRecordingStatus status = tr_->record_##x args;                  \
-            if (STATUS_ABORTS_RECORDING(status)) {                            \
+            AbortableRecordingStatus status = tr_->record_##x args;           \
+            if (StatusAbortsRecording(status)) {                              \
                 if (TRACE_RECORDER(cx))                                       \
                     js_AbortRecording(cx, #x);                                \
-                if (status == JSRS_ERROR)                                     \
+                if (status == ARECORD_ERROR)                                  \
                     goto error;                                               \
             }                                                                 \
-            JS_ASSERT(status != JSRS_IMACRO);                                 \
+            JS_ASSERT(status != ARECORD_IMACRO);                              \
         }                                                                     \
     JS_END_MACRO
 
 #define TRACE_ARGS(x,args)      TRACE_ARGS_(x, args)
 #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))