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