Path: blob/master/test/hotspot/jtreg/vmTestbase/vm/runtime/defmeth/MethodResolutionTest.java
41159 views
/*1* Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/*24* @test25*26* @modules java.base/jdk.internal.org.objectweb.asm:+open java.base/jdk.internal.org.objectweb.asm.util:+open27* @library /vmTestbase /test/lib28*29* @comment build retransform.jar in current dir30* @run driver vm.runtime.defmeth.shared.BuildJar31*32* @run driver jdk.test.lib.FileInstaller . .33* @run main/othervm/native34* -agentlib:redefineClasses35* -javaagent:retransform.jar36* vm.runtime.defmeth.MethodResolutionTest37*/38package vm.runtime.defmeth;3940import java.util.Set;4142import vm.runtime.defmeth.shared.data.*;43import vm.runtime.defmeth.shared.data.method.param.*;44import vm.runtime.defmeth.shared.DefMethTest;45import vm.runtime.defmeth.shared.builder.TestBuilder;4647import static jdk.internal.org.objectweb.asm.Opcodes.*;48import static vm.runtime.defmeth.shared.ExecutionMode.*;4950/**51* Tests on method resolution in presence of default methods in the hierarchy.52*53* Because default methods reside in interfaces, and interfaces do not have54* the constraint of being single-inheritance, it is possible to inherit55* multiple conflicting default methods, or even inherit the same default method56* from many different inheritance paths.57*58* There is an algorithm to select which method to use in the case that a59* concrete class does not provide an implementation. Informally, the algorithm60* works as follows:61*62* (1) If there is a adequate implementation in the class itself or in a63* superclass (not an interface), then that implementation should be used64* (i.e., class methods always "win").65*66* (2) Failing that, create the set of methods consisting of all methods in the67* type hierarchy which satisfy the slot to be filled, where in this case68* 'satisfy' means that the methods have the same name, the same language-69* level representation of the parameters, and covariant return values. Both70* default methods and abstract methods will be part of this set.71*72* (3) Remove from this set, any method which has a "more specific" version73* anywhere in the hierarchy. That is, if C implements I,J and I extends J,74* then if both I and J have a suitable methods, J's method is eliminated75* from the set since I is a subtype of J -- there exist a more specific76* method than J's method, so that is eliminated.77*78* (4) If the remaining set contains only a single entry, then that method is79* selected. Note that the method may be abstract, in which case an80* IncompatibleClassChangeError is thrown when/if the method is called. If there are81* multiple entries in the set, or no entries, then this also results in an82* IncompatibleClassChangeError when called.83*/84public class MethodResolutionTest extends DefMethTest {8586public static void main(String[] args) {87DefMethTest.runTest(MethodResolutionTest.class,88/* majorVer */ Set.of(MIN_MAJOR_VER, MAX_MAJOR_VER),89/* flags */ Set.of(0, ACC_SYNCHRONIZED),90/* redefine */ Set.of(false, true),91/* execMode */ Set.of(DIRECT, REFLECTION, INVOKE_EXACT, INVOKE_GENERIC, INVOKE_WITH_ARGS, INDY));92}9394/*95* Basic96*97* interface I { int m(); }98* class C implements I { public int m() { return 1; } }99*100* TEST: C c = new C(); c.m() == 1;101* TEST: I i = new C(); i.m() == 1;102*/103public void testBasic(TestBuilder b) {104Interface I =105b.intf("I")106.abstractMethod("m", "()I").build()107.build();108109ConcreteClass C =110b.clazz("C").implement(I)111.concreteMethod("m", "()I").returns(1).build()112.build();113114b.test()115.callSite(I, C, "m", "()I")116.returns(1)117.done()118.test()119.callSite(C, C, "m", "()I")120.returns(1)121.done();122}123124/*125* Basic Default126*127* interface I { int m() default { return 1; } }128* class C implements I {}129*130* TEST: C c = new C(); c.m() == 1;131* TEST: I i = new C(); i.m() == 1;132*/133public void testBasicDefault(TestBuilder b) {134Interface I =135b.intf("I")136.defaultMethod("m", "()I").returns(1)137.build()138.build();139140ConcreteClass C =141b.clazz("C").implement(I)142.build();143144b.test()145.callSite(I, C, "m", "()I")146.returns(1)147.done()148.test().callSite(C, C, "m", "()I")149.returns(1)150.done();151}152153/*154* Far Default155*156* interface I { int m() default { return 1; } }157* interface J extends I {}158* interface K extends J {}159* class C implements K {}160*161* TEST: [I|J|K|C] i = new C(); i.m() == 1;162*/163public void testFarDefault(TestBuilder b) {164Interface I =165b.intf("I")166.defaultMethod("m", "()I").returns(1)167.build()168.build();169170Interface J = b.intf("J").extend(I).build();171Interface K = b.intf("K").extend(J).build();172173ConcreteClass C =174b.clazz("C").implement(K)175.build();176177b.test()178.callSite(I, C, "m", "()I")179.returns(1)180.done()181.test().callSite(J, C, "m", "()I")182.returns(1)183.done()184.test().callSite(K, C, "m", "()I")185.returns(1)186.done()187.test().callSite(C, C, "m", "()I")188.returns(1)189.done();190}191192/*193* Override Abstract194*195* interface I { int m(); }196* interface J extends I { int m() default { return 1; } }197* interface K extends J {}198* class C implements K {}199*200* TEST: C c = new C(); c.m() == 1;201* TEST: K k = new C(); k.m() == 1;202*/203public void testOverrideAbstract(TestBuilder b) {204Interface I = b.intf("I")205.abstractMethod("m", "()I").build()206.build();207208Interface J = b.intf("J").extend(I)209.defaultMethod("m", "()I").returns(1).build()210.build();211212Interface K = b.intf("K").extend(J).build();213214ConcreteClass C = b.clazz("C").implement(K).build();215216b.test()217.callSite(I, C, "m", "()I")218.returns(1)219.done()220.test()221.callSite(J, C, "m", "()I")222.returns(1)223.done()224.test()225.callSite(K, C, "m", "()I")226.returns(1)227.done()228.test()229.callSite(C, C, "m", "()I")230.returns(1)231.done();232}233234/*235* Default vs Concrete236*237* interface I { int m() default { return 1; } }238* class C implements I { public int m() { return 2; } }239*240* TEST: [C|I] c = new C(); c.m() == 2;241*/242public void testDefaultVsConcrete(TestBuilder b) {243Interface I = b.intf("I")244.defaultMethod("m", "()I").returns(1).build()245.build();246247ConcreteClass C = b.clazz("C").implement(I)248.concreteMethod("m", "()I").returns(2).build()249.build();250251b.test()252.callSite(I, C, "m", "()I")253.returns(2)254.done()255.test()256.callSite(C, C, "m", "()I")257.returns(2)258.done();259}260261/*262* InheritedDefault263*264* interface I { int m() default { return 1; } }265* class B implements I {}266* class C extends B {}267*268* TEST: [I|B|C] v = new C(); v.m() == 1;269*/270public void testInheritedDefault(TestBuilder b) {271Interface I = b.intf("I")272.defaultMethod("m", "()I").returns(1).build()273.build();274275ConcreteClass B = b.clazz("B").implement(I).build();276ConcreteClass C = b.clazz("C").extend(B).build();277278b.test()279.callSite(I, C, "m","()I")280.returns(1)281.done()282.test()283.callSite(B, C, "m","()I")284.returns(1)285.done()286.test()287.callSite(C, C, "m","()I")288.returns(1)289.done();290}291292/*293* ExistingInherited294*295* interface I { int m() default { return 1; } }296* class B { public int m() { return 2; } }297* class C extends B implements I {}298*299* TEST: [I|B|C] v = new C(); v.m() == 2;300*/301public void testExistingInherited(TestBuilder b) {302Interface I = b.intf("I")303.defaultMethod("m", "()I").returns(1).build()304.build();305306ConcreteClass B = b.clazz("B")307.concreteMethod("m", "()I").returns(2).build()308.build();309310ConcreteClass C = b.clazz("C").extend(B).implement(I).build();311312b.test()313.callSite(I, C, "m","()I")314.returns(2)315.done()316.test()317.callSite(B, C, "m","()I")318.returns(2)319.done()320.test()321.callSite(C, C, "m","()I")322.returns(2)323.done();324}325326/*327* ExistingInheritedOverride328*329* interface I { int m() default { return 1; } }330* class B implements I { public int m() { return 2; } }331* class C extends B { public int m() { return 3; } }332*333* TEST: [I|B|D] v = new C(); v.m() == 3;334*/335public void testExistingInheritedOverride(TestBuilder b) {336Interface I = b.intf("I")337.defaultMethod("m", "()I").returns(1).build()338.build();339340ConcreteClass B = b.clazz("B").implement(I)341.concreteMethod("m", "()I").returns(2).build()342.build();343344ConcreteClass C = b.clazz("C").extend(B)345.concreteMethod("m", "()I").returns(3).build()346.build();347348b.test()349.callSite(I, C, "m","()I")350.returns(3)351.done()352.test()353.callSite(B, C, "m","()I")354.returns(3)355.done()356.test()357.callSite(C, C, "m","()I")358.returns(3)359.done();360}361362/*363* ExistingInheritedPlusDefault364*365* interface I { int m() default { return 11; } }366* interface J { int m() default { return 12; } }367* class C implements I { public int m() { return 21; } }368* class D extends C { public int m() { return 22; } }369* class E extends D implements J {}370*371* TEST: [I|J|C|D|J] v = new E(); v.m() == 22;372*/373public void testExistingInheritedPlusDefault(TestBuilder b) {374Interface I = b.intf("I")375.defaultMethod("m", "()I").returns(11).build()376.build();377378Interface J = b.intf("J")379.defaultMethod("m", "()I").returns(12).build()380.build();381382ConcreteClass C = b.clazz("C").implement(I)383.concreteMethod("m","()I").returns(21).build()384.build();385386ConcreteClass D = b.clazz("D").extend(C)387.concreteMethod("m", "()I").returns(22).build()388.build();389390ConcreteClass E = b.clazz("E").extend(D).implement(J)391.build();392393b.test()394.callSite(I, E, "m","()I")395.returns(22)396.done()397.test()398.callSite(J, E, "m","()I")399.returns(22)400.done()401.test()402.callSite(C, E, "m","()I")403.returns(22)404.done()405.test()406.callSite(D, E, "m","()I")407.returns(22)408.done()409.test()410.callSite(E, E, "m","()I")411.returns(22)412.done();413}414415/*416* InheritedWithConcrete417*418* interface I { int m() default { return 1; } }419* class B implements I {}420* class C extends B { public int m() { return 2; } }421*422* TEST: [I|B|C] v = new C(); v.m() == 2;423*/424public void testInheritedWithConcrete(TestBuilder b) {425Interface I = b.intf("I")426.defaultMethod("m", "()I").returns(1).build()427.build();428429ConcreteClass B = b.clazz("B").implement(I).build();430431ConcreteClass C = b.clazz("C").extend(B)432.concreteMethod("m", "()I").returns(2).build()433.build();434435b.test()436.callSite(I, C, "m","()I")437.returns(2)438.done()439.test()440.callSite(B, C, "m","()I")441.returns(2)442.done()443.test()444.callSite(C, C, "m","()I")445.returns(2)446.done();447}448449/*450* InheritedWithConcreteAndImpl451*452* interface I { int m() default { return 1; } }453* class B implements I {}454* class C extends B implements I { public int m() { return 2; } }455*456* TEST: [I|B|C] v = new C(); v.m() == 2;457*/458public void testInheritedWithConcreteAndImpl(TestBuilder b) {459Interface I = b.intf("I")460.defaultMethod("m", "()I").returns(1).build()461.build();462463ConcreteClass B = b.clazz("B").implement(I).build();464465ConcreteClass C = b.clazz("C").extend(B)466.concreteMethod("m", "()I").returns(2).build()467.build();468469b.test()470.callSite(I, C, "m","()I")471.returns(2)472.done()473.test()474.callSite(B, C, "m","()I")475.returns(2)476.done()477.test()478.callSite(C, C, "m","()I")479.returns(2)480.done();481}482483/*484* Diamond485*486* interface I { int m() default { return 1; } }487* interface J extends I {}488* interface K extends I {}489* class C implements J, K {}490*491* TEST: [I|J|K|C] c = new C(); c.m() == 99492*/493public void testDiamond(TestBuilder b) {494Interface I = b.intf("I")495.defaultMethod("m", "()I").returns(1).build()496.build();497498Interface J = b.intf("J").extend(I).build();499Interface K = b.intf("K").extend(I).build();500501ConcreteClass C = b.clazz("C").implement(J,K)502.build();503504b.test()505.callSite(I, C, "m","()I")506.returns(1)507.done()508.test()509.callSite(J, C, "m","()I")510.returns(1)511.done()512.test()513.callSite(K, C, "m","()I")514.returns(1)515.done()516.test()517.callSite(C, C, "m","()I")518.returns(1)519.done();520}521522/*523* ExpandedDiamond524*525* interface I { int m() default { return 1; } }526* interface J extends I {}527* interface K extends I {}528* interface L extends I {}529* interface M extends I {}530* class C implements J, K, L, M {}531*532* TEST: [I|J|K|L|M|C] c = new C(); c.m() == 1533*/534public void testExpandedDiamond(TestBuilder b) {535Interface I = b.intf("I")536.defaultMethod("m", "()I").returns(1).build()537.build();538539Interface J = b.intf("J").extend(I).build();540Interface K = b.intf("K").extend(I).build();541Interface L = b.intf("L").extend(I).build();542Interface M = b.intf("M").extend(I).build();543544ConcreteClass C = b.clazz("C").implement(J,K,L,M)545.build();546547b.test()548.callSite(I, C, "m","()I")549.returns(1)550.done()551.test()552.callSite(J, C, "m","()I")553.returns(1)554.done()555.test()556.callSite(K, C, "m","()I")557.returns(1)558.done()559.test()560.callSite(L, C, "m","()I")561.returns(1)562.done()563.test()564.callSite(M, C, "m","()I")565.returns(1)566.done()567.test()568.callSite(C, C, "m","()I")569.returns(1)570.done();571}572573/*574* SelfFill w/ explicit bridge575*576* interface I<T> { int m(T t) default { return 1; } }577* class C implements I<C> {578* public int m(C s) { return 2; }579* public int m(Object o) { ... }580* }581*582* TEST: I i = new C(); i.m((Object)null) == 2;583* TEST: C c = new C(); c.m((Object)null) == 2;584* TEST: C c = new C(); c.m((C)null) == 2;585*/586public void testSelfFillWithExplicitBridge(TestBuilder b) {587/* interface I<T> { ... */588Interface I = b.intf("I").sig("<T:Ljava/lang/Object;>Ljava/lang/Object;")589/* default int m(T t) { return 1; } */590.defaultMethod("m", "(Ljava/lang/Object;)I")591.sig("(TT;)I")592.returns(1)593.build()594.build();595596/* class C implements I<C> { ... */597ConcreteClass C = b.clazz("C").implement(I)598.sig("Ljava/lang/Object;LI<LC;>;")599600/* public int m(I i) { return 2; } */601.concreteMethod("m","(LC;)I").returns(2).build()602603/* bridge method for m(LI;)I */604.concreteMethod("m","(Ljava/lang/Object;)I")605.flags(ACC_PUBLIC | ACC_BRIDGE | ACC_SYNTHETIC)606.returns(2)607.build()608.build();609610// I i = new C(); ...611b.test()612.callSite(I, C, "m", "(Ljava/lang/Object;)I")613.params(new NullParam())614.returns(2)615.done()616// C c = new C(); ...617.test()618.callSite(C, C, "m", "(Ljava/lang/Object;)I")619.params(new NullParam())620.returns(2)621.done()622.test()623.callSite(C, C, "m", "(LC;)I")624.params(new NullParam())625.returns(2)626.done();627}628629/*630* interface I { int m() default { return 1; } }631* class C implements I { int m(int i) { return 2; } }632*633* TEST: C c = new C(); c.m(0) == 2;634* TEST: I i = new C(); i.m() == 1;635*/636public void testMixedArity() {637TestBuilder b = factory.getBuilder();638639Interface I =640b.intf("I")641.defaultMethod("m", "()I").returns(1)642.build()643.build();644645ConcreteClass C =646b.clazz("C").implement(I)647.concreteMethod("m", "(I)I").returns(2)648.build()649.build();650651b.test().callSite(I, C, "m", "()I")652.returns(1)653.build();654b.test().callSite(C, C, "m", "(I)I").params(ICONST_0)655.returns(2)656.build();657}658659/*660* interface I { int m() default { return 1; } }661* interface J { int m(int i) default { return 2; } }662* class C implements I, J {}663*664* TEST: I i = new C(); i.m() == 1; i.m(0) ==> NSME665* TEST: J j = new C(); j.m() ==> NSME; j.m(0) == 2666* TEST: C c = new C(); c.m() == 1; c.m(0) == 2667*/668public void testConflictingDefaultMixedArity1(TestBuilder b) {669Interface I = b.intf("I")670.defaultMethod("m", "()I").returns(1)671.build()672.build();673674Interface J = b.intf("J")675.defaultMethod("m", "(I)I").returns(2)676.build()677.build();678679ConcreteClass C = b.clazz("C").implement(I,J).build();680681682// I i = new C(); ...683b.test().callSite(I, C, "m", "()I")684.returns(1)685.build();686b.test().callSite(I, C, "m", "(I)I").params(ICONST_0)687.throws_(NoSuchMethodError.class)688.build();689690// J j = new C(); ...691b.test().callSite(J, C, "m", "()I")692.throws_(NoSuchMethodError.class)693.build();694b.test().callSite(J, C, "m", "(I)I").params(ICONST_0)695.returns(2)696.build();697698// C c = new C(); ...699b.test().callSite(C, C, "m", "()I")700.returns(1)701.build();702b.test().callSite(C, C, "m", "(I)I").params(ICONST_0)703.returns(2)704.build();705}706707/*708* interface I { int m() default { return 1; } }709* interface J { int m() default { return 2; } }710* class C implements I, J {711* int m(int i) { return 3; }712* }713*714* TEST: I i = new C(); i.m(0) ==> ICCE715* TEST: J j = new C(); j.m(0) ==> ICCE716* TEST: C c = new C(); c.m() ==> ICCE; c.m(0) == 3717*/718public void testConflictingDefaultMixedArity2(TestBuilder b) {719Interface I = b.intf("I")720.defaultMethod("m", "()I").returns(1)721.build()722.build();723724Interface J = b.intf("J")725.defaultMethod("m", "()I").returns(2)726.build()727.build();728729ConcreteClass C = b.clazz("C").implement(I, J)730.concreteMethod("m", "(I)I").returns(3)731.build()732.build();733734// I i = new C(); ...735b.test().callSite(I, C, "m", "()I")736.throws_(IncompatibleClassChangeError.class)737.build();738b.test().callSite(I, C, "m", "(I)I").params(ICONST_0)739.throws_(NoSuchMethodError.class)740.build();741742// J j = new C(); ...743b.test().callSite(J, C, "m", "()I")744.throws_(IncompatibleClassChangeError.class)745.build();746b.test().callSite(J, C, "m", "(I)I").params(ICONST_0)747.throws_(NoSuchMethodError.class)748.build();749750// C c = new C(); ...751b.test().callSite(C, C, "m", "()I")752.throws_(IncompatibleClassChangeError.class)753.build();754b.test().callSite(C, C, "m", "(I)I").params(ICONST_0)755.returns(3)756.build();757}758759/* In package1:760* package p1;761* interface I {762* default int m() { return 10; };763* }764* public interface J extends I {};765*766* In package2:767* class A implements p1.J {}768* A myA = new A;769* myA.m(); // should return 10 except for reflect mode,770* // throw IllegalAccessException with reflect mode771*/772773public void testMethodResolvedInDifferentPackage(TestBuilder b) {774Interface I = b.intf("p1.I").flags(~ACC_PUBLIC & ACC_PUBLIC) // make it package private775.defaultMethod("m", "()I").returns(10)776.build()777.build();778779Interface J = b.intf("p1.J").extend(I)780.build();781782ConcreteClass myA = b.clazz("p2.A").implement(J)783.build();784if (!factory.getExecutionMode().equals("REFLECTION")) {785b.test()786.callSite(myA, myA, "m", "()I")787.returns(10)788.done();789} else {790// -mode reflect will fail with IAE as expected791b.test()792.callSite(myA, myA, "m", "()I")793.throws_(IllegalAccessException.class)794.done();795}796}797798/* In package p1:799* package p1;800* interface I {801* public default int m() { return 12; };802* }803*804* public class A implements I {}805*806* In package p2:807* package p2;808* public interface J { int m(); }809*810* public class B extends p1.A implements J {811* public int m() { return 13; }812* }813*814* Then:815* A myA = new B;816* myA.m(); // should return 13, not throw IllegalAccessError817*/818819public void testMethodResolvedInLocalFirst(TestBuilder b) {820Interface I = b.intf("p1.I")821.defaultMethod("m", "()I").returns(12)822.build()823.build();824825ConcreteClass myA = b.clazz("p1.A").implement(I)826.build();827828Interface J = b.intf("p2.J").abstractMethod("m", "()I")829.build()830.build();831832ConcreteClass myB = b.clazz("p2.B").extend(myA).implement(J)833.concreteMethod("m", "()I").returns(13)834.build()835.build();836837b.test()838.callSite(myB, myB, "m", "()I")839.returns(13)840.done();841}842}843844845