A piece of C/C++ code could provide a JNI method with an array of function pointers. But is there a way to call to the stack the functions that array's pointers are pointing to, directly from inside Java code (without using JNI or similar)? JNI somehow does something like that, so there must be a way. How does JNI do it? Is it via sun.misc.Unsafe? Even if it is not, could we use some Unsafe workaround to get our hands on the JVM code that does that?
I don't plan to use that commercially of course. I'm not even a professional, I just really enjoy coding and I've been studying CUDA lately so I thought maybe I could experiment with mixing everything together, but the overhead of JNI calls would defeat the purpose of having GPU accelerated code.
JNI provides functions for accessing the contents of array objects. While arrays of objects must be accessed one entry at a time, arrays of primitives can be read and written directly as if they were declared in C.
typedef jobject jclass; In C++, JNI introduces a set of dummy classes to enforce the subtyping relationship. For example: class _jobject {}; class _jclass : public _jobject {}; ...
In software design, the Java Native Interface (JNI) is a foreign function interface programming framework that enables Java code running in a Java virtual machine (JVM) to call and be called by native applications (programs specific to a hardware and operating system platform) and libraries written in other languages ...
JNI has already been optimized a lot, you should give it a try first. But it indeed has certain overhead, see details.
This overhead can be significant if a native function is simple and is called frequently. JDK has a private API called Critical Natives to reduce overhead of calling functions that do not require much of JNI functionality.
A native method must satisfy the following conditions to become a critical native:
The declaration of a critical native looks like a regular JNI method, except that
JavaCritical_
instead of Java_
;JNIEnv*
and jclass
arguments;GetArrayElements
and friends, you can instantly use a direct array pointer.E.g. a JNI method
JNIEXPORT jint JNICALL Java_com_package_MyClass_nativeMethod(JNIEnv* env, jclass klass, jbyteArray array) { jboolean isCopy; jint length = (*env)->GetArrayLength(env, array); jbyte* buf = (*env)->GetByteArrayElements(env, array, &isCopy); jint result = process(buf, length); (*env)->ReleaseByteArrayElements(env, array, buf, JNI_ABORT); return result; }
will turn to
JNIEXPORT jint JNICALL JavaCritical_com_package_MyClass_nativeMethod(jint length, jbyte* buf) { return process(buf, length); }
Critical natives are supported only in HotSpot JVM starting from JDK 7. Moreover, "critical" version is called only from compiled code. Therefore you need both critical and standard implementation to make this work correctly.
This feature was designed for internal use in JDK. There is no public specification or something. Probably the only documentation you may find is in the comments to JDK-7013347.
This benchmark shows critical natives can be several times faster than regular JNI methods when the native workload is very small. The longer is method, the smaller is relative overhead.
P.S. There is an ongoing work in JDK to implement Native MethodHandles that will serve as a faster alternative to JNI. However it is unlikely to appear prior to JDK 10.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With