Most JNI functions are declared as
JNIEXPORT rettype JNICALL fnname(args);
or
JNIEXPORT rettype (JNICALL *pfnname)(args);
This is a problem for IBM (and Borland?) compilers, as these special type
qualifiers go in a different place to the Microsoft compilers.
For IBM Visual Age C/C++, a function should be declared as follows:
rettype _Export _System fnname(args);
(or
rettype _System _Export fnname(args);
)
or
rettype (* _Export _System pfnname)(args);
(or
rettype (* _System Export pfnname)(args);
)
for a function pointer.
Also, if the _Export qualifier is present in a compilation, then the function
definition also should be present, so the compiler can tag the definition label
such that the linker can make it a publically exportable symbol in a DLL.
If _Export is present when the definition isn't then the compiler generates a
warning.
This causes problems because appropriate substitutions can not always be made.
The first problem is that the JNIEXPORT qualifier is in the wrong place for OS/2.
This causes problems, because we cannot define JNIEXPORT as '_Export'
The best thing perhaps would have been to have had a second qualifier:
JNIEXPORT rettype JNIEXPORT2 JNICALL fnname(args);
or a new combined qualifier
JNIEXPORT rettype JNIEXPCALL fnname(args);
but there is existing user code using the original style of declaration.
About all that can be done is to declare JNICALL as '_Export _System', merging
the JNI export qualifier into the JNI calling convention qualifier.
This could mean some additional _Export qualifiers appearing where we did not
want them to be, so we would need an additional JNICALL qualifier for use where
we do not want have a JNIEXPORT as well.
The IBM C compiler is also more sensitive about having an _Export qualifier in a
declaration without there being a definition of that function in the
compilation unit. It produces a
warning EDC0397: Undefined function or variable f2 cannot have a #pragma export
or _Export in this situation.
We therefore need a new JNICALL qualifier for use where the JNIEXPORT qualifier
is not present. Fortunately, there are not that many of these, and these could
be changed to another name, for example, JNICALL0.
The original JNICALL qualifier can be left on the function definition if there
is also a JNIEXPORT qualifier present.
The IBM C compiler will not like a JNICALL definition defined as '_Export
_System' on
a function in a header because it is quite likely that the header will be
included when
the source file containing the definition of the function is not being compiled.
It is better therefore if JNICALL0 is used on the function declaration in a header,
as the definition will not always we present, so with the IBM compiler we do not
want the _Export qualifier.
The second problem is that the JNICALL is in the wrong place when a function
pointer is declared.
About the best thing that can be done is to either have two qualifiers, so at
least one is in the right place:
rettype (JNICALL1 * JNICALL2 pfnname)(args);
or have a separate qualifier for function pointers:
rettype (PJNICALL pfnname)(args);
If we want the qualifier to begin with 'JNI' then 'JNIPCALL' or 'JNICALLPTR' may
be better.
Files to change:
src\share\javavm\export\jni.h
Add:
#ifndef JNICALL0 /*ibm*/
#define JNICALL0 JNICALL /*ibm*/
#endif /*ibm*/
#ifndef PJNICALL /*ibm*/
#define PJNICALL JNICALL * /*ibm*/
#endif /*ibm*/
#ifndef JNIEXPCALL /*ibm*/
#define JNIEXPCALL JNICALL /*ibm*/
#endif /*ibm*/
struct JNINativeInterface_ {
void *reserved0;
void *reserved1;
void *reserved2;
void *reserved3;
jint (PJNICALL GetVersion)(JNIEnv *env); /*ibm*/
etc.
JNIEXPORT jint JNICALL0 /*ibm*/
JNI_GetDefaultJavaVMInitArgs(void *args);
JNIEXPORT jint JNICALL0 /*ibm*/
JNI_CreateJavaVM(JavaVM **pvm, void **penv, void *args);
JNIEXPORT jint JNICALL0 /*ibm*/
JNI_GetCreatedJavaVMs(JavaVM **, jsize, jsize *);
/* Defined in native libraries. */
JNIEXPORT jint JNICALL0 /*ibm*/
JNI_OnLoad(JavaVM *vm, void *reserved);
JNIEXPORT void JNICALL0 /*ibm*/
JNI_OnUnload(JavaVM *vm, void *reserved);
jvm_md.h:
JNIEXPORT void JNICALL0 /*ibm*/
JVM_Process_Create(JNIEnv *env, jobject process, jstring cmd0,
jstring environment0);
JNIEXPORT jint JNICALL0 /*ibm*/
JVM_Process_ExitValue(JNIEnv *env, jobject process);
JNIEXPORT jint JNICALL0 /*ibm*/
JVM_Process_WaitFor(JNIEnv *env, jobject process);
JNIEXPORT void JNICALL0 /*ibm*/
JVM_Process_Destroy(JNIEnv *env, jobject process);
JNIEXPORT void JNICALL0 /*ibm*/
JVM_Process_Close(JNIEnv *env, jobject process);
\1.2\src\share\native\java\lang\ClassLoader.c(178) :
typedef jint (PJNICALL JNI_OnLoad_t)(JavaVM *, jobject);
typedef void (PJNICALL JNI_OnUnload_t)(JavaVM *, jobject);
Change these as well:
\1.2\src\share\javavm\runtime\javai.c(38) : extern jint (JNICALL
*vfprintf_hook)(FILE *fp, const char *fmt, va_list args);
\1.2\src\share\javavm\runtime\javai.c(39) : extern void (JNICALL
*exit_hook)(jint code);
\1.2\src\share\javavm\runtime\javai.c(40) : extern void (JNICALL *abort_hook)();
Change 'JNICALL *' to 'PJNICALL' here as well:
\1.2\src\share\javavm\runtime\javai.c(287) : vfprintf_hook = (jint
(JNICALL *)(FILE *, const char *, va_list))
\1.2\src\share\javavm\runtime\javai.c(290) : exit_hook = (void (JNICALL
*)(jint))(option->value.p);
\1.2\src\share\javavm\runtime\javai.c(292) : abort_hook = (void (JNICALL
*)())(option->value.p);
Shouldn't the abort hook also be declared as having a void parameter list?
\1.2\src\share\javavm\runtime\javai.c(40) : extern void (JNICALL
*abort_hook)(void);
\1.2\src\share\javavm\runtime\util.c(87) : extern jint (JNICALL
*vfprintf_hook)(FILE *fp, const char *format,
jit.c
jni.c
Many functions declared as JNICALL without JNIEXPORT
We need to therefore use a JNICALL definition without the _Export
Function without JNICALL qualifier:
jvmdi.h:
/* event handler hook.
* Event handlers should not allocate java objects or call java methods.
* Thread getting the event calls the hook. Thread status is not
* changed, e.g. thread is not suspended - if this is desired, event
* handler should suspend.
* Note: JVMDI_Event structure and objects within event structure
* are allocated locally and will not be preserved across return
* from hook.
*/
typedef void (*JVMDI_EventHook)(JNIEnv *env, JVMDI_Event *event);
/* Set the routine which will handle in-coming events.
* Passing NULL as hook unsets hook.
*/
JNIEXPORT jvmdiError JNICALL
JVMDI_SetEventHook(JNIEnv *env, JVMDI_EventHook hook);
Does it need qualifying using PJNICALL?
src\win32\native\sun\plugin\jvm.cpp:
/* our own exit and abort hooks so an exit of the VM
* doesn't exit the browser. An exit of the VM shouldn't
* occur anyway from just running applets. Maybe it could,
* I reckon, with signed applets.
*/
void JNICALL0 /*ibm*/
myExitHook(jint code) {
DB("java VM exited", "jvm.cpp");
VMLoaded = FALSE;
}
void JNICALL0 /*ibm*/
myAbortHook() {
DB("java VM aborted!", "jvm.cpp");
VMLoaded = FALSE;
}