From 7f530f2a7d7ce7a492042d752a9fab27b84478bb Mon Sep 17 00:00:00 2001 From: amos402 Date: Thu, 28 Nov 2019 03:12:01 +0800 Subject: [PATCH 1/4] Add exception helper --- .editorconfig | 2 +- src/runtime/pythonexception.cs | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/.editorconfig b/.editorconfig index 9e10931d0..d64f74bc1 100644 --- a/.editorconfig +++ b/.editorconfig @@ -25,7 +25,7 @@ dotnet_sort_system_directives_first = true dotnet_separate_import_directive_groups = true [*.cs] -csharp_new_line_before_open_brace = true +csharp_new_line_before_open_brace = all csharp_new_line_before_else = true csharp_new_line_before_catch = true csharp_new_line_before_finally = true diff --git a/src/runtime/pythonexception.cs b/src/runtime/pythonexception.cs index 295a63b3d..8a6a24799 100644 --- a/src/runtime/pythonexception.cs +++ b/src/runtime/pythonexception.cs @@ -1,4 +1,5 @@ using System; +using System.Runtime.CompilerServices; namespace Python.Runtime { @@ -190,5 +191,21 @@ public static bool Matches(IntPtr ob) { return Runtime.PyErr_ExceptionMatches(ob) != 0; } + + public static void ThrowIfIsNull(IntPtr ob) + { + if (ob == IntPtr.Zero) + { + throw new PythonException(); + } + } + + public static void ThrowIfIsNotZero(int value) + { + if (value != 0) + { + throw new PythonException(); + } + } } } From 90e44bd9c3c0f04fee2f5226145887dc57a0a174 Mon Sep 17 00:00:00 2001 From: amos402 Date: Sat, 30 Nov 2019 17:01:39 +0800 Subject: [PATCH 2/4] Make the caller of `Interop.GetThunk` handle thunk's lifecycle(unfinished) --- src/runtime/interop.cs | 53 ++++++++++++++++++++++++++---------- src/runtime/methodwrapper.cs | 6 ++-- src/runtime/typemanager.cs | 13 +++++---- 3 files changed, 51 insertions(+), 21 deletions(-) diff --git a/src/runtime/interop.cs b/src/runtime/interop.cs index 4ae4b61e0..f59521448 100644 --- a/src/runtime/interop.cs +++ b/src/runtime/interop.cs @@ -4,6 +4,7 @@ using System.Runtime.InteropServices; using System.Reflection; using System.Text; +using System.Collections.Generic; namespace Python.Runtime { @@ -334,7 +335,7 @@ internal class TypeFlags internal class Interop { - private static ArrayList keepAlive; + private static List keepAlive; private static Hashtable pmap; static Interop() @@ -351,8 +352,7 @@ static Interop() p[item.Name] = item; } - keepAlive = new ArrayList(); - Marshal.AllocHGlobal(IntPtr.Size); + keepAlive = new List(); pmap = new Hashtable(); pmap["tp_dealloc"] = p["DestructorFunc"]; @@ -449,7 +449,7 @@ internal static Type GetPrototype(string name) return pmap[name] as Type; } - internal static IntPtr GetThunk(MethodInfo method, string funcType = null) + internal static ThunkInfo GetThunk(MethodInfo method, string funcType = null) { Type dt; if (funcType != null) @@ -457,18 +457,15 @@ internal static IntPtr GetThunk(MethodInfo method, string funcType = null) else dt = GetPrototype(method.Name); - if (dt != null) + if (dt == null) { - IntPtr tmp = Marshal.AllocHGlobal(IntPtr.Size); - Delegate d = Delegate.CreateDelegate(dt, method); - Thunk cb = new Thunk(d); - Marshal.StructureToPtr(cb, tmp, false); - IntPtr fp = Marshal.ReadIntPtr(tmp, 0); - Marshal.FreeHGlobal(tmp); - keepAlive.Add(d); - return fp; + return ThunkInfo.Empty; } - return IntPtr.Zero; + Delegate d = Delegate.CreateDelegate(dt, method); + var info = new ThunkInfo(d); + // TODO: remove keepAlive when #958 merged, let the lifecycle of ThunkInfo transfer to caller. + keepAlive.Add(info); + return info; } [UnmanagedFunctionPointer(CallingConvention.Cdecl)] @@ -522,4 +519,32 @@ public Thunk(Delegate d) fn = d; } } + + internal class ThunkInfo + { + public readonly Delegate Target; + public readonly IntPtr Address; + + public static readonly ThunkInfo Empty = new ThunkInfo(null); + + public ThunkInfo(Delegate target) + { + if (target == null) + { + return; + } + Target = target; + Thunk cb = new Thunk(target); + IntPtr tmp = Marshal.AllocHGlobal(IntPtr.Size); + try + { + Marshal.StructureToPtr(cb, tmp, false); + Address = Marshal.ReadIntPtr(tmp, 0); + } + finally + { + Marshal.FreeHGlobal(tmp); + } + } + } } diff --git a/src/runtime/methodwrapper.cs b/src/runtime/methodwrapper.cs index 2f3ce3ef2..8c19a7768 100644 --- a/src/runtime/methodwrapper.cs +++ b/src/runtime/methodwrapper.cs @@ -13,17 +13,19 @@ internal class MethodWrapper public IntPtr mdef; public IntPtr ptr; + private ThunkInfo _thunk; + public MethodWrapper(Type type, string name, string funcType = null) { // Turn the managed method into a function pointer - IntPtr fp = Interop.GetThunk(type.GetMethod(name), funcType); + _thunk = Interop.GetThunk(type.GetMethod(name), funcType); // Allocate and initialize a PyMethodDef structure to represent // the managed method, then create a PyCFunction. mdef = Runtime.PyMem_Malloc(4 * IntPtr.Size); - TypeManager.WriteMethodDef(mdef, name, fp, 0x0003); + TypeManager.WriteMethodDef(mdef, name, _thunk.Address, 0x0003); ptr = Runtime.PyCFunction_NewEx(mdef, IntPtr.Zero, IntPtr.Zero); } diff --git a/src/runtime/typemanager.cs b/src/runtime/typemanager.cs index 9a98e9ebb..80fd40d7a 100644 --- a/src/runtime/typemanager.cs +++ b/src/runtime/typemanager.cs @@ -335,16 +335,18 @@ internal static IntPtr CreateMetaType(Type impl) // 4 int-ptrs in size. IntPtr mdef = Runtime.PyMem_Malloc(3 * 4 * IntPtr.Size); IntPtr mdefStart = mdef; + ThunkInfo thunkInfo = Interop.GetThunk(typeof(MetaType).GetMethod("__instancecheck__"), "BinaryFunc"); mdef = WriteMethodDef( mdef, "__instancecheck__", - Interop.GetThunk(typeof(MetaType).GetMethod("__instancecheck__"), "BinaryFunc") + thunkInfo.Address ); + thunkInfo = Interop.GetThunk(typeof(MetaType).GetMethod("__subclasscheck__"), "BinaryFunc"); mdef = WriteMethodDef( mdef, "__subclasscheck__", - Interop.GetThunk(typeof(MetaType).GetMethod("__subclasscheck__"), "BinaryFunc") + thunkInfo.Address ); // FIXME: mdef is not used @@ -705,7 +707,8 @@ internal static void InitializeSlots(IntPtr type, Type impl) continue; } - InitializeSlot(type, Interop.GetThunk(method), name); + var thunkInfo = Interop.GetThunk(method); + InitializeSlot(type, thunkInfo.Address, name); seen.Add(name); } @@ -723,8 +726,8 @@ internal static void InitializeSlots(IntPtr type, Type impl) // These have to be defined, though, so by default we fill these with // static C# functions from this class. - var ret0 = Interop.GetThunk(((Func)Return0).Method); - var ret1 = Interop.GetThunk(((Func)Return1).Method); + var ret0 = Interop.GetThunk(((Func)Return0).Method).Address; + var ret1 = Interop.GetThunk(((Func)Return1).Method).Address; if (native != null) { From 169b1c2bc6cae0e4e61602e40e6042c9b1b63bd5 Mon Sep 17 00:00:00 2001 From: amos402 Date: Wed, 18 Dec 2019 00:41:52 +0800 Subject: [PATCH 3/4] Resolve merge conflict --- src/runtime/typemanager.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/runtime/typemanager.cs b/src/runtime/typemanager.cs index ba686a703..bb920b74f 100644 --- a/src/runtime/typemanager.cs +++ b/src/runtime/typemanager.cs @@ -204,8 +204,8 @@ internal static IntPtr CreateType(ManagedType impl, Type clrType) static void InitializeSlot(IntPtr type, int slotOffset, MethodInfo method) { - IntPtr thunk = Interop.GetThunk(method); - Marshal.WriteIntPtr(type, slotOffset, thunk); + var thunk = Interop.GetThunk(method); + Marshal.WriteIntPtr(type, slotOffset, thunk.Address); } internal static IntPtr CreateSubType(IntPtr py_name, IntPtr py_base_type, IntPtr py_dict) From a2e43ec419228ce51c852288aa76251cc4d4c71a Mon Sep 17 00:00:00 2001 From: amos402 Date: Wed, 18 Dec 2019 00:45:21 +0800 Subject: [PATCH 4/4] Use Marshal.GetFunctionPointerForDelegate instead of Marshal + Thunk --- src/runtime/interop.cs | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/runtime/interop.cs b/src/runtime/interop.cs index f59521448..0f813c2d1 100644 --- a/src/runtime/interop.cs +++ b/src/runtime/interop.cs @@ -534,17 +534,7 @@ public ThunkInfo(Delegate target) return; } Target = target; - Thunk cb = new Thunk(target); - IntPtr tmp = Marshal.AllocHGlobal(IntPtr.Size); - try - { - Marshal.StructureToPtr(cb, tmp, false); - Address = Marshal.ReadIntPtr(tmp, 0); - } - finally - { - Marshal.FreeHGlobal(tmp); - } + Address = Marshal.GetFunctionPointerForDelegate(target); } } }