[Kde-bindings] playground/bindings/kimono

Richard Dale Richard_Dale at tipitina.demon.co.uk
Fri Mar 23 12:17:54 UTC 2007


SVN commit 645696 by rdale:

* Cache various items in a dictionary with a key of the Smoke class's
  type to avoid using reflection to look up the items each time. A timing
  test consisting of starting the t14 cannon game and firing 5 shots at
  force 40, used half the mill of the version without caching.

* The following class is used to cache the data:

	public class SmokeClassData {
		public string className;
		public ConstructorInfo constructorInfo;
		public object[] constructorParamTypes;
		public MethodInfo proxyCreator;
		public FieldInfo smokeObjectField;
	}

	- classname: the C++ signature of the Smoke class
	- constructorInfo: the ConstructorInfo to construct a new instance
	- constructorParamTypes: the argument to pass to the constructorInfo
	- proxyCreator: the method to create the transparent proxy for the 
		new instance
	- smokeObjectField: the field for holding a pointer to the 
		smokeqyoto_object struct for the instance

* Add an entry to the strong reference map for custom QWidget subclasses 
  to prevent them being GC'd prematurally.

CCMAIL: kde-bindings at kde.org



 M  +28 -0     ChangeLog  
 M  +61 -39    SmokeMarshallers.cs  
 M  +4 -0      handlers.cpp  
 M  +11 -3     qyoto.cpp  


--- trunk/playground/bindings/kimono/ChangeLog #645695:645696
@@ -1,3 +1,31 @@
+2007-03-23  Richard Dale  <rdale at foton.es>
+
+	* Cache various items in a dictionary with a key of the Smoke class's
+	  type to avoid using reflection to look up the items each time. A timing
+	  test consisting of starting the t14 cannon game and firing 5 shots at
+	  force 40, used half the mill of the version without caching.
+
+	* The following class is used to cache the data:
+
+		public class SmokeClassData {
+			public string className;
+			public ConstructorInfo constructorInfo;
+			public object[] constructorParamTypes;
+			public MethodInfo proxyCreator;
+			public FieldInfo smokeObjectField;
+		}
+
+		- classname: the C++ signature of the Smoke class
+		- constructorInfo: the ConstructorInfo to construct a new instance
+		- constructorParamTypes: the argument to pass to the constructorInfo
+		- proxyCreator: the method to create the transparent proxy for the 
+			new instance
+		- smokeObjectField: the field for holding a pointer to the 
+			smokeqyoto_object struct for the instance
+
+	* Add an entry to the strong reference map for custom QWidget subclasses 
+	  to prevent them being GC'd prematurally.
+
 2007-03-22  Richard Dale  <rdale at foton.es>
 
 	* Added debug methods for logging GCHandle.Alloc() and Free() calls
--- trunk/playground/bindings/kimono/SmokeMarshallers.cs #645695:645696
@@ -25,6 +25,14 @@
 	using System.Runtime.InteropServices;
 	using System.Text;
 
+	public class SmokeClassData {
+		public string className;
+		public ConstructorInfo constructorInfo;
+		public object[] constructorParamTypes;
+		public MethodInfo proxyCreator;
+		public FieldInfo smokeObjectField;
+	}
+
 	public class SmokeMarshallers : object {
 		
 #region C++ functions
@@ -192,7 +200,6 @@
 		}
 		
 		public static IntPtr GetSmokeObject(IntPtr instancePtr) {
-
 			if (((int) instancePtr) == 0) {
 				return (IntPtr) 0;
 			}
@@ -200,22 +207,16 @@
 			Object instance = ((GCHandle) instancePtr).Target;
 			Debug.Assert(instance != null);
 
-			FieldInfo fieldInfo = instance.GetType().GetField(	"smokeObject", 
-															BindingFlags.NonPublic 
-															| BindingFlags.GetField
-															| BindingFlags.Instance );
-			return (IntPtr) fieldInfo.GetValue(instance);
+			SmokeClassData data = GetSmokeClassData(instance.GetType());
+			return (IntPtr) data.smokeObjectField.GetValue(instance);
 		}
 		
 		public static void SetSmokeObject(IntPtr instancePtr, IntPtr smokeObjectPtr) {
 			Object instance = ((GCHandle) instancePtr).Target;
 			Debug.Assert(instance != null);
 
-			FieldInfo fieldInfo = instance.GetType().GetField(	"smokeObject", 
-															BindingFlags.NonPublic 
-															| BindingFlags.GetField
-															| BindingFlags.Instance );
-			fieldInfo.SetValue(instance, smokeObjectPtr);
+			SmokeClassData data = GetSmokeClassData(instance.GetType());
+			data.smokeObjectField.SetValue(instance, smokeObjectPtr);
 			return;
 		}
 		
@@ -356,6 +357,50 @@
 			}
 		}
 
