001/* 002 * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. 008 * 009 * This code is distributed in the hope that it will be useful, but WITHOUT 010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 011 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 012 * version 2 for more details (a copy is included in the LICENSE file that 013 * accompanied this code). 014 * 015 * You should have received a copy of the GNU General Public License version 016 * 2 along with this work; if not, write to the Free Software Foundation, 017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 018 * 019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 020 * or visit www.oracle.com if you need additional information or have any 021 * questions. 022 */ 023package jdk.internal.jvmci.runtime.test; 024 025import static org.junit.Assert.*; 026 027import java.lang.annotation.*; 028import java.lang.invoke.*; 029import java.lang.reflect.*; 030import java.util.*; 031 032import jdk.internal.jvmci.meta.*; 033 034import org.junit.*; 035 036/** 037 * Tests for {@link ResolvedJavaMethod}. 038 */ 039public class TestResolvedJavaMethod extends MethodUniverse { 040 041 public TestResolvedJavaMethod() { 042 } 043 044 /** 045 * @see ResolvedJavaMethod#getCode() 046 */ 047 @Test 048 public void getCodeTest() { 049 for (Map.Entry<Method, ResolvedJavaMethod> e : methods.entrySet()) { 050 ResolvedJavaMethod m = e.getValue(); 051 byte[] code = m.getCode(); 052 if (code == null) { 053 assertTrue(m.getCodeSize() == 0); 054 } else { 055 if (m.isAbstract()) { 056 assertTrue(code.length == 0); 057 } else if (!m.isNative()) { 058 assertTrue(code.length > 0); 059 } 060 } 061 } 062 } 063 064 /** 065 * @see ResolvedJavaMethod#getCodeSize() 066 */ 067 @Test 068 public void getCodeSizeTest() { 069 for (Map.Entry<Method, ResolvedJavaMethod> e : methods.entrySet()) { 070 ResolvedJavaMethod m = e.getValue(); 071 int codeSize = m.getCodeSize(); 072 if (m.isAbstract()) { 073 assertTrue(codeSize == 0); 074 } else if (!m.isNative()) { 075 assertTrue(codeSize > 0); 076 } 077 } 078 } 079 080 @Test 081 public void getModifiersTest() { 082 for (Map.Entry<Method, ResolvedJavaMethod> e : methods.entrySet()) { 083 ResolvedJavaMethod m = e.getValue(); 084 int expected = e.getKey().getModifiers(); 085 int actual = m.getModifiers(); 086 assertEquals(String.format("%s: 0x%x != 0x%x", m, expected, actual), expected, actual); 087 } 088 for (Map.Entry<Constructor<?>, ResolvedJavaMethod> e : constructors.entrySet()) { 089 ResolvedJavaMethod m = e.getValue(); 090 int expected = e.getKey().getModifiers(); 091 int actual = m.getModifiers(); 092 assertEquals(String.format("%s: 0x%x != 0x%x", m, expected, actual), expected, actual); 093 } 094 } 095 096 /** 097 * @see ResolvedJavaMethod#isClassInitializer() 098 */ 099 @Test 100 public void isClassInitializerTest() { 101 for (Map.Entry<Method, ResolvedJavaMethod> e : methods.entrySet()) { 102 // Class initializers are hidden from reflection 103 ResolvedJavaMethod m = e.getValue(); 104 assertFalse(m.isClassInitializer()); 105 } 106 for (Map.Entry<Constructor<?>, ResolvedJavaMethod> e : constructors.entrySet()) { 107 ResolvedJavaMethod m = e.getValue(); 108 assertFalse(m.isClassInitializer()); 109 } 110 } 111 112 @Test 113 public void isConstructorTest() { 114 for (Map.Entry<Method, ResolvedJavaMethod> e : methods.entrySet()) { 115 ResolvedJavaMethod m = e.getValue(); 116 assertFalse(m.isConstructor()); 117 } 118 for (Map.Entry<Constructor<?>, ResolvedJavaMethod> e : constructors.entrySet()) { 119 ResolvedJavaMethod m = e.getValue(); 120 assertTrue(m.isConstructor()); 121 } 122 } 123 124 @Test 125 public void isSyntheticTest() { 126 for (Map.Entry<Method, ResolvedJavaMethod> e : methods.entrySet()) { 127 ResolvedJavaMethod m = e.getValue(); 128 assertEquals(e.getKey().isSynthetic(), m.isSynthetic()); 129 } 130 for (Map.Entry<Constructor<?>, ResolvedJavaMethod> e : constructors.entrySet()) { 131 ResolvedJavaMethod m = e.getValue(); 132 assertEquals(e.getKey().isSynthetic(), m.isSynthetic()); 133 } 134 } 135 136 @Test 137 public void isBridgeTest() { 138 for (Map.Entry<Method, ResolvedJavaMethod> e : methods.entrySet()) { 139 ResolvedJavaMethod m = e.getValue(); 140 assertEquals(e.getKey().isBridge(), m.isBridge()); 141 } 142 for (Map.Entry<Constructor<?>, ResolvedJavaMethod> e : constructors.entrySet()) { 143 ResolvedJavaMethod m = e.getValue(); 144 assertEquals(false, m.isBridge()); 145 } 146 } 147 148 @Test 149 public void isVarArgsTest() { 150 for (Map.Entry<Method, ResolvedJavaMethod> e : methods.entrySet()) { 151 ResolvedJavaMethod m = e.getValue(); 152 assertEquals(e.getKey().isVarArgs(), m.isVarArgs()); 153 } 154 for (Map.Entry<Constructor<?>, ResolvedJavaMethod> e : constructors.entrySet()) { 155 ResolvedJavaMethod m = e.getValue(); 156 assertEquals(e.getKey().isVarArgs(), m.isVarArgs()); 157 } 158 } 159 160 @Test 161 public void isSynchronizedTest() { 162 for (Map.Entry<Method, ResolvedJavaMethod> e : methods.entrySet()) { 163 ResolvedJavaMethod m = e.getValue(); 164 assertEquals(Modifier.isSynchronized(e.getKey().getModifiers()), m.isSynchronized()); 165 } 166 for (Map.Entry<Constructor<?>, ResolvedJavaMethod> e : constructors.entrySet()) { 167 ResolvedJavaMethod m = e.getValue(); 168 assertEquals(Modifier.isSynchronized(e.getKey().getModifiers()), m.isSynchronized()); 169 } 170 } 171 172 @Test 173 public void canBeStaticallyBoundTest() { 174 for (Map.Entry<Method, ResolvedJavaMethod> e : methods.entrySet()) { 175 ResolvedJavaMethod m = e.getValue(); 176 assertEquals(m.canBeStaticallyBound(), canBeStaticallyBound(e.getKey())); 177 } 178 for (Map.Entry<Constructor<?>, ResolvedJavaMethod> e : constructors.entrySet()) { 179 ResolvedJavaMethod m = e.getValue(); 180 assertEquals(m.canBeStaticallyBound(), canBeStaticallyBound(e.getKey())); 181 } 182 } 183 184 private static boolean canBeStaticallyBound(Member method) { 185 int modifiers = method.getModifiers(); 186 return (Modifier.isFinal(modifiers) || Modifier.isPrivate(modifiers) || Modifier.isStatic(modifiers) || Modifier.isFinal(method.getDeclaringClass().getModifiers())) && 187 !Modifier.isAbstract(modifiers); 188 } 189 190 private static String methodWithExceptionHandlers(String p1, Object o2) { 191 try { 192 return p1.substring(100) + o2.toString(); 193 } catch (IndexOutOfBoundsException e) { 194 e.printStackTrace(); 195 } catch (NullPointerException e) { 196 e.printStackTrace(); 197 } catch (RuntimeException e) { 198 e.printStackTrace(); 199 } 200 return null; 201 } 202 203 @Test 204 public void getExceptionHandlersTest() throws NoSuchMethodException { 205 ResolvedJavaMethod method = metaAccess.lookupJavaMethod(getClass().getDeclaredMethod("methodWithExceptionHandlers", String.class, Object.class)); 206 ExceptionHandler[] handlers = method.getExceptionHandlers(); 207 assertNotNull(handlers); 208 assertEquals(handlers.length, 3); 209 handlers[0].getCatchType().equals(metaAccess.lookupJavaType(IndexOutOfBoundsException.class)); 210 handlers[1].getCatchType().equals(metaAccess.lookupJavaType(NullPointerException.class)); 211 handlers[2].getCatchType().equals(metaAccess.lookupJavaType(RuntimeException.class)); 212 } 213 214 private static String nullPointerExceptionOnFirstLine(Object o, String ignored) { 215 return o.toString() + ignored; 216 } 217 218 @Test 219 public void asStackTraceElementTest() throws NoSuchMethodException { 220 try { 221 nullPointerExceptionOnFirstLine(null, "ignored"); 222 Assert.fail("should not reach here"); 223 } catch (NullPointerException e) { 224 StackTraceElement expected = e.getStackTrace()[0]; 225 ResolvedJavaMethod method = metaAccess.lookupJavaMethod(getClass().getDeclaredMethod("nullPointerExceptionOnFirstLine", Object.class, String.class)); 226 StackTraceElement actual = method.asStackTraceElement(0); 227 assertEquals(expected, actual); 228 } 229 } 230 231 @Test 232 public void getConstantPoolTest() { 233 for (Map.Entry<Method, ResolvedJavaMethod> e : methods.entrySet()) { 234 ResolvedJavaMethod m = e.getValue(); 235 ConstantPool cp = m.getConstantPool(); 236 assertTrue(cp.length() > 0); 237 } 238 } 239 240 @Test(timeout = 1000L) 241 public void getAnnotationTest() throws NoSuchMethodException { 242 ResolvedJavaMethod method = metaAccess.lookupJavaMethod(getClass().getDeclaredMethod("getAnnotationTest")); 243 Test annotation = method.getAnnotation(Test.class); 244 assertNotNull(annotation); 245 assertEquals(1000L, annotation.timeout()); 246 } 247 248 @Test(timeout = 1000L) 249 public void getAnnotationsTest() throws NoSuchMethodException { 250 ResolvedJavaMethod method = metaAccess.lookupJavaMethod(getClass().getDeclaredMethod("getAnnotationsTest")); 251 Annotation[] annotations = method.getAnnotations(); 252 assertNotNull(annotations); 253 assertEquals(1, annotations.length); 254 assertEquals(1000L, ((Test) annotations[0]).timeout()); 255 } 256 257 @Retention(RetentionPolicy.RUNTIME) 258 @Target(ElementType.PARAMETER) 259 @interface NonNull { 260 } 261 262 @Retention(RetentionPolicy.RUNTIME) 263 @Target(ElementType.PARAMETER) 264 @interface Special { 265 } 266 267 private static native void methodWithAnnotatedParameters(@NonNull HashMap<String, String> p1, @Special @NonNull Class<? extends Annotation> p2); 268 269 @Test 270 public void getParameterAnnotationsTest() throws NoSuchMethodException { 271 ResolvedJavaMethod method = metaAccess.lookupJavaMethod(getClass().getDeclaredMethod("methodWithAnnotatedParameters", HashMap.class, Class.class)); 272 Annotation[][] annotations = method.getParameterAnnotations(); 273 assertEquals(2, annotations.length); 274 assertEquals(1, annotations[0].length); 275 assertEquals(NonNull.class, annotations[0][0].annotationType()); 276 assertEquals(2, annotations[1].length); 277 assertEquals(Special.class, annotations[1][0].annotationType()); 278 assertEquals(NonNull.class, annotations[1][1].annotationType()); 279 } 280 281 @Test 282 public void getGenericParameterTypesTest() throws NoSuchMethodException { 283 ResolvedJavaMethod method = metaAccess.lookupJavaMethod(getClass().getDeclaredMethod("methodWithAnnotatedParameters", HashMap.class, Class.class)); 284 Type[] genericParameterTypes = method.getGenericParameterTypes(); 285 assertEquals(2, genericParameterTypes.length); 286 assertEquals("java.util.HashMap<java.lang.String, java.lang.String>", genericParameterTypes[0].toString()); 287 assertEquals("java.lang.Class<? extends java.lang.annotation.Annotation>", genericParameterTypes[1].toString()); 288 } 289 290 @Test 291 public void getMaxLocalsTest() throws NoSuchMethodException { 292 ResolvedJavaMethod method1 = metaAccess.lookupJavaMethod(getClass().getDeclaredMethod("methodWithAnnotatedParameters", HashMap.class, Class.class)); 293 ResolvedJavaMethod method2 = metaAccess.lookupJavaMethod(getClass().getDeclaredMethod("nullPointerExceptionOnFirstLine", Object.class, String.class)); 294 assertEquals(0, method1.getMaxLocals()); 295 assertEquals(2, method2.getMaxLocals()); 296 297 } 298 299 @Test 300 public void getMaxStackSizeTest() throws NoSuchMethodException { 301 ResolvedJavaMethod method1 = metaAccess.lookupJavaMethod(getClass().getDeclaredMethod("methodWithAnnotatedParameters", HashMap.class, Class.class)); 302 ResolvedJavaMethod method2 = metaAccess.lookupJavaMethod(getClass().getDeclaredMethod("nullPointerExceptionOnFirstLine", Object.class, String.class)); 303 assertEquals(0, method1.getMaxStackSize()); 304 // some versions of javac produce bytecode with a stacksize of 2 for this method 305 // JSR 292 also sometimes need one more stack slot 306 int method2StackSize = method2.getMaxStackSize(); 307 assertTrue(2 <= method2StackSize && method2StackSize <= 4); 308 } 309 310 @Test 311 public void isDefaultTest() { 312 for (Map.Entry<Method, ResolvedJavaMethod> e : methods.entrySet()) { 313 ResolvedJavaMethod m = e.getValue(); 314 assertEquals(e.getKey().isDefault(), m.isDefault()); 315 } 316 for (Map.Entry<Constructor<?>, ResolvedJavaMethod> e : constructors.entrySet()) { 317 ResolvedJavaMethod m = e.getValue(); 318 assertFalse(m.isDefault()); 319 } 320 } 321 322 @Test 323 public void hasReceiverTest() { 324 for (Map.Entry<Method, ResolvedJavaMethod> e : methods.entrySet()) { 325 ResolvedJavaMethod m = e.getValue(); 326 assertTrue(m.hasReceiver() != Modifier.isStatic(e.getKey().getModifiers())); 327 } 328 for (Map.Entry<Constructor<?>, ResolvedJavaMethod> e : constructors.entrySet()) { 329 ResolvedJavaMethod m = e.getValue(); 330 assertTrue(m.hasReceiver()); 331 } 332 } 333 334 @Test 335 public void hasBytecodesTest() { 336 for (Map.Entry<Method, ResolvedJavaMethod> e : methods.entrySet()) { 337 ResolvedJavaMethod m = e.getValue(); 338 assertTrue(m.hasBytecodes() == (m.isConcrete() && !m.isNative())); 339 } 340 for (Map.Entry<Constructor<?>, ResolvedJavaMethod> e : constructors.entrySet()) { 341 ResolvedJavaMethod m = e.getValue(); 342 assertTrue(m.hasBytecodes()); 343 } 344 } 345 346 @Test 347 public void isJavaLangObjectInitTest() throws NoSuchMethodException { 348 ResolvedJavaMethod method = metaAccess.lookupJavaMethod(Object.class.getConstructor()); 349 assertTrue(method.isJavaLangObjectInit()); 350 for (Map.Entry<Method, ResolvedJavaMethod> e : methods.entrySet()) { 351 ResolvedJavaMethod m = e.getValue(); 352 assertFalse(m.isJavaLangObjectInit()); 353 } 354 for (Map.Entry<Constructor<?>, ResolvedJavaMethod> e : constructors.entrySet()) { 355 ResolvedJavaMethod m = e.getValue(); 356 Constructor<?> key = e.getKey(); 357 if (key.getDeclaringClass() == Object.class && key.getParameters().length == 0) { 358 assertTrue(m.isJavaLangObjectInit()); 359 } else { 360 assertFalse(m.isJavaLangObjectInit()); 361 } 362 } 363 } 364 365 @Test 366 public void isSignaturePolymorphicTest() { 367 ResolvedJavaType methodHandleType = metaAccess.lookupJavaType(MethodHandle.class); 368 assertTrue(ResolvedJavaMethod.isSignaturePolymorphic(methodHandleType, "invokeExact", metaAccess)); 369 assertTrue(ResolvedJavaMethod.isSignaturePolymorphic(methodHandleType, "invoke", metaAccess)); 370 assertTrue(ResolvedJavaMethod.isSignaturePolymorphic(methodHandleType, "invokeBasic", metaAccess)); 371 assertTrue(ResolvedJavaMethod.isSignaturePolymorphic(methodHandleType, "linkToVirtual", metaAccess)); 372 assertTrue(ResolvedJavaMethod.isSignaturePolymorphic(methodHandleType, "linkToStatic", metaAccess)); 373 assertTrue(ResolvedJavaMethod.isSignaturePolymorphic(methodHandleType, "linkToSpecial", metaAccess)); 374 assertTrue(ResolvedJavaMethod.isSignaturePolymorphic(methodHandleType, "linkToInterface", metaAccess)); 375 assertFalse(ResolvedJavaMethod.isSignaturePolymorphic(methodHandleType, "type", metaAccess)); 376 assertFalse(ResolvedJavaMethod.isSignaturePolymorphic(metaAccess.lookupJavaType(Object.class), "toString", metaAccess)); 377 } 378 379 private Method findTestMethod(Method apiMethod) { 380 String testName = apiMethod.getName() + "Test"; 381 for (Method m : getClass().getDeclaredMethods()) { 382 if (m.getName().equals(testName) && m.getAnnotation(Test.class) != null) { 383 return m; 384 } 385 } 386 return null; 387 } 388 389 // @formatter:off 390 private static final String[] untestedApiMethods = { 391 "invoke", 392 "newInstance", 393 "getDeclaringClass", 394 "getEncoding", 395 "getProfilingInfo", 396 "reprofile", 397 "getCompilerStorage", 398 "canBeInlined", 399 "shouldBeInlined", 400 "getLineNumberTable", 401 "getLocalVariableTable", 402 "isInVirtualMethodTable", 403 "toParameterTypes", 404 "getParameterAnnotation", 405 "getSpeculationLog", 406 "isFinal", 407 "$jacocoInit" 408 }; 409 // @formatter:on 410 411 /** 412 * Ensures that any new methods added to {@link ResolvedJavaMethod} either have a test written 413 * for them or are added to {@link #untestedApiMethods}. 414 */ 415 @Test 416 public void testCoverage() { 417 Set<String> known = new HashSet<>(Arrays.asList(untestedApiMethods)); 418 for (Method m : ResolvedJavaMethod.class.getDeclaredMethods()) { 419 if (Modifier.isStatic(m.getModifiers())) { 420 continue; 421 } 422 if (findTestMethod(m) == null) { 423 assertTrue("test missing for " + m, known.contains(m.getName())); 424 } else { 425 assertFalse("test should be removed from untestedApiMethods" + m, known.contains(m.getName())); 426 } 427 } 428 } 429}