Verifier allows certain errors so they can fail at runtime.

Specifically, this relaxes array typing in the absense of local variable
info.

Change-Id: I1b1aeb64a0842be3cffe70c02418444457abe972
diff --git a/dx/src/com/android/dx/cf/code/BaseMachine.java b/dx/src/com/android/dx/cf/code/BaseMachine.java
index bdb3229..c56dd3e 100644
--- a/dx/src/com/android/dx/cf/code/BaseMachine.java
+++ b/dx/src/com/android/dx/cf/code/BaseMachine.java
@@ -63,6 +63,9 @@
     /** {@code >= -1;} last local accessed */
     private int localIndex;
 
+    /** specifies if local has info in the local variable table */
+    private boolean localInfo;
+
     /** {@code null-ok;} local target spec, if salient and calculated */
     private RegisterSpec localTarget;
 
@@ -107,6 +110,7 @@
         auxCases = null;
         auxInitValues = null;
         localIndex = -1;
+        localInfo = false;
         localTarget = null;
         resultCount = -1;
     }
@@ -196,7 +200,7 @@
         }
 
         if (! Merger.isPossiblyAssignableFrom(type3, args[2])) {
-            throw new SimException("expected type " + type2.toHuman() +
+            throw new SimException("expected type " + type3.toHuman() +
                     " but found " + args[2].getType().toHuman());
         }
     }
@@ -210,6 +214,11 @@
     }
 
     /** {@inheritDoc} */
+    public final void localInfo(boolean local) {
+        localInfo = local;
+    }
+
+    /** {@inheritDoc} */
     public final void auxType(Type type) {
         auxType = type;
     }
@@ -360,6 +369,15 @@
     }
 
     /**
+     * Gets whether the loaded local has info in the local variable table.
+     *
+     * @return {@code true} if local arg has info in the local variable table
+     */
+    protected final boolean getLocalInfo() {
+        return localInfo;
+    }
+
+    /**
      * Gets the target local register spec of the current operation, if any.
      * The local target spec is the combination of the values indicated
      * by a previous call to {@link #localTarget} with the type of what
@@ -533,6 +551,9 @@
         } else {
             ExecutionStack stack = frame.getStack();
             for (int i = 0; i < resultCount; i++) {
+                if (localInfo) {
+                    stack.setLocal();
+                }
                 stack.push(results[i]);
             }
         }
diff --git a/dx/src/com/android/dx/cf/code/ExecutionStack.java b/dx/src/com/android/dx/cf/code/ExecutionStack.java
index 8f5b528..51f6334 100644
--- a/dx/src/com/android/dx/cf/code/ExecutionStack.java
+++ b/dx/src/com/android/dx/cf/code/ExecutionStack.java
@@ -34,6 +34,11 @@
     private final TypeBearer[] stack;
 
     /**
+     * {@code non-null;} array specifying whether stack contents have entries
+     * in the local variable table
+     */
+    private final boolean[] local;
+    /**
      * {@code >= 0;} stack pointer (points one past the end) / current stack
      * size
      */
@@ -48,6 +53,7 @@
     public ExecutionStack(int maxStack) {
         super(maxStack != 0);
         stack = new TypeBearer[maxStack];
+        local = new boolean[maxStack];
         stackPtr = 0;
     }
 
@@ -60,6 +66,7 @@
         ExecutionStack result = new ExecutionStack(stack.length);
 
         System.arraycopy(stack, 0, result.stack, 0, stack.length);
+        System.arraycopy(local, 0, result.local, 0, local.length);
         result.stackPtr = stackPtr;
 
         return result;
@@ -131,6 +138,7 @@
 
         for (int i = 0; i < stackPtr; i++) {
             stack[i] = null;
+            local[i] = false;
         }
 
         stackPtr = 0;
@@ -171,6 +179,15 @@
     }
 
     /**
+     * Flags the next value pushed onto the stack as having local info.
+     */
+    public void setLocal() {
+        throwIfImmutable();
+
+        local[stackPtr] = true;
+    }
+
+    /**
      * Peeks at the {@code n}th element down from the top of the stack.
      * {@code n == 0} means to peek at the top of the stack. Note that
      * this will return {@code null} if the indicated element is the
@@ -194,6 +211,26 @@
 
     /**
      * Peeks at the {@code n}th element down from the top of the
+     * stack, returning whether or not it has local info.
+     *
+     * @param n {@code >= 0;} which element to peek at
+     * @return {@code true} if the value has local info, {@code false} otherwise
+     * @throws SimException thrown if {@code n >= size()}
+     */
+    public boolean peekLocal(int n) {
+        if (n < 0) {
+            throw new IllegalArgumentException("n < 0");
+        }
+
+        if (n >= stackPtr) {
+            throw new SimException("stack: underflow");
+        }
+
+        return local[stackPtr - n - 1];
+    }
+
+    /**
+     * Peeks at the {@code n}th element down from the top of the
      * stack, returning the type per se, as opposed to the
      * <i>type-bearer</i>.  This method is just a convenient shorthand
      * for {@code peek(n).getType()}.
@@ -216,6 +253,7 @@
         TypeBearer result = peek(0);
 
         stack[stackPtr - 1] = null;
+        local[stackPtr - 1] = false;
         stackPtr -= result.getType().getCategory();
 
         return result;
diff --git a/dx/src/com/android/dx/cf/code/Machine.java b/dx/src/com/android/dx/cf/code/Machine.java
index 72ba3b4..a81feaf 100644
--- a/dx/src/com/android/dx/cf/code/Machine.java
+++ b/dx/src/com/android/dx/cf/code/Machine.java
@@ -113,6 +113,14 @@
     public void localArg(Frame frame, int idx);
 
     /**
+     * Used to specify if a loaded local variable has info in the local
+     * variable table.
+     *
+     * @param local {@code true} if local arg has info in local variable table
+     */
+    public void localInfo(boolean local);
+
+    /**
      * Indicates that the salient type of this operation is as
      * given. This differentiates between, for example, the various
      * arithmetic opcodes, which, by the time they hit a
diff --git a/dx/src/com/android/dx/cf/code/Simulator.java b/dx/src/com/android/dx/cf/code/Simulator.java
index 0812305..eedc379 100644
--- a/dx/src/com/android/dx/cf/code/Simulator.java
+++ b/dx/src/com/android/dx/cf/code/Simulator.java
@@ -367,13 +367,21 @@
                      * element type is category 2, we have to skip
                      * over one extra stack slot to find the array.
                      */
-                    Type foundArrayType =
-                        frame.getStack().peekType(type.isCategory1() ? 2 : 3);
+                    ExecutionStack stack = frame.getStack();
+                    int peekDepth = type.isCategory1() ? 2 : 3;
+                    Type foundArrayType = stack.peekType(peekDepth);
+                    boolean foundArrayLocal = stack.peekLocal(peekDepth);
+
                     Type requiredArrayType =
                         requiredArrayTypeFor(type, foundArrayType);
 
-                    // Make type agree with the discovered requiredArrayType.
-                    type = requiredArrayType.getComponentType();
+                    /*
+                     * Make type agree with the discovered requiredArrayType
+                     * if it has local info.
+                     */
+                    if (foundArrayLocal) {
+                        type = requiredArrayType.getComponentType();
+                    }
 
                     machine.popArgs(frame, requiredArrayType, Type.INT, type);
                     break;
@@ -578,6 +586,7 @@
                 case ByteOps.ILOAD:
                 case ByteOps.RET: {
                     machine.localArg(frame, idx);
+                    machine.localInfo(local != null);
                     machine.auxType(type);
                     break;
                 }