1 /*
2  * Copyright (c) 2011, 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.ea;
26 
27 import java.util.List;
28 
29 import org.graalvm.compiler.core.test.GraalCompilerTest;
30 import org.graalvm.compiler.nodes.ProxyNode;
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.nodes.ValuePhiNode;
36 import org.graalvm.compiler.nodes.java.LoadFieldNode;
37 import org.graalvm.compiler.nodes.java.StoreFieldNode;
38 import org.graalvm.compiler.nodes.memory.ReadNode;
39 import org.graalvm.compiler.nodes.spi.LoweringTool;
40 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
41 import org.graalvm.compiler.phases.common.LoweringPhase;
42 import org.graalvm.compiler.phases.tiers.HighTierContext;
43 import org.graalvm.compiler.virtual.phases.ea.EarlyReadEliminationPhase;
44 import org.junit.Test;
45 
46 public class EarlyReadEliminationTest extends GraalCompilerTest {
47 
48     public static Object staticField;
49 
50     public static class TestObject {
51 
52         public int x;
53         public int y;
54 
TestObject(int x, int y)55         public TestObject(int x, int y) {
56             this.x = x;
57             this.y = y;
58         }
59     }
60 
61     public static class TestObject2 {
62 
63         public Object x;
64         public Object y;
65 
TestObject2(Object x, Object y)66         public TestObject2(Object x, Object y) {
67             this.x = x;
68             this.y = y;
69         }
70     }
71 
72     public static class TestObject3 extends TestObject {
73 
74         public int z;
75 
TestObject3(int x, int y, int z)76         public TestObject3(int x, int y, int z) {
77             super(x, y);
78             this.z = z;
79         }
80     }
81 
82     @SuppressWarnings("all")
testSimpleSnippet(TestObject a)83     public static int testSimpleSnippet(TestObject a) {
84         a.x = 2;
85         staticField = a;
86         return a.x;
87     }
88 
89     @Test
testSimple()90     public void testSimple() {
91         // Test without lowering.
92         ValueNode result = getReturn("testSimpleSnippet", false).result();
93         assertTrue(result.graph().getNodes().filter(LoadFieldNode.class).isEmpty());
94         assertTrue(result.isConstant());
95         assertDeepEquals(2, result.asJavaConstant().asInt());
96 
97         // Test with lowering.
98         result = getReturn("testSimpleSnippet", true).result();
99         assertTrue(result.graph().getNodes().filter(ReadNode.class).isEmpty());
100         assertTrue(result.isConstant());
101         assertDeepEquals(2, result.asJavaConstant().asInt());
102     }
103 
104     @SuppressWarnings("all")
testSimpleConflictSnippet(TestObject a, TestObject b)105     public static int testSimpleConflictSnippet(TestObject a, TestObject b) {
106         a.x = 2;
107         b.x = 3;
108         staticField = a;
109         return a.x;
110     }
111 
112     @Test
testSimpleConflict()113     public void testSimpleConflict() {
114         ValueNode result = getReturn("testSimpleConflictSnippet", false).result();
115         assertFalse(result.isConstant());
116         assertTrue(result instanceof LoadFieldNode);
117     }
118 
119     @SuppressWarnings("all")
testParamSnippet(TestObject a, int b)120     public static int testParamSnippet(TestObject a, int b) {
121         a.x = b;
122         return a.x;
123     }
124 
125     @Test
testParam()126     public void testParam() {
127         ValueNode result = getReturn("testParamSnippet", false).result();
128         assertTrue(result.graph().getNodes().filter(LoadFieldNode.class).isEmpty());
129         assertDeepEquals(result.graph().getParameter(1), result);
130     }
131 
132     @SuppressWarnings("all")
testMaterializedSnippet(int a)133     public static int testMaterializedSnippet(int a) {
134         TestObject obj = new TestObject(a, 0);
135         staticField = obj;
136         return obj.x;
137     }
138 
139     @Test
testMaterialized()140     public void testMaterialized() {
141         ValueNode result = getReturn("testMaterializedSnippet", false).result();
142         assertTrue(result.graph().getNodes().filter(LoadFieldNode.class).isEmpty());
143         assertDeepEquals(result.graph().getParameter(0), result);
144     }
145 
146     @SuppressWarnings("all")
testSimpleLoopSnippet(TestObject obj, int a, int b)147     public static int testSimpleLoopSnippet(TestObject obj, int a, int b) {
148         obj.x = a;
149         for (int i = 0; i < 10; i++) {
150             staticField = obj;
151         }
152         return obj.x;
153     }
154 
155     @Test
testSimpleLoop()156     public void testSimpleLoop() {
157         // Test without lowering.
158         ValueNode result = getReturn("testSimpleLoopSnippet", false).result();
159         assertTrue(result.graph().getNodes().filter(LoadFieldNode.class).isEmpty());
160         assertDeepEquals(result.graph().getParameter(1), result);
161 
162         // Now test with lowering.
163         result = getReturn("testSimpleLoopSnippet", true).result();
164         assertTrue(result.graph().getNodes().filter(ReadNode.class).isEmpty());
165         assertDeepEquals(result.graph().getParameter(1), result);
166     }
167 
168     @SuppressWarnings("all")
testBadLoopSnippet(TestObject obj, TestObject obj2, int a, int b)169     public static int testBadLoopSnippet(TestObject obj, TestObject obj2, int a, int b) {
170         obj.x = a;
171         for (int i = 0; i < 10; i++) {
172             staticField = obj;
173             obj2.x = 10;
174             obj.x = 0;
175         }
176         return obj.x;
177     }
178 
179     @Test
testBadLoop()180     public void testBadLoop() {
181         ValueNode result = getReturn("testBadLoopSnippet", false).result();
182         assertDeepEquals(0, result.graph().getNodes().filter(LoadFieldNode.class).count());
183         assertTrue(result instanceof ProxyNode);
184         assertTrue(((ProxyNode) result).value() instanceof ValuePhiNode);
185     }
186 
187     @SuppressWarnings("all")
testBadLoop2Snippet(TestObject obj, TestObject obj2, int a, int b)188     public static int testBadLoop2Snippet(TestObject obj, TestObject obj2, int a, int b) {
189         obj.x = a;
190         for (int i = 0; i < 10; i++) {
191             obj.x = 0;
192             obj2.x = 10;
193         }
194         return obj.x;
195     }
196 
197     @Test
testBadLoop2()198     public void testBadLoop2() {
199         ValueNode result = getReturn("testBadLoop2Snippet", false).result();
200         assertDeepEquals(1, result.graph().getNodes().filter(LoadFieldNode.class).count());
201         assertTrue(result instanceof LoadFieldNode);
202     }
203 
204     @SuppressWarnings("all")
testPhiSnippet(TestObject a, int b)205     public static int testPhiSnippet(TestObject a, int b) {
206         if (b < 0) {
207             a.x = 1;
208         } else {
209             a.x = 2;
210         }
211         return a.x;
212     }
213 
214     @Test
testPhi()215     public void testPhi() {
216         StructuredGraph graph = processMethod("testPhiSnippet", false);
217         assertTrue(graph.getNodes().filter(LoadFieldNode.class).isEmpty());
218         List<ReturnNode> returnNodes = graph.getNodes(ReturnNode.TYPE).snapshot();
219         assertDeepEquals(2, returnNodes.size());
220         assertTrue(returnNodes.get(0).predecessor() instanceof StoreFieldNode);
221         assertTrue(returnNodes.get(1).predecessor() instanceof StoreFieldNode);
222         assertTrue(returnNodes.get(0).result().isConstant());
223         assertTrue(returnNodes.get(1).result().isConstant());
224     }
225 
226     @SuppressWarnings("all")
testSimpleStoreSnippet(TestObject a, int b)227     public static void testSimpleStoreSnippet(TestObject a, int b) {
228         a.x = b;
229         a.x = b;
230     }
231 
232     @Test
testSimpleStore()233     public void testSimpleStore() {
234         StructuredGraph graph = processMethod("testSimpleStoreSnippet", false);
235         assertDeepEquals(1, graph.getNodes().filter(StoreFieldNode.class).count());
236     }
237 
testValueProxySnippet(boolean b, TestObject o)238     public static int testValueProxySnippet(boolean b, TestObject o) {
239         int sum = 0;
240         if (b) {
241             sum += o.x;
242         } else {
243             TestObject3 p = (TestObject3) o;
244             sum += p.x;
245         }
246         sum += o.x;
247         return sum;
248     }
249 
250     @Test
testValueProxy()251     public void testValueProxy() {
252         StructuredGraph graph = processMethod("testValueProxySnippet", false);
253         assertDeepEquals(2, graph.getNodes().filter(LoadFieldNode.class).count());
254     }
255 
getReturn(String snippet, boolean doLowering)256     ReturnNode getReturn(String snippet, boolean doLowering) {
257         StructuredGraph graph = processMethod(snippet, doLowering);
258         assertDeepEquals(1, graph.getNodes(ReturnNode.TYPE).count());
259         return graph.getNodes(ReturnNode.TYPE).first();
260     }
261 
processMethod(String snippet, boolean doLowering)262     protected StructuredGraph processMethod(String snippet, boolean doLowering) {
263         StructuredGraph graph = parseEager(getResolvedJavaMethod(snippet), AllowAssumptions.NO);
264         HighTierContext context = getDefaultHighTierContext();
265         createInliningPhase().apply(graph, context);
266         if (doLowering) {
267             new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
268         }
269         new EarlyReadEliminationPhase(new CanonicalizerPhase()).apply(graph, context);
270         return graph;
271     }
272 }
273