1 /* 2 * Copyright (c) 2012, 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 * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" 27 * @compile TestResolvedJavaMethod.java MethodUniverse.java TypeUniverse.java TestMetaAccessProvider.java 28 * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.vm.ci.runtime.test.TestResolvedJavaMethod 29 */ 30 31 package jdk.vm.ci.runtime.test; 32 33 import static org.junit.Assert.assertEquals; 34 import static org.junit.Assert.assertFalse; 35 import static org.junit.Assert.assertNotNull; 36 import static org.junit.Assert.assertTrue; 37 38 import java.lang.annotation.Annotation; 39 import java.lang.annotation.ElementType; 40 import java.lang.annotation.Retention; 41 import java.lang.annotation.RetentionPolicy; 42 import java.lang.annotation.Target; 43 import java.lang.invoke.MethodHandle; 44 import java.lang.reflect.Constructor; 45 import java.lang.reflect.Member; 46 import java.lang.reflect.Method; 47 import java.lang.reflect.Modifier; 48 import java.lang.reflect.Type; 49 import java.util.Arrays; 50 import java.util.HashMap; 51 import java.util.HashSet; 52 import java.util.Map; 53 import java.util.Set; 54 55 import jdk.vm.ci.meta.ConstantPool; 56 import jdk.vm.ci.meta.ExceptionHandler; 57 import jdk.vm.ci.meta.ResolvedJavaMethod; 58 import jdk.vm.ci.meta.ResolvedJavaType; 59 60 import org.junit.Assert; 61 import org.junit.Test; 62 63 /** 64 * Tests for {@link ResolvedJavaMethod}. 65 */ 66 public class TestResolvedJavaMethod extends MethodUniverse { 67 68 public TestResolvedJavaMethod() { 69 } 70 71 /** 72 * @see ResolvedJavaMethod#getCode() 73 */ 74 @Test 75 public void getCodeTest() { 76 for (Map.Entry<Method, ResolvedJavaMethod> e : methods.entrySet()) { 77 ResolvedJavaMethod m = e.getValue(); 78 byte[] code = m.getCode(); 79 if (code == null) { 80 assertTrue(m.getCodeSize() == 0); 81 } else { 82 if (m.isAbstract()) { 83 assertTrue(code.length == 0); 84 } else if (!m.isNative()) { 85 assertTrue(code.length > 0); 86 } 87 } 88 } 89 } 90 91 /** 92 * @see ResolvedJavaMethod#getCodeSize() 93 */ 94 @Test 95 public void getCodeSizeTest() { 96 for (Map.Entry<Method, ResolvedJavaMethod> e : methods.entrySet()) { 97 ResolvedJavaMethod m = e.getValue(); 98 int codeSize = m.getCodeSize(); 99 if (m.isAbstract()) { 100 assertTrue(codeSize == 0); 101 } else if (!m.isNative()) { 102 assertTrue(codeSize > 0); 103 } 104 } 105 } 106 107 @Test 108 public void getModifiersTest() { 109 for (Map.Entry<Method, ResolvedJavaMethod> e : methods.entrySet()) { 110 ResolvedJavaMethod m = e.getValue(); 111 int expected = e.getKey().getModifiers(); 112 int actual = m.getModifiers(); 113 assertEquals(String.format("%s: 0x%x != 0x%x", m, expected, actual), expected, actual); 114 } 115 for (Map.Entry<Constructor<?>, ResolvedJavaMethod> e : constructors.entrySet()) { 116 ResolvedJavaMethod m = e.getValue(); 117 int expected = e.getKey().getModifiers(); 118 int actual = m.getModifiers(); 119 assertEquals(String.format("%s: 0x%x != 0x%x", m, expected, actual), expected, actual); 120 } 121 } 122 123 /** 124 * @see ResolvedJavaMethod#isClassInitializer() 125 */ 126 @Test 127 public void isClassInitializerTest() { 128 for (Map.Entry<Method, ResolvedJavaMethod> e : methods.entrySet()) { 129 // Class initializers are hidden from reflection 130 ResolvedJavaMethod m = e.getValue(); 131 assertFalse(m.isClassInitializer()); 132 } 133 for (Map.Entry<Constructor<?>, ResolvedJavaMethod> e : constructors.entrySet()) { 134 ResolvedJavaMethod m = e.getValue(); 135 assertFalse(m.isClassInitializer()); 136 } 137 } 138 139 @Test 140 public void isConstructorTest() { 141 for (Map.Entry<Method, ResolvedJavaMethod> e : methods.entrySet()) { 142 ResolvedJavaMethod m = e.getValue(); 143 assertFalse(m.isConstructor()); 144 } 145 for (Map.Entry<Constructor<?>, ResolvedJavaMethod> e : constructors.entrySet()) { 146 ResolvedJavaMethod m = e.getValue(); 147 assertTrue(m.isConstructor()); 148 } 149 } 150 151 @Test 152 public void isSyntheticTest() { 153 for (Map.Entry<Method, ResolvedJavaMethod> e : methods.entrySet()) { 154 ResolvedJavaMethod m = e.getValue(); 155 assertEquals(e.getKey().isSynthetic(), m.isSynthetic()); 156 } 157 for (Map.Entry<Constructor<?>, ResolvedJavaMethod> e : constructors.entrySet()) { 158 ResolvedJavaMethod m = e.getValue(); 159 assertEquals(e.getKey().isSynthetic(), m.isSynthetic()); 160 } 161 } 162 163 @Test 164 public void isBridgeTest() { 165 for (Map.Entry<Method, ResolvedJavaMethod> e : methods.entrySet()) { 166 ResolvedJavaMethod m = e.getValue(); 167 assertEquals(e.getKey().isBridge(), m.isBridge()); 168 } 169 for (Map.Entry<Constructor<?>, ResolvedJavaMethod> e : constructors.entrySet()) { 170 ResolvedJavaMethod m = e.getValue(); 171 assertEquals(false, m.isBridge()); 172 } 173 } 174 175 @Test 176 public void isVarArgsTest() { 177 for (Map.Entry<Method, ResolvedJavaMethod> e : methods.entrySet()) { 178 ResolvedJavaMethod m = e.getValue(); 179 assertEquals(e.getKey().isVarArgs(), m.isVarArgs()); 180 } 181 for (Map.Entry<Constructor<?>, ResolvedJavaMethod> e : constructors.entrySet()) { 182 ResolvedJavaMethod m = e.getValue(); 183 assertEquals(e.getKey().isVarArgs(), m.isVarArgs()); 184 } 185 } 186 187 @Test 188 public void isSynchronizedTest() { 189 for (Map.Entry<Method, ResolvedJavaMethod> e : methods.entrySet()) { 190 ResolvedJavaMethod m = e.getValue(); 191 assertEquals(Modifier.isSynchronized(e.getKey().getModifiers()), m.isSynchronized()); 192 } 193 for (Map.Entry<Constructor<?>, ResolvedJavaMethod> e : constructors.entrySet()) { 194 ResolvedJavaMethod m = e.getValue(); 195 assertEquals(Modifier.isSynchronized(e.getKey().getModifiers()), m.isSynchronized()); 196 } 197 } 198 199 @Test 200 public void canBeStaticallyBoundTest() { 201 for (Map.Entry<Method, ResolvedJavaMethod> e : methods.entrySet()) { 202 ResolvedJavaMethod m = e.getValue(); 203 assertEquals(m.canBeStaticallyBound(), canBeStaticallyBound(e.getKey())); 204 } 205 for (Map.Entry<Constructor<?>, ResolvedJavaMethod> e : constructors.entrySet()) { 206 ResolvedJavaMethod m = e.getValue(); 207 assertEquals(m.canBeStaticallyBound(), canBeStaticallyBound(e.getKey())); 208 } 209 } 210 211 private static boolean canBeStaticallyBound(Member method) { 212 int modifiers = method.getModifiers(); 213 return (Modifier.isFinal(modifiers) || Modifier.isPrivate(modifiers) || Modifier.isStatic(modifiers) || Modifier.isFinal(method.getDeclaringClass().getModifiers())) && 214 !Modifier.isAbstract(modifiers); 215 } 216 217 private static String methodWithExceptionHandlers(String p1, Object o2) { 218 try { 219 return p1.substring(100) + o2.toString(); 220 } catch (IndexOutOfBoundsException e) { 221 e.printStackTrace(); 222 } catch (NullPointerException e) { 223 e.printStackTrace(); 224 } catch (RuntimeException e) { 225 e.printStackTrace(); 226 } 227 return null; 228 } 229 230 @Test 231 public void getExceptionHandlersTest() throws NoSuchMethodException { 232 ResolvedJavaMethod method = metaAccess.lookupJavaMethod(getClass().getDeclaredMethod("methodWithExceptionHandlers", String.class, Object.class)); 233 ExceptionHandler[] handlers = method.getExceptionHandlers(); 234 assertNotNull(handlers); 235 assertEquals(handlers.length, 3); 236 handlers[0].getCatchType().equals(metaAccess.lookupJavaType(IndexOutOfBoundsException.class)); 237 handlers[1].getCatchType().equals(metaAccess.lookupJavaType(NullPointerException.class)); 238 handlers[2].getCatchType().equals(metaAccess.lookupJavaType(RuntimeException.class)); 239 } 240 241 private static String nullPointerExceptionOnFirstLine(Object o, String ignored) { 242 return o.toString() + ignored; 243 } 244 245 @Test 246 public void asStackTraceElementTest() throws NoSuchMethodException { 247 try { 248 nullPointerExceptionOnFirstLine(null, "ignored"); 249 Assert.fail("should not reach here"); 250 } catch (NullPointerException e) { 251 StackTraceElement expected = e.getStackTrace()[0]; 252 ResolvedJavaMethod method = metaAccess.lookupJavaMethod(getClass().getDeclaredMethod("nullPointerExceptionOnFirstLine", Object.class, String.class)); 253 StackTraceElement actual = method.asStackTraceElement(0); 254 assertEquals(expected, actual); 255 } 256 } 257 258 @Test 259 public void getConstantPoolTest() { 260 for (Map.Entry<Method, ResolvedJavaMethod> e : methods.entrySet()) { 261 ResolvedJavaMethod m = e.getValue(); 262 ConstantPool cp = m.getConstantPool(); 263 assertTrue(cp.length() > 0); 264 } 265 } 266 267 @Test(timeout = 1000L) 268 public void getAnnotationTest() throws NoSuchMethodException { 269 ResolvedJavaMethod method = metaAccess.lookupJavaMethod(getClass().getDeclaredMethod("getAnnotationTest")); 270 Test annotation = method.getAnnotation(Test.class); 271 assertNotNull(annotation); 272 assertEquals(1000L, annotation.timeout()); 273 } 274 275 @Test(timeout = 1000L) 276 public void getAnnotationsTest() throws NoSuchMethodException { 277 ResolvedJavaMethod method = metaAccess.lookupJavaMethod(getClass().getDeclaredMethod("getAnnotationsTest")); 278 Annotation[] annotations = method.getAnnotations(); 279 assertNotNull(annotations); 280 assertEquals(1, annotations.length); 281 assertEquals(1000L, ((Test) annotations[0]).timeout()); 282 } 283 284 @Retention(RetentionPolicy.RUNTIME) 285 @Target(ElementType.PARAMETER) 286 @interface NonNull { 287 } 288 289 @Retention(RetentionPolicy.RUNTIME) 290 @Target(ElementType.PARAMETER) 291 @interface Special { 292 } 293 294 private static native void methodWithAnnotatedParameters(@NonNull HashMap<String, String> p1, @Special @NonNull Class<? extends Annotation> p2); 295 296 @Test 297 public void getParameterAnnotationsTest() throws NoSuchMethodException { 298 ResolvedJavaMethod method = metaAccess.lookupJavaMethod(getClass().getDeclaredMethod("methodWithAnnotatedParameters", HashMap.class, Class.class)); 299 Annotation[][] annotations = method.getParameterAnnotations(); 300 assertEquals(2, annotations.length); 301 assertEquals(1, annotations[0].length); 302 assertEquals(NonNull.class, annotations[0][0].annotationType()); 303 assertEquals(2, annotations[1].length); 304 assertEquals(Special.class, annotations[1][0].annotationType()); 305 assertEquals(NonNull.class, annotations[1][1].annotationType()); 306 } 307 308 @Test 309 public void getGenericParameterTypesTest() throws NoSuchMethodException { 310 ResolvedJavaMethod method = metaAccess.lookupJavaMethod(getClass().getDeclaredMethod("methodWithAnnotatedParameters", HashMap.class, Class.class)); 311 Type[] genericParameterTypes = method.getGenericParameterTypes(); 312 assertEquals(2, genericParameterTypes.length); 313 assertEquals("java.util.HashMap<java.lang.String, java.lang.String>", genericParameterTypes[0].toString()); 314 assertEquals("java.lang.Class<? extends java.lang.annotation.Annotation>", genericParameterTypes[1].toString()); 315 } 316 317 @Test 318 public void getMaxLocalsTest() throws NoSuchMethodException { 319 ResolvedJavaMethod method1 = metaAccess.lookupJavaMethod(getClass().getDeclaredMethod("methodWithAnnotatedParameters", HashMap.class, Class.class)); 320 ResolvedJavaMethod method2 = metaAccess.lookupJavaMethod(getClass().getDeclaredMethod("nullPointerExceptionOnFirstLine", Object.class, String.class)); 321 assertEquals(0, method1.getMaxLocals()); 322 assertEquals(2, method2.getMaxLocals()); 323 324 } 325 326 @Test 327 public void getMaxStackSizeTest() throws NoSuchMethodException { 328 ResolvedJavaMethod method1 = metaAccess.lookupJavaMethod(getClass().getDeclaredMethod("methodWithAnnotatedParameters", HashMap.class, Class.class)); 329 ResolvedJavaMethod method2 = metaAccess.lookupJavaMethod(getClass().getDeclaredMethod("nullPointerExceptionOnFirstLine", Object.class, String.class)); 330 assertEquals(0, method1.getMaxStackSize()); 331 // some versions of javac produce bytecode with a stacksize of 2 for this method 332 // JSR 292 also sometimes need one more stack slot 333 int method2StackSize = method2.getMaxStackSize(); 334 assertTrue(2 <= method2StackSize && method2StackSize <= 4); 335 } 336 337 @Test 338 public void isDefaultTest() { 339 for (Map.Entry<Method, ResolvedJavaMethod> e : methods.entrySet()) { 340 ResolvedJavaMethod m = e.getValue(); 341 assertEquals(e.getKey().isDefault(), m.isDefault()); 342 } 343 for (Map.Entry<Constructor<?>, ResolvedJavaMethod> e : constructors.entrySet()) { 344 ResolvedJavaMethod m = e.getValue(); 345 assertFalse(m.isDefault()); 346 } 347 } 348 349 @Test 350 public void hasReceiverTest() { 351 for (Map.Entry<Method, ResolvedJavaMethod> e : methods.entrySet()) { 352 ResolvedJavaMethod m = e.getValue(); 353 assertTrue(m.hasReceiver() != Modifier.isStatic(e.getKey().getModifiers())); 354 } 355 for (Map.Entry<Constructor<?>, ResolvedJavaMethod> e : constructors.entrySet()) { 356 ResolvedJavaMethod m = e.getValue(); 357 assertTrue(m.hasReceiver()); 358 } 359 } 360 361 @Test 362 public void hasBytecodesTest() { 363 for (Map.Entry<Method, ResolvedJavaMethod> e : methods.entrySet()) { 364 ResolvedJavaMethod m = e.getValue(); 365 assertTrue(m.hasBytecodes() == (m.isConcrete() && !m.isNative())); 366 } 367 for (Map.Entry<Constructor<?>, ResolvedJavaMethod> e : constructors.entrySet()) { 368 ResolvedJavaMethod m = e.getValue(); 369 assertTrue(m.hasBytecodes()); 370 } 371 } 372 373 @Test 374 public void isJavaLangObjectInitTest() throws NoSuchMethodException { 375 ResolvedJavaMethod method = metaAccess.lookupJavaMethod(Object.class.getConstructor()); 376 assertTrue(method.isJavaLangObjectInit()); 377 for (Map.Entry<Method, ResolvedJavaMethod> e : methods.entrySet()) { 378 ResolvedJavaMethod m = e.getValue(); 379 assertFalse(m.isJavaLangObjectInit()); 380 } 381 for (Map.Entry<Constructor<?>, ResolvedJavaMethod> e : constructors.entrySet()) { 382 ResolvedJavaMethod m = e.getValue(); 383 Constructor<?> key = e.getKey(); 384 if (key.getDeclaringClass() == Object.class && key.getParameters().length == 0) { 385 assertTrue(m.isJavaLangObjectInit()); 386 } else { 387 assertFalse(m.isJavaLangObjectInit()); 388 } 389 } 390 } 391 392 @Test 393 public void isSignaturePolymorphicTest() { 394 ResolvedJavaType methodHandleType = metaAccess.lookupJavaType(MethodHandle.class); 395 assertTrue(ResolvedJavaMethod.isSignaturePolymorphic(methodHandleType, "invokeExact", metaAccess)); 396 assertTrue(ResolvedJavaMethod.isSignaturePolymorphic(methodHandleType, "invoke", metaAccess)); 397 assertTrue(ResolvedJavaMethod.isSignaturePolymorphic(methodHandleType, "invokeBasic", metaAccess)); 398 assertTrue(ResolvedJavaMethod.isSignaturePolymorphic(methodHandleType, "linkToVirtual", metaAccess)); 399 assertTrue(ResolvedJavaMethod.isSignaturePolymorphic(methodHandleType, "linkToStatic", metaAccess)); 400 assertTrue(ResolvedJavaMethod.isSignaturePolymorphic(methodHandleType, "linkToSpecial", metaAccess)); 401 assertTrue(ResolvedJavaMethod.isSignaturePolymorphic(methodHandleType, "linkToInterface", metaAccess)); 402 assertFalse(ResolvedJavaMethod.isSignaturePolymorphic(methodHandleType, "type", metaAccess)); 403 assertFalse(ResolvedJavaMethod.isSignaturePolymorphic(metaAccess.lookupJavaType(Object.class), "toString", metaAccess)); 404 } 405 406 private Method findTestMethod(Method apiMethod) { 407 String testName = apiMethod.getName() + "Test"; 408 for (Method m : getClass().getDeclaredMethods()) { 409 if (m.getName().equals(testName) && m.getAnnotation(Test.class) != null) { 410 return m; 411 } 412 } 413 return null; 414 } 415 416 // @formatter:off 417 private static final String[] untestedApiMethods = { 418 "invoke", 419 "newInstance", 420 "getDeclaringClass", 421 "getEncoding", 422 "getProfilingInfo", 423 "reprofile", 424 "getCompilerStorage", 425 "canBeInlined", 426 "shouldBeInlined", 427 "getLineNumberTable", 428 "getLocalVariableTable", 429 "isInVirtualMethodTable", 430 "toParameterTypes", 431 "getParameterAnnotation", 432 "getSpeculationLog", 433 "isFinal", 434 "$jacocoInit" 435 }; 436 // @formatter:on 437 438 /** 439 * Ensures that any new methods added to {@link ResolvedJavaMethod} either have a test written 440 * for them or are added to {@link #untestedApiMethods}. 441 */ 442 @Test 443 public void testCoverage() { 444 Set<String> known = new HashSet<>(Arrays.asList(untestedApiMethods)); 445 for (Method m : ResolvedJavaMethod.class.getDeclaredMethods()) { 446 if (Modifier.isStatic(m.getModifiers())) { 447 continue; 448 } 449 if (findTestMethod(m) == null) { 450 assertTrue("test missing for " + m, known.contains(m.getName())); 451 } else { 452 assertFalse("test should be removed from untestedApiMethods" + m, known.contains(m.getName())); 453 } 454 } 455 } 456 }