-
Notifications
You must be signed in to change notification settings - Fork 752
Decref the members of Runtime(split from #958) #1019
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -169,6 +169,8 @@ public class Runtime | |
/// </summary> | ||
internal static readonly Encoding PyEncoding = _UCS == 2 ? Encoding.Unicode : Encoding.UTF32; | ||
|
||
private static PyReferenceCollection _pyRefs = new PyReferenceCollection(); | ||
|
||
/// <summary> | ||
/// Initialize the runtime... | ||
/// </summary> | ||
|
@@ -194,99 +196,116 @@ internal static void Initialize(bool initSigs = false) | |
TypeManager.Reset(); | ||
|
||
IntPtr op; | ||
IntPtr dict; | ||
if (IsPython3) | ||
{ | ||
op = PyImport_ImportModule("builtins"); | ||
dict = PyObject_GetAttrString(op, "__dict__"); | ||
} | ||
else // Python2 | ||
{ | ||
dict = PyImport_GetModuleDict(); | ||
op = PyDict_GetItemString(dict, "__builtin__"); | ||
var builtins = GetBuiltins(); | ||
SetPyMember(ref PyNotImplemented, PyObject_GetAttrString(builtins, "NotImplemented"), | ||
() => PyNotImplemented = IntPtr.Zero); | ||
|
||
SetPyMember(ref PyBaseObjectType, PyObject_GetAttrString(builtins, "object"), | ||
() => PyBaseObjectType = IntPtr.Zero); | ||
|
||
SetPyMember(ref PyNone, PyObject_GetAttrString(builtins, "None"), | ||
() => PyNone = IntPtr.Zero); | ||
SetPyMember(ref PyTrue, PyObject_GetAttrString(builtins, "True"), | ||
() => PyTrue = IntPtr.Zero); | ||
SetPyMember(ref PyFalse, PyObject_GetAttrString(builtins, "False"), | ||
() => PyFalse = IntPtr.Zero); | ||
|
||
SetPyMember(ref PyBoolType, PyObject_Type(PyTrue), | ||
() => PyBoolType = IntPtr.Zero); | ||
SetPyMember(ref PyNoneType, PyObject_Type(PyNone), | ||
() => PyNoneType = IntPtr.Zero); | ||
SetPyMember(ref PyTypeType, PyObject_Type(PyNoneType), | ||
() => PyTypeType = IntPtr.Zero); | ||
|
||
op = PyObject_GetAttrString(builtins, "len"); | ||
SetPyMember(ref PyMethodType, PyObject_Type(op), | ||
() => PyMethodType = IntPtr.Zero); | ||
XDecref(op); | ||
|
||
// For some arcane reason, builtins.__dict__.__setitem__ is *not* | ||
// a wrapper_descriptor, even though dict.__setitem__ is. | ||
// | ||
// object.__init__ seems safe, though. | ||
op = PyObject_GetAttrString(PyBaseObjectType, "__init__"); | ||
SetPyMember(ref PyWrapperDescriptorType, PyObject_Type(op), | ||
() => PyWrapperDescriptorType = IntPtr.Zero); | ||
XDecref(op); | ||
|
||
SetPyMember(ref PySuper_Type, PyObject_GetAttrString(builtins, "super"), | ||
() => PySuper_Type = IntPtr.Zero); | ||
|
||
XDecref(builtins); | ||
} | ||
PyNotImplemented = PyObject_GetAttrString(op, "NotImplemented"); | ||
PyBaseObjectType = PyObject_GetAttrString(op, "object"); | ||
|
||
PyNone = PyObject_GetAttrString(op, "None"); | ||
PyTrue = PyObject_GetAttrString(op, "True"); | ||
PyFalse = PyObject_GetAttrString(op, "False"); | ||
|
||
PyBoolType = PyObject_Type(PyTrue); | ||
PyNoneType = PyObject_Type(PyNone); | ||
PyTypeType = PyObject_Type(PyNoneType); | ||
|
||
op = PyObject_GetAttrString(dict, "keys"); | ||
PyMethodType = PyObject_Type(op); | ||
XDecref(op); | ||
|
||
// For some arcane reason, builtins.__dict__.__setitem__ is *not* | ||
// a wrapper_descriptor, even though dict.__setitem__ is. | ||
// | ||
// object.__init__ seems safe, though. | ||
op = PyObject_GetAttrString(PyBaseObjectType, "__init__"); | ||
PyWrapperDescriptorType = PyObject_Type(op); | ||
XDecref(op); | ||
|
||
#if PYTHON3 | ||
XDecref(dict); | ||
#endif | ||
|
||
op = PyString_FromString("string"); | ||
PyStringType = PyObject_Type(op); | ||
SetPyMember(ref PyStringType, PyObject_Type(op), | ||
() => PyStringType = IntPtr.Zero); | ||
XDecref(op); | ||
|
||
op = PyUnicode_FromString("unicode"); | ||
PyUnicodeType = PyObject_Type(op); | ||
SetPyMember(ref PyUnicodeType, PyObject_Type(op), | ||
() => PyUnicodeType = IntPtr.Zero); | ||
XDecref(op); | ||
|
||
#if PYTHON3 | ||
op = PyBytes_FromString("bytes"); | ||
PyBytesType = PyObject_Type(op); | ||
SetPyMember(ref PyBytesType, PyObject_Type(op), | ||
() => PyBytesType = IntPtr.Zero); | ||
XDecref(op); | ||
#endif | ||
|
||
op = PyTuple_New(0); | ||
PyTupleType = PyObject_Type(op); | ||
SetPyMember(ref PyTupleType, PyObject_Type(op), | ||
() => PyTupleType = IntPtr.Zero); | ||
XDecref(op); | ||
|
||
op = PyList_New(0); | ||
PyListType = PyObject_Type(op); | ||
SetPyMember(ref PyListType, PyObject_Type(op), | ||
() => PyListType = IntPtr.Zero); | ||
XDecref(op); | ||
|
||
op = PyDict_New(); | ||
PyDictType = PyObject_Type(op); | ||
SetPyMember(ref PyDictType, PyObject_Type(op), | ||
() => PyDictType = IntPtr.Zero); | ||
XDecref(op); | ||
|
||
op = PyInt_FromInt32(0); | ||
PyIntType = PyObject_Type(op); | ||
SetPyMember(ref PyIntType, PyObject_Type(op), | ||
() => PyIntType = IntPtr.Zero); | ||
XDecref(op); | ||
|
||
op = PyLong_FromLong(0); | ||
PyLongType = PyObject_Type(op); | ||
SetPyMember(ref PyLongType, PyObject_Type(op), | ||
() => PyLongType = IntPtr.Zero); | ||
XDecref(op); | ||
|
||
op = PyFloat_FromDouble(0); | ||
PyFloatType = PyObject_Type(op); | ||
SetPyMember(ref PyFloatType, PyObject_Type(op), | ||
() => PyFloatType = IntPtr.Zero); | ||
XDecref(op); | ||
|
||
#if PYTHON3 | ||
#if !PYTHON2 | ||
PyClassType = IntPtr.Zero; | ||
PyInstanceType = IntPtr.Zero; | ||
#elif PYTHON2 | ||
IntPtr s = PyString_FromString("_temp"); | ||
IntPtr d = PyDict_New(); | ||
#else | ||
{ | ||
IntPtr s = PyString_FromString("_temp"); | ||
IntPtr d = PyDict_New(); | ||
|
||
IntPtr c = PyClass_New(IntPtr.Zero, d, s); | ||
PyClassType = PyObject_Type(c); | ||
IntPtr c = PyClass_New(IntPtr.Zero, d, s); | ||
SetPyMember(ref PyClassType, PyObject_Type(c), | ||
() => PyClassType = IntPtr.Zero); | ||
|
||
IntPtr i = PyInstance_New(c, IntPtr.Zero, IntPtr.Zero); | ||
PyInstanceType = PyObject_Type(i); | ||
IntPtr i = PyInstance_New(c, IntPtr.Zero, IntPtr.Zero); | ||
SetPyMember(ref PyInstanceType, PyObject_Type(i), | ||
() => PyInstanceType = IntPtr.Zero); | ||
|
||
XDecref(s); | ||
XDecref(i); | ||
XDecref(c); | ||
XDecref(d); | ||
XDecref(s); | ||
XDecref(i); | ||
XDecref(c); | ||
XDecref(d); | ||
} | ||
#endif | ||
|
||
Error = new IntPtr(-1); | ||
|
@@ -380,6 +399,9 @@ internal static void Shutdown() | |
Exceptions.Shutdown(); | ||
ImportHook.Shutdown(); | ||
Finalizer.Shutdown(); | ||
// TOOD: PyCLRMetaType's release operation still in #958 | ||
PyCLRMetaType = IntPtr.Zero; | ||
ResetPyMembers(); | ||
Py_Finalize(); | ||
} | ||
|
||
|
@@ -393,6 +415,19 @@ internal static int AtExit() | |
return 0; | ||
} | ||
|
||
private static void SetPyMember(ref IntPtr obj, IntPtr value, Action onRelease) | ||
{ | ||
// XXX: For current usages, value should not be null. | ||
PythonException.ThrowIfIsNull(value); | ||
obj = value; | ||
_pyRefs.Add(value, onRelease); | ||
} | ||
|
||
private static void ResetPyMembers() | ||
{ | ||
_pyRefs.Release(); | ||
} | ||
|
||
internal static IntPtr Py_single_input = (IntPtr)256; | ||
internal static IntPtr Py_file_input = (IntPtr)257; | ||
internal static IntPtr Py_eval_input = (IntPtr)258; | ||
|
@@ -401,6 +436,7 @@ internal static int AtExit() | |
internal static IntPtr PyModuleType; | ||
internal static IntPtr PyClassType; | ||
internal static IntPtr PyInstanceType; | ||
internal static IntPtr PySuper_Type; | ||
internal static IntPtr PyCLRMetaType; | ||
internal static IntPtr PyMethodType; | ||
internal static IntPtr PyWrapperDescriptorType; | ||
|
@@ -963,7 +999,7 @@ internal static int PyObject_Compare(IntPtr value1, IntPtr value2) | |
|
||
internal static long PyObject_Size(IntPtr pointer) | ||
{ | ||
return (long) _PyObject_Size(pointer); | ||
return (long)_PyObject_Size(pointer); | ||
} | ||
|
||
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "PyObject_Size")] | ||
|
@@ -1079,7 +1115,7 @@ internal static bool PyLong_Check(IntPtr ob) | |
|
||
internal static IntPtr PyLong_FromUnsignedLong(object value) | ||
{ | ||
if(Is32Bit || IsWindows) | ||
if (Is32Bit || IsWindows) | ||
return PyLong_FromUnsignedLong32(Convert.ToUInt32(value)); | ||
else | ||
return PyLong_FromUnsignedLong64(Convert.ToUInt64(value)); | ||
|
@@ -1269,7 +1305,7 @@ internal static int PySequence_DelSlice(IntPtr pointer, long i1, long i2) | |
|
||
internal static long PySequence_Size(IntPtr pointer) | ||
{ | ||
return (long) _PySequence_Size(pointer); | ||
return (long)_PySequence_Size(pointer); | ||
} | ||
|
||
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "PySequence_Size")] | ||
|
@@ -1294,7 +1330,7 @@ internal static IntPtr PySequence_Repeat(IntPtr pointer, long count) | |
|
||
internal static long PySequence_Count(IntPtr pointer, IntPtr value) | ||
{ | ||
return (long) _PySequence_Count(pointer, value); | ||
return (long)_PySequence_Count(pointer, value); | ||
} | ||
|
||
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "PySequence_Count")] | ||
|
@@ -1337,7 +1373,7 @@ internal static IntPtr PyString_FromString(string value) | |
|
||
internal static long PyBytes_Size(IntPtr op) | ||
{ | ||
return (long) _PyBytes_Size(op); | ||
return (long)_PyBytes_Size(op); | ||
} | ||
|
||
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "PyBytes_Size")] | ||
|
@@ -1568,7 +1604,7 @@ internal static bool PyDict_Check(IntPtr ob) | |
|
||
internal static long PyDict_Size(IntPtr pointer) | ||
{ | ||
return (long) _PyDict_Size(pointer); | ||
return (long)_PyDict_Size(pointer); | ||
} | ||
|
||
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "PyDict_Size")] | ||
|
@@ -1646,7 +1682,7 @@ internal static int PyList_SetSlice(IntPtr pointer, long start, long end, IntPtr | |
|
||
internal static long PyList_Size(IntPtr pointer) | ||
{ | ||
return (long) _PyList_Size(pointer); | ||
return (long)_PyList_Size(pointer); | ||
} | ||
|
||
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "PyList_Size")] | ||
|
@@ -1695,7 +1731,7 @@ internal static IntPtr PyTuple_GetSlice(IntPtr pointer, long start, long end) | |
|
||
internal static long PyTuple_Size(IntPtr pointer) | ||
{ | ||
return (long) _PyTuple_Size(pointer); | ||
return (long)_PyTuple_Size(pointer); | ||
} | ||
|
||
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "PyTuple_Size")] | ||
|
@@ -1746,6 +1782,9 @@ internal static bool PyIter_Check(IntPtr pointer) | |
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] | ||
internal static extern IntPtr PyImport_Import(IntPtr name); | ||
|
||
/// <summary> | ||
/// Return value: New reference. | ||
/// </summary> | ||
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] | ||
internal static extern IntPtr PyImport_ImportModule(string name); | ||
|
||
|
@@ -1945,5 +1984,39 @@ internal static void SetNoSiteFlag() | |
} | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Return value: New reference. | ||
/// </summary> | ||
internal static IntPtr GetBuiltins() | ||
{ | ||
return IsPython3 ? PyImport_ImportModule("builtins") | ||
: PyImport_ImportModule("__builtin__"); | ||
} | ||
} | ||
|
||
|
||
class PyReferenceCollection | ||
{ | ||
private List<KeyValuePair<IntPtr, Action>> _actions = new List<KeyValuePair<IntPtr, Action>>(); | ||
|
||
/// <summary> | ||
/// Record obj's address to release the obj in the future, | ||
/// obj must alive before calling Release. | ||
/// </summary> | ||
public void Add(IntPtr ob, Action onRelease) | ||
{ | ||
_actions.Add(new KeyValuePair<IntPtr, Action>(ob, onRelease)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. NIT: use
Sorry, something went wrong. All reactionsThere was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why using Tuple? As my experience, with two elements cases, KeyValue would always faster than tuple(unless the struct is too big).
Sorry, something went wrong. All reactionsThere was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Simply for readability. This code is not a hot path, so a little performance difference hardly matters.
Sorry, something went wrong. All reactions |
||
} | ||
|
||
public void Release() | ||
{ | ||
foreach (var item in _actions) | ||
{ | ||
Runtime.XDecref(item.Key); | ||
item.Value?.Invoke(); | ||
} | ||
Comment on lines
+2014
to
+2018
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. NIT: use
Sorry, something went wrong. All reactions |
||
_actions.Clear(); | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NIT:
obj
can beout IntPtr