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