From cb43b0920f26f9f8d260988a7b1ef0845afa0848 Mon Sep 17 00:00:00 2001 From: Jason Orendorff Date: Mon, 3 May 2010 16:48:06 -0500 Subject: [PATCH] Bug 492915 - Trace incelem/decelem/eleminc/elemdec for objects other than arrays. r=brendan. --HG-- extra : rebase_source : 33ab817997096bd4b00c8a36bb0444dcacc58a27 --- js/src/imacros.c.out | 72 +++++++++++++++++-- js/src/imacros.jsasm | 54 ++++++++++++++ js/src/jstracer.cpp | 20 +++--- js/src/trace-test/tests/basic/testDecElem1.js | 10 +++ js/src/trace-test/tests/basic/testDecElem2.js | 11 +++ js/src/trace-test/tests/basic/testElemDec1.js | 10 +++ js/src/trace-test/tests/basic/testElemDec2.js | 7 ++ js/src/trace-test/tests/basic/testElemInc1.js | 10 +++ js/src/trace-test/tests/basic/testElemInc2.js | 7 ++ js/src/trace-test/tests/basic/testIncElem1.js | 10 +++ js/src/trace-test/tests/basic/testIncElem2.js | 11 +++ 11 files changed, 209 insertions(+), 13 deletions(-) create mode 100644 js/src/trace-test/tests/basic/testDecElem1.js create mode 100644 js/src/trace-test/tests/basic/testDecElem2.js create mode 100644 js/src/trace-test/tests/basic/testElemDec1.js create mode 100644 js/src/trace-test/tests/basic/testElemDec2.js create mode 100644 js/src/trace-test/tests/basic/testElemInc1.js create mode 100644 js/src/trace-test/tests/basic/testElemInc2.js create mode 100644 js/src/trace-test/tests/basic/testIncElem1.js create mode 100644 js/src/trace-test/tests/basic/testIncElem2.js diff --git a/js/src/imacros.c.out b/js/src/imacros.c.out index 6d936c1afc54..391a1c3a3197 100644 --- a/js/src/imacros.c.out +++ b/js/src/imacros.c.out @@ -256,6 +256,62 @@ static struct { /*40*/ JSOP_STOP, }, }; +static struct { + jsbytecode incelem[7]; + jsbytecode eleminc[15]; +} incelem_imacros = { + { +/* 0*/ JSOP_DUP2, +/* 1*/ JSOP_GETELEM, +/* 2*/ JSOP_POS, +/* 3*/ JSOP_ONE, +/* 4*/ JSOP_ADD, +/* 5*/ JSOP_SETELEM, +/* 6*/ JSOP_STOP, + }, + { +/* 0*/ JSOP_DUP2, +/* 1*/ JSOP_GETELEM, +/* 2*/ JSOP_POS, +/* 3*/ JSOP_DUP, +/* 4*/ JSOP_ONE, +/* 5*/ JSOP_ADD, +/* 6*/ JSOP_PICK, 3, +/* 8*/ JSOP_PICK, 3, +/*10*/ JSOP_PICK, 2, +/*12*/ JSOP_SETELEM, +/*13*/ JSOP_POP, +/*14*/ JSOP_STOP, + }, +}; +static struct { + jsbytecode decelem[7]; + jsbytecode elemdec[15]; +} decelem_imacros = { + { +/* 0*/ JSOP_DUP2, +/* 1*/ JSOP_GETELEM, +/* 2*/ JSOP_POS, +/* 3*/ JSOP_ONE, +/* 4*/ JSOP_SUB, +/* 5*/ JSOP_SETELEM, +/* 6*/ JSOP_STOP, + }, + { +/* 0*/ JSOP_DUP2, +/* 1*/ JSOP_GETELEM, +/* 2*/ JSOP_POS, +/* 3*/ JSOP_DUP, +/* 4*/ JSOP_ONE, +/* 5*/ JSOP_SUB, +/* 6*/ JSOP_PICK, 3, +/* 8*/ JSOP_PICK, 3, +/*10*/ JSOP_PICK, 2, +/*12*/ JSOP_SETELEM, +/*13*/ JSOP_POP, +/*14*/ JSOP_STOP, + }, +}; static struct { jsbytecode String[38]; } call_imacros = { @@ -744,16 +800,16 @@ uint8 js_opcode2extra[JSOP_LIMIT] = { 0, /* JSOP_VOID */ 0, /* JSOP_INCNAME */ 0, /* JSOP_INCPROP */ - 0, /* JSOP_INCELEM */ + 3, /* JSOP_INCELEM */ 0, /* JSOP_DECNAME */ 0, /* JSOP_DECPROP */ - 0, /* JSOP_DECELEM */ + 3, /* JSOP_DECELEM */ 0, /* JSOP_NAMEINC */ 0, /* JSOP_PROPINC */ - 0, /* JSOP_ELEMINC */ + 3, /* JSOP_ELEMINC */ 0, /* JSOP_NAMEDEC */ 0, /* JSOP_PROPDEC */ - 0, /* JSOP_ELEMDEC */ + 3, /* JSOP_ELEMDEC */ 1, /* JSOP_GETPROP */ 0, /* JSOP_SETPROP */ 0, /* JSOP_GETELEM */ @@ -963,6 +1019,10 @@ uint8 js_opcode2extra[JSOP_LIMIT] = { || x == JSOP_MOD \ || x == JSOP_NEG \ || x == JSOP_POS \ + || x == JSOP_INCELEM \ + || x == JSOP_DECELEM \ + || x == JSOP_ELEMINC \ + || x == JSOP_ELEMDEC \ || x == JSOP_GETPROP \ || x == JSOP_CALL \ || x == JSOP_ITER \ @@ -986,6 +1046,10 @@ js_GetImacroStart(jsbytecode* pc) { if (size_t(pc - add_imacros.obj_any) < 38) return add_imacros.obj_any; if (size_t(pc - add_imacros.obj_obj) < 72) return add_imacros.obj_obj; if (size_t(pc - unary_imacros.sign) < 41) return unary_imacros.sign; + if (size_t(pc - incelem_imacros.incelem) < 7) return incelem_imacros.incelem; + if (size_t(pc - incelem_imacros.eleminc) < 15) return incelem_imacros.eleminc; + if (size_t(pc - decelem_imacros.decelem) < 7) return decelem_imacros.decelem; + if (size_t(pc - decelem_imacros.elemdec) < 15) return decelem_imacros.elemdec; if (size_t(pc - call_imacros.String) < 38) return call_imacros.String; if (size_t(pc - new_imacros.String) < 38) return new_imacros.String; if (size_t(pc - apply_imacros.apply0) < 8) return apply_imacros.apply0; diff --git a/js/src/imacros.jsasm b/js/src/imacros.jsasm index 989996e3ddc5..9af50b5d7dc9 100644 --- a/js/src/imacros.jsasm +++ b/js/src/imacros.jsasm @@ -298,6 +298,60 @@ .end unary +.igroup incelem JSOP_INCELEM,JSOP_ELEMINC + .imacro incelem # obj id + dup2 # obj id obj id + getelem # obj id val + pos # obj id n + one # obj id n 1 + add # obj id m + setelem # m + stop + .end + + .imacro eleminc # obj id + dup2 # obj id obj id + getelem # obj id val + pos # obj id n + dup # obj id n n + one # obj id n n 1 + add # obj id n m + pick 3 # id n m obj + pick 3 # n m obj id + pick 2 # n obj id m + setelem # n m + pop # n + stop + .end +.end incelem + +.igroup decelem JSOP_DECELEM,JSOP_ELEMDEC + .imacro decelem # obj id + dup2 # obj id obj id + getelem # obj id val + pos # obj id n + one # obj id n 1 + sub # obj id m + setelem # m + stop + .end + + .imacro elemdec # obj id + dup2 # obj id obj id + getelem # obj id val + pos # obj id n + dup # obj id n n + one # obj id n n 1 + sub # obj id n m + pick 3 # id n m obj + pick 3 # n m obj id + pick 2 # n obj id m + setelem # n m + pop # n + stop + .end +.end decelem + .igroup call JSOP_CALL .imacro String # String this obj diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index 77548bb35289..f3a1b19afaa5 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -8608,17 +8608,19 @@ TraceRecorder::incElem(jsint incr, bool pre) LIns* v_ins; LIns* addr_ins; - if (JSVAL_IS_PRIMITIVE(l) || !JSVAL_IS_INT(r) || - !guardDenseArray(JSVAL_TO_OBJECT(l), get(&l), MISMATCH_EXIT)) { - return RECORD_STOP; + if (!JSVAL_IS_PRIMITIVE(l) && JSVAL_TO_OBJECT(l)->isDenseArray() && JSVAL_IS_INT(r)) { + JS_ALWAYS_TRUE(guardDenseArray(JSVAL_TO_OBJECT(l), get(&l), MISMATCH_EXIT)); + CHECK_STATUS(denseArrayElement(l, r, vp, v_ins, addr_ins)); + if (!addr_ins) // if we read a hole, abort + return RECORD_STOP; + CHECK_STATUS(inc(*vp, v_ins, incr, pre)); + lir->insStore(box_jsval(*vp, v_ins), addr_ins, 0, ACC_OTHER); + return RECORD_CONTINUE; } - CHECK_STATUS(denseArrayElement(l, r, vp, v_ins, addr_ins)); - if (!addr_ins) // if we read a hole, abort - return RECORD_STOP; - CHECK_STATUS(inc(*vp, v_ins, incr, pre)); - lir->insStore(box_jsval(*vp, v_ins), addr_ins, 0, ACC_OTHER); - return RECORD_CONTINUE; + return callImacro((incr == 1) + ? pre ? incelem_imacros.incelem : incelem_imacros.eleminc + : pre ? decelem_imacros.decelem : decelem_imacros.elemdec); } static bool diff --git a/js/src/trace-test/tests/basic/testDecElem1.js b/js/src/trace-test/tests/basic/testDecElem1.js new file mode 100644 index 000000000000..e95403086880 --- /dev/null +++ b/js/src/trace-test/tests/basic/testDecElem1.js @@ -0,0 +1,10 @@ +var obj = {p: 100}; +var name = "p"; +var a = []; +for (var i = 0; i < 10; i++) + a[i] = --obj[name]; +assertEq(a.join(','), '99,98,97,96,95,94,93,92,91,90'); +assertEq(obj.p, 90); + +checkStats({recorderStarted: 1, recorderAborted: 0, traceCompleted: 1, traceTriggered: 1}); + diff --git a/js/src/trace-test/tests/basic/testDecElem2.js b/js/src/trace-test/tests/basic/testDecElem2.js new file mode 100644 index 000000000000..5327f40ab93b --- /dev/null +++ b/js/src/trace-test/tests/basic/testDecElem2.js @@ -0,0 +1,11 @@ +var obj = {s: ""}; +var name = "s"; +var a = []; +for (var i = 0; i <= RECORDLOOP + 5; i++) { + a[i] = 'x'; + if (i > RECORDLOOP) + a[i] = --obj[name]; // first recording changes obj.s from string to number +} +assertEq(a.join(','), Array(RECORDLOOP + 2).join('x,') + '-1,-2,-3,-4,-5'); +assertEq(obj.s, -5); + diff --git a/js/src/trace-test/tests/basic/testElemDec1.js b/js/src/trace-test/tests/basic/testElemDec1.js new file mode 100644 index 000000000000..5c5f7a705bff --- /dev/null +++ b/js/src/trace-test/tests/basic/testElemDec1.js @@ -0,0 +1,10 @@ +var obj = {p: 100}; +var name = "p"; +var a = []; +for (var i = 0; i < 10; i++) + a[i] = obj[name]--; +assertEq(a.join(','), '100,99,98,97,96,95,94,93,92,91'); +assertEq(obj.p, 90); + +checkStats({recorderStarted: 1, recorderAborted: 0, traceCompleted: 1, traceTriggered: 1}); + diff --git a/js/src/trace-test/tests/basic/testElemDec2.js b/js/src/trace-test/tests/basic/testElemDec2.js new file mode 100644 index 000000000000..1388d39e546f --- /dev/null +++ b/js/src/trace-test/tests/basic/testElemDec2.js @@ -0,0 +1,7 @@ +var obj = {s: ""}; +var name = "s"; +for (var i = 0; i <= RECORDLOOP + 5; i++) + if (i > RECORDLOOP) + obj[name]--; // first recording changes obj.s from string to number +assertEq(obj.s, -5); + diff --git a/js/src/trace-test/tests/basic/testElemInc1.js b/js/src/trace-test/tests/basic/testElemInc1.js new file mode 100644 index 000000000000..84a0c74b2e5d --- /dev/null +++ b/js/src/trace-test/tests/basic/testElemInc1.js @@ -0,0 +1,10 @@ +var obj = {p: 100}; +var name = "p"; +var a = []; +for (var i = 0; i < 10; i++) + a[i] = obj[name]++; +assertEq(a.join(','), '100,101,102,103,104,105,106,107,108,109'); +assertEq(obj.p, 110); + +checkStats({recorderStarted: 1, recorderAborted: 0, traceCompleted: 1, traceTriggered: 1}); + diff --git a/js/src/trace-test/tests/basic/testElemInc2.js b/js/src/trace-test/tests/basic/testElemInc2.js new file mode 100644 index 000000000000..9a1712d63769 --- /dev/null +++ b/js/src/trace-test/tests/basic/testElemInc2.js @@ -0,0 +1,7 @@ +var obj = {s: ""}; +var name = "s"; +for (var i = 0; i <= RECORDLOOP + 5; i++) + if (i > RECORDLOOP) + obj[name]++; // first recording changes obj.s from string to number +assertEq(obj.s, 5); + diff --git a/js/src/trace-test/tests/basic/testIncElem1.js b/js/src/trace-test/tests/basic/testIncElem1.js new file mode 100644 index 000000000000..2f8ddf69e178 --- /dev/null +++ b/js/src/trace-test/tests/basic/testIncElem1.js @@ -0,0 +1,10 @@ +var obj = {p: 100}; +var name = "p"; +var a = []; +for (var i = 0; i < 10; i++) + a[i] = ++obj[name]; +assertEq(a.join(','), '101,102,103,104,105,106,107,108,109,110'); +assertEq(obj.p, 110); + +checkStats({recorderStarted: 1, recorderAborted: 0, traceCompleted: 1, traceTriggered: 1}); + diff --git a/js/src/trace-test/tests/basic/testIncElem2.js b/js/src/trace-test/tests/basic/testIncElem2.js new file mode 100644 index 000000000000..93ae1891e07e --- /dev/null +++ b/js/src/trace-test/tests/basic/testIncElem2.js @@ -0,0 +1,11 @@ +var obj = {s: ""}; +var name = "s"; +var a = []; +for (var i = 0; i <= RECORDLOOP + 5; i++) { + a[i] = 'x'; + if (i > RECORDLOOP) + a[i] = ++obj[name]; // first recording changes obj.s from string to number +} +assertEq(a.join(','), Array(RECORDLOOP + 2).join('x,') + '1,2,3,4,5'); +assertEq(obj.s, 5); +