aoqi@0: /* aoqi@0: * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. aoqi@0: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. aoqi@0: * aoqi@0: * This code is free software; you can redistribute it and/or modify it aoqi@0: * under the terms of the GNU General Public License version 2 only, as aoqi@0: * published by the Free Software Foundation. Oracle designates this aoqi@0: * particular file as subject to the "Classpath" exception as provided aoqi@0: * by Oracle in the LICENSE file that accompanied this code. aoqi@0: * aoqi@0: * This code is distributed in the hope that it will be useful, but WITHOUT aoqi@0: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or aoqi@0: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License aoqi@0: * version 2 for more details (a copy is included in the LICENSE file that aoqi@0: * accompanied this code). aoqi@0: * aoqi@0: * You should have received a copy of the GNU General Public License version aoqi@0: * 2 along with this work; if not, write to the Free Software Foundation, aoqi@0: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. aoqi@0: * aoqi@0: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA aoqi@0: * or visit www.oracle.com if you need additional information or have any aoqi@0: * questions. aoqi@0: */ aoqi@0: aoqi@0: package org.openjdk.tests.vm; aoqi@0: aoqi@0: import org.openjdk.tests.separate.Compiler; aoqi@0: import org.openjdk.tests.separate.TestHarness; aoqi@0: import org.testng.annotations.Test; aoqi@0: aoqi@0: import static org.openjdk.tests.separate.SourceModel.AbstractMethod; aoqi@0: import static org.openjdk.tests.separate.SourceModel.AccessFlag; aoqi@0: import static org.openjdk.tests.separate.SourceModel.Class; aoqi@0: import static org.openjdk.tests.separate.SourceModel.ConcreteMethod; aoqi@0: import static org.openjdk.tests.separate.SourceModel.DefaultMethod; aoqi@0: import static org.openjdk.tests.separate.SourceModel.Extends; aoqi@0: import static org.openjdk.tests.separate.SourceModel.Interface; aoqi@0: import static org.openjdk.tests.separate.SourceModel.MethodParameter; aoqi@0: import static org.openjdk.tests.separate.SourceModel.TypeParameter; aoqi@0: import static org.testng.Assert.assertEquals; aoqi@0: import static org.testng.Assert.assertNotNull; aoqi@0: import static org.testng.Assert.fail; aoqi@0: aoqi@0: @Test(groups = "vm") aoqi@0: public class DefaultMethodsTest extends TestHarness { aoqi@0: public DefaultMethodsTest() { aoqi@0: super(false, false); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * class C { public int m() { return 22; } } aoqi@0: * aoqi@0: * TEST: C c = new C(); c.m() == 22 aoqi@0: */ aoqi@0: public void testHarnessInvokeVirtual() { aoqi@0: Class C = new Class("C", ConcreteMethod.std("22")); aoqi@0: assertInvokeVirtualEquals(22, C); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * interface I { int m(); } aoqi@0: * class C implements I { public int m() { return 33; } } aoqi@0: * aoqi@0: * TEST: I i = new C(); i.m() == 33; aoqi@0: */ aoqi@0: public void testHarnessInvokeInterface() { aoqi@0: Interface I = new Interface("I", AbstractMethod.std()); aoqi@0: Class C = new Class("C", I, ConcreteMethod.std("33")); aoqi@0: assertInvokeInterfaceEquals(33, C, I); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * class C {} aoqi@0: * aoqi@0: * TEST: C c = new C(); c.m() throws NoSuchMethod aoqi@0: */ aoqi@0: public void testHarnessThrows() { aoqi@0: Class C = new Class("C"); aoqi@0: assertThrows(NoSuchMethodError.class, C); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * interface I { int m() default { return 44; } } aoqi@0: * class C implements I {} aoqi@0: * aoqi@0: * TEST: C c = new C(); c.m() == 44; aoqi@0: * TEST: I i = new C(); i.m() == 44; aoqi@0: */ aoqi@0: public void testBasicDefault() { aoqi@0: Interface I = new Interface("I", DefaultMethod.std("44")); aoqi@0: Class C = new Class("C", I); aoqi@0: aoqi@0: assertInvokeVirtualEquals(44, C); aoqi@0: assertInvokeInterfaceEquals(44, C, I); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * interface I { default int m() { return 44; } } aoqi@0: * interface J extends I {} aoqi@0: * interface K extends J {} aoqi@0: * class C implements K {} aoqi@0: * aoqi@0: * TEST: C c = new C(); c.m() == 44; aoqi@0: * TEST: I i = new C(); i.m() == 44; aoqi@0: */ aoqi@0: public void testFarDefault() { aoqi@0: Interface I = new Interface("I", DefaultMethod.std("44")); aoqi@0: Interface J = new Interface("J", I); aoqi@0: Interface K = new Interface("K", J); aoqi@0: Class C = new Class("C", K); aoqi@0: aoqi@0: assertInvokeVirtualEquals(44, C); aoqi@0: assertInvokeInterfaceEquals(44, C, K); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * interface I { int m(); } aoqi@0: * interface J extends I { default int m() { return 44; } } aoqi@0: * interface K extends J {} aoqi@0: * class C implements K {} aoqi@0: * aoqi@0: * TEST: C c = new C(); c.m() == 44; aoqi@0: * TEST: K k = new C(); k.m() == 44; aoqi@0: */ aoqi@0: public void testOverrideAbstract() { aoqi@0: Interface I = new Interface("I", AbstractMethod.std()); aoqi@0: Interface J = new Interface("J", I, DefaultMethod.std("44")); aoqi@0: Interface K = new Interface("K", J); aoqi@0: Class C = new Class("C", K); aoqi@0: aoqi@0: assertInvokeVirtualEquals(44, C); aoqi@0: assertInvokeInterfaceEquals(44, C, K); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * interface I { int m() default { return 44; } } aoqi@0: * class C implements I { public int m() { return 55; } } aoqi@0: * aoqi@0: * TEST: C c = new C(); c.m() == 55; aoqi@0: * TEST: I i = new C(); i.m() == 55; aoqi@0: */ aoqi@0: public void testExisting() { aoqi@0: Interface I = new Interface("I", DefaultMethod.std("44")); aoqi@0: Class C = new Class("C", I, ConcreteMethod.std("55")); aoqi@0: aoqi@0: assertInvokeVirtualEquals(55, C); aoqi@0: assertInvokeInterfaceEquals(55, C, I); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * interface I { default int m() { return 99; } } aoqi@0: * class B implements I {} aoqi@0: * class C extends B {} aoqi@0: * aoqi@0: * TEST: C c = new C(); c.m() == 99; aoqi@0: * TEST: I i = new C(); i.m() == 99; aoqi@0: */ aoqi@0: public void testInherited() { aoqi@0: Interface I = new Interface("I", DefaultMethod.std("99")); aoqi@0: Class B = new Class("B", I); aoqi@0: Class C = new Class("C", B); aoqi@0: aoqi@0: assertInvokeVirtualEquals(99, C); aoqi@0: assertInvokeInterfaceEquals(99, C, I); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * interface I { default int m() { return 99; } } aoqi@0: * class C { public int m() { return 11; } } aoqi@0: * class D extends C implements I {} aoqi@0: * aoqi@0: * TEST: D d = new D(); d.m() == 11; aoqi@0: * TEST: I i = new D(); i.m() == 11; aoqi@0: */ aoqi@0: public void testExistingInherited() { aoqi@0: Interface I = new Interface("I", DefaultMethod.std("99")); aoqi@0: Class C = new Class("C", ConcreteMethod.std("11")); aoqi@0: Class D = new Class("D", C, I); aoqi@0: aoqi@0: assertInvokeVirtualEquals(11, D); aoqi@0: assertInvokeInterfaceEquals(11, D, I); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * interface I { default int m() { return 44; } } aoqi@0: * class C implements I { public int m() { return 11; } } aoqi@0: * class D extends C { public int m() { return 22; } } aoqi@0: * aoqi@0: * TEST: D d = new D(); d.m() == 22; aoqi@0: * TEST: I i = new D(); i.m() == 22; aoqi@0: */ aoqi@0: public void testExistingInheritedOverride() { aoqi@0: Interface I = new Interface("I", DefaultMethod.std("99")); aoqi@0: Class C = new Class("C", I, ConcreteMethod.std("11")); aoqi@0: Class D = new Class("D", C, ConcreteMethod.std("22")); aoqi@0: aoqi@0: assertInvokeVirtualEquals(22, D); aoqi@0: assertInvokeInterfaceEquals(22, D, I); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * interface I { default int m() { return 99; } } aoqi@0: * interface J { defaultint m() { return 88; } } aoqi@0: * class C implements I { public int m() { return 11; } } aoqi@0: * class D extends C { public int m() { return 22; } } aoqi@0: * class E extends D implements J {} aoqi@0: * aoqi@0: * TEST: E e = new E(); e.m() == 22; aoqi@0: * TEST: J j = new E(); j.m() == 22; aoqi@0: */ aoqi@0: public void testExistingInheritedPlusDefault() { aoqi@0: Interface I = new Interface("I", DefaultMethod.std("99")); aoqi@0: Interface J = new Interface("J", DefaultMethod.std("88")); aoqi@0: Class C = new Class("C", I, ConcreteMethod.std("11")); aoqi@0: Class D = new Class("D", C, ConcreteMethod.std("22")); aoqi@0: Class E = new Class("E", D, J); aoqi@0: aoqi@0: assertInvokeVirtualEquals(22, E); aoqi@0: assertInvokeInterfaceEquals(22, E, J); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * interface I { default int m() { return 99; } } aoqi@0: * class B implements I {} aoqi@0: * class C extends B { public int m() { return 77; } } aoqi@0: * aoqi@0: * TEST: C c = new C(); c.m() == 77; aoqi@0: * TEST: I i = new C(); i.m() == 77; aoqi@0: */ aoqi@0: public void testInheritedWithConcrete() { aoqi@0: Interface I = new Interface("I", DefaultMethod.std("99")); aoqi@0: Class B = new Class("B", I); aoqi@0: Class C = new Class("C", B, ConcreteMethod.std("77")); aoqi@0: aoqi@0: assertInvokeVirtualEquals(77, C); aoqi@0: assertInvokeInterfaceEquals(77, C, I); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * interface I { default int m() { return 99; } } aoqi@0: * class B implements I {} aoqi@0: * class C extends B implements I { public int m() { return 66; } } aoqi@0: * aoqi@0: * TEST: C c = new C(); c.m() == 66; aoqi@0: * TEST: I i = new C(); i.m() == 66; aoqi@0: */ aoqi@0: public void testInheritedWithConcreteAndImpl() { aoqi@0: Interface I = new Interface("I", DefaultMethod.std("99")); aoqi@0: Class B = new Class("B", I); aoqi@0: Class C = new Class("C", B, I, ConcreteMethod.std("66")); aoqi@0: aoqi@0: assertInvokeVirtualEquals(66, C); aoqi@0: assertInvokeInterfaceEquals(66, C, I); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * interface I { default int m() { return 99; } } aoqi@0: * interface J { default int m() { return 88; } } aoqi@0: * class C implements I, J {} aoqi@0: * aoqi@0: * TEST: C c = new C(); c.m() throws ICCE aoqi@0: */ aoqi@0: public void testConflict() { aoqi@0: Interface I = new Interface("I", DefaultMethod.std("99")); aoqi@0: Interface J = new Interface("J", DefaultMethod.std("88")); aoqi@0: Class C = new Class("C", I, J); aoqi@0: aoqi@0: assertThrows(IncompatibleClassChangeError.class, C); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * interface I { int m(); } aoqi@0: * interface J { default int m() { return 88; } } aoqi@0: * class C implements I, J {} aoqi@0: * aoqi@0: * TEST: C c = new C(); c.m() == 88 aoqi@0: */ aoqi@0: public void testAmbiguousReabstract() { aoqi@0: Interface I = new Interface("I", AbstractMethod.std()); aoqi@0: Interface J = new Interface("J", DefaultMethod.std("88")); aoqi@0: Class C = new Class("C", I, J); aoqi@0: aoqi@0: assertInvokeVirtualEquals(88, C); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * interface I { default int m() { return 99; } } aoqi@0: * interface J extends I { } aoqi@0: * interface K extends I { } aoqi@0: * class C implements J, K {} aoqi@0: * aoqi@0: * TEST: C c = new C(); c.m() == 99 aoqi@0: * TEST: J j = new C(); j.m() == 99 aoqi@0: * TEST: K k = new C(); k.m() == 99 aoqi@0: * TEST: I i = new C(); i.m() == 99 aoqi@0: */ aoqi@0: public void testDiamond() { aoqi@0: Interface I = new Interface("I", DefaultMethod.std("99")); aoqi@0: Interface J = new Interface("J", I); aoqi@0: Interface K = new Interface("K", I); aoqi@0: Class C = new Class("C", J, K); aoqi@0: aoqi@0: assertInvokeVirtualEquals(99, C); aoqi@0: assertInvokeInterfaceEquals(99, C, J); aoqi@0: assertInvokeInterfaceEquals(99, C, K); aoqi@0: assertInvokeInterfaceEquals(99, C, I); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * interface I { default int m() { return 99; } } aoqi@0: * interface J extends I { } aoqi@0: * interface K extends I { } aoqi@0: * interface L extends I { } aoqi@0: * interface M extends I { } aoqi@0: * class C implements I, J, K, L, M {} aoqi@0: * aoqi@0: * TEST: C c = new C(); c.m() == 99 aoqi@0: * TEST: J j = new C(); j.m() == 99 aoqi@0: * TEST: K k = new C(); k.m() == 99 aoqi@0: * TEST: I i = new C(); i.m() == 99 aoqi@0: * TEST: L l = new C(); l.m() == 99 aoqi@0: * TEST: M m = new C(); m.m() == 99 aoqi@0: */ aoqi@0: public void testExpandedDiamond() { aoqi@0: Interface I = new Interface("I", DefaultMethod.std("99")); aoqi@0: Interface J = new Interface("J", I); aoqi@0: Interface K = new Interface("K", I); aoqi@0: Interface L = new Interface("L", I); aoqi@0: Interface M = new Interface("M", L); aoqi@0: Class C = new Class("C", I, J, K, L, M); aoqi@0: aoqi@0: assertInvokeVirtualEquals(99, C); aoqi@0: assertInvokeInterfaceEquals(99, C, J); aoqi@0: assertInvokeInterfaceEquals(99, C, K); aoqi@0: assertInvokeInterfaceEquals(99, C, I); aoqi@0: assertInvokeInterfaceEquals(99, C, L); aoqi@0: assertInvokeInterfaceEquals(99, C, M); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * interface I { int m() default { return 99; } } aoqi@0: * interface J extends I { int m(); } aoqi@0: * class C implements J {} aoqi@0: * aoqi@0: * TEST: C c = new C(); c.m() throws AME aoqi@0: */ aoqi@0: public void testReabstract() { aoqi@0: Interface I = new Interface("I", DefaultMethod.std("99")); aoqi@0: Interface J = new Interface("J", I, AbstractMethod.std()); aoqi@0: Class C = new Class("C", J); aoqi@0: aoqi@0: assertThrows(AbstractMethodError.class, C); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * interface I { default int m() { return 88; } } aoqi@0: * interface J extends I { default int m() { return 99; } } aoqi@0: * class C implements J {} aoqi@0: * aoqi@0: * TEST: C c = new C(); c.m() == 99; aoqi@0: * TEST: J j = new C(); j.m() == 99; aoqi@0: * TEST: I i = new C(); i.m() == 99; aoqi@0: */ aoqi@0: public void testShadow() { aoqi@0: Interface I = new Interface("I", DefaultMethod.std("88")); aoqi@0: Interface J = new Interface("J", I, DefaultMethod.std("99")); aoqi@0: Class C = new Class("C", J); aoqi@0: aoqi@0: assertInvokeVirtualEquals(99, C); aoqi@0: assertInvokeInterfaceEquals(99, C, J); aoqi@0: assertInvokeInterfaceEquals(99, C, I); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * interface I { default int m() { return 88; } } aoqi@0: * interface J extends I { default int m() { return 99; } } aoqi@0: * class C implements I, J {} aoqi@0: * aoqi@0: * TEST: C c = new C(); c.m() == 99; aoqi@0: * TEST: J j = new C(); j.m() == 99; aoqi@0: * TEST: I i = new C(); i.m() == 99; aoqi@0: */ aoqi@0: public void testDisqualified() { aoqi@0: Interface I = new Interface("I", DefaultMethod.std("88")); aoqi@0: Interface J = new Interface("J", I, DefaultMethod.std("99")); aoqi@0: Class C = new Class("C", I, J); aoqi@0: aoqi@0: assertInvokeVirtualEquals(99, C); aoqi@0: assertInvokeInterfaceEquals(99, C, J); aoqi@0: assertInvokeInterfaceEquals(99, C, I); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * interface I { default int m(T t) { return 99; } } aoqi@0: * Class C implements I { public int m(String s) { return 88; } } aoqi@0: * aoqi@0: * TEST: C c = new C(); c.m("string") == 88; aoqi@0: * TEST: I i = new C(); i.m("string") == 88; aoqi@0: */ aoqi@0: public void testSelfFill() { aoqi@0: // This test ensures that a concrete method overrides a default method aoqi@0: // that matches at the language-level, but has a different method aoqi@0: // signature due to erasure. aoqi@0: aoqi@0: DefaultMethod dm = new DefaultMethod( aoqi@0: "int", "m", "return 99;", new MethodParameter("T", "t")); aoqi@0: ConcreteMethod cm = new ConcreteMethod( aoqi@0: "int", "m", "return 88;", AccessFlag.PUBLIC, aoqi@0: new MethodParameter("String", "s")); aoqi@0: aoqi@0: Interface I = new Interface("I", new TypeParameter("T"), dm); aoqi@0: Class C = new Class("C", I.with("String"), cm); aoqi@0: aoqi@0: AbstractMethod pm = new AbstractMethod( aoqi@0: "int", "m", new MethodParameter("T", "t")); aoqi@0: aoqi@0: assertInvokeVirtualEquals(88, C, cm, "-1", "\"string\""); aoqi@0: assertInvokeInterfaceEquals(99, C, I.with("String"), pm, "\"string\""); aoqi@0: aoqi@0: C.setFullCompilation(true); // Force full bridge generation aoqi@0: assertInvokeInterfaceEquals(88, C, I.with("String"), pm, "\"string\""); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * interface I { default int m() { return 99; } } aoqi@0: * class C implements I {} aoqi@0: * aoqi@0: * TEST: C.class.getMethod("m").invoke(new C()) == 99 aoqi@0: */ aoqi@0: public void testReflectCall() { aoqi@0: Interface I = new Interface("I", DefaultMethod.std("99")); aoqi@0: //workaround accessibility issue when loading C with DirectedClassLoader aoqi@0: I.addAccessFlag(AccessFlag.PUBLIC); aoqi@0: Class C = new Class("C", I); aoqi@0: aoqi@0: Compiler.Flags[] flags = this.verbose ? aoqi@0: new Compiler.Flags[] { Compiler.Flags.VERBOSE } : aoqi@0: new Compiler.Flags[] {}; aoqi@0: Compiler compiler = new Compiler(flags); aoqi@0: java.lang.Class cls = null; aoqi@0: try { aoqi@0: cls = compiler.compileAndLoad(C); aoqi@0: } catch (ClassNotFoundException e) { aoqi@0: fail("Could not load class"); aoqi@0: } aoqi@0: aoqi@0: java.lang.reflect.Method method = null; aoqi@0: try { aoqi@0: method = cls.getMethod(stdMethodName); aoqi@0: } catch (NoSuchMethodException e) { aoqi@0: fail("Could not find method in class"); aoqi@0: } aoqi@0: assertNotNull(method); aoqi@0: aoqi@0: Object c = null; aoqi@0: try { aoqi@0: c = cls.newInstance(); aoqi@0: } catch (InstantiationException | IllegalAccessException e) { aoqi@0: fail("Could not create instance of class"); aoqi@0: } aoqi@0: assertNotNull(c); aoqi@0: aoqi@0: Integer res = null; aoqi@0: try { aoqi@0: res = (Integer)method.invoke(c); aoqi@0: } catch (IllegalAccessException | aoqi@0: java.lang.reflect.InvocationTargetException e) { aoqi@0: fail("Could not invoke default instance method"); aoqi@0: } aoqi@0: assertNotNull(res); aoqi@0: aoqi@0: assertEquals(res.intValue(), 99); aoqi@0: aoqi@0: compiler.cleanup(); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * interface I { default int m(T t, V v, W w) { return 99; } } aoqi@0: * interface J extends I { int m(T t, V v, String w); } } aoqi@0: * interface K extends J { int m(T t, String v, String w); } } aoqi@0: * class C implements K { aoqi@0: * public int m(String t, String v, String w) { return 88; } aoqi@0: * } aoqi@0: * aoqi@0: * TEST: I i = new C(); i.m("A","B","C") == 88; aoqi@0: * TEST: J j = new C(); j.m("A","B","C") == 88; aoqi@0: * TEST: K k = new C(); k.m("A","B","C") == 88; aoqi@0: */ aoqi@0: public void testBridges() { aoqi@0: DefaultMethod dm = new DefaultMethod("int", stdMethodName, "return 99;", aoqi@0: new MethodParameter("T", "t"), new MethodParameter("V", "v"), aoqi@0: new MethodParameter("W", "w")); aoqi@0: aoqi@0: AbstractMethod pm0 = new AbstractMethod("int", stdMethodName, aoqi@0: new MethodParameter("T", "t"), new MethodParameter("V", "v"), aoqi@0: new MethodParameter("W", "w")); aoqi@0: aoqi@0: AbstractMethod pm1 = new AbstractMethod("int", stdMethodName, aoqi@0: new MethodParameter("T", "t"), new MethodParameter("V", "v"), aoqi@0: new MethodParameter("String", "w")); aoqi@0: aoqi@0: AbstractMethod pm2 = new AbstractMethod("int", stdMethodName, aoqi@0: new MethodParameter("T", "t"), new MethodParameter("String", "v"), aoqi@0: new MethodParameter("String", "w")); aoqi@0: aoqi@0: ConcreteMethod cm = new ConcreteMethod("int",stdMethodName,"return 88;", aoqi@0: AccessFlag.PUBLIC, aoqi@0: new MethodParameter("String", "t"), aoqi@0: new MethodParameter("String", "v"), aoqi@0: new MethodParameter("String", "w")); aoqi@0: aoqi@0: Interface I = new Interface("I", new TypeParameter("T"), aoqi@0: new TypeParameter("V"), new TypeParameter("W"), dm); aoqi@0: Interface J = new Interface("J", aoqi@0: new TypeParameter("T"), new TypeParameter("V"), aoqi@0: I.with("String", "T", "V"), pm1); aoqi@0: Interface K = new Interface("K", new TypeParameter("T"), aoqi@0: J.with("String", "T"), pm2); aoqi@0: Class C = new Class("C", K.with("String"), cm); aoqi@0: aoqi@0: // First, without compiler bridges aoqi@0: String[] args = new String[] { "\"A\"", "\"B\"", "\"C\"" }; aoqi@0: assertInvokeInterfaceEquals(99, C, I.with("String", "String", "String"), pm0, args); aoqi@0: assertInvokeInterfaceThrows(AbstractMethodError.class, C, J.with("String", "String"), pm1, args); aoqi@0: assertInvokeInterfaceThrows(AbstractMethodError.class, C, K.with("String"), pm2, args); aoqi@0: aoqi@0: // Then with compiler bridges aoqi@0: C.setFullCompilation(true); aoqi@0: assertInvokeInterfaceEquals(88, C, I.with("String", "String", "String"), pm0, args); aoqi@0: assertInvokeInterfaceEquals(88, C, J.with("String", "String"), pm1, args); aoqi@0: assertInvokeInterfaceEquals(88, C, K.with("String"), pm2, args); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * interface J { default int m() { return 88; } } aoqi@0: * interface I extends J { default int m() { return J.super.m(); } } aoqi@0: * class C implements I {} aoqi@0: * aoqi@0: * TEST: C c = new C(); c.m() == 88; aoqi@0: * TEST: I i = new C(); i.m() == 88; aoqi@0: */ aoqi@0: public void testSuperBasic() { aoqi@0: Interface J = new Interface("J", DefaultMethod.std("88")); aoqi@0: Interface I = new Interface("I", J, new DefaultMethod( aoqi@0: "int", stdMethodName, "return J.super.m();")); aoqi@0: I.addCompilationDependency(J.findMethod(stdMethodName)); aoqi@0: Class C = new Class("C", I); aoqi@0: aoqi@0: assertInvokeVirtualEquals(88, C); aoqi@0: assertInvokeInterfaceEquals(88, C, I); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * interface K { int m() default { return 99; } } aoqi@0: * interface L { int m() default { return 101; } } aoqi@0: * interface J extends K, L {} aoqi@0: * interface I extends J, K { int m() default { J.super.m(); } } aoqi@0: * class C implements I {} aoqi@0: * aoqi@0: * TEST: C c = new C(); c.m() throws ICCE aoqi@0: * TODO: add case for K k = new C(); k.m() throws ICCE aoqi@0: */ aoqi@0: public void testSuperConflict() { aoqi@0: Interface K = new Interface("K", DefaultMethod.std("99")); aoqi@0: Interface L = new Interface("L", DefaultMethod.std("101")); aoqi@0: Interface J = new Interface("J", K, L); aoqi@0: Interface I = new Interface("I", J, K, new DefaultMethod( aoqi@0: "int", stdMethodName, "return J.super.m();")); aoqi@0: Interface Jstub = new Interface("J", DefaultMethod.std("-1")); aoqi@0: I.addCompilationDependency(Jstub); aoqi@0: I.addCompilationDependency(Jstub.findMethod(stdMethodName)); aoqi@0: Class C = new Class("C", I); aoqi@0: aoqi@0: assertThrows(IncompatibleClassChangeError.class, C); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * interface I { default int m() { return 99; } } aoqi@0: * interface J extends I { default int m() { return 55; } } aoqi@0: * class C implements I, J { public int m() { return I.super.m(); } } aoqi@0: * aoqi@0: * TEST: C c = new C(); c.m() == 99 aoqi@0: * TODO: add case for J j = new C(); j.m() == ??? aoqi@0: */ aoqi@0: public void testSuperDisqual() { aoqi@0: Interface I = new Interface("I", DefaultMethod.std("99")); aoqi@0: Interface J = new Interface("J", I, DefaultMethod.std("55")); aoqi@0: Class C = new Class("C", I, J, aoqi@0: new ConcreteMethod("int", stdMethodName, "return I.super.m();", aoqi@0: AccessFlag.PUBLIC)); aoqi@0: C.addCompilationDependency(I.findMethod(stdMethodName)); aoqi@0: aoqi@0: assertInvokeVirtualEquals(99, C); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * interface J { int m(); } aoqi@0: * interface I extends J { default int m() { return J.super.m(); } } aoqi@0: * class C implements I {} aoqi@0: * aoqi@0: * TEST: C c = new C(); c.m() throws AME aoqi@0: * TODO: add case for I i = new C(); i.m() throws AME aoqi@0: */ aoqi@0: public void testSuperNull() { aoqi@0: Interface J = new Interface("J", AbstractMethod.std()); aoqi@0: Interface I = new Interface("I", J, new DefaultMethod( aoqi@0: "int", stdMethodName, "return J.super.m();")); aoqi@0: Interface Jstub = new Interface("J", DefaultMethod.std("99")); aoqi@0: I.addCompilationDependency(Jstub); aoqi@0: I.addCompilationDependency(Jstub.findMethod(stdMethodName)); aoqi@0: Class C = new Class("C", I); aoqi@0: aoqi@0: assertThrows(AbstractMethodError.class, C); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * interface J { default int m(T t) { return 88; } } aoqi@0: * interface I extends J { aoqi@0: * int m(String s) default { return J.super.m(); } aoqi@0: * } aoqi@0: * class C implements I {} aoqi@0: * aoqi@0: * TEST: I i = new C(); i.m("") == 88; aoqi@0: */ aoqi@0: public void testSuperGeneric() { aoqi@0: Interface J = new Interface("J", new TypeParameter("T"), aoqi@0: new DefaultMethod("int", stdMethodName, "return 88;", aoqi@0: new MethodParameter("T", "t"))); aoqi@0: Interface I = new Interface("I", J.with("String"), aoqi@0: new DefaultMethod("int", stdMethodName, "return J.super.m(s);", aoqi@0: new MethodParameter("String", "s"))); aoqi@0: I.addCompilationDependency(J.findMethod(stdMethodName)); aoqi@0: Class C = new Class("C", I); aoqi@0: aoqi@0: AbstractMethod pm = new AbstractMethod("int", stdMethodName, aoqi@0: new MethodParameter("String", "s")); aoqi@0: aoqi@0: assertInvokeInterfaceEquals(88, C, new Extends(I), pm, "\"\""); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * interface I { int m(T t) default { return 44; } } aoqi@0: * interface J extends I { int m(String s) default { return 55; } } aoqi@0: * class C implements I, J { aoqi@0: * public int m(String s) { return I.super.m(s); } aoqi@0: * } aoqi@0: * aoqi@0: * TEST: C c = new C(); c.m("string") == 44 aoqi@0: */ aoqi@0: public void testSuperGenericDisqual() { aoqi@0: MethodParameter t = new MethodParameter("T", "t"); aoqi@0: MethodParameter s = new MethodParameter("String", "s"); aoqi@0: aoqi@0: Interface I = new Interface("I", new TypeParameter("T"), aoqi@0: new DefaultMethod("int", stdMethodName, "return 44;", t)); aoqi@0: Interface J = new Interface("J", I.with("String"), aoqi@0: new DefaultMethod("int", stdMethodName, "return 55;", s)); aoqi@0: Class C = new Class("C", I.with("String"), J, aoqi@0: new ConcreteMethod("int", stdMethodName, aoqi@0: "return I.super.m(s);", AccessFlag.PUBLIC, s)); aoqi@0: C.addCompilationDependency(I.findMethod(stdMethodName)); aoqi@0: aoqi@0: assertInvokeVirtualEquals(44, C, aoqi@0: new ConcreteMethod( aoqi@0: "int", stdMethodName, "return -1;", AccessFlag.PUBLIC, s), aoqi@0: "-1", "\"string\""); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * interface I { default Integer m() { return new Integer(88); } } aoqi@0: * class C { Number m() { return new Integer(99); } } aoqi@0: * class D extends C implements I {} aoqi@0: * class S { Object foo() { return (new D()).m(); } // link sig: ()LInteger; aoqi@0: * TEST: S s = new S(); s.foo() == new Integer(99) aoqi@0: */ aoqi@0: public void testCovarBridge() { aoqi@0: Interface I = new Interface("I", new DefaultMethod( aoqi@0: "Integer", "m", "return new Integer(88);")); aoqi@0: Class C = new Class("C", new ConcreteMethod( aoqi@0: "Number", "m", "return new Integer(99);", AccessFlag.PUBLIC)); aoqi@0: Class D = new Class("D", I, C); aoqi@0: aoqi@0: ConcreteMethod DstubMethod = new ConcreteMethod( aoqi@0: "Integer", "m", "return null;", AccessFlag.PUBLIC); aoqi@0: Class Dstub = new Class("D", DstubMethod); aoqi@0: aoqi@0: ConcreteMethod toCall = new ConcreteMethod( aoqi@0: "Object", "foo", "return (new D()).m();", AccessFlag.PUBLIC); aoqi@0: Class S = new Class("S", D, toCall); aoqi@0: S.addCompilationDependency(Dstub); aoqi@0: S.addCompilationDependency(DstubMethod); aoqi@0: aoqi@0: // NEGATIVE test for separate compilation -- dispatches to I, not C aoqi@0: assertInvokeVirtualEquals(88, S, toCall, "null"); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * interface I { default Integer m() { return new Integer(88); } } aoqi@0: * class C { int m() { return 99; } } aoqi@0: * class D extends C implements I {} aoqi@0: * class S { Object foo() { return (new D()).m(); } // link sig: ()LInteger; aoqi@0: * TEST: S s = new S(); s.foo() == new Integer(88) aoqi@0: */ aoqi@0: public void testNoCovarNoBridge() { aoqi@0: Interface I = new Interface("I", new DefaultMethod( aoqi@0: "Integer", "m", "return new Integer(88);")); aoqi@0: Class C = new Class("C", new ConcreteMethod( aoqi@0: "int", "m", "return 99;", AccessFlag.PUBLIC)); aoqi@0: Class D = new Class("D", I, C); aoqi@0: aoqi@0: ConcreteMethod DstubMethod = new ConcreteMethod( aoqi@0: "Integer", "m", "return null;", AccessFlag.PUBLIC); aoqi@0: Class Dstub = new Class("D", DstubMethod); aoqi@0: aoqi@0: ConcreteMethod toCall = new ConcreteMethod( aoqi@0: "Object", "foo", "return (new D()).m();", AccessFlag.PUBLIC); aoqi@0: Class S = new Class("S", D, toCall); aoqi@0: S.addCompilationDependency(Dstub); aoqi@0: S.addCompilationDependency(DstubMethod); aoqi@0: aoqi@0: assertInvokeVirtualEquals(88, S, toCall, "null"); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * interface J { int m(); } aoqi@0: * interface I extends J { default int m() { return 99; } } aoqi@0: * class B implements J {} aoqi@0: * class C extends B implements I {} aoqi@0: * TEST: C c = new C(); c.m() == 99 aoqi@0: * aoqi@0: * The point of this test is that B does not get default method analysis, aoqi@0: * and C does not generate any new miranda methods in the vtable. aoqi@0: * It verifies that default method analysis occurs when mirandas have been aoqi@0: * inherited and the supertypes don't have any overpass methods. aoqi@0: */ aoqi@0: public void testNoNewMiranda() { aoqi@0: Interface J = new Interface("J", AbstractMethod.std()); aoqi@0: Interface I = new Interface("I", J, DefaultMethod.std("99")); aoqi@0: Class B = new Class("B", J); aoqi@0: Class C = new Class("C", B, I); aoqi@0: assertInvokeVirtualEquals(99, C); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * interface I { int m(T t, V v, W w); } aoqi@0: * interface J implements I { int m(T t, V v, String w); } aoqi@0: * interface K implements J { aoqi@0: * int m(T t, String v, String w); { return 99; } } aoqi@0: * class C implements K { aoqi@0: * public int m(Object t, Object v, String w) { return 77; } aoqi@0: * } aoqi@0: * TEST C = new C(); ((I)c).m(Object,Object,Object) == 99 aoqi@0: * TEST C = new C(); ((J)c).m(Object,Object,String) == 77 aoqi@0: * TEST C = new C(); ((K)c).m(Object,String,String) == 99 aoqi@0: * aoqi@0: * Test that a erased-signature-matching method does not implement aoqi@0: * non-language-level matching methods aoqi@0: */ aoqi@0: public void testNonConcreteFill() { aoqi@0: AbstractMethod ipm = new AbstractMethod("int", "m", aoqi@0: new MethodParameter("T", "t"), aoqi@0: new MethodParameter("V", "s"), aoqi@0: new MethodParameter("W", "w")); aoqi@0: Interface I = new Interface("I", aoqi@0: new TypeParameter("T"), aoqi@0: new TypeParameter("V"), aoqi@0: new TypeParameter("W"), ipm); aoqi@0: aoqi@0: AbstractMethod jpm = new AbstractMethod("int", "m", aoqi@0: new MethodParameter("T", "t"), aoqi@0: new MethodParameter("V", "s"), aoqi@0: new MethodParameter("String", "w")); aoqi@0: Interface J = new Interface("J", aoqi@0: new TypeParameter("T"), aoqi@0: new TypeParameter("V"), aoqi@0: I.with("T", "V", "String"), jpm); aoqi@0: aoqi@0: AbstractMethod kpm = new AbstractMethod("int", "m", aoqi@0: new MethodParameter("T", "t"), aoqi@0: new MethodParameter("String", "s"), aoqi@0: new MethodParameter("String", "w")); aoqi@0: DefaultMethod kdm = new DefaultMethod("int", "m", "return 99;", aoqi@0: new MethodParameter("T", "t"), aoqi@0: new MethodParameter("String", "v"), aoqi@0: new MethodParameter("String", "w")); aoqi@0: Interface K = new Interface("K", aoqi@0: new TypeParameter("T"), aoqi@0: J.with("T", "String"), aoqi@0: kdm); aoqi@0: aoqi@0: Class C = new Class("C", aoqi@0: K.with("String"), aoqi@0: new ConcreteMethod("int", "m", "return 77;", aoqi@0: AccessFlag.PUBLIC, aoqi@0: new MethodParameter("Object", "t"), aoqi@0: new MethodParameter("Object", "v"), aoqi@0: new MethodParameter("String", "w"))); aoqi@0: aoqi@0: // First, without compiler bridges aoqi@0: String a = "\"\""; aoqi@0: assertInvokeInterfaceEquals(99, C, K.with("String"), kpm, a, a, a); aoqi@0: assertInvokeInterfaceEquals(77, C, J.with("String", "String"), jpm, a, a, a); aoqi@0: assertInvokeInterfaceThrows(AbstractMethodError.class, C, I.with("String", "String", "String"), ipm, a, a, a); aoqi@0: aoqi@0: // Now, with bridges aoqi@0: J.setFullCompilation(true); aoqi@0: K.setFullCompilation(true); aoqi@0: assertInvokeInterfaceEquals(99, C, K.with("String"), kpm, a, a, a); aoqi@0: assertInvokeInterfaceEquals(77, C, J.with("String", "String"), jpm, a, a, a); aoqi@0: assertInvokeInterfaceEquals(99, C, I.with("String", "String", "String"), ipm, a, a, a); aoqi@0: } aoqi@0: aoqi@0: public void testStrictfpDefault() { aoqi@0: try { aoqi@0: java.lang.Class.forName("org.openjdk.tests.vm.StrictfpDefault"); aoqi@0: } catch (Exception e) { aoqi@0: fail("Could not load class", e); aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: interface StrictfpDefault { aoqi@0: default strictfp void m() {} aoqi@0: }