Skip to content

Replace JNR-POSIX with Java FFM API#380

Merged
fglock merged 15 commits intomasterfrom
feature/ffm-migration
Mar 26, 2026
Merged

Replace JNR-POSIX with Java FFM API#380
fglock merged 15 commits intomasterfrom
feature/ffm-migration

Conversation

@fglock
Copy link
Owner

@fglock fglock commented Mar 26, 2026

Summary

This PR migrates PerlOnJava from JNR-POSIX to Java's Foreign Function & Memory (FFM) API (JEP 454), eliminating the sun.misc.Unsafe warnings on Java 24+.

Problem

JNR-POSIX depends on JFFI, which uses sun.misc.Unsafe for native memory access. Starting with Java 24 (JEP 498), warnings are issued by default, and these methods are scheduled for removal.

Solution

Migrate to Java's FFM API (finalized in Java 22), which provides a safe, supported replacement for native function calls.

Changes

Phase 1-2: Infrastructure & Simple Functions

  • Created FFM framework with platform detection (Linux, macOS, Windows)
  • Implemented getuid, geteuid, getgid, getegid, getpid, getppid, umask, chmod, kill, isatty
  • Added $< (REAL_UID) and $> (EFFECTIVE_UID) special variables

Phase 3: Struct-Based Functions

  • Implemented stat() and lstat() with platform-specific struct layouts
  • Implemented getpwnam, getpwuid, getpwent, setpwent, endpwent
  • Added proper errno capture using Linker.Option.captureCallState()

Phase 4-5: Windows Support & Migration

  • Windows uses Java fallbacks (ProcessHandle, NIO)
  • FFM enabled by default
  • Updated Java minimum version to 22

Phase 6: Cleanup

  • Removed JNR-POSIX dependency from build.gradle and libs.versions.toml
  • Removed --sun-misc-unsafe-memory-access flag from jperl/jperl.bat
  • Updated documentation

Files Migrated to FFM

  • NativeUtils (getuid, geteuid, getgid, getegid, getpid, getppid)
  • Stat (stat, lstat)
  • KillOperator (kill)
  • Operator (chmod)
  • FileTestOperator, DebugHooks (isatty)
  • UmaskOperator (umask)
  • IOOperator (fcntl)
  • UtimeOperator (utimes)
  • WaitpidOperator (waitpid)
  • ExtendedNativeUtils (getpwnam, getpwuid, getpwent, setpwent, endpwent)
  • POSIX (strerror)

Design Doc

See dev/design/ffm_migration.md for implementation details.

Test Plan

  • Build succeeds with make
  • All 122 unit tests pass
  • FFM enabled by default
  • No regressions on macOS
  • CI verification on Linux and Windows

Generated with Devin

fglock and others added 11 commits March 26, 2026 11:02
- Add jprove.bat: Windows batch wrapper for jprove test harness
- Fix jperl/jperl.bat: Apply --sun-misc-unsafe-memory-access=allow only for Java 24+
  (flag introduced in Java 23, default changed to 'warn' in Java 24 per JEP 498)
- Add FFM migration design doc: Plan to replace JNR-POSIX with Java FFM API
- Update testing.md: Document Windows support for jprove

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Add FFM framework for replacing JNR-POSIX with Java Foreign Function & Memory API:

- FFMPosixInterface.java: Interface defining all POSIX functions
- FFMPosix.java: Factory with platform detection (Linux/macOS/Windows)
- FFMPosixLinux.java: Linux stub implementation
- FFMPosixMacOS.java: macOS stub (extends Linux)
- FFMPosixWindows.java: Windows implementation with Java/ProcessHandle fallbacks
- PosixLibrary.java: Add FFM integration points and feature flag docs

Feature flag: -Dperlonjava.ffm.enabled=true or PERLONJAVA_FFM_ENABLED=true

All methods throw UnsupportedOperationException in stubs, indicating
JNR-POSIX should be used until FFM implementations are complete.

See dev/design/ffm_migration.md for the full migration plan.

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Phase 5 now includes explicit steps for updating:
- build.gradle
- pom.xml
- CI workflows
- Documentation (README, QUICKSTART, installation guide, presentations)

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
… API

- Implement FFM-based getuid, geteuid, getgid, getegid, getppid, umask, chmod, kill, isatty for Linux/macOS
- Add $< (REAL_UID) and $> (EFFECTIVE_UID) special variables with lazy evaluation
- Fix getppid JVM bytecode emission - was falling through to varargs handler
- Update Java version requirement to 22 (FFM finalized in Java 22)

The FFM implementation provides direct native calls without JNA overhead.
JNR-POSIX is still used as fallback for Windows and complex structs.

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
- Add platform-specific struct stat layouts for Linux x86_64 and macOS
- Implement stat() and lstat() with proper errno capture
- Read struct fields with correct byte offsets for each platform
- Tested: values match native Perl exactly on macOS

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…, etc.)

- Add method handles for getpwnam, getpwuid, getpwent, setpwent, endpwent
- Define platform-specific struct passwd layouts for Linux and macOS
- Implement readPasswdEntry() to parse native passwd struct
- Add helper readCString() for reading null-terminated strings from native memory

Phase 3 (struct-based functions) is now complete with stat, lstat, and passwd functions.

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Phase 6 of FFM migration: complete removal of JNR-POSIX dependency.

Changes:
- Remove jnr-posix from build.gradle and libs.versions.toml
- Simplify PosixLibrary.java (FFM only, no JNR-POSIX fallback)
- Remove --sun-misc-unsafe-memory-access flag from jperl/jperl.bat
- Update documentation to remove sun.misc.Unsafe references

All native POSIX calls now use Java Foreign Function & Memory (FFM) API:
- NativeUtils: getuid, geteuid, getgid, getegid, getpid, getppid
- Stat: stat, lstat with platform-specific struct layouts
- KillOperator: kill signal handling
- Operator: chmod file permissions
- FileTestOperator, DebugHooks: isatty terminal detection
- UmaskOperator: umask file creation mask
- IOOperator: fcntl file descriptor control
- UtimeOperator: utimes file timestamp modification
- WaitpidOperator: waitpid process management
- ExtendedNativeUtils: getpwnam, getpwuid, getpwent, setpwent, endpwent
- POSIX: strerror error messages

Benefits:
- No more sun.misc.Unsafe deprecation warnings on Java 24+
- Reduced dependency footprint
- Uses standard Java API (FFM finalized in Java 22)

Tested: All 122 unit tests pass.

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@fglock fglock changed the title WIP: Replace JNR-POSIX with Java FFM API Replace JNR-POSIX with Java FFM API Mar 26, 2026
fglock and others added 4 commits March 26, 2026 11:49
FFM (Foreign Function & Memory) API was finalized in Java 22 (JEP 454).
In Java 21, FFM is still a preview API which causes compilation errors.

Changes:
- Update CI workflow to use Java 22
- Update pom.xml compiler source/target to 22
- Remove JNR-POSIX from pom.xml dependencies
- Update QUICKSTART.md, installation.md, java-integration.md
- Update presentation slides
- Update Dockerfile to use eclipse-temurin:22-jdk
- Update build.gradle comment

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
The Dockerfile had an outdated JAR reference (3.0.0) that was missed
during previous version updates. Now that it matches the current version,
Configure.pl will correctly update it on future version changes.

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@fglock fglock marked this pull request as ready for review March 26, 2026 11:05
@fglock fglock merged commit 468444d into master Mar 26, 2026
2 checks passed
@fglock fglock deleted the feature/ffm-migration branch March 26, 2026 11:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant