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 }
--- EOF ---