< prev index next >

src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/Utils.java

Print this page
*** 25,21 ***
   */
  
  package jdk.internal.foreign;
  
  import jdk.incubator.foreign.*;
  import jdk.internal.access.foreign.MemorySegmentProxy;
! import jdk.internal.misc.VM;
- import sun.invoke.util.Wrapper;
  
  import java.lang.invoke.MethodHandle;
  import java.lang.invoke.MethodHandles;
  import java.lang.invoke.MethodType;
  import java.lang.invoke.VarHandle;
! import java.util.Optional;
  import java.util.function.Supplier;
  
  import static sun.security.action.GetPropertyAction.*;
  
  /**
   * This class contains misc helper functions to support creation of memory segments.
   */
--- 25,22 ---
   */
  
  package jdk.internal.foreign;
  
  import jdk.incubator.foreign.*;
+ import jdk.internal.access.SharedSecrets;
  import jdk.internal.access.foreign.MemorySegmentProxy;
! import jdk.internal.vm.annotation.ForceInline;
  
  import java.lang.invoke.MethodHandle;
  import java.lang.invoke.MethodHandles;
  import java.lang.invoke.MethodType;
  import java.lang.invoke.VarHandle;
! import java.nio.ByteOrder;
  import java.util.function.Supplier;
  
+ import static jdk.incubator.foreign.ValueLayout.JAVA_BYTE;
  import static sun.security.action.GetPropertyAction.*;
  
  /**
   * This class contains misc helper functions to support creation of memory segments.
   */

*** 47,20 ***
--- 48,32 ---
      // used when testing invoke exact behavior of memory access handles
      private static final boolean SHOULD_ADAPT_HANDLES
          = Boolean.parseBoolean(privilegedGetProperty("jdk.internal.foreign.SHOULD_ADAPT_HANDLES", "true"));
  
      private static final MethodHandle SEGMENT_FILTER;
+     private static final MethodHandle BYTE_TO_BOOL;
+     private static final MethodHandle BOOL_TO_BYTE;
+     private static final MethodHandle ADDRESS_TO_LONG;
+     private static final MethodHandle LONG_TO_ADDRESS;
      public static final MethodHandle MH_bitsToBytesOrThrowForOffset;
  
      public static final Supplier<RuntimeException> bitsToBytesThrowOffset
          = () -> new UnsupportedOperationException("Cannot compute byte offset; bit offset is not a multiple of 8");
  
      static {
          try {
              MethodHandles.Lookup lookup = MethodHandles.lookup();
              SEGMENT_FILTER = lookup.findStatic(Utils.class, "filterSegment",
                      MethodType.methodType(MemorySegmentProxy.class, MemorySegment.class));
+             BYTE_TO_BOOL = lookup.findStatic(Utils.class, "byteToBoolean",
+                     MethodType.methodType(boolean.class, byte.class));
+             BOOL_TO_BYTE = lookup.findStatic(Utils.class, "booleanToByte",
+                     MethodType.methodType(byte.class, boolean.class));
+             ADDRESS_TO_LONG = lookup.findVirtual(MemoryAddress.class, "toRawLongValue",
+                     MethodType.methodType(long.class));
+             LONG_TO_ADDRESS = lookup.findStatic(MemoryAddress.class, "ofLong",
+                     MethodType.methodType(MemoryAddress.class, long.class));
              MH_bitsToBytesOrThrowForOffset = MethodHandles.insertArguments(
                  lookup.findStatic(Utils.class, "bitsToBytesOrThrow",
                      MethodType.methodType(long.class, long.class, Supplier.class)),
                  1,
                  bitsToBytesThrowOffset);

*** 89,40 ***
          } else {
              throw exFactory.get();
          }
      }
  
!     public static VarHandle fixUpVarHandle(VarHandle handle) {
          // This adaptation is required, otherwise the memory access var handle will have type MemorySegmentProxy,
          // and not MemorySegment (which the user expects), which causes performance issues with asType() adaptations.
!         return SHOULD_ADAPT_HANDLES
              ? MemoryHandles.filterCoordinates(handle, 0, SEGMENT_FILTER)
              : handle;
      }
  
      private static MemorySegmentProxy filterSegment(MemorySegment segment) {
          return (AbstractMemorySegmentImpl)segment;
      }
  
