Home | History | Annotate | Download | only in art
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package art;
     18 
     19 import java.lang.reflect.Executable;
     20 import java.lang.reflect.Constructor;
     21 import java.lang.reflect.Method;
     22 
     23 import java.time.Duration;
     24 
     25 import java.util.ArrayList;
     26 import java.util.Arrays;
     27 import java.util.List;
     28 import java.util.Optional;
     29 import java.util.Random;
     30 import java.util.Stack;
     31 import java.util.Vector;
     32 
     33 import java.util.function.Supplier;
     34 
     35 public class Test993 {
     36 
     37   public static final Breakpoint.Manager MANAGER = new Breakpoint.Manager();
     38 
     39   // A function we can use as a start breakpoint.
     40   public static void breakpoint() {
     41     return;
     42   }
     43 
     44   private static void privateBreakpoint() {
     45     return;
     46   }
     47 
     48   // An interface with a default method we can break on.
     49   static interface Breakable {
     50     public static void iBreakpoint() {
     51       return;
     52     }
     53 
     54     public default void breakit() {
     55       return;
     56     }
     57   }
     58 
     59   // A class that has a default method we breakpoint on.
     60   public static class TestClass1 implements Breakable {
     61     public TestClass1() {
     62       super();
     63     }
     64     public String toString() { return "TestClass1"; }
     65   }
     66 
     67   // A class that overrides a default method that we can breakpoint on and calls super.
     68   public static class TestClass1ext extends TestClass1 {
     69     public TestClass1ext() {
     70       super();
     71     }
     72     public String toString() { return "TestClass1Ext"; }
     73     public void breakit() {
     74       super.breakit();
     75     }
     76   }
     77 
     78 
     79   // A class that overrides a default method that we can breakpoint on.
     80   public static class TestClass2 implements Breakable {
     81     public String toString() { return "TestClass2"; }
     82     public void breakit() {
     83       return;
     84     }
     85   }
     86 
     87   // A class that overrides a default method that we can breakpoint on and calls super.
     88   public static class TestClass2ext extends TestClass2 {
     89     public String toString() { return "TestClass2ext"; }
     90     public void breakit() {
     91       super.breakit();
     92     }
     93   }
     94 
     95   // A class that overrides a default method and calls it directly with interface invoke-super
     96   public static class TestClass3 implements Breakable {
     97     public String toString() { return "TestClass3"; }
     98     public void breakit() {
     99       Breakable.super.breakit();
    100     }
    101   }
    102 
    103   // A class that overrides a default method that we can breakpoint on and calls super to a class
    104   // that uses interface-invoke-super.
    105   public static class TestClass3ext extends TestClass3 {
    106     public String toString() { return "TestClass3ext"; }
    107     public void breakit() {
    108       super.breakit();
    109     }
    110   }
    111 
    112   public static class TestClass4 {
    113     public String toString() { return "TestClass4"; }
    114     public void callPrivateMethod() {
    115       privateMethod();
    116     }
    117     private void privateMethod() {
    118       return;
    119     }
    120   }
    121 
    122   public static void notifyBreakpointReached(Thread thr, Executable e, long loc) {
    123     String line;
    124     if (e.getDeclaringClass().getPackage().equals(Test993.class.getPackage())) {
    125       line = Integer.valueOf(Breakpoint.locationToLine(e, loc)).toString();
    126     } else {
    127       line = "<NON-DETERMINISTIC>";
    128     }
    129     System.out.println("\t\t\tBreakpoint: " + e + " @ line=" + line);
    130   }
    131 
    132   public static interface ThrowRunnable extends Runnable {
    133     public default void run() {
    134       try {
    135         runThrow();
    136       } catch (Exception e) {
    137         throw new Error("Caught error while running " + this, e);
    138       }
    139     }
    140     public void runThrow() throws Exception;
    141   }
    142 
    143   public static class InvokeDirect implements Runnable {
    144     String msg;
    145     Runnable r;
    146     public InvokeDirect(String msg, Runnable r) {
    147       this.msg = msg;
    148       this.r = r;
    149     }
    150     @Override
    151     public void run() {
    152       System.out.println("\t\tInvoking \"" + msg + "\"");
    153       r.run();
    154     }
    155   }
    156 
    157   public static class InvokeReflect implements ThrowRunnable {
    158     Method m;
    159     Object this_arg;
    160     public InvokeReflect(Method m, Object this_arg) {
    161       this.m = m;
    162       this.this_arg = this_arg;
    163     }
    164 
    165     @Override
    166     public void runThrow() throws Exception {
    167       System.out.println("\t\tReflective invoking: " + m + " args: [this: " + this_arg + "]");
    168       m.invoke(this_arg);
    169     }
    170   }
    171 
    172   public static class InvokeNative implements Runnable {
    173     Method m;
    174     Object this_arg;
    175     public InvokeNative(Method m, Object this_arg) {
    176       this.m = m;
    177       this.this_arg = this_arg;
    178     }
    179 
    180     @Override
    181     public void run() {
    182       System.out.println("\t\tNative invoking: " + m + " args: [this: " + this_arg + "]");
    183       invokeNative(m, m.getDeclaringClass(), this_arg);
    184     }
    185   }
    186 
    187   public static native void invokeNative(Method m, Class<?> clazz, Object thizz);
    188 
    189   public static class InvokeNativeBool implements Runnable {
    190     Method m;
    191     Object this_arg;
    192     public InvokeNativeBool(Method m, Object this_arg) {
    193       this.m = m;
    194       this.this_arg = this_arg;
    195     }
    196 
    197     @Override
    198     public void run() {
    199       System.out.println("\t\tNative invoking: " + m + " args: [this: " + this_arg + "]");
    200       invokeNativeBool(m, m.getDeclaringClass(), this_arg);
    201     }
    202   }
    203 
    204   public static native void invokeNativeBool(Method m, Class<?> clazz, Object thizz);
    205 
    206   public static class InvokeNativeObject implements Runnable {
    207     Method m;
    208     Object this_arg;
    209     public InvokeNativeObject(Method m, Object this_arg) {
    210       this.m = m;
    211       this.this_arg = this_arg;
    212     }
    213 
    214     @Override
    215     public void run() {
    216       System.out.println("\t\tNative invoking: " + m + " args: [this: " + this_arg + "]");
    217       invokeNativeObject(m, m.getDeclaringClass(), this_arg);
    218     }
    219   }
    220 
    221   public static native void invokeNativeObject(Method m, Class<?> clazz, Object thizz);
    222 
    223   public static class InvokeNativeLong implements Runnable {
    224     Method m;
    225     Object this_arg;
    226     public InvokeNativeLong(Method m, Object this_arg) {
    227       this.m = m;
    228       this.this_arg = this_arg;
    229     }
    230 
    231     @Override
    232     public void run() {
    233       System.out.println("\t\tNative invoking: " + m + " args: [this: " + this_arg + "]");
    234       invokeNativeLong(m, m.getDeclaringClass(), this_arg);
    235     }
    236   }
    237 
    238   public static native void invokeNativeLong(Method m, Class<?> clazz, Object thizz);
    239 
    240   public static class ConstructDirect implements Runnable {
    241     String msg;
    242     Supplier<Object> s;
    243     public ConstructDirect(String msg, Supplier<Object> s) {
    244       this.msg = msg;
    245       this.s = s;
    246     }
    247 
    248     @Override
    249     public void run() {
    250       System.out.println("\t\tConstructing: " + msg);
    251       System.out.println("\t\t\tCreated: " + s.get());
    252     }
    253   }
    254 
    255   public static class ConstructReflect implements ThrowRunnable {
    256     Constructor<?> m;
    257     public ConstructReflect(Constructor<?> m) {
    258       this.m = m;
    259     }
    260 
    261     @Override
    262     public void runThrow() throws Exception {
    263       System.out.println("\t\tReflective constructor: " + m);
    264       System.out.println("\t\t\tCreated: " + m.newInstance());
    265     }
    266   }
    267 
    268   public static class ConstructNative implements Runnable {
    269     Constructor<?> m;
    270     Class type;
    271     public ConstructNative(Constructor<?> m) {
    272       this.m = m;
    273       this.type = m.getDeclaringClass();
    274     }
    275 
    276     @Override
    277     public void run() {
    278       System.out.println("\t\tNative constructor: " + m + ", type: " + type);
    279       System.out.println("\t\t\tCreated: " + constructNative(m, type));
    280     }
    281   }
    282 
    283   public static native Object constructNative(Constructor m, Class<?> clazz);
    284 
    285   private static <T> List<List<T>> combinations(List<T> items, int len) {
    286     if (len > items.size()) {
    287       throw new Error("Bad length" + len + " " + items);
    288     }
    289     if (len == 1) {
    290       List<List<T>> out = new ArrayList<>();
    291       for (T t : items) {
    292         out.add(Arrays.asList(t));
    293       }
    294       return out;
    295     }
    296     List<List<T>> out = new ArrayList<>();
    297     for (int rem = 0; rem <= items.size() - len; rem++) {
    298       for (List<T> others : combinations(items.subList(rem + 1, items.size()), len - 1)) {
    299         List<T> newone = new ArrayList<>();
    300         newone.add(items.get(rem));
    301         newone.addAll(others);
    302         out.add(newone);
    303       }
    304     }
    305     return out;
    306   }
    307 
    308   private static <T> List<List<T>> allCombinations(List<T> items) {
    309     List<List<T>> out = new ArrayList<List<T>>();
    310     out.add(new ArrayList<>());
    311     for (int i = 0; i < items.size(); i++) {
    312       out.addAll(combinations(items, i + 1));
    313     }
    314     return out;
    315   }
    316 
    317   private static Breakpoint.Manager.BP BP(Executable m) {
    318     return new Breakpoint.Manager.BP(m) {
    319       public String toString() {
    320         if (method.getDeclaringClass().getPackage().equals(Test993.class.getPackage())) {
    321           return super.toString();
    322         } else {
    323           return method.toString() + " @ <NON-DETERMINISTIC>";
    324         }
    325       }
    326     };
    327   }
    328 
    329   public static void run() throws Exception {
    330     // Set up breakpoints
    331     Breakpoint.stopBreakpointWatch(Thread.currentThread());
    332     Breakpoint.startBreakpointWatch(
    333         Test993.class,
    334         Test993.class.getDeclaredMethod("notifyBreakpointReached",
    335           Thread.class, Executable.class, Long.TYPE),
    336         Thread.currentThread());
    337 
    338     runMethodTests();
    339     runBCPMethodTests();
    340     runConstructorTests();
    341 
    342     Breakpoint.stopBreakpointWatch(Thread.currentThread());
    343   }
    344 
    345   public static void runConstructorTests() throws Exception {
    346     // The constructors we will be breaking on.
    347     Constructor<?> tc1_construct = TestClass1.class.getConstructor();
    348     Constructor<?> tc1ext_construct = TestClass1ext.class.getConstructor();
    349 
    350     Runnable[] tc1_constructors = new Runnable[] {
    351       new ConstructNative(tc1_construct),
    352       new ConstructReflect(tc1_construct),
    353       new ConstructDirect("new TestClass1()", TestClass1::new),
    354     };
    355     Breakpoint.Manager.BP[] tc1_bps = new Breakpoint.Manager.BP[] {
    356       BP(tc1_construct),
    357     };
    358     runTestGroups("TestClass1 constructor", tc1_constructors, tc1_bps);
    359 
    360     Runnable[] tc1ext_constructors = new Runnable[] {
    361       new ConstructNative(tc1ext_construct),
    362       new ConstructReflect(tc1ext_construct),
    363       new ConstructDirect("new TestClass1ext()", TestClass1ext::new),
    364     };
    365     Breakpoint.Manager.BP[] tc1ext_bps = new Breakpoint.Manager.BP[] {
    366       BP(tc1_construct), BP(tc1ext_construct),
    367     };
    368     runTestGroups("TestClass1ext constructor", tc1ext_constructors, tc1ext_bps);
    369   }
    370 
    371   // These test to make sure we are able to break on functions that might have been quickened or
    372   // inlined from the boot-image. These were all chosen for being in the bootclasspath, not being
    373   // long enough to prevent inlining, and not being used for the testing framework.
    374   public static void runBCPMethodTests() throws Exception {
    375     // The methods we will be breaking on.
    376     Method bcp_private_method = Duration.class.getDeclaredMethod("toSeconds");
    377     Method bcp_virtual_method = Optional.class.getDeclaredMethod("isPresent");
    378     Method bcp_static_method = Optional.class.getDeclaredMethod("empty");
    379     Method bcp_private_static_method = Random.class.getDeclaredMethod("seedUniquifier");
    380 
    381     // Some constructors we will break on.
    382     Constructor<?> bcp_stack_constructor = Stack.class.getConstructor();
    383     Constructor<?> bcp_vector_constructor = Vector.class.getConstructor();
    384     if (!(Vector.class.isAssignableFrom(Stack.class))) {
    385       throw new Error("Expected Stack to extend Vector!");
    386     }
    387 
    388     // BCP constructors.
    389     Runnable[] vector_constructors = new Runnable[] {
    390       new ConstructNative(bcp_vector_constructor),
    391       new ConstructReflect(bcp_vector_constructor),
    392       new ConstructDirect("new Vector()", Vector::new),
    393     };
    394     Breakpoint.Manager.BP[] vector_breakpoints = new Breakpoint.Manager.BP[] {
    395       BP(bcp_vector_constructor),
    396     };
    397     runTestGroups("Vector constructor", vector_constructors, vector_breakpoints);
    398 
    399     Runnable[] stack_constructors = new Runnable[] {
    400       new ConstructNative(bcp_stack_constructor),
    401       new ConstructReflect(bcp_stack_constructor),
    402       new ConstructDirect("new Stack()", Stack::new),
    403     };
    404     Breakpoint.Manager.BP[] stack_breakpoints = new Breakpoint.Manager.BP[] {
    405       BP(bcp_stack_constructor), BP(bcp_vector_constructor),
    406     };
    407     runTestGroups("Stack constructor", stack_constructors, stack_breakpoints);
    408 
    409     // Static function
    410     Runnable[] static_invokes = new Runnable[] {
    411       new InvokeNativeObject(bcp_static_method, null),
    412 
    413       new InvokeReflect(bcp_static_method, null),
    414 
    415       new InvokeDirect("Optional::empty", () -> { Optional.empty(); }),
    416     };
    417     Breakpoint.Manager.BP[] static_breakpoints = new Breakpoint.Manager.BP[] {
    418       BP(bcp_static_method)
    419     };
    420     runTestGroups("bcp static invoke", static_invokes, static_breakpoints);
    421 
    422     // Static private class function
    423     Runnable[] private_static_invokes = new Runnable[] {
    424       new InvokeNativeLong(bcp_private_static_method, null),
    425 
    426       new InvokeDirect("Random::seedUniquifier", () -> { new Random(); }),
    427     };
    428     Breakpoint.Manager.BP[] private_static_breakpoints = new Breakpoint.Manager.BP[] {
    429       BP(bcp_private_static_method)
    430     };
    431     runTestGroups("bcp private static invoke", private_static_invokes, private_static_breakpoints);
    432 
    433     // private class method
    434     Duration test_duration = Duration.ofDays(14);
    435     Runnable[] private_invokes = new Runnable[] {
    436       new InvokeNativeObject(bcp_private_method, test_duration),
    437 
    438       new InvokeDirect("Duration::toSeconds", () -> { test_duration.multipliedBy(2); }),
    439     };
    440     Breakpoint.Manager.BP[] private_breakpoints = new Breakpoint.Manager.BP[] {
    441       BP(bcp_private_method)
    442     };
    443     runTestGroups("bcp private invoke", private_invokes, private_breakpoints);
    444 
    445     // class method
    446     Runnable[] public_invokes = new Runnable[] {
    447       new InvokeNativeBool(bcp_virtual_method, Optional.of("test")),
    448 
    449       new InvokeReflect(bcp_virtual_method, Optional.of("test2")),
    450 
    451       new InvokeDirect("Optional::isPresent", () -> { Optional.of("test3").isPresent(); }),
    452     };
    453     Breakpoint.Manager.BP[] public_breakpoints = new Breakpoint.Manager.BP[] {
    454       BP(bcp_virtual_method)
    455     };
    456     runTestGroups("bcp invoke", public_invokes, public_breakpoints);
    457   }
    458 
    459   public static void runMethodTests() throws Exception {
    460     // The methods we will be breaking on.
    461     Method breakpoint_method = Test993.class.getDeclaredMethod("breakpoint");
    462     Method private_breakpoint_method = Test993.class.getDeclaredMethod("privateBreakpoint");
    463     Method i_breakpoint_method = Breakable.class.getDeclaredMethod("iBreakpoint");
    464     Method breakit_method = Breakable.class.getDeclaredMethod("breakit");
    465     Method breakit_method_tc1ext = TestClass1ext.class.getDeclaredMethod("breakit");
    466     Method breakit_method_tc2 = TestClass2.class.getDeclaredMethod("breakit");
    467     Method breakit_method_tc2ext = TestClass2ext.class.getDeclaredMethod("breakit");
    468     Method breakit_method_tc3 = TestClass3.class.getDeclaredMethod("breakit");
    469     Method breakit_method_tc3ext = TestClass3ext.class.getDeclaredMethod("breakit");
    470     Method private_method = TestClass4.class.getDeclaredMethod("privateMethod");
    471 
    472     // Static class function
    473     Runnable[] static_invokes = new Runnable[] {
    474       new InvokeNative(breakpoint_method, null),
    475 
    476       new InvokeReflect(breakpoint_method, null),
    477 
    478       new InvokeDirect("Test993::breakpoint", Test993::breakpoint),
    479     };
    480     Breakpoint.Manager.BP[] static_breakpoints = new Breakpoint.Manager.BP[] {
    481       BP(breakpoint_method)
    482     };
    483     runTestGroups("static invoke", static_invokes, static_breakpoints);
    484 
    485     // Static private class function
    486     Runnable[] private_static_invokes = new Runnable[] {
    487       new InvokeNative(private_breakpoint_method, null),
    488 
    489       new InvokeDirect("Test993::privateBreakpoint", Test993::privateBreakpoint),
    490     };
    491     Breakpoint.Manager.BP[] private_static_breakpoints = new Breakpoint.Manager.BP[] {
    492       BP(private_breakpoint_method)
    493     };
    494     runTestGroups("private static invoke", private_static_invokes, private_static_breakpoints);
    495 
    496     // Static interface function.
    497     Runnable[] i_static_invokes = new Runnable[] {
    498       new InvokeNative(i_breakpoint_method, null),
    499 
    500       new InvokeReflect(i_breakpoint_method, null),
    501 
    502       new InvokeDirect("Breakable::iBreakpoint", Breakable::iBreakpoint),
    503     };
    504     Breakpoint.Manager.BP[] i_static_breakpoints = new Breakpoint.Manager.BP[] {
    505       BP(i_breakpoint_method)
    506     };
    507     runTestGroups("interface static invoke", i_static_invokes, i_static_breakpoints);
    508 
    509     // Call default method through a class.
    510     Runnable[] tc1_invokes = new Runnable[] {
    511       new InvokeNative(breakit_method, new TestClass1()),
    512 
    513       new InvokeReflect(breakit_method, new TestClass1()),
    514 
    515       new InvokeDirect("((Breakable)new TestClass1()).breakit()",
    516                   () -> ((Breakable)new TestClass1()).breakit()),
    517       new InvokeDirect("new TestClass1().breakit()",
    518                   () -> new TestClass1().breakit()),
    519     };
    520     Breakpoint.Manager.BP[] tc1_breakpoints = new Breakpoint.Manager.BP[] {
    521       BP(breakit_method)
    522     };
    523     runTestGroups("TestClass1 invokes", tc1_invokes, tc1_breakpoints);
    524 
    525     // Call default method through an override and normal invoke-super
    526     Runnable[] tc1ext_invokes = new Runnable[] {
    527       new InvokeNative(breakit_method, new TestClass1ext()),
    528       new InvokeNative(breakit_method_tc1ext, new TestClass1ext()),
    529 
    530       new InvokeReflect(breakit_method, new TestClass1ext()),
    531       new InvokeReflect(breakit_method_tc1ext, new TestClass1ext()),
    532 
    533       new InvokeDirect("((Breakable)new TestClass1ext()).breakit()",
    534                   () -> ((Breakable)new TestClass1ext()).breakit()),
    535       new InvokeDirect("((TestClass1)new TestClass1ext()).breakit()",
    536                   () -> ((TestClass1)new TestClass1ext()).breakit()),
    537       new InvokeDirect("new TestClass1ext().breakit()",
    538                   () -> new TestClass1ext().breakit()),
    539     };
    540     Breakpoint.Manager.BP[] tc1ext_breakpoints = new Breakpoint.Manager.BP[] {
    541       BP(breakit_method), BP(breakit_method_tc1ext)
    542     };
    543     runTestGroups("TestClass1ext invokes", tc1ext_invokes, tc1ext_breakpoints);
    544 
    545     // Override default/interface method.
    546     Runnable[] tc2_invokes = new Runnable[] {
    547       new InvokeNative(breakit_method, new TestClass2()),
    548       new InvokeNative(breakit_method_tc2, new TestClass2()),
    549 
    550       new InvokeReflect(breakit_method, new TestClass2()),
    551       new InvokeReflect(breakit_method_tc2, new TestClass2()),
    552 
    553       new InvokeDirect("((Breakable)new TestClass2()).breakit()",
    554                   () -> ((Breakable)new TestClass2()).breakit()),
    555       new InvokeDirect("new TestClass2().breakit()",
    556                   () -> new TestClass2().breakit()),
    557     };
    558     Breakpoint.Manager.BP[] tc2_breakpoints = new Breakpoint.Manager.BP[] {
    559       BP(breakit_method), BP(breakit_method_tc2)
    560     };
    561     runTestGroups("TestClass2 invokes", tc2_invokes, tc2_breakpoints);
    562 
    563     // Call overridden method using invoke-super
    564     Runnable[] tc2ext_invokes = new Runnable[] {
    565       new InvokeNative(breakit_method, new TestClass2ext()),
    566       new InvokeNative(breakit_method_tc2, new TestClass2ext()),
    567       new InvokeNative(breakit_method_tc2ext, new TestClass2ext()),
    568 
    569       new InvokeReflect(breakit_method, new TestClass2ext()),
    570       new InvokeReflect(breakit_method_tc2, new TestClass2ext()),
    571       new InvokeReflect(breakit_method_tc2ext, new TestClass2ext()),
    572 
    573       new InvokeDirect("((Breakable)new TestClass2ext()).breakit()",
    574                   () -> ((Breakable)new TestClass2ext()).breakit()),
    575       new InvokeDirect("((TestClass2)new TestClass2ext()).breakit()",
    576                   () -> ((TestClass2)new TestClass2ext()).breakit()),
    577       new InvokeDirect("new TestClass2ext().breakit())",
    578                   () -> new TestClass2ext().breakit()),
    579     };
    580     Breakpoint.Manager.BP[] tc2ext_breakpoints = new Breakpoint.Manager.BP[] {
    581       BP(breakit_method), BP(breakit_method_tc2), BP(breakit_method_tc2ext)
    582     };
    583     runTestGroups("TestClass2ext invokes", tc2ext_invokes, tc2ext_breakpoints);
    584 
    585     // Override default method and call it using interface-invoke-super
    586     Runnable[] tc3_invokes = new Runnable[] {
    587       new InvokeNative(breakit_method, new TestClass3()),
    588       new InvokeNative(breakit_method_tc3, new TestClass3()),
    589 
    590       new InvokeReflect(breakit_method, new TestClass3()),
    591       new InvokeReflect(breakit_method_tc3, new TestClass3()),
    592 
    593       new InvokeDirect("((Breakable)new TestClass3()).breakit()",
    594                   () -> ((Breakable)new TestClass3()).breakit()),
    595       new InvokeDirect("new TestClass3().breakit())",
    596                   () -> new TestClass3().breakit()),
    597     };
    598     Breakpoint.Manager.BP[] tc3_breakpoints = new Breakpoint.Manager.BP[] {
    599       BP(breakit_method), BP(breakit_method_tc3)
    600     };
    601     runTestGroups("TestClass3 invokes", tc3_invokes, tc3_breakpoints);
    602 
    603     // Call overridden method using invoke-super
    604     Runnable[] tc3ext_invokes = new Runnable[] {
    605       new InvokeNative(breakit_method, new TestClass3ext()),
    606       new InvokeNative(breakit_method_tc3, new TestClass3ext()),
    607       new InvokeNative(breakit_method_tc3ext, new TestClass3ext()),
    608 
    609       new InvokeReflect(breakit_method, new TestClass3ext()),
    610       new InvokeReflect(breakit_method_tc3, new TestClass3ext()),
    611       new InvokeReflect(breakit_method_tc3ext, new TestClass3ext()),
    612 
    613       new InvokeDirect("((Breakable)new TestClass3ext()).breakit()",
    614                   () -> ((Breakable)new TestClass3ext()).breakit()),
    615       new InvokeDirect("((TestClass3)new TestClass3ext()).breakit()",
    616                   () -> ((TestClass3)new TestClass3ext()).breakit()),
    617       new InvokeDirect("new TestClass3ext().breakit())",
    618                   () -> new TestClass3ext().breakit()),
    619     };
    620     Breakpoint.Manager.BP[] tc3ext_breakpoints = new Breakpoint.Manager.BP[] {
    621       BP(breakit_method), BP(breakit_method_tc3), BP(breakit_method_tc3ext)
    622     };
    623     runTestGroups("TestClass3ext invokes", tc3ext_invokes, tc3ext_breakpoints);
    624 
    625     // private instance method.
    626     Runnable[] private_instance_invokes = new Runnable[] {
    627       new InvokeNative(private_method, new TestClass4()),
    628 
    629       new InvokeDirect("new TestClass4().callPrivateMethod()",
    630                   () -> new TestClass4().callPrivateMethod()),
    631     };
    632     Breakpoint.Manager.BP[] private_instance_breakpoints = new Breakpoint.Manager.BP[] {
    633       BP(private_method)
    634     };
    635     runTestGroups(
    636         "private instance invoke", private_instance_invokes, private_instance_breakpoints);
    637   }
    638 
    639   private static void runTestGroups(String name,
    640                                     Runnable[] invokes,
    641                                     Breakpoint.Manager.BP[] breakpoints) throws Exception {
    642     System.out.println("Running " + name);
    643     for (List<Breakpoint.Manager.BP> bps : allCombinations(Arrays.asList(breakpoints))) {
    644       System.out.println("\tBreaking on " + bps);
    645       for (Runnable test : invokes) {
    646         MANAGER.clearAllBreakpoints();
    647         MANAGER.setBreakpoints(bps.toArray(new Breakpoint.Manager.BP[0]));
    648         test.run();
    649       }
    650     }
    651   }
    652 }
    653