Example #1
0
        private static SlotsHolder CreateSolotsHolder(IntPtr type)
        {
            var holder = new SlotsHolder(type);

            _slotsHolders.Add(type, holder);
            return(holder);
        }
Example #2
0
        internal static SlotsHolder SetupMetaSlots(Type impl, IntPtr type)
        {
            // Override type slots with those of the managed implementation.
            SlotsHolder slotsHolder = new SlotsHolder(type);

            InitializeSlots(type, impl, slotsHolder);

            // We need space for 3 PyMethodDef structs.
            int    mdefSize  = (MetaType.CustomMethods.Length + 1) * Marshal.SizeOf(typeof(PyMethodDef));
            IntPtr mdef      = Runtime.PyMem_Malloc(mdefSize);
            IntPtr mdefStart = mdef;

            foreach (var methodName in MetaType.CustomMethods)
            {
                mdef = AddCustomMetaMethod(methodName, type, mdef, slotsHolder);
            }
            mdef = WriteMethodDefSentinel(mdef);
            Debug.Assert((long)(mdefStart + mdefSize) <= (long)mdef);

            Marshal.WriteIntPtr(type, TypeOffset.tp_methods, mdefStart);

            // XXX: Hard code with mode check.
            if (Runtime.ShutdownMode != ShutdownMode.Reload)
            {
                slotsHolder.Set(TypeOffset.tp_methods, (t, offset) =>
                {
                    var p = Marshal.ReadIntPtr(t, offset);
                    Runtime.PyMem_Free(p);
                    Marshal.WriteIntPtr(t, offset, IntPtr.Zero);
                });
            }
            return(slotsHolder);
        }
Example #3
0
        /// <summary>
        /// The following CreateType implementations do the necessary work to
        /// create Python types to represent managed extension types, reflected
        /// types, subclasses of reflected types and the managed metatype. The
        /// dance is slightly different for each kind of type due to different
        /// behavior needed and the desire to have the existing Python runtime
        /// do as much of the allocation and initialization work as possible.
        /// </summary>
        internal static IntPtr CreateType(Type impl)
        {
            IntPtr type    = AllocateTypeObject(impl.Name);
            int    ob_size = ObjectOffset.Size(type);

            // Set tp_basicsize to the size of our managed instance objects.
            Marshal.WriteIntPtr(type, TypeOffset.tp_basicsize, (IntPtr)ob_size);

            var offset = (IntPtr)ObjectOffset.TypeDictOffset(type);

            Marshal.WriteIntPtr(type, TypeOffset.tp_dictoffset, offset);

            SlotsHolder slotsHolder = CreateSolotsHolder(type);

            InitializeSlots(type, impl, slotsHolder);

            int flags = TypeFlags.Default | TypeFlags.Managed |
                        TypeFlags.HeapType | TypeFlags.HaveGC;

            Util.WriteCLong(type, TypeOffset.tp_flags, flags);

            if (Runtime.PyType_Ready(type) != 0)
            {
                throw new PythonException();
            }

            IntPtr dict = Marshal.ReadIntPtr(type, TypeOffset.tp_dict);
            IntPtr mod  = Runtime.PyString_FromString("CLR");

            Runtime.PyDict_SetItem(dict, PyIdentifier.__module__, mod);
            Runtime.XDecref(mod);

            InitMethods(type, impl);
            return(type);
        }
Example #4
0
 public static void Release()
 {
     if (Runtime.Refcount(PyCLRMetaType) > 1)
     {
         _metaSlotsHodler.ResetSlots();
     }
     Runtime.Py_CLEAR(ref PyCLRMetaType);
     _metaSlotsHodler = null;
 }
Example #5
0
        static void InitializeSlot(IntPtr type, int slotOffset, MethodInfo method, SlotsHolder slotsHolder = null)
        {
            var thunk = Interop.GetThunk(method);

            Marshal.WriteIntPtr(type, slotOffset, thunk.Address);
            if (slotsHolder != null)
            {
                slotsHolder.Set(slotOffset, thunk);
            }
        }
