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