private static SlotsHolder CreateSolotsHolder(IntPtr type) { var holder = new SlotsHolder(type); _slotsHolders.Add(type, holder); return(holder); }
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); }
/// <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); }
public static void Release() { if (Runtime.Refcount(PyCLRMetaType) > 1) { _metaSlotsHodler.ResetSlots(); } Runtime.Py_CLEAR(ref PyCLRMetaType); _metaSlotsHodler = null; }
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); } }
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); }
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); } }
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); }
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) } }
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); } }
/// <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); }
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); }
/// <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)); } }
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) } }
/// <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); }
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); }
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); }
protected override void SetTypeNewSlot(BorrowedReference pyType, SlotsHolder slotsHolder) { // Python derived types rely on base tp_new and overridden __init__ }