.cognition/skills/migrate-jna/SKILL.md
Migrate from JNA to a modern native access library (eliminate sun.misc.Unsafe warnings)
npx skillsauth add fglock/perlonjava migrate-jnaInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
JNA 5.18.1 uses sun.misc.Unsafe::staticFieldBase internally, which produces deprecation warnings on Java 21+ and will break in future JDK releases. The project needs to migrate to a library that uses supported APIs.
The choice of replacement library is TBD. Evaluate these options:
com.github.jnr:jnr-posixFileStat, kill(), waitpid(), umask(), utime()), built on jnr-ffi (no sun.misc.Unsafe)java.lang.foreign (JDK built-in)com.github.jnr:jnr-ffisun.misc.Unsafe, flexible10 files use JNA. All paths relative to src/main/java/org/perlonjava/.
| File | JNA Usage |
|------|-----------|
| runtime/nativ/PosixLibrary.java | POSIX C library bindings: stat, lstat, chmod, chown, getpid, getppid, setpgid, getpgid, setsid, tcsetpgrp, tcgetpgrp, getpgrp, setpgrp |
| runtime/nativ/WindowsLibrary.java | Windows kernel32 bindings: GetCurrentProcessId, _getpid |
| runtime/nativ/NativeUtils.java | JNA Platform utilities: getpid(), getuid(), geteuid(), getgid(), getegid(), plus CLibrary for getpriority/setpriority/alarm/getlogin |
| runtime/nativ/ExtendedNativeUtils.java | Additional POSIX: getpwuid, getpwnam, getgrnam, getgrgid (passwd/group lookups) |
| File | Operations Used |
|------|----------------|
| runtime/operators/Stat.java | PosixLibrary.stat(), PosixLibrary.lstat() — all 13 stat fields (dev, ino, mode, nlink, uid, gid, rdev, size, atime, mtime, ctime, blksize, blocks) |
| runtime/operators/Operator.java | PosixLibrary.chmod(), PosixLibrary.chown(), NativeUtils for pid/uid/gid |
| runtime/operators/KillOperator.java | PosixLibrary.kill() for sending signals, NativeUtils.getpid() |
| runtime/operators/WaitpidOperator.java | JNA CLibrary.waitpid() with WNOHANG/WUNTRACED flags, macros WIFEXITED/WEXITSTATUS/WIFSIGNALED/WTERMSIG/WIFSTOPPED/WSTOPSIG |
| runtime/operators/UmaskOperator.java | JNA CLibrary.umask() |
| runtime/operators/UtimeOperator.java | JNA CLibrary.utimes() with timeval struct |
Migrate in this order (least to most complex):
UmaskOperator.java — single umask() callKillOperator.java — kill() + getpid()UtimeOperator.java — utimes() with structOperator.java — chmod(), chown(), pid/uid/gidWaitpidOperator.java — waitpid() with flag macrosStat.java — stat()/lstat() with 13-field structNativeUtils.java / ExtendedNativeUtils.java — passwd/group lookupsbuild.gradle and pom.xml--enable-native-access=ALL-UNNAMED from jperl launcher (if no longer needed)sun.misc.Unsafe warning is goneALWAYS use make commands. NEVER use raw mvn/gradlew commands.
| Command | What it does |
|---------|--------------|
| make | Build + run all unit tests (use before committing) |
| make dev | Build only, skip tests (for quick iteration) |
| make test-all | Run extended test suite |
After each file migration:
make # Build + unit tests (must pass)
make test-all # Check for regressions in extended tests
Key tests that exercise native operations:
perl5_t/t/op/stat.t — stat/lstat fieldsperl5_t/t/io/fs.t — chmod, chown, utimeperl5_t/t/op/fork.t — kill, waitpidsrc/test/resources/unit/glob.t — readdir (uses stat internally)# gradle/libs.versions.toml
jna = "5.18.1"
jna = { module = "net.java.dev.jna:jna", version.ref = "jna" }
jna-platform = { module = "net.java.dev.jna:jna-platform", version.ref = "jna" }
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
</dependency>
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna-platform</artifactId>
</dependency>
kernel32 (GetCurrentProcessId), msvcrt (_getpid, stat)development
# PerlOnJava Debugging Skills and Architecture Knowledge This document captures key knowledge about PerlOnJava internals learned during debugging sessions. ## Variable Storage and Scoping ### Three Types of Variable Declarations 1. **`my` variables** - Lexical scope - Stored in JVM local variable slots during normal execution - When captured by closures: stored as closure fields or in GlobalVariable with IDs - Symbol table entry: `decl = "my"`, has `index` (JVM slot number) 2. **`o
development
# PerlOnJava Interpreter Developer Guide - name all test files /tmp/test.pl ## Quick Reference **Performance:** 46.84M ops/sec (1.75x slower than compiler ✓) **Opcodes:** 0-157 (contiguous) for JVM tableswitch optimization **Runtime:** 100% API compatibility with compiler (zero duplication) ### Testing Modes **JPERL_EVAL_USE_INTERPRETER=1** - Forces all eval STRING to use the interpreter - Used for testing interpreter implementation of operators in eval context - Compiler still used for mai
development
# Profile PerlOnJava ## ⚠️⚠️⚠️ CRITICAL: NEVER USE `git stash` ⚠️⚠️⚠️ **DANGER: Changes are SILENTLY LOST when using git stash/stash pop!** - NEVER use `git stash` to temporarily revert changes - INSTEAD: Commit to a WIP branch or use `git diff > backup.patch` - This warning exists because completed work was lost during debugging Profile and optimize PerlOnJava runtime performance using Java Flight Recorder. ## Git Workflow **IMPORTANT: Never push directly to master. Always use feature bra
development
# Port CPAN Module to PerlOnJava ## ⚠️⚠️⚠️ CRITICAL: NEVER USE `git stash` ⚠️⚠️⚠️ **DANGER: Changes are SILENTLY LOST when using git stash/stash pop!** - NEVER use `git stash` to temporarily revert changes - INSTEAD: Commit to a WIP branch or use `git diff > backup.patch` - This warning exists because completed work was lost during debugging This skill guides you through porting a CPAN module with XS/C components to PerlOnJava using Java implementations. ## When to Use This Skill - User as