[Zope-CVS] CVS: PythonNet/src/runtime - ArrayObject.cs:1.3
CLRObject.cs:1.3 ClassBase.cs:1.7 ClassManager.cs:1.6
ClassObject.cs:1.7 Converter.cs:1.5 DebugHelper.cs:1.4
DelegateObject.cs:1.4 EventObject.cs:1.4 ExtensionType.cs:1.2
FieldObject.cs:1.2 ImportHook.cs:1.5 Indexer.cs:1.3
InterfaceObject.cs:1.2 Interop.cs:1.3 ManagedType.cs:1.3
MetaType.cs:1.6 MethodBinder.cs:1.5 MethodWrapper.cs:1.4
ModuleObject.cs:1.3 PropertyObject.cs:1.3 PyObject.cs:1.2
Python.cs:1.2 Runtime.cs:1.10 TypeManager.cs:1.8
Brian Lloyd
brian at zope.com
Mon Oct 20 23:05:46 EDT 2003
Update of /cvs-repository/PythonNet/src/runtime
In directory cvs.zope.org:/tmp/cvs-serv26410/src/runtime
Modified Files:
ArrayObject.cs CLRObject.cs ClassBase.cs ClassManager.cs
ClassObject.cs Converter.cs DebugHelper.cs DelegateObject.cs
EventObject.cs ExtensionType.cs FieldObject.cs ImportHook.cs
Indexer.cs InterfaceObject.cs Interop.cs ManagedType.cs
MetaType.cs MethodBinder.cs MethodWrapper.cs ModuleObject.cs
PropertyObject.cs PyObject.cs Python.cs Runtime.cs
TypeManager.cs
Log Message:
Check in the Great Type Refactoring before I go and break it again. All of
the tests pass again (well, except for two that were failing before the
refactoring).
The end result is a nice net reduction of C# code, letting the Python
runtime handle much more of the work of creating types.
The refactored version also plays nicely with the Python GC, so the
Python GC no longer needs to be disabled to run things under Python
for .NET. :) Also added some very preliminary leak and stress testing
scripts.
=== PythonNet/src/runtime/ArrayObject.cs 1.2 => 1.3 ===
--- PythonNet/src/runtime/ArrayObject.cs:1.2 Mon Jul 28 22:28:15 2003
+++ PythonNet/src/runtime/ArrayObject.cs Mon Oct 20 23:05:14 2003
@@ -38,14 +38,6 @@
return IntPtr.Zero;
}
- [CallConvCdecl()]
- public static int tp_init(IntPtr ob, IntPtr args, IntPtr kw) {
- Exceptions.SetError(Exceptions.TypeError,
- "cannot instantiate array wrapper"
- );
- return -1;
- }
-
//====================================================================
// Implements __getitem__ for array types.
=== PythonNet/src/runtime/CLRObject.cs 1.2 => 1.3 ===
--- PythonNet/src/runtime/CLRObject.cs:1.2 Fri Aug 1 19:56:10 2003
+++ PythonNet/src/runtime/CLRObject.cs Mon Oct 20 23:05:14 2003
@@ -21,35 +21,33 @@
internal Object inst;
- internal CLRObject(Object ob, IntPtr pyType) : base() {
- PyObjectHead pyObj = new PyObjectHead();
- this.gcHandle = GCHandle.Alloc(this);
- pyObj.ob_data = (IntPtr) this.gcHandle;
- pyObj.ob_refcnt = (IntPtr) 0; // rethink!
- pyObj.ob_type = pyType;
- this.tpHandle = pyType;
- Runtime.Incref(pyType); //??
-
- this.pyHandle = Runtime.PyMem_Malloc((4 * IntPtr.Size));
- Marshal.StructureToPtr(pyObj, this.pyHandle, false);
+ internal CLRObject(Object ob, IntPtr tp) : base() {
+ IntPtr py = Runtime.PyType_GenericAlloc(tp, 0);
+ GCHandle gc = GCHandle.Alloc(this);
+ Marshal.WriteIntPtr(py, ObjectOffset.magic(), (IntPtr)gc);
+ this.tpHandle = tp;
+ this.pyHandle = py;
+ this.gcHandle = gc;
inst = ob;
}
- // todo: caching of ref types?
internal static CLRObject GetInstance(Object ob, IntPtr pyType) {
return new CLRObject(ob, pyType);
}
+
internal static CLRObject GetInstance(Object ob) {
ClassBase cc = ClassManager.GetClass(ob.GetType());
return GetInstance(ob, cc.tpHandle);
}
+
internal static IntPtr GetInstHandle(Object ob, IntPtr pyType) {
CLRObject co = GetInstance(ob, pyType);
return co.pyHandle;
}
+
internal static IntPtr GetInstHandle(Object ob, Type type) {
ClassBase cc = ClassManager.GetClass(type);
=== PythonNet/src/runtime/ClassBase.cs 1.6 => 1.7 ===
--- PythonNet/src/runtime/ClassBase.cs:1.6 Tue Oct 7 22:29:17 2003
+++ PythonNet/src/runtime/ClassBase.cs Mon Oct 20 23:05:14 2003
@@ -33,9 +33,7 @@
internal ClassBase(Type tp) : base() {
indexer = null;
- //tpHandle = TypeManager.GetTypeHandle(this, tp);
type = tp;
- //InitializeClass();
}
internal virtual bool CanSubclass() {
@@ -44,6 +42,15 @@
//====================================================================
+ // Implements __init__ for reflected classes and value types.
+ //====================================================================
+
+ [CallConvCdecl()]
+ public static int tp_init(IntPtr ob, IntPtr args, IntPtr kw) {
+ return 0;
+ }
+
+ //====================================================================
// Standard comparison implementation for instances of reflected types.
//====================================================================
@@ -52,11 +59,12 @@
if (ob == other) {
return 0;
}
+
CLRObject co1 = GetManagedObject(ob) as CLRObject;
CLRObject co2 = GetManagedObject(other) as CLRObject;
Object o1 = co1.inst;
Object o2 = co2.inst;
- // Console.WriteLine("cmp: {0} {1}", o1, o2);
+
if (Object.Equals(o1, o2)) {
return 0;
}
@@ -109,34 +117,38 @@
//====================================================================
- // Standard dealloc implementation for instances of reflected types.
+ // Default implementations for required Python GC support.
//====================================================================
[CallConvCdecl()]
- public static void tp_dealloc(IntPtr ob) {
- //DebugUtil.Print("tp_dealloc: ", ob);
-
- ManagedType self = GetManagedObject(ob);
- Runtime.PyMem_Free(self.pyHandle);
- Runtime.Decref(self.tpHandle);
- self.gcHandle.Free();
-
- //Console.WriteLine("tp_dealloc done");
- }
-
-
- [CallConvCdecl()]
public static int tp_traverse(IntPtr ob, IntPtr func, IntPtr args) {
- DebugUtil.Print("tp_traverse: ", ob);
return 0;
}
[CallConvCdecl()]
public static int tp_clear(IntPtr ob) {
- DebugUtil.Print("tp_clear: ", ob);
return 0;
}
+ [CallConvCdecl()]
+ public static int tp_is_gc(IntPtr type) {
+ return 1;
+ }
+
+ //====================================================================
+ // Standard dealloc implementation for instances of reflected types.
+ //====================================================================
+
+ [CallConvCdecl()]
+ public static void tp_dealloc(IntPtr ob) {
+ ManagedType self = GetManagedObject(ob);
+ IntPtr dict = Marshal.ReadIntPtr(ob, ObjectOffset.ob_dict);
+ Runtime.Decref(dict);
+ Runtime._PyObject_GC_UnTrack(self.pyHandle);
+ Runtime._PyObject_GC_Del(self.pyHandle);
+ Runtime.Decref(self.tpHandle);
+ self.gcHandle.Free();
+ }
}
=== PythonNet/src/runtime/ClassManager.cs 1.5 => 1.6 ===
--- PythonNet/src/runtime/ClassManager.cs:1.5 Thu Oct 2 23:06:17 2003
+++ PythonNet/src/runtime/ClassManager.cs Mon Oct 20 23:05:14 2003
@@ -98,12 +98,13 @@
// managed type, filling the Python type slots with thunks that
// point to the managed methods providing the implementation.
- impl.tpHandle = TypeManager.GetTypeHandle(impl, type);
+
+ IntPtr tp = TypeManager.GetTypeHandle(impl, type);
+ impl.tpHandle = tp;
// Finally, initialize the class __dict__ and return the object.
+ IntPtr dict = Marshal.ReadIntPtr(tp, TypeOffset.tp_dict);
- IntPtr pp = Runtime._PyObject_GetDictPtr(impl.tpHandle);
- IntPtr dict = Marshal.ReadIntPtr(pp, 0);
IDictionaryEnumerator iter;
ManagedType item;
string name;
=== PythonNet/src/runtime/ClassObject.cs 1.6 => 1.7 ===
--- PythonNet/src/runtime/ClassObject.cs:1.6 Tue Oct 7 22:29:17 2003
+++ PythonNet/src/runtime/ClassObject.cs Mon Oct 20 23:05:14 2003
@@ -50,9 +50,8 @@
int flags = (int)Marshal.ReadIntPtr(tp, TypeOffset.tp_flags);
if ((flags & TypeFlags.Subclass) != 0) {
- // ob = tp.__bases__[0].__new__
- IntPtr _base = Marshal.ReadIntPtr(tp, TypeOffset.tp_base);
- if (_base == IntPtr.Zero) {
+ IntPtr base_ = Marshal.ReadIntPtr(tp, TypeOffset.tp_base);
+ if (base_ == IntPtr.Zero) {
return Exceptions.InvalidTypeError(tp);
}
IntPtr func = Marshal.ReadIntPtr(tp, TypeOffset.tp_new);
@@ -60,7 +59,7 @@
return Exceptions.InvalidTypeError(tp);
}
- IntPtr obj = NativeCall.Call_3(func, _base, args, kw);
+ IntPtr obj = NativeCall.Call_3(func, base_, args, kw);
if (obj == IntPtr.Zero) {
return IntPtr.Zero;
}
@@ -71,7 +70,7 @@
// because we only allow single inheritance and can depend on
// a known in-memory format for the instance object.
- Runtime.Decref(_base);
+ Runtime.Decref(base_);
Runtime.Incref(tp);
Marshal.WriteIntPtr(obj, ObjectOffset.ob_type, tp);
@@ -91,10 +90,7 @@
// a class that is not really derived from a managed class.
if (self == null) {
- Exceptions.SetError(Exceptions.TypeError,
- "invalid managed subclass"
- );
- return IntPtr.Zero;
+ return Exceptions.InvalidTypeError(tp);
}
Type type = self.type;
@@ -117,6 +113,7 @@
if (!Converter.ToManaged(op, type, out result, true)) {
return IntPtr.Zero;
}
+
op = CLRObject.GetInstHandle(result, tp);
Runtime.Incref(op);
return op;
@@ -139,15 +136,6 @@
return self.binder.Invoke(IntPtr.Zero, args, kw);
}
- //====================================================================
- // Implements __init__ for reflected classes and value types.
- //====================================================================
-
-// [CallConvCdecl()]
-// public static int tp_init(IntPtr ob, IntPtr args, IntPtr kw) {
-// return 0;
-// }
-
//====================================================================
// Implements __getitem__ for reflected classes and value types.
@@ -180,12 +168,16 @@
free = true;
}
- IntPtr value = cls.indexer.GetItem(ob, args);
+ IntPtr value = IntPtr.Zero;
- if (free) {
- Runtime.Decref(args);
+ try {
+ value = cls.indexer.GetItem(ob, args);
+ }
+ finally {
+ if (free) {
+ Runtime.Decref(args);
+ }
}
-
return value;
}
@@ -231,12 +223,15 @@
Runtime.Incref(v);
Runtime.PyTuple_SetItem(real, i, v);
- IntPtr value = cls.indexer.SetItem(ob, real);
-
- Runtime.Decref(real);
+ try {
+ cls.indexer.SetItem(ob, real);
+ }
+ finally {
+ Runtime.Decref(real);
- if (free) {
- Runtime.Decref(args);
+ if (free) {
+ Runtime.Decref(args);
+ }
}
if (Exceptions.ErrorOccurred()) {
=== PythonNet/src/runtime/Converter.cs 1.4 => 1.5 ===
--- PythonNet/src/runtime/Converter.cs:1.4 Tue Sep 30 19:54:11 2003
+++ PythonNet/src/runtime/Converter.cs Mon Oct 20 23:05:14 2003
@@ -31,6 +31,7 @@
static Type int32Type;
static Type int64Type;
static Type flagsType;
+ static Type typeType;
static Converter () {
objectType = typeof(Object);
@@ -38,6 +39,7 @@
int32Type = typeof(Int32);
int64Type = typeof(Int64);
flagsType = typeof(FlagsAttribute);
+ typeType = typeof(Type);
}
@@ -59,12 +61,11 @@
return result;
}
- // Special case: if the input conversion type is 'Object', we
- // convert to the actual runtime type of the input value.
+ // hmm - from Python, we almost never care what the declared
+ // type is. we'd rather have the object bound to the actual
+ // implementing class.
- if (type == objectType) {
- type = value.GetType();
- }
+ type = value.GetType();
TypeCode tc = Type.GetTypeCode(type);
@@ -171,6 +172,10 @@
return false;
}
+ if (obType.IsArray) {
+ return ToArray(value, obType, out result, setError);
+ }
+
if (obType.IsEnum) {
return ToEnum(value, obType, out result, setError);
}
@@ -477,6 +482,64 @@
return false;
}
+
+
+ static void SetConversionError(IntPtr value, Type target) {
+ IntPtr ob = Runtime.PyObject_Repr(value);
+ string src = Runtime.GetManagedString(ob);
+ Runtime.Decref(ob);
+ string error = String.Format(
+ "Cannot convert {0} to {1}", src, target
+ );
+ Exceptions.SetError(Exceptions.TypeError, error);
+ }
+
+
+ //====================================================================
+ // Convert a Python value to a correctly typed managed array instance.
+ // The Python value must support the Python sequence protocol and the
+ // items in the sequence must be convertible to the target array type.
+ //====================================================================
+
+ static bool ToArray(IntPtr value, Type obType, out Object result,
+ bool setError) {
+
+ Type elementType = obType.GetElementType();
+ int size = Runtime.PySequence_Size(value);
+ result = null;
+
+ if (size < 0) {
+ if (setError) {
+ SetConversionError(value, obType);
+ return false;
+ }
+ }
+
+ Array items = Array.CreateInstance(elementType, size);
+
+ for (int i = 0; i < size; i++) {
+ Object obj = null;
+ IntPtr item = Runtime.PySequence_GetItem(value, i);
+ if (item == IntPtr.Zero) {
+ if (setError) {
+ SetConversionError(value, obType);
+ return false;
+ }
+ }
+
+ if (!Converter.ToManaged(item, elementType, out obj, true)) {
+ Runtime.Decref(item);
+ return false;
+ }
+
+ items.SetValue(obj, i);
+ Runtime.Decref(item);
+ }
+
+ result = items;
+ return true;
+ }
+
//====================================================================
// Convert a Python value to a correctly typed managed enum instance.
=== PythonNet/src/runtime/DebugHelper.cs 1.3 => 1.4 ===
--- PythonNet/src/runtime/DebugHelper.cs:1.3 Wed Jul 30 09:55:50 2003
+++ PythonNet/src/runtime/DebugHelper.cs Mon Oct 20 23:05:14 2003
@@ -11,6 +11,7 @@
using System;
using System.Collections;
+using System.Reflection;
using System.Runtime.InteropServices;
namespace Python.Runtime {
@@ -26,6 +27,9 @@
result += " ";
for (int i = 0; i < args.Length; i++) {
+ if (args[i] == IntPtr.Zero) {
+ Console.WriteLine("null arg to print");
+ }
IntPtr ob = Runtime.PyObject_Repr(args[i]);
result += Runtime.GetManagedString(ob);
Runtime.Decref(ob);
@@ -33,6 +37,47 @@
}
Console.WriteLine(result);
return;
+ }
+
+
+ internal static void DumpType(IntPtr type) {
+ IntPtr op = Marshal.ReadIntPtr(type, TypeOffset.tp_name);
+ string name = Marshal.PtrToStringAnsi(op);
+
+ Console.WriteLine("Dump type: {0}", name);
+
+ op = Marshal.ReadIntPtr(type, TypeOffset.ob_type);
+ DebugUtil.Print(" type: ", op);
+
+ op = Marshal.ReadIntPtr(type, TypeOffset.tp_base);
+ DebugUtil.Print(" base: ", op);
+
+ op = Marshal.ReadIntPtr(type, TypeOffset.tp_bases);
+ DebugUtil.Print(" bases: ", op);
+
+ op = Marshal.ReadIntPtr(type, TypeOffset.tp_mro);
+ DebugUtil.Print(" mro: ", op);
+
+ op = Marshal.ReadIntPtr(type, TypeOffset.tp_dict);
+ if (op == IntPtr.Zero) {
+ Console.WriteLine(" dict: null");
+ }
+ else {
+ DebugUtil.Print(" dict: ", op);
+ }
+
+ FieldInfo[] slots = typeof(TypeOffset).GetFields();
+ int size = IntPtr.Size;
+
+ for (int i = 0; i < slots.Length; i++) {
+ int offset = i * size;
+ name = slots[i].Name;
+ op = Marshal.ReadIntPtr(type, offset);
+ Console.WriteLine(" {0}: {1}", name, op);
+ }
+
+ Console.WriteLine("");
+ Console.WriteLine("");
}
=== PythonNet/src/runtime/DelegateObject.cs 1.3 => 1.4 ===
--- PythonNet/src/runtime/DelegateObject.cs:1.3 Sat Aug 2 17:55:30 2003
+++ PythonNet/src/runtime/DelegateObject.cs Mon Oct 20 23:05:14 2003
@@ -82,14 +82,6 @@
return op;
}
- //====================================================================
- // Implements __init__ for reflected delegate types.
- //====================================================================
-
- [CallConvCdecl()]
- public static int tp_init(IntPtr ob, IntPtr args, IntPtr kw) {
- return 0;
- }
//====================================================================
// Implements __call__ for reflected delegate types.
=== PythonNet/src/runtime/EventObject.cs 1.3 => 1.4 ===
--- PythonNet/src/runtime/EventObject.cs:1.3 Tue Oct 7 22:29:17 2003
+++ PythonNet/src/runtime/EventObject.cs Mon Oct 20 23:05:14 2003
@@ -214,7 +214,7 @@
//====================================================================
[CallConvCdecl()]
- public static int tp_descr_set(IntPtr ds, IntPtr ob, IntPtr val) {
+ public static new int tp_descr_set(IntPtr ds, IntPtr ob, IntPtr val) {
EventBinding e = GetManagedObject(val) as EventBinding;
if (e != null) {
=== PythonNet/src/runtime/ExtensionType.cs 1.1 => 1.2 ===
--- PythonNet/src/runtime/ExtensionType.cs:1.1 Mon Jul 14 15:59:51 2003
+++ PythonNet/src/runtime/ExtensionType.cs Mon Oct 20 23:05:14 2003
@@ -16,47 +16,54 @@
namespace Python.Runtime {
- //========================================================================
- // Base class for extensions whose instances *share* a single Python
- // type object, such as the types that represent CLR methods, fields,
- // etc. Instances implemented by this class do not support subtyping.
- //========================================================================
+ /// <summary>
+ /// Base class for extensions whose instances *share* a single Python
+ /// type object, such as the types that represent CLR methods, fields,
+ /// etc. Instances implemented by this class do not support subtyping.
+ /// </summary>
internal abstract class ExtensionType : ManagedType {
public ExtensionType() : base() {
- // Get the Python type pointer for this extension type. This
- // will return a cached handle after the first call per type.
+ // Create a new PyObject whose type is a generated type that is
+ // implemented by the particuar concrete ExtensionType subclass.
+ // The Python instance object is related to an instance of a
+ // particular concrete subclass with a hidden CLR gchandle.
+
+ IntPtr tp = TypeManager.GetTypeHandle(this.GetType());
+ IntPtr py = Runtime.PyType_GenericAlloc(tp, 0);
+
+ GCHandle gc = GCHandle.Alloc(this);
+ Marshal.WriteIntPtr(py, ObjectOffset.magic(), (IntPtr)gc);
+
+ // We have to support gc because the type machinery makes it very
+ // hard not to - but we really don't have a need for it in most
+ // concrete extension types, so untrack the object to save calls
+ // from Python into the managed runtime that are pure overhead.
+
+ Runtime._PyObject_GC_UnTrack(py);
+
+ this.tpHandle = tp;
+ this.pyHandle = py;
+ this.gcHandle = gc;
+ }
+
- this.tpHandle = TypeManager.GetTypeHandle(this.GetType());
+ //====================================================================
+ // Common finalization code to support custom tp_deallocs.
+ //====================================================================
- // Create a PyObject struct to associate this object with Python.
- // We store a GCHandle to the CLR object in the PyObject struct
- // and store the PyObject * in the CLR object, which lets us find
- // the associated object given either the Python or CLR version.
-
- PyObjectHead pyObj = new PyObjectHead();
- this.gcHandle = GCHandle.Alloc(this);
- pyObj.ob_data = (IntPtr)this.gcHandle;
- pyObj.ob_refcnt = (IntPtr) 1;
- pyObj.ob_type = tpHandle;
- Runtime.Incref(tpHandle);
-
- // Now we blit this to unmanaged memory to avoid having to pin
- // CLR objects, which would interfere with the managed GC.
-
- this.pyHandle = Runtime.PyMem_Malloc((3 * IntPtr.Size));
- GCHandle gch = GCHandle.Alloc(pyObj, GCHandleType.Pinned);
- Marshal.StructureToPtr(pyObj, pyHandle, false);
- gch.Free();
+ public static void FinalizeObject(ManagedType self) {
+ Runtime._PyObject_GC_Del(self.pyHandle);
+ Runtime.Decref(self.tpHandle);
+ self.gcHandle.Free();
}
- [CallConvCdecl()]
- public static int tp_is_gc(IntPtr type) {
- return 0;
- }
+ //====================================================================
+ // Type __setattr__ implementation.
+ //====================================================================
[CallConvCdecl()]
public static int tp_setattro(IntPtr ob, IntPtr key, IntPtr val) {
@@ -68,21 +75,54 @@
return -1;
}
+
+ //====================================================================
+ // Default __set__ implementation - this prevents descriptor instances
+ // being silently replaced in a type __dict__ by default __setattr__.
+ //====================================================================
+
+ [CallConvCdecl()]
+ public static int tp_descr_set(IntPtr ds, IntPtr ob, IntPtr val) {
+ string message = "attribute is read-only";
+ Exceptions.SetError(Exceptions.AttributeError, message);
+ return -1;
+ }
+
+
+ //====================================================================
+ // Required Python GC support.
+ //====================================================================
+
+ [CallConvCdecl()]
+ public static int tp_traverse(IntPtr ob, IntPtr func, IntPtr args) {
+ return 0;
+ }
+
+
+ [CallConvCdecl()]
+ public static int tp_clear(IntPtr ob) {
+ return 0;
+ }
+
+
+ [CallConvCdecl()]
+ public static int tp_is_gc(IntPtr type) {
+ return 1;
+ }
+
+
+ //====================================================================
+ // Default dealloc implementation.
+ //====================================================================
+
[CallConvCdecl()]
public static void tp_dealloc(IntPtr ob) {
// Clean up a Python instance of this extension type. This
// frees the allocated Python object and decrefs the type.
+ //Console.WriteLine("dealloc");
ManagedType self = GetManagedObject(ob);
FinalizeObject(self);
}
-
- public static void FinalizeObject(ManagedType self) {
- // Perform standard base-class level finalization.
- Runtime.PyMem_Free(self.pyHandle);
- Runtime.Decref(self.tpHandle);
- self.gcHandle.Free();
- }
-
}
=== PythonNet/src/runtime/FieldObject.cs 1.1 => 1.2 ===
--- PythonNet/src/runtime/FieldObject.cs:1.1 Mon Jul 14 15:59:51 2003
+++ PythonNet/src/runtime/FieldObject.cs Mon Oct 20 23:05:14 2003
@@ -80,7 +80,7 @@
//====================================================================
[CallConvCdecl()]
- public static int tp_descr_set(IntPtr ds, IntPtr ob, IntPtr val) {
+ public static new int tp_descr_set(IntPtr ds, IntPtr ob, IntPtr val) {
FieldObject self = (FieldObject)GetManagedObject(ds);
Object newval;
=== PythonNet/src/runtime/ImportHook.cs 1.4 => 1.5 ===
--- PythonNet/src/runtime/ImportHook.cs:1.4 Fri Aug 1 19:56:10 2003
+++ PythonNet/src/runtime/ImportHook.cs Mon Oct 20 23:05:14 2003
@@ -34,14 +34,10 @@
IntPtr mod = Runtime.PyDict_GetItemString(dict, "__builtin__");
py_import = Runtime.PyObject_GetAttrString(mod, "__import__");
+ hook = new StaticMethodWrapper(typeof(ImportHook),"__import__");
- // should never die
- hook = new StaticMethodWrapper(
- typeof(ImportHook),
- "__import__"
- );
+ Runtime.PyObject_SetAttrString(mod, "__import__", hook.pyHandle);
- Runtime.PyObject_SetAttrString(mod, "__import__", hook.pyHandle);
Runtime.Decref(hook.pyHandle);
root = new ModuleObject("");
@@ -77,7 +73,6 @@
// Could use Python here to avoid a string conversion.
string mod_name = Runtime.GetManagedString(py_mod_name);
- //Console.WriteLine(mod_name);
if (!(mod_name.StartsWith("CLR.") || mod_name == "CLR")) {
return Runtime.PyObject_Call(py_import, args, kw);
=== PythonNet/src/runtime/Indexer.cs 1.2 => 1.3 ===
--- PythonNet/src/runtime/Indexer.cs:1.2 Mon Jul 28 22:28:15 2003
+++ PythonNet/src/runtime/Indexer.cs Mon Oct 20 23:05:14 2003
@@ -60,8 +60,8 @@
}
- internal IntPtr SetItem(IntPtr inst, IntPtr args) {
- return SetterBinder.Invoke(inst, args, IntPtr.Zero);
+ internal void SetItem(IntPtr inst, IntPtr args) {
+ SetterBinder.Invoke(inst, args, IntPtr.Zero);
}
}
=== PythonNet/src/runtime/InterfaceObject.cs 1.1 => 1.2 ===
--- PythonNet/src/runtime/InterfaceObject.cs:1.1 Mon Jul 14 15:59:51 2003
+++ PythonNet/src/runtime/InterfaceObject.cs Mon Oct 20 23:05:14 2003
@@ -62,28 +62,8 @@
return op;
}
- //====================================================================
- // Implements __init__ for reflected interface types.
- //====================================================================
-
- [CallConvCdecl()]
- public static int tp_init(IntPtr ob, IntPtr args, IntPtr kw) {
- return 0;
- }
-
- /*
- public override IntPtr ClassRepr() {
- string s = String.Format("<delegate '{0}'>", this.type.FullName);
- return Runtime.PyString_FromStringAndSize(s, s.Length);
- }
- */
-
-
-
}
-
-
}
=== PythonNet/src/runtime/Interop.cs 1.2 => 1.3 ===
--- PythonNet/src/runtime/Interop.cs:1.2 Tue Sep 30 19:54:11 2003
+++ PythonNet/src/runtime/Interop.cs Mon Oct 20 23:05:14 2003
@@ -11,15 +11,17 @@
using System;
using System.Collections;
+using System.Collections.Specialized;
using System.Runtime.InteropServices;
using System.Reflection;
namespace Python.Runtime {
+ //=======================================================================
// This file defines objects to support binary interop with the Python
// runtime. Generally, the definitions here need to be kept up to date
// when moving to new Python versions.
-
+ //=======================================================================
[Serializable()]
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Delegate)]
@@ -35,24 +37,6 @@
}
- // This class defines the in-memory layout of instances of all managed
- // classes and subclasses of managed classes. Because we do not allow
- // multiple inheritance from managed classes, we are always in control
- // of the object layout.
-
- [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
- internal class PyObjectHead {
- public IntPtr ob_refcnt = IntPtr.Zero;
- public IntPtr ob_type = IntPtr.Zero;
- public IntPtr ob_data = IntPtr.Zero;
- public IntPtr ob_dict = IntPtr.Zero;
- }
-
-
- // This class protects the rest of the code from having to deal with
- // PyObject * offsets directly, makes the code clearer and prevents
- // bugs caused by bad offset caculation :)
-
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
internal class ObjectOffset {
@@ -64,6 +48,14 @@
ob_dict = 3 * size;
}
+ public static int magic() {
+ return ob_data;
+ }
+
+ public static int Size() {
+ return 4 * IntPtr.Size;
+ }
+
public static int ob_refcnt;
public static int ob_type;
public static int ob_data;
@@ -71,125 +63,6 @@
}
- // This class is a managed representation of the in-memory layout of a
- // Python type object. This must be kept in sync with the definition in
- // object.h when making changes to support new Python versions.
-
- [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
- internal class PyTypeObject {
- public IntPtr ob_refcnt = IntPtr.Zero;
- public IntPtr ob_type = IntPtr.Zero;
- public IntPtr ob_size = IntPtr.Zero;
- public IntPtr tp_name = IntPtr.Zero;
- public IntPtr tp_basicsize = IntPtr.Zero;
- public IntPtr tp_itemsize = IntPtr.Zero;
- public IntPtr tp_dealloc = IntPtr.Zero;
- public IntPtr tp_print = IntPtr.Zero;
- public IntPtr tp_getattr = IntPtr.Zero;
- public IntPtr tp_setattr = IntPtr.Zero;
- public IntPtr tp_compare = IntPtr.Zero;
- public IntPtr tp_repr = IntPtr.Zero;
- public IntPtr tp_as_number = IntPtr.Zero;
- public IntPtr tp_as_sequence = IntPtr.Zero;
- public IntPtr tp_as_mapping = IntPtr.Zero;
- public IntPtr tp_hash = IntPtr.Zero;
- public IntPtr tp_call = IntPtr.Zero;
- public IntPtr tp_str = IntPtr.Zero;
- public IntPtr tp_getattro = IntPtr.Zero;
- public IntPtr tp_setattro = IntPtr.Zero;
- public IntPtr tp_as_buffer = IntPtr.Zero;
- public IntPtr tp_flags = IntPtr.Zero;
- public IntPtr tp_doc = IntPtr.Zero;
- public IntPtr tp_traverse = IntPtr.Zero;
- public IntPtr tp_clear = IntPtr.Zero;
- public IntPtr tp_richcompare = IntPtr.Zero;
- public IntPtr tp_weaklistoffset = IntPtr.Zero;
- public IntPtr tp_iter = IntPtr.Zero;
- public IntPtr tp_iternext = IntPtr.Zero;
- public IntPtr tp_methods = IntPtr.Zero;
- public IntPtr tp_members = IntPtr.Zero;
- public IntPtr tp_getset = IntPtr.Zero;
- public IntPtr tp_base = IntPtr.Zero;
- public IntPtr tp_dict = IntPtr.Zero;
- public IntPtr tp_descr_get = IntPtr.Zero;
- public IntPtr tp_descr_set = IntPtr.Zero;
- public IntPtr tp_dictoffset = IntPtr.Zero;
- public IntPtr tp_init = IntPtr.Zero;
- public IntPtr tp_alloc = IntPtr.Zero;
- public IntPtr tp_new = IntPtr.Zero;
- public IntPtr tp_free = IntPtr.Zero;
- public IntPtr tp_is_gc = IntPtr.Zero;
- public IntPtr tp_bases = IntPtr.Zero;
- public IntPtr tp_mro = IntPtr.Zero;
- public IntPtr tp_cache = IntPtr.Zero;
- public IntPtr tp_subclasses = IntPtr.Zero;
- public IntPtr tp_weaklist = IntPtr.Zero;
-
- public IntPtr nb_add = IntPtr.Zero;
- public IntPtr nb_subtract = IntPtr.Zero;
- public IntPtr nb_multiply = IntPtr.Zero;
- public IntPtr nb_divide = IntPtr.Zero;
- public IntPtr nb_remainder = IntPtr.Zero;
- public IntPtr nb_divmod = IntPtr.Zero;
- public IntPtr nb_power = IntPtr.Zero;
- public IntPtr nb_negative = IntPtr.Zero;
- public IntPtr nb_positive = IntPtr.Zero;
- public IntPtr nb_absolute = IntPtr.Zero;
- public IntPtr nb_nonzero = IntPtr.Zero;
- public IntPtr nb_invert = IntPtr.Zero;
- public IntPtr nb_lshift = IntPtr.Zero;
- public IntPtr nb_rshift = IntPtr.Zero;
- public IntPtr nb_and = IntPtr.Zero;
- public IntPtr nb_xor = IntPtr.Zero;
- public IntPtr nb_or = IntPtr.Zero;
- public IntPtr nb_coerce = IntPtr.Zero;
- public IntPtr nb_int = IntPtr.Zero;
- public IntPtr nb_long = IntPtr.Zero;
- public IntPtr nb_float = IntPtr.Zero;
- public IntPtr nb_oct = IntPtr.Zero;
- public IntPtr nb_hex = IntPtr.Zero;
- public IntPtr nb_inplace_add = IntPtr.Zero;
- public IntPtr nb_inplace_subtract = IntPtr.Zero;
- public IntPtr nb_inplace_multiply = IntPtr.Zero;
- public IntPtr nb_inplace_divide = IntPtr.Zero;
- public IntPtr nb_inplace_remainder = IntPtr.Zero;
- public IntPtr nb_inplace_power = IntPtr.Zero;
- public IntPtr nb_inplace_lshift = IntPtr.Zero;
- public IntPtr nb_inplace_rshift = IntPtr.Zero;
- public IntPtr nb_inplace_and = IntPtr.Zero;
- public IntPtr nb_inplace_xor = IntPtr.Zero;
- public IntPtr nb_inplace_or = IntPtr.Zero;
- public IntPtr nb_floor_divide = IntPtr.Zero;
- public IntPtr nb_true_divide = IntPtr.Zero;
- public IntPtr nb_inplace_floor_divide = IntPtr.Zero;
- public IntPtr nb_inplace_true_divide = IntPtr.Zero;
-
- public IntPtr sq_length = IntPtr.Zero;
- public IntPtr sq_concat = IntPtr.Zero;
- public IntPtr sq_repeat = IntPtr.Zero;
- public IntPtr sq_item = IntPtr.Zero;
- public IntPtr sq_slice = IntPtr.Zero;
- public IntPtr sq_ass_item = IntPtr.Zero;
- public IntPtr sq_ass_slice = IntPtr.Zero;
- public IntPtr sq_contains = IntPtr.Zero;
- public IntPtr sq_inplace_concat = IntPtr.Zero;
- public IntPtr sq_inplace_repeat = IntPtr.Zero;
-
- public IntPtr mp_length = IntPtr.Zero;
- public IntPtr mp_subscript = IntPtr.Zero;
- public IntPtr mp_ass_subscript = IntPtr.Zero;
-
- public IntPtr bf_getreadbuffer = IntPtr.Zero;
- public IntPtr bf_getwritebuffer = IntPtr.Zero;
- public IntPtr bf_getsegcount = IntPtr.Zero;
- public IntPtr bf_getcharbuffer = IntPtr.Zero;
- }
-
-
- // This class protects the rest of the code from having to deal with
- // PyTypeObject offsets directly, makes the code clearer and prevents
- // bugs caused by bad offset caculation :)
-
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
internal class TypeOffset {
@@ -202,6 +75,10 @@
}
}
+ public static int magic() {
+ return ob_size; // * IntPtr.Size;
+ }
+
public static int ob_refcnt = 0;
public static int ob_type = 0;
public static int ob_size = 0;
@@ -308,12 +185,15 @@
public static int bf_getwritebuffer = 0;
public static int bf_getsegcount = 0;
public static int bf_getcharbuffer = 0;
- }
+ public static int name = 0;
+ public static int slots = 0;
+ public static int members = 0;
+
+
+
+ }
- // Managed representation of PyTypeFlags. It is actually more convenient
- // to have this as a class than an enum, as the enum requires boxing and
- // casting just to do a simple flag mask check.
internal class TypeFlags {
public static int HaveGetCharBuffer = (1 << 0);
@@ -345,7 +225,7 @@
// This class defines the function prototypes (delegates) used for low
// level integration with the CPython runtime. It also provides name
// based lookup of the correct prototype for a particular Python type
- // slot and utilities for generating method thunks.
+ // slot and utilities for generating method thunks for managed methods.
internal class Interop {
@@ -459,13 +339,14 @@
}
internal static IntPtr GetThunk(MethodInfo method) {
- // WARNING: this probably needs a thread lock!
Type dt = Interop.GetPrototype(method.Name);
if (dt != null) {
+ IntPtr tmp = Marshal.AllocHGlobal(IntPtr.Size);
Delegate d = Delegate.CreateDelegate(dt, method);
- MethodThunk cb = new MethodThunk(d);
- Marshal.StructureToPtr(cb, temp, false);
- IntPtr fp = Marshal.ReadIntPtr(temp, 0);
+ Thunk cb = new Thunk(d);
+ Marshal.StructureToPtr(cb, tmp, false);
+ IntPtr fp = Marshal.ReadIntPtr(tmp, 0);
+ Marshal.FreeHGlobal(tmp);
keepAlive.Add(d);
return fp;
}
@@ -515,10 +396,10 @@
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
- internal struct MethodThunk {
+ internal struct Thunk {
public Delegate fn;
- public MethodThunk(Delegate d) {
+ public Thunk(Delegate d) {
fn = d;
}
}
=== PythonNet/src/runtime/ManagedType.cs 1.2 => 1.3 ===
--- PythonNet/src/runtime/ManagedType.cs:1.2 Fri Aug 8 15:49:21 2003
+++ PythonNet/src/runtime/ManagedType.cs Mon Oct 20 23:05:14 2003
@@ -36,49 +36,27 @@
get { return tpHandle; }
}
- internal static ManagedType GetManagedObject(IntPtr ob) {
-
- // Given a PyObject *, return the managed object associated with
- // the Python object or null if the object is not managed. We do
- // this by looking at the __mro__ of the object's type to see if
- // the object is an instance of a reflected managed type or is a
- // (direct, or subclass of a) reflected managed type.
- if (ob == IntPtr.Zero) {
- return null;
- }
-
- IntPtr tp = Marshal.ReadIntPtr(ob, IntPtr.Size);
- if (tp == Runtime.PyTypeType) {
- tp = ob;
- }
+ //====================================================================
+ // Given a Python object, return the associated managed object or null.
+ //====================================================================
- // If ob->ob_type->tp_mro is null then this is not a new style
- // class (type object), so it cannot be a CLR based object.
-
- IntPtr mro = Marshal.ReadIntPtr(tp, (43 * IntPtr.Size));
- if (mro == IntPtr.Zero) {
- return null;
- }
-
- // This gets called a lot, so this effectively inlines the std
- // PyTuple_GET_SIZE / GET_ITEM macros to avoid making a lot of
- // function calls across the managed / unmanaged code boundary.
-
- int num = (int)Marshal.ReadIntPtr(mro, (2 * IntPtr.Size));
-
- for (int i = 0; i < num; i++) {
- IntPtr item = Marshal.ReadIntPtr(mro, ((3 + i) * IntPtr.Size));
- int flags = (int)Marshal.ReadIntPtr(item, (21 * IntPtr.Size));
+ internal static ManagedType GetManagedObject(IntPtr ob) {
+ if (ob != IntPtr.Zero) {
+ IntPtr tp = Runtime.PyObject_TYPE(ob);
+ if (tp == Runtime.PyTypeType || tp == Runtime.PyCLRMetaType) {
+ tp = ob;
+ }
+
+ int flags = (int)Marshal.ReadIntPtr(tp, TypeOffset.tp_flags);
if ((flags & TypeFlags.Managed) != 0) {
- IntPtr handle = (tp == ob) ?
- Marshal.ReadIntPtr(item, (2 * IntPtr.Size)) :
- Marshal.ReadIntPtr(ob, (2 * IntPtr.Size));
- GCHandle gch = (GCHandle)handle;
- return (ManagedType)gch.Target;
+ IntPtr op = (tp == ob) ?
+ Marshal.ReadIntPtr(tp, TypeOffset.magic()) :
+ Marshal.ReadIntPtr(ob, ObjectOffset.magic());
+ GCHandle gc = (GCHandle)op;
+ return (ManagedType)gc.Target;
}
}
-
return null;
}
@@ -95,11 +73,23 @@
internal static bool IsManagedType(IntPtr ob) {
- Object result = GetManagedObject(ob);
- return (result != null);
+ if (ob != IntPtr.Zero) {
+ IntPtr tp = Runtime.PyObject_TYPE(ob);
+ if (tp == Runtime.PyTypeType || tp == Runtime.PyCLRMetaType) {
+ tp = ob;
+ }
+
+ int flags = (int)Marshal.ReadIntPtr(tp, TypeOffset.tp_flags);
+ if ((flags & TypeFlags.Managed) != 0) {
+ return true;
+ }
+ }
+ return false;
}
+
}
+
}
=== PythonNet/src/runtime/MetaType.cs 1.5 => 1.6 ===
--- PythonNet/src/runtime/MetaType.cs:1.5 Fri Aug 8 15:49:21 2003
+++ PythonNet/src/runtime/MetaType.cs Mon Oct 20 23:05:14 2003
@@ -24,88 +24,19 @@
internal class MetaType : ManagedType {
- // static Type delegateType;
static IntPtr PyCLRMetaType;
- static IntPtr py__init__;
- static IntPtr stdflags;
- static ArrayList dList;
- static Hashtable cache;
- static int obSize;
- static int tpSize;
-
- static MetaType() {
- obSize = Marshal.SizeOf(new PyObjectHead());
- tpSize = Marshal.SizeOf(new PyTypeObject());
- cache = new Hashtable();
- dList = new ArrayList();
- stdflags = (IntPtr) (TypeFlags.Default |
- TypeFlags.HeapType |
- TypeFlags.Subclass |
- TypeFlags.Managed);
- }
+
//====================================================================
// Metatype initialization. This bootstraps the CLR metatype to life.
//====================================================================
public static IntPtr Initialize() {
- py__init__ = Runtime.PyString_FromString("__init__");
-
- Type type = typeof(MetaType);
-
- PyTypeObject pyTypeObj = new PyTypeObject();
- pyTypeObj.tp_name = Marshal.StringToHGlobalAnsi(type.Name);
-
- pyTypeObj.ob_type = Runtime.PyTypeType;
- Runtime.Incref(Runtime.PyTypeType);
-
- pyTypeObj.tp_base = Runtime.PyTypeType;
- Runtime.Incref(Runtime.PyTypeType);
-
- pyTypeObj.tp_basicsize = (IntPtr)tpSize;
- pyTypeObj.ob_refcnt = (IntPtr) 1;
- pyTypeObj.tp_flags = (IntPtr) (TypeFlags.Default |
- TypeFlags.HeapType |
- TypeFlags.Managed);
-
- BindingFlags flags = BindingFlags.Public | BindingFlags.Static;
- Type py = pyTypeObj.GetType();
-
- while (type != null) {
- MethodInfo[] methods = type.GetMethods(flags);
- for (int i = 0; i < methods.Length; i++) {
- MethodInfo method = methods[i];
- string name = method.Name;
- if (! name.StartsWith("tp_") ) {
- continue;
- }
-
- FieldInfo fi = py.GetField(name);
- IntPtr value = (IntPtr) fi.GetValue(pyTypeObj);
- if ((fi != null) && (value == IntPtr.Zero)) {
- fi.SetValue(pyTypeObj, Interop.GetThunk(method));
- }
- }
- type = type.BaseType;
- }
-
- // Now blit the PyTypeObject instance to the unmanaged heap. This
- // bit lets us avoid pinning objects, which would disrupt the GC.
-
- IntPtr typePtr = Runtime.PyMem_Malloc(tpSize);
- GCHandle gch = GCHandle.Alloc(pyTypeObj, GCHandleType.Pinned);
- Marshal.StructureToPtr(pyTypeObj, typePtr, false);
- gch.Free();
- Runtime.PyType_Ready(typePtr);
-
- PyCLRMetaType = typePtr;
- return typePtr;
+ PyCLRMetaType = TypeManager.CreateMetaType(typeof(MetaType));
+ return PyCLRMetaType;
}
-
-
-
//====================================================================
// Metatype __new__ implementation. This is called to create a new
// class / type when a reflected class is subclassed.
@@ -113,7 +44,6 @@
[CallConvCdecl()]
public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) {
- // Note that this is still very incomplete!!!
int len = Runtime.PyTuple_Size(args);
if (len < 3) {
@@ -139,24 +69,25 @@
return IntPtr.Zero;
}
- IntPtr basetype = Runtime.PyTuple_GetItem(bases, 0);
- if (Runtime.PyObject_TYPE(basetype) != PyCLRMetaType) {
- Exceptions.SetError(Exceptions.TypeError,
- "metatype is not managed metatype - should not happen!"
- );
- return IntPtr.Zero;
+ IntPtr base_type = Runtime.PyTuple_GetItem(bases, 0);
+ IntPtr mt = Runtime.PyObject_TYPE(base_type);
+ if (!((mt == PyCLRMetaType) || (mt == Runtime.PyTypeType))) {
+ Exceptions.SetError(Exceptions.TypeError, "invalid metatype");
+ return IntPtr.Zero;
}
// Ensure that the reflected type is appropriate for subclassing,
// disallowing subclassing of delegates, enums and array types.
- ClassBase cb = (ClassBase)GetManagedObject(basetype);
- if (! cb.CanSubclass() ) {
- Exceptions.SetError(Exceptions.TypeError,
- "delegates, enums and array types cannot be subclassed"
- );
- return IntPtr.Zero;
+ ClassBase cb = GetManagedObject(base_type) as ClassBase;
+ if (cb != null) {
+ if (! cb.CanSubclass() ) {
+ Exceptions.SetError(Exceptions.TypeError,
+ "delegates, enums and array types cannot be subclassed"
+ );
+ return IntPtr.Zero;
+ }
}
@@ -169,65 +100,15 @@
}
- dict = Runtime.PyDict_Copy(dict);
-
- // todo: set module
-
- // todo: set doc
-
- // todo: kill __new__ or error
-
- // Create the subtype. Note that this does not go through the
- // standard protocols (tp_alloc, etc.) because we allow only
- // single inheritance and don't interoperate with other types.
-
- PyTypeObject sub = new PyTypeObject();
- string tp_name = Runtime.GetManagedString(name);
- sub.tp_name = Marshal.StringToHGlobalAnsi(tp_name);
- sub.ob_type = PyCLRMetaType;
- sub.ob_refcnt = (IntPtr) 1;
- sub.tp_flags = stdflags;
- sub.tp_basicsize = (IntPtr)tpSize;
- sub.tp_dictoffset = (IntPtr) ObjectOffset.ob_dict;
-
- sub.tp_base = basetype;
- Runtime.Incref(basetype);
-
- sub.tp_bases = bases;
- Runtime.Incref(bases);
-
- sub.tp_dict = dict;
-
- // get/set attr copy
- //IntPtr mt = Runtime.PyTypeType;
- //IntPtr fp = Marshal.ReadIntPtr(mt, TypeOffset.tp_getattro);
- //sub.tp_getattro = fp;
-
-
- // copy hidden obj !!!!do we need to copy gchandle??
- sub.ob_size = Marshal.ReadIntPtr(basetype, 2 * IntPtr.Size);
-
- IntPtr op = Runtime.PyMem_Malloc(tpSize);
- GCHandle gc = GCHandle.Alloc(sub, GCHandleType.Pinned);
- Marshal.StructureToPtr(sub, op, false);
- gc.Free();
+ return TypeManager.CreateSubType(args);
- TypeManager.FixupOffsets(op);
-
- if (Runtime.PyType_Ready(op) < 0) {
- Runtime.Decref(op);
- return IntPtr.Zero;
- }
-
- return op;
}
//====================================================================
// Metatype __call__ implementation. This is needed to ensure correct
// initialization (__init__ support), because the tp_call we inherit
- // from PyType_Type won't do initialization for types that do not use
- // the standard metatype.
+ // from PyType_Type won't call __init__ for metatypes it doesnt know.
//====================================================================
[CallConvCdecl()]
@@ -242,8 +123,10 @@
return IntPtr.Zero;
}
+ IntPtr py__init__ = Runtime.PyString_FromString("__init__");
IntPtr type = Runtime.PyObject_TYPE(obj);
IntPtr init = Runtime._PyType_Lookup(type, py__init__);
+ Runtime.Decref(py__init__);
Runtime.PyErr_Clear();
if (init != IntPtr.Zero) {
@@ -254,10 +137,13 @@
}
IntPtr result = Runtime.PyObject_Call(init, bound, kw);
+ Runtime.Decref(bound);
+
if (result == IntPtr.Zero) {
Runtime.Decref(obj);
return IntPtr.Zero;
}
+
Runtime.Decref(result);
}
@@ -279,7 +165,7 @@
if (descr != IntPtr.Zero) {
IntPtr dt = Runtime.PyObject_TYPE(descr);
- IntPtr fp = Marshal.ReadIntPtr(dt, (35 * IntPtr.Size));
+ IntPtr fp = Marshal.ReadIntPtr(dt, TypeOffset.tp_descr_set);
if (fp != IntPtr.Zero) {
return NativeCall.Impl.Int_Call_3(fp, descr, name, value);
}
@@ -297,20 +183,63 @@
//====================================================================
- // Dealloc implementation. This is called when a subclass generated
- // by this metatype is no longer referenced in Python.
+ // Dealloc implementation. This is called when a Python type generated
+ // by this metatype is no longer referenced from the Python runtime.
//====================================================================
[CallConvCdecl()]
public static void tp_dealloc(IntPtr tp) {
- // Free tp->tp_name, dealloc tp_dict, free type memory.
- IntPtr op = Marshal.ReadIntPtr(tp, 3 * IntPtr.Size);
+ DebugUtil.Print("mt tp_dealloc: ", tp);
+
+ // Free the allocated name of the generated type object.
+
+ IntPtr op = Marshal.ReadIntPtr(tp, TypeOffset.tp_name);
Marshal.FreeHGlobal(op);
- op = Marshal.ReadIntPtr(tp, 33 * IntPtr.Size);
- Runtime.Decref(op);
- Runtime.PyMem_Free(tp);
+
+ //op = Marshal.ReadIntPtr(tp, TypeOffset.ob_type);
+ Runtime.Decref(op); // is this right?
+
+ // Fix this when we dont cheat on the handle for subclasses!
+
+ int flags = (int)Marshal.ReadIntPtr(tp, TypeOffset.tp_flags);
+ if ((flags & TypeFlags.Subclass) == 0) {
+ IntPtr gc = Marshal.ReadIntPtr(tp, TypeOffset.magic());
+ ((GCHandle)gc).Free();
+ }
+
+ // Delegate the rest of finalization the Python metatype.
+
+ op = Marshal.ReadIntPtr(Runtime.PyTypeType, TypeOffset.tp_dealloc);
+ NativeCall.Void_Call_1(op, tp);
+
}
+
+ [CallConvCdecl()]
+ public static void tp_free(IntPtr tp) {
+ Console.WriteLine("mt tp_free - fix!");
+ }
+
+
+
+ [CallConvCdecl()]
+ public static int tp_traverse(IntPtr ob, IntPtr func, IntPtr args) {
+ //DebugUtil.Print("mt traverse: ", ob);
+ return 0;
+ }
+
+
+ [CallConvCdecl()]
+ public static int tp_clear(IntPtr ob) {
+ //Console.WriteLine("mtt clear");
+ return 0;
+ }
+
+
+ [CallConvCdecl()]
+ public static int tp_is_gc(IntPtr type) {
+ return 1;
+ }
}
=== PythonNet/src/runtime/MethodBinder.cs 1.4 => 1.5 ===
--- PythonNet/src/runtime/MethodBinder.cs:1.4 Thu Oct 2 23:06:17 2003
+++ PythonNet/src/runtime/MethodBinder.cs Mon Oct 20 23:05:14 2003
@@ -75,6 +75,7 @@
Type type = pi[n].ParameterType;
Object arg;
if (!Converter.ToManaged(op, type, out arg, false)) {
+ Exceptions.Clear();
margs = null;
break;
}
@@ -100,6 +101,7 @@
return null;
}
+
internal virtual IntPtr Invoke(IntPtr inst, IntPtr args, IntPtr kw) {
Binding binding = this.Bind(inst, args, kw);
Object result;
@@ -111,7 +113,6 @@
return IntPtr.Zero;
}
- //Console.WriteLine("\nrelease: {0}", binding.info);
PythonEngine.ReleaseThreadLock();
try {
@@ -126,14 +127,11 @@
e = e.InnerException;
}
- //Console.WriteLine("\nacquire: {0}", binding.info);
PythonEngine.AcquireThreadLock();
-
Exceptions.SetError(e);
return IntPtr.Zero;
}
- //Console.WriteLine("\nacquire: {0}", binding.info);
PythonEngine.AcquireThreadLock();
MethodInfo mi = (MethodInfo)binding.info;
=== PythonNet/src/runtime/MethodWrapper.cs 1.3 => 1.4 ===
--- PythonNet/src/runtime/MethodWrapper.cs:1.3 Tue Sep 30 19:54:11 2003
+++ PythonNet/src/runtime/MethodWrapper.cs Mon Oct 20 23:05:14 2003
@@ -45,8 +45,8 @@
typeof(Interop.TernaryFunc),
obType.GetMethod(name)
);
- MethodThunk cb = new MethodThunk(mDelegate);
- IntPtr pThunk = Marshal.AllocHGlobal(IntPtr.Size);
+ Thunk cb = new Thunk(mDelegate);
+ IntPtr pThunk = Runtime.PyMem_Malloc(1 * IntPtr.Size);
Marshal.StructureToPtr(cb, pThunk, false);
IntPtr fp = Marshal.ReadIntPtr(pThunk, 0);
Marshal.FreeHGlobal(pThunk);
@@ -61,6 +61,7 @@
keepAlive.Add(this);
}
+
public IntPtr Handle {
get { return pyHandle; }
}
@@ -68,6 +69,7 @@
public IntPtr Call(IntPtr args, IntPtr kw) {
return Runtime.PyCFunction_Call(pyHandle, args, kw);
}
+
}
=== PythonNet/src/runtime/ModuleObject.cs 1.2 => 1.3 ===
--- PythonNet/src/runtime/ModuleObject.cs:1.2 Wed Jul 30 09:55:50 2003
+++ PythonNet/src/runtime/ModuleObject.cs Mon Oct 20 23:05:14 2003
@@ -32,7 +32,6 @@
IntPtr dict;
public ModuleObject(string name) : base() {
-
moduleName = (name == String.Empty) ? "CLR" : "CLR." + name;
cache = new Hashtable();
_namespace = name;
@@ -50,6 +49,7 @@
}
}
+
//===================================================================
// Returns a ClassBase object representing a type that appears in
// this module's namespace or a ModuleObject representing a child
@@ -119,6 +119,7 @@
return null;
}
+
//===================================================================
// Stores an attribute in the instance dict for future lookups.
//===================================================================
@@ -129,17 +130,11 @@
}
-
-
[PythonMethod]
public static IntPtr _preload(IntPtr ob, IntPtr args, IntPtr kw) {
-
ModuleObject self = (ModuleObject)GetManagedObject(ob);
-
string module_ns = self._namespace;
-
-
AppDomain domain = AppDomain.CurrentDomain;
Assembly[] assemblies = domain.GetAssemblies();
for (int i = 0; i < assemblies.Length; i++) {
@@ -162,7 +157,6 @@
}
-
//====================================================================
// ModuleObject __getattribute__ implementation. Module attributes
// are always either classes or sub-modules representing subordinate
@@ -208,7 +202,7 @@
[CallConvCdecl()]
public static IntPtr tp_repr(IntPtr ob) {
ModuleObject self = (ModuleObject)GetManagedObject(ob);
- string s = String.Format("<module '{0}' (clr)>", self.moduleName);
+ string s = String.Format("<module '{0}'>", self.moduleName);
return Runtime.PyString_FromString(s);
}
=== PythonNet/src/runtime/PropertyObject.cs 1.2 => 1.3 ===
--- PythonNet/src/runtime/PropertyObject.cs:1.2 Mon Jul 28 22:28:15 2003
+++ PythonNet/src/runtime/PropertyObject.cs Mon Oct 20 23:05:14 2003
@@ -105,7 +105,7 @@
//====================================================================
[CallConvCdecl()]
- public static int tp_descr_set(IntPtr ds, IntPtr ob, IntPtr val) {
+ public static new int tp_descr_set(IntPtr ds, IntPtr ob, IntPtr val) {
PropertyObject self = (PropertyObject)GetManagedObject(ds);
MethodInfo setter = self.setter;
IntPtr ts = IntPtr.Zero;
@@ -172,8 +172,6 @@
}
-
- // mp_subscript should handle index params.
//====================================================================
// Descriptor __repr__ implementation.
=== PythonNet/src/runtime/PyObject.cs 1.1 => 1.2 ===
--- PythonNet/src/runtime/PyObject.cs:1.1 Thu Sep 11 23:49:34 2003
+++ PythonNet/src/runtime/PyObject.cs Mon Oct 20 23:05:14 2003
@@ -88,7 +88,7 @@
/// </remarks>
public void Dispose() {
- Console.WriteLine("dispose called: {0}", this.ToString());
+ //Console.WriteLine("dispose called: {0}", this.ToString());
GC.SuppressFinalize(this);
Runtime.Decref(obj);
obj = IntPtr.Zero;
=== PythonNet/src/runtime/Python.cs 1.1 => 1.2 ===
--- PythonNet/src/runtime/Python.cs:1.1 Mon Jul 28 22:28:15 2003
+++ PythonNet/src/runtime/Python.cs Mon Oct 20 23:05:14 2003
@@ -36,9 +36,11 @@
public static void Initialize() {
if (!initialized) {
+
Runtime.Initialize();
threads = new Hashtable();
+
IntPtr ts = Runtime.PyThreadState_Get();
threads[Thread.CurrentThread] = ts;
@@ -188,25 +190,26 @@
return Runtime.PyRun_SimpleString(code);
}
-// public static PyModule ImportModule(string name) {
-// PyString moduleName = new PyString(name);
-// IntPtr pointer = Runtime.PyImport_Import(moduleName.Handle);
-// return new PyModule(pointer);
-// }
-
-// public static PyModule ReloadModule(PyModule module) {
-// IntPtr pointer = Runtime.PyImport_ReloadModule(module.Handle);
-// return new PyModule(pointer);
-// }
-
-// public static PyModule AddModule(string name) {
-// IntPtr result = Runtime.PyImport_AddModule(name);
-// if (result == IntPtr.Zero) {
-// throw new PythonException();
-// }
-// Runtime.Incref(result);
-// return new PyModule(result);
-// }
+
+ /// <summary>
+ /// ImportModule Method
+ /// </summary>
+ ///
+ /// <remarks>
+ /// Given a fully-qualified module or package name, import the
+ /// module and return the resulting module object as a PyObject.
+ /// </remarks>
+
+ public static PyObject ImportModule(string name) {
+ PyString mod = new PyString(name);
+ IntPtr op = Runtime.PyImport_Import(mod.Handle);
+ mod.Dispose();
+ if (op == IntPtr.Zero) {
+ throw new PythonException();
+ }
+ return new PyObject(op);
+ }
+
}
=== PythonNet/src/runtime/Runtime.cs 1.9 => 1.10 ===
--- PythonNet/src/runtime/Runtime.cs:1.9 Thu Oct 2 23:06:17 2003
+++ PythonNet/src/runtime/Runtime.cs Mon Oct 20 23:05:14 2003
@@ -40,7 +40,7 @@
IntPtr dict = Runtime.PyImport_GetModuleDict();
IntPtr op = Runtime.PyDict_GetItemString(dict, "__builtin__");
-
+ PyBaseObjectType = Runtime.PyObject_GetAttrString(op, "object");
PyModuleType = Runtime.PyObject_Type(op);
PyNone = Runtime.PyObject_GetAttrString(op, "None");
@@ -96,32 +96,19 @@
Runtime.Decref(c);
Runtime.Decref(d);
+
Error = new IntPtr(-1);
PyCLRMetaType = MetaType.Initialize();
+
Exceptions.Initialize();
+
ImportHook.Initialize();
- // TODO: get rid of this! This works around the gc crash
- // until I have time to dig into it.
- bool hack = true;
-
- if (hack) {
- IntPtr nm = Runtime.PyString_FromString("gc");
- IntPtr md = Runtime.PyImport_Import(nm);
- IntPtr fn = Runtime.PyObject_GetAttrString(md, "disable");
- IntPtr aa = Runtime.PyTuple_New(0);
- IntPtr rr = Runtime.PyObject_Call(fn, aa, IntPtr.Zero);
- Runtime.Decref(rr);
- Runtime.Decref(aa);
- Runtime.Decref(fn);
- Runtime.Decref(nm);
- Runtime.Decref(md);
- }
}
-
+ internal static IntPtr PyBaseObjectType;
internal static IntPtr PyModuleType;
internal static IntPtr PyClassType;
internal static IntPtr PyInstanceType;
@@ -184,8 +171,6 @@
if (Is32Bit) { --(*(int *)p); }
else { --(*(long *)p); }
if ((*(int *)p) == 0) {
- //string nn = PyObject_GetTypeName(op);
- //Console.WriteLine("decref: {0}", nn);
void *t = Is32Bit ? (void *)(*((uint *)p + 1)) :
(void *)(*((ulong *)p + 1));
void *f = Is32Bit ? (void *)(*((uint *)t + 6)) :
@@ -1086,7 +1071,7 @@
PyType_GenericNew(IntPtr type, IntPtr args, IntPtr kw);
[DllImport("python22", CallingConvention=CallingConvention.Cdecl,
- ExactSpelling=true, CharSet=CharSet.Ansi)]
+ ExactSpelling=true, CharSet=CharSet.Ansi)]
internal unsafe static extern IntPtr
PyType_GenericAlloc(IntPtr type, int n);
@@ -1115,6 +1100,26 @@
internal unsafe static extern IntPtr
_PyObject_GetDictPtr(IntPtr obj);
+ [DllImport("python22", CallingConvention=CallingConvention.Cdecl,
+ ExactSpelling=true, CharSet=CharSet.Ansi)]
+ internal unsafe static extern IntPtr
+ _PyObject_GC_New(IntPtr tp);
+
+ [DllImport("python22", CallingConvention=CallingConvention.Cdecl,
+ ExactSpelling=true, CharSet=CharSet.Ansi)]
+ internal unsafe static extern void
+ _PyObject_GC_Del(IntPtr tp);
+
+ [DllImport("python22", CallingConvention=CallingConvention.Cdecl,
+ ExactSpelling=true, CharSet=CharSet.Ansi)]
+ internal unsafe static extern void
+ _PyObject_GC_Track(IntPtr tp);
+
+ [DllImport("python22", CallingConvention=CallingConvention.Cdecl,
+ ExactSpelling=true, CharSet=CharSet.Ansi)]
+ internal unsafe static extern void
+ _PyObject_GC_UnTrack(IntPtr tp);
+
//====================================================================
// Python memory API
@@ -1194,6 +1199,11 @@
ExactSpelling=true, CharSet=CharSet.Ansi)]
internal unsafe static extern void
PyErr_Clear();
+
+ [DllImport("python22", CallingConvention=CallingConvention.Cdecl,
+ ExactSpelling=true, CharSet=CharSet.Ansi)]
+ internal unsafe static extern void
+ PyErr_Print();
//====================================================================
=== PythonNet/src/runtime/TypeManager.cs 1.7 => 1.8 ===
--- PythonNet/src/runtime/TypeManager.cs:1.7 Tue Sep 30 19:54:11 2003
+++ PythonNet/src/runtime/TypeManager.cs Mon Oct 20 23:05:14 2003
@@ -14,48 +14,56 @@
using System.Reflection.Emit;
using System.Collections;
using System.Reflection;
-
-
using System.Threading;
namespace Python.Runtime {
//=======================================================================
// The TypeManager class is responsible for building binary-compatible
- // Python type objects that reflect a managed type.
+ // Python type objects that are implemented in managed code.
//=======================================================================
internal class TypeManager {
- static ArrayList dList;
+ static BindingFlags tbFlags;
static Hashtable cache;
- static IntPtr p_thunk;
static int obSize;
- static int tpSize;
static TypeManager() {
- obSize = Marshal.SizeOf(new PyObjectHead());
- tpSize = Marshal.SizeOf(new PyTypeObject());
- p_thunk = Marshal.AllocHGlobal(IntPtr.Size);
+ tbFlags = BindingFlags.Public | BindingFlags.Static;
+ obSize = 4 * IntPtr.Size;
cache = new Hashtable();
- dList = new ArrayList();
}
+
//====================================================================
- // Internal use: given a managed Type object, return the *handle* of
- // a Python type object that reflects the managed type. The handle is
- // a PyObject *,
+ // Given a managed Type derived from ExtensionType, get the handle to
+ // a Python type object that delegates its implementation to the Type
+ // object. These Python type instances are used to implement internal
+ // descriptor and utility types like ModuleObject, PropertyObject, etc.
+ //====================================================================
+
+ internal static IntPtr GetTypeHandle(Type type) {
+
+ // Note that these types are cached with a refcount of 1, so they
+ // effectively exist until the CPython runtime is finalized. We
- internal static IntPtr GetTypeHandle(Type obType) {
- Object ob = cache[obType];
+ Object ob = cache[type];
if (ob != null) {
return (IntPtr) ob;
}
- IntPtr tp = CreateType(obType);
- cache[obType] = tp;
+ IntPtr tp = CreateType(type);
+ cache[type] = tp;
return tp;
}
+
+ //====================================================================
+ // Get the handle of a Python type that reflects the given CLR type.
+ // The given ManagedType instance is a managed object that implements
+ // the appropriate semantics in Python for the reflected managed type.
+ //====================================================================
+
internal static IntPtr GetTypeHandle(ManagedType obj, Type clrType) {
Object ob = cache[clrType];
if (ob != null) {
@@ -67,21 +75,345 @@
}
+ //====================================================================
+ // The following CreateType implementations do the necessary work to
+ // create Python types to represent managed extension types, reflected
+ // types, subclasses of reflected types and the managed metatype. The
+ // dance is slightly different for each kind of type due to different
+ // behavior needed and the desire to have the existing Python runtime
+ // do as much of the allocation and initialization work as possible.
+ //====================================================================
+ internal static IntPtr CreateType(Type impl) {
- // Given a PyTypeObject instance, fill the slot pointer members of
- // the PyTypeObject with thunks pointing to methods defined by the
- // given implementing type.
+ IntPtr type = AllocateTypeObject(impl.Name);
+ IntPtr py_type = Runtime.PyTypeType;
- private static void InitializeSlots(PyTypeObject typeObj, Type type) {
- BindingFlags flags = BindingFlags.Public | BindingFlags.Static;
- Type typedesc = typeof(PyTypeObject);
+ // Set tp_basicsize to the size of our managed instance objects.
+ Marshal.WriteIntPtr(type, TypeOffset.tp_basicsize, (IntPtr)obSize);
- while (type != null) {
- MethodInfo[] methods = type.GetMethods(flags);
+ IntPtr offset = (IntPtr)ObjectOffset.ob_dict;
+ Marshal.WriteIntPtr(type, TypeOffset.tp_dictoffset, offset);
+
+ //CopySlot(py_type, type, TypeOffset.tp_hash);
+ //CopySlot(py_type, type, TypeOffset.tp_weaklistoffset);
+ //CopySlot(py_type, type, TypeOffset.tp_is_gc);
+
+ InitializeSlots(type, impl);
+
+ int flags = TypeFlags.Default;
+ flags |= TypeFlags.Managed;
+ flags |= TypeFlags.HeapType;
+ flags |= TypeFlags.HaveGC;
+ Marshal.WriteIntPtr(type, TypeOffset.tp_flags, (IntPtr)flags);
+
+ Runtime.PyType_Ready(type);
+
+ InitMethods(type, impl);
+
+ //DebugUtil.DumpType(type);
+
+ return type;
+ }
+
+
+ internal static IntPtr CreateType(ManagedType impl, Type clrType) {
+ // Cleanup the type name to get rid of funny nested type names.
+ string name = "CLR." + clrType.FullName;
+ int i = name.LastIndexOf('+');
+ if (i > -1) {
+ name = name.Substring(i + 1);
+ }
+
+ IntPtr base_ = IntPtr.Zero;
+ if (clrType.BaseType != null) {
+ ClassBase bc = ClassManager.GetClass(clrType.BaseType);
+ base_ = bc.pyHandle;
+ }
+
+ IntPtr type = AllocateTypeObject(name);
+
+ Marshal.WriteIntPtr(type,TypeOffset.ob_type,Runtime.PyCLRMetaType);
+ Runtime.Incref(Runtime.PyCLRMetaType);
+
+ Marshal.WriteIntPtr(type, TypeOffset.tp_basicsize, (IntPtr)obSize);
+ Marshal.WriteIntPtr(type, TypeOffset.tp_itemsize, IntPtr.Zero);
+
+ IntPtr offset = (IntPtr)ObjectOffset.ob_dict;
+ Marshal.WriteIntPtr(type, TypeOffset.tp_dictoffset, offset);
+
+ InitializeSlots(type, impl.GetType());
+
+ if (base_ != IntPtr.Zero) {
+ Marshal.WriteIntPtr(type, TypeOffset.tp_base, base_);
+ Runtime.Incref(base_);
+ }
+
+ int flags = TypeFlags.Default;
+ flags |= TypeFlags.Managed;
+ flags |= TypeFlags.HeapType;
+ flags |= TypeFlags.BaseType;
+ flags |= TypeFlags.HaveGC;
+ Marshal.WriteIntPtr(type, TypeOffset.tp_flags, (IntPtr)flags);
+
+ // Leverage followup initialization from the Python runtime. Note
+ // that the type of the new type must PyType_Type at the time we
+ // call this, else PyType_Ready will skip some slot initialization.
+
+ Runtime.PyType_Ready(type);
+
+
+ // Hide the gchandle of the implementation in a magic type slot.
+ GCHandle gc = GCHandle.Alloc(impl);
+ Marshal.WriteIntPtr(type, TypeOffset.magic(), (IntPtr)gc);
+
+ // Set the handle attributes on the implementing instance.
+ impl.tpHandle = Runtime.PyCLRMetaType;
+ impl.gcHandle = gc;
+ impl.pyHandle = type;
+
+ //DebugUtil.DumpType(type);
+
+ return type;
+ }
+
+
+ internal static IntPtr CreateSubType(IntPtr args) {
+
+ IntPtr py_name = Runtime.PyTuple_GetItem(args, 0);
+ IntPtr bases = Runtime.PyTuple_GetItem(args, 1);
+ IntPtr dict = Runtime.PyTuple_GetItem(args, 2);
+ IntPtr base_ = Runtime.PyTuple_GetItem(bases, 0);
+
+ string name = Runtime.GetManagedString(py_name);
+ IntPtr type = AllocateTypeObject(name);
+
+ Marshal.WriteIntPtr(type,TypeOffset.ob_type,Runtime.PyCLRMetaType);
+ Runtime.Incref(Runtime.PyCLRMetaType);
+
+ Marshal.WriteIntPtr(type, TypeOffset.tp_basicsize, (IntPtr)obSize);
+ Marshal.WriteIntPtr(type, TypeOffset.tp_itemsize, IntPtr.Zero);
+
+ IntPtr offset = (IntPtr)ObjectOffset.ob_dict;
+ Marshal.WriteIntPtr(type, TypeOffset.tp_dictoffset, offset);
+
+ Marshal.WriteIntPtr(type, TypeOffset.tp_base, base_);
+ Runtime.Incref(base_);
+
+ Marshal.WriteIntPtr(type, TypeOffset.tp_bases, bases);
+ Runtime.Incref(bases);
+
+ dict = Runtime.PyDict_Copy(dict);
+ Marshal.WriteIntPtr(type, TypeOffset.tp_dict, dict);
+
+ int flags = TypeFlags.Default;
+ flags |= TypeFlags.Managed;
+ flags |= TypeFlags.HeapType;
+ flags |= TypeFlags.BaseType;
+ flags |= TypeFlags.Subclass;
+ flags |= TypeFlags.HaveGC;
+ Marshal.WriteIntPtr(type, TypeOffset.tp_flags, (IntPtr)flags);
+
+ CopySlot(base_, type, TypeOffset.tp_traverse);
+ CopySlot(base_, type, TypeOffset.tp_clear);
+ CopySlot(base_, type, TypeOffset.tp_is_gc);
+
+
+ Runtime.PyType_Ready(type);
+
+
+ // for now, move up hidden handle...
+ IntPtr gc = Marshal.ReadIntPtr(base_, TypeOffset.magic());
+ Marshal.WriteIntPtr(type, TypeOffset.magic(), gc);
+
+ return type;
+ }
+
+
+
+ internal static IntPtr CreateMetaType(Type impl) {
+
+ // The managed metatype is functionally little different than the
+ // standard Python metatype (PyType_Type). It overrides certain of
+ // the standard type slots, and has to subclass PyType_Type for
+ // certain functions in the C runtime to work correctly with it.
+
+ IntPtr type = AllocateTypeObject("CLR Metatype");
+ IntPtr py_type = Runtime.PyTypeType;
+
+ Marshal.WriteIntPtr(type, TypeOffset.tp_base, py_type);
+ Runtime.Incref(py_type);
+
+ // Copy gc and other type slots from the base Python metatype.
+
+ CopySlot(py_type, type, TypeOffset.tp_basicsize);
+ //Marshal.WriteIntPtr(type, TypeOffset.tp_itemsize, (IntPtr)0);
+
+ //CopySlot(py_type, type, TypeOffset.tp_itemsize);
+ //CopySlot(py_type, type, TypeOffset.tp_compare);
+ //CopySlot(py_type, type, TypeOffset.tp_hash);
+ CopySlot(py_type, type, TypeOffset.tp_dictoffset);
+ CopySlot(py_type, type, TypeOffset.tp_weaklistoffset);
+ //CopySlot(py_type, type, TypeOffset.tp_traverse);
+ //CopySlot(py_type, type, TypeOffset.tp_clear);
+ //CopySlot(py_type, type, TypeOffset.tp_is_gc);
+ //CopySlot(py_type, type, TypeOffset.tp_repr);
+
+ //CopySlot(py_type, type, TypeOffset.tp_free);
+
+ // Override type slots with those of the managed implementation.
+
+ InitializeSlots(type, impl);
+
+ int flags = TypeFlags.Default;
+ flags |= TypeFlags.Managed;
+ flags |= TypeFlags.HeapType;
+ flags |= TypeFlags.HaveGC;
+ Marshal.WriteIntPtr(type, TypeOffset.tp_flags, (IntPtr)flags);
+
+ Runtime.PyType_Ready(type);
+
+ return type;
+ }
+
+
+
+ internal static IntPtr CreateMetaTypeOld(Type impl) {
+
+ // The managed metatype is functionally little different than the
+ // standard Python metatype (PyType_Type). It overrides certain of
+ // the standard type slots, and has to subclass PyType_Type for
+ // certain functions in the C runtime to work correctly with it.
+
+ IntPtr type = AllocateTypeObject("CLR Metatype");
+ IntPtr py_type = Runtime.PyTypeType;
+
+ // Copy gc and other type slots from the base Python metatype.
+
+ CopySlot(py_type, type, TypeOffset.tp_basicsize);
+ Marshal.WriteIntPtr(type, TypeOffset.tp_itemsize, (IntPtr)0);
+
+ CopySlot(py_type, type, TypeOffset.tp_itemsize);
+ CopySlot(py_type, type, TypeOffset.tp_compare);
+ CopySlot(py_type, type, TypeOffset.tp_hash);
+ CopySlot(py_type, type, TypeOffset.tp_dictoffset);
+ CopySlot(py_type, type, TypeOffset.tp_weaklistoffset);
+ //CopySlot(py_type, type, TypeOffset.tp_traverse);
+ //CopySlot(py_type, type, TypeOffset.tp_clear);
+ //CopySlot(py_type, type, TypeOffset.tp_is_gc);
+ //CopySlot(py_type, type, TypeOffset.tp_repr);
+
+ //CopySlot(py_type, type, TypeOffset.tp_free);
+
+ // Override type slots with those of the managed implementation.
+
+ InitializeSlots(type, impl);
+
+ int flags = TypeFlags.Default;
+ flags |= TypeFlags.Managed;
+ flags |= TypeFlags.HeapType;
+ flags |= TypeFlags.HaveGC;
+ flags |= TypeFlags.Ready;
+ Marshal.WriteIntPtr(type, TypeOffset.tp_flags, (IntPtr)flags);
+
+ //IntPtr op = Runtime.PyDict_New();
+ //Marshal.WriteIntPtr(type, TypeOffset.tp_dict, op);
+
+ Runtime.PyType_Ready(type);
+
+ InitializeSlots(type, impl);
+
+ // Set the tp_base, tp_bases and tp_mro work around issues with
+ // metaclasses. This is needed because Python will not initialize
+ // reflected types correctly unless their type is a subtype of
+ // the standard metatype. However, erratic things will happen in
+ // PyType_Ready if you try to subtype PyType_Type :(
+ //
+ // As a workaround, it turns out that PyType_Check determines
+ // sub-type-ness by looking at the mro, so as long as we add
+ // PyType_Type to the end of our mro, we can fool the runtime.
+
+ IntPtr basetype = Runtime.PyBaseObjectType;
+
+ Marshal.WriteIntPtr(type, TypeOffset.tp_base, basetype);
+
+ //temp = Marshal.ReadIntPtr(type, TypeOffset.tp_bases);
+ //Runtime.PyTuple_SetItem(temp, 0, basetype);
+ //Runtime.Incref(basetype);
+
+ IntPtr temp = Runtime.PyTuple_New(1);
+ Runtime.PyTuple_SetItem(temp, 0, basetype);
+ Runtime.Incref(basetype);
+
+
+ temp = Marshal.ReadIntPtr(type, TypeOffset.tp_mro);
+ Runtime.Decref(temp);
+
+ temp = Runtime.PyTuple_New(3);
+ Runtime.PyTuple_SetItem(temp, 0, type);
+ Runtime.PyTuple_SetItem(temp, 1, basetype);
+ Runtime.PyTuple_SetItem(temp, 2, py_type);
+ Runtime.Incref(type);
+ Runtime.Incref(basetype);
+ Runtime.Incref(py_type);
+
+ Marshal.WriteIntPtr(type, TypeOffset.tp_mro, temp);
+
+
+ //DebugUtil.DumpType(Runtime.PyTypeType);
+ //DebugUtil.DumpType(Runtime.PyBaseObjectType);
+ //DebugUtil.DumpType(type);
+
+ return type;
+ }
+
+
+ //====================================================================
+ // Utility method to allocate a type object & do basic initialization.
+ //====================================================================
+
+ internal static IntPtr AllocateTypeObject(string name) {
+ IntPtr type = Runtime.PyType_GenericAlloc(Runtime.PyTypeType, 0);
+
+ // TODO: this will leak for our metatype...
+ IntPtr temp = Marshal.StringToHGlobalAnsi(name);
+ Marshal.WriteIntPtr(type, TypeOffset.tp_name, temp);
+
+ temp = Runtime.PyString_FromString(name);
+ Marshal.WriteIntPtr(type, TypeOffset.name, temp);
+
+ long ptr = type.ToInt64(); // 64-bit safe
+
+ temp = new IntPtr(ptr + TypeOffset.nb_add);
+ Marshal.WriteIntPtr(type, TypeOffset.tp_as_number, temp);
+
+ temp = new IntPtr(ptr + TypeOffset.sq_length);
+ Marshal.WriteIntPtr(type, TypeOffset.tp_as_sequence, temp);
+
+ temp = new IntPtr(ptr + TypeOffset.mp_length);
+ Marshal.WriteIntPtr(type, TypeOffset.tp_as_mapping, temp);
+
+ temp = new IntPtr(ptr + TypeOffset.bf_getreadbuffer);
+ Marshal.WriteIntPtr(type, TypeOffset.tp_as_buffer, temp);
+
+ return type;
+ }
+
+
+ //====================================================================
+ // Given a newly allocated Python type object and a managed Type that
+ // provides the implementation for the type, connect the type slots of
+ // the Python object to the managed methods of the implementing Type.
+ //====================================================================
+
+ internal static void InitializeSlots(IntPtr type, Type impl) {
+ Hashtable seen = new Hashtable(8);
+ Type offsetType = typeof(TypeOffset);
+
+ while (impl != null) {
+ MethodInfo[] methods = impl.GetMethods(tbFlags);
for (int i = 0; i < methods.Length; i++) {
MethodInfo method = methods[i];
-
string name = method.Name;
if (! (name.StartsWith("tp_") ||
name.StartsWith("nb_") ||
@@ -92,23 +424,40 @@
continue;
}
- FieldInfo fi = typedesc.GetField(name);
- IntPtr value = (IntPtr) fi.GetValue(typeObj);
- if ((fi != null) && (value == IntPtr.Zero)) {
- fi.SetValue(typeObj, Interop.GetThunk(method));
+ if (seen[name] != null) {
+ continue;
}
+
+ FieldInfo fi = offsetType.GetField(name);
+ int offset = (int)fi.GetValue(offsetType);
+
+ IntPtr slot = Interop.GetThunk(method);
+ Marshal.WriteIntPtr(type, offset, slot);
+
+ seen[name] = 1;
}
- type = type.BaseType;
+
+ impl = impl.BaseType;
}
+
}
- // Given an initialized PyTypeObject, add type methods (implemented
- // by the passed in managed type) to the type dictionary.
+ //====================================================================
+ // Given a newly allocated Python type object and a managed Type that
+ // implements it, initialize any methods defined by the Type that need
+ // to appear in the Python type __dict__ (based on custom attribute).
+ //====================================================================
private static void InitMethods(IntPtr pytype, Type type) {
- IntPtr ppdict = Runtime._PyObject_GetDictPtr(pytype);
- IntPtr dict = Marshal.ReadIntPtr(ppdict, 0);
+ //IntPtr ppdict = Runtime._PyObject_GetDictPtr(pytype);
+ //IntPtr dict = Marshal.ReadIntPtr(ppdict, 0);
+ IntPtr dict = Marshal.ReadIntPtr(pytype, TypeOffset.tp_dict);
+
+ if (dict == IntPtr.Zero) {
+ DebugUtil.Print("null dict for: ", pytype);
+ }
+
Type marker = typeof(PythonMethodAttribute);
BindingFlags flags = BindingFlags.Public | BindingFlags.Static;
@@ -132,111 +481,39 @@
}
- // fixup internal offsets to protocol method structs.
-
- public static void FixupOffsets(IntPtr op) {
- IntPtr nboffset = new IntPtr(op.ToInt32() + (47 * IntPtr.Size));
- Marshal.WriteIntPtr(op, (12 * IntPtr.Size), nboffset);
-
- IntPtr sqoffset = new IntPtr(op.ToInt32() + (85 * IntPtr.Size));
- Marshal.WriteIntPtr(op, (13 * IntPtr.Size), sqoffset);
-
- IntPtr mpoffset = new IntPtr(op.ToInt32() + (95 * IntPtr.Size));
- Marshal.WriteIntPtr(op, (14 * IntPtr.Size), mpoffset);
-
- IntPtr bfoffset = new IntPtr(op.ToInt32() + (98 * IntPtr.Size));
- Marshal.WriteIntPtr(op, (20 * IntPtr.Size), bfoffset);
- }
-
-
- // Now blit the PyTypeObject instance to the unmanaged heap. This
- // bit lets us avoid pinning objects, which would disrupt the GC.
-
- private static IntPtr FinishType(PyTypeObject t) {
- IntPtr op = Runtime.PyMem_Malloc(tpSize);
- GCHandle gch = GCHandle.Alloc(t, GCHandleType.Pinned);
- Marshal.StructureToPtr(t, op, false);
-
- FixupOffsets(op);
-
- Runtime.PyType_Ready(op);
- gch.Free();
- return op;
- }
-
-
-
- // Initialize a new binary-compatible PyTypeObject for a simple
- // extension type. A separate overload handles reflected types.
-
- internal static IntPtr CreateType(Type obType) {
-
- PyTypeObject pyTypeObj = new PyTypeObject();
- pyTypeObj.tp_name = Marshal.StringToHGlobalAnsi(obType.Name);
- pyTypeObj.ob_type = Runtime.PyTypeType;
-
- pyTypeObj.tp_basicsize = (IntPtr)(3 * IntPtr.Size);
- pyTypeObj.ob_refcnt = (IntPtr) 1; // ??
- pyTypeObj.tp_flags = (IntPtr) (TypeFlags.Default |
- TypeFlags.Managed);
-
- InitializeSlots(pyTypeObj, obType);
-
- IntPtr o = FinishType(pyTypeObj);
- InitMethods(o, obType);
-
+ //====================================================================
+ // Utility method to copy slots from a given type to another type.
+ //====================================================================
- return o;
+ internal static void CopySlot(IntPtr from, IntPtr to, int offset) {
+ IntPtr fp = Marshal.ReadIntPtr(from, offset);
+ Marshal.WriteIntPtr(to, offset, fp);
}
- // Initialize a new binary-compatible PyTypeObject for a Python
- // type that reflects a managed type.
- internal static IntPtr CreateType(ManagedType obj, Type clrType) {
- // Cleanup the type name to get rid of funny nested type names.
- string name = "CLR." + clrType.FullName;
- int i = name.LastIndexOf('+');
- if (i > -1) {
- name = name.Substring(i + 1);
- }
+// internal static void AddDict(IntPtr type) {
+// IntPtr op = Runtime.PyDict_New();
+// Marshal.WriteIntPtr(type, TypeOffset.tp_dict, op);
+// }
- PyTypeObject pyTypeObj = new PyTypeObject();
- pyTypeObj.tp_name = Marshal.StringToHGlobalAnsi(name);
- if (clrType.BaseType != null) {
- ClassBase bc = ClassManager.GetClass(clrType.BaseType);
- pyTypeObj.tp_base = bc.tpHandle;
- }
- pyTypeObj.ob_type = Runtime.PyCLRMetaType;
- obj.tpHandle = pyTypeObj.ob_type;
- obj.gcHandle = GCHandle.Alloc(obj);
+// internal static void MyReady(IntPtr type) {
+// int flags = (int)Marshal.ReadIntPtr(type, TypeOffset.tp_flags);
+// flags |= TypeFlags.Ready;
+// Marshal.WriteIntPtr(type, TypeOffset.tp_flags, (IntPtr)flags);
- pyTypeObj.ob_size = (IntPtr)obj.gcHandle;
- pyTypeObj.tp_basicsize = (IntPtr)(3 * IntPtr.Size);
- pyTypeObj.ob_refcnt = (IntPtr) 1; // ??
- pyTypeObj.tp_flags = (IntPtr) (TypeFlags.Default |
- TypeFlags.BaseType |
- TypeFlags.HeapType |
- TypeFlags.Managed);
- //pyTypeObj.tp_dictoffset = (IntPtr) (3 * IntPtr.Size);
+// IntPtr op = Runtime.PyDict_New();
+// Marshal.WriteIntPtr(type, TypeOffset.tp_dict, op);
- InitializeSlots(pyTypeObj, obj.GetType());
- IntPtr op = FinishType(pyTypeObj);
- obj.pyHandle = op;
+// }
- return op;
- }
}
-
-
-
-
}
More information about the Zope-CVS
mailing list