Exemplo n.º 1
0
        /// <summary>
        /// Given a Python object, return the associated managed object or null.
        /// </summary>
        internal static ManagedType GetManagedObject(IntPtr ob)
        {
            if (ob != IntPtr.Zero)
            {
                IntPtr tp = Runtime.PyObject_TYPE(ob);
                if (tp == Runtime.PyTypeType || tp == Runtime.PyCLRMetaType)
                {
                    tp = ob;
                }

                var flags = Util.ReadCLong(tp, TypeOffset.tp_flags);
                if ((flags & TypeFlags.Managed) != 0)
                {
                    IntPtr op = tp == ob
                        ? Marshal.ReadIntPtr(tp, TypeOffset.magic())
                        : Marshal.ReadIntPtr(ob, ObjectOffset.magic(tp));

                    if (op == IntPtr.Zero)
                    {
                        return(null);
                    }
                    var gc = (GCHandle)op;
                    return((ManagedType)gc.Target);
                }
            }
            return(null);
        }
Exemplo n.º 2
0
        internal CLRObject(object ob, IntPtr tp)
        {
            IntPtr py = Runtime.PyType_GenericAlloc(tp, 0);

            long flags = Util.ReadCLong(tp, TypeOffset.tp_flags);

            if ((flags & TypeFlags.Subclass) != 0)
            {
                IntPtr dict = Marshal.ReadIntPtr(py, ObjectOffset.TypeDictOffset(tp));
                if (dict == IntPtr.Zero)
                {
                    dict = Runtime.PyDict_New();
                    Marshal.WriteIntPtr(py, ObjectOffset.TypeDictOffset(tp), dict);
                }
            }

            GCHandle gc = GCHandle.Alloc(this);

            Marshal.WriteIntPtr(py, ObjectOffset.magic(tp), (IntPtr)gc);
            tpHandle = tp;
            pyHandle = py;
            gcHandle = gc;
            inst     = ob;

            // for performance before calling SetArgsAndCause() lets check if we are an exception
            if (inst is Exception)
            {
                // Fix the BaseException args (and __cause__ in case of Python 3)
                // slot if wrapping a CLR exception
                Exceptions.SetArgsAndCause(py);
            }
        }
Exemplo n.º 3
0
        /// <summary>
        /// Dealloc implementation. This is called when a Python type generated
        /// by this metatype is no longer referenced from the Python runtime.
        /// </summary>
        public static void tp_dealloc(IntPtr tp)
        {
            // Fix this when we dont cheat on the handle for subclasses!

            var flags = (TypeFlags)Util.ReadCLong(tp, TypeOffset.tp_flags);

            if ((flags & TypeFlags.Subclass) == 0)
            {
                GetGCHandle(new BorrowedReference(tp)).Free();
#if DEBUG
                // prevent ExecutionEngineException in debug builds in case we have a bug
                // this would allow using managed debugger to investigate the issue
                SetGCHandle(new BorrowedReference(tp), Runtime.CLRMetaType, default);
#endif
            }

            IntPtr op = Marshal.ReadIntPtr(tp, TypeOffset.ob_type);
            Runtime.XDecref(op);

            // Delegate the rest of finalization the Python metatype. Note
            // that the PyType_Type implementation of tp_dealloc will call
            // tp_free on the type of the type being deallocated - in this
            // case our CLR metatype. That is why we implement tp_free.

            op = Marshal.ReadIntPtr(Runtime.PyTypeType, TypeOffset.tp_dealloc);
            NativeCall.Void_Call_1(op, tp);
        }
Exemplo n.º 4
0
        internal CLRObject(object ob, IntPtr tp)
        {
            System.Diagnostics.Debug.Assert(tp != IntPtr.Zero);
            IntPtr py = Runtime.PyType_GenericAlloc(tp, 0);

            long flags = Util.ReadCLong(tp, TypeOffset.tp_flags);

            if ((flags & TypeFlags.Subclass) != 0)
            {
                IntPtr dict = Marshal.ReadIntPtr(py, ObjectOffset.TypeDictOffset(tp));
                if (dict == IntPtr.Zero)
                {
                    dict = Runtime.PyDict_New();
                    Marshal.WriteIntPtr(py, ObjectOffset.TypeDictOffset(tp), dict);
                }
            }

            GCHandle gc = AllocGCHandle(TrackTypes.Wrapper);

            Marshal.WriteIntPtr(py, ObjectOffset.magic(tp), (IntPtr)gc);
            tpHandle = tp;
            pyHandle = py;
            inst     = ob;

            // Fix the BaseException args (and __cause__ in case of Python 3)
            // slot if wrapping a CLR exception
            Exceptions.SetArgsAndCause(py);
        }
