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     run(false);
331   }
332   public static void run(boolean test_BCP_private) throws Exception {
333     // Set up breakpoints
334     Breakpoint.stopBreakpointWatch(Thread.currentThread());
335     Breakpoint.startBreakpointWatch(
336         Test993.class,
337         Test993.class.getDeclaredMethod("notifyBreakpointReached",
338           Thread.class, Executable.class, Long.TYPE),
339         Thread.currentThread());
340 
341     runMethodTests();
342     runBCPMethodTests(test_BCP_private);
343     runConstructorTests();
344 
345     Breakpoint.stopBreakpointWatch(Thread.currentThread());
346   }
347 
348   public static void runConstructorTests() throws Exception {
349     // The constructors we will be breaking on.
350     Constructor<?> tc1_construct = TestClass1.class.getConstructor();
351     Constructor<?> tc1ext_construct = TestClass1ext.class.getConstructor();
352 
353     Runnable[] tc1_constructors = new Runnable[] {
354       new ConstructNative(tc1_construct),
355       new ConstructReflect(tc1_construct),
356       new ConstructDirect("new TestClass1()", TestClass1::new),
357     };
358     Breakpoint.Manager.BP[] tc1_bps = new Breakpoint.Manager.BP[] {
359       BP(tc1_construct),
360     };
361     runTestGroups("TestClass1 constructor", tc1_constructors, tc1_bps);
362 
363     Runnable[] tc1ext_constructors = new Runnable[] {
364       new ConstructNative(tc1ext_construct),
365       new ConstructReflect(tc1ext_construct),
366       new ConstructDirect("new TestClass1ext()", TestClass1ext::new),
367     };
368     Breakpoint.Manager.BP[] tc1ext_bps = new Breakpoint.Manager.BP[] {
369       BP(tc1_construct), BP(tc1ext_construct),
370     };
371     runTestGroups("TestClass1ext constructor", tc1ext_constructors, tc1ext_bps);
372   }
373 
374   // These test to make sure we are able to break on functions that might have been quickened or
375   // inlined from the boot-image. These were all chosen for being in the bootclasspath, not being
376   // long enough to prevent inlining, and not being used for the testing framework.
377   public static void runBCPMethodTests(boolean test_BCP_private) throws Exception {
378     // The methods we will be breaking on.
379     Method bcp_private_method =
380         test_BCP_private ? Duration.class.getDeclaredMethod("toBigDecimalSeconds") : null;
381     Method bcp_virtual_method = Optional.class.getDeclaredMethod("isPresent");
382     Method bcp_static_method = Optional.class.getDeclaredMethod("empty");
383     Method bcp_private_static_method =
384         test_BCP_private ? Random.class.getDeclaredMethod("seedUniquifier") : null;
385 
386     // Some constructors we will break on.
387     Constructor<?> bcp_stack_constructor = Stack.class.getConstructor();
388     Constructor<?> bcp_vector_constructor = Vector.class.getConstructor();
389     if (!(Vector.class.isAssignableFrom(Stack.class))) {
390       throw new Error("Expected Stack to extend Vector!");
391     }
392 
393     // BCP constructors.
394     Runnable[] vector_constructors = new Runnable[] {
395       new ConstructNative(bcp_vector_constructor),
396       new ConstructReflect(bcp_vector_constructor),
397       new ConstructDirect("new Vector()", Vector::new),
398     };
399     Breakpoint.Manager.BP[] vector_breakpoints = new Breakpoint.Manager.BP[] {
400       BP(bcp_vector_constructor),
401     };
402     runTestGroups("Vector constructor", vector_constructors, vector_breakpoints);
403 
404     Runnable[] stack_constructors = new Runnable[] {
405       new ConstructNative(bcp_stack_constructor),
406       new ConstructReflect(bcp_stack_constructor),
407       new ConstructDirect("new Stack()", Stack::new),
408     };
409     Breakpoint.Manager.BP[] stack_breakpoints = new Breakpoint.Manager.BP[] {
410       BP(bcp_stack_constructor), BP(bcp_vector_constructor),
411     };
412     runTestGroups("Stack constructor", stack_constructors, stack_breakpoints);
413 
414     // Static function
415     Runnable[] static_invokes = new Runnable[] {
416       new InvokeNativeObject(bcp_static_method, null),
417 
418       new InvokeReflect(bcp_static_method, null),
419 
420       new InvokeDirect("Optional::empty", () -> { Optional.empty(); }),
421     };
422     Breakpoint.Manager.BP[] static_breakpoints = new Breakpoint.Manager.BP[] {
423       BP(bcp_static_method)
424     };
425     runTestGroups("bcp static invoke", static_invokes, static_breakpoints);
426 
427     // Static private class function
428     if (test_BCP_private) {
429       Runnable[] private_static_invokes = new Runnable[] {
430         new InvokeNativeLong(bcp_private_static_method, null),
431 
432         new InvokeDirect("Random::seedUniquifier", () -> { new Random(); }),
433       };
434       Breakpoint.Manager.BP[] private_static_breakpoints = new Breakpoint.Manager.BP[] {
435         BP(bcp_private_static_method)
436       };
437       runTestGroups("bcp private static invoke", private_static_invokes, private_static_breakpoints);
438     }
439 
440     // private class method
441     if (test_BCP_private) {
442       Duration test_duration = Duration.ofDays(14);
443       Runnable[] private_invokes = new Runnable[] {
444         new InvokeNativeObject(bcp_private_method, test_duration),
445 
446         new InvokeDirect("Duration::toBigDecimalSeconds", () -> { test_duration.multipliedBy(2); }),
447       };
448       Breakpoint.Manager.BP[] private_breakpoints = new Breakpoint.Manager.BP[] {
449         BP(bcp_private_method)
450       };
451       runTestGroups("bcp private invoke", private_invokes, private_breakpoints);
452     }
453 
454     // class method
455     Runnable[] public_invokes = new Runnable[] {
456       new InvokeNativeBool(bcp_virtual_method, Optional.of("test")),
457 
458       new InvokeReflect(bcp_virtual_method, Optional.of("test2")),
459 
460       new InvokeDirect("Optional::isPresent", () -> { Optional.of("test3").isPresent(); }),
461     };
462     Breakpoint.Manager.BP[] public_breakpoints = new Breakpoint.Manager.BP[] {
463       BP(bcp_virtual_method)
464     };
465     runTestGroups("bcp invoke", public_invokes, public_breakpoints);
466   }
467 
468   public static void runMethodTests() throws Exception {
469     // The methods we will be breaking on.
470     Method breakpoint_method = Test993.class.getDeclaredMethod("breakpoint");
471     Method private_breakpoint_method = Test993.class.getDeclaredMethod("privateBreakpoint");
472     Method i_breakpoint_method = Breakable.class.getDeclaredMethod("iBreakpoint");
473     Method breakit_method = Breakable.class.getDeclaredMethod("breakit");
474     Method breakit_method_tc1ext = TestClass1ext.class.getDeclaredMethod("breakit");
475     Method breakit_method_tc2 = TestClass2.class.getDeclaredMethod("breakit");
476     Method breakit_method_tc2ext = TestClass2ext.class.getDeclaredMethod("breakit");
477     Method breakit_method_tc3 = TestClass3.class.getDeclaredMethod("breakit");
478     Method breakit_method_tc3ext = TestClass3ext.class.getDeclaredMethod("breakit");
479     Method private_method = TestClass4.class.getDeclaredMethod("privateMethod");
480 
481     // Static class function
482     Runnable[] static_invokes = new Runnable[] {
483       new InvokeNative(breakpoint_method, null),
484 
485       new InvokeReflect(breakpoint_method, null),
486 
487       new InvokeDirect("Test993::breakpoint", Test993::breakpoint),
488     };
489     Breakpoint.Manager.BP[] static_breakpoints = new Breakpoint.Manager.BP[] {
490       BP(breakpoint_method)
491     };
492     runTestGroups("static invoke", static_invokes, static_breakpoints);
493 
494     // Static private class function
495     Runnable[] private_static_invokes = new Runnable[] {
496       new InvokeNative(private_breakpoint_method, null),
497 
498       new InvokeDirect("Test993::privateBreakpoint", Test993::privateBreakpoint),
499     };
500     Breakpoint.Manager.BP[] private_static_breakpoints = new Breakpoint.Manager.BP[] {
501       BP(private_breakpoint_method)
502     };
503     runTestGroups("private static invoke", private_static_invokes, private_static_breakpoints);
504 
505     // Static interface function.
506     Runnable[] i_static_invokes = new Runnable[] {
507       new InvokeNative(i_breakpoint_method, null),
508 
509       new InvokeReflect(i_breakpoint_method, null),
510 
511       new InvokeDirect("Breakable::iBreakpoint", Breakable::iBreakpoint),
512     };
513     Breakpoint.Manager.BP[] i_static_breakpoints = new Breakpoint.Manager.BP[] {
514       BP(i_breakpoint_method)
515     };
516     runTestGroups("interface static invoke", i_static_invokes, i_static_breakpoints);
517 
518     // Call default method through a class.
519     Runnable[] tc1_invokes = new Runnable[] {
520       new InvokeNative(breakit_method, new TestClass1()),
521 
522       new InvokeReflect(breakit_method, new TestClass1()),
523 
524       new InvokeDirect("((Breakable)new TestClass1()).breakit()",
525                   () -> ((Breakable)new TestClass1()).breakit()),
526       new InvokeDirect("new TestClass1().breakit()",
527                   () -> new TestClass1().breakit()),
528     };
529     Breakpoint.Manager.BP[] tc1_breakpoints = new Breakpoint.Manager.BP[] {
530       BP(breakit_method)
531     };
532     runTestGroups("TestClass1 invokes", tc1_invokes, tc1_breakpoints);
533 
534     // Call default method through an override and normal invoke-super
535     Runnable[] tc1ext_invokes = new Runnable[] {
536       new InvokeNative(breakit_method, new TestClass1ext()),
537       new InvokeNative(breakit_method_tc1ext, new TestClass1ext()),
538 
539       new InvokeReflect(breakit_method, new TestClass1ext()),
540       new InvokeReflect(breakit_method_tc1ext, new TestClass1ext()),
541 
542       new InvokeDirect("((Breakable)new TestClass1ext()).breakit()",
543                   () -> ((Breakable)new TestClass1ext()).breakit()),
544       new InvokeDirect("((TestClass1)new TestClass1ext()).breakit()",
545                   () -> ((TestClass1)new TestClass1ext()).breakit()),
546       new InvokeDirect("new TestClass1ext().breakit()",
547                   () -> new TestClass1ext().breakit()),
548     };
549     Breakpoint.Manager.BP[] tc1ext_breakpoints = new Breakpoint.Manager.BP[] {
550       BP(breakit_method), BP(breakit_method_tc1ext)
551     };
552     runTestGroups("TestClass1ext invokes", tc1ext_invokes, tc1ext_breakpoints);
553 
554     // Override default/interface method.
555     Runnable[] tc2_invokes = new Runnable[] {
556       new InvokeNative(breakit_method, new TestClass2()),
557       new InvokeNative(breakit_method_tc2, new TestClass2()),
558 
559       new InvokeReflect(breakit_method, new TestClass2()),
560       new InvokeReflect(breakit_method_tc2, new TestClass2()),
561 
562       new InvokeDirect("((Breakable)new TestClass2()).breakit()",
563                   () -> ((Breakable)new TestClass2()).breakit()),
564       new InvokeDirect("new TestClass2().breakit()",
565                   () -> new TestClass2().breakit()),
566     };
567     Breakpoint.Manager.BP[] tc2_breakpoints = new Breakpoint.Manager.BP[] {
568       BP(breakit_method), BP(breakit_method_tc2)
569     };
570     runTestGroups("TestClass2 invokes", tc2_invokes, tc2_breakpoints);
571 
572     // Call overridden method using invoke-super
573     Runnable[] tc2ext_invokes = new Runnable[] {
574       new InvokeNative(breakit_method, new TestClass2ext()),
575       new InvokeNative(breakit_method_tc2, new TestClass2ext()),
576       new InvokeNative(breakit_method_tc2ext, new TestClass2ext()),
577 
578       new InvokeReflect(breakit_method, new TestClass2ext()),
579       new InvokeReflect(breakit_method_tc2, new TestClass2ext()),
580       new InvokeReflect(breakit_method_tc2ext, new TestClass2ext()),
581 
582       new InvokeDirect("((Breakable)new TestClass2ext()).breakit()",
583                   () -> ((Breakable)new TestClass2ext()).breakit()),
584       new InvokeDirect("((TestClass2)new TestClass2ext()).breakit()",
585                   () -> ((TestClass2)new TestClass2ext()).breakit()),
586       new InvokeDirect("new TestClass2ext().breakit())",
587                   () -> new TestClass2ext().breakit()),
588     };
589     Breakpoint.Manager.BP[] tc2ext_breakpoints = new Breakpoint.Manager.BP[] {
590       BP(breakit_method), BP(breakit_method_tc2), BP(breakit_method_tc2ext)
591     };
592     runTestGroups("TestClass2ext invokes", tc2ext_invokes, tc2ext_breakpoints);
593 
594     // Override default method and call it using interface-invoke-super
595     Runnable[] tc3_invokes = new Runnable[] {
596       new InvokeNative(breakit_method, new TestClass3()),
597       new InvokeNative(breakit_method_tc3, new TestClass3()),
598 
599       new InvokeReflect(breakit_method, new TestClass3()),
600       new InvokeReflect(breakit_method_tc3, new TestClass3()),
601 
602       new InvokeDirect("((Breakable)new TestClass3()).breakit()",
603                   () -> ((Breakable)new TestClass3()).breakit()),
604       new InvokeDirect("new TestClass3().breakit())",
605                   () -> new TestClass3().breakit()),
606     };
607     Breakpoint.Manager.BP[] tc3_breakpoints = new Breakpoint.Manager.BP[] {
608       BP(breakit_method), BP(breakit_method_tc3)
609     };
610     runTestGroups("TestClass3 invokes", tc3_invokes, tc3_breakpoints);
611 
612     // Call overridden method using invoke-super
613     Runnable[] tc3ext_invokes = new Runnable[] {
614       new InvokeNative(breakit_method, new TestClass3ext()),
615       new InvokeNative(breakit_method_tc3, new TestClass3ext()),
616       new InvokeNative(breakit_method_tc3ext, new TestClass3ext()),
617 
618       new InvokeReflect(breakit_method, new TestClass3ext()),
619       new InvokeReflect(breakit_method_tc3, new TestClass3ext()),
620       new InvokeReflect(breakit_method_tc3ext, new TestClass3ext()),
621 
622       new InvokeDirect("((Breakable)new TestClass3ext()).breakit()",
623                   () -> ((Breakable)new TestClass3ext()).breakit()),
624       new InvokeDirect("((TestClass3)new TestClass3ext()).breakit()",
625                   () -> ((TestClass3)new TestClass3ext()).breakit()),
626       new InvokeDirect("new TestClass3ext().breakit())",
627                   () -> new TestClass3ext().breakit()),
628     };
629     Breakpoint.Manager.BP[] tc3ext_breakpoints = new Breakpoint.Manager.BP[] {
630       BP(breakit_method), BP(breakit_method_tc3), BP(breakit_method_tc3ext)
631     };
632     runTestGroups("TestClass3ext invokes", tc3ext_invokes, tc3ext_breakpoints);
633 
634     // private instance method.
635     Runnable[] private_instance_invokes = new Runnable[] {
636       new InvokeNative(private_method, new TestClass4()),
637 
638       new InvokeDirect("new TestClass4().callPrivateMethod()",
639                   () -> new TestClass4().callPrivateMethod()),
640     };
641     Breakpoint.Manager.BP[] private_instance_breakpoints = new Breakpoint.Manager.BP[] {
642       BP(private_method)
643     };
644     runTestGroups(
645         "private instance invoke", private_instance_invokes, private_instance_breakpoints);
646   }
647 
648   private static void runTestGroups(String name,
649                                     Runnable[] invokes,
650                                     Breakpoint.Manager.BP[] breakpoints) throws Exception {
651     System.out.println("Running " + name);
652     for (List<Breakpoint.Manager.BP> bps : allCombinations(Arrays.asList(breakpoints))) {
653       System.out.println("\tBreaking on " + bps);
654       for (Runnable test : invokes) {
655         MANAGER.clearAllBreakpoints();
656         MANAGER.setBreakpoints(bps.toArray(new Breakpoint.Manager.BP[0]));
657         test.run();
658       }
659     }
660   }
661 }
662