Home | History | Annotate | Download | only in throwing
      1 // Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file
      2 // for details. All rights reserved. Use of this source code is governed by a
      3 // BSD-style license that can be found in the LICENSE file.
      4 
      5 // This code is not run directly. It needs to be compiled to dex code.
      6 // 'throwing.dex' is what is run.
      7 
      8 package throwing;
      9 
     10 import java.util.Collections;
     11 import java.util.List;
     12 
     13 class Throwing {
     14 
     15   static int[] used = new int[10];
     16 
     17   public static void main(String[] args) {
     18     try {
     19       used[0] = throwAtFistLine(42);
     20     } catch (Exception e) {
     21       printFrameHead(e);
     22     }
     23     try {
     24       used[1] = throwInMiddle(42);
     25     } catch (Exception e) {
     26       printFrameHead(e);
     27     }
     28     try {
     29       used[2] = throwAfterMultiInline(42);
     30     } catch (Exception e) {
     31       printFrameHead(e);
     32     }
     33     try {
     34       int value = magicNumber(42);
     35       // This throws after an inline, on the top-level.
     36       used[6] = value * 10;
     37       used[7] = anotherInlinedFunction(value);
     38       //
     39       // Some space to increase line numbers...
     40       //
     41       used[8] = value / (value & 0x0);
     42     } catch (Exception e) {
     43       printFrameHead(e);
     44     }
     45 
     46     Nested nested = new Nested();
     47 
     48     try {
     49       used[3] = nested.justThrow(42);
     50     } catch (Exception e) {
     51       printFrameHead(e);
     52     }
     53 
     54     nested.doSomethingUseless();
     55 
     56     used[0] += Nested.callAMethod(nested, 11);
     57     used[0] += Nested.callAMethod(nested, 42);
     58 
     59     RenamedClass aInstance = RenamedClass.create();
     60     aInstance.takeThingsForASpin(42);
     61 
     62     System.out.print(used[0]);
     63 
     64     try {
     65       throwInAFunctionThatIsNotInlinedAndCalledTwice();
     66     } catch (Exception e) {
     67       printFrameHead(e);
     68     }
     69 
     70     try {
     71       throwInAFunctionThatIsNotInlinedAndCalledTwice();
     72     } catch (Exception e) {
     73       printFrameHead(e);
     74     }
     75 
     76     try {
     77       aFunctionThatCallsAnInlinedMethodThatThrows(Collections.emptyList());
     78     } catch (Exception e) {
     79       printFrameHead(e);
     80     }
     81 
     82     try {
     83       anotherFunctionThatCallsAnInlinedMethodThatThrows("string");
     84     } catch (Exception e) {
     85       printFrameHead(e);
     86     }
     87 
     88     try {
     89       aFunctionsThatThrowsBeforeAnInlinedMethod(magicNumber(42));
     90     } catch (Exception e) {
     91       printFrameHead(e);
     92     }
     93   }
     94 
     95   public static int magicNumber(int value) {
     96     if (value < 0) {
     97       return magicNumber(value++);
     98     }
     99     return value;
    100   }
    101 
    102   public static void printFrameHead(Exception e) {
    103     for (StackTraceElement element : e.getStackTrace()) {
    104       System.out.println("FRAME: " + element);
    105     }
    106   }
    107 
    108   // This throws in the first line of the method.
    109   public static int throwAtFistLine(int value) {
    110     int aValue = value * 2 / (value & 0x0);
    111     return aValue;
    112   }
    113 
    114   // This throws a little further down.
    115   public static int throwInMiddle(int value) {
    116     used[2] = value * 10;
    117     used[3] = value >> 3;
    118     used[4] = value / (value & 0x0);
    119     used[5] = value * 20;
    120     return value >> 5;
    121   }
    122 
    123   // This throws after another inlined function.
    124   public static int throwAfterMultiInline(int value) {
    125     used[6] = value * 10;
    126     used[7] = anotherInlinedFunction(value);
    127     //
    128     // Some space to increase line numbers...
    129     //
    130     used[8] = value / (value & 0x0);
    131     return value >> 5;
    132   }
    133 
    134   public static int throwInAFunctionThatIsNotInlinedAndCalledTwice() {
    135     for (int i = 0; i < 10; i++) {
    136       used[9] += i;
    137       System.out.println("Increment by one!");
    138     }
    139     System.out.println("Incremented by 10.");
    140     used[9] = used[9] / (used[9] & 0x0);
    141     return used[9];
    142   }
    143 
    144   // Small method that throws and can be inlined.
    145   private static int anotherThrowingMethodToInline(int value) {
    146     used[4] = value / (value & 0x0);
    147     return value >> 5;
    148   }
    149 
    150   // It is important that this function uses an argument type that is otherwise unused, so it gets
    151   // the same minified name.
    152   public static int aFunctionThatCallsAnInlinedMethodThatThrows(List aList) {
    153     used[9] = aList.size();
    154     for (int i = 0; i < 10; i++) {
    155       used[9] += i;
    156       System.out.println("Increment by one!");
    157     }
    158     System.out.println("Incremented by 10.");
    159     used[9] = anotherThrowingMethodToInline(used[9]);
    160     return used[9];
    161   }
    162 
    163   // Small method that throws and can be inlined.
    164   private static int yetAnotherThrowingMethodToInline(int value) {
    165     used[5] = value / (value & 0x0);
    166     return value >> 5;
    167   }
    168 
    169   // It is important that this function uses an argument type that is otherwise unused, so it gets
    170   // the same minified name.
    171   public static int anotherFunctionThatCallsAnInlinedMethodThatThrows(String aString) {
    172     used[0] = aString.length();
    173     for (int i = 0; i < 10; i++) {
    174       used[8] += i;
    175       System.out.println("Increment by one!");
    176     }
    177     System.out.println("Incremented by 10.");
    178     used[8] = yetAnotherThrowingMethodToInline(used[8]);
    179     return used[8];
    180   }
    181 
    182   public static int aFunctionsThatThrowsBeforeAnInlinedMethod(int value) {
    183     used[1] = value / (value & 0x0);
    184     anotherInlinedFunction(used[1]);
    185     return used[1];
    186   }
    187 
    188   // This will be inlined above but does not throw
    189   public static int anotherInlinedFunction(int value) {
    190     return value / (value & 0xff);
    191   }
    192 
    193   /**
    194    * A nested class with different kind of methods to have inlining from a nested class and also
    195    * renamings of a nested class in the mapping file.
    196    *
    197    * <p>Some methods are recursive to avoid inlining.
    198    */
    199   static class Nested {
    200 
    201     int justThrow(int value) {
    202       return used[8] = value / (value & 0x0);
    203     }
    204 
    205     // This will also be inlined. Not used in test but for generating interesting mapping files.
    206     void doSomethingUseless() {
    207       Throwing.used[9] = 11;
    208     }
    209 
    210     static int callAMethod(Nested on, int value) {
    211       if (value > 20) {
    212         return callAMethod(on, value - 1);
    213       } else {
    214         return on.aMethod(value);
    215       }
    216     }
    217 
    218     int aMethod(int value) {
    219       if (value > 10) {
    220         return aMethod(value - 1);
    221       } else {
    222         return value;
    223       }
    224     }
    225   }
    226 
    227 }
    228