Jave/JNI (was: Re: Re: Boost::Ruby)

Rene Rivera <[email protected]>
Newsgroups gmane.comp.lib.boost.langbinding
Organization Redshift Software, Inc.
Message-ID <[email protected]>
Alan Gutierrez wrote:
> * Rene Rivera <[email protected]> [2005-10-12 23:04]:
>>For a while I entertained the idea of writing a special loader that 
>>would inject symbol bindings dynamically.
> 
>     Rene
> 
>     You're talking about a special java.lang.ClassLoader, right?

No.

>     The Objectweb ASM library is very popular in Java land these
>     days. It's a petite library (50K core) and it has a clean API
>     for bytecode manipulation. There's a lot of bytecode abuse out
>     there, but I don't know of anyone using ASM (or BCEL, or the
>     like) to make a better JNI.

Bytecode manipulations alone will not give you a complete JNI. The one 
aspect it could help you with would be to automagically produce the Java 
side of the native classes. That is instead of having to type out and 
compile the Java equivalent of the C++ classes.

>     I didn't think that you or David were considering doing much
>     development in the bridged language, whatever it may be.

 From my POV we would do what's needed to make it work. Ideally not 
having any code on the target language is best, but not a requirement.

> Though
>     with this as an example, I can see how it could be much easier
>     in the case of a recalcitrant language, to implement a facade in
>     the language to a well behaved, well defined C++ interface.
> 
>     The ClassLoader could be configured on teh Java side to load a
>     Langbinding library, and map the contents to whatever package
>     suits the Java application.

Unfortunately JNI is a JVM+runtime feature, not a Java language feature.

>     You've probably done much of this research yourself, I'm only
>     dumping what I know. Cheers. 

Actually I had to do a bit of it before I responded to this post as I 
truly didn't remember all that I was thinking. But now that I have 
here's what I was thinking of...

There are two symbol injection point I was thinking could be subverted 
for our cause:

1) The dynamic library OS loader. (very hard)
2) The JNI loader. (just hard)

Doing (1) would require some very platform specific magic to at DLL load 
time insert symbols into the DLLs symbol table. Since this is very hard, 
and very system specific I'll ignore this one unless someone wants to 
think hard about it :-) I must say that such a utility would be useful 
in a variety of other contexts.

(NOTE: What I'm about to say is from knowledge about the internals of 
Sun's JVM. I.e. I've looked at the source code, and how JNI is 
implemented. Although the basic info is available without looking at 
source code, which I'll point out for reference.)

Doing (2) involves doing the JNI method registration manually. Currently 
the Sub JVM implemented JNI by one add a loadLibrary() call in your 
class. After that when a native method is required the JVM calls a 
resolution algo that eventually calls the 
ClassLoader.NativeLibrary.find() method. That method does a symbol 
lookup on the DLL by asking the JVM to look through it's internal set of 
  loaded symbols. There are two things one can do to subvert that 
default process:

a) The JNI 1.2 API support having a JNI_OnLoad entry that is called as 
part of a DLL load to specify the JNI version on requires:

http://java.sun.com/j2se/1.5.0/docs/guide/jni/spec/invocation.html#library_version

One can define that entry and do any old processing one needs in it. So 
one could put code into it that registers the entry points for the 
langbinding classes defined. For that see (b)...

(b) For it's own internal use, the JNI API allows for registration of 
any old function pointer to specific method in a class with the 
JNI::RegisterNatives call:

http://java.sun.com/j2se/1.5.0/docs/guide/jni/spec/functions.html#registering_native_methods

Normally this is called from a class static initialization like so:

public class SomeClass {
   public void myNative();
   private static native void registerNatives();
   static { registerNatives(); }
}

And when one implements the JNI code for that one would:

JNIEXPORT void JNICALL
Java_SomeClass_registerNatives(JNIEnv *env, jclass cls)
{
   // Where methods is a function pointer array of the JNI methods.
   (*env)->RegisterNatives(env,cls,methods,
     sizeof(methods)/sizeof(JNINativeMethod));
}

Minimally for langbinding it could be called for any particular class 
and the registration placed in a helper class:

public class Langbinding {
   public static native void registerNatives(java.lang.Class cls);
}
JNIEXPORT void JNICALL
Java_Langinbind_registerNatives(JNIEnv *env, jclass, jclass cls)
{
   // Code to do the "dynamic" registration, that eventually calls:
   (*env)->RegisterNatives(env,cls,methods,methodCount);
}

And in the bound classes themselves one would:

public class MyClass {
   public native addition(int a, int b);
   public native subtraction(int a, int b);
   static {
     Langbinding.registerNatives(Class.forName("MyClass"));
   }
}

Of course the ideal would be to have the JNI_OnLoad generate JVM code 
for appropriate proxy classes as above, and feed that into the JVM, as 
you suggested :-)



-- 
-- Grafik - Don't Assume Anything
-- Redshift Software, Inc. - http://redshift-software.com
-- rrivera/acm.org - grafik/redshift-software.com
-- 102708583/icq - grafikrobot/aim - Grafik/jabber.org


-------------------------------------------------------
This SF.Net email is sponsored by:
Power Architecture Resource Center: Free content, downloads, discussions,
and more. http://solutions.newsforge.com/ibmarch.tmpl
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.