src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/LateMembarInsertionTest.java
author dlong
Thu, 31 Oct 2019 16:54:16 -0700
changeset 58877 aec7bf35d6f5
permissions -rw-r--r--
8233273: Update Graal Reviewed-by: kvn

/*
 * 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;
    }

}