1 /*
2  * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 package vm.runtime.defmeth;
25 
26 import nsk.share.test.TestBase;
27 import vm.runtime.defmeth.shared.DefMethTest;
28 import vm.runtime.defmeth.shared.annotation.KnownFailure;
29 import vm.runtime.defmeth.shared.data.*;
30 import vm.runtime.defmeth.shared.data.method.param.NewInstanceParam;
31 import vm.runtime.defmeth.shared.builder.TestBuilder;
32 import static vm.runtime.defmeth.shared.ExecutionMode.*;
33 import static vm.runtime.defmeth.shared.data.method.body.CallMethod.Invoke.*;
34 import static vm.runtime.defmeth.shared.data.method.body.CallMethod.IndexbyteOp.*;
35 
36 /**
37  * Tests on interaction of default methods with abstract methods
38  *
39  * The rule: "the superclass always wins."
40  *
41  * In searching the superclass hierarchy, a declaration in a superclass is
42  * preferred to a default in an interface. This preference includes abstract
43  * methods in superclasses as well; the defaults are only considered when
44  * the entire implementation hierarchy is silent on the status of the method
45  * in question.
46  */
47 public class DefaultVsAbstractTest extends DefMethTest {
48 
main(String[] args)49     public static void main(String[] args) {
50         TestBase.runTest(new DefaultVsAbstractTest(), args);
51     }
52 
53     /*
54      * interface I          { public int m() default { return 1; } }
55      * class C implements I { public abstract int m(); }
56      *
57      * TEST: new C() throws InstantiationError
58      */
test0()59     public void test0() {
60         TestBuilder b = factory.getBuilder();
61 
62         Interface I = b.intf("I")
63                 .defaultMethod("m", "()I").returns(1).build()
64             .build();
65 
66         ConcreteClass C = b.clazz("C").implement(I)
67                 .abstractMethod("m", "()I").build()
68             .build();
69 
70         b.test()
71             .callSite(I, C, "m", "()I")
72             .throws_(InstantiationError.class)
73             .done()
74         .run();
75     }
76 
77     /*
78      * interface I          {
79      *     public int m() default { return 1; }
80      * }
81      * class C implements I {
82      *     public abstract int m();
83      * }
84      * class D extends C {}
85      *
86      * TEST: I i = new D(); i.m() ==> AME
87      * TEST: C c = new D(); c.m() ==> AME
88      * TEST: D d = new D(); d.m() ==> AME
89      */
90     @KnownFailure(modes = {INVOKE_EXACT, INVOKE_GENERIC, INVOKE_WITH_ARGS, INDY }) // Test1_I_D_m: NPE instead of AME
91                                                                                    // Test3_D_D_m: AME => IAE => ICCE instead of AME
test1()92     public void test1() {
93         TestBuilder b = factory.getBuilder();
94 
95         Interface I = b.intf("I")
96                 .defaultMethod("m", "()I").returns(1).build()
97             .build();
98 
99         ConcreteClass C = b.clazz("C").implement(I)
100                 .abstractMethod("m", "()I").build()
101             .build();
102 
103         ConcreteClass D = b.clazz("D").extend(C).build();
104 
105         b.test()
106             .callSite(I, D, "m",  "()I")
107             .throws_(AbstractMethodError.class)
108             .done()
109         .test()
110             .callSite(C, D, "m", "()I")
111             .throws_(AbstractMethodError.class)
112             .done()
113         .test()
114             .callSite(D, D, "m", "()I")
115             .throws_(AbstractMethodError.class)
116             .done()
117         .run();
118     }
119 
120     /*
121      * interface I {
122      *     default  public int m() { return 1; }
123      * }
124      * class C     {
125      *     abstract public int m();
126      * }
127      * class D extends C implements I {}
128      *
129      * TEST: I o = new D(); o.m()I throws AME
130      * TEST: C o = new D(); o.m()I throws AME
131      * TEST: D o = new D(); o.m()I throws AME
132      */
133     @KnownFailure(modes = { INVOKE_EXACT, INVOKE_GENERIC, INVOKE_WITH_ARGS, INDY }) // Test1_I_D_m: NPE instead of AME
134                                                                                     // Test3_D_D_m: AME => IAE => ICCE instead of AME
test2()135     public void test2() {
136         TestBuilder b = factory.getBuilder();
137 
138         Interface I = b.intf("I")
139                 .defaultMethod("m", "()I").returns(1).build()
140             .build();
141 
142         ConcreteClass C = b.clazz("C")
143                 .abstractMethod("m", "()I").build()
144             .build();
145 
146         ConcreteClass D = b.clazz("D").extend(C).implement(I).build();
147 
148         b.test()
149             .callSite(I, D, "m", "()I")
150             .throws_(AbstractMethodError.class)
151             .done()
152         .test()
153             .callSite(C, D, "m", "()I")
154             .throws_(AbstractMethodError.class)
155             .done()
156         .test()
157             .callSite(D, D, "m", "()I")
158             .throws_(AbstractMethodError.class)
159             .done()
160         .run();
161     }
162 
163     /*
164      * interface I {
165      *     default public int m() { return 1; }
166      * }
167      * class C {
168      *     abstract public int m();
169      * }
170      * class D extends C implements I {
171      *     public int m()  { return 2; }
172      * }
173      *
174      * TEST: I o = new D(); o.m()I == 2
175      * TEST: C o = new D(); o.m()I == 2
176      * TEST: D o = new D(); o.m()I == 2
177      */
test3()178     public void test3() {
179         TestBuilder b = factory.getBuilder();
180 
181         Interface I = b.intf("I")
182                 .defaultMethod("m", "()I").returns(1).build()
183             .build();
184 
185         ConcreteClass C = b.clazz("C")
186                 .abstractMethod("m", "()I").build()
187             .build();
188 
189         ConcreteClass D = b.clazz("D").extend(C).implement(I)
190                 .concreteMethod("m", "()I").returns(2)
191                 .build()
192             .build();
193 
194         b.test() // I i = new D(); ...
195             .callSite(I, D, "m", "()I").returns(2)
196             .done()
197         .test()  // C c = new D(); ...
198             .callSite(C, D, "m", "()I").returns(2)
199             .done()
200         .test()  // D d = new C(); ...
201             .callSite(D, D, "m", "()I").returns(2)
202             .done()
203         .run();
204     }
205 
206     /*
207      * interface I {
208      *     default public int m() { return 1; }
209      * }
210      * class E {
211      *     abstract public int m();
212      * }
213      * class D extends E {}
214      * class C extends D implements I {}
215      *
216      * TEST: I o = new C(); o.m()I throws AME
217      * TEST: E o = new C(); o.m()I throws AME
218      * TEST: D o = new C(); o.m()I throws AME
219      * TEST: C o = new C(); o.m()I throws AME
220      */
221     @KnownFailure(modes = {
222         INVOKE_EXACT, INVOKE_GENERIC, INVOKE_WITH_ARGS, INDY // Test1_I_C_m: NPE instead of AME
223                                                              // Test3_D_C_m: AME => IAE => ICCE instead of AME
224                                                              // Test4_C_C_m: AME => IAE => ICCE instead of AME
225     })
test4()226     public void test4() {
227         TestBuilder b = factory.getBuilder();
228 
229         Interface I = b.intf("I")
230                 .defaultMethod("m", "()I").returns(1).build()
231                 .build();
232 
233         ConcreteClass E = b.clazz("E")
234                 .abstractMethod("m", "()I").build()
235                 .build();
236 
237         ConcreteClass D = b.clazz("D").extend(E).build();
238 
239         ConcreteClass C = b.clazz("C").extend(D).implement(I).build();
240 
241         b.test() // I i = new C(); ...
242             .callSite(I, C, "m", "()I")
243             .throws_(AbstractMethodError.class)
244             .done()
245         .test() // E e = new C(); ...
246             .callSite(E, C, "m", "()I")
247             .throws_(AbstractMethodError.class)
248             .done()
249         .test() // D d = new C(); ...
250             .callSite(D, C, "m", "()I")
251             .throws_(AbstractMethodError.class)
252             .done()
253         .test() // C c = new C(); ...
254             .callSite(C, C, "m", "()I")
255             .throws_(AbstractMethodError.class)
256             .done()
257         .run();
258     }
259 
260     /*
261      * interface I {
262      *     default public int m() { return 1; }
263      * }
264      * class E {
265      *     abstract public int m();
266      * }
267      * class D extends E {
268      *     public int m()  { return 2; }
269      * }
270      * class C extends D implements I {}
271      *
272      * TEST: I o = new C(); o.m()I == 2
273      * TEST: I o = new C(); o.m()I == 2
274      * TEST: I o = new C(); o.m()I == 2
275      * TEST: I o = new C(); o.m()I == 2
276      */
test5()277     public void test5() {
278         TestBuilder b = factory.getBuilder();
279 
280         Interface I = b.intf("I")
281                 .defaultMethod("m", "()I").returns(1).build()
282             .build();
283 
284         ConcreteClass E = b.clazz("E")
285                 .abstractMethod("m", "()I").build()
286             .build();
287 
288         ConcreteClass D = b.clazz("D").extend(E)
289                 .concreteMethod("m", "()I").returns(2).build()
290             .build();
291 
292         ConcreteClass C = b.clazz("C").extend(D).implement(I).build();
293 
294         b.test() // I i = new C(); ...
295             .callSite(I, C, "m", "()I")
296             .returns(2)
297             .done()
298         .test() // E e = new C(); ...
299             .callSite(I, C, "m", "()I")
300             .returns(2)
301             .done()
302         .test() // D d = new C(); ...
303             .callSite(I, C, "m", "()I")
304             .returns(2)
305             .done()
306         .test() // C c = new C(); ...
307             .callSite(I, C, "m", "()I")
308             .returns(2)
309             .done()
310         .run();
311     }
312 
313     /*
314      * interface I {
315      *     default public int m() { return 1; }
316      * }
317      * interface J {
318      *     default public int m() { return 2; }
319      * }
320      * class E {
321      *     abstract public int m();
322      * }
323      * class D extends E {
324      *     public int m()  { return 3; }
325      * }
326      * class C extends D implements I, J {}
327      *
328      * TEST: I o = new C(); o.m()I == 3
329      * TEST: J o = new C(); o.m()I == 3
330      * TEST: E o = new C(); o.m()I == 3
331      * TEST: D o = new C(); o.m()I == 3
332      * TEST: J o = new C(); o.m()I == 3
333      */
test6()334     public void test6() {
335         TestBuilder b = factory.getBuilder();
336 
337         Interface I = b.intf("I")
338                 .defaultMethod("m", "()I").returns(1).build()
339             .build();
340 
341         Interface J = b.intf("J")
342                 .defaultMethod("m", "()I").returns(2).build()
343             .build();
344 
345         ConcreteClass E = b.clazz("E")
346                 .abstractMethod("m", "()I").build()
347             .build();
348 
349         ConcreteClass D = b.clazz("D").extend(E)
350                 .concreteMethod("m", "()I").returns(3).build()
351             .build();
352 
353         ConcreteClass C = b.clazz("C").extend(D).implement(I, J).build();
354 
355 
356         b.test() // I i = new C(); ...
357             .callSite(I, C, "m", "()I").returns(3)
358             .done()
359         .test() // J j = new C(); ...
360             .callSite(J, C, "m", "()I").returns(3)
361             .done()
362         .test()  // E e = new C(); ...
363             .callSite(E, C, "m", "()I").returns(3)
364             .done()
365         .test()  // D d = new C(); ...
366             .callSite(D, C, "m", "()I").returns(3)
367             .done()
368         .test() // C c = new C(); ...
369             .callSite(J, C, "m", "()I").returns(3)
370             .done()
371         .run();
372     }
373 
374     /*
375      * interface I {
376      *     abstract public int m();
377      * }
378      *
379      * interface J {
380      *     default public int m() { return 1; }
381      * }
382      *
383      * class A implements I;
384      *
385      * class B extends A implements J;
386      *
387      * TEST: A o = new B(); o.m()I
388      *                returns 1 for REFLECTION and INVOKE_WITH_ARGS
389      *                ICCE for other modes
390      */
testInvokeInterfaceClassDefaultMethod()391     public void testInvokeInterfaceClassDefaultMethod() {
392         TestBuilder b = factory.getBuilder();
393 
394         Interface I = b.intf("I")
395             .abstractMethod("m", "()I").build()
396             .build();
397 
398         Interface J = b.intf("J")
399             .extend(I)
400             .defaultMethod("m", "()I").returns(1).build()
401             .build();
402 
403         ConcreteClass A = b.clazz("A").implement(I).build();
404 
405         ConcreteClass B = b.clazz("B").extend(A).implement(J).build();
406 
407         String exeMode = factory.getExecutionMode();
408 
409         // the test passes in the reflection mode because there's no way to
410         // express invokeinterface on a class using Reflection API
411         // In the test generator, vm.runtime.defmeth.shared.executor.ReflectionTest,
412         // the invokeinterface is switched to invokevirtual.
413         //
414         // the test passes in the INVOKE_WITH_ARGS mode due to the fix for
415         // JDK-8032010 to conform with the removal of the following check
416         // during method resolution in JVMS-5.4.3.3 Method Resolution
417         // "If method lookup succeeds and the method is abstract, but C is not
418         // abstract, method resolution throws an AbstractMethodError."
419         if (exeMode.equals("REFLECTION") ||
420             exeMode.equals("INVOKE_WITH_ARGS")) {
421             b.test().interfaceCallSite(A, B, "m", "()I")
422              .returns(1).done()
423              .run();
424         } else {
425             // ICCE in other modes due to
426             // JVMS-5.4.3.4. Interface Method Resolution
427             //   When resolving an interface method reference:
428             //     If C is not an interface, interface method resolution throws an IncompatibleClassChangeError.
429             b.test().interfaceCallSite(A, B, "m", "()I")
430              .throws_(IncompatibleClassChangeError.class).done()
431              .run();
432         }
433     }
434 
435     /*
436      * interface I {
437      *     abstract public int m();
438      * }
439      *
440      * interface J {
441      *     abstract public int m();
442      * }
443      *
444      * class A implements I;
445      *
446      * class B extends A implements J;
447      *
448      * TEST: A o = new B(); o.m()I
449      *                ICCE for DIRECT mode
450      *                AME for REFLECTION and INVOKE_WITH_ARGS modes
451      *                IAE for other modes
452      */
testInvokeInterfaceClassAbstractMethod()453     public void testInvokeInterfaceClassAbstractMethod() {
454         TestBuilder b = factory.getBuilder();
455 
456         Interface I = b.intf("I")
457             .abstractMethod("m", "()I").build()
458             .build();
459 
460         Interface J = b.intf("J")
461             .abstractMethod("m", "()I").build()
462             .build();
463 
464         ConcreteClass A = b.clazz("A").implement(I).build();
465 
466         ConcreteClass B = b.clazz("B").extend(A).implement(J).build();
467 
468         String exeMode = factory.getExecutionMode();
469 
470         // ICCE in direct mode due to
471         // JVMS-5.4.3.4. Interface Method Resolution
472         //   When resolving an interface method reference:
473         //     If C is not an interface, interface method resolution throws an IncompatibleClassChangeError.
474         Class expectedError = IncompatibleClassChangeError.class;;
475 
476         b.test().interfaceCallSite(A, B, "m", "()I")
477          .throws_(expectedError).done()
478          .run();
479 
480     }
481 
482     /*
483      * interface I {
484      *     public int m() default { return 1; }
485      * }
486      *
487      * interface J {
488      *     public int m() default { return 1; }
489      * }
490      *
491      * class A implements I;
492      *
493      * class B extends A implements J;
494      *
495      * TEST: A o = new B(); o.m()I
496      *                ICCE for all modes
497      */
testInvokeInterfaceMultipleDefinedClassDefaultMethod()498     public void testInvokeInterfaceMultipleDefinedClassDefaultMethod() {
499         TestBuilder b = factory.getBuilder();
500 
501         Interface I = b.intf("I")
502             .defaultMethod("m", "()I").returns(1).build()
503             .build();
504 
505         Interface J = b.intf("J")
506             .defaultMethod("m", "()I").returns(1).build()
507             .build();
508 
509         ConcreteClass A = b.clazz("A").implement(I).build();
510 
511         ConcreteClass B = b.clazz("B").extend(A).implement(J).build();
512 
513         String exeMode = factory.getExecutionMode();
514 
515         // ICCE in direct mode due to
516         // JVMS-5.4.3.4. Interface Method Resolution
517         //   When resolving an interface method reference:
518         //     If C is not an interface, interface method resolution throws an IncompatibleClassChangeError.
519         Class expectedError = IncompatibleClassChangeError.class;
520 
521         b.test().interfaceCallSite(A, B, "m", "()I")
522          .throws_(expectedError).done()
523          .run();
524     }
525 
526 }
527