Example #6
0
        internal static IntPtr CreateMetaType(Type impl, out SlotsHolder slotsHolder)
        {
            // The managed metatype is functionally little different than the
            // standard Python metatype (PyType_Type). It overrides certain of
            // the standard type slots, and has to subclass PyType_Type for
            // certain functions in the C runtime to work correctly with it.

            IntPtr type = AllocateTypeObject("CLR Metatype", metatype: Runtime.PyTypeType);

            IntPtr py_type = Runtime.PyTypeType;

            Marshal.WriteIntPtr(type, TypeOffset.tp_base, py_type);
            Runtime.XIncref(py_type);

            int size = Marshal.ReadInt32(Runtime.PyTypeType, TypeOffset.tp_basicsize)
                       + IntPtr.Size // tp_clr_inst_offset
                       + IntPtr.Size // tp_clr_inst
            ;

            Marshal.WriteIntPtr(type, TypeOffset.tp_basicsize, new IntPtr(size));
            Marshal.WriteInt32(type, ManagedType.Offsets.tp_clr_inst_offset, ManagedType.Offsets.tp_clr_inst);

            const TypeFlags flags = TypeFlags.Default
                                    | TypeFlags.HeapType
                                    | TypeFlags.HaveGC;

            Util.WriteCLong(type, TypeOffset.tp_flags, (int)flags);

            // Slots will inherit from TypeType, it's not neccesary for setting them.
            // Inheried slots:
            // tp_basicsize, tp_itemsize,
            // tp_dictoffset, tp_weaklistoffset,
            // tp_traverse, tp_clear, tp_is_gc, etc.
            slotsHolder = SetupMetaSlots(impl, type);

            if (Runtime.PyType_Ready(type) != 0)
            {
                throw new PythonException();
            }

            IntPtr dict = Marshal.ReadIntPtr(type, TypeOffset.tp_dict);
            IntPtr mod  = Runtime.PyString_FromString("CLR");

            Runtime.PyDict_SetItemString(dict, "__module__", mod);

            // The type has been modified after PyType_Ready has been called
            // Refresh the type
            Runtime.PyType_Modified(type);
            //DebugUtil.DumpType(type);

            return(type);
        }
Example #7
0
        static void InitializeSlot(IntPtr type, ThunkInfo thunk, string name, SlotsHolder slotsHolder = null, bool canOverride = true)
        {
            int offset = ManagedDataOffsets.GetSlotOffset(name);

            if (!canOverride && Marshal.ReadIntPtr(type, offset) != IntPtr.Zero)
            {
                return;
            }
            Marshal.WriteIntPtr(type, offset, thunk.Address);
            if (slotsHolder != null)
            {
                slotsHolder.Set(offset, thunk);
            }
        }
Example #8
0
        internal static IntPtr BasicSubType(string name, IntPtr base_, Type impl)
        {
            // Utility to create a subtype of a std Python type, but with
            // a managed type able to override implementation

            IntPtr type = AllocateTypeObject(name, metatype: Runtime.PyTypeType);

            //Marshal.WriteIntPtr(type, TypeOffset.tp_basicsize, (IntPtr)obSize);
            //Marshal.WriteIntPtr(type, TypeOffset.tp_itemsize, IntPtr.Zero);

            //IntPtr offset = (IntPtr)ObjectOffset.ob_dict;
            //Marshal.WriteIntPtr(type, TypeOffset.tp_dictoffset, offset);

            //IntPtr dc = Runtime.PyDict_Copy(dict);
            //Marshal.WriteIntPtr(type, TypeOffset.tp_dict, dc);

            Marshal.WriteIntPtr(type, TypeOffset.tp_base, base_);
            Runtime.XIncref(base_);

            var flags = TypeFlags.Default;

            flags |= TypeFlags.Managed;
            flags |= TypeFlags.HeapType;
            flags |= TypeFlags.HaveGC;
            Util.WriteCLong(type, TypeOffset.tp_flags, (int)flags);

            CopySlot(base_, type, TypeOffset.tp_traverse);
            CopySlot(base_, type, TypeOffset.tp_clear);
            CopySlot(base_, type, TypeOffset.tp_is_gc);

            SlotsHolder slotsHolder = CreateSolotsHolder(type);

            InitializeSlots(type, impl, slotsHolder);

            if (Runtime.PyType_Ready(type) != 0)
            {
                throw new PythonException();
            }

            IntPtr tp_dict = Marshal.ReadIntPtr(type, TypeOffset.tp_dict);
            IntPtr mod     = Runtime.PyString_FromString("CLR");

            Runtime.PyDict_SetItem(tp_dict, PyIdentifier.__module__, mod);

            // The type has been modified after PyType_Ready has been called
            // Refresh the type
            Runtime.PyType_Modified(type);

            return(type);
        }
