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.
breakpoint()40   public static void breakpoint() {
41     return;
42   }
43 
privateBreakpoint()44   private static void privateBreakpoint() {
45     return;
46   }
47 
48   // An interface with a default method we can break on.
49   static interface Breakable {
iBreakpoint()50     public static void iBreakpoint() {
51       return;
52     }
53 
breakit()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 {
TestClass1()61     public TestClass1() {
62       super();
63     }
toString()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 {
TestClass1ext()69     public TestClass1ext() {
70       super();
71     }
toString()72     public String toString() { return "TestClass1Ext"; }
breakit()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 {
toString()81     public String toString() { return "TestClass2"; }
breakit()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 {
toString()89     public String toString() { return "TestClass2ext"; }
breakit()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 {
toString()97     public String toString() { return "TestClass3"; }
breakit()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 {
toString()106     public String toString() { return "TestClass3ext"; }
breakit()107     public void breakit() {
108       super.breakit();
109     }
110   }
111 
112   public static class TestClass4 {
toString()113     public String toString() { return "TestClass4"; }
callPrivateMethod()114     public void callPrivateMethod() {
115       privateMethod();
116     }
privateMethod()117     private void privateMethod() {
118       return;
119     }
120   }
121 
notifyBreakpointReached(Thread thr, Executable e, long loc)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 {
run()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     }
runThrow()140     public void runThrow() throws Exception;
141   }
142 
143   public static class InvokeDirect implements Runnable {
144     String msg;
145     Runnable r;
InvokeDirect(String msg, Runnable r)146     public InvokeDirect(String msg, Runnable r) {
147       this.msg = msg;
148       this.r = r;
149     }
150     @Override
run()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;
InvokeReflect(Method m, 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
runThrow()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;
InvokeNative(Method m, 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
run()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 
invokeNative(Method m, Class<?> clazz, Object thizz)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;
InvokeNativeBool(Method m, 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
run()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 
invokeNativeBool(Method m, Class<?> clazz, Object thizz)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;
InvokeNativeObject(Method m, 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
run()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 
invokeNativeObject(Method m, Class<?> clazz, Object thizz)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;
InvokeNativeLong(Method m, 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
run()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 
invokeNativeLong(Method m, Class<?> clazz, Object thizz)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;
ConstructDirect(String msg, Supplier<Object> s)243     public ConstructDirect(String msg, Supplier<Object> s) {
244       this.msg = msg;
245       this.s = s;
246     }
247 
248     @Override
run()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;
ConstructReflect(Constructor<?> m)257     public ConstructReflect(Constructor<?> m) {
258       this.m = m;
259     }
260 
261     @Override
runThrow()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;
ConstructNative(Constructor<?> m)271     public ConstructNative(Constructor<?> m) {
272       this.m = m;
273       this.type = m.getDeclaringClass();
274     }
275 
276     @Override
run()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 
constructNative(Constructor m, Class<?> clazz)283   public static native Object constructNative(Constructor m, Class<?> clazz);
284 
combinations(List<T> items, int len)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 
allCombinations(List<T> items)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 
BP(Executable m)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