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 /*
  25  * @test
  26  * @run testng/othervm -Diters=20000 VarHandleTestMethodHandleAccessChar
  27  */
  28 
  29 import org.testng.annotations.BeforeClass;
  30 import org.testng.annotations.DataProvider;
  31 import org.testng.annotations.Test;
  32 
  33 import java.lang.invoke.MethodHandles;
  34 import java.lang.invoke.VarHandle;
  35 import java.util.ArrayList;
  36 import java.util.Arrays;
  37 import java.util.List;
  38 
  39 import static org.testng.Assert.*;
  40 
  41 public class VarHandleTestMethodHandleAccessChar extends VarHandleBaseTest {
  42     static final char static_final_v = 'a';
  43 
  44     static char static_v;
  45 
  46     final char final_v = 'a';
  47 
  48     char v;
  49 
  50     VarHandle vhFinalField;
  51 
  52     VarHandle vhField;
  53 
  54     VarHandle vhStaticField;
  55 
  56     VarHandle vhStaticFinalField;
  57 
  58     VarHandle vhArray;
  59 
  60     @BeforeClass
  61     public void setup() throws Exception {
  62         vhFinalField = MethodHandles.lookup().findVarHandle(
  63                 VarHandleTestMethodHandleAccessChar.class, "final_v", char.class);
  64 
  65         vhField = MethodHandles.lookup().findVarHandle(
  66                 VarHandleTestMethodHandleAccessChar.class, "v", char.class);
  67 
  68         vhStaticFinalField = MethodHandles.lookup().findStaticVarHandle(
  69             VarHandleTestMethodHandleAccessChar.class, "static_final_v", char.class);
  70 
  71         vhStaticField = MethodHandles.lookup().findStaticVarHandle(
  72             VarHandleTestMethodHandleAccessChar.class, "static_v", char.class);
  73 
  74         vhArray = MethodHandles.arrayElementVarHandle(char[].class);
  75     }
  76 
  77 
  78     @DataProvider
  79     public Object[][] accessTestCaseProvider() throws Exception {
  80         List<AccessTestCase<?>> cases = new ArrayList<>();
  81 
  82         for (VarHandleToMethodHandle f : VarHandleToMethodHandle.values()) {
  83             cases.add(new MethodHandleAccessTestCase("Instance field",
  84                                                      vhField, f, hs -> testInstanceField(this, hs)));
  85             cases.add(new MethodHandleAccessTestCase("Instance field unsupported",
  86                                                      vhField, f, hs -> testInstanceFieldUnsupported(this, hs),
  87                                                      false));
  88 
  89             cases.add(new MethodHandleAccessTestCase("Static field",
  90                                                      vhStaticField, f, VarHandleTestMethodHandleAccessChar::testStaticField));
  91             cases.add(new MethodHandleAccessTestCase("Static field unsupported",
  92                                                      vhStaticField, f, VarHandleTestMethodHandleAccessChar::testStaticFieldUnsupported,
  93                                                      false));
  94 
  95             cases.add(new MethodHandleAccessTestCase("Array",
  96                                                      vhArray, f, VarHandleTestMethodHandleAccessChar::testArray));
  97             cases.add(new MethodHandleAccessTestCase("Array unsupported",
  98                                                      vhArray, f, VarHandleTestMethodHandleAccessChar::testArrayUnsupported,
  99                                                      false));
 100             cases.add(new MethodHandleAccessTestCase("Array index out of bounds",
 101                                                      vhArray, f, VarHandleTestMethodHandleAccessChar::testArrayIndexOutOfBounds,
 102                                                      false));
 103         }
 104 
 105         // Work around issue with jtreg summary reporting which truncates
 106         // the String result of Object.toString to 30 characters, hence
 107         // the first dummy argument
 108         return cases.stream().map(tc -> new Object[]{tc.toString(), tc}).toArray(Object[][]::new);
 109     }
 110 
 111     @Test(dataProvider = "accessTestCaseProvider")
 112     public <T> void testAccess(String desc, AccessTestCase<T> atc) throws Throwable {
 113         T t = atc.get();
 114         int iters = atc.requiresLoop() ? ITERS : 1;
 115         for (int c = 0; c < iters; c++) {
 116             atc.testAccess(t);
 117         }
 118     }
 119 
 120 
 121     static void testInstanceField(VarHandleTestMethodHandleAccessChar recv, Handles hs) throws Throwable {
 122         // Plain
 123         {
 124             hs.get(TestAccessMode.SET).invokeExact(recv, 'a');
 125             char x = (char) hs.get(TestAccessMode.GET).invokeExact(recv);
 126             assertEquals(x, 'a', "set char value");
 127         }
 128 
 129 
 130         // Volatile
 131         {
 132             hs.get(TestAccessMode.SET_VOLATILE).invokeExact(recv, 'b');
 133             char x = (char) hs.get(TestAccessMode.GET_VOLATILE).invokeExact(recv);
 134             assertEquals(x, 'b', "setVolatile char value");
 135         }
 136 
 137         // Lazy
 138         {
 139             hs.get(TestAccessMode.SET_RELEASE).invokeExact(recv, 'a');
 140             char x = (char) hs.get(TestAccessMode.GET_ACQUIRE).invokeExact(recv);
 141             assertEquals(x, 'a', "setRelease char value");
 142         }
 143 
 144         // Opaque
 145         {
 146             hs.get(TestAccessMode.SET_OPAQUE).invokeExact(recv, 'b');
 147             char x = (char) hs.get(TestAccessMode.GET_OPAQUE).invokeExact(recv);
 148             assertEquals(x, 'b', "setOpaque char value");
 149         }
 150 
 151 
 152     }
 153 
 154     static void testInstanceFieldUnsupported(VarHandleTestMethodHandleAccessChar recv, Handles hs) throws Throwable {
 155         for (TestAccessMode am : testAccessModesOfType(TestAccessType.COMPARE_AND_SET)) {
 156             checkUOE(am, () -> {
 157                 boolean r = (boolean) hs.get(am).invokeExact(recv, 'a', 'b');
 158             });
 159         }
 160 
 161         for (TestAccessMode am : testAccessModesOfType(TestAccessType.COMPARE_AND_EXCHANGE)) {
 162             checkUOE(am, () -> {
 163                 char r = (char) hs.get(am).invokeExact(recv, 'a', 'b');
 164             });
 165         }
 166 
 167         for (TestAccessMode am : testAccessModesOfType(TestAccessType.GET_AND_SET)) {
 168             checkUOE(am, () -> {
 169                 char r = (char) hs.get(am).invokeExact(recv, 'a');
 170             });
 171         }
 172 
 173         for (TestAccessMode am : testAccessModesOfType(TestAccessType.GET_AND_ADD)) {
 174             checkUOE(am, () -> {
 175                 char r = (char) hs.get(am).invokeExact(recv, 'a');
 176             });
 177         }
 178     }
 179 
 180 
 181     static void testStaticField(Handles hs) throws Throwable {
 182         // Plain
 183         {
 184             hs.get(TestAccessMode.SET).invokeExact('a');
 185             char x = (char) hs.get(TestAccessMode.GET).invokeExact();
 186             assertEquals(x, 'a', "set char value");
 187         }
 188 
 189 
 190         // Volatile
 191         {
 192             hs.get(TestAccessMode.SET_VOLATILE).invokeExact('b');
 193             char x = (char) hs.get(TestAccessMode.GET_VOLATILE).invokeExact();
 194             assertEquals(x, 'b', "setVolatile char value");
 195         }
 196 
 197         // Lazy
 198         {
 199             hs.get(TestAccessMode.SET_RELEASE).invokeExact('a');
 200             char x = (char) hs.get(TestAccessMode.GET_ACQUIRE).invokeExact();
 201             assertEquals(x, 'a', "setRelease char value");
 202         }
 203 
 204         // Opaque
 205         {
 206             hs.get(TestAccessMode.SET_OPAQUE).invokeExact('b');
 207             char x = (char) hs.get(TestAccessMode.GET_OPAQUE).invokeExact();
 208             assertEquals(x, 'b', "setOpaque char value");
 209         }
 210 
 211 
 212     }
 213 
 214     static void testStaticFieldUnsupported(Handles hs) throws Throwable {
 215         for (TestAccessMode am : testAccessModesOfType(TestAccessType.COMPARE_AND_SET)) {
 216             checkUOE(am, () -> {
 217                 boolean r = (boolean) hs.get(am).invokeExact('a', 'b');
 218             });
 219         }
 220 
 221         for (TestAccessMode am : testAccessModesOfType(TestAccessType.COMPARE_AND_EXCHANGE)) {
 222             checkUOE(am, () -> {
 223                 char r = (char) hs.get(am).invokeExact('a', 'b');
 224             });
 225         }
 226 
 227         for (TestAccessMode am : testAccessModesOfType(TestAccessType.GET_AND_SET)) {
 228             checkUOE(am, () -> {
 229                 char r = (char) hs.get(am).invokeExact('a');
 230             });
 231         }
 232 
 233         for (TestAccessMode am : testAccessModesOfType(TestAccessType.GET_AND_ADD)) {
 234             checkUOE(am, () -> {
 235                 char r = (char) hs.get(am).invokeExact('a');
 236             });
 237         }
 238     }
 239 
 240 
 241     static void testArray(Handles hs) throws Throwable {
 242         char[] array = new char[10];
 243 
 244         for (int i = 0; i < array.length; i++) {
 245             // Plain
 246             {
 247                 hs.get(TestAccessMode.SET).invokeExact(array, i, 'a');
 248                 char x = (char) hs.get(TestAccessMode.GET).invokeExact(array, i);
 249                 assertEquals(x, 'a', "get char value");
 250             }
 251 
 252 
 253             // Volatile
 254             {
 255                 hs.get(TestAccessMode.SET_VOLATILE).invokeExact(array, i, 'b');
 256                 char x = (char) hs.get(TestAccessMode.GET_VOLATILE).invokeExact(array, i);
 257                 assertEquals(x, 'b', "setVolatile char value");
 258             }
 259 
 260             // Lazy
 261             {
 262                 hs.get(TestAccessMode.SET_RELEASE).invokeExact(array, i, 'a');
 263                 char x = (char) hs.get(TestAccessMode.GET_ACQUIRE).invokeExact(array, i);
 264                 assertEquals(x, 'a', "setRelease char value");
 265             }
 266 
 267             // Opaque
 268             {
 269                 hs.get(TestAccessMode.SET_OPAQUE).invokeExact(array, i, 'b');
 270                 char x = (char) hs.get(TestAccessMode.GET_OPAQUE).invokeExact(array, i);
 271                 assertEquals(x, 'b', "setOpaque char value");
 272             }
 273 
 274 
 275         }
 276     }
 277 
 278     static void testArrayUnsupported(Handles hs) throws Throwable {
 279         char[] array = new char[10];
 280 
 281         final int i = 0;
 282         for (TestAccessMode am : testAccessModesOfType(TestAccessType.COMPARE_AND_SET)) {
 283             checkUOE(am, () -> {
 284                 boolean r = (boolean) hs.get(am).invokeExact(array, i, 'a', 'b');
 285             });
 286         }
 287 
 288         for (TestAccessMode am : testAccessModesOfType(TestAccessType.COMPARE_AND_EXCHANGE)) {
 289             checkUOE(am, () -> {
 290                 char r = (char) hs.get(am).invokeExact(array, i, 'a', 'b');
 291             });
 292         }
 293 
 294         for (TestAccessMode am : testAccessModesOfType(TestAccessType.GET_AND_SET)) {
 295             checkUOE(am, () -> {
 296                 char r = (char) hs.get(am).invokeExact(array, i, 'a');
 297             });
 298         }
 299 
 300         for (TestAccessMode am : testAccessModesOfType(TestAccessType.GET_AND_ADD)) {
 301             checkUOE(am, () -> {
 302                 char o = (char) hs.get(am).invokeExact(array, i, 'a');
 303             });
 304         }
 305     }
 306 
 307     static void testArrayIndexOutOfBounds(Handles hs) throws Throwable {
 308         char[] array = new char[10];
 309 
 310         for (int i : new int[]{-1, Integer.MIN_VALUE, 10, 11, Integer.MAX_VALUE}) {
 311             final int ci = i;
 312 
 313             for (TestAccessMode am : testAccessModesOfType(TestAccessType.GET)) {
 314                 checkIOOBE(am, () -> {
 315                     char x = (char) hs.get(am).invokeExact(array, ci);
 316                 });
 317             }
 318 
 319             for (TestAccessMode am : testAccessModesOfType(TestAccessType.SET)) {
 320                 checkIOOBE(am, () -> {
 321                     hs.get(am).invokeExact(array, ci, 'a');
 322                 });
 323             }
 324 
 325 
 326         }
 327     }
 328 }
 329