From: William S F. <ws...@fu...> - 2009-02-09 19:42:20
|
Brian Cole wrote: > Question about shutdown though. With finalizers there is a way to > guarantee that all finalizers are called before program exit. I thought the JVM does not make any such guarantees. Do you have a reference on how to achieve this guarantee? > If it works out well for you, we can incorporate this as > alternative set > of typemaps and ship it with SWIG. > > > William > > > Good to know we’re not on a wild goose chase. Did he design it with > SWIG in mind? No, the proxy class pattern is a common design pattern, sometimes called peer classes in the Java JNI community which suffers the said memory issues. > We were thinking it would be doable with the current > SWIG features as well. For a proof of concept we’re going to > hardcode the functionality into an object we know is causing us > problems. Then move forward with a more general approach. > > The conceptual issue we’re struggling with now is how to force SWIG > to create two proxy classes. One needs to hold the long swigCPtr > which inherits from WeakReference. The other which simply contains a > reference to the former class. I see how to make SWIG inherit from a > universal base class with the following: > http://www.swig.org/Doc1.3/Java.html#void_pointers The first proxy > class would be created with a swig interface like the following: > > %typemap(javabase) SWIGTYPE, SWIGTYPE *, SWIGTYPE &, SWIGTYPE [], > SWIGTYPE > (CLASS::*) "SWIGJavaBase" > > %typemap(javacode) SWIGTYPE, SWIGTYPE *, SWIGTYPE &, SWIGTYPE [], > SWIGTYPE > (CLASS::*) %{ > protected long getPointer() { > return swigCPtr; > } > %} > > final class SWIGJavaBase extends WeakReference<JavaBase> { > void dispose() { > refList.remove(this); > delete(); // calls the SWIG generated delete which > will call the actual C++ dtor > } > static private ReferenceQueue<JavaBase> refQueue; > static private List<SWIGJavaBase> refList; > static ReferenceQueue<JavaBase> referenceQueue() { > return refQueue; > } > > SWIGJavaBase(JavaBase obj) { > super(obj, refQueue); > refList.add(this); > } > } > > The second proxy class would have the following base: > > public class JavaBase { > private SWIGJavaBase obj; > > public void dispose() { obj.dispose(); } > } > > > So if a C++ class is defined as follows: > class Foo { > public: > int spam(int num, Foo* foo); > }; > > > I need SWIG to generate both of the following proxy classes: > public class FooNative extends SWIGJavaBase { > private long swigCPtr; > protected boolean swigCMemOwn; > > protected FooNative(long cPtr, boolean cMemoryOwn) { > > swigCMemOwn = cMemoryOwn; > swigCPtr = cPtr; > } > protected static long getCPtr(FooNative obj) { > return (obj == null) ? 0 : obj.swigCPtr; > } > ... // no finalize method > public synchronized void delete() { > if(swigCPtr != 0 && swigCMemOwn) { > swigCMemOwn = false; > exampleJNI.delete_Foo(swigCPtr); > } > swigCPtr = 0; > } > public int spam(int num, Foo foo) { > return exampleJNI.Foo_spam(swigCPtr, this, num, > Foo.getCPtr(foo), foo); > } > public FooNative(Foo obj) { > super(obj); > this(exampleJNI.new_Foo(), true); > } > } > > public class Foo extends JavaBase { > private FooNative obj; > Foo() { > obj = new FooNative(this); > } > } > > Any ideas on forcing SWIG to give me two proxy classes (almost like > Python SWIG used to do)? Also, they both have to derive from my > specially defined pure Java base classes. > This will probably depend on usage, so the ability to have both options would be ideal. > Then there’s the separate decision of whether cleanup should be > handled by a separate thread or the object constructor. Thoughts? > > We’ll keep pushing forward. Our hope is to provide seamless Java > support without requiring our users to be experts in Java garbage > collection. Perhaps too tall an order. > The problem with extending the Java class is that it then removes the ability to wrap single inheritance class hierarchies. I was wondering if the approach could be adapted to use an interface with containment instead. Given your split into Foo and FooNative, I don't see how a user would call Foo.spam() as it is only available as FooNative.spam(). Anyway, if you want to send the desired code in the form of a modified version of what SWIG generates as a standalone example, I'll see if I can bend SWIG into generating the desired code. The 2nd proxy class might require an extra feature, but if Foo can have package access instead of public acccess, then we could do something. William |