| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 782eff8 commit 4a92d80
10 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -24,6 +24,7 @@ This document follows the conventions laid out in [Keep a CHANGELOG][]. | |||
| 24 | 24 | - Added argument types information to "No method matches given arguments" message | |
| 25 | 25 | - Moved wheel import in setup.py inside of a try/except to prevent pip collection failures | |
| 26 | 26 | - Removes PyLong_GetMax and PyClass_New when targetting Python3 | |
| 27 | + - Improved performance of calls from Python to C# | ||
| 27 | 28 | - Added support for converting python iterators to C# arrays | |
| 28 | 29 | - Changed usage of obselete function GetDelegateForFunctionPointer(IntPtr, Type) to GetDelegateForFunctionPointer<TDelegate>(IntPtr) | |
| 29 | 30 | - When calling C# from Python, enable passing argument of any type to a parameter of C# type `object` by wrapping it into `PyObject` instance. ([#881][i881]) | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -30,14 +30,14 @@ public void SetUp() | |||
| 30 | 30 | public void ReadInt64Property() | |
| 31 | 31 | { | |
| 32 | 32 | double optimisticPerfRatio = GetOptimisticPerfRatio(this.summary.Reports); | |
| 33 | - AssertPerformanceIsBetterOrSame(optimisticPerfRatio, target: 0.66); | ||
| 33 | + AssertPerformanceIsBetterOrSame(optimisticPerfRatio, target: 0.57); | ||
| 34 | 34 | } | |
| 35 | 35 | ||
| 36 | 36 | [Test] | |
| 37 | 37 | public void WriteInt64Property() | |
| 38 | 38 | { | |
| 39 | 39 | double optimisticPerfRatio = GetOptimisticPerfRatio(this.summary.Reports); | |
| 40 | - AssertPerformanceIsBetterOrSame(optimisticPerfRatio, target: 0.64); | ||
| 40 | + AssertPerformanceIsBetterOrSame(optimisticPerfRatio, target: 0.57); | ||
| 41 | 41 | } | |
| 42 | 42 | ||
| 43 | 43 | static double GetOptimisticPerfRatio( | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -291,7 +291,7 @@ public static IntPtr tp_repr(IntPtr ob) | |||
| 291 | 291 | public static void tp_dealloc(IntPtr ob) | |
| 292 | 292 | { | |
| 293 | 293 | ManagedType self = GetManagedObject(ob); | |
| 294 | - IntPtr dict = Marshal.ReadIntPtr(ob, ObjectOffset.DictOffset(ob)); | ||
| 294 | + IntPtr dict = Marshal.ReadIntPtr(ob, ObjectOffset.TypeDictOffset(self.tpHandle)); | ||
| 295 | 295 | if (dict != IntPtr.Zero) | |
| 296 | 296 | { | |
| 297 | 297 | Runtime.XDecref(dict); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -877,7 +877,7 @@ public static void Finalize(IPythonDerivedType obj) | |||
| 877 | 877 | // the C# object is being destroyed which must mean there are no more | |
| 878 | 878 | // references to the Python object as well so now we can dealloc the | |
| 879 | 879 | // python object. | |
| 880 | - IntPtr dict = Marshal.ReadIntPtr(self.pyHandle, ObjectOffset.DictOffset(self.pyHandle)); | ||
| 880 | + IntPtr dict = Marshal.ReadIntPtr(self.pyHandle, ObjectOffset.TypeDictOffset(self.tpHandle)); | ||
| 881 | 881 | if (dict != IntPtr.Zero) | |
| 882 | 882 | { | |
| 883 | 883 | Runtime.XDecref(dict); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -14,11 +14,11 @@ internal CLRObject(object ob, IntPtr tp) | |||
| 14 | 14 | long flags = Util.ReadCLong(tp, TypeOffset.tp_flags); | |
| 15 | 15 | if ((flags & TypeFlags.Subclass) != 0) | |
| 16 | 16 | { | |
| 17 | - IntPtr dict = Marshal.ReadIntPtr(py, ObjectOffset.DictOffset(tp)); | ||
| 17 | + IntPtr dict = Marshal.ReadIntPtr(py, ObjectOffset.TypeDictOffset(tp)); | ||
| 18 | 18 | if (dict == IntPtr.Zero) | |
| 19 | 19 | { | |
| 20 | 20 | dict = Runtime.PyDict_New(); | |
| 21 | - Marshal.WriteIntPtr(py, ObjectOffset.DictOffset(tp), dict); | ||
| 21 | + Marshal.WriteIntPtr(py, ObjectOffset.TypeDictOffset(tp), dict); | ||
| 22 | 22 | } | |
| 23 | 23 | } | |
| 24 | 24 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,6 +1,7 @@ | |||
| 1 | 1 | using System; | |
| 2 | 2 | using System.Collections; | |
| 3 | - using System.Collections.Specialized; | ||
| 3 | + using System.Collections.Generic; | ||
| 4 | + using System.Diagnostics; | ||
| 4 | 5 | using System.Runtime.InteropServices; | |
| 5 | 6 | using System.Reflection; | |
| 6 | 7 | using System.Text; | |
@@ -68,11 +69,47 @@ public ModulePropertyAttribute() | |||
| 68 | 69 | } | |
| 69 | 70 | } | |
| 70 | 71 | ||
| 72 | + internal static class ManagedDataOffsets | ||
| 73 | + { | ||
| 74 | + static ManagedDataOffsets() | ||
| 75 | + { | ||
| 76 | + FieldInfo[] fi = typeof(ManagedDataOffsets).GetFields(BindingFlags.Static | BindingFlags.Public); | ||
| 77 | + for (int i = 0; i < fi.Length; i++) | ||
| 78 | + { | ||
| 79 | + fi[i].SetValue(null, -(i * IntPtr.Size) - IntPtr.Size); | ||
| 80 | + } | ||
| 71 | 81 | ||
| 72 | - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] | ||
| 73 | - internal class ObjectOffset | ||
| 82 | + size = fi.Length * IntPtr.Size; | ||
| 83 | + } | ||
| 84 | + | ||
| 85 | + public static readonly int ob_data; | ||
| 86 | + public static readonly int ob_dict; | ||
| 87 | + | ||
| 88 | + private static int BaseOffset(IntPtr type) | ||
| 89 | + { | ||
| 90 | + Debug.Assert(type != IntPtr.Zero); | ||
| 91 | + int typeSize = Marshal.ReadInt32(type, TypeOffset.tp_basicsize); | ||
| 92 | + Debug.Assert(typeSize > 0 && typeSize <= ExceptionOffset.Size()); | ||
| 93 | + return typeSize; | ||
| 94 | + } | ||
| 95 | + public static int DataOffset(IntPtr type) | ||
| 96 | + { | ||
| 97 | + return BaseOffset(type) + ob_data; | ||
| 98 | + } | ||
| 99 | + | ||
| 100 | + public static int DictOffset(IntPtr type) | ||
| 101 | + { | ||
| 102 | + return BaseOffset(type) + ob_dict; | ||
| 103 | + } | ||
| 104 | + | ||
| 105 | + public static int Size { get { return size; } } | ||
| 106 | + | ||
| 107 | + private static readonly int size; | ||
| 108 | + } | ||
| 109 | + | ||
| 110 | + internal static class OriginalObjectOffsets | ||
| 74 | 111 | { | |
| 75 | - static ObjectOffset() | ||
| 112 | + static OriginalObjectOffsets() | ||
| 76 | 113 | { | |
| 77 | 114 | int size = IntPtr.Size; | |
| 78 | 115 | var n = 0; // Py_TRACE_REFS add two pointers to PyObject_HEAD | |
@@ -83,42 +120,58 @@ static ObjectOffset() | |||
| 83 | 120 | #endif | |
| 84 | 121 | ob_refcnt = (n + 0) * size; | |
| 85 | 122 | ob_type = (n + 1) * size; | |
| 86 | - ob_dict = (n + 2) * size; | ||
| 87 | - ob_data = (n + 3) * size; | ||
| 88 | 123 | } | |
| 89 | 124 | ||
| 90 | - public static int magic(IntPtr ob) | ||
| 125 | + public static int Size { get { return size; } } | ||
| 126 | + | ||
| 127 | + private static readonly int size = | ||
| 128 | + #if PYTHON_WITH_PYDEBUG | ||
| 129 | + 4 * IntPtr.Size; | ||
| 130 | + #else | ||
| 131 | + 2 * IntPtr.Size; | ||
| 132 | + #endif | ||
| 133 | + | ||
| 134 | + #if PYTHON_WITH_PYDEBUG | ||
| 135 | + public static int _ob_next; | ||
| 136 | + public static int _ob_prev; | ||
| 137 | + #endif | ||
| 138 | + public static int ob_refcnt; | ||
| 139 | + public static int ob_type; | ||
| 140 | + } | ||
| 141 | + | ||
| 142 | + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] | ||
| 143 | + internal class ObjectOffset | ||
| 144 | + { | ||
| 145 | + static ObjectOffset() | ||
| 146 | + { | ||
| 147 | + #if PYTHON_WITH_PYDEBUG | ||
| 148 | + _ob_next = OriginalObjectOffsets._ob_next; | ||
| 149 | + _ob_prev = OriginalObjectOffsets._ob_prev; | ||
| 150 | + #endif | ||
| 151 | + ob_refcnt = OriginalObjectOffsets.ob_refcnt; | ||
| 152 | + ob_type = OriginalObjectOffsets.ob_type; | ||
| 153 | + | ||
| 154 | + size = OriginalObjectOffsets.Size + ManagedDataOffsets.Size; | ||
| 155 | + } | ||
| 156 | + | ||
| 157 | + public static int magic(IntPtr type) | ||
| 91 | 158 | { | |
| 92 | - if ((Runtime.PyObject_TypeCheck(ob, Exceptions.BaseException) || | ||
| 93 | - (Runtime.PyType_Check(ob) && Runtime.PyType_IsSubtype(ob, Exceptions.BaseException)))) | ||
| 94 | - { | ||
| 95 | - return ExceptionOffset.ob_data; | ||
| 96 | - } | ||
| 97 | - return ob_data; | ||
| 159 | + return ManagedDataOffsets.DataOffset(type); | ||
| 98 | 160 | } | |
| 99 | 161 | ||
| 100 | - public static int DictOffset(IntPtr ob) | ||
| 162 | + public static int TypeDictOffset(IntPtr type) | ||
| 101 | 163 | { | |
| 102 | - if ((Runtime.PyObject_TypeCheck(ob, Exceptions.BaseException) || | ||
| 103 | - (Runtime.PyType_Check(ob) && Runtime.PyType_IsSubtype(ob, Exceptions.BaseException)))) | ||
| 104 | - { | ||
| 105 | - return ExceptionOffset.ob_dict; | ||
| 106 | - } | ||
| 107 | - return ob_dict; | ||
| 164 | + return ManagedDataOffsets.DictOffset(type); | ||
| 108 | 165 | } | |
| 109 | 166 | ||
| 110 | - public static int Size(IntPtr ob) | ||
| 167 | + public static int Size(IntPtr pyType) | ||
| 111 | 168 | { | |
| 112 | - if ((Runtime.PyObject_TypeCheck(ob, Exceptions.BaseException) || | ||
| 113 | - (Runtime.PyType_Check(ob) && Runtime.PyType_IsSubtype(ob, Exceptions.BaseException)))) | ||
| 169 | + if (IsException(pyType)) | ||
| 114 | 170 | { | |
| 115 | 171 | return ExceptionOffset.Size(); | |
| 116 | 172 | } | |
| 117 | - #if PYTHON_WITH_PYDEBUG | ||
| 118 | - return 6 * IntPtr.Size; | ||
| 119 | - #else | ||
| 120 | - return 4 * IntPtr.Size; | ||
| 121 | - #endif | ||
| 173 | + | ||
| 174 | + return size; | ||
| 122 | 175 | } | |
| 123 | 176 | ||
| 124 | 177 | #if PYTHON_WITH_PYDEBUG | |
@@ -127,8 +180,15 @@ public static int Size(IntPtr ob) | |||
| 127 | 180 | #endif | |
| 128 | 181 | public static int ob_refcnt; | |
| 129 | 182 | public static int ob_type; | |
| 130 | - private static int ob_dict; | ||
| 131 | - private static int ob_data; | ||
| 183 | + private static readonly int size; | ||
| 184 | + | ||
| 185 | + private static bool IsException(IntPtr pyObject) | ||
| 186 | + { | ||
| 187 | + var type = Runtime.PyObject_TYPE(pyObject); | ||
| 188 | + return Runtime.PyType_IsSameAsOrSubtype(type, ofType: Exceptions.BaseException) | ||
| 189 | + || Runtime.PyType_IsSameAsOrSubtype(type, ofType: Runtime.PyTypeType) | ||
| 190 | + && Runtime.PyType_IsSubtype(pyObject, Exceptions.BaseException); | ||
| 191 | + } | ||
| 132 | 192 | } | |
| 133 | 193 | ||
| 134 | 194 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] | |
@@ -137,19 +197,17 @@ internal class ExceptionOffset | |||
| 137 | 197 | static ExceptionOffset() | |
| 138 | 198 | { | |
| 139 | 199 | Type type = typeof(ExceptionOffset); | |
| 140 | - FieldInfo[] fi = type.GetFields(); | ||
| 141 | - int size = IntPtr.Size; | ||
| 200 | + FieldInfo[] fi = type.GetFields(BindingFlags.Static | BindingFlags.Public); | ||
| 142 | 201 | for (int i = 0; i < fi.Length; i++) | |
| 143 | 202 | { | |
| 144 | - fi[i].SetValue(null, (i * size) + ObjectOffset.ob_type + size); | ||
| 203 | + fi[i].SetValue(null, (i * IntPtr.Size) + OriginalObjectOffsets.Size); | ||
| 145 | 204 | } | |
| 146 | - } | ||
| 147 | 205 | ||
| 148 | - public static int Size() | ||
| 149 | - { | ||
| 150 | - return ob_data + IntPtr.Size; | ||
| 206 | + size = fi.Length * IntPtr.Size + OriginalObjectOffsets.Size + ManagedDataOffsets.Size; | ||
| 151 | 207 | } | |
| 152 | 208 | ||
| 209 | + public static int Size() { return size; } | ||
| 210 | + | ||
| 153 | 211 | // PyException_HEAD | |
| 154 | 212 | // (start after PyObject_HEAD) | |
| 155 | 213 | public static int dict = 0; | |
@@ -163,9 +221,7 @@ public static int Size() | |||
| 163 | 221 | public static int suppress_context = 0; | |
| 164 | 222 | #endif | |
| 165 | 223 | ||
| 166 | - // extra c# data | ||
| 167 | - public static int ob_dict; | ||
| 168 | - public static int ob_data; | ||
| 224 | + private static readonly int size; | ||
| 169 | 225 | } | |
| 170 | 226 | ||
| 171 | 227 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -33,7 +33,7 @@ internal static ManagedType GetManagedObject(IntPtr ob) | |||
| 33 | 33 | { | |
| 34 | 34 | IntPtr op = tp == ob | |
| 35 | 35 | ? Marshal.ReadIntPtr(tp, TypeOffset.magic()) | |
| 36 | - : Marshal.ReadIntPtr(ob, ObjectOffset.magic(ob)); | ||
| 36 | + : Marshal.ReadIntPtr(ob, ObjectOffset.magic(tp)); | ||
| 37 | 37 | if (op == IntPtr.Zero) | |
| 38 | 38 | { | |
| 39 | 39 | return null; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -54,7 +54,7 @@ public ModuleObject(string name) | |||
| 54 | 54 | Runtime.XDecref(pyfilename); | |
| 55 | 55 | Runtime.XDecref(pydocstring); | |
| 56 | 56 | ||
| 57 | - Marshal.WriteIntPtr(pyHandle, ObjectOffset.DictOffset(pyHandle), dict); | ||
| 57 | + Marshal.WriteIntPtr(pyHandle, ObjectOffset.TypeDictOffset(tpHandle), dict); | ||
| 58 | 58 | ||
| 59 | 59 | InitializeModuleMembers(); | |
| 60 | 60 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1889,6 +1889,11 @@ internal static bool PyObject_TypeCheck(IntPtr ob, IntPtr tp) | |||
| 1889 | 1889 | return (t == tp) || PyType_IsSubtype(t, tp); | |
| 1890 | 1890 | } | |
| 1891 | 1891 | ||
| 1892 | + internal static bool PyType_IsSameAsOrSubtype(IntPtr type, IntPtr ofType) | ||
| 1893 | + { | ||
| 1894 | + return (type == ofType) || PyType_IsSubtype(type, ofType); | ||
| 1895 | + } | ||
| 1896 | + | ||
| 1892 | 1897 | [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] | |
| 1893 | 1898 | internal static extern IntPtr PyType_GenericNew(IntPtr type, IntPtr args, IntPtr kw); | |
| 1894 | 1899 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -87,7 +87,7 @@ internal static IntPtr CreateType(Type impl) | |||
| 87 | 87 | // Set tp_basicsize to the size of our managed instance objects. | |
| 88 | 88 | Marshal.WriteIntPtr(type, TypeOffset.tp_basicsize, (IntPtr)ob_size); | |
| 89 | 89 | ||
| 90 | - var offset = (IntPtr)ObjectOffset.DictOffset(type); | ||
| 90 | + var offset = (IntPtr)ObjectOffset.TypeDictOffset(type); | ||
| 91 | 91 | Marshal.WriteIntPtr(type, TypeOffset.tp_dictoffset, offset); | |
| 92 | 92 | ||
| 93 | 93 | InitializeSlots(type, impl); | |
@@ -125,17 +125,17 @@ internal static IntPtr CreateType(ManagedType impl, Type clrType) | |||
| 125 | 125 | ||
| 126 | 126 | IntPtr base_ = IntPtr.Zero; | |
| 127 | 127 | int ob_size = ObjectOffset.Size(Runtime.PyTypeType); | |
| 128 | - int tp_dictoffset = ObjectOffset.DictOffset(Runtime.PyTypeType); | ||
| 129 | 128 | ||
| 130 | 129 | // XXX Hack, use a different base class for System.Exception | |
| 131 | 130 | // Python 2.5+ allows new style class exceptions but they *must* | |
| 132 | 131 | // subclass BaseException (or better Exception). | |
| 133 | 132 | if (typeof(Exception).IsAssignableFrom(clrType)) | |
| 134 | 133 | { | |
| 135 | 134 | ob_size = ObjectOffset.Size(Exceptions.Exception); | |
| 136 | - tp_dictoffset = ObjectOffset.DictOffset(Exceptions.Exception); | ||
| 137 | 135 | } | |
| 138 | 136 | ||
| 137 | + int tp_dictoffset = ob_size + ManagedDataOffsets.ob_dict; | ||
| 138 | + | ||
| 139 | 139 | if (clrType == typeof(Exception)) | |
| 140 | 140 | { | |
| 141 | 141 | base_ = Exceptions.Exception; | |
| Back | FazBrowse Home | New Git URL |
0 commit comments