1 /*
   2  * Copyright (c) 2018, 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 package org.graalvm.compiler.replacements.jdk9.test;
  26 
  27 import java.lang.invoke.MethodHandles;
  28 import java.lang.invoke.VarHandle;
  29 
  30 import org.graalvm.compiler.core.test.GraalCompilerTest;
  31 import org.graalvm.compiler.debug.GraalError;
  32 import org.graalvm.compiler.graph.Node;
  33 import org.graalvm.compiler.nodes.StartNode;
  34 import org.graalvm.compiler.nodes.StructuredGraph;
  35 import org.graalvm.compiler.nodes.extended.MembarNode;
  36 import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
  37 import org.graalvm.compiler.nodes.memory.ReadNode;
  38 import org.graalvm.compiler.nodes.memory.WriteNode;
  39 import jdk.internal.vm.compiler.word.LocationIdentity;
  40 import org.junit.Assert;
  41 import org.junit.Test;
  42 
  43 import jdk.vm.ci.meta.ResolvedJavaMethod;
  44 
  45 public class VarHandleTest extends GraalCompilerTest {
  46 
  47     static class Holder {
  48         /* Field is declared volatile, but accessed with non-volatile semantics in the tests. */
  49         volatile int volatileField = 42;
  50 
  51         /* Field is declared non-volatile, but accessed with volatile semantics in the tests. */
  52         int field = 2018;
  53 
  54         static final VarHandle VOLATILE_FIELD;
  55         static final VarHandle FIELD;
  56 
  57         static {
  58             try {
  59                 VOLATILE_FIELD = MethodHandles.lookup().findVarHandle(Holder.class, "volatileField", int.class);
  60                 FIELD = MethodHandles.lookup().findVarHandle(Holder.class, "field", int.class);
  61             } catch (ReflectiveOperationException ex) {
  62                 throw GraalError.shouldNotReachHere(ex);
  63             }
  64         }
  65     }
  66 
  67     public static int testRead1Snippet(Holder h) {
  68         /* Explicitly access the volatile field with non-volatile access semantics. */
  69         return (int) Holder.VOLATILE_FIELD.get(h);
  70     }
  71 
  72     public static int testRead2Snippet(Holder h) {
  73         /* Explicitly access the volatile field with volatile access semantics. */
  74         return (int) Holder.VOLATILE_FIELD.getVolatile(h);
  75     }
  76 
  77     public static int testRead3Snippet(Holder h) {
  78         /* Explicitly access the non-volatile field with non-volatile access semantics. */
  79         return (int) Holder.FIELD.get(h);
  80     }
  81 
  82     public static int testRead4Snippet(Holder h) {
  83         /* Explicitly access the non-volatile field with volatile access semantics. */
  84         return (int) Holder.FIELD.getVolatile(h);
  85     }
  86 
  87     public static void testWrite1Snippet(Holder h) {
  88         /* Explicitly access the volatile field with non-volatile access semantics. */
  89         Holder.VOLATILE_FIELD.set(h, 123);
  90     }
  91 
  92     public static void testWrite2Snippet(Holder h) {
  93         /* Explicitly access the volatile field with volatile access semantics. */
  94         Holder.VOLATILE_FIELD.setVolatile(h, 123);
  95     }
  96 
  97     public static void testWrite3Snippet(Holder h) {
  98         /* Explicitly access the non-volatile field with non-volatile access semantics. */
  99         Holder.FIELD.set(h, 123);
 100     }
 101 
 102     public static void testWrite4Snippet(Holder h) {
 103         /* Explicitly access the non-volatile field with volatile access semantics. */
 104         Holder.FIELD.setVolatile(h, 123);
 105     }
 106 
 107     void testAccess(String name, int expectedReads, int expectedWrites, int expectedMembars, int expectedAnyKill) {
 108         ResolvedJavaMethod method = getResolvedJavaMethod(name);
 109         StructuredGraph graph = parseForCompile(method);
 110         compile(method, graph);
 111         Assert.assertEquals(expectedReads, graph.getNodes().filter(ReadNode.class).count());
 112         Assert.assertEquals(expectedWrites, graph.getNodes().filter(WriteNode.class).count());
 113         Assert.assertEquals(expectedMembars, graph.getNodes().filter(MembarNode.class).count());
 114         Assert.assertEquals(expectedAnyKill, countAnyKill(graph));
 115     }
 116 
 117     @Test
 118     public void testRead1() {
 119         testAccess("testRead1Snippet", 1, 0, 0, 0);
 120     }
 121 
 122     @Test
 123     public void testRead2() {
 124         testAccess("testRead2Snippet", 1, 0, 2, 2);
 125     }
 126 
 127     @Test
 128     public void testRead3() {
 129         testAccess("testRead3Snippet", 1, 0, 0, 0);
 130     }
 131 
 132     @Test
 133     public void testRead4() {
 134         testAccess("testRead4Snippet", 1, 0, 2, 2);
 135     }
 136 
 137     @Test
 138     public void testWrite1() {
 139         testAccess("testWrite1Snippet", 0, 1, 0, 0);
 140     }
 141 
 142     @Test
 143     public void testWrite2() {
 144         testAccess("testWrite2Snippet", 0, 1, 2, 2);
 145     }
 146 
 147     @Test
 148     public void testWrite3() {
 149         testAccess("testWrite3Snippet", 0, 1, 0, 0);
 150     }
 151 
 152     @Test
 153     public void testWrite4() {
 154         testAccess("testWrite4Snippet", 0, 1, 2, 2);
 155     }
 156 
 157     private static int countAnyKill(StructuredGraph graph) {
 158         int anyKillCount = 0;
 159         int startNodes = 0;
 160         for (Node n : graph.getNodes()) {
 161             if (n instanceof StartNode) {
 162                 startNodes++;
 163             } else if (n instanceof MemoryCheckpoint.Single) {
 164                 MemoryCheckpoint.Single single = (MemoryCheckpoint.Single) n;
 165                 if (single.getLocationIdentity().isAny()) {
 166                     anyKillCount++;
 167                 }
 168             } else if (n instanceof MemoryCheckpoint.Multi) {
 169                 MemoryCheckpoint.Multi multi = (MemoryCheckpoint.Multi) n;
 170                 for (LocationIdentity loc : multi.getLocationIdentities()) {
 171                     if (loc.isAny()) {
 172                         anyKillCount++;
 173                         break;
 174                     }
 175                 }
 176             }
 177         }
 178         // Ignore single StartNode.
 179         Assert.assertEquals(1, startNodes);
 180         return anyKillCount;
 181     }
 182 }