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.NativeCallback; 42 import java.nicl.metadata.NativeLocation; 43 import java.nicl.metadata.NativeStruct; 44 import java.nicl.metadata.NativeType; 45 import java.nicl.types.*; 46 import java.nicl.types.Array; 47 import java.nio.Buffer; 48 import java.nio.ByteBuffer; 49 import java.util.Objects; 50 51 public final class Util { 52 53 public static final long BYTE_BUFFER_BASE; 54 public static final long BUFFER_ADDRESS; 55 56 static { 57 try { 58 Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe"); 59 unsafeField.setAccessible(true); 60 Unsafe UNSAFE = (Unsafe) unsafeField.get(null); 61 62 BYTE_BUFFER_BASE = UNSAFE.objectFieldOffset(ByteBuffer.class.getDeclaredField("hb")); 63 BUFFER_ADDRESS = UNSAFE.objectFieldOffset(Buffer.class.getDeclaredField("address")); 64 } 65 catch (Exception e) { 66 throw new InternalError(e); 67 } 68 } 69 70 private Util() { 71 } 72 73 public static Object getBufferBase(ByteBuffer bb) { 74 return UNSAFE.getObject(bb, BYTE_BUFFER_BASE); 75 } 76 77 public static long getBufferAddress(ByteBuffer bb) { 78 return UNSAFE.getLong(bb, BUFFER_ADDRESS); 79 } 80 81 public static long alignUp(long n, long alignment) { 82 return (n + alignment - 1) & ~(alignment - 1); 83 } 84 85 public static boolean isCStruct(Class<?> clz) { 86 return clz.isAnnotationPresent(NativeStruct.class); 87 } 88 89 public static Layout variadicLayout(Class<?> c) { 90 c = (Class<?>)unboxIfNeeded(c); 91 if (c.isPrimitive()) { 92 //it is ok to approximate with a machine word here; numerics arguments in a prototype-less 93 //function call are always rounded up to a register size anyway. 94 return Types.INT64; 95 } else if (Pointer.class.isAssignableFrom(c)) { 96 return Types.POINTER; 97 } else if (isFunctionalInterface(c)) { 98 return Types.POINTER; 99 } else if (isCStruct(c)) { 100 return layoutof(c); 101 } else { 102 throw new IllegalArgumentException("Unhandled variadic argument class: " + c); 103 } 104 } 105 106 public static Layout layoutof(Class<?> c) { 107 String layout; 108 if (c.isAnnotationPresent(NativeStruct.class)) { 109 layout = c.getAnnotation(NativeStruct.class).value(); 110 } else if (c.isAnnotationPresent(NativeType.class)) { 111 layout = c.getAnnotation(NativeType.class).layout(); 112 } else { 113 throw new IllegalArgumentException("@NativeStruct or @NativeType expected: " + c); 114 } 115 return new DescriptorParser(layout).parseLayout().findFirst().get(); 116 } 117 118 public static Function functionof(Class<?> c) { 119 if (! c.isAnnotationPresent(NativeCallback.class)) { 120 throw new IllegalArgumentException("@NativeCallback expected: " + c); 121 } 122 NativeCallback nc = c.getAnnotation(NativeCallback.class); 123 return (Function)new DescriptorParser(nc.value()).parseDescriptorOrLayouts().findFirst().get(); 124 } 125 126 public static Function functionof(Method m) { 127 if (! m.isAnnotationPresent(NativeType.class)) { 128 throw new IllegalArgumentException("@NativeType expected: " + m); 129 } 130 NativeType nt = m.getAnnotation(NativeType.class); 131 return (Function)new DescriptorParser(nt.layout()).parseDescriptorOrLayouts().findFirst().get(); 132 } 133 134 public static boolean isFunction(Method m) { 135 try { 136 functionof(m); 137 return true; 138 } catch (Throwable ex) { 139 return false; 140 } 141 } 142 143 static MethodType methodTypeFor(Method method) { 144 return MethodType.methodType(method.getReturnType(), method.getParameterTypes()); 145 } 146 147 public static boolean isFunctionalInterface(Class<?> c) { 148 return c.isAnnotationPresent(FunctionalInterface.class); 149 } 150 151 public static Method findFunctionalInterfaceMethod(Class<?> c) { 152 for (Method m : c.getMethods()) { 153 if (m.getName().equals("fn")) { 154 return m; 155 } 156 } 157 158 return null; 159 } 160 161 @SuppressWarnings({"unchecked", "rawtypes"}) 162 public static LayoutType<?> makeType(java.lang.reflect.Type carrier, Layout layout) { 163 carrier = unboxIfNeeded(carrier); 164 if (carrier == byte.class) { 165 return LayoutType.ofByte(layout); 166 } else if (carrier == boolean.class) { 167 return LayoutType.ofBoolean(layout); 168 } else if (carrier == short.class) { 169 return LayoutType.ofShort(layout); 170 } else if (carrier == int.class) { 171 return LayoutType.ofInt(layout); 172 } else if (carrier == char.class) { 173 return LayoutType.ofChar(layout); 174 } else if (carrier == long.class) { 175 return LayoutType.ofLong(layout); 176 } else if (carrier == float.class) { 177 return LayoutType.ofFloat(layout); 178 } else if (carrier == double.class) { 179 return LayoutType.ofDouble(layout); 180 } else if (carrier == Pointer.class) { //pointers 181 return NativeTypes.VOID.pointer(); 182 } else if (Pointer.class.isAssignableFrom(erasure(carrier))) { 183 if (carrier instanceof ParameterizedType) { 184 ParameterizedType pt = (ParameterizedType)carrier; 185 java.lang.reflect.Type arg = pt.getActualTypeArguments()[0]; 186 if (arg instanceof WildcardType) { 187 return NativeTypes.VOID.pointer(); 188 } 189 Address addr = (Address)layout; 190 return addr.addresseeInfo().isPresent() ? 191 makeType(arg, ((Address)layout).addresseeInfo().get().layout()).pointer() : 192 NativeTypes.VOID.pointer(); 193 } else { 194 return NativeTypes.VOID.pointer(); 195 } 196 } else if (Array.class.isAssignableFrom(erasure(carrier))) { 197 if (carrier instanceof ParameterizedType) { 198 ParameterizedType pt = (ParameterizedType)carrier; 199 java.lang.reflect.Type arg = pt.getActualTypeArguments()[0]; 200 if (arg instanceof WildcardType) { 201 return NativeTypes.VOID.array(); 202 } 203 return makeType(arg, ((Sequence)layout).element()).array(((Sequence)layout).elementsSize()); 204 } else { 205 return NativeTypes.VOID.array(); 206 } 207 } else if (Struct.class.isAssignableFrom(erasure(carrier))) { 208 return LayoutType.ofStruct((Class) carrier); 209 } else if (erasure(carrier).isArray()) { 210 //Todo: this provisional, Java arrays are not meant to be supported in this way 211 java.lang.reflect.Type element = (carrier instanceof GenericArrayType) ? 212 ((GenericArrayType)carrier).getGenericComponentType() : 213 erasure(carrier).getComponentType(); 214 return makeType(element, ((Sequence)layout).element()).array(((Sequence)layout).elementsSize()); 215 } else { 216 throw new IllegalStateException("Unknown carrier: " + carrier.getTypeName()); 217 } 218 } 219 220 static Class<?> erasure(java.lang.reflect.Type type) { 221 return (type instanceof ParameterizedType) ? 222 (Class<?>)((ParameterizedType)type).getRawType() : 223 (Class<?>)type; 224 } 225 226 public static java.lang.reflect.Type unboxIfNeeded(java.lang.reflect.Type clazz) { 227 if (clazz == Boolean.class) { 228 return boolean.class; 229 } else if (clazz == Byte.class) { 230 return byte.class; 231 } else if (clazz == Character.class) { 232 return char.class; 233 } else if (clazz == Short.class) { 234 return short.class; 235 } else if (clazz == Integer.class) { 236 return int.class; 237 } else if (clazz == Long.class) { 238 return long.class; 239 } else if (clazz == Float.class) { 240 return float.class; 241 } else if (clazz == Double.class) { 242 return double.class; 243 } else { 244 return clazz; 245 } 246 } 247 248 public static final LayoutType<Byte> BYTE_TYPE = NativeTypes.INT8; 249 public static final LayoutType<Pointer<Byte>> BYTE_PTR_TYPE = BYTE_TYPE.pointer(); 250 251 private static final Unsafe UNSAFE = Unsafe.getUnsafe(); 252 253 public static long strlen(long addr) { 254 long i = 0; 255 256 while (UNSAFE.getByte(addr + i) != 0) { 257 i++; 258 } 259 260 return i; 261 } 262 263 public static <T> Pointer<T> createPtr(long addr, LayoutType<T> type) { 264 return createPtr(null, addr, type); 265 } 266 267 public static <T> Pointer<T> createPtr(Object base, long addr, LayoutType<T> type) { 268 // FIXME: Long.MAX_VALUE is not correct 269 return new BoundedPointer<>(type, new BoundedMemoryRegion(base, addr, Long.MAX_VALUE), 0); 270 } 271 272 // Helper methods useful for playing with pointers into the Java heap and data copying 273 274 public static BoundedMemoryRegion createRegionForArrayElements(long[] arr) { 275 return new BoundedMemoryRegion(arr, UNSAFE.arrayBaseOffset(long[].class), arr.length * 8, BoundedMemoryRegion.MODE_RW); 276 } 277 278 public static BoundedMemoryRegion createRegionForArrayElements(byte[] arr) { 279 return new BoundedMemoryRegion(arr, UNSAFE.arrayBaseOffset(byte[].class), arr.length, BoundedMemoryRegion.MODE_RW); 280 } 281 282 public static BoundedMemoryRegion createRegionForArrayElements(long[] arr, Scope scope) { 283 return new BoundedMemoryRegion(arr, UNSAFE.arrayBaseOffset(long[].class), arr.length * 8, BoundedMemoryRegion.MODE_RW, scope); 284 } 285 286 public static Pointer<Long> createArrayElementsPointer(long[] arr) { 287 return new BoundedPointer<>(NativeTypes.INT64, createRegionForArrayElements(arr), 0); 288 } 289 290 public static Pointer<Byte> createArrayElementsPointer(byte[] arr) { 291 return new BoundedPointer<>(NativeTypes.INT8, createRegionForArrayElements(arr), 0); 292 } 293 294 public static Pointer<Long> createArrayElementsPointer(long[] arr, Scope scope) { 295 return new BoundedPointer<>(NativeTypes.INT64, createRegionForArrayElements(arr, scope), 0); 296 } 297 298 public static void copy(Pointer<?> src, Pointer<?> dst, long bytes) throws IllegalAccessException { 299 BoundedPointer<?> bsrc = (BoundedPointer<?>)Objects.requireNonNull(src); 300 BoundedPointer<?> bdst = (BoundedPointer<?>)Objects.requireNonNull(dst); 301 302 bsrc.copyTo(bdst, bytes); 303 } 304 }