Bug 617617. Remove remnants of the assumption that inc() and incHelper() preserve type. r=njn
authorBoris Zbarsky <bzbarsky@mit.edu>
Mon, 20 Dec 2010 16:48:28 -0500
changeset 59903 e10bd9b6cea01fac0967b8a821b83338c5cb0488
parent 59902 563a9221c6c53ee5fef485fb84d954c25437e6e2
child 59904 e30d605097be22809c11ebac0c9a45de6d24de58
push id17820
push usercleary@mozilla.com
push dateTue, 04 Jan 2011 21:40:57 +0000
treeherdermozilla-central@969691cfe40e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnjn
bugs617617
milestone2.0b8pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 617617. Remove remnants of the assumption that inc() and incHelper() preserve type. r=njn
js/src/jit-test/tests/basic/testStringPropIncrement.js
js/src/jstracer.cpp
js/src/jstracer.h
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/testStringPropIncrement.js
@@ -0,0 +1,16 @@
+function f() {
+    var o = { n: "" };
+    for (var i = 0; i < 2*RUNLOOP; ++i) {
+	o.n = "";
+	if (o.n++) { }
+    }
+}
+
+f();
+
+checkStats({
+    recorderStarted: 1,
+    recorderAborted: 0,
+    traceCompleted: 1,
+    traceTriggered: 1
+});
\ No newline at end of file
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -8674,55 +8674,63 @@ TraceRecorder::switchop()
     }
     return RECORD_CONTINUE;
 }
 
 JS_REQUIRES_STACK RecordingStatus
 TraceRecorder::inc(Value& v, jsint incr, bool pre)
 {
     LIns* v_ins = get(&v);
-    CHECK_STATUS(inc(v, v_ins, incr, pre));
+    Value dummy;
+    CHECK_STATUS(inc(v, v_ins, dummy, incr, pre));
     set(&v, v_ins);
     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.
+ * (pre- or post-increment as described by pre) is stacked.  v_out is set to
+ * the value corresponding to v_ins.
  */
 JS_REQUIRES_STACK RecordingStatus
-TraceRecorder::inc(const Value &v, LIns*& v_ins, jsint incr, bool pre)
+TraceRecorder::inc(const Value &v, LIns*& v_ins, Value &v_out, jsint incr, bool pre)
 {
     LIns* v_after;
-    CHECK_STATUS(incHelper(v, v_ins, v_after, incr));
+    CHECK_STATUS(incHelper(v, v_ins, v_out, v_after, incr));
 
     const JSCodeSpec& cs = js_CodeSpec[*cx->regs->pc];
     JS_ASSERT(cs.ndefs == 1);
     stack(-cs.nuses, pre ? v_after : v_ins);
     v_ins = v_after;
     return RECORD_CONTINUE;
 }
 
 /*
  * Do an increment operation without storing anything to the stack.
+ *
+ * v_after is an out param whose value corresponds to the instruction the
+ * v_ins_after out param gets set to.
  */
 JS_REQUIRES_STACK RecordingStatus
-TraceRecorder::incHelper(const Value &v, LIns*& v_ins, LIns*& v_after, jsint incr)
+TraceRecorder::incHelper(const Value &v, LIns*& v_ins, Value &v_after,
+                         LIns*& v_ins_after, jsint incr)
 {
     // FIXME: Bug 606071 on making this work for objects.
     if (!v.isPrimitive())
         RETURN_STOP("can inc primitives only");
 
     // We need to modify |v_ins| the same way relational() modifies
     // its RHS and LHS.
     if (v.isUndefined()) {
-        v_after = w.immd(js_NaN);
+        v_ins_after = w.immd(js_NaN);
+        v_after.setDouble(js_NaN);
         v_ins = w.immd(js_NaN);
     } else if (v.isNull()) {
-        v_after = w.immd(incr);
+        v_ins_after = w.immd(incr);
+        v_after.setDouble(incr);
         v_ins = w.immd(0.0);
     } else {
         if (v.isBoolean()) {
             v_ins = w.i2d(v_ins);
         } else if (v.isString()) {
             LIns* ok_ins = w.allocp(sizeof(JSBool));
             LIns* args[] = { ok_ins, v_ins, cx_ins };
             v_ins = w.call(&js_StringToNumber_ci, args);
@@ -8732,17 +8740,18 @@ TraceRecorder::incHelper(const Value &v,
         } else {
             JS_ASSERT(v.isNumber());
         }
 
         jsdouble num;
         AutoValueRooter tvr(cx);
         *tvr.addr() = v;
         ValueToNumber(cx, tvr.value(), &num);
-        v_after = alu(LIR_addd, num, incr, v_ins, w.immd(incr));
+        v_ins_after = alu(LIR_addd, num, incr, v_ins, w.immd(incr));
+        v_after.setDouble(num + incr);
     }
 
     return RECORD_CONTINUE;
 }
 
 JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::incProp(jsint incr, bool pre)
 {
@@ -8756,20 +8765,21 @@ TraceRecorder::incProp(jsint incr, bool 
     uint32 slot;
     LIns* v_ins;
     CHECK_STATUS_A(prop(obj, obj_ins, &slot, &v_ins, NULL));
 
     if (slot == SHAPE_INVALID_SLOT)
         RETURN_STOP_A("incProp on invalid slot");
 
     Value& v = obj->getSlotRef(slot);
-    CHECK_STATUS_A(inc(v, v_ins, incr, pre));
+    Value v_after;
+    CHECK_STATUS_A(inc(v, v_ins, v_after, incr, pre));
 
     LIns* slots_ins = NULL;
-    stobj_set_slot(obj, obj_ins, slot, slots_ins, v, v_ins);
+    stobj_set_slot(obj, obj_ins, slot, slots_ins, v_after, v_ins);
     return ARECORD_CONTINUE;
 }
 
 JS_REQUIRES_STACK RecordingStatus
 TraceRecorder::incElem(jsint incr, bool pre)
 {
     Value& r = stackval(-1);
     Value& l = stackval(-2);
@@ -8777,18 +8787,19 @@ TraceRecorder::incElem(jsint incr, bool 
     LIns* v_ins;
     LIns* addr_ins;
 
     if (!l.isPrimitive() && l.toObject().isDenseArray() && r.isInt32()) {
         guardDenseArray(get(&l), MISMATCH_EXIT);
         CHECK_STATUS(denseArrayElement(l, r, vp, v_ins, addr_ins, snapshot(BRANCH_EXIT)));
         if (!addr_ins) // if we read a hole, abort
             return RECORD_STOP;
-        CHECK_STATUS(inc(*vp, v_ins, incr, pre));
-        box_value_into(*vp, v_ins, DSlotsAddress(addr_ins));
+        Value v_after;
+        CHECK_STATUS(inc(*vp, v_ins, v_after, incr, pre));
+        box_value_into(v_after, v_ins, DSlotsAddress(addr_ins));
         return RECORD_CONTINUE;
     }
 
     return callImacro((incr == 1)
                       ? pre ? incelem_imacros.incelem : incelem_imacros.eleminc
                       : pre ? decelem_imacros.decelem : decelem_imacros.elemdec);
 }
 
@@ -11782,34 +11793,35 @@ TraceRecorder::record_JSOP_DECELEM()
     return InjectStatus(incElem(-1));
 }
 
 JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::incName(jsint incr, bool pre)
 {
     Value* vp;
     LIns* v_ins;
-    LIns* v_after;
+    LIns* v_ins_after;
     NameResult nr;
 
     CHECK_STATUS_A(name(vp, v_ins, nr));
     Value v = nr.tracked ? *vp : nr.v;
-    CHECK_STATUS_A(incHelper(v, v_ins, v_after, incr));
-    LIns* v_result = pre ? v_after : v_ins;
+    Value v_after;
+    CHECK_STATUS_A(incHelper(v, v_ins, v_after, v_ins_after, incr));
+    LIns* v_ins_result = pre ? v_ins_after : v_ins;
     if (nr.tracked) {
-        set(vp, v_after);
-        stack(0, v_result);
+        set(vp, v_ins_after);
+        stack(0, v_ins_result);
         return ARECORD_CONTINUE;
     }
 
     if (!nr.obj->isCall())
         RETURN_STOP_A("incName on unsupported object class");
 
-    CHECK_STATUS_A(setCallProp(nr.obj, nr.obj_ins, nr.shape, v_after, v));
-    stack(0, v_result);
+    CHECK_STATUS_A(setCallProp(nr.obj, nr.obj_ins, nr.shape, v_ins_after, v_after));
+    stack(0, v_ins_result);
     return ARECORD_CONTINUE;
 }
 
 JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_NAMEINC()
 {
     return incName(1, false);
 }
--- a/js/src/jstracer.h
+++ b/js/src/jstracer.h
@@ -1287,20 +1287,23 @@ class TraceRecorder
     JS_REQUIRES_STACK RecordingStatus callImacroInfallibly(jsbytecode* imacro);
 
     JS_REQUIRES_STACK AbortableRecordingStatus ifop();
     JS_REQUIRES_STACK RecordingStatus switchop();
 #ifdef NANOJIT_IA32
     JS_REQUIRES_STACK AbortableRecordingStatus tableswitch();
 #endif
     JS_REQUIRES_STACK RecordingStatus inc(Value& v, jsint incr, bool pre = true);
-    JS_REQUIRES_STACK RecordingStatus inc(const Value &v, nanojit::LIns*& v_ins, jsint incr,
-                                            bool pre = true);
+    JS_REQUIRES_STACK RecordingStatus inc(const Value &v, nanojit::LIns*& v_ins,
+                                          Value &v_out, jsint incr,
+                                          bool pre = true);
     JS_REQUIRES_STACK RecordingStatus incHelper(const Value &v, nanojit::LIns*& v_ins,
-                                                  nanojit::LIns*& v_after, jsint incr);
+                                                Value &v_after,
+                                                nanojit::LIns*& v_ins_after,
+                                                jsint incr);
     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 RecordingStatus strictEquality(bool equal, bool cmpCase);
     JS_REQUIRES_STACK AbortableRecordingStatus equality(bool negate, bool tryBranchAfterCond);
     JS_REQUIRES_STACK AbortableRecordingStatus equalityHelper(Value& l, Value& r,
                                                                 nanojit::LIns* l_ins, nanojit::LIns* r_ins,