java-gobject-introspection r124 - in trunk: src/org/gnome/gir/compiler src/org/gnome/gir/gobject stub-examples



Author: walters
Date: Sun Nov 16 22:52:12 2008
New Revision: 124
URL: http://svn.gnome.org/viewvc/java-gobject-introspection?rev=124&view=rev

Log:
Rationalize memmgt; handle transfer-none objects and transfer-full strings

Modified:
   trunk/src/org/gnome/gir/compiler/CodeFactory.java
   trunk/src/org/gnome/gir/gobject/GObject.java
   trunk/src/org/gnome/gir/gobject/GTypeMapper.java
   trunk/src/org/gnome/gir/gobject/GlibRuntime.java
   trunk/src/org/gnome/gir/gobject/Handle.java
   trunk/src/org/gnome/gir/gobject/NativeObject.java
   trunk/src/org/gnome/gir/gobject/RefCountedObject.java
   trunk/stub-examples/Test.java

Modified: trunk/src/org/gnome/gir/compiler/CodeFactory.java
==============================================================================
--- trunk/src/org/gnome/gir/compiler/CodeFactory.java	(original)
+++ trunk/src/org/gnome/gir/compiler/CodeFactory.java	Sun Nov 16 22:52:12 2008
@@ -69,10 +69,12 @@
 
 import org.gnome.gir.gobject.GErrorException;
 import org.gnome.gir.gobject.GErrorStruct;
+import org.gnome.gir.gobject.GObject;
 import org.gnome.gir.gobject.GObjectAPI;
 import org.gnome.gir.gobject.GType;
 import org.gnome.gir.gobject.GlibAPI;
 import org.gnome.gir.gobject.GlibRuntime;
+import org.gnome.gir.gobject.NativeObject;
 import org.gnome.gir.gobject.annotation.Return;
 import org.gnome.gir.repository.ArgInfo;
 import org.gnome.gir.repository.BaseInfo;
@@ -1151,15 +1153,24 @@
 		String globalInternalsName = getInternals(fi);	
 		String symbol = fi.getSymbol();
 		
-		Class<?> returnBox = TypeMap.getPrimitiveBox(ctx.returnType);
-		Type returnTypeBox;
-		if (returnBox != null)
-			returnTypeBox = Type.getType(returnBox);
-		else
-			returnTypeBox = ctx.returnType;
-		
 		Transfer returnTransfer = fi.getCallerOwns();
