1 /*
  2  *  Copyright (c) 2019, 2020, 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 
 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 }