8287809: Revisit implementation of memory session

Reviewed-by: jvernee
This commit is contained in:
Maurizio Cimadamore 2022-07-11 14:30:19 +00:00
parent cb6e9cb728
commit fed3af8ae0
21 changed files with 328 additions and 383 deletions

View File

@ -37,7 +37,6 @@ import jdk.internal.vm.annotation.ForceInline;
import java.io.FileDescriptor;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.MemorySession;
import java.util.Objects;
import java.util.Spliterator;
@ -771,11 +770,7 @@ public abstract sealed class Buffer
final void checkSession() {
MemorySessionImpl session = session();
if (session != null) {
try {
session.checkValidState();
} catch (ScopedMemoryAccess.ScopedAccessError e) {
throw new IllegalStateException("This segment is already closed");
}
session.checkValidState();
}
}

View File

@ -313,11 +313,7 @@ class Direct$Type$Buffer$RW$$BO$
if (session.ownerThread() == null && session.isCloseable()) {
throw new UnsupportedOperationException("ByteBuffer derived from closeable shared sessions not supported");
}
try {
session.checkValidState();
} catch (ScopedAccessError e) {
throw new IllegalStateException("This segment is already closed");
}
session.checkValidState();
}
return address;
}

View File

@ -70,40 +70,33 @@ public abstract non-sealed class AbstractMemorySegmentImpl implements MemorySegm
private static final ScopedMemoryAccess SCOPED_MEMORY_ACCESS = ScopedMemoryAccess.getScopedMemoryAccess();
static final int READ_ONLY = 1;
static final long NONCE = new Random().nextLong();
static final int DEFAULT_MODES = 0;
static final JavaNioAccess nioAccess = SharedSecrets.getJavaNioAccess();
final long length;
final int mask;
final boolean readOnly;
final MemorySession session;
@ForceInline
AbstractMemorySegmentImpl(long length, int mask, MemorySession session) {
AbstractMemorySegmentImpl(long length, boolean readOnly, MemorySession session) {
this.length = length;
this.mask = mask;
this.readOnly = readOnly;
this.session = session;
}
abstract long min();
abstract Object base();
abstract AbstractMemorySegmentImpl dup(long offset, long size, int mask, MemorySession session);
abstract AbstractMemorySegmentImpl dup(long offset, long size, boolean readOnly, MemorySession session);
abstract ByteBuffer makeByteBuffer();
@Override
public AbstractMemorySegmentImpl asReadOnly() {
return dup(0, length, mask | READ_ONLY, session);
return dup(0, length, true, session);
}
@Override
public boolean isReadOnly() {
return isSet(READ_ONLY);
return readOnly;
}
@Override
@ -119,7 +112,7 @@ public abstract non-sealed class AbstractMemorySegmentImpl implements MemorySegm
}
private AbstractMemorySegmentImpl asSliceNoCheck(long offset, long newSize) {
return dup(offset, newSize, mask, session);
return dup(offset, newSize, readOnly, session);
}
@Override
@ -147,7 +140,7 @@ public abstract non-sealed class AbstractMemorySegmentImpl implements MemorySegm
@Override
public final MemorySegment fill(byte value){
checkAccess(0, length, false);
SCOPED_MEMORY_ACCESS.setMemory(sessionImpl(), base(), min(), length, value);
SCOPED_MEMORY_ACCESS.setMemory(sessionImpl(), unsafeGetBase(), unsafeGetOffset(), length, value);
return this;
}
@ -176,8 +169,8 @@ public abstract non-sealed class AbstractMemorySegmentImpl implements MemorySegm
return 0;
}
i = vectorizedMismatchLargeForBytes(sessionImpl(), that.sessionImpl(),
this.base(), this.min(),
that.base(), that.min(),
this.unsafeGetBase(), this.unsafeGetOffset(),
that.unsafeGetBase(), that.unsafeGetOffset(),
length);
if (i >= 0) {
return i;
@ -235,7 +228,7 @@ public abstract non-sealed class AbstractMemorySegmentImpl implements MemorySegm
public final ByteBuffer asByteBuffer() {
checkArraySize("ByteBuffer", 1);
ByteBuffer _bb = makeByteBuffer();
if (isSet(READ_ONLY)) {
if (readOnly) {
//session is IMMUTABLE - obtain a RO byte buffer
_bb = _bb.asReadOnlyBuffer();
}
@ -260,9 +253,9 @@ public abstract non-sealed class AbstractMemorySegmentImpl implements MemorySegm
@Override
public final Optional<MemorySegment> asOverlappingSlice(MemorySegment other) {
AbstractMemorySegmentImpl that = (AbstractMemorySegmentImpl)Objects.requireNonNull(other);
if (base() == that.base()) { // both either native or heap
final long thisStart = this.min();
final long thatStart = that.min();
if (unsafeGetBase() == that.unsafeGetBase()) { // both either native or heap
final long thisStart = this.unsafeGetOffset();
final long thatStart = that.unsafeGetOffset();
final long thisEnd = thisStart + this.byteSize();
final long thatEnd = thatStart + that.byteSize();
@ -278,8 +271,8 @@ public abstract non-sealed class AbstractMemorySegmentImpl implements MemorySegm
@Override
public final long segmentOffset(MemorySegment other) {
AbstractMemorySegmentImpl that = (AbstractMemorySegmentImpl) Objects.requireNonNull(other);
if (base() == that.base()) {
return that.min() - this.min();
if (unsafeGetBase() == that.unsafeGetBase()) {
return that.unsafeGetOffset() - this.unsafeGetOffset();
}
throw new UnsupportedOperationException("Cannot compute offset from native to heap (or vice versa).");
}
@ -347,31 +340,24 @@ public abstract non-sealed class AbstractMemorySegmentImpl implements MemorySegm
return arr;
}
@ForceInline
public void checkAccess(long offset, long length, boolean readOnly) {
if (!readOnly && isSet(READ_ONLY)) {
if (!readOnly && this.readOnly) {
throw new UnsupportedOperationException("Attempt to write a read-only segment");
}
checkBounds(offset, length);
}
public void checkValidState() {
sessionImpl().checkValidStateSlow();
sessionImpl().checkValidState();
}
public long unsafeGetOffset() {
return min();
}
public abstract long unsafeGetOffset();
public Object unsafeGetBase() {
return base();
}
public abstract Object unsafeGetBase();
// Helper methods
private boolean isSet(int mask) {
return (this.mask & mask) != 0;
}
public abstract long maxAlignMask();
@ForceInline
@ -407,25 +393,19 @@ public abstract non-sealed class AbstractMemorySegmentImpl implements MemorySegm
return outOfBoundException(offset, length);
}
@Override
@ForceInline
public MemorySessionImpl sessionImpl() {
return MemorySessionImpl.toSessionImpl(session);
}
@Override
public MemorySession session() {
return session;
}
private IndexOutOfBoundsException outOfBoundException(long offset, long length) {
return new IndexOutOfBoundsException(String.format("Out of bound access on segment %s; offset = %d; length = %d",
return new IndexOutOfBoundsException(String.format("Out of bound access on segment %s; new offset = %d; new length = %d",
this, offset, length));
}
protected int id() {
//compute a stable and random id for this memory segment
return Math.abs(Objects.hash(base(), min(), NONCE));
return Math.abs(Objects.hash(unsafeGetBase(), unsafeGetOffset(), NONCE));
}
static class SegmentSplitter implements Spliterator<MemorySegment> {
@ -541,42 +521,37 @@ public abstract non-sealed class AbstractMemorySegmentImpl implements MemorySegm
int size = limit - pos;
AbstractMemorySegmentImpl bufferSegment = (AbstractMemorySegmentImpl)nioAccess.bufferSegment(bb);
final MemorySessionImpl bufferSession;
int modes;
final MemorySession bufferSession;
if (bufferSegment != null) {
bufferSession = bufferSegment.sessionImpl();
modes = bufferSegment.mask;
bufferSession = bufferSegment.session;
} else {
bufferSession = MemorySessionImpl.heapSession(bb);
modes = DEFAULT_MODES;
}
if (bb.isReadOnly()) {
modes |= READ_ONLY;
}
boolean readOnly = bb.isReadOnly();
int scaleFactor = getScaleFactor(bb);
if (base != null) {
if (base instanceof byte[]) {
return new HeapMemorySegmentImpl.OfByte(bbAddress + (pos << scaleFactor), base, size << scaleFactor, modes);
return new HeapMemorySegmentImpl.OfByte(bbAddress + (pos << scaleFactor), base, size << scaleFactor, readOnly);
} else if (base instanceof short[]) {
return new HeapMemorySegmentImpl.OfShort(bbAddress + (pos << scaleFactor), base, size << scaleFactor, modes);
return new HeapMemorySegmentImpl.OfShort(bbAddress + (pos << scaleFactor), base, size << scaleFactor, readOnly);
} else if (base instanceof char[]) {
return new HeapMemorySegmentImpl.OfChar(bbAddress + (pos << scaleFactor), base, size << scaleFactor, modes);
return new HeapMemorySegmentImpl.OfChar(bbAddress + (pos << scaleFactor), base, size << scaleFactor, readOnly);
} else if (base instanceof int[]) {
return new HeapMemorySegmentImpl.OfInt(bbAddress + (pos << scaleFactor), base, size << scaleFactor, modes);
return new HeapMemorySegmentImpl.OfInt(bbAddress + (pos << scaleFactor), base, size << scaleFactor, readOnly);
} else if (base instanceof float[]) {
return new HeapMemorySegmentImpl.OfFloat(bbAddress + (pos << scaleFactor), base, size << scaleFactor, modes);
return new HeapMemorySegmentImpl.OfFloat(bbAddress + (pos << scaleFactor), base, size << scaleFactor, readOnly);
} else if (base instanceof long[]) {
return new HeapMemorySegmentImpl.OfLong(bbAddress + (pos << scaleFactor), base, size << scaleFactor, modes);
return new HeapMemorySegmentImpl.OfLong(bbAddress + (pos << scaleFactor), base, size << scaleFactor, readOnly);
} else if (base instanceof double[]) {
return new HeapMemorySegmentImpl.OfDouble(bbAddress + (pos << scaleFactor), base, size << scaleFactor, modes);
return new HeapMemorySegmentImpl.OfDouble(bbAddress + (pos << scaleFactor), base, size << scaleFactor, readOnly);
} else {
throw new AssertionError("Cannot get here");
}
} else if (unmapper == null) {
return new NativeMemorySegmentImpl(bbAddress + (pos << scaleFactor), size << scaleFactor, modes, bufferSession);
return new NativeMemorySegmentImpl(bbAddress + (pos << scaleFactor), size << scaleFactor, readOnly, bufferSession);
} else {
// we can ignore scale factor here, a mapped buffer is always a byte buffer, so scaleFactor == 0.
return new MappedMemorySegmentImpl(bbAddress + pos, unmapper, size, modes, bufferSession);
return new MappedMemorySegmentImpl(bbAddress + pos, unmapper, size, readOnly, bufferSession);
}
}

View File

@ -55,17 +55,12 @@ final class ConfinedSession extends MemorySessionImpl {
super(owner, new ConfinedResourceList(), cleaner);
}
@Override
public boolean isAlive() {
return state != CLOSED;
}
@Override
@ForceInline
public void acquire0() {
checkValidStateSlow();
checkValidState();
if (state == MAX_FORKS) {
throw new IllegalStateException("Session keep alive limit exceeded");
throw tooManyAcquires();
}
state++;
}
@ -85,11 +80,11 @@ final class ConfinedSession extends MemorySessionImpl {
}
void justClose() {
checkValidStateSlow();
checkValidState();
if (state == 0 || state - ((int)ASYNC_RELEASE_COUNT.getVolatile(this)) == 0) {
state = CLOSED;
} else {
throw new IllegalStateException("Session is acquired by " + state + " clients");
throw alreadyAcquired(state);
}
}
@ -103,7 +98,7 @@ final class ConfinedSession extends MemorySessionImpl {
cleanup.next = fst;
fst = cleanup;
} else {
throw new IllegalStateException("Already closed!");
throw alreadyClosed();
}
}
@ -114,7 +109,7 @@ final class ConfinedSession extends MemorySessionImpl {
fst = ResourceCleanup.CLOSED_LIST;
cleanup(prev);
} else {
throw new IllegalStateException("Attempt to cleanup an already closed resource list");
throw alreadyClosed();
}
}
}

View File

@ -40,7 +40,7 @@ import jdk.internal.vm.annotation.ForceInline;
* 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, 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. Note that
* {@link HeapMemorySegmentImpl#unsafeGetBase()} method so that it returns an array of the correct (sharp) type. Note that
* the field type storing the 'base' coordinate is just Object; similarly, all the constructor in the subclasses
* accept an Object 'base' parameter instead of a sharper type (e.g. {@code byte[]}). This is deliberate, as
* using sharper types would require use of type-conversions, which in turn would inhibit some C2 optimizations,
@ -60,54 +60,51 @@ public abstract class HeapMemorySegmentImpl extends AbstractMemorySegmentImpl {
final Object base;
@ForceInline
HeapMemorySegmentImpl(long offset, Object base, long length, int mask) {
super(length, mask, MemorySessionImpl.GLOBAL);
HeapMemorySegmentImpl(long offset, Object base, long length, boolean readOnly) {
super(length, readOnly, MemorySessionImpl.GLOBAL);
this.offset = offset;
this.base = base;
}
@Override
abstract Object base();
@Override
long min() {
public long unsafeGetOffset() {
return offset;
}
@Override
abstract HeapMemorySegmentImpl dup(long offset, long size, int mask, MemorySession session);
abstract HeapMemorySegmentImpl dup(long offset, long size, boolean readOnly, MemorySession session);
@Override
ByteBuffer makeByteBuffer() {
if (!(base() instanceof byte[])) {
if (!(base instanceof byte[])) {
throw new UnsupportedOperationException("Not an address to an heap-allocated byte array");
}
JavaNioAccess nioAccess = SharedSecrets.getJavaNioAccess();
return nioAccess.newHeapByteBuffer((byte[]) base(), (int)min() - BYTE_ARR_BASE, (int) byteSize(), null);
return nioAccess.newHeapByteBuffer((byte[])base, (int)offset - BYTE_ARR_BASE, (int) byteSize(), null);
}
// factories
public static class OfByte extends HeapMemorySegmentImpl {
OfByte(long offset, Object base, long length, int mask) {
super(offset, base, length, mask);
OfByte(long offset, Object base, long length, boolean readOnly) {
super(offset, base, length, readOnly);
}
@Override
OfByte dup(long offset, long size, int mask, MemorySession session) {
return new OfByte(this.offset + offset, base, size, mask);
OfByte dup(long offset, long size, boolean readOnly, MemorySession session) {
return new OfByte(this.offset + offset, base, size, readOnly);
}
@Override
byte[] base() {
public byte[] unsafeGetBase() {
return (byte[])Objects.requireNonNull(base);
}
public static MemorySegment fromArray(byte[] arr) {
Objects.requireNonNull(arr);
long byteSize = (long)arr.length * Unsafe.ARRAY_BYTE_INDEX_SCALE;
return new OfByte(Unsafe.ARRAY_BYTE_BASE_OFFSET, arr, byteSize, DEFAULT_MODES);
return new OfByte(Unsafe.ARRAY_BYTE_BASE_OFFSET, arr, byteSize, false);
}
@Override
@ -118,24 +115,24 @@ public abstract class HeapMemorySegmentImpl extends AbstractMemorySegmentImpl {
public static class OfChar extends HeapMemorySegmentImpl {
OfChar(long offset, Object base, long length, int mask) {
super(offset, base, length, mask);
OfChar(long offset, Object base, long length, boolean readOnly) {
super(offset, base, length, readOnly);
}
@Override
OfChar dup(long offset, long size, int mask, MemorySession session) {
return new OfChar(this.offset + offset, base, size, mask);
OfChar dup(long offset, long size, boolean readOnly, MemorySession session) {
return new OfChar(this.offset + offset, base, size, readOnly);
}
@Override
char[] base() {
public char[] unsafeGetBase() {
return (char[])Objects.requireNonNull(base);
}
public static MemorySegment fromArray(char[] arr) {
Objects.requireNonNull(arr);
long byteSize = (long)arr.length * Unsafe.ARRAY_CHAR_INDEX_SCALE;
return new OfChar(Unsafe.ARRAY_CHAR_BASE_OFFSET, arr, byteSize, DEFAULT_MODES);
return new OfChar(Unsafe.ARRAY_CHAR_BASE_OFFSET, arr, byteSize, false);
}
@Override
@ -146,24 +143,24 @@ public abstract class HeapMemorySegmentImpl extends AbstractMemorySegmentImpl {
public static class OfShort extends HeapMemorySegmentImpl {
OfShort(long offset, Object base, long length, int mask) {
super(offset, base, length, mask);
OfShort(long offset, Object base, long length, boolean readOnly) {
super(offset, base, length, readOnly);
}
@Override
OfShort dup(long offset, long size, int mask, MemorySession session) {
return new OfShort(this.offset + offset, base, size, mask);
OfShort dup(long offset, long size, boolean readOnly, MemorySession session) {
return new OfShort(this.offset + offset, base, size, readOnly);
}
@Override
short[] base() {
public short[] unsafeGetBase() {
return (short[])Objects.requireNonNull(base);
}
public static MemorySegment fromArray(short[] arr) {
Objects.requireNonNull(arr);
long byteSize = (long)arr.length * Unsafe.ARRAY_SHORT_INDEX_SCALE;
return new OfShort(Unsafe.ARRAY_SHORT_BASE_OFFSET, arr, byteSize, DEFAULT_MODES);
return new OfShort(Unsafe.ARRAY_SHORT_BASE_OFFSET, arr, byteSize, false);
}
@Override
@ -174,24 +171,24 @@ public abstract class HeapMemorySegmentImpl extends AbstractMemorySegmentImpl {
public static class OfInt extends HeapMemorySegmentImpl {
OfInt(long offset, Object base, long length, int mask) {
super(offset, base, length, mask);
OfInt(long offset, Object base, long length, boolean readOnly) {
super(offset, base, length, readOnly);
}
@Override
OfInt dup(long offset, long size, int mask, MemorySession session) {
return new OfInt(this.offset + offset, base, size, mask);
OfInt dup(long offset, long size, boolean readOnly, MemorySession session) {
return new OfInt(this.offset + offset, base, size, readOnly);
}
@Override
int[] base() {
public int[] unsafeGetBase() {
return (int[])Objects.requireNonNull(base);
}
public static MemorySegment fromArray(int[] arr) {
Objects.requireNonNull(arr);
long byteSize = (long)arr.length * Unsafe.ARRAY_INT_INDEX_SCALE;
return new OfInt(Unsafe.ARRAY_INT_BASE_OFFSET, arr, byteSize, DEFAULT_MODES);
return new OfInt(Unsafe.ARRAY_INT_BASE_OFFSET, arr, byteSize, false);
}
@Override
@ -202,24 +199,24 @@ public abstract class HeapMemorySegmentImpl extends AbstractMemorySegmentImpl {
public static class OfLong extends HeapMemorySegmentImpl {
OfLong(long offset, Object base, long length, int mask) {
super(offset, base, length, mask);
OfLong(long offset, Object base, long length, boolean readOnly) {
super(offset, base, length, readOnly);
}
@Override
OfLong dup(long offset, long size, int mask, MemorySession session) {
return new OfLong(this.offset + offset, base, size, mask);
OfLong dup(long offset, long size, boolean readOnly, MemorySession session) {
return new OfLong(this.offset + offset, base, size, readOnly);
}
@Override
long[] base() {
public long[] unsafeGetBase() {
return (long[])Objects.requireNonNull(base);
}
public static MemorySegment fromArray(long[] arr) {
Objects.requireNonNull(arr);
long byteSize = (long)arr.length * Unsafe.ARRAY_LONG_INDEX_SCALE;
return new OfLong(Unsafe.ARRAY_LONG_BASE_OFFSET, arr, byteSize, DEFAULT_MODES);
return new OfLong(Unsafe.ARRAY_LONG_BASE_OFFSET, arr, byteSize, false);
}
@Override
@ -230,24 +227,24 @@ public abstract class HeapMemorySegmentImpl extends AbstractMemorySegmentImpl {
public static class OfFloat extends HeapMemorySegmentImpl {
OfFloat(long offset, Object base, long length, int mask) {
super(offset, base, length, mask);
OfFloat(long offset, Object base, long length, boolean readOnly) {
super(offset, base, length, readOnly);
}
@Override
OfFloat dup(long offset, long size, int mask, MemorySession session) {
return new OfFloat(this.offset + offset, base, size, mask);
OfFloat dup(long offset, long size, boolean readOnly, MemorySession session) {
return new OfFloat(this.offset + offset, base, size, readOnly);
}
@Override
float[] base() {
public float[] unsafeGetBase() {
return (float[])Objects.requireNonNull(base);
}
public static MemorySegment fromArray(float[] arr) {
Objects.requireNonNull(arr);
long byteSize = (long)arr.length * Unsafe.ARRAY_FLOAT_INDEX_SCALE;
return new OfFloat(Unsafe.ARRAY_FLOAT_BASE_OFFSET, arr, byteSize, DEFAULT_MODES);
return new OfFloat(Unsafe.ARRAY_FLOAT_BASE_OFFSET, arr, byteSize, false);
}
@Override
@ -258,24 +255,24 @@ public abstract class HeapMemorySegmentImpl extends AbstractMemorySegmentImpl {
public static class OfDouble extends HeapMemorySegmentImpl {
OfDouble(long offset, Object base, long length, int mask) {
super(offset, base, length, mask);
OfDouble(long offset, Object base, long length, boolean readOnly) {
super(offset, base, length, readOnly);
}
@Override
OfDouble dup(long offset, long size, int mask, MemorySession session) {
return new OfDouble(this.offset + offset, base, size, mask);
OfDouble dup(long offset, long size, boolean readOnly, MemorySession session) {
return new OfDouble(this.offset + offset, base, size, readOnly);
}
@Override
double[] base() {
public double[] unsafeGetBase() {
return (double[])Objects.requireNonNull(base);
}
public static MemorySegment fromArray(double[] arr) {
Objects.requireNonNull(arr);
long byteSize = (long)arr.length * Unsafe.ARRAY_DOUBLE_INDEX_SCALE;
return new OfDouble(Unsafe.ARRAY_DOUBLE_BASE_OFFSET, arr, byteSize, DEFAULT_MODES);
return new OfDouble(Unsafe.ARRAY_DOUBLE_BASE_OFFSET, arr, byteSize, false);
}
@Override

View File

@ -43,8 +43,8 @@ public class MappedMemorySegmentImpl extends NativeMemorySegmentImpl {
static ScopedMemoryAccess SCOPED_MEMORY_ACCESS = ScopedMemoryAccess.getScopedMemoryAccess();
public MappedMemorySegmentImpl(long min, UnmapperProxy unmapper, long length, int mask, MemorySession session) {
super(min, length, mask, session);
public MappedMemorySegmentImpl(long min, UnmapperProxy unmapper, long length, boolean readOnly, MemorySession session) {
super(min, length, readOnly, session);
this.unmapper = unmapper;
}
@ -55,8 +55,8 @@ public class MappedMemorySegmentImpl extends NativeMemorySegmentImpl {
}
@Override
MappedMemorySegmentImpl dup(long offset, long size, int mask, MemorySession session) {
return new MappedMemorySegmentImpl(min + offset, unmapper, size, mask, session);
MappedMemorySegmentImpl dup(long offset, long size, boolean readOnly, MemorySession session) {
return new MappedMemorySegmentImpl(min + offset, unmapper, size, readOnly, session);
}
// mapped segment methods
@ -95,8 +95,8 @@ public class MappedMemorySegmentImpl extends NativeMemorySegmentImpl {
public static class EmptyMappedMemorySegmentImpl extends MappedMemorySegmentImpl {
public EmptyMappedMemorySegmentImpl(int modes, MemorySession session) {
super(0, null, 0, modes, session);
public EmptyMappedMemorySegmentImpl(boolean readOnly, MemorySessionImpl session) {
super(0, null, 0, readOnly, session);
}
@Override

View File

@ -95,7 +95,7 @@ public final class MemoryAddressImpl implements MemoryAddress, Scoped {
}
@Override
public MemorySessionImpl sessionImpl() {
public MemorySessionImpl session() {
return MemorySessionImpl.GLOBAL;
}

View File

@ -43,16 +43,16 @@ import sun.nio.ch.DirectBuffer;
* This class manages the temporal bounds associated with a memory segment as well
* as thread confinement. A session has a liveness bit, which is updated when the session is closed
* (this operation is triggered by {@link MemorySession#close()}). This bit is consulted prior
* to memory access (see {@link #checkValidState()}).
* to memory access (see {@link #checkValidStateRaw()}).
* There are two kinds of memory session: confined memory session and shared memory session.
* A confined memory session has an associated owner thread that confines some operations to
* associated owner thread such as {@link #close()} or {@link #checkValidState()}.
* associated owner thread such as {@link #close()} or {@link #checkValidStateRaw()}.
* Shared sessions do not feature an owner thread - meaning their operations can be called, in a racy
* manner, by multiple threads. To guarantee temporal safety in the presence of concurrent thread,
* shared sessions use a more sophisticated synchronization mechanism, which guarantees that no concurrent
* access is possible when a session is being closed (see {@link jdk.internal.misc.ScopedMemoryAccess}).
*/
public abstract non-sealed class MemorySessionImpl implements Scoped, MemorySession, SegmentAllocator {
public abstract non-sealed class MemorySessionImpl implements MemorySession, SegmentAllocator {
final ResourceList resourceList;
final Cleaner.Cleanable cleanable;
final Thread owner;
@ -78,8 +78,7 @@ public abstract non-sealed class MemorySessionImpl implements Scoped, MemorySess
@Override
public void addCloseAction(Runnable runnable) {
Objects.requireNonNull(runnable);
addInternal(runnable instanceof ResourceList.ResourceCleanup cleanup ?
cleanup : ResourceList.ResourceCleanup.ofRunnable(runnable));
addInternal(ResourceList.ResourceCleanup.ofRunnable(runnable));
}
/**
@ -102,7 +101,7 @@ public abstract non-sealed class MemorySessionImpl implements Scoped, MemorySess
}
void addInternal(ResourceList.ResourceCleanup resource) {
checkValidStateSlow();
checkValidState();
// Note: from here on we no longer check the session state. Two cases are possible: either the resource cleanup
// is added to the list when the session is still open, in which case everything works ok; or the resource
// cleanup is added while the session is being closed. In this latter case, what matters is whether we have already
@ -141,13 +140,13 @@ public abstract non-sealed class MemorySessionImpl implements Scoped, MemorySess
public abstract void acquire0();
@Override
public boolean equals(Object o) {
public final boolean equals(Object o) {
return (o instanceof MemorySession other) &&
toSessionImpl(other) == this;
}
@Override
public int hashCode() {
public final int hashCode() {
return super.hashCode();
}
@ -174,7 +173,9 @@ public abstract non-sealed class MemorySessionImpl implements Scoped, MemorySess
* Returns true, if this session is still open. This method may be called in any thread.
* @return {@code true} if this session is not closed yet.
*/
public abstract boolean isAlive();
public boolean isAlive() {
return state >= OPEN;
}
@Override
public MemorySession asNonCloseable() {
@ -182,30 +183,27 @@ public abstract non-sealed class MemorySessionImpl implements Scoped, MemorySess
new NonCloseableView(this) : this;
}
@ForceInline
public static MemorySessionImpl toSessionImpl(MemorySession session) {
return ((Scoped)session).sessionImpl();
}
@Override
public MemorySessionImpl sessionImpl() {
return this;
return session instanceof MemorySessionImpl sessionImpl ?
sessionImpl : ((NonCloseableView)session).session;
}
/**
* This is a faster version of {@link #checkValidStateSlow()}, which is called upon memory access, and which
* This is a faster version of {@link #checkValidState()}, which is called upon memory access, and which
* relies on invariants associated with the memory session implementations (volatile access
* to the closed state bit is replaced with plain access). This method should be monomorphic,
* to avoid virtual calls in the memory access hot path. This method is not intended as general purpose method
* and should only be used in the memory access handle hot path; for liveness checks triggered by other API methods,
* please use {@link #checkValidStateSlow()}.
* please use {@link #checkValidState()}.
*/
@ForceInline
public final void checkValidState() {
public void checkValidStateRaw() {
if (owner != null && owner != Thread.currentThread()) {
throw new WrongThreadException("Attempted access outside owning thread");
throw WRONG_THREAD;
}
if (state < OPEN) {
throw ScopedMemoryAccess.ScopedAccessError.INSTANCE;
throw ALREADY_CLOSED;
}
}
@ -214,11 +212,11 @@ public abstract non-sealed class MemorySessionImpl implements Scoped, MemorySess
* @throws IllegalStateException if this session is already closed or if this is
* a confined session and this method is called outside of the owner thread.
*/
public final void checkValidStateSlow() {
if (owner != null && Thread.currentThread() != owner) {
throw new WrongThreadException("Attempted access outside owning thread");
} else if (!isAlive()) {
throw new IllegalStateException("Already closed");
public void checkValidState() {
try {
checkValidStateRaw();
} catch (ScopedMemoryAccess.ScopedAccessError error) {
throw error.newRuntimeException();
}
}
@ -289,14 +287,9 @@ public abstract non-sealed class MemorySessionImpl implements Scoped, MemorySess
// do nothing
}
@Override
public boolean isAlive() {
return true;
}
@Override
public void justClose() {
throw new UnsupportedOperationException();
throw nonCloseable();
}
}
@ -335,19 +328,9 @@ public abstract non-sealed class MemorySessionImpl implements Scoped, MemorySess
return false;
}
@Override
public boolean isAlive() {
return true;
}
@Override
public MemorySession asNonCloseable() {
return this;
}
@Override
public void justClose() {
throw new UnsupportedOperationException();
throw nonCloseable();
}
}
@ -358,17 +341,13 @@ public abstract non-sealed class MemorySessionImpl implements Scoped, MemorySess
* a strong reference to the original session, so even if the original session is dropped by the client
* it would still be reachable by the GC, which is important if the session is implicitly closed.
*/
public final static class NonCloseableView implements MemorySession, Scoped {
public final static class NonCloseableView implements MemorySession {
final MemorySessionImpl session;
public NonCloseableView(MemorySessionImpl session) {
this.session = session;
}
public MemorySessionImpl sessionImpl() {
return session;
}
@Override
public boolean isAlive() {
return session.isAlive();
@ -461,6 +440,31 @@ public abstract non-sealed class MemorySessionImpl implements Scoped, MemorySess
};
}
}
}
// helper functions to centralize error handling
static IllegalStateException tooManyAcquires() {
return new IllegalStateException("Session acquire limit exceeded");
}
static IllegalStateException alreadyAcquired(int acquires) {
return new IllegalStateException(String.format("Session is acquired by %d clients", acquires));
}
static IllegalStateException alreadyClosed() {
return new IllegalStateException("Already closed");
}
static WrongThreadException wrongThread() {
return new WrongThreadException("Attempted access outside owning thread");
}
static UnsupportedOperationException nonCloseable() {
return new UnsupportedOperationException("Attempted to close a non-closeable session");
}
static final ScopedMemoryAccess.ScopedAccessError ALREADY_CLOSED = new ScopedMemoryAccess.ScopedAccessError(MemorySessionImpl::alreadyClosed);
static final ScopedMemoryAccess.ScopedAccessError WRONG_THREAD = new ScopedMemoryAccess.ScopedAccessError(MemorySessionImpl::wrongThread);
}

View File

@ -41,14 +41,14 @@ import sun.security.action.GetBooleanAction;
*/
public class NativeMemorySegmentImpl extends AbstractMemorySegmentImpl {
public static final MemorySegment EVERYTHING = new NativeMemorySegmentImpl(0, Long.MAX_VALUE, 0, MemorySessionImpl.GLOBAL) {
public static final MemorySegment EVERYTHING = new NativeMemorySegmentImpl(0, Long.MAX_VALUE, false, MemorySessionImpl.GLOBAL) {
@Override
void checkBounds(long offset, long length) {
// do nothing
}
@Override
NativeMemorySegmentImpl dup(long offset, long size, int mask, MemorySession scope) {
NativeMemorySegmentImpl dup(long offset, long size, boolean readOnly, MemorySession session) {
throw new IllegalStateException();
}
};
@ -64,8 +64,8 @@ public class NativeMemorySegmentImpl extends AbstractMemorySegmentImpl {
final long min;
@ForceInline
NativeMemorySegmentImpl(long min, long length, int mask, MemorySession session) {
super(length, mask, session);
NativeMemorySegmentImpl(long min, long length, boolean readOnly, MemorySession session) {
super(length, readOnly, session);
this.min = min;
}
@ -77,13 +77,13 @@ public class NativeMemorySegmentImpl extends AbstractMemorySegmentImpl {
}
@Override
NativeMemorySegmentImpl dup(long offset, long size, int mask, MemorySession session) {
return new NativeMemorySegmentImpl(min + offset, size, mask, session);
NativeMemorySegmentImpl dup(long offset, long size, boolean readOnly, MemorySession session) {
return new NativeMemorySegmentImpl(min + offset, size, readOnly, session);
}
@Override
ByteBuffer makeByteBuffer() {
return nioAccess.newDirectByteBuffer(min(), (int) this.length, null,
return nioAccess.newDirectByteBuffer(min, (int) this.length, null,
session == MemorySessionImpl.GLOBAL ? null : this);
}
@ -93,12 +93,12 @@ public class NativeMemorySegmentImpl extends AbstractMemorySegmentImpl {
}
@Override
long min() {
public long unsafeGetOffset() {
return min;
}
@Override
Object base() {
public Object unsafeGetBase() {
return null;
}
@ -111,7 +111,7 @@ public class NativeMemorySegmentImpl extends AbstractMemorySegmentImpl {
public static MemorySegment makeNativeSegment(long bytesSize, long alignmentBytes, MemorySession session) {
MemorySessionImpl sessionImpl = MemorySessionImpl.toSessionImpl(session);
sessionImpl.checkValidStateSlow();
sessionImpl.checkValidState();
if (VM.isDirectMemoryPageAligned()) {
alignmentBytes = Math.max(alignmentBytes, nioAccess.pageSize());
}
@ -127,7 +127,7 @@ public class NativeMemorySegmentImpl extends AbstractMemorySegmentImpl {
}
long alignedBuf = Utils.alignUp(buf, alignmentBytes);
AbstractMemorySegmentImpl segment = new NativeMemorySegmentImpl(buf, alignedSize,
DEFAULT_MODES, session);
false, session);
sessionImpl.addOrCleanupIfFail(new MemorySessionImpl.ResourceList.ResourceCleanup() {
@Override
public void cleanup() {
@ -143,9 +143,8 @@ public class NativeMemorySegmentImpl extends AbstractMemorySegmentImpl {
}
public static MemorySegment makeNativeSegmentUnchecked(MemoryAddress min, long bytesSize, MemorySession session) {
MemorySessionImpl sessionImpl = MemorySessionImpl.toSessionImpl(session);
sessionImpl.checkValidStateSlow();
AbstractMemorySegmentImpl segment = new NativeMemorySegmentImpl(min.toRawLongValue(), bytesSize, DEFAULT_MODES, session);
MemorySessionImpl.toSessionImpl(session).checkValidState();
AbstractMemorySegmentImpl segment = new NativeMemorySegmentImpl(min.toRawLongValue(), bytesSize, false, session);
return segment;
}
}

View File

@ -25,6 +25,14 @@
package jdk.internal.foreign;
import jdk.internal.vm.annotation.ForceInline;
import java.lang.foreign.MemorySession;
public interface Scoped {
MemorySessionImpl sessionImpl();
@ForceInline
default MemorySessionImpl sessionImpl() {
return MemorySessionImpl.toSessionImpl(session());
}
MemorySession session();
}

View File

@ -56,10 +56,10 @@ class SharedSession extends MemorySessionImpl {
value = (int) STATE.getVolatile(this);
if (value < OPEN) {
//segment is not open!
throw new IllegalStateException("Already closed");
throw alreadyClosed();
} else if (value == MAX_FORKS) {
//overflow
throw new IllegalStateException("Session acquire limit exceeded");
throw tooManyAcquires();
}
} while (!STATE.compareAndSet(this, value, value + 1));
}
@ -72,7 +72,7 @@ class SharedSession extends MemorySessionImpl {
value = (int) STATE.getVolatile(this);
if (value <= OPEN) {
//cannot get here - we can't close segment twice
throw new IllegalStateException("Already closed");
throw alreadyClosed();
}
} while (!STATE.compareAndSet(this, value, value - 1));
}
@ -80,22 +80,17 @@ class SharedSession extends MemorySessionImpl {
void justClose() {
int prevState = (int) STATE.compareAndExchange(this, OPEN, CLOSING);
if (prevState < 0) {
throw new IllegalStateException("Already closed");
throw alreadyClosed();
} else if (prevState != OPEN) {
throw new IllegalStateException("Session is acquired by " + prevState + " clients");
throw alreadyAcquired(prevState);
}
boolean success = SCOPED_MEMORY_ACCESS.closeScope(this);
STATE.setVolatile(this, success ? CLOSED : OPEN);
if (!success) {
throw new IllegalStateException("Session is acquired by 1 client");
throw alreadyAcquired(1);
}
}
@Override
public boolean isAlive() {
return (int) STATE.getVolatile(this) != CLOSED;
}
/**
* A shared resource list; this implementation has to handle add vs. add races, as well as add vs. cleanup races.
*/
@ -117,7 +112,7 @@ class SharedSession extends MemorySessionImpl {
ResourceCleanup prev = (ResourceCleanup) FST.getVolatile(this);
if (prev == ResourceCleanup.CLOSED_LIST) {
// too late
throw new IllegalStateException("Already closed");
throw alreadyClosed();
}
cleanup.next = prev;
if (FST.compareAndSet(this, prev, cleanup)) {
@ -144,7 +139,7 @@ class SharedSession extends MemorySessionImpl {
}
cleanup(prev);
} else {
throw new IllegalStateException("Attempt to cleanup an already closed resource list");
throw alreadyClosed();
}
}
}

View File

@ -445,11 +445,6 @@ public class SharedUtils {
return MemorySessionImpl.GLOBAL;
}
@Override
public MemorySessionImpl sessionImpl() {
return MemorySessionImpl.GLOBAL;
}
@Override
public VaList copy() {
return this;

View File

@ -320,7 +320,7 @@ public non-sealed class LinuxAArch64VaList implements VaList, Scoped {
@Override
public void skip(MemoryLayout... layouts) {
Objects.requireNonNull(layouts);
MemorySessionImpl.toSessionImpl(session()).checkValidStateSlow();
sessionImpl().checkValidState();
for (MemoryLayout layout : layouts) {
Objects.requireNonNull(layout);
TypeClass typeClass = TypeClass.classifyLayout(layout);
@ -350,11 +350,6 @@ public non-sealed class LinuxAArch64VaList implements VaList, Scoped {
return segment.session();
}
@Override
public MemorySessionImpl sessionImpl() {
return MemorySessionImpl.toSessionImpl(session());
}
@Override
public VaList copy() {
MemorySegment copy = MemorySegment.allocateNative(LAYOUT, segment.session());

View File

@ -127,7 +127,7 @@ public non-sealed class MacOsAArch64VaList implements VaList, Scoped {
@Override
public void skip(MemoryLayout... layouts) {
Objects.requireNonNull(layouts);
MemorySessionImpl.toSessionImpl(session()).checkValidStateSlow();
sessionImpl().checkValidState();
for (MemoryLayout layout : layouts) {
Objects.requireNonNull(layout);
@ -152,14 +152,9 @@ public non-sealed class MacOsAArch64VaList implements VaList, Scoped {
return session;
}
@Override
public MemorySessionImpl sessionImpl() {
return MemorySessionImpl.toSessionImpl(session());
}
@Override
public VaList copy() {
MemorySessionImpl.toSessionImpl(session()).checkValidStateSlow();
sessionImpl().checkValidState();
return new MacOsAArch64VaList(segment, session);
}
@ -174,7 +169,7 @@ public non-sealed class MacOsAArch64VaList implements VaList, Scoped {
private final List<SimpleVaArg> args = new ArrayList<>();
public Builder(MemorySession session) {
MemorySessionImpl.toSessionImpl(session).checkValidStateSlow();
MemorySessionImpl.toSessionImpl(session).checkValidState();
this.session = session;
}

View File

@ -277,7 +277,7 @@ public non-sealed class SysVVaList implements VaList, Scoped {
@Override
public void skip(MemoryLayout... layouts) {
Objects.requireNonNull(layouts);
MemorySessionImpl.toSessionImpl(session()).checkValidStateSlow();
sessionImpl().checkValidState();
for (MemoryLayout layout : layouts) {
Objects.requireNonNull(layout);
TypeClass typeClass = TypeClass.classifyLayout(layout);
@ -304,11 +304,6 @@ public non-sealed class SysVVaList implements VaList, Scoped {
return segment.session();
}
@Override
public MemorySessionImpl sessionImpl() {
return MemorySessionImpl.toSessionImpl(session());
}
@Override
public VaList copy() {
MemorySegment copy = MemorySegment.allocateNative(LAYOUT, segment.session());

View File

@ -133,7 +133,7 @@ public non-sealed class WinVaList implements VaList, Scoped {
@Override
public void skip(MemoryLayout... layouts) {
Objects.requireNonNull(layouts);
MemorySessionImpl.toSessionImpl(session()).checkValidStateSlow();
sessionImpl().checkValidState();
Stream.of(layouts).forEach(Objects::requireNonNull);
segment = segment.asSlice(layouts.length * VA_SLOT_SIZE_BYTES);
}
@ -152,14 +152,9 @@ public non-sealed class WinVaList implements VaList, Scoped {
return session;
}
@Override
public MemorySessionImpl sessionImpl() {
return MemorySessionImpl.toSessionImpl(session());
}
@Override
public VaList copy() {
MemorySessionImpl.toSessionImpl(session).checkValidStateSlow();
sessionImpl().checkValidState();
return new WinVaList(segment, session);
}
@ -174,7 +169,7 @@ public non-sealed class WinVaList implements VaList, Scoped {
private final List<SimpleVaArg> args = new ArrayList<>();
public Builder(MemorySession session) {
MemorySessionImpl.toSessionImpl(session).checkValidStateSlow();
MemorySessionImpl.toSessionImpl(session).checkValidState();
this.session = session;
}

View File

@ -3,7 +3,7 @@
try {
return get$Type$Internal(session, base, offset);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
throw ex.newRuntimeException();
}
}
@ -11,7 +11,7 @@
private $type$ get$Type$Internal(MemorySessionImpl session, Object base, long offset) {
try {
if (session != null) {
session.checkValidState();
session.checkValidStateRaw();
}
return UNSAFE.get$Type$(base, offset);
} finally {
@ -24,7 +24,7 @@
try {
put$Type$Internal(session, base, offset, value);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
throw ex.newRuntimeException();
}
}
@ -32,7 +32,7 @@
private void put$Type$Internal(MemorySessionImpl session, Object base, long offset, $type$ value) {
try {
if (session != null) {
session.checkValidState();
session.checkValidStateRaw();
}
UNSAFE.put$Type$(base, offset, value);
} finally {
@ -46,7 +46,7 @@
try {
return get$Type$UnalignedInternal(session, base, offset, be);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
throw ex.newRuntimeException();
}
}
@ -54,7 +54,7 @@
private $type$ get$Type$UnalignedInternal(MemorySessionImpl session, Object base, long offset, boolean be) {
try {
if (session != null) {
session.checkValidState();
session.checkValidStateRaw();
}
return UNSAFE.get$Type$Unaligned(base, offset, be);
} finally {
@ -67,7 +67,7 @@
try {
put$Type$UnalignedInternal(session, base, offset, value, be);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
throw ex.newRuntimeException();
}
}
@ -75,7 +75,7 @@
private void put$Type$UnalignedInternal(MemorySessionImpl session, Object base, long offset, $type$ value, boolean be) {
try {
if (session != null) {
session.checkValidState();
session.checkValidStateRaw();
}
UNSAFE.put$Type$Unaligned(base, offset, value, be);
} finally {
@ -89,7 +89,7 @@
try {
return get$Type$VolatileInternal(session, base, offset);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
throw ex.newRuntimeException();
}
}
@ -97,7 +97,7 @@
private $type$ get$Type$VolatileInternal(MemorySessionImpl session, Object base, long offset) {
try {
if (session != null) {
session.checkValidState();
session.checkValidStateRaw();
}
return UNSAFE.get$Type$Volatile(base, offset);
} finally {
@ -110,7 +110,7 @@
try {
put$Type$VolatileInternal(session, base, offset, value);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
throw ex.newRuntimeException();
}
}
@ -118,7 +118,7 @@
private void put$Type$VolatileInternal(MemorySessionImpl session, Object base, long offset, $type$ value) {
try {
if (session != null) {
session.checkValidState();
session.checkValidStateRaw();
}
UNSAFE.put$Type$Volatile(base, offset, value);
} finally {
@ -131,7 +131,7 @@
try {
return get$Type$AcquireInternal(session, base, offset);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
throw ex.newRuntimeException();
}
}
@ -139,7 +139,7 @@
private $type$ get$Type$AcquireInternal(MemorySessionImpl session, Object base, long offset) {
try {
if (session != null) {
session.checkValidState();
session.checkValidStateRaw();
}
return UNSAFE.get$Type$Acquire(base, offset);
} finally {
@ -152,7 +152,7 @@
try {
put$Type$ReleaseInternal(session, base, offset, value);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
throw ex.newRuntimeException();
}
}
@ -160,7 +160,7 @@
private void put$Type$ReleaseInternal(MemorySessionImpl session, Object base, long offset, $type$ value) {
try {
if (session != null) {
session.checkValidState();
session.checkValidStateRaw();
}
UNSAFE.put$Type$Release(base, offset, value);
} finally {
@ -173,7 +173,7 @@
try {
return get$Type$OpaqueInternal(session, base, offset);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
throw ex.newRuntimeException();
}
}
@ -181,7 +181,7 @@
private $type$ get$Type$OpaqueInternal(MemorySessionImpl session, Object base, long offset) {
try {
if (session != null) {
session.checkValidState();
session.checkValidStateRaw();
}
return UNSAFE.get$Type$Opaque(base, offset);
} finally {
@ -193,7 +193,7 @@
try {
put$Type$OpaqueInternal(session, base, offset, value);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
throw ex.newRuntimeException();
}
}
@ -201,7 +201,7 @@
private void put$Type$OpaqueInternal(MemorySessionImpl session, Object base, long offset, $type$ value) {
try {
if (session != null) {
session.checkValidState();
session.checkValidStateRaw();
}
UNSAFE.put$Type$Opaque(base, offset, value);
} finally {
@ -214,7 +214,7 @@
try {
return compareAndSet$Type$Internal(session, base, offset, expected, value);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
throw ex.newRuntimeException();
}
}
@ -222,7 +222,7 @@
private boolean compareAndSet$Type$Internal(MemorySessionImpl session, Object base, long offset, $type$ expected, $type$ value) {
try {
if (session != null) {
session.checkValidState();
session.checkValidStateRaw();
}
return UNSAFE.compareAndSet$Type$(base, offset, expected, value);
} finally {
@ -235,7 +235,7 @@
try {
return compareAndExchange$Type$Internal(session, base, offset, expected, value);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
throw ex.newRuntimeException();
}
}
@ -243,7 +243,7 @@
private $type$ compareAndExchange$Type$Internal(MemorySessionImpl session, Object base, long offset, $type$ expected, $type$ value) {
try {
if (session != null) {
session.checkValidState();
session.checkValidStateRaw();
}
return UNSAFE.compareAndExchange$Type$(base, offset, expected, value);
} finally {
@ -256,7 +256,7 @@
try {
return compareAndExchange$Type$AcquireInternal(session, base, offset, expected, value);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
throw ex.newRuntimeException();
}
}
@ -264,7 +264,7 @@
private $type$ compareAndExchange$Type$AcquireInternal(MemorySessionImpl session, Object base, long offset, $type$ expected, $type$ value) {
try {
if (session != null) {
session.checkValidState();
session.checkValidStateRaw();
}
return UNSAFE.compareAndExchange$Type$Acquire(base, offset, expected, value);
} finally {
@ -277,7 +277,7 @@
try {
return compareAndExchange$Type$ReleaseInternal(session, base, offset, expected, value);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
throw ex.newRuntimeException();
}
}
@ -285,7 +285,7 @@
private $type$ compareAndExchange$Type$ReleaseInternal(MemorySessionImpl session, Object base, long offset, $type$ expected, $type$ value) {
try {
if (session != null) {
session.checkValidState();
session.checkValidStateRaw();
}
return UNSAFE.compareAndExchange$Type$Release(base, offset, expected, value);
} finally {
@ -298,7 +298,7 @@
try {
return weakCompareAndSet$Type$PlainInternal(session, base, offset, expected, value);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
throw ex.newRuntimeException();
}
}
@ -306,7 +306,7 @@
private boolean weakCompareAndSet$Type$PlainInternal(MemorySessionImpl session, Object base, long offset, $type$ expected, $type$ value) {
try {
if (session != null) {
session.checkValidState();
session.checkValidStateRaw();
}
return UNSAFE.weakCompareAndSet$Type$Plain(base, offset, expected, value);
} finally {
@ -319,7 +319,7 @@
try {
return weakCompareAndSet$Type$Internal(session, base, offset, expected, value);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
throw ex.newRuntimeException();
}
}
@ -327,7 +327,7 @@
private boolean weakCompareAndSet$Type$Internal(MemorySessionImpl session, Object base, long offset, $type$ expected, $type$ value) {
try {
if (session != null) {
session.checkValidState();
session.checkValidStateRaw();
}
return UNSAFE.weakCompareAndSet$Type$(base, offset, expected, value);
} finally {
@ -340,7 +340,7 @@
try {
return weakCompareAndSet$Type$AcquireInternal(session, base, offset, expected, value);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
throw ex.newRuntimeException();
}
}
@ -348,7 +348,7 @@
private boolean weakCompareAndSet$Type$AcquireInternal(MemorySessionImpl session, Object base, long offset, $type$ expected, $type$ value) {
try {
if (session != null) {
session.checkValidState();
session.checkValidStateRaw();
}
return UNSAFE.weakCompareAndSet$Type$Acquire(base, offset, expected, value);
} finally {
@ -361,7 +361,7 @@
try {
return weakCompareAndSet$Type$ReleaseInternal(session, base, offset, expected, value);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
throw ex.newRuntimeException();
}
}
@ -369,7 +369,7 @@
private boolean weakCompareAndSet$Type$ReleaseInternal(MemorySessionImpl session, Object base, long offset, $type$ expected, $type$ value) {
try {
if (session != null) {
session.checkValidState();
session.checkValidStateRaw();
}
return UNSAFE.weakCompareAndSet$Type$Release(base, offset, expected, value);
} finally {
@ -382,7 +382,7 @@
try {
return getAndSet$Type$Internal(session, base, offset, value);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
throw ex.newRuntimeException();
}
}
@ -390,7 +390,7 @@
private $type$ getAndSet$Type$Internal(MemorySessionImpl session, Object base, long offset, $type$ value) {
try {
if (session != null) {
session.checkValidState();
session.checkValidStateRaw();
}
return UNSAFE.getAndSet$Type$(base, offset, value);
} finally {
@ -403,7 +403,7 @@
try {
return getAndSet$Type$AcquireInternal(session, base, offset, value);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
throw ex.newRuntimeException();
}
}
@ -411,7 +411,7 @@
private $type$ getAndSet$Type$AcquireInternal(MemorySessionImpl session, Object base, long offset, $type$ value) {
try {
if (session != null) {
session.checkValidState();
session.checkValidStateRaw();
}
return UNSAFE.getAndSet$Type$Acquire(base, offset, value);
} finally {
@ -424,7 +424,7 @@
try {
return getAndSet$Type$ReleaseInternal(session, base, offset, value);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
throw ex.newRuntimeException();
}
}
@ -432,7 +432,7 @@
private $type$ getAndSet$Type$ReleaseInternal(MemorySessionImpl session, Object base, long offset, $type$ value) {
try {
if (session != null) {
session.checkValidState();
session.checkValidStateRaw();
}
return UNSAFE.getAndSet$Type$Release(base, offset, value);
} finally {
@ -447,7 +447,7 @@
try {
return getAndAdd$Type$Internal(session, base, offset, delta);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
throw ex.newRuntimeException();
}
}
@ -455,7 +455,7 @@
private $type$ getAndAdd$Type$Internal(MemorySessionImpl session, Object base, long offset, $type$ delta) {
try {
if (session != null) {
session.checkValidState();
session.checkValidStateRaw();
}
return UNSAFE.getAndAdd$Type$(base, offset, delta);
} finally {
@ -468,7 +468,7 @@
try {
return getAndAdd$Type$AcquireInternal(session, base, offset, delta);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
throw ex.newRuntimeException();
}
}
@ -476,7 +476,7 @@
private $type$ getAndAdd$Type$AcquireInternal(MemorySessionImpl session, Object base, long offset, $type$ delta) {
try {
if (session != null) {
session.checkValidState();
session.checkValidStateRaw();
}
return UNSAFE.getAndAdd$Type$Acquire(base, offset, delta);
} finally {
@ -489,7 +489,7 @@
try {
return getAndAdd$Type$ReleaseInternal(session, base, offset, delta);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
throw ex.newRuntimeException();
}
}
@ -497,7 +497,7 @@
private $type$ getAndAdd$Type$ReleaseInternal(MemorySessionImpl session, Object base, long offset, $type$ delta) {
try {
if (session != null) {
session.checkValidState();
session.checkValidStateRaw();
}
return UNSAFE.getAndAdd$Type$Release(base, offset, delta);
} finally {
@ -512,7 +512,7 @@
try {
return getAndBitwiseOr$Type$Internal(session, base, offset, value);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
throw ex.newRuntimeException();
}
}
@ -520,7 +520,7 @@
private $type$ getAndBitwiseOr$Type$Internal(MemorySessionImpl session, Object base, long offset, $type$ value) {
try {
if (session != null) {
session.checkValidState();
session.checkValidStateRaw();
}
return UNSAFE.getAndBitwiseOr$Type$(base, offset, value);
} finally {
@ -533,7 +533,7 @@
try {
return getAndBitwiseOr$Type$AcquireInternal(session, base, offset, value);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
throw ex.newRuntimeException();
}
}
@ -541,7 +541,7 @@
private $type$ getAndBitwiseOr$Type$AcquireInternal(MemorySessionImpl session, Object base, long offset, $type$ value) {
try {
if (session != null) {
session.checkValidState();
session.checkValidStateRaw();
}
return UNSAFE.getAndBitwiseOr$Type$Acquire(base, offset, value);
} finally {
@ -554,7 +554,7 @@
try {
return getAndBitwiseOr$Type$ReleaseInternal(session, base, offset, value);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
throw ex.newRuntimeException();
}
}
@ -562,7 +562,7 @@
private $type$ getAndBitwiseOr$Type$ReleaseInternal(MemorySessionImpl session, Object base, long offset, $type$ value) {
try {
if (session != null) {
session.checkValidState();
session.checkValidStateRaw();
}
return UNSAFE.getAndBitwiseOr$Type$Release(base, offset, value);
} finally {
@ -575,7 +575,7 @@
try {
return getAndBitwiseAnd$Type$Internal(session, base, offset, value);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
throw ex.newRuntimeException();
}
}
@ -583,7 +583,7 @@
private $type$ getAndBitwiseAnd$Type$Internal(MemorySessionImpl session, Object base, long offset, $type$ value) {
try {
if (session != null) {
session.checkValidState();
session.checkValidStateRaw();
}
return UNSAFE.getAndBitwiseAnd$Type$(base, offset, value);
} finally {
@ -596,7 +596,7 @@
try {
return getAndBitwiseAnd$Type$AcquireInternal(session, base, offset, value);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
throw ex.newRuntimeException();
}
}
@ -604,7 +604,7 @@
private $type$ getAndBitwiseAnd$Type$AcquireInternal(MemorySessionImpl session, Object base, long offset, $type$ value) {
try {
if (session != null) {
session.checkValidState();
session.checkValidStateRaw();
}
return UNSAFE.getAndBitwiseAnd$Type$Acquire(base, offset, value);
} finally {
@ -617,7 +617,7 @@
try {
return getAndBitwiseAnd$Type$ReleaseInternal(session, base, offset, value);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
throw ex.newRuntimeException();
}
}
@ -625,7 +625,7 @@
private $type$ getAndBitwiseAnd$Type$ReleaseInternal(MemorySessionImpl session, Object base, long offset, $type$ value) {
try {
if (session != null) {
session.checkValidState();
session.checkValidStateRaw();
}
return UNSAFE.getAndBitwiseAnd$Type$Release(base, offset, value);
} finally {
@ -638,7 +638,7 @@
try {
return getAndBitwiseXor$Type$Internal(session, base, offset, value);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
throw ex.newRuntimeException();
}
}
@ -646,7 +646,7 @@
private $type$ getAndBitwiseXor$Type$Internal(MemorySessionImpl session, Object base, long offset, $type$ value) {
try {
if (session != null) {
session.checkValidState();
session.checkValidStateRaw();
}
return UNSAFE.getAndBitwiseXor$Type$(base, offset, value);
} finally {
@ -659,7 +659,7 @@
try {
return getAndBitwiseXor$Type$AcquireInternal(session, base, offset, value);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
throw ex.newRuntimeException();
}
}
@ -667,7 +667,7 @@
private $type$ getAndBitwiseXor$Type$AcquireInternal(MemorySessionImpl session, Object base, long offset, $type$ value) {
try {
if (session != null) {
session.checkValidState();
session.checkValidStateRaw();
}
return UNSAFE.getAndBitwiseXor$Type$Acquire(base, offset, value);
} finally {
@ -680,7 +680,7 @@
try {
return getAndBitwiseXor$Type$ReleaseInternal(session, base, offset, value);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
throw ex.newRuntimeException();
}
}
@ -688,7 +688,7 @@
private $type$ getAndBitwiseXor$Type$ReleaseInternal(MemorySessionImpl session, Object base, long offset, $type$ value) {
try {
if (session != null) {
session.checkValidState();
session.checkValidStateRaw();
}
return UNSAFE.getAndBitwiseXor$Type$Release(base, offset, value);
} finally {

View File

@ -32,6 +32,7 @@ import java.lang.annotation.Target;
import java.lang.foreign.MemorySegment;
import java.lang.ref.Reference;
import java.io.FileDescriptor;
import java.util.function.Supplier;
import jdk.internal.access.JavaNioAccess;
import jdk.internal.access.SharedSecrets;
@ -55,10 +56,10 @@ import jdk.internal.vm.vector.VectorSupport;
* a memory region while another thread is releasing it.
* <p>
* This class provides tools to manage races when multiple threads are accessing and/or releasing the same memory
* region concurrently. More specifically, when a thread wants to release a memory region, it should call the
* {@link MemorySessionImpl#close()} method. This method initiates thread-local handshakes with all the other VM threads,
* session concurrently. More specifically, when a thread wants to release a memory session, it should call the
* {@link ScopedMemoryAccess#closeScope(MemorySessionImpl)} method. This method initiates thread-local handshakes with all the other VM threads,
* which are then stopped one by one. If any thread is found accessing a resource associated to the very memory session
* being closed, the handshake fails, and the session cannot be closed.
* being closed, the handshake fails, and the session will not be closed.
* <p>
* This synchronization strategy relies on the idea that accessing memory is atomic with respect to checking the
* validity of the session associated with that memory region - that is, a thread that wants to perform memory access will be
@ -97,12 +98,20 @@ public class ScopedMemoryAccess {
}
public static final class ScopedAccessError extends Error {
private ScopedAccessError() {
super("Attempt to access an already released memory resource", null, false, false);
@SuppressWarnings("serial")
private final Supplier<RuntimeException> runtimeExceptionSupplier;
public ScopedAccessError(Supplier<RuntimeException> runtimeExceptionSupplier) {
super("Invalid memory access", null, false, false);
this.runtimeExceptionSupplier = runtimeExceptionSupplier;
}
static final long serialVersionUID = 1L;
public static final ScopedAccessError INSTANCE = new ScopedAccessError();
public final RuntimeException newRuntimeException() {
return runtimeExceptionSupplier.get();
}
}
@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
@ -112,64 +121,64 @@ public class ScopedMemoryAccess {
// bulk ops
@ForceInline
public void copyMemory(MemorySessionImpl srcScope, MemorySessionImpl dstScope,
public void copyMemory(MemorySessionImpl srcSession, MemorySessionImpl dstSession,
Object srcBase, long srcOffset,
Object destBase, long destOffset,
long bytes) {
try {
copyMemoryInternal(srcScope, dstScope, srcBase, srcOffset, destBase, destOffset, bytes);
copyMemoryInternal(srcSession, dstSession, srcBase, srcOffset, destBase, destOffset, bytes);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
throw ex.newRuntimeException();
}
}
@ForceInline @Scoped
private void copyMemoryInternal(MemorySessionImpl srcScope, MemorySessionImpl dstScope,
private void copyMemoryInternal(MemorySessionImpl srcSession, MemorySessionImpl dstSession,
Object srcBase, long srcOffset,
Object destBase, long destOffset,
long bytes) {
try {
if (srcScope != null) {
srcScope.checkValidState();
if (srcSession != null) {
srcSession.checkValidStateRaw();
}
if (dstScope != null) {
dstScope.checkValidState();
if (dstSession != null) {
dstSession.checkValidStateRaw();
}
UNSAFE.copyMemory(srcBase, srcOffset, destBase, destOffset, bytes);
} finally {
Reference.reachabilityFence(srcScope);
Reference.reachabilityFence(dstScope);
Reference.reachabilityFence(srcSession);
Reference.reachabilityFence(dstSession);
}
}
@ForceInline
public void copySwapMemory(MemorySessionImpl srcScope, MemorySessionImpl dstScope,
public void copySwapMemory(MemorySessionImpl srcSession, MemorySessionImpl dstSession,
Object srcBase, long srcOffset,
Object destBase, long destOffset,
long bytes, long elemSize) {
try {
copySwapMemoryInternal(srcScope, dstScope, srcBase, srcOffset, destBase, destOffset, bytes, elemSize);
copySwapMemoryInternal(srcSession, dstSession, srcBase, srcOffset, destBase, destOffset, bytes, elemSize);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
throw ex.newRuntimeException();
}
}
@ForceInline @Scoped
private void copySwapMemoryInternal(MemorySessionImpl srcScope, MemorySessionImpl dstScope,
private void copySwapMemoryInternal(MemorySessionImpl srcSession, MemorySessionImpl dstSession,
Object srcBase, long srcOffset,
Object destBase, long destOffset,
long bytes, long elemSize) {
try {
if (srcScope != null) {
srcScope.checkValidState();
if (srcSession != null) {
srcSession.checkValidStateRaw();
}
if (dstScope != null) {
dstScope.checkValidState();
if (dstSession != null) {
dstSession.checkValidStateRaw();
}
UNSAFE.copySwapMemory(srcBase, srcOffset, destBase, destOffset, bytes, elemSize);
} finally {
Reference.reachabilityFence(srcScope);
Reference.reachabilityFence(dstScope);
Reference.reachabilityFence(srcSession);
Reference.reachabilityFence(dstSession);
}
}
@ -178,7 +187,7 @@ public class ScopedMemoryAccess {
try {
setMemoryInternal(session, o, offset, bytes, value);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
throw ex.newRuntimeException();
}
}
@ -186,7 +195,7 @@ public class ScopedMemoryAccess {
private void setMemoryInternal(MemorySessionImpl session, Object o, long offset, long bytes, byte value) {
try {
if (session != null) {
session.checkValidState();
session.checkValidStateRaw();
}
UNSAFE.setMemory(o, offset, bytes, value);
} finally {
@ -195,35 +204,35 @@ public class ScopedMemoryAccess {
}
@ForceInline
public int vectorizedMismatch(MemorySessionImpl aScope, MemorySessionImpl bScope,
public int vectorizedMismatch(MemorySessionImpl aSession, MemorySessionImpl bSession,
Object a, long aOffset,
Object b, long bOffset,
int length,
int log2ArrayIndexScale) {
try {
return vectorizedMismatchInternal(aScope, bScope, a, aOffset, b, bOffset, length, log2ArrayIndexScale);
return vectorizedMismatchInternal(aSession, bSession, a, aOffset, b, bOffset, length, log2ArrayIndexScale);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
throw ex.newRuntimeException();
}
}
@ForceInline @Scoped
private int vectorizedMismatchInternal(MemorySessionImpl aScope, MemorySessionImpl bScope,
private int vectorizedMismatchInternal(MemorySessionImpl aSession, MemorySessionImpl bSession,
Object a, long aOffset,
Object b, long bOffset,
int length,
int log2ArrayIndexScale) {
try {
if (aScope != null) {
aScope.checkValidState();
if (aSession != null) {
aSession.checkValidStateRaw();
}
if (bScope != null) {
bScope.checkValidState();
if (bSession != null) {
bSession.checkValidStateRaw();
}
return ArraysSupport.vectorizedMismatch(a, aOffset, b, bOffset, length, log2ArrayIndexScale);
} finally {
Reference.reachabilityFence(aScope);
Reference.reachabilityFence(bScope);
Reference.reachabilityFence(aSession);
Reference.reachabilityFence(bSession);
}
}
@ -232,7 +241,7 @@ public class ScopedMemoryAccess {
try {
return isLoadedInternal(session, address, isSync, size);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
throw ex.newRuntimeException();
}
}
@ -240,7 +249,7 @@ public class ScopedMemoryAccess {
public boolean isLoadedInternal(MemorySessionImpl session, long address, boolean isSync, long size) {
try {
if (session != null) {
session.checkValidState();
session.checkValidStateRaw();
}
return SharedSecrets.getJavaNioAccess().isLoaded(address, isSync, size);
} finally {
@ -253,7 +262,7 @@ public class ScopedMemoryAccess {
try {
loadInternal(session, address, isSync, size);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
throw ex.newRuntimeException();
}
}
@ -261,7 +270,7 @@ public class ScopedMemoryAccess {
public void loadInternal(MemorySessionImpl session, long address, boolean isSync, long size) {
try {
if (session != null) {
session.checkValidState();
session.checkValidStateRaw();
}
SharedSecrets.getJavaNioAccess().load(address, isSync, size);
} finally {
@ -274,7 +283,7 @@ public class ScopedMemoryAccess {
try {
unloadInternal(session, address, isSync, size);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
throw ex.newRuntimeException();
}
}
@ -282,7 +291,7 @@ public class ScopedMemoryAccess {
public void unloadInternal(MemorySessionImpl session, long address, boolean isSync, long size) {
try {
if (session != null) {
session.checkValidState();
session.checkValidStateRaw();
}
SharedSecrets.getJavaNioAccess().unload(address, isSync, size);
} finally {
@ -295,7 +304,7 @@ public class ScopedMemoryAccess {
try {
forceInternal(session, fd, address, isSync, index, length);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
throw ex.newRuntimeException();
}
}
@ -303,7 +312,7 @@ public class ScopedMemoryAccess {
public void forceInternal(MemorySessionImpl session, FileDescriptor fd, long address, boolean isSync, long index, long length) {
try {
if (session != null) {
session.checkValidState();
session.checkValidStateRaw();
}
SharedSecrets.getJavaNioAccess().force(fd, address, isSync, index, length);
} finally {
@ -333,7 +342,7 @@ public class ScopedMemoryAccess {
s,
defaultImpl);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
throw ex.newRuntimeException();
}
}
@ -347,7 +356,7 @@ public class ScopedMemoryAccess {
S s,
VectorSupport.LoadOperation<AbstractMemorySegmentImpl, V, S> defaultImpl) {
try {
session.checkValidState();
session.checkValidStateRaw();
return VectorSupport.load(vmClass, e, length,
msp.unsafeGetBase(), msp.unsafeGetOffset() + offset,
@ -378,7 +387,7 @@ public class ScopedMemoryAccess {
s, offsetInRange,
defaultImpl);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
throw ex.newRuntimeException();
}
}
@ -393,7 +402,7 @@ public class ScopedMemoryAccess {
S s, int offsetInRange,
VectorSupport.LoadVectorMaskedOperation<AbstractMemorySegmentImpl, V, S, M> defaultImpl) {
try {
session.checkValidState();
session.checkValidStateRaw();
return VectorSupport.loadMasked(vmClass, maskClass, e, length,
msp.unsafeGetBase(), msp.unsafeGetOffset() + offset, m, offsetInRange,
@ -424,7 +433,7 @@ public class ScopedMemoryAccess {
msp, offset,
defaultImpl);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
throw ex.newRuntimeException();
}
}
@ -438,7 +447,7 @@ public class ScopedMemoryAccess {
AbstractMemorySegmentImpl msp, long offset,
VectorSupport.StoreVectorOperation<AbstractMemorySegmentImpl, V> defaultImpl) {
try {
session.checkValidState();
session.checkValidStateRaw();
VectorSupport.store(vmClass, e, length,
msp.unsafeGetBase(), msp.unsafeGetOffset() + offset,
@ -470,7 +479,7 @@ public class ScopedMemoryAccess {
msp, offset,
defaultImpl);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
throw ex.newRuntimeException();
}
}
@ -484,7 +493,7 @@ public class ScopedMemoryAccess {
AbstractMemorySegmentImpl msp, long offset,
VectorSupport.StoreVectorMaskedOperation<AbstractMemorySegmentImpl, V, M> defaultImpl) {
try {
session.checkValidState();
session.checkValidStateRaw();
VectorSupport.storeMasked(vmClass, maskClass, e, length,
msp.unsafeGetBase(), msp.unsafeGetOffset() + offset,

View File

@ -1199,9 +1199,6 @@ public class FileChannelImpl
}
}
private static final int MAP_MEM_SEG_DEFAULT_MODES = 0;
private static final int MAP_MEM_SEG_READ_ONLY = 1;
@Override
public MemorySegment map(MapMode mode, long offset, long size,
MemorySession session)
@ -1210,7 +1207,7 @@ public class FileChannelImpl
Objects.requireNonNull(mode,"Mode is null");
Objects.requireNonNull(session, "Session is null");
MemorySessionImpl sessionImpl = MemorySessionImpl.toSessionImpl(session);
sessionImpl.checkValidStateSlow();
sessionImpl.checkValidState();
if (offset < 0)
throw new IllegalArgumentException("Requested bytes offset must be >= 0.");
if (size < 0)
@ -1219,14 +1216,14 @@ public class FileChannelImpl
boolean isSync = isSync(mode);
int prot = toProt(mode);
Unmapper unmapper = mapInternal(mode, offset, size, prot, isSync);
int modes = MAP_MEM_SEG_DEFAULT_MODES;
boolean readOnly = false;
if (mode == MapMode.READ_ONLY) {
modes |= MAP_MEM_SEG_READ_ONLY;
readOnly = true;
}
if (unmapper != null) {
AbstractMemorySegmentImpl segment =
new MappedMemorySegmentImpl(unmapper.address(), unmapper, size,
modes, session);
readOnly, session);
MemorySessionImpl.ResourceList.ResourceCleanup resource =
new MemorySessionImpl.ResourceList.ResourceCleanup() {
@Override
@ -1237,7 +1234,7 @@ public class FileChannelImpl
sessionImpl.addOrCleanupIfFail(resource);
return segment;
} else {
return new MappedMemorySegmentImpl.EmptyMappedMemorySegmentImpl(modes, session);
return new MappedMemorySegmentImpl.EmptyMappedMemorySegmentImpl(readOnly, sessionImpl);
}
}

View File

@ -373,7 +373,7 @@ public class TestByteBuffer {
Throwable cause = ex.getCause();
if (cause instanceof IllegalStateException) {
//all get/set buffer operation should fail because of the session check
assertTrue(ex.getCause().getMessage().contains("already closed"));
assertTrue(ex.getCause().getMessage().contains("Already closed"));
} else {
//all other exceptions were unexpected - fail
fail("Unexpected exception", cause);
@ -410,7 +410,7 @@ public class TestByteBuffer {
handle.invoke(e.getValue());
fail();
} catch (IllegalStateException ex) {
assertTrue(ex.getMessage().contains("already closed"));
assertTrue(ex.getMessage().contains("Already closed"));
} catch (UnsupportedOperationException ex) {
//skip
} catch (Throwable ex) {

View File

@ -370,8 +370,8 @@ public class TestMemorySession {
}
private void keepAlive(MemorySession child, MemorySession parent) {
MemorySessionImpl sessionImpl = MemorySessionImpl.toSessionImpl(parent);
sessionImpl.acquire0();
child.addCloseAction(sessionImpl::release0);
MemorySessionImpl parentImpl = MemorySessionImpl.toSessionImpl(parent);
parentImpl.acquire0();
child.addCloseAction(parentImpl::release0);
}
}