From b5d11a90e74799e6c4c6be0fc85848c351be1e9f Mon Sep 17 00:00:00 2001 From: Maurizio Cimadamore Date: Fri, 16 Aug 2024 18:54:59 +0100 Subject: [PATCH 1/6] Initial push --- .../X-VarHandleSegmentView.java.template | 243 +++++++++--------- .../jdk/internal/foreign/LayoutPath.java | 26 +- 2 files changed, 138 insertions(+), 131 deletions(-) diff --git a/src/java.base/share/classes/java/lang/invoke/X-VarHandleSegmentView.java.template b/src/java.base/share/classes/java/lang/invoke/X-VarHandleSegmentView.java.template index 0c088cd5c4b45..d490e581a6330 100644 --- a/src/java.base/share/classes/java/lang/invoke/X-VarHandleSegmentView.java.template +++ b/src/java.base/share/classes/java/lang/invoke/X-VarHandleSegmentView.java.template @@ -28,6 +28,7 @@ import jdk.internal.foreign.AbstractMemorySegmentImpl; import jdk.internal.misc.ScopedMemoryAccess; import jdk.internal.vm.annotation.ForceInline; +import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; import java.lang.ref.Reference; @@ -45,7 +46,7 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase { static final int NON_PLAIN_ACCESS_MIN_ALIGN_MASK = $BoxType$.BYTES - 1; - static final VarForm FORM = new VarForm(VarHandleSegmentAs$Type$s.class, MemorySegment.class, $type$.class, long.class); + static final VarForm FORM = new VarForm(VarHandleSegmentAs$Type$s.class, MemorySegment.class, $type$.class, MemoryLayout.class, long.class, long.class); VarHandleSegmentAs$Type$s(boolean be, long alignmentMask, boolean exact) { super(FORM, be, alignmentMask, exact); @@ -53,7 +54,7 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase { @Override final MethodType accessModeTypeUncached(VarHandle.AccessType accessType) { - return accessType.accessModeType(MemorySegment.class, $type$.class, long.class); + return accessType.accessModeType(MemorySegment.class, $type$.class, MemoryLayout.class, long.class, long.class); } @Override @@ -97,70 +98,76 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase { #end[floatingPoint] @ForceInline - static AbstractMemorySegmentImpl checkReadOnly(Object obb, boolean ro) { + static AbstractMemorySegmentImpl checkSegment(Object obb, Object encl, long base, boolean ro) { AbstractMemorySegmentImpl oo = (AbstractMemorySegmentImpl)Objects.requireNonNull(obb); - oo.checkReadOnly(ro); + MemoryLayout layout = (MemoryLayout)encl; + oo.checkAccess(base, layout.byteSize(), ro); + if (!oo.isAlignedForElement(base, layout)) { + throw new IllegalArgumentException(String.format( + "Target offset %d is incompatible with alignment constraint %d (of %s) for segment %s" + , base, layout.byteAlignment(), layout, oo)); + } return oo; } @ForceInline - static long offsetNonPlain(AbstractMemorySegmentImpl bb, long offset, long alignmentMask) { + static long offsetNonPlain(AbstractMemorySegmentImpl bb, long base, long offset, long alignmentMask) { if ((alignmentMask & NON_PLAIN_ACCESS_MIN_ALIGN_MASK) != NON_PLAIN_ACCESS_MIN_ALIGN_MASK) { throw VarHandleSegmentViewBase.newUnsupportedAccessModeForAlignment(alignmentMask + 1); } - return offsetPlain(bb, offset); + return offsetPlain(bb, base, offset); } @ForceInline - static long offsetPlain(AbstractMemorySegmentImpl bb, long offset) { - long base = bb.unsafeGetOffset(); - return base + offset; + static long offsetPlain(AbstractMemorySegmentImpl bb, long base, long offset) { + long segment_base = bb.unsafeGetOffset(); + return segment_base + base + offset; } @ForceInline - static $type$ get(VarHandle ob, Object obb, long base) { + static $type$ get(VarHandle ob, Object obb, Object encl, long base, long offset) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkReadOnly(obb, true); + AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, true); #if[floatingPoint] $rawType$ rawValue = SCOPED_MEMORY_ACCESS.get$RawType$Unaligned(bb.sessionImpl(), bb.unsafeGetBase(), - offsetPlain(bb, base), + offsetPlain(bb, base, offset), handle.be); return $Type$.$rawType$BitsTo$Type$(rawValue); #else[floatingPoint] #if[byte] return SCOPED_MEMORY_ACCESS.get$Type$(bb.sessionImpl(), bb.unsafeGetBase(), - offsetPlain(bb, base)); + offsetPlain(bb, base, offset)); #else[byte] return SCOPED_MEMORY_ACCESS.get$Type$Unaligned(bb.sessionImpl(), bb.unsafeGetBase(), - offsetPlain(bb, base), + offsetPlain(bb, base, offset), handle.be); #end[byte] #end[floatingPoint] } @ForceInline - static void set(VarHandle ob, Object obb, long base, $type$ value) { + static void set(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ value) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkReadOnly(obb, false); + AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); #if[floatingPoint] SCOPED_MEMORY_ACCESS.put$RawType$Unaligned(bb.sessionImpl(), bb.unsafeGetBase(), - offsetPlain(bb, base), + offsetPlain(bb, base, offset), $Type$.$type$ToRaw$RawType$Bits(value), handle.be); #else[floatingPoint] #if[byte] SCOPED_MEMORY_ACCESS.put$Type$(bb.sessionImpl(), bb.unsafeGetBase(), - offsetPlain(bb, base), + offsetPlain(bb, base, offset), value); #else[byte] SCOPED_MEMORY_ACCESS.put$Type$Unaligned(bb.sessionImpl(), bb.unsafeGetBase(), - offsetPlain(bb, base), + offsetPlain(bb, base, offset), value, handle.be); #end[byte] @@ -168,223 +175,223 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase { } @ForceInline - static $type$ getVolatile(VarHandle ob, Object obb, long base) { + static $type$ getVolatile(VarHandle ob, Object obb, Object encl, long base, long offset) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkReadOnly(obb, true); + AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, true); return convEndian(handle.be, SCOPED_MEMORY_ACCESS.get$RawType$Volatile(bb.sessionImpl(), bb.unsafeGetBase(), - offsetNonPlain(bb, base, handle.alignmentMask))); + offsetNonPlain(bb, base, offset, handle.alignmentMask))); } @ForceInline - static void setVolatile(VarHandle ob, Object obb, long base, $type$ value) { + static void setVolatile(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ value) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkReadOnly(obb, false); + AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); SCOPED_MEMORY_ACCESS.put$RawType$Volatile(bb.sessionImpl(), bb.unsafeGetBase(), - offsetNonPlain(bb, base, handle.alignmentMask), + offsetNonPlain(bb, base, offset, handle.alignmentMask), convEndian(handle.be, value)); } @ForceInline - static $type$ getAcquire(VarHandle ob, Object obb, long base) { + static $type$ getAcquire(VarHandle ob, Object obb, Object encl, long base, long offset) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkReadOnly(obb, true); + AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, true); return convEndian(handle.be, SCOPED_MEMORY_ACCESS.get$RawType$Acquire(bb.sessionImpl(), bb.unsafeGetBase(), - offsetNonPlain(bb, base, handle.alignmentMask))); + offsetNonPlain(bb, base, offset, handle.alignmentMask))); } @ForceInline - static void setRelease(VarHandle ob, Object obb, long base, $type$ value) { + static void setRelease(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ value) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkReadOnly(obb, false); + AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); SCOPED_MEMORY_ACCESS.put$RawType$Release(bb.sessionImpl(), bb.unsafeGetBase(), - offsetNonPlain(bb, base, handle.alignmentMask), + offsetNonPlain(bb, base, offset, handle.alignmentMask), convEndian(handle.be, value)); } @ForceInline - static $type$ getOpaque(VarHandle ob, Object obb, long base) { + static $type$ getOpaque(VarHandle ob, Object obb, Object encl, long base, long offset) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkReadOnly(obb, true); + AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, true); return convEndian(handle.be, SCOPED_MEMORY_ACCESS.get$RawType$Opaque(bb.sessionImpl(), bb.unsafeGetBase(), - offsetNonPlain(bb, base, handle.alignmentMask))); + offsetNonPlain(bb, base, offset, handle.alignmentMask))); } @ForceInline - static void setOpaque(VarHandle ob, Object obb, long base, $type$ value) { + static void setOpaque(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ value) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkReadOnly(obb, false); + AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); SCOPED_MEMORY_ACCESS.put$RawType$Opaque(bb.sessionImpl(), bb.unsafeGetBase(), - offsetNonPlain(bb, base, handle.alignmentMask), + offsetNonPlain(bb, base, offset, handle.alignmentMask), convEndian(handle.be, value)); } #if[CAS] @ForceInline - static boolean compareAndSet(VarHandle ob, Object obb, long base, $type$ expected, $type$ value) { + static boolean compareAndSet(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ expected, $type$ value) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkReadOnly(obb, false); + AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); return SCOPED_MEMORY_ACCESS.compareAndSet$RawType$(bb.sessionImpl(), bb.unsafeGetBase(), - offsetNonPlain(bb, base, handle.alignmentMask), + offsetNonPlain(bb, base, offset, handle.alignmentMask), convEndian(handle.be, expected), convEndian(handle.be, value)); } @ForceInline - static $type$ compareAndExchange(VarHandle ob, Object obb, long base, $type$ expected, $type$ value) { + static $type$ compareAndExchange(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ expected, $type$ value) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkReadOnly(obb, false); + AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); return convEndian(handle.be, SCOPED_MEMORY_ACCESS.compareAndExchange$RawType$(bb.sessionImpl(), bb.unsafeGetBase(), - offsetNonPlain(bb, base, handle.alignmentMask), + offsetNonPlain(bb, base, offset, handle.alignmentMask), convEndian(handle.be, expected), convEndian(handle.be, value))); } @ForceInline - static $type$ compareAndExchangeAcquire(VarHandle ob, Object obb, long base, $type$ expected, $type$ value) { + static $type$ compareAndExchangeAcquire(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ expected, $type$ value) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkReadOnly(obb, false); + AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); return convEndian(handle.be, SCOPED_MEMORY_ACCESS.compareAndExchange$RawType$Acquire(bb.sessionImpl(), bb.unsafeGetBase(), - offsetNonPlain(bb, base, handle.alignmentMask), + offsetNonPlain(bb, base, offset, handle.alignmentMask), convEndian(handle.be, expected), convEndian(handle.be, value))); } @ForceInline - static $type$ compareAndExchangeRelease(VarHandle ob, Object obb, long base, $type$ expected, $type$ value) { + static $type$ compareAndExchangeRelease(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ expected, $type$ value) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkReadOnly(obb, false); + AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); return convEndian(handle.be, SCOPED_MEMORY_ACCESS.compareAndExchange$RawType$Release(bb.sessionImpl(), bb.unsafeGetBase(), - offsetNonPlain(bb, base, handle.alignmentMask), + offsetNonPlain(bb, base, offset, handle.alignmentMask), convEndian(handle.be, expected), convEndian(handle.be, value))); } @ForceInline - static boolean weakCompareAndSetPlain(VarHandle ob, Object obb, long base, $type$ expected, $type$ value) { + static boolean weakCompareAndSetPlain(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ expected, $type$ value) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkReadOnly(obb, false); + AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); return SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$Plain(bb.sessionImpl(), bb.unsafeGetBase(), - offsetNonPlain(bb, base, handle.alignmentMask), + offsetNonPlain(bb, base, offset, handle.alignmentMask), convEndian(handle.be, expected), convEndian(handle.be, value)); } @ForceInline - static boolean weakCompareAndSet(VarHandle ob, Object obb, long base, $type$ expected, $type$ value) { + static boolean weakCompareAndSet(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ expected, $type$ value) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkReadOnly(obb, false); + AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); return SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$(bb.sessionImpl(), bb.unsafeGetBase(), - offsetNonPlain(bb, base, handle.alignmentMask), + offsetNonPlain(bb, base, offset, handle.alignmentMask), convEndian(handle.be, expected), convEndian(handle.be, value)); } @ForceInline - static boolean weakCompareAndSetAcquire(VarHandle ob, Object obb, long base, $type$ expected, $type$ value) { + static boolean weakCompareAndSetAcquire(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ expected, $type$ value) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkReadOnly(obb, false); + AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); return SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$Acquire(bb.sessionImpl(), bb.unsafeGetBase(), - offsetNonPlain(bb, base, handle.alignmentMask), + offsetNonPlain(bb, base, offset, handle.alignmentMask), convEndian(handle.be, expected), convEndian(handle.be, value)); } @ForceInline - static boolean weakCompareAndSetRelease(VarHandle ob, Object obb, long base, $type$ expected, $type$ value) { + static boolean weakCompareAndSetRelease(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ expected, $type$ value) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkReadOnly(obb, false); + AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); return SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$Release(bb.sessionImpl(), bb.unsafeGetBase(), - offsetNonPlain(bb, base, handle.alignmentMask), + offsetNonPlain(bb, base, offset, handle.alignmentMask), convEndian(handle.be, expected), convEndian(handle.be, value)); } @ForceInline - static $type$ getAndSet(VarHandle ob, Object obb, long base, $type$ value) { + static $type$ getAndSet(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ value) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkReadOnly(obb, false); + AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); return convEndian(handle.be, SCOPED_MEMORY_ACCESS.getAndSet$RawType$(bb.sessionImpl(), bb.unsafeGetBase(), - offsetNonPlain(bb, base, handle.alignmentMask), + offsetNonPlain(bb, base, offset, handle.alignmentMask), convEndian(handle.be, value))); } @ForceInline - static $type$ getAndSetAcquire(VarHandle ob, Object obb, long base, $type$ value) { + static $type$ getAndSetAcquire(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ value) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkReadOnly(obb, false); + AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); return convEndian(handle.be, SCOPED_MEMORY_ACCESS.getAndSet$RawType$Acquire(bb.sessionImpl(), bb.unsafeGetBase(), - offsetNonPlain(bb, base, handle.alignmentMask), + offsetNonPlain(bb, base, offset, handle.alignmentMask), convEndian(handle.be, value))); } @ForceInline - static $type$ getAndSetRelease(VarHandle ob, Object obb, long base, $type$ value) { + static $type$ getAndSetRelease(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ value) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkReadOnly(obb, false); + AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); return convEndian(handle.be, SCOPED_MEMORY_ACCESS.getAndSet$RawType$Release(bb.sessionImpl(), bb.unsafeGetBase(), - offsetNonPlain(bb, base, handle.alignmentMask), + offsetNonPlain(bb, base, offset, handle.alignmentMask), convEndian(handle.be, value))); } #end[CAS] #if[AtomicAdd] @ForceInline - static $type$ getAndAdd(VarHandle ob, Object obb, long base, $type$ delta) { + static $type$ getAndAdd(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ delta) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkReadOnly(obb, false); + AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); if (handle.be == BE) { return SCOPED_MEMORY_ACCESS.getAndAdd$RawType$(bb.sessionImpl(), bb.unsafeGetBase(), - offsetNonPlain(bb, base, handle.alignmentMask), + offsetNonPlain(bb, base, offset, handle.alignmentMask), delta); } else { - return getAndAddConvEndianWithCAS(bb, offsetNonPlain(bb, base, handle.alignmentMask), delta); + return getAndAddConvEndianWithCAS(bb, offsetNonPlain(bb, base, offset, handle.alignmentMask), delta); } } @ForceInline - static $type$ getAndAddAcquire(VarHandle ob, Object obb, long base, $type$ delta) { + static $type$ getAndAddAcquire(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ delta) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkReadOnly(obb, false); + AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); if (handle.be == BE) { return SCOPED_MEMORY_ACCESS.getAndAdd$RawType$Acquire(bb.sessionImpl(), bb.unsafeGetBase(), - offsetNonPlain(bb, base, handle.alignmentMask), + offsetNonPlain(bb, base, offset, handle.alignmentMask), delta); } else { - return getAndAddConvEndianWithCAS(bb, offsetNonPlain(bb, base, handle.alignmentMask), delta); + return getAndAddConvEndianWithCAS(bb, offsetNonPlain(bb, base, offset, handle.alignmentMask), delta); } } @ForceInline - static $type$ getAndAddRelease(VarHandle ob, Object obb, long base, $type$ delta) { + static $type$ getAndAddRelease(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ delta) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkReadOnly(obb, false); + AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); if (handle.be == BE) { return SCOPED_MEMORY_ACCESS.getAndAdd$RawType$Release(bb.sessionImpl(), bb.unsafeGetBase(), - offsetNonPlain(bb, base, handle.alignmentMask), + offsetNonPlain(bb, base, offset, handle.alignmentMask), delta); } else { - return getAndAddConvEndianWithCAS(bb, offsetNonPlain(bb, base, handle.alignmentMask), delta); + return getAndAddConvEndianWithCAS(bb, offsetNonPlain(bb, base, offset, handle.alignmentMask), delta); } } @@ -403,44 +410,44 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase { #if[Bitwise] @ForceInline - static $type$ getAndBitwiseOr(VarHandle ob, Object obb, long base, $type$ value) { + static $type$ getAndBitwiseOr(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ value) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkReadOnly(obb, false); + AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); if (handle.be == BE) { return SCOPED_MEMORY_ACCESS.getAndBitwiseOr$RawType$(bb.sessionImpl(), bb.unsafeGetBase(), - offsetNonPlain(bb, base, handle.alignmentMask), + offsetNonPlain(bb, base, offset, handle.alignmentMask), value); } else { - return getAndBitwiseOrConvEndianWithCAS(bb, offsetNonPlain(bb, base, handle.alignmentMask), value); + return getAndBitwiseOrConvEndianWithCAS(bb, offsetNonPlain(bb, base, offset, handle.alignmentMask), value); } } @ForceInline - static $type$ getAndBitwiseOrRelease(VarHandle ob, Object obb, long base, $type$ value) { + static $type$ getAndBitwiseOrRelease(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ value) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkReadOnly(obb, false); + AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); if (handle.be == BE) { return SCOPED_MEMORY_ACCESS.getAndBitwiseOr$RawType$Release(bb.sessionImpl(), bb.unsafeGetBase(), - offsetNonPlain(bb, base, handle.alignmentMask), + offsetNonPlain(bb, base, offset, handle.alignmentMask), value); } else { - return getAndBitwiseOrConvEndianWithCAS(bb, offsetNonPlain(bb, base, handle.alignmentMask), value); + return getAndBitwiseOrConvEndianWithCAS(bb, offsetNonPlain(bb, base, offset, handle.alignmentMask), value); } } @ForceInline - static $type$ getAndBitwiseOrAcquire(VarHandle ob, Object obb, long base, $type$ value) { + static $type$ getAndBitwiseOrAcquire(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ value) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkReadOnly(obb, false); + AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); if (handle.be == BE) { return SCOPED_MEMORY_ACCESS.getAndBitwiseOr$RawType$Acquire(bb.sessionImpl(), bb.unsafeGetBase(), - offsetNonPlain(bb, base, handle.alignmentMask), + offsetNonPlain(bb, base, offset, handle.alignmentMask), value); } else { - return getAndBitwiseOrConvEndianWithCAS(bb, offsetNonPlain(bb, base, handle.alignmentMask), value); + return getAndBitwiseOrConvEndianWithCAS(bb, offsetNonPlain(bb, base, offset, handle.alignmentMask), value); } } @@ -457,44 +464,44 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase { } @ForceInline - static $type$ getAndBitwiseAnd(VarHandle ob, Object obb, long base, $type$ value) { + static $type$ getAndBitwiseAnd(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ value) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkReadOnly(obb, false); + AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); if (handle.be == BE) { return SCOPED_MEMORY_ACCESS.getAndBitwiseAnd$RawType$(bb.sessionImpl(), bb.unsafeGetBase(), - offsetNonPlain(bb, base, handle.alignmentMask), + offsetNonPlain(bb, base, offset, handle.alignmentMask), value); } else { - return getAndBitwiseAndConvEndianWithCAS(bb, offsetNonPlain(bb, base, handle.alignmentMask), value); + return getAndBitwiseAndConvEndianWithCAS(bb, offsetNonPlain(bb, base, offset, handle.alignmentMask), value); } } @ForceInline - static $type$ getAndBitwiseAndRelease(VarHandle ob, Object obb, long base, $type$ value) { + static $type$ getAndBitwiseAndRelease(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ value) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkReadOnly(obb, false); + AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); if (handle.be == BE) { return SCOPED_MEMORY_ACCESS.getAndBitwiseAnd$RawType$Release(bb.sessionImpl(), bb.unsafeGetBase(), - offsetNonPlain(bb, base, handle.alignmentMask), + offsetNonPlain(bb, base, offset, handle.alignmentMask), value); } else { - return getAndBitwiseAndConvEndianWithCAS(bb, offsetNonPlain(bb, base, handle.alignmentMask), value); + return getAndBitwiseAndConvEndianWithCAS(bb, offsetNonPlain(bb, base, offset, handle.alignmentMask), value); } } @ForceInline - static $type$ getAndBitwiseAndAcquire(VarHandle ob, Object obb, long base, $type$ value) { + static $type$ getAndBitwiseAndAcquire(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ value) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkReadOnly(obb, false); + AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); if (handle.be == BE) { return SCOPED_MEMORY_ACCESS.getAndBitwiseAnd$RawType$Acquire(bb.sessionImpl(), bb.unsafeGetBase(), - offsetNonPlain(bb, base, handle.alignmentMask), + offsetNonPlain(bb, base, offset, handle.alignmentMask), value); } else { - return getAndBitwiseAndConvEndianWithCAS(bb, offsetNonPlain(bb, base, handle.alignmentMask), value); + return getAndBitwiseAndConvEndianWithCAS(bb, offsetNonPlain(bb, base, offset, handle.alignmentMask), value); } } @@ -512,44 +519,44 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase { @ForceInline - static $type$ getAndBitwiseXor(VarHandle ob, Object obb, long base, $type$ value) { + static $type$ getAndBitwiseXor(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ value) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkReadOnly(obb, false); + AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); if (handle.be == BE) { return SCOPED_MEMORY_ACCESS.getAndBitwiseXor$RawType$(bb.sessionImpl(), bb.unsafeGetBase(), - offsetNonPlain(bb, base, handle.alignmentMask), + offsetNonPlain(bb, base, offset, handle.alignmentMask), value); } else { - return getAndBitwiseXorConvEndianWithCAS(bb, offsetNonPlain(bb, base, handle.alignmentMask), value); + return getAndBitwiseXorConvEndianWithCAS(bb, offsetNonPlain(bb, base, offset, handle.alignmentMask), value); } } @ForceInline - static $type$ getAndBitwiseXorRelease(VarHandle ob, Object obb, long base, $type$ value) { + static $type$ getAndBitwiseXorRelease(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ value) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkReadOnly(obb, false); + AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); if (handle.be == BE) { return SCOPED_MEMORY_ACCESS.getAndBitwiseXor$RawType$Release(bb.sessionImpl(), bb.unsafeGetBase(), - offsetNonPlain(bb, base, handle.alignmentMask), + offsetNonPlain(bb, base, offset, handle.alignmentMask), value); } else { - return getAndBitwiseXorConvEndianWithCAS(bb, offsetNonPlain(bb, base, handle.alignmentMask), value); + return getAndBitwiseXorConvEndianWithCAS(bb, offsetNonPlain(bb, base, offset, handle.alignmentMask), value); } } @ForceInline - static $type$ getAndBitwiseXorAcquire(VarHandle ob, Object obb, long base, $type$ value) { + static $type$ getAndBitwiseXorAcquire(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ value) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkReadOnly(obb, false); + AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); if (handle.be == BE) { return SCOPED_MEMORY_ACCESS.getAndBitwiseXor$RawType$Acquire(bb.sessionImpl(), bb.unsafeGetBase(), - offsetNonPlain(bb, base, handle.alignmentMask), + offsetNonPlain(bb, base, offset, handle.alignmentMask), value); } else { - return getAndBitwiseXorConvEndianWithCAS(bb, offsetNonPlain(bb, base, handle.alignmentMask), value); + return getAndBitwiseXorConvEndianWithCAS(bb, offsetNonPlain(bb, base, offset, handle.alignmentMask), value); } } diff --git a/src/java.base/share/classes/jdk/internal/foreign/LayoutPath.java b/src/java.base/share/classes/jdk/internal/foreign/LayoutPath.java index ebd83d1c5da5f..8c1f97b168cd5 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/LayoutPath.java +++ b/src/java.base/share/classes/jdk/internal/foreign/LayoutPath.java @@ -205,19 +205,15 @@ public VarHandle dereferenceHandle(boolean adapt) { String.format("Path does not select a value layout: %s", breadcrumbs())); } - VarHandle handle = Utils.makeRawSegmentViewVarHandle(valueLayout); - handle = MethodHandles.collectCoordinates(handle, 1, offsetHandle()); - - // we only have to check the alignment of the root layout for the first dereference we do, - // as each dereference checks the alignment of the target address when constructing its segment - // (see Utils::longToAddress) - if (derefAdapters.length == 0) { - // insert align check for the root layout on the initial MS + offset - List> coordinateTypes = handle.coordinateTypes(); - MethodHandle alignCheck = MethodHandles.insertArguments(MH_CHECK_ENCL_LAYOUT, 2, rootLayout()); - handle = MethodHandles.collectCoordinates(handle, 0, alignCheck); - int[] reorder = IntStream.concat(IntStream.of(0, 1), IntStream.range(0, coordinateTypes.size())).toArray(); - handle = MethodHandles.permuteCoordinates(handle, coordinateTypes, reorder); + VarHandle handle = Utils.makeRawSegmentViewVarHandle(valueLayout); // (MS, ML, long, long) + handle = MethodHandles.insertCoordinates(handle, 1, rootLayout()); // (MS, long, long) + if (strides.length > 0) { + MethodHandle offsetAdapter = offsetHandle(); + offsetAdapter = MethodHandles.insertArguments(offsetAdapter, 0, 0L); + handle = MethodHandles.collectCoordinates(handle, 2, offsetAdapter); // (MS, long) + } else { + // simpler adaptation + handle = MethodHandles.insertCoordinates(handle, 2, offset); // (MS, long) } if (adapt) { @@ -241,6 +237,10 @@ public VarHandle dereferenceHandle(boolean adapt) { @ForceInline private static long addScaledOffset(long base, long index, long stride, long bound) { Objects.checkIndex(index, bound); + // note: the below can overflow, depending on 'base'. When constructing var handles + // through the layout API, this is never the case, as the segment offset is checked + // against the segment size. But when using 'byteOffsetHandle' this might return a + // negative value. Seems incompatible also with scale(), which use exact operations. return base + (stride * index); } From 532b84092b91f9650c823a4e79fe9bcd6c4c24ff Mon Sep 17 00:00:00 2001 From: Maurizio Cimadamore Date: Mon, 19 Aug 2024 14:32:06 +0100 Subject: [PATCH 2/6] Simplify address adaptation --- .../share/classes/jdk/internal/foreign/Utils.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/java.base/share/classes/jdk/internal/foreign/Utils.java b/src/java.base/share/classes/jdk/internal/foreign/Utils.java index 2ed65e3dd0428..e634719e8a9d3 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/Utils.java +++ b/src/java.base/share/classes/jdk/internal/foreign/Utils.java @@ -75,7 +75,7 @@ private Utils() {} ADDRESS_TO_LONG = lookup.findStatic(SharedUtils.class, "unboxSegment", MethodType.methodType(long.class, MemorySegment.class)); LONG_TO_ADDRESS = lookup.findStatic(Utils.class, "longToAddress", - MethodType.methodType(MemorySegment.class, long.class, long.class, long.class)); + MethodType.methodType(MemorySegment.class, long.class, AddressLayout.class)); } catch (Throwable ex) { throw new ExceptionInInitializerError(ex); } @@ -130,10 +130,7 @@ private static VarHandle makeRawSegmentViewVarHandleInternal(ValueLayout layout) handle = MethodHandles.filterValue(handle, BOOL_TO_BYTE, BYTE_TO_BOOL); } else if (layout instanceof AddressLayout addressLayout) { handle = MethodHandles.filterValue(handle, - MethodHandles.explicitCastArguments(ADDRESS_TO_LONG, MethodType.methodType(baseCarrier, MemorySegment.class)), - MethodHandles.explicitCastArguments(MethodHandles.insertArguments(LONG_TO_ADDRESS, 1, - pointeeByteSize(addressLayout), pointeeByteAlign(addressLayout)), - MethodType.methodType(MemorySegment.class, baseCarrier))); + ADDRESS_TO_LONG, MethodHandles.insertArguments(LONG_TO_ADDRESS, 1, addressLayout)); } return handle; } @@ -146,6 +143,11 @@ private static byte booleanToByte(boolean b) { return b ? (byte)1 : (byte)0; } + @ForceInline + public static MemorySegment longToAddress(long addr, AddressLayout layout) { + return longToAddress(addr, pointeeByteSize(layout), pointeeByteAlign(layout)); + } + @ForceInline public static MemorySegment longToAddress(long addr, long size, long align) { if (!isAligned(addr, align)) { From 67362ff7c6a4d79b51d4dc4e36972da2a4333d65 Mon Sep 17 00:00:00 2001 From: Maurizio Cimadamore Date: Tue, 20 Aug 2024 12:36:46 +0100 Subject: [PATCH 3/6] Improve adaptation of address handles --- .../jdk/internal/foreign/LayoutPath.java | 11 ++++++----- .../classes/jdk/internal/foreign/Utils.java | 18 ++++++++++++++---- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/java.base/share/classes/jdk/internal/foreign/LayoutPath.java b/src/java.base/share/classes/jdk/internal/foreign/LayoutPath.java index 8c1f97b168cd5..299cedf299000 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/LayoutPath.java +++ b/src/java.base/share/classes/jdk/internal/foreign/LayoutPath.java @@ -80,7 +80,7 @@ public class LayoutPath { MH_CHECK_ENCL_LAYOUT = lookup.findStatic(LayoutPath.class, "checkEnclosingLayout", MethodType.methodType(void.class, MemorySegment.class, long.class, MemoryLayout.class)); MH_SEGMENT_RESIZE = lookup.findStatic(LayoutPath.class, "resizeSegment", - MethodType.methodType(MemorySegment.class, MemorySegment.class, MemoryLayout.class)); + MethodType.methodType(MemorySegment.class, MemorySegment.class)); MH_ADD = lookup.findStatic(Long.class, "sum", MethodType.methodType(long.class, long.class, long.class)); } catch (Throwable ex) { @@ -180,13 +180,14 @@ public LayoutPath derefElement() { } MemoryLayout derefLayout = addressLayout.targetLayout().get(); MethodHandle handle = dereferenceHandle(false).toMethodHandle(VarHandle.AccessMode.GET); - handle = MethodHandles.filterReturnValue(handle, - MethodHandles.insertArguments(MH_SEGMENT_RESIZE, 1, derefLayout)); + handle = MethodHandles.filterReturnValue(handle, MH_SEGMENT_RESIZE); return derefPath(derefLayout, handle, this); } - private static MemorySegment resizeSegment(MemorySegment segment, MemoryLayout layout) { - return Utils.longToAddress(segment.address(), layout.byteSize(), layout.byteAlignment()); + private static MemorySegment resizeSegment(MemorySegment segment) { + // Avoid adapting for specific target layout. The check for the root layout + // size and alignment will be inserted by LayoutPath::dereferenceHandle anyway. + return Utils.longToAddress(segment.address(), Long.MAX_VALUE, 1); } // Layout path projections diff --git a/src/java.base/share/classes/jdk/internal/foreign/Utils.java b/src/java.base/share/classes/jdk/internal/foreign/Utils.java index e634719e8a9d3..f214d3fb8066f 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/Utils.java +++ b/src/java.base/share/classes/jdk/internal/foreign/Utils.java @@ -63,7 +63,8 @@ private Utils() {} private static final MethodHandle BYTE_TO_BOOL; private static final MethodHandle BOOL_TO_BYTE; private static final MethodHandle ADDRESS_TO_LONG; - private static final MethodHandle LONG_TO_ADDRESS; + private static final MethodHandle LONG_TO_ADDRESS_TARGET; + private static final MethodHandle LONG_TO_ADDRESS_NO_TARGET; static { try { @@ -74,8 +75,10 @@ private Utils() {} MethodType.methodType(byte.class, boolean.class)); ADDRESS_TO_LONG = lookup.findStatic(SharedUtils.class, "unboxSegment", MethodType.methodType(long.class, MemorySegment.class)); - LONG_TO_ADDRESS = lookup.findStatic(Utils.class, "longToAddress", + LONG_TO_ADDRESS_TARGET = lookup.findStatic(Utils.class, "longToAddress", MethodType.methodType(MemorySegment.class, long.class, AddressLayout.class)); + LONG_TO_ADDRESS_NO_TARGET = lookup.findStatic(Utils.class, "longToAddress", + MethodType.methodType(MemorySegment.class, long.class)); } catch (Throwable ex) { throw new ExceptionInInitializerError(ex); } @@ -129,8 +132,10 @@ private static VarHandle makeRawSegmentViewVarHandleInternal(ValueLayout layout) if (layout.carrier() == boolean.class) { handle = MethodHandles.filterValue(handle, BOOL_TO_BYTE, BYTE_TO_BOOL); } else if (layout instanceof AddressLayout addressLayout) { - handle = MethodHandles.filterValue(handle, - ADDRESS_TO_LONG, MethodHandles.insertArguments(LONG_TO_ADDRESS, 1, addressLayout)); + MethodHandle longToAddressAdapter = addressLayout.targetLayout().isPresent() ? + MethodHandles.insertArguments(LONG_TO_ADDRESS_TARGET, 1, addressLayout) : + LONG_TO_ADDRESS_NO_TARGET; + handle = MethodHandles.filterValue(handle, ADDRESS_TO_LONG, longToAddressAdapter); } return handle; } @@ -143,6 +148,11 @@ private static byte booleanToByte(boolean b) { return b ? (byte)1 : (byte)0; } + @ForceInline + public static MemorySegment longToAddress(long addr) { + return longToAddress(addr, 0, 1); + } + @ForceInline public static MemorySegment longToAddress(long addr, AddressLayout layout) { return longToAddress(addr, pointeeByteSize(layout), pointeeByteAlign(layout)); From ecd2d9bcdfd302be03bb4ee870aa429aff1632b9 Mon Sep 17 00:00:00 2001 From: Maurizio Cimadamore Date: Tue, 20 Aug 2024 16:03:59 +0100 Subject: [PATCH 4/6] Consoldiate and share code --- .../lang/invoke/X-VarHandleSegmentView.java.template | 9 ++------- .../classes/jdk/internal/foreign/LayoutPath.java | 11 +---------- .../share/classes/jdk/internal/foreign/Utils.java | 10 ++++++++++ 3 files changed, 13 insertions(+), 17 deletions(-) diff --git a/src/java.base/share/classes/java/lang/invoke/X-VarHandleSegmentView.java.template b/src/java.base/share/classes/java/lang/invoke/X-VarHandleSegmentView.java.template index d490e581a6330..343f1c2867865 100644 --- a/src/java.base/share/classes/java/lang/invoke/X-VarHandleSegmentView.java.template +++ b/src/java.base/share/classes/java/lang/invoke/X-VarHandleSegmentView.java.template @@ -25,6 +25,7 @@ package java.lang.invoke; import jdk.internal.foreign.AbstractMemorySegmentImpl; +import jdk.internal.foreign.Utils; import jdk.internal.misc.ScopedMemoryAccess; import jdk.internal.vm.annotation.ForceInline; @@ -100,13 +101,7 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase { @ForceInline static AbstractMemorySegmentImpl checkSegment(Object obb, Object encl, long base, boolean ro) { AbstractMemorySegmentImpl oo = (AbstractMemorySegmentImpl)Objects.requireNonNull(obb); - MemoryLayout layout = (MemoryLayout)encl; - oo.checkAccess(base, layout.byteSize(), ro); - if (!oo.isAlignedForElement(base, layout)) { - throw new IllegalArgumentException(String.format( - "Target offset %d is incompatible with alignment constraint %d (of %s) for segment %s" - , base, layout.byteAlignment(), layout, oo)); - } + Utils.checkEnclosingLayout(oo, base, (MemoryLayout)encl); return oo; } diff --git a/src/java.base/share/classes/jdk/internal/foreign/LayoutPath.java b/src/java.base/share/classes/jdk/internal/foreign/LayoutPath.java index 299cedf299000..019a33023f9d8 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/LayoutPath.java +++ b/src/java.base/share/classes/jdk/internal/foreign/LayoutPath.java @@ -77,7 +77,7 @@ public class LayoutPath { MethodType.methodType(MemorySegment.class, long.class, long.class)); MH_SLICE_LAYOUT = lookup.findVirtual(MemorySegment.class, "asSlice", MethodType.methodType(MemorySegment.class, long.class, MemoryLayout.class)); - MH_CHECK_ENCL_LAYOUT = lookup.findStatic(LayoutPath.class, "checkEnclosingLayout", + MH_CHECK_ENCL_LAYOUT = lookup.findStatic(Utils.class, "checkEnclosingLayout", MethodType.methodType(void.class, MemorySegment.class, long.class, MemoryLayout.class)); MH_SEGMENT_RESIZE = lookup.findStatic(LayoutPath.class, "resizeSegment", MethodType.methodType(MemorySegment.class, MemorySegment.class)); @@ -285,15 +285,6 @@ public MethodHandle sliceHandle() { return sliceHandle; } - private static void checkEnclosingLayout(MemorySegment segment, long offset, MemoryLayout enclosing) { - ((AbstractMemorySegmentImpl)segment).checkAccess(offset, enclosing.byteSize(), true); - if (!((AbstractMemorySegmentImpl) segment).isAlignedForElement(offset, enclosing)) { - throw new IllegalArgumentException(String.format( - "Target offset %d is incompatible with alignment constraint %d (of %s) for segment %s" - , offset, enclosing.byteAlignment(), enclosing, segment)); - } - } - public MemoryLayout layout() { return layout; } diff --git a/src/java.base/share/classes/jdk/internal/foreign/Utils.java b/src/java.base/share/classes/jdk/internal/foreign/Utils.java index f214d3fb8066f..58b5cb63657cb 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/Utils.java +++ b/src/java.base/share/classes/jdk/internal/foreign/Utils.java @@ -241,6 +241,16 @@ public static void checkNonNegativeIndex(long value, String name) { } } + @ForceInline + public static void checkEnclosingLayout(MemorySegment segment, long offset, MemoryLayout enclosing) { + ((AbstractMemorySegmentImpl)segment).checkAccess(offset, enclosing.byteSize(), true); + if (!((AbstractMemorySegmentImpl) segment).isAlignedForElement(offset, enclosing)) { + throw new IllegalArgumentException(String.format( + "Target offset %d is incompatible with alignment constraint %d (of %s) for segment %s" + , offset, enclosing.byteAlignment(), enclosing, segment)); + } + } + private static long computePadding(long offset, long align) { boolean isAligned = offset == 0 || offset % align == 0; if (isAligned) { From a3018b2668b829b6cd6107ed595dd36ac87151e6 Mon Sep 17 00:00:00 2001 From: Maurizio Cimadamore Date: Tue, 20 Aug 2024 19:11:50 +0100 Subject: [PATCH 5/6] Fix code breakage after refatcor --- .../java/lang/invoke/X-VarHandleSegmentView.java.template | 2 +- .../share/classes/jdk/internal/foreign/LayoutPath.java | 6 +++++- src/java.base/share/classes/jdk/internal/foreign/Utils.java | 4 ++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/java.base/share/classes/java/lang/invoke/X-VarHandleSegmentView.java.template b/src/java.base/share/classes/java/lang/invoke/X-VarHandleSegmentView.java.template index 343f1c2867865..ffe7b3095ed3d 100644 --- a/src/java.base/share/classes/java/lang/invoke/X-VarHandleSegmentView.java.template +++ b/src/java.base/share/classes/java/lang/invoke/X-VarHandleSegmentView.java.template @@ -101,7 +101,7 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase { @ForceInline static AbstractMemorySegmentImpl checkSegment(Object obb, Object encl, long base, boolean ro) { AbstractMemorySegmentImpl oo = (AbstractMemorySegmentImpl)Objects.requireNonNull(obb); - Utils.checkEnclosingLayout(oo, base, (MemoryLayout)encl); + Utils.checkEnclosingLayout(oo, base, (MemoryLayout)encl, ro); return oo; } diff --git a/src/java.base/share/classes/jdk/internal/foreign/LayoutPath.java b/src/java.base/share/classes/jdk/internal/foreign/LayoutPath.java index 019a33023f9d8..2f1a0aa38ffbf 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/LayoutPath.java +++ b/src/java.base/share/classes/jdk/internal/foreign/LayoutPath.java @@ -77,7 +77,7 @@ public class LayoutPath { MethodType.methodType(MemorySegment.class, long.class, long.class)); MH_SLICE_LAYOUT = lookup.findVirtual(MemorySegment.class, "asSlice", MethodType.methodType(MemorySegment.class, long.class, MemoryLayout.class)); - MH_CHECK_ENCL_LAYOUT = lookup.findStatic(Utils.class, "checkEnclosingLayout", + MH_CHECK_ENCL_LAYOUT = lookup.findStatic(LayoutPath.class, "checkEnclosingLayout", MethodType.methodType(void.class, MemorySegment.class, long.class, MemoryLayout.class)); MH_SEGMENT_RESIZE = lookup.findStatic(LayoutPath.class, "resizeSegment", MethodType.methodType(MemorySegment.class, MemorySegment.class)); @@ -285,6 +285,10 @@ public MethodHandle sliceHandle() { return sliceHandle; } + private static void checkEnclosingLayout(MemorySegment segment, long offset, MemoryLayout enclosing) { + Utils.checkEnclosingLayout(segment, offset, enclosing, true); + } + public MemoryLayout layout() { return layout; } diff --git a/src/java.base/share/classes/jdk/internal/foreign/Utils.java b/src/java.base/share/classes/jdk/internal/foreign/Utils.java index 58b5cb63657cb..d66b2fa86fd01 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/Utils.java +++ b/src/java.base/share/classes/jdk/internal/foreign/Utils.java @@ -242,8 +242,8 @@ public static void checkNonNegativeIndex(long value, String name) { } @ForceInline - public static void checkEnclosingLayout(MemorySegment segment, long offset, MemoryLayout enclosing) { - ((AbstractMemorySegmentImpl)segment).checkAccess(offset, enclosing.byteSize(), true); + public static void checkEnclosingLayout(MemorySegment segment, long offset, MemoryLayout enclosing, boolean readOnly) { + ((AbstractMemorySegmentImpl)segment).checkAccess(offset, enclosing.byteSize(), readOnly); if (!((AbstractMemorySegmentImpl) segment).isAlignedForElement(offset, enclosing)) { throw new IllegalArgumentException(String.format( "Target offset %d is incompatible with alignment constraint %d (of %s) for segment %s" From b6c7cf1d77a5262453801403a6907308e319f064 Mon Sep 17 00:00:00 2001 From: Maurizio Cimadamore Date: Wed, 21 Aug 2024 10:34:41 +0100 Subject: [PATCH 6/6] Address review comment Clarify code comment --- .../lang/invoke/X-VarHandleSegmentView.java.template | 2 +- .../internal/foreign/AbstractMemorySegmentImpl.java | 10 ++++++++++ .../share/classes/jdk/internal/foreign/LayoutPath.java | 6 ++---- .../share/classes/jdk/internal/foreign/Utils.java | 10 ---------- 4 files changed, 13 insertions(+), 15 deletions(-) diff --git a/src/java.base/share/classes/java/lang/invoke/X-VarHandleSegmentView.java.template b/src/java.base/share/classes/java/lang/invoke/X-VarHandleSegmentView.java.template index ffe7b3095ed3d..c5942e93c46c3 100644 --- a/src/java.base/share/classes/java/lang/invoke/X-VarHandleSegmentView.java.template +++ b/src/java.base/share/classes/java/lang/invoke/X-VarHandleSegmentView.java.template @@ -101,7 +101,7 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase { @ForceInline static AbstractMemorySegmentImpl checkSegment(Object obb, Object encl, long base, boolean ro) { AbstractMemorySegmentImpl oo = (AbstractMemorySegmentImpl)Objects.requireNonNull(obb); - Utils.checkEnclosingLayout(oo, base, (MemoryLayout)encl, ro); + oo.checkEnclosingLayout(base, (MemoryLayout)encl, ro); return oo; } diff --git a/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java b/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java index 325dbe1093f25..42857decf63b1 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java +++ b/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java @@ -373,6 +373,16 @@ public void checkValidState() { sessionImpl().checkValidState(); } + @ForceInline + public final void checkEnclosingLayout(long offset, MemoryLayout enclosing, boolean readOnly) { + checkAccess(offset, enclosing.byteSize(), readOnly); + if (!isAlignedForElement(offset, enclosing)) { + throw new IllegalArgumentException(String.format( + "Target offset %d is incompatible with alignment constraint %d (of %s) for segment %s" + , offset, enclosing.byteAlignment(), enclosing, this)); + } + } + public abstract long unsafeGetOffset(); public abstract Object unsafeGetBase(); diff --git a/src/java.base/share/classes/jdk/internal/foreign/LayoutPath.java b/src/java.base/share/classes/jdk/internal/foreign/LayoutPath.java index 2f1a0aa38ffbf..956a5c75875ab 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/LayoutPath.java +++ b/src/java.base/share/classes/jdk/internal/foreign/LayoutPath.java @@ -239,9 +239,7 @@ public VarHandle dereferenceHandle(boolean adapt) { private static long addScaledOffset(long base, long index, long stride, long bound) { Objects.checkIndex(index, bound); // note: the below can overflow, depending on 'base'. When constructing var handles - // through the layout API, this is never the case, as the segment offset is checked - // against the segment size. But when using 'byteOffsetHandle' this might return a - // negative value. Seems incompatible also with scale(), which use exact operations. + // through the layout API, this is never the case, as the injected 'base' is always 0. return base + (stride * index); } @@ -286,7 +284,7 @@ public MethodHandle sliceHandle() { } private static void checkEnclosingLayout(MemorySegment segment, long offset, MemoryLayout enclosing) { - Utils.checkEnclosingLayout(segment, offset, enclosing, true); + ((AbstractMemorySegmentImpl)segment).checkEnclosingLayout(offset, enclosing, true); } public MemoryLayout layout() { diff --git a/src/java.base/share/classes/jdk/internal/foreign/Utils.java b/src/java.base/share/classes/jdk/internal/foreign/Utils.java index d66b2fa86fd01..f214d3fb8066f 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/Utils.java +++ b/src/java.base/share/classes/jdk/internal/foreign/Utils.java @@ -241,16 +241,6 @@ public static void checkNonNegativeIndex(long value, String name) { } } - @ForceInline - public static void checkEnclosingLayout(MemorySegment segment, long offset, MemoryLayout enclosing, boolean readOnly) { - ((AbstractMemorySegmentImpl)segment).checkAccess(offset, enclosing.byteSize(), readOnly); - if (!((AbstractMemorySegmentImpl) segment).isAlignedForElement(offset, enclosing)) { - throw new IllegalArgumentException(String.format( - "Target offset %d is incompatible with alignment constraint %d (of %s) for segment %s" - , offset, enclosing.byteAlignment(), enclosing, segment)); - } - } - private static long computePadding(long offset, long align) { boolean isAligned = offset == 0 || offset % align == 0; if (isAligned) {