Example #9
0
 internal static void RestoreRuntimeData(RuntimeDataStorage storage)
 {
     Debug.Assert(cache == null || cache.Count == 0);
     storage.GetValue("slots", out _slotsImpls);
     storage.GetValue("cache", out cache);
     foreach (var entry in cache)
     {
         Type        type   = entry.Key;
         IntPtr      handle = entry.Value;
         SlotsHolder holder = CreateSolotsHolder(handle);
         InitializeSlots(handle, _slotsImpls[type], holder);
         // FIXME: mp_length_slot.CanAssgin(clrType)
     }
 }
Example #10
0
        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);

            if (!canOverride && Marshal.ReadIntPtr(type, offset) != IntPtr.Zero)
            {
                return;
            }
            Marshal.WriteIntPtr(type, offset, thunk.Address);
            if (slotsHolder != null)
            {
                slotsHolder.Set(offset, thunk);
            }
        }
Example #11
0
        /// <summary>
        /// The following CreateType implementations do the necessary work to
        /// create Python types to represent managed extension types, reflected
        /// types, subclasses of reflected types and the managed metatype. The
        /// dance is slightly different for each kind of type due to different
        /// behavior needed and the desire to have the existing Python runtime
        /// do as much of the allocation and initialization work as possible.
        /// </summary>
        internal static unsafe IntPtr CreateType(Type impl)
        {
            IntPtr type  = AllocateTypeObject(impl.Name, metatype: Runtime.PyCLRMetaType);
            IntPtr base_ = impl == typeof(CLRModule)
                ? Runtime.PyModuleType
                : Runtime.PyBaseObjectType;

            int newFieldOffset = InheritOrAllocateStandardFields(type, base_);

            int tp_clr_inst_offset = newFieldOffset;

            newFieldOffset += IntPtr.Size;

            int ob_size = newFieldOffset;

            // Set tp_basicsize to the size of our managed instance objects.
            Marshal.WriteIntPtr(type, TypeOffset.tp_basicsize, (IntPtr)ob_size);
            Marshal.WriteInt32(type, ManagedType.Offsets.tp_clr_inst_offset, tp_clr_inst_offset);
            Marshal.WriteIntPtr(type, TypeOffset.tp_new, (IntPtr)Runtime.Delegates.PyType_GenericNew);

            SlotsHolder slotsHolder = CreateSolotsHolder(type);

            InitializeSlots(type, impl, slotsHolder);

            var flags = TypeFlags.Default | TypeFlags.HasClrInstance |
                        TypeFlags.HeapType | TypeFlags.HaveGC;

            Util.WriteCLong(type, TypeOffset.tp_flags, (int)flags);

            if (Runtime.PyType_Ready(type) != 0)
            {
                throw new PythonException();
            }

            var dict = new BorrowedReference(Marshal.ReadIntPtr(type, TypeOffset.tp_dict));
            var mod  = NewReference.DangerousFromPointer(Runtime.PyString_FromString("CLR"));

            Runtime.PyDict_SetItem(dict, PyIdentifier.__module__, mod);
            mod.Dispose();

            InitMethods(type, impl);

            // The type has been modified after PyType_Ready has been called
            // Refresh the type
            Runtime.PyType_Modified(type);
            return(type);
        }
