From bc29a2886899e93ca61cbfd0445f044a79af99dd Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Tue, 9 Apr 2024 09:57:07 +0900 Subject: [PATCH 01/12] add a private function --- Include/internal/pycore_typeobject.h | 2 ++ Objects/typeobject.c | 47 +++++++++++++++++++++++++--- 2 files changed, 44 insertions(+), 5 deletions(-) diff --git a/Include/internal/pycore_typeobject.h b/Include/internal/pycore_typeobject.h index 8a25935f308178..869ad914089a7e 100644 --- a/Include/internal/pycore_typeobject.h +++ b/Include/internal/pycore_typeobject.h @@ -126,6 +126,8 @@ PyAPI_FUNC(PyObject *) _PyType_GetDict(PyTypeObject *); extern PyObject * _PyType_GetBases(PyTypeObject *type); extern PyObject * _PyType_GetMRO(PyTypeObject *type); extern PyObject* _PyType_GetSubclasses(PyTypeObject *); +extern PyObject* _PyType_GetModuleByDefInPairs(PyTypeObject *, PyTypeObject *, + PyModuleDef *); extern int _PyType_HasSubclasses(PyTypeObject *); // PyType_Ready() must be called if _PyType_IsReady() is false. diff --git a/Objects/typeobject.c b/Objects/typeobject.c index e9f2d2577e9fab..1c5bc37f8c5732 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4816,11 +4816,24 @@ PyType_GetModuleState(PyTypeObject *type) /* Get the module of the first superclass where the module has the * given PyModuleDef. */ -PyObject * -PyType_GetModuleByDef(PyTypeObject *type, PyModuleDef *def) +static inline PyObject * +type_get_module_by_def(PyTypeObject *type, PyModuleDef *def) { assert(PyType_Check(type)); + if (!_PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE)) { + // type_ready_mro() ensures that no heap type is + // contained in a static type MRO. + return NULL; + } + else { + PyHeapTypeObject *ht = (PyHeapTypeObject*)type; + PyObject *module = ht->ht_module; + if (module && _PyModule_GetDef(module) == def) { + return module; + } + } + PyObject *res = NULL; BEGIN_TYPE_LOCK() @@ -4831,9 +4844,10 @@ PyType_GetModuleByDef(PyTypeObject *type, PyModuleDef *def) // mro_invoke() ensures that the type MRO cannot be empty, so we don't have // to check i < PyTuple_GET_SIZE(mro) at the first loop iteration. assert(PyTuple_GET_SIZE(mro) >= 1); + assert(PyTuple_GET_ITEM(mro, 0) == (PyObject *)type); Py_ssize_t n = PyTuple_GET_SIZE(mro); - for (Py_ssize_t i = 0; i < n; i++) { + for (Py_ssize_t i = 1; i < n; i++) { PyObject *super = PyTuple_GET_ITEM(mro, i); if(!_PyType_HasFeature((PyTypeObject *)super, Py_TPFLAGS_HEAPTYPE)) { // Static types in the MRO need to be skipped @@ -4848,14 +4862,37 @@ PyType_GetModuleByDef(PyTypeObject *type, PyModuleDef *def) } } END_TYPE_LOCK() + return res; +} - if (res == NULL) { +PyObject * +PyType_GetModuleByDef(PyTypeObject *type, PyModuleDef *def) +{ + PyObject *module = type_get_module_by_def(type, def); + if (module == NULL) { PyErr_Format( PyExc_TypeError, "PyType_GetModuleByDef: No superclass of '%s' has the given module", type->tp_name); } - return res; + return module; +} + +PyObject * +_PyType_GetModuleByDefInPairs(PyTypeObject *left, PyTypeObject *right, + PyModuleDef *def) +{ + PyObject *module = type_get_module_by_def(left, def); + if (module == NULL) { + module = type_get_module_by_def(right, def); + if (module == NULL) { + PyErr_Format( + PyExc_TypeError, + "PyType_GetModuleByDef: No superclass of '%s' and '%s' has" + "the given module", left->tp_name, right->tp_name); + } + } + return module; } void * From a0a3b599d633af6c6edb448af6fa1d5ff0d5fbd3 Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Tue, 9 Apr 2024 19:17:12 +0900 Subject: [PATCH 02/12] ByDefInPairs -> ByDef2 --- Include/internal/pycore_typeobject.h | 3 +-- Objects/typeobject.c | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Include/internal/pycore_typeobject.h b/Include/internal/pycore_typeobject.h index 869ad914089a7e..9b710689932412 100644 --- a/Include/internal/pycore_typeobject.h +++ b/Include/internal/pycore_typeobject.h @@ -126,8 +126,7 @@ PyAPI_FUNC(PyObject *) _PyType_GetDict(PyTypeObject *); extern PyObject * _PyType_GetBases(PyTypeObject *type); extern PyObject * _PyType_GetMRO(PyTypeObject *type); extern PyObject* _PyType_GetSubclasses(PyTypeObject *); -extern PyObject* _PyType_GetModuleByDefInPairs(PyTypeObject *, PyTypeObject *, - PyModuleDef *); +extern PyObject* _PyType_GetModuleByDef2(PyTypeObject *, PyTypeObject *, PyModuleDef *); extern int _PyType_HasSubclasses(PyTypeObject *); // PyType_Ready() must be called if _PyType_IsReady() is false. diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 1c5bc37f8c5732..65a74c49b847f1 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4879,7 +4879,7 @@ PyType_GetModuleByDef(PyTypeObject *type, PyModuleDef *def) } PyObject * -_PyType_GetModuleByDefInPairs(PyTypeObject *left, PyTypeObject *right, +_PyType_GetModuleByDef2(PyTypeObject *left, PyTypeObject *right, PyModuleDef *def) { PyObject *module = type_get_module_by_def(left, def); From 1e58f14be69cffbf46ef8f8fcb10e40de5d5eb1b Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Tue, 9 Apr 2024 19:25:54 +0900 Subject: [PATCH 03/12] fix error msg Co-authored-by: Erlend E. Aasland --- Objects/typeobject.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 65a74c49b847f1..4845a1702dba2f 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4888,7 +4888,7 @@ _PyType_GetModuleByDef2(PyTypeObject *left, PyTypeObject *right, if (module == NULL) { PyErr_Format( PyExc_TypeError, - "PyType_GetModuleByDef: No superclass of '%s' and '%s' has" + "PyType_GetModuleByDef: No superclass of '%s' or '%s' has" "the given module", left->tp_name, right->tp_name); } } From 0e31eaeab614b4a267a3968209c24ad6c950d95e Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Tue, 9 Apr 2024 19:27:48 +0900 Subject: [PATCH 04/12] fix error msg2 --- Objects/typeobject.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 4845a1702dba2f..6747e392556ca6 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4888,7 +4888,7 @@ _PyType_GetModuleByDef2(PyTypeObject *left, PyTypeObject *right, if (module == NULL) { PyErr_Format( PyExc_TypeError, - "PyType_GetModuleByDef: No superclass of '%s' or '%s' has" + "PyType_GetModuleByDef: No superclass of '%s' or '%s' has " "the given module", left->tp_name, right->tp_name); } } From 5efe3b0a52a510e4aaa8c90ec90bf20f00c1099f Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Tue, 9 Apr 2024 19:38:05 +0900 Subject: [PATCH 05/12] fix error msg --- Objects/typeobject.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 6747e392556ca6..42cac00a45ea1b 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4888,7 +4888,7 @@ _PyType_GetModuleByDef2(PyTypeObject *left, PyTypeObject *right, if (module == NULL) { PyErr_Format( PyExc_TypeError, - "PyType_GetModuleByDef: No superclass of '%s' or '%s' has " + "PyType_GetModuleByDef: No superclass of '%s' nor '%s' has " "the given module", left->tp_name, right->tp_name); } } From dcef50590d94afcf9a6a102eb697879bc64fdf0c Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Tue, 9 Apr 2024 20:36:55 +0900 Subject: [PATCH 06/12] apply PyAPI_FUNC() --- Include/internal/pycore_typeobject.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Include/internal/pycore_typeobject.h b/Include/internal/pycore_typeobject.h index 9b710689932412..b6ccc42a25db51 100644 --- a/Include/internal/pycore_typeobject.h +++ b/Include/internal/pycore_typeobject.h @@ -126,8 +126,8 @@ PyAPI_FUNC(PyObject *) _PyType_GetDict(PyTypeObject *); extern PyObject * _PyType_GetBases(PyTypeObject *type); extern PyObject * _PyType_GetMRO(PyTypeObject *type); extern PyObject* _PyType_GetSubclasses(PyTypeObject *); -extern PyObject* _PyType_GetModuleByDef2(PyTypeObject *, PyTypeObject *, PyModuleDef *); extern int _PyType_HasSubclasses(PyTypeObject *); +PyAPI_FUNC(PyObject *) _PyType_GetModuleByDef2(PyTypeObject *, PyTypeObject *, PyModuleDef *); // PyType_Ready() must be called if _PyType_IsReady() is false. // See also the Py_TPFLAGS_READY flag. From 4727f8a54c99e2e90bb9757914d56d8c2717625a Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Tue, 9 Apr 2024 21:52:10 +0900 Subject: [PATCH 07/12] indent --- Objects/typeobject.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 42cac00a45ea1b..ff74a2cb6c4ff3 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4880,7 +4880,7 @@ PyType_GetModuleByDef(PyTypeObject *type, PyModuleDef *def) PyObject * _PyType_GetModuleByDef2(PyTypeObject *left, PyTypeObject *right, - PyModuleDef *def) + PyModuleDef *def) { PyObject *module = type_get_module_by_def(left, def); if (module == NULL) { From dad0ea90c41243202d006cb6f8aa208b9bc7878f Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Tue, 23 Apr 2024 21:48:23 +0900 Subject: [PATCH 08/12] strip type_get_module_by_def of type_ --- Objects/typeobject.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 2fa3d1d4a37bfa..652dd4e4a3ccb7 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4826,7 +4826,7 @@ PyType_GetModuleState(PyTypeObject *type) * given PyModuleDef. */ static inline PyObject * -type_get_module_by_def(PyTypeObject *type, PyModuleDef *def) +get_module_by_def(PyTypeObject *type, PyModuleDef *def) { assert(PyType_Check(type)); @@ -4877,7 +4877,7 @@ type_get_module_by_def(PyTypeObject *type, PyModuleDef *def) PyObject * PyType_GetModuleByDef(PyTypeObject *type, PyModuleDef *def) { - PyObject *module = type_get_module_by_def(type, def); + PyObject *module = get_module_by_def(type, def); if (module == NULL) { PyErr_Format( PyExc_TypeError, @@ -4891,9 +4891,9 @@ PyObject * _PyType_GetModuleByDef2(PyTypeObject *left, PyTypeObject *right, PyModuleDef *def) { - PyObject *module = type_get_module_by_def(left, def); + PyObject *module = get_module_by_def(left, def); if (module == NULL) { - module = type_get_module_by_def(right, def); + module = get_module_by_def(right, def); if (module == NULL) { PyErr_Format( PyExc_TypeError, From 09dcfee4d2f062b68d2996e45b32aec164774675 Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Tue, 23 Apr 2024 21:49:18 +0900 Subject: [PATCH 09/12] apply new func to _decimal module --- Modules/_decimal/_decimal.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index 2481455ac0d143..fa425f4f740d31 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -32,6 +32,7 @@ #include #include "pycore_long.h" // _PyLong_IsZero() #include "pycore_pystate.h" // _PyThreadState_GET() +#include "pycore_typeobject.h" #include "complexobject.h" #include "mpdecimal.h" @@ -120,11 +121,8 @@ get_module_state_by_def(PyTypeObject *tp) static inline decimal_state * find_state_left_or_right(PyObject *left, PyObject *right) { - PyObject *mod = PyType_GetModuleByDef(Py_TYPE(left), &_decimal_module); - if (mod == NULL) { - PyErr_Clear(); - mod = PyType_GetModuleByDef(Py_TYPE(right), &_decimal_module); - } + PyObject *mod = _PyType_GetModuleByDef2(Py_TYPE(left), Py_TYPE(right), + &_decimal_module); assert(mod != NULL); return get_module_state(mod); } From a4d49f0c3c3f1d656b6bfd9a4fc59566bc43824c Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Tue, 23 Apr 2024 21:52:57 +0900 Subject: [PATCH 10/12] walk MRO from super to sub --- Objects/typeobject.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 652dd4e4a3ccb7..e667054ecf39f4 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4850,19 +4850,12 @@ get_module_by_def(PyTypeObject *type, PyModuleDef *def) // The type must be ready assert(mro != NULL); assert(PyTuple_Check(mro)); - // mro_invoke() ensures that the type MRO cannot be empty, so we don't have - // to check i < PyTuple_GET_SIZE(mro) at the first loop iteration. - assert(PyTuple_GET_SIZE(mro) >= 1); - assert(PyTuple_GET_ITEM(mro, 0) == (PyObject *)type); - - Py_ssize_t n = PyTuple_GET_SIZE(mro); - for (Py_ssize_t i = 1; i < n; i++) { + for (Py_ssize_t i = PyTuple_GET_SIZE(mro) - 1; i >= 0; i--) { PyObject *super = PyTuple_GET_ITEM(mro, i); if(!_PyType_HasFeature((PyTypeObject *)super, Py_TPFLAGS_HEAPTYPE)) { // Static types in the MRO need to be skipped continue; } - PyHeapTypeObject *ht = (PyHeapTypeObject*)super; PyObject *module = ht->ht_module; if (module && _PyModule_GetDef(module) == def) { From e89a7744124116f9e2b1c003c046ffc6f6186944 Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Wed, 24 Apr 2024 01:12:29 +0900 Subject: [PATCH 11/12] revert a4d49f0 --- Objects/typeobject.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index e667054ecf39f4..652dd4e4a3ccb7 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4850,12 +4850,19 @@ get_module_by_def(PyTypeObject *type, PyModuleDef *def) // The type must be ready assert(mro != NULL); assert(PyTuple_Check(mro)); - for (Py_ssize_t i = PyTuple_GET_SIZE(mro) - 1; i >= 0; i--) { + // mro_invoke() ensures that the type MRO cannot be empty, so we don't have + // to check i < PyTuple_GET_SIZE(mro) at the first loop iteration. + assert(PyTuple_GET_SIZE(mro) >= 1); + assert(PyTuple_GET_ITEM(mro, 0) == (PyObject *)type); + + Py_ssize_t n = PyTuple_GET_SIZE(mro); + for (Py_ssize_t i = 1; i < n; i++) { PyObject *super = PyTuple_GET_ITEM(mro, i); if(!_PyType_HasFeature((PyTypeObject *)super, Py_TPFLAGS_HEAPTYPE)) { // Static types in the MRO need to be skipped continue; } + PyHeapTypeObject *ht = (PyHeapTypeObject*)super; PyObject *module = ht->ht_module; if (module && _PyModule_GetDef(module) == def) { From bc14506772b40d73df6993ac6c165159257ca1ec Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Wed, 24 Apr 2024 20:47:54 +0900 Subject: [PATCH 12/12] update comments Co-authored-by: Petr Viktorin --- Objects/typeobject.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 652dd4e4a3ccb7..07e0a5a02da87f 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4850,9 +4850,10 @@ get_module_by_def(PyTypeObject *type, PyModuleDef *def) // The type must be ready assert(mro != NULL); assert(PyTuple_Check(mro)); - // mro_invoke() ensures that the type MRO cannot be empty, so we don't have - // to check i < PyTuple_GET_SIZE(mro) at the first loop iteration. + // mro_invoke() ensures that the type MRO cannot be empty. assert(PyTuple_GET_SIZE(mro) >= 1); + // Also, the first item in the MRO is the type itself, which + // we already checked above. We skip it in the loop. assert(PyTuple_GET_ITEM(mro, 0) == (PyObject *)type); Py_ssize_t n = PyTuple_GET_SIZE(mro);