diff --git a/src/runtime/classbase.cs b/src/runtime/classbase.cs index bf6a8034d..55f5c5b8f 100644 --- a/src/runtime/classbase.cs +++ b/src/runtime/classbase.cs @@ -373,7 +373,7 @@ public static int tp_clear(IntPtr ob) protected override void OnSave(InterDomainContext context) { base.OnSave(context); - if (pyHandle != tpHandle) + if (!this.IsClrMetaTypeInstance()) { IntPtr dict = GetObjectDict(pyHandle); Runtime.XIncref(dict); @@ -384,7 +384,7 @@ protected override void OnSave(InterDomainContext context) protected override void OnLoad(InterDomainContext context) { base.OnLoad(context); - if (pyHandle != tpHandle) + if (!this.IsClrMetaTypeInstance()) { IntPtr dict = context.Storage.GetValue("dict"); SetObjectDict(pyHandle, dict); diff --git a/src/runtime/classderived.cs b/src/runtime/classderived.cs index f8b97b397..cc2397225 100644 --- a/src/runtime/classderived.cs +++ b/src/runtime/classderived.cs @@ -122,11 +122,13 @@ internal static IntPtr ToPython(IPythonDerivedType obj) /// internal static Type CreateDerivedType(string name, Type baseType, - IntPtr py_dict, + BorrowedReference dictRef, string namespaceStr, string assemblyName, string moduleName = "Python.Runtime.Dynamic.dll") { + // TODO: clean up + IntPtr py_dict = dictRef.DangerousGetAddress(); if (null != namespaceStr) { name = namespaceStr + "." + name; @@ -824,7 +826,7 @@ public static void InvokeCtor(IPythonDerivedType obj, string origCtorName, objec try { // create the python object - IntPtr type = TypeManager.GetTypeHandle(obj.GetType()); + BorrowedReference type = TypeManager.GetTypeReference(obj.GetType()); self = new CLRObject(obj, type); // set __pyobj__ to self and deref the python object which will allow this diff --git a/src/runtime/classmanager.cs b/src/runtime/classmanager.cs index 306962f56..e3c5b2a3b 100644 --- a/src/runtime/classmanager.cs +++ b/src/runtime/classmanager.cs @@ -117,7 +117,7 @@ internal static void SaveRuntimeData(RuntimeDataStorage storage) // Python object's dictionary tool; thus raising an AttributeError // instead of a TypeError. // Classes are re-initialized on in RestoreRuntimeData. - var dict = new BorrowedReference(Marshal.ReadIntPtr(cls.Value.tpHandle, TypeOffset.tp_dict)); + using var dict = Runtime.PyObject_GenericGetDict(cls.Value.TypeReference); foreach (var member in cls.Value.dotNetMembers) { // No need to decref the member, the ClassBase instance does @@ -135,7 +135,7 @@ internal static void SaveRuntimeData(RuntimeDataStorage storage) } } // We modified the Type object, notify it we did. - Runtime.PyType_Modified(cls.Value.tpHandle); + Runtime.PyType_Modified(cls.Value.TypeReference); } } @@ -155,7 +155,7 @@ internal static Dictionary RestoreRuntimeData(R // re-init the class InitClassBase(pair.Key.Value, pair.Value); // We modified the Type object, notify it we did. - Runtime.PyType_Modified(pair.Value.tpHandle); + Runtime.PyType_Modified(pair.Value.TypeReference); var context = contexts[pair.Value.pyHandle]; pair.Value.Load(context); loadedObjs.Add(pair.Value, context); @@ -266,10 +266,10 @@ private static void InitClassBase(Type type, ClassBase impl) // point to the managed methods providing the implementation. - IntPtr tp = TypeManager.GetTypeHandle(impl, type); + var pyType = TypeManager.GetType(impl, type); // Finally, initialize the class __dict__ and return the object. - var dict = new BorrowedReference(Marshal.ReadIntPtr(tp, TypeOffset.tp_dict)); + using var dict = Runtime.PyObject_GenericGetDict(pyType.Reference); if (impl.dotNetMembers == null) @@ -312,7 +312,7 @@ private static void InitClassBase(Type type, ClassBase impl) // Implement Overloads on the class object if (!CLRModule._SuppressOverloads) { - var ctors = new ConstructorBinding(type, tp, co.binder); + var ctors = new ConstructorBinding(type, pyType, co.binder); // ExtensionType types are untracked, so don't Incref() them. // TODO: deprecate __overloads__ soon... Runtime.PyDict_SetItem(dict, PyIdentifier.__overloads__, ctors.ObjectReference); @@ -332,7 +332,7 @@ private static void InitClassBase(Type type, ClassBase impl) // The type has been modified after PyType_Ready has been called // Refresh the type - Runtime.PyType_Modified(tp); + Runtime.PyType_Modified(pyType.Reference); } internal static bool ShouldBindMethod(MethodBase mb) diff --git a/src/runtime/clrobject.cs b/src/runtime/clrobject.cs index 46cd896e2..142fade25 100644 --- a/src/runtime/clrobject.cs +++ b/src/runtime/clrobject.cs @@ -26,6 +26,8 @@ internal CLRObject(object ob, IntPtr tp) if (ob is Exception e) Exceptions.SetArgsAndCause(e, py); } + internal CLRObject(object ob, BorrowedReference tp) : this(ob, tp.DangerousGetAddress()) { } + protected CLRObject() { } diff --git a/src/runtime/constructorbinding.cs b/src/runtime/constructorbinding.cs index 803823e39..6706c2b48 100644 --- a/src/runtime/constructorbinding.cs +++ b/src/runtime/constructorbinding.cs @@ -23,16 +23,16 @@ namespace Python.Runtime internal class ConstructorBinding : ExtensionType { private MaybeType type; // The managed Type being wrapped in a ClassObject - private IntPtr pyTypeHndl; // The python type tells GetInstHandle which Type to create. + private PyType typeToCreate; // The python type tells GetInstHandle which Type to create. private ConstructorBinder ctorBinder; [NonSerialized] private IntPtr repr; - public ConstructorBinding(Type type, IntPtr pyTypeHndl, ConstructorBinder ctorBinder) + public ConstructorBinding(Type type, PyType typeToCreate, ConstructorBinder ctorBinder) { this.type = type; - this.pyTypeHndl = pyTypeHndl; // steal a type reference + this.typeToCreate = typeToCreate; this.ctorBinder = ctorBinder; repr = IntPtr.Zero; } @@ -110,7 +110,7 @@ public static IntPtr mp_subscript(IntPtr op, IntPtr key) { return Exceptions.RaiseTypeError("No match found for constructor signature"); } - var boundCtor = new BoundContructor(tp, self.pyTypeHndl, self.ctorBinder, ci); + var boundCtor = new BoundContructor(tp, self.typeToCreate, self.ctorBinder, ci); return boundCtor.pyHandle; } @@ -169,7 +169,7 @@ public static int tp_clear(IntPtr ob) public static int tp_traverse(IntPtr ob, IntPtr visit, IntPtr arg) { var self = (ConstructorBinding)GetManagedObject(ob); - int res = PyVisit(self.pyTypeHndl, visit, arg); + int res = PyVisit(self.typeToCreate.Handle, visit, arg); if (res != 0) return res; res = PyVisit(self.repr, visit, arg); @@ -190,15 +190,15 @@ public static int tp_traverse(IntPtr ob, IntPtr visit, IntPtr arg) internal class BoundContructor : ExtensionType { private Type type; // The managed Type being wrapped in a ClassObject - private IntPtr pyTypeHndl; // The python type tells GetInstHandle which Type to create. + private PyType typeToCreate; // The python type tells GetInstHandle which Type to create. private ConstructorBinder ctorBinder; private ConstructorInfo ctorInfo; private IntPtr repr; - public BoundContructor(Type type, IntPtr pyTypeHndl, ConstructorBinder ctorBinder, ConstructorInfo ci) + public BoundContructor(Type type, PyType typeToCreate, ConstructorBinder ctorBinder, ConstructorInfo ci) { this.type = type; - this.pyTypeHndl = pyTypeHndl; // steal a type reference + this.typeToCreate = typeToCreate; this.ctorBinder = ctorBinder; ctorInfo = ci; repr = IntPtr.Zero; @@ -229,7 +229,7 @@ public static IntPtr tp_call(IntPtr op, IntPtr args, IntPtr kw) } // Instantiate the python object that wraps the result of the method call // and return the PyObject* to it. - return CLRObject.GetInstHandle(obj, self.pyTypeHndl); + return CLRObject.GetInstHandle(obj, self.typeToCreate.Reference).DangerousMoveToPointer(); } /// @@ -272,7 +272,7 @@ public static int tp_clear(IntPtr ob) public static int tp_traverse(IntPtr ob, IntPtr visit, IntPtr arg) { var self = (BoundContructor)GetManagedObject(ob); - int res = PyVisit(self.pyTypeHndl, visit, arg); + int res = PyVisit(self.typeToCreate.Handle, visit, arg); if (res != 0) return res; res = PyVisit(self.repr, visit, arg); diff --git a/src/runtime/exceptions.cs b/src/runtime/exceptions.cs index 40e018fe6..163b0a11e 100644 --- a/src/runtime/exceptions.cs +++ b/src/runtime/exceptions.cs @@ -206,6 +206,15 @@ internal static void ErrorOccurredCheck(IntPtr pointer) } } + internal static IntPtr ErrorCheckIfNull(IntPtr pointer) + { + if (pointer == IntPtr.Zero && ErrorOccurred()) + { + throw new PythonException(); + } + return pointer; + } + /// /// ExceptionMatches Method /// diff --git a/src/runtime/extensiontype.cs b/src/runtime/extensiontype.cs index 554837c46..34a82fe37 100644 --- a/src/runtime/extensiontype.cs +++ b/src/runtime/extensiontype.cs @@ -18,7 +18,7 @@ public ExtensionType() // The Python instance object is related to an instance of a // particular concrete subclass with a hidden CLR gchandle. - IntPtr tp = TypeManager.GetTypeHandle(GetType()); + BorrowedReference tp = TypeManager.GetTypeReference(GetType()); //int rc = (int)Marshal.ReadIntPtr(tp, TypeOffset.ob_refcnt); //if (rc > 1050) @@ -27,11 +27,11 @@ public ExtensionType() // DebugUtil.DumpType(tp); //} - IntPtr py = Runtime.PyType_GenericAlloc(tp, 0); + NewReference py = Runtime.PyType_GenericAlloc(tp, 0); - // Steals a ref to tpHandle. - tpHandle = tp; - pyHandle = py; + // Borrowed reference. Valid as long as pyHandle is valid. + tpHandle = tp.DangerousGetAddress(); + pyHandle = py.DangerousMoveToPointer(); #if DEBUG GetGCHandle(ObjectReference, TypeReference, out var existing); diff --git a/src/runtime/managedtype.cs b/src/runtime/managedtype.cs index 41408abc7..e2f7a171f 100644 --- a/src/runtime/managedtype.cs +++ b/src/runtime/managedtype.cs @@ -1,3 +1,4 @@ +#nullable enable using System; using System.Collections.Generic; using System.Diagnostics; @@ -27,8 +28,8 @@ internal enum TrackTypes internal IntPtr pyHandle; // PyObject * internal IntPtr tpHandle; // PyType * - internal BorrowedReference ObjectReference => new BorrowedReference(pyHandle); - internal BorrowedReference TypeReference => new BorrowedReference(tpHandle); + internal BorrowedReference ObjectReference => new(pyHandle); + internal BorrowedReference TypeReference => new(tpHandle); private static readonly Dictionary _managedObjs = new Dictionary(); @@ -78,12 +79,12 @@ internal void FreeGCHandle() } } - internal static ManagedType GetManagedObject(BorrowedReference ob) + internal static ManagedType? GetManagedObject(BorrowedReference ob) => GetManagedObject(ob.DangerousGetAddress()); /// /// Given a Python object, return the associated managed object or null. /// - internal static ManagedType GetManagedObject(IntPtr ob) + internal static ManagedType? GetManagedObject(IntPtr ob) { if (ob != IntPtr.Zero) { @@ -106,7 +107,7 @@ internal static ManagedType GetManagedObject(IntPtr ob) /// /// Given a Python object, return the associated managed object type or null. /// - internal static ManagedType GetManagedObjectType(IntPtr ob) + internal static ManagedType? GetManagedObjectType(IntPtr ob) { if (ob != IntPtr.Zero) { @@ -121,18 +122,6 @@ internal static ManagedType GetManagedObjectType(IntPtr ob) return null; } - - internal static ManagedType GetManagedObjectErr(IntPtr ob) - { - ManagedType result = GetManagedObject(ob); - if (result == null) - { - Exceptions.SetError(Exceptions.TypeError, "invalid argument, expected CLR type"); - } - return result; - } - - internal static bool IsInstanceOfManagedType(BorrowedReference ob) => IsInstanceOfManagedType(ob.DangerousGetAddressOrNull()); internal static bool IsInstanceOfManagedType(IntPtr ob) @@ -156,6 +145,13 @@ internal static bool IsManagedType(BorrowedReference type) return (flags & TypeFlags.HasClrInstance) != 0; } + public bool IsClrMetaTypeInstance() + { + Debug.Assert(Runtime.PyCLRMetaType != IntPtr.Zero); + Debug.Assert(pyHandle != IntPtr.Zero); + return Runtime.PyObject_TYPE(pyHandle) == Runtime.PyCLRMetaType; + } + internal static IDictionary GetManagedObjects() { return _managedObjs; @@ -185,7 +181,8 @@ internal void CallTypeClear() { return; } - var clearPtr = Marshal.ReadIntPtr(tpHandle, TypeOffset.tp_clear); + + var clearPtr = Runtime.PyType_GetSlot(TypeReference, TypeSlotID.tp_clear); if (clearPtr == IntPtr.Zero) { return; @@ -203,7 +200,7 @@ internal void CallTypeTraverse(Interop.ObjObjFunc visitproc, IntPtr arg) { return; } - var traversePtr = Marshal.ReadIntPtr(tpHandle, TypeOffset.tp_traverse); + var traversePtr = Runtime.PyType_GetSlot(TypeReference, TypeSlotID.tp_traverse); if (traversePtr == IntPtr.Zero) { return; diff --git a/src/runtime/metatype.cs b/src/runtime/metatype.cs index 1fde7dd78..a25df30e5 100644 --- a/src/runtime/metatype.cs +++ b/src/runtime/metatype.cs @@ -132,7 +132,7 @@ public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) { if (clsDict.HasKey("__assembly__") || clsDict.HasKey("__namespace__")) { - return TypeManager.CreateSubType(name, base_type, dict); + return TypeManager.CreateSubType(name, base_type, clsDict.Reference); } } } @@ -266,7 +266,7 @@ public static int tp_setattro(IntPtr tp, IntPtr name, IntPtr value) } int res = Runtime.PyObject_GenericSetAttr(tp, name, value); - Runtime.PyType_Modified(tp); + Runtime.PyType_Modified(new BorrowedReference(tp)); return res; } diff --git a/src/runtime/pytype.cs b/src/runtime/pytype.cs index 8bc08b76d..e3d95db8d 100644 --- a/src/runtime/pytype.cs +++ b/src/runtime/pytype.cs @@ -6,6 +6,7 @@ namespace Python.Runtime { + [Serializable] public class PyType : PyObject { /// Creates heap type object from the . @@ -13,6 +14,12 @@ public PyType(TypeSpec spec, PyTuple? bases = null) : base(FromSpec(spec, bases) /// Wraps an existing type object. public PyType(PyObject o) : base(FromObject(o)) { } + internal PyType(BorrowedReference reference) : base(reference) + { + if (!Runtime.PyType_Check(this.Handle)) + throw new ArgumentException("object is not a type"); + } + /// Checks if specified object is a Python type. public static bool IsType(PyObject value) { @@ -21,6 +28,12 @@ public static bool IsType(PyObject value) return Runtime.PyType_Check(value.obj); } + internal IntPtr GetSlot(TypeSlotID slot) + { + IntPtr result = Runtime.PyType_GetSlot(this.Reference, slot); + return Exceptions.ErrorCheckIfNull(result); + } + private static BorrowedReference FromObject(PyObject o) { if (o is null) throw new ArgumentNullException(nameof(o)); diff --git a/src/runtime/runtime.cs b/src/runtime/runtime.cs index 232dd8708..8a3ad9231 100644 --- a/src/runtime/runtime.cs +++ b/src/runtime/runtime.cs @@ -1991,7 +1991,7 @@ internal static bool PyType_Check(IntPtr ob) } - internal static void PyType_Modified(IntPtr type) => Delegates.PyType_Modified(type); + internal static void PyType_Modified(BorrowedReference type) => Delegates.PyType_Modified(type); internal static bool PyType_IsSubtype(BorrowedReference t1, IntPtr ofType) => PyType_IsSubtype(t1, new BorrowedReference(ofType)); internal static bool PyType_IsSubtype(BorrowedReference t1, BorrowedReference t2) => Delegates.PyType_IsSubtype(t1, t2); @@ -2014,14 +2014,10 @@ internal static bool PyType_IsSameAsOrSubtype(BorrowedReference type, BorrowedRe internal static IntPtr PyType_GenericNew(IntPtr type, IntPtr args, IntPtr kw) => Delegates.PyType_GenericNew(type, args, kw); - internal static IntPtr PyType_GenericAlloc(IntPtr type, long n) - { - return PyType_GenericAlloc(type, new IntPtr(n)); - } - + internal static IntPtr PyType_GenericAlloc(IntPtr type, nint n) => PyType_GenericAlloc(new BorrowedReference(type), n).DangerousMoveToPointer(); + internal static NewReference PyType_GenericAlloc(BorrowedReference type, nint n) => Delegates.PyType_GenericAlloc(type, n); - private static IntPtr PyType_GenericAlloc(IntPtr type, IntPtr n) => Delegates.PyType_GenericAlloc(type, n); - + internal static IntPtr PyType_GetSlot(BorrowedReference type, TypeSlotID slot) => Delegates.PyType_GetSlot(type, slot); internal static NewReference PyType_FromSpecWithBases(in NativeTypeSpec spec, BorrowedReference bases) => Delegates.PyType_FromSpecWithBases(in spec, bases); /// @@ -2489,10 +2485,10 @@ static Delegates() PySys_SetArgvEx = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PySys_SetArgvEx), GetUnmanagedDll(_PythonDll)); PySys_GetObject = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PySys_GetObject), GetUnmanagedDll(_PythonDll)); PySys_SetObject = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PySys_SetObject), GetUnmanagedDll(_PythonDll)); - PyType_Modified = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyType_Modified), GetUnmanagedDll(_PythonDll)); + PyType_Modified = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyType_Modified), GetUnmanagedDll(_PythonDll)); PyType_IsSubtype = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyType_IsSubtype), GetUnmanagedDll(_PythonDll)); PyType_GenericNew = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyType_GenericNew), GetUnmanagedDll(_PythonDll)); - PyType_GenericAlloc = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyType_GenericAlloc), GetUnmanagedDll(_PythonDll)); + PyType_GenericAlloc = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyType_GenericAlloc), GetUnmanagedDll(_PythonDll)); PyType_Ready = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyType_Ready), GetUnmanagedDll(_PythonDll)); _PyType_Lookup = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(_PyType_Lookup), GetUnmanagedDll(_PythonDll)); PyObject_GenericGetAttr = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyObject_GenericGetAttr), GetUnmanagedDll(_PythonDll)); @@ -2534,6 +2530,7 @@ static Delegates() PyException_SetCause = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyException_SetCause), GetUnmanagedDll(_PythonDll)); PyThreadState_SetAsyncExcLLP64 = (delegate* unmanaged[Cdecl])GetFunctionByName("PyThreadState_SetAsyncExc", GetUnmanagedDll(_PythonDll)); PyThreadState_SetAsyncExcLP64 = (delegate* unmanaged[Cdecl])GetFunctionByName("PyThreadState_SetAsyncExc", GetUnmanagedDll(_PythonDll)); + PyType_GetSlot = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyType_GetSlot), GetUnmanagedDll(_PythonDll)); PyType_FromSpecWithBases = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyType_FromSpecWithBases), GetUnmanagedDll(PythonDLL)); try @@ -2774,10 +2771,10 @@ static Delegates() internal static delegate* unmanaged[Cdecl] PySys_SetArgvEx { get; } internal static delegate* unmanaged[Cdecl] PySys_GetObject { get; } internal static delegate* unmanaged[Cdecl] PySys_SetObject { get; } - internal static delegate* unmanaged[Cdecl] PyType_Modified { get; } + internal static delegate* unmanaged[Cdecl] PyType_Modified { get; } internal static delegate* unmanaged[Cdecl] PyType_IsSubtype { get; } internal static delegate* unmanaged[Cdecl] PyType_GenericNew { get; } - internal static delegate* unmanaged[Cdecl] PyType_GenericAlloc { get; } + internal static delegate* unmanaged[Cdecl] PyType_GenericAlloc { get; } internal static delegate* unmanaged[Cdecl] PyType_Ready { get; } internal static delegate* unmanaged[Cdecl] _PyType_Lookup { get; } internal static delegate* unmanaged[Cdecl] PyObject_GenericGetAttr { get; } @@ -2819,6 +2816,7 @@ static Delegates() internal static delegate* unmanaged[Cdecl] PyThreadState_SetAsyncExcLLP64 { get; } internal static delegate* unmanaged[Cdecl] PyThreadState_SetAsyncExcLP64 { get; } internal static delegate* unmanaged[Cdecl] PyObject_GenericGetDict { get; } + internal static delegate* unmanaged[Cdecl] PyType_GetSlot { get; } internal static delegate* unmanaged[Cdecl] PyType_FromSpecWithBases { get; } internal static delegate* unmanaged[Cdecl] _Py_NewReference { get; } } diff --git a/src/runtime/runtime_data.cs b/src/runtime/runtime_data.cs index 29cea4181..832e5bbec 100644 --- a/src/runtime/runtime_data.cs +++ b/src/runtime/runtime_data.cs @@ -119,12 +119,13 @@ private static void RestoreRuntimeDataImpl() var formatter = CreateFormatter(); var storage = (RuntimeDataStorage)formatter.Deserialize(ms); + PyCLRMetaType = MetaType.RestoreRuntimeData(storage.GetStorage("meta")); + var objs = RestoreRuntimeDataObjects(storage.GetStorage("objs")); RestoreRuntimeDataModules(storage.GetStorage("modules")); TypeManager.RestoreRuntimeData(storage.GetStorage("types")); var clsObjs = ClassManager.RestoreRuntimeData(storage.GetStorage("classes")); ImportHook.RestoreRuntimeData(storage.GetStorage("import")); - PyCLRMetaType = MetaType.RestoreRuntimeData(storage.GetStorage("meta")); foreach (var item in objs) { diff --git a/src/runtime/typemanager.cs b/src/runtime/typemanager.cs index 20b95d85c..9707568b5 100644 --- a/src/runtime/typemanager.cs +++ b/src/runtime/typemanager.cs @@ -21,7 +21,7 @@ internal class TypeManager internal static IntPtr subtype_clear; private const BindingFlags tbFlags = BindingFlags.Public | BindingFlags.Static; - private static Dictionary cache = new Dictionary(); + private static Dictionary cache = new(); private static readonly Dictionary _slotsHolders = new Dictionary(); private static Dictionary _slotsImpls = new Dictionary(); @@ -45,19 +45,19 @@ internal static void Initialize() internal static void RemoveTypes() { - foreach (var tpHandle in cache.Values) + foreach (var type in cache.Values) { SlotsHolder holder; - if (_slotsHolders.TryGetValue(tpHandle, out holder)) + if (_slotsHolders.TryGetValue(type.Handle, out holder)) { // If refcount > 1, it needs to reset the managed slot, // otherwise it can dealloc without any trick. - if (Runtime.Refcount(tpHandle) > 1) + if (Runtime.Refcount(type.Handle) > 1) { holder.ResetSlots(); } } - Runtime.XDecref(tpHandle); + type.Dispose(); } cache.Clear(); _slotsImpls.Clear(); @@ -68,7 +68,7 @@ internal static void SaveRuntimeData(RuntimeDataStorage storage) { foreach (var tpHandle in cache.Values) { - Runtime.XIncref(tpHandle); + Runtime.XIncref(tpHandle.Handle); } storage.AddValue("cache", cache); storage.AddValue("slots", _slotsImpls); @@ -78,45 +78,33 @@ internal static void RestoreRuntimeData(RuntimeDataStorage storage) { Debug.Assert(cache == null || cache.Count == 0); storage.GetValue("slots", out _slotsImpls); - storage.GetValue>("cache", out var _cache); + storage.GetValue>("cache", out var _cache); foreach (var entry in _cache) { if (!entry.Key.Valid) { - Runtime.XDecref(entry.Value); + entry.Value.Dispose(); continue; } Type type = entry.Key.Value;; - IntPtr handle = entry.Value; - cache[type] = handle; - SlotsHolder holder = CreateSolotsHolder(handle); - InitializeSlots(handle, _slotsImpls[type], holder); + cache[type] = entry.Value; + SlotsHolder holder = CreateSolotsHolder(entry.Value.Handle); + InitializeSlots(entry.Value.Handle, _slotsImpls[type], holder); // FIXME: mp_length_slot.CanAssgin(clrType) } } - /// - /// Return value: Borrowed reference. - /// 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. - /// - [Obsolete] - internal static IntPtr GetTypeHandle(Type type) + internal static PyType GetType(Type type) { // Note that these types are cached with a refcount of 1, so they // effectively exist until the CPython runtime is finalized. - IntPtr handle; - cache.TryGetValue(type, out handle); - if (handle != IntPtr.Zero) + if (!cache.TryGetValue(type, out var pyType)) { - return handle; + pyType = CreateType(type); + cache[type] = pyType; + _slotsImpls.Add(type, type); } - handle = CreateType(type); - cache[type] = handle; - _slotsImpls.Add(type, type); - return handle; + return pyType; } /// /// Given a managed Type derived from ExtensionType, get the handle to @@ -124,28 +112,23 @@ internal static IntPtr GetTypeHandle(Type type) /// object. These Python type instances are used to implement internal /// descriptor and utility types like ModuleObject, PropertyObject, etc. /// - internal static BorrowedReference GetTypeReference(Type type) - => new BorrowedReference(GetTypeHandle(type)); + internal static BorrowedReference GetTypeReference(Type type) => GetType(type).Reference; /// - /// Return value: Borrowed reference. - /// Get the handle of a Python type that reflects the given CLR type. + /// Get the 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(ClassBase obj, Type type) + internal static PyType GetType(ClassBase obj, Type type) { - IntPtr handle; - cache.TryGetValue(type, out handle); - if (handle != IntPtr.Zero) + if (!cache.TryGetValue(type, out var pyType)) { - return handle; + pyType = CreateType(obj, type); + cache[type] = pyType; + _slotsImpls.Add(type, obj.GetType()); } - handle = CreateType(obj, type); - cache[type] = handle; - _slotsImpls.Add(type, obj.GetType()); - return handle; + return pyType; } @@ -157,7 +140,7 @@ internal static IntPtr GetTypeHandle(ClassBase obj, Type type) /// behavior needed and the desire to have the existing Python runtime /// do as much of the allocation and initialization work as possible. /// - internal static unsafe IntPtr CreateType(Type impl) + internal static unsafe PyType CreateType(Type impl) { IntPtr type = AllocateTypeObject(impl.Name, metatype: Runtime.PyCLRMetaType); IntPtr base_ = impl == typeof(CLRModule) @@ -187,21 +170,27 @@ internal static unsafe IntPtr CreateType(Type impl) throw new PythonException(); } - var dict = new BorrowedReference(Marshal.ReadIntPtr(type, TypeOffset.tp_dict)); + // TODO: use PyType(TypeSpec) constructor + var pyType = new PyType(new BorrowedReference(type)); + Runtime.XDecref(type); + + NewReference dict = Runtime.PyObject_GenericGetDict(pyType.Reference); var mod = NewReference.DangerousFromPointer(Runtime.PyString_FromString("CLR")); Runtime.PyDict_SetItem(dict, PyIdentifier.__module__, mod); mod.Dispose(); - InitMethods(type, impl); + InitMethods(dict, impl); + + dict.Dispose(); // The type has been modified after PyType_Ready has been called // Refresh the type - Runtime.PyType_Modified(type); - return type; + Runtime.PyType_Modified(pyType.Reference); + return pyType; } - internal static IntPtr CreateType(ClassBase impl, Type clrType) + internal static PyType CreateType(ClassBase impl, Type clrType) { // Cleanup the type name to get rid of funny nested type names. string name = $"clr.{clrType.FullName}"; @@ -322,8 +311,9 @@ internal static IntPtr CreateType(ClassBase impl, Type clrType) impl.pyHandle = type; //DebugUtil.DumpType(type); - - return type; + var pyType = new PyType(new BorrowedReference(type)); + Runtime.XDecref(type); + return pyType; } static int InheritOrAllocateStandardFields(IntPtr type, IntPtr @base) @@ -351,9 +341,8 @@ void InheritOrAllocate(int typeField) return newFieldOffset; } - internal static IntPtr CreateSubType(IntPtr py_name, IntPtr py_base_type, IntPtr py_dict) + internal static IntPtr CreateSubType(IntPtr py_name, IntPtr py_base_type, BorrowedReference dictRef) { - var dictRef = new BorrowedReference(py_dict); // Utility to create a subtype of a managed type with the ability for the // a python subtype able to override the managed implementation string name = Runtime.GetManagedString(py_name); @@ -400,18 +389,18 @@ internal static IntPtr CreateSubType(IntPtr py_name, IntPtr py_base_type, IntPtr { Type subType = ClassDerivedObject.CreateDerivedType(name, baseClass.type.Value, - py_dict, + dictRef, (string)namespaceStr, (string)assembly); // create the new ManagedType and python type ClassBase subClass = ClassManager.GetClass(subType); - IntPtr py_type = GetTypeHandle(subClass, subType); + IntPtr py_type = GetType(subClass, subType).Handle; // by default the class dict will have all the C# methods in it, but as this is a // derived class we want the python overrides in there instead if they exist. var cls_dict = new BorrowedReference(Marshal.ReadIntPtr(py_type, TypeOffset.tp_dict)); - ThrowIfIsNotZero(Runtime.PyDict_Update(cls_dict, new BorrowedReference(py_dict))); + ThrowIfIsNotZero(Runtime.PyDict_Update(cls_dict, dictRef)); Runtime.XIncref(py_type); // Update the __classcell__ if it exists BorrowedReference cell = Runtime.PyDict_GetItemString(cls_dict, "__classcell__"); @@ -513,7 +502,7 @@ internal static IntPtr CreateMetaType(Type impl, out SlotsHolder slotsHolder) // The type has been modified after PyType_Ready has been called // Refresh the type - Runtime.PyType_Modified(type); + Runtime.PyType_Modified(new BorrowedReference(type)); //DebugUtil.DumpType(type); return type; @@ -576,7 +565,6 @@ private static IntPtr AddCustomMetaMethod(string name, IntPtr type, IntPtr mdef, return mdef; } - /// /// Utility method to allocate a type object & do basic initialization. /// @@ -599,6 +587,8 @@ internal static IntPtr AllocateTypeObject(string name, IntPtr metatype) Runtime.XIncref(temp); Marshal.WriteIntPtr(type, TypeOffset.qualname, temp); + + #warning dead code? temp = type + TypeOffset.nb_add; Marshal.WriteIntPtr(type, TypeOffset.tp_as_number, temp); @@ -610,6 +600,7 @@ internal static IntPtr AllocateTypeObject(string name, IntPtr metatype) temp = type + TypeOffset.bf_getbuffer; Marshal.WriteIntPtr(type, TypeOffset.tp_as_buffer, temp); + return type; } @@ -661,45 +652,24 @@ internal static void InitializeSlots(IntPtr type, Type impl, SlotsHolder slotsHo } } - /// - /// Helper for InitializeSlots. - /// - /// Initializes one slot to point to a function pointer. - /// The function pointer might be a thunk for C#, or it may be - /// an address in the NativeCodePage. - /// - /// Type being initialized. - /// Function pointer. - /// Name of the method. - /// Can override the slot when it existed - static void InitializeSlot(IntPtr type, IntPtr slot, string name, bool canOverride = true) + static void InitializeSlot(IntPtr type, ThunkInfo thunk, string name, SlotsHolder slotsHolder) { - var offset = TypeOffset.GetSlotOffset(name); - if (!canOverride && Marshal.ReadIntPtr(type, offset) != IntPtr.Zero) + if (!Enum.TryParse(name, out var id)) { - return; + throw new NotSupportedException("Bad slot name " + name); } - Marshal.WriteIntPtr(type, offset, slot); + int offset = TypeOffset.GetSlotOffset(name); + InitializeSlot(type, offset, thunk, slotsHolder); } - static void InitializeSlot(IntPtr type, ThunkInfo thunk, string name, SlotsHolder slotsHolder = null, bool canOverride = true) + static void InitializeSlot(IntPtr type, int slotOffset, MethodInfo method, SlotsHolder slotsHolder) { - int offset = TypeOffset.GetSlotOffset(name); - - if (!canOverride && Marshal.ReadIntPtr(type, offset) != IntPtr.Zero) - { - return; - } - Marshal.WriteIntPtr(type, offset, thunk.Address); - if (slotsHolder != null) - { - slotsHolder.Set(offset, thunk); - } + var thunk = Interop.GetThunk(method); + InitializeSlot(type, slotOffset, thunk, slotsHolder); } - static void InitializeSlot(IntPtr type, int slotOffset, MethodInfo method, SlotsHolder slotsHolder = null) + static void InitializeSlot(IntPtr type, int slotOffset, ThunkInfo thunk, SlotsHolder slotsHolder) { - var thunk = Interop.GetThunk(method); Marshal.WriteIntPtr(type, slotOffset, thunk.Address); if (slotsHolder != null) { @@ -707,20 +677,13 @@ static void InitializeSlot(IntPtr type, int slotOffset, MethodInfo method, Slots } } - static bool IsSlotSet(IntPtr type, string name) - { - int offset = TypeOffset.GetSlotOffset(name); - return Marshal.ReadIntPtr(type, offset) != IntPtr.Zero; - } - /// - /// Given a newly allocated Python type object and a managed Type that + /// Given a dict of 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) + private static void InitMethods(BorrowedReference typeDict, Type type) { - IntPtr dict = Marshal.ReadIntPtr(pytype, TypeOffset.tp_dict); Type marker = typeof(PythonMethodAttribute); BindingFlags flags = BindingFlags.Public | BindingFlags.Static; @@ -740,7 +703,7 @@ private static void InitMethods(IntPtr pytype, Type type) var mi = new MethodInfo[1]; mi[0] = method; MethodObject m = new TypeMethod(type, method_name, mi); - Runtime.PyDict_SetItemString(dict, method_name, m.pyHandle); + Runtime.PyDict_SetItemString(typeDict, method_name, m.ObjectReference); m.DecrRefCount(); addedMethods.Add(method_name); } pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy