Skip to content

Commit e7effd8

Browse files
amos402Félix Bourbonnais
authored andcommitted
Partial cherry pick of 433d0f6
Manipulate SlotsHolder manually instead of Capsule mechanism
1 parent 03674d2 commit e7effd8

File tree

3 files changed

+72
-89
lines changed

3 files changed

+72
-89
lines changed

src/runtime/metatype.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,25 +11,25 @@ namespace Python.Runtime
1111
internal class MetaType : ManagedType
1212
{
1313
private static IntPtr PyCLRMetaType;
14-
14+
private static SlotsHolder _metaSlotsHodler;
1515

1616
/// <summary>
1717
/// Metatype initialization. This bootstraps the CLR metatype to life.
1818
/// </summary>
1919
public static IntPtr Initialize()
2020
{
21-
PyCLRMetaType = TypeManager.CreateMetaType(typeof(MetaType));
21+
PyCLRMetaType = TypeManager.CreateMetaType(typeof(MetaType), out _metaSlotsHodler);
2222
return PyCLRMetaType;
2323
}
2424

2525
public static void Release()
2626
{
2727
if (Runtime.Refcount(PyCLRMetaType) > 1)
2828
{
29-
SlotsHolder.ReleaseTypeSlots(PyCLRMetaType);
29+
_metaSlotsHodler.ResetSlots();
3030
}
31-
Runtime.XDecref(PyCLRMetaType);
32-
PyCLRMetaType = IntPtr.Zero;
31+
Runtime.Py_CLEAR(ref PyCLRMetaType);
32+
_metaSlotsHodler = null;
3333
}
3434

3535
/// <summary>

src/runtime/runtime.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1912,6 +1912,12 @@ internal static IntPtr PyMem_Realloc(IntPtr ptr, long size)
19121912
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
19131913
internal static extern void PyErr_Print();
19141914

1915+
internal static void Py_CLEAR(ref IntPtr ob)
1916+
{
1917+
XDecref(ob);
1918+
ob = IntPtr.Zero;
1919+
}
1920+
19151921
//====================================================================
19161922
// Python Capsules API
19171923
//====================================================================

src/runtime/typemanager.cs

Lines changed: 61 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -17,33 +17,38 @@ namespace Python.Runtime
1717
/// </summary>
1818
internal class TypeManager
1919
{
20-
private static BindingFlags tbFlags;
21-
private static Dictionary<Type, IntPtr> cache;
20+
private const BindingFlags tbFlags = BindingFlags.Public | BindingFlags.Static;
21+
private static readonly Dictionary<Type, IntPtr> cache = new Dictionary<Type, IntPtr>();
22+
private static readonly Dictionary<IntPtr, SlotsHolder> _slotsHolders = new Dictionary<IntPtr, SlotsHolder>();
2223

2324
static TypeManager()
2425
{
25-
tbFlags = BindingFlags.Public | BindingFlags.Static;
26-
cache = new Dictionary<Type, IntPtr>(128);
26+
2727
}
2828

2929
public static void Reset()
3030
{
31-
cache = new Dictionary<Type, IntPtr>(128);
31+
cache.Clear();
3232
}
3333

3434
internal static void RemoveTypes()
3535
{
3636
foreach (var tpHandle in cache.Values)
3737
{
38-
// If refcount > 1, it needs to reset the managed slot,
39-
// otherwise it can dealloc without any trick.
40-
if (Runtime.Refcount(tpHandle) > 1)
38+
SlotsHolder holder;
39+
if (_slotsHolders.TryGetValue(tpHandle, out holder))
4140
{
42-
SlotsHolder.ReleaseTypeSlots(tpHandle);
41+
// If refcount > 1, it needs to reset the managed slot,
42+
// otherwise it can dealloc without any trick.
43+
if (Runtime.Refcount(tpHandle) > 1)
44+
{
45+
holder.ResetSlots();
46+
}
4347
}
4448
Runtime.XDecref(tpHandle);
4549
}
4650
cache.Clear();
51+
_slotsHolders.Clear();
4752
}
4853

4954
/// <summary>
@@ -107,7 +112,7 @@ internal static IntPtr CreateType(Type impl)
107112
var offset = (IntPtr)ObjectOffset.DictOffset(type);
108113
Marshal.WriteIntPtr(type, TypeOffset.tp_dictoffset, offset);
109114

110-
SlotsHolder slotsHolder = new SlotsHolder(type);
115+
SlotsHolder slotsHolder = CreateSlotsHolder(type);
111116
InitializeSlots(type, impl, slotsHolder);
112117

113118
int flags = TypeFlags.Default | TypeFlags.Managed |
@@ -123,10 +128,6 @@ internal static IntPtr CreateType(Type impl)
123128
Runtime.PyDict_SetItemString(dict, "__module__", mod);
124129
Runtime.XDecref(mod);
125130

126-
IntPtr capsule = slotsHolder.ToCapsule();
127-
Runtime.PyDict_SetItemString(dict, SlotsHolder.HolderKeyName, capsule);
128-
Runtime.XDecref(capsule);
129-
130131
InitMethods(type, impl);
131132
return type;
132133
}
@@ -180,7 +181,7 @@ internal static IntPtr CreateType(ManagedType impl, Type clrType)
180181
Marshal.WriteIntPtr(type, TypeOffset.tp_dictoffset, (IntPtr)tp_dictoffset);
181182

182183
// we want to do this after the slot stuff above in case the class itself implements a slot method
183-
SlotsHolder slotsHolder = new SlotsHolder(type);
184+
SlotsHolder slotsHolder = CreateSlotsHolder(type);
184185
InitializeSlots(type, impl.GetType(), slotsHolder);
185186

186187
// add a __len__ slot for inheritors of ICollection and ICollection<>
@@ -218,10 +219,6 @@ internal static IntPtr CreateType(ManagedType impl, Type clrType)
218219
Runtime.PyDict_SetItemString(dict, "__module__", mod);
219220
Runtime.XDecref(mod);
220221

221-
IntPtr capsule = slotsHolder.ToCapsule();
222-
Runtime.PyDict_SetItemString(dict, SlotsHolder.HolderKeyName, capsule);
223-
Runtime.XDecref(capsule);
224-
225222
// Hide the gchandle of the implementation in a magic type slot.
226223
GCHandle gc = GCHandle.Alloc(impl);
227224
Marshal.WriteIntPtr(type, TypeOffset.magic(), (IntPtr)gc);
@@ -357,7 +354,7 @@ internal static void FreeMethodDef(IntPtr mdef)
357354
}
358355
}
359356

