Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Java Goes Outside: FFM API, Vector API, and Beyond

Java Goes Outside: FFM API, Vector API, and Beyond

The slide for JCConf 2026 Taiwan.

Avatar for Sugiyama Takaaki

Sugiyama Takaaki

September 10, 2026

More Decks by Sugiyama Takaaki

Other Decks in Programming

Transcript

  1. JCConf TAIWAN 2026 / JAVA COMMUNITY CONFERENCE Java Goes Outside

    FFM API, Vector API, and Beyond Takaaki Sugiyama / 杉山 貴章 @zinbe
  2. IN TR O D U C T IO N About

    me • Takaaki Sugiyama • @zinbe / @zinbe.bsky.social • Software Engineer • Technical Writer / Author • Board member of Japan Java User Group (JJUG) • Director of CCC Association JCConf 2025: Building a Community for Developer to Connect →
  3. AGE ND A What we'll cover today • What "going

    outside" means for Java • FFM API • native code and memory • Vector API • the CPU’s SIMD instructions • Project Babylon • GPUs and accelerators
  4. W H Y JA VA G O ES O U

    T S ID E The "outside world" = beyond the JVM • “Write Once, Run Anywhere” — Java's original promise • Anything platform-specific is hidden beneath the JVM abstraction • Everything past that boundary is the "outside world" Java application JVM “Hiding” was Java's strength OS · CPU · hardware hidden below this line Outside
  5. T H E JN I ER A JNI – Java

    Native Interface • An API for calling native code (C/C++) from Java — and Java from native code • Gives Java access to OS-specific features • Serial ports, for example • Has been part of Java since 1.1 (1997)
  6. T H E JN I ER A The JNI example

    Java program Serial communication Arduino
  7. T H E JN I ER A Blinking an LED

    with Java and Arduino — JNI Main Java Program C header file Interface for serial communication C native library Wrapper class for C function OS system call Arduino sketch
  8. T H E JN I ER A The Arduino sketch

    Led_blink.ino const int LED_PIN = 18; // Use GPIO 18 void loop() { if (Serial.available() > 0) { char command = Serial.read(); if (command == ‘1’) { digitalWrite(LED_PIN, HIGH); } else if (command == '0’) { digitalWrite(LED_PIN, LOW); } } }
  9. T H E JN I ER A Wrapper class and

    C header SerialPortNative.java SerialPortNative.h (Auto generated) public class SerialPortNative { static { System.loadLibrary("serialport"); } #include <jni.h> Load C library public native int openPort (String portName); public native int closePort(int fd); public native int writeData (int fd, byte[] data, int length); } Wrapper for system call (open/close/write) C header file for JNI #ifndef _Included_SerialPortNative #define _Included_SerialPortNative JNIEXPORT jint JNICALL Java_SerialPortNative_openPort (JNIEnv *, jobject, jstring); JNIEXPORT jint JNICALL Java_SerialPortNative_closePort (JNIEnv *, jobject, jint); JNIEXPORT jint JNICALL Java_SerialPortNative_writeData (JNIEnv *, jobject, jint, jbyteArray, jint); #endif javac -h OUTPUT_DIR SerialPortNative.java
  10. T H E JN I ER A C native library

    SerialPortNative.c #include "SerialPortNative.h" JNIEXPORT jint JNICALL Java_SerialPortNative_openPort (JNIEnv *env, jobject obj, jstring portName) { const char *port = (*env)->GetStringUTFChars(env, portName, NULL); int fd = open(port, O_RDWR | O_NOCTTY | O_NONBLOCK); // Setting for serial communication return fd; gcc -shared -fPIC ¥ -I“$JAVA_HOME/include” ¥ -I”$JAVA_HOME/include/darwin” ¥ -o libserialport.dylib \ SerialPortNative.c } JNIEXPORT jint JNICALL Java_SerialPortNative_closePort (JNIEnv *env, jobject obj, jint fd) { ... } JNIEXPORT jint JNICALL Java_SerialPortNative_writeData (JNIEnv *env, jobject obj, jint fd, jbyteArray data, jint length) { ... } libserialport.dylib
  11. T H E JN I ER A Interface for serial

    communication SerialPort.java public class SerialPort implements AutoCloseable { private final SerialPortNative nativePort; private final int fd; public SerialPort(String portName) throws Exception { this.nativePort = new SerialPortNative(); this.fd = nativePort.openPort(portName); } public void sendCommand(char command) { byte[] data = new byte[] { (byte) command }; nativePort.writeData(fd, data, 1); } public void close() { nativePort.closePort(fd); } } Port open Write some data Port close
  12. T H E JN I ER A Main Java program

    LedBlinker.java public class LedBlinker implements AutoCloseable { private final SerialPort serialPort; public LedBlinker(String portName) throws Exception { this.serialPort = new SerialPort(portName); Connect } public void blink(int times, int delayMs) throws InterruptedException { for (int i = 0; i < times; i++) { serialPort.sendCommand(‘1’); Turn on Thread.sleep(delayMs); serialPort.sendCommand(‘0’); Turn off Thread.sleep(delayMs); } } public static void main(String[] args) { String port = "/dev/cu.usbserial-110"; try (LedBlinker blinker = new LedBlinker(port)) { // 5times,500ms blinker.blink(5, 500); } catch (Exception e) { e.printStackTrace(); } public void close() { serialPort.close(); } } }
  13. T H E JN I ER A Finally, I did

    java -Djava.library.path=LIB_DIR LedBlinker
  14. T H E JN I ER A ......This is a

    hassle Complicated to implement Requires knowledge of C Not type-safe Manual memory management All I want to do was just talk to a serial port…
  15. W H Y JA VA G O ES O U

    T S ID E Why so complex? I can't remember who it was, but I was talking to one of the engineers back in the Sun days and expressing my frustration with JNI being hard to use. That's when he said it had been developed that way to encourage people NOT to use it… — Simon Ritter, Deputy CTO of Azul Hard to use — by design, not by accident
  16. W H Y JA VA G O ES O U

    T S ID E The times changed What's out there now Native Libraries SIMD GPU · TPU · FPGA A vast body of existing code — image processing, machine learning, cryptography, numerical computing The CPU's own instructions. AVX-512 processes 16 floats at once Parallel computation is no longer a specialist niche Not being able to use them stopped being the price of safety.
  17. W H Y JA VA G O ES O U

    T S ID E The path Java chose 1 Hide it beneath an abstraction 2 Hand it off to another language 3 Make the outside world expressible in Java You sacrifice both performance and expressiveness The JNI world. The complexity stays The path Java chose
  18. W H Y JA VA G O ES O U

    T S ID E The map of this session The outside world Java's answer What became in Java Native code and memory FFM API Memory and function calls The CPU's SIMD instructions Vector API Vector arithmetic GPUs and accelerators Project Babylon Code itself
  19. https://openjdk.org/jeps/454 FFM API What is FFM API • An API

    for working with native memory and native functions from Java, safely and efficiently • Released in Java 22 (March 2024) • An output of OpenJDK Project Panama Goals • Replace JNI with something usable • Reduce overhead • Manage native memory safely
  20. FFM API The structure changes Main Java Program Arduino sketch

    Interface for serial communication OS system call
  21. FFM API Components of FFM API Foreign Memory API Foreign

    Function API Safely manage native memory Calling native functions (JNI replacement) Key features Key features • Arena • MemorySegment • MemoryLayout • SymbolLookup • Linker • FunctionDescriptor
  22. FFM API · M E MO R Y Arena —

    managing the lifetime of memory • An Arena has a scope, and every segment allocated from it is tied to that scope • When memory is released, and which threads may access it, are both decided by the Arena • Four kinds: Global / Automatic / Confined / Shared try (Arena arena = Arena.ofConfined()) { // All memory allocated // here becomes // inaccessible once the // scope is left }
  23. FFM API · M E MO R Y MemorySegment —

    a region of native memory // Allocate memory MemorySegment segment = arena.allocate(100); // Write data segment.set(ValueLayout.JAVA_INT, 0, 42); segment.set(ValueLayout.JAVA_BYTE, 4, (byte) 5); // Read data int value = segment.get(ValueLayout.JAVA_INT, 0); • Out-of-bounds access throws an exception • Once the Arena is closed, the segment becomes inaccessible automatically In C these are segfaults — or worse, code that appears to work
  24. FFM API · M E MO R Y MemoryLayout —

    the shape of data in memory C Java struct Point { int x; int y; }; StructLayout pointLayout = MemoryLayout.structLayout( ValueLayout.JAVA_INT.withName("x"), ValueLayout.JAVA_INT.withName("y") ); • ValueLayout — primitives (JAVA_INT, JAVA_LONG, …) • StructLayout — structs • SequenceLayout — a repetition of the same layout
  25. FFM API · F UNCT IO NS Three pieces of

    the Foreign Function API • SymbolLookup: Finds a function's address in a library • defaultLookup(): Search the standard C library (libc) • libraryLookup(): Search the library at the specified path • loaderLookup(): Search for a library loaded via System.loadLibrary() • Linker: Turns the native function address into a MethodHandle • downcallHandle(): Native function call from Java • upcallStub(): Pass a callback function to native code • FunctionDescriptor: Define the signature information for native functions.
  26. FFM API · F UNCT IO NS Example: Calling strlen()

    Linker linker = Linker.nativeLinker(); SymbolLookup stdlib = linker.defaultLookup(); MethodHandle strlen = linker.downcallHandle( stdlib.find("strlen").orElseThrow(), FunctionDescriptor.of(ValueLayout.JAVA_LONG, ValueLayout.ADDRESS)); try (Arena arena = Arena.ofConfined()) { MemorySegment str = arena.allocateFrom("Hello"); long len = (long) strlen.invokeExact(str); }
  27. FFM API · F UNCT IO NS Example: Calling strlen()

    Linker linker = Linker.nativeLinker(); SymbolLookup stdlib = linker.defaultLookup(); MethodHandle strlen = linker.downcallHandle( stdlib.find("strlen").orElseThrow(), FunctionDescriptor.of(ValueLayout.JAVA_LONG, ValueLayout.ADDRESS)); try (Arena arena = Arena.ofConfined()) { MemorySegment str = arena.allocateFrom("Hello"); long len = (long) strlen.invokeExact(str); } Still complex
  28. https://jdk.java.net/jextract/ FFM API · T O O LIN G jextract

    • Generates Java bindings mechanically from a C header file • Another output of Project Panama • Currently an early-access build, installed separately jextract --output classes -t org.unix /usr/include/string.h ↓ public static long strlen(MemorySegment __s) { ...... } long length = (long) org.unix.string_h.strlen(str);
  29. FFM API · E CO S YST E M https://www.pi4j.com/about/info-v4/

    Another example: Raspberry Pi • Direct hardware control via GPIO • Calling the C library libgpiod through the FFM API Pi4J V4 · February 2026 • The standard library for GPIO, I2C, SPI and PWM from Java • V4 moved to Java 25 and added an FFM API plugin • Native libraries are the heart of Pi4J — and that heart is now FFM Providers are pluggable PiGpio JNI-based GpioD libgpiod-based LinuxFS Linux filesystem-based FFM FFM API-based
  30. FFM API · S AFE T Y https://openjdk.org/jeps/8305968 Is FFM

    API really safe? You get some warnings when running it • JEP draft: Integrity by Default - Disable or warn by default for unsafe features • Some FFM API methods are inherently unsafe • Linker.downcallHandle, SymbolLookup.libraryLookup, … • JNI, sun.misc.Unsafe, some parts of reflection are also unsafe Going outside requires explicit permission
  31. VE CTO R A PI The map, revisited The outside

    world Java's answer What became in Java Native code and memory FFM API Memory and function calls The CPU's SIMD instructions Vector API Vector arithmetic GPUs and accelerators Project Babylon Code itself
  32. VE CTO R A PI SIMD One instruction, multiple data

    Scalar a[0]+b[0] → a[1]+b[1] → a[2]+b[2] → a[3]+b[3] 4 operations SIMD a[0..3] + b[0..3] 1 operation SSE AVX AVX-512 ARM SVE 4 floats 8 floats 16 floats up to 16 The CPU always had this. Java just had no explicit way to use it
  33. https://openjdk.org/jeps/537 VE CTO R A PI What is Vector API

    Compile to SIMD instructions on CPUs at run time Core concepts VectorSpecies Vector<E> A combination of element type and vector length. FloatVector.SPECIES_PREFERRED picks the best one for the runtime environment A fixed-length sequence of elements: FloatVector, IntVector, DoubleVector, ByteVector, … Lane VectorMask The position of each element within a vector Controls, per lane, whether the operation applies
  34. VE CTO R A PI Why auto-vectorization isn't enough HotSpot

    does auto-vectorize. However — • The JIT analyses loops and converts them to SIMD instructions automatically • But there is no guarantee about when it kicks in • Results vary with how the loop is written, the JVM version, and the CPU • Complex algorithms are never recognised in the first place • Vectorized hashCode, specialised array comparisons, and so on “it'll probably be faster” → “it will be faster”
  35. VE CTO R A PI Code example: a dot product

    Scalar Vector API float sum = 0f; for (int i = 0; i < a.length; i++) { sum += a[i] * b[i]; } static final VectorSpecies<Float> SPECIES = FloatVector.SPECIES_PREFERRED; FloatVector vsum = FloatVector.zero(SPECIES); int upperBound = SPECIES.loopBound(a.length); for (int i = 0; i < upperBound; i += SPECIES.length()) { var va = FloatVector.fromArray(SPECIES, a, i); var vb = FloatVector.fromArray(SPECIES, b, i); vsum = va.fma(vb, vsum); // vsum += va * vb } float sum = vsum.reduceLanes(VectorOperators.ADD); // tail elements handled separately It is longer to write. In exchange, you get the instructions as you write.
  36. VE CTO R A PI Where does it pays off

    Anywhere the same operation repeats over a lot of data • Machine learning • Image processing • Linear algebra • Cryptography • Financial computation • The JDK’s own internals
  37. VE CTO R A PI Still in the incubator stage

    • Introduced in JDK 16 (March 2021) • JEP 529 in JDK 26 as the Eleventh Incubator • JDK 27 has JEP 537 planned — The Twelfth Incubator • Requires --add-modules jdk.incubator.vector The Vector API will incubate until Value Objects (the features of Project Valhalla) become available as preview features. JEP 401: Value Objects (Preview) is targeted in JDK 28 (planned for March 2027)
  38. D EM O · V EC T OR AP I

    The scalar version for (int px = 0; px < width; px++) { float cx = cxs[px]; float x = 0f, y = 0f; int iter = 0; while (x * x + y * y <= 4f && iter < maxIter) { float xt = x * x - y * y + cx; y = (x * y) * 2f + cy; x = xt; iter++; } iters[px] = iter; } How many times this loop runs depends on the data • Every pixel escapes at a different iteration • The JIT cannot know the trip count in advance • Exactly the case autovectorization does not handle
  39. D EM O · V EC T OR AP I

    The vector version: the shape for (int px = 0; px < width; px += SPECIES.length()) { FloatVector cx = FloatVector.fromArray(SPECIES, cxs, px); FloatVector cy = FloatVector.broadcast(SPECIES, cyScalar); FloatVector x = FloatVector.zero(SPECIES); FloatVector y = FloatVector.zero(SPECIES); FloatVector iter = FloatVector.zero(SPECIES); for (int i = 0; i < maxIter; i++) { // the same arithmetic, on whole vectors // + three lines that do the real work } iter.intoArray(iterCounts, px); } • The outer loop advances by SPECIES.length() pixels at a time • The while became a for — a fixed count, up to maxIter • “When does this pixel stop?” moves out of the loop condition
  40. D EM O · V EC T OR AP I

    The vector version: the mask VectorMask<Float> active = x2.add(y2).lt(4f); if (!active.anyTrue()) break; iter = iter.add(1f, active);
  41. D EM O · V EC T OR AP I

    The numbers Time Speedup Scalar 2685 ms 1.0× Vector API / ARM NEON – 4 lanes 775 ms 3.46× Vector API / AVX-512 – 16 lanes 288 ms 9.32× Why isn't the speedup equal to the lane count? Lanes that escape early still run until the last lane in their group finishes. You pay for the slowest pixel in every group. Isn't this just parallelism? No — one thread, one core. SIMD is width, not thread count. And the two compose.
  42. PR O JE CT B AB YL ON The map,

    revisited The outside world Java's answer What became in Java Native code and memory FFM API Memory and function calls The CPU's SIMD instructions Vector API Vector arithmetic GPUs and accelerators Project Babylon Code itself
  43. PR O JE CT B AB YL ON https://openjdk.org/projects/babylon/ What

    is Project Babylon • A project to extend Java's reach to “foreign programming models” • GPUs, machine learning models, SQL, differentiable programming Code Model Code Reflection API A symbolic representation of code, generated by the compiler, at a higher level than bytecode An API for accessing, manipulating and transforming the Code Model at runtime Not a JEP yet — the priority is getting code reflection designed correctly
  44. PR O JE CT B AB YL ON What's new

    about Code Reflection @CodeReflection static float compute(float a, float b) { return a * b + 1.0f; } • Traditional reflection: inspects the structure — classes, methods, fields • Code Reflection: extracts the meaning of a computation as a symbolic representation Bytecode Code Model “how to execute it” “what is being computed”
  45. PR O JE CT B AB YL ON HAT —

    Heterogeneous Accelerator Toolkit Java → Code Model → GPU driver binary • Backends: OpenCL C, CUDA PTX (SPIR-V in development) • NDRange API (thread configuration), iFaceMapper (memory layout), Accelerator (device selection) No C No separate kernel source files No JNI
  46. PR O JE CT B AB YL ON It's not

    just GPUs GPU execution Generative AI inference HAT ONNX models running inside Java Automatic differentiation Query translation Training neural networks Something like C#'s LINQ, in Java Still experimental — try it today with --add-modules jdk.incubator.code
  47. WR AP -UP The completed map The outside world Java's

    answer What became in Java Status Native code and memory FFM API Memory and function calls Final in Java 22 The CPU's SIMD instructions Vector API Vector arithmetic Incubator, waiting on Valhalla GPUs and accelerators Project Babylon Code itself Experimental, pre-JEP Only the FFM API is finished. We are partway there.
  48. WR AP -UP Summary What Java chose was to speak

    about the outside world in its own language FFM API Native interop in Java has fundamentally changed. The ecosystem is moving too, as Pi4J V4 shows. Vector API Makes the CPU's capabilities explicitly available from Java. Progress on Valhalla may change the situation. Project Babylon Trying to widen the reach of Java itself. We’re halfway there. It's going to keep getting better.
  49. Java is now stepping out beyond the JVM. To boldly

    go where Java has never gone before. 勇踏 Java 前所未至之境 謝謝
  50. WR AP -UP References • OpenJDK — https://openjdk.org/ • JEP

    454: Foreign Function & Memory API — https://openjdk.org/jeps/454 • JEP 472: Prepare to Restrict the Use of JNI — https://openjdk.org/jeps/472 • JEP 529: Vector API (Eleventh Incubator) — https://openjdk.org/jeps/529 • JEP 401: Value Objects (Preview) — https://openjdk.org/jeps/401 • JEP draft: Integrity by Default — https://openjdk.org/jeps/8305968 • Project Babylon — https://openjdk.org/projects/babylon/ • jextract — https://jdk.java.net/jextract/ • Pi4J — https://www.pi4j.com/