On 12/12/2018 12:34 am, Magnus Ihse Bursie wrote:
On 2018-12-11 00:23, David Holmes wrote:
Hi Magnus,
On 10/12/2018 11:19 pm, Magnus Ihse Bursie wrote:
I propose that we introduce a new define, available to all JDK native
files (Hotspot included), called JDK_EXPORT. The behavior of this
symbol will be very similar (as of now, in fact identical) to
JNIEXPORT; however, the semantics will not.
Currently, we "mis-use" the JNIEXPORT define to mark a function for
exporting from the library. The problem with this is that JNIEXPORT
is part of the JNI interface, and is supposed to be used when C
programs interact with Java. And, when doing this, the function
should be fully decorated like this: "JNIEXPORT foo JNICALL".
I've seen a lot of the emails on this issue and I don't fully
understand what has been going wrong. But the intent is obviously the
JNIEXPORT represents what is needed to export this function for use by
JNI, while JNICALL defines the calling convention. I agree there may
be some mistmatch when functions are actually not intended for general
export outside the JDK but are only for internal JDK use.
We do have many such JNI exports in our native libraries, but we also
have a lot of other, non-JNI exports, where one native library just
provides an interface to other libraries. In these cases, we have
still used JNIEXPORT for the functionality of getting the function
exported, but we have not been consistent in our use of JNICALL. This
has caused us way too much trouble for something that should Just
Work<tm>.
Are you suggesting that the interface between different libraries in
the JDK should not be a JNI interface? Is this because you think the
functions in these libraries are only for JDK internal use or ... ??
I therefore propose that we define "JDK_EXPORT", with the same
behavior as JNIEXPORT (that is, flagging the function for external
visibility in the resulting native library), but which is *not*
supposed to be exported to Java code using JNI, nor supposed to be
decorated with
Just a clarification there. JNI functions are not exported to Java
code, they are exported to native code. Java code can declare native
methods and those native methods must be written as JNI functions, but
that's not what we are discussing. Libraries expose a JNI interface (a
set of functions in the library) that can be called by application
native code, using JNI.
We're apparently looking at "JNI" and "exporting" from two opposite
sides here. :-) Just to make everything clear: If I have a Java class
class MyClass {
public static void native myNativeFunc();
}
then I have one half of the JNI function, the Java half. This must be
matched by a corresponding implementation in native, like this:
JNIEXPORT void JNICALL
Java_MyClass_myNativeFunc(void) {
// ... do stuff
}
And this is the native half of the JNI function. Right? Let's leave
aside which side is "exporting" to the other for now. :-)
This way of setting up native functions that can be called from Java is
what I refer to as JNI. And when you declare a native JNI function, you
*must* use both JNIEXPORT and JNICALL. Alright?
We do have a lot of those functions in our native libraries. And they
are correct just the way they are.
Yep all well and good. A function declared native in Java must have an
implementation as you describe. But not all native functions exist to
provide the native-half of a Java native function!
However, we also have *other* native functions, that are exported, not
as JNI functions that should be called from Java, but as normal native
library functions that should be called by other native code. Okay so
far? And *those* functions have been problematic in how we decorate
But there are again two cases. Those functions exported from a library
that are expected to be called from external code using the JNI
interface mechanism - such as all the JNI functions and JVM TI functions
we export from the JVM - and those "exported" for access between
libraries within the JDK (such as all the JVM_* functions in libjvm).
I think it is only the second group that should be addressed by your
JDK_EXPORT proposal - though I'm not completely clear exactly how to
identify them.
them. My proposal is that we *refrain* from using JNIEXPORT for those
functions, and instead use JDK_EXPORT as name for the macro that
decorates them as exported. That way, we can clearly see that a function
like this:
JDK_EXPORT void
JLI_ReadEnv(char* env);
is correctly declared, and will be exported to other native libraries,
but not to Java.
The issue is not whether it is "exported to Java"** but whether it is
exported using the JNI mechanism such that other native code calls it
using the JNI mechanism.
** There is no way to write a native method declaration in Java such
that it would be linked to the JLI_ReadEnv function. The naming is all
wrong, as is the signature.
Just to clarify, this has nothing to do with if this is a officially
supported API or not. In general though, I assume that most (if not
all?) of our exported functions (apart from the JNI_* stuff) is supposed
to be consumed by other libraries in the JDK, and is not a public API.
I think it varies library by library. You may need native application
code that can call directly into native JDK libraries. JLI is the Java
Launcher Interface - I think it was introduced to make it easier for
other launchers to be created. Native agents may need access to
libmanagement or libjdwp functions. Native graphics code may need access
to the JDK graphics library. Some of these accesses may be unsupported
and undocumented, but I don't think you can just cut them all off.
David
/Magnus
JNICALL. All current instances of JNIEXPORT which is not pure JNI
native functions should be changed to use JDK_EXPORT instead.
I further propose that this macro should reside in a new file
"jdk.h", placed in the new directory
src/java.base/share/native/include/internal. This header file path
will automatically be provided to all native libraries, but not
copied to the JDK being built. (The existence of a "include/internal"
directory with this behavior has been discussed before. There are
more files that ought to be moved there, if/when it is created.) I
believe in many cases the #include "jni.h" can be just modified to
#include "#jdk.h", since most native code will not require "jni.h"
unless actually doing JNI calls -- most have included this file to
get the JNIEXPORT macro, which would explain the pervasive use of
#include "jni.h" in our code base.
jni.h also defines all of the types used by the JNI. Those types are
pervsive to the native code used throughout the JDK.
Thoughts?
I think we need to understand the problems on Windows that prompted
all this. Then I think we need to look at exactly how jni.h and
JNIEXPORT etc are being used and understand whether this is truly an
exported interface or not.
Cheers,
David
/Magnus