@@ -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,99 +196,116 @@ 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 }
208- PyNotImplemented = PyObject_GetAttrString ( op , "NotImplemented" ) ;
209- PyBaseObjectType = PyObject_GetAttrString ( op , "object" ) ;
210-
211- PyNone = PyObject_GetAttrString ( op , "None" ) ;
212- PyTrue = PyObject_GetAttrString ( op , "True" ) ;
213- PyFalse = PyObject_GetAttrString ( op , "False" ) ;
214-
215- PyBoolType = PyObject_Type ( PyTrue ) ;
216- PyNoneType = PyObject_Type ( PyNone ) ;
217- PyTypeType = PyObject_Type ( PyNoneType ) ;
218-
219- op = PyObject_GetAttrString ( dict , "keys" ) ;
220- PyMethodType = PyObject_Type ( op ) ;
221- XDecref ( op ) ;
222-
223- // For some arcane reason, builtins.__dict__.__setitem__ is *not*
224- // a wrapper_descriptor, even though dict.__setitem__ is.
225- //
226- // object.__init__ seems safe, though.
227- op = PyObject_GetAttrString ( PyBaseObjectType , "__init__" ) ;
228- PyWrapperDescriptorType = PyObject_Type ( op ) ;
229- XDecref ( op ) ;
230-
231- #if PYTHON3
232- XDecref ( dict ) ;
233- #endif
234240
235241 op = PyString_FromString ( "string" ) ;
236- PyStringType = PyObject_Type ( op ) ;
242+ SetPyMember ( ref PyStringType , PyObject_Type ( op ) ,
243+ ( ) => PyStringType = IntPtr . Zero ) ;
237244 XDecref ( op ) ;
238245
239246 op = PyUnicode_FromString ( "unicode" ) ;
240- PyUnicodeType = PyObject_Type ( op ) ;
247+ SetPyMember ( ref PyUnicodeType , PyObject_Type ( op ) ,
248+ ( ) => PyUnicodeType = IntPtr . Zero ) ;
241249 XDecref ( op ) ;
242250
243251#if PYTHON3
244252 op = PyBytes_FromString ( "bytes" ) ;
245- PyBytesType = PyObject_Type ( op ) ;
253+ SetPyMember ( ref PyBytesType , PyObject_Type ( op ) ,
254+ ( ) => PyBytesType = IntPtr . Zero ) ;
246255 XDecref ( op ) ;
247256#endif
248257
249258 op = PyTuple_New ( 0 ) ;
250- PyTupleType = PyObject_Type ( op ) ;
259+ SetPyMember ( ref PyTupleType , PyObject_Type ( op ) ,
260+ ( ) => PyTupleType = IntPtr . Zero ) ;
251261 XDecref ( op ) ;
252262
253263 op = PyList_New ( 0 ) ;
254- PyListType = PyObject_Type ( op ) ;
264+ SetPyMember ( ref PyListType , PyObject_Type ( op ) ,
265+ ( ) => PyListType = IntPtr . Zero ) ;
255266 XDecref ( op ) ;
256267
257268 op = PyDict_New ( ) ;
258- PyDictType = PyObject_Type ( op ) ;
269+ SetPyMember ( ref PyDictType , PyObject_Type ( op ) ,
270+ ( ) => PyDictType = IntPtr . Zero ) ;
259271 XDecref ( op ) ;
260272
261273 op = PyInt_FromInt32 ( 0 ) ;
262- PyIntType = PyObject_Type ( op ) ;
274+ SetPyMember ( ref PyIntType , PyObject_Type ( op ) ,
275+ ( ) => PyIntType = IntPtr . Zero ) ;
263276 XDecref ( op ) ;
264277
265278 op = PyLong_FromLong ( 0 ) ;
266- PyLongType = PyObject_Type ( op ) ;
279+ SetPyMember ( ref PyLongType , PyObject_Type ( op ) ,
280+ ( ) => PyLongType = IntPtr . Zero ) ;
267281 XDecref ( op ) ;
268282
269283 op = PyFloat_FromDouble ( 0 ) ;
270- PyFloatType = PyObject_Type ( op ) ;
284+ SetPyMember ( ref PyFloatType , PyObject_Type ( op ) ,
285+ ( ) => PyFloatType = IntPtr . Zero ) ;
271286 XDecref ( op ) ;
272287
273- #if PYTHON3
288+ #if ! PYTHON2
274289 PyClassType = IntPtr . Zero ;
275290 PyInstanceType = IntPtr . Zero ;
276- #elif PYTHON2
277- IntPtr s = PyString_FromString ( "_temp" ) ;
278- IntPtr d = PyDict_New ( ) ;
291+ #else
292+ {
293+ IntPtr s = PyString_FromString ( "_temp" ) ;
294+ IntPtr d = PyDict_New ( ) ;
279295
280- IntPtr c = PyClass_New ( IntPtr . Zero , d , s ) ;
281- PyClassType = PyObject_Type ( c ) ;
296+ IntPtr c = PyClass_New ( IntPtr . Zero , d , s ) ;
297+ SetPyMember ( ref PyClassType , PyObject_Type ( c ) ,
298+ ( ) => PyClassType = IntPtr . Zero ) ;
282299
283- IntPtr i = PyInstance_New ( c , IntPtr . Zero , IntPtr . Zero ) ;
284- PyInstanceType = PyObject_Type ( i ) ;
300+ IntPtr i = PyInstance_New ( c , IntPtr . Zero , IntPtr . Zero ) ;
301+ SetPyMember ( ref PyInstanceType , PyObject_Type ( i ) ,
302+ ( ) => PyInstanceType = IntPtr . Zero ) ;
285303
286- XDecref ( s ) ;
287- XDecref ( i ) ;
288- XDecref ( c ) ;
289- XDecref ( d ) ;
304+ XDecref ( s ) ;
305+ XDecref ( i ) ;
306+ XDecref ( c ) ;
307+ XDecref ( d ) ;
308+ }
290309#endif
291310
292311 Error = new IntPtr ( - 1 ) ;
@@ -380,6 +399,9 @@ internal static void Shutdown()
380399 Exceptions . Shutdown ( ) ;
381400 ImportHook . Shutdown ( ) ;
382401 Finalizer . Shutdown ( ) ;
402+ // TOOD: PyCLRMetaType's release operation still in #958
403+ PyCLRMetaType = IntPtr . Zero ;
404+ ResetPyMembers ( ) ;
383405 Py_Finalize ( ) ;
384406 }
385407
@@ -393,6 +415,19 @@ internal static int AtExit()
393415 return 0 ;
394416 }
395417
418+ private static void SetPyMember ( ref IntPtr obj , IntPtr value , Action onRelease )
419+ {
420+ // XXX: For current usages, value should not be null.
421+ PythonException . ThrowIfIsNull ( value ) ;
422+ obj = value ;
423+ _pyRefs . Add ( value , onRelease ) ;
424+ }
425+
426+ private static void ResetPyMembers ( )
427+ {
428+ _pyRefs . Release ( ) ;
429+ }
430+
396431 internal static IntPtr Py_single_input = ( IntPtr ) 256 ;
397432 internal static IntPtr Py_file_input = ( IntPtr ) 257 ;
398433 internal static IntPtr Py_eval_input = ( IntPtr ) 258 ;
@@ -401,6 +436,7 @@ internal static int AtExit()
401436 internal static IntPtr PyModuleType ;
402437 internal static IntPtr PyClassType ;
403438 internal static IntPtr PyInstanceType ;
439+ internal static IntPtr PySuper_Type ;
404440 internal static IntPtr PyCLRMetaType ;
405441 internal static IntPtr PyMethodType ;
406442 internal static IntPtr PyWrapperDescriptorType ;
@@ -963,7 +999,7 @@ internal static int PyObject_Compare(IntPtr value1, IntPtr value2)
963999
9641000 internal static long PyObject_Size( IntPtr pointer)
9651001 {
966- return ( long ) _PyObject_Size( pointer) ;
1002+ return ( long ) _PyObject_Size( pointer) ;
9671003 }
9681004
9691005 [ DllImport( _PythonDll, CallingConvention = CallingConvention. Cdecl, EntryPoint = "PyObject_Size") ]
@@ -1079,7 +1115,7 @@ internal static bool PyLong_Check(IntPtr ob)
10791115
10801116 internal static IntPtr PyLong_FromUnsignedLong( object value)
10811117 {
1082- if ( Is32Bit || IsWindows)
1118+ if ( Is32Bit || IsWindows)
10831119 return PyLong_FromUnsignedLong32( Convert. ToUInt32( value) ) ;
10841120 else
10851121 return PyLong_FromUnsignedLong64( Convert. ToUInt64( value) ) ;
@@ -1269,7 +1305,7 @@ internal static int PySequence_DelSlice(IntPtr pointer, long i1, long i2)
12691305
12701306 internal static long PySequence_Size( IntPtr pointer)
12711307 {
1272- return ( long ) _PySequence_Size( pointer) ;
1308+ return ( long ) _PySequence_Size( pointer) ;
12731309 }
12741310
12751311 [ DllImport( _PythonDll, CallingConvention = CallingConvention. Cdecl, EntryPoint = "PySequence_Size") ]
@@ -1294,7 +1330,7 @@ internal static IntPtr PySequence_Repeat(IntPtr pointer, long count)
12941330
12951331 internal static long PySequence_Count( IntPtr pointer, IntPtr value)
12961332 {
1297- return ( long ) _PySequence_Count( pointer, value) ;
1333+ return ( long ) _PySequence_Count( pointer, value) ;
12981334 }
12991335
13001336 [ DllImport( _PythonDll, CallingConvention = CallingConvention. Cdecl, EntryPoint = "PySequence_Count") ]
@@ -1337,7 +1373,7 @@ internal static IntPtr PyString_FromString(string value)
13371373
13381374 internal static long PyBytes_Size( IntPtr op)
13391375 {
1340- return ( long ) _PyBytes_Size( op) ;
1376+ return ( long ) _PyBytes_Size( op) ;
13411377 }
13421378
13431379 [ DllImport( _PythonDll, CallingConvention = CallingConvention. Cdecl, EntryPoint = "PyBytes_Size") ]
@@ -1568,7 +1604,7 @@ internal static bool PyDict_Check(IntPtr ob)
15681604
15691605 internal static long PyDict_Size( IntPtr pointer)
15701606 {
1571- return ( long ) _PyDict_Size( pointer) ;
1607+ return ( long ) _PyDict_Size( pointer) ;
15721608 }
15731609
15741610 [ DllImport( _PythonDll, CallingConvention = CallingConvention. Cdecl, EntryPoint = "PyDict_Size") ]
@@ -1646,7 +1682,7 @@ internal static int PyList_SetSlice(IntPtr pointer, long start, long end, IntPtr
16461682
16471683 internal static long PyList_Size( IntPtr pointer)
16481684 {
1649- return ( long ) _PyList_Size( pointer) ;
1685+ return ( long ) _PyList_Size( pointer) ;
16501686 }
16511687
16521688 [ DllImport( _PythonDll, CallingConvention = CallingConvention. Cdecl, EntryPoint = "PyList_Size") ]
@@ -1695,7 +1731,7 @@ internal static IntPtr PyTuple_GetSlice(IntPtr pointer, long start, long end)
16951731
16961732 internal static long PyTuple_Size( IntPtr pointer)
16971733 {
1698- return ( long ) _PyTuple_Size( pointer) ;
1734+ return ( long ) _PyTuple_Size( pointer) ;
16991735 }
17001736
17011737 [ DllImport( _PythonDll, CallingConvention = CallingConvention. Cdecl, EntryPoint = "PyTuple_Size") ]
@@ -1746,6 +1782,9 @@ internal static bool PyIter_Check(IntPtr pointer)
17461782 [ DllImport( _PythonDll, CallingConvention = CallingConvention. Cdecl) ]
17471783 internal static extern IntPtr PyImport_Import( IntPtr name) ;
17481784
1785+ /// <summary>
1786+ /// Return value: New reference.
1787+ /// </summary>
17491788 [ DllImport( _PythonDll, CallingConvention = CallingConvention. Cdecl) ]
17501789 internal static extern IntPtr PyImport_ImportModule( string name) ;
17511790
@@ -1945,5 +1984,39 @@ internal static void SetNoSiteFlag()
19451984 }
19461985 }
19471986 }
1987+
1988+ /// <summary>
1989+ /// Return value: New reference.
1990+ /// </summary>
1991+ internal static IntPtr GetBuiltins( )
1992+ {
1993+ return IsPython3 ? PyImport_ImportModule( "builtins")
1994+ : PyImport_ImportModule( "__builtin__") ;
1995+ }
1996+ }
1997+
1998+
1999+ class PyReferenceCollection
2000+ {
2001+ private List< KeyValuePair< IntPtr, Action>> _actions = new List< KeyValuePair< IntPtr, Action>> ( ) ;
2002+
2003+ /// <summary>
2004+ /// Record obj's address to release the obj in the future,
2005+ /// obj must alive before calling Release.
2006+ /// </summary>
2007+ public void Add( IntPtr ob, Action onRelease)
2008+ {
2009+ _actions. Add( new KeyValuePair< IntPtr, Action> ( ob, onRelease) ) ;
2010+ }
2011+
2012+ public void Release( )
2013+ {
2014+ foreach ( var item in _actions)
2015+ {
2016+ Runtime. XDecref( item. Key) ;
2017+ item. Value? . Invoke( ) ;
2018+ }
2019+ _actions. Clear( ) ;
2020+ }
19482021 }
19492022}
0 commit comments