@@ -169,6 +169,8 @@ public class Runtime
169
169
/// </summary>
170
170
internal static readonly Encoding PyEncoding = _UCS == 2 ? Encoding . Unicode : Encoding . UTF32 ;
171
171
172
+ private static PyReferenceCollection _pyRefs = new PyReferenceCollection ( ) ;
173
+
172
174
/// <summary>
173
175
/// Initialize the runtime...
174
176
/// </summary>
@@ -194,99 +196,116 @@ internal static void Initialize(bool initSigs = false)
194
196
TypeManager . Reset ( ) ;
195
197
196
198
IntPtr op ;
197
- IntPtr dict ;
198
- if ( IsPython3 )
199
- {
200
- op = PyImport_ImportModule ( "builtins" ) ;
201
- dict = PyObject_GetAttrString ( op , "__dict__" ) ;
202
- }
203
- else // Python2
204
199
{
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 ) ;
207
239
}
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
234
240
235
241
op = PyString_FromString ( "string" ) ;
236
- PyStringType = PyObject_Type ( op ) ;
242
+ SetPyMember ( ref PyStringType , PyObject_Type ( op ) ,
243
+ ( ) => PyStringType = IntPtr . Zero ) ;
237
244
XDecref ( op ) ;
238
245
239
246
op = PyUnicode_FromString ( "unicode" ) ;
240
- PyUnicodeType = PyObject_Type ( op ) ;
247
+ SetPyMember ( ref PyUnicodeType , PyObject_Type ( op ) ,
248
+ ( ) => PyUnicodeType = IntPtr . Zero ) ;
241
249
XDecref ( op ) ;
242
250
243
251
#if PYTHON3
244
252
op = PyBytes_FromString ( "bytes" ) ;
245
- PyBytesType = PyObject_Type ( op ) ;
253
+ SetPyMember ( ref PyBytesType , PyObject_Type ( op ) ,
254
+ ( ) => PyBytesType = IntPtr . Zero ) ;
246
255
XDecref ( op ) ;
247
256
#endif
248
257
249
258
op = PyTuple_New ( 0 ) ;
250
- PyTupleType = PyObject_Type ( op ) ;
259
+ SetPyMember ( ref PyTupleType , PyObject_Type ( op ) ,
260
+ ( ) => PyTupleType = IntPtr . Zero ) ;
251
261
XDecref ( op ) ;
252
262
253
263
op = PyList_New ( 0 ) ;
254
- PyListType = PyObject_Type ( op ) ;
264
+ SetPyMember ( ref PyListType , PyObject_Type ( op ) ,
265
+ ( ) => PyListType = IntPtr . Zero ) ;
255
266
XDecref ( op ) ;
256
267
257
268
op = PyDict_New ( ) ;
258
- PyDictType = PyObject_Type ( op ) ;
269
+ SetPyMember ( ref PyDictType , PyObject_Type ( op ) ,
270
+ ( ) => PyDictType = IntPtr . Zero ) ;
259
271
XDecref ( op ) ;
260
272
261
273
op = PyInt_FromInt32 ( 0 ) ;
262
- PyIntType = PyObject_Type ( op ) ;
274
+ SetPyMember ( ref PyIntType , PyObject_Type ( op ) ,
275
+ ( ) => PyIntType = IntPtr . Zero ) ;
263
276
XDecref ( op ) ;
264
277
265
278
op = PyLong_FromLong ( 0 ) ;
266
- PyLongType = PyObject_Type ( op ) ;
279
+ SetPyMember ( ref PyLongType , PyObject_Type ( op ) ,
280
+ ( ) => PyLongType = IntPtr . Zero ) ;
267
281
XDecref ( op ) ;
268
282
269
283
op = PyFloat_FromDouble ( 0 ) ;
270
- PyFloatType = PyObject_Type ( op ) ;
284
+ SetPyMember ( ref PyFloatType , PyObject_Type ( op ) ,
285
+ ( ) => PyFloatType = IntPtr . Zero ) ;
271
286
XDecref ( op ) ;
272
287
273
- #if PYTHON3
288
+ #if ! PYTHON2
274
289
PyClassType = IntPtr . Zero ;
275
290
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 ( ) ;
279
295
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 ) ;
282
299
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 ) ;
285
303
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
+ }
290
309
#endif
291
310
292
311
Error = new IntPtr ( - 1 ) ;
@@ -380,6 +399,9 @@ internal static void Shutdown()
380
399
Exceptions . Shutdown ( ) ;
381
400
ImportHook . Shutdown ( ) ;
382
401
Finalizer . Shutdown ( ) ;
402
+ // TOOD: PyCLRMetaType's release operation still in #958
403
+ PyCLRMetaType = IntPtr . Zero ;
404
+ ResetPyMembers ( ) ;
383
405
Py_Finalize ( ) ;
384
406
}
385
407
@@ -393,6 +415,19 @@ internal static int AtExit()
393
415
return 0 ;
394
416
}
395
417
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
+
396
431
internal static IntPtr Py_single_input = ( IntPtr ) 256 ;
397
432
internal static IntPtr Py_file_input = ( IntPtr ) 257 ;
398
433
internal static IntPtr Py_eval_input = ( IntPtr ) 258 ;
@@ -401,6 +436,7 @@ internal static int AtExit()
401
436
internal static IntPtr PyModuleType ;
402
437
internal static IntPtr PyClassType ;
403
438
internal static IntPtr PyInstanceType ;
439
+ internal static IntPtr PySuper_Type ;
404
440
internal static IntPtr PyCLRMetaType ;
405
441
internal static IntPtr PyMethodType ;
406
442
internal static IntPtr PyWrapperDescriptorType ;
@@ -963,7 +999,7 @@ internal static int PyObject_Compare(IntPtr value1, IntPtr value2)
963
999
964
1000
internal static long PyObject_Size( IntPtr pointer)
965
1001
{
966
- return ( long ) _PyObject_Size( pointer) ;
1002
+ return ( long ) _PyObject_Size( pointer) ;
967
1003
}
968
1004
969
1005
[ DllImport( _PythonDll, CallingConvention = CallingConvention. Cdecl, EntryPoint = "PyObject_Size") ]
@@ -1079,7 +1115,7 @@ internal static bool PyLong_Check(IntPtr ob)
1079
1115
1080
1116
internal static IntPtr PyLong_FromUnsignedLong( object value)
1081
1117
{
1082
- if ( Is32Bit || IsWindows)
1118
+ if ( Is32Bit || IsWindows)
1083
1119
return PyLong_FromUnsignedLong32( Convert. ToUInt32( value) ) ;
1084
1120
else
1085
1121
return PyLong_FromUnsignedLong64( Convert. ToUInt64( value) ) ;
@@ -1269,7 +1305,7 @@ internal static int PySequence_DelSlice(IntPtr pointer, long i1, long i2)
1269
1305
1270
1306
internal static long PySequence_Size( IntPtr pointer)
1271
1307
{
1272
- return ( long ) _PySequence_Size( pointer) ;
1308
+ return ( long ) _PySequence_Size( pointer) ;
1273
1309
}
1274
1310
1275
1311
[ DllImport( _PythonDll, CallingConvention = CallingConvention. Cdecl, EntryPoint = "PySequence_Size") ]
@@ -1294,7 +1330,7 @@ internal static IntPtr PySequence_Repeat(IntPtr pointer, long count)
1294
1330
1295
1331
internal static long PySequence_Count( IntPtr pointer, IntPtr value)
1296
1332
{
1297
- return ( long ) _PySequence_Count( pointer, value) ;
1333
+ return ( long ) _PySequence_Count( pointer, value) ;
1298
1334
}
1299
1335
1300
1336
[ DllImport( _PythonDll, CallingConvention = CallingConvention. Cdecl, EntryPoint = "PySequence_Count") ]
@@ -1337,7 +1373,7 @@ internal static IntPtr PyString_FromString(string value)
1337
1373
1338
1374
internal static long PyBytes_Size( IntPtr op)
1339
1375
{
1340
- return ( long ) _PyBytes_Size( op) ;
1376
+ return ( long ) _PyBytes_Size( op) ;
1341
1377
}
1342
1378
1343
1379
[ DllImport( _PythonDll, CallingConvention = CallingConvention. Cdecl, EntryPoint = "PyBytes_Size") ]
@@ -1568,7 +1604,7 @@ internal static bool PyDict_Check(IntPtr ob)
1568
1604
1569
1605
internal static long PyDict_Size( IntPtr pointer)
1570
1606
{
1571
- return ( long ) _PyDict_Size( pointer) ;
1607
+ return ( long ) _PyDict_Size( pointer) ;
1572
1608
}
1573
1609
1574
1610
[ DllImport( _PythonDll, CallingConvention = CallingConvention. Cdecl, EntryPoint = "PyDict_Size") ]
@@ -1646,7 +1682,7 @@ internal static int PyList_SetSlice(IntPtr pointer, long start, long end, IntPtr
1646
1682
1647
1683
internal static long PyList_Size( IntPtr pointer)
1648
1684
{
1649
- return ( long ) _PyList_Size( pointer) ;
1685
+ return ( long ) _PyList_Size( pointer) ;
1650
1686
}
1651
1687
1652
1688
[ DllImport( _PythonDll, CallingConvention = CallingConvention. Cdecl, EntryPoint = "PyList_Size") ]
@@ -1695,7 +1731,7 @@ internal static IntPtr PyTuple_GetSlice(IntPtr pointer, long start, long end)
1695
1731
1696
1732
internal static long PyTuple_Size( IntPtr pointer)
1697
1733
{
1698
- return ( long ) _PyTuple_Size( pointer) ;
1734
+ return ( long ) _PyTuple_Size( pointer) ;
1699
1735
}
1700
1736
1701
1737
[ DllImport( _PythonDll, CallingConvention = CallingConvention. Cdecl, EntryPoint = "PyTuple_Size") ]
@@ -1746,6 +1782,9 @@ internal static bool PyIter_Check(IntPtr pointer)
1746
1782
[ DllImport( _PythonDll, CallingConvention = CallingConvention. Cdecl) ]
1747
1783
internal static extern IntPtr PyImport_Import( IntPtr name) ;
1748
1784
1785
+ /// <summary>
1786
+ /// Return value: New reference.
1787
+ /// </summary>
1749
1788
[ DllImport( _PythonDll, CallingConvention = CallingConvention. Cdecl) ]
1750
1789
internal static extern IntPtr PyImport_ImportModule( string name) ;
1751
1790
@@ -1945,5 +1984,39 @@ internal static void SetNoSiteFlag()
1945
1984
}
1946
1985
}
1947
1986
}
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
+ }
1948
2021
}
1949
2022
}
0 commit comments