hello all, (this concerns VM implementers so i'm posting it here since it may relate to VMs other than the two i use for my testing) since Jeroen F.'s comments on my recent BigInteger/GMP patch, i've been playing with having an inner class in BigInteger which has all the native methods. the pattern is similar to the class OC (attached). having thought i overcame a bug in how our gjavah generates the header files, i tried running the resulting code with both cacao and jamvm but i kept getting an UnsatisfiedLinkError. i then tried the same code with both RIs 1.4 (1.4.2_12) and 1.5 (1.5.0_08) using a rudimentary Makefile (attached). the results are interesting: * the header file generated by the RI-1.5 emits a signature for the native method of an inner class that looks like so: JNIEXPORT void JNICALL Java_OC_IC_natInit * the one for RI-1.4 looks like so: JNIEXPORT void JNICALL Java_OC_00024IC_natInit * coding the native code (.c file attached) with the first signature and generating the .so library cause an UnsatisfiedLinkError with both RIs. * coding with the second signature etc... works OK! * with both cacao and jamvm, even with the second signature, running the code causes an UnsatisfiedLinkError to be raised. * i haven't tried with ikvm, but an email from JF (http://sourceforge.net/mailarchive/message.php?msg_id=20565848) suggests that ikvm knows how to mangle the names before calling native methods of inner classes. my questions are: 1. do VMs handle differently native method names depending on whether they are defined in an inner class or not? 2. should VMs handle native method calls for inner classes the same way as the RI? TIA + cheers; rsn
public class OC { static { System.loadLibrary("dummy"); System.out.println("*** Loaded native library..."); } transient IC _ic; OC() { super(); _ic = new IC(); } public static final void main(String[] args) { new OC(); } private static final class IC { int np; IC() { super(); natInit(); } native void natInit(); } }
JAVA_HOME=/opt/j2sdk1.4.2_12 #JAVA_HOME=/opt/jdk1.5.0_08 JAVA=${JAVA_HOME}/bin/java JAVAC=${JAVA_HOME}/bin/javac JAVAH=${JAVA_HOME}/bin/javah JAVA_LIBRARY_PATH=${JAVA_HOME}/jre/lib/i386/server:${JAVA_HOME}/jre/lib/i386:${JAVA_HOME}/lib/i386 CACAO=/data/workspace/cvs/classpath/install/bin/cacao JAMVM=/data/workspace/cvs/classpath/install/bin/jamvm class: ${JAVAC} -classpath . OC.java ## with jdk 1.4 this has to be done on the command line; i.e. ## # /opt/j2sdk1.4.2_12/bin/javah -classpath . -o OC_IC.h OC\$IC jni: ${JAVAH} -classpath . -o OC_IC.h OC$$IC # ${JAVAH} -classpath . -d . OC$$IC lib: gcc -fPIC -g -c -Wall OC_IC.c gcc -I/usr/local/java/include -I/usr/local/java/include/linux -shared -Wl,-soname,libdummy.so -o libdummy.so OC_IC.o -lc run: ${JAVA} -classpath . -Djava.library.path=.:${JAVA_LIBRARY_PATH} OC # ${CACAO} -classpath . -Djava.library.path=.:${JAVA_LIBRARY_PATH} OC # ${JAMVM} -classpath . -Djava.library.path=.:${JAVA_LIBRARY_PATH} OC
#include "OC_IC.h" #include <stdio.h> JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm __attribute__ ((__unused__)), void *reserved __attribute__ ((__unused__))) { fprintf(stderr, "*** Loading dummy native library...\n"); return (JNI_VERSION_1_2); } /* Java_OC_IC_natInit(JNIEnv *env __attribute__ ((__unused__)), jobject this __attribute__ ((__unused__))) */ JNIEXPORT void JNICALL Java_OC_00024IC_natInit(JNIEnv *env __attribute__ ((__unused__)), jobject this __attribute__ ((__unused__))) { printf("*** ...natInit() not implemented\n"); return; }
Attachment:
pgpi2zB77EBzb.pgp
Description: PGP signature