author | Boris Zbarsky <bzbarsky@mit.edu> |
Mon, 20 Dec 2010 16:48:28 -0500 | |
changeset 59903 | e10bd9b6cea01fac0967b8a821b83338c5cb0488 |
parent 59902 | 563a9221c6c53ee5fef485fb84d954c25437e6e2 |
child 59904 | e30d605097be22809c11ebac0c9a45de6d24de58 |
push id | 17820 |
push user | cleary@mozilla.com |
push date | Tue, 04 Jan 2011 21:40:57 +0000 |
treeherder | mozilla-central@969691cfe40e [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | njn |
bugs | 617617 |
milestone | 2.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
|
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,