Skip to content

Commit

Permalink
Merge pull request #16 from elide-dev/feat/static-graalvm-jni-r8
Browse files Browse the repository at this point in the history
JNA: Support GraalVM (Final Review)
  • Loading branch information
sgammon authored Jun 13, 2024
2 parents 4f94c57 + 874c272 commit 664527c
Show file tree
Hide file tree
Showing 36 changed files with 2,638 additions and 80 deletions.
38 changes: 38 additions & 0 deletions .github/workflows/graalvm.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# GraalVM build and native test.
name: GraalVM CI

on:
workflow_dispatch:
workflow_call:
pull_request:
push:
branches:
- master

permissions:
contents: read

env:
ANT_OPTS: -Djava.security.manager=allow

jobs:
build:
runs-on: ubuntu-latest
name: Test GVM 22, ubuntu-latest

steps:
- uses: actions/checkout@v4
- uses: graalvm/setup-graalvm@v1
with:
java-version: '22'
distribution: 'graalvm-community'
github-token: ${{ secrets.GITHUB_TOKEN }}
- name: Linux requirements
run: sudo apt-get -y install texinfo
- uses: gradle/actions/setup-gradle@v3
- name: "Build: Compile & Install JNA"
run: ant && ant install
- name: "Build: Native Images (Dynamic JNI)"
run: ant nativeImage && ant nativeRun
- name: "Build: Native Image (Static JNI)"
run: ant nativeImageStatic && ant nativeRunStatic
240 changes: 236 additions & 4 deletions build.xml

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion common.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,15 @@
</or>
</condition>
<property name="jna.version" value="${jna.major}.${jna.minor}.${jna.revision}${version.suffix}"/>
<property name="graalvm.version" value="24.0.1" />
<property name="osgi.version" value="${jna.major}.${jna.minor}.${jna.revision}"/>
<!-- jnidispatch library release version -->
<property name="jni.major" value="7"/>
<property name="jni.minor" value="0"/>
<property name="jni.revision" value="2"/>
<property name="jni.build" value="0"/> <!--${build.number}-->
<property name="jni.version" value="${jni.major}.${jni.minor}.${jni.revision}"/>
<property name="jni.md5" value="5fb98531302accd485c534c452dd952a"/>
<property name="jni.md5" value="2758dad3ef270c95b39b70ca30de3941"/>
<property name="spec.title" value="Java Native Access (JNA)"/>
<property name="spec.vendor" value="${vendor}"/>
<property name="spec.version" value="${jna.major}"/>
Expand Down
209 changes: 209 additions & 0 deletions lib/gvm/AbstractJNAFeature.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
/* Copyright (c) 2015 Adam Marcionek, All Rights Reserved
*
* The contents of this file is dual-licensed under 2
* alternative Open Source/Free licenses: LGPL 2.1 or later and
* Apache License 2.0. (starting with JNA version 4.0.0).
*
* You can freely decide which license you want to apply to
* the project.
*
* You may obtain a copy of the LGPL License at:
*
* http://www.gnu.org/licenses/licenses.html
*
* A copy is also included in the downloadable source code package
* containing JNA, in file "LGPL2.1".
*
* You may obtain a copy of the Apache License at:
*
* http://www.apache.org/licenses/
*
* A copy is also included in the downloadable source code package
* containing JNA, in file "AL2.0".
*/
package com.sun.jna;

import org.graalvm.nativeimage.hosted.Feature;
import org.graalvm.nativeimage.hosted.RuntimeClassInitialization;
import org.graalvm.nativeimage.hosted.RuntimeJNIAccess;
import org.graalvm.nativeimage.hosted.RuntimeProxyCreation;
import org.graalvm.nativeimage.hosted.RuntimeReflection;
import org.graalvm.nativeimage.hosted.RuntimeResourceAccess;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;

