1 /*
   2  * Copyright (c) 2015, 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=10    -Xint                   VarHandleTestAccessDouble
  27  * @run testng/othervm -Diters=20000 -XX:TieredStopAtLevel=1 VarHandleTestAccessDouble
  28  * @run testng/othervm -Diters=20000                         VarHandleTestAccessDouble
  29  * @run testng/othervm -Diters=20000 -XX:-TieredCompilation  VarHandleTestAccessDouble
  30  */
  31 
  32 import org.testng.annotations.BeforeClass;
  33 import org.testng.annotations.DataProvider;
  34 import org.testng.annotations.Test;
  35 
  36 import java.lang.invoke.MethodHandles;
  37 import java.lang.invoke.VarHandle;
  38 import java.util.ArrayList;
  39 import java.util.Arrays;
  40 import java.util.List;
  41 
  42 import static org.testng.Assert.*;
  43 
  44 public class VarHandleTestAccessDouble extends VarHandleBaseTest {
  45     static final double static_final_v = 1.0d;
  46 
  47     static double static_v;
  48 
  49     final double final_v = 1.0d;
  50 
  51     double v;
  52 
  53     VarHandle vhFinalField;
  54 
  55     VarHandle vhField;
  56 
  57     VarHandle vhStaticField;
  58 
  59     VarHandle vhStaticFinalField;
  60 
  61     VarHandle vhArray;
  62 
  63     @BeforeClass
  64     public void setup() throws Exception {
  65         vhFinalField = MethodHandles.lookup().findVarHandle(
  66                 VarHandleTestAccessDouble.class, "final_v", double.class);
  67 
  68         vhField = MethodHandles.lookup().findVarHandle(
  69                 VarHandleTestAccessDouble.class, "v", double.class);
  70 
  71         vhStaticFinalField = MethodHandles.lookup().findStaticVarHandle(
  72             VarHandleTestAccessDouble.class, "static_final_v", double.class);
  73 
  74         vhStaticField = MethodHandles.lookup().findStaticVarHandle(
  75             VarHandleTestAccessDouble.class, "static_v", double.class);
  76 
  77         vhArray = MethodHandles.arrayElementVarHandle(double[].class);
  78     }
  79 
  80 
  81     @DataProvider
  82     public Object[][] varHandlesProvider() throws Exception {
  83         List<VarHandle> vhs = new ArrayList<>();
  84         vhs.add(vhField);
  85         vhs.add(vhStaticField);
  86         vhs.add(vhArray);
  87 
  88         return vhs.stream().map(tc -> new Object[]{tc}).toArray(Object[][]::new);
  89     }
  90 
  91     @Test(dataProvider = "varHandlesProvider")
  92     public void testIsAccessModeSupported(VarHandle vh) {
  93         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.GET));
  94         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.SET));
  95         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.GET_VOLATILE));
  96         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.SET_VOLATILE));
  97         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.GET_ACQUIRE));
  98         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.SET_RELEASE));
  99         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.GET_OPAQUE));
 100         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.SET_OPAQUE));
 101 
 102         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_SET));
 103         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_VOLATILE));
 104         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE));
 105         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE));
 106         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET));
 107         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE));
 108         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE));
 109         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_SET));
 110 
 111         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_ADD));
 112         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.ADD_AND_GET));
 113     }
 114 
 115 
 116     @DataProvider
 117     public Object[][] typesProvider() throws Exception {
 118         List<Object[]> types = new ArrayList<>();
 119         types.add(new Object[] {vhField, Arrays.asList(VarHandleTestAccessDouble.class)});
 120         types.add(new Object[] {vhStaticField, Arrays.asList()});
 121         types.add(new Object[] {vhArray, Arrays.asList(double[].class, int.class)});
 122 
 123         return types.stream().toArray(Object[][]::new);
 124     }
 125 
 126     @Test(dataProvider = "typesProvider")
 127     public void testTypes(VarHandle vh, List<Class<?>> pts) {
 128         assertEquals(vh.varType(), double.class);
 129 
 130         assertEquals(vh.coordinateTypes(), pts);
 131 
 132         testTypes(vh);
 133     }
 134 
 135 
 136     @Test
 137     public void testLookupInstanceToStatic() {
 138         checkIAE("Lookup of static final field to instance final field", () -> {
 139             MethodHandles.lookup().findStaticVarHandle(
 140                     VarHandleTestAccessDouble.class, "final_v", double.class);
 141         });
 142 
 143         checkIAE("Lookup of static field to instance field", () -> {
 144             MethodHandles.lookup().findStaticVarHandle(
 145                     VarHandleTestAccessDouble.class, "v", double.class);
 146         });
 147     }
 148 
 149     @Test
 150     public void testLookupStaticToInstance() {
 151         checkIAE("Lookup of instance final field to static final field", () -> {
 152             MethodHandles.lookup().findVarHandle(
 153                 VarHandleTestAccessDouble.class, "static_final_v", double.class);
 154         });
 155 
 156         checkIAE("Lookup of instance field to static field", () -> {
 157             vhStaticField = MethodHandles.lookup().findVarHandle(
 158                 VarHandleTestAccessDouble.class, "static_v", double.class);
 159         });
 160     }
 161 
 162 
 163     @DataProvider
 164     public Object[][] accessTestCaseProvider() throws Exception {
 165         List<AccessTestCase<?>> cases = new ArrayList<>();
 166 
 167         cases.add(new VarHandleAccessTestCase("Instance final field",
 168                                               vhFinalField, vh -> testInstanceFinalField(this, vh)));
 169         cases.add(new VarHandleAccessTestCase("Instance final field unsupported",
 170                                               vhFinalField, vh -> testInstanceFinalFieldUnsupported(this, vh),
 171                                               false));
 172 
 173         cases.add(new VarHandleAccessTestCase("Static final field",
 174                                               vhStaticFinalField, VarHandleTestAccessDouble::testStaticFinalField));
 175         cases.add(new VarHandleAccessTestCase("Static final field unsupported",
 176                                               vhStaticFinalField, VarHandleTestAccessDouble::testStaticFinalFieldUnsupported,
 177                                               false));
 178 
 179         cases.add(new VarHandleAccessTestCase("Instance field",
 180                                               vhField, vh -> testInstanceField(this, vh)));
 181         cases.add(new VarHandleAccessTestCase("Instance field unsupported",
 182                                               vhField, vh -> testInstanceFieldUnsupported(this, vh),
 183                                               false));
 184 
 185         cases.add(new VarHandleAccessTestCase("Static field",
 186                                               vhStaticField, VarHandleTestAccessDouble::testStaticField));
 187         cases.add(new VarHandleAccessTestCase("Static field unsupported",
 188                                               vhStaticField, VarHandleTestAccessDouble::testStaticFieldUnsupported,
 189                                               false));
 190 
 191         cases.add(new VarHandleAccessTestCase("Array",
 192                                               vhArray, VarHandleTestAccessDouble::testArray));
 193         cases.add(new VarHandleAccessTestCase("Array unsupported",
 194                                               vhArray, VarHandleTestAccessDouble::testArrayUnsupported,
 195                                               false));
 196         cases.add(new VarHandleAccessTestCase("Array index out of bounds",
 197                                               vhArray, VarHandleTestAccessDouble::testArrayIndexOutOfBounds,
 198                                               false));
 199 
 200         // Work around issue with jtreg summary reporting which truncates
 201         // the String result of Object.toString to 30 characters, hence
 202         // the first dummy argument
 203         return cases.stream().map(tc -> new Object[]{tc.toString(), tc}).toArray(Object[][]::new);
 204     }
 205 
 206     @Test(dataProvider = "accessTestCaseProvider")
 207     public <T> void testAccess(String desc, AccessTestCase<T> atc) throws Throwable {
 208         T t = atc.get();
 209         int iters = atc.requiresLoop() ? ITERS : 1;
 210         for (int c = 0; c < iters; c++) {
 211             atc.testAccess(t);
 212         }
 213     }
 214 
 215 
 216 
 217 
 218     static void testInstanceFinalField(VarHandleTestAccessDouble recv, VarHandle vh) {
 219         // Plain
 220         {
 221             double x = (double) vh.get(recv);
 222             assertEquals(x, 1.0d, "get double value");
 223         }
 224 
 225 
 226         // Volatile
 227         {
 228             double x = (double) vh.getVolatile(recv);
 229             assertEquals(x, 1.0d, "getVolatile double value");
 230         }
 231 
 232         // Lazy
 233         {
 234             double x = (double) vh.getAcquire(recv);
 235             assertEquals(x, 1.0d, "getRelease double value");
 236         }
 237 
 238         // Opaque
 239         {
 240             double x = (double) vh.getOpaque(recv);
 241             assertEquals(x, 1.0d, "getOpaque double value");
 242         }
 243     }
 244 
 245     static void testInstanceFinalFieldUnsupported(VarHandleTestAccessDouble recv, VarHandle vh) {
 246         checkUOE(() -> {
 247             vh.set(recv, 2.0d);
 248         });
 249 
 250         checkUOE(() -> {
 251             vh.setVolatile(recv, 2.0d);
 252         });
 253 
 254         checkUOE(() -> {
 255             vh.setRelease(recv, 2.0d);
 256         });
 257 
 258         checkUOE(() -> {
 259             vh.setOpaque(recv, 2.0d);
 260         });
 261 
 262         checkUOE(() -> {
 263             boolean r = vh.compareAndSet(recv, 1.0d, 2.0d);
 264         });
 265 
 266         checkUOE(() -> {
 267             double r = (double) vh.compareAndExchangeVolatile(recv, 1.0d, 2.0d);
 268         });
 269 
 270         checkUOE(() -> {
 271             double r = (double) vh.compareAndExchangeAcquire(recv, 1.0d, 2.0d);
 272         });
 273 
 274         checkUOE(() -> {
 275             double r = (double) vh.compareAndExchangeRelease(recv, 1.0d, 2.0d);
 276         });
 277 
 278         checkUOE(() -> {
 279             boolean r = vh.weakCompareAndSet(recv, 1.0d, 2.0d);
 280         });
 281 
 282         checkUOE(() -> {
 283             boolean r = vh.weakCompareAndSetAcquire(recv, 1.0d, 2.0d);
 284         });
 285 
 286         checkUOE(() -> {
 287             boolean r = vh.weakCompareAndSetRelease(recv, 1.0d, 2.0d);
 288         });
 289 
 290         checkUOE(() -> {
 291             double o = (double) vh.getAndAdd(recv, 1.0d);
 292         });
 293 
 294         checkUOE(() -> {
 295             double o = (double) vh.addAndGet(recv, 1.0d);
 296         });
 297     }
 298 
 299 
 300     static void testStaticFinalField(VarHandle vh) {
 301         // Plain
 302         {
 303             double x = (double) vh.get();
 304             assertEquals(x, 1.0d, "get double value");
 305         }
 306 
 307 
 308         // Volatile
 309         {
 310             double x = (double) vh.getVolatile();
 311             assertEquals(x, 1.0d, "getVolatile double value");
 312         }
 313 
 314         // Lazy
 315         {
 316             double x = (double) vh.getAcquire();
 317             assertEquals(x, 1.0d, "getRelease double value");
 318         }
 319 
 320         // Opaque
 321         {
 322             double x = (double) vh.getOpaque();
 323             assertEquals(x, 1.0d, "getOpaque double value");
 324         }
 325     }
 326 
 327     static void testStaticFinalFieldUnsupported(VarHandle vh) {
 328         checkUOE(() -> {
 329             vh.set(2.0d);
 330         });
 331 
 332         checkUOE(() -> {
 333             vh.setVolatile(2.0d);
 334         });
 335 
 336         checkUOE(() -> {
 337             vh.setRelease(2.0d);
 338         });
 339 
 340         checkUOE(() -> {
 341             vh.setOpaque(2.0d);
 342         });
 343 
 344         checkUOE(() -> {
 345             boolean r = vh.compareAndSet(1.0d, 2.0d);
 346         });
 347 
 348         checkUOE(() -> {
 349             double r = (double) vh.compareAndExchangeVolatile(1.0d, 2.0d);
 350         });
 351 
 352         checkUOE(() -> {
 353             double r = (double) vh.compareAndExchangeAcquire(1.0d, 2.0d);
 354         });
 355 
 356         checkUOE(() -> {
 357             double r = (double) vh.compareAndExchangeRelease(1.0d, 2.0d);
 358         });
 359 
 360         checkUOE(() -> {
 361             boolean r = vh.weakCompareAndSet(1.0d, 2.0d);
 362         });
 363 
 364         checkUOE(() -> {
 365             boolean r = vh.weakCompareAndSetAcquire(1.0d, 2.0d);
 366         });
 367 
 368         checkUOE(() -> {
 369             boolean r = vh.weakCompareAndSetRelease(1.0d, 2.0d);
 370         });
 371 
 372         checkUOE(() -> {
 373             double o = (double) vh.getAndAdd(1.0d);
 374         });
 375 
 376         checkUOE(() -> {
 377             double o = (double) vh.addAndGet(1.0d);
 378         });
 379     }
 380 
 381 
 382     static void testInstanceField(VarHandleTestAccessDouble recv, VarHandle vh) {
 383         // Plain
 384         {
 385             vh.set(recv, 1.0d);
 386             double x = (double) vh.get(recv);
 387             assertEquals(x, 1.0d, "set double value");
 388         }
 389 
 390 
 391         // Volatile
 392         {
 393             vh.setVolatile(recv, 2.0d);
 394             double x = (double) vh.getVolatile(recv);
 395             assertEquals(x, 2.0d, "setVolatile double value");
 396         }
 397 
 398         // Lazy
 399         {
 400             vh.setRelease(recv, 1.0d);
 401             double x = (double) vh.getAcquire(recv);
 402             assertEquals(x, 1.0d, "setRelease double value");
 403         }
 404 
 405         // Opaque
 406         {
 407             vh.setOpaque(recv, 2.0d);
 408             double x = (double) vh.getOpaque(recv);
 409             assertEquals(x, 2.0d, "setOpaque double value");
 410         }
 411 
 412 
 413     }
 414 
 415     static void testInstanceFieldUnsupported(VarHandleTestAccessDouble recv, VarHandle vh) {
 416         checkUOE(() -> {
 417             boolean r = vh.compareAndSet(recv, 1.0d, 2.0d);
 418         });
 419 
 420         checkUOE(() -> {
 421             double r = (double) vh.compareAndExchangeVolatile(recv, 1.0d, 2.0d);
 422         });
 423 
 424         checkUOE(() -> {
 425             double r = (double) vh.compareAndExchangeAcquire(recv, 1.0d, 2.0d);
 426         });
 427 
 428         checkUOE(() -> {
 429             double r = (double) vh.compareAndExchangeRelease(recv, 1.0d, 2.0d);
 430         });
 431 
 432         checkUOE(() -> {
 433             boolean r = vh.weakCompareAndSet(recv, 1.0d, 2.0d);
 434         });
 435 
 436         checkUOE(() -> {
 437             boolean r = vh.weakCompareAndSetAcquire(recv, 1.0d, 2.0d);
 438         });
 439 
 440         checkUOE(() -> {
 441             boolean r = vh.weakCompareAndSetRelease(recv, 1.0d, 2.0d);
 442         });
 443 
 444         checkUOE(() -> {
 445             double o = (double) vh.getAndAdd(recv, 1.0d);
 446         });
 447 
 448         checkUOE(() -> {
 449             double o = (double) vh.addAndGet(recv, 1.0d);
 450         });
 451     }
 452 
 453 
 454     static void testStaticField(VarHandle vh) {
 455         // Plain
 456         {
 457             vh.set(1.0d);
 458             double x = (double) vh.get();
 459             assertEquals(x, 1.0d, "set double value");
 460         }
 461 
 462 
 463         // Volatile
 464         {
 465             vh.setVolatile(2.0d);
 466             double x = (double) vh.getVolatile();
 467             assertEquals(x, 2.0d, "setVolatile double value");
 468         }
 469 
 470         // Lazy
 471         {
 472             vh.setRelease(1.0d);
 473             double x = (double) vh.getAcquire();
 474             assertEquals(x, 1.0d, "setRelease double value");
 475         }
 476 
 477         // Opaque
 478         {
 479             vh.setOpaque(2.0d);
 480             double x = (double) vh.getOpaque();
 481             assertEquals(x, 2.0d, "setOpaque double value");
 482         }
 483 
 484 
 485     }
 486 
 487     static void testStaticFieldUnsupported(VarHandle vh) {
 488         checkUOE(() -> {
 489             boolean r = vh.compareAndSet(1.0d, 2.0d);
 490         });
 491 
 492         checkUOE(() -> {
 493             double r = (double) vh.compareAndExchangeVolatile(1.0d, 2.0d);
 494         });
 495 
 496         checkUOE(() -> {
 497             double r = (double) vh.compareAndExchangeAcquire(1.0d, 2.0d);
 498         });
 499 
 500         checkUOE(() -> {
 501             double r = (double) vh.compareAndExchangeRelease(1.0d, 2.0d);
 502         });
 503 
 504         checkUOE(() -> {
 505             boolean r = vh.weakCompareAndSet(1.0d, 2.0d);
 506         });
 507 
 508         checkUOE(() -> {
 509             boolean r = vh.weakCompareAndSetAcquire(1.0d, 2.0d);
 510         });
 511 
 512         checkUOE(() -> {
 513             boolean r = vh.weakCompareAndSetRelease(1.0d, 2.0d);
 514         });
 515 
 516         checkUOE(() -> {
 517             double o = (double) vh.getAndAdd(1.0d);
 518         });
 519 
 520         checkUOE(() -> {
 521             double o = (double) vh.addAndGet(1.0d);
 522         });
 523     }
 524 
 525 
 526     static void testArray(VarHandle vh) {
 527         double[] array = new double[10];
 528 
 529         for (int i = 0; i < array.length; i++) {
 530             // Plain
 531             {
 532                 vh.set(array, i, 1.0d);
 533                 double x = (double) vh.get(array, i);
 534                 assertEquals(x, 1.0d, "get double value");
 535             }
 536 
 537 
 538             // Volatile
 539             {
 540                 vh.setVolatile(array, i, 2.0d);
 541                 double x = (double) vh.getVolatile(array, i);
 542                 assertEquals(x, 2.0d, "setVolatile double value");
 543             }
 544 
 545             // Lazy
 546             {
 547                 vh.setRelease(array, i, 1.0d);
 548                 double x = (double) vh.getAcquire(array, i);
 549                 assertEquals(x, 1.0d, "setRelease double value");
 550             }
 551 
 552             // Opaque
 553             {
 554                 vh.setOpaque(array, i, 2.0d);
 555                 double x = (double) vh.getOpaque(array, i);
 556                 assertEquals(x, 2.0d, "setOpaque double value");
 557             }
 558 
 559 
 560         }
 561     }
 562 
 563     static void testArrayUnsupported(VarHandle vh) {
 564         double[] array = new double[10];
 565 
 566         int i = 0;
 567         checkUOE(() -> {
 568             boolean r = vh.compareAndSet(array, i, 1.0d, 2.0d);
 569         });
 570 
 571         checkUOE(() -> {
 572             double r = (double) vh.compareAndExchangeVolatile(array, i, 1.0d, 2.0d);
 573         });
 574 
 575         checkUOE(() -> {
 576             double r = (double) vh.compareAndExchangeAcquire(array, i, 1.0d, 2.0d);
 577         });
 578 
 579         checkUOE(() -> {
 580             double r = (double) vh.compareAndExchangeRelease(array, i, 1.0d, 2.0d);
 581         });
 582 
 583         checkUOE(() -> {
 584             boolean r = vh.weakCompareAndSet(array, i, 1.0d, 2.0d);
 585         });
 586 
 587         checkUOE(() -> {
 588             boolean r = vh.weakCompareAndSetAcquire(array, i, 1.0d, 2.0d);
 589         });
 590 
 591         checkUOE(() -> {
 592             boolean r = vh.weakCompareAndSetRelease(array, i, 1.0d, 2.0d);
 593         });
 594 
 595         checkUOE(() -> {
 596             double o = (double) vh.getAndAdd(array, i, 1.0d);
 597         });
 598 
 599         checkUOE(() -> {
 600             double o = (double) vh.addAndGet(array, i, 1.0d);
 601         });
 602     }
 603 
 604     static void testArrayIndexOutOfBounds(VarHandle vh) throws Throwable {
 605         double[] array = new double[10];
 606 
 607         for (int i : new int[]{-1, Integer.MIN_VALUE, 10, 11, Integer.MAX_VALUE}) {
 608             final int ci = i;
 609 
 610             checkIOOBE(() -> {
 611                 double x = (double) vh.get(array, ci);
 612             });
 613 
 614             checkIOOBE(() -> {
 615                 vh.set(array, ci, 1.0d);
 616             });
 617 
 618             checkIOOBE(() -> {
 619                 double x = (double) vh.getVolatile(array, ci);
 620             });
 621 
 622             checkIOOBE(() -> {
 623                 vh.setVolatile(array, ci, 1.0d);
 624             });
 625 
 626             checkIOOBE(() -> {
 627                 double x = (double) vh.getAcquire(array, ci);
 628             });
 629 
 630             checkIOOBE(() -> {
 631                 vh.setRelease(array, ci, 1.0d);
 632             });
 633 
 634             checkIOOBE(() -> {
 635                 double x = (double) vh.getOpaque(array, ci);
 636             });
 637 
 638             checkIOOBE(() -> {
 639                 vh.setOpaque(array, ci, 1.0d);
 640             });
 641 
 642 
 643         }
 644     }
 645 }
 646