1 /*
   2  * Copyright (c) 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 package org.graalvm.compiler.core.test;
  24 
  25 import java.lang.reflect.Field;
  26 
  27 import org.junit.Assert;
  28 import org.junit.Test;
  29 
  30 import org.graalvm.compiler.api.directives.GraalDirectives;
  31 import org.graalvm.compiler.nodes.StructuredGraph;
  32 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
  33 import org.graalvm.compiler.nodes.extended.UnsafeAccessNode;
  34 import org.graalvm.compiler.nodes.memory.ReadNode;
  35 import org.graalvm.compiler.nodes.memory.WriteNode;
  36 import org.graalvm.compiler.nodes.spi.LoweringTool;
  37 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
  38 import org.graalvm.compiler.phases.common.LoweringPhase;
  39 import org.graalvm.compiler.phases.tiers.PhaseContext;
  40 import org.graalvm.compiler.virtual.phases.ea.EarlyReadEliminationPhase;
  41 import org.graalvm.compiler.virtual.phases.ea.PartialEscapePhase;
  42 
  43 import sun.misc.Unsafe;
  44 
  45 public class UnsafeReadEliminationTest extends GraalCompilerTest {
  46 
  47     public static final Unsafe UNSAFE;
  48     static {
  49         try {
  50             Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
  51             theUnsafe.setAccessible(true);
  52             UNSAFE = (Unsafe) theUnsafe.get(Unsafe.class);
  53         } catch (Exception e) {
  54             throw new RuntimeException("Exception while trying to get Unsafe", e);
  55         }
  56     }
  57 
  58     public static long[] Memory = new long[]{1, 2};
  59     public static double SideEffectD;
  60     public static double SideEffectL;
  61 
  62     public static long test1Snippet(double a) {
  63         final Object m = Memory;
  64         if (a > 0) {
  65             UNSAFE.putDouble(m, (long) Unsafe.ARRAY_LONG_BASE_OFFSET, a);
  66         } else {
  67             SideEffectL = UNSAFE.getLong(m, (long) Unsafe.ARRAY_LONG_BASE_OFFSET);
  68         }
  69         return UNSAFE.getLong(m, (long) Unsafe.ARRAY_LONG_BASE_OFFSET);
  70     }
  71 
  72     public static class A {
  73         long[][] o;
  74         long[][] p;
  75     }
  76 
  77     public static Object test2Snippet(A a, int c) {
  78         Object phi = null;
  79         if (c != 0) {
  80             long[][] r = a.o;
  81             phi = r;
  82             UNSAFE.putDouble(r, (long) Unsafe.ARRAY_LONG_BASE_OFFSET, 12d);
  83         } else {
  84             long[][] r = a.p;
  85             phi = r;
  86             UNSAFE.putLong(r, (long) Unsafe.ARRAY_LONG_BASE_OFFSET, 123);
  87         }
  88         GraalDirectives.controlFlowAnchor();
  89         SideEffectD = UNSAFE.getDouble(phi, (long) Unsafe.ARRAY_LONG_BASE_OFFSET);
  90         return phi;
  91     }
  92 
  93     @Test
  94     public void test01() {
  95         StructuredGraph graph = parseEager("test1Snippet", AllowAssumptions.NO);
  96         testEarlyReadElimination(graph, 3, 2);
  97     }
  98 
  99     @Test
 100     public void test02() {
 101         StructuredGraph graph = parseEager("test1Snippet", AllowAssumptions.NO);
 102         testPartialEscapeReadElimination(graph, 3, 2);
 103     }
 104 
 105     @Test
 106     public void test03() {
 107         StructuredGraph graph = parseEager("test2Snippet", AllowAssumptions.NO);
 108         testEarlyReadElimination(graph, 3, 3);
 109     }
 110 
 111     @Test
 112     public void test04() {
 113         StructuredGraph graph = parseEager("test2Snippet", AllowAssumptions.NO);
 114         testEarlyReadElimination(graph, 3, 3);
 115     }
 116 
 117     public void testEarlyReadElimination(StructuredGraph graph, int reads, int writes) {
 118         PhaseContext context = getDefaultHighTierContext();
 119         CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
 120         canonicalizer.apply(graph, context);
 121         new EarlyReadEliminationPhase(canonicalizer).apply(graph, context);
 122         Assert.assertEquals(3, graph.getNodes().filter(UnsafeAccessNode.class).count());
 123         // after lowering the same applies for reads and writes
 124         new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
 125         canonicalizer.apply(graph, context);
 126         new EarlyReadEliminationPhase(canonicalizer).apply(graph, context);
 127         Assert.assertEquals(reads, graph.getNodes().filter(ReadNode.class).count());
 128         Assert.assertEquals(writes, graph.getNodes().filter(WriteNode.class).count());
 129     }
 130 
 131     public void testPartialEscapeReadElimination(StructuredGraph graph, int reads, int writes) {
 132         PhaseContext context = getDefaultHighTierContext();
 133         CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
 134         canonicalizer.apply(graph, context);
 135         new PartialEscapePhase(true, true, canonicalizer, null).apply(graph, context);
 136         Assert.assertEquals(3, graph.getNodes().filter(UnsafeAccessNode.class).count());
 137         // after lowering the same applies for reads and writes
 138         new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
 139         canonicalizer.apply(graph, context);
 140         new PartialEscapePhase(true, true, canonicalizer, null).apply(graph, context);
 141         Assert.assertEquals(reads, graph.getNodes().filter(ReadNode.class).count());
 142         Assert.assertEquals(writes, graph.getNodes().filter(WriteNode.class).count());
 143     }
 144 
 145 }