1 /*
  2  *  Copyright (c) 2021, 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.  Oracle designates this
  8  *  particular file as subject to the "Classpath" exception as provided
  9  *  by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  *  This code is distributed in the hope that it will be useful, but WITHOUT
 12  *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  *  version 2 for more details (a copy is included in the LICENSE file that
 15  *  accompanied this code).
 16  *
 17  *  You should have received a copy of the GNU General Public License version
 18  *  2 along with this work; if not, write to the Free Software Foundation,
 19  *  Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  *   Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  *  or visit www.oracle.com if you need additional information or have any
 23  *  questions.
 24  */
 25 
 26 package jdk.internal.clang.libclang;
 27 // Generated by jextract
 28 
 29 import jdk.incubator.foreign.Addressable;
 30 import jdk.incubator.foreign.CLinker;
 31 import jdk.incubator.foreign.FunctionDescriptor;
 32 import jdk.incubator.foreign.GroupLayout;
 33 import jdk.incubator.foreign.NativeSymbol;
 34 import jdk.incubator.foreign.SymbolLookup;
 35 import jdk.incubator.foreign.MemoryAddress;
 36 import jdk.incubator.foreign.MemoryLayout;
 37 import jdk.incubator.foreign.MemorySegment;
 38 import jdk.incubator.foreign.ResourceScope;
 39 import jdk.incubator.foreign.SegmentAllocator;
 40 import jdk.incubator.foreign.ValueLayout;
 41 import java.lang.invoke.MethodHandle;
 42 import java.lang.invoke.MethodHandles;
 43 import java.lang.invoke.MethodType;
 44 import java.io.File;
 45 import java.nio.file.Path;
 46 import java.nio.charset.StandardCharsets;
 47 import java.util.Arrays;
 48 import java.util.Optional;
 49 import java.util.stream.Stream;
 50 
 51 import static jdk.incubator.foreign.CLinker.*;
 52 import static jdk.incubator.foreign.ValueLayout.*;
 53 
 54 final class RuntimeHelper {
 55 
 56     private RuntimeHelper() {}
 57     private final static CLinker LINKER = CLinker.systemCLinker();
 58     private final static ClassLoader LOADER = RuntimeHelper.class.getClassLoader();
 59     private final static MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup();
 60     private final static SymbolLookup SYMBOL_LOOKUP;
 61 
 62     final static SegmentAllocator CONSTANT_ALLOCATOR =
 63             (size, align) -> MemorySegment.allocateNative(size, align, ResourceScope.newImplicitScope());
 64 
 65     static {
 66         // Manual change to handle platform specific library name difference
 67         String libName = System.getProperty("os.name").startsWith("Windows")? "libclang" : "clang";
 68         System.loadLibrary(libName);
 69 
 70         SymbolLookup loaderLookup = SymbolLookup.loaderLookup();
 71         SYMBOL_LOOKUP = name -> loaderLookup.lookup(name).or(() -> LINKER.lookup(name));
 72     }
 73 
 74     static <T> T requireNonNull(T obj, String symbolName) {
 75         if (obj == null) {
 76             throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName);
 77         }
 78         return obj;
 79     }
 80 
 81     private final static SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); };
 82 
 83     static final MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) {
 84         return SYMBOL_LOOKUP.lookup(name).map(symbol -> MemorySegment.ofAddressNative(symbol.address(), layout.byteSize(), ResourceScope.newSharedScope())).orElse(null);
 85     }
 86 
 87     static final MethodHandle downcallHandle(String name, FunctionDescriptor fdesc, boolean variadic) {
 88         return SYMBOL_LOOKUP.lookup(name).map(
 89                 addr -> {
 90                     return variadic ?
 91                         VarargsInvoker.make(addr, fdesc) :
 92                         LINKER.downcallHandle(addr, fdesc);
 93                 }).orElse(null);
 94     }
 95 
 96     static final MethodHandle downcallHandle(FunctionDescriptor fdesc, boolean variadic) {
 97         if (variadic) {
 98             throw new AssertionError("Cannot get here!");
 99         }
100         return LINKER.downcallHandle(fdesc);
101     }
102 
103     static final <Z> NativeSymbol upcallStub(Class<Z> fi, Z z, FunctionDescriptor fdesc, String mtypeDesc, ResourceScope scope) {
104         try {
105             MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply",
106                     MethodType.fromMethodDescriptorString(mtypeDesc, LOADER));
107             handle = handle.bindTo(z);
108             return LINKER.upcallStub(handle, fdesc, scope);
109         } catch (Throwable ex) {
110             throw new AssertionError(ex);
111         }
112     }
113 
114     static MemorySegment asArray(MemoryAddress addr, MemoryLayout layout, int numElements, ResourceScope scope) {
115          return MemorySegment.ofAddressNative(addr, numElements * layout.byteSize(), scope);
116     }
117 
118     // Internals only below this point
119 
120     private static class VarargsInvoker {
121         private static final MethodHandle INVOKE_MH;
122         private final NativeSymbol symbol;
123         private final FunctionDescriptor function;
124 
125         private VarargsInvoker(NativeSymbol symbol, FunctionDescriptor function) {
126             this.symbol = symbol;
127             this.function = function;
128         }
129 
130         static {
131             try {
132                 INVOKE_MH = MethodHandles.lookup().findVirtual(VarargsInvoker.class, "invoke", MethodType.methodType(Object.class, SegmentAllocator.class, Object[].class));
133             } catch (ReflectiveOperationException e) {
134                 throw new RuntimeException(e);
135             }
136         }
137 
138         static MethodHandle make(NativeSymbol symbol, FunctionDescriptor function) {
139             VarargsInvoker invoker = new VarargsInvoker(symbol, function);
140             MethodHandle handle = INVOKE_MH.bindTo(invoker).asCollector(Object[].class, function.argumentLayouts().size() + 1);
141             MethodType mtype = MethodType.methodType(function.returnLayout().isPresent() ? carrier(function.returnLayout().get(), true) : void.class);
142             for (MemoryLayout layout : function.argumentLayouts()) {
143                 mtype = mtype.appendParameterTypes(carrier(layout, false));
144             }
145             mtype = mtype.appendParameterTypes(Object[].class);
146             if (mtype.returnType().equals(MemorySegment.class)) {
147                 mtype = mtype.insertParameterTypes(0, SegmentAllocator.class);
148             } else {
149                 handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR);
150             }
151             return handle.asType(mtype);
152         }
153 
154         static Class<?> carrier(MemoryLayout layout, boolean ret) {
155             if (layout instanceof ValueLayout valueLayout) {
156                 return (ret || valueLayout.carrier() != MemoryAddress.class) ?
157                         valueLayout.carrier() : Addressable.class;
158             } else if (layout instanceof GroupLayout) {
159                 return MemorySegment.class;
160             } else {
161                 throw new AssertionError("Cannot get here!");
162             }
163         }
164 
165         private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwable {
166             // one trailing Object[]
167             int nNamedArgs = function.argumentLayouts().size();
168             assert(args.length == nNamedArgs + 1);
169             // The last argument is the array of vararg collector
170             Object[] unnamedArgs = (Object[]) args[args.length - 1];
171 
172             int argsCount = nNamedArgs + unnamedArgs.length;
173             Class<?>[] argTypes = new Class<?>[argsCount];
174             MemoryLayout[] argLayouts = new MemoryLayout[nNamedArgs + unnamedArgs.length];
175 
176             int pos = 0;
177             for (pos = 0; pos < nNamedArgs; pos++) {
178                 argLayouts[pos] = function.argumentLayouts().get(pos);
179             }
180 
181             assert pos == nNamedArgs;
182             for (Object o: unnamedArgs) {
183                 argLayouts[pos] = variadicLayout(normalize(o.getClass()));
184                 pos++;
185             }
186             assert pos == argsCount;
187 
188             FunctionDescriptor f = (function.returnLayout().isEmpty()) ?
189                     FunctionDescriptor.ofVoid(argLayouts) :
190                     FunctionDescriptor.of(function.returnLayout().get(), argLayouts);
191             MethodHandle mh = LINKER.downcallHandle(symbol, f);
192             if (mh.type().returnType() == MemorySegment.class) {
193                 mh = mh.bindTo(allocator);
194             }
195             // flatten argument list so that it can be passed to an asSpreader MH
196             Object[] allArgs = new Object[nNamedArgs + unnamedArgs.length];
197             System.arraycopy(args, 0, allArgs, 0, nNamedArgs);
198             System.arraycopy(unnamedArgs, 0, allArgs, nNamedArgs, unnamedArgs.length);
199 
200             return mh.asSpreader(Object[].class, argsCount).invoke(allArgs);
201         }
202 
203         private static Class<?> unboxIfNeeded(Class<?> clazz) {
204             if (clazz == Boolean.class) {
205                 return boolean.class;
206             } else if (clazz == Void.class) {
207                 return void.class;
208             } else if (clazz == Byte.class) {
209                 return byte.class;
210             } else if (clazz == Character.class) {
211                 return char.class;
212             } else if (clazz == Short.class) {
213                 return short.class;
214             } else if (clazz == Integer.class) {
215                 return int.class;
216             } else if (clazz == Long.class) {
217                 return long.class;
218             } else if (clazz == Float.class) {
219                 return float.class;
220             } else if (clazz == Double.class) {
221                 return double.class;
222             } else {
223                 return clazz;
224             }
225         }
226 
227         private Class<?> promote(Class<?> c) {
228             if (c == byte.class || c == char.class || c == short.class || c == int.class) {
229                 return long.class;
230             } else if (c == float.class) {
231                 return double.class;
232             } else {
233                 return c;
234             }
235         }
236 
237         private Class<?> normalize(Class<?> c) {
238             c = unboxIfNeeded(c);
239             if (c.isPrimitive()) {
240                 return promote(c);
241             }
242             if (MemoryAddress.class.isAssignableFrom(c)) {
243                 return MemoryAddress.class;
244             }
245             if (MemorySegment.class.isAssignableFrom(c)) {
246                 return MemorySegment.class;
247             }
248             throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName());
249         }
250 
251         private MemoryLayout variadicLayout(Class<?> c) {
252             if (c == long.class) {
253                 return JAVA_LONG;
254             } else if (c == double.class) {
255                 return JAVA_DOUBLE;
256             } else if (MemoryAddress.class.isAssignableFrom(c)) {
257                 return ADDRESS;
258             } else {
259                 throw new IllegalArgumentException("Unhandled variadic argument class: " + c);
260             }
261         }
262     }
263 }