1 /*
   2  * Copyright (c) 2017, 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.core.test;
  26 
  27 import static org.graalvm.compiler.graph.test.matchers.NodeIterableCount.hasCount;
  28 import static org.graalvm.compiler.graph.test.matchers.NodeIterableIsEmpty.isNotEmpty;
  29 import static org.junit.Assert.assertThat;
  30 import static org.junit.Assume.assumeThat;
  31 import static org.junit.Assume.assumeTrue;
  32 
  33 import java.util.Iterator;
  34 
  35 import org.graalvm.compiler.api.directives.GraalDirectives;
  36 import org.graalvm.compiler.core.common.GraalOptions;
  37 import org.graalvm.compiler.graph.iterators.NodeIterable;
  38 import org.graalvm.compiler.nodes.GuardNode;
  39 import org.graalvm.compiler.nodes.ParameterNode;
  40 import org.graalvm.compiler.nodes.StructuredGraph;
  41 import org.graalvm.compiler.nodes.calc.IntegerLowerThanNode;
  42 import org.graalvm.compiler.nodes.calc.IsNullNode;
  43 import org.graalvm.compiler.nodes.spi.LoweringTool;
  44 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
  45 import org.graalvm.compiler.phases.common.ConvertDeoptimizeToGuardPhase;
  46 import org.graalvm.compiler.phases.common.FloatingReadPhase;
  47 import org.graalvm.compiler.phases.common.LoweringPhase;
  48 import org.graalvm.compiler.phases.schedule.SchedulePhase;
  49 import org.graalvm.compiler.phases.tiers.HighTierContext;
  50 import org.junit.Test;
  51 
  52 import jdk.vm.ci.meta.SpeculationLog;
  53 
  54 public class GuardPrioritiesTest extends GraphScheduleTest {
  55     private int[] array;
  56     private int size;
  57 
  58     public void growing(int e) {
  59         if (size >= array.length) {
  60             // grow
  61             GraalDirectives.deoptimizeAndInvalidateWithSpeculation();
  62         }
  63         array[size++] = e;
  64     }
  65 
  66     @Test
  67     public void growingTest() {
  68         assumeTrue("GuardPriorities must be turned one", GraalOptions.GuardPriorities.getValue(getInitialOptions()));
  69         StructuredGraph graph = prepareGraph("growing");
  70 
  71         NodeIterable<GuardNode> guards = graph.getNodes(GuardNode.TYPE).filter(n -> n.inputs().filter(i -> i instanceof IntegerLowerThanNode).isNotEmpty());
  72         assertThat(guards, isNotEmpty());
  73         assumeThat(guards, hasCount(2));
  74 
  75         Iterator<GuardNode> iterator = guards.iterator();
  76         GuardNode g1 = iterator.next();
  77         GuardNode g2 = iterator.next();
  78         assertTrue("There should be one guard with speculation, the other one without",
  79                         (g1.getSpeculation().equals(SpeculationLog.NO_SPECULATION)) ^ (g2.getSpeculation().equals(SpeculationLog.NO_SPECULATION)));
  80         GuardNode withSpeculation = g1.getSpeculation().equals(SpeculationLog.NO_SPECULATION) ? g2 : g1;
  81         GuardNode withoutSpeculation = g1.getSpeculation().equals(SpeculationLog.NO_SPECULATION) ? g1 : g2;
  82 
  83         assertOrderedAfterSchedule(graph, SchedulePhase.SchedulingStrategy.EARLIEST_WITH_GUARD_ORDER, withSpeculation, withoutSpeculation);
  84     }
  85 
  86     private StructuredGraph prepareGraph(String method) {
  87         StructuredGraph graph = parseEager(method, StructuredGraph.AllowAssumptions.YES);
  88         HighTierContext highTierContext = getDefaultHighTierContext();
  89         CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
  90         new ConvertDeoptimizeToGuardPhase().apply(graph, highTierContext);
  91         new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, highTierContext);
  92         new FloatingReadPhase().apply(graph);
  93         return graph;
  94     }
  95 
  96     public int unknownCondition(Integer c, Object o, int[] a, Integer i) {
  97         if (o != null) {
  98             GraalDirectives.deoptimizeAndInvalidate();
  99         }
 100         if (i > 5560) {
 101             GraalDirectives.deoptimizeAndInvalidate();
 102         }
 103         if (c >= 10) {
 104             GraalDirectives.deoptimizeAndInvalidateWithSpeculation();
 105         }
 106         return array[8] + a[i];
 107     }
 108 
 109     @Test
 110     public void unknownTest() {
 111         assumeTrue("GuardPriorities must be turned one", GraalOptions.GuardPriorities.getValue(getInitialOptions()));
 112         StructuredGraph graph = prepareGraph("unknownCondition");
 113 
 114         new SchedulePhase(SchedulePhase.SchedulingStrategy.EARLIEST_WITH_GUARD_ORDER).apply(graph);
 115         for (GuardNode g1 : graph.getNodes(GuardNode.TYPE)) {
 116             for (GuardNode g2 : graph.getNodes(GuardNode.TYPE)) {
 117                 if (g1.getSpeculation().equals(SpeculationLog.NO_SPECULATION) ^ g2.getSpeculation().equals(SpeculationLog.NO_SPECULATION)) {
 118                     GuardNode withSpeculation = g1.getSpeculation().equals(SpeculationLog.NO_SPECULATION) ? g2 : g1;
 119                     GuardNode withoutSpeculation = g1.getSpeculation().equals(SpeculationLog.NO_SPECULATION) ? g1 : g2;
 120 
 121                     if (withoutSpeculation.isNegated() && withoutSpeculation.getCondition() instanceof IsNullNode) {
 122                         IsNullNode isNullNode = (IsNullNode) withoutSpeculation.getCondition();
 123                         if (isNullNode.getValue() instanceof ParameterNode && ((ParameterNode) isNullNode.getValue()).index() == 1) {
 124                             // this is the null check before the speculative guard, it's the only
 125                             // one that should be above
 126                             assertOrderedAfterLastSchedule(graph, withoutSpeculation, withSpeculation);
 127                             continue;
 128                         }
 129                     }
 130 
 131                     assertOrderedAfterLastSchedule(graph, withSpeculation, withoutSpeculation);
 132                 }
 133             }
 134         }
 135     }
 136 }