8256477: Specialize heap memory segment implementations

Reviewed-by: jvernee, chegar
This commit is contained in:
Maurizio Cimadamore 2020-11-18 10:23:20 +00:00
parent 97074969a5
commit d2ddf07461
4 changed files with 183 additions and 47 deletions

View File

@ -691,7 +691,7 @@ for (long l = 0; l < segment.byteSize(); l++) {
* @return a new confined array memory segment.
*/
static MemorySegment ofArray(byte[] arr) {
return HeapMemorySegmentImpl.makeArraySegment(arr);
return HeapMemorySegmentImpl.OfByte.fromArray(arr);
}
/**
@ -705,7 +705,7 @@ for (long l = 0; l < segment.byteSize(); l++) {
* @return a new confined array memory segment.
*/
static MemorySegment ofArray(char[] arr) {
return HeapMemorySegmentImpl.makeArraySegment(arr);
return HeapMemorySegmentImpl.OfChar.fromArray(arr);
}
/**
@ -719,7 +719,7 @@ for (long l = 0; l < segment.byteSize(); l++) {
* @return a new confined array memory segment.
*/
static MemorySegment ofArray(short[] arr) {
return HeapMemorySegmentImpl.makeArraySegment(arr);
return HeapMemorySegmentImpl.OfShort.fromArray(arr);
}
/**
@ -733,7 +733,7 @@ for (long l = 0; l < segment.byteSize(); l++) {
* @return a new confined array memory segment.
*/
static MemorySegment ofArray(int[] arr) {
return HeapMemorySegmentImpl.makeArraySegment(arr);
return HeapMemorySegmentImpl.OfInt.fromArray(arr);
}
/**
@ -747,7 +747,7 @@ for (long l = 0; l < segment.byteSize(); l++) {
* @return a new confined array memory segment.
*/
static MemorySegment ofArray(float[] arr) {
return HeapMemorySegmentImpl.makeArraySegment(arr);
return HeapMemorySegmentImpl.OfFloat.fromArray(arr);
}
/**
@ -761,7 +761,7 @@ for (long l = 0; l < segment.byteSize(); l++) {
* @return a new confined array memory segment.
*/
static MemorySegment ofArray(long[] arr) {
return HeapMemorySegmentImpl.makeArraySegment(arr);
return HeapMemorySegmentImpl.OfLong.fromArray(arr);
}
/**
@ -775,7 +775,7 @@ for (long l = 0; l < segment.byteSize(); l++) {
* @return a new confined array memory segment.
*/
static MemorySegment ofArray(double[] arr) {
return HeapMemorySegmentImpl.makeArraySegment(arr);
return HeapMemorySegmentImpl.OfDouble.fromArray(arr);
}
/**

View File

@ -588,7 +588,7 @@ public abstract class AbstractMemorySegmentImpl implements MemorySegment, Memory
modes &= ~WRITE;
}
if (base != null) {
return new HeapMemorySegmentImpl<>(bbAddress + pos, () -> (byte[])base, size, modes, bufferScope);
return new HeapMemorySegmentImpl.OfByte(bbAddress + pos, (byte[])base, size, modes, bufferScope);
} else if (unmapper == null) {
return new NativeMemorySegmentImpl(bbAddress + pos, size, modes, bufferScope);
} else {

View File

@ -39,29 +39,27 @@ import java.util.function.Supplier;
/**
* Implementation for heap memory segments. An heap memory segment is composed by an offset and
* a base object (typically an array). To enhance performances, the access to the base object needs to feature
* sharp type information, as well as sharp null-check information. For this reason, the factories for heap segments
* use a lambda to implement the base object accessor, so that the type information will remain sharp (e.g.
* the static compiler will generate specialized base accessor for us).
* sharp type information, as well as sharp null-check information. For this reason, many concrete subclasses
* of {@link HeapMemorySegmentImpl} are defined (e.g. {@link OfFloat}, so that each subclass can override the
* {@link HeapMemorySegmentImpl#base()} method so that it returns an array of the correct (sharp) type.
*/
public class HeapMemorySegmentImpl<H> extends AbstractMemorySegmentImpl {
public abstract class HeapMemorySegmentImpl<H> extends AbstractMemorySegmentImpl {
private static final Unsafe UNSAFE = Unsafe.getUnsafe();
private static final int BYTE_ARR_BASE = UNSAFE.arrayBaseOffset(byte[].class);
final long offset;
final Supplier<H> baseProvider;
final H base;
@ForceInline
HeapMemorySegmentImpl(long offset, Supplier<H> baseProvider, long length, int mask, MemoryScope scope) {
HeapMemorySegmentImpl(long offset, H base, long length, int mask, MemoryScope scope) {
super(length, mask, scope);
this.offset = offset;
this.baseProvider = baseProvider;
this.base = base;
}
@Override
H base() {
return Objects.requireNonNull(baseProvider.get());
}
abstract H base();
@Override
long min() {
@ -69,9 +67,7 @@ public class HeapMemorySegmentImpl<H> extends AbstractMemorySegmentImpl {
}
@Override
HeapMemorySegmentImpl<H> dup(long offset, long size, int mask, MemoryScope scope) {
return new HeapMemorySegmentImpl<>(this.offset + offset, baseProvider, size, mask, scope);
}
abstract HeapMemorySegmentImpl<H> dup(long offset, long size, int mask, MemoryScope scope);
@Override
ByteBuffer makeByteBuffer() {
@ -84,44 +80,164 @@ public class HeapMemorySegmentImpl<H> extends AbstractMemorySegmentImpl {
// factories
public static MemorySegment makeArraySegment(byte[] arr) {
return makeHeapSegment(() -> arr, arr.length,
Unsafe.ARRAY_BYTE_BASE_OFFSET, Unsafe.ARRAY_BYTE_INDEX_SCALE);
public static class OfByte extends HeapMemorySegmentImpl<byte[]> {
OfByte(long offset, byte[] base, long length, int mask, MemoryScope scope) {
super(offset, base, length, mask, scope);
}
@Override
OfByte dup(long offset, long size, int mask, MemoryScope scope) {
return new OfByte(this.offset + offset, base, size, mask, scope);
}
@Override
byte[] base() {
return Objects.requireNonNull(base);
}
public static MemorySegment fromArray(byte[] arr) {
int byteSize = arr.length * Unsafe.ARRAY_BYTE_INDEX_SCALE;
MemoryScope scope = MemoryScope.createConfined(null, MemoryScope.DUMMY_CLEANUP_ACTION, null);
return new OfByte(Unsafe.ARRAY_BYTE_BASE_OFFSET, arr, byteSize, defaultAccessModes(byteSize), scope);
}
}
public static MemorySegment makeArraySegment(char[] arr) {
return makeHeapSegment(() -> arr, arr.length,
Unsafe.ARRAY_CHAR_BASE_OFFSET, Unsafe.ARRAY_CHAR_INDEX_SCALE);
public static class OfChar extends HeapMemorySegmentImpl<char[]> {
OfChar(long offset, char[] base, long length, int mask, MemoryScope scope) {
super(offset, base, length, mask, scope);
}
@Override
OfChar dup(long offset, long size, int mask, MemoryScope scope) {
return new OfChar(this.offset + offset, base, size, mask, scope);
}
@Override
char[] base() {
return Objects.requireNonNull(base);
}
public static MemorySegment fromArray(char[] arr) {
int byteSize = arr.length * Unsafe.ARRAY_CHAR_INDEX_SCALE;
MemoryScope scope = MemoryScope.createConfined(null, MemoryScope.DUMMY_CLEANUP_ACTION, null);
return new OfChar(Unsafe.ARRAY_CHAR_BASE_OFFSET, arr, byteSize, defaultAccessModes(byteSize), scope);
}
}
public static MemorySegment makeArraySegment(short[] arr) {
return makeHeapSegment(() -> arr, arr.length,
Unsafe.ARRAY_SHORT_BASE_OFFSET, Unsafe.ARRAY_SHORT_INDEX_SCALE);
public static class OfShort extends HeapMemorySegmentImpl<short[]> {
OfShort(long offset, short[] base, long length, int mask, MemoryScope scope) {
super(offset, base, length, mask, scope);
}
@Override
OfShort dup(long offset, long size, int mask, MemoryScope scope) {
return new OfShort(this.offset + offset, base, size, mask, scope);
}
@Override
short[] base() {
return Objects.requireNonNull(base);
}
public static MemorySegment fromArray(short[] arr) {
int byteSize = arr.length * Unsafe.ARRAY_SHORT_INDEX_SCALE;
MemoryScope scope = MemoryScope.createConfined(null, MemoryScope.DUMMY_CLEANUP_ACTION, null);
return new OfShort(Unsafe.ARRAY_SHORT_BASE_OFFSET, arr, byteSize, defaultAccessModes(byteSize), scope);
}
}
public static MemorySegment makeArraySegment(int[] arr) {
return makeHeapSegment(() -> arr, arr.length,
Unsafe.ARRAY_INT_BASE_OFFSET, Unsafe.ARRAY_INT_INDEX_SCALE);
public static class OfInt extends HeapMemorySegmentImpl<int[]> {
OfInt(long offset, int[] base, long length, int mask, MemoryScope scope) {
super(offset, base, length, mask, scope);
}
@Override
OfInt dup(long offset, long size, int mask, MemoryScope scope) {
return new OfInt(this.offset + offset, base, size, mask, scope);
}
@Override
int[] base() {
return Objects.requireNonNull(base);
}
public static MemorySegment fromArray(int[] arr) {
int byteSize = arr.length * Unsafe.ARRAY_INT_INDEX_SCALE;
MemoryScope scope = MemoryScope.createConfined(null, MemoryScope.DUMMY_CLEANUP_ACTION, null);
return new OfInt(Unsafe.ARRAY_INT_BASE_OFFSET, arr, byteSize, defaultAccessModes(byteSize), scope);
}
}
public static MemorySegment makeArraySegment(long[] arr) {
return makeHeapSegment(() -> arr, arr.length,
Unsafe.ARRAY_LONG_BASE_OFFSET, Unsafe.ARRAY_LONG_INDEX_SCALE);
public static class OfLong extends HeapMemorySegmentImpl<long[]> {
OfLong(long offset, long[] base, long length, int mask, MemoryScope scope) {
super(offset, base, length, mask, scope);
}
@Override
OfLong dup(long offset, long size, int mask, MemoryScope scope) {
return new OfLong(this.offset + offset, base, size, mask, scope);
}
@Override
long[] base() {
return Objects.requireNonNull(base);
}
public static MemorySegment fromArray(long[] arr) {
int byteSize = arr.length * Unsafe.ARRAY_LONG_INDEX_SCALE;
MemoryScope scope = MemoryScope.createConfined(null, MemoryScope.DUMMY_CLEANUP_ACTION, null);
return new OfLong(Unsafe.ARRAY_LONG_BASE_OFFSET, arr, byteSize, defaultAccessModes(byteSize), scope);
}
}
public static MemorySegment makeArraySegment(float[] arr) {
return makeHeapSegment(() -> arr, arr.length,
Unsafe.ARRAY_FLOAT_BASE_OFFSET, Unsafe.ARRAY_FLOAT_INDEX_SCALE);
public static class OfFloat extends HeapMemorySegmentImpl<float[]> {
OfFloat(long offset, float[] base, long length, int mask, MemoryScope scope) {
super(offset, base, length, mask, scope);
}
@Override
OfFloat dup(long offset, long size, int mask, MemoryScope scope) {
return new OfFloat(this.offset + offset, base, size, mask, scope);
}
@Override
float[] base() {
return Objects.requireNonNull(base);
}
public static MemorySegment fromArray(float[] arr) {
int byteSize = arr.length * Unsafe.ARRAY_FLOAT_INDEX_SCALE;
MemoryScope scope = MemoryScope.createConfined(null, MemoryScope.DUMMY_CLEANUP_ACTION, null);
return new OfFloat(Unsafe.ARRAY_FLOAT_BASE_OFFSET, arr, byteSize, defaultAccessModes(byteSize), scope);
}
}
public static MemorySegment makeArraySegment(double[] arr) {
return makeHeapSegment(() -> arr, arr.length,
Unsafe.ARRAY_DOUBLE_BASE_OFFSET, Unsafe.ARRAY_DOUBLE_INDEX_SCALE);
}
public static class OfDouble extends HeapMemorySegmentImpl<double[]> {
static <Z> HeapMemorySegmentImpl<Z> makeHeapSegment(Supplier<Z> obj, int length, int base, int scale) {
int byteSize = length * scale;
MemoryScope scope = MemoryScope.createConfined(null, MemoryScope.DUMMY_CLEANUP_ACTION, null);
return new HeapMemorySegmentImpl<>(base, obj, byteSize, defaultAccessModes(byteSize), scope);
OfDouble(long offset, double[] base, long length, int mask, MemoryScope scope) {
super(offset, base, length, mask, scope);
}
@Override
OfDouble dup(long offset, long size, int mask, MemoryScope scope) {
return new OfDouble(this.offset + offset, base, size, mask, scope);
}
@Override
double[] base() {
return Objects.requireNonNull(base);
}
public static MemorySegment fromArray(double[] arr) {
int byteSize = arr.length * Unsafe.ARRAY_DOUBLE_INDEX_SCALE;
MemoryScope scope = MemoryScope.createConfined(null, MemoryScope.DUMMY_CLEANUP_ACTION, null);
return new OfDouble(Unsafe.ARRAY_DOUBLE_BASE_OFFSET, arr, byteSize, defaultAccessModes(byteSize), scope);
}
}
}

View File

@ -32,6 +32,7 @@ import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Param;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.TearDown;
@ -67,8 +68,27 @@ public class LoopOverNonConstantHeap {
ByteBuffer byteBuffer;
@Param(value = {"false", "true"})
boolean polluteProfile;
@Setup
public void setup() {
if (polluteProfile) {
MemorySegment intB = MemorySegment.ofArray(new byte[ALLOC_SIZE]);
MemorySegment intI = MemorySegment.ofArray(new int[ALLOC_SIZE]);
MemorySegment intD = MemorySegment.ofArray(new double[ALLOC_SIZE]);
MemorySegment intF = MemorySegment.ofArray(new float[ALLOC_SIZE]);
try (MemorySegment s = MemorySegment.allocateNative(ALLOC_SIZE)) {
for (int i = 0; i < ALLOC_SIZE; i++) {
MemoryAccess.setByteAtOffset(intB, i, (byte)i);
MemoryAccess.setIntAtIndex(intI, i, i);
MemoryAccess.setDoubleAtIndex(intD, i, i);
MemoryAccess.setFloatAtIndex(intF, i, i);
MemoryAccess.setByteAtOffset(s, i, (byte) i);
}
}
}
base = new byte[ALLOC_SIZE];
for (int i = 0; i < ELEM_SIZE; i++) {
unsafe.putInt(base, UNSAFE_BYTE_BASE + (i * CARRIER_SIZE) , i);