|
|
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@xxxxxxx
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@xxxxxxxx>
+
+ * 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@xxxxxxxx>
* 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;
}
|
|