/*
* Copyright (c) 2015, 2017, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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 com.oracle.svm.core.jdk;
import org.graalvm.compiler.serviceprovider.GraalUnsafeAccess;
import org.graalvm.word.PointerBase;
import org.graalvm.word.UnsignedWord;
import org.graalvm.word.WordBase;
import org.graalvm.word.WordFactory;
import com.oracle.svm.core.annotate.Uninterruptible;
import com.oracle.svm.core.util.VMError;
// Checkstyle: stop
import sun.misc.Unsafe;
// Checkstyle: resume
Annotated replacements to be called from uninterruptible code for methods whose source I do not
control, and so can not annotate.
For each of these methods I have to inline the body of the method I am replacing. This is a
maintenance nightmare. Fortunately these methods are simple.
/**
* Annotated replacements to be called from uninterruptible code for methods whose source I do not
* control, and so can not annotate.
*
* For each of these methods I have to inline the body of the method I am replacing. This is a
* maintenance nightmare. Fortunately these methods are simple.
*/
public class UninterruptibleUtils {
public static class AtomicInteger {
private static final Unsafe UNSAFE = GraalUnsafeAccess.getUnsafe();
private static final long VALUE_OFFSET;
static {
try {
VALUE_OFFSET = UNSAFE.objectFieldOffset(AtomicInteger.class.getDeclaredField("value"));
} catch (Throwable ex) {
throw VMError.shouldNotReachHere(ex);
}
}
private volatile int value;
public AtomicInteger(int value) {
this.value = value;
}
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
public int get() {
return value;
}
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
public void set(int newValue) {
value = newValue;
}
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
public int incrementAndGet() {
return UNSAFE.getAndAddInt(this, VALUE_OFFSET, 1) + 1;
}
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
public int getAndDecrement() {
return UNSAFE.getAndAddInt(this, VALUE_OFFSET, -1);
}
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
public int decrementAndGet() {
return UNSAFE.getAndAddInt(this, VALUE_OFFSET, -1) - 1;
}
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
public boolean compareAndSet(int expected, int update) {
return UNSAFE.compareAndSwapInt(this, VALUE_OFFSET, expected, update);
}
}
public static class AtomicLong {
private static final Unsafe UNSAFE = GraalUnsafeAccess.getUnsafe();
private static final long VALUE_OFFSET;
static {
try {
VALUE_OFFSET = UNSAFE.objectFieldOffset(AtomicLong.class.getDeclaredField("value"));
} catch (Throwable ex) {
throw VMError.shouldNotReachHere(ex);
}
}
private volatile long value;
public AtomicLong(long value) {
this.value = value;
}
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
public long get() {
return value;
}
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
public void set(long newValue) {
value = newValue;
}
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
public long getAndSet(long newValue) {
return UNSAFE.getAndSetLong(this, VALUE_OFFSET, newValue);
}
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
public long getAndAdd(long delta) {
return UNSAFE.getAndAddLong(this, VALUE_OFFSET, delta);
}
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
public long addAndGet(long delta) {
return getAndAdd(delta) + delta;
}
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
public long incrementAndGet() {
return addAndGet(1);
}
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
public long decrementAndGet() {
return addAndGet(-1);
}
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
public long getAndDecrement() {
return getAndAdd(-1);
}
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
public boolean compareAndSet(long expected, long update) {
return UNSAFE.compareAndSwapLong(this, VALUE_OFFSET, expected, update);
}
}
A word
value that may be updated atomically. See the atomic
package specification for description of the properties of atomic variables. Similar to AtomicReference
, but for word
types. A dedicated implementation is necessary because Object and word types cannot be mixed. /**
* A {@link WordBase word} value that may be updated atomically. See the
* {@link java.util.concurrent.atomic} package specification for description of the properties
* of atomic variables.
*
* Similar to {@link AtomicReference}, but for {@link WordBase word} types. A dedicated
* implementation is necessary because Object and word types cannot be mixed.
*/
public static class AtomicWord<T extends WordBase> {
For simplicity, we convert the word value to a long and delegate to existing atomic
operations.
/**
* For simplicity, we convert the word value to a long and delegate to existing atomic
* operations.
*/
protected final AtomicLong value;
Creates a new AtomicWord with initial value WordFactory.zero
. /**
* Creates a new AtomicWord with initial value {@link WordFactory#zero}.
*/
public AtomicWord() {
value = new AtomicLong(0L);
}
Gets the current value.
Returns: the current value
/**
* Gets the current value.
*
* @return the current value
*/
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
public final T get() {
return WordFactory.unsigned(value.get());
}
Sets to the given value.
Params: - newValue – the new value
/**
* Sets to the given value.
*
* @param newValue the new value
*/
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
public final void set(T newValue) {
value.set(newValue.rawValue());
}
Atomically sets to the given value and returns the old value.
Params: - newValue – the new value
Returns: the previous value
/**
* Atomically sets to the given value and returns the old value.
*
* @param newValue the new value
* @return the previous value
*/
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
public final T getAndSet(T newValue) {
return WordFactory.unsigned(value.getAndSet(newValue.rawValue()));
}
Atomically sets the value to the given updated value if the current value ==
the expected value. Params: - expect – the expected value
- update – the new value
Returns: true
if successful. False return indicates that the actual value was not equal to the expected value.
/**
* Atomically sets the value to the given updated value if the current value {@code ==} the
* expected value.
*
* @param expect the expected value
* @param update the new value
* @return {@code true} if successful. False return indicates that the actual value was not
* equal to the expected value.
*/
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
public final boolean compareAndSet(T expect, T update) {
return value.compareAndSet(expect.rawValue(), update.rawValue());
}
}
A UnsignedWord
value that may be updated atomically. See the atomic
package specification for description of the properties of atomic variables. /**
* A {@link UnsignedWord} value that may be updated atomically. See the
* {@link java.util.concurrent.atomic} package specification for description of the properties
* of atomic variables.
*/
public static class AtomicUnsigned extends AtomicWord<UnsignedWord> {
Atomically adds the given value to the current value.
Params: - delta – the value to add
Returns: the previous value
/**
* Atomically adds the given value to the current value.
*
* @param delta the value to add
* @return the previous value
*/
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
public final UnsignedWord getAndAdd(UnsignedWord delta) {
return WordFactory.unsigned(value.getAndAdd(delta.rawValue()));
}
Atomically adds the given value to the current value.
Params: - delta – the value to add
Returns: the updated value
/**
* Atomically adds the given value to the current value.
*
* @param delta the value to add
* @return the updated value
*/
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
public final UnsignedWord addAndGet(UnsignedWord delta) {
return WordFactory.unsigned(value.addAndGet(delta.rawValue()));
}
Atomically subtracts the given value from the current value.
Params: - delta – the value to add
Returns: the previous value
/**
* Atomically subtracts the given value from the current value.
*
* @param delta the value to add
* @return the previous value
*/
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
public final UnsignedWord getAndSubtract(UnsignedWord delta) {
return WordFactory.unsigned(value.getAndAdd(-delta.rawValue()));
}
Atomically subtracts the given value from the current value.
Params: - delta – the value to add
Returns: the updated value
/**
* Atomically subtracts the given value from the current value.
*
* @param delta the value to add
* @return the updated value
*/
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
public final UnsignedWord subtractAndGet(UnsignedWord delta) {
return WordFactory.unsigned(value.addAndGet(-delta.rawValue()));
}
}
public static class AtomicPointer<T extends PointerBase> {
private static final Unsafe UNSAFE = GraalUnsafeAccess.getUnsafe();
private static final long VALUE_OFFSET;
static {
try {
VALUE_OFFSET = UNSAFE.objectFieldOffset(AtomicPointer.class.getDeclaredField("value"));
} catch (Throwable ex) {
throw VMError.shouldNotReachHere(ex);
}
}
private volatile long value;
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
public T get() {
return WordFactory.pointer(value);
}
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
public void set(T newValue) {
value = newValue.rawValue();
}
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
public boolean compareAndSet(T expected, T update) {
return UNSAFE.compareAndSwapLong(this, VALUE_OFFSET, expected.rawValue(), update.rawValue());
}
}
public static class AtomicReference<T> {
private static final Unsafe UNSAFE = GraalUnsafeAccess.getUnsafe();
private static final long VALUE_OFFSET;
static {
try {
VALUE_OFFSET = UNSAFE.objectFieldOffset(AtomicReference.class.getDeclaredField("value"));
} catch (Throwable ex) {
throw VMError.shouldNotReachHere(ex);
}
}
private volatile T value;
public AtomicReference() {
}
public AtomicReference(T value) {
this.value = value;
}
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
public T get() {
return value;
}
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
public void set(T newValue) {
value = newValue;
}
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
public boolean compareAndSet(T expected, T update) {
return UNSAFE.compareAndSwapObject(this, VALUE_OFFSET, expected, update);
}
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
@SuppressWarnings("unchecked")
public final T getAndSet(T newValue) {
return (T) UNSAFE.getAndSetObject(this, VALUE_OFFSET, newValue);
}
}
Methods like the ones from Math
but annotated as uninterruptible. /** Methods like the ones from {@link java.lang.Math} but annotated as uninterruptible. */
public static class Math {
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
public static int min(int a, int b) {
return (a <= b) ? a : b;
}
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
public static int max(int a, int b) {
return (a >= b) ? a : b;
}
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
public static long max(long a, long b) {
return (a >= b) ? a : b;
}
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
public static long abs(long a) {
return (a < 0) ? -a : a;
}
}
public static class Long {
Uninterruptible version of Long.numberOfLeadingZeros(long)
. /** Uninterruptible version of {@link java.lang.Long#numberOfLeadingZeros(long)}. */
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
// Checkstyle: stop
public static int numberOfLeadingZeros(long i) {
// @formatter:off
// HD, Figure 5-6
if (i == 0)
return 64;
int n = 1;
int x = (int)(i >>> 32);
if (x == 0) { n += 32; x = (int)i; }
if (x >>> 16 == 0) { n += 16; x <<= 16; }
if (x >>> 24 == 0) { n += 8; x <<= 8; }
if (x >>> 28 == 0) { n += 4; x <<= 4; }
if (x >>> 30 == 0) { n += 2; x <<= 2; }
n -= x >>> 31;
return n;
// @formatter:on
}
// Checkstyle: resume
}
public static class Integer {
// Checkstyle: stop
Uninterruptible version of Integer.numberOfLeadingZeros(int)
. /** Uninterruptible version of {@link java.lang.Integer#numberOfLeadingZeros(int)}. */
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
@SuppressWarnings("all")
public static int numberOfLeadingZeros(int i) {
// @formatter:off
// HD, Figure 5-6
if (i == 0)
return 32;
int n = 1;
if (i >>> 16 == 0) { n += 16; i <<= 16; }
if (i >>> 24 == 0) { n += 8; i <<= 8; }
if (i >>> 28 == 0) { n += 4; i <<= 4; }
if (i >>> 30 == 0) { n += 2; i <<= 2; }
n -= i >>> 31;
return n;
// @formatter:on
}
Uninterruptible version of Integer.highestOneBit(int)
. /** Uninterruptible version of {@link java.lang.Integer#highestOneBit(int)}. */
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
@SuppressWarnings("all")
public static int highestOneBit(int i) {
// @formatter:off
// HD, Figure 3-1
i |= (i >> 1);
i |= (i >> 2);
i |= (i >> 4);
i |= (i >> 8);
i |= (i >> 16);
return i - (i >>> 1);
// @formatter:on
}
// Checkstyle: resume
Uninterruptible version of Integer.compare(int, int)
. /** Uninterruptible version of {@link java.lang.Integer#compare(int, int)}. */
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
public static int compare(int x, int y) {
return (x < y) ? -1 : ((x == y) ? 0 : 1);
}
Uninterruptible version of Integer.compareUnsigned(int, int)
. /** Uninterruptible version of {@link java.lang.Integer#compareUnsigned(int, int)}. */
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
public static int compareUnsigned(int x, int y) {
return compare(x + java.lang.Integer.MIN_VALUE, y + java.lang.Integer.MIN_VALUE);
}
}
}