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