360-
internal static IntPtr CreateMetaType(Type impl)
357+
internal static IntPtr CreateMetaType(Type impl, out SlotsHolder slotsHolder)
361358
{
362359
// The managed metatype is functionally little different than the
363360
// standard Python metatype (PyType_Type). It overrides certain of
@@ -376,9 +373,8 @@ internal static IntPtr CreateMetaType(Type impl)
376373
// tp_dictoffset, tp_weaklistoffset,
377374
// tp_traverse, tp_clear, tp_is_gc, etc.
378375

379-
SlotsHolder slotsHolder = new SlotsHolder(type);
380376
// Override type slots with those of the managed implementation.
381-
377+
slotsHolder = new SlotsHolder(type);
382378
InitializeSlots(type, impl, slotsHolder);
383379

384380
int flags = TypeFlags.Default;
@@ -456,10 +452,6 @@ internal static IntPtr CreateMetaType(Type impl)
456452
IntPtr mod = Runtime.PyString_FromString("CLR");
457453
Runtime.PyDict_SetItemString(dict, "__module__", mod);
458454

459-
IntPtr capsule = slotsHolder.ToCapsule();
460-
Runtime.PyDict_SetItemString(dict, SlotsHolder.HolderKeyName, capsule);
461-
Runtime.XDecref(capsule);
462-
463455
//DebugUtil.DumpType(type);
464456

465457
return type;
@@ -494,7 +486,7 @@ internal static IntPtr BasicSubType(string name, IntPtr base_, Type impl)
494486
CopySlot(base_, type, TypeOffset.tp_clear);
495487
CopySlot(base_, type, TypeOffset.tp_is_gc);
496488

497-
SlotsHolder slotsHolder = new SlotsHolder(type);
489+
SlotsHolder slotsHolder = CreateSlotsHolder(type);
498490
InitializeSlots(type, impl, slotsHolder);
499491

500492
if (Runtime.PyType_Ready(type) != 0)
@@ -506,10 +498,6 @@ internal static IntPtr BasicSubType(string name, IntPtr base_, Type impl)
506498
IntPtr mod = Runtime.PyString_FromString("CLR");
507499
Runtime.PyDict_SetItemString(tp_dict, "__module__", mod);
508500

509-
IntPtr capsule = slotsHolder.ToCapsule();
510-
Runtime.PyDict_SetItemString(tp_dict, SlotsHolder.HolderKeyName, capsule);
511-
Runtime.XDecref(capsule);
512-
513501
return type;
514502
}
515503

@@ -982,17 +970,20 @@ internal static void CopySlot(IntPtr from, IntPtr to, int offset)
982970
IntPtr fp = Marshal.ReadIntPtr(from, offset);
983971
Marshal.WriteIntPtr(to, offset, fp);
984972
}
973+
974+
private static SlotsHolder CreateSlotsHolder(IntPtr type)
975+
{
976+
var holder = new SlotsHolder(type);
977+
_slotsHolders.Add(type, holder);
978+
return holder;
979+
}
985980
}
986981

