1 /*
   2  * Copyright (c) 2011, 2014, 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 org.junit.Assert;
  26 import org.junit.Ignore;
  27 import org.junit.Test;
  28 
  29 import org.graalvm.compiler.loop.DefaultLoopPolicies;
  30 import org.graalvm.compiler.loop.phases.LoopPeelingPhase;
  31 import org.graalvm.compiler.nodes.ReturnNode;
  32 import org.graalvm.compiler.nodes.StructuredGraph;
  33 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
  34 import org.graalvm.compiler.nodes.ValueNode;
  35 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
  36 import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
  37 import org.graalvm.compiler.phases.common.inlining.InliningPhase;
  38 import org.graalvm.compiler.phases.tiers.HighTierContext;
  39 import org.graalvm.compiler.virtual.phases.ea.PartialEscapePhase;
  40 
  41 /**
  42  * In the following tests, the usages of local variable "a" are replaced with the integer constant
  43  * 0. Then boxing elimination is applied and it is verified that the resulting graph is equal to the
  44  * graph of the method that just has a "return 1" statement in it.
  45  */
  46 public class BoxingEliminationTest extends GraalCompilerTest {
  47 
  48     private static final Short s = 2;
  49 
  50     @SuppressWarnings("all")
  51     public static short referenceSnippet1() {
  52         return 1;
  53     }
  54 
  55     @SuppressWarnings("all")
  56     public static short referenceSnippet2() {
  57         return 2;
  58     }
  59 
  60     public static Short boxedShort() {
  61         return 1;
  62     }
  63 
  64     public static Object boxedObjectShort() {
  65         return (short) 1;
  66     }
  67 
  68     public static Object boxedObjectInteger() {
  69         return 1;
  70     }
  71 
  72     public static Integer boxedInteger() {
  73         return 2;
  74     }
  75 
  76     public static Short constantBoxedShort() {
  77         return s;
  78     }
  79 
  80     @Test
  81     public void test1() {
  82         compareGraphs("test1Snippet", "referenceSnippet1");
  83     }
  84 
  85     @SuppressWarnings("all")
  86     public static short test1Snippet() {
  87         return boxedShort();
  88     }
  89 
  90     @Test
  91     public void test2() {
  92         compareGraphs("test2Snippet", "referenceSnippet1");
  93     }
  94 
  95     @SuppressWarnings("all")
  96     public static short test2Snippet() {
  97         return (Short) boxedObjectShort();
  98     }
  99 
 100     @Test
 101     public void test3() {
 102         compareGraphs("test3Snippet", "referenceSnippet1");
 103     }
 104 
 105     @SuppressWarnings("all")
 106     public static short test3Snippet() {
 107         short b = boxedShort();
 108         if (b < 0) {
 109             b = boxedShort();
 110         }
 111         return b;
 112     }
 113 
 114     @Test
 115     public void test4() {
 116         compareGraphs("test4Snippet", "referenceSnippet2");
 117     }
 118 
 119     @SuppressWarnings("all")
 120     public static short test4Snippet() {
 121         return constantBoxedShort();
 122     }
 123 
 124     @Ignore
 125     @Test
 126     public void testLoop() {
 127         compareGraphs("testLoopSnippet", "referenceLoopSnippet", false, true);
 128     }
 129 
 130     public static int testLoopSnippet(int n, int a) {
 131         Integer sum = a;
 132         for (Integer i = 0; i < n; i++) {
 133             sum += i;
 134         }
 135         return sum;
 136     }
 137 
 138     public static int referenceLoopSnippet(int n, int a) {
 139         int sum = a;
 140         for (int i = 0; i < n; i++) {
 141             sum += i;
 142         }
 143         return sum;
 144     }
 145 
 146     @Test
 147     public void testLoop2() {
 148         compareGraphs("testLoop2Snippet", "referenceLoop2Snippet", true, true);
 149     }
 150 
 151     public static int testLoop2Snippet(int n, Integer a) {
 152         Integer sum = a;
 153         for (Integer i = 0; i < n; i++) {
 154             sum += i;
 155         }
 156         return sum;
 157     }
 158 
 159     public static int referenceLoop2Snippet(int n, Integer a) {
 160         Integer sum0;
 161         if (n <= 0) {
 162             sum0 = a;
 163         } else {
 164             int sum = a;
 165             for (int i = 0; i < n; i++) {
 166                 sum += i;
 167             }
 168             sum0 = sum;
 169         }
 170         return sum0;
 171     }
 172 
 173     public static int referenceIfSnippet(int a) {
 174         int result;
 175         if (a < 0) {
 176             result = 2;
 177         } else {
 178             result = 1;
 179         }
 180         return result;
 181     }
 182 
 183     @Test
 184     public void testIf() {
 185         compareGraphs("testIfSnippet", "referenceIfSnippet");
 186     }
 187 
 188     public static int testIfSnippet(int a) {
 189         Integer result;
 190         if (a < 0) {
 191             result = boxedInteger();
 192         } else {
 193             result = (Integer) boxedObjectInteger();
 194         }
 195         return result;
 196     }
 197 
 198     @Test
 199     public void testComparison() {
 200         compareGraphs("testComparison1Snippet", "referenceComparisonSnippet");
 201         compareGraphs("testComparison2Snippet", "referenceComparisonSnippet");
 202     }
 203 
 204     @SuppressWarnings("cast")
 205     public static boolean testComparison1Snippet(int a, int b) {
 206         return ((Integer) a) == b;
 207     }
 208 
 209     public static boolean testComparison2Snippet(int a, int b) {
 210         Integer x = a;
 211         Integer y = b;
 212         return x == y;
 213     }
 214 
 215     public static boolean referenceComparisonSnippet(int a, int b) {
 216         return a == b;
 217     }
 218 
 219     @Test
 220     public void testLateCanonicalization() {
 221         compareGraphs("testLateCanonicalizationSnippet", "referenceLateCanonicalizationSnippet");
 222     }
 223 
 224     public static boolean testLateCanonicalizationSnippet(int a) {
 225         Integer x = a;
 226         Integer y = 1000;
 227         return x == y;
 228     }
 229 
 230     public static boolean referenceLateCanonicalizationSnippet(int a) {
 231         return a == 1000;
 232     }
 233 
 234     private StructuredGraph graph;
 235 
 236     public static Integer materializeReferenceSnippet(int a) {
 237         return Integer.valueOf(a);
 238     }
 239 
 240     public static Integer materializeTest1Snippet(int a) {
 241         Integer v = a;
 242 
 243         if (v == a) {
 244             return v;
 245         } else {
 246             return null;
 247         }
 248     }
 249 
 250     @Test
 251     public void materializeTest1() {
 252         test("materializeTest1Snippet", 1);
 253     }
 254 
 255     public static int intTest1Snippet() {
 256         return Integer.valueOf(1);
 257     }
 258 
 259     @Test
 260     public void intTest1() {
 261         ValueNode result = getResult("intTest1Snippet");
 262         Assert.assertTrue(result.isConstant());
 263         Assert.assertEquals(1, result.asJavaConstant().asInt());
 264     }
 265 
 266     public static int mergeTest1Snippet(boolean d, int a, int b) {
 267         Integer v;
 268         if (d) {
 269             v = a;
 270         } else {
 271             v = b;
 272         }
 273         return v;
 274     }
 275 
 276     @Test
 277     public void mergeTest1() {
 278         processMethod("mergeTest1Snippet");
 279     }
 280 
 281     public static boolean equalsTest1Snippet(int x, int y) {
 282         Integer a = x;
 283         Integer b = y;
 284         return a == b;
 285     }
 286 
 287     @Test
 288     public void equalsTest1() {
 289         processMethod("equalsTest1Snippet");
 290     }
 291 
 292     public static int loopTest1Snippet(int n, int v) {
 293         Integer sum = 0;
 294         for (int i = 0; i < n; i++) {
 295             sum += v;
 296         }
 297         return sum;
 298     }
 299 
 300     @Test
 301     public void loopTest1() {
 302         processMethod("loopTest1Snippet");
 303 
 304     }
 305 
 306     final ValueNode getResult(String snippet) {
 307         processMethod(snippet);
 308         assertDeepEquals(1, graph.getNodes(ReturnNode.TYPE).count());
 309         return graph.getNodes(ReturnNode.TYPE).first().result();
 310     }
 311 
 312     private void processMethod(final String snippet) {
 313         graph = parseEager(snippet, AllowAssumptions.NO);
 314         HighTierContext context = getDefaultHighTierContext();
 315         new InliningPhase(new CanonicalizerPhase()).apply(graph, context);
 316         new PartialEscapePhase(false, new CanonicalizerPhase()).apply(graph, context);
 317     }
 318 
 319     private void compareGraphs(final String snippet, final String referenceSnippet) {
 320         compareGraphs(snippet, referenceSnippet, false, false);
 321     }
 322 
 323     private void compareGraphs(final String snippet, final String referenceSnippet, final boolean loopPeeling, final boolean excludeVirtual) {
 324         graph = parseEager(snippet, AllowAssumptions.NO);
 325         HighTierContext context = getDefaultHighTierContext();
 326         CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
 327         canonicalizer.apply(graph, context);
 328         new InliningPhase(new CanonicalizerPhase()).apply(graph, context);
 329         if (loopPeeling) {
 330             new LoopPeelingPhase(new DefaultLoopPolicies()).apply(graph, context);
 331         }
 332         new DeadCodeEliminationPhase().apply(graph);
 333         canonicalizer.apply(graph, context);
 334         new PartialEscapePhase(false, canonicalizer).apply(graph, context);
 335 
 336         new DeadCodeEliminationPhase().apply(graph);
 337         canonicalizer.apply(graph, context);
 338 
 339         StructuredGraph referenceGraph = parseEager(referenceSnippet, AllowAssumptions.YES);
 340         new InliningPhase(new CanonicalizerPhase()).apply(referenceGraph, context);
 341         new DeadCodeEliminationPhase().apply(referenceGraph);
 342         new CanonicalizerPhase().apply(referenceGraph, context);
 343 
 344         assertEquals(referenceGraph, graph, excludeVirtual, true);
 345     }
 346 }