using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Runtime.InteropServices; using System.Reflection; using System.Text; 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 { return docStr; } set { docStr = value; } } private string docStr; } [Serializable] [AttributeUsage(AttributeTargets.Method | AttributeTargets.Delegate)] internal class PythonMethodAttribute : Attribute { public PythonMethodAttribute() { } } [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: int { 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), HaveIndex = (1 << 17), /* 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 { private static Hashtable pmap; static Interop() { // Here we build a mapping of PyTypeObject slot names to the // appropriate prototype (delegate) type to use for the slot. Type[] items = typeof(Interop).GetNestedTypes(); Hashtable p = new Hashtable(); for (int i = 0; i < items.Length; i++) { Type item = items[i]; p[item.Name] = item; } pmap = new Hashtable(); pmap["tp_dealloc"] = p["DestructorFunc"]; pmap["tp_print"] = p["PrintFunc"]; pmap["tp_getattr"] = p["BinaryFunc"]; pmap["tp_setattr"] = p["ObjObjArgFunc"]; pmap["tp_compare"] = p["ObjObjFunc"]; pmap["tp_repr"] = p["UnaryFunc"]; pmap["tp_hash"] = p["UnaryFunc"]; pmap["tp_call"] = p["TernaryFunc"]; pmap["tp_str"] = p["UnaryFunc"]; pmap["tp_getattro"] = p["BinaryFunc"]; pmap["tp_setattro"] = p["ObjObjArgFunc"]; pmap["tp_traverse"] = p["ObjObjArgFunc"]; pmap["tp_clear"] = p["InquiryFunc"]; pmap["tp_richcompare"] = p["RichCmpFunc"]; pmap["tp_iter"] = p["UnaryFunc"]; pmap["tp_iternext"] = p["UnaryFunc"]; pmap["tp_descr_get"] = p["TernaryFunc"]; pmap["tp_descr_set"] = p["ObjObjArgFunc"]; pmap["tp_init"] = p["ObjObjArgFunc"]; pmap["tp_alloc"] = p["IntArgFunc"]; pmap["tp_new"] = p["TernaryFunc"]; pmap["tp_free"] = p["DestructorFunc"]; pmap["tp_is_gc"] = p["InquiryFunc"]; pmap["nb_add"] = p["BinaryFunc"]; pmap["nb_subtract"] = p["BinaryFunc"]; pmap["nb_multiply"] = p["BinaryFunc"]; pmap["nb_remainder"] = p["BinaryFunc"]; pmap["nb_divmod"] = p["BinaryFunc"]; pmap["nb_power"] = p["TernaryFunc"]; pmap["nb_negative"] = p["UnaryFunc"]; pmap["nb_positive"] = p["UnaryFunc"]; pmap["nb_absolute"] = p["UnaryFunc"]; pmap["nb_nonzero"] = p["InquiryFunc"]; pmap["nb_invert"] = p["UnaryFunc"]; pmap["nb_lshift"] = p["BinaryFunc"]; pmap["nb_rshift"] = p["BinaryFunc"]; pmap["nb_and"] = p["BinaryFunc"]; pmap["nb_xor"] = p["BinaryFunc"]; pmap["nb_or"] = p["BinaryFunc"]; pmap["nb_coerce"] = p["ObjObjFunc"]; pmap["nb_int"] = p["UnaryFunc"]; pmap["nb_long"] = p["UnaryFunc"]; pmap["nb_float"] = p["UnaryFunc"]; pmap["nb_oct"] = p["UnaryFunc"]; pmap["nb_hex"] = p["UnaryFunc"]; pmap["nb_inplace_add"] = p["BinaryFunc"]; pmap["nb_inplace_subtract"] = p["BinaryFunc"]; pmap["nb_inplace_multiply"] = p["BinaryFunc"]; pmap["nb_inplace_remainder"] = p["BinaryFunc"]; pmap["nb_inplace_power"] = p["TernaryFunc"]; pmap["nb_inplace_lshift"] = p["BinaryFunc"]; pmap["nb_inplace_rshift"] = p["BinaryFunc"]; pmap["nb_inplace_and"] = p["BinaryFunc"]; pmap["nb_inplace_xor"] = p["BinaryFunc"]; pmap["nb_inplace_or"] = p["BinaryFunc"]; pmap["nb_floor_divide"] = p["BinaryFunc"]; pmap["nb_true_divide"] = p["BinaryFunc"]; pmap["nb_inplace_floor_divide"] = p["BinaryFunc"]; pmap["nb_inplace_true_divide"] = p["BinaryFunc"]; pmap["nb_index"] = p["UnaryFunc"]; pmap["sq_length"] = p["InquiryFunc"]; pmap["sq_concat"] = p["BinaryFunc"]; pmap["sq_repeat"] = p["IntArgFunc"]; pmap["sq_item"] = p["IntArgFunc"]; pmap["sq_slice"] = p["IntIntArgFunc"]; pmap["sq_ass_item"] = p["IntObjArgFunc"]; pmap["sq_ass_slice"] = p["IntIntObjArgFunc"]; pmap["sq_contains"] = p["ObjObjFunc"]; pmap["sq_inplace_concat"] = p["BinaryFunc"]; pmap["sq_inplace_repeat"] = p["IntArgFunc"]; pmap["mp_length"] = p["InquiryFunc"]; pmap["mp_subscript"] = p["BinaryFunc"]; pmap["mp_ass_subscript"] = p["ObjObjArgFunc"]; pmap["bf_getreadbuffer"] = p["IntObjArgFunc"]; pmap["bf_getwritebuffer"] = p["IntObjArgFunc"]; pmap["bf_getsegcount"] = p["ObjObjFunc"]; pmap["bf_getcharbuffer"] = p["IntObjArgFunc"]; } internal static Type GetPrototype(string name) { return pmap[name] as Type; } internal static Dictionary allocatedThunks = new Dictionary(); internal static ThunkInfo GetThunk(MethodInfo method, string funcType = null) { Type dt; if (funcType != null) dt = typeof(Interop).GetNestedType(funcType) as Type; else dt = GetPrototype(method.Name); if (dt == null) { return ThunkInfo.Empty; } Delegate d = Delegate.CreateDelegate(dt, method); var info = new ThunkInfo(d); allocatedThunks[info.Address] = d; return info; } [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate IntPtr UnaryFunc(IntPtr ob); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate IntPtr BinaryFunc(IntPtr ob, IntPtr arg); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate IntPtr TernaryFunc(IntPtr ob, IntPtr a1, IntPtr a2); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate int InquiryFunc(IntPtr ob); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate IntPtr IntArgFunc(IntPtr ob, int arg); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate IntPtr IntIntArgFunc(IntPtr ob, int a1, int a2); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate int IntObjArgFunc(IntPtr ob, int a1, IntPtr a2); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate int IntIntObjArgFunc(IntPtr o, int a, int b, IntPtr c); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate int ObjObjArgFunc(IntPtr o, IntPtr a, IntPtr b); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate int ObjObjFunc(IntPtr ob, IntPtr arg); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate void DestructorFunc(IntPtr ob); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate int PrintFunc(IntPtr ob, IntPtr a, int b); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate IntPtr RichCmpFunc(IntPtr ob, IntPtr a, int b); } 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; Address = Marshal.GetFunctionPointerForDelegate(target); } } [StructLayout(LayoutKind.Sequential)] struct PyGC_Node { public IntPtr gc_next; public IntPtr gc_prev; public IntPtr gc_refs; } [StructLayout(LayoutKind.Sequential)] struct PyGC_Head { public PyGC_Node gc; } [StructLayout(LayoutKind.Sequential)] struct PyMethodDef { public IntPtr ml_name; public IntPtr ml_meth; public int ml_flags; public IntPtr ml_doc; } }