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 }