Skip to content

Commit e896aa6

Browse files
committed
* Decref the members of Runtime
* Unified GetBuiltins method
1 parent c1190f4 commit e896aa6

File tree

2 files changed

+120
-75
lines changed

2 files changed

+120
-75
lines changed

src/runtime/importhook.cs

Lines changed: 2 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -35,27 +35,6 @@ internal static void ReleaseModuleDef()
3535
}
3636
#endif
3737

38-
/// <summary>
39-
/// Get a <i>New reference</i> to the builtins module.
40-
/// </summary>
41-
static IntPtr GetNewRefToBuiltins()
42-
{
43-
if (Runtime.IsPython3)
44-
{
45-
return Runtime.PyImport_ImportModule("builtins");
46-
}
47-
else
48-
{
49-
// dict is a borrowed ref, no need to decref
50-
IntPtr dict = Runtime.PyImport_GetModuleDict();
51-
52-
// GetItemString is a borrowed ref; incref to get a new ref
53-
IntPtr builtins = Runtime.PyDict_GetItemString(dict, "__builtin__");
54-
Runtime.XIncref(builtins);
55-
return builtins;
56-
}
57-
}
58-
5938
/// <summary>
6039
/// Initialize just the __import__ hook itself.
6140
/// </summary>
@@ -64,7 +43,7 @@ static void InitImport()
6443
// We replace the built-in Python __import__ with our own: first
6544
// look in CLR modules, then if we don't find any call the default
6645
// Python __import__.
67-
IntPtr builtins = GetNewRefToBuiltins();
46+
IntPtr builtins = Runtime.GetBuiltins();
6847
py_import = Runtime.PyObject_GetAttrString(builtins, "__import__");
6948
PythonException.ThrowIfIsNull(py_import);
7049

@@ -80,7 +59,7 @@ static void InitImport()
8059
/// </summary>
8160
static void RestoreImport()
8261
{
83-
IntPtr builtins = GetNewRefToBuiltins();
62+
IntPtr builtins = Runtime.GetBuiltins();
8463

8564
int res = Runtime.PyObject_SetAttrString(builtins, "__import__", py_import);
8665
PythonException.ThrowIfIsNotZero(res);

src/runtime/runtime.cs

Lines changed: 118 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -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,94 @@ 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__");
207-
}
208-
PyNotImplemented = PyObject_GetAttrString(op, "NotImplemented");
209-
PyBaseObjectType = PyObject_GetAttrString(op, "object");
200+
var builtins = GetBuiltins();
201+
SetPyMember(ref PyNotImplemented, PyObject_GetAttrString(builtins, "NotImplemented"));
210202

211-
PyNone = PyObject_GetAttrString(op, "None");
212-
PyTrue = PyObject_GetAttrString(op, "True");
213-
PyFalse = PyObject_GetAttrString(op, "False");
203+
SetPyMember(ref PyBaseObjectType, PyObject_GetAttrString(builtins, "object"));
214204

215-
PyBoolType = PyObject_Type(PyTrue);
216-
PyNoneType = PyObject_Type(PyNone);
217-
PyTypeType = PyObject_Type(PyNoneType);
205+
SetPyMember(ref PyNone, PyObject_GetAttrString(builtins, "None"));
206+
SetPyMember(ref PyTrue, PyObject_GetAttrString(builtins, "True"));
207+
SetPyMember(ref PyFalse, PyObject_GetAttrString(builtins, "False"));
218208

219-
op = PyObject_GetAttrString(dict, "keys");
220-
PyMethodType = PyObject_Type(op);
221-
XDecref(op);
209+
SetPyMember(ref PyBoolType, PyObject_Type(PyTrue));
210+
SetPyMember(ref PyNoneType, PyObject_Type(PyNone));
211+
SetPyMember(ref PyTypeType, PyObject_Type(PyNoneType));
222212

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);
213+
op = PyObject_GetAttrString(builtins, "len");
214+
SetPyMember(ref PyMethodType, PyObject_Type(op));
215+
XDecref(op);
230216

231-
#if PYTHON3
232-
XDecref(dict);
233-
#endif
217+
// For some arcane reason, builtins.__dict__.__setitem__ is *not*
218+
// a wrapper_descriptor, even though dict.__setitem__ is.
219+
//
220+
// object.__init__ seems safe, though.
221+
op = PyObject_GetAttrString(PyBaseObjectType, "__init__");
222+
SetPyMember(ref PyWrapperDescriptorType, PyObject_Type(op));
223+
XDecref(op);
224+
225+
SetPyMember(ref PySuper_Type, PyObject_GetAttrString(builtins, "super"));
226+
227+
XDecref(builtins);
228+
}
234229

235230
op = PyString_FromString("string");
236-
PyStringType = PyObject_Type(op);
231+
SetPyMember(ref PyStringType, PyObject_Type(op));
237232
XDecref(op);
238233

239234
op = PyUnicode_FromString("unicode");
240-
PyUnicodeType = PyObject_Type(op);
235+
SetPyMember(ref PyUnicodeType, PyObject_Type(op));
241236
XDecref(op);
242237

243238
#if PYTHON3
244239
op = PyBytes_FromString("bytes");
245-
PyBytesType = PyObject_Type(op);
240+
SetPyMember(ref PyBytesType, PyObject_Type(op));
246241
XDecref(op);
247242
#endif
248243

249244
op = PyTuple_New(0);
250-
PyTupleType = PyObject_Type(op);
245+
SetPyMember(ref PyTupleType, PyObject_Type(op));
251246
XDecref(op);
252247

253248
op = PyList_New(0);
254-
PyListType = PyObject_Type(op);
249+
SetPyMember(ref PyListType, PyObject_Type(op));
255250
XDecref(op);
256251

