Independent-Society-of-Knowledge / Kotlin-For-Science

Kotlin for science is an open-source project to develop and maintain libraries for Kotlin that are used in Science.
GNU General Public License v2.0
17 stars 1 forks source link

[jvm] passing Heap References to Native - Linker Option Critical #3

Open nort3x opened 1 month ago

nort3x commented 1 month ago

upon inspection of this interesting openjdk-issue it's apparently now possible to pass heap-segments to native (but not advised cause it can possible lock the GC)

but as we can read in jextract docs:

Linker options. It is currently not possible to tell jextract to use linker options to link a particular function. Code will have to be edited manually to add them. (for instance, if the function sets errno, the Linker.Option.captureCallState option has to be added manually).

it's not trivial on how to edit the generated bindings for JVM, atleast in a clean, straight forward way (i could traverse the classes at runtime and re-every function handles, but thats a huge starting overhead and black magic for reader)

here is the modified result:

// gsl_vector_view_array is modified
fun main(){
    val a = doubleArrayOf(1.0,2.0,3.0)
    val s = GSLBLAS.gsl_vector_view_array(Arena.ofAuto(), a.segment, a.size.toLong())
    GSLBLAS.gsl_blas_daxpy(1.0, s, s)
    println(a.toList()) // [2.0, 4.0, 6.0]
}

please notice that no off-heap copy is made and the changes are instant on the on-heap jvm array (hence no transformation)

modification:

private static class gsl_vector_view_array {

    // public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC);
    // notice modification here \|/
    public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC, Linker.Option.critical(true));

    public static final FunctionDescriptor DESC = FunctionDescriptor.of(
          _gsl_vector_view.layout(),
          GSLBLAS.C_POINTER,
          GSLBLAS.C_LONG
       );

     public static final MemorySegment ADDR = GSLBLAS.findOrThrow("gsl_vector_view_array");
}

i also need to cite this piece of document from oracle:

A critical function is a function that has an extremely short running time in all cases (similar to calling an empty function), and does not call back into Java (e.g. using an upcall stub).

Using this linker option is a hint that some implementations may use to apply optimizations that are only valid for critical functions.

Using this linker option when linking non-critical functions is likely to have adverse effects, such as loss of performance or JVM crashes.

Critical functions can optionally allow access to the Java heap. This allows clients to pass heap memory segments as addresses, where normally only off-heap memory segments would be allowed. The memory region inside the Java heap is exposed through a temporary native address that is valid for the duration of the function call. Use of this mechanism is therefore only recommended when a function needs to do short-lived access to Java heap memory, and copying the relevant data to an off-heap memory segment would be prohibitive in terms of performance.

this topic should further be inspected and in case Linker Options is added to all method handles, the usecase should be left optional for users