Exemplo n.º 5
0
 /// <summary>
 /// Given a Python object, return the associated managed object type or null.
 /// </summary>
 internal static ManagedType GetManagedObjectType(IntPtr ob)
 {
     if (ob != IntPtr.Zero)
     {
         IntPtr tp = Runtime.PyObject_TYPE(ob);
         var flags = (TypeFlags)Util.ReadCLong(tp, TypeOffset.tp_flags);
         if ((flags & TypeFlags.HasClrInstance) != 0)
         {
             var gc = GetGCHandle(new BorrowedReference(tp), Runtime.CLRMetaType);
             return (ManagedType)gc.Target;
         }
     }
     return null;
 }
Exemplo n.º 6
0
        //====================================================================
        // Python iterator API
        //====================================================================

        internal static bool PyIter_Check(IntPtr pointer)
        {
            var ob_type = Marshal.ReadIntPtr(pointer, ObjectOffset.ob_type);

#if PYTHON2
            long tp_flags = Util.ReadCLong(ob_type, TypeOffset.tp_flags);
            if ((tp_flags & TypeFlags.HaveIter) == 0)
            {
                return(false);
            }
#endif
            IntPtr tp_iternext = Marshal.ReadIntPtr(ob_type, TypeOffset.tp_iternext);
            return(tp_iternext != IntPtr.Zero && tp_iternext != _PyObject_NextNotImplemented);
        }
Exemplo n.º 7
0
        /// <summary>
        /// Test whether the Python object is an iterable.
        /// </summary>
        internal static bool PyObject_IsIterable(IntPtr pointer)
        {
            var ob_type = Marshal.ReadIntPtr(pointer, ObjectOffset.ob_type);

#if PYTHON2
            long tp_flags = Util.ReadCLong(ob_type, TypeOffset.tp_flags);
            if ((tp_flags & TypeFlags.HaveIter) == 0)
            {
                return(false);
            }
#endif
            IntPtr tp_iter = Marshal.ReadIntPtr(ob_type, TypeOffset.tp_iter);
            return(tp_iter != IntPtr.Zero);
        }
Exemplo n.º 8
0
 /// <summary>
 /// Given a Python object, return the associated managed object type or null.
 /// </summary>
 internal static ManagedType GetManagedObjectType(IntPtr ob)
 {
     if (ob != IntPtr.Zero)
     {
         IntPtr tp    = Runtime.PyObject_TYPE(ob);
         var    flags = Util.ReadCLong(tp, TypeOffset.tp_flags);
         if ((flags & TypeFlags.Managed) != 0)
         {
             tp = Marshal.ReadIntPtr(tp, TypeOffset.magic());
             var gc = (GCHandle)tp;
             return((ManagedType)gc.Target);
         }
     }
     return(null);
 }
Exemplo n.º 9
0
        internal static bool IsManagedType(IntPtr ob)
        {
            if (ob != IntPtr.Zero)
            {
                IntPtr tp = Runtime.PyObject_TYPE(ob);
                if (tp == Runtime.PyTypeType || tp == Runtime.PyCLRMetaType)
                {
                    tp = ob;
                }

                var flags = Util.ReadCLong(tp, TypeOffset.tp_flags);
                if ((flags & TypeFlags.Managed) != 0)
                {
                    return(true);
                }
            }
            return(false);
        }
Exemplo n.º 10
0
        internal static ManagedType?GetManagedObject(IntPtr ob)
        {
            if (ob != IntPtr.Zero)
            {
                IntPtr tp = Runtime.PyObject_TYPE(ob);
                if (tp == Runtime.PyTypeType || tp == Runtime.PyCLRMetaType)
                {
                    tp = ob;
                }

                var flags = (TypeFlags)Util.ReadCLong(tp, TypeOffset.tp_flags);
                if ((flags & TypeFlags.HasClrInstance) != 0)
                {
                    var gc = TryGetGCHandle(new BorrowedReference(ob));
                    return((ManagedType)gc?.Target);
                }
            }
            return(null);
        }
Exemplo n.º 11
0
        /// <summary>
        /// Dealloc implementation. This is called when a Python type generated
        /// by this metatype is no longer referenced from the Python runtime.
        /// </summary>
        public static void tp_dealloc(IntPtr tp)
        {
            // Fix this when we dont cheat on the handle for subclasses!

            var flags = Util.ReadCLong(tp, TypeOffset.tp_flags);

            if ((flags & TypeFlags.Subclass) == 0)
            {
                IntPtr gc = Marshal.ReadIntPtr(tp, TypeOffset.magic());
                ((GCHandle)gc).Free();
            }

            IntPtr op = Marshal.ReadIntPtr(tp, TypeOffset.ob_type);

            Runtime.XDecref(op);

            // Delegate the rest of finalization the Python metatype. Note
            // that the PyType_Type implementation of tp_dealloc will call
            // tp_free on the type of the type being deallocated - in this
            // case our CLR metatype. That is why we implement tp_free.

            op = Marshal.ReadIntPtr(Runtime.PyTypeType, TypeOffset.tp_dealloc);
            NativeCall.Void_Call_1(op, tp);
        }
