1 /*
2  * Copyright (c) 2013, 2016, 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.replacements.test;
26 
27 import org.graalvm.compiler.api.replacements.Snippet;
28 import org.graalvm.compiler.nodes.NamedLocationIdentity;
29 import org.graalvm.compiler.nodes.NodeView;
30 import org.graalvm.compiler.nodes.ReturnNode;
31 import org.graalvm.compiler.nodes.StructuredGraph;
32 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
33 import org.graalvm.compiler.nodes.ValueNode;
34 import org.graalvm.compiler.nodes.calc.ConvertNode;
35 import org.graalvm.compiler.nodes.calc.SignExtendNode;
36 import org.graalvm.compiler.nodes.extended.JavaReadNode;
37 import org.graalvm.compiler.nodes.extended.JavaWriteNode;
38 import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
39 import org.graalvm.compiler.phases.OptimisticOptimizations;
40 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
41 import org.graalvm.compiler.phases.tiers.HighTierContext;
42 import org.graalvm.compiler.word.Word;
43 import org.graalvm.compiler.word.WordCastNode;
44 import jdk.internal.vm.compiler.word.LocationIdentity;
45 import jdk.internal.vm.compiler.word.Pointer;
46 import jdk.internal.vm.compiler.word.WordFactory;
47 import org.junit.Assert;
48 import org.junit.Test;
49 
50 import jdk.vm.ci.code.BytecodeFrame;
51 import jdk.vm.ci.code.TargetDescription;
52 import jdk.vm.ci.meta.JavaKind;
53 
54 /**
55  * Tests for the {@link Pointer} read and write operations.
56  */
57 public class PointerTest extends SnippetsTest {
58 
59     private static final LocationIdentity ID = NamedLocationIdentity.mutable("ID");
60     private static final JavaKind[] KINDS = new JavaKind[]{JavaKind.Byte, JavaKind.Char, JavaKind.Short, JavaKind.Int, JavaKind.Long, JavaKind.Float, JavaKind.Double, JavaKind.Object};
61     private final TargetDescription target;
62 
PointerTest()63     public PointerTest() {
64         target = getCodeCache().getTarget();
65     }
66 
67     @Test
testRead1()68     public void testRead1() {
69         for (JavaKind kind : KINDS) {
70             assertRead(parseEager("read" + kind.name() + "1", AllowAssumptions.YES), kind, true, ID);
71         }
72     }
73 
74     @Test
testRead2()75     public void testRead2() {
76         for (JavaKind kind : KINDS) {
77             assertRead(parseEager("read" + kind.name() + "2", AllowAssumptions.YES), kind, true, ID);
78         }
79     }
80 
81     @Test
testRead3()82     public void testRead3() {
83         for (JavaKind kind : KINDS) {
84             assertRead(parseEager("read" + kind.name() + "3", AllowAssumptions.YES), kind, true, LocationIdentity.any());
85         }
86     }
87 
88     @Test
testWrite1()89     public void testWrite1() {
90         for (JavaKind kind : KINDS) {
91             assertWrite(parseEager("write" + kind.name() + "1", AllowAssumptions.YES), kind, true, ID);
92         }
93     }
94 
95     @Test
testWrite2()96     public void testWrite2() {
97         for (JavaKind kind : KINDS) {
98             assertWrite(parseEager("write" + kind.name() + "2", AllowAssumptions.YES), kind, true, ID);
99         }
100     }
101 
102     @Test
testWrite3()103     public void testWrite3() {
104         for (JavaKind kind : KINDS) {
105             assertWrite(parseEager("write" + kind.name() + "3", AllowAssumptions.YES), kind, true, LocationIdentity.any());
106         }
107     }
108 
assertRead(StructuredGraph graph, JavaKind kind, boolean indexConvert, LocationIdentity locationIdentity)109     private void assertRead(StructuredGraph graph, JavaKind kind, boolean indexConvert, LocationIdentity locationIdentity) {
110         WordCastNode cast = (WordCastNode) graph.start().next();
111 
112         JavaReadNode read = (JavaReadNode) cast.next();
113         Assert.assertEquals(kind.getStackKind(), read.stamp(NodeView.DEFAULT).getStackKind());
114 
115         OffsetAddressNode address = (OffsetAddressNode) read.getAddress();
116         Assert.assertEquals(cast, address.getBase());
117         Assert.assertEquals(graph.getParameter(0), cast.getInput());
118         Assert.assertEquals(target.wordJavaKind, cast.stamp(NodeView.DEFAULT).getStackKind());
119 
120         Assert.assertEquals(locationIdentity, read.getLocationIdentity());
121 
122         if (indexConvert) {
123             SignExtendNode convert = (SignExtendNode) address.getOffset();
124             Assert.assertEquals(convert.getInputBits(), 32);
125             Assert.assertEquals(convert.getResultBits(), 64);
126             Assert.assertEquals(graph.getParameter(1), convert.getValue());
127         } else {
128             Assert.assertEquals(graph.getParameter(1), address.getOffset());
129         }
130 
131         ReturnNode ret = (ReturnNode) read.next();
132         Assert.assertEquals(read, ret.result());
133     }
134 
assertWrite(StructuredGraph graph, JavaKind kind, boolean indexConvert, LocationIdentity locationIdentity)135     private void assertWrite(StructuredGraph graph, JavaKind kind, boolean indexConvert, LocationIdentity locationIdentity) {
136         WordCastNode cast = (WordCastNode) graph.start().next();
137 
138         JavaWriteNode write = (JavaWriteNode) cast.next();
139         ValueNode valueNode = write.value();
140         if (kind != kind.getStackKind()) {
141             while (valueNode instanceof ConvertNode) {
142                 valueNode = ((ConvertNode) valueNode).getValue();
143             }
144         }
145         Assert.assertEquals(graph.getParameter(2), valueNode);
146         Assert.assertEquals(BytecodeFrame.AFTER_BCI, write.stateAfter().bci);
147 
148         OffsetAddressNode address = (OffsetAddressNode) write.getAddress();
149         Assert.assertEquals(cast, address.getBase());
150         Assert.assertEquals(graph.getParameter(0), cast.getInput());
151         Assert.assertEquals(target.wordJavaKind, cast.stamp(NodeView.DEFAULT).getStackKind());
152 
153         Assert.assertEquals(locationIdentity, write.getLocationIdentity());
154 
155         if (indexConvert) {
156             SignExtendNode convert = (SignExtendNode) address.getOffset();
157             Assert.assertEquals(convert.getInputBits(), 32);
158             Assert.assertEquals(convert.getResultBits(), 64);
159             Assert.assertEquals(graph.getParameter(1), convert.getValue());
160         } else {
161             Assert.assertEquals(graph.getParameter(1), address.getOffset());
162         }
163 
164         ReturnNode ret = (ReturnNode) write.next();
165         Assert.assertEquals(null, ret.result());
166     }
167 
168     @Snippet
readByte1(Object o, int offset)169     public static byte readByte1(Object o, int offset) {
170         return Word.objectToTrackedPointer(o).readByte(offset, ID);
171     }
172 
173     @Snippet
readByte2(Object o, int offset)174     public static byte readByte2(Object o, int offset) {
175         return Word.objectToTrackedPointer(o).readByte(WordFactory.signed(offset), ID);
176     }
177 
178     @Snippet
readByte3(Object o, int offset)179     public static byte readByte3(Object o, int offset) {
180         return Word.objectToTrackedPointer(o).readByte(offset);
181     }
182 
183     @Snippet
writeByte1(Object o, int offset, byte value)184     public static void writeByte1(Object o, int offset, byte value) {
185         Word.objectToTrackedPointer(o).writeByte(offset, value, ID);
186     }
187 
188     @Snippet
writeByte2(Object o, int offset, byte value)189     public static void writeByte2(Object o, int offset, byte value) {
190         Word.objectToTrackedPointer(o).writeByte(WordFactory.signed(offset), value, ID);
191     }
192 
193     @Snippet
writeByte3(Object o, int offset, byte value)194     public static void writeByte3(Object o, int offset, byte value) {
195         Word.objectToTrackedPointer(o).writeByte(offset, value);
196     }
197 
198     @Snippet
readChar1(Object o, int offset)199     public static char readChar1(Object o, int offset) {
200         return Word.objectToTrackedPointer(o).readChar(offset, ID);
201     }
202 
203     @Snippet
readChar2(Object o, int offset)204     public static char readChar2(Object o, int offset) {
205         return Word.objectToTrackedPointer(o).readChar(WordFactory.signed(offset), ID);
206     }
207 
208     @Snippet
readChar3(Object o, int offset)209     public static char readChar3(Object o, int offset) {
210         return Word.objectToTrackedPointer(o).readChar(offset);
211     }
212 
213     @Snippet
writeChar1(Object o, int offset, char value)214     public static void writeChar1(Object o, int offset, char value) {
215         Word.objectToTrackedPointer(o).writeChar(offset, value, ID);
216     }
217 
218     @Snippet
writeChar2(Object o, int offset, char value)219     public static void writeChar2(Object o, int offset, char value) {
220         Word.objectToTrackedPointer(o).writeChar(WordFactory.signed(offset), value, ID);
221     }
222 
223     @Snippet
writeChar3(Object o, int offset, char value)224     public static void writeChar3(Object o, int offset, char value) {
225         Word.objectToTrackedPointer(o).writeChar(offset, value);
226     }
227 
228     @Snippet
readShort1(Object o, int offset)229     public static short readShort1(Object o, int offset) {
230         return Word.objectToTrackedPointer(o).readShort(offset, ID);
231     }
232 
233     @Snippet
readShort2(Object o, int offset)234     public static short readShort2(Object o, int offset) {
235         return Word.objectToTrackedPointer(o).readShort(WordFactory.signed(offset), ID);
236     }
237 
238     @Snippet
readShort3(Object o, int offset)239     public static short readShort3(Object o, int offset) {
240         return Word.objectToTrackedPointer(o).readShort(offset);
241     }
242 
243     @Snippet
writeShort1(Object o, int offset, short value)244     public static void writeShort1(Object o, int offset, short value) {
245         Word.objectToTrackedPointer(o).writeShort(offset, value, ID);
246     }
247 
248     @Snippet
writeShort2(Object o, int offset, short value)249     public static void writeShort2(Object o, int offset, short value) {
250         Word.objectToTrackedPointer(o).writeShort(WordFactory.signed(offset), value, ID);
251     }
252 
253     @Snippet
writeShort3(Object o, int offset, short value)254     public static void writeShort3(Object o, int offset, short value) {
255         Word.objectToTrackedPointer(o).writeShort(offset, value);
256     }
257 
258     @Snippet
readInt1(Object o, int offset)259     public static int readInt1(Object o, int offset) {
260         return Word.objectToTrackedPointer(o).readInt(offset, ID);
261     }
262 
263     @Snippet
readInt2(Object o, int offset)264     public static int readInt2(Object o, int offset) {
265         return Word.objectToTrackedPointer(o).readInt(WordFactory.signed(offset), ID);
266     }
267 
268     @Snippet
readInt3(Object o, int offset)269     public static int readInt3(Object o, int offset) {
270         return Word.objectToTrackedPointer(o).readInt(offset);
271     }
272 
273     @Snippet
writeInt1(Object o, int offset, int value)274     public static void writeInt1(Object o, int offset, int value) {
275         Word.objectToTrackedPointer(o).writeInt(offset, value, ID);
276     }
277 
278     @Snippet
writeInt2(Object o, int offset, int value)279     public static void writeInt2(Object o, int offset, int value) {
280         Word.objectToTrackedPointer(o).writeInt(WordFactory.signed(offset), value, ID);
281     }
282 
283     @Snippet
writeInt3(Object o, int offset, int value)284     public static void writeInt3(Object o, int offset, int value) {
285         Word.objectToTrackedPointer(o).writeInt(offset, value);
286     }
287 
288     @Snippet
readLong1(Object o, int offset)289     public static long readLong1(Object o, int offset) {
290         return Word.objectToTrackedPointer(o).readLong(offset, ID);
291     }
292 
293     @Snippet
readLong2(Object o, int offset)294     public static long readLong2(Object o, int offset) {
295         return Word.objectToTrackedPointer(o).readLong(WordFactory.signed(offset), ID);
296     }
297 
298     @Snippet
readLong3(Object o, int offset)299     public static long readLong3(Object o, int offset) {
300         return Word.objectToTrackedPointer(o).readLong(offset);
301     }
302 
303     @Snippet
writeLong1(Object o, int offset, long value)304     public static void writeLong1(Object o, int offset, long value) {
305         Word.objectToTrackedPointer(o).writeLong(offset, value, ID);
306     }
307 
308     @Snippet
writeLong2(Object o, int offset, long value)309     public static void writeLong2(Object o, int offset, long value) {
310         Word.objectToTrackedPointer(o).writeLong(WordFactory.signed(offset), value, ID);
311     }
312 
313     @Snippet
writeLong3(Object o, int offset, long value)314     public static void writeLong3(Object o, int offset, long value) {
315         Word.objectToTrackedPointer(o).writeLong(offset, value);
316     }
317 
318     @Snippet
readFloat1(Object o, int offset)319     public static float readFloat1(Object o, int offset) {
320         return Word.objectToTrackedPointer(o).readFloat(offset, ID);
321     }
322 
323     @Snippet
readFloat2(Object o, int offset)324     public static float readFloat2(Object o, int offset) {
325         return Word.objectToTrackedPointer(o).readFloat(WordFactory.signed(offset), ID);
326     }
327 
328     @Snippet
readFloat3(Object o, int offset)329     public static float readFloat3(Object o, int offset) {
330         return Word.objectToTrackedPointer(o).readFloat(offset);
331     }
332 
333     @Snippet
writeFloat1(Object o, int offset, float value)334     public static void writeFloat1(Object o, int offset, float value) {
335         Word.objectToTrackedPointer(o).writeFloat(offset, value, ID);
336     }
337 
338     @Snippet
writeFloat2(Object o, int offset, float value)339     public static void writeFloat2(Object o, int offset, float value) {
340         Word.objectToTrackedPointer(o).writeFloat(WordFactory.signed(offset), value, ID);
341     }
342 
343     @Snippet
writeFloat3(Object o, int offset, float value)344     public static void writeFloat3(Object o, int offset, float value) {
345         Word.objectToTrackedPointer(o).writeFloat(offset, value);
346     }
347 
348     @Snippet
readDouble1(Object o, int offset)349     public static double readDouble1(Object o, int offset) {
350         return Word.objectToTrackedPointer(o).readDouble(offset, ID);
351     }
352 
353     @Snippet
readDouble2(Object o, int offset)354     public static double readDouble2(Object o, int offset) {
355         return Word.objectToTrackedPointer(o).readDouble(WordFactory.signed(offset), ID);
356     }
357 
358     @Snippet
readDouble3(Object o, int offset)359     public static double readDouble3(Object o, int offset) {
360         return Word.objectToTrackedPointer(o).readDouble(offset);
361     }
362 
363     @Snippet
writeDouble1(Object o, int offset, double value)364     public static void writeDouble1(Object o, int offset, double value) {
365         Word.objectToTrackedPointer(o).writeDouble(offset, value, ID);
366     }
367 
368     @Snippet
writeDouble2(Object o, int offset, double value)369     public static void writeDouble2(Object o, int offset, double value) {
370         Word.objectToTrackedPointer(o).writeDouble(WordFactory.signed(offset), value, ID);
371     }
372 
373     @Snippet
writeDouble3(Object o, int offset, double value)374     public static void writeDouble3(Object o, int offset, double value) {
375         Word.objectToTrackedPointer(o).writeDouble(offset, value);
376     }
377 
378     @Snippet
readObject1(Object o, int offset)379     public static Object readObject1(Object o, int offset) {
380         return Word.objectToTrackedPointer(o).readObject(offset, ID);
381     }
382 
383     @Snippet
readObject2(Object o, int offset)384     public static Object readObject2(Object o, int offset) {
385         return Word.objectToTrackedPointer(o).readObject(WordFactory.signed(offset), ID);
386     }
387 
388     @Snippet
readObject3(Object o, int offset)389     public static Object readObject3(Object o, int offset) {
390         return Word.objectToTrackedPointer(o).readObject(offset);
391     }
392 
393     @Snippet
writeObject1(Object o, int offset, Object value)394     public static void writeObject1(Object o, int offset, Object value) {
395         Word.objectToTrackedPointer(o).writeObject(offset, value, ID);
396     }
397 
398     @Snippet
writeObject2(Object o, int offset, Object value)399     public static void writeObject2(Object o, int offset, Object value) {
400         Word.objectToTrackedPointer(o).writeObject(WordFactory.signed(offset), value, ID);
401     }
402 
403     @Snippet
writeObject3(Object o, int offset, Object value)404     public static void writeObject3(Object o, int offset, Object value) {
405         Word.objectToTrackedPointer(o).writeObject(offset, value);
406     }
407 
assertNumWordCasts(String snippetName, int expectedWordCasts)408     private void assertNumWordCasts(String snippetName, int expectedWordCasts) {
409         HighTierContext context = new HighTierContext(getProviders(), null, OptimisticOptimizations.ALL);
410 
411         StructuredGraph graph = parseEager(snippetName, AllowAssumptions.YES);
412         new CanonicalizerPhase().apply(graph, context);
413         Assert.assertEquals(expectedWordCasts, graph.getNodes().filter(WordCastNode.class).count());
414     }
415 
416     @Test
testUnusedFromObject()417     public void testUnusedFromObject() {
418         assertNumWordCasts("unusedFromObject", 0);
419     }
420 
421     @Snippet
unusedFromObject(Object o)422     public static void unusedFromObject(Object o) {
423         Word.objectToTrackedPointer(o);
424     }
425 
426     @Test
testUnusedRawValue()427     public void testUnusedRawValue() {
428         assertNumWordCasts("unusedRawValue", 0);
429     }
430 
431     @Snippet
unusedRawValue(Object o)432     public static void unusedRawValue(Object o) {
433         Word.objectToTrackedPointer(o).rawValue();
434     }
435 
436     @Test
testUsedRawValue()437     public void testUsedRawValue() {
438         assertNumWordCasts("usedRawValue", 1);
439     }
440 
441     @Snippet
usedRawValue(Object o)442     public static long usedRawValue(Object o) {
443         return Word.objectToTrackedPointer(o).rawValue();
444     }
445 
446     @Test
testUnusedToObject()447     public void testUnusedToObject() {
448         assertNumWordCasts("unusedToObject", 0);
449     }
450 
451     @Snippet
unusedToObject(Word w)452     public static void unusedToObject(Word w) {
453         w.toObject();
454     }
455 
456     @Test
testUsedToObject()457     public void testUsedToObject() {
458         assertNumWordCasts("usedToObject", 1);
459     }
460 
461     @Snippet
usedToObject(Word w)462     public static Object usedToObject(Word w) {
463         return w.toObject();
464     }
465 }
466