1 /* 2 * Copyright (c) 2015, 2016, 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. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 package jdk.internal.nicl; 24 25 import jdk.internal.misc.Unsafe; 26 import jdk.internal.nicl.types.BoundedMemoryRegion; 27 import jdk.internal.nicl.types.BoundedPointer; 28 import jdk.internal.nicl.types.DescriptorParser; 29 import jdk.internal.nicl.types.Types; 30 import jdk.internal.org.objectweb.asm.Type; 31 32 import java.lang.annotation.Native; 33 import java.lang.invoke.MethodType; 34 import java.lang.reflect.*; 35 import java.nicl.NativeTypes; 36 import java.nicl.Scope; 37 import java.nicl.layout.Address; 38 import java.nicl.layout.Function; 39 import java.nicl.layout.Layout; 40 import java.nicl.layout.Sequence; 41 import java.nicl.metadata.C; 42 import java.nicl.metadata.CallingConvention; 43 import java.nicl.metadata.NativeType; 44 import java.nicl.types.*; 45 import java.nicl.types.Array; 46 import java.nio.Buffer; 47 import java.nio.ByteBuffer; 48 import java.util.Objects; 49 50 public final class Util { 51 52 public static final long BYTE_BUFFER_BASE; 53 public static final long BUFFER_ADDRESS; 54 55 static { 56 try { 57 Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe"); 58 unsafeField.setAccessible(true); 59 Unsafe UNSAFE = (Unsafe) unsafeField.get(null); 60 61 BYTE_BUFFER_BASE = UNSAFE.objectFieldOffset(ByteBuffer.class.getDeclaredField("hb")); 62 BUFFER_ADDRESS = UNSAFE.objectFieldOffset(Buffer.class.getDeclaredField("address")); 63 } 64 catch (Exception e) { 65 throw new InternalError(e); 66 } 67 } 68 69 private Util() { 70 } 71 72 public static Object getBufferBase(ByteBuffer bb) { 73 return UNSAFE.getObject(bb, BYTE_BUFFER_BASE); 74 } 75 76 public static long getBufferAddress(ByteBuffer bb) { 77 return UNSAFE.getLong(bb, BUFFER_ADDRESS); 78 } 79 80 public static long alignUp(long n, long alignment) { 81 return (n + alignment - 1) & ~(alignment - 1); 82 } 83 84 public static boolean isCStruct(Class<?> clz) { 85 if (!clz.isAnnotationPresent(C.class) || 86 !clz.isAnnotationPresent(NativeType.class)) { 87 return false; 88 } 89 NativeType nt = clz.getAnnotation(NativeType.class); 90 return nt.isRecordType(); 91 } 92 93 public static boolean isFunction(Class<?> clz) { 94 if (!isCStruct(clz)) { 95 return false; 96 } 97 98 return clz.isAnnotationPresent(CallingConvention.class); 99 } 100 101 public static Layout variadicLayout(Class<?> c) { 102 c = (Class<?>)unboxIfNeeded(c); 103 if (c.isPrimitive()) { 104 //it is ok to approximate with a machine word here; numerics arguments in a prototype-less 105 //function call are always rounded up to a register size anyway. 106 return Types.INT64; 107 } else if (Pointer.class.isAssignableFrom(c)) { 108 return Types.POINTER; 109 } else if (isFunctionalInterface(c)) { 110 return Types.POINTER; 111 } else if (isCStruct(c)) { 112 return layoutof(c); 113 } else { 114 throw new IllegalArgumentException("Unhandled variadic argument class: " + c); 115 } 116 } 117 118 public static Layout layoutof(Class<?> c) { 119 NativeType nt = c.getAnnotation(NativeType.class); 120 return new DescriptorParser(nt.layout()).parseLayout().findFirst().get(); 121 } 122 123 public static Function functionof(Method m) { 124 NativeType nt = m.getAnnotation(NativeType.class); 125 return (Function)new DescriptorParser(nt.layout()).parseDescriptorOrLayouts().findFirst().get(); 126 } 127 128 public static boolean isFunction(Method m) { 129 try { 130 functionof(m); 131 return true; 132 } catch (Throwable ex) { 133 return false; 134 } 135 } 136 137 static MethodType methodTypeFor(Method method) { 138 return MethodType.methodType(method.getReturnType(), method.getParameterTypes()); 139 } 140 141 public static boolean isFunctionalInterface(Class<?> c) { 142 return c.isAnnotationPresent(FunctionalInterface.class); 143 } 144 145 public static Method findFunctionalInterfaceMethod(Class<?> c) { 146 for (Method m : c.getMethods()) { 147 if (m.getName().equals("fn")) { 148 return m; 149 } 150 } 151 152 return null; 153 } 154 155 @SuppressWarnings({"unchecked", "rawtypes"}) 156 public static LayoutType<?> makeType(java.lang.reflect.Type carrier, Layout layout) { 157 carrier = unboxIfNeeded(carrier); 158 if (carrier == byte.class) { 159 return LayoutType.ofByte(layout); 160 } else if (carrier == boolean.class) { 161 return LayoutType.ofBoolean(layout); 162 } else if (carrier == short.class) { 163 return LayoutType.ofShort(layout); 164 } else if (carrier == int.class) { 165 return LayoutType.ofInt(layout); 166 } else if (carrier == char.class) { 167 return LayoutType.ofChar(layout); 168 } else if (carrier == long.class) { 169 return LayoutType.ofLong(layout); 170 } else if (carrier == float.class) { 171 return LayoutType.ofFloat(layout); 172 } else if (carrier == double.class) { 173 return LayoutType.ofDouble(layout); 174 } else if (carrier == Pointer.class) { //pointers 175 return NativeTypes.VOID.pointer(); 176 } else if (Pointer.class.isAssignableFrom(erasure(carrier))) { 177 if (carrier instanceof ParameterizedType) { 178 ParameterizedType pt = (ParameterizedType)carrier; 179 java.lang.reflect.Type arg = pt.getActualTypeArguments()[0]; 180 if (arg instanceof WildcardType) { 181 return NativeTypes.VOID.pointer(); 182 } 183 Address addr = (Address)layout; 184 return addr.addresseeInfo().isPresent() ? 185 makeType(arg, ((Address)layout).addresseeInfo().get().layout()).pointer() : 186 NativeTypes.VOID.pointer(); 187 } else { 188 return NativeTypes.VOID.pointer(); 189 } 190 } else if (Array.class.isAssignableFrom(erasure(carrier))) { 191 if (carrier instanceof ParameterizedType) { 192 ParameterizedType pt = (ParameterizedType)carrier; 193 java.lang.reflect.Type arg = pt.getActualTypeArguments()[0]; 194 if (arg instanceof WildcardType) { 195 return NativeTypes.VOID.array(); 196 } 197 return makeType(arg, ((Sequence)layout).element()).array(((Sequence)layout).elementsSize()); 198 } else { 199 return NativeTypes.VOID.array(); 200 } 201 } else if (Struct.class.isAssignableFrom(erasure(carrier))) { 202 return LayoutType.ofStruct((Class) carrier); 203 } else if (erasure(carrier).isArray()) { 204 //Todo: this provisional, Java arrays are not meant to be supported in this way 205 java.lang.reflect.Type element = (carrier instanceof GenericArrayType) ? 206 ((GenericArrayType)carrier).getGenericComponentType() : 207 erasure(carrier).getComponentType(); 208 return makeType(element, ((Sequence)layout).element()).array(((Sequence)layout).elementsSize()); 209 } else { 210 throw new IllegalStateException("Unknown carrier: " + carrier.getTypeName()); 211 } 212 } 213 214 static Class<?> erasure(java.lang.reflect.Type type) { 215 return (type instanceof ParameterizedType) ? 216 (Class<?>)((ParameterizedType)type).getRawType() : 217 (Class<?>)type; 218 } 219 220 public static java.lang.reflect.Type unboxIfNeeded(java.lang.reflect.Type clazz) { 221 if (clazz == Boolean.class) { 222 return boolean.class; 223 } else if (clazz == Byte.class) { 224 return byte.class; 225 } else if (clazz == Character.class) { 226 return char.class; 227 } else if (clazz == Short.class) { 228 return short.class; 229 } else if (clazz == Integer.class) { 230 return int.class; 231 } else if (clazz == Long.class) { 232 return long.class; 233 } else if (clazz == Float.class) { 234 return float.class; 235 } else if (clazz == Double.class) { 236 return double.class; 237 } else { 238 return clazz; 239 } 240 } 241 242 public static final LayoutType<Byte> BYTE_TYPE = NativeTypes.INT8; 243 public static final LayoutType<Pointer<Byte>> BYTE_PTR_TYPE = BYTE_TYPE.pointer(); 244 245 private static final Unsafe UNSAFE = Unsafe.getUnsafe(); 246 247 public static long strlen(long addr) { 248 long i = 0; 249 250 while (UNSAFE.getByte(addr + i) != 0) { 251 i++; 252 } 253 254 return i; 255 } 256 257 public static <T> Pointer<T> createPtr(long addr, LayoutType<T> type) { 258 return createPtr(null, addr, type); 259 } 260 261 public static <T> Pointer<T> createPtr(Object base, long addr, LayoutType<T> type) { 262 // FIXME: Long.MAX_VALUE is not correct 263 return new BoundedPointer<>(type, new BoundedMemoryRegion(base, addr, Long.MAX_VALUE), 0); 264 } 265 266 // Helper methods useful for playing with pointers into the Java heap and data copying 267 268 public static BoundedMemoryRegion createRegionForArrayElements(long[] arr) { 269 return new BoundedMemoryRegion(arr, UNSAFE.arrayBaseOffset(long[].class), arr.length * 8, BoundedMemoryRegion.MODE_RW); 270 } 271 272 public static BoundedMemoryRegion createRegionForArrayElements(byte[] arr) { 273 return new BoundedMemoryRegion(arr, UNSAFE.arrayBaseOffset(byte[].class), arr.length, BoundedMemoryRegion.MODE_RW); 274 } 275 276 public static BoundedMemoryRegion createRegionForArrayElements(long[] arr, Scope scope) { 277 return new BoundedMemoryRegion(arr, UNSAFE.arrayBaseOffset(long[].class), arr.length * 8, BoundedMemoryRegion.MODE_RW, scope); 278 } 279 280 public static Pointer<Long> createArrayElementsPointer(long[] arr) { 281 return new BoundedPointer<>(NativeTypes.INT64, createRegionForArrayElements(arr), 0); 282 } 283 284 public static Pointer<Byte> createArrayElementsPointer(byte[] arr) { 285 return new BoundedPointer<>(NativeTypes.INT8, createRegionForArrayElements(arr), 0); 286 } 287 288 public static Pointer<Long> createArrayElementsPointer(long[] arr, Scope scope) { 289 return new BoundedPointer<>(NativeTypes.INT64, createRegionForArrayElements(arr, scope), 0); 290 } 291 292 public static void copy(Pointer<?> src, Pointer<?> dst, long bytes) throws IllegalAccessException { 293 BoundedPointer<?> bsrc = (BoundedPointer<?>)Objects.requireNonNull(src); 294 BoundedPointer<?> bdst = (BoundedPointer<?>)Objects.requireNonNull(dst); 295 296 bsrc.copyTo(bdst, bytes); 297 } 298 }