- GraalVM for JDK 23 (Latest)
- GraalVM for JDK 24 (Early Access)
- GraalVM for JDK 21
- GraalVM for JDK 17
- Archives
- Dev Build
- Getting Started with Native Image
- Guides
- Native Image Basics
- Build Overview
- Reachability Metadata
- Optimizations and Performance
- Debugging and Diagnostics
- Dynamic Features
- Accessing Resources
- Certificate Management
- Dynamic Proxy
- Java Native Interface
- JCA Security Services
- Reflection
- URL Protocols
- Interoperability with Native Code
- LLVM Backend
- Workshops and Labs
Foreign Function & Memory API in Native Image
The Foreign Function & Memory (FFM) API is a native interface that enables Java code to interact with native code and vice versa.
As of JEP 442, it is a preview API of the Java platform and must be enabled with --enable-preview
.
Modules that are permitted to perform “restricted” native operations (including creating handles for calls to or from native code) must be specified using --enable-native-access=
.
This page gives an overview of support for the FFM API in Native Image.
Foreign memory #
Foreign memory functionality is generally supported. Shared arenas are currently not supported.
Foreign functions #
The FFM API enables Java code to call down to native functions, and conversely allows native code to call up to invoke Java code via method handles. These two kinds of calls are referred to as “downcalls” and “upcalls” respectively and are collectively referred to as “foreign calls”.
Currently, only downcalls are supported, and only on the AMD64 architecture.
Looking up native functions #
The FFM API provides the SymbolLookup
interface to find functions in native libraries by name.
SymbolLookup.loaderLookup()
is currently the only supported kind of SymbolLookup
.
Registering foreign calls #
In order to perform calls to native code at runtime, supporting code must be generated at image build time.
Therefore, the native-image
tool must be provided with descriptors that characterize functions to which downcalls may be performed at runtime.
These descriptors can be registered using a custom Feature
, for example:
import static java.lang.foreign.ValueLayout.*;
class ForeignRegistrationFeature implements Feature {
public void duringSetup(DuringSetupAccess access) {
RuntimeForeignAccess.registerForDowncall(FunctionDescriptor.ofVoid());
RuntimeForeignAccess.registerForDowncall(FunctionDescriptor.ofVoid(), Linker.Option.isTrivial());
RuntimeForeignAccess.registerForDowncall(FunctionDescriptor.of(JAVA_INT, JAVA_INT, JAVA_INT));
RuntimeForeignAccess.registerForDowncall(FunctionDescriptor.of(ADDRESS, JAVA_INT, JAVA_INT), Linker.Option.firstVariadicArg(1));
RuntimeForeignAccess.registerForDowncall(FunctionDescriptor.ofVoid(JAVA_INT), Linker.Option.captureCallState("errno"));
}
}
To activate the custom feature, --features=com.example.ForeignRegistrationFeature
(the fully-qualified name of the feature class) needs to be passed to native-image
.
It is recommended to do so with a native-image.properties file.
Upcalls #
Upcalls are not yet supported.