!     public static void checkPrimitiveCarrierCompat(Class<?> carrier, MemoryLayout layout) {
!         checkLayoutType(layout, ValueLayout.class);
!         if (!isValidPrimitiveCarrier(carrier))
!             throw new IllegalArgumentException("Unsupported carrier: " + carrier);
!         if (Wrapper.forPrimitiveType(carrier).bitWidth() != layout.bitSize())
!             throw new IllegalArgumentException("Carrier size mismatch: " + carrier + " != " + layout);
      }
  
!     public static boolean isValidPrimitiveCarrier(Class<?> carrier) {
!         return carrier == byte.class
!             || carrier == short.class
!             || carrier == char.class
-             || carrier == int.class
-             || carrier == long.class
-             || carrier == float.class
-             || carrier == double.class;
      }
  
!     public static void checkLayoutType(MemoryLayout layout, Class<? extends MemoryLayout> layoutType) {
!         if (!layoutType.isInstance(layout))
!             throw new IllegalArgumentException("Expected a " + layoutType.getSimpleName() + ": " + layout);
      }
  }
--- 102,65 ---
          } else {
              throw exFactory.get();
          }
      }
  
!     public static VarHandle makeMemoryAccessVarHandle(Class<?> carrier, boolean skipAlignmentCheck, long alignmentMask, ByteOrder order) {
+         Class<?> baseCarrier = carrier;
+         if (carrier == MemoryAddress.class) {
+             baseCarrier = switch ((int) ValueLayout.ADDRESS.byteSize()) {
+                 case 8 -> long.class;
+                 case 4 -> int.class;
+                 default -> throw new UnsupportedOperationException("Unsupported address layout");
+             };
+         } else if (carrier == boolean.class) {
+             baseCarrier = byte.class;
+         }
+ 
+         VarHandle handle = SharedSecrets.getJavaLangInvokeAccess().memoryAccessVarHandle(baseCarrier, skipAlignmentCheck, alignmentMask, order);
+ 
          // This adaptation is required, otherwise the memory access var handle will have type MemorySegmentProxy,
          // and not MemorySegment (which the user expects), which causes performance issues with asType() adaptations.
!         handle = SHOULD_ADAPT_HANDLES
              ? MemoryHandles.filterCoordinates(handle, 0, SEGMENT_FILTER)
              : handle;
+         if (carrier == boolean.class) {
+             return MemoryHandles.filterValue(handle, BOOL_TO_BYTE, BYTE_TO_BOOL);
+         } else if (carrier == MemoryAddress.class) {
+             return MemoryHandles.filterValue(handle,
+                     MethodHandles.explicitCastArguments(ADDRESS_TO_LONG, MethodType.methodType(baseCarrier, MemoryAddress.class)),
+                     MethodHandles.explicitCastArguments(LONG_TO_ADDRESS, MethodType.methodType(MemoryAddress.class, baseCarrier)));
+         } else {
+             return handle;
+         }
      }
  
      private static MemorySegmentProxy filterSegment(MemorySegment segment) {
          return (AbstractMemorySegmentImpl)segment;
      }
  
!     private static boolean byteToBoolean(byte b) {
!         return b != 0;
!     }
! 
!     private static byte booleanToByte(boolean b) {
!         return b ? (byte)1 : (byte)0;
+     }
+ 
+     public static void copy(MemorySegment addr, byte[] bytes) {
+         var heapSegment = MemorySegment.ofArray(bytes);
+         addr.copyFrom(heapSegment);
+         addr.set(JAVA_BYTE, bytes.length, (byte)0);
      }
  
!     public static MemorySegment toCString(byte[] bytes, SegmentAllocator allocator) {
!         MemorySegment addr = allocator.allocate(bytes.length + 1, 1L);
!         copy(addr, bytes);
!         return addr;
      }
  
!     @ForceInline
!     public static long scaleOffset(MemorySegment segment, long index, long size) {
!         // note: we know size is a small value (as it comes from ValueLayout::byteSize())
+         return MemorySegmentProxy.multiplyOffsets(index, (int)size, (AbstractMemorySegmentImpl)segment);
      }
  }
< prev index next >