src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/LateMembarInsertionTest.java
changeset 58877 aec7bf35d6f5
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/LateMembarInsertionTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -0,0 +1,233 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, Red Hat Inc. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package org.graalvm.compiler.core.test;
+
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaType;
+import jdk.internal.vm.compiler.collections.EconomicMap;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.NodeView;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.cfg.Block;
+import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
+import org.graalvm.compiler.nodes.memory.FixedAccessNode;
+import org.graalvm.compiler.nodes.memory.MemoryAccess;
+import org.graalvm.compiler.nodes.memory.ReadNode;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+import org.graalvm.compiler.options.OptionKey;
+import org.graalvm.compiler.options.OptionValues;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static org.graalvm.compiler.core.common.GraalOptions.StressTestEarlyReads;
+
+public class LateMembarInsertionTest extends GraalCompilerTest {
+
+    private final ResolvedJavaType volatileAccessType = getMetaAccess().lookupJavaType(VolatileAccess.class);
+    private final ResolvedJavaType regularAccessField = getMetaAccess().lookupJavaType(RegularAccess.class);
+    private final ResolvedJavaType volatileAccess2Type = getMetaAccess().lookupJavaType(VolatileAccess2.class);
+
+    static class VolatileAccess {
+        static volatile int field;
+    }
+
+    static class VolatileAccess2 {
+        static volatile int field;
+    }
+
+    static class RegularAccess {
+        static int field;
+    }
+
+    public static int volatileFieldLoadFieldLoad() {
+        int v1 = VolatileAccess.field;
+        int v2 = RegularAccess.field;
+        return v1 + v2;
+    }
+
+    @Test
+    public void test01() {
+        List<TypePair> accesses = compile("volatileFieldLoadFieldLoad", stressTestEarlyReads());
+
+        Assert.assertEquals(accesses.size(), 2);
+        Assert.assertEquals(accesses.get(0).getType(), volatileAccessType);
+        Assert.assertEquals(accesses.get(1).getType(), regularAccessField);
+        Assert.assertTrue(accesses.get(0).isRead());
+        Assert.assertTrue(accesses.get(1).isRead());
+    }
+
+    public static int volatileFieldLoadVolatileFieldLoad() {
+        int v1 = VolatileAccess.field;
+        int v2 = VolatileAccess2.field;
+        return v1 + v2;
+    }
+
+    @Test
+    public void test02() {
+        List<TypePair> accesses = compile("volatileFieldLoadVolatileFieldLoad", stressTestEarlyReads());
+
+        Assert.assertEquals(accesses.size(), 2);
+        Assert.assertEquals(accesses.get(0).getType(), volatileAccessType);
+        Assert.assertEquals(accesses.get(1).getType(), volatileAccess2Type);
+        Assert.assertTrue(accesses.get(0).isRead());
+        Assert.assertTrue(accesses.get(1).isRead());
+    }
+
+    public static int volatileFieldLoadVolatileFieldStore(int v2) {
+        int v1 = VolatileAccess.field;
+        VolatileAccess2.field = v2;
+        return v1;
+    }
+
+    @Test
+    public void test03() {
+        List<TypePair> accesses = compile("volatileFieldLoadVolatileFieldStore");
+
+        Assert.assertEquals(accesses.size(), 2);
+        Assert.assertEquals(accesses.get(0).getType(), volatileAccessType);
+        Assert.assertEquals(accesses.get(1).getType(), volatileAccess2Type);
+        Assert.assertTrue(accesses.get(0).isRead());
+        Assert.assertTrue(accesses.get(1).isWrite());
+    }
+
+    public static int volatileFieldStoreVolatileFieldLoad(int v2) {
+        VolatileAccess.field = v2;
+        return VolatileAccess2.field;
+    }
+
+    @Test
+    public void test04() {
+        List<TypePair> accesses = compile("volatileFieldStoreVolatileFieldLoad", stressTestEarlyReads());
+
+        Assert.assertEquals(accesses.size(), 2);
+        Assert.assertEquals(accesses.get(0).getType(), volatileAccessType);
+        Assert.assertEquals(accesses.get(1).getType(), volatileAccess2Type);
+        Assert.assertTrue(accesses.get(0).isWrite());
+        Assert.assertTrue(accesses.get(1).isRead());
+    }
+
+    public static int fieldLoadVolatileFieldStore(int v2) {
+        int v1 = RegularAccess.field;
+        VolatileAccess2.field = v2;
+        return v1;
+    }
+
+    @Test
+    public void test05() {
+        List<TypePair> accesses = compile("fieldLoadVolatileFieldStore");
+
+        Assert.assertEquals(accesses.size(), 2);
+        Assert.assertEquals(accesses.get(0).getType(), regularAccessField);
+        Assert.assertEquals(accesses.get(1).getType(), volatileAccess2Type);
+        Assert.assertTrue(accesses.get(0).isRead());
+        Assert.assertTrue(accesses.get(1).isWrite());
+    }
+
+    public static void volatileFieldStoreVolatileFieldStore(int v1, int v2) {
+        VolatileAccess.field = v1;
+        VolatileAccess2.field = v2;
+    }
+
+    @Test
+    public void test06() {
+        List<TypePair> accesses = compile("volatileFieldStoreVolatileFieldStore");
+
+        Assert.assertEquals(accesses.size(), 2);
+        Assert.assertEquals(accesses.get(0).getType(), volatileAccessType);
+        Assert.assertEquals(accesses.get(1).getType(), volatileAccess2Type);
+        Assert.assertTrue(accesses.get(0).isWrite());
+        Assert.assertTrue(accesses.get(1).isWrite());
+    }
+
+    private static OptionValues stressTestEarlyReads() {
+        EconomicMap<OptionKey<?>, Object> overrides = OptionValues.newOptionMap();
+        overrides.put(StressTestEarlyReads, true);
+        return new OptionValues(getInitialOptions(), overrides);
+    }
+
+    static class TypePair {
+        private boolean isRead;
+        private ResolvedJavaType type;
+
+        TypePair(boolean isRead, ResolvedJavaType type) {
+            this.isRead = isRead;
+            this.type = type;
+        }
+
+        public boolean isRead() {
+            return isRead;
+        }
+
+        public boolean isWrite() {
+            return !isRead;
+        }
+
+        public ResolvedJavaType getType() {
+            return type;
+        }
+    }
+
+    private List<TypePair> compile(String test, OptionValues options) {
+        StructuredGraph graph = getFinalGraph(getResolvedJavaMethod(test), options);
+        return getAccesses(graph);
+    }
+
+    private List<TypePair> getAccesses(StructuredGraph graph) {
+        StructuredGraph.ScheduleResult schedule = graph.getLastSchedule();
+        ControlFlowGraph cfg = schedule.getCFG();
+        Block[] blocks = cfg.getBlocks();
+
+        return Arrays.stream(blocks).flatMap(b -> schedule.nodesFor(b).stream()).filter(n -> n instanceof MemoryAccess).map(
+                        n -> new TypePair(n instanceof ReadNode, classForAccess((FixedAccessNode) n))).collect(Collectors.toList());
+    }
+
+    private List<TypePair> compile(String test) {
+        StructuredGraph graph = getFinalGraph(getResolvedJavaMethod(test));
+        return getAccesses(graph);
+    }
+
+    private ResolvedJavaType classForAccess(FixedAccessNode n) {
+        AddressNode address = n.getAddress();
+        ValueNode base = address.getBase();
+        Stamp stamp = base.stamp(NodeView.DEFAULT);
+        MetaAccessProvider metaAccess = getMetaAccess();
+        ResolvedJavaType javaType = stamp.javaType(metaAccess);
+        if (javaType == metaAccess.lookupJavaType(Class.class) && base instanceof ConstantNode) {
+            ConstantReflectionProvider constantReflection = getConstantReflection();
+            javaType = constantReflection.asJavaType(base.asConstant());
+        }
+        return javaType;
+    }
+
+}