diff --git a/src/runtime/classderived.cs b/src/runtime/classderived.cs
index 8b15213c3..f8b97b397 100644
--- a/src/runtime/classderived.cs
+++ b/src/runtime/classderived.cs
@@ -102,10 +102,7 @@ internal static IntPtr ToPython(IPythonDerivedType obj)
// collected while Python still has a reference to it.
if (Runtime.Refcount(self.pyHandle) == 1)
{
-
-#if PYTHON_WITH_PYDEBUG
- Runtime._Py_NewReference(self.pyHandle);
-#endif
+ Runtime._Py_NewReference(self.ObjectReference);
GCHandle gc = GCHandle.Alloc(self, GCHandleType.Normal);
SetGCHandle(self.ObjectReference, self.TypeReference, gc);
self.gcHandle.Free();
diff --git a/src/runtime/converter.cs b/src/runtime/converter.cs
index 2e10e9041..70b3d9eaa 100644
--- a/src/runtime/converter.cs
+++ b/src/runtime/converter.cs
@@ -525,6 +525,16 @@ internal static bool ToManagedValue(IntPtr value, Type obType,
internal delegate bool TryConvertFromPythonDelegate(IntPtr pyObj, out object result);
+ internal static int ToInt32(BorrowedReference value)
+ {
+ nint num = Runtime.PyLong_AsSignedSize_t(value);
+ if (num == -1 && Exceptions.ErrorOccurred())
+ {
+ throw new PythonException();
+ }
+ return checked((int)num);
+ }
+
///
/// Convert a Python value to an instance of a primitive managed type.
///
diff --git a/src/runtime/native/ABI.cs b/src/runtime/native/ABI.cs
index 339919dee..e99fc33ab 100644
--- a/src/runtime/native/ABI.cs
+++ b/src/runtime/native/ABI.cs
@@ -7,6 +7,9 @@ namespace Python.Runtime.Native
static class ABI
{
+ public static int RefCountOffset { get; } = GetRefCountOffset();
+ public static int ObjectHeadOffset => RefCountOffset;
+
internal static void Initialize(Version version, BorrowedReference pyType)
{
string offsetsClassSuffix = string.Format(CultureInfo.InvariantCulture,
@@ -16,18 +19,34 @@ internal static void Initialize(Version version, BorrowedReference pyType)
const string nativeTypeOffsetClassName = "Python.Runtime.NativeTypeOffset";
string className = "Python.Runtime.TypeOffset" + offsetsClassSuffix;
+ Type nativeOffsetsClass = thisAssembly.GetType(nativeTypeOffsetClassName, throwOnError: false);
Type typeOffsetsClass =
// Try platform native offsets first. It is only present when generated by setup.py
- thisAssembly.GetType(nativeTypeOffsetClassName, throwOnError: false)
- ?? thisAssembly.GetType(className, throwOnError: false);
+ nativeOffsetsClass ?? thisAssembly.GetType(className, throwOnError: false);
if (typeOffsetsClass is null)
{
var types = thisAssembly.GetTypes().Select(type => type.Name).Where(name => name.StartsWith("TypeOffset"));
string message = $"Searching for {className}, found {string.Join(",", types)}.";
throw new NotSupportedException($"Python ABI v{version} is not supported: {message}");
}
+
var typeOffsets = (ITypeOffsets)Activator.CreateInstance(typeOffsetsClass);
- TypeOffset.Use(typeOffsets);
+ TypeOffset.Use(typeOffsets, nativeOffsetsClass == null ? ObjectHeadOffset : 0);
+ }
+
+ static unsafe int GetRefCountOffset()
+ {
+ IntPtr tempObject = Runtime.PyList_New(0);
+ IntPtr* tempPtr = (IntPtr*)tempObject;
+ int offset = 0;
+ while(tempPtr[offset] != (IntPtr)1)
+ {
+ offset++;
+ if (offset > 100)
+ throw new InvalidProgramException("PyObject_HEAD could not be found withing reasonable distance from the start of PyObject");
+ }
+ Runtime.XDecref(tempObject);
+ return offset * IntPtr.Size;
}
}
}
diff --git a/src/runtime/native/TypeOffset.cs b/src/runtime/native/TypeOffset.cs
index edbbe3b2c..4e5a726bc 100644
--- a/src/runtime/native/TypeOffset.cs
+++ b/src/runtime/native/TypeOffset.cs
@@ -75,7 +75,7 @@ static partial class TypeOffset
internal static int tp_str { get; private set; }
internal static int tp_traverse { get; private set; }
- internal static void Use(ITypeOffsets offsets)
+ internal static void Use(ITypeOffsets offsets, int extraHeadOffset)
{
if (offsets is null) throw new ArgumentNullException(nameof(offsets));
@@ -87,6 +87,7 @@ internal static void Use(ITypeOffsets offsets)
var sourceProperty = typeof(ITypeOffsets).GetProperty(offsetProperty.Name);
int value = (int)sourceProperty.GetValue(offsets, null);
+ value += extraHeadOffset;
offsetProperty.SetValue(obj: null, value: value, index: null);
}
diff --git a/src/runtime/runtime.cs b/src/runtime/runtime.cs
index 1b1a7eccc..6ebf885a0 100644
--- a/src/runtime/runtime.cs
+++ b/src/runtime/runtime.cs
@@ -85,9 +85,9 @@ internal static Version PyVersion
{
using (var versionTuple = new PyTuple(PySys_GetObject("version_info")))
{
- var major = versionTuple[0].As();
- var minor = versionTuple[1].As();
- var micro = versionTuple[2].As();
+ var major = Converter.ToInt32(versionTuple[0].Reference);
+ var minor = Converter.ToInt32(versionTuple[1].Reference);
+ var micro = Converter.ToInt32(versionTuple[2].Reference);
return new Version(major, minor, micro);
}
}
@@ -198,15 +198,15 @@ private static void InitPyMembers()
SetPyMember(ref PyFalse, PyObject_GetAttrString(builtins, "False"),
() => PyFalse = IntPtr.Zero);
- SetPyMember(ref PyBoolType, PyObject_Type(PyTrue),
+ SetPyMemberTypeOf(ref PyBoolType, PyTrue,
() => PyBoolType = IntPtr.Zero);
- SetPyMember(ref PyNoneType, PyObject_Type(PyNone),
+ SetPyMemberTypeOf(ref PyNoneType, PyNone,
() => PyNoneType = IntPtr.Zero);
- SetPyMember(ref PyTypeType, PyObject_Type(PyNoneType),
+ SetPyMemberTypeOf(ref PyTypeType, PyNoneType,
() => PyTypeType = IntPtr.Zero);
op = PyObject_GetAttrString(builtins, "len");
- SetPyMember(ref PyMethodType, PyObject_Type(op),
+ SetPyMemberTypeOf(ref PyMethodType, op,
() => PyMethodType = IntPtr.Zero);
XDecref(op);
@@ -215,7 +215,7 @@ private static void InitPyMembers()
//
// object.__init__ seems safe, though.
op = PyObject_GetAttr(PyBaseObjectType, PyIdentifier.__init__);
- SetPyMember(ref PyWrapperDescriptorType, PyObject_Type(op),
+ SetPyMemberTypeOf(ref PyWrapperDescriptorType, op,
() => PyWrapperDescriptorType = IntPtr.Zero);
XDecref(op);
@@ -226,47 +226,47 @@ private static void InitPyMembers()
}
op = PyString_FromString("string");
- SetPyMember(ref PyStringType, PyObject_Type(op),
+ SetPyMemberTypeOf(ref PyStringType, op,
() => PyStringType = IntPtr.Zero);
XDecref(op);
op = PyUnicode_FromString("unicode");
- SetPyMember(ref PyUnicodeType, PyObject_Type(op),
+ SetPyMemberTypeOf(ref PyUnicodeType, op,
() => PyUnicodeType = IntPtr.Zero);
XDecref(op);
op = EmptyPyBytes();
- SetPyMember(ref PyBytesType, PyObject_Type(op),
+ SetPyMemberTypeOf(ref PyBytesType, op,
() => PyBytesType = IntPtr.Zero);
XDecref(op);
op = PyTuple_New(0);
- SetPyMember(ref PyTupleType, PyObject_Type(op),
+ SetPyMemberTypeOf(ref PyTupleType, op,
() => PyTupleType = IntPtr.Zero);
XDecref(op);
op = PyList_New(0);
- SetPyMember(ref PyListType, PyObject_Type(op),
+ SetPyMemberTypeOf(ref PyListType, op,
() => PyListType = IntPtr.Zero);
XDecref(op);
op = PyDict_New();
- SetPyMember(ref PyDictType, PyObject_Type(op),
+ SetPyMemberTypeOf(ref PyDictType, op,
() => PyDictType = IntPtr.Zero);
XDecref(op);
op = PyInt_FromInt32(0);
- SetPyMember(ref PyIntType, PyObject_Type(op),
+ SetPyMemberTypeOf(ref PyIntType, op,
() => PyIntType = IntPtr.Zero);
XDecref(op);
op = PyLong_FromLong(0);
- SetPyMember(ref PyLongType, PyObject_Type(op),
+ SetPyMemberTypeOf(ref PyLongType, op,
() => PyLongType = IntPtr.Zero);
XDecref(op);
op = PyFloat_FromDouble(0);
- SetPyMember(ref PyFloatType, PyObject_Type(op),
+ SetPyMemberTypeOf(ref PyFloatType, op,
() => PyFloatType = IntPtr.Zero);
XDecref(op);
@@ -278,7 +278,8 @@ private static void InitPyMembers()
_PyObject_NextNotImplemented = Get_PyObject_NextNotImplemented();
{
using var sys = PyImport_ImportModule("sys");
- PyModuleType = PyObject_Type(sys.DangerousMoveToPointer());
+ SetPyMemberTypeOf(ref PyModuleType, sys.DangerousGetAddress(),
+ () => PyModuleType = IntPtr.Zero);
}
}
@@ -455,6 +456,12 @@ private static void SetPyMember(ref IntPtr obj, IntPtr value, Action onRelease)
_pyRefs.Add(value, onRelease);
}
+ private static void SetPyMemberTypeOf(ref IntPtr obj, IntPtr value, Action onRelease)
+ {
+ var type = PyObject_Type(new BorrowedReference(value)).DangerousMoveToPointer();
+ SetPyMember(ref obj, type, onRelease);
+ }
+
private static void ResetPyMembers()
{
_pyRefs.Release();
@@ -761,16 +768,12 @@ internal static unsafe void XDecref(IntPtr op)
[Pure]
internal static unsafe long Refcount(IntPtr op)
{
-#if PYTHON_WITH_PYDEBUG
- var p = (void*)(op + TypeOffset.ob_refcnt);
-#else
- var p = (void*)op;
-#endif
- if ((void*)0 == p)
+ if (op == IntPtr.Zero)
{
return 0;
}
- return Is32Bit ? (*(int*)p) : (*(long*)p);
+ var p = (nint*)(op + ABI.RefCountOffset);
+ return *p;
}
///
@@ -977,14 +980,9 @@ internal static unsafe IntPtr PyObject_TYPE(IntPtr op)
{
return IntPtr.Zero;
}
-#if PYTHON_WITH_PYDEBUG
- var n = 3;
-#else
- var n = 1;
-#endif
- return Is32Bit
- ? new IntPtr((void*)(*((uint*)p + n)))
- : new IntPtr((void*)(*((ulong*)p + n)));
+ Debug.Assert(TypeOffset.ob_type > 0);
+ IntPtr* typePtr = (IntPtr*)(op + TypeOffset.ob_type);
+ return *typePtr;
}
internal static unsafe BorrowedReference PyObject_TYPE(BorrowedReference op)
=> new BorrowedReference(PyObject_TYPE(op.DangerousGetAddress()));
@@ -1001,6 +999,9 @@ internal static IntPtr PyObject_Type(IntPtr op)
return tp;
}
+ internal static NewReference PyObject_Type(BorrowedReference o)
+ => Delegates.PyObject_Type(o);
+
internal static string PyObject_GetTypeName(IntPtr op)
{
IntPtr pyType = PyObject_TYPE(op);
@@ -1145,10 +1146,11 @@ internal static IntPtr PyObject_Str(IntPtr pointer)
internal static IntPtr PyObject_Dir(IntPtr pointer) => Delegates.PyObject_Dir(pointer);
-#if PYTHON_WITH_PYDEBUG
- [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
- internal static extern void _Py_NewReference(IntPtr ob);
-#endif
+ internal static void _Py_NewReference(BorrowedReference ob)
+ {
+ if (Delegates._Py_NewReference != null)
+ Delegates._Py_NewReference(ob);
+ }
//====================================================================
// Python buffer API
@@ -1912,11 +1914,6 @@ internal static string PyModule_GetName(IntPtr module)
internal static string PyModule_GetFilename(IntPtr module)
=> Delegates.PyModule_GetFilename(module).ToString(Encoding.UTF8);
-#if PYTHON_WITH_PYDEBUG
- [DllImport(_PythonDll, EntryPoint = "PyModule_Create2TraceRefs", CallingConvention = CallingConvention.Cdecl)]
-#else
-
-#endif
internal static IntPtr PyModule_Create2(IntPtr module, int apiver) => Delegates.PyModule_Create2(module, apiver);
@@ -2331,6 +2328,7 @@ static Delegates()
PyObject_Hash = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyObject_Hash), GetUnmanagedDll(_PythonDll));
PyObject_Repr = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyObject_Repr), GetUnmanagedDll(_PythonDll));
PyObject_Str = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyObject_Str), GetUnmanagedDll(_PythonDll));
+ PyObject_Type = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyObject_Type), GetUnmanagedDll(_PythonDll));
PyObject_Dir = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyObject_Dir), GetUnmanagedDll(_PythonDll));
PyObject_GetBuffer = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyObject_GetBuffer), GetUnmanagedDll(_PythonDll));
PyBuffer_Release = (delegate* unmanaged[Cdecl][)GetFunctionByName(nameof(PyBuffer_Release), GetUnmanagedDll(_PythonDll));
@@ -2466,7 +2464,14 @@ static Delegates()
PyModule_GetName = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyModule_GetName), GetUnmanagedDll(_PythonDll));
PyModule_GetDict = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyModule_GetDict), GetUnmanagedDll(_PythonDll));
PyModule_GetFilename = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyModule_GetFilename), GetUnmanagedDll(_PythonDll));
- PyModule_Create2 = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyModule_Create2), GetUnmanagedDll(_PythonDll));
+ try
+ {
+ PyModule_Create2 = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyModule_Create2), GetUnmanagedDll(_PythonDll));
+ }
+ catch (MissingMethodException)
+ {
+ PyModule_Create2 = (delegate* unmanaged[Cdecl])GetFunctionByName("PyModule_Create2TraceRefs", GetUnmanagedDll(_PythonDll));
+ }
PyImport_Import = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyImport_Import), GetUnmanagedDll(_PythonDll));
PyImport_ImportModule = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyImport_ImportModule), GetUnmanagedDll(_PythonDll));
PyImport_ReloadModule = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyImport_ReloadModule), GetUnmanagedDll(_PythonDll));
@@ -2521,6 +2526,12 @@ static Delegates()
PyThreadState_SetAsyncExcLLP64 = (delegate* unmanaged[Cdecl])GetFunctionByName("PyThreadState_SetAsyncExc", GetUnmanagedDll(_PythonDll));
PyThreadState_SetAsyncExcLP64 = (delegate* unmanaged[Cdecl])GetFunctionByName("PyThreadState_SetAsyncExc", GetUnmanagedDll(_PythonDll));
PyType_FromSpecWithBases = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyType_FromSpecWithBases), GetUnmanagedDll(PythonDLL));
+
+ try
+ {
+ _Py_NewReference = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(_Py_NewReference), GetUnmanagedDll(_PythonDll));
+ }
+ catch (MissingMethodException) { }
}
static global::System.IntPtr GetUnmanagedDll(string libraryName)
@@ -2616,6 +2627,7 @@ static Delegates()
internal static delegate* unmanaged[Cdecl] PyObject_Hash { get; }
internal static delegate* unmanaged[Cdecl] PyObject_Repr { get; }
internal static delegate* unmanaged[Cdecl] PyObject_Str { get; }
+ internal static delegate* unmanaged[Cdecl] PyObject_Type { get; }
internal static delegate* unmanaged[Cdecl] PyObject_Dir { get; }
internal static delegate* unmanaged[Cdecl] PyObject_GetBuffer { get; }
internal static delegate* unmanaged[Cdecl]][ PyBuffer_Release { get; }
@@ -2799,6 +2811,7 @@ static Delegates()
internal static delegate* unmanaged[Cdecl] PyThreadState_SetAsyncExcLP64 { get; }
internal static delegate* unmanaged[Cdecl] PyObject_GenericGetDict { get; }
internal static delegate* unmanaged[Cdecl] PyType_FromSpecWithBases { get; }
+ internal static delegate* unmanaged[Cdecl] _Py_NewReference { get; }
}
}
]