/// <summary> /// 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. /// </summary> internal static IntPtr CreateType(Type impl) { IntPtr type = AllocateTypeObject(impl.Name); int ob_size = ObjectOffset.Size(type); // Set tp_basicsize to the size of our managed instance objects. Marshal.WriteIntPtr(type, TypeOffset.tp_basicsize, (IntPtr)ob_size); var offset = (IntPtr)ObjectOffset.DictOffset(type); Marshal.WriteIntPtr(type, TypeOffset.tp_dictoffset, offset); InitializeSlots(type, impl); int flags = TypeFlags.Default | TypeFlags.Managed | TypeFlags.HeapType | TypeFlags.HaveGC; Util.WriteCLong(type, TypeOffset.tp_flags, flags); Runtime.PyType_Ready(type); IntPtr dict = Marshal.ReadIntPtr(type, TypeOffset.tp_dict); IntPtr mod = Runtime.PyString_FromString("CLR"); Runtime.PyDict_SetItemString(dict, "__module__", mod); InitMethods(type, impl); return(type); }
public ExtensionType() { // Create a new PyObject whose type is a generated type that is // implemented by the particular 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(GetType()); //int rc = (int)Marshal.ReadIntPtr(tp, TypeOffset.ob_refcnt); //if (rc > 1050) //{ // DebugUtil.Print("tp is: ", tp); // DebugUtil.DumpType(tp); //} IntPtr py = Runtime.PyType_GenericAlloc(tp, 0); GCHandle gc = GCHandle.Alloc(this); Marshal.WriteIntPtr(py, ObjectOffset.magic(tp), (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); tpHandle = tp; pyHandle = py; gcHandle = gc; }
internal IntPtr tpHandle; // PyType * /// <summary> /// Given a Python object, return the associated managed object or null. /// </summary> 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; } var flags = Util.ReadCLong(tp, TypeOffset.tp_flags); if ((flags & TypeFlags.Managed) != 0) { IntPtr op = tp == ob ? Marshal.ReadIntPtr(tp, TypeOffset.magic()) : Marshal.ReadIntPtr(ob, ObjectOffset.magic(ob)); if (op == IntPtr.Zero) { return(null); } var gc = (GCHandle)op; return((ManagedType)gc.Target); } } return(null); }
/// <summary> /// Called from Converter.ToPython for types that are python subclasses of managed types. /// The referenced python object is returned instead of a new wrapper. /// </summary> internal static IntPtr ToPython(IPythonDerivedType obj) { // derived types have a __pyobj__ field that gets set to the python // object in the overridden constructor FieldInfo fi = obj.GetType().GetField("__pyobj__"); var self = (CLRObject)fi.GetValue(obj); Runtime.XIncref(self.pyHandle); // when the C# constructor creates the python object it starts as a weak // reference with a reference count of 0. Now we're passing this object // to Python the reference count needs to be incremented and the reference // needs to be replaced with a strong reference to stop the C# object being // collected while Python still has a reference to it. if (Runtime.Refcount(self.pyHandle) == 1) { GCHandle gc = GCHandle.Alloc(self, GCHandleType.Normal); Marshal.WriteIntPtr(self.pyHandle, ObjectOffset.magic(self.tpHandle), (IntPtr)gc); self.gcHandle.Free(); self.gcHandle = gc; // now the object has a python reference it's safe for the python GC to track it Runtime.PyObject_GC_Track(self.pyHandle); } return(self.pyHandle); }
internal CLRObject(object ob, IntPtr tp) { IntPtr py = Runtime.PyType_GenericAlloc(tp, 0); long flags = Util.ReadCLong(tp, TypeOffset.tp_flags); if ((flags & TypeFlags.Subclass) != 0) { IntPtr dict = Marshal.ReadIntPtr(py, ObjectOffset.DictOffset(tp)); if (dict == IntPtr.Zero) { dict = Runtime.PyDict_New(); Marshal.WriteIntPtr(py, ObjectOffset.DictOffset(tp), dict); } } GCHandle gc = GCHandle.Alloc(this); Marshal.WriteIntPtr(py, ObjectOffset.magic(tp), (IntPtr)gc); tpHandle = tp; pyHandle = py; gcHandle = gc; inst = ob; // Fix the BaseException args (and __cause__ in case of Python 3) // slot if wrapping a CLR exception Exceptions.SetArgsAndCause(py); }
/// <summary> /// Standard dealloc implementation for instances of reflected types. /// </summary> public static void tp_dealloc(IntPtr ob) { ManagedType self = GetManagedObject(ob); IntPtr dict = Marshal.ReadIntPtr(ob, ObjectOffset.DictOffset(ob)); if (dict != IntPtr.Zero) { Runtime.XDecref(dict); } Runtime.PyObject_GC_UnTrack(self.pyHandle); Runtime.PyObject_GC_Del(self.pyHandle); Runtime.XDecref(self.tpHandle); self.gcHandle.Free(); }
public new static void tp_dealloc(IntPtr ob) { var self = (CLRObject)GetManagedObject(ob); // don't let the python GC destroy this object Runtime.PyObject_GC_UnTrack(self.pyHandle); // The python should now have a ref count of 0, but we don't actually want to // deallocate the object until the C# object that references it is destroyed. // So we don't call PyObject_GC_Del here and instead we set the python // reference to a weak reference so that the C# object can be collected. GCHandle gc = GCHandle.Alloc(self, GCHandleType.Weak); Marshal.WriteIntPtr(self.pyHandle, ObjectOffset.magic(self.tpHandle), (IntPtr)gc); self.gcHandle.Free(); self.gcHandle = gc; }
public static void Finalize(IPythonDerivedType obj) { FieldInfo fi = obj.GetType().GetField("__pyobj__"); var self = (CLRObject)fi.GetValue(obj); // If python's been terminated then just free the gchandle. lock (Runtime.IsFinalizingLock) { if (0 == Runtime.Py_IsInitialized() || Runtime.IsFinalizing) { self.gcHandle.Free(); return; } } // delete the python object in an async task as we may not be able to acquire // the GIL immediately and we don't want to block the GC thread. // FIXME: t isn't used Task t = Task.Factory.StartNew(() => { lock (Runtime.IsFinalizingLock) { // If python's been terminated then just free the gchandle. if (0 == Runtime.Py_IsInitialized() || Runtime.IsFinalizing) { self.gcHandle.Free(); return; } IntPtr gs = Runtime.PyGILState_Ensure(); try { // the C# object is being destroyed which must mean there are no more // references to the Python object as well so now we can dealloc the // python object. IntPtr dict = Marshal.ReadIntPtr(self.pyHandle, ObjectOffset.DictOffset(self.pyHandle)); if (dict != IntPtr.Zero) { Runtime.XDecref(dict); } Runtime.PyObject_GC_Del(self.pyHandle); self.gcHandle.Free(); } finally { Runtime.PyGILState_Release(gs); } } }); }
public ModuleObject(string name) { if (name == string.Empty) { throw new ArgumentException("Name must not be empty!"); } moduleName = name; cache = new Dictionary <string, ManagedType>(); _namespace = name; // Use the filename from any of the assemblies just so there's something for // anything that expects __file__ to be set. var filename = "unknown"; var docstring = "Namespace containing types from the following assemblies:\n\n"; foreach (Assembly a in AssemblyManager.GetAssemblies(name)) { if (!a.IsDynamic && a.Location != null) { filename = a.Location; } docstring += "- " + a.FullName + "\n"; } dict = Runtime.PyDict_New(); IntPtr pyname = Runtime.PyString_FromString(moduleName); IntPtr pyfilename = Runtime.PyString_FromString(filename); IntPtr pydocstring = Runtime.PyString_FromString(docstring); IntPtr pycls = TypeManager.GetTypeHandle(GetType()); Runtime.PyDict_SetItemString(dict, "__name__", pyname); Runtime.PyDict_SetItemString(dict, "__file__", pyfilename); Runtime.PyDict_SetItemString(dict, "__doc__", pydocstring); Runtime.PyDict_SetItemString(dict, "__class__", pycls); Runtime.XDecref(pyname); Runtime.XDecref(pyfilename); Runtime.XDecref(pydocstring); Marshal.WriteIntPtr(pyHandle, ObjectOffset.DictOffset(pyHandle), dict); InitializeModuleMembers(); }
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); } i = name.LastIndexOf('.'); if (i > -1) { name = name.Substring(i + 1); } IntPtr base_ = IntPtr.Zero; int ob_size = ObjectOffset.Size(Runtime.PyTypeType); int tp_dictoffset = ObjectOffset.DictOffset(Runtime.PyTypeType); // XXX Hack, use a different base class for System.Exception // Python 2.5+ allows new style class exceptions but they *must* // subclass BaseException (or better Exception). if (typeof(Exception).IsAssignableFrom(clrType)) { ob_size = ObjectOffset.Size(Exceptions.Exception); tp_dictoffset = ObjectOffset.DictOffset(Exceptions.Exception); } if (clrType == typeof(Exception)) { base_ = Exceptions.Exception; } else 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.XIncref(Runtime.PyCLRMetaType); Marshal.WriteIntPtr(type, TypeOffset.tp_basicsize, (IntPtr)ob_size); Marshal.WriteIntPtr(type, TypeOffset.tp_itemsize, IntPtr.Zero); Marshal.WriteIntPtr(type, TypeOffset.tp_dictoffset, (IntPtr)tp_dictoffset); InitializeSlots(type, impl.GetType()); if (base_ != IntPtr.Zero) { Marshal.WriteIntPtr(type, TypeOffset.tp_base, base_); Runtime.XIncref(base_); } int flags = TypeFlags.Default; flags |= TypeFlags.Managed; flags |= TypeFlags.HeapType; flags |= TypeFlags.BaseType; flags |= TypeFlags.HaveGC; Util.WriteCLong(type, TypeOffset.tp_flags, 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); IntPtr dict = Marshal.ReadIntPtr(type, TypeOffset.tp_dict); string mn = clrType.Namespace ?? ""; IntPtr mod = Runtime.PyString_FromString(mn); Runtime.PyDict_SetItemString(dict, "__module__", mod); // 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); }