X Tutup
using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Runtime.InteropServices; using Python.Runtime.Reflection; using System.Reflection; namespace Python.Runtime { /// /// This file defines objects to support binary interop with the Python /// runtime. Generally, the definitions here need to be kept up to date /// when moving to new Python versions. /// [Serializable] [AttributeUsage(AttributeTargets.All)] public class DocStringAttribute : Attribute { public DocStringAttribute(string docStr) { DocString = docStr; } public string DocString { get; } } [Serializable] [AttributeUsage(AttributeTargets.Method | AttributeTargets.Delegate)] internal class ModuleFunctionAttribute : Attribute { public ModuleFunctionAttribute() { } } [Serializable] [AttributeUsage(AttributeTargets.Method | AttributeTargets.Delegate)] internal class ForbidPythonThreadsAttribute : Attribute { public ForbidPythonThreadsAttribute() { } } [Serializable] [AttributeUsage(AttributeTargets.Property)] internal class ModulePropertyAttribute : Attribute { public ModulePropertyAttribute() { } } /// /// TypeFlags(): The actual bit values for the Type Flags stored /// in a class. /// Note that the two values reserved for stackless have been put /// to good use as PythonNet specific flags (Managed and Subclass) /// // Py_TPFLAGS_* [Flags] public enum TypeFlags: long { HeapType = (1 << 9), BaseType = (1 << 10), Ready = (1 << 12), Readying = (1 << 13), HaveGC = (1 << 14), // 15 and 16 are reserved for stackless HaveStacklessExtension = 0, /* XXX Reusing reserved constants */ /// PythonNet specific HasClrInstance = (1 << 15), /// PythonNet specific Subclass = (1 << 16), /* Objects support nb_index in PyNumberMethods */ HaveVersionTag = (1 << 18), ValidVersionTag = (1 << 19), IsAbstract = (1 << 20), HaveNewBuffer = (1 << 21), // TODO: Implement FastSubclass functions IntSubclass = (1 << 23), LongSubclass = (1 << 24), ListSubclass = (1 << 25), TupleSubclass = (1 << 26), StringSubclass = (1 << 27), UnicodeSubclass = (1 << 28), DictSubclass = (1 << 29), BaseExceptionSubclass = (1 << 30), TypeSubclass = (1 << 31), Default = ( HaveStacklessExtension | HaveVersionTag), } // This class defines the function prototypes (delegates) used for low // level integration with the CPython runtime. It also provides name // based lookup of the correct prototype for a particular Python type // slot and utilities for generating method thunks for managed methods. internal class Interop { static readonly Dictionary delegateTypes = new(); internal static Type GetPrototype(MethodInfo method) { if (delegateTypes.TryGetValue(method, out var delegateType)) return delegateType; var parameters = method.GetParameters().Select(p => new ParameterHelper(p)).ToArray(); foreach (var candidate in typeof(Interop).GetNestedTypes()) { if (!typeof(Delegate).IsAssignableFrom(candidate)) continue; MethodInfo invoke = candidate.GetMethod("Invoke"); var candiateParameters = invoke.GetParameters(); if (candiateParameters.Length != parameters.Length) continue; var parametersMatch = parameters.Zip(candiateParameters, (expected, actual) => expected.Matches(actual)) .All(matches => matches); if (!parametersMatch) continue; if (invoke.ReturnType != method.ReturnType) continue; delegateTypes.Add(method, candidate); return candidate; } throw new NotImplementedException(method.ToString()); } internal static Dictionary allocatedThunks = new(); internal static ThunkInfo GetThunk(MethodInfo method) { Type dt = GetPrototype(method); Delegate d = Delegate.CreateDelegate(dt, method); return GetThunk(d); } internal static ThunkInfo GetThunk(Delegate @delegate) { var info = new ThunkInfo(@delegate); allocatedThunks[info.Address] = @delegate; return info; } [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate NewReference B_N(BorrowedReference ob); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate NewReference BB_N(BorrowedReference ob, BorrowedReference a); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate NewReference BBB_N(BorrowedReference ob, BorrowedReference a1, BorrowedReference a2); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate int B_I32(BorrowedReference ob); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate int BB_I32(BorrowedReference ob, BorrowedReference a); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate int BBB_I32(BorrowedReference ob, BorrowedReference a1, BorrowedReference a2); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate int BP_I32(BorrowedReference ob, IntPtr arg); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate IntPtr B_P(BorrowedReference ob); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate NewReference BBI32_N(BorrowedReference ob, BorrowedReference a1, int a2); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate NewReference BP_N(BorrowedReference ob, IntPtr arg); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate void N_V(NewReference ob); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate int BPP_I32(BorrowedReference ob, IntPtr a1, IntPtr a2); } internal class ThunkInfo { public readonly Delegate Target; public readonly IntPtr Address; public ThunkInfo(Delegate target) { Debug.Assert(target is not null); Target = target!; Address = Marshal.GetFunctionPointerForDelegate(target); } } [StructLayout(LayoutKind.Sequential)] struct PyMethodDef { public IntPtr ml_name; public IntPtr ml_meth; public int ml_flags; public IntPtr ml_doc; } }
X Tutup