987982
class SlotsHolder
988983
{
989-
public const string HolderKeyName = "_slots_holder";
990984
public delegate void Resetor(IntPtr type, int offset);
991985

992-
private GCHandle _handle;
993-
private Interop.DestructorFunc _destructor;
994-
private IntPtr _capsule;
995-
private IntPtr _type;
986+
private readonly IntPtr _type;
996987
private Dictionary<int, ThunkInfo> _slots = new Dictionary<int, ThunkInfo>();
997988
private List<Delegate> _keepalive = new List<Delegate>();
998989
private Dictionary<int, Resetor> _customRestors = new Dictionary<int, Resetor>();
@@ -1028,39 +1019,7 @@ public void KeeapAlive(Delegate d)
10281019
_keepalive.Add(d);
10291020
}
10301021

1031-
public IntPtr ToCapsule()
1032-
{
1033-
if (_capsule != IntPtr.Zero)
1034-
{
1035-
Runtime.XIncref(_capsule);
1036-
return _capsule;
1037-
}
1038-
_handle = GCHandle.Alloc(this);
1039-
_destructor = OnDestruct;
1040-
var fp = Marshal.GetFunctionPointerForDelegate(_destructor);
1041-
_capsule = Runtime.PyCapsule_New((IntPtr)_handle, null, fp);
1042-
return _capsule;
1043-
}
1044-
1045-
public static void ReleaseTypeSlots(IntPtr type)
1046-
{
1047-
IntPtr capsule = Runtime.PyObject_GetAttrString(type, HolderKeyName);
1048-
if (capsule == IntPtr.Zero)
1049-
{
1050-
return;
1051-
}
1052-
var self = RecoverFromCapsule(capsule);
1053-
self.ResetSlots();
1054-
Runtime.XDecref(capsule);
1055-
1056-
IntPtr tp_dict = Marshal.ReadIntPtr(type, TypeOffset.tp_dict);
1057-
if (Runtime.PyDict_DelItemString(tp_dict, HolderKeyName) != 0)
1058-
{
1059-
throw new PythonException();
1060-
}
1061-
}
1062-
1063-
private void ResetSlots()
1022+
public void ResetSlots()
10641023
{
10651024
if (_alredyReset)
10661025
{
@@ -1104,21 +1063,6 @@ private void ResetSlots()
11041063
Marshal.WriteIntPtr(_type, TypeOffset.tp_bases, tp_bases);
11051064
}
11061065

1107-
private static void OnDestruct(IntPtr ob)
1108-
{
1109-
var self = RecoverFromCapsule(ob);
1110-
self._handle.Free();
1111-
self.ResetSlots();
1112-
}
1113-
1114-
private static SlotsHolder RecoverFromCapsule(IntPtr ob)
1115-
{
1116-
var ptr = Runtime.PyCapsule_GetPointer(ob, null);
1117-
PythonException.ThrowIfIsNull(ptr);
1118-
GCHandle handle = GCHandle.FromIntPtr(ptr);
1119-
return (SlotsHolder)handle.Target;
1120-
}
1121-
11221066
private static IntPtr GetDefaultSlot(int offset)
11231067
{
11241068
if (offset == TypeOffset.tp_clear
@@ -1159,4 +1103,37 @@ private static IntPtr GetDefaultSlot(int offset)
11591103
return Marshal.ReadIntPtr(Runtime.PyTypeType, offset);
11601104
}
11611105
}
1106+
1107+
1108+
static class SlotHelper
1109+
{
1110+
public static IntPtr CreateObjectType()
1111+
{
1112+
IntPtr globals = Runtime.PyDict_New();
1113+
if (Runtime.PyDict_SetItemString(globals, "__builtins__", Runtime.PyEval_GetBuiltins()) != 0)
1114+
{
1115+
Runtime.XDecref(globals);
1116+
throw new PythonException();
1117+
}
1118+
const string code = "class A(object): pass";
1119+
IntPtr res = Runtime.PyRun_String(code, (IntPtr)RunFlagType.File, globals, globals);
1120+
if (res == IntPtr.Zero)
1121+
{
1122+
try
1123+
{
1124+
throw new PythonException();
1125+
}
1126+
finally
1127+
{
1128+
Runtime.XDecref(globals);
1129+
}
1130+
}
1131+
Runtime.XDecref(res);
1132+
IntPtr A = Runtime.PyDict_GetItemString(globals, "A");
1133+
Debug.Assert(A != IntPtr.Zero);
1134+
Runtime.XIncref(A);
1135+
Runtime.XDecref(globals);
1136+
return A;
1137+
}
1138+
}
11621139
}

0 commit comments

Comments
 (0)