Merge "Correct verifier merging of primitive arrays" into dalvik-dev
diff --git a/vm/analysis/CodeVerify.c b/vm/analysis/CodeVerify.c
index dcd8252..d2b3a2c 100644
--- a/vm/analysis/CodeVerify.c
+++ b/vm/analysis/CodeVerify.c
@@ -2262,6 +2262,12 @@
  * If the dimensions don't match, we want to convert to an array of Object
  * with the least dimension, e.g. String[][] + String[][][][] = Object[][].
  *
+ * Arrays of primitive types effectively have one less dimension when
+ * merging.  int[] + float[] = Object, int[] + String[] = Object,
+ * int[][] + float[][] = Object[], int[][] + String[] = Object[].  (The
+ * only time this function doesn't return an array class is when one of
+ * the arguments is a 1-dimensional primitive array.)
+ *
  * This gets a little awkward because we may have to ask the VM to create
  * a new array type with the appropriate element and dimensions.  However, we
  * shouldn't be doing this often.
@@ -2270,28 +2276,56 @@
 {
     ClassObject* arrayClass = NULL;
     ClassObject* commonElem;
+    int arrayDim1, arrayDim2;
     int i, numDims;
+    bool hasPrimitive = false;
 
+    arrayDim1 = c1->arrayDim;
+    arrayDim2 = c2->arrayDim;
     assert(c1->arrayDim > 0);
     assert(c2->arrayDim > 0);
 
-    if (c1->arrayDim == c2->arrayDim) {
-        //commonElem = digForSuperclass(c1->elementClass, c2->elementClass);
-        commonElem = findCommonSuperclass(c1->elementClass, c2->elementClass);
-        numDims = c1->arrayDim;
-    } else {
-        if (c1->arrayDim < c2->arrayDim)
-            numDims = c1->arrayDim;
-        else
-            numDims = c2->arrayDim;
-        commonElem = c1->super;     // == java.lang.Object
+    if (dvmIsPrimitiveClass(c1->elementClass)) {
+        arrayDim1--;
+        hasPrimitive = true;
+    }
+    if (dvmIsPrimitiveClass(c2->elementClass)) {
+        arrayDim2--;
+        hasPrimitive = true;
     }
 
-    /* walk from the element to the (multi-)dimensioned array type */
+    if (!hasPrimitive && arrayDim1 == arrayDim2) {
+        /*
+         * Two arrays of reference types with equal dimensions.  Try to
+         * find a good match.
+         */
+        commonElem = findCommonSuperclass(c1->elementClass, c2->elementClass);
+        numDims = arrayDim1;
+    } else {
+        /*
+         * Mismatched array depths and/or array(s) of primitives.  We want
+         * Object, or an Object array with appropriate dimensions.
+         *
+         * We initialize arrayClass to Object here, because it's possible
+         * for us to set numDims=0.
+         */
+        if (arrayDim1 < arrayDim2)
+            numDims = arrayDim1;
+        else
+            numDims = arrayDim2;
+        arrayClass = commonElem = c1->super;     // == java.lang.Object
+    }
+
+    /*
+     * Find an appropriately-dimensioned array class.  This is easiest
+     * to do iteratively, using the array class found by the current round
+     * as the element type for the next round.
+     */
     for (i = 0; i < numDims; i++) {
         arrayClass = dvmFindArrayClassForElement(commonElem);
         commonElem = arrayClass;
     }
+    assert(arrayClass != NULL);
 
     LOGVV("ArrayMerge '%s' + '%s' --> '%s'\n",
         c1->descriptor, c2->descriptor, arrayClass->descriptor);
@@ -2306,8 +2340,8 @@
  * depth" of each, move up toward the root of the deepest one until they're
  * at the same depth, then walk both up to the root until they match.
  *
- * If both classes are arrays of non-primitive types, we need to merge
- * based on array depth and element type.
+ * If both classes are arrays, we need to merge based on array depth and
+ * element type.
  *
  * If one class is an interface, we check to see if the other class/interface
  * (or one of its predecessors) implements the interface.  If so, we return
@@ -2348,10 +2382,7 @@
         return c2;
     }
 
-    if (dvmIsArrayClass(c1) && dvmIsArrayClass(c2) &&
-        !dvmIsPrimitiveClass(c1->elementClass) &&
-        !dvmIsPrimitiveClass(c2->elementClass))
-    {
+    if (dvmIsArrayClass(c1) && dvmIsArrayClass(c2)) {
         return findCommonArraySuperclass(c1, c2);
     }