1 /* 2 * Copyright (c) 2015, 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 /* 25 * @test 26 * @bug 8136421 27 * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" 28 * @library / /testlibrary /../../test/lib 29 * @compile ../common/CompilerToVMHelper.java 30 * @build compiler.jvmci.compilerToVM.GetVtableIndexForInterfaceTest 31 * @run main ClassFileInstaller 32 * jdk.vm.ci.hotspot.CompilerToVMHelper 33 * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockExperimentalVMOptions 34 * -XX:+EnableJVMCI compiler.jvmci.compilerToVM.GetVtableIndexForInterfaceTest 35 */ 36 37 package compiler.jvmci.compilerToVM; 38 39 import compiler.jvmci.common.testcases.AbstractClass; 40 import compiler.jvmci.common.testcases.DoNotExtendClass; 41 import compiler.jvmci.common.testcases.MultipleAbstractImplementer; 42 import compiler.jvmci.common.testcases.MultipleImplementersInterface; 43 import compiler.jvmci.common.testcases.MultipleImplementersInterfaceExtender; 44 import compiler.jvmci.common.testcases.SingleImplementer; 45 import compiler.jvmci.common.testcases.SingleImplementerInterface; 46 import compiler.jvmci.common.testcases.SingleSubclass; 47 import compiler.jvmci.common.testcases.SingleSubclassedClass; 48 import compiler.jvmci.common.CTVMUtilities; 49 import compiler.jvmci.common.testcases.AnotherSingleImplementer; 50 import compiler.jvmci.common.testcases.AnotherSingleImplementerInterface; 51 import java.lang.reflect.Method; 52 import java.util.HashSet; 53 import java.util.Set; 54 import java.util.stream.Stream; 55 import jdk.vm.ci.hotspot.CompilerToVMHelper; 56 import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethodImpl; 57 import jdk.vm.ci.hotspot.HotSpotResolvedObjectTypeImpl; 58 import jdk.test.lib.Asserts; 59 import jdk.test.lib.Utils; 60 61 public class GetVtableIndexForInterfaceTest { 62 private static final int INVALID_VTABLE_INDEX = -4; // see method.hpp: VtableIndexFlag 63 64 public static void main(String args[]) { 65 GetVtableIndexForInterfaceTest test 66 = new GetVtableIndexForInterfaceTest(); 67 try { 68 for (TestCase tcase : createTestCases()) { 69 test.runTest(tcase); 70 } 71 } catch (NoSuchMethodException e) { 72 throw new Error("TEST BUG: can't find requested method", e); 73 } 74 } 75 76 private static Set<TestCase> createTestCases() { 77 Set<TestCase> result = new HashSet<>(); 78 Stream.of( 79 AbstractClass.class, 80 SingleImplementer.class, 81 SingleImplementerInterface.class, 82 MultipleImplementersInterface.class, 83 MultipleImplementersInterfaceExtender.class, 84 SingleSubclass.class, 85 SingleSubclassedClass.class, 86 DoNotExtendClass.class, 87 MultipleAbstractImplementer.class 88 ) 89 .forEach(Utils::ensureClassIsLoaded); 90 // non iface method 91 result.add(new TestCase(SingleImplementer.class, 92 SingleImplementer.class, "nonInterfaceMethod", 93 false, InternalError.class)); 94 // iface method w/o default implementation 95 result.add(new TestCase(SingleImplementer.class, 96 SingleImplementerInterface.class, "interfaceMethod", false)); 97 /* another iface which provides default implementation for the 98 original iface*/ 99 result.add(new TestCase(MultipleImplementersInterfaceExtender.class, 100 MultipleImplementersInterface.class, "testMethod", false, 101 InternalError.class)); 102 // iface method w/ default implementation 103 result.add(new TestCase(SingleImplementer.class, 104 SingleImplementerInterface.class, "defaultMethod", true)); 105 // non iface class 106 result.add(new TestCase(SingleSubclass.class, 107 SingleSubclassedClass.class, "inheritedMethod", false, 108 InternalError.class)); 109 // class not implementing iface 110 result.add(new TestCase(DoNotExtendClass.class, 111 SingleImplementerInterface.class, "defaultMethod", false)); 112 // abstract class which doesn't implement iface 113 result.add(new TestCase(AbstractClass.class, 114 SingleImplementerInterface.class, "defaultMethod", false)); 115 // abstract class which implements iface 116 result.add(new TestCase(MultipleAbstractImplementer.class, 117 MultipleImplementersInterface.class, "defaultMethod", true)); 118 // class not initialized 119 result.add(new TestCase(AnotherSingleImplementer.class, 120 AnotherSingleImplementerInterface.class, "defaultMethod", 121 false, InternalError.class)); 122 return result; 123 } 124 125 private void runTest(TestCase tcase) throws NoSuchMethodException { 126 System.out.println(tcase); 127 Method method = tcase.holder.getDeclaredMethod(tcase.methodName); 128 HotSpotResolvedObjectTypeImpl metaspaceKlass = CompilerToVMHelper 129 .lookupType(Utils.toJVMTypeSignature(tcase.receiver), 130 getClass(), /* resolve = */ true); 131 HotSpotResolvedJavaMethodImpl metaspaceMethod = CTVMUtilities 132 .getResolvedMethod(tcase.holder, method); 133 int index = 0; 134 try { 135 index = CompilerToVMHelper 136 .getVtableIndexForInterfaceMethod(metaspaceKlass, 137 metaspaceMethod); 138 } catch (Throwable t) { 139 if (tcase.isPositive || tcase.expectedException == null) { 140 throw new Error("Caught unexpected exception " + t); 141 } 142 if (!tcase.expectedException.equals(t.getClass())) { 143 throw new Error(String.format("Caught %s while expected %s", 144 t.getClass().getName(), 145 tcase.expectedException.getName())); 146 } 147 return; 148 } 149 if (tcase.expectedException != null) { 150 throw new AssertionError("Expected exception wasn't caught: " 151 + tcase.expectedException.getName()); 152 } 153 if (tcase.isPositive) { 154 Asserts.assertNE(index, INVALID_VTABLE_INDEX, 155 "Unexpected: got invalid index"); 156 } else { 157 Asserts.assertEQ(index, INVALID_VTABLE_INDEX, 158 "Unexpected: got valid index "); 159 } 160 } 161 162 private static class TestCase { 163 public final Class<?> receiver; 164 public final Class<?> holder; 165 public final String methodName; 166 public final boolean isPositive; 167 public final Class<? extends Throwable> expectedException; 168 169 public TestCase(Class<?> receiver, Class<?> holder, String methodName, 170 boolean isPositive, 171 Class<? extends Throwable> expectedException) { 172 this.receiver = receiver; 173 this.holder = holder; 174 this.methodName = methodName; 175 this.isPositive = isPositive; 176 this.expectedException = expectedException; 177 } 178 179 public TestCase(Class<?> receiver, Class<?> holder, String methodName, 180 boolean isPositive) { 181 this(receiver, holder, methodName, isPositive, null); 182 } 183 184 @Override 185 public String toString() { 186 return String.format("CASE: receiver=%s, holder=%s, method=%s," 187 + " isPositive=%s%n", receiver.getName(), holder.getName(), 188 methodName, isPositive); 189 } 190 } 191 }