1 /* 2 * Copyright (c) 2015, 2017, 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 // Android-added: package for test. 25 package test.java.lang.invoke.VarHandles; 26 27 import java.lang.invoke.MethodHandle; 28 import java.lang.invoke.MethodHandleInfo; 29 import java.lang.invoke.MethodHandles; 30 import java.lang.invoke.MethodType; 31 import java.lang.invoke.VarHandle; 32 import java.lang.invoke.WrongMethodTypeException; 33 import java.lang.reflect.Method; 34 import java.nio.ReadOnlyBufferException; 35 import java.util.EnumMap; 36 import java.util.HashMap; 37 import java.util.List; 38 import java.util.Map; 39 import java.util.stream.Stream; 40 41 import static java.util.stream.Collectors.toList; 42 import static org.testng.Assert.*; 43 44 abstract class VarHandleBaseTest { 45 static final int ITERS = Integer.getInteger("iters", 1); 46 static final int WEAK_ATTEMPTS = Integer.getInteger("weakAttempts", 10); 47 48 interface ThrowingRunnable { run()49 void run() throws Throwable; 50 } 51 checkUOE(ThrowingRunnable r)52 static void checkUOE(ThrowingRunnable r) { 53 checkWithThrowable(UnsupportedOperationException.class, null, r); 54 } 55 checkUOE(Object message, ThrowingRunnable r)56 static void checkUOE(Object message, ThrowingRunnable r) { 57 checkWithThrowable(UnsupportedOperationException.class, message, r); 58 } 59 checkROBE(ThrowingRunnable r)60 static void checkROBE(ThrowingRunnable r) { 61 checkWithThrowable(ReadOnlyBufferException.class, null, r); 62 } 63 checkROBE(Object message, ThrowingRunnable r)64 static void checkROBE(Object message, ThrowingRunnable r) { 65 checkWithThrowable(ReadOnlyBufferException.class, message, r); 66 } 67 checkIOOBE(ThrowingRunnable r)68 static void checkIOOBE(ThrowingRunnable r) { 69 checkWithThrowable(IndexOutOfBoundsException.class, null, r); 70 } 71 checkIOOBE(Object message, ThrowingRunnable r)72 static void checkIOOBE(Object message, ThrowingRunnable r) { 73 checkWithThrowable(IndexOutOfBoundsException.class, message, r); 74 } 75 checkASE(ThrowingRunnable r)76 static void checkASE(ThrowingRunnable r) { 77 checkWithThrowable(ArrayStoreException.class, null, r); 78 } 79 checkASE(Object message, ThrowingRunnable r)80 static void checkASE(Object message, ThrowingRunnable r) { 81 checkWithThrowable(ArrayStoreException.class, message, r); 82 } 83 checkISE(ThrowingRunnable r)84 static void checkISE(ThrowingRunnable r) { 85 checkWithThrowable(IllegalStateException.class, null, r); 86 } 87 checkISE(Object message, ThrowingRunnable r)88 static void checkISE(Object message, ThrowingRunnable r) { 89 checkWithThrowable(IllegalStateException.class, message, r); 90 } 91 checkIAE(ThrowingRunnable r)92 static void checkIAE(ThrowingRunnable r) { 93 checkWithThrowable(IllegalAccessException.class, null, r); 94 } 95 checkIAE(Object message, ThrowingRunnable r)96 static void checkIAE(Object message, ThrowingRunnable r) { 97 checkWithThrowable(IllegalAccessException.class, message, r); 98 } 99 checkWMTE(ThrowingRunnable r)100 static void checkWMTE(ThrowingRunnable r) { 101 checkWithThrowable(WrongMethodTypeException.class, null, r); 102 } 103 checkWMTE(Object message, ThrowingRunnable r)104 static void checkWMTE(Object message, ThrowingRunnable r) { 105 checkWithThrowable(WrongMethodTypeException.class, message, r); 106 } 107 checkCCE(ThrowingRunnable r)108 static void checkCCE(ThrowingRunnable r) { 109 checkWithThrowable(ClassCastException.class, null, r); 110 } 111 checkCCE(Object message, ThrowingRunnable r)112 static void checkCCE(Object message, ThrowingRunnable r) { 113 checkWithThrowable(ClassCastException.class, message, r); 114 } 115 checkNPE(ThrowingRunnable r)116 static void checkNPE(ThrowingRunnable r) { 117 checkWithThrowable(NullPointerException.class, null, r); 118 } 119 checkNPE(Object message, ThrowingRunnable r)120 static void checkNPE(Object message, ThrowingRunnable r) { 121 checkWithThrowable(NullPointerException.class, message, r); 122 } 123 checkWithThrowable(Class<? extends Throwable> re, Object message, ThrowingRunnable r)124 static void checkWithThrowable(Class<? extends Throwable> re, 125 Object message, 126 ThrowingRunnable r) { 127 Throwable _e = null; 128 try { 129 r.run(); 130 } 131 catch (Throwable e) { 132 _e = e; 133 } 134 message = message == null ? "" : message + ". "; 135 assertNotNull(_e, String.format("%sNo throwable thrown. Expected %s", message, re)); 136 assertTrue(re.isInstance(_e), String.format("%sIncorrect throwable thrown, %s. Expected %s", message, _e, re)); 137 } 138 139 140 enum TestAccessType { 141 GET, 142 SET, 143 COMPARE_AND_SET, 144 COMPARE_AND_EXCHANGE, 145 GET_AND_SET, 146 GET_AND_ADD, 147 GET_AND_BITWISE; 148 } 149 150 enum TestAccessMode { 151 GET(TestAccessType.GET), 152 SET(TestAccessType.SET), 153 GET_VOLATILE(TestAccessType.GET), 154 SET_VOLATILE(TestAccessType.SET), 155 GET_ACQUIRE(TestAccessType.GET), 156 SET_RELEASE(TestAccessType.SET), 157 GET_OPAQUE(TestAccessType.GET), 158 SET_OPAQUE(TestAccessType.SET), 159 COMPARE_AND_SET(TestAccessType.COMPARE_AND_SET), 160 COMPARE_AND_EXCHANGE(TestAccessType.COMPARE_AND_EXCHANGE), 161 COMPARE_AND_EXCHANGE_ACQUIRE(TestAccessType.COMPARE_AND_EXCHANGE), 162 COMPARE_AND_EXCHANGE_RELEASE(TestAccessType.COMPARE_AND_EXCHANGE), 163 WEAK_COMPARE_AND_SET_PLAIN(TestAccessType.COMPARE_AND_SET), 164 WEAK_COMPARE_AND_SET(TestAccessType.COMPARE_AND_SET), 165 WEAK_COMPARE_AND_SET_ACQUIRE(TestAccessType.COMPARE_AND_SET), 166 WEAK_COMPARE_AND_SET_RELEASE(TestAccessType.COMPARE_AND_SET), 167 GET_AND_SET(TestAccessType.GET_AND_SET), 168 GET_AND_SET_ACQUIRE(TestAccessType.GET_AND_SET), 169 GET_AND_SET_RELEASE(TestAccessType.GET_AND_SET), 170 GET_AND_ADD(TestAccessType.GET_AND_ADD), 171 GET_AND_ADD_ACQUIRE(TestAccessType.GET_AND_ADD), 172 GET_AND_ADD_RELEASE(TestAccessType.GET_AND_ADD), 173 GET_AND_BITWISE_OR(TestAccessType.GET_AND_BITWISE), 174 GET_AND_BITWISE_OR_ACQUIRE(TestAccessType.GET_AND_BITWISE), 175 GET_AND_BITWISE_OR_RELEASE(TestAccessType.GET_AND_BITWISE), 176 GET_AND_BITWISE_AND(TestAccessType.GET_AND_BITWISE), 177 GET_AND_BITWISE_AND_ACQUIRE(TestAccessType.GET_AND_BITWISE), 178 GET_AND_BITWISE_AND_RELEASE(TestAccessType.GET_AND_BITWISE), 179 GET_AND_BITWISE_XOR(TestAccessType.GET_AND_BITWISE), 180 GET_AND_BITWISE_XOR_ACQUIRE(TestAccessType.GET_AND_BITWISE), 181 GET_AND_BITWISE_XOR_RELEASE(TestAccessType.GET_AND_BITWISE), 182 ; 183 184 final TestAccessType at; 185 final boolean isPolyMorphicInReturnType; 186 final Class<?> returnType; 187 TestAccessMode(TestAccessType at)188 TestAccessMode(TestAccessType at) { 189 this.at = at; 190 191 try { 192 VarHandle.AccessMode vh_am = toAccessMode(); 193 Method m = VarHandle.class.getMethod(vh_am.methodName(), Object[].class); 194 this.returnType = m.getReturnType(); 195 isPolyMorphicInReturnType = returnType != Object.class; 196 } 197 catch (Exception e) { 198 throw new Error(e); 199 } 200 } 201 isOfType(TestAccessType at)202 boolean isOfType(TestAccessType at) { 203 return this.at == at; 204 } 205 toAccessMode()206 VarHandle.AccessMode toAccessMode() { 207 return VarHandle.AccessMode.valueOf(name()); 208 } 209 } 210 testAccessModes()211 static List<TestAccessMode> testAccessModes() { 212 return Stream.of(TestAccessMode.values()).collect(toList()); 213 } 214 testAccessModesOfType(TestAccessType... ats)215 static List<TestAccessMode> testAccessModesOfType(TestAccessType... ats) { 216 Stream<TestAccessMode> s = Stream.of(TestAccessMode.values()); 217 return s.filter(e -> Stream.of(ats).anyMatch(e::isOfType)) 218 .collect(toList()); 219 } 220 accessModes()221 static List<VarHandle.AccessMode> accessModes() { 222 return Stream.of(VarHandle.AccessMode.values()).collect(toList()); 223 } 224 accessModesOfType(TestAccessType... ats)225 static List<VarHandle.AccessMode> accessModesOfType(TestAccessType... ats) { 226 Stream<TestAccessMode> s = Stream.of(TestAccessMode.values()); 227 return s.filter(e -> Stream.of(ats).anyMatch(e::isOfType)) 228 .map(TestAccessMode::toAccessMode) 229 .collect(toList()); 230 } 231 toMethodHandle(VarHandle vh, TestAccessMode tam, MethodType mt)232 static MethodHandle toMethodHandle(VarHandle vh, TestAccessMode tam, MethodType mt) { 233 return vh.toMethodHandle(tam.toAccessMode()); 234 } 235 findVirtual(VarHandle vh, TestAccessMode tam, MethodType mt)236 static MethodHandle findVirtual(VarHandle vh, TestAccessMode tam, MethodType mt) { 237 MethodHandle mh; 238 try { 239 mh = MethodHandles.publicLookup(). 240 findVirtual(VarHandle.class, 241 tam.toAccessMode().methodName(), 242 mt); 243 } catch (Exception e) { 244 throw new RuntimeException(e); 245 } 246 return bind(vh, mh, mt); 247 } 248 varHandleInvoker(VarHandle vh, TestAccessMode tam, MethodType mt)249 static MethodHandle varHandleInvoker(VarHandle vh, TestAccessMode tam, MethodType mt) { 250 MethodHandle mh = MethodHandles.varHandleInvoker( 251 tam.toAccessMode(), 252 mt); 253 254 return bind(vh, mh, mt); 255 } 256 varHandleExactInvoker(VarHandle vh, TestAccessMode tam, MethodType mt)257 static MethodHandle varHandleExactInvoker(VarHandle vh, TestAccessMode tam, MethodType mt) { 258 MethodHandle mh = MethodHandles.varHandleExactInvoker( 259 tam.toAccessMode(), 260 mt); 261 262 return bind(vh, mh, mt); 263 } 264 bind(VarHandle vh, MethodHandle mh, MethodType emt)265 private static MethodHandle bind(VarHandle vh, MethodHandle mh, MethodType emt) { 266 assertEquals(mh.type(), emt.insertParameterTypes(0, VarHandle.class), 267 "MethodHandle type differs from access mode type"); 268 269 MethodHandleInfo info = MethodHandles.lookup().revealDirect(mh); 270 assertEquals(info.getMethodType(), emt, 271 "MethodHandleInfo method type differs from access mode type"); 272 273 return mh.bindTo(vh); 274 } 275 276 private interface TriFunction<T, U, V, R> { apply(T t, U u, V v)277 R apply(T t, U u, V v); 278 } 279 280 enum VarHandleToMethodHandle { 281 VAR_HANDLE_TO_METHOD_HANDLE( 282 "VarHandle.toMethodHandle", 283 true, 284 VarHandleBaseTest::toMethodHandle), 285 METHOD_HANDLES_LOOKUP_FIND_VIRTUAL( 286 "Lookup.findVirtual", 287 false, 288 VarHandleBaseTest::findVirtual), 289 METHOD_HANDLES_VAR_HANDLE_INVOKER( 290 "MethodHandles.varHandleInvoker", 291 false, 292 VarHandleBaseTest::varHandleInvoker), 293 METHOD_HANDLES_VAR_HANDLE_EXACT_INVOKER( 294 "MethodHandles.varHandleExactInvoker", 295 true, 296 VarHandleBaseTest::varHandleExactInvoker); 297 298 final String desc; 299 final boolean isExact; 300 final TriFunction<VarHandle, TestAccessMode, MethodType, MethodHandle> f; 301 VarHandleToMethodHandle(String desc, boolean isExact, TriFunction<VarHandle, TestAccessMode, MethodType, MethodHandle> f)302 VarHandleToMethodHandle(String desc, boolean isExact, 303 TriFunction<VarHandle, TestAccessMode, MethodType, MethodHandle> f) { 304 this.desc = desc; 305 this.f = f; 306 this.isExact = isExact; 307 } 308 apply(VarHandle vh, TestAccessMode am, MethodType mt)309 MethodHandle apply(VarHandle vh, TestAccessMode am, MethodType mt) { 310 return f.apply(vh, am, mt); 311 } 312 313 @Override toString()314 public String toString() { 315 return desc; 316 } 317 } 318 319 static class Handles { 320 static class AccessModeAndType { 321 final TestAccessMode tam; 322 final MethodType t; 323 AccessModeAndType(TestAccessMode tam, MethodType t)324 public AccessModeAndType(TestAccessMode tam, MethodType t) { 325 this.tam = tam; 326 this.t = t; 327 } 328 329 @Override equals(Object o)330 public boolean equals(Object o) { 331 if (this == o) return true; 332 if (o == null || getClass() != o.getClass()) return false; 333 334 AccessModeAndType x = (AccessModeAndType) o; 335 336 if (tam != x.tam) return false; 337 if (t != null ? !t.equals(x.t) : x.t != null) return false; 338 339 return true; 340 } 341 342 @Override hashCode()343 public int hashCode() { 344 int result = tam != null ? tam.hashCode() : 0; 345 result = 31 * result + (t != null ? t.hashCode() : 0); 346 return result; 347 } 348 } 349 350 final VarHandle vh; 351 final VarHandleToMethodHandle f; 352 final EnumMap<TestAccessMode, MethodType> amToType; 353 final Map<AccessModeAndType, MethodHandle> amToHandle; 354 Handles(VarHandle vh, VarHandleToMethodHandle f)355 Handles(VarHandle vh, VarHandleToMethodHandle f) throws Exception { 356 this.vh = vh; 357 this.f = f; 358 this.amToHandle = new HashMap<>(); 359 360 amToType = new EnumMap<>(TestAccessMode.class); 361 for (TestAccessMode am : testAccessModes()) { 362 amToType.put(am, vh.accessModeType(am.toAccessMode())); 363 } 364 } 365 get(TestAccessMode am)366 MethodHandle get(TestAccessMode am) { 367 return get(am, amToType.get(am)); 368 } 369 get(TestAccessMode am, MethodType mt)370 MethodHandle get(TestAccessMode am, MethodType mt) { 371 AccessModeAndType amt = new AccessModeAndType(am, mt); 372 return amToHandle.computeIfAbsent( 373 amt, k -> f.apply(vh, am, mt)); 374 } 375 getWMTEOOrOther(Class<? extends Throwable> c)376 Class<? extends Throwable> getWMTEOOrOther(Class<? extends Throwable> c) { 377 return f.isExact ? WrongMethodTypeException.class : c; 378 } 379 checkWMTEOrCCE(ThrowingRunnable r)380 void checkWMTEOrCCE(ThrowingRunnable r) { 381 checkWithThrowable(getWMTEOOrOther(ClassCastException.class), null, r); 382 } 383 384 } 385 386 interface AccessTestAction<T> { action(T t)387 void action(T t) throws Throwable; 388 } 389 390 static abstract class AccessTestCase<T> { 391 final String desc; 392 final AccessTestAction<T> ata; 393 final boolean loop; 394 AccessTestCase(String desc, AccessTestAction<T> ata, boolean loop)395 AccessTestCase(String desc, AccessTestAction<T> ata, boolean loop) { 396 this.desc = desc; 397 this.ata = ata; 398 this.loop = loop; 399 } 400 requiresLoop()401 boolean requiresLoop() { 402 return loop; 403 } 404 get()405 abstract T get() throws Exception; 406 testAccess(T t)407 void testAccess(T t) throws Throwable { 408 ata.action(t); 409 } 410 411 @Override toString()412 public String toString() { 413 return desc; 414 } 415 } 416 417 static class VarHandleAccessTestCase extends AccessTestCase<VarHandle> { 418 final VarHandle vh; 419 VarHandleAccessTestCase(String desc, VarHandle vh, AccessTestAction<VarHandle> ata)420 VarHandleAccessTestCase(String desc, VarHandle vh, AccessTestAction<VarHandle> ata) { 421 this(desc, vh, ata, true); 422 } 423 VarHandleAccessTestCase(String desc, VarHandle vh, AccessTestAction<VarHandle> ata, boolean loop)424 VarHandleAccessTestCase(String desc, VarHandle vh, AccessTestAction<VarHandle> ata, boolean loop) { 425 super("VarHandle -> " + desc, ata, loop); 426 this.vh = vh; 427 } 428 429 @Override get()430 VarHandle get() { 431 return vh; 432 } 433 } 434 435 static class MethodHandleAccessTestCase extends AccessTestCase<Handles> { 436 final VarHandle vh; 437 final VarHandleToMethodHandle f; 438 MethodHandleAccessTestCase(String desc, VarHandle vh, VarHandleToMethodHandle f, AccessTestAction<Handles> ata)439 MethodHandleAccessTestCase(String desc, VarHandle vh, VarHandleToMethodHandle f, AccessTestAction<Handles> ata) { 440 this(desc, vh, f, ata, true); 441 } 442 MethodHandleAccessTestCase(String desc, VarHandle vh, VarHandleToMethodHandle f, AccessTestAction<Handles> ata, boolean loop)443 MethodHandleAccessTestCase(String desc, VarHandle vh, VarHandleToMethodHandle f, AccessTestAction<Handles> ata, boolean loop) { 444 super("VarHandle -> " + f.toString() + " -> " + desc, ata, loop); 445 this.vh = vh; 446 this.f = f; 447 } 448 449 @Override get()450 Handles get() throws Exception { 451 return new Handles(vh, f); 452 } 453 } 454 testTypes(VarHandle vh)455 static void testTypes(VarHandle vh) { 456 List<Class<?>> pts = vh.coordinateTypes(); 457 458 for (TestAccessMode accessMode : testAccessModes()) { 459 MethodType amt = vh.accessModeType(accessMode.toAccessMode()); 460 461 assertEquals(amt.parameterList().subList(0, pts.size()), pts); 462 } 463 464 for (TestAccessMode testAccessMode : testAccessModesOfType(TestAccessType.GET)) { 465 MethodType mt = vh.accessModeType(testAccessMode.toAccessMode()); 466 assertEquals(mt.returnType(), vh.varType()); 467 assertEquals(mt.parameterList(), pts); 468 } 469 470 for (TestAccessMode testAccessMode : testAccessModesOfType(TestAccessType.SET)) { 471 MethodType mt = vh.accessModeType(testAccessMode.toAccessMode()); 472 assertEquals(mt.returnType(), void.class); 473 assertEquals(mt.parameterType(mt.parameterCount() - 1), vh.varType()); 474 } 475 476 for (TestAccessMode testAccessMode : testAccessModesOfType(TestAccessType.COMPARE_AND_SET)) { 477 MethodType mt = vh.accessModeType(testAccessMode.toAccessMode()); 478 assertEquals(mt.returnType(), boolean.class); 479 assertEquals(mt.parameterType(mt.parameterCount() - 1), vh.varType()); 480 assertEquals(mt.parameterType(mt.parameterCount() - 2), vh.varType()); 481 } 482 483 for (TestAccessMode testAccessMode : testAccessModesOfType(TestAccessType.COMPARE_AND_EXCHANGE)) { 484 MethodType mt = vh.accessModeType(testAccessMode.toAccessMode()); 485 assertEquals(mt.returnType(), vh.varType()); 486 assertEquals(mt.parameterType(mt.parameterCount() - 1), vh.varType()); 487 assertEquals(mt.parameterType(mt.parameterCount() - 2), vh.varType()); 488 } 489 490 for (TestAccessMode testAccessMode : testAccessModesOfType(TestAccessType.GET_AND_SET, TestAccessType.GET_AND_ADD)) { 491 MethodType mt = vh.accessModeType(testAccessMode.toAccessMode()); 492 assertEquals(mt.returnType(), vh.varType()); 493 assertEquals(mt.parameterType(mt.parameterCount() - 1), vh.varType()); 494 } 495 } 496 } 497