Test access to locals on instruction level when debugging
Adds more tests related to local variables which are specifically
meant to verify we correctly see local variables on each instruction,
despite extra DEX move instructions (like for invoke-range or
instructions working on low registers only).
The test LocalsTest.testInvokeRangeLong is expected to fail until
we fix the issue detected by this test.
Change-Id: I0799a4c1bfe604f7d24b98b2f32975244db03dc1
diff --git a/src/test/debugTestResources/Locals.java b/src/test/debugTestResources/Locals.java
index 21d08c1..3ad6596 100644
--- a/src/test/debugTestResources/Locals.java
+++ b/src/test/debugTestResources/Locals.java
@@ -34,12 +34,170 @@
}
}
+ private static void manyLocals() {
+ int i1 = 1;
+ int i2 = 2;
+ int i3 = 3;
+ int i4 = 4;
+ int i5 = 5;
+ int i6 = 6;
+ int i7 = 7;
+ int i8 = 8;
+ int i9 = 9;
+ int i10 = 10;
+ int i11 = 11;
+ int i12 = 12;
+ invokeRange(i6, i5, i4, i3, i2, i1, invokeRange(i12, i11, i10, i9, i8, i7, 0));
+ }
+
+ private static int reverseRange(int a, int b, int c, int d, int e, int f, int g) {
+ return invokeRange(g, f, e, d, c, b, a);
+ }
+
+ private static int invokeRange(int a, int b, int c, int d, int e, int f, int g) {
+ System.out.println(a + b + c + d + e + f + g);
+ return a + b + c + d + e + f + g;
+ }
+
+ private void lotsOfArrayLength() {
+ int lengthOfArray1 = 0;
+ int lengthOfArray2 = 0;
+ int lengthOfArray3 = 0;
+ int lengthOfArray4 = 0;
+ int lengthOfArray5 = 0;
+ int lengthOfArray6 = 0;
+ int lengthOfArray7 = 0;
+ int lengthOfArray8 = 0;
+ int lengthOfArray9 = 0;
+ int lengthOfArray10 = 0;
+ int lengthOfArray11 = 0;
+ int lengthOfArray12 = 0;
+ int lengthOfArray13 = 0;
+ int lengthOfArray14 = 0;
+ int lengthOfArray15 = 0;
+ int lengthOfArray16 = 0;
+
+ // These statements are compiled into new-array in DEX which stores the result in a 4bit
+ // register (0..15).
+ boolean[] array1 = new boolean[1];
+ byte[] array2 = new byte[1];
+ char[] array3 = new char[1];
+ short[] array4 = new short[1];
+ int[] array5 = new int[1];
+ long[] array6 = new long[1];
+ float[] array7 = new float[1];
+ double[] array8 = new double[1];
+ Object[] array9 = new Object[1];
+ String[] array10 = new String[1];
+ String[] array11 = new String[1];
+ String[] array12 = new String[1];
+ String[] array13 = new String[1];
+ String[] array14 = new String[1];
+ String[] array15 = new String[1];
+ String[] array16 = new String[1];
+
+ // 1st breakpoint to capture the IDs of each array.
+ breakpoint();
+
+ // Breakpoint at line below. In DEX, the array-length instruction expects a 4bit register
+ // (0..15). By creating >16 locals, we should cause an intermediate move instruction to
+ // copy/move a high register (>= 16) into a lower register (< 16).
+ // A test should step instruction by instruction and make sure all locals have the correct
+ // value.
+ lengthOfArray1 = array1.length;
+ lengthOfArray2 = array2.length;
+ lengthOfArray3 = array3.length;
+ lengthOfArray4 = array4.length;
+ lengthOfArray5 = array5.length;
+ lengthOfArray6 = array6.length;
+ lengthOfArray7 = array7.length;
+ lengthOfArray8 = array8.length;
+ lengthOfArray9 = array9.length;
+ lengthOfArray10 = array10.length;
+ lengthOfArray11 = array11.length;
+ lengthOfArray12 = array12.length;
+ lengthOfArray13 = array13.length;
+ lengthOfArray14 = array14.length;
+ lengthOfArray15 = array15.length;
+ lengthOfArray16 = array16.length;
+
+ // Use all locals
+ System.out.println(array1);
+ System.out.println(array2);
+ System.out.println(array3);
+ System.out.println(array4);
+ System.out.println(array5);
+ System.out.println(array6);
+ System.out.println(array7);
+ System.out.println(array8);
+ System.out.println(array9);
+ System.out.println(array10);
+ System.out.println(array11);
+ System.out.println(array12);
+ System.out.println(array13);
+ System.out.println(array14);
+ System.out.println(array15);
+ System.out.println(array16);
+
+ System.out.println(lengthOfArray1);
+ System.out.println(lengthOfArray2);
+ System.out.println(lengthOfArray3);
+ System.out.println(lengthOfArray4);
+ System.out.println(lengthOfArray5);
+ System.out.println(lengthOfArray6);
+ System.out.println(lengthOfArray7);
+ System.out.println(lengthOfArray8);
+ System.out.println(lengthOfArray9);
+ System.out.println(lengthOfArray10);
+ System.out.println(lengthOfArray11);
+ System.out.println(lengthOfArray12);
+ System.out.println(lengthOfArray13);
+ System.out.println(lengthOfArray14);
+ System.out.println(lengthOfArray15);
+ System.out.println(lengthOfArray16);
+ }
+
+ // Utility method to set a breakpoint and inspect the stack.
+ private static void breakpoint() {
+ }
+
+ public void foo(int x) {
+ Integer obj = new Integer(x + x);
+ long l = obj.longValue();
+ try {
+ l = obj.longValue();
+ x = (int) l / x;
+ invokerangeLong(l, l, l, l, l, l);
+ sout(x);
+ } catch (ArithmeticException e) {
+ sout(l);
+ } catch (RuntimeException e) {
+ sout(l); // We should not attempt to read the previous definition of 'e' here or below.
+ } catch (Throwable e) {
+ sout(l);
+ }
+ }
+
+ private void sout(long l) {
+ System.out.print(l);
+ }
+
+ private void invokerangeLong(long a, long b, long c, long d, long e, long f) {
+ if (a != d) {
+ throw new RuntimeException("unexpected");
+ }
+ }
+
public static void main(String[] args) {
noLocals();
unusedLocals();
constantLocals(10);
zeroLocals();
noFlowOptimization();
+ manyLocals();
+ reverseRange(1,2,3,4,5,6,7);
+ new Locals().lotsOfArrayLength();
+ new Locals().foo(21);
}
}