OK, it's been a bit, and I've been doing some heavy thinking about
jnilink.  There is a huge amount of improvement which can be made, in terms
of speed, readability and ease-of-use.  I believe I have finally cut it down
to its core components.
     The main point of jnilink is to ensure that the class you want is
available when you want it and remains available during the execution of the
native method.  Anything else is unnecessary.  Methods and fields are all
corollaries to that one objective: if the class goes invalid, so do methods
and fields; and if it does not, they do not.  Thus I am adding the
requirement that every time you enter a native method, you call
LINK_LinkClass() in order to make sure the class is linked.  This will
ensure that you have, at the very least, a local reference to the class
which will be valid until the end of the function (when 1.2 comes around, I
will create new local references to the weakly-referred-to class).
     Additionally, the way jnilink works, linking and resolving have to be
done every time you enter the function anyway (the link has to happen if the
class, method or field has not yet been linked), so I am combining the two
steps.
     Finally, linkPtr is an unnecessary construct and hinders readability.
Therefore I am reverting to the use of jfieldID and jmethodID to store
cached info about methods, fields.  I am keeping another type, called
linkClass, for classes, because they are somewhat special and code
ambiguities could arise that would not be caught by the compiler.
     I am leaving the method and field linking functions in as a
convenience, and actually I have turned them into macros so that the
overhead of a function call (there are a lot of parameters to these
functions) is unnecessary.  Don't worry, it's a one-liner macro for each of
them.
     Another optimization which I will put in in 1.2 is the creation of a
simple global reference when the classloader that loaded the class was the
system classloader, instead of a monitored weak reference.  The system
classloader cannot be unloaded, and thus, neither can any classes loaded by
it.

     Here is the new proposed interface:

     The variables you declare for your cached variables, usually as static
variables, are like this:
     static linkedClass theClass; // for classes.
     static jmethodID theMethod;
     static jmethodID theStaticMethod;
     static jmethodID theConstructor;
     static jfieldID theField;
     static jfieldID theStaticField;

     Now, whenever you enter a method, you must first resolve the class, and
then resolve the methods and fields you want to use:
     JNIEXPORT int JNICALL Java_FunctionClass_myFunction(JNIEnv * env) {
          jclass intClass =
LINK_LinkClass(env,theClass,"java/lang/Integer");
          if(intClass == NULL) return -1;
          LINK_LinkMethod(env,theMethod,intClass,"intValue","()I");
          if(theMethod == NULL) return -1;
          LINK_LinkField(env,theField,intClass,"TYPE","Ljava/lang/Class");
          if(theField == NULL) return -1;
          .
          .
          .
     }

     LINK_LinkStaticField, LINK_LinkStaticMethod, LINK_LinkConstructor, and
LINK_LinkKnownClass are also still provided.  LINK_UnlinkClass is provided
as well, for when the class is unloaded, so that jnilink will be able to
free the global references or weak global references it has created.  No
other Unlink methods are provided, since there will be no cleanup required
for methods and fields.
     I am hoping that these changes will make it much easier to use.  If
everyone who's been using it approves, the new version will be committed
tonight.
--John Keiser

winmail.dat

Reply via email to