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 }