When you ask a a VM that supports JNI 1.2 for
JNI 1.1 you get back JNI 1.2 - that includes not just the function
table (aka interface structure) but also what version it reports
itself as being - it will tell you it is JNI 1.2 (code below).
By comparison, when you ask a VM that supports JVMPI 1.1 for
JVMPI 1 you get back JVMPI 1 (version field and function table).
To summarize:
JNI choose - 2) always newest
JVMPI choose - 1) exact match
Since GetEnv is a JNI function, JNI should define its action. This
is an incompatibility.
Additionally, note that the JVMPI spec:
http://java.sun.com/j2se/1.3/docs/guide/jvmpi/jvmpi.html
describes compatibility not exact match:
The GetEnv function returns a pointer to a JVMPI_Interface whose version field
indicates a JVMPI version that is compatible to the version number argument
passed in the GetEnv call. Note that the value of the version field is not
necessarily identical to the version argument passed in the GetEnv call.
Thus it is also an incompatibility with the JVMPI spec.
============================ Code ========================
---- HotSpot GetEnv ----
jint JNICALL jni_GetEnv(JavaVM *vm, void **penv, jint version) {
Thread* thread = ThreadLocalStorage::thread();
if (thread != NULL && thread->is_Java_thread()) {
if (version == JNI_VERSION_1_1 || version == JNI_VERSION_1_2) {
*(JNIEnv**)penv = ((JavaThread*) thread)->jni_environment();
return JNI_OK;
} else if (version == JVMPI_VERSION_1 || version == JVMPI_VERSION_1_1) {
*penv = (void* )jvmpi::GetInterface_1(version); // version 1.X support
return JNI_OK;
} else if (version == JVMDI_VERSION_1) {
*penv = (void *)jvmdi::GetInterface_1(vm);
return JNI_OK;
} else {
*penv = NULL;
return JNI_EVERSION;
}
} else {
*penv = NULL;
return JNI_EDETACHED;
}
}
---- partial original Classic GetEnv ----
static jint JNICALL
jni_GetEnv(JavaVM *vm, void **penv, jint version)
{
sys_thread_t *self = sysThreadSelf();
if (self) {
if (version == JNI_VERSION_1_1 || version == JNI_VERSION_1_2) {
*penv = (void *)EE2JNIEnv(SysThread2EE(self));
return JNI_OK;
...
---- HotSpot JNI GetVersion ----
JNI_LEAF(jint, jni_GetVersion(JNIEnv *env))
JNIWrapper("GetVersion");
return JNI_VERSION_1_2;
JNI_END
---- HotSpot partial JVMPI initialize ----
void jvmpi::initialize(int version) {
....
jvmpi_interface.GetMethodClass = &get_method_class;
if (version == JVMPI_VERSION_1) {
jvmpi_interface.jobjectID2jobject = NULL;
jvmpi_interface.jobject2jobjectID = NULL;
} else { // JVMPI_VERSION_1_1 and beyond
jvmpi_interface.jobjectID2jobject = &jobjectID_2_jobject;
jvmpi_interface.jobject2jobjectID = &jobject_2_jobjectID;
}
}
---- HotSpot partial JVMPI initialize ----
JVMPI_Interface* jvmpi::GetInterface_1(int version) {
initialize(version);
return &jvmpi_interface;
}