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 }