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.CSupport; 30 import jdk.incubator.foreign.MemoryAddress; 31 import jdk.incubator.foreign.MemoryHandles; 32 import jdk.incubator.foreign.MemoryLayout; 33 import jdk.incubator.foreign.ForeignLinker; 34 import jdk.incubator.foreign.ValueLayout; 35 import jdk.internal.access.foreign.MemoryAddressProxy; 36 import jdk.internal.foreign.abi.SharedUtils; 37 import jdk.internal.misc.VM; 38 import sun.invoke.util.Wrapper; 39 40 import java.lang.invoke.MethodHandle; 41 import java.lang.invoke.MethodHandles; 42 import java.lang.invoke.MethodType; 43 import java.lang.invoke.VarHandle; 44 import java.util.Optional; 45 import java.util.function.Supplier; 46 47 /** 48 * This class contains misc helper functions to support creation of memory segments. 49 */ 50 public final class Utils { 51 52 private static final String foreignRestrictedAccess = Optional.ofNullable(VM.getSavedProperty("foreign.restricted")) 53 .orElse("deny"); 54 55 private static final MethodHandle ADDRESS_FILTER; 56 57 static { 58 try { 59 ADDRESS_FILTER = MethodHandles.lookup().findStatic(Utils.class, "filterAddress", 60 MethodType.methodType(MemoryAddressProxy.class, MemoryAddress.class)); 61 } catch (Throwable ex) { 62 throw new ExceptionInInitializerError(ex); 63 } 64 } 65 66 public static long alignUp(long n, long alignment) { 67 return (n + alignment - 1) & -alignment; 68 } 69 70 public static MemoryAddress alignUp(MemoryAddress ma, long alignment) { 71 long offset = ma.toRawLongValue(); 72 return ma.addOffset(alignUp(offset, alignment) - offset); 73 } 74 75 public static long bitsToBytesOrThrow(long bits, Supplier<RuntimeException> exFactory) { 76 if (bits % 8 == 0) { 77 return bits / 8; 78 } else { 79 throw exFactory.get(); 80 } 81 } 82 83 public static VarHandle fixUpVarHandle(VarHandle handle) { 84 // This adaptation is required, otherwise the memory access var handle will have type MemoryAddressProxy, 85 // and not MemoryAddress (which the user expects), which causes performance issues with asType() adaptations. 86 return MemoryHandles.filterCoordinates(handle, 0, ADDRESS_FILTER); 87 } 88 89 private static MemoryAddressProxy filterAddress(MemoryAddress addr) { 90 return (MemoryAddressImpl)addr; 91 } 92 93 public static void checkRestrictedAccess(String method) { 94 switch (foreignRestrictedAccess) { 95 case "deny" -> throwIllegalAccessError(foreignRestrictedAccess, method); 96 case "warn" -> System.err.println("WARNING: Accessing restricted foreign method: " + method); 97 case "debug" -> { 98 StringBuilder sb = new StringBuilder("DEBUG: restricted foreign method: \" + method"); 99 StackWalker.getInstance().forEach(f -> sb.append(System.lineSeparator()) 100 .append("\tat ") 101 .append(f)); 102 System.err.println(sb.toString()); 103 } 104 case "permit" -> {} 105 default -> throwIllegalAccessError(foreignRestrictedAccess, method); 106 } 107 } 108 109 private static void throwIllegalAccessError(String value, String method) { 110 throw new IllegalAccessError("Illegal access to restricted foreign method: " + method + 111 " ; system property 'foreign.restricted' is set to '" + value + "'"); 112 } 113 114 public static <Z extends MemoryLayout> Z pick(Z sysv, Z win64, Z aarch64) { 115 ForeignLinker abi = SharedUtils.getSystemLinker(); 116 return switch (abi.name()) { 117 case CSupport.SysV.NAME -> sysv; 118 case CSupport.Win64.NAME -> win64; 119 case CSupport.AArch64.NAME -> aarch64; 120 default -> throw new ExceptionInInitializerError("Unexpected ABI: " + abi.name()); 121 }; 122 } 123 124 public static void checkPrimitiveCarrierCompat(Class<?> carrier, MemoryLayout layout) { 125 checkLayoutType(layout, ValueLayout.class); 126 if (!isValidPrimitiveCarrier(carrier)) 127 throw new IllegalArgumentException("Unsupported carrier: " + carrier); 128 if (Wrapper.forPrimitiveType(carrier).bitWidth() != layout.bitSize()) 129 throw new IllegalArgumentException("Carrier size mismatch: " + carrier + " != " + layout); 130 } 131 132 public static boolean isValidPrimitiveCarrier(Class<?> carrier) { 133 return carrier == byte.class 134 || carrier == short.class 135 || carrier == char.class 136 || carrier == int.class 137 || carrier == long.class 138 || carrier == float.class 139 || carrier == double.class; 140 } 141 142 public static void checkLayoutType(MemoryLayout layout, Class<? extends MemoryLayout> layoutType) { 143 if (!layoutType.isInstance(layout)) 144 throw new IllegalArgumentException("Expected a " + layoutType.getSimpleName() + ": " + layout); 145 } 146 }