1 ## State of foreign function support
  2 
  3 **September 2021**
  4 
  5 **Maurizio Cimadamore**
  6 
  7 Panama support foreign functions through the Foreign Memory Access 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 *native* 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.
  8 
  9 ### Native addresses
 10 
 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.
 12 
 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 will often be receiving *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.
 14 
 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:
 16 
 17 ```java
 18 ...
 19 MemoryAddress addr = ... //obtain address from native code
 20 int x = addr.get(JAVA_INT, 0);
 21 ```
 22 
 23 Alternatively, the client can create a memory segment from an address *unsafely*, using the `MemorySegment::ofAddressNative` 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:
 24 
 25 ```java
 26 MemoryAddress addr = ... //obtain address from native code
 27 try (ResourceScope scope = ResourceScope.newConfinedScope()) {
 28 	MemorySegment segment = MemorySegment.ofAddressNative(100, scope);
 29 	int x = segment.get(JAVA_INT, 0);
 30 }
 31 ```
 32 
 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 `MemoryAddres` 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).
 34 
 35 ### Segment allocators
 36 
 37 Idiomatic C code implicitly relies on stack allocation to allow for concise variable declarations; consider this example:
 38 
 39 ```c
 40 int arr[] = { 0, 1, 2, 3, 4 };
 41 ```
 42 
 43 A variable initializer such as the one above can be implemented as follows, using the Foreign Memory Access API:
 44 
 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 ```
 53 
 54 There are a number of issues with the above code snippet:
 55 
 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
 59 
 60 To address these problems, Panama provides a `SegmentAllocator` abstraction, a functional interface which provides methods to allocate commonly used values. Conveniently, all resource scopes implement the `SegmentAllocator` interface, which means that the above code can be rewritten as follows:
 61 
 62 ```java
 63 try (ResourceScope scope = ResourceScope.newConfinedScope()) {
 64     MemorySegment arr = scope.allocateArray(JAVA_INT, new int[] { 0, 1, 2, 3, 4 });
 65 } // 'arr' is released here
 66 ```
 67 
 68 In the above code, the resource scope is used as an allocator (built on top of `MemorySegment::allocateNative`) to create a native array which is 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. Since 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.
 69 
 70 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:
 71 
 72 ```java
 73 try (ResourceScope scope = ResourceScope.newConfinedScope()) {
 74     SegmentAllocator allocator = SegmentAllocator.arenaAllocator(scope);
 75     for (int i = 0 ; i < 100 ; i++) {
 76         allocator.allocateArray(JAVA_INT, new int[] { 0, 1, 2, 3, 4 });
 77     }
 78     ...
 79 } // all memory allocated is released here
 80 ```
 81 
 82 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 allocate slabs of memory, of a specific size, and respond to allocation requests by returning different slices of the pre-allocated slab. If a slab does not have sufficient space to accommodate a new allocation request, a new one will be allocated. If the scope associated with the arena allocator is closed, all memory associated with the 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.
 83 
 84 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.
 85 
 86 ### Symbol lookups
 87 
 88 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>:
 89 
 90 * `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`)
 91 * 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.
 92 
 93 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<MemoryAddress>`.
 94 
 95 For instance, the following code can be used to look up the `clang_getClangVersion` function provided by the `clang` library:
 96 
 97 ```java
 98 System.loadLibrary("clang");
 99 MemoryAddress clangVersion = SymbolLookup.loaderLookup().lookup("clang_getClangVersion").get();
100 ```
101 
102 ### C Linker
103 
104 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 `ForeignLinker::downcallHandle`); second, for upcalls, it allows to convert an existing `MethodHandle` (which might point to some Java method) into a `MemorySegment` which could then be passed to native functions as a function pointer (see `ForeignLinker::upcallStub`):
105 
106 ```java
107 interface CLinker {
108     MethodHandle downcallHandle(Addressable func, MethodType type, FunctionDescriptor function);
109     UpcallStub upcallStub(MethodHandle target, FunctionDescriptor function, ResourceScope scope);    
110     ... // some overloads omitted here
111 
112     static CLinker systemCLinker() { ... }
113 }
114 ```
115 
116 In the following sections we will dive deeper into how downcall handles and upcall stubs are created; here we want to focus on the similarities between these two routines. First, both 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`, embodying the Java signature that clients will be using when interacting with said downcall handles, or upcall stubs.
117 
118 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:
119 
120 | C type                                                       | Layout         | Java carrier                       |
121 | ------------------------------------------------------------ | -------------- | ---------------------------------- |
122 | `bool`                                                       | `JAVA_BOOLEAN` | `byte`                             |
123 | `char`                                                       | `JAVA_BYTE`    | `byte`                             |
124 | `short`                                                      | `JAVA_SHORT`   | `short`, `char`                    |
125 | `int`                                                        | `JAVA_INT`     | `int`                              |
126 | `long`                                                       | `JAVA_LONG`    | `long`                             |
127 | `long long`                                                  | `JAVA_LONG`    | `long`                             |
128 | `float`                                                      | `JAVA_FLOAT`   | `float`                            |
129 | `double`                                                     | `JAVA_DOUBLE`  | `double`                           |
130 | `char*`<br />`int**`<br /> ...                               | `ADDRESS`      | `Addressable`<br />`MemoryAddress` |
131 | `struct Point { int x; int y; };`<br />`union Choice { float a; int b; };`<br />... | `GroupLayout`  | `MemorySegment`                    |
132 
133 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.
134 
135 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.
136 
137 ### Downcalls
138 
139 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:
140 
141 ```c
142 size_t strlen(const char *s);
143 ```
144 
145 In order to do that, we have to:
146 
147 * lookup the `strlen` symbol
148 * describe the signature of the C function using a function descriptor
149 
150 * create a *downcall* native method handle with the above information, using the standard C foreign linker
151 
152 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)):
153 
154 ```java
155 CLinker linker = CLinker.systemCLinker();
156 MethodHandle strlen = linker.downcallHandle(
157 		linker.lookup("strlen").get(),
158         FunctionDescriptor.of(JAVA_LONG, ADDRESS)
159 );
160 ```
161 
162 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.
163 
164 One we have obtained the downcall native method handle, we can just use it as any other method handle<a href="#3"><sup>3</sup></a>:
165 
166 ```java
167 try (ResourceScope scope = ResourceScope.newConfinedScope()) {
168     long len = strlen.invoke(scope.allocateUtf8String("Hello")); // 5
169 }
170 ```
171 
172 Here we are using one of the helper methods in `CLinker` 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 has been possible *without* any piece of intervening native code — all the interop code can be expressed in (low level) Java. Note also how we used 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.
173 
174 The `CLinker` interfaces also supports linking of native function without an address known at link time; when that happens, an address 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:
175 
176 ```java
177 MethodHandle strlen_virtual = linker.downcallHandle( // address parameter missing!
178 		FunctionDescriptor.of(JAVA_LONG, ADDRESS)
179 );
180 
181 try (ResourceScope scope = ResourceScope.newConfinedScope()) {
182     long len = strlen_virtual.invoke(
183         linker.lookup("strlen").get() // address provided here!
184         scope.allocateUtf8String("Hello")
185     ); // 5
186 }
187 ```
188 
189 Now that we have seen the basics of how foreign function calls are supported in Panama, let's add some additional considerations. First, 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, mostly 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, in this case, the Panama runtime has to *trust* our description of the `strlen` function. 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 <a href="#2"><sup>2</sup></a>.
190 
191 Certain functions might return pointers, or structs; it is important to realize that if a function returns a pointer (or a `MemoryAddress`), no life-cycle whatsoever is attached to that pointer. It is then up to the client to e.g. free the memory associated with that pointer, or do nothing (in case the library is responsible for the life-cycle of that pointer). If a library returns a struct by value, things are different, as a *fresh*, memory segment is allocated off-heap and returned to the callee. In such cases, the foreign linker API will request an additional prefix `SegmentAllocator` (see above) parameter which will be responsible for allocating the returned segment. The allocation will likely associate the segment with a *resource scope* that is known to the callee and which can then be used to release the memory associated with that segment. An additional overload of `downcallHandle` is also provided by `CLinker` where a client can specify which allocator should be used in such cases at *link-time*.
192 
193 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 just 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.
194 
195 ### Upcalls
196 
197 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:
198 
199 ```c
200 void qsort(void *base, size_t nmemb, size_t size,
201            int (*compar)(const void *, const void *));
202 ```
203 
204 This is a function that 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 native method handle for it:
205 
206 ```java
207 CLinker linker = CLinker.systemCLinker();
208 MethodHandle qsort = linker.downcallHandle(
209 		CLinker.systemLookup().lookup("qsort").get(),
210         FunctionDescriptor.ofVoid(ADDRESS, JAVA_LONG, JAVA_LONG, ADDRESS)
211 );
212 ```
213 
214 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).
215 
216 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):
217 
218 ```java
219 class Qsort {
220 	static int qsortCompare(MemoryAddress addr1, MemoryAddress addr2) {
221 		return addr1.get(JAVA_INT, 0) - addr2.get(JAVA_INT, 0);
222 	}
223 }
224 ```
225 
226 Here we can see that the function is performing some *unsafe* dereference of the pointer contents.
227 
228  Now let's create a method handle pointing to the comparator function above:
229 
230 ```java
231 MethodHandle comparHandle = MethodHandles.lookup()
232                                          .findStatic(Qsort.class, "qsortCompare",
233                                                      MethodType.methodType(int.class, MemoryAddress.class, MemoryAddress.class));
234 ```
235 
236 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:
237 
238 ```java
239 try (ResourceScope scope = ResourceScope.newConfinedScope()) {
240     UpcallStub comparFunc = linker.upcallStub(
241         comparHandle,
242     	FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS),
243         scope);
244     MemorySegment array = scope.allocateArray(new int[] { 0, 9, 3, 4, 6, 5, 1, 8, 2, 7 }));
245     qsort.invoke(array, 10L, 4L, comparFunc);
246     int[] sorted = array.toArray(JAVA_INT); // [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
247 }
248 ```
249 
250 The above code creates an upcall stub — `comparFunc` — a function pointer that can be used to invoke our Java comparator function. 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.
251 
252 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.
253 
254 ### Varargs
255 
256 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:
257 
258 ```c
259 int printf(const char *format, ...);
260 ```
261 
262 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.
263 
264 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:
265 
266 ```C
267 printf("%d plus %d equals %d", 2, 2, 4);
268 ```
269 
270 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:
271 
272 ```java
273 CLinker linker = CLinker.systemCLinker();
274 MethodHandle printf = linker.downcallHandle(
275 		linker.lookup("printf").get(),
276         FunctionDescriptor.of(JAVA_INT, ADDRESS).asVariadic(JAVA_INT, JAVA_INT, JAVA_INT)
277 );
278 ```
279 
280 Then we can call the specialized downcall handle as usual:
281 
282 ```java
283 try (ResourceScope scope = ResourceScope.newConfinedScope()) {
284 	printf.invoke(scope.allocateUtf8String("%d plus %d equals %d"), 2, 2, 4); //prints "2 plus 2 equals 4"
285 }
286 ```
287 
288 While this works, and provides optimal performance, there are some drawbacks:
289 
290 * If the variadic function needs to be called with many shapes, we have to create many downcall handles
291 * 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.
292 
293 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:
294 
295 ```c
296 int vprintf(const char *format, va_list ap);
297 ```
298 
299 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.
300 
301 It is indeed fairly easy to create a downcall for `vprintf`:
302 
303 ```java
304 CLinker linker = CLinker.systemCLinker();
305 MethodHandle vprintf = linker.downcallHandle(
306 		linker.lookup("vprintf").get(),
307 		FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS));
308 ```
309 
310 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:
311 
312 ```java
313 try (ResourceScope scope = ResourceScope.newConfinedScope()) {
314     vprintf.invoke(
315             scope.allocateUtf8String("%d plus %d equals %d", scope),
316             VaList.make(builder ->
317                             builder.addVarg(C_INT, 2)
318                                    .addVarg(C_INT, 2)
319                                    .addVarg(C_INT, 4), scope)
320 ); //prints "2 plus 2 equals 4"
321 ```
322 
323 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.
324 
325 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.
326 
327 ### Appendix: full source code
328 
329 The full source code containing most of the code shown throughout this document can be seen below:
330 
331 ```java
332 import jdk.incubator.foreign.Addressable;
333 import jdk.incubator.foreign.CLinker;
334 import jdk.incubator.foreign.FunctionDescriptor;
335 import jdk.incubator.foreign.SymbolLookup;
336 import jdk.incubator.foreign.MemoryAddress;
337 import jdk.incubator.foreign.MemorySegment;
338 import jdk.incubator.foreign.ResourceScope;
339 import jdk.incubator.foreign.SegmentAllocator;
340 import jdk.incubator.foreign.VaList;
341 
342 import java.lang.invoke.MethodHandle;
343 import java.lang.invoke.MethodHandles;
344 import java.lang.invoke.MethodType;
345 import java.util.Arrays;
346 
347 import static jdk.incubator.foreign.ValueLayout.*;
348 
349 public class Examples {
350 
351     static CLinker LINKER = CLinker.systemCLinker();
352 
353     public static void main(String[] args) throws Throwable {
354         strlen();
355         strlen_virtual();
356         qsort();
357         printf();
358         vprintf();
359     }
360 
361     public static void strlen() throws Throwable {
362         MethodHandle strlen = LINKER.downcallHandle(
363                 LINKER.lookup("strlen").get(),
364                 FunctionDescriptor.of(JAVA_LONG, ADDRESS)
365         );
366 
367         try (ResourceScope scope = ResourceScope.newConfinedScope()) {
368             MemorySegment hello = scope.allocateUtf8String("Hello");
369             long len = (long) strlen.invoke(hello); // 5
370             System.out.println(len);
371         }
372     }
373 
374     public static void strlen_virtual() throws Throwable {
375         MethodHandle strlen_virtual = LINKER.downcallHandle(
376                 FunctionDescriptor.of(JAVA_LONG, ADDRESS)
377         );
378 
379         try (ResourceScope scope = ResourceScope.newConfinedScope()) {
380             MemorySegment hello = scope.allocateUtf8String("Hello");
381             long len = (long) strlen_virtual.invoke(
382                 LINKER.lookup("strlen").get(),
383                 hello); // 5
384             System.out.println(len);
385         }
386     }
387 
388     static class Qsort {
389         static int qsortCompare(MemoryAddress addr1, MemoryAddress addr2) {
390             return addr1.get(JAVA_INT, 0) - addr2.get(JAVA_INT, 0);
391         }
392     }
393 
394     public static void qsort() throws Throwable {
395         MethodHandle qsort = LINKER.downcallHandle(
396                 LINKER.lookup("qsort").get(),
397                 FunctionDescriptor.ofVoid(ADDRESS, JAVA_LONG, JAVA_LONG, ADDRESS)
398         );
399 
400         MethodHandle comparHandle = MethodHandles.lookup()
401                 .findStatic(Qsort.class, "qsortCompare",
402                         MethodType.methodType(int.class, MemoryAddress.class, MemoryAddress.class));
403 
404         try (ResourceScope scope = ResourceScope.newConfinedScope()) {
405             CLinker.UpcallStub comparFunc = LINKER.upcallStub(
406                 comparHandle,
407                 FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS), scope);
408 
409             MemorySegment array = scope.allocateArray(JAVA_INT, new int[] { 0, 9, 3, 4, 6, 5, 1, 8, 2, 7 });
410             qsort.invoke(array, 10L, 4L, comparFunc);
411             int[] sorted = array.toArray(JAVA_INT); // [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
412             System.out.println(Arrays.toString(sorted));
413         }
414     }
415 
416     public static void printf() throws Throwable {
417         MethodHandle printf = LINKER.downcallHandle(
418                 LINKER.lookup("printf").get(),
419                 FunctionDescriptor.of(JAVA_INT, ADDRESS).asVariadic(JAVA_INT, JAVA_INT, JAVA_INT)
420         );
421         try (ResourceScope scope = ResourceScope.newConfinedScope()) {
422             MemorySegment s = scope.allocateUtf8String("%d plus %d equals %d\n");
423             printf.invoke(s, 2, 2, 4);
424         }
425     }
426 
427     public static void vprintf() throws Throwable {
428 
429         MethodHandle vprintf = LINKER.downcallHandle(
430                 LINKER.lookup("vprintf").get(),
431                 FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS));
432 
433         try (ResourceScope scope = ResourceScope.newConfinedScope()) {
434             MemorySegment s = scope.allocateUtf8String("%d plus %d equals %d\n");
435             VaList vlist = VaList.make(builder ->
436                      builder.addVarg(JAVA_INT, 2)
437                             .addVarg(JAVA_INT, 2)
438                             .addVarg(JAVA_INT, 4), scope);
439             vprintf.invoke(s, vlist);
440         }
441     }
442 }
443 ```
444 
445 
446 
447 * <a id="1"/>(<sup>1</sup>):<small> In the future, we might add more ways to obtain a symbol lookup — for instance: `SymbolLookup.ofLibrary(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. However, adding these new mode will require some additional foundational work on the `CLinker` support — as we need to make sure that the memory address used by a downcall method handle cannot be unloaded while the downcall method handle is being invoked.</small>
448 * <a id="2"/>(<sup>2</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>
449 * <a id="3"/>(<sup>3</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)scope.allocateUtf8String("Hello"));`</small>
450