@@ -169,6 +169,8 @@ public class Runtime
169169 /// </summary>
170170 internal static readonly Encoding PyEncoding = _UCS == 2 ? Encoding . Unicode : Encoding . UTF32 ;
171171
172+ private static PyReferenceCollection _pyRefs = new PyReferenceCollection ( ) ;
173+
172174 /// <summary>
173175 /// Initialize the runtime...
174176 /// </summary>
@@ -194,16 +196,46 @@ internal static void Initialize(bool initSigs = false)
194196 TypeManager . Reset ( ) ;
195197
196198 IntPtr op ;
197- IntPtr dict ;
198- if ( IsPython3 )
199- {
200- op = PyImport_ImportModule ( "builtins" ) ;
201- dict = PyObject_GetAttrString ( op , "__dict__" ) ;
202- }
203- else // Python2
204199 {
205- dict = PyImport_GetModuleDict ( ) ;
206- op = PyDict_GetItemString ( dict , "__builtin__" ) ;
200+ var builtins = GetBuiltins ( ) ;
201+ SetPyMember ( ref PyNotImplemented , PyObject_GetAttrString ( builtins , "NotImplemented" ) ,
202+ ( ) => PyNotImplemented = IntPtr . Zero ) ;
203+
204+ SetPyMember ( ref PyBaseObjectType , PyObject_GetAttrString ( builtins , "object" ) ,
205+ ( ) => PyBaseObjectType = IntPtr . Zero ) ;
206+
207+ SetPyMember ( ref PyNone , PyObject_GetAttrString ( builtins , "None" ) ,
208+ ( ) => PyNone = IntPtr . Zero ) ;
209+ SetPyMember ( ref PyTrue , PyObject_GetAttrString ( builtins , "True" ) ,
210+ ( ) => PyTrue = IntPtr . Zero ) ;
211+ SetPyMember ( ref PyFalse , PyObject_GetAttrString ( builtins , "False" ) ,
212+ ( ) => PyFalse = IntPtr . Zero ) ;
213+
214+ SetPyMember ( ref PyBoolType , PyObject_Type ( PyTrue ) ,
215+ ( ) => PyBoolType = IntPtr . Zero ) ;
216+ SetPyMember ( ref PyNoneType , PyObject_Type ( PyNone ) ,
217+ ( ) => PyNoneType = IntPtr . Zero ) ;
218+ SetPyMember ( ref PyTypeType , PyObject_Type ( PyNoneType ) ,
219+ ( ) => PyTypeType = IntPtr . Zero ) ;
220+
221+ op = PyObject_GetAttrString ( builtins , "len" ) ;
222+ SetPyMember ( ref PyMethodType , PyObject_Type ( op ) ,
223+ ( ) => PyMethodType = IntPtr . Zero ) ;
224+ XDecref ( op ) ;
225+
226+ // For some arcane reason, builtins.__dict__.__setitem__ is *not*
227+ // a wrapper_descriptor, even though dict.__setitem__ is.
228+ //
229+ // object.__init__ seems safe, though.
230+ op = PyObject_GetAttrString ( PyBaseObjectType , "__init__" ) ;
231+ SetPyMember ( ref PyWrapperDescriptorType , PyObject_Type ( op ) ,
232+ ( ) => PyWrapperDescriptorType = IntPtr . Zero ) ;
233+ XDecref ( op ) ;
234+
235+ SetPyMember ( ref PySuper_Type , PyObject_GetAttrString ( builtins , "super" ) ,
236+ ( ) => PySuper_Type = IntPtr . Zero ) ;
237+
238+ XDecref ( builtins ) ;
207239 }
208240 PyNotImplemented = PyObject_GetAttrString ( op , "NotImplemented" ) ;
209241 PyBaseObjectType = PyObject_GetAttrString ( op , "object" ) ;
@@ -234,60 +266,73 @@ internal static void Initialize(bool initSigs = false)
234266#endif
235267
236268 op = PyString_FromString ( "string" ) ;
237- PyStringType = PyObject_Type ( op ) ;
269+ SetPyMember ( ref PyStringType , PyObject_Type ( op ) ,
270+ ( ) => PyStringType = IntPtr . Zero ) ;
238271 XDecref ( op ) ;
239272
240273 op = PyUnicode_FromString ( "unicode" ) ;
241- PyUnicodeType = PyObject_Type ( op ) ;
274+ SetPyMember ( ref PyUnicodeType , PyObject_Type ( op ) ,
275+ ( ) => PyUnicodeType = IntPtr . Zero ) ;
242276 XDecref ( op ) ;
243277
244278#if PYTHON3
245279 op = PyBytes_FromString ( "bytes" ) ;
246- PyBytesType = PyObject_Type ( op ) ;
280+ SetPyMember ( ref PyBytesType , PyObject_Type ( op ) ,
281+ ( ) => PyBytesType = IntPtr . Zero ) ;
247282 XDecref ( op ) ;
248283#endif
249284
250285 op = PyTuple_New ( 0 ) ;
251- PyTupleType = PyObject_Type ( op ) ;
286+ SetPyMember ( ref PyTupleType , PyObject_Type ( op ) ,
287+ ( ) => PyTupleType = IntPtr . Zero ) ;
252288 XDecref ( op ) ;
253289
254290 op = PyList_New ( 0 ) ;
255- PyListType = PyObject_Type ( op ) ;
291+ SetPyMember ( ref PyListType , PyObject_Type ( op ) ,
292+ ( ) => PyListType = IntPtr . Zero ) ;
256293 XDecref ( op ) ;
257294
258295 op = PyDict_New ( ) ;
259- PyDictType = PyObject_Type ( op ) ;
296+ SetPyMember ( ref PyDictType , PyObject_Type ( op ) ,
297+ ( ) => PyDictType = IntPtr . Zero ) ;
260298 XDecref ( op ) ;
261299
262300 op = PyInt_FromInt32 ( 0 ) ;
263- PyIntType = PyObject_Type ( op ) ;
301+ SetPyMember ( ref PyIntType , PyObject_Type ( op ) ,
302+ ( ) => PyIntType = IntPtr . Zero ) ;
264303 XDecref ( op ) ;
265304
266305 op = PyLong_FromLong ( 0 ) ;
267- PyLongType = PyObject_Type ( op ) ;
306+ SetPyMember ( ref PyLongType , PyObject_Type ( op ) ,
307+ ( ) => PyLongType = IntPtr . Zero ) ;
268308 XDecref ( op ) ;
269309
270310 op = PyFloat_FromDouble ( 0 ) ;
271- PyFloatType = PyObject_Type ( op ) ;
311+ SetPyMember ( ref PyFloatType , PyObject_Type ( op ) ,
312+ ( ) => PyFloatType = IntPtr . Zero ) ;
272313 XDecref ( op ) ;
273314
274- #if PYTHON3
315+ #if ! PYTHON2
275316 PyClassType = IntPtr . Zero ;
276317 PyInstanceType = IntPtr . Zero ;
277- #elif PYTHON2
278- IntPtr s = PyString_FromString ( "_temp" ) ;
279- IntPtr d = PyDict_New ( ) ;
318+ #else
319+ {
320+ IntPtr s = PyString_FromString ( "_temp" ) ;
321+ IntPtr d = PyDict_New ( ) ;
280322
281- IntPtr c = PyClass_New ( IntPtr . Zero , d , s ) ;
282- PyClassType = PyObject_Type ( c ) ;
323+ IntPtr c = PyClass_New ( IntPtr . Zero , d , s ) ;
324+ SetPyMember ( ref PyClassType , PyObject_Type ( c ) ,
325+ ( ) => PyClassType = IntPtr . Zero ) ;
283326
284- IntPtr i = PyInstance_New ( c , IntPtr . Zero , IntPtr . Zero ) ;
285- PyInstanceType = PyObject_Type ( i ) ;
327+ IntPtr i = PyInstance_New ( c , IntPtr . Zero , IntPtr . Zero ) ;
328+ SetPyMember ( ref PyInstanceType , PyObject_Type ( i ) ,
329+ ( ) => PyInstanceType = IntPtr . Zero ) ;
286330
287- XDecref ( s ) ;
288- XDecref ( i ) ;
289- XDecref ( c ) ;
290- XDecref ( d ) ;
331+ XDecref ( s ) ;
332+ XDecref ( i ) ;
333+ XDecref ( c ) ;
334+ XDecref ( d ) ;
335+ }
291336#endif
292337
293338 Error = new IntPtr ( - 1 ) ;
@@ -381,6 +426,9 @@ internal static void Shutdown()
381426 Exceptions . Shutdown ( ) ;
382427 ImportHook . Shutdown ( ) ;
383428 Finalizer . Shutdown ( ) ;
429+ // TOOD: PyCLRMetaType's release operation still in #958
430+ PyCLRMetaType = IntPtr . Zero ;
431+ ResetPyMembers ( ) ;
384432 Py_Finalize ( ) ;
385433 }
386434
@@ -394,6 +442,19 @@ internal static int AtExit()
394442 return 0 ;
395443 }
396444
445+ private static void SetPyMember ( ref IntPtr obj , IntPtr value , Action onRelease )
446+ {
447+ // XXX: For current usages, value should not be null.
448+ PythonException . ThrowIfIsNull ( value ) ;
449+ obj = value ;
450+ _pyRefs . Add ( value , onRelease ) ;
451+ }
452+
453+ private static void ResetPyMembers ( )
454+ {
455+ _pyRefs . Release ( ) ;
456+ }
457+
397458 internal static IntPtr Py_single_input = ( IntPtr ) 256 ;
398459 internal static IntPtr Py_file_input = ( IntPtr ) 257 ;
399460 internal static IntPtr Py_eval_input = ( IntPtr ) 258 ;
@@ -402,6 +463,7 @@ internal static int AtExit()
402463 internal static IntPtr PyModuleType ;
403464 internal static IntPtr PyClassType ;
404465 internal static IntPtr PyInstanceType ;
466+ internal static IntPtr PySuper_Type ;
405467 internal static IntPtr PyCLRMetaType ;
406468 internal static IntPtr PyMethodType ;
407469 internal static IntPtr PyWrapperDescriptorType ;
@@ -974,7 +1036,7 @@ internal static int PyObject_Compare(IntPtr value1, IntPtr value2)
9741036
9751037 internal static long PyObject_Size( IntPtr pointer)
9761038 {
977- return ( long ) _PyObject_Size( pointer) ;
1039+ return ( long ) _PyObject_Size( pointer) ;
9781040 }
9791041
9801042 [ DllImport( _PythonDll, CallingConvention = CallingConvention. Cdecl, EntryPoint = "PyObject_Size") ]
@@ -1090,7 +1152,7 @@ internal static bool PyLong_Check(IntPtr ob)
10901152
10911153 internal static IntPtr PyLong_FromUnsignedLong( object value)
10921154 {
1093- if ( Is32Bit || IsWindows)
1155+ if ( Is32Bit || IsWindows)
10941156 return PyLong_FromUnsignedLong32( Convert. ToUInt32( value) ) ;
10951157 else
10961158 return PyLong_FromUnsignedLong64( Convert. ToUInt64( value) ) ;
@@ -1280,7 +1342,7 @@ internal static int PySequence_DelSlice(IntPtr pointer, long i1, long i2)
12801342
12811343 internal static long PySequence_Size( IntPtr pointer)
12821344 {
1283- return ( long ) _PySequence_Size( pointer) ;
1345+ return ( long ) _PySequence_Size( pointer) ;
12841346 }
12851347
12861348 [ DllImport( _PythonDll, CallingConvention = CallingConvention. Cdecl, EntryPoint = "PySequence_Size") ]
@@ -1305,7 +1367,7 @@ internal static IntPtr PySequence_Repeat(IntPtr pointer, long count)
13051367
13061368 internal static long PySequence_Count( IntPtr pointer, IntPtr value)
13071369 {
1308- return ( long ) _PySequence_Count( pointer, value) ;
1370+ return ( long ) _PySequence_Count( pointer, value) ;
13091371 }
13101372
13111373 [ DllImport( _PythonDll, CallingConvention = CallingConvention. Cdecl, EntryPoint = "PySequence_Count") ]
@@ -1348,7 +1410,7 @@ internal static IntPtr PyString_FromString(string value)
13481410
13491411 internal static long PyBytes_Size( IntPtr op)
13501412 {
1351- return ( long ) _PyBytes_Size( op) ;
1413+ return ( long ) _PyBytes_Size( op) ;
13521414 }
13531415
13541416 [ DllImport( _PythonDll, CallingConvention = CallingConvention. Cdecl, EntryPoint = "PyBytes_Size") ]
@@ -1579,7 +1641,7 @@ internal static bool PyDict_Check(IntPtr ob)
15791641
15801642 internal static long PyDict_Size( IntPtr pointer)
15811643 {
1582- return ( long ) _PyDict_Size( pointer) ;
1644+ return ( long ) _PyDict_Size( pointer) ;
15831645 }
15841646
15851647 [ DllImport( _PythonDll, CallingConvention = CallingConvention. Cdecl, EntryPoint = "PyDict_Size") ]
@@ -1657,7 +1719,7 @@ internal static int PyList_SetSlice(IntPtr pointer, long start, long end, IntPtr
16571719
16581720 internal static long PyList_Size( IntPtr pointer)
16591721 {
1660- return ( long ) _PyList_Size( pointer) ;
1722+ return ( long ) _PyList_Size( pointer) ;
16611723 }
16621724
16631725 [ DllImport( _PythonDll, CallingConvention = CallingConvention. Cdecl, EntryPoint = "PyList_Size") ]
@@ -1706,7 +1768,7 @@ internal static IntPtr PyTuple_GetSlice(IntPtr pointer, long start, long end)
17061768
17071769 internal static long PyTuple_Size( IntPtr pointer)
17081770 {
1709- return ( long ) _PyTuple_Size( pointer) ;
1771+ return ( long ) _PyTuple_Size( pointer) ;
17101772 }
17111773
17121774 [ DllImport( _PythonDll, CallingConvention = CallingConvention. Cdecl, EntryPoint = "PyTuple_Size") ]
@@ -1757,6 +1819,9 @@ internal static bool PyIter_Check(IntPtr pointer)
17571819 [ DllImport( _PythonDll, CallingConvention = CallingConvention. Cdecl) ]
17581820 internal static extern IntPtr PyImport_Import( IntPtr name) ;
17591821
1822+ /// <summary>
1823+ /// Return value: New reference.
1824+ /// </summary>
17601825 [ DllImport( _PythonDll, CallingConvention = CallingConvention. Cdecl) ]
17611826 internal static extern IntPtr PyImport_ImportModule( string name) ;
17621827
@@ -1956,5 +2021,39 @@ internal static void SetNoSiteFlag()
19562021 }
19572022 }
19582023 }
2024+
2025+ /// <summary>
2026+ /// Return value: New reference.
2027+ /// </summary>
2028+ internal static IntPtr GetBuiltins( )
2029+ {
2030+ return IsPython3 ? PyImport_ImportModule( "builtins")
2031+ : PyImport_ImportModule( "__builtin__") ;
2032+ }
2033+ }
2034+
2035+
2036+ class PyReferenceCollection
2037+ {
2038+ private List< KeyValuePair< IntPtr, Action>> _actions = new List< KeyValuePair< IntPtr, Action>> ( ) ;
2039+
2040+ /// <summary>
2041+ /// Record obj's address to release the obj in the future,
2042+ /// obj must alive before calling Release.
2043+ /// </summary>
2044+ public void Add( IntPtr ob, Action onRelease)
2045+ {
2046+ _actions. Add( new KeyValuePair< IntPtr, Action> ( ob, onRelease) ) ;
2047+ }
2048+
2049+ public void Release( )
2050+ {
2051+ foreach ( var item in _actions)
2052+ {
2053+ Runtime. XDecref( item. Key) ;
2054+ item. Value? . Invoke( ) ;
2055+ }
2056+ _actions. Clear( ) ;
2057+ }
19592058 }
19602059}
0 commit comments