Bug 507446 - TM: use return values instead of outparams for box_jsval, unbox_jsval. r=dmandelin.
authorJason Orendorff <jorendorff@mozilla.com>
Wed, 19 Aug 2009 17:00:18 -0500
changeset 31902 0b47a120e4e11260f76afd618da474f45cbcec6f
parent 31901 15166116171f252bb017f2554700980ce8766212
child 31903 427326d92dfbe6d9cda5004eaade7253ffe13b94
push idunknown
push userunknown
push dateunknown
reviewersdmandelin
bugs507446
milestone1.9.3a1pre
Bug 507446 - TM: use return values instead of outparams for box_jsval, unbox_jsval. r=dmandelin.
js/src/jstracer.cpp
js/src/jstracer.h
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -2794,19 +2794,18 @@ public:
     {}
 
     JS_REQUIRES_STACK JS_ALWAYS_INLINE bool
     visitStackSlots(jsval *vp, size_t count, JSStackFrame* fp) {
         for (size_t i = 0; i < count; ++i) {
             if (*mTypemap == TT_JSVAL) {
                 mRecorder.import(mBase, mStackOffset, vp, TT_JSVAL,
                                  "jsval", i, fp);
-                LIns *vp_ins = mRecorder.get(vp);
-                mRecorder.unbox_jsval(*vp, vp_ins,
-                                      mRecorder.copy(mRecorder.anchor));
+                LIns *vp_ins = mRecorder.unbox_jsval(*vp, mRecorder.get(vp),
+                                                     mRecorder.copy(mRecorder.anchor));
                 mRecorder.set(vp, vp_ins);
             }
             vp++;
             mTypemap++;
             mStackOffset += sizeof(double);
         }
         return true;
     }
