/* * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package vm.runtime.defmeth; import nsk.share.test.TestBase; import vm.runtime.defmeth.shared.DefMethTest; import vm.runtime.defmeth.shared.annotation.KnownFailure; import vm.runtime.defmeth.shared.annotation.NotApplicableFor; import vm.runtime.defmeth.shared.data.*; import static vm.runtime.defmeth.shared.data.method.body.CallMethod.Invoke.*; import static vm.runtime.defmeth.shared.data.method.body.CallMethod.IndexbyteOp.*; import vm.runtime.defmeth.shared.builder.TestBuilder; import static vm.runtime.defmeth.shared.ExecutionMode.*; /** * Tests on conflicting defaults. * * It is allowable to inherit a default through multiple paths (such as * through a diamond-shaped interface hierarchy), but the resolution procedure * is looking for a unique, most specific default-providing interface. * * If one default shadows another (where a subinterface provides a different * default for an extension method declared in a superinterface), then the less * specific interface is pruned from consideration no matter where it appears * in the inheritance hierarchy. If two or more extended interfaces provide * default implementations, and one is not a superinterface of the other, then * neither is used and a linkage exception is thrown indicating conflicting * default implementations. */ public class ConflictingDefaultsTest extends DefMethTest { public static void main(String[] args) { TestBase.runTest(new ConflictingDefaultsTest(), args); } /* * Conflict * * interface I { int m() default { return 1; } } * interface J { int m() default { return 2; } } * class C implements I, J {} * * TEST: C c = new C(); c.m() ==> ICCE */ public void testConflict() { TestBuilder b = factory.getBuilder(); Interface I = b.intf("I") .defaultMethod("m", "()I").returns(1).build() .build(); Interface J = b.intf("J") .defaultMethod("m", "()I").returns(2).build() .build(); ConcreteClass C = b.clazz("C").implement(I,J).build(); b.test().callSite(C, C, "m","()I") .throws_(IncompatibleClassChangeError.class) .done() .run(); } /* * Maximally-specific Default (0.6.3 spec change) * * interface I { int m(); } * interface J { int m() default { return 2; } } * class C implements I, J {} * * TEST: C c = new C(); c.m() return 2 */ public void testMaximallySpecificDefault() { TestBuilder b = factory.getBuilder(); Interface I = b.intf("I") .abstractMethod("m", "()I").build() .build(); Interface J = b.intf("J") .defaultMethod("m", "()I").returns(2).build() .build(); ConcreteClass C = b.clazz("C").implement(I,J).build(); b.test().callSite(C, C, "m","()I") .returns(2) .done() .run(); } /* * Reabstract * * interface I { int m() default { return 1; } } * interface J extends I { int m(); } * class C implements J {} * * TEST: C c = new C(); c.m() ==> AME */ public void testReabstract() { TestBuilder b = factory.getBuilder(); Interface I = b.intf("I") .defaultMethod("m", "()I").returns(1).build() .build(); Interface J = b.intf("J").extend(I) .abstractMethod("m", "()I").build() .build(); ConcreteClass C = b.clazz("C").implement(J).build(); b.test().callSite(C, C, "m","()I") .throws_(AbstractMethodError.class) .done() .run(); } /* * Reabstract2 * * interface I { int m() default { return 1; } } * interface J extends I { int m(); } * class C implements J {} * class D extends C { callSuper C.m} * * TEST: C c = new C(); c.m() ==> AME * TEST: J j = new C(); j.m() ==> AME * TEST: I i = new C(); i.m() ==> AME * TEST: D d = new D(); d.m() ==> callSuper C.m ==> AME */ public void testReabstract2() { TestBuilder b = factory.getBuilder(); Interface I = b.intf("I") .defaultMethod("m", "()I").returns(1).build() .build(); Interface J = b.intf("J").extend(I) .abstractMethod("m", "()I").build() .build(); ConcreteClass C = b.clazz("C").implement(J).build(); ConcreteClass D = b.clazz("D").extend(C) .concreteMethod("m", "()I").callSuper(C, "m", "()I").build() .build(); b.test().callSite(C, C, "m","()I") .throws_(AbstractMethodError.class) .done() .test().callSite(J, C, "m","()I") .throws_(AbstractMethodError.class) .done() .test().callSite(I, C, "m","()I") .throws_(AbstractMethodError.class) .done() .test().callSite(D, D, "m","()I") .throws_(AbstractMethodError.class) .done() .run(); } /* * ReabstractConflictingDefaults * * interface I { int m() default { return 1; } } * interface J { int m() default { return 2; } } * interface K extends I,J { int m(); } * class A implements I,J {} * class C extends A implements K {} * * TEST: A c = new C(); c.m() ==> AME */ public void testReabstractConflictingDefaults() { TestBuilder b = factory.getBuilder(); Interface I = b.intf("I") .defaultMethod("m", "()I").returns(1).build() .build(); Interface J = b.intf("J") .defaultMethod("m", "()I").returns(2).build() .build(); Interface K = b.intf("K").extend(I,J) .abstractMethod("m", "()I").build() .build(); ConcreteClass A = b.clazz("A").implement(I,J).build(); ConcreteClass C = b.clazz("C").extend(A).implement(K).build(); b.test().callSite(A, C, "m","()I") .throws_(AbstractMethodError.class) .done() .run(); } /* * ReabstractConflictingDefaultsInvokeInterface * * interface I { int m() default { return 1; } } * interface J { int m() default { return 2; } } * interface K extends I,J { int m(); } * interface L extends K { } * class A implements I,J {} * class C extends A implements K {} * class D extends C implements L {} * * TEST: I i = new A(); i.m() ==> ICCE * TEST: K k = new C(); k.m() ==> AME * TEST: L l = new D(); l.m() ==> AME */ public void testReabstractConflictingDefaultsInvokeInterface() { TestBuilder b = factory.getBuilder(); Interface I = b.intf("I") .defaultMethod("m", "()I").returns(1).build() .build(); Interface J = b.intf("J") .defaultMethod("m", "()I").returns(2).build() .build(); Interface K = b.intf("K").extend(I,J) .abstractMethod("m", "()I").build() .build(); Interface L = b.intf("L").extend(K) .build(); ConcreteClass A = b.clazz("A").implement(I,J).build(); ConcreteClass C = b.clazz("C").extend(A).implement(K).build(); ConcreteClass D = b.clazz("D").extend(C).implement(L).build(); b.test().callSite(I, A, "m","()I") .throws_(IncompatibleClassChangeError.class) .done() .test().callSite(K, C, "m","()I") .throws_(AbstractMethodError.class) .done() .test().callSite(L, D, "m","()I") .throws_(AbstractMethodError.class) .done() .run(); } /* * ReabstractConflictingDefaultsSuper * * interface I { int m() default { return 1; } } * interface J { int m() default { return 2; } } * interface K extends I,J { int m(); } * interface L extends K { } * class A implements I,J {} * class C extends A implements K {} * class D extends C implements L {int m() {callSuper A.m } * * TEST: I i = new A(); i.m() ==> ICCE * TEST: K k = new C(); CallSuper k.m() ==> AME * TEST: L l = new D(); l.m() ==> AME */ public void testReabstractConflictingDefaultsSuper() { TestBuilder b = factory.getBuilder(); Interface I = b.intf("I") .defaultMethod("m", "()I").returns(1).build() .build(); Interface J = b.intf("J") .defaultMethod("m", "()I").returns(2).build() .build(); Interface K = b.intf("K").extend(I,J) .abstractMethod("m", "()I").build() .build(); Interface L = b.intf("L").extend(K) .build(); ConcreteClass A = b.clazz("A").implement(I,J).build(); ConcreteClass C = b.clazz("C").extend(A).implement(K).build(); ConcreteClass D = b.clazz("D").extend(C).implement(L) .concreteMethod("m", "()I").callSuper(A, "m", "()I").build() .build(); b.test().callSite(I, A, "m","()I") .throws_(IncompatibleClassChangeError.class) .done() .test().callSite(L, D, "m","()I") .throws_(AbstractMethodError.class) .done() .run(); } /* * testReabstractResolveMethod00705m2 * * Test case for JDK-8027804: JCK resolveMethod test fails expecting AME * * This test is an extension of the JCK test resolveMethod00705m2 * with additional invoke* bytecodes specified for testing purposes. * * interface I { int m() default { return 1; } } * interface J implements I { int m(); } * class A implements J,I {} * class C extends A {} * * TEST: A a = new C(); a.m() ==> AME (invokevirtual) * C c = new C(); c.m() ==> AME (invokevirtual) * J j = new C(); j.m() ==> AME (invokeinterface) * I i = new C(); i.m() ==> AME (invokeinterface) * c.test_Cmethod_ISMR(); c.super.m() ==> AME (invokespecial MR) * a.test_Amethod_ISIMR(); j.super.m() ==> AME (invokespecial IMR) * * For ver > 49, error will be AME * For ver = 49, error will be VE */ @NotApplicableFor(modes = { REDEFINITION }) // Can't redefine a class that gets error during loading public void testReabstractResolveMethod00705m2() { TestBuilder b = factory.getBuilder(); Interface I = b.intf("I") .defaultMethod("m", "()I").returns(1).build() .build(); Interface J = b.intf("J").extend(I) .abstractMethod("m", "()I").build() .build(); ConcreteClass A = b.clazz("A").implement(J,I) .concreteMethod("test_Amethod_ISIMR", "()V") .invoke(SPECIAL, b.clazzByName("J"), b.clazzByName("A"), "m", "()I", INTERFACEMETHODREF) .build() .build(); ConcreteClass C = b.clazz("C").extend(A) .concreteMethod("test_Cmethod_ISMR", "()V") .invoke(SPECIAL, b.clazzByName("C"), b.clazzByName("C"), "m", "()I", CALLSITE) .build() .build(); Class expectedError1, expectedError2; if (factory.getVer() >=52) { expectedError1 = expectedError2 = AbstractMethodError.class; } else { expectedError1 = expectedError2 = VerifyError.class; } b.test().callSite(A, C, "m", "()I") .throws_(expectedError2) .done() .test().callSite(C, C, "m", "()I") .throws_(expectedError2) .done() .test().callSite(J, C, "m", "()I") .throws_(expectedError1) .done() .test().callSite(I, C, "m", "()I") .throws_(expectedError1) .done() .test().callSite(C, C, "test_Cmethod_ISMR", "()V") .throws_(expectedError2) .done() .test().callSite(A, C, "test_Amethod_ISIMR", "()V") .throws_(expectedError2) .done() .run(); } /* * Shadow * * interface I { int m() default { return 1; } } * interface J extends I { int m() default { return 2; } } * class C implements J {} * * TEST: [I|J|C] c = new C(); c.m() == 2; */ public void testShadow() { TestBuilder b = factory.getBuilder(); Interface I = b.intf("I") .defaultMethod("m", "()I").returns(1).build() .build(); Interface J = b.intf("J").extend(I) .defaultMethod("m", "()I").returns(2).build() .build(); ConcreteClass C = b.clazz("C").implement(J).build(); b.test().callSite(I, C, "m","()I") .returns(2) .done() .test() .callSite(J, C, "m","()I") .returns(2) .done() .test() .callSite(C, C, "m","()I") .returns(2) .done() .run(); } /* * Disqualified * * interface I { int m() default { return 1; } } * interface J extends I { int m() default { return 2; } } * class C implements I, J {} * * TEST: [I|J|C] c = new C(); c.m() == 2; */ public void testDisqualified() { TestBuilder b = factory.getBuilder(); Interface I = b.intf("I") .defaultMethod("m", "()I").returns(1).build() .build(); Interface J = b.intf("J").extend(I) .defaultMethod("m", "()I").returns(2).build() .build(); ConcreteClass C = b.clazz("C").implement(I,J).build(); b.test() .callSite(I, C, "m","()I") .returns(2) .done() .test() .callSite(J, C, "m","()I") .returns(2) .done() .test() .callSite(C, C, "m","()I") .returns(2) .done() .run(); } /* * Mixed arity * * interface I { int m() default { return 1; } } * interface J { int m(int i) default { return 2; } } * class C implements I, J {} * * TEST: I i = new C(); i.m() == 1; i.m(0) ==> NSME * TEST: J j = new C(); j.m() ==> NSME; j.m(0) == 2 * TEST: C c = new C(); c.m() == 1; c.m(0) == 2 */ @KnownFailure(modes = { INVOKE_EXACT, INVOKE_GENERIC, INDY }) // IncompatibleClassChangeError instead of NoSuchMethodError public void testMixedArity1() { TestBuilder b = factory.getBuilder(); Interface I = b.intf("I") .defaultMethod("m", "()I").returns(1).build() .build(); Interface J = b.intf("J") .defaultMethod("m", "(I)I").returns(2).build() .build(); ConcreteClass C = b.clazz("C").implement(I,J).build(); // I i = new C(); ... b.test() .callSite(I, C, "m","()I") .returns(1) .done() .test() .callSite(I, C, "m","(I)I") .params(0) .throws_(NoSuchMethodError.class) .done() // J j = new C(); ... .test() .callSite(J, C, "m","()I") .throws_(NoSuchMethodError.class) .done() .test() .callSite(J, C, "m","(I)I") .params(0) .returns(2) .done() // C c = new C(); ... .test() .callSite(C, C, "m","()I") .returns(1) .done() .test() .callSite(C, C, "m","(I)I") .params(0) .returns(2) .done() .run(); } /* * Mixed arity * * interface I { int m() default { return 1; } } * interface J { int m() default { return 2; } } * class C implements I, J { int m(int i) { return 3; }} * * TEST: I i = new C(); i.m() ==> ICCE * TEST: J j = new C(); j.m() ==> ICCE * TEST: C c = new C(); c.m() ==> ICCE; c.m(0) == 3 */ public void testMixedArity2() { TestBuilder b = factory.getBuilder(); Interface I = b.intf("I") .defaultMethod("m", "()I").returns(1).build() .build(); Interface J = b.intf("J") .defaultMethod("m", "()I").returns(2).build() .build(); ConcreteClass C = b.clazz("C").implement(I,J) .concreteMethod("m", "(I)I").returns(3).build() .build(); // I i = new C(); ... b.test() .callSite(I, C, "m","()I") .throws_(IncompatibleClassChangeError.class) .done() // J j = new C(); ... .test() .callSite(J, C, "m","()I") .throws_(IncompatibleClassChangeError.class) .done() // C c = new C(); ... .test() .callSite(C, C, "m","()I") .throws_(IncompatibleClassChangeError.class) .done() .test() .callSite(C, C, "m","(I)I") .params(0) .returns(3) .done() .run(); } }