//==================================================================== // Dealloc implementation. This is called when a Python type generated // by this metatype is no longer referenced from the Python runtime. //==================================================================== public static void tp_dealloc(IntPtr tp) { // 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(); } IntPtr op = Marshal.ReadIntPtr(tp, TypeOffset.ob_type); Runtime.Decref(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); return; }
/// <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); }
/// <summary> /// Type __setattr__ implementation for reflected types. Note that this /// is slightly different than the standard setattr implementation for /// the normal Python metatype (PyTypeType). We need to look first in /// the type object of a reflected type for a descriptor in order to /// support the right setattr behavior for static fields and properties. /// </summary> public static int tp_setattro(IntPtr tp, IntPtr name, IntPtr value) { IntPtr descr = Runtime._PyType_Lookup(tp, name); if (descr != IntPtr.Zero) { IntPtr dt = Runtime.PyObject_TYPE(descr); if (dt == Runtime.PyWrapperDescriptorType || dt == Runtime.PyMethodType || typeof(ExtensionType).IsInstanceOfType(GetManagedObject(descr)) ) { IntPtr fp = Marshal.ReadIntPtr(dt, TypeOffset.tp_descr_set); if (fp != IntPtr.Zero) { return(NativeCall.Int_Call_3(fp, descr, name, value)); } Exceptions.SetError(Exceptions.AttributeError, "attribute is read-only"); return(-1); } } int res = Runtime.PyObject_GenericSetAttr(tp, name, value); Runtime.PyType_Modified(tp); return(res); }
internal static int PyVisit(IntPtr ob, IntPtr visit, IntPtr arg) { if (ob == IntPtr.Zero) { return 0; } var visitFunc = NativeCall.GetDelegate<Interop.ObjObjFunc>(visit); return visitFunc(ob, arg); }
/// <summary> /// Wrapper for calling tp_clear /// </summary> internal void CallTypeClear() { if (tpHandle == IntPtr.Zero || pyHandle == IntPtr.Zero) { return; } var clearPtr = Marshal.ReadIntPtr(tpHandle, TypeOffset.tp_clear); if (clearPtr == IntPtr.Zero) { return; } var clearFunc = NativeCall.GetDelegate<Interop.InquiryFunc>(clearPtr); clearFunc(pyHandle); }
/// <summary> /// Wrapper for calling tp_traverse /// </summary> internal void CallTypeTraverse(Interop.ObjObjFunc visitproc, IntPtr arg) { if (tpHandle == IntPtr.Zero || pyHandle == IntPtr.Zero) { return; } var traversePtr = Marshal.ReadIntPtr(tpHandle, TypeOffset.tp_traverse); if (traversePtr == IntPtr.Zero) { return; } var traverseFunc = NativeCall.GetDelegate<Interop.ObjObjArgFunc>(traversePtr); var visiPtr = Marshal.GetFunctionPointerForDelegate(visitproc); traverseFunc(pyHandle, visiPtr, arg); }
//==================================================================== // Metatype __call__ implementation. This is needed to ensure correct // initialization (__init__ support), because the tp_call we inherit // from PyType_Type won't call __init__ for metatypes it doesnt know. //==================================================================== public static IntPtr tp_call(IntPtr tp, IntPtr args, IntPtr kw) { IntPtr func = Marshal.ReadIntPtr(tp, TypeOffset.tp_new); if (func == IntPtr.Zero) { return(Exceptions.RaiseTypeError("invalid object")); } IntPtr obj = NativeCall.Call_3(func, tp, args, kw); if (obj == IntPtr.Zero) { 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) { IntPtr bound = Runtime.GetBoundArgTuple(obj, args); if (bound == IntPtr.Zero) { Runtime.Decref(obj); return(IntPtr.Zero); } IntPtr result = Runtime.PyObject_Call(init, bound, kw); Runtime.Decref(bound); if (result == IntPtr.Zero) { Runtime.Decref(obj); return(IntPtr.Zero); } Runtime.Decref(result); } return(obj); }
internal void CallTypeClear() { if (tpHandle == IntPtr.Zero || pyHandle == IntPtr.Zero) { return; } var clearPtr = Runtime.PyType_GetSlot(TypeReference, TypeSlotID.tp_clear); if (clearPtr == IntPtr.Zero) { return; } var clearFunc = NativeCall.GetDelegate <Interop.InquiryFunc>(clearPtr); clearFunc(pyHandle); }
/// <summary> /// Metatype __call__ implementation. This is needed to ensure correct /// initialization (__init__ support), because the tp_call we inherit /// from PyType_Type won't call __init__ for metatypes it doesn't know. /// </summary> public static IntPtr tp_call(IntPtr tp, IntPtr args, IntPtr kw) { IntPtr func = Marshal.ReadIntPtr(tp, TypeOffset.tp_new); if (func == IntPtr.Zero) { return(Exceptions.RaiseTypeError("invalid object")); } IntPtr obj = NativeCall.Call_3(func, tp, args, kw); if (obj == IntPtr.Zero) { return(IntPtr.Zero); } return(CallInit(obj, args, kw)); }
internal void CallTypeTraverse(Interop.ObjObjFunc visitproc, IntPtr arg) { if (tpHandle == IntPtr.Zero || pyHandle == IntPtr.Zero) { return; } var traversePtr = Runtime.PyType_GetSlot(TypeReference, TypeSlotID.tp_traverse); if (traversePtr == IntPtr.Zero) { return; } var traverseFunc = NativeCall.GetDelegate <Interop.ObjObjArgFunc>(traversePtr); var visiPtr = Marshal.GetFunctionPointerForDelegate(visitproc); traverseFunc(pyHandle, visiPtr, arg); }
/// <summary> /// Metatype __call__ implementation. This is needed to ensure correct /// initialization (__init__ support), because the tp_call we inherit /// from PyType_Type won't call __init__ for metatypes it doesn't know. /// </summary> public static IntPtr tp_call(IntPtr tp, IntPtr args, IntPtr kw) { IntPtr func = Marshal.ReadIntPtr(tp, TypeOffset.tp_new); if (func == IntPtr.Zero) { return(Exceptions.RaiseTypeError("invalid object")); } IntPtr obj = NativeCall.Call_3(func, tp, args, kw); if (obj == IntPtr.Zero) { return(IntPtr.Zero); } var init = Runtime.PyObject_GetAttrString(obj, "__init__"); Runtime.PyErr_Clear(); if (init != IntPtr.Zero) { IntPtr result = Runtime.PyObject_Call(init, args, kw); Runtime.XDecref(init); if (result == IntPtr.Zero) { Runtime.XDecref(obj); return(IntPtr.Zero); } Runtime.XDecref(result); } return(obj); }
/// <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) { int 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) { if (!cb.CanSubclass()) { return(Exceptions.RaiseTypeError("delegates, enums and array types cannot be subclassed")); } } IntPtr slots = Runtime.PyDict_GetItemString(dict, "__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) { Runtime.XIncref(dict); using (var clsDict = new PyDict(dict)) { if (clsDict.HasKey("__assembly__") || clsDict.HasKey("__namespace__")) { return(TypeManager.CreateSubType(name, base_type, dict)); } } } // 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); } int flags = TypeFlags.Default; flags |= TypeFlags.Managed; flags |= TypeFlags.HeapType; flags |= TypeFlags.BaseType; flags |= TypeFlags.Subclass; flags |= TypeFlags.HaveGC; Util.WriteCLong(type, TypeOffset.tp_flags, 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); // for now, move up hidden handle... IntPtr gc = Marshal.ReadIntPtr(base_type, TypeOffset.magic()); Marshal.WriteIntPtr(type, TypeOffset.magic(), gc); return(type); }
public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) { int 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. ClassBase cb = GetManagedObject(base_type) as ClassBase; if (cb != null) { if (!cb.CanSubclass()) { return(Exceptions.RaiseTypeError( "delegates, enums and array types cannot be subclassed" )); } } IntPtr slots = Runtime.PyDict_GetItemString(dict, "__slots__"); if (slots != IntPtr.Zero) { return(Exceptions.RaiseTypeError( "subclasses of managed classes do not support __slots__" )); } // hack for now... fix for 1.0 //return TypeManager.CreateSubType(args); // right way 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); } 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); 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); // for now, move up hidden handle... IntPtr gc = Marshal.ReadIntPtr(base_type, TypeOffset.magic()); Marshal.WriteIntPtr(type, TypeOffset.magic(), gc); //DebugUtil.DumpType(base_type); //DebugUtil.DumpType(type); return(type); }