@@ -6074,17 +6073,17 @@ TraceRecorder::monitorRecording(JSContex
     if (tr->pendingGuardCondition) {
         tr->guard(true, tr->pendingGuardCondition, STATUS_EXIT);
         tr->pendingGuardCondition = NULL;
     }
 
     /* Handle one-shot request to unbox the result of a property get. */
     if (tr->pendingUnboxSlot) {
         LIns* val_ins = tr->get(tr->pendingUnboxSlot);
-        tr->unbox_jsval(*tr->pendingUnboxSlot, val_ins, tr->snapshot(BRANCH_EXIT));
+        val_ins = tr->unbox_jsval(*tr->pendingUnboxSlot, val_ins, tr->snapshot(BRANCH_EXIT));
         tr->set(tr->pendingUnboxSlot, val_ins);
         tr->pendingUnboxSlot = 0;
     }
 
     debug_only_stmt(
         if (js_LogController.lcbits & LC_TMRecorder) {
             js_Disassemble1(cx, cx->fp->script, cx->fp->regs->pc,
                             cx->fp->imacpc
@@ -7411,20 +7410,18 @@ TraceRecorder::incProp(jsint incr, bool 
     CHECK_STATUS(prop(obj, obj_ins, slot, v_ins));
 
     if (slot == SPROP_INVALID_SLOT)
         ABORT_TRACE("incProp on invalid slot");
 
     jsval& v = STOBJ_GET_SLOT(obj, slot);
     CHECK_STATUS(inc(v, v_ins, incr, pre));
 
-    box_jsval(v, v_ins);
-
     LIns* dslots_ins = NULL;
-    stobj_set_slot(obj_ins, slot, dslots_ins, v_ins);
+    stobj_set_slot(obj_ins, slot, dslots_ins, box_jsval(v, v_ins));
     return JSRS_CONTINUE;
 }
 
 JS_REQUIRES_STACK JSRecordingStatus
 TraceRecorder::incElem(jsint incr, bool pre)
 {
     jsval& r = stackval(-1);
     jsval& l = stackval(-2);
@@ -7436,18 +7433,17 @@ TraceRecorder::incElem(jsint incr, bool 
         !guardDenseArray(JSVAL_TO_OBJECT(l), get(&l))) {
         return JSRS_STOP;
     }
 
     CHECK_STATUS(denseArrayElement(l, r, vp, v_ins, addr_ins));
     if (!addr_ins) // if we read a hole, abort
         return JSRS_STOP;
     CHECK_STATUS(inc(*vp, v_ins, incr, pre));
-    box_jsval(*vp, v_ins);
-    lir->insStorei(v_ins, addr_ins, 0);
+    lir->insStorei(box_jsval(*vp, v_ins), addr_ins, 0);
     return JSRS_CONTINUE;
 }
 
 static bool
 EvalCmp(LOpcode op, double l, double r)
 {
     bool cond;
     switch (op) {
@@ -8184,65 +8180,62 @@ TraceRecorder::native_get(LIns* obj_ins,
 
     if (sprop->slot != SPROP_INVALID_SLOT)
         v_ins = stobj_get_slot(pobj_ins, sprop->slot, dslots_ins);
     else
         v_ins = INS_CONST(JSVAL_TO_SPECIAL(JSVAL_VOID));
     return JSRS_CONTINUE;
 }
 
-JS_REQUIRES_STACK void
-TraceRecorder::box_jsval(jsval v, LIns*& v_ins)
+JS_REQUIRES_STACK LIns*
+TraceRecorder::box_jsval(jsval v, LIns* v_ins)
 {
     if (isNumber(v)) {
         LIns* args[] = { v_ins, cx_ins };
         v_ins = lir->insCall(&js_BoxDouble_ci, args);
         guard(false, lir->ins2(LIR_eq, v_ins, INS_CONST(JSVAL_ERROR_COOKIE)),
               OOM_EXIT);
-        return;
+        return v_ins;
     }
     switch (JSVAL_TAG(v)) {
       case JSVAL_SPECIAL:
-        v_ins = lir->ins2i(LIR_pior, lir->ins2i(LIR_pilsh, v_ins, JSVAL_TAGBITS), JSVAL_SPECIAL);
-        return;
+        return lir->ins2i(LIR_pior, lir->ins2i(LIR_pilsh, v_ins, JSVAL_TAGBITS), JSVAL_SPECIAL);
       case JSVAL_OBJECT:
-        return;
+        return v_ins;
       default:
         JS_ASSERT(JSVAL_TAG(v) == JSVAL_STRING);
-        v_ins = lir->ins2(LIR_pior, v_ins, INS_CONST(JSVAL_STRING));
-        return;
-    }
-}
-
-JS_REQUIRES_STACK void
-TraceRecorder::unbox_jsval(jsval v, LIns*& v_ins, VMSideExit* exit)
+        return lir->ins2(LIR_pior, v_ins, INS_CONST(JSVAL_STRING));
+    }
+}
+
+JS_REQUIRES_STACK LIns*
+TraceRecorder::unbox_jsval(jsval v, LIns* v_ins, VMSideExit* exit)
 {
     if (isNumber(v)) {
         // JSVAL_IS_NUMBER(v)
         guard(false,
               lir->ins_eq0(lir->ins2(LIR_pior,
                                      lir->ins2(LIR_piand, v_ins, INS_CONST(JSVAL_INT)),
                                      lir->ins2i(LIR_eq,
                                                 lir->ins2(LIR_piand, v_ins,
                                                           INS_CONST(JSVAL_TAGMASK)),
                                                 JSVAL_DOUBLE))),
               exit);
         LIns* args[] = { v_ins };
-        v_ins = lir->insCall(&js_UnboxDouble_ci, args);
-        return;
+        return lir->insCall(&js_UnboxDouble_ci, args);
     }
     switch (JSVAL_TAG(v)) {
       case JSVAL_SPECIAL:
         guard(true,
               lir->ins2i(LIR_eq,
                          lir->ins2(LIR_piand, v_ins, INS_CONST(JSVAL_TAGMASK)),
                          JSVAL_SPECIAL),
               exit);
-        v_ins = lir->ins2i(LIR_ush, v_ins, JSVAL_TAGBITS);
-        return;
+        return lir->ins2i(LIR_ush, v_ins, JSVAL_TAGBITS);
+
       case JSVAL_OBJECT:
         if (JSVAL_IS_NULL(v)) {
             // JSVAL_NULL maps to type TT_NULL, so insist that v_ins == 0 here.
             guard(true, lir->ins_eq0(v_ins), exit);
         } else {
             guard(false, lir->ins_eq0(v_ins), exit);
             guard(true,
                   lir->ins2i(LIR_eq,
@@ -8252,26 +8245,26 @@ TraceRecorder::unbox_jsval(jsval v, LIns
             guard(HAS_FUNCTION_CLASS(JSVAL_TO_OBJECT(v)),
                   lir->ins2(LIR_eq,
                             lir->ins2(LIR_piand,
                                       lir->insLoad(LIR_ldp, v_ins, offsetof(JSObject, classword)),
                                       INS_CONSTWORD(~JSSLOT_CLASS_MASK_BITS)),
                             INS_CONSTPTR(&js_FunctionClass)),
                   exit);
         }
-        return;
+        return v_ins;
+
       default:
         JS_ASSERT(JSVAL_TAG(v) == JSVAL_STRING);
         guard(true,
               lir->ins2i(LIR_eq,
                         lir->ins2(LIR_piand, v_ins, INS_CONST(JSVAL_TAGMASK)),
                         JSVAL_STRING),
               exit);
-        v_ins = lir->ins2(LIR_piand, v_ins, INS_CONST(~JSVAL_TAGMASK));
-        return;
+        return lir->ins2(LIR_piand, v_ins, INS_CONST(~JSVAL_TAGMASK));
     }
 }
 
 JS_REQUIRES_STACK JSRecordingStatus
 TraceRecorder::getThis(LIns*& this_ins)
 {
     /*
      * js_ComputeThisForFrame updates cx->fp->argv[-1], so sample it into 'original' first.
@@ -8490,18 +8483,17 @@ TraceRecorder::clearFrameSlotsFromCache(
  */
 JS_REQUIRES_STACK void
 TraceRecorder::putArguments()
 {
     if (cx->fp->argsobj && cx->fp->argc) {
         LIns* argsobj_ins = get(&cx->fp->argsobj);
         LIns* args_ins = lir->insAlloc(sizeof(jsval) * cx->fp->argc);
         for (uintN i = 0; i < cx->fp->argc; ++i) {
-            LIns* arg_ins = get(&cx->fp->argv[i]);
-            box_jsval(cx->fp->argv[i], arg_ins);
+            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
@@ -8573,18 +8565,17 @@ TraceRecorder::record_JSOP_PUSH()
     stack(0, INS_CONST(JSVAL_TO_SPECIAL(JSVAL_VOID)));
     return JSRS_CONTINUE;
 }
 
 JS_REQUIRES_STACK JSRecordingStatus
 TraceRecorder::record_JSOP_POPV()
 {
     jsval& rval = stackval(-1);
-    LIns *rval_ins = get(&rval);
-    box_jsval(rval, rval_ins);
+    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;
 }
@@ -9059,18 +9050,17 @@ TraceRecorder::newArray(JSObject* ctor, 
         LIns *args[] = { INS_CONST(argc), proto_ins, cx_ins };
         arr_ins = lir->insCall(&js_NewUninitializedArray_ci, args);
         guard(false, lir->ins_eq0(arr_ins), OOM_EXIT);
 
         // arr->dslots[i] = box_jsval(vp[i]);  for i in 0..argc
         LIns *dslots_ins = NULL;
         VMAllocator *alloc = traceMonitor->allocator;
         for (uint32 i = 0; i < argc && !alloc->outOfMemory(); i++) {
-            LIns *elt_ins = get(argv + i);
-            box_jsval(argv[i], elt_ins);
+            LIns *elt_ins = box_jsval(argv[i], get(&argv[i]));
             stobj_set_dslot(arr_ins, i, dslots_ins, elt_ins);
         }
 
         if (argc > 0)
             stobj_set_fslot(arr_ins, JSSLOT_ARRAY_COUNT, INS_CONST(argc));
     }
 
     set(rval, arr_ins);
@@ -9301,17 +9291,17 @@ TraceRecorder::callTraceableNative(JSFun
                     goto next_specialization;
             } else if (argtype == 'r') {
                 if (!VALUE_IS_REGEXP(cx, arg))
                     goto next_specialization;
             } else if (argtype == 'f') {
                 if (!VALUE_IS_FUNCTION(cx, arg))
                     goto next_specialization;
             } else if (argtype == 'v') {
-                box_jsval(arg, *argp);
+                *argp = box_jsval(arg, *argp);
             } else {
                 goto next_specialization;
             }
             argp--;
         }
 #if defined DEBUG
         JS_ASSERT(args[0] != (LIns *)0xcdcdcdcd);
 #endif
@@ -9433,25 +9423,24 @@ TraceRecorder::callNative(uintN argc, JS
                 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");
 
                 this_ins = lir->ins_choose(lir->ins_eq0(stobj_get_fslot(this_ins, JSSLOT_PARENT)),
                                            INS_CONSTOBJ(globalObj),
                                            this_ins);
             }
         }
-        box_jsval(vp[1], this_ins);
+        this_ins = box_jsval(vp[1], this_ins);
     }
     lir->insStorei(this_ins, invokevp_ins, 1 * sizeof(jsval));
 
     VMAllocator *alloc = traceMonitor->allocator;
     // Populate argv.
     for (uintN n = 2; n < 2 + argc; n++) {
-        LIns* i = get(&vp[n]);
-        box_jsval(vp[n], i);
+        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 (alloc->outOfMemory())
             ABORT_TRACE("out of memory in argument list");
     }
 
@@ -9793,38 +9782,30 @@ TraceRecorder::nativeSet(JSObject* obj, 
      * setter's return value differed from the record-time type of v, in which
      * case unboxing would fail and, having called a native setter, we could
      * not just retry the instruction in the interpreter.
      */
     JS_ASSERT(SPROP_HAS_STUB_SETTER(sprop) || slot == SPROP_INVALID_SLOT);
 
     // Box the value to be stored, if necessary.
     LIns* boxed_ins = NULL;
-    if (!SPROP_HAS_STUB_SETTER(sprop) || (slot != SPROP_INVALID_SLOT && obj != globalObj)) {
-        boxed_ins = v_ins;
-        box_jsval(v, boxed_ins);
-    }
+    if (!SPROP_HAS_STUB_SETTER(sprop) || (slot != SPROP_INVALID_SLOT && obj != globalObj))
+        boxed_ins = box_jsval(v, v_ins);
 
     // Call the setter, if any.
     if (!SPROP_HAS_STUB_SETTER(sprop))
         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");
-
-            // If we called a native setter, unbox the result.
-            if (!SPROP_HAS_STUB_SETTER(sprop)) {
-                v_ins = boxed_ins;
-                unbox_jsval(STOBJ_GET_SLOT(obj, slot), v_ins, snapshot(BRANCH_EXIT));
-            }
             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;
@@ -9928,19 +9909,18 @@ TraceRecorder::setCallProp(JSObject *cal
     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");
 
-    box_jsval(v, v_ins);
     LIns* args[] = {
-        v_ins,
+        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;
 }
@@ -10271,18 +10251,17 @@ InitPropertyByName(JSContext* cx, JSObje
 JS_DEFINE_CALLINFO_4(static, BOOL_FAIL, InitPropertyByName, CONTEXT, OBJECT, STRINGPTR, JSVAL,
                      0, 0)
 
 JS_REQUIRES_STACK JSRecordingStatus
 TraceRecorder::initOrSetPropertyByName(LIns* obj_ins, jsval* idvalp, jsval* rvalp, bool init)
 {
     CHECK_STATUS(primitiveToStringInPlace(idvalp));
 
-    LIns* rval_ins = get(rvalp);
-    box_jsval(*rvalp, rval_ins);
+    LIns* rval_ins = box_jsval(*rvalp, get(rvalp));
 
     enterDeepBailCall();
 
     LIns* ok_ins;
     LIns* idvalp_ins = addName(addr(idvalp), "idvalp");
     if (init) {
         LIns* args[] = {rval_ins, idvalp_ins, obj_ins, cx_ins};
         ok_ins = lir->insCall(&InitPropertyByName_ci, args);
@@ -10328,18 +10307,17 @@ InitPropertyByIndex(JSContext* cx, JSObj
 }
 JS_DEFINE_CALLINFO_4(static, BOOL_FAIL, InitPropertyByIndex, CONTEXT, OBJECT, INT32, JSVAL, 0, 0)
 
 JS_REQUIRES_STACK JSRecordingStatus
 TraceRecorder::initOrSetPropertyByIndex(LIns* obj_ins, LIns* index_ins, jsval* rvalp, bool init)
 {
     index_ins = makeNumberInt32(index_ins);
 
-    LIns* rval_ins = get(rvalp);
-    box_jsval(*rvalp, rval_ins);
+    LIns* rval_ins = box_jsval(*rvalp, get(rvalp));
 
     enterDeepBailCall();
 
     LIns* ok_ins;
     if (init) {
         LIns* args[] = {rval_ins, index_ins, obj_ins, cx_ins};
         ok_ins = lir->insCall(&InitPropertyByIndex_ci, args);
     } else {
@@ -10393,20 +10371,17 @@ TraceRecorder::record_JSOP_SETELEM()
         // 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.
         LIns* res_ins;
         if (isNumber(v) && isPromoteInt(v_ins)) {
             LIns* args[] = { ::demote(lir, v_ins), idx_ins, obj_ins, cx_ins };
             res_ins = lir->insCall(&js_Array_dense_setelem_int_ci, args);
         } else {
-            LIns* boxed_v_ins = v_ins;
-            box_jsval(v, boxed_v_ins);
-
-            LIns* args[] = { boxed_v_ins, idx_ins, obj_ins, cx_ins };
+            LIns* args[] = { box_jsval(v, v_ins), idx_ins, obj_ins, cx_ins };
             res_ins = lir->insCall(&js_Array_dense_setelem_ci, args);
         }
         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);
@@ -10576,18 +10551,17 @@ TraceRecorder::record_JSOP_GETDSLOT()
 {
     JSObject* callee = cx->fp->callee;
     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);
 
-    unbox_jsval(callee->dslots[index], v_ins, snapshot(BRANCH_EXIT));
-    stack(0, v_ins);
+    stack(0, unbox_jsval(callee->dslots[index], v_ins, snapshot(BRANCH_EXIT)));
     return JSRS_CONTINUE;
 }
 
 JS_REQUIRES_STACK JSRecordingStatus
 TraceRecorder::record_JSOP_CALLDSLOT()
 {
     CHECK_STATUS(record_JSOP_GETDSLOT());
     stack(1, INS_NULL());
@@ -10893,18 +10867,17 @@ TraceRecorder::record_NativeCallComplete
     JSRecordingStatus ok = JSRS_CONTINUE;
     if (pendingTraceableNative->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);
-        unbox_jsval(v, v_ins, snapshot(BRANCH_EXIT));
-        set(&v, v_ins);
+        set(&v, unbox_jsval(v, v_ins, snapshot(BRANCH_EXIT)));
     } else if (JSTN_ERRTYPE(pendingTraceableNative) == FAIL_NEG) {
         /* Already added i2f in functionCall. */
         JS_ASSERT(JSVAL_IS_NUMBER(v));
     } else {
         /* Convert the result to double if the builtin returns int32. */
         if (JSVAL_IS_NUMBER(v) &&
             (pendingTraceableNative->builtin->_argtypes & ARGSIZE_MASK_ANY) == ARGSIZE_LO) {
             set(&v, lir->ins1(LIR_i2f, v_ins));
@@ -11042,19 +11015,20 @@ TraceRecorder::prop(JSObject* obj, LIns*
                 LIns* args[] = { INS_CONSTSPROP(sprop), obj_ins, cx_ins };
                 v_ins = lir->insCall(&js_CallGetter_ci, args);
                 guard(false, lir->ins2(LIR_eq, v_ins, INS_CONST(JSVAL_ERROR_COOKIE)), OOM_EXIT);
 
                 /*
                  * BIG FAT WARNING: This snapshot cannot be a BRANCH_EXIT, since
                  * the value to the top of the stack is not the value we unbox.
                  */
-                unbox_jsval((sprop->shortid == REGEXP_SOURCE) ? JSVAL_STRING : JSVAL_SPECIAL,
-                            v_ins,
-                            snapshot(MISMATCH_EXIT));
+                v_ins =
+                    unbox_jsval((sprop->shortid == REGEXP_SOURCE) ? JSVAL_STRING : JSVAL_SPECIAL,
+                                v_ins,
+                                snapshot(MISMATCH_EXIT));
                 return JSRS_CONTINUE;
             }
             if (setflags == 0 &&
                 sprop->getter == js_StringClass.getProperty &&
                 sprop->id == ATOM_KEY(cx->runtime->atomState.lengthAtom)) {
                 if (!guardClass(obj, obj_ins, &js_StringClass, snapshot(MISMATCH_EXIT)))
                     ABORT_TRACE("can't trace String.length on non-String objects");
                 LIns* str_ins = stobj_get_private(obj_ins, JSVAL_TAGMASK);
@@ -11083,18 +11057,19 @@ TraceRecorder::prop(JSObject* obj, LIns*
          */
         while (obj != obj2) {
             obj_ins = stobj_get_fslot(obj_ins, JSSLOT_PROTO);
             obj = STOBJ_GET_PROTO(obj);
         }
     }
 
     LIns* dslots_ins = NULL;
-    v_ins = stobj_get_slot(obj_ins, slot, dslots_ins);
-    unbox_jsval(STOBJ_GET_SLOT(obj, slot), v_ins, snapshot(BRANCH_EXIT));
+    v_ins = unbox_jsval(STOBJ_GET_SLOT(obj, slot),
+                        stobj_get_slot(obj_ins, slot, dslots_ins),
+                        snapshot(BRANCH_EXIT));
 
     return JSRS_CONTINUE;
 }
 
 JS_REQUIRES_STACK JSRecordingStatus
 TraceRecorder::denseArrayElement(jsval& oval, jsval& ival, jsval*& vp, LIns*& v_ins,
                                  LIns*& addr_ins)
 {
@@ -11179,18 +11154,17 @@ TraceRecorder::denseArrayElement(jsval& 
                     idx_ins,
                     lir->insLoad(LIR_ldp, dslots_ins, 0 - (int)sizeof(jsval))),
           exit);
 
     /* Load the value and guard on its type to unbox it. */
     vp = &obj->dslots[jsuint(idx)];
     addr_ins = lir->ins2(LIR_piadd, dslots_ins,
                          lir->ins2i(LIR_pilsh, idx_ins, (sizeof(jsval) == 4) ? 2 : 3));
-    v_ins = lir->insLoad(LIR_ldp, addr_ins, 0);
-    unbox_jsval(*vp, v_ins, exit);
+    v_ins = unbox_jsval(*vp, lir->insLoad(LIR_ldp, addr_ins, 0), exit);
 
     if (JSVAL_IS_SPECIAL(*vp)) {
         /*
          * If we read a hole from the array, convert it to undefined and guard
          * that there are no indexed properties along the prototype chain.
          */
         LIns* br = lir->insBranch(LIR_jf,
                                   lir->ins2i(LIR_eq, v_ins, JSVAL_TO_SPECIAL(JSVAL_HOLE)),
@@ -11752,18 +11726,17 @@ JS_REQUIRES_STACK JSRecordingStatus
 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");
 
     jsval& val = stackval(-2);
-    LIns* val_ins = get(&val);
-    box_jsval(val, val_ins);
+    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));
     guard(true, lir->ins_eq0(status_ins), STATUS_EXIT);
@@ -11918,19 +11891,18 @@ TraceRecorder::record_JSOP_LAMBDA_FC()
 
     if (fun->u.i.nupvars) {
         JSUpvarArray *uva = JS_SCRIPT_UPVARS(fun->u.i.script);
         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;
-            box_jsval(v, upvar_ins);
             LIns* dslots_ins = NULL;
-            stobj_set_dslot(call_ins, i, dslots_ins, upvar_ins);
+            stobj_set_dslot(call_ins, i, dslots_ins, box_jsval(v, upvar_ins));
         }
     }
 
     return JSRS_CONTINUE;
 }
 
 JS_REQUIRES_STACK JSRecordingStatus
 TraceRecorder::record_JSOP_CALLEE()
@@ -12589,18 +12561,17 @@ 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 = get(&elt);
-    box_jsval(elt, elt_ins);
+    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
@@ -12878,18 +12849,17 @@ TraceRecorder::record_JSOP_NEWARRAY()
     guard(false, lir->ins_eq0(v_ins), OOM_EXIT);
 
     LIns* dslots_ins = NULL;
     uint32 count = 0;
     for (uint32 i = 0; i < len; i++) {
         jsval& v = stackval(int(i) - int(len));
         if (v != JSVAL_HOLE)
             count++;
-        LIns* elt_ins = get(&v);
-        box_jsval(v, elt_ins);
+        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;
--- a/js/src/jstracer.h
+++ b/js/src/jstracer.h
@@ -835,18 +835,18 @@ class TraceRecorder : public avmplus::GC
                                                     jsval v);
     JS_REQUIRES_STACK JSRecordingStatus initOrSetPropertyByName(nanojit::LIns* obj_ins,
                                                                 jsval* idvalp, jsval* rvalp,
                                                                 bool init);
     JS_REQUIRES_STACK JSRecordingStatus initOrSetPropertyByIndex(nanojit::LIns* obj_ins,
                                                                  nanojit::LIns* index_ins,
                                                                  jsval* rvalp, bool init);
 
-    JS_REQUIRES_STACK void box_jsval(jsval v, nanojit::LIns*& v_ins);
-    JS_REQUIRES_STACK void unbox_jsval(jsval v, nanojit::LIns*& v_ins, VMSideExit* exit);
+    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 guardHasPrototype(JSObject* obj, nanojit::LIns* obj_ins,
                                              JSObject** pobj, nanojit::LIns** pobj_ins,
                                              VMSideExit* exit);
     JS_REQUIRES_STACK JSRecordingStatus guardPrototypeHasNoIndexedProperties(JSObject* obj,