31 import java.nio.ByteBuffer;
32 import java.nio.ByteOrder;
33 import java.nio.CharBuffer;
34 import java.nio.DoubleBuffer;
35 import java.nio.FloatBuffer;
36 import java.nio.IntBuffer;
37 import java.nio.LongBuffer;
38 import java.nio.ShortBuffer;
39 import java.util.*;
40 import java.util.function.BiFunction;
41 import java.util.function.Consumer;
42 import java.util.function.Function;
43 import java.util.function.IntFunction;
44 import java.util.stream.Stream;
45 import java.util.stream.StreamSupport;
46
47 import jdk.internal.access.JavaNioAccess;
48 import jdk.internal.access.SharedSecrets;
49 import jdk.internal.access.foreign.UnmapperProxy;
50 import jdk.internal.misc.ScopedMemoryAccess;
51 import jdk.internal.misc.Unsafe;
52 import jdk.internal.reflect.CallerSensitive;
53 import jdk.internal.reflect.Reflection;
54 import jdk.internal.util.ArraysSupport;
55 import jdk.internal.util.Preconditions;
56 import jdk.internal.vm.annotation.ForceInline;
57
58 import static java.lang.foreign.ValueLayout.JAVA_BYTE;
59
60 /**
61 * This abstract class provides an immutable implementation for the {@code MemorySegment} interface. This class contains information
62 * about the segment's spatial and temporal bounds; each memory segment implementation is associated with an owner thread which is set at creation time.
63 * Access to certain sensitive operations on the memory segment will fail with {@code IllegalStateException} if the
64 * segment is either in an invalid state (e.g. it has already been closed) or if access occurs from a thread other
65 * than the owner thread. See {@link MemorySessionImpl} for more details on management of temporal bounds. Subclasses
66 * are defined for each memory segment kind, see {@link NativeMemorySegmentImpl}, {@link HeapMemorySegmentImpl} and
67 * {@link MappedMemorySegmentImpl}.
68 */
69 public abstract sealed class AbstractMemorySegmentImpl
70 implements MemorySegment, SegmentAllocator, BiFunction<String, List<Number>, RuntimeException>
71 permits HeapMemorySegmentImpl, NativeMemorySegmentImpl {
72
73 private static final ScopedMemoryAccess SCOPED_MEMORY_ACCESS = ScopedMemoryAccess.getScopedMemoryAccess();
74
75 static final JavaNioAccess NIO_ACCESS = SharedSecrets.getJavaNioAccess();
76
247 @Override
248 public boolean isMapped() {
249 return false;
250 }
251
252 @Override
253 public boolean isNative() {
254 return false;
255 }
256
257 @Override
258 public final Optional<MemorySegment> asOverlappingSlice(MemorySegment other) {
259 AbstractMemorySegmentImpl that = (AbstractMemorySegmentImpl)Objects.requireNonNull(other);
260 if (unsafeGetBase() == that.unsafeGetBase()) { // both either native or heap
261 final long thisStart = this.unsafeGetOffset();
262 final long thatStart = that.unsafeGetOffset();
263 final long thisEnd = thisStart + this.byteSize();
264 final long thatEnd = thatStart + that.byteSize();
265
266 if (thisStart < thatEnd && thisEnd > thatStart) { //overlap occurs
267 long offsetToThat = this.segmentOffset(that);
268 long newOffset = offsetToThat >= 0 ? offsetToThat : 0;
269 return Optional.of(asSlice(newOffset, Math.min(this.byteSize() - newOffset, that.byteSize() + offsetToThat)));
270 }
271 }
272 return Optional.empty();
273 }
274
275 @Override
276 public final long segmentOffset(MemorySegment other) {
277 AbstractMemorySegmentImpl that = (AbstractMemorySegmentImpl) Objects.requireNonNull(other);
278 if (unsafeGetBase() == that.unsafeGetBase()) {
279 return that.unsafeGetOffset() - this.unsafeGetOffset();
280 }
281 throw new UnsupportedOperationException("Cannot compute offset from native to heap (or vice versa).");
282 }
283
284 @Override
285 public void load() {
286 throw notAMappedSegment();
287 }
288
289 @Override
290 public void unload() {
291 throw notAMappedSegment();
292 }
293
294 @Override
295 public boolean isLoaded() {
296 throw notAMappedSegment();
297 }
298
299 @Override
300 public void force() {
301 throw notAMappedSegment();
302 }
303
529 public static AbstractMemorySegmentImpl ofBuffer(Buffer bb) {
530 Objects.requireNonNull(bb);
531 Object base = NIO_ACCESS.getBufferBase(bb);
532 if (!bb.isDirect() && base == null) {
533 throw new IllegalArgumentException("The provided heap buffer is not backed by an array.");
534 }
535 long bbAddress = NIO_ACCESS.getBufferAddress(bb);
536 UnmapperProxy unmapper = NIO_ACCESS.unmapper(bb);
537
538 int pos = bb.position();
539 int limit = bb.limit();
540 int size = limit - pos;
541
542 AbstractMemorySegmentImpl bufferSegment = (AbstractMemorySegmentImpl) NIO_ACCESS.bufferSegment(bb);
543 boolean readOnly = bb.isReadOnly();
544 int scaleFactor = getScaleFactor(bb);
545 final MemorySessionImpl bufferScope;
546 if (bufferSegment != null) {
547 bufferScope = bufferSegment.scope;
548 } else {
549 bufferScope = MemorySessionImpl.heapSession(bb);
550 }
551 if (base != null) {
552 if (base instanceof byte[]) {
553 return new HeapMemorySegmentImpl.OfByte(bbAddress + (pos << scaleFactor), base, size << scaleFactor, readOnly, bufferScope);
554 } else if (base instanceof short[]) {
555 return new HeapMemorySegmentImpl.OfShort(bbAddress + (pos << scaleFactor), base, size << scaleFactor, readOnly, bufferScope);
556 } else if (base instanceof char[]) {
557 return new HeapMemorySegmentImpl.OfChar(bbAddress + (pos << scaleFactor), base, size << scaleFactor, readOnly, bufferScope);
558 } else if (base instanceof int[]) {
559 return new HeapMemorySegmentImpl.OfInt(bbAddress + (pos << scaleFactor), base, size << scaleFactor, readOnly, bufferScope);
560 } else if (base instanceof float[]) {
561 return new HeapMemorySegmentImpl.OfFloat(bbAddress + (pos << scaleFactor), base, size << scaleFactor, readOnly, bufferScope);
562 } else if (base instanceof long[]) {
563 return new HeapMemorySegmentImpl.OfLong(bbAddress + (pos << scaleFactor), base, size << scaleFactor, readOnly, bufferScope);
564 } else if (base instanceof double[]) {
565 return new HeapMemorySegmentImpl.OfDouble(bbAddress + (pos << scaleFactor), base, size << scaleFactor, readOnly, bufferScope);
566 } else {
567 throw new AssertionError("Cannot get here");
568 }
569 } else if (unmapper == null) {
570 return new NativeMemorySegmentImpl(bbAddress + (pos << scaleFactor), size << scaleFactor, readOnly, bufferScope);
571 } else {
572 // we can ignore scale factor here, a mapped buffer is always a byte buffer, so scaleFactor == 0.
573 return new MappedMemorySegmentImpl(bbAddress + pos, unmapper, size, readOnly, bufferScope);
574 }
575 }
576
577 private static int getScaleFactor(Buffer buffer) {
578 if (buffer instanceof ByteBuffer) {
579 return 0;
580 } else if (buffer instanceof CharBuffer) {
581 return 1;
582 } else if (buffer instanceof ShortBuffer) {
583 return 1;
584 } else if (buffer instanceof IntBuffer) {
585 return 2;
586 } else if (buffer instanceof FloatBuffer) {
587 return 2;
588 } else if (buffer instanceof LongBuffer) {
589 return 3;
590 } else if (buffer instanceof DoubleBuffer) {
591 return 3;
592 } else {
593 throw new AssertionError("Cannot get here");
594 }
595 }
596
597 @ForceInline
598 public static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long srcOffset,
599 MemorySegment dstSegment, ValueLayout dstElementLayout, long dstOffset,
600 long elementCount) {
601
602 AbstractMemorySegmentImpl srcImpl = (AbstractMemorySegmentImpl)srcSegment;
603 AbstractMemorySegmentImpl dstImpl = (AbstractMemorySegmentImpl)dstSegment;
604 if (srcElementLayout.byteSize() != dstElementLayout.byteSize()) {
605 throw new IllegalArgumentException("Source and destination layouts must have same size");
606 }
607 Utils.checkElementAlignment(srcElementLayout, "Source layout alignment greater than its size");
608 Utils.checkElementAlignment(dstElementLayout, "Destination layout alignment greater than its size");
609 if (!srcImpl.isAlignedForElement(srcOffset, srcElementLayout)) {
610 throw new IllegalArgumentException("Source segment incompatible with alignment constraints");
611 }
612 if (!dstImpl.isAlignedForElement(dstOffset, dstElementLayout)) {
613 throw new IllegalArgumentException("Destination segment incompatible with alignment constraints");
614 }
615 long size = elementCount * srcElementLayout.byteSize();
616 srcImpl.checkAccess(srcOffset, size, true);
617 dstImpl.checkAccess(dstOffset, size, false);
618 if (srcElementLayout.byteSize() == 1 || srcElementLayout.order() == dstElementLayout.order()) {
619 ScopedMemoryAccess.getScopedMemoryAccess().copyMemory(srcImpl.sessionImpl(), dstImpl.sessionImpl(),
620 srcImpl.unsafeGetBase(), srcImpl.unsafeGetOffset() + srcOffset,
621 dstImpl.unsafeGetBase(), dstImpl.unsafeGetOffset() + dstOffset, size);
622 } else {
623 ScopedMemoryAccess.getScopedMemoryAccess().copySwapMemory(srcImpl.sessionImpl(), dstImpl.sessionImpl(),
624 srcImpl.unsafeGetBase(), srcImpl.unsafeGetOffset() + srcOffset,
625 dstImpl.unsafeGetBase(), dstImpl.unsafeGetOffset() + dstOffset, size, srcElementLayout.byteSize());
626 }
627 }
628
629 @ForceInline
630 public static void copy(MemorySegment srcSegment, ValueLayout srcLayout, long srcOffset,
631 Object dstArray, int dstIndex,
632 int elementCount) {
633
634 long baseAndScale = getBaseAndScale(dstArray.getClass());
635 if (dstArray.getClass().componentType() != srcLayout.carrier()) {
636 throw new IllegalArgumentException("Incompatible value layout: " + srcLayout);
637 }
638 int dstBase = (int)baseAndScale;
639 long dstWidth = (int)(baseAndScale >> 32); // Use long arithmetics below
640 AbstractMemorySegmentImpl srcImpl = (AbstractMemorySegmentImpl)srcSegment;
641 Utils.checkElementAlignment(srcLayout, "Source layout alignment greater than its size");
642 if (!srcImpl.isAlignedForElement(srcOffset, srcLayout)) {
643 throw new IllegalArgumentException("Source segment incompatible with alignment constraints");
644 }
645 srcImpl.checkAccess(srcOffset, elementCount * dstWidth, true);
646 Objects.checkFromIndexSize(dstIndex, elementCount, Array.getLength(dstArray));
647 if (dstWidth == 1 || srcLayout.order() == ByteOrder.nativeOrder()) {
648 ScopedMemoryAccess.getScopedMemoryAccess().copyMemory(srcImpl.sessionImpl(), null,
649 srcImpl.unsafeGetBase(), srcImpl.unsafeGetOffset() + srcOffset,
650 dstArray, dstBase + (dstIndex * dstWidth), elementCount * dstWidth);
651 } else {
652 ScopedMemoryAccess.getScopedMemoryAccess().copySwapMemory(srcImpl.sessionImpl(), null,
653 srcImpl.unsafeGetBase(), srcImpl.unsafeGetOffset() + srcOffset,
654 dstArray, dstBase + (dstIndex * dstWidth), elementCount * dstWidth, dstWidth);
655 }
656 }
657
658 @ForceInline
659 public static void copy(Object srcArray, int srcIndex,
660 MemorySegment dstSegment, ValueLayout dstLayout, long dstOffset,
661 int elementCount) {
662
663 long baseAndScale = getBaseAndScale(srcArray.getClass());
664 if (srcArray.getClass().componentType() != dstLayout.carrier()) {
665 throw new IllegalArgumentException("Incompatible value layout: " + dstLayout);
666 }
667 int srcBase = (int)baseAndScale;
668 long srcWidth = (int)(baseAndScale >> 32); // Use long arithmetics below
669 Objects.checkFromIndexSize(srcIndex, elementCount, Array.getLength(srcArray));
670 AbstractMemorySegmentImpl destImpl = (AbstractMemorySegmentImpl)dstSegment;
671 Utils.checkElementAlignment(dstLayout, "Destination layout alignment greater than its size");
672 if (!destImpl.isAlignedForElement(dstOffset, dstLayout)) {
673 throw new IllegalArgumentException("Destination segment incompatible with alignment constraints");
674 }
675 destImpl.checkAccess(dstOffset, elementCount * srcWidth, false);
676 if (srcWidth == 1 || dstLayout.order() == ByteOrder.nativeOrder()) {
677 ScopedMemoryAccess.getScopedMemoryAccess().copyMemory(null, destImpl.sessionImpl(),
678 srcArray, srcBase + (srcIndex * srcWidth),
679 destImpl.unsafeGetBase(), destImpl.unsafeGetOffset() + dstOffset, elementCount * srcWidth);
680 } else {
681 ScopedMemoryAccess.getScopedMemoryAccess().copySwapMemory(null, destImpl.sessionImpl(),
682 srcArray, srcBase + (srcIndex * srcWidth),
683 destImpl.unsafeGetBase(), destImpl.unsafeGetOffset() + dstOffset, elementCount * srcWidth, srcWidth);
684 }
685 }
686
687 public static long mismatch(MemorySegment srcSegment, long srcFromOffset, long srcToOffset,
688 MemorySegment dstSegment, long dstFromOffset, long dstToOffset) {
689 AbstractMemorySegmentImpl srcImpl = (AbstractMemorySegmentImpl)Objects.requireNonNull(srcSegment);
690 AbstractMemorySegmentImpl dstImpl = (AbstractMemorySegmentImpl)Objects.requireNonNull(dstSegment);
691 long srcBytes = srcToOffset - srcFromOffset;
692 long dstBytes = dstToOffset - dstFromOffset;
693 srcImpl.checkAccess(srcFromOffset, srcBytes, true);
694 dstImpl.checkAccess(dstFromOffset, dstBytes, true);
695 if (dstImpl == srcImpl) {
696 srcImpl.checkValidState();
697 return -1;
698 }
699
700 long bytes = Math.min(srcBytes, dstBytes);
701 long i = 0;
702 if (bytes > 7) {
703 if (srcImpl.get(JAVA_BYTE, srcFromOffset) != dstImpl.get(JAVA_BYTE, dstFromOffset)) {
705 }
706 i = AbstractMemorySegmentImpl.vectorizedMismatchLargeForBytes(srcImpl.sessionImpl(), dstImpl.sessionImpl(),
707 srcImpl.unsafeGetBase(), srcImpl.unsafeGetOffset() + srcFromOffset,
708 dstImpl.unsafeGetBase(), dstImpl.unsafeGetOffset() + dstFromOffset,
709 bytes);
710 if (i >= 0) {
711 return i;
712 }
713 long remaining = ~i;
714 assert remaining < 8 : "remaining greater than 7: " + remaining;
715 i = bytes - remaining;
716 }
717 for (; i < bytes; i++) {
718 if (srcImpl.get(JAVA_BYTE, srcFromOffset + i) != dstImpl.get(JAVA_BYTE, dstFromOffset + i)) {
719 return i;
720 }
721 }
722 return srcBytes != dstBytes ? bytes : -1;
723 }
724
725 private static long getBaseAndScale(Class<?> arrayType) {
726 if (arrayType.equals(byte[].class)) {
727 return (long) Unsafe.ARRAY_BYTE_BASE_OFFSET | ((long)Unsafe.ARRAY_BYTE_INDEX_SCALE << 32);
728 } else if (arrayType.equals(char[].class)) {
729 return (long) Unsafe.ARRAY_CHAR_BASE_OFFSET | ((long)Unsafe.ARRAY_CHAR_INDEX_SCALE << 32);
730 } else if (arrayType.equals(short[].class)) {
731 return (long)Unsafe.ARRAY_SHORT_BASE_OFFSET | ((long)Unsafe.ARRAY_SHORT_INDEX_SCALE << 32);
732 } else if (arrayType.equals(int[].class)) {
733 return (long)Unsafe.ARRAY_INT_BASE_OFFSET | ((long) Unsafe.ARRAY_INT_INDEX_SCALE << 32);
734 } else if (arrayType.equals(float[].class)) {
735 return (long)Unsafe.ARRAY_FLOAT_BASE_OFFSET | ((long)Unsafe.ARRAY_FLOAT_INDEX_SCALE << 32);
736 } else if (arrayType.equals(long[].class)) {
737 return (long)Unsafe.ARRAY_LONG_BASE_OFFSET | ((long)Unsafe.ARRAY_LONG_INDEX_SCALE << 32);
738 } else if (arrayType.equals(double[].class)) {
739 return (long)Unsafe.ARRAY_DOUBLE_BASE_OFFSET | ((long)Unsafe.ARRAY_DOUBLE_INDEX_SCALE << 32);
740 } else {
741 throw new IllegalArgumentException("Not a supported array class: " + arrayType.getSimpleName());
742 }
743 }
744 }
|
31 import java.nio.ByteBuffer;
32 import java.nio.ByteOrder;
33 import java.nio.CharBuffer;
34 import java.nio.DoubleBuffer;
35 import java.nio.FloatBuffer;
36 import java.nio.IntBuffer;
37 import java.nio.LongBuffer;
38 import java.nio.ShortBuffer;
39 import java.util.*;
40 import java.util.function.BiFunction;
41 import java.util.function.Consumer;
42 import java.util.function.Function;
43 import java.util.function.IntFunction;
44 import java.util.stream.Stream;
45 import java.util.stream.StreamSupport;
46
47 import jdk.internal.access.JavaNioAccess;
48 import jdk.internal.access.SharedSecrets;
49 import jdk.internal.access.foreign.UnmapperProxy;
50 import jdk.internal.misc.ScopedMemoryAccess;
51 import jdk.internal.reflect.CallerSensitive;
52 import jdk.internal.reflect.Reflection;
53 import jdk.internal.util.ArraysSupport;
54 import jdk.internal.util.Preconditions;
55 import jdk.internal.vm.annotation.ForceInline;
56 import sun.nio.ch.DirectBuffer;
57
58 import static java.lang.foreign.ValueLayout.JAVA_BYTE;
59
60 /**
61 * This abstract class provides an immutable implementation for the {@code MemorySegment} interface. This class contains information
62 * about the segment's spatial and temporal bounds; each memory segment implementation is associated with an owner thread which is set at creation time.
63 * Access to certain sensitive operations on the memory segment will fail with {@code IllegalStateException} if the
64 * segment is either in an invalid state (e.g. it has already been closed) or if access occurs from a thread other
65 * than the owner thread. See {@link MemorySessionImpl} for more details on management of temporal bounds. Subclasses
66 * are defined for each memory segment kind, see {@link NativeMemorySegmentImpl}, {@link HeapMemorySegmentImpl} and
67 * {@link MappedMemorySegmentImpl}.
68 */
69 public abstract sealed class AbstractMemorySegmentImpl
70 implements MemorySegment, SegmentAllocator, BiFunction<String, List<Number>, RuntimeException>
71 permits HeapMemorySegmentImpl, NativeMemorySegmentImpl {
72
73 private static final ScopedMemoryAccess SCOPED_MEMORY_ACCESS = ScopedMemoryAccess.getScopedMemoryAccess();
74
75 static final JavaNioAccess NIO_ACCESS = SharedSecrets.getJavaNioAccess();
76
247 @Override
248 public boolean isMapped() {
249 return false;
250 }
251
252 @Override
253 public boolean isNative() {
254 return false;
255 }
256
257 @Override
258 public final Optional<MemorySegment> asOverlappingSlice(MemorySegment other) {
259 AbstractMemorySegmentImpl that = (AbstractMemorySegmentImpl)Objects.requireNonNull(other);
260 if (unsafeGetBase() == that.unsafeGetBase()) { // both either native or heap
261 final long thisStart = this.unsafeGetOffset();
262 final long thatStart = that.unsafeGetOffset();
263 final long thisEnd = thisStart + this.byteSize();
264 final long thatEnd = thatStart + that.byteSize();
265
266 if (thisStart < thatEnd && thisEnd > thatStart) { //overlap occurs
267 long offsetToThat = that.address() - this.address();
268 long newOffset = offsetToThat >= 0 ? offsetToThat : 0;
269 return Optional.of(asSlice(newOffset, Math.min(this.byteSize() - newOffset, that.byteSize() + offsetToThat)));
270 }
271 }
272 return Optional.empty();
273 }
274
275 @Override
276 public void load() {
277 throw notAMappedSegment();
278 }
279
280 @Override
281 public void unload() {
282 throw notAMappedSegment();
283 }
284
285 @Override
286 public boolean isLoaded() {
287 throw notAMappedSegment();
288 }
289
290 @Override
291 public void force() {
292 throw notAMappedSegment();
293 }
294
520 public static AbstractMemorySegmentImpl ofBuffer(Buffer bb) {
521 Objects.requireNonNull(bb);
522 Object base = NIO_ACCESS.getBufferBase(bb);
523 if (!bb.isDirect() && base == null) {
524 throw new IllegalArgumentException("The provided heap buffer is not backed by an array.");
525 }
526 long bbAddress = NIO_ACCESS.getBufferAddress(bb);
527 UnmapperProxy unmapper = NIO_ACCESS.unmapper(bb);
528
529 int pos = bb.position();
530 int limit = bb.limit();
531 int size = limit - pos;
532
533 AbstractMemorySegmentImpl bufferSegment = (AbstractMemorySegmentImpl) NIO_ACCESS.bufferSegment(bb);
534 boolean readOnly = bb.isReadOnly();
535 int scaleFactor = getScaleFactor(bb);
536 final MemorySessionImpl bufferScope;
537 if (bufferSegment != null) {
538 bufferScope = bufferSegment.scope;
539 } else {
540 bufferScope = MemorySessionImpl.createHeap(bufferRef(bb));
541 }
542 if (base != null) {
543 return switch (base) {
544 case byte[] __ ->
545 new HeapMemorySegmentImpl.OfByte(bbAddress + (pos << scaleFactor), base, size << scaleFactor, readOnly, bufferScope);
546 case short[] __ ->
547 new HeapMemorySegmentImpl.OfShort(bbAddress + (pos << scaleFactor), base, size << scaleFactor, readOnly, bufferScope);
548 case char[] __ ->
549 new HeapMemorySegmentImpl.OfChar(bbAddress + (pos << scaleFactor), base, size << scaleFactor, readOnly, bufferScope);
550 case int[] __ ->
551 new HeapMemorySegmentImpl.OfInt(bbAddress + (pos << scaleFactor), base, size << scaleFactor, readOnly, bufferScope);
552 case float[] __ ->
553 new HeapMemorySegmentImpl.OfFloat(bbAddress + (pos << scaleFactor), base, size << scaleFactor, readOnly, bufferScope);
554 case long[] __ ->
555 new HeapMemorySegmentImpl.OfLong(bbAddress + (pos << scaleFactor), base, size << scaleFactor, readOnly, bufferScope);
556 case double[] __ ->
557 new HeapMemorySegmentImpl.OfDouble(bbAddress + (pos << scaleFactor), base, size << scaleFactor, readOnly, bufferScope);
558 default -> throw new AssertionError("Cannot get here");
559 };
560 } else if (unmapper == null) {
561 return new NativeMemorySegmentImpl(bbAddress + (pos << scaleFactor), size << scaleFactor, readOnly, bufferScope);
562 } else {
563 // we can ignore scale factor here, a mapped buffer is always a byte buffer, so scaleFactor == 0.
564 return new MappedMemorySegmentImpl(bbAddress + pos, unmapper, size, readOnly, bufferScope);
565 }
566 }
567
568 private static Object bufferRef(Buffer buffer) {
569 if (buffer instanceof DirectBuffer directBuffer) {
570 // direct buffer, return either the buffer attachment (for slices and views), or the buffer itself
571 return directBuffer.attachment() != null ?
572 directBuffer.attachment() : directBuffer;
573 } else {
574 // heap buffer, return the underlying array
575 return NIO_ACCESS.getBufferBase(buffer);
576 }
577 }
578
579 @ForceInline
580 public static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long srcOffset,
581 MemorySegment dstSegment, ValueLayout dstElementLayout, long dstOffset,
582 long elementCount) {
583
584 AbstractMemorySegmentImpl srcImpl = (AbstractMemorySegmentImpl)srcSegment;
585 AbstractMemorySegmentImpl dstImpl = (AbstractMemorySegmentImpl)dstSegment;
586 if (srcElementLayout.byteSize() != dstElementLayout.byteSize()) {
587 throw new IllegalArgumentException("Source and destination layouts must have same size");
588 }
589 Utils.checkElementAlignment(srcElementLayout, "Source layout alignment greater than its size");
590 Utils.checkElementAlignment(dstElementLayout, "Destination layout alignment greater than its size");
591 if (!srcImpl.isAlignedForElement(srcOffset, srcElementLayout)) {
592 throw new IllegalArgumentException("Source segment incompatible with alignment constraints");
593 }
594 if (!dstImpl.isAlignedForElement(dstOffset, dstElementLayout)) {
595 throw new IllegalArgumentException("Destination segment incompatible with alignment constraints");
596 }
597 long size = elementCount * srcElementLayout.byteSize();
598 srcImpl.checkAccess(srcOffset, size, true);
599 dstImpl.checkAccess(dstOffset, size, false);
600 if (srcElementLayout.byteSize() == 1 || srcElementLayout.order() == dstElementLayout.order()) {
601 ScopedMemoryAccess.getScopedMemoryAccess().copyMemory(srcImpl.sessionImpl(), dstImpl.sessionImpl(),
602 srcImpl.unsafeGetBase(), srcImpl.unsafeGetOffset() + srcOffset,
603 dstImpl.unsafeGetBase(), dstImpl.unsafeGetOffset() + dstOffset, size);
604 } else {
605 ScopedMemoryAccess.getScopedMemoryAccess().copySwapMemory(srcImpl.sessionImpl(), dstImpl.sessionImpl(),
606 srcImpl.unsafeGetBase(), srcImpl.unsafeGetOffset() + srcOffset,
607 dstImpl.unsafeGetBase(), dstImpl.unsafeGetOffset() + dstOffset, size, srcElementLayout.byteSize());
608 }
609 }
610
611 @ForceInline
612 public static void copy(MemorySegment srcSegment, ValueLayout srcLayout, long srcOffset,
613 Object dstArray, int dstIndex,
614 int elementCount) {
615
616 var dstInfo = Utils.BaseAndScale.of(dstArray);
617 if (dstArray.getClass().componentType() != srcLayout.carrier()) {
618 throw new IllegalArgumentException("Incompatible value layout: " + srcLayout);
619 }
620 AbstractMemorySegmentImpl srcImpl = (AbstractMemorySegmentImpl)srcSegment;
621 Utils.checkElementAlignment(srcLayout, "Source layout alignment greater than its size");
622 if (!srcImpl.isAlignedForElement(srcOffset, srcLayout)) {
623 throw new IllegalArgumentException("Source segment incompatible with alignment constraints");
624 }
625 srcImpl.checkAccess(srcOffset, elementCount * dstInfo.scale(), true);
626 Objects.checkFromIndexSize(dstIndex, elementCount, Array.getLength(dstArray));
627 if (dstInfo.scale() == 1 || srcLayout.order() == ByteOrder.nativeOrder()) {
628 ScopedMemoryAccess.getScopedMemoryAccess().copyMemory(srcImpl.sessionImpl(), null,
629 srcImpl.unsafeGetBase(), srcImpl.unsafeGetOffset() + srcOffset,
630 dstArray, dstInfo.base() + (dstIndex * dstInfo.scale()), elementCount * dstInfo.scale());
631 } else {
632 ScopedMemoryAccess.getScopedMemoryAccess().copySwapMemory(srcImpl.sessionImpl(), null,
633 srcImpl.unsafeGetBase(), srcImpl.unsafeGetOffset() + srcOffset,
634 dstArray, dstInfo.base() + (dstIndex * dstInfo.scale()), elementCount * dstInfo.scale(), dstInfo.scale());
635 }
636 }
637
638 @ForceInline
639 public static void copy(Object srcArray, int srcIndex,
640 MemorySegment dstSegment, ValueLayout dstLayout, long dstOffset,
641 int elementCount) {
642
643 var srcInfo = Utils.BaseAndScale.of(srcArray);
644 if (srcArray.getClass().componentType() != dstLayout.carrier()) {
645 throw new IllegalArgumentException("Incompatible value layout: " + dstLayout);
646 }
647 Objects.checkFromIndexSize(srcIndex, elementCount, Array.getLength(srcArray));
648 AbstractMemorySegmentImpl destImpl = (AbstractMemorySegmentImpl)dstSegment;
649 Utils.checkElementAlignment(dstLayout, "Destination layout alignment greater than its size");
650 if (!destImpl.isAlignedForElement(dstOffset, dstLayout)) {
651 throw new IllegalArgumentException("Destination segment incompatible with alignment constraints");
652 }
653 destImpl.checkAccess(dstOffset, elementCount * srcInfo.scale(), false);
654 if (srcInfo.scale() == 1 || dstLayout.order() == ByteOrder.nativeOrder()) {
655 ScopedMemoryAccess.getScopedMemoryAccess().copyMemory(null, destImpl.sessionImpl(),
656 srcArray, srcInfo.base() + (srcIndex * srcInfo.scale()),
657 destImpl.unsafeGetBase(), destImpl.unsafeGetOffset() + dstOffset, elementCount * srcInfo.scale());
658 } else {
659 ScopedMemoryAccess.getScopedMemoryAccess().copySwapMemory(null, destImpl.sessionImpl(),
660 srcArray, srcInfo.base() + (srcIndex * srcInfo.scale()),
661 destImpl.unsafeGetBase(), destImpl.unsafeGetOffset() + dstOffset, elementCount * srcInfo.scale(), srcInfo.scale());
662 }
663 }
664
665 public static long mismatch(MemorySegment srcSegment, long srcFromOffset, long srcToOffset,
666 MemorySegment dstSegment, long dstFromOffset, long dstToOffset) {
667 AbstractMemorySegmentImpl srcImpl = (AbstractMemorySegmentImpl)Objects.requireNonNull(srcSegment);
668 AbstractMemorySegmentImpl dstImpl = (AbstractMemorySegmentImpl)Objects.requireNonNull(dstSegment);
669 long srcBytes = srcToOffset - srcFromOffset;
670 long dstBytes = dstToOffset - dstFromOffset;
671 srcImpl.checkAccess(srcFromOffset, srcBytes, true);
672 dstImpl.checkAccess(dstFromOffset, dstBytes, true);
673 if (dstImpl == srcImpl) {
674 srcImpl.checkValidState();
675 return -1;
676 }
677
678 long bytes = Math.min(srcBytes, dstBytes);
679 long i = 0;
680 if (bytes > 7) {
681 if (srcImpl.get(JAVA_BYTE, srcFromOffset) != dstImpl.get(JAVA_BYTE, dstFromOffset)) {
683 }
684 i = AbstractMemorySegmentImpl.vectorizedMismatchLargeForBytes(srcImpl.sessionImpl(), dstImpl.sessionImpl(),
685 srcImpl.unsafeGetBase(), srcImpl.unsafeGetOffset() + srcFromOffset,
686 dstImpl.unsafeGetBase(), dstImpl.unsafeGetOffset() + dstFromOffset,
687 bytes);
688 if (i >= 0) {
689 return i;
690 }
691 long remaining = ~i;
692 assert remaining < 8 : "remaining greater than 7: " + remaining;
693 i = bytes - remaining;
694 }
695 for (; i < bytes; i++) {
696 if (srcImpl.get(JAVA_BYTE, srcFromOffset + i) != dstImpl.get(JAVA_BYTE, dstFromOffset + i)) {
697 return i;
698 }
699 }
700 return srcBytes != dstBytes ? bytes : -1;
701 }
702
703 private static int getScaleFactor(Buffer buffer) {
704 return switch (buffer) {
705 case ByteBuffer __ -> 0;
706 case CharBuffer __ -> 1;
707 case ShortBuffer __ -> 1;
708 case IntBuffer __ -> 2;
709 case FloatBuffer __ -> 2;
710 case LongBuffer __ -> 3;
711 case DoubleBuffer __ -> 3;
712 };
713 }
714 }
|