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.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 
 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 = 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 
304     private static UnsupportedOperationException notAMappedSegment() {
305         throw new UnsupportedOperationException("Not a mapped segment");
306     }
307 
308     @Override
309     public final byte[] toArray(ValueLayout.OfByte elementLayout) {
310         return toArray(byte[].class, elementLayout, byte[]::new, MemorySegment::ofArray);
311     }
312 
313     @Override
314     public final short[] toArray(ValueLayout.OfShort elementLayout) {
315         return toArray(short[].class, elementLayout, short[]::new, MemorySegment::ofArray);
316     }
317 
318     @Override
319     public final char[] toArray(ValueLayout.OfChar elementLayout) {
320         return toArray(char[].class, elementLayout, char[]::new, MemorySegment::ofArray);
321     }
322 
323     @Override
324     public final int[] toArray(ValueLayout.OfInt elementLayout) {
325         return toArray(int[].class, elementLayout, int[]::new, MemorySegment::ofArray);
326     }
327 
328     @Override
329     public final float[] toArray(ValueLayout.OfFloat elementLayout) {
330         return toArray(float[].class, elementLayout, float[]::new, MemorySegment::ofArray);
331     }
332 
333     @Override
334     public final long[] toArray(ValueLayout.OfLong elementLayout) {
335         return toArray(long[].class, elementLayout, long[]::new, MemorySegment::ofArray);
336     }
337 
338     @Override
339     public final double[] toArray(ValueLayout.OfDouble elementLayout) {
340         return toArray(double[].class, elementLayout, double[]::new, MemorySegment::ofArray);
341     }
342 
343     private <Z> Z toArray(Class<Z> arrayClass, ValueLayout elemLayout, IntFunction<Z> arrayFactory, Function<Z, MemorySegment> segmentFactory) {
344         int size = checkArraySize(arrayClass.getSimpleName(), (int)elemLayout.byteSize());
345         Z arr = arrayFactory.apply(size);
346         MemorySegment arrSegment = segmentFactory.apply(arr);
347         MemorySegment.copy(this, elemLayout, 0, arrSegment, elemLayout.withOrder(ByteOrder.nativeOrder()), 0, size);
348         return arr;
349     }
350 
351     @ForceInline
352     public void checkAccess(long offset, long length, boolean readOnly) {
353         if (!readOnly && this.readOnly) {
354             throw new UnsupportedOperationException("Attempt to write a read-only segment");
355         }
356         checkBounds(offset, length);
357     }
358 
359     public void checkValidState() {
360         sessionImpl().checkValidState();
361     }
362 
363     public abstract long unsafeGetOffset();
364 
365     public abstract Object unsafeGetBase();
366 
367     // Helper methods
368 
369     public abstract long maxAlignMask();
370 
371     @ForceInline
372     public final boolean isAlignedForElement(long offset, MemoryLayout layout) {
373         return isAlignedForElement(offset, layout.byteAlignment());
374     }
375 
376     @ForceInline
377     public final boolean isAlignedForElement(long offset, long byteAlignment) {
378         return (((unsafeGetOffset() + offset) | maxAlignMask()) & (byteAlignment - 1)) == 0;
379     }
380 
381     private int checkArraySize(String typeName, int elemSize) {
382         // elemSize is guaranteed to be a power of two, so we can use an alignment check
383         if (!Utils.isAligned(length, elemSize)) {
384             throw new IllegalStateException(String.format("Segment size is not a multiple of %d. Size: %d", elemSize, length));
385         }
386         long arraySize = length / elemSize;
387         if (arraySize > (Integer.MAX_VALUE - 8)) { //conservative check
388             throw new IllegalStateException(String.format("Segment is too large to wrap as %s. Size: %d", typeName, length));
389         }
390         return (int)arraySize;
391     }
392 
393     @ForceInline
394     void checkBounds(long offset, long length) {
395         if (length > 0) {
396             Preconditions.checkIndex(offset, this.length - length + 1, this);
397         } else if (length < 0 || offset < 0 ||
398                 offset > this.length - length) {
399             throw outOfBoundException(offset, length);
400         }
401     }
402 
403     @Override
404     public RuntimeException apply(String s, List<Number> numbers) {
405         long offset = numbers.get(0).longValue();
406         long length = byteSize() - numbers.get(1).longValue() + 1;
407         return outOfBoundException(offset, length);
408     }
409 
410     @Override
411     public Scope scope() {
412         return scope;
413     }
414 
415     @Override
416     public boolean isAccessibleBy(Thread thread) {
417         return sessionImpl().isAccessibleBy(thread);
418     }
419 
420     @ForceInline
421     public final MemorySessionImpl sessionImpl() {
422         return scope;
423     }
424 
425     private IndexOutOfBoundsException outOfBoundException(long offset, long length) {
426         return new IndexOutOfBoundsException(String.format("Out of bound access on segment %s; new offset = %d; new length = %d",
427                         this, offset, length));
428     }
429 
430     static class SegmentSplitter implements Spliterator<MemorySegment> {
431         AbstractMemorySegmentImpl segment;
432         long elemCount;
433         final long elementSize;
434         long currentIndex;
435 
436         SegmentSplitter(long elementSize, long elemCount, AbstractMemorySegmentImpl segment) {
437             this.segment = segment;
438             this.elementSize = elementSize;
439             this.elemCount = elemCount;
440         }
441 
442         @Override
443         public SegmentSplitter trySplit() {
444             if (currentIndex == 0 && elemCount > 1) {
445                 AbstractMemorySegmentImpl parent = segment;
446                 long rem = elemCount % 2;
447                 long split = elemCount / 2;
448                 long lobound = split * elementSize;
449                 long hibound = lobound + (rem * elementSize);
450                 elemCount  = split + rem;
451                 segment = parent.asSliceNoCheck(lobound, hibound);
452                 return new SegmentSplitter(elementSize, split, parent.asSliceNoCheck(0, lobound));
453             } else {
454                 return null;
455             }
456         }
457 
458         @Override
459         public boolean tryAdvance(Consumer<? super MemorySegment> action) {
460             Objects.requireNonNull(action);
461             if (currentIndex < elemCount) {
462                 AbstractMemorySegmentImpl acquired = segment;
463                 try {
464                     action.accept(acquired.asSliceNoCheck(currentIndex * elementSize, elementSize));
465                 } finally {
466                     currentIndex++;
467                     if (currentIndex == elemCount) {
468                         segment = null;
469                     }
470                 }
471                 return true;
472             } else {
473                 return false;
474             }
475         }
476 
477         @Override
478         public void forEachRemaining(Consumer<? super MemorySegment> action) {
479             Objects.requireNonNull(action);
480             if (currentIndex < elemCount) {
481                 AbstractMemorySegmentImpl acquired = segment;
482                 try {
483                     for (long i = currentIndex ; i < elemCount ; i++) {
484                         action.accept(acquired.asSliceNoCheck(i * elementSize, elementSize));
485                     }
486                 } finally {
487                     currentIndex = elemCount;
488                     segment = null;
489                 }
490             }
491         }
492 
493         @Override
494         public long estimateSize() {
495             return elemCount;
496         }
497 
498         @Override
499         public int characteristics() {
500             return NONNULL | SUBSIZED | SIZED | IMMUTABLE | ORDERED;
501         }
502     }
503 
504     // Object methods
505 
506     @Override
507     public String toString() {
508         return "MemorySegment{ " +
509                 heapBase().map(hb -> "heapBase: " + hb + ", ").orElse("") +
510                 "address: " + Utils.toHexString(address()) +
511                 ", byteSize: " + length +
512                 " }";
513     }
514 
515     @Override
516     public boolean equals(Object o) {
517         return o instanceof AbstractMemorySegmentImpl that &&
518                 unsafeGetBase() == that.unsafeGetBase() &&
519                 unsafeGetOffset() == that.unsafeGetOffset();
520     }
521 
522     @Override
523     public int hashCode() {
524         return Objects.hash(
525                 unsafeGetOffset(),
526                 unsafeGetBase());
527     }
528 
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)) {
704                 return 0;
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 }