20 * or visit www.oracle.com if you need additional information or have any |
20 * or visit www.oracle.com if you need additional information or have any |
21 * questions. |
21 * questions. |
22 */ |
22 */ |
23 package org.graalvm.compiler.core.test.ea; |
23 package org.graalvm.compiler.core.test.ea; |
24 |
24 |
25 import jdk.vm.ci.meta.JavaConstant; |
25 import java.nio.ByteBuffer; |
26 |
26 |
|
27 import org.graalvm.compiler.api.directives.GraalDirectives; |
|
28 import org.graalvm.compiler.graph.Graph; |
|
29 import org.graalvm.compiler.graph.Node; |
|
30 import org.graalvm.compiler.nodes.NamedLocationIdentity; |
|
31 import org.graalvm.compiler.nodes.PhiNode; |
|
32 import org.graalvm.compiler.nodes.ValuePhiNode; |
|
33 import org.graalvm.compiler.nodes.calc.UnpackEndianHalfNode; |
|
34 import org.graalvm.compiler.nodes.extended.RawLoadNode; |
|
35 import org.graalvm.compiler.nodes.extended.RawStoreNode; |
|
36 import org.graalvm.compiler.nodes.extended.UnsafeAccessNode; |
|
37 import org.graalvm.compiler.nodes.java.LoadFieldNode; |
|
38 import org.graalvm.compiler.phases.common.CanonicalizerPhase; |
27 import org.junit.Assert; |
39 import org.junit.Assert; |
28 import org.junit.Test; |
40 import org.junit.Test; |
29 |
41 |
30 import org.graalvm.compiler.nodes.PhiNode; |
42 import jdk.vm.ci.meta.JavaConstant; |
31 import org.graalvm.compiler.nodes.ValuePhiNode; |
43 import jdk.vm.ci.meta.JavaKind; |
32 import org.graalvm.compiler.nodes.java.LoadFieldNode; |
44 import jdk.vm.ci.meta.ResolvedJavaMethod; |
33 |
45 |
34 public class UnsafeEATest extends EATestBase { |
46 public class UnsafeEATest extends EATestBase { |
35 |
47 |
36 public static int zero = 0; |
48 public static int zero = 0; |
37 |
49 |
54 } catch (Exception e) { |
66 } catch (Exception e) { |
55 throw new RuntimeException(e); |
67 throw new RuntimeException(e); |
56 } |
68 } |
57 } |
69 } |
58 |
70 |
|
71 @Override |
|
72 protected void testEscapeAnalysis(String snippet, JavaConstant expectedConstantResult, boolean iterativeEscapeAnalysis) { |
|
73 // Exercise both a graph containing UnsafeAccessNodes and one which has been possibly been |
|
74 // canonicalized into AccessFieldNodes. |
|
75 testingUnsafe = true; |
|
76 super.testEscapeAnalysis(snippet, expectedConstantResult, iterativeEscapeAnalysis); |
|
77 testingUnsafe = false; |
|
78 super.testEscapeAnalysis(snippet, expectedConstantResult, iterativeEscapeAnalysis); |
|
79 if (expectedConstantResult != null) { |
|
80 // Check that a compiled version of this method returns the same value if we expect a |
|
81 // constant result. |
|
82 ResolvedJavaMethod method = getResolvedJavaMethod(snippet); |
|
83 JavaKind[] javaKinds = method.getSignature().toParameterKinds(false); |
|
84 Object[] args = new Object[javaKinds.length]; |
|
85 int i = 0; |
|
86 for (JavaKind k : javaKinds) { |
|
87 args[i++] = JavaConstant.defaultForKind(k).asBoxedPrimitive(); |
|
88 } |
|
89 Result result = executeExpected(method, null, args); |
|
90 assertTrue(result.returnValue.equals(expectedConstantResult.asBoxedPrimitive())); |
|
91 } |
|
92 } |
|
93 |
|
94 @Override |
|
95 protected void canonicalizeGraph() { |
|
96 if (testingUnsafe) { |
|
97 // For testing purposes we'd like to ensure that our raw unsafe operations stay as |
|
98 // unsafe nodes, so force them to appear to have LocationIdentity.any to disable |
|
99 // transformation into field access nodes. |
|
100 for (Node node : graph.getNodes().filter(x -> x instanceof UnsafeAccessNode).snapshot()) { |
|
101 if (node instanceof RawStoreNode) { |
|
102 RawStoreNode store = (RawStoreNode) node; |
|
103 RawStoreNode newStore = graph.add(new RawStoreNode(store.object(), store.offset(), store.value(), store.accessKind(), NamedLocationIdentity.any(), |
|
104 store.needsBarrier(), store.stateAfter(), true)); |
|
105 graph.replaceFixedWithFixed(store, newStore); |
|
106 } else if (node instanceof RawLoadNode) { |
|
107 RawLoadNode load = (RawLoadNode) node; |
|
108 RawLoadNode newLoad = graph.add(new RawLoadNode(load.object(), load.offset(), load.accessKind(), NamedLocationIdentity.any(), |
|
109 true)); |
|
110 graph.replaceFixedWithFixed(load, newLoad); |
|
111 } |
|
112 } |
|
113 } |
|
114 super.canonicalizeGraph(); |
|
115 } |
|
116 |
|
117 @Override |
|
118 protected void postEACanonicalizeGraph() { |
|
119 // Simplify any UnpackEndianHalfNode so we end up with constants. |
|
120 Graph.Mark mark = graph.getMark(); |
|
121 for (UnpackEndianHalfNode node : graph.getNodes().filter(UnpackEndianHalfNode.class)) { |
|
122 node.lower(getTarget().arch.getByteOrder()); |
|
123 } |
|
124 new CanonicalizerPhase().applyIncremental(graph, context, mark); |
|
125 } |
|
126 |
|
127 private boolean testingUnsafe; |
|
128 |
59 @Test |
129 @Test |
60 public void testSimpleInt() { |
130 public void testSimpleInt() { |
61 testEscapeAnalysis("testSimpleIntSnippet", JavaConstant.forInt(101), false); |
131 testEscapeAnalysis("testSimpleIntSnippet", JavaConstant.forInt(101), false); |
62 } |
132 } |
63 |
133 |
85 |
155 |
86 public static double testSimpleDoubleSnippet() { |
156 public static double testSimpleDoubleSnippet() { |
87 TestClassInt x = new TestClassInt(); |
157 TestClassInt x = new TestClassInt(); |
88 UNSAFE.putDouble(x, fieldOffset1, 10.1); |
158 UNSAFE.putDouble(x, fieldOffset1, 10.1); |
89 return UNSAFE.getDouble(x, fieldOffset1); |
159 return UNSAFE.getDouble(x, fieldOffset1); |
|
160 } |
|
161 |
|
162 @Test |
|
163 public void testSimpleDoubleOverwriteWithInt() { |
|
164 testEscapeAnalysis("testSimpleDoubleOverwriteWithIntSnippet", JavaConstant.forInt(10), false); |
|
165 } |
|
166 |
|
167 public static int testSimpleDoubleOverwriteWithIntSnippet() { |
|
168 TestClassInt x = new TestClassInt(); |
|
169 UNSAFE.putDouble(x, fieldOffset1, 10.1); |
|
170 UNSAFE.putInt(x, fieldOffset1, 10); |
|
171 return UNSAFE.getInt(x, fieldOffset1); |
|
172 } |
|
173 |
|
174 @Test |
|
175 public void testSimpleDoubleOverwriteWithSecondInt() { |
|
176 ByteBuffer bb = ByteBuffer.allocate(8).order(getTarget().arch.getByteOrder()); |
|
177 bb.putDouble(10.1); |
|
178 int value = bb.getInt(4); |
|
179 |
|
180 testEscapeAnalysis("testSimpleDoubleOverwriteWithSecondIntSnippet", JavaConstant.forInt(value), false); |
|
181 } |
|
182 |
|
183 public static int testSimpleDoubleOverwriteWithSecondIntSnippet() { |
|
184 TestClassInt x = new TestClassInt(); |
|
185 UNSAFE.putDouble(x, fieldOffset1, 10.1); |
|
186 UNSAFE.putInt(x, fieldOffset1, 10); |
|
187 return UNSAFE.getInt(x, fieldOffset2); |
|
188 } |
|
189 |
|
190 @Test |
|
191 public void testSimpleDoubleOverwriteWithFirstInt() { |
|
192 ByteBuffer bb = ByteBuffer.allocate(8).order(getTarget().arch.getByteOrder()); |
|
193 bb.putDouble(10.1); |
|
194 int value = bb.getInt(0); |
|
195 |
|
196 testEscapeAnalysis("testSimpleDoubleOverwriteWithFirstIntSnippet", JavaConstant.forInt(value), false); |
|
197 } |
|
198 |
|
199 public static int testSimpleDoubleOverwriteWithFirstIntSnippet() { |
|
200 TestClassInt x = new TestClassInt(); |
|
201 UNSAFE.putDouble(x, fieldOffset1, 10.1); |
|
202 UNSAFE.putInt(x, fieldOffset2, 10); |
|
203 return UNSAFE.getInt(x, fieldOffset1); |
|
204 } |
|
205 |
|
206 @Test |
|
207 public void testSimpleLongOverwriteWithSecondInt() { |
|
208 ByteBuffer bb = ByteBuffer.allocate(8).order(getTarget().arch.getByteOrder()); |
|
209 bb.putLong(0, 0x1122334455667788L); |
|
210 int value = bb.getInt(4); |
|
211 |
|
212 testEscapeAnalysis("testSimpleLongOverwriteWithSecondIntSnippet", JavaConstant.forInt(value), false); |
|
213 } |
|
214 |
|
215 public static int testSimpleLongOverwriteWithSecondIntSnippet() { |
|
216 TestClassInt x = new TestClassInt(); |
|
217 UNSAFE.putLong(x, fieldOffset1, 0x1122334455667788L); |
|
218 UNSAFE.putInt(x, fieldOffset1, 10); |
|
219 return UNSAFE.getInt(x, fieldOffset2); |
|
220 } |
|
221 |
|
222 @Test |
|
223 public void testSimpleLongOverwriteWithFirstInt() { |
|
224 ByteBuffer bb = ByteBuffer.allocate(8).order(getTarget().arch.getByteOrder()); |
|
225 bb.putLong(0, 0x1122334455667788L); |
|
226 int value = bb.getInt(0); |
|
227 |
|
228 testEscapeAnalysis("testSimpleLongOverwriteWithFirstIntSnippet", JavaConstant.forInt(value), false); |
|
229 } |
|
230 |
|
231 public static int testSimpleLongOverwriteWithFirstIntSnippet() { |
|
232 TestClassInt x = new TestClassInt(); |
|
233 UNSAFE.putLong(x, fieldOffset1, 0x1122334455667788L); |
|
234 UNSAFE.putInt(x, fieldOffset2, 10); |
|
235 return UNSAFE.getInt(x, fieldOffset1); |
90 } |
236 } |
91 |
237 |
92 @Test |
238 @Test |
93 public void testMergedDouble() { |
239 public void testMergedDouble() { |
94 testEscapeAnalysis("testMergedDoubleSnippet", null, false); |
240 testEscapeAnalysis("testMergedDoubleSnippet", null, false); |
109 UNSAFE.putDouble(x, fieldOffset1, doubleField2); |
255 UNSAFE.putDouble(x, fieldOffset1, doubleField2); |
110 } |
256 } |
111 return UNSAFE.getDouble(x, fieldOffset1); |
257 return UNSAFE.getDouble(x, fieldOffset1); |
112 } |
258 } |
113 |
259 |
|
260 static class ExtendedTestClassInt extends TestClassInt { |
|
261 public long l; |
|
262 } |
|
263 |
|
264 @Test |
|
265 public void testMergedVirtualObjects() { |
|
266 testEscapeAnalysis("testMergedVirtualObjectsSnippet", null, false); |
|
267 } |
|
268 |
|
269 public static TestClassInt testMergedVirtualObjectsSnippet(int value) { |
|
270 TestClassInt x; |
|
271 if (value == 1) { |
|
272 x = new TestClassInt(); |
|
273 UNSAFE.putDouble(x, fieldOffset1, 10); |
|
274 } else { |
|
275 x = new TestClassInt(); |
|
276 UNSAFE.putInt(x, fieldOffset1, 0); |
|
277 } |
|
278 UNSAFE.putInt(x, fieldOffset1, 0); |
|
279 if (value == 2) { |
|
280 UNSAFE.putInt(x, fieldOffset2, 0); |
|
281 } |
|
282 GraalDirectives.deoptimizeAndInvalidate(); |
|
283 return x; |
|
284 } |
|
285 |
114 @Test |
286 @Test |
115 public void testMaterializedDouble() { |
287 public void testMaterializedDouble() { |
116 test("testMaterializedDoubleSnippet"); |
288 test("testMaterializedDoubleSnippet"); |
117 } |
289 } |
118 |
290 |