Bug 492915 - Trace incelem/decelem/eleminc/elemdec for objects other than arrays. r=brendan.
authorJason Orendorff <jorendorff@mozilla.com>
Mon, 03 May 2010 16:48:06 -0500
changeset 41877 b7ab81f30d4173126dc1be1054c2204fc75737d3
parent 41876 df1837614a6f77f40f3d89f24eea91991b3d29f0
child 41878 6303a12e08fdc1f396cd0fa3891fdc144d25d203
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersbrendan
bugs492915
milestone1.9.3a5pre
Bug 492915 - Trace incelem/decelem/eleminc/elemdec for objects other than arrays. r=brendan.
js/src/imacros.c.out
js/src/imacros.jsasm
js/src/jstracer.cpp
js/src/trace-test/tests/basic/testDecElem1.js
js/src/trace-test/tests/basic/testDecElem2.js
js/src/trace-test/tests/basic/testElemDec1.js
js/src/trace-test/tests/basic/testElemDec2.js
js/src/trace-test/tests/basic/testElemInc1.js
js/src/trace-test/tests/basic/testElemInc2.js
js/src/trace-test/tests/basic/testIncElem1.js
js/src/trace-test/tests/basic/testIncElem2.js
--- a/js/src/imacros.c.out
+++ b/js/src/imacros.c.out
@@ -252,16 +252,72 @@ static struct {
 /*35*/  JSOP_PRIMTOP, (JSTYPE_NUMBER),
 /*37*/  JSOP_SWAP,
 /*38*/  JSOP_POP,
 /*39*/  JSOP_IMACOP,
 /*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 = {
     {
 /* 0*/  JSOP_DUP,
 /* 1*/  JSOP_DUP,
 /* 2*/  JSOP_GETPROP, 0, COMMON_ATOM_INDEX(toString),
 /* 5*/  JSOP_IFPRIMTOP, 0, 15,
 /* 8*/  JSOP_SWAP,
@@ -739,26 +795,26 @@ uint8 js_opcode2extra[JSOP_LIMIT] = {
     3,  /* JSOP_POS */
     0,  /* JSOP_DELNAME */
     0,  /* JSOP_DELPROP */
     0,  /* JSOP_DELELEM */
     0,  /* JSOP_TYPEOF */
     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 */
     0,  /* JSOP_SETELEM */
     0,  /* JSOP_CALLNAME */
     3,  /* JSOP_CALL */
     0,  /* JSOP_NAME */
     0,  /* JSOP_DOUBLE */
@@ -958,16 +1014,20 @@ uint8 js_opcode2extra[JSOP_LIMIT] = {
  || x == JSOP_URSH \
  || x == JSOP_ADD \
  || x == JSOP_SUB \
  || x == JSOP_MUL \
  || x == JSOP_DIV \
  || 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 \
  || x == JSOP_NEXTITER \
  || x == JSOP_APPLY \
  || x == JSOP_NEW \
  || x == JSOP_CALLPROP \
  || x == JSOP_GETTHISPROP \
@@ -981,16 +1041,20 @@ js_GetImacroStart(jsbytecode* pc) {
     if (size_t(pc - equality_imacros.obj_any) < 38) return equality_imacros.obj_any;
     if (size_t(pc - binary_imacros.any_obj) < 36) return binary_imacros.any_obj;
     if (size_t(pc - binary_imacros.obj_any) < 38) return binary_imacros.obj_any;
     if (size_t(pc - binary_imacros.obj_obj) < 72) return binary_imacros.obj_obj;
     if (size_t(pc - add_imacros.any_obj) < 36) return add_imacros.any_obj;
     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;
     if (size_t(pc - apply_imacros.apply1) < 12) return apply_imacros.apply1;
     if (size_t(pc - apply_imacros.apply2) < 16) return apply_imacros.apply2;
     if (size_t(pc - apply_imacros.apply3) < 21) return apply_imacros.apply3;
     if (size_t(pc - apply_imacros.apply4) < 26) return apply_imacros.apply4;
     if (size_t(pc - apply_imacros.apply5) < 31) return apply_imacros.apply5;
--- a/js/src/imacros.jsasm
+++ b/js/src/imacros.jsasm
@@ -293,16 +293,70 @@ 3:      callprop toString               
         swap                            # lval obj
         pop                             # lval
 4:      imacop                          # aval
         stop
     .end
 
 .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
         dup                                 # String this obj obj
         dup                                 # String this obj obj obj
         getprop toString                    # String this obj obj toString
         ifprimtop 1                         # String this obj obj toString
         swap                                # String this obj toString obj
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -8603,27 +8603,29 @@ 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), MISMATCH_EXIT)) {
-        return RECORD_STOP;
-    }
-
-    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;
+    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;
+    }
+
+    return callImacro((incr == 1)
+                      ? pre ? incelem_imacros.incelem : incelem_imacros.eleminc
+                      : pre ? decelem_imacros.decelem : decelem_imacros.elemdec);
 }
 
 static bool
 EvalCmp(LOpcode op, double l, double r)
 {
     bool cond;
     switch (op) {
       case LIR_feq:
new file mode 100644
--- /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});
+
new file mode 100644
--- /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);
+
new file mode 100644
--- /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});
+
new file mode 100644
--- /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);
+
new file mode 100644
--- /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});
+
new file mode 100644
--- /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);
+
new file mode 100644
--- /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});
+
new file mode 100644
--- /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);
+