Exemplo n.º 12
0
 internal static bool IsManagedType(BorrowedReference type)
 {
     var flags = (TypeFlags)Util.ReadCLong(type.DangerousGetAddress(), TypeOffset.tp_flags);
     return (flags & TypeFlags.HasClrInstance) != 0;
 }
Exemplo n.º 13
0
        /// <summary>
        /// Metatype __new__ implementation. This is called to create a new
        /// class / type when a reflected class is subclassed.
        /// </summary>
        public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw)
        {
            var len = Runtime.PyTuple_Size(args);

            if (len < 3)
            {
                return(Exceptions.RaiseTypeError("invalid argument list"));
            }

            IntPtr name  = Runtime.PyTuple_GetItem(args, 0);
            IntPtr bases = Runtime.PyTuple_GetItem(args, 1);
            IntPtr dict  = Runtime.PyTuple_GetItem(args, 2);

            // We do not support multiple inheritance, so the bases argument
            // should be a 1-item tuple containing the type we are subtyping.
            // That type must itself have a managed implementation. We check
            // that by making sure its metatype is the CLR metatype.

            if (Runtime.PyTuple_Size(bases) != 1)
            {
                return(Exceptions.RaiseTypeError("cannot use multiple inheritance with managed classes"));
            }

            IntPtr base_type = Runtime.PyTuple_GetItem(bases, 0);
            IntPtr mt        = Runtime.PyObject_TYPE(base_type);

            if (!(mt == PyCLRMetaType || mt == Runtime.PyTypeType))
            {
                return(Exceptions.RaiseTypeError("invalid metatype"));
            }

            // Ensure that the reflected type is appropriate for subclassing,
            // disallowing subclassing of delegates, enums and array types.

            var cb = GetManagedObject(base_type) as ClassBase;

            if (cb != null)
            {
                try
                {
                    if (!cb.CanSubclass())
                    {
                        return(Exceptions.RaiseTypeError("delegates, enums and array types cannot be subclassed"));
                    }
                }
                catch (SerializationException)
                {
                    return(Exceptions.RaiseTypeError($"Underlying C# Base class {cb.type} has been deleted"));
                }
            }

            IntPtr slots = Runtime.PyDict_GetItem(dict, PyIdentifier.__slots__);

            if (slots != IntPtr.Zero)
            {
                return(Exceptions.RaiseTypeError("subclasses of managed classes do not support __slots__"));
            }

            // If __assembly__ or __namespace__ are in the class dictionary then create
            // a managed sub type.
            // This creates a new managed type that can be used from .net to call back
            // into python.
            if (IntPtr.Zero != dict)
            {
                using (var clsDict = new PyDict(new BorrowedReference(dict)))
                {
                    if (clsDict.HasKey("__assembly__") || clsDict.HasKey("__namespace__"))
                    {
                        return(TypeManager.CreateSubType(name, base_type, clsDict.Reference));
                    }
                }
            }

            // otherwise just create a basic type without reflecting back into the managed side.
            IntPtr func = Marshal.ReadIntPtr(Runtime.PyTypeType, TypeOffset.tp_new);
            IntPtr type = NativeCall.Call_3(func, tp, args, kw);

            if (type == IntPtr.Zero)
            {
                return(IntPtr.Zero);
            }

            var flags = (TypeFlags)Util.ReadCLong(type, TypeOffset.tp_flags);

            if (!flags.HasFlag(TypeFlags.Ready))
            {
                throw new NotSupportedException("PyType.tp_new returned an incomplete type");
            }
            flags |= TypeFlags.HasClrInstance;
            flags |= TypeFlags.HeapType;
            flags |= TypeFlags.BaseType;
            flags |= TypeFlags.Subclass;
            flags |= TypeFlags.HaveGC;
            Util.WriteCLong(type, TypeOffset.tp_flags, (int)flags);

            TypeManager.CopySlot(base_type, type, TypeOffset.tp_dealloc);

            // Hmm - the standard subtype_traverse, clear look at ob_size to
            // do things, so to allow gc to work correctly we need to move
            // our hidden handle out of ob_size. Then, in theory we can
            // comment this out and still not crash.
            TypeManager.CopySlot(base_type, type, TypeOffset.tp_traverse);
            TypeManager.CopySlot(base_type, type, TypeOffset.tp_clear);

            // derived types must have their GCHandle at the same offset as the base types
            int clrInstOffset = Marshal.ReadInt32(base_type, Offsets.tp_clr_inst_offset);

            Marshal.WriteInt32(type, Offsets.tp_clr_inst_offset, clrInstOffset);

            // for now, move up hidden handle...
            IntPtr gc = Marshal.ReadIntPtr(base_type, Offsets.tp_clr_inst);

            Marshal.WriteIntPtr(type, Offsets.tp_clr_inst, gc);

            Runtime.PyType_Modified(new BorrowedReference(type));

            return(type);
        }