From: William S F. <ws...@fu...> - 2012-08-11 21:27:16
|
On 07/08/12 00:51, Stephen McGruer wrote: > I posted something related to this to swig-user, but have since dug into > the swig source and had a look for myself so thought I'd ask swig-devel > since I'll be talking more code here. > > I have a setup where I have a C++ and Java implementation of the same > type, and want to pass theme across the boundary. Additionally, the Java > side will override some virtual functionality, so I am using directors. > > To do this at the moment, I convert the C++ class to a byte[], copy that > to the Java side (well, using GetPrimitiveArrayCritical/etc), then > convert the byte[] to the Java class. In other words, the typemaps are > something like this: > > %typemap(jni) CLASS_TYPE* INPUT "jbyteArray" > %typemap(jtype) CLASS_TYPE* INPUT "byte[]" > %typemap(jstype) CLASS_TYPE* INPUT "JavaClassType" > > %typemap(javain, pre=" > // Convert $javainput (JavaClassType) to byte[] > ") CLASS_TYPE* INPUT "array$javainput" > > %typemap(in) CLASS_TYPE* INPUT (CppClassType temp) { > // Convert byte[] to CppClassType. > } > > %typemap(javadirectorin) CLASS_TYPE* INPUT " > // Convert byte[] to JavaClassType > " > > %typemap(directorin,descriptor="L"JavaClassWithSlashes";") CLASS_TYPE* > INPUT %{ > // Convert a CppClassType to jbyteArray > %} > > I decided that it would be preferable to use ByteBuffers instead, so > that there was definitely only one copy of the byte[], and to avoid the > limits imposed by PrimitiveArrayCritical. So, I changed the code to use > that, ending up with typemaps something like: > > %typemap(jni) CLASS_TYPE* INPUT "jobject" > %typemap(jtype) CLASS_TYPE* INPUT "java.nio.ByteBuffer" > %typemap(jstype) CLASS_TYPE* INPUT "JavaClassType" > > %typemap(javain, pre=" > // Convert $javainput (JavaClassType) to ByteBuffer > ") CLASS_TYPE* INPUT "buffer$javainput" > > %typemap(in) CLASS_TYPE* INPUT (CppClassType temp) { > // Convert ByteBuffer to CppClassType. > } > > %typemap(javadirectorin) CLASS_TYPE* INPUT " > // Convert ByteBuffer to JavaClassType > " > > %typemap(directorin,descriptor="L"JavaClassWithSlashes";") CLASS_TYPE* > INPUT %{ > // Convert a CppClassType to jobject (i.e. from NewDirectByteBuffer). > %} > > However, this suddenly broke my code! Specifically, the director upcalls > created in emitDirectorUpcalls() changed from having [B (byte[]) in > their method signatures, to having JavaClassType. (Whereas they should > have changed to have Ljava/nio/ByteBuffer;). I.e. I had the following > sort of change: > > methods[72] = { > { > "SwigDirector_ClassXJni_getSomething", "(Lcom/example/ClassXJni;[B)J" > }, > ... > } > > Turned into: > > methods[72] = { > { > "SwigDirector_ClassXJni_getSomething", > "(Lcom/example/ClassXJni;Lcom/example/JavaClassType;)J" > }, > ... > } > > Digging into the code, I found that emitDirectorUpcalls() uses the > "imclass_fdesc" attribute of udata. This attribute of udata is set from > 'jnidesc' and 'jniret_desc': > > String *imclass_desc = NewStringf("(%s)%s", jnidesc, jniret_desc); > String *class_desc = NewStringf("(%s)%s", classdesc, classret_desc); > UpcallData *udata = addUpcallMethod(imclass_dmethod, symname, > imclass_desc, class_desc, decl); > > Tracking jnidesc back (a similar situation happens for jniret_desc), I > found that it is set from the 'directorin:descriptor' attribute of the > parameter node: > > /* Get parameter's intermediary C type */ > if ((c_param_type = Getattr(p, "tmap:jni"))) { > Parm *tp = NewParm(c_param_type, empty_str, n); > String *desc_tm = NULL, *jdesc = NULL, *cdesc = NULL; > > /* Add to local variables */ > Printf(c_decl, "%s %s", c_param_type, arg); > if (!ignored_method) > Wrapper_add_localv(w, arg, c_decl, (!(SwigType_ispointer(pt) || > SwigType_isreference(pt)) ? "" : "= 0"), NIL); > > /* Add input marshalling code and update JNI field descriptor */ > if ((desc_tm = Swig_typemap_lookup("directorin", tp, "", 0)) > && (jdesc = Getattr(tp, "tmap:directorin:descriptor")) > && (tm = Getattr(p, "tmap:directorin")) > && (cdesc = Getattr(p, "tmap:directorin:descriptor"))) { > > // Objects marshalled by passing a Java class across the JNI > boundary use jobject as the JNI type - > // the nouse flag indicates this. We need the specific Java class > name instead of the generic 'Ljava/lang/Object;' > if (GetFlag(tp, "tmap:directorin:nouse")) > jdesc = cdesc; > String *jni_canon = canonicalizeJNIDescriptor(jdesc, tp); > Append(jnidesc, jni_canon); > > Now this seems very strange, because (as far as I can see) these > director upcalls should be passing (a converted) jtype, not the > director:descriptor. For some reason that I don't understand, the > descriptor is set to '[B' when using the jbyteArray approach, but when > the jni typemap is jobject, it uses the JavaClassWithSlashes input that > I give. (Which is used in other locations, i.e. in the > swig_connect_director method). > > Have I misunderstood something here (very possible, I find swig hard to > follow), or is this a bug within swig? > > Just to note, I am working with swig 2.0.4, but have eyeballed the head > source and it still looks the same, so I don't think things have changed. Look at java.swg and the 'directorin' typemaps. For the first set of typemaps, "jbyteArray" from the 'jni' typemap is used to get "[B": %typemap(directorin,descriptor="[B") jbyteArray "$input = $1;" For the second set of typemaps, the 'jni' typemap specifies "jobject" so this is used: %typemap(directorin,descriptor="Ljava/lang/Object;",nouse="1") jobject "$input = $1;" The "nouse" flag indicates to work differently and the descriptor shown is ignored and is taken instead from the C type (CLASS_TYPE *) typemap you gave: %typemap(directorin,descriptor="L\"JavaClassWithSlashes\";") CLASS_TYPE* INPUT %{ // Convert a CppClassType to jobject (i.e. from NewDirectByteBuffer). %} Given you are using ByteBuffer to marshall CLASS_TYPE *, then you should change this one to: %typemap(directorin,descriptor="L\"java/nio/ByteArray\";") CLASS_TYPE* INPUT %{ // Convert a CppClassType to jobject (i.e. from NewDirectByteBuffer). %} I hope that seems reasonable. William |