| // Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file | |
| // for details. All rights reserved. Use of this source code is governed by a | |
| // BSD-style license that can be found in the LICENSE file. | |
| public class Locals { | |
| private static void noLocals() { | |
| System.out.println("There's no local here"); | |
| } | |
| private static void unusedLocals() { | |
| int i = Integer.MAX_VALUE; | |
| System.out.println("Not using local variable"); | |
| } | |
| private static void constantLocals(int p) { | |
| int c = 5; | |
| int v = c + p; | |
| System.out.println("c=" + c + ", v=" + v); | |
| } | |
| private static void zeroLocals() { | |
| int i = 0; | |
| float f = 0.0f; | |
| System.out.println("zeroLocals"); | |
| } | |
| private static void noFlowOptimization() { | |
| int i = 0; | |
| if (i == 0) { | |
| System.out.println("i == 0"); | |
| } else { | |
| System.out.println("i != 0"); | |
| } | |
| } | |
| 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 int stepEmptyForLoopBody1(int n) { | |
| int i; | |
| for (i = 0; i < n; i++) ; | |
| return i; | |
| } | |
| public static int stepEmptyForLoopBody2(int n) { | |
| int i; | |
| for (i = 0; i < n; i++) { | |
| // has a line but still empty... | |
| } | |
| return i; | |
| } | |
| public static int stepNonEmptyForLoopBody(int n) { | |
| int i; | |
| for (i = 0; i < n; i++) | |
| nop(); | |
| return i; | |
| } | |
| public static void nop() {} | |
| public static int tempInCase(int x) { | |
| int res = 0; | |
| for (int i = 0; i < x; ++i) { | |
| int rem = x - i; | |
| switch (rem) { | |
| case 1: | |
| return res; | |
| case 5: | |
| int tmp = res + x + i; | |
| res += tmp; | |
| break; | |
| case 10: | |
| i++; | |
| break; | |
| default: | |
| res += rem; | |
| } | |
| res += rem % 2; | |
| } | |
| res *= x; | |
| return res; | |
| } | |
| public static int localSwap(int x, int y) { | |
| int sum = x + y; | |
| { | |
| int t = x; | |
| x = y; | |
| y = t; | |
| } | |
| return sum + x + y; | |
| } | |
| public static int argumentLiveAtReturn(int x) { | |
| switch (x) { | |
| case 0: | |
| return 0; | |
| case 1: | |
| return 0; | |
| case 2: | |
| return 0; | |
| case 100: | |
| return 1; | |
| case 101: | |
| return 1; | |
| case 102: | |
| return 1; | |
| } | |
| return -1; | |
| } | |
| public static int switchRewriteToIfs(int x) { | |
| { | |
| int t = x + 1; | |
| x = t; | |
| x = x + x; | |
| } | |
| switch (x) { | |
| case 0: | |
| return 0; | |
| case 100: | |
| return 1; | |
| } | |
| return -1; | |
| } | |
| public static int switchRewriteToSwitches(int x) { | |
| { | |
| int t = x + 1; | |
| x = t; | |
| x = x + x; | |
| } | |
| switch (x) { | |
| case 0: | |
| return 0; | |
| case 1: | |
| return 0; | |
| case 2: | |
| return 0; | |
| case 100: | |
| return 1; | |
| case 101: | |
| return 1; | |
| case 102: | |
| return 1; | |
| } | |
| return -1; | |
| } | |
| public static String regression65039701(boolean createIntNotLong) { | |
| Object a = createIntNotLong ? new int[1] : new long[1]; | |
| if (a instanceof int []) { | |
| ((int [])a)[0] = 0; | |
| } | |
| return "OK"; | |
| } | |
| public static void regression65066975(boolean bit) { | |
| nop(); | |
| if (bit) { | |
| nop(); | |
| } else { | |
| nop(); | |
| } | |
| nop(); | |
| } | |
| public static int localConstant(boolean b) { | |
| if (b) { | |
| int result1 = 1; | |
| return result1; | |
| } else { | |
| int result2 = 2; | |
| return result2; | |
| } | |
| } | |
| public static int localConstantBis(boolean b) { | |
| int result = 0; | |
| if (b) { | |
| result = 1; | |
| } else { | |
| result = 2; | |
| } | |
| return result; | |
| } | |
| public static int localTriggeringCSE() { | |
| int a = 1; | |
| int b = 3; | |
| int c = a + b; | |
| int d = a + b; | |
| return c + d; | |
| } | |
| public static int intAddition(int a, int b, int c) { | |
| a += b; | |
| b += c; | |
| c = a + b; | |
| return c; | |
| } | |
| public static void localVisibilityIntoLoop(double B[][], double A[][]) { | |
| int i; | |
| int length = 1; | |
| for (i = 0; i < length; i++) { | |
| double Bi[] = B[i]; | |
| double Ai[] = A[i]; | |
| for (int j = 0; j < 1; j += 4) { | |
| Bi[j] = Ai[j]; | |
| } | |
| } | |
| } | |
| 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); | |
| stepEmptyForLoopBody1(3); | |
| stepEmptyForLoopBody2(3); | |
| stepNonEmptyForLoopBody(3); | |
| tempInCase(42); | |
| localSwap(1, 2); | |
| argumentLiveAtReturn(-1); | |
| switchRewriteToIfs(1); | |
| switchRewriteToSwitches(1); | |
| regression65039701(true); | |
| regression65066975(false); | |
| System.out.println(localConstant(true)); | |
| System.out.println(localConstantBis(true)); | |
| System.out.println(localTriggeringCSE()); | |
| System.out.println(intAddition(1, 2, 6)); | |
| localVisibilityIntoLoop(new double[1][1], new double[1][1]); | |
| } | |
| } |