am 2f5e3cb2: Merge "Scale the card count by bits per byte to derive a bit vector length."

* commit '2f5e3cb20ed3fa00e474fb4813f2c1f46d04afd4':
  Scale the card count by bits per byte to derive a bit vector length.
diff --git a/docs/dex-format.html b/docs/dex-format.html
index 5a71b59..81c0b36 100644
--- a/docs/dex-format.html
+++ b/docs/dex-format.html
@@ -315,7 +315,7 @@
 
 <h2><code>access_flags</code> Definitions</h2>
 <h4>embedded in <code>class_def_item</code>,
-<code>field_item</code>, <code>method_item</code>, and
+<code>encoded_field</code>, <code>encoded_method</code>, and
 <code>InnerClass</code></h4>
 
 <p>Bitfields of these flags are used to indicate the accessibility and
@@ -2017,7 +2017,7 @@
 </table>
 
 <h2><code>code_item</code></h2>
-<h4>referenced from <code>method_item</code></h4>
+<h4>referenced from <code>encoded_method</code></h4>
 <h4>appears in the <code>data</code> section</h4>
 <h4>alignment: 4 bytes</h4>
 
diff --git a/vm/Jni.c b/vm/Jni.c
index 6f96132..5bff882 100644
--- a/vm/Jni.c
+++ b/vm/Jni.c
@@ -2130,7 +2130,7 @@
         assert(dvmCheckException(_self));
         id = NULL;
     } else {
-        id = (jfieldID) dvmFindStaticField(clazz, name, sig);
+        id = (jfieldID) dvmFindStaticFieldHier(clazz, name, sig);
         if (id == NULL) {
             dvmThrowExceptionFmt(gDvm.exNoSuchFieldError,
                 "no static field with name='%s' signature='%s' in class %s",
diff --git a/vm/Thread.c b/vm/Thread.c
index 087c2e0..62f95aa 100644
--- a/vm/Thread.c
+++ b/vm/Thread.c
@@ -557,7 +557,7 @@
         }
 
         char* threadName = dvmGetThreadName(target);
-        LOGD("threadid=%d: suspending daemon id=%d name='%s'\n",
+        LOGV("threadid=%d: suspending daemon id=%d name='%s'\n",
             threadId, target->threadId, threadName);
         free(threadName);
 
@@ -618,7 +618,7 @@
             }
 
             if (allSuspended) {
-                LOGD("threadid=%d: all daemons have suspended\n", threadId);
+                LOGV("threadid=%d: all daemons have suspended\n", threadId);
                 break;
             } else {
                 if (!complained) {
diff --git a/vm/Thread.h b/vm/Thread.h
index d84682f..4ad3974 100644
--- a/vm/Thread.h
+++ b/vm/Thread.h
@@ -71,7 +71,7 @@
 void dvmSlayDaemons(void);
 
 
-#define kJniLocalRefMin         32
+#define kJniLocalRefMin         64
 #define kJniLocalRefMax         512     /* arbitrary; should be plenty */
 #define kInternalRefDefault     32      /* equally arbitrary */
 #define kInternalRefMax         4096    /* mainly a sanity check */
diff --git a/vm/compiler/Dataflow.h b/vm/compiler/Dataflow.h
index f3d3984..e573d8b 100644
--- a/vm/compiler/Dataflow.h
+++ b/vm/compiler/Dataflow.h
@@ -102,12 +102,16 @@
     bool *fpDef;
 } SSARepresentation;
 
+/*
+ * An induction variable is represented by "m*i + c", where i is a basic
+ * induction variable.
+ */
 typedef struct InductionVariableInfo {
     int ssaReg;
     int basicSSAReg;
-    int m;
-    int c;
-    int inc;
+    int m;      // multiplier
+    int c;      // constant
+    int inc;    // loop incriment
 } InductionVariableInfo;
 
 typedef struct ArrayAccessInfo {
diff --git a/vm/compiler/Loop.c b/vm/compiler/Loop.c
index ba8714c..54517e4 100644
--- a/vm/compiler/Loop.c
+++ b/vm/compiler/Loop.c
@@ -118,20 +118,59 @@
     }
 }
 
+/* Used for normalized loop exit condition checks */
+static Opcode negateOpcode(Opcode opcode)
+{
+    switch (opcode) {
+        /* reg/reg cmp */
+        case OP_IF_EQ:
+            return OP_IF_NE;
+        case OP_IF_NE:
+            return OP_IF_EQ;
+        case OP_IF_LT:
+            return OP_IF_GE;
+        case OP_IF_GE:
+            return OP_IF_LT;
+        case OP_IF_GT:
+            return OP_IF_LE;
+        case OP_IF_LE:
+            return OP_IF_GT;
+        /* reg/zero cmp */
+        case OP_IF_EQZ:
+            return OP_IF_NEZ;
+        case OP_IF_NEZ:
+            return OP_IF_EQZ;
+        case OP_IF_LTZ:
+            return OP_IF_GEZ;
+        case OP_IF_GEZ:
+            return OP_IF_LTZ;
+        case OP_IF_GTZ:
+            return OP_IF_LEZ;
+        case OP_IF_LEZ:
+            return OP_IF_GTZ;
+        default:
+            LOGE("opcode %d cannot be negated", opcode);
+            dvmAbort();
+            break;
+    }
+    return -1;
+}
+
 /*
  * A loop is considered optimizable if:
- * 1) It has one basic induction variable
- * 2) The loop back branch compares the BIV with a constant
- * 3) If it is a count-up loop, the condition is GE/GT, or LE/LT/LEZ/LTZ for
- *    a count-down loop.
+ * 1) It has one basic induction variable.
+ * 2) The loop back branch compares the BIV with a constant.
+ * 3) We need to normalize the loop exit condition so that the loop is exited
+ *    via the taken path.
+ * 4) If it is a count-up loop, the condition is GE/GT. Otherwise it is
+ *    LE/LT/LEZ/LTZ for a count-down loop.
  *
- * Return false if the loop is not optimizable.
+ * Return false for loops that fail the above tests.
  */
 static bool isSimpleCountedLoop(CompilationUnit *cUnit)
 {
     unsigned int i;
-    BasicBlock *loopBranch = findPredecessorBlock(cUnit,
-                                  cUnit->entryBlock->fallThrough);
+    BasicBlock *loopBackBlock = cUnit->entryBlock->fallThrough;
     LoopAnalysis *loopAnalysis = cUnit->loopAnalysis;
 
     if (loopAnalysis->numBasicIV != 1) return false;
@@ -150,67 +189,104 @@
         }
     }
 
-    MIR *branch = loopBranch->lastMIRInsn;
+    /* Find the block that ends with a branch to exit the loop */
+    while (true) {
+        loopBackBlock = findPredecessorBlock(cUnit, loopBackBlock);
+        /* Loop structure not recognized as counted blocks */
+        if (loopBackBlock == NULL) {
+            return false;
+        }
+        /* Unconditional goto - continue to trace up the predecessor chain */
+        if (loopBackBlock->taken == NULL) {
+            continue;
+        }
+        break;
+    }
+
+    MIR *branch = loopBackBlock->lastMIRInsn;
     Opcode opcode = branch->dalvikInsn.opcode;
 
-    /*
-     * If the instruction is not accessing the IV as the first operand, return
-     * false.
-     */
-    if (branch->ssaRep->numUses == 0 || branch->ssaRep->numDefs != 0) {
+    /* Last instruction is not a conditional branch - bail */
+    if (dexGetFlagsFromOpcode(opcode) != (kInstrCanContinue|kInstrCanBranch)) {
         return false;
     }
 
-    /*
-     * If the first operand of the comparison is not the basic induction
-     * variable, return false.
-     */
-    if (branch->ssaRep->uses[0] != loopAnalysis->ssaBIV) {
+    int endSSAReg;
+    int endDalvikReg;
+
+    /* reg/reg comparison */
+    if (branch->ssaRep->numUses == 2) {
+        if (branch->ssaRep->uses[0] == loopAnalysis->ssaBIV) {
+            endSSAReg = branch->ssaRep->uses[1];
+        } else if (branch->ssaRep->uses[1] == loopAnalysis->ssaBIV) {
+            endSSAReg = branch->ssaRep->uses[0];
+            opcode = negateOpcode(opcode);
+        } else {
+            return false;
+        }
+        endDalvikReg = dvmConvertSSARegToDalvik(cUnit, endSSAReg);
+        /*
+         * If the comparison is not between the BIV and a loop invariant,
+         * return false. endDalvikReg is loop invariant if one of the
+         * following is true:
+         * - It is not defined in the loop (ie DECODE_SUB returns 0)
+         * - It is reloaded with a constant
+         */
+        if ((DECODE_SUB(endDalvikReg) != 0) &&
+            !dvmIsBitSet(cUnit->isConstantV, endSSAReg)) {
+            return false;
+        }
+    /* Compare against zero */
+    } else if (branch->ssaRep->numUses == 1) {
+        if (branch->ssaRep->uses[0] == loopAnalysis->ssaBIV) {
+            /* Keep the compiler happy */
+            endDalvikReg = -1;
+        } else {
+            return false;
+        }
+    } else {
         return false;
     }
 
+    /* Normalize the loop exit check as "if (iv op end) exit;" */
+    if (loopBackBlock->taken->blockType == kDalvikByteCode) {
+        opcode = negateOpcode(opcode);
+    }
+
     if (loopAnalysis->isCountUpLoop) {
         /*
-         * If the condition op is not > or >=, this is not an optimization
-         * candidate.
+         * If the normalized condition op is not > or >=, this is not an
+         * optimization candidate.
          */
-        if (opcode != OP_IF_GT && opcode != OP_IF_GE) {
-            return false;
+        switch (opcode) {
+            case OP_IF_GT:
+            case OP_IF_GE:
+                break;
+            default:
+                return false;
         }
-        /*
-         * If the comparison is not between the BIV and a loop invariant,
-         * return false. endReg is loop invariant if one of the following is
-         * true:
-         * - It is not defined in the loop (ie DECODE_SUB returns 0)
-         * - It is reloaded with a constant
-         */
-        int endReg = dvmConvertSSARegToDalvik(cUnit, branch->ssaRep->uses[1]);
-        if (DECODE_SUB(endReg) != 0 &&
-            !dvmIsBitSet(cUnit->isConstantV, branch->ssaRep->uses[1])) {
-            return false;
-        }
-        loopAnalysis->endConditionReg = DECODE_REG(endReg);
+        loopAnalysis->endConditionReg = DECODE_REG(endDalvikReg);
     } else  {
         /*
-         * If the condition op is not < or <=, this is not an optimization
-         * candidate.
+         * If the normalized condition op is not < or <=, this is not an
+         * optimization candidate.
          */
-        if (opcode == OP_IF_LT || opcode == OP_IF_LE) {
-            /*
-             * If the comparison is not between the BIV and a loop invariant,
-             * return false.
-             */
-            int endReg = dvmConvertSSARegToDalvik(cUnit,
-                                                  branch->ssaRep->uses[1]);
-
-            if (DECODE_SUB(endReg) != 0) {
+        switch (opcode) {
+            case OP_IF_LT:
+            case OP_IF_LE:
+                loopAnalysis->endConditionReg = DECODE_REG(endDalvikReg);
+                break;
+            case OP_IF_LTZ:
+            case OP_IF_LEZ:
+                break;
+            default:
                 return false;
-            }
-            loopAnalysis->endConditionReg = DECODE_REG(endReg);
-        } else if (opcode != OP_IF_LTZ && opcode != OP_IF_LEZ) {
-            return false;
         }
     }
+    /*
+     * Remember the normalized opcode, which will be used to determine the end
+     * value used for the yanked range checks.
+     */
     loopAnalysis->loopBranchOpcode = opcode;
     return true;
 }
@@ -432,7 +508,6 @@
                 dvmCompilerAbort(cUnit);
             }
         }
-
     }
 }