Check for operations on integers in loops, bug 689892. r=dvander
authorBrian Hackett <bhackett1024@gmail.com>
Mon, 03 Oct 2011 14:43:09 -0700
changeset 78031 28a549e9041047f280aaeff17139021c2711294a
parent 78030 ae1ba25d7d07e1df9c75f9c4d2b72eff4bc7722c
child 78032 c6405a1d4b2271705bf1f74a73cf4d1808afe108
push id2350
push userbhackett@mozilla.com
push dateMon, 03 Oct 2011 21:43:30 +0000
treeherdermozilla-inbound@28a549e90410 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdvander
bugs689892
milestone10.0a1
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
Check for operations on integers in loops, bug 689892. r=dvander
js/src/jsanalyze.h
js/src/jsinfer.cpp
js/src/methodjit/LoopState.cpp
--- a/js/src/jsanalyze.h
+++ b/js/src/jsanalyze.h
@@ -1090,16 +1090,19 @@ class ScriptAnalysis
 
     types::TypeSet *poppedTypes(uint32 offset, uint32 which) {
         return getValueTypes(poppedValue(offset, which));
     }
     types::TypeSet *poppedTypes(const jsbytecode *pc, uint32 which) {
         return getValueTypes(poppedValue(pc, which));
     }
 
+    /* Whether an arithmetic operation is operating on integers, with an integer result. */
+    bool integerOperation(JSContext *cx, jsbytecode *pc);
+
     bool trackUseChain(const SSAValue &v) {
         JS_ASSERT_IF(v.kind() == SSAValue::VAR, trackSlot(v.varSlot()));
         return v.kind() != SSAValue::EMPTY &&
             (v.kind() != SSAValue::VAR || !v.varInitial());
     }
 
     /*
      * Get the use chain for an SSA value. May be invalid for some opcodes in
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -4268,16 +4268,59 @@ ScriptAnalysis::followEscapingArguments(
     }
 
     if (op == JSOP_GETLOCAL)
         return followEscapingArguments(cx, SSAValue::PushedValue(use->offset, 0), seen);
 
     return false;
 }
 
+bool
+ScriptAnalysis::integerOperation(JSContext *cx, jsbytecode *pc)
+{
+    uint32 offset = pc - script->code;
+    JS_ASSERT(offset < script->length);
+
+    switch (JSOp(*pc)) {
+
+      case JSOP_INCARG:
+      case JSOP_DECARG:
+      case JSOP_ARGINC:
+      case JSOP_ARGDEC:
+      case JSOP_INCLOCAL:
+      case JSOP_DECLOCAL:
+      case JSOP_LOCALINC:
+      case JSOP_LOCALDEC: {
+        if (pushedTypes(pc, 0)->getKnownTypeTag(cx) != JSVAL_TYPE_INT32)
+            return false;
+        uint32 slot = GetBytecodeSlot(script, pc);
+        if (trackSlot(slot)) {
+            if (poppedTypes(pc, 0)->getKnownTypeTag(cx) != JSVAL_TYPE_INT32)
+                return false;
+        }
+        return true;
+      }
+
+      case JSOP_ADD:
+      case JSOP_SUB:
+      case JSOP_MUL:
+      case JSOP_DIV:
+        if (pushedTypes(pc, 0)->getKnownTypeTag(cx) != JSVAL_TYPE_INT32)
+            return false;
+        if (poppedTypes(pc, 0)->getKnownTypeTag(cx) != JSVAL_TYPE_INT32)
+            return false;
+        if (poppedTypes(pc, 1)->getKnownTypeTag(cx) != JSVAL_TYPE_INT32)
+            return false;
+        return true;
+
+      default:
+        return true;
+    }
+}
+
 /*
  * Persistent constraint clearing out newScript and definite properties from
  * an object should a property on another object get a setter.
  */
 class TypeConstraintClearDefiniteSetter : public TypeConstraint
 {
 public:
     TypeObject *object;
--- a/js/src/methodjit/LoopState.cpp
+++ b/js/src/methodjit/LoopState.cpp
@@ -984,16 +984,19 @@ LoopState::cannotIntegerOverflow(const C
      * Compute a slot and constant such that the result of the binary op is
      * 'slot + constant', where slot is expressed in terms of its value at
      * the head of the loop.
      */
     JS_ASSERT(pushed.v.kind() == SSAValue::PUSHED);
     jsbytecode *PC = ssa->getFrame(pushed.frame).script->code + pushed.v.pushedOffset();
     ScriptAnalysis *analysis = ssa->getFrame(pushed.frame).script->analysis();
 
+    if (!analysis->integerOperation(cx, PC))
+        return false;
+
     uint32 baseSlot = UNASSIGNED;
     int32 baseConstant = 0;
     JSOp op = JSOp(*PC);
     switch (op) {
 
       case JSOP_INCLOCAL:
       case JSOP_LOCALINC:
       case JSOP_INCARG:
@@ -1526,16 +1529,18 @@ LoopState::getLoopTestAccess(const SSAVa
       case JSOP_INCLOCAL:
       case JSOP_DECLOCAL:
       case JSOP_LOCALINC:
       case JSOP_LOCALDEC:
       case JSOP_INCARG:
       case JSOP_DECARG:
       case JSOP_ARGINC:
       case JSOP_ARGDEC: {
+        if (!outerAnalysis->integerOperation(cx, pc))
+            return false;
         uint32 slot = GetBytecodeSlot(outerScript, pc);
         if (outerAnalysis->slotEscapes(slot))
             return false;
 
         *pslot = slot;
         if (cs->format & JOF_POST) {
             if (cs->format & JOF_INC)
                 *pconstant = -1;
@@ -1663,21 +1668,21 @@ LoopState::analyzeLoopIncrements()
     for (uint32 slot = ArgSlot(0); slot < LocalSlot(outerScript, outerScript->nfixed); slot++) {
         if (outerAnalysis->slotEscapes(slot))
             continue;
 
         uint32 offset = outerAnalysis->liveness(slot).onlyWrite(lifetime);
         if (offset == uint32(-1) || offset < lifetime->lastBlock)
             continue;
 
-        JSOp op = JSOp(outerScript->code[offset]);
+        jsbytecode *pc = outerScript->code + offset;
+        JSOp op = JSOp(*pc);
         const JSCodeSpec *cs = &js_CodeSpec[op];
         if (cs->format & (JOF_INC | JOF_DEC)) {
-            TypeSet *types = outerAnalysis->pushedTypes(offset);
-            if (types->getKnownTypeTag(cx) != JSVAL_TYPE_INT32)
+            if (!outerAnalysis->integerOperation(cx, pc))
                 continue;
 
             Increment inc;
             inc.slot = slot;
             inc.offset = offset;
             increments.append(inc);
         }
     }
@@ -2132,17 +2137,17 @@ LoopState::getEntryValue(const CrossSSAV
     switch (op) {
 
       case JSOP_GETLOCAL:
       case JSOP_LOCALINC:
       case JSOP_INCLOCAL:
       case JSOP_GETARG:
       case JSOP_ARGINC:
       case JSOP_INCARG: {
-        if (cv.frame != CrossScriptSSA::OUTER_FRAME)
+        if (cv.frame != CrossScriptSSA::OUTER_FRAME || !analysis->integerOperation(cx, pc))
             return false;
         uint32 slot = GetBytecodeSlot(outerScript, pc);
         if (outerAnalysis->slotEscapes(slot))
             return false;
         uint32 write = outerAnalysis->liveness(slot).firstWrite(lifetime);
         if (write != uint32(-1) && write < v.pushedOffset()) {
             /* Variable has been modified since the start of the loop. */
             return false;