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