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