1 ## State of foreign function support
  3 **January 2022**
  5 **Maurizio Cimadamore**
  7 Panama supports foreign functions through the Foreign Linker API, which has been available as an [incubating](https://openjdk.java.net/jeps/11) API since Java [16](https://openjdk.java.net/jeps/389). The central abstraction in the Foreign Linker API is the *foreign linker*, which allows clients to construct *downcall* method handles — that is, method handles whose invocation targets a native function defined in some native library. In other words, Panama foreign function support is completely expressed in terms of Java code and no intermediate native code is required.
  9 ### Native addresses
 11 Before we dive into the specifics of the foreign function support, it would be useful to briefly recap some of the main concepts we have learned when exploring the [foreign memory access support](panama_memaccess.md). The Foreign Memory Access API allows client to create and manipulate *memory segments*. A memory segment is a view over a memory source (either on- or off-heap) which is spatially bounded, temporally bounded and thread-confined. The guarantees ensure that dereferencing a segment that has been created by Java code is always *safe*, and can never result in a VM crash, or, worse, in silent memory corruption.
 13 Now, in the case of memory segments, the above properties (spatial bounds, temporal bounds and confinement) can be known *in full* when the segment is created. But when we interact with native libraries we often receive *raw* pointers; such pointers have no spatial bounds (does a `char*` in C refer to one `char`, or a `char` array of a given size?), no notion of temporal bounds, nor thread-confinement. Raw addresses in our interop support are modeled using the `MemoryAddress` abstraction.
 15 If clients want to dereference `MemoryAddress`, they can do so *unsafely* in two ways. First, they can use one of the *unsafe* dereference methods provided by `MemoryAddress` (these methods closely mirror those offered by `MemorySegment`); these methods are *restricted* and can only be called if the caller module has been listed in the `--enable-native-access` command-line flag:
 17 ```java
 18 ...
 19 MemoryAddress addr = ... //obtain address from native code
 20 int x = addr.get(JAVA_INT, 0);
 21 ```
 23 Alternatively, the client can create a memory segment from an address *unsafely*, using the `MemorySegment::ofAddress` factory (which is also a *restricted* method); this can also be useful to inject extra knowledge about spatial bounds which might be available in the native library the client is interacting with:
 25 ```java
 26 MemoryAddress addr = ... //obtain address from native code
 27 try (ResourceScope scope = ResourceScope.newConfinedScope()) {
 28 	MemorySegment segment = MemorySegment.ofAddress(100, scope);
 29 	int x = segment.get(JAVA_INT, 0);
 30 }
 31 ```
 33 Both `MemoryAddress` and `MemorySegment` implement the `Addressable` interface, which is an interface modelling entities that can be passed *by reference* — that is, which can be projected to a `MemoryAddress` instance. In the case of `MemoryAddress` such a projection is the identity function; in the case of a memory segment, the projection returns the `MemoryAddress` instance for the segment's base address. This abstraction allows to pass either memory address or memory segments where an address is expected (this is especially useful when generating native bindings).
 35 ### Segment allocators
 37 Idiomatic C code implicitly relies on stack allocation to allow for concise variable declarations; consider this example:
 39 ```c
 40 int arr[] = { 0, 1, 2, 3, 4 };
 41 ```
 43 A variable initializer such as the one above can be implemented as follows, using the Foreign Memory Access API:
 45 ```java
 46 try (ResourceScope scope = ResourceScope.newConfinedScope()) {
 47     MemorySegment arr = MemorySegment.allocateNative(MemoryLayout.sequenceLayout(5, JAVA_INT), scope);
 48     for (int i = 0 ; i < 5 ; i++) {
 49         arr.setAtIndex(JAVA_INT, i, i);
 50     }
 51 }
 52 ```
 54 There are a number of issues with the above code snippet:
 56 * compared to the C code, it is more verbose — the native array has to be initialized *element by element*
 57 * allocation is very slow compared to C; allocating the `arr` variable now takes a full `malloc`, while in C the variable was simply stack-allocated
 58 * when having multiple declarations like the one above, it might become increasingly harder to manage the lifecycle of the various segments
 60 To address these problems, Panama provides a `SegmentAllocator` abstraction, a functional interface which provides methods to allocate commonly used values. Conveniently, the above code can be rewritten as follows:
 62 ```java
 63 try (ResourceScope scope = ResourceScope.newConfinedScope()) {
 64     SegmentAllocator allocator = SegmentAllocator.nativeAllocator(scope);
 65     MemorySegment arr = allocator.allocateArray(JAVA_INT, new int[] { 0, 1, 2, 3, 4 });
 66 } // 'arr' is released here
 67 ```
 69 In the above code, the resource scope is used to build a *native* allocator (that is, an allocator built on top of `MemorySegment::allocateNative`). The segment allocator is then used to create a native array, initialized to the values `{ 0, 1, 2, 3, 4 }`.  The array initialization is more efficient, compared to the previous snippet, as the Java array is copied *in bulk* into the memory region associated with the newly allocated memory segment. The returned segment is associated with the scope which performed the allocation, meaning that the segment will no longer be accessible after the try-with-resource construct.
 71 Custom segment allocators are also critical to achieve optimal allocation performance; for this reason, a number of predefined allocators are available via factories in the `SegmentAllocator` interface. For instance, it is possible to create an arena-based allocator, as follows:
 73 ```java
 74 try (ResourceScope scope = ResourceScope.newConfinedScope()) {
 75     SegmentAllocator allocator = SegmentAllocator.newNativeArena(scope);
 76     for (int i = 0 ; i < 100 ; i++) {
 77         allocator.allocateArray(JAVA_INT, new int[] { 0, 1, 2, 3, 4 });
 78     }
 79     ...
 80 } // all memory allocated is released here
 81 ```
 83 The above code creates a confined scope; inside the *try-with-resources*, a new unbounded arena allocation is created, associated with the existing scope. The allocator will pre-allocate a native segment, of a specific size, and respond to allocation requests by returning different slices of the pre-allocated segment. If the pre-allocated segment does not have sufficient space to accommodate a new allocation request, a new segment will be allocated. If the scope associated with the arena allocator is closed, all memory segments created by the allocator (see the body of the `for` loop) will be deallocated at once. This idiom combines the advantages of deterministic deallocation (provided by the Memory Access API) with a more flexible and scalable allocation scheme, and can be very useful when writing large applications.
 85 For these reasons, all the methods in the Foreign Linker API which *produce* memory segments (see `VaList::nextVarg`), allow an optional allocator to be provided by user code — this is key in ensuring that an application using the Foreign Linker API achieves optimal allocation performances, especially in non-trivial use cases.
 87 ### Symbol lookups
 89 The first ingredient of any foreign function support is a mechanism to lookup symbols in native libraries. In traditional Java/JNI, this is done via the `System::loadLibrary` and `System::load` methods. Unfortunately, these methods do not provide a way for clients to obtain the *address* associated with a given library symbol. For this reason, the Foreign Linker API introduces a new abstraction, namely `SymbolLookup` (similar in spirit to a method handle lookup), which provides capabilities to lookup named symbols; we can obtain a symbol lookup in 2 different ways <a href="#1"><sup>1</sup></a>:
 91 * `SymbolLookup::loaderLookup` — creates a symbol lookup which can be used to search symbols in all the libraries loaded by the caller's classloader (e.g. using `System::loadLibrary` or `System::load`)
 92 * By obtaining a `CLinker` instance. In fact, `CLinker` implements the `SymbolLookup` interface, and can be used to look up platform-specific symbols in the standard C library.
 94 Once a lookup has been obtained, a client can use it to retrieve handles to library symbols (either global variables or functions) using the `lookup(String)` method, which returns an `Optional<NativeSymbol>`.  `NativeSymbol` is a class used to model references to library symbols, which implements the `Addressable` interface.
 96 For instance, the following code can be used to look up the `clang_getClangVersion` function provided by the `clang` library:
 98 ```java
 99 System.loadLibrary("clang");
100 NativeSymbol clangVersion = SymbolLookup.loaderLookup().lookup("clang_getClangVersion").get();
101 ```
103 ### C Linker
105 At the core of Panama foreign function support we find the `CLinker` abstraction. This abstraction plays a dual role: first, for downcalls, it allows modelling native function calls as plain `MethodHandle` calls (see `CLinker::downcallHandle`); second, for upcalls, it allows to convert an existing `MethodHandle` (which might point to some Java method) into a `NativeSymbol` which could then be passed to native functions as a function pointer (see `CLinker::upcallStub`):
107 ```java
108 interface CLinker {
109     MethodHandle downcallHandle(NativeSymbol func, FunctionDescriptor function);
110     NativeSymbol upcallStub(MethodHandle target, FunctionDescriptor function, ResourceScope scope);    
111     ... // some overloads omitted here
113     static CLinker systemCLinker() { ... }
114 }
115 ```
117 Both functions take a `FunctionDescriptor` instance — essentially an aggregate of memory layouts which is used to describe the argument and return types of a foreign function in full. Supported layouts are *value layouts* (for scalars and pointers) and *group layouts* (for structs/unions). Each layout in a function descriptor is associated with a carrier Java type (see table below); together, all the carrier types associated with layouts in a function descriptor will determine a unique Java `MethodType`  — that is, the Java signature that clients will be using when interacting with said downcall handles, or upcall stubs.
119 The following table shows the mapping between C types, layouts and Java carriers under the Linux/macOS foreign linker implementation; note that the mappings can be platform dependent: on Windows/x64, the C type `long` is 32-bit, so the `JAVA_INT` layout (and the Java carrier `int.class`) would have to be used instead:
121 | C type                                                       | Layout                                                       | Java carrier                       |
122 | ------------------------------------------------------------ | ------------------------------------------------------------ | ---------------------------------- |
123 | `bool`                                                       | `JAVA_BOOLEAN`                                               | `byte`                             |
124 | `char`                                                       | `JAVA_BYTE`                                                  | `byte`                             |
125 | `short`                                                      | `JAVA_SHORT`                                                 | `short`, `char`                    |
126 | `int`                                                        | `JAVA_INT`                                                   | `int`                              |
127 | `long`                                                       | `JAVA_LONG`                                                  | `long`                             |
128 | `long long`                                                  | `JAVA_LONG`                                                  | `long`                             |
129 | `float`                                                      | `JAVA_FLOAT`                                                 | `float`                            |
130 | `double`                                                     | `JAVA_DOUBLE`                                                | `double`                           |
131 | `char*`<br />`int**`<br /> ...                               | `ADDRESS`                                                    | `Addressable`<br />`MemoryAddress` |
132 | `struct Point { int x; int y; };`<br />`union Choice { float a; int b; };`<br />... | `MemoryLayout.structLayout(...)`<br />`MemoryLayout.unionLayout(...)`<br /> | `MemorySegment`                    |
134 Note that all C pointer types are modelled using the `ADDRESS` layout constant; the Java carrier type associated with this layout is either `Addressable` or `MemoryAddress` depending on where the layout occurs in the function descriptor. For downcall method handles, for instance, the `Addressable` carrier is used when the `ADDRESS` layout occurs in a parameter position of the corresponding function descriptor. This maximizes applicability of a downcall method handles, ensuring that any implementation of `Addressable` (e.g. memory segments, memory address, upcall stubs, va lists) can be passed where a pointer is expected.
136 A tool, such as `jextract`, will generate all the required C layouts (for scalars and structs/unions) *automatically*, so that clients do not have to worry about platform-dependent details such as sizes, alignment constraints and padding.
138 ### Downcalls
140 We will now look at how foreign functions can be called from Java using the foreign linker abstraction. Assume we wanted to call the following function from the standard C library:
142 ```c
143 size_t strlen(const char *s);
144 ```
146 In order to do that, we have to:
148 * lookup the `strlen` symbol
149 * describe the signature of the C function using a function descriptor
151 * create a *downcall* native method handle with the above information, using the standard C foreign linker
153 Here's an example of how we might want to do that (a full listing of all the examples in this and subsequent sections will be provided in the [appendix](#appendix-full-source-code)):
155 ```java
156 CLinker linker = CLinker.systemCLinker();
157 MethodHandle strlen = linker.downcallHandle(
158 		linker.lookup("strlen").get(),
159         FunctionDescriptor.of(JAVA_LONG, ADDRESS)
160 );
161 ```
163 Note that, since the function `strlen` is part of the standard C library, which is loaded with the VM, we can just use the system lookup to look it up. The rest is pretty straightforward — the only tricky detail is how to model `size_t`: typically this type has the size of a pointer, so we can use `JAVA_LONG` both Linux and Windows. On the Java side, we model the `size_t` using a `long` and the pointer is modelled using an `Addressable` parameter.
165 Once we have obtained the downcall method handle, we can just use it as any other method handle<a href="#2"><sup>2</sup></a>:
167 ```java
168 try (ResourceScope scope = ResourceScope.newConfinedScope()) {
169     SegmentAllocator malloc = SegmentAllocator.nativeAllocator(scope);
170     long len = strlen.invoke(malloc.allocateUtf8String("Hello")); // 5
171 }
172 ```
174 Here we are using a native segment allocator to convert a Java string into an off-heap memory segment which contains a `NULL` terminated C string. We then pass that segment to the method handle and retrieve our result in a Java `long`. Note how all this is possible *without* any piece of intervening native code — all the interop code can be expressed in (low level) Java. Note also how we use an explicit resource scope to control the lifecycle of the allocated C string, which ensures timely deallocation of the memory segment holding the native string.
176 The `CLinker` interface also supports linking of native functions without an address known at link time; when that happens, an address (of type `Addressable`) must be provided when the method handle returned by the linker is invoked — this is very useful to support *virtual calls*. For instance, the above code can be rewritten as follows:
178 ```java
179 MethodHandle strlen_virtual = linker.downcallHandle( // address parameter missing!
180 		FunctionDescriptor.of(JAVA_LONG, ADDRESS)
181 );
183 try (ResourceScope scope = ResourceScope.newConfinedScope()) {
184     SegmentAllocator malloc = SegmentAllocator.nativeAllocator(scope);
185     long len = strlen_virtual.invoke(
186         linker.lookup("strlen").get() // address provided here!
187         malloc.allocateUtf8String("Hello")
188     ); // 5
189 }
190 ```
192 It is important to note that, albeit the interop code is written in Java, the above code can *not* be considered 100% safe. There are many arbitrary decisions to be made when setting up downcall method handles such as the one above, some of which might be obvious to us (e.g. how many parameters does the function take), but which cannot ultimately be verified by the Panama runtime. After all, a symbol in a dynamic library is nothing but a numeric offset and, unless we are using a shared library with debugging information, no type information is attached to a given library symbol. This means that the Panama runtime has to *trust* the function descriptor passed in<a href="#3"><sup>3</sup></a>; for this reason, access to the foreign linker is a restricted operation, which can only be performed if the requesting module is listed in the `--enable-native-access` command-line flag.
194 If a native function returns a raw pointer (of type `MemoryAddress`), it is then up to the client to make sure that the address is being accessed and disposed of correctly, compatibly with the requirements of the underlying native library. If a native function returns a struct by value, a *fresh*, memory segment is allocated off-heap and returned to the caller. In such cases, the downcall method handle will feature an additional prefix `SegmentAllocator` (see above) parameter which will be used by the downcall method handle to allocate the returned segment. The allocation will likely associate the segment with a *resource scope* that is known to the caller and which can then be used to release the memory associated with that segment. 
196 Performance-wise, the reader might ask how efficient calling a foreign function using a native method handle is; the answer is *very*. The JVM comes with some special support for native method handles, so that, if a give method handle is invoked many times (e.g, inside a *hot* loop), the JIT compiler might decide to generate a snippet of assembly code required to call the native function, and execute that directly. In most cases, invoking native function this way is as efficient as doing so through JNI.
198 ### Upcalls
200 Sometimes, it is useful to pass Java code as a function pointer to some native function; we can achieve that by using foreign linker support for upcalls. To demonstrate this, let's consider the following function from the C standard library:
202 ```c
203 void qsort(void *base, size_t nmemb, size_t size,
204            int (*compar)(const void *, const void *));
205 ```
207 The `qsort` function can be used to sort the contents of an array, using a custom comparator function — `compar` — which is passed as a function pointer. To be able to call the `qsort` function from Java we have first to create a downcall method handle for it:
209 ```java
210 CLinker linker = CLinker.systemCLinker();
211 MethodHandle qsort = linker.downcallHandle(
212 		CLinker.systemLookup().lookup("qsort").get(),
213         FunctionDescriptor.ofVoid(ADDRESS, JAVA_LONG, JAVA_LONG, ADDRESS)
214 );
215 ```
217 As before, we use `JAVA_LONG` and `long.class` to map the C `size_t` type, and `ADDRESS` for both the first pointer parameter (the array pointer) and the last parameter (the function pointer).
219 This time, in order to invoke the `qsort` downcall handle, we need a *function pointer* to be passed as the last parameter; this is where the upcall support in foreign linker comes in handy, as it allows us to create a function pointer out of an existing method handle. First, let's write a function that can compare two int elements (passed as pointers):
221 ```java
222 class Qsort {
223 	static int qsortCompare(MemoryAddress addr1, MemoryAddress addr2) {
224 		return addr1.get(JAVA_INT, 0) - addr2.get(JAVA_INT, 0);
225 	}
226 }
227 ```
229 Here we can see that the function is performing some *unsafe* dereference of the pointer contents.
231 Now let's create a method handle pointing to the comparator function above:
233 ```java
234 FunctionDescriptor comparDesc = FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS);
235 MethodHandle comparHandle = MethodHandles.lookup()
236                                          .findStatic(Qsort.class, "qsortCompare",
237                                                      CLinker.upcallType(comparDesc));
238 ```
240 To do that, we first create a function descriptor for the function pointer type, and then we use the `CLinker::upcallType` to turn that function descriptor into a suitable `MethodType` instance to be used in a method handle lookup. Now that we have a method handle for our Java comparator function, we finally have all the ingredients to create an upcall stub, and pass it to the `qsort` downcall handle:
242 ```java
243 try (ResourceScope scope = ResourceScope.newConfinedScope()) {
244     NativeSymbol comparFunc = linker.upcallStub(
245         comparHandle, comparDesc, scope);
246     SegmentAllocator malloc = SegmentAllocator.nativeAllocator(scope);
247     MemorySegment array = malloc.allocateArray(new int[] { 0, 9, 3, 4, 6, 5, 1, 8, 2, 7 }));
248     qsort.invoke(array, 10L, 4L, comparFunc);
249     int[] sorted = array.toArray(JAVA_INT); // [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
250 }
251 ```
253 The above code creates an upcall stub — `comparFunc` — a function pointer that can be used to invoke our Java comparator function, of type `NativeSymbol`. The upcall stub is associated with the provided resource scope instance; this means that the stub will be uninstalled when the resource scope is closed.
255 The snippet then creates an off-heap array from a Java array (using a `SegmentAllocator`), which is then passed to the `qsort` handle, along with the comparator function we obtained from the foreign linker.  As a side effect, after the call, the contents of the off-heap array will be sorted (as instructed by our comparator function, written in Java). We can than extract a new Java array from the segment, which contains the sorted elements. This is a more advanced example, but one that shows how powerful the native interop support provided by the foreign linker abstraction is, allowing full bidirectional interop support between Java and native.
257 ### Varargs
259 Some C functions are *variadic* and can take an arbitrary number of arguments. Perhaps the most common example of this is the `printf` function, defined in the C standard library:
261 ```c
262 int printf(const char *format, ...);
263 ```
265 This function takes a format string, which features zero or more *holes*, and then can take a number of additional arguments that is identical to the number of holes in the format string.
267 The foreign function support can support variadic calls, but with a caveat: the client must provide a specialized Java signature, and a specialized description of the C signature. For instance, let's say we wanted to model the following C call:
269 ```C
270 printf("%d plus %d equals %d", 2, 2, 4);
271 ```
273 To do this using the foreign function support provided by Panama we would have to build a *specialized* downcall handle for that call shape, using the `FunctionDescriptor::asVariadic` to inject additional variadic layouts, as follows:
275 ```java
276 CLinker linker = CLinker.systemCLinker();
277 MethodHandle printf = linker.downcallHandle(
278 		linker.lookup("printf").get(),
279         FunctionDescriptor.of(JAVA_INT, ADDRESS).asVariadic(JAVA_INT, JAVA_INT, JAVA_INT)
280 );
281 ```
283 Then we can call the specialized downcall handle as usual:
285 ```java
286 try (ResourceScope scope = ResourceScope.newConfinedScope()) {
287     SegmentAllocator malloc = SegmentAllocator.nativeAllocator(scope);
288     printf.invoke(malloc.allocateUtf8String("%d plus %d equals %d"), 2, 2, 4); //prints "2 plus 2 equals 4"
289 }
290 ```
292 While this works, and provides optimal performance, there are some drawbacks:
294 * If the variadic function needs to be called with many shapes, we have to create many downcall handles
295 * while this approach works for downcalls (since the Java code is in charge of determining which and how many arguments should be passed) it fails to scale to upcalls; in that case, the call comes from native code, so we have no way to guarantee that the shape of the upcall stub we have created will match that required by the native function.
297 To add flexibility, the standard C foreign linker comes equipped with support for C variable argument lists — or `va_list`.  When a variadic function is called, C code has to unpack the variadic arguments by creating a `va_list` structure, and then accessing the variadic arguments through the `va_list` one by one (using the `va_arg` macro). To facilitate interop between standard variadic functions and `va_list` many C library functions in fact define *two* flavors of the same function, one using standard variadic signature, one using an extra `va_list` parameter. For instance, in the case of `printf` we can find that a `va_list`-accepting function performing the same task is also defined:
299 ```c
300 int vprintf(const char *format, va_list ap);
301 ```
303 The behavior of this function is the same as before — the only difference is that the ellipsis notation `...` has been replaced with a single `va_list` parameter; in other words, the function is no longer variadic.
305 It is indeed fairly easy to create a downcall for `vprintf`:
307 ```java
308 CLinker linker = CLinker.systemCLinker();
309 MethodHandle vprintf = linker.downcallHandle(
310 		linker.lookup("vprintf").get(),
311 		FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS));
312 ```
314 Here, the layout of a `va_list` parameter is simply `ADDRESS` (as va lists are passed by reference). To call the `vprintf` handle we need to create an instance of `VaList` which contains the arguments we want to pass to the `vprintf` function — we can do so, as follows:
316 ```java
317 try (ResourceScope scope = ResourceScope.newConfinedScope()) {
318     SegmentAllocator malloc = SegmentAllocator.nativeAllocator(scope);
319     vprintf.invoke(
320             malloc.allocateUtf8String("%d plus %d equals %d", scope),
321             VaList.make(builder ->
322                             builder.addVarg(JAVA_INT, 2)
323                                    .addVarg(JAVA_INT, 2)
324                                    .addVarg(JAVA_INT, 4), scope)
325 ); //prints "2 plus 2 equals 4"
326 ```
328 While the callee has to do more work to call the `vprintf` handle, note that that now we're back in a place where the downcall handle  `vprintf` can be shared across multiple callees. Note that both the format string and the `VaList` are associated with the given resource scope — this means that both will remain valid throughout the native function call.
330 Using `VaList` also scales to upcall stubs — it is therefore possible for clients to create upcalls stubs which take a `VaList` and then, from the Java upcall, read the arguments packed inside the `VaList` one by one using the methods provided by the `VaList` API (e.g. `VaList::nextVarg(ValueLayout.OfInt)`), which mimics the behavior of the C `va_arg` macro.
332 ### Appendix: full source code
334 The full source code containing most of the code shown throughout this document can be seen below:
336 ```java
337 import jdk.incubator.foreign.Addressable;
338 import jdk.incubator.foreign.CLinker;
339 import jdk.incubator.foreign.FunctionDescriptor;
340 import jdk.incubator.foreign.SymbolLookup;
341 import jdk.incubator.foreign.MemoryAddress;
342 import jdk.incubator.foreign.MemorySegment;
343 import jdk.incubator.foreign.NativeSymbol;
344 import jdk.incubator.foreign.ResourceScope;
345 import jdk.incubator.foreign.SegmentAllocator;
346 import jdk.incubator.foreign.VaList;
348 import java.lang.invoke.MethodHandle;
349 import java.lang.invoke.MethodHandles;
350 import java.lang.invoke.MethodType;
351 import java.util.Arrays;
353 import static jdk.incubator.foreign.ValueLayout.*;
355 public class Examples {
357     static CLinker LINKER = CLinker.systemCLinker();
359     public static void main(String[] args) throws Throwable {
360         strlen();
361         strlen_virtual();
362         qsort();
363         printf();
364         vprintf();
365     }
367     public static void strlen() throws Throwable {
368         MethodHandle strlen = LINKER.downcallHandle(
369                 LINKER.lookup("strlen").get(),
370                 FunctionDescriptor.of(JAVA_LONG, ADDRESS)
371         );
373         try (ResourceScope scope = ResourceScope.newConfinedScope()) {
374             SegmentAllocator malloc = SegmentAllocator.nativeAllocator(scope);
375             MemorySegment hello = malloc.allocateUtf8String("Hello");
376             long len = (long) strlen.invoke(hello); // 5
377             System.out.println(len);
378         }
379     }
381     public static void strlen_virtual() throws Throwable {
382         MethodHandle strlen_virtual = LINKER.downcallHandle(
383                 FunctionDescriptor.of(JAVA_LONG, ADDRESS)
384         );
386         try (ResourceScope scope = ResourceScope.newConfinedScope()) {
387             SegmentAllocator malloc = SegmentAllocator.nativeAllocator(scope);
388             MemorySegment hello = malloc.allocateUtf8String("Hello");
389             long len = (long) strlen_virtual.invoke(
390                 LINKER.lookup("strlen").get(),
391                 hello); // 5
392             System.out.println(len);
393         }
394     }
396     static class Qsort {
397         static int qsortCompare(MemoryAddress addr1, MemoryAddress addr2) {
398             return addr1.get(JAVA_INT, 0) - addr2.get(JAVA_INT, 0);
399         }
400     }
402     public static void qsort() throws Throwable {
403         MethodHandle qsort = LINKER.downcallHandle(
404                 LINKER.lookup("qsort").get(),
405                 FunctionDescriptor.ofVoid(ADDRESS, JAVA_LONG, JAVA_LONG, ADDRESS)
406         );
407         FunctionDescriptor comparDesc = FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS);
408         MethodHandle comparHandle = MethodHandles.lookup()
409                                          .findStatic(Qsort.class, "qsortCompare",
410                                                      CLinker.upcallType(comparDesc));
412         try (ResourceScope scope = ResourceScope.newConfinedScope()) {
413             NativeSymbol comparFunc = LINKER.upcallStub(
414                 comparHandle, comparDesc, scope);
416             SegmentAllocator malloc = SegmentAllocator.nativeAllocator(scope);
417             MemorySegment array = malloc.allocateArray(JAVA_INT, new int[] { 0, 9, 3, 4, 6, 5, 1, 8, 2, 7 });
418             qsort.invoke(array, 10L, 4L, comparFunc);
419             int[] sorted = array.toArray(JAVA_INT); // [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
420             System.out.println(Arrays.toString(sorted));
421         }
422     }
424     public static void printf() throws Throwable {
425         MethodHandle printf = LINKER.downcallHandle(
426                 LINKER.lookup("printf").get(),
427                 FunctionDescriptor.of(JAVA_INT, ADDRESS).asVariadic(JAVA_INT, JAVA_INT, JAVA_INT)
428         );
429         try (ResourceScope scope = ResourceScope.newConfinedScope()) {
430             SegmentAllocator malloc = SegmentAllocator.nativeAllocator(scope);
431             MemorySegment s = malloc.allocateUtf8String("%d plus %d equals %d\n");
432             printf.invoke(s, 2, 2, 4);
433         }
434     }
436     public static void vprintf() throws Throwable {
438         MethodHandle vprintf = LINKER.downcallHandle(
439                 LINKER.lookup("vprintf").get(),
440                 FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS));
442         try (ResourceScope scope = ResourceScope.newConfinedScope()) {
443             SegmentAllocator malloc = SegmentAllocator.nativeAllocator(scope);
444             MemorySegment s = malloc.allocateUtf8String("%d plus %d equals %d\n");
445             VaList vlist = VaList.make(builder ->
446                      builder.addVarg(JAVA_INT, 2)
447                             .addVarg(JAVA_INT, 2)
448                             .addVarg(JAVA_INT, 4), scope);
449             vprintf.invoke(s, vlist);
450         }
451     }
452 }
453 ```
457 * <a id="1"/>(<sup>1</sup>):<small> Users might add more ways to obtain a symbol lookup — for instance: `SymbolLookup libraryLookup(String libName, ResourceScope scope)`. This would allow developers to load a library and associate its lifecycle with a `ResourceScope` (rather than a classloader). That is, when the scope is closed, the library will be unloaded. This is possible, as `CLinker` guarantees that memory addresses used by a downcall method handle cannot be released while the downcall method handle is being invoked.</small>
458 * <a id="2"/>(<sup>2</sup>):<small> For simplicity, the examples shown in this document use `MethodHandle::invoke` rather than `MethodHandle::invokeExact`; by doing so we avoid having to cast by-reference arguments back to `Addressable`. With `invokeExact` the method handle invocation should be rewritten as `strlen.invokeExact((Addressable)malloc.allocateUtf8String("Hello"));`</small>
459 * <a id="3"/>(<sup>3</sup>):<small> In reality this is not entirely new; even in JNI, when you call a `native` method the VM trusts that the corresponding implementing function in C will feature compatible parameter types and return values; if not a crash might occur.</small>