257252
op = PyDict_New();
258-
PyDictType = PyObject_Type(op);
253+
SetPyMember(ref PyDictType, PyObject_Type(op));
259254
XDecref(op);
260255

261256
op = PyInt_FromInt32(0);
262-
PyIntType = PyObject_Type(op);
257+
SetPyMember(ref PyIntType, PyObject_Type(op));
263258
XDecref(op);
264259

265260
op = PyLong_FromLong(0);
266-
PyLongType = PyObject_Type(op);
261+
SetPyMember(ref PyLongType, PyObject_Type(op));
267262
XDecref(op);
268263

269264
op = PyFloat_FromDouble(0);
270-
PyFloatType = PyObject_Type(op);
265+
SetPyMember(ref PyFloatType, PyObject_Type(op));
271266
XDecref(op);
272267

273-
#if PYTHON3
268+
#if !PYTHON2
274269
PyClassType = IntPtr.Zero;
275270
PyInstanceType = IntPtr.Zero;
276-
#elif PYTHON2
277-
IntPtr s = PyString_FromString("_temp");
278-
IntPtr d = PyDict_New();
271+
#else
272+
{
273+
IntPtr s = PyString_FromString("_temp");
274+
IntPtr d = PyDict_New();
279275

280-
IntPtr c = PyClass_New(IntPtr.Zero, d, s);
281-
PyClassType = PyObject_Type(c);
276+
IntPtr c = PyClass_New(IntPtr.Zero, d, s);
277+
SetPyMember(ref PyClassType, PyObject_Type(c));
282278

283-
IntPtr i = PyInstance_New(c, IntPtr.Zero, IntPtr.Zero);
284-
PyInstanceType = PyObject_Type(i);
279+
IntPtr i = PyInstance_New(c, IntPtr.Zero, IntPtr.Zero);
280+
SetPyMember(ref PyInstanceType, PyObject_Type(i));
285281

286-
XDecref(s);
287-
XDecref(i);
288-
XDecref(c);
289-
XDecref(d);
282+
XDecref(s);
283+
XDecref(i);
284+
XDecref(c);
285+
XDecref(d);
286+
}
290287
#endif
291288

292289
Error = new IntPtr(-1);
@@ -380,6 +377,9 @@ internal static void Shutdown()
380377
Exceptions.Shutdown();
381378
ImportHook.Shutdown();
382379
Finalizer.Shutdown();
380+
// TOOD: PyCLRMetaType's release operation still in #958
381+
PyCLRMetaType = IntPtr.Zero;
382+
ResetPyMembers();
383383
Py_Finalize();
384384
}
385385

@@ -393,6 +393,19 @@ internal static int AtExit()
393393
return 0;
394394
}
395395

396+
private static void SetPyMember(ref IntPtr obj, IntPtr value)
397+
{
398+
// XXX: For current usages, value should not be null.
399+
PythonException.ThrowIfIsNull(value);
400+
obj = value;
401+
_pyRefs.Add(ref obj);
402+
}
403+
404+
private static void ResetPyMembers()
405+
{
406+
_pyRefs.Release();
407+
}
408+
396409
internal static IntPtr Py_single_input = (IntPtr)256;
397410
internal static IntPtr Py_file_input = (IntPtr)257;
398411
internal static IntPtr Py_eval_input = (IntPtr)258;
@@ -401,6 +414,7 @@ internal static int AtExit()
401414
internal static IntPtr PyModuleType;
402415
internal static IntPtr PyClassType;
403416
internal static IntPtr PyInstanceType;
417+
internal static IntPtr PySuper_Type;
404418
internal static IntPtr PyCLRMetaType;
405419
internal static IntPtr PyMethodType;
406420
internal static IntPtr PyWrapperDescriptorType;
@@ -1746,6 +1760,9 @@ internal static bool PyIter_Check(IntPtr pointer)
17461760
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
17471761
internal static extern IntPtr PyImport_Import(IntPtr name);
17481762

1763+
/// <summary>
1764+
/// Return value: New reference.
1765+
/// </summary>
17491766
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
17501767
internal static extern IntPtr PyImport_ImportModule(string name);
17511768

@@ -1945,5 +1962,54 @@ internal static void SetNoSiteFlag()
19451962
}
19461963
}
19471964
}
1965+
1966+
/// <summary>
1967+
/// Return value: New reference.
1968+
/// </summary>
1969+
internal static IntPtr GetBuiltins()
1970+
{
1971+
return IsPython3 ? PyImport_ImportModule("builtins")
1972+
: PyImport_ImportModule("__builtin__");
1973+
}
1974+
}
1975+
1976+
1977+
class PyReferenceCollection
1978+
{
1979+
public List<IntPtr> _objects { get; private set; }
1980+
1981+
public PyReferenceCollection()
1982+
{
1983+
_objects = new List<IntPtr>();
1984+
}
1985+
1986+
/// <summary>
1987+
/// Record obj's address to release the obj in the future,
1988+
/// obj must alive before calling Release.
1989+
/// </summary>
1990+
public void Add(ref IntPtr obj)
1991+
{
1992+
unsafe
1993+
{
1994+
fixed (void* p = &obj)
1995+
{
1996+
_objects.Add((IntPtr)p);
1997+
}
1998+
}
1999+
}
2000+
2001+
public void Release()
2002+
{
2003+
foreach (var objRef in _objects)
2004+
{
2005+
unsafe
2006+
{
2007+
var p = (void**)objRef;
2008+
Runtime.XDecref((IntPtr)(*p));
2009+
*p = null;
2010+
}
2011+
}
2012+
_objects.Clear();
2013+
}
19482014
}
19492015
}

0 commit comments

Comments
 (0)