/**
* Provides common logic for JNA-related GraalVM feature classes.
*
* <p>These classes should only be included at build time for a `native-image` target.</p>
*
* @since 5.15.0
* @author Sam Gammon ([email protected])
* @author Dario Valdespino ([email protected])
*/
abstract class AbstractJNAFeature implements Feature {
/**
* Obtain a reference to a method on a class, in order to register it for reflective access
*
* @param clazz Class to obtain method reference from
* @param methodName Name of the method to obtain a reference to
* @param args Method arguments
* @return Method reference
*/
protected static Method method(Class<?> clazz, String methodName, Class<?>... args) {
try {
return clazz.getDeclaredMethod(methodName, args);
} catch (NoSuchMethodException e) {
throw new IllegalStateException(e);
}
}

/**
* Obtain a reference to one or more fields on a class, in order to register them for reflective access
*
* @param clazz Class to obtain field references from
* @param fieldNames Names of the fields to obtain references to
* @return Field references
*/
protected static Field[] fields(Class<?> clazz, String... fieldNames) {
try {
Field[] fields = new Field[fieldNames.length];
for (int i = 0; i < fieldNames.length; i++) {
fields[i] = clazz.getDeclaredField(fieldNames[i]);
}
return fields;
} catch (NoSuchFieldException e) {
throw new IllegalStateException(e);
}
}

/**
* Register a class for reflective access at runtime
*
* @param clazz Class to register
*/
protected static void reflectiveClass(Class<?>... clazz) {
RuntimeReflection.register(clazz);
}

/**
* Register a resource for use in the final image
*
* @param module Module which owns the resource
* @param resource Path to the resource to register
*/
protected static void registerResource(Module module, String resource) {
RuntimeResourceAccess.addResource(module, resource);
}

/**
* Register a resource for use in the final image
*
* @param resource Path to the resource to register
*/
protected static void registerResource(String resource) {
registerResource(AbstractJNAFeature.class.getModule(), resource);
}

/**
* Register a class for JNI access at runtime
*
* @param clazz Class to register
*/
protected static void registerJniClass(Class<?> clazz) {
RuntimeJNIAccess.register(clazz);
Arrays.stream(clazz.getConstructors()).forEach(RuntimeJNIAccess::register);
Arrays.stream(clazz.getMethods()).forEach(RuntimeJNIAccess::register);
}

/**
* Register a class for JNI access at runtime, potentially with reflective access as well
*
* @param clazz Class to register
* @param reflective Whether to register the class and constructors for reflective access
*/
protected static void registerJniClass(Class<?> clazz, Boolean reflective) {
registerJniClass(clazz);
if (reflective) {
RuntimeReflection.register(clazz);
RuntimeReflection.registerAllConstructors(clazz);
}
}

/**
* Register a suite of JNA methods for use at runtime
*
* @param reflective Whether to register the methods for reflective access
* @param methods Methods to register
*/
protected static void registerJniMethods(Boolean reflective, Method... methods) {
RuntimeJNIAccess.register(methods);
if (reflective) {
RuntimeReflection.register(methods);
}
}

/**
* Register a suite of JNA methods for use at runtime
*
* @param methods Methods to register
*/
protected static void registerJniMethods(Method... methods) {
registerJniMethods(false, methods);
}

/**
* Register a suite of JNA fields for use at runtime
*
* @param reflective Whether to register the fields for reflective access
* @param fields Fields to register
*/
protected static void registerJniFields(Boolean reflective, Field[] fields) {
RuntimeJNIAccess.register(fields);
if (reflective) {
RuntimeReflection.register(fields);
}
}

/**
* Register a suite of JNA fields for use at runtime
*
* @param fields Fields to register
*/
protected static void registerJniFields(Field[] fields) {
registerJniFields(false, fields);
}

/**
* Register a combination of interfaces used at runtime as a dynamic proxy object
*
* @param classes Combination of interface classes; order matters
*/
protected static void registerProxyInterfaces(Class<?>... classes) {
RuntimeProxyCreation.register(classes);
}

/**
* Assign the specified class or classes to initialize at image build time
*
* @param clazz Classes to register for build-time initialization
*/
protected static void initializeAtBuildTime(Class<?>... clazz) {
for (Class<?> c : clazz) {
RuntimeClassInitialization.initializeAtBuildTime(c);
}
}

/**
* Assign the specified class or classes to initialize at image run-time
*
* @param clazz Classes to register for run-time initialization
*/
protected static void initializeAtRunTime(Class<?>... clazz) {
for (Class<?> c : clazz) {
RuntimeClassInitialization.initializeAtRunTime(c);
}
}
}
Loading

0 comments on commit 664527c

Please sign in to comment.