@@ -17,33 +17,38 @@ namespace Python.Runtime
17
17
/// </summary>
18
18
internal class TypeManager
19
19
{
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 > ( ) ;
22
23
23
24
static TypeManager ( )
24
25
{
25
- tbFlags = BindingFlags . Public | BindingFlags . Static ;
26
- cache = new Dictionary < Type , IntPtr > ( 128 ) ;
26
+
27
27
}
28
28
29
29
public static void Reset ( )
30
30
{
31
- cache = new Dictionary < Type , IntPtr > ( 128 ) ;
31
+ cache . Clear ( ) ;
32
32
}
33
33
34
34
internal static void RemoveTypes ( )
35
35
{
36
36
foreach ( var tpHandle in cache . Values )
37
37
{
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 ) )
41
40
{
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
+ }
43
47
}
44
48
Runtime . XDecref ( tpHandle ) ;
45
49
}
46
50
cache . Clear ( ) ;
51
+ _slotsHolders . Clear ( ) ;
47
52
}
48
53
49
54
/// <summary>
@@ -107,7 +112,7 @@ internal static IntPtr CreateType(Type impl)
107
112
var offset = ( IntPtr ) ObjectOffset . DictOffset ( type ) ;
108
113
Marshal . WriteIntPtr ( type , TypeOffset . tp_dictoffset , offset ) ;
109
114
110
- SlotsHolder slotsHolder = new SlotsHolder ( type ) ;
115
+ SlotsHolder slotsHolder = CreateSlotsHolder ( type ) ;
111
116
InitializeSlots ( type , impl , slotsHolder ) ;
112
117
113
118
int flags = TypeFlags . Default | TypeFlags . Managed |
@@ -123,10 +128,6 @@ internal static IntPtr CreateType(Type impl)
123
128
Runtime . PyDict_SetItemString ( dict , "__module__" , mod ) ;
124
129
Runtime . XDecref ( mod ) ;
125
130
126
- IntPtr capsule = slotsHolder . ToCapsule ( ) ;
127
- Runtime . PyDict_SetItemString ( dict , SlotsHolder . HolderKeyName , capsule ) ;
128
- Runtime . XDecref ( capsule ) ;
129
-
130
131
InitMethods ( type , impl ) ;
131
132
return type ;
132
133
}
@@ -180,7 +181,7 @@ internal static IntPtr CreateType(ManagedType impl, Type clrType)
180
181
Marshal . WriteIntPtr ( type , TypeOffset . tp_dictoffset , ( IntPtr ) tp_dictoffset ) ;
181
182
182
183
// 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 ) ;
184
185
InitializeSlots ( type , impl . GetType ( ) , slotsHolder ) ;
185
186
186
187
// add a __len__ slot for inheritors of ICollection and ICollection<>
@@ -218,10 +219,6 @@ internal static IntPtr CreateType(ManagedType impl, Type clrType)
218
219
Runtime . PyDict_SetItemString ( dict , "__module__" , mod ) ;
219
220
Runtime . XDecref ( mod ) ;
220
221
221
- IntPtr capsule = slotsHolder . ToCapsule ( ) ;
222
- Runtime . PyDict_SetItemString ( dict , SlotsHolder . HolderKeyName , capsule ) ;
223
- Runtime . XDecref ( capsule ) ;
224
-
225
222
// Hide the gchandle of the implementation in a magic type slot.
226
223
GCHandle gc = GCHandle . Alloc ( impl ) ;
227
224
Marshal . WriteIntPtr ( type , TypeOffset . magic ( ) , ( IntPtr ) gc ) ;
@@ -357,7 +354,7 @@ internal static void FreeMethodDef(IntPtr mdef)
357
354
}
358
355
}
359
356
360
- internal static IntPtr CreateMetaType ( Type impl )
357
+ internal static IntPtr CreateMetaType ( Type impl , out SlotsHolder slotsHolder )
361
358
{
362
359
// The managed metatype is functionally little different than the
363
360
// standard Python metatype (PyType_Type). It overrides certain of
@@ -376,9 +373,8 @@ internal static IntPtr CreateMetaType(Type impl)
376
373
// tp_dictoffset, tp_weaklistoffset,
377
374
// tp_traverse, tp_clear, tp_is_gc, etc.
378
375
379
- SlotsHolder slotsHolder = new SlotsHolder ( type ) ;
380
376
// Override type slots with those of the managed implementation.
381
-
377
+ slotsHolder = new SlotsHolder ( type ) ;
382
378
InitializeSlots ( type , impl , slotsHolder ) ;
383
379
384
380
int flags = TypeFlags . Default ;
@@ -456,10 +452,6 @@ internal static IntPtr CreateMetaType(Type impl)
456
452
IntPtr mod = Runtime . PyString_FromString ( "CLR" ) ;
457
453
Runtime . PyDict_SetItemString ( dict , "__module__" , mod ) ;
458
454
459
- IntPtr capsule = slotsHolder . ToCapsule ( ) ;
460
- Runtime . PyDict_SetItemString ( dict , SlotsHolder . HolderKeyName , capsule ) ;
461
- Runtime . XDecref ( capsule ) ;
462
-
463
455
//DebugUtil.DumpType(type);
464
456
465
457
return type ;
@@ -494,7 +486,7 @@ internal static IntPtr BasicSubType(string name, IntPtr base_, Type impl)
494
486
CopySlot ( base_ , type , TypeOffset . tp_clear ) ;
495
487
CopySlot ( base_ , type , TypeOffset . tp_is_gc ) ;
496
488
497
- SlotsHolder slotsHolder = new SlotsHolder ( type ) ;
489
+ SlotsHolder slotsHolder = CreateSlotsHolder ( type ) ;
498
490
InitializeSlots ( type , impl , slotsHolder ) ;
499
491
500
492
if ( Runtime . PyType_Ready ( type ) != 0 )
@@ -506,10 +498,6 @@ internal static IntPtr BasicSubType(string name, IntPtr base_, Type impl)
506
498
IntPtr mod = Runtime . PyString_FromString ( "CLR" ) ;
507
499
Runtime . PyDict_SetItemString ( tp_dict , "__module__" , mod ) ;
508
500
509
- IntPtr capsule = slotsHolder . ToCapsule ( ) ;
510
- Runtime . PyDict_SetItemString ( tp_dict , SlotsHolder . HolderKeyName , capsule ) ;
511
- Runtime . XDecref ( capsule ) ;
512
-
513
501
return type ;
514
502
}
515
503
@@ -982,17 +970,20 @@ internal static void CopySlot(IntPtr from, IntPtr to, int offset)
982
970
IntPtr fp = Marshal . ReadIntPtr ( from , offset ) ;
983
971
Marshal . WriteIntPtr ( to , offset , fp ) ;
984
972
}
973
+
974
+ private static SlotsHolder CreateSlotsHolder ( IntPtr type )
975
+ {
976
+ var holder = new SlotsHolder ( type ) ;
977
+ _slotsHolders . Add ( type , holder ) ;
978
+ return holder ;
979
+ }
985
980
}
986
981
987
982
class SlotsHolder
988
983
{
989
- public const string HolderKeyName = "_slots_holder" ;
990
984
public delegate void Resetor ( IntPtr type , int offset ) ;
991
985
992
- private GCHandle _handle ;
993
- private Interop . DestructorFunc _destructor ;
994
- private IntPtr _capsule ;
995
- private IntPtr _type ;
986
+ private readonly IntPtr _type ;
996
987
private Dictionary < int , ThunkInfo > _slots = new Dictionary < int , ThunkInfo > ( ) ;
997
988
private List < Delegate > _keepalive = new List < Delegate > ( ) ;
998
989
private Dictionary < int , Resetor > _customRestors = new Dictionary < int , Resetor > ( ) ;
@@ -1028,39 +1019,7 @@ public void KeeapAlive(Delegate d)
1028
1019
_keepalive . Add ( d ) ;
1029
1020
}
1030
1021
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 ( )
1064
1023
{
1065
1024
if ( _alredyReset )
1066
1025
{
@@ -1104,21 +1063,6 @@ private void ResetSlots()
1104
1063
Marshal . WriteIntPtr ( _type , TypeOffset . tp_bases , tp_bases ) ;
1105
1064
}
1106
1065
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
-
1122
1066
private static IntPtr GetDefaultSlot ( int offset )
1123
1067
{
1124
1068
if ( offset == TypeOffset . tp_clear
@@ -1159,4 +1103,37 @@ private static IntPtr GetDefaultSlot(int offset)
1159
1103
return Marshal . ReadIntPtr ( Runtime . PyTypeType , offset ) ;
1160
1104
}
1161
1105
}
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
+ }
1162
1139
}
0 commit comments