1 /*
2  * Copyright (c) 2017, 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 
growing(int e)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
growingTest()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 
prepareGraph(String method)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 
unknownCondition(Integer c, Object o, int[] a, Integer i)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
unknownTest()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 }
137