Repository navigation
Replace _Py_IDENTIFIER() with statically initialized objects. #90699
Copy link
Copy link
Closed
Labels
3.12only security fixesonly security fixesinterpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)
Description
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
assignee = 'https://github.com/ericsnowcurrently'
closed_at = None
created_at = <Date 2022-01-26.22:01:04.421>
labels = ['interpreter-core', '3.11']
title = 'Replace _Py_IDENTIFIER() with statically initialized objects.'
updated_at = <Date 2022-03-23.15:52:58.371>
user = 'https://github.com/ericsnowcurrently'bugs.python.org fields:
activity = <Date 2022-03-23.15:52:58.371>
actor = 'eric.snow'
assignee = 'eric.snow'
closed = False
closed_date = None
closer = None
components = ['Interpreter Core']
creation = <Date 2022-01-26.22:01:04.421>
creator = 'eric.snow'
dependencies = []
files = []
hgrepos = []
issue_num = 46541
keywords = ['patch']
message_count = 28.0
messages = ['411799', '411800', '411910', '411987', '412229', '412405', '412488', '412868', '413047', '413086', '413246', '413274', '413311', '413312', '413323', '413333', '413334', '413337', '413355', '413374', '413384', '413653', '414178', '414182', '414265', '414274', '414534', '415881']
nosy_count = 8.0
nosy_names = ['vstinner', 'christian.heimes', 'eric.snow', 'serhiy.storchaka', 'corona10', 'erlendaasland', 'kumaraditya', 'notarealdeveloper']
pr_nums = ['30928', '30941', '31261', '31344', '31346', '31351', '31358', '31363', '31364', '31372', '31375', '31376', '30310', '31468', '31475', '31599', '31608', '31609', '31683', '32063']
priority = 'normal'
resolution = None
stage = 'patch review'
status = 'open'
superseder = None
type = None
url = 'https://bugs.python.org/issue46541'
versions = ['Python 3.11']Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
3.12only security fixesonly security fixesinterpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)
Activity
ericsnowcurrently commentedon Jan 26, 2022
_Py_Identifierhas been useful but at this point there is a faster and simpler approach we could take as a replacement: statically initialize the objects as fields on_PyRuntimeStateand reference them directly through a macro.This would involve the following:
PyUnicodeObject field (not a pointer) to_PyRuntimeStatefor each string that currently uses_Py_IDENTIFIER()`_PyRuntimeState_Py_IDENTIFIER()to use the new macro insteadAs part of this, we would also do the following:
_Py_Identiferparameters_Py_Identifier,_Py_IDENTIFIER(), etc.(Note that there are several hundred uses of
_Py_IDENTIFIER(), including a number of duplicates.)Pros:
_PyRuntimeStatefields for themCons:
make check)_Py_IDENTIFIER()(even though it is "private" C-API)Note that with a basic partial implementation (GH-30928) I'm seeing a 1% improvement in performance (see faster-cpython/ideas#230).
ericsnowcurrently commentedon Jan 26, 2022
## Background ##
_Py_Identifier(and_Py_IDENTIFIER(), etc.) was added in 2011 [1][2] for several reasons:The solution involved using a static variable defined, using
_Py_IDENTIFIER()near the code that needed the string. The variable (a_Py_Identifier) would hold the desired C string (statically initialized) and the corresponding (lazily created)PyUnicodeObject. The code where the_Py_Identifierwas defined would then pass it to specialized versions of various C-API that would normally consume a C string orPyUnicodeObject. Then that code would use either the C-string or the object (creating and caching it first if not done already). This approach decentralized the caching but also provided a single tracking mechanism that made it easier to clean up the objects.Over the last decade a number of changes were made, including recent changes to make the identifiers per-interpreter and to use a centralized cache.
[1] afe55bb
[2] https://mail.python.org/archives/list/python-dev@python.org/message/FRUTTE47JO2XN3LXV2J4VB5A5VILILLA/
ericsnowcurrently commentedon Jan 27, 2022
New changeset 247480a by Eric Snow in branch 'main':
bpo-46541: Generate the global objects initializer. (gh-30941)
247480a
vstinner commentedon Jan 28, 2022
This change is going to break projects in the wild. Yes, people use the _Py_IDENTIFIER(), _PyUnicode_FromId() and other "Id" variant of many functions in 3rd party projects.
Is it possible to keep runtime initialization if this API is used by 3rd party code?
ericsnowcurrently commentedon Feb 1, 2022
If necessary, we can keep _Py_IDENTIFIER() (and the functions). Regardless, we can stop using it internally.
ericsnowcurrently commentedon Feb 2, 2022
FYI, I've posted to python-dev for feedback before proceeding:
https://mail.python.org/archives/list/python-dev@python.org/thread/DNMZAMB4M6RVR76RDZMUK2WRLI6KAAYS/
ericsnowcurrently commentedon Feb 4, 2022
(thanks Victor: https://mail.python.org/archives/list/python-dev@python.org/message/7RMLIJHUWVBZFV747TFEHOE6LNBVQSMM/)
3rd party use of _Py_IDENTIFIER():
+ https://github.com/blender/blender/blob/master/source/blender/python/intern/bpy_traceback.c#L53
- copied from core code
- "msg", "filename", "lineno", "offset", "text", "<string>"
- uses _PyObject_GetAttrId()
+ https://github.com/h2oai/datatable/blob/45a87337bc68576c7fb6900f524925d4fb77d6a6/src/core/python/obj.cc#L76
- in C++ wrapper getting sys.stdout, etc. and writing to sys.stdout
- has to hack around C++14 support
- has a fallback under limited API
- "stdin", "stdout", "stderr", "write"
- uses _PySys_GetObjectId(), _PyObject_GetAttrId()
+ https://github.com/aio-libs/multidict/blob/6dedb623cca8e8fe64f502dfa479826efc321385/multidict/_multilib/defs.h#L8
+ https://github.com/aio-libs/multidict/blob/6dedb623cca8e8fe64f502dfa479826efc321385/multidict/_multilib/istr.h#L46
+ https://github.com/aio-libs/multidict/blob/6dedb623cca8e8fe64f502dfa479826efc321385/multidict/_multilib/pair_list.h#L114
- calling str.lower()
- "lower"
- uses _PyObject_CallMethodId()
+ https://github.com/python/mypy/blob/3c935bdd1332672f5daeae7f3f9a858a453333d4/mypyc/lib-rt/dict_ops.c#L76
+ https://github.com/python/mypy/blob/3c935bdd1332672f5daeae7f3f9a858a453333d4/mypyc/lib-rt/dict_ops.c#L131
- "setdefault", "update"
- uses _PyObject_CallMethodIdObjArgs(), _PyObject_CallMethodIdOneArg()
+ https://github.com/python/mypy/blob/2b7e2df923f7e4a3a199915b3c8563f45bc69dfa/mypyc/lib-rt/pythonsupport.h#L26
+ https://github.com/python/mypy/blob/2b7e2df923f7e4a3a199915b3c8563f45bc69dfa/mypyc/lib-rt/pythonsupport.h#L109
- "__mro_entries__", "__init_subclass__"
- uses _PyObject_LookupAttrId(), _PyObject_GetAttrId()
+ https://github.com/python/mypy/blob/2b7e2df923f7e4a3a199915b3c8563f45bc69dfa/mypyc/lib-rt/misc_ops.c#L27
+ https://github.com/python/mypy/blob/2b7e2df923f7e4a3a199915b3c8563f45bc69dfa/mypyc/lib-rt/misc_ops.c#L47
- "send", "throw", "close"
- uses _PyObject_CallMethodIdOneArg(), _PyObject_GetAttrId()
+ https://github.com/python/mypy/blob/8c5c915a89ec0f35b3e07332c7090e62f143043e/mypyc/lib-rt/bytes_ops.c#L104
- "join"
- uses _PyObject_CallMethodIdOneArg()
+ https://github.com/python/mypy/blob/3c935bdd1332672f5daeae7f3f9a858a453333d4/mypyc/codegen/emitwrapper.py#L326
+ https://github.com/python/mypy/blob/2b7e2df923f7e4a3a199915b3c8563f45bc69dfa/mypyc/lib-rt/misc_ops.c#L694
- uses _PyObject_GetAttrId()
+ https://github.com/pitrou/pickle5-backport/blob/e6117502435aba2901585cc6c692fb9582545f08/pickle5/_pickle.c#L224
+ https://github.com/pitrou/pickle5-backport/blob/e6117502435aba2901585cc6c692fb9582545f08/pickle5/compat.h
- "getattr"
- uses _PyUnicode_FromId()
+ https://github.com/coleifer/pysqlite3/blob/f302859dc9ddb47a1089324dbca3873740b74af9/src/microprotocols.c#L103
+ https://github.com/coleifer/pysqlite3/blob/f302859dc9ddb47a1089324dbca3873740b74af9/src/microprotocols.c#L119
- "__adapt__", "__conform__"
- uses _PyObject_CallMethodId()
+ https://github.com/coleifer/pysqlite3/blob/093b88d1a58b141db8cf971c35ea1f6b674d0d02/src/connection.c#L51
+ https://github.com/coleifer/pysqlite3/blob/093b88d1a58b141db8cf971c35ea1f6b674d0d02/src/connection.c#L772
- "finalize", "value", "upper", "cursor"
- uses _PyObject_CallMethodId(), _PyObject_CallMethodIdObjArgs()
+ https://github.com/coleifer/pysqlite3/blob/49ce9c7a89a3c9f47ab8d32b6c4e2f7d629c1688/src/module.c#L195
- "upper"
- uses _PyObject_CallMethodId()
+ https://github.com/coleifer/pysqlite3/blob/91b2664f525b19feedfca3f0913302c6f1e8be8a/src/cursor.c#L103
- "upper"
- uses _PyObject_CallMethodId()
+ a fork of CPython's ast code
+ a fork of CPython's pickle
All of them should be trivial to drop _Py_IDENTIFIER() without any real performance impact or mess.
Also, the following implies that PyPy has some sort of _Py_IDENTIFIER() support: https://github.com/benhoyt/scandir/blob/3396aa4155ffde8600a0e9ca50d5872569169b5d/_scandir.c#L51.
ericsnowcurrently commentedon Feb 8, 2022
New changeset 81c7204 by Eric Snow in branch 'main':
bpo-46541: Replace core use of _Py_IDENTIFIER() with statically initialized global objects. (gh-30928)
81c7204
lazka commentedon Feb 11, 2022
Sorry if off topic, but I noticed that CPython doesn't deprecate macros in code, while with gcc/clang it's possible to show compiler warnings for them using some pragma magic:
Here is how glib implements this for example: https://gist.github.com/lazka/4749c74249a3918a059d944040aca4a3
Maybe that makes getting rid of them easier in the long run?
47 remaining items
kumaraditya303 commentedon Nov 3, 2022
practicality beats purity :) We can of course reconsider this when these modules will be ported to multiphase heap types.
kumaraditya303 commentedon Nov 3, 2022
PR #99067 removes the remaining.
GH-90699: Remove `_Py_IDENTIFIER` usage from `_ctypes` (GH-99054)
kumaraditya303 commentedon Nov 7, 2022
FYI, once #99067 is merged, I'll disable using
_Py_IDENTIFIERin core code. With that completed I consider this done and deprecation/removal for_Py_IDENTIFIERcan be discussed separately.ericsnowcurrently commentedon Nov 7, 2022
We will address Programs/_testembed.c in the issue/PR where we remove
_Py_IDENTIFIER()(or decide to not).GH-90699: Remove remaining `_Py_IDENTIFIER` stdlib usage (GH-99067)
ericsnowcurrently commentedon Nov 7, 2022
Thanks for doing all that work, @kumaraditya303!
ericsnowcurrently commentedon Nov 7, 2022
We can close this once gh-99210 lands.
GH-90699: fix refleak in `_testcapimodule.c` (gh-99236)
GH-90699: disallow `_Py_IDENTIFIER` in core code (GH-99210)
ericsnowcurrently commentedon Nov 9, 2022
This side of things is done. We can create a new issue about maybe getting rid of
_Py_IDENTIFIER()and what to do about third-party usage in the community.kumaraditya303 commentedon Nov 9, 2022
Thanks to everyone!
@ericsnowcurrently: It would be nice to update the c analyzer tool as a lot of globals are removed as part of this.
pythonGH-90699: Clear interned strings in _elementtree
GH-90699: Clear interned strings in `_elementtree` (#101185)