--- old/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java 2019-12-09 18:35:44.251042161 +0000 +++ new/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java 2019-12-09 18:35:43.771030523 +0000 @@ -1792,9 +1792,9 @@ } @Override - public VarHandle memoryAddressViewVarHandle(Class carrier, long alignment, + public VarHandle memoryAddressViewVarHandle(Class carrier, long alignmentMask, ByteOrder order, long offset, long[] strides) { - return VarHandles.makeMemoryAddressViewHandle(carrier, alignment, order, offset, strides); + return VarHandles.makeMemoryAddressViewHandle(carrier, alignmentMask, order, offset, strides); } @Override @@ -1803,8 +1803,8 @@ } @Override - public long memoryAddressAlignment(VarHandle handle) { - return checkMemAccessHandle(handle).alignment + 1; + public long memoryAddressAlignmentMask(VarHandle handle) { + return checkMemAccessHandle(handle).alignmentMask; } @Override --- old/src/java.base/share/classes/java/lang/invoke/VarHandleMemoryAddressBase.java 2019-12-09 18:35:45.115063110 +0000 +++ new/src/java.base/share/classes/java/lang/invoke/VarHandleMemoryAddressBase.java 2019-12-09 18:35:44.643051665 +0000 @@ -29,23 +29,34 @@ * Base class for memory access var handle implementations. */ abstract class VarHandleMemoryAddressBase extends VarHandle { + + /** endianness **/ final boolean be; + + /** access size (in bytes, computed from var handle carrier type) **/ final long length; + + /** access offset (in bytes); must be compatible with {@code alignmentMask} **/ final long offset; - final long alignment; - VarHandleMemoryAddressBase(VarForm form, boolean be, long length, long offset, long alignment) { + /** alignment constraint (in bytes, expressed as a bit mask) **/ + final long alignmentMask; + + VarHandleMemoryAddressBase(VarForm form, boolean be, long length, long offset, long alignmentMask) { super(form); this.be = be; this.length = length; this.offset = offset; - this.alignment = alignment; + this.alignmentMask = alignmentMask; } static IllegalStateException newIllegalStateExceptionForMisalignedAccess(long address) { return new IllegalStateException("Misaligned access at address: " + address); } + /** + * Strides used for multi-dimensional access; each stride must be compatible with {@code alignmentMask}. + */ abstract long[] strides(); abstract Class carrier(); --- old/src/java.base/share/classes/java/lang/invoke/VarHandles.java 2019-12-09 18:35:45.891081927 +0000 +++ new/src/java.base/share/classes/java/lang/invoke/VarHandles.java 2019-12-09 18:35:45.463071548 +0000 @@ -303,13 +303,13 @@ * to a single fixed offset to compute an effective offset from the given MemoryAddress for the access. * * @param carrier the Java carrier type. - * @param alignment alignment requirement to be checked upon access. In bytes. Must be a power of 2. + * @param alignmentMask alignment requirement to be checked upon access. In bytes. Expressed as a mask. * @param byteOrder the byte order. * @param offset a constant offset for the access. * @param strides the scale factors with which to multiply given access coordinates. * @return the created VarHandle. */ - static VarHandle makeMemoryAddressViewHandle(Class carrier, long alignment, + static VarHandle makeMemoryAddressViewHandle(Class carrier, long alignmentMask, ByteOrder byteOrder, long offset, long[] strides) { if (!carrier.isPrimitive() || carrier == void.class || carrier == boolean.class) { throw new IllegalArgumentException("Invalid carrier: " + carrier.getName()); @@ -323,7 +323,7 @@ .generateHandleFactory()); try { - return (VarHandle)fac.invoke(be, size, offset, alignment - 1, strides); + return (VarHandle)fac.invoke(be, size, offset, alignmentMask, strides); } catch (Throwable ex) { throw new IllegalStateException(ex); } --- old/src/java.base/share/classes/java/lang/invoke/X-VarHandleMemoryAddressView.java.template 2019-12-09 18:35:46.759102975 +0000 +++ new/src/java.base/share/classes/java/lang/invoke/X-VarHandleMemoryAddressView.java.template 2019-12-09 18:35:46.283091432 +0000 @@ -37,6 +37,8 @@ static final boolean BE = UNSAFE.isBigEndian(); + static final int VM_ALIGN = $BoxType$.BYTES - 1; + #if[floatingPoint] @ForceInline static $rawType$ convEndian(boolean big, $type$ v) { @@ -71,9 +73,21 @@ } @ForceInline - static long offset(MemoryAddressProxy bb, long offset, long alignment) { + static long offset(MemoryAddressProxy bb, long offset, long alignmentMask) { + long address = bb.unsafeGetOffset() + offset; + if ((address & alignmentMask) != 0) { + throw VarHandleMemoryAddressBase.newIllegalStateExceptionForMisalignedAccess(address); + } + if ((address & VM_ALIGN) != 0) { + throw VarHandleMemoryAddressBase.newIllegalStateExceptionForMisalignedAccess(address); + } + return address; + } + + @ForceInline + static long offsetNoVMAlignCheck(MemoryAddressProxy bb, long offset, long alignmentMask) { long address = bb.unsafeGetOffset() + offset; - if ((address & alignment) != 0) { + if ((address & alignmentMask) != 0) { throw VarHandleMemoryAddressBase.newIllegalStateExceptionForMisalignedAccess(address); } return address; @@ -85,18 +99,18 @@ #if[floatingPoint] $rawType$ rawValue = UNSAFE.get$RawType$Unaligned( bb.unsafeGetBase(), - offset(bb, base, handle.alignment), + offsetNoVMAlignCheck(bb, base, handle.alignmentMask), handle.be); return $Type$.$rawType$BitsTo$Type$(rawValue); #else[floatingPoint] #if[byte] return UNSAFE.get$Type$( bb.unsafeGetBase(), - offset(bb, base, handle.alignment)); + offsetNoVMAlignCheck(bb, base, handle.alignmentMask)); #else[byte] return UNSAFE.get$Type$Unaligned( bb.unsafeGetBase(), - offset(bb, base, handle.alignment), + offsetNoVMAlignCheck(bb, base, handle.alignmentMask), handle.be); #end[byte] #end[floatingPoint] @@ -108,19 +122,19 @@ #if[floatingPoint] UNSAFE.put$RawType$Unaligned( bb.unsafeGetBase(), - offset(bb, base, handle.alignment), + offsetNoVMAlignCheck(bb, base, handle.alignmentMask), $Type$.$type$ToRaw$RawType$Bits(value), handle.be); #else[floatingPoint] #if[byte] UNSAFE.put$Type$( bb.unsafeGetBase(), - offset(bb, base, handle.alignment), + offsetNoVMAlignCheck(bb, base, handle.alignmentMask), value); #else[byte] UNSAFE.put$Type$Unaligned( bb.unsafeGetBase(), - offset(bb, base, handle.alignment), + offsetNoVMAlignCheck(bb, base, handle.alignmentMask), value, handle.be); #end[byte] @@ -133,7 +147,7 @@ return convEndian(handle.be, UNSAFE.get$RawType$Volatile( bb.unsafeGetBase(), - offset(bb, base, handle.alignment))); + offset(bb, base, handle.alignmentMask))); } @ForceInline @@ -141,7 +155,7 @@ MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false); UNSAFE.put$RawType$Volatile( bb.unsafeGetBase(), - offset(bb, base, handle.alignment), + offset(bb, base, handle.alignmentMask), convEndian(handle.be, value)); } @@ -151,7 +165,7 @@ return convEndian(handle.be, UNSAFE.get$RawType$Acquire( bb.unsafeGetBase(), - offset(bb, base, handle.alignment))); + offset(bb, base, handle.alignmentMask))); } @ForceInline @@ -159,7 +173,7 @@ MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false); UNSAFE.put$RawType$Release( bb.unsafeGetBase(), - offset(bb, base, handle.alignment), + offset(bb, base, handle.alignmentMask), convEndian(handle.be, value)); } @@ -169,7 +183,7 @@ return convEndian(handle.be, UNSAFE.get$RawType$Opaque( bb.unsafeGetBase(), - offset(bb, base, handle.alignment))); + offset(bb, base, handle.alignmentMask))); } @ForceInline @@ -177,7 +191,7 @@ MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false); UNSAFE.put$RawType$Opaque( bb.unsafeGetBase(), - offset(bb, base, handle.alignment), + offset(bb, base, handle.alignmentMask), convEndian(handle.be, value)); } #if[CAS] @@ -187,7 +201,7 @@ MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false); return UNSAFE.compareAndSet$RawType$( bb.unsafeGetBase(), - offset(bb, base, handle.alignment), + offset(bb, base, handle.alignmentMask), convEndian(handle.be, expected), convEndian(handle.be, value)); } @@ -197,7 +211,7 @@ return convEndian(handle.be, UNSAFE.compareAndExchange$RawType$( bb.unsafeGetBase(), - offset(bb, base, handle.alignment), + offset(bb, base, handle.alignmentMask), convEndian(handle.be, expected), convEndian(handle.be, value))); } @@ -207,7 +221,7 @@ return convEndian(handle.be, UNSAFE.compareAndExchange$RawType$Acquire( bb.unsafeGetBase(), - offset(bb, base, handle.alignment), + offset(bb, base, handle.alignmentMask), convEndian(handle.be, expected), convEndian(handle.be, value))); } @@ -217,7 +231,7 @@ return convEndian(handle.be, UNSAFE.compareAndExchange$RawType$Release( bb.unsafeGetBase(), - offset(bb, base, handle.alignment), + offset(bb, base, handle.alignmentMask), convEndian(handle.be, expected), convEndian(handle.be, value))); } @@ -226,7 +240,7 @@ MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false); return UNSAFE.weakCompareAndSet$RawType$Plain( bb.unsafeGetBase(), - offset(bb, base, handle.alignment), + offset(bb, base, handle.alignmentMask), convEndian(handle.be, expected), convEndian(handle.be, value)); } @@ -235,7 +249,7 @@ MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false); return UNSAFE.weakCompareAndSet$RawType$( bb.unsafeGetBase(), - offset(bb, base, handle.alignment), + offset(bb, base, handle.alignmentMask), convEndian(handle.be, expected), convEndian(handle.be, value)); } @@ -244,7 +258,7 @@ MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false); return UNSAFE.weakCompareAndSet$RawType$Acquire( bb.unsafeGetBase(), - offset(bb, base, handle.alignment), + offset(bb, base, handle.alignmentMask), convEndian(handle.be, expected), convEndian(handle.be, value)); } @@ -253,7 +267,7 @@ MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false); return UNSAFE.weakCompareAndSet$RawType$Release( bb.unsafeGetBase(), - offset(bb, base, handle.alignment), + offset(bb, base, handle.alignmentMask), convEndian(handle.be, expected), convEndian(handle.be, value)); } @@ -263,7 +277,7 @@ return convEndian(handle.be, UNSAFE.getAndSet$RawType$( bb.unsafeGetBase(), - offset(bb, base, handle.alignment), + offset(bb, base, handle.alignmentMask), convEndian(handle.be, value))); } @@ -273,7 +287,7 @@ return convEndian(handle.be, UNSAFE.getAndSet$RawType$Acquire( bb.unsafeGetBase(), - offset(bb, base, handle.alignment), + offset(bb, base, handle.alignmentMask), convEndian(handle.be, value))); } @@ -283,7 +297,7 @@ return convEndian(handle.be, UNSAFE.getAndSet$RawType$Release( bb.unsafeGetBase(), - offset(bb, base, handle.alignment), + offset(bb, base, handle.alignmentMask), convEndian(handle.be, value))); } #end[CAS] @@ -295,10 +309,10 @@ if (handle.be == BE) { return UNSAFE.getAndAdd$RawType$( bb.unsafeGetBase(), - offset(bb, base, handle.alignment), + offset(bb, base, handle.alignmentMask), delta); } else { - return getAndAddConvEndianWithCAS(bb, offset(bb, base, handle.alignment), delta); + return getAndAddConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), delta); } } @@ -308,10 +322,10 @@ if (handle.be == BE) { return UNSAFE.getAndAdd$RawType$Acquire( bb.unsafeGetBase(), - offset(bb, base, handle.alignment), + offset(bb, base, handle.alignmentMask), delta); } else { - return getAndAddConvEndianWithCAS(bb, offset(bb, base, handle.alignment), delta); + return getAndAddConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), delta); } } @@ -321,10 +335,10 @@ if (handle.be == BE) { return UNSAFE.getAndAdd$RawType$Release( bb.unsafeGetBase(), - offset(bb, base, handle.alignment), + offset(bb, base, handle.alignmentMask), delta); } else { - return getAndAddConvEndianWithCAS(bb, offset(bb, base, handle.alignment), delta); + return getAndAddConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), delta); } } @@ -348,10 +362,10 @@ if (handle.be == BE) { return UNSAFE.getAndBitwiseOr$RawType$( bb.unsafeGetBase(), - offset(bb, base, handle.alignment), + offset(bb, base, handle.alignmentMask), value); } else { - return getAndBitwiseOrConvEndianWithCAS(bb, offset(bb, base, handle.alignment), value); + return getAndBitwiseOrConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), value); } } @@ -361,10 +375,10 @@ if (handle.be == BE) { return UNSAFE.getAndBitwiseOr$RawType$Release( bb.unsafeGetBase(), - offset(bb, base, handle.alignment), + offset(bb, base, handle.alignmentMask), value); } else { - return getAndBitwiseOrConvEndianWithCAS(bb, offset(bb, base, handle.alignment), value); + return getAndBitwiseOrConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), value); } } @@ -374,10 +388,10 @@ if (handle.be == BE) { return UNSAFE.getAndBitwiseOr$RawType$Acquire( bb.unsafeGetBase(), - offset(bb, base, handle.alignment), + offset(bb, base, handle.alignmentMask), value); } else { - return getAndBitwiseOrConvEndianWithCAS(bb, offset(bb, base, handle.alignment), value); + return getAndBitwiseOrConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), value); } } @@ -399,10 +413,10 @@ if (handle.be == BE) { return UNSAFE.getAndBitwiseAnd$RawType$( bb.unsafeGetBase(), - offset(bb, base, handle.alignment), + offset(bb, base, handle.alignmentMask), value); } else { - return getAndBitwiseAndConvEndianWithCAS(bb, offset(bb, base, handle.alignment), value); + return getAndBitwiseAndConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), value); } } @@ -412,10 +426,10 @@ if (handle.be == BE) { return UNSAFE.getAndBitwiseAnd$RawType$Release( bb.unsafeGetBase(), - offset(bb, base, handle.alignment), + offset(bb, base, handle.alignmentMask), value); } else { - return getAndBitwiseAndConvEndianWithCAS(bb, offset(bb, base, handle.alignment), value); + return getAndBitwiseAndConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), value); } } @@ -425,10 +439,10 @@ if (handle.be == BE) { return UNSAFE.getAndBitwiseAnd$RawType$Acquire( bb.unsafeGetBase(), - offset(bb, base, handle.alignment), + offset(bb, base, handle.alignmentMask), value); } else { - return getAndBitwiseAndConvEndianWithCAS(bb, offset(bb, base, handle.alignment), value); + return getAndBitwiseAndConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), value); } } @@ -451,10 +465,10 @@ if (handle.be == BE) { return UNSAFE.getAndBitwiseXor$RawType$( bb.unsafeGetBase(), - offset(bb, base, handle.alignment), + offset(bb, base, handle.alignmentMask), value); } else { - return getAndBitwiseXorConvEndianWithCAS(bb, offset(bb, base, handle.alignment), value); + return getAndBitwiseXorConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), value); } } @@ -464,10 +478,10 @@ if (handle.be == BE) { return UNSAFE.getAndBitwiseXor$RawType$Release( bb.unsafeGetBase(), - offset(bb, base, handle.alignment), + offset(bb, base, handle.alignmentMask), value); } else { - return getAndBitwiseXorConvEndianWithCAS(bb, offset(bb, base, handle.alignment), value); + return getAndBitwiseXorConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), value); } } @@ -477,10 +491,10 @@ if (handle.be == BE) { return UNSAFE.getAndBitwiseXor$RawType$Acquire( bb.unsafeGetBase(), - offset(bb, base, handle.alignment), + offset(bb, base, handle.alignmentMask), value); } else { - return getAndBitwiseXorConvEndianWithCAS(bb, offset(bb, base, handle.alignment), value); + return getAndBitwiseXorConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), value); } } --- old/src/java.base/share/classes/java/nio/Buffer.java 2019-12-09 18:35:47.627124024 +0000 +++ new/src/java.base/share/classes/java/nio/Buffer.java 2019-12-09 18:35:47.159112674 +0000 @@ -763,8 +763,8 @@ } @Override - public ByteBuffer newDirectByteBuffer(long addr, int cap, Object ob, MemorySegmentProxy segment) { - return new DirectByteBuffer(addr, cap, ob, segment); + public ByteBuffer newDirectByteBuffer(long addr, int cap, Object obj, MemorySegmentProxy segment) { + return new DirectByteBuffer(addr, cap, obj, segment); } @Override --- old/src/java.base/share/classes/jdk/internal/access/JavaLangInvokeAccess.java 2019-12-09 18:35:48.519145656 +0000 +++ new/src/java.base/share/classes/jdk/internal/access/JavaLangInvokeAccess.java 2019-12-09 18:35:48.031133822 +0000 @@ -110,32 +110,39 @@ /** * Returns a var handle view of a given memory address. + * Used by {@code jdk.internal.foreign.LayoutPath} and + * {@code jdk.incubator.foreign.MemoryHandles}. */ - VarHandle memoryAddressViewVarHandle(Class carrier, long alignment, + VarHandle memoryAddressViewVarHandle(Class carrier, long alignmentMask, ByteOrder order, long offset, long[] strides); /** * Returns the carrier associated with a memory access var handle. + * Used by {@code jdk.incubator.foreign.MemoryHandles}. */ Class memoryAddressCarrier(VarHandle handle); /** - * Returns the alignment associated with a memory access var handle. + * Returns the alignment mask associated with a memory access var handle. + * Used by {@code jdk.incubator.foreign.MemoryHandles}. */ - long memoryAddressAlignment(VarHandle handle); + long memoryAddressAlignmentMask(VarHandle handle); /** * Returns the byte order associated with a memory access var handle. + * Used by {@code jdk.incubator.foreign.MemoryHandles}. */ ByteOrder memoryAddressByteOrder(VarHandle handle); /** * Returns the offset associated with a memory access var handle. + * Used by {@code jdk.incubator.foreign.MemoryHandles}. */ long memoryAddressOffset(VarHandle handle); /** * Returns the strides associated with a memory access var handle. + * Used by {@code jdk.incubator.foreign.MemoryHandles}. */ long[] memoryAddressStrides(VarHandle handle); } --- old/src/java.base/share/classes/jdk/internal/access/JavaNioAccess.java 2019-12-09 18:35:49.331165348 +0000 +++ new/src/java.base/share/classes/jdk/internal/access/JavaNioAccess.java 2019-12-09 18:35:48.875154289 +0000 @@ -47,17 +47,28 @@ * at the given memory address and extending {@code cap} bytes. * The {@code ob} parameter is an arbitrary object that is attached * to the resulting buffer. + * Used by {@code jdk.internal.foreignMemorySegmentImpl}. */ - ByteBuffer newDirectByteBuffer(long addr, int cap, Object ob, MemorySegmentProxy segment); + ByteBuffer newDirectByteBuffer(long addr, int cap, Object obj, MemorySegmentProxy segment); /** * Constructs an heap ByteBuffer with given backing array, offset, capacity and segment. + * Used by {@code jdk.internal.foreignMemorySegmentImpl}. */ ByteBuffer newHeapByteBuffer(byte[] hb, int offset, int capacity, MemorySegmentProxy segment); + /** + * Used by {@code jdk.internal.foreign.Utils}. + */ Object getBufferBase(ByteBuffer bb); + /** + * Used by {@code jdk.internal.foreign.Utils}. + */ long getBufferAddress(ByteBuffer bb); + /** + * Used by byte buffer var handle views. + */ void checkSegment(Buffer buffer); } --- old/src/java.base/share/classes/jdk/internal/access/foreign/MemoryAddressProxy.java 2019-12-09 18:35:50.159185430 +0000 +++ new/src/java.base/share/classes/jdk/internal/access/foreign/MemoryAddressProxy.java 2019-12-09 18:35:49.711174564 +0000 @@ -31,6 +31,11 @@ * an incubating module) to be accessed from the memory access var handles. */ public interface MemoryAddressProxy { + /** + * Check that memory access is within spatial and temporal bounds. + * @throws IllegalStateException if underlying segment has been closed already. + * @throws IndexOutOfBoundsException if access is out-of-bounds. + */ void checkAccess(long offset, long length, boolean readOnly); long unsafeGetOffset(); Object unsafeGetBase(); --- old/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java 2019-12-09 18:35:50.983205416 +0000 +++ new/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java 2019-12-09 18:35:50.531194453 +0000 @@ -1001,8 +1001,7 @@ return Util.newMappedByteBufferR(0, 0, dummy, null, isSync); else return Util.newMappedByteBuffer(0, 0, dummy, null, isSync); - } - else if ((!writable) || (prot == MAP_RO)) { + } else if ((!writable) || (prot == MAP_RO)) { return Util.newMappedByteBufferR((int)unmapper.cap, unmapper.address + unmapper.pagePosition, unmapper.fd, @@ -1123,13 +1122,13 @@ private int toProt(MapMode mode) { int prot; - if (mode == MapMode.READ_ONLY) + if (mode == MapMode.READ_ONLY) { prot = MAP_RO; - else if (mode == MapMode.READ_WRITE) + } else if (mode == MapMode.READ_WRITE) { prot = MAP_RW; - else if (mode == MapMode.PRIVATE) + } else if (mode == MapMode.PRIVATE) { prot = MAP_PV; - else if (mode == ExtendedMapMode.READ_ONLY_SYNC) { + } else if (mode == ExtendedMapMode.READ_ONLY_SYNC) { prot = MAP_RO; } else if (mode == ExtendedMapMode.READ_WRITE_SYNC) { prot = MAP_RW; --- old/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/MemoryAddress.java 2019-12-09 18:35:51.887227343 +0000 +++ new/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/MemoryAddress.java 2019-12-09 18:35:51.407215699 +0000 @@ -60,7 +60,7 @@ MemoryAddress offset(long l); /** - * The offset of this MemoryAddress into the underlying segment. + * The offset of this memory address into the underlying segment. * * @return the offset */ --- old/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/MemoryHandles.java 2019-12-09 18:35:52.735247912 +0000 +++ new/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/MemoryHandles.java 2019-12-09 18:35:52.271236657 +0000 @@ -81,14 +81,10 @@ * *

Alignment and access modes

* - * Memory access may be aligned or misaligned for the given carrier {@code T}, - * with respect to the underlying memory address, {@code A} say, which is the final address (computed by the formula described above) - * at which the memory dereference operation occurs. - * - * If access is misaligned then access for anything other than the {@code get} and {@code set} access modes will result - * in an {@code IllegalStateException}. In such cases atomic access is only guaranteed with respect to the largest power - * of two that divides the GCD of {@code A} and the size (in bytes) of {@code T}. - * If access is aligned then following access modes are supported and are + * A memory access var handle is associated with an access size {@code S} and an alignment constraint {@code B} + * (both expressed in bytes). We say that a memory access operation is fully aligned if it occurs + * at a memory address {@code A} which is compatible with both alignment constraints {@code S} and {@code B}. + * If access is fully aligned then following access modes are supported and are * guaranteed to support atomic access: * - *

+ * * If {@code T} is {@code float} or {@code double} then atomic * update access modes compare values using their bitwise representation * (see {@link Float#floatToRawIntBits} and * {@link Double#doubleToRawLongBits}, respectively). + *

+ * Alternatively, a memory access operation is partially aligned if it occurs at a memory address {@code A} + * which is only compatible with the alignment constraint {@code B}; in such cases, access for anything other than the + * {@code get} and {@code set} access modes will result in an {@code IllegalStateException}. If access is partially aligned, + * atomic access is only guaranteed with respect to the largest power of two that divides the GCD of {@code A} and {@code S}. + *

+ * Finally, in all other cases, we say that a memory access operation is misaligned; in such cases an + * {@code IllegalStateException} is thrown, irrespective of the access mode being used. */ public final class MemoryHandles { @@ -170,7 +174,7 @@ throw new IllegalArgumentException("Bad alignment: " + alignmentBytes); } - return JLI.memoryAddressViewVarHandle(carrier, alignmentBytes, byteOrder, 0, new long[]{}); + return JLI.memoryAddressViewVarHandle(carrier, alignmentBytes - 1, byteOrder, 0, new long[]{}); } /** @@ -194,15 +198,15 @@ throw new IllegalArgumentException("Illegal offset: " + bytesOffset); } - long align = JLI.memoryAddressAlignment(target); + long alignMask = JLI.memoryAddressAlignmentMask(target); - if (bytesOffset % align != 0) { - throw new IllegalArgumentException("Offset " + bytesOffset + " does not conform to alignment " + align); + if ((bytesOffset & alignMask) != 0) { + throw new IllegalArgumentException("Offset " + bytesOffset + " does not conform to alignment " + (alignMask + 1)); } return JLI.memoryAddressViewVarHandle( JLI.memoryAddressCarrier(target), - align, + alignMask, JLI.memoryAddressByteOrder(target), JLI.memoryAddressOffset(target) + bytesOffset, JLI.memoryAddressStrides(target)); @@ -230,14 +234,13 @@ throw new IllegalArgumentException("Stride must be positive: " + bytesStride); } - long align = JLI.memoryAddressAlignment(target); + long alignMask = JLI.memoryAddressAlignmentMask(target); - if (bytesStride % align != 0) { - throw new IllegalArgumentException("Stride " + bytesStride + " does not conform to alignment " + align); + if ((bytesStride & alignMask) != 0) { + throw new IllegalArgumentException("Stride " + bytesStride + " does not conform to alignment " + (alignMask + 1)); } long offset = JLI.memoryAddressOffset(target); - Class carrier = JLI.memoryAddressCarrier(target); long[] strides = JLI.memoryAddressStrides(target); long[] newStrides = new long[strides.length + 1]; @@ -246,7 +249,7 @@ return JLI.memoryAddressViewVarHandle( JLI.memoryAddressCarrier(target), - align, + alignMask, JLI.memoryAddressByteOrder(target), offset, newStrides); --- old/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/MemoryLayout.java 2019-12-09 18:35:53.575268288 +0000 +++ new/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/MemoryLayout.java 2019-12-09 18:35:53.107256936 +0000 @@ -171,13 +171,13 @@ /** * Returns the alignment constraint associated with this layout, expressed in bits. Layout alignment defines a power - * of two A which is the bitwise alignment of the layout. If A>=8 then A/8 is the number of bytes that must be aligned - * for any pointer that correctly points to this layout. Thus: + * of two {@code A} which is the bit-wise alignment of the layout. If {@code A <= 8} then {@code A/8} is the number of + * bytes that must be aligned for any pointer that correctly points to this layout. Thus: * *

* * @return the layout alignment constraint, in bits. @@ -186,13 +186,13 @@ /** * Returns the alignment constraint associated with this layout, expressed in bytes. Layout alignment defines a power - * of two A which is the bytewise alignment of the layout, where A is the number of bytes that must be aligned + * of two {@code A} which is the byte-wise alignment of the layout, where {@code A} is the number of bytes that must be aligned * for any pointer that correctly points to this layout. Thus: * * * * @return the layout alignment constraint, in bytes. --- old/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/MemorySegment.java 2019-12-09 18:35:54.455289635 +0000 +++ new/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/MemorySegment.java 2019-12-09 18:35:53.991278379 +0000 @@ -79,7 +79,7 @@ *
  • closing a mapped memory segment results in the backing memory-mapped file to be unmapped
  • *
  • closing an acquired memory segment does not result in the release of resources * (see the section on thread confinement for more details)
  • - *
  • closing a buffer, or a heap segment does not have any side-effect, other than making the marking the segment + *
  • closing a buffer, or a heap segment does not have any side-effect, other than marking the segment * as not alive (see {@link MemorySegment#isAlive()}). Also, since the buffer and heap segments might keep * strong references to the original buffer or array instance, it is the responsibility of clients to ensure that * these segments are discarded in a timely manner, so as not to prevent garbage collection to reclaim the underlying --- old/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/LayoutPath.java 2019-12-09 18:35:55.275309528 +0000 +++ new/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/LayoutPath.java 2019-12-09 18:35:54.819298466 +0000 @@ -130,7 +130,7 @@ return JLI.memoryAddressViewVarHandle( carrier, - layout.byteAlignment(), + layout.byteAlignment() - 1, //mask ((ValueLayout) layout).order(), Utils.bitsToBytesOrThrow(offset, IllegalStateException::new), LongStream.of(scales).map(s -> Utils.bitsToBytesOrThrow(s, IllegalStateException::new)).toArray()); --- old/test/jdk/java/foreign/TestMemoryCopy.java 2019-12-09 18:35:56.131330295 +0000 +++ new/test/jdk/java/foreign/TestMemoryCopy.java 2019-12-09 18:35:55.671319135 +0000 @@ -28,10 +28,13 @@ */ import jdk.incubator.foreign.MemoryAddress; +import jdk.incubator.foreign.MemoryHandles; +import jdk.incubator.foreign.MemoryLayouts; import jdk.incubator.foreign.MemorySegment; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; +import java.lang.invoke.VarHandle; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -43,15 +46,27 @@ public class TestMemoryCopy { + final static VarHandle BYTE_HANDLE = MemoryLayouts.JAVA_BYTE.varHandle(byte.class); + @Test(dataProvider = "slices") - public void testBadCopy(SegmentSlice s1, SegmentSlice s2) { + public void testCopy(SegmentSlice s1, SegmentSlice s2) { MemoryAddress addr1 = s1.segment.baseAddress(); MemoryAddress addr2 = s2.segment.baseAddress(); int size = Math.min(s1.size(), s2.size()); boolean overlap = SegmentSlice.overlap(s1, s2, size); + //prepare source and target segments + for (int i = 0 ; i < size ; i++) { + BYTE_HANDLE.set(addr1.offset(i), (byte)i); + BYTE_HANDLE.set(addr2.offset(i), (byte)0); + } try { MemoryAddress.copy(addr1, addr2, size); assertFalse(overlap); + //check that copy actually worked + for (int i = 0 ; i < size ; i++) { + assertEquals((byte)i, BYTE_HANDLE.get(addr2.offset(i))); + } + } catch (IllegalArgumentException ex) { assertTrue(overlap); }