-		if (returnBox == null) {
+		TypeInfo returnGIType = fi.getReturnType();
+		TypeTag returnTypeTag = returnGIType.getTag();
+		Class<?> primitiveBox = TypeMap.getPrimitiveBox(ctx.returnType);
+		Type nativeReturnType;
+		if (primitiveBox != null) {
+			nativeReturnType = Type.getType(primitiveBox);
+		} else if /* Now test for special return value transfer handling */   
+			((returnTransfer.equals(Transfer.NOTHING) &&
+				 (returnTypeTag.equals(TypeTag.INTERFACE))) ||
+				(returnTransfer.equals(Transfer.EVERYTHING) && 
+				 returnTypeTag.equals(TypeTag.UTF8))) {
+			nativeReturnType = Type.getType(Pointer.class);
+		} else { 
+			nativeReturnType = ctx.returnType;
+		}
+		
+		if (primitiveBox == null) {
 			AnnotationVisitor av = mv.visitAnnotation(Type.getDescriptor(Return.class), true);
 			av.visitEnum("transfer", Type.getDescriptor(Transfer.class), returnTransfer.name());
 			av.visitEnd();
@@ -1247,7 +1258,7 @@
 		if (ctx.returnType.equals(Type.VOID_TYPE)) {
 			mv.visitLdcInsn(Type.getType(Void.class));
 		} else {
-			mv.visitLdcInsn(returnTypeBox);
+			mv.visitLdcInsn(nativeReturnType);
 		}
 		mv.visitVarInsn(ALOAD, argsOffset);
 		mv.visitFieldInsn(GETSTATIC, globalInternalsName, "invocationOptions", Type.getDescriptor(Map.class));
@@ -1258,10 +1269,28 @@
 		if (ctx.returnType.equals(Type.VOID_TYPE)) {
 			mv.visitInsn(POP);
 		} else {
-			mv.visitTypeInsn(CHECKCAST, returnTypeBox.getInternalName());
-			if (returnBox != null)
-				mv.visitMethodInsn(INVOKEVIRTUAL, returnTypeBox.getInternalName(), 
+			mv.visitTypeInsn(CHECKCAST, nativeReturnType.getInternalName());
+			if (primitiveBox != null) {
+				/* Turn primitive boxeds into the corresponding primitive */
+				mv.visitMethodInsn(INVOKEVIRTUAL, nativeReturnType.getInternalName(), 
 						ctx.returnType.getClassName() + "Value", "()" + ctx.returnType.getDescriptor());
+			} else if (nativeReturnType != ctx.returnType) {
+				/* Special handling for return types; see above where nativeReturnType is calculated. */
+				if (returnTypeTag.equals(TypeTag.INTERFACE)) {
+					/* These are objects for which we do *not* own a reference.  */
+					mv.visitLdcInsn(ctx.returnType);
+					mv.visitInsn(ICONST_0);
+					mv.visitMethodInsn(INVOKESTATIC, Type.getInternalName(NativeObject.class), "objectFor", 
+							Type.getMethodDescriptor(getType(NativeObject.class), new Type[] { getType(Pointer.class), getType(Class.class), Type.BOOLEAN_TYPE }));
+					mv.visitTypeInsn(CHECKCAST, ctx.returnType.getInternalName());					
+				} else if (returnTypeTag.equals(TypeTag.UTF8)) {
+					/* Strings which are *not* const and must be g_free'd */
+					mv.visitMethodInsn(INVOKESTATIC, Type.getInternalName(GlibRuntime.class), "toStringAndGFree", 
+							Type.getMethodDescriptor(getType(String.class), new Type[] { getType(Pointer.class) }));
+				} else {
+					throw new IllegalArgumentException(String.format("Unhandled nativeReturn %s vs public %s", nativeReturnType, ctx.returnType));
+				}
+			}
 		}
 		if (ctx.throwsGError) {
 			jtarget = new Label();

Modified: trunk/src/org/gnome/gir/gobject/GObject.java
==============================================================================
--- trunk/src/org/gnome/gir/gobject/GObject.java	(original)
+++ trunk/src/org/gnome/gir/gobject/GObject.java	Sun Nov 16 22:52:12 2008
@@ -51,6 +51,7 @@
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 
+import org.gnome.gir.gobject.GObjectAPI.GObjectStruct;
 import org.gnome.gir.gobject.GObjectAPI.GParamSpec;
 import org.gnome.gir.gobject.GObjectAPI.GToggleNotify;
 import org.gnome.gir.gobject.GObjectAPI.GWeakNotify;
@@ -75,9 +76,19 @@
     	debugMemory = System.getProperty("jgir.debugMemory") != null;
     }
     
-    private static final void debugMemory(String fmt, Object... args) {
-    	if (debugMemory)
-    		System.err.println(String.format(fmt, (Object[])args));
+    private static final void debugMemory(GObject obj, String fmt, Object... args) {
+    	if (debugMemory) {
+    		Object[] newArgs = new Object[args.length+2];
+    		System.arraycopy(args, 0, newArgs, 1, args.length);
+    		newArgs[0] = obj;
+    		if (obj != null) {
+    			GObjectStruct objStruct = new GObjectAPI.GObjectStruct(obj);    		
+    			newArgs[newArgs.length-1] = objStruct.ref_count;
+    		} else {
+    			newArgs[newArgs.length-1] = "<null>";
+    		}
+    		System.err.println(String.format(fmt, newArgs));
+    	}
     }
     
     /* Hold a strong Java reference between this proxy object and any signal
@@ -107,7 +118,7 @@
      * @param init
      */
     public GObject(Initializer init) { 
-        super(init.needRef ? initializer(init.ptr, false, init.ownsHandle) : init);
+        super(init.ownsRef ? initializer(init.ptr, false, init.ownsHandle) : init);
         if (init.ownsHandle) {
             strongReferences.put(this, Boolean.TRUE);
             
@@ -116,10 +127,10 @@
              */
             boolean wasFloating = GObjectAPI.gobj.g_object_is_floating(this);
             if (wasFloating) {
-            	debugMemory("SINK AND TOGGLE %s", this);
+            	debugMemory(this, "SINK AND TOGGLE %s %s");
             	GObjectAPI.gobj.g_object_ref_sink(this);
             } else {
-            	debugMemory("TOGGLE %s", this);            	
+            	debugMemory(this, "TOGGLE %s %s");            	
             }
             
             /* The toggle reference is our primary means of memory management between
@@ -132,10 +143,16 @@
              */
             GObjectAPI.gobj.g_object_weak_ref(this, weakNotify, null);
             
-            /* Since we normally have a strong reference given to us (except in special cases),
-             * here we unref and this should normally just leave the toggle reference.
-             */ 
-            if (!init.needRef) {
+            /*
+			 * Normally we have a strong reference given to us by constructors,
+			 * GValue property gets, etc. So here we unref, leaving the toggle
+			 * reference we just added.
+			 * 
+			 * An example case where we don't own a ref are C convenience
+			 * getters - need to ensure those are annotated with (transfer
+			 * none).
+			 */ 
+            if (init.ownsRef) {
                 unref();
             }            
         }
@@ -229,22 +246,24 @@
     }
     @Override
     protected void ref() {
-    	debugMemory("REF %s", this);    	
+    	debugMemory(this, "REF %s %s");    	
     	GObjectAPI.gobj.g_object_ref(this);
     }
 
     @Override
     protected void unref() {
-    	debugMemory("UNREF %s", this);    	
+    	debugMemory(this, "UNREF %s %s");    	
     	GObjectAPI.gobj.g_object_unref(this);
     }
+    
+    @Override
     protected void invalidate() {
         try {
-        	debugMemory("INVALIDATE %s", this);        	
+        	debugMemory(this, "INVALIDATE %s %s");        	
             // Need to increase the ref count before removing the toggle ref, so 
             // ensure the native object is not destroyed.
             if (ownsHandle.get()) {
-            	debugMemory("REMOVING TOGGLE %s", this);             	
+            	debugMemory(this, "REMOVING TOGGLE %s %s");             	
                 ref();
 
                 // Disconnect the callback.
@@ -302,15 +321,6 @@
     	GSignalAPI.gsignal.g_signal_handler_disconnect(GObject.this, new NativeLong(id));
     	signalHandlers.remove(id);
     }
-    
-    public static GObject objectFor(Pointer ptr, Class<? extends GObject> defaultClass) {
-        return GObject.objectFor(ptr, defaultClass, true);
-    }
-    
-    @SuppressWarnings("unchecked")
-    public static <T extends GObject> T objectFor(Pointer ptr, Class<T> defaultClass, boolean needRef) {
-        return NativeObject.objectFor(ptr, defaultClass, needRef);        
-    }
 
     private GObjectAPI.GParamSpec findProperty(String propertyName) {
         return GObjectAPI.gobj.g_object_class_find_property(handle().getPointer(0), propertyName);
@@ -343,7 +353,7 @@
 		@Override
 		public void callback(Pointer data, Pointer obj) {
 			GObject o = (GObject) NativeObject.instanceFor(obj);
-            debugMemory("WEAK o=%s obj=%s", o, obj);			
+            debugMemory(o, "WEAK %s %s obj=%s", o, obj);			
 			// Clear out the signal handler references
 			if (o == null)
 				return;

Modified: trunk/src/org/gnome/gir/gobject/GTypeMapper.java
==============================================================================
--- trunk/src/org/gnome/gir/gobject/GTypeMapper.java	(original)
+++ trunk/src/org/gnome/gir/gobject/GTypeMapper.java	Sun Nov 16 22:52:12 2008
@@ -102,29 +102,6 @@
                 return null;
             }
             Pointer ptr = ((NativeObject) arg).handle();
-            
-            //
-            // Deal with any adjustments to the proxy neccessitated by gstreamer
-            // breaking their reference-counting idiom with special cases
-            //
-            if (context instanceof MethodParameterContext) {
-                MethodParameterContext mcontext = (MethodParameterContext) context;
-                Method method = mcontext.getMethod();
-                int index = mcontext.getParameterIndex();
-                Annotation[][] parameterAnnotations = method.getParameterAnnotations();
-                if (index < parameterAnnotations.length) {
-                    Annotation[] annotations = parameterAnnotations[index];
-                    for (int i = 0; i < annotations.length; ++i) {
-                        if (annotations[i] instanceof Invalidate) {
-                            ((Handle) arg).invalidate();
-                            break;
-                        } else if (annotations[i] instanceof IncRef) {
-                            ((RefCountedObject) arg).ref();
-                            break;
-                        }
-                    }
-                }
-            }
             return ptr;
         }
  
@@ -133,33 +110,15 @@
             if (result == null) {
                 return null;
             }
-            if (context instanceof MethodResultContext) {
-                //
-                // By default, we assume objects have incremented reference counts. 
-            	// Otherwise, the code generator should have created an @Return(transfer=NOTHING)
-            	// annotation.
-                //
-                Return anno = ((MethodResultContext) context).getMethod().getAnnotation(Return.class);
-                boolean ownsHandle;
-                if (anno == null || anno.transfer().equals(Transfer.EVERYTHING)) {
-                	ownsHandle = true;
-                } else {
-                	ownsHandle = false;
-                }
-                int refadj = ownsHandle ? -1 : 0;
-                return NativeObject.objectFor((Pointer) result, context.getTargetType(), refadj, ownsHandle);
-            }
-            if (context instanceof CallbackParameterContext) {
-                return NativeObject.objectFor((Pointer) result, context.getTargetType(), 1, true);
-            }
-            if (context instanceof StructureReadContext) {
-                StructureReadContext sctx = (StructureReadContext) context;
-                boolean ownsHandle = sctx.getField().getAnnotation(ConstField.class) == null;
-                return NativeObject.objectFor((Pointer) result, context.getTargetType(), 1, ownsHandle);
-            }
             if (context instanceof FunctionResultContext) {
-            	return NativeObject.objectFor((Pointer) result, context.getTargetType(), 0, true);
+            	return NativeObject.objectFor((Pointer) result, context.getTargetType(), true, true);
+            }            
+            if (context instanceof CallbackParameterContext || context instanceof StructureReadContext) {
+                return NativeObject.objectFor((Pointer) result, context.getTargetType(), false, true);
             }
+            if (context instanceof MethodResultContext) {
+            	throw new RuntimeException("Got illegal MethodResultContext in GTypeMapper");
+            }            
             throw new IllegalStateException("Cannot convert to NativeObject from " + context);
         }
         

Modified: trunk/src/org/gnome/gir/gobject/GlibRuntime.java
==============================================================================
--- trunk/src/org/gnome/gir/gobject/GlibRuntime.java	(original)
+++ trunk/src/org/gnome/gir/gobject/GlibRuntime.java	Sun Nov 16 22:52:12 2008
@@ -40,6 +40,12 @@
 	 */
 	private static final Set<CallbackData> outstandingCallbacks 
 		= Collections.synchronizedSet(new HashSet<CallbackData>());
+
+	public static final String toStringAndGFree(Pointer ptr) {
+		String result = ptr.getString(0);
+		GlibAPI.glib.g_free(ptr);
+		return result;
+	}
 	
 	public static final GlibAPI.GDestroyNotify createDestroyNotify(Callback callback) {
 		if (callback == null)

Modified: trunk/src/org/gnome/gir/gobject/Handle.java
==============================================================================
--- trunk/src/org/gnome/gir/gobject/Handle.java	(original)
+++ trunk/src/org/gnome/gir/gobject/Handle.java	Sun Nov 16 22:52:12 2008
@@ -51,25 +51,19 @@
     // Use this to propagate low level pointer arguments up the constructor chain
     protected static class Initializer {
         public final Pointer ptr;
-        public final boolean needRef, ownsHandle;
-        public Initializer() {
-            this.ptr = null;
-            this.needRef = false;
-            this.ownsHandle = false;
-        }
+        public final boolean ownsRef, ownsHandle;
+        
         public Initializer(Pointer ptr) {
-        	this(ptr, false, true);
+        	this(ptr, true, true);
         }
-        public Initializer(Pointer ptr, boolean needRef, boolean ownsHandle) {
+        public Initializer(Pointer ptr, boolean ownsRef, boolean ownsHandle) {
         	if (ptr == null)
         		throw new RuntimeException("Invalid NULL pointer for initializer");
             this.ptr = ptr;
-            this.needRef = needRef;
+            this.ownsRef = ownsRef;
             this.ownsHandle = ownsHandle;
         }
-    }	
-    
-    protected static final Initializer defaultInit = new Initializer();    
+    }  
 
     public Handle() {
     }

Modified: trunk/src/org/gnome/gir/gobject/NativeObject.java
==============================================================================
--- trunk/src/org/gnome/gir/gobject/NativeObject.java	(original)
+++ trunk/src/org/gnome/gir/gobject/NativeObject.java	Sun Nov 16 22:52:12 2008
@@ -162,11 +162,8 @@
         }
         return ref != null ? ref.get() : null;
     }
-    public static <T extends NativeObject> T objectFor(Pointer ptr, Class<T> cls, boolean needRef) {
-        return objectFor(ptr, cls, needRef, true);
-    }
-    public static <T extends NativeObject> T objectFor(Pointer ptr, Class<T> cls, boolean needRef, boolean ownsHandle) {
-        return objectFor(ptr, cls, needRef ? 1 : 0, ownsHandle);
+    public static <T extends NativeObject> T objectFor(Pointer ptr, Class<T> cls, boolean ownsRef) {
+        return objectFor(ptr, cls, ownsRef, true);
     }
     
     private static Class<?> getStubClassFor(Class<?> proxyClass) {
@@ -179,7 +176,7 @@
     }
     
     @SuppressWarnings("unchecked")
-	public static <T extends NativeObject> T objectFor(Pointer ptr, Class<T> cls, int refAdjust, boolean ownsHandle) {
+	public static <T extends NativeObject> T objectFor(Pointer ptr, Class<T> cls, boolean ownsRef, boolean ownsHandle) {
         // Ignore null pointers
         if (ptr == null) {
             return null;
@@ -190,7 +187,7 @@
         else if (GObject.class.isAssignableFrom(cls) || GObject.GObjectProxy.class.isAssignableFrom(cls))
         	obj = NativeObject.instanceFor(ptr);
         if (obj != null && cls.isInstance(obj)) {
-            if (refAdjust < 0) {
+            if (ownsRef) {
                 ((RefCountedObject) obj).unref(); // Lose the extra ref that we expect functions to add by default
             }
             return cls.cast(obj);
@@ -217,7 +214,7 @@
         try {
             Constructor<T> constructor = cls.getDeclaredConstructor(Initializer.class);
             constructor.setAccessible(true);
-            T retVal = constructor.newInstance(initializer(ptr, refAdjust > 0, ownsHandle));
+            T retVal = constructor.newInstance(initializer(ptr, ownsRef, ownsHandle));
             //retVal.initNativeHandle(ptr, refAdjust > 0, ownsHandle);
             return retVal;
         } catch (SecurityException ex) {

Modified: trunk/src/org/gnome/gir/gobject/RefCountedObject.java
==============================================================================
--- trunk/src/org/gnome/gir/gobject/RefCountedObject.java	(original)
+++ trunk/src/org/gnome/gir/gobject/RefCountedObject.java	Sun Nov 16 22:52:12 2008
@@ -53,7 +53,7 @@
     /** Creates a new instance of RefCountedObject */
     protected RefCountedObject(Initializer init) {
         super(init);
-        if (init.ownsHandle && init.needRef) {
+        if (init.ownsHandle && init.ownsRef) {
             ref();
         }
     }

Modified: trunk/stub-examples/Test.java
==============================================================================
--- trunk/stub-examples/Test.java	(original)
+++ trunk/stub-examples/Test.java	Sun Nov 16 22:52:12 2008
@@ -8,6 +8,7 @@
 import org.gnome.gir.gobject.GObject;
 import org.gnome.gir.gobject.GType;
 import org.gnome.gir.gobject.GTypeMapper;
+import org.gnome.gir.gobject.NativeObject;
 import org.gnome.gir.gobject.annotation.Return;
 import org.gnome.gir.repository.Direction;
 import org.gnome.gir.repository.Repository;
@@ -79,7 +80,7 @@
 		if (error.getValue() != null) {
 			throw new GErrorException(new GErrorStruct(error.getValue()));
 		}
-		return (Test) objectFor(result, Test.class);
+		return (Test) NativeObject.objectFor(result, Test.class, false);
 	}	
 	
 	public static Test newWithFoo(String blah) {



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]