Cleanup SETELEM, box early (in case we side exit on that) and don't set return value if INITELEM or followed by POP (457336, r=brendan).
authorAndreas Gal <gal@mozilla.com>
Fri, 26 Sep 2008 17:33:40 -0700
changeset 19993 cfa7088079dadada0940c005d2b1b761304df089
parent 19992 7b29d221e3564ab124c7104437c56b9e56fe1a3f
child 19994 af4d2ab298e07b9f66bc8566308c799d904fc37e
child 19995 3bdea835df9ce1a54404fb2cabf09a9272cf835e
push id2577
push userbrendan@mozilla.com
push dateWed, 01 Oct 2008 04:35:27 +0000
treeherdermozilla-central@a613924403d6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbrendan
bugs457336
milestone1.9.1b1pre
Cleanup SETELEM, box early (in case we side exit on that) and don't set return value if INITELEM or followed by POP (457336, r=brendan).
js/src/jstracer.cpp
js/src/trace-test.js
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -4808,62 +4808,49 @@ TraceRecorder::record_JSOP_SETELEM()
     /* no guards for type checks, trace specialized this already */
     if (JSVAL_IS_PRIMITIVE(lval))
         ABORT_TRACE("left JSOP_SETELEM operand is not an object");
 
     JSObject* obj = JSVAL_TO_OBJECT(lval);
     LIns* obj_ins = get(&lval);
     LIns* idx_ins = get(&idx);
     LIns* v_ins = get(&v);
+
+    LIns* boxed_v_ins = v_ins;
+    if (!box_jsval(v, boxed_v_ins))
+        ABORT_TRACE("boxing string-indexed JSOP_SETELEM value");
     
     if (JSVAL_IS_STRING(idx)) {
         jsid id;
         if (!js_ValueToStringId(cx, idx, &id))
             return false;
         // Store the interned string to the stack to save the interpreter from redoing this work.
         idx = ID_TO_VALUE(id);
         if (!guardElemOp(obj, obj_ins, id, offsetof(JSObjectOps, setProperty), NULL))
             return false;
-        LIns* unboxed_v_ins = v_ins;
-        if (!box_jsval(v, v_ins))
-            ABORT_TRACE("boxing string-indexed JSOP_SETELEM value");
-        LIns* args[] = { v_ins, idx_ins, obj_ins, cx_ins };
+        LIns* args[] = { boxed_v_ins, idx_ins, obj_ins, cx_ins };
         LIns* ok_ins = lir->insCall(F_Any_setprop, args);
-        guard(false, lir->ins_eq0(ok_ins), MISMATCH_EXIT);
-        set(&lval, unboxed_v_ins);
-        return true;
-    }
-
-    if (!JSVAL_IS_INT(idx))
+        guard(false, lir->ins_eq0(ok_ins), MISMATCH_EXIT);    
+    } else if (JSVAL_IS_INT(idx)) {
+        idx_ins = makeNumberInt32(idx_ins);
+        LIns* args[] = { boxed_v_ins, idx_ins, obj_ins, cx_ins };
+        LIns* res_ins;
+        if (guardDenseArray(obj, obj_ins)) 
+            res_ins = lir->insCall(F_Array_dense_setelem, args);
+        else 
+            res_ins = lir->insCall(F_Any_setelem, args);
+        guard(false, lir->ins_eq0(res_ins), MISMATCH_EXIT);
+    } else {
         ABORT_TRACE("non-string, non-int JSOP_SETELEM index");
-
-    idx_ins = makeNumberInt32(idx_ins);
+    }
     
-    if (!guardDenseArray(obj, obj_ins)) {
-        LIns* unboxed_v_ins = v_ins;
-        if (!box_jsval(v, v_ins))
-            ABORT_TRACE("boxing string-indexed JSOP_SETELEM value");
-        LIns* args[] = { v_ins, idx_ins, obj_ins, cx_ins };
-        LIns* ok_ins = lir->insCall(F_Any_setelem, args);
-        guard(false, lir->ins_eq0(ok_ins), MISMATCH_EXIT);
-        set(&lval, unboxed_v_ins);
-        return true;
-    }
-
-    /* ok, box the value we are storing, store it and we are done */
-    LIns* boxed_ins = v_ins;
-    if (!box_jsval(v, boxed_ins))
-        ABORT_TRACE("boxing failed");
-    LIns* args[] = { boxed_ins, idx_ins, obj_ins, cx_ins };
-    LIns* res_ins = lir->insCall(F_Array_dense_setelem, 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);
+
     return true;
 }
 
 bool
 TraceRecorder::record_JSOP_CALLNAME()
 {
     JSObject* obj = cx->fp->scopeChain;
     if (obj != globalObj) {
--- a/js/src/trace-test.js
+++ b/js/src/trace-test.js
@@ -1670,18 +1670,17 @@ testRUNLOOPCorrectness.jitstats = {
     recorderStarted: 1,
     recorderAborted: 0,
     traceTriggered: 1
 };
 // Change the global shape right before doing the test
 this.testRUNLOOPCorrectnessVar = 1;
 test(testRUNLOOPCorrectness);
 
-function testDateNow()
-{
+function testDateNow() {
     // Accessing global.Date for the first time will change the global shape,
     // so do it before the loop starts; otherwise we have to loop an extra time
     // to pick things up.
     var time = Date.now();
     for (var j = 0; j < RUNLOOP; ++j) {
 	time = Date.now();
     }
     return "ok";
@@ -1689,11 +1688,21 @@ function testDateNow()
 testDateNow.expected = "ok";
 testDateNow.jitstats = {
     recorderStarted: 1,
     recorderAborted: 0,
     traceTriggered: 1
 };
 test(testDateNow);
 
+function testINITELEM() 
+{
+    var x;
+    for (var i = 0; i < 10; ++i)
+	x = { 0: 5, 1: 5 };    
+    return x[0] + x[1];
+}
+testINITELEM.expected = 10;
+test(testINITELEM);
+
 /* Keep these at the end so that we can see the summary after the trace-debug spew. */
 print("\npassed:", passes.length && passes.join(","));
 print("\nFAILED:", fails.length && fails.join(","));