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