Example #12
0
        internal static IntPtr RestoreRuntimeData(RuntimeDataStorage storage)
        {
            PyCLRMetaType    = storage.PopValue <IntPtr>();
            _metaSlotsHodler = new SlotsHolder(PyCLRMetaType);
            TypeManager.InitializeSlots(PyCLRMetaType, typeof(MetaType), _metaSlotsHodler);

            IntPtr mdef = Marshal.ReadIntPtr(PyCLRMetaType, TypeOffset.tp_methods);

            foreach (var methodName in CustomMethods)
            {
                var       mi        = typeof(MetaType).GetMethod(methodName);
                ThunkInfo thunkInfo = Interop.GetThunk(mi, "BinaryFunc");
                _metaSlotsHodler.KeeapAlive(thunkInfo);
                mdef = TypeManager.WriteMethodDef(mdef, methodName, thunkInfo.Address);
            }
            return(PyCLRMetaType);
        }
Example #13
0
        /// <summary>
        /// Given a newly allocated Python type object and a managed Type that
        /// provides the implementation for the type, connect the type slots of
        /// the Python object to the managed methods of the implementing Type.
        /// </summary>
        internal static void InitializeSlots(IntPtr type, Type impl, SlotsHolder slotsHolder = null)
        {
            // We work from the most-derived class up; make sure to get
            // the most-derived slot and not to override it with a base
            // class's slot.
            var seen = new HashSet <string>();

            while (impl != null)
            {
                MethodInfo[] methods = impl.GetMethods(tbFlags);
                foreach (MethodInfo method in methods)
                {
                    string name = method.Name;
                    if (!name.StartsWith("tp_") && !TypeOffset.IsSupportedSlotName(name))
                    {
                        Debug.Assert(!name.Contains("_") || name.StartsWith("_") || method.IsSpecialName);
                        continue;
                    }

                    if (seen.Contains(name))
                    {
                        continue;
                    }

                    InitializeSlot(type, Interop.GetThunk(method), name, slotsHolder);

                    seen.Add(name);
                }

                impl = impl.BaseType;
            }

            foreach (string slot in _requiredSlots)
            {
                if (seen.Contains(slot))
                {
                    continue;
                }
                var offset = ManagedDataOffsets.GetSlotOffset(slot);
                Marshal.WriteIntPtr(type, offset, SlotsHolder.GetDefaultSlot(offset));
            }
        }
Example #14
0
 internal static void RestoreRuntimeData(RuntimeDataStorage storage)
 {
     Debug.Assert(cache == null || cache.Count == 0);
     storage.GetValue("slots", out _slotsImpls);
     storage.GetValue <Dictionary <MaybeType, IntPtr> >("cache", out var _cache);
     foreach (var entry in _cache)
     {
         if (!entry.Key.Valid)
         {
             Runtime.XDecref(entry.Value);
             continue;
         }
         Type   type   = entry.Key.Value;;
         IntPtr handle = entry.Value;
         cache[type] = handle;
         SlotsHolder holder = CreateSolotsHolder(handle);
         InitializeSlots(handle, _slotsImpls[type], holder);
         // FIXME: mp_length_slot.CanAssgin(clrType)
     }
 }
