1 /*
  2  * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.  Oracle designates this
  8  * particular file as subject to the "Classpath" exception as provided
  9  * by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any
 23  * questions.
 24  */
 25 
 26 package jdk.internal.foreign;
 27 
 28 import java.lang.foreign.*;
 29 import java.lang.reflect.Array;
 30 import java.nio.Buffer;
 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 
 77     final long length;
 78     final boolean readOnly;
 79     final MemorySessionImpl scope;
 80 
 81     @ForceInline
 82     AbstractMemorySegmentImpl(long length, boolean readOnly, MemorySessionImpl scope) {
 83         this.length = length;
 84         this.readOnly = readOnly;
 85         this.scope = scope;
 86     }
 87 
 88     abstract AbstractMemorySegmentImpl dup(long offset, long size, boolean readOnly, MemorySessionImpl scope);
 89 
 90     abstract ByteBuffer makeByteBuffer();
 91 
 92     @Override
 93     public AbstractMemorySegmentImpl asReadOnly() {
 94         return dup(0, length, true, scope);
 95     }
 96 
 97     @Override
 98     public boolean isReadOnly() {
 99         return readOnly;
100     }
101 
102     @Override
103     public AbstractMemorySegmentImpl asSlice(long offset, long newSize) {
104         checkBounds(offset, newSize);
105         return asSliceNoCheck(offset, newSize);
106     }
107 
108     @Override
109     public AbstractMemorySegmentImpl asSlice(long offset) {
110         checkBounds(offset, 0);
111         return asSliceNoCheck(offset, length - offset);
112     }
113 
114     @Override
115     public MemorySegment asSlice(long offset, long newSize, long byteAlignment) {
116         checkBounds(offset, newSize);
117         Utils.checkAlign(byteAlignment);
118 
119         if (!isAlignedForElement(offset, byteAlignment)) {
120             throw new IllegalArgumentException("Target offset incompatible with alignment constraints");
121         }
122         return asSliceNoCheck(offset, newSize);
123     }
124 
125     @Override
126     @CallerSensitive
127     public final MemorySegment reinterpret(long newSize, Arena arena, Consumer<MemorySegment> cleanup) {
128         Objects.requireNonNull(arena);
129         return reinterpretInternal(Reflection.getCallerClass(), newSize,
130                 MemorySessionImpl.toMemorySession(arena), cleanup);
131     }
132 
133     @Override
134     @CallerSensitive
135     public final MemorySegment reinterpret(long newSize) {
136         return reinterpretInternal(Reflection.getCallerClass(), newSize, scope, null);
137     }
138 
139     @Override
140     @CallerSensitive
141     public final MemorySegment reinterpret(Arena arena, Consumer<MemorySegment> cleanup) {
142         Objects.requireNonNull(arena);
143         return reinterpretInternal(Reflection.getCallerClass(), byteSize(),
144                 MemorySessionImpl.toMemorySession(arena), cleanup);
145     }
146 
147     public MemorySegment reinterpretInternal(Class<?> callerClass, long newSize, Scope scope, Consumer<MemorySegment> cleanup) {
148         Reflection.ensureNativeAccess(callerClass, MemorySegment.class, "reinterpret");
149         if (newSize < 0) {
150             throw new IllegalArgumentException("newSize < 0");
151         }
152         if (!isNative()) throw new UnsupportedOperationException("Not a native segment");
153         Runnable action = cleanup != null ?
154                 () -> cleanup.accept(NativeMemorySegmentImpl.makeNativeSegmentUnchecked(address(), newSize)) :
155                 null;
156         return NativeMemorySegmentImpl.makeNativeSegmentUnchecked(address(), newSize,
157                 (MemorySessionImpl)scope, action);
158     }
159 
160     private AbstractMemorySegmentImpl asSliceNoCheck(long offset, long newSize) {
161         return dup(offset, newSize, readOnly, scope);
162     }
163 
164     @Override
165     public Spliterator<MemorySegment> spliterator(MemoryLayout elementLayout) {
166         Objects.requireNonNull(elementLayout);
167         if (elementLayout.byteSize() == 0) {
168             throw new IllegalArgumentException("Element layout size cannot be zero");
169         }
170         Utils.checkElementAlignment(elementLayout, "Element layout size is not multiple of alignment");
171         if (!isAlignedForElement(0, elementLayout)) {
172             throw new IllegalArgumentException("Incompatible alignment constraints");
173         }
174         if ((byteSize() % elementLayout.byteSize()) != 0) {
175             throw new IllegalArgumentException("Segment size is not a multiple of layout size");
176         }
177         return new SegmentSplitter(elementLayout.byteSize(), byteSize() / elementLayout.byteSize(),
178                 this);
179     }
180 
181     @Override
182     public Stream<MemorySegment> elements(MemoryLayout elementLayout) {
183         return StreamSupport.stream(spliterator(elementLayout), false);
184     }
185 
186     @Override
187     public final MemorySegment fill(byte value){
188         checkAccess(0, length, false);
189         SCOPED_MEMORY_ACCESS.setMemory(sessionImpl(), unsafeGetBase(), unsafeGetOffset(), length, value);
190         return this;
191     }
192 
193     @Override
194     public MemorySegment allocate(long byteSize, long byteAlignment) {
195         Utils.checkAllocationSizeAndAlign(byteSize, byteAlignment);
196         return asSlice(0, byteSize, byteAlignment);
197     }
198 
199     /**
200      * Mismatch over long lengths.
201      */
202     public static long vectorizedMismatchLargeForBytes(MemorySessionImpl aSession, MemorySessionImpl bSession,
203                                                         Object a, long aOffset,
204                                                         Object b, long bOffset,
205                                                         long length) {
206         long off = 0;
207         long remaining = length;
208         int i, size;
209         boolean lastSubRange = false;
210         while (remaining > 7 && !lastSubRange) {
211             if (remaining > Integer.MAX_VALUE) {
212                 size = Integer.MAX_VALUE;
213             } else {
214                 size = (int) remaining;
215                 lastSubRange = true;
216             }
217             i = SCOPED_MEMORY_ACCESS.vectorizedMismatch(aSession, bSession,
218                     a, aOffset + off,
219                     b, bOffset + off,
220                     size, ArraysSupport.LOG2_ARRAY_BYTE_INDEX_SCALE);
221             if (i >= 0)
222                 return off + i;
223 
224             i = size - ~i;
225             off += i;
226             remaining -= i;
227         }
228         return ~remaining;
229     }
230 
231     @Override
232     public final ByteBuffer asByteBuffer() {
233         checkArraySize("ByteBuffer", 1);
234         ByteBuffer _bb = makeByteBuffer();
235         if (readOnly) {
236             //session is IMMUTABLE - obtain a RO byte buffer
237             _bb = _bb.asReadOnlyBuffer();
238         }
239         return _bb;
240     }
241 
242     @Override
243     public final long byteSize() {
244         return length;
245     }
246 
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 
295     private static UnsupportedOperationException notAMappedSegment() {
296         throw new UnsupportedOperationException("Not a mapped segment");
297     }
298 
299     @Override
300     public final byte[] toArray(ValueLayout.OfByte elementLayout) {
301         return toArray(byte[].class, elementLayout, byte[]::new, MemorySegment::ofArray);
302     }
303 
304     @Override
305     public final short[] toArray(ValueLayout.OfShort elementLayout) {
306         return toArray(short[].class, elementLayout, short[]::new, MemorySegment::ofArray);
307     }
308 
309     @Override
310     public final char[] toArray(ValueLayout.OfChar elementLayout) {
311         return toArray(char[].class, elementLayout, char[]::new, MemorySegment::ofArray);
312     }
313 
314     @Override
315     public final int[] toArray(ValueLayout.OfInt elementLayout) {
316         return toArray(int[].class, elementLayout, int[]::new, MemorySegment::ofArray);
317     }
318 
319     @Override
320     public final float[] toArray(ValueLayout.OfFloat elementLayout) {
321         return toArray(float[].class, elementLayout, float[]::new, MemorySegment::ofArray);
322     }
323 
324     @Override
325     public final long[] toArray(ValueLayout.OfLong elementLayout) {
326         return toArray(long[].class, elementLayout, long[]::new, MemorySegment::ofArray);
327     }
328 
329     @Override
330     public final double[] toArray(ValueLayout.OfDouble elementLayout) {
331         return toArray(double[].class, elementLayout, double[]::new, MemorySegment::ofArray);
332     }
333 
334     private <Z> Z toArray(Class<Z> arrayClass, ValueLayout elemLayout, IntFunction<Z> arrayFactory, Function<Z, MemorySegment> segmentFactory) {
335         int size = checkArraySize(arrayClass.getSimpleName(), (int)elemLayout.byteSize());
336         Z arr = arrayFactory.apply(size);
337         MemorySegment arrSegment = segmentFactory.apply(arr);
338         MemorySegment.copy(this, elemLayout, 0, arrSegment, elemLayout.withOrder(ByteOrder.nativeOrder()), 0, size);
339         return arr;
340     }
341 
342     @ForceInline
343     public void checkAccess(long offset, long length, boolean readOnly) {
344         if (!readOnly && this.readOnly) {
345             throw new UnsupportedOperationException("Attempt to write a read-only segment");
346         }
347         checkBounds(offset, length);
348     }
349 
350     public void checkValidState() {
351         sessionImpl().checkValidState();
352     }
353 
354     public abstract long unsafeGetOffset();
355 
356     public abstract Object unsafeGetBase();
357 
358     // Helper methods
359 
360     public abstract long maxAlignMask();
361 
362     @ForceInline
363     public final boolean isAlignedForElement(long offset, MemoryLayout layout) {
364         return isAlignedForElement(offset, layout.byteAlignment());
365     }
366 
367     @ForceInline
368     public final boolean isAlignedForElement(long offset, long byteAlignment) {
369         return (((unsafeGetOffset() + offset) | maxAlignMask()) & (byteAlignment - 1)) == 0;
370     }
371 
372     private int checkArraySize(String typeName, int elemSize) {
373         // elemSize is guaranteed to be a power of two, so we can use an alignment check
374         if (!Utils.isAligned(length, elemSize)) {
375             throw new IllegalStateException(String.format("Segment size is not a multiple of %d. Size: %d", elemSize, length));
376         }
377         long arraySize = length / elemSize;
378         if (arraySize > (Integer.MAX_VALUE - 8)) { //conservative check
379             throw new IllegalStateException(String.format("Segment is too large to wrap as %s. Size: %d", typeName, length));
380         }
381         return (int)arraySize;
382     }
383 
384     @ForceInline
385     void checkBounds(long offset, long length) {
386         if (length > 0) {
387             Preconditions.checkIndex(offset, this.length - length + 1, this);
388         } else if (length < 0 || offset < 0 ||
389                 offset > this.length - length) {
390             throw outOfBoundException(offset, length);
391         }
392     }
393 
394     @Override
395     public RuntimeException apply(String s, List<Number> numbers) {
396         long offset = numbers.get(0).longValue();
397         long length = byteSize() - numbers.get(1).longValue() + 1;
398         return outOfBoundException(offset, length);
399     }
400 
401     @Override
402     public Scope scope() {
403         return scope;
404     }
405 
406     @Override
407     public boolean isAccessibleBy(Thread thread) {
408         return sessionImpl().isAccessibleBy(thread);
409     }
410 
411     @ForceInline
412     public final MemorySessionImpl sessionImpl() {
413         return scope;
414     }
415 
416     private IndexOutOfBoundsException outOfBoundException(long offset, long length) {
417         return new IndexOutOfBoundsException(String.format("Out of bound access on segment %s; new offset = %d; new length = %d",
418                         this, offset, length));
419     }
420 
421     static class SegmentSplitter implements Spliterator<MemorySegment> {
422         AbstractMemorySegmentImpl segment;
423         long elemCount;
424         final long elementSize;
425         long currentIndex;
426 
427         SegmentSplitter(long elementSize, long elemCount, AbstractMemorySegmentImpl segment) {
428             this.segment = segment;
429             this.elementSize = elementSize;
430             this.elemCount = elemCount;
431         }
432 
433         @Override
434         public SegmentSplitter trySplit() {
435             if (currentIndex == 0 && elemCount > 1) {
436                 AbstractMemorySegmentImpl parent = segment;
437                 long rem = elemCount % 2;
438                 long split = elemCount / 2;
439                 long lobound = split * elementSize;
440                 long hibound = lobound + (rem * elementSize);
441                 elemCount  = split + rem;
442                 segment = parent.asSliceNoCheck(lobound, hibound);
443                 return new SegmentSplitter(elementSize, split, parent.asSliceNoCheck(0, lobound));
444             } else {
445                 return null;
446             }
447         }
448 
449         @Override
450         public boolean tryAdvance(Consumer<? super MemorySegment> action) {
451             Objects.requireNonNull(action);
452             if (currentIndex < elemCount) {
453                 AbstractMemorySegmentImpl acquired = segment;
454                 try {
455                     action.accept(acquired.asSliceNoCheck(currentIndex * elementSize, elementSize));
456                 } finally {
457                     currentIndex++;
458                     if (currentIndex == elemCount) {
459                         segment = null;
460                     }
461                 }
462                 return true;
463             } else {
464                 return false;
465             }
466         }
467 
468         @Override
469         public void forEachRemaining(Consumer<? super MemorySegment> action) {
470             Objects.requireNonNull(action);
471             if (currentIndex < elemCount) {
472                 AbstractMemorySegmentImpl acquired = segment;
473                 try {
474                     for (long i = currentIndex ; i < elemCount ; i++) {
475                         action.accept(acquired.asSliceNoCheck(i * elementSize, elementSize));
476                     }
477                 } finally {
478                     currentIndex = elemCount;
479                     segment = null;
480                 }
481             }
482         }
483 
484         @Override
485         public long estimateSize() {
486             return elemCount;
487         }
488 
489         @Override
490         public int characteristics() {
491             return NONNULL | SUBSIZED | SIZED | IMMUTABLE | ORDERED;
492         }
493     }
494 
495     // Object methods
496 
497     @Override
498     public String toString() {
499         return "MemorySegment{ " +
500                 heapBase().map(hb -> "heapBase: " + hb + ", ").orElse("") +
501                 "address: " + Utils.toHexString(address()) +
502                 ", byteSize: " + length +
503                 " }";
504     }
505 
506     @Override
507     public boolean equals(Object o) {
508         return o instanceof AbstractMemorySegmentImpl that &&
509                 unsafeGetBase() == that.unsafeGetBase() &&
510                 unsafeGetOffset() == that.unsafeGetOffset();
511     }
512 
513     @Override
514     public int hashCode() {
515         return Objects.hash(
516                 unsafeGetOffset(),
517                 unsafeGetBase());
518     }
519 
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)) {
682                 return 0;
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 }