1 /*
   2  * Copyright (c) 2017, 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.core.test;
  24 
  25 import java.lang.reflect.Field;
  26 
  27 import org.graalvm.compiler.nodes.NamedLocationIdentity;
  28 import org.graalvm.compiler.nodes.memory.ReadNode;
  29 import org.junit.Assert;
  30 import org.junit.Test;
  31 
  32 import jdk.vm.ci.meta.JavaKind;
  33 import sun.misc.Unsafe;
  34 
  35 /**
  36  * Tests that off-heap memory writes don't prevent optimization of on-heap accesses.
  37  */
  38 public class OffHeapUnsafeAccessTest extends GraalCompilerTest {
  39 
  40     static final Unsafe UNSAFE = initUnsafe();
  41 
  42     private static Unsafe initUnsafe() {
  43         try {
  44             // Fast path when we are trusted.
  45             return Unsafe.getUnsafe();
  46         } catch (SecurityException se) {
  47             // Slow path when we are not trusted.
  48             try {
  49                 Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
  50                 theUnsafe.setAccessible(true);
  51                 return (Unsafe) theUnsafe.get(Unsafe.class);
  52             } catch (Exception e) {
  53                 throw new RuntimeException("exception while trying to get Unsafe", e);
  54             }
  55         }
  56     }
  57 
  58     public byte unboxByteAndStore(long memory, byte[] box) {
  59         byte val = box[0];
  60         UNSAFE.putByte(memory, val);
  61         UNSAFE.putByte(null, memory, val);
  62         return box[0];
  63     }
  64 
  65     public char unboxCharAndStore(long memory, char[] box) {
  66         char val = box[0];
  67         UNSAFE.putChar(memory, val);
  68         UNSAFE.putChar(null, memory, val);
  69         return box[0];
  70     }
  71 
  72     public int unboxIntAndStore(long memory, int[] box) {
  73         int val = box[0];
  74         UNSAFE.putInt(memory, val);
  75         UNSAFE.putInt(null, memory, val);
  76         return box[0];
  77     }
  78 
  79     public long unboxLongAndStore(long memory, long[] box) {
  80         long val = box[0];
  81         UNSAFE.putLong(memory, val);
  82         UNSAFE.putLong(null, memory, val);
  83         UNSAFE.putAddress(memory, val);
  84         return box[0];
  85     }
  86 
  87     public float unboxFloatAndStore(long memory, float[] box) {
  88         float val = box[0];
  89         UNSAFE.putFloat(memory, val);
  90         UNSAFE.putFloat(null, memory, val);
  91         return box[0];
  92     }
  93 
  94     public double unboxDoubleAndStore(long memory, double[] box) {
  95         double val = box[0];
  96         UNSAFE.putDouble(memory, val);
  97         UNSAFE.putDouble(null, memory, val);
  98         return box[0];
  99     }
 100 
 101     private void assertExactlyOneArrayLoad(JavaKind elementKind) {
 102         int total = 0;
 103         for (ReadNode read : lastCompiledGraph.getNodes().filter(ReadNode.class)) {
 104             if (read.getLocationIdentity().equals(NamedLocationIdentity.getArrayLocation(elementKind))) {
 105                 total++;
 106             }
 107         }
 108         Assert.assertEquals(1, total);
 109     }
 110 
 111     @Test
 112     public void testGet() {
 113         long buf = allocBuf();
 114         if (buf != 0) {
 115             try {
 116                 test("unboxByteAndStore", buf, new byte[]{40});
 117                 assertExactlyOneArrayLoad(JavaKind.Byte);
 118 
 119                 test("unboxCharAndStore", buf, new char[]{41});
 120                 assertExactlyOneArrayLoad(JavaKind.Char);
 121 
 122                 test("unboxIntAndStore", buf, new int[]{42});
 123                 assertExactlyOneArrayLoad(JavaKind.Int);
 124 
 125                 test("unboxLongAndStore", buf, new long[]{43});
 126                 assertExactlyOneArrayLoad(JavaKind.Long);
 127 
 128                 test("unboxFloatAndStore", buf, new float[]{44.0F});
 129                 assertExactlyOneArrayLoad(JavaKind.Float);
 130 
 131                 test("unboxDoubleAndStore", buf, new double[]{45.0D});
 132                 assertExactlyOneArrayLoad(JavaKind.Double);
 133             } finally {
 134                 UNSAFE.freeMemory(buf);
 135             }
 136         }
 137     }
 138 
 139     protected long allocBuf() {
 140         try {
 141             return UNSAFE.allocateMemory(16);
 142         } catch (OutOfMemoryError e) {
 143             return 0L;
 144         }
 145     }
 146 }