|
JNI Enhancements
|
JNI Documentation |
JNI has been enhanced in the Java 2 SDK to:
Changes to the JNI are made based on feedback from users . Please continue to send your comments, suggestions, and concerns to jni@java.sun.com.
#define JNI_VERSION_1_1 0x00010001 #define JNI_VERSION_1_2 0x00010002 /* Error codes */ #define JNI_EDETACHED (-2) /* thread detached from the VM */ #define JNI_EVERSION (-3) /* JNI version error */
FindClass has been extended
so that it finds classes loaded with a class loader.
jclass FindClass(JNIEnv *env, const char *name);
In JDK 1.1,
FindClasssearched only local classes inCLASSPATH. The resulting classes did not have a class loader.The Java security model has been extended to allow non-system classes to load and call native methods. In the Java 2 Platform,
FindClasslocates the class loader associated with the current native method. If the native code belongs to a system class, no class loader will be involved. Otherwise, the proper class loader will be invoked to load and link the named class.When
FindClassis called through the Invocation Interface, there is no current native method or its associated class loader. In that case, the result ofClassLoader.getBaseClassLoaderis used. This is the class loader the virtual machine creates for applications, and is able to locate classes listed in thejava.class.pathproperty.
In the Java 2 SDK, each class loader manages its own set of native libraries.
The same JNI native library cannot be loaded into more than
one class loader. Doing so causes UnsatisfiedLinkError
to be thrown. For example, System.loadLibrary throws an
UnsatisfiedLinkError when used to load a native library
into two class loaders. The benefits of the new approach are:
To facilitate versioning control and resource management, JNI libraries in the Java 2 Platform may optionally export the following two functions:
jint JNI_OnLoad(JavaVM *vm, void *reserved);
The VM callsJNI_OnLoadwhen the native library is loaded (for example, throughSystem.loadLibrary).JNI_OnLoadmust return the JNI version needed by the native library.In order to use any of the new JNI functions, a native library must export a
JNI_OnLoadfunction that returnsJNI_VERSION_1_2. If the native library does not export aJNI_OnLoadfunction, the VM assumes that the library only requires JNI versionJNI_VERSION_1_1. If the VM does not recognize the version number returned byJNI_OnLoad, the native library cannot be loaded.
void JNI_OnUnload(JavaVM *vm, void *reserved);
The VM calls JNI_OnUnload when the class loader
containing the native library is garbage collected. This function can
be used to perform cleanup operations. Because this function is called
in an unknown context (such as from a finalizer), the programmer
should be conservative on using Java VM services, and refrain from
arbitrary Java call-backs.
Note that JNI_OnLoad and JNI_OnUnload are
two functions optionally supplied by JNI libraries, not exported from
the VM.
JDK 1.1 provides a DeleteLocalRef function so that
programmers can manually delete local references. For example, if
native code iterates through a potentially large array of objects and
uses one element in each iteration, it is a good practice to delete
the local reference to the no-longer-used array element before a new
local reference is created in the next iteration.
The Java 2 SDK provides an additional set of functions for local reference lifetime management.
jint EnsureLocalCapacity(JNIEnv *env, jint capacity);
Ensures that at least a given number of local references can be created in the current thread. Returns 0 on success; otherwise returns a negative number and throws an
OutOfMemoryError.Before it enters a native method, the VM automatically ensures that at least 16 local references can be created.
For backward compatibility, the VM allocates local references beyond the ensured capacity. (As a debugging support, the VM may give the user warnings that too many local references are being created. In the Java 2 SDK, the programmer can supply the
-verbose:jnicommand line option to turn on these messages.) The VM callsFatalErrorif no more local references can be created beyond the ensured capacity.
jint PushLocalFrame(JNIEnv *env, jint capacity);
Creates a new local reference frame, in which at least a given number of local references can be created. Returns 0 on success, a negative number and a pending
OutOfMemoryErroron failure.Note that local references already created in previous local frames are still valid in the current local frame.
jobject PopLocalFrame(JNIEnv *env, jobject result);
Pops off the current local reference frame, frees all the local references, and returns a local reference in the previous local reference frame for the given
resultobject.Pass
NULLasresultif you do not need to return a reference to the previous frame.
jobject NewLocalRef(JNIEnv *env, jobject ref);
Creates a new local reference that refers to the same object asref. The givenrefmay be a global or local reference. ReturnsNULLifrefrefers tonull.
jboolean ExceptionCheck(JNIEnv *env);
ReturnsJNI_TRUEwhen there is a pending exception; otherwise, returnsJNI_FALSE.
NULL. Programmers can detect
whether a weak global reference points to a freed object by using
IsSameObject to compare the weak reference against
NULL.
Weak global references in JNI are a simplified version of the Java
Weak References, available as part of the Java 2 Platform API (
java.lang.Ref and its related classes).
jweak NewWeakGlobalRef(JNIEnv *env, jobject obj);
Creates a new weak global reference. ReturnsNULLifobjrefers tonull, or if the VM runs out of memory. If the VM runs out of memory, anOutOfMemoryErrorwill be thrown.
void DeleteWeakGlobalRef(JNIEnv *env, jweak obj);
Delete the VM resources needed for the given weak global reference.
In JDK 1.1, programmers can use
Get/Release functions to
obtain a pointer to primitive array elements. If the VM supports
pinning, the pointer to the original data is returned; otherwise, a
copy is made.
New functions allow native code to obtain a direct pointer to array elements even if the VM does not support pinning.
void * GetPrimitiveArrayCritical(JNIEnv *env, jarray array, jboolean *isCopy);
void ReleasePrimitiveArrayCritical(JNIEnv *env, jarray array, void *carray, jint mode);
The semantics of these two functions are very similar to the existingGet/Releasefunctions. If possible, the VM returns a pointer to the primitive array; otherwise, a copy is made. However, there are significant restrictions on how these functions can be used.ArrayElements After calling
GetPrimitiveArrayCritical, the native code should not run for an extended period of time before it callsReleasePrimitiveArrayCritical. We must treat the code inside this pair of functions as running in a "critical region." Inside a critical region, native code must not call other JNI functions, or any system call that may cause the current thread to block and wait for another Java thread. (For example, the current thread must not callreadon a stream being written by another Java thread.)These restrictions make it more likely that the native code will obtain an uncopied version of the array, even if the VM does not support pinning. For example, a VM may temporarily disable garbage collection when the native code is holding a pointer to an array obtained via
GetPrimitiveArrayCritical.Multiple pairs of
GetPrimtiveArrayCriticalandReleasePrimitiveArrayCriticalmay be nested. For example:jint len = (*env)->GetArrayLength(env, arr1); jbyte *a1 = (*env)->GetPrimitiveArrayCritical(env, arr1, 0); jbyte *a2 = (*env)->GetPrimitiveArrayCritical(env, arr2, 0); /* We need to check in case the VM tried to make a copy. */ if (a1 == NULL || a2 == NULL) { ... /* out of memory exception thrown */ } memcpy(a1, a2, len); (*env)->ReleasePrimitiveArrayCritical(env, arr2, a2, 0); (*env)->ReleasePrimitiveArrayCritical(env, arr1, a1, 0);
Note that GetPrimitiveArrayCritical might still make a copy
of the array if the VM internally represents arrays in a different format.
Therefore we need to check its return value against NULL for
possible out of memory situations.
void GetStringRegion(JNIEnv *env, jstring str, jsize start, jsize len, jchar *buf);
Copieslennumber of Unicode characters beginning at offsetstartto the given bufferbuf.Throws
StringIndexOutOfBoundsExceptionon index overflow.
<
void GetStringUTFRegion(JNIEnv *env, jstring str, jsize start, jsize len, char *buf);
Translateslennumber of Unicode characters beginning at offsetstartinto UTF-8 format and place the result in the given bufferbuf.Throws
StringIndexOutOfBoundsExceptionon index overflow.
const jchar * GetStringCritical(JNIEnv *env, jstring string, jboolean *isCopy);
void ReleaseStringCritical(JNIEnv *env, jstring string, const jchar *carray);
The semantics of these two functions are similar to the existingGet/ReleaseStringCharsfunctions. If possible, the VM returns a pointer to string elements; otherwise, a copy is made. However, there are significant restrictions on how these functions can be used. In a code segment enclosed byGet/ReleaseStringCriticalcalls, the native code must not issue arbitrary JNI calls, or cause the current thread to block.The restrictions on
Get/ReleaseStringCriticalare similar to those onGet/ReleasePrimitiveArrayCritical.
Programmers can use the JNI to call Java methods or access Java fields if they know the name and type of the methods or fields. The Java Core Reflection API allows programmers to introspect Java classes at runtime. JNI provides a set of conversion functions between field and method IDs used in the JNI to field and method objects used in the Java Core Reflection API.
jmethodID FromReflectedMethod(JNIEnv *env, jobject method);
Converts ajava.lang.reflect.Methodorjava.lang.reflect.Constructorobject to a method ID.
jfieldID FromReflectedField(JNIEnv *env, jobject field);
Converts a java.lang.reflect.Field
to a field ID.
jobject ToReflectedMethod(JNIEnv *env, jclass cls,
jmethodID methodID);
Converts a method ID derived fromclsto ajava.lang.reflect.Methodorjava.lang.reflect.Constructorobject.Throws
OutOfMemoryErrorand returns 0 if fails.
jobject ToReflectedField(JNIEnv *env, jclass cls,
jfieldID fieldID);
Converts a field ID derived fromclsto ajava.lang.reflect.Fieldobject.Throws
OutOfMemoryErrorand returns 0 if fails.
jint JNI_CreateJavaVM(JavaVM **pvm, void **penv, void *args);
In JDK 1.1, the second argument toJNI_CreateJavaVMis always a pointer toJNIEnv *. The third argument is a pointer to a JDK 1.1 specific structure (JDK1_1InitArgs). TheJDK1_1InitArgsstructure is clearly not designed to be portable on all VMs.In the Java 2 SDK, we introduce a standard VM initialization structure. Backward compatibility is preserved. If the VM initialization argument points to a
JDK1_1InitArgsstructure,JNI_CreateJavaVMstill returns the 1.1 version of JNI interface pointer. The VM returns the 1.2 version of JNI interface pointer if the third argument points to aJavaVMInitArgsstructure. UnlikeJDK1_1InitArgs, which contains a fixed set of options,JavaVMInitArgsuses option strings to encode arbitrary VM start up options.typedef struct JavaVMInitArgs { jint version; jint nOptions; JavaVMOption *options; jboolean ignoreUnrecognized; } JavaVMInitArgs;Theversionfield must be set toJNI_VERSION_1_2. (In contrast, the version field inJDK1_1InitArgsmust be set toJNI_VERSION_1_1.) Theoptionsfield is an array of the following type:typedef struct JavaVMOption { char *optionString; void *extraInfo; } JavaVMOption;The size of the array is denoted by the nOptions field inJavaVMInitArgs. IfignoreUnrecognizedisJNI_TRUE,JNI_CreateJavaVMignore all unrecognized option strings that begin with "-X" or "_". IfignoreUnrecognizedisJNI_FALSE,JNI_CreateJavaVMreturnsJNI_ERRas soon as it encounters any unrecognized option strings. All Java VMs must recognize the following set of standard options:
optionString meaning -D<name>=<value>Set a system property -verbose[:class|gc|jni]Enable verbose output. The options can be followed by a comma-separated list of names indicating what kind of messages will be printed by the VM. For example, " -verbose:gc,class" instructs the VM to print GC and class loading related messages. Standard names include:gc,class, andjni. All nonstandard (VM-specific) names must begin with "X".vfprintfextraInfois a pointer to thevfprintfhook.exitextraInfois a pointer to theexithook.abortextraInfois a pointer to theaborthook.In addition, each VM implementation may support its own set of non-standard option strings. Non-standard option names must begin with "
-X" or an underscore ("_"). For example, the Java 2 SDK supports-Xmsand-Xmxoptions to allow programmers specify the initial and maximum heap size. Options that begin with "-X" are accessible from the "java" command line.Here is the example code that creates a Java VM in the Java 2 SDK:
JavaVMInitArgs vm_args; JavaVMOption options[4]; options[0].optionString = "-Djava.compiler=NONE"; /* disable JIT */ options[1].optionString = "-Djava.class.path=c:\myclasses"; /* user classes */ options[2].optionString = "-Djava.library.path=c:\mylibs"; /* set native library path */ options[3].optionString = "-verbose:jni"; /* print JNI-related messages */ vm_args.version = JNI_VERSION_1_2; vm_args.options = options; vm_args.nOptions = 4; vm_args.ignoreUnrecognized = TRUE; /* Note that in the Java 2 SDK, there is no longer any need to call * JNI_GetDefaultJavaVMInitArgs. */ res = JNI_CreateJavaVM(&vm, (void **)&env, &vm_args); if (res < 0) ...The Java 2 SDK still supports
JDK1_1InitArgsin exactly the same way as JDK 1.1.
jint AttachCurrentThread(JavaVM *vm, void **penv, void *args);
In JDK 1.1, the second argument toAttachCurrentThreadis always a pointer toJNIEnv. The third argument toAttachCurrentThreadwas reserved, and should be set toNULL.In the Java 2 SDK, you pass
NULLas the third argument for 1.1 behavior, or pass a pointer to the following structure to specify additional information:typedef struct JavaVMAttachArgs { jint version; /* must be JNI_VERSION_1_2 */ char *name; /* the name of the thread, or NULL */ jobject group; /* global ref of a ThreadGroup object, or NULL */ } JavaVMAttachArgs;
jint DetachCurrentThread(JavaVM *vm);
In JDK 1.1, the main thread cannot be detached from the VM. It must callDestroyJavaVMto unload the entire VM.In the Java 2 SDK, the main thread can be detached from the VM.
jint DestroyJavaVM(JavaVM *vm);
The support forDestroyJavaVMwas not complete in 1.1. Only the main thread may callDestroyJavaVM. In the Java 2 SDK, any thread, whether attached or not, can call this function. If the current thread is attached, the VM waits until the current thread is the only user-level Java thread. If the current thread is not attached, the VM attaches the current thread and then waits until the current thread is the only user-level thread. The Java 2 SDK still does not support VM unloading, however.DestroyJavaVMalways returns an error code.
jint GetEnv(JavaVM *vm, void **env, jint version);
If the current thread is not attached to the VM, sets*envtoNULL, and returnsJNI_EDETACHED. If the specified version is not supported, sets*envtoNULL, and returnsJNI_EVERSION. Otherwise, sets*envto the appropriate interface, and returnsJNI_OK.
|
Copyright © 1995-99
Sun Microsystems, Inc.
All Rights Reserved.
Please send comments to: jni@java.sun.com |
|