/// <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(tp)); if (op == IntPtr.Zero) { return(null); } var gc = (GCHandle)op; return((ManagedType)gc.Target); } } return(null); }
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.TypeDictOffset(tp)); if (dict == IntPtr.Zero) { dict = Runtime.PyDict_New(); Marshal.WriteIntPtr(py, ObjectOffset.TypeDictOffset(tp), dict); } } GCHandle gc = GCHandle.Alloc(this); Marshal.WriteIntPtr(py, ObjectOffset.magic(tp), (IntPtr)gc); tpHandle = tp; pyHandle = py; gcHandle = gc; inst = ob; // for performance before calling SetArgsAndCause() lets check if we are an exception if (inst is Exception) { // Fix the BaseException args (and __cause__ in case of Python 3) // slot if wrapping a CLR exception Exceptions.SetArgsAndCause(py); } }
/// <summary> /// Dealloc implementation. This is called when a Python type generated /// by this metatype is no longer referenced from the Python runtime. /// </summary> public static void tp_dealloc(IntPtr tp) { // Fix this when we dont cheat on the handle for subclasses! var flags = (TypeFlags)Util.ReadCLong(tp, TypeOffset.tp_flags); if ((flags & TypeFlags.Subclass) == 0) { GetGCHandle(new BorrowedReference(tp)).Free(); #if DEBUG // prevent ExecutionEngineException in debug builds in case we have a bug // this would allow using managed debugger to investigate the issue SetGCHandle(new BorrowedReference(tp), Runtime.CLRMetaType, default); #endif } IntPtr op = Marshal.ReadIntPtr(tp, TypeOffset.ob_type); Runtime.XDecref(op); // Delegate the rest of finalization the Python metatype. Note // that the PyType_Type implementation of tp_dealloc will call // tp_free on the type of the type being deallocated - in this // case our CLR metatype. That is why we implement tp_free. op = Marshal.ReadIntPtr(Runtime.PyTypeType, TypeOffset.tp_dealloc); NativeCall.Void_Call_1(op, tp); }
internal CLRObject(object ob, IntPtr tp) { System.Diagnostics.Debug.Assert(tp != IntPtr.Zero); 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.TypeDictOffset(tp)); if (dict == IntPtr.Zero) { dict = Runtime.PyDict_New(); Marshal.WriteIntPtr(py, ObjectOffset.TypeDictOffset(tp), dict); } } GCHandle gc = AllocGCHandle(TrackTypes.Wrapper); Marshal.WriteIntPtr(py, ObjectOffset.magic(tp), (IntPtr)gc); tpHandle = tp; pyHandle = py; inst = ob; // Fix the BaseException args (and __cause__ in case of Python 3) // slot if wrapping a CLR exception Exceptions.SetArgsAndCause(py); }
/// <summary> /// Given a Python object, return the associated managed object type or null. /// </summary> internal static ManagedType GetManagedObjectType(IntPtr ob) { if (ob != IntPtr.Zero) { IntPtr tp = Runtime.PyObject_TYPE(ob); var flags = (TypeFlags)Util.ReadCLong(tp, TypeOffset.tp_flags); if ((flags & TypeFlags.HasClrInstance) != 0) { var gc = GetGCHandle(new BorrowedReference(tp), Runtime.CLRMetaType); return (ManagedType)gc.Target; } } return null; }
//==================================================================== // Python iterator API //==================================================================== internal static bool PyIter_Check(IntPtr pointer) { var ob_type = Marshal.ReadIntPtr(pointer, ObjectOffset.ob_type); #if PYTHON2 long tp_flags = Util.ReadCLong(ob_type, TypeOffset.tp_flags); if ((tp_flags & TypeFlags.HaveIter) == 0) { return(false); } #endif IntPtr tp_iternext = Marshal.ReadIntPtr(ob_type, TypeOffset.tp_iternext); return(tp_iternext != IntPtr.Zero && tp_iternext != _PyObject_NextNotImplemented); }
/// <summary> /// Test whether the Python object is an iterable. /// </summary> internal static bool PyObject_IsIterable(IntPtr pointer) { var ob_type = Marshal.ReadIntPtr(pointer, ObjectOffset.ob_type); #if PYTHON2 long tp_flags = Util.ReadCLong(ob_type, TypeOffset.tp_flags); if ((tp_flags & TypeFlags.HaveIter) == 0) { return(false); } #endif IntPtr tp_iter = Marshal.ReadIntPtr(ob_type, TypeOffset.tp_iter); return(tp_iter != IntPtr.Zero); }
/// <summary> /// Given a Python object, return the associated managed object type or null. /// </summary> internal static ManagedType GetManagedObjectType(IntPtr ob) { if (ob != IntPtr.Zero) { IntPtr tp = Runtime.PyObject_TYPE(ob); var flags = Util.ReadCLong(tp, TypeOffset.tp_flags); if ((flags & TypeFlags.Managed) != 0) { tp = Marshal.ReadIntPtr(tp, TypeOffset.magic()); var gc = (GCHandle)tp; return((ManagedType)gc.Target); } } return(null); }
internal static bool IsManagedType(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) { return(true); } } return(false); }
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 = (TypeFlags)Util.ReadCLong(tp, TypeOffset.tp_flags); if ((flags & TypeFlags.HasClrInstance) != 0) { var gc = TryGetGCHandle(new BorrowedReference(ob)); return((ManagedType)gc?.Target); } } return(null); }
/// <summary> /// Dealloc implementation. This is called when a Python type generated /// by this metatype is no longer referenced from the Python runtime. /// </summary> public static void tp_dealloc(IntPtr tp) { // Fix this when we dont cheat on the handle for subclasses! var flags = Util.ReadCLong(tp, TypeOffset.tp_flags); if ((flags & TypeFlags.Subclass) == 0) { IntPtr gc = Marshal.ReadIntPtr(tp, TypeOffset.magic()); ((GCHandle)gc).Free(); } IntPtr op = Marshal.ReadIntPtr(tp, TypeOffset.ob_type); Runtime.XDecref(op); // Delegate the rest of finalization the Python metatype. Note // that the PyType_Type implementation of tp_dealloc will call // tp_free on the type of the type being deallocated - in this // case our CLR metatype. That is why we implement tp_free. op = Marshal.ReadIntPtr(Runtime.PyTypeType, TypeOffset.tp_dealloc); NativeCall.Void_Call_1(op, tp); }
internal static bool IsManagedType(BorrowedReference type) { var flags = (TypeFlags)Util.ReadCLong(type.DangerousGetAddress(), TypeOffset.tp_flags); return (flags & TypeFlags.HasClrInstance) != 0; }
/// <summary> /// Metatype __new__ implementation. This is called to create a new /// class / type when a reflected class is subclassed. /// </summary> public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) { var len = Runtime.PyTuple_Size(args); if (len < 3) { return(Exceptions.RaiseTypeError("invalid argument list")); } IntPtr name = Runtime.PyTuple_GetItem(args, 0); IntPtr bases = Runtime.PyTuple_GetItem(args, 1); IntPtr dict = Runtime.PyTuple_GetItem(args, 2); // We do not support multiple inheritance, so the bases argument // should be a 1-item tuple containing the type we are subtyping. // That type must itself have a managed implementation. We check // that by making sure its metatype is the CLR metatype. if (Runtime.PyTuple_Size(bases) != 1) { return(Exceptions.RaiseTypeError("cannot use multiple inheritance with managed classes")); } IntPtr base_type = Runtime.PyTuple_GetItem(bases, 0); IntPtr mt = Runtime.PyObject_TYPE(base_type); if (!(mt == PyCLRMetaType || mt == Runtime.PyTypeType)) { return(Exceptions.RaiseTypeError("invalid metatype")); } // Ensure that the reflected type is appropriate for subclassing, // disallowing subclassing of delegates, enums and array types. var cb = GetManagedObject(base_type) as ClassBase; if (cb != null) { try { if (!cb.CanSubclass()) { return(Exceptions.RaiseTypeError("delegates, enums and array types cannot be subclassed")); } } catch (SerializationException) { return(Exceptions.RaiseTypeError($"Underlying C# Base class {cb.type} has been deleted")); } } IntPtr slots = Runtime.PyDict_GetItem(dict, PyIdentifier.__slots__); if (slots != IntPtr.Zero) { return(Exceptions.RaiseTypeError("subclasses of managed classes do not support __slots__")); } // If __assembly__ or __namespace__ are in the class dictionary then create // a managed sub type. // This creates a new managed type that can be used from .net to call back // into python. if (IntPtr.Zero != dict) { using (var clsDict = new PyDict(new BorrowedReference(dict))) { if (clsDict.HasKey("__assembly__") || clsDict.HasKey("__namespace__")) { return(TypeManager.CreateSubType(name, base_type, clsDict.Reference)); } } } // otherwise just create a basic type without reflecting back into the managed side. IntPtr func = Marshal.ReadIntPtr(Runtime.PyTypeType, TypeOffset.tp_new); IntPtr type = NativeCall.Call_3(func, tp, args, kw); if (type == IntPtr.Zero) { return(IntPtr.Zero); } var flags = (TypeFlags)Util.ReadCLong(type, TypeOffset.tp_flags); if (!flags.HasFlag(TypeFlags.Ready)) { throw new NotSupportedException("PyType.tp_new returned an incomplete type"); } flags |= TypeFlags.HasClrInstance; flags |= TypeFlags.HeapType; flags |= TypeFlags.BaseType; flags |= TypeFlags.Subclass; flags |= TypeFlags.HaveGC; Util.WriteCLong(type, TypeOffset.tp_flags, (int)flags); TypeManager.CopySlot(base_type, type, TypeOffset.tp_dealloc); // Hmm - the standard subtype_traverse, clear look at ob_size to // do things, so to allow gc to work correctly we need to move // our hidden handle out of ob_size. Then, in theory we can // comment this out and still not crash. TypeManager.CopySlot(base_type, type, TypeOffset.tp_traverse); TypeManager.CopySlot(base_type, type, TypeOffset.tp_clear); // derived types must have their GCHandle at the same offset as the base types int clrInstOffset = Marshal.ReadInt32(base_type, Offsets.tp_clr_inst_offset); Marshal.WriteInt32(type, Offsets.tp_clr_inst_offset, clrInstOffset); // for now, move up hidden handle... IntPtr gc = Marshal.ReadIntPtr(base_type, Offsets.tp_clr_inst); Marshal.WriteIntPtr(type, Offsets.tp_clr_inst, gc); Runtime.PyType_Modified(new BorrowedReference(type)); return(type); }