Example #15
0
        /// <summary>
        /// The following CreateType implementations do the necessary work to
        /// create Python types to represent managed extension types, reflected
        /// types, subclasses of reflected types and the managed metatype. The
        /// dance is slightly different for each kind of type due to different
        /// behavior needed and the desire to have the existing Python runtime
        /// do as much of the allocation and initialization work as possible.
        /// </summary>
        internal static IntPtr CreateType(Type impl)
        {
            IntPtr type    = AllocateTypeObject(impl.Name, metatype: Runtime.PyTypeType);
            int    ob_size = ObjectOffset.Size(type);

            // Set tp_basicsize to the size of our managed instance objects.
            Marshal.WriteIntPtr(type, TypeOffset.tp_basicsize, (IntPtr)ob_size);

            var offset = (IntPtr)ObjectOffset.TypeDictOffset(type);

            Marshal.WriteIntPtr(type, TypeOffset.tp_dictoffset, offset);

            SlotsHolder slotsHolder = CreateSolotsHolder(type);

            InitializeSlots(type, impl, slotsHolder);

            var flags = TypeFlags.Default | TypeFlags.Managed |
                        TypeFlags.HeapType | TypeFlags.HaveGC;

            Util.WriteCLong(type, TypeOffset.tp_flags, (int)flags);

            if (Runtime.PyType_Ready(type) != 0)
            {
                throw new PythonException();
            }

            var dict = new BorrowedReference(Marshal.ReadIntPtr(type, TypeOffset.tp_dict));
            var mod  = NewReference.DangerousFromPointer(Runtime.PyString_FromString("CLR"));

            Runtime.PyDict_SetItem(dict, PyIdentifier.__module__, mod);
            mod.Dispose();

            InitMethods(type, impl);

            // The type has been modified after PyType_Ready has been called
            // Refresh the type
            Runtime.PyType_Modified(type);
            return(type);
        }
Example #16
0
        private static IntPtr AddCustomMetaMethod(string name, IntPtr type, IntPtr mdef, SlotsHolder slotsHolder)
        {
            MethodInfo mi        = typeof(MetaType).GetMethod(name);
            ThunkInfo  thunkInfo = Interop.GetThunk(mi, "BinaryFunc");

            slotsHolder.KeeapAlive(thunkInfo);

            // XXX: Hard code with mode check.
            if (Runtime.ShutdownMode != ShutdownMode.Reload)
            {
                IntPtr mdefAddr = mdef;
                slotsHolder.AddDealloctor(() =>
                {
                    var tp_dict = new BorrowedReference(Marshal.ReadIntPtr(type, TypeOffset.tp_dict));
                    if (Runtime.PyDict_DelItemString(tp_dict, name) != 0)
                    {
                        Runtime.PyErr_Print();
                        Debug.Fail($"Cannot remove {name} from metatype");
                    }
                    FreeMethodDef(mdefAddr);
                });
            }
            mdef = WriteMethodDef(mdef, name, thunkInfo.Address);
            return(mdef);
        }
