1 // Generated by jextract
  2 
  3 import jdk.incubator.foreign.Addressable;
  4 import jdk.incubator.foreign.CLinker;
  5 import jdk.incubator.foreign.FunctionDescriptor;
  6 import jdk.incubator.foreign.GroupLayout;
  7 import jdk.incubator.foreign.NativeSymbol;
  8 import jdk.incubator.foreign.SymbolLookup;
  9 import jdk.incubator.foreign.MemoryAddress;
 10 import jdk.incubator.foreign.MemoryLayout;
 11 import jdk.incubator.foreign.MemorySegment;
 12 import jdk.incubator.foreign.ResourceScope;
 13 import jdk.incubator.foreign.SegmentAllocator;
 14 import jdk.incubator.foreign.ValueLayout;
 15 import java.lang.invoke.MethodHandle;
 16 import java.lang.invoke.MethodHandles;
 17 import java.lang.invoke.MethodType;
 18 import java.io.File;
 19 import java.nio.file.Path;
 20 import java.nio.charset.StandardCharsets;
 21 import java.util.Arrays;
 22 import java.util.Optional;
 23 import java.util.stream.Stream;
 24 
 25 import static jdk.incubator.foreign.CLinker.*;
 26 import static jdk.incubator.foreign.ValueLayout.*;
 27 
 28 final class RuntimeHelper {
 29 
 30     private RuntimeHelper() {}
 31     private final static CLinker LINKER = CLinker.systemCLinker();
 32     private final static ClassLoader LOADER = RuntimeHelper.class.getClassLoader();
 33     private final static MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup();
 34     private final static SymbolLookup SYMBOL_LOOKUP;
 35 
 36     final static SegmentAllocator CONSTANT_ALLOCATOR =
 37             (size, align) -> MemorySegment.allocateNative(size, align, ResourceScope.newImplicitScope());
 38 
 39     static {
 40         #LOAD_LIBRARIES#
 41         SymbolLookup loaderLookup = SymbolLookup.loaderLookup();
 42         SYMBOL_LOOKUP = name -> loaderLookup.lookup(name).or(() -> LINKER.lookup(name));
 43     }
 44 
 45     static <T> T requireNonNull(T obj, String symbolName) {
 46         if (obj == null) {
 47             throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName);
 48         }
 49         return obj;
 50     }
 51 
 52     private final static SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); };
 53 
 54     static final MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) {
 55         return SYMBOL_LOOKUP.lookup(name).map(symbol -> MemorySegment.ofAddressNative(symbol.address(), layout.byteSize(), ResourceScope.newSharedScope())).orElse(null);
 56     }
 57 
 58     static final MethodHandle downcallHandle(String name, FunctionDescriptor fdesc, boolean variadic) {
 59         return SYMBOL_LOOKUP.lookup(name).map(
 60                 addr -> {
 61                     return variadic ?
 62                         VarargsInvoker.make(addr, fdesc) :
 63                         LINKER.downcallHandle(addr, fdesc);
 64                 }).orElse(null);
 65     }
 66 
 67     static final MethodHandle downcallHandle(FunctionDescriptor fdesc, boolean variadic) {
 68         if (variadic) {
 69             throw new AssertionError("Cannot get here!");
 70         }
 71         return LINKER.downcallHandle(fdesc);
 72     }
 73 
 74     static final <Z> NativeSymbol upcallStub(Class<Z> fi, Z z, FunctionDescriptor fdesc, String mtypeDesc, ResourceScope scope) {
 75         try {
 76             MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply",
 77                     MethodType.fromMethodDescriptorString(mtypeDesc, LOADER));
 78             handle = handle.bindTo(z);
 79             return LINKER.upcallStub(handle, fdesc, scope);
 80         } catch (Throwable ex) {
 81             throw new AssertionError(ex);
 82         }
 83     }
 84 
 85     static MemorySegment asArray(MemoryAddress addr, MemoryLayout layout, int numElements, ResourceScope scope) {
 86          return MemorySegment.ofAddressNative(addr, numElements * layout.byteSize(), scope);
 87     }
 88 
 89     // Internals only below this point
 90 
 91     private static class VarargsInvoker {
 92         private static final MethodHandle INVOKE_MH;
 93         private final NativeSymbol symbol;
 94         private final FunctionDescriptor function;
 95 
 96         private VarargsInvoker(NativeSymbol symbol, FunctionDescriptor function) {
 97             this.symbol = symbol;
 98             this.function = function;
 99         }
100 
101         static {
102             try {
103                 INVOKE_MH = MethodHandles.lookup().findVirtual(VarargsInvoker.class, "invoke", MethodType.methodType(Object.class, SegmentAllocator.class, Object[].class));
104             } catch (ReflectiveOperationException e) {
105                 throw new RuntimeException(e);
106             }
107         }
108 
109         static MethodHandle make(NativeSymbol symbol, FunctionDescriptor function) {
110             VarargsInvoker invoker = new VarargsInvoker(symbol, function);
111             MethodHandle handle = INVOKE_MH.bindTo(invoker).asCollector(Object[].class, function.argumentLayouts().size() + 1);
112             MethodType mtype = MethodType.methodType(function.returnLayout().isPresent() ? carrier(function.returnLayout().get(), true) : void.class);
113             for (MemoryLayout layout : function.argumentLayouts()) {
114                 mtype = mtype.appendParameterTypes(carrier(layout, false));
115             }
116             mtype = mtype.appendParameterTypes(Object[].class);
117             if (mtype.returnType().equals(MemorySegment.class)) {
118                 mtype = mtype.insertParameterTypes(0, SegmentAllocator.class);
119             } else {
120                 handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR);
121             }
122             return handle.asType(mtype);
123         }
124 
125         static Class<?> carrier(MemoryLayout layout, boolean ret) {
126             if (layout instanceof ValueLayout valueLayout) {
127                 return (ret || valueLayout.carrier() != MemoryAddress.class) ?
128                         valueLayout.carrier() : Addressable.class;
129             } else if (layout instanceof GroupLayout) {
130                 return MemorySegment.class;
131             } else {
132                 throw new AssertionError("Cannot get here!");
133             }
134         }
135 
136         private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwable {
137             // one trailing Object[]
138             int nNamedArgs = function.argumentLayouts().size();
139             assert(args.length == nNamedArgs + 1);
140             // The last argument is the array of vararg collector
141             Object[] unnamedArgs = (Object[]) args[args.length - 1];
142 
143             int argsCount = nNamedArgs + unnamedArgs.length;
144             Class<?>[] argTypes = new Class<?>[argsCount];
145             MemoryLayout[] argLayouts = new MemoryLayout[nNamedArgs + unnamedArgs.length];
146 
147             int pos = 0;
148             for (pos = 0; pos < nNamedArgs; pos++) {
149                 argLayouts[pos] = function.argumentLayouts().get(pos);
150             }
151 
152             assert pos == nNamedArgs;
153             for (Object o: unnamedArgs) {
154                 argLayouts[pos] = variadicLayout(normalize(o.getClass()));
155                 pos++;
156             }
157             assert pos == argsCount;
158 
159             FunctionDescriptor f = (function.returnLayout().isEmpty()) ?
160                     FunctionDescriptor.ofVoid(argLayouts) :
161                     FunctionDescriptor.of(function.returnLayout().get(), argLayouts);
162             MethodHandle mh = LINKER.downcallHandle(symbol, f);
163             if (mh.type().returnType() == MemorySegment.class) {
164                 mh = mh.bindTo(allocator);
165             }
166             // flatten argument list so that it can be passed to an asSpreader MH
167             Object[] allArgs = new Object[nNamedArgs + unnamedArgs.length];
168             System.arraycopy(args, 0, allArgs, 0, nNamedArgs);
169             System.arraycopy(unnamedArgs, 0, allArgs, nNamedArgs, unnamedArgs.length);
170 
171             return mh.asSpreader(Object[].class, argsCount).invoke(allArgs);
172         }
173 
174         private static Class<?> unboxIfNeeded(Class<?> clazz) {
175             if (clazz == Boolean.class) {
176                 return boolean.class;
177             } else if (clazz == Void.class) {
178                 return void.class;
179             } else if (clazz == Byte.class) {
180                 return byte.class;
181             } else if (clazz == Character.class) {
182                 return char.class;
183             } else if (clazz == Short.class) {
184                 return short.class;
185             } else if (clazz == Integer.class) {
186                 return int.class;
187             } else if (clazz == Long.class) {
188                 return long.class;
189             } else if (clazz == Float.class) {
190                 return float.class;
191             } else if (clazz == Double.class) {
192                 return double.class;
193             } else {
194                 return clazz;
195             }
196         }
197 
198         private Class<?> promote(Class<?> c) {
199             if (c == byte.class || c == char.class || c == short.class || c == int.class) {
200                 return long.class;
201             } else if (c == float.class) {
202                 return double.class;
203             } else {
204                 return c;
205             }
206         }
207 
208         private Class<?> normalize(Class<?> c) {
209             c = unboxIfNeeded(c);
210             if (c.isPrimitive()) {
211                 return promote(c);
212             }
213             if (MemoryAddress.class.isAssignableFrom(c)) {
214                 return MemoryAddress.class;
215             }
216             if (MemorySegment.class.isAssignableFrom(c)) {
217                 return MemorySegment.class;
218             }
219             throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName());
220         }
221 
222         private MemoryLayout variadicLayout(Class<?> c) {
223             if (c == long.class) {
224                 return JAVA_LONG;
225             } else if (c == double.class) {
226                 return JAVA_DOUBLE;
227             } else if (MemoryAddress.class.isAssignableFrom(c)) {
228                 return ADDRESS;
229             } else {
230                 throw new IllegalArgumentException("Unhandled variadic argument class: " + c);
231             }
232         }
233     }
234 }