< prev index next >

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

Print this page

 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 
 27 package jdk.internal.foreign;
 28 
 29 import jdk.incubator.foreign.*;

 30 import jdk.internal.access.foreign.MemorySegmentProxy;
 31 import jdk.internal.misc.VM;
 32 import sun.invoke.util.Wrapper;
 33 
 34 import java.lang.invoke.MethodHandle;
 35 import java.lang.invoke.MethodHandles;
 36 import java.lang.invoke.MethodType;
 37 import java.lang.invoke.VarHandle;
 38 import java.util.Optional;
 39 import java.util.function.Supplier;
 40 

 41 import static sun.security.action.GetPropertyAction.*;
 42 
 43 /**
 44  * This class contains misc helper functions to support creation of memory segments.
 45  */
 46 public final class Utils {
 47     // used when testing invoke exact behavior of memory access handles
 48     private static final boolean SHOULD_ADAPT_HANDLES
 49         = Boolean.parseBoolean(privilegedGetProperty("jdk.internal.foreign.SHOULD_ADAPT_HANDLES", "true"));
 50 
 51     private static final MethodHandle SEGMENT_FILTER;




 52     public static final MethodHandle MH_bitsToBytesOrThrowForOffset;
 53 
 54     public static final Supplier<RuntimeException> bitsToBytesThrowOffset
 55         = () -> new UnsupportedOperationException("Cannot compute byte offset; bit offset is not a multiple of 8");
 56 
 57     static {
 58         try {
 59             MethodHandles.Lookup lookup = MethodHandles.lookup();
 60             SEGMENT_FILTER = lookup.findStatic(Utils.class, "filterSegment",
 61                     MethodType.methodType(MemorySegmentProxy.class, MemorySegment.class));








 62             MH_bitsToBytesOrThrowForOffset = MethodHandles.insertArguments(
 63                 lookup.findStatic(Utils.class, "bitsToBytesOrThrow",
 64                     MethodType.methodType(long.class, long.class, Supplier.class)),
 65                 1,
 66                 bitsToBytesThrowOffset);
 67         } catch (Throwable ex) {
 68             throw new ExceptionInInitializerError(ex);
 69         }
 70     }
 71 
 72     public static long alignUp(long n, long alignment) {
 73         return (n + alignment - 1) & -alignment;
 74     }
 75 
 76     public static MemoryAddress alignUp(MemoryAddress ma, long alignment) {
 77         long offset = ma.toRawLongValue();
 78         return ma.addOffset(alignUp(offset, alignment) - offset);
 79     }
 80 
 81     public static MemorySegment alignUp(MemorySegment ms, long alignment) {
 82         long offset = ms.address().toRawLongValue();
 83         return ms.asSlice(alignUp(offset, alignment) - offset);
 84     }
 85 
 86     public static long bitsToBytesOrThrow(long bits, Supplier<RuntimeException> exFactory) {
 87         if (bits % 8 == 0) {
 88             return bits / 8;
 89         } else {
 90             throw exFactory.get();
 91         }
 92     }
 93 
 94     public static VarHandle fixUpVarHandle(VarHandle handle) {













 95         // This adaptation is required, otherwise the memory access var handle will have type MemorySegmentProxy,
 96         // and not MemorySegment (which the user expects), which causes performance issues with asType() adaptations.
 97         return SHOULD_ADAPT_HANDLES
 98             ? MemoryHandles.filterCoordinates(handle, 0, SEGMENT_FILTER)
 99             : handle;









100     }
101 
102     private static MemorySegmentProxy filterSegment(MemorySegment segment) {
103         return (AbstractMemorySegmentImpl)segment;
104     }
105 
106     public static void checkPrimitiveCarrierCompat(Class<?> carrier, MemoryLayout layout) {
107         checkLayoutType(layout, ValueLayout.class);
108         if (!isValidPrimitiveCarrier(carrier))
109             throw new IllegalArgumentException("Unsupported carrier: " + carrier);
110         if (Wrapper.forPrimitiveType(carrier).bitWidth() != layout.bitSize())
111             throw new IllegalArgumentException("Carrier size mismatch: " + carrier + " != " + layout);






112     }
113 
114     public static boolean isValidPrimitiveCarrier(Class<?> carrier) {
115         return carrier == byte.class
116             || carrier == short.class
117             || carrier == char.class
118             || carrier == int.class
119             || carrier == long.class
120             || carrier == float.class
121             || carrier == double.class;
122     }
123 
124     public static void checkLayoutType(MemoryLayout layout, Class<? extends MemoryLayout> layoutType) {
125         if (!layoutType.isInstance(layout))
126             throw new IllegalArgumentException("Expected a " + layoutType.getSimpleName() + ": " + layout);

127     }
128 }

 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 
 27 package jdk.internal.foreign;
 28 
 29 import jdk.incubator.foreign.*;
 30 import jdk.internal.access.SharedSecrets;
 31 import jdk.internal.access.foreign.MemorySegmentProxy;
 32 import jdk.internal.vm.annotation.ForceInline;

 33 
 34 import java.lang.invoke.MethodHandle;
 35 import java.lang.invoke.MethodHandles;
 36 import java.lang.invoke.MethodType;
 37 import java.lang.invoke.VarHandle;
 38 import java.nio.ByteOrder;
 39 import java.util.function.Supplier;
 40 
 41 import static jdk.incubator.foreign.ValueLayout.JAVA_BYTE;
 42 import static sun.security.action.GetPropertyAction.*;
 43 
 44 /**
 45  * This class contains misc helper functions to support creation of memory segments.
 46  */
 47 public final class Utils {
 48     // used when testing invoke exact behavior of memory access handles
 49     private static final boolean SHOULD_ADAPT_HANDLES
 50         = Boolean.parseBoolean(privilegedGetProperty("jdk.internal.foreign.SHOULD_ADAPT_HANDLES", "true"));
 51 
 52     private static final MethodHandle SEGMENT_FILTER;
 53     private static final MethodHandle BYTE_TO_BOOL;
 54     private static final MethodHandle BOOL_TO_BYTE;
 55     private static final MethodHandle ADDRESS_TO_LONG;
 56     private static final MethodHandle LONG_TO_ADDRESS;
 57     public static final MethodHandle MH_bitsToBytesOrThrowForOffset;
 58 
 59     public static final Supplier<RuntimeException> bitsToBytesThrowOffset
 60         = () -> new UnsupportedOperationException("Cannot compute byte offset; bit offset is not a multiple of 8");
 61 
 62     static {
 63         try {
 64             MethodHandles.Lookup lookup = MethodHandles.lookup();
 65             SEGMENT_FILTER = lookup.findStatic(Utils.class, "filterSegment",
 66                     MethodType.methodType(MemorySegmentProxy.class, MemorySegment.class));
 67             BYTE_TO_BOOL = lookup.findStatic(Utils.class, "byteToBoolean",
 68                     MethodType.methodType(boolean.class, byte.class));
 69             BOOL_TO_BYTE = lookup.findStatic(Utils.class, "booleanToByte",
 70                     MethodType.methodType(byte.class, boolean.class));
 71             ADDRESS_TO_LONG = lookup.findVirtual(MemoryAddress.class, "toRawLongValue",
 72                     MethodType.methodType(long.class));
 73             LONG_TO_ADDRESS = lookup.findStatic(MemoryAddress.class, "ofLong",
 74                     MethodType.methodType(MemoryAddress.class, long.class));
 75             MH_bitsToBytesOrThrowForOffset = MethodHandles.insertArguments(
 76                 lookup.findStatic(Utils.class, "bitsToBytesOrThrow",
 77                     MethodType.methodType(long.class, long.class, Supplier.class)),
 78                 1,
 79                 bitsToBytesThrowOffset);
 80         } catch (Throwable ex) {
 81             throw new ExceptionInInitializerError(ex);
 82         }
 83     }
 84 
 85     public static long alignUp(long n, long alignment) {
 86         return (n + alignment - 1) & -alignment;
 87     }
 88 
 89     public static MemoryAddress alignUp(MemoryAddress ma, long alignment) {
 90         long offset = ma.toRawLongValue();
 91         return ma.addOffset(alignUp(offset, alignment) - offset);
 92     }
 93 
 94     public static MemorySegment alignUp(MemorySegment ms, long alignment) {
 95         long offset = ms.address().toRawLongValue();
 96         return ms.asSlice(alignUp(offset, alignment) - offset);
 97     }
 98 
 99     public static long bitsToBytesOrThrow(long bits, Supplier<RuntimeException> exFactory) {
100         if (bits % 8 == 0) {
101             return bits / 8;
102         } else {
103             throw exFactory.get();
104         }
105     }
106 
107     public static VarHandle makeMemoryAccessVarHandle(Class<?> carrier, boolean skipAlignmentCheck, long alignmentMask, ByteOrder order) {
108         Class<?> baseCarrier = carrier;
109         if (carrier == MemoryAddress.class) {
110             baseCarrier = switch ((int) ValueLayout.ADDRESS.byteSize()) {
111                 case 8 -> long.class;
112                 case 4 -> int.class;
113                 default -> throw new UnsupportedOperationException("Unsupported address layout");
114             };
115         } else if (carrier == boolean.class) {
116             baseCarrier = byte.class;
117         }
118 
119         VarHandle handle = SharedSecrets.getJavaLangInvokeAccess().memoryAccessVarHandle(baseCarrier, skipAlignmentCheck, alignmentMask, order);
120 
121         // This adaptation is required, otherwise the memory access var handle will have type MemorySegmentProxy,
122         // and not MemorySegment (which the user expects), which causes performance issues with asType() adaptations.
123         handle = SHOULD_ADAPT_HANDLES
124             ? MemoryHandles.filterCoordinates(handle, 0, SEGMENT_FILTER)
125             : handle;
126         if (carrier == boolean.class) {
127             return MemoryHandles.filterValue(handle, BOOL_TO_BYTE, BYTE_TO_BOOL);
128         } else if (carrier == MemoryAddress.class) {
129             return MemoryHandles.filterValue(handle,
130                     MethodHandles.explicitCastArguments(ADDRESS_TO_LONG, MethodType.methodType(baseCarrier, MemoryAddress.class)),
131                     MethodHandles.explicitCastArguments(LONG_TO_ADDRESS, MethodType.methodType(MemoryAddress.class, baseCarrier)));
132         } else {
133             return handle;
134         }
135     }
136 
137     private static MemorySegmentProxy filterSegment(MemorySegment segment) {
138         return (AbstractMemorySegmentImpl)segment;
139     }
140 
141     private static boolean byteToBoolean(byte b) {
142         return b != 0;
143     }
144 
145     private static byte booleanToByte(boolean b) {
146         return b ? (byte)1 : (byte)0;
147     }
148 
149     public static void copy(MemorySegment addr, byte[] bytes) {
150         var heapSegment = MemorySegment.ofArray(bytes);
151         addr.copyFrom(heapSegment);
152         addr.set(JAVA_BYTE, bytes.length, (byte)0);
153     }
154 
155     public static MemorySegment toCString(byte[] bytes, SegmentAllocator allocator) {
156         MemorySegment addr = allocator.allocate(bytes.length + 1, 1L);
157         copy(addr, bytes);
158         return addr;




159     }
160 
161     @ForceInline
162     public static long scaleOffset(MemorySegment segment, long index, long size) {
163         // note: we know size is a small value (as it comes from ValueLayout::byteSize())
164         return MemorySegmentProxy.multiplyOffsets(index, (int)size, (AbstractMemorySegmentImpl)segment);
165     }
166 }
< prev index next >