diff --git a/src/embed_tests/TestPyType.cs b/src/embed_tests/TestPyType.cs
index 02142b782..f70a54c99 100644
--- a/src/embed_tests/TestPyType.cs
+++ b/src/embed_tests/TestPyType.cs
@@ -1,3 +1,4 @@
+using System.Runtime.InteropServices;
using System.Text;
using NUnit.Framework;
@@ -30,7 +31,7 @@ public void CanCreateHeapType()
using var doc = new StrPtr(docStr, Encoding.UTF8);
var spec = new TypeSpec(
name: name,
- basicSize: ObjectOffset.Size(Runtime.Runtime.PyTypeType),
+ basicSize: Marshal.ReadInt32(Runtime.Runtime.PyBaseObjectType, TypeOffset.tp_basicsize),
slots: new TypeSpec.Slot[] {
new (TypeSlotID.tp_doc, doc.RawPointer),
},
diff --git a/src/runtime/classbase.cs b/src/runtime/classbase.cs
index 8b96a96da..bf6a8034d 100644
--- a/src/runtime/classbase.cs
+++ b/src/runtime/classbase.cs
@@ -1,9 +1,6 @@
using System;
using System.Collections;
using System.Collections.Generic;
-using System.Diagnostics;
-using System.Runtime.InteropServices;
-using System.Runtime.Serialization;
namespace Python.Runtime
{
@@ -355,19 +352,21 @@ public static void tp_dealloc(IntPtr ob)
{
ManagedType self = GetManagedObject(ob);
tp_clear(ob);
- Runtime.PyObject_GC_UnTrack(self.pyHandle);
- Runtime.PyObject_GC_Del(self.pyHandle);
- self.FreeGCHandle();
+ Runtime.PyObject_GC_UnTrack(ob);
+ Runtime.PyObject_GC_Del(ob);
+ self?.FreeGCHandle();
}
public static int tp_clear(IntPtr ob)
{
ManagedType self = GetManagedObject(ob);
- if (!self.IsTypeObject())
+
+ bool isTypeObject = Runtime.PyObject_TYPE(ob) == Runtime.PyCLRMetaType;
+ if (!isTypeObject)
{
ClearObjectDict(ob);
}
- self.tpHandle = IntPtr.Zero;
+ if (self is not null) self.tpHandle = IntPtr.Zero;
return 0;
}
@@ -391,7 +390,7 @@ protected override void OnLoad(InterDomainContext context)
SetObjectDict(pyHandle, dict);
}
gcHandle = AllocGCHandle();
- Marshal.WriteIntPtr(pyHandle, TypeOffset.magic(), (IntPtr)gcHandle);
+ SetGCHandle(ObjectReference, gcHandle);
}
diff --git a/src/runtime/classderived.cs b/src/runtime/classderived.cs
index 4e8e88bf3..8b15213c3 100644
--- a/src/runtime/classderived.cs
+++ b/src/runtime/classderived.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
@@ -75,8 +76,8 @@ internal ClassDerivedObject(Type tp) : base(tp)
// 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);
- int gcOffset = ObjectOffset.magic(Runtime.PyObject_TYPE(self.pyHandle));
- Marshal.WriteIntPtr(self.pyHandle, gcOffset, (IntPtr)gc);
+ Debug.Assert(self.TypeReference == Runtime.PyObject_TYPE(self.ObjectReference));
+ SetGCHandle(self.ObjectReference, self.TypeReference, gc);
self.gcHandle.Free();
self.gcHandle = gc;
}
@@ -106,7 +107,7 @@ internal static IntPtr ToPython(IPythonDerivedType obj)
Runtime._Py_NewReference(self.pyHandle);
#endif
GCHandle gc = GCHandle.Alloc(self, GCHandleType.Normal);
- Marshal.WriteIntPtr(self.pyHandle, ObjectOffset.magic(self.tpHandle), (IntPtr)gc);
+ SetGCHandle(self.ObjectReference, self.TypeReference, gc);
self.gcHandle.Free();
self.gcHandle = gc;
@@ -883,11 +884,6 @@ public static void Finalize(IPythonDerivedType obj)
// 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.TypeDictOffset(self.tpHandle));
- if (dict != IntPtr.Zero)
- {
- Runtime.XDecref(dict);
- }
Runtime.PyObject_GC_Del(self.pyHandle);
self.gcHandle.Free();
}
diff --git a/src/runtime/clrobject.cs b/src/runtime/clrobject.cs
index 0aa829ee6..46cd896e2 100644
--- a/src/runtime/clrobject.cs
+++ b/src/runtime/clrobject.cs
@@ -14,26 +14,16 @@ internal CLRObject(object ob, IntPtr tp)
System.Diagnostics.Debug.Assert(tp != IntPtr.Zero);
IntPtr py = Runtime.PyType_GenericAlloc(tp, 0);
- var flags = (TypeFlags)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;
+ GCHandle gc = AllocGCHandle(TrackTypes.Wrapper);
+ InitGCHandle(ObjectReference, type: TypeReference, gc);
+
// Fix the BaseException args (and __cause__ in case of Python 3)
// slot if wrapping a CLR exception
- Exceptions.SetArgsAndCause(py);
+ if (ob is Exception e) Exceptions.SetArgsAndCause(e, py);
}
protected CLRObject()
@@ -78,6 +68,9 @@ internal static IntPtr GetInstHandle(object ob)
return co.pyHandle;
}
+ internal static NewReference GetReference(object ob)
+ => NewReference.DangerousFromPointer(GetInstHandle(ob));
+
internal static CLRObject Restore(object ob, IntPtr pyHandle, InterDomainContext context)
{
CLRObject co = new CLRObject()
@@ -101,7 +94,7 @@ protected override void OnLoad(InterDomainContext context)
{
base.OnLoad(context);
GCHandle gc = AllocGCHandle(TrackTypes.Wrapper);
- Marshal.WriteIntPtr(pyHandle, ObjectOffset.magic(tpHandle), (IntPtr)gc);
+ SetGCHandle(ObjectReference, TypeReference, gc);
}
}
}
diff --git a/src/runtime/converter.cs b/src/runtime/converter.cs
index 6b2e0f648..2e10e9041 100644
--- a/src/runtime/converter.cs
+++ b/src/runtime/converter.cs
@@ -580,7 +580,7 @@ private static bool ToPrimitive(IntPtr value, Type obType, out object result, bo
{
if (Runtime.PyBytes_Size(value) == 1)
{
- op = Runtime.PyBytes_AS_STRING(value);
+ op = Runtime.PyBytes_AsString(value);
result = (byte)Marshal.ReadByte(op);
return true;
}
@@ -606,7 +606,7 @@ private static bool ToPrimitive(IntPtr value, Type obType, out object result, bo
{
if (Runtime.PyBytes_Size(value) == 1)
{
- op = Runtime.PyBytes_AS_STRING(value);
+ op = Runtime.PyBytes_AsString(value);
result = (byte)Marshal.ReadByte(op);
return true;
}
@@ -632,7 +632,7 @@ private static bool ToPrimitive(IntPtr value, Type obType, out object result, bo
{
if (Runtime.PyBytes_Size(value) == 1)
{
- op = Runtime.PyBytes_AS_STRING(value);
+ op = Runtime.PyBytes_AsString(value);
result = (byte)Marshal.ReadByte(op);
return true;
}
diff --git a/src/runtime/exceptions.cs b/src/runtime/exceptions.cs
index 06d2d55b5..40e018fe6 100644
--- a/src/runtime/exceptions.cs
+++ b/src/runtime/exceptions.cs
@@ -156,15 +156,8 @@ internal static void Shutdown()
/// pointer.
///
/// The python object wrapping
- internal static void SetArgsAndCause(IntPtr ob)
+ internal static void SetArgsAndCause(Exception e, IntPtr ob)
{
- // e: A CLR Exception
- Exception e = ExceptionClassObject.ToException(ob);
- if (e == null)
- {
- return;
- }
-
IntPtr args;
if (!string.IsNullOrEmpty(e.Message))
{
@@ -177,13 +170,14 @@ internal static void SetArgsAndCause(IntPtr ob)
args = Runtime.PyTuple_New(0);
}
- Marshal.WriteIntPtr(ob, ExceptionOffset.args, args);
+ if (Runtime.PyObject_SetAttrString(ob, "args", args) != 0)
+ throw new PythonException();
if (e.InnerException != null)
{
// Note: For an AggregateException, InnerException is only the first of the InnerExceptions.
- IntPtr cause = CLRObject.GetInstHandle(e.InnerException);
- Marshal.WriteIntPtr(ob, ExceptionOffset.cause, cause);
+ using var cause = CLRObject.GetReference(e.InnerException);
+ Runtime.PyException_SetCause(ob, cause.DangerousMoveToPointer());
}
}
diff --git a/src/runtime/extensiontype.cs b/src/runtime/extensiontype.cs
index a5f0f1219..554837c46 100644
--- a/src/runtime/extensiontype.cs
+++ b/src/runtime/extensiontype.cs
@@ -33,13 +33,17 @@ public ExtensionType()
tpHandle = tp;
pyHandle = py;
+#if DEBUG
+ GetGCHandle(ObjectReference, TypeReference, out var existing);
+ System.Diagnostics.Debug.Assert(existing == IntPtr.Zero);
+#endif
SetupGc();
}
void SetupGc ()
{
GCHandle gc = AllocGCHandle(TrackTypes.Extension);
- Marshal.WriteIntPtr(pyHandle, ObjectOffset.magic(tpHandle), (IntPtr)gc);
+ InitGCHandle(ObjectReference, TypeReference, 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
diff --git a/src/runtime/importhook.cs b/src/runtime/importhook.cs
index 184b588ad..be2281c8f 100644
--- a/src/runtime/importhook.cs
+++ b/src/runtime/importhook.cs
@@ -15,26 +15,6 @@ internal static class ImportHook
private static IntPtr py_clr_module;
static BorrowedReference ClrModuleReference => new BorrowedReference(py_clr_module);
- private static IntPtr module_def = IntPtr.Zero;
-
- internal static void InitializeModuleDef()
- {
- if (module_def == IntPtr.Zero)
- {
- module_def = ModuleDefOffset.AllocModuleDef("clr");
- }
- }
-
- internal static void ReleaseModuleDef()
- {
- if (module_def == IntPtr.Zero)
- {
- return;
- }
- ModuleDefOffset.FreeModuleDef(module_def);
- module_def = IntPtr.Zero;
- }
-
///
/// Initialize just the __import__ hook itself.
///
@@ -90,8 +70,7 @@ internal static unsafe void Initialize()
root = new CLRModule();
// create a python module with the same methods as the clr module-like object
- InitializeModuleDef();
- py_clr_module = Runtime.PyModule_Create2(module_def, 3);
+ py_clr_module = Runtime.PyModule_New("clr").DangerousMoveToPointer();
// both dicts are borrowed references
BorrowedReference mod_dict = Runtime.PyModule_GetDict(ClrModuleReference);
@@ -116,13 +95,8 @@ internal static void Shutdown()
RestoreImport();
- bool shouldFreeDef = Runtime.Refcount(py_clr_module) == 1;
Runtime.XDecref(py_clr_module);
py_clr_module = IntPtr.Zero;
- if (shouldFreeDef)
- {
- ReleaseModuleDef();
- }
Runtime.XDecref(root.pyHandle);
root = null;
diff --git a/src/runtime/interop.cs b/src/runtime/interop.cs
index c5958e0f7..188db3a58 100644
--- a/src/runtime/interop.cs
+++ b/src/runtime/interop.cs
@@ -68,276 +68,6 @@ public ModulePropertyAttribute()
}
}
- internal static partial class TypeOffset
- {
- public static int magic() => ManagedDataOffsets.Magic;
- }
-
- internal static class ManagedDataOffsets
- {
- public static int Magic { get; internal set; }
- public static readonly Dictionary NameMapping = new Dictionary();
-
- static class DataOffsets
- {
- public static readonly int ob_data = 0;
- public static readonly int ob_dict = 0;
-
- static DataOffsets()
- {
- FieldInfo[] fields = typeof(DataOffsets).GetFields(BindingFlags.Static | BindingFlags.Public);
- for (int i = 0; i < fields.Length; i++)
- {
- fields[i].SetValue(null, -(i * IntPtr.Size) - IntPtr.Size);
- }
- }
- }
-
- static ManagedDataOffsets()
- {
- NameMapping = TypeOffset.GetOffsets();
-
- FieldInfo[] fields = typeof(DataOffsets).GetFields(BindingFlags.Static | BindingFlags.Public);
- size = fields.Length * IntPtr.Size;
- }
-
- public static int GetSlotOffset(string name)
- {
- return NameMapping[name];
- }
-
- private static int BaseOffset(IntPtr type)
- {
- Debug.Assert(type != IntPtr.Zero);
- int typeSize = Marshal.ReadInt32(type, TypeOffset.tp_basicsize);
- Debug.Assert(typeSize > 0);
- return typeSize;
- }
-
- public static int DataOffset(IntPtr type)
- {
- return BaseOffset(type) + DataOffsets.ob_data;
- }
-
- public static int DictOffset(IntPtr type)
- {
- return BaseOffset(type) + DataOffsets.ob_dict;
- }
-
- public static int ob_data => DataOffsets.ob_data;
- public static int ob_dict => DataOffsets.ob_dict;
- public static int Size { get { return size; } }
-
- private static readonly int size;
- }
-
- internal static class OriginalObjectOffsets
- {
- static OriginalObjectOffsets()
- {
- int size = IntPtr.Size;
- var n = 0; // Py_TRACE_REFS add two pointers to PyObject_HEAD
-#if PYTHON_WITH_PYDEBUG
- _ob_next = 0;
- _ob_prev = 1 * size;
- n = 2;
-#endif
- ob_refcnt = (n + 0) * size;
- ob_type = (n + 1) * size;
- }
-
- public static int Size { get { return size; } }
-
- private static readonly int size =
-#if PYTHON_WITH_PYDEBUG
- 4 * IntPtr.Size;
-#else
- 2 * IntPtr.Size;
-#endif
-
-#if PYTHON_WITH_PYDEBUG
- public static int _ob_next;
- public static int _ob_prev;
-#endif
- public static int ob_refcnt;
- public static int ob_type;
- }
-
- [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
- internal class ObjectOffset
- {
- static ObjectOffset()
- {
-#if PYTHON_WITH_PYDEBUG
- _ob_next = OriginalObjectOffsets._ob_next;
- _ob_prev = OriginalObjectOffsets._ob_prev;
-#endif
- ob_refcnt = OriginalObjectOffsets.ob_refcnt;
- ob_type = OriginalObjectOffsets.ob_type;
-
- size = OriginalObjectOffsets.Size + ManagedDataOffsets.Size;
- }
-
- public static int magic(IntPtr type)
- {
- return ManagedDataOffsets.DataOffset(type);
- }
-
- public static int TypeDictOffset(IntPtr type)
- {
- return ManagedDataOffsets.DictOffset(type);
- }
-
- public static int Size(IntPtr pyType)
- {
- if (IsException(pyType))
- {
- return ExceptionOffset.Size();
- }
-
- return size;
- }
-
-#if PYTHON_WITH_PYDEBUG
- public static int _ob_next;
- public static int _ob_prev;
-#endif
- public static int ob_refcnt;
- public static int ob_type;
- private static readonly int size;
-
- private static bool IsException(IntPtr pyObjectPtr)
- {
- var pyObject = new BorrowedReference(pyObjectPtr);
- var type = Runtime.PyObject_TYPE(pyObject);
- return Runtime.PyType_IsSameAsOrSubtype(type, ofType: Exceptions.BaseException)
- || Runtime.PyType_IsSameAsOrSubtype(type, ofType: Runtime.PyTypeType)
- && Runtime.PyType_IsSubtype(pyObject, Exceptions.BaseException);
- }
- }
-
- [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
- internal class ExceptionOffset
- {
- static ExceptionOffset()
- {
- Type type = typeof(ExceptionOffset);
- FieldInfo[] fi = type.GetFields(BindingFlags.Static | BindingFlags.Public);
- for (int i = 0; i < fi.Length; i++)
- {
- fi[i].SetValue(null, (i * IntPtr.Size) + OriginalObjectOffsets.Size);
- }
-
- size = fi.Length * IntPtr.Size + OriginalObjectOffsets.Size + ManagedDataOffsets.Size;
- }
-
- public static int Size() { return size; }
-
- // PyException_HEAD
- // (start after PyObject_HEAD)
- public static int dict = 0;
- public static int args = 0;
- public static int traceback = 0;
- public static int context = 0;
- public static int cause = 0;
- public static int suppress_context = 0;
-
- private static readonly int size;
- }
-
-
- [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
- internal class BytesOffset
- {
- static BytesOffset()
- {
- Type type = typeof(BytesOffset);
- FieldInfo[] fi = type.GetFields();
- int size = IntPtr.Size;
- for (int i = 0; i < fi.Length; i++)
- {
- fi[i].SetValue(null, i * size);
- }
- }
-
- /* The *real* layout of a type object when allocated on the heap */
- //typedef struct _heaptypeobject {
-#if PYTHON_WITH_PYDEBUG
-/* _PyObject_HEAD_EXTRA defines pointers to support a doubly-linked list of all live heap objects. */
- public static int _ob_next = 0;
- public static int _ob_prev = 0;
-#endif
- // PyObject_VAR_HEAD {
- // PyObject_HEAD {
- public static int ob_refcnt = 0;
- public static int ob_type = 0;
- // }
- public static int ob_size = 0; /* Number of items in _VAR_iable part */
- // }
- public static int ob_shash = 0;
- public static int ob_sval = 0; /* start of data */
-
- /* Invariants:
- * ob_sval contains space for 'ob_size+1' elements.
- * ob_sval[ob_size] == 0.
- * ob_shash is the hash of the string or -1 if not computed yet.
- */
- //} PyBytesObject;
- }
-
- [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
- internal class ModuleDefOffset
- {
- static ModuleDefOffset()
- {
- Type type = typeof(ModuleDefOffset);
- FieldInfo[] fi = type.GetFields();
- int size = IntPtr.Size;
- for (int i = 0; i < fi.Length; i++)
- {
- fi[i].SetValue(null, (i * size) + TypeOffset.ob_size);
- }
- }
-
- public static IntPtr AllocModuleDef(string modulename)
- {
- byte[] ascii = Encoding.ASCII.GetBytes(modulename);
- int size = name + ascii.Length + 1;
- IntPtr ptr = Marshal.AllocHGlobal(size);
- for (int i = 0; i <= m_free; i += IntPtr.Size)
- Marshal.WriteIntPtr(ptr, i, IntPtr.Zero);
- Marshal.Copy(ascii, 0, (IntPtr)(ptr + name), ascii.Length);
- Marshal.WriteIntPtr(ptr, m_name, (IntPtr)(ptr + name));
- Marshal.WriteByte(ptr, name + ascii.Length, 0);
- return ptr;
- }
-
- public static void FreeModuleDef(IntPtr ptr)
- {
- Marshal.FreeHGlobal(ptr);
- }
-
- // typedef struct PyModuleDef{
- // typedef struct PyModuleDef_Base {
- // starts after PyObject_HEAD (TypeOffset.ob_type + 1)
- public static int m_init = 0;
- public static int m_index = 0;
- public static int m_copy = 0;
- // } PyModuleDef_Base
- public static int m_name = 0;
- public static int m_doc = 0;
- public static int m_size = 0;
- public static int m_methods = 0;
- public static int m_reload = 0;
- public static int m_traverse = 0;
- public static int m_clear = 0;
- public static int m_free = 0;
- // } PyModuleDef
-
- public static int name = 0;
- }
-
-
///
/// TypeFlags(): The actual bit values for the Type Flags stored
/// in a class.
@@ -357,7 +87,7 @@ public enum TypeFlags: int
HaveStacklessExtension = 0,
/* XXX Reusing reserved constants */
/// PythonNet specific
- Managed = (1 << 15),
+ HasClrInstance = (1 << 15),
/// PythonNet specific
Subclass = (1 << 16),
HaveIndex = (1 << 17),
diff --git a/src/runtime/managedtype.cs b/src/runtime/managedtype.cs
index d3ee697fd..41408abc7 100644
--- a/src/runtime/managedtype.cs
+++ b/src/runtime/managedtype.cs
@@ -28,6 +28,7 @@ internal enum TrackTypes
internal IntPtr tpHandle; // PyType *
internal BorrowedReference ObjectReference => new BorrowedReference(pyHandle);
+ internal BorrowedReference TypeReference => new BorrowedReference(tpHandle);
private static readonly Dictionary _managedObjs = new Dictionary();
@@ -93,17 +94,10 @@ internal static ManagedType GetManagedObject(IntPtr ob)
}
var flags = (TypeFlags)Util.ReadCLong(tp, TypeOffset.tp_flags);
- if ((flags & TypeFlags.Managed) != 0)
+ if ((flags & TypeFlags.HasClrInstance) != 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;
+ var gc = TryGetGCHandle(new BorrowedReference(ob));
+ return (ManagedType)gc?.Target;
}
}
return null;
@@ -118,10 +112,9 @@ internal static ManagedType GetManagedObjectType(IntPtr ob)
{
IntPtr tp = Runtime.PyObject_TYPE(ob);
var flags = (TypeFlags)Util.ReadCLong(tp, TypeOffset.tp_flags);
- if ((flags & TypeFlags.Managed) != 0)
+ if ((flags & TypeFlags.HasClrInstance) != 0)
{
- tp = Marshal.ReadIntPtr(tp, TypeOffset.magic());
- var gc = (GCHandle)tp;
+ var gc = GetGCHandle(new BorrowedReference(tp), Runtime.CLRMetaType);
return (ManagedType)gc.Target;
}
}
@@ -140,9 +133,9 @@ internal static ManagedType GetManagedObjectErr(IntPtr ob)
}
- internal static bool IsManagedType(BorrowedReference ob)
- => IsManagedType(ob.DangerousGetAddressOrNull());
- internal static bool IsManagedType(IntPtr ob)
+ internal static bool IsInstanceOfManagedType(BorrowedReference ob)
+ => IsInstanceOfManagedType(ob.DangerousGetAddressOrNull());
+ internal static bool IsInstanceOfManagedType(IntPtr ob)
{
if (ob != IntPtr.Zero)
{
@@ -152,18 +145,15 @@ internal static bool IsManagedType(IntPtr ob)
tp = ob;
}
- var flags = (TypeFlags)Util.ReadCLong(tp, TypeOffset.tp_flags);
- if ((flags & TypeFlags.Managed) != 0)
- {
- return true;
- }
+ return IsManagedType(new BorrowedReference(tp));
}
return false;
}
- public bool IsTypeObject()
+ internal static bool IsManagedType(BorrowedReference type)
{
- return pyHandle == tpHandle;
+ var flags = (TypeFlags)Util.ReadCLong(type.DangerousGetAddress(), TypeOffset.tp_flags);
+ return (flags & TypeFlags.HasClrInstance) != 0;
}
internal static IDictionary GetManagedObjects()
@@ -256,13 +246,81 @@ protected static void ClearObjectDict(IntPtr ob)
protected static IntPtr GetObjectDict(IntPtr ob)
{
IntPtr type = Runtime.PyObject_TYPE(ob);
- return Marshal.ReadIntPtr(ob, ObjectOffset.TypeDictOffset(type));
+ int instanceDictOffset = Marshal.ReadInt32(type, TypeOffset.tp_dictoffset);
+ Debug.Assert(instanceDictOffset > 0);
+ return Marshal.ReadIntPtr(ob, instanceDictOffset);
}
protected static void SetObjectDict(IntPtr ob, IntPtr value)
{
IntPtr type = Runtime.PyObject_TYPE(ob);
- Marshal.WriteIntPtr(ob, ObjectOffset.TypeDictOffset(type), value);
+ int instanceDictOffset = Marshal.ReadInt32(type, TypeOffset.tp_dictoffset);
+ Debug.Assert(instanceDictOffset > 0);
+ Marshal.WriteIntPtr(ob, instanceDictOffset, value);
+ }
+
+ internal static void GetGCHandle(BorrowedReference reflectedClrObject, BorrowedReference type, out IntPtr handle)
+ {
+ Debug.Assert(reflectedClrObject != null);
+ Debug.Assert(IsManagedType(type) || type == Runtime.CLRMetaType);
+ Debug.Assert(Runtime.PyObject_TypeCheck(reflectedClrObject, type));
+
+ int gcHandleOffset = Marshal.ReadInt32(type.DangerousGetAddress(), Offsets.tp_clr_inst_offset);
+ Debug.Assert(gcHandleOffset > 0);
+
+ handle = Marshal.ReadIntPtr(reflectedClrObject.DangerousGetAddress(), gcHandleOffset);
+ }
+
+ internal static GCHandle? TryGetGCHandle(BorrowedReference reflectedClrObject, BorrowedReference type)
+ {
+ GetGCHandle(reflectedClrObject, type, out IntPtr handle);
+ return handle == IntPtr.Zero ? null : (GCHandle)handle;
+ }
+ internal static GCHandle? TryGetGCHandle(BorrowedReference reflectedClrObject)
+ {
+ BorrowedReference reflectedType = Runtime.PyObject_TYPE(reflectedClrObject);
+
+ return TryGetGCHandle(reflectedClrObject, reflectedType);
+ }
+
+ internal static GCHandle GetGCHandle(BorrowedReference reflectedClrObject)
+ => TryGetGCHandle(reflectedClrObject) ?? throw new InvalidOperationException();
+ internal static GCHandle GetGCHandle(BorrowedReference reflectedClrObject, BorrowedReference type)
+ => TryGetGCHandle(reflectedClrObject, type) ?? throw new InvalidOperationException();
+
+ internal static void InitGCHandle(BorrowedReference reflectedClrObject, BorrowedReference type, GCHandle handle)
+ {
+ Debug.Assert(TryGetGCHandle(reflectedClrObject) == null);
+
+ SetGCHandle(reflectedClrObject, type: type, handle);
+ }
+ internal static void InitGCHandle(BorrowedReference reflectedClrObject, GCHandle handle)
+ => InitGCHandle(reflectedClrObject, Runtime.PyObject_TYPE(reflectedClrObject), handle);
+
+ internal static void SetGCHandle(BorrowedReference reflectedClrObject, BorrowedReference type, GCHandle newHandle)
+ {
+ Debug.Assert(Runtime.PyObject_TypeCheck(reflectedClrObject, type));
+
+ int offset = Marshal.ReadInt32(type.DangerousGetAddress(), Offsets.tp_clr_inst_offset);
+ Debug.Assert(offset > 0);
+
+ Marshal.WriteIntPtr(reflectedClrObject.DangerousGetAddress(), offset, (IntPtr)newHandle);
+ }
+ internal static void SetGCHandle(BorrowedReference reflectedClrObject, GCHandle newHandle)
+ => SetGCHandle(reflectedClrObject, Runtime.PyObject_TYPE(reflectedClrObject), newHandle);
+
+ internal static class Offsets
+ {
+ static Offsets()
+ {
+ int pyTypeSize = Marshal.ReadInt32(Runtime.PyTypeType, TypeOffset.tp_basicsize);
+ if (pyTypeSize < 0) throw new InvalidOperationException();
+
+ tp_clr_inst_offset = pyTypeSize;
+ tp_clr_inst = tp_clr_inst_offset + IntPtr.Size;
+ }
+ public static int tp_clr_inst_offset { get; }
+ public static int tp_clr_inst { get; }
}
}
}
diff --git a/src/runtime/metatype.cs b/src/runtime/metatype.cs
index 68dae2508..1fde7dd78 100644
--- a/src/runtime/metatype.cs
+++ b/src/runtime/metatype.cs
@@ -1,6 +1,4 @@
using System;
-using System.Collections;
-using System.IO;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
@@ -148,7 +146,7 @@ public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw)
}
var flags = TypeFlags.Default;
- flags |= TypeFlags.Managed;
+ flags |= TypeFlags.HasClrInstance;
flags |= TypeFlags.HeapType;
flags |= TypeFlags.BaseType;
flags |= TypeFlags.Subclass;
@@ -164,10 +162,16 @@ public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw)
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, TypeOffset.magic());
- Marshal.WriteIntPtr(type, TypeOffset.magic(), gc);
+ IntPtr gc = Marshal.ReadIntPtr(base_type, Offsets.tp_clr_inst);
+ Marshal.WriteIntPtr(type, Offsets.tp_clr_inst, gc);
+
+ if (Runtime.PyType_Ready(type) != 0)
+ throw new PythonException();
return type;
}
@@ -205,6 +209,11 @@ public static IntPtr tp_call(IntPtr tp, IntPtr args, IntPtr kw)
return IntPtr.Zero;
}
+ return CallInit(obj, args, kw);
+ }
+
+ private static IntPtr CallInit(IntPtr obj, IntPtr args, IntPtr kw)
+ {
var init = Runtime.PyObject_GetAttr(obj, PyIdentifier.__init__);
Runtime.PyErr_Clear();
@@ -288,8 +297,12 @@ public static void tp_dealloc(IntPtr tp)
var flags = (TypeFlags)Util.ReadCLong(tp, TypeOffset.tp_flags);
if ((flags & TypeFlags.Subclass) == 0)
{
- IntPtr gc = Marshal.ReadIntPtr(tp, TypeOffset.magic());
- ((GCHandle)gc).Free();
+ 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);
diff --git a/src/runtime/moduleobject.cs b/src/runtime/moduleobject.cs
index 41167e322..3c4e02a23 100644
--- a/src/runtime/moduleobject.cs
+++ b/src/runtime/moduleobject.cs
@@ -44,7 +44,10 @@ public ModuleObject(string name)
docstring += "- " + a.FullName + "\n";
}
- dict = Runtime.PyDict_New();
+ var dictRef = Runtime.PyObject_GenericGetDict(ObjectReference);
+ PythonException.ThrowIfIsNull(dictRef);
+ dict = dictRef.DangerousMoveToPointer();
+
using var pyname = NewReference.DangerousFromPointer(Runtime.PyString_FromString(moduleName));
using var pyfilename = NewReference.DangerousFromPointer(Runtime.PyString_FromString(filename));
using var pydocstring = NewReference.DangerousFromPointer(Runtime.PyString_FromString(docstring));
@@ -54,9 +57,6 @@ public ModuleObject(string name)
Runtime.PyDict_SetItem(DictRef, PyIdentifier.__doc__, pydocstring);
Runtime.PyDict_SetItem(DictRef, PyIdentifier.__class__, pycls);
- Runtime.XIncref(dict);
- SetObjectDict(pyHandle, dict);
-
InitializeModuleMembers();
}
diff --git a/src/runtime/native/ABI.cs b/src/runtime/native/ABI.cs
index 3264531de..339919dee 100644
--- a/src/runtime/native/ABI.cs
+++ b/src/runtime/native/ABI.cs
@@ -4,7 +4,6 @@ namespace Python.Runtime.Native
using System.Globalization;
using System.Linq;
using System.Reflection;
- using System.Runtime.InteropServices;
static class ABI
{
@@ -29,8 +28,6 @@ internal static void Initialize(Version version, BorrowedReference pyType)
}
var typeOffsets = (ITypeOffsets)Activator.CreateInstance(typeOffsetsClass);
TypeOffset.Use(typeOffsets);
-
- ManagedDataOffsets.Magic = Marshal.ReadInt32(pyType.DangerousGetAddress(), TypeOffset.tp_basicsize);
}
}
}
diff --git a/src/runtime/native/ITypeOffsets.cs b/src/runtime/native/ITypeOffsets.cs
index 485c041f8..0829e5bc9 100644
--- a/src/runtime/native/ITypeOffsets.cs
+++ b/src/runtime/native/ITypeOffsets.cs
@@ -63,6 +63,7 @@ interface ITypeOffsets
int tp_new { get; }
int tp_repr { get; }
int tp_richcompare { get; }
+ int tp_weaklistoffset { get; }
int tp_setattro { get; }
int tp_str { get; }
int tp_traverse { get; }
diff --git a/src/runtime/native/TypeOffset.cs b/src/runtime/native/TypeOffset.cs
index 9f5ed671b..edbbe3b2c 100644
--- a/src/runtime/native/TypeOffset.cs
+++ b/src/runtime/native/TypeOffset.cs
@@ -70,6 +70,7 @@ static partial class TypeOffset
internal static int tp_new { get; private set; }
internal static int tp_repr { get; private set; }
internal static int tp_richcompare { get; private set; }
+ internal static int tp_weaklistoffset { get; private set; }
internal static int tp_setattro { get; private set; }
internal static int tp_str { get; private set; }
internal static int tp_traverse { get; private set; }
@@ -91,9 +92,13 @@ internal static void Use(ITypeOffsets offsets)
ValidateUnusedTypeOffsetProperties(offsetProperties);
ValidateRequiredOffsetsPresent(offsetProperties);
+
+ SlotOffsets = GetOffsets();
}
static readonly BindingFlags FieldFlags = BindingFlags.NonPublic | BindingFlags.Static;
+
+ static Dictionary SlotOffsets;
internal static Dictionary GetOffsets()
{
var properties = typeof(TypeOffset).GetProperties(FieldFlags);
@@ -104,10 +109,9 @@ internal static Dictionary GetOffsets()
return result;
}
- internal static int GetOffsetUncached(string name)
+ public static int GetSlotOffset(string slotName)
{
- var property = typeof(TypeOffset).GetProperty(name, FieldFlags);
- return (int)property.GetValue(obj: null, index: null);
+ return SlotOffsets[slotName];
}
static readonly HashSet slotNames = new HashSet();
diff --git a/src/runtime/runtime.cs b/src/runtime/runtime.cs
index 4a8d01dd8..1b1a7eccc 100644
--- a/src/runtime/runtime.cs
+++ b/src/runtime/runtime.cs
@@ -470,7 +470,7 @@ private static void ClearClrModules()
var item = PyList_GetItem(items, i);
var name = PyTuple_GetItem(item, 0);
var module = PyTuple_GetItem(item, 1);
- if (ManagedType.IsManagedType(module))
+ if (ManagedType.IsInstanceOfManagedType(module))
{
PyDict_DelItem(modules, name);
}
@@ -523,6 +523,7 @@ private static void MoveClrInstancesOnwershipToPython()
if (obj.gcHandle.IsAllocated)
{
obj.gcHandle.Free();
+ ManagedType.SetGCHandle(obj.ObjectReference, default);
}
obj.gcHandle = default;
}
@@ -568,6 +569,8 @@ private static void MoveClrInstancesOnwershipToPython()
internal static IntPtr PyNone;
internal static IntPtr Error;
+ internal static BorrowedReference CLRMetaType => new BorrowedReference(PyCLRMetaType);
+
public static PyObject None
{
get
@@ -1000,7 +1003,7 @@ internal static IntPtr PyObject_Type(IntPtr op)
internal static string PyObject_GetTypeName(IntPtr op)
{
- IntPtr pyType = Marshal.ReadIntPtr(op, ObjectOffset.ob_type);
+ IntPtr pyType = PyObject_TYPE(op);
IntPtr ppName = Marshal.ReadIntPtr(pyType, TypeOffset.tp_name);
return Marshal.PtrToStringAnsi(ppName);
}
@@ -1010,7 +1013,7 @@ internal static string PyObject_GetTypeName(IntPtr op)
///
internal static bool PyObject_IsIterable(IntPtr pointer)
{
- var ob_type = Marshal.ReadIntPtr(pointer, ObjectOffset.ob_type);
+ var ob_type = PyObject_TYPE(pointer);
IntPtr tp_iter = Marshal.ReadIntPtr(ob_type, TypeOffset.tp_iter);
return tp_iter != IntPtr.Zero;
}
@@ -1508,6 +1511,13 @@ internal static IntPtr EmptyPyBytes()
return Delegates.PyBytes_FromString((IntPtr)bytes);
}
+ internal static IntPtr PyBytes_AsString(IntPtr ob) => PyBytes_AsString(new BorrowedReference(ob));
+ internal static IntPtr PyBytes_AsString(BorrowedReference ob)
+ {
+ Debug.Assert(ob != null);
+ return Delegates.PyBytes_AsString(ob);
+ }
+
internal static long PyBytes_Size(IntPtr op)
{
return (long)_PyBytes_Size(op);
@@ -1516,11 +1526,6 @@ internal static long PyBytes_Size(IntPtr op)
private static IntPtr _PyBytes_Size(IntPtr op) => Delegates._PyBytes_Size(op);
- internal static IntPtr PyBytes_AS_STRING(IntPtr ob)
- {
- return ob + BytesOffset.ob_sval;
- }
-
internal static IntPtr PyUnicode_FromStringAndSize(IntPtr value, long size)
{
@@ -1615,7 +1620,7 @@ internal static string GetManagedString(IntPtr op)
{
using var p = PyUnicode_AsUTF16String(new BorrowedReference(op));
int length = (int)PyUnicode_GetSize(op);
- char* codePoints = (char*)PyBytes_AS_STRING(p.DangerousGetAddress());
+ char* codePoints = (char*)PyBytes_AsString(p.DangerousGetAddress());
return new string(codePoints,
startIndex: 1, // skip BOM
length: length);
@@ -1876,7 +1881,7 @@ internal static IntPtr PyTuple_GetSlice(IntPtr pointer, long start, long end)
internal static bool PyIter_Check(IntPtr pointer)
{
- var ob_type = Marshal.ReadIntPtr(pointer, ObjectOffset.ob_type);
+ var ob_type = PyObject_TYPE(pointer);
IntPtr tp_iternext = Marshal.ReadIntPtr(ob_type, TypeOffset.tp_iternext);
return tp_iternext != IntPtr.Zero && tp_iternext != _PyObject_NextNotImplemented;
}
@@ -2248,7 +2253,7 @@ internal static IntPtr GetBuiltins()
return PyImport_Import(PyIdentifier.builtins);
}
- private static class Delegates
+ internal static class Delegates
{
static readonly ILibraryLoader libraryLoader = LibraryLoader.Instance;
@@ -2406,6 +2411,7 @@ static Delegates()
_PySequence_Count = (delegate* unmanaged[Cdecl])GetFunctionByName("PySequence_Count", GetUnmanagedDll(_PythonDll));
PySequence_Tuple = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PySequence_Tuple), GetUnmanagedDll(_PythonDll));
PySequence_List = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PySequence_List), GetUnmanagedDll(_PythonDll));
+ PyBytes_AsString = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyBytes_AsString), GetUnmanagedDll(_PythonDll));
PyBytes_FromString = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyBytes_FromString), GetUnmanagedDll(_PythonDll));
_PyBytes_Size = (delegate* unmanaged[Cdecl])GetFunctionByName("PyBytes_Size", GetUnmanagedDll(_PythonDll));
PyUnicode_FromStringAndSize = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyUnicode_FromStringAndSize), GetUnmanagedDll(_PythonDll));
@@ -2683,6 +2689,7 @@ static Delegates()
internal static delegate* unmanaged[Cdecl] _PySequence_Count { get; }
internal static delegate* unmanaged[Cdecl] PySequence_Tuple { get; }
internal static delegate* unmanaged[Cdecl] PySequence_List { get; }
+ internal static delegate* unmanaged[Cdecl] PyBytes_AsString { get; }
internal static delegate* unmanaged[Cdecl] PyBytes_FromString { get; }
internal static delegate* unmanaged[Cdecl] _PyBytes_Size { get; }
internal static delegate* unmanaged[Cdecl] PyUnicode_FromStringAndSize { get; }
diff --git a/src/runtime/runtime_data.cs b/src/runtime/runtime_data.cs
index 0b3bf3017..29cea4181 100644
--- a/src/runtime/runtime_data.cs
+++ b/src/runtime/runtime_data.cs
@@ -279,7 +279,7 @@ private static void SaveRuntimeDataModules(RuntimeDataStorage storage)
var item = PyList_GetItem(items, i);
var name = PyTuple_GetItem(item.DangerousGetAddress(), 0);
var module = PyTuple_GetItem(item.DangerousGetAddress(), 1);
- if (ManagedType.IsManagedType(module))
+ if (ManagedType.IsInstanceOfManagedType(module))
{
XIncref(name);
XIncref(module);
diff --git a/src/runtime/typemanager.cs b/src/runtime/typemanager.cs
index 01aceb656..20b95d85c 100644
--- a/src/runtime/typemanager.cs
+++ b/src/runtime/typemanager.cs
@@ -134,7 +134,7 @@ internal static BorrowedReference GetTypeReference(Type 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 type)
+ internal static IntPtr GetTypeHandle(ClassBase obj, Type type)
{
IntPtr handle;
cache.TryGetValue(type, out handle);
@@ -157,21 +157,28 @@ internal static IntPtr GetTypeHandle(ManagedType 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 IntPtr CreateType(Type impl)
+ internal static unsafe IntPtr CreateType(Type impl)
{
- IntPtr type = AllocateTypeObject(impl.Name, metatype: Runtime.PyTypeType);
- int ob_size = ObjectOffset.Size(type);
+ IntPtr type = AllocateTypeObject(impl.Name, metatype: Runtime.PyCLRMetaType);
+ IntPtr base_ = impl == typeof(CLRModule)
+ ? Runtime.PyModuleType
+ : Runtime.PyBaseObjectType;
+ int newFieldOffset = InheritOrAllocateStandardFields(type, base_);
+
+ int tp_clr_inst_offset = newFieldOffset;
+ newFieldOffset += IntPtr.Size;
+
+ int ob_size = newFieldOffset;
// Set tp_basicsize to the size of our managed instance objects.
Marshal.WriteIntPtr(type, TypeOffset.tp_basicsize, (IntPtr)ob_size);
-
- var offset = (IntPtr)ObjectOffset.TypeDictOffset(type);
- Marshal.WriteIntPtr(type, TypeOffset.tp_dictoffset, offset);
+ Marshal.WriteInt32(type, ManagedType.Offsets.tp_clr_inst_offset, tp_clr_inst_offset);
+ Marshal.WriteIntPtr(type, TypeOffset.tp_new, (IntPtr)Runtime.Delegates.PyType_GenericNew);
SlotsHolder slotsHolder = CreateSolotsHolder(type);
InitializeSlots(type, impl, slotsHolder);
- var flags = TypeFlags.Default | TypeFlags.Managed |
+ var flags = TypeFlags.Default | TypeFlags.HasClrInstance |
TypeFlags.HeapType | TypeFlags.HaveGC;
Util.WriteCLong(type, TypeOffset.tp_flags, (int)flags);
@@ -194,7 +201,7 @@ internal static IntPtr CreateType(Type impl)
}
- internal static IntPtr CreateType(ManagedType impl, Type clrType)
+ internal static IntPtr CreateType(ClassBase impl, Type clrType)
{
// Cleanup the type name to get rid of funny nested type names.
string name = $"clr.{clrType.FullName}";
@@ -209,19 +216,7 @@ internal static IntPtr CreateType(ManagedType impl, Type clrType)
name = name.Substring(i + 1);
}
- IntPtr base_ = IntPtr.Zero;
- int ob_size = ObjectOffset.Size(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);
- }
-
- int tp_dictoffset = ob_size + ManagedDataOffsets.ob_dict;
-
+ IntPtr base_ = Runtime.PyBaseObjectType;
if (clrType == typeof(Exception))
{
base_ = Exceptions.Exception;
@@ -229,17 +224,32 @@ internal static IntPtr CreateType(ManagedType impl, Type clrType)
else if (clrType.BaseType != null)
{
ClassBase bc = ClassManager.GetClass(clrType.BaseType);
- base_ = bc.pyHandle;
+ if (bc.ObjectReference != null)
+ {
+ // there are cases when base class has not been fully initialized yet (nested types)
+ base_ = bc.pyHandle;
+ }
}
IntPtr type = AllocateTypeObject(name, Runtime.PyCLRMetaType);
- Marshal.WriteIntPtr(type, TypeOffset.ob_type, Runtime.PyCLRMetaType);
- Runtime.XIncref(Runtime.PyCLRMetaType);
+ int newFieldOffset = InheritOrAllocateStandardFields(type, base_);
+
+ if (ManagedType.IsManagedType(new BorrowedReference(base_)))
+ {
+ int baseClrInstOffset = Marshal.ReadInt32(base_, ManagedType.Offsets.tp_clr_inst_offset);
+ Marshal.WriteInt32(type, ManagedType.Offsets.tp_clr_inst_offset, baseClrInstOffset);
+ }
+ else
+ {
+ Marshal.WriteInt32(type, ManagedType.Offsets.tp_clr_inst_offset, newFieldOffset);
+ newFieldOffset += IntPtr.Size;
+ }
+
+ int ob_size = newFieldOffset;
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);
// we want to do this after the slot stuff above in case the class itself implements a slot method
SlotsHolder slotsHolder = CreateSolotsHolder(type);
@@ -260,24 +270,16 @@ internal static IntPtr CreateType(ManagedType impl, Type clrType)
// Only set mp_subscript and mp_ass_subscript for types with indexers
- if (impl is ClassBase cb)
+ if (!(impl is ArrayObject))
{
- if (!(impl is ArrayObject))
+ if (impl.indexer == null || !impl.indexer.CanGet)
{
- if (cb.indexer == null || !cb.indexer.CanGet)
- {
- Marshal.WriteIntPtr(type, TypeOffset.mp_subscript, IntPtr.Zero);
- }
- if (cb.indexer == null || !cb.indexer.CanSet)
- {
- Marshal.WriteIntPtr(type, TypeOffset.mp_ass_subscript, IntPtr.Zero);
- }
+ Marshal.WriteIntPtr(type, TypeOffset.mp_subscript, IntPtr.Zero);
+ }
+ if (impl.indexer == null || !impl.indexer.CanSet)
+ {
+ Marshal.WriteIntPtr(type, TypeOffset.mp_ass_subscript, IntPtr.Zero);
}
- }
- else
- {
- Marshal.WriteIntPtr(type, TypeOffset.mp_subscript, IntPtr.Zero);
- Marshal.WriteIntPtr(type, TypeOffset.mp_ass_subscript, IntPtr.Zero);
}
if (base_ != IntPtr.Zero)
@@ -287,7 +289,7 @@ internal static IntPtr CreateType(ManagedType impl, Type clrType)
}
const TypeFlags flags = TypeFlags.Default
- | TypeFlags.Managed
+ | TypeFlags.HasClrInstance
| TypeFlags.HeapType
| TypeFlags.BaseType
| TypeFlags.HaveGC;
@@ -309,9 +311,11 @@ internal static IntPtr CreateType(ManagedType impl, Type clrType)
Runtime.PyDict_SetItem(dict, PyIdentifier.__module__, mod);
mod.Dispose();
+ var typeRef = new BorrowedReference(type);
+
// Hide the gchandle of the implementation in a magic type slot.
GCHandle gc = impl.AllocGCHandle();
- Marshal.WriteIntPtr(type, TypeOffset.magic(), (IntPtr)gc);
+ ManagedType.InitGCHandle(typeRef, Runtime.CLRMetaType, gc);
// Set the handle attributes on the implementing instance.
impl.tpHandle = type;
@@ -322,6 +326,31 @@ internal static IntPtr CreateType(ManagedType impl, Type clrType)
return type;
}
+ static int InheritOrAllocateStandardFields(IntPtr type, IntPtr @base)
+ {
+ int baseSize = Marshal.ReadInt32(@base, TypeOffset.tp_basicsize);
+ int newFieldOffset = baseSize;
+
+ void InheritOrAllocate(int typeField)
+ {
+ int value = Marshal.ReadInt32(@base, typeField);
+ if (value == 0)
+ {
+ Marshal.WriteIntPtr(type, typeField, new IntPtr(newFieldOffset));
+ newFieldOffset += IntPtr.Size;
+ }
+ else
+ {
+ Marshal.WriteIntPtr(type, typeField, new IntPtr(value));
+ }
+ }
+
+ InheritOrAllocate(TypeOffset.tp_dictoffset);
+ InheritOrAllocate(TypeOffset.tp_weaklistoffset);
+
+ return newFieldOffset;
+ }
+
internal static IntPtr CreateSubType(IntPtr py_name, IntPtr py_base_type, IntPtr py_dict)
{
var dictRef = new BorrowedReference(py_dict);
@@ -454,11 +483,14 @@ internal static IntPtr CreateMetaType(Type impl, out SlotsHolder slotsHolder)
Marshal.WriteIntPtr(type, TypeOffset.tp_base, py_type);
Runtime.XIncref(py_type);
- int size = TypeOffset.magic() + IntPtr.Size;
+ int size = Marshal.ReadInt32(Runtime.PyTypeType, TypeOffset.tp_basicsize)
+ + IntPtr.Size // tp_clr_inst_offset
+ + IntPtr.Size // tp_clr_inst
+ ;
Marshal.WriteIntPtr(type, TypeOffset.tp_basicsize, new IntPtr(size));
+ Marshal.WriteInt32(type, ManagedType.Offsets.tp_clr_inst_offset, ManagedType.Offsets.tp_clr_inst);
const TypeFlags flags = TypeFlags.Default
- | TypeFlags.Managed
| TypeFlags.HeapType
| TypeFlags.HaveGC;
Util.WriteCLong(type, TypeOffset.tp_flags, (int)flags);
@@ -544,53 +576,6 @@ private static IntPtr AddCustomMetaMethod(string name, IntPtr type, IntPtr mdef,
return mdef;
}
- internal static IntPtr BasicSubType(string name, IntPtr base_, Type impl)
- {
- // Utility to create a subtype of a std Python type, but with
- // a managed type able to override implementation
-
- IntPtr type = AllocateTypeObject(name, metatype: Runtime.PyTypeType);
- //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);
-
- //IntPtr dc = Runtime.PyDict_Copy(dict);
- //Marshal.WriteIntPtr(type, TypeOffset.tp_dict, dc);
-
- Marshal.WriteIntPtr(type, TypeOffset.tp_base, base_);
- Runtime.XIncref(base_);
-
- var flags = TypeFlags.Default;
- flags |= TypeFlags.Managed;
- flags |= TypeFlags.HeapType;
- flags |= TypeFlags.HaveGC;
- Util.WriteCLong(type, TypeOffset.tp_flags, (int)flags);
-
- CopySlot(base_, type, TypeOffset.tp_traverse);
- CopySlot(base_, type, TypeOffset.tp_clear);
- CopySlot(base_, type, TypeOffset.tp_is_gc);
-
- SlotsHolder slotsHolder = CreateSolotsHolder(type);
- InitializeSlots(type, impl, slotsHolder);
-
- if (Runtime.PyType_Ready(type) != 0)
- {
- throw new PythonException();
- }
-
- IntPtr tp_dict = Marshal.ReadIntPtr(type, TypeOffset.tp_dict);
- IntPtr mod = Runtime.PyString_FromString("CLR");
- Runtime.PyDict_SetItem(tp_dict, PyIdentifier.__module__, mod);
-
- // The type has been modified after PyType_Ready has been called
- // Refresh the type
- Runtime.PyType_Modified(type);
-
- return type;
- }
-
///
/// Utility method to allocate a type object & do basic initialization.
@@ -598,6 +583,7 @@ internal static IntPtr BasicSubType(string name, IntPtr base_, Type impl)
internal static IntPtr AllocateTypeObject(string name, IntPtr metatype)
{
IntPtr type = Runtime.PyType_GenericAlloc(metatype, 0);
+ PythonException.ThrowIfIsNull(type);
// Clr type would not use __slots__,
// and the PyMemberDef after PyHeapTypeObject will have other uses(e.g. type handle),
// thus set the ob_size to 0 for avoiding slots iterations.
@@ -670,7 +656,7 @@ internal static void InitializeSlots(IntPtr type, Type impl, SlotsHolder slotsHo
{
continue;
}
- var offset = ManagedDataOffsets.GetSlotOffset(slot);
+ var offset = TypeOffset.GetSlotOffset(slot);
Marshal.WriteIntPtr(type, offset, SlotsHolder.GetDefaultSlot(offset));
}
}
@@ -688,7 +674,7 @@ internal static void InitializeSlots(IntPtr type, Type impl, SlotsHolder slotsHo
/// Can override the slot when it existed
static void InitializeSlot(IntPtr type, IntPtr slot, string name, bool canOverride = true)
{
- var offset = ManagedDataOffsets.GetSlotOffset(name);
+ var offset = TypeOffset.GetSlotOffset(name);
if (!canOverride && Marshal.ReadIntPtr(type, offset) != IntPtr.Zero)
{
return;
@@ -698,7 +684,7 @@ static void InitializeSlot(IntPtr type, IntPtr slot, string name, bool canOverri
static void InitializeSlot(IntPtr type, ThunkInfo thunk, string name, SlotsHolder slotsHolder = null, bool canOverride = true)
{
- int offset = ManagedDataOffsets.GetSlotOffset(name);
+ int offset = TypeOffset.GetSlotOffset(name);
if (!canOverride && Marshal.ReadIntPtr(type, offset) != IntPtr.Zero)
{
@@ -723,7 +709,7 @@ static void InitializeSlot(IntPtr type, int slotOffset, MethodInfo method, Slots
static bool IsSlotSet(IntPtr type, string name)
{
- int offset = ManagedDataOffsets.GetSlotOffset(name);
+ int offset = TypeOffset.GetSlotOffset(name);
return Marshal.ReadIntPtr(type, offset) != IntPtr.Zero;
}
@@ -794,6 +780,8 @@ class SlotsHolder
private List _deallocators = new List();
private bool _alreadyReset = false;
+ BorrowedReference Type => new BorrowedReference(_type);
+
///
/// Create slots holder for holding the delegate of slots and be able to reset them.
///
@@ -861,15 +849,18 @@ public void ResetSlots()
_deallocators.Clear();
// Custom reset
- IntPtr handlePtr = Marshal.ReadIntPtr(_type, TypeOffset.magic());
- if (handlePtr != IntPtr.Zero)
+ if (Type != Runtime.CLRMetaType)
{
- GCHandle handle = GCHandle.FromIntPtr(handlePtr);
- if (handle.IsAllocated)
+ var metatype = Runtime.PyObject_TYPE(Type);
+ if (ManagedType.TryGetGCHandle(Type, metatype) is { } handle)
{
- handle.Free();
+ if (handle.IsAllocated)
+ {
+ handle.Free();
+ }
+
+ ManagedType.SetGCHandle(Type, metatype, default);
}
- Marshal.WriteIntPtr(_type, TypeOffset.magic(), IntPtr.Zero);
}
}