Catch negative indexes at recording time. At runtime the builtins already check for us. Also guard for shape and setters/getters for non-dense integer index setelem case (57580, r=mrbkap).
authorAndreas Gal <gal@mozilla.com>
Sun, 28 Sep 2008 17:11:47 -0700
changeset 20000 358a6b0a757cb99f98a881e7d873399d897468b2
parent 19999 bd6c14287863e19f2b5da0be29b088b8c2e79ee5
child 20001 3c899d350d7ff93e4c3c915221c8ff10a9ca9fa3
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)
reviewersmrbkap
bugs57580
milestone1.9.1b1pre
Catch negative indexes at recording time. At runtime the builtins already check for us. Also guard for shape and setters/getters for non-dense integer index setelem case (57580, r=mrbkap).
js/src/jstracer.cpp
js/src/trace-test.js
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -4794,26 +4794,28 @@ TraceRecorder::record_JSOP_GETELEM()
             ABORT_TRACE("JSOP_GETELEM");
         set(&lval, v_ins);
         return true;
     }
     
     /* At this point we expect a whole number or we bail. */
     if (!JSVAL_IS_INT(idx))
         ABORT_TRACE("non-string, non-int JSOP_GETELEM index");
-
+    if (JSVAL_TO_INT(idx) < 0)
+        ABORT_TRACE("negative JSOP_GETELEM index");
+    
     /* Accessing an object using integer index but not a dense array. */
     if (!OBJ_IS_DENSE_ARRAY(cx, obj)) {
         idx_ins = makeNumberInt32(idx_ins);
+        LIns* args[] = { idx_ins, obj_ins, cx_ins };
         if (!js_IndexToId(cx, JSVAL_TO_INT(idx), &id))
             return false;
         idx = ID_TO_VALUE(id);
         if (!guardElemOp(obj, obj_ins, id, offsetof(JSObjectOps, getProperty), &v))
             return false;
-        LIns* args[] = { idx_ins, obj_ins, cx_ins };
         LIns* v_ins = lir->insCall(F_Any_getelem, args);
         guard(false, lir->ins2(LIR_eq, v_ins, INS_CONST(JSVAL_ERROR_COOKIE)), MISMATCH_EXIT);
         if (!unbox_jsval(v, v_ins))
             ABORT_TRACE("JSOP_GETELEM");
         set(&lval, v_ins);
         return true;
     }
 
@@ -4835,40 +4837,48 @@ 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);
+    jsid id;
 
     LIns* boxed_v_ins = v_ins;
     if (!box_jsval(v, boxed_v_ins))
-        ABORT_TRACE("boxing string-indexed JSOP_SETELEM value");
+        ABORT_TRACE("boxing 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* 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);    
     } else if (JSVAL_IS_INT(idx)) {
+        if (JSVAL_TO_INT(idx) < 0)
+            ABORT_TRACE("negative JSOP_GETELEM index");
         idx_ins = makeNumberInt32(idx_ins);
         LIns* args[] = { boxed_v_ins, idx_ins, obj_ins, cx_ins };
         LIns* res_ins;
-        if (guardDenseArray(obj, obj_ins)) 
+        if (guardDenseArray(obj, obj_ins)) {
             res_ins = lir->insCall(F_Array_dense_setelem, args);
-        else 
+        } else {
+            if (!js_IndexToId(cx, JSVAL_TO_INT(idx), &id))
+                return false;
+            idx = ID_TO_VALUE(id);
+            if (!guardElemOp(obj, obj_ins, id, offsetof(JSObjectOps, getProperty), &v))
+                return false;
             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");
     }
     
     jsbytecode* pc = cx->fp->regs->pc;
     if (*pc == JSOP_SETELEM && pc[JSOP_SETELEM_LENGTH] != JSOP_POP)
         set(&lval, v_ins);
--- a/js/src/trace-test.js
+++ b/js/src/trace-test.js
@@ -1732,11 +1732,19 @@ test(testUndefinedBooleanCmp);
 function testConstantBooleanExpr()
 {
     for (var j = 0; j < 3; ++j) { if(true <= true) { } }
     return "ok";
 }
 testConstantBooleanExpr.expected = "ok";
 test(testConstantBooleanExpr);
 
+function testNegativeGETELEMIndex()
+{
+    for (let i=0;i<3;++i) /x/[-4];
+    return "ok";
+}
+testNegativeGETELEMIndex.expected = "ok";
+test(testNegativeGETELEMIndex);
+
 /* 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(","));