// Copyright (c) 2016, 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. // This code is not run directly. It needs to be compiled to dex code. // 'throwing.dex' is what is run. package throwing; import java.util.Collections; import java.util.List; class Throwing { static int[] used = new int[10]; public static void main(String[] args) { try { used[0] = throwAtFistLine(42); } catch (Exception e) { printFrameHead(e); } try { used[1] = throwInMiddle(42); } catch (Exception e) { printFrameHead(e); } try { used[2] = throwAfterMultiInline(42); } catch (Exception e) { printFrameHead(e); } try { int value = magicNumber(42); // This throws after an inline, on the top-level. used[6] = value * 10; used[7] = anotherInlinedFunction(value); // // Some space to increase line numbers... // used[8] = value / (value & 0x0); } catch (Exception e) { printFrameHead(e); } Nested nested = new Nested(); try { used[3] = nested.justThrow(42); } catch (Exception e) { printFrameHead(e); } nested.doSomethingUseless(); used[0] += Nested.callAMethod(nested, 11); used[0] += Nested.callAMethod(nested, 42); RenamedClass aInstance = RenamedClass.create(); aInstance.takeThingsForASpin(42); System.out.print(used[0]); try { throwInAFunctionThatIsNotInlinedAndCalledTwice(); } catch (Exception e) { printFrameHead(e); } try { throwInAFunctionThatIsNotInlinedAndCalledTwice(); } catch (Exception e) { printFrameHead(e); } try { aFunctionThatCallsAnInlinedMethodThatThrows(Collections.emptyList()); } catch (Exception e) { printFrameHead(e); } try { anotherFunctionThatCallsAnInlinedMethodThatThrows("string"); } catch (Exception e) { printFrameHead(e); } try { aFunctionsThatThrowsBeforeAnInlinedMethod(magicNumber(42)); } catch (Exception e) { printFrameHead(e); } } public static int magicNumber(int value) { if (value < 0) { return magicNumber(value++); } return value; } public static void printFrameHead(Exception e) { for (StackTraceElement element : e.getStackTrace()) { System.out.println("FRAME: " + element); } } // This throws in the first line of the method. public static int throwAtFistLine(int value) { int aValue = value * 2 / (value & 0x0); return aValue; } // This throws a little further down. public static int throwInMiddle(int value) { used[2] = value * 10; used[3] = value >> 3; used[4] = value / (value & 0x0); used[5] = value * 20; return value >> 5; } // This throws after another inlined function. public static int throwAfterMultiInline(int value) { used[6] = value * 10; used[7] = anotherInlinedFunction(value); // // Some space to increase line numbers... // used[8] = value / (value & 0x0); return value >> 5; } public static int throwInAFunctionThatIsNotInlinedAndCalledTwice() { for (int i = 0; i < 10; i++) { used[9] += i; System.out.println("Increment by one!"); } System.out.println("Incremented by 10."); used[9] = used[9] / (used[9] & 0x0); return used[9]; } // Small method that throws and can be inlined. private static int anotherThrowingMethodToInline(int value) { used[4] = value / (value & 0x0); return value >> 5; } // It is important that this function uses an argument type that is otherwise unused, so it gets // the same minified name. public static int aFunctionThatCallsAnInlinedMethodThatThrows(List aList) { used[9] = aList.size(); for (int i = 0; i < 10; i++) { used[9] += i; System.out.println("Increment by one!"); } System.out.println("Incremented by 10."); used[9] = anotherThrowingMethodToInline(used[9]); return used[9]; } // Small method that throws and can be inlined. private static int yetAnotherThrowingMethodToInline(int value) { used[5] = value / (value & 0x0); return value >> 5; } // It is important that this function uses an argument type that is otherwise unused, so it gets // the same minified name. public static int anotherFunctionThatCallsAnInlinedMethodThatThrows(String aString) { used[0] = aString.length(); for (int i = 0; i < 10; i++) { used[8] += i; System.out.println("Increment by one!"); } System.out.println("Incremented by 10."); used[8] = yetAnotherThrowingMethodToInline(used[8]); return used[8]; } public static int aFunctionsThatThrowsBeforeAnInlinedMethod(int value) { used[1] = value / (value & 0x0); anotherInlinedFunction(used[1]); return used[1]; } // This will be inlined above but does not throw public static int anotherInlinedFunction(int value) { return value / (value & 0xff); } /** * A nested class with different kind of methods to have inlining from a nested class and also * renamings of a nested class in the mapping file. * *

Some methods are recursive to avoid inlining. */ static class Nested { int justThrow(int value) { return used[8] = value / (value & 0x0); } // This will also be inlined. Not used in test but for generating interesting mapping files. void doSomethingUseless() { Throwing.used[9] = 11; } static int callAMethod(Nested on, int value) { if (value > 20) { return callAMethod(on, value - 1); } else { return on.aMethod(value); } } int aMethod(int value) { if (value > 10) { return aMethod(value - 1); } else { return value; } } } }