Example #17
0
        internal static IntPtr CreateType(ManagedType impl, Type clrType)
        {
            // Cleanup the type name to get rid of funny nested type names.
            string name = $"clr.{clrType.FullName}";
            int    i    = name.LastIndexOf('+');

            if (i > -1)
            {
                name = name.Substring(i + 1);
            }
            i = name.LastIndexOf('.');
            if (i > -1)
            {
                name = name.Substring(i + 1);
            }

            IntPtr base_   = IntPtr.Zero;
            int    ob_size = ObjectOffset.Size(Runtime.PyTypeType);

            // XXX Hack, use a different base class for System.Exception
            // Python 2.5+ allows new style class exceptions but they *must*
            // subclass BaseException (or better Exception).
            if (typeof(Exception).IsAssignableFrom(clrType))
            {
                ob_size = ObjectOffset.Size(Exceptions.Exception);
            }

            int tp_dictoffset = ob_size + ManagedDataOffsets.ob_dict;

            if (clrType == typeof(Exception))
            {
                base_ = Exceptions.Exception;
            }
            else if (clrType.BaseType != null)
            {
                ClassBase bc = ClassManager.GetClass(clrType.BaseType);
                base_ = bc.pyHandle;
            }

            IntPtr type = AllocateTypeObject(name, Runtime.PyCLRMetaType);

            Marshal.WriteIntPtr(type, TypeOffset.ob_type, Runtime.PyCLRMetaType);
            Runtime.XIncref(Runtime.PyCLRMetaType);

            Marshal.WriteIntPtr(type, TypeOffset.tp_basicsize, (IntPtr)ob_size);
            Marshal.WriteIntPtr(type, TypeOffset.tp_itemsize, IntPtr.Zero);
            Marshal.WriteIntPtr(type, TypeOffset.tp_dictoffset, (IntPtr)tp_dictoffset);

            // we want to do this after the slot stuff above in case the class itself implements a slot method
            SlotsHolder slotsHolder = CreateSolotsHolder(type);

            InitializeSlots(type, impl.GetType(), slotsHolder);

            if (Marshal.ReadIntPtr(type, TypeOffset.mp_length) == IntPtr.Zero &&
                mp_length_slot.CanAssign(clrType))
            {
                InitializeSlot(type, TypeOffset.mp_length, mp_length_slot.Method, slotsHolder);
            }

            if (!typeof(IEnumerable).IsAssignableFrom(clrType) &&
                !typeof(IEnumerator).IsAssignableFrom(clrType))
            {
                // The tp_iter slot should only be set for enumerable types.
                Marshal.WriteIntPtr(type, TypeOffset.tp_iter, IntPtr.Zero);
            }


            // Only set mp_subscript and mp_ass_subscript for types with indexers
            if (impl is ClassBase cb)
            {
                if (!(impl is ArrayObject))
                {
                    if (cb.indexer == null || !cb.indexer.CanGet)
                    {
                        Marshal.WriteIntPtr(type, TypeOffset.mp_subscript, IntPtr.Zero);
                    }
                    if (cb.indexer == null || !cb.indexer.CanSet)
                    {
                        Marshal.WriteIntPtr(type, TypeOffset.mp_ass_subscript, IntPtr.Zero);
                    }
                }
            }
            else
            {
                Marshal.WriteIntPtr(type, TypeOffset.mp_subscript, IntPtr.Zero);
                Marshal.WriteIntPtr(type, TypeOffset.mp_ass_subscript, IntPtr.Zero);
            }

            if (base_ != IntPtr.Zero)
            {
                Marshal.WriteIntPtr(type, TypeOffset.tp_base, base_);
                Runtime.XIncref(base_);
            }

            const TypeFlags flags = TypeFlags.Default
                                    | TypeFlags.Managed
                                    | TypeFlags.HeapType
                                    | TypeFlags.BaseType
                                    | TypeFlags.HaveGC;

            Util.WriteCLong(type, TypeOffset.tp_flags, (int)flags);

            OperatorMethod.FixupSlots(type, clrType);
            // Leverage followup initialization from the Python runtime. Note
            // that the type of the new type must PyType_Type at the time we
            // call this, else PyType_Ready will skip some slot initialization.

            if (Runtime.PyType_Ready(type) != 0)
            {
                throw new PythonException();
            }

            var    dict = new BorrowedReference(Marshal.ReadIntPtr(type, TypeOffset.tp_dict));
            string mn   = clrType.Namespace ?? "";
            var    mod  = NewReference.DangerousFromPointer(Runtime.PyString_FromString(mn));

            Runtime.PyDict_SetItem(dict, PyIdentifier.__module__, mod);
            mod.Dispose();

            // Hide the gchandle of the implementation in a magic type slot.
            GCHandle gc = impl.AllocGCHandle();

            Marshal.WriteIntPtr(type, TypeOffset.magic(), (IntPtr)gc);

            // Set the handle attributes on the implementing instance.
            impl.tpHandle = type;
            impl.pyHandle = type;

            //DebugUtil.DumpType(type);

            return(type);
        }
Example #18
0
 protected override void SetTypeNewSlot(BorrowedReference pyType, SlotsHolder slotsHolder)
 {
     // Python derived types rely on base tp_new and overridden __init__
 }