| // 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]); | 
 |   } | 
 | } |