From 6402780f0b631c188ed3395986075dd727128bb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Sun, 1 Dec 2024 09:04:25 +0100 Subject: [PATCH 1/6] Add semantics for stolen references in `Doc/data/refcounts.dat` --- Doc/data/refcounts.dat | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/Doc/data/refcounts.dat b/Doc/data/refcounts.dat index 6bfcc191b2270b..2a8705b2d37071 100644 --- a/Doc/data/refcounts.dat +++ b/Doc/data/refcounts.dat @@ -9,27 +9,26 @@ # function's return value. Successive lines with the same function name # correspond to the function's parameter list and appear in the order the # parameters appear in the function's prototype. +# +# Whenever possible, the parameter names are as they appear in the API manual, +# not the source code. # For readability, each function's lines are surrounded by a blank line. -# The blocks are sorted alphabetically by function name. - -# Refcount behavior is given for all PyObject* types: 0 (no change), +1 -# (increment) and -1 (decrement). A blank refcount field indicates the -# parameter or function value is not a PyObject* and is therefore not -# subject to reference counting. A special case for the value "null" -# (without quotes) is used for functions which return a PyObject* type but -# always return NULL. This is used by some of the PyErr_*() functions, in -# particular. - -# XXX NOTE: the 0/+1/-1 refcount information for arguments is -# confusing! Much more useful would be to indicate whether the -# function "steals" a reference to the argument or not. Take for -# example PyList_SetItem(list, i, item). This lists as a 0 change for -# both the list and the item arguments. However, in fact it steals a -# reference to the item argument! - -# The parameter names are as they appear in the API manual, not the source -# code. +# The blocks should be sorted alphabetically by function name. + +# Refcount behavior is given for all PyObject* types: +# +# 0 (no change) +# +1 (increment) +# -1 (decrement) +# $ (stolen reference) +# +# A blank refcount field indicates the parameter or function value is not +# a PyObject* object and is therefore not subject to reference counting. +# +# A special case for the value "null" (without quotes) is used for functions +# which return a PyObject* type but always return NULL. For instance, this is +# used by the PyErr_*() functions. PyAnySet_Check:int::: PyAnySet_Check:PyObject*:p:0: @@ -1193,7 +1192,7 @@ PyList_SET_ITEM:PyObject*:o:0: PyList_SetItem:int::: PyList_SetItem:PyObject*:list:0: PyList_SetItem:Py_ssize_t:index:: -PyList_SetItem:PyObject*:item:0: +PyList_SetItem:PyObject*:item:$: PyList_SetSlice:int::: PyList_SetSlice:PyObject*:list:0: From e23a6add9aaf8f57340d0d897fb442d3075e1082 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Sun, 1 Dec 2024 09:23:12 +0100 Subject: [PATCH 2/6] Support '$' token --- Doc/tools/extensions/c_annotations.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Doc/tools/extensions/c_annotations.py b/Doc/tools/extensions/c_annotations.py index 50065d34a2c27a..fee0f5c315de81 100644 --- a/Doc/tools/extensions/c_annotations.py +++ b/Doc/tools/extensions/c_annotations.py @@ -91,6 +91,9 @@ def read_refcount_data(refcount_filename: Path) -> dict[str, RefCountEntry]: entry = refcount_data[function] = RefCountEntry(function) if not refcount or refcount == "null": refcount = None + elif recount == '$': + # steals a reference (hence, the reference count does not change) + refcount = 0 else: refcount = int(refcount) # Update the entry with the new parameter From bf08fe06adad6279fd4727eeb67d23e9fe086e81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Sun, 1 Dec 2024 09:24:56 +0100 Subject: [PATCH 3/6] fix lint --- Doc/tools/extensions/c_annotations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/tools/extensions/c_annotations.py b/Doc/tools/extensions/c_annotations.py index fee0f5c315de81..752eb6bb11f0f3 100644 --- a/Doc/tools/extensions/c_annotations.py +++ b/Doc/tools/extensions/c_annotations.py @@ -91,7 +91,7 @@ def read_refcount_data(refcount_filename: Path) -> dict[str, RefCountEntry]: entry = refcount_data[function] = RefCountEntry(function) if not refcount or refcount == "null": refcount = None - elif recount == '$': + elif refcount == '$': # steals a reference (hence, the reference count does not change) refcount = 0 else: From 83f5a95ec4ccd27b2e7776c0707b9b222905925c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Sun, 1 Dec 2024 15:24:32 +0100 Subject: [PATCH 4/6] update entries that steal references --- Doc/data/refcounts.dat | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Doc/data/refcounts.dat b/Doc/data/refcounts.dat index 2a8705b2d37071..38fa6a717ab6c0 100644 --- a/Doc/data/refcounts.dat +++ b/Doc/data/refcounts.dat @@ -1187,7 +1187,7 @@ PyList_Reverse:PyObject*:list:0: PyList_SET_ITEM:void::: PyList_SET_ITEM:PyObject*:list:0: PyList_SET_ITEM:Py_ssize_t:i:: -PyList_SET_ITEM:PyObject*:o:0: +PyList_SET_ITEM:PyObject*:o:$: PyList_SetItem:int::: PyList_SetItem:PyObject*:list:0: @@ -1414,7 +1414,7 @@ PyModule_AddIntMacro::macro:: PyModule_AddObject:int::: PyModule_AddObject:PyObject*:module:0: PyModule_AddObject:const char*:name:: -PyModule_AddObject:PyObject*:value:+1: +PyModule_AddObject:PyObject*:value:$:steals on success, +1 on failure PyModule_AddStringConstant:int::: PyModule_AddStringConstant:PyObject*:module:0: @@ -2187,7 +2187,7 @@ PyStructSequence_SET_ITEM:PyObject*:o:0: PyStructSequence_SetItem:void::: PyStructSequence_SetItem:PyObject*:p:0: PyStructSequence_SetItem:Py_ssize_t:pos:: -PyStructSequence_SetItem:PyObject*:o:0: +PyStructSequence_SetItem:PyObject*:o:$:stolen PySys_AddWarnOption:void::: PySys_AddWarnOption:const wchar_t*:s:: @@ -2335,12 +2335,12 @@ PyTuple_Pack:PyObject*:...:0: PyTuple_SET_ITEM:void::: PyTuple_SET_ITEM:PyObject*:p:0: PyTuple_SET_ITEM:Py_ssize_t:pos:: -PyTuple_SET_ITEM:PyObject*:o:0: +PyTuple_SET_ITEM:PyObject*:o:$:stolen PyTuple_SetItem:int::: PyTuple_SetItem:PyObject*:p:0: PyTuple_SetItem:Py_ssize_t:pos:: -PyTuple_SetItem:PyObject*:o:0: +PyTuple_SetItem:PyObject*:o:$:stolen PyTuple_Size:Py_ssize_t::: PyTuple_Size:PyObject*:p:0: From 07fae8ce45d98824d4c3182b61f97e7e7fe44c24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Sun, 1 Dec 2024 15:25:10 +0100 Subject: [PATCH 5/6] add comments for stolen references --- Doc/data/refcounts.dat | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/data/refcounts.dat b/Doc/data/refcounts.dat index 38fa6a717ab6c0..78146c3fce9508 100644 --- a/Doc/data/refcounts.dat +++ b/Doc/data/refcounts.dat @@ -1187,12 +1187,12 @@ PyList_Reverse:PyObject*:list:0: PyList_SET_ITEM:void::: PyList_SET_ITEM:PyObject*:list:0: PyList_SET_ITEM:Py_ssize_t:i:: -PyList_SET_ITEM:PyObject*:o:$: +PyList_SET_ITEM:PyObject*:o:$:stolen PyList_SetItem:int::: PyList_SetItem:PyObject*:list:0: PyList_SetItem:Py_ssize_t:index:: -PyList_SetItem:PyObject*:item:$: +PyList_SetItem:PyObject*:item:$:stolen PyList_SetSlice:int::: PyList_SetSlice:PyObject*:list:0: From e3d61ca618c54bb1ca01a2fe554bab5dd9723a94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Mon, 2 Dec 2024 10:26:05 +0100 Subject: [PATCH 6/6] post-merge --- Doc/data/refcounts.dat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/data/refcounts.dat b/Doc/data/refcounts.dat index 47dd335cfc0995..4d724632cce6a2 100644 --- a/Doc/data/refcounts.dat +++ b/Doc/data/refcounts.dat @@ -621,7 +621,7 @@ PyErr_GetExcInfo:PyObject**:ptraceback:+1: PyErr_GetRaisedException:PyObject*::+1: PyErr_SetRaisedException:void::: -PyErr_SetRaisedException:PyObject *:exc:0:stolen +PyErr_SetRaisedException:PyObject *:exc:$:stolen PyErr_GivenExceptionMatches:int::: PyErr_GivenExceptionMatches:PyObject*:given:0: