From bbc0dfbb9071dca92c491bfea679a096df269263 Mon Sep 17 00:00:00 2001 From: Victor Milovanov Date: Tue, 24 Nov 2020 00:24:51 -0800 Subject: [PATCH 1/4] TypeOffset class no longer depends on target Python version Instead, for each supported Python version a separate class is generated (e.g. TypeOffset36). Then the Runtime picks the correct class using reflection, and copies only the necessary TypeOffset members over from it. ManagedDataOffsets.Magic is now also read at runtime from tp_basicsize of PyType --- pythonnet.15.sln | 5 + src/runtime/Python.Runtime.csproj | 4 + src/runtime/debughelper.cs | 8 +- src/runtime/interop.cs | 23 +- src/runtime/interop36.cs | 238 ++++++++++---------- src/runtime/interop37.cs | 238 ++++++++++---------- src/runtime/interop38.cs | 242 +++++++++++---------- src/runtime/interop39.cs | 241 ++++++++++---------- src/runtime/native/ABI.cs | 28 +++ src/runtime/native/GeneratedTypeOffsets.cs | 22 ++ src/runtime/native/ITypeOffsets.cs | 56 +++++ src/runtime/native/TypeOffset.cs | 106 +++++++++ src/runtime/runtime.cs | 21 +- src/runtime/typemanager.cs | 4 +- tools/geninterop/geninterop.py | 47 ++-- 15 files changed, 751 insertions(+), 532 deletions(-) create mode 100644 src/runtime/native/ABI.cs create mode 100644 src/runtime/native/GeneratedTypeOffsets.cs create mode 100644 src/runtime/native/ITypeOffsets.cs create mode 100644 src/runtime/native/TypeOffset.cs diff --git a/pythonnet.15.sln b/pythonnet.15.sln index ce863817f..402bd0003 100644 --- a/pythonnet.15.sln +++ b/pythonnet.15.sln @@ -42,6 +42,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "conda.recipe", "conda.recip conda.recipe\README.md = conda.recipe\README.md EndProjectSection EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tools", "Tools", "{BC426F42-8494-4AA5-82C9-5109ACD97BD1}" + ProjectSection(SolutionItems) = preProject + tools\geninterop\geninterop.py = tools\geninterop\geninterop.py + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU diff --git a/src/runtime/Python.Runtime.csproj b/src/runtime/Python.Runtime.csproj index 418620136..55e92387f 100644 --- a/src/runtime/Python.Runtime.csproj +++ b/src/runtime/Python.Runtime.csproj @@ -80,6 +80,10 @@ + + + + diff --git a/src/runtime/debughelper.cs b/src/runtime/debughelper.cs index 3fe9ee5bb..babe726c6 100644 --- a/src/runtime/debughelper.cs +++ b/src/runtime/debughelper.cs @@ -60,13 +60,13 @@ internal static void DumpType(IntPtr type) //DebugUtil.Print(" mro: ", op); - FieldInfo[] slots = typeof(TypeOffset).GetFields(); + var slots = TypeOffset.GetOffsets(); int size = IntPtr.Size; - for (var i = 0; i < slots.Length; i++) + foreach (var entry in slots) { - int offset = i * size; - name = slots[i].Name; + int offset = entry.Value; + name = entry.Key; op = Marshal.ReadIntPtr(type, offset); Console.WriteLine(" {0}: {1}", name, op); } diff --git a/src/runtime/interop.cs b/src/runtime/interop.cs index 1caabab17..a8330619b 100644 --- a/src/runtime/interop.cs +++ b/src/runtime/interop.cs @@ -70,25 +70,12 @@ public ModulePropertyAttribute() internal static partial class TypeOffset { - static TypeOffset() - { - Type type = typeof(TypeOffset); - FieldInfo[] fields = type.GetFields(); - int size = IntPtr.Size; - for (int i = 0; i < fields.Length; i++) - { - int offset = i * size; - FieldInfo fi = fields[i]; - fi.SetValue(null, offset); - } - } - public static int magic() => ManagedDataOffsets.Magic; } internal static class ManagedDataOffsets { - public static int Magic { get; private set; } + public static int Magic { get; internal set; } public static readonly Dictionary NameMapping = new Dictionary(); static class DataOffsets @@ -108,13 +95,7 @@ static DataOffsets() static ManagedDataOffsets() { - Type type = typeof(TypeOffset); - foreach (FieldInfo fi in type.GetFields()) - { - NameMapping[fi.Name] = (int)fi.GetValue(null); - } - // XXX: Use the members after PyHeapTypeObject as magic slot - Magic = TypeOffset.members; + NameMapping = TypeOffset.GetOffsets(); FieldInfo[] fields = typeof(DataOffsets).GetFields(BindingFlags.Static | BindingFlags.Public); size = fields.Length * IntPtr.Size; diff --git a/src/runtime/interop36.cs b/src/runtime/interop36.cs index d68539d56..1ac567e09 100644 --- a/src/runtime/interop36.cs +++ b/src/runtime/interop36.cs @@ -2,135 +2,137 @@ // Auto-generated by geninterop.py. // DO NOT MODIFY BY HAND. +// ReSharper disable InconsistentNaming +// ReSharper disable IdentifierTypo -#if PYTHON36 using System; -using System.Collections; -using System.Collections.Specialized; +using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; -using System.Reflection; -using System.Text; + +using Python.Runtime.Native; namespace Python.Runtime { + [SuppressMessage("Style", "IDE1006:Naming Styles", + Justification = "Following CPython", + Scope = "type")] [StructLayout(LayoutKind.Sequential)] - internal static partial class TypeOffset + internal class TypeOffset36 : GeneratedTypeOffsets, ITypeOffsets { + public TypeOffset36() { } // Auto-generated from PyHeapTypeObject in Python.h - public static int ob_refcnt = 0; - public static int ob_type = 0; - public static int ob_size = 0; - public static int tp_name = 0; - public static int tp_basicsize = 0; - public static int tp_itemsize = 0; - public static int tp_dealloc = 0; - public static int tp_print = 0; - public static int tp_getattr = 0; - public static int tp_setattr = 0; - public static int tp_as_async = 0; - public static int tp_repr = 0; - public static int tp_as_number = 0; - public static int tp_as_sequence = 0; - public static int tp_as_mapping = 0; - public static int tp_hash = 0; - public static int tp_call = 0; - public static int tp_str = 0; - public static int tp_getattro = 0; - public static int tp_setattro = 0; - public static int tp_as_buffer = 0; - public static int tp_flags = 0; - public static int tp_doc = 0; - public static int tp_traverse = 0; - public static int tp_clear = 0; - public static int tp_richcompare = 0; - public static int tp_weaklistoffset = 0; - public static int tp_iter = 0; - public static int tp_iternext = 0; - public static int tp_methods = 0; - public static int tp_members = 0; - public static int tp_getset = 0; - public static int tp_base = 0; - public static int tp_dict = 0; - public static int tp_descr_get = 0; - public static int tp_descr_set = 0; - public static int tp_dictoffset = 0; - public static int tp_init = 0; - public static int tp_alloc = 0; - public static int tp_new = 0; - public static int tp_free = 0; - public static int tp_is_gc = 0; - public static int tp_bases = 0; - public static int tp_mro = 0; - public static int tp_cache = 0; - public static int tp_subclasses = 0; - public static int tp_weaklist = 0; - public static int tp_del = 0; - public static int tp_version_tag = 0; - public static int tp_finalize = 0; - public static int am_await = 0; - public static int am_aiter = 0; - public static int am_anext = 0; - public static int nb_add = 0; - public static int nb_subtract = 0; - public static int nb_multiply = 0; - public static int nb_remainder = 0; - public static int nb_divmod = 0; - public static int nb_power = 0; - public static int nb_negative = 0; - public static int nb_positive = 0; - public static int nb_absolute = 0; - public static int nb_bool = 0; - public static int nb_invert = 0; - public static int nb_lshift = 0; - public static int nb_rshift = 0; - public static int nb_and = 0; - public static int nb_xor = 0; - public static int nb_or = 0; - public static int nb_int = 0; - public static int nb_reserved = 0; - public static int nb_float = 0; - public static int nb_inplace_add = 0; - public static int nb_inplace_subtract = 0; - public static int nb_inplace_multiply = 0; - public static int nb_inplace_remainder = 0; - public static int nb_inplace_power = 0; - public static int nb_inplace_lshift = 0; - public static int nb_inplace_rshift = 0; - public static int nb_inplace_and = 0; - public static int nb_inplace_xor = 0; - public static int nb_inplace_or = 0; - public static int nb_floor_divide = 0; - public static int nb_true_divide = 0; - public static int nb_inplace_floor_divide = 0; - public static int nb_inplace_true_divide = 0; - public static int nb_index = 0; - public static int nb_matrix_multiply = 0; - public static int nb_inplace_matrix_multiply = 0; - public static int mp_length = 0; - public static int mp_subscript = 0; - public static int mp_ass_subscript = 0; - public static int sq_length = 0; - public static int sq_concat = 0; - public static int sq_repeat = 0; - public static int sq_item = 0; - public static int was_sq_slice = 0; - public static int sq_ass_item = 0; - public static int was_sq_ass_slice = 0; - public static int sq_contains = 0; - public static int sq_inplace_concat = 0; - public static int sq_inplace_repeat = 0; - public static int bf_getbuffer = 0; - public static int bf_releasebuffer = 0; - public static int name = 0; - public static int ht_slots = 0; - public static int qualname = 0; - public static int ht_cached_keys = 0; - - /* here are optional user slots, followed by the members. */ - public static int members = 0; + public int ob_refcnt { get; private set; } + public int ob_type { get; private set; } + public int ob_size { get; private set; } + public int tp_name { get; private set; } + public int tp_basicsize { get; private set; } + public int tp_itemsize { get; private set; } + public int tp_dealloc { get; private set; } + public int tp_print { get; private set; } + public int tp_getattr { get; private set; } + public int tp_setattr { get; private set; } + public int tp_as_async { get; private set; } + public int tp_repr { get; private set; } + public int tp_as_number { get; private set; } + public int tp_as_sequence { get; private set; } + public int tp_as_mapping { get; private set; } + public int tp_hash { get; private set; } + public int tp_call { get; private set; } + public int tp_str { get; private set; } + public int tp_getattro { get; private set; } + public int tp_setattro { get; private set; } + public int tp_as_buffer { get; private set; } + public int tp_flags { get; private set; } + public int tp_doc { get; private set; } + public int tp_traverse { get; private set; } + public int tp_clear { get; private set; } + public int tp_richcompare { get; private set; } + public int tp_weaklistoffset { get; private set; } + public int tp_iter { get; private set; } + public int tp_iternext { get; private set; } + public int tp_methods { get; private set; } + public int tp_members { get; private set; } + public int tp_getset { get; private set; } + public int tp_base { get; private set; } + public int tp_dict { get; private set; } + public int tp_descr_get { get; private set; } + public int tp_descr_set { get; private set; } + public int tp_dictoffset { get; private set; } + public int tp_init { get; private set; } + public int tp_alloc { get; private set; } + public int tp_new { get; private set; } + public int tp_free { get; private set; } + public int tp_is_gc { get; private set; } + public int tp_bases { get; private set; } + public int tp_mro { get; private set; } + public int tp_cache { get; private set; } + public int tp_subclasses { get; private set; } + public int tp_weaklist { get; private set; } + public int tp_del { get; private set; } + public int tp_version_tag { get; private set; } + public int tp_finalize { get; private set; } + public int am_await { get; private set; } + public int am_aiter { get; private set; } + public int am_anext { get; private set; } + public int nb_add { get; private set; } + public int nb_subtract { get; private set; } + public int nb_multiply { get; private set; } + public int nb_remainder { get; private set; } + public int nb_divmod { get; private set; } + public int nb_power { get; private set; } + public int nb_negative { get; private set; } + public int nb_positive { get; private set; } + public int nb_absolute { get; private set; } + public int nb_bool { get; private set; } + public int nb_invert { get; private set; } + public int nb_lshift { get; private set; } + public int nb_rshift { get; private set; } + public int nb_and { get; private set; } + public int nb_xor { get; private set; } + public int nb_or { get; private set; } + public int nb_int { get; private set; } + public int nb_reserved { get; private set; } + public int nb_float { get; private set; } + public int nb_inplace_add { get; private set; } + public int nb_inplace_subtract { get; private set; } + public int nb_inplace_multiply { get; private set; } + public int nb_inplace_remainder { get; private set; } + public int nb_inplace_power { get; private set; } + public int nb_inplace_lshift { get; private set; } + public int nb_inplace_rshift { get; private set; } + public int nb_inplace_and { get; private set; } + public int nb_inplace_xor { get; private set; } + public int nb_inplace_or { get; private set; } + public int nb_floor_divide { get; private set; } + public int nb_true_divide { get; private set; } + public int nb_inplace_floor_divide { get; private set; } + public int nb_inplace_true_divide { get; private set; } + public int nb_index { get; private set; } + public int nb_matrix_multiply { get; private set; } + public int nb_inplace_matrix_multiply { get; private set; } + public int mp_length { get; private set; } + public int mp_subscript { get; private set; } + public int mp_ass_subscript { get; private set; } + public int sq_length { get; private set; } + public int sq_concat { get; private set; } + public int sq_repeat { get; private set; } + public int sq_item { get; private set; } + public int was_sq_slice { get; private set; } + public int sq_ass_item { get; private set; } + public int was_sq_ass_slice { get; private set; } + public int sq_contains { get; private set; } + public int sq_inplace_concat { get; private set; } + public int sq_inplace_repeat { get; private set; } + public int bf_getbuffer { get; private set; } + public int bf_releasebuffer { get; private set; } + public int name { get; private set; } + public int ht_slots { get; private set; } + public int qualname { get; private set; } + public int ht_cached_keys { get; private set; } } +#if PYTHON36 [StructLayout(LayoutKind.Sequential)] internal struct PyNumberMethods { @@ -221,5 +223,5 @@ internal static partial class SlotTypes }; } -} #endif +} diff --git a/src/runtime/interop37.cs b/src/runtime/interop37.cs index c85d06525..ca091e27c 100644 --- a/src/runtime/interop37.cs +++ b/src/runtime/interop37.cs @@ -2,135 +2,137 @@ // Auto-generated by geninterop.py. // DO NOT MODIFY BY HAND. +// ReSharper disable InconsistentNaming +// ReSharper disable IdentifierTypo -#if PYTHON37 using System; -using System.Collections; -using System.Collections.Specialized; +using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; -using System.Reflection; -using System.Text; + +using Python.Runtime.Native; namespace Python.Runtime { + [SuppressMessage("Style", "IDE1006:Naming Styles", + Justification = "Following CPython", + Scope = "type")] [StructLayout(LayoutKind.Sequential)] - internal static partial class TypeOffset + internal class TypeOffset37 : GeneratedTypeOffsets, ITypeOffsets { + public TypeOffset37() { } // Auto-generated from PyHeapTypeObject in Python.h - public static int ob_refcnt = 0; - public static int ob_type = 0; - public static int ob_size = 0; - public static int tp_name = 0; - public static int tp_basicsize = 0; - public static int tp_itemsize = 0; - public static int tp_dealloc = 0; - public static int tp_print = 0; - public static int tp_getattr = 0; - public static int tp_setattr = 0; - public static int tp_as_async = 0; - public static int tp_repr = 0; - public static int tp_as_number = 0; - public static int tp_as_sequence = 0; - public static int tp_as_mapping = 0; - public static int tp_hash = 0; - public static int tp_call = 0; - public static int tp_str = 0; - public static int tp_getattro = 0; - public static int tp_setattro = 0; - public static int tp_as_buffer = 0; - public static int tp_flags = 0; - public static int tp_doc = 0; - public static int tp_traverse = 0; - public static int tp_clear = 0; - public static int tp_richcompare = 0; - public static int tp_weaklistoffset = 0; - public static int tp_iter = 0; - public static int tp_iternext = 0; - public static int tp_methods = 0; - public static int tp_members = 0; - public static int tp_getset = 0; - public static int tp_base = 0; - public static int tp_dict = 0; - public static int tp_descr_get = 0; - public static int tp_descr_set = 0; - public static int tp_dictoffset = 0; - public static int tp_init = 0; - public static int tp_alloc = 0; - public static int tp_new = 0; - public static int tp_free = 0; - public static int tp_is_gc = 0; - public static int tp_bases = 0; - public static int tp_mro = 0; - public static int tp_cache = 0; - public static int tp_subclasses = 0; - public static int tp_weaklist = 0; - public static int tp_del = 0; - public static int tp_version_tag = 0; - public static int tp_finalize = 0; - public static int am_await = 0; - public static int am_aiter = 0; - public static int am_anext = 0; - public static int nb_add = 0; - public static int nb_subtract = 0; - public static int nb_multiply = 0; - public static int nb_remainder = 0; - public static int nb_divmod = 0; - public static int nb_power = 0; - public static int nb_negative = 0; - public static int nb_positive = 0; - public static int nb_absolute = 0; - public static int nb_bool = 0; - public static int nb_invert = 0; - public static int nb_lshift = 0; - public static int nb_rshift = 0; - public static int nb_and = 0; - public static int nb_xor = 0; - public static int nb_or = 0; - public static int nb_int = 0; - public static int nb_reserved = 0; - public static int nb_float = 0; - public static int nb_inplace_add = 0; - public static int nb_inplace_subtract = 0; - public static int nb_inplace_multiply = 0; - public static int nb_inplace_remainder = 0; - public static int nb_inplace_power = 0; - public static int nb_inplace_lshift = 0; - public static int nb_inplace_rshift = 0; - public static int nb_inplace_and = 0; - public static int nb_inplace_xor = 0; - public static int nb_inplace_or = 0; - public static int nb_floor_divide = 0; - public static int nb_true_divide = 0; - public static int nb_inplace_floor_divide = 0; - public static int nb_inplace_true_divide = 0; - public static int nb_index = 0; - public static int nb_matrix_multiply = 0; - public static int nb_inplace_matrix_multiply = 0; - public static int mp_length = 0; - public static int mp_subscript = 0; - public static int mp_ass_subscript = 0; - public static int sq_length = 0; - public static int sq_concat = 0; - public static int sq_repeat = 0; - public static int sq_item = 0; - public static int was_sq_slice = 0; - public static int sq_ass_item = 0; - public static int was_sq_ass_slice = 0; - public static int sq_contains = 0; - public static int sq_inplace_concat = 0; - public static int sq_inplace_repeat = 0; - public static int bf_getbuffer = 0; - public static int bf_releasebuffer = 0; - public static int name = 0; - public static int ht_slots = 0; - public static int qualname = 0; - public static int ht_cached_keys = 0; - - /* here are optional user slots, followed by the members. */ - public static int members = 0; + public int ob_refcnt { get; private set; } + public int ob_type { get; private set; } + public int ob_size { get; private set; } + public int tp_name { get; private set; } + public int tp_basicsize { get; private set; } + public int tp_itemsize { get; private set; } + public int tp_dealloc { get; private set; } + public int tp_print { get; private set; } + public int tp_getattr { get; private set; } + public int tp_setattr { get; private set; } + public int tp_as_async { get; private set; } + public int tp_repr { get; private set; } + public int tp_as_number { get; private set; } + public int tp_as_sequence { get; private set; } + public int tp_as_mapping { get; private set; } + public int tp_hash { get; private set; } + public int tp_call { get; private set; } + public int tp_str { get; private set; } + public int tp_getattro { get; private set; } + public int tp_setattro { get; private set; } + public int tp_as_buffer { get; private set; } + public int tp_flags { get; private set; } + public int tp_doc { get; private set; } + public int tp_traverse { get; private set; } + public int tp_clear { get; private set; } + public int tp_richcompare { get; private set; } + public int tp_weaklistoffset { get; private set; } + public int tp_iter { get; private set; } + public int tp_iternext { get; private set; } + public int tp_methods { get; private set; } + public int tp_members { get; private set; } + public int tp_getset { get; private set; } + public int tp_base { get; private set; } + public int tp_dict { get; private set; } + public int tp_descr_get { get; private set; } + public int tp_descr_set { get; private set; } + public int tp_dictoffset { get; private set; } + public int tp_init { get; private set; } + public int tp_alloc { get; private set; } + public int tp_new { get; private set; } + public int tp_free { get; private set; } + public int tp_is_gc { get; private set; } + public int tp_bases { get; private set; } + public int tp_mro { get; private set; } + public int tp_cache { get; private set; } + public int tp_subclasses { get; private set; } + public int tp_weaklist { get; private set; } + public int tp_del { get; private set; } + public int tp_version_tag { get; private set; } + public int tp_finalize { get; private set; } + public int am_await { get; private set; } + public int am_aiter { get; private set; } + public int am_anext { get; private set; } + public int nb_add { get; private set; } + public int nb_subtract { get; private set; } + public int nb_multiply { get; private set; } + public int nb_remainder { get; private set; } + public int nb_divmod { get; private set; } + public int nb_power { get; private set; } + public int nb_negative { get; private set; } + public int nb_positive { get; private set; } + public int nb_absolute { get; private set; } + public int nb_bool { get; private set; } + public int nb_invert { get; private set; } + public int nb_lshift { get; private set; } + public int nb_rshift { get; private set; } + public int nb_and { get; private set; } + public int nb_xor { get; private set; } + public int nb_or { get; private set; } + public int nb_int { get; private set; } + public int nb_reserved { get; private set; } + public int nb_float { get; private set; } + public int nb_inplace_add { get; private set; } + public int nb_inplace_subtract { get; private set; } + public int nb_inplace_multiply { get; private set; } + public int nb_inplace_remainder { get; private set; } + public int nb_inplace_power { get; private set; } + public int nb_inplace_lshift { get; private set; } + public int nb_inplace_rshift { get; private set; } + public int nb_inplace_and { get; private set; } + public int nb_inplace_xor { get; private set; } + public int nb_inplace_or { get; private set; } + public int nb_floor_divide { get; private set; } + public int nb_true_divide { get; private set; } + public int nb_inplace_floor_divide { get; private set; } + public int nb_inplace_true_divide { get; private set; } + public int nb_index { get; private set; } + public int nb_matrix_multiply { get; private set; } + public int nb_inplace_matrix_multiply { get; private set; } + public int mp_length { get; private set; } + public int mp_subscript { get; private set; } + public int mp_ass_subscript { get; private set; } + public int sq_length { get; private set; } + public int sq_concat { get; private set; } + public int sq_repeat { get; private set; } + public int sq_item { get; private set; } + public int was_sq_slice { get; private set; } + public int sq_ass_item { get; private set; } + public int was_sq_ass_slice { get; private set; } + public int sq_contains { get; private set; } + public int sq_inplace_concat { get; private set; } + public int sq_inplace_repeat { get; private set; } + public int bf_getbuffer { get; private set; } + public int bf_releasebuffer { get; private set; } + public int name { get; private set; } + public int ht_slots { get; private set; } + public int qualname { get; private set; } + public int ht_cached_keys { get; private set; } } +#if PYTHON37 [StructLayout(LayoutKind.Sequential)] internal struct PyNumberMethods { @@ -221,5 +223,5 @@ internal static partial class SlotTypes }; } -} #endif +} diff --git a/src/runtime/interop38.cs b/src/runtime/interop38.cs index a87573e90..031d25c1b 100644 --- a/src/runtime/interop38.cs +++ b/src/runtime/interop38.cs @@ -2,137 +2,139 @@ // Auto-generated by geninterop.py. // DO NOT MODIFY BY HAND. +// ReSharper disable InconsistentNaming +// ReSharper disable IdentifierTypo -#if PYTHON38 using System; -using System.Collections; -using System.Collections.Specialized; +using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; -using System.Reflection; -using System.Text; + +using Python.Runtime.Native; namespace Python.Runtime { + [SuppressMessage("Style", "IDE1006:Naming Styles", + Justification = "Following CPython", + Scope = "type")] [StructLayout(LayoutKind.Sequential)] - internal static partial class TypeOffset + internal class TypeOffset38 : GeneratedTypeOffsets, ITypeOffsets { + public TypeOffset38() { } // Auto-generated from PyHeapTypeObject in Python.h - public static int ob_refcnt = 0; - public static int ob_type = 0; - public static int ob_size = 0; - public static int tp_name = 0; - public static int tp_basicsize = 0; - public static int tp_itemsize = 0; - public static int tp_dealloc = 0; - public static int tp_vectorcall_offset = 0; - public static int tp_getattr = 0; - public static int tp_setattr = 0; - public static int tp_as_async = 0; - public static int tp_repr = 0; - public static int tp_as_number = 0; - public static int tp_as_sequence = 0; - public static int tp_as_mapping = 0; - public static int tp_hash = 0; - public static int tp_call = 0; - public static int tp_str = 0; - public static int tp_getattro = 0; - public static int tp_setattro = 0; - public static int tp_as_buffer = 0; - public static int tp_flags = 0; - public static int tp_doc = 0; - public static int tp_traverse = 0; - public static int tp_clear = 0; - public static int tp_richcompare = 0; - public static int tp_weaklistoffset = 0; - public static int tp_iter = 0; - public static int tp_iternext = 0; - public static int tp_methods = 0; - public static int tp_members = 0; - public static int tp_getset = 0; - public static int tp_base = 0; - public static int tp_dict = 0; - public static int tp_descr_get = 0; - public static int tp_descr_set = 0; - public static int tp_dictoffset = 0; - public static int tp_init = 0; - public static int tp_alloc = 0; - public static int tp_new = 0; - public static int tp_free = 0; - public static int tp_is_gc = 0; - public static int tp_bases = 0; - public static int tp_mro = 0; - public static int tp_cache = 0; - public static int tp_subclasses = 0; - public static int tp_weaklist = 0; - public static int tp_del = 0; - public static int tp_version_tag = 0; - public static int tp_finalize = 0; - public static int tp_vectorcall = 0; - public static int tp_print = 0; - public static int am_await = 0; - public static int am_aiter = 0; - public static int am_anext = 0; - public static int nb_add = 0; - public static int nb_subtract = 0; - public static int nb_multiply = 0; - public static int nb_remainder = 0; - public static int nb_divmod = 0; - public static int nb_power = 0; - public static int nb_negative = 0; - public static int nb_positive = 0; - public static int nb_absolute = 0; - public static int nb_bool = 0; - public static int nb_invert = 0; - public static int nb_lshift = 0; - public static int nb_rshift = 0; - public static int nb_and = 0; - public static int nb_xor = 0; - public static int nb_or = 0; - public static int nb_int = 0; - public static int nb_reserved = 0; - public static int nb_float = 0; - public static int nb_inplace_add = 0; - public static int nb_inplace_subtract = 0; - public static int nb_inplace_multiply = 0; - public static int nb_inplace_remainder = 0; - public static int nb_inplace_power = 0; - public static int nb_inplace_lshift = 0; - public static int nb_inplace_rshift = 0; - public static int nb_inplace_and = 0; - public static int nb_inplace_xor = 0; - public static int nb_inplace_or = 0; - public static int nb_floor_divide = 0; - public static int nb_true_divide = 0; - public static int nb_inplace_floor_divide = 0; - public static int nb_inplace_true_divide = 0; - public static int nb_index = 0; - public static int nb_matrix_multiply = 0; - public static int nb_inplace_matrix_multiply = 0; - public static int mp_length = 0; - public static int mp_subscript = 0; - public static int mp_ass_subscript = 0; - public static int sq_length = 0; - public static int sq_concat = 0; - public static int sq_repeat = 0; - public static int sq_item = 0; - public static int was_sq_slice = 0; - public static int sq_ass_item = 0; - public static int was_sq_ass_slice = 0; - public static int sq_contains = 0; - public static int sq_inplace_concat = 0; - public static int sq_inplace_repeat = 0; - public static int bf_getbuffer = 0; - public static int bf_releasebuffer = 0; - public static int name = 0; - public static int ht_slots = 0; - public static int qualname = 0; - public static int ht_cached_keys = 0; - - /* here are optional user slots, followed by the members. */ - public static int members = 0; + public int ob_refcnt { get; private set; } + public int ob_type { get; private set; } + public int ob_size { get; private set; } + public int tp_name { get; private set; } + public int tp_basicsize { get; private set; } + public int tp_itemsize { get; private set; } + public int tp_dealloc { get; private set; } + public int tp_vectorcall_offset { get; private set; } + public int tp_getattr { get; private set; } + public int tp_setattr { get; private set; } + public int tp_as_async { get; private set; } + public int tp_repr { get; private set; } + public int tp_as_number { get; private set; } + public int tp_as_sequence { get; private set; } + public int tp_as_mapping { get; private set; } + public int tp_hash { get; private set; } + public int tp_call { get; private set; } + public int tp_str { get; private set; } + public int tp_getattro { get; private set; } + public int tp_setattro { get; private set; } + public int tp_as_buffer { get; private set; } + public int tp_flags { get; private set; } + public int tp_doc { get; private set; } + public int tp_traverse { get; private set; } + public int tp_clear { get; private set; } + public int tp_richcompare { get; private set; } + public int tp_weaklistoffset { get; private set; } + public int tp_iter { get; private set; } + public int tp_iternext { get; private set; } + public int tp_methods { get; private set; } + public int tp_members { get; private set; } + public int tp_getset { get; private set; } + public int tp_base { get; private set; } + public int tp_dict { get; private set; } + public int tp_descr_get { get; private set; } + public int tp_descr_set { get; private set; } + public int tp_dictoffset { get; private set; } + public int tp_init { get; private set; } + public int tp_alloc { get; private set; } + public int tp_new { get; private set; } + public int tp_free { get; private set; } + public int tp_is_gc { get; private set; } + public int tp_bases { get; private set; } + public int tp_mro { get; private set; } + public int tp_cache { get; private set; } + public int tp_subclasses { get; private set; } + public int tp_weaklist { get; private set; } + public int tp_del { get; private set; } + public int tp_version_tag { get; private set; } + public int tp_finalize { get; private set; } + public int tp_vectorcall { get; private set; } + public int tp_print { get; private set; } + public int am_await { get; private set; } + public int am_aiter { get; private set; } + public int am_anext { get; private set; } + public int nb_add { get; private set; } + public int nb_subtract { get; private set; } + public int nb_multiply { get; private set; } + public int nb_remainder { get; private set; } + public int nb_divmod { get; private set; } + public int nb_power { get; private set; } + public int nb_negative { get; private set; } + public int nb_positive { get; private set; } + public int nb_absolute { get; private set; } + public int nb_bool { get; private set; } + public int nb_invert { get; private set; } + public int nb_lshift { get; private set; } + public int nb_rshift { get; private set; } + public int nb_and { get; private set; } + public int nb_xor { get; private set; } + public int nb_or { get; private set; } + public int nb_int { get; private set; } + public int nb_reserved { get; private set; } + public int nb_float { get; private set; } + public int nb_inplace_add { get; private set; } + public int nb_inplace_subtract { get; private set; } + public int nb_inplace_multiply { get; private set; } + public int nb_inplace_remainder { get; private set; } + public int nb_inplace_power { get; private set; } + public int nb_inplace_lshift { get; private set; } + public int nb_inplace_rshift { get; private set; } + public int nb_inplace_and { get; private set; } + public int nb_inplace_xor { get; private set; } + public int nb_inplace_or { get; private set; } + public int nb_floor_divide { get; private set; } + public int nb_true_divide { get; private set; } + public int nb_inplace_floor_divide { get; private set; } + public int nb_inplace_true_divide { get; private set; } + public int nb_index { get; private set; } + public int nb_matrix_multiply { get; private set; } + public int nb_inplace_matrix_multiply { get; private set; } + public int mp_length { get; private set; } + public int mp_subscript { get; private set; } + public int mp_ass_subscript { get; private set; } + public int sq_length { get; private set; } + public int sq_concat { get; private set; } + public int sq_repeat { get; private set; } + public int sq_item { get; private set; } + public int was_sq_slice { get; private set; } + public int sq_ass_item { get; private set; } + public int was_sq_ass_slice { get; private set; } + public int sq_contains { get; private set; } + public int sq_inplace_concat { get; private set; } + public int sq_inplace_repeat { get; private set; } + public int bf_getbuffer { get; private set; } + public int bf_releasebuffer { get; private set; } + public int name { get; private set; } + public int ht_slots { get; private set; } + public int qualname { get; private set; } + public int ht_cached_keys { get; private set; } } +#if PYTHON38 [StructLayout(LayoutKind.Sequential)] internal struct PyNumberMethods { @@ -223,5 +225,5 @@ internal static partial class SlotTypes }; } -} #endif +} diff --git a/src/runtime/interop39.cs b/src/runtime/interop39.cs index cb2b5b49a..6961d3302 100644 --- a/src/runtime/interop39.cs +++ b/src/runtime/interop39.cs @@ -2,137 +2,140 @@ // Auto-generated by geninterop.py. // DO NOT MODIFY BY HAND. +// ReSharper disable InconsistentNaming +// ReSharper disable IdentifierTypo -#if PYTHON39 using System; -using System.Collections; -using System.Collections.Specialized; +using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; -using System.Reflection; -using System.Text; + +using Python.Runtime.Native; namespace Python.Runtime { + [SuppressMessage("Style", "IDE1006:Naming Styles", + Justification = "Following CPython", + Scope = "type")] [StructLayout(LayoutKind.Sequential)] - internal static partial class TypeOffset + internal class TypeOffset39 : GeneratedTypeOffsets, ITypeOffsets { + public TypeOffset39() { } // Auto-generated from PyHeapTypeObject in Python.h - public static int ob_refcnt = 0; - public static int ob_type = 0; - public static int ob_size = 0; - public static int tp_name = 0; - public static int tp_basicsize = 0; - public static int tp_itemsize = 0; - public static int tp_dealloc = 0; - public static int tp_vectorcall_offset = 0; - public static int tp_getattr = 0; - public static int tp_setattr = 0; - public static int tp_as_async = 0; - public static int tp_repr = 0; - public static int tp_as_number = 0; - public static int tp_as_sequence = 0; - public static int tp_as_mapping = 0; - public static int tp_hash = 0; - public static int tp_call = 0; - public static int tp_str = 0; - public static int tp_getattro = 0; - public static int tp_setattro = 0; - public static int tp_as_buffer = 0; - public static int tp_flags = 0; - public static int tp_doc = 0; - public static int tp_traverse = 0; - public static int tp_clear = 0; - public static int tp_richcompare = 0; - public static int tp_weaklistoffset = 0; - public static int tp_iter = 0; - public static int tp_iternext = 0; - public static int tp_methods = 0; - public static int tp_members = 0; - public static int tp_getset = 0; - public static int tp_base = 0; - public static int tp_dict = 0; - public static int tp_descr_get = 0; - public static int tp_descr_set = 0; - public static int tp_dictoffset = 0; - public static int tp_init = 0; - public static int tp_alloc = 0; - public static int tp_new = 0; - public static int tp_free = 0; - public static int tp_is_gc = 0; - public static int tp_bases = 0; - public static int tp_mro = 0; - public static int tp_cache = 0; - public static int tp_subclasses = 0; - public static int tp_weaklist = 0; - public static int tp_del = 0; - public static int tp_version_tag = 0; - public static int tp_finalize = 0; - public static int tp_vectorcall = 0; - public static int am_await = 0; - public static int am_aiter = 0; - public static int am_anext = 0; - public static int nb_add = 0; - public static int nb_subtract = 0; - public static int nb_multiply = 0; - public static int nb_remainder = 0; - public static int nb_divmod = 0; - public static int nb_power = 0; - public static int nb_negative = 0; - public static int nb_positive = 0; - public static int nb_absolute = 0; - public static int nb_bool = 0; - public static int nb_invert = 0; - public static int nb_lshift = 0; - public static int nb_rshift = 0; - public static int nb_and = 0; - public static int nb_xor = 0; - public static int nb_or = 0; - public static int nb_int = 0; - public static int nb_reserved = 0; - public static int nb_float = 0; - public static int nb_inplace_add = 0; - public static int nb_inplace_subtract = 0; - public static int nb_inplace_multiply = 0; - public static int nb_inplace_remainder = 0; - public static int nb_inplace_power = 0; - public static int nb_inplace_lshift = 0; - public static int nb_inplace_rshift = 0; - public static int nb_inplace_and = 0; - public static int nb_inplace_xor = 0; - public static int nb_inplace_or = 0; - public static int nb_floor_divide = 0; - public static int nb_true_divide = 0; - public static int nb_inplace_floor_divide = 0; - public static int nb_inplace_true_divide = 0; - public static int nb_index = 0; - public static int nb_matrix_multiply = 0; - public static int nb_inplace_matrix_multiply = 0; - public static int mp_length = 0; - public static int mp_subscript = 0; - public static int mp_ass_subscript = 0; - public static int sq_length = 0; - public static int sq_concat = 0; - public static int sq_repeat = 0; - public static int sq_item = 0; - public static int was_sq_slice = 0; - public static int sq_ass_item = 0; - public static int was_sq_ass_slice = 0; - public static int sq_contains = 0; - public static int sq_inplace_concat = 0; - public static int sq_inplace_repeat = 0; - public static int bf_getbuffer = 0; - public static int bf_releasebuffer = 0; - public static int name = 0; - public static int ht_slots = 0; - public static int qualname = 0; - public static int ht_cached_keys = 0; - public static int ht_module = 0; + public int ob_refcnt { get; private set; } + public int ob_type { get; private set; } + public int ob_size { get; private set; } + public int tp_name { get; private set; } + public int tp_basicsize { get; private set; } + public int tp_itemsize { get; private set; } + public int tp_dealloc { get; private set; } + public int tp_vectorcall_offset { get; private set; } + public int tp_getattr { get; private set; } + public int tp_setattr { get; private set; } + public int tp_as_async { get; private set; } + public int tp_repr { get; private set; } + public int tp_as_number { get; private set; } + public int tp_as_sequence { get; private set; } + public int tp_as_mapping { get; private set; } + public int tp_hash { get; private set; } + public int tp_call { get; private set; } + public int tp_str { get; private set; } + public int tp_getattro { get; private set; } + public int tp_setattro { get; private set; } + public int tp_as_buffer { get; private set; } + public int tp_flags { get; private set; } + public int tp_doc { get; private set; } + public int tp_traverse { get; private set; } + public int tp_clear { get; private set; } + public int tp_richcompare { get; private set; } + public int tp_weaklistoffset { get; private set; } + public int tp_iter { get; private set; } + public int tp_iternext { get; private set; } + public int tp_methods { get; private set; } + public int tp_members { get; private set; } + public int tp_getset { get; private set; } + public int tp_base { get; private set; } + public int tp_dict { get; private set; } + public int tp_descr_get { get; private set; } + public int tp_descr_set { get; private set; } + public int tp_dictoffset { get; private set; } + public int tp_init { get; private set; } + public int tp_alloc { get; private set; } + public int tp_new { get; private set; } + public int tp_free { get; private set; } + public int tp_is_gc { get; private set; } + public int tp_bases { get; private set; } + public int tp_mro { get; private set; } + public int tp_cache { get; private set; } + public int tp_subclasses { get; private set; } + public int tp_weaklist { get; private set; } + public int tp_del { get; private set; } + public int tp_version_tag { get; private set; } + public int tp_finalize { get; private set; } + public int tp_vectorcall { get; private set; } + public int am_await { get; private set; } + public int am_aiter { get; private set; } + public int am_anext { get; private set; } + public int nb_add { get; private set; } + public int nb_subtract { get; private set; } + public int nb_multiply { get; private set; } + public int nb_remainder { get; private set; } + public int nb_divmod { get; private set; } + public int nb_power { get; private set; } + public int nb_negative { get; private set; } + public int nb_positive { get; private set; } + public int nb_absolute { get; private set; } + public int nb_bool { get; private set; } + public int nb_invert { get; private set; } + public int nb_lshift { get; private set; } + public int nb_rshift { get; private set; } + public int nb_and { get; private set; } + public int nb_xor { get; private set; } + public int nb_or { get; private set; } + public int nb_int { get; private set; } + public int nb_reserved { get; private set; } + public int nb_float { get; private set; } + public int nb_inplace_add { get; private set; } + public int nb_inplace_subtract { get; private set; } + public int nb_inplace_multiply { get; private set; } + public int nb_inplace_remainder { get; private set; } + public int nb_inplace_power { get; private set; } + public int nb_inplace_lshift { get; private set; } + public int nb_inplace_rshift { get; private set; } + public int nb_inplace_and { get; private set; } + public int nb_inplace_xor { get; private set; } + public int nb_inplace_or { get; private set; } + public int nb_floor_divide { get; private set; } + public int nb_true_divide { get; private set; } + public int nb_inplace_floor_divide { get; private set; } + public int nb_inplace_true_divide { get; private set; } + public int nb_index { get; private set; } + public int nb_matrix_multiply { get; private set; } + public int nb_inplace_matrix_multiply { get; private set; } + public int mp_length { get; private set; } + public int mp_subscript { get; private set; } + public int mp_ass_subscript { get; private set; } + public int sq_length { get; private set; } + public int sq_concat { get; private set; } + public int sq_repeat { get; private set; } + public int sq_item { get; private set; } + public int was_sq_slice { get; private set; } + public int sq_ass_item { get; private set; } + public int was_sq_ass_slice { get; private set; } + public int sq_contains { get; private set; } + public int sq_inplace_concat { get; private set; } + public int sq_inplace_repeat { get; private set; } + public int bf_getbuffer { get; private set; } + public int bf_releasebuffer { get; private set; } + public int name { get; private set; } + public int ht_slots { get; private set; } + public int qualname { get; private set; } + public int ht_cached_keys { get; private set; } + public int ht_module { get; private set; } - /* here are optional user slots, followed by the members. */ - public static int members = 0; } +#if PYTHON39 [StructLayout(LayoutKind.Sequential)] internal struct PyNumberMethods { @@ -223,5 +226,5 @@ internal static partial class SlotTypes }; } -} #endif +} diff --git a/src/runtime/native/ABI.cs b/src/runtime/native/ABI.cs new file mode 100644 index 000000000..dc375cc29 --- /dev/null +++ b/src/runtime/native/ABI.cs @@ -0,0 +1,28 @@ +namespace Python.Runtime.Native +{ + using System; + using System.Globalization; + using System.Linq; + using System.Reflection; + using System.Runtime.InteropServices; + + static class ABI + { + internal static void Initialize(Version version, BorrowedReference pyType) + { + string offsetsClassSuffix = string.Format(CultureInfo.InvariantCulture, + "{0}{1}", version.Major, version.Minor); + + var thisAssembly = Assembly.GetExecutingAssembly(); + + string className = "Python.Runtime.TypeOffset" + offsetsClassSuffix; + Type typeOffsetsClass = thisAssembly.GetType(className, throwOnError: false); + if (typeOffsetsClass is null) + throw new NotSupportedException($"Python ABI v{version} is not supported"); + var typeOffsets = (ITypeOffsets)Activator.CreateInstance(typeOffsetsClass); + TypeOffset.Use(typeOffsets); + + ManagedDataOffsets.Magic = Marshal.ReadInt32(pyType.DangerousGetAddress(), TypeOffset.tp_basicsize); + } + } +} diff --git a/src/runtime/native/GeneratedTypeOffsets.cs b/src/runtime/native/GeneratedTypeOffsets.cs new file mode 100644 index 000000000..bf10df124 --- /dev/null +++ b/src/runtime/native/GeneratedTypeOffsets.cs @@ -0,0 +1,22 @@ +namespace Python.Runtime.Native +{ + using System; + using System.Reflection; + using System.Runtime.InteropServices; + + [StructLayout(LayoutKind.Sequential)] + abstract class GeneratedTypeOffsets + { + protected GeneratedTypeOffsets() + { + var type = this.GetType(); + var offsetProperties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public); + int fieldSize = IntPtr.Size; + for (int fieldIndex = 0; fieldIndex < offsetProperties.Length; fieldIndex++) + { + int offset = fieldIndex * fieldSize; + offsetProperties[fieldIndex].SetValue(this, offset, index: null); + } + } + } +} diff --git a/src/runtime/native/ITypeOffsets.cs b/src/runtime/native/ITypeOffsets.cs new file mode 100644 index 000000000..54faeba8a --- /dev/null +++ b/src/runtime/native/ITypeOffsets.cs @@ -0,0 +1,56 @@ +// ReSharper disable InconsistentNaming +// ReSharper disable IdentifierTypo +namespace Python.Runtime.Native +{ + using System.Diagnostics.CodeAnalysis; + + [SuppressMessage("Style", "IDE1006:Naming Styles", + Justification = "Following CPython", + Scope = "type")] + interface ITypeOffsets + { + int bf_getbuffer { get; } + int mp_ass_subscript { get; } + int mp_length { get; } + int mp_subscript { get; } + int name { get; } + int nb_add { get; } + int ob_size { get; } + int ob_type { get; } + int qualname { get; } + int sq_contains { get; } + int sq_length { get; } + int tp_alloc { get; } + int tp_as_buffer { get; } + int tp_as_mapping { get; } + int tp_as_number { get; } + int tp_as_sequence { get; } + int tp_base { get; } + int tp_bases { get; } + int tp_basicsize { get; } + int tp_call { get; } + int tp_clear { get; } + int tp_dealloc { get; } + int tp_descr_get { get; } + int tp_descr_set { get; } + int tp_dict { get; } + int tp_dictoffset { get; } + int tp_flags { get; } + int tp_free { get; } + int tp_getattro { get; } + int tp_hash { get; } + int tp_is_gc { get; } + int tp_itemsize { get; } + int tp_iter { get; } + int tp_iternext { get; } + int tp_methods { get; } + int tp_mro { get; } + int tp_name { get; } + int tp_new { get; } + int tp_repr { get; } + int tp_richcompare { 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 new file mode 100644 index 000000000..e93d13f9b --- /dev/null +++ b/src/runtime/native/TypeOffset.cs @@ -0,0 +1,106 @@ +// ReSharper disable InconsistentNaming +// ReSharper disable IdentifierTypo +namespace Python.Runtime +{ + using System; + using System.Collections.Generic; + using System.Diagnostics; + using System.Diagnostics.CodeAnalysis; + using System.Linq; + using System.Reflection; + + using Python.Runtime.Native; + + [SuppressMessage("Style", "IDE1006:Naming Styles", + Justification = "Following CPython", + Scope = "type")] + static partial class TypeOffset + { + internal static int bf_getbuffer { get; private set; } + internal static int mp_ass_subscript { get; private set; } + internal static int mp_length { get; private set; } + internal static int mp_subscript { get; private set; } + internal static int name { get; private set; } + internal static int nb_add { get; private set; } + internal static int ob_size { get; private set; } + internal static int ob_type { get; private set; } + internal static int qualname { get; private set; } + internal static int sq_contains { get; private set; } + internal static int sq_length { get; private set; } + internal static int tp_alloc { get; private set; } + internal static int tp_as_buffer { get; private set; } + internal static int tp_as_mapping { get; private set; } + internal static int tp_as_number { get; private set; } + internal static int tp_as_sequence { get; private set; } + internal static int tp_base { get; private set; } + internal static int tp_bases { get; private set; } + internal static int tp_basicsize { get; private set; } + internal static int tp_call { get; private set; } + internal static int tp_clear { get; private set; } + internal static int tp_dealloc { get; private set; } + internal static int tp_descr_get { get; private set; } + internal static int tp_descr_set { get; private set; } + internal static int tp_dict { get; private set; } + internal static int tp_dictoffset { get; private set; } + internal static int tp_flags { get; private set; } + internal static int tp_free { get; private set; } + internal static int tp_getattro { get; private set; } + internal static int tp_hash { get; private set; } + internal static int tp_is_gc { get; private set; } + internal static int tp_itemsize { get; private set; } + internal static int tp_iter { get; private set; } + internal static int tp_iternext { get; private set; } + internal static int tp_methods { get; private set; } + internal static int tp_mro { get; private set; } + internal static int tp_name { get; private set; } + 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_setattro { get; private set; } + internal static int tp_str { get; private set; } + internal static int tp_traverse { get; private set; } + + internal static void Use(ITypeOffsets offsets) + { + if (offsets is null) throw new ArgumentNullException(nameof(offsets)); + + var offsetProperties = typeof(TypeOffset).GetProperties(FieldFlags); + foreach (var offsetProperty in offsetProperties) + { + var sourceProperty = typeof(ITypeOffsets).GetProperty(offsetProperty.Name); + int value = (int)sourceProperty.GetValue(offsets, null); + offsetProperty.SetValue(obj: null, value: value, index: null); + } + + ValidateUnusedTypeOffsetProperties(offsetProperties); + } + + static readonly BindingFlags FieldFlags = BindingFlags.NonPublic | BindingFlags.Static; + internal static Dictionary GetOffsets() + { + var properties = typeof(TypeOffset).GetProperties(FieldFlags); + return properties.ToDictionary( + keySelector: p => p.Name, + elementSelector: p => (int)p.GetValue(obj: null, index: null)); + } + + internal static int GetOffsetUncached(string name) + { + var property = typeof(TypeOffset).GetProperty(name, FieldFlags); + return (int)property.GetValue(obj: null, index: null); + } + + [Conditional("DEBUG")] + static void ValidateUnusedTypeOffsetProperties(PropertyInfo[] offsetProperties) + { + var extras = new List(); + foreach (var property in typeof(ITypeOffsets).GetProperties(FieldFlags)) + { + if (!offsetProperties.Any(prop => prop.Name == property.Name)) + extras.Add(property.Name); + } + extras.Sort(); + Debug.Assert(extras.Count == 0, message: string.Join(", ", extras)); + } + } +} diff --git a/src/runtime/runtime.cs b/src/runtime/runtime.cs index 10aa165c8..00f90ea67 100644 --- a/src/runtime/runtime.cs +++ b/src/runtime/runtime.cs @@ -6,6 +6,7 @@ using System.Text; using System.Threading; using System.Collections.Generic; +using Python.Runtime.Native; using Python.Runtime.Platform; using System.Linq; @@ -113,11 +114,13 @@ internal static Version PyVersion { get { - var versionTuple = new PyTuple(PySys_GetObject("version_info")); - var major = versionTuple[0].As(); - var minor = versionTuple[1].As(); - var micro = versionTuple[2].As(); - return new Version(major, minor, micro); + using (var versionTuple = new PyTuple(PySys_GetObject("version_info"))) + { + var major = versionTuple[0].As(); + var minor = versionTuple[1].As(); + var micro = versionTuple[2].As(); + return new Version(major, minor, micro); + } } } @@ -166,14 +169,18 @@ internal static void Initialize(bool initSigs = false, ShutdownMode mode = Shutd IsFinalizing = false; InternString.Initialize(); + + InitPyMembers(); + + ABI.Initialize(PyVersion, + pyType: new BorrowedReference(PyTypeType)); + GenericUtil.Reset(); PyScopeManager.Reset(); ClassManager.Reset(); ClassDerivedObject.Reset(); TypeManager.Initialize(); - InitPyMembers(); - // Initialize data about the platform we're running on. We need // this for the type manager and potentially other details. Must // happen after caching the python types, above. diff --git a/src/runtime/typemanager.cs b/src/runtime/typemanager.cs index 43c160bc3..17fdb793e 100644 --- a/src/runtime/typemanager.cs +++ b/src/runtime/typemanager.cs @@ -675,9 +675,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) { - Type typeOffset = typeof(TypeOffset); - FieldInfo fi = typeOffset.GetField(name); - var offset = (int)fi.GetValue(typeOffset); + int offset = ManagedDataOffsets.GetSlotOffset(name); if (!canOverride && Marshal.ReadIntPtr(type, offset) != IntPtr.Zero) { diff --git a/tools/geninterop/geninterop.py b/tools/geninterop/geninterop.py index e74221e46..6feddd44d 100644 --- a/tools/geninterop/geninterop.py +++ b/tools/geninterop/geninterop.py @@ -244,42 +244,39 @@ def preprocess_python_headers(): def gen_interop_head(writer): - defines = [ - "PYTHON{0}{1}".format(PY_MAJOR, PY_MINOR) - ] - if hasattr(sys, "abiflags"): if "d" in sys.abiflags: defines.append("PYTHON_WITH_PYDEBUG") + raise NotImplementedError if "m" in sys.abiflags: defines.append("PYTHON_WITH_PYMALLOC") + raise NotImplementedError if "u" in sys.abiflags: defines.append("PYTHON_WITH_WIDE_UNICODE") + raise NotImplementedError filename = os.path.basename(__file__) - defines_str = " && ".join(defines) class_definition = """ // Auto-generated by %s. // DO NOT MODIFY BY HAND. +// ReSharper disable InconsistentNaming +// ReSharper disable IdentifierTypo -#if %s using System; -using System.Collections; -using System.Collections.Specialized; +using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; -using System.Reflection; -using System.Text; + +using Python.Runtime.Native; namespace Python.Runtime -{ -""" % (filename, defines_str) +{""" % filename writer.extend(class_definition) def gen_interop_tail(writer): - tail = """} -#endif + tail = """#endif +} """ writer.extend(tail) @@ -288,22 +285,24 @@ def gen_heap_type_members(parser, writer): """Generate the TypeOffset C# class""" members = parser.get_struct_members("PyHeapTypeObject") class_definition = """ + [SuppressMessage("Style", "IDE1006:Naming Styles", + Justification = "Following CPython", + Scope = "type")] + [StructLayout(LayoutKind.Sequential)] - internal static partial class TypeOffset - { + internal class TypeOffset{0}{1} : GeneratedTypeOffsets, ITypeOffsets + {{ + public TypeOffset{0}{1}() {{ }} // Auto-generated from PyHeapTypeObject in Python.h -""" +""".format(PY_MAJOR, PY_MINOR) # All the members are sizeof(void*) so we don't need to do any # extra work to determine the size based on the type. for name, tpy in members: name = _typeoffset_member_renames.get(name, name) - class_definition += " public static int %s = 0;\n" % name + class_definition += " public int %s { get; private set; }\n" % name - class_definition += """ - /* here are optional user slots, followed by the members. */ - public static int members = 0; - } + class_definition += """ } """ writer.extend(class_definition) @@ -351,6 +350,10 @@ def main(): gen_interop_head(writer) gen_heap_type_members(ast_parser, writer) + + ver_define = "PYTHON{0}{1}".format(PY_MAJOR, PY_MINOR) + writer.append(code="#if " + ver_define) + slots_types = [ "PyNumberMethods", "PySequenceMethods", From 6dd92ad9fb3300042ca2551f312463346f1c3a96 Mon Sep 17 00:00:00 2001 From: Victor Milovanov Date: Tue, 24 Nov 2020 12:23:29 -0800 Subject: [PATCH 2/4] implemented NativeTypeOffset for installation with setup.py --- .gitignore | 2 ++ src/runtime/interop36.cs | 2 ++ src/runtime/interop37.cs | 2 ++ src/runtime/interop38.cs | 2 ++ src/runtime/interop39.cs | 2 ++ src/runtime/native/ABI.cs | 6 +++++- tools/geninterop/geninterop.py | 29 ++++++++++++----------------- 7 files changed, 27 insertions(+), 18 deletions(-) diff --git a/.gitignore b/.gitignore index 1e494b12d..87f7fe4ed 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +/src/runtime/interopNative.cs + # General binaries and Build results *.dll *.exe diff --git a/src/runtime/interop36.cs b/src/runtime/interop36.cs index 1ac567e09..84ff49e5d 100644 --- a/src/runtime/interop36.cs +++ b/src/runtime/interop36.cs @@ -2,6 +2,8 @@ // Auto-generated by geninterop.py. // DO NOT MODIFY BY HAND. +// Python 3.6: ABI flags: '' + // ReSharper disable InconsistentNaming // ReSharper disable IdentifierTypo diff --git a/src/runtime/interop37.cs b/src/runtime/interop37.cs index ca091e27c..ed6c05394 100644 --- a/src/runtime/interop37.cs +++ b/src/runtime/interop37.cs @@ -2,6 +2,8 @@ // Auto-generated by geninterop.py. // DO NOT MODIFY BY HAND. +// Python 3.7: ABI flags: '' + // ReSharper disable InconsistentNaming // ReSharper disable IdentifierTypo diff --git a/src/runtime/interop38.cs b/src/runtime/interop38.cs index 031d25c1b..841f0ec58 100644 --- a/src/runtime/interop38.cs +++ b/src/runtime/interop38.cs @@ -2,6 +2,8 @@ // Auto-generated by geninterop.py. // DO NOT MODIFY BY HAND. +// Python 3.8: ABI flags: '' + // ReSharper disable InconsistentNaming // ReSharper disable IdentifierTypo diff --git a/src/runtime/interop39.cs b/src/runtime/interop39.cs index 6961d3302..f9d2a14a7 100644 --- a/src/runtime/interop39.cs +++ b/src/runtime/interop39.cs @@ -2,6 +2,8 @@ // Auto-generated by geninterop.py. // DO NOT MODIFY BY HAND. +// Python 3.9: ABI flags: '' + // ReSharper disable InconsistentNaming // ReSharper disable IdentifierTypo diff --git a/src/runtime/native/ABI.cs b/src/runtime/native/ABI.cs index dc375cc29..76337c797 100644 --- a/src/runtime/native/ABI.cs +++ b/src/runtime/native/ABI.cs @@ -15,8 +15,12 @@ internal static void Initialize(Version version, BorrowedReference pyType) var thisAssembly = Assembly.GetExecutingAssembly(); + const string nativeTypeOffsetClassName = "Python.Runtime.NativeTypeOffset"; string className = "Python.Runtime.TypeOffset" + offsetsClassSuffix; - Type typeOffsetsClass = thisAssembly.GetType(className, 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); if (typeOffsetsClass is null) throw new NotSupportedException($"Python ABI v{version} is not supported"); var typeOffsets = (ITypeOffsets)Activator.CreateInstance(typeOffsetsClass); diff --git a/tools/geninterop/geninterop.py b/tools/geninterop/geninterop.py index 6feddd44d..bc3e35170 100644 --- a/tools/geninterop/geninterop.py +++ b/tools/geninterop/geninterop.py @@ -244,22 +244,15 @@ def preprocess_python_headers(): def gen_interop_head(writer): - if hasattr(sys, "abiflags"): - if "d" in sys.abiflags: - defines.append("PYTHON_WITH_PYDEBUG") - raise NotImplementedError - if "m" in sys.abiflags: - defines.append("PYTHON_WITH_PYMALLOC") - raise NotImplementedError - if "u" in sys.abiflags: - defines.append("PYTHON_WITH_WIDE_UNICODE") - raise NotImplementedError - filename = os.path.basename(__file__) + abi_flags = getattr(sys, "abiflags", "") + py_ver = "{0}.{1}".format(PY_MAJOR, PY_MINOR) class_definition = """ // Auto-generated by %s. // DO NOT MODIFY BY HAND. +// Python %s: ABI flags: '%s' + // ReSharper disable InconsistentNaming // ReSharper disable IdentifierTypo @@ -270,7 +263,7 @@ def gen_interop_head(writer): using Python.Runtime.Native; namespace Python.Runtime -{""" % filename +{""" % (filename, py_ver, abi_flags) writer.extend(class_definition) @@ -281,20 +274,21 @@ def gen_interop_tail(writer): writer.extend(tail) -def gen_heap_type_members(parser, writer): +def gen_heap_type_members(parser, writer, type_name = None): """Generate the TypeOffset C# class""" members = parser.get_struct_members("PyHeapTypeObject") + type_name = type_name or "TypeOffset{0}{1}".format(PY_MAJOR, PY_MINOR) class_definition = """ [SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "Following CPython", Scope = "type")] [StructLayout(LayoutKind.Sequential)] - internal class TypeOffset{0}{1} : GeneratedTypeOffsets, ITypeOffsets + internal class {0} : GeneratedTypeOffsets, ITypeOffsets {{ - public TypeOffset{0}{1}() {{ }} + public {0}() {{ }} // Auto-generated from PyHeapTypeObject in Python.h -""".format(PY_MAJOR, PY_MINOR) +""".format(type_name) # All the members are sizeof(void*) so we don't need to do any # extra work to determine the size based on the type. @@ -347,9 +341,10 @@ def main(): writer = Writer() # generate the C# code + offsets_type_name = "NativeTypeOffset" if len(sys.argv) > 1 else None gen_interop_head(writer) - gen_heap_type_members(ast_parser, writer) + gen_heap_type_members(ast_parser, writer, type_name = offsets_type_name) ver_define = "PYTHON{0}{1}".format(PY_MAJOR, PY_MINOR) writer.append(code="#if " + ver_define) From e36a027944ba632b8d70388555791e18f24f0538 Mon Sep 17 00:00:00 2001 From: Victor Milovanov Date: Tue, 24 Nov 2020 18:25:48 -0800 Subject: [PATCH 3/4] fixed missing ITypeOffset members np_inplace_* --- src/runtime/native/ITypeOffsets.cs | 2 ++ src/runtime/native/TypeOffset.cs | 46 ++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/src/runtime/native/ITypeOffsets.cs b/src/runtime/native/ITypeOffsets.cs index 54faeba8a..31344c66d 100644 --- a/src/runtime/native/ITypeOffsets.cs +++ b/src/runtime/native/ITypeOffsets.cs @@ -15,6 +15,8 @@ interface ITypeOffsets int mp_subscript { get; } int name { get; } int nb_add { get; } + int nb_inplace_add { get; } + int nb_inplace_subtract { get; } int ob_size { get; } int ob_type { get; } int qualname { get; } diff --git a/src/runtime/native/TypeOffset.cs b/src/runtime/native/TypeOffset.cs index e93d13f9b..ae2c8001e 100644 --- a/src/runtime/native/TypeOffset.cs +++ b/src/runtime/native/TypeOffset.cs @@ -22,6 +22,8 @@ static partial class TypeOffset internal static int mp_subscript { get; private set; } internal static int name { get; private set; } internal static int nb_add { get; private set; } + internal static int nb_inplace_add { get; private set; } + internal static int nb_inplace_subtract { get; private set; } internal static int ob_size { get; private set; } internal static int ob_type { get; private set; } internal static int qualname { get; private set; } @@ -73,6 +75,7 @@ internal static void Use(ITypeOffsets offsets) } ValidateUnusedTypeOffsetProperties(offsetProperties); + ValidateRequiredOffsetsPresent(offsetProperties); } static readonly BindingFlags FieldFlags = BindingFlags.NonPublic | BindingFlags.Static; @@ -102,5 +105,48 @@ static void ValidateUnusedTypeOffsetProperties(PropertyInfo[] offsetProperties) extras.Sort(); Debug.Assert(extras.Count == 0, message: string.Join(", ", extras)); } + + [Conditional("DEBUG")] + static void ValidateRequiredOffsetsPresent(PropertyInfo[] offsetProperties) + { + var present = new HashSet(offsetProperties.Select(p => p.Name)); + var missing = new HashSet(); + + var thisAssembly = Assembly.GetExecutingAssembly(); + var managedTypes = thisAssembly.GetTypes() + .Where(typeof(ManagedType).IsAssignableFrom) + .ToList(); + foreach (var managedType in managedTypes) + { + var slots = managedType.GetMethods(BindingFlags.Public | BindingFlags.Static); + foreach(var slot in slots) + if (!present.Contains(slot.Name)) + missing.Add(slot.Name); + } + foreach (string notSlot in new[] + { + "__instancecheck__", + "__subclasscheck__", + "_AtExit", + "AddReference", + "FinalizeObject", + "FindAssembly", + "get_SuppressDocs", + "get_SuppressOverloads", + "GetClrType", + "getPreload", + "Initialize", + "ListAssemblies", + "Release", + "Reset", + "set_SuppressDocs", + "set_SuppressOverloads", + "setPreload", + }) + missing.Remove(notSlot); + + Debug.Assert(missing.Count == 0, + "Missing slots: " + string.Join(", ", missing)); + } } } From f9a3a53b4040646d29858e0fcc4defbfa4b20353 Mon Sep 17 00:00:00 2001 From: Victor Milovanov Date: Sun, 29 Nov 2020 16:35:13 -0800 Subject: [PATCH 4/4] revert slot-related parts of 1b466df0 to avoid conditional compilation --- src/runtime/interop36.cs | 93 ------------------------------- src/runtime/interop37.cs | 93 ------------------------------- src/runtime/interop38.cs | 93 ------------------------------- src/runtime/interop39.cs | 94 -------------------------------- src/runtime/native/TypeOffset.cs | 6 ++ src/runtime/typemanager.cs | 26 +-------- tools/geninterop/geninterop.py | 35 +----------- 7 files changed, 9 insertions(+), 431 deletions(-) diff --git a/src/runtime/interop36.cs b/src/runtime/interop36.cs index 84ff49e5d..4b3b8bfb9 100644 --- a/src/runtime/interop36.cs +++ b/src/runtime/interop36.cs @@ -133,97 +133,4 @@ public TypeOffset36() { } public int qualname { get; private set; } public int ht_cached_keys { get; private set; } } - -#if PYTHON36 - [StructLayout(LayoutKind.Sequential)] - internal struct PyNumberMethods - { - public IntPtr nb_add; - public IntPtr nb_subtract; - public IntPtr nb_multiply; - public IntPtr nb_remainder; - public IntPtr nb_divmod; - public IntPtr nb_power; - public IntPtr nb_negative; - public IntPtr nb_positive; - public IntPtr nb_absolute; - public IntPtr nb_bool; - public IntPtr nb_invert; - public IntPtr nb_lshift; - public IntPtr nb_rshift; - public IntPtr nb_and; - public IntPtr nb_xor; - public IntPtr nb_or; - public IntPtr nb_int; - public IntPtr nb_reserved; - public IntPtr nb_float; - public IntPtr nb_inplace_add; - public IntPtr nb_inplace_subtract; - public IntPtr nb_inplace_multiply; - public IntPtr nb_inplace_remainder; - public IntPtr nb_inplace_power; - public IntPtr nb_inplace_lshift; - public IntPtr nb_inplace_rshift; - public IntPtr nb_inplace_and; - public IntPtr nb_inplace_xor; - public IntPtr nb_inplace_or; - public IntPtr nb_floor_divide; - public IntPtr nb_true_divide; - public IntPtr nb_inplace_floor_divide; - public IntPtr nb_inplace_true_divide; - public IntPtr nb_index; - public IntPtr nb_matrix_multiply; - public IntPtr nb_inplace_matrix_multiply; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct PySequenceMethods - { - public IntPtr sq_length; - public IntPtr sq_concat; - public IntPtr sq_repeat; - public IntPtr sq_item; - public IntPtr was_sq_slice; - public IntPtr sq_ass_item; - public IntPtr was_sq_ass_slice; - public IntPtr sq_contains; - public IntPtr sq_inplace_concat; - public IntPtr sq_inplace_repeat; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct PyMappingMethods - { - public IntPtr mp_length; - public IntPtr mp_subscript; - public IntPtr mp_ass_subscript; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct PyAsyncMethods - { - public IntPtr am_await; - public IntPtr am_aiter; - public IntPtr am_anext; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct PyBufferProcs - { - public IntPtr bf_getbuffer; - public IntPtr bf_releasebuffer; - } - - internal static partial class SlotTypes - { - public static readonly Type[] Types = { - typeof(PyNumberMethods), - typeof(PySequenceMethods), - typeof(PyMappingMethods), - typeof(PyAsyncMethods), - typeof(PyBufferProcs), - }; - } - -#endif } diff --git a/src/runtime/interop37.cs b/src/runtime/interop37.cs index ed6c05394..951cb1068 100644 --- a/src/runtime/interop37.cs +++ b/src/runtime/interop37.cs @@ -133,97 +133,4 @@ public TypeOffset37() { } public int qualname { get; private set; } public int ht_cached_keys { get; private set; } } - -#if PYTHON37 - [StructLayout(LayoutKind.Sequential)] - internal struct PyNumberMethods - { - public IntPtr nb_add; - public IntPtr nb_subtract; - public IntPtr nb_multiply; - public IntPtr nb_remainder; - public IntPtr nb_divmod; - public IntPtr nb_power; - public IntPtr nb_negative; - public IntPtr nb_positive; - public IntPtr nb_absolute; - public IntPtr nb_bool; - public IntPtr nb_invert; - public IntPtr nb_lshift; - public IntPtr nb_rshift; - public IntPtr nb_and; - public IntPtr nb_xor; - public IntPtr nb_or; - public IntPtr nb_int; - public IntPtr nb_reserved; - public IntPtr nb_float; - public IntPtr nb_inplace_add; - public IntPtr nb_inplace_subtract; - public IntPtr nb_inplace_multiply; - public IntPtr nb_inplace_remainder; - public IntPtr nb_inplace_power; - public IntPtr nb_inplace_lshift; - public IntPtr nb_inplace_rshift; - public IntPtr nb_inplace_and; - public IntPtr nb_inplace_xor; - public IntPtr nb_inplace_or; - public IntPtr nb_floor_divide; - public IntPtr nb_true_divide; - public IntPtr nb_inplace_floor_divide; - public IntPtr nb_inplace_true_divide; - public IntPtr nb_index; - public IntPtr nb_matrix_multiply; - public IntPtr nb_inplace_matrix_multiply; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct PySequenceMethods - { - public IntPtr sq_length; - public IntPtr sq_concat; - public IntPtr sq_repeat; - public IntPtr sq_item; - public IntPtr was_sq_slice; - public IntPtr sq_ass_item; - public IntPtr was_sq_ass_slice; - public IntPtr sq_contains; - public IntPtr sq_inplace_concat; - public IntPtr sq_inplace_repeat; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct PyMappingMethods - { - public IntPtr mp_length; - public IntPtr mp_subscript; - public IntPtr mp_ass_subscript; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct PyAsyncMethods - { - public IntPtr am_await; - public IntPtr am_aiter; - public IntPtr am_anext; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct PyBufferProcs - { - public IntPtr bf_getbuffer; - public IntPtr bf_releasebuffer; - } - - internal static partial class SlotTypes - { - public static readonly Type[] Types = { - typeof(PyNumberMethods), - typeof(PySequenceMethods), - typeof(PyMappingMethods), - typeof(PyAsyncMethods), - typeof(PyBufferProcs), - }; - } - -#endif } diff --git a/src/runtime/interop38.cs b/src/runtime/interop38.cs index 841f0ec58..67a40eabd 100644 --- a/src/runtime/interop38.cs +++ b/src/runtime/interop38.cs @@ -135,97 +135,4 @@ public TypeOffset38() { } public int qualname { get; private set; } public int ht_cached_keys { get; private set; } } - -#if PYTHON38 - [StructLayout(LayoutKind.Sequential)] - internal struct PyNumberMethods - { - public IntPtr nb_add; - public IntPtr nb_subtract; - public IntPtr nb_multiply; - public IntPtr nb_remainder; - public IntPtr nb_divmod; - public IntPtr nb_power; - public IntPtr nb_negative; - public IntPtr nb_positive; - public IntPtr nb_absolute; - public IntPtr nb_bool; - public IntPtr nb_invert; - public IntPtr nb_lshift; - public IntPtr nb_rshift; - public IntPtr nb_and; - public IntPtr nb_xor; - public IntPtr nb_or; - public IntPtr nb_int; - public IntPtr nb_reserved; - public IntPtr nb_float; - public IntPtr nb_inplace_add; - public IntPtr nb_inplace_subtract; - public IntPtr nb_inplace_multiply; - public IntPtr nb_inplace_remainder; - public IntPtr nb_inplace_power; - public IntPtr nb_inplace_lshift; - public IntPtr nb_inplace_rshift; - public IntPtr nb_inplace_and; - public IntPtr nb_inplace_xor; - public IntPtr nb_inplace_or; - public IntPtr nb_floor_divide; - public IntPtr nb_true_divide; - public IntPtr nb_inplace_floor_divide; - public IntPtr nb_inplace_true_divide; - public IntPtr nb_index; - public IntPtr nb_matrix_multiply; - public IntPtr nb_inplace_matrix_multiply; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct PySequenceMethods - { - public IntPtr sq_length; - public IntPtr sq_concat; - public IntPtr sq_repeat; - public IntPtr sq_item; - public IntPtr was_sq_slice; - public IntPtr sq_ass_item; - public IntPtr was_sq_ass_slice; - public IntPtr sq_contains; - public IntPtr sq_inplace_concat; - public IntPtr sq_inplace_repeat; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct PyMappingMethods - { - public IntPtr mp_length; - public IntPtr mp_subscript; - public IntPtr mp_ass_subscript; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct PyAsyncMethods - { - public IntPtr am_await; - public IntPtr am_aiter; - public IntPtr am_anext; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct PyBufferProcs - { - public IntPtr bf_getbuffer; - public IntPtr bf_releasebuffer; - } - - internal static partial class SlotTypes - { - public static readonly Type[] Types = { - typeof(PyNumberMethods), - typeof(PySequenceMethods), - typeof(PyMappingMethods), - typeof(PyAsyncMethods), - typeof(PyBufferProcs), - }; - } - -#endif } diff --git a/src/runtime/interop39.cs b/src/runtime/interop39.cs index f9d2a14a7..cf3acc984 100644 --- a/src/runtime/interop39.cs +++ b/src/runtime/interop39.cs @@ -134,99 +134,5 @@ public TypeOffset39() { } public int qualname { get; private set; } public int ht_cached_keys { get; private set; } public int ht_module { get; private set; } - - } - -#if PYTHON39 - [StructLayout(LayoutKind.Sequential)] - internal struct PyNumberMethods - { - public IntPtr nb_add; - public IntPtr nb_subtract; - public IntPtr nb_multiply; - public IntPtr nb_remainder; - public IntPtr nb_divmod; - public IntPtr nb_power; - public IntPtr nb_negative; - public IntPtr nb_positive; - public IntPtr nb_absolute; - public IntPtr nb_bool; - public IntPtr nb_invert; - public IntPtr nb_lshift; - public IntPtr nb_rshift; - public IntPtr nb_and; - public IntPtr nb_xor; - public IntPtr nb_or; - public IntPtr nb_int; - public IntPtr nb_reserved; - public IntPtr nb_float; - public IntPtr nb_inplace_add; - public IntPtr nb_inplace_subtract; - public IntPtr nb_inplace_multiply; - public IntPtr nb_inplace_remainder; - public IntPtr nb_inplace_power; - public IntPtr nb_inplace_lshift; - public IntPtr nb_inplace_rshift; - public IntPtr nb_inplace_and; - public IntPtr nb_inplace_xor; - public IntPtr nb_inplace_or; - public IntPtr nb_floor_divide; - public IntPtr nb_true_divide; - public IntPtr nb_inplace_floor_divide; - public IntPtr nb_inplace_true_divide; - public IntPtr nb_index; - public IntPtr nb_matrix_multiply; - public IntPtr nb_inplace_matrix_multiply; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct PySequenceMethods - { - public IntPtr sq_length; - public IntPtr sq_concat; - public IntPtr sq_repeat; - public IntPtr sq_item; - public IntPtr was_sq_slice; - public IntPtr sq_ass_item; - public IntPtr was_sq_ass_slice; - public IntPtr sq_contains; - public IntPtr sq_inplace_concat; - public IntPtr sq_inplace_repeat; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct PyMappingMethods - { - public IntPtr mp_length; - public IntPtr mp_subscript; - public IntPtr mp_ass_subscript; } - - [StructLayout(LayoutKind.Sequential)] - internal struct PyAsyncMethods - { - public IntPtr am_await; - public IntPtr am_aiter; - public IntPtr am_anext; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct PyBufferProcs - { - public IntPtr bf_getbuffer; - public IntPtr bf_releasebuffer; - } - - internal static partial class SlotTypes - { - public static readonly Type[] Types = { - typeof(PyNumberMethods), - typeof(PySequenceMethods), - typeof(PyMappingMethods), - typeof(PyAsyncMethods), - typeof(PyBufferProcs), - }; - } - -#endif } diff --git a/src/runtime/native/TypeOffset.cs b/src/runtime/native/TypeOffset.cs index ae2c8001e..0c51110da 100644 --- a/src/runtime/native/TypeOffset.cs +++ b/src/runtime/native/TypeOffset.cs @@ -66,9 +66,12 @@ internal static void Use(ITypeOffsets offsets) { if (offsets is null) throw new ArgumentNullException(nameof(offsets)); + slotNames.Clear(); var offsetProperties = typeof(TypeOffset).GetProperties(FieldFlags); foreach (var offsetProperty in offsetProperties) { + slotNames.Add(offsetProperty.Name); + var sourceProperty = typeof(ITypeOffsets).GetProperty(offsetProperty.Name); int value = (int)sourceProperty.GetValue(offsets, null); offsetProperty.SetValue(obj: null, value: value, index: null); @@ -93,6 +96,9 @@ internal static int GetOffsetUncached(string name) return (int)property.GetValue(obj: null, index: null); } + static readonly HashSet slotNames = new HashSet(); + internal static bool IsSupportedSlotName(string name) => slotNames.Contains(name); + [Conditional("DEBUG")] static void ValidateUnusedTypeOffsetProperties(PropertyInfo[] offsetProperties) { diff --git a/src/runtime/typemanager.cs b/src/runtime/typemanager.cs index 17fdb793e..b1403081e 100644 --- a/src/runtime/typemanager.cs +++ b/src/runtime/typemanager.cs @@ -623,8 +623,9 @@ internal static void InitializeSlots(IntPtr type, Type impl, SlotsHolder slotsHo foreach (MethodInfo method in methods) { string name = method.Name; - if (!name.StartsWith("tp_") && !SlotTypes.IsSlotName(name)) + if (!name.StartsWith("tp_") && !TypeOffset.IsSupportedSlotName(name)) { + Debug.Assert(!name.Contains("_") || name.StartsWith("_") || method.IsSpecialName); continue; } @@ -927,27 +928,4 @@ public static IntPtr CreateObjectType() return A; } } - - - static partial class SlotTypes - { - private static Dictionary _nameMap = new Dictionary(); - - static SlotTypes() - { - foreach (var type in Types) - { - FieldInfo[] fields = type.GetFields(); - foreach (var fi in fields) - { - _nameMap[fi.Name] = type; - } - } - } - - public static bool IsSlotName(string name) - { - return _nameMap.ContainsKey(name); - } - } } diff --git a/tools/geninterop/geninterop.py b/tools/geninterop/geninterop.py index bc3e35170..0d5b83b30 100644 --- a/tools/geninterop/geninterop.py +++ b/tools/geninterop/geninterop.py @@ -268,8 +268,7 @@ def gen_interop_head(writer): def gen_interop_tail(writer): - tail = """#endif -} + tail = """} """ writer.extend(tail) @@ -297,7 +296,6 @@ def gen_heap_type_members(parser, writer, type_name = None): class_definition += " public int %s { get; private set; }\n" % name class_definition += """ } - """ writer.extend(class_definition) @@ -316,19 +314,6 @@ def gen_structure_code(parser, writer, type_name, indent): out() return True - -def gen_supported_slot_record(writer, types, indent): - out = writer.append - out(indent, "internal static partial class SlotTypes") - out(indent, "{") - out(indent + 1, "public static readonly Type[] Types = {") - for name in types: - out(indent + 2, "typeof(%s)," % name) - out(indent + 1, "};") - out(indent, "}") - out() - - def main(): # preprocess Python.h and build the AST python_h = preprocess_python_headers() @@ -346,24 +331,6 @@ def main(): gen_heap_type_members(ast_parser, writer, type_name = offsets_type_name) - ver_define = "PYTHON{0}{1}".format(PY_MAJOR, PY_MINOR) - writer.append(code="#if " + ver_define) - - slots_types = [ - "PyNumberMethods", - "PySequenceMethods", - "PyMappingMethods", - "PyAsyncMethods", - "PyBufferProcs", - ] - supported_types = [] - indent = 1 - for type_name in slots_types: - if not gen_structure_code(ast_parser, writer, type_name, indent): - continue - supported_types.append(type_name) - gen_supported_slot_record(writer, supported_types, indent) - gen_interop_tail(writer) interop_cs = writer.to_string()