+		static Dictionary<Type, SmokeClassData> smokeClassCache = new Dictionary<Type, SmokeClassData> ();
+		
+		public static SmokeClassData GetSmokeClassData(Type t) {
+			SmokeClassData result;
+
+			if (!smokeClassCache.TryGetValue(t, out result)) {
+				result = new SmokeClassData();
+
+				object[] attr = t.GetCustomAttributes(typeof(SmokeClass), false);
+				if (attr.Length > 0) {
+					result.className = ((SmokeClass) attr[0]).signature;
+				}
+
+				Type[] paramTypes = new Type[1];
+				paramTypes[0] = typeof(Type);
+				result.constructorParamTypes = new object[] { paramTypes[0] };
+
+				result.constructorInfo = t.GetConstructor(BindingFlags.NonPublic 
+					| BindingFlags.Instance, null, new Type[ ] { typeof( Type ) } , null);
+				Debug.Assert(	result.constructorInfo != null,
+								"GetSmokeClassData(\"" + result.className + "\") constructor method missing" );
+
+				Type klass = t;
+				do {
+					result.proxyCreator = klass.GetMethod("CreateProxy", BindingFlags.NonPublic 
+																| BindingFlags.Instance
+																| BindingFlags.DeclaredOnly);
+
+					klass = klass.BaseType;
+				} while (result.proxyCreator == null && klass != typeof(object));
+
+				Debug.Assert(	result.proxyCreator != null, 
+								"GetSmokeClassData(\"" + result.className + "\") no CreateProxy() found" );
+
+				result.smokeObjectField = t.GetField(	"smokeObject", 
+														BindingFlags.NonPublic 
+														| BindingFlags.GetField
+														| BindingFlags.Instance );
+				smokeClassCache[t] = result;
+			}
+
+			return result;
+		}
+
 		// CreateInstance() creates a wrapper instance around a C++ instance which
 		// has been created in C++ code, and not via a Qyoto C# constructor call.
 		// It takes the class name string and obtains its Type. Then it finds the
@@ -367,42 +412,19 @@
 		// 'CreateProxy()' to create the transparent proxy to forward the method
 		// calls to SmokeInvocation.Invoke() is called.
 		public static IntPtr CreateInstance(string className) {
-			Type klass = Type.GetType(className);
-			Type[] constructorParamTypes = new Type[1];
-			constructorParamTypes[0] = typeof(Type);
-			ConstructorInfo constructorInfo = klass.GetConstructor(BindingFlags.NonPublic 
-					| BindingFlags.Instance, null, new Type[ ] { typeof( Type ) } , null);
-
-			Debug.Assert(	constructorInfo != null,
-							"CreateInstance(\"" + className + "\") constructor method missing" );
-
-			object result = constructorInfo.Invoke(new object [] { constructorParamTypes[0] });
+			SmokeClassData data = GetSmokeClassData(Type.GetType(className));
+			object result = data.constructorInfo.Invoke(data.constructorParamTypes);
 #if DEBUG
 			if ((QDebug.DebugChannel() & QtDebugChannel.QTDB_GC) != 0) {
 				Console.WriteLine("CreateInstance(\"{0}\") constructed {1}", className, result);
 			}
 #endif
-
-			MethodInfo proxyCreator = null;
-			do {
-				proxyCreator = klass.GetMethod("CreateProxy", BindingFlags.NonPublic 
-																| BindingFlags.Instance
-																| BindingFlags.DeclaredOnly);
-				if (proxyCreator != null) {
-					proxyCreator.Invoke(result, null);
+			data.proxyCreator.Invoke(result, null);
 #if DEBUG
-					return (IntPtr) DebugGCHandle.Alloc(result);
+			return (IntPtr) DebugGCHandle.Alloc(result);
 #else
-					return (IntPtr) GCHandle.Alloc(result);
+			return (IntPtr) GCHandle.Alloc(result);
 #endif
-				}
-
-				klass = klass.BaseType;
-			} while (klass != typeof(object));
-
-			Debug.Assert(	proxyCreator != null, 
-							"CreateInstance(\"" + className + "\") no CreateProxy() found" );
-			return (IntPtr) 0;
 		}
 
 		public static IntPtr IntPtrToCharStarStar(IntPtr ptr) {
--- trunk/playground/bindings/kimono/handlers.cpp #645695:645696
@@ -257,6 +257,10 @@
 		if (qwidget->parentWidget() != 0) {
 			return true;
 		}
+		// Don't garbage collect custom subclasses of QWidget classes for now
+		const QMetaObject * meta = qwidget->metaObject();
+		Smoke::Index classId = o->smoke->idClass(meta->className());
+		return (classId == 0);
 	} else if (isDerivedFromByName(o->smoke, className, "QObject")) {
 		QObject * qobject = (QObject *) o->smoke->cast(o->ptr, o->classId, o->smoke->idClass("QObject"));
 		if (qobject->parent() != 0) {
--- trunk/playground/bindings/kimono/qyoto.cpp #645695:645696
@@ -998,9 +998,18 @@
 		}
 
 		void * obj = getPointerObject(ptr);
+
+		if (obj == 0) {
+			if( do_debug & qtdb_virtual ) {  // if not in global destruction
+				printf("Cannot find object for virtual method %p -> %p\n", ptr, obj);
+			}
+
+			return false;
+		}
+
 		smokeqyoto_object *o = value_obj_info(obj);
 
-		if (!o) {
+		if (o == 0) {
 			if( do_debug & qtdb_virtual ) {  // if not in global destruction
 				printf("Cannot find object for virtual method %p -> %p\n", ptr, obj);
 			}
@@ -1015,8 +1024,7 @@
 			
 			args[0].s_int = qt_metacall(obj, _c, _id, _o);
 
-			// This line stops custom slots from working - how can that be?
-//			(*FreeGCHandle)(obj);
+			(*FreeGCHandle)(obj);
 			return true;
 		}
 		



More information about the Kde-bindings mailing list