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