blob: 1cd5c4180acadfdabf1f4b5fba133ddcaddd8788 [file] [log] [blame]
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.compiler.replacements.jdk9;
import jdk.vm.ci.amd64.AMD64;
import jdk.vm.ci.code.TargetDescription;
import jdk.vm.ci.meta.ResolvedJavaMethod;
import org.graalvm.compiler.api.test.Graal;
import org.graalvm.compiler.replacements.test.MethodSubstitutionTest;
import org.graalvm.compiler.runtime.RuntimeProvider;
import org.graalvm.compiler.test.AddExports;
import org.junit.Test;
@AddExports("java.base/jdk.internal.misc")
public class UnsafeReplacementsTest extends MethodSubstitutionTest {
// See GR-9819.
@SuppressWarnings("unused") ResolvedJavaMethod method = null;
static class Container {
public volatile boolean booleanField;
public volatile byte byteField = 17;
public volatile char charField = 1025;
public volatile short shortField = 2232;
public volatile int intField = 0xcafebabe;
public volatile long longField = 0xdedababafafaL;
public volatile float floatField = 0.125f;
public volatile double doubleField = 0.125;
public volatile Object objectField = dummyValue;
}
static jdk.internal.misc.Unsafe unsafe = jdk.internal.misc.Unsafe.getUnsafe();
static Container dummyValue = new Container();
static Container newDummyValue = new Container();
static long booleanOffset;
static long byteOffset;
static long charOffset;
static long shortOffset;
static long intOffset;
static long longOffset;
static long floatOffset;
static long doubleOffset;
static long objectOffset;
static {
try {
booleanOffset = unsafe.objectFieldOffset(Container.class.getDeclaredField("booleanField"));
byteOffset = unsafe.objectFieldOffset(Container.class.getDeclaredField("byteField"));
charOffset = unsafe.objectFieldOffset(Container.class.getDeclaredField("charField"));
shortOffset = unsafe.objectFieldOffset(Container.class.getDeclaredField("shortField"));
intOffset = unsafe.objectFieldOffset(Container.class.getDeclaredField("intField"));
longOffset = unsafe.objectFieldOffset(Container.class.getDeclaredField("longField"));
floatOffset = unsafe.objectFieldOffset(Container.class.getDeclaredField("floatField"));
doubleOffset = unsafe.objectFieldOffset(Container.class.getDeclaredField("doubleField"));
objectOffset = unsafe.objectFieldOffset(Container.class.getDeclaredField("objectField"));
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
}
}
public static boolean unsafeCompareAndSetBoolean() {
Container container = new Container();
return unsafe.compareAndSetBoolean(container, booleanOffset, false, true);
}
public static boolean unsafeCompareAndSetByte() {
Container container = new Container();
return unsafe.compareAndSetByte(container, byteOffset, (byte) 17, (byte) 121);
}
public static boolean unsafeCompareAndSetChar() {
Container container = new Container();
return unsafe.compareAndSetChar(container, charOffset, (char) 1025, (char) 1777);
}
public static boolean unsafeCompareAndSetShort() {
Container container = new Container();
return unsafe.compareAndSetShort(container, shortOffset, (short) 2232, (short) 12111);
}
public static boolean unsafeCompareAndSetInt() {
Container container = new Container();
return unsafe.compareAndSetInt(container, intOffset, 0xcafebabe, 0xbabefafa);
}
public static boolean unsafeCompareAndSetLong() {
Container container = new Container();
return unsafe.compareAndSetLong(container, longOffset, 0xdedababafafaL, 0xfafacecafafadedaL);
}
public static boolean unsafeCompareAndSetFloat() {
Container container = new Container();
return unsafe.compareAndSetFloat(container, floatOffset, 0.125f, 0.25f);
}
public static boolean unsafeCompareAndSetDouble() {
Container container = new Container();
return unsafe.compareAndSetDouble(container, doubleOffset, 0.125, 0.25);
}
public static boolean unsafeCompareAndSetObject() {
Container container = new Container();
return unsafe.compareAndSetObject(container, objectOffset, dummyValue, newDummyValue);
}
public static boolean unsafeCompareAndExchangeBoolean() {
Container container = new Container();
return unsafe.compareAndExchangeBoolean(container, booleanOffset, false, true);
}
public static byte unsafeCompareAndExchangeByte() {
Container container = new Container();
return unsafe.compareAndExchangeByte(container, byteOffset, (byte) 17, (byte) 31);
}
public static char unsafeCompareAndExchangeChar() {
Container container = new Container();
return unsafe.compareAndExchangeChar(container, charOffset, (char) 1025, (char) 4502);
}
public static short unsafeCompareAndExchangeShort() {
Container container = new Container();
return unsafe.compareAndExchangeShort(container, shortOffset, (short) 2232, (short) 8121);
}
public static int unsafeCompareAndExchangeInt() {
Container container = new Container();
return unsafe.compareAndExchangeInt(container, intOffset, 0xcafebabe, 0xbabefafa);
}
public static long unsafeCompareAndExchangeLong() {
Container container = new Container();
return unsafe.compareAndExchangeLong(container, longOffset, 0xdedababafafaL, 0xfafacecafafadedaL);
}
public static float unsafeCompareAndExchangeFloat() {
Container container = new Container();
return unsafe.compareAndExchangeFloat(container, floatOffset, 0.125f, 0.25f);
}
public static double unsafeCompareAndExchangeDouble() {
Container container = new Container();
return unsafe.compareAndExchangeDouble(container, doubleOffset, 0.125, 0.25);
}
public static Object unsafeCompareAndExchangeObject() {
Container container = new Container();
return unsafe.compareAndExchangeObject(container, objectOffset, dummyValue, newDummyValue);
}
@Test
public void testCompareAndSet() {
TargetDescription target = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getTarget();
if (target.arch instanceof AMD64) {
testGraph("unsafeCompareAndSetBoolean");
testGraph("unsafeCompareAndSetByte");
testGraph("unsafeCompareAndSetChar");
testGraph("unsafeCompareAndSetShort");
testGraph("unsafeCompareAndSetInt");
testGraph("unsafeCompareAndSetLong");
testGraph("unsafeCompareAndSetFloat");
testGraph("unsafeCompareAndSetDouble");
testGraph("unsafeCompareAndSetObject");
testGraph("unsafeCompareAndExchangeBoolean");
testGraph("unsafeCompareAndExchangeByte");
testGraph("unsafeCompareAndExchangeChar");
testGraph("unsafeCompareAndExchangeShort");
testGraph("unsafeCompareAndExchangeInt");
testGraph("unsafeCompareAndExchangeLong");
testGraph("unsafeCompareAndExchangeFloat");
testGraph("unsafeCompareAndExchangeDouble");
testGraph("unsafeCompareAndExchangeObject");
}
test("unsafeCompareAndSetBoolean");
test("unsafeCompareAndSetByte");
test("unsafeCompareAndSetChar");
test("unsafeCompareAndSetShort");
test("unsafeCompareAndSetInt");
test("unsafeCompareAndSetLong");
test("unsafeCompareAndSetFloat");
test("unsafeCompareAndSetDouble");
test("unsafeCompareAndSetObject");
test("unsafeCompareAndExchangeBoolean");
test("unsafeCompareAndExchangeByte");
test("unsafeCompareAndExchangeChar");
test("unsafeCompareAndExchangeShort");
test("unsafeCompareAndExchangeInt");
test("unsafeCompareAndExchangeLong");
test("unsafeCompareAndExchangeFloat");
test("unsafeCompareAndExchangeDouble");
test("unsafeCompareAndExchangeObject");
}
public static int unsafeGetAndAddByte() {
Container container = new Container();
return unsafe.getAndAddByte(container, byteOffset, (byte) 2);
}
public static int unsafeGetAndAddChar() {
Container container = new Container();
return unsafe.getAndAddChar(container, charOffset, (char) 250);
}
public static int unsafeGetAndAddShort() {
Container container = new Container();
return unsafe.getAndAddShort(container, shortOffset, (short) 1250);
}
public static int unsafeGetAndAddInt() {
Container container = new Container();
return unsafe.getAndAddInt(container, intOffset, 104501);
}
public static long unsafeGetAndAddLong() {
Container container = new Container();
return unsafe.getAndAddLong(container, longOffset, 0x123456abcdL);
}
@Test
public void testGetAndAdd() {
TargetDescription target = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getTarget();
if (target.arch instanceof AMD64) {
testGraph("unsafeGetAndAddByte");
testGraph("unsafeGetAndAddChar");
testGraph("unsafeGetAndAddShort");
testGraph("unsafeGetAndAddInt");
testGraph("unsafeGetAndAddLong");
}
test("unsafeGetAndAddByte");
test("unsafeGetAndAddChar");
test("unsafeGetAndAddShort");
test("unsafeGetAndAddInt");
test("unsafeGetAndAddLong");
}
public static boolean unsafeGetAndSetBoolean() {
Container container = new Container();
return unsafe.getAndSetBoolean(container, booleanOffset, true);
}
public static byte unsafeGetAndSetByte() {
Container container = new Container();
return unsafe.getAndSetByte(container, byteOffset, (byte) 129);
}
public static char unsafeGetAndSetChar() {
Container container = new Container();
return unsafe.getAndSetChar(container, charOffset, (char) 21111);
}
public static short unsafeGetAndSetShort() {
Container container = new Container();
return unsafe.getAndSetShort(container, shortOffset, (short) 21111);
}
public static int unsafeGetAndSetInt() {
Container container = new Container();
return unsafe.getAndSetInt(container, intOffset, 0x1234af);
}
public static long unsafeGetAndSetLong() {
Container container = new Container();
return unsafe.getAndSetLong(container, longOffset, 0x12345678abL);
}
public static Object unsafeGetAndSetObject() {
Container container = new Container();
container.objectField = null;
Container other = new Container();
return unsafe.getAndSetObject(container, objectOffset, other);
}
@Test
public void testGetAndSet() {
TargetDescription target = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getTarget();
if (target.arch instanceof AMD64) {
testGraph("unsafeGetAndSetBoolean");
testGraph("unsafeGetAndSetByte");
testGraph("unsafeGetAndSetChar");
testGraph("unsafeGetAndSetShort");
testGraph("unsafeGetAndSetInt");
testGraph("unsafeGetAndSetLong");
testGraph("unsafeGetAndSetObject");
}
test("unsafeGetAndSetBoolean");
test("unsafeGetAndSetByte");
test("unsafeGetAndSetChar");
test("unsafeGetAndSetShort");
test("unsafeGetAndSetInt");
test("unsafeGetAndSetLong");
test("unsafeGetAndSetObject");
}
}