diff options
-rw-r--r-- | dx/src/com/android/dx/cf/code/BaseMachine.java | 23 | ||||
-rw-r--r-- | dx/src/com/android/dx/cf/code/ExecutionStack.java | 38 | ||||
-rw-r--r-- | dx/src/com/android/dx/cf/code/Machine.java | 8 | ||||
-rw-r--r-- | dx/src/com/android/dx/cf/code/Simulator.java | 17 |
4 files changed, 81 insertions, 5 deletions
diff --git a/dx/src/com/android/dx/cf/code/BaseMachine.java b/dx/src/com/android/dx/cf/code/BaseMachine.java index bdb322964..c56dd3e72 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 @@ public abstract class BaseMachine implements Machine { /** {@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 @@ public abstract class BaseMachine implements Machine { auxCases = null; auxInitValues = null; localIndex = -1; + localInfo = false; localTarget = null; resultCount = -1; } @@ -196,7 +200,7 @@ public abstract class BaseMachine implements Machine { } 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 @@ public abstract class BaseMachine implements Machine { } /** {@inheritDoc} */ + public final void localInfo(boolean local) { + localInfo = local; + } + + /** {@inheritDoc} */ public final void auxType(Type type) { auxType = type; } @@ -360,6 +369,15 @@ public abstract class BaseMachine implements Machine { } /** + * 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 @@ public abstract class BaseMachine implements Machine { } 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 8f5b528b2..51f633447 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 @@ public final class ExecutionStack extends MutabilityControl { 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 final class ExecutionStack extends MutabilityControl { public ExecutionStack(int maxStack) { super(maxStack != 0); stack = new TypeBearer[maxStack]; + local = new boolean[maxStack]; stackPtr = 0; } @@ -60,6 +66,7 @@ public final class ExecutionStack extends MutabilityControl { 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 @@ public final class ExecutionStack extends MutabilityControl { for (int i = 0; i < stackPtr; i++) { stack[i] = null; + local[i] = false; } stackPtr = 0; @@ -171,6 +179,15 @@ public final class ExecutionStack extends MutabilityControl { } /** + * 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 @@ public final class ExecutionStack extends MutabilityControl { /** * 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 @@ public final class ExecutionStack extends MutabilityControl { 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 72ba3b456..a81feaff3 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 interface Machine { 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 081230596..eedc37990 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 @@ public class Simulator { * 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 @@ public class Simulator { case ByteOps.ILOAD: case ByteOps.RET: { machine.localArg(frame, idx); + machine.localInfo(local != null); machine.auxType(type); break; } |